Upgrade lzma to 23.01

This project was upgraded with external_updater.
Usage: tools/external_updater/updater.sh update external/lzma
For more info, check https://cs.android.com/android/platform/superproject/+/main:tools/external_updater/README.md

Test: TreeHugger
Change-Id: I56f7697a4e24afe360a4a6ccaa25f8c6e6e348a3
diff --git a/Asm/arm/7zCrcOpt.asm b/Asm/arm/7zCrcOpt.asm
index f008d65..6001d8e 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
new file mode 100644
index 0000000..12e950b
--- /dev/null
+++ b/Asm/arm64/7zAsm.S
@@ -0,0 +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
diff --git a/Asm/arm64/LzmaDecOpt.S b/Asm/arm64/LzmaDecOpt.S
new file mode 100644
index 0000000..10dc473
--- /dev/null
+++ b/Asm/arm64/LzmaDecOpt.S
@@ -0,0 +1,1487 @@
+// LzmaDecOpt.S -- ARM64-ASM version of LzmaDec_DecodeReal_3() function
+// 2021-04-25 : 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).
+*/
+
+
+#include "7zAsm.S"
+
+	// .arch armv8-a
+	// .file        "LzmaDecOpt.c"
+	.text
+	.align	2
+	.p2align 4,,15
+#ifdef __APPLE__
+        .globl _LzmaDec_DecodeReal_3
+#else        
+	.global LzmaDec_DecodeReal_3
+#endif        
+	// .type LzmaDec_DecodeReal_3, %function
+
+// #define _LZMA_SIZE_OPT 1
+
+#define LZMA_USE_4BYTES_FILL 1
+// #define LZMA_USE_2BYTES_COPY 1
+// #define LZMA_USE_CMOV_LZ_WRAP 1
+// #define _LZMA_PROB32 1
+
+#define MY_ALIGN_FOR_ENTRY   MY_ALIGN_32
+#define MY_ALIGN_FOR_LOOP    MY_ALIGN_32
+#define MY_ALIGN_FOR_LOOP_16 MY_ALIGN_16
+
+#ifdef _LZMA_PROB32
+        .equ PSHIFT , 2
+        .macro PLOAD dest:req, mem:req
+                ldr     \dest, [\mem]
+        .endm
+        .macro PLOAD_PREINDEXED dest:req, mem:req, offset:req
+                ldr     \dest, [\mem, \offset]!
+        .endm
+        .macro PLOAD_2 dest:req, mem1:req, mem2:req
+                ldr     \dest, [\mem1, \mem2]
+        .endm
+        .macro PLOAD_LSL dest:req, mem1:req, mem2:req
+                ldr     \dest, [\mem1, \mem2, lsl #PSHIFT]
+        .endm
+        .macro PSTORE src:req, mem:req
+                str     \src, [\mem]
+        .endm
+        .macro PSTORE_2 src:req, mem1:req, mem2:req
+                str     \src, [\mem1, \mem2]
+        .endm
+        .macro PSTORE_LSL src:req, mem1:req, mem2:req
+                str     \src, [\mem1, \mem2, lsl #PSHIFT]
+        .endm
+        .macro PSTORE_LSL_M1 src:req, mem1:req, mem2:req, temp_reg:req
+                // you must check that temp_reg is free register when macro is used
+                add     \temp_reg, \mem1, \mem2
+                str     \src, [\temp_reg, \mem2]
+        .endm
+#else
+        // .equ PSHIFT  , 1
+        #define PSHIFT  1
+        .macro PLOAD dest:req, mem:req
+                ldrh    \dest, [\mem]
+        .endm
+        .macro PLOAD_PREINDEXED dest:req, mem:req, offset:req
+                ldrh    \dest, [\mem, \offset]!
+        .endm
+        .macro PLOAD_2 dest:req, mem1:req, mem2:req
+                ldrh    \dest, [\mem1, \mem2]
+        .endm
+        .macro PLOAD_LSL dest:req, mem1:req, mem2:req
+                ldrh    \dest, [\mem1, \mem2, lsl #PSHIFT]
+        .endm
+        .macro PSTORE src:req, mem:req
+                strh    \src, [\mem]
+        .endm
+        .macro PSTORE_2 src:req, mem1:req, mem2:req
+                strh    \src, [\mem1, \mem2]
+        .endm
+        .macro PSTORE_LSL src:req, mem1:req, mem2:req
+                strh    \src, [\mem1, \mem2, lsl #PSHIFT]
+        .endm
+        .macro PSTORE_LSL_M1 src:req, mem1:req, mem2:req, temp_reg:req
+                strh    \src, [\mem1, \mem2]
+        .endm
+#endif
+
+.equ PMULT    , (1 << PSHIFT)
+.equ PMULT_2  , (2 << PSHIFT)
+
+.equ kMatchSpecLen_Error_Data , (1 << 9)
+
+#       x7      t0 : NORM_CALC    : prob2 (IF_BIT_1)
+#       x6      t1 : NORM_CALC    : probs_state
+#       x8      t2 : (LITM) temp  : (TREE) temp
+#       x4      t3 : (LITM) bit   : (TREE) temp : UPDATE_0/UPDATE_0 temp
+#       x10     t4 : (LITM) offs  : (TREE) probs_PMULT : numBits
+#       x9      t5 : (LITM) match : sym2 (ShortDist)
+#       x1      t6 : (LITM) litm_prob : (TREE) prob_reg : pbPos
+#       x2      t7 : (LITM) prm   : probBranch  : cnt
+#       x3      sym : dist
+#       x12     len
+#       x0      range
+#       x5      cod
+
+
+#define range   w0
+
+// t6
+#define pbPos     w1
+#define pbPos_R   r1
+#define prob_reg  w1
+#define litm_prob    prob_reg
+
+// t7
+#define probBranch    w2
+#define cnt     w2
+#define cnt_R   r2
+#define prm     r2
+
+#define sym     w3
+#define sym_R   r3
+#define dist       sym
+
+#define t3      w4
+#define bit     w4
+#define bit_R   r4
+#define update_temp_reg  r4
+
+#define cod     w5
+
+#define t1      w6
+#define t1_R    r6
+#define probs_state  t1_R
+
+#define t0      w7
+#define t0_R    r7
+#define prob2      t0
+
+#define t2      w8
+#define t2_R    r8 
+
+// t5
+#define match   w9
+#define sym2    w9
+#define sym2_R  r9
+
+#define t4      w10
+#define t4_R    r10
+
+#define offs    w10
+#define offs_R  r10
+
+#define probs   r11
+
+#define len     w12
+#define len_R   x12
+
+#define state   w13
+#define state_R r13
+
+#define dicPos          r14
+#define buf             r15
+#define bufLimit        r16
+#define dicBufSize      r17
+
+#define limit           r19
+#define rep0            w20
+#define rep0_R          r20
+#define rep1            w21
+#define rep2            w22
+#define rep3            w23
+#define dic             r24
+#define probs_IsMatch   r25
+#define probs_Spec      r26
+#define checkDicSize    w27
+#define processedPos    w28
+#define pbMask          w29
+#define lc2_lpMask      w30
+
+
+.equ kNumBitModelTotalBits   , 11
+.equ kBitModelTotal          , (1 << kNumBitModelTotalBits)
+.equ kNumMoveBits            , 5
+.equ kBitModelOffset         , (kBitModelTotal - (1 << kNumMoveBits) + 1)
+
+.macro NORM_2 macro
+        ldrb    t0, [buf], 1
+        shl     range, 8
+        orr     cod, t0, cod, lsl 8
+        /*
+        mov     t0, cod
+        ldrb    cod, [buf], 1
+        shl     range, 8
+        bfi	cod, t0, #8, #24
+        */
+.endm
+
+.macro TEST_HIGH_BYTE_range macro
+        tst     range, 0xFF000000
+.endm   
+
+.macro NORM macro
+        TEST_HIGH_BYTE_range
+        jnz     1f
+        NORM_2
+1:
+.endm
+
+
+# ---------- Branch MACROS ----------
+
+.macro UPDATE_0__0
+        sub     prob2, probBranch, kBitModelOffset
+.endm
+
+.macro UPDATE_0__1
+        sub     probBranch, probBranch, prob2, asr #(kNumMoveBits)
+.endm
+
+.macro UPDATE_0__2 probsArray:req, probOffset:req, probDisp:req
+     .if \probDisp == 0
+        PSTORE_2  probBranch, \probsArray, \probOffset
+    .elseif \probOffset == 0
+        PSTORE_2  probBranch, \probsArray, \probDisp * PMULT
+    .else
+        .error "unsupported"
+        // add     update_temp_reg, \probsArray, \probOffset
+        PSTORE_2  probBranch, update_temp_reg, \probDisp * PMULT
+    .endif
+.endm
+
+.macro UPDATE_0 probsArray:req, probOffset:req, probDisp:req
+        UPDATE_0__0
+        UPDATE_0__1
+        UPDATE_0__2 \probsArray, \probOffset, \probDisp
+.endm
+
+
+.macro UPDATE_1 probsArray:req, probOffset:req, probDisp:req
+        // sub     cod, cod, prob2
+        // sub     range, range, prob2
+        p2_sub  cod, range
+        sub     range, prob2, range
+        sub     prob2, probBranch, probBranch, lsr #(kNumMoveBits)
+    .if \probDisp == 0
+        PSTORE_2  prob2, \probsArray, \probOffset
+    .elseif \probOffset == 0
+        PSTORE_2  prob2, \probsArray, \probDisp * PMULT
+    .else
+        .error "unsupported"
+        // add     update_temp_reg, \probsArray, \probOffset
+        PSTORE_2  prob2, update_temp_reg, \probDisp * PMULT
+    .endif
+.endm
+
+
+.macro CMP_COD_BASE
+        NORM
+        // lsr     prob2, range, kNumBitModelTotalBits
+        // imul    prob2, probBranch
+        // cmp     cod, prob2
+        mov     prob2, range
+        shr     range, kNumBitModelTotalBits
+        imul    range, probBranch
+        cmp     cod, range
+.endm
+
+.macro CMP_COD_1 probsArray:req
+        PLOAD   probBranch, \probsArray
+        CMP_COD_BASE
+.endm
+
+.macro CMP_COD_3 probsArray:req, probOffset:req, probDisp:req
+    .if \probDisp == 0
+        PLOAD_2 probBranch, \probsArray, \probOffset
+    .elseif \probOffset == 0
+        PLOAD_2 probBranch, \probsArray, \probDisp * PMULT
+    .else
+        .error "unsupported"
+        add     update_temp_reg, \probsArray, \probOffset
+        PLOAD_2 probBranch, update_temp_reg, \probDisp * PMULT
+    .endif
+        CMP_COD_BASE
+.endm
+
+
+.macro IF_BIT_1_NOUP probsArray:req, probOffset:req, probDisp:req, toLabel:req
+        CMP_COD_3 \probsArray, \probOffset, \probDisp
+        jae     \toLabel
+.endm
+
+
+.macro IF_BIT_1 probsArray:req, probOffset:req, probDisp:req, toLabel:req
+        IF_BIT_1_NOUP \probsArray, \probOffset, \probDisp, \toLabel
+        UPDATE_0 \probsArray, \probOffset, \probDisp
+.endm
+
+
+.macro IF_BIT_0_NOUP probsArray:req, probOffset:req, probDisp:req, toLabel:req
+        CMP_COD_3 \probsArray, \probOffset, \probDisp
+        jb      \toLabel
+.endm
+
+.macro IF_BIT_0_NOUP_1 probsArray:req, toLabel:req
+        CMP_COD_1 \probsArray
+        jb      \toLabel
+.endm
+
+
+# ---------- CMOV MACROS ----------
+
+.macro NORM_LSR
+        NORM
+        lsr     t0, range, #kNumBitModelTotalBits
+.endm
+
+.macro COD_RANGE_SUB
+        subs    t1, cod, t0
+        p2_sub  range, t0
+.endm
+
+.macro RANGE_IMUL prob:req
+        imul    t0, \prob
+.endm
+
+.macro NORM_CALC prob:req
+        NORM_LSR
+        RANGE_IMUL \prob
+        COD_RANGE_SUB
+.endm
+
+.macro CMOV_range
+        cmovb   range, t0
+.endm
+
+.macro CMOV_code
+        cmovae  cod, t1
+.endm
+
+.macro CMOV_code_Model_Pre prob:req
+        sub     t0, \prob, kBitModelOffset
+        CMOV_code
+        cmovae  t0, \prob
+.endm
+        
+
+.macro PUP_BASE_2 prob:req, dest_reg:req
+        # only sar works for both 16/32 bit prob modes
+        sub     \dest_reg, \prob, \dest_reg, asr #(kNumMoveBits)
+.endm
+
+.macro PUP prob:req, probPtr:req, mem2:req
+        PUP_BASE_2 \prob, t0
+        PSTORE_2   t0, \probPtr, \mem2
+.endm
+
+
+
+#define probs_PMULT t4_R
+
+.macro BIT_01
+        add     probs_PMULT, probs, PMULT
+.endm
+
+
+.macro BIT_0_R prob:req
+        PLOAD_2 \prob, probs, 1 * PMULT
+        NORM_LSR
+            sub     t3, \prob, kBitModelOffset
+        RANGE_IMUL  \prob
+            PLOAD_2 t2, probs, 1 * PMULT_2
+        COD_RANGE_SUB
+        CMOV_range
+            cmovae  t3, \prob
+        PLOAD_2 t0, probs, 1 * PMULT_2 + PMULT
+            PUP_BASE_2 \prob, t3
+        csel   \prob, t2, t0, lo
+            CMOV_code
+        mov     sym, 2
+        PSTORE_2  t3, probs, 1 * PMULT
+            adc     sym, sym, wzr
+        BIT_01
+.endm
+
+.macro BIT_1_R prob:req
+        NORM_LSR
+            p2_add  sym, sym
+            sub     t3, \prob, kBitModelOffset
+        RANGE_IMUL  \prob
+            PLOAD_LSL t2, probs, sym_R
+        COD_RANGE_SUB
+        CMOV_range
+            cmovae  t3, \prob
+        PLOAD_LSL t0, probs_PMULT, sym_R
+            PUP_BASE_2 \prob, t3
+        csel   \prob, t2, t0, lo
+            CMOV_code
+        PSTORE_LSL_M1  t3, probs, sym_R, t2_R
+            adc     sym, sym, wzr
+.endm
+
+
+.macro BIT_2_R prob:req
+        NORM_LSR
+            p2_add  sym, sym
+            sub     t3, \prob, kBitModelOffset
+        RANGE_IMUL  \prob
+        COD_RANGE_SUB
+        CMOV_range
+            cmovae  t3, \prob
+            CMOV_code
+            PUP_BASE_2 \prob, t3
+        PSTORE_LSL_M1  t3, probs, sym_R, t2_R
+            adc     sym, sym, wzr
+.endm
+
+
+# ---------- MATCHED LITERAL ----------
+
+.macro LITM_0 macro
+        shl     match, (PSHIFT + 1)
+        and     bit, match, 256 * PMULT
+        add     prm, probs, 256 * PMULT + 1 * PMULT
+        p2_add  match, match
+        p2_add  prm, bit_R
+        eor     offs, bit, 256 * PMULT
+        PLOAD   litm_prob, prm
+        
+        NORM_LSR
+            sub     t2, litm_prob, kBitModelOffset
+        RANGE_IMUL  litm_prob
+        COD_RANGE_SUB
+        cmovae  offs, bit
+            CMOV_range
+        and     bit, match, offs
+            cmovae  t2, litm_prob
+            CMOV_code
+            mov     sym, 2
+        PUP_BASE_2 litm_prob, t2
+        PSTORE  t2, prm
+        add     prm, probs, offs_R
+        adc     sym, sym, wzr
+.endm
+
+.macro LITM macro
+        p2_add  prm, bit_R
+            xor     offs, bit
+        PLOAD_LSL litm_prob, prm, sym_R
+        
+        NORM_LSR
+            p2_add  match, match
+            sub     t2, litm_prob, kBitModelOffset
+        RANGE_IMUL  litm_prob
+        COD_RANGE_SUB
+        cmovae  offs, bit
+            CMOV_range
+        and     bit, match, offs
+            cmovae  t2, litm_prob
+            CMOV_code
+        PUP_BASE_2 litm_prob, t2
+        PSTORE_LSL t2, prm, sym_R
+        add     prm, probs, offs_R
+        adc     sym, sym, sym
+.endm
+
+
+.macro LITM_2 macro
+        p2_add  prm, bit_R
+        PLOAD_LSL litm_prob, prm, sym_R
+        
+        NORM_LSR
+            sub     t2, litm_prob, kBitModelOffset
+        RANGE_IMUL  litm_prob
+        COD_RANGE_SUB
+            CMOV_range
+            cmovae  t2, litm_prob
+            CMOV_code
+        PUP_BASE_2 litm_prob, t2
+        PSTORE_LSL t2, prm, sym_R
+        adc     sym, sym, sym
+.endm
+
+
+# ---------- REVERSE BITS ----------
+
+.macro REV_0 prob:req
+        NORM_CALC \prob
+        CMOV_range
+        PLOAD   t2, sym2_R
+        PLOAD_2 t3, probs, 3 * PMULT
+        CMOV_code_Model_Pre \prob
+        add     t1_R, probs, 3 * PMULT
+        cmovae  sym2_R, t1_R
+        PUP     \prob, probs, 1 * PMULT
+        csel    \prob, t2, t3, lo
+.endm
+
+
+.macro REV_1 prob:req, step:req
+        NORM_LSR
+            PLOAD_PREINDEXED  t2, sym2_R, (\step * PMULT)
+        RANGE_IMUL  \prob
+        COD_RANGE_SUB
+        CMOV_range
+        PLOAD_2 t3, sym2_R, (\step * PMULT)
+        sub     t0, \prob, kBitModelOffset
+        CMOV_code
+        add     t1_R, sym2_R, \step * PMULT
+        cmovae  t0, \prob
+        cmovae  sym2_R, t1_R
+        PUP_BASE_2 \prob, t0
+        csel    \prob, t2, t3, lo
+        PSTORE_2   t0, t1_R, 0 - \step * PMULT_2
+.endm
+
+
+.macro REV_2 prob:req, step:req
+        sub     t1_R, sym2_R, probs
+        NORM_LSR
+            orr     sym, sym, t1, lsr #PSHIFT
+        RANGE_IMUL  \prob
+        COD_RANGE_SUB
+        sub     t2, sym, \step
+        CMOV_range
+        cmovb   sym, t2
+        CMOV_code_Model_Pre \prob
+        PUP     \prob, sym2_R, 0
+.endm
+
+
+.macro REV_1_VAR prob:req
+        PLOAD   \prob, sym_R
+        mov     probs, sym_R
+        p2_add  sym_R, sym2_R
+        NORM_LSR
+            add     t2_R, sym_R, sym2_R
+        RANGE_IMUL  \prob
+        COD_RANGE_SUB
+        cmovae  sym_R, t2_R
+        CMOV_range
+        CMOV_code_Model_Pre \prob
+        p2_add  sym2, sym2
+        PUP     \prob, probs, 0
+.endm
+
+
+.macro add_big dest:req, src:req, param:req
+    .if (\param) < (1 << 12)
+        add     \dest, \src, \param
+    .else
+        #ifndef _LZMA_PROB32    
+          .error "unexpcted add_big expansion"
+        #endif
+        add     \dest, \src, (\param) / 2
+        add     \dest, \dest, (\param) - (\param) / 2
+    .endif
+.endm
+
+.macro sub_big dest:req, src:req, param:req
+    .if (\param) < (1 << 12)
+        sub     \dest, \src, \param
+    .else
+        #ifndef _LZMA_PROB32    
+          .error "unexpcted sub_big expansion"
+        #endif
+        sub     \dest, \src, (\param) / 2
+        sub     \dest, \dest, (\param) - (\param) / 2
+    .endif
+.endm
+
+
+.macro SET_probs offset:req
+        // add_big probs, probs_Spec, (\offset) * PMULT
+        add     probs, probs_IsMatch, ((\offset) - IsMatch) * PMULT
+.endm        
+
+
+.macro LIT_PROBS
+        add     sym, sym, processedPos, lsl 8
+        inc     processedPos
+        UPDATE_0__0
+        shl     sym, lc2_lpMask
+        SET_probs Literal
+        p2_and  sym, lc2_lpMask
+        // p2_add  probs_state, pbPos_R
+        p2_add  probs, sym_R
+        UPDATE_0__1
+        add     probs, probs, sym_R, lsl 1
+        UPDATE_0__2 probs_state, pbPos_R, 0
+.endm
+
+
+
+.equ kNumPosBitsMax       , 4
+.equ kNumPosStatesMax     , (1 << kNumPosBitsMax)
+                         
+.equ kLenNumLowBits       , 3
+.equ kLenNumLowSymbols    , (1 << kLenNumLowBits)
+.equ kLenNumHighBits      , 8
+.equ kLenNumHighSymbols   , (1 << kLenNumHighBits)
+.equ kNumLenProbs         , (2 * kLenNumLowSymbols * kNumPosStatesMax + kLenNumHighSymbols)
+                         
+.equ LenLow               , 0
+.equ LenChoice            , LenLow
+.equ LenChoice2           , (LenLow + kLenNumLowSymbols)
+.equ LenHigh              , (LenLow + 2 * kLenNumLowSymbols * kNumPosStatesMax)
+                         
+.equ kNumStates           , 12
+.equ kNumStates2          , 16
+.equ kNumLitStates        , 7
+                         
+.equ kStartPosModelIndex  , 4
+.equ kEndPosModelIndex    , 14
+.equ kNumFullDistances    , (1 << (kEndPosModelIndex >> 1))
+                         
+.equ kNumPosSlotBits      , 6
+.equ kNumLenToPosStates   , 4
+                         
+.equ kNumAlignBits        , 4
+.equ kAlignTableSize      , (1 << kNumAlignBits)
+                         
+.equ kMatchMinLen         , 2
+.equ kMatchSpecLenStart   , (kMatchMinLen + kLenNumLowSymbols * 2 + kLenNumHighSymbols)
+
+// .equ kStartOffset    , 1408
+.equ kStartOffset    , 0
+.equ SpecPos         , (-kStartOffset)
+.equ IsRep0Long      , (SpecPos + kNumFullDistances)
+.equ RepLenCoder     , (IsRep0Long + (kNumStates2 << kNumPosBitsMax))
+.equ LenCoder        , (RepLenCoder + kNumLenProbs)
+.equ IsMatch         , (LenCoder + kNumLenProbs)
+.equ kAlign          , (IsMatch + (kNumStates2 << kNumPosBitsMax))
+.equ IsRep           , (kAlign + kAlignTableSize)
+.equ IsRepG0         , (IsRep + kNumStates)
+.equ IsRepG1         , (IsRepG0 + kNumStates)
+.equ IsRepG2         , (IsRepG1 + kNumStates)
+.equ PosSlot         , (IsRepG2 + kNumStates)
+.equ Literal         , (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
+.equ NUM_BASE_PROBS  , (Literal + kStartOffset)
+
+.if kStartOffset != 0   // && IsMatch != 0
+  .error "Stop_Compiling_Bad_StartOffset"
+.endif
+
+.if NUM_BASE_PROBS != 1984
+  .error "Stop_Compiling_Bad_LZMA_PROBS"
+.endif
+
+.equ offset_lc    , 0
+.equ offset_lp    , 1
+.equ offset_pb    , 2
+.equ offset_dicSize       , 4
+.equ offset_probs         , 4 + offset_dicSize
+.equ offset_probs_1664    , 8 + offset_probs
+.equ offset_dic           , 8 + offset_probs_1664
+.equ offset_dicBufSize    , 8 + offset_dic
+.equ offset_dicPos        , 8 + offset_dicBufSize
+.equ offset_buf           , 8 + offset_dicPos
+.equ offset_range         , 8 + offset_buf
+.equ offset_code          , 4 + offset_range
+.equ offset_processedPos  , 4 + offset_code
+.equ offset_checkDicSize  , 4 + offset_processedPos
+.equ offset_rep0          , 4 + offset_checkDicSize
+.equ offset_rep1          , 4 + offset_rep0
+.equ offset_rep2          , 4 + offset_rep1
+.equ offset_rep3          , 4 + offset_rep2
+.equ offset_state         , 4 + offset_rep3
+.equ offset_remainLen     , 4 + offset_state
+.equ offset_TOTAL_SIZE    , 4 + offset_remainLen
+
+.if offset_TOTAL_SIZE != 96
+  .error "Incorrect offset_TOTAL_SIZE"
+.endif
+
+
+.macro IsMatchBranch_Pre
+        # prob = probs + IsMatch + (state << kNumPosBitsMax) + posState;
+        and     pbPos, pbMask, processedPos, lsl #(kLenNumLowBits + 1 + PSHIFT)
+        add     probs_state, probs_IsMatch, state_R
+.endm
+
+
+/*
+.macro IsMatchBranch
+        IsMatchBranch_Pre
+        IF_BIT_1 probs_state, pbPos_R, (IsMatch - IsMatch), IsMatch_label
+.endm
+*/        
+
+.macro CheckLimits
+        cmp     buf, bufLimit
+        jae     fin_OK
+        cmp     dicPos, limit
+        jae     fin_OK
+.endm
+
+#define  CheckLimits_lit  CheckLimits
+/*
+.macro CheckLimits_lit
+        cmp     buf, bufLimit
+        jae     fin_OK_lit
+        cmp     dicPos, limit
+        jae     fin_OK_lit
+.endm
+*/
+
+
+#define PARAM_lzma      REG_ABI_PARAM_0
+#define PARAM_limit     REG_ABI_PARAM_1
+#define PARAM_bufLimit  REG_ABI_PARAM_2
+
+
+.macro LOAD_LZMA_VAR reg:req, struct_offs:req
+        ldr     \reg, [PARAM_lzma, \struct_offs]
+.endm
+
+.macro LOAD_LZMA_BYTE reg:req, struct_offs:req
+        ldrb    \reg, [PARAM_lzma, \struct_offs]
+.endm
+
+.macro LOAD_LZMA_PAIR reg0:req, reg1:req, struct_offs:req
+        ldp     \reg0, \reg1, [PARAM_lzma, \struct_offs]
+.endm
+
+
+LzmaDec_DecodeReal_3:
+_LzmaDec_DecodeReal_3:
+/*
+.LFB0:
+	.cfi_startproc  
+*/
+
+	stp	x19, x20, [sp, -128]!
+	stp	x21, x22, [sp, 16]
+	stp	x23, x24, [sp, 32]
+	stp	x25, x26, [sp, 48]
+	stp	x27, x28, [sp, 64]
+	stp	x29, x30, [sp, 80]
+        
+        str     PARAM_lzma, [sp, 120]
+        
+        mov     bufLimit, PARAM_bufLimit
+        mov     limit, PARAM_limit
+        
+        LOAD_LZMA_PAIR  dic, dicBufSize, offset_dic
+        LOAD_LZMA_PAIR  dicPos, buf, offset_dicPos
+        LOAD_LZMA_PAIR  rep0, rep1, offset_rep0
+        LOAD_LZMA_PAIR  rep2, rep3, offset_rep2
+        
+        mov     t0, 1 << (kLenNumLowBits + 1 + PSHIFT)
+        LOAD_LZMA_BYTE  pbMask, offset_pb
+        p2_add  limit, dic
+        mov     len, wzr    // we can set it in all requiread branches instead
+        lsl     pbMask, t0, pbMask
+        p2_add  dicPos, dic
+        p2_sub  pbMask, t0
+
+        LOAD_LZMA_BYTE  lc2_lpMask, offset_lc
+        mov     t0, 256 << PSHIFT
+        LOAD_LZMA_BYTE  t1, offset_lp
+        p2_add  t1, lc2_lpMask
+        p2_sub  lc2_lpMask, (256 << PSHIFT) - PSHIFT
+        shl     t0, t1
+        p2_add  lc2_lpMask, t0
+        
+        LOAD_LZMA_VAR   probs_Spec, offset_probs
+        LOAD_LZMA_VAR   checkDicSize, offset_checkDicSize
+        LOAD_LZMA_VAR   processedPos, offset_processedPos
+        LOAD_LZMA_VAR   state, offset_state
+        // range is r0 : this load must be last don't move        
+        LOAD_LZMA_PAIR  range, cod, offset_range    
+        mov     sym, wzr
+        shl     state, PSHIFT
+
+        add_big probs_IsMatch, probs_Spec, ((IsMatch - SpecPos) << PSHIFT)
+
+        // if (processedPos != 0 || checkDicSize != 0)
+        orr     t0, checkDicSize, processedPos
+        cbz     t0, 1f
+        add     t0_R, dicBufSize, dic
+        cmp     dicPos, dic
+        cmovne  t0_R, dicPos
+        ldrb    sym, [t0_R, -1]
+1:
+        IsMatchBranch_Pre
+        cmp     state, 4 * PMULT
+        jb      lit_end
+        cmp     state, kNumLitStates * PMULT
+        jb      lit_matched_end
+        jmp     lz_end
+        
+
+        
+#define BIT_0  BIT_0_R prob_reg
+#define BIT_1  BIT_1_R prob_reg
+#define BIT_2  BIT_2_R prob_reg
+
+# ---------- LITERAL ----------
+MY_ALIGN_64
+lit_start:
+        mov     state, wzr
+lit_start_2:
+        LIT_PROBS
+
+    #ifdef _LZMA_SIZE_OPT
+
+        PLOAD_2 prob_reg, probs, 1 * PMULT
+        mov     sym, 1
+        BIT_01        
+MY_ALIGN_FOR_LOOP
+lit_loop:
+        BIT_1
+        tbz     sym, 7, lit_loop
+        
+    #else
+        
+        BIT_0
+        BIT_1
+        BIT_1
+        BIT_1
+        BIT_1
+        BIT_1
+        BIT_1
+        
+    #endif
+
+        BIT_2
+        IsMatchBranch_Pre
+        strb    sym, [dicPos], 1
+        p2_and  sym, 255
+                
+        CheckLimits_lit
+lit_end:
+        IF_BIT_0_NOUP probs_state, pbPos_R, (IsMatch - IsMatch), lit_start
+
+        # jmp     IsMatch_label
+        
+
+#define FLAG_STATE_BITS (4 + PSHIFT)          
+
+# ---------- MATCHES ----------
+# MY_ALIGN_FOR_ENTRY
+IsMatch_label:
+        UPDATE_1 probs_state, pbPos_R, (IsMatch - IsMatch)
+        IF_BIT_1 probs_state, 0, (IsRep - IsMatch), IsRep_label
+
+        SET_probs LenCoder
+        or      state, (1 << FLAG_STATE_BITS)
+
+# ---------- LEN DECODE ----------
+len_decode:
+        mov     len, 8 - kMatchMinLen
+        IF_BIT_0_NOUP_1 probs, len_mid_0
+        UPDATE_1 probs, 0, 0
+        p2_add  probs, (1 << (kLenNumLowBits + PSHIFT))
+        mov     len, 0 - kMatchMinLen
+        IF_BIT_0_NOUP_1 probs, len_mid_0
+        UPDATE_1 probs, 0, 0
+        p2_add  probs, LenHigh * PMULT - (1 << (kLenNumLowBits + PSHIFT))
+        
+    #if 0 == 1
+        BIT_0
+        BIT_1
+        BIT_1
+        BIT_1
+        BIT_1
+        BIT_1
+   #else
+        PLOAD_2 prob_reg, probs, 1 * PMULT
+        mov     sym, 1
+        BIT_01
+MY_ALIGN_FOR_LOOP
+len8_loop:
+        BIT_1
+        tbz     sym, 6, len8_loop
+   #endif        
+        
+        mov     len, (kLenNumHighSymbols - kLenNumLowSymbols * 2) - kMatchMinLen
+        jmp     len_mid_2 
+        
+MY_ALIGN_FOR_ENTRY
+len_mid_0:
+        UPDATE_0 probs, 0, 0
+        p2_add  probs, pbPos_R
+        BIT_0
+len_mid_2:
+        BIT_1
+        BIT_2
+        sub     len, sym, len
+        tbz     state, FLAG_STATE_BITS, copy_match
+        
+# ---------- DECODE DISTANCE ----------
+        // probs + PosSlot + ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits);
+
+        mov     t0, 3 + kMatchMinLen
+        cmp     len, 3 + kMatchMinLen
+        cmovb   t0, len
+        SET_probs PosSlot - (kMatchMinLen << (kNumPosSlotBits))
+        add     probs, probs, t0_R, lsl #(kNumPosSlotBits + PSHIFT)
+        
+    #ifdef _LZMA_SIZE_OPT
+
+        PLOAD_2 prob_reg, probs, 1 * PMULT
+        mov     sym, 1
+        BIT_01
+MY_ALIGN_FOR_LOOP
+slot_loop:
+        BIT_1
+        tbz     sym, 5, slot_loop
+        
+    #else
+        
+        BIT_0
+        BIT_1
+        BIT_1
+        BIT_1
+        BIT_1
+        
+    #endif
+        
+    #define numBits t4
+        mov     numBits, sym
+        BIT_2
+        // we need only low bits
+        p2_and  sym, 3
+        cmp     numBits, 32 + kEndPosModelIndex / 2
+        jb      short_dist
+
+        SET_probs kAlign
+
+        #  unsigned numDirectBits = (unsigned)(((distance >> 1) - 1));
+        p2_sub  numBits, (32 + 1 + kNumAlignBits)
+        #  distance = (2 | (distance & 1));
+        or      sym, 2
+        PLOAD_2 prob_reg, probs, 1 * PMULT
+        add     sym2_R, probs, 2 * PMULT
+        
+# ---------- DIRECT DISTANCE ----------
+
+.macro DIRECT_1
+        shr     range, 1
+        subs    t0, cod, range
+        p2_add  sym, sym
+        // add     t1, sym, 1
+        csel    cod, cod, t0, mi
+        csinc   sym, sym, sym, mi
+        // csel    sym, t1, sym, pl
+        // adc     sym, sym, sym // not 100% compatible for "corruptued-allowed" LZMA streams
+        dec_s   numBits
+        je      direct_end
+.endm
+
+    #ifdef _LZMA_SIZE_OPT
+
+        jmp     direct_norm
+MY_ALIGN_FOR_ENTRY
+direct_loop:
+        DIRECT_1
+direct_norm:
+        TEST_HIGH_BYTE_range
+        jnz     direct_loop
+        NORM_2
+        jmp     direct_loop
+
+    #else        
+
+.macro DIRECT_2
+        TEST_HIGH_BYTE_range
+        jz      direct_unroll
+        DIRECT_1
+.endm
+
+        DIRECT_2
+        DIRECT_2
+        DIRECT_2
+        DIRECT_2
+        DIRECT_2
+        DIRECT_2
+        DIRECT_2
+        DIRECT_2
+        
+direct_unroll:
+        NORM_2
+        DIRECT_1
+        DIRECT_1
+        DIRECT_1
+        DIRECT_1
+        DIRECT_1
+        DIRECT_1
+        DIRECT_1
+        DIRECT_1
+        jmp     direct_unroll
+    
+    #endif
+
+MY_ALIGN_FOR_ENTRY
+direct_end:
+        shl     sym, kNumAlignBits
+        REV_0   prob_reg
+        REV_1   prob_reg, 2
+        REV_1   prob_reg, 4
+        REV_2   prob_reg, 8
+
+decode_dist_end:
+
+    // if (distance >= (checkDicSize == 0 ? processedPos: checkDicSize))
+
+        tst     checkDicSize, checkDicSize
+        csel    t0, processedPos, checkDicSize, eq
+        cmp     sym, t0
+        jae     end_of_payload
+        // jmp     end_of_payload # for debug
+        
+        mov     rep3, rep2
+        mov     rep2, rep1
+        mov     rep1, rep0
+        add     rep0, sym, 1
+
+.macro  STATE_UPDATE_FOR_MATCH
+        // state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3;
+        // cmp     state, (kNumStates + kNumLitStates) * PMULT
+        cmp     state, kNumLitStates * PMULT + (1 << FLAG_STATE_BITS)
+        mov     state, kNumLitStates * PMULT
+        mov     t0, (kNumLitStates + 3) * PMULT
+        cmovae  state, t0
+.endm
+        STATE_UPDATE_FOR_MATCH
+        
+# ---------- COPY MATCH ----------
+copy_match:
+
+    // if ((rem = limit - dicPos) == 0) break // return SZ_ERROR_DATA;
+        subs    cnt_R, limit, dicPos
+        // jz      fin_dicPos_LIMIT
+        jz      fin_OK
+
+    // curLen = ((rem < len) ? (unsigned)rem : len);
+        cmp     cnt_R, len_R
+        cmovae  cnt, len
+
+        sub     t0_R, dicPos, dic
+        p2_add  dicPos, cnt_R
+        p2_add  processedPos, cnt
+        p2_sub  len, cnt
+        
+    // pos = dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0);
+        p2_sub_s  t0_R, rep0_R
+        jae     1f
+
+        cmn     t0_R, cnt_R
+        p2_add  t0_R, dicBufSize
+        ja      copy_match_cross
+1:
+# ---------- COPY MATCH FAST ----------
+    # t0_R : src_pos
+        p2_add  t0_R, dic
+        ldrb    sym, [t0_R]
+        p2_add  t0_R, cnt_R
+        p1_neg  cnt_R
+
+copy_common:
+        dec     dicPos
+
+    # dicPos  : (ptr_to_last_dest_BYTE)    
+    # t0_R    : (src_lim)
+    # cnt_R   : (-curLen)
+
+        IsMatchBranch_Pre
+        
+        inc_s   cnt_R
+        jz      copy_end
+        
+        cmp     rep0, 1
+        je      copy_match_0
+   
+    #ifdef LZMA_USE_2BYTES_COPY
+        strb    sym, [dicPos, cnt_R]
+        dec     dicPos
+    # dicPos  : (ptr_to_last_dest_16bitWORD)    
+        p2_and  cnt_R, -2
+        ldrh    sym, [t0_R, cnt_R]
+        adds    cnt_R, cnt_R, 2
+        jz      2f
+MY_ALIGN_FOR_LOOP
+1:
+        /*
+        strh    sym, [dicPos, cnt_R]
+        ldrh    sym, [t0_R, cnt_R]
+        adds    cnt_R, cnt_R, 2
+        jz      2f
+        */
+
+        strh    sym, [dicPos, cnt_R]
+        ldrh    sym, [t0_R, cnt_R]
+        adds    cnt_R, cnt_R, 2
+        jnz     1b
+2:
+        
+        /*
+        // for universal little/big endian code, but slow
+        strh    sym, [dicPos]
+        inc     dicPos 
+        ldrb    sym, [t0_R, -1]
+        */
+
+        #if  __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+        // we must improve big-endian detection for another compilers 
+        // for big-endian we need to revert bytes
+        rev16   sym, sym         
+        #endif
+        
+        // (sym) must represent as little-endian here:
+        strb    sym, [dicPos], 1
+        shr     sym, 8             
+
+    #else
+
+MY_ALIGN_FOR_LOOP
+1:
+        strb    sym, [dicPos, cnt_R]
+        ldrb    sym, [t0_R, cnt_R]
+        inc_s   cnt_R
+        jz      copy_end
+
+        strb    sym, [dicPos, cnt_R]
+        ldrb    sym, [t0_R, cnt_R]
+        inc_s   cnt_R
+        jnz     1b
+    #endif
+
+copy_end:
+lz_end_match:
+        strb    sym, [dicPos], 1
+  
+        # IsMatchBranch_Pre
+        CheckLimits
+lz_end:
+        IF_BIT_1_NOUP probs_state, pbPos_R, (IsMatch - IsMatch), IsMatch_label
+
+
+
+# ---------- LITERAL MATCHED ----------
+                
+        LIT_PROBS
+        
+    // matchByte = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)];
+
+        sub     t0_R, dicPos, dic
+        p2_sub_s t0_R, rep0_R
+    
+    #ifdef LZMA_USE_CMOV_LZ_WRAP
+        add     t1_R, t0_R, dicBufSize
+        cmovb   t0_R, t1_R
+    #else                
+        jae     1f
+        p2_add  t0_R, dicBufSize
+1:
+    #endif                        
+
+        ldrb    match, [dic, t0_R]
+
+    // state -= (state < 10) ? 3 : 6;
+        sub     sym, state, 6 * PMULT
+        cmp     state, 10 * PMULT
+        p2_sub  state, 3 * PMULT
+        cmovae  state, sym
+
+    #ifdef _LZMA_SIZE_OPT
+
+        mov     offs, 256 * PMULT
+        shl     match, (PSHIFT + 1)
+        mov     sym, 1
+        and     bit, match, offs
+        add     prm, probs, offs_R
+
+MY_ALIGN_FOR_LOOP
+litm_loop:
+        LITM
+        tbz     sym, 8, litm_loop
+        
+    #else
+        
+        LITM_0
+        LITM
+        LITM
+        LITM
+        LITM
+        LITM
+        LITM
+        LITM_2
+        
+    #endif
+    
+        IsMatchBranch_Pre
+        strb    sym, [dicPos], 1
+        p2_and  sym, 255
+        
+        // mov     len, wzr // LITM uses same regisetr (len / offs). So we clear it
+        CheckLimits_lit
+lit_matched_end:
+        IF_BIT_1_NOUP probs_state, pbPos_R, (IsMatch - IsMatch), IsMatch_label
+        # IsMatchBranch
+        p2_sub  state, 3 * PMULT
+        jmp     lit_start_2
+        
+
+
+# ---------- REP 0 LITERAL ----------
+MY_ALIGN_FOR_ENTRY
+IsRep0Short_label:
+        UPDATE_0 probs_state, pbPos_R, 0
+
+    // dic[dicPos] = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)];
+        sub     t0_R, dicPos, dic
+        
+        // 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, limit
+        # jae     fin_dicPos_LIMIT_REP_SHORT
+        # // jmp fin_dicPos_LIMIT_REP_SHORT // for testing/debug puposes
+
+        inc     processedPos
+
+        IsMatchBranch_Pre
+       
+        p2_sub_s t0_R, rep0_R
+    #ifdef LZMA_USE_CMOV_LZ_WRAP
+        add     sym_R, t0_R, dicBufSize
+        cmovb   t0_R, sym_R
+    #else       
+        jae     1f
+        p2_add  t0_R, dicBufSize
+1:
+    #endif
+        
+        ldrb    sym, [dic, t0_R]
+        // mov     len, wzr
+        jmp     lz_end_match
+        
+MY_ALIGN_FOR_ENTRY
+IsRep_label:
+        UPDATE_1 probs_state, 0, (IsRep - IsMatch)
+
+        # 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, 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
+
+        SET_probs RepLenCoder
+        
+        IF_BIT_1 probs_state, 0, (IsRepG0 - IsMatch), IsRepG0_label
+        sub_big  probs_state, probs_state, (IsMatch - IsRep0Long) << PSHIFT
+        IF_BIT_0_NOUP probs_state, pbPos_R, 0, IsRep0Short_label
+        UPDATE_1 probs_state, pbPos_R, 0
+        jmp     len_decode
+
+MY_ALIGN_FOR_ENTRY
+IsRepG0_label:
+        UPDATE_1 probs_state, 0, (IsRepG0 - IsMatch)
+        IF_BIT_1 probs_state, 0, (IsRepG1 - IsMatch), IsRepG1_label
+        mov     dist, rep1
+        mov     rep1, rep0
+        mov     rep0, dist
+        jmp     len_decode
+        
+# MY_ALIGN_FOR_ENTRY
+IsRepG1_label:
+        UPDATE_1 probs_state, 0, (IsRepG1 - IsMatch)
+        IF_BIT_1 probs_state, 0, (IsRepG2 - IsMatch), IsRepG2_label
+        mov     dist, rep2
+        mov     rep2, rep1
+        mov     rep1, rep0
+        mov     rep0, dist
+        jmp     len_decode
+
+# MY_ALIGN_FOR_ENTRY
+IsRepG2_label:
+        UPDATE_1 probs_state, 0, (IsRepG2 - IsMatch)
+        mov     dist, rep3
+        mov     rep3, rep2
+        mov     rep2, rep1
+        mov     rep1, rep0
+        mov     rep0, dist
+        jmp     len_decode
+
+        
+
+# ---------- SPEC SHORT DISTANCE ----------
+
+MY_ALIGN_FOR_ENTRY
+short_dist:
+        p2_sub_s numBits, 32 + 1
+        jbe     decode_dist_end
+        or      sym, 2
+        shl     sym, numBits
+        add     sym_R, probs_Spec, sym_R, lsl #PSHIFT
+        p2_add  sym_R, SpecPos * PMULT + 1 * PMULT
+        mov     sym2, PMULT // # step
+MY_ALIGN_FOR_LOOP
+spec_loop:
+        REV_1_VAR prob_reg
+        dec_s   numBits
+        jnz     spec_loop
+        
+        p2_add  sym2_R, probs_Spec
+    .if SpecPos != 0
+        p2_add  sym2_R, SpecPos * PMULT
+    .endif
+        p2_sub  sym_R, sym2_R
+        shr     sym, PSHIFT
+        
+        jmp     decode_dist_end
+
+
+
+# ---------- COPY MATCH 0 ----------
+MY_ALIGN_FOR_ENTRY
+copy_match_0:
+    #ifdef LZMA_USE_4BYTES_FILL
+        strb    sym, [dicPos, cnt_R]
+        inc_s   cnt_R
+        jz      copy_end
+        
+        strb    sym, [dicPos, cnt_R]
+        inc_s   cnt_R
+        jz      copy_end
+        
+        strb    sym, [dicPos, cnt_R]
+        inc_s   cnt_R
+        jz      copy_end
+        
+        orr     t3, sym, sym, lsl 8
+        p2_and  cnt_R, -4
+        orr     t3, t3, t3, lsl 16
+MY_ALIGN_FOR_LOOP_16
+1:
+        /*
+        str     t3, [dicPos, cnt_R]
+        adds    cnt_R, cnt_R, 4
+        jz      2f
+        */
+
+        str     t3, [dicPos, cnt_R]
+        adds    cnt_R, cnt_R, 4
+        jnz     1b
+2:
+        // p2_and  sym, 255
+    #else
+
+MY_ALIGN_FOR_LOOP
+1:
+        strb    sym, [dicPos, cnt_R]
+        inc_s   cnt_R
+        jz      copy_end
+
+        strb    sym, [dicPos, cnt_R]
+        inc_s   cnt_R
+        jnz     1b
+    #endif        
+
+    jmp     copy_end
+
+
+# ---------- COPY MATCH CROSS ----------
+copy_match_cross:
+        # t0_R  - src pos
+        # cnt_R - total copy len
+
+        p1_neg  cnt_R
+1:
+        ldrb    sym, [dic, t0_R]
+        inc     t0_R
+        strb    sym, [dicPos, cnt_R]
+        inc     cnt_R
+        cmp     t0_R, dicBufSize
+        jne     1b
+        
+        ldrb    sym, [dic]
+        sub     t0_R, dic, cnt_R
+        jmp     copy_common
+
+
+
+
+/*
+fin_dicPos_LIMIT_REP_SHORT:
+        mov     len, 1
+        jmp     fin_OK
+*/
+
+/*
+fin_dicPos_LIMIT:
+        jmp     fin_OK
+        # For more strict mode we can stop decoding with error
+        # mov     sym, 1
+        # jmp     fin
+*/
+
+fin_ERROR_MATCH_DIST:
+        # rep0 = distance + 1;
+        p2_add  len, kMatchSpecLen_Error_Data
+        mov     rep3, rep2
+        mov     rep2, rep1
+        mov     rep1, rep0
+        mov     rep0, sym
+        STATE_UPDATE_FOR_MATCH
+        # jmp     fin_OK
+        mov     sym, 1
+        jmp     fin
+
+end_of_payload:
+        inc_s   sym
+        jnz     fin_ERROR_MATCH_DIST
+
+        mov     len, kMatchSpecLenStart
+        xor     state, (1 << FLAG_STATE_BITS)
+        jmp     fin_OK
+
+/*
+fin_OK_lit:
+        mov     len, wzr
+*/
+
+fin_OK:
+        mov     sym, wzr
+
+fin:
+        NORM
+
+    #define fin_lzma_reg  t0_R
+
+   .macro STORE_LZMA_VAR reg:req, struct_offs:req
+        str     \reg, [fin_lzma_reg, \struct_offs]
+   .endm
+
+   .macro STORE_LZMA_PAIR reg0:req, reg1:req, struct_offs:req
+        stp     \reg0, \reg1, [fin_lzma_reg, \struct_offs]
+   .endm
+
+        ldr     fin_lzma_reg, [sp, 120]
+        p2_sub  dicPos, dic
+        shr     state, PSHIFT
+
+        STORE_LZMA_PAIR   dicPos, buf,  offset_dicPos
+        STORE_LZMA_PAIR   range, cod,   offset_range
+        STORE_LZMA_VAR    processedPos, offset_processedPos
+        STORE_LZMA_PAIR   rep0, rep1,   offset_rep0
+        STORE_LZMA_PAIR   rep2, rep3,   offset_rep2
+        STORE_LZMA_PAIR   state, len,   offset_state
+
+        mov     w0, sym
+        
+	ldp	x29, x30, [sp, 80]
+	ldp	x27, x28, [sp, 64]
+	ldp	x25, x26, [sp, 48]
+        ldp	x23, x24, [sp, 32]
+	ldp	x21, x22, [sp, 16]
+	ldp	x19, x20, [sp], 128
+
+        ret
+/*
+	.cfi_endproc
+.LFE0:
+	.size	LzmaDec_DecodeReal_3, .-LzmaDec_DecodeReal_3
+	.ident	"TAG_LZMA"
+	.section	.note.GNU-stack,"",@progbits
+*/        
diff --git a/Asm/x86/7zAsm.asm b/Asm/x86/7zAsm.asm
index 8c30d7b..19c40da 100644
--- a/Asm/x86/7zAsm.asm
+++ b/Asm/x86/7zAsm.asm
@@ -1,147 +1,289 @@
-; 7zAsm.asm -- ASM macros

-; 2018-02-03 : Igor Pavlov : Public domain

-

-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

-  ifdef x64

-    proc_name equ name

-  else

-    proc_name equ @CatStr(@,name,@, %numParams * 4)

-  endif

-  proc_name PROC

-endm

-

-MY_ENDP macro

-  ifdef x64

-    ret

-  else

-    if proc_numParams LT 3

-      ret

-    else

-      ret (proc_numParams - 2) * 4

-    endif

-  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

-

-ifdef x64

-  x5_L equ BPL

-  x6_L equ SIL

-  x7_L equ DIL

-

-  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

-

-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

-

-

-ifdef x64

-

-; for WIN64-x64 ABI:

-

-REG_PARAM_0 equ r1

-REG_PARAM_1 equ r2

-REG_PARAM_2 equ r8

-REG_PARAM_3 equ r9

-

-MY_PUSH_PRESERVED_REGS macro

-    MY_PUSH_4_REGS

-    push    r12

-    push    r13

-    push    r14

-    push    r15

-endm

-

-

-MY_POP_PRESERVED_REGS macro

-    pop     r15

-    pop     r14

-    pop     r13

-    pop     r12

-    MY_POP_4_REGS

-endm

-

-endif

+; 7zAsm.asm -- ASM macros
+; 2022-05-16 : 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
+
+ifdef x64
+  x5_L equ BPL
+  x6_L equ SIL
+  x7_L equ DIL
+
+  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
+
+
+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
+
+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 macro
+    if  (IS_LINUX gt 0)
+        MY_PUSH_2_REGS
+    else
+        MY_PUSH_4_REGS
+    endif
+        push    r12
+        push    r13
+        push    r14
+        push    r15
+endm
+
+
+MY_POP_PRESERVED_ABI_REGS macro
+        pop     r15
+        pop     r14
+        pop     r13
+        pop     r12
+    if  (IS_LINUX gt 0)
+        MY_POP_2_REGS
+    else
+        MY_POP_4_REGS
+    endif
+endm
+
+endif ; x64
diff --git a/Asm/x86/7zCrcOpt.asm b/Asm/x86/7zCrcOpt.asm
index 2de5171..0fee206 100644
--- a/Asm/x86/7zCrcOpt.asm
+++ b/Asm/x86/7zCrcOpt.asm
@@ -1,147 +1,180 @@
-; 7zCrcOpt.asm -- CRC32 calculation : optimized version

-; 2009-12-12 : Igor Pavlov : Public domain

-

-include 7zAsm.asm

-

-MY_ASM_START

-

-rD   equ  r2

-rN   equ  r7

-

-ifdef x64

-    num_VAR     equ r8

-    table_VAR   equ r9

-else

-    data_size   equ (REG_SIZE * 5)

-    crc_table   equ (REG_SIZE + data_size)

-    num_VAR     equ [r4 + data_size]

-    table_VAR   equ [r4 + crc_table]

-endif

-

-SRCDAT  equ  rN + rD + 4 *

-

-CRC macro op:req, dest:req, src:req, t:req

-    op      dest, DWORD PTR [r5 + src * 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

-

-CRC1b macro

-    movzx   x6, BYTE PTR [rD]

-    inc     rD

-    movzx   x3, x0_L

-    xor     x6, x3

-    shr     x0, 8

-    CRC     xor, x0, r6, 0

-    dec     rN

-endm

-

-MY_PROLOG macro crc_end:req

-    MY_PUSH_4_REGS

-    

-    mov     x0, x1

-    mov     rN, num_VAR

-    mov     r5, table_VAR

-    test    rN, rN

-    jz      crc_end

-  @@:

-    test    rD, 7

-    jz      @F

-    CRC1b

-    jnz     @B

-  @@:

-    cmp     rN, 16

-    jb      crc_end

-    add     rN, rD

-    mov     num_VAR, rN

-    sub     rN, 8

-    and     rN, NOT 7

-    sub     rD, rN

-    xor     x0, [SRCDAT 0]

-endm

-

-MY_EPILOG macro crc_end:req

-    xor     x0, [SRCDAT 0]

-    mov     rD, rN

-    mov     rN, num_VAR

-    sub     rN, rD

-  crc_end:

-    test    rN, rN

-    jz      @F

-    CRC1b

-    jmp     crc_end

-  @@:

-    MY_POP_4_REGS

-endm

-

-MY_PROC CrcUpdateT8, 4

-    MY_PROLOG crc_end_8

-    mov     x1, [SRCDAT 1]

-    align 16

-  main_loop_8:

-    mov     x6, [SRCDAT 2]

-    movzx   x3, x1_L

-    CRC_XOR x6, r3, 3

-    movzx   x3, x1_H

-    CRC_XOR x6, r3, 2

-    shr     x1, 16

-    movzx   x3, x1_L

-    movzx   x1, x1_H

-    CRC_XOR x6, r3, 1

-    movzx   x3, x0_L

-    CRC_XOR x6, r1, 0

-

-    mov     x1, [SRCDAT 3]

-    CRC_XOR x6, r3, 7

-    movzx   x3, x0_H

-    shr     x0, 16

-    CRC_XOR x6, r3, 6

-    movzx   x3, x0_L

-    CRC_XOR x6, r3, 5

-    movzx   x3, x0_H

-    CRC_MOV x0, r3, 4

-    xor     x0, x6

-    add     rD, 8

-    jnz     main_loop_8

-

-    MY_EPILOG crc_end_8

-MY_ENDP

-

-MY_PROC CrcUpdateT4, 4

-    MY_PROLOG crc_end_4

-    align 16

-  main_loop_4:

-    movzx   x1, x0_L

-    movzx   x3, x0_H

-    shr     x0, 16

-    movzx   x6, x0_H

-    and     x0, 0FFh

-    CRC_MOV x1, r1, 3

-    xor     x1, [SRCDAT 1]

-    CRC_XOR x1, r3, 2

-    CRC_XOR x1, r6, 0

-    CRC_XOR x1, r0, 1

- 

-    movzx   x0, x1_L

-    movzx   x3, x1_H

-    shr     x1, 16

-    movzx   x6, x1_H

-    and     x1, 0FFh

-    CRC_MOV x0, r0, 3

-    xor     x0, [SRCDAT 2]

-    CRC_XOR x0, r3, 2

-    CRC_XOR x0, r6, 0

-    CRC_XOR x0, r1, 1

-    add     rD, 8

-    jnz     main_loop_4

-

-    MY_EPILOG crc_end_4

-MY_ENDP

-

-end

+; 7zCrcOpt.asm -- CRC32 calculation : optimized version
+; 2021-02-07 : Igor Pavlov : Public domain
+
+include 7zAsm.asm
+
+MY_ASM_START
+
+rD   equ  r2
+rN   equ  r7
+rT   equ  r5
+
+ifdef x64
+    num_VAR     equ r8
+    table_VAR   equ r9
+else
+  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)
+    num_VAR     equ [r4 + size_OFFS]
+    table_VAR   equ [r4 + table_OFFS]
+endif
+
+SRCDAT  equ  rD + rN * 1 + 4 *
+
+CRC macro op:req, dest:req, src:req, t:req
+    op      dest, DWORD PTR [rT + src * 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
+
+CRC1b macro
+    movzx   x6, BYTE PTR [rD]
+    inc     rD
+    movzx   x3, x0_L
+    xor     x6, x3
+    shr     x0, 8
+    CRC     xor, x0, r6, 0
+    dec     rN
+endm
+
+MY_PROLOG macro crc_end:req
+
+    ifdef x64
+      if  (IS_LINUX gt 0)
+        MY_PUSH_2_REGS
+        mov     x0, REG_ABI_PARAM_0_x   ; x0 = x7
+        mov     rT, REG_ABI_PARAM_3     ; r5 = r1
+        mov     rN, REG_ABI_PARAM_2     ; r7 = r2
+        mov     rD, REG_ABI_PARAM_1     ; r2 = r6
+      else
+        MY_PUSH_4_REGS
+        mov     x0, REG_ABI_PARAM_0_x   ; x0 = x1
+        mov     rT, REG_ABI_PARAM_3     ; r5 = r9
+        mov     rN, REG_ABI_PARAM_2     ; r7 = r8
+        ; mov     rD, REG_ABI_PARAM_1     ; r2 = r2
+      endif
+    else
+        MY_PUSH_4_REGS
+      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, num_VAR
+        mov     rT, table_VAR
+    endif
+    
+    test    rN, rN
+    jz      crc_end
+  @@:
+    test    rD, 7
+    jz      @F
+    CRC1b
+    jnz     @B
+  @@:
+    cmp     rN, 16
+    jb      crc_end
+    add     rN, rD
+    mov     num_VAR, rN
+    sub     rN, 8
+    and     rN, NOT 7
+    sub     rD, rN
+    xor     x0, [SRCDAT 0]
+endm
+
+MY_EPILOG macro crc_end:req
+    xor     x0, [SRCDAT 0]
+    mov     rD, rN
+    mov     rN, num_VAR
+    sub     rN, rD
+  crc_end:
+    test    rN, rN
+    jz      @F
+    CRC1b
+    jmp     crc_end
+  @@:
+      if (IS_X64 gt 0) and (IS_LINUX gt 0)
+        MY_POP_2_REGS
+      else
+        MY_POP_4_REGS
+      endif
+endm
+
+MY_PROC CrcUpdateT8, 4
+    MY_PROLOG crc_end_8
+    mov     x1, [SRCDAT 1]
+    align 16
+  main_loop_8:
+    mov     x6, [SRCDAT 2]
+    movzx   x3, x1_L
+    CRC_XOR x6, r3, 3
+    movzx   x3, x1_H
+    CRC_XOR x6, r3, 2
+    shr     x1, 16
+    movzx   x3, x1_L
+    movzx   x1, x1_H
+    CRC_XOR x6, r3, 1
+    movzx   x3, x0_L
+    CRC_XOR x6, r1, 0
+
+    mov     x1, [SRCDAT 3]
+    CRC_XOR x6, r3, 7
+    movzx   x3, x0_H
+    shr     x0, 16
+    CRC_XOR x6, r3, 6
+    movzx   x3, x0_L
+    CRC_XOR x6, r3, 5
+    movzx   x3, x0_H
+    CRC_MOV x0, r3, 4
+    xor     x0, x6
+    add     rD, 8
+    jnz     main_loop_8
+
+    MY_EPILOG crc_end_8
+MY_ENDP
+
+MY_PROC CrcUpdateT4, 4
+    MY_PROLOG crc_end_4
+    align 16
+  main_loop_4:
+    movzx   x1, x0_L
+    movzx   x3, x0_H
+    shr     x0, 16
+    movzx   x6, x0_H
+    and     x0, 0FFh
+    CRC_MOV x1, r1, 3
+    xor     x1, [SRCDAT 1]
+    CRC_XOR x1, r3, 2
+    CRC_XOR x1, r6, 0
+    CRC_XOR x1, r0, 1
+ 
+    movzx   x0, x1_L
+    movzx   x3, x1_H
+    shr     x1, 16
+    movzx   x6, x1_H
+    and     x1, 0FFh
+    CRC_MOV x0, r0, 3
+    xor     x0, [SRCDAT 2]
+    CRC_XOR x0, r3, 2
+    CRC_XOR x0, r6, 0
+    CRC_XOR x0, r1, 1
+    add     rD, 8
+    jnz     main_loop_4
+
+    MY_EPILOG crc_end_4
+MY_ENDP
+
+end
diff --git a/Asm/x86/AesOpt.asm b/Asm/x86/AesOpt.asm
index c32e48f..84bf897 100644
--- a/Asm/x86/AesOpt.asm
+++ b/Asm/x86/AesOpt.asm
@@ -1,237 +1,742 @@
-; AesOpt.asm -- Intel's AES.

-; 2009-12-12 : Igor Pavlov : Public domain

-

-include 7zAsm.asm

-

-MY_ASM_START

-

-ifndef x64

-    .xmm

-endif

-

-ifdef x64

-    num     equ r8

-else

-    num     equ [r4 + REG_SIZE * 4]

-endif

-

-rD equ r2

-rN equ r0

-

-MY_PROLOG macro reg:req

-    ifdef x64

-    movdqa  [r4 + 8], xmm6

-    movdqa  [r4 + 8 + 16], xmm7

-    endif

-

-    push    r3

-    push    r5

-    push    r6

-

-    mov     rN, num

-    mov     x6, [r1 + 16]

-    shl     x6, 5

-

-    movdqa  reg, [r1]

-    add     r1, 32

-endm

-

-MY_EPILOG macro

-    pop     r6

-    pop     r5

-    pop     r3

-

-    ifdef x64

-    movdqa  xmm6, [r4 + 8]

-    movdqa  xmm7, [r4 + 8 + 16]

-    endif

-

-    MY_ENDP

-endm

-

-ways equ 4

-ways16 equ (ways * 16)

-

-OP_W macro op, op2

-    i = 0

-    rept ways

-    op @CatStr(xmm,%i), op2

-    i = i + 1

-    endm

-endm

-

-LOAD_OP macro op:req, offs:req

-    op      xmm0, [r1 + r3 offs]

-endm

-  

-LOAD_OP_W macro op:req, offs:req

-    movdqa  xmm7, [r1 + r3 offs]

-    OP_W    op, xmm7

-endm

-

-

-; ---------- AES-CBC Decode ----------

-

-CBC_DEC_UPDATE macro reg, offs

-    pxor    reg, xmm6

-    movdqa  xmm6, [rD + offs]

-    movdqa  [rD + offs], reg

-endm

-

-DECODE macro op:req

-    op      aesdec, +16

-  @@:

-    op      aesdec, +0

-    op      aesdec, -16

-    sub     x3, 32

-    jnz     @B

-    op      aesdeclast, +0

-endm

-

-MY_PROC AesCbc_Decode_Intel, 3

-    MY_PROLOG xmm6

-

-    sub     x6, 32

-

-    jmp     check2

-

-  align 16

-  nextBlocks2:

-    mov     x3, x6

-    OP_W    movdqa, [rD + i * 16]

-    LOAD_OP_W  pxor, +32

-    DECODE  LOAD_OP_W

-    OP_W    CBC_DEC_UPDATE, i * 16

-    add     rD, ways16

-  check2:

-    sub     rN, ways

-    jnc     nextBlocks2

-

-    add     rN, ways

-    jmp     check

-

-  nextBlock:

-    mov     x3, x6

-    movdqa  xmm1, [rD]

-    LOAD_OP movdqa, +32

-    pxor    xmm0, xmm1

-    DECODE  LOAD_OP

-    pxor    xmm0, xmm6

-    movdqa  [rD], xmm0

-    movdqa  xmm6, xmm1

-    add     rD, 16

-  check:

-    sub     rN, 1

-    jnc     nextBlock

-

-    movdqa  [r1 - 32], xmm6

-    MY_EPILOG

-

-

-; ---------- AES-CBC Encode ----------

-

-ENCODE macro op:req

-    op      aesenc, -16

-  @@:

-    op      aesenc, +0

-    op      aesenc, +16

-    add     r3, 32

-    jnz     @B

-    op      aesenclast, +0

-endm

-

-MY_PROC AesCbc_Encode_Intel, 3

-    MY_PROLOG xmm0

-

-    add     r1, r6

-    neg     r6

-    add     r6, 32

-

-    jmp     check_e

-

-  align 16

-  nextBlock_e:

-    mov     r3, r6

-    pxor    xmm0, [rD]

-    pxor    xmm0, [r1 + r3 - 32]

-    ENCODE  LOAD_OP

-    movdqa  [rD], xmm0

-    add     rD, 16

-  check_e:

-    sub     rN, 1

-    jnc     nextBlock_e

-

-    movdqa  [r1 + r6 - 64], xmm0

-    MY_EPILOG

-

-

-; ---------- AES-CTR ----------

-

-XOR_UPD_1 macro reg, offs

-    pxor    reg, [rD + offs]

-endm

-

-XOR_UPD_2 macro reg, offs

-    movdqa  [rD + offs], reg

-endm

-

-MY_PROC AesCtr_Code_Intel, 3

-    MY_PROLOG xmm6

-

-    mov     r5, r4

-    shr     r5, 4

-    dec     r5

-    shl     r5, 4

-

-    mov     DWORD PTR [r5], 1

-    mov     DWORD PTR [r5 + 4], 0

-    mov     DWORD PTR [r5 + 8], 0

-    mov     DWORD PTR [r5 + 12], 0

-    

-    add     r1, r6

-    neg     r6

-    add     r6, 32

-

-    jmp     check2_c

-

-  align 16

-  nextBlocks2_c:

-    movdqa  xmm7, [r5]

-

-    i = 0

-    rept ways

-    paddq   xmm6, xmm7

-    movdqa  @CatStr(xmm,%i), xmm6

-    i = i + 1

-    endm

-

-    mov     r3, r6

-    LOAD_OP_W  pxor, -32

-    ENCODE  LOAD_OP_W

-    OP_W    XOR_UPD_1, i * 16

-    OP_W    XOR_UPD_2, i * 16

-    add     rD, ways16

-  check2_c:

-    sub     rN, ways

-    jnc     nextBlocks2_c

-

-    add     rN, ways

-    jmp     check_c

-

-  nextBlock_c:

-    paddq   xmm6, [r5]

-    mov     r3, r6

-    movdqa  xmm0, [r1 + r3 - 32]

-    pxor    xmm0, xmm6

-    ENCODE  LOAD_OP

-    XOR_UPD_1 xmm0, 0

-    XOR_UPD_2 xmm0, 0

-    add     rD, 16

-  check_c:

-    sub     rN, 1

-    jnc     nextBlock_c

-

-    movdqa  [r1 + r6 - 64], xmm6

-    MY_EPILOG

-

-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
new file mode 100644
index 0000000..42e10bd
--- /dev/null
+++ b/Asm/x86/LzFindOpt.asm
@@ -0,0 +1,513 @@
+; LzFindOpt.asm -- ASM version of GetMatchesSpecN_2() function
+; 2021-07-21: Igor Pavlov : Public domain
+;
+
+ifndef x64
+; x64=1
+; .err <x64_IS_REQUIRED>
+endif
+
+include 7zAsm.asm
+
+MY_ASM_START
+
+_TEXT$LZFINDOPT SEGMENT ALIGN(64) 'CODE'
+
+MY_ALIGN macro num:req
+        align  num
+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
+
+
+; MY_ALIGN_64
+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
+
+_TEXT$LZFINDOPT ENDS
+
+end
diff --git a/Asm/x86/LzmaDecOpt.asm b/Asm/x86/LzmaDecOpt.asm
index 0a89eb7..f2818e7 100644
--- a/Asm/x86/LzmaDecOpt.asm
+++ b/Asm/x86/LzmaDecOpt.asm
@@ -1,1258 +1,1303 @@
-; LzmaDecOpt.asm -- ASM version of LzmaDec_DecodeReal_3() function

-; 2018-02-06: 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 <x64_IS_REQUIRED>

-endif

-

-include 7zAsm.asm

-

-MY_ASM_START

-

-_TEXT$LZMADECOPT SEGMENT ALIGN(64) 'CODE'

-

-MY_ALIGN macro num:req

-        align  num

-endm

-

-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))

-

-

-;       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 + 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 <Stop_Compiling_Bad_LZMA_kAlign>

-endif

-

-if NUM_BASE_PROBS ne 1984

-  .err <Stop_Compiling_Bad_LZMA_PROBS>

-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 + 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_PARAM_0

-PARAM_limit     equ REG_PARAM_1

-PARAM_bufLimit  equ REG_PARAM_2

-

-; MY_ALIGN_64

-MY_PROC LzmaDec_DecodeReal_3, 3

-MY_PUSH_PRESERVED_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     len_mid_2

-        

-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     t0, LOC checkDicSize

-        test    t0, t0

-        cmove   t0, processedPos

-        cmp     sym, t0

-        jae     end_of_payload

-        

-        ; rep3 = rep2;

-        ; rep2 = rep1;

-        ; rep1 = rep0;

-        ; rep0 = distance + 1;

-

-        inc     sym

-        mov     t0, LOC rep0

-        mov     t1, LOC rep1

-        mov     x1, LOC rep2

-        mov     LOC rep0, sym

-        ; mov     sym, LOC remainLen

-        mov     sym, len_temp

-        mov     LOC rep1, t0

-        mov     LOC rep2, t1

-        mov     LOC rep3, x1

-        

-        ; 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_ERROR

-

-        ; 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

-        inc     processedPos

-        ; state = state < kNumLitStates ? 9 : 11;

-        or      state, 1 * PMULT

-        IsMatchBranch_Pre

-       

-        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_ERROR:

-        mov     LOC remainLen, len_temp

-; fin_ERROR_2:

-        mov     sym, 1

-        jmp     fin

-

-end_of_payload:

-        cmp     sym, 0FFFFFFFFh ; -1

-        jne     fin_ERROR

-

-        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_REGS

-MY_ENDP

-

-_TEXT$LZMADECOPT ENDS

-

-end

+; LzmaDecOpt.asm -- ASM version of LzmaDec_DecodeReal_3() function
+; 2021-02-23: 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 <x64_IS_REQUIRED>
+endif
+
+include 7zAsm.asm
+
+MY_ASM_START
+
+_TEXT$LZMADECOPT SEGMENT ALIGN(64) 'CODE'
+
+MY_ALIGN macro num:req
+        align  num
+endm
+
+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 <Stop_Compiling_Bad_LZMA_kAlign>
+endif
+
+if NUM_BASE_PROBS ne 1984
+  .err <Stop_Compiling_Bad_LZMA_PROBS>
+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
+
+; MY_ALIGN_64
+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
+
+_TEXT$LZMADECOPT ENDS
+
+end
diff --git a/Asm/x86/Sha1Opt.asm b/Asm/x86/Sha1Opt.asm
new file mode 100644
index 0000000..3495fd1
--- /dev/null
+++ b/Asm/x86/Sha1Opt.asm
@@ -0,0 +1,263 @@
+; Sha1Opt.asm -- SHA-1 optimized code for SHA-1 x86 hardware instructions
+; 2021-03-10 : Igor Pavlov : Public domain
+
+include 7zAsm.asm
+
+MY_ASM_START
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+CONST   SEGMENT
+
+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
new file mode 100644
index 0000000..3e9f6ed
--- /dev/null
+++ b/Asm/x86/Sha256Opt.asm
@@ -0,0 +1,275 @@
+; Sha256Opt.asm -- SHA-256 optimized code for SHA-256 x86 hardware instructions
+; 2022-04-17 : 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
+
+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 3e6d490..ad22cc2 100644
--- a/Asm/x86/XzCrc64Opt.asm
+++ b/Asm/x86/XzCrc64Opt.asm
@@ -1,205 +1,239 @@
-; XzCrc64Opt.asm -- CRC64 calculation : optimized version

-; 2011-06-28 : Igor Pavlov : Public domain

-

-include 7zAsm.asm

-

-MY_ASM_START

-

-ifdef x64

-

-    rD   equ  r9

-    rN   equ  r10

-

-    num_VAR     equ  r8

-    table_VAR   equ  r9

-

-    SRCDAT  equ  rN + rD

-

-CRC_XOR macro dest:req, src:req, t:req

-    xor     dest, QWORD PTR [r5 + src * 8 + 0800h * t]

-endm

-

-CRC1b macro

-    movzx   x6, BYTE PTR [rD]

-    inc     rD

-    movzx   x3, x0_L

-    xor     x6, x3

-    shr     r0, 8

-    CRC_XOR r0, r6, 0

-    dec     rN

-endm

-

-MY_PROLOG macro crc_end:req

-    MY_PUSH_4_REGS

-    

-    mov     r0, r1

-    mov     rN, num_VAR

-    mov     r5, table_VAR

-    mov     rD, r2

-    test    rN, rN

-    jz      crc_end

-  @@:

-    test    rD, 3

-    jz      @F

-    CRC1b

-    jnz     @B

-  @@:

-    cmp     rN, 8

-    jb      crc_end

-    add     rN, rD

-    mov     num_VAR, rN

-    sub     rN, 4

-    and     rN, NOT 3

-    sub     rD, rN

-    mov     x1, [SRCDAT]

-    xor     r0, r1

-    add     rN, 4

-endm

-

-MY_EPILOG macro crc_end:req

-    sub     rN, 4

-    mov     x1, [SRCDAT]

-    xor     r0, r1

-    mov     rD, rN

-    mov     rN, num_VAR

-    sub     rN, rD

-  crc_end:

-    test    rN, rN

-    jz      @F

-    CRC1b

-    jmp     crc_end

-  @@:

-    MY_POP_4_REGS

-endm

-

-MY_PROC XzCrc64UpdateT4, 4

-    MY_PROLOG crc_end_4

-    align 16

-  main_loop_4:

-    mov     x1, [SRCDAT]

-    movzx   x2, x0_L

-    movzx   x3, x0_H

-    shr     r0, 16

-    movzx   x6, x0_L

-    movzx   x7, x0_H

-    shr     r0, 16

-    CRC_XOR r1, r2, 3

-    CRC_XOR r0, r3, 2

-    CRC_XOR r1, r6, 1

-    CRC_XOR r0, r7, 0

-    xor     r0, r1

-

-    add     rD, 4

-    jnz     main_loop_4

-

-    MY_EPILOG crc_end_4

-MY_ENDP

-

-else

-

-    rD   equ  r1

-    rN   equ  r7

-

-    crc_val     equ (REG_SIZE * 5)

-    crc_table   equ (8 + crc_val)

-    table_VAR   equ [r4 + crc_table]

-    num_VAR     equ table_VAR

-

-

-    SRCDAT  equ  rN + rD

-

-CRC macro op0:req, op1:req, dest0:req, dest1:req, src:req, t:req

-    op0     dest0, DWORD PTR [r5 + src * 8 + 0800h * t]

-    op1     dest1, DWORD PTR [r5 + src * 8 + 0800h * t + 4]

-endm

-

-CRC_XOR macro dest0:req, dest1:req, src:req, t:req

-    CRC xor, xor, dest0, dest1, src, t

-endm

-

-

-CRC1b macro

-    movzx   x6, BYTE PTR [rD]

-    inc     rD

-    movzx   x3, x0_L

-    xor     x6, x3

-    shrd    r0, r2, 8

-    shr     r2, 8

-    CRC_XOR r0, r2, r6, 0

-    dec     rN

-endm

-

-MY_PROLOG macro crc_end:req

-    MY_PUSH_4_REGS

-    

-    mov     rN, r2

-

-    mov     x0, [r4 + crc_val]

-    mov     x2, [r4 + crc_val + 4]

-    mov     r5, table_VAR

-    test    rN, rN

-    jz      crc_end

-  @@:

-    test    rD, 3

-    jz      @F

-    CRC1b

-    jnz     @B

-  @@:

-    cmp     rN, 8

-    jb      crc_end

-    add     rN, rD

-

-    mov     num_VAR, rN

-

-    sub     rN, 4

-    and     rN, NOT 3

-    sub     rD, rN

-    xor     r0, [SRCDAT]

-    add     rN, 4

-endm

-

-MY_EPILOG macro crc_end:req

-    sub     rN, 4

-    xor     r0, [SRCDAT]

-

-    mov     rD, rN

-    mov     rN, num_VAR

-    sub     rN, rD

-  crc_end:

-    test    rN, rN

-    jz      @F

-    CRC1b

-    jmp     crc_end

-  @@:

-    MY_POP_4_REGS

-endm

-

-MY_PROC XzCrc64UpdateT4, 5

-    MY_PROLOG crc_end_4

-    movzx   x6, x0_L

-    align 16

-  main_loop_4:

-    mov     r3, [SRCDAT]

-    xor     r3, r2

-

-    CRC xor, mov, r3, r2, r6, 3

-    movzx   x6, x0_H

-    shr     r0, 16

-    CRC_XOR r3, r2, r6, 2

-

-    movzx   x6, x0_L

-    movzx   x0, x0_H

-    CRC_XOR r3, r2, r6, 1

-    CRC_XOR r3, r2, r0, 0

-    movzx   x6, x3_L

-    mov     r0, r3

-

-    add     rD, 4

-    jnz     main_loop_4

-

-    MY_EPILOG crc_end_4

-MY_ENDP

-

-endif

-

-end

+; XzCrc64Opt.asm -- CRC64 calculation : optimized version
+; 2021-02-06 : Igor Pavlov : Public domain
+
+include 7zAsm.asm
+
+MY_ASM_START
+
+ifdef x64
+
+rD      equ  r9
+rN      equ  r10
+rT      equ  r5
+num_VAR equ  r8
+
+SRCDAT4 equ  dword ptr [rD + rN * 1]
+    
+CRC_XOR macro dest:req, src:req, t:req
+    xor     dest, QWORD PTR [rT + src * 8 + 0800h * t]
+endm
+
+CRC1b macro
+    movzx   x6, BYTE PTR [rD]
+    inc     rD
+    movzx   x3, x0_L
+    xor     x6, x3
+    shr     r0, 8
+    CRC_XOR r0, r6, 0
+    dec     rN
+endm
+
+MY_PROLOG macro crc_end:req
+  ifdef ABI_LINUX
+    MY_PUSH_2_REGS
+  else
+    MY_PUSH_4_REGS
+  endif
+    mov     r0, REG_ABI_PARAM_0
+    mov     rN, REG_ABI_PARAM_2
+    mov     rT, REG_ABI_PARAM_3
+    mov     rD, REG_ABI_PARAM_1
+    test    rN, rN
+    jz      crc_end
+  @@:
+    test    rD, 3
+    jz      @F
+    CRC1b
+    jnz     @B
+  @@:
+    cmp     rN, 8
+    jb      crc_end
+    add     rN, rD
+    mov     num_VAR, rN
+    sub     rN, 4
+    and     rN, NOT 3
+    sub     rD, rN
+    mov     x1, SRCDAT4
+    xor     r0, r1
+    add     rN, 4
+endm
+
+MY_EPILOG macro crc_end:req
+    sub     rN, 4
+    mov     x1, SRCDAT4
+    xor     r0, r1
+    mov     rD, rN
+    mov     rN, num_VAR
+    sub     rN, rD
+  crc_end:
+    test    rN, rN
+    jz      @F
+    CRC1b
+    jmp     crc_end
+  @@:
+  ifdef ABI_LINUX
+    MY_POP_2_REGS
+  else
+    MY_POP_4_REGS
+  endif
+endm
+
+MY_PROC XzCrc64UpdateT4, 4
+    MY_PROLOG crc_end_4
+    align 16
+  main_loop_4:
+    mov     x1, SRCDAT4
+    movzx   x2, x0_L
+    movzx   x3, x0_H
+    shr     r0, 16
+    movzx   x6, x0_L
+    movzx   x7, x0_H
+    shr     r0, 16
+    CRC_XOR r1, r2, 3
+    CRC_XOR r0, r3, 2
+    CRC_XOR r1, r6, 1
+    CRC_XOR r0, r7, 0
+    xor     r0, r1
+
+    add     rD, 4
+    jnz     main_loop_4
+
+    MY_EPILOG crc_end_4
+MY_ENDP
+
+else
+; x86 (32-bit)
+
+rD      equ  r1
+rN      equ  r7
+rT      equ  r5
+
+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
+
+SRCDAT4 equ  dword ptr [rD + rN * 1]
+
+CRC macro op0:req, op1:req, dest0:req, dest1:req, src:req, t:req
+    op0     dest0, DWORD PTR [rT + src * 8 + 0800h * t]
+    op1     dest1, DWORD PTR [rT + src * 8 + 0800h * t + 4]
+endm
+
+CRC_XOR macro dest0:req, dest1:req, src:req, t:req
+    CRC xor, xor, dest0, dest1, src, t
+endm
+
+
+CRC1b macro
+    movzx   x6, BYTE PTR [rD]
+    inc     rD
+    movzx   x3, x0_L
+    xor     x6, x3
+    shrd    r0, r2, 8
+    shr     r2, 8
+    CRC_XOR r0, r2, r6, 0
+    dec     rN
+endm
+
+MY_PROLOG macro crc_end:req
+    MY_PUSH_4_REGS
+
+  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     rN, r2
+  endif
+
+    mov     x0, [r4 + crc_OFFS]
+    mov     x2, [r4 + crc_OFFS + 4]
+    mov     rT, table_VAR
+    test    rN, rN
+    jz      crc_end
+  @@:
+    test    rD, 3
+    jz      @F
+    CRC1b
+    jnz     @B
+  @@:
+    cmp     rN, 8
+    jb      crc_end
+    add     rN, rD
+
+    mov     num_VAR, rN
+
+    sub     rN, 4
+    and     rN, NOT 3
+    sub     rD, rN
+    xor     r0, SRCDAT4
+    add     rN, 4
+endm
+
+MY_EPILOG macro crc_end:req
+    sub     rN, 4
+    xor     r0, SRCDAT4
+
+    mov     rD, rN
+    mov     rN, num_VAR
+    sub     rN, rD
+  crc_end:
+    test    rN, rN
+    jz      @F
+    CRC1b
+    jmp     crc_end
+  @@:
+    MY_POP_4_REGS
+endm
+
+MY_PROC XzCrc64UpdateT4, 5
+    MY_PROLOG crc_end_4
+    movzx   x6, x0_L
+    align 16
+  main_loop_4:
+    mov     r3, SRCDAT4
+    xor     r3, r2
+
+    CRC xor, mov, r3, r2, r6, 3
+    movzx   x6, x0_H
+    shr     r0, 16
+    CRC_XOR r3, r2, r6, 2
+
+    movzx   x6, x0_L
+    movzx   x0, x0_H
+    CRC_XOR r3, r2, r6, 1
+    CRC_XOR r3, r2, r0, 0
+    movzx   x6, x3_L
+    mov     r0, r3
+
+    add     rD, 4
+    jnz     main_loop_4
+
+    MY_EPILOG crc_end_4
+MY_ENDP
+
+endif ; ! x64
+
+end
diff --git a/C/7z.h b/C/7z.h
index 82813c2..9e27c01 100644
--- a/C/7z.h
+++ b/C/7z.h
@@ -1,202 +1,204 @@
-/* 7z.h -- 7z interface

-2017-04-03 : Igor Pavlov : Public domain */

-

-#ifndef __7Z_H

-#define __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;

-} CSzAr;

-

-UInt64 SzAr_GetFolderUnpackSize(const CSzAr *p, UInt32 folderIndex);

-

-SRes SzAr_DecodeFolder(const CSzAr *p, UInt32 folderIndex,

-    ILookInStream *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,

-    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 */

-    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, ILookInStream *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 ea32809..2f0659a 100644
--- a/C/7zAlloc.c
+++ b/C/7zAlloc.c
@@ -1,80 +1,89 @@
-/* 7zAlloc.c -- Allocation functions

-2017-04-03 : Igor Pavlov : Public domain */

-

-#include "Precomp.h"

-

-#include <stdlib.h>

-

-#include "7zAlloc.h"

-

-/* #define _SZ_ALLOC_DEBUG */

-/* use _SZ_ALLOC_DEBUG to debug alloc/free operations */

-

-#ifdef _SZ_ALLOC_DEBUG

-

-#ifdef _WIN32

-#include <windows.h>

-#endif

-

-#include <stdio.h>

-int g_allocCount = 0;

-int g_allocCountTemp = 0;

-

-#endif

-

-void *SzAlloc(ISzAllocPtr p, size_t size)

-{

-  UNUSED_VAR(p);

-  if (size == 0)

-    return 0;

-  #ifdef _SZ_ALLOC_DEBUG

-  fprintf(stderr, "\nAlloc %10u bytes; count = %10d", (unsigned)size, g_allocCount);

-  g_allocCount++;

-  #endif

-  return malloc(size);

-}

-

-void SzFree(ISzAllocPtr p, void *address)

-{

-  UNUSED_VAR(p);

-  #ifdef _SZ_ALLOC_DEBUG

-  if (address != 0)

-  {

-    g_allocCount--;

-    fprintf(stderr, "\nFree; count = %10d", g_allocCount);

-  }

-  #endif

-  free(address);

-}

-

-void *SzAllocTemp(ISzAllocPtr p, size_t size)

-{

-  UNUSED_VAR(p);

-  if (size == 0)

-    return 0;

-  #ifdef _SZ_ALLOC_DEBUG

-  fprintf(stderr, "\nAlloc_temp %10u bytes;  count = %10d", (unsigned)size, g_allocCountTemp);

-  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 != 0)

-  {

-    g_allocCountTemp--;

-    fprintf(stderr, "\nFree_temp; count = %10d", 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 <stdlib.h>
+
+#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 <stdio.h>
+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 c0f89d7..b2b8b0c 100644
--- a/C/7zAlloc.h
+++ b/C/7zAlloc.h
@@ -1,19 +1,19 @@
-/* 7zAlloc.h -- Allocation functions

-2017-04-03 : Igor Pavlov : Public domain */

-

-#ifndef __7Z_ALLOC_H

-#define __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 68cc12f..43fa7c2 100644
--- a/C/7zArcIn.c
+++ b/C/7zArcIn.c
@@ -1,1771 +1,1786 @@
-/* 7zArcIn.c -- 7z Input functions

-2018-12-31 : Igor Pavlov : Public domain */

-

-#include "Precomp.h"

-

-#include <string.h>

-

-#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;

-}

-

-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; }

-

-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;

-}

-

-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(_sd_, dest) if ((_sd_)->Size == 0) return SZ_ERROR_ARCHIVE; (_sd_)->Size--; dest = *(_sd_)->Data++;

-#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 MY_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)

-    {

-      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 MY_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)

-{

-  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)

-{

-  Byte b = 0;

-  unsigned m = 0;

-  UInt32 sum = 0;

-  for (; numItems != 0; numItems--)

-  {

-    if (m == 0)

-    {

-      b = *bits++;

-      m = 8;

-    }

-    m--;

-    sum += ((b >> m) & 1);

-  }

-  return sum;

-}

-

-static MY_NO_INLINE SRes ReadBitVector(CSzData *sd, UInt32 numItems, Byte **v, ISzAllocPtr alloc)

-{

-  Byte allAreDefined;

-  Byte *v2;

-  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);

-  {

-    unsigned numBits = (unsigned)numItems & 7;

-    if (numBits != 0)

-      v2[(size_t)numBytes - 1] = (Byte)((((UInt32)1 << numBits) - 1) << (8 - numBits));

-  }

-  return SZ_OK;

-}

-

-static MY_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)

-  {

-    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;

-    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 = 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 MY_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] = 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;

-        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;

-  

-  {

-    size_t dataSize = 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;

-  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 = 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 = 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 = 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));

-    RINOK(ReadPackInfo(p, sd, alloc));

-    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(

-    ILookInStream *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;

-    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 *)p != 0

-      #else

-      p[0] != 0 || p[1] != 0

-      #endif

-      ; p += 2);

-    pos = p - data + 2;

-    *offsets++ = (pos >> 1);

-  }

-  while (--numFiles);

-  return (pos == size) ? SZ_OK : SZ_ERROR_ARCHIVE;

-}

-

-static MY_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,

-    ILookInStream *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);

-    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 digestsValsIndex = 0;

-    UInt32 digestIndex;

-    Byte allDigestsDefined = 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)

-    {

-      SZ_READ_BYTE_SD(&ssi.sdCRCs, allDigestsDefined);

-      if (allDigestsDefined)

-        digestsVals = ssi.sdCRCs.Data;

-      else

-      {

-        size_t numBytes = (ssi.NumSubDigests + 7) >> 3;

-        digestsDefs = ssi.sdCRCs.Data;

-        digestsVals = digestsDefs + numBytes;

-      }

-    }

-

-    digestIndex = 0;

-    

-    for (i = 0; i < numFiles; i++, mask >>= 1)

-    {

-      if (mask == 0)

-      {

-        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;

-          {

-            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)

-      {

-        UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex);

-        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, i))

-        {

-          p->CRCs.Vals[i] = p->db.FolderCRCs.Vals[folderIndex];

-          crcMask |= mask;

-        }

-        else if (allDigestsDefined || (digestsDefs && SzBitArray_Check(digestsDefs, digestIndex)))

-        {

-          p->CRCs.Vals[i] = GetUi32(digestsVals + (size_t)digestsValsIndex * 4);

-          digestsValsIndex++;

-          crcMask |= mask;

-        }

-        

-        folderIndex++;

-      }

-      else

-      {

-        UInt64 v;

-        RINOK(ReadNumber(&ssi.sdSizes, &v));

-        unpackPos += v;

-        if (unpackPos < v)

-          return SZ_ERROR_ARCHIVE;

-        if (allDigestsDefined || (digestsDefs && SzBitArray_Check(digestsDefs, digestIndex)))

-        {

-          p->CRCs.Vals[i] = GetUi32(digestsVals + (size_t)digestsValsIndex * 4);

-          digestsValsIndex++;

-          crcMask |= mask;

-        }

-      }

-    }

-

-    if (mask != 0x80)

-    {

-      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,

-    ILookInStream *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,

-    ILookInStream *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 = startArcPos + k7zStartHeaderSize;

-  

-  if (CrcCalc(header + 12, 20) != GetUi32(header + 8))

-    return SZ_ERROR_CRC;

-

-  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 < startArcPos + nextHeaderOffset ||

-        (UInt64)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset ||

-        (UInt64)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset + nextHeaderSize)

-      return SZ_ERROR_INPUT_EOF;

-  }

-

-  RINOK(LookInStream_SeekTo(inStream, 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);

-        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, ILookInStream *inStream,

-    ISzAllocPtr allocMain, ISzAllocPtr allocTemp)

-{

-  SRes res = SzArEx_Open2(p, inStream, allocMain, allocTemp);

-  if (res != SZ_OK)

-    SzArEx_Free(p, allocMain);

-  return res;

-}

-

-

-SRes SzArEx_Extract(

-    const CSzArEx *p,

-    ILookInStream *inStream,

-    UInt32 fileIndex,

-    UInt32 *blockIndex,

-    Byte **tempBuf,

-    size_t *outBufferSize,

-    size_t *offset,

-    size_t *outSizeProcessed,

-    ISzAllocPtr allocMain,

-    ISzAllocPtr allocTemp)

-{

-  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)

-  {

-    UInt64 unpackSizeSpec = SzAr_GetFolderUnpackSize(&p->db, folderIndex);

-    /*

-    UInt64 unpackSizeSpec =

-        p->UnpackPositions[p->FolderToFile[(size_t)folderIndex + 1]] -

-        p->UnpackPositions[p->FolderToFile[folderIndex]];

-    */

-    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)

-  {

-    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)

-{

-  size_t offs = p->FileNameOffsets[fileIndex];

-  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-05-11 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include <string.h>
+
+#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)
+{
+  Byte b = 0;
+  unsigned m = 0;
+  UInt32 sum = 0;
+  for (; numItems != 0; numItems--)
+  {
+    if (m == 0)
+    {
+      b = *bits++;
+      m = 8;
+    }
+    m--;
+    sum += ((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 438bba6..8865c32 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 5942d6e..c0ba8a7 100644
--- a/C/7zBuf.h
+++ b/C/7zBuf.h
@@ -1,35 +1,35 @@
-/* 7zBuf.h -- Byte Buffer

-2017-04-03 : Igor Pavlov : Public domain */

-

-#ifndef __7Z_BUF_H

-#define __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 49b4343..2083474 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 <string.h>

-

-#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 <string.h>
+
+#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 40ab759..c995a8b 100644
--- a/C/7zCrc.c
+++ b/C/7zCrc.c
@@ -1,128 +1,340 @@
-/* 7zCrc.c -- CRC32 init

-2017-06-06 : Igor Pavlov : Public domain */

-

-#include "Precomp.h"

-

-#include "7zCrc.h"

-#include "CpuArch.h"

-

-#define kCrcPoly 0xEDB88320

-

-#ifdef MY_CPU_LE

-  #define CRC_NUM_TABLES 8

-#else

-  #define CRC_NUM_TABLES 9

-

-  #define CRC_UINT32_SWAP(v) ((v >> 24) | ((v >> 8) & 0xFF00) | ((v << 8) & 0xFF0000) | (v << 24))

-

-  UInt32 MY_FAST_CALL CrcUpdateT1_BeT4(UInt32 v, const void *data, size_t size, const UInt32 *table);

-  UInt32 MY_FAST_CALL CrcUpdateT1_BeT8(UInt32 v, const void *data, size_t size, const UInt32 *table);

-#endif

-

-#ifndef MY_CPU_BE

-  UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table);

-  UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table);

-#endif

-

-typedef UInt32 (MY_FAST_CALL *CRC_FUNC)(UInt32 v, const void *data, size_t size, const UInt32 *table);

-

-CRC_FUNC g_CrcUpdateT4;

-CRC_FUNC g_CrcUpdateT8;

-CRC_FUNC g_CrcUpdate;

-

-UInt32 g_CrcTable[256 * CRC_NUM_TABLES];

-

-UInt32 MY_FAST_CALL CrcUpdate(UInt32 v, const void *data, size_t size)

-{

-  return g_CrcUpdate(v, data, size, g_CrcTable);

-}

-

-UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size)

-{

-  return g_CrcUpdate(CRC_INIT_VAL, data, size, g_CrcTable) ^ CRC_INIT_VAL;

-}

-

-#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))

-

-UInt32 MY_FAST_CALL CrcUpdateT1(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;

-}

-

-void MY_FAST_CALL CrcGenerateTable()

-{

-  UInt32 i;

-  for (i = 0; i < 256; i++)

-  {

-    UInt32 r = i;

-    unsigned j;

-    for (j = 0; j < 8; j++)

-      r = (r >> 1) ^ (kCrcPoly & ((UInt32)0 - (r & 1)));

-    g_CrcTable[i] = r;

-  }

-  for (i = 256; i < 256 * CRC_NUM_TABLES; i++)

-  {

-    UInt32 r = g_CrcTable[(size_t)i - 256];

-    g_CrcTable[i] = g_CrcTable[r & 0xFF] ^ (r >> 8);

-  }

-

-  #if CRC_NUM_TABLES < 4

-  

-  g_CrcUpdate = CrcUpdateT1;

-  

-  #else

- 

-  #ifdef MY_CPU_LE

-

-    g_CrcUpdateT4 = CrcUpdateT4;

-    g_CrcUpdate = CrcUpdateT4;

-

-    #if CRC_NUM_TABLES >= 8

-      g_CrcUpdateT8 = CrcUpdateT8;

-  

-      #ifdef MY_CPU_X86_OR_AMD64

-      if (!CPU_Is_InOrder())

-      #endif

-        g_CrcUpdate = CrcUpdateT8;

-    #endif

-

-  #else

-  {

-    #ifndef MY_CPU_BE

-    UInt32 k = 0x01020304;

-    const Byte *p = (const Byte *)&k;

-    if (p[0] == 4 && p[1] == 3)

-    {

-      g_CrcUpdateT4 = CrcUpdateT4;

-      g_CrcUpdate = CrcUpdateT4;

-      #if CRC_NUM_TABLES >= 8

-      g_CrcUpdateT8 = CrcUpdateT8;

-      g_CrcUpdate = CrcUpdateT8;

-      #endif

-    }

-    else if (p[0] != 1 || p[1] != 2)

-      g_CrcUpdate = CrcUpdateT1;

-    else

-    #endif

-    {

-      for (i = 256 * CRC_NUM_TABLES - 1; i >= 256; i--)

-      {

-        UInt32 x = g_CrcTable[(size_t)i - 256];

-        g_CrcTable[i] = CRC_UINT32_SWAP(x);

-      }

-      g_CrcUpdateT4 = CrcUpdateT1_BeT4;

-      g_CrcUpdate = CrcUpdateT1_BeT4;

-      #if CRC_NUM_TABLES >= 8

-      g_CrcUpdateT8 = CrcUpdateT1_BeT8;

-      g_CrcUpdate = CrcUpdateT1_BeT8;

-      #endif

-    }

-  }

-  #endif

-

-  #endif

-}

+/* 7zCrc.c -- CRC32 calculation and init
+2023-04-02 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "7zCrc.h"
+#include "CpuArch.h"
+
+#define kCrcPoly 0xEDB88320
+
+#ifdef MY_CPU_LE
+  #define CRC_NUM_TABLES 8
+#else
+  #define CRC_NUM_TABLES 9
+
+  UInt32 Z7_FASTCALL CrcUpdateT1_BeT4(UInt32 v, const void *data, size_t size, const UInt32 *table);
+  UInt32 Z7_FASTCALL CrcUpdateT1_BeT8(UInt32 v, const void *data, size_t size, const UInt32 *table);
+#endif
+
+#ifndef MY_CPU_BE
+  UInt32 Z7_FASTCALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table);
+  UInt32 Z7_FASTCALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table);
+#endif
+
+/*
+extern
+CRC_FUNC g_CrcUpdateT4;
+CRC_FUNC g_CrcUpdateT4;
+*/
+extern
+CRC_FUNC g_CrcUpdateT8;
+CRC_FUNC g_CrcUpdateT8;
+extern
+CRC_FUNC g_CrcUpdateT0_32;
+CRC_FUNC g_CrcUpdateT0_32;
+extern
+CRC_FUNC g_CrcUpdateT0_64;
+CRC_FUNC g_CrcUpdateT0_64;
+extern
+CRC_FUNC g_CrcUpdate;
+CRC_FUNC g_CrcUpdate;
+
+UInt32 g_CrcTable[256 * CRC_NUM_TABLES];
+
+UInt32 Z7_FASTCALL CrcUpdate(UInt32 v, const void *data, size_t size)
+{
+  return g_CrcUpdate(v, data, size, g_CrcTable);
+}
+
+UInt32 Z7_FASTCALL CrcCalc(const void *data, size_t size)
+{
+  return g_CrcUpdate(CRC_INIT_VAL, data, size, g_CrcTable) ^ CRC_INIT_VAL;
+}
+
+#if CRC_NUM_TABLES < 4 \
+   || (CRC_NUM_TABLES == 4 && defined(MY_CPU_BE)) \
+   || (!defined(MY_CPU_LE) && !defined(MY_CPU_BE))
+#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);
+UInt32 Z7_FASTCALL CrcUpdateT1(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;
+}
+#endif
+
+/* ---------- hardware CRC ---------- */
+
+#ifdef MY_CPU_LE
+
+#if defined(MY_CPU_ARM_OR_ARM64)
+
+// #pragma message("ARM*")
+
+  #if defined(_MSC_VER)
+    #if defined(MY_CPU_ARM64)
+    #if (_MSC_VER >= 1910)
+    #ifndef __clang__
+        #define USE_ARM64_CRC
+        #include <intrin.h>
+    #endif
+    #endif
+    #endif
+  #elif (defined(__clang__) && (__clang_major__ >= 3)) \
+     || (defined(__GNUC__) && (__GNUC__ > 4))
+      #if !defined(__ARM_FEATURE_CRC32)
+        #define __ARM_FEATURE_CRC32 1
+        #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)
+            #define ATTRIB_CRC __attribute__((__target__("+crc")))
+          #else
+            #define ATTRIB_CRC __attribute__((__target__("arch=armv8-a+crc")))
+          #endif
+        #endif
+      #endif
+      #if defined(__ARM_FEATURE_CRC32)
+        #define USE_ARM64_CRC
+        #include <arm_acle.h>
+      #endif
+  #endif
+
+#else
+
+// no hardware CRC
+
+// #define USE_CRC_EMU
+
+#ifdef USE_CRC_EMU
+
+#pragma message("ARM64 CRC emulation")
+
+Z7_FORCE_INLINE
+UInt32 __crc32b(UInt32 v, UInt32 data)
+{
+  const UInt32 *table = g_CrcTable;
+  v = CRC_UPDATE_BYTE_2(v, (Byte)data);
+  return v;
+}
+
+Z7_FORCE_INLINE
+UInt32 __crc32w(UInt32 v, UInt32 data)
+{
+  const UInt32 *table = g_CrcTable;
+  v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8;
+  v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8;
+  v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8;
+  v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8;
+  return v;
+}
+
+Z7_FORCE_INLINE
+UInt32 __crc32d(UInt32 v, UInt64 data)
+{
+  const UInt32 *table = g_CrcTable;
+  v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8;
+  v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8;
+  v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8;
+  v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8;
+  v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8;
+  v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8;
+  v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8;
+  v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8;
+  return v;
+}
+
+#endif // USE_CRC_EMU
+
+#endif // defined(MY_CPU_ARM64) && defined(MY_CPU_LE)
+
+
+
+#if defined(USE_ARM64_CRC) || defined(USE_CRC_EMU)
+
+#define T0_32_UNROLL_BYTES (4 * 4)
+#define T0_64_UNROLL_BYTES (4 * 8)
+
+#ifndef ATTRIB_CRC
+#define ATTRIB_CRC
+#endif
+// #pragma message("USE ARM HW CRC")
+
+ATTRIB_CRC
+UInt32 Z7_FASTCALL CrcUpdateT0_32(UInt32 v, const void *data, size_t size, const UInt32 *table);
+ATTRIB_CRC
+UInt32 Z7_FASTCALL CrcUpdateT0_32(UInt32 v, const void *data, size_t size, const UInt32 *table)
+{
+  const Byte *p = (const Byte *)data;
+  UNUSED_VAR(table);
+
+  for (; size != 0 && ((unsigned)(ptrdiff_t)p & (T0_32_UNROLL_BYTES - 1)) != 0; size--)
+    v = __crc32b(v, *p++);
+
+  if (size >= T0_32_UNROLL_BYTES)
+  {
+    const Byte *lim = p + size;
+    size &= (T0_32_UNROLL_BYTES - 1);
+    lim -= size;
+    do
+    {
+      v = __crc32w(v, *(const UInt32 *)(const void *)(p));
+      v = __crc32w(v, *(const UInt32 *)(const void *)(p + 4)); p += 2 * 4;
+      v = __crc32w(v, *(const UInt32 *)(const void *)(p));
+      v = __crc32w(v, *(const UInt32 *)(const void *)(p + 4)); p += 2 * 4;
+    }
+    while (p != lim);
+  }
+  
+  for (; size != 0; size--)
+    v = __crc32b(v, *p++);
+
+  return v;
+}
+
+ATTRIB_CRC
+UInt32 Z7_FASTCALL CrcUpdateT0_64(UInt32 v, const void *data, size_t size, const UInt32 *table);
+ATTRIB_CRC
+UInt32 Z7_FASTCALL CrcUpdateT0_64(UInt32 v, const void *data, size_t size, const UInt32 *table)
+{
+  const Byte *p = (const Byte *)data;
+  UNUSED_VAR(table);
+
+  for (; size != 0 && ((unsigned)(ptrdiff_t)p & (T0_64_UNROLL_BYTES - 1)) != 0; size--)
+    v = __crc32b(v, *p++);
+
+  if (size >= T0_64_UNROLL_BYTES)
+  {
+    const Byte *lim = p + size;
+    size &= (T0_64_UNROLL_BYTES - 1);
+    lim -= size;
+    do
+    {
+      v = __crc32d(v, *(const UInt64 *)(const void *)(p));
+      v = __crc32d(v, *(const UInt64 *)(const void *)(p + 8)); p += 2 * 8;
+      v = __crc32d(v, *(const UInt64 *)(const void *)(p));
+      v = __crc32d(v, *(const UInt64 *)(const void *)(p + 8)); p += 2 * 8;
+    }
+    while (p != lim);
+  }
+  
+  for (; size != 0; size--)
+    v = __crc32b(v, *p++);
+
+  return v;
+}
+
+#undef T0_32_UNROLL_BYTES
+#undef T0_64_UNROLL_BYTES
+
+#endif // defined(USE_ARM64_CRC) || defined(USE_CRC_EMU)
+
+#endif // MY_CPU_LE
+
+
+
+
+void Z7_FASTCALL CrcGenerateTable(void)
+{
+  UInt32 i;
+  for (i = 0; i < 256; i++)
+  {
+    UInt32 r = i;
+    unsigned j;
+    for (j = 0; j < 8; j++)
+      r = (r >> 1) ^ (kCrcPoly & ((UInt32)0 - (r & 1)));
+    g_CrcTable[i] = r;
+  }
+  for (i = 256; i < 256 * CRC_NUM_TABLES; i++)
+  {
+    const UInt32 r = g_CrcTable[(size_t)i - 256];
+    g_CrcTable[i] = g_CrcTable[r & 0xFF] ^ (r >> 8);
+  }
+
+  #if CRC_NUM_TABLES < 4
+    g_CrcUpdate = CrcUpdateT1;
+  #elif defined(MY_CPU_LE)
+    // g_CrcUpdateT4 = CrcUpdateT4;
+    #if CRC_NUM_TABLES < 8
+      g_CrcUpdate = CrcUpdateT4;
+    #else // CRC_NUM_TABLES >= 8
+      g_CrcUpdateT8 = CrcUpdateT8;
+      /*
+      #ifdef MY_CPU_X86_OR_AMD64
+      if (!CPU_Is_InOrder())
+      #endif
+      */
+      g_CrcUpdate = CrcUpdateT8;
+    #endif
+  #else
+  {
+   #ifndef MY_CPU_BE
+    UInt32 k = 0x01020304;
+    const Byte *p = (const Byte *)&k;
+    if (p[0] == 4 && p[1] == 3)
+    {
+      #if CRC_NUM_TABLES < 8
+        // g_CrcUpdateT4 = CrcUpdateT4;
+        g_CrcUpdate   = CrcUpdateT4;
+      #else  // CRC_NUM_TABLES >= 8
+        g_CrcUpdateT8 = CrcUpdateT8;
+        g_CrcUpdate   = CrcUpdateT8;
+      #endif
+    }
+    else if (p[0] != 1 || p[1] != 2)
+      g_CrcUpdate = CrcUpdateT1;
+    else
+   #endif // MY_CPU_BE
+    {
+      for (i = 256 * CRC_NUM_TABLES - 1; i >= 256; i--)
+      {
+        const UInt32 x = g_CrcTable[(size_t)i - 256];
+        g_CrcTable[i] = Z7_BSWAP32(x);
+      }
+      #if CRC_NUM_TABLES <= 4
+        g_CrcUpdate = CrcUpdateT1;
+      #elif CRC_NUM_TABLES <= 8
+        // g_CrcUpdateT4 = CrcUpdateT1_BeT4;
+        g_CrcUpdate   = CrcUpdateT1_BeT4;
+      #else  // CRC_NUM_TABLES > 8
+        g_CrcUpdateT8 = CrcUpdateT1_BeT8;
+        g_CrcUpdate   = CrcUpdateT1_BeT8;
+      #endif
+    }
+  }
+  #endif // CRC_NUM_TABLES < 4
+
+  #ifdef MY_CPU_LE
+    #ifdef USE_ARM64_CRC
+      if (CPU_IsSupported_CRC32())
+      {
+        g_CrcUpdateT0_32 = CrcUpdateT0_32;
+        g_CrcUpdateT0_64 = CrcUpdateT0_64;
+        g_CrcUpdate =
+          #if defined(MY_CPU_ARM)
+            CrcUpdateT0_32;
+          #else
+            CrcUpdateT0_64;
+          #endif
+      }
+    #endif
+    
+    #ifdef USE_CRC_EMU
+      g_CrcUpdateT0_32 = CrcUpdateT0_32;
+      g_CrcUpdateT0_64 = CrcUpdateT0_64;
+      g_CrcUpdate = CrcUpdateT0_64;
+    #endif
+  #endif
+}
+
+#undef kCrcPoly
+#undef CRC64_NUM_TABLES
+#undef CRC_UPDATE_BYTE_2
diff --git a/C/7zCrc.h b/C/7zCrc.h
index 3b04594..4afaeae 100644
--- a/C/7zCrc.h
+++ b/C/7zCrc.h
@@ -1,25 +1,27 @@
-/* 7zCrc.h -- CRC32 calculation

-2013-01-18 : Igor Pavlov : Public domain */

-

-#ifndef __7Z_CRC_H

-#define __7Z_CRC_H

-

-#include "7zTypes.h"

-

-EXTERN_C_BEGIN

-

-extern UInt32 g_CrcTable[];

-

-/* Call CrcGenerateTable one time before other CRC functions */

-void MY_FAST_CALL 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 MY_FAST_CALL CrcUpdate(UInt32 crc, const void *data, size_t size);

-UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size);

-

-EXTERN_C_END

-

-#endif

+/* 7zCrc.h -- CRC32 calculation
+2023-04-02 : 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 *CRC_FUNC)(UInt32 v, const void *data, size_t size, const UInt32 *table);
+
+EXTERN_C_END
+
+#endif
diff --git a/C/7zCrcOpt.c b/C/7zCrcOpt.c
index 2ee0de8..9c64929 100644
--- a/C/7zCrcOpt.c
+++ b/C/7zCrcOpt.c
@@ -1,115 +1,117 @@
-/* 7zCrcOpt.c -- CRC32 calculation

-2017-04-03 : Igor Pavlov : Public domain */

-

-#include "Precomp.h"

-

-#include "CpuArch.h"

-

-#ifndef MY_CPU_BE

-

-#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))

-

-UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table)

-{

-  const Byte *p = (const Byte *)data;

-  for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++)

-    v = CRC_UPDATE_BYTE_2(v, *p);

-  for (; size >= 4; size -= 4, p += 4)

-  {

-    v ^= *(const UInt32 *)p;

-    v =

-          (table + 0x300)[((v      ) & 0xFF)]

-        ^ (table + 0x200)[((v >>  8) & 0xFF)]

-        ^ (table + 0x100)[((v >> 16) & 0xFF)]

-        ^ (table + 0x000)[((v >> 24))];

-  }

-  for (; size > 0; size--, p++)

-    v = CRC_UPDATE_BYTE_2(v, *p);

-  return v;

-}

-

-UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table)

-{

-  const Byte *p = (const Byte *)data;

-  for (; size > 0 && ((unsigned)(ptrdiff_t)p & 7) != 0; size--, p++)

-    v = CRC_UPDATE_BYTE_2(v, *p);

-  for (; size >= 8; size -= 8, p += 8)

-  {

-    UInt32 d;

-    v ^= *(const UInt32 *)p;

-    v =

-          (table + 0x700)[((v      ) & 0xFF)]

-        ^ (table + 0x600)[((v >>  8) & 0xFF)]

-        ^ (table + 0x500)[((v >> 16) & 0xFF)]

-        ^ (table + 0x400)[((v >> 24))];

-    d = *((const UInt32 *)p + 1);

-    v ^=

-          (table + 0x300)[((d      ) & 0xFF)]

-        ^ (table + 0x200)[((d >>  8) & 0xFF)]

-        ^ (table + 0x100)[((d >> 16) & 0xFF)]

-        ^ (table + 0x000)[((d >> 24))];

-  }

-  for (; size > 0; size--, p++)

-    v = CRC_UPDATE_BYTE_2(v, *p);

-  return v;

-}

-

-#endif

-

-

-#ifndef MY_CPU_LE

-

-#define CRC_UINT32_SWAP(v) ((v >> 24) | ((v >> 8) & 0xFF00) | ((v << 8) & 0xFF0000) | (v << 24))

-

-#define CRC_UPDATE_BYTE_2_BE(crc, b) (table[(((crc) >> 24) ^ (b))] ^ ((crc) << 8))

-

-UInt32 MY_FAST_CALL CrcUpdateT1_BeT4(UInt32 v, const void *data, size_t size, const UInt32 *table)

-{

-  const Byte *p = (const Byte *)data;

-  table += 0x100;

-  v = CRC_UINT32_SWAP(v);

-  for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++)

-    v = CRC_UPDATE_BYTE_2_BE(v, *p);

-  for (; size >= 4; size -= 4, p += 4)

-  {

-    v ^= *(const UInt32 *)p;

-    v =

-          (table + 0x000)[((v      ) & 0xFF)]

-        ^ (table + 0x100)[((v >>  8) & 0xFF)]

-        ^ (table + 0x200)[((v >> 16) & 0xFF)]

-        ^ (table + 0x300)[((v >> 24))];

-  }

-  for (; size > 0; size--, p++)

-    v = CRC_UPDATE_BYTE_2_BE(v, *p);

-  return CRC_UINT32_SWAP(v);

-}

-

-UInt32 MY_FAST_CALL CrcUpdateT1_BeT8(UInt32 v, const void *data, size_t size, const UInt32 *table)

-{

-  const Byte *p = (const Byte *)data;

-  table += 0x100;

-  v = CRC_UINT32_SWAP(v);

-  for (; size > 0 && ((unsigned)(ptrdiff_t)p & 7) != 0; size--, p++)

-    v = CRC_UPDATE_BYTE_2_BE(v, *p);

-  for (; size >= 8; size -= 8, p += 8)

-  {

-    UInt32 d;

-    v ^= *(const UInt32 *)p;

-    v =

-          (table + 0x400)[((v      ) & 0xFF)]

-        ^ (table + 0x500)[((v >>  8) & 0xFF)]

-        ^ (table + 0x600)[((v >> 16) & 0xFF)]

-        ^ (table + 0x700)[((v >> 24))];

-    d = *((const UInt32 *)p + 1);

-    v ^=

-          (table + 0x000)[((d      ) & 0xFF)]

-        ^ (table + 0x100)[((d >>  8) & 0xFF)]

-        ^ (table + 0x200)[((d >> 16) & 0xFF)]

-        ^ (table + 0x300)[((d >> 24))];

-  }

-  for (; size > 0; size--, p++)

-    v = CRC_UPDATE_BYTE_2_BE(v, *p);

-  return CRC_UINT32_SWAP(v);

-}

-

-#endif

+/* 7zCrcOpt.c -- CRC32 calculation
+2023-04-02 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "CpuArch.h"
+
+#ifndef MY_CPU_BE
+
+#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
+
+UInt32 Z7_FASTCALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table);
+UInt32 Z7_FASTCALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table)
+{
+  const Byte *p = (const Byte *)data;
+  for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++)
+    v = CRC_UPDATE_BYTE_2(v, *p);
+  for (; size >= 4; size -= 4, p += 4)
+  {
+    v ^= *(const UInt32 *)(const void *)p;
+    v =
+          (table + 0x300)[((v      ) & 0xFF)]
+        ^ (table + 0x200)[((v >>  8) & 0xFF)]
+        ^ (table + 0x100)[((v >> 16) & 0xFF)]
+        ^ (table + 0x000)[((v >> 24))];
+  }
+  for (; size > 0; size--, p++)
+    v = CRC_UPDATE_BYTE_2(v, *p);
+  return v;
+}
+
+UInt32 Z7_FASTCALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table);
+UInt32 Z7_FASTCALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table)
+{
+  const Byte *p = (const Byte *)data;
+  for (; size > 0 && ((unsigned)(ptrdiff_t)p & 7) != 0; size--, p++)
+    v = CRC_UPDATE_BYTE_2(v, *p);
+  for (; size >= 8; size -= 8, p += 8)
+  {
+    UInt32 d;
+    v ^= *(const UInt32 *)(const void *)p;
+    v =
+          (table + 0x700)[((v      ) & 0xFF)]
+        ^ (table + 0x600)[((v >>  8) & 0xFF)]
+        ^ (table + 0x500)[((v >> 16) & 0xFF)]
+        ^ (table + 0x400)[((v >> 24))];
+    d = *((const UInt32 *)(const void *)p + 1);
+    v ^=
+          (table + 0x300)[((d      ) & 0xFF)]
+        ^ (table + 0x200)[((d >>  8) & 0xFF)]
+        ^ (table + 0x100)[((d >> 16) & 0xFF)]
+        ^ (table + 0x000)[((d >> 24))];
+  }
+  for (; size > 0; size--, p++)
+    v = CRC_UPDATE_BYTE_2(v, *p);
+  return v;
+}
+
+#endif
+
+
+#ifndef MY_CPU_LE
+
+#define CRC_UINT32_SWAP(v)  Z7_BSWAP32(v)
+
+#define CRC_UPDATE_BYTE_2_BE(crc, b) (table[(((crc) >> 24) ^ (b))] ^ ((crc) << 8))
+
+UInt32 Z7_FASTCALL CrcUpdateT1_BeT4(UInt32 v, const void *data, size_t size, const UInt32 *table)
+{
+  const Byte *p = (const Byte *)data;
+  table += 0x100;
+  v = CRC_UINT32_SWAP(v);
+  for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++)
+    v = CRC_UPDATE_BYTE_2_BE(v, *p);
+  for (; size >= 4; size -= 4, p += 4)
+  {
+    v ^= *(const UInt32 *)(const void *)p;
+    v =
+          (table + 0x000)[((v      ) & 0xFF)]
+        ^ (table + 0x100)[((v >>  8) & 0xFF)]
+        ^ (table + 0x200)[((v >> 16) & 0xFF)]
+        ^ (table + 0x300)[((v >> 24))];
+  }
+  for (; size > 0; size--, p++)
+    v = CRC_UPDATE_BYTE_2_BE(v, *p);
+  return CRC_UINT32_SWAP(v);
+}
+
+UInt32 Z7_FASTCALL CrcUpdateT1_BeT8(UInt32 v, const void *data, size_t size, const UInt32 *table)
+{
+  const Byte *p = (const Byte *)data;
+  table += 0x100;
+  v = CRC_UINT32_SWAP(v);
+  for (; size > 0 && ((unsigned)(ptrdiff_t)p & 7) != 0; size--, p++)
+    v = CRC_UPDATE_BYTE_2_BE(v, *p);
+  for (; size >= 8; size -= 8, p += 8)
+  {
+    UInt32 d;
+    v ^= *(const UInt32 *)(const void *)p;
+    v =
+          (table + 0x400)[((v      ) & 0xFF)]
+        ^ (table + 0x500)[((v >>  8) & 0xFF)]
+        ^ (table + 0x600)[((v >> 16) & 0xFF)]
+        ^ (table + 0x700)[((v >> 24))];
+    d = *((const UInt32 *)(const void *)p + 1);
+    v ^=
+          (table + 0x000)[((d      ) & 0xFF)]
+        ^ (table + 0x100)[((d >>  8) & 0xFF)]
+        ^ (table + 0x200)[((d >> 16) & 0xFF)]
+        ^ (table + 0x300)[((d >> 24))];
+  }
+  for (; size > 0; size--, p++)
+    v = CRC_UPDATE_BYTE_2_BE(v, *p);
+  return CRC_UINT32_SWAP(v);
+}
+
+#endif
diff --git a/C/7zDec.c b/C/7zDec.c
index 2a7b090..96c6035 100644
--- a/C/7zDec.c
+++ b/C/7zDec.c
@@ -1,591 +1,648 @@
-/* 7zDec.c -- Decoding from 7z folder

-2019-02-02 : Igor Pavlov : Public domain */

-

-#include "Precomp.h"

-

-#include <string.h>

-

-/* #define _7ZIP_PPMD_SUPPPORT */

-

-#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 _7ZIP_PPMD_SUPPPORT

-#include "Ppmd7.h"

-#endif

-

-#define k_Copy 0

-#define k_Delta 3

-#define k_LZMA2 0x21

-#define k_LZMA  0x30101

-#define k_BCJ   0x3030103

-#define k_BCJ2  0x303011B

-#define k_PPC   0x3030205

-#define k_IA64  0x3030401

-#define k_ARM   0x3030501

-#define k_ARMT  0x3030701

-#define k_SPARC 0x3030805

-

-

-#ifdef _7ZIP_PPMD_SUPPPORT

-

-#define k_PPMD 0x30401

-

-typedef struct

-{

-  IByteIn vt;

-  const Byte *cur;

-  const Byte *end;

-  const Byte *begin;

-  UInt64 processed;

-  BoolInt extra;

-  SRes res;

-  const ILookInStream *inStream;

-} CByteInToLook;

-

-static Byte ReadByte(const IByteIn *pp)

-{

-  CByteInToLook *p = CONTAINER_FROM_VTBL(pp, CByteInToLook, vt);

-  if (p->cur != p->end)

-    return *p->cur++;

-  if (p->res == SZ_OK)

-  {

-    size_t size = 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, const ILookInStream *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);

-  }

-  {

-    CPpmd7z_RangeDec rc;

-    Ppmd7z_RangeDec_CreateVTable(&rc);

-    rc.Stream = &s.vt;

-    if (!Ppmd7z_RangeDec_Init(&rc))

-      res = SZ_ERROR_DATA;

-    else if (s.extra)

-      res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA);

-    else

-    {

-      SizeT i;

-      for (i = 0; i < outSize; i++)

-      {

-        int sym = Ppmd7_DecodeSymbol(&ppmd, &rc.vt);

-        if (s.extra || sym < 0)

-          break;

-        outBuffer[i] = (Byte)sym;

-      }

-      if (i != outSize)

-        res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA);

-      else if (s.processed + (s.cur - s.begin) != inSize || !Ppmd7z_RangeDec_IsFinishedOK(&rc))

-        res = SZ_ERROR_DATA;

-    }

-  }

-  Ppmd7_Free(&ppmd, allocMain);

-  return res;

-}

-

-#endif

-

-

-static SRes SzDecodeLzma(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStream *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 _7Z_NO_METHOD_LZMA2

-

-static SRes SzDecodeLzma2(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStream *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, ILookInStream *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 _7Z_NO_METHOD_LZMA2

-    case k_LZMA2:

-    #endif

-    #ifdef _7ZIP_PPMD_SUPPPORT

-    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;

-  }

-  

-  

-  #ifndef _7Z_NO_METHODS_FILTERS

-

-  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)

-    {

-      case k_Delta:

-      case k_BCJ:

-      case k_PPC:

-      case k_IA64:

-      case k_SPARC:

-      case k_ARM:

-      case k_ARMT:

-        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;

-}

-

-#define CASE_BRA_CONV(isa) case k_ ## isa: isa ## _Convert(outBuffer, outSize, 0, 0); break;

-

-static SRes SzFolder_Decode2(const CSzFolder *folder,

-    const Byte *propsData,

-    const UInt64 *unpackSizes,

-    const UInt64 *packPositions,

-    ILookInStream *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)

-      {

-        UInt32 indices[] = { 3, 2, 0 };

-        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 _7Z_NO_METHOD_LZMA2

-      else if (coder->MethodID == k_LZMA2)

-      {

-        RINOK(SzDecodeLzma2(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain));

-      }

-      #endif

-      #ifdef _7ZIP_PPMD_SUPPPORT

-      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)

-    {

-      UInt64 offset = packPositions[1];

-      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 (!Bcj2Dec_IsFinished(&p))

-            return SZ_ERROR_DATA;

-

-          if (p.dest != p.destLim

-             || p.state != BCJ2_STREAM_MAIN)

-            return SZ_ERROR_DATA;

-        }

-      }

-    }

-    #ifndef _7Z_NO_METHODS_FILTERS

-    else if (ci == 1)

-    {

-      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);

-        }

-      }

-      else

-      {

-        if (coder->PropsSize != 0)

-          return SZ_ERROR_UNSUPPORTED;

-        switch (coder->MethodID)

-        {

-          case k_BCJ:

-          {

-            UInt32 state;

-            x86_Convert_Init(state);

-            x86_Convert(outBuffer, outSize, 0, &state, 0);

-            break;

-          }

-          CASE_BRA_CONV(PPC)

-          CASE_BRA_CONV(IA64)

-          CASE_BRA_CONV(SPARC)

-          CASE_BRA_CONV(ARM)

-          CASE_BRA_CONV(ARMT)

-          default:

-            return SZ_ERROR_UNSUPPORTED;

-        }

-      }

-    }

-    #endif

-    else

-      return SZ_ERROR_UNSUPPORTED;

-  }

-

-  return SZ_OK;

-}

-

-

-SRes SzAr_DecodeFolder(const CSzAr *p, UInt32 folderIndex,

-    ILookInStream *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
+2023-04-02 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include <string.h>
+
+/* #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_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:
+    #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);
+        else if (coder->PropsSize != 0)
+          return SZ_ERROR_UNSUPPORTED;
+        z7_BranchConv_ARM64_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_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
+    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 e486901..ba5daa1 100644
--- a/C/7zFile.c
+++ b/C/7zFile.c
@@ -1,286 +1,443 @@
-/* 7zFile.c -- File IO

-2017-04-03 : Igor Pavlov : Public domain */

-

-#include "Precomp.h"

-

-#include "7zFile.h"

-

-#ifndef USE_WINDOWS_FILE

-

-#ifndef UNDER_CE

-#include <errno.h>

-#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"

-*/

-

-#define kChunkSizeMax (1 << 22)

-

-#endif

-

-void File_Construct(CSzFile *p)

-{

-  #ifdef USE_WINDOWS_FILE

-  p->handle = INVALID_HANDLE_VALUE;

-  #else

-  p->file = NULL;

-  #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();

-  #else

-  p->file = fopen(name, writeMode ? "wb+" : "rb");

-  return (p->file != 0) ? 0 :

-    #ifdef UNDER_CE

-    2; /* ENOENT */

-    #else

-    errno;

-    #endif

-  #endif

-}

-

-WRes InFile_Open(CSzFile *p, const char *name) { return File_Open(p, name, 0); }

-WRes OutFile_Open(CSzFile *p, const char *name) { return File_Open(p, name, 1); }

-#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;

-  }

-  #else

-  if (p->file != NULL)

-  {

-    int res = fclose(p->file);

-    if (res != 0)

-      return res;

-    p->file = NULL;

-  }

-  #endif

-  return 0;

-}

-

-WRes File_Read(CSzFile *p, void *data, size_t *size)

-{

-  size_t originalSize = *size;

-  if (originalSize == 0)

-    return 0;

-

-  #ifdef USE_WINDOWS_FILE

-

-  *size = 0;

-  do

-  {

-    DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize;

-    DWORD processed = 0;

-    BOOL res = ReadFile(p->handle, data, curSize, &processed, NULL);

-    data = (void *)((Byte *)data + processed);

-    originalSize -= processed;

-    *size += processed;

-    if (!res)

-      return GetLastError();

-    if (processed == 0)

-      break;

-  }

-  while (originalSize > 0);

-  return 0;

-

-  #else

-  

-  *size = fread(data, 1, originalSize, p->file);

-  if (*size == originalSize)

-    return 0;

-  return ferror(p->file);

-  

-  #endif

-}

-

-WRes File_Write(CSzFile *p, const void *data, size_t *size)

-{

-  size_t originalSize = *size;

-  if (originalSize == 0)

-    return 0;

-  

-  #ifdef USE_WINDOWS_FILE

-

-  *size = 0;

-  do

-  {

-    DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize;

-    DWORD processed = 0;

-    BOOL res = WriteFile(p->handle, data, curSize, &processed, NULL);

-    data = (void *)((Byte *)data + processed);

-    originalSize -= processed;

-    *size += processed;

-    if (!res)

-      return GetLastError();

-    if (processed == 0)

-      break;

-  }

-  while (originalSize > 0);

-  return 0;

-

-  #else

-

-  *size = fwrite(data, 1, originalSize, p->file);

-  if (*size == originalSize)

-    return 0;

-  return ferror(p->file);

-  

-  #endif

-}

-

-WRes File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin)

-{

-  #ifdef USE_WINDOWS_FILE

-

-  LARGE_INTEGER value;

-  DWORD moveMethod;

-  value.LowPart = (DWORD)*pos;

-  value.HighPart = (LONG)((UInt64)*pos >> 16 >> 16); /* for case when UInt64 is 32-bit only */

-  switch (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;

-  }

-  value.LowPart = SetFilePointer(p->handle, value.LowPart, &value.HighPart, moveMethod);

-  if (value.LowPart == 0xFFFFFFFF)

-  {

-    WRes res = GetLastError();

-    if (res != NO_ERROR)

-      return res;

-  }

-  *pos = ((Int64)value.HighPart << 32) | value.LowPart;

-  return 0;

-

-  #else

-  

-  int moveMethod;

-  int res;

-  switch (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 1;

-  }

-  res = fseek(p->file, (long)*pos, moveMethod);

-  *pos = ftell(p->file);

-  return res;

-  

-  #endif

-}

-

-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;

-  

-  #else

-  

-  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;

-  

-  #endif

-}

-

-

-/* ---------- FileSeqInStream ---------- */

-

-static SRes FileSeqInStream_Read(const ISeqInStream *pp, void *buf, size_t *size)

-{

-  CFileSeqInStream *p = CONTAINER_FROM_VTBL(pp, CFileSeqInStream, vt);

-  return File_Read(&p->file, buf, size) == 0 ? SZ_OK : SZ_ERROR_READ;

-}

-

-void FileSeqInStream_CreateVTable(CFileSeqInStream *p)

-{

-  p->vt.Read = FileSeqInStream_Read;

-}

-

-

-/* ---------- FileInStream ---------- */

-

-static SRes FileInStream_Read(const ISeekInStream *pp, void *buf, size_t *size)

-{

-  CFileInStream *p = CONTAINER_FROM_VTBL(pp, CFileInStream, vt);

-  return (File_Read(&p->file, buf, size) == 0) ? SZ_OK : SZ_ERROR_READ;

-}

-

-static SRes FileInStream_Seek(const ISeekInStream *pp, Int64 *pos, ESzSeek origin)

-{

-  CFileInStream *p = CONTAINER_FROM_VTBL(pp, CFileInStream, vt);

-  return File_Seek(&p->file, pos, origin);

-}

-

-void FileInStream_CreateVTable(CFileInStream *p)

-{

-  p->vt.Read = FileInStream_Read;

-  p->vt.Seek = FileInStream_Seek;

-}

-

-

-/* ---------- FileOutStream ---------- */

-

-static size_t FileOutStream_Write(const ISeqOutStream *pp, const void *data, size_t size)

-{

-  CFileOutStream *p = CONTAINER_FROM_VTBL(pp, CFileOutStream, vt);

-  File_Write(&p->file, data, &size);

-  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 <errno.h>
+
+  #ifndef USE_FOPEN
+    #include <stdio.h>
+    #include <fcntl.h>
+    #ifdef _WIN32
+      #include <io.h>
+      typedef int ssize_t;
+      typedef int off_t;
+    #else
+      #include <unistd.h>
+    #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 7e263be..f5069cd 100644
--- a/C/7zFile.h
+++ b/C/7zFile.h
@@ -1,83 +1,92 @@
-/* 7zFile.h -- File IO

-2017-04-03 : Igor Pavlov : Public domain */

-

-#ifndef __7Z_FILE_H

-#define __7Z_FILE_H

-

-#ifdef _WIN32

-#define USE_WINDOWS_FILE

-#endif

-

-#ifdef USE_WINDOWS_FILE

-#include <windows.h>

-#else

-#include <stdio.h>

-#endif

-

-#include "7zTypes.h"

-

-EXTERN_C_BEGIN

-

-/* ---------- File ---------- */

-

-typedef struct

-{

-  #ifdef USE_WINDOWS_FILE

-  HANDLE handle;

-  #else

-  FILE *file;

-  #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;

-} CFileSeqInStream;

-

-void FileSeqInStream_CreateVTable(CFileSeqInStream *p);

-

-

-typedef struct

-{

-  ISeekInStream vt;

-  CSzFile file;

-} CFileInStream;

-

-void FileInStream_CreateVTable(CFileInStream *p);

-

-

-typedef struct

-{

-  ISeqOutStream vt;

-  CSzFile file;

-} 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 <windows.h>
+#endif
+
+#ifdef USE_WINDOWS_FILE
+#include "7zWindows.h"
+
+#else
+// note: USE_FOPEN mode is limited to 32-bit file size
+// #define USE_FOPEN
+// #include <stdio.h>
+#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 579741f..74e75b6 100644
--- a/C/7zStream.c
+++ b/C/7zStream.c
@@ -1,176 +1,199 @@
-/* 7zStream.c -- 7z Stream functions

-2017-04-03 : Igor Pavlov : Public domain */

-

-#include "Precomp.h"

-

-#include <string.h>

-

-#include "7zTypes.h"

-

-SRes SeqInStream_Read2(const ISeqInStream *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(const ISeqInStream *stream, void *buf, size_t size)

-{

-  return SeqInStream_Read2(stream, buf, size, SZ_ERROR_INPUT_EOF);

-}

-

-SRes SeqInStream_ReadByte(const ISeqInStream *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(const ILookInStream *stream, UInt64 offset)

-{

-  Int64 t = offset;

-  return ILookInStream_Seek(stream, &t, SZ_SEEK_SET);

-}

-

-SRes LookInStream_LookRead(const ILookInStream *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(const ILookInStream *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(const ILookInStream *stream, void *buf, size_t size)

-{

-  return LookInStream_Read2(stream, buf, size, SZ_ERROR_INPUT_EOF);

-}

-

-

-

-#define GET_LookToRead2 CLookToRead2 *p = CONTAINER_FROM_VTBL(pp, CLookToRead2, vt);

-

-static SRes LookToRead2_Look_Lookahead(const ILookInStream *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(const ILookInStream *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(const ILookInStream *pp, size_t offset)

-{

-  GET_LookToRead2

-  p->pos += offset;

-  return SZ_OK;

-}

-

-static SRes LookToRead2_Read(const ILookInStream *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(const ILookInStream *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(const ISeqInStream *pp, void *buf, size_t *size)

-{

-  CSecToLook *p = CONTAINER_FROM_VTBL(pp, CSecToLook, vt);

-  return LookInStream_LookRead(p->realStream, buf, size);

-}

-

-void SecToLook_CreateVTable(CSecToLook *p)

-{

-  p->vt.Read = SecToLook_Read;

-}

-

-static SRes SecToRead_Read(const ISeqInStream *pp, void *buf, size_t *size)

-{

-  CSecToRead *p = CONTAINER_FROM_VTBL(pp, CSecToRead, vt);

-  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 <string.h>
+
+#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 593f5aa..1fcb247 100644
--- a/C/7zTypes.h
+++ b/C/7zTypes.h
@@ -1,375 +1,597 @@
-/* 7zTypes.h -- Basic types

-2018-08-04 : Igor Pavlov : Public domain */

-

-#ifndef __7Z_TYPES_H

-#define __7Z_TYPES_H

-

-#ifdef _WIN32

-/* #include <windows.h> */

-#endif

-

-#include <stddef.h>

-

-#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 _WIN32

-

-/* typedef DWORD WRes; */

-typedef unsigned WRes;

-#define MY_SRes_HRESULT_FROM_WRes(x) HRESULT_FROM_WIN32(x)

-

-#else

-

-typedef int WRes;

-#define MY__FACILITY_WIN32 7

-#define MY__FACILITY__WRes MY__FACILITY_WIN32

-#define MY_SRes_HRESULT_FROM_WRes(x) ((HRESULT)(x) <= 0 ? ((HRESULT)(x)) : ((HRESULT) (((x) & 0x0000FFFF) | (MY__FACILITY__WRes << 16) | 0x80000000)))

-

-#endif

-

-

-#ifndef RINOK

-#define RINOK(x) { int __result__ = (x); if (__result__ != 0) return __result__; }

-#endif

-

-typedef unsigned char Byte;

-typedef short Int16;

-typedef unsigned short UInt16;

-

-#ifdef _LZMA_UINT32_IS_ULONG

-typedef long Int32;

-typedef unsigned long UInt32;

-#else

-typedef int Int32;

-typedef unsigned int UInt32;

-#endif

-

-#ifdef _SZ_NO_INT_64

-

-/* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers.

-   NOTES: Some code will work incorrectly in that case! */

-

-typedef long Int64;

-typedef unsigned long UInt64;

-

-#else

-

-#if defined(_MSC_VER) || defined(__BORLANDC__)

-typedef __int64 Int64;

-typedef unsigned __int64 UInt64;

-#define UINT64_CONST(n) n

-#else

-typedef long long int Int64;

-typedef unsigned long long int UInt64;

-#define UINT64_CONST(n) n ## ULL

-#endif

-

-#endif

-

-#ifdef _LZMA_NO_SYSTEM_SIZE_T

-typedef UInt32 SizeT;

-#else

-typedef size_t SizeT;

-#endif

-

-typedef int BoolInt;

-/* typedef BoolInt Bool; */

-#define True 1

-#define False 0

-

-

-#ifdef _WIN32

-#define MY_STD_CALL __stdcall

-#else

-#define MY_STD_CALL

-#endif

-

-#ifdef _MSC_VER

-

-#if _MSC_VER >= 1300

-#define MY_NO_INLINE __declspec(noinline)

-#else

-#define MY_NO_INLINE

-#endif

-

-#define MY_FORCE_INLINE __forceinline

-

-#define MY_CDECL __cdecl

-#define MY_FAST_CALL __fastcall

-

-#else

-

-#define MY_NO_INLINE

-#define MY_FORCE_INLINE

-#define MY_CDECL

-#define MY_FAST_CALL

-

-/* inline keyword : for C++ / C99 */

-

-/* GCC, clang: */

-/*

-#if defined (__GNUC__) && (__GNUC__ >= 4)

-#define MY_FORCE_INLINE __attribute__((always_inline))

-#define MY_NO_INLINE __attribute__((noinline))

-#endif

-*/

-

-#endif

-

-

-/* The following interfaces use first parameter as pointer to structure */

-

-typedef struct IByteIn IByteIn;

-struct IByteIn

-{

-  Byte (*Read)(const IByteIn *p); /* reads one byte, returns 0 in case of EOF or error */

-};

-#define IByteIn_Read(p) (p)->Read(p)

-

-

-typedef struct IByteOut IByteOut;

-struct IByteOut

-{

-  void (*Write)(const IByteOut *p, Byte b);

-};

-#define IByteOut_Write(p, b) (p)->Write(p, b)

-

-

-typedef struct ISeqInStream ISeqInStream;

-struct ISeqInStream

-{

-  SRes (*Read)(const ISeqInStream *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)

-

-/* it can return SZ_ERROR_INPUT_EOF */

-SRes SeqInStream_Read(const ISeqInStream *stream, void *buf, size_t size);

-SRes SeqInStream_Read2(const ISeqInStream *stream, void *buf, size_t size, SRes errorType);

-SRes SeqInStream_ReadByte(const ISeqInStream *stream, Byte *buf);

-

-

-typedef struct ISeqOutStream ISeqOutStream;

-struct ISeqOutStream

-{

-  size_t (*Write)(const ISeqOutStream *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;

-

-

-typedef struct ISeekInStream ISeekInStream;

-struct ISeekInStream

-{

-  SRes (*Read)(const ISeekInStream *p, void *buf, size_t *size);  /* same as ISeqInStream::Read */

-  SRes (*Seek)(const ISeekInStream *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)

-

-

-typedef struct ILookInStream ILookInStream;

-struct ILookInStream

-{

-  SRes (*Look)(const ILookInStream *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)(const ILookInStream *p, size_t offset);

-    /* offset must be <= output(*size) of Look */

-

-  SRes (*Read)(const ILookInStream *p, void *buf, size_t *size);

-    /* reads directly (without buffer). It's same as ISeqInStream::Read */

-  SRes (*Seek)(const ILookInStream *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(const ILookInStream *stream, void *buf, size_t *size);

-SRes LookInStream_SeekTo(const ILookInStream *stream, UInt64 offset);

-

-/* reads via ILookInStream::Read */

-SRes LookInStream_Read2(const ILookInStream *stream, void *buf, size_t size, SRes errorType);

-SRes LookInStream_Read(const ILookInStream *stream, void *buf, size_t size);

-

-

-

-typedef struct

-{

-  ILookInStream vt;

-  const ISeekInStream *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;

-  const ILookInStream *realStream;

-} CSecToLook;

-

-void SecToLook_CreateVTable(CSecToLook *p);

-

-

-

-typedef struct

-{

-  ISeqInStream vt;

-  const ILookInStream *realStream;

-} CSecToRead;

-

-void SecToRead_CreateVTable(CSecToRead *p);

-

-

-typedef struct ICompressProgress ICompressProgress;

-

-struct ICompressProgress

-{

-  SRes (*Progress)(const ICompressProgress *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 MY_container_of

-

-/*

-#define MY_container_of(ptr, type, m) container_of(ptr, type, m)

-#define MY_container_of(ptr, type, m) CONTAINING_RECORD(ptr, type, m)

-#define MY_container_of(ptr, type, m) ((type *)((char *)(ptr) - offsetof(type, m)))

-#define MY_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 MY_container_of(ptr, type, m) ((type *)((char *)(1 ? (ptr) : &((type *)0)->m) - MY_offsetof(type, m)))

-

-

-#endif

-

-#define CONTAINER_FROM_VTBL_SIMPLE(ptr, type, m) ((type *)(ptr))

-

-/*

-#define CONTAINER_FROM_VTBL(ptr, type, m) CONTAINER_FROM_VTBL_SIMPLE(ptr, type, m)

-*/

-#define CONTAINER_FROM_VTBL(ptr, type, m) MY_container_of(ptr, type, m)

-

-#define CONTAINER_FROM_VTBL_CLS(ptr, type, m) CONTAINER_FROM_VTBL_SIMPLE(ptr, type, m)

-/*

-#define CONTAINER_FROM_VTBL_CLS(ptr, type, m) CONTAINER_FROM_VTBL(ptr, type, m)

-*/

-

-

-

-#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

-

-EXTERN_C_END

-

-#endif

+/* 7zTypes.h -- Basic types
+2023-04-02 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_7Z_TYPES_H
+#define ZIP7_7Z_TYPES_H
+
+#ifdef _WIN32
+/* #include <windows.h> */
+#else
+#include <errno.h>
+#endif
+
+#include <stddef.h>
+
+#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 <stdalign.h>
+  #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 <stdint.h>
+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 <stdint.h>
+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_DIAGNOSCTIC_IGNORE_BEGIN_CAST_QUAL \
+  _Pragma("GCC diagnostic push") \
+  _Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
+#define Z7_DIAGNOSCTIC_IGNORE_END_CAST_QUAL \
+  _Pragma("GCC diagnostic pop")
+#else
+#define Z7_DIAGNOSCTIC_IGNORE_BEGIN_CAST_QUAL
+#define Z7_DIAGNOSCTIC_IGNORE_END_CAST_QUAL
+#endif
+
+#define Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR(ptr, type, m, p) \
+  Z7_DIAGNOSCTIC_IGNORE_BEGIN_CAST_QUAL \
+  type *p = Z7_CONTAINER_FROM_VTBL(ptr, type, m); \
+  Z7_DIAGNOSCTIC_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 0074c64..7549239 100644
--- a/C/7zVersion.h
+++ b/C/7zVersion.h
@@ -1,27 +1,27 @@
-#define MY_VER_MAJOR 19

-#define MY_VER_MINOR 00

-#define MY_VER_BUILD 0

-#define MY_VERSION_NUMBERS "19.00"

-#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 "2019-02-21"

-#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-2018 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 23
+#define MY_VER_MINOR 01
+#define MY_VER_BUILD 0
+#define MY_VERSION_NUMBERS "23.01"
+#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 "2023-06-20"
+#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-2023 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 6ed26de..e520995 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 <WinVer.h>

-

-#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 <WinVer.h>
+
+#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
new file mode 100644
index 0000000..42c6db8
--- /dev/null
+++ b/C/7zWindows.h
@@ -0,0 +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 <windows.h>
+#else
+#include <Windows.h>
+#endif
+// #include <basetsd.h>
+// #include <wtypes.h>
+
+// but if precompiled with clang-cl then we need
+// #include <windows.h>
+#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
new file mode 100644
index 0000000..f19a99b
--- /dev/null
+++ b/C/7zip_gcc_c.mak
@@ -0,0 +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 =
+FLAGS_FLTO = -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) $<
+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 8f7d50e..bcaafab 100644
--- a/C/Aes.c
+++ b/C/Aes.c
@@ -1,306 +1,393 @@
-/* Aes.c -- AES encryption / decryption

-2017-01-24 : Igor Pavlov : Public domain */

-

-#include "Precomp.h"

-

-#include "Aes.h"

-#include "CpuArch.h"

-

-static UInt32 T[256 * 4];

-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};

-

-void MY_FAST_CALL AesCbc_Encode(UInt32 *ivAes, Byte *data, size_t numBlocks);

-void MY_FAST_CALL AesCbc_Decode(UInt32 *ivAes, Byte *data, size_t numBlocks);

-void MY_FAST_CALL AesCtr_Code(UInt32 *ivAes, Byte *data, size_t numBlocks);

-

-void MY_FAST_CALL AesCbc_Encode_Intel(UInt32 *ivAes, Byte *data, size_t numBlocks);

-void MY_FAST_CALL AesCbc_Decode_Intel(UInt32 *ivAes, Byte *data, size_t numBlocks);

-void MY_FAST_CALL AesCtr_Code_Intel(UInt32 *ivAes, Byte *data, size_t numBlocks);

-

-AES_CODE_FUNC g_AesCbc_Encode;

-AES_CODE_FUNC g_AesCbc_Decode;

-AES_CODE_FUNC g_AesCtr_Code;

-

-static UInt32 D[256 * 4];

-static Byte InvS[256];

-

-static const Byte Rcon[11] = { 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 };

-

-#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))

-

-

-void AesGenTables(void)

-{

-  unsigned i;

-  for (i = 0; i < 256; i++)

-    InvS[Sbox[i]] = (Byte)i;

-  

-  for (i = 0; i < 256; i++)

-  {

-    {

-      UInt32 a1 = Sbox[i];

-      UInt32 a2 = xtime(a1);

-      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);

-    }

-    {

-      UInt32 a1 = InvS[i];

-      UInt32 a2 = xtime(a1);

-      UInt32 a4 = xtime(a2);

-      UInt32 a8 = xtime(a4);

-      UInt32 a9 = a8 ^ a1;

-      UInt32 aB = a8 ^ a2 ^ a1;

-      UInt32 aD = a8 ^ a4 ^ a1;

-      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);

-    }

-  }

-  

-  g_AesCbc_Encode = AesCbc_Encode;

-  g_AesCbc_Decode = AesCbc_Decode;

-  g_AesCtr_Code = AesCtr_Code;

-  

-  #ifdef MY_CPU_X86_OR_AMD64

-  if (CPU_Is_Aes_Supported())

-  {

-    g_AesCbc_Encode = AesCbc_Encode_Intel;

-    g_AesCbc_Decode = AesCbc_Decode_Intel;

-    g_AesCtr_Code = AesCtr_Code_Intel;

-  }

-  #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 MY_FAST_CALL Aes_SetKey_Enc(UInt32 *w, const Byte *key, unsigned keySize)

-{

-  unsigned i, wSize;

-  wSize = keySize + 28;

-  keySize /= 4;

-  w[0] = ((UInt32)keySize / 2) + 3;

-  w += 4;

-

-  for (i = 0; i < keySize; i++, key += 4)

-    w[i] = GetUi32(key);

-

-  for (; i < wSize; i++)

-  {

-    UInt32 t = w[(size_t)i - 1];

-    unsigned rem = i % keySize;

-    if (rem == 0)

-      t = Ui32(Sbox[gb1(t)] ^ Rcon[i / keySize], Sbox[gb2(t)], Sbox[gb3(t)], Sbox[gb0(t)]);

-    else if (keySize > 6 && rem == 4)

-      t = Ui32(Sbox[gb0(t)], Sbox[gb1(t)], Sbox[gb2(t)], Sbox[gb3(t)]);

-    w[i] = w[i - keySize] ^ t;

-  }

-}

-

-void MY_FAST_CALL 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 */

-

-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);

-}

-

-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 MY_FAST_CALL 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 MY_FAST_CALL 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 MY_FAST_CALL 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)

-    {

-      UInt32 t = temp[i];

-

-      #ifdef MY_CPU_LE_UNALIGN

-        *((UInt32 *)data) ^= t;

-      #else

-        data[0] ^= (t & 0xFF);

-        data[1] ^= ((t >> 8) & 0xFF);

-        data[2] ^= ((t >> 16) & 0xFF);

-        data[3] ^= ((t >> 24));

-      #endif

-    }

-  }

-}

+/* Aes.c -- AES encryption / decryption
+2023-04-02 : 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
+
+static UInt32 T[256 * 4];
+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};
+
+
+static UInt32 D[256 * 4];
+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
+  #define USE_HW_AES
+#elif defined(MY_CPU_ARM_OR_ARM64) && defined(MY_CPU_LE)
+  #if defined(__clang__)
+    #if (__clang_major__ >= 8) // fix that check
+      #define USE_HW_AES
+    #endif
+  #elif defined(__GNUC__)
+    #if (__GNUC__ >= 6) // fix that check
+      #define USE_HW_AES
+    #endif
+  #elif defined(_MSC_VER)
+    #if _MSC_VER >= 1910
+      #define USE_HW_AES
+    #endif
+  #endif
+#endif
+
+#ifdef USE_HW_AES
+#ifdef Z7_SHOW_AES_STATUS
+#include <stdio.h>
+#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
+    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
+
+  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 381e979..7f0182a 100644
--- a/C/Aes.h
+++ b/C/Aes.h
@@ -1,38 +1,60 @@
-/* Aes.h -- AES encryption / decryption

-2013-01-18 : Igor Pavlov : Public domain */

-

-#ifndef __AES_H

-#define __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 (MY_FAST_CALL *AES_SET_KEY_FUNC)(UInt32 *aes, const Byte *key, unsigned keySize);

-void MY_FAST_CALL Aes_SetKey_Enc(UInt32 *aes, const Byte *key, unsigned keySize);

-void MY_FAST_CALL 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 (MY_FAST_CALL *AES_CODE_FUNC)(UInt32 *ivAes, Byte *data, size_t numBlocks);

-extern AES_CODE_FUNC g_AesCbc_Encode;

-extern AES_CODE_FUNC g_AesCbc_Decode;

-extern AES_CODE_FUNC g_AesCtr_Code;

-

-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 0e7f49a..cfa6413 100644
--- a/C/AesOpt.c
+++ b/C/AesOpt.c
@@ -1,184 +1,840 @@
-/* AesOpt.c -- Intel's AES

-2017-06-08 : Igor Pavlov : Public domain */

-

-#include "Precomp.h"

-

-#include "CpuArch.h"

-

-#ifdef MY_CPU_X86_OR_AMD64

-#if (_MSC_VER > 1500) || (_MSC_FULL_VER >= 150030729)

-#define USE_INTEL_AES

-#endif

-#endif

-

-#ifdef USE_INTEL_AES

-

-#include <wmmintrin.h>

-

-void MY_FAST_CALL AesCbc_Encode_Intel(__m128i *p, __m128i *data, size_t numBlocks)

-{

-  __m128i m = *p;

-  for (; numBlocks != 0; numBlocks--, data++)

-  {

-    UInt32 numRounds2 = *(const UInt32 *)(p + 1) - 1;

-    const __m128i *w = p + 3;

-    m = _mm_xor_si128(m, *data);

-    m = _mm_xor_si128(m, p[2]);

-    do

-    {

-      m = _mm_aesenc_si128(m, w[0]);

-      m = _mm_aesenc_si128(m, w[1]);

-      w += 2;

-    }

-    while (--numRounds2 != 0);

-    m = _mm_aesenc_si128(m, w[0]);

-    m = _mm_aesenclast_si128(m, w[1]);

-    *data = m;

-  }

-  *p = m;

-}

-

-#define NUM_WAYS 3

-

-#define AES_OP_W(op, n) { \

-    const __m128i t = w[n]; \

-    m0 = op(m0, t); \

-    m1 = op(m1, t); \

-    m2 = op(m2, t); \

-    }

-

-#define AES_DEC(n) AES_OP_W(_mm_aesdec_si128, n)

-#define AES_DEC_LAST(n) AES_OP_W(_mm_aesdeclast_si128, n)

-#define AES_ENC(n) AES_OP_W(_mm_aesenc_si128, n)

-#define AES_ENC_LAST(n) AES_OP_W(_mm_aesenclast_si128, n)

-

-void MY_FAST_CALL AesCbc_Decode_Intel(__m128i *p, __m128i *data, size_t numBlocks)

-{

-  __m128i iv = *p;

-  for (; numBlocks >= NUM_WAYS; numBlocks -= NUM_WAYS, data += NUM_WAYS)

-  {

-    UInt32 numRounds2 = *(const UInt32 *)(p + 1);

-    const __m128i *w = p + numRounds2 * 2;

-    __m128i m0, m1, m2;

-    {

-      const __m128i t = w[2];

-      m0 = _mm_xor_si128(t, data[0]);

-      m1 = _mm_xor_si128(t, data[1]);

-      m2 = _mm_xor_si128(t, data[2]);

-    }

-    numRounds2--;

-    do

-    {

-      AES_DEC(1)

-      AES_DEC(0)

-      w -= 2;

-    }

-    while (--numRounds2 != 0);

-    AES_DEC(1)

-    AES_DEC_LAST(0)

-

-    {

-      __m128i t;

-      t = _mm_xor_si128(m0, iv); iv = data[0]; data[0] = t;

-      t = _mm_xor_si128(m1, iv); iv = data[1]; data[1] = t;

-      t = _mm_xor_si128(m2, iv); iv = data[2]; data[2] = t;

-    }

-  }

-  for (; numBlocks != 0; numBlocks--, data++)

-  {

-    UInt32 numRounds2 = *(const UInt32 *)(p + 1);

-    const __m128i *w = p + numRounds2 * 2;

-    __m128i m = _mm_xor_si128(w[2], *data);

-    numRounds2--;

-    do

-    {

-      m = _mm_aesdec_si128(m, w[1]);

-      m = _mm_aesdec_si128(m, w[0]);

-      w -= 2;

-    }

-    while (--numRounds2 != 0);

-    m = _mm_aesdec_si128(m, w[1]);

-    m = _mm_aesdeclast_si128(m, w[0]);

-

-    m = _mm_xor_si128(m, iv);

-    iv = *data;

-    *data = m;

-  }

-  *p = iv;

-}

-

-void MY_FAST_CALL AesCtr_Code_Intel(__m128i *p, __m128i *data, size_t numBlocks)

-{

-  __m128i ctr = *p;

-  __m128i one;

-  one.m128i_u64[0] = 1;

-  one.m128i_u64[1] = 0;

-  for (; numBlocks >= NUM_WAYS; numBlocks -= NUM_WAYS, data += NUM_WAYS)

-  {

-    UInt32 numRounds2 = *(const UInt32 *)(p + 1) - 1;

-    const __m128i *w = p;

-    __m128i m0, m1, m2;

-    {

-      const __m128i t = w[2];

-      ctr = _mm_add_epi64(ctr, one); m0 = _mm_xor_si128(ctr, t);

-      ctr = _mm_add_epi64(ctr, one); m1 = _mm_xor_si128(ctr, t);

-      ctr = _mm_add_epi64(ctr, one); m2 = _mm_xor_si128(ctr, t);

-    }

-    w += 3;

-    do

-    {

-      AES_ENC(0)

-      AES_ENC(1)

-      w += 2;

-    }

-    while (--numRounds2 != 0);

-    AES_ENC(0)

-    AES_ENC_LAST(1)

-    data[0] = _mm_xor_si128(data[0], m0);

-    data[1] = _mm_xor_si128(data[1], m1);

-    data[2] = _mm_xor_si128(data[2], m2);

-  }

-  for (; numBlocks != 0; numBlocks--, data++)

-  {

-    UInt32 numRounds2 = *(const UInt32 *)(p + 1) - 1;

-    const __m128i *w = p;

-    __m128i m;

-    ctr = _mm_add_epi64(ctr, one);

-    m = _mm_xor_si128(ctr, p[2]);

-    w += 3;

-    do

-    {

-      m = _mm_aesenc_si128(m, w[0]);

-      m = _mm_aesenc_si128(m, w[1]);

-      w += 2;

-    }

-    while (--numRounds2 != 0);

-    m = _mm_aesenc_si128(m, w[0]);

-    m = _mm_aesenclast_si128(m, w[1]);

-    *data = _mm_xor_si128(*data, m);

-  }

-  *p = ctr;

-}

-

-#else

-

-void MY_FAST_CALL AesCbc_Encode(UInt32 *ivAes, Byte *data, size_t numBlocks);

-void MY_FAST_CALL AesCbc_Decode(UInt32 *ivAes, Byte *data, size_t numBlocks);

-void MY_FAST_CALL AesCtr_Code(UInt32 *ivAes, Byte *data, size_t numBlocks);

-

-void MY_FAST_CALL AesCbc_Encode_Intel(UInt32 *p, Byte *data, size_t numBlocks)

-{

-  AesCbc_Encode(p, data, numBlocks);

-}

-

-void MY_FAST_CALL AesCbc_Decode_Intel(UInt32 *p, Byte *data, size_t numBlocks)

-{

-  AesCbc_Decode(p, data, numBlocks);

-}

-

-void MY_FAST_CALL AesCtr_Code_Intel(UInt32 *p, Byte *data, size_t numBlocks)

-{

-  AesCtr_Code(p, data, numBlocks);

-}

-

-#endif

+/* AesOpt.c -- AES optimized code for x86 AES hardware instructions
+2023-04-02 : 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(__clang__) && (__clang_major__ > 3 || __clang_major__ == 3 && __clang_minor__ >= 8) \
+       || defined(__GNUC__) && (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 4)
+        #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
+  #endif
+
+#ifndef ATTRIB_AES
+  #define ATTRIB_AES
+#endif
+#ifndef ATTRIB_VAES
+  #define ATTRIB_VAES
+#endif
+
+
+#ifdef USE_INTEL_AES
+
+#include <wmmintrin.h>
+
+#ifndef USE_INTEL_VAES
+#define AES_TYPE_keys UInt32
+#define AES_TYPE_data Byte
+// #define AES_TYPE_keys __m128i
+// #define AES_TYPE_data __m128i
+#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)
+#define AVX_XOR(dest, src)    MM_OP(_mm256_xor_si256, 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 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;
+#define AVX_XOR_data_M1(reg, ii)  AVX_XOR (reg, (((const __m256i *)(const void *)(data - 1))[ii]))
+
+#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 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 CTR_START(reg, ii)  MM_OP (_mm_add_epi64, ctr, one)  reg = ctr;
+#define CTR_END(  reg, ii)  MM_XOR (data[ii], 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 WOP_KEY(op, n) { \
+    const __m128i key = w[n]; \
+    WOP(op); }
+
+#define AVX_WOP_KEY(op, n) { \
+    const __m256i 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++)
+
+
+#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. */
+
+
+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:
+  <immintrin.h>:
+    #ifdef __AVX__
+     #include <avxintrin.h>
+    #endif
+GCC after 2013-Jun:
+  <immintrin.h>:
+    #include <avxintrin.h>
+CLANG 3.8+:
+{
+  <immintrin.h>:
+    #if !defined(_MSC_VER) || defined(__AVX__)
+      #include <avxintrin.h>
+    #endif
+
+  if (the compiler is clang for Windows and if global arch is not set for __AVX__)
+    [ if (defined(_MSC_VER) && !defined(__AVX__)) ]
+  {
+    <immintrin.h> doesn't include <avxintrin.h>
+    and we have 2 ways to fix it:
+      1) we can define required __AVX__ before <immintrin.h>
+      or
+      2) we can include <avxintrin.h> after <immintrin.h>
+  }
+}
+
+If we include <avxintrin.h> manually for GCC/CLANG, it's
+required that <immintrin.h> must be included before <avxintrin.h>.
+*/
+
+/*
+#if defined(__clang__) && defined(_MSC_VER)
+#define __AVX__
+#define __AVX2__
+#define __VAES__
+#endif
+*/
+
+#include <immintrin.h>
+#if defined(__clang__) && defined(_MSC_VER)
+  #if !defined(__AVX__)
+    #include <avxintrin.h>
+  #endif
+  #if !defined(__AVX2__)
+    #include <avx2intrin.h>
+  #endif
+  #if !defined(__VAES__)
+    #include <vaesintrin.h>
+  #endif
+#endif  // __clang__ && _MSC_VER
+
+
+#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 */
+
+#pragma message("AES  HW_SW stub was used")
+
+#define AES_TYPE_keys UInt32
+#define AES_TYPE_data Byte
+
+#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 // USE_INTEL_AES
+
+
+#ifndef USE_INTEL_VAES
+
+#pragma message("VAES HW_SW stub was used")
+
+#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 // ! USE_INTEL_VAES
+
+
+#elif defined(MY_CPU_ARM_OR_ARM64) && defined(MY_CPU_LE)
+
+  #if defined(__clang__)
+    #if (__clang_major__ >= 8) // fix that check
+      #define USE_HW_AES
+    #endif
+  #elif defined(__GNUC__)
+    #if (__GNUC__ >= 6) // fix that check
+      #define USE_HW_AES
+    #endif
+  #elif defined(_MSC_VER)
+    #if _MSC_VER >= 1910
+      #define USE_HW_AES
+    #endif
+  #endif
+
+#ifdef USE_HW_AES
+
+// #pragma message("=== AES HW === ")
+
+#if defined(__clang__) || defined(__GNUC__)
+  #ifdef MY_CPU_ARM64
+    #define ATTRIB_AES __attribute__((__target__("+crypto")))
+  #else
+    #define ATTRIB_AES __attribute__((__target__("fpu=crypto-neon-fp-armv8")))
+  #endif
+#else
+  // _MSC_VER
+  // for arm32
+  #define _ARM_USE_NEW_NEON_INTRINSICS
+#endif
+
+#ifndef ATTRIB_AES
+  #define ATTRIB_AES
+#endif
+
+#if defined(_MSC_VER) && defined(MY_CPU_ARM64)
+#include <arm64_neon.h>
+#else
+#include <arm_neon.h>
+#endif
+
+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 *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);
+  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
diff --git a/C/Alloc.c b/C/Alloc.c
index 30b499e..d841bf2 100644
--- a/C/Alloc.c
+++ b/C/Alloc.c
@@ -1,455 +1,535 @@
-/* Alloc.c -- Memory allocation functions

-2018-04-27 : Igor Pavlov : Public domain */

-

-#include "Precomp.h"

-

-#include <stdio.h>

-

-#ifdef _WIN32

-#include <windows.h>

-#endif

-#include <stdlib.h>

-

-#include "Alloc.h"

-

-/* #define _SZ_ALLOC_DEBUG */

-

-/* use _SZ_ALLOC_DEBUG to debug alloc/free operations */

-#ifdef _SZ_ALLOC_DEBUG

-

-#include <stdio.h>

-int g_allocCount = 0;

-int g_allocCountMid = 0;

-int g_allocCountBig = 0;

-

-

-#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++ = 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()

-{

-  Print("\n");

-}

-

-static void PrintHex(UInt64 v, size_t align)

-{

-  char s[32];

-  ConvertUInt64ToHex(v, s);

-  PrintAligned(s, align);

-}

-

-static void PrintDec(UInt64 v, size_t align)

-{

-  char s[32];

-  ConvertUInt64ToString(v, s);

-  PrintAligned(s, align);

-}

-

-static void PrintAddr(void *p)

-{

-  PrintHex((UInt64)(size_t)(ptrdiff_t)p, 12);

-}

-

-

-#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

-

-#define PRINT_ALLOC(name, cnt, size, ptr)

-#define PRINT_FREE(name, cnt, ptr)

-#define Print(s)

-#define PrintLn()

-#define PrintHex(v, align)

-#define PrintDec(v, align)

-#define PrintAddr(p)

-

-#endif

-

-

-

-void *MyAlloc(size_t size)

-{

-  if (size == 0)

-    return NULL;

-  #ifdef _SZ_ALLOC_DEBUG

-  {

-    void *p = malloc(size);

-    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);

-}

-

-#ifdef _WIN32

-

-void *MidAlloc(size_t size)

-{

-  if (size == 0)

-    return NULL;

-  

-  PRINT_ALLOC("Alloc-Mid", g_allocCountMid, size, NULL);

-  

-  return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);

-}

-

-void MidFree(void *address)

-{

-  PRINT_FREE("Free-Mid", g_allocCountMid, address);

-

-  if (!address)

-    return;

-  VirtualFree(address, 0, MEM_RELEASE);

-}

-

-#ifndef MEM_LARGE_PAGES

-#undef _7ZIP_LARGE_PAGES

-#endif

-

-#ifdef _7ZIP_LARGE_PAGES

-SIZE_T g_LargePageSize = 0;

-typedef SIZE_T (WINAPI *GetLargePageMinimumP)();

-#endif

-

-void SetLargePageSize()

-{

-  #ifdef _7ZIP_LARGE_PAGES

-  SIZE_T size;

-  GetLargePageMinimumP largePageMinimum = (GetLargePageMinimumP)

-        GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "GetLargePageMinimum");

-  if (!largePageMinimum)

-    return;

-  size = largePageMinimum();

-  if (size == 0 || (size & (size - 1)) != 0)

-    return;

-  g_LargePageSize = size;

-  #endif

-}

-

-

-void *BigAlloc(size_t size)

-{

-  if (size == 0)

-    return NULL;

-

-  PRINT_ALLOC("Alloc-Big", g_allocCountBig, size, NULL);

-  

-  #ifdef _7ZIP_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 *res = VirtualAlloc(NULL, size2, MEM_COMMIT | MEM_LARGE_PAGES, PAGE_READWRITE);

-        if (res)

-          return res;

-      }

-    }

-  }

-  #endif

-

-  return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);

-}

-

-void BigFree(void *address)

-{

-  PRINT_FREE("Free-Big", g_allocCountBig, address);

-  

-  if (!address)

-    return;

-  VirtualFree(address, 0, MEM_RELEASE);

-}

-

-#endif

-

-

-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 };

-

-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); }

-const ISzAlloc g_MidAlloc = { SzMidAlloc, SzMidFree };

-

-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_BigAlloc = { SzBigAlloc, SzBigFree };

-

-

-/*

-  uintptr_t : <stdint.h> C99 (optional)

-            : unsupported in VS6

-*/

-

-#ifdef _WIN32

-  typedef UINT_PTR UIntPtr;

-#else

-  /*

-  typedef uintptr_t UIntPtr;

-  */

-  typedef ptrdiff_t UIntPtr;

-#endif

-

-

-#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 *).

-*/

-

-

-/*

-#define MY_ALIGN_PTR_DOWN(p, align) ((void *)((char *)(p) - ((size_t)(UIntPtr)(p) & ((align) - 1))))

-*/

-#define MY_ALIGN_PTR_DOWN(p, align) ((void *)((((UIntPtr)(p)) & ~((UIntPtr)(align) - 1))))

-

-#define MY_ALIGN_PTR_UP_PLUS(p, align) MY_ALIGN_PTR_DOWN(((char *)(p) + (align) + ADJUST_ALLOC_SIZE), align)

-

-

-#if (_POSIX_C_SOURCE >= 200112L) && !defined(_WIN32)

-  #define USE_posix_memalign

-#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)

-

-static void *SzAlignedAlloc(ISzAllocPtr pp, size_t size)

-{

-  #ifndef USE_posix_memalign

-  

-  void *p;

-  void *pAligned;

-  size_t newSize;

-  UNUSED_VAR(pp);

-

-  /* 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;

-  UNUSED_VAR(pp);

-  if (posix_memalign(&p, ALLOC_ALIGN_SIZE, size))

-    return NULL;

-

-  Print(" posix_memalign="); PrintAddr(p);

-  PrintLn();

-

-  return p;

-

-  #endif

-}

-

-

-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 };

-

-

-

-#define MY_ALIGN_PTR_DOWN_1(p) MY_ALIGN_PTR_DOWN(p, sizeof(void *))

-

-/* we align ptr to support cases where CAlignOffsetAlloc::offset is not multiply of sizeof(void *) */

-#define REAL_BLOCK_PTR_VAR(p) ((void **)MY_ALIGN_PTR_DOWN_1(p))[-1]

-/*

-#define REAL_BLOCK_PTR_VAR(p) ((void **)(p))[-1]

-*/

-

-static void *AlignOffsetAlloc_Alloc(ISzAllocPtr pp, size_t size)

-{

-  CAlignOffsetAlloc *p = CONTAINER_FROM_VTBL(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;

-

-  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;

-}

-

-

-static void AlignOffsetAlloc_Free(ISzAllocPtr pp, void *address)

-{

-  if (address)

-  {

-    CAlignOffsetAlloc *p = CONTAINER_FROM_VTBL(pp, CAlignOffsetAlloc, vt);

-    PrintLn();

-    Print("- Aligned Free: ");

-    PrintLn();

-    ISzAlloc_Free(p->baseAlloc, REAL_BLOCK_PTR_VAR(address));

-  }

-}

-

-

-void AlignOffsetAlloc_CreateVTable(CAlignOffsetAlloc *p)

-{

-  p->vt.Alloc = AlignOffsetAlloc_Alloc;

-  p->vt.Free = AlignOffsetAlloc_Free;

-}

+/* Alloc.c -- Memory allocation functions
+2023-04-02 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#ifdef _WIN32
+#include "7zWindows.h"
+#endif
+#include <stdlib.h>
+
+#include "Alloc.h"
+
+#ifdef _WIN32
+#ifdef Z7_LARGE_PAGES
+#if defined(__clang__) || defined(__GNUC__)
+typedef void (*Z7_voidFunction)(void);
+#define MY_CAST_FUNC (Z7_voidFunction)
+#elif defined(_MSC_VER) && _MSC_VER > 1920
+#define MY_CAST_FUNC  (void *)
+// #pragma warning(disable : 4191) // 'type cast': unsafe conversion from 'FARPROC' to 'void (__cdecl *)()'
+#else
+#define MY_CAST_FUNC
+#endif
+#endif // Z7_LARGE_PAGES
+#endif // _WIN32
+
+// #define SZ_ALLOC_DEBUG
+/* #define SZ_ALLOC_DEBUG */
+
+/* use SZ_ALLOC_DEBUG to debug alloc/free operations */
+#ifdef SZ_ALLOC_DEBUG
+
+#include <string.h>
+#include <stdio.h>
+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()
+#define PrintHex(v, align)
+#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)
+{
+  #ifdef Z7_LARGE_PAGES
+  SIZE_T size;
+  const
+   Func_GetLargePageMinimum fn =
+  (Func_GetLargePageMinimum) MY_CAST_FUNC GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")),
+       "GetLargePageMinimum");
+  if (!fn)
+    return;
+  size = fn();
+  if (size == 0 || (size & (size - 1)) != 0)
+    return;
+  g_LargePageSize = size;
+  #endif
+}
+
+#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
+
+/*
+  uintptr_t : <stdint.h> C99 (optional)
+            : unsupported in VS6
+*/
+
+#ifdef _WIN32
+  typedef UINT_PTR UIntPtr;
+#else
+  /*
+  typedef uintptr_t UIntPtr;
+  */
+  typedef ptrdiff_t UIntPtr;
+#endif
+
+
+#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 *).
+*/
+
+
+/*
+#define MY_ALIGN_PTR_DOWN(p, align) ((void *)((char *)(p) - ((size_t)(UIntPtr)(p) & ((align) - 1))))
+*/
+#define MY_ALIGN_PTR_DOWN(p, align) ((void *)((((UIntPtr)(p)) & ~((UIntPtr)(align) - 1))))
+
+
+#if !defined(_WIN32) && 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)
+
+static void *SzAlignedAlloc(ISzAllocPtr pp, size_t size)
+{
+  #ifndef USE_posix_memalign
+  
+  void *p;
+  void *pAligned;
+  size_t newSize;
+  UNUSED_VAR(pp)
+
+  /* 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;
+  UNUSED_VAR(pp)
+  if (posix_memalign(&p, ALLOC_ALIGN_SIZE, size))
+    return NULL;
+
+  Print(" posix_memalign="); PrintAddr(p);
+  PrintLn();
+
+  return p;
+
+  #endif
+}
+
+
+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 };
+
+
+
+#define MY_ALIGN_PTR_DOWN_1(p) MY_ALIGN_PTR_DOWN(p, sizeof(void *))
+
+/* we align ptr to support cases where CAlignOffsetAlloc::offset is not multiply of sizeof(void *) */
+#define REAL_BLOCK_PTR_VAR(p) ((void **)MY_ALIGN_PTR_DOWN_1(p))[-1]
+/*
+#define REAL_BLOCK_PTR_VAR(p) ((void **)(p))[-1]
+*/
+
+static void *AlignOffsetAlloc_Alloc(ISzAllocPtr pp, size_t size)
+{
+  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;
+
+  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;
+}
+
+
+static void AlignOffsetAlloc_Free(ISzAllocPtr pp, void *address)
+{
+  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));
+  }
+}
+
+
+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 3d796e5..fac5b62 100644
--- a/C/Alloc.h
+++ b/C/Alloc.h
@@ -1,51 +1,71 @@
-/* Alloc.h -- Memory allocation functions

-2018-02-19 : Igor Pavlov : Public domain */

-

-#ifndef __COMMON_ALLOC_H

-#define __COMMON_ALLOC_H

-

-#include "7zTypes.h"

-

-EXTERN_C_BEGIN

-

-void *MyAlloc(size_t size);

-void MyFree(void *address);

-

-#ifdef _WIN32

-

-void SetLargePageSize();

-

-void *MidAlloc(size_t size);

-void MidFree(void *address);

-void *BigAlloc(size_t size);

-void BigFree(void *address);

-

-#else

-

-#define MidAlloc(size) MyAlloc(size)

-#define MidFree(address) MyFree(address)

-#define BigAlloc(size) MyAlloc(size)

-#define BigFree(address) MyFree(address)

-

-#endif

-

-extern const ISzAlloc g_Alloc;

-extern const ISzAlloc g_BigAlloc;

-extern const ISzAlloc g_MidAlloc;

-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
+2023-03-04 : 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);
+
+#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);
+
+#else
+
+#define MidAlloc(size) MyAlloc(size)
+#define MidFree(address) MyFree(address)
+#define BigAlloc(size) MyAlloc(size)
+#define BigFree(address) MyFree(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/Android.bp b/C/Android.bp
index c5d201b..071f557 100644
--- a/C/Android.bp
+++ b/C/Android.bp
@@ -24,7 +24,7 @@
     stl: "none",
 
     cflags: [
-        "-D_7ZIP_ST",
+        "-DZ7_ST",
         "-Wall",
         "-Werror",
         "-Wno-empty-body",
@@ -66,6 +66,7 @@
         "Ppmd7Dec.c",
         "Ppmd7Enc.c",
         "Sha256.c",
+        "Sha256Opt.c",
         "Sort.c",
         "Xz.c",
         "XzCrc64.c",
@@ -75,6 +76,15 @@
         "XzIn.c",
     ],
 
+    arch: {
+        arm: {
+            cflags: ["-march=armv8-a+crypto"],
+        },
+        arm64: {
+            cflags: ["-march=armv8-a+crypto"],
+        },
+    },
+
     target: {
         linux_bionic: {
             enabled: true,
@@ -85,6 +95,7 @@
                 "Bcj2Enc.c",
                 "DllSecur.c",
                 "LzFindMt.c",
+                "LzFindOpt.c",
                 "Lzma2DecMt.c",
                 "MtCoder.c",
                 "MtDec.c",
diff --git a/C/Bcj2.c b/C/Bcj2.c
index da93985..7cb57ad 100644
--- a/C/Bcj2.c
+++ b/C/Bcj2.c
@@ -1,257 +1,290 @@
-/* Bcj2.c -- BCJ2 Decoder (Converter for x86 code)

-2018-04-28 : Igor Pavlov : Public domain */

-

-#include "Precomp.h"

-

-#include "Bcj2.h"

-#include "CpuArch.h"

-

-#define CProb UInt16

-

-#define kTopValue ((UInt32)1 << 24)

-#define kNumModelBits 11

-#define kBitModelTotal (1 << kNumModelBits)

-#define kNumMoveBits 5

-

-#define _IF_BIT_0 ttt = *prob; bound = (p->range >> kNumModelBits) * ttt; if (p->code < bound)

-#define _UPDATE_0 p->range = bound; *prob = (CProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits));

-#define _UPDATE_1 p->range -= bound; p->code -= bound; *prob = (CProb)(ttt - (ttt >> kNumMoveBits));

-

-void Bcj2Dec_Init(CBcj2Dec *p)

-{

-  unsigned i;

-

-  p->state = BCJ2_DEC_STATE_OK;

-  p->ip = 0;

-  p->temp[3] = 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)

-{

-  if (p->range <= 5)

-  {

-    p->state = BCJ2_DEC_STATE_OK;

-    for (; p->range != 5; p->range++)

-    {

-      if (p->range == 1 && p->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;

-      }

-

-      p->code = (p->code << 8) | *(p->bufs[BCJ2_STREAM_RC])++;

-    }

-    

-    if (p->code == 0xFFFFFFFF)

-      return SZ_ERROR_DATA;

-    

-    p->range = 0xFFFFFFFF;

-  }

-  else if (p->state >= BCJ2_DEC_STATE_ORIG_0)

-  {

-    while (p->state <= BCJ2_DEC_STATE_ORIG_3)

-    {

-      Byte *dest = p->dest;

-      if (dest == p->destLim)

-        return SZ_OK;

-      *dest = p->temp[(size_t)p->state - BCJ2_DEC_STATE_ORIG_0];

-      p->state++;

-      p->dest = dest + 1;

-    }

-  }

-

-  /*

-  if (BCJ2_IS_32BIT_STREAM(p->state))

-  {

-    const Byte *cur = p->bufs[p->state];

-    if (cur == p->lims[p->state])

-      return SZ_OK;

-    p->bufs[p->state] = cur + 4;

-    

-    {

-      UInt32 val;

-      Byte *dest;

-      SizeT rem;

-      

-      p->ip += 4;

-      val = GetBe32(cur) - p->ip;

-      dest = p->dest;

-      rem = p->destLim - dest;

-      if (rem < 4)

-      {

-        SizeT i;

-        SetUi32(p->temp, val);

-        for (i = 0; i < rem; i++)

-          dest[i] = p->temp[i];

-        p->dest = dest + rem;

-        p->state = BCJ2_DEC_STATE_ORIG_0 + (unsigned)rem;

-        return SZ_OK;

-      }

-      SetUi32(dest, val);

-      p->temp[3] = (Byte)(val >> 24);

-      p->dest = dest + 4;

-      p->state = BCJ2_DEC_STATE_OK;

-    }

-  }

-  */

-

-  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;

-          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;

-        SizeT num = p->lims[BCJ2_STREAM_MAIN] - src;

-        

-        if (num == 0)

-        {

-          p->state = BCJ2_STREAM_MAIN;

-          return SZ_OK;

-        }

-        

-        dest = p->dest;

-        if (num > (SizeT)(p->destLim - dest))

-        {

-          num = p->destLim - dest;

-          if (num == 0)

-          {

-            p->state = BCJ2_DEC_STATE_ORIG;

-            return SZ_OK;

-          }

-        }

-       

-        srcLim = src + num;

-

-        if (p->temp[3] == 0x0F && (src[0] & 0xF0) == 0x80)

-          *dest = src[0];

-        else for (;;)

-        {

-          Byte b = *src;

-          *dest = b;

-          if (b != 0x0F)

-          {

-            if ((b & 0xFE) == 0xE8)

-              break;

-            dest++;

-            if (++src != srcLim)

-              continue;

-            break;

-          }

-          dest++;

-          if (++src == srcLim)

-            break;

-          if ((*src & 0xF0) != 0x80)

-            continue;

-          *dest = *src;

-          break;

-        }

-        

-        num = src - p->bufs[BCJ2_STREAM_MAIN];

-        

-        if (src == srcLim)

-        {

-          p->temp[3] = src[-1];

-          p->bufs[BCJ2_STREAM_MAIN] = src;

-          p->ip += (UInt32)num;

-          p->dest += num;

-          p->state =

-            p->bufs[BCJ2_STREAM_MAIN] ==

-            p->lims[BCJ2_STREAM_MAIN] ?

-              (unsigned)BCJ2_STREAM_MAIN :

-              (unsigned)BCJ2_DEC_STATE_ORIG;

-          return SZ_OK;

-        }

-        

-        {

-          UInt32 bound, ttt;

-          CProb *prob;

-          Byte b = src[0];

-          Byte prev = (Byte)(num == 0 ? p->temp[3] : src[-1]);

-          

-          p->temp[3] = b;

-          p->bufs[BCJ2_STREAM_MAIN] = src + 1;

-          num++;

-          p->ip += (UInt32)num;

-          p->dest += num;

-          

-          prob = p->probs + (unsigned)(b == 0xE8 ? 2 + (unsigned)prev : (b == 0xE9 ? 1 : 0));

-          

-          _IF_BIT_0

-          {

-            _UPDATE_0

-            continue;

-          }

-          _UPDATE_1

-            

-        }

-      }

-    }

-

-    {

-      UInt32 val;

-      unsigned cj = (p->temp[3] == 0xE8) ? BCJ2_STREAM_CALL : BCJ2_STREAM_JUMP;

-      const Byte *cur = p->bufs[cj];

-      Byte *dest;

-      SizeT rem;

-      

-      if (cur == p->lims[cj])

-      {

-        p->state = cj;

-        break;

-      }

-      

-      val = GetBe32(cur);

-      p->bufs[cj] = cur + 4;

-

-      p->ip += 4;

-      val -= p->ip;

-      dest = p->dest;

-      rem = p->destLim - dest;

-      

-      if (rem < 4)

-      {

-        p->temp[0] = (Byte)val; if (rem > 0) dest[0] = (Byte)val; val >>= 8;

-        p->temp[1] = (Byte)val; if (rem > 1) dest[1] = (Byte)val; val >>= 8;

-        p->temp[2] = (Byte)val; if (rem > 2) dest[2] = (Byte)val; val >>= 8;

-        p->temp[3] = (Byte)val;

-        p->dest = dest + rem;

-        p->state = BCJ2_DEC_STATE_ORIG_0 + (unsigned)rem;

-        break;

-      }

-      

-      SetUi32(dest, val);

-      p->temp[3] = (Byte)(val >> 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;

-}

+/* 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 68893d2..4575545 100644
--- a/C/Bcj2.h
+++ b/C/Bcj2.h
@@ -1,146 +1,332 @@
-/* Bcj2.h -- BCJ2 Converter for x86 code

-2014-11-10 : Igor Pavlov : Public domain */

-

-#ifndef __BCJ2_H

-#define __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_OK

-};

-

-enum

-{

-  BCJ2_ENC_STATE_ORIG = BCJ2_NUM_STREAMS,

-  BCJ2_ENC_STATE_OK

-};

-

-

-#define BCJ2_IS_32BIT_STREAM(s) ((s) == BCJ2_STREAM_CALL || (s) == BCJ2_STREAM_JUMP)

-

-/*

-CBcj2Dec / CBcj2Enc

-bufs sizes:

-  BUF_SIZE(n) = lims[n] - bufs[n]

-bufs sizes for BCJ2_STREAM_CALL and BCJ2_STREAM_JUMP must be mutliply of 4:

-    (BUF_SIZE(BCJ2_STREAM_CALL) & 3) == 0

-    (BUF_SIZE(BCJ2_STREAM_JUMP) & 3) == 0

-*/

-

-/*

-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 >= tempReserv +

-        BUF_SIZE(BCJ2_STREAM_CALL) +

-        BUF_SIZE(BCJ2_STREAM_JUMP)

-     tempReserv = 0 : for first call of Bcj2Dec_Decode

-     tempReserv = 4 : for any other calls of Bcj2Dec_Decode

-  overlap with offset = 1 is not allowed

-*/

-

-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;

-  Byte temp[4];

-  UInt32 range;

-  UInt32 code;

-  UInt16 probs[2 + 256];

-} CBcj2Dec;

-

-void Bcj2Dec_Init(CBcj2Dec *p);

-

-/* Returns: SZ_OK or SZ_ERROR_DATA */

-SRes Bcj2Dec_Decode(CBcj2Dec *p);

-

-#define Bcj2Dec_IsFinished(_p_) ((_p_)->code == 0)

-

-

-

-typedef enum

-{

-  BCJ2_ENC_FINISH_MODE_CONTINUE,

-  BCJ2_ENC_FINISH_MODE_END_BLOCK,

-  BCJ2_ENC_FINISH_MODE_END_STREAM

-} EBcj2Enc_FinishMode;

-

-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 prevByte;

-

-  Byte cache;

-  UInt32 range;

-  UInt64 low;

-  UInt64 cacheSize;

-

-  UInt32 ip;

-

-  /* 32-bit ralative offset in JUMP/CALL commands is

-       - (mod 4 GB)   in 32-bit mode

-       - signed Int32 in 64-bit mode

-     We use (mod 4 GB) check for fileSize.

-     Use fileSize up to 2 GB, if you want to support 32-bit and 64-bit code conversion. */

-  UInt32 fileIp;

-  UInt32 fileSize;    /* (fileSize <= ((UInt32)1 << 31)), 0 means no_limit */

-  UInt32 relatLimit;  /* (relatLimit <= ((UInt32)1 << 31)), 0 means desable_conversion */

-

-  UInt32 tempTarget;

-  unsigned tempPos;

-  Byte temp[4 * 2];

-

-  unsigned flushPos;

-  

-  UInt16 probs[2 + 256];

-} CBcj2Enc;

-

-void Bcj2Enc_Init(CBcj2Enc *p);

-void Bcj2Enc_Encode(CBcj2Enc *p);

-

-#define Bcj2Enc_Get_InputData_Size(p) ((SizeT)((p)->srcLim - (p)->src) + (p)->tempPos)

-#define Bcj2Enc_IsFinished(p) ((p)->flushPos == 5)

-

-

-#define BCJ2_RELAT_LIMIT_NUM_BITS 26

-#define BCJ2_RELAT_LIMIT ((UInt32)1 << BCJ2_RELAT_LIMIT_NUM_BITS)

-

-/* limit for CBcj2Enc::fileSize variable */

-#define BCJ2_FileSize_MAX ((UInt32)1 << 31)

-

-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 7a02ecd..79460bb 100644
--- a/C/Bcj2Enc.c
+++ b/C/Bcj2Enc.c
@@ -1,311 +1,506 @@
-/* Bcj2Enc.c -- BCJ2 Encoder (Converter for x86 code)

-2019-02-02 : Igor Pavlov : Public domain */

-

-#include "Precomp.h"

-

-/* #define SHOW_STAT */

-

-#ifdef SHOW_STAT

-#include <stdio.h>

-#define PRF(x) x

-#else

-#define PRF(x)

-#endif

-

-#include <string.h>

-

-#include "Bcj2.h"

-#include "CpuArch.h"

-

-#define CProb UInt16

-

-#define kTopValue ((UInt32)1 << 24)

-#define kNumModelBits 11

-#define kBitModelTotal (1 << kNumModelBits)

-#define kNumMoveBits 5

-

-void Bcj2Enc_Init(CBcj2Enc *p)

-{

-  unsigned i;

-

-  p->state = BCJ2_ENC_STATE_OK;

-  p->finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE;

-

-  p->prevByte = 0;

-

-  p->cache = 0;

-  p->range = 0xFFFFFFFF;

-  p->low = 0;

-  p->cacheSize = 1;

-

-  p->ip = 0;

-

-  p->fileIp = 0;

-  p->fileSize = 0;

-  p->relatLimit = BCJ2_RELAT_LIMIT;

-

-  p->tempPos = 0;

-

-  p->flushPos = 0;

-

-  for (i = 0; i < sizeof(p->probs) / sizeof(p->probs[0]); i++)

-    p->probs[i] = kBitModelTotal >> 1;

-}

-

-static BoolInt MY_FAST_CALL RangeEnc_ShiftLow(CBcj2Enc *p)

-{

-  if ((UInt32)p->low < (UInt32)0xFF000000 || (UInt32)(p->low >> 32) != 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 + (Byte)(p->low >> 32));

-      p->cache = 0xFF;

-    }

-    while (--p->cacheSize);

-    p->bufs[BCJ2_STREAM_RC] = buf;

-    p->cache = (Byte)((UInt32)p->low >> 24);

-  }

-  p->cacheSize++;

-  p->low = (UInt32)p->low << 8;

-  return False;

-}

-

-static void Bcj2Enc_Encode_2(CBcj2Enc *p)

-{

-  if (BCJ2_IS_32BIT_STREAM(p->state))

-  {

-    Byte *cur = p->bufs[p->state];

-    if (cur == p->lims[p->state])

-      return;

-    SetBe32(cur, p->tempTarget);

-    p->bufs[p->state] = cur + 4;

-  }

-

-  p->state = BCJ2_ENC_STATE_ORIG;

-

-  for (;;)

-  {

-    if (p->range < kTopValue)

-    {

-      if (RangeEnc_ShiftLow(p))

-        return;

-      p->range <<= 8;

-    }

-

-    {

-      {

-        const Byte *src = p->src;

-        const Byte *srcLim;

-        Byte *dest;

-        SizeT num = p->srcLim - src;

-

-        if (p->finishMode == BCJ2_ENC_FINISH_MODE_CONTINUE)

-        {

-          if (num <= 4)

-            return;

-          num -= 4;

-        }

-        else if (num == 0)

-          break;

-

-        dest = p->bufs[BCJ2_STREAM_MAIN];

-        if (num > (SizeT)(p->lims[BCJ2_STREAM_MAIN] - dest))

-        {

-          num = p->lims[BCJ2_STREAM_MAIN] - dest;

-          if (num == 0)

-          {

-            p->state = BCJ2_STREAM_MAIN;

-            return;

-          }

-        }

-       

-        srcLim = src + num;

-

-        if (p->prevByte == 0x0F && (src[0] & 0xF0) == 0x80)

-          *dest = src[0];

-        else for (;;)

-        {

-          Byte b = *src;

-          *dest = b;

-          if (b != 0x0F)

-          {

-            if ((b & 0xFE) == 0xE8)

-              break;

-            dest++;

-            if (++src != srcLim)

-              continue;

-            break;

-          }

-          dest++;

-          if (++src == srcLim)

-            break;

-          if ((*src & 0xF0) != 0x80)

-            continue;

-          *dest = *src;

-          break;

-        }

-        

-        num = src - p->src;

-        

-        if (src == srcLim)

-        {

-          p->prevByte = src[-1];

-          p->bufs[BCJ2_STREAM_MAIN] = dest;

-          p->src = src;

-          p->ip += (UInt32)num;

-          continue;

-        }

- 

-        {

-          Byte context = (Byte)(num == 0 ? p->prevByte : src[-1]);

-          BoolInt needConvert;

-

-          p->bufs[BCJ2_STREAM_MAIN] = dest + 1;

-          p->ip += (UInt32)num + 1;

-          src++;

-          

-          needConvert = False;

-

-          if ((SizeT)(p->srcLim - src) >= 4)

-          {

-            UInt32 relatVal = GetUi32(src);

-            if ((p->fileSize == 0 || (UInt32)(p->ip + 4 + relatVal - p->fileIp) < p->fileSize)

-                && ((relatVal + p->relatLimit) >> 1) < p->relatLimit)

-              needConvert = True;

-          }

-

-          {

-            UInt32 bound;

-            unsigned ttt;

-            Byte b = src[-1];

-            CProb *prob = p->probs + (unsigned)(b == 0xE8 ? 2 + (unsigned)context : (b == 0xE9 ? 1 : 0));

-

-            ttt = *prob;

-            bound = (p->range >> kNumModelBits) * ttt;

-            

-            if (!needConvert)

-            {

-              p->range = bound;

-              *prob = (CProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits));

-              p->src = src;

-              p->prevByte = b;

-              continue;

-            }

-            

-            p->low += bound;

-            p->range -= bound;

-            *prob = (CProb)(ttt - (ttt >> kNumMoveBits));

-

-            {

-              UInt32 relatVal = GetUi32(src);

-              UInt32 absVal;

-              p->ip += 4;

-              absVal = p->ip + relatVal;

-              p->prevByte = src[3];

-              src += 4;

-              p->src = src;

-              {

-                unsigned cj = (b == 0xE8) ? BCJ2_STREAM_CALL : BCJ2_STREAM_JUMP;

-                Byte *cur = p->bufs[cj];

-                if (cur == p->lims[cj])

-                {

-                  p->state = cj;

-                  p->tempTarget = absVal;

-                  return;

-                }

-                SetBe32(cur, absVal);

-                p->bufs[cj] = cur + 4;

-              }

-            }

-          }

-        }

-      }

-    }

-  }

-

-  if (p->finishMode != BCJ2_ENC_FINISH_MODE_END_STREAM)

-    return;

-

-  for (; p->flushPos < 5; p->flushPos++)

-    if (RangeEnc_ShiftLow(p))

-      return;

-  p->state = BCJ2_ENC_STATE_OK;

-}

-

-

-void Bcj2Enc_Encode(CBcj2Enc *p)

-{

-  PRF(printf("\n"));

-  PRF(printf("---- ip = %8d   tempPos = %8d   src = %8d\n", p->ip, p->tempPos, p->srcLim - p->src));

-

-  if (p->tempPos != 0)

-  {

-    unsigned extra = 0;

-   

-    for (;;)

-    {

-      const Byte *src = p->src;

-      const Byte *srcLim = p->srcLim;

-      EBcj2Enc_FinishMode finishMode = p->finishMode;

-      

-      p->src = p->temp;

-      p->srcLim = p->temp + p->tempPos;

-      if (src != srcLim)

-        p->finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE;

-      

-      PRF(printf("     ip = %8d   tempPos = %8d   src = %8d\n", p->ip, p->tempPos, p->srcLim - p->src));

-

-      Bcj2Enc_Encode_2(p);

-      

-      {

-        unsigned num = (unsigned)(p->src - p->temp);

-        unsigned tempPos = p->tempPos - num;

-        unsigned i;

-        p->tempPos = tempPos;

-        for (i = 0; i < tempPos; i++)

-          p->temp[i] = p->temp[(size_t)i + num];

-      

-        p->src = src;

-        p->srcLim = srcLim;

-        p->finishMode = finishMode;

-        

-        if (p->state != BCJ2_ENC_STATE_ORIG || src == srcLim)

-          return;

-        

-        if (extra >= tempPos)

-        {

-          p->src = src - tempPos;

-          p->tempPos = 0;

-          break;

-        }

-        

-        p->temp[tempPos] = src[0];

-        p->tempPos = tempPos + 1;

-        p->src = src + 1;

-        extra++;

-      }

-    }

-  }

-

-  PRF(printf("++++ ip = %8d   tempPos = %8d   src = %8d\n", p->ip, p->tempPos, p->srcLim - p->src));

-

-  Bcj2Enc_Encode_2(p);

-  

-  if (p->state == BCJ2_ENC_STATE_ORIG)

-  {

-    const Byte *src = p->src;

-    unsigned rem = (unsigned)(p->srcLim - src);

-    unsigned i;

-    for (i = 0; i < rem; i++)

-      p->temp[i] = src[i];

-    p->tempPos = rem;

-    p->src = src + rem;

-  }

-}

+/* 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 <stdio.h>
+#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
new file mode 100644
index 0000000..7235235
--- /dev/null
+++ b/C/Blake2.h
@@ -0,0 +1,48 @@
+/* Blake2.h -- BLAKE2 Hash
+2023-03-04 : Igor Pavlov : Public domain
+2015 : Samuel Neves : Public domain */
+
+#ifndef ZIP7_INC_BLAKE2_H
+#define ZIP7_INC_BLAKE2_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+#define BLAKE2S_BLOCK_SIZE 64
+#define BLAKE2S_DIGEST_SIZE 32
+#define BLAKE2SP_PARALLEL_DEGREE 8
+
+typedef struct
+{
+  UInt32 h[8];
+  UInt32 t[2];
+  UInt32 f[2];
+  Byte buf[BLAKE2S_BLOCK_SIZE];
+  UInt32 bufPos;
+  UInt32 lastNode_f1;
+  UInt32 dummy[2]; /* for sizeof(CBlake2s) alignment */
+} CBlake2s;
+
+/* You need to xor CBlake2s::h[i] with input parameter block after Blake2s_Init0() */
+/*
+void Blake2s_Init0(CBlake2s *p);
+void Blake2s_Update(CBlake2s *p, const Byte *data, size_t size);
+void Blake2s_Final(CBlake2s *p, Byte *digest);
+*/
+
+
+typedef struct
+{
+  CBlake2s S[BLAKE2SP_PARALLEL_DEGREE];
+  unsigned bufPos;
+} CBlake2sp;
+
+
+void Blake2sp_Init(CBlake2sp *p);
+void Blake2sp_Update(CBlake2sp *p, const Byte *data, size_t size);
+void Blake2sp_Final(CBlake2sp *p, Byte *digest);
+
+EXTERN_C_END
+
+#endif
diff --git a/C/Blake2s.c b/C/Blake2s.c
new file mode 100644
index 0000000..2a84b57
--- /dev/null
+++ b/C/Blake2s.c
@@ -0,0 +1,250 @@
+/* Blake2s.c -- BLAKE2s and BLAKE2sp Hash
+2023-03-04 : Igor Pavlov : Public domain
+2015 : Samuel Neves : Public domain */
+
+#include "Precomp.h"
+
+#include <string.h>
+
+#include "Blake2.h"
+#include "CpuArch.h"
+#include "RotateDefs.h"
+
+#define rotr32 rotrFixed
+
+#define BLAKE2S_NUM_ROUNDS 10
+#define BLAKE2S_FINAL_FLAG (~(UInt32)0)
+
+static const UInt32 k_Blake2s_IV[8] =
+{
+  0x6A09E667UL, 0xBB67AE85UL, 0x3C6EF372UL, 0xA54FF53AUL,
+  0x510E527FUL, 0x9B05688CUL, 0x1F83D9ABUL, 0x5BE0CD19UL
+};
+
+static const Byte k_Blake2s_Sigma[BLAKE2S_NUM_ROUNDS][16] =
+{
+  {  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15 } ,
+  { 14, 10,  4,  8,  9, 15, 13,  6,  1, 12,  0,  2, 11,  7,  5,  3 } ,
+  { 11,  8, 12,  0,  5,  2, 15, 13, 10, 14,  3,  6,  7,  1,  9,  4 } ,
+  {  7,  9,  3,  1, 13, 12, 11, 14,  2,  6,  5, 10,  4,  0, 15,  8 } ,
+  {  9,  0,  5,  7,  2,  4, 10, 15, 14,  1, 11, 12,  6,  8,  3, 13 } ,
+  {  2, 12,  6, 10,  0, 11,  8,  3,  4, 13,  7,  5, 15, 14,  1,  9 } ,
+  { 12,  5,  1, 15, 14, 13,  4, 10,  0,  7,  6,  3,  9,  2,  8, 11 } ,
+  { 13, 11,  7, 14, 12,  1,  3,  9,  5,  0, 15,  4,  8,  6,  2, 10 } ,
+  {  6, 15, 14,  9, 11,  3,  0,  8, 12,  2, 13,  7,  1,  4, 10,  5 } ,
+  { 10,  2,  8,  4,  7,  6,  1,  5, 15, 11,  9, 14,  3, 12, 13 , 0 } ,
+};
+
+
+static void Blake2s_Init0(CBlake2s *p)
+{
+  unsigned i;
+  for (i = 0; i < 8; i++)
+    p->h[i] = k_Blake2s_IV[i];
+  p->t[0] = 0;
+  p->t[1] = 0;
+  p->f[0] = 0;
+  p->f[1] = 0;
+  p->bufPos = 0;
+  p->lastNode_f1 = 0;
+}
+
+
+static void Blake2s_Compress(CBlake2s *p)
+{
+  UInt32 m[16];
+  UInt32 v[16];
+  
+  {
+    unsigned i;
+    
+    for (i = 0; i < 16; i++)
+      m[i] = GetUi32(p->buf + i * sizeof(m[i]));
+    
+    for (i = 0; i < 8; i++)
+      v[i] = p->h[i];
+  }
+
+  v[ 8] = k_Blake2s_IV[0];
+  v[ 9] = k_Blake2s_IV[1];
+  v[10] = k_Blake2s_IV[2];
+  v[11] = k_Blake2s_IV[3];
+  
+  v[12] = p->t[0] ^ k_Blake2s_IV[4];
+  v[13] = p->t[1] ^ k_Blake2s_IV[5];
+  v[14] = p->f[0] ^ k_Blake2s_IV[6];
+  v[15] = p->f[1] ^ k_Blake2s_IV[7];
+
+  #define G(r,i,a,b,c,d) \
+    a += b + m[sigma[2*i+0]];  d ^= a; d = rotr32(d, 16);  c += d;  b ^= c; b = rotr32(b, 12); \
+    a += b + m[sigma[2*i+1]];  d ^= a; d = rotr32(d,  8);  c += d;  b ^= c; b = rotr32(b,  7); \
+
+  #define R(r) \
+    G(r,0,v[ 0],v[ 4],v[ 8],v[12]) \
+    G(r,1,v[ 1],v[ 5],v[ 9],v[13]) \
+    G(r,2,v[ 2],v[ 6],v[10],v[14]) \
+    G(r,3,v[ 3],v[ 7],v[11],v[15]) \
+    G(r,4,v[ 0],v[ 5],v[10],v[15]) \
+    G(r,5,v[ 1],v[ 6],v[11],v[12]) \
+    G(r,6,v[ 2],v[ 7],v[ 8],v[13]) \
+    G(r,7,v[ 3],v[ 4],v[ 9],v[14]) \
+
+  {
+    unsigned r;
+    for (r = 0; r < BLAKE2S_NUM_ROUNDS; r++)
+    {
+      const Byte *sigma = k_Blake2s_Sigma[r];
+      R(r)
+    }
+    /* R(0); R(1); R(2); R(3); R(4); R(5); R(6); R(7); R(8); R(9); */
+  }
+
+  #undef G
+  #undef R
+
+  {
+    unsigned i;
+    for (i = 0; i < 8; i++)
+      p->h[i] ^= v[i] ^ v[i + 8];
+  }
+}
+
+
+#define Blake2s_Increment_Counter(S, inc) \
+  { p->t[0] += (inc); p->t[1] += (p->t[0] < (inc)); }
+
+#define Blake2s_Set_LastBlock(p) \
+  { p->f[0] = BLAKE2S_FINAL_FLAG; p->f[1] = p->lastNode_f1; }
+
+
+static void Blake2s_Update(CBlake2s *p, const Byte *data, size_t size)
+{
+  while (size != 0)
+  {
+    unsigned pos = (unsigned)p->bufPos;
+    unsigned rem = BLAKE2S_BLOCK_SIZE - pos;
+
+    if (size <= rem)
+    {
+      memcpy(p->buf + pos, data, size);
+      p->bufPos += (UInt32)size;
+      return;
+    }
+
+    memcpy(p->buf + pos, data, rem);
+    Blake2s_Increment_Counter(S, BLAKE2S_BLOCK_SIZE)
+    Blake2s_Compress(p);
+    p->bufPos = 0;
+    data += rem;
+    size -= rem;
+  }
+}
+
+
+static void Blake2s_Final(CBlake2s *p, Byte *digest)
+{
+  unsigned i;
+
+  Blake2s_Increment_Counter(S, (UInt32)p->bufPos)
+  Blake2s_Set_LastBlock(p)
+  memset(p->buf + p->bufPos, 0, BLAKE2S_BLOCK_SIZE - p->bufPos);
+  Blake2s_Compress(p);
+
+  for (i = 0; i < 8; i++)
+  {
+    SetUi32(digest + sizeof(p->h[i]) * i, p->h[i])
+  }
+}
+
+
+/* ---------- 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;
+  Byte  depth;
+  UInt32 leaf_length;
+  Byte  node_offset[6];
+  Byte  node_depth;
+  Byte  inner_length;
+  Byte  salt[BLAKE2S_SALTBYTES];
+  Byte  personal[BLAKE2S_PERSONALBYTES];
+} CBlake2sParam;
+*/
+
+
+static void Blake2sp_Init_Spec(CBlake2s *p, unsigned node_offset, unsigned node_depth)
+{
+  Blake2s_Init0(p);
+  
+  p->h[0] ^= (BLAKE2S_DIGEST_SIZE | ((UInt32)BLAKE2SP_PARALLEL_DEGREE << 16) | ((UInt32)2 << 24));
+  p->h[2] ^= ((UInt32)node_offset);
+  p->h[3] ^= ((UInt32)node_depth << 16) | ((UInt32)BLAKE2S_DIGEST_SIZE << 24);
+  /*
+  P->digest_length = BLAKE2S_DIGEST_SIZE;
+  P->key_length = 0;
+  P->fanout = BLAKE2SP_PARALLEL_DEGREE;
+  P->depth = 2;
+  P->leaf_length = 0;
+  store48(P->node_offset, node_offset);
+  P->node_depth = node_depth;
+  P->inner_length = BLAKE2S_DIGEST_SIZE;
+  */
+}
+
+
+void Blake2sp_Init(CBlake2sp *p)
+{
+  unsigned i;
+  
+  p->bufPos = 0;
+
+  for (i = 0; i < BLAKE2SP_PARALLEL_DEGREE; i++)
+    Blake2sp_Init_Spec(&p->S[i], i, 0);
+
+  p->S[BLAKE2SP_PARALLEL_DEGREE - 1].lastNode_f1 = BLAKE2S_FINAL_FLAG;
+}
+
+
+void Blake2sp_Update(CBlake2sp *p, const Byte *data, size_t size)
+{
+  unsigned pos = p->bufPos;
+  while (size != 0)
+  {
+    unsigned index = pos / BLAKE2S_BLOCK_SIZE;
+    unsigned rem = BLAKE2S_BLOCK_SIZE - (pos & (BLAKE2S_BLOCK_SIZE - 1));
+    if (rem > size)
+      rem = (unsigned)size;
+    Blake2s_Update(&p->S[index], data, rem);
+    size -= rem;
+    data += rem;
+    pos += rem;
+    pos &= (BLAKE2S_BLOCK_SIZE * BLAKE2SP_PARALLEL_DEGREE - 1);
+  }
+  p->bufPos = pos;
+}
+
+
+void Blake2sp_Final(CBlake2sp *p, Byte *digest)
+{
+  CBlake2s R;
+  unsigned i;
+
+  Blake2sp_Init_Spec(&R, 0, 1);
+  R.lastNode_f1 = BLAKE2S_FINAL_FLAG;
+
+  for (i = 0; i < BLAKE2SP_PARALLEL_DEGREE; i++)
+  {
+    Byte hash[BLAKE2S_DIGEST_SIZE];
+    Blake2s_Final(&p->S[i], hash);
+    Blake2s_Update(&R, hash, BLAKE2S_DIGEST_SIZE);
+  }
+
+  Blake2s_Final(&R, digest);
+}
+
+#undef rotr32
diff --git a/C/Bra.c b/C/Bra.c
index cbdcb29..22e0e47 100644
--- a/C/Bra.c
+++ b/C/Bra.c
@@ -1,230 +1,420 @@
-/* Bra.c -- Converters for RISC code

-2017-04-04 : Igor Pavlov : Public domain */

-

-#include "Precomp.h"

-

-#include "CpuArch.h"

-#include "Bra.h"

-

-SizeT ARM_Convert(Byte *data, SizeT size, UInt32 ip, int encoding)

-{

-  Byte *p;

-  const Byte *lim;

-  size &= ~(size_t)3;

-  ip += 4;

-  p = data;

-  lim = data + size;

-

-  if (encoding)

-

-  for (;;)

-  {

-    for (;;)

-    {

-      if (p >= lim)

-        return p - data;

-      p += 4;

-      if (p[-1] == 0xEB)

-        break;

-    }

-    {

-      UInt32 v = GetUi32(p - 4);

-      v <<= 2;

-        v += ip + (UInt32)(p - data);

-      v >>= 2;

-      v &= 0x00FFFFFF;

-      v |= 0xEB000000;

-      SetUi32(p - 4, v);

-    }

-  }

-

-  for (;;)

-  {

-    for (;;)

-    {

-      if (p >= lim)

-        return p - data;

-      p += 4;

-      if (p[-1] == 0xEB)

-        break;

-    }

-    {

-      UInt32 v = GetUi32(p - 4);

-      v <<= 2;

-        v -= ip + (UInt32)(p - data);

-      v >>= 2;

-      v &= 0x00FFFFFF;

-      v |= 0xEB000000;

-      SetUi32(p - 4, v);

-    }

-  }

-}

-

-

-SizeT ARMT_Convert(Byte *data, SizeT size, UInt32 ip, int encoding)

-{

-  Byte *p;

-  const Byte *lim;

-  size &= ~(size_t)1;

-  p = data;

-  lim = data + size - 4;

-

-  if (encoding)

-  

-  for (;;)

-  {

-    UInt32 b1;

-    for (;;)

-    {

-      UInt32 b3;

-      if (p > lim)

-        return p - data;

-      b1 = p[1];

-      b3 = p[3];

-      p += 2;

-      b1 ^= 8;

-      if ((b3 & b1) >= 0xF8)

-        break;

-    }

-    {

-      UInt32 v =

-             ((UInt32)b1 << 19)

-          + (((UInt32)p[1] & 0x7) << 8)

-          + (((UInt32)p[-2] << 11))

-          + (p[0]);

-

-      p += 2;

-      {

-        UInt32 cur = (ip + (UInt32)(p - data)) >> 1;

-          v += cur;

-      }

-

-      p[-4] = (Byte)(v >> 11);

-      p[-3] = (Byte)(0xF0 | ((v >> 19) & 0x7));

-      p[-2] = (Byte)v;

-      p[-1] = (Byte)(0xF8 | (v >> 8));

-    }

-  }

-  

-  for (;;)

-  {

-    UInt32 b1;

-    for (;;)

-    {

-      UInt32 b3;

-      if (p > lim)

-        return p - data;

-      b1 = p[1];

-      b3 = p[3];

-      p += 2;

-      b1 ^= 8;

-      if ((b3 & b1) >= 0xF8)

-        break;

-    }

-    {

-      UInt32 v =

-             ((UInt32)b1 << 19)

-          + (((UInt32)p[1] & 0x7) << 8)

-          + (((UInt32)p[-2] << 11))

-          + (p[0]);

-

-      p += 2;

-      {

-        UInt32 cur = (ip + (UInt32)(p - data)) >> 1;

-          v -= cur;

-      }

-

-      /*

-      SetUi16(p - 4, (UInt16)(((v >> 11) & 0x7FF) | 0xF000));

-      SetUi16(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));

-    }

-  }

-}

-

-

-SizeT PPC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding)

-{

-  Byte *p;

-  const Byte *lim;

-  size &= ~(size_t)3;

-  ip -= 4;

-  p = data;

-  lim = data + size;

-

-  for (;;)

-  {

-    for (;;)

-    {

-      if (p >= lim)

-        return p - data;

-      p += 4;

-      /* if ((v & 0xFC000003) == 0x48000001) */

-      if ((p[-4] & 0xFC) == 0x48 && (p[-1] & 3) == 1)

-        break;

-    }

-    {

-      UInt32 v = GetBe32(p - 4);

-      if (encoding)

-        v += ip + (UInt32)(p - data);

-      else

-        v -= ip + (UInt32)(p - data);

-      v &= 0x03FFFFFF;

-      v |= 0x48000000;

-      SetBe32(p - 4, v);

-    }

-  }

-}

-

-

-SizeT SPARC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding)

-{

-  Byte *p;

-  const Byte *lim;

-  size &= ~(size_t)3;

-  ip -= 4;

-  p = data;

-  lim = data + size;

-

-  for (;;)

-  {

-    for (;;)

-    {

-      if (p >= lim)

-        return p - data;

-      /*

-      v = GetBe32(p);

-      p += 4;

-      m = v + ((UInt32)5 << 29);

-      m ^= (UInt32)7 << 29;

-      m += (UInt32)1 << 22;

-      if ((m & ((UInt32)0x1FF << 23)) == 0)

-        break;

-      */

-      p += 4;

-      if ((p[-4] == 0x40 && (p[-3] & 0xC0) == 0) ||

-          (p[-4] == 0x7F && (p[-3] >= 0xC0)))

-        break;

-    }

-    {

-      UInt32 v = GetBe32(p - 4);

-      v <<= 2;

-      if (encoding)

-        v += ip + (UInt32)(p - data);

-      else

-        v -= ip + (UInt32)(p - data);

-      

-      v &= 0x01FFFFFF;

-      v -= (UInt32)1 << 24;

-      v ^= 0xFF000000;

-      v >>= 2;

-      v |= 0x40000000;

-      SetBe32(p - 4, v);

-    }

-  }

-}

+/* Bra.c -- Branch converters for RISC code
+2023-04-02 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "Bra.h"
+#include "CpuArch.h"
+#include "RotateDefs.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_BranchConv_ ## 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, 0)
+#else
+#define Z7_BRANCH_FUNCS_IMP(name) \
+  Z7_BRANCH_FUNC_IMP(name, Z7_BRANCH_CONV_DEC, 0) \
+  Z7_BRANCH_FUNC_IMP(name, Z7_BRANCH_CONV_ENC, 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(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(ARM64)
+
+
+Z7_BRANCH_FUNC_MAIN(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(ARM)
+
+
+Z7_BRANCH_FUNC_MAIN(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(PPC)
+
+
+#ifdef Z7_CPU_FAST_ROTATE_SUPPORTED
+#define BR_SPARC_USE_ROTATE
+#endif
+
+Z7_BRANCH_FUNC_MAIN(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(SPARC)
+
+
+Z7_BRANCH_FUNC_MAIN(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(ARMT)
+
+
+// #define BR_IA64_NO_INLINE
+
+Z7_BRANCH_FUNC_MAIN(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(IA64)
diff --git a/C/Bra.h b/C/Bra.h
index aba8dce..a4ee568 100644
--- a/C/Bra.h
+++ b/C/Bra.h
@@ -1,64 +1,99 @@
-/* Bra.h -- Branch converters for executables

-2013-01-18 : Igor Pavlov : Public domain */

-

-#ifndef __BRA_H

-#define __BRA_H

-

-#include "7zTypes.h"

-

-EXTERN_C_BEGIN

-

-/*

-These functions convert relative addresses to absolute addresses

-in CALL instructions to increase the compression ratio.

-  

-  In:

-    data     - data buffer

-    size     - size of data

-    ip       - current virtual Instruction Pinter (IP) value

-    state    - state variable for x86 converter

-    encoding - 0 (for decoding), 1 (for encoding)

-  

-  Out:

-    state    - state variable for x86 converter

-

-  Returns:

-    The number of processed bytes. If you call these functions with multiple calls,

-    you must start next call with first byte after block of processed bytes.

-  

-  Type   Endian  Alignment  LookAhead

-  

-  x86    little      1          4

-  ARMT   little      2          2

-  ARM    little      4          0

-  PPC     big        4          0

-  SPARC   big        4          0

-  IA64   little     16          0

-

-  size must be >= Alignment + LookAhead, if it's not last block.

-  If (size < Alignment + LookAhead), converter returns 0.

-

-  Example:

-

-    UInt32 ip = 0;

-    for ()

-    {

-      ; size must be >= Alignment + LookAhead, if it's not last block

-      SizeT processed = Convert(data, size, ip, 1);

-      data += processed;

-      size -= processed;

-      ip += processed;

-    }

-*/

-

-#define x86_Convert_Init(state) { state = 0; }

-SizeT x86_Convert(Byte *data, SizeT size, UInt32 ip, UInt32 *state, int encoding);

-SizeT ARM_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);

-SizeT ARMT_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);

-SizeT PPC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);

-SizeT SPARC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);

-SizeT IA64_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);

-

-EXTERN_C_END

-

-#endif

+/* Bra.h -- Branch converters for executables
+2023-04-02 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_BRA_H
+#define ZIP7_INC_BRA_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+#define Z7_BRANCH_CONV_DEC(name)    z7_BranchConv_   ## name ## _Dec
+#define Z7_BRANCH_CONV_ENC(name)    z7_BranchConv_   ## name ## _Enc
+#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(name)); \
+Z7_BRANCH_CONV_DECL(Z7_BRANCH_CONV_ENC(name));
+
+Z7_BRANCH_FUNCS_DECL(ARM64)
+Z7_BRANCH_FUNCS_DECL(ARM)
+Z7_BRANCH_FUNCS_DECL(ARMT)
+Z7_BRANCH_FUNCS_DECL(PPC)
+Z7_BRANCH_FUNCS_DECL(SPARC)
+Z7_BRANCH_FUNCS_DECL(IA64)
+
+/*
+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 Pinter) 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
+  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 a6463c6..d81f392 100644
--- a/C/Bra86.c
+++ b/C/Bra86.c
@@ -1,82 +1,187 @@
-/* Bra86.c -- Converter for x86 code (BCJ)

-2017-04-03 : Igor Pavlov : Public domain */

-

-#include "Precomp.h"

-

-#include "Bra.h"

-

-#define Test86MSByte(b) ((((b) + 1) & 0xFE) == 0)

-

-SizeT x86_Convert(Byte *data, SizeT size, UInt32 ip, UInt32 *state, int encoding)

-{

-  SizeT pos = 0;

-  UInt32 mask = *state & 7;

-  if (size < 5)

-    return 0;

-  size -= 4;

-  ip += 5;

-

-  for (;;)

-  {

-    Byte *p = data + pos;

-    const Byte *limit = data + size;

-    for (; p < limit; p++)

-      if ((*p & 0xFE) == 0xE8)

-        break;

-

-    {

-      SizeT d = (SizeT)(p - data - pos);

-      pos = (SizeT)(p - data);

-      if (p >= limit)

-      {

-        *state = (d > 2 ? 0 : mask >> (unsigned)d);

-        return pos;

-      }

-      if (d > 2)

-        mask = 0;

-      else

-      {

-        mask >>= (unsigned)d;

-        if (mask != 0 && (mask > 4 || mask == 3 || Test86MSByte(p[(size_t)(mask >> 1) + 1])))

-        {

-          mask = (mask >> 1) | 4;

-          pos++;

-          continue;

-        }

-      }

-    }

-

-    if (Test86MSByte(p[4]))

-    {

-      UInt32 v = ((UInt32)p[4] << 24) | ((UInt32)p[3] << 16) | ((UInt32)p[2] << 8) | ((UInt32)p[1]);

-      UInt32 cur = ip + (UInt32)pos;

-      pos += 5;

-      if (encoding)

-        v += cur;

-      else

-        v -= cur;

-      if (mask != 0)

-      {

-        unsigned sh = (mask & 6) << 2;

-        if (Test86MSByte((Byte)(v >> sh)))

-        {

-          v ^= (((UInt32)0x100 << sh) - 1);

-          if (encoding)

-            v += cur;

-          else

-            v -= cur;

-        }

-        mask = 0;

-      }

-      p[1] = (Byte)v;

-      p[2] = (Byte)(v >> 8);

-      p[3] = (Byte)(v >> 16);

-      p[4] = (Byte)(0 - ((v >> 24) & 1));

-    }

-    else

-    {

-      mask = (mask >> 1) | 4;

-      pos++;

-    }

-  }

-}

+/* 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 2656907..9dfe3e2 100644
--- a/C/BraIA64.c
+++ b/C/BraIA64.c
@@ -1,53 +1,14 @@
-/* BraIA64.c -- Converter for IA-64 code

-2017-01-26 : Igor Pavlov : Public domain */

-

-#include "Precomp.h"

-

-#include "CpuArch.h"

-#include "Bra.h"

-

-SizeT IA64_Convert(Byte *data, SizeT size, UInt32 ip, int encoding)

-{

-  SizeT i;

-  if (size < 16)

-    return 0;

-  size -= 16;

-  i = 0;

-  do

-  {

-    unsigned m = ((UInt32)0x334B0000 >> (data[i] & 0x1E)) & 3;

-    if (m)

-    {

-      m++;

-      do

-      {

-        Byte *p = data + (i + (size_t)m * 5 - 8);

-        if (((p[3] >> m) & 15) == 5

-            && (((p[-1] | ((UInt32)p[0] << 8)) >> m) & 0x70) == 0)

-        {

-          unsigned raw = GetUi32(p);

-          unsigned v = raw >> m;

-          v = (v & 0xFFFFF) | ((v & (1 << 23)) >> 3);

-          

-          v <<= 4;

-          if (encoding)

-            v += ip + (UInt32)i;

-          else

-            v -= ip + (UInt32)i;

-          v >>= 4;

-          

-          v &= 0x1FFFFF;

-          v += 0x700000;

-          v &= 0x8FFFFF;

-          raw &= ~((UInt32)0x8FFFFF << m);

-          raw |= (v << m);

-          SetUi32(p, raw);

-        }

-      }

-      while (++m <= 4);

-    }

-    i += 16;

-  }

-  while (i <= size);

-  return i;

-}

+/* 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
new file mode 100644
index 0000000..05ad6de
--- /dev/null
+++ b/C/BwtSort.c
@@ -0,0 +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];
+}
diff --git a/C/BwtSort.h b/C/BwtSort.h
new file mode 100644
index 0000000..a34b243
--- /dev/null
+++ b/C/BwtSort.h
@@ -0,0 +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
diff --git a/C/Compiler.h b/C/Compiler.h
index c788648..185a52d 100644
--- a/C/Compiler.h
+++ b/C/Compiler.h
@@ -1,33 +1,159 @@
-/* Compiler.h

-2017-04-03 : Igor Pavlov : Public domain */

-

-#ifndef __7Z_COMPILER_H

-#define __7Z_COMPILER_H

-

-#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 _MSC_VER >= 1300

-    #pragma warning(disable : 4996) // This function or variable may be unsafe

-  #else

-    #pragma warning(disable : 4511) // copy constructor could not be generated

-    #pragma warning(disable : 4512) // assignment operator could not be generated

-    #pragma warning(disable : 4514) // unreferenced inline function has been removed

-    #pragma warning(disable : 4702) // unreachable code

-    #pragma warning(disable : 4710) // not inlined

-    #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

-

-#endif

-

-#define UNUSED_VAR(x) (void)x;

-/* #define UNUSED_VAR(x) x=x; */

-

-#endif

+/* Compiler.h : Compiler specific defines and pragmas
+2023-04-02 : 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
+
+// #pragma GCC diagnostic ignored "-Wunknown-pragmas"
+
+#ifdef __clang__
+// padding size of '' with 4 bytes to alignment boundary
+#pragma GCC diagnostic ignored "-Wpadded"
+#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)
+  #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 >= 36000))
+#define Z7_DIAGNOSCTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER \
+  _Pragma("GCC diagnostic push") \
+  _Pragma("GCC diagnostic ignored \"-Wreserved-macro-identifier\"")
+#define Z7_DIAGNOSCTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER \
+  _Pragma("GCC diagnostic pop")
+#else
+#define Z7_DIAGNOSCTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER
+#define Z7_DIAGNOSCTIC_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 ff1890e..33f8a3a 100644
--- a/C/CpuArch.c
+++ b/C/CpuArch.c
@@ -1,218 +1,823 @@
-/* CpuArch.c -- CPU specific code

-2018-02-18: Igor Pavlov : Public domain */

-

-#include "Precomp.h"

-

-#include "CpuArch.h"

-

-#ifdef MY_CPU_X86_OR_AMD64

-

-#if (defined(_MSC_VER) && !defined(MY_CPU_AMD64)) || defined(__GNUC__)

-#define USE_ASM

-#endif

-

-#if !defined(USE_ASM) && _MSC_VER >= 1500

-#include <intrin.h>

-#endif

-

-#if defined(USE_ASM) && !defined(MY_CPU_AMD64)

-static UInt32 CheckFlag(UInt32 flag)

-{

-  #ifdef _MSC_VER

-  __asm pushfd;

-  __asm pop EAX;

-  __asm mov EDX, EAX;

-  __asm xor EAX, flag;

-  __asm push EAX;

-  __asm popfd;

-  __asm pushfd;

-  __asm pop EAX;

-  __asm xor EAX, EDX;

-  __asm push EDX;

-  __asm popfd;

-  __asm and flag, EAX;

-  #else

-  __asm__ __volatile__ (

-    "pushf\n\t"

-    "pop  %%EAX\n\t"

-    "movl %%EAX,%%EDX\n\t"

-    "xorl %0,%%EAX\n\t"

-    "push %%EAX\n\t"

-    "popf\n\t"

-    "pushf\n\t"

-    "pop  %%EAX\n\t"

-    "xorl %%EDX,%%EAX\n\t"

-    "push %%EDX\n\t"

-    "popf\n\t"

-    "andl %%EAX, %0\n\t":

-    "=c" (flag) : "c" (flag) :

-    "%eax", "%edx");

-  #endif

-  return flag;

-}

-#define CHECK_CPUID_IS_SUPPORTED if (CheckFlag(1 << 18) == 0 || CheckFlag(1 << 21) == 0) return False;

-#else

-#define CHECK_CPUID_IS_SUPPORTED

-#endif

-

-void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d)

-{

-  #ifdef USE_ASM

-

-  #ifdef _MSC_VER

-

-  UInt32 a2, b2, c2, d2;

-  __asm xor EBX, EBX;

-  __asm xor ECX, ECX;

-  __asm xor EDX, EDX;

-  __asm mov EAX, function;

-  __asm cpuid;

-  __asm mov a2, EAX;

-  __asm mov b2, EBX;

-  __asm mov c2, ECX;

-  __asm mov d2, EDX;

-

-  *a = a2;

-  *b = b2;

-  *c = c2;

-  *d = d2;

-

-  #else

-

-  __asm__ __volatile__ (

-  #if defined(MY_CPU_AMD64) && defined(__PIC__)

-    "mov %%rbx, %%rdi;"

-    "cpuid;"

-    "xchg %%rbx, %%rdi;"

-    : "=a" (*a) ,

-      "=D" (*b) ,

-  #elif defined(MY_CPU_X86) && defined(__PIC__)

-    "mov %%ebx, %%edi;"

-    "cpuid;"

-    "xchgl %%ebx, %%edi;"

-    : "=a" (*a) ,

-      "=D" (*b) ,

-  #else

-    "cpuid"

-    : "=a" (*a) ,

-      "=b" (*b) ,

-  #endif

-      "=c" (*c) ,

-      "=d" (*d)

-    : "0" (function)) ;

-

-  #endif

-  

-  #else

-

-  int CPUInfo[4];

-  __cpuid(CPUInfo, function);

-  *a = CPUInfo[0];

-  *b = CPUInfo[1];

-  *c = CPUInfo[2];

-  *d = CPUInfo[3];

-

-  #endif

-}

-

-BoolInt x86cpuid_CheckAndRead(Cx86cpuid *p)

-{

-  CHECK_CPUID_IS_SUPPORTED

-  MyCPUID(0, &p->maxFunc, &p->vendor[0], &p->vendor[2], &p->vendor[1]);

-  MyCPUID(1, &p->ver, &p->b, &p->c, &p->d);

-  return True;

-}

-

-static const UInt32 kVendors[][3] =

-{

-  { 0x756E6547, 0x49656E69, 0x6C65746E},

-  { 0x68747541, 0x69746E65, 0x444D4163},

-  { 0x746E6543, 0x48727561, 0x736C7561}

-};

-

-int x86cpuid_GetFirm(const Cx86cpuid *p)

-{

-  unsigned i;

-  for (i = 0; i < sizeof(kVendors) / sizeof(kVendors[i]); 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;

-  int firm;

-  UInt32 family, model;

-  if (!x86cpuid_CheckAndRead(&p))

-    return True;

-

-  family = x86cpuid_GetFamily(p.ver);

-  model = x86cpuid_GetModel(p.ver);

-  

-  firm = x86cpuid_GetFirm(&p);

-

-  switch (firm)

-  {

-    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 True;

-}

-

-#if !defined(MY_CPU_AMD64) && defined(_WIN32)

-#include <windows.h>

-static BoolInt CPU_Sys_Is_SSE_Supported()

-{

-  OSVERSIONINFO vi;

-  vi.dwOSVersionInfoSize = sizeof(vi);

-  if (!GetVersionEx(&vi))

-    return False;

-  return (vi.dwMajorVersion >= 5);

-}

-#define CHECK_SYS_SSE_SUPPORT if (!CPU_Sys_Is_SSE_Supported()) return False;

-#else

-#define CHECK_SYS_SSE_SUPPORT

-#endif

-

-BoolInt CPU_Is_Aes_Supported()

-{

-  Cx86cpuid p;

-  CHECK_SYS_SSE_SUPPORT

-  if (!x86cpuid_CheckAndRead(&p))

-    return False;

-  return (p.c >> 25) & 1;

-}

-

-BoolInt CPU_IsSupported_PageGB()

-{

-  Cx86cpuid cpuid;

-  if (!x86cpuid_CheckAndRead(&cpuid))

-    return False;

-  {

-    UInt32 d[4] = { 0 };

-    MyCPUID(0x80000000, &d[0], &d[1], &d[2], &d[3]);

-    if (d[0] < 0x80000001)

-      return False;

-  }

-  {

-    UInt32 d[4] = { 0 };

-    MyCPUID(0x80000001, &d[0], &d[1], &d[2], &d[3]);

-    return (d[3] >> 26) & 1;

-  }

-}

-

-#endif

+/* CpuArch.c -- CPU specific code
+2023-05-18 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+// #include <stdio.h>
+
+#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 <cpuid.h> 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 <cpuid.h>
+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 <intrin.h>
+      #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(UInt32 subFunction, UInt32 func, int *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((int *)p, (int)func, 0);
+}
+
+Z7_NO_INLINE
+UInt32 Z7_FASTCALL z7_x86_cpuid_GetMaxFunc(void)
+{
+  int 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 (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 (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 (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 (x86cpuid_Func_1_ECX() >> 25) & 1;
+}
+
+BoolInt CPU_IsSupported_SSSE3(void)
+{
+  return (x86cpuid_Func_1_ECX() >> 9) & 1;
+}
+
+BoolInt CPU_IsSupported_SSE41(void)
+{
+  return (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 (d[1] >> 29) & 1;
+  }
+}
+
+/*
+MSVC: _xgetbv() intrinsic is available since VS2010SP1.
+   MSVC also defines (_XCR_XFEATURE_ENABLED_MASK) macro in
+   <immintrin.h> 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 <immintrin.h>
+#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=%d\n", bm);
+    return 1
+        & (bm >> 1)  // SSE state is supported (set by OS) for storing/restoring
+        & (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
+      & (d[1] >> 5); // avx2
+  }
+}
+
+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
+      & (d[1] >> 5) // avx2
+      // & (d[1] >> 31) // avx512vl
+      & (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 (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 <stdio.h>
+#include <string.h>
+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__
+
+#include <sys/auxv.h>
+
+#define USE_HWCAP
+
+#ifdef USE_HWCAP
+
+#include <asm/hwcap.h>
+
+  #define MY_HWCAP_CHECK_FUNC_2(name1, name2) \
+  BoolInt CPU_IsSupported_ ## name1() { return (getauxval(AT_HWCAP)  & (HWCAP_  ## name2)) ? 1 : 0; }
+
+#ifdef MY_CPU_ARM64
+  #define MY_HWCAP_CHECK_FUNC(name) \
+  MY_HWCAP_CHECK_FUNC_2(name, name)
+  MY_HWCAP_CHECK_FUNC_2(NEON, ASIMD)
+// MY_HWCAP_CHECK_FUNC (ASIMD)
+#elif defined(MY_CPU_ARM)
+  #define MY_HWCAP_CHECK_FUNC(name) \
+  BoolInt CPU_IsSupported_ ## name() { return (getauxval(AT_HWCAP2) & (HWCAP2_ ## name)) ? 1 : 0; }
+  MY_HWCAP_CHECK_FUNC_2(NEON, NEON)
+#endif
+
+#else // USE_HWCAP
+
+  #define MY_HWCAP_CHECK_FUNC(name) \
+  BoolInt CPU_IsSupported_ ## name() { return 0; }
+  MY_HWCAP_CHECK_FUNC(NEON)
+
+#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 <sys/sysctl.h>
+
+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 5f74c1c..8e5d8a5 100644
--- a/C/CpuArch.h
+++ b/C/CpuArch.h
@@ -1,336 +1,523 @@
-/* CpuArch.h -- CPU specific code

-2018-02-18 : Igor Pavlov : Public domain */

-

-#ifndef __CPU_ARCH_H

-#define __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.

-*/

-

-#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"

-  #else

-    #define MY_CPU_NAME "x64"

-  #endif

-  #define MY_CPU_64BIT

-#endif

-

-

-#if  defined(_M_IX86) \

-  || defined(__i386__)

-  #define MY_CPU_X86

-  #define MY_CPU_NAME "x86"

-  #define MY_CPU_32BIT

-#endif

-

-

-#if  defined(_M_ARM64) \

-  || defined(__AARCH64EL__) \

-  || defined(__AARCH64EB__) \

-  || defined(__aarch64__)

-  #define MY_CPU_ARM64

-  #define MY_CPU_NAME "arm64"

-  #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

-  #define MY_CPU_NAME "arm"

-  #define MY_CPU_32BIT

-#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__)

-  #ifdef __ILP32__

-    #define MY_CPU_NAME "ppc64-32"

-  #else

-    #define MY_CPU_NAME "ppc64"

-  #endif

-  #define MY_CPU_64BIT

-#elif defined(__ppc__) \

-  || defined(__powerpc__)

-  #define MY_CPU_NAME "ppc"

-  #define MY_CPU_32BIT

-#endif

-

-

-#if  defined(__sparc64__)

-  #define MY_CPU_NAME "sparc64"

-  #define MY_CPU_64BIT

-#elif defined(__sparc__)

-  #define MY_CPU_NAME "sparc"

-  /* #define MY_CPU_32BIT */

-#endif

-

-

-#if defined(MY_CPU_X86) || defined(MY_CPU_AMD64)

-#define MY_CPU_X86_OR_AMD64

-#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(__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_32BIT) && defined(MY_CPU_64BIT)

-  #error Stop_Compiling_Bad_32_64_BIT

-#endif

-

-

-#ifndef MY_CPU_NAME

-  #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 MY_CPU_LE

-  #if defined(MY_CPU_X86_OR_AMD64) \

-      || defined(MY_CPU_ARM64) \

-      || defined(__ARM_FEATURE_UNALIGNED)

-    #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))

-#define GetUi64(p) (*(const UInt64 *)(const void *)(p))

-

-#define SetUi16(p, v) { *(UInt16 *)(p) = (v); }

-#define SetUi32(p, v) { *(UInt32 *)(p) = (v); }

-#define SetUi64(p, v) { *(UInt64 *)(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 GetUi64(p) (GetUi32(p) | ((UInt64)GetUi32(((const Byte *)(p)) + 4) << 32))

-

-#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); }

-

-#define SetUi64(p, v) { Byte *_ppp2_ = (Byte *)(p); UInt64 _vvv2_ = (v); \

-    SetUi32(_ppp2_    , (UInt32)_vvv2_); \

-    SetUi32(_ppp2_ + 4, (UInt32)(_vvv2_ >> 32)); }

-

-#endif

-

-#ifdef __has_builtin

-  #define MY__has_builtin(x) __has_builtin(x)

-#else

-  #define MY__has_builtin(x) 0

-#endif

-

-#if defined(MY_CPU_LE_UNALIGN) && /* defined(_WIN64) && */ (_MSC_VER >= 1300)

-

-/* Note: we use bswap instruction, that is unsupported in 386 cpu */

-

-#include <stdlib.h>

-

-#pragma intrinsic(_byteswap_ushort)

-#pragma intrinsic(_byteswap_ulong)

-#pragma intrinsic(_byteswap_uint64)

-

-/* #define GetBe16(p) _byteswap_ushort(*(const UInt16 *)(const Byte *)(p)) */

-#define GetBe32(p) _byteswap_ulong(*(const UInt32 *)(const Byte *)(p))

-#define GetBe64(p) _byteswap_uint64(*(const UInt64 *)(const Byte *)(p))

-

-#define SetBe32(p, v) (*(UInt32 *)(void *)(p)) = _byteswap_ulong(v)

-

-#elif defined(MY_CPU_LE_UNALIGN) && ( \

-       (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))) \

-    || (defined(__clang__) && MY__has_builtin(__builtin_bswap16)) )

-

-/* #define GetBe16(p) __builtin_bswap16(*(const UInt16 *)(const Byte *)(p)) */

-#define GetBe32(p) __builtin_bswap32(*(const UInt32 *)(const Byte *)(p))

-#define GetBe64(p) __builtin_bswap64(*(const UInt64 *)(const Byte *)(p))

-

-#define SetBe32(p, v) (*(UInt32 *)(void *)(p)) = __builtin_bswap32(v)

-

-#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 GetBe64(p) (((UInt64)GetBe32(p) << 32) | GetBe32(((const Byte *)(p)) + 4))

-

-#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 GetBe16

-

-#define GetBe16(p) ( (UInt16) ( \

-    ((UInt16)((const Byte *)(p))[0] << 8) | \

-             ((const Byte *)(p))[1] ))

-

-#endif

-

-

-

-#ifdef MY_CPU_X86_OR_AMD64

-

-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

-};

-

-void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d);

-

-BoolInt x86cpuid_CheckAndRead(Cx86cpuid *p);

-int x86cpuid_GetFirm(const Cx86cpuid *p);

-

-#define x86cpuid_GetFamily(ver) (((ver >> 16) & 0xFF0) | ((ver >> 8) & 0xF))

-#define x86cpuid_GetModel(ver)  (((ver >> 12) &  0xF0) | ((ver >> 4) & 0xF))

-#define x86cpuid_GetStepping(ver) (ver & 0xF)

-

-BoolInt CPU_Is_InOrder();

-BoolInt CPU_Is_Aes_Supported();

-BoolInt CPU_IsSupported_PageGB();

-

-#endif

-

-EXTERN_C_END

-

-#endif

+/* CpuArch.h -- CPU specific code
+2023-04-02 : 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_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
+
+
+#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(__AARCH64EL__) \
+  || defined(__AARCH64EB__) \
+  || defined(__aarch64__)
+  #define MY_CPU_ARM64
+  #ifdef __ILP32__
+    #define MY_CPU_NAME "arm64-32"
+    #define MY_CPU_SIZEOF_POINTER 4
+  #else
+    #define MY_CPU_NAME "arm64"
+    #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(__riscv) \
+  || defined(__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(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(__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
+  #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 <stdlib.h>
+
+/* 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
+
+#elif  (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)
+    #define MY_CPU_LE_UNALIGN
+    #define MY_CPU_LE_UNALIGN_64
+  #elif defined(__ARM_FEATURE_UNALIGNED)
+    /* gcc9 for 32-bit arm can use LDRD instruction that requires 32-bit alignment.
+       So we can't use unaligned 64-bit operations. */
+    #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 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 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 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 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_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
diff --git a/C/Delta.c b/C/Delta.c
index 6cbbe46..c4a4499 100644
--- a/C/Delta.c
+++ b/C/Delta.c
@@ -1,64 +1,169 @@
-/* Delta.c -- Delta converter

-2009-05-26 : 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;

-}

-

-static void MyMemCpy(Byte *dest, const Byte *src, unsigned size)

-{

-  unsigned i;

-  for (i = 0; i < size; i++)

-    dest[i] = src[i];

-}

-

-void Delta_Encode(Byte *state, unsigned delta, Byte *data, SizeT size)

-{

-  Byte buf[DELTA_STATE_SIZE];

-  unsigned j = 0;

-  MyMemCpy(buf, state, delta);

-  {

-    SizeT i;

-    for (i = 0; i < size;)

-    {

-      for (j = 0; j < delta && i < size; i++, j++)

-      {

-        Byte b = data[i];

-        data[i] = (Byte)(b - buf[j]);

-        buf[j] = b;

-      }

-    }

-  }

-  if (j == delta)

-    j = 0;

-  MyMemCpy(state, buf + j, delta - j);

-  MyMemCpy(state + delta - j, buf, j);

-}

-

-void Delta_Decode(Byte *state, unsigned delta, Byte *data, SizeT size)

-{

-  Byte buf[DELTA_STATE_SIZE];

-  unsigned j = 0;

-  MyMemCpy(buf, state, delta);

-  {

-    SizeT i;

-    for (i = 0; i < size;)

-    {

-      for (j = 0; j < delta && i < size; i++, j++)

-      {

-        buf[j] = data[i] = (Byte)(buf[j] + data[i]);

-      }

-    }

-  }

-  if (j == delta)

-    j = 0;

-  MyMemCpy(state, buf + j, delta - j);

-  MyMemCpy(state + delta - j, buf, j);

-}

+/* 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 e59d5a2..7060954 100644
--- a/C/Delta.h
+++ b/C/Delta.h
@@ -1,19 +1,19 @@
-/* Delta.h -- Delta converter

-2013-01-18 : Igor Pavlov : Public domain */

-

-#ifndef __DELTA_H

-#define __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 19a22a9..02a0f97 100644
--- a/C/DllSecur.c
+++ b/C/DllSecur.c
@@ -1,108 +1,111 @@
-/* DllSecur.c -- DLL loading security

-2018-02-21 : Igor Pavlov : Public domain */

-

-#include "Precomp.h"

-

-#ifdef _WIN32

-

-#include <windows.h>

-

-#include "DllSecur.h"

-

-#ifndef UNDER_CE

-

-typedef BOOL (WINAPI *Func_SetDefaultDllDirectories)(DWORD DirectoryFlags);

-

-#define MY_LOAD_LIBRARY_SEARCH_USER_DIRS 0x400

-#define MY_LOAD_LIBRARY_SEARCH_SYSTEM32  0x800

-

-static const char * const g_Dlls =

-  #ifndef _CONSOLE

-  "UXTHEME\0"

-  #endif

-  "USERENV\0"

-  "SETUPAPI\0"

-  "APPHELP\0"

-  "PROPSYS\0"

-  "DWMAPI\0"

-  "CRYPTBASE\0"

-  "OLEACC\0"

-  "CLBCATQ\0"

-  "VERSION\0"

-  ;

-

-#endif

-

-void My_SetDefaultDllDirectories()

-{

-  #ifndef UNDER_CE

-  

-    OSVERSIONINFO vi;

-    vi.dwOSVersionInfoSize = sizeof(vi);

-    GetVersionEx(&vi);

-    if (!GetVersionEx(&vi) || vi.dwMajorVersion != 6 || vi.dwMinorVersion != 0)

-    {

-      Func_SetDefaultDllDirectories setDllDirs = (Func_SetDefaultDllDirectories)

-          GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "SetDefaultDllDirectories");

-      if (setDllDirs)

-        if (setDllDirs(MY_LOAD_LIBRARY_SEARCH_SYSTEM32 | MY_LOAD_LIBRARY_SEARCH_USER_DIRS))

-          return;

-    }

-

-  #endif

-}

-

-

-void LoadSecurityDlls()

-{

-  #ifndef UNDER_CE

-  

-  wchar_t buf[MAX_PATH + 100];

-

-  {

-    // at Vista (ver 6.0) : CoCreateInstance(CLSID_ShellLink, ...) doesn't work after SetDefaultDllDirectories() : Check it ???

-    OSVERSIONINFO vi;

-    vi.dwOSVersionInfoSize = sizeof(vi);

-    if (!GetVersionEx(&vi) || vi.dwMajorVersion != 6 || vi.dwMinorVersion != 0)

-    {

-      Func_SetDefaultDllDirectories setDllDirs = (Func_SetDefaultDllDirectories)

-          GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "SetDefaultDllDirectories");

-      if (setDllDirs)

-        if (setDllDirs(MY_LOAD_LIBRARY_SEARCH_SYSTEM32 | MY_LOAD_LIBRARY_SEARCH_USER_DIRS))

-          return;

-    }

-  }

-

-  {

-    unsigned len = GetSystemDirectoryW(buf, MAX_PATH + 2);

-    if (len == 0 || len > MAX_PATH)

-      return;

-  }

-  {

-    const char *dll;

-    unsigned pos = (unsigned)lstrlenW(buf);

-

-    if (buf[pos - 1] != '\\')

-      buf[pos++] = '\\';

-    

-    for (dll = g_Dlls; dll[0] != 0;)

-    {

-      unsigned k = 0;

-      for (;;)

-      {

-        char c = *dll++;

-        buf[pos + k] = (Byte)c;

-        k++;

-        if (c == 0)

-          break;

-      }

-

-      lstrcatW(buf, L".dll");

-      LoadLibraryExW(buf, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);

-    }

-  }

-  

-  #endif

-}

-

-#endif

+/* DllSecur.c -- DLL loading security
+2023-04-02 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#ifdef _WIN32
+
+#include "7zWindows.h"
+
+#include "DllSecur.h"
+
+#ifndef UNDER_CE
+
+#if (defined(__GNUC__) && (__GNUC__ >= 8)) || defined(__clang__)
+  // #pragma GCC diagnostic ignored "-Wcast-function-type"
+#endif
+
+#if defined(__clang__) || defined(__GNUC__)
+typedef void (*Z7_voidFunction)(void);
+#define MY_CAST_FUNC (Z7_voidFunction)
+#elif defined(_MSC_VER) && _MSC_VER > 1920
+#define MY_CAST_FUNC  (void *)
+// #pragma warning(disable : 4191) // 'type cast': unsafe conversion from 'FARPROC' to 'void (__cdecl *)()'
+#else
+#define MY_CAST_FUNC
+#endif
+
+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) MY_CAST_FUNC 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 4c11356..9fa4153 100644
--- a/C/DllSecur.h
+++ b/C/DllSecur.h
@@ -1,20 +1,20 @@
-/* DllSecur.h -- DLL loading for security

-2018-02-19 : Igor Pavlov : Public domain */

-

-#ifndef __DLL_SECUR_H

-#define __DLL_SECUR_H

-

-#include "7zTypes.h"

-

-EXTERN_C_BEGIN

-

-#ifdef _WIN32

-

-void My_SetDefaultDllDirectories();

-void LoadSecurityDlls();

-

-#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
new file mode 100644
index 0000000..3dc1e39
--- /dev/null
+++ b/C/HuffEnc.c
@@ -0,0 +1,154 @@
+/* HuffEnc.c -- functions for Huffman encoding
+2023-03-04 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "HuffEnc.h"
+#include "Sort.h"
+
+#define kMaxLen 16
+#define NUM_BITS 10
+#define MASK (((unsigned)1 << 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
new file mode 100644
index 0000000..cbc5d11
--- /dev/null
+++ b/C/HuffEnc.h
@@ -0,0 +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
diff --git a/C/LzFind.c b/C/LzFind.c
index 4eefc17..0fbd5aa 100644
--- a/C/LzFind.c
+++ b/C/LzFind.c
@@ -1,1127 +1,1717 @@
-/* LzFind.c -- Match finder for LZ algorithms

-2018-07-08 : Igor Pavlov : Public domain */

-

-#include "Precomp.h"

-

-#include <string.h>

-

-#include "LzFind.h"

-#include "LzHash.h"

-

-#define kEmptyHashValue 0

-#define kMaxValForNormalize ((UInt32)0xFFFFFFFF)

-#define kNormalizeStepMin (1 << 10) /* it must be power of 2 */

-#define kNormalizeMask (~(UInt32)(kNormalizeStepMin - 1))

-#define kMaxHistorySize ((UInt32)7 << 29)

-

-#define kStartMaxLen 3

-

-static void LzInWindow_Free(CMatchFinder *p, ISzAllocPtr alloc)

-{

-  if (!p->directInput)

-  {

-    ISzAlloc_Free(alloc, p->bufferBase);

-    p->bufferBase = NULL;

-  }

-}

-

-/* keepSizeBefore + keepSizeAfter + keepSizeReserv must be < 4G) */

-

-static int LzInWindow_Create(CMatchFinder *p, UInt32 keepSizeReserv, ISzAllocPtr alloc)

-{

-  UInt32 blockSize = p->keepSizeBefore + p->keepSizeAfter + keepSizeReserv;

-  if (p->directInput)

-  {

-    p->blockSize = blockSize;

-    return 1;

-  }

-  if (!p->bufferBase || p->blockSize != blockSize)

-  {

-    LzInWindow_Free(p, alloc);

-    p->blockSize = blockSize;

-    p->bufferBase = (Byte *)ISzAlloc_Alloc(alloc, (size_t)blockSize);

-  }

-  return (p->bufferBase != NULL);

-}

-

-Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; }

-

-UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; }

-

-void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue)

-{

-  p->posLimit -= subValue;

-  p->pos -= subValue;

-  p->streamPos -= subValue;

-}

-

-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 - (p->streamPos - p->pos);

-    if (curSize > p->directInputRem)

-      curSize = (UInt32)p->directInputRem;

-    p->directInputRem -= curSize;

-    p->streamPos += curSize;

-    if (p->directInputRem == 0)

-      p->streamEndWasReached = 1;

-    return;

-  }

-  

-  for (;;)

-  {

-    Byte *dest = p->buffer + (p->streamPos - p->pos);

-    size_t size = (p->bufferBase + p->blockSize - dest);

-    if (size == 0)

-      return;

-

-    p->result = ISeqInStream_Read(p->stream, dest, &size);

-    if (p->result != SZ_OK)

-      return;

-    if (size == 0)

-    {

-      p->streamEndWasReached = 1;

-      return;

-    }

-    p->streamPos += (UInt32)size;

-    if (p->streamPos - p->pos > p->keepSizeAfter)

-      return;

-  }

-}

-

-void MatchFinder_MoveBlock(CMatchFinder *p)

-{

-  memmove(p->bufferBase,

-      p->buffer - p->keepSizeBefore,

-      (size_t)(p->streamPos - p->pos) + p->keepSizeBefore);

-  p->buffer = p->bufferBase + p->keepSizeBefore;

-}

-

-int MatchFinder_NeedMove(CMatchFinder *p)

-{

-  if (p->directInput)

-    return 0;

-  /* if (p->streamEndWasReached) return 0; */

-  return ((size_t)(p->bufferBase + p->blockSize - p->buffer) <= p->keepSizeAfter);

-}

-

-void MatchFinder_ReadIfRequired(CMatchFinder *p)

-{

-  if (p->streamEndWasReached)

-    return;

-  if (p->keepSizeAfter >= p->streamPos - p->pos)

-    MatchFinder_ReadBlock(p);

-}

-

-static void MatchFinder_CheckAndMoveAndRead(CMatchFinder *p)

-{

-  if (MatchFinder_NeedMove(p))

-    MatchFinder_MoveBlock(p);

-  MatchFinder_ReadBlock(p);

-}

-

-static void MatchFinder_SetDefaultSettings(CMatchFinder *p)

-{

-  p->cutValue = 32;

-  p->btMode = 1;

-  p->numHashBytes = 4;

-  p->bigHash = 0;

-}

-

-#define kCrcPoly 0xEDB88320

-

-void MatchFinder_Construct(CMatchFinder *p)

-{

-  unsigned i;

-  p->bufferBase = NULL;

-  p->directInput = 0;

-  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;

-  }

-}

-

-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)

-{

-  size_t sizeInBytes = (size_t)num * sizeof(CLzRef);

-  if (sizeInBytes / sizeof(CLzRef) != num)

-    return NULL;

-  return (CLzRef *)ISzAlloc_Alloc(alloc, sizeInBytes);

-}

-

-int MatchFinder_Create(CMatchFinder *p, UInt32 historySize,

-    UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,

-    ISzAllocPtr alloc)

-{

-  UInt32 sizeReserv;

-  

-  if (historySize > kMaxHistorySize)

-  {

-    MatchFinder_Free(p, alloc);

-    return 0;

-  }

-  

-  sizeReserv = historySize >> 1;

-       if (historySize >= ((UInt32)3 << 30)) sizeReserv = historySize >> 3;

-  else if (historySize >= ((UInt32)2 << 30)) sizeReserv = historySize >> 2;

-  

-  sizeReserv += (keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) / 2 + (1 << 19);

-

-  p->keepSizeBefore = historySize + keepAddBufferBefore + 1;

-  p->keepSizeAfter = matchMaxLen + keepAddBufferAfter;

-  

-  /* we need one additional byte, since we use MoveBlock after pos++ and before dictionary using */

-  

-  if (LzInWindow_Create(p, sizeReserv, alloc))

-  {

-    UInt32 newCyclicBufferSize = historySize + 1;

-    UInt32 hs;

-    p->matchMaxLen = matchMaxLen;

-    {

-      p->fixedHashSize = 0;

-      if (p->numHashBytes == 2)

-        hs = (1 << 16) - 1;

-      else

-      {

-        hs = historySize;

-        if (hs > p->expectedDataSize)

-          hs = (UInt32)p->expectedDataSize;

-        if (hs != 0)

-          hs--;

-        hs |= (hs >> 1);

-        hs |= (hs >> 2);

-        hs |= (hs >> 4);

-        hs |= (hs >> 8);

-        hs >>= 1;

-        hs |= 0xFFFF; /* don't change it! It's required for Deflate */

-        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))) */

-        }

-      }

-      p->hashMask = hs;

-      hs++;

-      if (p->numHashBytes > 2) p->fixedHashSize += kHash2Size;

-      if (p->numHashBytes > 3) p->fixedHashSize += kHash3Size;

-      if (p->numHashBytes > 4) p->fixedHashSize += kHash4Size;

-      hs += p->fixedHashSize;

-    }

-

-    {

-      size_t newSize;

-      size_t numSons;

-      p->historySize = historySize;

-      p->hashSizeSum = hs;

-      p->cyclicBufferSize = newCyclicBufferSize;

-      

-      numSons = newCyclicBufferSize;

-      if (p->btMode)

-        numSons <<= 1;

-      newSize = hs + numSons;

-

-      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 + p->hashSizeSum;

-        return 1;

-      }

-    }

-  }

-

-  MatchFinder_Free(p, alloc);

-  return 0;

-}

-

-static void MatchFinder_SetLimits(CMatchFinder *p)

-{

-  UInt32 limit = kMaxValForNormalize - p->pos;

-  UInt32 limit2 = p->cyclicBufferSize - p->cyclicBufferPos;

-  

-  if (limit2 < limit)

-    limit = limit2;

-  limit2 = p->streamPos - p->pos;

-  

-  if (limit2 <= p->keepSizeAfter)

-  {

-    if (limit2 > 0)

-      limit2 = 1;

-  }

-  else

-    limit2 -= p->keepSizeAfter;

-  

-  if (limit2 < limit)

-    limit = limit2;

-  

-  {

-    UInt32 lenLimit = p->streamPos - p->pos;

-    if (lenLimit > p->matchMaxLen)

-      lenLimit = p->matchMaxLen;

-    p->lenLimit = lenLimit;

-  }

-  p->posLimit = p->pos + limit;

-}

-

-

-void MatchFinder_Init_LowHash(CMatchFinder *p)

-{

-  size_t i;

-  CLzRef *items = p->hash;

-  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;

-  size_t numItems = (size_t)p->hashMask + 1;

-  for (i = 0; i < numItems; i++)

-    items[i] = kEmptyHashValue;

-}

-

-

-void MatchFinder_Init_3(CMatchFinder *p, int readData)

-{

-  p->cyclicBufferPos = 0;

-  p->buffer = p->bufferBase;

-  p->pos =

-  p->streamPos = p->cyclicBufferSize;

-  p->result = SZ_OK;

-  p->streamEndWasReached = 0;

-  

-  if (readData)

-    MatchFinder_ReadBlock(p);

-  

-  MatchFinder_SetLimits(p);

-}

-

-

-void MatchFinder_Init(CMatchFinder *p)

-{

-  MatchFinder_Init_HighHash(p);

-  MatchFinder_Init_LowHash(p);

-  MatchFinder_Init_3(p, True);

-}

-

-  

-static UInt32 MatchFinder_GetSubValue(CMatchFinder *p)

-{

-  return (p->pos - p->historySize - 1) & kNormalizeMask;

-}

-

-void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, size_t numItems)

-{

-  size_t i;

-  for (i = 0; i < numItems; i++)

-  {

-    UInt32 value = items[i];

-    if (value <= subValue)

-      value = kEmptyHashValue;

-    else

-      value -= subValue;

-    items[i] = value;

-  }

-}

-

-static void MatchFinder_Normalize(CMatchFinder *p)

-{

-  UInt32 subValue = MatchFinder_GetSubValue(p);

-  MatchFinder_Normalize3(subValue, p->hash, p->numRefs);

-  MatchFinder_ReduceOffsets(p, subValue);

-}

-

-

-MY_NO_INLINE

-static void MatchFinder_CheckLimits(CMatchFinder *p)

-{

-  if (p->pos == kMaxValForNormalize)

-    MatchFinder_Normalize(p);

-  if (!p->streamEndWasReached && p->keepSizeAfter == p->streamPos - p->pos)

-    MatchFinder_CheckAndMoveAndRead(p);

-  if (p->cyclicBufferPos == p->cyclicBufferSize)

-    p->cyclicBufferPos = 0;

-  MatchFinder_SetLimits(p);

-}

-

-

-/*

-  (lenLimit > maxLen)

-*/

-MY_FORCE_INLINE

-static UInt32 * Hc_GetMatchesSpec(unsigned lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,

-    UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue,

-    UInt32 *distances, unsigned maxLen)

-{

-  /*

-  son[_cyclicBufferPos] = curMatch;

-  for (;;)

-  {

-    UInt32 delta = pos - curMatch;

-    if (cutValue-- == 0 || delta >= _cyclicBufferSize)

-      return distances;

-    {

-      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;

-          *distances++ = len;

-          *distances++ = delta - 1;

-          if (len == lenLimit)

-            return distances;

-        }

-      }

-    }

-  }

-  */

-

-  const Byte *lim = cur + lenLimit;

-  son[_cyclicBufferPos] = curMatch;

-  do

-  {

-    UInt32 delta = pos - curMatch;

-    if (delta >= _cyclicBufferSize)

-      break;

-    {

-      ptrdiff_t diff;

-      curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)];

-      diff = (ptrdiff_t)0 - delta;

-      if (cur[maxLen] == cur[maxLen + diff])

-      {

-        const Byte *c = cur;

-        while (*c == c[diff])

-        {

-          if (++c == lim)

-          {

-            distances[0] = (UInt32)(lim - cur);

-            distances[1] = delta - 1;

-            return distances + 2;

-          }

-        }

-        {

-          unsigned len = (unsigned)(c - cur);

-          if (maxLen < len)

-          {

-            maxLen = len;

-            distances[0] = (UInt32)len;

-            distances[1] = delta - 1;

-            distances += 2;

-          }

-        }

-      }

-    }

-  }

-  while (--cutValue);

-  

-  return distances;

-}

-

-

-MY_FORCE_INLINE

-UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,

-    UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue,

-    UInt32 *distances, UInt32 maxLen)

-{

-  CLzRef *ptr0 = son + ((size_t)_cyclicBufferPos << 1) + 1;

-  CLzRef *ptr1 = son + ((size_t)_cyclicBufferPos << 1);

-  unsigned len0 = 0, len1 = 0;

-  for (;;)

-  {

-    UInt32 delta = pos - curMatch;

-    if (cutValue-- == 0 || delta >= _cyclicBufferSize)

-    {

-      *ptr0 = *ptr1 = kEmptyHashValue;

-      return distances;

-    }

-    {

-      CLzRef *pair = son + ((size_t)(_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);

-      const Byte *pb = cur - delta;

-      unsigned len = (len0 < len1 ? len0 : len1);

-      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;

-          *distances++ = (UInt32)len;

-          *distances++ = delta - 1;

-          if (len == lenLimit)

-          {

-            *ptr1 = pair0;

-            *ptr0 = pair[1];

-            return distances;

-          }

-        }

-      }

-      if (pb[len] < cur[len])

-      {

-        *ptr1 = curMatch;

-        ptr1 = pair + 1;

-        curMatch = *ptr1;

-        len1 = len;

-      }

-      else

-      {

-        *ptr0 = curMatch;

-        ptr0 = pair;

-        curMatch = *ptr0;

-        len0 = len;

-      }

-    }

-  }

-}

-

-static void SkipMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,

-    UInt32 _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;

-  for (;;)

-  {

-    UInt32 delta = pos - curMatch;

-    if (cutValue-- == 0 || delta >= _cyclicBufferSize)

-    {

-      *ptr0 = *ptr1 = kEmptyHashValue;

-      return;

-    }

-    {

-      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;

-        ptr1 = pair + 1;

-        curMatch = *ptr1;

-        len1 = len;

-      }

-      else

-      {

-        *ptr0 = curMatch;

-        ptr0 = pair;

-        curMatch = *ptr0;

-        len0 = len;

-      }

-    }

-  }

-}

-

-#define MOVE_POS \

-  ++p->cyclicBufferPos; \

-  p->buffer++; \

-  if (++p->pos == p->posLimit) MatchFinder_CheckLimits(p);

-

-#define MOVE_POS_RET MOVE_POS return (UInt32)offset;

-

-static void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; }

-

-#define GET_MATCHES_HEADER2(minLen, ret_op) \

-  unsigned lenLimit; UInt32 hv; const Byte *cur; UInt32 curMatch; \

-  lenLimit = (unsigned)p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \

-  cur = p->buffer;

-

-#define GET_MATCHES_HEADER(minLen) GET_MATCHES_HEADER2(minLen, return 0)

-#define SKIP_HEADER(minLen)        GET_MATCHES_HEADER2(minLen, continue)

-

-#define MF_PARAMS(p) p->pos, p->buffer, p->son, p->cyclicBufferPos, p->cyclicBufferSize, p->cutValue

-

-#define GET_MATCHES_FOOTER(offset, maxLen) \

-  offset = (unsigned)(GetMatchesSpec1((UInt32)lenLimit, curMatch, MF_PARAMS(p), \

-  distances + offset, (UInt32)maxLen) - distances); MOVE_POS_RET;

-

-#define SKIP_FOOTER \

-  SkipMatchesSpec((UInt32)lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS;

-

-#define UPDATE_maxLen { \

-    ptrdiff_t diff = (ptrdiff_t)0 - 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(CMatchFinder *p, UInt32 *distances)

-{

-  unsigned offset;

-  GET_MATCHES_HEADER(2)

-  HASH2_CALC;

-  curMatch = p->hash[hv];

-  p->hash[hv] = p->pos;

-  offset = 0;

-  GET_MATCHES_FOOTER(offset, 1)

-}

-

-UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)

-{

-  unsigned offset;

-  GET_MATCHES_HEADER(3)

-  HASH_ZIP_CALC;

-  curMatch = p->hash[hv];

-  p->hash[hv] = p->pos;

-  offset = 0;

-  GET_MATCHES_FOOTER(offset, 2)

-}

-

-static UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)

-{

-  UInt32 h2, d2, pos;

-  unsigned maxLen, offset;

-  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;

-

-  maxLen = 2;

-  offset = 0;

-

-  if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur)

-  {

-    UPDATE_maxLen

-    distances[0] = (UInt32)maxLen;

-    distances[1] = d2 - 1;

-    offset = 2;

-    if (maxLen == lenLimit)

-    {

-      SkipMatchesSpec((UInt32)lenLimit, curMatch, MF_PARAMS(p));

-      MOVE_POS_RET;

-    }

-  }

-  

-  GET_MATCHES_FOOTER(offset, maxLen)

-}

-

-static UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)

-{

-  UInt32 h2, h3, d2, d3, pos;

-  unsigned maxLen, offset;

-  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;

-

-  maxLen = 0;

-  offset = 0;

-  

-  if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur)

-  {

-    maxLen = 2;

-    distances[0] = 2;

-    distances[1] = d2 - 1;

-    offset = 2;

-  }

-  

-  if (d2 != d3 && d3 < p->cyclicBufferSize && *(cur - d3) == *cur)

-  {

-    maxLen = 3;

-    distances[(size_t)offset + 1] = d3 - 1;

-    offset += 2;

-    d2 = d3;

-  }

-  

-  if (offset != 0)

-  {

-    UPDATE_maxLen

-    distances[(size_t)offset - 2] = (UInt32)maxLen;

-    if (maxLen == lenLimit)

-    {

-      SkipMatchesSpec((UInt32)lenLimit, curMatch, MF_PARAMS(p));

-      MOVE_POS_RET;

-    }

-  }

-  

-  if (maxLen < 3)

-    maxLen = 3;

-  

-  GET_MATCHES_FOOTER(offset, maxLen)

-}

-

-/*

-static UInt32 Bt5_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)

-{

-  UInt32 h2, h3, h4, d2, d3, d4, maxLen, offset, pos;

-  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;

-

-  maxLen = 0;

-  offset = 0;

-

-  if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur)

-  {

-    distances[0] = maxLen = 2;

-    distances[1] = d2 - 1;

-    offset = 2;

-    if (*(cur - d2 + 2) == cur[2])

-      distances[0] = maxLen = 3;

-    else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur)

-    {

-      distances[2] = maxLen = 3;

-      distances[3] = d3 - 1;

-      offset = 4;

-      d2 = d3;

-    }

-  }

-  else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur)

-  {

-    distances[0] = maxLen = 3;

-    distances[1] = d3 - 1;

-    offset = 2;

-    d2 = d3;

-  }

-  

-  if (d2 != d4 && d4 < p->cyclicBufferSize

-      && *(cur - d4) == *cur

-      && *(cur - d4 + 3) == *(cur + 3))

-  {

-    maxLen = 4;

-    distances[(size_t)offset + 1] = d4 - 1;

-    offset += 2;

-    d2 = d4;

-  }

-  

-  if (offset != 0)

-  {

-    UPDATE_maxLen

-    distances[(size_t)offset - 2] = maxLen;

-    if (maxLen == lenLimit)

-    {

-      SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));

-      MOVE_POS_RET;

-    }

-  }

-

-  if (maxLen < 4)

-    maxLen = 4;

-  

-  GET_MATCHES_FOOTER(offset, maxLen)

-}

-*/

-

-static UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)

-{

-  UInt32 h2, h3, d2, d3, pos;

-  unsigned maxLen, offset;

-  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;

-

-  maxLen = 0;

-  offset = 0;

-

-  if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur)

-  {

-    maxLen = 2;

-    distances[0] = 2;

-    distances[1] = d2 - 1;

-    offset = 2;

-  }

-  

-  if (d2 != d3 && d3 < p->cyclicBufferSize && *(cur - d3) == *cur)

-  {

-    maxLen = 3;

-    distances[(size_t)offset + 1] = d3 - 1;

-    offset += 2;

-    d2 = d3;

-  }

-  

-  if (offset != 0)

-  {

-    UPDATE_maxLen

-    distances[(size_t)offset - 2] = (UInt32)maxLen;

-    if (maxLen == lenLimit)

-    {

-      p->son[p->cyclicBufferPos] = curMatch;

-      MOVE_POS_RET;

-    }

-  }

-  

-  if (maxLen < 3)

-    maxLen = 3;

-

-  offset = (unsigned)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),

-      distances + offset, maxLen) - (distances));

-  MOVE_POS_RET

-}

-

-/*

-static UInt32 Hc5_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)

-{

-  UInt32 h2, h3, h4, d2, d3, d4, maxLen, offset, pos

-  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;

-

-  maxLen = 0;

-  offset = 0;

-

-  if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur)

-  {

-    distances[0] = maxLen = 2;

-    distances[1] = d2 - 1;

-    offset = 2;

-    if (*(cur - d2 + 2) == cur[2])

-      distances[0] = maxLen = 3;

-    else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur)

-    {

-      distances[2] = maxLen = 3;

-      distances[3] = d3 - 1;

-      offset = 4;

-      d2 = d3;

-    }

-  }

-  else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur)

-  {

-    distances[0] = maxLen = 3;

-    distances[1] = d3 - 1;

-    offset = 2;

-    d2 = d3;

-  }

-  

-  if (d2 != d4 && d4 < p->cyclicBufferSize

-      && *(cur - d4) == *cur

-      && *(cur - d4 + 3) == *(cur + 3))

-  {

-    maxLen = 4;

-    distances[(size_t)offset + 1] = d4 - 1;

-    offset += 2;

-    d2 = d4;

-  }

-  

-  if (offset != 0)

-  {

-    UPDATE_maxLen

-    distances[(size_t)offset - 2] = maxLen;

-    if (maxLen == lenLimit)

-    {

-      p->son[p->cyclicBufferPos] = curMatch;

-      MOVE_POS_RET;

-    }

-  }

-  

-  if (maxLen < 4)

-    maxLen = 4;

-

-  offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),

-      distances + offset, maxLen) - (distances));

-  MOVE_POS_RET

-}

-*/

-

-UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)

-{

-  unsigned offset;

-  GET_MATCHES_HEADER(3)

-  HASH_ZIP_CALC;

-  curMatch = p->hash[hv];

-  p->hash[hv] = p->pos;

-  offset = (unsigned)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),

-      distances, 2) - (distances));

-  MOVE_POS_RET

-}

-

-static void Bt2_MatchFinder_Skip(CMatchFinder *p, UInt32 num)

-{

-  do

-  {

-    SKIP_HEADER(2)

-    HASH2_CALC;

-    curMatch = p->hash[hv];

-    p->hash[hv] = p->pos;

-    SKIP_FOOTER

-  }

-  while (--num != 0);

-}

-

-void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)

-{

-  do

-  {

-    SKIP_HEADER(3)

-    HASH_ZIP_CALC;

-    curMatch = p->hash[hv];

-    p->hash[hv] = p->pos;

-    SKIP_FOOTER

-  }

-  while (--num != 0);

-}

-

-static void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num)

-{

-  do

-  {

-    UInt32 h2;

-    UInt32 *hash;

-    SKIP_HEADER(3)

-    HASH3_CALC;

-    hash = p->hash;

-    curMatch = (hash + kFix3HashSize)[hv];

-    hash[h2] =

-    (hash + kFix3HashSize)[hv] = p->pos;

-    SKIP_FOOTER

-  }

-  while (--num != 0);

-}

-

-static void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)

-{

-  do

-  {

-    UInt32 h2, h3;

-    UInt32 *hash;

-    SKIP_HEADER(4)

-    HASH4_CALC;

-    hash = p->hash;

-    curMatch = (hash + kFix4HashSize)[hv];

-    hash                  [h2] =

-    (hash + kFix3HashSize)[h3] =

-    (hash + kFix4HashSize)[hv] = p->pos;

-    SKIP_FOOTER

-  }

-  while (--num != 0);

-}

-

-/*

-static void Bt5_MatchFinder_Skip(CMatchFinder *p, UInt32 num)

-{

-  do

-  {

-    UInt32 h2, h3, h4;

-    UInt32 *hash;

-    SKIP_HEADER(5)

-    HASH5_CALC;

-    hash = p->hash;

-    curMatch = (hash + kFix5HashSize)[hv];

-    hash                  [h2] =

-    (hash + kFix3HashSize)[h3] =

-    (hash + kFix4HashSize)[h4] =

-    (hash + kFix5HashSize)[hv] = p->pos;

-    SKIP_FOOTER

-  }

-  while (--num != 0);

-}

-*/

-

-static void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)

-{

-  do

-  {

-    UInt32 h2, h3;

-    UInt32 *hash;

-    SKIP_HEADER(4)

-    HASH4_CALC;

-    hash = p->hash;

-    curMatch = (hash + kFix4HashSize)[hv];

-    hash                  [h2] =

-    (hash + kFix3HashSize)[h3] =

-    (hash + kFix4HashSize)[hv] = p->pos;

-    p->son[p->cyclicBufferPos] = curMatch;

-    MOVE_POS

-  }

-  while (--num != 0);

-}

-

-/*

-static void Hc5_MatchFinder_Skip(CMatchFinder *p, UInt32 num)

-{

-  do

-  {

-    UInt32 h2, h3, h4;

-    UInt32 *hash;

-    SKIP_HEADER(5)

-    HASH5_CALC;

-    hash = p->hash;

-    curMatch = hash + kFix5HashSize)[hv];

-    hash                  [h2] =

-    (hash + kFix3HashSize)[h3] =

-    (hash + kFix4HashSize)[h4] =

-    (hash + kFix5HashSize)[hv] = p->pos;

-    p->son[p->cyclicBufferPos] = curMatch;

-    MOVE_POS

-  }

-  while (--num != 0);

-}

-*/

-

-void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)

-{

-  do

-  {

-    SKIP_HEADER(3)

-    HASH_ZIP_CALC;

-    curMatch = p->hash[hv];

-    p->hash[hv] = p->pos;

-    p->son[p->cyclicBufferPos] = curMatch;

-    MOVE_POS

-  }

-  while (--num != 0);

-}

-

-void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable)

-{

-  vTable->Init = (Mf_Init_Func)MatchFinder_Init;

-  vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes;

-  vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos;

-  if (!p->btMode)

-  {

-    /* if (p->numHashBytes <= 4) */

-    {

-      vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches;

-      vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip;

-    }

-    /*

-    else

-    {

-      vTable->GetMatches = (Mf_GetMatches_Func)Hc5_MatchFinder_GetMatches;

-      vTable->Skip = (Mf_Skip_Func)Hc5_MatchFinder_Skip;

-    }

-    */

-  }

-  else if (p->numHashBytes == 2)

-  {

-    vTable->GetMatches = (Mf_GetMatches_Func)Bt2_MatchFinder_GetMatches;

-    vTable->Skip = (Mf_Skip_Func)Bt2_MatchFinder_Skip;

-  }

-  else if (p->numHashBytes == 3)

-  {

-    vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches;

-    vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip;

-  }

-  else /* if (p->numHashBytes == 4) */

-  {

-    vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches;

-    vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip;

-  }

-  /*

-  else

-  {

-    vTable->GetMatches = (Mf_GetMatches_Func)Bt5_MatchFinder_GetMatches;

-    vTable->Skip = (Mf_Skip_Func)Bt5_MatchFinder_Skip;

-  }

-  */

-}

+/* LzFind.c -- Match finder for LZ algorithms
+2023-03-14 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include <string.h>
+// #include <stdio.h>
+
+#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(CMatchFinder *p) { return p->buffer; }
+
+static UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return GET_AVAIL_BYTES(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(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_ARM_OR_ARM64)
+#elif defined(MY_CPU_ARM64)
+
+  #if defined(__clang__) && (__clang_major__ >= 8) \
+    || defined(__GNUC__) && (__GNUC__ >= 8)
+      #define USE_LZFIND_SATUR_SUB_128
+    #ifdef MY_CPU_ARM64
+      // #define LZFIND_ATTRIB_SSE41 __attribute__((__target__("")))
+    #else
+      // #define LZFIND_ATTRIB_SSE41 __attribute__((__target__("fpu=crypto-neon-fp-armv8")))
+    #endif
+
+  #elif defined(_MSC_VER)
+    #if (_MSC_VER >= 1910)
+      #define USE_LZFIND_SATUR_SUB_128
+    #endif
+  #endif
+
+  #if defined(_MSC_VER) && defined(MY_CPU_ARM64)
+    #include <arm64_neon.h>
+  #else
+    #include <arm_neon.h>
+  #endif
+
+#endif
+
+
+#ifdef USE_LZFIND_SATUR_SUB_128
+
+// #define Z7_SHOW_HW_STATUS
+
+#ifdef Z7_SHOW_HW_STATUS
+#include <stdio.h>
+#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 <smmintrin.h> // 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 <immintrin.h> // avx
+/*
+clang :immintrin.h uses
+#if !(defined(_MSC_VER) || defined(__SCE__)) || __has_feature(modules) ||      \
+    defined(__AVX2__)
+#include <avx2intrin.h>
+#endif
+so we need <avxintrin.h> for clang-cl */
+
+#if defined(__clang__)
+#include <avxintrin.h>
+#include <avx2intrin.h>
+#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) \
+  unsigned lenLimit; UInt32 hv; const Byte *cur; UInt32 curMatch; \
+  lenLimit = (unsigned)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(CMatchFinder *p, UInt32 *distances)
+{
+  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(CMatchFinder *p, UInt32 *distances)
+{
+  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(CMatchFinder *p, UInt32 *distances)
+{
+  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(CMatchFinder *p, UInt32 *distances)
+{
+  UInt32 mmm;
+  UInt32 h2, h3, d2, d3, maxLen, pos;
+  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(CMatchFinder *p, UInt32 *distances)
+{
+  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(CMatchFinder *p, UInt32 *distances)
+{
+  UInt32 mmm;
+  UInt32 h2, h3, d2, d3, maxLen, pos;
+  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] = 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(CMatchFinder *p, UInt32 num)
+{
+  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(CMatchFinder *p, UInt32 num)
+{
+  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(CMatchFinder *p, UInt32 num)
+{
+  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(CMatchFinder *p, UInt32 num)
+{
+  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(CMatchFinder *p, UInt32 num)
+{
+  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(CMatchFinder *p, UInt32 num)
+{
+  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 = (Mf_Init_Func)MatchFinder_Init;
+  vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes;
+  vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos;
+  if (!p->btMode)
+  {
+    if (p->numHashBytes <= 4)
+    {
+      vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches;
+      vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip;
+    }
+    else
+    {
+      vTable->GetMatches = (Mf_GetMatches_Func)Hc5_MatchFinder_GetMatches;
+      vTable->Skip = (Mf_Skip_Func)Hc5_MatchFinder_Skip;
+    }
+  }
+  else if (p->numHashBytes == 2)
+  {
+    vTable->GetMatches = (Mf_GetMatches_Func)Bt2_MatchFinder_GetMatches;
+    vTable->Skip = (Mf_Skip_Func)Bt2_MatchFinder_Skip;
+  }
+  else if (p->numHashBytes == 3)
+  {
+    vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches;
+    vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip;
+  }
+  else if (p->numHashBytes == 4)
+  {
+    vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches;
+    vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip;
+  }
+  else
+  {
+    vTable->GetMatches = (Mf_GetMatches_Func)Bt5_MatchFinder_GetMatches;
+    vTable->Skip = (Mf_Skip_Func)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 c77adde..a3f72c9 100644
--- a/C/LzFind.h
+++ b/C/LzFind.h
@@ -1,121 +1,159 @@
-/* LzFind.h -- Match finder for LZ algorithms

-2017-06-10 : Igor Pavlov : Public domain */

-

-#ifndef __LZ_FIND_H

-#define __LZ_FIND_H

-

-#include "7zTypes.h"

-

-EXTERN_C_BEGIN

-

-typedef UInt32 CLzRef;

-

-typedef struct _CMatchFinder

-{

-  Byte *buffer;

-  UInt32 pos;

-  UInt32 posLimit;

-  UInt32 streamPos;

-  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 *bufferBase;

-  ISeqInStream *stream;

-  

-  UInt32 blockSize;

-  UInt32 keepSizeBefore;

-  UInt32 keepSizeAfter;

-

-  UInt32 numHashBytes;

-  size_t directInputRem;

-  UInt32 historySize;

-  UInt32 fixedHashSize;

-  UInt32 hashSizeSum;

-  SRes result;

-  UInt32 crc[256];

-  size_t numRefs;

-

-  UInt64 expectedDataSize;

-} CMatchFinder;

-

-#define Inline_MatchFinder_GetPointerToCurrentPos(p) ((p)->buffer)

-

-#define Inline_MatchFinder_GetNumAvailableBytes(p) ((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);

-

-/* Conditions:

-     historySize <= 3 GB

-     keepAddBufferBefore + matchMaxLen + keepAddBufferAfter < 511MB

-*/

-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);

-void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue);

-

-UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son,

-    UInt32 _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 _IMatchFinder

-{

-  Mf_Init_Func Init;

-  Mf_GetNumAvailableBytes_Func GetNumAvailableBytes;

-  Mf_GetPointerToCurrentPos_Func GetPointerToCurrentPos;

-  Mf_GetMatches_Func GetMatches;

-  Mf_Skip_Func Skip;

-} IMatchFinder;

-

-void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable);

-

-void MatchFinder_Init_LowHash(CMatchFinder *p);

-void MatchFinder_Init_HighHash(CMatchFinder *p);

-void MatchFinder_Init_3(CMatchFinder *p, int readData);

-void MatchFinder_Init(CMatchFinder *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);

-

-EXTERN_C_END

-

-#endif

+/* LzFind.h -- Match finder for LZ algorithms
+2023-03-04 : 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);
+
+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 df32146..5253e6e 100644
--- a/C/LzFindMt.c
+++ b/C/LzFindMt.c
@@ -1,853 +1,1406 @@
-/* LzFindMt.c -- multithreaded Match finder for LZ algorithms

-2018-12-29 : Igor Pavlov : Public domain */

-

-#include "Precomp.h"

-

-#include "LzHash.h"

-

-#include "LzFindMt.h"

-

-static void MtSync_Construct(CMtSync *p)

-{

-  p->wasCreated = False;

-  p->csWasInitialized = False;

-  p->csWasEntered = False;

-  Thread_Construct(&p->thread);

-  Event_Construct(&p->canStart);

-  Event_Construct(&p->wasStarted);

-  Event_Construct(&p->wasStopped);

-  Semaphore_Construct(&p->freeSemaphore);

-  Semaphore_Construct(&p->filledSemaphore);

-}

-

-static void MtSync_GetNextBlock(CMtSync *p)

-{

-  if (p->needStart)

-  {

-    p->numProcessedBlocks = 1;

-    p->needStart = False;

-    p->stopWriting = False;

-    p->exit = False;

-    Event_Reset(&p->wasStarted);

-    Event_Reset(&p->wasStopped);

-

-    Event_Set(&p->canStart);

-    Event_Wait(&p->wasStarted);

-

-    // if (mt) MatchFinder_Init_LowHash(mt->MatchFinder);

-  }

-  else

-  {

-    CriticalSection_Leave(&p->cs);

-    p->csWasEntered = False;

-    p->numProcessedBlocks++;

-    Semaphore_Release1(&p->freeSemaphore);

-  }

-  Semaphore_Wait(&p->filledSemaphore);

-  CriticalSection_Enter(&p->cs);

-  p->csWasEntered = True;

-}

-

-/* MtSync_StopWriting must be called if Writing was started */

-

-static void MtSync_StopWriting(CMtSync *p)

-{

-  UInt32 myNumBlocks = p->numProcessedBlocks;

-  if (!Thread_WasCreated(&p->thread) || p->needStart)

-    return;

-  p->stopWriting = True;

-  if (p->csWasEntered)

-  {

-    CriticalSection_Leave(&p->cs);

-    p->csWasEntered = False;

-  }

-  Semaphore_Release1(&p->freeSemaphore);

- 

-  Event_Wait(&p->wasStopped);

-

-  while (myNumBlocks++ != p->numProcessedBlocks)

-  {

-    Semaphore_Wait(&p->filledSemaphore);

-    Semaphore_Release1(&p->freeSemaphore);

-  }

-  p->needStart = True;

-}

-

-static void MtSync_Destruct(CMtSync *p)

-{

-  if (Thread_WasCreated(&p->thread))

-  {

-    MtSync_StopWriting(p);

-    p->exit = True;

-    if (p->needStart)

-      Event_Set(&p->canStart);

-    Thread_Wait(&p->thread);

-    Thread_Close(&p->thread);

-  }

-  if (p->csWasInitialized)

-  {

-    CriticalSection_Delete(&p->cs);

-    p->csWasInitialized = False;

-  }

-

-  Event_Close(&p->canStart);

-  Event_Close(&p->wasStarted);

-  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; }

-

-static SRes MtSync_Create2(CMtSync *p, THREAD_FUNC_TYPE startAddress, void *obj, UInt32 numBlocks)

-{

-  if (p->wasCreated)

-    return SZ_OK;

-

-  RINOK_THREAD(CriticalSection_Init(&p->cs));

-  p->csWasInitialized = True;

-

-  RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->canStart));

-  RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->wasStarted));

-  RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->wasStopped));

-  

-  RINOK_THREAD(Semaphore_Create(&p->freeSemaphore, numBlocks, numBlocks));

-  RINOK_THREAD(Semaphore_Create(&p->filledSemaphore, 0, numBlocks));

-

-  p->needStart = True;

-  

-  RINOK_THREAD(Thread_Create(&p->thread, startAddress, obj));

-  p->wasCreated = True;

-  return SZ_OK;

-}

-

-static SRes MtSync_Create(CMtSync *p, THREAD_FUNC_TYPE startAddress, void *obj, UInt32 numBlocks)

-{

-  SRes res = MtSync_Create2(p, startAddress, obj, numBlocks);

-  if (res != SZ_OK)

-    MtSync_Destruct(p);

-  return res;

-}

-

-void MtSync_Init(CMtSync *p) { p->needStart = True; }

-

-#define kMtMaxValForNormalize 0xFFFFFFFF

-

-#define DEF_GetHeads2(name, v, action) \

-  static void GetHeads ## name(const Byte *p, UInt32 pos, \

-      UInt32 *hash, UInt32 hashMask, UInt32 *heads, UInt32 numHeads, const UInt32 *crc) \

-    { action; for (; numHeads != 0; numHeads--) { \

-      const UInt32 value = (v); p++; *heads++ = pos - hash[value]; hash[value] = pos++;  } }

-

-#define DEF_GetHeads(name, v) DEF_GetHeads2(name, v, ;)

-

-DEF_GetHeads2(2,  (p[0] | ((UInt32)p[1] << 8)), UNUSED_VAR(hashMask); UNUSED_VAR(crc); )

-DEF_GetHeads(3,  (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8)) & hashMask)

-DEF_GetHeads(4,  (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ (crc[p[3]] << 5)) & hashMask)

-DEF_GetHeads(4b, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ ((UInt32)p[3] << 16)) & hashMask)

-/* DEF_GetHeads(5,  (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ (crc[p[3]] << 5) ^ (crc[p[4]] << 3)) & hashMask) */

-

-static void HashThreadFunc(CMatchFinderMt *mt)

-{

-  CMtSync *p = &mt->hashSync;

-  for (;;)

-  {

-    UInt32 numProcessedBlocks = 0;

-    Event_Wait(&p->canStart);

-    Event_Set(&p->wasStarted);

-

-    MatchFinder_Init_HighHash(mt->MatchFinder);

-

-    for (;;)

-    {

-      if (p->exit)

-        return;

-      if (p->stopWriting)

-      {

-        p->numProcessedBlocks = numProcessedBlocks;

-        Event_Set(&p->wasStopped);

-        break;

-      }

-

-      {

-        CMatchFinder *mf = mt->MatchFinder;

-        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->btSync.cs);

-          CriticalSection_Leave(&mt->hashSync.cs);

-          continue;

-        }

-

-        Semaphore_Wait(&p->freeSemaphore);

-

-        MatchFinder_ReadIfRequired(mf);

-        if (mf->pos > (kMtMaxValForNormalize - kMtHashBlockSize))

-        {

-          UInt32 subValue = (mf->pos - mf->historySize - 1);

-          MatchFinder_ReduceOffsets(mf, subValue);

-          MatchFinder_Normalize3(subValue, mf->hash + mf->fixedHashSize, (size_t)mf->hashMask + 1);

-        }

-        {

-          UInt32 *heads = mt->hashBuf + ((numProcessedBlocks++) & kMtHashNumBlocksMask) * kMtHashBlockSize;

-          UInt32 num = mf->streamPos - mf->pos;

-          heads[0] = 2;

-          heads[1] = num;

-          if (num >= mf->numHashBytes)

-          {

-            num = num - mf->numHashBytes + 1;

-            if (num > kMtHashBlockSize - 2)

-              num = kMtHashBlockSize - 2;

-            mt->GetHeadsFunc(mf->buffer, mf->pos, mf->hash + mf->fixedHashSize, mf->hashMask, heads + 2, num, mf->crc);

-            heads[0] = 2 + num;

-          }

-          mf->pos += num;

-          mf->buffer += num;

-        }

-      }

-

-      Semaphore_Release1(&p->filledSemaphore);

-    }

-  }

-}

-

-static void MatchFinderMt_GetNextBlock_Hash(CMatchFinderMt *p)

-{

-  MtSync_GetNextBlock(&p->hashSync);

-  p->hashBufPosLimit = p->hashBufPos = ((p->hashSync.numProcessedBlocks - 1) & kMtHashNumBlocksMask) * kMtHashBlockSize;

-  p->hashBufPosLimit += p->hashBuf[p->hashBufPos++];

-  p->hashNumAvail = p->hashBuf[p->hashBufPos++];

-}

-

-#define kEmptyHashValue 0

-

-#define MFMT_GM_INLINE

-

-#ifdef MFMT_GM_INLINE

-

-/*

-  we use size_t for _cyclicBufferPos instead of UInt32

-  to eliminate "movsx" BUG in old MSVC x64 compiler.

-*/

-

-MY_NO_INLINE

-static UInt32 *GetMatchesSpecN(UInt32 lenLimit, UInt32 pos, const Byte *cur, CLzRef *son,

-    size_t _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue,

-    UInt32 *distances, UInt32 _maxLen, const UInt32 *hash, const UInt32 *limit, UInt32 size, UInt32 *posRes)

-{

-  do

-  {

-  UInt32 *_distances = ++distances;

-  UInt32 delta = *hash++;

-

-  CLzRef *ptr0 = son + ((size_t)_cyclicBufferPos << 1) + 1;

-  CLzRef *ptr1 = son + ((size_t)_cyclicBufferPos << 1);

-  unsigned len0 = 0, len1 = 0;

-  UInt32 cutValue = _cutValue;

-  unsigned maxLen = (unsigned)_maxLen;

-

-  /*

-  if (size > 1)

-  {

-    UInt32 delta = *hash;

-    if (delta < _cyclicBufferSize)

-    {

-      UInt32 cyc1 = _cyclicBufferPos + 1;

-      CLzRef *pair = son + ((size_t)(cyc1 - delta + ((delta > cyc1) ? _cyclicBufferSize : 0)) << 1);

-      Byte b = *(cur + 1 - delta);

-      _distances[0] = pair[0];

-      _distances[1] = b;

-    }

-  }

-  */

-  if (cutValue == 0 || delta >= _cyclicBufferSize)

-  {

-    *ptr0 = *ptr1 = kEmptyHashValue;

-  }

-  else

-  for(;;)

-  {

-    {

-      CLzRef *pair = son + ((size_t)(_cyclicBufferPos - delta + ((_cyclicBufferPos < delta) ? _cyclicBufferSize : 0)) << 1);

-      const Byte *pb = cur - delta;

-      unsigned len = (len0 < len1 ? len0 : len1);

-      UInt32 pair0 = *pair;

-      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;

-          *distances++ = (UInt32)len;

-          *distances++ = delta - 1;

-          if (len == lenLimit)

-          {

-            UInt32 pair1 = pair[1];

-            *ptr1 = pair0;

-            *ptr0 = pair1;

-            break;

-          }

-        }

-      }

-      {

-        UInt32 curMatch = pos - delta;

-        // delta = pos - *pair;

-        // delta = pos - pair[((UInt32)pb[len] - (UInt32)cur[len]) >> 31];

-        if (pb[len] < cur[len])

-        {

-          delta = pos - pair[1];

-          *ptr1 = curMatch;

-          ptr1 = pair + 1;

-          len1 = len;

-        }

-        else

-        {

-          delta = pos - *pair;

-          *ptr0 = curMatch;

-          ptr0 = pair;

-          len0 = len;

-        }

-      }

-    }

-    if (--cutValue == 0 || delta >= _cyclicBufferSize)

-    {

-      *ptr0 = *ptr1 = kEmptyHashValue;

-      break;

-    }

-  }

-  pos++;

-  _cyclicBufferPos++;

-  cur++;

-  {

-    UInt32 num = (UInt32)(distances - _distances);

-    _distances[-1] = num;

-  }

-  }

-  while (distances < limit && --size != 0);

-  *posRes = pos;

-  return distances;

-}

-

-#endif

-

-

-

-static void BtGetMatches(CMatchFinderMt *p, UInt32 *distances)

-{

-  UInt32 numProcessed = 0;

-  UInt32 curPos = 2;

-  UInt32 limit = kMtBtBlockSize - (p->matchMaxLen * 2); //  * 2

-  

-  distances[1] = p->hashNumAvail;

-  

-  while (curPos < limit)

-  {

-    if (p->hashBufPos == p->hashBufPosLimit)

-    {

-      MatchFinderMt_GetNextBlock_Hash(p);

-      distances[1] = numProcessed + p->hashNumAvail;

-      if (p->hashNumAvail >= p->numHashBytes)

-        continue;

-      distances[0] = curPos + p->hashNumAvail;

-      distances += curPos;

-      for (; p->hashNumAvail != 0; p->hashNumAvail--)

-        *distances++ = 0;

-      return;

-    }

-    {

-      UInt32 size = p->hashBufPosLimit - p->hashBufPos;

-      UInt32 lenLimit = p->matchMaxLen;

-      UInt32 pos = p->pos;

-      UInt32 cyclicBufferPos = p->cyclicBufferPos;

-      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;

-      }

-      

-      #ifndef MFMT_GM_INLINE

-      while (curPos < limit && size-- != 0)

-      {

-        UInt32 *startDistances = distances + 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;

-        curPos = (UInt32)(GetMatchesSpecN(lenLimit, pos, p->buffer, p->son, cyclicBufferPos, p->cyclicBufferSize, p->cutValue,

-            distances + curPos, p->numHashBytes - 1, p->hashBuf + p->hashBufPos,

-            distances + limit,

-            size, &posRes) - distances);

-        p->hashBufPos += posRes - pos;

-        cyclicBufferPos += posRes - pos;

-        p->buffer += posRes - pos;

-        pos = posRes;

-      }

-      #endif

-

-      numProcessed += pos - p->pos;

-      p->hashNumAvail -= pos - p->pos;

-      p->pos = pos;

-      if (cyclicBufferPos == p->cyclicBufferSize)

-        cyclicBufferPos = 0;

-      p->cyclicBufferPos = cyclicBufferPos;

-    }

-  }

-  

-  distances[0] = curPos;

-}

-

-static void BtFillBlock(CMatchFinderMt *p, UInt32 globalBlockIndex)

-{

-  CMtSync *sync = &p->hashSync;

-  if (!sync->needStart)

-  {

-    CriticalSection_Enter(&sync->cs);

-    sync->csWasEntered = True;

-  }

-  

-  BtGetMatches(p, p->btBuf + (globalBlockIndex & kMtBtNumBlocksMask) * kMtBtBlockSize);

-

-  if (p->pos > kMtMaxValForNormalize - kMtBtBlockSize)

-  {

-    UInt32 subValue = p->pos - p->cyclicBufferSize;

-    MatchFinder_Normalize3(subValue, p->son, (size_t)p->cyclicBufferSize * 2);

-    p->pos -= subValue;

-  }

-

-  if (!sync->needStart)

-  {

-    CriticalSection_Leave(&sync->cs);

-    sync->csWasEntered = False;

-  }

-}

-

-void BtThreadFunc(CMatchFinderMt *mt)

-{

-  CMtSync *p = &mt->btSync;

-  for (;;)

-  {

-    UInt32 blockIndex = 0;

-    Event_Wait(&p->canStart);

-    Event_Set(&p->wasStarted);

-    for (;;)

-    {

-      if (p->exit)

-        return;

-      if (p->stopWriting)

-      {

-        p->numProcessedBlocks = blockIndex;

-        MtSync_StopWriting(&mt->hashSync);

-        Event_Set(&p->wasStopped);

-        break;

-      }

-      Semaphore_Wait(&p->freeSemaphore);

-      BtFillBlock(mt, blockIndex++);

-      Semaphore_Release1(&p->filledSemaphore);

-    }

-  }

-}

-

-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)

-{

-  MtSync_Destruct(&p->hashSync);

-  MtSync_Destruct(&p->btSync);

-  MatchFinderMt_FreeMem(p, alloc);

-}

-

-#define kHashBufferSize (kMtHashBlockSize * kMtHashNumBlocks)

-#define kBtBufferSize (kMtBtBlockSize * kMtBtNumBlocks)

-

-static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE HashThreadFunc2(void *p) { HashThreadFunc((CMatchFinderMt *)p);  return 0; }

-static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE 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 = p->MatchFinder;

-  p->historySize = historySize;

-  if (kMtBtBlockSize <= matchMaxLen * 4)

-    return SZ_ERROR_PARAM;

-  if (!p->hashBuf)

-  {

-    p->hashBuf = (UInt32 *)ISzAlloc_Alloc(alloc, (kHashBufferSize + 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, kMtHashNumBlocks));

-  RINOK(MtSync_Create(&p->btSync, BtThreadFunc2, p, kMtBtNumBlocks));

-  return SZ_OK;

-}

-

-/* Call it after ReleaseStream / SetStream */

-static void MatchFinderMt_Init(CMatchFinderMt *p)

-{

-  CMatchFinder *mf = p->MatchFinder;

-  

-  p->btBufPos =

-  p->btBufPosLimit = 0;

-  p->hashBufPos =

-  p->hashBufPosLimit = 0;

-

-  /* Init without data reading. We don't want to read data in this thread */

-  MatchFinder_Init_3(mf, False);

-  MatchFinder_Init_LowHash(mf);

-  

-  p->pointerToCurPos = Inline_MatchFinder_GetPointerToCurrentPos(mf);

-  p->btNumAvailBytes = 0;

-  p->lzPos = p->historySize + 1;

-

-  p->hash = mf->hash;

-  p->fixedHashSize = mf->fixedHashSize;

-  p->crc = mf->crc;

-

-  p->son = mf->son;

-  p->matchMaxLen = mf->matchMaxLen;

-  p->numHashBytes = mf->numHashBytes;

-  p->pos = mf->pos;

-  p->buffer = mf->buffer;

-  p->cyclicBufferPos = mf->cyclicBufferPos;

-  p->cyclicBufferSize = mf->cyclicBufferSize;

-  p->cutValue = mf->cutValue;

-}

-

-/* ReleaseStream is required to finish multithreading */

-void MatchFinderMt_ReleaseStream(CMatchFinderMt *p)

-{

-  MtSync_StopWriting(&p->btSync);

-  /* p->MatchFinder->ReleaseStream(); */

-}

-

-static void MatchFinderMt_Normalize(CMatchFinderMt *p)

-{

-  MatchFinder_Normalize3(p->lzPos - p->historySize - 1, p->hash, p->fixedHashSize);

-  p->lzPos = p->historySize + 1;

-}

-

-static void MatchFinderMt_GetNextBlock_Bt(CMatchFinderMt *p)

-{

-  UInt32 blockIndex;

-  MtSync_GetNextBlock(&p->btSync);

-  blockIndex = ((p->btSync.numProcessedBlocks - 1) & kMtBtNumBlocksMask);

-  p->btBufPosLimit = p->btBufPos = blockIndex * kMtBtBlockSize;

-  p->btBufPosLimit += p->btBuf[p->btBufPos++];

-  p->btNumAvailBytes = p->btBuf[p->btBufPos++];

-  if (p->lzPos >= kMtMaxValForNormalize - kMtBtBlockSize)

-    MatchFinderMt_Normalize(p);

-}

-

-static const Byte * MatchFinderMt_GetPointerToCurrentPos(CMatchFinderMt *p)

-{

-  return p->pointerToCurPos;

-}

-

-#define GET_NEXT_BLOCK_IF_REQUIRED if (p->btBufPos == p->btBufPosLimit) MatchFinderMt_GetNextBlock_Bt(p);

-

-static UInt32 MatchFinderMt_GetNumAvailableBytes(CMatchFinderMt *p)

-{

-  GET_NEXT_BLOCK_IF_REQUIRED;

-  return p->btNumAvailBytes;

-}

-

-static UInt32 * MixMatches2(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances)

-{

-  UInt32 h2, curMatch2;

-  UInt32 *hash = p->hash;

-  const Byte *cur = p->pointerToCurPos;

-  UInt32 lzPos = p->lzPos;

-  MT_HASH2_CALC

-      

-  curMatch2 = hash[h2];

-  hash[h2] = lzPos;

-

-  if (curMatch2 >= matchMinPos)

-    if (cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0])

-    {

-      *distances++ = 2;

-      *distances++ = lzPos - curMatch2 - 1;

-    }

-  

-  return distances;

-}

-

-static UInt32 * MixMatches3(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances)

-{

-  UInt32 h2, h3, curMatch2, curMatch3;

-  UInt32 *hash = p->hash;

-  const Byte *cur = p->pointerToCurPos;

-  UInt32 lzPos = p->lzPos;

-  MT_HASH3_CALC

-

-  curMatch2 = hash[                h2];

-  curMatch3 = (hash + kFix3HashSize)[h3];

-  

-  hash[                h2] = lzPos;

-  (hash + kFix3HashSize)[h3] = lzPos;

-

-  if (curMatch2 >= matchMinPos && cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0])

-  {

-    distances[1] = lzPos - curMatch2 - 1;

-    if (cur[(ptrdiff_t)curMatch2 - lzPos + 2] == cur[2])

-    {

-      distances[0] = 3;

-      return distances + 2;

-    }

-    distances[0] = 2;

-    distances += 2;

-  }

-  

-  if (curMatch3 >= matchMinPos && cur[(ptrdiff_t)curMatch3 - lzPos] == cur[0])

-  {

-    *distances++ = 3;

-    *distances++ = lzPos - curMatch3 - 1;

-  }

-  

-  return distances;

-}

-

-/*

-static UInt32 *MixMatches4(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances)

-{

-  UInt32 h2, h3, h4, curMatch2, curMatch3, curMatch4;

-  UInt32 *hash = p->hash;

-  const Byte *cur = p->pointerToCurPos;

-  UInt32 lzPos = p->lzPos;

-  MT_HASH4_CALC

-      

-  curMatch2 = hash[                h2];

-  curMatch3 = (hash + kFix3HashSize)[h3];

-  curMatch4 = (hash + kFix4HashSize)[h4];

-  

-  hash[                h2] = lzPos;

-  (hash + kFix3HashSize)[h3] = lzPos;

-  (hash + kFix4HashSize)[h4] = lzPos;

-

-  if (curMatch2 >= matchMinPos && cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0])

-  {

-    distances[1] = lzPos - curMatch2 - 1;

-    if (cur[(ptrdiff_t)curMatch2 - lzPos + 2] == cur[2])

-    {

-      distances[0] = (cur[(ptrdiff_t)curMatch2 - lzPos + 3] == cur[3]) ? 4 : 3;

-      return distances + 2;

-    }

-    distances[0] = 2;

-    distances += 2;

-  }

-  

-  if (curMatch3 >= matchMinPos && cur[(ptrdiff_t)curMatch3 - lzPos] == cur[0])

-  {

-    distances[1] = lzPos - curMatch3 - 1;

-    if (cur[(ptrdiff_t)curMatch3 - lzPos + 3] == cur[3])

-    {

-      distances[0] = 4;

-      return distances + 2;

-    }

-    distances[0] = 3;

-    distances += 2;

-  }

-

-  if (curMatch4 >= matchMinPos)

-    if (

-      cur[(ptrdiff_t)curMatch4 - lzPos] == cur[0] &&

-      cur[(ptrdiff_t)curMatch4 - lzPos + 3] == cur[3]

-      )

-    {

-      *distances++ = 4;

-      *distances++ = lzPos - curMatch4 - 1;

-    }

-  

-  return distances;

-}

-*/

-

-#define INCREASE_LZ_POS p->lzPos++; p->pointerToCurPos++;

-

-static UInt32 MatchFinderMt2_GetMatches(CMatchFinderMt *p, UInt32 *distances)

-{

-  const UInt32 *btBuf = p->btBuf + p->btBufPos;

-  UInt32 len = *btBuf++;

-  p->btBufPos += 1 + len;

-  p->btNumAvailBytes--;

-  {

-    UInt32 i;

-    for (i = 0; i < len; i += 2)

-    {

-      UInt32 v0 = btBuf[0];

-      UInt32 v1 = btBuf[1];

-      btBuf += 2;

-      distances[0] = v0;

-      distances[1] = v1;

-      distances += 2;

-    }

-  }

-  INCREASE_LZ_POS

-  return len;

-}

-

-static UInt32 MatchFinderMt_GetMatches(CMatchFinderMt *p, UInt32 *distances)

-{

-  const UInt32 *btBuf = p->btBuf + p->btBufPos;

-  UInt32 len = *btBuf++;

-  p->btBufPos += 1 + len;

-

-  if (len == 0)

-  {

-    /* change for bt5 ! */

-    if (p->btNumAvailBytes-- >= 4)

-      len = (UInt32)(p->MixMatchesFunc(p, p->lzPos - p->historySize, distances) - (distances));

-  }

-  else

-  {

-    /* Condition: there are matches in btBuf with length < p->numHashBytes */

-    UInt32 *distances2;

-    p->btNumAvailBytes--;

-    distances2 = p->MixMatchesFunc(p, p->lzPos - btBuf[1], distances);

-    do

-    {

-      UInt32 v0 = btBuf[0];

-      UInt32 v1 = btBuf[1];

-      btBuf += 2;

-      distances2[0] = v0;

-      distances2[1] = v1;

-      distances2 += 2;

-    }

-    while ((len -= 2) != 0);

-    len = (UInt32)(distances2 - (distances));

-  }

-  INCREASE_LZ_POS

-  return len;

-}

-

-#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 += p->btBuf[p->btBufPos] + 1; } while (--num != 0);

-

-static void MatchFinderMt0_Skip(CMatchFinderMt *p, UInt32 num)

-{

-  SKIP_HEADER2_MT { p->btNumAvailBytes--;

-  SKIP_FOOTER_MT

-}

-

-static void MatchFinderMt2_Skip(CMatchFinderMt *p, UInt32 num)

-{

-  SKIP_HEADER_MT(2)

-      UInt32 h2;

-      MT_HASH2_CALC

-      hash[h2] = p->lzPos;

-  SKIP_FOOTER_MT

-}

-

-static void MatchFinderMt3_Skip(CMatchFinderMt *p, UInt32 num)

-{

-  SKIP_HEADER_MT(3)

-      UInt32 h2, h3;

-      MT_HASH3_CALC

-      (hash + kFix3HashSize)[h3] =

-      hash[                h2] =

-        p->lzPos;

-  SKIP_FOOTER_MT

-}

-

-/*

-static void MatchFinderMt4_Skip(CMatchFinderMt *p, UInt32 num)

-{

-  SKIP_HEADER_MT(4)

-      UInt32 h2, h3, h4;

-      MT_HASH4_CALC

-      (hash + kFix4HashSize)[h4] =

-      (hash + kFix3HashSize)[h3] =

-      hash[                h2] =

-        p->lzPos;

-  SKIP_FOOTER_MT

-}

-*/

-

-void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder *vTable)

-{

-  vTable->Init = (Mf_Init_Func)MatchFinderMt_Init;

-  vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinderMt_GetNumAvailableBytes;

-  vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinderMt_GetPointerToCurrentPos;

-  vTable->GetMatches = (Mf_GetMatches_Func)MatchFinderMt_GetMatches;

-  

-  switch (p->MatchFinder->numHashBytes)

-  {

-    case 2:

-      p->GetHeadsFunc = GetHeads2;

-      p->MixMatchesFunc = (Mf_Mix_Matches)NULL;

-      vTable->Skip = (Mf_Skip_Func)MatchFinderMt0_Skip;

-      vTable->GetMatches = (Mf_GetMatches_Func)MatchFinderMt2_GetMatches;

-      break;

-    case 3:

-      p->GetHeadsFunc = GetHeads3;

-      p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches2;

-      vTable->Skip = (Mf_Skip_Func)MatchFinderMt2_Skip;

-      break;

-    default:

-    /* case 4: */

-      p->GetHeadsFunc = p->MatchFinder->bigHash ? GetHeads4b : GetHeads4;

-      p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches3;

-      vTable->Skip = (Mf_Skip_Func)MatchFinderMt3_Skip;

-      break;

-    /*

-    default:

-      p->GetHeadsFunc = GetHeads5;

-      p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches4;

-      vTable->Skip = (Mf_Skip_Func)MatchFinderMt4_Skip;

-      break;

-    */

-  }

-}

+/* LzFindMt.c -- multithreaded Match finder for LZ algorithms
+2023-04-02 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+// #include <stdio.h>
+
+#include "CpuArch.h"
+
+#include "LzHash.h"
+#include "LzFindMt.h"
+
+// #define LOG_ITERS
+
+// #define LOG_THREAD
+
+#ifdef LOG_THREAD
+#include <stdio.h>
+#define PRF(x) x
+#else
+#define PRF(x)
+#endif
+
+#ifdef LOG_ITERS
+#include <stdio.h>
+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 <stdlib.h>
+#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(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(CMatchFinderMt *p)
+{
+  return p->pointerToCurPos;
+}
+
+
+#define GET_NEXT_BLOCK_IF_REQUIRED if (p->btBufPos == p->btBufPosLimit) MatchFinderMt_GetNextBlock_Bt(p);
+
+
+static UInt32 MatchFinderMt_GetNumAvailableBytes(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(CMatchFinderMt *p, UInt32 *d)
+{
+  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(CMatchFinderMt *p, UInt32 *d)
+{
+  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(CMatchFinderMt *p, UInt32 num)
+{
+  SKIP_HEADER2_MT { p->btNumAvailBytes--;
+  SKIP_FOOTER_MT
+}
+
+static void MatchFinderMt2_Skip(CMatchFinderMt *p, UInt32 num)
+{
+  SKIP_HEADER_MT(2)
+      UInt32 h2;
+      MT_HASH2_CALC
+      hash[h2] = p->lzPos;
+  SKIP_FOOTER_MT
+}
+
+static void MatchFinderMt3_Skip(CMatchFinderMt *p, UInt32 num)
+{
+  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 = (Mf_Init_Func)MatchFinderMt_Init;
+  vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinderMt_GetNumAvailableBytes;
+  vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinderMt_GetPointerToCurrentPos;
+  vTable->GetMatches = (Mf_GetMatches_Func)MatchFinderMt_GetMatches;
+  
+  switch (MF(p)->numHashBytes)
+  {
+    case 2:
+      p->GetHeadsFunc = GetHeads2;
+      p->MixMatchesFunc = (Mf_Mix_Matches)NULL;
+      vTable->Skip = (Mf_Skip_Func)MatchFinderMt0_Skip;
+      vTable->GetMatches = (Mf_GetMatches_Func)MatchFinderMt2_GetMatches;
+      break;
+    case 3:
+      p->GetHeadsFunc = MF(p)->bigHash ? GetHeads3b : GetHeads3;
+      p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches2;
+      vTable->Skip = (Mf_Skip_Func)MatchFinderMt2_Skip;
+      break;
+    case 4:
+      p->GetHeadsFunc = MF(p)->bigHash ? GetHeads4b : GetHeads4;
+
+      // it's fast inline version of GetMatches()
+      // vTable->GetMatches = (Mf_GetMatches_Func)MatchFinderMt_GetMatches_Bt4;
+
+      p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches3;
+      vTable->Skip = (Mf_Skip_Func)MatchFinderMt3_Skip;
+      break;
+    default:
+      p->GetHeadsFunc = MF(p)->bigHash ? GetHeads5b : GetHeads5;
+      p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches4;
+      vTable->Skip =
+          (Mf_Skip_Func)MatchFinderMt3_Skip;
+          // (Mf_Skip_Func)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 fdd1700..db5923e 100644
--- a/C/LzFindMt.h
+++ b/C/LzFindMt.h
@@ -1,101 +1,109 @@
-/* LzFindMt.h -- multithreaded Match finder for LZ algorithms

-2018-07-04 : Igor Pavlov : Public domain */

-

-#ifndef __LZ_FIND_MT_H

-#define __LZ_FIND_MT_H

-

-#include "LzFind.h"

-#include "Threads.h"

-

-EXTERN_C_BEGIN

-

-#define kMtHashBlockSize (1 << 13)

-#define kMtHashNumBlocks (1 << 3)

-#define kMtHashNumBlocksMask (kMtHashNumBlocks - 1)

-

-#define kMtBtBlockSize (1 << 14)

-#define kMtBtNumBlocks (1 << 6)

-#define kMtBtNumBlocksMask (kMtBtNumBlocks - 1)

-

-typedef struct _CMtSync

-{

-  BoolInt wasCreated;

-  BoolInt needStart;

-  BoolInt exit;

-  BoolInt stopWriting;

-

-  CThread thread;

-  CAutoResetEvent canStart;

-  CAutoResetEvent wasStarted;

-  CAutoResetEvent wasStopped;

-  CSemaphore freeSemaphore;

-  CSemaphore filledSemaphore;

-  BoolInt csWasInitialized;

-  BoolInt csWasEntered;

-  CCriticalSection cs;

-  UInt32 numProcessedBlocks;

-} CMtSync;

-

-typedef UInt32 * (*Mf_Mix_Matches)(void *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;

-  UInt32 btBufPos;

-  UInt32 btBufPosLimit;

-  UInt32 lzPos;

-  UInt32 btNumAvailBytes;

-

-  UInt32 *hash;

-  UInt32 fixedHashSize;

-  UInt32 historySize;

-  const UInt32 *crc;

-

-  Mf_Mix_Matches MixMatchesFunc;

-  

-  /* LZ + BT */

-  CMtSync btSync;

-  Byte btDummy[kMtCacheLineDummy];

-

-  /* BT */

-  UInt32 *hashBuf;

-  UInt32 hashBufPos;

-  UInt32 hashBufPosLimit;

-  UInt32 hashNumAvail;

-

-  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;

-} CMatchFinderMt;

-

-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, IMatchFinder *vTable);

-void MatchFinderMt_ReleaseStream(CMatchFinderMt *p);

-

-EXTERN_C_END

-

-#endif

+/* LzFindMt.h -- multithreaded Match finder for LZ algorithms
+2023-03-05 : 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;
+
+typedef UInt32 * (*Mf_Mix_Matches)(void *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
+{
+  /* 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
new file mode 100644
index 0000000..85bdc13
--- /dev/null
+++ b/C/LzFindOpt.c
@@ -0,0 +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 <stdio.h>
+#define PRF(x) x
+#else
+// #define PRF(x)
+#endif
+
+#ifdef LOG_ITERS
+#include <stdio.h>
+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 2191444..2b6290b 100644
--- a/C/LzHash.h
+++ b/C/LzHash.h
@@ -1,57 +1,34 @@
-/* LzHash.h -- HASH functions for LZ algorithms

-2015-04-12 : Igor Pavlov : Public domain */

-

-#ifndef __LZ_HASH_H

-#define __LZ_HASH_H

-

-#define kHash2Size (1 << 10)

-#define kHash3Size (1 << 16)

-#define kHash4Size (1 << 20)

-

-#define kFix3HashSize (kHash2Size)

-#define kFix4HashSize (kHash2Size + kHash3Size)

-#define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size)

-

-#define HASH2_CALC hv = cur[0] | ((UInt32)cur[1] << 8);

-

-#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]] << 5)) & 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]] << 5); \

-  h4 = temp & (kHash4Size - 1); \

-  hv = (temp ^ (p->crc[cur[4]] << 3)) & p->hashMask; }

-

-/* #define HASH_ZIP_CALC hv = ((cur[0] | ((UInt32)cur[1] << 8)) ^ p->crc[cur[2]]) & 0xFFFF; */

-#define HASH_ZIP_CALC hv = ((cur[2] | ((UInt32)cur[0] << 8)) ^ p->crc[cur[1]]) & 0xFFFF;

-

-

-#define MT_HASH2_CALC \

-  h2 = (p->crc[cur[0]] ^ cur[1]) & (kHash2Size - 1);

-

-#define MT_HASH3_CALC { \

-  UInt32 temp = p->crc[cur[0]] ^ cur[1]; \

-  h2 = temp & (kHash2Size - 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]] << 5)) & (kHash4Size - 1); }

-

-#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 2e63105..388cbc7 100644
--- a/C/Lzma2Dec.c
+++ b/C/Lzma2Dec.c
@@ -1,488 +1,491 @@
-/* Lzma2Dec.c -- LZMA2 Decoder

-2019-02-02 : Igor Pavlov : Public domain */

-

-/* #define SHOW_DEBUG_INFO */

-

-#include "Precomp.h"

-

-#ifdef SHOW_DEBUG_INFO

-#include <stdio.h>

-#endif

-

-#include <string.h>

-

-#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);

-}

-

-static ELzma2State 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;

-    }

-  }

-  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;

-}

+/* Lzma2Dec.c -- LZMA2 Decoder
+2023-03-03 : Igor Pavlov : Public domain */
+
+/* #define SHOW_DEBUG_INFO */
+
+#include "Precomp.h"
+
+#ifdef SHOW_DEBUG_INFO
+#include <stdio.h>
+#endif
+
+#include <string.h>
+
+#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;
+    }
+  }
+  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 da50387..1f5233a 100644
--- a/C/Lzma2Dec.h
+++ b/C/Lzma2Dec.h
@@ -1,120 +1,121 @@
-/* Lzma2Dec.h -- LZMA2 Decoder

-2018-02-19 : Igor Pavlov : Public domain */

-

-#ifndef __LZMA2_DEC_H

-#define __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_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 87d5567..4bc4dde 100644
--- a/C/Lzma2DecMt.c
+++ b/C/Lzma2DecMt.c
@@ -1,1082 +1,1095 @@
-/* Lzma2DecMt.c -- LZMA2 Decoder Multi-thread

-2019-02-02 : Igor Pavlov : Public domain */

-

-#include "Precomp.h"

-

-// #define SHOW_DEBUG_INFO

-

-#ifdef SHOW_DEBUG_INFO

-#include <stdio.h>

-#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))

-#define PRF_STR_INT_2(s, d1, d2) PRF(printf("\n" s " %d %d\n", (unsigned)d1, (unsigned)d2))

-

-// #define _7ZIP_ST

-

-#include "Alloc.h"

-

-#include "Lzma2Dec.h"

-#include "Lzma2DecMt.h"

-

-#ifndef _7ZIP_ST

-#include "MtDec.h"

-#endif

-

-

-#define LZMA2DECMT_OUT_BLOCK_MAX_DEFAULT (1 << 28)

-

-void Lzma2DecMtProps_Init(CLzma2DecMtProps *p)

-{

-  p->inBufSize_ST = 1 << 20;

-  p->outStep_ST = 1 << 20;

-

-  #ifndef _7ZIP_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 _7ZIP_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 ---------- */

-

-typedef struct

-{

-  // ISzAllocPtr alloc;

-  ISzAllocPtr allocMid;

-

-  CAlignOffsetAlloc alignOffsetAlloc;

-  CLzma2DecMtProps props;

-  Byte prop;

-  

-  ISeqInStream *inStream;

-  ISeqOutStream *outStream;

-  ICompressProgress *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 _7ZIP_ST

-  UInt64 outProcessed_Parse;

-  BoolInt mtc_WasConstructed;

-  CMtDec mtc;

-  CLzma2DecMtThread coders[MTDEC__THREADS_MAX];

-  #endif

-

-} CLzma2DecMt;

-

-

-

-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 _7ZIP_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 p;

-}

-

-

-#ifndef _7ZIP_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;

-}

-

-

-void Lzma2DecMt_Destroy(CLzma2DecMtHandle pp)

-{

-  CLzma2DecMt *p = (CLzma2DecMt *)pp;

-

-  Lzma2DecMt_FreeSt(p);

-

-  #ifndef _7ZIP_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, pp);

-}

-

-

-

-#ifndef _7ZIP_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 * ((1 << 11) + (1 << 8) + (1 << 6))) & ((1 << kNumAlignBits) - (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 SizeT srcOrig = cc->srcSize;

-      SizeT srcSize_Point = 0;

-      SizeT dicPos_Point = 0;

-      

-      cc->srcSize = 0;

-      overflow = False;

-

-      for (;;)

-      {

-        SizeT srcCur = srcOrig - cc->srcSize;

-        

-        status = Lzma2Dec_Parse(&t->dec,

-            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 = 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 */

-              SizeT 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 = 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;

-    size_t srcProcessed = srcSize;

-    BoolInt blockWasFinished =

-        ((int)t->parseStatus == LZMA_STATUS_FINISHED_WITH_MARK

-        || t->parseStatus == LZMA2_PARSE_STATUS_NEW_BLOCK);

-    

-    SRes res = Lzma2Dec_DecodeToDic(&t->dec,

-        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 *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;

-

-  PRF_STR_INT_2("Write", coderIndex, srcSize);

-

-  *needContinue = False;

-  *canRecode = True;

-  UNUSED_VAR(src)

-  UNUSED_VAR(srcSize)

-

-  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 _7ZIP_ST

-    , BoolInt tMode

-    #endif

-    )

-{

-  SizeT wrPos;

-  size_t inPos, inLim;

-  const Byte *inData;

-  UInt64 inPrev, outPrev;

-

-  CLzma2Dec *dec;

-

-  #ifndef _7ZIP_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 _7ZIP_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 *)inData, &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 + 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 = 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 pp,

-    Byte prop,

-    const CLzma2DecMtProps *props,

-    ISeqOutStream *outStream, const UInt64 *outDataSize, int finishMode,

-    // Byte *outBuf, size_t *outBufSize,

-    ISeqInStream *inStream,

-    // const Byte *inData, size_t inDataSize,

-    UInt64 *inProcessed,

-    // UInt64 *outProcessed,

-    int *isMT,

-    ICompressProgress *progress)

-{

-  CLzma2DecMt *p = (CLzma2DecMt *)pp;

-  #ifndef _7ZIP_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;

-

-  *isMT = False;

-

-  

-  #ifndef _7ZIP_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)

-  {

-    IMtDecCallback 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 _7ZIP_ST

-        , tMode

-        #endif

-        );

-

-    *inProcessed = p->inProcessed;

-

-    // res = SZ_OK; // for test

-    if (res == SZ_OK && p->readRes != SZ_OK)

-      res = p->readRes;

-    

-    /*

-    #ifndef _7ZIP_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 pp,

-    Byte prop,

-    const CLzma2DecMtProps *props,

-    const UInt64 *outDataSize, int finishMode,

-    ISeqInStream *inStream)

-{

-  CLzma2DecMt *p = (CLzma2DecMt *)pp;

-

-  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 pp,

-    Byte *data, size_t *outSize,

-    UInt64 *inStreamProcessed)

-{

-  CLzma2DecMt *p = (CLzma2DecMt *)pp;

-  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 = p->inLim - p->inPos;

-    outCur = 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;

-  }

-}

+/* 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 <stdio.h>
+#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 96f89a3..93a5cd5 100644
--- a/C/Lzma2DecMt.h
+++ b/C/Lzma2DecMt.h
@@ -1,79 +1,81 @@
-/* Lzma2DecMt.h -- LZMA2 Decoder Multi-thread

-2018-02-17 : Igor Pavlov : Public domain */

-

-#ifndef __LZMA2_DEC_MT_H

-#define __LZMA2_DEC_MT_H

-

-#include "7zTypes.h"

-

-EXTERN_C_BEGIN

-

-typedef struct

-{

-  size_t inBufSize_ST;

-  size_t outStep_ST;

-  

-  #ifndef _7ZIP_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 void * CLzma2DecMtHandle;

-

-CLzma2DecMtHandle Lzma2DecMt_Create(ISzAllocPtr alloc, ISzAllocPtr allocMid);

-void Lzma2DecMt_Destroy(CLzma2DecMtHandle p);

-

-SRes Lzma2DecMt_Decode(CLzma2DecMtHandle p,

-    Byte prop,

-    const CLzma2DecMtProps *props,

-    ISeqOutStream *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,

-    ISeqInStream *inStream,

-    // const Byte *inData, size_t inDataSize,

-    

-    // out variables:

-    UInt64 *inProcessed,

-    int *isMT,  /* out: (*isMT == 0), if single thread decoding was used */

-

-    // UInt64 *outProcessed,

-    ICompressProgress *progress);

-

-

-/* ---------- Read from CLzma2DecMtHandle Interface ---------- */

-

-SRes Lzma2DecMt_Init(CLzma2DecMtHandle pp,

-    Byte prop,

-    const CLzma2DecMtProps *props,

-    const UInt64 *outDataSize, int finishMode,

-    ISeqInStream *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 d541477..703e146 100644
--- a/C/Lzma2Enc.c
+++ b/C/Lzma2Enc.c
@@ -1,803 +1,805 @@
-/* Lzma2Enc.c -- LZMA2 Encoder

-2018-07-04 : Igor Pavlov : Public domain */

-

-#include "Precomp.h"

-

-#include <string.h>

-

-/* #define _7ZIP_ST */

-

-#include "Lzma2Enc.h"

-

-#ifndef _7ZIP_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;

-  ISeqInStream *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(const ISeqInStream *pp, void *data, size_t *size)

-{

-  CLimitedSeqInStream *p = CONTAINER_FROM_VTBL(pp, CLimitedSeqInStream, vt);

-  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)

-  {

-    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 pp, ISeqInStream *inStream, UInt32 keepWindowSize,

-    ISzAllocPtr alloc, ISzAllocPtr allocBig);

-SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen,

-    UInt32 keepWindowSize, ISzAllocPtr alloc, ISzAllocPtr allocBig);

-SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, BoolInt reInit,

-    Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize);

-const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp);

-void LzmaEnc_Finish(CLzmaEncHandle pp);

-void LzmaEnc_SaveState(CLzmaEncHandle pp);

-void LzmaEnc_RestoreState(CLzmaEncHandle pp);

-

-/*

-UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle pp);

-*/

-

-static SRes Lzma2EncInt_EncodeSubblock(CLzma2EncInt *p, Byte *outBuf,

-    size_t *packSizeRes, ISeqOutStream *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)

-    {

-      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;

-    UInt32 u = unpackSize - 1;

-    UInt32 pm = (UInt32)(packSize - 1);

-    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 = (unsigned)numBlocks;

-        if (t2r == 0)

-          t2r = 1;

-        t3 = t1 * t2r;

-      }

-    }

-  }

-  

-  p->numBlockThreads_Max = t2;

-  p->numBlockThreads_Reduced = t2r;

-  p->numTotalThreads = t3;

-}

-

-

-static SRes Progress(ICompressProgress *p, UInt64 inSize, UInt64 outSize)

-{

-  return (p && ICompressProgress_Progress(p, inSize, outSize) != SZ_OK) ? SZ_ERROR_PROGRESS : SZ_OK;

-}

-

-

-/* ---------- Lzma2 ---------- */

-

-typedef struct

-{

-  Byte propEncoded;

-  CLzma2EncProps props;

-  UInt64 expectedDataSize;

-  

-  Byte *tempBufLzma;

-

-  ISzAllocPtr alloc;

-  ISzAllocPtr allocBig;

-

-  CLzma2EncInt coders[MTCODER__THREADS_MAX];

-

-  #ifndef _7ZIP_ST

-  

-  ISeqOutStream *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

-

-} CLzma2Enc;

-

-

-

-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 _7ZIP_ST

-  p->mtCoder_WasConstructed = False;

-  {

-    unsigned i;

-    for (i = 0; i < MTCODER__BLOCKS_MAX; i++)

-      p->outBufs[i] = NULL;

-    p->outBufSize = 0;

-  }

-  #endif

-

-  return p;

-}

-

-

-#ifndef _7ZIP_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

-

-

-void Lzma2Enc_Destroy(CLzma2EncHandle pp)

-{

-  CLzma2Enc *p = (CLzma2Enc *)pp;

-  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 _7ZIP_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, pp);

-}

-

-

-SRes Lzma2Enc_SetProps(CLzma2EncHandle pp, const CLzma2EncProps *props)

-{

-  CLzma2Enc *p = (CLzma2Enc *)pp;

-  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(CLzmaEncHandle pp, UInt64 expectedDataSiize)

-{

-  CLzma2Enc *p = (CLzma2Enc *)pp;

-  p->expectedDataSize = expectedDataSiize;

-}

-

-

-Byte Lzma2Enc_WriteProperties(CLzma2EncHandle pp)

-{

-  CLzma2Enc *p = (CLzma2Enc *)pp;

-  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,

-    ISeqOutStream *outStream,

-    Byte *outBuf, size_t *outBufSize,

-    ISeqInStream *inStream,

-    const Byte *inData, size_t inDataSize,

-    int finished,

-    ICompressProgress *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;

-    size_t 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 = inDataSize - (size_t)unpackTotal;

-      if (me->props.blockSize != LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID

-          && inSizeCur > me->props.blockSize)

-        inSizeCur = (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)

-        {

-          size_t destPos = *outBufSize;

-          if (destPos >= outLim)

-            return SZ_ERROR_OUTPUT_EOF;

-          outBuf[destPos] = 0;

-          *outBufSize = destPos + 1;

-        }

-        else

-        {

-          Byte b = 0;

-          if (ISeqOutStream_Write(outStream, &b, 1) != 1)

-            return SZ_ERROR_WRITE;

-        }

-      }

-      return SZ_OK;

-    }

-  }

-}

-

-

-

-#ifndef _7ZIP_ST

-

-static SRes Lzma2Enc_MtCallback_Code(void *pp, unsigned coderIndex, unsigned outBufIndex,

-    const Byte *src, size_t srcSize, int finished)

-{

-  CLzma2Enc *me = (CLzma2Enc *)pp;

-  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 *pp, unsigned outBufIndex)

-{

-  CLzma2Enc *me = (CLzma2Enc *)pp;

-  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 pp,

-    ISeqOutStream *outStream,

-    Byte *outBuf, size_t *outBufSize,

-    ISeqInStream *inStream,

-    const Byte *inData, size_t inDataSize,

-    ICompressProgress *progress)

-{

-  CLzma2Enc *p = (CLzma2Enc *)pp;

-

-  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 _7ZIP_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 */

-

-    {

-      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 = p->props.numBlockThreads_Max;

-    p->mtCoder.expectedDataSize = p->expectedDataSize;

-    

-    {

-      SRes res = MtCoder_Code(&p->mtCoder);

-      if (!outStream)

-        *outBufSize = p->outBuf - outBuf;

-      return res;

-    }

-  }

-

-  #endif

-

-

-  return Lzma2Enc_EncodeMt1(p,

-      &p->coders[0],

-      outStream, outBuf, outBufSize,

-      inStream, inData, inDataSize,

-      True, /* finished */

-      progress);

-}

+/* Lzma2Enc.c -- LZMA2 Encoder
+2023-04-13 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include <string.h>
+
+/* #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 65f2dd1..cb25275 100644
--- a/C/Lzma2Enc.h
+++ b/C/Lzma2Enc.h
@@ -1,55 +1,57 @@
-/* Lzma2Enc.h -- LZMA2 Encoder

-2017-07-27 : Igor Pavlov : Public domain */

-

-#ifndef __LZMA2_ENC_H

-#define __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 void * 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,

-    ISeqOutStream *outStream,

-    Byte *outBuf, size_t *outBufSize,

-    ISeqInStream *inStream,

-    const Byte *inData, size_t inDataSize,

-    ICompressProgress *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 83057e5..e7707e2 100644
--- a/C/Lzma86.h
+++ b/C/Lzma86.h
@@ -1,111 +1,111 @@
-/* Lzma86.h -- LZMA + x86 (BCJ) Filter

-2013-01-18 : Igor Pavlov : Public domain */

-

-#ifndef __LZMA86_H

-#define __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 20ac5e7..f094d4c 100644
--- a/C/Lzma86Dec.c
+++ b/C/Lzma86Dec.c
@@ -1,54 +1,53 @@
-/* Lzma86Dec.c -- LZMA + x86 (BCJ) Filter Decoder

-2016-05-16 : 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;

-    x86_Convert_Init(x86State);

-    x86_Convert(dest, *destLen, 0, &x86State, 0);

-  }

-  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 8d35e6d..0cdde1c 100644
--- a/C/Lzma86Enc.c
+++ b/C/Lzma86Enc.c
@@ -1,106 +1,103 @@
-/* Lzma86Enc.c -- LZMA + x86 (BCJ) Filter Encoder

-2018-07-04 : Igor Pavlov : Public domain */

-

-#include "Precomp.h"

-

-#include <string.h>

-

-#include "Lzma86.h"

-

-#include "Alloc.h"

-#include "Bra.h"

-#include "LzmaEnc.h"

-

-#define SZE_OUT_OVERFLOW SZE_DATA_ERROR

-

-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;

-      x86_Convert_Init(x86State);

-      x86_Convert(filteredStream, srcLen, 0, &x86State, 1);

-    }

-  }

-

-  {

-    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 <string.h>
+
+#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 4d15764..69bb8bb 100644
--- a/C/LzmaDec.c
+++ b/C/LzmaDec.c
@@ -1,1185 +1,1363 @@
-/* LzmaDec.c -- LZMA Decoder

-2018-07-04 : Igor Pavlov : Public domain */

-

-#include "Precomp.h"

-

-#include <string.h>

-

-/* #include "CpuArch.h" */

-#include "LzmaDec.h"

-

-#define kNumTopBits 24

-#define kTopValue ((UInt32)1 << kNumTopBits)

-

-#define kNumBitModelTotalBits 11

-#define kBitModelTotal (1 << kNumBitModelTotalBits)

-#define kNumMoveBits 5

-

-#define RC_INIT_SIZE 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 _LZMA_SIZE_OPT */

-

-#ifdef _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; , ;)

-

-

-

-#define NORMALIZE_CHECK if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; 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)

-

-/* 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 : normal remain

-    = kMatchSpecLenStart : finished

-    = kMatchSpecLenStart + 1 : need init range coder

-    = kMatchSpecLenStart + 2 : need init range coder and state

-*/

-

-/* ---------- 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 function returns error code.

-  }

-

-Processing:

-  first LZMA symbol will be decoded in any case

-  All checks for limits are at the end of main loop,

-  It will decode new LZMA-symbols while (p->buf < bufLimit && dicPos < limit),

-  RangeCoder is still without last normalization when (p->buf < bufLimit) is being checked.

-

-Out:

-  RangeCoder is normalized

-  Result:

-    SZ_OK - OK

-    SZ_ERROR_DATA - Error

-  p->remainLen:

-    < kMatchSpecLenStart : normal remain

-    = kMatchSpecLenStart : finished

-*/

-

-

-#ifdef _LZMA_DEC_OPT

-

-int MY_FAST_CALL LZMA_DECODE_REAL(CLzmaDec *p, SizeT limit, const Byte *bufLimit);

-

-#else

-

-static

-int MY_FAST_CALL 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 _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 _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);

-        /*

-        // that case was checked before with kBadRepCode

-        if (checkDicSize == 0 && processedPos == 0)

-          return SZ_ERROR_DATA;

-        */

-        prob = probs + IsRepG0 + state;

-        IF_BIT_0(prob)

-        {

-          UPDATE_0(prob);

-          prob = probs + IsRep0Long + COMBINED_PS_STATE;

-          IF_BIT_0(prob)

-          {

-            UPDATE_0(prob);

-            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 _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))

-        {

-          p->dicPos = dicPos;

-          return SZ_ERROR_DATA;

-        }

-      }

-

-      len += kMatchMinLen;

-

-      {

-        SizeT rem;

-        unsigned curLen;

-        SizeT pos;

-        

-        if ((rem = limit - dicPos) == 0)

-        {

-          p->dicPos = dicPos;

-          return SZ_ERROR_DATA;

-        }

-        

-        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;

-  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;

-

-  return SZ_OK;

-}

-#endif

-

-static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit)

-{

-  if (p->remainLen != 0 && p->remainLen < kMatchSpecLenStart)

-  {

-    Byte *dic = p->dic;

-    SizeT dicPos = p->dicPos;

-    SizeT dicBufSize = p->dicBufSize;

-    unsigned len = (unsigned)p->remainLen;

-    SizeT rep0 = p->reps[0]; /* we use SizeT to avoid the BUG of VC14 for AMD64 */

-    SizeT rem = limit - dicPos;

-    if (rem < len)

-      len = (unsigned)(rem);

-

-    if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len)

-      p->checkDicSize = p->prop.dicSize;

-

-    p->processedPos += (UInt32)len;

-    p->remainLen -= (UInt32)len;

-    while (len != 0)

-    {

-      len--;

-      dic[dicPos] = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)];

-      dicPos++;

-    }

-    p->dicPos = dicPos;

-  }

-}

-

-

-#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

-

-static int MY_FAST_CALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte *bufLimit)

-{

-  do

-  {

-    SizeT limit2 = limit;

-    if (p->checkDicSize == 0)

-    {

-      UInt32 rem = p->prop.dicSize - p->processedPos;

-      if (limit - p->dicPos > rem)

-        limit2 = p->dicPos + rem;

-

-      if (p->processedPos == 0)

-        if (p->code >= kBadRepCode)

-          return SZ_ERROR_DATA;

-    }

-

-    RINOK(LZMA_DECODE_REAL(p, limit2, bufLimit));

-    

-    if (p->checkDicSize == 0 && p->processedPos >= p->prop.dicSize)

-      p->checkDicSize = p->prop.dicSize;

-    

-    LzmaDec_WriteRem(p, limit);

-  }

-  while (p->dicPos < limit && p->buf < bufLimit && p->remainLen < kMatchSpecLenStart);

-

-  return 0;

-}

-

-typedef enum

-{

-  DUMMY_ERROR, /* unexpected end of input stream */

-  DUMMY_LIT,

-  DUMMY_MATCH,

-  DUMMY_REP

-} ELzmaDummy;

-

-static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inSize)

-{

-  UInt32 range = p->range;

-  UInt32 code = p->code;

-  const Byte *bufLimit = buf + inSize;

-  const CLzmaProb *probs = GET_PROBS;

-  unsigned state = (unsigned)p->state;

-  ELzmaDummy res;

-

-  {

-    const CLzmaProb *prob;

-    UInt32 bound;

-    unsigned ttt;

-    unsigned posState = CALC_POS_STATE(p->processedPos, (1 << p->prop.pb) - 1);

-

-    prob = probs + IsMatch + COMBINED_PS_STATE;

-    IF_BIT_0_CHECK(prob)

-    {

-      UPDATE_0_CHECK

-

-      /* if (bufLimit - buf >= 7) return DUMMY_LIT; */

-

-      prob = probs + Literal;

-      if (p->checkDicSize != 0 || p->processedPos != 0)

-        prob += ((UInt32)LZMA_LIT_SIZE *

-            ((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) +

-            (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;

-            NORMALIZE_CHECK;

-            return DUMMY_REP;

-          }

-          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 (bufLimit - buf >= 8) return DUMMY_MATCH; */

-

-          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);

-          }

-        }

-      }

-    }

-  }

-  NORMALIZE_CHECK;

-  return res;

-}

-

-

-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);

-}

-

-

-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)

-  {

-    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]);

-    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;

-  }

-

-  LzmaDec_WriteRem(p, dicLimit);

-

-  while (p->remainLen != kMatchSpecLenStart)

-  {

-      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)

-        {

-          *status = LZMA_STATUS_NOT_FINISHED;

-          return SZ_ERROR_DATA;

-        }

-        checkEndMarkNow = 1;

-      }

-

-      if (p->tempBufSize == 0)

-      {

-        SizeT processed;

-        const Byte *bufLimit;

-        if (inSize < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow)

-        {

-          int dummyRes = LzmaDec_TryDummy(p, src, inSize);

-          if (dummyRes == DUMMY_ERROR)

-          {

-            memcpy(p->tempBuf, src, inSize);

-            p->tempBufSize = (unsigned)inSize;

-            (*srcLen) += inSize;

-            *status = LZMA_STATUS_NEEDS_MORE_INPUT;

-            return SZ_OK;

-          }

-          if (checkEndMarkNow && dummyRes != DUMMY_MATCH)

-          {

-            *status = LZMA_STATUS_NOT_FINISHED;

-            return SZ_ERROR_DATA;

-          }

-          bufLimit = src;

-        }

-        else

-          bufLimit = src + inSize - LZMA_REQUIRED_INPUT_MAX;

-        p->buf = src;

-        if (LzmaDec_DecodeReal2(p, dicLimit, bufLimit) != 0)

-          return SZ_ERROR_DATA;

-        processed = (SizeT)(p->buf - src);

-        (*srcLen) += processed;

-        src += processed;

-        inSize -= processed;

-      }

-      else

-      {

-        unsigned rem = p->tempBufSize, lookAhead = 0;

-        while (rem < LZMA_REQUIRED_INPUT_MAX && lookAhead < inSize)

-          p->tempBuf[rem++] = src[lookAhead++];

-        p->tempBufSize = rem;

-        if (rem < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow)

-        {

-          int dummyRes = LzmaDec_TryDummy(p, p->tempBuf, (SizeT)rem);

-          if (dummyRes == DUMMY_ERROR)

-          {

-            (*srcLen) += (SizeT)lookAhead;

-            *status = LZMA_STATUS_NEEDS_MORE_INPUT;

-            return SZ_OK;

-          }

-          if (checkEndMarkNow && dummyRes != DUMMY_MATCH)

-          {

-            *status = LZMA_STATUS_NOT_FINISHED;

-            return SZ_ERROR_DATA;

-          }

-        }

-        p->buf = p->tempBuf;

-        if (LzmaDec_DecodeReal2(p, dicLimit, p->buf) != 0)

-          return SZ_ERROR_DATA;

-        

-        {

-          unsigned kkk = (unsigned)(p->buf - p->tempBuf);

-          if (rem < kkk)

-            return SZ_ERROR_FAIL; /* some internal error */

-          rem -= kkk;

-          if (lookAhead < rem)

-            return SZ_ERROR_FAIL; /* some internal error */

-          lookAhead -= rem;

-        }

-        (*srcLen) += (SizeT)lookAhead;

-        src += lookAhead;

-        inSize -= (SizeT)lookAhead;

-        p->tempBufSize = 0;

-      }

-  }

-  

-  if (p->code != 0)

-    return SZ_ERROR_DATA;

-  *status = LZMA_STATUS_FINISHED_WITH_MARK;

-  return SZ_OK;

-}

-

-

-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 <string.h>
+
+/* #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 28ce60c..b0ce28f 100644
--- a/C/LzmaDec.h
+++ b/C/LzmaDec.h
@@ -1,234 +1,237 @@
-/* LzmaDec.h -- LZMA Decoder

-2018-04-21 : Igor Pavlov : Public domain */

-

-#ifndef __LZMA_DEC_H

-#define __LZMA_DEC_H

-

-#include "7zTypes.h"

-

-EXTERN_C_BEGIN

-

-/* #define _LZMA_PROB32 */

-/* _LZMA_PROB32 can increase the speed on some CPUs,

-   but memory usage for CLzmaDec::probs will be doubled in that case */

-

-typedef

-#ifdef _LZMA_PROB32

-  UInt32

-#else

-  UInt16

-#endif

-  CLzmaProb;

-

-

-/* ---------- LZMA Properties ---------- */

-

-#define LZMA_PROPS_SIZE 5

-

-typedef struct _CLzmaProps

-{

-  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; }

-

-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

-*/

-

-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).

-*/

-

-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 14086fc..6d13cac 100644
--- a/C/LzmaEnc.c
+++ b/C/LzmaEnc.c
@@ -1,2976 +1,3144 @@
-/* LzmaEnc.c -- LZMA Encoder

-2019-01-10: Igor Pavlov : Public domain */

-

-#include "Precomp.h"

-

-#include <string.h>

-

-/* #define SHOW_STAT */

-/* #define SHOW_STAT2 */

-

-#if defined(SHOW_STAT) || defined(SHOW_STAT2)

-#include <stdio.h>

-#endif

-

-#include "LzmaEnc.h"

-

-#include "LzFind.h"

-#ifndef _7ZIP_ST

-#include "LzFindMt.h"

-#endif

-

-#ifdef SHOW_STAT

-static unsigned g_STAT_OFFSET = 0;

-#endif

-

-#define kLzmaMaxHistorySize ((UInt32)3 << 29)

-/* #define kLzmaMaxHistorySize ((UInt32)7 << 29) */

-

-#define kNumTopBits 24

-#define kTopValue ((UInt32)1 << kNumTopBits)

-

-#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->writeEndMark = 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 <= 5 ? (1 << (level * 2 + 14)) : (level <= 7 ? (1 << 25) : (1 << 26)));

-  if (p->dictSize > p->reduceSize)

-  {

-    unsigned i;

-    UInt32 reduceSize = (UInt32)p->reduceSize;

-    for (i = 11; i <= 30; i++)

-    {

-      if (reduceSize <= ((UInt32)2 << i)) { p->dictSize = ((UInt32)2 << i); break; }

-      if (reduceSize <= ((UInt32)3 << i)) { p->dictSize = ((UInt32)3 << i); break; }

-    }

-  }

-

-  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 = 4;

-  if (p->mc == 0) p->mc = (16 + (p->fb >> 1)) >> (p->btMode ? 0 : 1);

-  

-  if (p->numThreads < 0)

-    p->numThreads =

-      #ifndef _7ZIP_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;

-}

-

-#if (_MSC_VER >= 1400)

-/* BSR code is fast for some new CPUs */

-/* #define LZMA_LOG_BSR */

-#endif

-

-#ifdef LZMA_LOG_BSR

-

-#define kDicLogSizeMaxCompress 32

-

-#define BSR2_RET(pos, res) { unsigned long zz; _BitScanReverse(&zz, (pos)); res = (zz + zz) + ((pos >> (zz - 1)) & 1); }

-

-static 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

-

-#define kNumLogBits (9 + sizeof(size_t) / 2)

-/* #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

-

-

-#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 _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;

-  ISeqOutStream *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;

-

-

-typedef struct

-{

-  void *matchFinderObj;

-  IMatchFinder 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 _7ZIP_ST

-  BoolInt mtMode;

-  // begin of CMatchFinderMt is used in LZ thread

-  CMatchFinderMt matchFinderMt;

-  // end of CMatchFinderMt is used in BT and HASH threads

-  #endif

-

-  CMatchFinder matchFinderBase;

-

-  #ifndef _7ZIP_ST

-  Byte pad[128];

-  #endif

-  

-  // LZ thread

-  CProbPrice ProbPrices[kBitModelTotal >> kNumMoveReducingBits];

-

-  UInt32 matches[LZMA_MATCH_LEN_MAX * 2 + 2 + 1];

-

-  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;

-

-  #ifndef _7ZIP_ST

-  Byte pad2[128];

-  #endif

-} CLzmaEnc;

-

-

-

-#define COPY_ARR(dest, src, arr) memcpy(dest->arr, src->arr, sizeof(src->arr));

-

-void LzmaEnc_SaveState(CLzmaEncHandle pp)

-{

-  CLzmaEnc *p = (CLzmaEnc *)pp;

-  CSaveState *dest = &p->saveState;

-  

-  dest->state = p->state;

-  

-  dest->lenProbs = p->lenProbs;

-  dest->repLenProbs = p->repLenProbs;

-

-  COPY_ARR(dest, p, reps);

-

-  COPY_ARR(dest, p, posAlignEncoder);

-  COPY_ARR(dest, p, isRep);

-  COPY_ARR(dest, p, isRepG0);

-  COPY_ARR(dest, p, isRepG1);

-  COPY_ARR(dest, p, isRepG2);

-  COPY_ARR(dest, p, isMatch);

-  COPY_ARR(dest, p, isRep0Long);

-  COPY_ARR(dest, p, posSlotEncoder);

-  COPY_ARR(dest, p, posEncoders);

-

-  memcpy(dest->litProbs, p->litProbs, ((UInt32)0x300 << p->lclp) * sizeof(CLzmaProb));

-}

-

-

-void LzmaEnc_RestoreState(CLzmaEncHandle pp)

-{

-  CLzmaEnc *dest = (CLzmaEnc *)pp;

-  const CSaveState *p = &dest->saveState;

-

-  dest->state = p->state;

-

-  dest->lenProbs = p->lenProbs;

-  dest->repLenProbs = p->repLenProbs;

-  

-  COPY_ARR(dest, p, reps);

-  

-  COPY_ARR(dest, p, posAlignEncoder);

-  COPY_ARR(dest, p, isRep);

-  COPY_ARR(dest, p, isRepG0);

-  COPY_ARR(dest, p, isRepG1);

-  COPY_ARR(dest, p, isRepG2);

-  COPY_ARR(dest, p, isMatch);

-  COPY_ARR(dest, p, isRep0Long);

-  COPY_ARR(dest, p, posSlotEncoder);

-  COPY_ARR(dest, p, posEncoders);

-

-  memcpy(dest->litProbs, p->litProbs, ((UInt32)0x300 << dest->lclp) * sizeof(CLzmaProb));

-}

-

-

-

-SRes LzmaEnc_SetProps(CLzmaEncHandle pp, const CLzmaEncProps *props2)

-{

-  CLzmaEnc *p = (CLzmaEnc *)pp;

-  CLzmaEncProps props = *props2;

-  LzmaEncProps_Normalize(&props);

-

-  if (props.lc > LZMA_LC_MAX

-      || props.lp > LZMA_LP_MAX

-      || props.pb > LZMA_PB_MAX

-      || props.dictSize > ((UInt64)1 << kDicLogSizeMaxCompress)

-      || props.dictSize > kLzmaMaxHistorySize)

-    return SZ_ERROR_PARAM;

-

-  p->dictSize = props.dictSize;

-  {

-    unsigned fb = props.fb;

-    if (fb < 5)

-      fb = 5;

-    if (fb > LZMA_MATCH_LEN_MAX)

-      fb = LZMA_MATCH_LEN_MAX;

-    p->numFastBytes = fb;

-  }

-  p->lc = props.lc;

-  p->lp = props.lp;

-  p->pb = props.pb;

-  p->fastMode = (props.algo == 0);

-  // p->_maxMode = True;

-  p->matchFinderBase.btMode = (Byte)(props.btMode ? 1 : 0);

-  {

-    unsigned numHashBytes = 4;

-    if (props.btMode)

-    {

-      if (props.numHashBytes < 2)

-        numHashBytes = 2;

-      else if (props.numHashBytes < 4)

-        numHashBytes = props.numHashBytes;

-    }

-    p->matchFinderBase.numHashBytes = numHashBytes;

-  }

-

-  p->matchFinderBase.cutValue = props.mc;

-

-  p->writeEndMark = props.writeEndMark;

-

-  #ifndef _7ZIP_ST

-  /*

-  if (newMultiThread != _multiThread)

-  {

-    ReleaseMatchFinder();

-    _multiThread = newMultiThread;

-  }

-  */

-  p->multiThread = (props.numThreads > 1);

-  #endif

-

-  return SZ_OK;

-}

-

-

-void LzmaEnc_SetDataSize(CLzmaEncHandle pp, UInt64 expectedDataSiize)

-{

-  CLzmaEnc *p = (CLzmaEnc *)pp;

-  p->matchFinderBase.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 + ((p)->buf - (p)->bufBase) + (p)->cacheSize)

-#define RangeEnc_GetProcessed_sizet(p) ((size_t)(p)->processed + ((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 = 0;

-}

-

-static void RangeEnc_Init(CRangeEnc *p)

-{

-  /* Stream.Init(); */

-  p->range = 0xFFFFFFFF;

-  p->cache = 0;

-  p->low = 0;

-  p->cacheSize = 0;

-

-  p->buf = p->bufBase;

-

-  p->processed = 0;

-  p->res = SZ_OK;

-}

-

-MY_NO_INLINE static void RangeEnc_FlushStream(CRangeEnc *p)

-{

-  size_t num;

-  if (p->res != SZ_OK)

-    return;

-  num = p->buf - p->bufBase;

-  if (num != ISeqOutStream_Write(p->outStream, p->bufBase, num))

-    p->res = SZ_ERROR_WRITE;

-  p->processed += num;

-  p->buf = p->bufBase;

-}

-

-MY_NO_INLINE static void MY_FAST_CALL 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 _LZMA_ENC_USE_BRANCH

-

-#ifdef _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 += (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)((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);

-  }

-}

-

-

-MY_NO_INLINE static void MY_FAST_CALL 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

-        {

-          unsigned bit = sym & 1;

-          sym >>= 1;

-          price += GET_PRICEa(probs[sym], bit);

-        }

-        while (sym >= 2);

-

-        {

-          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;

-        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);

-  numPairs = p->matchFinder.GetMatches(p->matchFinderObj, 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;

-  {

-    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;

-        ptrdiff_t dif = (ptrdiff_t)-1 - 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])

-  

-MY_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 (repLens[repMaxIndex] >= p->numFastBytes)

-    {

-      unsigned len;

-      p->backRes = (UInt32)repMaxIndex;

-      len = repLens[repMaxIndex];

-      MOVE_POS(p, len - 1)

-      return len;

-    }

-    

-    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;

-  if (p->matchFinderBase.result != SZ_OK)

-    p->result = SZ_ERROR_READ;

-  if (p->result != SZ_OK)

-    p->finished = True;

-  return p->result;

-}

-

-

-MY_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);

-}

-

-

-MY_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);

-  }

-}

-

-

-MY_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];

-      }

-    }

-  }

-  // }

-}

-

-

-

-void LzmaEnc_Construct(CLzmaEnc *p)

-{

-  RangeEnc_Construct(&p->rc);

-  MatchFinder_Construct(&p->matchFinderBase);

-  

-  #ifndef _7ZIP_ST

-  MatchFinderMt_Construct(&p->matchFinderMt);

-  p->matchFinderMt.MatchFinder = &p->matchFinderBase;

-  #endif

-

-  {

-    CLzmaEncProps props;

-    LzmaEncProps_Init(&props);

-    LzmaEnc_SetProps(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;

-}

-

-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;

-}

-

-void LzmaEnc_Destruct(CLzmaEnc *p, ISzAllocPtr alloc, ISzAllocPtr allocBig)

-{

-  #ifndef _7ZIP_ST

-  MatchFinderMt_Destruct(&p->matchFinderMt, allocBig);

-  #endif

-  

-  MatchFinder_Free(&p->matchFinderBase, allocBig);

-  LzmaEnc_FreeLits(p, alloc);

-  RangeEnc_Free(&p->rc, alloc);

-}

-

-void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAllocPtr alloc, ISzAllocPtr allocBig)

-{

-  LzmaEnc_Destruct((CLzmaEnc *)p, alloc, allocBig);

-  ISzAlloc_Free(alloc, p);

-}

-

-

-static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, UInt32 maxPackSize, UInt32 maxUnpackSize)

-{

-  UInt32 nowPos32, startPos32;

-  if (p->needInit)

-  {

-    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, 1 << p->pb, &p->lenProbs, p->ProbPrices);

-        }

-        if (p->repLenEncCounter <= 0)

-        {

-          p->repLenEncCounter = REP_LEN_COUNT;

-          LenPriceEnc_UpdateTables(&p->repLenEnc, 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;

-  if (!RangeEnc_Alloc(&p->rc, alloc))

-    return SZ_ERROR_MEM;

-

-  #ifndef _7ZIP_ST

-  p->mtMode = (p->multiThread && !p->fastMode && (p->matchFinderBase.btMode != 0));

-  #endif

-

-  {

-    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, ((UInt32)0x300 << lclp) * sizeof(CLzmaProb));

-      p->saveState.litProbs = (CLzmaProb *)ISzAlloc_Alloc(alloc, ((UInt32)0x300 << lclp) * sizeof(CLzmaProb));

-      if (!p->litProbs || !p->saveState.litProbs)

-      {

-        LzmaEnc_FreeLits(p, alloc);

-        return SZ_ERROR_MEM;

-      }

-      p->lclp = lclp;

-    }

-  }

-

-  p->matchFinderBase.bigHash = (Byte)(p->dictSize > kBigHashDicLimit ? 1 : 0);

-

-  if (beforeSize + p->dictSize < keepWindowSize)

-    beforeSize = keepWindowSize - p->dictSize;

-

-  #ifndef _7ZIP_ST

-  if (p->mtMode)

-  {

-    RINOK(MatchFinderMt_Create(&p->matchFinderMt, p->dictSize, beforeSize, p->numFastBytes,

-        LZMA_MATCH_LEN_MAX

-        + 1  /* 18.04 */

-        , allocBig));

-    p->matchFinderObj = &p->matchFinderMt;

-    p->matchFinderBase.bigHash = (Byte)(

-        (p->dictSize > kBigHashDicLimit && p->matchFinderBase.hashMask >= 0xFFFFFF) ? 1 : 0);

-    MatchFinderMt_CreateVTable(&p->matchFinderMt, &p->matchFinder);

-  }

-  else

-  #endif

-  {

-    if (!MatchFinder_Create(&p->matchFinderBase, p->dictSize, beforeSize, p->numFastBytes, LZMA_MATCH_LEN_MAX, allocBig))

-      return SZ_ERROR_MEM;

-    p->matchFinderObj = &p->matchFinderBase;

-    MatchFinder_CreateVTable(&p->matchFinderBase, &p->matchFinder);

-  }

-  

-  return SZ_OK;

-}

-

-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;

-  }

-

-  {

-    UInt32 num = (UInt32)0x300 << (p->lp + p->lc);

-    UInt32 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 = (1 << p->pb) - 1;

-  p->lpMask = ((UInt32)0x100 << p->lp) - ((unsigned)0x100 >> p->lc);

-}

-

-

-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, 1 << p->pb, &p->lenProbs, p->ProbPrices);

-  LenPriceEnc_UpdateTables(&p->repLenEnc, 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;

-  RINOK(LzmaEnc_Alloc(p, keepWindowSize, alloc, allocBig));

-  LzmaEnc_Init(p);

-  LzmaEnc_InitPrices(p);

-  p->nowPos64 = 0;

-  return SZ_OK;

-}

-

-static SRes LzmaEnc_Prepare(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream,

-    ISzAllocPtr alloc, ISzAllocPtr allocBig)

-{

-  CLzmaEnc *p = (CLzmaEnc *)pp;

-  p->matchFinderBase.stream = inStream;

-  p->needInit = 1;

-  p->rc.outStream = outStream;

-  return LzmaEnc_AllocAndInit(p, 0, alloc, allocBig);

-}

-

-SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp,

-    ISeqInStream *inStream, UInt32 keepWindowSize,

-    ISzAllocPtr alloc, ISzAllocPtr allocBig)

-{

-  CLzmaEnc *p = (CLzmaEnc *)pp;

-  p->matchFinderBase.stream = inStream;

-  p->needInit = 1;

-  return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig);

-}

-

-static void LzmaEnc_SetInputBuf(CLzmaEnc *p, const Byte *src, SizeT srcLen)

-{

-  p->matchFinderBase.directInput = 1;

-  p->matchFinderBase.bufferBase = (Byte *)src;

-  p->matchFinderBase.directInputRem = srcLen;

-}

-

-SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen,

-    UInt32 keepWindowSize, ISzAllocPtr alloc, ISzAllocPtr allocBig)

-{

-  CLzmaEnc *p = (CLzmaEnc *)pp;

-  LzmaEnc_SetInputBuf(p, src, srcLen);

-  p->needInit = 1;

-

-  LzmaEnc_SetDataSize(pp, srcLen);

-  return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig);

-}

-

-void LzmaEnc_Finish(CLzmaEncHandle pp)

-{

-  #ifndef _7ZIP_ST

-  CLzmaEnc *p = (CLzmaEnc *)pp;

-  if (p->mtMode)

-    MatchFinderMt_ReleaseStream(&p->matchFinderMt);

-  #else

-  UNUSED_VAR(pp);

-  #endif

-}

-

-

-typedef struct

-{

-  ISeqOutStream vt;

-  Byte *data;

-  SizeT rem;

-  BoolInt overflow;

-} CLzmaEnc_SeqOutStreamBuf;

-

-static size_t SeqOutStreamBuf_Write(const ISeqOutStream *pp, const void *data, size_t size)

-{

-  CLzmaEnc_SeqOutStreamBuf *p = CONTAINER_FROM_VTBL(pp, CLzmaEnc_SeqOutStreamBuf, vt);

-  if (p->rem < size)

-  {

-    size = p->rem;

-    p->overflow = True;

-  }

-  memcpy(p->data, data, size);

-  p->rem -= size;

-  p->data += size;

-  return size;

-}

-

-

-UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle pp)

-{

-  const CLzmaEnc *p = (CLzmaEnc *)pp;

-  return p->matchFinder.GetNumAvailableBytes(p->matchFinderObj);

-}

-

-

-const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp)

-{

-  const CLzmaEnc *p = (CLzmaEnc *)pp;

-  return p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset;

-}

-

-

-SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, BoolInt reInit,

-    Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize)

-{

-  CLzmaEnc *p = (CLzmaEnc *)pp;

-  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);

-

-  nowPos64 = p->nowPos64;

-  RangeEnc_Init(&p->rc);

-  p->rc.outStream = &outStream.vt;

-

-  if (desiredPackSize == 0)

-    return SZ_ERROR_OUTPUT_EOF;

-

-  res = LzmaEnc_CodeOneBlock(p, desiredPackSize, *unpackSize);

-  

-  *unpackSize = (UInt32)(p->nowPos64 - nowPos64);

-  *destLen -= outStream.rem;

-  if (outStream.overflow)

-    return SZ_ERROR_OUTPUT_EOF;

-

-  return res;

-}

-

-

-static SRes LzmaEnc_Encode2(CLzmaEnc *p, ICompressProgress *progress)

-{

-  SRes res = SZ_OK;

-

-  #ifndef _7ZIP_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(p);

-

-  /*

-  if (res == SZ_OK && !Inline_MatchFinder_IsFinishedOK(&p->matchFinderBase))

-    res = SZ_ERROR_FAIL;

-  }

-  */

-

-  return res;

-}

-

-

-SRes LzmaEnc_Encode(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress,

-    ISzAllocPtr alloc, ISzAllocPtr allocBig)

-{

-  RINOK(LzmaEnc_Prepare(pp, outStream, inStream, alloc, allocBig));

-  return LzmaEnc_Encode2((CLzmaEnc *)pp, progress);

-}

-

-

-SRes LzmaEnc_WriteProperties(CLzmaEncHandle pp, Byte *props, SizeT *size)

-{

-  CLzmaEnc *p = (CLzmaEnc *)pp;

-  unsigned i;

-  UInt32 dictSize = p->dictSize;

-  if (*size < LZMA_PROPS_SIZE)

-    return SZ_ERROR_PARAM;

-  *size = LZMA_PROPS_SIZE;

-  props[0] = (Byte)((p->pb * 5 + p->lp) * 9 + p->lc);

-

-  if (dictSize >= ((UInt32)1 << 22))

-  {

-    UInt32 kDictMask = ((UInt32)1 << 20) - 1;

-    if (dictSize < (UInt32)0xFFFFFFFF - kDictMask)

-      dictSize = (dictSize + kDictMask) & ~kDictMask;

-  }

-  else for (i = 11; i <= 30; i++)

-  {

-    if (dictSize <= ((UInt32)2 << i)) { dictSize = (2 << i); break; }

-    if (dictSize <= ((UInt32)3 << i)) { dictSize = (3 << i); break; }

-  }

-

-  for (i = 0; i < 4; i++)

-    props[1 + i] = (Byte)(dictSize >> (8 * i));

-  return SZ_OK;

-}

-

-

-unsigned LzmaEnc_IsWriteEndMark(CLzmaEncHandle pp)

-{

-  return ((CLzmaEnc *)pp)->writeEndMark;

-}

-

-

-SRes LzmaEnc_MemEncode(CLzmaEncHandle pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,

-    int writeEndMark, ICompressProgress *progress, ISzAllocPtr alloc, ISzAllocPtr allocBig)

-{

-  SRes res;

-  CLzmaEnc *p = (CLzmaEnc *)pp;

-

-  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(pp, 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 -= 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,

-    ICompressProgress *progress, ISzAllocPtr alloc, ISzAllocPtr allocBig)

-{

-  CLzmaEnc *p = (CLzmaEnc *)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;

-}

+/* LzmaEnc.c -- LZMA Encoder
+2023-04-13: Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include <string.h>
+
+/* #define SHOW_STAT */
+/* #define SHOW_STAT2 */
+
+#if defined(SHOW_STAT) || defined(SHOW_STAT2)
+#include <stdio.h>
+#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 <intrin.h>
+
+#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, ((UInt32)0x300 << (p)->lclp) * sizeof(CLzmaProb));
+
+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
+        {
+          unsigned bit = sym & 1;
+          sym >>= 1;
+          price += GET_PRICEa(probs[sym], bit);
+        }
+        while (sym >= 2);
+
+        {
+          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;
+        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
+
+  {
+    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, ((UInt32)0x300 << lclp) * sizeof(CLzmaProb));
+      p->saveState.litProbs = (CLzmaProb *)ISzAlloc_Alloc(alloc, ((UInt32)0x300 << lclp) * sizeof(CLzmaProb));
+      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;
+  }
+
+  {
+    UInt32 num = (UInt32)0x300 << (p->lp + p->lc);
+    UInt32 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 c9938f0..9f8039a 100644
--- a/C/LzmaEnc.h
+++ b/C/LzmaEnc.h
@@ -1,76 +1,83 @@
-/*  LzmaEnc.h -- LZMA Encoder

-2017-07-27 : Igor Pavlov : Public domain */

-

-#ifndef __LZMA_ENC_H

-#define __LZMA_ENC_H

-

-#include "7zTypes.h"

-

-EXTERN_C_BEGIN

-

-#define LZMA_PROPS_SIZE 5

-

-typedef struct _CLzmaEncProps

-{

-  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 */

-  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 */

-

-  UInt64 reduceSize; /* estimated size of data that will be compressed. default = (UInt64)(Int64)-1.

-                        Encoder uses this value to reduce dictionary size */

-} 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 void * 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, ISeqOutStream *outStream, ISeqInStream *inStream,

-    ICompressProgress *progress, ISzAllocPtr alloc, ISzAllocPtr allocBig);

-SRes LzmaEnc_MemEncode(CLzmaEncHandle p, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,

-    int writeEndMark, ICompressProgress *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,

-    ICompressProgress *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 c10cf1a..785e884 100644
--- a/C/LzmaLib.c
+++ b/C/LzmaLib.c
@@ -1,40 +1,42 @@
-/* LzmaLib.c -- LZMA library wrapper

-2015-06-13 : Igor Pavlov : Public domain */

-

-#include "Alloc.h"

-#include "LzmaDec.h"

-#include "LzmaEnc.h"

-#include "LzmaLib.h"

-

-MY_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);

-}

-

-

-MY_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 5c35e53..d7c0724 100644
--- a/C/LzmaLib.h
+++ b/C/LzmaLib.h
@@ -1,131 +1,138 @@
-/* LzmaLib.h -- LZMA library interface

-2013-01-18 : Igor Pavlov : Public domain */

-

-#ifndef __LZMA_LIB_H

-#define __LZMA_LIB_H

-

-#include "7zTypes.h"

-

-EXTERN_C_BEGIN

-

-#define MY_STDAPI int MY_STD_CALL

-

-#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:    16 KB   0    32

-    1:    64 KB   0    32

-    2:   256 KB   0    32

-    3:     1 MB   0    32

-    4:     4 MB   0    32

-    5:    16 MB   1    32

-    6:    32 MB   1    32

-    7+:   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.

-

-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)

-*/

-

-MY_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

-  destLen  - output data 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)

-*/

-

-MY_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/MtCoder.c b/C/MtCoder.c
index 5667f2d..6f58abb 100644
--- a/C/MtCoder.c
+++ b/C/MtCoder.c
@@ -1,601 +1,571 @@
-/* MtCoder.c -- Multi-thread Coder

-2018-07-04 : Igor Pavlov : Public domain */

-

-#include "Precomp.h"

-

-#include "MtCoder.h"

-

-#ifndef _7ZIP_ST

-

-SRes MtProgressThunk_Progress(const ICompressProgress *pp, UInt64 inSize, UInt64 outSize)

-{

-  CMtProgressThunk *thunk = CONTAINER_FROM_VTBL(pp, CMtProgressThunk, vt);

-  UInt64 inSize2 = 0;

-  UInt64 outSize2 = 0;

-  if (inSize != (UInt64)(Int64)-1)

-  {

-    inSize2 = inSize - thunk->inSize;

-    thunk->inSize = inSize;

-  }

-  if (outSize != (UInt64)(Int64)-1)

-  {

-    outSize2 = outSize - thunk->outSize;

-    thunk->outSize = outSize;

-  }

-  return MtProgress_ProgressAdd(thunk->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 WRes ArEvent_OptCreate_And_Reset(CEvent *p)

-{

-  if (Event_IsCreated(p))

-    return Event_Reset(p);

-  return AutoResetEvent_CreateNotSignaled(p);

-}

-

-

-static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE ThreadFunc(void *pp);

-

-

-static SRes MtCoderThread_CreateAndStart(CMtCoderThread *t)

-{

-  WRes wres = ArEvent_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(&t->thread);

-    Thread_Close(&t->thread);

-  }

-

-  Event_Close(&t->startEvent);

-

-  if (t->inBuf)

-  {

-    ISzAlloc_Free(t->mtCoder->allocBig, t->inBuf);

-    t->inBuf = NULL;

-  }

-}

-

-

-

-static SRes FullRead(ISeqInStream *stream, Byte *data, size_t *processedSize)

-{

-  size_t size = *processedSize;

-  *processedSize = 0;

-  while (size != 0)

-  {

-    size_t cur = size;

-    SRes res = ISeqInStream_Read(stream, data, &cur);

-    *processedSize += cur;

-    data += cur;

-    size -= cur;

-    RINOK(res);

-    if (cur == 0)

-      return SZ_OK;

-  }

-  return SZ_OK;

-}

-

-

-/*

-  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 = FullRead(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_RET_TYPE THREAD_FUNC_CALL_TYPE ThreadFunc(void *pp)

-{

-  CMtCoderThread *t = (CMtCoderThread *)pp;

-  for (;;)

-  {

-    if (Event_Wait(&t->startEvent) != 0)

-      return 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 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(ArEvent_OptCreate_And_Reset(&p->writeEvents[i]));

-    }

-  #else

-    RINOK_THREAD(ArEvent_OptCreate_And_Reset(&p->finishedEvent));

-  #endif

-

-  {

-    RINOK_THREAD(ArEvent_OptCreate_And_Reset(&p->readEvent));

-

-    if (Semaphore_IsCreated(&p->blocksSemaphore))

-    {

-      RINOK_THREAD(Semaphore_Close(&p->blocksSemaphore));

-    }

-    RINOK_THREAD(Semaphore_Create(&p->blocksSemaphore, numBlocksMax, 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

+/* MtCoder.c -- Multi-thread Coder
+2023-04-13 : 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, numBlocksMax, 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 603329d..1231d3c 100644
--- a/C/MtCoder.h
+++ b/C/MtCoder.h
@@ -1,141 +1,141 @@
-/* MtCoder.h -- Multi-thread Coder

-2018-07-04 : Igor Pavlov : Public domain */

-

-#ifndef __MT_CODER_H

-#define __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 _7ZIP_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 _7ZIP_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;

-

-  ISeqInStream *inStream;

-  const Byte *inData;

-  size_t inDataSize;

-

-  ICompressProgress *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 25a8b04..7820699 100644
--- a/C/MtDec.c
+++ b/C/MtDec.c
@@ -1,1138 +1,1114 @@
-/* MtDec.c -- Multi-thread Decoder

-2019-02-02 : Igor Pavlov : Public domain */

-

-#include "Precomp.h"

-

-// #define SHOW_DEBUG_INFO

-

-// #include <stdio.h>

-

-#ifdef SHOW_DEBUG_INFO

-#include <stdio.h>

-#endif

-

-#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))

-

-#include "MtDec.h"

-

-#ifndef _7ZIP_ST

-

-void MtProgress_Init(CMtProgress *p, ICompressProgress *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(x)

-

-

-static WRes ArEvent_OptCreate_And_Reset(CEvent *p)

-{

-  if (Event_IsCreated(p))

-    return Event_Reset(p);

-  return AutoResetEvent_CreateNotSignaled(p);

-}

-

-

-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_RET_TYPE THREAD_FUNC_CALL_TYPE ThreadFunc(void *pp);

-

-

-static WRes MtDecThread_CreateEvents(CMtDecThread *t)

-{

-  WRes wres = ArEvent_OptCreate_And_Reset(&t->canWrite);

-  if (wres == 0)

-  {

-    wres = ArEvent_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, 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(&t->thread);

-    Thread_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 FullRead(ISeqInStream *stream, Byte *data, size_t *processedSize)

-{

-  size_t size = *processedSize;

-  *processedSize = 0;

-  while (size != 0)

-  {

-    size_t cur = size;

-    SRes res = ISeqInStream_Read(stream, data, &cur);

-    *processedSize += cur;

-    data += cur;

-    size -= cur;

-    RINOK(res);

-    if (cur == 0)

-      return SZ_OK;

-  }

-  return SZ_OK;

-}

-

-

-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);

-}

-

-

-/*

-  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 ThreadFunc2(CMtDecThread *t)

-{

-  CMtDec *p = t->mtDec;

-

-  PRF_STR_INT("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 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 = FullRead(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);

-

-              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)

-                {

-                  p->crossStart = 0;

-                  p->crossEnd = 0;

-

-                  if (crossSize != 0)

-                    memcpy(data + parse.srcSize, parseData + parse.srcSize, size - parse.srcSize); // we need all data

-                  afterEndData_Size = size - parse.srcSize;

-                  afterEndData = parseData + parse.srcSize;

-

-                  // we reduce data size to required bytes (parsed only)

-                  inDataSize -= (size - parse.srcSize);

-                  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 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;

-

-      res = p->mtCallback->Write(p->mtCallbackObject, t->index,

-          res == SZ_OK && needWriteToStream && !wasInterrupted, // needWrite

-          afterEndData, afterEndData_Size,

-          &needContinue,

-          &canRecode);

-      

-      // res= E_INVALIDARG; // 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 <malloc.h>

-#else

-#include <stdlib.h>

-#endif

-#endif

-

-

-static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE ThreadFunc1(void *pp)

-{

-  WRes res;

-

-  CMtDecThread *t = (CMtDecThread *)pp;

-  CMtDec *p;

-

-  // fprintf(stdout, "\n%d = %p\n", t->index, &t);

-

-  res = ThreadFunc2(t);

-  p = t->mtDec;

-  if (res == 0)

-    return 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 res;

-}

-

-static MY_NO_INLINE THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE ThreadFunc(void *pp)

-{

-  CMtDecThread *t = (CMtDecThread *)pp;

-

-  // fprintf(stderr, "\n%d = %p - before", t->index, &t);

-  #ifdef USE_ALLOCA

-  t->allocaPtr = alloca(t->index * 128);

-  #endif

-  return 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(ArEvent_OptCreate_And_Reset(&p->finishedEvent));

-  p->exitThread = False;

-  p->exitThreadWRes = 0;

-

-  {

-    WRes wres;

-    WRes 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) { wres = ThreadFunc(nextThread);

-    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 E_FAIL;

-  }

-}

-

-#endif

+/* MtDec.c -- Multi-thread Decoder
+2023-04-02 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+// #define SHOW_DEBUG_INFO
+
+// #include <stdio.h>
+#include <string.h>
+
+#ifdef SHOW_DEBUG_INFO
+#include <stdio.h>
+#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 <malloc.h>
+#else
+#include <stdlib.h>
+#endif
+#endif
+
+
+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)(UINT_PTR)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)(UINT_PTR)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)(UINT_PTR)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 9864cc8..c28e8d9 100644
--- a/C/MtDec.h
+++ b/C/MtDec.h
@@ -1,201 +1,202 @@
-/* MtDec.h -- Multi-thread Decoder

-2018-07-04 : Igor Pavlov : Public domain */

-

-#ifndef __MT_DEC_H

-#define __MT_DEC_H

-

-#include "7zTypes.h"

-

-#ifndef _7ZIP_ST

-#include "Threads.h"

-#endif

-

-EXTERN_C_BEGIN

-

-#ifndef _7ZIP_ST

-

-#ifndef _7ZIP_ST

-  #define MTDEC__THREADS_MAX 32

-#else

-  #define MTDEC__THREADS_MAX 1

-#endif

-

-

-typedef struct

-{

-  ICompressProgress *progress;

-  SRes res;

-  UInt64 totalInSize;

-  UInt64 totalOutSize;

-  CCriticalSection cs;

-} CMtProgress;

-

-void MtProgress_Init(CMtProgress *p, ICompressProgress *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,

-      // int srcFinished,

-      BoolInt *needContinue,

-      BoolInt *canRecode);

-} IMtDecCallback;

-

-

-

-typedef struct _CMtDec

-{

-  /* input variables */

-  

-  size_t inBufSize;        /* size of input block */

-  unsigned numThreadsMax;

-  // size_t inBlockMax;

-  unsigned numThreadsMax_2;

-

-  ISeqInStream *inStream;

-  // const Byte *inData;

-  // size_t inDataSize;

-

-  ICompressProgress *progress;

-  ISzAllocPtr alloc;

-

-  IMtDecCallback *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 _7ZIP_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 4b99415..66b2626 100644
--- a/C/Ppmd.h
+++ b/C/Ppmd.h
@@ -1,85 +1,169 @@
-/* Ppmd.h -- PPMD codec common code

-2017-04-03 : Igor Pavlov : Public domain

-This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */

-

-#ifndef __PPMD_H

-#define __PPMD_H

-

-#include "CpuArch.h"

-

-EXTERN_C_BEGIN

-

-#ifdef MY_CPU_32BIT

-  #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)

-

-#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 <<= 1; (p)->Count = (Byte)(3 << (p)->Shift++); }

-

-typedef struct

-{

-  Byte Symbol;

-  Byte Freq;

-  UInt16 SuccessorLow;

-  UInt16 SuccessorHigh;

-} CPpmd_State;

-

-#pragma pack(pop)

-

-typedef

-  #ifdef PPMD_32BIT

-    CPpmd_State *

-  #else

-    UInt32

-  #endif

-  CPpmd_State_Ref;

-

-typedef

-  #ifdef PPMD_32BIT

-    void *

-  #else

-    UInt32

-  #endif

-  CPpmd_Void_Ref;

-

-typedef

-  #ifdef PPMD_32BIT

-    Byte *

-  #else

-    UInt32

-  #endif

-  CPpmd_Byte_Ref;

-

-#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 80e7de9..6e1307e 100644
--- a/C/Ppmd7.c
+++ b/C/Ppmd7.c
@@ -1,712 +1,1122 @@
-/* Ppmd7.c -- PPMdH codec

-2018-07-04 : Igor Pavlov : Public domain

-This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */

-

-#include "Precomp.h"

-

-#include <string.h>

-

-#include "Ppmd7.h"

-

-const Byte PPMD7_kExpEscape[16] = { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 };

-static const UInt16 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) (p->Indx2Units[indx])

-

-#ifdef PPMD_32BIT

-  #define REF(ptr) (ptr)

-#else

-  #define REF(ptr) ((UInt32)((Byte *)(ptr) - (p)->Base))

-#endif

-

-#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 * CTX_PTR;

-

-struct CPpmd7_Node_;

-

-typedef

-  #ifdef PPMD_32BIT

-    struct CPpmd7_Node_ *

-  #else

-    UInt32

-  #endif

-  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;

-

-#ifdef PPMD_32BIT

-  #define NODE(ptr) (ptr)

-#else

-  #define NODE(offs) ((CPpmd7_Node *)(p->Base + (offs)))

-#endif

-

-void Ppmd7_Construct(CPpmd7 *p)

-{

-  unsigned i, k, m;

-

-  p->Base = 0;

-

-  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;

-  }

-

-  memset(p->HB2Flag, 0, 0x40);

-  memset(p->HB2Flag + 0x40, 8, 0x100 - 0x40);

-}

-

-void Ppmd7_Free(CPpmd7 *p, ISzAllocPtr alloc)

-{

-  ISzAlloc_Free(alloc, p->Base);

-  p->Size = 0;

-  p->Base = 0;

-}

-

-BoolInt Ppmd7_Alloc(CPpmd7 *p, UInt32 size, ISzAllocPtr alloc)

-{

-  if (!p->Base || p->Size != size)

-  {

-    size_t size2;

-    Ppmd7_Free(p, alloc);

-    size2 = 0

-      #ifndef PPMD_32BIT

-      + UNIT_SIZE

-      #endif

-      ;

-    p->AlignOffset =

-      #ifdef PPMD_32BIT

-        (4 - size) & 3;

-      #else

-        4 - (size & 3);

-      #endif

-    if ((p->Base = (Byte *)ISzAlloc_Alloc(alloc, p->AlignOffset + size + size2)) == 0)

-      return False;

-    p->Size = size;

-  }

-  return True;

-}

-

-static void InsertNode(CPpmd7 *p, void *node, unsigned indx)

-{

-  *((CPpmd_Void_Ref *)node) = p->FreeList[indx];

-  p->FreeList[indx] = REF(node);

-}

-

-static void *RemoveNode(CPpmd7 *p, unsigned indx)

-{

-  CPpmd_Void_Ref *node = (CPpmd_Void_Ref *)Ppmd7_GetPtr(p, p->FreeList[indx]);

-  p->FreeList[indx] = *node;

-  return node;

-}

-

-static void 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);

-    InsertNode(p, ((Byte *)ptr) + U2B(k), nu - k - 1);

-  }

-  InsertNode(p, ptr, i);

-}

-

-static void GlueFreeBlocks(CPpmd7 *p)

-{

-  #ifdef PPMD_32BIT

-  CPpmd7_Node headItem;

-  CPpmd7_Node_Ref head = &headItem;

-  #else

-  CPpmd7_Node_Ref head = p->AlignOffset + p->Size;

-  #endif

-  

-  CPpmd7_Node_Ref n = head;

-  unsigned i;

-

-  p->GlueCount = 255;

-

-  /* create doubly-linked list of free blocks */

-  for (i = 0; i < PPMD_NUM_INDEXES; i++)

-  {

-    UInt16 nu = I2U(i);

-    CPpmd7_Node_Ref next = (CPpmd7_Node_Ref)p->FreeList[i];

-    p->FreeList[i] = 0;

-    while (next != 0)

-    {

-      CPpmd7_Node *node = NODE(next);

-      node->Next = n;

-      n = NODE(n)->Prev = next;

-      next = *(const CPpmd7_Node_Ref *)node;

-      node->Stamp = 0;

-      node->NU = (UInt16)nu;

-    }

-  }

-  NODE(head)->Stamp = 1;

-  NODE(head)->Next = n;

-  NODE(n)->Prev = head;

-  if (p->LoUnit != p->HiUnit)

-    ((CPpmd7_Node *)p->LoUnit)->Stamp = 1;

-  

-  /* Glue free blocks */

-  while (n != head)

-  {

-    CPpmd7_Node *node = NODE(n);

-    UInt32 nu = (UInt32)node->NU;

-    for (;;)

-    {

-      CPpmd7_Node *node2 = NODE(n) + nu;

-      nu += node2->NU;

-      if (node2->Stamp != 0 || nu >= 0x10000)

-        break;

-      NODE(node2->Prev)->Next = node2->Next;

-      NODE(node2->Next)->Prev = node2->Prev;

-      node->NU = (UInt16)nu;

-    }

-    n = node->Next;

-  }

-  

-  /* Fill lists of free blocks */

-  for (n = NODE(head)->Next; n != head;)

-  {

-    CPpmd7_Node *node = NODE(n);

-    unsigned nu;

-    CPpmd7_Node_Ref next = node->Next;

-    for (nu = node->NU; nu > 128; nu -= 128, node += 128)

-      InsertNode(p, node, PPMD_NUM_INDEXES - 1);

-    if (I2U(i = U2I(nu)) != nu)

-    {

-      unsigned k = I2U(--i);

-      InsertNode(p, node + k, nu - k - 1);

-    }

-    InsertNode(p, node, i);

-    n = next;

-  }

-}

-

-static void *AllocUnitsRare(CPpmd7 *p, unsigned indx)

-{

-  unsigned i;

-  void *retVal;

-  if (p->GlueCount == 0)

-  {

-    GlueFreeBlocks(p);

-    if (p->FreeList[indx] != 0)

-      return RemoveNode(p, indx);

-  }

-  i = indx;

-  do

-  {

-    if (++i == PPMD_NUM_INDEXES)

-    {

-      UInt32 numBytes = U2B(I2U(indx));

-      p->GlueCount--;

-      return ((UInt32)(p->UnitsStart - p->Text) > numBytes) ? (p->UnitsStart -= numBytes) : (NULL);

-    }

-  }

-  while (p->FreeList[i] == 0);

-  retVal = RemoveNode(p, i);

-  SplitBlock(p, retVal, i, indx);

-  return retVal;

-}

-

-static void *AllocUnits(CPpmd7 *p, unsigned indx)

-{

-  UInt32 numBytes;

-  if (p->FreeList[indx] != 0)

-    return RemoveNode(p, indx);

-  numBytes = U2B(I2U(indx));

-  if (numBytes <= (UInt32)(p->HiUnit - p->LoUnit))

-  {

-    void *retVal = p->LoUnit;

-    p->LoUnit += numBytes;

-    return retVal;

-  }

-  return AllocUnitsRare(p, indx);

-}

-

-#define MyMem12Cpy(dest, src, num) \

-  { UInt32 *d = (UInt32 *)dest; const UInt32 *s = (const UInt32 *)src; UInt32 n = num; \

-    do { d[0] = s[0]; d[1] = s[1]; d[2] = s[2]; s += 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 = RemoveNode(p, i1);

-    MyMem12Cpy(ptr, oldPtr, newNU);

-    InsertNode(p, oldPtr, i0);

-    return ptr;

-  }

-  SplitBlock(p, oldPtr, i0, i1);

-  return oldPtr;

-}

-

-#define SUCCESSOR(p) ((CPpmd_Void_Ref)((p)->SuccessorLow | ((UInt32)(p)->SuccessorHigh << 16)))

-

-static void SetSuccessor(CPpmd_State *p, CPpmd_Void_Ref v)

-{

-  (p)->SuccessorLow = (UInt16)((UInt32)(v) & 0xFFFF);

-  (p)->SuccessorHigh = (UInt16)(((UInt32)(v) >> 16) & 0xFFFF);

-}

-

-static void RestartModel(CPpmd7 *p)

-{

-  unsigned i, k, m;

-

-  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;

-

-  p->MinContext = p->MaxContext = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); /* AllocContext(p); */

-  p->MinContext->Suffix = 0;

-  p->MinContext->NumStats = 256;

-  p->MinContext->SummFreq = 256 + 1;

-  p->FoundState = (CPpmd_State *)p->LoUnit; /* AllocUnits(p, PPMD_NUM_INDEXES - 1); */

-  p->LoUnit += U2B(256 / 2);

-  p->MinContext->Stats = REF(p->FoundState);

-  for (i = 0; i < 256; i++)

-  {

-    CPpmd_State *s = &p->FoundState[i];

-    s->Symbol = (Byte)i;

-    s->Freq = 1;

-    SetSuccessor(s, 0);

-  }

-

-  for (i = 0; i < 128; i++)

-    for (k = 0; k < 8; k++)

-    {

-      UInt16 *dest = p->BinSumm[i] + k;

-      UInt16 val = (UInt16)(PPMD_BIN_SCALE - kInitBinEsc[k] / (i + 2));

-      for (m = 0; m < 64; m += 8)

-        dest[m] = val;

-    }

-  

-  for (i = 0; i < 25; i++)

-    for (k = 0; k < 16; k++)

-    {

-      CPpmd_See *s = &p->See[i][k];

-      s->Summ = (UInt16)((5 * i + 10) << (s->Shift = PPMD_PERIOD_BITS - 4));

-      s->Count = 4;

-    }

-}

-

-void Ppmd7_Init(CPpmd7 *p, unsigned maxOrder)

-{

-  p->MaxOrder = maxOrder;

-  RestartModel(p);

-  p->DummySee.Shift = PPMD_PERIOD_BITS;

-  p->DummySee.Summ = 0; /* unused */

-  p->DummySee.Count = 64; /* unused */

-}

-

-static CTX_PTR CreateSuccessors(CPpmd7 *p, BoolInt skip)

-{

-  CPpmd_State upState;

-  CTX_PTR c = p->MinContext;

-  CPpmd_Byte_Ref upBranch = (CPpmd_Byte_Ref)SUCCESSOR(p->FoundState);

-  CPpmd_State *ps[PPMD7_MAX_ORDER];

-  unsigned numPs = 0;

-  

-  if (!skip)

-    ps[numPs++] = p->FoundState;

-  

-  while (c->Suffix)

-  {

-    CPpmd_Void_Ref successor;

-    CPpmd_State *s;

-    c = SUFFIX(c);

-    if (c->NumStats != 1)

-    {

-      for (s = STATS(c); s->Symbol != p->FoundState->Symbol; s++);

-    }

-    else

-      s = ONE_STATE(c);

-    successor = SUCCESSOR(s);

-    if (successor != upBranch)

-    {

-      c = CTX(successor);

-      if (numPs == 0)

-        return c;

-      break;

-    }

-    ps[numPs++] = s;

-  }

-  

-  upState.Symbol = *(const Byte *)Ppmd7_GetPtr(p, upBranch);

-  SetSuccessor(&upState, upBranch + 1);

-  

-  if (c->NumStats == 1)

-    upState.Freq = ONE_STATE(c)->Freq;

-  else

-  {

-    UInt32 cf, s0;

-    CPpmd_State *s;

-    for (s = STATS(c); s->Symbol != upState.Symbol; s++);

-    cf = s->Freq - 1;

-    s0 = c->SummFreq - c->NumStats - cf;

-    upState.Freq = (Byte)(1 + ((2 * cf <= s0) ? (5 * cf > s0) : ((2 * cf + 3 * s0 - 1) / (2 * s0))));

-  }

-

-  do

-  {

-    /* Create Child */

-    CTX_PTR c1; /* = AllocContext(p); */

-    if (p->HiUnit != p->LoUnit)

-      c1 = (CTX_PTR)(p->HiUnit -= UNIT_SIZE);

-    else if (p->FreeList[0] != 0)

-      c1 = (CTX_PTR)RemoveNode(p, 0);

-    else

-    {

-      c1 = (CTX_PTR)AllocUnitsRare(p, 0);

-      if (!c1)

-        return NULL;

-    }

-    c1->NumStats = 1;

-    *ONE_STATE(c1) = upState;

-    c1->Suffix = REF(c);

-    SetSuccessor(ps[--numPs], REF(c1));

-    c = c1;

-  }

-  while (numPs != 0);

-  

-  return c;

-}

-

-static void SwapStates(CPpmd_State *t1, CPpmd_State *t2)

-{

-  CPpmd_State tmp = *t1;

-  *t1 = *t2;

-  *t2 = tmp;

-}

-

-static void UpdateModel(CPpmd7 *p)

-{

-  CPpmd_Void_Ref successor, fSuccessor = SUCCESSOR(p->FoundState);

-  CTX_PTR c;

-  unsigned s0, ns;

-  

-  if (p->FoundState->Freq < MAX_FREQ / 4 && p->MinContext->Suffix != 0)

-  {

-    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);

-      if (s->Symbol != p->FoundState->Symbol)

-      {

-        do { s++; } while (s->Symbol != p->FoundState->Symbol);

-        if (s[0].Freq >= s[-1].Freq)

-        {

-          SwapStates(&s[0], &s[-1]);

-          s--;

-        }

-      }

-      if (s->Freq < MAX_FREQ - 9)

-      {

-        s->Freq += 2;

-        c->SummFreq += 2;

-      }

-    }

-  }

-

-  if (p->OrderFall == 0)

-  {

-    p->MinContext = p->MaxContext = CreateSuccessors(p, True);

-    if (p->MinContext == 0)

-    {

-      RestartModel(p);

-      return;

-    }

-    SetSuccessor(p->FoundState, REF(p->MinContext));

-    return;

-  }

-  

-  *p->Text++ = p->FoundState->Symbol;

-  successor = REF(p->Text);

-  if (p->Text >= p->UnitsStart)

-  {

-    RestartModel(p);

-    return;

-  }

-  

-  if (fSuccessor)

-  {

-    if (fSuccessor <= successor)

-    {

-      CTX_PTR cs = CreateSuccessors(p, False);

-      if (cs == NULL)

-      {

-        RestartModel(p);

-        return;

-      }

-      fSuccessor = REF(cs);

-    }

-    if (--p->OrderFall == 0)

-    {

-      successor = fSuccessor;

-      p->Text -= (p->MaxContext != p->MinContext);

-    }

-  }

-  else

-  {

-    SetSuccessor(p->FoundState, successor);

-    fSuccessor = REF(p->MinContext);

-  }

-  

-  s0 = p->MinContext->SummFreq - (ns = p->MinContext->NumStats) - (p->FoundState->Freq - 1);

-  

-  for (c = p->MaxContext; c != p->MinContext; c = SUFFIX(c))

-  {

-    unsigned ns1;

-    UInt32 cf, sf;

-    if ((ns1 = c->NumStats) != 1)

-    {

-      if ((ns1 & 1) == 0)

-      {

-        /* Expand for one UNIT */

-        unsigned oldNU = ns1 >> 1;

-        unsigned i = U2I(oldNU);

-        if (i != U2I((size_t)oldNU + 1))

-        {

-          void *ptr = AllocUnits(p, i + 1);

-          void *oldPtr;

-          if (!ptr)

-          {

-            RestartModel(p);

-            return;

-          }

-          oldPtr = STATS(c);

-          MyMem12Cpy(ptr, oldPtr, oldNU);

-          InsertNode(p, oldPtr, i);

-          c->Stats = STATS_REF(ptr);

-        }

-      }

-      c->SummFreq = (UInt16)(c->SummFreq + (2 * ns1 < ns) + 2 * ((4 * ns1 <= ns) & (c->SummFreq <= 8 * ns1)));

-    }

-    else

-    {

-      CPpmd_State *s = (CPpmd_State*)AllocUnits(p, 0);

-      if (!s)

-      {

-        RestartModel(p);

-        return;

-      }

-      *s = *ONE_STATE(c);

-      c->Stats = REF(s);

-      if (s->Freq < MAX_FREQ / 4 - 1)

-        s->Freq <<= 1;

-      else

-        s->Freq = MAX_FREQ - 4;

-      c->SummFreq = (UInt16)(s->Freq + p->InitEsc + (ns > 3));

-    }

-    cf = 2 * (UInt32)p->FoundState->Freq * (c->SummFreq + 6);

-    sf = (UInt32)s0 + c->SummFreq;

-    if (cf < 6 * sf)

-    {

-      cf = 1 + (cf > sf) + (cf >= 4 * sf);

-      c->SummFreq += 3;

-    }

-    else

-    {

-      cf = 4 + (cf >= 9 * sf) + (cf >= 12 * sf) + (cf >= 15 * sf);

-      c->SummFreq = (UInt16)(c->SummFreq + cf);

-    }

-    {

-      CPpmd_State *s = STATS(c) + ns1;

-      SetSuccessor(s, successor);

-      s->Symbol = p->FoundState->Symbol;

-      s->Freq = (Byte)cf;

-      c->NumStats = (UInt16)(ns1 + 1);

-    }

-  }

-  p->MaxContext = p->MinContext = CTX(fSuccessor);

-}

-  

-static void Rescale(CPpmd7 *p)

-{

-  unsigned i, adder, sumFreq, escFreq;

-  CPpmd_State *stats = STATS(p->MinContext);

-  CPpmd_State *s = p->FoundState;

-  {

-    CPpmd_State tmp = *s;

-    for (; s != stats; s--)

-      s[0] = s[-1];

-    *s = tmp;

-  }

-  escFreq = p->MinContext->SummFreq - s->Freq;

-  s->Freq += 4;

-  adder = (p->OrderFall != 0);

-  s->Freq = (Byte)((s->Freq + adder) >> 1);

-  sumFreq = s->Freq;

-  

-  i = p->MinContext->NumStats - 1;

-  do

-  {

-    escFreq -= (++s)->Freq;

-    s->Freq = (Byte)((s->Freq + adder) >> 1);

-    sumFreq += s->Freq;

-    if (s[0].Freq > s[-1].Freq)

-    {

-      CPpmd_State *s1 = s;

-      CPpmd_State tmp = *s1;

-      do

-        s1[0] = s1[-1];

-      while (--s1 != stats && tmp.Freq > s1[-1].Freq);

-      *s1 = tmp;

-    }

-  }

-  while (--i);

-  

-  if (s->Freq == 0)

-  {

-    unsigned numStats = p->MinContext->NumStats;

-    unsigned n0, n1;

-    do { i++; } while ((--s)->Freq == 0);

-    escFreq += i;

-    p->MinContext->NumStats = (UInt16)(p->MinContext->NumStats - i);

-    if (p->MinContext->NumStats == 1)

-    {

-      CPpmd_State tmp = *stats;

-      do

-      {

-        tmp.Freq = (Byte)(tmp.Freq - (tmp.Freq >> 1));

-        escFreq >>= 1;

-      }

-      while (escFreq > 1);

-      InsertNode(p, stats, U2I(((numStats + 1) >> 1)));

-      *(p->FoundState = ONE_STATE(p->MinContext)) = tmp;

-      return;

-    }

-    n0 = (numStats + 1) >> 1;

-    n1 = (p->MinContext->NumStats + 1) >> 1;

-    if (n0 != n1)

-      p->MinContext->Stats = STATS_REF(ShrinkUnits(p, stats, n0, n1));

-  }

-  p->MinContext->SummFreq = (UInt16)(sumFreq + escFreq - (escFreq >> 1));

-  p->FoundState = STATS(p->MinContext);

-}

-

-CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, UInt32 *escFreq)

-{

-  CPpmd_See *see;

-  unsigned nonMasked = p->MinContext->NumStats - numMasked;

-  if (p->MinContext->NumStats != 256)

-  {

-    see = p->See[(unsigned)p->NS2Indx[(size_t)nonMasked - 1]] +

-        (nonMasked < (unsigned)SUFFIX(p->MinContext)->NumStats - p->MinContext->NumStats) +

-        2 * (unsigned)(p->MinContext->SummFreq < 11 * p->MinContext->NumStats) +

-        4 * (unsigned)(numMasked > nonMasked) +

-        p->HiBitsFlag;

-    {

-      unsigned r = (see->Summ >> see->Shift);

-      see->Summ = (UInt16)(see->Summ - r);

-      *escFreq = r + (r == 0);

-    }

-  }

-  else

-  {

-    see = &p->DummySee;

-    *escFreq = 1;

-  }

-  return see;

-}

-

-static void NextContext(CPpmd7 *p)

-{

-  CTX_PTR c = CTX(SUCCESSOR(p->FoundState));

-  if (p->OrderFall == 0 && (Byte *)c > p->Text)

-    p->MinContext = p->MaxContext = c;

-  else

-    UpdateModel(p);

-}

-

-void Ppmd7_Update1(CPpmd7 *p)

-{

-  CPpmd_State *s = p->FoundState;

-  s->Freq += 4;

-  p->MinContext->SummFreq += 4;

-  if (s[0].Freq > s[-1].Freq)

-  {

-    SwapStates(&s[0], &s[-1]);

-    p->FoundState = --s;

-    if (s->Freq > MAX_FREQ)

-      Rescale(p);

-  }

-  NextContext(p);

-}

-

-void Ppmd7_Update1_0(CPpmd7 *p)

-{

-  p->PrevSuccess = (2 * p->FoundState->Freq > p->MinContext->SummFreq);

-  p->RunLength += p->PrevSuccess;

-  p->MinContext->SummFreq += 4;

-  if ((p->FoundState->Freq += 4) > MAX_FREQ)

-    Rescale(p);

-  NextContext(p);

-}

-

-void Ppmd7_UpdateBin(CPpmd7 *p)

-{

-  p->FoundState->Freq = (Byte)(p->FoundState->Freq + (p->FoundState->Freq < 128 ? 1: 0));

-  p->PrevSuccess = 1;

-  p->RunLength++;

-  NextContext(p);

-}

-

-void Ppmd7_Update2(CPpmd7 *p)

-{

-  p->MinContext->SummFreq += 4;

-  if ((p->FoundState->Freq += 4) > MAX_FREQ)

-    Rescale(p);

-  p->RunLength = p->InitRL;

-  UpdateModel(p);

-}

+/* Ppmd7.c -- PPMdH codec
+2023-04-02 : Igor Pavlov : Public domain
+This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */
+
+#include "Precomp.h"
+
+#include <string.h>
+
+#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; UInt32 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 */
+        unsigned oldNU = ns1 >> 1;
+        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)(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 = 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
+      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;
+  }
+  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;
+  unsigned summFreq = mc->Union2.SummFreq;
+  p->PrevSuccess = (2 * freq > summFreq);
+  p->RunLength += (int)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 cce93f1..d9eb326 100644
--- a/C/Ppmd7.h
+++ b/C/Ppmd7.h
@@ -1,142 +1,181 @@
-/* Ppmd7.h -- PPMdH compression codec

-2018-07-04 : Igor Pavlov : Public domain

-This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */

-

-/* This code supports virtual RangeDecoder and includes the implementation

-of RangeCoder from 7z, instead of RangeCoder from original PPMd var.H.

-If you need the compatibility with original PPMd var.H, you can use external RangeDecoder */

-

-#ifndef __PPMD7_H

-#define __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

-  #ifdef PPMD_32BIT

-    struct CPpmd7_Context_ *

-  #else

-    UInt32

-  #endif

-  CPpmd7_Context_Ref;

-

-typedef struct CPpmd7_Context_

-{

-  UInt16 NumStats;

-  UInt16 SummFreq;

-  CPpmd_State_Ref Stats;

-  CPpmd7_Context_Ref Suffix;

-} CPpmd7_Context;

-

-#define Ppmd7Context_OneState(p) ((CPpmd_State *)&(p)->SummFreq)

-

-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;

-  Byte *Base, *LoUnit, *HiUnit, *Text, *UnitsStart;

-  UInt32 AlignOffset;

-

-  Byte Indx2Units[PPMD_NUM_INDEXES];

-  Byte Units2Indx[128];

-  CPpmd_Void_Ref FreeList[PPMD_NUM_INDEXES];

-  Byte NS2Indx[256], NS2BSIndx[256], HB2Flag[256];

-  CPpmd_See DummySee, See[25][16];

-  UInt16 BinSumm[128][64];

-} 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 ---------- */

-

-extern const Byte PPMD7_kExpEscape[16];

-

-#ifdef PPMD_32BIT

-  #define Ppmd7_GetPtr(p, ptr) (ptr)

-  #define Ppmd7_GetContext(p, ptr) (ptr)

-  #define Ppmd7_GetStats(p, ctx) ((ctx)->Stats)

-#else

-  #define Ppmd7_GetPtr(p, offs) ((void *)((p)->Base + (offs)))

-  #define Ppmd7_GetContext(p, offs) ((CPpmd7_Context *)Ppmd7_GetPtr((p), (offs)))

-  #define Ppmd7_GetStats(p, ctx) ((CPpmd_State *)Ppmd7_GetPtr((p), ((ctx)->Stats)))

-#endif

-

-void Ppmd7_Update1(CPpmd7 *p);

-void Ppmd7_Update1_0(CPpmd7 *p);

-void Ppmd7_Update2(CPpmd7 *p);

-void Ppmd7_UpdateBin(CPpmd7 *p);

-

-#define Ppmd7_GetBinSumm(p) \

-    &p->BinSumm[(size_t)(unsigned)Ppmd7Context_OneState(p->MinContext)->Freq - 1][p->PrevSuccess + \

-    p->NS2BSIndx[(size_t)Ppmd7_GetContext(p, p->MinContext->Suffix)->NumStats - 1] + \

-    (p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol]) + \

-    2 * p->HB2Flag[(unsigned)Ppmd7Context_OneState(p->MinContext)->Symbol] + \

-    ((p->RunLength >> 26) & 0x20)]

-

-CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, UInt32 *scale);

-

-

-/* ---------- Decode ---------- */

-

-typedef struct IPpmd7_RangeDec IPpmd7_RangeDec;

-

-struct IPpmd7_RangeDec

-{

-  UInt32 (*GetThreshold)(const IPpmd7_RangeDec *p, UInt32 total);

-  void (*Decode)(const IPpmd7_RangeDec *p, UInt32 start, UInt32 size);

-  UInt32 (*DecodeBit)(const IPpmd7_RangeDec *p, UInt32 size0);

-};

-

-typedef struct

-{

-  IPpmd7_RangeDec vt;

-  UInt32 Range;

-  UInt32 Code;

-  IByteIn *Stream;

-} CPpmd7z_RangeDec;

-

-void Ppmd7z_RangeDec_CreateVTable(CPpmd7z_RangeDec *p);

-BoolInt Ppmd7z_RangeDec_Init(CPpmd7z_RangeDec *p);

-#define Ppmd7z_RangeDec_IsFinishedOK(p) ((p)->Code == 0)

-

-int Ppmd7_DecodeSymbol(CPpmd7 *p, const IPpmd7_RangeDec *rc);

-

-

-/* ---------- Encode ---------- */

-

-typedef struct

-{

-  UInt64 Low;

-  UInt32 Range;

-  Byte Cache;

-  UInt64 CacheSize;

-  IByteOut *Stream;

-} CPpmd7z_RangeEnc;

-

-void Ppmd7z_RangeEnc_Init(CPpmd7z_RangeEnc *p);

-void Ppmd7z_RangeEnc_FlushData(CPpmd7z_RangeEnc *p);

-

-void Ppmd7_EncodeSymbol(CPpmd7 *p, CPpmd7z_RangeEnc *rc, int symbol);

-

-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 2026407..8323828 100644
--- a/C/Ppmd7Dec.c
+++ b/C/Ppmd7Dec.c
@@ -1,191 +1,312 @@
-/* Ppmd7Dec.c -- PPMdH Decoder

-2018-07-04 : 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 (1 << 24)

-

-BoolInt Ppmd7z_RangeDec_Init(CPpmd7z_RangeDec *p)

-{

-  unsigned i;

-  p->Code = 0;

-  p->Range = 0xFFFFFFFF;

-  if (IByteIn_Read(p->Stream) != 0)

-    return False;

-  for (i = 0; i < 4; i++)

-    p->Code = (p->Code << 8) | IByteIn_Read(p->Stream);

-  return (p->Code < 0xFFFFFFFF);

-}

-

-#define GET_Ppmd7z_RangeDec CPpmd7z_RangeDec *p = CONTAINER_FROM_VTBL(pp, CPpmd7z_RangeDec, vt);

- 

-static UInt32 Range_GetThreshold(const IPpmd7_RangeDec *pp, UInt32 total)

-{

-  GET_Ppmd7z_RangeDec

-  return p->Code / (p->Range /= total);

-}

-

-static void Range_Normalize(CPpmd7z_RangeDec *p)

-{

-  if (p->Range < kTopValue)

-  {

-    p->Code = (p->Code << 8) | IByteIn_Read(p->Stream);

-    p->Range <<= 8;

-    if (p->Range < kTopValue)

-    {

-      p->Code = (p->Code << 8) | IByteIn_Read(p->Stream);

-      p->Range <<= 8;

-    }

-  }

-}

-

-static void Range_Decode(const IPpmd7_RangeDec *pp, UInt32 start, UInt32 size)

-{

-  GET_Ppmd7z_RangeDec

-  p->Code -= start * p->Range;

-  p->Range *= size;

-  Range_Normalize(p);

-}

-

-static UInt32 Range_DecodeBit(const IPpmd7_RangeDec *pp, UInt32 size0)

-{

-  GET_Ppmd7z_RangeDec

-  UInt32 newBound = (p->Range >> 14) * size0;

-  UInt32 symbol;

-  if (p->Code < newBound)

-  {

-    symbol = 0;

-    p->Range = newBound;

-  }

-  else

-  {

-    symbol = 1;

-    p->Code -= newBound;

-    p->Range -= newBound;

-  }

-  Range_Normalize(p);

-  return symbol;

-}

-

-void Ppmd7z_RangeDec_CreateVTable(CPpmd7z_RangeDec *p)

-{

-  p->vt.GetThreshold = Range_GetThreshold;

-  p->vt.Decode = Range_Decode;

-  p->vt.DecodeBit = Range_DecodeBit;

-}

-

-

-#define MASK(sym) ((signed char *)charMask)[sym]

-

-int Ppmd7_DecodeSymbol(CPpmd7 *p, const IPpmd7_RangeDec *rc)

-{

-  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;

-    if ((count = rc->GetThreshold(rc, p->MinContext->SummFreq)) < (hiCnt = s->Freq))

-    {

-      Byte symbol;

-      rc->Decode(rc, 0, s->Freq);

-      p->FoundState = s;

-      symbol = s->Symbol;

-      Ppmd7_Update1_0(p);

-      return symbol;

-    }

-    p->PrevSuccess = 0;

-    i = p->MinContext->NumStats - 1;

-    do

-    {

-      if ((hiCnt += (++s)->Freq) > count)

-      {

-        Byte symbol;

-        rc->Decode(rc, hiCnt - s->Freq, s->Freq);

-        p->FoundState = s;

-        symbol = s->Symbol;

-        Ppmd7_Update1(p);

-        return symbol;

-      }

-    }

-    while (--i);

-    if (count >= p->MinContext->SummFreq)

-      return -2;

-    p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol];

-    rc->Decode(rc, hiCnt, p->MinContext->SummFreq - hiCnt);

-    PPMD_SetAllBitsIn256Bytes(charMask);

-    MASK(s->Symbol) = 0;

-    i = p->MinContext->NumStats - 1;

-    do { MASK((--s)->Symbol) = 0; } while (--i);

-  }

-  else

-  {

-    UInt16 *prob = Ppmd7_GetBinSumm(p);

-    if (rc->DecodeBit(rc, *prob) == 0)

-    {

-      Byte symbol;

-      *prob = (UInt16)PPMD_UPDATE_PROB_0(*prob);

-      symbol = (p->FoundState = Ppmd7Context_OneState(p->MinContext))->Symbol;

-      Ppmd7_UpdateBin(p);

-      return symbol;

-    }

-    *prob = (UInt16)PPMD_UPDATE_PROB_1(*prob);

-    p->InitEsc = PPMD7_kExpEscape[*prob >> 10];

-    PPMD_SetAllBitsIn256Bytes(charMask);

-    MASK(Ppmd7Context_OneState(p->MinContext)->Symbol) = 0;

-    p->PrevSuccess = 0;

-  }

-  for (;;)

-  {

-    CPpmd_State *ps[256], *s;

-    UInt32 freqSum, count, hiCnt;

-    CPpmd_See *see;

-    unsigned i, num, numMasked = p->MinContext->NumStats;

-    do

-    {

-      p->OrderFall++;

-      if (!p->MinContext->Suffix)

-        return -1;

-      p->MinContext = Ppmd7_GetContext(p, p->MinContext->Suffix);

-    }

-    while (p->MinContext->NumStats == numMasked);

-    hiCnt = 0;

-    s = Ppmd7_GetStats(p, p->MinContext);

-    i = 0;

-    num = p->MinContext->NumStats - numMasked;

-    do

-    {

-      int k = (int)(MASK(s->Symbol));

-      hiCnt += (s->Freq & k);

-      ps[i] = s++;

-      i -= k;

-    }

-    while (i != num);

-    

-    see = Ppmd7_MakeEscFreq(p, numMasked, &freqSum);

-    freqSum += hiCnt;

-    count = rc->GetThreshold(rc, freqSum);

-    

-    if (count < hiCnt)

-    {

-      Byte symbol;

-      CPpmd_State **pps = ps;

-      for (hiCnt = 0; (hiCnt += (*pps)->Freq) <= count; pps++);

-      s = *pps;

-      rc->Decode(rc, hiCnt - s->Freq, s->Freq);

-      Ppmd_See_Update(see);

-      p->FoundState = s;

-      symbol = s->Symbol;

-      Ppmd7_Update2(p);

-      return symbol;

-    }

-    if (count >= freqSum)

-      return -2;

-    rc->Decode(rc, hiCnt, freqSum - hiCnt);

-    see->Summ = (UInt16)(see->Summ + freqSum);

-    do { MASK(ps[--i]->Symbol) = 0; } while (i != 0);

-  }

-}

+/* Ppmd7Dec.c -- Ppmd7z (PPMdH with 7z Range Coder) Decoder
+2023-04-02 : 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) ((unsigned char *)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
+      {
+        unsigned sym0 = s2[0].Symbol;
+        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 & (unsigned)(MASK(s->Symbol))) & (0 - (UInt32)num);
+      s += num;
+      p->MinContext = mc;
+
+      do
+      {
+        unsigned sym0 = s[0].Symbol;
+        unsigned sym1 = s[1].Symbol;
+        s += 2;
+        hiCnt += (s[-2].Freq & (unsigned)(MASK(sym0)));
+        hiCnt += (s[-1].Freq & (unsigned)(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 & (unsigned)(MASK(s->Symbol));
+      // if ((Int32)count >= 0)
+      {
+        for (;;)
+        {
+          count -= s->Freq & (unsigned)(MASK((s)->Symbol)); s++; if ((Int32)count < 0) break;
+          // count -= s->Freq & (unsigned)(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 a74d300..41106ba 100644
--- a/C/Ppmd7Enc.c
+++ b/C/Ppmd7Enc.c
@@ -1,187 +1,338 @@
-/* Ppmd7Enc.c -- PPMdH Encoder

-2017-04-03 : 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 (1 << 24)

-

-void Ppmd7z_RangeEnc_Init(CPpmd7z_RangeEnc *p)

-{

-  p->Low = 0;

-  p->Range = 0xFFFFFFFF;

-  p->Cache = 0;

-  p->CacheSize = 1;

-}

-

-static void RangeEnc_ShiftLow(CPpmd7z_RangeEnc *p)

-{

-  if ((UInt32)p->Low < (UInt32)0xFF000000 || (unsigned)(p->Low >> 32) != 0)

-  {

-    Byte temp = p->Cache;

-    do

-    {

-      IByteOut_Write(p->Stream, (Byte)(temp + (Byte)(p->Low >> 32)));

-      temp = 0xFF;

-    }

-    while (--p->CacheSize != 0);

-    p->Cache = (Byte)((UInt32)p->Low >> 24);

-  }

-  p->CacheSize++;

-  p->Low = (UInt32)p->Low << 8;

-}

-

-static void RangeEnc_Encode(CPpmd7z_RangeEnc *p, UInt32 start, UInt32 size, UInt32 total)

-{

-  p->Low += start * (p->Range /= total);

-  p->Range *= size;

-  while (p->Range < kTopValue)

-  {

-    p->Range <<= 8;

-    RangeEnc_ShiftLow(p);

-  }

-}

-

-static void RangeEnc_EncodeBit_0(CPpmd7z_RangeEnc *p, UInt32 size0)

-{

-  p->Range = (p->Range >> 14) * size0;

-  while (p->Range < kTopValue)

-  {

-    p->Range <<= 8;

-    RangeEnc_ShiftLow(p);

-  }

-}

-

-static void RangeEnc_EncodeBit_1(CPpmd7z_RangeEnc *p, UInt32 size0)

-{

-  UInt32 newBound = (p->Range >> 14) * size0;

-  p->Low += newBound;

-  p->Range -= newBound;

-  while (p->Range < kTopValue)

-  {

-    p->Range <<= 8;

-    RangeEnc_ShiftLow(p);

-  }

-}

-

-void Ppmd7z_RangeEnc_FlushData(CPpmd7z_RangeEnc *p)

-{

-  unsigned i;

-  for (i = 0; i < 5; i++)

-    RangeEnc_ShiftLow(p);

-}

-

-

-#define MASK(sym) ((signed char *)charMask)[sym]

-

-void Ppmd7_EncodeSymbol(CPpmd7 *p, CPpmd7z_RangeEnc *rc, 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;

-    if (s->Symbol == symbol)

-    {

-      RangeEnc_Encode(rc, 0, s->Freq, p->MinContext->SummFreq);

-      p->FoundState = s;

-      Ppmd7_Update1_0(p);

-      return;

-    }

-    p->PrevSuccess = 0;

-    sum = s->Freq;

-    i = p->MinContext->NumStats - 1;

-    do

-    {

-      if ((++s)->Symbol == symbol)

-      {

-        RangeEnc_Encode(rc, sum, s->Freq, p->MinContext->SummFreq);

-        p->FoundState = s;

-        Ppmd7_Update1(p);

-        return;

-      }

-      sum += s->Freq;

-    }

-    while (--i);

-    

-    p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol];

-    PPMD_SetAllBitsIn256Bytes(charMask);

-    MASK(s->Symbol) = 0;

-    i = p->MinContext->NumStats - 1;

-    do { MASK((--s)->Symbol) = 0; } while (--i);

-    RangeEnc_Encode(rc, sum, p->MinContext->SummFreq - sum, p->MinContext->SummFreq);

-  }

-  else

-  {

-    UInt16 *prob = Ppmd7_GetBinSumm(p);

-    CPpmd_State *s = Ppmd7Context_OneState(p->MinContext);

-    if (s->Symbol == symbol)

-    {

-      RangeEnc_EncodeBit_0(rc, *prob);

-      *prob = (UInt16)PPMD_UPDATE_PROB_0(*prob);

-      p->FoundState = s;

-      Ppmd7_UpdateBin(p);

-      return;

-    }

-    else

-    {

-      RangeEnc_EncodeBit_1(rc, *prob);

-      *prob = (UInt16)PPMD_UPDATE_PROB_1(*prob);

-      p->InitEsc = PPMD7_kExpEscape[*prob >> 10];

-      PPMD_SetAllBitsIn256Bytes(charMask);

-      MASK(s->Symbol) = 0;

-      p->PrevSuccess = 0;

-    }

-  }

-  for (;;)

-  {

-    UInt32 escFreq;

-    CPpmd_See *see;

-    CPpmd_State *s;

-    UInt32 sum;

-    unsigned i, numMasked = p->MinContext->NumStats;

-    do

-    {

-      p->OrderFall++;

-      if (!p->MinContext->Suffix)

-        return; /* EndMarker (symbol = -1) */

-      p->MinContext = Ppmd7_GetContext(p, p->MinContext->Suffix);

-    }

-    while (p->MinContext->NumStats == numMasked);

-    

-    see = Ppmd7_MakeEscFreq(p, numMasked, &escFreq);

-    s = Ppmd7_GetStats(p, p->MinContext);

-    sum = 0;

-    i = p->MinContext->NumStats;

-    do

-    {

-      int cur = s->Symbol;

-      if (cur == symbol)

-      {

-        UInt32 low = sum;

-        CPpmd_State *s1 = s;

-        do

-        {

-          sum += (s->Freq & (int)(MASK(s->Symbol)));

-          s++;

-        }

-        while (--i);

-        RangeEnc_Encode(rc, low, s1->Freq, sum + escFreq);

-        Ppmd_See_Update(see);

-        p->FoundState = s1;

-        Ppmd7_Update2(p);

-        return;

-      }

-      sum += (s->Freq & (int)(MASK(cur)));

-      MASK(cur) = 0;

-      s++;

-    }

-    while (--i);

-    

-    RangeEnc_Encode(rc, sum, escFreq, sum + escFreq);

-    see->Summ = (UInt16)(see->Summ + sum + escFreq);

-  }

-}

+/* Ppmd7Enc.c -- Ppmd7z (PPMdH with 7z Range Coder) Encoder
+2023-04-02 : 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) ((unsigned char *)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
+      {
+        unsigned sym0 = s2[0].Symbol;
+        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;
+          for (;;)
+          {
+            unsigned sym0 = s[0].Symbol;
+            unsigned sym1 = s[1].Symbol;
+            s += 2;
+            sum += (s[-2].Freq & (unsigned)(MASK(sym0)));
+            sum += (s[-1].Freq & (unsigned)(MASK(sym1)));
+            if (--num2 == 0)
+              break;
+          }
+        }
+
+        
+        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
new file mode 100644
index 0000000..55e164e
--- /dev/null
+++ b/C/Ppmd7aDec.c
@@ -0,0 +1,295 @@
+/* Ppmd7aDec.c -- PPMd7a (PPMdH) Decoder
+2023-04-02 : 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) ((unsigned char *)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
+      {
+        unsigned sym0 = s2[0].Symbol;
+        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 & (unsigned)(MASK(s->Symbol))) & (0 - (UInt32)num);
+      s += num;
+      p->MinContext = mc;
+
+      do
+      {
+        unsigned sym0 = s[0].Symbol;
+        unsigned sym1 = s[1].Symbol;
+        s += 2;
+        hiCnt += (s[-2].Freq & (unsigned)(MASK(sym0)));
+        hiCnt += (s[-1].Freq & (unsigned)(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 & (unsigned)(MASK(s->Symbol));
+      // if ((Int32)count >= 0)
+      {
+        for (;;)
+        {
+          count -= s->Freq & (unsigned)(MASK((s)->Symbol)); s++; if ((Int32)count < 0) break;
+          // count -= s->Freq & (unsigned)(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
new file mode 100644
index 0000000..28abf27
--- /dev/null
+++ b/C/Ppmd8.c
@@ -0,0 +1,1565 @@
+/* Ppmd8.c -- PPMdI codec
+2023-04-02 : Igor Pavlov : Public domain
+This code is based on PPMd var.I (2002): Dmitry Shkarin : Public domain */
+
+#include "Precomp.h"
+
+#include <string.h>
+
+#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; UInt32 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 */
+        unsigned oldNU = (ns1 + 1) >> 1;
+        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 += (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 = 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
+      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;
+  }
+  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;
+  unsigned summFreq = mc->Union2.SummFreq;
+  p->PrevSuccess = (2 * freq >= summFreq); // Ppmd8 (>=)
+  p->RunLength += (int)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
new file mode 100644
index 0000000..d5bb57e
--- /dev/null
+++ b/C/Ppmd8.h
@@ -0,0 +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
diff --git a/C/Ppmd8Dec.c b/C/Ppmd8Dec.c
new file mode 100644
index 0000000..72d3626
--- /dev/null
+++ b/C/Ppmd8Dec.c
@@ -0,0 +1,295 @@
+/* Ppmd8Dec.c -- Ppmd8 (PPMdI) Decoder
+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 */
+
+#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) ((unsigned char *)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
+      {
+        unsigned sym0 = s2[0].Symbol;
+        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 & (unsigned)(MASK(s->Symbol))) & (0 - (UInt32)num);
+      s += num;
+      p->MinContext = mc;
+
+      do
+      {
+        unsigned sym0 = s[0].Symbol;
+        unsigned sym1 = s[1].Symbol;
+        s += 2;
+        hiCnt += (s[-2].Freq & (unsigned)(MASK(sym0)));
+        hiCnt += (s[-1].Freq & (unsigned)(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 & (unsigned)(MASK((s)->Symbol)); s++; if ((Int32)count < 0) break;
+          // count -= s->Freq & (unsigned)(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
new file mode 100644
index 0000000..9e29ef7
--- /dev/null
+++ b/C/Ppmd8Enc.c
@@ -0,0 +1,338 @@
+/* Ppmd8Enc.c -- Ppmd8 (PPMdI) Encoder
+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 */
+
+#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) ((unsigned char *)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
+      {
+        unsigned sym0 = s2[0].Symbol;
+        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;
+          for (;;)
+          {
+            unsigned sym0 = s[0].Symbol;
+            unsigned sym1 = s[1].Symbol;
+            s += 2;
+            sum += (s[-2].Freq & (unsigned)(MASK(sym0)));
+            sum += (s[-1].Freq & (unsigned)(MASK(sym1)));
+            if (--num2 == 0)
+              break;
+          }
+        }
+
+        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 edb5814..69afb2f 100644
--- a/C/Precomp.h
+++ b/C/Precomp.h
@@ -1,10 +1,10 @@
-/* Precomp.h -- StdAfx

-2013-11-12 : Igor Pavlov : Public domain */

-

-#ifndef __7Z_PRECOMP_H

-#define __7Z_PRECOMP_H

-

-#include "Compiler.h"

-/* #include "7zTypes.h" */

-

-#endif

+/* Precomp.h -- StdAfx
+2023-04-02 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_PRECOMP_H
+#define ZIP7_INC_PRECOMP_H
+
+#include "Compiler.h"
+/* #include "7zTypes.h" */
+
+#endif
diff --git a/C/RotateDefs.h b/C/RotateDefs.h
index 6c790e7..c16b4f8 100644
--- a/C/RotateDefs.h
+++ b/C/RotateDefs.h
@@ -1,30 +1,50 @@
-/* RotateDefs.h -- Rotate functions

-2015-03-25 : Igor Pavlov : Public domain */

-

-#ifndef __ROTATE_DEFS_H

-#define __ROTATE_DEFS_H

-

-#ifdef _MSC_VER

-

-#include <stdlib.h>

-

-/* don't use _rotl with 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))

-

-#else

-

-/* new compilers can translate these macros to fast commands. */

-

-#define rotlFixed(x, n) (((x) << (n)) | ((x) >> (32 - (n))))

-#define rotrFixed(x, n) (((x) >> (n)) | ((x) << (32 - (n))))

-

-#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 <stdlib.h>
+
+/* 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
new file mode 100644
index 0000000..fd6c018
--- /dev/null
+++ b/C/Sha1.c
@@ -0,0 +1,498 @@
+/* Sha1.c -- SHA-1 Hash
+2023-04-02 : 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 <string.h>
+
+#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
+  #ifdef _MSC_VER
+    #if _MSC_VER >= 1200
+      #define Z7_COMPILER_SHA1_SUPPORTED
+    #endif
+  #elif defined(__clang__)
+    #if (__clang_major__ >= 8) // fix that check
+      #define Z7_COMPILER_SHA1_SUPPORTED
+    #endif
+  #elif defined(__GNUC__)
+    #if (__GNUC__ >= 8) // fix that check
+      #define Z7_COMPILER_SHA1_SUPPORTED
+    #endif
+  #elif defined(__INTEL_COMPILER)
+    #if (__INTEL_COMPILER >= 1800) // fix that check
+      #define Z7_COMPILER_SHA1_SUPPORTED
+    #endif
+  #endif
+#elif defined(MY_CPU_ARM_OR_ARM64)
+  #ifdef _MSC_VER
+    #if _MSC_VER >= 1910 && _MSC_VER >= 1929 && _MSC_FULL_VER >= 192930037
+      #define Z7_COMPILER_SHA1_SUPPORTED
+    #endif
+  #elif defined(__clang__)
+    #if (__clang_major__ >= 8) // fix that check
+      #define Z7_COMPILER_SHA1_SUPPORTED
+    #endif
+  #elif defined(__GNUC__)
+    #if (__GNUC__ >= 6) // fix that check
+      #define Z7_COMPILER_SHA1_SUPPORTED
+    #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 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
diff --git a/C/Sha1.h b/C/Sha1.h
new file mode 100644
index 0000000..fecd9d3
--- /dev/null
+++ b/C/Sha1.h
@@ -0,0 +1,76 @@
+/* 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
diff --git a/C/Sha1Opt.c b/C/Sha1Opt.c
new file mode 100644
index 0000000..27796aa
--- /dev/null
+++ b/C/Sha1Opt.c
@@ -0,0 +1,386 @@
+/* Sha1Opt.c -- SHA-1 optimized code for SHA-1 hardware instructions
+2023-04-02 : 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
+
+#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
+    #endif
+  #endif
+// #endif // MY_CPU_X86_OR_AMD64
+
+#ifdef USE_HW_SHA
+
+// #pragma message("Sha1 HW")
+
+// sse/sse2/ssse3:
+#include <tmmintrin.h>
+// sha*:
+#include <immintrin.h>
+
+#if defined (__clang__) && defined(_MSC_VER)
+  // #if !defined(__SSSE3__)
+  // #endif
+  #if !defined(__SHA__)
+    #include <shaintrin.h>
+  #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)
+
+  #if defined(__clang__)
+    #if (__clang_major__ >= 8) // fix that check
+      #define USE_HW_SHA
+    #endif
+  #elif defined(__GNUC__)
+    #if (__GNUC__ >= 6) // fix that check
+      #define USE_HW_SHA
+    #endif
+  #elif defined(_MSC_VER)
+    #if _MSC_VER >= 1910
+      #define USE_HW_SHA
+    #endif
+  #endif
+
+#ifdef USE_HW_SHA
+
+// #pragma message("=== Sha1 HW === ")
+
+#if defined(__clang__) || defined(__GNUC__)
+  #ifdef MY_CPU_ARM64
+    #define ATTRIB_SHA __attribute__((__target__("+crypto")))
+  #else
+    #define ATTRIB_SHA __attribute__((__target__("fpu=crypto-neon-fp-armv8")))
+  #endif
+#else
+  // _MSC_VER
+  // for arm32
+  #define _ARM_USE_NEW_NEON_INTRINSICS
+#endif
+
+#if defined(_MSC_VER) && defined(MY_CPU_ARM64)
+#include <arm64_neon.h>
+#else
+#include <arm_neon.h>
+#endif
+
+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); \
+
+#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
+
+
+#ifndef USE_HW_SHA
+
+// #error Stop_Compiling_UNSUPPORTED_SHA
+// #include <stdlib.h>
+
+// #include "Sha1.h"
+void Z7_FASTCALL Sha1_UpdateBlocks(UInt32 state[5], const Byte *data, size_t numBlocks);
+
+#pragma message("Sha1   HW-SW stub was used")
+
+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
diff --git a/C/Sha256.c b/C/Sha256.c
index 90994e5..018cf6f 100644
--- a/C/Sha256.c
+++ b/C/Sha256.c
@@ -1,248 +1,516 @@
-/* Crypto/Sha256.c -- SHA-256 Hash

-2017-04-03 : Igor Pavlov : Public domain

-This code is based on public domain code from Wei Dai's Crypto++ library. */

-

-#include "Precomp.h"

-

-#include <string.h>

-

-#include "CpuArch.h"

-#include "RotateDefs.h"

-#include "Sha256.h"

-

-/* define it for speed optimization */

-#ifndef _SFX

-#define _SHA256_UNROLL

-#define _SHA256_UNROLL2

-#endif

-

-/* #define _SHA256_UNROLL2 */

-

-void Sha256_Init(CSha256 *p)

-{

-  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;

-  p->count = 0;

-}

-

-#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 blk0(i) (W[i])

-#define blk2(i) (W[i] += s1(W[((i)-2)&15]) + W[((i)-7)&15] + s0(W[((i)-15)&15]))

-

-#define Ch(x,y,z) (z^(x&(y^z)))

-#define Maj(x,y,z) ((x&y)|(z&(x|y)))

-

-#ifdef _SHA256_UNROLL2

-

-#define R(a,b,c,d,e,f,g,h, i) \

-    h += S1(e) + Ch(e,f,g) + K[(i)+(size_t)(j)] + (j ? blk2(i) : blk0(i)); \

-    d += h; \

-    h += S0(a) + Maj(a, b, c)

-

-#define RX_8(i) \

-  R(a,b,c,d,e,f,g,h, i); \

-  R(h,a,b,c,d,e,f,g, i+1); \

-  R(g,h,a,b,c,d,e,f, i+2); \

-  R(f,g,h,a,b,c,d,e, i+3); \

-  R(e,f,g,h,a,b,c,d, i+4); \

-  R(d,e,f,g,h,a,b,c, i+5); \

-  R(c,d,e,f,g,h,a,b, i+6); \

-  R(b,c,d,e,f,g,h,a, i+7)

-

-#define RX_16  RX_8(0); RX_8(8);

-

-#else

-

-#define a(i) T[(0-(i))&7]

-#define b(i) T[(1-(i))&7]

-#define c(i) T[(2-(i))&7]

-#define d(i) T[(3-(i))&7]

-#define e(i) T[(4-(i))&7]

-#define f(i) T[(5-(i))&7]

-#define g(i) T[(6-(i))&7]

-#define h(i) T[(7-(i))&7]

-

-#define R(i) \

-    h(i) += S1(e(i)) + Ch(e(i),f(i),g(i)) + K[(i)+(size_t)(j)] + (j ? blk2(i) : blk0(i)); \

-    d(i) += h(i); \

-    h(i) += S0(a(i)) + Maj(a(i), b(i), c(i)) \

-

-#ifdef _SHA256_UNROLL

-

-#define RX_8(i)  R(i+0); R(i+1); R(i+2); R(i+3); R(i+4); R(i+5); R(i+6); R(i+7);

-#define RX_16  RX_8(0); RX_8(8);

-

-#else

-

-#define RX_16  unsigned i; for (i = 0; i < 16; i++) { R(i); }

-

-#endif

-

-#endif

-

-static const UInt32 K[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

-};

-

-static void Sha256_WriteByteBlock(CSha256 *p)

-{

-  UInt32 W[16];

-  unsigned j;

-  UInt32 *state;

-

-  #ifdef _SHA256_UNROLL2

-  UInt32 a,b,c,d,e,f,g,h;

-  #else

-  UInt32 T[8];

-  #endif

-

-  for (j = 0; j < 16; j += 4)

-  {

-    const Byte *ccc = p->buffer + j * 4;

-    W[j    ] = GetBe32(ccc);

-    W[j + 1] = GetBe32(ccc + 4);

-    W[j + 2] = GetBe32(ccc + 8);

-    W[j + 3] = GetBe32(ccc + 12);

-  }

-

-  state = p->state;

-

-  #ifdef _SHA256_UNROLL2

-  a = state[0];

-  b = state[1];

-  c = state[2];

-  d = state[3];

-  e = state[4];

-  f = state[5];

-  g = state[6];

-  h = state[7];

-  #else

-  for (j = 0; j < 8; j++)

-    T[j] = state[j];

-  #endif

-

-  for (j = 0; j < 64; j += 16)

-  {

-    RX_16

-  }

-

-  #ifdef _SHA256_UNROLL2

-  state[0] += a;

-  state[1] += b;

-  state[2] += c;

-  state[3] += d;

-  state[4] += e;

-  state[5] += f;

-  state[6] += g;

-  state[7] += h;

-  #else

-  for (j = 0; j < 8; j++)

-    state[j] += T[j];

-  #endif

-  

-  /* Wipe variables */

-  /* memset(W, 0, sizeof(W)); */

-  /* memset(T, 0, sizeof(T)); */

-}

-

-#undef S0

-#undef S1

-#undef s0

-#undef s1

-

-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;

-    }

-    

-    size -= num;

-    memcpy(p->buffer + pos, data, num);

-    data += num;

-  }

-

-  for (;;)

-  {

-    Sha256_WriteByteBlock(p);

-    if (size < 64)

-      break;

-    size -= 64;

-    memcpy(p->buffer, data, 64);

-    data += 64;

-  }

-

-  if (size != 0)

-    memcpy(p->buffer, data, size);

-}

-

-void Sha256_Final(CSha256 *p, Byte *digest)

-{

-  unsigned pos = (unsigned)p->count & 0x3F;

-  unsigned i;

-  

-  p->buffer[pos++] = 0x80;

-  

-  while (pos != (64 - 8))

-  {

-    pos &= 0x3F;

-    if (pos == 0)

-      Sha256_WriteByteBlock(p);

-    p->buffer[pos++] = 0;

-  }

-

-  {

-    UInt64 numBits = (p->count << 3);

-    SetBe32(p->buffer + 64 - 8, (UInt32)(numBits >> 32));

-    SetBe32(p->buffer + 64 - 4, (UInt32)(numBits));

-  }

-  

-  Sha256_WriteByteBlock(p);

-

-  for (i = 0; i < 8; i += 2)

-  {

-    UInt32 v0 = p->state[i];

-    UInt32 v1 = p->state[i + 1];

-    SetBe32(digest    , v0);

-    SetBe32(digest + 4, v1);

-    digest += 8;

-  }

-  

-  Sha256_Init(p);

-}

+/* Sha256.c -- SHA-256 Hash
+2023-04-02 : Igor Pavlov : Public domain
+This code is based on public domain code from Wei Dai's Crypto++ library. */
+
+#include "Precomp.h"
+
+#include <string.h>
+
+#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
+  #ifdef _MSC_VER
+    #if _MSC_VER >= 1200
+      #define Z7_COMPILER_SHA256_SUPPORTED
+    #endif
+  #elif defined(__clang__)
+    #if (__clang_major__ >= 8) // fix that check
+      #define Z7_COMPILER_SHA256_SUPPORTED
+    #endif
+  #elif defined(__GNUC__)
+    #if (__GNUC__ >= 8) // fix that check
+      #define Z7_COMPILER_SHA256_SUPPORTED
+    #endif
+  #elif defined(__INTEL_COMPILER)
+    #if (__INTEL_COMPILER >= 1800) // fix that check
+      #define Z7_COMPILER_SHA256_SUPPORTED
+    #endif
+  #endif
+#elif defined(MY_CPU_ARM_OR_ARM64)
+  #ifdef _MSC_VER
+    #if _MSC_VER >= 1910
+      #define Z7_COMPILER_SHA256_SUPPORTED
+    #endif
+  #elif defined(__clang__)
+    #if (__clang_major__ >= 8) // fix that check
+      #define Z7_COMPILER_SHA256_SUPPORTED
+    #endif
+  #elif defined(__GNUC__)
+    #if (__GNUC__ >= 6) // fix that check
+      #define Z7_COMPILER_SHA256_SUPPORTED
+    #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
+
+void Z7_FASTCALL Sha256_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks);
+
+// 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
diff --git a/C/Sha256.h b/C/Sha256.h
index 7f17ccf..9e04223 100644
--- a/C/Sha256.h
+++ b/C/Sha256.h
@@ -1,26 +1,76 @@
-/* Sha256.h -- SHA-256 Hash

-2013-01-18 : Igor Pavlov : Public domain */

-

-#ifndef __CRYPTO_SHA256_H

-#define __CRYPTO_SHA256_H

-

-#include "7zTypes.h"

-

-EXTERN_C_BEGIN

-

-#define SHA256_DIGEST_SIZE 32

-

-typedef struct

-{

-  UInt32 state[8];

-  UInt64 count;

-  Byte buffer[64];

-} CSha256;

-

-void Sha256_Init(CSha256 *p);

-void Sha256_Update(CSha256 *p, const Byte *data, size_t size);

-void Sha256_Final(CSha256 *p, Byte *digest);

-

-EXTERN_C_END

-

-#endif

+/* 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
diff --git a/C/Sha256Opt.c b/C/Sha256Opt.c
new file mode 100644
index 0000000..e4465e3
--- /dev/null
+++ b/C/Sha256Opt.c
@@ -0,0 +1,386 @@
+/* Sha256Opt.c -- SHA-256 optimized code for SHA-256 hardware instructions
+2023-04-02 : 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
+
+#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
+    #endif
+  #endif
+// #endif // MY_CPU_X86_OR_AMD64
+
+#ifdef USE_HW_SHA
+
+// #pragma message("Sha256 HW")
+
+// sse/sse2/ssse3:
+#include <tmmintrin.h>
+// sha*:
+#include <immintrin.h>
+
+#if defined (__clang__) && defined(_MSC_VER)
+  // #if !defined(__SSSE3__)
+  // #endif
+  #if !defined(__SHA__)
+    #include <shaintrin.h>
+  #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)
+
+  #if defined(__clang__)
+    #if (__clang_major__ >= 8) // fix that check
+      #define USE_HW_SHA
+    #endif
+  #elif defined(__GNUC__)
+    #if (__GNUC__ >= 6) // fix that check
+      #define USE_HW_SHA
+    #endif
+  #elif defined(_MSC_VER)
+    #if _MSC_VER >= 1910
+      #define USE_HW_SHA
+    #endif
+  #endif
+
+#ifdef USE_HW_SHA
+
+// #pragma message("=== Sha256 HW === ")
+
+#if defined(__clang__) || defined(__GNUC__)
+  #ifdef MY_CPU_ARM64
+    #define ATTRIB_SHA __attribute__((__target__("+crypto")))
+  #else
+    #define ATTRIB_SHA __attribute__((__target__("fpu=crypto-neon-fp-armv8")))
+  #endif
+#else
+  // _MSC_VER
+  // for arm32
+  #define _ARM_USE_NEW_NEON_INTRINSICS
+#endif
+
+#if defined(_MSC_VER) && defined(MY_CPU_ARM64)
+#include <arm64_neon.h>
+#else
+#include <arm_neon.h>
+#endif
+
+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
+
+
+#ifndef USE_HW_SHA
+
+// #error Stop_Compiling_UNSUPPORTED_SHA
+// #include <stdlib.h>
+
+// #include "Sha256.h"
+void Z7_FASTCALL Sha256_UpdateBlocks(UInt32 state[8], const Byte *data, size_t numBlocks);
+
+#pragma message("Sha256 HW-SW stub was used")
+
+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
diff --git a/C/Sort.c b/C/Sort.c
index 73dcbf0..e1097e3 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 7209d78..1817b65 100644
--- a/C/Sort.h
+++ b/C/Sort.h
@@ -1,18 +1,18 @@
-/* Sort.h -- Sort functions

-2014-04-05 : Igor Pavlov : Public domain */

-

-#ifndef __7Z_SORT_H

-#define __7Z_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
new file mode 100644
index 0000000..7901bba
--- /dev/null
+++ b/C/SwapBytes.c
@@ -0,0 +1,800 @@
+/* SwapBytes.c -- Byte Swap conversion filter
+2023-04-07 : 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
+/*
+ <mmintrin.h> MMX
+<xmmintrin.h> SSE
+<emmintrin.h> SSE2
+<pmmintrin.h> SSE3
+<tmmintrin.h> SSSE3
+<smmintrin.h> SSE4.1
+<nmmintrin.h> SSE4.2
+<ammintrin.h> SSE4A
+<wmmintrin.h> AES
+<immintrin.h> AVX, AVX2, FMA
+*/
+
+#include <emmintrin.h> // 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 <tmmintrin.h> // 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 <immintrin.h> // avx, avx2
+#if defined(__clang__)
+#include <avxintrin.h>
+#include <avx2intrin.h>
+#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);
+  /*
+  #define MY_mm256_set_m128i(hi, lo)  _mm256_insertf128_si256(_mm256_castsi128_si256(lo), (hi), 1)
+  MY_mm256_set_m128i
+  */
+      _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(__ARM_ARCH) && (__ARM_ARCH >= 7))
+// #elif defined(MY_CPU_ARM64)
+
+  #if defined(__clang__) && (__clang_major__ >= 8) \
+    || defined(__GNUC__) && (__GNUC__ >= 8)
+    #if (defined(__ARM_ARCH) && (__ARM_ARCH >= 7)) \
+        || defined(MY_CPU_ARM64)
+      #define USE_SWAP_128
+    #endif
+    #ifdef MY_CPU_ARM64
+      // #define SWAP_ATTRIB_NEON __attribute__((__target__("")))
+    #else
+      // #define SWAP_ATTRIB_NEON __attribute__((__target__("fpu=crypto-neon-fp-armv8")))
+    #endif
+  #elif defined(_MSC_VER)
+    #if (_MSC_VER >= 1910)
+      #define USE_SWAP_128
+    #endif
+  #endif
+
+  #if defined(_MSC_VER) && defined(MY_CPU_ARM64)
+    #include <arm64_neon.h>
+  #else
+    #include <arm_neon.h>
+  #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 <intrin.h>
+    #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
+
+
+#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 <stdio.h>
+#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
new file mode 100644
index 0000000..d442467
--- /dev/null
+++ b/C/SwapBytes.h
@@ -0,0 +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
diff --git a/C/Threads.c b/C/Threads.c
index 8fd86f2..cf52bd3 100644
--- a/C/Threads.c
+++ b/C/Threads.c
@@ -1,95 +1,562 @@
-/* Threads.c -- multithreading library

-2017-06-26 : Igor Pavlov : Public domain */

-

-#include "Precomp.h"

-

-#ifndef UNDER_CE

-#include <process.h>

-#endif

-

-#include "Threads.h"

-

-static WRes GetError()

-{

-  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) { return (WRes)WaitForSingleObject(h, INFINITE); }

-

-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 UNDER_CE

-  

-  DWORD threadId;

-  *p = CreateThread(0, 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);

-}

-

-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)

-{

-  *p = CreateSemaphore(NULL, (LONG)initCount, (LONG)maxCount, NULL);

-  return HandleToWRes(*p);

-}

-

-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 only STATUS_NO_MEMORY exception */

-  #ifdef _MSC_VER

-  __try

-  #endif

-  {

-    InitializeCriticalSection(p);

-    /* InitializeCriticalSectionAndSpinCount(p, 0); */

-  }

-  #ifdef _MSC_VER

-  __except (EXCEPTION_EXECUTE_HANDLER) { return 1; }

-  #endif

-  return 0;

-}

+/* Threads.c -- multithreading library
+2023-03-04 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#ifdef _WIN32
+
+#ifndef USE_THREADS_CreateThread
+#include <process.h>
+#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 ----------
+
+#ifndef __APPLE__
+#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)
+  #if defined(__clang__) && (__clang_major__ >= 4) && (__clang_major__ <= 12)
+    #pragma GCC diagnostic ignored "-Wreserved-id-macro"
+  #endif
+#define _GNU_SOURCE
+#endif // !defined(_GNU_SOURCE)
+#endif // Z7_AFFINITY_DISABLE
+#endif // __APPLE__
+
+#include "Threads.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef Z7_AFFINITY_SUPPORTED
+// #include <sched.h>
+#endif
+
+
+// #include <stdio.h>
+// #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)
+    {
+      #ifdef Z7_AFFINITY_SUPPORTED
+      
+      /*
+      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); }
+
+
+WRes Event_Set(CEvent *p)
+{
+  RINOK(pthread_mutex_lock(&p->_mutex))
+  p->_state = True;
+  int res1 = pthread_cond_broadcast(&p->_cond);
+  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;
+  {
+    int res1 = pthread_mutex_destroy(&p->_mutex);
+    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;
+  {
+    int res1 = pthread_mutex_destroy(&p->_mutex);
+    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
+}
+
+#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 f913241..4028464 100644
--- a/C/Threads.h
+++ b/C/Threads.h
@@ -1,68 +1,240 @@
-/* Threads.h -- multithreading library

-2017-06-18 : Igor Pavlov : Public domain */

-

-#ifndef __7Z_THREADS_H

-#define __7Z_THREADS_H

-

-#ifdef _WIN32

-#include <windows.h>

-#endif

-

-#include "7zTypes.h"

-

-EXTERN_C_BEGIN

-

-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))

-

-typedef

-#ifdef UNDER_CE

-  DWORD

-#else

-  unsigned

-#endif

-  THREAD_FUNC_RET_TYPE;

-

-#define THREAD_FUNC_CALL_TYPE MY_STD_CALL

-#define THREAD_FUNC_DECL 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);

-

-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_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)

-

-EXTERN_C_END

-

-#endif

+/* Threads.h -- multithreading library
+2023-04-02 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_THREADS_H
+#define ZIP7_INC_THREADS_H
+
+#ifdef _WIN32
+#include "7zWindows.h"
+
+#else
+
+#if defined(__linux__)
+#if !defined(__APPLE__) && !defined(_AIX) && !defined(__ANDROID__)
+#ifndef Z7_AFFINITY_DISABLE
+#define Z7_AFFINITY_SUPPORTED
+// #pragma message(" ==== Z7_AFFINITY_SUPPORTED")
+// #define _GNU_SOURCE
+#endif
+#endif
+#endif
+
+#include <pthread.h>
+
+#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 _CEvent
+{
+  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 _CSemaphore
+{
+  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 _CCriticalSection
+{
+  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);
+
+#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 d3bf0fe..11e1b03 100644
--- a/C/Util/7z/7z.dsp
+++ b/C/Util/7z/7z.dsp
@@ -1,241 +1,245 @@
-# 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" /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" /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=..\..\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

-# 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" /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" /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
+# 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 23089fb..848d13c 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 1c02b48..547920a 100644
--- a/C/Util/7z/7zMain.c
+++ b/C/Util/7z/7zMain.c
@@ -1,686 +1,888 @@
-/* 7zMain.c - Test application for 7z Decoder

-2019-02-02 : Igor Pavlov : Public domain */

-

-#include "Precomp.h"

-

-#include <stdio.h>

-#include <string.h>

-

-#include "../../CpuArch.h"

-

-#include "../../7z.h"

-#include "../../7zAlloc.h"

-#include "../../7zBuf.h"

-#include "../../7zCrc.h"

-#include "../../7zFile.h"

-#include "../../7zVersion.h"

-

-#ifndef USE_WINDOWS_FILE

-/* for mkdir */

-#ifdef _WIN32

-#include <direct.h>

-#else

-#include <sys/stat.h>

-#include <errno.h>

-#endif

-#endif

-

-

-#define kInputBufSize ((size_t)1 << 18)

-

-static const ISzAlloc g_Alloc = { SzAlloc, SzFree };

-

-

-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 _USE_UTF8

-#endif

-

-/* #define _USE_UTF8 */

-

-#ifdef _USE_UTF8

-

-#define _UTF8_START(n) (0x100 - (1 << (7 - (n))))

-

-#define _UTF8_RANGE(n) (((UInt32)1) << ((n) * 5 + 6))

-

-#define _UTF8_HEAD(n, val) ((Byte)(_UTF8_START(n) + (val >> (6 * (n)))))

-#define _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 < _UTF8_RANGE(1))

-    {

-      size++;

-      continue;

-    }

-

-    if (val >= 0xD800 && val < 0xDC00 && src != srcLim)

-    {

-      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++ = (char)val;

-      continue;

-    }

-

-    if (val < _UTF8_RANGE(1))

-    {

-      dest[0] = _UTF8_HEAD(1, val);

-      dest[1] = _UTF8_CHAR(0, val);

-      dest += 2;

-      continue;

-    }

-

-    if (val >= 0xD800 && val < 0xDC00 && src != srcLim)

-    {

-      UInt32 c2 = *src;

-      if (c2 >= 0xDC00 && c2 < 0xE000)

-      {

-        src++;

-        val = (((val - 0xD800) << 10) | (c2 - 0xDC00)) + 0x10000;

-        dest[0] = _UTF8_HEAD(3, val);

-        dest[1] = _UTF8_CHAR(2, val);

-        dest[2] = _UTF8_CHAR(1, val);

-        dest[3] = _UTF8_CHAR(0, val);

-        dest += 4;

-        continue;

-      }

-    }

-    

-    dest[0] = _UTF8_HEAD(2, val);

-    dest[1] = _UTF8_CHAR(1, val);

-    dest[2] = _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 _USE_UTF8

-    , UINT codePage

-    #endif

-    )

-{

-  unsigned len = 0;

-  for (len = 0; s[len] != 0; len++);

-

-  #ifndef _USE_UTF8

-  {

-    unsigned size = len * 3 + 100;

-    if (!Buf_EnsureSize(buf, size))

-      return SZ_ERROR_MEM;

-    {

-      buf->data[0] = 0;

-      if (len != 0)

-      {

-        char defaultChar = '_';

-        BOOL defUsed;

-        unsigned numChars = 0;

-        numChars = WideCharToMultiByte(codePage, 0, (LPCWSTR)s, len, (char *)buf->data, 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;

-  #endif

-  #define MY_FILE_CODE_PAGE_PARAM ,g_FileCodePage

-#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 _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)

-

-static void ConvertFileTimeToString(const CNtfsFileTime *nt, char *s)

-{

-  unsigned year, mon, hour, min, sec;

-  Byte ms[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

-  unsigned t;

-  UInt32 v;

-  UInt64 v64 = nt->Low | ((UInt64)nt->High << 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++)

-  {

-    unsigned 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()

-{

-  Print("\n");

-}

-

-static void PrintError(char *s)

-{

-  Print("\nERROR: ");

-  Print(s);

-  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 MY_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 <command> <archive_name>\n\n"

-      "<Commands>\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;

-

-  #ifdef UNDER_CE

-  if (InFile_OpenW(&archiveStream.file, L"\test.7z"))

-  #else

-  if (InFile_Open(&archiveStream.file, args[2]))

-  #endif

-  {

-    PrintError("can not open input file");

-    return 1;

-  }

-

-  FileInStream_CreateVTable(&archiveStream);

-  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;

-        unsigned 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 ?

-            "Testing    ":

-            "Extracting ");

-        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 if (OutFile_OpenUtf16(&outFile, destPath))

-          {

-            PrintError("can not open output file");

-            res = SZ_ERROR_FAIL;

-            break;

-          }

-

-          processedSize = outSizeProcessed;

-          

-          if (File_Write(&outFile, outBuffer + offset, &processedSize) != 0 || processedSize != outSizeProcessed)

-          {

-            PrintError("can not write output file");

-            res = SZ_ERROR_FAIL;

-            break;

-          }

-

-          #ifdef USE_WINDOWS_FILE

-          {

-            FILETIME mtime, ctime;

-            FILETIME *mtimePtr = NULL;

-            FILETIME *ctimePtr = NULL;

-

-            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;

-            }

-            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

-          

-          if (File_Close(&outFile))

-          {

-            PrintError("can not close output file");

-            res = SZ_ERROR_FAIL;

-            break;

-          }

-          

-          #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("can not allocate memory");

-  else if (res == SZ_ERROR_CRC)

-    PrintError("CRC error");

-  else

-  {

-    char s[32];

-    UInt64ToStr(res, s, 0);

-    PrintError(s);

-  }

-  

-  return 1;

-}

+/* 7zMain.c - Test application for 7z Decoder
+2023-04-04 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include "../../CpuArch.h"
+
+#include "../../7z.h"
+#include "../../7zAlloc.h"
+#include "../../7zBuf.h"
+#include "../../7zCrc.h"
+#include "../../7zFile.h"
+#include "../../7zVersion.h"
+
+#ifndef USE_WINDOWS_FILE
+/* for mkdir */
+#ifdef _WIN32
+#include <direct.h>
+#else
+#include <stdlib.h>
+#include <time.h>
+#ifdef __GNUC__
+#include <sys/time.h>
+#endif
+#include <fcntl.h>
+// #include <utime.h>
+#include <sys/stat.h>
+#include <errno.h>
+#endif
+#endif
+
+#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
+    )
+{
+  unsigned len = 0;
+  for (len = 0; s[len] != 0; len++) {}
+
+  #ifndef MY_USE_UTF8
+  {
+    const unsigned 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 _FILETIME
+{
+  DWORD dwLowDateTime;
+  DWORD dwHighDateTime;
+} FILETIME;
+
+static LONG TIME_GetBias()
+{
+  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 */
+  const LONG bias = (int)(mktime(ptm) - utc);
+  return bias;
+}
+
+#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 const UInt64 kUnixTimeOffset =
+    (UInt64)60 * 60 * 24 * (89 + 365 * (kUnixTimeStartYear - kFileTimeStartYear));
+
+static Int64 Time_FileTimeToUnixTime64(const FILETIME *ft)
+{
+  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, &times[0]);
+  FILETIME_To_timespec(mTime, &times[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 };
+  unsigned 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 unsigned 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 <command> <archive_name>\n\n"
+      "<Commands>\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 34b60f8..01605e3 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 9f398d0..bc8fa21 100644
--- a/C/Util/7z/Precomp.h
+++ b/C/Util/7z/Precomp.h
@@ -1,10 +1,14 @@
-/* Precomp.h -- StdAfx

-2013-06-16 : Igor Pavlov : Public domain */

-

-#ifndef __7Z_PRECOMP_H

-#define __7Z_PRECOMP_H

-

-#include "../../Compiler.h"

-#include "../../7zTypes.h"

-

-#endif

+/* Precomp.h -- StdAfx
+2023-03-04 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_PRECOMP_H
+#define ZIP7_INC_PRECOMP_H
+
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+#pragma warning(disable : 4464) // relative include path contains '..'
+#endif
+
+#include "../../Compiler.h"
+#include "../../7zTypes.h"
+
+#endif
diff --git a/C/Util/7z/makefile b/C/Util/7z/makefile
index f4a54af..dfc560e 100644
--- a/C/Util/7z/makefile
+++ b/C/Util/7z/makefile
@@ -1,40 +1,40 @@
-CFLAGS = $(CFLAGS) -D_7ZIP_PPMD_SUPPPORT

-

-PROG = 7zDec.exe

-

-C_OBJS = \

-  $O\7zAlloc.obj \

-  $O\7zBuf.obj \

-  $O\7zCrc.obj \

-  $O\7zCrcOpt.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 \

-

-OBJS = \

-  $O\Precomp.obj \

-  $(7Z_OBJS) \

-  $(C_OBJS) \

-

-!include "../../../CPP/Build.mak"

-

-$(7Z_OBJS): $(*B).c

-	$(CCOMPL_USE)

-$(C_OBJS): ../../$(*B).c

-	$(CCOMPL_USE)

-$O\Precomp.obj: Precomp.c

-	$(CCOMPL_PCH)

+CFLAGS = $(CFLAGS) -DZ7_PPMD_SUPPORT -DZ7_EXTRACT_ONLY
+
+PROG = 7zDec.exe
+
+C_OBJS = \
+  $O\7zAlloc.obj \
+  $O\7zBuf.obj \
+  $O\7zCrc.obj \
+  $O\7zCrcOpt.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 \
+
+OBJS = \
+  $O\Precomp.obj \
+  $(7Z_OBJS) \
+  $(C_OBJS) \
+
+!include "../../../CPP/Build.mak"
+
+$(7Z_OBJS): $(*B).c
+	$(CCOMPL_USE)
+$(C_OBJS): ../../$(*B).c
+	$(CCOMPL_USE)
+$O\Precomp.obj: Precomp.c
+	$(CCOMPL_PCH)
diff --git a/C/Util/7z/makefile.gcc b/C/Util/7z/makefile.gcc
index f707935..f48d362 100644
--- a/C/Util/7z/makefile.gcc
+++ b/C/Util/7z/makefile.gcc
@@ -1,75 +1,32 @@
-PROG = 7zDec

-CXX = gcc

-LIB =

-RM = rm -f

-CFLAGS = -c -O2 -Wall

-

-OBJS = 7zMain.o 7zAlloc.o 7zArcIn.o 7zBuf.o 7zBuf2.o 7zCrc.o 7zCrcOpt.o 7zDec.o CpuArch.o Delta.o LzmaDec.o Lzma2Dec.o Bra.o Bra86.o BraIA64.o Bcj2.o Ppmd7.o Ppmd7Dec.o 7zFile.o 7zStream.o

-

-all: $(PROG)

-

-$(PROG): $(OBJS)

-	$(CXX) -o $(PROG) $(LDFLAGS) $(OBJS) $(LIB)

-

-7zMain.o: 7zMain.c

-	$(CXX) $(CFLAGS) 7zMain.c

-

-7zAlloc.o: ../../7zAlloc.c

-	$(CXX) $(CFLAGS) ../../7zAlloc.c

-

-7zArcIn.o: ../../7zArcIn.c

-	$(CXX) $(CFLAGS) ../../7zArcIn.c

-

-7zBuf.o: ../../7zBuf.c

-	$(CXX) $(CFLAGS) ../../7zBuf.c

-

-7zBuf2.o: ../../7zBuf2.c

-	$(CXX) $(CFLAGS) ../../7zBuf2.c

-

-7zCrc.o: ../../7zCrc.c

-	$(CXX) $(CFLAGS) ../../7zCrc.c

-

-7zCrcOpt.o: ../../7zCrc.c

-	$(CXX) $(CFLAGS) ../../7zCrcOpt.c

-

-7zDec.o: ../../7zDec.c

-	$(CXX) $(CFLAGS) -D_7ZIP_PPMD_SUPPPORT ../../7zDec.c

-

-CpuArch.o: ../../CpuArch.c

-	$(CXX) $(CFLAGS) ../../CpuArch.c

-

-Delta.o: ../../Delta.c

-	$(CXX) $(CFLAGS) ../../Delta.c

-

-LzmaDec.o: ../../LzmaDec.c

-	$(CXX) $(CFLAGS) ../../LzmaDec.c

-

-Lzma2Dec.o: ../../Lzma2Dec.c

-	$(CXX) $(CFLAGS) ../../Lzma2Dec.c

-

-Bra.o: ../../Bra.c

-	$(CXX) $(CFLAGS) ../../Bra.c

-

-Bra86.o: ../../Bra86.c

-	$(CXX) $(CFLAGS) ../../Bra86.c

-

-BraIA64.o: ../../BraIA64.c

-	$(CXX) $(CFLAGS) ../../BraIA64.c

-

-Bcj2.o: ../../Bcj2.c

-	$(CXX) $(CFLAGS) ../../Bcj2.c

-

-Ppmd7.o: ../../Ppmd7.c

-	$(CXX) $(CFLAGS) ../../Ppmd7.c

-

-Ppmd7Dec.o: ../../Ppmd7Dec.c

-	$(CXX) $(CFLAGS) ../../Ppmd7Dec.c

-

-7zFile.o: ../../7zFile.c

-	$(CXX) $(CFLAGS) ../../7zFile.c

-

-7zStream.o: ../../7zStream.c

-	$(CXX) $(CFLAGS) ../../7zStream.c

-

-clean:

-	-$(RM) $(PROG) $(OBJS)

+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/7zip.ico b/C/Util/7zipInstall/7zip.ico
new file mode 100644
index 0000000..47ffb78
--- /dev/null
+++ b/C/Util/7zipInstall/7zip.ico
Binary files differ
diff --git a/C/Util/7zipInstall/7zipInstall.c b/C/Util/7zipInstall/7zipInstall.c
new file mode 100644
index 0000000..7f5fd19
--- /dev/null
+++ b/C/Util/7zipInstall/7zipInstall.c
@@ -0,0 +1,1699 @@
+/* 7zipInstall.c - 7-Zip Installer
+2023-04-04 : 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
+
+#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 <shlobj.h>
+#else
+#include <ShlObj.h>
+#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
+
+#if defined(__clang__) || defined(__GNUC__)
+typedef void (*Z7_voidFunction)(void);
+#define MY_CAST_FUNC (Z7_voidFunction)
+#elif defined(_MSC_VER) && _MSC_VER > 1920
+#define MY_CAST_FUNC  (void *)
+// #pragma warning(disable : 4191) // 'type cast': unsafe conversion from 'FARPROC' to 'void (__cdecl *)()'
+#else
+#define MY_CAST_FUNC
+#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 _WIN64
+  #define k_Reg_WOW_Flag_32 KEY_WOW64_32KEY
+#else
+  #define k_Reg_WOW_Flag_32 0
+#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) MY_CAST_FUNC GetProcAddress(g_version_dll_hModule,
+    "GetFileVersionInfoSizeW");
+  my_GetFileVersionInfoW = (Func_GetFileVersionInfoW) MY_CAST_FUNC GetProcAddress(g_version_dll_hModule,
+    "GetFileVersionInfoW");
+  my_VerQueryValueW = (Func_VerQueryValueW) MY_CAST_FUNC 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)
+        MY_CAST_FUNC GetProcAddress(GetModuleHandleW(L"kernel32.dll"),
+        "IsWow64Process");
+    
+    if (func_IsWow64Process)
+      func_IsWow64Process(GetCurrentProcess(), &isWow64);
+
+    if (!isWow64)
+    {
+      if (!g_SilentMode)
+        PrintErrorMessage("This installation requires Windows " MY_CPU_NAME, 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
new file mode 100644
index 0000000..4c6ea4d
--- /dev/null
+++ b/C/Util/7zipInstall/7zipInstall.dsp
@@ -0,0 +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
diff --git a/C/Util/7zipInstall/7zipInstall.dsw b/C/Util/7zipInstall/7zipInstall.dsw
new file mode 100644
index 0000000..b7db73f
--- /dev/null
+++ b/C/Util/7zipInstall/7zipInstall.dsw
@@ -0,0 +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>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/C/Util/7zipInstall/7zipInstall.manifest b/C/Util/7zipInstall/7zipInstall.manifest
new file mode 100644
index 0000000..f5c3ae5
--- /dev/null
+++ b/C/Util/7zipInstall/7zipInstall.manifest
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
+<assemblyIdentity version="1.0.0.0" processorArchitecture="*" name="7-Zip.7-Zip.7zipInstall" type="win32"/>
+<description>7-Zip Installer</description>
+<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2"><security><requestedPrivileges>
+  <requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
+</requestedPrivileges></security></trustInfo>
+<dependency><dependentAssembly><assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"/></dependentAssembly></dependency>
+<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"><application>
+<!-- Vista   --> <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
+<!-- Win 7   --> <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
+<!-- Win 8   --> <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
+<!-- Win 8.1 --> <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
+<!-- Win 10  --> <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
+</application></compatibility>
+<asmv3:application><asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
+<dpiAware>true</dpiAware></asmv3:windowsSettings></asmv3:application>
+</assembly>
diff --git a/C/Util/7zipInstall/Precomp.c b/C/Util/7zipInstall/Precomp.c
new file mode 100644
index 0000000..01605e3
--- /dev/null
+++ b/C/Util/7zipInstall/Precomp.c
@@ -0,0 +1,4 @@
+/* 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
new file mode 100644
index 0000000..bc8fa21
--- /dev/null
+++ b/C/Util/7zipInstall/Precomp.h
@@ -0,0 +1,14 @@
+/* Precomp.h -- StdAfx
+2023-03-04 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_PRECOMP_H
+#define ZIP7_INC_PRECOMP_H
+
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+#pragma warning(disable : 4464) // relative include path contains '..'
+#endif
+
+#include "../../Compiler.h"
+#include "../../7zTypes.h"
+
+#endif
diff --git a/C/Util/7zipInstall/makefile b/C/Util/7zipInstall/makefile
new file mode 100644
index 0000000..18e2783
--- /dev/null
+++ b/C/Util/7zipInstall/makefile
@@ -0,0 +1,44 @@
+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\7zBuf2.obj \
+  $O\7zCrc.obj \
+  $O\7zCrcOpt.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) \
+  $O\resource.res
+
+!include "../../../CPP/Build.mak"
+
+$(MAIN_OBJS): $(*B).c
+	$(COMPL_O1)
+$(C_OBJS): ../../$(*B).c
+	$(COMPL_O1)
diff --git a/C/Util/7zipInstall/resource.h b/C/Util/7zipInstall/resource.h
new file mode 100644
index 0000000..63c6b4c
--- /dev/null
+++ b/C/Util/7zipInstall/resource.h
@@ -0,0 +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
diff --git a/C/Util/7zipInstall/resource.rc b/C/Util/7zipInstall/resource.rc
new file mode 100644
index 0000000..df6474e
--- /dev/null
+++ b/C/Util/7zipInstall/resource.rc
@@ -0,0 +1,47 @@
+#include <winnt.h>
+#include <WinUser.h>
+#include <CommCtrl.h>
+
+#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
new file mode 100644
index 0000000..8bc18b3
--- /dev/null
+++ b/C/Util/7zipUninstall/7zipUninstall.c
@@ -0,0 +1,1217 @@
+/* 7zipUninstall.c - 7-Zip Uninstaller
+2022-07-15 : 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
+
+#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 <shlobj.h>
+#else
+#include <ShlObj.h>
+#endif
+
+#include "../../7zVersion.h"
+
+#include "resource.h"
+
+#if (defined(__GNUC__) && (__GNUC__ >= 8)) || defined(__clang__)
+  // #pragma GCC diagnostic ignored "-Wcast-function-type"
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER > 1920
+#define MY_CAST_FUNC  (void *)
+// #pragma warning(disable : 4191) // 'type cast': unsafe conversion from 'FARPROC' to 'void (__cdecl *)()'
+#else
+#define MY_CAST_FUNC
+#endif
+
+
+#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 _WIN64
+  #define k_Reg_WOW_Flag_32 KEY_WOW64_32KEY
+#else
+  #define k_Reg_WOW_Flag_32 0
+#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;
+
+// WINADVAPI
+typedef LONG (APIENTRY *Func_RegDeleteKeyExW)(HKEY hKey, LPCWSTR lpSubKey, REGSAM samDesired, DWORD Reserved);
+static Func_RegDeleteKeyExW func_RegDeleteKeyExW;
+
+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
+    if (func_RegDeleteKeyExW)
+      return func_RegDeleteKeyExW(parentKey, name, k_Reg_WOW_Flag, 0);
+    return E_FAIL;
+  #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
+    if (func_RegDeleteKeyExW)
+      return func_RegDeleteKeyExW(parentKey, name, k_Reg_WOW_Flag_32, 0);
+    return E_FAIL;
+  #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
+  func_RegDeleteKeyExW = (Func_RegDeleteKeyExW) MY_CAST_FUNC
+      GetProcAddress(GetModuleHandleW(L"advapi32.dll"), "RegDeleteKeyExW");
+  #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
new file mode 100644
index 0000000..bb7473f
--- /dev/null
+++ b/C/Util/7zipUninstall/7zipUninstall.dsp
@@ -0,0 +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
diff --git a/C/Util/7zipUninstall/7zipUninstall.dsw b/C/Util/7zipUninstall/7zipUninstall.dsw
new file mode 100644
index 0000000..2873eda
--- /dev/null
+++ b/C/Util/7zipUninstall/7zipUninstall.dsw
@@ -0,0 +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>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/C/Util/7zipUninstall/7zipUninstall.ico b/C/Util/7zipUninstall/7zipUninstall.ico
new file mode 100644
index 0000000..19eb20c
--- /dev/null
+++ b/C/Util/7zipUninstall/7zipUninstall.ico
Binary files differ
diff --git a/C/Util/7zipUninstall/7zipUninstall.manifest b/C/Util/7zipUninstall/7zipUninstall.manifest
new file mode 100644
index 0000000..a601443
--- /dev/null
+++ b/C/Util/7zipUninstall/7zipUninstall.manifest
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
+<assemblyIdentity version="1.0.0.0" processorArchitecture="*" name="7-Zip.7-Zip.Uninstall" type="win32"/>
+<description>7-Zip Uninstaller</description>
+<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2"><security><requestedPrivileges>
+  <requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
+</requestedPrivileges></security></trustInfo>
+<dependency><dependentAssembly><assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"/></dependentAssembly></dependency>
+<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"><application>
+<!-- Vista   --> <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
+<!-- Win 7   --> <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
+<!-- Win 8   --> <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
+<!-- Win 8.1 --> <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
+<!-- Win 10  --> <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
+</application></compatibility>
+<asmv3:application><asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
+<dpiAware>true</dpiAware></asmv3:windowsSettings></asmv3:application>
+</assembly>
diff --git a/C/Util/7zipUninstall/Precomp.c b/C/Util/7zipUninstall/Precomp.c
new file mode 100644
index 0000000..01605e3
--- /dev/null
+++ b/C/Util/7zipUninstall/Precomp.c
@@ -0,0 +1,4 @@
+/* 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
new file mode 100644
index 0000000..bc8fa21
--- /dev/null
+++ b/C/Util/7zipUninstall/Precomp.h
@@ -0,0 +1,14 @@
+/* Precomp.h -- StdAfx
+2023-03-04 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_PRECOMP_H
+#define ZIP7_INC_PRECOMP_H
+
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+#pragma warning(disable : 4464) // relative include path contains '..'
+#endif
+
+#include "../../Compiler.h"
+#include "../../7zTypes.h"
+
+#endif
diff --git a/C/Util/7zipUninstall/makefile b/C/Util/7zipUninstall/makefile
new file mode 100644
index 0000000..9d8aafc
--- /dev/null
+++ b/C/Util/7zipUninstall/makefile
@@ -0,0 +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)
diff --git a/C/Util/7zipUninstall/resource.h b/C/Util/7zipUninstall/resource.h
new file mode 100644
index 0000000..b5c33ff
--- /dev/null
+++ b/C/Util/7zipUninstall/resource.h
@@ -0,0 +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
diff --git a/C/Util/7zipUninstall/resource.rc b/C/Util/7zipUninstall/resource.rc
new file mode 100644
index 0000000..00bdcc0
--- /dev/null
+++ b/C/Util/7zipUninstall/resource.rc
@@ -0,0 +1,47 @@
+#include <winnt.h>
+#include <WinUser.h>
+#include <CommCtrl.h>
+
+#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 82130e8..b9b974b 100644
--- a/C/Util/Lzma/LzmaUtil.c
+++ b/C/Util/Lzma/LzmaUtil.c
@@ -1,258 +1,313 @@
-/* LzmaUtil.c -- Test application for LZMA compression

-2018-07-04 : Igor Pavlov : Public domain */

-

-#include "../../Precomp.h"

-

-#include <stdio.h>

-#include <stdlib.h>

-#include <string.h>

-

-#include "../../CpuArch.h"

-

-#include "../../Alloc.h"

-#include "../../7zFile.h"

-#include "../../7zVersion.h"

-#include "../../LzmaDec.h"

-#include "../../LzmaEnc.h"

-

-static const char * const kCantReadMessage = "Can not read input file";

-static const char * const kCantWriteMessage = "Can not write output file";

-static const char * const kCantAllocateMessage = "Can not allocate memory";

-static const char * const kDataErrorMessage = "Data error";

-

-static void PrintHelp(char *buffer)

-{

-  strcat(buffer,

-    "\nLZMA-C " MY_VERSION_CPU " : " MY_COPYRIGHT_DATE "\n\n"

-    "Usage:  lzma <e|d> inputFile outputFile\n"

-    "  e: encode file\n"

-    "  d: decode file\n");

-}

-

-static int PrintError(char *buffer, const char *message)

-{

-  strcat(buffer, "\nError: ");

-  strcat(buffer, message);

-  strcat(buffer, "\n");

-  return 1;

-}

-

-static int PrintErrorNumber(char *buffer, SRes val)

-{

-  sprintf(buffer + strlen(buffer), "\nError code: %x\n", (unsigned)val);

-  return 1;

-}

-

-static int PrintUserError(char *buffer)

-{

-  return PrintError(buffer, "Incorrect command");

-}

-

-

-#define IN_BUF_SIZE (1 << 16)

-#define OUT_BUF_SIZE (1 << 16)

-

-

-static SRes Decode2(CLzmaDec *state, ISeqOutStream *outStream, ISeqInStream *inStream,

-    UInt64 unpackSize)

-{

-  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(ISeqOutStream *outStream, ISeqInStream *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 */

-

-  RINOK(SeqInStream_Read(inStream, header, sizeof(header)));

-

-  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(ISeqOutStream *outStream, ISeqInStream *inStream, UInt64 fileSize, char *rs)

-{

-  CLzmaEncHandle enc;

-  SRes res;

-  CLzmaEncProps props;

-

-  UNUSED_VAR(rs);

-

-  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;

-}

-

-

-static int main2(int numArgs, const char *args[], char *rs)

-{

-  CFileSeqInStream inStream;

-  CFileOutStream outStream;

-  char c;

-  int res;

-  int encodeMode;

-  BoolInt useOutFile = False;

-

-  FileSeqInStream_CreateVTable(&inStream);

-  File_Construct(&inStream.file);

-

-  FileOutStream_CreateVTable(&outStream);

-  File_Construct(&outStream.file);

-

-  if (numArgs == 1)

-  {

-    PrintHelp(rs);

-    return 0;

-  }

-

-  if (numArgs < 3 || numArgs > 4 || strlen(args[1]) != 1)

-    return PrintUserError(rs);

-

-  c = args[1][0];

-  encodeMode = (c == 'e' || c == 'E');

-  if (!encodeMode && c != 'd' && c != 'D')

-    return PrintUserError(rs);

-

-  {

-    size_t t4 = sizeof(UInt32);

-    size_t t8 = sizeof(UInt64);

-    if (t4 != 4 || t8 != 8)

-      return PrintError(rs, "Incorrect UInt32 or UInt64");

-  }

-

-  if (InFile_Open(&inStream.file, args[2]) != 0)

-    return PrintError(rs, "Can not open input file");

-

-  if (numArgs > 3)

-  {

-    useOutFile = True;

-    if (OutFile_Open(&outStream.file, args[3]) != 0)

-      return PrintError(rs, "Can not open output file");

-  }

-  else if (encodeMode)

-    PrintUserError(rs);

-

-  if (encodeMode)

-  {

-    UInt64 fileSize;

-    File_GetLength(&inStream.file, &fileSize);

-    res = Encode(&outStream.vt, &inStream.vt, fileSize, rs);

-  }

-  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(rs, kCantAllocateMessage);

-    else if (res == SZ_ERROR_DATA)

-      return PrintError(rs, kDataErrorMessage);

-    else if (res == SZ_ERROR_WRITE)

-      return PrintError(rs, kCantWriteMessage);

-    else if (res == SZ_ERROR_READ)

-      return PrintError(rs, kCantReadMessage);

-    return PrintErrorNumber(rs, res);

-  }

-  return 0;

-}

-

-

-int MY_CDECL main(int numArgs, const char *args[])

-{

-  char rs[800] = { 0 };

-  int res = main2(numArgs, args, rs);

-  fputs(rs, stdout);

-  return res;

-}

+/* LzmaUtil.c -- Test application for LZMA compression
+2023-03-07 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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 <e|d> 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 eedde07..e2e7d42 100644
--- a/C/Util/Lzma/LzmaUtil.dsp
+++ b/C/Util/Lzma/LzmaUtil.dsp
@@ -1,168 +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=..\..\Alloc.c

-# End Source File

-# Begin Source File

-

-SOURCE=..\..\Alloc.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=..\..\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=..\..\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 f435487..c52eaf6 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
new file mode 100644
index 0000000..bc8fa21
--- /dev/null
+++ b/C/Util/Lzma/Precomp.h
@@ -0,0 +1,14 @@
+/* Precomp.h -- StdAfx
+2023-03-04 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_PRECOMP_H
+#define ZIP7_INC_PRECOMP_H
+
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+#pragma warning(disable : 4464) // relative include path contains '..'
+#endif
+
+#include "../../Compiler.h"
+#include "../../7zTypes.h"
+
+#endif
diff --git a/C/Util/Lzma/makefile b/C/Util/Lzma/makefile
index 3b825f2..7813bdb 100644
--- a/C/Util/Lzma/makefile
+++ b/C/Util/Lzma/makefile
@@ -1,28 +1,30 @@
-# MY_STATIC_LINK=1

-PROG = LZMAc.exe

-

-CFLAGS = $(CFLAGS) \

-

-LIB_OBJS = \

-  $O\LzmaUtil.obj \

-

-C_OBJS = \

-  $O\Alloc.obj \

-  $O\LzFind.obj \

-  $O\LzFindMt.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 12a72bb..2acb0b8 100644
--- a/C/Util/Lzma/makefile.gcc
+++ b/C/Util/Lzma/makefile.gcc
@@ -1,44 +1,21 @@
-PROG = lzma

-CXX = g++

-LIB =

-RM = rm -f

-CFLAGS = -c -O2 -Wall -D_7ZIP_ST

-

-OBJS = \

-  LzmaUtil.o \

-  Alloc.o \

-  LzFind.o \

-  LzmaDec.o \

-  LzmaEnc.o \

-  7zFile.o \

-  7zStream.o \

-

-

-all: $(PROG)

-

-$(PROG): $(OBJS)

-	$(CXX) -o $(PROG) $(LDFLAGS) $(OBJS) $(LIB) $(LIB2)

-

-LzmaUtil.o: LzmaUtil.c

-	$(CXX) $(CFLAGS) LzmaUtil.c

-

-Alloc.o: ../../Alloc.c

-	$(CXX) $(CFLAGS) ../../Alloc.c

-

-LzFind.o: ../../LzFind.c

-	$(CXX) $(CFLAGS) ../../LzFind.c

-

-LzmaDec.o: ../../LzmaDec.c

-	$(CXX) $(CFLAGS) ../../LzmaDec.c

-

-LzmaEnc.o: ../../LzmaEnc.c

-	$(CXX) $(CFLAGS) ../../LzmaEnc.c

-

-7zFile.o: ../../7zFile.c

-	$(CXX) $(CFLAGS) ../../7zFile.c

-

-7zStream.o: ../../7zStream.c

-	$(CXX) $(CFLAGS) ../../7zStream.c

-

-clean:

-	-$(RM) $(PROG) $(OBJS)

+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 43b9597..8bc6add 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 0d4c981..bacd967 100644
--- a/C/Util/LzmaLib/LzmaLib.dsp
+++ b/C/Util/LzmaLib/LzmaLib.dsp
@@ -1,178 +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

-# End Group

-# Begin Source File

-

-SOURCE=..\..\7zTypes.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=..\..\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=..\..\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=.\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 f6c5559..6faf333 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 02600c7..a46c9a8 100644
--- a/C/Util/LzmaLib/LzmaLibExports.c
+++ b/C/Util/LzmaLib/LzmaLibExports.c
@@ -1,14 +1,15 @@
-/* LzmaLibExports.c -- LZMA library DLL Entry point

-2015-11-08 : Igor Pavlov : Public domain */

-

-#include "../../Precomp.h"

-

-#include <windows.h>

-

-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
new file mode 100644
index 0000000..01605e3
--- /dev/null
+++ b/C/Util/LzmaLib/Precomp.c
@@ -0,0 +1,4 @@
+/* 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
new file mode 100644
index 0000000..bc8fa21
--- /dev/null
+++ b/C/Util/LzmaLib/Precomp.h
@@ -0,0 +1,14 @@
+/* Precomp.h -- StdAfx
+2023-03-04 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_PRECOMP_H
+#define ZIP7_INC_PRECOMP_H
+
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+#pragma warning(disable : 4464) // relative include path contains '..'
+#endif
+
+#include "../../Compiler.h"
+#include "../../7zTypes.h"
+
+#endif
diff --git a/C/Util/LzmaLib/makefile b/C/Util/LzmaLib/makefile
index e0f3114..b8e054e 100644
--- a/C/Util/LzmaLib/makefile
+++ b/C/Util/LzmaLib/makefile
@@ -1,34 +1,54 @@
-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\LzFind.obj \

-  $O\LzFindMt.obj \

-  $O\LzmaDec.obj \

-  $O\LzmaEnc.obj \

-  $O\LzmaLib.obj \

-  $O\Threads.obj \

-

-OBJS = \

-  $(LIB_OBJS) \

-  $(C_OBJS) \

-  $O\resource.res

-

-!include "../../../CPP/Build.mak"

-

-$(SLIBPATH): $O $(OBJS)

-	lib -out:$(SLIBPATH) $(OBJS) $(LIBS)

-

-$(LIB_OBJS): $(*B).c

-	$(COMPL_O2)

-$(C_OBJS): ../../$(*B).c

-	$(COMPL_O2)

+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\LzFindOpt.obj \
+  $O\LzmaDec.obj \
+  $O\LzmaEnc.obj \
+  $O\LzmaLib.obj \
+  $O\Threads.obj \
+
+OBJS = \
+  $O\Precomp.obj \
+  $(LIB_OBJS) \
+  $(C_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
diff --git a/C/Util/LzmaLib/resource.rc b/C/Util/LzmaLib/resource.rc
index d95e3f3..674832e 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 34b60f8..01605e3 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 9f398d0..bc8fa21 100644
--- a/C/Util/SfxSetup/Precomp.h
+++ b/C/Util/SfxSetup/Precomp.h
@@ -1,10 +1,14 @@
-/* Precomp.h -- StdAfx

-2013-06-16 : Igor Pavlov : Public domain */

-

-#ifndef __7Z_PRECOMP_H

-#define __7Z_PRECOMP_H

-

-#include "../../Compiler.h"

-#include "../../7zTypes.h"

-

-#endif

+/* Precomp.h -- StdAfx
+2023-03-04 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_PRECOMP_H
+#define ZIP7_INC_PRECOMP_H
+
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+#pragma warning(disable : 4464) // relative include path contains '..'
+#endif
+
+#include "../../Compiler.h"
+#include "../../7zTypes.h"
+
+#endif
diff --git a/C/Util/SfxSetup/SfxSetup.c b/C/Util/SfxSetup/SfxSetup.c
index 394369a..7304a0b 100644
--- a/C/Util/SfxSetup/SfxSetup.c
+++ b/C/Util/SfxSetup/SfxSetup.c
@@ -1,640 +1,656 @@
-/* SfxSetup.c - 7z SFX Setup

-2019-02-02 : Igor Pavlov : Public domain */

-

-#include "Precomp.h"

-

-#ifndef UNICODE

-#define UNICODE

-#endif

-

-#ifndef _UNICODE

-#define _UNICODE

-#endif

-

-#ifdef _CONSOLE

-#include <stdio.h>

-#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)

-

-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];

-    unsigned itemLen = (unsigned)strlen(item);

-    unsigned j;

-    if (len != itemLen)

-      continue;

-    for (j = 0; j < len; j++)

-    {

-      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

-

-static void PrintErrorMessage(const char *message)

-{

-  #ifdef _CONSOLE

-  printf("\n7-Zip Error: %s\n", message);

-  #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;

-  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 MY_CDECL main()

-#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++)

-      {

-        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++)

-        {

-          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);

-          unsigned nameLen = FindExt(temp + nameStartPos, &extLen);

-          unsigned extPrice = FindItem(kExts, sizeof(kExts) / sizeof(kExts[0]), name + len - extLen, extLen);

-          unsigned namePrice = FindItem(kNames, sizeof(kNames) / sizeof(kNames[0]), name, nameLen);

-

-          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

-        

-        {

-          SRes res2 = File_Close(&outFile);

-          if (res != SZ_OK)

-            break;

-          if (res2 != SZ_OK)

-          {

-            res = res2;

-            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;

-    {

-      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
+2019-02-02 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#ifndef UNICODE
+#define UNICODE
+#endif
+
+#ifndef _UNICODE
+#define _UNICODE
+#endif
+
+#ifdef _CONSOLE
+#include <stdio.h>
+#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 SRes res2 = File_Close(&outFile);
+          if (res != SZ_OK)
+            break;
+          if (res2 != SZ_OK)
+          {
+            res = res2;
+            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 be9de6d..60439a6 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 128fcdd..ea23111 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 c9f59cc..bc0cf8b 100644
--- a/C/Util/SfxSetup/makefile
+++ b/C/Util/SfxSetup/makefile
@@ -1,37 +1,40 @@
-PROG = 7zS2.sfx

-MY_FIXED = 1

-

-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 = 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\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/makefile_con b/C/Util/SfxSetup/makefile_con
index 6f604ed..9f4b916 100644
--- a/C/Util/SfxSetup/makefile_con
+++ b/C/Util/SfxSetup/makefile_con
@@ -1,38 +1,40 @@
-PROG = 7zS2con.sfx

-MY_FIXED = 1

-CFLAGS = $(CFLAGS) -D_CONSOLE

-

-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 64f4e2c..0c1637f 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/Xz.c b/C/Xz.c
index 7e061d6..4ad0710 100644
--- a/C/Xz.c
+++ b/C/Xz.c
@@ -1,90 +1,90 @@
-/* Xz.c - Xz

-2017-05-12 : 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 : (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;

-  }

-}

-

-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;

-  }

-}

-

-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
+2023-04-02 : 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;
+  }
+}
+
+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;
+  }
+}
+
+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 fad56a3..d5001f6 100644
--- a/C/Xz.h
+++ b/C/Xz.h
@@ -1,460 +1,535 @@
-/* Xz.h - Xz interface

-2018-07-04 : Igor Pavlov : Public domain */

-

-#ifndef __XZ_H

-#define __XZ_H

-

-#include "Sha256.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_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) (((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, ISeqInStream *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, ISeqInStream *inStream);

-

-typedef struct

-{

-  UInt64 unpackSize;

-  UInt64 totalSize;

-} CXzBlockSizes;

-

-typedef struct

-{

-  CXzStreamFlags flags;

-  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, ILookInStream *inStream, Int64 *startOffset, ICompressProgress *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 _IStateCoder

-{

-  void *p;

-  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;

-

-

-

-#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;

-  UInt32 pos;

-  unsigned alignPos;

-  unsigned indexPreSize;

-

-  CXzStreamFlags streamFlags;

-  

-  UInt32 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();

-    }

-    

-  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()

-    }

-

-  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()

-    }

-*/

-

-/*

-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 - maybe there are more xz streams,

-                                      call XzUnpacker_IsStreamWasFinished to check that current stream was finished

-  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);

-

-BoolInt XzUnpacker_IsStreamWasFinished(const CXzUnpacker *p);

-

-/*

-XzUnpacker_GetExtraSize() returns then number of uncofirmed bytes,

- if it's in (XZ_STATE_STREAM_HEADER) state or in (XZ_STATE_STREAM_PADDING) state.

-These bytes can be some bytes 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))

-

-

-

-/* ---------- Multi Threading Decoding ---------- */

-

-

-typedef struct

-{

-  size_t inBufSize_ST;

-  size_t outStep_ST;

-  BoolInt ignoreErrors;

-  

-  #ifndef _7ZIP_ST

-  unsigned numThreads;

-  size_t inBufSize_MT;

-  size_t memUseMax;

-  #endif

-} CXzDecMtProps;

-

-void XzDecMtProps_Init(CXzDecMtProps *p);

-

-

-typedef void * CXzDecMtHandle;

-

-/*

-  alloc    : XzDecMt uses CAlignOffsetAlloc 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;

-  Byte DecodingTruncated; // Decoding was Truncated, we need only partial output data

-

-  UInt64 InSize;  // pack size processed

-  UInt64 OutSize;

-

-  UInt64 NumStreams;

-  UInt64 NumBlocks;

-

-  SRes DecodeRes;

-  SRes ReadRes;

-  SRes ProgressRes;

-  SRes CombinedRes;

-  SRes CombinedRes_Type;

-

-} CXzStatInfo;

-

-void XzStatInfo_Clear(CXzStatInfo *p);

-

-/*

-XzDecMt_Decode()

-SRes:

-  SZ_OK               - OK

-  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_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

-    ISeqOutStream *outStream,

-    // Byte *outBuf, size_t *outBufSize,

-    ISeqInStream *inStream,

-    // const Byte *inData, size_t inDataSize,

-    CXzStatInfo *stat,

-    int *isMT,                 // 0 means that ST (Single-Thread) version was used

-    ICompressProgress *progress);

-

-EXTERN_C_END

-

-#endif

+/* Xz.h - Xz interface
+2023-04-13 : 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_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;
+  UInt32 pos;
+  unsigned alignPos;
+  unsigned indexPreSize;
+
+  CXzStreamFlags streamFlags;
+  
+  UInt32 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 e9ca9ec..c2fad6c 100644
--- a/C/XzCrc64.c
+++ b/C/XzCrc64.c
@@ -1,86 +1,80 @@
-/* XzCrc64.c -- CRC64 calculation

-2017-05-23 : Igor Pavlov : Public domain */

-

-#include "Precomp.h"

-

-#include "XzCrc64.h"

-#include "CpuArch.h"

-

-#define kCrc64Poly UINT64_CONST(0xC96C5795D7870F42)

-

-#ifdef MY_CPU_LE

-  #define CRC64_NUM_TABLES 4

-#else

-  #define CRC64_NUM_TABLES 5

-  #define CRC_UINT64_SWAP(v) \

-      ((v >> 56) \

-    | ((v >> 40) & ((UInt64)0xFF <<  8)) \

-    | ((v >> 24) & ((UInt64)0xFF << 16)) \

-    | ((v >>  8) & ((UInt64)0xFF << 24)) \

-    | ((v <<  8) & ((UInt64)0xFF << 32)) \

-    | ((v << 24) & ((UInt64)0xFF << 40)) \

-    | ((v << 40) & ((UInt64)0xFF << 48)) \

-    | ((v << 56)))

-

-  UInt64 MY_FAST_CALL XzCrc64UpdateT1_BeT4(UInt64 v, const void *data, size_t size, const UInt64 *table);

-#endif

-

-#ifndef MY_CPU_BE

-  UInt64 MY_FAST_CALL XzCrc64UpdateT4(UInt64 v, const void *data, size_t size, const UInt64 *table);

-#endif

-

-typedef UInt64 (MY_FAST_CALL *CRC64_FUNC)(UInt64 v, const void *data, size_t size, const UInt64 *table);

-

-static CRC64_FUNC g_Crc64Update;

-UInt64 g_Crc64Table[256 * CRC64_NUM_TABLES];

-

-UInt64 MY_FAST_CALL Crc64Update(UInt64 v, const void *data, size_t size)

-{

-  return g_Crc64Update(v, data, size, g_Crc64Table);

-}

-

-UInt64 MY_FAST_CALL Crc64Calc(const void *data, size_t size)

-{

-  return g_Crc64Update(CRC64_INIT_VAL, data, size, g_Crc64Table) ^ CRC64_INIT_VAL;

-}

-

-void MY_FAST_CALL Crc64GenerateTable()

-{

-  UInt32 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;

-  }

-  for (i = 256; i < 256 * CRC64_NUM_TABLES; i++)

-  {

-    UInt64 r = g_Crc64Table[(size_t)i - 256];

-    g_Crc64Table[i] = g_Crc64Table[r & 0xFF] ^ (r >> 8);

-  }

-  

-  #ifdef MY_CPU_LE

-

-  g_Crc64Update = XzCrc64UpdateT4;

-

-  #else

-  {

-    #ifndef MY_CPU_BE

-    UInt32 k = 1;

-    if (*(const Byte *)&k == 1)

-      g_Crc64Update = XzCrc64UpdateT4;

-    else

-    #endif

-    {

-      for (i = 256 * CRC64_NUM_TABLES - 1; i >= 256; i--)

-      {

-        UInt64 x = g_Crc64Table[(size_t)i - 256];

-        g_Crc64Table[i] = CRC_UINT64_SWAP(x);

-      }

-      g_Crc64Update = XzCrc64UpdateT1_BeT4;

-    }

-  }

-  #endif

-}

+/* XzCrc64.c -- CRC64 calculation
+2023-04-02 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "XzCrc64.h"
+#include "CpuArch.h"
+
+#define kCrc64Poly UINT64_CONST(0xC96C5795D7870F42)
+
+#ifdef MY_CPU_LE
+  #define CRC64_NUM_TABLES 4
+#else
+  #define CRC64_NUM_TABLES 5
+
+  UInt64 Z7_FASTCALL XzCrc64UpdateT1_BeT4(UInt64 v, const void *data, size_t size, const UInt64 *table);
+#endif
+
+#ifndef MY_CPU_BE
+  UInt64 Z7_FASTCALL XzCrc64UpdateT4(UInt64 v, const void *data, size_t size, const UInt64 *table);
+#endif
+
+typedef UInt64 (Z7_FASTCALL *CRC64_FUNC)(UInt64 v, const void *data, size_t size, const UInt64 *table);
+
+static CRC64_FUNC g_Crc64Update;
+UInt64 g_Crc64Table[256 * CRC64_NUM_TABLES];
+
+UInt64 Z7_FASTCALL Crc64Update(UInt64 v, const void *data, size_t size)
+{
+  return g_Crc64Update(v, data, size, g_Crc64Table);
+}
+
+UInt64 Z7_FASTCALL Crc64Calc(const void *data, size_t size)
+{
+  return g_Crc64Update(CRC64_INIT_VAL, data, size, g_Crc64Table) ^ CRC64_INIT_VAL;
+}
+
+void Z7_FASTCALL Crc64GenerateTable(void)
+{
+  UInt32 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;
+  }
+  for (i = 256; i < 256 * CRC64_NUM_TABLES; i++)
+  {
+    const UInt64 r = g_Crc64Table[(size_t)i - 256];
+    g_Crc64Table[i] = g_Crc64Table[r & 0xFF] ^ (r >> 8);
+  }
+  
+  #ifdef MY_CPU_LE
+
+  g_Crc64Update = XzCrc64UpdateT4;
+
+  #else
+  {
+    #ifndef MY_CPU_BE
+    UInt32 k = 1;
+    if (*(const Byte *)&k == 1)
+      g_Crc64Update = XzCrc64UpdateT4;
+    else
+    #endif
+    {
+      for (i = 256 * CRC64_NUM_TABLES - 1; i >= 256; i--)
+      {
+        const UInt64 x = g_Crc64Table[(size_t)i - 256];
+        g_Crc64Table[i] = Z7_BSWAP64(x);
+      }
+      g_Crc64Update = XzCrc64UpdateT1_BeT4;
+    }
+  }
+  #endif
+}
+
+#undef kCrc64Poly
+#undef CRC64_NUM_TABLES
diff --git a/C/XzCrc64.h b/C/XzCrc64.h
index 71b10d5..ca46869 100644
--- a/C/XzCrc64.h
+++ b/C/XzCrc64.h
@@ -1,26 +1,26 @@
-/* XzCrc64.h -- CRC64 calculation

-2013-01-18 : Igor Pavlov : Public domain */

-

-#ifndef __XZ_CRC64_H

-#define __XZ_CRC64_H

-

-#include <stddef.h>

-

-#include "7zTypes.h"

-

-EXTERN_C_BEGIN

-

-extern UInt64 g_Crc64Table[];

-

-void MY_FAST_CALL 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 MY_FAST_CALL Crc64Update(UInt64 crc, const void *data, size_t size);

-UInt64 MY_FAST_CALL Crc64Calc(const void *data, size_t size);

-

-EXTERN_C_END

-

-#endif

+/* XzCrc64.h -- CRC64 calculation
+2023-04-02 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_XZ_CRC64_H
+#define ZIP7_INC_XZ_CRC64_H
+
+#include <stddef.h>
+
+#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 9273465..d03374c 100644
--- a/C/XzCrc64Opt.c
+++ b/C/XzCrc64Opt.c
@@ -1,69 +1,61 @@
-/* XzCrc64Opt.c -- CRC64 calculation

-2017-06-30 : Igor Pavlov : Public domain */

-

-#include "Precomp.h"

-

-#include "CpuArch.h"

-

-#ifndef MY_CPU_BE

-

-#define CRC64_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))

-

-UInt64 MY_FAST_CALL XzCrc64UpdateT4(UInt64 v, const void *data, size_t size, const UInt64 *table)

-{

-  const Byte *p = (const Byte *)data;

-  for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++)

-    v = CRC64_UPDATE_BYTE_2(v, *p);

-  for (; size >= 4; size -= 4, p += 4)

-  {

-    UInt32 d = (UInt32)v ^ *(const UInt32 *)p;

-    v = (v >> 32)

-        ^ (table + 0x300)[((d      ) & 0xFF)]

-        ^ (table + 0x200)[((d >>  8) & 0xFF)]

-        ^ (table + 0x100)[((d >> 16) & 0xFF)]

-        ^ (table + 0x000)[((d >> 24))];

-  }

-  for (; size > 0; size--, p++)

-    v = CRC64_UPDATE_BYTE_2(v, *p);

-  return v;

-}

-

-#endif

-

-

-#ifndef MY_CPU_LE

-

-#define CRC_UINT64_SWAP(v) \

-      ((v >> 56) \

-    | ((v >> 40) & ((UInt64)0xFF <<  8)) \

-    | ((v >> 24) & ((UInt64)0xFF << 16)) \

-    | ((v >>  8) & ((UInt64)0xFF << 24)) \

-    | ((v <<  8) & ((UInt64)0xFF << 32)) \

-    | ((v << 24) & ((UInt64)0xFF << 40)) \

-    | ((v << 40) & ((UInt64)0xFF << 48)) \

-    | ((v << 56)))

-

-#define CRC64_UPDATE_BYTE_2_BE(crc, b) (table[(Byte)((crc) >> 56) ^ (b)] ^ ((crc) << 8))

-

-UInt64 MY_FAST_CALL XzCrc64UpdateT1_BeT4(UInt64 v, const void *data, size_t size, const UInt64 *table)

-{

-  const Byte *p = (const Byte *)data;

-  table += 0x100;

-  v = CRC_UINT64_SWAP(v);

-  for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++)

-    v = CRC64_UPDATE_BYTE_2_BE(v, *p);

-  for (; size >= 4; size -= 4, p += 4)

-  {

-    UInt32 d = (UInt32)(v >> 32) ^ *(const UInt32 *)p;

-    v = (v << 32)

-        ^ (table + 0x000)[((d      ) & 0xFF)]

-        ^ (table + 0x100)[((d >>  8) & 0xFF)]

-        ^ (table + 0x200)[((d >> 16) & 0xFF)]

-        ^ (table + 0x300)[((d >> 24))];

-  }

-  for (; size > 0; size--, p++)

-    v = CRC64_UPDATE_BYTE_2_BE(v, *p);

-  return CRC_UINT64_SWAP(v);

-}

-

-#endif

+/* XzCrc64Opt.c -- CRC64 calculation
+2023-04-02 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "CpuArch.h"
+
+#ifndef MY_CPU_BE
+
+#define CRC64_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
+
+UInt64 Z7_FASTCALL XzCrc64UpdateT4(UInt64 v, const void *data, size_t size, const UInt64 *table);
+UInt64 Z7_FASTCALL XzCrc64UpdateT4(UInt64 v, const void *data, size_t size, const UInt64 *table)
+{
+  const Byte *p = (const Byte *)data;
+  for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++)
+    v = CRC64_UPDATE_BYTE_2(v, *p);
+  for (; size >= 4; size -= 4, p += 4)
+  {
+    const UInt32 d = (UInt32)v ^ *(const UInt32 *)(const void *)p;
+    v = (v >> 32)
+        ^ (table + 0x300)[((d      ) & 0xFF)]
+        ^ (table + 0x200)[((d >>  8) & 0xFF)]
+        ^ (table + 0x100)[((d >> 16) & 0xFF)]
+        ^ (table + 0x000)[((d >> 24))];
+  }
+  for (; size > 0; size--, p++)
+    v = CRC64_UPDATE_BYTE_2(v, *p);
+  return v;
+}
+
+#endif
+
+
+#ifndef MY_CPU_LE
+
+#define CRC64_UPDATE_BYTE_2_BE(crc, b) (table[(Byte)((crc) >> 56) ^ (b)] ^ ((crc) << 8))
+
+UInt64 Z7_FASTCALL XzCrc64UpdateT1_BeT4(UInt64 v, const void *data, size_t size, const UInt64 *table);
+UInt64 Z7_FASTCALL XzCrc64UpdateT1_BeT4(UInt64 v, const void *data, size_t size, const UInt64 *table)
+{
+  const Byte *p = (const Byte *)data;
+  table += 0x100;
+  v = Z7_BSWAP64(v);
+  for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++)
+    v = CRC64_UPDATE_BYTE_2_BE(v, *p);
+  for (; size >= 4; size -= 4, p += 4)
+  {
+    const UInt32 d = (UInt32)(v >> 32) ^ *(const UInt32 *)(const void *)p;
+    v = (v << 32)
+        ^ (table + 0x000)[((d      ) & 0xFF)]
+        ^ (table + 0x100)[((d >>  8) & 0xFF)]
+        ^ (table + 0x200)[((d >> 16) & 0xFF)]
+        ^ (table + 0x300)[((d >> 24))];
+  }
+  for (; size > 0; size--, p++)
+    v = CRC64_UPDATE_BYTE_2_BE(v, *p);
+  return Z7_BSWAP64(v);
+}
+
+#endif
diff --git a/C/XzDec.c b/C/XzDec.c
index 4f53272..a5f7039 100644
--- a/C/XzDec.c
+++ b/C/XzDec.c
@@ -1,2766 +1,2875 @@
-/* XzDec.c -- Xz Decode

-2019-02-02 : Igor Pavlov : Public domain */

-

-#include "Precomp.h"

-

-// #include <stdio.h>

-

-// #define XZ_DUMP

-

-/* #define XZ_DUMP */

-

-#ifdef XZ_DUMP

-#include <stdio.h>

-#endif

-

-// #define SHOW_DEBUG_INFO

-

-#ifdef SHOW_DEBUG_INFO

-#include <stdio.h>

-#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 <stdlib.h>

-#include <string.h>

-

-#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;

-}

-

-/* ---------- BraState ---------- */

-

-#define BRA_BUF_SIZE (1 << 14)

-

-typedef struct

-{

-  size_t bufPos;

-  size_t bufConv;

-  size_t bufTotal;

-

-  int encodeMode;

-

-  UInt32 methodId;

-  UInt32 delta;

-  UInt32 ip;

-  UInt32 x86State;

-  Byte deltaState[DELTA_STATE_SIZE];

-

-  Byte buf[BRA_BUF_SIZE];

-} CBraState;

-

-static void BraState_Free(void *pp, ISzAllocPtr alloc)

-{

-  ISzAlloc_Free(alloc, pp);

-}

-

-static SRes BraState_SetProps(void *pp, const Byte *props, size_t propSize, ISzAllocPtr alloc)

-{

-  CBraState *p = ((CBraState *)pp);

-  UNUSED_VAR(alloc);

-  p->ip = 0;

-  if (p->methodId == XZ_ID_Delta)

-  {

-    if (propSize != 1)

-      return SZ_ERROR_UNSUPPORTED;

-    p->delta = (unsigned)props[0] + 1;

-  }

-  else

-  {

-    if (propSize == 4)

-    {

-      UInt32 v = GetUi32(props);

-      switch (p->methodId)

-      {

-        case XZ_ID_PPC:

-        case XZ_ID_ARM:

-        case XZ_ID_SPARC:

-          if ((v & 3) != 0)

-            return SZ_ERROR_UNSUPPORTED;

-          break;

-        case XZ_ID_ARMT:

-          if ((v & 1) != 0)

-            return SZ_ERROR_UNSUPPORTED;

-          break;

-        case XZ_ID_IA64:

-          if ((v & 0xF) != 0)

-            return SZ_ERROR_UNSUPPORTED;

-          break;

-      }

-      p->ip = v;

-    }

-    else if (propSize != 0)

-      return SZ_ERROR_UNSUPPORTED;

-  }

-  return SZ_OK;

-}

-

-static void BraState_Init(void *pp)

-{

-  CBraState *p = ((CBraState *)pp);

-  p->bufPos = p->bufConv = p->bufTotal = 0;

-  x86_Convert_Init(p->x86State);

-  if (p->methodId == XZ_ID_Delta)

-    Delta_Init(p->deltaState);

-}

-

-

-#define CASE_BRA_CONV(isa) case XZ_ID_ ## isa: size = isa ## _Convert(data, size, p->ip, p->encodeMode); break;

-

-static SizeT BraState_Filter(void *pp, Byte *data, SizeT size)

-{

-  CBraState *p = ((CBraState *)pp);

-  switch (p->methodId)

-  {

-    case XZ_ID_Delta:

-      if (p->encodeMode)

-        Delta_Encode(p->deltaState, p->delta, data, size);

-      else

-        Delta_Decode(p->deltaState, p->delta, data, size);

-      break;

-    case XZ_ID_X86:

-      size = x86_Convert(data, size, p->ip, &p->x86State, p->encodeMode);

-      break;

-    CASE_BRA_CONV(PPC)

-    CASE_BRA_CONV(IA64)

-    CASE_BRA_CONV(ARM)

-    CASE_BRA_CONV(ARMT)

-    CASE_BRA_CONV(SPARC)

-  }

-  p->ip += (UInt32)size;

-  return size;

-}

-

-

-static SRes BraState_Code2(void *pp,

-    Byte *dest, SizeT *destLen,

-    const Byte *src, SizeT *srcLen, int srcWasFinished,

-    ECoderFinishMode finishMode,

-    // int *wasFinished

-    ECoderStatus *status)

-{

-  CBraState *p = ((CBraState *)pp);

-  SizeT destRem = *destLen;

-  SizeT srcRem = *srcLen;

-  UNUSED_VAR(finishMode);

-

-  *destLen = 0;

-  *srcLen = 0;

-  // *wasFinished = False;

-  *status = CODER_STATUS_NOT_FINISHED;

-  

-  while (destRem > 0)

-  {

-    if (p->bufPos != p->bufConv)

-    {

-      size_t size = p->bufConv - p->bufPos;

-      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 = BraState_Filter(pp, 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;

-}

-

-

-SRes BraState_SetFromMethod(IStateCoder *p, UInt64 id, int encodeMode, ISzAllocPtr alloc)

-{

-  CBraState *decoder;

-  if (id < XZ_ID_Delta || id > XZ_ID_SPARC)

-    return SZ_ERROR_UNSUPPORTED;

-  decoder = (CBraState *)p->p;

-  if (!decoder)

-  {

-    decoder = (CBraState *)ISzAlloc_Alloc(alloc, sizeof(CBraState));

-    if (!decoder)

-      return SZ_ERROR_MEM;

-    p->p = decoder;

-    p->Free = BraState_Free;

-    p->SetProps = BraState_SetProps;

-    p->Init = BraState_Init;

-    p->Code2 = BraState_Code2;

-    p->Filter = BraState_Filter;

-  }

-  decoder->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;

-  switch (methodId)

-  {

-    case XZ_ID_LZMA2: return Lzma2State_SetFromMethod(sc, outBuf, outBufSize, p->alloc);

-    #ifdef USE_SUBBLOCK

-    case XZ_ID_Subblock: return SbState_SetFromMethod(sc, p->alloc);

-    #endif

-  }

-  if (coderIndex == 0)

-    return SZ_ERROR_UNSUPPORTED;

-  return BraState_SetFromMethod(sc, methodId, 0, p->alloc);

-}

-

-

-static SRes MixCoder_ResetFromMethod(CMixCoder *p, unsigned coderIndex, UInt64 methodId, Byte *outBuf, size_t outBufSize)

-{

-  IStateCoder *sc = &p->coders[coderIndex];

-  switch (methodId)

-  {

-    case 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) \

-  { 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)

-{

-  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 (f->id < XZ_ID_Delta

-        || f->id > XZ_ID_SPARC

-        || (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 = 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 (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 = ((UInt32)p->buf[0] << 2) + 4;

-          break;

-        }

-        

-        if (p->pos != p->blockHeaderSize)

-        {

-          UInt32 cur = p->blockHeaderSize - p->pos;

-          if (cur > srcRem)

-            cur = (UInt32)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

-        {

-          UInt32 checkSize = XzFlags_GetCheckSize(p->streamFlags);

-          UInt32 cur = checkSize - p->pos;

-          if (cur != 0)

-          {

-            if (srcRem == 0)

-            {

-              *status = CODER_STATUS_NEEDS_MORE_INPUT;

-              return SZ_OK;

-            }

-            if (cur > srcRem)

-              cur = (UInt32)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

-        {

-          p->state = XZ_STATE_STREAM_FOOTER;

-          p->pos = 0;

-          if (CRC_GET_DIGEST(p->crc) != GetUi32(p->buf))

-            return SZ_ERROR_CRC;

-        }

-        break;

-      }

-

-      case XZ_STATE_STREAM_FOOTER:

-      {

-        UInt32 cur = XZ_STREAM_FOOTER_SIZE - p->pos;

-        if (cur > srcRem)

-          cur = (UInt32)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 */

-    }

-  }

-  /*

-  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 _7ZIP_ST

-#include "MtDec.h"

-#endif

-

-

-void XzDecMtProps_Init(CXzDecMtProps *p)

-{

-  p->inBufSize_ST = 1 << 18;

-  p->outStep_ST = 1 << 20;

-  p->ignoreErrors = False;

-

-  #ifndef _7ZIP_ST

-  p->numThreads = 1;

-  p->inBufSize_MT = 1 << 18;

-  p->memUseMax = sizeof(size_t) << 28;

-  #endif

-}

-

-

-

-#ifndef _7ZIP_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 ---------- */

-

-typedef struct

-{

-  CAlignOffsetAlloc alignOffsetAlloc;

-  ISzAllocPtr allocMid;

-

-  CXzDecMtProps props;

-  size_t unpackBlockMaxSize;

-  

-  ISeqInStream *inStream;

-  ISeqOutStream *outStream;

-  ICompressProgress *progress;

-  // CXzStatInfo *stat;

-

-  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 _7ZIP_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;

-

-  BoolInt isBlockHeaderState_Parse;

-  BoolInt isBlockHeaderState_Write;

-  UInt64 outProcessed_Parse;

-  BoolInt parsing_Truncated;

-

-  BoolInt mtc_WasConstructed;

-  CMtDec mtc;

-  CXzDecMtThread coders[MTDEC__THREADS_MAX];

-  #endif

-

-} CXzDecMt;

-

-

-

-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 _7ZIP_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 p;

-}

-

-

-#ifndef _7ZIP_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;

-}

-

-

-void XzDecMt_Destroy(CXzDecMtHandle pp)

-{

-  CXzDecMt *p = (CXzDecMt *)pp;

-

-  XzDecMt_FreeSt(p);

-

-  #ifndef _7ZIP_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, pp);

-}

-

-

-

-#ifndef _7ZIP_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;

-          }

-        }

-        {

-        UInt64 packSize = block->packSize;

-        UInt64 packSizeAligned = packSize + ((0 - (unsigned)packSize) & 3);

-        UInt32 checkSize = XzFlags_GetCheckSize(coder->dec.streamFlags);

-        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 S_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 (coder->inCodeSize < coder->inPreHeaderSize)

-  {

-    UInt64 rem = coder->inPreHeaderSize - coder->inCodeSize;

-    size_t step = srcSize;

-    if (step > rem)

-      step = (size_t)rem;

-    src += step;

-    srcSize -= step;

-    coder->inCodeSize += step;

-    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 S_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,

-    // 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 = 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 = coderIndex;

-        return res;

-      }

-

-    RINOK(res);

-

-    if (coder->inPreSize != coder->inCodeSize

-        || coder->blockPackTotal != coder->inCodeSize)

-    {

-      me->finishedDecoderIndex = 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;

-      }

-      

-      res = XzUnpacker_Code(dec,

-          NULL, &outSizeCur,

-          src, &srcProcessed,

-          me->mtc.readWasFinished, // srcFinished

-          CODER_FINISH_END, // CODER_FINISH_ANY,

-          &status);

-      

-      me->status = status;

-      me->codeRes = res;

-

-      me->mtc.inProcessed += srcProcessed;

-      me->mtc.mtProgress.totalInSize = me->mtc.inProcessed;

-

-      if (res != SZ_OK)

-      {

-        return S_OK;

-        // return res;

-      }

-      

-      if (dec->state == XZ_STATE_STREAM_HEADER)

-      {

-        *needContinue = True;

-        me->isBlockHeaderState_Parse = False;

-        me->isBlockHeaderState_Write = False;

-        {

-          Byte *crossBuf = MtDec_GetCrossBuff(&me->mtc);

-          if (!crossBuf)

-            return SZ_ERROR_MEM;

-          memcpy(crossBuf, src + srcProcessed, srcSize - srcProcessed);

-        }

-        me->mtc.crossStart = 0;

-        me->mtc.crossEnd = srcSize - srcProcessed;

-        return SZ_OK;

-      }

-      

-      if (status != CODER_STATUS_NEEDS_MORE_INPUT)

-      {

-        return E_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;

-      // outProcessed = 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 *)inData, &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,

-            inData + 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 S_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 E_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->IsArc = False;

-  // p->UnexpectedEnd = False;

-  // p->Unsupported = False;

-  // p->HeadersError = False;

-  // p->DataError = False;

-  // p->CrcError = 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;

-}

-

-

-

-

-static SRes XzDecMt_Decode_ST(CXzDecMt *p

-    #ifndef _7ZIP_ST

-    , BoolInt tMode

-    #endif

-    , CXzStatInfo *stat)

-{

-  size_t outPos;

-  size_t inPos, inLim;

-  const Byte *inData;

-  UInt64 inPrev, outPrev;

-

-  CXzUnpacker *dec;

-

-  #ifndef _7ZIP_ST

-  if (tMode)

-  {

-    XzDecMt_FreeOutBufs(p);

-    tMode = 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 _7ZIP_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 *)inData, &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)

-      {

-        size_t written = ISeqOutStream_Write(p->outStream, p->outBuf, outPos);

-        p->outProcessed += written;

-        if (written != outPos)

-        {

-          stat->CombinedRes_Type = SZ_ERROR_WRITE;

-          return SZ_ERROR_WRITE;

-        }

-        outPos = 0;

-      }

-

-    if (p->progress && res == SZ_OK)

-    {

-      UInt64 inDelta = p->inProcessed - inPrev;

-      UInt64 outDelta = p->outProcessed - outPrev;

-      if (inDelta >= (1 << 22) || outDelta >= (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)

-      return res;

-  }

-}

-

-static SRes XzStatInfo_SetStat(const CXzUnpacker *dec,

-    int finishMode,

-    UInt64 readProcessed, UInt64 inProcessed,

-    SRes res, 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

-      extraSize = 0;

-      if (!XzUnpacker_IsStreamWasFinished(dec))

-        res = SZ_ERROR_INPUT_EOF;

-    }

-    else if (!decodingTruncated || finishMode) // (status == CODER_STATUS_NOT_FINISHED)

-      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 / inProcessed don't include "bad" byte

-    */

-    if (inProcessed != extraSize) // if good streams before error

-      if (extraSize != 0 || readProcessed != inProcessed)

-      {

-        stat->DataAfterEnd = True;

-        // there is some good xz stream before. So we set SZ_OK

-        res = SZ_OK;

-      }

-  }

-  

-  stat->DecodeRes = res;

-

-  stat->InSize -= extraSize;

-  return res;

-}

-

-

-SRes XzDecMt_Decode(CXzDecMtHandle pp,

-    const CXzDecMtProps *props,

-    const UInt64 *outDataSize, int finishMode,

-    ISeqOutStream *outStream,

-    // Byte *outBuf, size_t *outBufSize,

-    ISeqInStream *inStream,

-    // const Byte *inData, size_t inDataSize,

-    CXzStatInfo *stat,

-    int *isMT,

-    ICompressProgress *progress)

-{

-  CXzDecMt *p = (CXzDecMt *)pp;

-  #ifndef _7ZIP_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 = 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->codeRes = 0;

-  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 _7ZIP_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)

-  {

-    IMtDecCallback vt;

-

-    // 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;

-

-    {

-      BoolInt needContinue;

-      

-      SRes 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;

-        CXzUnpacker *dec;

-

-        stat->OutSize = p->outProcessed;

-       

-        if (p->finishedDecoderIndex >= 0)

-        {

-          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 E_FAIL;

-

-        XzStatInfo_SetStat(dec, p->finishMode,

-            p->mtc.readProcessed, p->mtc.inProcessed,

-            codeRes, status,

-            truncated,

-            stat);

-

-        if (res == SZ_OK)

-        {

-          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)

-          {

-            res = p->mtc.readRes;

-            stat->ReadRes = res;

-            stat->CombinedRes_Type = SZ_ERROR_READ;

-          }

-          else if (p->mainErrorCode != SZ_OK)

-          {

-            res = p->mainErrorCode;

-          }

-        }

-

-        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 _7ZIP_ST

-        , tMode

-        #endif

-        , stat

-        );

-

-    XzStatInfo_SetStat(&p->dec,

-        p->finishMode,

-        p->readProcessed, p->inProcessed,

-        p->codeRes, p->status,

-        False, // truncated

-        stat);

-

-    if (res == SZ_OK)

-    {

-      /*

-      if (p->writeRes != SZ_OK)

-      {

-        res = p->writeRes;

-        stat->CombinedRes_Type = SZ_ERROR_WRITE;

-      }

-      else

-      */

-      if (p->readRes != SZ_OK && p->inProcessed == p->readProcessed)

-      {

-        res = p->readRes;

-        stat->ReadRes = res;

-        stat->CombinedRes_Type = SZ_ERROR_READ;

-      }

-      #ifndef _7ZIP_ST

-      else if (p->mainErrorCode != SZ_OK)

-        res = p->mainErrorCode;

-      #endif

-    }

-

-    stat->CombinedRes = res;

-    if (stat->CombinedRes_Type == SZ_OK)

-      stat->CombinedRes_Type = res;

-    return res;

-  }

-}

+/* XzDec.c -- Xz Decode
+2023-04-13 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+// #include <stdio.h>
+
+// #define XZ_DUMP
+
+/* #define XZ_DUMP */
+
+#ifdef XZ_DUMP
+#include <stdio.h>
+#endif
+
+// #define SHOW_DEBUG_INFO
+
+#ifdef SHOW_DEBUG_INFO
+#include <stdio.h>
+#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 <stdlib.h>
+#include <string.h>
+
+#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 = (unsigned)props[0] + 1;
+  }
+  else
+  {
+    if (propSize == 4)
+    {
+      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) != 0)
+            return SZ_ERROR_UNSUPPORTED;
+          break;
+        case XZ_ID_ARMT:
+          if ((v & 1) != 0)
+            return SZ_ERROR_UNSUPPORTED;
+          break;
+        case XZ_ID_IA64:
+          if ((v & 0xF) != 0)
+            return SZ_ERROR_UNSUPPORTED;
+          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(PPC),
+  Z7_BRANCH_CONV_DEC(IA64),
+  Z7_BRANCH_CONV_DEC(ARM),
+  Z7_BRANCH_CONV_DEC(ARMT),
+  Z7_BRANCH_CONV_DEC(SPARC),
+  Z7_BRANCH_CONV_DEC(ARM64)
+};
+
+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_ARM64)
+     
+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;
+  switch (methodId)
+  {
+    case XZ_ID_LZMA2: return Lzma2State_SetFromMethod(sc, outBuf, outBufSize, p->alloc);
+    #ifdef USE_SUBBLOCK
+    case 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];
+  switch (methodId)
+  {
+    case 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) \
+  { 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 = 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 (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 = ((UInt32)p->buf[0] << 2) + 4;
+          break;
+        }
+        
+        if (p->pos != p->blockHeaderSize)
+        {
+          UInt32 cur = p->blockHeaderSize - p->pos;
+          if (cur > srcRem)
+            cur = (UInt32)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
+        {
+          UInt32 checkSize = XzFlags_GetCheckSize(p->streamFlags);
+          UInt32 cur = checkSize - p->pos;
+          if (cur != 0)
+          {
+            if (srcRem == 0)
+            {
+              *status = CODER_STATUS_NEEDS_MORE_INPUT;
+              return SZ_OK;
+            }
+            if (cur > srcRem)
+              cur = (UInt32)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:
+      {
+        UInt32 cur = XZ_STREAM_FOOTER_SIZE - p->pos;
+        if (cur > srcRem)
+          cur = (UInt32)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 */
+    }
+  }
+  /*
+  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;
+          }
+        }
+        {
+        UInt64 packSize = block->packSize;
+        UInt64 packSizeAligned = packSize + ((0 - (unsigned)packSize) & 3);
+        UInt32 checkSize = XzFlags_GetCheckSize(coder->dec.streamFlags);
+        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 = 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 = 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 309eca9..22408e2 100644
--- a/C/XzEnc.c
+++ b/C/XzEnc.c
@@ -1,1329 +1,1362 @@
-/* XzEnc.c -- Xz Encode

-2019-02-02 : Igor Pavlov : Public domain */

-

-#include "Precomp.h"

-

-#include <stdlib.h>

-#include <string.h>

-

-#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 _7ZIP_ST

-

-#ifndef _7ZIP_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)

-

-/* max pack size for LZMA2 block + check-64bytrs: */

-#define XZ_GET_MAX_BLOCK_PACK_SIZE(unpackSize) ((unpackSize) + ((unpackSize) >> 10) + 16 + 64)

-

-#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_SetNumFilters(p, n) (p)->flags |= ((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(ISeqOutStream *s, const void *buf, size_t size)

-{

-  return (ISeqOutStream_Write(s, buf, size) == size) ? SZ_OK : SZ_ERROR_WRITE;

-}

-

-static SRes WriteBytesUpdateCrc(ISeqOutStream *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, ISeqOutStream *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, ISeqOutStream *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, ISeqOutStream *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(WriteBytesUpdateCrc(s, buf, pos, &crc));

-  RINOK(WriteBytesUpdateCrc(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;

-  ISeqInStream *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(const ISeqInStream *pp, void *data, size_t *size)

-{

-  CSeqCheckInStream *p = CONTAINER_FROM_VTBL(pp, CSeqCheckInStream, vt);

-  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;

-  ISeqOutStream *realStream;

-  Byte *outBuf;

-  size_t outBufLimit;

-  UInt64 processed;

-} CSeqSizeOutStream;

-

-static size_t SeqSizeOutStream_Write(const ISeqOutStream *pp, const void *data, size_t size)

-{

-  CSeqSizeOutStream *p = CONTAINER_FROM_VTBL(pp, CSeqSizeOutStream, vt);

-  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 p;

-  ISeqInStream *realStream;

-  IStateCoder StateCoder;

-  Byte *buf;

-  size_t curPos;

-  size_t endPos;

-  int srcWasFinished;

-} CSeqInFilter;

-

-

-SRes BraState_SetFromMethod(IStateCoder *p, UInt64 id, int encodeMode, ISzAllocPtr alloc);

-

-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(BraState_SetFromMethod(&p->StateCoder, props->id, 1, 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(const ISeqInStream *pp, void *data, size_t *size)

-{

-  CSeqInFilter *p = CONTAINER_FROM_VTBL(pp, CSeqInFilter, p);

-  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->p.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;

-  ISeqInStream *inStream;

-  CSbEnc enc;

-} CSbEncInStream;

-

-static SRes SbEncInStream_Read(const ISeqInStream *pp, void *data, size_t *size)

-{

-  CSbEncInStream *p = 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 = (unsigned)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,

-    

-    ISeqOutStream *outStream,

-    Byte *outBufHeader,

-    Byte *outBufData, size_t outBufDataLimit,

-

-    ISeqInStream *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,

-    ICompressProgress *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_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)

-    {

-      SetUi32(filter->props, 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.p) :

-            &checkInStream.vt) : NULL,

-      

-        useStream ? NULL : inBuf,

-        useStream ? 0 : inBufSize,

-        

-        progress);

-    

-    if (outBuf)

-      seqSizeOutStream.processed += outSize;

-    

-    RINOK(res);

-    blockSizes->unpackSize = checkInStream.processed;

-  }

-  {

-    Byte buf[4 + 64];

-    unsigned padSize = XZ_GET_PAD_SIZE(seqSizeOutStream.processed);

-    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;

-  ICompressProgress *progress;

-  UInt64 inOffset;

-  UInt64 outOffset;

-} CCompressProgress_XzEncOffset;

-

-

-static SRes CompressProgress_XzEncOffset_Progress(const ICompressProgress *pp, UInt64 inSize, UInt64 outSize)

-{

-  const CCompressProgress_XzEncOffset *p = CONTAINER_FROM_VTBL(pp, CCompressProgress_XzEncOffset, vt);

-  inSize += p->inOffset;

-  outSize += p->outOffset;

-  return ICompressProgress_Progress(p->progress, inSize, outSize);

-}

-

-

-

-

-typedef struct

-{

-  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 _7ZIP_ST

-  unsigned checkType;

-  ISeqOutStream *outStream;

-  BoolInt mtCoder_WasConstructed;

-  CMtCoder mtCoder;

-  CXzEncBlockInfo EncBlocks[MTCODER__BLOCKS_MAX];

-  #endif

-

-} CXzEnc;

-

-

-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 _7ZIP_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 _7ZIP_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 p;

-}

-

-

-void XzEnc_Destroy(CXzEncHandle pp)

-{

-  CXzEnc *p = (CXzEnc *)pp;

-  XzEnc_Free(p, p->alloc);

-  ISzAlloc_Free(p->alloc, p);

-}

-

-

-SRes XzEnc_SetProps(CXzEncHandle pp, const CXzProps *props)

-{

-  CXzEnc *p = (CXzEnc *)pp;

-  p->xzProps = *props;

-  XzProps_Normalize(&p->xzProps);

-  return SZ_OK;

-}

-

-

-void XzEnc_SetDataSize(CXzEncHandle pp, UInt64 expectedDataSiize)

-{

-  CXzEnc *p = (CXzEnc *)pp;

-  p->expectedDataSize = expectedDataSiize;

-}

-

-

-

-

-#ifndef _7ZIP_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 = me->outBufs[outBufIndex];

-

-  UNUSED_VAR(finished)

-

-  {

-    CXzEncBlockInfo *bInfo = &me->EncBlocks[outBufIndex];

-    bInfo->totalSize = 0;

-    bInfo->unpackSize = 0;

-    bInfo->headerSize = 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;

-  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];

-  const Byte *data = me->outBufs[outBufIndex];

-

-  RINOK(WriteBytes(me->outStream, data, bInfo->headerSize));

-

-  {

-    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 pp, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress)

-{

-  CXzEnc *p = (CXzEnc *)pp;

-

-  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 _7ZIP_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 = 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(ISeqOutStream *outStream, ISeqInStream *inStream,

-    const CXzProps *props, ICompressProgress *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(ISeqOutStream *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
+2023-04-13 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#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)
+
+/* max pack size for LZMA2 block + check-64bytrs: */
+#define XZ_GET_MAX_BLOCK_PACK_SIZE(unpackSize) ((unpackSize) + ((unpackSize) >> 10) + 16 + 64)
+
+#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(PPC),
+  Z7_BRANCH_CONV_ENC(IA64),
+  Z7_BRANCH_CONV_ENC(ARM),
+  Z7_BRANCH_CONV_ENC(ARMT),
+  Z7_BRANCH_CONV_ENC(SPARC),
+  Z7_BRANCH_CONV_ENC(ARM64)
+};
+
+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 + 64];
+    unsigned padSize = XZ_GET_PAD_SIZE(seqSizeOutStream.processed);
+    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 = me->outBufs[outBufIndex];
+
+  UNUSED_VAR(finished)
+
+  {
+    CXzEncBlockInfo *bInfo = &me->EncBlocks[outBufIndex];
+    bInfo->totalSize = 0;
+    bInfo->unpackSize = 0;
+    bInfo->headerSize = 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;
+  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];
+  const Byte *data = me->outBufs[outBufIndex];
+
+  RINOK(WriteBytes(me->outStream, data, bInfo->headerSize))
+
+  {
+    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 529ac3f..77b78c0 100644
--- a/C/XzEnc.h
+++ b/C/XzEnc.h
@@ -1,60 +1,61 @@
-/* XzEnc.h -- Xz Encode

-2017-06-27 : Igor Pavlov : Public domain */

-

-#ifndef __XZ_ENC_H

-#define __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 void * 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, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress);

-

-SRes Xz_Encode(ISeqOutStream *outStream, ISeqInStream *inStream,

-    const CXzProps *props, ICompressProgress *progress);

-

-SRes Xz_EncodeEmpty(ISeqOutStream *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 792a617..d0fc763 100644
--- a/C/XzIn.c
+++ b/C/XzIn.c
@@ -1,319 +1,340 @@
-/* XzIn.c - Xz input

-2018-07-04 : Igor Pavlov : Public domain */

-

-#include "Precomp.h"

-

-#include <string.h>

-

-#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, ISeqInStream *inStream)

-{

-  Byte sig[XZ_STREAM_HEADER_SIZE];

-  RINOK(SeqInStream_Read2(inStream, sig, XZ_STREAM_HEADER_SIZE, SZ_ERROR_NO_ARCHIVE));

-  if (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) \

-  { unsigned s = Xz_ReadVarInt(buf + pos, size - pos, res); \

-  if (s == 0) return SZ_ERROR_ARCHIVE; pos += s; }

-

-SRes XzBlock_ReadHeader(CXzBlock *p, ISeqInStream *inStream, BoolInt *isIndex, UInt32 *headerSizeRes)

-{

-  Byte header[XZ_BLOCK_HEADER_SIZE_MAX];

-  unsigned headerSize;

-  *headerSizeRes = 0;

-  RINOK(SeqInStream_ReadByte(inStream, &header[0]));

-  headerSize = (unsigned)header[0];

-  if (headerSize == 0)

-  {

-    *headerSizeRes = 1;

-    *isIndex = True;

-    return SZ_OK;

-  }

-

-  *isIndex = False;

-  headerSize = (headerSize << 2) + 4;

-  *headerSizeRes = headerSize;

-  RINOK(SeqInStream_Read(inStream, header + 1, headerSize - 1));

-  return XzBlock_Parse(p, header);

-}

-

-#define ADD_SIZE_CHECK(size, val) \

-  { 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, ISeqInStream *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, ILookInStream *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(ILookInStream *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, ILookInStream *stream, Int64 *startOffset, ISzAllocPtr alloc)

-{

-  UInt64 indexSize;

-  Byte buf[XZ_STREAM_FOOTER_SIZE];

-  UInt64 pos = *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;

-

-  if (GetUi32(buf) != 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 = 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, ILookInStream *stream, Int64 *startOffset, ICompressProgress *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 = *startOffset;

-    RINOK(res);

-    if (p->num == p->numAllocated)

-    {

-      size_t newNum = p->num + p->num / 4 + 1;

-      Byte *data = (Byte *)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, *startOffset));

-    if (progress && ICompressProgress_Progress(progress, endOffset - *startOffset, (UInt64)(Int64)-1) != SZ_OK)

-      return SZ_ERROR_PROGRESS;

-  }

-  return SZ_OK;

-}

+/* XzIn.c - Xz input
+2023-04-02 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include <string.h>
+
+#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) \
+  { 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 = (unsigned)header[0];
+  if (headerSize == 0)
+  {
+    *headerSizeRes = 1;
+    *isIndex = True;
+    return SZ_OK;
+  }
+
+  *isIndex = False;
+  headerSize = (headerSize << 2) + 4;
+  *headerSizeRes = 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) \
+  { 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/var_clang.mak b/C/var_clang.mak
new file mode 100644
index 0000000..a6df26e
--- /dev/null
+++ b/C/var_clang.mak
@@ -0,0 +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
diff --git a/C/var_clang_arm64.mak b/C/var_clang_arm64.mak
new file mode 100644
index 0000000..4b35409
--- /dev/null
+++ b/C/var_clang_arm64.mak
@@ -0,0 +1,11 @@
+PLATFORM=arm64
+O=b/c_$(PLATFORM)
+IS_X64=
+IS_X86=
+IS_ARM64=1
+CROSS_COMPILE=
+MY_ARCH=
+USE_ASM=1
+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
new file mode 100644
index 0000000..34e1b49
--- /dev/null
+++ b/C/var_clang_x64.mak
@@ -0,0 +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
diff --git a/C/var_clang_x86.mak b/C/var_clang_x86.mak
new file mode 100644
index 0000000..bd2317c
--- /dev/null
+++ b/C/var_clang_x86.mak
@@ -0,0 +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
diff --git a/C/var_gcc.mak b/C/var_gcc.mak
new file mode 100644
index 0000000..664491c
--- /dev/null
+++ b/C/var_gcc.mak
@@ -0,0 +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
diff --git a/C/var_gcc_arm64.mak b/C/var_gcc_arm64.mak
new file mode 100644
index 0000000..4bbb687
--- /dev/null
+++ b/C/var_gcc_arm64.mak
@@ -0,0 +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
diff --git a/C/var_gcc_x64.mak b/C/var_gcc_x64.mak
new file mode 100644
index 0000000..1acf604
--- /dev/null
+++ b/C/var_gcc_x64.mak
@@ -0,0 +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++
diff --git a/C/var_gcc_x86.mak b/C/var_gcc_x86.mak
new file mode 100644
index 0000000..f0718ec
--- /dev/null
+++ b/C/var_gcc_x86.mak
@@ -0,0 +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++
diff --git a/C/var_mac_arm64.mak b/C/var_mac_arm64.mak
new file mode 100644
index 0000000..adf5fa1
--- /dev/null
+++ b/C/var_mac_arm64.mak
@@ -0,0 +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
diff --git a/C/var_mac_x64.mak b/C/var_mac_x64.mak
new file mode 100644
index 0000000..13d7aa7
--- /dev/null
+++ b/C/var_mac_x64.mak
@@ -0,0 +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
diff --git a/C/warn_clang.mak b/C/warn_clang.mak
new file mode 100644
index 0000000..0d6446d
--- /dev/null
+++ b/C/warn_clang.mak
@@ -0,0 +1 @@
+CFLAGS_WARN = -Weverything -Wfatal-errors
diff --git a/C/warn_clang_mac.mak b/C/warn_clang_mac.mak
new file mode 100644
index 0000000..44afc53
--- /dev/null
+++ b/C/warn_clang_mac.mak
@@ -0,0 +1 @@
+CFLAGS_WARN = -Weverything -Wfatal-errors -Wno-poison-system-directories
diff --git a/C/warn_gcc.mak b/C/warn_gcc.mak
new file mode 100644
index 0000000..7aab7a4
--- /dev/null
+++ b/C/warn_gcc.mak
@@ -0,0 +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)
diff --git a/CPP/7zip/7zip.mak b/CPP/7zip/7zip.mak
index 7fec27c..6f4a0a1 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) \

-  $(AR_OBJS) \

-  $(AR_COMMON_OBJS) \

-  $(UI_COMMON_OBJS) \

-  $(AGENT_OBJS) \

-  $(CONSOLE_OBJS) \

-  $(EXPLORER_OBJS) \

-  $(FM_OBJS) \

-  $(GUI_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)

-!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)

-!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)

-{../../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)

-

-{../../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)
+!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)
+!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)
+{../../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)
+
+{../../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
new file mode 100644
index 0000000..8bf0594
--- /dev/null
+++ b/CPP/7zip/7zip_gcc.mak
@@ -0,0 +1,1294 @@
+# 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
+CFLAGS_BASE_LIST = -c
+# CFLAGS_BASE_LIST = -S
+CFLAGS_BASE = -O2 $(CFLAGS_BASE_LIST) $(CFLAGS_WARN_WALL) $(CFLAGS_WARN) \
+ -DNDEBUG -D_REENTRANT -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE \
+ -fPIC
+
+FLAGS_FLTO = -ffunction-sections
+FLAGS_FLTO = -flto
+FLAGS_FLTO =
+# 
+# -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 = -DNDEBUG $(LDFLAGS_STATIC_2)
+
+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)
+# -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)
+
+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 -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 $(<F)).o
+
+else  # IS_MINGW
+
+ifdef IS_X64
+AFLAGS_ABI = -elf64 -DABI_LINUX
+else
+AFLAGS_ABI = -elf -DABI_LINUX -DABI_CDECL
+# -DABI_CDECL
+# -DABI_LINUX
+# -DABI_CDECL
+endif
+AFLAGS = -nologo $(AFLAGS_ABI) -Fo$(O)/
+
+endif  # IS_MINGW
+
+
+
+ifdef USE_ASM
+CONSOLE_ASM_FLAGS=-DZ7_7ZIP_ASM
+else
+CONSOLE_ASM_FLAGS=
+endif
+
+CXX_WARN_FLAGS =
+#-Wno-invalid-offsetof
+#-Wno-reorder
+
+CXXFLAGS = $(MY_ARCH_2) $(LOCAL_FLAGS) $(CXXFLAGS_BASE2) $(CFLAGS_BASE) $(FLAGS_FLTO) $(CXXFLAGS_EXTRA) $(CC_SHARED) $(CXX_WARN_FLAGS) $(CXX_STD_FLAGS) -o $@
+
+STATIC_TARGET=
+ifdef COMPL_STATIC
+STATIC_TARGET=$(PROGPATH_STATIC)
+endif
+
+
+all: $(O) $(PROGPATH) $(STATIC_TARGET)
+
+$(O):
+	$(MY_MKDIR) $(O)
+
+# LDFLAGS3= -flto
+# LDFLAGS3= -Wl,--gc-sections
+# -Wl,--print-gc-sections
+
+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)
+
+# -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/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/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/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) $<
+$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/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/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/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/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
+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) $<
+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 3d0d877..7d8da2d 100644
--- a/CPP/7zip/Aes.mak
+++ b/CPP/7zip/Aes.mak
@@ -1,7 +1,10 @@
-C_OBJS = $(C_OBJS) \

-  $O\Aes.obj

-

-!IF "$(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
new file mode 100644
index 0000000..2c3e144
--- /dev/null
+++ b/CPP/7zip/Archive/7z/7z.dsp
@@ -0,0 +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
diff --git a/CPP/7zip/Archive/7z/7z.dsw b/CPP/7zip/Archive/7z/7z.dsw
new file mode 100644
index 0000000..702a86c
--- /dev/null
+++ b/CPP/7zip/Archive/7z/7z.dsw
@@ -0,0 +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>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/CPP/7zip/Archive/7z/7zCompressionMode.cpp b/CPP/7zip/Archive/7z/7zCompressionMode.cpp
index 232c638..6774fc4 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 2360017..ac1f6ad 100644
--- a/CPP/7zip/Archive/7z/7zCompressionMode.h
+++ b/CPP/7zip/Archive/7z/7zCompressionMode.h
@@ -1,76 +1,91 @@
-// 7zCompressionMode.h

-

-#ifndef __7Z_COMPRESSION_MODE_H

-#define __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;

-

-  CMethodFull(): CodecIndex(-1) {}

-  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<CMethodFull> Methods;

-  CRecordVector<CBond2> 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;

-

-  #ifndef _7ZIP_ST

-  UInt32 NumThreads;

-  bool MultiThreadMixer;

-  #endif

-  

-  bool PasswordIsDefined;

-  UString Password;

-

-  bool IsEmpty() const { return (Methods.IsEmpty() && !PasswordIsDefined); }

-  CCompressionMethodMode():

-      DefaultMethod_was_Inserted(false),

-      Filter_was_Inserted(false),

-      PasswordIsDefined(false)

-      #ifndef _7ZIP_ST

-      , NumThreads(1)

-      , MultiThreadMixer(true)

-      #endif

-  {}

-};

-

-}}

-

-#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<CMethodFull> Methods;
+  CRecordVector<CBond2> 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;
+
+  #ifndef Z7_ST
+  UInt32 NumThreads;
+  bool NumThreads_WasForced;
+  bool MultiThreadMixer;
+  #endif
+
+  UInt64 MemoryUsageLimit;
+  bool MemoryUsageLimit_WasSet;
+  
+  bool PasswordIsDefined;
+  UString Password; // _Wipe
+
+  bool IsEmpty() const { return (Methods.IsEmpty() && !PasswordIsDefined); }
+  CCompressionMethodMode():
+        DefaultMethod_was_Inserted(false)
+      , Filter_was_Inserted(false)
+      #ifndef Z7_ST
+      , NumThreads(1)
+      , NumThreads_WasForced(false)
+      , MultiThreadMixer(true)
+      #endif
+      , MemoryUsageLimit((UInt64)1 << 30)
+      , MemoryUsageLimit_WasSet(false)
+      , PasswordIsDefined(false)
+  {}
+
+#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 f61ad4a..5420dce 100644
--- a/CPP/7zip/Archive/7z/7zDecode.cpp
+++ b/CPP/7zip/Archive/7z/7zDecode.cpp
@@ -1,569 +1,599 @@
-// 7zDecode.cpp

-

-#include "StdAfx.h"

-

-#include "../../Common/LimitedStreams.h"

-#include "../../Common/ProgressUtils.h"

-#include "../../Common/StreamObjects.h"

-

-#include "7zDecode.h"

-

-namespace NArchive {

-namespace N7z {

-

-class CDecProgress:

-  public ICompressProgressInfo,

-  public CMyUnknownImp

-{

-  CMyComPtr<ICompressProgressInfo> _progress;

-public:

-  CDecProgress(ICompressProgressInfo *progress): _progress(progress) {}

-  

-  MY_UNKNOWN_IMP1(ICompressProgressInfo)

-  STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);

-};

-

-STDMETHODIMP 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),

-    _useMixerMT(useMixerMT)

-{}

-

-

-struct CLockedInStream:

-  public IUnknown,

-  public CMyUnknownImp

-{

-  CMyComPtr<IInStream> Stream;

-  UInt64 Pos;

-

-  MY_UNKNOWN_IMP

-

-  #ifdef USE_MIXER_MT

-  NWindows::NSynchronization::CCriticalSection CriticalSection;

-  #endif

-};

-

-

-#ifdef USE_MIXER_MT

-

-class CLockedSequentialInStreamMT:

-  public ISequentialInStream,

-  public CMyUnknownImp

-{

-  CLockedInStream *_glob;

-  UInt64 _pos;

-  CMyComPtr<IUnknown> _globRef;

-public:

-  void Init(CLockedInStream *lockedInStream, UInt64 startPos)

-  {

-    _globRef = lockedInStream;

-    _glob = lockedInStream;

-    _pos = startPos;

-  }

-

-  MY_UNKNOWN_IMP1(ISequentialInStream)

-

-  STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);

-};

-

-STDMETHODIMP CLockedSequentialInStreamMT::Read(void *data, UInt32 size, UInt32 *processedSize)

-{

-  NWindows::NSynchronization::CCriticalSectionLock lock(_glob->CriticalSection);

-

-  if (_pos != _glob->Pos)

-  {

-    RINOK(_glob->Stream->Seek(_pos, STREAM_SEEK_SET, NULL));

-    _glob->Pos = _pos;

-  }

-

-  UInt32 realProcessedSize = 0;

-  HRESULT res = _glob->Stream->Read(data, size, &realProcessedSize);

-  _pos += realProcessedSize;

-  _glob->Pos = _pos;

-  if (processedSize)

-    *processedSize = realProcessedSize;

-  return res;

-}

-

-#endif

-

-

-#ifdef USE_MIXER_ST

-

-class CLockedSequentialInStreamST:

-  public ISequentialInStream,

-  public CMyUnknownImp

-{

-  CLockedInStream *_glob;

-  UInt64 _pos;

-  CMyComPtr<IUnknown> _globRef;

-public:

-  void Init(CLockedInStream *lockedInStream, UInt64 startPos)

-  {

-    _globRef = lockedInStream;

-    _glob = lockedInStream;

-    _pos = startPos;

-  }

-

-  MY_UNKNOWN_IMP1(ISequentialInStream)

-

-  STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);

-};

-

-STDMETHODIMP CLockedSequentialInStreamST::Read(void *data, UInt32 size, UInt32 *processedSize)

-{

-  if (_pos != _glob->Pos)

-  {

-    RINOK(_glob->Stream->Seek(_pos, STREAM_SEEK_SET, NULL));

-    _glob->Pos = _pos;

-  }

-

-  UInt32 realProcessedSize = 0;

-  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

-    

-    _7Z_DECODER_CRYPRO_VARS_DECL

-

-    #if !defined(_7ZIP_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 _NO_CRYPTO

-  isEncrypted = false;

-  passwordIsDefined = false;

-  #endif

-  */

-  

-  if (!_bindInfoPrev_Defined || !AreBindInfoExEqual(bindInfo, _bindInfoPrev))

-  {

-    _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 _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 EXTERNAL_CODECS

-      CMyComPtr<ISetCompressCodecsInfo> 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;

-  }

-

-  _mixer->ReInit();

-  

-  UInt32 packStreamIndex = 0;

-  UInt32 unpackStreamIndexStart = folders.FoToCoderUnpackSizes[folderIndex];

-

-  unsigned i;

-

-  #if !defined(_7ZIP_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();

-

-    #if !defined(_7ZIP_ST)

-    if (!mt_wasUsed)

-    {

-      if (mtMode)

-      {

-        CMyComPtr<ICompressSetCoderMt> setCoderMt;

-        decoder->QueryInterface(IID_ICompressSetCoderMt, (void **)&setCoderMt);

-        if (setCoderMt)

-        {

-          mt_wasUsed = true;

-          RINOK(setCoderMt->SetNumberOfThreads(numThreads));

-        }

-      }

-      // if (memUsage != 0)

-      {

-        CMyComPtr<ICompressSetMemLimit> setMemLimit;

-        decoder->QueryInterface(IID_ICompressSetMemLimit, (void **)&setMemLimit);

-        if (setMemLimit)

-        {

-          mt_wasUsed = true;

-          RINOK(setMemLimit->SetMemLimit(memUsage));

-        }

-      }

-    }

-    #endif

-

-    {

-      CMyComPtr<ICompressSetDecoderProperties2> setDecoderProperties;

-      decoder->QueryInterface(IID_ICompressSetDecoderProperties2, (void **)&setDecoderProperties);

-      if (setDecoderProperties)

-      {

-        const CByteBuffer &props = coderInfo.Props;

-        size_t size = props.Size();

-        if (size > 0xFFFFFFFF)

-          return E_NOTIMPL;

-        HRESULT res = setDecoderProperties->SetDecoderProperties2((const Byte *)props, (UInt32)size);

-        if (res == E_INVALIDARG)

-          res = E_NOTIMPL;

-        RINOK(res);

-      }

-    }

-

-    #ifndef _NO_CRYPTO

-    {

-      CMyComPtr<ICryptoSetPassword> cryptoSetPassword;

-      decoder->QueryInterface(IID_ICryptoSetPassword, (void **)&cryptoSetPassword);

-      if (cryptoSetPassword)

-      {

-        isEncrypted = true;

-        if (!getTextPassword)

-          return E_NOTIMPL;

-        CMyComBSTR passwordBSTR;

-        RINOK(getTextPassword->CryptoGetTextPassword(&passwordBSTR));

-        passwordIsDefined = true;

-        password.Empty();

-        size_t len = 0;

-        if (passwordBSTR)

-        {

-          password = passwordBSTR;

-          len = password.Len();

-        }

-        CByteBuffer buffer(len * 2);

-        for (size_t k = 0; k < len; k++)

-        {

-          wchar_t c = passwordBSTR[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;

-    {

-      CMyComPtr<ICompressSetFinishMode> setFinishMode;

-      decoder->QueryInterface(IID_ICompressSetFinishMode, (void **)&setFinishMode);

-      if (setFinishMode)

-      {

-        finishMode = fullUnpack;

-        RINOK(setFinishMode->SetFinishMode(BoolToInt(finishMode)));

-      }

-    }

-    

-    UInt32 numStreams = (UInt32)coderInfo.NumStreams;

-    

-    CObjArray<UInt64> packSizes(numStreams);

-    CObjArray<const UInt64 *> 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<ISequentialInStream> > inStreams;

-  

-  CLockedInStream *lockedInStreamSpec = new CLockedInStream;

-  CMyComPtr<IUnknown> lockedInStream = lockedInStreamSpec;

-

-  bool needMtLock = false;

-

-  if (folderInfo.PackStreams.Size() > 1)

-  {

-    // lockedInStream.Pos = (UInt64)(Int64)-1;

-    // RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &lockedInStream.Pos));

-    RINOK(inStream->Seek(startPos + packPositions[0], STREAM_SEEK_SET, &lockedInStreamSpec->Pos));

-    lockedInStreamSpec->Stream = inStream;

-

-    #ifdef USE_MIXER_ST

-    if (_mixer->IsThere_ExternalCoder_in_PackTree(_mixer->MainCoderIndex))

-    #endif

-      needMtLock = true;

-  }

-

-  for (unsigned j = 0; j < folderInfo.PackStreams.Size(); j++)

-  {

-    CMyComPtr<ISequentialInStream> packStream;

-    UInt64 packPos = startPos + packPositions[j];

-

-    if (folderInfo.PackStreams.Size() == 1)

-    {

-      RINOK(inStream->Seek(packPos, STREAM_SEEK_SET, NULL));

-      packStream = inStream;

-    }

-    else

-    {

-      #ifdef USE_MIXER_MT

-      #ifdef USE_MIXER_ST

-      if (_useMixerMT || needMtLock)

-      #endif

-      {

-        CLockedSequentialInStreamMT *lockedStreamImpSpec = new CLockedSequentialInStreamMT;

-        packStream = lockedStreamImpSpec;

-        lockedStreamImpSpec->Init(lockedInStreamSpec, packPos);

-      }

-      #ifdef USE_MIXER_ST

-      else

-      #endif

-      #endif

-      {

-        #ifdef USE_MIXER_ST

-        CLockedSequentialInStreamST *lockedStreamImpSpec = new CLockedSequentialInStreamST;

-        packStream = lockedStreamImpSpec;

-        lockedStreamImpSpec->Init(lockedInStreamSpec, packPos);

-        #endif

-      }

-    }

-

-    CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;

-    inStreams.AddNew() = streamSpec;

-    streamSpec->SetStream(packStream);

-    streamSpec->Init(packPositions[j + 1] - packPositions[j]);

-  }

-  

-  unsigned num = inStreams.Size();

-  CObjArray<ISequentialInStream *> inStreamPointers(num);

-  for (i = 0; i < num; i++)

-    inStreamPointers[i] = inStreams[i];

-

-  if (outStream)

-  {

-    CMyComPtr<ICompressProgressInfo> 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<ICompressProgressInfo> _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<IInStream> 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<IUnknown> _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<IUnknown> _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<ISetCompressCodecsInfo> 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);
+        for (size_t k = 0; k < len; k++)
+        {
+          const wchar_t c = passwordBSTR[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<UInt64> packSizes(numStreams);
+    CObjArray<const UInt64 *> 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<ISequentialInStream> > inStreams;
+  
+  CLockedInStream *lockedInStreamSpec = new CLockedInStream;
+  CMyComPtr<IUnknown> lockedInStream = lockedInStreamSpec;
+
+  #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, &lockedInStreamSpec->Pos))
+    lockedInStreamSpec->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<ISequentialInStream> 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(lockedInStreamSpec, packPos);
+      }
+      #ifdef USE_MIXER_ST
+      else
+      #endif
+      #endif
+      {
+        #ifdef USE_MIXER_ST
+        CLockedSequentialInStreamST *lockedStreamImpSpec = new CLockedSequentialInStreamST;
+        packStream = lockedStreamImpSpec;
+        lockedStreamImpSpec->Init(lockedInStreamSpec, 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<ISequentialInStream *> inStreamPointers(num);
+  for (i = 0; i < num; i++)
+    inStreamPointers[i] = inStreams[i];
+
+  if (outStream)
+  {
+    CMyComPtr<ICompressProgressInfo> 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 944f8a3..ee9d9c2 100644
--- a/CPP/7zip/Archive/7z/7zDecode.h
+++ b/CPP/7zip/Archive/7z/7zDecode.h
@@ -1,70 +1,73 @@
-// 7zDecode.h

-

-#ifndef __7Z_DECODE_H

-#define __7Z_DECODE_H

-

-#include "../Common/CoderMixer2.h"

-

-#include "7zIn.h"

-

-namespace NArchive {

-namespace N7z {

-

-struct CBindInfoEx: public NCoderMixer2::CBindInfo

-{

-  CRecordVector<CMethodId> CoderMethodIDs;

-

-  void Clear()

-  {

-    CBindInfo::Clear();

-    CoderMethodIDs.Clear();

-  }

-};

-

-class CDecoder

-{

-  bool _bindInfoPrev_Defined;

-  CBindInfoEx _bindInfoPrev;

-  

-  bool _useMixerMT;

-  

-  #ifdef USE_MIXER_ST

-    NCoderMixer2::CMixerST *_mixerST;

-  #endif

-  

-  #ifdef USE_MIXER_MT

-    NCoderMixer2::CMixerMT *_mixerMT;

-  #endif

-  

-  NCoderMixer2::CMixer *_mixer;

-  CMyComPtr<IUnknown> _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

-      

-      _7Z_DECODER_CRYPRO_VARS_DECL

-      

-      #if !defined(_7ZIP_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<CMethodId> 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<IUnknown> _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 4c0d221..78c91cf 100644
--- a/CPP/7zip/Archive/7z/7zEncode.cpp
+++ b/CPP/7zip/Archive/7z/7zEncode.cpp
@@ -1,678 +1,725 @@
-// 7zEncode.cpp

-

-#include "StdAfx.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)

-{

-  CMyComPtr<ICompressSetCoderProperties> setCoderProperties;

-  coder->QueryInterface(IID_ICompressSetCoderProperties, (void **)&setCoderProperties);

-  if (setCoderProperties)

-    return props.SetCoderProps(setCoderProperties, dataSizeReduce);

-  return props.AreThereNonOptionalProps() ? E_INVALIDARG : S_OK;

-}

-

-

-

-void CMtEncMultiProgress::Init(ICompressProgressInfo *progress)

-{

-  _progress = progress;

-  OutSize = 0;

-}

-

-STDMETHODIMP CMtEncMultiProgress::SetRatioInfo(const UInt64 *inSize, const UInt64 * /* outSize */)

-{

-  UInt64 outSize2;

-  {

-    #ifndef _7ZIP_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

-        methodFull.CodecIndex, true, cod));

-    }

-    else

-    {

-      RINOK(CreateCoder_Id(

-        EXTERNAL_CODECS_LOC_VARS

-        methodFull.Id, true, cod));

-    }

-

-    if (cod.NumStreams != methodFull.NumStreams)

-      return E_FAIL;

-    if (!cod.Coder && !cod.Coder2)

-      return E_FAIL;

-

-    CMyComPtr<IUnknown> encoderCommon = cod.Coder ? (IUnknown *)cod.Coder : (IUnknown *)cod.Coder2;

-   

-    #ifndef _7ZIP_ST

-    {

-      CMyComPtr<ICompressSetCoderMt> setCoderMt;

-      encoderCommon.QueryInterface(IID_ICompressSetCoderMt, &setCoderMt);

-      if (setCoderMt)

-      {

-        RINOK(setCoderMt->SetNumberOfThreads(_options.NumThreads));

-      }

-    }

-    #endif

-        

-    RINOK(SetCoderProps2(methodFull, inSizeForReduce, encoderCommon));

-

-    /*

-    CMyComPtr<ICryptoResetSalt> resetSalt;

-    encoderCommon.QueryInterface(IID_ICryptoResetSalt, (void **)&resetSalt);

-    if (resetSalt)

-    {

-      resetSalt->ResetSalt();

-    }

-    */

-

-    // now there is no codec that uses another external codec

-    /*

-    #ifdef EXTERNAL_CODECS

-    CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo;

-    encoderCommon.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo);

-    if (setCompressCodecsInfo)

-    {

-      // we must use g_ExternalCodecs also

-      RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(__externalCodecs->GetCodecs));

-    }

-    #endif

-    */

-    

-    CMyComPtr<ICryptoSetPassword> cryptoSetPassword;

-    encoderCommon.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword);

-

-    if (cryptoSetPassword)

-    {

-      const unsigned sizeInBytes = _options.Password.Len() * 2;

-      CByteBuffer 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;

-}

-

-

-

-class CSequentialOutTempBufferImp2:

-  public ISequentialOutStream,

-  public CMyUnknownImp

-{

-  CInOutTempBuffer *_buf;

-public:

-  CMtEncMultiProgress *_mtProgresSpec;

-  

-  CSequentialOutTempBufferImp2(): _buf(0), _mtProgresSpec(NULL) {}

-  void Init(CInOutTempBuffer *buffer) { _buf = buffer; }

-  MY_UNKNOWN_IMP1(ISequentialOutStream)

-

-  STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);

-};

-

-STDMETHODIMP CSequentialOutTempBufferImp2::Write(const void *data, UInt32 size, UInt32 *processed)

-{

-  if (!_buf->Write(data, size))

-  {

-    if (processed)

-      *processed = 0;

-    return E_FAIL;

-  }

-  if (processed)

-    *processed = size;

-  if (_mtProgresSpec)

-    _mtProgresSpec->AddOutSize(size);

-  return S_OK;

-}

-

-

-class CSequentialOutMtNotify:

-  public ISequentialOutStream,

-  public CMyUnknownImp

-{

-public:

-  CMyComPtr<ISequentialOutStream> _stream;

-  CMtEncMultiProgress *_mtProgresSpec;

-  

-  CSequentialOutMtNotify(): _mtProgresSpec(NULL) {}

-  MY_UNKNOWN_IMP1(ISequentialOutStream)

-

-  STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);

-};

-

-STDMETHODIMP CSequentialOutMtNotify::Write(const void *data, UInt32 size, UInt32 *processed)

-{

-  UInt32 realProcessed = 0;

-  HRESULT res = _stream->Write(data, size, &realProcessed);

-  if (processed)

-    *processed = realProcessed;

-  if (_mtProgresSpec)

-    _mtProgresSpec->AddOutSize(size);

-  return res;

-}

-

-

-

-HRESULT CEncoder::Encode(

-    DECL_EXTERNAL_CODECS_LOC_VARS

-    ISequentialInStream *inStream,

-    // const UInt64 *inStreamSize,

-    const UInt64 *inSizeForReduce,

-    CFolder &folderItem,

-    CRecordVector<UInt64> &coderUnpackSizes,

-    UInt64 &unpackSize,

-    ISequentialOutStream *outStream,

-    CRecordVector<UInt64> &packSizes,

-    ICompressProgressInfo *compressProgress)

-{

-  RINOK(EncoderConstr());

-

-  if (!_mixerRef)

-  {

-    RINOK(CreateMixerCoder(EXTERNAL_CODECS_LOC_VARS inSizeForReduce));

-  }

-  

-  _mixer->ReInit();

-

-  CMtEncMultiProgress *mtProgressSpec = NULL;

-  CMyComPtr<ICompressProgressInfo> mtProgress;

-

-  CSequentialOutMtNotify *mtOutStreamNotifySpec = NULL;

-  CMyComPtr<ISequentialOutStream> mtOutStreamNotify;

-

-  CObjectVector<CInOutTempBuffer> inOutTempBuffers;

-  CObjectVector<CSequentialOutTempBufferImp2 *> tempBufferSpecs;

-  CObjectVector<CMyComPtr<ISequentialOutStream> > tempBuffers;

-  

-  unsigned numMethods = _bindInfo.Coders.Size();

-  

-  unsigned i;

-

-  for (i = 1; i < _bindInfo.PackStreams.Size(); i++)

-  {

-    CInOutTempBuffer &iotb = inOutTempBuffers.AddNew();

-    iotb.Create();

-    iotb.InitWriting();

-  }

-  

-  for (i = 1; i < _bindInfo.PackStreams.Size(); i++)

-  {

-    CSequentialOutTempBufferImp2 *tempBufferSpec = new CSequentialOutTempBufferImp2;

-    CMyComPtr<ISequentialOutStream> tempBuffer = tempBufferSpec;

-    tempBufferSpec->Init(&inOutTempBuffers[i - 1]);

-    tempBuffers.Add(tempBuffer);

-    tempBufferSpecs.Add(tempBufferSpec);

-  }

-

-  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<ISequentialInStream> inStreamSizeCount = inStreamSizeCountSpec;

-

-  CSequentialOutStreamSizeCount *outStreamSizeCountSpec = NULL;

-  CMyComPtr<ISequentialOutStream> outStreamSizeCount;

-

-  inStreamSizeCountSpec->Init(inStream);

-

-  ISequentialInStream *inStreamPointer = inStreamSizeCount;

-  CRecordVector<ISequentialOutStream *> outStreamPointers;

-  

-  SetFolder(folderItem);

-

-  for (i = 0; i < numMethods; i++)

-  {

-    IUnknown *coder = _mixer->GetCoder(i).GetUnknown();

-

-    CMyComPtr<ICryptoResetInitVector> resetInitVector;

-    coder->QueryInterface(IID_ICryptoResetInitVector, (void **)&resetInitVector);

-    if (resetInitVector)

-    {

-      resetInitVector->ResetInitVector();

-    }

-

-    {

-      CMyComPtr<ICompressSetCoderPropertiesOpt> optProps;

-      coder->QueryInterface(IID_ICompressSetCoderPropertiesOpt, (void **)&optProps);

-      if (optProps)

-      {

-        PROPID propID = NCoderPropID::kExpectedDataSize;

-        NWindows::NCOM::CPropVariant prop = (UInt64)unpackSize;

-        RINOK(optProps->SetCoderPropertiesOpt(&propID, &prop, 1));

-      }

-    }

-

-    CMyComPtr<ICompressWriteCoderProperties> writeCoderProperties;

-    coder->QueryInterface(IID_ICompressWriteCoderProperties, (void **)&writeCoderProperties);

-

-    CByteBuffer &props = folderItem.Coders[numMethods - 1 - i].Props;

-

-    if (writeCoderProperties)

-    {

-      CDynBufSeqOutStream *outStreamSpec = new CDynBufSeqOutStream;

-      CMyComPtr<ISequentialOutStream> dynOutStream(outStreamSpec);

-      outStreamSpec->Init();

-      RINOK(writeCoderProperties->WriteCoderProperties(dynOutStream));

-      outStreamSpec->CopyToBuffer(props);

-    }

-    else

-      props.Free();

-  }

-

-  _mixer->SelectMainCoder(false);

-  UInt32 mainCoder = _mixer->MainCoderIndex;

-

-  bool useMtProgress = false;

-  if (!_mixer->Is_PackSize_Correct_for_Coder(mainCoder))

-  {

-    #ifdef _7ZIP_ST

-    if (!_mixer->IsThere_ExternalCoder_in_PackTree(mainCoder))

-    #endif

-      useMtProgress = true;

-  }

-

-  if (useMtProgress)

-  {

-    mtProgressSpec = new CMtEncMultiProgress;

-    mtProgress = mtProgressSpec;

-    mtProgressSpec->Init(compressProgress);

-    

-    mtOutStreamNotifySpec = new CSequentialOutMtNotify;

-    mtOutStreamNotify = mtOutStreamNotifySpec;

-    mtOutStreamNotifySpec->_stream = outStream;

-    mtOutStreamNotifySpec->_mtProgresSpec = mtProgressSpec;

-    

-    FOR_VECTOR(t, tempBufferSpecs)

-    {

-      tempBufferSpecs[t]->_mtProgresSpec = mtProgressSpec;

-    }

-  }

-  

-  

-  if (_bindInfo.PackStreams.Size() != 0)

-  {

-    outStreamSizeCountSpec = new CSequentialOutStreamSizeCount;

-    outStreamSizeCount = outStreamSizeCountSpec;

-    outStreamSizeCountSpec->SetStream(mtOutStreamNotify ? (ISequentialOutStream *)mtOutStreamNotify : 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.Front(),

-      mtProgress ? (ICompressProgressInfo *)mtProgress : compressProgress, dataAfterEnd_Error));

-  

-  if (_bindInfo.PackStreams.Size() != 0)

-    packSizes.Add(outStreamSizeCountSpec->GetSize());

-  

-  for (i = 1; i < _bindInfo.PackStreams.Size(); i++)

-  {

-    CInOutTempBuffer &inOutTempBuffer = inOutTempBuffers[i - 1];

-    RINOK(inOutTempBuffer.WriteToStream(outStream));

-    packSizes.Add(inOutTempBuffer.GetDataSize());

-  }

-

-  unpackSize = 0;

-  

-  for (i = 0; i < _bindInfo.Coders.Size(); i++)

-  {

-    int bond = _bindInfo.FindBond_for_UnpackStream(_DestOut_to_SrcIn[i]);

-    UInt64 streamSize;

-    if (bond < 0)

-    {

-      streamSize = inStreamSizeCountSpec->GetSize();

-      unpackSize = streamSize;

-    }

-    else

-      streamSize = _mixer->GetBondStreamSize(bond);

-    coderUnpackSizes.Add(streamSize);

-  }

-  

-  return S_OK;

-}

-

-

-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;

-      

-      UInt32 outIndex = _bindInfo.Coder_to_Stream[ci];

-      int bond = _bindInfo.FindBond_for_PackStream(outIndex);

-      if (bond >= 0)

-      {

-        ci = _bindInfo.Bonds[bond].UnpackIndex;

-        continue;

-      }

-      

-      int si = _bindInfo.FindStream_in_PackStreams(outIndex);

-      if (si >= 0)

-        _bindInfo.PackStreams.MoveToFront(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<IUnknown> encoderCommon = cod.Coder ? (IUnknown *)cod.Coder : (IUnknown *)cod.Coder2;
+   
+    #ifndef Z7_ST
+    if (methodFull.Set_NumThreads)
+    {
+      CMyComPtr<ICompressSetCoderMt> setCoderMt;
+      encoderCommon.QueryInterface(IID_ICompressSetCoderMt, &setCoderMt);
+      if (setCoderMt)
+      {
+        RINOK(setCoderMt->SetNumberOfThreads(
+            /* _options.NumThreads */
+            methodFull.NumThreads
+            ))
+      }
+    }
+    #endif
+        
+    RINOK(SetCoderProps2(methodFull, inSizeForReduce, encoderCommon))
+
+    /*
+    CMyComPtr<ICryptoResetSalt> 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<ISetCompressCodecsInfo> setCompressCodecsInfo;
+    encoderCommon.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo);
+    if (setCompressCodecsInfo)
+    {
+      // we must use g_ExternalCodecs also
+      RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(_externalCodecs->GetCodecs));
+    }
+    #endif
+    */
+    
+    CMyComPtr<ICryptoSetPassword> 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<ISequentialOutStream> _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)
+  {
+    CDynBufSeqOutStream *outStreamSpec = new CDynBufSeqOutStream;
+    CMyComPtr<ISequentialOutStream> dynOutStream(outStreamSpec);
+    outStreamSpec->Init();
+    RINOK(writeCoderProperties->WriteCoderProperties(dynOutStream))
+    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<UInt64> &coderUnpackSizes,
+    // UInt64 &unpackSize,
+    ISequentialOutStream *outStream,
+    CRecordVector<UInt64> &packSizes,
+    ICompressProgressInfo *compressProgress)
+{
+  RINOK(EncoderConstr())
+
+  if (!_mixerRef)
+  {
+    RINOK(CreateMixerCoder(EXTERNAL_CODECS_LOC_VARS inSizeForReduce))
+  }
+  
+  RINOK(_mixer->ReInit2())
+
+  CMtEncMultiProgress *mtProgressSpec = NULL;
+  CMyComPtr<ICompressProgressInfo> mtProgress;
+
+  CSequentialOutMtNotify *mtOutStreamNotifySpec = NULL;
+  CMyComPtr<ISequentialOutStream> mtOutStreamNotify;
+
+  CRecordVector<CSequentialOutTempBufferImp2 *> tempBufferSpecs;
+  CObjectVector<CMyComPtr<ISequentialOutStream> > tempBuffers;
+  
+  unsigned i;
+
+  for (i = 1; i < _bindInfo.PackStreams.Size(); i++)
+  {
+    CSequentialOutTempBufferImp2 *tempBufferSpec = new CSequentialOutTempBufferImp2();
+    CMyComPtr<ISequentialOutStream> 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<ISequentialInStream> inStreamSizeCount = inStreamSizeCountSpec;
+  */
+
+  CSequentialOutStreamSizeCount *outStreamSizeCountSpec = NULL;
+  CMyComPtr<ISequentialOutStream> outStreamSizeCount;
+
+  // inStreamSizeCountSpec->Init(inStream);
+
+  // ISequentialInStream *inStreamPointer = inStreamSizeCount;
+  ISequentialInStream *inStreamPointer = inStream;
+
+  CRecordVector<ISequentialOutStream *> 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)
+  {
+    mtProgressSpec = new CMtEncMultiProgress;
+    mtProgress = mtProgressSpec;
+    mtProgressSpec->Init(compressProgress);
+    
+    mtOutStreamNotifySpec = new CSequentialOutMtNotify;
+    mtOutStreamNotify = mtOutStreamNotifySpec;
+    mtOutStreamNotifySpec->_stream = outStream;
+    mtOutStreamNotifySpec->_mtProgressSpec = mtProgressSpec;
+    
+    FOR_VECTOR (t, tempBufferSpecs)
+    {
+      tempBufferSpecs[t]->_mtProgressSpec = mtProgressSpec;
+    }
+  }
+  
+  
+  if (_bindInfo.PackStreams.Size() != 0)
+  {
+    outStreamSizeCountSpec = new CSequentialOutStreamSizeCount;
+    outStreamSizeCount = outStreamSizeCountSpec;
+    outStreamSizeCountSpec->SetStream(mtOutStreamNotify ? (ISequentialOutStream *)mtOutStreamNotify : 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.Front(),
+      mtProgress ? (ICompressProgressInfo *)mtProgress : 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<UInt64> &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 434cbec..849ac63 100644
--- a/CPP/7zip/Archive/7z/7zEncode.h
+++ b/CPP/7zip/Archive/7z/7zEncode.h
@@ -1,92 +1,95 @@
-// 7zEncode.h

-

-#ifndef __7Z_ENCODE_H

-#define __7Z_ENCODE_H

-

-#include "7zCompressionMode.h"

-

-#include "../Common/CoderMixer2.h"

-

-#include "7zItem.h"

-

-namespace NArchive {

-namespace N7z {

-

-class CMtEncMultiProgress:

-  public ICompressProgressInfo,

-  public CMyUnknownImp

-{

-  CMyComPtr<ICompressProgressInfo> _progress;

-  #ifndef _7ZIP_ST

-  NWindows::NSynchronization::CCriticalSection CriticalSection;

-  #endif

-

-public:

-  UInt64 OutSize;

-

-  CMtEncMultiProgress(): OutSize(0) {}

-

-  void Init(ICompressProgressInfo *progress);

-

-  void AddOutSize(UInt64 addOutSize)

-  {

-    #ifndef _7ZIP_ST

-    NWindows::NSynchronization::CCriticalSectionLock lock(CriticalSection);

-    #endif

-    OutSize += addOutSize;

-  }

-

-  MY_UNKNOWN_IMP1(ICompressProgressInfo)

-

-  STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);

-};

-

-class CEncoder

-{

-  #ifdef USE_MIXER_ST

-    NCoderMixer2::CMixerST *_mixerST;

-  #endif

-  #ifdef USE_MIXER_MT

-    NCoderMixer2::CMixerMT *_mixerMT;

-  #endif

-  

-  NCoderMixer2::CMixer *_mixer;

-  CMyComPtr<IUnknown> _mixerRef;

-

-  CCompressionMethodMode _options;

-  NCoderMixer2::CBindInfo _bindInfo;

-  CRecordVector<CMethodId> _decompressionMethods;

-

-  CRecordVector<UInt32> _SrcIn_to_DestOut;

-  CRecordVector<UInt32> _SrcOut_to_DestIn;

-  // CRecordVector<UInt32> _DestIn_to_SrcOut;

-  CRecordVector<UInt32> _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 Encode(

-      DECL_EXTERNAL_CODECS_LOC_VARS

-      ISequentialInStream *inStream,

-      // const UInt64 *inStreamSize,

-      const UInt64 *inSizeForReduce,

-      CFolder &folderItem,

-      CRecordVector<UInt64> &coderUnpackSizes,

-      UInt64 &unpackSize,

-      ISequentialOutStream *outStream,

-      CRecordVector<UInt64> &packSizes,

-      ICompressProgressInfo *compressProgress);

-};

-

-}}

-

-#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<ICompressProgressInfo> _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<IUnknown> _mixerRef;
+
+  CCompressionMethodMode _options;
+  NCoderMixer2::CBindInfo _bindInfo;
+  CRecordVector<CMethodId> _decompressionMethods;
+
+  CRecordVector<UInt32> SrcIn_to_DestOut;
+  CRecordVector<UInt32> SrcOut_to_DestIn;
+  // CRecordVector<UInt32> DestIn_to_SrcOut;
+  CRecordVector<UInt32> 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<UInt64> &coderUnpackSizes,
+      // UInt64 &unpackSize,
+      ISequentialOutStream *outStream,
+      CRecordVector<UInt64> &packSizes,
+      ICompressProgressInfo *compressProgress);
+
+  void Encode_Post(
+      UInt64 unpackSize,
+      CRecordVector<UInt64> &coderUnpackSizes);
+
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/7z/7zExtract.cpp b/CPP/7zip/Archive/7z/7zExtract.cpp
index 075644f..5498c59 100644
--- a/CPP/7zip/Archive/7z/7zExtract.cpp
+++ b/CPP/7zip/Archive/7z/7zExtract.cpp
@@ -1,423 +1,445 @@
-// 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 {

-

-class CFolderOutStream:

-  public ISequentialOutStream,

-  public CMyUnknownImp

-{

-  CMyComPtr<ISequentialOutStream> _stream;

-public:

-  bool TestMode;

-  bool CheckCrc;

-private:

-  bool _fileIsOpen;

-  bool _calcCrc;

-  UInt32 _crc;

-  UInt64 _rem;

-

-  const UInt32 *_indexes;

-  unsigned _numFiles;

-  unsigned _fileIndex;

-

-  HRESULT OpenFile(bool isCorrupted = false);

-  HRESULT CloseFile_and_SetResult(Int32 res);

-  HRESULT CloseFile();

-  HRESULT ProcessEmptyFiles();

-

-public:

-  MY_UNKNOWN_IMP1(ISequentialOutStream)

-

-  const CDbEx *_db;

-  CMyComPtr<IArchiveExtractCallback> ExtractCallback;

-

-  bool ExtraWriteWasCut;

-

-  CFolderOutStream():

-      TestMode(false),

-      CheckCrc(true)

-      {}

-

-  STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);

-

-  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)

-{

-  _fileIndex = startIndex;

-  _indexes = indexes;

-  _numFiles = numFiles;

-  

-  _fileIsOpen = false;

-  ExtraWriteWasCut = false;

-  

-  return ProcessEmptyFiles();

-}

-

-HRESULT CFolderOutStream::OpenFile(bool isCorrupted)

-{

-  const CFileItem &fi = _db->Files[_fileIndex];

-  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<ISequentialOutStream> 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;

-}

-

-STDMETHODIMP 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;

-}

-

-STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,

-    Int32 testModeSpec, IArchiveExtractCallback *extractCallbackSpec)

-{

-  COM_TRY_BEGIN

-  

-  CMyComPtr<IArchiveExtractCallback> extractCallback = extractCallbackSpec;

-  

-  UInt64 importantTotalUnpacked = 0;

-

-  // numItems = (UInt32)(Int32)-1;

-

-  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++)

-    {

-      UInt32 fileIndex = allFilesMode ? i : indices[i];

-      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));

-

-  CLocalProgress *lps = new CLocalProgress;

-  CMyComPtr<ICompressProgressInfo> progress = lps;

-  lps->Init(extractCallback, false);

-

-  CDecoder decoder(

-    #if !defined(USE_MIXER_MT)

-      false

-    #elif !defined(USE_MIXER_ST)

-      true

-    #elif !defined(__7Z_SET_PROPERTIES)

-      #ifdef _7ZIP_ST

-        false

-      #else

-        true

-      #endif

-    #else

-      _useMultiThreadMixer

-    #endif

-    );

-

-  UInt64 curPacked, curUnpacked;

-

-  CMyComPtr<IArchiveExtractCallbackMessage> callbackMessage;

-  extractCallback.QueryInterface(IID_IArchiveExtractCallbackMessage, &callbackMessage);

-

-  CFolderOutStream *folderOutStream = new CFolderOutStream;

-  CMyComPtr<ISequentialOutStream> 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];

-    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++)

-      {

-        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;

-    }

-

-    {

-      HRESULT result = folderOutStream->Init(fileIndex,

-          allFilesMode ? NULL : indices + i,

-          numSolidFiles);

-

-      i += numSolidFiles;

-

-      RINOK(result);

-    }

-

-    // to test solid block with zero unpacked size we disable that code

-    if (folderOutStream->WasWritingFinished())

-      continue;

-

-    #ifndef _NO_CRYPTO

-    CMyComPtr<ICryptoGetTextPassword> getTextPassword;

-    if (extractCallback)

-      extractCallback.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword);

-    #endif

-

-    try

-    {

-      #ifndef _NO_CRYPTO

-        bool isEncrypted = false;

-        bool passwordIsDefined = false;

-        UString password;

-      #endif

-

-

-      bool dataAfterEnd_Error = false;

-

-      HRESULT result = decoder.Decode(

-          EXTERNAL_CODECS_VARS

-          _inStream,

-          _db.ArcInfo.DataStartPosition,

-          _db, folderIndex,

-          &curUnpacked,

-

-          outStream,

-          progress,

-          NULL // *inStreamMainRes

-          , dataAfterEnd_Error

-          

-          _7Z_DECODER_CRYPRO_VARS

-          #if !defined(_7ZIP_ST)

-            , true, _numThreads, _memUsage

-          #endif

-          );

-

-      if (result == S_FALSE || result == E_NOTIMPL || dataAfterEnd_Error)

-      {

-        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;

-    }

-  }

-

-  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<ISequentialOutStream> _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<IArchiveExtractCallback> 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<ISequentialOutStream> 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<ISequentialOutStream> outStream(folderOutStream);
+
+  COM_TRY_BEGIN
+  
+  CMyComPtr<IArchiveExtractCallback> 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))
+
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> progress = 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<IArchiveExtractCallbackMessage2> callbackMessage;
+  extractCallback.QueryInterface(IID_IArchiveExtractCallbackMessage2, &callbackMessage);
+
+  CFolderOutStream *folderOutStream = new CFolderOutStream;
+  CMyComPtr<ISequentialOutStream> 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<ICryptoGetTextPassword> 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,
+          progress,
+          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 eee11a0..0823189 100644
--- a/CPP/7zip/Archive/7z/7zFolderInStream.cpp
+++ b/CPP/7zip/Archive/7z/7zFolderInStream.cpp
@@ -1,139 +1,264 @@
-// 7zFolderInStream.cpp

-

-#include "StdAfx.h"

-

-#include "7zFolderInStream.h"

-

-namespace NArchive {

-namespace N7z {

-

-void CFolderInStream::Init(IArchiveUpdateCallback *updateCallback,

-    const UInt32 *indexes, unsigned numFiles)

-{

-  _updateCallback = updateCallback;

-  _indexes = indexes;

-  _numFiles = numFiles;

-  _index = 0;

-  

-  Processed.ClearAndReserve(numFiles);

-  CRCs.ClearAndReserve(numFiles);

-  Sizes.ClearAndReserve(numFiles);

-  

-  _pos = 0;

-  _crc = CRC_INIT_VAL;

-  _size_Defined = false;

-  _size = 0;

-

-  _stream.Release();

-}

-

-HRESULT CFolderInStream::OpenStream()

-{

-  _pos = 0;

-  _crc = CRC_INIT_VAL;

-  _size_Defined = false;

-  _size = 0;

-

-  while (_index < _numFiles)

-  {

-    CMyComPtr<ISequentialInStream> stream;

-    HRESULT result = _updateCallback->GetStream(_indexes[_index], &stream);

-    if (result != S_OK)

-    {

-      if (result != S_FALSE)

-        return result;

-    }

-

-    _stream = stream;

-    

-    if (stream)

-    {

-      CMyComPtr<IStreamGetSize> streamGetSize;

-      stream.QueryInterface(IID_IStreamGetSize, &streamGetSize);

-      if (streamGetSize)

-      {

-        if (streamGetSize->GetSize(&_size) == S_OK)

-          _size_Defined = true;

-      }

-      return S_OK;

-    }

-    

-    _index++;

-    RINOK(_updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));

-    AddFileInfo(result == S_OK);

-  }

-  return S_OK;

-}

-

-void CFolderInStream::AddFileInfo(bool isProcessed)

-{

-  Processed.Add(isProcessed);

-  Sizes.Add(_pos);

-  CRCs.Add(CRC_GET_DIGEST(_crc));

-}

-

-STDMETHODIMP CFolderInStream::Read(void *data, UInt32 size, UInt32 *processedSize)

-{

-  if (processedSize)

-    *processedSize = 0;

-  while (size != 0)

-  {

-    if (_stream)

-    {

-      UInt32 cur = size;

-      const UInt32 kMax = (UInt32)1 << 20;

-      if (cur > kMax)

-        cur = kMax;

-      RINOK(_stream->Read(data, cur, &cur));

-      if (cur != 0)

-      {

-        _crc = CrcUpdate(_crc, data, cur);

-        _pos += cur;

-        if (processedSize)

-          *processedSize = cur;

-        return S_OK;

-      }

-      

-      _stream.Release();

-      _index++;

-      AddFileInfo(true);

-

-      _pos = 0;

-      _crc = CRC_INIT_VAL;

-      _size_Defined = false;

-      _size = 0;

-

-      RINOK(_updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));

-    }

-    

-    if (_index >= _numFiles)

-      break;

-    RINOK(OpenStream());

-  }

-  return S_OK;

-}

-

-STDMETHODIMP CFolderInStream::GetSubStreamSize(UInt64 subStream, UInt64 *value)

-{

-  *value = 0;

-  if (subStream > Sizes.Size())

-    return S_FALSE; // E_FAIL;

-  

-  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;

-}

-

-}}

+// 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<ISequentialInStream> stream;
+    const HRESULT result = _updateCallback->GetStream(_indexes[Processed.Size()], &stream);
+    if (result != S_OK && result != S_FALSE)
+      return result;
+
+    _stream = stream;
+    
+    if (stream)
+    {
+      {
+        CMyComPtr<IStreamGetProps> 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<IStreamGetSize> 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<UInt64> &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 f2b1c59..6447b25 100644
--- a/CPP/7zip/Archive/7z/7zFolderInStream.h
+++ b/CPP/7zip/Archive/7z/7zFolderInStream.h
@@ -1,61 +1,101 @@
-// 7zFolderInStream.h

-

-#ifndef __7Z_FOLDER_IN_STREAM_H

-#define __7Z_FOLDER_IN_STREAM_H

-

-#include "../../../../C/7zCrc.h"

-

-#include "../../../Common/MyCom.h"

-#include "../../../Common/MyVector.h"

-

-#include "../../ICoder.h"

-#include "../IArchive.h"

-

-namespace NArchive {

-namespace N7z {

-

-class CFolderInStream:

-  public ISequentialInStream,

-  public ICompressGetSubStreamSize,

-  public CMyUnknownImp

-{

-  CMyComPtr<ISequentialInStream> _stream;

-  UInt64 _pos;

-  UInt32 _crc;

-  bool _size_Defined;

-  UInt64 _size;

-

-  const UInt32 *_indexes;

-  unsigned _numFiles;

-  unsigned _index;

-

-  CMyComPtr<IArchiveUpdateCallback> _updateCallback;

-

-  HRESULT OpenStream();

-  void AddFileInfo(bool isProcessed);

-

-public:

-  CRecordVector<bool> Processed;

-  CRecordVector<UInt32> CRCs;

-  CRecordVector<UInt64> Sizes;

-

-  MY_UNKNOWN_IMP2(ISequentialInStream, ICompressGetSubStreamSize)

-  STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);

-  STDMETHOD(GetSubStreamSize)(UInt64 subStream, UInt64 *value);

-

-  void Init(IArchiveUpdateCallback *updateCallback, const UInt32 *indexes, unsigned numFiles);

-

-  bool WasFinished() const { return _index == _numFiles; }

-

-  UInt64 GetFullSize() const

-  {

-    UInt64 size = 0;

-    FOR_VECTOR (i, Sizes)

-      size += Sizes[i];

-    return size;

-  }

-};

-

-}}

-

-#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<ISequentialInStream> _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<IArchiveUpdateCallback> _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<bool> Processed;
+  CRecordVector<UInt64> Sizes;
+  CRecordVector<UInt32> CRCs;
+  CRecordVector<UInt32> Attribs;
+  CRecordVector<bool> TimesDefined;
+  CRecordVector<UInt64> MTimes;
+  CRecordVector<UInt64> CTimes;
+  CRecordVector<UInt64> ATimes;
+  // UInt32 FolderCrc;
+
+  // UInt32 GetFolderCrc() const { return CRC_GET_DIGEST(FolderCrc); }
+  // CSequentialInStreamWithCRC *_crcStream_Spec;
+  // CMyComPtr<ISequentialInStream> _crcStream;
+  // CMyComPtr<IArchiveUpdateCallbackArcProp> _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 45dda9c..23d3a9d 100644
--- a/CPP/7zip/Archive/7z/7zHandler.cpp
+++ b/CPP/7zip/Archive/7z/7zHandler.cpp
@@ -1,763 +1,793 @@
-// 7zHandler.cpp

-

-#include "StdAfx.h"

-

-#include "../../../../C/CpuArch.h"

-

-#include "../../../Common/ComTry.h"

-#include "../../../Common/IntToString.h"

-

-#ifndef __7Z_SET_PROPERTIES

-#include "../../../Windows/System.h"

-#endif

-

-#include "../Common/ItemNameUtils.h"

-

-#include "7zHandler.h"

-#include "7zProperties.h"

-

-#ifdef __7Z_SET_PROPERTIES

-#ifdef EXTRACT_ONLY

-#include "../Common/ParseProperties.h"

-#endif

-#endif

-

-using namespace NWindows;

-using namespace NCOM;

-

-namespace NArchive {

-namespace N7z {

-

-CHandler::CHandler()

-{

-  #ifndef _NO_CRYPTO

-  _isEncrypted = false;

-  _passwordIsDefined = false;

-  #endif

-

-  #ifdef EXTRACT_ONLY

-  

-  _crcSize = 4;

-  

-  #ifdef __7Z_SET_PROPERTIES

-  _useMultiThreadMixer = true;

-  #endif

-  

-  #endif

-}

-

-STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)

-{

-  *numItems = _db.Files.Size();

-  return S_OK;

-}

-

-#ifdef _SFX

-

-IMP_IInArchive_ArcProps_NO_Table

-

-STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProps)

-{

-  *numProps = 0;

-  return S_OK;

-}

-

-STDMETHODIMP 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 unsigned GetStringForSizeValue(char *s, UInt32 val)

-{

-  unsigned i;

-  for (i = 0; i <= 31; i++)

-    if (((UInt32)1 << i) == val)

-    {

-      if (i < 10)

-      {

-        s[0] = (char)('0' + i);

-        s[1] = 0;

-        return 1;

-      }

-           if (i < 20) { s[0] = '1'; s[1] = (char)('0' + i - 10); }

-      else if (i < 30) { s[0] = '2'; s[1] = (char)('0' + i - 20); }

-      else             { s[0] = '3'; s[1] = (char)('0' + i - 30); }

-      s[2] = 0;

-      return 2;

-    }

-  char 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;

-  return pos;

-}

-

-/*

-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);

-  ::ConvertUInt32ToString(v, s);

-  return s + MyStringLen(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

-

-STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)

-{

-  #ifndef _SFX

-  COM_TRY_BEGIN

-  #endif

-  NCOM::CPropVariant prop;

-  switch (propID)

-  {

-    #ifndef _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:";

-          if ((pm.Lzma2Prop & 1) == 0)

-            ConvertUInt32ToString((pm.Lzma2Prop >> 1) + 12, temp);

-          else

-            GetStringForSizeValue(temp, 3 << ((pm.Lzma2Prop >> 1) + 11));

-          s += temp;

-        }

-        else if (id == k_LZMA)

-        {

-          s += "LZMA:";

-          GetStringForSizeValue(temp, pm.LzmaDic);

-          s += temp;

-        }

-        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;

-    }

-  }

-  prop.Detach(value);

-  return S_OK;

-  #ifndef _SFX

-  COM_TRY_END

-  #endif

-}

-

-static void SetFileTimeProp_From_UInt64Def(PROPVARIANT *prop, const CUInt64DefVector &v, int index)

-{

-  UInt64 value;

-  if (v.GetItem(index, value))

-    PropVarEm_Set_FileTime64(prop, value);

-}

-

-bool CHandler::IsFolderEncrypted(CNum folderIndex) const

-{

-  if (folderIndex == kNumNoIndex)

-    return false;

-  size_t startPos = _db.FoCodersDataOffset[folderIndex];

-  const Byte *p = _db.CodersData + startPos;

-  size_t size = _db.FoCodersDataOffset[folderIndex + 1] - startPos;

-  CInByte2 inByte;

-  inByte.Init(p, size);

-  

-  CNum numCoders = inByte.ReadNum();

-  for (; numCoders != 0; numCoders--)

-  {

-    Byte mainByte = inByte.ReadByte();

-    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;

-}

-

-STDMETHODIMP CHandler::GetNumRawProps(UInt32 *numProps)

-{

-  *numProps = 0;

-  return S_OK;

-}

-

-STDMETHODIMP CHandler::GetRawPropInfo(UInt32 /* index */, BSTR *name, PROPID *propID)

-{

-  *name = NULL;

-  *propID = kpidNtSecure;

-  return S_OK;

-}

-

-STDMETHODIMP 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;

-}

-

-STDMETHODIMP 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)

-    {

-      size_t offset = _db.NameOffsets[index];

-      size_t size = (_db.NameOffsets[index + 1] - offset) * 2;

-      if (size < ((UInt32)1 << 31))

-      {

-        *data = (const void *)(_db.NamesBuf + 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 _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;

- 

-  size_t startPos = _db.FoCodersDataOffset[folderIndex];

-  const Byte *p = _db.CodersData + startPos;

-  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;

-    Byte mainByte = inByte.ReadByte();

-    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 ((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)

-    {

-      UInt32 id = (UInt32)id64;

-      if (id == k_LZMA)

-      {

-        name = "LZMA";

-        if (propsSize == 5)

-        {

-          UInt32 dicSize = GetUi32((const Byte *)props + 1);

-          char *dest = s + GetStringForSizeValue(s, dicSize);

-          UInt32 d = props[0];

-          if (d != 0x5D)

-          {

-            UInt32 lc = d % 9;

-            d /= 9;

-            UInt32 pb = d / 5;

-            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)

-        {

-          Byte d = props[0];

-          if ((d & 1) == 0)

-            ConvertUInt32ToString((UInt32)((d >> 1) + 12), s);

-          else

-            GetStringForSizeValue(s, 3 << ((d >> 1) + 11));

-        }

-      }

-      else if (id == k_PPMD)

-      {

-        name = "PPMD";

-        if (propsSize == 5)

-        {

-          Byte order = *props;

-          char *dest = s;

-          *dest++ = 'o';

-          ConvertUInt32ToString(order, dest);

-          dest += MyStringLen(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_BCJ2) name = "BCJ2";

-      else if (id == k_BCJ) name = "BCJ";

-      else if (id == k_AES)

-      {

-        name = "7zAES";

-        if (propsSize >= 1)

-        {

-          Byte firstByte = props[0];

-          UInt32 numCyclesPower = firstByte & 0x3F;

-          ConvertUInt32ToString(numCyclesPower, s);

-        }

-      }

-    }

-    

-    if (name)

-    {

-      unsigned nameLen = MyStringLen(name);

-      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

-      {

-        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

-

-STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)

-{

-  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;

-      {

-        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 _SFX

-    

-    case kpidMethod: return SetMethodToProp(_db.FileIndexToFolderIndexMap[index2], value);

-    case kpidBlock:

-      {

-        CNum folderIndex = _db.FileIndexToFolderIndexMap[index2];

-        if (folderIndex != kNumNoIndex)

-          PropVarEm_Set_UInt32(value, (UInt32)folderIndex);

-      }

-      break;

-    /*

-    case kpidPackedSize0:

-    case kpidPackedSize1:

-    case kpidPackedSize2:

-    case kpidPackedSize3:

-    case kpidPackedSize4:

-      {

-        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

-  }

-  // prop.Detach(value);

-  return S_OK;

-  // COM_TRY_END

-}

-

-STDMETHODIMP CHandler::Open(IInStream *stream,

-    const UInt64 *maxCheckStartPosition,

-    IArchiveOpenCallback *openArchiveCallback)

-{

-  COM_TRY_BEGIN

-  Close();

-  #ifndef _SFX

-  _fileInfoPopIDs.Clear();

-  #endif

-  

-  try

-  {

-    CMyComPtr<IArchiveOpenCallback> openArchiveCallbackTemp = openArchiveCallback;

-

-    #ifndef _NO_CRYPTO

-    CMyComPtr<ICryptoGetTextPassword> getTextPassword;

-    if (openArchiveCallback)

-      openArchiveCallbackTemp.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword);

-    #endif

-

-    CInArchive archive(

-          #ifdef __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 _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 _SFX

-  FillPopIDs();

-  #endif

-  return S_OK;

-  COM_TRY_END

-}

-

-STDMETHODIMP CHandler::Close()

-{

-  COM_TRY_BEGIN

-  _inStream.Release();

-  _db.Clear();

-  #ifndef _NO_CRYPTO

-  _isEncrypted = false;

-  _passwordIsDefined = false;

-  _password.Empty();

-  #endif

-  return S_OK;

-  COM_TRY_END

-}

-

-#ifdef __7Z_SET_PROPERTIES

-#ifdef EXTRACT_ONLY

-

-STDMETHODIMP 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;

-    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;
+    }
+  }
+  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 + 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)
+    {
+      size_t offset = _db.NameOffsets[index];
+      size_t size = (_db.NameOffsets[index + 1] - offset) * 2;
+      if (size < ((UInt32)1 << 31))
+      {
+        *data = (const void *)(_db.NamesBuf + 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 + 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)
+      {
+        name = "ARM64";
+        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
+  }
+  // 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<IArchiveOpenCallback> openArchiveCallbackTemp = openArchiveCallback;
+
+    #ifndef Z7_NO_CRYPTO
+    CMyComPtr<ICryptoGetTextPassword> 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 7d5a5f0..b1c0466 100644
--- a/CPP/7zip/Archive/7z/7zHandler.h
+++ b/CPP/7zip/Archive/7z/7zHandler.h
@@ -1,181 +1,176 @@
-// 7z/Handler.h

-

-#ifndef __7Z_HANDLER_H

-#define __7Z_HANDLER_H

-

-#include "../../ICoder.h"

-#include "../IArchive.h"

-

-#include "../../Common/CreateCoder.h"

-

-#ifndef __7Z_SET_PROPERTIES

-

-#ifdef EXTRACT_ONLY

-  #if !defined(_7ZIP_ST) && !defined(_SFX)

-    #define __7Z_SET_PROPERTIES

-  #endif

-#else

-  #define __7Z_SET_PROPERTIES

-#endif

-

-#endif

-

-// #ifdef __7Z_SET_PROPERTIES

-#include "../Common/HandlerOut.h"

-// #endif

-

-#include "7zCompressionMode.h"

-#include "7zIn.h"

-

-namespace NArchive {

-namespace N7z {

-

-

-#ifndef 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

-

-  CBoolPair Write_CTime;

-  CBoolPair Write_ATime;

-  CBoolPair Write_MTime;

-  CBoolPair Write_Attrib;

-

-  bool _useMultiThreadMixer;

-

-  bool _removeSfxBlock;

-  

-  // bool _volumeMode;

-

-  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:

-  public IInArchive,

-  public IArchiveGetRawProps,

-  

-  #ifdef __7Z_SET_PROPERTIES

-  public ISetProperties,

-  #endif

-  

-  #ifndef EXTRACT_ONLY

-  public IOutArchive,

-  #endif

-  

-  PUBLIC_ISetCompressCodecsInfo

-  

-  public CMyUnknownImp,

-

-  #ifndef EXTRACT_ONLY

-    public COutHandler

-  #else

-    public CCommonMethodProps

-  #endif

-{

-public:

-  MY_QUERYINTERFACE_BEGIN2(IInArchive)

-  MY_QUERYINTERFACE_ENTRY(IArchiveGetRawProps)

-  #ifdef __7Z_SET_PROPERTIES

-  MY_QUERYINTERFACE_ENTRY(ISetProperties)

-  #endif

-  #ifndef EXTRACT_ONLY

-  MY_QUERYINTERFACE_ENTRY(IOutArchive)

-  #endif

-  QUERY_ENTRY_ISetCompressCodecsInfo

-  MY_QUERYINTERFACE_END

-  MY_ADDREF_RELEASE

-

-  INTERFACE_IInArchive(;)

-  INTERFACE_IArchiveGetRawProps(;)

-

-  #ifdef __7Z_SET_PROPERTIES

-  STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps);

-  #endif

-

-  #ifndef EXTRACT_ONLY

-  INTERFACE_IOutArchive(;)

-  #endif

-

-  DECL_ISetCompressCodecsInfo

-

-  CHandler();

-

-private:

-  CMyComPtr<IInStream> _inStream;

-  NArchive::N7z::CDbEx _db;

-  

-  #ifndef _NO_CRYPTO

-  bool _isEncrypted;

-  bool _passwordIsDefined;

-  UString _password;

-  #endif

-

-  #ifdef EXTRACT_ONLY

-  

-  #ifdef __7Z_SET_PROPERTIES

-  bool _useMultiThreadMixer;

-  #endif

-

-  UInt32 _crcSize;

-

-  #else

-  

-  CRecordVector<CBond2> _bonds;

-

-  HRESULT PropsMethod_To_FullMethod(CMethodFull &dest, const COneMethodInfo &m);

-  HRESULT SetHeaderMethod(CCompressionMethodMode &headerMethod);

-  HRESULT SetMainMethod(CCompressionMethodMode &method

-      #ifndef _7ZIP_ST

-      , UInt32 numThreads

-      #endif

-      );

-

-

-  #endif

-

-  bool IsFolderEncrypted(CNum folderIndex) const;

-  #ifndef _SFX

-

-  CRecordVector<UInt64> _fileInfoPopIDs;

-  void FillPopIDs();

-  void AddMethodName(AString &s, UInt64 id);

-  HRESULT SetMethodToProp(CNum folderIndex, PROPVARIANT *prop) const;

-

-  #endif

-

-  DECL_EXTERNAL_CODECS_VARS

-};

-

-}}

-

-#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;
+
+  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<IInStream> _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<CBond2> _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<UInt64> _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 62587e8..ff8735f 100644
--- a/CPP/7zip/Archive/7z/7zHandlerOut.cpp
+++ b/CPP/7zip/Archive/7z/7zHandlerOut.cpp
@@ -1,942 +1,1086 @@
-// 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 EXTRACT_ONLY

-

-using namespace NWindows;

-

-namespace NArchive {

-namespace N7z {

-

-#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

-

-STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type)

-{

-  *type = NFileTimeType::kWindows;

-  return S_OK;

-}

-

-HRESULT CHandler::PropsMethod_To_FullMethod(CMethodFull &dest, const COneMethodInfo &m)

-{

-  dest.CodecIndex = FindMethod_Index(

-      EXTERNAL_CODECS_VARS

-      m.MethodName, true,

-      dest.Id, dest.NumStreams);

-  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

-    #ifndef _7ZIP_ST

-    , UInt32 numThreads

-    #endif

-    )

-{

-  methodMode.Bonds = _bonds;

-

-  CObjectVector<COneMethodInfo> 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) - 1;

-

-  bool needSolid = false;

-  

-  FOR_VECTOR (i, methods)

-  {

-    COneMethodInfo &oneMethodInfo = methods[i];

-

-    SetGlobalLevelTo(oneMethodInfo);

-    #ifndef _7ZIP_ST

-    CMultiMethodProps::SetMethodThreadsTo(oneMethodInfo, numThreads);

-    #endif

-

-    CMethodFull &methodFull = methodMode.Methods.AddNew();

-    RINOK(PropsMethod_To_FullMethod(methodFull, oneMethodInfo));

-

-    if (methodFull.Id != k_Copy)

-      needSolid = true;

-

-    if (_numSolidBytesDefined)

-      continue;

-

-    UInt32 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_BZip2: dicSize = oneMethodInfo.Get_BZip2_BlockSize(); break;

-      default: continue;

-    }

-    

-    _numSolidBytes = (UInt64)dicSize << 7;

-    if (_numSolidBytes < kSolidBytes_Min) _numSolidBytes = kSolidBytes_Min;

-    if (_numSolidBytes > kSolidBytes_Max) _numSolidBytes = kSolidBytes_Max;

-    _numSolidBytesDefined = true;

-  }

-

-  if (!_numSolidBytesDefined)

-    if (needSolid)

-      _numSolidBytes = kSolidBytes_Max;

-    else

-      _numSolidBytes = 0;

-  _numSolidBytesDefined = true;

-  return S_OK;

-}

-

-static HRESULT GetTime(IArchiveUpdateCallback *updateCallback, int 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<CTreeFolder> &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<CTreeFolder> &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<CTreeFolder> &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;

-}

-*/

-

-STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,

-    IArchiveUpdateCallback *updateCallback)

-{

-  COM_TRY_BEGIN

-

-  const CDbEx *db = 0;

-  #ifdef _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 != 0)

-    db = &_db;

-  #endif

-

-  if (db && !db->CanUpdate())

-    return E_NOTIMPL;

-

-  /*

-  CMyComPtr<IArchiveGetRawProps> getRawProps;

-  updateCallback->QueryInterface(IID_IArchiveGetRawProps, (void **)&getRawProps);

-

-  CUniqBlocks secureBlocks;

-  secureBlocks.AddUniq(NULL, 0);

-

-  CObjectVector<CTreeFolder> treeFolders;

-  {

-    CTreeFolder folder;

-    folder.Parent = -1;

-    treeFolders.Add(folder);

-  }

-  */

-

-  CObjectVector<CUpdateItem> updateItems;

-

-  bool need_CTime = (Write_CTime.Def && Write_CTime.Val);

-  bool need_ATime = (Write_ATime.Def && Write_ATime.Val);

-  bool need_MTime = (Write_MTime.Def && Write_MTime.Val || !Write_MTime.Def);

-  bool need_Attrib = (Write_Attrib.Def && Write_Attrib.Val || !Write_Attrib.Def);

-  

-  if (db && !db->Files.IsEmpty())

-  {

-    if (!Write_CTime.Def) need_CTime = !db->CTime.Defs.IsEmpty();

-    if (!Write_ATime.Def) need_ATime = !db->ATime.Defs.IsEmpty();

-    if (!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 = indexInArchive;

-    ui.IndexInClient = i;

-    ui.IsAnti = false;

-    ui.Size = 0;

-

-    name.Empty();

-    // bool isAltStream = false;

-    if (ui.IndexInArchive != -1)

-    {

-      if (db == 0 || (unsigned)ui.IndexInArchive >= db->Files.Size())

-        return E_INVALIDARG;

-      const CFileItem &fi = db->Files[ui.IndexInArchive];

-      if (!ui.NewProps)

-      {

-        _db.GetPath(ui.IndexInArchive, name);

-      }

-      ui.IsDir = fi.IsDir;

-      ui.Size = fi.Size;

-      // isAltStream = fi.IsAltStream;

-      ui.IsAnti = db->IsItemAnti(ui.IndexInArchive);

-      

-      if (!ui.NewProps)

-      {

-        ui.CTimeDefined = db->CTime.GetItem(ui.IndexInArchive, ui.CTime);

-        ui.ATimeDefined = db->ATime.GetItem(ui.IndexInArchive, ui.ATime);

-        ui.MTimeDefined = db->MTime.GetItem(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;

-

-  HRESULT res = SetMainMethod(methodMode

-    #ifndef _7ZIP_ST

-    , _numThreads

-    #endif

-    );

-  RINOK(res);

-

-  RINOK(SetHeaderMethod(headerMethod));

-  

-  #ifndef _7ZIP_ST

-  methodMode.NumThreads = _numThreads;

-  methodMode.MultiThreadMixer = _useMultiThreadMixer;

-  headerMethod.NumThreads = 1;

-  headerMethod.MultiThreadMixer = _useMultiThreadMixer;

-  #endif

-

-  CMyComPtr<ICryptoGetTextPassword2> getPassword2;

-  updateCallback->QueryInterface(IID_ICryptoGetTextPassword2, (void **)&getPassword2);

-

-  methodMode.PasswordIsDefined = false;

-  methodMode.Password.Empty();

-  if (getPassword2)

-  {

-    CMyComBSTR 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 _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 _NO_CRYPTO

-    else

-      encryptHeaders = _passwordIsDefined;

-    #endif

-    compressMainHeader = true;

-    if (encryptHeaders)

-    {

-      headerMethod.PasswordIsDefined = methodMode.PasswordIsDefined;

-      headerMethod.Password = methodMode.Password;

-    }

-  }

-

-  if (numItems < 2)

-    compressMainHeader = false;

-

-  int level = GetLevel();

-

-  CUpdateOptions options;

-  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.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;

-

-  COutArchive archive;

-  CArchiveDatabaseOut newDatabase;

-

-  CMyComPtr<ICryptoGetTextPassword> getPassword;

-  updateCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&getPassword);

-  

-  /*

-  if (secureBlocks.Sorted.Size() > 1)

-  {

-    secureBlocks.GetReverseMap();

-    for (int i = 0; i < updateItems.Size(); i++)

-    {

-      int &secureIndex = updateItems[i].SecureIndex;

-      secureIndex = secureBlocks.BufIndexToSortedIndex[secureIndex];

-    }

-  }

-  */

-

-  res = Update(

-      EXTERNAL_CODECS_VARS

-      #ifdef _7Z_VOL

-      volume ? volume->Stream: 0,

-      volume ? db : 0,

-      #else

-      _inStream,

-      db,

-      #endif

-      updateItems,

-      // treeFolders,

-      // secureBlocks,

-      archive, newDatabase, outStream, updateCallback, options

-      #ifndef _NO_CRYPTO

-      , getPassword

-      #endif

-      );

-

-  RINOK(res);

-

-  updateItems.ClearAndFree();

-

-  return archive.WriteDatabase(EXTERNAL_CODECS_VARS

-      newDatabase, options.HeaderMethod, options.HeaderOptions);

-

-  COM_TRY_END

-}

-

-static HRESULT ParseBond(UString &srcString, UInt32 &coder, UInt32 &stream)

-{

-  stream = 0;

-  {

-    unsigned index = ParseStringToUInt32(srcString, coder);

-    if (index == 0)

-      return E_INVALIDARG;

-    srcString.DeleteFrontal(index);

-  }

-  if (srcString[0] == 's')

-  {

-    srcString.Delete(0);

-    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;

-  

-  Write_CTime.Init();

-  Write_ATime.Init();

-  Write_MTime.Init();

-  Write_Attrib.Init();

-

-  _useMultiThreadMixer = true;

-

-  // _volumeMode = false;

-

-  InitSolid();

-  _useTypeSorting = false;

-}

-

-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 += (int)(end - start);

-    if (i == s2.Len())

-      return E_INVALIDARG;

-    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;

-}

-

-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;

-  int 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;

-    }

-    

-    if (name.IsEqualTo("tc")) return PROPVARIANT_to_BoolPair(value, Write_CTime);

-    if (name.IsEqualTo("ta")) return PROPVARIANT_to_BoolPair(value, Write_ATime);

-    if (name.IsEqualTo("tm")) return PROPVARIANT_to_BoolPair(value, Write_MTime);

-    

-    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.IsEqualTo("v"))  return PROPVARIANT_to_bool(value, _volumeMode);

-  }

-  return CMultiMethodProps::SetProperty(name, value);

-}

-

-STDMETHODIMP 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[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 {
+
+#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<COneMethodInfo> 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<CTreeFolder> &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<CTreeFolder> &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<CTreeFolder> &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<CTreeFolder> treeFolders;
+  {
+    CTreeFolder folder;
+    folder.Parent = -1;
+    treeFolders.Add(folder);
+  }
+  */
+
+  CObjectVector<CUpdateItem> 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.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;
+}
+
+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;
+}
+
+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.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 de39909..d5f9497 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 _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 7de6eee..bd96ca3 100644
--- a/CPP/7zip/Archive/7z/7zHeader.h
+++ b/CPP/7zip/Archive/7z/7zHeader.h
@@ -1,148 +1,153 @@
-// 7z/7zHeader.h

-

-#ifndef __7Z_HEADER_H

-#define __7Z_HEADER_H

-

-#include "../../../Common/MyTypes.h"

-

-namespace NArchive {

-namespace N7z {

-

-const unsigned kSignatureSize = 6;

-extern Byte kSignature[kSignatureSize];

-

-// #define _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 _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 _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_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_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;

-

-

-static inline bool IsFilterMethod(UInt64 m)

-{

-  if (m > (UInt64)0xFFFFFFFF)

-    return false;

-  switch ((UInt32)m)

-  {

-    case k_Delta:

-    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;

-  }

-  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_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
+
+static inline bool IsFilterMethod(UInt64 m)
+{
+  if (m > (UInt32)0xFFFFFFFF)
+    return false;
+  switch ((UInt32)m)
+  {
+    case k_Delta:
+    case k_ARM64:
+    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;
+  }
+  return false;
+}
+
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/7z/7zIn.cpp b/CPP/7zip/Archive/7z/7zIn.cpp
index ae5ff19..4defd27 100644
--- a/CPP/7zip/Archive/7z/7zIn.cpp
+++ b/CPP/7zip/Archive/7z/7zIn.cpp
@@ -1,1666 +1,1757 @@
-// 7zIn.cpp

-

-#include "StdAfx.h"

-

-#ifdef _WIN32

-#include <wchar.h>

-#else

-#include <ctype.h>

-#endif

-

-#include "../../../../C/7zCrc.h"

-#include "../../../../C/CpuArch.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 _SFX

-#define FORMAT_7Z_RECOVERY

-#endif

-

-using namespace NWindows;

-using namespace NCOM;

-

-namespace NArchive {

-namespace N7z {

-

-unsigned BoolVector_CountSum(const CBoolVector &v)

-{

-  unsigned sum = 0;

-  const unsigned size = v.Size();

-  for (unsigned i = 0; i < size; i++)

-    if (v[i])

-      sum++;

-  return sum;

-}

-

-static inline bool BoolVector_Item_IsValidAndTrue(const CBoolVector &v, unsigned i)

-{

-  return (i < v.Size() ? v[i] : false);

-}

-

-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;

-}

-

-

-class CInArchiveException {};

-class CUnsupportedFeatureException: public CInArchiveException {};

-

-static void ThrowException() { throw CInArchiveException(); }

-static inline void ThrowEndOfData()   { ThrowException(); }

-static inline void ThrowUnsupported() { throw CUnsupportedFeatureException(); }

-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<CByteBuffer> *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<CByteBuffer> *dataVector)

-{

-  Remove();

-  Byte external = archive->ReadByte();

-  if (external != 0)

-  {

-    if (!dataVector)

-      ThrowIncorrect();

-    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;

-  }

-  

-  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++)

-  {

-    unsigned mask = (unsigned)0x80 >> i;

-    if ((b & mask) == 0)

-    {

-      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;

-  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;

-    }

-  }

-  */

-  UInt64 value = ReadNumber();

-  if (value > kNumMax)

-    ThrowUnsupported();

-  return (CNum)value;

-}

-

-UInt32 CInByte2::ReadUInt32()

-{

-  if (_pos + 4 > _size)

-    ThrowEndOfData();

-  UInt32 res = Get32(_buffer + _pos);

-  _pos += 4;

-  return res;

-}

-

-UInt64 CInByte2::ReadUInt64()

-{

-  if (_pos + 8 > _size)

-    ThrowEndOfData();

-  UInt64 res = Get64(_buffer + _pos);

-  _pos += 8;

-  return res;

-}

-

-#define CHECK_SIGNATURE if (p[0] != '7' || p[1] != 'z' || p[2] != 0xBC || p[3] != 0xAF || p[4] != 0x27 || p[5] != 0x1C) return false;

-

-static inline bool TestSignature(const Byte *p)

-{

-  CHECK_SIGNATURE

-  return CrcCalc(p + 12, 20) == Get32(p + 8);

-}

-

-#ifdef FORMAT_7Z_RECOVERY

-static inline bool TestSignature2(const Byte *p)

-{

-  CHECK_SIGNATURE;

-  if (CrcCalc(p + 12, 20) == Get32(p + 8))

-    return true;

-  for (unsigned i = 8; i < kHeaderSize; i++)

-    if (p[i] != 0)

-      return false;

-  return (p[6] != 0 || p[7] != 0);

-}

-#else

-#define TestSignature2(p) TestSignature(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;

-  CByteArr buf(kBufSize);

-  memcpy(buf, _header, kHeaderSize);

-  UInt64 offset = 0;

-  

-  for (;;)

-  {

-    UInt32 readSize = kBufSize - kHeaderSize;

-    if (searchHeaderSizeLimit)

-    {

-      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;

-    

-    for (UInt32 pos = 0;;)

-    {

-      const Byte *p = buf + pos + 1;

-      const Byte *lim = buf + processed;

-      for (; p <= lim; p += 4)

-      {

-        if (p[0] == '7') break;

-        if (p[1] == '7') { p += 1; break; }

-        if (p[2] == '7') { p += 2; break; }

-        if (p[3] == '7') { p += 3; break; }

-      };

-      if (p > lim)

-        break;

-      pos = (UInt32)(p - buf);

-      if (TestSignature(p))

-      {

-        memcpy(_header, p, kHeaderSize);

-        _arhiveBeginStreamPosition += offset + pos;

-        return stream->Seek(_arhiveBeginStreamPosition + kHeaderSize, STREAM_SEEK_SET, NULL);

-      }

-    }

-    

-    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(stream->Seek(0, STREAM_SEEK_CUR, &_arhiveBeginStreamPosition))

-  RINOK(stream->Seek(0, STREAM_SEEK_END, &_fileEndPosition))

-  RINOK(stream->Seek(_arhiveBeginStreamPosition, STREAM_SEEK_SET, NULL))

-  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)

-{

-  UInt32 numCoders = ReadNum();

-

-  if (numCoders == 0)

-    ThrowUnsupported();

-

-  folder.Coders.SetSize(numCoders);

-

-  UInt32 numInStreams = 0;

-  UInt32 i;

-  for (i = 0; i < numCoders; i++)

-  {

-    CCoderInfo &coder = folder.Coders[i];

-    {

-      Byte mainByte = ReadByte();

-      if ((mainByte & 0xC0) != 0)

-        ThrowUnsupported();

-      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();

-        /* numOutStreams = */ ReadNum();

-      }

-      else

-      {

-        coder.NumStreams = 1;

-      }

-      

-      if ((mainByte & 0x20) != 0)

-      {

-        CNum propsSize = ReadNum();

-        coder.Props.Alloc((size_t)propsSize);

-        ReadBytes((Byte *)coder.Props, (size_t)propsSize);

-      }

-      else

-        coder.Props.Free();

-    }

-    numInStreams += coder.NumStreams;

-  }

-

-  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();

-  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

-{

-  size_t startPos = FoCodersDataOffset[folderIndex];

-  CInByte2 inByte;

-  inByte.Init(CodersData + 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;

-

-  size_t offset = NameOffsets[index];

-  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 *)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;

-

-  size_t offset = NameOffsets[index];

-  size_t size = NameOffsets[index + 1] - offset;

-

-  if (size >= (1 << 14))

-    return S_OK;

-

-  RINOK(PropVarEm_Alloc_Bstr(path, (unsigned)size - 1));

-  wchar_t *s = path->bstrVal;

-

-  const Byte *p = ((const Byte *)NamesBuf + offset * 2);

-

-  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;

-    #endif

-    *s++ = c;

-  }

-

-  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 (;;)

-  {

-    UInt64 type = ReadID();

-    if (type == id)

-      return;

-    if (type == NID::kEnd)

-      ThrowIncorrect();

-    SkipData();

-  }

-}

-

-

-void CInArchive::Read_UInt32_Vector(CUInt32DefVector &v)

-{

-  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);

-}

-

-

-#define k_Scan_NumCoders_MAX 64

-#define k_Scan_NumCodersStreams_in_Folder_MAX 64

-

-void CInArchive::ReadPackInfo(CFolders &f)

-{

-  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;

-    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<CByteBuffer> *dataVector,

-    CFolders &folders)

-{

-  WaitId(NID::kFolder);

-  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] = _inByteBack->GetPtr() - startBufPtr;

-

-      CNum numInStreams = 0;

-      CNum numCoders = inByte->ReadNum();

-    

-      if (numCoders == 0 || numCoders > k_Scan_NumCoders_MAX)

-        ThrowUnsupported();

-

-      for (CNum ci = 0; ci < numCoders; ci++)

-      {

-        Byte mainByte = inByte->ReadByte();

-        if ((mainByte & 0xC0) != 0)

-          ThrowUnsupported();

-        

-        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)

-        {

-          CNum propsSize = inByte->ReadNum();

-          if (propsSize > inByte->GetRem())

-            ThrowEndOfData();

-          if (id == k_LZMA2 && propsSize == 1)

-          {

-            Byte v = *_inByteBack->GetPtr();

-            if (folders.ParsedMethods.Lzma2Prop < v)

-              folders.ParsedMethods.Lzma2Prop = v;

-          }

-          else if (id == k_LZMA && propsSize == 5)

-          {

-            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;

-        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++)

-          {

-            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;

-    }

-    

-    size_t dataSize = _inByteBack->GetPtr() - startBufPtr;

-    folders.FoToCoderUnpackSizes[fo] = numCodersOutStreams;

-    folders.FoStartPackStreamIndex[fo] = packStreamIndex;

-    folders.FoCodersDataOffset[fo] = _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 (;;)

-  {

-    UInt64 type = ReadID();

-    if (type == NID::kEnd)

-      return;

-    if (type == NID::kCRC)

-    {

-      ReadHashDigests(numFolders, folders.FolderCRCs);

-      continue;

-    }

-    SkipData();

-  }

-}

-

-void CInArchive::ReadSubStreamsInfo(

-    CFolders &folders,

-    CRecordVector<UInt64> &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

-      CNum numSubstreams = folders.NumUnpackStreamsVector[i];

-      if (numSubstreams == 0)

-        continue;

-      UInt64 sum = 0;

-      for (CNum j = 1; j < numSubstreams; j++)

-      {

-        UInt64 size = ReadNumber();

-        unpackSizes.Add(size);

-        sum += size;

-        if (sum < size)

-          ThrowIncorrect();

-      }

-      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 */

-      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++)

-  {

-    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++)

-      {

-        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++)

-    {

-      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<CByteBuffer> *dataVector,

-    UInt64 &dataOffset,

-    CFolders &folders,

-    CRecordVector<UInt64> &unpackSizes,

-    CUInt32DefVector &digests)

-{

-  UInt64 type = ReadID();

-  

-  if (type == NID::kPackInfo)

-  {

-    dataOffset = ReadNumber();

-    ReadPackInfo(folders);

-    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 >>= 1;

-  }

-}

-

-void CInArchive::ReadBoolVector2(unsigned numItems, CBoolVector &v)

-{

-  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<CByteBuffer> &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<CByteBuffer> &dataVector

-    _7Z_DECODER_CRYPRO_VARS_DECL

-    )

-{

-  CFolders folders;

-  CRecordVector<UInt64> unpackSizes;

-  CUInt32DefVector  digests;

-  

-  ReadStreamsInfo(NULL,

-    dataOffset,

-    folders,

-    unpackSizes,

-    digests);

-  

-  CDecoder decoder(_useMixerMT);

-

-  for (CNum i = 0; i < folders.NumFolders; i++)

-  {

-    CByteBuffer &data = dataVector.AddNew();

-    UInt64 unpackSize64 = folders.GetFolderUnpackSize(i);

-    size_t unpackSize = (size_t)unpackSize64;

-    if (unpackSize != unpackSize64)

-      ThrowUnsupported();

-    data.Alloc(unpackSize);

-    

-    CBufPtrSeqOutStream *outStreamSpec = new CBufPtrSeqOutStream;

-    CMyComPtr<ISequentialOutStream> outStream = outStreamSpec;

-    outStreamSpec->Init(data, unpackSize);

-    

-    bool dataAfterEnd_Error = false;

-

-    HRESULT result = decoder.Decode(

-        EXTERNAL_CODECS_LOC_VARS

-        _stream, baseOffset + dataOffset,

-        folders, i,

-        NULL, // *unpackSize

-        

-        outStream,

-        NULL, // *compressProgress

-

-        NULL  // **inStreamMainRes

-        , dataAfterEnd_Error

-        

-        _7Z_DECODER_CRYPRO_VARS

-        #if !defined(_7ZIP_ST)

-          , false // mtMode

-          , 1     // numThreads

-          , 0     // memUsage

-        #endif

-      );

-    

-    RINOK(result);

-    

-    if (dataAfterEnd_Error)

-      ThereIsHeaderError = true;

-    

-    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

-    _7Z_DECODER_CRYPRO_VARS_DECL

-    )

-{

-  UInt64 type = ReadID();

-

-  if (type == NID::kArchiveProperties)

-  {

-    ReadArchiveProperties(db.ArcInfo);

-    type = ReadID();

-  }

- 

-  CObjectVector<CByteBuffer> dataVector;

-  

-  if (type == NID::kAdditionalStreamsInfo)

-  {

-    HRESULT result = ReadAndDecodePackedStreams(

-        EXTERNAL_CODECS_LOC_VARS

-        db.ArcInfo.StartPositionAfterHeader,

-        db.ArcInfo.DataStartPosition2,

-        dataVector

-        _7Z_DECODER_CRYPRO_VARS

-        );

-    RINOK(result);

-    db.ArcInfo.DataStartPosition2 += db.ArcInfo.StartPositionAfterHeader;

-    type = ReadID();

-  }

-

-  CRecordVector<UInt64> 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;

-  CNum numEmptyStreams = 0;

-

-  for (;;)

-  {

-    const UInt64 type2 = ReadID();

-    if (type2 == NID::kEnd)

-      break;

-    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);

-        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++)

-        {

-          size_t curRem = (rem - pos) / 2;

-          const UInt16 *buf = (const UInt16 *)(db.NamesBuf + 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 CNum 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++)

-  {

-    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

-    _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

-  UInt32 crcFromArc = Get32(_header + 8);

-  if (crcFromArc == 0 && nextHeaderOffset == 0 && nextHeaderSize == 0 && nextHeaderCRC == 0)

-  {

-    UInt64 cur, fileSize;

-    RINOK(_stream->Seek(0, STREAM_SEEK_CUR, &cur));

-    const unsigned kCheckSize = 512;

-    Byte buf[kCheckSize];

-    RINOK(_stream->Seek(0, STREAM_SEEK_END, &fileSize));

-    UInt64 rem = fileSize - cur;

-    unsigned checkSize = kCheckSize;

-    if (rem < kCheckSize)

-      checkSize = (unsigned)(rem);

-    if (checkSize < 3)

-      return S_FALSE;

-    RINOK(_stream->Seek(fileSize - checkSize, STREAM_SEEK_SET, NULL));

-    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(_stream->Seek(cur, STREAM_SEEK_SET, NULL));

-    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;

-  if (nextHeaderSize == 0)

-  {

-    if (nextHeaderOffset != 0)

-      return S_FALSE;

-    db.IsArc = true;

-    return S_OK;

-  }

-  

-  if (!db.StartHeaderWasRecovered)

-    db.IsArc = true;

-  

-  HeadersSize += kHeaderSize + nextHeaderSize;

-  db.PhySize = kHeaderSize + nextHeaderOffset + nextHeaderSize;

-  if (_fileEndPosition - db.ArcInfo.StartPositionAfterHeader < nextHeaderOffset + nextHeaderSize)

-  {

-    db.UnexpectedEnd = true;

-    return S_FALSE;

-  }

-  RINOK(_stream->Seek(nextHeaderOffset, STREAM_SEEK_CUR, NULL));

-

-  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<CByteBuffer> dataVector;

-  

-  UInt64 type = ReadID();

-  if (type != NID::kHeader)

-  {

-    if (type != NID::kEncodedHeader)

-      ThrowIncorrect();

-    HRESULT result = ReadAndDecodePackedStreams(

-        EXTERNAL_CODECS_LOC_VARS

-        db.ArcInfo.StartPositionAfterHeader,

-        db.ArcInfo.DataStartPosition2,

-        dataVector

-        _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

-    _7Z_DECODER_CRYPRO_VARS

-    );

-}

-

-

-HRESULT CInArchive::ReadDatabase(

-    DECL_EXTERNAL_CODECS_LOC_VARS

-    CDbEx &db

-    _7Z_DECODER_CRYPRO_VARS_DECL

-    )

-{

-  try

-  {

-    HRESULT res = ReadDatabase2(

-      EXTERNAL_CODECS_LOC_VARS db

-      _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 <wchar.h>
+#else
+#include <ctype.h>
+#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;
+
+namespace NArchive {
+namespace N7z {
+
+#define k_Scan_NumCoders_MAX 64
+#define k_Scan_NumCodersStreams_in_Folder_MAX 64
+
+unsigned BoolVector_CountSum(const CBoolVector &v);
+unsigned BoolVector_CountSum(const CBoolVector &v)
+{
+  unsigned sum = 0;
+  const unsigned size = v.Size();
+  for (unsigned i = 0; i < size; i++)
+    if (v[i])
+      sum++;
+  return sum;
+}
+
+static inline bool BoolVector_Item_IsValidAndTrue(const CBoolVector &v, unsigned i)
+{
+  return (i < v.Size() ? v[i] : false);
+}
+
+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;
+}
+
+
+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<CByteBuffer> *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<CByteBuffer> *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 + 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<CByteBuffer> *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<UInt64> &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<CByteBuffer> *dataVector,
+    UInt64 &dataOffset,
+    CFolders &folders,
+    CRecordVector<UInt64> &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<CByteBuffer> &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<CByteBuffer> &dataVector
+    Z7_7Z_DECODER_CRYPRO_VARS_DECL
+    )
+{
+  CFolders folders;
+  CRecordVector<UInt64> 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);
+    
+    CBufPtrSeqOutStream *outStreamSpec = new CBufPtrSeqOutStream;
+    CMyComPtr<ISequentialOutStream> outStream = outStreamSpec;
+    outStreamSpec->Init(data, unpackSize);
+    
+    bool dataAfterEnd_Error = false;
+
+    HRESULT result = decoder.Decode(
+        EXTERNAL_CODECS_LOC_VARS
+        _stream, baseOffset + dataOffset,
+        folders, i,
+        NULL, // &unpackSize64
+        
+        outStream,
+        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<CByteBuffer> 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<UInt64> 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;
+  CNum 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 + 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 CNum 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)
+      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<CByteBuffer> 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 bb0e474..a9c14fb 100644
--- a/CPP/7zip/Archive/7z/7zIn.h
+++ b/CPP/7zip/Archive/7z/7zIn.h
@@ -1,445 +1,451 @@
-// 7zIn.h

-

-#ifndef __7Z_IN_H

-#define __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 _NO_CRYPTO

-#define _7Z_DECODER_CRYPRO_VARS_DECL

-#define _7Z_DECODER_CRYPRO_VARS

-#else

-#define _7Z_DECODER_CRYPRO_VARS_DECL , ICryptoGetTextPassword *getTextPassword, bool &isEncrypted, bool &passwordIsDefined, UString &password

-#define _7Z_DECODER_CRYPRO_VARS , getTextPassword, isEncrypted, passwordIsDefined, password

-#endif

-

-struct CParsedMethods

-{

-  Byte Lzma2Prop;

-  UInt32 LzmaDic;

-  CRecordVector<UInt64> IDs;

-

-  CParsedMethods(): Lzma2Prop(0), LzmaDic(0) {}

-};

-

-struct CFolderEx: public CFolder

-{

-  unsigned UnpackCoder;

-};

-

-struct CFolders

-{

-  CNum NumPackStreams;

-  CNum NumFolders;

-

-  CObjArray<UInt64> PackPositions; // NumPackStreams + 1

-  // CUInt32DefVector PackCRCs; // we don't use PackCRCs now

-

-  CUInt32DefVector FolderCRCs;             // NumFolders

-  CObjArray<CNum> NumUnpackStreamsVector;  // NumFolders

-

-  CObjArray<UInt64> CoderUnpackSizes;      // including unpack sizes of bond coders

-  CObjArray<CNum> FoToCoderUnpackSizes;    // NumFolders + 1

-  CObjArray<CNum> FoStartPackStreamIndex;  // NumFolders + 1

-  CObjArray<Byte> FoToMainUnpackSizeIndex; // NumFolders

-  

-  CObjArray<size_t> 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<CFileItem> Files;

-

-  CUInt64DefVector CTime;

-  CUInt64DefVector ATime;

-  CUInt64DefVector MTime;

-  CUInt64DefVector StartPos;

-  CUInt32DefVector Attrib;

-  CBoolVector IsAnti;

-  /*

-  CBoolVector IsAux;

-  CByteBuffer SecureBuf;

-  CRecordVector<UInt32> SecureIDs;

-  */

-

-  CByteBuffer NamesBuf;

-  CObjArray<size_t> 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;

-  UInt64 StartPositionAfterHeader;

-  UInt64 DataStartPosition;

-  UInt64 DataStartPosition2;

-  CRecordVector<UInt64> FileInfoPopIDs;

-  

-  void Clear()

-  {

-    StartPosition = 0;

-    StartPositionAfterHeader = 0;

-    DataStartPosition = 0;

-    DataStartPosition2 = 0;

-    FileInfoPopIDs.Clear();

-  }

-};

-

-struct CDbEx: public CDatabase

-{

-  CInArchiveInfo ArcInfo;

-  

-  CObjArray<CNum> FolderStartFileIndex;

-  CObjArray<CNum> FileIndexToFolderIndexMap;

-

-  UInt64 HeadersSize;

-  UInt64 PhySize;

-

-  /*

-  CRecordVector<size_t> 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;

-  }

-

-  bool CanUpdate() const

-  {

-    if (ThereIsHeaderError

-        || UnexpectedEnd

-        || StartHeaderWasRecovered

-        || UnsupportedFeatureError)

-      return false;

-    return true;

-  }

-

-  void FillLinks();

-  

-  UInt64 GetFolderStreamPos(CNum folderIndex, unsigned indexInFolder) const

-  {

-    return ArcInfo.DataStartPosition +

-        PackPositions[FoStartPackStreamIndex[folderIndex] + indexInFolder];

-  }

-  

-  UInt64 GetFolderFullPackSize(CNum folderIndex) const

-  {

-    return

-      PackPositions[FoStartPackStreamIndex[folderIndex + 1]] -

-      PackPositions[FoStartPackStreamIndex[folderIndex]];

-  }

-  

-  UInt64 GetFolderPackStreamSize(CNum folderIndex, unsigned streamIndex) const

-  {

-    size_t i = FoStartPackStreamIndex[folderIndex] + streamIndex;

-    return PackPositions[i + 1] - PackPositions[i];

-  }

-

-  UInt64 GetFilePackSize(CNum fileIndex) 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<IInStream> _stream;

-

-  unsigned _numInByteBufs;

-  CInByte2 _inByteVector[kNumBufLevelsMax];

-

-  CInByte2 *_inByteBack;

-  bool ThereIsHeaderError;

- 

-  UInt64 _arhiveBeginStreamPosition;

-  UInt64 _fileEndPosition;

-

-  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<CByteBuffer> *dataVector,

-      CFolders &folders);

-  

-  void ReadSubStreamsInfo(

-      CFolders &folders,

-      CRecordVector<UInt64> &unpackSizes,

-      CUInt32DefVector &digests);

-

-  void ReadStreamsInfo(

-      const CObjectVector<CByteBuffer> *dataVector,

-      UInt64 &dataOffset,

-      CFolders &folders,

-      CRecordVector<UInt64> &unpackSizes,

-      CUInt32DefVector &digests);

-

-  void ReadBoolVector(unsigned numItems, CBoolVector &v);

-  void ReadBoolVector2(unsigned numItems, CBoolVector &v);

-  void ReadUInt64DefVector(const CObjectVector<CByteBuffer> &dataVector,

-      CUInt64DefVector &v, unsigned numItems);

-  HRESULT ReadAndDecodePackedStreams(

-      DECL_EXTERNAL_CODECS_LOC_VARS

-      UInt64 baseOffset, UInt64 &dataOffset,

-      CObjectVector<CByteBuffer> &dataVector

-      _7Z_DECODER_CRYPRO_VARS_DECL

-      );

-  HRESULT ReadHeader(

-      DECL_EXTERNAL_CODECS_LOC_VARS

-      CDbEx &db

-      _7Z_DECODER_CRYPRO_VARS_DECL

-      );

-  HRESULT ReadDatabase2(

-      DECL_EXTERNAL_CODECS_LOC_VARS

-      CDbEx &db

-      _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

-      _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<UInt64> IDs;
+
+  CParsedMethods(): Lzma2Prop(0), LzmaDic(0) {}
+};
+
+struct CFolderEx: public CFolder
+{
+  unsigned UnpackCoder;
+};
+
+struct CFolders
+{
+  CNum NumPackStreams;
+  CNum NumFolders;
+
+  CObjArray<UInt64> PackPositions; // NumPackStreams + 1
+  // CUInt32DefVector PackCRCs; // we don't use PackCRCs now
+
+  CUInt32DefVector FolderCRCs;             // NumFolders
+  CObjArray<CNum> NumUnpackStreamsVector;  // NumFolders
+
+  CObjArray<UInt64> CoderUnpackSizes;      // including unpack sizes of bond coders
+  CObjArray<CNum> FoToCoderUnpackSizes;    // NumFolders + 1
+  CObjArray<CNum> FoStartPackStreamIndex;  // NumFolders + 1
+  CObjArray<Byte> FoToMainUnpackSizeIndex; // NumFolders
+  
+  CObjArray<size_t> 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<CFileItem> Files;
+
+  CUInt64DefVector CTime;
+  CUInt64DefVector ATime;
+  CUInt64DefVector MTime;
+  CUInt64DefVector StartPos;
+  CUInt32DefVector Attrib;
+  CBoolVector IsAnti;
+  /*
+  CBoolVector IsAux;
+  CByteBuffer SecureBuf;
+  CRecordVector<UInt32> SecureIDs;
+  */
+
+  CByteBuffer NamesBuf;
+  CObjArray<size_t> 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<UInt64> FileInfoPopIDs;
+  
+  void Clear()
+  {
+    StartPosition = 0;
+    StartPositionAfterHeader = 0;
+    DataStartPosition = 0;
+    DataStartPosition2 = 0;
+    FileInfoPopIDs.Clear();
+  }
+};
+
+
+struct CDbEx: public CDatabase
+{
+  CInArchiveInfo ArcInfo;
+  
+  CObjArray<CNum> FolderStartFileIndex;
+  CObjArray<CNum> FileIndexToFolderIndexMap;
+
+  UInt64 HeadersSize;
+  UInt64 PhySize;
+  // UInt64 EndHeaderOffset; // relative to position after StartHeader (32 bytes)
+
+  /*
+  CRecordVector<size_t> 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(CNum folderIndex, unsigned indexInFolder) const
+  {
+    return ArcInfo.DataStartPosition +
+        PackPositions[FoStartPackStreamIndex[folderIndex] + indexInFolder];
+  }
+  
+  UInt64 GetFolderFullPackSize(CNum folderIndex) const
+  {
+    return
+      PackPositions[FoStartPackStreamIndex[folderIndex + 1]] -
+      PackPositions[FoStartPackStreamIndex[folderIndex]];
+  }
+  
+  UInt64 GetFolderPackStreamSize(CNum folderIndex, unsigned streamIndex) const
+  {
+    size_t i = FoStartPackStreamIndex[folderIndex] + streamIndex;
+    return PackPositions[i + 1] - PackPositions[i];
+  }
+
+  UInt64 GetFilePackSize(CNum fileIndex) 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<IInStream> _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<CByteBuffer> *dataVector,
+      CFolders &folders);
+  
+  void ReadSubStreamsInfo(
+      CFolders &folders,
+      CRecordVector<UInt64> &unpackSizes,
+      CUInt32DefVector &digests);
+
+  void ReadStreamsInfo(
+      const CObjectVector<CByteBuffer> *dataVector,
+      UInt64 &dataOffset,
+      CFolders &folders,
+      CRecordVector<UInt64> &unpackSizes,
+      CUInt32DefVector &digests);
+
+  void ReadBoolVector(unsigned numItems, CBoolVector &v);
+  void ReadBoolVector2(unsigned numItems, CBoolVector &v);
+  void ReadUInt64DefVector(const CObjectVector<CByteBuffer> &dataVector,
+      CUInt64DefVector &v, unsigned numItems);
+  HRESULT ReadAndDecodePackedStreams(
+      DECL_EXTERNAL_CODECS_LOC_VARS
+      UInt64 baseOffset, UInt64 &dataOffset,
+      CObjectVector<CByteBuffer> &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 90cf98c..e8c68be 100644
--- a/CPP/7zip/Archive/7z/7zItem.h
+++ b/CPP/7zip/Archive/7z/7zItem.h
@@ -1,202 +1,207 @@
-// 7zItem.h

-

-#ifndef __7Z_ITEM_H

-#define __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

-{

-  CLASS_NO_COPY(CFolder)

-public:

-  CObjArray2<CCoderInfo> Coders;

-  CObjArray2<CBond> Bonds;

-  CObjArray2<UInt32> 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 i;

-    return -1;

-  }

-

-  int FindBond_for_PackStream(UInt32 packStream) const

-  {

-    FOR_VECTOR(i, Bonds)

-      if (Bonds[i].PackIndex == packStream)

-        return 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<UInt32> 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);

-};

-

-

-struct CUInt64DefVector

-{

-  CBoolVector Defs;

-  CRecordVector<UInt64> 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<CCoderInfo> Coders;
+  CObjArray2<CBond> Bonds;
+  CObjArray2<UInt32> 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<UInt32> 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_FillResedue_with_false(unsigned numItems)
+  {
+    if (Defs.Size() != 0 && Defs.Size() < numItems)
+      SetItem(numItems - 1, false, 0);
+  }
+};
+
+
+struct CUInt64DefVector
+{
+  CBoolVector Defs;
+  CRecordVector<UInt64> 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 5bd3a41..7f8fa5b 100644
--- a/CPP/7zip/Archive/7z/7zOut.cpp
+++ b/CPP/7zip/Archive/7z/7zOut.cpp
@@ -1,901 +1,955 @@
-// 7zOut.cpp

-

-#include "StdAfx.h"

-

-#include "../../../../C/7zCrc.h"

-

-#include "../../../Common/AutoPtr.h"

-

-#include "../../Common/StreamObjects.h"

-

-#include "7zOut.h"

-

-namespace NArchive {

-namespace N7z {

-

-HRESULT COutArchive::WriteSignature()

-{

-  Byte buf[8];

-  memcpy(buf, kSignature, kSignatureSize);

-  buf[kSignatureSize] = kMajorVersion;

-  buf[kSignatureSize + 1] = 4;

-  return WriteDirect(buf, 8);

-}

-

-#ifdef _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[24];

-  SetUInt64(buf + 4, h.NextHeaderOffset);

-  SetUInt64(buf + 12, h.NextHeaderSize);

-  SetUInt32(buf + 20, h.NextHeaderCRC);

-  SetUInt32(buf, CrcCalc(buf + 4, 20));

-  return WriteDirect(buf, 24);

-}

-

-#ifdef _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(ISequentialOutStream *stream, bool endMarker)

-{

-  Close();

-  #ifdef _7Z_VOL

-  // endMarker = false;

-  _endMarker = endMarker;

-  #endif

-  SeqStream = stream;

-  if (!endMarker)

-  {

-    SeqStream.QueryInterface(IID_IOutStream, &Stream);

-    if (!Stream)

-    {

-      return E_NOTIMPL;

-      // endMarker = true;

-    }

-  }

-  #ifdef _7Z_VOL

-  if (endMarker)

-  {

-    /*

-    CStartHeader sh;

-    sh.NextHeaderOffset = (UInt32)(Int32)-1;

-    sh.NextHeaderSize = (UInt32)(Int32)-1;

-    sh.NextHeaderCRC = 0;

-    WriteStartHeader(sh);

-    */

-  }

-  else

-  #endif

-  {

-    if (!Stream)

-      return E_FAIL;

-    RINOK(WriteSignature());

-    RINOK(Stream->Seek(0, STREAM_SEEK_CUR, &_prefixHeaderPos));

-  }

-  return S_OK;

-}

-

-void COutArchive::Close()

-{

-  SeqStream.Release();

-  Stream.Release();

-}

-

-HRESULT COutArchive::SkipPrefixArchiveHeader()

-{

-  #ifdef _7Z_VOL

-  if (_endMarker)

-    return S_OK;

-  #endif

-  Byte buf[24];

-  memset(buf, 0, 24);

-  return WriteDirect(buf, 24);

-}

-

-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)

-  {

-    _outByte.WriteByte(b);

-    _crc = CRC_UPDATE_BYTE(_crc, 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 >>= 1;

-  }

-  WriteByte(firstByte);

-  for (; i > 0; i--)

-  {

-    WriteByte((Byte)value);

-    value >>= 8;

-  }

-}

-

-static UInt32 GetBigNumberSize(UInt64 value)

-{

-  int i;

-  for (i = 1; i < 9; i++)

-    if (value < (((UInt64)1 << (i * 7))))

-      break;

-  return i;

-}

-

-#ifdef _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;

-      Byte temp[16];

-      for (unsigned t = idSize; t != 0; t--, id >>= 8)

-        temp[t] = (Byte)(id & 0xFF);

-  

-      Byte b = (Byte)(idSize);

-      bool isComplex = !coder.IsSimpleCoder();

-      b |= (isComplex ? 0x10 : 0);

-

-      size_t propsSize = coder.Props.Size();

-      b |= ((propsSize != 0) ? 0x20 : 0);

-      temp[0] = 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::WriteBoolVector(const CBoolVector &boolVector)

-{

-  Byte b = 0;

-  Byte mask = 0x80;

-  FOR_VECTOR (i, boolVector)

-  {

-    if (boolVector[i])

-      b |= mask;

-    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));

-  WriteBoolVector(boolVector);

-}

-

-unsigned BoolVector_CountSum(const CBoolVector &v);

-

-void COutArchive::WriteHashDigests(const CUInt32DefVector &digests)

-{

-  const unsigned numDefined = BoolVector_CountSum(digests.Defs);

-  if (numDefined == 0)

-    return;

-

-  WriteByte(NID::kCRC);

-  if (numDefined == digests.Defs.Size())

-    WriteByte(1);

-  else

-  {

-    WriteByte(0);

-    WriteBoolVector(digests.Defs);

-  }

-  

-  for (unsigned i = 0; i < digests.Defs.Size(); i++)

-    if (digests.Defs[i])

-      WriteUInt32(digests.Vals[i]);

-}

-

-void COutArchive::WritePackInfo(

-    UInt64 dataOffset,

-    const CRecordVector<UInt64> &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<CFolder> &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<CFolder> &folders,

-    const COutFolders &outFolders,

-    const CRecordVector<UInt64> &unpackSizes,

-    const CUInt32DefVector &digests)

-{

-  const CRecordVector<CNum> &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 + (unsigned)bvSize + (unsigned)GetBigNumberSize(dataSize), itemSizeShifts);

-

-  WriteByte(type);

-  WriteNumber(dataSize);

-  if (numDefined == v.Size())

-    WriteByte(1);

-  else

-  {

-    WriteByte(0);

-    WriteBoolVector(v);

-  }

-  WriteByte(0); // 0 means no switching to external stream

-}

-

-void COutArchive::WriteUInt64DefVector(const CUInt64DefVector &v, Byte type)

-{

-  const unsigned numDefined = BoolVector_CountSum(v.Defs);

-  if (numDefined == 0)

-    return;

-

-  WriteAlignedBools(v.Defs, numDefined, type, 3);

-  

-  for (unsigned i = 0; i < v.Defs.Size(); i++)

-    if (v.Defs[i])

-      WriteUInt64(v.Vals[i]);

-}

-

-HRESULT COutArchive::EncodeStream(

-    DECL_EXTERNAL_CODECS_LOC_VARS

-    CEncoder &encoder, const CByteBuffer &data,

-    CRecordVector<UInt64> &packSizes, CObjectVector<CFolder> &folders, COutFolders &outFolders)

-{

-  CBufInStream *streamSpec = new CBufInStream;

-  CMyComPtr<ISequentialInStream> stream = streamSpec;

-  streamSpec->Init(data, data.Size());

-  outFolders.FolderUnpackCRCs.Defs.Add(true);

-  outFolders.FolderUnpackCRCs.Vals.Add(CrcCalc(data, data.Size()));

-  // outFolders.NumUnpackStreamsVector.Add(1);

-  UInt64 dataSize64 = data.Size();

-  UInt64 unpackSize = data.Size();

-  RINOK(encoder.Encode(

-      EXTERNAL_CODECS_LOC_VARS

-      stream,

-      // NULL,

-      &dataSize64,

-      folders.AddNew(), outFolders.CoderUnpackSizes, unpackSize, SeqStream, packSizes, NULL))

-  return S_OK;

-}

-

-void COutArchive::WriteHeader(

-    const CArchiveDatabaseOut &db,

-    // const CHeaderOptions &headerOptions,

-    UInt64 &headerOffset)

-{

-  /*

-  bool thereIsSecure = (db.SecureBuf.Size() != 0);

-  */

-  _useAlign = true;

-

-  {

-    UInt64 packSize = 0;

-    FOR_VECTOR (i, db.PackSizes)

-      packSize += db.PackSizes[i];

-    headerOffset = packSize;

-  }

-

-

-  WriteByte(NID::kHeader);

-

-  // Archive Properties

-

-  if (db.Folders.Size() > 0)

-  {

-    WriteByte(NID::kMainStreamsInfo);

-    WritePackInfo(0, db.PackSizes, db.PackCRCs);

-    WriteUnpackInfo(db.Folders, (const COutFolders &)db);

-

-    CRecordVector<UInt64> 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 ---------- */

-    

-    unsigned numDefined = 0;

-    size_t namesDataSize = 0;

-    FOR_VECTOR (i, db.Files)

-    {

-      const UString &name = db.Names[i];

-      if (!name.IsEmpty())

-        numDefined++;

-      namesDataSize += (name.Len() + 1) * 2;

-    }

-    

-    if (numDefined > 0)

-    {

-      namesDataSize++;

-      SkipToAligned(2 + GetBigNumberSize(namesDataSize), 4);

-

-      WriteByte(NID::kName);

-      WriteNumber(namesDataSize);

-      WriteByte(0);

-      FOR_VECTOR (i, db.Files)

-      {

-        const UString &name = db.Names[i];

-        for (unsigned t = 0; t <= name.Len(); t++)

-        {

-          wchar_t c = name[t];

-          WriteByte((Byte)c);

-          WriteByte((Byte)(c >> 8));

-        }

-      }

-    }

-  }

-

-  /* if (headerOptions.WriteCTime) */ WriteUInt64DefVector(db.CTime, NID::kCTime);

-  /* if (headerOptions.WriteATime) */ WriteUInt64DefVector(db.ATime, NID::kATime);

-  /* if (headerOptions.WriteMTime) */ WriteUInt64DefVector(db.MTime, NID::kMTime);

-  WriteUInt64DefVector(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);

-      FOR_VECTOR (i, db.Attrib.Defs)

-      {

-        if (db.Attrib.Defs[i])

-          WriteUInt32(db.Attrib.Vals[i]);

-      }

-    }

-  }

-

-  /*

-  {

-    // ---------- 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);

-      if (numIsDir == boolVector.Size())

-        WriteByte(1);

-      else

-      {

-        WriteByte(0);

-        WriteBoolVector(boolVector);

-      }

-      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;

-

-  UInt64 headerOffset;

-  UInt32 headerCRC;

-  UInt64 headerSize;

-  if (db.IsEmpty())

-  {

-    headerSize = 0;

-    headerOffset = 0;

-    headerCRC = CrcCalc(0, 0);

-  }

-  else

-  {

-    bool encodeHeaders = false;

-    if (options != 0)

-      if (options->IsEmpty())

-        options = 0;

-    if (options != 0)

-      if (options->PasswordIsDefined || headerOptions.CompressMainHeader)

-        encodeHeaders = true;

-

-    _outByte.SetStream(SeqStream);

-    _outByte.Init();

-    _crc = CRC_INIT_VAL;

-    _countMode = encodeHeaders;

-    _writeToStream = true;

-    _countSize = 0;

-    WriteHeader(db, /* headerOptions, */ headerOffset);

-

-    if (encodeHeaders)

-    {

-      CByteBuffer buf(_countSize);

-      _outByte2.Init((Byte *)buf, _countSize);

-      

-      _countMode = false;

-      _writeToStream = false;

-      WriteHeader(db, /* headerOptions, */ headerOffset);

-      

-      if (_countSize != _outByte2.GetPos())

-        return E_FAIL;

-

-      CCompressionMethodMode encryptOptions;

-      encryptOptions.PasswordIsDefined = options->PasswordIsDefined;

-      encryptOptions.Password = options->Password;

-      CEncoder encoder(headerOptions.CompressMainHeader ? *options : encryptOptions);

-      CRecordVector<UInt64> packSizes;

-      CObjectVector<CFolder> 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(headerOffset, packSizes, CUInt32DefVector());

-      WriteUnpackInfo(folders, outFolders);

-      WriteByte(NID::kEnd);

-      FOR_VECTOR (i, packSizes)

-        headerOffset += packSizes[i];

-    }

-    RINOK(_outByte.Flush());

-    headerCRC = CRC_GET_DIGEST(_crc);

-    headerSize = _outByte.GetProcessedSize();

-  }

-  #ifdef _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

-  {

-    CStartHeader h;

-    h.NextHeaderSize = headerSize;

-    h.NextHeaderCRC = headerCRC;

-    h.NextHeaderOffset = headerOffset;

-    RINOK(Stream->Seek(_prefixHeaderPos, STREAM_SEEK_SET, NULL));

-    return WriteStartHeader(h);

-  }

-}

-

-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 "../../../Common/AutoPtr.h"
+// #include "../../../Common/UTFConvert.h"
+
+#include "../../Common/StreamObjects.h"
+
+#include "7zOut.h"
+
+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)
+  {
+    _outByte.WriteByte(b);
+    _crc = CRC_UPDATE_BYTE(_crc, 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::WriteBoolVector(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));
+  WriteBoolVector(boolVector);
+}
+
+unsigned BoolVector_CountSum(const CBoolVector &v);
+
+void COutArchive::WriteHashDigests(const CUInt32DefVector &digests)
+{
+  const unsigned numDefined = BoolVector_CountSum(digests.Defs);
+  if (numDefined == 0)
+    return;
+
+  WriteByte(NID::kCRC);
+  if (numDefined == digests.Defs.Size())
+    WriteByte(1);
+  else
+  {
+    WriteByte(0);
+    WriteBoolVector(digests.Defs);
+  }
+  
+  for (unsigned i = 0; i < digests.Defs.Size(); i++)
+    if (digests.Defs[i])
+      WriteUInt32(digests.Vals[i]);
+}
+
+void COutArchive::WritePackInfo(
+    UInt64 dataOffset,
+    const CRecordVector<UInt64> &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<CFolder> &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<CFolder> &folders,
+    const COutFolders &outFolders,
+    const CRecordVector<UInt64> &unpackSizes,
+    const CUInt32DefVector &digests)
+{
+  const CRecordVector<CNum> &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);
+  if (numDefined == v.Size())
+    WriteByte(1);
+  else
+  {
+    WriteByte(0);
+    WriteBoolVector(v);
+  }
+  WriteByte(0); // 0 means no switching to external stream
+}
+
+void COutArchive::WriteUInt64DefVector(const CUInt64DefVector &v, Byte type)
+{
+  const unsigned numDefined = BoolVector_CountSum(v.Defs);
+  if (numDefined == 0)
+    return;
+
+  WriteAlignedBools(v.Defs, numDefined, type, 3);
+  
+  for (unsigned i = 0; i < v.Defs.Size(); i++)
+    if (v.Defs[i])
+      WriteUInt64(v.Vals[i]);
+}
+
+HRESULT COutArchive::EncodeStream(
+    DECL_EXTERNAL_CODECS_LOC_VARS
+    CEncoder &encoder, const CByteBuffer &data,
+    CRecordVector<UInt64> &packSizes, CObjectVector<CFolder> &folders, COutFolders &outFolders)
+{
+  CBufInStream *streamSpec = new CBufInStream;
+  CMyComPtr<ISequentialInStream> stream = 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
+      stream,
+      // 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;
+
+  {
+    UInt64 packSize = 0;
+    FOR_VECTOR (i, db.PackSizes)
+      packSize += db.PackSizes[i];
+    headerOffset = packSize;
+  }
+
+
+  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<UInt64> 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 ---------- */
+    
+    unsigned numDefined = 0;
+    size_t namesDataSize = 0;
+    FOR_VECTOR (i, db.Files)
+    {
+      const UString &name = db.Names[i];
+      if (!name.IsEmpty())
+        numDefined++;
+      const size_t numUtfChars =
+      /*
+      #if WCHAR_MAX > 0xffff
+        Get_Num_Utf16_chars_from_wchar_string(name.Ptr());
+      #else
+      */
+        name.Len();
+      // #endif
+      namesDataSize += (numUtfChars + 1) * 2;
+    }
+    
+    if (numDefined > 0)
+    {
+      namesDataSize++;
+      SkipToAligned(2 + GetBigNumberSize(namesDataSize), 4);
+
+      WriteByte(NID::kName);
+      WriteNumber(namesDataSize);
+      WriteByte(0);
+      FOR_VECTOR (i, db.Files)
+      {
+        const UString &name = db.Names[i];
+        for (unsigned t = 0; t <= name.Len(); t++)
+        {
+          wchar_t c = name[t];
+
+          /*
+          #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
+          */
+  
+          WriteByte((Byte)c);
+          WriteByte((Byte)(c >> 8));
+        }
+      }
+    }
+  }
+
+  /* if (headerOptions.WriteCTime) */ WriteUInt64DefVector(db.CTime, NID::kCTime);
+  /* if (headerOptions.WriteATime) */ WriteUInt64DefVector(db.ATime, NID::kATime);
+  /* if (headerOptions.WriteMTime) */ WriteUInt64DefVector(db.MTime, NID::kMTime);
+  WriteUInt64DefVector(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);
+      FOR_VECTOR (i, db.Attrib.Defs)
+      {
+        if (db.Attrib.Defs[i])
+          WriteUInt32(db.Attrib.Vals[i]);
+      }
+    }
+  }
+
+  /*
+  {
+    // ---------- 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);
+      if (numIsDir == boolVector.Size())
+        WriteByte(1);
+      else
+      {
+        WriteByte(0);
+        WriteBoolVector(boolVector);
+      }
+      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;
+
+  UInt64 headerOffset;
+  UInt32 headerCRC;
+  UInt64 headerSize;
+  if (db.IsEmpty())
+  {
+    headerSize = 0;
+    headerOffset = 0;
+    headerCRC = CrcCalc(NULL, 0);
+  }
+  else
+  {
+    bool encodeHeaders = false;
+    if (options)
+      if (options->IsEmpty())
+        options = NULL;
+    if (options)
+      if (options->PasswordIsDefined || headerOptions.CompressMainHeader)
+        encodeHeaders = true;
+
+    _outByte.SetStream(SeqStream);
+    _outByte.Init();
+    _crc = CRC_INIT_VAL;
+    _countMode = encodeHeaders;
+    _writeToStream = true;
+    _countSize = 0;
+    WriteHeader(db, /* headerOptions, */ headerOffset);
+
+    if (encodeHeaders)
+    {
+      CByteBuffer buf(_countSize);
+      _outByte2.Init((Byte *)buf, _countSize);
+      
+      _countMode = false;
+      _writeToStream = false;
+      WriteHeader(db, /* headerOptions, */ headerOffset);
+      
+      if (_countSize != _outByte2.GetPos())
+        return E_FAIL;
+
+      CCompressionMethodMode encryptOptions;
+      encryptOptions.PasswordIsDefined = options->PasswordIsDefined;
+      encryptOptions.Password = options->Password;
+      CEncoder encoder(headerOptions.CompressMainHeader ? *options : encryptOptions);
+      CRecordVector<UInt64> packSizes;
+      CObjectVector<CFolder> 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(headerOffset, packSizes, CUInt32DefVector());
+      WriteUnpackInfo(folders, outFolders);
+      WriteByte(NID::kEnd);
+      FOR_VECTOR (i, packSizes)
+        headerOffset += packSizes[i];
+    }
+    RINOK(_outByte.Flush())
+    headerCRC = CRC_GET_DIGEST(_crc);
+    headerSize = _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)
+  {
+    CStartHeader h;
+    h.NextHeaderSize = headerSize;
+    h.NextHeaderCRC = headerCRC;
+    h.NextHeaderOffset = headerOffset;
+    RINOK(Stream->Seek((Int64)_signatureHeaderPos, STREAM_SEEK_SET, NULL))
+    return WriteStartHeader(h);
+  }
+  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 12e965f..940cafc 100644
--- a/CPP/7zip/Archive/7z/7zOut.h
+++ b/CPP/7zip/Archive/7z/7zOut.h
@@ -1,335 +1,330 @@
-// 7zOut.h

-

-#ifndef __7Z_OUT_H

-#define __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 {

-

-class CWriteBufferLoc

-{

-  Byte *_data;

-  size_t _size;

-  size_t _pos;

-public:

-  CWriteBufferLoc(): _size(0), _pos(0) {}

-  void Init(Byte *data, size_t size)

-  {

-    _data = data;

-    _size = size;

-    _pos = 0;

-  }

-  void WriteBytes(const void *data, size_t size)

-  {

-    if (size == 0)

-      return;

-    if (size > _size - _pos)

-      throw 1;

-    memcpy(_data + _pos, data, size);

-    _pos += size;

-  }

-  void WriteByte(Byte b)

-  {

-    if (_size == _pos)

-      throw 1;

-    _data[_pos++] = b;

-  }

-  size_t GetPos() const { return _pos; }

-};

-

-

-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<CNum> NumUnpackStreamsVector;

-  CRecordVector<UInt64> 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<UInt64> PackSizes;

-  CUInt32DefVector PackCRCs;

-  CObjectVector<CFolder> Folders;

-

-  CRecordVector<CFileItem> Files;

-  UStringVector Names;

-  CUInt64DefVector CTime;

-  CUInt64DefVector ATime;

-  CUInt64DefVector MTime;

-  CUInt64DefVector StartPos;

-  CUInt32DefVector Attrib;

-  CBoolVector IsAnti;

-

-  /*

-  CBoolVector IsAux;

-

-  CByteBuffer SecureBuf;

-  CRecordVector<UInt32> SecureSizes;

-  CRecordVector<UInt32> 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

-{

-  UInt64 _prefixHeaderPos;

-

-  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 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 WriteBoolVector(const CBoolVector &boolVector);

-  void WritePropBoolVector(Byte id, const CBoolVector &boolVector);

-

-  void WriteHashDigests(const CUInt32DefVector &digests);

-

-  void WritePackInfo(

-      UInt64 dataOffset,

-      const CRecordVector<UInt64> &packSizes,

-      const CUInt32DefVector &packCRCs);

-

-  void WriteUnpackInfo(

-      const CObjectVector<CFolder> &folders,

-      const COutFolders &outFolders);

-

-  void WriteSubStreamsInfo(

-      const CObjectVector<CFolder> &folders,

-      const COutFolders &outFolders,

-      const CRecordVector<UInt64> &unpackSizes,

-      const CUInt32DefVector &digests);

-

-  void SkipToAligned(unsigned pos, unsigned alignShifts);

-  void WriteAlignedBools(const CBoolVector &v, unsigned numDefined, Byte type, unsigned itemSizeShifts);

-  void WriteUInt64DefVector(const CUInt64DefVector &v, Byte type);

-

-  HRESULT EncodeStream(

-      DECL_EXTERNAL_CODECS_LOC_VARS

-      CEncoder &encoder, const CByteBuffer &data,

-      CRecordVector<UInt64> &packSizes, CObjectVector<CFolder> &folders, COutFolders &outFolders);

-  void WriteHeader(

-      const CArchiveDatabaseOut &db,

-      // const CHeaderOptions &headerOptions,

-      UInt64 &headerOffset);

-  

-  bool _countMode;

-  bool _writeToStream;

-  size_t _countSize;

-  UInt32 _crc;

-  COutBuffer _outByte;

-  CWriteBufferLoc _outByte2;

-

-  #ifdef _7Z_VOL

-  bool _endMarker;

-  #endif

-

-  bool _useAlign;

-

-  HRESULT WriteSignature();

-  #ifdef _7Z_VOL

-  HRESULT WriteFinishSignature();

-  #endif

-  HRESULT WriteStartHeader(const CStartHeader &h);

-  #ifdef _7Z_VOL

-  HRESULT WriteFinishHeader(const CFinishHeader &h);

-  #endif

-  CMyComPtr<IOutStream> Stream;

-public:

-

-  COutArchive() { _outByte.Create(1 << 16); }

-  CMyComPtr<ISequentialOutStream> SeqStream;

-  HRESULT Create(ISequentialOutStream *stream, bool endMarker);

-  void Close();

-  HRESULT SkipPrefixArchiveHeader();

-  HRESULT WriteDatabase(

-      DECL_EXTERNAL_CODECS_LOC_VARS

-      const CArchiveDatabaseOut &db,

-      const CCompressionMethodMode *options,

-      const CHeaderOptions &headerOptions);

-

-  #ifdef _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;
+  size_t _size;
+  size_t _pos;
+public:
+  CWriteBufferLoc(): _size(0), _pos(0) {}
+  void Init(Byte *data, size_t size)
+  {
+    _data = data;
+    _size = size;
+    _pos = 0;
+  }
+  void WriteBytes(const void *data, size_t size)
+  {
+    if (size == 0)
+      return;
+    if (size > _size - _pos)
+      throw 1;
+    memcpy(_data + _pos, data, size);
+    _pos += size;
+  }
+  void WriteByte(Byte b)
+  {
+    if (_size == _pos)
+      throw 1;
+    _data[_pos++] = b;
+  }
+  size_t GetPos() const { return _pos; }
+};
+
+
+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<CNum> NumUnpackStreamsVector;
+  CRecordVector<UInt64> 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<UInt64> PackSizes;
+  CUInt32DefVector PackCRCs;
+  CObjectVector<CFolder> Folders;
+
+  CRecordVector<CFileItem> Files;
+  UStringVector Names;
+  CUInt64DefVector CTime;
+  CUInt64DefVector ATime;
+  CUInt64DefVector MTime;
+  CUInt64DefVector StartPos;
+  CUInt32DefVector Attrib;
+  CBoolVector IsAnti;
+
+  /*
+  CBoolVector IsAux;
+
+  CByteBuffer SecureBuf;
+  CRecordVector<UInt32> SecureSizes;
+  CRecordVector<UInt32> 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 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 WriteBoolVector(const CBoolVector &boolVector);
+  void WritePropBoolVector(Byte id, const CBoolVector &boolVector);
+
+  void WriteHashDigests(const CUInt32DefVector &digests);
+
+  void WritePackInfo(
+      UInt64 dataOffset,
+      const CRecordVector<UInt64> &packSizes,
+      const CUInt32DefVector &packCRCs);
+
+  void WriteUnpackInfo(
+      const CObjectVector<CFolder> &folders,
+      const COutFolders &outFolders);
+
+  void WriteSubStreamsInfo(
+      const CObjectVector<CFolder> &folders,
+      const COutFolders &outFolders,
+      const CRecordVector<UInt64> &unpackSizes,
+      const CUInt32DefVector &digests);
+
+  void SkipToAligned(unsigned pos, unsigned alignShifts);
+  void WriteAlignedBools(const CBoolVector &v, unsigned numDefined, Byte type, unsigned itemSizeShifts);
+  void WriteUInt64DefVector(const CUInt64DefVector &v, Byte type);
+
+  HRESULT EncodeStream(
+      DECL_EXTERNAL_CODECS_LOC_VARS
+      CEncoder &encoder, const CByteBuffer &data,
+      CRecordVector<UInt64> &packSizes, CObjectVector<CFolder> &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<IOutStream> Stream;
+
+  #ifdef Z7_7Z_VOL
+  HRESULT WriteFinishSignature();
+  HRESULT WriteFinishHeader(const CFinishHeader &h);
+  #endif
+  HRESULT WriteStartHeader(const CStartHeader &h);
+
+public:
+  CMyComPtr<ISequentialOutStream> SeqStream;
+
+  COutArchive() { _outByte.Create(1 << 16); }
+  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 388ac76..d3b3cbe 100644
--- a/CPP/7zip/Archive/7z/7zProperties.cpp
+++ b/CPP/7zip/Archive/7z/7zProperties.cpp
@@ -1,174 +1,182 @@
-// 7zProperties.cpp

-

-#include "StdAfx.h"

-

-#include "7zProperties.h"

-#include "7zHeader.h"

-#include "7zHandler.h"

-

-// #define _MULTI_PACK

-

-namespace NArchive {

-namespace N7z {

-

-struct CPropMap

-{

-  UInt32 FilePropID;

-  CStatProp StatProp;

-};

-

-static const CPropMap kPropMap[] =

-{

-  { NID::kName, { NULL, kpidPath, VT_BSTR } },

-  { NID::kSize, { NULL, kpidSize, VT_UI8 } },

-  { NID::kPackInfo, { NULL, kpidPackSize, VT_UI8 } },

-  

-  #ifdef _MULTI_PACK

-  { 100, { "Pack0", kpidPackedSize0, VT_UI8 } },

-  { 101, { "Pack1", kpidPackedSize1, VT_UI8 } },

-  { 102, { "Pack2", kpidPackedSize2, VT_UI8 } },

-  { 103, { "Pack3", kpidPackedSize3, VT_UI8 } },

-  { 104, { "Pack4", kpidPackedSize4, VT_UI8 } },

-  #endif

-

-  { NID::kCTime, { NULL, kpidCTime, VT_FILETIME } },

-  { NID::kMTime, { NULL, kpidMTime, VT_FILETIME } },

-  { NID::kATime, { NULL, kpidATime, VT_FILETIME } },

-  { NID::kWinAttrib, { NULL, kpidAttrib, VT_UI4 } },

-  { NID::kStartPos, { NULL, kpidPosition, VT_UI8 } },

-

-  { NID::kCRC, { NULL, kpidCRC, VT_UI4 } },

-  

-//  { NID::kIsAux, { NULL, kpidIsAux, VT_BOOL } },

-  { NID::kAnti, { NULL, kpidIsAnti, VT_BOOL } }

-

-  #ifndef _SFX

-  ,

-  { 97, { NULL, kpidEncrypted, VT_BOOL } },

-  { 98, { NULL, kpidMethod, VT_BSTR } },

-  { 99, { NULL, kpidBlock, VT_UI4 } }

-  #endif

-};

-

-static void CopyOneItem(CRecordVector<UInt64> &src,

-    CRecordVector<UInt64> &dest, UInt32 item)

-{

-  FOR_VECTOR (i, src)

-    if (src[i] == item)

-    {

-      dest.Add(item);

-      src.Delete(i);

-      return;

-    }

-}

-

-static void RemoveOneItem(CRecordVector<UInt64> &src, UInt32 item)

-{

-  FOR_VECTOR (i, src)

-    if (src[i] == item)

-    {

-      src.Delete(i);

-      return;

-    }

-}

-

-static void InsertToHead(CRecordVector<UInt64> &dest, 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 _7Z_VOL

-  if (_volumes.Size() < 1)

-    return;

-  const CVolume &volume = _volumes.Front();

-  const CArchiveDatabaseEx &_db = volume.Database;

-  #endif

-

-  CRecordVector<UInt64> 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 _SFX

-  _fileInfoPopIDs.Add(97);

-  _fileInfoPopIDs.Add(98);

-  _fileInfoPopIDs.Add(99);

-  #endif

-

-  #ifdef _MULTI_PACK

-  _fileInfoPopIDs.Add(100);

-  _fileInfoPopIDs.Add(101);

-  _fileInfoPopIDs.Add(102);

-  _fileInfoPopIDs.Add(103);

-  _fileInfoPopIDs.Add(104);

-  #endif

-

-  #ifndef _SFX

-  InsertToHead(_fileInfoPopIDs, NID::kMTime);

-  InsertToHead(_fileInfoPopIDs, NID::kPackInfo);

-  InsertToHead(_fileInfoPopIDs, NID::kSize);

-  InsertToHead(_fileInfoPopIDs, NID::kName);

-  #endif

-}

-

-STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProps)

-{

-  *numProps = _fileInfoPopIDs.Size();

-  return S_OK;

-}

-

-STDMETHODIMP CHandler::GetPropertyInfo(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)

-{

-  if (index >= _fileInfoPopIDs.Size())

-    return E_INVALIDARG;

-  UInt64 id = _fileInfoPopIDs[index];

-  for (unsigned i = 0; i < ARRAY_SIZE(kPropMap); i++)

-  {

-    const CPropMap &pr = kPropMap[i];

-    if (pr.FilePropID == id)

-    {

-      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<UInt64> &src,
+    CRecordVector<UInt64> &dest, const UInt32 item)
+{
+  FOR_VECTOR (i, src)
+    if (src[i] == item)
+    {
+      dest.Add(item);
+      src.Delete(i);
+      return;
+    }
+}
+
+static void RemoveOneItem(CRecordVector<UInt64> &src, const UInt32 item)
+{
+  FOR_VECTOR (i, src)
+    if (src[i] == item)
+    {
+      src.Delete(i);
+      return;
+    }
+}
+
+static void InsertToHead(CRecordVector<UInt64> &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<UInt64> 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 7b78130..091c39b 100644
--- a/CPP/7zip/Archive/7z/7zProperties.h
+++ b/CPP/7zip/Archive/7z/7zProperties.h
@@ -1,22 +1,26 @@
-// 7zProperties.h

-

-#ifndef __7Z_PROPERTIES_H

-#define __7Z_PROPERTIES_H

-

-#include "../../PropID.h"

-

-namespace NArchive {

-namespace N7z {

-

-enum

-{

-  kpidPackedSize0 = kpidUserDefined,

-  kpidPackedSize1,

-  kpidPackedSize2,

-  kpidPackedSize3,

-  kpidPackedSize4

-};

-

-}}

-

-#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 3e8cfb6..1f11079 100644
--- a/CPP/7zip/Archive/7z/7zRegister.cpp
+++ b/CPP/7zip/Archive/7z/7zRegister.cpp
@@ -1,21 +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,

-  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 e9671a8..8b531bc 100644
--- a/CPP/7zip/Archive/7z/7zSpecStream.cpp
+++ b/CPP/7zip/Archive/7z/7zSpecStream.cpp
@@ -1,22 +1,31 @@
-// 7zSpecStream.cpp

-

-#include "StdAfx.h"

-

-#include "7zSpecStream.h"

-

-STDMETHODIMP CSequentialInStreamSizeCount2::Read(void *data, UInt32 size, UInt32 *processedSize)

-{

-  UInt32 realProcessedSize;

-  HRESULT result = _stream->Read(data, size, &realProcessedSize);

-  _size += realProcessedSize;

-  if (processedSize)

-    *processedSize = realProcessedSize;

-  return result;

-}

-

-STDMETHODIMP CSequentialInStreamSizeCount2::GetSubStreamSize(UInt64 subStream, UInt64 *value)

-{

-  if (!_getSubStreamSize)

-    return E_NOTIMPL;

-  return _getSubStreamSize->GetSubStreamSize(subStream, value);

-}

+// 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 0994128..78f631e 100644
--- a/CPP/7zip/Archive/7z/7zSpecStream.h
+++ b/CPP/7zip/Archive/7z/7zSpecStream.h
@@ -1,35 +1,49 @@
-// 7zSpecStream.h

-

-#ifndef __7Z_SPEC_STREAM_H

-#define __7Z_SPEC_STREAM_H

-

-#include "../../../Common/MyCom.h"

-

-#include "../../ICoder.h"

-

-class CSequentialInStreamSizeCount2:

-  public ISequentialInStream,

-  public ICompressGetSubStreamSize,

-  public CMyUnknownImp

-{

-  CMyComPtr<ISequentialInStream> _stream;

-  CMyComPtr<ICompressGetSubStreamSize> _getSubStreamSize;

-  UInt64 _size;

-public:

-  void Init(ISequentialInStream *stream)

-  {

-    _size = 0;

-    _getSubStreamSize.Release();

-    _stream = stream;

-    _stream.QueryInterface(IID_ICompressGetSubStreamSize, &_getSubStreamSize);

-  }

-  UInt64 GetSize() const { return _size; }

-

-  MY_UNKNOWN_IMP2(ISequentialInStream, ICompressGetSubStreamSize)

-

-  STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);

-

-  STDMETHOD(GetSubStreamSize)(UInt64 subStream, UInt64 *value);

-};

-

-#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<ISequentialInStream> _stream;
+  CMyComPtr<ICompressGetSubStreamSize> _getSubStreamSize;
+  CMyComPtr<ICompressInSubStreams> _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 5b156be..4e9ea5d 100644
--- a/CPP/7zip/Archive/7z/7zUpdate.cpp
+++ b/CPP/7zip/Archive/7z/7zUpdate.cpp
@@ -1,2500 +1,2991 @@
-// 7zUpdate.cpp

-

-#include "StdAfx.h"

-

-#include "../../../../C/CpuArch.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;

-

-  CFilterMode(): Id(0), Delta(0) {}

-

-  void SetDelta()

-  {

-    if (Id == k_IA64)

-      Delta = 16;

-    else if (Id == k_ARM || Id == k_PPC || Id == k_SPARC)

-      Delta = 4;

-    else if (Id == k_ARMT)

-      Delta = 2;

-    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;

-  

-  switch (GetUi16(p))

-  {

-    case 0x014C:

-    case 0x8664:  filterId = k_X86; 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 0x0200:  filterId = k_IA64; break;

-    default:  return 0;

-  }

-

-  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;

-  }

-

-  filterMode->Id = filterId;

-  return 1;

-}

-

-

-/* ---------- 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;

-  }

-

-  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;

-    

-    /* Some IA-64 ELF exacutable 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)

-

-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;

-  }

-

-  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;

-    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;

-  

-  unsigned numChannels = GetUi16(buf + 0x16);

-  unsigned bitsPerSample = GetUi16(buf + 0x22);

-

-  if ((bitsPerSample & 0x7) != 0 || bitsPerSample >= 256 || numChannels >= 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)

-    {

-      unsigned delta = numChannels * (bitsPerSample >> 3);

-      if (delta >= 256)

-        return False;

-      filterMode->Id = k_Delta;

-      filterMode->Delta = delta;

-      return True;

-    }

-    if (subChunkSize > (1 << 16))

-      return False;

-    pos += subChunkSize + 8;

-  }

-  return False;

-}

-

-static BoolInt ParseFile(const Byte *buf, size_t size, CFilterMode *filterMode)

-{

-  filterMode->Id = 0;

-  filterMode->Delta = 0;

-

-  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;

-    

-    if (Id < m.Id) return -1;

-    if (Id > m.Id) return 1;

-

-    if (Delta < m.Delta) return -1;

-    if (Delta > m.Delta) return 1;

-

-    return 0;

-  }

-  

-  bool operator ==(const CFilterMode2 &m) const

-  {

-    return Id == m.Id && Delta == m.Delta && Encrypted == m.Encrypted;

-  }

-};

-

-static unsigned GetGroup(CRecordVector<CFilterMode2> &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_BCJ:

-    case k_BCJ2:

-    case k_ARM:

-    case k_ARMT:

-    case k_PPC:

-    case k_SPARC:

-    case k_IA64:

-      return true;

-  }

-  return false;

-}

-

-static unsigned Get_FilterGroup_for_Folder(

-    CRecordVector<CFilterMode2> &filters, const CFolderEx &f, bool extractFilter)

-{

-  CFilterMode2 m;

-  m.Id = 0;

-  m.Delta = 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();

-    }

-  }

-  

-  return GetGroup(filters, m);

-}

-

-

-

-

-static HRESULT WriteRange(IInStream *inStream, ISequentialOutStream *outStream,

-    UInt64 position, UInt64 size, ICompressProgressInfo *progress)

-{

-  RINOK(inStream->Seek(position, STREAM_SEEK_SET, 0));

-  CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;

-  CMyComPtr<CLimitedSequentialInStream> inStreamLimited(streamSpec);

-  streamSpec->SetStream(inStream);

-  streamSpec->Init(size);

-

-  NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder;

-  CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;

-  RINOK(copyCoder->Code(inStreamLimited, outStream, NULL, NULL, progress));

-  return (copyCoderSpec->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) { int __tt = (x); if (__tt != 0) return __tt; }

-

-#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<CUpdateItem> &updateItems = *(const CObjectVector<CUpdateItem> *)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)

-    {

-      int slashPos = ui.Name.ReverseFind_PathSepar();

-      NamePos = slashPos + 1;

-      int dotPos = ui.Name.ReverseFind_Dot();

-      if (dotPos <= slashPos)

-        ExtensionPos = ui.Name.Len();

-      else

-      {

-        ExtensionPos = dotPos + 1;

-        if (ExtensionPos != ui.Name.Len())

-        {

-          AString s;

-          for (unsigned pos = ExtensionPos;; pos++)

-          {

-            wchar_t c = ui.Name[pos];

-            if (c >= 0x80)

-              break;

-            if (c == 0)

-            {

-              ExtensionIndex = GetExtIndex(s);

-              break;

-            }

-            s += (char)MyCharLower_Ascii((char)c);

-          }

-        }

-      }

-    }

-  }

-};

-

-struct CSortParam

-{

-  // const CObjectVector<CTreeFolder> *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;

-  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<UInt32> Indices;

-

-  CRecordVector<CFolderRepack> folderRefs;

-};

-

-static const char * const g_ExeExts[] =

-{

-    "dll"

-  , "exe"

-  , "ocx"

-  , "sfx"

-  , "sys"

-};

-

-static bool IsExeExt(const wchar_t *ext)

-{

-  for (unsigned i = 0; i < ARRAY_SIZE(g_ExeExts); i++)

-    if (StringsAreEqualNoCase_Ascii(ext, g_ExeExts[i]))

-      return true;

-  return false;

-}

-

-struct CAnalysis

-{

-  CMyComPtr<IArchiveUpdateCallbackFile> Callback;

-  CByteBuffer Buffer;

-

-  bool ParseWav;

-  bool ParseExe;

-  bool ParseAll;

-

-  CAnalysis():

-      ParseWav(true),

-      ParseExe(false),

-      ParseAll(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;

-

-  CFilterMode filterModeTemp = filterMode;

-

-  int slashPos = ui.Name.ReverseFind_PathSepar();

-  int dotPos = ui.Name.ReverseFind_Dot();

-

-  // if (dotPos > slashPos)

-  {

-    bool needReadFile = ParseAll;

-

-    bool probablyIsSameIsa = false;

-

-    if (!needReadFile || !Callback)

-    {

-      const wchar_t *ext;

-      if (dotPos > slashPos)

-        ext = ui.Name.Ptr(dotPos + 1);

-      else

-        ext = ui.Name.RightPtr(0);

-      

-      // p7zip uses the trick to store posix attributes in high 16 bits

-      if (ui.Attrib & 0x8000)

-      {

-        unsigned st_mode = ui.Attrib >> 16;

-        // st_mode = 00111;

-        if ((st_mode & 00111) && (ui.Size >= 2048))

-        {

-          #ifndef _WIN32

-          probablyIsSameIsa = true;

-          #endif

-          needReadFile = true;

-        }

-      }

-

-      if (IsExeExt(ext))

-      {

-        needReadFile = true;

-        #ifdef _WIN32

-        probablyIsSameIsa = true;

-        needReadFile = ParseExe;

-        #endif

-      }

-      else if (StringsAreEqualNoCase_Ascii(ext, "wav"))

-      {

-        needReadFile = ParseWav;

-      }

-      /*

-      else if (!needReadFile && ParseUnixExt)

-      {

-        if (StringsAreEqualNoCase_Ascii(ext, "so")

-          || StringsAreEqualNoCase_Ascii(ext, ""))

-          

-          needReadFile = true;

-      }

-      */

-    }

-

-    if (needReadFile && Callback)

-    {

-      if (Buffer.Size() != kAnalysisBufSize)

-      {

-        Buffer.Alloc(kAnalysisBufSize);

-      }

-      {

-        CMyComPtr<ISequentialInStream> stream;

-        HRESULT result = Callback->GetStream2(index, &stream, NUpdateNotifyOp::kAnalyze);

-        if (result == S_OK && stream)

-        {

-          size_t size = kAnalysisBufSize;

-          result = ReadStream(stream, Buffer, &size);

-          stream.Release();

-          // RINOK(Callback->SetOperationResult2(index, NUpdate::NOperationResult::kOK));

-          if (result == S_OK)

-          {

-            BoolInt parseRes = ParseFile(Buffer, size, &filterModeTemp);

-            if (parseRes && filterModeTemp.Delta == 0)

-            {

-              filterModeTemp.SetDelta();

-              if (filterModeTemp.Delta != 0 && filterModeTemp.Id != k_Delta)

-              {

-                if (ui.Size % filterModeTemp.Delta != 0)

-                {

-                  parseRes = false;

-                }

-              }

-            }

-            if (!parseRes)

-            {

-              filterModeTemp.Id = 0;

-              filterModeTemp.Delta = 0;

-            }

-          }

-        }

-      }

-    }

-    else if ((needReadFile && !Callback) || probablyIsSameIsa)

-    {

-      #ifdef MY_CPU_X86_OR_AMD64

-      if (probablyIsSameIsa)

-        filterModeTemp.Id = k_X86;

-      #endif

-    }

-  }

-  

-  filterMode = filterModeTemp;

-  return S_OK;

-}

-

-static inline void GetMethodFull(UInt64 methodID, UInt32 numStreams, CMethodFull &m)

-{

-  m.Id = methodID;

-  m.NumStreams = numStreams;

-}

-

-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 AddFilterBond(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 !

-

-  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");

-

-  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;

-  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, /* bool addFilter, */ bool bcj2Filter)

-{

-  if (mode.Filter_was_Inserted)

-  {

-    const CMethodFull &m = mode.Methods[0];

-    CMethodId id = m.Id;

-    if (id == k_BCJ2)

-      return AddBcj2Methods(mode);

-    if (!m.IsSimpleCoder())

-      return E_NOTIMPL;

-    // if (Bonds.IsEmpty()) we can create bonds later

-    return AddFilterBond(mode);

-  }

-

-  if (filterMode.Id == 0)

-    return S_OK;

-

-  CMethodFull &m = mode.Methods.InsertNew(0);

-

-  {

-    FOR_VECTOR(k, mode.Bonds)

-    {

-      CBond2 &bond = mode.Bonds[k];

-      bond.InCoder++;

-      bond.OutCoder++;

-    }

-  }

-

-  HRESULT res;

-  

-  if (bcj2Filter && Is86Filter(filterMode.Id))

-  {

-    GetMethodFull(k_BCJ2, 4, m);

-    res = AddBcj2Methods(mode);

-  }

-  else

-  {

-    GetMethodFull(filterMode.Id, 1, m);

-    if (filterMode.Id == k_Delta)

-      m.AddProp32(NCoderPropID::kDefaultProp, filterMode.Delta);

-    res = AddFilterBond(mode);

-

-    int alignBits = -1;

-    if (filterMode.Id == k_Delta || filterMode.Delta != 0)

-    {

-           if (filterMode.Delta == 1) alignBits = 0;

-      else if (filterMode.Delta == 2) alignBits = 1;

-      else if (filterMode.Delta == 4) alignBits = 2;

-      else if (filterMode.Delta == 8) alignBits = 3;

-      else if (filterMode.Delta == 16) alignBits = 4;

-    }

-    else

-    {

-      // alignBits = GetAlignForFilterMethod(filterMode.Id);

-    }

-    

-    if (res == S_OK && alignBits >= 0)

-    {

-      unsigned nextCoder = 1;

-      if (!mode.Bonds.IsEmpty())

-      {

-        nextCoder = mode.Bonds.Back().InCoder;

-      }

-      if (nextCoder < mode.Methods.Size())

-      {

-        CMethodFull &nextMethod = mode.Methods[nextCoder];

-        if (nextMethod.Id == k_LZMA || nextMethod.Id == k_LZMA2)

-        {

-          if (!nextMethod.Are_Lzma_Model_Props_Defined())

-          {

-            if (alignBits != 0)

-            {

-              if (alignBits > 2 || filterMode.Id == k_Delta)

-                nextMethod.AddProp32(NCoderPropID::kPosStateBits, alignBits);

-              unsigned lc = 0;

-              if (alignBits < 3)

-                lc = 3 - alignBits;

-              nextMethod.AddProp32(NCoderPropID::kLitContextBits, lc);

-              nextMethod.AddProp32(NCoderPropID::kLitPosBits, alignBits);

-            }

-          }

-        }

-      }

-    }

-  }

-

-  return res;

-}

-

-

-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;

-}

-

-

-

-class CRepackInStreamWithSizes:

-  public ISequentialInStream,

-  public ICompressGetSubStreamSize,

-  public CMyUnknownImp

-{

-  CMyComPtr<ISequentialInStream> _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; }

-

-  MY_UNKNOWN_IMP2(ISequentialInStream, ICompressGetSubStreamSize)

-

-  STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);

-

-  STDMETHOD(GetSubStreamSize)(UInt64 subStream, UInt64 *value);

-};

-

-STDMETHODIMP CRepackInStreamWithSizes::Read(void *data, UInt32 size, UInt32 *processedSize)

-{

-  return _stream->Read(data, size, processedSize);

-  /*

-  UInt32 realProcessedSize;

-  HRESULT result = _stream->Read(data, size, &realProcessedSize);

-  _size += realProcessedSize;

-  if (processedSize)

-    *processedSize = realProcessedSize;

-  return result;

-  */

-}

-

-STDMETHODIMP CRepackInStreamWithSizes::GetSubStreamSize(UInt64 subStream, UInt64 *value)

-{

-  *value = 0;

-  if (subStream >= _extractStatuses->Size())

-    return S_FALSE; // E_FAIL;

-  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<IArchiveUpdateCallbackFile> _opCallback;

-  CMyComPtr<IArchiveExtractCallbackMessage> _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 _7ZIP_ST

-

-class CFolderOutStream2:

-  public CRepackStreamBase,

-  public ISequentialOutStream,

-  public CMyUnknownImp

-{

-public:

-  CMyComPtr<ISequentialOutStream> _stream;

-

-  MY_UNKNOWN_IMP

-

-  STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);

-};

-

-STDMETHODIMP 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:

-  public CRepackStreamBase,

-  public ISequentialInStream,

-  public CMyUnknownImp

-{

-  Byte *_buf;

-public:

-  CMyComPtr<ISequentialInStream> _inStream;

-  HRESULT Result;

-

-  MY_UNKNOWN_IMP

-

-  CFolderInStream2():

-      Result(S_OK)

-  {

-    _buf = new Byte[kTempBufSize];

-  }

-

-  ~CFolderInStream2()

-  {

-    delete []_buf;

-  }

-

-  void Init() { Result = S_OK; }

-  STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);

-};

-

-STDMETHODIMP 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;

-      }

-

-      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

-  #ifndef _7ZIP_ST

-    : public CVirtThread

-  #endif

-{

-public:

-  CDecoder Decoder;

-

-  CThreadDecoder(bool multiThreadMixer):

-      Decoder(multiThreadMixer)

-  {

-    #ifndef _7ZIP_ST

-    if (multiThreadMixer)

-    {

-      MtMode = false;

-      NumThreads = 1;

-      FosSpec = new CFolderOutStream2;

-      Fos = FosSpec;

-      Result = E_FAIL;

-    }

-    #endif

-    // UnpackSize = 0;

-    // send_UnpackSize = false;

-  }

-

-  #ifndef _7ZIP_ST

-  

-  bool dataAfterEnd_Error;

-  HRESULT Result;

-  CMyComPtr<IInStream> InStream;

-

-  CFolderOutStream2 *FosSpec;

-  CMyComPtr<ISequentialOutStream> Fos;

-

-  UInt64 StartPos;

-  const CFolders *Folders;

-  int FolderIndex;

-

-  // bool send_UnpackSize;

-  // UInt64 UnpackSize;

-  

-  #ifndef _NO_CRYPTO

-  CMyComPtr<ICryptoGetTextPassword> getTextPassword;

-  #endif

-

-  DECL_EXTERNAL_CODECS_LOC_VARS2;

-

-  #ifndef _7ZIP_ST

-  bool MtMode;

-  UInt32 NumThreads;

-  #endif

-

-  

-  ~CThreadDecoder() { CVirtThread::WaitThreadFinish(); }

-  virtual void Execute();

-

-  #endif

-};

-

-#ifndef _7ZIP_ST

-

-void CThreadDecoder::Execute()

-{

-  try

-  {

-    #ifndef _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

-

-      _7Z_DECODER_CRYPRO_VARS

-      #ifndef _7ZIP_ST

-        , MtMode, NumThreads,

-        0 // MemUsage

-      #endif

-

-      );

-  }

-  catch(...)

-  {

-    Result = E_FAIL;

-  }

-  

-  /*

-  if (Result == S_OK)

-    Result = FosSpec->CheckFinishedState();

-  */

-  FosSpec->_stream.Release();

-}

-

-#endif

-

-#ifndef _NO_CRYPTO

-

-class CCryptoGetTextPassword:

-  public ICryptoGetTextPassword,

-  public CMyUnknownImp

-{

-public:

-  UString Password;

-

-  MY_UNKNOWN_IMP

-  STDMETHOD(CryptoGetTextPassword)(BSTR *password);

-};

-

-STDMETHODIMP 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,

-    const CObjectVector<CUpdateItem> &updateItems,

-    // const CObjectVector<CTreeFolder> &treeFolders,

-    // const CUniqBlocks &secureBlocks,

-    COutArchive &archive,

-    CArchiveDatabaseOut &newDatabase,

-    ISequentialOutStream *seqOutStream,

-    IArchiveUpdateCallback *updateCallback,

-    const CUpdateOptions &options

-    #ifndef _NO_CRYPTO

-    , ICryptoGetTextPassword *getDecoderPassword

-    #endif

-    )

-{

-  UInt64 numSolidFiles = options.NumSolidFiles;

-  if (numSolidFiles == 0)

-    numSolidFiles = 1;

-

-  CMyComPtr<IArchiveUpdateCallbackFile> opCallback;

-  updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback);

-

-  CMyComPtr<IArchiveExtractCallbackMessage> extractCallback;

-  updateCallback->QueryInterface(IID_IArchiveExtractCallbackMessage, (void **)&extractCallback);

-

-  // size_t totalSecureDataSize = (size_t)secureBlocks.GetTotalSizeInBytes();

-

-  /*

-  CMyComPtr<IOutStream> outStream;

-  RINOK(seqOutStream->QueryInterface(IID_IOutStream, (void **)&outStream));

-  if (!outStream)

-    return E_NOTIMPL;

-  */

-

-  UInt64 startBlockSize = db ? db->ArcInfo.StartPosition: 0;

-  if (startBlockSize > 0 && !options.RemoveSfxBlock)

-  {

-    RINOK(WriteRange(inStream, seqOutStream, 0, startBlockSize, NULL));

-  }

-

-  CIntArr fileIndexToUpdateIndexMap;

-  UInt64 complexity = 0;

-  UInt64 inSizeForReduce2 = 0;

-  bool needEncryptedRepack = false;

-

-  CRecordVector<CFilterMode2> filters;

-  CObjectVector<CSolidGroup> groups;

-  bool thereAreRepacks = false;

-

-  bool useFilters = options.UseFilters;

-  if (useFilters)

-  {

-    const CCompressionMethodMode &method = *options.Method;

-

-    FOR_VECTOR (i, method.Methods)

-      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] = i;

-    }

-

-    for (i = 0; i < db->NumFolders; i++)

-    {

-      CNum indexInFolder = 0;

-      CNum numCopyItems = 0;

-      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++;

-          int updateIndex = fileIndexToUpdateIndexMap[fi];

-          if (updateIndex >= 0 && !updateItems[updateIndex].NewData)

-          {

-            numCopyItems++;

-            repackSize += file.Size;

-          }

-        }

-      }

-

-      if (numCopyItems == 0)

-        continue;

-

-      CFolderRepack rep;

-      rep.FolderIndex = i;

-      rep.NumCopyFiles = numCopyItems;

-      CFolderEx f;

-      db->ParseFolderEx(i, f);

-

-      const bool isEncrypted = f.IsEncrypted();

-      const bool needCopy = (numCopyItems == numUnpackStreams);

-      const bool extractFilter = (useFilters || needCopy);

-

-      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

-      {

-        thereAreRepacks = true;

-        complexity += repackSize;

-        if (inSizeForReduce2 < repackSize)

-          inSizeForReduce2 = repackSize;

-        if (isEncrypted)

-          needEncryptedRepack = true;

-      }

-    }

-  }

-

-  UInt64 inSizeForReduce = 0;

-  {

-    bool isSolid = (numSolidFiles > 1 && options.NumSolidBytes != 0);

-    FOR_VECTOR (i, updateItems)

-    {

-      const CUpdateItem &ui = updateItems[i];

-      if (ui.NewData)

-      {

-        complexity += ui.Size;

-        if (isSolid)

-          inSizeForReduce += ui.Size;

-        else if (inSizeForReduce < ui.Size)

-          inSizeForReduce = ui.Size;

-      }

-    }

-  }

-

-  if (inSizeForReduce < inSizeForReduce2)

-    inSizeForReduce = inSizeForReduce2;

-

-  RINOK(updateCallback->SetTotal(complexity));

-

-  CLocalProgress *lps = new CLocalProgress;

-  CMyComPtr<ICompressProgressInfo> progress = lps;

-  lps->Init(updateCallback, true);

-

-  #ifndef _7ZIP_ST

-  

-  CStreamBinder sb;

-  if (options.MultiThreadMixer)

-  {

-    RINOK(sb.CreateEvents());

-  }

-  

-  #endif

-

-  CThreadDecoder threadDecoder(options.MultiThreadMixer);

-  

-  #ifndef _7ZIP_ST

-  if (options.MultiThreadMixer && thereAreRepacks)

-  {

-    #ifdef EXTERNAL_CODECS

-    threadDecoder.__externalCodecs = __externalCodecs;

-    #endif

-    RINOK(threadDecoder.Create());

-  }

-  #endif

-

-  {

-    CAnalysis analysis;

-    if (options.AnalysisLevel == 0)

-    {

-      analysis.ParseWav = false;

-      analysis.ParseExe = false;

-      analysis.ParseAll = false;

-    }

-    else

-    {

-      analysis.Callback = opCallback;

-      if (options.AnalysisLevel > 0)

-      {

-        analysis.ParseWav = true;

-        if (options.AnalysisLevel >= 7)

-        {

-          analysis.ParseExe = true;

-          if (options.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)

-      {

-        RINOK(analysis.GetFilterGroup(i, ui, fm));

-      }

-      fm.Encrypted = method.PasswordIsDefined;

-

-      unsigned groupIndex = GetGroup(filters, fm);

-      while (groupIndex >= groups.Size())

-        groups.AddNew();

-      groups[groupIndex].Indices.Add(i);

-    }

-  }

-

-

-  #ifndef _NO_CRYPTO

-

-  CCryptoGetTextPassword *getPasswordSpec = NULL;

-  CMyComPtr<ICryptoGetTextPassword> getTextPassword;

-  if (needEncryptedRepack)

-  {

-    getPasswordSpec = new CCryptoGetTextPassword;

-    getTextPassword = getPasswordSpec;

-    

-    #ifndef _7ZIP_ST

-    threadDecoder.getTextPassword = getPasswordSpec;

-    #endif

-

-    if (options.Method->PasswordIsDefined)

-      getPasswordSpec->Password = options.Method->Password;

-    else

-    {

-      if (!getDecoderPassword)

-        return E_NOTIMPL;

-      CMyComBSTR password;

-      RINOK(getDecoderPassword->CryptoGetTextPassword(&password));

-      if (password)

-        getPasswordSpec->Password = password;

-    }

-  }

-

-  #endif

-

-  

-  // ---------- Compress ----------

-

-  RINOK(archive.Create(seqOutStream, false));

-  RINOK(archive.SkipPrefixArchiveHeader());

-

-  /*

-  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[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, ui.IndexInArchive, file, file2);

-        db->GetPath(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;

-    {

-      HRESULT res = MakeExeMethod(method, filterMode,

-        #ifdef _7ZIP_ST

-          false

-        #else

-          options.MaxFilter && options.MultiThreadMixer

-        #endif

-        );

-

-      RINOK(res);

-    }

-

-    if (filterMode.Encrypted)

-    {

-      if (!method.PasswordIsDefined)

-      {

-        #ifndef _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];

-

-      unsigned folderIndex = rep.FolderIndex;

-      

-      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));

-              }

-            }

-          }

-        }

-

-        UInt64 packSize = db->GetFolderFullPackSize(folderIndex);

-        RINOK(WriteRange(inStream, archive.SeqStream,

-            db->GetFolderStreamPos(folderIndex, 0), packSize, progress));

-        lps->ProgressOffset += packSize;

-        

-        CFolder &folder = newDatabase.Folders.AddNew();

-        db->ParseFolderInfo(folderIndex, folder);

-        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];

-        size_t indexEnd = db->FoToCoderUnpackSizes[folderIndex + 1];

-        for (; indexStart < indexEnd; indexStart++)

-          newDatabase.CoderUnpackSizes.Add(db->CoderUnpackSizes[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++;

-            int updateIndex = fileIndexToUpdateIndexMap[fi];

-            if (updateIndex >= 0 && !updateItems[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<ISequentialInStream> sbInStream;

-          CRepackStreamBase *repackBase;

-          CFolderInStream2 *FosSpec2 = NULL;

-

-          CRepackInStreamWithSizes *inStreamSizeCountSpec = new CRepackInStreamWithSizes;

-          CMyComPtr<ISequentialInStream> inStreamSizeCount = inStreamSizeCountSpec;

-          {

-            #ifndef _7ZIP_ST

-            if (options.MultiThreadMixer)

-            {

-              repackBase = threadDecoder.FosSpec;

-              CMyComPtr<ISequentialOutStream> sbOutStream;

-              sb.CreateStreams(&sbInStream, &sbOutStream);

-              sb.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 _NO_CRYPTO

-              bool isEncrypted = false;

-              bool passwordIsDefined = false;

-              UString password;

-              #endif

-              

-              CMyComPtr<ISequentialInStream> decodedStream;

-              bool dataAfterEnd_Error = false;

-

-              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

-                

-                  _7Z_DECODER_CRYPRO_VARS

-                  #ifndef _7ZIP_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 _7ZIP_ST

-            if (options.MultiThreadMixer)

-            {

-              threadDecoder.Start();

-            }

-            #endif

-          }

-

-          curUnpackSize = sizeToEncode;

-

-          HRESULT encodeRes = encoder.Encode(

-              EXTERNAL_CODECS_LOC_VARS

-              inStreamSizeCount,

-              // NULL,

-              &inSizeForReduce,

-              newDatabase.Folders.AddNew(), newDatabase.CoderUnpackSizes, curUnpackSize,

-              archive.SeqStream, newDatabase.PackSizes, progress);

-

-          if (encodeRes == k_My_HRESULT_CRC_ERROR)

-            return E_FAIL;

-

-          #ifndef _7ZIP_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();

-            

-            threadDecoder.WaitExecuteFinish();

-            

-            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++;

-          int updateIndex = fileIndexToUpdateIndexMap[fi];

-          if (updateIndex >= 0)

-          {

-            const CUpdateItem &ui = updateItems[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 ----------

-

-    unsigned numFiles = group.Indices.Size();

-    if (numFiles == 0)

-      continue;

-    CRecordVector<CRefItem> refItems;

-    refItems.ClearAndSetSize(numFiles);

-    // bool sortByType = (options.UseTypeSorting && isSoid); // numSolidFiles > 1

-    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<UInt32> indices(numFiles);

-

-    for (i = 0; i < numFiles; i++)

-    {

-      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)

-        {

-          int slashPos = ui.Name.ReverseFind_PathSepar();

-          int dotPos = ui.Name.ReverseFind_Dot();

-          const wchar_t *ext = ui.Name.Ptr(dotPos <= slashPos ? ui.Name.Len() : dotPos + 1);

-          if (numSubFiles == 0)

-            prevExtension = ext;

-          else if (!StringsAreEqualNoCase(ext, prevExtension))

-            break;

-        }

-      }

-

-      if (numSubFiles < 1)

-        numSubFiles = 1;

-

-      RINOK(lps->SetCur());

-

-      CFolderInStream *inStreamSpec = new CFolderInStream;

-      CMyComPtr<ISequentialInStream> solidInStream(inStreamSpec);

-      inStreamSpec->Init(updateCallback, &indices[i], numSubFiles);

-      

-      unsigned startPackIndex = newDatabase.PackSizes.Size();

-      UInt64 curFolderUnpackSize = totalSize;

-      // curFolderUnpackSize = (UInt64)(Int64)-1;

-      

-      RINOK(encoder.Encode(

-          EXTERNAL_CODECS_LOC_VARS

-          solidInStream,

-          // NULL,

-          &inSizeForReduce,

-          newDatabase.Folders.AddNew(), newDatabase.CoderUnpackSizes, curFolderUnpackSize,

-          archive.SeqStream, newDatabase.PackSizes, progress));

-

-      if (!inStreamSpec->WasFinished())

-        return E_FAIL;

-

-      for (; startPackIndex < newDatabase.PackSizes.Size(); startPackIndex++)

-        lps->OutSize += newDatabase.PackSizes[startPackIndex];

-

-      lps->InSize += curFolderUnpackSize;

-      // for ()

-      // newDatabase.PackCRCsDefined.Add(false);

-      // newDatabase.PackCRCs.Add(0);

-

-      CNum numUnpackStreams = 0;

-      UInt64 skippedSize = 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, ui.IndexInArchive, file, file2);

-          db->GetPath(ui.IndexInArchive, name);

-        }

-        if (file2.IsAnti || file.IsDir)

-          return E_FAIL;

-        

-        /*

-        CFileItem &file = newDatabase.Files[

-              startFileIndexInDatabase + i + subIndex];

-        */

-        if (!inStreamSpec->Processed[subIndex])

-        {

-          skippedSize += ui.Size;

-          continue;

-          // file.Name += ".locked";

-        }

-

-        file.Crc = inStreamSpec->CRCs[subIndex];

-        file.Size = inStreamSpec->Sizes[subIndex];

-        

-        // if (file.Size >= 0) // test purposes

-        if (file.Size != 0)

-        {

-          file.CrcDefined = true;

-          file.HasStream = true;

-          numUnpackStreams++;

-        }

-        else

-        {

-          file.CrcDefined = false;

-          file.HasStream = false;

-        }

-

-        /*

-        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);

-      }

-

-      // 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));

-      }

-    }

-  }

-

-  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;

-    }

-  }

-  */

-  newDatabase.ReserveDown();

-

-  if (opCallback)

-    RINOK(opCallback->ReportOperation(NEventIndexType::kNoIndex, (UInt32)(Int32)-1, NUpdateNotifyOp::kHeader));

-

-  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
+  // 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)
+      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;
+  
+  switch (GetUi16(p))
+  {
+    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 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;
+
+  p += optHeaderSize;
+  // UInt32 numExeSections = 0;
+  // bool execute_finded = false;
+  // UInt32 sect_va = 0;
+  // UInt32 sect_size = 0;
+  // UInt32 sect_offset = 0;
+
+  for (UInt32 i = 0; i < numSections
+        // && numExeSections < numSectionsMax
+        ; i++, p += PE_SectHeaderSize)
+  {
+    UInt32 characts, rawSize, offset;
+    if ((UInt32)(p - buf) + PE_SectHeaderSize > size)
+      return 0;
+    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;
+}
+
+
+/* ---------- 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;
+  }
+
+  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;
+
+    /* 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;
+  }
+
+  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<CFilterMode2> &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_BCJ:
+    case k_BCJ2:
+    case k_ARM:
+    case k_ARMT:
+    case k_PPC:
+    case k_SPARC:
+    case k_IA64:
+      return true;
+  }
+  return false;
+}
+
+static unsigned Get_FilterGroup_for_Folder(
+    CRecordVector<CFilterMode2> &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)
+        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))
+  CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+  CMyComPtr<ISequentialInStream> inStreamLimited(streamSpec);
+  streamSpec->SetStream(inStream);
+  streamSpec->Init(size);
+
+  NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder;
+  CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+  RINOK(copyCoder->Code(inStreamLimited, outStream, NULL, NULL, progress))
+  return (copyCoderSpec->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<CUpdateItem> &updateItems = *(const CObjectVector<CUpdateItem> *)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)
+    {
+      int slashPos = ui.Name.ReverseFind_PathSepar();
+      NamePos = (unsigned)(slashPos + 1);
+      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++)
+          {
+            wchar_t c = ui.Name[pos];
+            if (c >= 0x80)
+              break;
+            if (c == 0)
+            {
+              ExtensionIndex = GetExtIndex(s);
+              break;
+            }
+            s += (char)MyCharLower_Ascii((char)c);
+          }
+        }
+      }
+    }
+  }
+};
+
+struct CSortParam
+{
+  // const CObjectVector<CTreeFolder> *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<UInt32> Indices;
+
+  CRecordVector<CFolderRepack> 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<IArchiveUpdateCallbackFile> 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<ISequentialInStream> 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<IStreamGetProps> 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
+        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;
+}
+
+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 AddFilterBond(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 !
+
+  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");
+
+  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;
+  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, /* bool addFilter, */ bool bcj2Filter)
+{
+  if (mode.Filter_was_Inserted)
+  {
+    const CMethodFull &m = mode.Methods[0];
+    const CMethodId id = m.Id;
+    if (id == k_BCJ2)
+      return AddBcj2Methods(mode);
+    if (!m.IsSimpleCoder())
+      return E_NOTIMPL;
+    // if (Bonds.IsEmpty()) we can create bonds later
+    return AddFilterBond(mode);
+  }
+
+  if (filterMode.Id == 0)
+    return S_OK;
+
+  CMethodFull &m = mode.Methods.InsertNew(0);
+
+  {
+    FOR_VECTOR (k, mode.Bonds)
+    {
+      CBond2 &bond = mode.Bonds[k];
+      bond.InCoder++;
+      bond.OutCoder++;
+    }
+  }
+
+  HRESULT res;
+  
+  if (bcj2Filter && Is86Filter(filterMode.Id))
+  {
+    GetMethodFull(k_BCJ2, 4, m);
+    res = AddBcj2Methods(mode);
+  }
+  else
+  {
+    GetMethodFull(filterMode.Id, 1, m);
+    if (filterMode.Id == k_Delta)
+      m.AddProp32(NCoderPropID::kDefaultProp, filterMode.Delta);
+    else if (filterMode.Id == k_ARM64)
+    {
+      // if (filterMode.Offset != 0)
+        m.AddProp32(
+          NCoderPropID::kDefaultProp,
+          // NCoderPropID::kBranchOffset,
+          filterMode.Offset);
+    }
+    res = AddFilterBond(mode);
+
+    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 (res == S_OK && alignBits > 0)
+    {
+      unsigned nextCoder = 1;
+      if (!mode.Bonds.IsEmpty())
+      {
+        nextCoder = mode.Bonds.Back().InCoder;
+      }
+      if (nextCoder < mode.Methods.Size())
+      {
+        CMethodFull &nextMethod = mode.Methods[nextCoder];
+        if (nextMethod.Id == k_LZMA || nextMethod.Id == k_LZMA2)
+        {
+          if (!nextMethod.Are_Lzma_Model_Props_Defined())
+          {
+            if (alignBits != 0)
+            {
+              if (alignBits > 2 || filterMode.Id == k_Delta)
+                nextMethod.AddProp32(NCoderPropID::kPosStateBits, (unsigned)alignBits);
+              unsigned lc = 0;
+              if (alignBits < 3)
+                lc = (unsigned)(3 - alignBits);
+              nextMethod.AddProp32(NCoderPropID::kLitContextBits, lc);
+              nextMethod.AddProp32(NCoderPropID::kLitPosBits, (unsigned)alignBits);
+            }
+          }
+        }
+      }
+    }
+  }
+
+  return res;
+}
+
+
+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<ISequentialInStream> _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<IArchiveUpdateCallbackFile> _opCallback;
+  CMyComPtr<IArchiveExtractCallbackMessage2> _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<ISequentialOutStream> _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<ISequentialInStream> _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<IInStream> InStream;
+
+  CFolderOutStream2 *FosSpec;
+  CMyComPtr<ISequentialOutStream> Fos;
+
+  UInt64 StartPos;
+  const CFolders *Folders;
+  unsigned FolderIndex;
+
+  // bool send_UnpackSize;
+  // UInt64 UnpackSize;
+  
+  #ifndef Z7_NO_CRYPTO
+  CMyComPtr<ICryptoGetTextPassword> 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<CUpdateItem> &updateItems,
+    // const CObjectVector<CTreeFolder> &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<IStreamSetRestriction> 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;
+  UInt64 inSizeForReduce2 = 0;
+
+ #ifndef Z7_NO_CRYPTO
+  bool needEncryptedRepack = false;
+ #endif
+
+  CRecordVector<CFilterMode2> filters;
+  CObjectVector<CSolidGroup> 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;
+  {
+    bool isSolid = (numSolidFiles > 1 && options.NumSolidBytes != 0);
+    FOR_VECTOR (i, updateItems)
+    {
+      const CUpdateItem &ui = updateItems[i];
+      if (ui.NewData)
+      {
+        complexity += ui.Size;
+        if (isSolid)
+          inSizeForReduce += ui.Size;
+        else if (inSizeForReduce < ui.Size)
+          inSizeForReduce = ui.Size;
+      }
+    }
+  }
+
+  if (inSizeForReduce < inSizeForReduce2)
+    inSizeForReduce = inSizeForReduce2;
+
+  RINOK(updateCallback->SetTotal(complexity))
+
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> progress = 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<ICryptoGetTextPassword> 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,
+        #ifdef Z7_ST
+          false
+        #else
+          options.MaxFilter && options.MultiThreadMixer
+        #endif
+        );
+
+      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, progress))
+        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[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<ISequentialInStream> sbInStream;
+          CRepackStreamBase *repackBase;
+          CFolderInStream2 *FosSpec2 = NULL;
+
+          CRepackInStreamWithSizes *inStreamSizeCountSpec = new CRepackInStreamWithSizes;
+          CMyComPtr<ISequentialInStream> inStreamSizeCount = inStreamSizeCountSpec;
+          {
+            #ifndef Z7_ST
+            if (options.MultiThreadMixer)
+            {
+              repackBase = threadDecoder.FosSpec;
+              CMyComPtr<ISequentialOutStream> 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<ISequentialInStream> 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, progress);
+
+          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<CRefItem> 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<UInt32> 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));
+      }
+      */
+
+
+      CFolderInStream *inStreamSpec = new CFolderInStream;
+      CMyComPtr<ISequentialInStream> solidInStream(inStreamSpec);
+
+      // 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
+          solidInStream,
+          // NULL,
+          &inSizeForReduce,
+          expectedDataSize, // expected size
+          newDatabase.Folders.AddNew(),
+          // newDatabase.CoderUnpackSizes, curFolderUnpackSize,
+          archive.SeqStream, newDatabase.PackSizes, progress))
+
+      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_FillResedue_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 06a0b05..de4117a 100644
--- a/CPP/7zip/Archive/7z/7zUpdate.h
+++ b/CPP/7zip/Archive/7z/7zUpdate.h
@@ -1,139 +1,146 @@
-// 7zUpdate.h

-

-#ifndef __7Z_UPDATE_H

-#define __7Z_UPDATE_H

-

-#include "../IArchive.h"

-

-// #include "../../Common/UniqBlocks.h"

-

-#include "7zCompressionMode.h"

-#include "7zIn.h"

-#include "7zOut.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;

-  int 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;

-

-  // 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)

-      // 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;

-

-  CHeaderOptions HeaderOptions;

-

-  UInt64 NumSolidFiles;

-  UInt64 NumSolidBytes;

-  bool SolidExtension;

-  

-  bool UseTypeSorting;

-  

-  bool RemoveSfxBlock;

-  bool MultiThreadMixer;

-

-  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)

-    {}

-};

-

-HRESULT Update(

-    DECL_EXTERNAL_CODECS_LOC_VARS

-    IInStream *inStream,

-    const CDbEx *db,

-    const CObjectVector<CUpdateItem> &updateItems,

-    // const CObjectVector<CTreeFolder> &treeFolders, // treeFolders[0] is root

-    // const CUniqBlocks &secureBlocks,

-    COutArchive &archive,

-    CArchiveDatabaseOut &newDatabase,

-    ISequentialOutStream *seqOutStream,

-    IArchiveUpdateCallback *updateCallback,

-    const CUpdateOptions &options

-    #ifndef _NO_CRYPTO

-    , ICryptoGetTextPassword *getDecoderPassword

-    #endif

-    );

-}}

-

-#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;
+
+  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)
+    {}
+};
+
+HRESULT Update(
+    DECL_EXTERNAL_CODECS_LOC_VARS
+    IInStream *inStream,
+    const CDbEx *db,
+    CObjectVector<CUpdateItem> &updateItems,
+    // const CObjectVector<CTreeFolder> &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 c6d3b1f..d0feea8 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 59d9ac1..035267c 100644
--- a/CPP/7zip/Archive/7z/StdAfx.h
+++ b/CPP/7zip/Archive/7z/StdAfx.h
@@ -1,8 +1,11 @@
-// StdAfx.h

-

-#ifndef __STDAFX_H

-#define __STDAFX_H

-

-#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
new file mode 100644
index 0000000..ff60e4d
--- /dev/null
+++ b/CPP/7zip/Archive/7z/makefile
@@ -0,0 +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"
diff --git a/CPP/7zip/Archive/7z/resource.rc b/CPP/7zip/Archive/7z/resource.rc
new file mode 100644
index 0000000..f79dac0
--- /dev/null
+++ b/CPP/7zip/Archive/7z/resource.rc
@@ -0,0 +1,11 @@
+#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
new file mode 100644
index 0000000..5fb7e0a
--- /dev/null
+++ b/CPP/7zip/Archive/ApfsHandler.cpp
@@ -0,0 +1,4482 @@
+// ApfsHandler.cpp
+
+#include "StdAfx.h"
+
+// #define SHOW_DEBUG_INFO
+
+#ifdef SHOW_DEBUG_INFO
+#include <stdio.h>
+#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 {
+
+#define ValToHex(t) ((char)(((t) < 10) ? ('0' + (t)) : ('a' + ((t) - 10))))
+
+static void ConvertByteToHex(unsigned val, char *s)
+{
+  unsigned t;
+  t = val >> 4;
+  s[0] = ValToHex(t);
+  t = val & 0xF;
+  s[1] = ValToHex(t);
+}
+
+struct CUuid
+{
+  Byte Data[16];
+
+  void SetHex_To_str(char *s) const
+  {
+    for (unsigned i = 0; i < 16; i++)
+      ConvertByteToHex(Data[i], s + i * 2);
+    s[32] = 0;
+  }
+
+  void AddHexToString(UString &dest) const
+  {
+    char temp[32 + 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<CExtent> Extents;
+  CObjectVector<CAttr> 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<CExtent> 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<CHashChunk> CStreamHashes;
+
+
+Z7_CLASS_IMP_NOQIB_1(
+  COutStreamWithHash
+  , ISequentialOutStream
+)
+  bool _hashError;
+  CAlignedBuffer1 _sha;
+  CMyComPtr<ISequentialOutStream> _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<CNode> Nodes;
+  CRecordVector<UInt64> NodeIDs;
+  CObjectVector<CItem> Items;
+  CRecordVector<CRef> Refs;
+
+  CObjectVector<CSmallNode> SmallNodes;
+  CRecordVector<UInt64> SmallNodeIDs;
+
+  CObjectVector<CSmallNode> FEXT_Nodes;
+  CRecordVector<UInt64> FEXT_NodeIDs;
+
+  CObjectVector<CStreamHashes> Hash_Vectors;
+  CRecordVector<UInt64> 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<UInt64> Keys;
+  CRecordVector<omap_val> Vals;
+
+  bool Parse(const CObjectVector<CKeyValPair> &pairs);
+  int FindKey(UInt64 id) const { return Keys.FindInSorted(id); }
+};
+
+bool CObjectMap::Parse(const CObjectVector<CKeyValPair> &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<CKeyValPair> 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<CRef2> Refs2;
+  CObjectVector<CVol> 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<CByteBuffer> 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<CExtent> *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 UInt32 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<CExtent> &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<ISequentialInStream> 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<IInStream> _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 += ':';
+      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;
+  
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> progress = lps;
+  lps->Init(extractCallback, false);
+
+  NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+  CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+  NHfs::CDecoder decoder;
+
+  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);
+
+    CMyComPtr<ISequentialOutStream> 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))
+    int 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<ISequentialInStream> 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<ISequentialInStream> inStream;
+        if (GetStream(index, &inStream) == S_OK && inStream)
+        {
+          COutStreamWithHash *hashStreamSpec = NULL;
+          CMyComPtr<ISequentialOutStream> hashStream;
+          
+          if (vol.integrity.Is_SHA256())
+          {
+            const int hashIndex = FindHashIndex_for_Item(index);
+            if (hashIndex != -1)
+            {
+              hashStreamSpec = new COutStreamWithHash;
+              hashStream = hashStreamSpec;
+              hashStreamSpec->SetStream(realOutStream);
+              hashStreamSpec->Init(&(vol.Hash_Vectors[(unsigned)hashIndex]), sb.block_size_Log);
+            }
+          }
+          
+          RINOK(copyCoder->Code(inStream,
+              hashStream ? hashStream : realOutStream, NULL, NULL, progress))
+          opRes = NExtract::NOperationResult::kDataError;
+          if (copyCoderSpec->TotalSize == currentItemSize)
+          {
+            opRes = NExtract::NOperationResult::kOK;
+            if (hashStream)
+              if (!hashStreamSpec->FinalCheck())
+                opRes = NExtract::NOperationResult::kCRCError;
+          }
+          else if (copyCoderSpec->TotalSize < currentItemSize)
+            opRes = NExtract::NOperationResult::kUnexpectedEnd;
+        }
+      }
+    }
+    
+    realOutStream.Release();
+    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<CExtent> *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)
+    {
+      CBufInStream *streamSpec = new CBufInStream;
+      CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
+      streamSpec->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)
+  {
+    CBufInStream *streamSpec = new CBufInStream;
+    CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
+    streamSpec->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<CExtent> *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<CExtent> *extents, UInt64 rem,
+    ISequentialInStream **stream)
+{
+  CExtentsStream *extentStreamSpec = new CExtentsStream();
+  CMyComPtr<ISequentialInStream> extentStream = extentStreamSpec;
+
+  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;
+    extentStreamSpec->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;
+  extentStreamSpec->Extents.Add(se);
+  extentStreamSpec->Stream = apfsInStream;
+  extentStreamSpec->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
new file mode 100644
index 0000000..6770301
--- /dev/null
+++ b/CPP/7zip/Archive/ApmHandler.cpp
@@ -0,0 +1,314 @@
+// ApmHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "../../Common/ComTry.h"
+#include "../../Common/Defs.h"
+
+#include "../../Windows/PropVariant.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 NApm {
+
+static const Byte kSig0 = 'E';
+static const Byte kSig1 = 'R';
+
+struct CItem
+{
+  UInt32 StartBlock;
+  UInt32 NumBlocks;
+  char Name[32];
+  char Type[32];
+  /*
+  UInt32 DataStartBlock;
+  UInt32 NumDataBlocks;
+  UInt32 Status;
+  UInt32 BootStartBlock;
+  UInt32 BootSize;
+  UInt32 BootAddr;
+  UInt32 BootEntry;
+  UInt32 BootChecksum;
+  char Processor[16];
+  */
+
+  bool Parse(const Byte *p, UInt32 &numBlocksInMap)
+  {
+    numBlocksInMap = Get32(p + 4);
+    StartBlock = Get32(p + 8);
+    NumBlocks = Get32(p + 0xC);
+    memcpy(Name, p + 0x10, 32);
+    memcpy(Type, p + 0x30, 32);
+    if (p[0] != 0x50 || p[1] != 0x4D || p[2] != 0 || p[3] != 0)
+      return false;
+    /*
+    DataStartBlock = Get32(p + 0x50);
+    NumDataBlocks = Get32(p + 0x54);
+    Status = Get32(p + 0x58);
+    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<CItem> _items;
+  unsigned _blockSizeLog;
+  UInt32 _numBlocks;
+  UInt64 _phySize;
+  bool _isArc;
+
+  HRESULT ReadTables(IInStream *stream);
+  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;
+
+API_FUNC_static_IsArc IsArc_Apm(const Byte *p, size_t size)
+{
+  if (size < kSectorSize)
+    return k_IsArc_Res_NEED_MORE;
+  if (p[0] != kSig0 || p[1] != kSig1)
+    return k_IsArc_Res_NO;
+  unsigned i;
+  for (i = 8; i < 16; i++)
+    if (p[i] != 0)
+      return k_IsArc_Res_NO;
+  UInt32 blockSize = Get16(p + 2);
+  for (i = 9; ((UInt32)1 << i) != blockSize; i++)
+    if (i >= 12)
+      return k_IsArc_Res_NO;
+  return k_IsArc_Res_YES;
+}
+}
+
+HRESULT CHandler::ReadTables(IInStream *stream)
+{
+  Byte buf[kSectorSize];
+  {
+    RINOK(ReadStream_FALSE(stream, buf, kSectorSize))
+    if (buf[0] != kSig0 || buf[1] != kSig1)
+      return S_FALSE;
+    UInt32 blockSize = Get16(buf + 2);
+    unsigned i;
+    for (i = 9; ((UInt32)1 << i) != blockSize; i++)
+      if (i >= 12)
+        return S_FALSE;
+    _blockSizeLog = i;
+    _numBlocks = Get32(buf + 4);
+    for (i = 8; i < 16; i++)
+      if (buf[i] != 0)
+        return S_FALSE;
+  }
+
+  unsigned numSkips = (unsigned)1 << (_blockSizeLog - 9);
+  for (unsigned j = 1; j < numSkips; j++)
+  {
+    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))
+        return S_FALSE;
+    }
+    else if (numBlocksInMap2 != numBlocksInMap)
+      return S_FALSE;
+
+    UInt32 finish = item.StartBlock + item.NumBlocks;
+    if (finish < item.StartBlock)
+      return S_FALSE;
+    _numBlocks = MyMax(_numBlocks, finish);
+    
+    _items.Add(item);
+    for (unsigned j = 1; j < numSkips; j++)
+    {
+      RINOK(ReadStream_FALSE(stream, buf, kSectorSize))
+    }
+    if (++i == numBlocksInMap)
+      break;
+  }
+  
+  _phySize = BlocksToBytes(_numBlocks);
+  _isArc = true;
+  return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback * /* callback */))
+{
+  COM_TRY_BEGIN
+  Close();
+  RINOK(ReadTables(stream))
+  _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
+};
+
+static const Byte kArcProps[] =
+{
+  kpidClusterSize
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+static AString GetString(const char *s)
+{
+  AString res;
+  for (unsigned i = 0; i < 32 && s[i] != 0; i++)
+    res += s[i];
+  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)
+      {
+        AString s (GetString(_items[i].Type));
+        if (s != "Apple_Free" &&
+            s != "Apple_partition_map")
+        {
+          if (mainIndex >= 0)
+          {
+            mainIndex = -1;
+            break;
+          }
+          mainIndex = (int)i;
+        }
+      }
+      if (mainIndex >= 0)
+        prop = (UInt32)(Int32)mainIndex;
+      break;
+    }
+    case kpidClusterSize: prop = (UInt32)1 << _blockSizeLog; break;
+    case kpidPhySize: prop = _phySize; 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));
+      if (type == "Apple_HFS")
+        type = "hfs";
+      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;
+  }
+  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
new file mode 100644
index 0000000..07ecec6
--- /dev/null
+++ b/CPP/7zip/Archive/ArHandler.cpp
@@ -0,0 +1,843 @@
+// 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<IInStream> 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
+)
+  CObjectVector<CItem> _items;
+  CMyComPtr<IInStream> _stream;
+  Int32 _mainSubfile;
+  UInt64 _phySize;
+
+  EType _type;
+  ESubType _subType;
+  int _longNames_FileIndex;
+  AString _libFiles[2];
+  unsigned _numLibFiles;
+  AString _errorMessage;
+  bool _isArc;
+
+  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 += '\n';
+  _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 += (char)0xD;
+  s += (char)0xA;
+  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 + 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)
+      {
+        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;
+  
+  NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+  CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> progress = lps;
+  lps->Init(extractCallback, false);
+
+  CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+  CMyComPtr<ISequentialInStream> inStream(streamSpec);
+  streamSpec->SetStream(_stream);
+
+  for (i = 0; i < numItems; i++)
+  {
+    lps->InSize = lps->OutSize = currentTotalSize;
+    RINOK(lps->SetCur())
+    CMyComPtr<ISequentialOutStream> 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;
+    }
+    bool isOk = true;
+    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()))
+      streamSpec->Init(item.Size);
+      RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress))
+      isOk = (copyCoderSpec->TotalSize == item.Size);
+    }
+    realOutStream.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
+  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 a3fe6dd..2ed6246 100644
--- a/CPP/7zip/Archive/Archive.def
+++ b/CPP/7zip/Archive/Archive.def
@@ -1,12 +1,14 @@
-EXPORTS

-  CreateObject PRIVATE

-

-  GetHandlerProperty PRIVATE

-  GetNumberOfFormats PRIVATE

-  GetHandlerProperty2 PRIVATE

-  GetIsArc PRIVATE

-

-  SetCodecs PRIVATE

-

-  SetLargePageMode PRIVATE

-  SetCaseSensitive 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 de744b5..f891ad3 100644
--- a/CPP/7zip/Archive/Archive2.def
+++ b/CPP/7zip/Archive/Archive2.def
@@ -1,19 +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

+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 94f2fff..4735fcf 100644
--- a/CPP/7zip/Archive/ArchiveExports.cpp
+++ b/CPP/7zip/Archive/ArchiveExports.cpp
@@ -1,151 +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 = 64;

-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;

-  }

-}

-

-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)) != 0)

-    value->vt = VT_BSTR;

-  return S_OK;

-}

-

-static inline HRESULT SetPropGUID(const GUID &guid, PROPVARIANT *value)

-{

-  return SetPropStrFromBin((const char *)&guid, sizeof(guid), value);

-}

-

-int FindFormatCalssId(const GUID *clsid)

-{

-  GUID cls = *clsid;

-  CLS_ARC_ID_ITEM(cls) = 0;

-  if (cls != CLSID_CArchiveHandler)

-    return -1;

-  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)

-{

-  COM_TRY_BEGIN

-  {

-    int needIn = (*iid == IID_IInArchive);

-    int needOut = (*iid == IID_IOutArchive);

-    if (!needIn && !needOut)

-      return E_NOINTERFACE;

-    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)

-{

-  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::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)

-{

-  return GetHandlerProperty2(g_DefaultArcIndex, propID, value);

-}

-

-STDAPI GetNumberOfFormats(UINT32 *numFormats)

-{

-  *numFormats = g_NumArcs;

-  return S_OK;

-}

-

-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
new file mode 100644
index 0000000..2f982c4
--- /dev/null
+++ b/CPP/7zip/Archive/ArjHandler.cpp
@@ -0,0 +1,1009 @@
+// ArjHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.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)
+
+
+Z7_CLASS_IMP_NOQIB_1(
+  CCoder
+  , ICompressCoder
+)
+  CLzOutWindow _outWindow;
+  NBitm::CDecoder<CInBuffer> _inBitStream;
+
+  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(UInt64 outSize, ICompressProgressInfo *progress);
+public:
+  bool FinishMode;
+
+  CCoder(): FinishMode(false) {}
+  UInt64 GetInputProcessedSize() const { return _inBitStream.GetProcessedSize(); }
+};
+
+
+HRESULT CCoder::CodeReal(UInt64 rem, ICompressProgressInfo *progress)
+{
+  const UInt32 kStep = 1 << 20;
+  UInt64 next = 0;
+  if (rem > kStep && progress)
+    next = rem - kStep;
+
+  while (rem != 0)
+  {
+    if (rem <= next)
+    {
+      if (_inBitStream.ExtraBitsWereRead())
+        return S_FALSE;
+
+      UInt64 packSize = _inBitStream.GetProcessedSize();
+      UInt64 pos = _outWindow.GetProcessedSize();
+      RINOK(progress->SetRatioInfo(&packSize, &pos))
+      next = 0;
+      if (rem > kStep)
+        next = rem - kStep;
+    }
+
+    UInt32 len;
+    
+    {
+      const unsigned kNumBits = 7 + 7;
+      UInt32 val = _inBitStream.GetValue(kNumBits);
+      
+      if ((val & (1 << (kNumBits - 1))) == 0)
+      {
+        _outWindow.PutByte((Byte)(val >> 5));
+        _inBitStream.MovePos(1 + 8);
+        rem--;
+        continue;
+      }
+
+      UInt32 mask = 1 << (kNumBits - 2);
+      unsigned w;
+
+      for (w = 1; w < 7; w++, mask >>= 1)
+        if ((val & mask) == 0)
+          break;
+      
+      unsigned readBits = (w != 7 ? 1 : 0);
+      readBits += w + w;
+      len = (1 << w) - 1 + kMatchMinLen - 1 +
+          (((val >> (kNumBits - readBits)) & ((1 << w) - 1)));
+      _inBitStream.MovePos(readBits);
+    }
+    
+    {
+      const unsigned kNumBits = 4 + 13;
+      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;
+
+      UInt32 dist = ((UInt32)1 << w) - (1 << 9) +
+          (((val >> (kNumBits - readBits)) & ((1 << w) - 1)));
+      _inBitStream.MovePos(readBits);
+
+      if (len > rem)
+        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;
+}
+
+
+
+Z7_COM7F_IMF(CCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+    const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress))
+{
+  try
+  {
+    if (!outSize)
+      return E_INVALIDARG;
+    
+    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);
+    HRESULT res;
+    {
+      res = CodeReal(*outSize, progress);
+      if (res != S_OK)
+        return res;
+    }
+    
+    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<CItem> _items;
+  CMyComPtr<IInStream> _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;
+  }
+  extractCallback->SetTotal(totalUnpacked);
+
+  totalUnpacked = totalPacked = 0;
+  UInt64 curUnpacked, curPacked;
+  
+  NCompress::NLzh::NDecoder::CCoder *lzhDecoderSpec = NULL;
+  CMyComPtr<ICompressCoder> lzhDecoder;
+
+  NCompress::NArj::NDecoder::CCoder *arjDecoderSpec = NULL;
+  CMyComPtr<ICompressCoder> arjDecoder;
+
+  NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+  CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> progress = lps;
+  lps->Init(extractCallback, false);
+
+  CLimitedSequentialInStream *inStreamSpec = new CLimitedSequentialInStream;
+  CMyComPtr<ISequentialInStream> inStream(inStreamSpec);
+  inStreamSpec->SetStream(_stream);
+
+  for (i = 0; i < numItems; i++, totalUnpacked += curUnpacked, totalPacked += curPacked)
+  {
+    lps->InSize = totalPacked;
+    lps->OutSize = totalUnpacked;
+    RINOK(lps->SetCur())
+
+    curUnpacked = curPacked = 0;
+
+    CMyComPtr<ISequentialOutStream> 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))
+        RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
+      }
+      continue;
+    }
+
+    if (!testMode && !realOutStream)
+      continue;
+
+    RINOK(extractCallback->PrepareOperation(askMode))
+    curUnpacked = item.Size;
+    curPacked = item.PackSize;
+
+    {
+      COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC;
+      CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+      outStreamSpec->SetStream(realOutStream);
+      realOutStream.Release();
+      outStreamSpec->Init();
+  
+      inStreamSpec->Init(item.PackSize);
+      
+      RINOK(InStream_SeekSet(_stream, item.DataPosition))
+
+      HRESULT result = S_OK;
+      Int32 opRes = NExtract::NOperationResult::kOK;
+
+      if (item.IsEncrypted())
+        opRes = NExtract::NOperationResult::kUnsupportedMethod;
+      else
+      {
+        switch (item.Method)
+        {
+          case NCompressionMethod::kStored:
+          {
+            result = copyCoder->Code(inStream, outStream, NULL, NULL, progress);
+            if (result == S_OK && copyCoderSpec->TotalSize != item.PackSize)
+              result = S_FALSE;
+            break;
+          }
+          case NCompressionMethod::kCompressed1a:
+          case NCompressionMethod::kCompressed1b:
+          case NCompressionMethod::kCompressed1c:
+          {
+            if (!lzhDecoder)
+            {
+              lzhDecoderSpec = new NCompress::NLzh::NDecoder::CCoder;
+              lzhDecoder = lzhDecoderSpec;
+            }
+            lzhDecoderSpec->FinishMode = true;
+            const UInt32 kHistorySize = 26624;
+            lzhDecoderSpec->SetDictSize(kHistorySize);
+            result = lzhDecoder->Code(inStream, outStream, NULL, &curUnpacked, progress);
+            if (result == S_OK && lzhDecoderSpec->GetInputProcessedSize() != item.PackSize)
+              result = S_FALSE;
+            break;
+          }
+          case NCompressionMethod::kCompressed2:
+          {
+            if (!arjDecoder)
+            {
+              arjDecoderSpec = new NCompress::NArj::NDecoder::CCoder;
+              arjDecoder = arjDecoderSpec;
+            }
+            arjDecoderSpec->FinishMode = true;
+            result = arjDecoder->Code(inStream, outStream, NULL, &curUnpacked, progress);
+            if (result == S_OK && arjDecoderSpec->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 = (outStreamSpec->GetCRC() == item.FileCRC) ?
+              NExtract::NOperationResult::kOK:
+              NExtract::NOperationResult::kCRCError;
+        }
+      }
+      
+      outStream.Release();
+      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/Base64Handler.cpp b/CPP/7zip/Archive/Base64Handler.cpp
new file mode 100644
index 0000000..5b06051
--- /dev/null
+++ b/CPP/7zip/Archive/Base64Handler.cpp
@@ -0,0 +1,505 @@
+// 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))
+      UInt32 isArcRes = IsArc_Base64(_data, size);
+      if (isArcRes == 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))
+
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> progress = lps;
+  lps->Init(extractCallback, false);
+
+  {
+    lps->InSize = lps->OutSize = 0;
+    RINOK(lps->SetCur())
+
+    CMyComPtr<ISequentialOutStream> 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 (realOutStream)
+    {
+      RINOK(WriteStream(realOutStream, (const Byte *)_data, _size))
+      realOutStream.Release();
+    }
+  
+    Int32 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
new file mode 100644
index 0000000..994b1ad
--- /dev/null
+++ b/CPP/7zip/Archive/Bz2Handler.cpp
@@ -0,0 +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<IInStream> _stream;
+  CMyComPtr<ISequentialInStream> _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;
+    }
+  }
+  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;
+  }
+  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)
+    extractCallback->SetTotal(_packSize);
+
+  CMyComPtr<ISequentialOutStream> 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(InStream_SeekToBegin(_stream))
+  }
+  else
+    _needSeekToStart = true;
+
+  // try {
+
+  NCompress::NBZip2::CDecoder *decoderSpec = new NCompress::NBZip2::CDecoder;
+  CMyComPtr<ICompressCoder> decoder = decoderSpec;
+
+  #ifndef Z7_ST
+  RINOK(decoderSpec->SetNumberOfThreads(_props._numThreads))
+  #endif
+
+  CDummyOutStream *outStreamSpec = new CDummyOutStream;
+  CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+  outStreamSpec->SetStream(realOutStream);
+  outStreamSpec->Init();
+  
+  realOutStream.Release();
+
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> progress = lps;
+  lps->Init(extractCallback, true);
+
+  decoderSpec->FinishMode = true;
+  decoderSpec->Base.DecodeAllStreams = true;
+  
+  _dataAfterEnd = false;
+  _needMoreInput = false;
+
+  lps->InSize = 0;
+  lps->OutSize = 0;
+  
+  HRESULT result = decoder->Code(_seqStream, outStream, NULL, NULL, progress);
+  
+  if (result != S_FALSE && result != S_OK)
+    return result;
+  
+  if (decoderSpec->Base.NumStreams == 0)
+  {
+    _isArc = false;
+    result = S_FALSE;
+  }
+  else
+  {
+    const UInt64 inProcessedSize = decoderSpec->GetInputProcessedSize();
+    UInt64 packSize = inProcessedSize;
+
+    if (decoderSpec->Base.NeedMoreInput)
+      _needMoreInput = true;
+    
+    if (!decoderSpec->Base.IsBz)
+    {
+      packSize = decoderSpec->Base.FinishedPackSize;
+      if (packSize != inProcessedSize)
+        _dataAfterEnd = true;
+    }
+
+    _packSize = packSize;
+    _unpackSize = decoderSpec->GetOutProcessedSize();
+    _numStreams = decoderSpec->Base.NumStreams;
+    _numBlocks = decoderSpec->GetNumBlocks();
+
+    _packSize_Defined = true;
+    _unpackSize_Defined = true;
+    _numStreams_Defined = true;
+    _numBlocks_Defined = true;
+  }
+  
+  outStream.Release();
+
+  Int32 opRes;
+
+  if (!_isArc)
+    opRes = NExtract::NOperationResult::kIsNotArc;
+  else if (_needMoreInput)
+    opRes = NExtract::NOperationResult::kUnexpectedEnd;
+  else if (decoderSpec->GetCrcError())
+    opRes = NExtract::NOperationResult::kCRCError;
+  else if (_dataAfterEnd)
+    opRes = NExtract::NOperationResult::kDataAfterEnd;
+  else if (result == S_FALSE)
+    opRes = NExtract::NOperationResult::kDataError;
+  else if (decoderSpec->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<ISequentialInStream> 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))
+    CLocalProgress *localProgressSpec = new CLocalProgress;
+    CMyComPtr<ICompressProgressInfo> localProgress = localProgressSpec;
+    localProgressSpec->Init(updateCallback, true);
+    {
+      NCompress::NBZip2::CEncoder *encoderSpec = new NCompress::NBZip2::CEncoder;
+      CMyComPtr<ICompressCoder> encoder = encoderSpec;
+      RINOK(props.SetCoderProps(encoderSpec, NULL))
+      RINOK(encoder->Code(fileInStream, outStream, NULL, NULL, localProgress))
+      /*
+      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;
+
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> progress = 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, progress);
+
+  // 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
new file mode 100644
index 0000000..dc767a4
--- /dev/null
+++ b/CPP/7zip/Archive/Cab/CabBlockInStream.cpp
@@ -0,0 +1,100 @@
+// 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);
+
+bool CCabBlockInStream::Create()
+{
+  if (!_buf)
+    _buf = (Byte *)::MyAlloc(kBlockSize);
+  return _buf != NULL;
+}
+
+CCabBlockInStream::~CCabBlockInStream()
+{
+  ::MyFree(_buf);
+}
+
+static UInt32 CheckSum(const Byte *p, UInt32 size)
+{
+  UInt32 sum = 0;
+  
+  for (; size >= 8; size -= 8)
+  {
+    sum ^= GetUi32(p) ^ GetUi32(p + 4);
+    p += 8;
+  }
+  
+  if (size >= 4)
+  {
+    sum ^= GetUi32(p);
+    p += 4;
+  }
+  
+  size &= 3;
+  if (size > 2) sum ^= (UInt32)(*p++) << 16;
+  if (size > 1) sum ^= (UInt32)(*p++) << 8;
+  if (size > 0) sum ^= (UInt32)(*p++);
+  
+  return sum;
+}
+
+HRESULT CCabBlockInStream::PreRead(ISequentialInStream *stream, UInt32 &packSize, UInt32 &unpackSize)
+{
+  const UInt32 kHeaderSize = 8;
+  const UInt32 kReservedMax = 256;
+  Byte header[kHeaderSize + kReservedMax];
+  RINOK(ReadStream_FALSE(stream, header, kHeaderSize + ReservedSize))
+  packSize = GetUi16(header + 4);
+  unpackSize = GetUi16(header + 6);
+  if (packSize > kBlockSize - _size)
+    return S_FALSE;
+  RINOK(ReadStream_FALSE(stream, _buf + _size, packSize))
+  
+  if (MsZip)
+  {
+    if (_size == 0)
+    {
+      if (packSize < 2 || _buf[0] != 0x43 || _buf[1] != 0x4B)
+        return S_FALSE;
+      _pos = 2;
+    }
+    if (_size + packSize > ((UInt32)1 << 15) + 12) /* v9.31 fix. MSZIP specification */
+      return S_FALSE;
+  }
+
+  if (GetUi32(header) != 0) // checkSum
+    if (CheckSum(header, kHeaderSize + ReservedSize) != CheckSum(_buf + _size, packSize))
+      return S_FALSE;
+
+  _size += packSize;
+  return S_OK;
+}
+
+Z7_COM7F_IMF(CCabBlockInStream::Read(void *data, UInt32 size, UInt32 *processedSize))
+{
+  if (size != 0)
+  {
+    UInt32 rem = _size - _pos;
+    if (size > rem)
+      size = rem;
+    memcpy(data, _buf + _pos, size);
+    _pos += size;
+  }
+  if (processedSize)
+    *processedSize = size;
+  return S_OK;
+}
+
+}}
diff --git a/CPP/7zip/Archive/Cab/CabBlockInStream.h b/CPP/7zip/Archive/Cab/CabBlockInStream.h
new file mode 100644
index 0000000..d14fff8
--- /dev/null
+++ b/CPP/7zip/Archive/Cab/CabBlockInStream.h
@@ -0,0 +1,39 @@
+// CabBlockInStream.h
+
+#ifndef ZIP7_INC_CAB_BLOCK_IN_STREAM_H
+#define ZIP7_INC_CAB_BLOCK_IN_STREAM_H
+
+#include "../../../Common/MyCom.h"
+#include "../../IStream.h"
+
+namespace NArchive {
+namespace NCab {
+
+Z7_CLASS_IMP_NOQIB_1(
+  CCabBlockInStream
+  , ISequentialInStream
+)
+  Byte *_buf;
+  UInt32 _size;
+  UInt32 _pos;
+
+public:
+  UInt32 ReservedSize; // < 256
+  bool MsZip;
+
+  CCabBlockInStream(): _buf(NULL), ReservedSize(0), MsZip(false) {}
+  ~CCabBlockInStream();
+  
+  bool Create();
+  
+  void InitForNewBlock() { _size = 0; _pos = 0; }
+  
+  HRESULT PreRead(ISequentialInStream *stream, UInt32 &packSize, UInt32 &unpackSize);
+
+  UInt32 GetPackSizeAvail() const { return _size - _pos; }
+  const Byte *GetData() const { return _buf + _pos; }
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/Cab/CabHandler.cpp b/CPP/7zip/Archive/Cab/CabHandler.cpp
new file mode 100644
index 0000000..f015145
--- /dev/null
+++ b/CPP/7zip/Archive/Cab/CabHandler.cpp
@@ -0,0 +1,1261 @@
+// CabHandler.cpp
+
+#include "StdAfx.h"
+
+// #include <stdio.h>
+
+#include "../../../../C/Alloc.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/StreamUtils.h"
+
+#include "../../Compress/CopyCoder.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<CFolder> &folders = m_Database.Volumes[v].Folders;
+          FOR_VECTOR (i, folders)
+          {
+            const CFolder &folder = folders[i];
+            unsigned method = folder.GetMethod();
+            mask |= ((UInt32)1 << method);
+            if (method == NHeader::NMethod::kLZX ||
+                method == NHeader::NMethod::kQuantum)
+            {
+              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 += '_';
+          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:
+  }
+  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];
+  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
+  }
+  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<IArchiveOpenVolumeCallback> openVolumeCallback;
+  if (callback)
+    callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback);
+  
+  CMyComPtr<IInStream> 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;
+        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;
+        }
+
+        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
+)
+  const CMvDatabaseEx *m_Database;
+  const CRecordVector<bool> *m_ExtractStatuses;
+  
+  Byte *TempBuf;
+  UInt32 TempBufSize;
+  UInt32 TempBufWritten;
+  unsigned NumIdenticalFiles;
+  bool TempBufMode;
+
+  unsigned m_StartIndex;
+  unsigned m_CurrentIndex;
+  CMyComPtr<IArchiveExtractCallback> m_ExtractCallback;
+  bool m_TestMode;
+
+  CMyComPtr<ISequentialOutStream> m_RealOutStream;
+
+  bool m_IsOk;
+  bool m_FileIsOpen;
+  UInt32 m_RemainFileSize;
+  UInt64 m_FolderSize;
+  UInt64 m_PosInFolder;
+
+  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<bool> *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<bool> *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<ISequentialOutStream> 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];
+    UInt64 fileSize = item.Size;
+    if (fileSize != 0)
+      return S_OK;
+    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;
+
+      UInt32 fileOffset = item.Offset;
+      
+      if (fileOffset < m_PosInFolder)
+        return E_FAIL;
+      
+      if (fileOffset > m_PosInFolder)
+      {
+        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<IArchiveExtractCallbackMessage2> 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;
+    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())
+  {
+    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 testModeSpec, 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;
+  bool testMode = (testModeSpec != 0);
+  UInt64 totalUnPacked = 0;
+
+  UInt32 i;
+  int lastFolder = -2;
+  UInt64 lastFolderSize = 0;
+  
+  for (i = 0; i < numItems; i++)
+  {
+    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;
+    int folderIndex = m_Database.GetFolderIndex(&mvItem);
+    if (folderIndex != lastFolder)
+      totalUnPacked += lastFolderSize;
+    lastFolder = folderIndex;
+    lastFolderSize = item.GetEndOffset();
+  }
+  
+  totalUnPacked += lastFolderSize;
+
+  extractCallback->SetTotal(totalUnPacked);
+
+  totalUnPacked = 0;
+
+  UInt64 totalPacked = 0;
+
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> progress = lps;
+  lps->Init(extractCallback, false);
+
+  NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder;
+  CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+  NCompress::NDeflate::NDecoder::CCOMCoder *deflateDecoderSpec = NULL;
+  CMyComPtr<ICompressCoder> deflateDecoder;
+
+  NCompress::NLzx::CDecoder *lzxDecoderSpec = NULL;
+  CMyComPtr<IUnknown> lzxDecoder;
+
+  NCompress::NQuantum::CDecoder *quantumDecoderSpec = NULL;
+  CMyComPtr<IUnknown> quantumDecoder;
+
+  CCabBlockInStream *cabBlockInStreamSpec = new CCabBlockInStream();
+  CMyComPtr<ISequentialInStream> cabBlockInStream = cabBlockInStreamSpec;
+  if (!cabBlockInStreamSpec->Create())
+    return E_OUTOFMEMORY;
+
+  CRecordVector<bool> extractStatuses;
+  
+  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<ISequentialOutStream> 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<ISequentialOutStream> 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();
+    }
+
+    CFolderOutStream *cabFolderOutStream = new CFolderOutStream;
+    CMyComPtr<ISequentialOutStream> outStream(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);
+
+    cabBlockInStreamSpec->MsZip = false;
+    HRESULT res = S_OK;
+    
+    switch (folder.GetMethod())
+    {
+      case NHeader::NMethod::kNone:
+        break;
+      
+      case NHeader::NMethod::kMSZip:
+        if (!deflateDecoder)
+        {
+          deflateDecoderSpec = new NCompress::NDeflate::NDecoder::CCOMCoder;
+          deflateDecoder = deflateDecoderSpec;
+        }
+        cabBlockInStreamSpec->MsZip = true;
+        break;
+      
+      case NHeader::NMethod::kLZX:
+        if (!lzxDecoder)
+        {
+          lzxDecoderSpec = new NCompress::NLzx::CDecoder;
+          lzxDecoder = lzxDecoderSpec;
+        }
+        res = lzxDecoderSpec->SetParams_and_Alloc(folder.MethodMinor);
+        break;
+
+      case NHeader::NMethod::kQuantum:
+        if (!quantumDecoder)
+        {
+          quantumDecoderSpec = new NCompress::NQuantum::CDecoder;
+          quantumDecoder = quantumDecoderSpec;
+        }
+        res = quantumDecoderSpec->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)
+        {
+          cabBlockInStreamSpec->ReservedSize = db2.ArcInfo.GetDataBlockReserveSize();
+          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)
+          cabBlockInStreamSpec->InitForNewBlock();
+
+        UInt32 packSize, unpackSize;
+        res = cabBlockInStreamSpec->PreRead(db2.Stream, packSize, unpackSize);
+        if (res == S_FALSE)
+          break;
+        RINOK(res)
+        keepInputBuffer = (unpackSize == 0);
+        if (keepInputBuffer)
+          continue;
+
+        UInt64 totalUnPacked2 = totalUnPacked + cabFolderOutStream->GetPosInFolder();
+        totalPacked += packSize;
+
+        lps->OutSize = totalUnPacked2;
+        lps->InSize = totalPacked;
+        RINOK(lps->SetCur())
+
+        const UInt32 kBlockSizeMax = (1 << 15);
+
+        /* 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 */
+
+        if (unpackSize > kBlockSizeMax)
+        {
+          res = S_FALSE;
+          break;
+        }
+
+        if (unpackSize != kBlockSizeMax)
+        {
+          if (thereWasNotAlignedChunk)
+          {
+            res = S_FALSE;
+            break;
+          }
+          thereWasNotAlignedChunk = true;
+        }
+
+        UInt64 unpackSize64 = unpackSize;
+        UInt32 packSizeChunk = cabBlockInStreamSpec->GetPackSizeAvail();
+
+        switch (folder2.GetMethod())
+        {
+          case NHeader::NMethod::kNone:
+            res = copyCoder->Code(cabBlockInStream, outStream, NULL, &unpackSize64, NULL);
+            break;
+          
+          case NHeader::NMethod::kMSZip:
+            deflateDecoderSpec->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 doesn't have finish marker at the end of block.
+               Cabarc probably ignores such errors in cab archives.
+               Maybe we also should ignore that error?
+               Or we should extract full file and show the warning? */
+            deflateDecoderSpec->Set_NeedFinishInput(true);
+            res = deflateDecoder->Code(cabBlockInStream, outStream, NULL, &unpackSize64, NULL);
+            if (res == S_OK)
+            {
+              if (!deflateDecoderSpec->IsFinished())
+                res = S_FALSE;
+              if (!deflateDecoderSpec->IsFinalBlock())
+                res = S_FALSE;
+            }
+            break;
+
+          case NHeader::NMethod::kLZX:
+            lzxDecoderSpec->SetKeepHistory(keepHistory);
+            lzxDecoderSpec->KeepHistoryForNext = true;
+            
+            res = lzxDecoderSpec->Code(cabBlockInStreamSpec->GetData(), packSizeChunk, unpackSize);
+
+            if (res == S_OK)
+              res = WriteStream(outStream,
+                  lzxDecoderSpec->GetUnpackData(),
+                  lzxDecoderSpec->GetUnpackSize());
+            break;
+          
+          case NHeader::NMethod::kQuantum:
+            res = quantumDecoderSpec->Code(cabBlockInStreamSpec->GetData(),
+                packSizeChunk, outStream, unpackSize, keepHistory);
+            break;
+        }
+      
+        if (res != S_OK)
+        {
+          if (res != S_FALSE)
+            RINOK(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
new file mode 100644
index 0000000..1e1811f
--- /dev/null
+++ b/CPP/7zip/Archive/Cab/CabHandler.h
@@ -0,0 +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
diff --git a/CPP/7zip/Archive/Cab/CabHeader.cpp b/CPP/7zip/Archive/Cab/CabHeader.cpp
new file mode 100644
index 0000000..370a2f1
--- /dev/null
+++ b/CPP/7zip/Archive/Cab/CabHeader.cpp
@@ -0,0 +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;
+
+}}}
diff --git a/CPP/7zip/Archive/Cab/CabHeader.h b/CPP/7zip/Archive/Cab/CabHeader.h
new file mode 100644
index 0000000..ecb9a87
--- /dev/null
+++ b/CPP/7zip/Archive/Cab/CabHeader.h
@@ -0,0 +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
diff --git a/CPP/7zip/Archive/Cab/CabIn.cpp b/CPP/7zip/Archive/Cab/CabIn.cpp
new file mode 100644
index 0000000..fb69643
--- /dev/null
+++ b/CPP/7zip/Archive/Cab/CabIn.cpp
@@ -0,0 +1,491 @@
+// Archive/CabIn.cpp
+
+#include "StdAfx.h"
+
+// #include <stdio.h>
+
+#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;
+
+  ISequentialInStream *Stream;
+  UInt64 Processed; // Global offset of start of Buf
+
+  const UInt64 *SearchLimit;
+
+  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;
+      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)
+    {
+      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;
+      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<ISequentialInStream> 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;
+          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];
+  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);
+    UInt16 pureDate = Get16(p + 10);
+    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];
+  bool isDir1 = item1.IsDir();
+  bool isDir2 = item2.IsDir();
+  if (isDir1 && !isDir2) return -1;
+  if (isDir2 && !isDir1) return 1;
+  int f1 = mvDb.GetFolderIndex(p1);
+  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)
+  {
+    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.Front();
+      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];
+    int fIndex = GetFolderIndex(&mvItem);
+    if (fIndex >= (int)FolderStartFileIndex.Size())
+      return false;
+    const CItem &item = Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex];
+    if (item.IsDir())
+      continue;
+    
+    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
new file mode 100644
index 0000000..06aa34c
--- /dev/null
+++ b/CPP/7zip/Archive/Cab/CabIn.h
@@ -0,0 +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<CFolder> Folders;
+  CObjectVector<CItem> 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<IInStream> Stream;
+};
+
+
+struct CMvItem
+{
+  unsigned VolumeIndex;
+  unsigned ItemIndex;
+};
+
+
+class CMvDatabaseEx
+{
+  bool AreItemsEqual(unsigned i1, unsigned i2);
+
+public:
+  CObjectVector<CDatabaseEx> Volumes;
+  CRecordVector<CMvItem> Items;
+  CRecordVector<int> StartFolderOfVol; // can be negative
+  CRecordVector<unsigned> 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
new file mode 100644
index 0000000..b7e07d1
--- /dev/null
+++ b/CPP/7zip/Archive/Cab/CabItem.h
@@ -0,0 +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
diff --git a/CPP/7zip/Archive/Cab/CabRegister.cpp b/CPP/7zip/Archive/Cab/CabRegister.cpp
new file mode 100644
index 0000000..8f4f323
--- /dev/null
+++ b/CPP/7zip/Archive/Cab/CabRegister.cpp
@@ -0,0 +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)
+
+}}
diff --git a/CPP/7zip/Archive/Cab/StdAfx.h b/CPP/7zip/Archive/Cab/StdAfx.h
new file mode 100644
index 0000000..035267c
--- /dev/null
+++ b/CPP/7zip/Archive/Cab/StdAfx.h
@@ -0,0 +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
diff --git a/CPP/7zip/Archive/Chm/ChmHandler.cpp b/CPP/7zip/Archive/Chm/ChmHandler.cpp
new file mode 100644
index 0000000..38e2543
--- /dev/null
+++ b/CPP/7zip/Archive/Chm/ChmHandler.cpp
@@ -0,0 +1,800 @@
+// ChmHandler.cpp
+
+#include "StdAfx.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<IArchiveExtractCallback> m_ExtractCallback;
+  CMyComPtr<ISequentialOutStream> 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<bool> *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;
+  bool testMode = (testModeSpec != 0);
+
+  UInt64 currentTotalSize = 0;
+
+  NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder;
+  CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+  UInt32 i;
+
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> progress = lps;
+  lps->Init(extractCallback, false);
+
+  CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+  CMyComPtr<ISequentialInStream> inStream(streamSpec);
+  streamSpec->SetStream(m_Stream);
+
+  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;
+    
+    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<ISequentialOutStream> 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)
+        {
+          UInt32 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))
+      streamSpec->Init(item.Size);
+      
+      RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress))
+      realOutStream.Release();
+      RINOK(extractCallback->SetOperationResult((copyCoderSpec->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 &section = 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))
+
+  NCompress::NLzx::CDecoder *lzxDecoderSpec = NULL;
+  CMyComPtr<IUnknown> lzxDecoder;
+  CChmFolderOutStream *chmFolderOutStream = NULL;
+  CMyComPtr<ISequentialOutStream> outStream;
+
+  currentTotalSize = 0;
+
+  CRecordVector<bool> extractStatuses;
+
+  CByteBuffer packBuf;
+  
+  for (i = 0;;)
+  {
+    RINOK(extractCallback->SetCompleted(&currentTotalSize))
+
+    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;
+    Int32 askMode= testMode ?
+        NExtract::NAskMode::kTest :
+        NExtract::NAskMode::kExtract;
+    
+    if (item.IsDir())
+    {
+      CMyComPtr<ISequentialOutStream> 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<ISequentialOutStream> 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))
+        streamSpec->Init(item.Size);
+        RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress))
+        if (copyCoderSpec->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<ISequentialOutStream> realOutStream;
+      RINOK(extractCallback->GetStream(index, &realOutStream, askMode))
+      if (!testMode && !realOutStream)
+        continue;
+      RINOK(extractCallback->PrepareOperation(askMode))
+      RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kHeadersError))
+      continue;
+    }
+
+    const CSectionInfo &section = m_Database.Sections[(unsigned)sectionIndex];
+
+    if (!section.IsLzx())
+    {
+      CMyComPtr<ISequentialOutStream> 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;
+
+    if (!chmFolderOutStream)
+    {
+      chmFolderOutStream = new CChmFolderOutStream;
+      outStream = chmFolderOutStream;
+    }
+
+    chmFolderOutStream->Init(&m_Database, extractCallback, testMode);
+
+    if (!lzxDecoderSpec)
+    {
+      lzxDecoderSpec = new NCompress::NLzx::CDecoder;
+      lzxDecoder = lzxDecoderSpec;
+    }
+
+    UInt64 folderIndex = m_Database.GetFolder(index);
+
+    const UInt64 compressedPos = m_Database.ContentOffset + section.Offset;
+    RINOK(lzxDecoderSpec->SetParams_and_Alloc(lzxInfo.GetNumDictBits()))
+
+    const CItem *lastItem = &item;
+    extractStatuses.Clear();
+    extractStatuses.Add(true);
+
+    for (;; folderIndex++)
+    {
+      RINOK(extractCallback->SetCompleted(&currentTotalSize))
+
+      UInt64 startPos = lzxInfo.GetFolderPos(folderIndex);
+      UInt64 finishPos = lastItem->Offset + lastItem->Size;
+      UInt64 limitFolderIndex = lzxInfo.GetFolder(finishPos);
+
+      lastFolderIndex = m_Database.GetLastFolder(index);
+      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
+      {
+        UInt64 startBlock = lzxInfo.GetBlockIndexFromFolderIndex(folderIndex);
+        const CResetTable &rt = lzxInfo.ResetTable;
+        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;
+          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))
+          streamSpec->SetStream(m_Stream);
+          streamSpec->Init(compressedSize);
+          
+          lzxDecoderSpec->SetKeepHistory(b > 0);
+      
+          size_t compressedSizeT = (size_t)compressedSize;
+          if (compressedSizeT != compressedSize)
+            throw 2;
+          packBuf.AllocAtLeast(compressedSizeT);
+
+          HRESULT res = ReadStream_FALSE(inStream, packBuf, compressedSizeT);
+          
+          if (res == S_OK)
+          {
+            lzxDecoderSpec->KeepHistoryForNext = true;
+            res = lzxDecoderSpec->Code(packBuf, compressedSizeT, kBlockSize); // rt.BlockSize;
+            if (res == S_OK)
+              res = WriteStream(chmFolderOutStream,
+                  lzxDecoderSpec->GetUnpackData(),
+                  lzxDecoderSpec->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
new file mode 100644
index 0000000..94821b2
--- /dev/null
+++ b/CPP/7zip/Archive/Chm/ChmHandler.h
@@ -0,0 +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<IInStream> 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
new file mode 100644
index 0000000..28d512d
--- /dev/null
+++ b/CPP/7zip/Archive/Chm/ChmIn.cpp
@@ -0,0 +1,1018 @@
+// Archive/ChmIn.cpp
+
+#include "StdAfx.h"
+
+// #include <stdio.h>
+
+#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 char GetHex(unsigned v)
+{
+  return (char)((v < 10) ? ('0' + v) : ('A' + (v - 10)));
+}
+
+static void PrintByte(Byte b, AString &s)
+{
+  s += GetHex(b >> 4);
+  s += GetHex(b & 0xF);
+}
+
+AString CMethodInfo::GetGuidString() const
+{
+  char s[48];
+  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)
+      {
+        s += ':';
+        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++)
+  {
+    Byte 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)
+  {
+    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<ISequentialInStream> 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;
+  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.
+
+      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 (;;)
+      {
+        UInt64 offset = _inBuffer.GetProcessedSize() - chunkPos;
+        UInt32 offsetLimit = dirChunkSize - quickrefLength;
+        if (offset > offsetLimit)
+          return S_FALSE;
+        if (offset == offsetLimit)
+          break;
+        RINOK(ReadDirEntry(database))
+        numItems++;
+      }
+      
+      Skip(quickrefLength - 2);
+      
+      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 (;;)
+      {
+        UInt64 offset = _inBuffer.GetProcessedSize() - chunkPos;
+        UInt32 offsetLimit = dirChunkSize - quickrefLength;
+        if (offset > offsetLimit)
+          return S_FALSE;
+        if (offset == offsetLimit)
+          break;
+        if (database.NewFormat)
+        {
+          UInt16 nameLen = ReadUInt16();
+          if (nameLen == 0)
+            return S_FALSE;
+          UString name;
+          ReadUString((unsigned)nameLen, name);
+          AString s;
+          ConvertUnicodeToUTF8(name, s);
+          Byte 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?)
+          while (len-- != 0)
+          {
+            b = ReadByte();
+            PrintByte(b, s);
+          }
+          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 += '/';
+  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<CItem> &items = *(const CObjectVector<CItem> *)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;
+      UInt16 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 &section = 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;
+          while (numDWORDS-- != 0)
+            ReadUInt32();
+        }
+        else
+        {
+          UInt32 numBytes = numDWORDS * 4;
+          method.ControlData.Alloc(numBytes);
+          ReadBytes(method.ControlData, 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
+        {
+          UInt32 ver = ReadUInt32(); // 2  unknown (possibly a version number)
+          if (ver != 2 && ver != 3)
+            return S_FALSE;
+          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
new file mode 100644
index 0000000..c01ef4d
--- /dev/null
+++ b/CPP/7zip/Archive/Chm/ChmIn.h
@@ -0,0 +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
+{
+  UInt64 StartPosition;
+  UInt64 ContentOffset;
+  CObjectVector<CItem> Items;
+  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<UInt64> 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 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
+  {
+    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<CMethodInfo> Methods;
+
+  bool IsLzx() const;
+  UString GetMethodName() const;
+};
+
+class CFilesDatabase: public CDatabase
+{
+public:
+  bool LowLevel;
+  CUIntVector Indices;
+  CObjectVector<CSectionInfo> Sections;
+
+  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 &section = 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 &section = 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<ISequentialInStream> 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
new file mode 100644
index 0000000..035267c
--- /dev/null
+++ b/CPP/7zip/Archive/Chm/StdAfx.h
@@ -0,0 +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
diff --git a/CPP/7zip/Archive/ComHandler.cpp b/CPP/7zip/Archive/ComHandler.cpp
new file mode 100644
index 0000000..7aabd65
--- /dev/null
+++ b/CPP/7zip/Archive/ComHandler.cpp
@@ -0,0 +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<UInt32> MiniSids;
+
+  HRESULT AddNode(int parent, UInt32 did);
+public:
+
+  CObjArray<UInt32> Fat;
+  UInt32 FatSize;
+  
+  CObjArray<UInt32> Mat;
+  UInt32 MatSize;
+
+  CObjectVector<CItem> Items;
+  CRecordVector<CRef> 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 += '[';
+      res.Add_UInt32((UInt32)(unsigned)(int)c);
+      res += ']';
+    }
+    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 -= k_Msi_StartUnicodeChar;
+    
+    unsigned c0 = (unsigned)c & k_Msi_CharMask;
+    unsigned c1 = (unsigned)c >> k_Msi_NumBits;
+
+    if (c1 <= k_Msi_NumChars)
+    {
+      res += k_Msi_Chars[c0];
+      if (c1 == k_Msi_NumChars)
+        break;
+      res += k_Msi_Chars[c1];
+    }
+    else
+      res += 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<UInt32> 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<IInStream> _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<ICompressCoder> copyCoder = copyCoderSpec;
+
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> 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<ISequentialOutStream> 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<ISequentialInStream> 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<ISequentialInStream> 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 baddddf..b6ddeb8 100644
--- a/CPP/7zip/Archive/Common/CoderMixer2.cpp
+++ b/CPP/7zip/Archive/Common/CoderMixer2.cpp
@@ -1,1125 +1,1144 @@
-// CoderMixer2.cpp

-

-#include "StdAfx.h"

-

-#include "CoderMixer2.h"

-

-#ifdef USE_MIXER_ST

-

-STDMETHODIMP 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;

-}

-

-

-STDMETHODIMP 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;

-}

-

-STDMETHODIMP COutStreamCalcSize::OutStreamFinish()

-{

-  HRESULT result = S_OK;

-  if (_stream)

-  {

-    CMyComPtr<IOutStreamFinish> 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<ICompressGetInStreamProcessedSize> 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<ICompressGetInStreamProcessedSize2> 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;

-  

-  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;

-    

-    int bond = BindInfo->FindBond_for_PackStream(ind);

-    if (bond < 0)

-      return false;

-    if (!CheckCoder(BindInfo->Bonds[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;

-  

-  int bond = _bi.FindBond_for_UnpackStream(coderIndex);

-  if (bond < 0)

-    throw 20150213;

-  

-  /*

-  UInt32 coderIndex, coderStreamIndex;

-  _bi.GetCoder_for_Stream(_bi.Bonds[bond].PackIndex, coderIndex, coderStreamIndex);

-  */

-  UInt32 nextCoder = _bi.Stream_to_Coder[_bi.Bonds[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;

-  

-  int bond = _bi.FindBond_for_PackStream(streamIndex);

-  if (bond < 0)

-    throw 20150213;

-

-  UInt32 nextCoder = _bi.Bonds[bond].UnpackIndex;

-

-  if (!IsFilter_Vector[nextCoder])

-    return false;

-  

-  return Is_PackSize_Correct_for_Coder(nextCoder);

-}

-

-bool CMixer::Is_PackSize_Correct_for_Coder(UInt32 coderIndex)

-{

-  UInt32 startIndex = _bi.Coder_to_Stream[coderIndex];

-  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;

-  UInt32 startIndex = _bi.Coder_to_Stream[coderIndex];

-  UInt32 numStreams = _bi.Coders[coderIndex].NumStreams;

-  for (UInt32 i = 0; i < numStreams; i++)

-  {

-    UInt32 si = startIndex + i;

-    if (_bi.IsStream_in_PackStreams(si))

-      continue;

-  

-    int bond = _bi.FindBond_for_PackStream(si);

-    if (bond < 0)

-      throw 20150213;

-

-    if (IsThere_ExternalCoder_in_PackTree(_bi.Bonds[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);

-    {

-      CMyComPtr<ISequentialInStream> s;

-      unk->QueryInterface(IID_ISequentialInStream, (void**)&s);

-      c2.CanRead = (s != NULL);

-    }

-    {

-      CMyComPtr<ISequentialOutStream> s;

-      unk->QueryInterface(IID_ISequentialOutStream, (void**)&s);

-      c2.CanWrite = (s != NULL);

-    }

-  }

-}

-

-CCoder &CMixerST::GetCoder(unsigned index)

-{

-  return _coders[index];

-}

-

-void CMixerST::ReInit() {}

-

-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<ISequentialInStream> seqInStream;

-  coder.QueryInterface(IID_ISequentialInStream, (void **)&seqInStream);

-  if (!seqInStream)

-    return E_NOTIMPL;

-

-  UInt32 numInStreams = EncodeMode ? 1 : coder.NumStreams;

-  UInt32 startIndex = EncodeMode ? coderIndex : _bi.Coder_to_Stream[coderIndex];

-

-  bool isSet = false;

-  

-  if (numInStreams == 1)

-  {

-    CMyComPtr<ICompressSetInStream> setStream;

-    coder.QueryInterface(IID_ICompressSetInStream, (void **)&setStream);

-    if (setStream)

-    {

-      CMyComPtr<ISequentialInStream> seqInStream2;

-      RINOK(GetInStream(inStreams, /* inSizes, */ startIndex + 0, &seqInStream2));

-      RINOK(setStream->SetInStream(seqInStream2));

-      isSet = true;

-    }

-  }

-  

-  if (!isSet && numInStreams != 0)

-  {

-    CMyComPtr<ICompressSetInStream2> setStream2;

-    coder.QueryInterface(IID_ICompressSetInStream2, (void **)&setStream2);

-    if (!setStream2)

-      return E_NOTIMPL;

-    

-    for (UInt32 i = 0; i < numInStreams; i++)

-    {

-      CMyComPtr<ISequentialInStream> 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<ISequentialInStream> 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;

-    }

-  }

-  

-  int bond = FindBond_for_Stream(

-      true, // forInputStream

-      inStreamIndex);

-  if (bond < 0)

-    return E_INVALIDARG;

-

-  RINOK(GetInStream2(inStreams, /* inSizes, */

-      _bi.Bonds[bond].Get_OutIndex(EncodeMode), &seqInStream));

-

-  while (_binderStreams.Size() <= (unsigned)bond)

-    _binderStreams.AddNew();

-  CStBinderStream &bs = _binderStreams[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<ISequentialOutStream> 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;

-    }

-  }

-  

-  int bond = FindBond_for_Stream(

-      false, // forInputStream

-      outStreamIndex);

-  if (bond < 0)

-    return E_INVALIDARG;

-

-  UInt32 inStreamIndex = _bi.Bonds[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;

-

-  UInt32 numOutStreams = EncodeMode ? coder.NumStreams : 1;

-  UInt32 startIndex = EncodeMode ? _bi.Coder_to_Stream[coderIndex]: coderIndex;

-

-  bool isSet = false;

-

-  if (numOutStreams == 1)

-  {

-    CMyComPtr<ICompressSetOutStream> setOutStream;

-    coder.Coder.QueryInterface(IID_ICompressSetOutStream, &setOutStream);

-    if (setOutStream)

-    {

-      CMyComPtr<ISequentialOutStream> seqOutStream2;

-      RINOK(GetOutStream(outStreams, /* outSizes, */ startIndex + 0, &seqOutStream2));

-      RINOK(setOutStream->SetOutStream(seqOutStream2));

-      isSet = true;

-    }

-  }

-

-  if (!isSet && numOutStreams != 0)

-  {

-    return E_NOTIMPL;

-    /*

-    CMyComPtr<ICompressSetOutStream2> setStream2;

-    coder.QueryInterface(IID_ICompressSetOutStream2, (void **)&setStream2);

-    if (!setStream2)

-      return E_NOTIMPL;

-    for (UInt32 i = 0; i < numOutStreams; i++)

-    {

-      CMyComPtr<ISequentialOutStream> seqOutStream2;

-      RINOK(GetOutStream(outStreams, startIndex + i, &seqOutStream2));

-      RINOK(setStream2->SetOutStream2(i, seqOutStream2));

-    }

-    */

-  }

-

-  while (_binderStreams.Size() <= (unsigned)bond)

-    _binderStreams.AddNew();

-  CStBinderStream &bs = _binderStreams[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;

-  }

-

-  int bond = FindBond_for_Stream(

-      false, // forInputStream

-      streamIndex);

-  if (bond < 0)

-    return E_INVALIDARG;

-

-  UInt32 inStreamIndex = _bi.Bonds[bond].Get_InIndex(EncodeMode);

-

-  UInt32 coderIndex = inStreamIndex;

-  UInt32 coderStreamIndex = 0;

-  if (!EncodeMode)

-    _bi.GetCoder_for_Stream(inStreamIndex, coderIndex, coderStreamIndex);

-

-  CCoder &coder = _coders[coderIndex];

-  CMyComPtr<IOutStreamFinish> 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];

-

-  UInt32 numOutStreams = EncodeMode ? coder.NumStreams : 1;

-  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;

-  int 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;

-    

-    UInt32 st = _bi.Coder_to_Stream[ci];

-    if (_bi.IsStream_in_PackStreams(st))

-      break;

-    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 = ci;

-    

-    ci = _bi.Bonds[bond].UnpackIndex;

-  }

-  

-  if (useFirst)

-    ci = firstAllowed;

-  else if (firstNonFilter >= 0)

-    ci = firstNonFilter;

-

-  MainCoderIndex = ci;

-}

-

-

-HRESULT CMixerST::Code(

-    ISequentialInStream * const *inStreams,

-    ISequentialOutStream * const *outStreams,

-    ICompressProgressInfo *progress,

-    bool &dataAfterEnd_Error)

-{

-  // InternalPackSizeError = false;

-  dataAfterEnd_Error = false;

-

-  _binderStreams.Clear();

-  unsigned ci = MainCoderIndex;

- 

-  const CCoder &mainCoder = _coders[MainCoderIndex];

-

-  CObjectVector< CMyComPtr<ISequentialInStream> > seqInStreams;

-  CObjectVector< CMyComPtr<ISequentialOutStream> > seqOutStreams;

-  

-  UInt32 numInStreams  =  EncodeMode ? 1 : mainCoder.NumStreams;

-  UInt32 numOutStreams = !EncodeMode ? 1 : mainCoder.NumStreams;

-  

-  UInt32 startInIndex  =  EncodeMode ? ci : _bi.Coder_to_Stream[ci];

-  UInt32 startOutIndex = !EncodeMode ? ci : _bi.Coder_to_Stream[ci];

-  

-  UInt32 i;

-

-  for (i = 0; i < numInStreams; i++)

-  {

-    CMyComPtr<ISequentialInStream> seqInStream;

-    RINOK(GetInStream(inStreams, /* inSizes, */ startInIndex + i, &seqInStream));

-    seqInStreams.Add(seqInStream);

-  }

-  

-  for (i = 0; i < numOutStreams; i++)

-  {

-    CMyComPtr<ISequentialOutStream> 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<ICompressInitEncoder> initEncoder;

-      coder.QueryInterface(IID_ICompressInitEncoder, (void **)&initEncoder);

-      if (initEncoder)

-        RINOK(initEncoder->InitEncoder());

-    }

-    else

-    {

-      CMyComPtr<ICompressSetOutStreamSize> 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.Front();

-  const UInt64 * const *outSizes2 = EncodeMode ? &mainCoder.PackSizePointers.Front() : &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.Front(), isSizes2, numInStreams,

-        &seqOutStreamsSpec.Front(), 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<ISequentialInStream> seqInStream;

-

-  RINOK(GetInStream2(inStreams, /* inSizes, */

-      _bi.UnpackCoder, &seqInStream))

-  

-  FOR_VECTOR (i, _coders)

-  {

-    CCoder &coder = _coders[i];

-    CMyComPtr<ICompressSetOutStreamSize> 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.Front(),  EncodeMode ? &UnpackSizePointer : &PackSizePointers.Front(), numInStreams,

-        &OutStreamPointers.Front(), EncodeMode ? &PackSizePointers.Front(): &UnpackSizePointer, numOutStreams,

-        progress);

-}

-

-HRESULT CMixerMT::SetBindInfo(const CBindInfo &bindInfo)

-{

-  CMixer::SetBindInfo(bindInfo);

-  

-  _streamBinders.Clear();

-  FOR_VECTOR (i, _bi.Bonds)

-  {

-    RINOK(_streamBinders.AddNew().CreateEvents());

-  }

-  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];

-}

-

-void CMixerMT::ReInit()

-{

-  FOR_VECTOR (i, _streamBinders)

-    _streamBinders[i].ReInit();

-}

-

-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;

-    int bond = _bi.FindBond_for_PackStream(st);

-    if (bond < 0)

-      throw 20150213;

-    ci = _bi.Bonds[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;

-

-    unsigned numInStreams = EncodeMode ? 1 : csi.NumStreams;

-    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].CreateStreams(

-        &_coders[inCoderIndex].InStreams[inCoderStreamIndex],

-        &_coders[outCoderIndex].OutStreams[outCoderStreamIndex]);

-

-    CMyComPtr<ICompressSetBufSize> 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)

-    {

-      RINOK(_coders[i].Create());

-    }

-

-  for (i = 0; i < _coders.Size(); i++)

-    if (i != MainCoderIndex)

-      _coders[i].Start();

-

-  _coders[MainCoderIndex].Code(progress);

-

-  for (i = 0; i < _coders.Size(); i++)

-    if (i != MainCoderIndex)

-      _coders[i].WaitExecuteFinish();

-

-  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<IOutStreamFinish> 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<ICompressGetInStreamProcessedSize> 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<ICompressGetInStreamProcessedSize2> 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<ISequentialInStream> 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<ICompressSetInStream> setStream;
+    coder.QueryInterface(IID_ICompressSetInStream, (void **)&setStream);
+    if (setStream)
+    {
+      CMyComPtr<ISequentialInStream> seqInStream2;
+      RINOK(GetInStream(inStreams, /* inSizes, */ startIndex + 0, &seqInStream2))
+      RINOK(setStream->SetInStream(seqInStream2))
+      isSet = true;
+    }
+  }
+  
+  if (!isSet && numInStreams != 0)
+  {
+    CMyComPtr<ICompressSetInStream2> setStream2;
+    coder.QueryInterface(IID_ICompressSetInStream2, (void **)&setStream2);
+    if (!setStream2)
+      return E_NOTIMPL;
+    
+    for (UInt32 i = 0; i < numInStreams; i++)
+    {
+      CMyComPtr<ISequentialInStream> 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<ISequentialInStream> 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<ISequentialOutStream> 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<ICompressSetOutStream> setOutStream;
+    coder.Coder.QueryInterface(IID_ICompressSetOutStream, &setOutStream);
+    if (setOutStream)
+    {
+      CMyComPtr<ISequentialOutStream> seqOutStream2;
+      RINOK(GetOutStream(outStreams, /* outSizes, */ startIndex + 0, &seqOutStream2))
+      RINOK(setOutStream->SetOutStream(seqOutStream2))
+      isSet = true;
+    }
+  }
+
+  if (!isSet && numOutStreams != 0)
+  {
+    return E_NOTIMPL;
+    /*
+    CMyComPtr<ICompressSetOutStream2> setStream2;
+    coder.QueryInterface(IID_ICompressSetOutStream2, (void **)&setStream2);
+    if (!setStream2)
+      return E_NOTIMPL;
+    for (UInt32 i = 0; i < numOutStreams; i++)
+    {
+      CMyComPtr<ISequentialOutStream> 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<IOutStreamFinish> 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<ISequentialInStream> > seqInStreams;
+  CObjectVector< CMyComPtr<ISequentialOutStream> > 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<ISequentialInStream> seqInStream;
+    RINOK(GetInStream(inStreams, /* inSizes, */ startInIndex + i, &seqInStream))
+    seqInStreams.Add(seqInStream);
+  }
+  
+  for (i = 0; i < numOutStreams; i++)
+  {
+    CMyComPtr<ISequentialOutStream> 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<ICompressInitEncoder> initEncoder;
+      coder.QueryInterface(IID_ICompressInitEncoder, (void **)&initEncoder);
+      if (initEncoder)
+      {
+        RINOK(initEncoder->InitEncoder())
+      }
+    }
+    else
+    {
+      CMyComPtr<ICompressSetOutStreamSize> 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.Front();
+  const UInt64 * const *outSizes2 = EncodeMode ? &mainCoder.PackSizePointers.Front() : &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.Front(), isSizes2, numInStreams,
+        &seqOutStreamsSpec.Front(), 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<ISequentialInStream> seqInStream;
+
+  RINOK(GetInStream2(inStreams, /* inSizes, */
+      _bi.UnpackCoder, &seqInStream))
+  
+  FOR_VECTOR (i, _coders)
+  {
+    CCoder &coder = _coders[i];
+    CMyComPtr<ICompressSetOutStreamSize> 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.Front(),  EncodeMode ? &UnpackSizePointer : &PackSizePointers.Front(), numInStreams,
+        &OutStreamPointers.Front(), EncodeMode ? &PackSizePointers.Front(): &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<ICompressSetBufSize> 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 4bd6418..484a608 100644
--- a/CPP/7zip/Archive/Common/CoderMixer2.h
+++ b/CPP/7zip/Archive/Common/CoderMixer2.h
@@ -1,447 +1,447 @@
-// CoderMixer2.h

-

-#ifndef __CODER_MIXER2_H

-#define __CODER_MIXER2_H

-

-#include "../../../Common/MyCom.h"

-#include "../../../Common/MyVector.h"

-

-#include "../../ICoder.h"

-

-#include "../../Common/CreateCoder.h"

-

-#ifdef _7ZIP_ST

-  #define USE_MIXER_ST

-#else

-  #define USE_MIXER_MT

-  #ifndef _SFX

-    #define USE_MIXER_ST

-  #endif

-#endif

-

-#ifdef USE_MIXER_MT

-#include "../../Common/StreamBinder.h"

-#include "../../Common/VirtThread.h"

-#endif

-

-

-

-#ifdef USE_MIXER_ST

-

-class CSequentialInStreamCalcSize:

-  public ISequentialInStream,

-  public CMyUnknownImp

-{

-public:

-  MY_UNKNOWN_IMP1(ISequentialInStream)

-

-  STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);

-private:

-  CMyComPtr<ISequentialInStream> _stream;

-  UInt64 _size;

-  bool _wasFinished;

-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; }

-};

-

-

-class COutStreamCalcSize:

-  public ISequentialOutStream,

-  public IOutStreamFinish,

-  public CMyUnknownImp

-{

-  CMyComPtr<ISequentialOutStream> _stream;

-  UInt64 _size;

-public:

-  MY_UNKNOWN_IMP2(ISequentialOutStream, IOutStreamFinish)

-  

-  STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);

-  STDMETHOD(OutStreamFinish)();

-  

-  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<CCoderStreamsInfo> Coders;

-  CRecordVector<CBond> Bonds;

-  CRecordVector<UInt32> 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 i;

-    return -1;

-  }

-

-  int FindBond_for_UnpackStream(UInt32 unpackStream) const

-  {

-    FOR_VECTOR (i, Bonds)

-      if (Bonds[i].UnpackIndex == unpackStream)

-        return 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 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<UInt32> Coder_to_Stream;

-  CRecordVector<UInt32> 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

-{

-  CLASS_NO_COPY(CCoder);

-public:

-  CMyComPtr<ICompressCoder> Coder;

-  CMyComPtr<ICompressCoder2> Coder2;

-  UInt32 NumStreams;

-

-  UInt64 UnpackSize;

-  const UInt64 *UnpackSizePointer;

-

-  CRecordVector<UInt64> PackSizes;

-  CRecordVector<const UInt64 *> PackSizePointers;

-

-  bool Finish;

-

-  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)

-      {}

-

-  /*

-  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 void ReInit() = 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<IUnknown> StreamRef;

-

-  CStBinderStream(): InStreamSpec(NULL), OutStreamSpec(NULL) {}

-};

-

-

-class CMixerST:

-  public IUnknown,

-  public CMixer,

-  public CMyUnknownImp

-{

-  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<CCoderST> _coders;

-  

-  CObjectVector<CStBinderStream> _binderStreams;

-

-  MY_UNKNOWN_IMP

-

-  CMixerST(bool encodeMode);

-  ~CMixerST();

-

-  virtual void AddCoder(const CCreatedCoder &cod);

-  virtual CCoder &GetCoder(unsigned index);

-  virtual void SelectMainCoder(bool useFirst);

-  virtual void ReInit();

-  virtual void SetCoderInfo(unsigned coderIndex, const UInt64 *unpackSize, const UInt64 * const *packSizes, bool finish)

-    { _coders[coderIndex].SetCoderInfo(unpackSize, packSizes, finish); }

-  virtual HRESULT Code(

-      ISequentialInStream * const *inStreams,

-      ISequentialOutStream * const *outStreams,

-      ICompressProgressInfo *progress,

-      bool &dataAfterEnd_Error);

-  virtual UInt64 GetBondStreamSize(unsigned bondIndex) const;

-

-  HRESULT GetMainUnpackStream(

-      ISequentialInStream * const *inStreams,

-      ISequentialInStream **inStreamRes);

-};

-

-#endif

-

-

-

-

-#ifdef USE_MIXER_MT

-

-class CCoderMT: public CCoder, public CVirtThread

-{

-  CLASS_NO_COPY(CCoderMT)

-  CRecordVector<ISequentialInStream*> InStreamPointers;

-  CRecordVector<ISequentialOutStream*> OutStreamPointers;

-

-private:

-  void Execute();

-public:

-  bool EncodeMode;

-  HRESULT Result;

-  CObjectVector< CMyComPtr<ISequentialInStream> > InStreams;

-  CObjectVector< CMyComPtr<ISequentialOutStream> > 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

-  {

-    CLASS_NO_COPY(CReleaser)

-    CCoderMT &_c;

-  public:

-    CReleaser(CCoderMT &c): _c(c) {}

-    ~CReleaser() { _c.Release(); }

-  };

-

-  CCoderMT(): EncodeMode(false) {}

-  ~CCoderMT() { CVirtThread::WaitThreadFinish(); }

-  

-  void Code(ICompressProgressInfo *progress);

-};

-

-

-class CMixerMT:

-  public IUnknown,

-  public CMixer,

-  public CMyUnknownImp

-{

-  CObjectVector<CStreamBinder> _streamBinders;

-

-  HRESULT Init(ISequentialInStream * const *inStreams, ISequentialOutStream * const *outStreams);

-  HRESULT ReturnIfError(HRESULT code);

-

-public:

-  CObjectVector<CCoderMT> _coders;

-

-  MY_UNKNOWN_IMP

-

-  virtual HRESULT SetBindInfo(const CBindInfo &bindInfo);

-  virtual void AddCoder(const CCreatedCoder &cod);

-  virtual CCoder &GetCoder(unsigned index);

-  virtual void SelectMainCoder(bool useFirst);

-  virtual void ReInit();

-  virtual void SetCoderInfo(unsigned coderIndex, const UInt64 *unpackSize, const UInt64 * const *packSizes, bool finish)

-    { _coders[coderIndex].SetCoderInfo(unpackSize, packSizes, finish); }

-  virtual HRESULT Code(

-      ISequentialInStream * const *inStreams,

-      ISequentialOutStream * const *outStreams,

-      ICompressProgressInfo *progress,

-      bool &dataAfterEnd_Error);

-  virtual UInt64 GetBondStreamSize(unsigned bondIndex) const;

-

-  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<ISequentialInStream> _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<ISequentialOutStream> _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<CCoderStreamsInfo> Coders;
+  CRecordVector<CBond> Bonds;
+  CRecordVector<UInt32> 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<UInt32> Coder_to_Stream;
+  CRecordVector<UInt32> 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<ICompressCoder> Coder;
+  CMyComPtr<ICompressCoder2> Coder2;
+  UInt32 NumStreams;
+  bool Finish;
+
+  UInt64 UnpackSize;
+  const UInt64 *UnpackSizePointer;
+
+  CRecordVector<UInt64> PackSizes;
+  CRecordVector<const UInt64 *> 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<IUnknown> 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<CCoderST> _coders;
+  
+  CObjectVector<CStBinderStream> _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<ISequentialInStream*> InStreamPointers;
+  CRecordVector<ISequentialOutStream*> OutStreamPointers;
+
+private:
+  virtual void Execute() Z7_override;
+public:
+  bool EncodeMode;
+  HRESULT Result;
+  CObjectVector< CMyComPtr<ISequentialInStream> > InStreams;
+  CObjectVector< CMyComPtr<ISequentialOutStream> > 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<CStreamBinder> _streamBinders;
+
+  HRESULT Init(ISequentialInStream * const *inStreams, ISequentialOutStream * const *outStreams);
+  HRESULT ReturnIfError(HRESULT code);
+
+  // virtual ~CMixerMT() {}
+public:
+  CObjectVector<CCoderMT> _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 c7d45e7..f48c32f 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"

-

-STDMETHODIMP 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 30e84c5..f884e13 100644
--- a/CPP/7zip/Archive/Common/DummyOutStream.h
+++ b/CPP/7zip/Archive/Common/DummyOutStream.h
@@ -1,25 +1,23 @@
-// DummyOutStream.h

-

-#ifndef __DUMMY_OUT_STREAM_H

-#define __DUMMY_OUT_STREAM_H

-

-#include "../../../Common/MyCom.h"

-

-#include "../../IStream.h"

-

-class CDummyOutStream:

-  public ISequentialOutStream,

-  public CMyUnknownImp

-{

-  CMyComPtr<ISequentialOutStream> _stream;

-  UInt64 _size;

-public:

-  void SetStream(ISequentialOutStream *outStream) { _stream = outStream; }

-  void ReleaseStream() { _stream.Release(); }

-  void Init() { _size = 0; }

-  MY_UNKNOWN_IMP

-  STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);

-  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<ISequentialOutStream> _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
new file mode 100644
index 0000000..6c6740f
--- /dev/null
+++ b/CPP/7zip/Archive/Common/FindSignature.cpp
@@ -0,0 +1,62 @@
+// FindSignature.cpp
+
+#include "StdAfx.h"
+
+#include <string.h>
+
+#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 UInt32 kBufferSize = (1 << 16);
+  CByteBuffer byteBuffer(kBufferSize);
+  Byte *buffer = byteBuffer;
+  UInt32 numPrevBytes = signatureSize - 1;
+  memcpy(buffer, (const Byte *)byteBuffer2 + 1, numPrevBytes);
+  resPos = 1;
+  for (;;)
+  {
+    if (limit)
+      if (resPos > *limit)
+        return S_FALSE;
+    do
+    {
+      const UInt32 numReadBytes = kBufferSize - numPrevBytes;
+      UInt32 processedSize;
+      RINOK(stream->Read(buffer + numPrevBytes, numReadBytes, &processedSize))
+      numPrevBytes += processedSize;
+      if (processedSize == 0)
+        return S_FALSE;
+    }
+    while (numPrevBytes < signatureSize);
+    const UInt32 numTests = numPrevBytes - signatureSize + 1;
+    for (UInt32 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);
+  }
+}
diff --git a/CPP/7zip/Archive/Common/FindSignature.h b/CPP/7zip/Archive/Common/FindSignature.h
new file mode 100644
index 0000000..f0e6cdd
--- /dev/null
+++ b/CPP/7zip/Archive/Common/FindSignature.h
@@ -0,0 +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
diff --git a/CPP/7zip/Archive/Common/HandlerOut.cpp b/CPP/7zip/Archive/Common/HandlerOut.cpp
index 41762d9..17fed67 100644
--- a/CPP/7zip/Archive/Common/HandlerOut.cpp
+++ b/CPP/7zip/Archive/Common/HandlerOut.cpp
@@ -1,232 +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;

-

-  const wchar_t *end;

-  UInt64 v = ConvertStringToUInt64(s, &end);

-  if (s == end)

-    return false;

-  wchar_t c = *end;

-  if (c == 0)

-  {

-    res = v;

-    return true;

-  }

-  if (end[1] != 0)

-    return false;

-

-  if (c == '%')

-  {

-    res = percentsBase / 100 * 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;

-  }

-  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 _7ZIP_ST

-    hres = ParseMtProp(name.Ptr(2), value, _numProcessors, _numThreads);

-    #endif

-    return true;

-  }

-  

-  if (name.IsPrefixedBy_Ascii_NoCase("memuse"))

-  {

-    if (!ParseSizeString(name.Ptr(6), value, _memAvail, _memUsage))

-      hres = E_INVALIDARG;

-    return true;

-  }

-

-  return false;

-}

-

-

-#ifndef EXTRACT_ONLY

-

-static void SetMethodProp32(COneMethodInfo &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 _7ZIP_ST

-void CMultiMethodProps::SetMethodThreadsTo(COneMethodInfo &oneMethodInfo, UInt32 numThreads)

-{

-  SetMethodProp32(oneMethodInfo, NCoderPropID::kNumThreads, numThreads);

-}

-#endif

-

-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;

-  unsigned index = ParseStringToUInt32(name, number);

-  UString realName = name.Ptr(index);

-  if (index == 0)

-  {

-    if (name.IsEqualTo("f"))

-    {

-      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_FAIL;

-  for (int j = _methods.Size(); j <= (int)number; j++)

-    _methods.Add(COneMethodInfo());

-  return _methods[number].ParseMethodFromPROPVARIANT(realName, value);

-}

-

-

-

-void CSingleMethodProps::Init()

-{

-  InitCommon();

-  InitSingle();

-  Clear();

-}

-

-

-HRESULT CSingleMethodProps::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 &value = values[i];

-    if (name[0] == L'x')

-    {

-      UInt32 a = 9;

-      RINOK(ParsePropToUInt32(name.Ptr(1), value, a));

-      _level = a;

-      AddProp_Level(a);

-      continue;

-    }

-    {

-      HRESULT hres;

-      if (SetCommonProperty(name, value, hres))

-      {

-        RINOK(hres)

-        continue;

-      }

-    }

-    RINOK(ParseMethodFromPROPVARIANT(names[i], value));

-  }

-

-  return S_OK;

-}

-

-#endif

-

-}

+// 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 90b000a..cfba46e 100644
--- a/CPP/7zip/Archive/Common/HandlerOut.h
+++ b/CPP/7zip/Archive/Common/HandlerOut.h
@@ -1,110 +1,154 @@
-// HandlerOut.h

-

-#ifndef __HANDLER_OUT_H

-#define __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()

-  {

-    #ifndef _7ZIP_ST

-    _numProcessors = _numThreads = NWindows::NSystem::GetNumberOfProcessors();

-    #endif

-

-    UInt64 memAvail = (UInt64)(sizeof(size_t)) << 28;

-    _memAvail = memAvail;

-    _memUsage = memAvail;

-    if (NWindows::NSystem::GetRamSize(memAvail))

-    {

-      _memAvail = memAvail;

-      _memUsage = memAvail / 32 * 17;

-    }

-  }

-

-public:

-  #ifndef _7ZIP_ST

-  UInt32 _numThreads;

-  UInt32 _numProcessors;

-  #endif

-

-  UInt64 _memUsage;

-  UInt64 _memAvail;

-

-  bool SetCommonProperty(const UString &name, const PROPVARIANT &value, HRESULT &hres);

-

-  CCommonMethodProps() { InitCommon(); }

-};

-

-

-#ifndef EXTRACT_ONLY

-

-class CMultiMethodProps: public CCommonMethodProps

-{

-  UInt32 _level;

-  int _analysisLevel;

-

-  void InitMulti();

-public:

-  UInt32 _crcSize;

-  CObjectVector<COneMethodInfo> _methods;

-  COneMethodInfo _filterMethod;

-  bool _autoFilter;

-

-  

-  void SetGlobalLevelTo(COneMethodInfo &oneMethodInfo) const;

-

-  #ifndef _7ZIP_ST

-  static void SetMethodThreadsTo(COneMethodInfo &oneMethodInfo, 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 SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps);

-};

-

-#endif

-

-}

-

-#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
+
+    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<COneMethodInfo> _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 cddc083..735d5d1 100644
--- a/CPP/7zip/Archive/Common/InStreamWithCRC.cpp
+++ b/CPP/7zip/Archive/Common/InStreamWithCRC.cpp
@@ -1,46 +1,57 @@
-// InStreamWithCRC.cpp

-

-#include "StdAfx.h"

-

-#include "InStreamWithCRC.h"

-

-STDMETHODIMP CSequentialInStreamWithCRC::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;

-}

-

-STDMETHODIMP 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;

-}

-

-STDMETHODIMP 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 1a4b2c9..2a91d76 100644
--- a/CPP/7zip/Archive/Common/InStreamWithCRC.h
+++ b/CPP/7zip/Archive/Common/InStreamWithCRC.h
@@ -1,67 +1,67 @@
-// InStreamWithCRC.h

-

-#ifndef __IN_STREAM_WITH_CRC_H

-#define __IN_STREAM_WITH_CRC_H

-

-#include "../../../../C/7zCrc.h"

-

-#include "../../../Common/MyCom.h"

-

-#include "../../IStream.h"

-

-class CSequentialInStreamWithCRC:

-  public ISequentialInStream,

-  public CMyUnknownImp

-{

-public:

-  MY_UNKNOWN_IMP

-

-  STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);

-private:

-  CMyComPtr<ISequentialInStream> _stream;

-  UInt64 _size;

-  UInt32 _crc;

-  bool _wasFinished;

-public:

-  void SetStream(ISequentialInStream *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; }

-};

-

-class CInStreamWithCRC:

-  public IInStream,

-  public CMyUnknownImp

-{

-public:

-  MY_UNKNOWN_IMP1(IInStream)

-

-  STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);

-  STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);

-private:

-  CMyComPtr<IInStream> _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<ISequentialInStream> _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_COM_1(
+  CInStreamWithCRC,
+  IInStream
+)
+  Z7_IFACE_COM7_IMP(ISequentialInStream)
+
+  CMyComPtr<IInStream> _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 e0c35a9..8caf1d1 100644
--- a/CPP/7zip/Archive/Common/ItemNameUtils.cpp
+++ b/CPP/7zip/Archive/Common/ItemNameUtils.cpp
@@ -1,88 +1,135 @@
-// Archive/Common/ItemNameUtils.cpp

-

-#include "StdAfx.h"

-

-#include "ItemNameUtils.h"

-

-namespace NArchive {

-namespace NItemName {

-

-static const wchar_t kOsPathSepar = WCHAR_PATH_SEPARATOR;

-static const wchar_t kUnixPathSepar = L'/';

-

-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)

-{

-  if (!name.IsEmpty())

-  {

-    #if WCHAR_PATH_SEPARATOR != L'/'

-      name.Replace(kUnixPathSepar, kOsPathSepar);

-    #endif

-    

-    if (name.Back() == kOsPathSepar)

-      name.DeleteBack();

-  }

-}

-

-

-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)

-      *CharPrevExA((WORD)codePage, name, name.Ptr(name.Len()), 0);

-    #else

-      name.Back();

-    #endif

-  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 404fce4..8ab9b61 100644
--- a/CPP/7zip/Archive/Common/ItemNameUtils.h
+++ b/CPP/7zip/Archive/Common/ItemNameUtils.h
@@ -1,28 +1,30 @@
-// Archive/Common/ItemNameUtils.h

-

-#ifndef __ARCHIVE_ITEM_NAME_UTILS_H

-#define __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 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 39d1521..5d357af 100644
--- a/CPP/7zip/Archive/Common/MultiStream.cpp
+++ b/CPP/7zip/Archive/Common/MultiStream.cpp
@@ -1,191 +1,193 @@
-// MultiStream.cpp

-

-#include "StdAfx.h"

-

-#include "MultiStream.h"

-

-STDMETHODIMP 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

-      {

-        _streamIndex = mid;

-        break;

-      }

-      mid = (left + right) / 2;

-    }

-    _streamIndex = mid;

-  }

-  

-  CSubStreamInfo &s = Streams[_streamIndex];

-  UInt64 localPos = _pos - s.GlobalOffset;

-  if (localPos != s.LocalPos)

-  {

-    RINOK(s.Stream->Seek(localPos, STREAM_SEEK_SET, &s.LocalPos));

-  }

-  UInt64 rem = s.Size - localPos;

-  if (size > rem)

-    size = (UInt32)rem;

-  HRESULT result = s.Stream->Read(data, size, &size);

-  _pos += size;

-  s.LocalPos += size;

-  if (processedSize)

-    *processedSize = size;

-  return result;

-}

-  

-STDMETHODIMP 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 = offset;

-  if (newPosition)

-    *newPosition = offset;

-  return S_OK;

-}

-

-

-/*

-class COutVolumeStream:

-  public ISequentialOutStream,

-  public CMyUnknownImp

-{

-  unsigned _volIndex;

-  UInt64 _volSize;

-  UInt64 _curPos;

-  CMyComPtr<ISequentialOutStream> _volumeStream;

-  COutArchive _archive;

-  CCRC _crc;

-

-public:

-  MY_UNKNOWN_IMP

-

-  CFileItem _file;

-  CUpdateOptions _options;

-  CMyComPtr<IArchiveUpdateCallback2> 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();

-  STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);

-};

-

-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;

-}

-*/

-

-/*

-STDMETHODIMP 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<IOutStream> outStream;

-      RINOK(subStream.Stream.QueryInterface(IID_IOutStream, &outStream));

-      RINOK(outStream->Seek(_offsetPos, STREAM_SEEK_SET, NULL));

-      subStream.Pos = _offsetPos;

-    }

-

-    UInt32 curSize = (UInt32)MyMin((UInt64)size, subStream.Size - subStream.Pos);

-    UInt32 realProcessed;

-    RINOK(subStream.Stream->Write(data, curSize, &realProcessed));

-    data = (void *)((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;

-}

-

-STDMETHODIMP 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 = offset;

-  _offsetPos = _absPos;

-  _streamIndex = 0;

-  if (newPosition)

-    *newPosition = 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<ISequentialOutStream> _volumeStream;
+  COutArchive _archive;
+  CCRC _crc;
+
+public:
+  CFileItem _file;
+  CUpdateOptions _options;
+  CMyComPtr<IArchiveUpdateCallback2> 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<IOutStream> 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 39e041d..e3096f5 100644
--- a/CPP/7zip/Archive/Common/MultiStream.h
+++ b/CPP/7zip/Archive/Common/MultiStream.h
@@ -1,89 +1,88 @@
-// MultiStream.h

-

-#ifndef __MULTI_STREAM_H

-#define __MULTI_STREAM_H

-

-#include "../../../Common/MyCom.h"

-#include "../../../Common/MyVector.h"

-

-#include "../../IStream.h"

-

-class CMultiStream:

-  public IInStream,

-  public CMyUnknownImp

-{

-  UInt64 _pos;

-  UInt64 _totalLength;

-  unsigned _streamIndex;

-

-public:

-

-  struct CSubStreamInfo

-  {

-    CMyComPtr<IInStream> Stream;

-    UInt64 Size;

-    UInt64 GlobalOffset;

-    UInt64 LocalPos;

-

-    CSubStreamInfo(): Size(0), GlobalOffset(0), LocalPos(0) {}

-  };

-  

-  CObjectVector<CSubStreamInfo> Streams;

-  

-  HRESULT Init()

-  {

-    UInt64 total = 0;

-    FOR_VECTOR (i, Streams)

-    {

-      CSubStreamInfo &s = Streams[i];

-      s.GlobalOffset = total;

-      total += Streams[i].Size;

-      RINOK(s.Stream->Seek(0, STREAM_SEEK_CUR, &s.LocalPos));

-    }

-    _totalLength = total;

-    _pos = 0;

-    _streamIndex = 0;

-    return S_OK;

-  }

-

-  MY_UNKNOWN_IMP1(IInStream)

-

-  STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);

-  STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);

-};

-

-/*

-class COutMultiStream:

-  public IOutStream,

-  public CMyUnknownImp

-{

-  unsigned _streamIndex; // required stream

-  UInt64 _offsetPos; // offset from start of _streamIndex index

-  UInt64 _absPos;

-  UInt64 _length;

-

-  struct CSubStreamInfo

-  {

-    CMyComPtr<ISequentialOutStream> Stream;

-    UInt64 Size;

-    UInt64 Pos;

- };

-  CObjectVector<CSubStreamInfo> Streams;

-public:

-  CMyComPtr<IArchiveUpdateCallback2> VolumeCallback;

-  void Init()

-  {

-    _streamIndex = 0;

-    _offsetPos = 0;

-    _absPos = 0;

-    _length = 0;

-  }

-

-  MY_UNKNOWN_IMP1(IOutStream)

-

-  STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);

-  STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);

-};

-*/

-

-#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_COM_1(
+  CMultiStream
+  , IInStream
+)
+  Z7_IFACE_COM7_IMP(ISequentialInStream)
+
+  unsigned _streamIndex;
+  UInt64 _pos;
+  UInt64 _totalLength;
+
+public:
+
+  struct CSubStreamInfo
+  {
+    CMyComPtr<IInStream> Stream;
+    UInt64 Size;
+    UInt64 GlobalOffset;
+    UInt64 LocalPos;
+    CSubStreamInfo(): Size(0), GlobalOffset(0), LocalPos(0) {}
+  };
+
+  CMyComPtr<IArchiveUpdateCallbackFile> updateCallbackFile;
+  CObjectVector<CSubStreamInfo> 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<ISequentialOutStream> Stream;
+    UInt64 Size;
+    UInt64 Pos;
+ };
+  CObjectVector<CSubStreamInfo> Streams;
+public:
+  CMyComPtr<IArchiveUpdateCallback2> 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 e0d3894..7dcd44a 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"

-

-STDMETHODIMP 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 != NULL)

-    *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 0cc9a85..845146a 100644
--- a/CPP/7zip/Archive/Common/OutStreamWithCRC.h
+++ b/CPP/7zip/Archive/Common/OutStreamWithCRC.h
@@ -1,37 +1,35 @@
-// OutStreamWithCRC.h

-

-#ifndef __OUT_STREAM_WITH_CRC_H

-#define __OUT_STREAM_WITH_CRC_H

-

-#include "../../../../C/7zCrc.h"

-

-#include "../../../Common/MyCom.h"

-

-#include "../../IStream.h"

-

-class COutStreamWithCRC:

-  public ISequentialOutStream,

-  public CMyUnknownImp

-{

-  CMyComPtr<ISequentialOutStream> _stream;

-  UInt64 _size;

-  UInt32 _crc;

-  bool _calculate;

-public:

-  MY_UNKNOWN_IMP

-  STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);

-  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<ISequentialOutStream> _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
new file mode 100644
index 0000000..57c18ec
--- /dev/null
+++ b/CPP/7zip/Archive/Common/OutStreamWithSha1.cpp
@@ -0,0 +1,18 @@
+// 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;
+}
diff --git a/CPP/7zip/Archive/Common/OutStreamWithSha1.h b/CPP/7zip/Archive/Common/OutStreamWithSha1.h
new file mode 100644
index 0000000..74bc53c
--- /dev/null
+++ b/CPP/7zip/Archive/Common/OutStreamWithSha1.h
@@ -0,0 +1,39 @@
+// 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
+)
+  CMyComPtr<ISequentialOutStream> _stream;
+  UInt64 _size;
+  // CSha1 _sha;
+  bool _calculate;
+  CAlignedBuffer1 _sha;
+
+  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)
+  {
+    _size = 0;
+    _calculate = calculate;
+    Sha1_Init(Sha());
+  }
+  void InitSha1() { Sha1_Init(Sha()); }
+  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 0fe89b3..63e4f3e 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 f4367a7..4ec2e48 100644
--- a/CPP/7zip/Archive/Common/ParseProperties.h
+++ b/CPP/7zip/Archive/Common/ParseProperties.h
@@ -1,6 +1,6 @@
-// ParseProperties.h

-

-#ifndef __PARSE_PROPERTIES_H

-#define __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 59d9ac1..035267c 100644
--- a/CPP/7zip/Archive/Common/StdAfx.h
+++ b/CPP/7zip/Archive/Common/StdAfx.h
@@ -1,8 +1,11 @@
-// StdAfx.h

-

-#ifndef __STDAFX_H

-#define __STDAFX_H

-

-#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
new file mode 100644
index 0000000..872cea7
--- /dev/null
+++ b/CPP/7zip/Archive/CpioHandler.cpp
@@ -0,0 +1,1099 @@
+// 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;
+
+// #define MAGIC_ASCII { '0', '7', '0', '7', '0' }
+
+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 Byte c = p[i];
+    if (c < '0' || c > '7')
+      return false;
+  }
+  return true;
+}
+
+static bool CheckHexRecord(const Byte *p)
+{
+  for (unsigned i = 6; i < k_HexRecord_Size; i++)
+  {
+    const Byte c = p[i];
+    if ((c < '0' || c > '9') &&
+        (c < 'A' || c > 'F') &&
+        (c < 'a' || c > 'f'))
+      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;
+
+  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;
+
+  if (item.RDevMinor != 0 ||
+      item.RDevMajor != 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<CItem> _items;
+  CMyComPtr<IInStream> _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<CItem> &items = *(const CObjectVector<CItem> *)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<ISequentialOutStream> _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 = 0;
+  }
+  void EnableCalc(bool calculate) { _calculate = calculate; }
+  void InitCRC() { _crc = 0; }
+  UInt64 GetSize() const { return _size; }
+  UInt32 GetCRC() const { return _crc; }
+};
+
+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 (_calculate)
+  {
+    UInt32 crc = 0;
+    for (UInt32 i = 0; i < size; i++)
+      crc += (UInt32)(((const Byte *)data)[i]);
+    _crc += crc;
+  }
+  if (processedSize)
+    *processedSize = size;
+  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))
+
+  NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+  CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> progress = lps;
+  lps->Init(extractCallback, false);
+
+  CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+  CMyComPtr<ISequentialInStream> inStream(streamSpec);
+  streamSpec->SetStream(_stream);
+
+  COutStreamWithSum *outStreamSumSpec = new COutStreamWithSum;
+  CMyComPtr<ISequentialOutStream> outStreamSum(outStreamSumSpec);
+
+  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;
+    CMyComPtr<ISequentialOutStream> outStream;
+    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];
+    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;
+    outStreamSumSpec->Init(item.IsCrcFormat());
+    outStreamSumSpec->SetStream(outStream);
+    outStream.Release();
+
+    RINOK(extractCallback->PrepareOperation(askMode))
+    RINOK(InStream_SeekSet(_stream, item.GetDataPosition()))
+    streamSpec->Init(item.Size);
+    RINOK(copyCoder->Code(inStream, outStreamSum, NULL, NULL, progress))
+    outStreamSumSpec->ReleaseStream();
+    Int32 res = NExtract::NOperationResult::kDataError;
+    if (copyCoderSpec->TotalSize == item.Size)
+    {
+      res = NExtract::NOperationResult::kOK;
+      if (item.IsCrcFormat() && item.ChkSum != outStreamSumSpec->GetCRC())
+        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
new file mode 100644
index 0000000..fd83f71
--- /dev/null
+++ b/CPP/7zip/Archive/CramfsHandler.cpp
@@ -0,0 +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<CItem> _items;
+  CMyComPtr<IInStream> _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<ICompressCoder> _zlibDecoder;
+
+  CBufInStream *_inStreamSpec;
+  CMyComPtr<ISequentialInStream> _inStream;
+
+  CBufPtrSeqOutStream *_outStreamSpec;
+  CMyComPtr<ISequentialOutStream> _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<ICompressCoder> copyCoder = copyCoderSpec;
+
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> progress = lps;
+  lps->Init(extractCallback, false);
+
+  for (i = 0; i < numItems; i++)
+  {
+    lps->InSize = totalPackSize;
+    lps->OutSize = totalSize;
+    RINOK(lps->SetCur())
+    CMyComPtr<ISequentialOutStream> 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<ISequentialInStream> 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<IInStream> 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<IInStream> 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
new file mode 100644
index 0000000..ca3dc6f
--- /dev/null
+++ b/CPP/7zip/Archive/DeflateProps.cpp
@@ -0,0 +1,3 @@
+// DeflateProps.cpp
+
+#include "StdAfx.h"
diff --git a/CPP/7zip/Archive/DeflateProps.h b/CPP/7zip/Archive/DeflateProps.h
new file mode 100644
index 0000000..666fb39
--- /dev/null
+++ b/CPP/7zip/Archive/DeflateProps.h
@@ -0,0 +1,6 @@
+// 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
new file mode 100644
index 0000000..9def208
--- /dev/null
+++ b/CPP/7zip/Archive/DllExports.cpp
@@ -0,0 +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
diff --git a/CPP/7zip/Archive/DllExports2.cpp b/CPP/7zip/Archive/DllExports2.cpp
index c43e72a..ae8d8ac 100644
--- a/CPP/7zip/Archive/DllExports2.cpp
+++ b/CPP/7zip/Archive/DllExports2.cpp
@@ -1,122 +1,175 @@
-// DLLExports2.cpp

-

-#include "StdAfx.h"

-

-#include "../../Common/MyWindows.h"

-

-#include "../../Common/MyInitGuid.h"

-

-#if defined(_7ZIP_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"

-

-HINSTANCE g_hInstance;

-

-#define NT_CHECK_FAIL_ACTION return FALSE;

-

-#ifdef _WIN32

-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;

-}

-#endif

-

-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)

-{

-  // COM_TRY_BEGIN

-  *outObject = 0;

-  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()

-{

-  #if defined(_7ZIP_LARGE_PAGES)

-  SetLargePageSize();

-  #endif

-  return S_OK;

-}

-

-extern bool g_CaseSensitive;

-

-STDAPI SetCaseSensitive(Int32 caseSensitive)

-{

-  g_CaseSensitive = (caseSensitive != 0);

-  return S_OK;

-}

-

-#ifdef 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

+// 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 <stdio.h>
+
+// 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
new file mode 100644
index 0000000..4bcb904
--- /dev/null
+++ b/CPP/7zip/Archive/DmgHandler.cpp
@@ -0,0 +1,1771 @@
+// DmgHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "../../Common/ComTry.h"
+#include "../../Common/IntToString.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/ZlibDecoder.h"
+
+#include "Common/OutStreamWithCRC.h"
+
+// #define DMG_SHOW_RAW
+
+// #include <stdio.h>
+#define PRF(x) // x
+
+#define Get16(p) GetBe16(p)
+#define Get32(p) GetBe32(p)
+#define Get64(p) GetBe64(p)
+
+Byte *Base64ToBin(Byte *dest, const char *src);
+
+namespace NArchive {
+namespace NDmg {
+
+
+static const UInt32  METHOD_ZERO_0  = 0;
+static const UInt32  METHOD_COPY    = 1;
+static const UInt32  METHOD_ZERO_2  = 2; // 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_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;
+  
+  UInt64 GetNextPackOffset() const { return PackPos + PackSize; }
+  UInt64 GetNextUnpPos() const { return UnpPos + UnpSize; }
+
+  bool IsZeroMethod() const { return Type == METHOD_ZERO_0 || Type == METHOD_ZERO_2; }
+  bool ThereAreDataInBlock() const { return Type != METHOD_COMMENT && Type != METHOD_END; }
+};
+
+static const UInt32 kCheckSumType_CRC = 2;
+
+static const size_t 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 CChecksum::Parse(const Byte *p)
+{
+  Type = Get32(p);
+  NumBits = Get32(p + 4);
+  memcpy(Data, p + 8, kChecksumSize_Max);
+}
+
+struct CFile
+{
+  UInt64 Size;
+  UInt64 PackSize;
+  UInt64 StartPos;
+  AString Name;
+  CRecordVector<CBlock> Blocks;
+  CChecksum Checksum;
+  bool FullFileChecksum;
+
+  HRESULT Parse(const Byte *p, UInt32 size);
+};
+
+#ifdef DMG_SHOW_RAW
+struct CExtraFile
+{
+  CByteBuffer Data;
+  AString Name;
+};
+#endif
+
+
+struct CForkPair
+{
+  UInt64 Offset;
+  UInt64 Len;
+  
+  void Parse(const Byte *p)
+  {
+    Offset = Get64(p);
+    Len = Get64(p + 8);
+  }
+
+  bool UpdateTop(UInt64 limit, UInt64 &top)
+  {
+    if (Offset > limit || Len > limit - Offset)
+      return false;
+    UInt64 top2 = Offset + Len;
+    if (top <= top2)
+      top = top2;
+    return true;
+  }
+};
+
+
+Z7_CLASS_IMP_CHandler_IInArchive_1(
+  IInArchiveGetStream
+)
+  CMyComPtr<IInStream> _inStream;
+  CObjectVector<CFile> _files;
+  bool _masterCrcError;
+  bool _headersError;
+
+  UInt32 _dataStartOffset;
+  UInt64 _startPos;
+  UInt64 _phySize;
+
+  AString _name;
+  
+  #ifdef DMG_SHOW_RAW
+  CObjectVector<CExtraFile> _extras;
+  #endif
+
+  HRESULT ReadData(IInStream *stream, const CForkPair &pair, CByteBuffer &buf);
+  bool ParseBlob(const CByteBuffer &data);
+  HRESULT Open2(IInStream *stream);
+  HRESULT Extract(IInStream *stream);
+};
+
+// that limit can be increased, if there are such dmg files
+static const size_t kXmlSizeMax = 0xFFFF0000; // 4 GB - 64 KB;
+
+struct CMethods
+{
+  CRecordVector<UInt32> Types;
+  CRecordVector<UInt32> ChecksumTypes;
+
+  void Update(const CFile &file);
+  void GetString(AString &s) const;
+};
+
+void CMethods::Update(const CFile &file)
+{
+  ChecksumTypes.AddToUniqueSorted(file.Checksum.Type);
+  FOR_VECTOR (i, file.Blocks)
+    Types.AddToUniqueSorted(file.Blocks[i].Type);
+}
+
+void CMethods::GetString(AString &res) const
+{
+  res.Empty();
+
+  unsigned i;
+  
+  for (i = 0; i < Types.Size(); i++)
+  {
+    const UInt32 type = Types[i];
+    if (type == METHOD_COMMENT || type == METHOD_END)
+      continue;
+    char buf[16];
+    const char *s;
+    switch (type)
+    {
+      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;
+      default: ConvertUInt32ToString(type, buf); s = buf;
+    }
+    res.Add_OptSpaced(s);
+  }
+  
+  for (i = 0; i < ChecksumTypes.Size(); i++)
+  {
+    res.Add_Space_if_NotEmpty();
+    UInt32 type = ChecksumTypes[i];
+    switch (type)
+    {
+      case kCheckSumType_CRC: res += "CRC"; break;
+      default:
+        res += "Check";
+        res.Add_UInt32(type);
+    }
+  }
+}
+
+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" },
+
+  // 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 " },
+  { false, NULL,   "MBR" },
+  { false, NULL,   "Driver" },
+  { false, NULL,   "Patches" }
+};
+  
+static const unsigned kNumAppleNames = Z7_ARRAY_SIZE(k_Names);
+
+static const Byte kProps[] =
+{
+  kpidPath,
+  kpidSize,
+  kpidPackSize,
+  kpidCRC,
+  kpidComment,
+  kpidMethod
+  // kpidOffset
+};
+
+IMP_IInArchive_Props
+
+static const Byte kArcProps[] =
+{
+  kpidMethod,
+  kpidNumBlocks,
+  kpidComment
+};
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+  COM_TRY_BEGIN
+  NWindows::NCOM::CPropVariant prop;
+  switch (propID)
+  {
+    case kpidMethod:
+    {
+      CMethods m;
+      FOR_VECTOR (i, _files)
+        m.Update(_files[i]);
+      AString s;
+      m.GetString(s);
+      if (!s.IsEmpty())
+        prop = s;
+      break;
+    }
+    case kpidNumBlocks:
+    {
+      UInt64 numBlocks = 0;
+      FOR_VECTOR (i, _files)
+        numBlocks += _files[i].Blocks.Size();
+      prop = numBlocks;
+      break;
+    }
+    case kpidMainSubfile:
+    {
+      int mainIndex = -1;
+      unsigned numFS = 0;
+      unsigned numUnknown = 0;
+      FOR_VECTOR (i, _files)
+      {
+        const AString &name = _files[i].Name;
+        unsigned n;
+        for (n = 0; n < kNumAppleNames; n++)
+        {
+          const CAppleName &appleName = k_Names[n];
+          // if (name.Find(appleName.AppleName) >= 0)
+          if (strstr(name, appleName.AppleName))
+          {
+            if (appleName.IsFs)
+            {
+              numFS++;
+              mainIndex = (int)i;
+            }
+            break;
+          }
+        }
+        if (n == kNumAppleNames)
+        {
+          mainIndex = (int)i;
+          numUnknown++;
+        }
+      }
+      if (numFS + numUnknown == 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 (v != 0)
+        prop = v;
+      break;
+    }
+
+    case kpidOffset: prop = _startPos; break;
+    case kpidPhySize: prop = _phySize; break;
+
+    case kpidComment:
+      if (!_name.IsEmpty() && _name.Len() < 256)
+        prop = _name;
+      break;
+
+    case kpidName:
+      if (!_name.IsEmpty() && _name.Len() < 256)
+      {
+        prop = _name + ".dmg";
+      }
+      break;
+  }
+  prop.Detach(value);
+  return S_OK;
+  COM_TRY_END
+}
+
+IMP_IInArchive_ArcProps
+
+HRESULT CFile::Parse(const Byte *p, UInt32 size)
+{
+  const UInt32 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;
+  // UInt64 firstSectorNumber = Get64(p + 8);
+  UInt64 numSectors = Get64(p + 0x10);
+
+  StartPos = Get64(p + 0x18);
+
+  // UInt32 decompressedBufRequested = Get32(p + 0x20); // ???
+  // UInt32 blocksDescriptor = Get32(p + 0x24); // number starting from -1?
+  // char Reserved1[24];
+  
+  Checksum.Parse(p + 0x40);
+  PRF(printf("\n\nChecksum Type = %2d", Checksum.Type));
+
+  UInt32 numBlocks = Get32(p + 0xC8);
+  if (numBlocks > ((UInt32)1 << 28))
+    return S_FALSE;
+
+  const UInt32 kRecordSize = 40;
+  if (numBlocks * kRecordSize + kHeadSize != size)
+    return S_FALSE;
+
+  PackSize = 0;
+  Size = 0;
+  Blocks.ClearAndReserve(numBlocks);
+  FullFileChecksum = true;
+
+  p += kHeadSize;
+  UInt32 i;
+ 
+  for (i = 0; i < numBlocks; i++, p += kRecordSize)
+  {
+    CBlock b;
+    b.Type = Get32(p);
+    b.UnpPos   = Get64(p + 0x08) << 9;
+    b.UnpSize  = Get64(p + 0x10) << 9;
+    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 (!Blocks.IsEmpty())
+      if (b.UnpPos != Blocks.Back().GetNextUnpPos())
+        return S_FALSE;
+    
+    PRF(printf("\nType=%8x  m[1]=%8x  uPos=%8x  uSize=%7x  pPos=%8x  pSize=%7x",
+        b.Type, Get32(p + 4), (UInt32)b.UnpPos, (UInt32)b.UnpSize, (UInt32)b.PackPos, (UInt32)b.PackSize));
+    
+    if (b.Type == METHOD_COMMENT)
+      continue;
+    if (b.Type == METHOD_END)
+      break;
+    PackSize += b.PackSize;
+  
+    if (b.UnpSize != 0)
+    {
+      if (b.Type == METHOD_ZERO_2)
+        FullFileChecksum = false;
+      Blocks.AddInReserved(b);
+    }
+  }
+  
+  if (i != numBlocks - 1)
+    return S_FALSE;
+  if (!Blocks.IsEmpty())
+    Size = Blocks.Back().GetNextUnpPos();
+  if (Size != (numSectors << 9))
+    return S_FALSE;
+  
+  return S_OK;
+}
+
+static int 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 && item.SubItems[i + 1].IsTagged(nextTag))
+      return (int)(i + 1);
+  }
+  return -1;
+}
+
+static const AString *GetStringFromKeyPair(const CXmlItem &item, const char *key, const char *nextTag)
+{
+  int index = FindKeyPair(item, key, nextTag);
+  if (index >= 0)
+    return item.SubItems[index].GetSubStringPtr();
+  return NULL;
+}
+
+static const unsigned HEADER_SIZE = 0x200;
+
+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)
+{
+  if (data.Size() < 12)
+    return false;
+  const Byte *p = (const Byte *)data;
+  if (Get32(p) != 0xFADE0CC0)
+    return true;
+  const UInt32 size = Get32(p + 4);
+  if (size != data.Size())
+    return false;
+  const UInt32 num = Get32(p + 8);
+  if (num > (size - 12) / 8)
+    return false;
+  
+  for (UInt32 i = 0; i < num; i++)
+  {
+    // UInt32 type = Get32(p + i * 8 + 12);
+    UInt32 offset = Get32(p + i * 8 + 12 + 4);
+    if (size - offset < 8)
+      return false;
+    const Byte *p2 = (const Byte *)data + 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)
+    {
+      #ifdef DMG_SHOW_RAW
+      extra.Name += "codedir";
+      #endif
+    
+      if (len < 11 * 4)
+        return false;
+      UInt32 idOffset = Get32(p2 + 0x14);
+      if (idOffset >= len)
+        return false;
+      UInt32 len2 = len - idOffset;
+      if (len2 < (1 << 10))
+        _name.SetFrom_CalcLen((const char *)(p2 + idOffset), len2);
+    }
+    #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)
+{
+  /*
+  - usual dmg contains Koly Header at the end:
+  - rare case dmg contains Koly Header at the start.
+  */
+
+  _dataStartOffset = 0;
+  UInt64 fileSize;
+  RINOK(InStream_GetPos_GetSize(stream, _startPos, fileSize))
+
+  Byte buf[HEADER_SIZE];
+  RINOK(ReadStream_FALSE(stream, buf, HEADER_SIZE))
+
+  UInt64 headerPos;
+  bool startKolyMode = false;
+
+  if (IsKoly(buf))
+  {
+    // it can be normal koly-at-the-end or koly-at-the-start
+    headerPos = _startPos;
+    if (_startPos <= (1 << 8))
+    {
+      // we want to support startKolyMode, even if there is
+      // some data before dmg file, like 128 bytes MacBin header
+      _dataStartOffset = HEADER_SIZE;
+      startKolyMode = true;
+    }
+  }
+  else
+  {
+    // we check only koly-at-the-end
+    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(buf))
+      return S_FALSE;
+  }
+
+  // UInt32 flags = Get32(buf + 12);
+  // UInt64 runningDataForkOffset = Get64(buf + 0x10);
+  
+  CForkPair dataForkPair, rsrcPair, xmlPair, blobPair;
+  
+  dataForkPair.Parse(buf + 0x18);
+  rsrcPair.Parse(buf + 0x28);
+  xmlPair.Parse(buf + 0xD8);
+  blobPair.Parse(buf + 0x128);
+
+  // UInt32 segmentNumber = Get32(buf + 0x38);
+  // UInt32 segmentCount = Get32(buf + 0x3C);
+  // Byte segmentGUID[16];
+  // CChecksum dataForkChecksum;
+  // dataForkChecksum.Parse(buf + 0x50);
+
+  UInt64 top = 0;
+  UInt64 limit = startKolyMode ? fileSize : headerPos;
+
+  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. */
+
+  bool useBlob = blobPair.UpdateTop(limit, top);
+
+
+  if (startKolyMode)
+    _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 = "<?xml version";
+    const unsigned len = (unsigned)strlen(sz);
+    if (xmlPair2.Len > 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;
+    }
+    }
+  }
+
+  // Byte reserved[0x78]
+
+  if (useBlob && blobPair.Len != 0)
+  {
+    #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;
+  }
+
+
+  CChecksum masterChecksum;
+  masterChecksum.Parse(buf + 0x160);
+
+  // UInt32 imageVariant = Get32(buf + 0x1E8);
+  // UInt64 numSectors = Get64(buf + 0x1EC);
+  // Byte reserved[0x12]
+
+  const UInt32 RSRC_HEAD_SIZE = 0x100;
+
+  // 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 rsrcLen < (1 << 24).
+  bool useRsrc = (rsrcPair.Len > RSRC_HEAD_SIZE && rsrcPair.Len < ((UInt32)1 << 24));
+  // useRsrc = false;
+
+  if (useRsrc)
+  {
+    #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;
+    UInt32 headSize = Get32(p + 0);
+    UInt32 footerOffset = Get32(p + 4);
+    UInt32 mainDataSize = Get32(p + 8);
+    UInt32 footerSize = Get32(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
+      UInt64 rem = rsrcPair.Len - footerOffset;
+      if (rem < footerSize
+          || rem - footerSize != 4
+          || Get32(p + footerEnd) != 0)
+        return S_FALSE;
+    }
+  
+    if (footerSize < 16)
+      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;
+    
+    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 + i * 8;
+    
+      const UInt32 typeId = Get32(p2);
+      
+      #ifndef DMG_SHOW_RAW
+      if (typeId != 0x626C6B78) // 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
+        // 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)
+        {
+          UInt32 namesBlockSize = footerSize - namesOffset;
+          if (namePos >= namesBlockSize)
+            return S_FALSE;
+          const Byte *namePtr = p + namesOffset + namePos;
+          UInt32 nameLen = *namePtr;
+          if (namesBlockSize - namePos <= nameLen)
+            return S_FALSE;
+          for (UInt32 r = 1; r <= nameLen; r++)
+          {
+            Byte c = namePtr[r];
+            if (c < 0x20 || c >= 0x80)
+              break;
+            name += (char)c;
+          }
+        }
+        
+        if (typeId == 0x626C6B78) // blkx
+        {
+          CFile &file = _files.AddNew();
+          file.Name = name;
+          RINOK(file.Parse(pBlock + 4, blockSize))
+        }
+        
+        #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 &extra = _extras.AddNew();
+          extra.Name = name2;
+          extra.Data.CopyFrom(pBlock + 4, blockSize);
+        }
+        #endif
+      }
+    }
+  }
+  else
+  {
+    if (xmlPair.Len >= kXmlSizeMax || xmlPair.Len == 0)
+      return S_FALSE;
+    size_t size = (size_t)xmlPair.Len;
+    if (size != xmlPair.Len)
+      return S_FALSE;
+
+    RINOK(InStream_SeekSet(stream, _startPos + xmlPair.Offset))
+    
+    CXml xml;
+    {
+      CObjArray<char> xmlStr(size + 1);
+      RINOK(ReadStream_FALSE(stream, xmlStr, size))
+      xmlStr[size] = 0;
+      // if (strlen(xmlStr) != size) return S_FALSE;
+      if (!xml.Parse(xmlStr))
+        return S_FALSE;
+
+      #ifdef DMG_SHOW_RAW
+      CExtraFile &extra = _extras.AddNew();
+      extra.Name = "a.xml";
+      extra.Data.CopyFrom((const Byte *)(const char *)xmlStr, size);
+      #endif
+    }
+    
+    if (xml.Root.Name != "plist")
+      return S_FALSE;
+    
+    int dictIndex = xml.Root.FindSubTag("dict");
+    if (dictIndex < 0)
+      return S_FALSE;
+    
+    const CXmlItem &dictItem = xml.Root.SubItems[dictIndex];
+    int rfDictIndex = FindKeyPair(dictItem, "resource-fork", "dict");
+    if (rfDictIndex < 0)
+      return S_FALSE;
+    
+    const CXmlItem &rfDictItem = dictItem.SubItems[rfDictIndex];
+    int arrIndex = FindKeyPair(rfDictItem, "blkx", "array");
+    if (arrIndex < 0)
+      return S_FALSE;
+    
+    const CXmlItem &arrItem = rfDictItem.SubItems[arrIndex];
+    
+    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();
+      {
+        const AString *name = GetStringFromKeyPair(item, "Name", "string");
+        if (!name || name->IsEmpty())
+          name = GetStringFromKeyPair(item, "CFName", "string");
+        if (name)
+          file.Name = *name;
+      }
+      RINOK(file.Parse(rawBuf, destLen))
+    }
+  }
+
+  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;
+      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());
+  }
+
+  return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::Open(IInStream *stream,
+    const UInt64 * /* maxCheckStartPosition */,
+    IArchiveOpenCallback * /* openArchiveCallback */))
+{
+  COM_TRY_BEGIN
+  {
+    Close();
+    if (Open2(stream) != S_OK)
+      return S_FALSE;
+    _inStream = stream;
+  }
+  return S_OK;
+  COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+  _phySize = 0;
+  _inStream.Release();
+  _files.Clear();
+  _masterCrcError = false;
+  _headersError = false;
+  _name.Empty();
+  #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 kpidOffset:
+      {
+        prop = item.StartPos;
+        break;
+      }
+      */
+
+      case kpidMethod:
+      {
+        CMethods m;
+        m.Update(item);
+        AString s;
+        m.GetString(s);
+        if (!s.IsEmpty())
+          prop = s;
+        break;
+      }
+      
+      case kpidPath:
+      {
+        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())
+        {
+          for (unsigned n = 0; n < kNumAppleNames; n++)
+          {
+            const CAppleName &appleName = k_Names[n];
+            if (appleName.Ext)
+            {
+              if (subName == appleName.AppleName)
+              {
+                subName = appleName.Ext;
+                break;
+              }
+            }
+          }
+          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;
+        break;
+      }
+      
+      case kpidComment:
+      {
+        UString name;
+        ConvertUTF8ToUnicode(item.Name, name);
+        prop = name;
+        break;
+      }
+    }
+  }
+  prop.Detach(value);
+  return S_OK;
+  COM_TRY_END
+}
+
+
+Z7_CLASS_IMP_NOQIB_1(
+  CAdcDecoder
+  , ICompressCoder
+)
+  CLzOutWindow m_OutWindowStream;
+  CInBuffer m_InStream;
+
+  /*
+  void ReleaseStreams()
+  {
+    m_OutWindowStream.ReleaseStream();
+    m_InStream.ReleaseStream();
+  }
+  */
+
+  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();
+      // m_Coder->ReleaseStreams();
+    }
+  };
+  friend class CCoderReleaser;
+
+public:
+  HRESULT CodeReal(ISequentialInStream *inStream,
+      ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize,
+      ICompressProgressInfo *progress);
+};
+
+HRESULT CAdcDecoder::CodeReal(ISequentialInStream *inStream,
+    ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize,
+    ICompressProgressInfo *progress)
+{
+  if (!m_OutWindowStream.Create(1 << 18))
+    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 << 20);
+  UInt64 nextLimit = kStep;
+
+  UInt64 pos = 0;
+  while (pos < *outSize)
+  {
+    if (pos > nextLimit && progress)
+    {
+      UInt64 packSize = m_InStream.GetProcessedSize();
+      RINOK(progress->SetRatioInfo(&packSize, &pos))
+      nextLimit += kStep;
+    }
+    Byte b;
+    if (!m_InStream.ReadByte(b))
+      return S_FALSE;
+    UInt64 rem = *outSize - pos;
+    if (b & 0x80)
+    {
+      unsigned num = (b & 0x7F) + 1;
+      if (num > rem)
+        return S_FALSE;
+      for (unsigned i = 0; i < num; i++)
+      {
+        if (!m_InStream.ReadByte(b))
+          return S_FALSE;
+        m_OutWindowStream.PutByte(b);
+      }
+      pos += num;
+      continue;
+    }
+    Byte b1;
+    if (!m_InStream.ReadByte(b1))
+      return S_FALSE;
+
+    UInt32 len, distance;
+
+    if (b & 0x40)
+    {
+      len = ((UInt32)b & 0x3F) + 4;
+      Byte b2;
+      if (!m_InStream.ReadByte(b2))
+        return S_FALSE;
+      distance = ((UInt32)b1 << 8) + b2;
+    }
+    else
+    {
+      b &= 0x3F;
+      len = ((UInt32)b >> 2) + 3;
+      distance = (((UInt32)b & 3) << 8) + b1;
+    }
+
+    if (distance >= pos || len > rem)
+      return S_FALSE;
+    m_OutWindowStream.CopyBlock(distance, len);
+    pos += len;
+  }
+  if (*inSize != m_InStream.GetProcessedSize())
+    return S_FALSE;
+  coderReleaser.NeedFlush = false;
+  return m_OutWindowStream.Flush();
+}
+
+Z7_COM7F_IMF(CAdcDecoder::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(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();
+  if (numItems == 0)
+    return S_OK;
+  UInt64 totalSize = 0;
+  UInt32 i;
+  
+  for (i = 0; i < numItems; i++)
+  {
+    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;
+  }
+  extractCallback->SetTotal(totalSize);
+
+  UInt64 currentPackTotal = 0;
+  UInt64 currentUnpTotal = 0;
+  UInt64 currentPackSize = 0;
+  UInt64 currentUnpSize = 0;
+
+  const UInt32 kZeroBufSize = (1 << 14);
+  CByteBuffer zeroBuf(kZeroBufSize);
+  memset(zeroBuf, 0, kZeroBufSize);
+  
+  NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+  CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+  NCompress::NBZip2::CDecoder *bzip2CoderSpec = new NCompress::NBZip2::CDecoder();
+  CMyComPtr<ICompressCoder> bzip2Coder = bzip2CoderSpec;
+
+  NCompress::NZlib::CDecoder *zlibCoderSpec = new NCompress::NZlib::CDecoder();
+  CMyComPtr<ICompressCoder> zlibCoder = zlibCoderSpec;
+
+  CAdcDecoder *adcCoderSpec = new CAdcDecoder();
+  CMyComPtr<ICompressCoder> adcCoder = adcCoderSpec;
+
+  NCompress::NLzfse::CDecoder *lzfseCoderSpec = new NCompress::NLzfse::CDecoder();
+  CMyComPtr<ICompressCoder> lzfseCoder = lzfseCoderSpec;
+
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> progress = lps;
+  lps->Init(extractCallback, false);
+
+  CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+  CMyComPtr<ISequentialInStream> inStream(streamSpec);
+  streamSpec->SetStream(_inStream);
+
+  for (i = 0; i < numItems; i++, currentPackTotal += currentPackSize, currentUnpTotal += currentUnpSize)
+  {
+    lps->InSize = currentPackTotal;
+    lps->OutSize = currentUnpTotal;
+    currentPackSize = 0;
+    currentUnpSize = 0;
+    RINOK(lps->SetCur())
+    CMyComPtr<ISequentialOutStream> 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))
+
+
+    COutStreamWithCRC *outCrcStreamSpec = new COutStreamWithCRC;
+    CMyComPtr<ISequentialOutStream> outCrcStream = outCrcStreamSpec;
+    outCrcStreamSpec->SetStream(realOutStream);
+    bool needCrc = false;
+    outCrcStreamSpec->Init(needCrc);
+
+    CLimitedSequentialOutStream *outStreamSpec = new CLimitedSequentialOutStream;
+    CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+    outStreamSpec->SetStream(outCrcStream);
+    
+    realOutStream.Release();
+
+    Int32 opRes = NExtract::NOperationResult::kOK;
+    #ifdef DMG_SHOW_RAW
+    if (index >= _files.Size())
+    {
+      const CByteBuffer &buf = _extras[index - _files.Size()].Data;
+      outStreamSpec->Init(buf.Size());
+      RINOK(WriteStream(outStream, buf, buf.Size()));
+      currentPackSize = currentUnpSize = buf.Size();
+    }
+    else
+    #endif
+    {
+      const CFile &item = _files[index];
+      currentPackSize = item.PackSize;
+      currentUnpSize = item.Size;
+
+      needCrc = item.Checksum.IsCrc32();
+
+      UInt64 unpPos = 0;
+      UInt64 packPos = 0;
+      {
+        FOR_VECTOR (j, item.Blocks)
+        {
+          lps->InSize = currentPackTotal + packPos;
+          lps->OutSize = currentUnpTotal + unpPos;
+          RINOK(lps->SetCur())
+
+          const CBlock &block = item.Blocks[j];
+          if (!block.ThereAreDataInBlock())
+            continue;
+
+          packPos += block.PackSize;
+          if (block.UnpPos != unpPos)
+          {
+            opRes = NExtract::NOperationResult::kDataError;
+            break;
+          }
+
+          RINOK(InStream_SeekSet(_inStream, _startPos + _dataStartOffset + item.StartPos + block.PackPos))
+          streamSpec->Init(block.PackSize);
+          bool realMethod = true;
+          outStreamSpec->Init(block.UnpSize);
+          HRESULT res = S_OK;
+
+          outCrcStreamSpec->EnableCalc(needCrc);
+
+          switch (block.Type)
+          {
+            case METHOD_ZERO_0:
+            case METHOD_ZERO_2:
+              realMethod = false;
+              if (block.PackSize != 0)
+                opRes = NExtract::NOperationResult::kUnsupportedMethod;
+              outCrcStreamSpec->EnableCalc(block.Type == METHOD_ZERO_0);
+              break;
+
+            case METHOD_COPY:
+              if (block.UnpSize != block.PackSize)
+              {
+                opRes = NExtract::NOperationResult::kUnsupportedMethod;
+                break;
+              }
+              res = copyCoder->Code(inStream, outStream, NULL, NULL, progress);
+              break;
+            
+            case METHOD_ADC:
+            {
+              res = adcCoder->Code(inStream, outStream, &block.PackSize, &block.UnpSize, progress);
+              break;
+            }
+            
+            case METHOD_ZLIB:
+            {
+              res = zlibCoder->Code(inStream, outStream, NULL, NULL, progress);
+              if (res == S_OK)
+                if (zlibCoderSpec->GetInputProcessedSize() != block.PackSize)
+                  opRes = NExtract::NOperationResult::kDataError;
+              break;
+            }
+
+            case METHOD_BZIP2:
+            {
+              res = bzip2Coder->Code(inStream, outStream, NULL, NULL, progress);
+              if (res == S_OK)
+                if (bzip2CoderSpec->GetInputProcessedSize() != block.PackSize)
+                  opRes = NExtract::NOperationResult::kDataError;
+              break;
+            }
+
+            case METHOD_LZFSE:
+            {
+              res = lzfseCoder->Code(inStream, outStream, &block.PackSize, &block.UnpSize, progress);
+              break;
+            }
+            
+            default:
+              opRes = NExtract::NOperationResult::kUnsupportedMethod;
+              break;
+          }
+
+          if (res != S_OK)
+          {
+            if (res != S_FALSE)
+              return res;
+            if (opRes == NExtract::NOperationResult::kOK)
+              opRes = NExtract::NOperationResult::kDataError;
+          }
+          
+          unpPos += block.UnpSize;
+          
+          if (!outStreamSpec->IsFinishedOK())
+          {
+            if (realMethod && opRes == NExtract::NOperationResult::kOK)
+              opRes = NExtract::NOperationResult::kDataError;
+
+            while (outStreamSpec->GetRem() != 0)
+            {
+              UInt64 rem = outStreamSpec->GetRem();
+              UInt32 size = (UInt32)MyMin(rem, (UInt64)kZeroBufSize);
+              RINOK(WriteStream(outStream, zeroBuf, size))
+            }
+          }
+        }
+      }
+  
+      if (needCrc && opRes == NExtract::NOperationResult::kOK)
+      {
+        if (outCrcStreamSpec->GetCRC() != item.Checksum.GetCrc32())
+          opRes = NExtract::NOperationResult::kCRCError;
+      }
+    }
+    outStream.Release();
+    RINOK(extractCallback->SetOperationResult(opRes))
+  }
+
+  return S_OK;
+  COM_TRY_END
+}
+
+struct CChunk
+{
+  int BlockIndex;
+  UInt64 AccessMark;
+  CByteBuffer Buf;
+};
+
+
+Z7_CLASS_IMP_COM_1(
+  CInStream
+  , IInStream
+)
+  Z7_IFACE_COM7_IMP(ISequentialInStream)
+
+  UInt64 _virtPos;
+  int _latestChunk;
+  int _latestBlock;
+  UInt64 _accessMark;
+  CObjectVector<CChunk> _chunks;
+
+  NCompress::NBZip2::CDecoder *bzip2CoderSpec;
+  CMyComPtr<ICompressCoder> bzip2Coder;
+
+  NCompress::NZlib::CDecoder *zlibCoderSpec;
+  CMyComPtr<ICompressCoder> zlibCoder;
+
+  CAdcDecoder *adcCoderSpec;
+  CMyComPtr<ICompressCoder> adcCoder;
+
+  NCompress::NLzfse::CDecoder *lzfseCoderSpec;
+  CMyComPtr<ICompressCoder> lzfseCoder;
+
+  CBufPtrSeqOutStream *outStreamSpec;
+  CMyComPtr<ISequentialOutStream> outStream;
+
+  CLimitedSequentialInStream *limitedStreamSpec;
+  CMyComPtr<ISequentialInStream> inStream;
+
+public:
+  CMyComPtr<IInStream> Stream;
+  UInt64 Size;
+  const CFile *File;
+  UInt64 _startPos;
+
+  HRESULT InitAndSeek(UInt64 startPos)
+  {
+    _startPos = startPos;
+    _virtPos = 0;
+    _latestChunk = -1;
+    _latestBlock = -1;
+    _accessMark = 0;
+
+    limitedStreamSpec = new CLimitedSequentialInStream;
+    inStream = limitedStreamSpec;
+    limitedStreamSpec->SetStream(Stream);
+
+    outStreamSpec = new CBufPtrSeqOutStream;
+    outStream = outStreamSpec;
+    return S_OK;
+  }
+};
+
+
+static unsigned FindBlock(const CRecordVector<CBlock> &blocks, UInt64 pos)
+{
+  unsigned left = 0, right = blocks.Size();
+  for (;;)
+  {
+    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
+
+  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 (_latestBlock >= 0)
+  {
+    const CBlock &block = File->Blocks[(unsigned)_latestBlock];
+    if (_virtPos < block.UnpPos || (_virtPos - block.UnpPos) >= block.UnpSize)
+      _latestBlock = -1;
+  }
+  
+  if (_latestBlock < 0)
+  {
+    _latestChunk = -1;
+    unsigned blockIndex = FindBlock(File->Blocks, _virtPos);
+    const CBlock &block = File->Blocks[blockIndex];
+    
+    if (!block.IsZeroMethod() && block.Type != METHOD_COPY)
+    {
+      unsigned i;
+      for (i = 0; i < _chunks.Size(); i++)
+        if (_chunks[i].BlockIndex == (int)blockIndex)
+          break;
+      
+      if (i != _chunks.Size())
+        _latestChunk = (int)i;
+      else
+      {
+        const unsigned kNumChunksMax = 128;
+        unsigned chunkIndex;
+      
+        if (_chunks.Size() != kNumChunksMax)
+          chunkIndex = _chunks.Add(CChunk());
+        else
+        {
+          chunkIndex = 0;
+          for (i = 0; i < _chunks.Size(); i++)
+            if (_chunks[i].AccessMark < _chunks[chunkIndex].AccessMark)
+              chunkIndex = i;
+        }
+        
+        CChunk &chunk = _chunks[chunkIndex];
+        chunk.BlockIndex = -1;
+        chunk.AccessMark = 0;
+        
+        if (chunk.Buf.Size() < block.UnpSize)
+        {
+          chunk.Buf.Free();
+          if (block.UnpSize > ((UInt32)1 << 31))
+            return E_FAIL;
+          chunk.Buf.Alloc((size_t)block.UnpSize);
+        }
+        
+        outStreamSpec->Init(chunk.Buf, (size_t)block.UnpSize);
+          
+        RINOK(InStream_SeekSet(Stream, _startPos + File->StartPos + block.PackPos))
+
+        limitedStreamSpec->Init(block.PackSize);
+        HRESULT res = S_OK;
+        
+        switch (block.Type)
+        {
+          case METHOD_COPY:
+            if (block.PackSize != block.UnpSize)
+              return E_FAIL;
+            res = ReadStream_FAIL(inStream, chunk.Buf, (size_t)block.UnpSize);
+            break;
+            
+          case METHOD_ADC:
+            if (!adcCoder)
+            {
+              adcCoderSpec = new CAdcDecoder();
+              adcCoder = adcCoderSpec;
+            }
+            res = adcCoder->Code(inStream, outStream, &block.PackSize, &block.UnpSize, NULL);
+            break;
+            
+          case METHOD_ZLIB:
+            if (!zlibCoder)
+            {
+              zlibCoderSpec = new NCompress::NZlib::CDecoder();
+              zlibCoder = zlibCoderSpec;
+            }
+            res = zlibCoder->Code(inStream, outStream, NULL, NULL, NULL);
+            if (res == S_OK && zlibCoderSpec->GetInputProcessedSize() != block.PackSize)
+              res = S_FALSE;
+            break;
+            
+          case METHOD_BZIP2:
+            if (!bzip2Coder)
+            {
+              bzip2CoderSpec = new NCompress::NBZip2::CDecoder();
+              bzip2Coder = bzip2CoderSpec;
+            }
+            res = bzip2Coder->Code(inStream, outStream, NULL, NULL, NULL);
+            if (res == S_OK && bzip2CoderSpec->GetInputProcessedSize() != block.PackSize)
+              res = S_FALSE;
+            break;
+
+          case METHOD_LZFSE:
+            if (!lzfseCoder)
+            {
+              lzfseCoderSpec = new NCompress::NLzfse::CDecoder();
+              lzfseCoder = lzfseCoderSpec;
+            }
+            res = lzfseCoder->Code(inStream, outStream, &block.PackSize, &block.UnpSize, NULL);
+            break;
+            
+          default:
+            return E_FAIL;
+        }
+        
+        if (res != S_OK)
+          return res;
+        if (block.Type != METHOD_COPY && outStreamSpec->GetPos() != block.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 = block.UnpSize - offset;
+  if (size > rem)
+    size = (UInt32)rem;
+  
+  HRESULT res = S_OK;
+  
+  if (block.Type == METHOD_COPY)
+  {
+    RINOK(InStream_SeekSet(Stream, _startPos + File->StartPos + block.PackPos + offset))
+    res = Stream->Read(data, size, &size);
+  }
+  else if (block.IsZeroMethod())
+    memset(data, 0, size);
+  else if (size != 0)
+    memcpy(data, _chunks[_latestChunk].Buf + (size_t)offset, size);
+  
+  _virtPos += size;
+  if (processedSize)
+    *processedSize = size;
+  
+  return res;
+  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;
+}
+
+Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream))
+{
+  COM_TRY_BEGIN
+  
+  #ifdef DMG_SHOW_RAW
+  if (index >= (UInt32)_files.Size())
+    return S_FALSE;
+  #endif
+  
+  CInStream *spec = new CInStream;
+  CMyComPtr<ISequentialInStream> specStream = spec;
+  spec->File = &_files[index];
+  const CFile &file = *spec->File;
+  
+  FOR_VECTOR (i, file.Blocks)
+  {
+    const CBlock &block = file.Blocks[i];
+    switch (block.Type)
+    {
+      case METHOD_ZERO_0:
+      case METHOD_ZERO_2:
+      case METHOD_COPY:
+      case METHOD_ADC:
+      case METHOD_ZLIB:
+      case METHOD_BZIP2:
+      case METHOD_LZFSE:
+      case METHOD_END:
+        break;
+      default:
+        return S_FALSE;
+    }
+  }
+  
+  spec->Stream = _inStream;
+  spec->Size = spec->File->Size;
+  RINOK(spec->InitAndSeek(_startPos + _dataStartOffset))
+  *stream = specStream.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
new file mode 100644
index 0000000..7e1facc
--- /dev/null
+++ b/CPP/7zip/Archive/ElfHandler.cpp
@@ -0,0 +1,1108 @@
+// 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"
+
+using namespace NWindows;
+
+static UInt16 Get16(const Byte *p, bool be) { if (be) return GetBe16(p); return GetUi16(p); }
+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); }
+
+#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 for most files (real order can be different):
+   Header
+   Program (segment) header table (used at runtime)
+     Segment1 (Section ... Section)
+     Segment2
+     ...
+     SegmentN
+   Section header table (the data for linking and relocation)
+*/
+
+#define ELF_CLASS_32 1
+#define ELF_CLASS_64 2
+
+#define ELF_DATA_2LSB 1
+#define ELF_DATA_2MSB 2
+
+static const UInt32 kHeaderSize32 = 0x34;
+static const UInt32 kHeaderSize64 = 0x40;
+
+static const UInt32 kSegmentSize32 = 0x20;
+static const UInt32 kSegmentSize64 = 0x38;
+
+static const UInt32 kSectionSize32 = 0x28;
+static const UInt32 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 *buf);
+
+  UInt64 GetHeadersSize() const { return (UInt64)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);
+    G64(0x28, SectOffset);
+    p += 0x30;
+  }
+  else
+  {
+    // G32(0x18, EntryVa);
+    G32(0x1C, ProgOffset);
+    G32(0x20, SectOffset);
+    p += 0x24;
+  }
+
+  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 != 0 || NumSegments != 0)) return false;
+  if (SectOffset < HeaderSize && (SectOffset != 0 || NumSections != 0)) return false;
+
+  if (SegmentEntrySize == 0) { if (NumSegments != 0) return false; }
+  else if (SegmentEntrySize != (Mode64 ? kSegmentSize64 : kSegmentSize32)) return false;
+
+  if (SectionEntrySize == 0) { if (NumSections != 0) return false; }
+  else if (SectionEntrySize != (Mode64 ? kSectionSize64 : kSectionSize32)) return false;
+
+  return true;
+}
+
+// The program header table itself.
+
+#define PT_PHDR 6
+
+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" },
+  { 0x6474e551, "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 Pa;
+  UInt64 Size;
+  UInt64 VSize;
+  UInt64 Align;
+
+  void UpdateTotalSize(UInt64 &totalSize)
+  {
+    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(0x18, Pa);
+    G64(0x20, Size);
+    G64(0x28, VSize);
+    G64(0x30, Align);
+  }
+  else
+  {
+    G32(4, Offset);
+    G32(8, Va);
+    // G32(0x0C, Pa);
+    G32(0x10, Size);
+    G32(0x14, VSize);
+    G32(0x18, Flags);
+    G32(0x1C, Align);
+  }
+}
+
+// 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" }
+};
+
+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, "CP_SECTION" },
+  { 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)
+  {
+    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"
+  , "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" },
+  { 47787, "Xilinx MicroBlaze" }
+  // { 0x9026, "Alpha" }
+};
+
+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" },
+  { 64, "Bare-metal TMS320C6000" },
+  { 65, "Linux TMS320C6000" },
+  { 97, "ARM" },
+  { 255, "Standalone" }
+};
+
+#define k_Machine_MIPS 8
+#define k_Machine_ARM 40
+
+/*
+#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" }
+};
+
+
+// #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<CSegment> _segments;
+  CRecordVector<CSection> _sections;
+  CByteBuffer _namesData;
+  CMyComPtr<IInStream> _inStream;
+  UInt64 _totalSize;
+  CHeader _header;
+  bool _headersError;
+  bool _allowTail;
+
+  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())
+    return;
+  const CSection &section = _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;
+  size_t size = _namesData.Size();
+  for (size_t i = offset; i < size; i++)
+    if (p[i] == 0)
+    {
+      prop = (const char *)(p + offset);
+      return;
+    }
+}
+
+static const Byte kArcProps[] =
+{
+  kpidCpu,
+  kpidBit64,
+  kpidBigEndian,
+  kpidHostOS,
+  kpidCharacts,
+  kpidHeadersSize
+};
+
+enum
+{
+  kpidLinkSection = kpidUserDefined,
+  kpidInfoSection
+};
+
+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 }
+  , { "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 != 0)
+      {
+        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 += "v";
+          s.Add_UInt32(ver);
+          flags &= (((UInt32)1 << 28) - 1);
+
+          UInt32 abi = (flags >> 12) & 7;
+          if (abi != 0)
+          {
+            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
+        {
+          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 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;
+      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;
+      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 kpidLinkSection: GetSectionName(item.Link, prop, false); break;
+      case kpidInfoSection: GetSectionName(item.Info, prop, false); break;
+    }
+  }
+  prop.Detach(value);
+  return S_OK;
+  COM_TRY_END
+}
+
+HRESULT CHandler::Open2(IInStream *stream)
+{
+  const UInt32 kStartSize = kHeaderSize64;
+  Byte h[kStartSize];
+  RINOK(ReadStream_FALSE(stream, h, kStartSize))
+  if (h[0] != 0x7F || h[1] != 'E' || h[2] != 'L' || h[3] != 'F')
+    return S_FALSE;
+  if (!_header.Parse(h))
+    return S_FALSE;
+
+  _totalSize = _header.HeaderSize;
+
+  bool addSegments = false;
+  bool addSections = false;
+
+  if (_header.NumSections > 1)
+    addSections = true;
+  else
+    addSegments = true;
+
+  if (_header.NumSegments != 0)
+  {
+    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;
+
+    const Byte *p = buf;
+    
+    if (addSegments)
+      _segments.ClearAndReserve(_header.NumSegments);
+    for (unsigned i = 0; i < _header.NumSegments; i++, p += _header.SegmentEntrySize)
+    {
+      CSegment seg;
+      seg.Parse(p, _header.Mode64, _header.Be);
+      seg.UpdateTotalSize(_totalSize);
+      if (addSegments)
+        if (seg.Type != PT_PHDR)
+          _segments.AddInReserved(seg);
+    }
+  }
+
+  if (_header.NumSections != 0)
+  {
+    if (_header.SectOffset > (UInt64)1 << 60) return S_FALSE;
+    RINOK(InStream_SeekSet(stream, _header.SectOffset))
+    size_t size = (size_t)_header.SectionEntrySize * _header.NumSections;
+    
+    CByteArr buf(size);
+    
+    RINOK(ReadStream_FALSE(stream, buf, size))
+
+    UInt64 total = _header.SectOffset + size;
+    if (_totalSize < total)
+      _totalSize = total;
+
+    const Byte *p = buf;
+    
+    if (addSections)
+      _sections.ClearAndReserve(_header.NumSections);
+    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 &sect = _sections[_header.NamesSectIndex];
+      const UInt64 size = sect.GetSize();
+      if (size != 0
+        && 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 will not delete NULL sections, since we have links to section 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;
+
+  _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();
+  }
+  extractCallback->SetTotal(totalSize);
+
+  UInt64 currentTotalSize = 0;
+  UInt64 currentItemSize;
+  
+  NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+  CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> progress = lps;
+  lps->Init(extractCallback, false);
+
+  CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+  CMyComPtr<ISequentialInStream> 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];
+    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<ISequentialOutStream> outStream;
+    RINOK(extractCallback->GetStream(index, &outStream, askMode))
+    if (!testMode && !outStream)
+      continue;
+      
+    RINOK(extractCallback->PrepareOperation(askMode))
+    RINOK(InStream_SeekSet(_inStream, offset))
+    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[] = { 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
new file mode 100644
index 0000000..f309485
--- /dev/null
+++ b/CPP/7zip/Archive/ExtHandler.cpp
@@ -0,0 +1,2869 @@
+// ExtHandler.cpp
+
+#include "StdAfx.h"
+
+// #define SHOW_DEBUG_INFO
+
+// #include <stdio.h>
+// #define PRF2(x) x
+
+#define PRF2(x)
+
+#ifdef SHOW_DEBUG_INFO
+#include <stdio.h>
+#define PRF(x) x
+#else
+#define PRF(x)
+#endif
+
+#include "../../../C/Alloc.h"
+#include "../../../C/CpuArch.h"
+
+#include "../../Common/ComTry.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
+};
+
+
+static inline char GetHex(unsigned t) { return (char)(((t < 10) ? ('0' + t) : ('A' + (t - 10)))); }
+
+static inline void PrintHex(unsigned v, char *s)
+{
+  s[0] = GetHex((v >> 4) & 0xF);
+  s[1] = GetHex(v & 0xF);
+}
+
+
+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<CItem> _items;
+  CIntVector _refs;                 // iNode -> (index in _nodes). if (_refs[iNode] < 0), that node is not filled
+  CRecordVector<CNode> _nodes;
+  CObjectVector<CUIntVector> _dirs; // each CUIntVector contains indexes in _items[] only for dir items;
+  AStringVector _symLinks;
+  AStringVector _auxItems;
+  int _auxSysIndex;
+  int _auxUnknownIndex;
+
+  CMyComPtr<IInStream> _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<UInt32> &blocks);
+  HRESULT FillFileBlocks(const Byte *p, unsigned numBlocks, CRecordVector<UInt32> &blocks);
+  HRESULT FillExtents(const Byte *p, size_t size, CRecordVector<CExtent> &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<CItem> &items = *(const CObjectVector<CItem> *)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<CGroupDescriptor> 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, 16))
+      {
+        char s[16 * 2 + 2];
+        for (unsigned i = 0; i < 16; i++)
+          PrintHex(_h.Uuid[i], s + i * 2);
+        s[16 * 2] = 0;
+        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<IInStream> Stream;
+  CRecordVector<UInt32> 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<IInStream> Stream;
+  CRecordVector<CExtent> 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<UInt32> &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<UInt32> &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<CExtent> &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<CExtent> &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<CExtent> &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<IInStream> streamTemp;
+  
+  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<ISequentialInStream> 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;
+  }
+  
+  extractCallback->SetTotal(totalSize);
+
+  UInt64 totalPackSize;
+  totalSize = totalPackSize = 0;
+  
+  NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+  CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> progress = lps;
+  lps->Init(extractCallback, false);
+
+  for (i = 0;; i++)
+  {
+    lps->InSize = totalPackSize;
+    lps->OutSize = totalSize;
+    RINOK(lps->SetCur())
+
+    if (i == numItems)
+      break;
+
+    CMyComPtr<ISequentialOutStream> 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))
+
+    int res = NExtract::NOperationResult::kDataError;
+    {
+      CMyComPtr<ISequentialInStream> 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->Code(inSeqStream, outStream, NULL, NULL, progress);
+          if (hres == S_OK)
+          {
+            if (copyCoderSpec->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))
+{
+  *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
new file mode 100644
index 0000000..4a843a8
--- /dev/null
+++ b/CPP/7zip/Archive/FatHandler.cpp
@@ -0,0 +1,1068 @@
+// FatHandler.cpp
+
+#include "StdAfx.h"
+
+// #include <stdio.h>
+
+#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 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;
+  
+  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;
+
+  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 || CalcFatSizeInSectors() > NumFatSectors)
+    return false;
+  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<CItem> Items;
+  UInt32 *Fat;
+  CMyComPtr<IInStream> 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)
+  {
+    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))
+        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())
+    {
+      SeekToSector(Header.FsInfoSector);
+      RINOK(ReadStream_FALSE(InStream, buf, kHeaderSize))
+      if (buf[0x1FE] != 0x55 || buf[0x1FF] != 0xAA)
+        return S_FALSE;
+      if (Get32(buf) == 0x41615252 && Get32(buf + 484) == 0x61417272)
+      {
+        NumFreeClusters = Get32(buf + 488);
+        numFreeClustersDefined = (NumFreeClusters <= Header.FatSize);
+      }
+    }
+  }
+
+  // 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; i < Header.FatSize;)
+    {
+      UInt32 size = Header.FatSize - i;
+      const UInt32 kBufSize32 = kBufSize / 4;
+      if (size > kBufSize32)
+        size = kBufSize32;
+      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;
+      if (numFreeClustersDefined)
+        for (UInt32 j = 0; j < size; j++)
+          dest[j] = Get32(src + j) & 0x0FFFFFFF;
+      else
+      {
+        UInt32 numFreeClusters = 0;
+        for (UInt32 j = 0; j < size; j++)
+        {
+          UInt32 v = Get32(src + j) & 0x0FFFFFFF;
+          numFreeClusters += (UInt32)(v - 1) >> 31;
+          dest[j] = v;
+        }
+        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))
+    UInt32 fatSize = Header.FatSize;
+    UInt32 *fat = &Fat[0];
+    if (Header.NumFatBits == 16)
+      for (UInt32 j = 0; j < fatSize; j++)
+        fat[j] = Get16(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<ISequentialInStream> streamTemp = streamSpec;
+  streamSpec->Stream = InStream;
+  streamSpec->StartOffset = Header.DataSector << Header.SectorSizeLog;
+  streamSpec->BlockSizeLog = Header.ClusterSizeLog;
+  streamSpec->Size = item.Size;
+
+  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
+  {
+    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;
+  }
+  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<ICompressCoder> copyCoder = copyCoderSpec;
+
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> progress = lps;
+  lps->Init(extractCallback, false);
+
+  CDummyOutStream *outStreamSpec = new CDummyOutStream;
+  CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+
+  for (i = 0;; i++)
+  {
+    lps->InSize = totalPackSize;
+    lps->OutSize = totalSize;
+    RINOK(lps->SetCur())
+    if (i == numItems)
+      break;
+    CMyComPtr<ISequentialOutStream> 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<ISequentialInStream> 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
new file mode 100644
index 0000000..1f746aa
--- /dev/null
+++ b/CPP/7zip/Archive/FlvHandler.cpp
@@ -0,0 +1,521 @@
+// FlvHandler.cpp
+
+#include "StdAfx.h"
+
+// #include <stdio.h>
+
+#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<IUnknown> RefBuf;
+
+  bool IsAudio() const { return Type == kType_Audio; }
+};
+
+
+Z7_CLASS_IMP_CHandler_IInArchive_1(
+  IInArchiveGetStream
+)
+  CMyComPtr<IInStream> _stream;
+  CObjectVector<CItem2> _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<CItem> 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<ICompressProgressInfo> progress = lps;
+  lps->Init(extractCallback, false);
+
+  for (i = 0; i < numItems; i++)
+  {
+    lps->InSize = lps->OutSize = totalSize;
+    RINOK(lps->SetCur())
+    CMyComPtr<ISequentialOutStream> 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<ISequentialInStream> 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
new file mode 100644
index 0000000..78c76cf
--- /dev/null
+++ b/CPP/7zip/Archive/GptHandler.cpp
@@ -0,0 +1,472 @@
+// 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 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 UInt32 kSectorSize = 512;
+
+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() const { return (LastLba - FirstLba + 1) * kSectorSize; }
+  UInt64 GetPos() const { return FirstLba * kSectorSize; }
+  UInt64 GetEnd() const { return (LastLba + 1) * kSectorSize; }
+
+  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" },
+
+  { 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<CPartition> _items;
+  UInt64 _totalSize;
+  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();
+    size = item.GetSize();
+    return NExtract::NOperationResult::kOK;
+  }
+};
+
+
+HRESULT CHandler::Open2(IInStream *stream)
+{
+  _buffer.Alloc(kSectorSize * 2);
+  RINOK(ReadStream_FALSE(stream, _buffer, kSectorSize * 2))
+  
+  const Byte *buf = _buffer;
+  if (buf[0x1FE] != 0x55 || buf[0x1FF] != 0xAA)
+    return S_FALSE;
+  
+  buf += kSectorSize;
+  if (memcmp(buf, k_Signature, k_SignatureSize) != 0)
+    return S_FALSE;
+  {
+    // if (Get32(buf + 8) != 0x10000) return S_FALSE; // revision
+    UInt32 headerSize = Get32(buf + 12); // = 0x5C usually
+    if (headerSize > kSectorSize)
+      return S_FALSE;
+    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)
+    return S_FALSE;
+  const UInt32 numEntries = Get32(buf + 0x50);
+  const UInt32 entrySize = Get32(buf + 0x54); // = 128 usually
+  const UInt32 entriesCrc = Get32(buf + 0x58);
+  
+  if (entrySize < 128
+      || entrySize > (1 << 12)
+      || numEntries > (1 << 16)
+      || tableLba < 2
+      || tableLba >= ((UInt64)1 << (64 - 10)))
+    return S_FALSE;
+  
+  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;
+    UInt64 endPos = item.GetEnd();
+    if (_totalSize < endPos)
+      _totalSize = endPos;
+    _items.Add(item);
+  }
+  
+  {
+    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;
+}
+
+
+
+static const unsigned k_Ntfs_Fat_HeaderSize = 512;
+
+static const Byte k_NtfsSignature[] = { 'N', 'T', 'F', 'S', ' ', ' ', ' ', ' ', 0 };
+
+static bool IsNtfs(const Byte *p)
+{
+  if (p[0x1FE] != 0x55 || p[0x1FF] != 0xAA)
+    return false;
+  if (memcmp(p + 3, k_NtfsSignature, Z7_ARRAY_SIZE(k_NtfsSignature)) != 0)
+    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 true;
+}
+
+
+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<ISequentialInStream> inStream;
+      if (
+          // ((IInArchiveGetStream *)this)->
+          GetStream(fileIndex, &inStream) == S_OK && inStream)
+      {
+        Byte temp[k_Ntfs_Fat_HeaderSize];
+        if (ReadStream_FAIL(inStream, temp, k_Ntfs_Fat_HeaderSize) == S_OK)
+        {
+          if (IsNtfs(temp))
+          {
+            item.Ext = "ntfs";
+            continue;
+          }
+          if (NFat::IsArc_Fat(temp, k_Ntfs_Fat_HeaderSize) == k_IsArc_Res_YES)
+          {
+            item.Ext = "fat";
+            continue;
+          }
+        }
+      }
+    }
+  }
+
+  return S_OK;
+  COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+  _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[] =
+{
+  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 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();
+        s += (item.Ext ? item.Ext : "img");
+      }
+      prop = s;
+      break;
+    }
+    
+    case kpidSize:
+    case kpidPackSize: prop = item.GetSize(); break;
+    case kpidOffset: prop = item.GetPos(); 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
+}
+
+REGISTER_ARC_I(
+  "GPT", "gpt mbr", NULL, 0xCB,
+  k_Signature,
+  kSectorSize,
+  0,
+  NULL)
+
+}}
diff --git a/CPP/7zip/Archive/GzHandler.cpp b/CPP/7zip/Archive/GzHandler.cpp
new file mode 100644
index 0000000..ad9a074
--- /dev/null
+++ b/CPP/7zip/Archive/GzHandler.cpp
@@ -0,0 +1,1210 @@
+// GzHandler.cpp
+
+#include "StdAfx.h"
+
+// #include  <stdio.h>
+
+#include "../../../C/CpuArch.h"
+
+#include "../../Common/ComTry.h"
+#include "../../Common/Defs.h"
+#include "../../Common/StringConvert.h"
+
+#include "../../Windows/PropVariant.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++)
+  {
+    Byte b = stream->ReadAlignedByte();
+    if (stream->InputEofError())
+      return S_FALSE;
+    // crc = CRC_UPDATE_BYTE(crc, b);
+    if (b == 0)
+      return S_OK;
+    s += (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;
+
+  Byte flags = p[3];
+  if ((flags & NFlags::kReserved) != 0)
+    return k_IsArc_Res_NO;
+
+  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;
+      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<IInStream> _stream;
+  CMyComPtr<ICompressCoder> _decoder;
+  NDecoder::CCOMCoder *_decoderSpec;
+
+  CSingleMethodProps _props;
+  CHandlerTimeOptions _timeOptions;
+
+public:
+  CHandler():
+      _isArc(false),
+      _decoderSpec(NULL)
+      {}
+  
+  void CreateDecoder()
+  {
+    if (_decoder)
+      return;
+    _decoderSpec = new NDecoder::CCOMCoder;
+    _decoder = _decoderSpec;
+  }
+};
+
+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;
+  }
+  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;
+  }
+  prop.Detach(value);
+  return S_OK;
+  COM_TRY_END
+}
+
+Z7_CLASS_IMP_COM_1(
+  CCompressProgressInfoImp,
+  ICompressProgressInfo
+)
+  CMyComPtr<IArchiveOpenCallback> 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();
+    _decoderSpec->SetInStream(stream);
+    _decoderSpec->InitInStream(true);
+    RINOK(_item.ReadHeader(_decoderSpec))
+    if (_decoderSpec->InputEofError())
+      return S_FALSE;
+    _headerSize = _decoderSpec->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)
+    _decoderSpec->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)
+    extractCallback->SetTotal(_packSize);
+  // UInt64 currentTotalPacked = 0;
+  // RINOK(extractCallback->SetCompleted(&currentTotalPacked));
+  CMyComPtr<ISequentialOutStream> 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);
+
+  CreateDecoder();
+
+  COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC;
+  CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+  outStreamSpec->SetStream(realOutStream);
+  outStreamSpec->Init();
+  realOutStream.Release();
+
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> progress = lps;
+  lps->Init(extractCallback, true);
+
+  bool needReadFirstItem = _needSeekToStart;
+  
+  if (_needSeekToStart)
+  {
+    if (!_stream)
+      return E_FAIL;
+    RINOK(InStream_SeekToBegin(_stream))
+    _decoderSpec->InitInStream(true);
+    // printf("\nSeek");
+  }
+  else
+    _needSeekToStart = true;
+
+  bool firstItem = true;
+
+  UInt64 packSize = _decoderSpec->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(_decoderSpec);
+
+      if (result != S_OK && result != S_FALSE)
+        return result;
+    
+      if (_decoderSpec->InputEofError())
+        result = S_FALSE;
+
+      if (result != S_OK && firstItem)
+      {
+        _isArc = false;
+        break;
+      }
+
+      if (packSize == _decoderSpec->GetStreamSize())
+      {
+        result = S_OK;
+        break;
+      }
+
+      if (result != S_OK)
+      {
+        _dataAfterEnd = true;
+        break;
+      }
+    }
+    
+    numStreams++;
+    firstItem = false;
+
+    UInt64 startOffset = outStreamSpec->GetSize();
+    outStreamSpec->InitCRC();
+
+    result = _decoderSpec->CodeResume(outStream, NULL, progress);
+
+    packSize = _decoderSpec->GetInputProcessedSize();
+    unpackedSize = outStreamSpec->GetSize();
+
+    if (result != S_OK && result != S_FALSE)
+      return result;
+
+    if (_decoderSpec->InputEofError())
+    {
+      packSize = _decoderSpec->GetStreamSize();
+      _needMoreInput = true;
+      result = S_FALSE;
+    }
+
+    if (result != S_OK)
+      break;
+
+    _decoderSpec->AlignToByte();
+    
+    result = item.ReadFooter1(_decoderSpec);
+
+    packSize = _decoderSpec->GetInputProcessedSize();
+
+    if (result != S_OK && result != S_FALSE)
+      return result;
+
+    if (result != S_OK)
+    {
+      if (_decoderSpec->InputEofError())
+      {
+        _needMoreInput = true;
+        result = S_FALSE;
+      }
+      break;
+    }
+
+    if (item.Crc != outStreamSpec->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();
+
+  Int32 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<ISequentialInStream> 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))
+
+  CSequentialInStreamWithCRC *inStreamSpec = new CSequentialInStreamWithCRC;
+  CMyComPtr<ISequentialInStream> crcStream(inStreamSpec);
+  inStreamSpec->SetStream(fileInStream);
+  inStreamSpec->Init();
+
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> progress = lps;
+  lps->Init(updateCallback, true);
+  
+  item.ExtraFlags = props.GetLevel() >= 7 ?
+      NExtraFlags::kMaximum :
+      NExtraFlags::kFastest;
+
+  item.HostOS = kHostOS;
+
+  RINOK(item.WriteHeader(outStream))
+
+  NEncoder::CCOMCoder *deflateEncoderSpec = new NEncoder::CCOMCoder;
+  CMyComPtr<ICompressCoder> deflateEncoder = deflateEncoderSpec;
+  RINOK(props.SetCoderProps(deflateEncoderSpec, NULL))
+  RINOK(deflateEncoder->Code(crcStream, outStream, NULL, NULL, progress))
+
+  item.Crc = inStreamSpec->GetCRC();
+  unpackSizeReal = inStreamSpec->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;
+
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> progress = 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, progress);
+
+  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
new file mode 100644
index 0000000..b4524a4
--- /dev/null
+++ b/CPP/7zip/Archive/HandlerCont.cpp
@@ -0,0 +1,346 @@
+// 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;
+  }
+  extractCallback->SetTotal(totalSize);
+
+  totalSize = 0;
+  
+  NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+  CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> progress = lps;
+  lps->Init(extractCallback, false);
+
+  CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+  CMyComPtr<ISequentialInStream> inStream(streamSpec);
+  streamSpec->SetStream(_stream);
+
+  for (i = 0; i < numItems; i++)
+  {
+    lps->InSize = totalSize;
+    lps->OutSize = totalSize;
+    RINOK(lps->SetCur())
+    CMyComPtr<ISequentialOutStream> 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->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
+}
+
+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' };
+// 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 = 1 << 11;
+  Byte buf[kHeaderSize];
+  if (ReadStream_FAIL(stream, buf, kHeaderSize) == S_OK)
+  {
+    if (buf[0x1FE] == 0x55 && buf[0x1FF] == 0xAA)
+    {
+      if (memcmp(buf + 512, k_GDP_Signature, sizeof(k_GDP_Signature)) == 0)
+        return "gpt";
+      return "mbr";
+    }
+    if (NExt::IsArc_Ext(buf, kHeaderSize) == 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<ISequentialInStream> 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<ICompressProgressInfo> _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<ISequentialOutStream> 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<ISequentialInStream> inStream;
+  HRESULT hres = GetStream(0, &inStream);
+  if (hres == S_FALSE)
+    hres = E_NOTIMPL;
+
+  if (hres == S_OK && inStream)
+  {
+    CLocalProgress *lps = new CLocalProgress;
+    CMyComPtr<ICompressProgressInfo> progress = lps;
+    lps->Init(extractCallback, false);
+    
+    if (Init_PackSizeProcessed())
+    {
+      CHandlerImgProgress *imgProgressSpec = new CHandlerImgProgress(*this);
+      CMyComPtr<ICompressProgressInfo> imgProgress = imgProgressSpec;
+      imgProgressSpec->_ratioProgress = progress;
+      progress.Release();
+      progress = imgProgress;
+    }
+
+    NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+    CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+    hres = copyCoder->Code(inStream, outStream, NULL, &_size, progress);
+    if (hres == S_OK)
+    {
+      if (copyCoderSpec->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 (copyCoderSpec->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
+}
+
+
+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/HandlerCont.h b/CPP/7zip/Archive/HandlerCont.h
new file mode 100644
index 0000000..2dd0529
--- /dev/null
+++ b/CPP/7zip/Archive/HandlerCont.h
@@ -0,0 +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<IInStream> _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_3(
+      IInArchive,
+      IInArchiveGetStream,
+      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:
+  UInt64 _virtPos;
+  UInt64 _posInArc;
+  UInt64 _size;
+  CMyComPtr<IInStream> Stream;
+  const char *_imgExt;
+  
+  bool _stream_unavailData;
+  bool _stream_unsupportedMethod;
+  bool _stream_dataError;
+  // bool _stream_UsePackSize;
+  // UInt64 _stream_PackSize;
+
+  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
new file mode 100644
index 0000000..696ecd7
--- /dev/null
+++ b/CPP/7zip/Archive/HfsHandler.cpp
@@ -0,0 +1,2590 @@
+// 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<CExtent> Extents;
+};
+
+struct CFork
+{
+  UInt64 Size;
+  UInt32 NumBlocks;
+  // UInt32 ClumpSize;
+  CRecordVector<CExtent> 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<CIdExtents> &items, UInt32 id);
+  bool UpgradeAndTest(const CObjectVector<CIdExtents> &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<CIdIndexPair> &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<CIdExtents> &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<CIdExtents> &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<CIdExtents> *overflowExtentsArray);
+  HRESULT LoadAttrs(const CFork &fork, IInStream *inStream, IArchiveOpenCallback *progress);
+  HRESULT LoadCatalog(const CFork &fork, const CObjectVector<CIdExtents> *overflowExtentsArray, IInStream *inStream, IArchiveOpenCallback *progress);
+  bool Parse_decmpgfs(unsigned attrIndex, CItem &item, bool &skip);
+public:
+  CRecordVector<CRef> Refs;
+  CObjectVector<CItem> Items;
+  CObjectVector<CAttr> 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<CIdExtents> *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<CIdExtents> &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<CIdExtents> *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<CIdIndexPair> 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<CIdExtents> 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<IInStream> _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()
+{
+  _zlibDecoderSpec = new NCompress::NZlib::CDecoder();
+  _zlibDecoder = _zlibDecoderSpec;
+  
+  _lzfseDecoderSpec = new NCompress::NLzfse::CDecoder();
+  _lzfseDecoder = _lzfseDecoderSpec;
+  _lzfseDecoderSpec->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;
+
+  CBufInStream *bufInStreamSpec = new CBufInStream;
+  CMyComPtr<ISequentialInStream> bufInStream = bufInStreamSpec;
+
+  // 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;
+      bufInStreamSpec->Init(buf, size);
+      RINOK(_zlibDecoder->Code(bufInStream, outStream, NULL, &blockSize64, NULL))
+      if (_zlibDecoderSpec->GetOutputProcessedSize() != blockSize)
+        return S_FALSE;
+      const UInt64 inSize = _zlibDecoderSpec->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
+
+  CBufInStream *bufInStreamSpec = new CBufInStream;
+  CMyComPtr<ISequentialInStream> bufInStream = bufInStreamSpec;
+
+  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;
+      bufInStreamSpec->Init(buf, size);
+      RINOK(_lzfseDecoder->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 *bufInStreamSpec = new CBufInStream;
+  CMyComPtr<ISequentialInStream> bufInStream = bufInStreamSpec;
+
+  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;
+      // bufInStreamSpec->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)
+  {
+    CBufInStream *bufInStreamSpec = new CBufInStream;
+    CMyComPtr<ISequentialInStream> bufInStream = bufInStreamSpec;
+    const size_t packSize = data->Size() - compressHeader.DataPos;
+    bufInStreamSpec->Init(*data + compressHeader.DataPos, packSize);
+    
+    if (compressHeader.Method == kMethod_ZLIB_ATTR)
+    {
+      const HRESULT hres = _zlibDecoder->Code(bufInStream, realOutStream,
+          NULL, &compressHeader.UnpackSize, NULL);
+      if (hres == S_OK)
+        if (_zlibDecoderSpec->GetOutputProcessedSize() == compressHeader.UnpackSize
+            && _zlibDecoderSpec->GetInputProcessedSize() == packSize)
+          opRes = NExtract::NOperationResult::kOK;
+      return hres;
+    }
+    {
+      const UInt64 packSize64 = packSize;
+      const HRESULT hres = _lzfseDecoder->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);
+  }
+  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
+
+  CDecoder decoder;
+
+  for (i = 0;; i++, currentTotalSize += currentItemSize)
+  {
+    RINOK(extractCallback->SetCompleted(&currentTotalSize))
+    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);
+
+    CMyComPtr<ISequentialOutStream> 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;
+    int 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<ISequentialInStream> 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;
+      }
+    }
+    realOutStream.Release();
+    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;
+
+  CExtentsStream *extentStreamSpec = new CExtentsStream();
+  CMyComPtr<ISequentialInStream> extentStream = extentStreamSpec;
+
+  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;
+    extentStreamSpec->Extents.Add(se);
+  }
+  
+  if (rem != 0)
+    return S_FALSE;
+  
+  CSeekExtent se;
+  se.Phy = 0;
+  se.Virt = virt;
+  extentStreamSpec->Extents.Add(se);
+  extentStreamSpec->Stream = _stream;
+  extentStreamSpec->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
new file mode 100644
index 0000000..0006e12
--- /dev/null
+++ b/CPP/7zip/Archive/HfsHandler.h
@@ -0,0 +1,90 @@
+// 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
+{
+  NCompress::NZlib::CDecoder *_zlibDecoderSpec;
+  CMyComPtr<ICompressCoder> _zlibDecoder;
+
+  NCompress::NLzfse::CDecoder *_lzfseDecoderSpec;
+  CMyComPtr<ICompressCoder> _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();
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/IArchive.h b/CPP/7zip/Archive/IArchive.h
index 96451a6..3e68ac3 100644
--- a/CPP/7zip/Archive/IArchive.h
+++ b/CPP/7zip/Archive/IArchive.h
@@ -1,608 +1,704 @@
-// IArchive.h

-

-#ifndef __IARCHIVE_H

-#define __IARCHIVE_H

-

-#include "../IProgress.h"

-#include "../IStream.h"

-#include "../PropID.h"

-

-#define ARCHIVE_INTERFACE_SUB(i, base, x) DECL_INTERFACE_SUB(i, base, 6, x)

-#define ARCHIVE_INTERFACE(i, x) ARCHIVE_INTERFACE_SUB(i, IUnknown, x)

-

-namespace NFileTimeType

-{

-  enum EEnum

-  {

-    kWindows,

-    kUnix,

-    kDOS

-  };

-}

-

-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

-}

-

-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

-      // kVersion          // VT_UI4 ((VER_MAJOR << 8) | VER_MINOR)

-    };

-  }

-

-  namespace NExtract

-  {

-    namespace NAskMode

-    {

-      enum

-      {

-        kExtract = 0,

-        kTest,

-        kSkip

-      };

-    }

-  

-    namespace NOperationResult

-    {

-      enum

-      {

-        kOK = 0,

-        kUnsupportedMethod,

-        kDataError,

-        kCRCError,

-        kUnavailable,

-        kUnexpectedEnd,

-        kDataAfterEnd,

-        kIsNotArc,

-        kHeadersError,

-        kWrongPassword

-      };

-    }

-  }

-

-  namespace NEventIndexType

-  {

-    enum

-    {

-      kNoIndex = 0,

-      kInArcIndex,

-      kBlockIndex,

-      kOutArcIndex

-    };

-  }

-  

-  namespace NUpdate

-  {

-    namespace NOperationResult

-    {

-      enum

-      {

-        kOK = 0

-        , // kError

-      };

-    }

-  }

-}

-

-#define INTERFACE_IArchiveOpenCallback(x) \

-  STDMETHOD(SetTotal)(const UInt64 *files, const UInt64 *bytes) x; \

-  STDMETHOD(SetCompleted)(const UInt64 *files, const UInt64 *bytes) x; \

-

-ARCHIVE_INTERFACE(IArchiveOpenCallback, 0x10)

-{

-  INTERFACE_IArchiveOpenCallback(PURE);

-};

-

-/*

-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 can not real stream: (*inStream == NULL)

-    }

-  

-  Out:

-      (*inStream == NULL) - for directories

-      (*inStream == NULL) - if link (hard link or symbolic link) was created

-      if (*inStream == 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)

-*/

-

-#define INTERFACE_IArchiveExtractCallback(x) \

-  INTERFACE_IProgress(x) \

-  STDMETHOD(GetStream)(UInt32 index, ISequentialOutStream **outStream, Int32 askExtractMode) x; \

-  STDMETHOD(PrepareOperation)(Int32 askExtractMode) x; \

-  STDMETHOD(SetOperationResult)(Int32 opRes) x; \

-

-ARCHIVE_INTERFACE_SUB(IArchiveExtractCallback, IProgress, 0x20)

-{

-  INTERFACE_IArchiveExtractCallback(PURE)

-};

-

-

-

-/*

-IArchiveExtractCallbackMessage 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)

-*/

-

-#define INTERFACE_IArchiveExtractCallbackMessage(x) \

-  STDMETHOD(ReportExtractResult)(UInt32 indexType, UInt32 index, Int32 opRes) x; \

-

-ARCHIVE_INTERFACE_SUB(IArchiveExtractCallbackMessage, IProgress, 0x21)

-{

-  INTERFACE_IArchiveExtractCallbackMessage(PURE)

-};

-

-

-#define INTERFACE_IArchiveOpenVolumeCallback(x) \

-  STDMETHOD(GetProperty)(PROPID propID, PROPVARIANT *value) x; \

-  STDMETHOD(GetStream)(const wchar_t *name, IInStream **inStream) x; \

-

-ARCHIVE_INTERFACE(IArchiveOpenVolumeCallback, 0x30)

-{

-  INTERFACE_IArchiveOpenVolumeCallback(PURE);

-};

-

-

-ARCHIVE_INTERFACE(IInArchiveGetStream, 0x40)

-{

-  STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream) PURE;

-};

-

-

-ARCHIVE_INTERFACE(IArchiveOpenSetSubArchiveName, 0x50)

-{

-  STDMETHOD(SetSubArchiveName)(const wchar_t *name) PURE;

-};

-

-

-/*

-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.

-*/

-

-#ifdef _MSC_VER

-  #define MY_NO_THROW_DECL_ONLY throw()

-#else

-  #define MY_NO_THROW_DECL_ONLY

-#endif

-

-#define INTERFACE_IInArchive(x) \

-  STDMETHOD(Open)(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *openCallback) MY_NO_THROW_DECL_ONLY x; \

-  STDMETHOD(Close)() MY_NO_THROW_DECL_ONLY x; \

-  STDMETHOD(GetNumberOfItems)(UInt32 *numItems) MY_NO_THROW_DECL_ONLY x; \

-  STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value) MY_NO_THROW_DECL_ONLY x; \

-  STDMETHOD(Extract)(const UInt32* indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) MY_NO_THROW_DECL_ONLY x; \

-  STDMETHOD(GetArchiveProperty)(PROPID propID, PROPVARIANT *value) MY_NO_THROW_DECL_ONLY x; \

-  STDMETHOD(GetNumberOfProperties)(UInt32 *numProps) MY_NO_THROW_DECL_ONLY x; \

-  STDMETHOD(GetPropertyInfo)(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) MY_NO_THROW_DECL_ONLY x; \

-  STDMETHOD(GetNumberOfArchiveProperties)(UInt32 *numProps) MY_NO_THROW_DECL_ONLY x; \

-  STDMETHOD(GetArchivePropertyInfo)(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) MY_NO_THROW_DECL_ONLY x; \

-

-ARCHIVE_INTERFACE(IInArchive, 0x60)

-{

-  INTERFACE_IInArchive(PURE)

-};

-

-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 INTERFACE_IArchiveGetRawProps(x) \

-  STDMETHOD(GetParent)(UInt32 index, UInt32 *parent, UInt32 *parentType) x; \

-  STDMETHOD(GetRawProp)(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType) x; \

-  STDMETHOD(GetNumRawProps)(UInt32 *numProps) x; \

-  STDMETHOD(GetRawPropInfo)(UInt32 index, BSTR *name, PROPID *propID) x;

-

-ARCHIVE_INTERFACE(IArchiveGetRawProps, 0x70)

-{

-  INTERFACE_IArchiveGetRawProps(PURE)

-};

-

-#define INTERFACE_IArchiveGetRootProps(x) \

-  STDMETHOD(GetRootProp)(PROPID propID, PROPVARIANT *value) x; \

-  STDMETHOD(GetRootRawProp)(PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType) x; \

- 

-ARCHIVE_INTERFACE(IArchiveGetRootProps, 0x71)

-{

-  INTERFACE_IArchiveGetRootProps(PURE)

-};

-

-ARCHIVE_INTERFACE(IArchiveOpenSeq, 0x61)

-{

-  STDMETHOD(OpenSeq)(ISequentialInStream *stream) PURE;

-};

-

-/*

-  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.

-*/

-

-/*

-ARCHIVE_INTERFACE(IArchiveOpen2, 0x62)

-{

-  STDMETHOD(ArcOpen2)(ISequentialInStream *stream, UInt32 flags, IArchiveOpenCallback *openCallback) PURE;

-};

-*/

-

-// ---------- 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)

-*/

-

-#define INTERFACE_IArchiveUpdateCallback(x) \

-  INTERFACE_IProgress(x); \

-  STDMETHOD(GetUpdateItemInfo)(UInt32 index, Int32 *newData, Int32 *newProps, UInt32 *indexInArchive) x; \

-  STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value) x; \

-  STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **inStream) x; \

-  STDMETHOD(SetOperationResult)(Int32 operationResult) x; \

-

-ARCHIVE_INTERFACE_SUB(IArchiveUpdateCallback, IProgress, 0x80)

-{

-  INTERFACE_IArchiveUpdateCallback(PURE);

-};

-

-#define INTERFACE_IArchiveUpdateCallback2(x) \

-  INTERFACE_IArchiveUpdateCallback(x) \

-  STDMETHOD(GetVolumeSize)(UInt32 index, UInt64 *size) x; \

-  STDMETHOD(GetVolumeStream)(UInt32 index, ISequentialOutStream **volumeStream) x; \

-

-ARCHIVE_INTERFACE_SUB(IArchiveUpdateCallback2, IArchiveUpdateCallback, 0x82)

-{

-  INTERFACE_IArchiveUpdateCallback2(PURE);

-};

-

-namespace NUpdateNotifyOp

-{

-  enum

-  {

-    kAdd = 0,

-    kUpdate,

-    kAnalyze,

-    kReplicate,

-    kRepack,

-    kSkip,

-    kDelete,

-    kHeader

-

-    // kNumDefined

-  };

-};

-

-/*

-IArchiveUpdateCallbackFile::ReportOperation

-  UInt32 indexType (NEventIndexType)

-  UInt32 index

-  UInt32 notifyOp (NUpdateNotifyOp)

-*/

-

-#define INTERFACE_IArchiveUpdateCallbackFile(x) \

-  STDMETHOD(GetStream2)(UInt32 index, ISequentialInStream **inStream, UInt32 notifyOp) x; \

-  STDMETHOD(ReportOperation)(UInt32 indexType, UInt32 index, UInt32 notifyOp) x; \

-

-ARCHIVE_INTERFACE(IArchiveUpdateCallbackFile, 0x83)

-{

-  INTERFACE_IArchiveUpdateCallbackFile(PURE);

-};

-

-

-/*

-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 INTERFACE_IOutArchive(x) \

-  STDMETHOD(UpdateItems)(ISequentialOutStream *outStream, UInt32 numItems, IArchiveUpdateCallback *updateCallback) x; \

-  STDMETHOD(GetFileTimeType)(UInt32 *type) x;

-

-ARCHIVE_INTERFACE(IOutArchive, 0xA0)

-{

-  INTERFACE_IOutArchive(PURE)

-};

-

-

-/*

-ISetProperties::SetProperties()

-  PROPVARIANT values[i].vt:

-    VT_EMPTY

-    VT_BOOL

-    VT_UI4   - if 32-bit number

-    VT_UI8   - if 64-bit number

-    VT_BSTR

-*/

-

-ARCHIVE_INTERFACE(ISetProperties, 0x03)

-{

-  STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps) PURE;

-};

-

-ARCHIVE_INTERFACE(IArchiveKeepModeForNextOpen, 0x04)

-{

-  STDMETHOD(KeepModeForNextOpen)() PURE;

-};

-

-/* 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 */

-

-ARCHIVE_INTERFACE(IArchiveAllowTail, 0x05)

-{

-  STDMETHOD(AllowTail)(Int32 allowTail) PURE;

-};

-

-

-#define IMP_IInArchive_GetProp(k) \

-  (UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) \

-    { if (index >= ARRAY_SIZE(k)) return E_INVALIDARG; \

-    *propID = k[index]; *varType = k7z_PROPID_To_VARTYPE[(unsigned)*propID];  *name = 0; return S_OK; } \

-

-

-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_WITH_NAME(k) \

-  (UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) \

-    { if (index >= ARRAY_SIZE(k)) return E_INVALIDARG; \

-    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 \

-  STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProps) \

-    { *numProps = ARRAY_SIZE(kProps); return S_OK; } \

-  STDMETHODIMP CHandler::GetPropertyInfo IMP_IInArchive_GetProp(kProps)

-

-#define IMP_IInArchive_Props_WITH_NAME \

-  STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProps) \

-    { *numProps = ARRAY_SIZE(kProps); return S_OK; } \

-  STDMETHODIMP CHandler::GetPropertyInfo IMP_IInArchive_GetProp_WITH_NAME(kProps)

-

-

-#define IMP_IInArchive_ArcProps \

-  STDMETHODIMP CHandler::GetNumberOfArchiveProperties(UInt32 *numProps) \

-    { *numProps = ARRAY_SIZE(kArcProps); return S_OK; } \

-  STDMETHODIMP CHandler::GetArchivePropertyInfo IMP_IInArchive_GetProp(kArcProps)

-

-#define IMP_IInArchive_ArcProps_WITH_NAME \

-  STDMETHODIMP CHandler::GetNumberOfArchiveProperties(UInt32 *numProps) \

-    { *numProps = ARRAY_SIZE(kArcProps); return S_OK; } \

-  STDMETHODIMP CHandler::GetArchivePropertyInfo IMP_IInArchive_GetProp_WITH_NAME(kArcProps)

-

-#define IMP_IInArchive_ArcProps_NO_Table \

-  STDMETHODIMP CHandler::GetNumberOfArchiveProperties(UInt32 *numProps) \

-    { *numProps = 0; return S_OK; } \

-  STDMETHODIMP CHandler::GetArchivePropertyInfo(UInt32, BSTR *, PROPID *, VARTYPE *) \

-    { return E_NOTIMPL; } \

-

-#define IMP_IInArchive_ArcProps_NO \

-  IMP_IInArchive_ArcProps_NO_Table \

-  STDMETHODIMP CHandler::GetArchiveProperty(PROPID, PROPVARIANT *value) \

-    { value->vt = VT_EMPTY; return S_OK; }

-

-

-

-#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 IOutArchive * (*Func_CreateOutArchive)();

-  typedef IInArchive * (*Func_CreateInArchive)();

-}

-

-#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)
+
+
+
+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/Icons/apfs.ico b/CPP/7zip/Archive/Icons/apfs.ico
new file mode 100644
index 0000000..124eb76
--- /dev/null
+++ b/CPP/7zip/Archive/Icons/apfs.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/arj.ico b/CPP/7zip/Archive/Icons/arj.ico
new file mode 100644
index 0000000..c0f8b14
--- /dev/null
+++ b/CPP/7zip/Archive/Icons/arj.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/bz2.ico b/CPP/7zip/Archive/Icons/bz2.ico
new file mode 100644
index 0000000..f22abeb
--- /dev/null
+++ b/CPP/7zip/Archive/Icons/bz2.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/cab.ico b/CPP/7zip/Archive/Icons/cab.ico
new file mode 100644
index 0000000..c96c0f0
--- /dev/null
+++ b/CPP/7zip/Archive/Icons/cab.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/cpio.ico b/CPP/7zip/Archive/Icons/cpio.ico
new file mode 100644
index 0000000..9abaabc
--- /dev/null
+++ b/CPP/7zip/Archive/Icons/cpio.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/deb.ico b/CPP/7zip/Archive/Icons/deb.ico
new file mode 100644
index 0000000..97a0865
--- /dev/null
+++ b/CPP/7zip/Archive/Icons/deb.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/dmg.ico b/CPP/7zip/Archive/Icons/dmg.ico
new file mode 100644
index 0000000..7d63b09
--- /dev/null
+++ b/CPP/7zip/Archive/Icons/dmg.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/fat.ico b/CPP/7zip/Archive/Icons/fat.ico
new file mode 100644
index 0000000..7503d93
--- /dev/null
+++ b/CPP/7zip/Archive/Icons/fat.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/gz.ico b/CPP/7zip/Archive/Icons/gz.ico
new file mode 100644
index 0000000..d402a69
--- /dev/null
+++ b/CPP/7zip/Archive/Icons/gz.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/hfs.ico b/CPP/7zip/Archive/Icons/hfs.ico
new file mode 100644
index 0000000..bf2c198
--- /dev/null
+++ b/CPP/7zip/Archive/Icons/hfs.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/iso.ico b/CPP/7zip/Archive/Icons/iso.ico
new file mode 100644
index 0000000..b3e3ac2
--- /dev/null
+++ b/CPP/7zip/Archive/Icons/iso.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/lzh.ico b/CPP/7zip/Archive/Icons/lzh.ico
new file mode 100644
index 0000000..84dab49
--- /dev/null
+++ b/CPP/7zip/Archive/Icons/lzh.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/lzma.ico b/CPP/7zip/Archive/Icons/lzma.ico
new file mode 100644
index 0000000..2de2c24
--- /dev/null
+++ b/CPP/7zip/Archive/Icons/lzma.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/ntfs.ico b/CPP/7zip/Archive/Icons/ntfs.ico
new file mode 100644
index 0000000..6b2aeb0
--- /dev/null
+++ b/CPP/7zip/Archive/Icons/ntfs.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/rar.ico b/CPP/7zip/Archive/Icons/rar.ico
new file mode 100644
index 0000000..2918d29
--- /dev/null
+++ b/CPP/7zip/Archive/Icons/rar.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/rpm.ico b/CPP/7zip/Archive/Icons/rpm.ico
new file mode 100644
index 0000000..cdeb8d1
--- /dev/null
+++ b/CPP/7zip/Archive/Icons/rpm.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/split.ico b/CPP/7zip/Archive/Icons/split.ico
new file mode 100644
index 0000000..65723ff
--- /dev/null
+++ b/CPP/7zip/Archive/Icons/split.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/squashfs.ico b/CPP/7zip/Archive/Icons/squashfs.ico
new file mode 100644
index 0000000..b802d94
--- /dev/null
+++ b/CPP/7zip/Archive/Icons/squashfs.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/tar.ico b/CPP/7zip/Archive/Icons/tar.ico
new file mode 100644
index 0000000..6835885
--- /dev/null
+++ b/CPP/7zip/Archive/Icons/tar.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/vhd.ico b/CPP/7zip/Archive/Icons/vhd.ico
new file mode 100644
index 0000000..33bed3c
--- /dev/null
+++ b/CPP/7zip/Archive/Icons/vhd.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/wim.ico b/CPP/7zip/Archive/Icons/wim.ico
new file mode 100644
index 0000000..887975e
--- /dev/null
+++ b/CPP/7zip/Archive/Icons/wim.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/xar.ico b/CPP/7zip/Archive/Icons/xar.ico
new file mode 100644
index 0000000..281aa7d
--- /dev/null
+++ b/CPP/7zip/Archive/Icons/xar.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/xz.ico b/CPP/7zip/Archive/Icons/xz.ico
new file mode 100644
index 0000000..bc07a7e
--- /dev/null
+++ b/CPP/7zip/Archive/Icons/xz.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/z.ico b/CPP/7zip/Archive/Icons/z.ico
new file mode 100644
index 0000000..2db5358
--- /dev/null
+++ b/CPP/7zip/Archive/Icons/z.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/zip.ico b/CPP/7zip/Archive/Icons/zip.ico
new file mode 100644
index 0000000..2af4606
--- /dev/null
+++ b/CPP/7zip/Archive/Icons/zip.ico
Binary files differ
diff --git a/CPP/7zip/Archive/IhexHandler.cpp b/CPP/7zip/Archive/IhexHandler.cpp
new file mode 100644
index 0000000..badb559
--- /dev/null
+++ b/CPP/7zip/Archive/IhexHandler.cpp
@@ -0,0 +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/MyVector.h"
+
+#include "../../Windows/PropVariant.h"
+
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+#include "../Common/InBuffer.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<CBlock> _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;
+    }
+  }
+  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 inline int HexToByte(unsigned c)
+{
+  if (c >= '0' && c <= '9') return (int)(c - '0');
+  if (c >= 'A' && c <= 'F') return (int)(c - 'A' + 10);
+  if (c >= 'a' && c <= 'f') return (int)(c - 'a' + 10);
+  return -1;
+}
+
+static int Parse(const Byte *p)
+{
+  const int c1 = HexToByte(p[0]); if (c1 < 0) return -1;
+  const int c2 = HexToByte(p[1]); if (c2 < 0) return -1;
+  return (c1 << 4) | c2;
+}
+  
+#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
+
+#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;
+    
+    int num = Parse(p);
+    if (num < 0)
+      return k_IsArc_Res_NO;
+    
+    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) != 0)
+      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;
+    
+    for (;;)
+    {
+      if (size == 0)
+        return k_IsArc_Res_NEED_MORE;
+      const Byte b = *p++;
+      size--;
+      if (IS_LINE_DELIMITER(b))
+        continue;
+      if (b == ':')
+        break;
+      return k_IsArc_Res_NO;
+    }
+  }
+  
+  return k_IsArc_Res_YES;
+}
+}
+
+Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *))
+{
+  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))
+      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;
+
+    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;
+      }
+      
+      {
+        size_t numPairs = ((unsigned)num + 4);
+        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) != 0)
+        {
+          _dataError = true;
+          return S_FALSE;
+        }
+      }
+
+      unsigned type = temp[2];
+      if (type > kType_MAX)
+      {
+        _dataError = true;
+        return S_FALSE;
+      }
+
+      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)
+        {
+          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 (type == kType_Eof)
+      {
+        _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;
+      }
+      else
+      {
+        if (a != 0)
+        {
+          _dataError = true;
+          return S_FALSE;
+        }
+        if (type == kType_Seg || type == kType_High)
+        {
+          if (num != 2)
+          {
+            _dataError = true;
+            return S_FALSE;
+          }
+          UInt32 d = GetBe16(temp + 3);
+          globalOffset = d << (type == kType_Seg ? 4 : 16);
+        }
+        else
+        {
+          if (num != 4)
+          {
+            _dataError = true;
+            return S_FALSE;
+          }
+        }
+      }
+
+      for (;;)
+      {
+        Byte b;
+        if (!s.ReadByte(b))
+        {
+          _needMoreInput = true;
+          return S_FALSE;
+        }
+        if (IS_LINE_DELIMITER(b))
+          continue;
+        if (b == ':')
+          break;
+        _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();
+  extractCallback->SetTotal(totalSize);
+
+  UInt64 currentTotalSize = 0;
+  UInt64 currentItemSize;
+
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> progress = lps;
+  lps->Init(extractCallback, false);
+
+  for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
+  {
+    currentItemSize = 0;
+    lps->InSize = lps->OutSize = currentTotalSize;
+    RINOK(lps->SetCur())
+
+    const UInt32 index = allFilesMode ? i : indices[i];
+    const CByteDynamicBuffer &data = _blocks[index].Data;
+    currentItemSize = data.GetPos();
+    
+    CMyComPtr<ISequentialOutStream> realOutStream;
+    const Int32 askMode = testMode ?
+        NExtract::NAskMode::kTest :
+        NExtract::NAskMode::kExtract;
+    
+    RINOK(extractCallback->GetStream(index, &realOutStream, askMode))
+    
+    if (!testMode && !realOutStream)
+      continue;
+    
+    extractCallback->PrepareOperation(askMode);
+    
+    if (realOutStream)
+    {
+      RINOK(WriteStream(realOutStream, (const Byte *)data, data.GetPos()))
+    }
+  
+    realOutStream.Release();
+    RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
+  }
+  
+  lps->InSize = lps->OutSize = currentTotalSize;
+  return lps->SetCur();
+
+  COM_TRY_END
+}
+
+// k_Signature: { ':', '1' }
+
+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
new file mode 100644
index 0000000..0c63c71
--- /dev/null
+++ b/CPP/7zip/Archive/Iso/IsoHandler.cpp
@@ -0,0 +1,486 @@
+// 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 += '\n';
+    s += name;
+    s += ": ";
+    s += d;
+  }
+}
+
+#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);
+      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());
+  }
+  extractCallback->SetTotal(totalSize);
+
+  UInt64 currentTotalSize = 0;
+  UInt64 currentItemSize;
+  
+  NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+  CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> progress = lps;
+  lps->Init(extractCallback, false);
+
+  CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+  CMyComPtr<ISequentialInStream> inStream(streamSpec);
+  streamSpec->SetStream(_stream);
+
+  for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
+  {
+    lps->InSize = lps->OutSize = currentTotalSize;
+    RINOK(lps->SetCur())
+    currentItemSize = 0;
+    CMyComPtr<ISequentialOutStream> 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))
+
+    bool isOK = true;
+    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))
+        streamSpec->Init(item2.Size);
+        RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress))
+        if (copyCoderSpec->TotalSize != item2.Size)
+        {
+          isOK = false;
+          break;
+        }
+        offset += item2.Size;
+      }
+    }
+    else
+    {
+      RINOK(InStream_SeekSet(_stream, (UInt64)blockIndex * kBlockSize))
+      streamSpec->Init(currentItemSize);
+      RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress))
+      if (copyCoderSpec->TotalSize != currentItemSize)
+        isOK = false;
+    }
+    realOutStream.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;
+  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<ISequentialInStream> 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
new file mode 100644
index 0000000..507814a
--- /dev/null
+++ b/CPP/7zip/Archive/Iso/IsoHandler.h
@@ -0,0 +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<IInStream> _stream;
+  CInArchive _archive;
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/Iso/IsoHeader.cpp b/CPP/7zip/Archive/Iso/IsoHeader.cpp
new file mode 100644
index 0000000..3b59060
--- /dev/null
+++ b/CPP/7zip/Archive/Iso/IsoHeader.cpp
@@ -0,0 +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";
+
+}}
diff --git a/CPP/7zip/Archive/Iso/IsoHeader.h b/CPP/7zip/Archive/Iso/IsoHeader.h
new file mode 100644
index 0000000..0b14c9f
--- /dev/null
+++ b/CPP/7zip/Archive/Iso/IsoHeader.h
@@ -0,0 +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
diff --git a/CPP/7zip/Archive/Iso/IsoIn.cpp b/CPP/7zip/Archive/Iso/IsoIn.cpp
new file mode 100644
index 0000000..1d3a42f
--- /dev/null
+++ b/CPP/7zip/Archive/Iso/IsoIn.cpp
@@ -0,0 +1,693 @@
+// 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);
+  d.FileStructureVersion = ReadByte(); // = 1
+  SkipZeros(1);
+  ReadBytes(d.ApplicationUse, sizeof(d.ApplicationUse));
+
+  // Most ISO contains 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;
+  
+  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);
+      }
+    }
+  }
+  {
+    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;
+}
+
+
+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;
+    if (rem < size)
+      size = rem;
+  }
+  return size;
+}
+
+}}
diff --git a/CPP/7zip/Archive/Iso/IsoIn.h b/CPP/7zip/Archive/Iso/IsoIn.h
new file mode 100644
index 0000000..f3e4751
--- /dev/null
+++ b/CPP/7zip/Archive/Iso/IsoIn.h
@@ -0,0 +1,318 @@
+// 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<CDir> _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;
+    Byte b = EscapeSequence[2];
+    return (EscapeSequence[0] == 0x25 && EscapeSequence[1] == 0x2F &&
+      (b == 0x40 || b == 0x43 || b == 0x45));
+  }
+};
+
+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<CRef> Refs;
+  CObjectVector<CVolumeDescriptor> VolDescs;
+  int MainVolDescIndex;
+  // UInt32 BlockSize;
+  CObjectVector<CBootInitialEntry> BootEntries;
+
+private:
+  bool _bootIsDefined;
+public:
+  bool IsArc;
+  bool UnexpectedEnd;
+  bool HeadersError;
+  bool IncorrectBigEndian;
+  bool TooDeepDirs;
+  bool SelfLinkedDirs;
+  bool IsSusp;
+  unsigned SuspSkipSize;
+
+  CRecordVector<UInt32> 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
new file mode 100644
index 0000000..9556805
--- /dev/null
+++ b/CPP/7zip/Archive/Iso/IsoItem.h
@@ -0,0 +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 += '/';
+      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 += '/';
+    }
+
+    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
new file mode 100644
index 0000000..41b56ba
--- /dev/null
+++ b/CPP/7zip/Archive/Iso/IsoRegister.cpp
@@ -0,0 +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)
+
+}}
diff --git a/CPP/7zip/Archive/Iso/StdAfx.h b/CPP/7zip/Archive/Iso/StdAfx.h
new file mode 100644
index 0000000..035267c
--- /dev/null
+++ b/CPP/7zip/Archive/Iso/StdAfx.h
@@ -0,0 +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
diff --git a/CPP/7zip/Archive/LpHandler.cpp b/CPP/7zip/Archive/LpHandler.cpp
new file mode 100644
index 0000000..c1a76b4
--- /dev/null
+++ b/CPP/7zip/Archive/LpHandler.cpp
@@ -0,0 +1,1166 @@
+// 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<CPartition> _items;
+  CRecordVector<CExtent> Extents;
+
+  CMyComPtr<IInStream> _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<CDevice> 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<ISequentialInStream> 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<ISequentialInStream> 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<ICompressCoder> copyCoder = copyCoderSpec;
+
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> progress = lps;
+  lps->Init(extractCallback, false);
+
+  for (i = 0; i < numItems; i++)
+  {
+    lps->InSize = totalSize;
+    lps->OutSize = totalSize;
+    RINOK(lps->SetCur())
+    CMyComPtr<ISequentialOutStream> 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<ISequentialInStream> 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/LzhHandler.cpp b/CPP/7zip/Archive/LzhHandler.cpp
new file mode 100644
index 0000000..9239afd
--- /dev/null
+++ b/CPP/7zip/Archive/LzhHandler.cpp
@@ -0,0 +1,733 @@
+// LzhHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.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;
+
+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<CExtension> 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)(unsigned char)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<ISequentialOutStream> _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<CItemEx> _items;
+  CMyComPtr<IInStream> _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 = item.Size; break;
+    case kpidPackSize:  prop = 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)
+        {
+          UInt64 numFiles = _items.Size();
+          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))
+
+  UInt64 currentItemUnPacked, currentItemPacked;
+  
+  NCompress::NLzh::NDecoder::CCoder *lzhDecoderSpec = NULL;
+  CMyComPtr<ICompressCoder> lzhDecoder;
+  // CMyComPtr<ICompressCoder> lzh1Decoder;
+  // CMyComPtr<ICompressCoder> arj2Decoder;
+
+  NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+  CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> progress = lps;
+  lps->Init(extractCallback, false);
+
+  CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+  CMyComPtr<ISequentialInStream> inStream(streamSpec);
+  streamSpec->SetStream(_stream);
+
+  for (i = 0;; i++,
+      lps->OutSize += currentItemUnPacked,
+      lps->InSize += currentItemPacked)
+  {
+    currentItemUnPacked = 0;
+    currentItemPacked = 0;
+
+    RINOK(lps->SetCur())
+
+    if (i >= numItems)
+      break;
+
+    CMyComPtr<ISequentialOutStream> 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))
+    currentItemUnPacked = item.Size;
+    currentItemPacked = item.PackSize;
+
+    {
+      COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC;
+      CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+      outStreamSpec->Init(realOutStream);
+      realOutStream.Release();
+      
+      RINOK(InStream_SeekSet(_stream, item.DataPosition))
+
+      streamSpec->Init(item.PackSize);
+
+      HRESULT res = S_OK;
+      Int32 opRes = NExtract::NOperationResult::kOK;
+
+      if (item.IsCopyMethod())
+      {
+        res = copyCoder->Code(inStream, outStream, NULL, NULL, progress);
+        if (res == S_OK && copyCoderSpec->TotalSize != item.PackSize)
+          res = S_FALSE;
+      }
+      else if (item.IsLh4GroupMethod())
+      {
+        if (!lzhDecoder)
+        {
+          lzhDecoderSpec = new NCompress::NLzh::NDecoder::CCoder;
+          lzhDecoder = lzhDecoderSpec;
+        }
+        lzhDecoderSpec->FinishMode = true;
+        lzhDecoderSpec->SetDictSize(1 << item.GetNumDictBits());
+        res = lzhDecoder->Code(inStream, outStream, NULL, &currentItemUnPacked, progress);
+        if (res == S_OK && lzhDecoderSpec->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, &currentItemUnPacked, progress);
+      }
+      */
+      else
+        opRes = NExtract::NOperationResult::kUnsupportedMethod;
+
+      if (opRes == NExtract::NOperationResult::kOK)
+      {
+        if (res == S_FALSE)
+          opRes = NExtract::NOperationResult::kDataError;
+        else
+        {
+          RINOK(res)
+          if (outStreamSpec->GetCRC() != item.CRC)
+            opRes = NExtract::NOperationResult::kCRCError;
+        }
+      }
+      outStream.Release();
+      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 f13fca7..11cb76e 100644
--- a/CPP/7zip/Archive/LzmaHandler.cpp
+++ b/CPP/7zip/Archive/LzmaHandler.cpp
@@ -1,629 +1,611 @@
-// 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

-{

-  CMyComPtr<ISequentialOutStream> _bcjStream;

-  CFilterCoder *_filterCoder;

-  CMyComPtr<ICompressCoder> _lzmaDecoder;

-public:

-  NCompress::NLzma::CDecoder *_lzmaDecoderSpec;

-

-  ~CDecoder();

-  HRESULT Create(bool filtered, ISequentialInStream *inStream);

-

-  HRESULT Code(const CHeader &header, ISequentialOutStream *outStream, ICompressProgressInfo *progress);

-

-  UInt64 GetInputProcessedSize() const { return _lzmaDecoderSpec->GetInputProcessedSize(); }

-

-  void ReleaseInStream() { if (_lzmaDecoder) _lzmaDecoderSpec->ReleaseInStream(); }

-

-  HRESULT ReadInput(Byte *data, UInt32 size, UInt32 *processedSize)

-    { return _lzmaDecoderSpec->ReadFromInputStream(data, size, processedSize); }

-};

-

-HRESULT CDecoder::Create(bool filteredMode, ISequentialInStream *inStream)

-{

-  if (!_lzmaDecoder)

-  {

-    _lzmaDecoderSpec = new NCompress::NLzma::CDecoder;

-    _lzmaDecoderSpec->FinishStream = true;

-    _lzmaDecoder = _lzmaDecoderSpec;

-  }

-

-  if (filteredMode)

-  {

-    if (!_bcjStream)

-    {

-      _filterCoder = new CFilterCoder(false);

-      CMyComPtr<ICompressCoder> coder = _filterCoder;

-      _filterCoder->Filter = new NCompress::NBcj::CCoder(false);

-      _bcjStream = _filterCoder;

-    }

-  }

-

-  return _lzmaDecoderSpec->SetInStream(inStream);

-}

-

-CDecoder::~CDecoder()

-{

-  ReleaseInStream();

-}

-

-HRESULT CDecoder::Code(const CHeader &header, ISequentialOutStream *outStream,

-    ICompressProgressInfo *progress)

-{

-  if (header.FilterID > 1)

-    return E_NOTIMPL;

-

-  RINOK(_lzmaDecoderSpec->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 = _lzmaDecoderSpec->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 (_lzmaDecoderSpec->GetOutputProcessedSize() != header.Size)

-      return S_FALSE;

-

-  return S_OK;

-}

-

-

-class CHandler:

-  public IInArchive,

-  public IArchiveOpenSeq,

-  public CMyUnknownImp

-{

-  CHeader _header;

-  bool _lzma86;

-  CMyComPtr<IInStream> _stream;

-  CMyComPtr<ISequentialInStream> _seqStream;

-  

-  bool _isArc;

-  bool _needSeekToStart;

-  bool _dataAfterEnd;

-  bool _needMoreInput;

-

-  bool _packSize_Defined;

-  bool _unpackSize_Defined;

-  bool _numStreams_Defined;

-

-  bool _unsupported;

-  bool _dataError;

-

-  UInt64 _packSize;

-  UInt64 _unpackSize;

-  UInt64 _numStreams;

-

-  void GetMethod(NCOM::CPropVariant &prop);

-

-public:

-  MY_UNKNOWN_IMP2(IInArchive, IArchiveOpenSeq)

-

-  INTERFACE_IInArchive(;)

-  STDMETHOD(OpenSeq)(ISequentialInStream *stream);

-

-  CHandler(bool lzma86) { _lzma86 = lzma86; }

-

-  unsigned GetHeaderSize() const { return 5 + 8 + (_lzma86 ? 1 : 0); }

-

-};

-

-IMP_IInArchive_Props

-IMP_IInArchive_ArcProps

-

-STDMETHODIMP 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;

-    }

-  }

-  prop.Detach(value);

-  return S_OK;

-}

-

-STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)

-{

-  *numItems = 1;

-  return S_OK;

-}

-

-

-static void DictSizeToString(UInt32 val, char *s)

-{

-  for (unsigned i = 0; i <= 31; i++)

-    if (((UInt32)1 << i) == val)

-    {

-      ::ConvertUInt32ToString(i, s);

-      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'; }

-  ::ConvertUInt32ToString(val, s);

-  s += MyStringLen(s);

-  *s++ = c;

-  *s = 0;

-}

-

-static char *AddProp32(char *s, const char *name, UInt32 v)

-{

-  *s++ = ':';

-  s = MyStpCpy(s, name);

-  ::ConvertUInt32ToString(v, s);

-  return s + MyStringLen(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:");

-  DictSizeToString(_header.GetDicSize(), s);

-  s += strlen(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;

-}

-

-

-STDMETHODIMP 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;

-  }

-  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;

-  UInt64 unpackSize = GetUi64(p + 1 + 4);

-  if (unpackSize != (UInt64)(Int64)-1)

-  {

-    if (size >= ((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);

-}

-}

-

-

-

-STDMETHODIMP 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->Seek(0, STREAM_SEEK_END, &_packSize));

-

-  SizeT srcLen = processedSize - headerSize;

-

-  if (srcLen > 10

-      && _header.Size == 0

-      // && _header.FilterID == 0

-      && _header.LzmaProps[0] == 0

-      )

-    return S_FALSE;

-

-  CDecoder state;

-  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;

-}

-

-STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream)

-{

-  Close();

-  _isArc = true;

-  _seqStream = stream;

-  return S_OK;

-}

-

-STDMETHODIMP CHandler::Close()

-{

-  _isArc = false;

-  _packSize_Defined = false;

-  _unpackSize_Defined = false;

-  _numStreams_Defined = false;

-

-  _dataAfterEnd = false;

-  _needMoreInput = false;

-  _unsupported = false;

-  _dataError = false;

-

-  _packSize = 0;

-

-  _needSeekToStart = false;

-

-  _stream.Release();

-  _seqStream.Release();

-   return S_OK;

-}

-

-class CCompressProgressInfoImp:

-  public ICompressProgressInfo,

-  public CMyUnknownImp

-{

-  CMyComPtr<IArchiveOpenCallback> Callback;

-public:

-  UInt64 Offset;

- 

-  MY_UNKNOWN_IMP1(ICompressProgressInfo)

-  STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);

-  void Init(IArchiveOpenCallback *callback) { Callback = callback; }

-};

-

-STDMETHODIMP 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;

-}

-

-STDMETHODIMP 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)

-    extractCallback->SetTotal(_packSize);

-    

-  

-  CMyComPtr<ISequentialOutStream> realOutStream;

-  Int32 askMode = testMode ?

-      NExtract::NAskMode::kTest :

-      NExtract::NAskMode::kExtract;

-  RINOK(extractCallback->GetStream(0, &realOutStream, askMode));

-  if (!testMode && !realOutStream)

-    return S_OK;

-  

-  extractCallback->PrepareOperation(askMode);

-

-  CDummyOutStream *outStreamSpec = new CDummyOutStream;

-  CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);

-  outStreamSpec->SetStream(realOutStream);

-  outStreamSpec->Init();

-  realOutStream.Release();

-

-  CLocalProgress *lps = new CLocalProgress;

-  CMyComPtr<ICompressProgressInfo> progress = lps;

-  lps->Init(extractCallback, true);

-

-  if (_needSeekToStart)

-  {

-    if (!_stream)

-      return E_FAIL;

-    RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL));

-  }

-  else

-    _needSeekToStart = true;

-

-  CDecoder decoder;

-  HRESULT result = decoder.Create(_lzma86, _seqStream);

-  RINOK(result);

- 

-  bool firstItem = true;

-

-  UInt64 packSize = 0;

-  UInt64 unpackSize = 0;

-  UInt64 numStreams = 0;

-

-  bool dataAfterEnd = false;

-  

-  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;

-

-    result = decoder.Code(st, outStream, progress);

-

-    packSize = decoder.GetInputProcessedSize();

-    unpackSize = outStreamSpec->GetSize();

-    

-    if (result == E_NOTIMPL)

-    {

-      _unsupported = true;

-      result = S_FALSE;

-      break;

-    }

-    if (result == S_FALSE)

-      break;

-    RINOK(result);

-  }

-

-  if (firstItem)

-  {

-    _isArc = false;

-    result = S_FALSE;

-  }

-  else if (result == S_OK || result == S_FALSE)

-  {

-    if (dataAfterEnd)

-      _dataAfterEnd = true;

-    else if (decoder._lzmaDecoderSpec->NeedsMoreInput())

-      _needMoreInput = true;

-

-    _packSize = packSize;

-    _unpackSize = unpackSize;

-    _numStreams = numStreams;

-  

-    _packSize_Defined = true;

-    _unpackSize_Defined = true;

-    _numStreams_Defined = true;

-  }

-  

-  Int32 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 (result == S_FALSE)

-    opResult = NExtract::NOperationResult::kDataError;

-  else if (result == S_OK)

-    opResult = NExtract::NOperationResult::kOK;

-  else

-    return result;

-

-  outStream.Release();

-  return extractCallback->SetOperationResult(opResult);

-

-  COM_TRY_END

-}

-

-namespace NLzmaAr {

-

-// 2, { 0x5D, 0x00 },

-

-REGISTER_ARC_I_CLS_NO_SIG(

-  CHandler(false),

-  "lzma", "lzma", 0, 0xA,

-  0,

-  NArcInfoFlags::kStartOpen |

-  NArcInfoFlags::kKeepName,

-  IsArc_Lzma)

- 

-}

-

-namespace NLzma86Ar {

-

-REGISTER_ARC_I_CLS_NO_SIG(

-  CHandler(true),

-  "lzma86", "lzma86", 0, 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<ISequentialOutStream> _bcjStream;
+  CFilterCoder *_filterCoder;
+  CMyComPtr<ICompressCoder> _lzmaDecoder;
+public:
+  NCompress::NLzma::CDecoder *_lzmaDecoderSpec;
+
+  ~CDecoder();
+  HRESULT Create(bool filtered, ISequentialInStream *inStream);
+
+  HRESULT Code(const CHeader &header, ISequentialOutStream *outStream, ICompressProgressInfo *progress);
+
+  UInt64 GetInputProcessedSize() const { return _lzmaDecoderSpec->GetInputProcessedSize(); }
+
+  void ReleaseInStream() { if (_lzmaDecoder) _lzmaDecoderSpec->ReleaseInStream(); }
+
+  HRESULT ReadInput(Byte *data, UInt32 size, UInt32 *processedSize)
+    { return _lzmaDecoderSpec->ReadFromInputStream(data, size, processedSize); }
+};
+
+HRESULT CDecoder::Create(bool filteredMode, ISequentialInStream *inStream)
+{
+  if (!_lzmaDecoder)
+  {
+    _lzmaDecoderSpec = new NCompress::NLzma::CDecoder;
+    _lzmaDecoderSpec->FinishStream = true;
+    _lzmaDecoder = _lzmaDecoderSpec;
+  }
+
+  if (filteredMode)
+  {
+    if (!_bcjStream)
+    {
+      _filterCoder = new CFilterCoder(false);
+      CMyComPtr<ICompressCoder> coder = _filterCoder;
+      _filterCoder->Filter = new NCompress::NBcj::CCoder2(z7_BranchConvSt_X86_Dec);
+      _bcjStream = _filterCoder;
+    }
+  }
+
+  return _lzmaDecoderSpec->SetInStream(inStream);
+}
+
+CDecoder::~CDecoder()
+{
+  ReleaseInStream();
+}
+
+HRESULT CDecoder::Code(const CHeader &header, ISequentialOutStream *outStream,
+    ICompressProgressInfo *progress)
+{
+  if (header.FilterID > 1)
+    return E_NOTIMPL;
+
+  RINOK(_lzmaDecoderSpec->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 = _lzmaDecoderSpec->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 (_lzmaDecoderSpec->GetOutputProcessedSize() != header.Size)
+      return S_FALSE;
+
+  return S_OK;
+}
+
+
+Z7_CLASS_IMP_CHandler_IInArchive_1(
+  IArchiveOpenSeq
+)
+  CHeader _header;
+  bool _lzma86;
+  CMyComPtr<IInStream> _stream;
+  CMyComPtr<ISequentialInStream> _seqStream;
+  
+  bool _isArc;
+  bool _needSeekToStart;
+  bool _dataAfterEnd;
+  bool _needMoreInput;
+  bool _unsupported;
+  bool _dataError;
+
+  bool _packSize_Defined;
+  bool _unpackSize_Defined;
+  bool _numStreams_Defined;
+
+  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;
+    }
+  }
+  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;
+  }
+  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;
+
+  CDecoder state;
+  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<IArchiveOpenCallback> 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)
+    extractCallback->SetTotal(_packSize);
+    
+  
+  CMyComPtr<ISequentialOutStream> 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);
+
+  CDummyOutStream *outStreamSpec = new CDummyOutStream;
+  CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+  outStreamSpec->SetStream(realOutStream);
+  outStreamSpec->Init();
+  realOutStream.Release();
+
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> progress = lps;
+  lps->Init(extractCallback, true);
+
+  if (_needSeekToStart)
+  {
+    if (!_stream)
+      return E_FAIL;
+    RINOK(InStream_SeekToBegin(_stream))
+  }
+  else
+    _needSeekToStart = true;
+
+  CDecoder decoder;
+  HRESULT result = decoder.Create(_lzma86, _seqStream);
+  RINOK(result)
+ 
+  bool firstItem = true;
+
+  UInt64 packSize = 0;
+  UInt64 unpackSize = 0;
+  UInt64 numStreams = 0;
+
+  bool dataAfterEnd = false;
+  
+  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;
+
+    result = decoder.Code(st, outStream, progress);
+
+    packSize = decoder.GetInputProcessedSize();
+    unpackSize = outStreamSpec->GetSize();
+    
+    if (result == E_NOTIMPL)
+    {
+      _unsupported = true;
+      result = S_FALSE;
+      break;
+    }
+    if (result == S_FALSE)
+      break;
+    RINOK(result)
+  }
+
+  if (firstItem)
+  {
+    _isArc = false;
+    result = S_FALSE;
+  }
+  else if (result == S_OK || result == S_FALSE)
+  {
+    if (dataAfterEnd)
+      _dataAfterEnd = true;
+    else if (decoder._lzmaDecoderSpec->NeedsMoreInput())
+      _needMoreInput = true;
+
+    _packSize = packSize;
+    _unpackSize = unpackSize;
+    _numStreams = numStreams;
+  
+    _packSize_Defined = true;
+    _unpackSize_Defined = true;
+    _numStreams_Defined = true;
+  }
+  
+  Int32 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 (result == S_FALSE)
+    opResult = NExtract::NOperationResult::kDataError;
+  else if (result == S_OK)
+    opResult = NExtract::NOperationResult::kOK;
+  else
+    return result;
+
+  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
new file mode 100644
index 0000000..4920a04
--- /dev/null
+++ b/CPP/7zip/Archive/MachoHandler.cpp
@@ -0,0 +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<IInStream> _inStream;
+  CObjectVector<CSegment> _segments;
+  CObjectVector<CSection> _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 &sect = _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 &sect = _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<ICompressCoder> copyCoder = copyCoderSpec;
+
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> progress = lps;
+  lps->Init(extractCallback, false);
+
+  CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+  CMyComPtr<ISequentialInStream> 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<ISequentialOutStream> 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
new file mode 100644
index 0000000..0d3611b
--- /dev/null
+++ b/CPP/7zip/Archive/MbrHandler.cpp
@@ -0,0 +1,567 @@
+// MbrHandler.cpp
+
+#include "StdAfx.h"
+
+// #define SHOW_DEBUG_INFO
+
+#ifdef SHOW_DEBUG_INFO
+#include <stdio.h>
+#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 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() const { return (UInt64)Lba * 512; }
+  UInt64 GetSize() const { return (UInt64)NumBlocks * 512; }
+
+  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<CItem> _items;
+  UInt64 _totalSize;
+  CByteBuffer _buffer;
+
+  virtual int GetItem_ExtractInfo(UInt32 index, UInt64 &pos, UInt64 &size) const Z7_override Z7_final
+  {
+    const CItem &item = _items[index];
+    pos = item.Part.GetPos();
+    size = item.Size;
+    return NExtract::NOperationResult::kOK;
+  }
+
+  HRESULT ReadTables(IInStream *stream, UInt32 baseLba, UInt32 lba, unsigned level);
+};
+
+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];
+
+  {
+    const UInt32 kSectorSize = 512;
+    _buffer.Alloc(kSectorSize);
+    Byte *buf = _buffer;
+    UInt64 newPos = (UInt64)lba << 9;
+    if (newPos + 512 > _totalSize)
+      return S_FALSE;
+    RINOK(InStream_SeekSet(stream, newPos))
+    RINOK(ReadStream_FALSE(stream, buf, kSectorSize))
+    
+    if (buf[0x1FE] != 0x55 || buf[0x1FF] != 0xAA)
+      return S_FALSE;
+    
+    for (unsigned i = 0; i < kNumHeaderParts; i++)
+      if (!parts[i].Parse(buf + 0x1BE + 16 * i))
+        return S_FALSE;
+  }
+
+  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;
+      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();
+      UInt32 backLimit = back.Part.GetLimit();
+      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();
+      _items.Add(n);
+    }
+  }
+  return S_OK;
+}
+
+
+static bool Is_Ntfs(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;
+  }
+  return memcmp(p + 3, "NTFS    ", 8) == 0;
+}
+
+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, "EXFAT   ", 8) == 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;
+}
+
+
+static 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";
+      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;
+  UInt32 lbaLimit = _items.Back().Part.GetLimit();
+  UInt64 lim = (UInt64)lbaLimit << 9;
+  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()) != 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}
+};
+
+IMP_IInArchive_Props_WITH_NAME
+IMP_IInArchive_ArcProps_NO_Table
+
+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;
+  }
+  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(); 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
new file mode 100644
index 0000000..04549f8
--- /dev/null
+++ b/CPP/7zip/Archive/MslzHandler.cpp
@@ -0,0 +1,390 @@
+// 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<IInStream> _inStream;
+  CMyComPtr<ISequentialInStream> _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;
+    }
+  }
+  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 += (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;
+
+  // extractCallback->SetTotal(_unpackSize);
+
+  CMyComPtr<ISequentialOutStream> 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);
+
+  CDummyOutStream *outStreamSpec = new CDummyOutStream;
+  CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+  outStreamSpec->SetStream(realOutStream);
+  outStreamSpec->Init();
+  realOutStream.Release();
+
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> progress = lps;
+  lps->Init(extractCallback, false);
+
+  if (_needSeekToStart)
+  {
+    if (!_inStream)
+      return E_FAIL;
+    RINOK(InStream_SeekToBegin(_inStream))
+  }
+  else
+    _needSeekToStart = true;
+
+  Int32 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)
+        {
+          HRESULT result = MslzDec(s, outStream, unpackSize, needMoreInput, progress);
+          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;
+
+  outStream.Release();
+  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
new file mode 100644
index 0000000..7363b1b
--- /dev/null
+++ b/CPP/7zip/Archive/MubHandler.cpp
@@ -0,0 +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)
+
+}
+
+}}
diff --git a/CPP/7zip/Archive/Nsis/NsisDecode.cpp b/CPP/7zip/Archive/Nsis/NsisDecode.cpp
new file mode 100644
index 0000000..044de37
--- /dev/null
+++ b/CPP/7zip/Archive/Nsis/NsisDecode.cpp
@@ -0,0 +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<ICompressSetInStream> setInStream;
+    _codecInStream.QueryInterface(IID_ICompressSetInStream, &setInStream);
+    if (!setInStream)
+      return E_NOTIMPL;
+    RINOK(setInStream->SetInStream(inStream))
+  }
+
+  {
+    CMyComPtr<ICompressSetOutStreamSize> 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<ISequentialInStream> 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
new file mode 100644
index 0000000..1d08d01
--- /dev/null
+++ b/CPP/7zip/Archive/Nsis/NsisDecode.h
@@ -0,0 +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<ISequentialInStream> _filterInStream;
+  CMyComPtr<ISequentialInStream> _codecInStream;
+  CMyComPtr<ISequentialInStream> _decoderInStream;
+
+  NCompress::NBZip2::CNsisDecoder *_bzDecoder;
+  NCompress::NDeflate::NDecoder::CCOMCoder *_deflateDecoder;
+  NCompress::NLzma::CDecoder *_lzmaDecoder;
+
+public:
+  CMyComPtr<IInStream> 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
new file mode 100644
index 0000000..7a512b7
--- /dev/null
+++ b/CPP/7zip/Archive/Nsis/NsisHandler.cpp
@@ -0,0 +1,694 @@
+// 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 += 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 += ':';
+    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 += ':';
+    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);
+
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> progress = 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(&currentTotalSize))
+    CMyComPtr<ISequentialOutStream> 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, progress);
+            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,
+                progress,
+                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,
+                progress,
+                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
new file mode 100644
index 0000000..bb90bfe
--- /dev/null
+++ b/CPP/7zip/Archive/Nsis/NsisHandler.h
@@ -0,0 +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
diff --git a/CPP/7zip/Archive/Nsis/NsisIn.cpp b/CPP/7zip/Archive/Nsis/NsisIn.cpp
new file mode 100644
index 0000000..05ebfd0
--- /dev/null
+++ b/CPP/7zip/Archive/Nsis/NsisIn.cpp
@@ -0,0 +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 += (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 &sect, 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)
+    {
+      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;
+
+      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]))
+      {
+        unsigned numInserts = cmd - EW_WRITEUNINSTALLER;
+        mask |= (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<UInt32> 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<CSection> 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 &section = 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 &sect = 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 &sect = 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(&params[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(&params[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(&params[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(&params[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 &sect = Sections[curSectionIndex];
+      if (sect.StartCmdIndex + sect.NumCommands + 1 == kkk)
+      {
+        PrintSectionEnd();
+        sectionIsOpen = false;
+        // lastSectionEndCmd = kkk;
+        curSectionIndex++;
+      }
+    }
+  }
+  
+  while (curSectionIndex < bhSections.Num)
+  {
+    const CSection &sect = 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
new file mode 100644
index 0000000..bb8de62
--- /dev/null
+++ b/CPP/7zip/Archive/Nsis/NsisIn.h
@@ -0,0 +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<CItem> 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<UInt32> langStrIDs;
+  UInt32 numOnFunc;
+  UInt32 onFuncOffset;
+  // CRecordVector<UInt32> OnFuncs;
+  unsigned _numRootLicenses;
+  CRecordVector<UInt32> noParseStringIndexes;
+  AString _tempString_for_GetVar;
+  AString _tempString_for_AddFuncName;
+  AString _tempString;
+
+  #endif
+
+
+public:
+  CMyComPtr<IInStream> _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<CLicenseFile> 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 &sect, 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 += '\\';
+    }
+
+    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
new file mode 100644
index 0000000..a500381
--- /dev/null
+++ b/CPP/7zip/Archive/Nsis/NsisRegister.cpp
@@ -0,0 +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)
+
+}}
diff --git a/CPP/7zip/Archive/Nsis/StdAfx.h b/CPP/7zip/Archive/Nsis/StdAfx.h
new file mode 100644
index 0000000..035267c
--- /dev/null
+++ b/CPP/7zip/Archive/Nsis/StdAfx.h
@@ -0,0 +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
diff --git a/CPP/7zip/Archive/NtfsHandler.cpp b/CPP/7zip/Archive/NtfsHandler.cpp
new file mode 100644
index 0000000..c13e0ca
--- /dev/null
+++ b/CPP/7zip/Archive/NtfsHandler.cpp
@@ -0,0 +1,2861 @@
+// NtfsHandler.cpp
+
+#include "StdAfx.h"
+
+// #define SHOW_DEBUG_INFO
+// #define SHOW_DEBUG_INFO2
+
+#if defined(SHOW_DEBUG_INFO) || defined(SHOW_DEBUG_INFO2)
+#include <stdio.h>
+#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;
+  // 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;
+  {
+    int t = GetLog(Get16(p + 11));
+    if (t < 9 || t > 12)
+      return false;
+    SectorSizeLog = (unsigned)t;
+    t = GetLog(p[13]);
+    if (t < 0)
+      return false;
+    sectorsPerClusterLog = (unsigned)t;
+    ClusterSizeLog = SectorSizeLog + sectorsPerClusterLog;
+    if (ClusterSizeLog > 30)
+      return false;
+  }
+
+  for (int i = 14; i < 21; i++)
+    if (p[i] != 0)
+      return false;
+
+  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);
+  // G64(p + 0x38, Mft2Cluster);
+  G64(p + 0x48, SerialNumber);
+  UInt32 numClustersInMftRec;
+  UInt32 numClustersInIndexBlock;
+  G32(p + 0x40, numClustersInMftRec); // -10 means 2 ^10 = 1024 bytes.
+  G32(p + 0x44, numClustersInIndexBlock);
+  return (numClustersInMftRec < 256 && numClustersInIndexBlock < 256);
+}
+
+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, unsigned len, UString2 &res)
+{
+  if (len == 0 && res.IsEmpty())
+    return;
+  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 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];
+  unsigned len = p[0x40];
+  if (0x42 + len > 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<CExtent> &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<CExtent> &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)
+  {
+    Byte b = *p++;
+    size--;
+    if (b == 0)
+      break;
+    UInt32 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) & 0xF;
+    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_COM_1(
+  CInStream
+  , IInStream
+)
+  Z7_IFACE_COM7_IMP(ISequentialInStream)
+
+  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<CExtent> Extents;
+  CMyComPtr<IInStream> 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<CAttr> &attrs,
+    unsigned attrIndex, unsigned attrIndexLim, UInt64 numPhysClusters, CRecordVector<CExtent> &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<CAttr> DataAttrs;
+  CObjectVector<CFileNameAttr> FileNames;
+  CRecordVector<CDataRef> 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<CAttr> *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<IInStream> 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<IInStream> 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<CExtent> 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<CAttr> *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));
+  UInt32 attrOffs = Get16(p + 0x14);
+  G16(p + 0x16, Flags);
+  PRF(printf(" F=%4X", Flags));
+
+  UInt32 bytesInUse = Get32(p + 0x18);
+  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<CItem> Items;
+  CObjectVector<CMftRec> Recs;
+  CMyComPtr<IInStream> InStream;
+  CHeader Header;
+  unsigned RecSizeLog;
+  UInt64 PhySize;
+
+  IArchiveOpenCallback *OpenCallback;
+
+  CByteBuffer ByteBuf;
+
+  CObjectVector<CAttr> VolAttrs;
+
+  CByteBuffer SecurData;
+  CRecordVector<size_t> SecurOffsets;
+
+  bool _showSystemFiles;
+  bool _showDeletedFiles;
+  CObjectVector<UString2> VirtFolderNames;
+  UString EmptyString;
+
+  int _systemFolderIndex;
+  int _lostFolderIndex_Normal;
+  int _lostFolderIndex_Deleted;
+
+  // bool _headerWarning;
+
+  bool ThereAreAltStreams;
+
+  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 FindDirItemForMtfRec(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);
+
+  CMftRec mftRec;
+  UInt32 numSectorsInRec;
+
+  CMyComPtr<IInStream> mftStream;
+  {
+    UInt32 blockSize = 1 << 12;
+    ByteBuf.Alloc(blockSize);
+    RINOK(ReadStream_FALSE(InStream, ByteBuf, blockSize))
+    
+    {
+      const UInt32 allocSize = Get32(ByteBuf + 0x1C);
+      const int t = GetLog(allocSize);
+      if (t < (int)Header.SectorSizeLog)
+        return S_FALSE;
+      RecSizeLog = (unsigned)t;
+      if (RecSizeLog > 15)
+        return S_FALSE;
+    }
+
+    numSectorsInRec = 1 << (RecSizeLog - Header.SectorSizeLog);
+    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<CAttr> SecurityAttrs;
+
+  UInt64 mftSize = mftRec.DataAttrs[0].Size;
+  if ((mftSize >> 4) > Header.GetPhySize_Clusters())
+    return S_FALSE;
+
+  const size_t kBufSize = (1 << 15);
+  const size_t recSize = ((size_t)1 << RecSizeLog);
+  if (kBufSize < recSize)
+    return S_FALSE;
+
+  {
+    const UInt64 numFiles = mftSize >> RecSizeLog;
+    if (numFiles > (1 << 30))
+      return S_FALSE;
+    if (OpenCallback)
+    {
+      RINOK(OpenCallback->SetTotal(&numFiles, &mftSize))
+    }
+    
+    ByteBuf.Alloc(kBufSize);
+    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<CAttr> *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<IInStream> 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 = FindDirItemForMtfRec(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},
+  { "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 << RecSizeLog; 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);
+
+  NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+  CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> progress = lps;
+  lps->Init(extractCallback, false);
+
+  CDummyOutStream *outStreamSpec = new CDummyOutStream;
+  CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+
+  for (i = 0; i < numItems; i++)
+  {
+    lps->InSize = totalPackSize;
+    lps->OutSize = totalSize;
+    RINOK(lps->SetCur())
+    CMyComPtr<ISequentialOutStream> 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))
+
+    outStreamSpec->SetStream(realOutStream);
+    realOutStream.Release();
+    outStreamSpec->Init();
+
+    const CMftRec &rec = Recs[item.RecIndex];
+
+    int res = NExtract::NOperationResult::kDataError;
+    {
+      CMyComPtr<IInStream> 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->Code(inStream, outStream, NULL, NULL, progress);
+          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();
+    }
+    outStreamSpec->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
+      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
new file mode 100644
index 0000000..9851ed3
--- /dev/null
+++ b/CPP/7zip/Archive/PeHandler.cpp
@@ -0,0 +1,3272 @@
+// PeHandler.cpp
+
+#include "StdAfx.h"
+
+// #include <stdio.h>
+
+#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);
+  }
+};
+
+enum
+{
+  kDirLink_Certificate = 4,
+  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;
+  // 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;
+  }
+};
+
+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;
+  }
+
+  G32(pos, NumDirItems);
+  if (NumDirItems > (1 << 16))
+    return false;
+  pos += 4;
+  if (pos + 8 * NumDirItems > size)
+    return false;
+  memset((void *)DirItems, 0, sizeof(DirItems));
+  for (UInt32 i = 0; i < NumDirItems && i < kNumDirItemsMax; i++)
+    DirItems[i].Parse(p + pos + i * 8);
+  return true;
+}
+
+static const UInt32 kSectionSize = 40;
+
+struct CSection
+{
+  AString Name;
+
+  UInt32 VSize;
+  UInt32 Va;
+  UInt32 PSize;
+  UInt32 Pa;
+  UInt32 Flags;
+  UInt32 Time;
+  // UInt16 NumRelocs;
+  bool IsRealSect;
+  bool IsDebug;
+  bool IsAdditionalSection;
+
+  CSection(): IsRealSect(false), IsDebug(false), IsAdditionalSection(false) {}
+
+  UInt32 GetSizeExtract() const { return PSize; }
+  UInt32 GetSizeMin() const { return MyMin(PSize, VSize); }
+
+  void UpdateTotalSize(UInt32 &totalSize) 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))
+    UInt32 size1 = GetSizeExtract();
+    UInt32 size2 = s.GetSizeExtract();
+    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);
+}
+
+
+
+// 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" },
+  { 0x0200, "IA-64" },
+  { 0x0266, "MIPS-16" },
+  { 0x0284, "Alpha-64" },
+  { 0x0366, "MIPS-FPU" },
+  { 0x0466, "MIPS-FPU16" },
+  { 0x0520, "TriCore" },
+  { 0x0CEF, "CEF" },
+  { 0x0EBC, "EFI" },
+  { 0x8664, "x64" },
+  { 0x9041, "M32R" },
+  { 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<IInStream> _stream;
+  CObjectVector<CSection> _sections;
+  CHeader _header;
+  UInt32 _totalSize;
+  Int32 _mainSubfile;
+
+  CRecordVector<CMixItem> _mixItems;
+  CRecordVector<CResItem> _items;
+  CObjectVector<CStringItem> _strings;
+  CObjectVector<CByteBuffer_WithLang> _versionFiles;
+  UString _versionFullString;
+  UString _versionShortString;
+  UString _originalFilename;
+  CObjectVector<CStringKeyValue> _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<CTableItem> &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 &sect, 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},
+  { "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},
+};
+
+static const Byte kProps[] =
+{
+  kpidPath,
+  kpidSize,
+  kpidPackSize,
+  kpidVirtualSize,
+  kpidCharacts,
+  kpidOffset,
+  kpidVa,
+};
+
+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: if (!_versionFullString.IsEmpty()) prop = _versionFullString; 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 kpidImageBase: prop = _optHeader.ImageBase; break;
+    // 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.PSize; 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 &sect = _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 &sect = _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.PSize = sect.VSize = de.Size;
+    }
+    buf += kEntrySize;
+  }
+
+  return S_OK;
+}
+
+HRESULT CHandler::ReadTable(UInt32 offset, CRecordVector<CTableItem> &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<CStringKeyValue> &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<CStringKeyValue> &v, const char *key)
+{
+  FOR_VECTOR (i, v)
+    if (v[i].Key.IsEqualTo(key))
+      return (int)i;
+  return -1;
+}
+
+static void AddToUniqueUStringVector(CObjectVector<CStringKeyValue> &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<CStringKeyValue> &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 (;;)
+  {
+    wchar_t c = (wchar_t)Get16(p);
+    p += 2;
+    if (c == 0)
+      return;
+    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;
+  bool 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 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;
+  switch (Get16(p + 4))
+  {
+    case 0: IsTextValue = false; break;
+    case 1: IsTextValue = true; break;
+    default: 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<CStringKeyValue> &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;
+    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;
+        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)
+        {
+          UInt32 dw = Get32(p + pos);
+          UInt32 lang = LOWORD(dw);
+          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;
+        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 sometimes is a number of characters (not bytes)?
+          // So we don't use it.
+          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);
+              const int sLen = Get_Utf16Str_Len_InBytes(p + pos, endPos3 - pos);
+              if (sLen < 0)
+                return false;
+              AddParamString(f, p + pos, (unsigned)sLen);
+              CopyToUString(p + pos, value);
+              pos += (unsigned)sLen + 2;
+            }
+            AddToUniqueUStringVector(keys, key, value);
+          }
+          pos = endPos3;
+          f.NewLine();
+        }
+        f.CloseBlock(4);
+      }
+    }
+    f.CloseBlock(2);
+  }
+
+  f.CloseBlock(0);
+  return true;
+}
+
+
+HRESULT CHandler::OpenResources(unsigned sectionIndex, IInStream *stream, IArchiveOpenCallback *callback)
+{
+  const CSection &sect = _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<CTableItem> 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<CTableItem> 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<CTableItem> 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.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 &sect = _sections.AddNew();
+    sect.Parse(buffer + pos);
+    sect.IsRealSect = true;
+    
+    /* 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 &sect = _sections.AddNew();
+    sect.Name = "CERTIFICATE";
+    sect.Va = 0;
+    sect.Pa = certLink.Va;
+    sect.PSize = sect.VSize = 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 &sect = _sections.AddNew();
+    sect.Name = "COFF_SYMBOLS";
+    sect.Va = 0;
+    sect.Pa = _header.PointerToSymbolTable;
+    sect.PSize = sect.VSize = size;
+    sect.UpdateTotalSize(_totalSize);
+  }
+
+  {
+    CObjectVector<CSection> 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.PSize = s2.VSize = s.Pa - limit;
+        s2.IsAdditionalSection = true;
+        s2.Name = '[';
+        s2.Name.Add_UInt32(num++);
+        s2.Name += ']';
+        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 &sect = _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 &sect2 = _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].GetSizeExtract();
+    totalSize += size;
+  }
+  extractCallback->SetTotal(totalSize);
+
+  UInt64 currentTotalSize = 0;
+  UInt64 currentItemSize;
+  
+  NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+  CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> progress = lps;
+  lps->Init(extractCallback, false);
+
+  CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+  CMyComPtr<ISequentialInStream> inStream(streamSpec);
+  streamSpec->SetStream(_stream);
+
+  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];
+
+    CMyComPtr<ISequentialOutStream> outStream;
+    RINOK(extractCallback->GetStream(index, &outStream, askMode))
+    const CMixItem &mixItem = _mixItems[index];
+
+    const CSection &sect = _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.GetSizeExtract();
+      if (!testMode && !outStream)
+        continue;
+      
+      RINOK(extractCallback->PrepareOperation(askMode))
+      RINOK(InStream_SeekSet(_stream, sect.Pa))
+      streamSpec->Init(currentItemSize);
+      RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress))
+      isOk = (copyCoderSpec->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 &sect = _sections[mixItem.SectionIndex];
+  if (mixItem.IsSectionItem())
+    return CreateLimitedInStream(_stream, sect.Pa, sect.PSize, stream);
+
+  CBufInStream *inStreamSpec = new CBufInStream;
+  CMyComPtr<ISequentialInStream> streamTemp = inStreamSpec;
+  CReferenceBuf *referenceBuf = new CReferenceBuf;
+  CMyComPtr<IUnknown> 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<IInStream> 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 (int 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 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);
+  }
+
+  bool Check() const
+  {
+    return
+        Pa <= ((UInt32)1 << 30) &&
+        PSize <= ((UInt32)1 << 30);
+  }
+
+  void UpdateTotalSize(UInt32 &totalSize)
+  {
+    UInt32 t = Pa + PSize;
+    if (t > totalSize)
+      totalSize = t;
+  }
+};
+
+
+Z7_CLASS_IMP_CHandler_IInArchive_2(
+  IInArchiveGetStream,
+  IArchiveAllowTail
+)
+  CRecordVector<CSection> _items;
+  CMyComPtr<IInStream> _stream;
+  UInt32 _totalSize;
+  bool _allowTail;
+  CHeader _h;
+  
+  HRESULT Open2(IInStream *stream);
+public:
+  CHandler(): _allowTail(false) {}
+};
+
+static const Byte kProps[] =
+{
+  kpidPath,
+  kpidSize,
+  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:
+      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]].PSize;
+  extractCallback->SetTotal(totalSize);
+
+  UInt64 currentTotalSize = 0;
+  
+  NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+  CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> progress = lps;
+  lps->Init(extractCallback, false);
+
+  CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+  CMyComPtr<ISequentialInStream> inStream(streamSpec);
+  streamSpec->SetStream(_stream);
+
+  for (i = 0; i < numItems; i++)
+  {
+    lps->InSize = lps->OutSize = currentTotalSize;
+    RINOK(lps->SetCur())
+    CMyComPtr<ISequentialOutStream> 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))
+    currentTotalSize += item.PSize;
+    
+    if (!testMode && !realOutStream)
+      continue;
+    RINOK(extractCallback->PrepareOperation(askMode))
+    int res = NExtract::NOperationResult::kDataError;
+
+    RINOK(InStream_SeekSet(_stream, item.Pa))
+    streamSpec->Init(item.PSize);
+    RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress))
+    if (copyCoderSpec->TotalSize == item.PSize)
+      res = NExtract::NOperationResult::kOK;
+
+    realOutStream.Release();
+    RINOK(extractCallback->SetOperationResult(res))
+  }
+  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.PSize, 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
new file mode 100644
index 0000000..e5c2f9b
--- /dev/null
+++ b/CPP/7zip/Archive/PpmdHandler.cpp
@@ -0,0 +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);
+  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);
+  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<ISequentialInStream> _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 += (char)('A' + _item.Ver);
+  s += ":o";
+  s.Add_UInt32(_item.Order);
+  s += ":mem";
+  s.Add_UInt32(_item.MemInMB);
+  s += '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(&currentTotalPacked))
+  CMyComPtr<ISequentialOutStream> 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);
+
+  CByteInBufWrap inBuf;
+  if (!inBuf.Alloc(1 << 20))
+    return E_OUTOFMEMORY;
+  inBuf.Stream = _stream;
+
+  CBuf outBuf;
+  if (!outBuf.Alloc())
+    return E_OUTOFMEMORY;
+
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> progress = lps;
+  lps->Init(extractCallback, true);
+
+  CPpmdCpp ppmd(_item.Ver);
+  if (!ppmd.Alloc(_item.MemInMB))
+    return E_OUTOFMEMORY;
+  
+  Int32 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)
+  }
+  
+  realOutStream.Release();
+  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
new file mode 100644
index 0000000..5a80daa
--- /dev/null
+++ b/CPP/7zip/Archive/QcowHandler.cpp
@@ -0,0 +1,668 @@
+// QcowHandler.cpp
+
+#include "StdAfx.h"
+
+// #include <stdio.h>
+
+#include "../../../C/CpuArch.h"
+
+#include "../../Common/ComTry.h"
+#include "../../Common/IntToString.h"
+#include "../../Common/MyBuffer2.h"
+
+#include "../../Windows/PropVariant.h"
+
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamObjects.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/DeflateDecoder.h"
+
+#include "HandlerCont.h"
+
+#define Get32(p) GetBe32(p)
+#define Get64(p) GetBe64(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) :              : in L1 Table : the reference to L1 Table
+  mid bits  (L2) : _numMidBits  : in L2 Table : the reference to cluster
+  low bits       : _clusterBits
+*/
+
+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<UInt32> _dir;
+  CAlignedBuffer _table;
+  UInt64 _cacheCluster;
+  CByteBuffer _cache;
+  CByteBuffer _cacheCompressed;
+
+  UInt64 _comprPos;
+  size_t _comprSize;
+
+  UInt64 _phySize;
+
+  CBufInStream *_bufInStreamSpec;
+  CMyComPtr<ISequentialInStream> _bufInStream;
+
+  CBufPtrSeqOutStream *_bufOutStreamSpec;
+  CMyComPtr<ISequentialOutStream> _bufOutStream;
+
+  NCompress::NDeflate::NDecoder::CCOMCoder *_deflateDecoderSpec;
+  CMyComPtr<ICompressCoder> _deflateDecoder;
+
+  bool _needDeflate;
+  bool _isArc;
+  bool _unsupported;
+
+  UInt32 _version;
+  UInt32 _cryptMethod;
+  
+  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;
+  {
+    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);
+    {
+      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[(unsigned)high];
+    
+      if (tabl != kEmptyDirItem)
+      {
+        const Byte *buffer = _table + ((size_t)tabl << (_numMidBits + 3));
+        const size_t midBits = (size_t)cluster & (((size_t)1 << _numMidBits) - 1);
+        const Byte *p = (const Byte *)buffer + (midBits << 3);
+        UInt64 v = Get64(p);
+        
+        if (v != 0)
+        {
+          if ((v & _compressedFlag) != 0)
+          {
+            if (_version <= 1)
+              return E_FAIL;
+
+            /*
+            the example of table record for 12-bit clusters (4KB uncompressed).
+             2 bits : isCompressed status
+             4 bits : num_sectors_minus1; packSize = (num_sectors_minus1 + 1) * 512;
+                      it uses one additional bit over unpacked cluster_bits
+            49 bits : offset of 512-sector
+             9 bits : offset in 512-sector
+            */
+
+            const unsigned numOffsetBits = (62 - (_clusterBits - 9 + 1));
+            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 != 0)
+              {
+                _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);
+              RINOK(ReadStream(Stream, _cacheCompressed + _comprSize, &dataSize2))
+              _posInArc += dataSize2;
+              if (dataSize2 != dataSize3)
+                return E_FAIL;
+              _comprSize += dataSize2;
+            }
+            
+            const size_t kSectorMask = (1 << 9) - 1;
+            const size_t offsetInSector = ((size_t)offset & kSectorMask);
+            _bufInStreamSpec->Init(_cacheCompressed + offsetInSector, dataSize - offsetInSector);
+            
+            _cacheCluster = (UInt64)(Int64)-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 = _deflateDecoder->Code(_bufInStream, _bufOutStream, NULL, &blockSize64, NULL);
+
+            /*
+            if (_bufOutStreamSpec->GetPos() != clusterSize)
+              memset(_cache + _bufOutStreamSpec->GetPos(), 0, clusterSize - _bufOutStreamSpec->GetPos());
+            */
+
+            if (res == S_OK)
+              if (!_deflateDecoderSpec->IsFinished()
+                  || _bufOutStreamSpec->GetPos() != clusterSize)
+                res = S_FALSE;
+
+            RINOK(res)
+            _cacheCluster = cluster;
+            
+            continue;
+            /*
+            memcpy(data, _cache + lowBits, size);
+            break;
+            */
+          }
+
+          // version 3 support zero clusters
+          if (((UInt32)v & 511) != 1)
+          {
+            v &= (_compressedFlag - 1);
+            v += lowBits;
+            if (v != _posInArc)
+            {
+              // printf("\n%12I64x\n", v - _posInArc);
+              RINOK(Seek2(v))
+            }
+            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,
+  kpidUnpackVer,
+  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)1 << _clusterBits; break;
+    case kpidPhySize: if (_phySize != 0) prop = _phySize; break;
+    case kpidUnpackVer: prop = _version; break;
+
+    case kpidMethod:
+    {
+      AString s;
+
+      if (_needDeflate)
+        s = "Deflate";
+
+      if (_cryptMethod != 0)
+      {
+        s.Add_Space_if_NotEmpty();
+        if (_cryptMethod == 1)
+          s += "AES";
+        else
+          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 && _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
+}
+
+
+HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *openCallback)
+{
+  const unsigned kHeaderSize = 18 * 4;
+  Byte buf[kHeaderSize];
+  RINOK(ReadStream_FALSE(stream, buf, kHeaderSize))
+
+  if (memcmp(buf, k_Signature, 4) != 0)
+    return S_FALSE;
+
+  _version = Get32(buf + 4);
+  if (_version < 1 || _version > 3)
+    return S_FALSE;
+  
+  const UInt64 backOffset = Get64(buf + 8);
+  // UInt32 backSize = Get32(buf + 0x10);
+  
+  UInt64 l1Offset;
+  UInt32 l1Size;
+
+  if (_version == 1)
+  {
+    // _mTime = Get32(buf + 0x14); // is unused im most images
+    _size = Get64(buf + 0x18);
+    _clusterBits = buf[0x20];
+    _numMidBits = buf[0x21];
+    if (_clusterBits < 9 || _clusterBits > 30)
+      return S_FALSE;
+    if (_numMidBits < 1 || _numMidBits > 28)
+      return S_FALSE;
+    _cryptMethod = Get32(buf + 0x24);
+    l1Offset = Get64(buf + 0x28);
+    if (l1Offset < 0x30)
+      return S_FALSE;
+    const unsigned numBits2 = (_clusterBits + _numMidBits);
+    const UInt64 l1Size64 = (_size + (((UInt64)1 << numBits2) - 1)) >> numBits2;
+    if (l1Size64 > ((UInt32)1 << 31))
+      return S_FALSE;
+    l1Size = (UInt32)l1Size64;
+  }
+  else
+  {
+    _clusterBits = Get32(buf + 0x14);
+    if (_clusterBits < 9 || _clusterBits > 30)
+      return S_FALSE;
+    _numMidBits = _clusterBits - 3;
+    _size = Get64(buf + 0x18);
+    _cryptMethod = Get32(buf + 0x20);
+    l1Size = Get32(buf + 0x24);
+    l1Offset = Get64(buf + 0x28); // must be aligned for cluster
+    
+    const UInt64 refOffset = Get64(buf + 0x30); // must be aligned for cluster
+    const UInt32 refClusters = Get32(buf + 0x38);
+    
+    // UInt32 numSnapshots = Get32(buf + 0x3C);
+    // UInt64 snapshotsOffset = Get64(buf + 0x40); // must be aligned for cluster
+    /*
+    if (numSnapshots != 0)
+      return S_FALSE;
+    */
+
+    if (refClusters != 0)
+    {
+      const size_t numBytes = refClusters << _clusterBits;
+      /*
+      CByteBuffer refs;
+      refs.Alloc(numBytes);
+      RINOK(InStream_SeekSet(stream, refOffset))
+      RINOK(ReadStream_FALSE(stream, refs, numBytes));
+      */
+      const UInt64 end = refOffset + 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;
+      }
+      */
+    }
+  }
+
+  _isArc = true;
+
+  if (backOffset != 0)
+  {
+    _unsupported = true;
+    return S_FALSE;
+  }
+
+  const size_t clusterSize = (size_t)1 << _clusterBits;
+
+  CByteBuffer table;
+  {
+    const size_t t1SizeBytes = (size_t)l1Size << 3;
+    if ((t1SizeBytes >> 3) != l1Size)
+      return S_FALSE;
+    table.Alloc(t1SizeBytes);
+    RINOK(InStream_SeekSet(stream, l1Offset))
+    RINOK(ReadStream_FALSE(stream, table, t1SizeBytes))
+    
+    {
+      UInt64 end = l1Offset + t1SizeBytes;
+      // we need to uses align end for empty qcow files
+      end = (end + clusterSize - 1) >> _clusterBits << _clusterBits;
+      if (_phySize < end)
+        _phySize = end;
+    }
+  }
+
+  _compressedFlag = (_version <= 1) ? ((UInt64)1 << 63) : ((UInt64)1 << 62);
+  const UInt64 offsetMask = _compressedFlag - 1;
+
+  UInt32 numTables = 0;
+  UInt32 i;
+  
+  for (i = 0; i < l1Size; i++)
+  {
+    const UInt64 v = Get64((const Byte *)table + (size_t)i * 8) & offsetMask;
+    if (v != 0)
+      numTables++;
+  }
+
+  if (numTables != 0)
+  {
+    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;
+  }
+
+  _dir.SetSize(l1Size);
+
+  UInt32 curTable = 0;
+
+  if (openCallback)
+  {
+    const UInt64 totalBytes = (UInt64)numTables << (_numMidBits + 3);
+    RINOK(openCallback->SetTotal(NULL, &totalBytes))
+  }
+
+  for (i = 0; i < l1Size; i++)
+  {
+    Byte *buf2;
+    const size_t midSize = (size_t)1 << (_numMidBits + 3);
+   
+    {
+      const UInt64 v = Get64((const Byte *)table + (size_t)i * 8) & 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))
+
+      const UInt64 end = v + midSize;
+      if (_phySize < end)
+        _phySize = end;
+    }
+
+    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) != 0)
+      {
+        if (_version <= 1)
+        {
+          unsigned numOffsetBits = (63 - _clusterBits);
+          dataSize = ((size_t)(offset >> numOffsetBits) + 1) << 9;
+          offset &= ((UInt64)1 << numOffsetBits) - 1;
+          dataSize = 0;
+          // offset >>= 9;
+          // offset <<= 9;
+        }
+        else
+        {
+          unsigned numOffsetBits = (62 - (_clusterBits - 8));
+          dataSize = ((size_t)(offset >> numOffsetBits) + 1) << 9;
+          offset &= ((UInt64)1 << numOffsetBits) - 1;
+          offset >>= 9;
+          offset <<= 9;
+        }
+        _needDeflate = true;
+      }
+      else
+      {
+        UInt32 low = (UInt32)v & 511;
+        if (low != 0)
+        {
+          // version 3 support 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 != 0)
+    _unsupported = true;
+
+  if (_needDeflate && _version <= 1) // that case was not implemented
+    _unsupported = true;
+
+  Stream = stream;
+  return S_OK;
+}
+
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+  _table.Free();
+  _dir.Free();
+  _phySize = 0;
+
+  _cacheCluster = (UInt64)(Int64)-1;
+  _comprPos = 0;
+  _comprSize = 0;
+  _needDeflate = false;
+
+  _isArc = false;
+  _unsupported = false;
+
+  // 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;
+
+  if (_needDeflate)
+  {
+    if (_version <= 1)
+      return S_FALSE;
+
+    if (!_bufInStream)
+    {
+      _bufInStreamSpec = new CBufInStream;
+      _bufInStream = _bufInStreamSpec;
+    }
+    
+    if (!_bufOutStream)
+    {
+      _bufOutStreamSpec = new CBufPtrSeqOutStream();
+      _bufOutStream = _bufOutStreamSpec;
+    }
+
+    if (!_deflateDecoder)
+    {
+      _deflateDecoderSpec = new NCompress::NDeflate::NDecoder::CCOMCoder();
+      _deflateDecoder = _deflateDecoderSpec;
+      _deflateDecoderSpec->Set_NeedFinishInput(true);
+    }
+    
+    const size_t clusterSize = (size_t)1 << _clusterBits;
+    _cache.AllocAtLeast(clusterSize);
+    _cacheCompressed.AllocAtLeast(clusterSize * 2);
+  }
+    
+  CMyComPtr<ISequentialInStream> 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
new file mode 100644
index 0000000..87d11e7
--- /dev/null
+++ b/CPP/7zip/Archive/Rar/Rar5Handler.cpp
@@ -0,0 +1,3001 @@
+// 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/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 "../Common/FindSignature.h"
+#include "../Common/ItemNameUtils.h"
+
+#include "../HandlerCont.h"
+
+#include "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 };
+
+static const size_t kCommentSize_Max = (size_t)1 << 16;
+
+
+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 unsigned ReadVarInt(const Byte *p, size_t 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;
+}
+
+
+bool CLinkInfo::Parse(const Byte *p, unsigned size)
+{
+  const Byte *pStart = p;
+  unsigned num;
+  UInt64 len;
+  num = ReadVarInt(p, size, &Type);  if (num == 0) { return false; }  p += num; size -= num;
+  num = ReadVarInt(p, size, &Flags); if (num == 0) { return false; }  p += num; size -= num;
+  num = ReadVarInt(p, size, &len);   if (num == 0) { return false; }  p += num; size -= num;
+  if (size != len)
+    return false;
+  NameLen = (unsigned)len;
+  NameOffset = (unsigned)(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;
+      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;
+      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;
+        unsigned num = ReadVarInt(p, rem, &flags);
+        if (num != 0)
+        {
+          s += ':';
+          for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_ExtraTimeFlags); i++)
+            if ((flags & ((UInt64)1 << i)) != 0)
+              s += g_ExtraTimeFlags[i];
+          flags &= ~(((UInt64)1 << Z7_ARRAY_SIZE(g_ExtraTimeFlags)) - 1);
+          if (flags != 0)
+          {
+            s += '_';
+            AddHex64(s, flags);
+          }
+        }
+      }
+      else if (id == NExtraID::kLink)
+      {
+        CLinkInfo linkInfo;
+        if (linkInfo.Parse(Extra + offset, (unsigned)rem))
+        {
+          s += ':';
+          PrintType(s, g_LinkTypes, Z7_ARRAY_SIZE(g_LinkTypes), linkInfo.Type);
+          UInt64 flags = linkInfo.Flags;
+          if (flags != 0)
+          {
+            s += ':';
+            if (flags & NLinkFlags::kTargetIsDir)
+            {
+              s += 'D';
+              flags &= ~((UInt64)NLinkFlags::kTargetIsDir);
+            }
+            if (flags != 0)
+            {
+              s += '_';
+              AddHex64(s, flags);
+            }
+          }
+        }
+      }
+
+      offset += rem;
+    }
+  }
+
+  s.Add_OptSpaced("ERROR");
+}
+
+
+bool CCryptoInfo::Parse(const Byte *p, size_t size)
+{
+  Algo = 0;
+  Flags = 0;
+  Cnt = 0;
+
+  unsigned num = ReadVarInt(p, size, &Algo);
+  if (num == 0) { return false; }  p += num; size -= num;
+  
+  num = ReadVarInt(p, size, &Flags);
+  if (num == 0) { return false; }  p += num; size -= num;
+
+  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;
+  int offset = FindExtra(NExtraID::kVersion, size);
+  if (offset < 0)
+    return false;
+  const Byte *p = Extra + (unsigned)offset;
+
+  UInt64 flags;
+  unsigned num = ReadVarInt(p, size, &flags);
+  if (num == 0) { return false; }  p += num; size -= num;
+  
+  num = ReadVarInt(p, size, &version);
+  if (num == 0) { return false; }  p += num; size -= num;
+
+  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;
+  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;
+  CBlake2sp _blake;
+public:
+
+  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 *cryptoDecoderSpec);
+};
+
+void CHash::Init(const CItem &item)
+{
+  _crc = CRC_INIT_VAL;
+  _calcCRC = item.Has_CRC();
+  
+  _blakeOffset = item.FindExtra_Blake();
+  if (_blakeOffset >= 0)
+    Blake2sp_Init(&_blake);
+}
+
+void CHash::Update(const void *data, size_t size)
+{
+  if (_calcCRC)
+    _crc = CrcUpdate(_crc, data, size);
+  if (_blakeOffset >= 0)
+    Blake2sp_Update(&_blake, (const Byte *)data, size);
+}
+
+bool CHash::Check(const CItem &item, NCrypto::NRar5::CDecoder *cryptoDecoderSpec)
+{
+  if (_calcCRC)
+  {
+    UInt32 crc = GetCRC();
+    if (cryptoDecoderSpec)
+      crc = cryptoDecoderSpec->Hmac_Convert_Crc32(crc);
+    if (crc != item.CRC)
+      return false;
+  }
+    
+  if (_blakeOffset >= 0)
+  {
+    Byte digest[BLAKE2S_DIGEST_SIZE];
+    Blake2sp_Final(&_blake, digest);
+    if (cryptoDecoderSpec)
+      cryptoDecoderSpec->Hmac_Convert_32Bytes(digest);
+    if (memcmp(digest, &item.Extra[(unsigned)_blakeOffset], BLAKE2S_DIGEST_SIZE) != 0)
+      return false;
+  }
+
+  return true;
+}
+
+
+Z7_CLASS_IMP_NOQIB_1(
+  COutStreamWithHash
+  , ISequentialOutStream
+)
+  ISequentialOutStream *_stream;
+  UInt64 _pos;
+  UInt64 _size;
+  bool _size_Defined;
+  Byte *_destBuf;
+public:
+  CHash _hash;
+
+  COutStreamWithHash(): _destBuf(NULL) {}
+
+  void SetStream(ISequentialOutStream *stream) { _stream = stream; }
+  void Init(const CItem &item, Byte *destBuf)
+  {
+    _size_Defined = false;
+    _size = 0;
+    _destBuf = NULL;
+    if (!item.Is_UnknownSize())
+    {
+      _size_Defined = true;
+      _size = item.Size;
+      _destBuf = destBuf;
+    }
+    _pos = 0;
+    _hash.Init(item);
+  }
+  UInt64 GetPos() const { return _pos; }
+};
+
+
+Z7_COM7F_IMF(COutStreamWithHash::Write(const void *data, UInt32 size, UInt32 *processedSize))
+{
+  HRESULT result = S_OK;
+  if (_size_Defined)
+  {
+    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;
+
+  NCrypto::NRar5::CDecoder *m_CryptoDecoderSpec;
+  CMyComPtr<ICompressFilter> 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;
+    
+  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 *cryptoDecoderSpec)
+{
+  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);
+  cryptoDecoderSpec->SetPassword((const Byte *)(const char *)utf8, utf8.Len());
+  return S_OK;
+}
+
+
+bool CInArchive::ReadVar(UInt64 &val)
+{
+  unsigned offset = ReadVarInt(_buf + _bufPos, _bufSize - _bufPos, &val);
+  _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;
+
+  const unsigned kStartSize = 4 + 3;
+  const unsigned kBufSize = AES_BLOCK_SIZE + AES_BLOCK_SIZE; // must be >= kStartSize;
+  Byte buf[kBufSize];
+  unsigned filled;
+  
+  if (m_CryptoMode)
+  {
+    RINOK(ReadStream_Check(buf, kBufSize))
+    memcpy(m_CryptoDecoderSpec->_iv, buf, AES_BLOCK_SIZE);
+    RINOK(m_CryptoDecoderSpec->Init())
+
+    _buf.AllocAtLeast(1 << 12);
+    if (!(Byte *)_buf)
+      return E_OUTOFMEMORY;
+
+    memcpy(_buf, buf + AES_BLOCK_SIZE, AES_BLOCK_SIZE);
+    if (m_CryptoDecoder->Filter(_buf, AES_BLOCK_SIZE) != AES_BLOCK_SIZE)
+      return E_FAIL;
+    memcpy(buf, _buf, AES_BLOCK_SIZE);
+    filled = AES_BLOCK_SIZE;
+  }
+  else
+  {
+    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;
+    _bufPos = (4 + offset);
+    _bufSize = _bufPos + size;
+    if (size < 2)
+      return S_FALSE;
+  }
+  
+  size_t allocSize = _bufSize;
+  if (m_CryptoMode)
+    allocSize = (allocSize + AES_BLOCK_SIZE - 1) & ~(size_t)(AES_BLOCK_SIZE - 1);
+  _buf.AllocAtLeast(allocSize);
+  if (!(Byte *)_buf)
+    return E_OUTOFMEMORY;
+  
+  memcpy(_buf, buf, filled);
+
+  size_t rem = allocSize - filled;
+  AddToSeekValue(allocSize + (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 (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 > _bufSize)
+      return S_FALSE;
+    h.ExtraSize = (size_t)extraSize;
+  }
+  
+  if (h.Flags & NHeaderFlags::kData)
+  {
+    if (!ReadVar(h.DataSize))
+      return S_FALSE;
+  }
+  
+  return S_OK;
+}
+
+
+/*
+int CInArcInfo::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;
+      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;
+      unsigned num = ReadVarInt(Extra + offset, rem, &id);
+      if (num == 0)
+        return -1;
+      offset += num;
+      rem -= num;
+
+      if (id == extraID)
+      {
+        recordDataSize = (unsigned)rem;
+        return (int)offset;
+      }
+
+      offset += rem;
+    }
+  }
+}
+
+
+bool CInArcInfo::FindExtra_Locator(CLocator &locator) const
+{
+  locator.Flags = 0;
+  locator.QuickOpen = 0;
+  locator.Recovery = 0;
+
+  unsigned size;
+  int offset = FindExtra(kArcExtraRecordType_Locator, size);
+  if (offset < 0)
+    return false;
+  const Byte *p = Extra + (unsigned)offset;
+
+  unsigned num;
+
+  num = ReadVarInt(p, size, &locator.Flags);
+  if (num == 0) return false; p += num; size -= num;
+
+  if (locator.Is_QuickOpen())
+  {
+    num = ReadVarInt(p, size, &locator.QuickOpen);
+    if (num == 0) return false; p += num; size -= num;
+  }
+
+  if (locator.Is_Recovery())
+  {
+    num = ReadVarInt(p, size, &locator.Recovery);
+    if (num == 0) return false; p += num; size -= num;
+  }
+
+  return true;
+}
+*/
+
+
+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;
+    
+    if (!m_CryptoDecoder)
+    {
+      m_CryptoDecoderSpec = new NCrypto::NRar5::CDecoder;
+      m_CryptoDecoder = m_CryptoDecoderSpec;
+    }
+
+    RINOK(m_CryptoDecoderSpec->SetDecoderProps(
+        _buf + _bufPos, (unsigned)(_bufSize - _bufPos), false, false))
+
+    RINOK(MySetPassword(getTextPassword, m_CryptoDecoderSpec))
+
+    if (!m_CryptoDecoderSpec->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 != 0)
+  {
+    if (_bufSize - _bufPos < h.ExtraSize)
+      return S_FALSE;
+    /*
+    info.Extra.Alloc(h.ExtraSize);
+    memcpy(info.Extra, _buf + _bufPos, h.ExtraSize);
+    */
+    _bufPos += h.ExtraSize;
+
+    /*
+    CInArcInfo::CLocator locator;
+    if (info.FindExtra_Locator(locator))
+      locator.Flags = locator.Flags;
+    */
+  }
+
+  if (_bufPos != _bufSize)
+    return S_FALSE;
+
+  return S_OK;
+}
+
+
+bool CInArchive::ReadFileHeader(const CHeader &header, CItem &item)
+{
+  item.UnixMTime = 0;
+  item.CRC = 0;
+  item.Flags = 0;
+  
+  item.CommonFlags = (UInt32)header.Flags;
+  item.PackSize = header.DataSize;
+
+  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 (_bufSize - _bufPos < 4)
+      return false;
+    item.UnixMTime = Get32(_buf + _bufPos);
+    _bufPos += 4;
+  }
+
+  if (item.Has_CRC())
+  {
+    if (_bufSize - _bufPos < 4)
+      return false;
+    item.CRC = Get32(_buf + _bufPos);
+    _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 > _bufSize - _bufPos)
+      return false;
+    item.Name.SetFrom_CalcLen((const char *)(_buf + _bufPos), (unsigned)len);
+    _bufPos += (unsigned)len;
+  }
+  
+  item.Extra.Free();
+  size_t extraSize = header.ExtraSize;
+  if (extraSize != 0)
+  {
+    if (_bufSize - _bufPos < extraSize)
+      return false;
+    item.Extra.Alloc(extraSize);
+    memcpy(item.Extra, _buf + _bufPos, extraSize);
+    _bufPos += extraSize;
+  }
+
+  
+  return (_bufPos == _bufSize);
+}
+
+
+
+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
+{
+  NCompress::CCopyCoder *copyCoderSpec;
+  CMyComPtr<ICompressCoder> copyCoder;
+  
+  CMyComPtr<ICompressCoder> LzCoders[2];
+  bool SolidAllowed;
+
+  CFilterCoder *filterStreamSpec;
+  CMyComPtr<ISequentialInStream> filterStream;
+
+  NCrypto::NRar5::CDecoder *cryptoDecoderSpec;
+  CMyComPtr<ICompressFilter> cryptoDecoder;
+
+  CMyComPtr<ICryptoGetTextPassword> getTextPassword;
+
+  COutStreamWithHash *outStreamSpec;
+  CMyComPtr<ISequentialOutStream> outStream;
+
+  CByteBuffer _tempBuf;
+
+  CLinkFile *linkFile;
+
+  CUnpacker(): linkFile(NULL) { SolidAllowed = false; }
+
+  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.GetAlgoVersion() != 0)
+    return E_NOTIMPL;
+
+  if (!outStream)
+  {
+    outStreamSpec = new COutStreamWithHash;
+    outStream = outStreamSpec;
+  }
+
+  unsigned method = item.GetMethod();
+
+  if (method == 0)
+  {
+    if (!copyCoder)
+    {
+      copyCoderSpec = new NCompress::CCopyCoder;
+      copyCoder = copyCoderSpec;
+    }
+  }
+  else
+  {
+    if (method > kLzMethodMax)
+      return E_NOTIMPL;
+
+    /*
+    if (item.IsSplitBefore())
+      return S_FALSE;
+    */
+
+    int lzIndex = item.IsService() ? 1 : 0;
+    CMyComPtr<ICompressCoder> &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<ICompressSetDecoderProperties2> csdp;
+    RINOK(lzCoder.QueryInterface(IID_ICompressSetDecoderProperties2, &csdp))
+
+    Byte props[2] = { (Byte)(item.GetDictSize()), (Byte)(isSolid ? 1 : 0) };
+    RINOK(csdp->SetDecoderProperties2(props, 2))
+  }
+
+  unsigned cryptoSize = 0;
+  int cryptoOffset = item.FindExtra(NExtraID::kCrypto, cryptoSize);
+
+  if (cryptoOffset >= 0)
+  {
+    if (!filterStream)
+    {
+      filterStreamSpec = new CFilterCoder(false);
+      filterStream = filterStreamSpec;
+    }
+
+    if (!cryptoDecoder)
+    {
+      cryptoDecoderSpec = new NCrypto::NRar5::CDecoder;
+      cryptoDecoder = cryptoDecoderSpec;
+    }
+
+    RINOK(cryptoDecoderSpec->SetDecoderProps(item.Extra + (unsigned)cryptoOffset, cryptoSize, true, item.IsService()))
+
+    if (!getTextPassword)
+    {
+      wrongPassword = True;
+      return E_NOTIMPL;
+    }
+
+    RINOK(MySetPassword(getTextPassword, cryptoDecoderSpec))
+      
+    if (!cryptoDecoderSpec->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;
+
+  unsigned method = item.GetMethod();
+  if (method > kLzMethodMax)
+    return E_NOTIMPL;
+
+  bool needBuf = (linkFile && linkFile->NumLinks != 0);
+
+  if (needBuf && !lastItem.Is_UnknownSize())
+  {
+    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 : LzCoders[item.IsService() ? 1 : 0];
+
+  outStreamSpec->SetStream(realOutStream);
+  outStreamSpec->Init(lastItem, (needBuf ? (Byte *)linkFile->Data : NULL));
+
+  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();
+
+  UInt64 processedSize = outStreamSpec->GetPos();
+  if (res == S_OK && !lastItem.Is_UnknownSize() && processedSize != lastItem.Size)
+    res = S_FALSE;
+
+  // if (res == S_OK)
+  {
+    unsigned cryptoSize = 0;
+    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 = cryptoDecoderSpec;
+    }
+    
+    isCrcOK = outStreamSpec->_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)
+{
+  CBufPtrSeqOutStream *outSpec = new CBufPtrSeqOutStream;
+  CMyComPtr<ISequentialOutStream> out = outSpec;
+  _tempBuf.AllocAtLeast((size_t)item.Size);
+  outSpec->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;
+
+    CLimitedSequentialInStream *limitedStreamSpec = new CLimitedSequentialInStream;
+    CMyComPtr<ISequentialInStream> limitedStream(limitedStreamSpec);
+    limitedStreamSpec->SetStream(inStream);
+    limitedStreamSpec->Init(packSize);
+
+    bool crcOK = true;
+    res = Code(item, item, packSize, limitedStream, out, NULL, crcOK);
+    if (res == S_OK)
+    {
+      if (!crcOK || outSpec->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
+      {
+        CBufInStream *bufInStreamSpec = new CBufInStream;
+        CMyComPtr<ISequentialInStream> bufInStream = bufInStreamSpec;
+        bufInStreamSpec->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,
+
+  kpidIsAltStream,
+  kpidEncrypted,
+  kpidSolid,
+  kpidSplitBefore,
+  kpidSplitAfter,
+  kpidCRC,
+  kpidHostOS,
+  kpidMethod,
+  kpidCharacts,
+  kpidSymLink,
+  kpidHardLink,
+  kpidCopyLink,
+
+  kpidVolumeIndex
+};
+
+
+static const Byte kArcProps[] =
+{
+  kpidTotalPhySize,
+  kpidCharacts,
+  kpidSolid,
+  kpidNumBlocks,
+  kpidEncrypted,
+  kpidIsVolume,
+  kpidVolumeIndex,
+  kpidNumVolumes,
+  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;
+  }
+}
+
+
+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:
+    {
+      if (!_arcs.IsEmpty())
+      {
+        FLAGS_TO_PROP(k_ArcFlags, (UInt32)arcInfo->Flags, prop);
+      }
+      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 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:
+    {
+      UInt32 numBlocks = 0;
+      FOR_VECTOR (i, _refs)
+        if (!_items[_refs[i].Item].IsSolid())
+          numBlocks++;
+      prop = (UInt32)numBlocks;
+      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;
+      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 += '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 = _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)
+  {
+    int hashRecOffset = item.FindExtra_Blake();
+    if (hashRecOffset >= 0)
+    {
+      *dataSize = BLAKE2S_DIGEST_SIZE;
+      *propType = NPropDataType::kRaw;
+      *data = &item.Extra[hashRecOffset];
+    }
+    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;
+  {
+    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 += ':';
+        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(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 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);
+      if (item2->Has_CRC())
+        prop = item2->CRC;
+      break;
+    }
+
+    case kpidMethod:
+    {
+      char temp[128];
+      unsigned algo = item.GetAlgoVersion();
+      char *s = temp;
+      if (algo != 0)
+      {
+        ConvertUInt32ToString(algo, s);
+        s += MyStringLen(s);
+        *s++ = ':';
+      }
+      unsigned m = item.GetMethod();
+      {
+        s[0] = 'm';
+        s[1] = (char)(m + '0');
+        s[2] = 0;
+        if (!item.IsDir())
+        {
+          s[2] = ':';
+          ConvertUInt32ToString(item.GetDictSize() + 17, s + 3);
+        }
+      }
+
+      unsigned cryptoSize = 0;
+      int cryptoOffset = item.FindExtra(NExtraID::kCrypto, cryptoSize);
+      if (cryptoOffset >= 0)
+      {
+        s = temp + strlen(temp);
+        *s++ = ' ';
+        
+        CCryptoInfo cryptoInfo;
+       
+        bool isOK = cryptoInfo.Parse(item.Extra + (unsigned)cryptoOffset, cryptoSize);
+        
+        if (cryptoInfo.Algo == 0)
+          s = MyStpCpy(s, "AES");
+        else
+        {
+          s = MyStpCpy(s, "Crypto_");
+          ConvertUInt64ToString(cryptoInfo.Algo, s);
+          s += strlen(s);
+        }
+
+        if (isOK)
+        {
+          *s++ = ':';
+          ConvertUInt32ToString(cryptoInfo.Cnt, s);
+          s += strlen(s);
+          *s++ = ':';
+          ConvertUInt64ToString(cryptoInfo.Flags, s);
+        }
+      }
+
+      prop = temp;
+      break;
+    }
+    
+    case kpidCharacts:
+    {
+      AString s;
+
+      if (item.ACL >= 0)
+      {
+        s.Add_OptSpaced("ACL");
+      }
+
+      UInt32 flags = item.Flags;
+      // flags &= ~(6); // we don't need compression related bits here.
+
+      if (flags != 0)
+      {
+        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;
+    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)
+{
+  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;
+  
+  for (i = 0; i < _refs.Size(); i++)
+  {
+    const CItem &item = _items[_refs[i].Item];
+    if (!item.IsDir() && !item.IsService() && item.NeedUse_as_CopyLink())
+      break;
+  }
+
+  if (i == _refs.Size())
+    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);
+    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<IArchiveOpenVolumeCallback> openVolumeCallback;
+  CMyComPtr<ICryptoGetTextPassword> getTextPassword;
+  
+  NRar::CVolumeName seqName;
+  
+  UInt64 totalBytes = 0;
+  UInt64 curBytes = 0;
+  
+  if (openCallback)
+  {
+    openCallback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback);
+    openCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&getTextPassword);
+  }
+  
+  CTempBuf tempBuf;
+  
+  CUnpacker unpacker;
+  unpacker.getTextPassword = getTextPassword;
+  
+  int prevSplitFile = -1;
+  int prevMainFile = -1;
+  
+  bool nextVol_is_Required = false;
+
+  CInArchive arch;
+  
+  for (;;)
+  {
+    CMyComPtr<IInStream> 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();
+      
+      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 arcInfoOpen;
+    {
+    HRESULT res = arch.Open(inStream, maxCheckStartPosition, getTextPassword, arcInfoOpen);
+    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 = arcInfoOpen;
+    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;
+        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 (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.MainPartSize = (UInt32)(Position - item.Position);
+        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.Size() == 0
+            && item.Is_CMT()
+            && item.PackSize < kCommentSize_Max
+            && item.PackSize == item.Size
+            && item.PackSize != 0
+            && item.GetMethod() == 0
+            && !item.IsSplit())
+        {
+          RINOK(unpacker.DecodeToBuf(EXTERNAL_CODECS_VARS item, item.PackSize, inStream, _comment))
+          needAdd = false;
+        }
+      }
+      
+      if (needAdd)
+      {
+        CRefItem ref;
+        ref.Item = _items.Size();
+        ref.Last = ref.Item;
+        ref.Parent = -1;
+        ref.Link = -1;
+        
+        if (item.IsService())
+        {
+          if (item.Is_STM())
+          {
+            if (prevMainFile >= 0)
+              ref.Parent = prevMainFile;
+          }
+          else
+          {
+            needAdd = false;
+            if (item.Is_ACL() && (!item.IsEncrypted() || arch.m_CryptoMode))
+            {
+              if (prevMainFile >= 0 && item.Size < (1 << 24) && item.Size != 0)
+              {
+                CItem &mainItem = _items[_refs[prevMainFile].Item];
+                
+                if (mainItem.ACL < 0)
+                {
+                  CByteBuffer acl;
+                  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;
+                  }
+                  // RINOK();
+                  
+                  if (res == S_OK && acl.Size() != 0)
+                  {
+                    if (_acls.IsEmpty() || acl != _acls.Back())
+                      _acls.Add(acl);
+                    mainItem.ACL = (int)_acls.Size() - 1;
+                  }
+                }
+              }
+            }
+          }
+        }
+        
+        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;
+              }
+            }
+          }
+        }
+        
+        if (needAdd)
+        {
+          if (item.IsSplitAfter())
+            prevSplitFile = (int)_refs.Size();
+          if (!item.IsService())
+            prevMainFile = (int)_refs.Size();
+          _refs.Add(ref);
+        }
+      }
+      
+      {
+        UInt64 version;
+        if (item.FindExtra_Version(version))
+        {
+          item.Version_Defined = true;
+          item.Version = version;
+        }
+      }
+      
+      item.VolIndex = _arcs.Size() - 1;
+      _items.Add(item);
+      
+      if (openCallback && (_items.Size() & 0xFF) == 0)
+      {
+        UInt64 numFiles = _items.Size();
+        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;
+  _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<CArc> *_arcs;
+  const CObjectVector<CItem> *_items;
+  int _itemIndex;
+public:
+  bool CrcIsOK;
+private:
+  CHash _hash;
+public:
+  void Init(const CObjectVector<CArc> *arcs,
+      const CObjectVector<CItem> *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;
+      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<CLinkFile> &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)
+{
+  size_t pos = 0;
+  
+  while (pos < size)
+  {
+    const UInt32 kStepSize = ((UInt32)1 << 24);
+    UInt32 cur32;
+    {
+      size_t cur = size - pos;
+      if (cur > kStepSize)
+        cur = kStepSize;
+      cur32 = (UInt32)cur;
+    }
+    RINOK(outStream->Write(data + pos, cur32, &cur32))
+    if (cur32 == 0)
+      return E_FAIL;
+    pos += cur32;
+    if (progress)
+    {
+      UInt64 pos64 = pos;
+      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 = _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<CLinkFile> linkFiles;
+
+  {
+    UInt64 total = 0;
+    bool isThereUndefinedSize = false;
+    bool thereAreLinks = false;
+
+    {
+      unsigned solidLimit = 0;
+      for (UInt32 t = 0; t < numItems; t++)
+      {
+        unsigned index = 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++)
+      {
+        unsigned index = allFilesMode ? t : indices[t];
+        const CRefItem &ref = _refs[index];
+       
+        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))
+    }
+  }
+
+
+  UInt64 totalUnpacked = 0;
+  UInt64 totalPacked = 0;
+  UInt64 curUnpackSize = 0;
+  UInt64 curPackSize = 0;
+
+  CUnpacker unpacker;
+
+  CVolsInStream *volsInStreamSpec = new CVolsInStream;
+  CMyComPtr<ISequentialInStream> volsInStream = volsInStreamSpec;
+
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> progress = lps;
+  lps->Init(extractCallback, false);
+
+  // bool needClearSolid = true;
+
+  FOR_VECTOR (i, _refs)
+  {
+    if (extractStatuses[i] == 0)
+      continue;
+
+    totalUnpacked += curUnpackSize;
+    totalPacked += curPackSize;
+    lps->InSize = totalPacked;
+    lps->OutSize = totalUnpacked;
+    RINOK(lps->SetCur())
+    
+    CMyComPtr<ISequentialOutStream> realOutStream;
+
+    // isExtract means that we don't skip that item. So we need read data.
+
+    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)
+    {
+      int bufIndex = FindLinkBuf(linkFiles, i);
+      if (bufIndex < 0)
+        return E_FAIL;
+      unpacker.linkFile = &linkFiles[bufIndex];
+    }
+
+    UInt32 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);
+
+    RINOK(extractCallback->GetStream(index, &realOutStream, askMode))
+
+    bool isSolid = false;
+    if (!item->IsService())
+    {
+      if (item->IsSolid())
+        isSolid = unpacker.SolidAllowed;
+      unpacker.SolidAllowed = isSolid;
+    }
+
+    if (item->IsDir())
+    {
+      RINOK(extractCallback->PrepareOperation(askMode))
+      RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
+      continue;
+    }
+
+    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, progress))
+        }
+      
+        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())
+    {
+      int opRes = realOutStream ?
+          NExtract::NOperationResult::kUnsupportedMethod:
+          NExtract::NOperationResult::kOK;
+      realOutStream.Release();
+      RINOK(extractCallback->SetOperationResult(opRes))
+      continue;
+    }
+
+    volsInStreamSpec->Init(&_arcs, &_items, ref->Item);
+
+    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, progress, crcOK);
+    realOutStream.Release();
+    if (!volsInStreamSpec->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 (i, linkFiles)
+      if (linkFiles[i].NumLinks != 0)
+        return E_FAIL;
+  }
+
+  return S_OK;
+  
+  COM_TRY_END
+}
+
+
+IMPL_ISetCompressCodecsInfo
+
+REGISTER_ARC_I(
+  "Rar5", "rar r00", NULL, 0xCC,
+  kMarker,
+  0,
+  NArcInfoFlags::kFindSignature,
+  NULL)
+
+}}
+
+
+Z7_CLASS_IMP_COM_1(
+  CBlake2spHasher
+  , IHasher
+)
+  CBlake2sp _blake;
+public:
+  Byte _mtDummy[1 << 7];  // it's public to eliminate clang warning: unused private field
+  CBlake2spHasher() { Init(); }
+};
+
+Z7_COM7F_IMF2(void, CBlake2spHasher::Init())
+{
+  Blake2sp_Init(&_blake);
+}
+
+Z7_COM7F_IMF2(void, CBlake2spHasher::Update(const void *data, UInt32 size))
+{
+  Blake2sp_Update(&_blake, (const Byte *)data, size);
+}
+
+Z7_COM7F_IMF2(void, CBlake2spHasher::Final(Byte *digest))
+{
+  Blake2sp_Final(&_blake, digest);
+}
+
+REGISTER_HASHER(CBlake2spHasher, 0x202, "BLAKE2sp", BLAKE2S_DIGEST_SIZE)
diff --git a/CPP/7zip/Archive/Rar/Rar5Handler.h b/CPP/7zip/Archive/Rar/Rar5Handler.h
new file mode 100644
index 0000000..72e1efc
--- /dev/null
+++ b/CPP/7zip/Archive/Rar/Rar5Handler.h
@@ -0,0 +1,419 @@
+// 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;
+
+namespace NLocatorFlags
+{
+  const unsigned kQuickOpen  = 1 << 0;
+  const unsigned kRecovery   = 1 << 1;
+}
+
+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;
+}
+
+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;
+
+  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;
+    
+    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;
+  }
+
+  bool IsSolid() const { return ((UInt32)Method & NMethodFlags::kSolid) != 0; }
+  unsigned GetAlgoVersion() const { return (unsigned)Method & 0x3F; }
+  unsigned GetMethod() const { return ((unsigned)Method >> 7) & 0x7; }
+  UInt32 GetDictSize() const { return (((UInt32)Method >> 10) & 0xF); }
+
+  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;
+    int offset = FindExtra(NExtraID::kHash, size);
+    if (offset >= 0
+        && size == 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); 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;
+
+  // CByteBuffer Extra;
+
+  /*
+  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; }
+  };
+
+  int FindExtra(unsigned extraID, unsigned &recordDataSize) const;
+  bool FindExtra_Locator(CLocator &locator) const;
+  */
+
+  CInArcInfo():
+    Flags(0),
+    VolNumber(0),
+    StartPos(0),
+    EndPos(0),
+    EndFlags(0),
+    EndOfArchive_was_Read(false),
+    IsEncrypted(false)
+      {}
+
+  /*
+  void Clear()
+  {
+    Flags = 0;
+    VolNumber = 0;
+    StartPos = 0;
+    EndPos = 0;
+    EndFlags = 0;
+    EndOfArchive_was_Read = false;
+    Extra.Free();
+  }
+  */
+
+  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;
+  unsigned Last;
+  int Parent;
+  int Link;
+};
+
+
+struct CArc
+{
+  CMyComPtr<IInStream> Stream;
+  CInArcInfo Info;
+};
+
+
+class CHandler Z7_final:
+  public IInArchive,
+  public IArchiveGetRawProps,
+  Z7_PUBLIC_ISetCompressCodecsInfo_IFEC
+  public CMyUnknownImp
+{
+  Z7_COM_QI_BEGIN2(IInArchive)
+  Z7_COM_QI_ENTRY(IArchiveGetRawProps)
+  Z7_COM_QI_ENTRY_ISetCompressCodecsInfo_IFEC
+  Z7_COM_QI_END
+  Z7_COM_ADDREF_RELEASE
+  
+  Z7_IFACE_COM7_IMP(IInArchive)
+  Z7_IFACE_COM7_IMP(IArchiveGetRawProps)
+  DECL_ISetCompressCodecsInfo
+
+public:
+  CRecordVector<CRefItem> _refs;
+  CObjectVector<CItem> _items;
+private:
+  CObjectVector<CArc> _arcs;
+  CObjectVector<CByteBuffer> _acls;
+
+  UInt32 _errorFlags;
+  // UInt32 _warningFlags;
+  bool _isArc;
+  CByteBuffer _comment;
+  UString _missingVolName;
+
+  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
new file mode 100644
index 0000000..9157acc
--- /dev/null
+++ b/CPP/7zip/Archive/Rar/RarHandler.cpp
@@ -0,0 +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<ICompressFilter> 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<IArchiveOpenVolumeCallback> openVolumeCallback;
+    CMyComPtr<ICryptoGetTextPassword> 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<IInStream> 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<ICompressCoder> Coder;
+};
+
+
+Z7_CLASS_IMP_NOQIB_1(
+  CVolsInStream
+  , ISequentialInStream
+)
+  UInt64 _rem;
+  ISequentialInStream *_stream;
+  const CObjectVector<CArc> *_arcs;
+  const CObjectVector<CItem> *_items;
+  CRefItem _refItem;
+  unsigned _curIndex;
+  UInt32 _crc;
+  bool _calcCrc;
+
+public:
+  void Init(const CObjectVector<CArc> *arcs,
+      const CObjectVector<CItem> *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<ICryptoGetTextPassword> 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<unsigned> importantIndexes;
+  CRecordVector<bool> 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<CMethodItem> methodItems;
+
+  NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder;
+  CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+  CFilterCoder *filterStreamSpec = new CFilterCoder(false);
+  CMyComPtr<ISequentialInStream> filterStream = filterStreamSpec;
+
+  NCrypto::NRar2::CDecoder *rar20CryptoDecoderSpec = NULL;
+  CMyComPtr<ICompressFilter> rar20CryptoDecoder;
+  NCrypto::NRar3::CDecoder *rar3CryptoDecoderSpec = NULL;
+  CMyComPtr<ICompressFilter> rar3CryptoDecoder;
+
+  CVolsInStream *volsInStreamSpec = NULL;
+  CMyComPtr<ISequentialInStream> volsInStream;
+
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> 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<ISequentialOutStream> 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<ISequentialOutStream> 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<ISequentialInStream> inStream;
+    
+    if (item.IsEncrypted())
+    {
+      // CMyComPtr<ICryptoSetPassword> cryptoSetPassword;
+      
+      if (item.UnPackVersion >= 29)
+      {
+        if (!rar3CryptoDecoder)
+        {
+          rar3CryptoDecoderSpec = new NCrypto::NRar3::CDecoder;
+          rar3CryptoDecoder = rar3CryptoDecoderSpec;
+        }
+        // rar3CryptoDecoderSpec->SetRar350Mode(item.UnPackVersion < 36);
+        /*
+        CMyComPtr<ICompressSetDecoderProperties2> 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<ICompressCoder> 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<ICompressCoder> decoder = methodItems[m].Coder;
+
+        CMyComPtr<ICompressSetDecoderProperties2> 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
new file mode 100644
index 0000000..c4d8450
--- /dev/null
+++ b/CPP/7zip/Archive/Rar/RarHandler.h
@@ -0,0 +1,114 @@
+// 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<IInStream> 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
+
+  CRecordVector<CRefItem> _refItems;
+  CObjectVector<CItem> _items;
+  CObjectVector<CArc> _arcs;
+  NArchive::NRar::CInArcInfo _arcInfo;
+  // AString _errorMessage;
+  UInt32 _errorFlags;
+  UInt32 _warningFlags;
+  bool _isArc;
+  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 += '\n';
+    _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
new file mode 100644
index 0000000..031fea6
--- /dev/null
+++ b/CPP/7zip/Archive/Rar/RarHeader.h
@@ -0,0 +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
diff --git a/CPP/7zip/Archive/Rar/RarItem.h b/CPP/7zip/Archive/Rar/RarItem.h
new file mode 100644
index 0000000..e1028ba
--- /dev/null
+++ b/CPP/7zip/Archive/Rar/RarItem.h
@@ -0,0 +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
diff --git a/CPP/7zip/Archive/Rar/RarVol.h b/CPP/7zip/Archive/Rar/RarVol.h
new file mode 100644
index 0000000..9ee8e86
--- /dev/null
+++ b/CPP/7zip/Archive/Rar/RarVol.h
@@ -0,0 +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
diff --git a/CPP/7zip/Archive/Rar/StdAfx.cpp b/CPP/7zip/Archive/Rar/StdAfx.cpp
new file mode 100644
index 0000000..d0feea8
--- /dev/null
+++ b/CPP/7zip/Archive/Rar/StdAfx.cpp
@@ -0,0 +1,3 @@
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/CPP/7zip/Archive/Rar/StdAfx.h b/CPP/7zip/Archive/Rar/StdAfx.h
new file mode 100644
index 0000000..035267c
--- /dev/null
+++ b/CPP/7zip/Archive/Rar/StdAfx.h
@@ -0,0 +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
diff --git a/CPP/7zip/Archive/RpmHandler.cpp b/CPP/7zip/Archive/RpmHandler.cpp
new file mode 100644
index 0000000..e05ac26
--- /dev/null
+++ b/CPP/7zip/Archive/RpmHandler.cpp
@@ -0,0 +1,769 @@
+// 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
+};
+
+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
+{
+  unsigned char Major;
+  unsigned char 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
+
+  CLead _lead;
+
+  #ifdef Z7_RPM_SHOW_METADATA
+  AString _metadata;
+  CRecordVector<CMetaFile> _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
+  {
+    const Byte *p = _payloadSig;
+    if (p[0] == 0x1F && p[1] == 0x8B)
+      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
+      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;
+}
+
+#ifdef Z7_RPM_SHOW_METADATA
+static inline char GetHex(unsigned value)
+{
+  return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10)));
+}
+#endif
+
+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 += '\n';
+          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 += GetHex((b >> 4) & 0xF);
+          _metadata += GetHex(b & 0xF);
+        }
+      }
+      else
+      {
+        // p = p;
+      }
+
+      _metadata += '\n';
+      #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
new file mode 100644
index 0000000..ab76f32
--- /dev/null
+++ b/CPP/7zip/Archive/SparseHandler.cpp
@@ -0,0 +1,547 @@
+// 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;
+};
+
+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<CChunk> 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<ISequentialInStream> 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 ffb0e33..ae7ca03 100644
--- a/CPP/7zip/Archive/SplitHandler.cpp
+++ b/CPP/7zip/Archive/SplitHandler.cpp
@@ -1,359 +1,351 @@
-// 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 "../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

-};

-

-class CHandler:

-  public IInArchive,

-  public IInArchiveGetStream,

-  public CMyUnknownImp

-{

-  CObjectVector<CMyComPtr<IInStream> > _streams;

-  CRecordVector<UInt64> _sizes;

-  UString _subName;

-  UInt64 _totalSize;

-

-  HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback);

-public:

-  MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)

-  INTERFACE_IInArchive(;)

-  STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);

-};

-

-IMP_IInArchive_Props

-IMP_IInArchive_ArcProps

-

-STDMETHODIMP 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;

-  }

-  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;

-

-  CMyComPtr<IArchiveOpenVolumeCallback> volumeCallback;

-  callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&volumeCallback);

-  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;

-  }

-  

-  int dotPos = name.ReverseFind_Dot();

-  const UString prefix = name.Left(dotPos + 1);

-  const UString ext = name.Ptr(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 (ext.Len() >= 2 && StringsAreEqual_Ascii(ext2.RightPtr(2), "01"))

-  {

-    while (numLetters < ext2.Len())

-    {

-      if (ext2[ext2.Len() - numLetters - 1] != '0')

-        break;

-      numLetters++;

-    }

-    if (numLetters != ext.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(stream->Seek(0, STREAM_SEEK_END, &size));

-    RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));

-  }

-  

-  _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<IInStream> nextStream;

-    HRESULT result = volumeCallback->GetStream(fullName, &nextStream);

-    if (result == S_FALSE)

-      break;

-    if (result != S_OK)

-      return result;

-    if (!nextStream)

-      break;

-    {

-      /*

-      NCOM::CPropVariant prop;

-      RINOK(volumeCallback->GetProperty(kpidSize, &prop));

-      if (prop.vt != VT_UI8)

-        return E_INVALIDARG;

-      size = prop.uhVal.QuadPart;

-      */

-      RINOK(nextStream->Seek(0, STREAM_SEEK_END, &size));

-      RINOK(nextStream->Seek(0, STREAM_SEEK_SET, NULL));

-    }

-    _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;

-}

-

-STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback)

-{

-  COM_TRY_BEGIN

-  HRESULT res = Open2(stream, callback);

-  if (res != S_OK)

-    Close();

-  return res;

-  COM_TRY_END

-}

-

-STDMETHODIMP CHandler::Close()

-{

-  _totalSize = 0;

-  _subName.Empty();

-  _streams.Clear();

-  _sizes.Clear();

-  return S_OK;

-}

-

-STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)

-{

-  *numItems = _streams.IsEmpty() ? 0 : 1;

-  return S_OK;

-}

-

-STDMETHODIMP 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;

-  }

-  prop.Detach(value);

-  return S_OK;

-}

-

-STDMETHODIMP 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<ISequentialOutStream> outStream;

-  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<ICompressCoder> copyCoder = copyCoderSpec;

-

-  CLocalProgress *lps = new CLocalProgress;

-  CMyComPtr<ICompressProgressInfo> progress = lps;

-  lps->Init(extractCallback, false);

-

-  FOR_VECTOR (i, _streams)

-  {

-    lps->InSize = lps->OutSize = currentTotalSize;

-    RINOK(lps->SetCur());

-    IInStream *inStream = _streams[i];

-    RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL));

-    RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));

-    currentTotalSize += copyCoderSpec->TotalSize;

-  }

-  outStream.Release();

-  return extractCallback->SetOperationResult(NExtract::NOperationResult::kOK);

-  COM_TRY_END

-}

-

-STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)

-{

-  COM_TRY_BEGIN

-  if (index != 0)

-    return E_INVALIDARG;

-  *stream = 0;

-  CMultiStream *streamSpec = new CMultiStream;

-  CMyComPtr<ISequentialInStream> 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", 0, 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<CMyComPtr<IInStream> > _streams;
+  CRecordVector<UInt64> _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;
+  }
+  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<IInStream> 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;
+  }
+  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<ISequentialOutStream> 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<ICompressCoder> copyCoder = copyCoderSpec;
+
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> 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<ISequentialInStream> 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
new file mode 100644
index 0000000..9c9ec03
--- /dev/null
+++ b/CPP/7zip/Archive/SquashfsHandler.cpp
@@ -0,0 +1,2326 @@
+// SquashfsHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+#include "../../../C/CpuArch.h"
+#include "../../../C/LzmaDec.h"
+#include "../../../C/Xz.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
+
+static const char * const k_Methods[] =
+{
+    "0"
+  , "ZLIB"
+  , "LZMA"
+  , "LZO"
+  , "XZ"
+};
+
+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<UInt32> PackPos;
+  CRecordVector<UInt32> 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
+)
+  CRecordVector<CItem> _items;
+  CRecordVector<CNode> _nodes;
+  CRecordVector<UInt32> _nodesPos;
+  CRecordVector<UInt32> _blockToNode;
+  CData _inodesData;
+  CData _dirs;
+  CRecordVector<CFrag> _frags;
+  CByteBuffer _uids;
+  CByteBuffer _gids;
+  CHeader _h;
+  bool _noPropsLZMA;
+  bool _needCheckLzma;
+  
+  UInt32 _openCodePage;
+
+  CMyComPtr<IInStream> _stream;
+  UInt64 _sizeCalculated;
+
+  IArchiveOpenCallback *_openCallback;
+
+  int _nodeIndex;
+  CRecordVector<bool> _blockCompressed;
+  CRecordVector<UInt64> _blockOffsets;
+  
+  CByteBuffer _cachedBlock;
+  UInt64 _cachedBlockStartPos;
+  UInt32 _cachedPackBlockSize;
+  UInt32 _cachedUnpackBlockSize;
+
+  CLimitedSequentialInStream *_limitedInStreamSpec;
+  CMyComPtr<ISequentialInStream> _limitedInStream;
+
+  CBufPtrSeqOutStream *_outStreamSpec;
+  CMyComPtr<ISequentialOutStream> _outStream;
+
+  // NCompress::NLzma::CDecoder *_lzmaDecoderSpec;
+  // CMyComPtr<ICompressCoder> _lzmaDecoder;
+
+  NCompress::NZlib::CDecoder *_zlibDecoderSpec;
+  CMyComPtr<ICompressCoder> _zlibDecoder;
+  
+  CXzUnpacker _xz;
+
+  CByteBuffer _inputBuffer;
+
+  CDynBufSeqOutStream *_dynOutStreamSpec;
+  CMyComPtr<ISequentialOutStream> _dynOutStream;
+
+  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);
+  }
+
+  HRESULT ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize);
+};
+
+
+CHandler::CHandler()
+{
+  XzUnpacker_Construct(&_xz, &g_Alloc);
+
+  _limitedInStreamSpec = new CLimitedSequentialInStream;
+  _limitedInStream = _limitedInStreamSpec;
+
+  _outStreamSpec = new CBufPtrSeqOutStream();
+  _outStream = _outStreamSpec;
+
+  _dynOutStreamSpec = new CDynBufSeqOutStream;
+  _dynOutStream = _dynOutStreamSpec;
+}
+
+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)
+  {
+    if (!_zlibDecoder)
+    {
+      _zlibDecoderSpec = new NCompress::NZlib::CDecoder();
+      _zlibDecoder = _zlibDecoderSpec;
+    }
+    RINOK(_zlibDecoder->Code(_limitedInStream, outStream, NULL, NULL, NULL))
+    if (inSize != _zlibDecoderSpec->GetInputProcessedSize())
+      return S_FALSE;
+  }
+  /*
+  else if (method == kMethod_LZMA)
+  {
+    if (!_lzmaDecoder)
+    {
+      _lzmaDecoderSpec = new NCompress::NLzma::CDecoder();
+      // _lzmaDecoderSpec->FinishStream = true;
+      _lzmaDecoder = _lzmaDecoderSpec;
+    }
+    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 = _dynOutStreamSpec->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
+    {
+      ECoderStatus status;
+      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
+      _dynOutStreamSpec->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)
+  {
+    _limitedInStreamSpec->Init(size);
+    RINOK(Decompress(_dynOutStream, NULL, NULL, NULL, size, kMetadataBlockSize))
+  }
+  else
+  {
+    // size != 0 here
+    Byte *buf = _dynOutStreamSpec->GetBufPtrForWriting(size);
+    if (!buf)
+      return E_OUTOFMEMORY;
+    RINOK(ReadStream_FALSE(_stream, buf, size))
+    _dynOutStreamSpec->UpdateSize(size);
+  }
+  return S_OK;
+}
+
+
+HRESULT CHandler::ReadMetadataBlock2()
+{
+  _dynOutStreamSpec->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))
+  _dynOutStreamSpec->Init();
+  UInt32 packPos = 0;
+  while (packPos != size)
+  {
+    data.PackPos.Add(packPos);
+    data.UnpackPos.Add((UInt32)_dynOutStreamSpec->GetSize());
+    if (packPos > size)
+      return S_FALSE;
+    UInt32 packSize = size - packPos;
+    RINOK(ReadMetadataBlock(packSize))
+    {
+      const size_t tSize = _dynOutStreamSpec->GetSize();
+      if (tSize != (UInt32)tSize)
+        return S_FALSE;
+    }
+    packPos += packSize;
+  }
+  data.UnpackPos.Add((UInt32)_dynOutStreamSpec->GetSize());
+  _dynOutStreamSpec->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<CTempItem> 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 ((UInt32)_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:
+        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)_dynOutStreamSpec->GetSize();
+      if (unpackSize != kMetadataBlockSize)
+        if (i != numBlocks - 1 || unpackSize != ((_h.NumFrags << (3 + bigFrag)) & (kMetadataBlockSize - 1)))
+          return S_FALSE;
+      const Byte *buf = _dynOutStreamSpec->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 = _dynOutStreamSpec->GetSize();
+      const UInt32 remSize = (i == numBlocks - 1)  ?
+          (size & (kMetadataBlockSize - 1)) : kMetadataBlockSize;
+      if (unpackSize != remSize)
+        return S_FALSE;
+      memcpy(_uids + kMetadataBlockSize * i, _dynOutStreamSpec->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();
+    _limitedInStreamSpec->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;
+
+  _limitedInStreamSpec->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))
+    _limitedInStreamSpec->Init(packBlockSize);
+    
+    if (compressed)
+    {
+      _outStreamSpec->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)_outStreamSpec->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();
+  }
+  extractCallback->SetTotal(totalSize);
+
+  UInt64 totalPackSize;
+  totalSize = totalPackSize = 0;
+  
+  NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+  CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> progress = lps;
+  lps->Init(extractCallback, false);
+
+  for (i = 0; i < numItems; i++)
+  {
+    lps->InSize = totalPackSize;
+    lps->OutSize = totalSize;
+    RINOK(lps->SetCur())
+    CMyComPtr<ISequentialOutStream> 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;
+    }
+    UInt64 unpackSize = node.GetSize();
+    totalSize += unpackSize;
+    UInt64 packSize;
+    if (GetPackSize(index, packSize, false))
+      totalPackSize += packSize;
+
+    if (!testMode && !outStream)
+      continue;
+    RINOK(extractCallback->PrepareOperation(askMode))
+
+    int res = NExtract::NOperationResult::kDataError;
+    {
+      CMyComPtr<ISequentialInStream> 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->Code(inSeqStream, outStream, NULL, NULL, progress);
+          if (hres == S_OK)
+          {
+            if (copyCoderSpec->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<IInStream> 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<IInStream> 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 42a088f..8086655 100644
--- a/CPP/7zip/Archive/StdAfx.h
+++ b/CPP/7zip/Archive/StdAfx.h
@@ -1,8 +1,11 @@
-// StdAfx.h

-

-#ifndef __STDAFX_H

-#define __STDAFX_H

-

-#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
new file mode 100644
index 0000000..ab704b6
--- /dev/null
+++ b/CPP/7zip/Archive/SwfHandler.cpp
@@ -0,0 +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<ISequentialInStream> _seqStream;
+  CMyComPtr<IInStream> _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<IArchiveOpenCallback> 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()))
+  CMyComPtr<ISequentialOutStream> 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);
+
+  CDummyOutStream *outStreamSpec = new CDummyOutStream;
+  CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+  outStreamSpec->SetStream(realOutStream);
+  outStreamSpec->Init();
+  realOutStream.Release();
+
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> progress = lps;
+  lps->Init(extractCallback, false);
+
+  lps->InSize = _item.HeaderSize;
+  lps->OutSize = outStreamSpec->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<ICompressCoder> _decoder;
+
+  CMyComPtr<ISequentialInStream> inStream2;
+
+  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))
+  HRESULT result = _decoder->Code(inStream2, outStream, NULL, &unpackSize, progress);
+  Int32 opRes = NExtract::NOperationResult::kDataError;
+  if (result == S_OK)
+  {
+    if (item.GetSize() == outStreamSpec->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<ISequentialInStream> fileInStream;
+  RINOK(updateCallback->GetStream(0, &fileInStream))
+
+  /*
+  CDummyOutStream *outStreamSpec = new CDummyOutStream;
+  CMyComPtr<ISequentialOutStream> 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<ICompressCoder> encoder;
+  CMyComPtr<IOutStream> 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<ISequentialOutStream> 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))
+
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> progress = lps;
+  lps->Init(updateCallback, true);
+  
+  RINOK(encoder->Code(fileInStream, outStream, NULL, NULL, progress))
+  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<CTag> _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<ICompressProgressInfo> 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<ISequentialOutStream> 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
new file mode 100644
index 0000000..035267c
--- /dev/null
+++ b/CPP/7zip/Archive/Tar/StdAfx.h
@@ -0,0 +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
diff --git a/CPP/7zip/Archive/Tar/TarHandler.cpp b/CPP/7zip/Archive/Tar/TarHandler.cpp
new file mode 100644
index 0000000..d7fe175
--- /dev/null
+++ b/CPP/7zip/Archive/Tar/TarHandler.cpp
@@ -0,0 +1,1045 @@
+// 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,
+  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 (_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;
+        // 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;
+      }
+      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._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;
+    }
+  }
+  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()
+{
+  copyCoderSpec = new NCompress::CCopyCoder();
+  copyCoder = copyCoderSpec;
+  _openCodePage = CP_UTF8;
+  Init();
+}
+
+HRESULT CHandler::SkipTo(UInt32 index)
+{
+  while (_curIndex < index || !_latestIsRead)
+  {
+    if (_latestIsRead)
+    {
+      const UInt64 packSize = _latestItem.Get_PackSize_Aligned();
+      RINOK(copyCoder->Code(_seqStream, NULL, &packSize, &packSize, NULL))
+      _arc._phySize += copyCoderSpec->TotalSize;
+      if (copyCoderSpec->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);
+}
+
+
+#define ValToHex(t) ((char)(((t) < 10) ? ('0' + (t)) : ('a' + ((t) - 10))))
+
+static void AddByteToHex2(unsigned val, AString &s)
+{
+  unsigned t;
+  t = val >> 4;
+  s += ValToHex(t);
+  t = val & 0xF;
+  s += ValToHex(t);
+}
+
+static void AddSpecCharToString(const char c, AString &s)
+{
+  if ((Byte)c <= 0x20 || (Byte)c > 127)
+  {
+    s += '[';
+    AddByteToHex2((Byte)(c), s);
+    s += ']';
+  }
+  else
+    s += c;
+}
+
+static void AddSpecUInt64(AString &s, const char *name, UInt64 v)
+{
+  if (v != 0)
+  {
+    s.Add_OptSpaced(name);
+    if (v > 1)
+    {
+      s += ':';
+      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 += '*';
+  }
+}
+
+
+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;
+    
+    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->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
+  }
+  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();
+  extractCallback->SetTotal(totalSize);
+
+  UInt64 totalPackSize;
+  totalSize = totalPackSize = 0;
+  
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> progress = lps;
+  lps->Init(extractCallback, false);
+
+  CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+  CMyComPtr<ISequentialInStream> inStream(streamSpec);
+  streamSpec->SetStream(stream);
+
+  CLimitedSequentialOutStream *outStreamSpec = new CLimitedSequentialOutStream;
+  CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+
+  for (i = 0; i < numItems || seqMode; i++)
+  {
+    lps->InSize = totalPackSize;
+    lps->OutSize = totalSize;
+    RINOK(lps->SetCur())
+    CMyComPtr<ISequentialOutStream> realOutStream;
+    Int32 askMode = testMode ?
+        NExtract::NAskMode::kTest :
+        NExtract::NAskMode::kExtract;
+    const UInt32 index = allFilesMode ? i : indices[i];
+    const CItemEx *item;
+    if (seqMode)
+    {
+      HRESULT res = SkipTo(index);
+      if (res == E_INVALIDARG)
+        break;
+      RINOK(res)
+      item = &_latestItem;
+    }
+    else
+      item = &_items[index];
+
+    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))
+      RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
+      continue;
+    }
+    bool skipMode = false;
+    if (!testMode && !realOutStream)
+    {
+      if (!seqMode)
+      {
+        /*
+        // probably we must show extracting info it callback handler instead
+        if (item->IsHardLink() ||
+            item->IsSymLink())
+        {
+          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<ISequentialInStream> 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()))
+        }
+        streamSpec->Init(item->Get_PackSize_Aligned());
+        RINOK(copyCoder->Code(inStream2, outStream, NULL, NULL, progress))
+      }
+      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<IUnknown> HandlerRef;
+  unsigned ItemIndex;
+  CRecordVector<UInt64> 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<IInStream> 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
new file mode 100644
index 0000000..451c2fd
--- /dev/null
+++ b/CPP/7zip/Archive/Tar/TarHandler.h
@@ -0,0 +1,58 @@
+// 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<CItemEx> _items;
+  CMyComPtr<IInStream> _stream;
+  CMyComPtr<ISequentialInStream> _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;
+
+  NCompress::CCopyCoder *copyCoderSpec;
+  CMyComPtr<ICompressCoder> 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
new file mode 100644
index 0000000..c93a86e
--- /dev/null
+++ b/CPP/7zip/Archive/Tar/TarHandlerOut.cpp
@@ -0,0 +1,332 @@
+// TarHandlerOut.cpp
+
+#include "StdAfx.h"
+
+// #include <stdio.h>
+
+#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<CUpdateItem> 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 += '/';
+      // ui.Name += '/'; // 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
new file mode 100644
index 0000000..deae357
--- /dev/null
+++ b/CPP/7zip/Archive/Tar/TarHeader.cpp
@@ -0,0 +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); }
+*/
+
+}}}
diff --git a/CPP/7zip/Archive/Tar/TarHeader.h b/CPP/7zip/Archive/Tar/TarHeader.h
new file mode 100644
index 0000000..aeccd28
--- /dev/null
+++ b/CPP/7zip/Archive/Tar/TarHeader.h
@@ -0,0 +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
diff --git a/CPP/7zip/Archive/Tar/TarIn.cpp b/CPP/7zip/Archive/Tar/TarIn.cpp
new file mode 100644
index 0000000..90b6f84
--- /dev/null
+++ b/CPP/7zip/Archive/Tar/TarIn.cpp
@@ -0,0 +1,1132 @@
+// 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 += '/';
+    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;
+  
+  UInt64 Size;
+  UInt32 UID;
+  UInt32 GID;
+
+  AString Path;
+  AString Link;
+  AString User;
+  AString Group;
+  AString UnknownLines;
+  
+  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;
+  
+  // 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
+        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.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.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.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
new file mode 100644
index 0000000..8c69057
--- /dev/null
+++ b/CPP/7zip/Archive/Tar/TarIn.h
@@ -0,0 +1,149 @@
+// 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 _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;
+    // _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
new file mode 100644
index 0000000..2e12c9d
--- /dev/null
+++ b/CPP/7zip/Archive/Tar/TarItem.h
@@ -0,0 +1,360 @@
+// 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<CSparseBlock> 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;
+    }
+    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;
+    }
+
+    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);
+    }
+    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;
+
+  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
new file mode 100644
index 0000000..26d0855
--- /dev/null
+++ b/CPP/7zip/Archive/Tar/TarOut.cpp
@@ -0,0 +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 += '=';
+  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
new file mode 100644
index 0000000..7b99c26
--- /dev/null
+++ b/CPP/7zip/Archive/Tar/TarOut.h
@@ -0,0 +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<ISequentialOutStream> 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
new file mode 100644
index 0000000..709c191
--- /dev/null
+++ b/CPP/7zip/Archive/Tar/TarRegister.cpp
@@ -0,0 +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)
+ 
+}}
diff --git a/CPP/7zip/Archive/Tar/TarUpdate.cpp b/CPP/7zip/Archive/Tar/TarUpdate.cpp
new file mode 100644
index 0000000..0b348e9
--- /dev/null
+++ b/CPP/7zip/Archive/Tar/TarUpdate.cpp
@@ -0,0 +1,555 @@
+// TarUpdate.cpp
+
+#include "StdAfx.h"
+
+// #include <stdio.h>
+
+#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<NArchive::NTar::CItemEx> &inputItems,
+    const CObjectVector<CUpdateItem> &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)
+      complexity += ui.Size;
+    else
+      complexity += inputItems[(unsigned)ui.IndexInArc].Get_FullSize_Aligned();
+  }
+
+  RINOK(updateCallback->SetTotal(complexity))
+
+  NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder;
+  CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> progress = lps;
+  lps->Init(updateCallback, true);
+
+  CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+  CMyComPtr<ISequentialInStream> inStreamLimited(streamSpec);
+  streamSpec->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 (ui.Size == (UInt64)(Int64)-1)
+        return E_INVALIDARG;
+
+      CMyComPtr<ISequentialInStream> 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;
+                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)
+      {
+        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++)
+          {
+            /* 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->Code(fileInStream, outStream, NULL, NULL, progress))
+            outArchive.Pos += copyCoderSpec->TotalSize;
+            RINOK(outArchive.Write_AfterDataResidual(copyCoderSpec->TotalSize))
+            
+            // if (numPasses >= 10) // for debug
+            if (copyCoderSpec->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 = copyCoderSpec->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))
+        streamSpec->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->Code(inStreamLimited, outStream, NULL, NULL, progress))
+        if (copyCoderSpec->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
new file mode 100644
index 0000000..f6c2e77
--- /dev/null
+++ b/CPP/7zip/Archive/Tar/TarUpdate.h
@@ -0,0 +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<CItemEx> &inputItems,
+    const CObjectVector<CUpdateItem> &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
new file mode 100644
index 0000000..035267c
--- /dev/null
+++ b/CPP/7zip/Archive/Udf/StdAfx.h
@@ -0,0 +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
diff --git a/CPP/7zip/Archive/Udf/UdfHandler.cpp b/CPP/7zip/Archive/Udf/UdfHandler.cpp
new file mode 100644
index 0000000..ae6113f
--- /dev/null
+++ b/CPP/7zip/Archive/Udf/UdfHandler.cpp
@@ -0,0 +1,428 @@
+// 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<IArchiveOpenCallback> _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<ISequentialInStream> 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++)
+  {
+    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;
+  }
+  extractCallback->SetTotal(totalSize);
+
+  UInt64 currentTotalSize = 0;
+  
+  NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+  CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> progress = lps;
+  lps->Init(extractCallback, false);
+
+  CLimitedSequentialOutStream *outStreamSpec = new CLimitedSequentialOutStream;
+  CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+
+  for (i = 0; i < numItems; i++)
+  {
+    lps->InSize = lps->OutSize = currentTotalSize;
+    RINOK(lps->SetCur())
+    CMyComPtr<ISequentialOutStream> 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))
+    outStreamSpec->SetStream(realOutStream);
+    realOutStream.Release();
+    outStreamSpec->Init(item.Size);
+    Int32 opRes;
+    CMyComPtr<ISequentialInStream> udfInStream;
+    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->Code(udfInStream, outStream, NULL, NULL, progress))
+      opRes = outStreamSpec->IsFinishedOK() ?
+        NExtract::NOperationResult::kOK:
+        NExtract::NOperationResult::kDataError;
+    }
+    outStreamSpec->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
new file mode 100644
index 0000000..5426d06
--- /dev/null
+++ b/CPP/7zip/Archive/Udf/UdfHandler.h
@@ -0,0 +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<CRef2> _refs2;
+  CMyComPtr<IInStream> _inStream;
+  CInArchive _archive;
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/Udf/UdfIn.cpp b/CPP/7zip/Archive/Udf/UdfIn.cpp
new file mode 100644
index 0000000..13d84e0
--- /dev/null
+++ b/CPP/7zip/Archive/Udf/UdfIn.cpp
@@ -0,0 +1,1741 @@
+// Archive/UdfIn.cpp
+
+#include "StdAfx.h"
+
+// #define SHOW_DEBUG_INFO
+
+#ifdef SHOW_DEBUG_INFO
+#include <stdio.h>
+#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 += '-';
+    newName += newName2;
+    UpdateWithName(name, newName);
+  }
+  return name;
+}
+
+}}
diff --git a/CPP/7zip/Archive/Udf/UdfIn.h b/CPP/7zip/Archive/Udf/UdfIn.h
new file mode 100644
index 0000000..9ccbf74
--- /dev/null
+++ b/CPP/7zip/Archive/Udf/UdfIn.h
@@ -0,0 +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<CMyExtent> 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<CRef> 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<CPartitionMap> PartitionMaps;
+  CObjectVector<CFileSet> 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<CLogVol> LogVols;
+  CObjectVector<CItem> Items;
+  CObjectVector<CFile> Files;
+  CObjectVector<CPartition> Partitions;
+
+  unsigned SecLogSize;
+  UInt64 PhySize;
+  UInt64 FileSize;
+
+  bool IsArc;
+  bool Unsupported;
+  bool UnexpectedEnd;
+  bool NoEndAnchor;
+
+  CObjectVector<CPrimeVol> 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
new file mode 100644
index 0000000..cd6fcbd
--- /dev/null
+++ b/CPP/7zip/Archive/UefiHandler.cpp
@@ -0,0 +1,1893 @@
+// UefiHandler.cpp
+
+#include "StdAfx.h"
+
+// #define SHOW_DEBUG_INFO
+
+#ifdef SHOW_DEBUG_INFO
+#include <stdio.h>
+#endif
+
+#include "../../../C/7zCrc.h"
+#include "../../../C/Alloc.h"
+#include "../../../C/CpuArch.h"
+#include "../../../C/LzmaDec.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<CItem> _items;
+  CObjectVector<CItem2> _items2;
+  CObjectVector<CByteBuffer> _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;
+      UInt32 uncompressedSize = Get32(p + 4);
+      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)
+        {
+          unsigned newBufIndex = AddBuf(uncompressedSize);
+          CByteBuffer &buf = _bufs[newBufIndex];
+
+          NCompress::NLzh::NDecoder::CCoder *lzhDecoderSpec = NULL;
+          CMyComPtr<ICompressCoder> lzhDecoder;
+ 
+          lzhDecoderSpec = new NCompress::NLzh::NDecoder::CCoder;
+          lzhDecoder = lzhDecoderSpec;
+
+          {
+            const Byte *src = pStart;
+            if (newSectSize < 8)
+              return S_FALSE;
+            UInt32 packSize = Get32(src);
+            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;
+
+            CBufInStream *inStreamSpec = new CBufInStream;
+            CMyComPtr<IInStream> inStream = inStreamSpec;
+
+            CBufPtrSeqOutStream *outStreamSpec = new CBufPtrSeqOutStream;
+            CMyComPtr<ISequentialOutStream> outStream = outStreamSpec;
+
+            UInt64 uncompressedSize64 = uncompressedSize;
+            lzhDecoderSpec->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++)
+            {
+              inStreamSpec->Init(src, packSize);
+              outStreamSpec->Init(buf, uncompressedSize);
+              lzhDecoderSpec->SetDictSize((m == 0) ? ((UInt32)1 << 19) : ((UInt32)1 << 14));
+              res = lzhDecoder->Code(inStream, outStream, NULL, &uncompressedSize64, 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<UInt32> 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
+      )
+    return S_FALSE;
+  _phySize = _h.CapsuleImageSize;
+
+  if (_h.SequenceNumber != 0 ||
+      _h.OffsetToSplitInformation != 0 )
+    return E_NOTIMPL;
+
+  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;
+  extractCallback->SetTotal(totalSize);
+
+  UInt64 currentTotalSize = 0;
+  
+  NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+  CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> progress = lps;
+  lps->Init(extractCallback, false);
+
+  for (i = 0; i < numItems; i++)
+  {
+    lps->InSize = lps->OutSize = currentTotalSize;
+    RINOK(lps->SetCur())
+    CMyComPtr<ISequentialOutStream> 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))
+    currentTotalSize += item.Size;
+    
+    if (!testMode && !realOutStream)
+      continue;
+    RINOK(extractCallback->PrepareOperation(askMode))
+    if (testMode || item.IsDir)
+    {
+      RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
+      continue;
+    }
+    int res = NExtract::NOperationResult::kDataError;
+    CMyComPtr<ISequentialInStream> inStream;
+    GetStream(index, &inStream);
+    if (inStream)
+    {
+      RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress))
+      if (copyCoderSpec->TotalSize == item.Size)
+        res = NExtract::NOperationResult::kOK;
+    }
+    realOutStream.Release();
+    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[_items2[index].MainIndex];
+  if (item.IsDir)
+    return S_FALSE;
+  CBufInStream *streamSpec = new CBufInStream;
+  CMyComPtr<IInStream> 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
new file mode 100644
index 0000000..a5a9332
--- /dev/null
+++ b/CPP/7zip/Archive/VdiHandler.cpp
@@ -0,0 +1,438 @@
+// VdiHandler.cpp
+
+#include "StdAfx.h"
+
+// #include <stdio.h>
+
+#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<ISequentialInStream> 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
new file mode 100644
index 0000000..e5bf997
--- /dev/null
+++ b/CPP/7zip/Archive/VhdHandler.cpp
@@ -0,0 +1,977 @@
+// VhdHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "../../Common/ComTry.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<UInt32> Bat;
+  CByteBuffer BitMap;
+  UInt32 BitMapTag;
+  UInt32 NumUsedBlocks;
+  CMyComPtr<IInStream> 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 += '(';
+        res += anotherName;
+        res += ')';
+      }
+      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;
+}
+
+static void ConvertByteToHex(unsigned value, char *s)
+{
+  for (int i = 0; i < 2; i++)
+  {
+    unsigned t = value & 0xF;
+    value >>= 4;
+    s[1 - i] = (char)((t < 10) ? ('0' + t) : ('A' + (t - 10)));
+  }
+}
+
+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[32 + 4];
+      for (int i = 0; i < 16; i++)
+        ConvertByteToHex(Footer.Id[i], s + i * 2);
+      s[32] = 0;
+      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<IInStream> 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())
+  {
+    CLimitedInStream *streamSpec = new CLimitedInStream;
+    CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
+    streamSpec->SetStream(Stream);
+    // fixme : check (startOffset = 0)
+    streamSpec->InitAndSeek(_startOffset, Footer.CurrentSize);
+    RINOK(streamSpec->SeekToStart())
+    *stream = streamTemp.Detach();
+    return S_OK;
+  }
+  if (!Footer.ThereIsDynamic() || !AreParentsOK())
+    return S_FALSE;
+  CMyComPtr<ISequentialInStream> 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
new file mode 100644
index 0000000..e3ddedd
--- /dev/null
+++ b/CPP/7zip/Archive/VhdxHandler.cpp
@@ -0,0 +1,2097 @@
+// VhdxHandler.cpp
+
+#include "StdAfx.h"
+
+// #include <stdio.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 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
+
+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;
+}
+
+
+#define ValToHex(t) ((char)(((t) < 10) ? ('0' + (t)) : ('a' + ((t) - 10))))
+
+static void AddByteToHex2(unsigned val, UString &s)
+{
+  unsigned t;
+  t = val >> 4;
+  s += ValToHex(t);
+  t = val & 0xF;
+  s += ValToHex(t);
+}
+
+
+static int HexToVal(const wchar_t c)
+{
+  if (c >= '0' && c <= '9')  return c - '0';
+  if (c >= 'a' && c <= 'z')  return c - 'a' + 10;
+  if (c >= 'A' && c <= 'Z')  return c - 'A' + 10;
+  return -1;
+}
+
+static int DecodeFrom2HexChars(const wchar_t *s)
+{
+  const int v0 = HexToVal(s[0]);  if (v0 < 0)  return -1;
+  const int v1 = HexToVal(s[1]);  if (v1 < 0)  return -1;
+  return (int)(((unsigned)v0 << 4) | (unsigned)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
+{
+  for (unsigned i = 0; i < 16; i++)
+    AddByteToHex2(Data[i], s);
+}
+
+
+#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 unsigned 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<CParentPair> 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<CByteBuffer> 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<IInStream> 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 &region = 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 += 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<IInStream> 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<ISequentialInStream> 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
new file mode 100644
index 0000000..0a6b967
--- /dev/null
+++ b/CPP/7zip/Archive/VmdkHandler.cpp
@@ -0,0 +1,1527 @@
+// VmdkHandler.cpp
+
+#include "StdAfx.h"
+
+// #include <stdio.h>
+
+#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<CExtentInfo> 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<CByteBuffer> Tables;
+
+  CMyComPtr<IInStream> 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<CExtent> _extents;
+
+  CBufInStream *_bufInStreamSpec;
+  CMyComPtr<ISequentialInStream> _bufInStream;
+
+  CBufPtrSeqOutStream *_bufOutStreamSpec;
+  CMyComPtr<ISequentialOutStream> _bufOutStream;
+
+  NCompress::NZlib::CDecoder *_zlibDecoderSpec;
+  CMyComPtr<ICompressCoder> _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;
+      int 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 != (int)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<IArchiveOpenVolumeCallback> 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<IInStream> 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<ISequentialInStream> 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
new file mode 100644
index 0000000..035267c
--- /dev/null
+++ b/CPP/7zip/Archive/Wim/StdAfx.h
@@ -0,0 +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
diff --git a/CPP/7zip/Archive/Wim/WimHandler.cpp b/CPP/7zip/Archive/Wim/WimHandler.cpp
new file mode 100644
index 0000000..7f96dcc
--- /dev/null
+++ b/CPP/7zip/Archive/Wim/WimHandler.cpp
@@ -0,0 +1,1236 @@
+// 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 += ':';
+        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<IArchiveOpenVolumeCallback> openVolumeCallback;
+    
+    CVolumeName seqName;
+    if (callback)
+      callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback);
+
+    UInt32 numVolumes = 1;
+    
+    for (UInt32 i = 1; i <= numVolumes; i++)
+    {
+      CMyComPtr<IInStream> 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))
+
+  UInt64 currentTotalUnPacked = 0;
+  UInt64 currentItemUnPacked;
+  
+  int prevSuccessStreamIndex = -1;
+
+  CUnpacker unpacker;
+
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> progress = lps;
+  lps->Init(extractCallback, false);
+
+  for (i = 0;; i++,
+      currentTotalUnPacked += currentItemUnPacked)
+  {
+    currentItemUnPacked = 0;
+
+    lps->InSize = unpacker.TotalPacked;
+    lps->OutSize = currentTotalUnPacked;
+
+    RINOK(lps->SetCur())
+
+    if (i >= numItems)
+      break;
+
+    UInt32 index = allFilesMode ? i : indices[i];
+    const Int32 askMode = testMode ?
+        NExtract::NAskMode::kTest :
+        NExtract::NAskMode::kExtract;
+
+    CMyComPtr<ISequentialOutStream> 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]];
+    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];
+      bool needDigest = !si.IsEmptyHash();
+      
+      HRESULT res = unpacker.Unpack(vol.Stream, si.Resource, vol.Header, &_db,
+          realOutStream, progress, 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
+    {
+      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
new file mode 100644
index 0000000..60bb156
--- /dev/null
+++ b/CPP/7zip/Archive/Wim/WimHandler.h
@@ -0,0 +1,93 @@
+// 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 {
+
+static const Int32 kNumImagesMaxUpdate = (1 << 10);
+
+Z7_CLASS_IMP_CHandler_IInArchive_5(
+    IArchiveGetRawProps
+  , IArchiveGetRootProps
+  , IArchiveKeepModeForNextOpen
+  , ISetProperties
+  , IOutArchive
+)
+  CDatabase _db;
+  UInt32 _version;
+  bool _isOldVersion;
+  UInt32 _bootIndex;
+
+  CObjectVector<CVolume> _volumes;
+  CObjectVector<CWimXml> _xmls;
+  // unsigned _nameLenForStreams;
+  bool _xmlInComments;
+  
+  unsigned _numXmlItems;
+  unsigned _numIgnoreItems;
+
+  bool _xmlError;
+  bool _isArc;
+  bool _unsupported;
+
+  bool _set_use_ShowImageNumber;
+  bool _set_showImageNumber;
+  int _defaultImageNumber;
+
+  bool _showImageNumber;
+
+  bool _keepMode_ShowImageNumber;
+
+  UInt64 _phySize;
+  int _firstVolumeIndex;
+
+  CHandlerTimeOptions _timeOptions;
+
+  void InitDefaults()
+  {
+    _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
new file mode 100644
index 0000000..5d9dea2
--- /dev/null
+++ b/CPP/7zip/Archive/Wim/WimHandlerOut.cpp
@@ -0,0 +1,2008 @@
+// 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 "WimHandler.h"
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NWim {
+
+static const unsigned k_NumSubVectors_Bits = 12; // must be <= 16
+
+struct CSortedIndex
+{
+  CObjectVector<CUIntVector> 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<CAltStream> 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<CMetaItem> &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<CDir> Dirs;
+  CUIntVector Files; // indexes in MetaItems[]
+
+  CDir(): MetaIndex(-1) {}
+  unsigned GetNumDirs() const;
+  unsigned GetNumFiles() const;
+  UInt64 GetTotalSize(const CObjectVector<CMetaItem> &metaItems) const;
+  bool FindDir(const CObjectVector<CMetaItem> &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<CMetaItem> &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<CMetaItem> &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);
+}
+
+
+Z7_CLASS_IMP_NOQIB_1(
+  CInStreamWithSha1
+  , ISequentialInStream
+)
+  CMyComPtr<ISequentialInStream> _stream;
+  UInt64 _size;
+  // NCrypto::NSha1::CContext _sha;
+  CAlignedBuffer1 _sha;
+  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); }
+};
+
+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;
+}
+
+
+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<CMetaItem> MetaItems;
+  CRecordVector<CUpdateItem> 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 += '<';
+  s += name;
+  s += '>';
+  s += value;
+  s += '<';
+  s += '/';
+  s += name;
+  s += '>';
+}
+
+
+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)
+{
+  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)
+{
+  int index = parentItem.FindSubTag(name);
+  if (index >= 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<CDir> &trees, CObjectVector<CMetaItem> &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<IOutStream> outStream;
+  RINOK(outSeqStream->QueryInterface(IID_IOutStream, (void **)&outStream))
+  if (!outStream)
+    return E_NOTIMPL;
+  if (!callback)
+    return E_FAIL;
+
+  CDb db;
+  CObjectVector<CDir> 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<IArchiveGetRawProps> getRawProps;
+  callback->QueryInterface(IID_IArchiveGetRawProps, (void **)&getRawProps);
+
+  CMyComPtr<IArchiveGetRootProps> getRootProps;
+  callback->QueryInterface(IID_IArchiveGetRootProps, (void **)&getRootProps);
+
+  CObjectVector<CUniqBlocks> 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 (;;)
+      {
+        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;
+
+  NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder;
+  CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> progress = lps;
+  lps->Init(callback, true);
+
+  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<IStreamSetRestriction> 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;
+
+  CInStreamWithSha1 *inShaStreamSpec = new CInStreamWithSha1;
+  CMyComPtr<ISequentialInStream> inShaStream = inShaStreamSpec;
+
+  CLimitedSequentialInStream *inStreamLimitedSpec = NULL;
+  CMyComPtr<ISequentialInStream> inStreamLimited;
+  if (_volumes.Size() == 2)
+  {
+    inStreamLimitedSpec = new CLimitedSequentialInStream;
+    inStreamLimited = inStreamLimitedSpec;
+    inStreamLimitedSpec->SetStream(_volumes[1].Stream);
+  }
+
+  
+  CRecordVector<CStreamInfo> 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.Front(), 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->Code(inStreamLimited, outStream, NULL, NULL, progress))
+      if (copyCoderSpec->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.Front(), 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<ISequentialInStream> 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<IStreamGetProps2> 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.Front(), 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
+      {
+        inShaStreamSpec->SetStream(fileInStream);
+
+        CMyComPtr<IInStream> inSeekStream;
+        fileInStream.QueryInterface(IID_IInStream, (void **)&inSeekStream);
+        
+        fileInStream.Release();
+        inShaStreamSpec->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->Code(inShaStream, NULL, NULL, NULL, progress))
+          size = copyCoderSpec->TotalSize;
+          if (size == 0)
+            needWritePass = false;
+          else
+          {
+            Byte hash[kHashSize];
+            inShaStreamSpec->Final(hash);
+
+            index = AddUniqHash(&streams.Front(), sortedHashes, hash, -1);
+            if (index != -1)
+            {
+              streams[index].RefCount++;
+              needWritePass = false;
+            }
+            else
+            {
+              RINOK(InStream_SeekToBegin(inSeekStream))
+              inShaStreamSpec->Init();
+            }
+          }
+        }
+        
+        if (needWritePass)
+        {
+          RINOK(copyCoder->Code(inShaStream, outStream, NULL, NULL, progress))
+          size = copyCoderSpec->TotalSize;
+        }
+       
+        if (size != 0)
+        {
+          if (needWritePass)
+          {
+            Byte hash[kHashSize];
+            const UInt64 packSize = offsetBlockSize + size;
+            inShaStreamSpec->Final(hash);
+            
+            index = AddUniqHash(&streams.Front(), 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->Code(inStreamLimited, outStream, NULL, NULL, progress))
+      if (copyCoderSpec->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<CByteBuffer> &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.Front();
+    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 ("<WIM>");
+  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 += "</WIM>";
+
+  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
new file mode 100644
index 0000000..ff118d8
--- /dev/null
+++ b/CPP/7zip/Archive/Wim/WimIn.cpp
@@ -0,0 +1,1878 @@
+// Archive/WimIn.cpp
+
+#include "StdAfx.h"
+
+// #define SHOW_DEBUG_INFO
+
+#ifdef SHOW_DEBUG_INFO
+#include <stdio.h>
+#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 int inline GetLog(UInt32 num)
+{
+  for (int i = 0; i < 32; i++)
+    if (((UInt32)1 << i) == num)
+      return i;
+  return -1;
+}
+
+
+CUnpacker::~CUnpacker()
+{
+  if (lzmsDecoder)
+    delete lzmsDecoder;
+}
+
+
+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)
+  {
+    if (!lzxDecoder)
+    {
+      lzxDecoderSpec = new NCompress::NLzx::CDecoder(true);
+      lzxDecoder = lzxDecoderSpec;
+    }
+  }
+  else if (method == NMethod::kLZMS)
+  {
+    if (!lzmsDecoder)
+      lzmsDecoder = new NCompress::NLzms::CDecoder();
+  }
+  else
+    return E_NOTIMPL;
+
+  const size_t chunkSize = (size_t)1 << chunkSizeBits;
+  
+  unpackBuf.EnsureCapacity(chunkSize);
+  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)
+  {
+    packBuf.EnsureCapacity(chunkSize);
+    if (!packBuf.Data)
+      return E_OUTOFMEMORY;
+    
+    RINOK(ReadStream_FALSE(inStream, packBuf.Data, inSize))
+
+    TotalPacked += inSize;
+    
+    if (method == NMethod::kXPRESS)
+    {
+      res = NCompress::NXpress::Decode(packBuf.Data, inSize, unpackBuf.Data, outSize);
+      if (res == S_OK)
+        unpackedSize = outSize;
+    }
+    else if (method == NMethod::kLZX)
+    {
+      res = lzxDecoderSpec->SetExternalWindow(unpackBuf.Data, chunkSizeBits);
+      if (res != S_OK)
+        return E_NOTIMPL;
+      lzxDecoderSpec->KeepHistoryForNext = false;
+      lzxDecoderSpec->SetKeepHistory(false);
+      res = lzxDecoderSpec->Code(packBuf.Data, inSize, (UInt32)outSize);
+      unpackedSize = lzxDecoderSpec->GetUnpackSize();
+      if (res == S_OK && !lzxDecoderSpec->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())
+  {
+    if (!copyCoder)
+    {
+      copyCoderSpec = new NCompress::CCopyCoder;
+      copyCoder = copyCoderSpec;
+    }
+
+    CLimitedSequentialInStream *limitedStreamSpec = new CLimitedSequentialInStream();
+    CMyComPtr<ISequentialInStream> limitedStream = limitedStreamSpec;
+    limitedStreamSpec->SetStream(inStream);
+    
+    RINOK(InStream_SeekSet(inStream, resource.Offset))
+    if (resource.PackSize != resource.UnpackSize)
+      return S_FALSE;
+
+    limitedStreamSpec->Init(resource.PackSize);
+    TotalPacked += resource.PackSize;
+    
+    HRESULT res = copyCoder->Code(limitedStream, outStream, NULL, NULL, progress);
+    
+    if (res == S_OK && copyCoderSpec->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)
+{
+  COutStreamWithSha1 *shaStreamSpec = NULL;
+  CMyComPtr<ISequentialOutStream> shaStream;
+  
+  // outStream can be NULL, so we use COutStreamWithSha1 even if sha1 is not required
+  // if (digest)
+  {
+    shaStreamSpec = new COutStreamWithSha1();
+    shaStream = shaStreamSpec;
+    shaStreamSpec->SetStream(outStream);
+    shaStreamSpec->Init(digest != NULL);
+    outStream = shaStream;
+  }
+  
+  HRESULT res = Unpack2(inStream, resource, header, db, outStream, progress);
+  
+  if (digest)
+    shaStreamSpec->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);
+
+  size_t size = (size_t)unpackSize64;
+  if (size != unpackSize64)
+    return E_OUTOFMEMORY;
+
+  buf.Alloc(size);
+
+  CBufPtrSeqOutStream *outStreamSpec = new CBufPtrSeqOutStream();
+  CMyComPtr<ISequentialOutStream> outStream = outStreamSpec;
+  outStreamSpec->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)
+    {
+      const int log = GetLog(ChunkSize);
+      if (log < 12)
+        return S_FALSE;
+      ChunkSizeBits = (unsigned)log;
+    }
+  }
+
+  _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<CItem> &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<CVolume> &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);
+          const int log = GetLog(solidChunkSize);
+          if (log < 8 || log > 31)
+            return S_FALSE;
+          ss.ChunkSizeBits = (unsigned)log;
+          ss.Method = (Int32)GetUi32(header + 12);
+          
+          UInt64 numChunks64 = (ss.UnpackSize + (((UInt32)1 << ss.ChunkSizeBits) - 1)) >> ss.ChunkSizeBits;
+          UInt64 sizesBufSize64 = 4 * numChunks64;
+          ss.HeadersSize = kSolidHeaderSize + sizesBufSize64;
+          size_t sizesBufSize = (size_t)sizesBufSize64;
+          if (sizesBufSize != sizesBufSize64)
+            return E_OUTOFMEMORY;
+          sizesBuf.AllocAtLeast(sizesBufSize);
+          
+          RINOK(ReadStream_FALSE(inStream, sizesBuf, sizesBufSize))
+          
+          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.Front();
+
+      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.Front(), 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.Front(), 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++)
+    {
+      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<CVolume> &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)
+{
+  int index = item.FindSubTag(tag);
+  if (index >= 0)
+  {
+    const CXmlItem &timeItem = item.SubItems[index];
+    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
new file mode 100644
index 0000000..3de8456
--- /dev/null
+++ b/CPP/7zip/Archive/Wim/WimIn.h
@@ -0,0 +1,659 @@
+// Archive/WimIn.h
+
+#ifndef ZIP7_INC_ARCHIVE_WIM_IN_H
+#define ZIP7_INC_ARCHIVE_WIM_IN_H
+
+#include "../../../../C/Alloc.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<UInt64> 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<UInt32> 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<CImageInfo> 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<IInStream> 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<CStreamInfo> DataStreams;
+  CRecordVector<CStreamInfo> MetaStreams;
+
+  CObjectVector<CSolid> Solids;
+  
+  CRecordVector<CItem> Items;
+  CObjectVector<CByteBuffer> ReparseItems;
+  CIntVector ItemToReparse; // from index_in_Items to index_in_ReparseItems
+                            // -1 means no reparse;
+  
+  CObjectVector<CImage> 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<CVolume> &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<CVolume> &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)
+    {
+      ::MidFree(Data);
+      _size = 0;
+      Data = (Byte *)::MidAlloc(size);
+      if (Data)
+        _size = size;
+    }
+  }
+
+  ~CMidBuf() { ::MidFree(Data); }
+};
+
+
+class CUnpacker
+{
+  NCompress::CCopyCoder *copyCoderSpec;
+  CMyComPtr<ICompressCoder> copyCoder;
+
+  NCompress::NLzx::CDecoder *lzxDecoderSpec;
+  CMyComPtr<IUnknown> lzxDecoder;
+
+  NCompress::NLzms::CDecoder *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)
+      {}
+  ~CUnpacker();
+
+  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
new file mode 100644
index 0000000..e143f91
--- /dev/null
+++ b/CPP/7zip/Archive/Wim/WimRegister.cpp
@@ -0,0 +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)
+
+}}
diff --git a/CPP/7zip/Archive/XarHandler.cpp b/CPP/7zip/Archive/XarHandler.cpp
new file mode 100644
index 0000000..c03128f
--- /dev/null
+++ b/CPP/7zip/Archive/XarHandler.cpp
@@ -0,0 +1,730 @@
+// XarHandler.cpp
+
+#include "StdAfx.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 {
+
+static const size_t kXmlSizeMax = ((size_t )1 << 30) - (1 << 14);
+static const size_t kXmlPackSizeMax = kXmlSizeMax;
+
+/*
+#define XAR_CKSUM_NONE  0
+#define XAR_CKSUM_SHA1  1
+#define XAR_CKSUM_MD5   2
+
+static const char * const k_ChecksumAlgos[] =
+{
+    "None"
+  , "SHA-1"
+  , "MD5"
+};
+*/
+
+#define METHOD_NAME_ZLIB "zlib"
+
+
+struct CFile
+{
+  AString Name;
+  AString Method;
+  UInt64 Size;
+  UInt64 PackSize;
+  UInt64 Offset;
+  
+  UInt64 CTime;
+  UInt64 MTime;
+  UInt64 ATime;
+  UInt32 Mode;
+
+  AString User;
+  AString Group;
+  
+  bool IsDir;
+  bool HasData;
+  bool ModeDefined;
+  bool Sha1IsDefined;
+  // bool packSha1IsDefined;
+
+  Byte Sha1[SHA1_DIGEST_SIZE];
+  // Byte packSha1[SHA1_DIGEST_SIZE];
+
+  int Parent;
+
+  CFile():
+      Size(0), PackSize(0), Offset(0),
+      CTime(0), MTime(0), ATime(0), Mode(0),
+      IsDir(false), HasData(false), ModeDefined(false), Sha1IsDefined(false),
+      /* packSha1IsDefined(false), */
+      Parent(-1)
+      {}
+
+  bool IsCopyMethod() const
+  {
+    return Method.IsEmpty() || Method == "octet-stream";
+  }
+
+  void UpdateTotalPackSize(UInt64 &totalSize) const
+  {
+    UInt64 t = Offset + PackSize;
+    if (totalSize < t)
+      totalSize = t;
+  }
+};
+
+
+Z7_CLASS_IMP_CHandler_IInArchive_1(
+    IInArchiveGetStream
+)
+  UInt64 _dataStartPos;
+  CMyComPtr<IInStream> _inStream;
+  CByteArr _xml;
+  size_t _xmlLen;
+  CObjectVector<CFile> _files;
+  // UInt32 _checkSumAlgo;
+  UInt64 _phySize;
+  Int32 _mainSubfile;
+  bool _is_pkg;
+
+  HRESULT Open2(IInStream *stream);
+  HRESULT Extract(IInStream *stream);
+};
+
+static const Byte kArcProps[] =
+{
+  kpidSubType,
+  kpidHeadersSize
+};
+
+static const Byte kProps[] =
+{
+  kpidPath,
+  kpidSize,
+  kpidPackSize,
+  kpidMTime,
+  kpidCTime,
+  kpidATime,
+  kpidPosixAttrib,
+  kpidUser,
+  kpidGroup,
+  kpidMethod
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+#define PARSE_NUM(_num_, _dest_) \
+    { const char *end; _dest_ = ConvertStringToUInt32(p, &end); \
+    if ((unsigned)(end - p) != _num_) return 0; \
+    p += _num_ + 1; }
+
+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;
+}
+
+static UInt64 ParseTime(const CXmlItem &item, const char *name)
+{
+  const AString s (item.GetSubStringForTag(name));
+  if (s.Len() < 20)
+    return 0;
+  const char *p = s;
+  if (p[ 4] != '-' || p[ 7] != '-' || p[10] != 'T' ||
+      p[13] != ':' || p[16] != ':' || 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 int HexToByte(char c)
+{
+  if (c >= '0' && c <= '9') return c - '0';
+  if (c >= 'A' && c <= 'F') return c - 'A' + 10;
+  if (c >= 'a' && c <= 'f') return c - 'a' + 10;
+  return -1;
+}
+
+static bool ParseSha1(const CXmlItem &item, const char *name, Byte *digest)
+{
+  const int index = item.FindSubTag(name);
+  if (index < 0)
+    return false;
+  const CXmlItem &checkItem = item.SubItems[index];
+  const AString style (checkItem.GetPropVal("style"));
+  if (style == "SHA1")
+  {
+    const AString s (checkItem.GetSubString());
+    if (s.Len() != SHA1_DIGEST_SIZE * 2)
+      return false;
+    for (unsigned i = 0; i < s.Len(); i += 2)
+    {
+      const int b0 = HexToByte(s[i]);
+      const int b1 = HexToByte(s[i + 1]);
+      if (b0 < 0 || b1 < 0)
+        return false;
+      digest[i / 2] = (Byte)((b0 << 4) | b1);
+    }
+    return true;
+  }
+  return false;
+}
+
+static bool AddItem(const CXmlItem &item, CObjectVector<CFile> &files, int parent)
+{
+  if (!item.IsTag)
+    return true;
+  if (item.Name == "file")
+  {
+    CFile file;
+    file.Parent = parent;
+    parent = (int)files.Size();
+    file.Name = item.GetSubStringForTag("name");
+    const AString type (item.GetSubStringForTag("type"));
+    if (type == "directory")
+      file.IsDir = true;
+    else if (type == "file")
+      file.IsDir = false;
+    else
+      return false;
+
+    int dataIndex = item.FindSubTag("data");
+    if (dataIndex >= 0 && !file.IsDir)
+    {
+      file.HasData = true;
+      const CXmlItem &dataItem = item.SubItems[dataIndex];
+      if (!ParseUInt64(dataItem, "size", file.Size))
+        return false;
+      if (!ParseUInt64(dataItem, "length", file.PackSize))
+        return false;
+      if (!ParseUInt64(dataItem, "offset", file.Offset))
+        return false;
+      file.Sha1IsDefined = ParseSha1(dataItem, "extracted-checksum", file.Sha1);
+      // file.packSha1IsDefined = ParseSha1(dataItem, "archived-checksum",  file.packSha1);
+      int encodingIndex = dataItem.FindSubTag("encoding");
+      if (encodingIndex >= 0)
+      {
+        const CXmlItem &encodingItem = dataItem.SubItems[encodingIndex];
+        if (encodingItem.IsTag)
+        {
+          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.CTime = ParseTime(item, "ctime");
+    file.MTime = ParseTime(item, "mtime");
+    file.ATime = ParseTime(item, "atime");
+
+    {
+      const AString s (item.GetSubStringForTag("mode"));
+      if (s[0] == '0')
+      {
+        const char *end;
+        file.Mode = ConvertOctStringToUInt32(s, &end);
+        file.ModeDefined = (*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))
+      return false;
+  return true;
+}
+
+HRESULT CHandler::Open2(IInStream *stream)
+{
+  const UInt32 kHeaderSize = 0x1C;
+  Byte buf[kHeaderSize];
+  RINOK(ReadStream_FALSE(stream, buf, kHeaderSize))
+  UInt32 size = Get16(buf + 4);
+  // UInt32 ver = Get16(buf + 6); // == 1
+  if (Get32(buf) != 0x78617221 || size != kHeaderSize)
+    return S_FALSE;
+
+  UInt64 packSize = Get64(buf + 8);
+  UInt64 unpackSize = Get64(buf + 0x10);
+
+  // _checkSumAlgo = Get32(buf + 0x18);
+
+  if (packSize >= kXmlPackSizeMax ||
+      unpackSize >= kXmlSizeMax)
+    return S_FALSE;
+
+  _dataStartPos = kHeaderSize + packSize;
+  _phySize = _dataStartPos;
+
+  _xml.Alloc((size_t)unpackSize + 1);
+  _xmlLen = (size_t)unpackSize;
+  
+  NCompress::NZlib::CDecoder *zlibCoderSpec = new NCompress::NZlib::CDecoder();
+  CMyComPtr<ICompressCoder> zlibCoder = zlibCoderSpec;
+
+  CLimitedSequentialInStream *inStreamLimSpec = new CLimitedSequentialInStream;
+  CMyComPtr<ISequentialInStream> inStreamLim(inStreamLimSpec);
+  inStreamLimSpec->SetStream(stream);
+  inStreamLimSpec->Init(packSize);
+
+  CBufPtrSeqOutStream *outStreamLimSpec = new CBufPtrSeqOutStream;
+  CMyComPtr<ISequentialOutStream> outStreamLim(outStreamLimSpec);
+  outStreamLimSpec->Init(_xml, (size_t)unpackSize);
+
+  RINOK(zlibCoder->Code(inStreamLim, outStreamLim, NULL, NULL, NULL))
+
+  if (outStreamLimSpec->GetPos() != (size_t)unpackSize)
+    return S_FALSE;
+
+  _xml[(size_t)unpackSize] = 0;
+  if (strlen((const char *)(const Byte *)_xml) != unpackSize) return S_FALSE;
+
+  CXml xml;
+  if (!xml.Parse((const char *)(const Byte *)_xml))
+    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;
+  if (!AddItem(toc, _files, -1))
+    return S_FALSE;
+
+  UInt64 totalPackSize = 0;
+  unsigned numMainFiles = 0;
+  
+  FOR_VECTOR (i, _files)
+  {
+    const CFile &file = _files[i];
+    file.UpdateTotalPackSize(totalPackSize);
+    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;
+  
+  _phySize = _dataStartPos + totalPackSize;
+
+  return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::Open(IInStream *stream,
+    const UInt64 * /* maxCheckStartPosition */,
+    IArchiveOpenCallback * /* openArchiveCallback */))
+{
+  COM_TRY_BEGIN
+  {
+    Close();
+    if (Open2(stream) != S_OK)
+      return S_FALSE;
+    _inStream = stream;
+  }
+  return S_OK;
+  COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+  _phySize = 0;
+  _inStream.Release();
+  _files.Clear();
+  _xmlLen = 0;
+  _xml.Free();
+  _mainSubfile = -1;
+  _is_pkg = false;
+  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;
+  }
+  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;
+  
+  #ifdef XAR_SHOW_RAW
+  if (index == _files.Size())
+  {
+    switch (propID)
+    {
+      case kpidPath: prop = "[TOC].xml"; break;
+      case kpidSize:
+      case kpidPackSize: prop = (UInt64)_xmlLen; break;
+    }
+  }
+  else
+  #endif
+  {
+    const CFile &item = _files[index];
+    switch (propID)
+    {
+      case kpidMethod: Utf8StringToProp(item.Method, prop); break;
+
+      case kpidPath:
+      {
+        AString path;
+        unsigned cur = index;
+        for (;;)
+        {
+          const CFile &item2 = _files[cur];
+          if (!path.IsEmpty())
+            path.InsertAtFront(CHAR_PATH_SEPARATOR);
+          if (item2.Name.IsEmpty())
+            path.Insert(0, "unknown");
+          else
+            path.Insert(0, item2.Name);
+          cur = (unsigned)item2.Parent;
+          if (item2.Parent < 0)
+            break;
+        }
+
+        Utf8StringToProp(path, prop);
+        break;
+      }
+      
+      case kpidIsDir: prop = item.IsDir; break;
+      case kpidSize: if (!item.IsDir) prop = item.Size; break;
+      case kpidPackSize: if (!item.IsDir) prop = item.PackSize; 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.ModeDefined)
+        {
+          UInt32 mode = item.Mode;
+          if ((mode & MY_LIN_S_IFMT) == 0)
+            mode |= (item.IsDir ? MY_LIN_S_IFDIR : MY_LIN_S_IFREG);
+          prop = mode;
+        }
+        break;
+      case kpidUser: Utf8StringToProp(item.User, prop); break;
+      case kpidGroup: Utf8StringToProp(item.Group, prop); 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 = _files.Size();
+  if (numItems == 0)
+    return S_OK;
+  UInt64 totalSize = 0;
+  UInt32 i;
+  for (i = 0; i < numItems; i++)
+  {
+    UInt32 index = (allFilesMode ? i : indices[i]);
+    #ifdef XAR_SHOW_RAW
+    if (index == _files.Size())
+      totalSize += _xmlLen;
+    else
+    #endif
+      totalSize += _files[index].Size;
+  }
+  extractCallback->SetTotal(totalSize);
+
+  UInt64 currentPackTotal = 0;
+  UInt64 currentUnpTotal = 0;
+  UInt64 currentPackSize = 0;
+  UInt64 currentUnpSize = 0;
+
+  const UInt32 kZeroBufSize = (1 << 14);
+  CByteBuffer zeroBuf(kZeroBufSize);
+  memset(zeroBuf, 0, kZeroBufSize);
+  
+  NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+  CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+  NCompress::NZlib::CDecoder *zlibCoderSpec = new NCompress::NZlib::CDecoder();
+  CMyComPtr<ICompressCoder> zlibCoder = zlibCoderSpec;
+  
+  NCompress::NBZip2::CDecoder *bzip2CoderSpec = new NCompress::NBZip2::CDecoder();
+  CMyComPtr<ICompressCoder> bzip2Coder = bzip2CoderSpec;
+
+  NCompress::NDeflate::NDecoder::CCOMCoder *deflateCoderSpec = new NCompress::NDeflate::NDecoder::CCOMCoder();
+  CMyComPtr<ICompressCoder> deflateCoder = deflateCoderSpec;
+
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> progress = lps;
+  lps->Init(extractCallback, false);
+
+  CLimitedSequentialInStream *inStreamSpec = new CLimitedSequentialInStream;
+  CMyComPtr<ISequentialInStream> inStream(inStreamSpec);
+  inStreamSpec->SetStream(_inStream);
+
+  
+  CLimitedSequentialOutStream *outStreamLimSpec = new CLimitedSequentialOutStream;
+  CMyComPtr<ISequentialOutStream> outStream(outStreamLimSpec);
+
+  COutStreamWithSha1 *outStreamSha1Spec = new COutStreamWithSha1;
+  {
+    CMyComPtr<ISequentialOutStream> outStreamSha1(outStreamSha1Spec);
+    outStreamLimSpec->SetStream(outStreamSha1);
+  }
+
+  for (i = 0; i < numItems; i++, currentPackTotal += currentPackSize, currentUnpTotal += currentUnpSize)
+  {
+    lps->InSize = currentPackTotal;
+    lps->OutSize = currentUnpTotal;
+    currentPackSize = 0;
+    currentUnpSize = 0;
+    RINOK(lps->SetCur())
+    CMyComPtr<ISequentialOutStream> 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))
+        RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
+        continue;
+      }
+    }
+
+    if (!testMode && !realOutStream)
+      continue;
+    RINOK(extractCallback->PrepareOperation(askMode))
+
+    outStreamSha1Spec->SetStream(realOutStream);
+    realOutStream.Release();
+
+    Int32 opRes = NExtract::NOperationResult::kOK;
+    #ifdef XAR_SHOW_RAW
+    if (index == _files.Size())
+    {
+      outStreamSha1Spec->Init(false);
+      outStreamLimSpec->Init(_xmlLen);
+      RINOK(WriteStream(outStream, _xml, _xmlLen))
+      currentPackSize = currentUnpSize = _xmlLen;
+    }
+    else
+    #endif
+    {
+      const CFile &item = _files[index];
+      if (item.HasData)
+      {
+        currentPackSize = item.PackSize;
+        currentUnpSize = item.Size;
+        
+        RINOK(InStream_SeekSet(_inStream, _dataStartPos + item.Offset))
+        inStreamSpec->Init(item.PackSize);
+        outStreamSha1Spec->Init(item.Sha1IsDefined);
+        outStreamLimSpec->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(inStream, outStream, NULL, NULL, progress);
+        
+        if (res != S_OK)
+        {
+          if (!outStreamLimSpec->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 (outStreamLimSpec->IsFinishedOK() &&
+              outStreamSha1Spec->GetSize() == item.Size)
+          {
+            if (!outStreamLimSpec->IsFinishedOK())
+            {
+              opRes = NExtract::NOperationResult::kDataError;
+            }
+            else if (item.Sha1IsDefined)
+            {
+              Byte digest[SHA1_DIGEST_SIZE];
+              outStreamSha1Spec->Final(digest);
+              if (memcmp(digest, item.Sha1, SHA1_DIGEST_SIZE) != 0)
+                opRes = NExtract::NOperationResult::kCRCError;
+            }
+          }
+          else
+            opRes = NExtract::NOperationResult::kDataError;
+        }
+      }
+    }
+    outStreamSha1Spec->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(_xml, _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
+}
+
+static const Byte k_Signature[] = { 'x', 'a', 'r', '!', 0, 0x1C };
+
+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 743271a..976817c 100644
--- a/CPP/7zip/Archive/XzHandler.cpp
+++ b/CPP/7zip/Archive/XzHandler.cpp
@@ -1,1308 +1,1443 @@
-// 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;

-};

-

-

-class CHandler:

-  public IInArchive,

-  public IArchiveOpenSeq,

-  public IInArchiveGetStream,

-  public ISetProperties,

-

-  #ifndef EXTRACT_ONLY

-  public IOutArchive,

-  #endif

-

-  public CMyUnknownImp,

-

-  #ifndef EXTRACT_ONLY

-    public CMultiMethodProps

-  #else

-    public CCommonMethodProps

-  #endif

-{

-  CXzStatInfo _stat;

-  SRes MainDecodeSRes;

-  

-  bool _isArc;

-  bool _needSeekToStart;

-  bool _phySize_Defined;

-  bool _firstBlockWasRead;

-

-  AString _methodsString;

-

-  #ifndef EXTRACT_ONLY

-

-  UInt32 _filterId;

-

-  UInt64 _numSolidBytes;

-

-  void InitXz()

-  {

-    _filterId = 0;

-    _numSolidBytes = XZ_PROPS__BLOCK_SIZE__AUTO;

-  }

-

-  #endif

-

-  void Init()

-  {

-    #ifndef 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 _7ZIP_ST

-    decoder._numThreads = _numThreads;

-    #endif

-    decoder._memUsage = _memUsage;

-

-    MainDecodeSRes = SZ_OK;

-

-    RINOK(decoder.Decode(seqInStream, outStream,

-        NULL, // *outSizeLimit

-        true, // finishStream

-        progress));

-    

-    _stat = decoder.Stat;

-    MainDecodeSRes = decoder.MainDecodeSRes;

-

-    _phySize_Defined = true;

-    return S_OK;

-  }

-

-public:

-  MY_QUERYINTERFACE_BEGIN2(IInArchive)

-  MY_QUERYINTERFACE_ENTRY(IArchiveOpenSeq)

-  MY_QUERYINTERFACE_ENTRY(IInArchiveGetStream)

-  MY_QUERYINTERFACE_ENTRY(ISetProperties)

-  #ifndef EXTRACT_ONLY

-  MY_QUERYINTERFACE_ENTRY(IOutArchive)

-  #endif

-  MY_QUERYINTERFACE_END

-  MY_ADDREF_RELEASE

-

-  INTERFACE_IInArchive(;)

-  STDMETHOD(OpenSeq)(ISequentialInStream *stream);

-  STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);

-  STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps);

-

-  #ifndef EXTRACT_ONLY

-  INTERFACE_IOutArchive(;)

-  #endif

-

-  size_t _blocksArraySize;

-  CBlockInfo *_blocks;

-  UInt64 _maxBlocksSize;

-  CMyComPtr<IInStream> _stream;

-  CMyComPtr<ISequentialInStream> _seqStream;

-

-  CXzBlock _firstBlock;

-

-  CHandler();

-  ~CHandler();

-

-  HRESULT SeekToPackPos(UInt64 pos)

-  {

-    return _stream->Seek(pos, STREAM_SEEK_SET, NULL);

-  }

-};

-

-

-CHandler::CHandler():

-    _blocks(NULL),

-    _blocksArraySize(0)

-{

-  #ifndef 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 inline char GetHex(unsigned value)

-{

-  return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10)));

-}

-

-static inline void AddHexToString(AString &s, Byte value)

-{

-  s += GetHex(value >> 4);

-  s += GetHex(value & 0xF);

-}

-

-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 += 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_LZMA2, "LZMA2" }

-};

-

-static void AddMethodString(AString &s, const CXzFilter &f)

-{

-  const char *p = NULL;

-  for (unsigned i = 0; i < 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 += ':';

-    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

-    {

-      s += '[';

-      for (UInt32 bi = 0; bi < f.propsSize; bi++)

-        AddHexToString(s, f.props[bi]);

-      s += ']';

-    }

-  }

-}

-

-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);

-      }

-    }

-}

-

-STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)

-{

-  COM_TRY_BEGIN

-  NCOM::CPropVariant prop;

-  switch (propID)

-  {

-    case kpidPhySize: if (_phySize_Defined) prop = _stat.InSize; break;

-    case kpidNumStreams: if (_stat.NumStreams_Defined) prop = _stat.NumStreams; break;

-    case kpidNumBlocks: if (_stat.NumBlocks_Defined) prop = _stat.NumBlocks; break;

-    case kpidUnpackSize: if (_stat.UnpackSize_Defined) prop = _stat.OutSize; break;

-    case kpidClusterSize: if (_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 = MainDecodeSRes; // _stat.DecodeRes2; //

-      if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;

-      if (/*_stat.UnexpectedEnd */ sres == SZ_ERROR_INPUT_EOF) v |= kpv_ErrorFlags_UnexpectedEnd;

-      if (_stat.DataAfterEnd) v |= kpv_ErrorFlags_DataAfterEnd;

-      if (/* _stat.HeadersError */ sres == SZ_ERROR_ARCHIVE) v |= kpv_ErrorFlags_HeadersError;

-      if (/* _stat.Unsupported */ sres == SZ_ERROR_UNSUPPORTED) v |= kpv_ErrorFlags_UnsupportedMethod;

-      if (/* _stat.DataError */ sres == SZ_ERROR_DATA) v |= kpv_ErrorFlags_DataError;

-      if (/* _stat.CrcError */ 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;

-    }

-  }

-  prop.Detach(value);

-  return S_OK;

-  COM_TRY_END

-}

-

-STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)

-{

-  *numItems = 1;

-  return S_OK;

-}

-

-STDMETHODIMP CHandler::GetProperty(UInt32, PROPID propID, PROPVARIANT *value)

-{

-  COM_TRY_BEGIN

-  NCOM::CPropVariant prop;

-  switch (propID)

-  {

-    case kpidSize: if (_stat.UnpackSize_Defined) prop = _stat.OutSize; break;

-    case kpidPackSize: if (_phySize_Defined) prop = _stat.InSize; break;

-    case kpidMethod: if (!_methodsString.IsEmpty()) prop = _methodsString; break;

-  }

-  prop.Detach(value);

-  return S_OK;

-  COM_TRY_END

-}

-

-

-struct COpenCallbackWrap

-{

-  ICompressProgress vt;

-  IArchiveOpenCallback *OpenCallback;

-  HRESULT Res;

-  COpenCallbackWrap(IArchiveOpenCallback *progress);

-};

-

-static SRes OpenCallbackProgress(const ICompressProgress *pp, UInt64 inSize, UInt64 /* outSize */)

-{

-  COpenCallbackWrap *p = CONTAINER_FROM_VTBL(pp, COpenCallbackWrap, vt);

-  if (p->OpenCallback)

-    p->Res = p->OpenCallback->SetCompleted(NULL, &inSize);

-  return HRESULT_To_SRes(p->Res, SZ_ERROR_PROGRESS);

-}

-

-COpenCallbackWrap::COpenCallbackWrap(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;

-    */

-  }

-  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 (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 (res2 == SZ_OK && !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->Seek(0, STREAM_SEEK_END, &_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(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)

-  {

-    _phySize_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;

-}

-

-

-

-STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *callback)

-{

-  COM_TRY_BEGIN

-  {

-    Close();

-    return Open2(inStream, callback);

-  }

-  COM_TRY_END

-}

-

-STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream)

-{

-  Close();

-  _seqStream = stream;

-  _isArc = true;

-  _needSeekToStart = false;

-  return S_OK;

-}

-

-STDMETHODIMP CHandler::Close()

-{

-  XzStatInfo_Clear(&_stat);

-

-  _isArc = false;

-  _needSeekToStart = false;

-  _phySize_Defined = false;

-  _firstBlockWasRead = false;

-  

-   _methodsString.Empty();

-  _stream.Release();

-  _seqStream.Release();

-

-  MyFree(_blocks);

-  _blocks = NULL;

-  _blocksArraySize = 0;

-  _maxBlocksSize = 0;

-

-  MainDecodeSRes = SZ_OK;

-

-  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);

-}

-

-

-class CInStream:

-  public IInStream,

-  public CMyUnknownImp

-{

-public:

-  UInt64 _virtPos;

-  UInt64 Size;

-  UInt64 _cacheStartPos;

-  size_t _cacheSize;

-  CByteBuffer _cache;

-  // UInt64 _startPos;

-  CXzUnpackerCPP2 xz;

-

-  void InitAndSeek()

-  {

-    _virtPos = 0;

-    _cacheStartPos = 0;

-    _cacheSize = 0;

-    // _startPos = startPos;

-  }

-

-  CHandler *_handlerSpec;

-  CMyComPtr<IUnknown> _handler;

-

-  MY_UNKNOWN_IMP1(IInStream)

-

-  STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);

-  STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);

-

-  ~CInStream();

-};

-

-

-CInStream::~CInStream()

-{

-  // _cache.Free();

-}

-

-

-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;

-

-    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;

-  

-    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;

-    }

-  }

-}

-

-

-STDMETHODIMP 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)

-  {

-    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;

-  }

-

-  {

-    size_t offset = (size_t)(_virtPos - _cacheStartPos);

-    size_t rem = _cacheSize - offset;

-    if (size > rem)

-      size = (UInt32)rem;

-    memcpy(data, _cache + offset, size);

-    _virtPos += size;

-    if (processedSize)

-      *processedSize = size;

-    return S_OK;

-  }

-

-  COM_TRY_END

-}

- 

-

-STDMETHODIMP 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 = offset;

-  if (newPosition)

-    *newPosition = offset;

-  return S_OK;

-}

-

-

-

-static const UInt64 kMaxBlockSize_for_GetStream = (UInt64)1 << 40;

-

-STDMETHODIMP 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;

-  }

-

-  CInStream *spec = new CInStream;

-  CMyComPtr<ISequentialInStream> specStream = spec;

-  spec->_cache.Alloc((size_t)_maxBlocksSize);

-  spec->_handlerSpec = this;

-  spec->_handler = (IInArchive *)this;

-  spec->Size = _stat.OutSize;

-  spec->InitAndSeek();

-

-  *stream = specStream.Detach();

-  return S_OK;

-  

-  COM_TRY_END

-}

-

-

-static Int32 Get_Extract_OperationResult(const NCompress::NXz::CDecoder &decoder)

-{

-  Int32 opRes;

-  SRes sres = decoder.MainDecodeSRes; // decoder.Stat.DecodeRes2;

-  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;

-}

-

-

-

-

-STDMETHODIMP 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 (_phySize_Defined)

-    extractCallback->SetTotal(_stat.InSize);

-

-  UInt64 currentTotalPacked = 0;

-  RINOK(extractCallback->SetCompleted(&currentTotalPacked));

-  CMyComPtr<ISequentialOutStream> realOutStream;

-  Int32 askMode = testMode ?

-      NExtract::NAskMode::kTest :

-      NExtract::NAskMode::kExtract;

-  

-  RINOK(extractCallback->GetStream(0, &realOutStream, askMode));

-  

-  if (!testMode && !realOutStream)

-    return S_OK;

-

-  extractCallback->PrepareOperation(askMode);

-

-  CLocalProgress *lps = new CLocalProgress;

-  CMyComPtr<ICompressProgressInfo> lpsRef = lps;

-  lps->Init(extractCallback, true);

-

-  if (_needSeekToStart)

-  {

-    if (!_stream)

-      return E_FAIL;

-    RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL));

-  }

-  else

-    _needSeekToStart = true;

-

-

-  NCompress::NXz::CDecoder decoder;

-

-  HRESULT hres = Decode(decoder, _seqStream, realOutStream, lpsRef);

-

-  if (!decoder.MainDecodeSRes_wasUsed)

-    return hres == S_OK ? E_FAIL : hres;

-

-  Int32 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 EXTRACT_ONLY

-

-STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType)

-{

-  *timeType = NFileTimeType::kUnix;

-  return S_OK;

-}

-

-

-STDMETHODIMP 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;

-

-  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;

-      RINOK(updateCallback->SetTotal(size));

-    }

-

-    NCompress::NXz::CEncoder *encoderSpec = new NCompress::NXz::CEncoder;

-    CMyComPtr<ICompressCoder> encoder = encoderSpec;

-

-    CXzProps &xzProps = encoderSpec->xzProps;

-    CLzma2EncProps &lzma2Props = xzProps.lzma2Props;

-

-    lzma2Props.lzmaProps.level = GetLevel();

-

-    xzProps.reduceSize = size;

-    /*

-    {

-      NCOM::CPropVariant prop = (UInt64)size;

-      RINOK(encoderSpec->SetCoderProp(NCoderPropID::kReduceSize, prop));

-    }

-    */

-

-    #ifndef _7ZIP_ST

-    xzProps.numTotalThreads = _numThreads;

-    #endif

-

-    xzProps.blockSize = _numSolidBytes;

-    if (_numSolidBytes == XZ_PROPS__BLOCK_SIZE__SOLID)

-    {

-      xzProps.lzma2Props.blockSize = LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID;

-    }

-

-    RINOK(encoderSpec->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(encoderSpec->SetCoderProp(prop.Id, prop.Value));

-      }

-    }

-

-    CMyComPtr<ISequentialInStream> fileInStream;

-    RINOK(updateCallback->GetStream(0, &fileInStream));

-

-    CLocalProgress *lps = new CLocalProgress;

-    CMyComPtr<ICompressProgressInfo> progress = lps;

-    lps->Init(updateCallback, true);

-

-    return encoderSpec->Code(fileInStream, outStream, NULL, NULL, progress);

-  }

-

-  if (indexInArchive != 0)

-    return E_INVALIDARG;

-

-  CMyComPtr<IArchiveUpdateCallbackFile> opCallback;

-  updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback);

-  if (opCallback)

-  {

-    RINOK(opCallback->ReportOperation(NEventIndexType::kInArcIndex, 0, NUpdateNotifyOp::kReplicate))

-  }

-

-  if (_stream)

-  {

-    if (_phySize_Defined)

-      RINOK(updateCallback->SetTotal(_stat.InSize));

-    RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL));

-  }

-

-  CLocalProgress *lps = new CLocalProgress;

-  CMyComPtr<ICompressProgressInfo> progress = lps;

-  lps->Init(updateCallback, true);

-

-  return NCompress::CopyStream(_stream, outStream, progress);

-

-  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 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

-}

-

-

-

-STDMETHODIMP 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 EXTRACT_ONLY

-

-  if (!_filterMethod.MethodName.IsEmpty())

-  {

-    unsigned k;

-    for (k = 0; k < ARRAY_SIZE(g_NamePairs); k++)

-    {

-      const CMethodNamePair &pair = g_NamePairs[k];

-      if (StringsAreEqualNoCase_Ascii(_filterMethod.MethodName, pair.Name))

-      {

-        _filterId = pair.Id;

-        break;

-      }

-    }

-    if (k == 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,

-  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
+
+  CXzStatInfo _stat;    // it's stat from backward parsing
+  CXzStatInfo _stat2;   // it's data from forward parsing, if the decoder was called
+  SRes _stat2_decode_SRes;
+  bool _stat_defined;
+  bool _stat2_defined;
+
+  const CXzStatInfo *GetStat() const
+  {
+    if (_stat_defined) return &_stat;
+    if (_stat2_defined) return &_stat2;
+    return NULL;
+  }
+  
+  bool _isArc;
+  bool _needSeekToStart;
+  bool _firstBlockWasRead;
+
+  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;
+
+    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;
+      }
+    }
+
+    return hres;
+  }
+
+public:
+  CBlockInfo *_blocks;
+  size_t _blocksArraySize;
+  UInt64 _maxBlocksSize;
+  CMyComPtr<IInStream> _stream;
+  CMyComPtr<ISequentialInStream> _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 inline char GetHex(unsigned value)
+{
+  return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10)));
+}
+
+static inline void AddHexToString(AString &s, Byte value)
+{
+  s += GetHex(value >> 4);
+  s += GetHex(value & 0xF);
+}
+
+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 += 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_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 += ':';
+    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 += '[';
+      for (UInt32 bi = 0; bi < f.propsSize; bi++)
+        AddHexToString(s, f.props[bi]);
+      s += ']';
+    }
+  }
+}
+
+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;
+    }
+  }
+  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;
+  }
+  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;
+    */
+  }
+  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_COM_1(
+  CInStream
+  , IInStream
+)
+  Z7_IFACE_COM7_IMP(ISequentialInStream)
+
+  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;
+  }
+
+  CHandler *_handlerSpec;
+  CMyComPtr<IUnknown> _handler;
+
+  // ~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 + 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;
+  }
+
+  CInStream *spec = new CInStream;
+  CMyComPtr<ISequentialInStream> specStream = spec;
+  spec->_cache.Alloc((size_t)_maxBlocksSize);
+  spec->_handlerSpec = this;
+  spec->_handler = (IInArchive *)this;
+  spec->Size = _stat.OutSize;
+  spec->InitAndSeek();
+
+  *stream = specStream.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)
+    extractCallback->SetTotal(stat->InSize);
+
+  UInt64 currentTotalPacked = 0;
+  RINOK(extractCallback->SetCompleted(&currentTotalPacked))
+  CMyComPtr<ISequentialOutStream> 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);
+
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> lpsRef = lps;
+  lps->Init(extractCallback, true);
+
+  if (_needSeekToStart)
+  {
+    if (!_stream)
+      return E_FAIL;
+    RINOK(InStream_SeekToBegin(_stream))
+  }
+  else
+    _needSeekToStart = true;
+
+
+  NCompress::NXz::CDecoder decoder;
+
+  HRESULT hres = Decode(decoder, _seqStream, realOutStream, lpsRef);
+
+  if (!decoder.MainDecodeSRes_wasUsed)
+    return hres == S_OK ? E_FAIL : hres;
+
+  Int32 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;
+    }
+
+    NCompress::NXz::CEncoder *encoderSpec = new NCompress::NXz::CEncoder;
+    CMyComPtr<ICompressCoder> encoder = encoderSpec;
+
+    CXzProps &xzProps = encoderSpec->xzProps;
+    CLzma2EncProps &lzma2Props = xzProps.lzma2Props;
+
+    lzma2Props.lzmaProps.level = GetLevel();
+
+    xzProps.reduceSize = dataSize;
+    /*
+    {
+      NCOM::CPropVariant prop = (UInt64)dataSize;
+      RINOK(encoderSpec->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(encoderSpec->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(encoderSpec->SetCoderProp(prop.Id, prop.Value))
+      }
+    }
+
+    {
+      CMyComPtr<ISequentialInStream> fileInStream;
+      RINOK(updateCallback->GetStream(0, &fileInStream))
+      if (!fileInStream)
+        return S_FALSE;
+      {
+        CMyComPtr<IStreamGetSize> streamGetSize;
+        fileInStream.QueryInterface(IID_IStreamGetSize, &streamGetSize);
+        if (streamGetSize)
+        {
+          UInt64 size;
+          if (streamGetSize->GetSize(&size) == S_OK)
+            dataSize = size;
+        }
+      }
+      RINOK(updateCallback->SetTotal(dataSize))
+      CLocalProgress *lps = new CLocalProgress;
+      CMyComPtr<ICompressProgressInfo> progress = lps;
+      lps->Init(updateCallback, true);
+      RINOK(encoder->Code(fileInStream, outStream, NULL, NULL, progress))
+    }
+      
+    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))
+  }
+
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> progress = lps;
+  lps->Init(updateCallback, true);
+
+  return NCompress::CopyStream(_stream, outStream, progress);
+
+  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 18633fb..4d09954 100644
--- a/CPP/7zip/Archive/XzHandler.h
+++ b/CPP/7zip/Archive/XzHandler.h
@@ -1,11 +1,11 @@
-// XzHandler.h

-

-#ifndef __XZ_HANDLER_H

-#define __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
new file mode 100644
index 0000000..18e712a
--- /dev/null
+++ b/CPP/7zip/Archive/ZHandler.cpp
@@ -0,0 +1,230 @@
+// 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<IInStream> _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<IArchiveOpenCallback> 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<ICompressProgressInfo> compressProgress = compressProgressSpec;
+      compressProgressSpec->Init(openCallback);
+
+      NCompress::NZ::CDecoder *decoderSpec = new NCompress::NZ::CDecoder;
+      CMyComPtr<ICompressCoder> decoder = decoderSpec;
+
+      CDummyOutStream *outStreamSpec = new CDummyOutStream;
+      CMyComPtr<ISequentialOutStream> 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;
+
+  extractCallback->SetTotal(_packSize);
+
+  UInt64 currentTotalPacked = 0;
+  
+  RINOK(extractCallback->SetCompleted(&currentTotalPacked))
+  
+  CMyComPtr<ISequentialOutStream> 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);
+
+  CDummyOutStream *outStreamSpec = new CDummyOutStream;
+  CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+  outStreamSpec->SetStream(realOutStream);
+  outStreamSpec->Init();
+  realOutStream.Release();
+
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> progress = lps;
+  lps->Init(extractCallback, true);
+  
+  RINOK(InStream_SeekToBegin(_stream))
+
+  NCompress::NZ::CDecoder *decoderSpec = new NCompress::NZ::CDecoder;
+  CMyComPtr<ICompressCoder> decoder = decoderSpec;
+
+  int opRes;
+  {
+    HRESULT result = decoder->Code(_stream, outStream, NULL, NULL, progress);
+    if (result == S_FALSE)
+      opRes = NExtract::NOperationResult::kDataError;
+    else
+    {
+      RINOK(result)
+      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
new file mode 100644
index 0000000..035267c
--- /dev/null
+++ b/CPP/7zip/Archive/Zip/StdAfx.h
@@ -0,0 +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
diff --git a/CPP/7zip/Archive/Zip/ZipAddCommon.cpp b/CPP/7zip/Archive/Zip/ZipAddCommon.cpp
new file mode 100644
index 0000000..8af84b4
--- /dev/null
+++ b/CPP/7zip/Archive/Zip/ZipAddCommon.cpp
@@ -0,0 +1,499 @@
+// 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:
+  NCompress::NLzma::CEncoder *EncoderSpec;
+  CMyComPtr<ICompressCoder> Encoder;
+  Byte Header[kLzmaHeaderSize];
+};
+
+Z7_COM7F_IMF(CLzmaEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps))
+{
+  if (!Encoder)
+  {
+    EncoderSpec = new NCompress::NLzma::CEncoder;
+    Encoder = EncoderSpec;
+  }
+  CBufPtrSeqOutStream *outStreamSpec = new CBufPtrSeqOutStream;
+  CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+  outStreamSpec->Init(Header + 4, kLzmaPropsSize);
+  RINOK(EncoderSpec->SetCoderProperties(propIDs, props, numProps))
+  RINOK(EncoderSpec->WriteCoderProperties(outStream))
+  if (outStreamSpec->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 EncoderSpec->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->Code(inStream, outStream, inSize, outSize, progress);
+}
+
+
+CAddCommon::CAddCommon():
+    _copyCoderSpec(NULL),
+    _isLzmaEos(false),
+    _cryptoStreamSpec(NULL),
+    _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;
+    }
+  }
+  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;
+  }
+
+  CSequentialInStreamWithCRC *inSecCrcStreamSpec = new CSequentialInStreamWithCRC;
+  CMyComPtr<ISequentialInStream> inCrcStream = inSecCrcStreamSpec;
+  
+  CMyComPtr<IInStream> inStream2;
+  if (!inSeqMode)
+  {
+    inStream->QueryInterface(IID_IInStream, (void **)&inStream2);
+    if (!inStream2)
+    {
+      // inSeqMode = true;
+      // inSeqMode must be correct before
+      return E_FAIL;
+    }
+  }
+
+  inSecCrcStreamSpec->SetStream(inStream);
+  inSecCrcStreamSpec->SetFullSize(expectedDataSize_IsConfirmed ? expectedDataSize : (UInt64)(Int64)-1);
+  // inSecCrcStreamSpec->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++)
+  {
+    inSecCrcStreamSpec->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)
+      {
+        _cryptoStreamSpec = new CFilterCoder(true);
+        _cryptoStream = _cryptoStreamSpec;
+      }
+      
+      if (_options.IsAesMode)
+      {
+        opRes.ExtractVersion = NCompressionMethod::kExtractVersion_Aes;
+        if (!_cryptoStreamSpec->Filter)
+        {
+          _cryptoStreamSpec->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 (!_cryptoStreamSpec->Filter)
+        {
+          _cryptoStreamSpec->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))
+            inSecCrcStreamSpec->Init();
+          }
+          check = (crc >> 16);
+        }
+        
+        RINOK(_filterSpec->WriteHeader_Check16(outStream, (UInt16)check))
+      }
+      
+      if (method == NCompressionMethod::kStore)
+      {
+        needCode = false;
+        RINOK(_cryptoStreamSpec->Code(inCrcStream, outStream, NULL, NULL, progress))
+      }
+      else
+      {
+        RINOK(_cryptoStreamSpec->SetOutStream(outStream))
+        RINOK(_cryptoStreamSpec->InitEncoder())
+        outStreamReleaser.FilterCoder = _cryptoStreamSpec;
+      }
+    }
+
+    if (needCode)
+    {
+      switch (method)
+      {
+      case NCompressionMethod::kStore:
+      {
+        if (!_copyCoderSpec)
+        {
+          _copyCoderSpec = new NCompress::CCopyCoder;
+          _copyCoder = _copyCoderSpec;
+        }
+        CMyComPtr<ISequentialOutStream> outStreamNew;
+        if (_options.Password_Defined)
+          outStreamNew = _cryptoStream;
+        else
+          outStreamNew = outStream;
+        RINOK(_copyCoder->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<ICompressSetCoderProperties> 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->EncoderSpec->IsWriteEndMark();
+        }
+
+        if (method == NCompressionMethod::kLZMA)
+          opRes.LzmaEos = _isLzmaEos;
+
+        CMyComPtr<ISequentialOutStream> outStreamNew;
+        if (_options.Password_Defined)
+          outStreamNew = _cryptoStream;
+        else
+          outStreamNew = outStream;
+        if (_compressExtractVersion > opRes.ExtractVersion)
+          opRes.ExtractVersion = _compressExtractVersion;
+
+        {
+          CMyComPtr<ICompressSetCoderPropertiesOpt> 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(_cryptoStreamSpec->OutStreamFinish())
+      }
+    }
+
+    if (_options.Password_Defined)
+    {
+      if (_options.IsAesMode)
+      {
+        RINOK(_filterAesSpec->WriteFooter(outStream))
+      }
+    }
+    
+    RINOK(outStream->Seek(0, STREAM_SEEK_CUR, &opRes.PackSize))
+
+    {
+      opRes.CRC = inSecCrcStreamSpec->GetCRC();
+      opRes.UnpackSize = inSecCrcStreamSpec->GetSize();
+      opRes.Method = method;
+    }
+
+    if (!inSecCrcStreamSpec->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
new file mode 100644
index 0000000..051915c
--- /dev/null
+++ b/CPP/7zip/Archive/Zip/ZipAddCommon.h
@@ -0,0 +1,78 @@
+// 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;
+  NCompress::CCopyCoder *_copyCoderSpec;
+  CMyComPtr<ICompressCoder> _copyCoder;
+
+  CMyComPtr<ICompressCoder> _compressEncoder;
+  Byte _compressExtractVersion;
+  bool _isLzmaEos;
+
+  CFilterCoder *_cryptoStreamSpec;
+  CMyComPtr<ISequentialOutStream> _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
new file mode 100644
index 0000000..8974261
--- /dev/null
+++ b/CPP/7zip/Archive/Zip/ZipCompressionMode.h
@@ -0,0 +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<Byte> 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
new file mode 100644
index 0000000..5f022cc
--- /dev/null
+++ b/CPP/7zip/Archive/Zip/ZipHandler.cpp
@@ -0,0 +1,1716 @@
+// 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"
+
+#ifdef Z7_EXTERNAL_CODECS
+#ifndef SUPPORT_LZFSE
+#define SUPPORT_LZFSE
+#endif
+#endif
+
+#ifdef SUPPORT_LZFSE
+#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 "../../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;
+  }
+  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 += ':';
+              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
+        {
+          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 += ':';
+            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;
+    */
+  }
+  
+  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<CItemEx> &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:
+  NCompress::NLzma::CDecoder *DecoderSpec;
+  CMyComPtr<ICompressCoder> Decoder;
+
+  CLzmaDecoder();
+};
+
+CLzmaDecoder::CLzmaDecoder()
+{
+  DecoderSpec = new NCompress::NLzma::CDecoder;
+  Decoder = DecoderSpec;
+}
+
+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(DecoderSpec->SetDecoderProperties2(buf + 4, LZMA_PROPS_SIZE))
+  UInt64 inSize2 = 0;
+  if (inSize)
+  {
+    inSize2 = *inSize;
+    if (inSize2 < kZipLzmaPropsSize)
+      return S_FALSE;
+    inSize2 -= kZipLzmaPropsSize;
+  }
+  return Decoder->Code(inStream, outStream, inSize ? &inSize2 : NULL, outSize, progress);
+}
+
+Z7_COM7F_IMF(CLzmaDecoder::SetFinishMode(UInt32 finishMode))
+{
+  DecoderSpec->FinishStream = (finishMode != 0);
+  return S_OK;
+}
+
+Z7_COM7F_IMF(CLzmaDecoder::GetInStreamProcessedSize(UInt64 *value))
+{
+  *value = DecoderSpec->GetInputProcessedSize() + kZipLzmaPropsSize;
+  return S_OK;
+}
+
+
+
+
+
+
+
+struct CMethodItem
+{
+  unsigned ZipMethod;
+  CMyComPtr<ICompressCoder> Coder;
+};
+
+
+
+class CZipDecoder
+{
+  NCrypto::NZip::CDecoder *_zipCryptoDecoderSpec;
+  NCrypto::NZipStrong::CDecoder *_pkAesDecoderSpec;
+  NCrypto::NWzAes::CDecoder *_wzAesDecoderSpec;
+
+  CMyComPtr<ICompressFilter> _zipCryptoDecoder;
+  CMyComPtr<ICompressFilter> _pkAesDecoder;
+  CMyComPtr<ICompressFilter> _wzAesDecoder;
+
+  CFilterCoder *filterStreamSpec;
+  CMyComPtr<ISequentialInStream> filterStream;
+  CMyComPtr<ICryptoGetTextPassword> getTextPassword;
+  CObjectVector<CMethodItem> methodItems;
+
+  CLzmaDecoder *lzmaDecoderSpec;
+public:
+  CZipDecoder():
+      _zipCryptoDecoderSpec(NULL),
+      _pkAesDecoderSpec(NULL),
+      _wzAesDecoderSpec(NULL),
+      filterStreamSpec(NULL),
+      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<ISequentialOutStream> _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;
+    }
+  }
+
+  COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC;
+  CMyComPtr<ISequentialOutStream> outStream = outStreamSpec;
+  outStreamSpec->SetStream(realOutStream);
+  outStreamSpec->Init(needCRC);
+  
+  CMyComPtr<ISequentialInStream> packStream;
+
+  CLimitedSequentialInStream *limitedStreamSpec = new CLimitedSequentialInStream;
+  CMyComPtr<ISequentialInStream> inStream(limitedStreamSpec);
+
+  {
+    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;
+    }
+    limitedStreamSpec->SetStream(packStream);
+    limitedStreamSpec->Init(packSize);
+  }
+
+  
+  res = NExtract::NOperationResult::kDataError;
+  
+  CMyComPtr<ICompressFilter> cryptoFilter;
+  
+  if (item.IsEncrypted())
+  {
+    if (wzAesMode)
+    {
+      id = aesField.Method;
+      if (!_wzAesDecoder)
+      {
+        _wzAesDecoderSpec = new NCrypto::NWzAes::CDecoder;
+        _wzAesDecoder = _wzAesDecoderSpec;
+      }
+      cryptoFilter = _wzAesDecoder;
+      if (!_wzAesDecoderSpec->SetKeyMode(aesField.Strength))
+      {
+        res = NExtract::NOperationResult::kUnsupportedMethod;
+        return S_OK;
+      }
+    }
+    else if (pkAesMode)
+    {
+      if (!_pkAesDecoder)
+      {
+        _pkAesDecoderSpec = new NCrypto::NZipStrong::CDecoder;
+        _pkAesDecoder = _pkAesDecoderSpec;
+      }
+      cryptoFilter = _pkAesDecoder;
+    }
+    else
+    {
+      if (!_zipCryptoDecoder)
+      {
+        _zipCryptoDecoderSpec = new NCrypto::NZip::CDecoder;
+        _zipCryptoDecoder = _zipCryptoDecoderSpec;
+      }
+      cryptoFilter = _zipCryptoDecoder;
+    }
+    
+    CMyComPtr<ICryptoSetPassword> 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)
+      {
+        /*
+        // 22.00: do we need UTF-8 passwords here ?
+        if (item.IsUtf8()) // 22.00
+        {
+          // throw 1;
+          ConvertUnicodeToUTF8((LPCOLESTR)password, charPassword);
+        }
+        else
+        */
+        {
+          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);
+    #ifdef SUPPORT_LZFSE
+    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<ICompressSetCoderMt> setCoderMt;
+    coder->QueryInterface(IID_ICompressSetCoderMt, (void **)&setCoderMt);
+    if (setCoderMt)
+    {
+      RINOK(setCoderMt->SetNumberOfThreads(numThreads))
+    }
+  }
+  // if (memUsage != 0)
+  {
+    CMyComPtr<ICompressSetMemLimit> setMemLimit;
+    coder->QueryInterface(IID_ICompressSetMemLimit, (void **)&setMemLimit);
+    if (setMemLimit)
+    {
+      RINOK(setMemLimit->SetMemLimit(memUsage))
+    }
+  }
+  #endif
+
+  {
+    CMyComPtr<ICompressSetDecoderProperties2> 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)
+      {
+        filterStreamSpec = new CFilterCoder(false);
+        filterStream = filterStreamSpec;
+      }
+     
+      filterReleaser.FilterCoder = filterStreamSpec;
+      filterStreamSpec->Filter = cryptoFilter;
+      
+      if (wzAesMode)
+      {
+        result = _wzAesDecoderSpec->ReadHeader(inStream);
+        if (result == S_OK)
+        {
+          if (!_wzAesDecoderSpec->Init_and_CheckPassword())
+          {
+            res = NExtract::NOperationResult::kWrongPassword;
+            return S_OK;
+          }
+        }
+      }
+      else if (pkAesMode)
+      {
+        isFullStreamExpected = false;
+        result =_pkAesDecoderSpec->ReadHeader(inStream, item.Crc, item.Size);
+        if (result == S_OK)
+        {
+          bool passwOK;
+          result = _pkAesDecoderSpec->Init_and_CheckPassword(passwOK);
+          if (result == S_OK && !passwOK)
+          {
+            res = NExtract::NOperationResult::kWrongPassword;
+            return S_OK;
+          }
+        }
+      }
+      else
+      {
+        result = _zipCryptoDecoderSpec->ReadHeader(inStream);
+        if (result == S_OK)
+        {
+          _zipCryptoDecoderSpec->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(_zipCryptoDecoderSpec->_header + NCrypto::NZip::kHeaderSize - 2);
+          // UInt32 v2 = (item.HasDescriptor() ? (item.Time & 0xFFFF) : (item.Crc >> 16));
+
+          Byte v1 = _zipCryptoDecoderSpec->_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<ICompressSetFinishMode> setFinishMode;
+      coder->QueryInterface(IID_ICompressSetFinishMode, (void **)&setFinishMode);
+      if (setFinishMode)
+      {
+        RINOK(setFinishMode->SetFinishMode(BoolToUInt(true)))
+      }
+      
+      const UInt64 coderPackSize = limitedStreamSpec->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<ISequentialOutStream> padStream;
+        UInt32 padSize = 0;
+        
+        if (pkAesMode)
+        {
+          padStreamSpec = new COutStreamWithPadPKCS7;
+          padStream = padStreamSpec;
+          padSize = _pkAesDecoderSpec->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 = filterStreamSpec->Code(inStream, padStream ?
+            (ISequentialOutStream *)padStream :
+            (ISequentialOutStream *)outStream,
+            NULL, &size, compressProgress);
+
+        if (outStreamSpec->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 = filterStreamSpec;
+          RINOK(filterStreamSpec->SetInStream(inStream))
+          
+          /* IFilter::Init() does nothing in all zip crypto filters.
+          So we can call any Initialize function in CFilterCoder. */
+          
+          RINOK(filterStreamSpec->Init_NoSubFilterInit())
+          // RINOK(filterStreamSpec->SetOutStreamSize(NULL));
+        }
+
+        try {
+        result = coder->Code(readFromFilter ?
+              (ISequentialInStream *)filterStream :
+              (ISequentialInStream *)inStream,
+            outStream,
+            isFullStreamExpected ? &coderPackSize : NULL,
+            // NULL,
+            useUnpackLimit ? &item.Size : NULL,
+            compressProgress);
+        } catch (...) { return E_FAIL; }
+
+        if (result == S_OK)
+        {
+        CMyComPtr<ICompressGetInStreamProcessedSize> 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 = _pkAesDecoderSpec->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<ICompressReadUnusedFromInBuf> 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->DecoderSpec->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 = (outStreamSpec->GetCRC() == item.Crc);
+
+  if (useUnpackLimit)
+    if (outStreamSpec->GetSize() != item.Size)
+      truncatedError = true;
+  
+  if (wzAesMode)
+  {
+    const UInt64 unpackSize = outStreamSpec->GetSize();
+    const UInt64 packSize = limitedStreamSpec->GetSize();
+    bool thereAreData = false;
+    // read to the end from filter or from packed stream
+    if (SkipStreamData(readFromFilter ?
+          (ISequentialInStream *)filterStream :
+          (ISequentialInStream *)inStream,
+        compressProgress, packSize, unpackSize, thereAreData) != S_OK)
+      authOk = false;
+    if (needReminderCheck && thereAreData)
+      dataAfterEnd = true;
+
+    if (limitedStreamSpec->GetRem() != 0)
+      truncatedError = true;
+    else
+    {
+      limitedStreamSpec->Init(NCrypto::NWzAes::kMacSize);
+      if (_wzAesDecoderSpec->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;
+  
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> progress = 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;
+
+    CMyComPtr<ISequentialOutStream> 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))
+
+    Int32 res;
+    const HRESULT hres = myDecoder.Decode(
+        EXTERNAL_CODECS_VARS
+        m_Archive, item, realOutStream, extractCallback,
+        progress,
+        #ifndef Z7_ST
+        _props._numThreads, _props._memUsage_Decompress,
+        #endif
+        res);
+    
+    RINOK(hres)
+    realOutStream.Release();
+    
+    if (res == NExtract::NOperationResult::kOK && headersError)
+      res = NExtract::NOperationResult::kHeadersError;
+
+    RINOK(extractCallback->SetOperationResult(res))
+  }
+  
+  COM_TRY_END
+}
+
+IMPL_ISetCompressCodecsInfo
+
+}}
diff --git a/CPP/7zip/Archive/Zip/ZipHandler.h b/CPP/7zip/Archive/Zip/ZipHandler.h
new file mode 100644
index 0000000..1f38bff
--- /dev/null
+++ b/CPP/7zip/Archive/Zip/ZipHandler.h
@@ -0,0 +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<CItemEx> 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<CItemEx> &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
new file mode 100644
index 0000000..19699b5
--- /dev/null
+++ b/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp
@@ -0,0 +1,618 @@
+// 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<CUpdateItem> 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<ICryptoGetTextPassword2> getTextPassword;
+  {
+    CMyComPtr<IArchiveUpdateCallback> 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;
+          if (StringsAreEqual_Ascii(m, "128"))
+            _props.AesKeyMode = 1;
+          else if (StringsAreEqual_Ascii(m, "192"))
+            _props.AesKeyMode = 2;
+          else if (StringsAreEqual_Ascii(m, "256") || m[0] == 0)
+            _props.AesKeyMode = 3;
+          else
+            return E_INVALIDARG;
+          _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
new file mode 100644
index 0000000..038d49d
--- /dev/null
+++ b/CPP/7zip/Archive/Zip/ZipHeader.h
@@ -0,0 +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
diff --git a/CPP/7zip/Archive/Zip/ZipIn.cpp b/CPP/7zip/Archive/Zip/ZipIn.cpp
new file mode 100644
index 0000000..4236df7
--- /dev/null
+++ b/CPP/7zip/Archive/Zip/ZipIn.cpp
@@ -0,0 +1,3485 @@
+// Archive/ZipIn.cpp
+
+#include "StdAfx.h"
+
+// #include <stdio.h>
+
+#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<CItemEx> &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<CItemEx> &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<CItemEx> &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<CItemEx> &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<IInStream> 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<IInStream> stream;
+
+    if ((int)i == zipDisk)
+    {
+      stream = Vols.ZipStream;
+    }
+    else if ((int)i == Vols.StartVolIndex)
+    {
+      stream = StartStream;
+    }
+    else
+    {
+      UString volName = Vols.BaseName;
+      {
+        volName += (char)(Vols.IsUpperCase ? 'Z' : 'z');
+        unsigned v = i + 1;
+        if (v < 10)
+          volName += '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<IArchiveOpenVolumeCallback> 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<CItemEx> &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<CItemEx> 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<unsigned> 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<CItemEx> &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<ISequentialInStream> &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
new file mode 100644
index 0000000..bea26dc
--- /dev/null
+++ b/CPP/7zip/Archive/Zip/ZipIn.h
@@ -0,0 +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<IInStream> Stream;
+    UInt64 Size;
+
+    HRESULT SeekToStart() const { return InStream_SeekToBegin(Stream); }
+
+    CSubStreamInfo(): Size(0) {}
+  };
+  
+  CObjectVector<CSubStreamInfo> 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<IInStream> 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<IInStream> 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<CItemEx> &items, const CCdInfo &cdInfo, UInt64 cdOffset, UInt64 cdSize);
+  HRESULT ReadCd(CObjectVector<CItemEx> &items, UInt32 &cdDisk, UInt64 &cdOffset, UInt64 &cdSize);
+  HRESULT ReadLocals(CObjectVector<CItemEx> &localItems);
+
+  HRESULT ReadHeaders(CObjectVector<CItemEx> &items);
+
+  HRESULT GetVolStream(unsigned vol, UInt64 pos, CMyComPtr<ISequentialInStream> &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<CItemEx> &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<ISequentialInStream> &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
new file mode 100644
index 0000000..a77643b
--- /dev/null
+++ b/CPP/7zip/Archive/Zip/ZipItem.cpp
@@ -0,0 +1,462 @@
+// 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 += ':';
+          const Byte flags = Data[0];
+          if (flags & 1) s += 'M';
+          if (flags & 2) s += 'A';
+          if (flags & 4) s += 'C';
+          const UInt32 size = (UInt32)(Data.Size()) - 1;
+          if (size % 4 == 0)
+          {
+            s += ':';
+            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[32];
+    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;
+    }
+  }
+
+  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;
+  }
+  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<CExtraSubBlock> &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
new file mode 100644
index 0000000..4a25de3
--- /dev/null
+++ b/CPP/7zip/Archive/Zip/ZipItem.h
@@ -0,0 +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<CExtraSubBlock> 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
new file mode 100644
index 0000000..63f1a71
--- /dev/null
+++ b/CPP/7zip/Archive/Zip/ZipOut.cpp
@@ -0,0 +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<CItemOut> &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<IOutStream> &outStream)
+{
+  COffsetOutStream *streamSpec = new COffsetOutStream;
+  outStream = streamSpec;
+  streamSpec->Init(m_Stream, m_Base + m_CurPos);
+}
+
+void COutArchive::CreateStreamForCopying(CMyComPtr<ISequentialOutStream> &outStream)
+{
+  outStream = m_Stream;
+}
+
+}}
diff --git a/CPP/7zip/Archive/Zip/ZipOut.h b/CPP/7zip/Archive/Zip/ZipOut.h
new file mode 100644
index 0000000..e9b2abb
--- /dev/null
+++ b/CPP/7zip/Archive/Zip/ZipOut.h
@@ -0,0 +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<IOutStream> 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<IStreamSetRestriction> 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<CItemOut> &items, const CByteBuffer *comment);
+
+  void CreateStreamForCompressing(CMyComPtr<IOutStream> &outStream);
+  void CreateStreamForCopying(CMyComPtr<ISequentialOutStream> &outStream);
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/Zip/ZipRegister.cpp b/CPP/7zip/Archive/Zip/ZipRegister.cpp
new file mode 100644
index 0000000..c17a1a3
--- /dev/null
+++ b/CPP/7zip/Archive/Zip/ZipRegister.cpp
@@ -0,0 +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)
+ 
+}}
diff --git a/CPP/7zip/Archive/Zip/ZipUpdate.cpp b/CPP/7zip/Archive/Zip/ZipUpdate.cpp
new file mode 100644
index 0000000..e6d881c
--- /dev/null
+++ b/CPP/7zip/Archive/Zip/ZipUpdate.cpp
@@ -0,0 +1,2027 @@
+// ZipUpdate.cpp
+
+#include "StdAfx.h"
+
+// #define DEBUG_CACHE
+
+#ifdef DEBUG_CACHE
+#include <stdio.h>
+  #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<ICompressProgressInfo> Progress;
+
+  COutMemStream *OutStreamSpec;
+  CMyComPtr<IOutStream> OutStream;
+  CMyComPtr<ISequentialInStream> 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<CThreadInfo> 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<CMemBlocks2> 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<IProgress> Progress;
+  CMyComPtr<ICompressProgressInfo> 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<ICompressProgressInfo> 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<ISequentialInStream> packStream;
+
+  RINOK(inArchive->GetItemStream(itemEx, ui.NewProps, packStream))
+  if (!packStream)
+    return E_NOTIMPL;
+
+  complexity += rangeSize;
+
+  CMyComPtr<ISequentialOutStream> 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<IStreamGetProps> 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<IStreamGetSize> 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<CItemEx> &inputItems,
+    CObjectVector<CUpdateItem> &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<ICompressProgressInfo> progress = lps;
+  lps->Init(updateCallback, true);
+
+  CAddCommon compressor;
+  compressor.SetOptions(*options);
+  
+  CObjectVector<CItemOut> 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<ISequentialInStream> 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<IInStream> 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<IOutStream> 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<CItemEx> &inputItems,
+    CObjectVector<CUpdateItem> &updateItems,
+    const CUpdateOptions &updateOptions,
+    const CCompressionMethodMode &options, bool outSeqMode,
+    const CByteBuffer *comment,
+    IArchiveUpdateCallback *updateCallback)
+{
+  CMyComPtr<IArchiveUpdateCallbackFile> opCallback;
+  updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback);
+
+  /*
+  CMyComPtr<IArchiveUpdateCallbackArcProp> 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.Front();
+
+  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<CItemOut> items;
+
+  CMtProgressMixer *mtProgressMixerSpec = new CMtProgressMixer;
+  CMyComPtr<ICompressProgressInfo> 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<ISequentialInStream> fileInStream;
+      
+      CMemBlocks2 &memRef2 = refs.Refs[mtItemIndex - 1];
+
+      {
+        NWindows::NSynchronization::CCriticalSectionLock lock(mtProgressMixerSpec->Mixer2->CriticalSection);
+        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<IInStream> 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());
+      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<ISequentialOutStream> 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.Front()];
+            if (!thread.OutStreamSpec->WasUnlockEventSent())
+            {
+              CMyComPtr<IOutStream> outStream;
+              archive.CreateStreamForCompressing(outStream);
+              thread.OutStreamSpec->SetOutStream(outStream);
+              thread.OutStreamSpec->SetRealStreamMode();
+            }
+          }
+
+          WRes wres = mtSem.Semaphore.Lock();
+          if (wres != 0)
+            return HRESULT_FROM_WIN32(wres);
+
+          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<ISequentialOutStream> _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)
+
+  CMyComPtr<IOutStream> _stream;
+  CMyComPtr<ISequentialOutStream> _seqStream;
+  Byte *_cache;
+  UInt64 _virtPos;
+  UInt64 _virtSize;
+  UInt64 _phyPos;
+  UInt64 _phySize; // <= _virtSize
+  UInt64 _cachedPos; // (_cachedPos + _cachedSize) <= _virtSize
+  size_t _cachedSize;
+  HRESULT _hres;
+
+  UInt64 _restrict_begin;
+  UInt64 _restrict_end;
+  UInt64 _restrict_phy; // begin
+  CMyComPtr<IStreamSetRestriction> _setRestriction;
+
+  HRESULT MyWrite(size_t size);
+  HRESULT MyWriteBlock()
+  {
+    return MyWrite(kCacheBlockSize - ((size_t)_cachedPos & (kCacheBlockSize - 1)));
+  }
+  HRESULT WriteNonRestrictedBlocks();
+  HRESULT FlushCache();
+public:
+  CCacheOutStream(): _cache(NULL) {}
+  ~CCacheOutStream();
+  bool Allocate();
+  HRESULT Init(ISequentialOutStream *seqStream, IOutStream *stream, IStreamSetRestriction *setRestriction);
+  HRESULT FinalFlush();
+};
+
+
+bool CCacheOutStream::Allocate()
+{
+  if (!_cache)
+    _cache = (Byte *)::MidAlloc(kCacheSize);
+  return (_cache != NULL);
+}
+
+HRESULT CCacheOutStream::Init(ISequentialOutStream *seqStream, IOutStream *stream, IStreamSetRestriction *setRestriction)
+{
+  _cachedPos = 0;
+  _cachedSize = 0;
+  _hres = S_OK;
+  _restrict_begin = 0;
+  _restrict_end = 0;
+  _restrict_phy = 0;
+  _virtPos = 0;
+  _virtSize = 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;
+}
+
+
+/* it writes up to (size) bytes from cache.
+   (size > _cachedSize) is allowed */
+
+HRESULT CCacheOutStream::MyWrite(size_t size)
+{
+  PRF(printf("\n-- CCacheOutStream::MyWrite %u\n", (unsigned)size));
+  if (_hres != S_OK)
+    return _hres;
+  while (size != 0 && _cachedSize != 0)
+  {
+    if (_phyPos != _cachedPos)
+    {
+      if (!_stream)
+        return E_FAIL;
+      _hres = _stream->Seek((Int64)_cachedPos, STREAM_SEEK_SET, &_phyPos);
+      RINOK(_hres)
+      if (_phyPos != _cachedPos)
+      {
+        _hres = E_FAIL;
+        return _hres;
+      }
+    }
+    const size_t pos = (size_t)_cachedPos & kCacheMask;
+    size_t curSize = kCacheSize - pos;
+    curSize = MyMin(curSize, _cachedSize);
+    curSize = MyMin(curSize, size);
+    _hres = WriteStream(_seqStream, _cache + pos, curSize);
+    RINOK(_hres)
+    _phyPos += curSize;
+    if (_phySize < _phyPos)
+      _phySize = _phyPos;
+    _cachedPos += curSize;
+    _cachedSize -= curSize;
+    size -= curSize;
+  }
+  
+  if (_setRestriction)
+  if (_restrict_begin == _restrict_end || _cachedPos <= _restrict_begin)
+  if (_restrict_phy < _cachedPos)
+  {
+    _restrict_phy = _cachedPos;
+    return _setRestriction->SetRestriction(_cachedPos, (UInt64)(Int64)-1);
+  }
+  return S_OK;
+}
+
+
+HRESULT CCacheOutStream::WriteNonRestrictedBlocks()
+{
+  for (;;)
+  {
+    const size_t size = kCacheBlockSize - ((size_t)_cachedPos & (kCacheBlockSize - 1));
+    if (_cachedSize < size)
+      break;
+    if (_restrict_begin != _restrict_end && _cachedPos + size > _restrict_begin)
+      break;
+    RINOK(MyWrite(size))
+  }
+  return S_OK;
+}
+
+
+HRESULT CCacheOutStream::FlushCache()
+{
+  return MyWrite(_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))
+    }
+    if (_virtPos != _phyPos)
+    {
+      RINOK(_stream->Seek((Int64)_virtPos, STREAM_SEEK_SET, NULL))
+    }
+  }
+  return S_OK;
+}
+
+
+CCacheOutStream::~CCacheOutStream()
+{
+  ::MidFree(_cache);
+}
+
+
+Z7_COM7F_IMF(CCacheOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize))
+{
+  PRF(printf("\n-- CCacheOutStream::Write %u\n", (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())
+  }
+
+  // ---------- Writing data to cache ----------
+
+  if (_cachedSize == 0)
+    _cachedPos = _virtPos;
+
+  const size_t pos = (size_t)_virtPos & kCacheMask;
+  size = (UInt32)MyMin((size_t)size, kCacheSize - pos);
+  const UInt64 cachedEnd = _cachedPos + _cachedSize;
+  
+  // (_virtPos >= _cachedPos) (_virtPos <= cachedEnd)
+  
+  if (_virtPos != cachedEnd)
+  {
+    // _virtPos < cachedEnd
+    // we rewrite only existing data in cache. So _cachedSize will be not changed
+    size = (UInt32)MyMin((size_t)size, (size_t)(cachedEnd - _virtPos));
+  }
+  else
+  {
+    // _virtPos == cachedEnd
+    // so we need to add new data to the end of cache
+    if (_cachedSize == kCacheSize)
+    {
+      // cache is full. So we flush part of cache
+      RINOK(MyWriteBlock())
+    }
+    // _cachedSize != kCacheSize
+    // so we have some space for new data in cache
+    const size_t startPos = (size_t)_cachedPos & kCacheMask;
+    // we don't allow new data to overwrite old start data in cache.
+    if (startPos > pos)
+      size = (UInt32)MyMin((size_t)size, (size_t)(startPos - pos));
+    _cachedSize += size;
+  }
+  
+  memcpy(_cache + pos, data, size);
+  if (processedSize)
+    *processedSize = size;
+  _virtPos += size;
+  if (_virtSize < _virtPos)
+    _virtSize = _virtPos;
+  return WriteNonRestrictedBlocks();
+}
+
+
+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;
+  _virtSize = newSize;
+ 
+  if (newSize <= _cachedPos)
+  {
+    _cachedSize = 0;
+    _cachedPos = newSize;
+  }
+  else
+  {
+    // newSize > _cachedPos
+    const UInt64 offset = newSize - _cachedPos;
+    if (offset <= _cachedSize)
+    {
+      _cachedSize = (size_t)offset;
+      if (_phySize <= newSize)
+        return S_OK;
+    }
+    else
+    {
+      // newSize > _cachedPos + _cachedSize
+      // So we flush cache
+      RINOK(FlushCache())
+    }
+  }
+
+  if (newSize != _phySize)
+  {
+    if (!_stream)
+      return E_NOTIMPL;
+    _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 %u, %u\n", (unsigned)begin, (unsigned)end));
+  _restrict_begin = begin;
+  _restrict_end = end;
+  return WriteNonRestrictedBlocks();
+}
+
+
+
+HRESULT Update(
+    DECL_EXTERNAL_CODECS_LOC_VARS
+    const CObjectVector<CItemEx> &inputItems,
+    CObjectVector<CUpdateItem> &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<IStreamSetRestriction> setRestriction;
+  seqOutStream->QueryInterface(IID_IStreamSetRestriction, (void **)&setRestriction);
+  if (setRestriction)
+  {
+    RINOK(setRestriction->SetRestriction(0, 0))
+  }
+
+  CMyComPtr<IOutStream> outStream;
+  CCacheOutStream *cacheStream;
+  bool outSeqMode;
+
+  {
+    CMyComPtr<IOutStream> 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))
+      }
+    }
+
+    // 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();
+      setRestriction = cacheStream;
+    }
+    /*
+    else if (!outStreamReal)
+    {
+      CSeekOutStream *seekOutStream = new CSeekOutStream();
+      outStream = seekOutStream;
+      seekOutStream->Init(seqOutStream);
+    }
+    else
+      outStream = outStreamReal;
+    */
+    outSeqMode = (outStreamReal == NULL);
+  }
+
+  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
new file mode 100644
index 0000000..13ecd9c
--- /dev/null
+++ b/CPP/7zip/Archive/Zip/ZipUpdate.h
@@ -0,0 +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<CItemEx> &inputItems,
+    CObjectVector<CUpdateItem> &updateItems,
+    ISequentialOutStream *seqOutStream,
+    CInArchive *inArchive, bool removeSfx,
+    const CUpdateOptions &updateOptions,
+    const CCompressionMethodMode &compressionMethodMode,
+    IArchiveUpdateCallback *updateCallback);
+
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/makefile b/CPP/7zip/Archive/makefile
new file mode 100644
index 0000000..7512ad5
--- /dev/null
+++ b/CPP/7zip/Archive/makefile
@@ -0,0 +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"
diff --git a/CPP/7zip/Asm.mak b/CPP/7zip/Asm.mak
index 3ad238a..c4073e8 100644
--- a/CPP/7zip/Asm.mak
+++ b/CPP/7zip/Asm.mak
@@ -1,9 +1,9 @@
-!IFDEF ASM_OBJS

-!IF "$(CPU)" == "ARM"

-$(ASM_OBJS): ../../../../Asm/Arm/$(*B).asm

-	$(COMPL_ASM)

-!ELSEIF "$(CPU)" != "IA64" && "$(CPU)" != "MIPS" && "$(CPU)" != "ARM64"

-$(ASM_OBJS): ../../../../Asm/x86/$(*B).asm

-	$(COMPL_ASM)

-!ENDIF

-!ENDIF

+!IFDEF ASM_OBJS
+!IF "$(CPU)" == "ARM"
+$(ASM_OBJS): ../../../../Asm/Arm/$(*B).asm
+	$(COMPL_ASM)
+!ELSEIF "$(CPU)" != "IA64" && "$(CPU)" != "MIPS" && "$(CPU)" != "ARM64"
+$(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
new file mode 100644
index 0000000..65c81c4
--- /dev/null
+++ b/CPP/7zip/Bundles/Alone/Alone.dsp
@@ -0,0 +1,3234 @@
+# 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 /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
+# SUBTRACT CPP /WX
+# 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
+# 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\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\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
+# 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
+# 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
+# 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
+# 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
+# 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\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
+# End Group
+# End Target
+# End Project
diff --git a/CPP/7zip/Bundles/Alone/Alone.dsw b/CPP/7zip/Bundles/Alone/Alone.dsw
new file mode 100644
index 0000000..65eca43
--- /dev/null
+++ b/CPP/7zip/Bundles/Alone/Alone.dsw
@@ -0,0 +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>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/CPP/7zip/Bundles/Alone/StdAfx.cpp b/CPP/7zip/Bundles/Alone/StdAfx.cpp
new file mode 100644
index 0000000..d0feea8
--- /dev/null
+++ b/CPP/7zip/Bundles/Alone/StdAfx.cpp
@@ -0,0 +1,3 @@
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/CPP/7zip/Bundles/Alone/StdAfx.h b/CPP/7zip/Bundles/Alone/StdAfx.h
new file mode 100644
index 0000000..035267c
--- /dev/null
+++ b/CPP/7zip/Bundles/Alone/StdAfx.h
@@ -0,0 +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
diff --git a/CPP/7zip/Bundles/Alone/afxres.h b/CPP/7zip/Bundles/Alone/afxres.h
new file mode 100644
index 0000000..c2fadd4
--- /dev/null
+++ b/CPP/7zip/Bundles/Alone/afxres.h
@@ -0,0 +1 @@
+#include <winresrc.h>
diff --git a/CPP/7zip/Bundles/Alone/makefile b/CPP/7zip/Bundles/Alone/makefile
new file mode 100644
index 0000000..bad953a
--- /dev/null
+++ b/CPP/7zip/Bundles/Alone/makefile
@@ -0,0 +1,230 @@
+PROG = 7za.exe
+# 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\XzCrc64Init.obj \
+  $O\XzCrc64Reg.obj \
+  $O\Sha1Reg.obj \
+  $O\Sha256Reg.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 \
+
+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 \
+
+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\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 "../../Sha1.mak"
+!include "../../Sha256.mak"
+
+!include "../../7zip.mak"
diff --git a/CPP/7zip/Bundles/Alone/makefile.gcc b/CPP/7zip/Bundles/Alone/makefile.gcc
new file mode 100644
index 0000000..cb7e828
--- /dev/null
+++ b/CPP/7zip/Bundles/Alone/makefile.gcc
@@ -0,0 +1,348 @@
+PROG = 7za
+
+
+
+# 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/LzFindMt.o \
+  $O/StreamBinder.o \
+  $O/Synchronization.o \
+  $O/VirtThread.o \
+  $O/MemBlocks.o \
+  $O/OutMemStream.o \
+  $O/ProgressMt.o \
+  $O/Threads.o \
+
+endif
+
+
+
+LOCAL_FLAGS_SYS =
+
+ifdef IS_MINGW
+
+LOCAL_FLAGS_SYS = \
+  -DZ7_LARGE_PAGES \
+  -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_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/NewHandler.o \
+  $O/StdInStream.o \
+  $O/StdOutStream.o \
+  $O/Sha1Prepare.o \
+  $O/Sha1Reg.o \
+  $O/Sha256Prepare.o \
+  $O/Sha256Reg.o \
+  $O/StringConvert.o \
+  $O/StringToInt.o \
+  $O/UTFConvert.o \
+  $O/MyVector.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/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 \
+
+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 \
+
+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/7zStream.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/LzFindOpt.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/Sort.o \
+  $O/SwapBytes.o \
+  $O/Xz.o \
+  $O/XzDec.o \
+  $O/XzEnc.o \
+  $O/XzIn.o \
+  $O/XzCrc64.o \
+  $O/XzCrc64Opt.o \
+  $O/7zCrc.o \
+  $O/7zCrcOpt.o \
+  $O/Aes.o \
+  $O/AesOpt.o \
+  $O/Sha256.o \
+  $O/Sha256Opt.o \
+  $O/Sha1.o \
+  $O/Sha1Opt.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
new file mode 100644
index 0000000..c85acaa
--- /dev/null
+++ b/CPP/7zip/Bundles/Alone/resource.rc
@@ -0,0 +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
diff --git a/CPP/7zip/Bundles/Alone2/StdAfx.cpp b/CPP/7zip/Bundles/Alone2/StdAfx.cpp
new file mode 100644
index 0000000..d0feea8
--- /dev/null
+++ b/CPP/7zip/Bundles/Alone2/StdAfx.cpp
@@ -0,0 +1,3 @@
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/CPP/7zip/Bundles/Alone2/StdAfx.h b/CPP/7zip/Bundles/Alone2/StdAfx.h
new file mode 100644
index 0000000..035267c
--- /dev/null
+++ b/CPP/7zip/Bundles/Alone2/StdAfx.h
@@ -0,0 +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
diff --git a/CPP/7zip/Bundles/Alone2/makefile b/CPP/7zip/Bundles/Alone2/makefile
new file mode 100644
index 0000000..4cb7718
--- /dev/null
+++ b/CPP/7zip/Bundles/Alone2/makefile
@@ -0,0 +1,29 @@
+PROG = 7zz.exe
+# USE_C_AES = 1
+# USE_C_SHA = 1
+CFLAGS = $(CFLAGS) -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
new file mode 100644
index 0000000..f767b0d
--- /dev/null
+++ b/CPP/7zip/Bundles/Alone2/makefile.gcc
@@ -0,0 +1,109 @@
+PROG = 7zz
+
+# IS_X64 = 1
+# USE_ASM = 1
+# ST_MODE = 1
+
+CONSOLE_VARIANT_FLAGS=-DZ7_PROG_VARIANT_Z
+
+include ../Format7zF/Arc_gcc.mak
+
+ifdef SystemDrive
+IS_MINGW = 1
+else
+ifdef SYSTEMDRIVE
+# ifdef OS
+IS_MINGW = 1
+endif
+endif
+
+ifdef IS_MINGW
+
+LOCAL_FLAGS_SYS = \
+  -DZ7_LARGE_PAGES \
+  -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
new file mode 100644
index 0000000..af24c17
--- /dev/null
+++ b/CPP/7zip/Bundles/Alone2/resource.rc
@@ -0,0 +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
diff --git a/CPP/7zip/Bundles/Alone7z/Alone.dsp b/CPP/7zip/Bundles/Alone7z/Alone.dsp
index e12207d..ef4ec60 100644
--- a/CPP/7zip/Bundles/Alone7z/Alone.dsp
+++ b/CPP/7zip/Bundles/Alone7z/Alone.dsp
@@ -1,1910 +1,2043 @@
-# 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 /W3 /GX /O1 /I "..\..\..\\" /D "NDEBUG" /D "_MBCS" /D "WIN32" /D "_CONSOLE" /D "_7ZIP_LARGE_PAGES" /D "SUPPORT_DEVICE_FILE" /FAc /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 /W3 /Gm /GX /ZI /Od /I "..\..\..\\" /D "_DEBUG" /D "_MBCS" /D "WIN32" /D "_CONSOLE" /D "_7ZIP_LARGE_PAGES" /D "SUPPORT_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" /D "EXCLUDE_COM" /D "NO_REGISTRY" /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 "_7ZIP_LARGE_PAGES" /D "SUPPORT_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 "EXCLUDE_COM" /D "NO_REGISTRY" /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 "_7ZIP_LARGE_PAGES" /D "SUPPORT_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\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 "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\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\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\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\MyString.cpp

-# End Source File

-# Begin Source File

-

-SOURCE=..\..\..\Common\MyString.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\NewHandler.cpp

-# End Source File

-# Begin Source File

-

-SOURCE=..\..\..\Common\NewHandler.h

-# 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\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\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\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\ByteSwap.h

-# 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\EnumDirItems.cpp

-# End Source File

-# Begin Source File

-

-SOURCE=..\..\UI\Common\EnumDirItems.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=..\..\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 "C"

-

-# PROP Default_Filter ""

-# Begin Group "Xz"

-

-# PROP Default_Filter ""

-# 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\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\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

-# 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\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\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\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\Types.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\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\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\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\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\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\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\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
+# 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
+
+!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\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 036aab4..65eca43 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 c6d3b1f..d0feea8 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 59d9ac1..035267c 100644
--- a/CPP/7zip/Bundles/Alone7z/StdAfx.h
+++ b/CPP/7zip/Bundles/Alone7z/StdAfx.h
@@ -1,8 +1,11 @@
-// StdAfx.h

-

-#ifndef __STDAFX_H

-#define __STDAFX_H

-

-#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 4f23c10..1f857c5 100644
--- a/CPP/7zip/Bundles/Alone7z/makefile
+++ b/CPP/7zip/Bundles/Alone7z/makefile
@@ -1,154 +1,163 @@
-PROG = 7zr.exe

-CFLAGS = $(CFLAGS) \

-  -DPROG_VARIANT_R \

-

-COMMON_OBJS = \

-  $O\CommandLineParser.obj \

-  $O\CRC.obj \

-  $O\CrcReg.obj \

-  $O\IntToString.obj \

-  $O\ListFileUtils.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\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\InOutTempBuffer.obj \

-  $O\FilterCoder.obj \

-  $O\LimitedStreams.obj \

-  $O\MethodId.obj \

-  $O\MethodProps.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\Sha256.obj \

-  $O\Sort.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 "../../LzmaDec.mak"

-

-!include "../../7zip.mak"

+PROG = 7zr.exe
+
+# USE_C_AES = 1
+# USE_C_SHA = 1
+
+CFLAGS = $(CFLAGS) -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
new file mode 100644
index 0000000..6d92c19
--- /dev/null
+++ b/CPP/7zip/Bundles/Alone7z/makefile.gcc
@@ -0,0 +1,276 @@
+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/StreamBinder.o \
+  $O/VirtThread.o \
+  $O/Threads.o \
+
+
+
+endif
+
+
+
+LOCAL_FLAGS_SYS =
+
+ifdef IS_MINGW
+
+LOCAL_FLAGS_SYS = \
+  -DZ7_LARGE_PAGES \
+  -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_ST) \
+  $(LOCAL_FLAGS_SYS) \
+
+
+CONSOLE_OBJS = \
+  $O/BenchCon.o \
+  $O/ConsoleClose.o \
+  $O/DynLimBuf.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/IntToString.o \
+  $O/ListFileUtils.o \
+  $O/LzFindPrepare.o \
+  $O/MyString.o \
+  $O/MyVector.o \
+  $O/NewHandler.o \
+  $O/Sha256Prepare.o \
+  $O/Sha256Reg.o \
+  $O/StringConvert.o \
+  $O/StringToInt.o \
+  $O/StdInStream.o \
+  $O/StdOutStream.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/7zStream.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 \
+  $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) \
+
+include ../../7zip_gcc.mak
diff --git a/CPP/7zip/Bundles/Alone7z/resource.rc b/CPP/7zip/Bundles/Alone7z/resource.rc
index 36d70e7..5937850 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
new file mode 100644
index 0000000..402dd2c
--- /dev/null
+++ b/CPP/7zip/Bundles/Fm/FM.dsp
@@ -0,0 +1,2251 @@
+# 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\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\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
new file mode 100644
index 0000000..1c955d9
--- /dev/null
+++ b/CPP/7zip/Bundles/Fm/FM.dsw
@@ -0,0 +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>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/CPP/7zip/Bundles/Fm/StdAfx.cpp b/CPP/7zip/Bundles/Fm/StdAfx.cpp
new file mode 100644
index 0000000..d0feea8
--- /dev/null
+++ b/CPP/7zip/Bundles/Fm/StdAfx.cpp
@@ -0,0 +1,3 @@
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/CPP/7zip/Bundles/Fm/StdAfx.h b/CPP/7zip/Bundles/Fm/StdAfx.h
new file mode 100644
index 0000000..4f27255
--- /dev/null
+++ b/CPP/7zip/Bundles/Fm/StdAfx.h
@@ -0,0 +1,6 @@
+// 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
new file mode 100644
index 0000000..33b5320
--- /dev/null
+++ b/CPP/7zip/Bundles/Fm/makefile
@@ -0,0 +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"
diff --git a/CPP/7zip/Bundles/Fm/resource.rc b/CPP/7zip/Bundles/Fm/resource.rc
new file mode 100644
index 0000000..ebc2f74
--- /dev/null
+++ b/CPP/7zip/Bundles/Fm/resource.rc
@@ -0,0 +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
diff --git a/CPP/7zip/Bundles/Format7z/StdAfx.cpp b/CPP/7zip/Bundles/Format7z/StdAfx.cpp
new file mode 100644
index 0000000..d0feea8
--- /dev/null
+++ b/CPP/7zip/Bundles/Format7z/StdAfx.cpp
@@ -0,0 +1,3 @@
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/CPP/7zip/Bundles/Format7z/StdAfx.h b/CPP/7zip/Bundles/Format7z/StdAfx.h
new file mode 100644
index 0000000..035267c
--- /dev/null
+++ b/CPP/7zip/Bundles/Format7z/StdAfx.h
@@ -0,0 +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
diff --git a/CPP/7zip/Bundles/Format7z/makefile b/CPP/7zip/Bundles/Format7z/makefile
new file mode 100644
index 0000000..d20a3c1
--- /dev/null
+++ b/CPP/7zip/Bundles/Format7z/makefile
@@ -0,0 +1,147 @@
+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 \
+
+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
new file mode 100644
index 0000000..2f2b42a
--- /dev/null
+++ b/CPP/7zip/Bundles/Format7z/resource.rc
@@ -0,0 +1,5 @@
+#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
new file mode 100644
index 0000000..d0feea8
--- /dev/null
+++ b/CPP/7zip/Bundles/Format7zExtract/StdAfx.cpp
@@ -0,0 +1,3 @@
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/CPP/7zip/Bundles/Format7zExtract/StdAfx.h b/CPP/7zip/Bundles/Format7zExtract/StdAfx.h
new file mode 100644
index 0000000..035267c
--- /dev/null
+++ b/CPP/7zip/Bundles/Format7zExtract/StdAfx.h
@@ -0,0 +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
diff --git a/CPP/7zip/Bundles/Format7zExtract/makefile b/CPP/7zip/Bundles/Format7zExtract/makefile
new file mode 100644
index 0000000..4e2ed3e
--- /dev/null
+++ b/CPP/7zip/Bundles/Format7zExtract/makefile
@@ -0,0 +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"
diff --git a/CPP/7zip/Bundles/Format7zExtract/resource.rc b/CPP/7zip/Bundles/Format7zExtract/resource.rc
new file mode 100644
index 0000000..6a65461
--- /dev/null
+++ b/CPP/7zip/Bundles/Format7zExtract/resource.rc
@@ -0,0 +1,5 @@
+#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 c6d3b1f..d0feea8 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 59d9ac1..035267c 100644
--- a/CPP/7zip/Bundles/Format7zExtractR/StdAfx.h
+++ b/CPP/7zip/Bundles/Format7zExtractR/StdAfx.h
@@ -1,8 +1,11 @@
-// StdAfx.h

-

-#ifndef __STDAFX_H

-#define __STDAFX_H

-

-#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 3a7f981..50b84d8 100644
--- a/CPP/7zip/Bundles/Format7zExtractR/makefile
+++ b/CPP/7zip/Bundles/Format7zExtractR/makefile
@@ -1,96 +1,98 @@
-PROG = 7zxr.dll

-DEF_FILE = ../../Archive/Archive2.def

-CFLAGS = $(CFLAGS) \

-  -DEXTRACT_ONLY \

-  -D_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\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\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 dac02a6..149f58c 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
new file mode 100644
index 0000000..37b400e
--- /dev/null
+++ b/CPP/7zip/Bundles/Format7zF/Arc.mak
@@ -0,0 +1,297 @@
+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\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 \
+
+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 \
+
+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\Xz.obj \
+  $O\XzDec.obj \
+  $O\XzEnc.obj \
+  $O\XzIn.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
new file mode 100644
index 0000000..404d917
--- /dev/null
+++ b/CPP/7zip/Bundles/Format7zF/Arc_gcc.mak
@@ -0,0 +1,379 @@
+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/StreamBinder.o \
+  $O/Synchronization.o \
+  $O/VirtThread.o \
+  $O/MemBlocks.o \
+  $O/OutMemStream.o \
+  $O/ProgressMt.o \
+  $O/Threads.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/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 \
+
+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 \
+
+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/7zStream.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/Sort.o \
+  $O/Xz.o \
+  $O/XzDec.o \
+  $O/XzEnc.o \
+  $O/XzIn.o \
+  $O/XzCrc64.o \
+  $O/XzCrc64Opt.o \
+  $O/7zCrc.o \
+  $O/7zCrcOpt.o \
+  $O/Aes.o \
+  $O/AesOpt.o \
+  $O/Sha256.o \
+  $O/Sha256Opt.o \
+  $O/Sha1.o \
+  $O/Sha1Opt.o \
+  $O/SwapBytes.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
new file mode 100644
index 0000000..a0c5d83
--- /dev/null
+++ b/CPP/7zip/Bundles/Format7zF/Format7z.dsp
@@ -0,0 +1,3266 @@
+# 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
+# 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\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\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\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
+# 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
+# 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
+# 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
new file mode 100644
index 0000000..324dab1
--- /dev/null
+++ b/CPP/7zip/Bundles/Format7zF/Format7z.dsw
@@ -0,0 +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>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/CPP/7zip/Bundles/Format7zF/StdAfx.cpp b/CPP/7zip/Bundles/Format7zF/StdAfx.cpp
new file mode 100644
index 0000000..d0feea8
--- /dev/null
+++ b/CPP/7zip/Bundles/Format7zF/StdAfx.cpp
@@ -0,0 +1,3 @@
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/CPP/7zip/Bundles/Format7zF/StdAfx.h b/CPP/7zip/Bundles/Format7zF/StdAfx.h
new file mode 100644
index 0000000..035267c
--- /dev/null
+++ b/CPP/7zip/Bundles/Format7zF/StdAfx.h
@@ -0,0 +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
diff --git a/CPP/7zip/Bundles/Format7zF/makefile b/CPP/7zip/Bundles/Format7zF/makefile
new file mode 100644
index 0000000..3487596
--- /dev/null
+++ b/CPP/7zip/Bundles/Format7zF/makefile
@@ -0,0 +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"
diff --git a/CPP/7zip/Bundles/Format7zF/makefile.gcc b/CPP/7zip/Bundles/Format7zF/makefile.gcc
new file mode 100644
index 0000000..fc65795
--- /dev/null
+++ b/CPP/7zip/Bundles/Format7zF/makefile.gcc
@@ -0,0 +1,55 @@
+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
+
+
+ifdef IS_MINGW
+
+LOCAL_FLAGS_WIN = \
+  -DZ7_LARGE_PAGES \
+  $(LOCAL_FLAGS_ST) \
+
+SYS_OBJS = \
+  $O/resource.o \
+
+else
+
+SYS_OBJS = \
+  $O/MyWindows.o \
+
+endif
+
+LOCAL_FLAGS = \
+  -DZ7_EXTERNAL_CODECS \
+  $(LOCAL_FLAGS_WIN) \
+  $(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
new file mode 100644
index 0000000..9c797c1
--- /dev/null
+++ b/CPP/7zip/Bundles/Format7zF/resource.rc
@@ -0,0 +1,38 @@
+#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"
+
+
+
+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 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 c6d3b1f..d0feea8 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 59d9ac1..035267c 100644
--- a/CPP/7zip/Bundles/Format7zR/StdAfx.h
+++ b/CPP/7zip/Bundles/Format7zR/StdAfx.h
@@ -1,8 +1,11 @@
-// StdAfx.h

-

-#ifndef __STDAFX_H

-#define __STDAFX_H

-

-#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 6a9dfb9..2449755 100644
--- a/CPP/7zip/Bundles/Format7zR/makefile
+++ b/CPP/7zip/Bundles/Format7zR/makefile
@@ -1,116 +1,120 @@
-PROG = 7zra.dll

-DEF_FILE = ../../Archive/Archive2.def

-CFLAGS = $(CFLAGS) \

-  -D_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\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\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\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\Threads.obj \

-

-!include "../../Crc.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 \
+
+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 262125c..a8baa59 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 f273337..ac1334f 100644
--- a/CPP/7zip/Bundles/LzmaCon/LzmaAlone.cpp
+++ b/CPP/7zip/Bundles/LzmaCon/LzmaAlone.cpp
@@ -1,799 +1,808 @@
-// LzmaAlone.cpp

-

-#include "StdAfx.h"

-

-#include <stdio.h>

-

-#include "../../../../C/CpuArch.h"

-

-#if (defined(_WIN32) || defined(OS2) || defined(MSDOS)) && !defined(UNDER_CE)

-#include <fcntl.h>

-#include <io.h>

-#define MY_SET_BINARY_MODE(file) _setmode(_fileno(file), O_BINARY)

-#else

-#define MY_SET_BINARY_MODE(file)

-#endif

-

-#include "../../../Common/MyWindows.h"

-#include "../../../Common/MyInitGuid.h"

-

-#include "../../../../C/7zVersion.h"

-#include "../../../../C/Alloc.h"

-#include "../../../../C/Lzma86.h"

-

-#include "../../../Windows/NtCheck.h"

-

-#ifndef _7ZIP_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"

-

-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 <command> [inputFile] [outputFile] [<switches>...]\n"

-    "\n"

-    "<command>\n"

-    "  e : Encode file\n"

-    "  d : Decode file\n"

-    "  b : Benchmark\n"

-    "<switches>\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 = "Can not 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

-};

-}

-

-static const CSwitchForm kSwitchForms[] =

-{

-  { "?",  NSwitchType::kSimple, false },

-  { "H",  NSwitchType::kSimple, false },

-  { "MM", NSwitchType::kString, false, 1 },

-  { "X", NSwitchType::kString, false, 1 },

-  { "A", NSwitchType::kString, false, 1 },

-  { "D", NSwitchType::kString, false, 1 },

-  { "FB", NSwitchType::kString, false, 1 },

-  { "MC", NSwitchType::kString, false, 1 },

-  { "LC", NSwitchType::kString, false, 1 },

-  { "LP", NSwitchType::kString, false, 1 },

-  { "PB", NSwitchType::kString, false, 1 },

-  { "MF", NSwitchType::kString, false, 1 },

-  { "MT", NSwitchType::kString, false, 0 },

-  { "EOS", NSwitchType::kSimple, false },

-  { "SI",  NSwitchType::kSimple, false },

-  { "SO",  NSwitchType::kSimple, false },

-  { "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);

-}

-

-class CProgressPrint:

-  public ICompressProgressInfo,

-  public CMyUnknownImp

-{

-  UInt64 _size1;

-  UInt64 _size2;

-public:

-  CProgressPrint(): _size1(0), _size2(0) {}

-

-  void ClosePrint();

-

-  MY_UNKNOWN_IMP1(ICompressProgressInfo)

-

-  STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);

-};

-

-#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);

-}

-

-STDMETHODIMP 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;

-}

-

-

-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(res, temp);

-    PrintErr("Error code = 0x");

-    PrintErr_LF(temp);

-  }

-  return 1;

-}

-

-#define NT_CHECK_FAIL_ACTION PrintError("Unsupported Windows version"); return 1;

-

-static void AddProp(CObjectVector<CProperty> &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, 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 &params = parser.NonSwitchStrings;

-

-  unsigned paramIndex = 0;

-  if (paramIndex >= params.Size())

-    IncorrectCommand();

-  const UString &command = params[paramIndex++];

-

-  CObjectVector<CProperty> 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 _7ZIP_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<ISequentialInStream> 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("can not open input file", inputName);

-      return 1;

-    }

-  }

-

-  CMyComPtr<ISequentialOutStream> 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(us2fs(outputName), true))

-    {

-      PrintError2("can not open output file", outputName);

-      return 1;

-    }

-  }

-

-  bool fileSizeDefined = false;

-  UInt64 fileSize = 0;

-  

-  if (inStreamSpec)

-  {

-    if (!inStreamSpec->File.GetLength(fileSize))

-      throw "Can not 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 "Can not 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 "Can not 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<ICompressProgressInfo> progress;

-

-  if (!stdOutMode)

-  {

-    progressSpec = new CProgressPrint;

-    progress = progressSpec;

-  }

-

-  if (encodeMode)

-  {

-    NCompress::NLzma::CEncoder *encoderSpec = new NCompress::NLzma::CEncoder;

-    CMyComPtr<ICompressCoder> 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 = 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<BSTR>((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<ICompressCoder> 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 (int 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 MY_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 <stdio.h>
+
+#if (defined(_WIN32) || defined(OS2) || defined(MSDOS)) && !defined(UNDER_CE)
+#include <fcntl.h>
+#include <io.h>
+#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 <command> [inputFile] [outputFile] [<switches>...]\n"
+    "\n"
+    "<command>\n"
+    "  e : Encode file\n"
+    "  d : Decode file\n"
+    "  b : Benchmark\n"
+    "<switches>\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<CProperty> &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 &params = parser.NonSwitchStrings;
+
+  unsigned paramIndex = 0;
+  if (paramIndex >= params.Size())
+    IncorrectCommand();
+  const UString &command = params[paramIndex++];
+
+  CObjectVector<CProperty> 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<ISequentialInStream> 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<ISequentialOutStream> 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(us2fs(outputName), true))
+    {
+      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<ICompressProgressInfo> progress;
+
+  if (!stdOutMode)
+  {
+    progressSpec = new CProgressPrint;
+    progress = progressSpec;
+  }
+
+  if (encodeMode)
+  {
+    NCompress::NLzma::CEncoder *encoderSpec = new NCompress::NLzma::CEncoder;
+    CMyComPtr<ICompressCoder> 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<BSTR>((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<ICompressCoder> 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 bdc0c3e..5a8911b 100644
--- a/CPP/7zip/Bundles/LzmaCon/LzmaCon.dsp
+++ b/CPP/7zip/Bundles/LzmaCon/LzmaCon.dsp
@@ -1,477 +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 "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:"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 "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:"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\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 "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\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\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\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

-# 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\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

-# Begin Source File

-

-SOURCE=..\..\UI\Common\LoadCodecs.cpp

-# End Source File

-# Begin Source File

-

-SOURCE=..\..\UI\Common\LoadCodecs.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\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\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\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\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 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 "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:"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 "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:"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 c6a6662..e62c9d2 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 c6d3b1f..d0feea8 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 59d9ac1..035267c 100644
--- a/CPP/7zip/Bundles/LzmaCon/StdAfx.h
+++ b/CPP/7zip/Bundles/LzmaCon/StdAfx.h
@@ -1,8 +1,11 @@
-// StdAfx.h

-

-#ifndef __STDAFX_H

-#define __STDAFX_H

-

-#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 5a50808..f303c31 100644
--- a/CPP/7zip/Bundles/LzmaCon/makefile
+++ b/CPP/7zip/Bundles/LzmaCon/makefile
@@ -1,59 +1,67 @@
-PROG = lzma.exe

-MY_CONSOLE = 1

-

-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\MyString.obj \

-  $O\NewHandler.obj \

-  $O\StringConvert.obj \

-  $O\StringToInt.obj \

-  $O\MyVector.obj

-

-WIN_OBJS = \

-  $O\FileIO.obj \

-  $O\PropVariant.obj \

-  $O\System.obj

-

-7ZIP_COMMON_OBJS = \

-  $O\CWrappers.obj \

-  $O\CreateCoder.obj \

-  $O\FileStreams.obj \

-  $O\FilterCoder.obj \

-  $O\MethodProps.obj \

-  $O\OutBuffer.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 "../../LzmaDec.mak"

-

-!include "../../7zip.mak"

+PROG = lzma.exe
+MY_CONSOLE = 1
+
+# 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 3fb5ec2..dd19a0e 100644
--- a/CPP/7zip/Bundles/LzmaCon/makefile.gcc
+++ b/CPP/7zip/Bundles/LzmaCon/makefile.gcc
@@ -1,195 +1,126 @@
-PROG = lzma

-CXX = g++ -O2

-# -Wall -Werror -Wno-delete-non-virtual-dtor

-CXX_C = gcc -O2 -Wall -Werror

-

-ifdef SystemDrive

-IS_MINGW = 1

-endif

-

-ifdef IS_MINGW

-

-RM = del

-CFLAGS = -c

-LIB2 = -loleaut32 -luuid

-LDFLAGS = -s

-

-FILE_IO =FileIO

-FILE_IO_2 =Windows/$(FILE_IO)

-

-MT_FILES = \

-  LzFindMt.o \

-  Threads.o \

-

-else

-

-RM = rm -f

-CFLAGS = -c -D_7ZIP_ST

-

-FILE_IO =C_FileIO

-FILE_IO_2 =Common/$(FILE_IO)

-

-

-endif

-

-

-OBJS = \

-  $(MT_FILES) \

-  $(FILE_IO).o \

-  LzmaAlone.o \

-  Bench.o \

-  BenchCon.o \

-  ConsoleClose.o \

-  LzmaDecoder.o \

-  LzmaEncoder.o \

-  LzmaRegister.o \

-  CreateCoder.o \

-  CWrappers.o \

-  FileStreams.o \

-  FilterCoder.o \

-  MethodProps.o \

-  StreamUtils.o \

-  CommandLineParser.o \

-  CRC.o \

-  CrcReg.o \

-  IntToString.o \

-  MyString.o \

-  MyVector.o \

-  MyWindows.o \

-  StringConvert.o \

-  StringToInt.o \

-  PropVariant.o \

-  System.o \

-  7zCrc.o \

-  7zCrcOpt.o \

-  Alloc.o \

-  Bra86.o \

-  CpuArch.o \

-  LzFind.o \

-  LzmaDec.o \

-  LzmaEnc.o \

-  Lzma86Dec.o \

-  Lzma86Enc.o \

-

-

-all: $(PROG)

-

-$(PROG): $(OBJS)

-	$(CXX) -o $(PROG) $(LDFLAGS) $(OBJS) $(LIB2)

-

-LzmaAlone.o: LzmaAlone.cpp

-	$(CXX) $(CFLAGS) LzmaAlone.cpp

-

-Bench.o: ../../UI/Common/Bench.cpp

-	$(CXX) $(CFLAGS) ../../UI/Common/Bench.cpp

-

-BenchCon.o: ../../UI/Console/BenchCon.cpp

-	$(CXX) $(CFLAGS) ../../UI/Console/BenchCon.cpp

-

-ConsoleClose.o: ../../UI/Console/ConsoleClose.cpp

-	$(CXX) $(CFLAGS) ../../UI/Console/ConsoleClose.cpp

-

-LzmaDecoder.o: ../../Compress/LzmaDecoder.cpp

-	$(CXX) $(CFLAGS) ../../Compress/LzmaDecoder.cpp

-

-LzmaEncoder.o: ../../Compress/LzmaEncoder.cpp

-	$(CXX) $(CFLAGS) ../../Compress/LzmaEncoder.cpp

-

-LzmaRegister.o: ../../Compress/LzmaRegister.cpp

-	$(CXX) $(CFLAGS) ../../Compress/LzmaRegister.cpp

-

-CreateCoder.o: ../../Common/CreateCoder.cpp

-	$(CXX) $(CFLAGS) ../../Common/CreateCoder.cpp

-

-CWrappers.o: ../../Common/CWrappers.cpp

-	$(CXX) $(CFLAGS) ../../Common/CWrappers.cpp

-

-FileStreams.o: ../../Common/FileStreams.cpp

-	$(CXX) $(CFLAGS) ../../Common/FileStreams.cpp

-

-FilterCoder.o: ../../Common/FilterCoder.cpp

-	$(CXX) $(CFLAGS) ../../Common/FilterCoder.cpp

-

-MethodProps.o: ../../Common/MethodProps.cpp

-	$(CXX) $(CFLAGS) ../../Common/MethodProps.cpp

-

-StreamUtils.o: ../../Common/StreamUtils.cpp

-	$(CXX) $(CFLAGS) ../../Common/StreamUtils.cpp

-

-$(FILE_IO).o: ../../../$(FILE_IO_2).cpp

-	$(CXX) $(CFLAGS) ../../../$(FILE_IO_2).cpp

-

-

-CommandLineParser.o: ../../../Common/CommandLineParser.cpp

-	$(CXX) $(CFLAGS) ../../../Common/CommandLineParser.cpp

-

-CRC.o: ../../../Common/CRC.cpp

-	$(CXX) $(CFLAGS) ../../../Common/CRC.cpp

-

-CrcReg.o: ../../../Common/CrcReg.cpp

-	$(CXX) $(CFLAGS) ../../../Common/CrcReg.cpp

-

-IntToString.o: ../../../Common/IntToString.cpp

-	$(CXX) $(CFLAGS) ../../../Common/IntToString.cpp

-

-MyString.o: ../../../Common/MyString.cpp

-	$(CXX) $(CFLAGS) ../../../Common/MyString.cpp

-

-MyVector.o: ../../../Common/MyVector.cpp

-	$(CXX) $(CFLAGS) ../../../Common/MyVector.cpp

-

-MyWindows.o: ../../../Common/MyWindows.cpp

-	$(CXX) $(CFLAGS) ../../../Common/MyWindows.cpp

-

-StringConvert.o: ../../../Common/StringConvert.cpp

-	$(CXX) $(CFLAGS) ../../../Common/StringConvert.cpp

-

-StringToInt.o: ../../../Common/StringToInt.cpp

-	$(CXX) $(CFLAGS) ../../../Common/StringToInt.cpp

-

-PropVariant.o: ../../../Windows/PropVariant.cpp

-	$(CXX) $(CFLAGS) ../../../Windows/PropVariant.cpp

-

-System.o: ../../../Windows/System.cpp

-	$(CXX) $(CFLAGS) ../../../Windows/System.cpp

-

-7zCrc.o: ../../../../C/7zCrc.c

-	$(CXX_C) $(CFLAGS) ../../../../C/7zCrc.c

-

-7zCrcOpt.o: ../../../../C/7zCrcOpt.c

-	$(CXX_C) $(CFLAGS) ../../../../C/7zCrcOpt.c

-

-Alloc.o: ../../../../C/Alloc.c

-	$(CXX_C) $(CFLAGS) ../../../../C/Alloc.c

-

-Bra86.o: ../../../../C/Bra86.c

-	$(CXX_C) $(CFLAGS) ../../../../C/Bra86.c

-

-CpuArch.o: ../../../../C/CpuArch.c

-	$(CXX_C) $(CFLAGS) ../../../../C/CpuArch.c

-

-LzFind.o: ../../../../C/LzFind.c

-	$(CXX_C) $(CFLAGS) ../../../../C/LzFind.c

-

-ifdef MT_FILES

-LzFindMt.o: ../../../../C/LzFindMt.c

-	$(CXX_C) $(CFLAGS) ../../../../C/LzFindMt.c

-

-Threads.o: ../../../../C/Threads.c

-	$(CXX_C) $(CFLAGS) ../../../../C/Threads.c

-endif

-

-LzmaDec.o: ../../../../C/LzmaDec.c

-	$(CXX_C) $(CFLAGS) ../../../../C/LzmaDec.c

-

-LzmaEnc.o: ../../../../C/LzmaEnc.c

-	$(CXX_C) $(CFLAGS) ../../../../C/LzmaEnc.c

-

-Lzma86Dec.o: ../../../../C/Lzma86Dec.c

-	$(CXX_C) $(CFLAGS) ../../../../C/Lzma86Dec.c

-

-Lzma86Enc.o: ../../../../C/Lzma86Enc.c

-	$(CXX_C) $(CFLAGS) ../../../../C/Lzma86Enc.c

-

-clean:

-	-$(RM) $(PROG) $(OBJS)

+PROG = lzma
+
+# 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
+
+else
+
+MT_OBJS = \
+  $O/LzFindMt.o \
+  $O/LzFindOpt.o \
+  $O/Synchronization.o \
+  $O/Threads.o \
+
+
+
+endif
+
+
+
+LOCAL_FLAGS_SYS =
+
+ifdef IS_MINGW
+
+SYS_OBJS = \
+  $O/Registry.o \
+  $O/resource.o \
+
+else
+
+SYS_OBJS = \
+  $O/FileDir.o \
+  $O/FileFind.o \
+  $O/FileName.o \
+  $O/MyWindows.o \
+  $O/TimeUtils.o \
+
+endif
+
+LOCAL_FLAGS = \
+  $(LOCAL_FLAGS_ST) \
+
+
+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 9b54fa8..43b5073 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/LzmaSpec/LzmaSpec.cpp b/CPP/7zip/Bundles/LzmaSpec/LzmaSpec.cpp
deleted file mode 100644
index 67e8dfc..0000000
--- a/CPP/7zip/Bundles/LzmaSpec/LzmaSpec.cpp
+++ /dev/null
@@ -1,715 +0,0 @@
-/* LzmaSpec.cpp -- LZMA Reference Decoder

-2015-06-14 : Igor Pavlov : Public domain */

-

-// This code implements LZMA file decoding according to LZMA specification.

-// This code is not optimized for speed.

-

-#include <stdio.h>

-

-#ifdef _MSC_VER

-  #pragma warning(disable : 4710) // function not inlined

-  #pragma warning(disable : 4996) // This function or variable may be unsafe

-#endif

-

-typedef unsigned char Byte;

-typedef unsigned short UInt16;

-

-#ifdef _LZMA_UINT32_IS_ULONG

-  typedef unsigned long UInt32;

-#else

-  typedef unsigned int UInt32;

-#endif

-

-#if defined(_MSC_VER) || defined(__BORLANDC__)

-  typedef unsigned __int64 UInt64;

-#else

-  typedef unsigned long long int UInt64;

-#endif

-

-

-struct CInputStream

-{

-  FILE *File;

-  UInt64 Processed;

-  

-  void Init() { Processed = 0; }

-

-  Byte ReadByte()

-  {

-    int c = getc(File);

-    if (c < 0)

-      throw "Unexpected end of file";

-    Processed++;

-    return (Byte)c;

-  }

-};

-

-

-struct COutStream

-{

-  FILE *File;

-  UInt64 Processed;

-

-  void Init() { Processed = 0; }

-

-  void WriteByte(Byte b)

-  {

-    if (putc(b, File) == EOF)

-      throw "File writing error";

-    Processed++;

-  }

-};

-

-

-class COutWindow

-{

-  Byte *Buf;

-  UInt32 Pos;

-  UInt32 Size;

-  bool IsFull;

-

-public:

-  unsigned TotalPos;

-  COutStream OutStream;

-

-  COutWindow(): Buf(NULL) {}

-  ~COutWindow() { delete []Buf; }

- 

-  void Create(UInt32 dictSize)

-  {

-    Buf = new Byte[dictSize];

-    Pos = 0;

-    Size = dictSize;

-    IsFull = false;

-    TotalPos = 0;

-  }

-

-  void PutByte(Byte b)

-  {

-    TotalPos++;

-    Buf[Pos++] = b;

-    if (Pos == Size)

-    {

-      Pos = 0;

-      IsFull = true;

-    }

-    OutStream.WriteByte(b);

-  }

-

-  Byte GetByte(UInt32 dist) const

-  {

-    return Buf[dist <= Pos ? Pos - dist : Size - dist + Pos];

-  }

-

-  void CopyMatch(UInt32 dist, unsigned len)

-  {

-    for (; len > 0; len--)

-      PutByte(GetByte(dist));

-  }

-

-  bool CheckDistance(UInt32 dist) const

-  {

-    return dist <= Pos || IsFull;

-  }

-

-  bool IsEmpty() const

-  {

-    return Pos == 0 && !IsFull;

-  }

-};

-

-

-#define kNumBitModelTotalBits 11

-#define kNumMoveBits 5

-

-typedef UInt16 CProb;

-

-#define PROB_INIT_VAL ((1 << kNumBitModelTotalBits) / 2)

-

-#define INIT_PROBS(p) \

- { for (unsigned i = 0; i < sizeof(p) / sizeof(p[0]); i++) p[i] = PROB_INIT_VAL; }

-

-class CRangeDecoder

-{

-  UInt32 Range;

-  UInt32 Code;

-

-  void Normalize();

-

-public:

-

-  CInputStream *InStream;

-  bool Corrupted;

-

-  bool Init();

-  bool IsFinishedOK() const { return Code == 0; }

-

-  UInt32 DecodeDirectBits(unsigned numBits);

-  unsigned DecodeBit(CProb *prob);

-};

-

-bool CRangeDecoder::Init()

-{

-  Corrupted = false;

-  Range = 0xFFFFFFFF;

-  Code = 0;

-

-  Byte b = InStream->ReadByte();

-  

-  for (int i = 0; i < 4; i++)

-    Code = (Code << 8) | InStream->ReadByte();

-  

-  if (b != 0 || Code == Range)

-    Corrupted = true;

-  return b == 0;

-}

-

-#define kTopValue ((UInt32)1 << 24)

-

-void CRangeDecoder::Normalize()

-{

-  if (Range < kTopValue)

-  {

-    Range <<= 8;

-    Code = (Code << 8) | InStream->ReadByte();

-  }

-}

-

-UInt32 CRangeDecoder::DecodeDirectBits(unsigned numBits)

-{

-  UInt32 res = 0;

-  do

-  {

-    Range >>= 1;

-    Code -= Range;

-    UInt32 t = 0 - ((UInt32)Code >> 31);

-    Code += Range & t;

-    

-    if (Code == Range)

-      Corrupted = true;

-    

-    Normalize();

-    res <<= 1;

-    res += t + 1;

-  }

-  while (--numBits);

-  return res;

-}

-

-unsigned CRangeDecoder::DecodeBit(CProb *prob)

-{

-  unsigned v = *prob;

-  UInt32 bound = (Range >> kNumBitModelTotalBits) * v;

-  unsigned symbol;

-  if (Code < bound)

-  {

-    v += ((1 << kNumBitModelTotalBits) - v) >> kNumMoveBits;

-    Range = bound;

-    symbol = 0;

-  }

-  else

-  {

-    v -= v >> kNumMoveBits;

-    Code -= bound;

-    Range -= bound;

-    symbol = 1;

-  }

-  *prob = (CProb)v;

-  Normalize();

-  return symbol;

-}

-

-

-unsigned BitTreeReverseDecode(CProb *probs, unsigned numBits, CRangeDecoder *rc)

-{

-  unsigned m = 1;

-  unsigned symbol = 0;

-  for (unsigned i = 0; i < numBits; i++)

-  {

-    unsigned bit = rc->DecodeBit(&probs[m]);

-    m <<= 1;

-    m += bit;

-    symbol |= (bit << i);

-  }

-  return symbol;

-}

-

-template <unsigned NumBits>

-class CBitTreeDecoder

-{

-  CProb Probs[(unsigned)1 << NumBits];

-

-public:

-

-  void Init()

-  {

-    INIT_PROBS(Probs);

-  }

-

-  unsigned Decode(CRangeDecoder *rc)

-  {

-    unsigned m = 1;

-    for (unsigned i = 0; i < NumBits; i++)

-      m = (m << 1) + rc->DecodeBit(&Probs[m]);

-    return m - ((unsigned)1 << NumBits);

-  }

-

-  unsigned ReverseDecode(CRangeDecoder *rc)

-  {

-    return BitTreeReverseDecode(Probs, NumBits, rc);

-  }

-};

-

-#define kNumPosBitsMax 4

-

-#define kNumStates 12

-#define kNumLenToPosStates 4

-#define kNumAlignBits 4

-#define kStartPosModelIndex 4

-#define kEndPosModelIndex 14

-#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))

-#define kMatchMinLen 2

-

-class CLenDecoder

-{

-  CProb Choice;

-  CProb Choice2;

-  CBitTreeDecoder<3> LowCoder[1 << kNumPosBitsMax];

-  CBitTreeDecoder<3> MidCoder[1 << kNumPosBitsMax];

-  CBitTreeDecoder<8> HighCoder;

-

-public:

-

-  void Init()

-  {

-    Choice = PROB_INIT_VAL;

-    Choice2 = PROB_INIT_VAL;

-    HighCoder.Init();

-    for (unsigned i = 0; i < (1 << kNumPosBitsMax); i++)

-    {

-      LowCoder[i].Init();

-      MidCoder[i].Init();

-    }

-  }

-

-  unsigned Decode(CRangeDecoder *rc, unsigned posState)

-  {

-    if (rc->DecodeBit(&Choice) == 0)

-      return LowCoder[posState].Decode(rc);

-    if (rc->DecodeBit(&Choice2) == 0)

-      return 8 + MidCoder[posState].Decode(rc);

-    return 16 + HighCoder.Decode(rc);

-  }

-};

-

-unsigned UpdateState_Literal(unsigned state)

-{

-  if (state < 4) return 0;

-  else if (state < 10) return state - 3;

-  else return state - 6;

-}

-unsigned UpdateState_Match   (unsigned state) { return state < 7 ? 7 : 10; }

-unsigned UpdateState_Rep     (unsigned state) { return state < 7 ? 8 : 11; }

-unsigned UpdateState_ShortRep(unsigned state) { return state < 7 ? 9 : 11; }

-

-#define LZMA_DIC_MIN (1 << 12)

-

-class CLzmaDecoder

-{

-public:

-  CRangeDecoder RangeDec;

-  COutWindow OutWindow;

-

-  bool markerIsMandatory;

-  unsigned lc, pb, lp;

-  UInt32 dictSize;

-  UInt32 dictSizeInProperties;

-

-  void DecodeProperties(const Byte *properties)

-  {

-    unsigned d = properties[0];

-    if (d >= (9 * 5 * 5))

-      throw "Incorrect LZMA properties";

-    lc = d % 9;

-    d /= 9;

-    pb = d / 5;

-    lp = d % 5;

-    dictSizeInProperties = 0;

-    for (int i = 0; i < 4; i++)

-      dictSizeInProperties |= (UInt32)properties[i + 1] << (8 * i);

-    dictSize = dictSizeInProperties;

-    if (dictSize < LZMA_DIC_MIN)

-      dictSize = LZMA_DIC_MIN;

-  }

-

-  CLzmaDecoder(): LitProbs(NULL) {}

-  ~CLzmaDecoder() { delete []LitProbs; }

-

-  void Create()

-  {

-    OutWindow.Create(dictSize);

-    CreateLiterals();

-  }

-

-  int Decode(bool unpackSizeDefined, UInt64 unpackSize);

-  

-private:

-

-  CProb *LitProbs;

-

-  void CreateLiterals()

-  {

-    LitProbs = new CProb[(UInt32)0x300 << (lc + lp)];

-  }

-  

-  void InitLiterals()

-  {

-    UInt32 num = (UInt32)0x300 << (lc + lp);

-    for (UInt32 i = 0; i < num; i++)

-      LitProbs[i] = PROB_INIT_VAL;

-  }

-  

-  void DecodeLiteral(unsigned state, UInt32 rep0)

-  {

-    unsigned prevByte = 0;

-    if (!OutWindow.IsEmpty())

-      prevByte = OutWindow.GetByte(1);

-    

-    unsigned symbol = 1;

-    unsigned litState = ((OutWindow.TotalPos & ((1 << lp) - 1)) << lc) + (prevByte >> (8 - lc));

-    CProb *probs = &LitProbs[(UInt32)0x300 * litState];

-    

-    if (state >= 7)

-    {

-      unsigned matchByte = OutWindow.GetByte(rep0 + 1);

-      do

-      {

-        unsigned matchBit = (matchByte >> 7) & 1;

-        matchByte <<= 1;

-        unsigned bit = RangeDec.DecodeBit(&probs[((1 + matchBit) << 8) + symbol]);

-        symbol = (symbol << 1) | bit;

-        if (matchBit != bit)

-          break;

-      }

-      while (symbol < 0x100);

-    }

-    while (symbol < 0x100)

-      symbol = (symbol << 1) | RangeDec.DecodeBit(&probs[symbol]);

-    OutWindow.PutByte((Byte)(symbol - 0x100));

-  }

-

-  CBitTreeDecoder<6> PosSlotDecoder[kNumLenToPosStates];

-  CBitTreeDecoder<kNumAlignBits> AlignDecoder;

-  CProb PosDecoders[1 + kNumFullDistances - kEndPosModelIndex];

-  

-  void InitDist()

-  {

-    for (unsigned i = 0; i < kNumLenToPosStates; i++)

-      PosSlotDecoder[i].Init();

-    AlignDecoder.Init();

-    INIT_PROBS(PosDecoders);

-  }

-  

-  unsigned DecodeDistance(unsigned len)

-  {

-    unsigned lenState = len;

-    if (lenState > kNumLenToPosStates - 1)

-      lenState = kNumLenToPosStates - 1;

-    

-    unsigned posSlot = PosSlotDecoder[lenState].Decode(&RangeDec);

-    if (posSlot < 4)

-      return posSlot;

-    

-    unsigned numDirectBits = (unsigned)((posSlot >> 1) - 1);

-    UInt32 dist = ((2 | (posSlot & 1)) << numDirectBits);

-    if (posSlot < kEndPosModelIndex)

-      dist += BitTreeReverseDecode(PosDecoders + dist - posSlot, numDirectBits, &RangeDec);

-    else

-    {

-      dist += RangeDec.DecodeDirectBits(numDirectBits - kNumAlignBits) << kNumAlignBits;

-      dist += AlignDecoder.ReverseDecode(&RangeDec);

-    }

-    return dist;

-  }

-

-  CProb IsMatch[kNumStates << kNumPosBitsMax];

-  CProb IsRep[kNumStates];

-  CProb IsRepG0[kNumStates];

-  CProb IsRepG1[kNumStates];

-  CProb IsRepG2[kNumStates];

-  CProb IsRep0Long[kNumStates << kNumPosBitsMax];

-

-  CLenDecoder LenDecoder;

-  CLenDecoder RepLenDecoder;

-

-  void Init()

-  {

-    InitLiterals();

-    InitDist();

-

-    INIT_PROBS(IsMatch);

-    INIT_PROBS(IsRep);

-    INIT_PROBS(IsRepG0);

-    INIT_PROBS(IsRepG1);

-    INIT_PROBS(IsRepG2);

-    INIT_PROBS(IsRep0Long);

-

-    LenDecoder.Init();

-    RepLenDecoder.Init();

-  }

-};

-    

-

-#define LZMA_RES_ERROR                   0

-#define LZMA_RES_FINISHED_WITH_MARKER    1

-#define LZMA_RES_FINISHED_WITHOUT_MARKER 2

-

-int CLzmaDecoder::Decode(bool unpackSizeDefined, UInt64 unpackSize)

-{

-  if (!RangeDec.Init())

-    return LZMA_RES_ERROR;

-

-  Init();

-

-  UInt32 rep0 = 0, rep1 = 0, rep2 = 0, rep3 = 0;

-  unsigned state = 0;

-  

-  for (;;)

-  {

-    if (unpackSizeDefined && unpackSize == 0 && !markerIsMandatory)

-      if (RangeDec.IsFinishedOK())

-        return LZMA_RES_FINISHED_WITHOUT_MARKER;

-

-    unsigned posState = OutWindow.TotalPos & ((1 << pb) - 1);

-

-    if (RangeDec.DecodeBit(&IsMatch[(state << kNumPosBitsMax) + posState]) == 0)

-    {

-      if (unpackSizeDefined && unpackSize == 0)

-        return LZMA_RES_ERROR;

-      DecodeLiteral(state, rep0);

-      state = UpdateState_Literal(state);

-      unpackSize--;

-      continue;

-    }

-    

-    unsigned len;

-    

-    if (RangeDec.DecodeBit(&IsRep[state]) != 0)

-    {

-      if (unpackSizeDefined && unpackSize == 0)

-        return LZMA_RES_ERROR;

-      if (OutWindow.IsEmpty())

-        return LZMA_RES_ERROR;

-      if (RangeDec.DecodeBit(&IsRepG0[state]) == 0)

-      {

-        if (RangeDec.DecodeBit(&IsRep0Long[(state << kNumPosBitsMax) + posState]) == 0)

-        {

-          state = UpdateState_ShortRep(state);

-          OutWindow.PutByte(OutWindow.GetByte(rep0 + 1));

-          unpackSize--;

-          continue;

-        }

-      }

-      else

-      {

-        UInt32 dist;

-        if (RangeDec.DecodeBit(&IsRepG1[state]) == 0)

-          dist = rep1;

-        else

-        {

-          if (RangeDec.DecodeBit(&IsRepG2[state]) == 0)

-            dist = rep2;

-          else

-          {

-            dist = rep3;

-            rep3 = rep2;

-          }

-          rep2 = rep1;

-        }

-        rep1 = rep0;

-        rep0 = dist;

-      }

-      len = RepLenDecoder.Decode(&RangeDec, posState);

-      state = UpdateState_Rep(state);

-    }

-    else

-    {

-      rep3 = rep2;

-      rep2 = rep1;

-      rep1 = rep0;

-      len = LenDecoder.Decode(&RangeDec, posState);

-      state = UpdateState_Match(state);

-      rep0 = DecodeDistance(len);

-      if (rep0 == 0xFFFFFFFF)

-        return RangeDec.IsFinishedOK() ?

-            LZMA_RES_FINISHED_WITH_MARKER :

-            LZMA_RES_ERROR;

-

-      if (unpackSizeDefined && unpackSize == 0)

-        return LZMA_RES_ERROR;

-      if (rep0 >= dictSize || !OutWindow.CheckDistance(rep0))

-        return LZMA_RES_ERROR;

-    }

-    len += kMatchMinLen;

-    bool isError = false;

-    if (unpackSizeDefined && unpackSize < len)

-    {

-      len = (unsigned)unpackSize;

-      isError = true;

-    }

-    OutWindow.CopyMatch(rep0 + 1, len);

-    unpackSize -= len;

-    if (isError)

-      return LZMA_RES_ERROR;

-  }

-}

-

-static void Print(const char *s)

-{

-  fputs(s, stdout);

-}

-

-static void PrintError(const char *s)

-{

-  fputs(s, stderr);

-}

-

-

-#define CONVERT_INT_TO_STR(charType, tempSize) \

-

-void ConvertUInt64ToString(UInt64 val, char *s)

-{

-  char temp[32];

-  unsigned i = 0;

-  while (val >= 10)

-  {

-    temp[i++] = (char)('0' + (unsigned)(val % 10));

-    val /= 10;

-  }

-  *s++ = (char)('0' + (unsigned)val);

-  while (i != 0)

-  {

-    i--;

-    *s++ = temp[i];

-  }

-  *s = 0;

-}

-

-void PrintUInt64(const char *title, UInt64 v)

-{

-  Print(title);

-  Print(" : ");

-  char s[32];

-  ConvertUInt64ToString(v, s);

-  Print(s);

-  Print(" bytes \n");

-}

-

-int main2(int numArgs, const char *args[])

-{

-  Print("\nLZMA Reference Decoder 15.00 : Igor Pavlov : Public domain : 2015-04-16\n");

-  if (numArgs == 1)

-    Print("\nUse: lzmaSpec a.lzma outFile");

-

-  if (numArgs != 3)

-    throw "you must specify two parameters";

-

-  CInputStream inStream;

-  inStream.File = fopen(args[1], "rb");

-  inStream.Init();

-  if (inStream.File == 0)

-    throw "Can't open input file";

-

-  CLzmaDecoder lzmaDecoder;

-  lzmaDecoder.OutWindow.OutStream.File = fopen(args[2], "wb+");

-  lzmaDecoder.OutWindow.OutStream.Init();

-  if (inStream.File == 0)

-    throw "Can't open output file";

-

-  Byte header[13];

-  int i;

-  for (i = 0; i < 13; i++)

-    header[i] = inStream.ReadByte();

-

-  lzmaDecoder.DecodeProperties(header);

-

-  printf("\nlc=%d, lp=%d, pb=%d", lzmaDecoder.lc, lzmaDecoder.lp, lzmaDecoder.pb);

-  printf("\nDictionary Size in properties = %u", lzmaDecoder.dictSizeInProperties);

-  printf("\nDictionary Size for decoding  = %u", lzmaDecoder.dictSize);

-

-  UInt64 unpackSize = 0;

-  bool unpackSizeDefined = false;

-  for (i = 0; i < 8; i++)

-  {

-    Byte b = header[5 + i];

-    if (b != 0xFF)

-      unpackSizeDefined = true;

-    unpackSize |= (UInt64)b << (8 * i);

-  }

-

-  lzmaDecoder.markerIsMandatory = !unpackSizeDefined;

-

-  Print("\n");

-  if (unpackSizeDefined)

-    PrintUInt64("Uncompressed Size", unpackSize);

-  else

-    Print("End marker is expected\n");

-  lzmaDecoder.RangeDec.InStream = &inStream;

-

-  Print("\n");

-

-  lzmaDecoder.Create();

-  

-  int res = lzmaDecoder.Decode(unpackSizeDefined, unpackSize);

-

-  PrintUInt64("Read    ", inStream.Processed);

-  PrintUInt64("Written ", lzmaDecoder.OutWindow.OutStream.Processed);

-

-  if (res == LZMA_RES_ERROR)

-    throw "LZMA decoding error";

-  else if (res == LZMA_RES_FINISHED_WITHOUT_MARKER)

-    Print("Finished without end marker");

-  else if (res == LZMA_RES_FINISHED_WITH_MARKER)

-  {

-    if (unpackSizeDefined)

-    {

-      if (lzmaDecoder.OutWindow.OutStream.Processed != unpackSize)

-        throw "Finished with end marker before than specified size";

-      Print("Warning: ");

-    }

-    Print("Finished with end marker");

-  }

-  else

-    throw "Internal Error";

-

-  Print("\n");

-  

-  if (lzmaDecoder.RangeDec.Corrupted)

-  {

-    Print("\nWarning: LZMA stream is corrupted\n");

-  }

-

-  return 0;

-}

-

-

-int

-  #ifdef _MSC_VER

-    __cdecl

-  #endif

-main(int numArgs, const char *args[])

-{

-  try { return main2(numArgs, args); }

-  catch (const char *s)

-  {

-    PrintError("\nError:\n");

-    PrintError(s);

-    PrintError("\n");

-    return 1;

-  }

-  catch(...)

-  {

-    PrintError("\nError\n");

-    return 1;

-  }

-}

diff --git a/CPP/7zip/Bundles/SFXCon/SFXCon.dsp b/CPP/7zip/Bundles/SFXCon/SFXCon.dsp
index 8775319..1bb063d 100644
--- a/CPP/7zip/Bundles/SFXCon/SFXCon.dsp
+++ b/CPP/7zip/Bundles/SFXCon/SFXCon.dsp
@@ -1,912 +1,1009 @@
-# 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 /Gz /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "EXTRACT_ONLY" /D "_SFX" /D "NO_READ_FROM_CODER" /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 "EXTRACT_ONLY" /D "_SFX" /D "NO_READ_FROM_CODER" /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\Bcj2Register.cpp

-# End Source File

-# Begin Source File

-

-SOURCE=..\..\Compress\BcjCoder.cpp

-# 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\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

-# Begin Source File

-

-SOURCE=..\..\Compress\PpmdDecoder.cpp

-# 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

-# 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\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\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\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\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\Sha256.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 Source File

-

-SOURCE=.\7z.ico

-# End Source File

-# Begin Source File

-

-SOURCE=..\..\Archive\IArchive.h

-# 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" /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" /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
+# 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 bfbc2b7..27bf7e6 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 9b34a08..cfce24d 100644
--- a/CPP/7zip/Bundles/SFXCon/SfxCon.cpp
+++ b/CPP/7zip/Bundles/SFXCon/SfxCon.cpp
@@ -1,482 +1,521 @@
-// Main.cpp

-

-#include "StdAfx.h"

-

-#include "../../../../C/CpuArch.h"

-

-#include "../../../Common/MyWindows.h"

-

-#include "../../../Common/MyInitGuid.h"

-

-#include "../../../Common/CommandLineParser.h"

-#include "../../../Common/MyException.h"

-

-#ifdef _WIN32

-#include "../../../Windows/DLL.h"

-#include "../../../Windows/FileDir.h"

-#endif

-#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"

-

-#include "../../../../C/DllSecur.h"

-

-using namespace NWindows;

-using namespace NFile;

-using namespace NDir;

-using namespace NCommandLineParser;

-

-#ifdef _WIN32

-HINSTANCE g_hInstance = 0;

-#endif

-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 <@|!><N>ame must be

-static const char kSomeCludeAfterRecursedPostStringMinSize = 2; // at least <@|!><N>ame must be

-*/

-static const CSwitchForm kSwitchForms[kNumSwitches] =

-{

-  { "?",  NSwitchType::kSimple },

-  { "H",  NSwitchType::kSimple },

-  { "BD", NSwitchType::kSimple },

-  { "Y",  NSwitchType::kSimple },

-  { "P",  NSwitchType::kString, false, 1 },

-  { "O",  NSwitchType::kString, false, 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 int kCommandIndex = 0;

-

-static const char * const kHelpString =

-    "\nUsage: 7zSFX [<command>] [<switches>...] [<file_name>...]\n"

-    "\n"

-    "<Commands>\n"

-    // "  l: List contents of archive\n"

-    "  t: Test integrity of archive\n"

-    "  x: eXtract files with full pathname (default)\n"

-    "<Switches>\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;

-};

-

-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];

-}

-

-void PrintHelp(void)

-{

-  g_StdOut << kHelpString;

-}

-

-static void ShowMessageAndThrowException(const char *message, NExitCode::EEnum code)

-{

-  g_StdOut << message << endl;

-  throw code;

-}

-

-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;

-  */

-  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;

-  }

-  wildcardCensor.AddPreItem(include, name, recursed, true);

-  return true;

-}

-

-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, const 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, const char *args[]

-  #endif

-)

-{

-  #ifdef _WIN32

-  // do we need load Security DLLs for console program?

-  LoadSecurityDlls();

-  #endif

-

-  #if defined(_WIN32) && !defined(UNDER_CE)

-  SetFileApisToOEM();

-  #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

-

-  UString arcPath = 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);

-    }

-  }

-

-  bool yesToAll = parser[NKey::kYes].ThereIs;

-

-  // NExtractMode::EEnum extractMode;

-  // bool isExtractGroupCommand = command.IsFromExtractGroup(extractMode);

-

-  bool passwordEnabled = parser[NKey::kPassword].ThereIs;

-

-  UString password;

-  if (passwordEnabled)

-    password = parser[NKey::kPassword].PostStrings[0];

-

-  if (!NFind::DoesFileExist(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 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<IFolderArchiveExtractCallback> extractCallback = ecs;

-      ecs->Init(g_StdStream, &g_StdErr, g_StdStream);

-

-      #ifndef _NO_CRYPTO

-      ecs->PasswordIsDefined = passwordEnabled;

-      ecs->Password = password;

-      #endif

-

-      /*

-      COpenCallbackConsole openCallback;

-      openCallback.Init(g_StdStream, g_StdStream);

-

-      #ifndef _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<COpenType>(), CIntVector(),

-          v1, v2,

-          wildcardCensorHead,

-          eo, ecs, ecs,

-          // NULL, // hash

-          errorMessage, stat);

-      if (!errorMessage.IsEmpty())

-      {

-        (*g_StdStream) << endl << "Error: " << errorMessage;;

-        if (result == S_OK)

-          result = E_FAIL;

-      }

-

-      if (ecs->NumArcsWithError != 0 || ecs->NumFileErrors != 0)

-      {

-        if (ecs->NumArcsWithError != 0)

-          (*g_StdStream) << endl << "Archive Errors" << endl;

-        if (ecs->NumFileErrors != 0)

-          (*g_StdStream) << endl << "Sub items Errors: " << ecs->NumFileErrors << 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<COpenType>(), CIntVector(),

-          false, // stdInMode

-          v1, v2,

-          true, // processAltStreams

-          false, // showAltStreams

-          wildcardCensorHead,

-          true, // enableHeaders

-          false, // techMode

-          #ifndef _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 <@|!><N>ame must be
+static const char kSomeCludeAfterRecursedPostStringMinSize = 2; // at least <@|!><N>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 [<command>] [<switches>...] [<file_name>...]\n"
+    "\n"
+    "<Commands>\n"
+    // "  l: List contents of archive\n"
+    "  t: Test integrity of archive\n"
+    "  x: eXtract files with full pathname (default)\n"
+    "<Switches>\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<IFolderArchiveExtractCallback> extractCallback = ecs;
+      ecs->Init(g_StdStream, &g_StdErr, g_StdStream);
+
+      #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<COpenType>(), 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<COpenType>(), 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 c6d3b1f..d0feea8 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 59d9ac1..035267c 100644
--- a/CPP/7zip/Bundles/SFXCon/StdAfx.h
+++ b/CPP/7zip/Bundles/SFXCon/StdAfx.h
@@ -1,8 +1,11 @@
-// StdAfx.h

-

-#ifndef __STDAFX_H

-#define __STDAFX_H

-

-#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 811975c..51aaf51 100644
--- a/CPP/7zip/Bundles/SFXCon/makefile
+++ b/CPP/7zip/Bundles/SFXCon/makefile
@@ -1,134 +1,134 @@
-PROG = 7zCon.sfx

-MY_CONSOLE = 1

-MY_FIXED = 1

-

-CFLAGS = $(CFLAGS) \

-  -DEXTRACT_ONLY \

-  -DNO_READ_FROM_CODER \

-  -D_SFX \

-

-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\Wildcard.obj \

-  $O\UTFConvert.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 \

-

-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\LoadCodecs.obj \

-  $O\Extract.obj \

-  $O\ExtractingFilePath.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\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\Sha256.obj \

-  $O\Threads.obj \

-

-!include "../../Aes.mak"

-!include "../../Crc.mak"

-!include "../../LzmaDec.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 \
+
+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 \
+
+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
new file mode 100644
index 0000000..9278502
--- /dev/null
+++ b/CPP/7zip/Bundles/SFXCon/makefile.gcc
@@ -0,0 +1,213 @@
+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 = \
+
+SYS_OBJS = \
+  $O/DLL.o \
+  $O/DllSecur.o \
+  $O/resource.o \
+
+else
+
+SYS_OBJS = \
+  $O/MyWindows.o \
+
+endif
+
+LOCAL_FLAGS = \
+  $(LOCAL_FLAGS_ST) \
+  $(LOCAL_FLAGS_SYS) \
+  -DZ7_EXTRACT_ONLY \
+  -DZ7_NO_READ_FROM_CODER \
+  -DZ7_SFX \
+
+
+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 97882cd..6576212 100644
--- a/CPP/7zip/Bundles/SFXCon/resource.rc
+++ b/CPP/7zip/Bundles/SFXCon/resource.rc
@@ -1,5 +1,9 @@
-#include "../../MyVersionInfo.rc"

-

-MY_VERSION_INFO_APP("7z Console SFX", "7z.sfx")

-

-101 ICON "7z.ico"
\ No newline at end of file
+#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 d35a24f..9d632ee 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 = "Can not delete output file";

-static LPCSTR const kCantOpenFile = "Can not 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;

-}

-

-STDMETHODIMP CExtractCallbackImp::SetTotal(UInt64 size)

-{

-  #ifndef _NO_PROGRESS

-  ProgressDialog.Sync.SetProgress(size, 0);

-  #endif

-  return S_OK;

-}

-

-STDMETHODIMP 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();

-  }

-}

-

-STDMETHODIMP 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<ISequentialOutStream> outStreamLoc(_outFileStreamSpec);

-      if (!_outFileStreamSpec->Create(fullProcessedPath, true))

-      {

-        _message = kCantOpenFile;

-        return E_FAIL;

-      }

-      _outFileStream = outStreamLoc;

-      *outStream = outStreamLoc.Detach();

-    }

-    _diskFilePath = fullProcessedPath;

-  }

-  else

-  {

-    *outStream = NULL;

-  }

-  return S_OK;

-}

-

-STDMETHODIMP CExtractCallbackImp::PrepareOperation(Int32 askExtractMode)

-{

-  _extractMode = (askExtractMode == NArchive::NExtract::NAskMode::kExtract);

-  return S_OK;

-}

-

-STDMETHODIMP 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<ISequentialOutStream> outStreamLoc(_outFileStreamSpec);
+      if (!_outFileStreamSpec->Create(fullProcessedPath, true))
+      {
+        _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 b7f04e0..b9377ae 100644
--- a/CPP/7zip/Bundles/SFXSetup/ExtractCallbackSfx.h
+++ b/CPP/7zip/Bundles/SFXSetup/ExtractCallbackSfx.h
@@ -1,86 +1,83 @@
-// ExtractCallbackSfx.h

-

-#ifndef __EXTRACT_CALLBACK_SFX_H

-#define __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:

-  public IArchiveExtractCallback,

-  public IOpenCallbackUI,

-  public CMyUnknownImp

-{

-public:

-  

-  MY_UNKNOWN_IMP

-

-  INTERFACE_IArchiveExtractCallback(;)

-  INTERFACE_IOpenCallbackUI(;)

-

-private:

-  CMyComPtr<IInArchive> _archiveHandler;

-  FString _directoryPath;

-  UString _filePath;

-  FString _diskFilePath;

-

-  bool _extractMode;

-  struct CProcessedFileInfo

-  {

-    FILETIME MTime;

-    bool IsDir;

-    UInt32 Attributes;

-  } _processedFileInfo;

-

-  COutFileStream *_outFileStreamSpec;

-  CMyComPtr<ISequentialOutStream> _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, 0);

-    {

-      ProgressDialog.SetText(LangString(IDS_PROGRESS_EXTRACTING));

-    }

-

-    ProgressDialog.Show(SW_SHOWNORMAL);

-    return S_OK;

-  }

-  virtual ~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<IInArchive> _archiveHandler;
+  FString _directoryPath;
+  UString _filePath;
+  FString _diskFilePath;
+
+  bool _extractMode;
+  struct CProcessedFileInfo
+  {
+    FILETIME MTime;
+    bool IsDir;
+    UInt32 Attributes;
+  } _processedFileInfo;
+
+  COutFileStream *_outFileStreamSpec;
+  CMyComPtr<ISequentialOutStream> _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 194e376..73ccff1 100644
--- a/CPP/7zip/Bundles/SFXSetup/ExtractEngine.cpp
+++ b/CPP/7zip/Bundles/SFXSetup/ExtractEngine.cpp
@@ -1,137 +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 = "Can not find archive file";

-static LPCSTR const kCantOpenArchive = "Can not open the file as archive";

-

-struct CThreadExtracting

-{

-  CCodecs *Codecs;

-  FString FileName;

-  FString DestFolder;

-

-  CExtractCallbackImp *ExtractCallbackSpec;

-  CMyComPtr<IArchiveExtractCallback> ExtractCallback;

-

-  CArchiveLink ArchiveLink;

-  HRESULT Result;

-  UString ErrorMessage;

-

-  void Process2()

-  {

-    NFind::CFileInfo fi;

-    if (!fi.Find(FileName))

-    {

-      ErrorMessage = kCantFindArchive;

-      Result = E_FAIL;

-      return;

-    }

-

-    CObjectVector<COpenType> incl;

-    CIntVector excl;

-    COpenOptions options;

-    options.codecs = Codecs;

-    options.types = &incl;

-    options.excludedFormats = &excl;

-    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,

-        #ifdef LANG

-        0x02000603,

-        #endif

-        fs2us(dirPath));

-      Result = E_FAIL;

-      return;

-    }

-

-    ExtractCallbackSpec->Init(ArchiveLink.GetArchive(), dirPath, (UString)"Default", fi.MTime, 0);

-

-    Result = ArchiveLink.GetArchive()->Extract(0, (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;

-    RINOK(thread.Create(CThreadExtracting::MyThreadFunction, &t));

-    

-    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<IArchiveExtractCallback> ExtractCallback;
+
+  CArchiveLink ArchiveLink;
+  HRESULT Result;
+  UString ErrorMessage;
+
+  void Process2()
+  {
+    NFind::CFileInfo fi;
+    if (!fi.Find(FileName))
+    {
+      ErrorMessage = kCantFindArchive;
+      Result = E_FAIL;
+      return;
+    }
+
+    CObjectVector<COpenType> incl;
+    CIntVector excl;
+    COpenOptions options;
+    options.codecs = Codecs;
+    options.types = &incl;
+    options.excludedFormats = &excl;
+    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 8aa9724..b7f7965 100644
--- a/CPP/7zip/Bundles/SFXSetup/ExtractEngine.h
+++ b/CPP/7zip/Bundles/SFXSetup/ExtractEngine.h
@@ -1,11 +1,11 @@
-// ExtractEngine.h

-

-#ifndef __EXTRACT_ENGINE_H

-#define __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 b1d740e..cf96460 100644
--- a/CPP/7zip/Bundles/SFXSetup/SFXSetup.dsp
+++ b/CPP/7zip/Bundles/SFXSetup/SFXSetup.dsp
@@ -1,803 +1,864 @@
-# 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 "EXTRACT_ONLY" /D "NO_REGISTRY" /D "_SFX" /D "_NO_CRYPTO" /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 "EXTRACT_ONLY" /D "NO_REGISTRY" /D "_SFX" /D "_NO_CRYPTO" /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 "EXTRACT_ONLY" /D "EXCLUDE_COM" /D "NO_REGISTRY" /D "_SFX" /Yu"StdAfx.h" /FD /c

-# ADD CPP /nologo /Gz /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "EXTRACT_ONLY" /D "NO_REGISTRY" /D "_SFX" /D "_NO_CRYPTO" /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\Bcj2Register.cpp

-# End Source File

-# Begin Source File

-

-SOURCE=..\..\Compress\BcjCoder.cpp

-# 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\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\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\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\Window.cpp

-# End Source File

-# Begin Source File

-

-SOURCE=..\..\..\Windows\Window.h

-# End Source File

-# End Group

-# Begin Group "7z 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\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\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 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" /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" /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" /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\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 2970370..f563b21 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 1705a8d..47d7966 100644
--- a/CPP/7zip/Bundles/SFXSetup/SfxSetup.cpp
+++ b/CPP/7zip/Bundles/SFXSetup/SfxSetup.cpp
@@ -1,364 +1,368 @@
-// Main.cpp

-

-#include "StdAfx.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 "../../../../C/DllSecur.h"

-

-#include "resource.h"

-

-using namespace NWindows;

-using namespace NFile;

-using namespace NDir;

-

-HINSTANCE g_hInstance;

-

-static CFSTR const kTempDirPrefix = FTEXT("7zS");

-

-#define _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 int kBufferSize = (1 << 12);

-

-  Byte buffer[kBufferSize];

-  int signatureStartSize = MyStringLen(startID);

-  int signatureEndSize = MyStringLen(endID);

-  

-  UInt32 numBytesPrev = 0;

-  bool writeMode = false;

-  UInt64 posTotal = 0;

-  for (;;)

-  {

-    if (posTotal > (1 << 20))

-      return (stringResult.IsEmpty());

-    UInt32 numReadBytes = kBufferSize - numBytesPrev;

-    UInt32 processedSize;

-    if (!inFile.Read(buffer + numBytesPrev, numReadBytes, processedSize))

-      return false;

-    if (processedSize == 0)

-      return true;

-    UInt32 numBytesInBuffer = numBytesPrev + processedSize;

-    UInt32 pos = 0;

-    for (;;)

-    {

-      if (writeMode)

-      {

-        if (pos > numBytesInBuffer - signatureEndSize)

-          break;

-        if (memcmp(buffer + pos, endID, signatureEndSize) == 0)

-          return true;

-        char b = buffer[pos];

-        if (b == 0)

-          return false;

-        stringResult += b;

-        pos++;

-      }

-      else

-      {

-        if (pos > numBytesInBuffer - signatureStartSize)

-          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 };

-

-struct CInstallIDInit

-{

-  CInstallIDInit()

-  {

-    kStartID[0] = ';';

-    kEndID[0] = ';';

-  };

-} g_CInstallIDInit;

-

-

-#define NT_CHECK_FAIL_ACTION ShowErrorMessage(L"Unsupported Windows version"); return 1;

-

-static void ShowErrorMessageSpec(const UString &name)

-{

-  UString message = NError::MyFormatMessage(::GetLastError());

-  int pos = message.Find(L"%1");

-  if (pos >= 0)

-  {

-    message.Delete(pos, 2);

-    message.Insert(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 _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<CTextConfigPair> pairs;

-    if (!GetTextConfig(config, pairs))

-    {

-      if (!assumeYes)

-        ShowErrorMessage(L"Config failed");

-      return 1;

-    }

-    UString friendlyName = GetTextConfigValue(pairs, "Title");

-    UString installPrompt = GetTextConfigValue(pairs, "BeginPrompt");

-    UString progress = GetTextConfigValue(pairs, "Progress");

-    if (progress.IsEqualTo_Ascii_NoCase("no"))

-      showProgress = false;

-    int index = FindTextConfigItem(pairs, "Directory");

-    if (index >= 0)

-      dirPrefix = pairs[index].String;

-    if (!installPrompt.IsEmpty() && !assumeYes)

-    {

-      if (MessageBoxW(0, installPrompt, friendlyName, MB_YESNO |

-          MB_ICONQUESTION) != IDYES)

-        return 0;

-    }

-    appLaunched = GetTextConfigValue(pairs, "RunProgram");

-    

-    #ifdef _SHELL_EXECUTE

-    executeFile = GetTextConfigValue(pairs, "ExecuteFile");

-    executeParameters = GetTextConfigValue(pairs, "ExecuteParameters");

-    #endif

-  }

-

-  CTempDir tempDir;

-  if (!tempDir.Create(kTempDirPrefix))

-  {

-    if (!assumeYes)

-      ShowErrorMessage(L"Can not create temp folder archive");

-    return 1;

-  }

-

-  CCodecs *codecs = new CCodecs;

-  CMyComPtr<IUnknown> compressCodecsInfo = codecs;

-  {

-    HRESULT result = codecs->Load();

-    if (result != S_OK)

-    {

-      ShowErrorMessage(L"Can not 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(0, errorMessage, NWindows::MyLoadString(IDS_EXTRACTION_ERROR_TITLE), MB_ICONERROR);

-        }

-      }

-      return 1;

-    }

-  }

-

-  #ifndef UNDER_CE

-  CCurrentDirRestorer currentDirRestorer;

-  if (!SetCurrentDir(tempDirPath))

-    return 1;

-  #endif

-  

-  HANDLE hProcess = 0;

-#ifdef _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;

-    }

-

-    CSysString parametersSys (GetSystemString(executeParameters));

-    if (parametersSys.IsEmpty())

-      execInfo.lpParameters = NULL;

-    else

-      execInfo.lpParameters = parametersSys;

-

-    execInfo.lpDirectory = NULL;

-    execInfo.nShow = SW_SHOWNORMAL;

-    execInfo.hProcess = 0;

-    /* BOOL success = */ ::ShellExecuteEx(&execInfo);

-    UINT32 result = (UINT32)(UINT_PTR)execInfo.hInstApp;

-    if (result <= 32)

-    {

-      if (!assumeYes)

-        ShowErrorMessage(L"Can not open file");

-      return 1;

-    }

-    hProcess = execInfo.hProcess;

-  }

-  else

-#endif

-  {

-    if (appLaunched.IsEmpty())

-    {

-      appLaunched = L"setup.exe";

-      if (!NFind::DoesFileExist(us2fs(appLaunched)))

-      {

-        if (!assumeYes)

-          ShowErrorMessage(L"Can not find setup.exe");

-        return 1;

-      }

-    }

-    

-    {

-      FString s2 = tempDirPath;

-      NName::NormalizeDirPathPrefix(s2);

-      appLaunched.Replace(L"%%T" WSTRING_PATH_SEPARATOR, fs2us(s2));

-    }

-    

-    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 = 0;

-    startupInfo.lpDesktop = 0;

-    startupInfo.lpTitle = 0;

-    startupInfo.dwFlags = 0;

-    startupInfo.cbReserved2 = 0;

-    startupInfo.lpReserved2 = 0;

-    

-    PROCESS_INFORMATION processInformation;

-    

-    CSysString appLaunchedSys (GetSystemString(dirPrefix + appLaunched));

-    

-    BOOL createResult = CreateProcess(NULL, (LPTSTR)(LPCTSTR)appLaunchedSys,

-      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 != 0)

-  {

-    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;
+
+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<CTextConfigPair> 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<IUnknown> 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 c6d3b1f..d0feea8 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 72410ee..4f27255 100644
--- a/CPP/7zip/Bundles/SFXSetup/StdAfx.h
+++ b/CPP/7zip/Bundles/SFXSetup/StdAfx.h
@@ -1,13 +1,6 @@
-// StdAfx.h

-

-#ifndef __STDAFX_H

-#define __STDAFX_H

-

-#include "../../../Common/Common.h"

-

-#include <commctrl.h>

-

-// #define printf(x) NO_PRINTF_(x)

-// #define sprintf(x) NO_SPRINTF_(x)

-

-#endif

+// 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 b97daad..ea0ece2 100644
--- a/CPP/7zip/Bundles/SFXSetup/makefile
+++ b/CPP/7zip/Bundles/SFXSetup/makefile
@@ -1,117 +1,118 @@
-PROG = 7zS.sfx

-MY_FIXED = 1

-

-CFLAGS = $(CFLAGS) \

-  -DNO_REGISTRY \

-  -DEXTRACT_ONLY \

-  -DNO_READ_FROM_CODER \

-  -D_SFX \

-  -D_NO_CRYPTO \

-

-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\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\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 \
+
+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\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 533197e..d5f440b 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 9e88fd4..47e1b76 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 83ec931..65cf0bf 100644
--- a/CPP/7zip/Bundles/SFXWin/SFXWin.dsp
+++ b/CPP/7zip/Bundles/SFXWin/SFXWin.dsp
@@ -1,988 +1,1066 @@
-# 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 "_SFXWIN32" /D "_WINDOWS" /D "_MBCS" /D "EXTRACT_ONLY" /D "NO_REGISTRY" /D "NO_READ_FROM_CODER" /D "_SFX" /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 "_SFXWIN32" /D "_WINDOWS" /D "_MBCS" /D "EXTRACT_ONLY" /D "NO_REGISTRY" /D "NO_READ_FROM_CODER" /D "_SFX" /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 "EXTRACT_ONLY" /D "EXCLUDE_COM" /D "NO_REGISTRY" /D "_SFX" /Yu"StdAfx.h" /FD /c

-# ADD CPP /nologo /Gz /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "_SFXWIN32" /D "_WINDOWS" /D "_MBCS" /D "EXTRACT_ONLY" /D "NO_REGISTRY" /D "NO_READ_FROM_CODER" /D "_SFX" /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\Bcj2Register.cpp

-# End Source File

-# Begin Source File

-

-SOURCE=..\..\Compress\BcjCoder.cpp

-# 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\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\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\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\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\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\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\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\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\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\Threads.c

-# SUBTRACT CPP /YX /Yc /Yu

-# End Source File

-# Begin Source File

-

-SOURCE=..\..\..\..\C\Threads.h

-# End Source File

-# End Group

-# Begin Source File

-

-SOURCE=.\7z.ico

-# End Source File

-# Begin Source File

-

-SOURCE=.\7z1.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" /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" /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" /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\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 6695803..a9926c7 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 5eade1a..3e1880e 100644
--- a/CPP/7zip/Bundles/SFXWin/SfxWin.cpp
+++ b/CPP/7zip/Bundles/SFXWin/SfxWin.cpp
@@ -1,241 +1,254 @@
-// Main.cpp

-

-#include "StdAfx.h"

-

-#include "../../../Common/MyWindows.h"

-

-#include <Shlwapi.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"

-

-#include "../../../../C/DllSecur.h"

-

-using namespace NWindows;

-using namespace NFile;

-using namespace NDir;

-

-HINSTANCE g_hInstance;

-

-#ifndef UNDER_CE

-

-DWORD g_ComCtl32Version;

-

-static DWORD GetDllVersion(LPCTSTR dllName)

-{

-  DWORD dwVersion = 0;

-  HINSTANCE hinstDll = LoadLibrary(dllName);

-  if (hinstDll)

-  {

-    DLLGETVERSIONPROC pDllGetVersion = (DLLGETVERSIONPROC)GetProcAddress(hinstDll, "DllGetVersion");

-    if (pDllGetVersion)

-    {

-      DLLVERSIONINFO dvi;

-      ZeroMemory(&dvi, sizeof(dvi));

-      dvi.cbSize = sizeof(dvi);

-      HRESULT hr = (*pDllGetVersion)(&dvi);

-      if (SUCCEEDED(hr))

-        dwVersion = MAKELONG(dvi.dwMinorVersion, dvi.dwMajorVersion);

-    }

-    FreeLibrary(hinstDll);

-  }

-  return dwVersion;

-}

-

-#endif

-

-bool g_LVN_ITEMACTIVATE_Support = true;

-

-static const wchar_t * const kUnknownExceptionMessage = L"ERROR: Unknown Error!";

-

-void ErrorMessageForHRESULT(HRESULT res)

-{

-  ShowErrorMessage(HResultToMessage(res));

-}

-

-int APIENTRY WinMain2()

-{

-  // OleInitialize is required for ProgressBar in TaskBar.

-  #ifndef UNDER_CE

-  OleInitialize(NULL);

-  #endif

-

-  #ifndef UNDER_CE

-  g_ComCtl32Version = ::GetDllVersion(TEXT("comctl32.dll"));

-  g_LVN_ITEMACTIVATE_Support = (g_ComCtl32Version >= MAKELONG(71, 4));

-  #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] == '-')

-    {

-      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);

-      }

-    }

-  }

-

-  FString path;

-  NDLL::MyGetModuleFileName(path);

-

-  FString fullPath;

-  if (!MyGetFullPathName(path, fullPath))

-  {

-    ShowErrorMessage(L"Error 1329484");

-    return 1;

-  }

-

-  CCodecs *codecs = new CCodecs;

-  CMyComPtr<IUnknown> 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<IFolderArchiveExtractCallback> extractCallback = ecs;

-  ecs->Init();

-

-  #ifndef _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.AddItem(true, L"*", true, true, true, true);

-

-  bool messageWasDisplayed = false;

-  result = ExtractGUI(codecs,

-      CObjectVector<COpenType>(), 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;

-}

-

-#define NT_CHECK_FAIL_ACTION ShowErrorMessage(L"Unsupported Windows version"); return NExitCode::kFatalError;

-

-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 <shlwapi.h>
+#else
+#include <Shlwapi.h>
+#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;
+
+#ifndef UNDER_CE
+
+static
+DWORD g_ComCtl32Version;
+
+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
+
+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
+  g_ComCtl32Version = ::GetDllVersion(TEXT("comctl32.dll"));
+  g_LVN_ITEMACTIVATE_Support = (g_ComCtl32Version >= MAKELONG(71, 4));
+  #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);
+      }
+    }
+  }
+
+  FString path;
+  NDLL::MyGetModuleFileName(path);
+
+  FString fullPath;
+  if (!MyGetFullPathName(path, fullPath))
+  {
+    ShowErrorMessage(L"Error 1329484");
+    return 1;
+  }
+
+  CCodecs *codecs = new CCodecs;
+  CMyComPtr<IUnknown> 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<IFolderArchiveExtractCallback> 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<COpenType>(), 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 c6d3b1f..d0feea8 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 f263ecb..4f27255 100644
--- a/CPP/7zip/Bundles/SFXWin/StdAfx.h
+++ b/CPP/7zip/Bundles/SFXWin/StdAfx.h
@@ -1,14 +1,6 @@
-// StdAfx.h

-

-#ifndef __STDAFX_H

-#define __STDAFX_H

-

-#include "../../../Common/Common.h"

-

-#include <commctrl.h>

-#include <ShlObj.h>

-

-// #define printf(x) NO_PRINTF_(x)

-// #define sprintf(x) NO_SPRINTF_(x)

-

-#endif

+// 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 21a67dd..69a8553 100644
--- a/CPP/7zip/Bundles/SFXWin/makefile
+++ b/CPP/7zip/Bundles/SFXWin/makefile
@@ -1,153 +1,156 @@
-PROG = 7z.sfx

-MY_FIXED = 1

-

-CFLAGS = $(CFLAGS) \

-  -DNO_REGISTRY \

-  -DEXTRACT_ONLY \

-  -DNO_READ_FROM_CODER \

-  -D_SFX \

-

-!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\CommonDialog.obj \

-  $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\ResourceString.obj \

-  $O\Shell.obj \

-  $O\Synchronization.obj \

-  $O\System.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\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\Sha256.obj \

-  $O\Threads.obj \

-

-!include "../../Aes.mak"

-!include "../../Crc.mak"

-!include "../../LzmaDec.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 \
+
+!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\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 d9fae1b..30fe203 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 3b69b35..3b2217a 100644
--- a/CPP/7zip/Bundles/SFXWin/resource.rc
+++ b/CPP/7zip/Bundles/SFXWin/resource.rc
@@ -1,50 +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

+#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
new file mode 100644
index 0000000..0651da5
--- /dev/null
+++ b/CPP/7zip/Bundles/makefile
@@ -0,0 +1,19 @@
+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 e726dad..346774e 100644
--- a/CPP/7zip/Common/CWrappers.cpp
+++ b/CPP/7zip/Common/CWrappers.cpp
@@ -1,250 +1,354 @@
-// CWrappers.h

-

-#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;

-  }

-  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:

-      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;

-  }

-  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(const ICompressProgress *pp, UInt64 inSize, UInt64 outSize) throw()

-{

-  CCompressProgressWrap *p = CONTAINER_FROM_VTBL(pp, CCompressProgressWrap, vt);

-  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(const ISeqInStream *pp, void *data, size_t *size) throw()

-{

-  CSeqInStreamWrap *p = CONTAINER_FROM_VTBL(pp, CSeqInStreamWrap, vt);

-  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(const ISeqOutStream *pp, const void *data, size_t size) throw()

-{

-  CSeqOutStreamWrap *p = CONTAINER_FROM_VTBL(pp, CSeqOutStreamWrap, vt);

-  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(const ISeekInStream *pp, void *data, size_t *size) throw()

-{

-  CSeekInStreamWrap *p = CONTAINER_FROM_VTBL(pp, CSeekInStreamWrap, vt);

-  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(const ISeekInStream *pp, Int64 *offset, ESzSeek origin) throw()

-{

-  CSeekInStreamWrap *p = CONTAINER_FROM_VTBL(pp, CSeekInStreamWrap, vt);

-  UInt32 moveMethod;

-  switch (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 = 0;

-}

-

-bool CByteInBufWrap::Alloc(UInt32 size) throw()

-{

-  if (Buf == 0 || size != Size)

-  {

-    Free();

-    Lim = Cur = Buf = (Byte *)::MidAlloc((size_t)size);

-    Size = size;

-  }

-  return (Buf != 0);

-}

-

-Byte CByteInBufWrap::ReadByteFromNewBlock() throw()

-{

-  if (Res == S_OK)

-  {

-    UInt32 avail;

-    Processed += (Cur - Buf);

-    Res = Stream->Read(Buf, Size, &avail);

-    Cur = Buf;

-    Lim = Buf + avail;

-    if (avail != 0)

-      return *Cur++;

-  }

-  Extra = true;

-  return 0;

-}

-

-static Byte Wrap_ReadByte(const IByteIn *pp) throw()

-{

-  CByteInBufWrap *p = CONTAINER_FROM_VTBL_CLS(pp, CByteInBufWrap, vt);

-  if (p->Cur != p->Lim)

-    return *p->Cur++;

-  return p->ReadByteFromNewBlock();

-}

-

-CByteInBufWrap::CByteInBufWrap(): Buf(0)

-{

-  vt.Read = Wrap_ReadByte;

-}

-

-

-/* ---------- CByteOutBufWrap ---------- */

-

-void CByteOutBufWrap::Free() throw()

-{

-  ::MidFree(Buf);

-  Buf = 0;

-}

-

-bool CByteOutBufWrap::Alloc(size_t size) throw()

-{

-  if (Buf == 0 || size != Size)

-  {

-    Free();

-    Buf = (Byte *)::MidAlloc(size);

-    Size = size;

-  }

-  return (Buf != 0);

-}

-

-HRESULT CByteOutBufWrap::Flush() throw()

-{

-  if (Res == S_OK)

-  {

-    size_t size = (Cur - Buf);

-    Res = WriteStream(Stream, Buf, size);

-    if (Res == S_OK)

-      Processed += size;

-    Cur = Buf;

-  }

-  return Res;

-}

-

-static void Wrap_WriteByte(const IByteOut *pp, Byte b) throw()

-{

-  CByteOutBufWrap *p = CONTAINER_FROM_VTBL_CLS(pp, CByteOutBufWrap, vt);

-  Byte *dest = p->Cur;

-  *dest = b;

-  p->Cur = ++dest;

-  if (dest == p->Lim)

-    p->Flush();

-}

-

-CByteOutBufWrap::CByteOutBufWrap() throw(): Buf(0)

-{

-  vt.Write = Wrap_WriteByte;

-}

+// 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;
+  }
+  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:
+      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;
+  }
+  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 f93c98a..6c10a5c 100644
--- a/CPP/7zip/Common/CWrappers.h
+++ b/CPP/7zip/Common/CWrappers.h
@@ -1,120 +1,182 @@
-// CWrappers.h

-

-#ifndef __C_WRAPPERS_H

-#define __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();

-  ~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 + (Cur - Buf); }

-  Byte ReadByteFromNewBlock() throw();

-  Byte ReadByte()

-  {

-    if (Cur != Lim)

-      return *Cur++;

-    return ReadByteFromNewBlock();

-  }

-};

-

-

-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 + (Cur - Buf); }

-  HRESULT Flush() throw();

-  void WriteByte(Byte b)

-  {

-    *Cur++ = b;

-    if (Cur == Lim)

-      Flush();

-  }

-};

-

-#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 5040765..bf7b04e 100644
--- a/CPP/7zip/Common/CreateCoder.cpp
+++ b/CPP/7zip/Common/CreateCoder.cpp
@@ -1,536 +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;

-unsigned g_NumCodecs = 0;

-const CCodecInfo *g_Codecs[kNumCodecsMax];

-

-// We use g_ExternalCodecs in other stages.

-/*

-#ifdef EXTERNAL_CODECS

-extern CExternalCodecs g_ExternalCodecs;

-#define CHECK_GLOBAL_CODECS \

-    if (!__externalCodecs || !__externalCodecs->IsSet()) __externalCodecs = &g_ExternalCodecs;

-#endif

-*/

-

-#define CHECK_GLOBAL_CODECS

-

-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 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));

-      

-      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)

-{

-  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;

-      return i;

-    }

-  }

-  

-  #ifdef 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;

-        return 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 i;

-  }

-  

-  #ifdef 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 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 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 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<CMethodId> &methods)

-{

-  methods.ClearAndSetSize(g_NumHashers);

-  unsigned i;

-  for (i = 0; i < g_NumHashers; i++)

-    methods[i] = (*g_Hashers[i]).Id;

-  

-  #ifdef 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<ICompressFilter> &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 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)

-            {

-              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)

-            {

-              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<ICompressFilter> filter;

-  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<ICompressFilter> &filter,

-    CCreatedCoder &cod)

-{

-  int index = FindMethod_Index(EXTERNAL_CODECS_LOC_VARS methodId, encode);

-  if (index < 0)

-    return S_OK;

-  return CreateCoder_Index(EXTERNAL_CODECS_LOC_VARS index, encode, filter, cod);

-}

-

-

-HRESULT CreateCoder_Id(

-    DECL_EXTERNAL_CODECS_LOC_VARS

-    CMethodId methodId, bool encode,

-    CCreatedCoder &cod)

-{

-  CMyComPtr<ICompressFilter> filter;

-  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<ICompressCoder> &coder)

-{

-  CCreatedCoder cod;

-  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<ICompressFilter> &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<IHasher> &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 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 = 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<CMethodId> &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<ICompressFilter> &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<ICompressFilter> 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<ICompressFilter> &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<ICompressFilter> 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<ICompressCoder> &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<ICompressFilter> &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<IHasher> &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 2105818..709fe83 100644
--- a/CPP/7zip/Common/CreateCoder.h
+++ b/CPP/7zip/Common/CreateCoder.h
@@ -1,192 +1,200 @@
-// CreateCoder.h

-

-#ifndef __CREATE_CODER_H

-#define __CREATE_CODER_H

-

-#include "../../Common/MyCom.h"

-#include "../../Common/MyString.h"

-

-#include "../ICoder.h"

-

-#include "MethodId.h"

-

-/*

-  if EXTERNAL_CODECS is not defined, the code supports only codecs that

-      are statically linked at compile-time and link-time.

-

-  if 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 EXTERNAL_CODECS

-

-struct CCodecInfoEx

-{

-  CMethodId Id;

-  AString Name;

-  UInt32 NumStreams;

-  bool EncoderIsAssigned;

-  bool DecoderIsAssigned;

-  

-  CCodecInfoEx(): EncoderIsAssigned(false), DecoderIsAssigned(false) {}

-};

-

-struct CHasherInfoEx

-{

-  CMethodId Id;

-  AString Name;

-};

-

-#define PUBLIC_ISetCompressCodecsInfo public ISetCompressCodecsInfo,

-#define QUERY_ENTRY_ISetCompressCodecsInfo MY_QUERYINTERFACE_ENTRY(ISetCompressCodecsInfo)

-#define DECL_ISetCompressCodecsInfo STDMETHOD(SetCompressCodecsInfo)(ICompressCodecsInfo *compressCodecsInfo);

-#define IMPL_ISetCompressCodecsInfo2(x) \

-STDMETHODIMP x::SetCompressCodecsInfo(ICompressCodecsInfo *compressCodecsInfo) { \

-  COM_TRY_BEGIN __externalCodecs.GetCodecs = compressCodecsInfo;  return __externalCodecs.Load(); COM_TRY_END }

-#define IMPL_ISetCompressCodecsInfo IMPL_ISetCompressCodecsInfo2(CHandler)

-

-struct CExternalCodecs

-{

-  CMyComPtr<ICompressCodecsInfo> GetCodecs;

-  CMyComPtr<IHashers> GetHashers;

-

-  CObjectVector<CCodecInfoEx> Codecs;

-  CObjectVector<CHasherInfoEx> 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 EXTERNAL_CODECS_LOC_VARS2 __externalCodecs

-

-#define DECL_EXTERNAL_CODECS_LOC_VARS DECL_EXTERNAL_CODECS_LOC_VARS2,

-#define EXTERNAL_CODECS_LOC_VARS EXTERNAL_CODECS_LOC_VARS2,

-

-#else

-

-#define PUBLIC_ISetCompressCodecsInfo

-#define QUERY_ENTRY_ISetCompressCodecsInfo

-#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 EXTERNAL_CODECS_LOC_VARS2

-#define DECL_EXTERNAL_CODECS_LOC_VARS

-#define EXTERNAL_CODECS_LOC_VARS

-

-#endif

-

-int FindMethod_Index(

-    DECL_EXTERNAL_CODECS_LOC_VARS

-    const AString &name,

-    bool encode,

-    CMethodId &methodId,

-    UInt32 &numStreams);

-

-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<CMethodId> &methods);

-

-

-struct CCreatedCoder

-{

-  CMyComPtr<ICompressCoder> Coder;

-  CMyComPtr<ICompressCoder2> 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<ICompressFilter> &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<ICompressFilter> &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<ICompressCoder> &coder);

-

-HRESULT CreateFilter(

-    DECL_EXTERNAL_CODECS_LOC_VARS

-    CMethodId methodId, bool encode,

-    CMyComPtr<ICompressFilter> &filter);

-

-HRESULT CreateHasher(

-    DECL_EXTERNAL_CODECS_LOC_VARS

-    CMethodId methodId,

-    AString &name,

-    CMyComPtr<IHasher> &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<ICompressCodecsInfo> GetCodecs;
+  CMyComPtr<IHashers> GetHashers;
+
+  CObjectVector<CCodecInfoEx> Codecs;
+  CObjectVector<CHasherInfoEx> 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<CMethodId> &methods);
+
+
+struct CCreatedCoder
+{
+  CMyComPtr<ICompressCoder> Coder;
+  CMyComPtr<ICompressCoder2> 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<ICompressFilter> &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<ICompressFilter> &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<ICompressCoder> &coder);
+
+HRESULT CreateFilter(
+    DECL_EXTERNAL_CODECS_LOC_VARS
+    CMethodId methodId, bool encode,
+    CMyComPtr<ICompressFilter> &filter);
+
+HRESULT CreateHasher(
+    DECL_EXTERNAL_CODECS_LOC_VARS
+    CMethodId methodId,
+    AString &name,
+    CMyComPtr<IHasher> &hasher);
+
+#endif
diff --git a/CPP/7zip/Common/FilePathAutoRename.cpp b/CPP/7zip/Common/FilePathAutoRename.cpp
index 84c9e2b..1ebfd72 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)

-{

-  int dotPos = path.ReverseFind_Dot();

-  int slashPos = path.ReverseFind_PathSepar();

-

-  FString name = path;

-  FString extension;

-  if (dotPos > slashPos + 1)

-  {

-    name.DeleteFrom(dotPos);

-    extension = path.Ptr(dotPos);

-  }

-  name += '_';

-  

-  FString temp;

-

-  UInt32 left = 1, right = ((UInt32)1 << 30);

-  while (left != right)

-  {

-    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)
+{
+  int dotPos = path.ReverseFind_Dot();
+  int slashPos = path.ReverseFind_PathSepar();
+
+  FString name = path;
+  FString extension;
+  if (dotPos > slashPos + 1)
+  {
+    name.DeleteFrom((unsigned)dotPos);
+    extension = path.Ptr((unsigned)dotPos);
+  }
+  name += '_';
+  
+  FString temp;
+
+  UInt32 left = 1, right = ((UInt32)1 << 30);
+  while (left != right)
+  {
+    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 cb2d71b..ac36882 100644
--- a/CPP/7zip/Common/FilePathAutoRename.h
+++ b/CPP/7zip/Common/FilePathAutoRename.h
@@ -1,10 +1,10 @@
-// FilePathAutoRename.h

-

-#ifndef __FILE_PATH_AUTO_RENAME_H

-#define __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 11c14d2..4298636 100644
--- a/CPP/7zip/Common/FileStreams.cpp
+++ b/CPP/7zip/Common/FileStreams.cpp
@@ -1,475 +1,800 @@
-// FileStreams.cpp

-

-#include "StdAfx.h"

-

-#ifndef _WIN32

-#include <fcntl.h>

-#include <unistd.h>

-#include <errno.h>

-#endif

-

-#ifdef SUPPORT_DEVICE_FILE

-#include "../../../C/Alloc.h"

-#include "../../Common/Defs.h"

-#endif

-

-#include "FileStreams.h"

-

-static inline HRESULT ConvertBoolToHRESULT(bool result)

-{

-  #ifdef _WIN32

-  if (result)

-    return S_OK;

-  DWORD lastError = ::GetLastError();

-  if (lastError == 0)

-    return E_FAIL;

-  return HRESULT_FROM_WIN32(lastError);

-  #else

-  return result ? S_OK: E_FAIL;

-  #endif

-}

-

-

-static const UInt32 kClusterSize = 1 << 18;

-CInFileStream::CInFileStream():

-  #ifdef SUPPORT_DEVICE_FILE

-  VirtPos(0),

-  PhyPos(0),

-  Buf(0),

-  BufSize(0),

-  #endif

-  SupportHardLinks(false),

-  Callback(NULL),

-  CallbackRef(0)

-{

-}

-

-CInFileStream::~CInFileStream()

-{

-  #ifdef SUPPORT_DEVICE_FILE

-  MidFree(Buf);

-  #endif

-

-  if (Callback)

-    Callback->InFileStream_On_Destroy(CallbackRef);

-}

-

-STDMETHODIMP CInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize)

-{

-  #ifdef USE_WIN_FILE

-  

-  #ifdef SUPPORT_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;

-      UInt64 rem = File.Size - VirtPos;

-      if (size > rem)

-        size = (UInt32)rem;

-    }

-    for (;;)

-    {

-      const UInt32 mask = kClusterSize - 1;

-      const UInt64 mask2 = ~(UInt64)mask;

-      UInt64 alignedPos = VirtPos & mask2;

-      if (BufSize > 0 && BufStartPos == alignedPos)

-      {

-        UInt32 pos = (UInt32)VirtPos & mask;

-        if (pos >= BufSize)

-          return S_OK;

-        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 || ((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;

-        bool result = File.Seek(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;

-      }

-      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(VirtPos, FILE_BEGIN, realNewPosition);

-      if (!result)

-        return ConvertBoolToHRESULT(result);

-      PhyPos = VirtPos = realNewPosition;

-    }

-  }

-  #endif

-

-  UInt32 realProcessedSize;

-  bool result = File.ReadPart(data, size, realProcessedSize);

-  if (processedSize)

-    *processedSize = realProcessedSize;

-

-  #ifdef SUPPORT_DEVICE_FILE

-  VirtPos += realProcessedSize;

-  PhyPos += realProcessedSize;

-  #endif

-

-  if (result)

-    return S_OK;

-

-  {

-    DWORD error = ::GetLastError();

-

-    if (Callback)

-      return Callback->InFileStream_On_Error(CallbackRef, error);

-    if (error == 0)

-      return E_FAIL;

-

-    return HRESULT_FROM_WIN32(error);

-  }

-

-  #else

-  

-  if (processedSize)

-    *processedSize = 0;

-  ssize_t res = File.Read(data, (size_t)size);

-  if (res == -1)

-  {

-    if (Callback)

-      return Callback->InFileStream_On_Error(CallbackRef, E_FAIL);

-    return E_FAIL;

-  }

-  if (processedSize)

-    *processedSize = (UInt32)res;

-  return S_OK;

-

-  #endif

-}

-

-#ifdef UNDER_CE

-STDMETHODIMP 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

-STDMETHODIMP CStdInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize)

-{

-  #ifdef _WIN32

-  

-  DWORD realProcessedSize;

-  UInt32 sizeTemp = (1 << 20);

-  if (sizeTemp > size)

-    sizeTemp = size;

-  BOOL res = ::ReadFile(GetStdHandle(STD_INPUT_HANDLE), data, sizeTemp, &realProcessedSize, NULL);

-  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 E_FAIL;

-  if (processedSize)

-    *processedSize = (UInt32)res;

-  return S_OK;

-  

-  #endif

-}

-  

-#endif

-

-STDMETHODIMP CInFileStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)

-{

-  if (seekOrigin >= 3)

-    return STG_E_INVALIDFUNCTION;

-

-  #ifdef USE_WIN_FILE

-

-  #ifdef SUPPORT_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 = offset;

-    if (newPosition)

-      *newPosition = offset;

-    return S_OK;

-  }

-  #endif

-  

-  UInt64 realNewPosition;

-  bool result = File.Seek(offset, seekOrigin, realNewPosition);

-  

-  #ifdef SUPPORT_DEVICE_FILE

-  PhyPos = VirtPos = realNewPosition;

-  #endif

-

-  if (newPosition)

-    *newPosition = realNewPosition;

-  return ConvertBoolToHRESULT(result);

-  

-  #else

-  

-  off_t res = File.Seek((off_t)offset, seekOrigin);

-  if (res == -1)

-    return E_FAIL;

-  if (newPosition)

-    *newPosition = (UInt64)res;

-  return S_OK;

-  

-  #endif

-}

-

-STDMETHODIMP CInFileStream::GetSize(UInt64 *size)

-{

-  return ConvertBoolToHRESULT(File.GetLength(*size));

-}

-

-#ifdef USE_WIN_FILE

-

-STDMETHODIMP CInFileStream::GetProps(UInt64 *size, FILETIME *cTime, FILETIME *aTime, FILETIME *mTime, UInt32 *attrib)

-{

-  BY_HANDLE_FILE_INFORMATION info;

-  if (File.GetFileInformation(&info))

-  {

-    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;

-  }

-  return GetLastError();

-}

-

-STDMETHODIMP CInFileStream::GetProps2(CStreamFileProps *props)

-{

-  BY_HANDLE_FILE_INFORMATION info;

-  if (File.GetFileInformation(&info))

-  {

-    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;

-  }

-  return GetLastError();

-}

-

-#endif

-

-//////////////////////////

-// COutFileStream

-

-HRESULT COutFileStream::Close()

-{

-  return ConvertBoolToHRESULT(File.Close());

-}

-

-STDMETHODIMP COutFileStream::Write(const void *data, UInt32 size, UInt32 *processedSize)

-{

-  #ifdef USE_WIN_FILE

-

-  UInt32 realProcessedSize;

-  bool result = File.Write(data, size, realProcessedSize);

-  ProcessedSize += realProcessedSize;

-  if (processedSize)

-    *processedSize = realProcessedSize;

-  return ConvertBoolToHRESULT(result);

-  

-  #else

-  

-  if (processedSize)

-    *processedSize = 0;

-  ssize_t res = File.Write(data, (size_t)size);

-  if (res == -1)

-    return E_FAIL;

-  if (processedSize)

-    *processedSize = (UInt32)res;

-  ProcessedSize += res;

-  return S_OK;

-  

-  #endif

-}

-  

-STDMETHODIMP COutFileStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)

-{

-  if (seekOrigin >= 3)

-    return STG_E_INVALIDFUNCTION;

-  

-  #ifdef USE_WIN_FILE

-

-  UInt64 realNewPosition;

-  bool result = File.Seek(offset, seekOrigin, realNewPosition);

-  if (newPosition)

-    *newPosition = realNewPosition;

-  return ConvertBoolToHRESULT(result);

-  

-  #else

-  

-  off_t res = File.Seek((off_t)offset, seekOrigin);

-  if (res == -1)

-    return E_FAIL;

-  if (newPosition)

-    *newPosition = (UInt64)res;

-  return S_OK;

-  

-  #endif

-}

-

-STDMETHODIMP COutFileStream::SetSize(UInt64 newSize)

-{

-  #ifdef USE_WIN_FILE

-  

-  UInt64 currentPos;

-  if (!File.Seek(0, FILE_CURRENT, currentPos))

-    return E_FAIL;

-  bool result = File.SetLength(newSize);

-  UInt64 currentPos2;

-  result = result && File.Seek(currentPos, currentPos2);

-  return result ? S_OK : E_FAIL;

-  

-  #else

-  

-  return E_FAIL;

-  

-  #endif

-}

-

-HRESULT COutFileStream::GetSize(UInt64 *size)

-{

-  return ConvertBoolToHRESULT(File.GetLength(*size));

-}

-

-#ifdef UNDER_CE

-

-STDMETHODIMP 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

-

-STDMETHODIMP 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 E_FAIL;

-

-  _size += (size_t)res;

-  if (processedSize)

-    *processedSize = (UInt32)res;

-  return S_OK;

-  

-  #endif

-}

-

-#endif

+// FileStreams.cpp
+
+#include "StdAfx.h"
+
+// #include <stdio.h>
+
+#ifndef _WIN32
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <grp.h>
+#include <pwd.h>
+
+// for major()/minor():
+#include <sys/types.h>
+#if defined(__FreeBSD__) || defined(BSD) || defined(__APPLE__)
+#else
+#ifndef major
+#include <sys/sysmacros.h>
+#endif
+#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))
+{
+  #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 (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))
+{
+  #ifdef _WIN32
+  
+  DWORD realProcessedSize;
+  UInt32 sizeTemp = (1 << 20);
+  if (sizeTemp > size)
+    sizeTemp = size;
+  BOOL res = ::ReadFile(GetStdHandle(STD_INPUT_HANDLE), data, sizeTemp, &realProcessedSize, NULL);
+  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
+
+Z7_COM7F_IMF(CInFileStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
+{
+  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();
+  return S_OK;
+}
+
+
+#elif !defined(_WIN32)
+
+Z7_COM7F_IMF(CInFileStream::GetProps(UInt64 *size, FILETIME *cTime, FILETIME *aTime, FILETIME *mTime, UInt32 *attrib))
+{
+  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 <stdio.h>
+
+Z7_COM7F_IMF(CInFileStream::GetProps2(CStreamFileProps *props))
+{
+  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))
+{
+  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;
+      }
+    }
+  }
+  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 a0996f8..7e1b086 100644
--- a/CPP/7zip/Common/FileStreams.h
+++ b/CPP/7zip/Common/FileStreams.h
@@ -1,166 +1,186 @@
-// FileStreams.h

-

-#ifndef __FILE_STREAMS_H

-#define __FILE_STREAMS_H

-

-#ifdef _WIN32

-#define USE_WIN_FILE

-#endif

-

-#include "../../Common/MyString.h"

-

-#ifdef USE_WIN_FILE

-#include "../../Windows/FileIO.h"

-#else

-#include "../../Common/C_FileIO.h"

-#endif

-

-#include "../../Common/MyCom.h"

-

-#include "../IStream.h"

-

-#ifdef _WIN32

-typedef UINT_PTR My_UINT_PTR;

-#else

-typedef UINT My_UINT_PTR;

-#endif

-

-struct IInFileStream_Callback

-{

-  virtual HRESULT InFileStream_On_Error(My_UINT_PTR val, DWORD error) = 0;

-  virtual void InFileStream_On_Destroy(My_UINT_PTR val) = 0;

-};

-

-class CInFileStream:

-  public IInStream,

-  public IStreamGetSize,

-  #ifdef USE_WIN_FILE

-  public IStreamGetProps,

-  public IStreamGetProps2,

-  #endif

-  public CMyUnknownImp

-{

-public:

-  #ifdef USE_WIN_FILE

-  NWindows::NFile::NIO::CInFile File;

-  

-  #ifdef SUPPORT_DEVICE_FILE

-  UInt64 VirtPos;

-  UInt64 PhyPos;

-  UInt64 BufStartPos;

-  Byte *Buf;

-  UInt32 BufSize;

-  #endif

-

-  #else

-  NC::NFile::NIO::CInFile File;

-  #endif

-

-  bool SupportHardLinks;

-

-  IInFileStream_Callback *Callback;

-  My_UINT_PTR CallbackRef;

-

-  virtual ~CInFileStream();

-

-  CInFileStream();

-  

-  bool Open(CFSTR fileName)

-  {

-    return File.Open(fileName);

-  }

-  

-  bool OpenShared(CFSTR fileName, bool shareForWrite)

-  {

-    return File.OpenShared(fileName, shareForWrite);

-  }

-

-  MY_QUERYINTERFACE_BEGIN2(IInStream)

-  MY_QUERYINTERFACE_ENTRY(IStreamGetSize)

-  #ifdef USE_WIN_FILE

-  MY_QUERYINTERFACE_ENTRY(IStreamGetProps)

-  MY_QUERYINTERFACE_ENTRY(IStreamGetProps2)

-  #endif

-  MY_QUERYINTERFACE_END

-  MY_ADDREF_RELEASE

-

-  STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);

-  STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);

-

-  STDMETHOD(GetSize)(UInt64 *size);

-  #ifdef USE_WIN_FILE

-  STDMETHOD(GetProps)(UInt64 *size, FILETIME *cTime, FILETIME *aTime, FILETIME *mTime, UInt32 *attrib);

-  STDMETHOD(GetProps2)(CStreamFileProps *props);

-  #endif

-};

-

-class CStdInFileStream:

-  public ISequentialInStream,

-  public CMyUnknownImp

-{

-public:

-  MY_UNKNOWN_IMP

-

-  virtual ~CStdInFileStream() {}

-  STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);

-};

-

-class COutFileStream:

-  public IOutStream,

-  public CMyUnknownImp

-{

-public:

-  #ifdef USE_WIN_FILE

-  NWindows::NFile::NIO::COutFile File;

-  #else

-  NC::NFile::NIO::COutFile File;

-  #endif

-  virtual ~COutFileStream() {}

-  bool Create(CFSTR fileName, bool createAlways)

-  {

-    ProcessedSize = 0;

-    return File.Create(fileName, createAlways);

-  }

-  bool Open(CFSTR fileName, DWORD creationDisposition)

-  {

-    ProcessedSize = 0;

-    return File.Open(fileName, creationDisposition);

-  }

-

-  HRESULT Close();

-  

-  UInt64 ProcessedSize;

-

-  #ifdef USE_WIN_FILE

-  bool SetTime(const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime)

-  {

-    return File.SetTime(cTime, aTime, mTime);

-  }

-  bool SetMTime(const FILETIME *mTime) {  return File.SetMTime(mTime); }

-  #endif

-

-

-  MY_UNKNOWN_IMP1(IOutStream)

-

-  STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);

-  STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);

-  STDMETHOD(SetSize)(UInt64 newSize);

-

-  HRESULT GetSize(UInt64 *size);

-};

-

-class CStdOutFileStream:

-  public ISequentialOutStream,

-  public CMyUnknownImp

-{

-  UInt64 _size;

-public:

-  MY_UNKNOWN_IMP

-

-  UInt64 GetSize() const { return _size; }

-  CStdOutFileStream(): _size(0) {}

-  virtual ~CStdOutFileStream() {}

-  STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);

-};

-

-#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_5(
+      IInStream,
+      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);
+  }
+  
+  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);
+  }
+};
+
+
+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(CFSTR fileName, bool createAlways)
+  {
+    ProcessedSize = 0;
+    return File.Create(fileName, createAlways);
+  }
+  bool Open(CFSTR fileName, DWORD creationDisposition)
+  {
+    ProcessedSize = 0;
+    return File.Open(fileName, creationDisposition);
+  }
+
+  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 d5c7ff0..8d7e0dc 100644
--- a/CPP/7zip/Common/FilterCoder.cpp
+++ b/CPP/7zip/Common/FilterCoder.cpp
@@ -1,435 +1,577 @@
-// FilterCoder.cpp

-

-#include "StdAfx.h"

-

-#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.

-*/

-

-

-static const UInt32 kBufSize = 1 << 20;

-

-STDMETHODIMP CFilterCoder::SetInBufSize(UInt32 , UInt32 size) { _inBufSize = size; return S_OK; }

-STDMETHODIMP 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;

-  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),

-    _outSizeIsDefined(false),

-    _outSize(0),

-    _nowPos64(0)

-  {}

-

-CFilterCoder::~CFilterCoder()

-{

-}

-

-STDMETHODIMP CFilterCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,

-    const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)

-{

-  RINOK(Init_and_Alloc());

-  

-  UInt64 nowPos64 = 0;

-  bool inputFinished = false;

-  UInt32 pos = 0;

-

-  while (!outSize || nowPos64 < *outSize)

-  {

-    UInt32 endPos = pos;

-    

-    if (!inputFinished)

-    {

-      size_t processedSize = _bufSize - pos;

-      RINOK(ReadStream(inStream, _buf + pos, &processedSize));

-      endPos = pos + (UInt32)processedSize;

-      inputFinished = (endPos != _bufSize);

-    }

-

-    pos = Filter->Filter(_buf, endPos);

-    

-    if (pos > endPos)

-    {

-      // AES

-      if (!inputFinished || pos > _bufSize)

-        return E_FAIL;

-      if (!_encodeMode)

-        return S_FALSE;

-      

-      do

-        _buf[endPos] = 0;

-      while (++endPos != pos);

-      

-      if (pos != Filter->Filter(_buf, pos))

-        return E_FAIL;

-    }

-

-    if (endPos == 0)

-      return S_OK;

-

-    UInt32 size = (pos != 0 ? pos : endPos);

-    if (outSize)

-    {

-      UInt64 remSize = *outSize - nowPos64;

-      if (size > remSize)

-        size = (UInt32)remSize;

-    }

-    

-    RINOK(WriteStream(outStream, _buf, size));

-    nowPos64 += size;

-

-    if (pos == 0)

-      return S_OK;

-

-    if (progress)

-      RINOK(progress->SetRatioInfo(&nowPos64, &nowPos64));

-

-    UInt32 i = 0;

-    while (pos < endPos)

-      _buf[i++] = _buf[pos++];

-    pos = i;

-  }

-

-  return S_OK;

-}

-

-

-

-// ---------- Write to Filter ----------

-

-STDMETHODIMP CFilterCoder::SetOutStream(ISequentialOutStream *outStream)

-{

-  _outStream = outStream;

-  return S_OK;

-}

-

-STDMETHODIMP CFilterCoder::ReleaseOutStream()

-{

-  _outStream.Release();

-  return S_OK;

-}

-

-HRESULT CFilterCoder::Flush2()

-{

-  while (_convSize != 0)

-  {

-    UInt32 num = _convSize;

-    if (_outSizeIsDefined)

-    {

-      UInt64 rem = _outSize - _nowPos64;

-      if (num > rem)

-        num = (UInt32)rem;

-      if (num == 0)

-        return k_My_HRESULT_WritingWasCut;

-    }

-    

-    UInt32 processed = 0;

-    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);

-  }

-    

-  if (_convPos != 0)

-  {

-    UInt32 num = _bufPos - _convPos;

-    for (UInt32 i = 0; i < num; i++)

-      _buf[i] = _buf[_convPos + i];

-    _bufPos = num;

-    _convPos = 0;

-  }

-    

-  return S_OK;

-}

-

-STDMETHODIMP 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;

-}

-

-STDMETHODIMP CFilterCoder::OutStreamFinish()

-{

-  for (;;)

-  {

-    RINOK(Flush2());

-    if (_bufPos == 0)

-      break;

-    _convSize = Filter->Filter(_buf, _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;

-      }

-      for (; _bufPos < _convSize; _bufPos++)

-        _buf[_bufPos] = 0;

-      _convSize = Filter->Filter(_buf, _bufPos);

-      if (_convSize != _bufPos)

-        return E_FAIL;

-    }

-  }

-  

-  CMyComPtr<IOutStreamFinish> finish;

-  _outStream.QueryInterface(IID_IOutStreamFinish, &finish);

-  if (finish)

-    return finish->OutStreamFinish();

-  return S_OK;

-}

-

-// ---------- Init functions ----------

-

-STDMETHODIMP CFilterCoder::InitEncoder()

-{

-  InitSpecVars();

-  return Init_and_Alloc();

-}

-

-HRESULT CFilterCoder::Init_NoSubFilterInit()

-{

-  InitSpecVars();

-  return Alloc();

-}

-

-STDMETHODIMP CFilterCoder::SetOutStreamSize(const UInt64 *outSize)

-{

-  InitSpecVars();

-  if (outSize)

-  {

-    _outSize = *outSize;

-    _outSizeIsDefined = true;

-  }

-  return Init_and_Alloc();

-}

-

-// ---------- Read from Filter ----------

-

-STDMETHODIMP CFilterCoder::SetInStream(ISequentialInStream *inStream)

-{

-  _inStream = inStream;

-  return S_OK;

-}

-

-STDMETHODIMP CFilterCoder::ReleaseInStream()

-{

-  _inStream.Release();

-  return S_OK;

-}

-

-

-STDMETHODIMP CFilterCoder::Read(void *data, UInt32 size, UInt32 *processedSize)

-{

-  if (processedSize)

-    *processedSize = 0;

-  

-  while (size != 0)

-  {

-    if (_convSize != 0)

-    {

-      if (size > _convSize)

-        size = _convSize;

-      if (_outSizeIsDefined)

-      {

-        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;

-    }

-  

-    if (_convPos != 0)

-    {

-      UInt32 num = _bufPos - _convPos;

-      for (UInt32 i = 0; i < num; i++)

-        _buf[i] = _buf[_convPos + i];

-      _bufPos = num;

-      _convPos = 0;

-    }

-    

-    {

-      size_t readSize = _bufSize - _bufPos;

-      HRESULT res = ReadStream(_inStream, _buf + _bufPos, &readSize);

-      _bufPos += (UInt32)readSize;

-      RINOK(res);

-    }

-    

-    _convSize = Filter->Filter(_buf, _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;

-      

-      do

-        _buf[_bufPos] = 0;

-      while (++_bufPos != _convSize);

-      

-      _convSize = Filter->Filter(_buf, _convSize);

-      if (_convSize != _bufPos)

-        return E_FAIL;

-    }

-  }

- 

-  return S_OK;

-}

-

-

-#ifndef _NO_CRYPTO

-

-STDMETHODIMP CFilterCoder::CryptoSetPassword(const Byte *data, UInt32 size)

-  { return _SetPassword->CryptoSetPassword(data, size); }

-

-STDMETHODIMP CFilterCoder::SetKey(const Byte *data, UInt32 size)

-  { return _CryptoProperties->SetKey(data, size); }

-

-STDMETHODIMP CFilterCoder::SetInitVector(const Byte *data, UInt32 size)

-  { return _CryptoProperties->SetInitVector(data, size); }

-

-#endif

-

-

-#ifndef EXTRACT_ONLY

-

-STDMETHODIMP CFilterCoder::SetCoderProperties(const PROPID *propIDs,

-    const PROPVARIANT *properties, UInt32 numProperties)

-  { return _SetCoderProperties->SetCoderProperties(propIDs, properties, numProperties); }

-

-STDMETHODIMP CFilterCoder::WriteCoderProperties(ISequentialOutStream *outStream)

-  { return _WriteCoderProperties->WriteCoderProperties(outStream); }

-

-/*

-STDMETHODIMP CFilterCoder::ResetSalt()

-  { return _CryptoResetSalt->ResetSalt(); }

-*/

-

-STDMETHODIMP CFilterCoder::ResetInitVector()

-  { return _CryptoResetInitVector->ResetInitVector(); }

-

-#endif

-

-

-STDMETHODIMP CFilterCoder::SetDecoderProperties2(const Byte *data, UInt32 size)

-  { return _SetDecoderProperties2->SetDecoderProperties2(data, size); }

+// FilterCoder.cpp
+
+#include "StdAfx.h"
+
+// #include <stdio.h>
+
+#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<IOutStreamFinish> 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 bde0e2b..3a588fd 100644
--- a/CPP/7zip/Common/FilterCoder.h
+++ b/CPP/7zip/Common/FilterCoder.h
@@ -1,205 +1,201 @@
-// FilterCoder.h

-

-#ifndef __FILTER_CODER_H

-#define __FILTER_CODER_H

-

-#include "../../../C/Alloc.h"

-

-#include "../../Common/MyCom.h"

-#include "../ICoder.h"

-

-#ifndef _NO_CRYPTO

-#include "../IPassword.h"

-#endif

-

-#define MY_QUERYINTERFACE_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:

-  public ICompressCoder,

-  

-  public ICompressSetOutStreamSize,

-  public ICompressInitEncoder,

- 

-  public ICompressSetInStream,

-  public ISequentialInStream,

-  

-  public ICompressSetOutStream,

-  public ISequentialOutStream,

-  public IOutStreamFinish,

-  

-  public ICompressSetBufSize,

-

-  #ifndef _NO_CRYPTO

-  public ICryptoSetPassword,

-  public ICryptoProperties,

-  #endif

-  

-  #ifndef EXTRACT_ONLY

-  public ICompressSetCoderProperties,

-  public ICompressWriteCoderProperties,

-  // public ICryptoResetSalt,

-  public ICryptoResetInitVector,

-  #endif

-  

-  public ICompressSetDecoderProperties2,

-  public CMyUnknownImp,

-  public CAlignedMidBuffer

-{

-  UInt32 _bufSize;

-  UInt32 _inBufSize;

-  UInt32 _outBufSize;

-

-  bool _encodeMode;

-  bool _outSizeIsDefined;

-  UInt64 _outSize;

-  UInt64 _nowPos64;

-

-  CMyComPtr<ISequentialInStream> _inStream;

-  CMyComPtr<ISequentialOutStream> _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;

-

-    _outSizeIsDefined = false;

-    _outSize = 0;

-    _nowPos64 = 0;

-  }

-

-  HRESULT Alloc();

-  HRESULT Init_and_Alloc();

-  HRESULT Flush2();

-

-  #ifndef _NO_CRYPTO

-  CMyComPtr<ICryptoSetPassword> _SetPassword;

-  CMyComPtr<ICryptoProperties> _CryptoProperties;

-  #endif

-

-  #ifndef EXTRACT_ONLY

-  CMyComPtr<ICompressSetCoderProperties> _SetCoderProperties;

-  CMyComPtr<ICompressWriteCoderProperties> _WriteCoderProperties;

-  // CMyComPtr<ICryptoResetSalt> _CryptoResetSalt;

-  CMyComPtr<ICryptoResetInitVector> _CryptoResetInitVector;

-  #endif

-

-  CMyComPtr<ICompressSetDecoderProperties2> _SetDecoderProperties2;

-

-public:

-  CMyComPtr<ICompressFilter> Filter;

-

-  CFilterCoder(bool encodeMode);

-  ~CFilterCoder();

-

-  class C_InStream_Releaser

-  {

-  public:

-    CFilterCoder *FilterCoder;

-    C_InStream_Releaser(): FilterCoder(NULL) {}

-    ~C_InStream_Releaser() { if (FilterCoder) FilterCoder->ReleaseInStream(); }

-  };

-  

-  class C_OutStream_Releaser

-  {

-  public:

-    CFilterCoder *FilterCoder;

-    C_OutStream_Releaser(): FilterCoder(NULL) {}

-    ~C_OutStream_Releaser() { if (FilterCoder) FilterCoder->ReleaseOutStream(); }

-  };

-

-  class C_Filter_Releaser

-  {

-  public:

-    CFilterCoder *FilterCoder;

-    C_Filter_Releaser(): FilterCoder(NULL) {}

-    ~C_Filter_Releaser() { if (FilterCoder) FilterCoder->Filter.Release(); }

-  };

-  

-

-  MY_QUERYINTERFACE_BEGIN2(ICompressCoder)

-

-    MY_QUERYINTERFACE_ENTRY(ICompressSetOutStreamSize)

-    MY_QUERYINTERFACE_ENTRY(ICompressInitEncoder)

-    

-    MY_QUERYINTERFACE_ENTRY(ICompressSetInStream)

-    MY_QUERYINTERFACE_ENTRY(ISequentialInStream)

-    

-    MY_QUERYINTERFACE_ENTRY(ICompressSetOutStream)

-    MY_QUERYINTERFACE_ENTRY(ISequentialOutStream)

-    MY_QUERYINTERFACE_ENTRY(IOutStreamFinish)

-    

-    MY_QUERYINTERFACE_ENTRY(ICompressSetBufSize)

-

-    #ifndef _NO_CRYPTO

-    MY_QUERYINTERFACE_ENTRY_AG(ICryptoSetPassword, Filter, _SetPassword)

-    MY_QUERYINTERFACE_ENTRY_AG(ICryptoProperties, Filter, _CryptoProperties)

-    #endif

-

-    #ifndef EXTRACT_ONLY

-    MY_QUERYINTERFACE_ENTRY_AG(ICompressSetCoderProperties, Filter, _SetCoderProperties)

-    MY_QUERYINTERFACE_ENTRY_AG(ICompressWriteCoderProperties, Filter, _WriteCoderProperties)

-    // MY_QUERYINTERFACE_ENTRY_AG(ICryptoResetSalt, Filter, _CryptoResetSalt)

-    MY_QUERYINTERFACE_ENTRY_AG(ICryptoResetInitVector, Filter, _CryptoResetInitVector)

-    #endif

-

-    MY_QUERYINTERFACE_ENTRY_AG(ICompressSetDecoderProperties2, Filter, _SetDecoderProperties2)

-  MY_QUERYINTERFACE_END

-  MY_ADDREF_RELEASE

-  

-  

-  STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,

-      const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);

-  

-  STDMETHOD(SetOutStreamSize)(const UInt64 *outSize);

-  STDMETHOD(InitEncoder)();

-

-  STDMETHOD(SetInStream)(ISequentialInStream *inStream);

-  STDMETHOD(ReleaseInStream)();

-  STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);

-

-  STDMETHOD(SetOutStream)(ISequentialOutStream *outStream);

-  STDMETHOD(ReleaseOutStream)();

-  STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);

-  STDMETHOD(OutStreamFinish)();

-  

-  STDMETHOD(SetInBufSize)(UInt32 streamIndex, UInt32 size);

-  STDMETHOD(SetOutBufSize)(UInt32 streamIndex, UInt32 size);

-

-  #ifndef _NO_CRYPTO

-  STDMETHOD(CryptoSetPassword)(const Byte *data, UInt32 size);

-

-  STDMETHOD(SetKey)(const Byte *data, UInt32 size);

-  STDMETHOD(SetInitVector)(const Byte *data, UInt32 size);

-  #endif

-  

-  #ifndef EXTRACT_ONLY

-  STDMETHOD(SetCoderProperties)(const PROPID *propIDs,

-      const PROPVARIANT *properties, UInt32 numProperties);

-  STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStream);

-  // STDMETHOD(ResetSalt)();

-  STDMETHOD(ResetInitVector)();

-  #endif

-  

-  STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);

-

-  

-  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<ISequentialInStream> _inStream;
+  CMyComPtr<ISequentialOutStream> _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<ICryptoSetPassword> _setPassword;
+  CMyComPtr<ICryptoProperties> _cryptoProperties;
+  #endif
+
+  #ifndef Z7_EXTRACT_ONLY
+  CMyComPtr<ICompressSetCoderProperties> _setCoderProperties;
+  CMyComPtr<ICompressWriteCoderProperties> _writeCoderProperties;
+  CMyComPtr<ICompressSetCoderPropertiesOpt> _setCoderPropertiesOpt;
+  // CMyComPtr<ICryptoResetSalt> _cryptoResetSalt;
+  CMyComPtr<ICryptoResetInitVector> _cryptoResetInitVector;
+  #endif
+
+  CMyComPtr<ICompressSetDecoderProperties2> _setDecoderProperties2;
+
+public:
+  CMyComPtr<ICompressFilter> 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 826e98b..b0f222c 100644
--- a/CPP/7zip/Common/InBuffer.cpp
+++ b/CPP/7zip/Common/InBuffer.cpp
@@ -1,163 +1,164 @@
-// InBuffer.cpp

-

-#include "StdAfx.h"

-

-#include "../../../C/Alloc.h"

-

-#include "InBuffer.h"

-

-CInBufferBase::CInBufferBase() throw():

-  _buf(0),

-  _bufLim(0),

-  _bufBase(0),

-  _stream(0),

-  _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 != 0 && _bufSize == bufSize)

-    return true;

-  Free();

-  _bufSize = bufSize;

-  _bufBase = (Byte *)::MidAlloc(bufSize);

-  return (_bufBase != 0);

-}

-

-void CInBuffer::Free() throw()

-{

-  ::MidFree(_bufBase);

-  _bufBase = 0;

-}

-

-void CInBufferBase::Init() throw()

-{

-  _processedSize = 0;

-  _buf = _bufBase;

-  _bufLim = _buf;

-  _wasFinished = false;

-  #ifdef _NO_EXCEPTIONS

-  ErrorCode = S_OK;

-  #endif

-  NumExtraBytes = 0;

-}

-

-bool CInBufferBase::ReadBlock()

-{

-  #ifdef _NO_EXCEPTIONS

-  if (ErrorCode != S_OK)

-    return false;

-  #endif

-  if (_wasFinished)

-    return false;

-  _processedSize += (_buf - _bufBase);

-  _buf = _bufBase;

-  _bufLim = _bufBase;

-  UInt32 processed;

-  // FIX_ME: we can improve it to support (_bufSize >= (1 << 32))

-  HRESULT result = _stream->Read(_bufBase, (UInt32)_bufSize, &processed);

-  #ifdef _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())

-  {

-    NumExtraBytes++;

-    b = 0xFF;

-    return false;

-  }

-  b = *_buf++;

-  return true;

-}

-

-Byte CInBufferBase::ReadByte_FromNewBlock()

-{

-  if (!ReadBlock())

-  {

-    NumExtraBytes++;

-    return 0xFF;

-  }

-  return *_buf++;

-}

-

-size_t CInBufferBase::ReadBytes(Byte *buf, size_t size)

-{

-  size_t num = 0;

-  for (;;)

-  {

-    const size_t rem = _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 (;;)

-  {

-    size_t rem = (_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::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 76e359a..3aaf797 100644
--- a/CPP/7zip/Common/InBuffer.h
+++ b/CPP/7zip/Common/InBuffer.h
@@ -1,92 +1,109 @@
-// InBuffer.h

-

-#ifndef __IN_BUFFER_H

-#define __IN_BUFFER_H

-

-#include "../../Common/MyException.h"

-#include "../IStream.h"

-

-#ifndef _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 _NO_EXCEPTIONS

-  HRESULT ErrorCode;

-  #endif

-  UInt32 NumExtraBytes;

-

-  CInBufferBase() throw();

-

-  UInt64 GetStreamSize() const { return _processedSize + (_buf - _bufBase); }

-  UInt64 GetProcessedSize() const { return _processedSize + NumExtraBytes + (_buf - _bufBase); }

-  bool WasFinished() const { return _wasFinished; }

-

-  void SetStream(ISequentialInStream *stream) { _stream = stream; }

-  

-  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 _NO_EXCEPTIONS

-    ErrorCode = S_OK;

-    #endif

-    NumExtraBytes = 0;

-  }

-

-  void Init() throw();

-  

-  MY_FORCE_INLINE

-  bool ReadByte(Byte &b)

-  {

-    if (_buf >= _bufLim)

-      return ReadByte_FromNewBlock(b);

-    b = *_buf++;

-    return true;

-  }

-  

-  MY_FORCE_INLINE

-  Byte ReadByte()

-  {

-    if (_buf >= _bufLim)

-      return ReadByte_FromNewBlock();

-    return *_buf++;

-  }

-  

-  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 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 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 d83d674..3f7272e 100644
--- a/CPP/7zip/Common/InOutTempBuffer.cpp
+++ b/CPP/7zip/Common/InOutTempBuffer.cpp
@@ -1,127 +1,237 @@
-// InOutTempBuffer.cpp

-

-#include "StdAfx.h"

-

-#include "../../../C/7zCrc.h"

-

-#include "../../Common/Defs.h"

-

-#include "InOutTempBuffer.h"

-#include "StreamUtils.h"

-

-using namespace NWindows;

-using namespace NFile;

-using namespace NDir;

-

-static const size_t kTempBufSize = (1 << 20);

-

-#define kTempFilePrefixString FTEXT("7zt")

-

-CInOutTempBuffer::CInOutTempBuffer(): _buf(NULL) { }

-

-void CInOutTempBuffer::Create()

-{

-  if (!_buf)

-    _buf = new Byte[kTempBufSize];

-}

-

-CInOutTempBuffer::~CInOutTempBuffer()

-{

-  delete []_buf;

-}

-

-void CInOutTempBuffer::InitWriting()

-{

-  _bufPos = 0;

-  _tempFileCreated = false;

-  _size = 0;

-  _crc = CRC_INIT_VAL;

-}

-

-bool CInOutTempBuffer::WriteToFile(const void *data, UInt32 size)

-{

-  if (size == 0)

-    return true;

-  if (!_tempFileCreated)

-  {

-    if (!_tempFile.CreateRandomInTempFolder(kTempFilePrefixString, &_outFile))

-      return false;

-    _tempFileCreated = true;

-  }

-  UInt32 processed;

-  if (!_outFile.Write(data, size, processed))

-    return false;

-  _crc = CrcUpdate(_crc, data, processed);

-  _size += processed;

-  return (processed == size);

-}

-

-bool CInOutTempBuffer::Write(const void *data, UInt32 size)

-{

-  if (size == 0)

-    return true;

-  size_t cur = kTempBufSize - _bufPos;

-  if (cur != 0)

-  {

-    if (cur > size)

-      cur = size;

-    memcpy(_buf + _bufPos, data, cur);

-    _crc = CrcUpdate(_crc, data, cur);

-    _bufPos += cur;

-    _size += cur;

-    size -= (UInt32)cur;

-    data = ((const Byte *)data) + cur;

-  }

-  return WriteToFile(data, size);

-}

-

-HRESULT CInOutTempBuffer::WriteToStream(ISequentialOutStream *stream)

-{

-  if (!_outFile.Close())

-    return E_FAIL;

-

-  UInt64 size = 0;

-  UInt32 crc = CRC_INIT_VAL;

-

-  if (_bufPos != 0)

-  {

-    RINOK(WriteStream(stream, _buf, _bufPos));

-    crc = CrcUpdate(crc, _buf, _bufPos);

-    size += _bufPos;

-  }

-  

-  if (_tempFileCreated)

-  {

-    NIO::CInFile inFile;

-    if (!inFile.Open(_tempFile.GetPath()))

-      return E_FAIL;

-    while (size < _size)

-    {

-      UInt32 processed;

-      if (!inFile.ReadPart(_buf, kTempBufSize, processed))

-        return E_FAIL;

-      if (processed == 0)

-        break;

-      RINOK(WriteStream(stream, _buf, processed));

-      crc = CrcUpdate(crc, _buf, processed);

-      size += processed;

-    }

-  }

-  

-  return (_crc == crc && size == _size) ? S_OK : E_FAIL;

-}

-

-/*

-STDMETHODIMP CSequentialOutTempBufferImp::Write(const void *data, UInt32 size, UInt32 *processed)

-{

-  if (!_buf->Write(data, size))

-  {

-    if (processed)

-      *processed = 0;

-    return E_FAIL;

-  }

-  if (processed)

-    *processed = size;

-  return S_OK;

-}

-*/

+// 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 4140d28..345c386 100644
--- a/CPP/7zip/Common/InOutTempBuffer.h
+++ b/CPP/7zip/Common/InOutTempBuffer.h
@@ -1,48 +1,45 @@
-// InOutTempBuffer.h

-

-#ifndef __IN_OUT_TEMP_BUFFER_H

-#define __IN_OUT_TEMP_BUFFER_H

-

-#include "../../Common/MyCom.h"

-#include "../../Windows/FileDir.h"

-

-#include "../IStream.h"

-

-class CInOutTempBuffer

-{

-  NWindows::NFile::NDir::CTempFile _tempFile;

-  NWindows::NFile::NIO::COutFile _outFile;

-  Byte *_buf;

-  size_t _bufPos;

-  UInt64 _size;

-  UInt32 _crc;

-  bool _tempFileCreated;

-

-  bool WriteToFile(const void *data, UInt32 size);

-public:

-  CInOutTempBuffer();

-  ~CInOutTempBuffer();

-  void Create();

-

-  void InitWriting();

-  bool Write(const void *data, UInt32 size);

-

-  HRESULT WriteToStream(ISequentialOutStream *stream);

-  UInt64 GetDataSize() const { return _size; }

-};

-

-/*

-class CSequentialOutTempBufferImp:

-  public ISequentialOutStream,

-  public CMyUnknownImp

-{

-  CInOutTempBuffer *_buf;

-public:

-  void Init(CInOutTempBuffer *buffer)  { _buf = buffer; }

-  MY_UNKNOWN_IMP

-

-  STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);

-};

-*/

-

-#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 fc7e794..664cd0c 100644
--- a/CPP/7zip/Common/LimitedStreams.cpp
+++ b/CPP/7zip/Common/LimitedStreams.cpp
@@ -1,367 +1,393 @@
-// LimitedStreams.cpp

-

-#include "StdAfx.h"

-

-#include <string.h>

-

-#include "LimitedStreams.h"

-

-STDMETHODIMP 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;

-}

-

-STDMETHODIMP 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;

-}

-

-STDMETHODIMP 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 = offset;

-  if (newPosition)

-    *newPosition = _virtPos;

-  return S_OK;

-}

-

-HRESULT CreateLimitedInStream(IInStream *inStream, UInt64 pos, UInt64 size, ISequentialInStream **resStream)

-{

-  *resStream = 0;

-  CLimitedInStream *streamSpec = new CLimitedInStream;

-  CMyComPtr<ISequentialInStream> streamTemp = streamSpec;

-  streamSpec->SetStream(inStream);

-  RINOK(streamSpec->InitAndSeek(pos, size));

-  streamSpec->SeekToStart();

-  *resStream = streamTemp.Detach();

-  return S_OK;

-}

-

-STDMETHODIMP 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 (int 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;

-}

- 

-STDMETHODIMP 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 = offset;

-  if (newPosition)

-    *newPosition = offset;

-  return S_OK;

-}

-

-

-STDMETHODIMP CExtentsStream::Read(void *data, UInt32 size, UInt32 *processedSize)

-{

-  if (processedSize)

-    *processedSize = 0;

-  if (_virtPos >= Extents.Back().Virt)

-    return S_OK;

-  if (size == 0)

-    return S_OK;

-  

-  unsigned left = 0, right = Extents.Size() - 1;

-  for (;;)

-  {

-    unsigned mid = (left + right) / 2;

-    if (mid == left)

-      break;

-    if (_virtPos < Extents[mid].Virt)

-      right = mid;

-    else

-      left = mid;

-  }

-  

-  const CSeekExtent &extent = Extents[left];

-  UInt64 phyPos = extent.Phy + (_virtPos - extent.Virt);

-  if (_needStartSeek || _phyPos != phyPos)

-  {

-    _needStartSeek = false;

-    _phyPos = phyPos;

-    RINOK(SeekToPhys());

-  }

-  

-  UInt64 rem = Extents[left + 1].Virt - _virtPos;

-  if (size > rem)

-    size = (UInt32)rem;

-  

-  HRESULT res = Stream->Read(data, size, &size);

-  _phyPos += size;

-  _virtPos += size;

-  if (processedSize)

-    *processedSize = size;

-  return res;

-}

-

-STDMETHODIMP 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 = offset;

-  if (newPosition)

-    *newPosition = _virtPos;

-  return S_OK;

-}

-

-

-STDMETHODIMP 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;

-}

-

-

-STDMETHODIMP 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;

-}

-  

-STDMETHODIMP 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 = offset;

-  if (newPosition)

-    *newPosition = _virtPos;

-  return Stream->Seek(Offset + _virtPos, STREAM_SEEK_SET, NULL);

-}

-

-STDMETHODIMP 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;

-}

-

-STDMETHODIMP 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 = offset;

-  if (newPosition)

-    *newPosition = _virtPos;

-  return S_OK;

-}

-

-STDMETHODIMP 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;

-}

-  

-STDMETHODIMP 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 = offset;

-  if (newPosition)

-    *newPosition = _virtPos;

-  return Stream->Seek(Offset + _virtPos, STREAM_SEEK_SET, NULL);

-}

-

-STDMETHODIMP CTailOutStream::SetSize(UInt64 newSize)

-{

-  _virtSize = newSize;

-  return Stream->SetSize(Offset + newSize);

-}

+// LimitedStreams.cpp
+
+#include "StdAfx.h"
+
+#include <string.h>
+
+#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<ISequentialInStream> 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 2e55aa0..69fcdcd 100644
--- a/CPP/7zip/Common/LimitedStreams.h
+++ b/CPP/7zip/Common/LimitedStreams.h
@@ -1,252 +1,221 @@
-// LimitedStreams.h

-

-#ifndef __LIMITED_STREAMS_H

-#define __LIMITED_STREAMS_H

-

-#include "../../Common/MyBuffer.h"

-#include "../../Common/MyCom.h"

-#include "../../Common/MyVector.h"

-#include "../IStream.h"

-

-class CLimitedSequentialInStream:

-  public ISequentialInStream,

-  public CMyUnknownImp

-{

-  CMyComPtr<ISequentialInStream> _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;

-  }

- 

-  MY_UNKNOWN_IMP1(ISequentialInStream)

-

-  STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);

-  UInt64 GetSize() const { return _pos; }

-  UInt64 GetRem() const { return _size - _pos; }

-  bool WasFinished() const { return _wasFinished; }

-};

-

-class CLimitedInStream:

-  public IInStream,

-  public CMyUnknownImp

-{

-  CMyComPtr<IInStream> _stream;

-  UInt64 _virtPos;

-  UInt64 _physPos;

-  UInt64 _size;

-  UInt64 _startOffset;

-

-  HRESULT SeekToPhys() { return _stream->Seek(_physPos, STREAM_SEEK_SET, NULL); }

-public:

-  void SetStream(IInStream *stream) { _stream = stream; }

-  HRESULT InitAndSeek(UInt64 startOffset, UInt64 size)

-  {

-    _startOffset = startOffset;

-    _physPos = startOffset;

-    _virtPos = 0;

-    _size = size;

-    return SeekToPhys();

-  }

- 

-  MY_UNKNOWN_IMP2(ISequentialInStream, IInStream)

-

-  STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);

-  STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);

-

-  HRESULT SeekToStart() { return Seek(0, STREAM_SEEK_SET, NULL); }

-};

-

-HRESULT CreateLimitedInStream(IInStream *inStream, UInt64 pos, UInt64 size, ISequentialInStream **resStream);

-

-class CClusterInStream:

-  public IInStream,

-  public CMyUnknownImp

-{

-  UInt64 _virtPos;

-  UInt64 _physPos;

-  UInt32 _curRem;

-public:

-  unsigned BlockSizeLog;

-  UInt64 Size;

-  CMyComPtr<IInStream> Stream;

-  CRecordVector<UInt32> Vector;

-  UInt64 StartOffset;

-

-  HRESULT SeekToPhys() { return Stream->Seek(_physPos, STREAM_SEEK_SET, NULL); }

-

-  HRESULT InitAndSeek()

-  {

-    _curRem = 0;

-    _virtPos = 0;

-    _physPos = StartOffset;

-    if (Vector.Size() > 0)

-    {

-      _physPos = StartOffset + (Vector[0] << BlockSizeLog);

-      return SeekToPhys();

-    }

-    return S_OK;

-  }

-

-  MY_UNKNOWN_IMP2(ISequentialInStream, IInStream)

-

-  STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);

-  STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);

-};

-

-struct CSeekExtent

-{

-  UInt64 Phy;

-  UInt64 Virt;

-};

-

-class CExtentsStream:

-  public IInStream,

-  public CMyUnknownImp

-{

-  UInt64 _phyPos;

-  UInt64 _virtPos;

-  bool _needStartSeek;

-

-  HRESULT SeekToPhys() { return Stream->Seek(_phyPos, STREAM_SEEK_SET, NULL); }

-

-public:

-  CMyComPtr<IInStream> Stream;

-  CRecordVector<CSeekExtent> Extents;

-

-  MY_UNKNOWN_IMP2(ISequentialInStream, IInStream)

-  STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);

-  STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);

-  void ReleaseStream() { Stream.Release(); }

-

-  void Init()

-  {

-    _virtPos = 0;

-    _phyPos = 0;

-    _needStartSeek = true;

-  }

-};

-

-class CLimitedSequentialOutStream:

-  public ISequentialOutStream,

-  public CMyUnknownImp

-{

-  CMyComPtr<ISequentialOutStream> _stream;

-  UInt64 _size;

-  bool _overflow;

-  bool _overflowIsAllowed;

-public:

-  MY_UNKNOWN_IMP1(ISequentialOutStream)

-  STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);

-  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; }

-};

-

-

-class CTailInStream:

-  public IInStream,

-  public CMyUnknownImp

-{

-  UInt64 _virtPos;

-public:

-  CMyComPtr<IInStream> Stream;

-  UInt64 Offset;

-

-  void Init()

-  {

-    _virtPos = 0;

-  }

- 

-  MY_UNKNOWN_IMP2(ISequentialInStream, IInStream)

-

-  STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);

-  STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);

-

-  HRESULT SeekToStart() { return Stream->Seek(Offset, STREAM_SEEK_SET, NULL); }

-};

-

-class CLimitedCachedInStream:

-  public IInStream,

-  public CMyUnknownImp

-{

-  CMyComPtr<IInStream> _stream;

-  UInt64 _virtPos;

-  UInt64 _physPos;

-  UInt64 _size;

-  UInt64 _startOffset;

-  

-  const Byte *_cache;

-  size_t _cacheSize;

-  size_t _cachePhyPos;

-

-

-  HRESULT SeekToPhys() { return _stream->Seek(_physPos, STREAM_SEEK_SET, NULL); }

-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();

-  }

- 

-  MY_UNKNOWN_IMP2(ISequentialInStream, IInStream)

-

-  STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);

-  STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);

-

-  HRESULT SeekToStart() { return Seek(0, STREAM_SEEK_SET, NULL); }

-};

-

-class CTailOutStream:

-  public IOutStream,

-  public CMyUnknownImp

-{

-  UInt64 _virtPos;

-  UInt64 _virtSize;

-public:

-  CMyComPtr<IOutStream> Stream;

-  UInt64 Offset;

-  

-  virtual ~CTailOutStream() {}

-

-  MY_UNKNOWN_IMP2(ISequentialOutStream, IOutStream)

-

-  void Init()

-  {

-    _virtPos = 0;

-    _virtSize = 0;

-  }

-

-  STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);

-  STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);

-  STDMETHOD(SetSize)(UInt64 newSize);

-};

-

-#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<ISequentialInStream> _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<IInStream> _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<IInStream> Stream;
+  CRecordVector<UInt32> 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<IInStream> Stream;
+  CRecordVector<CSeekExtent> 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<ISequentialOutStream> _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<IInStream> Stream;
+  UInt64 Offset;
+
+  void Init()
+  {
+    _virtPos = 0;
+  }
+  HRESULT SeekToStart() { return InStream_SeekSet(Stream, Offset); }
+};
+
+
+Z7_CLASS_IMP_IInStream(
+  CLimitedCachedInStream
+)
+  CMyComPtr<IInStream> _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<IOutStream> 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 1223efe..ca39fb4 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 5bf5c85..99ee805 100644
--- a/CPP/7zip/Common/LockedStream.h
+++ b/CPP/7zip/Common/LockedStream.h
@@ -1,6 +1,6 @@
-// LockedStream.h

-

-#ifndef __LOCKED_STREAM_H

-#define __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
new file mode 100644
index 0000000..aa68244
--- /dev/null
+++ b/CPP/7zip/Common/MemBlocks.cpp
@@ -0,0 +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 <stdio.h>
+
+HRes 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);
+}
+
+
+HRes 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;
+    HRes 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
new file mode 100644
index 0000000..7c34f21
--- /dev/null
+++ b/CPP/7zip/Common/MemBlocks.h
@@ -0,0 +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(); }
+
+  HRes AllocateSpace(size_t numBlocks, size_t numNoLockBlocks);
+  HRes 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<void *> 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);
+  // HRes 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 9a07e4c..1566c97 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 1ba9f49..19b1f10 100644
--- a/CPP/7zip/Common/MethodId.h
+++ b/CPP/7zip/Common/MethodId.h
@@ -1,10 +1,10 @@
-// MethodId.h

-

-#ifndef __7Z_METHOD_ID_H

-#define __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 2134462..fe60f61 100644
--- a/CPP/7zip/Common/MethodProps.cpp
+++ b/CPP/7zip/Common/MethodProps.cpp
@@ -1,509 +1,737 @@
-// MethodProps.cpp

-

-#include "StdAfx.h"

-

-#include "../../Common/StringToInt.h"

-

-#include "MethodProps.h"

-

-using namespace NWindows;

-

-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;

-  }

-  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

-  // {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 ParseMtProp(const UString &name, const PROPVARIANT &prop, UInt32 defaultNumThreads, UInt32 &numThreads)

-{

-  if (name.IsEmpty())

-  {

-    switch (prop.vt)

-    {

-      case VT_UI4:

-        numThreads = prop.ulVal;

-        break;

-      default:

-      {

-        bool val;

-        RINOK(PROPVARIANT_to_bool(prop, val));

-        numThreads = (val ? defaultNumThreads : 1);

-        break;

-      }

-    }

-    return S_OK;

-  }

-  if (prop.vt != VT_EMPTY)

-    return E_INVALIDARG;

-  return ParsePropToUInt32(name, prop, numThreads);

-}

-

-

-static HRESULT StringToDictSize(const UString &s, NCOM::CPropVariant &destProp)

-{

-  const wchar_t *end;

-  UInt32 number = ConvertStringToUInt32(s, &end);

-  unsigned numDigits = (unsigned)(end - s.Ptr());

-  if (numDigits == 0 || s.Len() > numDigits + 1)

-    return E_INVALIDARG;

-  

-  if (s.Len() == numDigits)

-  {

-    if (number >= 64)

-      return E_INVALIDARG;

-    if (number < 32)

-      destProp = (UInt32)((UInt32)1 << (unsigned)number);

-    else

-      destProp = (UInt64)((UInt64)1 << (unsigned)number);

-    return S_OK;

-  }

-  

-  unsigned numBits;

-  

-  switch (MyCharLower_Ascii(s[numDigits]))

-  {

-    case 'b': destProp = number; return S_OK;

-    case 'k': numBits = 10; break;

-    case 'm': numBits = 20; break;

-    case 'g': numBits = 30; break;

-    default: return E_INVALIDARG;

-  }

-  

-  if (number < ((UInt32)1 << (32 - numBits)))

-    destProp = (UInt32)(number << numBits);

-  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)

-  {

-    UInt32 v = prop.ulVal;

-    if (v >= 64)

-      return E_INVALIDARG;

-    if (v < 32)

-      destProp = (UInt32)((UInt32)1 << (unsigned)v);

-    else

-      destProp = (UInt64)((UInt64)1 << (unsigned)v);

-    return S_OK;

-  }

-  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)

-  {

-    _numPropsMax = numPropsMax;

-    _numProps = 0;

-    _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

-{

-  CCoderProps coderProps(Props.Size() + (dataSizeReduce ? 1 : 0));

-  FOR_VECTOR (i, Props)

-    coderProps.AddProp(Props[i]);

-  if (dataSizeReduce)

-  {

-    CProp prop;

-    prop.Id = NCoderPropID::kReduceSize;

-    prop.Value = *dataSizeReduce;

-    coderProps.AddProp(prop);

-  }

-  return coderProps.SetProps(scp);

-}

-

-

-int CMethodProps::FindProp(PROPID id) const

-{

-  for (int i = Props.Size() - 1; i >= 0; i--)

-    if (Props[i].Id == id)

-      return i;

-  return -1;

-}

-

-int CMethodProps::GetLevel() const

-{

-  int i = FindProp(NCoderPropID::kLevel);

-  if (i < 0)

-    return 5;

-  if (Props[i].Value.vt != VT_UI4)

-    return 9;

-  UInt32 level = Props[i].Value.ulVal;

-  return level > 9 ? 9 : (int)level;

-}

-

-struct CNameToPropID

-{

-  VARTYPE VarType;

-  const char *Name;

-};

-

-

-// the following are related to NCoderPropID::EEnum values

-

-static const CNameToPropID g_NameToPropID[] =

-{

-  { VT_UI4, "" },

-  { VT_UI4, "d" },

-  { VT_UI4, "mem" },

-  { VT_UI4, "o" },

-  { VT_UI4, "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_UI4, "b" },

-  { VT_UI4, "check" },

-  { VT_BSTR, "filter" },

-  { VT_UI8, "memuse" }

-};

-

-static int FindPropIdExact(const UString &name)

-{

-  for (unsigned i = 0; i < ARRAY_SIZE(g_NameToPropID); i++)

-    if (StringsAreEqualNoCase_Ascii(name, g_NameToPropID[i].Name))

-      return 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 &param, UString &name, UString &value)

-{

-  int eqPos = param.Find(L'=');

-  if (eqPos >= 0)

-  {

-    name.SetFrom(param, eqPos);

-    value = param.Ptr(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::kReduceSize:

-      return true;

-  }

-  return false;

-}

-

-HRESULT CMethodProps::SetParam(const UString &name, const UString &value)

-{

-  int index = FindPropIdExact(name);

-  if (index < 0)

-    return E_INVALIDARG;

-  const CNameToPropID &nameToPropID = g_NameToPropID[(unsigned)index];

-  CProp prop;

-  prop.Id = 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 &param = 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

-  int index = FindPropIdExact(realName);

-  if (index < 0)

-    return E_INVALIDARG;

-  const CNameToPropID &nameToPropID = g_NameToPropID[(unsigned)index];

-  CProp prop;

-  prop.Id = 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;

-}

-

-HRESULT COneMethodInfo::ParseMethodFromString(const UString &s)

-{

-  MethodName.Empty();

-  int splitPos = s.Find(L':');

-  {

-    UString temp = s;

-    if (splitPos >= 0)

-      temp.DeleteFrom(splitPos);

-    if (!temp.IsAscii())

-      return E_INVALIDARG;

-    MethodName.SetFromWStr_if_Ascii(temp);

-  }

-  if (splitPos < 0)

-    return S_OK;

-  PropsString = s.Ptr(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;
+  }
+  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 &param, 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;
+  }
+  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 &param = 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 c8a3d0d..3c332d6 100644
--- a/CPP/7zip/Common/MethodProps.h
+++ b/CPP/7zip/Common/MethodProps.h
@@ -1,264 +1,345 @@
-// MethodProps.h

-

-#ifndef __7Z_METHOD_PROPS_H

-#define __7Z_METHOD_PROPS_H

-

-#include "../../Common/MyString.h"

-#include "../../Common/Defs.h"

-

-#include "../../Windows/Defs.h"

-

-#include "../../Windows/PropVariant.h"

-

-#include "../ICoder.h"

-

-bool StringToBool(const wchar_t *s, bool &res);

-HRESULT PROPVARIANT_to_bool(const PROPVARIANT &prop, bool &dest);

-unsigned ParseStringToUInt32(const UString &srcString, UInt32 &number);

-HRESULT ParsePropToUInt32(const UString &name, const PROPVARIANT &prop, UInt32 &resValue);

-

-HRESULT ParseMtProp(const UString &name, const PROPVARIANT &prop, UInt32 defaultNumThreads, UInt32 &numThreads);

-

-struct CProp

-{

-  PROPID Id;

-  bool IsOptional;

-  NWindows::NCOM::CPropVariant Value;

-  CProp(): IsOptional(false) {}

-};

-

-struct CProps

-{

-  CObjectVector<CProp> 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) const;

-};

-

-class CMethodProps: public CProps

-{

-  HRESULT SetParam(const UString &name, const UString &value);

-public:

-  int GetLevel() const;

-  int Get_NumThreads() const

-  {

-    int i = FindProp(NCoderPropID::kNumThreads);

-    if (i >= 0)

-      if (Props[i].Value.vt == VT_UI4)

-        return (int)Props[i].Value.ulVal;

-    return -1;

-  }

-

-  bool Get_DicSize(UInt32 &res) const

-  {

-    res = 0;

-    int i = FindProp(NCoderPropID::kDictionarySize);

-    if (i >= 0)

-      if (Props[i].Value.vt == VT_UI4)

-      {

-        res = Props[i].Value.ulVal;

-        return true;

-      }

-    return false;

-  }

-

-  int FindProp(PROPID id) const;

-

-  UInt32 Get_Lzma_Algo() const

-  {

-    int i = FindProp(NCoderPropID::kAlgorithm);

-    if (i >= 0)

-      if (Props[i].Value.vt == VT_UI4)

-        return Props[i].Value.ulVal;

-    return GetLevel() >= 5 ? 1 : 0;

-  }

-

-  UInt32 Get_Lzma_DicSize() const

-  {

-    int i = FindProp(NCoderPropID::kDictionarySize);

-    if (i >= 0)

-      if (Props[i].Value.vt == VT_UI4)

-        return Props[i].Value.ulVal;

-    int level = GetLevel();

-    return level <= 5 ? (1 << (level * 2 + 14)) : (level == 6 ? (1 << 25) : (1 << 26));

-  }

-

-  bool Get_Lzma_Eos() const

-  {

-    int i = FindProp(NCoderPropID::kEndMarker);

-    if (i >= 0)

-    {

-      const NWindows::NCOM::CPropVariant &val = Props[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;

-  }

-

-  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

-  {

-    int i = FindProp(id);

-    if (i >= 0)

-    {

-      const NWindows::NCOM::CPropVariant &val = Props[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;

-    UInt32 dictSize = Get_Lzma_DicSize();

-    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 (numThreads > kNumBZip2ThreadsMax) return kNumBZip2ThreadsMax;

-      return numThreads;

-    }

-    return 1;

-  }

-

-  UInt32 Get_BZip2_BlockSize() const

-  {

-    int i = FindProp(NCoderPropID::kDictionarySize);

-    if (i >= 0)

-      if (Props[i].Value.vt == VT_UI4)

-      {

-        UInt32 blockSize = Props[i].Value.ulVal;

-        const UInt32 kDicSizeMin = 100000;

-        const UInt32 kDicSizeMax = 900000;

-        if (blockSize < kDicSizeMin) blockSize = kDicSizeMin;

-        if (blockSize > kDicSizeMax) blockSize = kDicSizeMax;

-        return blockSize;

-      }

-    int level = GetLevel();

-    return 100000 * (level >= 5 ? 9 : (level >= 1 ? level * 2 - 1: 1));

-  }

-

-  UInt32 Get_Ppmd_MemSize() const

-  {

-    int i = FindProp(NCoderPropID::kUsedMemorySize);

-    if (i >= 0)

-      if (Props[i].Value.vt == VT_UI4)

-        return Props[i].Value.ulVal;

-    int level = GetLevel();

-    return level >= 9 ? (192 << 20) : ((UInt32)1 << (level + 19));

-  }

-

-  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);

-  }

-

-  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<CProp> 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
diff --git a/CPP/7zip/Common/MultiOutStream.cpp b/CPP/7zip/Common/MultiOutStream.cpp
new file mode 100644
index 0000000..8efb977
--- /dev/null
+++ b/CPP/7zip/Common/MultiOutStream.cpp
@@ -0,0 +1,849 @@
+// MultiOutStream.cpp
+
+#include "StdAfx.h"
+
+// #define DEBUG_VOLUMES
+
+#ifdef DEBUG_VOLUMES
+#include <stdio.h>
+  #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<UInt64> &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(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()
+{
+  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(path, OPEN_EXISTING))
+  {
+    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)
+      {
+        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== 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;
+
+  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-- 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 (UInt32)(Int32)-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
new file mode 100644
index 0000000..2fb7811
--- /dev/null
+++ b/CPP/7zip/Common/MultiOutStream.h
@@ -0,0 +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<IOutStream> 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<CVolStream> Streams;
+  CRecordVector<UInt64> 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<UInt64> &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 3b01c7f..a6b005e 100644
--- a/CPP/7zip/Common/OffsetStream.cpp
+++ b/CPP/7zip/Common/OffsetStream.cpp
@@ -1,39 +1,37 @@
-// OffsetStream.cpp

-

-#include "StdAfx.h"

-

-#include "../../Common/Defs.h"

-

-#include "OffsetStream.h"

-

-HRESULT COffsetOutStream::Init(IOutStream *stream, UInt64 offset)

-{

-  _offset = offset;

-  _stream = stream;

-  return _stream->Seek(offset, STREAM_SEEK_SET, NULL);

-}

-

-STDMETHODIMP COffsetOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)

-{

-  return _stream->Write(data, size, processedSize);

-}

-

-STDMETHODIMP COffsetOutStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)

-{

-  UInt64 absoluteNewPosition;

-  if (seekOrigin == STREAM_SEEK_SET)

-  {

-    if (offset < 0)

-      return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;

-    offset += _offset;

-  }

-  HRESULT result = _stream->Seek(offset, seekOrigin, &absoluteNewPosition);

-  if (newPosition)

-    *newPosition = absoluteNewPosition - _offset;

-  return result;

-}

-

-STDMETHODIMP 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 ad835f2..9bd554c 100644
--- a/CPP/7zip/Common/OffsetStream.h
+++ b/CPP/7zip/Common/OffsetStream.h
@@ -1,26 +1,22 @@
-// OffsetStream.h

-

-#ifndef __OFFSET_STREAM_H

-#define __OFFSET_STREAM_H

-

-#include "../../Common/MyCom.h"

-

-#include "../IStream.h"

-

-class COffsetOutStream:

-  public IOutStream,

-  public CMyUnknownImp

-{

-  UInt64 _offset;

-  CMyComPtr<IOutStream> _stream;

-public:

-  HRESULT Init(IOutStream *stream, UInt64 offset);

-  

-  MY_UNKNOWN_IMP

-

-  STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);

-  STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);

-  STDMETHOD(SetSize)(UInt64 newSize);

-};

-

-#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<IOutStream> _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 fb8dc8d..197b376 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 != 0 && _bufSize == bufSize)

-    return true;

-  Free();

-  _bufSize = bufSize;

-  _buf = (Byte *)::MidAlloc(bufSize);

-  return (_buf != 0);

-}

-

-void COutBuffer::Free() throw()

-{

-  ::MidFree(_buf);

-  _buf = 0;

-}

-

-void COutBuffer::Init() throw()

-{

-  _streamPos = 0;

-  _limitPos = _bufSize;

-  _pos = 0;

-  _processedSize = 0;

-  _overDict = false;

-  #ifdef _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 _NO_EXCEPTIONS

-  result = ErrorCode;

-  #endif

-  if (_buf2 != 0)

-  {

-    memcpy(_buf2, _buf + _streamPos, size);

-    _buf2 += size;

-  }

-

-  if (_stream != 0

-      #ifdef _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 _NO_EXCEPTIONS

-  if (ErrorCode != S_OK)

-    return ErrorCode;

-  #endif

-

-  while (_streamPos != _pos)

-  {

-    HRESULT result = FlushPart();

-    if (result != S_OK)

-      return result;

-  }

-  return S_OK;

-}

-

-void COutBuffer::FlushWithCheck()

-{

-  HRESULT result = Flush();

-  #ifdef _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 2ffb5cd..cef7d50 100644
--- a/CPP/7zip/Common/OutBuffer.h
+++ b/CPP/7zip/Common/OutBuffer.h
@@ -1,66 +1,66 @@
-// OutBuffer.h

-

-#ifndef __OUT_BUFFER_H

-#define __OUT_BUFFER_H

-

-#include "../IStream.h"

-#include "../../Common/MyCom.h"

-#include "../../Common/MyException.h"

-

-#ifndef _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 _NO_EXCEPTIONS

-  HRESULT ErrorCode;

-  #endif

-

-  COutBuffer(): _buf(0), _pos(0), _stream(0), _buf2(0) {}

-  ~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]);

-  }

-

-  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]);
+  }
+
+  UInt64 GetProcessedSize() const throw();
+};
+
+#endif
diff --git a/CPP/7zip/Common/OutMemStream.cpp b/CPP/7zip/Common/OutMemStream.cpp
new file mode 100644
index 0000000..29a2394
--- /dev/null
+++ b/CPP/7zip/Common/OutMemStream.cpp
@@ -0,0 +1,158 @@
+// OutMemStream.cpp
+
+#include "StdAfx.h"
+
+// #include <stdio.h>
+
+#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
new file mode 100644
index 0000000..7fc2dbd
--- /dev/null
+++ b/CPP/7zip/Common/OutMemStream.h
@@ -0,0 +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<ISequentialOutStream> OutSeqStream;
+  CMyComPtr<IOutStream> OutStream;
+
+  UInt64 GetPos() const { return (UInt64)_curBlockIndex * _memManager->GetBlockSize() + _curBlockPos; }
+
+public:
+
+  HRes 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
new file mode 100644
index 0000000..ee21ab3
--- /dev/null
+++ b/CPP/7zip/Common/ProgressMt.cpp
@@ -0,0 +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);
+}
diff --git a/CPP/7zip/Common/ProgressMt.h b/CPP/7zip/Common/ProgressMt.h
new file mode 100644
index 0000000..78c806c
--- /dev/null
+++ b/CPP/7zip/Common/ProgressMt.h
@@ -0,0 +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<ICompressProgressInfo> _progress;
+  CRecordVector<UInt64> InSizes;
+  CRecordVector<UInt64> 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 86f1e78..fb81f29 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():

-    ProgressOffset(0),

-    InSize(0),

-    OutSize(0),

-    SendRatio(true),

-    SendProgress(true)

-  {}

-

-void CLocalProgress::Init(IProgress *progress, bool inSizeIsMain)

-{

-  _ratioProgress.Release();

-  _progress = progress;

-  _progress.QueryInterface(IID_ICompressProgressInfo, &_ratioProgress);

-  _inSizeIsMain = inSizeIsMain;

-}

-

-STDMETHODIMP 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 176e8bb..dad5fcc 100644
--- a/CPP/7zip/Common/ProgressUtils.h
+++ b/CPP/7zip/Common/ProgressUtils.h
@@ -1,35 +1,33 @@
-// ProgressUtils.h

-

-#ifndef __PROGRESS_UTILS_H

-#define __PROGRESS_UTILS_H

-

-#include "../../Common/MyCom.h"

-

-#include "../ICoder.h"

-#include "../IProgress.h"

-

-class CLocalProgress:

-  public ICompressProgressInfo,

-  public CMyUnknownImp

-{

-  CMyComPtr<IProgress> _progress;

-  CMyComPtr<ICompressProgressInfo> _ratioProgress;

-  bool _inSizeIsMain;

-public:

-  UInt64 ProgressOffset;

-  UInt64 InSize;

-  UInt64 OutSize;

-  bool SendRatio;

-  bool SendProgress;

-

-  CLocalProgress();

-

-  void Init(IProgress *progress, bool inSizeIsMain);

-  HRESULT SetCur();

-

-  MY_UNKNOWN_IMP1(ICompressProgressInfo)

-

-  STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);

-};

-

-#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<IProgress> _progress;
+  CMyComPtr<ICompressProgressInfo> _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 96f8f05..6117b0e 100644
--- a/CPP/7zip/Common/PropId.cpp
+++ b/CPP/7zip/Common/PropId.cpp
@@ -1,108 +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

-};

+// 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 08aa2d4..55c1483 100644
--- a/CPP/7zip/Common/RegisterArc.h
+++ b/CPP/7zip/Common/RegisterArc.h
@@ -1,78 +1,80 @@
-// RegisterArc.h

-

-#ifndef __REGISTER_ARC_H

-#define __REGISTER_ARC_H

-

-#include "../Archive/IArchive.h"

-

-struct CArcInfo

-{

-  UInt16 Flags;

-  Byte Id;

-  Byte SignatureSize;

-  UInt16 SignatureOffset;

-  

-  const Byte *Signature;

-  const char *Name;

-  const char *Ext;

-  const char *AddExt;

-  

-  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 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, crIn, crOut, isArc) \

-  static const CArcInfo g_ArcInfo = { flags, id, sigSize, offs, sig, n, e, ae, crIn, crOut, isArc } ; \

-

-#define REGISTER_ARC_R(n, e, ae, id, sigSize, sig, offs, flags, crIn, crOut, isArc) \

-  REGISTER_ARC_V(n, e, ae, id, sigSize, sig, offs, flags, 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, ARRAY_SIZE(sig), sig, offs, flags, 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, 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, isArc) \

-  IMP_CreateArcIn \

-  IMP_CreateArcOut \

-  REGISTER_ARC_R(n, e, ae, id, ARRAY_SIZE(sig), sig, offs, flags, CreateArc, CreateArcOut, isArc)

-

-#define REGISTER_ARC_IO_DECREMENT_SIG(n, e, ae, id, sig, offs, flags, isArc) \

-  IMP_CreateArcIn \

-  IMP_CreateArcOut \

-  REGISTER_ARC_V(n, e, ae, id, ARRAY_SIZE(sig), sig, offs, flags, 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 b566065..cf94998 100644
--- a/CPP/7zip/Common/RegisterCodec.h
+++ b/CPP/7zip/Common/RegisterCodec.h
@@ -1,106 +1,106 @@
-// RegisterCodec.h

-

-#ifndef __REGISTER_CODEC_H

-#define __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 static const CCodecInfo g_CodecInfo =

-

-#define REGISTER_CODEC(x) struct REGISTER_CODEC_NAME(x) { \

-    REGISTER_CODEC_NAME(x)() { RegisterCodec(&g_CodecInfo); }}; \

-    static REGISTER_CODEC_NAME(x) g_RegisterCodec;

-

-

-#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 < 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 \

-    { crDec, crEnc, id, name, 1, false }; \

-    REGISTER_CODEC(x)

-

-

-#ifdef 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 \

-    REGISTER_FILTER_ITEM(crDec, crEnc, id, name); \

-    REGISTER_CODEC(x)

-

-#ifdef EXTRACT_ONLY

-  #define REGISTER_FILTER_E(x, clsDec, clsEnc, id, name) \

-    REGISTER_FILTER_CREATE(CreateDec, clsDec) \

-    REGISTER_FILTER(x, CreateDec, NULL, id, name)

-#else

-  #define REGISTER_FILTER_E(x, clsDec, clsEnc, id, name) \

-    REGISTER_FILTER_CREATE(CreateDec, clsDec) \

-    REGISTER_FILTER_CREATE(CreateEnc, clsEnc) \

-    REGISTER_FILTER(x, CreateDec, 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) \

-    STDMETHODIMP_(UInt32) cls::GetDigestSize() throw() { 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 42a088f..8086655 100644
--- a/CPP/7zip/Common/StdAfx.h
+++ b/CPP/7zip/Common/StdAfx.h
@@ -1,8 +1,11 @@
-// StdAfx.h

-

-#ifndef __STDAFX_H

-#define __STDAFX_H

-

-#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 a6627db..38334af 100644
--- a/CPP/7zip/Common/StreamBinder.cpp
+++ b/CPP/7zip/Common/StreamBinder.cpp
@@ -1,156 +1,151 @@
-// StreamBinder.cpp

-

-#include "StdAfx.h"

-

-#include "../../Common/MyCom.h"

-

-#include "StreamBinder.h"

-

-class CBinderInStream:

-  public ISequentialInStream,

-  public CMyUnknownImp

-{

-  CStreamBinder *_binder;

-public:

-  MY_UNKNOWN_IMP1(ISequentialInStream)

-  STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);

-  ~CBinderInStream() { _binder->CloseRead(); }

-  CBinderInStream(CStreamBinder *binder): _binder(binder) {}

-};

-

-STDMETHODIMP CBinderInStream::Read(void *data, UInt32 size, UInt32 *processedSize)

-  { return _binder->Read(data, size, processedSize); }

-

-class CBinderOutStream:

-  public ISequentialOutStream,

-  public CMyUnknownImp

-{

-  CStreamBinder *_binder;

-public:

-  MY_UNKNOWN_IMP1(ISequentialOutStream)

-  STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);

-  ~CBinderOutStream() { _binder->CloseWrite(); }

-  CBinderOutStream(CStreamBinder *binder): _binder(binder) {}

-};

-

-STDMETHODIMP CBinderOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)

-  { return _binder->Write(data, size, processedSize); }

-

-

-

-WRes CStreamBinder::CreateEvents()

-{

-  RINOK(_canWrite_Event.Create());

-  RINOK(_canRead_Event.Create());

-  return _readingWasClosed_Event.Create();

-}

-

-void CStreamBinder::ReInit()

-{

-  _canWrite_Event.Reset();

-  _canRead_Event.Reset();

-  _readingWasClosed_Event.Reset();

-

-  // _readingWasClosed = false;

-  _readingWasClosed2 = false;

-

-  _waitWrite = true;

-  _bufSize = 0;

-  _buf = NULL;

-  ProcessedSize = 0;

-  // WritingWasCut = false;

-}

-

-

-void CStreamBinder::CreateStreams(ISequentialInStream **inStream, ISequentialOutStream **outStream)

-{

-  // _readingWasClosed = false;

-  _readingWasClosed2 = false;

-

-  _waitWrite = true;

-  _bufSize = 0;

-  _buf = NULL;

-  ProcessedSize = 0;

-  // WritingWasCut = false;

-

-  CBinderInStream *inStreamSpec = new CBinderInStream(this);

-  CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec);

-  *inStream = inStreamLoc.Detach();

-

-  CBinderOutStream *outStreamSpec = new CBinderOutStream(this);

-  CMyComPtr<ISequentialOutStream> outStreamLoc(outStreamSpec);

-  *outStream = outStreamLoc.Detach();

-}

-

-// (_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)

-    {

-      RINOK(_canRead_Event.Lock());

-      _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)

-      {

-        _waitWrite = true;

-        _canRead_Event.Reset();

-        _canWrite_Event.Set();

-      }

-    }

-  }

-  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;

-    */

-

-    HANDLE events[2] = { _canWrite_Event, _readingWasClosed_Event };

-    DWORD waitResult = ::WaitForMultipleObjects(2, events, FALSE, INFINITE);

-    if (waitResult >= WAIT_OBJECT_0 + 2)

-      return E_FAIL;

-

-    size -= _bufSize;

-    if (size != 0)

-    {

-      if (processedSize)

-        *processedSize = size;

-      return S_OK;

-    }

-    // if (waitResult == WAIT_OBJECT_0 + 1)

-      _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<ISequentialInStream> &inStream, CMyComPtr<ISequentialOutStream> &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 f4d4f3b..c0a7079 100644
--- a/CPP/7zip/Common/StreamBinder.h
+++ b/CPP/7zip/Common/StreamBinder.h
@@ -1,60 +1,78 @@
-// StreamBinder.h

-

-#ifndef __STREAM_BINDER_H

-#define __STREAM_BINDER_H

-

-#include "../../Windows/Synchronization.h"

-

-#include "../IStream.h"

-

-/*

-We don't use probably UNSAFE version:

-reader thread:

-     _canWrite_Event.Set();

-     _readingWasClosed = true

-     _canWrite_Event.Set();

-writer thread:

-     _canWrite_Event.Wait()

-      if (_readingWasClosed)

-Can second call of _canWrite_Event.Set() be executed without memory barrier, if event is already set?

-*/

-

-class CStreamBinder

-{

-  NWindows::NSynchronization::CAutoResetEvent _canWrite_Event;

-  NWindows::NSynchronization::CManualResetEvent _canRead_Event;

-  NWindows::NSynchronization::CManualResetEvent _readingWasClosed_Event;

-

-  // bool _readingWasClosed;

-  bool _readingWasClosed2;

-  // bool WritingWasCut;

-  bool _waitWrite;

-  UInt32 _bufSize;

-  const void *_buf;

-public:

-  UInt64 ProcessedSize;

-

-  WRes CreateEvents();

-  void CreateStreams(ISequentialInStream **inStream, ISequentialOutStream **outStream);

-  

-  void ReInit();

-  

-  HRESULT Read(void *data, UInt32 size, UInt32 *processedSize);

-  HRESULT Write(const void *data, UInt32 size, UInt32 *processedSize);

-

-  void CloseRead()

-  {

-    _readingWasClosed_Event.Set();

-    // _readingWasClosed = true;

-    // _canWrite_Event.Set();

-  }

-  

-  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<ISequentialInStream> &inStream, CMyComPtr<ISequentialOutStream> &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 4cd9cc6..b54f423 100644
--- a/CPP/7zip/Common/StreamObjects.cpp
+++ b/CPP/7zip/Common/StreamObjects.cpp
@@ -1,285 +1,290 @@
-// StreamObjects.cpp

-

-#include "StdAfx.h"

-

-#include <stdlib.h>

-

-#include "../../../C/Alloc.h"

-

-#include "StreamObjects.h"

-

-STDMETHODIMP 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;

-}

-

-STDMETHODIMP 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 = offset;

-  if (newPosition)

-    *newPosition = offset;

-  return S_OK;

-}

-

-STDMETHODIMP 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;

-}

-

-STDMETHODIMP 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 = offset;

-  if (newPosition)

-    *newPosition = 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<ISequentialInStream> 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<ISequentialInStream> streamTemp = inStreamSpec;

-  inStreamSpec->Buf.CopyFrom((const Byte *)data, size);

-  inStreamSpec->Init();

-  *stream = streamTemp.Detach();

-}

-

-void CByteDynBuffer::Free() throw()

-{

-  free(_buf);

-  _buf = 0;

-  _capacity = 0;

-}

-

-bool CByteDynBuffer::EnsureCapacity(size_t cap) throw()

-{

-  if (cap <= _capacity)

-    return true;

-  size_t delta;

-  if (_capacity > 64)

-    delta = _capacity / 4;

-  else if (_capacity > 8)

-    delta = 16;

-  else

-    delta = 4;

-  cap = MyMax(_capacity + delta, cap);

-  Byte *buf = (Byte *)realloc(_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);

-}

-

-STDMETHODIMP 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;

-}

-

-STDMETHODIMP 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;

-}

-

-STDMETHODIMP 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 = 0;

-  MidFree(_data);

-  _data = 0;

-}

-

-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 == 0 || dataSize != _dataSize)

-  {

-    MidFree(_data);

-    _data = (Byte *)MidAlloc(dataSize);

-    if (_data == 0)

-      return false;

-    _dataSize = dataSize;

-  }

-  if (_tags == 0 || numBlocksLog != _numBlocksLog)

-  {

-    MyFree(_tags);

-    _tags = (UInt64 *)MyAlloc(sizeof(UInt64) << numBlocksLog);

-    if (_tags == 0)

-      return false;

-    _numBlocksLog = numBlocksLog;

-  }

-  _blockSizeLog = blockSizeLog;

-  return true;

-}

-

-void CCachedInStream::Init(UInt64 size) throw()

-{

-  _size = size;

-  _pos = 0;

-  size_t numBlocks = (size_t)1 << _numBlocksLog;

-  for (size_t i = 0; i < numBlocks; i++)

-    _tags[i] = kEmptyTag;

-}

-

-STDMETHODIMP CCachedInStream::Read(void *data, UInt32 size, UInt32 *processedSize)

-{

-  if (processedSize)

-    *processedSize = 0;

-  if (size == 0)

-    return S_OK;

-  if (_pos >= _size)

-    return S_OK;

-

-  {

-    UInt64 rem = _size - _pos;

-    if (size > rem)

-      size = (UInt32)rem;

-  }

-

-  while (size != 0)

-  {

-    UInt64 cacheTag = _pos >> _blockSizeLog;

-    size_t cacheIndex = (size_t)cacheTag & (((size_t)1 << _numBlocksLog) - 1);

-    Byte *p = _data + (cacheIndex << _blockSizeLog);

-    if (_tags[cacheIndex] != cacheTag)

-    {

-      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;

-    }

-    size_t offset = (size_t)_pos & (((size_t)1 << _blockSizeLog) - 1);

-    UInt32 cur = (UInt32)MyMin(((size_t)1 << _blockSizeLog) - offset, (size_t)size);

-    memcpy(data, p + offset, cur);

-    if (processedSize)

-      *processedSize += cur;

-    data = (void *)((const Byte *)data + cur);

-    _pos += cur;

-    size -= cur;

-  }

-

-  return S_OK;

-}

- 

-STDMETHODIMP 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 = offset;

-  if (newPosition)

-    *newPosition = 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<ISequentialInStream> 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<ISequentialInStream> 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 c3e0837..2c0ebea 100644
--- a/CPP/7zip/Common/StreamObjects.h
+++ b/CPP/7zip/Common/StreamObjects.h
@@ -1,157 +1,146 @@
-// StreamObjects.h

-

-#ifndef __STREAM_OBJECTS_H

-#define __STREAM_OBJECTS_H

-

-#include "../../Common/MyBuffer.h"

-#include "../../Common/MyCom.h"

-#include "../../Common/MyVector.h"

-

-#include "../IStream.h"

-

-class CBufferInStream:

-  public IInStream,

-  public CMyUnknownImp

-{

-  UInt64 _pos;

-public:

-  CByteBuffer Buf;

-  void Init() { _pos = 0; }

- 

-  MY_UNKNOWN_IMP2(ISequentialInStream, IInStream)

-

-  STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);

-  STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);

-};

-

-struct CReferenceBuf:

-  public IUnknown,

-  public CMyUnknownImp

-{

-  CByteBuffer Buf;

-  MY_UNKNOWN_IMP

-};

-

-class CBufInStream:

-  public IInStream,

-  public CMyUnknownImp

-{

-  const Byte *_data;

-  UInt64 _pos;

-  size_t _size;

-  CMyComPtr<IUnknown> _ref;

-public:

-  void Init(const Byte *data, size_t size, IUnknown *ref = 0)

-  {

-    _data = data;

-    _size = size;

-    _pos = 0;

-    _ref = ref;

-  }

-  void Init(CReferenceBuf *ref) { Init(ref->Buf, ref->Buf.Size(), ref); }

-

-  MY_UNKNOWN_IMP2(ISequentialInStream, IInStream)

-  STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);

-  STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);

-};

-

-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

-{

-  size_t _capacity;

-  Byte *_buf;

-public:

-  CByteDynBuffer(): _capacity(0), _buf(0) {};

-  // 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();

-};

-

-class CDynBufSeqOutStream:

-  public ISequentialOutStream,

-  public CMyUnknownImp

-{

-  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; }

-

-  MY_UNKNOWN_IMP1(ISequentialOutStream)

-  STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);

-};

-

-class CBufPtrSeqOutStream:

-  public ISequentialOutStream,

-  public CMyUnknownImp

-{

-  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; }

-

-  MY_UNKNOWN_IMP1(ISequentialOutStream)

-  STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);

-};

-

-class CSequentialOutStreamSizeCount:

-  public ISequentialOutStream,

-  public CMyUnknownImp

-{

-  CMyComPtr<ISequentialOutStream> _stream;

-  UInt64 _size;

-public:

-  void SetStream(ISequentialOutStream *stream) { _stream = stream; }

-  void Init() { _size = 0; }

-  UInt64 GetSize() const { return _size; }

-

-  MY_UNKNOWN_IMP1(ISequentialOutStream)

-  STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);

-};

-

-class CCachedInStream:

-  public IInStream,

-  public CMyUnknownImp

-{

-  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(0), _data(0) {}

-  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();

-

-  MY_UNKNOWN_IMP2(ISequentialInStream, IInStream)

-  STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);

-  STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);

-};

-

-#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<IUnknown> _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<ISequentialOutStream> _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 a79de23..24eed36 100644
--- a/CPP/7zip/Common/StreamUtils.cpp
+++ b/CPP/7zip/Common/StreamUtils.cpp
@@ -1,56 +1,101 @@
-// StreamUtils.cpp

-

-#include "StdAfx.h"

-

-#include "StreamUtils.h"

-

-static const UInt32 kBlockSize = ((UInt32)1 << 31);

-

-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 799a8b9..35a62ed 100644
--- a/CPP/7zip/Common/StreamUtils.h
+++ b/CPP/7zip/Common/StreamUtils.h
@@ -1,13 +1,31 @@
-// StreamUtils.h

-

-#ifndef __STREAM_UTILS_H

-#define __STREAM_UTILS_H

-

-#include "../IStream.h"

-

-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 5baf1a4..32dc276 100644
--- a/CPP/7zip/Common/UniqBlocks.cpp
+++ b/CPP/7zip/Common/UniqBlocks.cpp
@@ -1,57 +1,57 @@
-// UniqBlocks.cpp

-

-#include "StdAfx.h"

-

-#include <string.h>

-

-#include "UniqBlocks.h"

-

-unsigned CUniqBlocks::AddUniq(const Byte *data, size_t size)

-{

-  unsigned left = 0, right = Sorted.Size();

-  while (left != right)

-  {

-    unsigned mid = (left + right) / 2;

-    unsigned index = Sorted[mid];

-    const CByteBuffer &buf = Bufs[index];

-    size_t sizeMid = buf.Size();

-    if (size < sizeMid)

-      right = mid;

-    else if (size > sizeMid)

-      left = mid + 1;

-    else

-    {

-      if (size == 0)

-        return index;

-      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 <string.h>
+
+#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 d9ec17d..66c7fa2 100644
--- a/CPP/7zip/Common/UniqBlocks.h
+++ b/CPP/7zip/Common/UniqBlocks.h
@@ -1,26 +1,41 @@
-// UniqBlocks.h

-

-#ifndef __UNIQ_BLOCKS_H

-#define __UNIQ_BLOCKS_H

-

-#include "../../Common/MyTypes.h"

-#include "../../Common/MyBuffer.h"

-#include "../../Common/MyVector.h"

-

-struct CUniqBlocks

-{

-  CObjectVector<CByteBuffer> 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<UInt32> Numbers;
+  UStringVector Strings;
+  
+  void Add_UInt32(const UInt32 n)
+  {
+    Numbers.AddToUniqueSorted(n);
+  }
+  int Find(const UInt32 n)
+  {
+    return Numbers.FindInSorted(n);
+  }
+};
+
+
+struct CUniqBlocks
+{
+  CObjectVector<CByteBuffer> 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 3cf9acd..3cf7296 100644
--- a/CPP/7zip/Common/VirtThread.cpp
+++ b/CPP/7zip/Common/VirtThread.cpp
@@ -1,48 +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 0;

-    t->Execute();

-    t->FinishedEvent.Set();

-  }

-}

-

-WRes CVirtThread::Create()

-{

-  RINOK(StartEvent.CreateIfNotCreated());

-  RINOK(FinishedEvent.CreateIfNotCreated());

-  StartEvent.Reset();

-  FinishedEvent.Reset();

-  Exit = false;

-  if (Thread.IsCreated())

-    return S_OK;

-  return Thread.Create(CoderThread, this);

-}

-

-void CVirtThread::Start()

-{

-  Exit = false;

-  StartEvent.Set();

-}

-

-void CVirtThread::WaitThreadFinish()

-{

-  Exit = true;

-  if (StartEvent.IsCreated())

-    StartEvent.Set();

-  if (Thread.IsCreated())

-  {

-    Thread.Wait();

-    Thread.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 a271103..809b356 100644
--- a/CPP/7zip/Common/VirtThread.h
+++ b/CPP/7zip/Common/VirtThread.h
@@ -1,24 +1,24 @@
-// VirtThread.h

-

-#ifndef __VIRT_THREAD_H

-#define __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;

-

-  ~CVirtThread() { WaitThreadFinish(); }

-  void WaitThreadFinish(); // call it in destructor of child class !

-  WRes Create();

-  void Start();

-  virtual void Execute() = 0;

-  void WaitExecuteFinish() { 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
new file mode 100644
index 0000000..0dfcfe5
--- /dev/null
+++ b/CPP/7zip/Compress/BZip2Const.h
@@ -0,0 +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
diff --git a/CPP/7zip/Compress/BZip2Crc.cpp b/CPP/7zip/Compress/BZip2Crc.cpp
new file mode 100644
index 0000000..9639c7b
--- /dev/null
+++ b/CPP/7zip/Compress/BZip2Crc.cpp
@@ -0,0 +1,27 @@
+// BZip2Crc.cpp
+
+#include "StdAfx.h"
+
+#include "BZip2Crc.h"
+
+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
new file mode 100644
index 0000000..10e147b
--- /dev/null
+++ b/CPP/7zip/Compress/BZip2Crc.h
@@ -0,0 +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
diff --git a/CPP/7zip/Compress/BZip2Decoder.cpp b/CPP/7zip/Compress/BZip2Decoder.cpp
new file mode 100644
index 0000000..b28da5f
--- /dev/null
+++ b/CPP/7zip/Compress/BZip2Decoder.cpp
@@ -0,0 +1,1797 @@
+// BZip2Decoder.cpp
+
+#include "StdAfx.h"
+
+// #include "CopyCoder.h"
+
+/*
+#include <stdio.h>
+#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;
+
+
+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) { \
+  val |= (UInt32)(*_buf) << (24 - _numBits); \
+ _numBits += 8; \
+ _buf++; \
+}
+
+#define UPDATE_VAL  UPDATE_VAL_2(VAL)
+
+#define READ_BITS(res, num) { \
+  while (_numBits < num) { \
+    if (_buf == _lim) return SZ_OK; \
+    UPDATE_VAL_2(_value) } \
+  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) } \
+  res = _value >> (32 - num); \
+  _value <<= num; \
+  _numBits -= num; \
+}
+
+#define READ_BIT(res) READ_BITS_8(res, 1)
+
+
+
+#define VAL _value2
+#define BLOCK_SIZE blockSize2
+#define RUN_COUNTER runCounter2
+
+#define LOAD_LOCAL \
+    UInt32 VAL = this->_value; \
+    UInt32 BLOCK_SIZE = this->blockSize; \
+    UInt32 RUN_COUNTER = this->runCounter; \
+
+#define SAVE_LOCAL \
+    this->_value = VAL; \
+    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;
+      }
+      UInt32 tmp = (state2 >> (kMtfBits * state4)) & kMtfMask;
+      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 Build() instead of BuildFull() to support lbzip2 archives
+      // lbzip2 2.5 can produce dummy tree, where lens[i] = kMaxHuffmanLen
+      // BuildFull() returns error for such tree
+      for (unsigned i = state4; i < kMaxAlphaSize; i++)
+        lens[i] = 0;
+      if (!huffs[state2].Build(lens))
+      /*
+      if (!huffs[state2].BuildFull(lens, state4))
+      */
+        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 *huff = &huffs[selectors[groupIndex]];
+
+    for (;;)
+    {
+      if (groupSize == 0)
+      {
+        if (++groupIndex >= numSelectors)
+          return SZ_ERROR_DATA;
+        huff = &huffs[selectors[groupIndex]];
+        groupSize = kGroupSize;
+      }
+
+      if (_numBits <= 8 &&
+          _buf != _lim) { UPDATE_VAL
+      if (_buf != _lim) { UPDATE_VAL
+      if (_buf != _lim) { UPDATE_VAL }}}
+
+      UInt32 sym;
+      UInt32 val = VAL >> (32 - kMaxHuffmanLen);
+      if (val >= huff->_limits[kNumTableBits])
+      {
+        if (_numBits <= kMaxHuffmanLen && _buf != _lim) { UPDATE_VAL
+        if (_numBits <= kMaxHuffmanLen && _buf != _lim) { UPDATE_VAL }}
+
+        val = VAL >> (32 - kMaxHuffmanLen);
+        unsigned len;
+        for (len = kNumTableBits + 1; val >= huff->_limits[len]; len++);
+        
+        // 19.03: we use that check to support partial trees created Build() for lbzip2 archives
+        if (len > kNumBitsMax)
+          return SZ_ERROR_DATA; // that check is required, if NHuffman::Build() was used instead of BuildFull()
+
+        if (_numBits < len)
+        {
+          SAVE_LOCAL
+          return SZ_OK;
+        }
+        sym = huff->_symbols[huff->_poses[len] + ((val - huff->_limits[(size_t)len - 1]) >> (kNumBitsMax - len))];
+        VAL <<= len;
+        _numBits -= len;
+      }
+      else
+      {
+        sym = huff->_lens[val >> (kMaxHuffmanLen - kNumTableBits)];
+        unsigned len = (sym & NHuffman::kPairLenMask);
+        sym >>= NHuffman::kNumPairLenBits;
+        if (_numBits < len)
+        {
+          SAVE_LOCAL
+          return SZ_OK;
+        }
+        VAL <<= len;
+        _numBits -= len;
+      }
+
+      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
new file mode 100644
index 0000000..a8ef700
--- /dev/null
+++ b/CPP/7zip/Compress/BZip2Decoder.h
@@ -0,0 +1,389 @@
+// 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;
+const unsigned kNumBitsMax = kMaxHuffmanLen;
+
+typedef NHuffman::CDecoder<kMaxHuffmanLen, kMaxAlphaSize, kNumTableBits> 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;
+  unsigned 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<ISequentialInStream> 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
new file mode 100644
index 0000000..ef2555a
--- /dev/null
+++ b/CPP/7zip/Compress/BZip2Encoder.cpp
@@ -0,0 +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
+
+}}
diff --git a/CPP/7zip/Compress/BZip2Encoder.h b/CPP/7zip/Compress/BZip2Encoder.h
new file mode 100644
index 0000000..4a04fbd
--- /dev/null
+++ b/CPP/7zip/Compress/BZip2Encoder.h
@@ -0,0 +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<COutBuffer> 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
new file mode 100644
index 0000000..83b911d
--- /dev/null
+++ b/CPP/7zip/Compress/BZip2Register.cpp
@@ -0,0 +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")
+
+}}
diff --git a/CPP/7zip/Compress/Bcj2Coder.cpp b/CPP/7zip/Compress/Bcj2Coder.cpp
index 4e083bf..27e78b0 100644
--- a/CPP/7zip/Compress/Bcj2Coder.cpp
+++ b/CPP/7zip/Compress/Bcj2Coder.cpp
@@ -1,666 +1,853 @@
-// Bcj2Coder.cpp

-

-#include "StdAfx.h"

-

-#include "../../../C/Alloc.h"

-

-#include "../Common/StreamUtils.h"

-

-#include "Bcj2Coder.h"

-

-namespace NCompress {

-namespace NBcj2 {

-

-CBaseCoder::CBaseCoder()

-{

-  for (int i = 0; i < BCJ2_NUM_STREAMS + 1; i++)

-  {

-    _bufs[i] = NULL;

-    _bufsCurSizes[i] = 0;

-    _bufsNewSizes[i] = (1 << 18);

-  }

-}

-

-CBaseCoder::~CBaseCoder()

-{

-  for (int i = 0; i < BCJ2_NUM_STREAMS + 1; i++)

-    ::MidFree(_bufs[i]);

-}

-

-HRESULT CBaseCoder::Alloc(bool allocForOrig)

-{

-  unsigned num = allocForOrig ? BCJ2_NUM_STREAMS + 1 : BCJ2_NUM_STREAMS;

-  for (unsigned i = 0; i < num; i++)

-  {

-    UInt32 newSize = _bufsNewSizes[i];

-    const UInt32 kMinBufSize = 1;

-    if (newSize < kMinBufSize)

-      newSize = kMinBufSize;

-    if (!_bufs[i] || newSize != _bufsCurSizes[i])

-    {

-      if (_bufs[i])

-      {

-        ::MidFree(_bufs[i]);

-        _bufs[i] = 0;

-      }

-      _bufsCurSizes[i] = 0;

-      Byte *buf = (Byte *)::MidAlloc(newSize);

-      _bufs[i] = buf;

-      if (!buf)

-        return E_OUTOFMEMORY;

-      _bufsCurSizes[i] = newSize;

-    }

-  }

-  return S_OK;

-}

-

-

-

-#ifndef EXTRACT_ONLY

-

-CEncoder::CEncoder(): _relatLim(BCJ2_RELAT_LIMIT) {}

-CEncoder::~CEncoder() {}

-

-STDMETHODIMP CEncoder::SetInBufSize(UInt32, UInt32 size) { _bufsNewSizes[BCJ2_NUM_STREAMS] = size; return S_OK; }

-STDMETHODIMP CEncoder::SetOutBufSize(UInt32 streamIndex, UInt32 size) { _bufsNewSizes[streamIndex] = size; return S_OK; }

-

-STDMETHODIMP CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps)

-{

-  UInt32 relatLim = BCJ2_RELAT_LIMIT;

-  

-  for (UInt32 i = 0; i < numProps; i++)

-  {

-    const PROPVARIANT &prop = props[i];

-    PROPID propID = propIDs[i];

-    if (propID >= NCoderPropID::kReduceSize)

-      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::kDictionarySize:

-      {

-        if (prop.vt != VT_UI4)

-          return E_INVALIDARG;

-        relatLim = prop.ulVal;

-        if (relatLim > ((UInt32)1 << 31))

-          return E_INVALIDARG;

-        break;

-      }

-

-      case NCoderPropID::kNumThreads:

-        continue;

-      case NCoderPropID::kLevel:

-        continue;

-     

-      default: return E_INVALIDARG;

-    }

-  }

-  

-  _relatLim = relatLim;

-  

-  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());

-

-  UInt32 fileSize_for_Conv = 0;

-  if (inSizes && inSizes[0])

-  {

-    UInt64 inSize = *inSizes[0];

-    if (inSize <= BCJ2_FileSize_MAX)

-      fileSize_for_Conv = (UInt32)inSize;

-  }

-

-  CMyComPtr<ICompressGetSubStreamSize> getSubStreamSize;

-  inStreams[0]->QueryInterface(IID_ICompressGetSubStreamSize, (void **)&getSubStreamSize);

-

-  CBcj2Enc enc;

-    

-  enc.src = _bufs[BCJ2_NUM_STREAMS];

-  enc.srcLim = enc.src;

-    

-  {

-    for (int i = 0; i < BCJ2_NUM_STREAMS; i++)

-    {

-      enc.bufs[i] = _bufs[i];

-      enc.lims[i] = _bufs[i] + _bufsCurSizes[i];

-    }

-  }

-

-  size_t numBytes_in_ReadBuf = 0;

-  UInt64 prevProgress = 0;

-  UInt64 totalStreamRead = 0; // size read from InputStream

-  UInt64 currentInPos = 0; // data that was processed, it doesn't include data in input buffer and data in enc.temp

-  UInt64 outSizeRc = 0;

-

-  Bcj2Enc_Init(&enc);

-

-  enc.fileIp = 0;

-  enc.fileSize = fileSize_for_Conv;

-

-  enc.relatLimit = _relatLim;

-

-  enc.finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE;

-

-  bool needSubSize = false;

-  UInt64 subStreamIndex = 0;

-  UInt64 subStreamStartPos = 0;

-  bool readWasFinished = false;

-

-  for (;;)

-  {

-    if (needSubSize && getSubStreamSize)

-    {

-      enc.fileIp = 0;

-      enc.fileSize = fileSize_for_Conv;

-      enc.finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE;

-      

-      for (;;)

-      {

-        UInt64 subStreamSize = 0;

-        HRESULT result = getSubStreamSize->GetSubStreamSize(subStreamIndex, &subStreamSize);

-        needSubSize = false;

-        

-        if (result == S_OK)

-        {

-          UInt64 newEndPos = subStreamStartPos + subStreamSize;

-          

-          bool isAccurateEnd = (newEndPos < totalStreamRead ||

-            (newEndPos <= totalStreamRead && readWasFinished));

-          

-          if (newEndPos <= currentInPos && isAccurateEnd)

-          {

-            subStreamStartPos = newEndPos;

-            subStreamIndex++;

-            continue;

-          }

-          

-          enc.srcLim = _bufs[BCJ2_NUM_STREAMS] + numBytes_in_ReadBuf;

-          

-          if (isAccurateEnd)

-          {

-            // data in enc.temp is possible here

-            size_t rem = (size_t)(totalStreamRead - newEndPos);

-            

-            /* Pos_of(enc.src) <= old newEndPos <= newEndPos

-               in another case, it's fail in some code */

-            if ((size_t)(enc.srcLim - enc.src) < rem)

-              return E_FAIL;

-            

-            enc.srcLim -= rem;

-            enc.finishMode = BCJ2_ENC_FINISH_MODE_END_BLOCK;

-          }

-          

-          if (subStreamSize <= BCJ2_FileSize_MAX)

-          {

-            enc.fileIp = enc.ip + (UInt32)(subStreamStartPos - currentInPos);

-            enc.fileSize = (UInt32)subStreamSize;

-          }

-          break;

-        }

-        

-        if (result == S_FALSE)

-          break;

-        if (result == E_NOTIMPL)

-        {

-          getSubStreamSize.Release();

-          break;

-        }

-        return result;

-      }

-    }

-

-    if (readWasFinished && totalStreamRead - currentInPos == Bcj2Enc_Get_InputData_Size(&enc))

-      enc.finishMode = BCJ2_ENC_FINISH_MODE_END_STREAM;

-

-    Bcj2Enc_Encode(&enc);

-

-    currentInPos = totalStreamRead - numBytes_in_ReadBuf + (enc.src - _bufs[BCJ2_NUM_STREAMS]) - enc.tempPos;

-    

-    if (Bcj2Enc_IsFinished(&enc))

-      break;

-

-    if (enc.state < BCJ2_NUM_STREAMS)

-    {

-      size_t curSize = 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] + _bufsCurSizes[enc.state];

-    }

-    else if (enc.state != BCJ2_ENC_STATE_ORIG)

-      return E_FAIL;

-    else

-    {

-      needSubSize = true;

-

-      if (numBytes_in_ReadBuf != (size_t)(enc.src - _bufs[BCJ2_NUM_STREAMS]))

-      {

-        enc.srcLim = _bufs[BCJ2_NUM_STREAMS] + numBytes_in_ReadBuf;

-        continue;

-      }

-

-      if (readWasFinished)

-        continue;

-      

-      numBytes_in_ReadBuf = 0;

-      enc.src    = _bufs[BCJ2_NUM_STREAMS];

-      enc.srcLim = _bufs[BCJ2_NUM_STREAMS];

- 

-      UInt32 curSize = _bufsCurSizes[BCJ2_NUM_STREAMS];

-      RINOK(inStreams[0]->Read(_bufs[BCJ2_NUM_STREAMS], curSize, &curSize));

-

-      // printf("Read %6d bytes\n", curSize);

-      if (curSize == 0)

-      {

-        readWasFinished = true;

-        continue;

-      }

-

-      numBytes_in_ReadBuf = curSize;

-      totalStreamRead += numBytes_in_ReadBuf;

-      enc.srcLim = _bufs[BCJ2_NUM_STREAMS] + numBytes_in_ReadBuf;

-    }

-

-    if (progress && currentInPos - prevProgress >= (1 << 20))

-    {

-      UInt64 outSize2 = currentInPos + outSizeRc + enc.bufs[BCJ2_STREAM_RC] - enc.bufs[BCJ2_STREAM_RC];

-      prevProgress = currentInPos;

-      // printf("progress %8d, %8d\n", (int)inSize2, (int)outSize2);

-      RINOK(progress->SetRatioInfo(&currentInPos, &outSize2));

-    }

-  }

-

-  for (int i = 0; i < BCJ2_NUM_STREAMS; i++)

-  {

-    RINOK(WriteStream(outStreams[i], _bufs[i], enc.bufs[i] - _bufs[i]));

-  }

-

-  // if (currentInPos != subStreamStartPos + subStreamSize) return E_FAIL;

-

-  return S_OK;

-}

-

-STDMETHODIMP 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

-

-

-

-

-

-

-STDMETHODIMP CDecoder::SetInBufSize(UInt32 streamIndex, UInt32 size) { _bufsNewSizes[streamIndex] = size; return S_OK; }

-STDMETHODIMP CDecoder::SetOutBufSize(UInt32 , UInt32 size) { _bufsNewSizes[BCJ2_NUM_STREAMS] = size; return S_OK; }

-

-CDecoder::CDecoder(): _finishMode(false), _outSizeDefined(false), _outSize(0)

-{}

-

-STDMETHODIMP CDecoder::SetFinishMode(UInt32 finishMode)

-{

-  _finishMode = (finishMode != 0);

-  return S_OK;

-}

-

-void CDecoder::InitCommon()

-{

-  {

-    for (int i = 0; i < BCJ2_NUM_STREAMS; i++)

-      dec.lims[i] = dec.bufs[i] = _bufs[i];

-  }

-

-  {

-    for (int i = 0; i < BCJ2_NUM_STREAMS; i++)

-    {

-      _extraReadSizes[i] = 0;

-      _inStreamsProcessed[i] = 0;

-      _readRes[i] = S_OK;

-    }

-  }

-    

-  Bcj2Dec_Init(&dec);

-}

-

-HRESULT 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 outSizeProcessed = 0;

-  UInt64 prevProgress = 0;

-

-  HRESULT res = S_OK;

-

-  for (;;)

-  {

-    if (Bcj2Dec_Decode(&dec) != SZ_OK)

-      return S_FALSE;

-    

-    if (dec.state < BCJ2_NUM_STREAMS)

-    {

-      size_t totalRead = _extraReadSizes[dec.state];

-      {

-        Byte *buf = _bufs[dec.state];

-        for (size_t i = 0; i < totalRead; i++)

-          buf[i] = dec.bufs[dec.state][i];

-        dec.lims[dec.state] =

-        dec.bufs[dec.state] = buf;

-      }

-

-      if (_readRes[dec.state] != S_OK)

-      {

-        res = _readRes[dec.state];

-        break;

-      }

-

-      do

-      {

-        UInt32 curSize = _bufsCurSizes[dec.state] - (UInt32)totalRead;

-        /*

-        we want to call Read even even if size is 0

-        if (inSizes && inSizes[dec.state])

-        {

-          UInt64 rem = *inSizes[dec.state] - _inStreamsProcessed[dec.state];

-          if (curSize > rem)

-            curSize = (UInt32)rem;

-        }

-        */

-

-        HRESULT res2 = inStreams[dec.state]->Read(_bufs[dec.state] + totalRead, curSize, &curSize);

-        _readRes[dec.state] = res2;

-        if (curSize == 0)

-          break;

-        _inStreamsProcessed[dec.state] += curSize;

-        totalRead += curSize;

-        if (res2 != S_OK)

-          break;

-      }

-      while (totalRead < 4 && BCJ2_IS_32BIT_STREAM(dec.state));

-

-      if (_readRes[dec.state] != S_OK)

-        res = _readRes[dec.state];

-

-      if (totalRead == 0)

-        break;

-

-      // res == S_OK;

-

-      if (BCJ2_IS_32BIT_STREAM(dec.state))

-      {

-        unsigned extraSize = ((unsigned)totalRead & 3);

-        _extraReadSizes[dec.state] = extraSize;

-        if (totalRead < 4)

-        {

-          res = (_readRes[dec.state] != S_OK) ? _readRes[dec.state] : S_FALSE;

-          break;

-        }

-        totalRead -= extraSize;

-      }

-

-      dec.lims[dec.state] = _bufs[dec.state] + totalRead;

-    }

-    else // if (dec.state <= BCJ2_STATE_ORIG)

-    {

-      size_t curSize = dec.dest - _bufs[BCJ2_NUM_STREAMS];

-      if (curSize != 0)

-      {

-        outSizeProcessed += curSize;

-        RINOK(WriteStream(outStreams[0], _bufs[BCJ2_NUM_STREAMS], curSize));

-      }

-      dec.dest = _bufs[BCJ2_NUM_STREAMS];

-      {

-        size_t rem = _bufsCurSizes[BCJ2_NUM_STREAMS];

-        if (outSizes && outSizes[0])

-        {

-          UInt64 outSize = *outSizes[0] - outSizeProcessed;

-          if (rem > outSize)

-            rem = (size_t)outSize;

-        }

-        dec.destLim = dec.dest + rem;

-        if (rem == 0)

-          break;

-      }

-    }

-

-    if (progress)

-    {

-      const UInt64 outSize2 = outSizeProcessed + (dec.dest - _bufs[BCJ2_NUM_STREAMS]);

-      if (outSize2 - prevProgress >= (1 << 22))

-      {

-        const UInt64 inSize2 = outSize2 + _inStreamsProcessed[BCJ2_STREAM_RC] - (dec.lims[BCJ2_STREAM_RC] - dec.bufs[BCJ2_STREAM_RC]);

-        RINOK(progress->SetRatioInfo(&inSize2, &outSize2));

-        prevProgress = outSize2;

-      }

-    }

-  }

-

-  size_t curSize = dec.dest - _bufs[BCJ2_NUM_STREAMS];

-  if (curSize != 0)

-  {

-    outSizeProcessed += curSize;

-    RINOK(WriteStream(outStreams[0], _bufs[BCJ2_NUM_STREAMS], curSize));

-  }

-

-  if (res != S_OK)

-    return res;

-

-  if (_finishMode)

-  {

-    if (!Bcj2Dec_IsFinished(&dec))

-      return S_FALSE;

-

-    // we still allow the cases when input streams are larger than required for decoding.

-    // so the case (dec.state == BCJ2_STATE_ORIG) is also allowed, if MAIN stream is larger than required.

-    if (dec.state != BCJ2_STREAM_MAIN &&

-        dec.state != BCJ2_DEC_STATE_ORIG)

-      return S_FALSE;

-

-    if (inSizes)

-    {

-      for (int i = 0; i < BCJ2_NUM_STREAMS; i++)

-      {

-        size_t rem = dec.lims[i] - dec.bufs[i] + _extraReadSizes[i];

-        /*

-        if (rem != 0)

-          return S_FALSE;

-        */

-        if (inSizes[i] && *inSizes[i] != _inStreamsProcessed[i] - rem)

-          return S_FALSE;

-      }

-    }

-  }

-

-  return S_OK;

-}

-

-STDMETHODIMP CDecoder::SetInStream2(UInt32 streamIndex, ISequentialInStream *inStream)

-{

-  _inStreams[streamIndex] = inStream;

-  return S_OK;

-}

-

-STDMETHODIMP CDecoder::ReleaseInStream2(UInt32 streamIndex)

-{

-  _inStreams[streamIndex].Release();

-  return S_OK;

-}

-

-STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)

-{

-  _outSizeDefined = (outSize != NULL);

-  _outSize = 0;

-  if (_outSizeDefined)

-    _outSize = *outSize;

-

-  _outSize_Processed = 0;

-

-  HRESULT res = Alloc(false);

-  

-  InitCommon();

-  dec.destLim = dec.dest = NULL;

-

-  return res;

-}

-

-

-STDMETHODIMP CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)

-{

-  if (processedSize)

-    *processedSize = 0;

-

-  if (size == 0)

-    return S_OK;

-

-  UInt32 totalProcessed = 0;

- 

-  if (_outSizeDefined)

-  {

-    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 (;;)

-  {

-    SRes sres = Bcj2Dec_Decode(&dec);

-    if (sres != SZ_OK)

-      return S_FALSE;

-    

-    {

-      UInt32 curSize = (UInt32)(dec.dest - (Byte *)data);

-      if (curSize != 0)

-      {

-        totalProcessed += curSize;

-        if (processedSize)

-          *processedSize = totalProcessed;

-        data = (void *)((Byte *)data + curSize);

-        size -= curSize;

-        _outSize_Processed += curSize;

-      }

-    }

-

-    if (dec.state >= BCJ2_NUM_STREAMS)

-      break;

-

-    {

-      size_t totalRead = _extraReadSizes[dec.state];

-      {

-        Byte *buf = _bufs[dec.state];

-        for (size_t i = 0; i < totalRead; i++)

-          buf[i] = dec.bufs[dec.state][i];

-        dec.lims[dec.state] =

-        dec.bufs[dec.state] = buf;

-      }

-

-      if (_readRes[dec.state] != S_OK)

-        return _readRes[dec.state];

-

-      do

-      {

-        UInt32 curSize = _bufsCurSizes[dec.state] - (UInt32)totalRead;

-        HRESULT res2 = _inStreams[dec.state]->Read(_bufs[dec.state] + totalRead, curSize, &curSize);

-        _readRes[dec.state] = res2;

-        if (curSize == 0)

-          break;

-        _inStreamsProcessed[dec.state] += curSize;

-        totalRead += curSize;

-        if (res2 != S_OK)

-          break;

-      }

-      while (totalRead < 4 && BCJ2_IS_32BIT_STREAM(dec.state));

-

-      if (totalRead == 0)

-      {

-        if (totalProcessed == 0)

-          res = _readRes[dec.state];

-        break;

-      }

-

-      if (BCJ2_IS_32BIT_STREAM(dec.state))

-      {

-        unsigned extraSize = ((unsigned)totalRead & 3);

-        _extraReadSizes[dec.state] = extraSize;

-        if (totalRead < 4)

-        {

-          if (totalProcessed != 0)

-            return S_OK;

-          return (_readRes[dec.state] != S_OK) ? _readRes[dec.state] : S_FALSE;

-        }

-        totalRead -= extraSize;

-      }

-

-      dec.lims[dec.state] = _bufs[dec.state] + totalRead;

-    }

-  }

-

-  if (_finishMode && _outSizeDefined && _outSize == _outSize_Processed)

-  {

-    if (!Bcj2Dec_IsFinished(&dec))

-      return S_FALSE;

-

-    if (dec.state != BCJ2_STREAM_MAIN &&

-        dec.state != BCJ2_DEC_STATE_ORIG)

-      return S_FALSE;

-  

-    /*

-    for (int i = 0; i < BCJ2_NUM_STREAMS; i++)

-      if (dec.bufs[i] != dec.lims[i] || _extraReadSizes[i] != 0)

-        return S_FALSE;

-    */

-  }

-

-  return res;

-}

-

-

-STDMETHODIMP CDecoder::GetInStreamProcessedSize2(UInt32 streamIndex, UInt64 *value)

-{

-  const size_t rem = dec.lims[streamIndex] - dec.bufs[streamIndex] + _extraReadSizes[streamIndex];

-  *value = _inStreamsProcessed[streamIndex] - rem;

-  return S_OK;

-}

-

-}}

+// Bcj2Coder.cpp
+
+#include "StdAfx.h"
+
+// #include <stdio.h>
+
+#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 -= 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;
+      }
+    }
+  }
+
+  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 666bf8c..2ab91bc 100644
--- a/CPP/7zip/Compress/Bcj2Coder.h
+++ b/CPP/7zip/Compress/Bcj2Coder.h
@@ -1,120 +1,127 @@
-// Bcj2Coder.h

-

-#ifndef __COMPRESS_BCJ2_CODER_H

-#define __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 _bufsCurSizes[BCJ2_NUM_STREAMS + 1];

-  UInt32 _bufsNewSizes[BCJ2_NUM_STREAMS + 1];

-

-  HRESULT Alloc(bool allocForOrig = true);

-public:

-  CBaseCoder();

-  ~CBaseCoder();

-};

-

-

-#ifndef EXTRACT_ONLY

-

-class CEncoder:

-  public ICompressCoder2,

-  public ICompressSetCoderProperties,

-  public ICompressSetBufSize,

-  public CMyUnknownImp,

-  public CBaseCoder

-{

-  UInt32 _relatLim;

-

-  HRESULT CodeReal(ISequentialInStream * const *inStreams, const UInt64 * const *inSizes, UInt32 numInStreams,

-      ISequentialOutStream * const *outStreams, const UInt64 * const *outSizes, UInt32 numOutStreams,

-      ICompressProgressInfo *progress);

-

-public:

-  MY_UNKNOWN_IMP3(ICompressCoder2, ICompressSetCoderProperties, ICompressSetBufSize)

-

-  STDMETHOD(Code)(ISequentialInStream * const *inStreams, const UInt64 * const *inSizes, UInt32 numInStreams,

-      ISequentialOutStream * const *outStreams, const UInt64 * const *outSizes, UInt32 numOutStreams,

-      ICompressProgressInfo *progress);

-

-  STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);

-  

-  STDMETHOD(SetInBufSize)(UInt32 streamIndex, UInt32 size);

-  STDMETHOD(SetOutBufSize)(UInt32 streamIndex, UInt32 size);

-  

-  CEncoder();

-  ~CEncoder();

-};

-

-#endif

-

-class CDecoder:

-  public ICompressCoder2,

-  public ICompressSetFinishMode,

-  public ICompressGetInStreamProcessedSize2,

-  public ICompressSetInStream2,

-  public ISequentialInStream,

-  public ICompressSetOutStreamSize,

-  public ICompressSetBufSize,

-  public CMyUnknownImp,

-  public CBaseCoder

-{

-  unsigned _extraReadSizes[BCJ2_NUM_STREAMS];

-  UInt64 _inStreamsProcessed[BCJ2_NUM_STREAMS];

-  HRESULT _readRes[BCJ2_NUM_STREAMS];

-  CMyComPtr<ISequentialInStream> _inStreams[BCJ2_NUM_STREAMS];

-

-  bool _finishMode;

-  bool _outSizeDefined;

-  UInt64 _outSize;

-  UInt64 _outSize_Processed;

-  CBcj2Dec dec;

-

-  void InitCommon();

-  // HRESULT ReadSpec();

-  

-public:

-  MY_UNKNOWN_IMP7(

-    ICompressCoder2,

-    ICompressSetFinishMode,

-    ICompressGetInStreamProcessedSize2,

-    ICompressSetInStream2,

-    ISequentialInStream,

-    ICompressSetOutStreamSize,

-    ICompressSetBufSize

-    );

-  

-  STDMETHOD(Code)(ISequentialInStream * const *inStreams, const UInt64 * const *inSizes, UInt32 numInStreams,

-      ISequentialOutStream * const *outStreams, const UInt64 * const *outSizes, UInt32 numOutStreams,

-      ICompressProgressInfo *progress);

-

-  STDMETHOD(SetFinishMode)(UInt32 finishMode);

-  STDMETHOD(GetInStreamProcessedSize2)(UInt32 streamIndex, UInt64 *value);

-

-  STDMETHOD(SetInStream2)(UInt32 streamIndex, ISequentialInStream *inStream);

-  STDMETHOD(ReleaseInStream2)(UInt32 streamIndex);

-

-  STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);

-

-  STDMETHOD(SetOutStreamSize)(const UInt64 *outSize);

-

-  STDMETHOD(SetInBufSize)(UInt32 streamIndex, UInt32 size);

-  STDMETHOD(SetOutBufSize)(UInt32 streamIndex, UInt32 size);

-

-  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<ISequentialInStream> _inStreams[BCJ2_NUM_STREAMS];
+#endif
+ 
+public:
+  CDecoder();
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Compress/Bcj2Register.cpp b/CPP/7zip/Compress/Bcj2Register.cpp
index bce6178..1ce4dec 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 EXTRACT_ONLY

-REGISTER_CODEC_CREATE_2(CreateCodecOut, CEncoder(), ICompressCoder2)

-#else

-#define CreateCodecOut NULL

-#endif

-

-REGISTER_CODEC_VAR

-  { 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 a50360c..0047874 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 {

-

-STDMETHODIMP CCoder::Init()

-{

-  _bufferPos = 0;

-  x86_Convert_Init(_prevMask);

-  return S_OK;

-}

-

-STDMETHODIMP_(UInt32) CCoder::Filter(Byte *data, UInt32 size)

-{

-  UInt32 processed = (UInt32)::x86_Convert(data, size, _bufferPos, &_prevMask, _encode);

-  _bufferPos += 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 475dfe5..734a278 100644
--- a/CPP/7zip/Compress/BcjCoder.h
+++ b/CPP/7zip/Compress/BcjCoder.h
@@ -1,31 +1,37 @@
-// BcjCoder.h

-

-#ifndef __COMPRESS_BCJ_CODER_H

-#define __COMPRESS_BCJ_CODER_H

-

-#include "../../../C/Bra.h"

-

-#include "../../Common/MyCom.h"

-

-#include "../ICoder.h"

-

-namespace NCompress {

-namespace NBcj {

-

-class CCoder:

-  public ICompressFilter,

-  public CMyUnknownImp

-{

-  UInt32 _bufferPos;

-  UInt32 _prevMask;

-  int _encode;

-public:

-  MY_UNKNOWN_IMP1(ICompressFilter);

-  INTERFACE_ICompressFilter(;)

-

-  CCoder(int encode): _bufferPos(0), _encode(encode) { x86_Convert_Init(_prevMask); }

-};

-

-}}

-

-#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 48cc057..0348f64 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,

-    CCoder(false),

-    CCoder(true),

-    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
new file mode 100644
index 0000000..876e649
--- /dev/null
+++ b/CPP/7zip/Compress/BitlDecoder.cpp
@@ -0,0 +1,25 @@
+// BitlDecoder.cpp
+
+#include "StdAfx.h"
+
+#include "BitlDecoder.h"
+
+namespace NBitl {
+
+Byte kInvertTable[256];
+
+static
+struct CInverterTableInitializer
+{
+  CInverterTableInitializer()
+  {
+    for (unsigned i = 0; i < 256; i++)
+    {
+      unsigned x = ((i & 0x55) << 1) | ((i & 0xAA) >> 1);
+      x = ((x & 0x33) << 2) | ((x & 0xCC) >> 2);
+      kInvertTable[i] = (Byte)(((x & 0x0F) << 4) | ((x & 0xF0) >> 4));
+    }
+  }
+} g_InverterTableInitializer;
+
+}
diff --git a/CPP/7zip/Compress/BitlDecoder.h b/CPP/7zip/Compress/BitlDecoder.h
new file mode 100644
index 0000000..789ad1f
--- /dev/null
+++ b/CPP/7zip/Compress/BitlDecoder.h
@@ -0,0 +1,172 @@
+// BitlDecoder.h -- the Least Significant Bit of byte is First
+
+#ifndef ZIP7_INC_BITL_DECODER_H
+#define ZIP7_INC_BITL_DECODER_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;
+
+extern Byte kInvertTable[256];
+
+/* 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 TInByte>
+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 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 TInByte>
+class CDecoder: public CBaseDecoder<TInByte>
+{
+  UInt32 _normalValue;
+
+public:
+  void Init()
+  {
+    CBaseDecoder<TInByte>::Init();
+    _normalValue = 0;
+  }
+  
+  Z7_FORCE_INLINE
+  void Normalize()
+  {
+    for (; this->_bitPos >= 8; this->_bitPos -= 8)
+    {
+      Byte b = this->_stream.ReadByte();
+      _normalValue = ((UInt32)b << (kNumBigValueBits - this->_bitPos)) | _normalValue;
+      this->_value = (this->_value << 8) | kInvertTable[b];
+    }
+  }
+  
+  Z7_FORCE_INLINE
+  UInt32 GetValue(unsigned numBits)
+  {
+    Normalize();
+    return ((this->_value >> (8 - this->_bitPos)) & kMask) >> (kNumValueBits - numBits);
+  }
+  
+  Z7_FORCE_INLINE
+  void MovePos(unsigned numBits)
+  {
+    this->_bitPos += 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
+  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
new file mode 100644
index 0000000..67b1428
--- /dev/null
+++ b/CPP/7zip/Compress/BitlEncoder.h
@@ -0,0 +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
diff --git a/CPP/7zip/Compress/BitmDecoder.h b/CPP/7zip/Compress/BitmDecoder.h
new file mode 100644
index 0000000..199a228
--- /dev/null
+++ b/CPP/7zip/Compress/BitmDecoder.h
@@ -0,0 +1,100 @@
+// 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 TInByte>
+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
+  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
new file mode 100644
index 0000000..978ee1c
--- /dev/null
+++ b/CPP/7zip/Compress/BitmEncoder.h
@@ -0,0 +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 TOutByte>
+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 d5a90f1..d9fec8c 100644
--- a/CPP/7zip/Compress/BranchMisc.cpp
+++ b/CPP/7zip/Compress/BranchMisc.cpp
@@ -1,23 +1,110 @@
-// BranchMisc.cpp

-

-#include "StdAfx.h"

-

-#include "BranchMisc.h"

-

-namespace NCompress {

-namespace NBranch {

-

-STDMETHODIMP CCoder::Init()

-{

-  _bufferPos = 0;

-  return S_OK;

-}

-

-STDMETHODIMP_(UInt32) CCoder::Filter(Byte *data, UInt32 size)

-{

-  UInt32 processed = (UInt32)BraFunc(data, size, _bufferPos, _encode);

-  _bufferPos += processed;

-  return processed;

-}

-

-}}

+// 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;
+}
+
+
+namespace NArm64 {
+
+#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)(Z7_BRANCH_CONV_ENC(ARM64)(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 & 3) != 0)
+        return E_INVALIDARG;
+    }
+  }
+  _pc_Init = pc;
+  return S_OK;
+}
+
+
+Z7_COM7F_IMF(CEncoder::WriteCoderProperties(ISequentialOutStream *outStream))
+{
+  if (_pc_Init == 0)
+    return S_OK;
+  Byte buf[4];
+  SetUi32(buf, _pc_Init)
+  return WriteStream(outStream, buf, 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)(Z7_BRANCH_CONV_DEC(ARM64)(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 & 3) != 0)
+      return E_NOTIMPL;
+  }
+  _pc_Init = val;
+  return S_OK;
+}
+
+}
+
+}}
diff --git a/CPP/7zip/Compress/BranchMisc.h b/CPP/7zip/Compress/BranchMisc.h
index 02a56c3..a5793f7 100644
--- a/CPP/7zip/Compress/BranchMisc.h
+++ b/CPP/7zip/Compress/BranchMisc.h
@@ -1,35 +1,57 @@
-// BranchMisc.h

-

-#ifndef __COMPRESS_BRANCH_MISC_H

-#define __COMPRESS_BRANCH_MISC_H

-

-#include "../../Common/MyCom.h"

-

-#include "../ICoder.h"

-

-EXTERN_C_BEGIN

-

-typedef SizeT (*Func_Bra)(Byte *data, SizeT size, UInt32 ip, int encoding);

-

-EXTERN_C_END

-

-namespace NCompress {

-namespace NBranch {

-

-class CCoder:

-  public ICompressFilter,

-  public CMyUnknownImp

-{

-  UInt32 _bufferPos;

-  int _encode;

-  Func_Bra BraFunc;

-public:

-  MY_UNKNOWN_IMP1(ICompressFilter);

-  INTERFACE_ICompressFilter(;)

-

-  CCoder(Func_Bra bra, int encode):  _bufferPos(0), _encode(encode), 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) {}
+};
+
+namespace NArm64 {
+
+#ifndef Z7_EXTRACT_ONLY
+
+Z7_CLASS_IMP_COM_3(
+  CEncoder
+  , ICompressFilter
+  , ICompressSetCoderProperties
+  , ICompressWriteCoderProperties
+)
+  UInt32 _pc;
+  UInt32 _pc_Init;
+public:
+  CEncoder(): _pc(0), _pc_Init(0) {}
+};
+
+#endif
+
+Z7_CLASS_IMP_COM_2(
+  CDecoder
+  , ICompressFilter
+  , ICompressSetDecoderProperties2
+)
+  UInt32 _pc;
+  UInt32 _pc_Init;
+public:
+  CDecoder(): _pc(0), _pc_Init(0) {}
+};
+
+}
+
+}}
+
+#endif
diff --git a/CPP/7zip/Compress/BranchRegister.cpp b/CPP/7zip/Compress/BranchRegister.cpp
index b83c6bc..80fbf60 100644
--- a/CPP/7zip/Compress/BranchRegister.cpp
+++ b/CPP/7zip/Compress/BranchRegister.cpp
@@ -1,41 +1,55 @@
-// BranchRegister.cpp

-

-#include "StdAfx.h"

-

-#include "../../../C/Bra.h"

-

-#include "../Common/RegisterCodec.h"

-

-#include "BranchMisc.h"

-

-namespace NCompress {

-namespace NBranch {

-

-#define CREATE_BRA(n) \

-    REGISTER_FILTER_CREATE(CreateBra_Decoder_ ## n, CCoder(n ## _Convert, false)) \

-    REGISTER_FILTER_CREATE(CreateBra_Encoder_ ## n, CCoder(n ## _Convert, true)) \

-

-CREATE_BRA(PPC)

-CREATE_BRA(IA64)

-CREATE_BRA(ARM)

-CREATE_BRA(ARMT)

-CREATE_BRA(SPARC)

-

-#define METHOD_ITEM(n, id, name) \

-    REGISTER_FILTER_ITEM( \

-      CreateBra_Decoder_ ## n, \

-      CreateBra_Encoder_ ## n, \

-      0x3030000 + id, name)

-

-REGISTER_CODECS_VAR

-{

-  METHOD_ITEM(PPC,   0x205, "PPC"),

-  METHOD_ITEM(IA64,  0x401, "IA64"),

-  METHOD_ITEM(ARM,   0x501, "ARM"),

-  METHOD_ITEM(ARMT,  0x701, "ARMT"),

-  METHOD_ITEM(SPARC, 0x805, "SPARC")

-};

-

-REGISTER_CODECS(Branch)

-

-}}

+// 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(n)))
+#endif
+
+#define CREATE_BRA(n) \
+    REGISTER_FILTER_CREATE(CreateBra_Decoder_ ## n, CCoder(Z7_BRANCH_CONV_DEC(n))) \
+    CREATE_BRA_E(n)
+
+CREATE_BRA(PPC)
+CREATE_BRA(IA64)
+CREATE_BRA(ARM)
+CREATE_BRA(ARMT)
+CREATE_BRA(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(PPC,   0x205, "PPC"),
+  METHOD_ITEM(IA64,  0x401, "IA64"),
+  METHOD_ITEM(ARM,   0x501, "ARM"),
+  METHOD_ITEM(ARMT,  0x701, "ARMT"),
+  METHOD_ITEM(SPARC, 0x805, "SPARC")
+};
+
+REGISTER_CODECS(Branch)
+
+namespace NArm64 {
+REGISTER_FILTER_E(ARM64,
+    CDecoder(),
+    CEncoder(),
+    0xa, "ARM64")
+}
+
+}}
diff --git a/CPP/7zip/Compress/ByteSwap.cpp b/CPP/7zip/Compress/ByteSwap.cpp
index ee103af..cc28d8b 100644
--- a/CPP/7zip/Compress/ByteSwap.cpp
+++ b/CPP/7zip/Compress/ByteSwap.cpp
@@ -1,92 +1,91 @@
-// ByteSwap.cpp

-

-#include "StdAfx.h"

-

-#include "../../Common/MyCom.h"

-

-#include "../ICoder.h"

-

-#include "../Common/RegisterCodec.h"

-

-namespace NCompress {

-namespace NByteSwap {

-

-class CByteSwap2:

-  public ICompressFilter,

-  public CMyUnknownImp

-{

-public:

-  MY_UNKNOWN_IMP1(ICompressFilter);

-  INTERFACE_ICompressFilter(;)

-};

-

-class CByteSwap4:

-  public ICompressFilter,

-  public CMyUnknownImp

-{

-public:

-  MY_UNKNOWN_IMP1(ICompressFilter);

-  INTERFACE_ICompressFilter(;)

-};

-

-STDMETHODIMP CByteSwap2::Init() { return S_OK; }

-

-STDMETHODIMP_(UInt32) CByteSwap2::Filter(Byte *data, UInt32 size)

-{

-  const UInt32 kStep = 2;

-  if (size < kStep)

-    return 0;

-  size &= ~(kStep - 1);

-  

-  const Byte *end = data + (size_t)size;

-  

-  do

-  {

-    Byte b0 = data[0];

-    data[0] = data[1];

-    data[1] = b0;

-    data += kStep;

-  }

-  while (data != end);

-

-  return size;

-}

-

-STDMETHODIMP CByteSwap4::Init() { return S_OK; }

-

-STDMETHODIMP_(UInt32) CByteSwap4::Filter(Byte *data, UInt32 size)

-{

-  const UInt32 kStep = 4;

-  if (size < kStep)

-    return 0;

-  size &= ~(kStep - 1);

-  

-  const Byte *end = data + (size_t)size;

-  

-  do

-  {

-    Byte b0 = data[0];

-    Byte b1 = data[1];

-    data[0] = data[3];

-    data[1] = data[2];

-    data[2] = b1;

-    data[3] = b0;

-    data += kStep;

-  }

-  while (data != end);

-

-  return size;

-}

-

-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
new file mode 100644
index 0000000..e2bc0df
--- /dev/null
+++ b/CPP/7zip/Compress/Codec.def
@@ -0,0 +1,7 @@
+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 7be496c..e37ae14 100644
--- a/CPP/7zip/Compress/CodecExports.cpp
+++ b/CPP/7zip/Compress/CodecExports.cpp
@@ -1,344 +1,378 @@
-// CodecExports.cpp

-

-#include "StdAfx.h"

-

-#include "../../../C/CpuArch.h"

-

-#include "../../Common/ComTry.h"

-#include "../../Common/MyCom.h"

-

-#include "../../Windows/Defs.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()

-{

-  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;

-  

-  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 = i;

-    return S_OK;

-  }

-  

-  return S_OK;

-}

-

-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;

-    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)

-{

-  return CreateCoder2(false, index, iid, 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)

-{

-  *outObject = NULL;

-

-  bool isFilter = false;

-  bool isCoder2 = false;

-  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;

-  HRESULT res = FindCodecClassId(clsid, isCoder2, isFilter, encode, codecIndex);

-  if (res != S_OK)

-    return res;

-  if (codecIndex < 0)

-    return CLASS_E_CLASSNOTAVAILABLE;

-

-  return CreateCoderMain(codecIndex, encode, outObject);

-}

- 

-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:

-      // if (codec.IsFilter)

-      {

-        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)

-{

-  *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;

-  UInt64 id = GetUi64(clsid->Data4);

-  for (unsigned i = 0; i < g_NumCodecs; i++)

-    if (id == g_Hashers[i]->Id)

-      return 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)

-{

-  COM_TRY_BEGIN

-  *outObject = 0;

-  int index = FindHasherClassId(clsid);

-  if (index < 0)

-    return CLASS_E_CLASSNOTAVAILABLE;

-  return CreateHasher2(index, outObject);

-  COM_TRY_END

-}

-

-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;

-}

-

-class CHashers:

-  public IHashers,

-  public CMyUnknownImp

-{

-public:

-  MY_UNKNOWN_IMP1(IHashers)

-

-  STDMETHOD_(UInt32, GetNumHashers)();

-  STDMETHOD(GetHasherProp)(UInt32 index, PROPID propID, PROPVARIANT *value);

-  STDMETHOD(CreateHasher)(UInt32 index, IHasher **hasher);

-};

-

-STDAPI GetHashers(IHashers **hashers)

-{

-  COM_TRY_BEGIN

-  *hashers = new CHashers;

-  if (*hashers)

-    (*hashers)->AddRef();

-  return S_OK;

-  COM_TRY_END

-}

-

-STDMETHODIMP_(UInt32) CHashers::GetNumHashers()

-{

-  return g_NumHashers;

-}

-

-STDMETHODIMP CHashers::GetHasherProp(UInt32 index, PROPID propID, PROPVARIANT *value)

-{

-  return ::GetHasherProp(index, propID, value);

-}

-

-STDMETHODIMP CHashers::CreateHasher(UInt32 index, IHasher **hasher)

-{

-  return ::CreateHasher2(index, hasher);

-}

+// 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 89b5237..b779e08 100644
--- a/CPP/7zip/Compress/CopyCoder.cpp
+++ b/CPP/7zip/Compress/CopyCoder.cpp
@@ -1,120 +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);

-}

-

-STDMETHODIMP CCopyCoder::SetFinishMode(UInt32 /* finishMode */)

-{

-  return S_OK;

-}

-

-STDMETHODIMP 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 && size > *outSize - TotalSize)

-      size = (UInt32)(*outSize - TotalSize);

-    if (size == 0)

-      return S_OK;

-    

-    HRESULT readRes = inStream->Read(_buf, size, &size);

-

-    if (size == 0)

-      return readRes;

-

-    if (outStream)

-    {

-      UInt32 pos = 0;

-      do

-      {

-        UInt32 curSize = size - pos;

-        HRESULT res = outStream->Write(_buf + pos, curSize, &curSize);

-        pos += curSize;

-        TotalSize += curSize;

-        RINOK(res);

-        if (curSize == 0)

-          return E_FAIL;

-      }

-      while (pos < size);

-    }

-    else

-      TotalSize += size;

-

-    RINOK(readRes);

-

-    if (progress)

-    {

-      RINOK(progress->SetRatioInfo(&TotalSize, &TotalSize));

-    }

-  }

-}

-

-STDMETHODIMP CCopyCoder::SetInStream(ISequentialInStream *inStream)

-{

-  _inStream = inStream;

-  TotalSize = 0;

-  return S_OK;

-}

-

-STDMETHODIMP CCopyCoder::ReleaseInStream()

-{

-  _inStream.Release();

-  return S_OK;

-}

-

-STDMETHODIMP 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;

-}

-

-STDMETHODIMP CCopyCoder::GetInStreamProcessedSize(UInt64 *value)

-{

-  *value = TotalSize;

-  return S_OK;

-}

-

-HRESULT CopyStream(ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress)

-{

-  CMyComPtr<ICompressCoder> 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<ICompressCoder> 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<ICompressCoder> 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<ICompressCoder> 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 b2fa491..cb93e4e 100644
--- a/CPP/7zip/Compress/CopyCoder.h
+++ b/CPP/7zip/Compress/CopyCoder.h
@@ -1,49 +1,34 @@
-// Compress/CopyCoder.h

-

-#ifndef __COMPRESS_COPY_CODER_H

-#define __COMPRESS_COPY_CODER_H

-

-#include "../../Common/MyCom.h"

-

-#include "../ICoder.h"

-

-namespace NCompress {

-

-class CCopyCoder:

-  public ICompressCoder,

-  public ICompressSetInStream,

-  public ISequentialInStream,

-  public ICompressSetFinishMode,

-  public ICompressGetInStreamProcessedSize,

-  public CMyUnknownImp

-{

-  Byte *_buf;

-  CMyComPtr<ISequentialInStream> _inStream;

-public:

-  UInt64 TotalSize;

-  

-  CCopyCoder(): _buf(0), TotalSize(0) {};

-  ~CCopyCoder();

-

-  MY_UNKNOWN_IMP5(

-      ICompressCoder,

-      ICompressSetInStream,

-      ISequentialInStream,

-      ICompressSetFinishMode,

-      ICompressGetInStreamProcessedSize)

-

-  STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,

-      const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);

-  STDMETHOD(SetInStream)(ISequentialInStream *inStream);

-  STDMETHOD(ReleaseInStream)();

-  STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);

-  STDMETHOD(SetFinishMode)(UInt32 finishMode);

-  STDMETHOD(GetInStreamProcessedSize)(UInt64 *value);

-};

-

-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<ISequentialInStream> _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 1c59fe0..7141ab5 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
new file mode 100644
index 0000000..7f6bae0
--- /dev/null
+++ b/CPP/7zip/Compress/Deflate64Register.cpp
@@ -0,0 +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")
+
+}}
diff --git a/CPP/7zip/Compress/DeflateConst.h b/CPP/7zip/Compress/DeflateConst.h
new file mode 100644
index 0000000..a73d8ff
--- /dev/null
+++ b/CPP/7zip/Compress/DeflateConst.h
@@ -0,0 +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
diff --git a/CPP/7zip/Compress/DeflateDecoder.cpp b/CPP/7zip/Compress/DeflateDecoder.cpp
new file mode 100644
index 0000000..017b694
--- /dev/null
+++ b/CPP/7zip/Compress/DeflateDecoder.cpp
@@ -0,0 +1,541 @@
+// 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),
+    ZlibMode(false) {}
+
+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
+  {
+    UInt32 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 = 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))
+    
+    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;
+  }
+
+  while (_remainLen > 0 && curSize > 0)
+  {
+    _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 > 0 || 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 */
+      for (; m_StoredBlockSize > 0 && curSize > 0 && m_InBitStream.ThereAreDataInBitsBuffer(); m_StoredBlockSize--, curSize--)
+        m_OutWindowStream.PutByte(ReadAlignedByte());
+      for (; m_StoredBlockSize > 0 && curSize > 0; m_StoredBlockSize--, curSize--)
+        m_OutWindowStream.PutByte(m_InBitStream.ReadDirectByte());
+      _needReadTable = (m_StoredBlockSize == 0);
+      continue;
+    }
+    
+    while (curSize > 0)
+    {
+      if (m_InBitStream.ExtraBitsWereRead_Fast())
+        return S_FALSE;
+
+      UInt32 sym = m_MainDecoder.Decode(&m_InBitStream);
+
+      if (sym < 0x100)
+      {
+        m_OutWindowStream.PutByte((Byte)sym);
+        curSize--;
+        continue;
+      }
+      else if (sym == kSymbolEndOfBlock)
+      {
+        _needReadTable = true;
+        break;
+      }
+      else if (sym < kMainTableSize)
+      {
+        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);
+        }
+        UInt32 locLen = len;
+        if (locLen > curSize)
+          locLen = (UInt32)curSize;
+        sym = m_DistDecoder.Decode(&m_InBitStream);
+        if (sym >= _numDistLevels)
+          return S_FALSE;
+        sym = kDistStart[sym] + m_InBitStream.ReadBits(kDistDirectBits[sym]);
+        /*
+        if (sym >= 4)
+        {
+          // sym &= 31;
+          const unsigned numDirectBits = (unsigned)(((sym >> 1) - 1));
+          sym = (2 | (sym & 1)) << numDirectBits;
+          sym += m_InBitStream.ReadBits(numDirectBits);
+        }
+        */
+        if (!m_OutWindowStream.CopyBlock(sym, locLen))
+          return S_FALSE;
+        curSize -= locLen;
+        len -= locLen;
+        if (len != 0)
+        {
+          _remainLen = (Int32)len;
+          _rep0 = sym;
+          break;
+        }
+      }
+      else
+        return S_FALSE;
+    }
+    
+    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 (ZlibMode || _needFinishInput)
+          finishInputStream = true;
+      }
+    }
+    if (!finishInputStream && 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))
+    }
+  }
+  
+  if (_remainLen == kLenIdFinished && ZlibMode)
+  {
+    m_InBitStream.AlignToByte();
+    for (unsigned i = 0; i < 4; i++)
+      ZlibFooter[i] = ReadAlignedByte();
+  }
+  
+  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();
+  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))
+{
+  HRESULT res;
+
+  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 (ZlibMode || _needFinishInput)
+        finishInputStream = true;
+    }
+  }
+  if (!finishInputStream && size == 0)
+    return S_OK;
+
+  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
new file mode 100644
index 0000000..d31f299
--- /dev/null
+++ b/CPP/7zip/Compress/DeflateDecoder.h
@@ -0,0 +1,153 @@
+// 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;
+
+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)
+  Z7_IFACE_COM7_IMP(ICompressReadUnusedFromInBuf)
+public:
+  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;
+  CMyComPtr<ISequentialInStream> m_InStreamRef;
+  NBitl::CDecoder<CInBuffer> m_InBitStream;
+  NCompress::NHuffman::CDecoder<kNumHuffmanBits, kFixedMainTableSize> m_MainDecoder;
+  NCompress::NHuffman::CDecoder<kNumHuffmanBits, kFixedDistTableSize> m_DistDecoder;
+  NCompress::NHuffman::CDecoder7b<kLevelTableSize> m_LevelDecoder;
+
+  UInt32 m_StoredBlockSize;
+
+  UInt32 _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;
+  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:
+  bool ZlibMode;
+  Byte ZlibFooter[4];
+
+  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
+  {
+    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
new file mode 100644
index 0000000..e277ad6
--- /dev/null
+++ b/CPP/7zip/Compress/DeflateEncoder.cpp
@@ -0,0 +1,1019 @@
+// 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;
+
+static Byte g_LenSlots[kNumLenSymbolsMax];
+
+#define kNumLogBits 9    // do not change it
+static Byte g_FastPos[1 << kNumLogBits];
+
+class CFastPosInit
+{
+public:
+  CFastPosInit()
+  {
+    unsigned i;
+    for (i = 0; i < kNumLenSlots; i++)
+    {
+      unsigned c = kLenStart32[i];
+      unsigned j = 1 << 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++)
+    {
+      UInt32 k = (1 << kDistDirectBits[slotFast]);
+      for (UInt32 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
new file mode 100644
index 0000000..be181e1
--- /dev/null
+++ b/CPP/7zip/Compress/DeflateEncoder.h
@@ -0,0 +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
diff --git a/CPP/7zip/Compress/DeflateRegister.cpp b/CPP/7zip/Compress/DeflateRegister.cpp
new file mode 100644
index 0000000..eaedb84
--- /dev/null
+++ b/CPP/7zip/Compress/DeflateRegister.cpp
@@ -0,0 +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")
+
+}}
diff --git a/CPP/7zip/Compress/DeltaFilter.cpp b/CPP/7zip/Compress/DeltaFilter.cpp
index cdbd33d..35b77ba 100644
--- a/CPP/7zip/Compress/DeltaFilter.cpp
+++ b/CPP/7zip/Compress/DeltaFilter.cpp
@@ -1,128 +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 EXTRACT_ONLY

-

-class CEncoder:

-  public ICompressFilter,

-  public ICompressSetCoderProperties,

-  public ICompressWriteCoderProperties,

-  CDelta,

-  public CMyUnknownImp

-{

-public:

-  MY_UNKNOWN_IMP3(ICompressFilter, ICompressSetCoderProperties, ICompressWriteCoderProperties)

-  INTERFACE_ICompressFilter(;)

-  STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);

-  STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStream);

-};

-

-STDMETHODIMP CEncoder::Init()

-{

-  DeltaInit();

-  return S_OK;

-}

-

-STDMETHODIMP_(UInt32) CEncoder::Filter(Byte *data, UInt32 size)

-{

-  Delta_Encode(_state, _delta, data, size);

-  return size;

-}

-

-STDMETHODIMP CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps)

-{

-  UInt32 delta = _delta;

-  for (UInt32 i = 0; i < numProps; i++)

-  {

-    const PROPVARIANT &prop = props[i];

-    PROPID propID = propIDs[i];

-    if (propID >= NCoderPropID::kReduceSize)

-      continue;

-    if (prop.vt != VT_UI4)

-      return E_INVALIDARG;

-    switch (propID)

-    {

-      case NCoderPropID::kDefaultProp:

-        delta = (UInt32)prop.ulVal;

-        if (delta < 1 || delta > 256)

-          return E_INVALIDARG;

-        break;

-      case NCoderPropID::kNumThreads: break;

-      case NCoderPropID::kLevel: break;

-      default: return E_INVALIDARG;

-    }

-  }

-  _delta = delta;

-  return S_OK;

-}

-

-STDMETHODIMP CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)

-{

-  Byte prop = (Byte)(_delta - 1);

-  return outStream->Write(&prop, 1, NULL);

-}

-

-#endif

-

-

-class CDecoder:

-  public ICompressFilter,

-  public ICompressSetDecoderProperties2,

-  CDelta,

-  public CMyUnknownImp

-{

-public:

-  MY_UNKNOWN_IMP2(ICompressFilter, ICompressSetDecoderProperties2)

-  INTERFACE_ICompressFilter(;)

-  STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);

-};

-

-STDMETHODIMP CDecoder::Init()

-{

-  DeltaInit();

-  return S_OK;

-}

-

-STDMETHODIMP_(UInt32) CDecoder::Filter(Byte *data, UInt32 size)

-{

-  Delta_Decode(_state, _delta, data, size);

-  return size;

-}

-

-STDMETHODIMP 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))
+{
+  UInt32 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:
+        delta = (UInt32)prop.ulVal;
+        if (delta < 1 || delta > 256)
+          return E_INVALIDARG;
+        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
new file mode 100644
index 0000000..a6ff690
--- /dev/null
+++ b/CPP/7zip/Compress/DllExports2Compress.cpp
@@ -0,0 +1,28 @@
+// 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*/)
+{
+  return TRUE;
+}
+
+STDAPI CreateCoder(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
new file mode 100644
index 0000000..24749d2
--- /dev/null
+++ b/CPP/7zip/Compress/DllExportsCompress.cpp
@@ -0,0 +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);
+}
diff --git a/CPP/7zip/Compress/HuffmanDecoder.h b/CPP/7zip/Compress/HuffmanDecoder.h
new file mode 100644
index 0000000..4b8169f
--- /dev/null
+++ b/CPP/7zip/Compress/HuffmanDecoder.h
@@ -0,0 +1,278 @@
+// Compress/HuffmanDecoder.h
+
+#ifndef ZIP7_INC_COMPRESS_HUFFMAN_DECODER_H
+#define ZIP7_INC_COMPRESS_HUFFMAN_DECODER_H
+
+#include "../../Common/MyTypes.h"
+
+namespace NCompress {
+namespace NHuffman {
+
+const unsigned kNumPairLenBits = 4;
+const unsigned kPairLenMask = (1 << kNumPairLenBits) - 1;
+
+template <unsigned kNumBitsMax, UInt32 m_NumSymbols, unsigned kNumTableBits = 9>
+class CDecoder
+{
+public:
+  UInt32 _limits[kNumBitsMax + 2];
+  UInt32 _poses[kNumBitsMax + 1];
+  UInt16 _lens[1 << kNumTableBits];
+  UInt16 _symbols[m_NumSymbols];
+
+  bool Build(const Byte *lens) throw()
+  {
+    UInt32 counts[kNumBitsMax + 1];
+    
+    unsigned i;
+    for (i = 0; i <= kNumBitsMax; i++)
+      counts[i] = 0;
+    
+    UInt32 sym;
+    
+    for (sym = 0; sym < m_NumSymbols; sym++)
+      counts[lens[sym]]++;
+    
+    const UInt32 kMaxValue = (UInt32)1 << kNumBitsMax;
+
+    _limits[0] = 0;
+    
+    UInt32 startPos = 0;
+    UInt32 sum = 0;
+    
+    for (i = 1; i <= kNumBitsMax; i++)
+    {
+      const UInt32 cnt = counts[i];
+      startPos += cnt << (kNumBitsMax - i);
+      if (startPos > kMaxValue)
+        return false;
+      _limits[i] = startPos;
+      counts[i] = sum;
+      _poses[i] = sum;
+      sum += cnt;
+    }
+
+    counts[0] = sum;
+    _poses[0] = sum;
+    _limits[kNumBitsMax + 1] = kMaxValue;
+    
+    for (sym = 0; sym < m_NumSymbols; sym++)
+    {
+      unsigned len = lens[sym];
+      if (len == 0)
+        continue;
+
+      unsigned offset = counts[len]++;
+      _symbols[offset] = (UInt16)sym;
+
+      if (len <= kNumTableBits)
+      {
+        offset -= _poses[len];
+        UInt32 num = (UInt32)1 << (kNumTableBits - len);
+        UInt16 val = (UInt16)((sym << kNumPairLenBits) | len);
+        UInt16 *dest = _lens + (_limits[(size_t)len - 1] >> (kNumBitsMax - kNumTableBits)) + (offset << (kNumTableBits - len));
+        for (UInt32 k = 0; k < num; k++)
+          dest[k] = val;
+      }
+    }
+    
+    return true;
+  }
+
+
+  bool BuildFull(const Byte *lens, UInt32 numSymbols = m_NumSymbols) throw()
+  {
+    UInt32 counts[kNumBitsMax + 1];
+    
+    unsigned i;
+    for (i = 0; i <= kNumBitsMax; i++)
+      counts[i] = 0;
+    
+    UInt32 sym;
+    
+    for (sym = 0; sym < numSymbols; sym++)
+      counts[lens[sym]]++;
+    
+    const UInt32 kMaxValue = (UInt32)1 << kNumBitsMax;
+
+    _limits[0] = 0;
+    
+    UInt32 startPos = 0;
+    UInt32 sum = 0;
+    
+    for (i = 1; i <= kNumBitsMax; i++)
+    {
+      const UInt32 cnt = counts[i];
+      startPos += cnt << (kNumBitsMax - i);
+      if (startPos > kMaxValue)
+        return false;
+      _limits[i] = startPos;
+      counts[i] = sum;
+      _poses[i] = sum;
+      sum += cnt;
+    }
+
+    counts[0] = sum;
+    _poses[0] = sum;
+    _limits[kNumBitsMax + 1] = kMaxValue;
+    
+    for (sym = 0; sym < numSymbols; sym++)
+    {
+      unsigned len = lens[sym];
+      if (len == 0)
+        continue;
+
+      unsigned offset = counts[len]++;
+      _symbols[offset] = (UInt16)sym;
+
+      if (len <= kNumTableBits)
+      {
+        offset -= _poses[len];
+        UInt32 num = (UInt32)1 << (kNumTableBits - len);
+        UInt16 val = (UInt16)((sym << kNumPairLenBits) | len);
+        UInt16 *dest = _lens + (_limits[(size_t)len - 1] >> (kNumBitsMax - kNumTableBits)) + (offset << (kNumTableBits - len));
+        for (UInt32 k = 0; k < num; k++)
+          dest[k] = val;
+      }
+    }
+    
+    return startPos == kMaxValue;
+  }
+
+  
+  template <class TBitDecoder>
+  Z7_FORCE_INLINE
+  UInt32 Decode(TBitDecoder *bitStream) const
+  {
+    UInt32 val = bitStream->GetValue(kNumBitsMax);
+    
+    if (val < _limits[kNumTableBits])
+    {
+      UInt32 pair = _lens[val >> (kNumBitsMax - kNumTableBits)];
+      bitStream->MovePos((unsigned)(pair & kPairLenMask));
+      return pair >> kNumPairLenBits;
+    }
+
+    unsigned numBits;
+    for (numBits = kNumTableBits + 1; val >= _limits[numBits]; numBits++);
+    
+    if (numBits > kNumBitsMax)
+      return 0xFFFFFFFF;
+
+    bitStream->MovePos(numBits);
+    UInt32 index = _poses[numBits] + ((val - _limits[(size_t)numBits - 1]) >> (kNumBitsMax - numBits));
+    return _symbols[index];
+  }
+
+  
+  template <class TBitDecoder>
+  Z7_FORCE_INLINE
+  UInt32 DecodeFull(TBitDecoder *bitStream) const
+  {
+    UInt32 val = bitStream->GetValue(kNumBitsMax);
+    
+    if (val < _limits[kNumTableBits])
+    {
+      UInt32 pair = _lens[val >> (kNumBitsMax - kNumTableBits)];
+      bitStream->MovePos((unsigned)(pair & kPairLenMask));
+      return pair >> kNumPairLenBits;
+    }
+
+    unsigned numBits;
+    for (numBits = kNumTableBits + 1; val >= _limits[numBits]; numBits++);
+    
+    bitStream->MovePos(numBits);
+    UInt32 index = _poses[numBits] + ((val - _limits[(size_t)numBits - 1]) >> (kNumBitsMax - numBits));
+    return _symbols[index];
+  }
+};
+
+
+
+template <UInt32 m_NumSymbols>
+class CDecoder7b
+{
+  Byte _lens[1 << 7];
+public:
+
+  bool Build(const Byte *lens) throw()
+  {
+    const unsigned kNumBitsMax = 7;
+    
+    UInt32 counts[kNumBitsMax + 1];
+    UInt32 _poses[kNumBitsMax + 1];
+    UInt32 _limits[kNumBitsMax + 1];
+      
+    unsigned i;
+    for (i = 0; i <= kNumBitsMax; i++)
+      counts[i] = 0;
+    
+    UInt32 sym;
+    
+    for (sym = 0; sym < m_NumSymbols; sym++)
+      counts[lens[sym]]++;
+    
+    const UInt32 kMaxValue = (UInt32)1 << kNumBitsMax;
+
+    _limits[0] = 0;
+    
+    UInt32 startPos = 0;
+    UInt32 sum = 0;
+    
+    for (i = 1; i <= kNumBitsMax; i++)
+    {
+      const UInt32 cnt = counts[i];
+      startPos += cnt << (kNumBitsMax - i);
+      if (startPos > kMaxValue)
+        return false;
+      _limits[i] = startPos;
+      counts[i] = sum;
+      _poses[i] = sum;
+      sum += cnt;
+    }
+
+    counts[0] = sum;
+    _poses[0] = sum;
+
+    for (sym = 0; sym < m_NumSymbols; sym++)
+    {
+      unsigned len = lens[sym];
+      if (len == 0)
+        continue;
+
+      unsigned offset = counts[len]++;
+
+      {
+        offset -= _poses[len];
+        UInt32 num = (UInt32)1 << (kNumBitsMax - len);
+        Byte val = (Byte)((sym << 3) | len);
+        Byte *dest = _lens + (_limits[(size_t)len - 1]) + (offset << (kNumBitsMax - len));
+        for (UInt32 k = 0; k < num; k++)
+          dest[k] = val;
+      }
+    }
+
+    {
+      UInt32 limit = _limits[kNumBitsMax];
+      UInt32 num = ((UInt32)1 << kNumBitsMax) - limit;
+      Byte *dest = _lens + limit;
+      for (UInt32 k = 0; k < num; k++)
+        dest[k] = (Byte)(0x1F << 3);
+    }
+    
+    return true;
+  }
+
+  template <class TBitDecoder>
+  UInt32 Decode(TBitDecoder *bitStream) const
+  {
+    UInt32 val = bitStream->GetValue(7);
+    UInt32 pair = _lens[val];
+    bitStream->MovePos((unsigned)(pair & 0x7));
+    return pair >> 3;
+  }
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Compress/ImplodeDecoder.cpp b/CPP/7zip/Compress/ImplodeDecoder.cpp
new file mode 100644
index 0000000..12f2dce
--- /dev/null
+++ b/CPP/7zip/Compress/ImplodeDecoder.cpp
@@ -0,0 +1,258 @@
+// 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;
+  
+  unsigned sym;
+  for (sym = 0; sym < numSymbols; sym++)
+    counts[lens[sym]]++;
+
+  const UInt32 kMaxValue = (UInt32)1 << kNumHuffmanBits;
+  
+  // _limits[0] = kMaxValue;
+
+  UInt32 startPos = kMaxValue;
+  UInt32 sum = 0;
+
+  for (i = 1; i <= kNumHuffmanBits; i++)
+  {
+    const UInt32 cnt = counts[i];
+    const UInt32 range = 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 (sym = 0; sym < numSymbols; sym++)
+  {
+    const unsigned len = lens[sym];
+    if (len != 0)
+      _symbols[--counts[len]] = (Byte)sym;
+  }
+
+  return true;
+}
+
+
+UInt32 CHuffmanDecoder::Decode(CInBit *inStream) const throw()
+{
+  const UInt32 val = inStream->GetValue(kNumHuffmanBits);
+  unsigned numBits;
+  for (numBits = 1; val < _limits[numBits]; numBits++);
+  const UInt32 sym = _symbols[_poses[numBits] + ((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 Byte level = (Byte)((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++] = 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 (progress && (pos - prevProgress) >= (1 << 18))
+    {
+      const UInt64 packSize = _inBitStream.GetProcessedSize();
+      RINOK(progress->SetRatioInfo(&packSize, &pos))
+      prevProgress = pos;
+    }
+
+    if (_inBitStream.ReadBits(1) != 0)
+    {
+      Byte b;
+      if (literalsOn)
+      {
+        const UInt32 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 = _distDecoder.Decode(&_inBitStream);
+      // if (dist >= kDistTableSize) break;
+      dist = (dist << numDistDirectBits) + lowDistBits;
+      UInt32 len = _lenDecoder.Decode(&_inBitStream);
+      // if (len >= kLenTableSize) break;
+      if (len == kLenTableSize - 1)
+        len += _inBitStream.ReadBits(kNumLenDirectBits);
+      len += minMatchLen;
+
+      {
+        const UInt64 limit = unPackSize - pos;
+        if (len > limit)
+        {
+          moreOut = true;
+          len = (UInt32)limit;
+        }
+      }
+
+      while (dist >= pos && len != 0)
+      {
+        _outWindowStream.PutByte(0);
+        pos++;
+        len--;
+      }
+      
+      if (len != 0)
+      {
+        _outWindowStream.CopyBlock(dist, len);
+        pos += 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
new file mode 100644
index 0000000..ec70045
--- /dev/null
+++ b/CPP/7zip/Compress/ImplodeDecoder.h
@@ -0,0 +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<CInBuffer> 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();
+  UInt32 Decode(CInBit *inStream) const throw();
+};
+
+
+Z7_CLASS_IMP_NOQIB_4(
+  CCoder
+  , ICompressCoder
+  , ICompressSetDecoderProperties2
+  , ICompressSetFinishMode
+  , ICompressGetInStreamProcessedSize
+)
+  CLzOutWindow _outWindowStream;
+  CInBit _inBitStream;
+  
+  CHuffmanDecoder _litDecoder;
+  CHuffmanDecoder _lenDecoder;
+  CHuffmanDecoder _distDecoder;
+
+  Byte _flags;
+  bool _fullStreamMode;
+
+  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
new file mode 100644
index 0000000..7d31bb9
--- /dev/null
+++ b/CPP/7zip/Compress/ImplodeHuffmanDecoder.cpp
@@ -0,0 +1,3 @@
+// ImplodeHuffmanDecoder.cpp
+
+#include "StdAfx.h"
diff --git a/CPP/7zip/Compress/ImplodeHuffmanDecoder.h b/CPP/7zip/Compress/ImplodeHuffmanDecoder.h
new file mode 100644
index 0000000..dcf8ac6
--- /dev/null
+++ b/CPP/7zip/Compress/ImplodeHuffmanDecoder.h
@@ -0,0 +1,6 @@
+// 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
new file mode 100644
index 0000000..aae02eb
--- /dev/null
+++ b/CPP/7zip/Compress/LzOutWindow.cpp
@@ -0,0 +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
+}
diff --git a/CPP/7zip/Compress/LzOutWindow.h b/CPP/7zip/Compress/LzOutWindow.h
new file mode 100644
index 0000000..599b124
--- /dev/null
+++ b/CPP/7zip/Compress/LzOutWindow.h
@@ -0,0 +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
diff --git a/CPP/7zip/Compress/LzfseDecoder.cpp b/CPP/7zip/Compress/LzfseDecoder.cpp
new file mode 100644
index 0000000..236d5bd
--- /dev/null
+++ b/CPP/7zip/Compress/LzfseDecoder.cpp
@@ -0,0 +1,942 @@
+// 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 <stdio.h>
+#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;
+    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 %7u %7u", 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 <LITERALS>
+      small L   - 1110LLLL <LITERALS>
+      
+      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 <LITERALS>
+        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 <LITERALS>
+          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 <LITERALS>
+          // small - LLMMMDDD DDDDDDDD <LITERALS>
+          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;
+  do
+  {
+    Byte b;
+    if (!m_InStream.ReadByte(b))
+      return S_FALSE;
+    packSize--;
+    if (b != 0)
+      return S_FALSE;
+  }
+  while (packSize != 0);
+
+  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) <  numStates * 2
+    //         0 <  j0     <= f
+    // (f + j0) = next_power_of_2 for f
+    unsigned k = CountZeroBits(f, NUM_LIT_STATES);
+    unsigned j0 = (((unsigned)NUM_LIT_STATES * 2) >> 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;
+  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 ((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
new file mode 100644
index 0000000..b7227dc
--- /dev/null
+++ b/CPP/7zip/Compress/LzfseDecoder.h
@@ -0,0 +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
diff --git a/CPP/7zip/Compress/LzhDecoder.cpp b/CPP/7zip/Compress/LzhDecoder.cpp
new file mode 100644
index 0000000..064bc55
--- /dev/null
+++ b/CPP/7zip/Compress/LzhDecoder.cpp
@@ -0,0 +1,252 @@
+// LzhDecoder.cpp
+
+#include "StdAfx.h"
+
+#include "LzhDecoder.h"
+
+namespace NCompress{
+namespace NLzh {
+namespace NDecoder {
+
+static const UInt32 kWindowSizeMin = 1 << 16;
+
+static bool CheckCodeLens(const Byte *lens, unsigned num)
+{
+  UInt32 sum = 0;
+  for (unsigned i = 0; i < num; i++)
+  {
+    const unsigned len = lens[i];
+    if (len != 0)
+      sum += ((UInt32)1 << (NUM_CODE_BITS - len));
+  }
+  return sum == ((UInt32)1 << NUM_CODE_BITS);
+}
+
+bool CCoder::ReadTP(unsigned num, unsigned numBits, int spec)
+{
+  _symbolT = -1;
+
+  const UInt32 n = _inBitStream.ReadBits(numBits);
+  if (n == 0)
+  {
+    const unsigned s = _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
+    {
+      const UInt32 val = _inBitStream.GetValue(16);
+      unsigned c = val >> 13;
+      
+      if (c == 7)
+      {
+        UInt32 mask = 1 << 12;
+        while (mask & val)
+        {
+          mask >>= 1;
+          c++;
+        }
+        if (c > 16)
+          return false;
+      }
+      
+      _inBitStream.MovePos(c < 7 ? 3 : c - 3);
+      lens[i++] = (Byte)c;
+      
+      if (i == (unsigned)spec)
+        i += _inBitStream.ReadBits(2);
+    }
+    while (i < n);
+    
+    if (!CheckCodeLens(lens, NPT))
+      return false;
+    return _decoderT.Build(lens);
+  }
+}
+
+static const unsigned NUM_C_BITS = 9;
+
+bool CCoder::ReadC()
+{
+  _symbolC = -1;
+
+  unsigned n = _inBitStream.ReadBits(NUM_C_BITS);
+  
+  if (n == 0)
+  {
+    const unsigned s = _inBitStream.ReadBits(NUM_C_BITS);
+    _symbolC = (int)s;
+    return (s < NC);
+  }
+
+  if (n > NC)
+    return false;
+
+  {
+    Byte lens[NC];
+
+    unsigned i = 0;
+  
+    do
+    {
+      UInt32 c = (unsigned)_symbolT;
+      if (_symbolT < 0)
+        c = _decoderT.Decode(&_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;
+    
+    if (!CheckCodeLens(lens, NC))
+      return false;
+    return _decoderC.Build(lens);
+  }
+}
+
+HRESULT CCoder::CodeReal(UInt64 rem, ICompressProgressInfo *progress)
+{
+  const unsigned pbit = (DictSize <= (1 << 14) ? 4 : 5);
+
+  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;
+      if (!ReadTP(NP, pbit, -1))
+        return S_FALSE;
+    }
+  
+    blockSize--;
+
+    UInt32 number = (unsigned)_symbolC;
+    if (_symbolC < 0)
+      number = _decoderC.Decode(&_inBitStream);
+
+    if (number < 256)
+    {
+      _outWindow.PutByte((Byte)number);
+      rem--;
+    }
+    else
+    {
+      UInt32 len = number - 256 + kMatchMinLen;
+
+      UInt32 dist = (unsigned)_symbolT;
+      if (_symbolT < 0)
+        dist = _decoderT.Decode(&_inBitStream);
+      
+      if (dist > 1)
+      {
+        dist--;
+        dist = ((UInt32)1 << dist) + _inBitStream.ReadBits((unsigned)dist);
+      }
+      
+      if (dist >= DictSize)
+        return S_FALSE;
+
+      if (len > rem)
+        len = (UInt32)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;
+}
+
+
+Z7_COM7F_IMF(CCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+    const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress))
+{
+  try
+  {
+    if (!outSize)
+      return E_INVALIDARG;
+    
+    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
new file mode 100644
index 0000000..491212e
--- /dev/null
+++ b/CPP/7zip/Compress/LzhDecoder.h
@@ -0,0 +1,69 @@
+// 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)
+
+Z7_CLASS_IMP_NOQIB_1(
+  CCoder
+  , ICompressCoder
+)
+  CLzOutWindow _outWindow;
+  NBitm::CDecoder<CInBuffer> _inBitStream;
+
+  int _symbolT;
+  int _symbolC;
+
+  NHuffman::CDecoder<NUM_CODE_BITS, NPT> _decoderT;
+  NHuffman::CDecoder<NUM_CODE_BITS, NC> _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(UInt64 outSize, ICompressProgressInfo *progress);
+public:
+  UInt32 DictSize;
+  bool FinishMode;
+
+  void SetDictSize(unsigned dictSize) { DictSize = dictSize; }
+  
+  CCoder(): DictSize(1 << 16), FinishMode(false) {}
+
+  UInt64 GetInputProcessedSize() const { return _inBitStream.GetProcessedSize(); }
+};
+
+}}}
+
+#endif
diff --git a/CPP/7zip/Compress/Lzma2Decoder.cpp b/CPP/7zip/Compress/Lzma2Decoder.cpp
index bb631c5..eab7800 100644
--- a/CPP/7zip/Compress/Lzma2Decoder.cpp
+++ b/CPP/7zip/Compress/Lzma2Decoder.cpp
@@ -1,265 +1,267 @@
-// Lzma2Decoder.cpp

-

-#include "StdAfx.h"

-

-// #include <stdio.h>

-

-#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 _7ZIP_ST

-    , _tryMt(1)

-    , _numThreads(1)

-    , _memUsage((UInt64)(sizeof(size_t)) << 28)

-    #endif

-{}

-

-CDecoder::~CDecoder()

-{

-  if (_dec)

-    Lzma2DecMt_Destroy(_dec);

-}

-

-STDMETHODIMP CDecoder::SetInBufSize(UInt32 , UInt32 size) { _inBufSize = size; return S_OK; }

-STDMETHODIMP CDecoder::SetOutBufSize(UInt32 , UInt32 size) { _outStep = size; return S_OK; }

-

-STDMETHODIMP 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;

-}

-

-

-STDMETHODIMP CDecoder::SetFinishMode(UInt32 finishMode)

-{

-  _finishMode = (finishMode != 0);

-  return S_OK;

-}

-

-

-

-#ifndef _7ZIP_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;

-

-STDMETHODIMP 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 _7ZIP_ST

-  {

-    props.numThreads = 1;

-    UInt32 numThreads = _numThreads;

-

-    if (_tryMt && numThreads >= 1)

-    {

-      UInt64 useLimit = _memUsage;

-      UInt32 dictSize = LZMA2_DIC_SIZE_FROM_PROP_FULL(_prop);

-      UInt64 expectedBlockSize64 = Get_ExpectedBlockSize_From_Dict(dictSize);

-      size_t expectedBlockSize = (size_t)expectedBlockSize64;

-      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);

-        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 _7ZIP_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 _7ZIP_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);

-}

-

-

-STDMETHODIMP CDecoder::GetInStreamProcessedSize(UInt64 *value)

-{

-  *value = _inProcessed;

-  return S_OK;

-}

-

-

-#ifndef _7ZIP_ST

-

-STDMETHODIMP CDecoder::SetNumberOfThreads(UInt32 numThreads)

-{

-  _numThreads = numThreads;

-  return S_OK;

-}

-

-STDMETHODIMP CDecoder::SetMemLimit(UInt64 memUsage)

-{

-  _memUsage = memUsage;

-  return S_OK;

-}

-

-#endif

-

-

-#ifndef NO_READ_FROM_CODER

-

-STDMETHODIMP 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);

-

-  SRes res = Lzma2DecMt_Init(_dec, _prop, &props, outSize, _finishMode, &_inWrap.vt);

-

-  if (res != SZ_OK)

-    return SResToHRESULT(res);

-  return S_OK;

-}

-

-

-STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream) { _inStream = inStream; return S_OK; }

-STDMETHODIMP CDecoder::ReleaseInStream() { _inStream.Release(); return S_OK; }

-  

-

-STDMETHODIMP CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)

-{

-  if (processedSize)

-    *processedSize = 0;

-

-  size_t size2 = size;

-  UInt64 inProcessed = 0;

-

-  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 <stdio.h>
+
+#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 b56488e..7ca717e 100644
--- a/CPP/7zip/Compress/Lzma2Decoder.h
+++ b/CPP/7zip/Compress/Lzma2Decoder.h
@@ -1,96 +1,87 @@
-// Lzma2Decoder.h

-

-#ifndef __LZMA2_DECODER_H

-#define __LZMA2_DECODER_H

-

-#include "../../../C/Lzma2DecMt.h"

-

-#include "../Common/CWrappers.h"

-

-namespace NCompress {

-namespace NLzma2 {

-

-class CDecoder:

-  public ICompressCoder,

-  public ICompressSetDecoderProperties2,

-  public ICompressSetFinishMode,

-  public ICompressGetInStreamProcessedSize,

-  public ICompressSetBufSize,

-

-  #ifndef NO_READ_FROM_CODER

-  public ICompressSetInStream,

-  public ICompressSetOutStreamSize,

-  public ISequentialInStream,

-  #endif

-

-  #ifndef _7ZIP_ST

-  public ICompressSetCoderMt,

-  public ICompressSetMemLimit,

-  #endif

-

-  public CMyUnknownImp

-{

-  CLzma2DecMtHandle _dec;

-  UInt64 _inProcessed;

-  Byte _prop;

-  int _finishMode;

-  UInt32 _inBufSize;

-  UInt32 _outStep;

-

-public:

-  MY_QUERYINTERFACE_BEGIN2(ICompressCoder)

-  MY_QUERYINTERFACE_ENTRY(ICompressSetDecoderProperties2)

-  MY_QUERYINTERFACE_ENTRY(ICompressSetFinishMode)

-  MY_QUERYINTERFACE_ENTRY(ICompressGetInStreamProcessedSize)

-  MY_QUERYINTERFACE_ENTRY(ICompressSetBufSize)

-  

-  #ifndef NO_READ_FROM_CODER

-  MY_QUERYINTERFACE_ENTRY(ICompressSetInStream)

-  MY_QUERYINTERFACE_ENTRY(ICompressSetOutStreamSize)

-  MY_QUERYINTERFACE_ENTRY(ISequentialInStream)

-  #endif

-  

-  #ifndef _7ZIP_ST

-  MY_QUERYINTERFACE_ENTRY(ICompressSetCoderMt)

-  MY_QUERYINTERFACE_ENTRY(ICompressSetMemLimit)

-  #endif

-  

-  MY_QUERYINTERFACE_END

-  MY_ADDREF_RELEASE

-

-  STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,

-      const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);

-  STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);

-  STDMETHOD(SetFinishMode)(UInt32 finishMode);

-  STDMETHOD(GetInStreamProcessedSize)(UInt64 *value);

-  STDMETHOD(SetInBufSize)(UInt32 streamIndex, UInt32 size);

-  STDMETHOD(SetOutBufSize)(UInt32 streamIndex, UInt32 size);

-

-  #ifndef _7ZIP_ST

-private:

-  int _tryMt;

-  UInt32 _numThreads;

-  UInt64 _memUsage;

-public:

-  STDMETHOD(SetNumberOfThreads)(UInt32 numThreads);

-  STDMETHOD(SetMemLimit)(UInt64 memUsage);

-  #endif

-

-  #ifndef NO_READ_FROM_CODER

-private:

-  CMyComPtr<ISequentialInStream> _inStream;

-  CSeqInStreamWrap _inWrap;

-public:

-  STDMETHOD(SetOutStreamSize)(const UInt64 *outSize);

-  STDMETHOD(SetInStream)(ISequentialInStream *inStream);

-  STDMETHOD(ReleaseInStream)();

-  STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);

-  #endif

-

-  CDecoder();

-  virtual ~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<ISequentialInStream> _inStream;
+  CSeqInStreamWrap _inWrap;
+ #endif
+
+public:
+  CDecoder();
+  ~CDecoder();
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Compress/Lzma2Encoder.cpp b/CPP/7zip/Compress/Lzma2Encoder.cpp
index 18f7d02..0dc7e23 100644
--- a/CPP/7zip/Compress/Lzma2Encoder.cpp
+++ b/CPP/7zip/Compress/Lzma2Encoder.cpp
@@ -1,122 +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)

-{

-  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;

-}

-

-

-STDMETHODIMP 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));

-}

-

-

-STDMETHODIMP CEncoder::SetCoderPropertiesOpt(const PROPID *propIDs,

-    const PROPVARIANT *coderProps, UInt32 numProps)

-{

-  for (UInt32 i = 0; i < numProps; i++)

-  {

-    const PROPVARIANT &prop = coderProps[i];

-    PROPID propID = propIDs[i];

-    if (propID == NCoderPropID::kExpectedDataSize)

-      if (prop.vt == VT_UI8)

-        Lzma2Enc_SetDataSize(_encoder, prop.uhVal.QuadPart);

-  }

-  return S_OK;

-}

-

-

-STDMETHODIMP CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)

-{

-  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;

-

-STDMETHODIMP 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 6539e73..18c29e1 100644
--- a/CPP/7zip/Compress/Lzma2Encoder.h
+++ b/CPP/7zip/Compress/Lzma2Encoder.h
@@ -1,42 +1,30 @@
-// Lzma2Encoder.h

-

-#ifndef __LZMA2_ENCODER_H

-#define __LZMA2_ENCODER_H

-

-#include "../../../C/Lzma2Enc.h"

-

-#include "../../Common/MyCom.h"

-

-#include "../ICoder.h"

-

-namespace NCompress {

-namespace NLzma2 {

-

-class CEncoder:

-  public ICompressCoder,

-  public ICompressSetCoderProperties,

-  public ICompressWriteCoderProperties,

-  public ICompressSetCoderPropertiesOpt,

-  public CMyUnknownImp

-{

-  CLzma2EncHandle _encoder;

-public:

-  MY_UNKNOWN_IMP4(

-      ICompressCoder,

-      ICompressSetCoderProperties,

-      ICompressWriteCoderProperties,

-      ICompressSetCoderPropertiesOpt)

- 

-  STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,

-      const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);

-  STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);

-  STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStream);

-  STDMETHOD(SetCoderPropertiesOpt)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);

-

-  CEncoder();

-  virtual ~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 4367105..fe53346 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 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 b6a8d3f..4f05b48 100644
--- a/CPP/7zip/Compress/LzmaDecoder.cpp
+++ b/CPP/7zip/Compress/LzmaDecoder.cpp
@@ -1,343 +1,349 @@
-// 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;

-  }

-  return E_FAIL;

-}

-

-namespace NCompress {

-namespace NLzma {

-

-CDecoder::CDecoder():

-    _inBuf(NULL),

-    _lzmaStatus(LZMA_STATUS_NOT_SPECIFIED),

-    FinishStream(false),

-    _propsWereSet(false),

-    _outSizeDefined(false),

-    _outStep(1 << 20),

-    _inBufSize(0),

-    _inBufSizeNew(1 << 20)

-{

-  _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);

-}

-

-STDMETHODIMP CDecoder::SetInBufSize(UInt32 , UInt32 size) { _inBufSizeNew = size; return S_OK; }

-STDMETHODIMP 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;

-}

-

-

-STDMETHODIMP 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);

-}

-

-

-STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)

-{

-  _inProcessed = 0;

-  _inPos = _inLim = 0;

-  SetOutStreamSizeResume(outSize);

-  return S_OK;

-}

-

-

-STDMETHODIMP CDecoder::SetFinishMode(UInt32 finishMode)

-{

-  FinishStream = (finishMode != 0);

-  return S_OK;

-}

-

-

-STDMETHODIMP 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;

-    

-    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)

-    bool outFinished = (_outSizeDefined && _outProcessed >= _outSize);

-

-    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)

-    {

-      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 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));

-    }

-  }

-}

-

-

-STDMETHODIMP 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 NO_READ_FROM_CODER

-

-STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream) { _inStream = inStream; return S_OK; }

-STDMETHODIMP CDecoder::ReleaseInStream() { _inStream.Release(); return S_OK; }

-

-

-STDMETHODIMP 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;

-    

-    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;
+  }
+  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 08b7c1b..095e76f 100644
--- a/CPP/7zip/Compress/LzmaDecoder.h
+++ b/CPP/7zip/Compress/LzmaDecoder.h
@@ -1,113 +1,113 @@
-// LzmaDecoder.h

-

-#ifndef __LZMA_DECODER_H

-#define __LZMA_DECODER_H

-

-// #include "../../../C/Alloc.h"

-#include "../../../C/LzmaDec.h"

-

-#include "../../Common/MyCom.h"

-#include "../ICoder.h"

-

-namespace NCompress {

-namespace NLzma {

-

-class CDecoder:

-  public ICompressCoder,

-  public ICompressSetDecoderProperties2,

-  public ICompressSetFinishMode,

-  public ICompressGetInStreamProcessedSize,

-  public ICompressSetBufSize,

-  #ifndef NO_READ_FROM_CODER

-  public ICompressSetInStream,

-  public ICompressSetOutStreamSize,

-  public ISequentialInStream,

-  #endif

-  public CMyUnknownImp

-{

-  Byte *_inBuf;

-  UInt32 _inPos;

-  UInt32 _inLim;

- 

-  ELzmaStatus _lzmaStatus;

-

-public:

-  bool FinishStream; // set it before decoding, if you need to decode full LZMA stream

-

-private:

-  bool _propsWereSet;

-  bool _outSizeDefined;

-  UInt64 _outSize;

-  UInt64 _inProcessed;

-  UInt64 _outProcessed;

-

-  UInt32 _outStep;

-  UInt32 _inBufSize;

-  UInt32 _inBufSizeNew;

-

-  // CAlignOffsetAlloc _alloc;

-

-  CLzmaDec _state;

-

-  HRESULT CreateInputBuffer();

-  HRESULT CodeSpec(ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress);

-  void SetOutStreamSizeResume(const UInt64 *outSize);

-

-public:

-  MY_QUERYINTERFACE_BEGIN2(ICompressCoder)

-  MY_QUERYINTERFACE_ENTRY(ICompressSetDecoderProperties2)

-  MY_QUERYINTERFACE_ENTRY(ICompressSetFinishMode)

-  MY_QUERYINTERFACE_ENTRY(ICompressGetInStreamProcessedSize)

-  MY_QUERYINTERFACE_ENTRY(ICompressSetBufSize)

-  #ifndef NO_READ_FROM_CODER

-  MY_QUERYINTERFACE_ENTRY(ICompressSetInStream)

-  MY_QUERYINTERFACE_ENTRY(ICompressSetOutStreamSize)

-  MY_QUERYINTERFACE_ENTRY(ISequentialInStream)

-  #endif

-  MY_QUERYINTERFACE_END

-  MY_ADDREF_RELEASE

-

-  STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,

-      const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);

-  STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);

-  STDMETHOD(SetFinishMode)(UInt32 finishMode);

-  STDMETHOD(GetInStreamProcessedSize)(UInt64 *value);

-  STDMETHOD(SetOutStreamSize)(const UInt64 *outSize);

-  STDMETHOD(SetInBufSize)(UInt32 streamIndex, UInt32 size);

-  STDMETHOD(SetOutBufSize)(UInt32 streamIndex, UInt32 size);

-

-  #ifndef NO_READ_FROM_CODER

-

-private:

-  CMyComPtr<ISequentialInStream> _inStream;

-public:

-  

-  STDMETHOD(SetInStream)(ISequentialInStream *inStream);

-  STDMETHOD(ReleaseInStream)();

-  STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);

-

-  HRESULT CodeResume(ISequentialOutStream *outStream, const UInt64 *outSize, ICompressProgressInfo *progress);

-  HRESULT ReadFromInputStream(void *data, UInt32 size, UInt32 *processedSize);

-  

-  #endif

-

-  UInt64 GetInputProcessedSize() const { return _inProcessed; }

-

-  CDecoder();

-  virtual ~CDecoder();

-

-  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<ISequentialInStream> _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 3151c3d..08e3ba5 100644
--- a/CPP/7zip/Compress/LzmaEncoder.cpp
+++ b/CPP/7zip/Compress/LzmaEncoder.cpp
@@ -1,182 +1,356 @@
-// LzmaEncoder.cpp

-

-#include "StdAfx.h"

-

-#include "../../../C/Alloc.h"

-

-#include "../Common/CWrappers.h"

-#include "../Common/StreamUtils.h"

-

-#include "LzmaEncoder.h"

-

-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 GetUpperChar(wchar_t c)

-{

-  if (c >= 'a' && c <= 'z')

-    c -= 0x20;

-  return c;

-}

-

-static int ParseMatchFinder(const wchar_t *s, int *btMode, int *numHashBytes)

-{

-  wchar_t c = GetUpperChar(*s++);

-  if (c == L'H')

-  {

-    if (GetUpperChar(*s++) != L'C')

-      return 0;

-    int numHashBytesLoc = (int)(*s++ - L'0');

-    if (numHashBytesLoc < 4 || numHashBytesLoc > 4)

-      return 0;

-    if (*s != 0)

-      return 0;

-    *btMode = 0;

-    *numHashBytes = numHashBytesLoc;

-    return 1;

-  }

-

-  if (c != L'B')

-    return 0;

-  if (GetUpperChar(*s++) != L'T')

-    return 0;

-  int numHashBytesLoc = (int)(*s++ - L'0');

-  if (numHashBytesLoc < 2 || numHashBytesLoc > 4)

-    return 0;

-  if (*s != 0)

-    return 0;

-  *btMode = 1;

-  *numHashBytes = numHashBytesLoc;

-  return 1;

-}

-

-#define SET_PROP_32(_id_, _dest_) case NCoderPropID::_id_: ep._dest_ = v; break;

-

-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::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 (prop.vt != VT_UI4)

-    return E_INVALIDARG;

-  UInt32 v = prop.ulVal;

-  switch (propID)

-  {

-    case NCoderPropID::kDefaultProp: if (v > 31) return E_INVALIDARG; ep.dictSize = (UInt32)1 << (unsigned)v; break;

-    SET_PROP_32(kLevel, level)

-    SET_PROP_32(kNumFastBytes, fb)

-    SET_PROP_32(kMatchFinderCycles, mc)

-    SET_PROP_32(kAlgorithm, algo)

-    SET_PROP_32(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;

-}

-

-STDMETHODIMP 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];

-    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));

-}

-

-

-STDMETHODIMP CEncoder::SetCoderPropertiesOpt(const PROPID *propIDs,

-    const PROPVARIANT *coderProps, UInt32 numProps)

-{

-  for (UInt32 i = 0; i < numProps; i++)

-  {

-    const PROPVARIANT &prop = coderProps[i];

-    PROPID propID = propIDs[i];

-    if (propID == NCoderPropID::kExpectedDataSize)

-      if (prop.vt == VT_UI8)

-        LzmaEnc_SetDataSize(_encoder, prop.uhVal.QuadPart);

-  }

-  return S_OK;

-}

-

-

-STDMETHODIMP CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)

-{

-  Byte props[LZMA_PROPS_SIZE];

-  size_t 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;

-

-STDMETHODIMP 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 = 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)

-  

-  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 <stdio.h>
+
+#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 7b31c66..2836d7d 100644
--- a/CPP/7zip/Compress/LzmaEncoder.h
+++ b/CPP/7zip/Compress/LzmaEncoder.h
@@ -1,46 +1,45 @@
-// LzmaEncoder.h

-

-#ifndef __LZMA_ENCODER_H

-#define __LZMA_ENCODER_H

-

-#include "../../../C/LzmaEnc.h"

-

-#include "../../Common/MyCom.h"

-

-#include "../ICoder.h"

-

-namespace NCompress {

-namespace NLzma {

-

-class CEncoder:

-  public ICompressCoder,

-  public ICompressSetCoderProperties,

-  public ICompressWriteCoderProperties,

-  public ICompressSetCoderPropertiesOpt,

-  public CMyUnknownImp

-{

-  CLzmaEncHandle _encoder;

-  UInt64 _inputProcessed;

-public:

-  MY_UNKNOWN_IMP4(

-      ICompressCoder,

-      ICompressSetCoderProperties,

-      ICompressWriteCoderProperties,

-      ICompressSetCoderPropertiesOpt)

-    

-  STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,

-      const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);

-  STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);

-  STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStream);

-  STDMETHOD(SetCoderPropertiesOpt)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);

-

-  CEncoder();

-  virtual ~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 4397595..887f7a2 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 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
new file mode 100644
index 0000000..38c0408
--- /dev/null
+++ b/CPP/7zip/Compress/LzmsDecoder.cpp
@@ -0,0 +1,576 @@
+// 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 {
+
+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 == 0x48)
+    {
+      if (p[1] == 0x8B)
+      {
+        if ((p[2] & 0xF7) != 0x5)
+          continue;
+        // MOV RAX / RCX, [RIP + disp32]
+      }
+      else if (p[1] == 0x8D) // LEA
+      {
+        if ((p[2] & 0x7) != 0x5)
+          continue;
+        // LEA R**, []
+      }
+      else
+        continue;
+      codeLen = 3;
+    }
+    else if (b == 0x4C)
+    {
+      if (p[1] != 0x8D || (p[2] & 0x7) != 0x5)
+        continue;
+      // LEA R*, []
+      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)
+      {
+        UInt32 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)
+        {
+          UInt32 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;
+            }
+          }
+        }
+
+        UInt32 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;
+
+        UInt32 power;
+        UInt32 distance32;
+        
+        if (_rc.Decode(&deltaRepStates[0], k_NumRepProbs, deltaRepProbs[0]) == 0)
+        {
+          HUFF_DEC(power, m_PowerDecoder)
+          LIMIT_CHECK
+
+          UInt32 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);
+        
+        UInt32 lenSlot;
+        HUFF_DEC(lenSlot, m_LenDecoder)
+        LIMIT_CHECK
+
+        UInt32 len = g_LenBases[lenSlot];
+        {
+          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
new file mode 100644
index 0000000..e173c97
--- /dev/null
+++ b/CPP/7zip/Compress/LzmsDecoder.h
@@ -0,0 +1,271 @@
+// LzmsDecoder.h
+// The code is based on LZMS description from wimlib code
+
+#ifndef ZIP7_INC_LZMS_DECODER_H
+#define ZIP7_INC_LZMS_DECODER_H
+
+// #define SHOW_DEBUG_INFO
+
+#ifdef SHOW_DEBUG_INFO
+#include <stdio.h>
+#define PRF(x) x
+#else
+// #define PRF(x)
+#endif
+
+#include "../../../C/CpuArch.h"
+#include "../../../C/HuffEnc.h"
+
+#include "../../Common/MyBuffer.h"
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+#include "HuffmanDecoder.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;
+  }
+
+  UInt32 GetValue(unsigned numBits) const
+  {
+    UInt32 v = ((UInt32)_buf[-1] << 16) | ((UInt32)_buf[-2] << 8) | (UInt32)_buf[-3];
+    v >>= (24 - numBits - _bitPos);
+    return v & ((1 << numBits) - 1);
+  }
+  
+  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;
+  }
+};
+
+
+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 <UInt32 m_NumSyms, UInt32 m_RebuildFreq, unsigned numTableBits>
+class CHuffDecoder: public NCompress::NHuffman::CDecoder<k_NumHuffmanBits, m_NumSyms, numTableBits>
+{
+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->BuildFull(levels, NumSyms);
+  }
+  
+  void Rebuild() throw()
+  {
+    Generate();
+    RebuildRem = m_RebuildFreq;
+    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);
+
+    UInt32 prob = entry->GetProb();
+
+    if (range <= 0xFFFF)
+    {
+      range <<= 16;
+      code <<= 16;
+      // if (cur >= end) throw 1;
+      code |= GetUi16(cur);
+      cur += 2;
+    }
+
+    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;
+  // CBitDecoder _bs;
+  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<k_NumLitSyms, 1024, 9> m_LitDecoder;
+  CHuffDecoder<k_NumPosSyms, 1024, 9> m_PosDecoder;
+  CHuffDecoder<k_NumLenSyms, 512, 8> m_LenDecoder;
+  CHuffDecoder<k_NumPowerSyms, 512, 6> m_PowerDecoder;
+  CHuffDecoder<k_NumPosSyms, 1024, 9> 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
new file mode 100644
index 0000000..2532088
--- /dev/null
+++ b/CPP/7zip/Compress/Lzx.h
@@ -0,0 +1,59 @@
+// 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;
+
+}}
+
+#endif
diff --git a/CPP/7zip/Compress/LzxDecoder.cpp b/CPP/7zip/Compress/LzxDecoder.cpp
new file mode 100644
index 0000000..b50d863
--- /dev/null
+++ b/CPP/7zip/Compress/LzxDecoder.cpp
@@ -0,0 +1,529 @@
+// LzxDecoder.cpp
+
+#include "StdAfx.h"
+
+#include <string.h>
+
+// #define SHOW_DEBUG_INFO
+
+#ifdef SHOW_DEBUG_INFO
+#include <stdio.h>
+#define PRF(x) x
+#else
+#define PRF(x)
+#endif
+
+#include "../../../C/Alloc.h"
+
+#include "LzxDecoder.h"
+
+namespace NCompress {
+namespace NLzx {
+
+static void x86_Filter(Byte *data, UInt32 size, UInt32 processedSize, UInt32 translationSize)
+{
+  const UInt32 kResidue = 10;
+  if (size <= kResidue)
+    return;
+  size -= kResidue;
+  
+  const Byte save = data[(size_t)size + 4];
+  data[(size_t)size + 4] = 0xE8;
+  
+  for (UInt32 i = 0;;)
+  {
+    Byte *p = data + i;
+    for (;;)
+    {
+      if (*p++ == 0xE8) break;
+      if (*p++ == 0xE8) break;
+      if (*p++ == 0xE8) break;
+      if (*p++ == 0xE8) break;
+    }
+
+    i = (UInt32)(p - data);
+
+    if (i > size)
+      break;
+    {
+      Int32 v = (Int32)GetUi32(p);
+      Int32 pos = (Int32)((Int32)1 - (Int32)(processedSize + i));
+      i += 4;
+      if (v >= pos && v < (Int32)translationSize)
+      {
+        v += (v >= 0 ? pos : (Int32)translationSize);
+        SetUi32(p, (UInt32)v)
+      }
+    }
+  }
+
+  data[(size_t)size + 4] = save;
+}
+
+
+CDecoder::CDecoder(bool wimMode):
+    _win(NULL),
+    _skipByte(false),
+    _unpackBlockSize(0),
+    KeepHistoryForNext(true),
+    NeedAlloc(true),
+    _keepHistory(false),
+    _wimMode(wimMode),
+    _numDictBits(15),
+    _x86_buf(NULL),
+    _x86_translationSize(0),
+    _unpackedData(NULL)
+{
+}
+
+CDecoder::~CDecoder()
+{
+  if (NeedAlloc)
+    ::MidFree(_win);
+  ::MidFree(_x86_buf);
+}
+
+HRESULT CDecoder::Flush()
+{
+  if (_x86_translationSize != 0)
+  {
+    Byte *destData = _win + _writePos;
+    const UInt32 curSize = _pos - _writePos;
+    if (KeepHistoryForNext)
+    {
+      if (!_x86_buf)
+      {
+        // we must change it to support another chunk sizes
+        const size_t kChunkSize = (size_t)1 << 15;
+        if (curSize > kChunkSize)
+          return E_NOTIMPL;
+        _x86_buf = (Byte *)::MidAlloc(kChunkSize);
+        if (!_x86_buf)
+          return E_OUTOFMEMORY;
+      }
+      memcpy(_x86_buf, destData, curSize);
+      _unpackedData = _x86_buf;
+      destData = _x86_buf;
+    }
+    x86_Filter(destData, (UInt32)curSize, _x86_processedSize, _x86_translationSize);
+    _x86_processedSize += (UInt32)curSize;
+    if (_x86_processedSize >= ((UInt32)1 << 30))
+      _x86_translationSize = 0;
+  }
+ 
+  return S_OK;
+}
+
+
+UInt32 CDecoder::ReadBits(unsigned numBits) { return _bitStream.ReadBitsSmall(numBits); }
+
+#define RIF(x) { if (!(x)) return false; }
+
+bool CDecoder::ReadTable(Byte *levels, unsigned numSymbols)
+{
+  {
+    Byte levels2[kLevelTableSize];
+    for (unsigned i = 0; i < kLevelTableSize; i++)
+      levels2[i] = (Byte)ReadBits(kNumLevelBits);
+    RIF(_levelDecoder.Build(levels2))
+  }
+  
+  unsigned i = 0;
+  do
+  {
+    UInt32 sym = _levelDecoder.Decode(&_bitStream);
+    if (sym <= kNumHuffmanBits)
+    {
+      int delta = (int)levels[i] - (int)sym;
+      delta += (delta < 0) ? (kNumHuffmanBits + 1) : 0;
+      levels[i++] = (Byte)delta;
+      continue;
+    }
+    
+    unsigned num;
+    Byte symbol;
+
+    if (sym < kLevelSym_Same)
+    {
+      sym -= kLevelSym_Zero1;
+      num = kLevelSym_Zero1_Start + ((unsigned)sym << kLevelSym_Zero1_NumBits) +
+          (unsigned)ReadBits(kLevelSym_Zero1_NumBits + sym);
+      symbol = 0;
+    }
+    else if (sym == kLevelSym_Same)
+    {
+      num = kLevelSym_Same_Start + (unsigned)ReadBits(kLevelSym_Same_NumBits);
+      sym = _levelDecoder.Decode(&_bitStream);
+      if (sym > kNumHuffmanBits)
+        return false;
+      int delta = (int)levels[i] - (int)sym;
+      delta += (delta < 0) ? (kNumHuffmanBits + 1) : 0;
+      symbol = (Byte)delta;
+    }
+    else
+      return false;
+
+    const unsigned limit = i + num;
+    if (limit > numSymbols)
+      return false;
+
+    do
+      levels[i++] = symbol;
+    while (i < limit);
+  }
+  while (i < numSymbols);
+
+  return true;
+}
+
+
+bool CDecoder::ReadTables(void)
+{
+  {
+    if (_skipByte)
+    {
+      if (_bitStream.DirectReadByte() != 0)
+        return false;
+    }
+
+    _bitStream.NormalizeBig();
+
+    const unsigned blockType = (unsigned)ReadBits(kBlockType_NumBits);
+    if (blockType > kBlockType_Uncompressed)
+      return false;
+    
+    _unpackBlockSize = (1 << 15);
+    if (!_wimMode || ReadBits(1) == 0)
+    {
+      _unpackBlockSize = ReadBits(16);
+      // wimlib supports chunks larger than 32KB (unsupported my MS wim).
+      if (!_wimMode || _numDictBits >= 16)
+      {
+        _unpackBlockSize <<= 8;
+        _unpackBlockSize |= ReadBits(8);
+      }
+    }
+
+    PRF(printf("\nBlockSize = %6d   %s  ", _unpackBlockSize, (_pos & 1) ? "@@@" : "   "));
+
+    _isUncompressedBlock = (blockType == kBlockType_Uncompressed);
+
+    _skipByte = false;
+
+    if (_isUncompressedBlock)
+    {
+      _skipByte = ((_unpackBlockSize & 1) != 0);
+
+      PRF(printf(" UncompressedBlock "));
+      if (_unpackBlockSize & 1)
+      {
+        PRF(printf(" ######### "));
+      }
+
+      if (!_bitStream.PrepareUncompressed())
+        return false;
+      if (_bitStream.GetRem() < kNumReps * 4)
+        return false;
+
+      for (unsigned i = 0; i < kNumReps; i++)
+      {
+        const UInt32 rep = _bitStream.ReadUInt32();
+        if (rep > _winSize)
+          return false;
+        _reps[i] = rep;
+      }
+      
+      return true;
+    }
+
+    _numAlignBits = 64;
+
+    if (blockType == kBlockType_Aligned)
+    {
+      Byte levels[kAlignTableSize];
+      _numAlignBits = kNumAlignBits;
+      for (unsigned i = 0; i < kAlignTableSize; i++)
+        levels[i] = (Byte)ReadBits(kNumAlignLevelBits);
+      RIF(_alignDecoder.Build(levels))
+    }
+  }
+
+  RIF(ReadTable(_mainLevels, 256))
+  RIF(ReadTable(_mainLevels + 256, _numPosLenSlots))
+  unsigned end = 256 + _numPosLenSlots;
+  memset(_mainLevels + end, 0, kMainTableSize - end);
+  RIF(_mainDecoder.Build(_mainLevels))
+  RIF(ReadTable(_lenLevels, kNumLenSymbols))
+  return _lenDecoder.Build(_lenLevels);
+}
+
+
+HRESULT CDecoder::CodeSpec(UInt32 curSize)
+{
+  if (!_keepHistory || !_isUncompressedBlock)
+    _bitStream.NormalizeBig();
+ 
+  if (!_keepHistory)
+  {
+    _skipByte = false;
+    _unpackBlockSize = 0;
+
+    memset(_mainLevels, 0, kMainTableSize);
+    memset(_lenLevels, 0, kNumLenSymbols);
+    
+    {
+      _x86_translationSize = 12000000;
+      if (!_wimMode)
+      {
+        _x86_translationSize = 0;
+        if (ReadBits(1) != 0)
+        {
+          UInt32 v = ReadBits(16) << 16;
+          v |= ReadBits(16);
+          _x86_translationSize = v;
+        }
+      }
+      
+      _x86_processedSize = 0;
+    }
+
+    _reps[0] = 1;
+    _reps[1] = 1;
+    _reps[2] = 1;
+  }
+
+  while (curSize > 0)
+  {
+    if (_bitStream.WasExtraReadError_Fast())
+      return S_FALSE;
+    
+    if (_unpackBlockSize == 0)
+    {
+      if (!ReadTables())
+        return S_FALSE;
+      continue;
+    }
+
+    UInt32 next = _unpackBlockSize;
+    if (next > curSize)
+      next = curSize;
+    
+    if (_isUncompressedBlock)
+    {
+      const size_t rem = _bitStream.GetRem();
+      if (rem == 0)
+        return S_FALSE;
+      if (next > rem)
+        next = (UInt32)rem;
+      _bitStream.CopyTo(_win + _pos, next);
+      _pos += next;
+      curSize -= next;
+      _unpackBlockSize -= next;
+
+      /* 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 (_skipByte
+          && _unpackBlockSize == 0
+          && curSize == 0
+          && _bitStream.IsOneDirectByteLeft())
+      {
+        _skipByte = false;
+        if (_bitStream.DirectReadByte() != 0)
+          return S_FALSE;
+      }
+      
+      continue;
+    }
+
+    curSize -= next;
+    _unpackBlockSize -= next;
+    
+    Byte *win = _win;
+
+    while (next > 0)
+    {
+      if (_bitStream.WasExtraReadError_Fast())
+        return S_FALSE;
+
+      UInt32 sym = _mainDecoder.Decode(&_bitStream);
+      
+      if (sym < 256)
+      {
+        win[_pos++] = (Byte)sym;
+        next--;
+        continue;
+      }
+      {
+        sym -= 256;
+        if (sym >= _numPosLenSlots)
+          return S_FALSE;
+        const UInt32 posSlot = sym / kNumLenSlots;
+        const UInt32 lenSlot = sym % kNumLenSlots;
+        UInt32 len = kMatchMinLen + lenSlot;
+        
+        if (lenSlot == kNumLenSlots - 1)
+        {
+          UInt32 lenTemp = _lenDecoder.Decode(&_bitStream);
+          if (lenTemp >= kNumLenSymbols)
+            return S_FALSE;
+          len = kMatchMinLen + kNumLenSlots - 1 + lenTemp;
+        }
+        
+        UInt32 dist;
+        
+        if (posSlot < kNumReps)
+        {
+          dist = _reps[posSlot];
+          _reps[posSlot] = _reps[0];
+          _reps[0] = dist;
+        }
+        else
+        {
+          unsigned numDirectBits;
+          
+          if (posSlot < kNumPowerPosSlots)
+          {
+            numDirectBits = (unsigned)(posSlot >> 1) - 1;
+            dist = ((2 | (posSlot & 1)) << numDirectBits);
+          }
+          else
+          {
+            numDirectBits = kNumLinearPosSlotBits;
+            dist = ((posSlot - 0x22) << kNumLinearPosSlotBits);
+          }
+
+          if (numDirectBits >= _numAlignBits)
+          {
+            dist += (_bitStream.ReadBitsSmall(numDirectBits - kNumAlignBits) << kNumAlignBits);
+            const UInt32 alignTemp = _alignDecoder.Decode(&_bitStream);
+            if (alignTemp >= kAlignTableSize)
+              return S_FALSE;
+            dist += alignTemp;
+          }
+          else
+            dist += _bitStream.ReadBitsBig(numDirectBits);
+          
+          dist -= kNumReps - 1;
+          _reps[2] = _reps[1];
+          _reps[1] = _reps[0];
+          _reps[0] = dist;
+        }
+
+        if (len > next)
+          return S_FALSE;
+
+        if (dist > _pos && !_overDict)
+          return S_FALSE;
+
+        Byte *dest = win + _pos;
+        const UInt32 mask = (_winSize - 1);
+        UInt32 srcPos = (_pos - dist) & mask;
+
+        next -= len;
+        
+        if (len > _winSize - srcPos)
+        {
+          _pos += len;
+          do
+          {
+            *dest++ = win[srcPos++];
+            srcPos &= mask;
+          }
+          while (--len);
+        }
+        else
+        {
+          const ptrdiff_t src = (ptrdiff_t)srcPos - (ptrdiff_t)_pos;
+          _pos += len;
+          const Byte *lim = dest + len;
+          *(dest) = *(dest + src);
+          dest++;
+          do
+            *(dest) = *(dest + src);
+          while (++dest != lim);
+        }
+      }
+    }
+  }
+
+  if (!_bitStream.WasFinishedOK())
+    return S_FALSE;
+
+  return S_OK;
+}
+
+
+HRESULT CDecoder::Code(const Byte *inData, size_t inSize, UInt32 outSize)
+{
+  if (!_keepHistory)
+  {
+    _pos = 0;
+    _overDict = false;
+  }
+  else if (_pos == _winSize)
+  {
+    _pos = 0;
+    _overDict = true;
+  }
+
+  _writePos = _pos;
+  _unpackedData = _win + _pos;
+  
+  if (outSize > _winSize - _pos)
+    return S_FALSE;
+
+  PRF(printf("\ninSize = %d", inSize));
+  if ((inSize & 1) != 0)
+  {
+    PRF(printf(" ---------"));
+  }
+
+  if (inSize < 1)
+    return S_FALSE;
+
+  _bitStream.Init(inData, inSize);
+
+  const HRESULT res = CodeSpec(outSize);
+  const HRESULT res2 = Flush();
+  return (res == S_OK ? res2 : res);
+}
+
+
+HRESULT CDecoder::SetParams2(unsigned numDictBits)
+{
+  _numDictBits = numDictBits;
+  if (numDictBits < kNumDictBits_Min || numDictBits > kNumDictBits_Max)
+    return E_INVALIDARG;
+  const unsigned numPosSlots = (numDictBits < 20) ?
+      numDictBits * 2 :
+      34 + ((unsigned)1 << (numDictBits - 17));
+  _numPosLenSlots = numPosSlots * kNumLenSlots;
+  return S_OK;
+}
+  
+
+HRESULT CDecoder::SetParams_and_Alloc(unsigned numDictBits)
+{
+  RINOK(SetParams2(numDictBits))
+  
+  const UInt32 newWinSize = (UInt32)1 << numDictBits;
+ 
+  if (NeedAlloc)
+  {
+    if (!_win || newWinSize != _winSize)
+    {
+      ::MidFree(_win);
+      _winSize = 0;
+      _win = (Byte *)::MidAlloc(newWinSize);
+      if (!_win)
+        return E_OUTOFMEMORY;
+    }
+  }
+
+  _winSize = (UInt32)newWinSize;
+  return S_OK;
+}
+
+}}
diff --git a/CPP/7zip/Compress/LzxDecoder.h b/CPP/7zip/Compress/LzxDecoder.h
new file mode 100644
index 0000000..ab114e5
--- /dev/null
+++ b/CPP/7zip/Compress/LzxDecoder.h
@@ -0,0 +1,243 @@
+// LzxDecoder.h
+
+#ifndef ZIP7_INC_LZX_DECODER_H
+#define ZIP7_INC_LZX_DECODER_H
+
+#include "../../../C/CpuArch.h"
+
+#include "../../Common/MyCom.h"
+
+#include "HuffmanDecoder.h"
+#include "Lzx.h"
+
+namespace NCompress {
+namespace NLzx {
+
+class CBitDecoder
+{
+  unsigned _bitPos;
+  UInt32 _value;
+  const Byte *_buf;
+  const Byte *_bufLim;
+  UInt32 _extraSize;
+public:
+
+  void Init(const Byte *data, size_t size)
+  {
+    _buf = data;
+    _bufLim = data + size - 1;
+    _bitPos = 0;
+    _extraSize = 0;
+  }
+
+  size_t GetRem() const { return (size_t)(_bufLim + 1 - _buf); }
+  bool WasExtraReadError_Fast() const { return _extraSize > 4; }
+
+  bool WasFinishedOK() const
+  {
+    if (_buf != _bufLim + 1)
+      return false;
+    if ((_bitPos >> 4) * 2 != _extraSize)
+      return false;
+    unsigned numBits = _bitPos & 15;
+    return (((_value >> (_bitPos - numBits)) & (((UInt32)1 << numBits) - 1)) == 0);
+  }
+  
+  void NormalizeSmall()
+  {
+    if (_bitPos <= 16)
+    {
+      UInt32 val;
+      if (_buf >= _bufLim)
+      {
+        val = 0xFFFF;
+        _extraSize += 2;
+      }
+      else
+      {
+        val = GetUi16(_buf);
+        _buf += 2;
+      }
+      _value = (_value << 16) | val;
+      _bitPos += 16;
+    }
+  }
+
+  void NormalizeBig()
+  {
+    if (_bitPos <= 16)
+    {
+      {
+        UInt32 val;
+        if (_buf >= _bufLim)
+        {
+          val = 0xFFFF;
+          _extraSize += 2;
+        }
+        else
+        {
+          val = GetUi16(_buf);
+          _buf += 2;
+        }
+        _value = (_value << 16) | val;
+        _bitPos += 16;
+      }
+      if (_bitPos <= 16)
+      {
+        UInt32 val;
+        if (_buf >= _bufLim)
+        {
+          val = 0xFFFF;
+          _extraSize += 2;
+        }
+        else
+        {
+          val = GetUi16(_buf);
+          _buf += 2;
+        }
+        _value = (_value << 16) | val;
+        _bitPos += 16;
+      }
+    }
+  }
+
+  UInt32 GetValue(unsigned numBits) const
+  {
+    return (_value >> (_bitPos - numBits)) & (((UInt32)1 << numBits) - 1);
+  }
+  
+  void MovePos(unsigned numBits)
+  {
+    _bitPos -= numBits;
+    NormalizeSmall();
+  }
+
+  UInt32 ReadBitsSmall(unsigned numBits)
+  {
+    _bitPos -= numBits;
+    UInt32 val = (_value >> _bitPos) & (((UInt32)1 << numBits) - 1);
+    NormalizeSmall();
+    return val;
+  }
+
+  UInt32 ReadBitsBig(unsigned numBits)
+  {
+    _bitPos -= numBits;
+    UInt32 val = (_value >> _bitPos) & (((UInt32)1 << numBits) - 1);
+    NormalizeBig();
+    return val;
+  }
+
+  bool PrepareUncompressed()
+  {
+    if (_extraSize != 0)
+      return false;
+    unsigned numBits = _bitPos - 16;
+    if (((_value >> 16) & (((UInt32)1 << numBits) - 1)) != 0)
+      return false;
+    _buf -= 2;
+    _bitPos = 0;
+    return true;
+  }
+
+  UInt32 ReadUInt32()
+  {
+    UInt32 v = GetUi32(_buf);
+    _buf += 4;
+    return v;
+  }
+
+  void CopyTo(Byte *dest, size_t size)
+  {
+    memcpy(dest, _buf, size);
+    _buf += size;
+  }
+
+  bool IsOneDirectByteLeft() const { return _buf == _bufLim && _extraSize == 0; }
+
+  Byte DirectReadByte()
+  {
+    if (_buf > _bufLim)
+    {
+      _extraSize++;
+      return 0xFF;
+    }
+    return *_buf++;
+  }
+};
+
+
+Z7_CLASS_IMP_COM_0(
+  CDecoder
+)
+  CBitDecoder _bitStream;
+  Byte *_win;
+  UInt32 _pos;
+  UInt32 _winSize;
+
+  bool _overDict;
+  bool _isUncompressedBlock;
+  bool _skipByte;
+  unsigned _numAlignBits;
+
+  UInt32 _reps[kNumReps];
+  UInt32 _numPosLenSlots;
+  UInt32 _unpackBlockSize;
+
+public:
+  bool KeepHistoryForNext;
+  bool NeedAlloc;
+private:
+  bool _keepHistory;
+  bool _wimMode;
+  unsigned _numDictBits;
+  UInt32 _writePos;
+
+  Byte *_x86_buf;
+  UInt32 _x86_translationSize;
+  UInt32 _x86_processedSize;
+
+  Byte *_unpackedData;
+  
+  NHuffman::CDecoder<kNumHuffmanBits, kMainTableSize> _mainDecoder;
+  NHuffman::CDecoder<kNumHuffmanBits, kNumLenSymbols> _lenDecoder;
+  NHuffman::CDecoder7b<kAlignTableSize> _alignDecoder;
+  NHuffman::CDecoder<kNumHuffmanBits, kLevelTableSize, 7> _levelDecoder;
+
+  Byte _mainLevels[kMainTableSize];
+  Byte _lenLevels[kNumLenSymbols];
+
+  HRESULT Flush();
+
+  UInt32 ReadBits(unsigned numBits);
+  bool ReadTable(Byte *levels, unsigned numSymbols);
+  bool ReadTables();
+
+  HRESULT CodeSpec(UInt32 size);
+  HRESULT SetParams2(unsigned numDictBits);
+public:
+  CDecoder(bool wimMode = false);
+  ~CDecoder();
+
+  HRESULT SetExternalWindow(Byte *win, unsigned numDictBits)
+  {
+    NeedAlloc = false;
+    _win = win;
+    _winSize = (UInt32)1 << numDictBits;
+    return SetParams2(numDictBits);
+  }
+
+  void SetKeepHistory(bool keepHistory) { _keepHistory = keepHistory; }
+
+  HRESULT SetParams_and_Alloc(unsigned numDictBits);
+
+  HRESULT Code(const Byte *inData, size_t inSize, UInt32 outSize);
+  
+  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
new file mode 100644
index 0000000..1b44d00
--- /dev/null
+++ b/CPP/7zip/Compress/Mtf8.h
@@ -0,0 +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
diff --git a/CPP/7zip/Compress/PpmdDecoder.cpp b/CPP/7zip/Compress/PpmdDecoder.cpp
index 4820c0a..1238df6 100644
--- a/CPP/7zip/Compress/PpmdDecoder.cpp
+++ b/CPP/7zip/Compress/PpmdDecoder.cpp
@@ -1,170 +1,218 @@
-// PpmdDecoder.cpp

-// 2009-03-11 : Igor Pavlov : Public domain

-

-#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 << 20);

-

-enum

-{

-  kStatus_NeedInit,

-  kStatus_Normal,

-  kStatus_Finished,

-  kStatus_Error

-};

-

-CDecoder::~CDecoder()

-{

-  ::MidFree(_outBuf);

-  Ppmd7_Free(&_ppmd, &g_BigAlloc);

-}

-

-STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *props, UInt32 size)

-{

-  if (size < 5)

-    return E_INVALIDARG;

-  _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 E_NOTIMPL;

-  if (!_inStream.Alloc(1 << 20))

-    return E_OUTOFMEMORY;

-  if (!Ppmd7_Alloc(&_ppmd, memSize, &g_BigAlloc))

-    return E_OUTOFMEMORY;

-  return S_OK;

-}

-

-HRESULT CDecoder::CodeSpec(Byte *memStream, UInt32 size)

-{

-  switch (_status)

-  {

-    case kStatus_Finished: return S_OK;

-    case kStatus_Error: return S_FALSE;

-    case kStatus_NeedInit:

-      _inStream.Init();

-      if (!Ppmd7z_RangeDec_Init(&_rangeDec))

-      {

-        _status = kStatus_Error;

-        return S_FALSE;

-      }

-      _status = kStatus_Normal;

-      Ppmd7_Init(&_ppmd, _order);

-      break;

-  }

-  if (_outSizeDefined)

-  {

-    const UInt64 rem = _outSize - _processedSize;

-    if (size > rem)

-      size = (UInt32)rem;

-  }

-

-  UInt32 i;

-  int sym = 0;

-  for (i = 0; i != size; i++)

-  {

-    sym = Ppmd7_DecodeSymbol(&_ppmd, &_rangeDec.vt);

-    if (_inStream.Extra || sym < 0)

-      break;

-    memStream[i] = (Byte)sym;

-  }

-

-  _processedSize += i;

-  if (_inStream.Extra)

-  {

-    _status = kStatus_Error;

-    return _inStream.Res;

-  }

-  if (sym < 0)

-    _status = (sym < -1) ? kStatus_Error : kStatus_Finished;

-  return S_OK;

-}

-

-STDMETHODIMP 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;

-    HRESULT res = CodeSpec(_outBuf, kBufSize);

-    size_t processed = (size_t)(_processedSize - startPos);

-    RINOK(WriteStream(outStream, _outBuf, processed));

-    RINOK(res);

-    if (_status == kStatus_Finished)

-      break;

-    if (progress)

-    {

-      UInt64 inSize = _inStream.GetProcessed();

-      RINOK(progress->SetRatioInfo(&inSize, &_processedSize));

-    }

-  }

-  while (!_outSizeDefined || _processedSize < _outSize);

-  return S_OK;

-}

-

-STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)

-{

-  _outSizeDefined = (outSize != NULL);

-  if (_outSizeDefined)

-    _outSize = *outSize;

-  _processedSize = 0;

-  _status = kStatus_NeedInit;

-  return S_OK;

-}

-

-

-STDMETHODIMP CDecoder::GetInStreamProcessedSize(UInt64 *value)

-{

-  *value = _inStream.GetProcessed();

-  return S_OK;

-}

-

-#ifndef NO_READ_FROM_CODER

-

-STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream)

-{

-  InSeqStream = inStream;

-  _inStream.Stream = inStream;

-  return S_OK;

-}

-

-STDMETHODIMP CDecoder::ReleaseInStream()

-{

-  InSeqStream.Release();

-  return S_OK;

-}

-

-STDMETHODIMP CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)

-{

-  const UInt64 startPos = _processedSize;

-  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;
+  }
+  
+  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 3c2f493..22e5bd4 100644
--- a/CPP/7zip/Compress/PpmdDecoder.h
+++ b/CPP/7zip/Compress/PpmdDecoder.h
@@ -1,86 +1,87 @@
-// PpmdDecoder.h

-// 2009-03-11 : Igor Pavlov : Public domain

-

-#ifndef __COMPRESS_PPMD_DECODER_H

-#define __COMPRESS_PPMD_DECODER_H

-

-#include "../../../C/Ppmd7.h"

-

-#include "../../Common/MyCom.h"

-

-#include "../Common/CWrappers.h"

-

-#include "../ICoder.h"

-

-namespace NCompress {

-namespace NPpmd {

-

-class CDecoder :

-  public ICompressCoder,

-  public ICompressSetDecoderProperties2,

-  public ICompressGetInStreamProcessedSize,

-  #ifndef NO_READ_FROM_CODER

-  public ICompressSetInStream,

-  public ICompressSetOutStreamSize,

-  public ISequentialInStream,

-  #endif

-  public CMyUnknownImp

-{

-  Byte *_outBuf;

-  CPpmd7z_RangeDec _rangeDec;

-  CByteInBufWrap _inStream;

-  CPpmd7 _ppmd;

-

-  Byte _order;

-  bool _outSizeDefined;

-  int _status;

-  UInt64 _outSize;

-  UInt64 _processedSize;

-

-  HRESULT CodeSpec(Byte *memStream, UInt32 size);

-

-public:

-

-  #ifndef NO_READ_FROM_CODER

-  CMyComPtr<ISequentialInStream> InSeqStream;

-  #endif

-

-  MY_QUERYINTERFACE_BEGIN2(ICompressCoder)

-  MY_QUERYINTERFACE_ENTRY(ICompressSetDecoderProperties2)

-  // MY_QUERYINTERFACE_ENTRY(ICompressSetFinishMode)

-  MY_QUERYINTERFACE_ENTRY(ICompressGetInStreamProcessedSize)

-  #ifndef NO_READ_FROM_CODER

-  MY_QUERYINTERFACE_ENTRY(ICompressSetInStream)

-  MY_QUERYINTERFACE_ENTRY(ICompressSetOutStreamSize)

-  MY_QUERYINTERFACE_ENTRY(ISequentialInStream)

-  #endif

-  MY_QUERYINTERFACE_END

-  MY_ADDREF_RELEASE

-

-

-  STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,

-      const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);

-  STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);

-  STDMETHOD(GetInStreamProcessedSize)(UInt64 *value);

-  

-  STDMETHOD(SetOutStreamSize)(const UInt64 *outSize);

-

-  #ifndef NO_READ_FROM_CODER

-  STDMETHOD(SetInStream)(ISequentialInStream *inStream);

-  STDMETHOD(ReleaseInStream)();

-  STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);

-  #endif

-

-  CDecoder(): _outBuf(NULL), _outSizeDefined(false)

-  {

-    Ppmd7z_RangeDec_CreateVTable(&_rangeDec);

-    _rangeDec.Stream = &_inStream.vt;

-    Ppmd7_Construct(&_ppmd);

-  }

-

-  ~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<ISequentialInStream> 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 0aef701..2dfca6d 100644
--- a/CPP/7zip/Compress/PpmdEncoder.cpp
+++ b/CPP/7zip/Compress/PpmdEncoder.cpp
@@ -1,152 +1,193 @@
-// PpmdEncoder.cpp

-

-#include "StdAfx.h"

-

-#include "../../../C/Alloc.h"

-#include "../../../C/CpuArch.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 = level >= 9 ? ((UInt32)192 << 20) : ((UInt32)1 << (level + 19));

-  const unsigned kMult = 16;

-  if (MemSize / kMult > ReduceSize)

-  {

-    for (unsigned i = 16; i <= 31; 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);

-  _rangeEnc.Stream = &_outStream.vt;

-  Ppmd7_Construct(&_ppmd);

-}

-

-CEncoder::~CEncoder()

-{

-  ::MidFree(_inBuf);

-  Ppmd7_Free(&_ppmd, &g_BigAlloc);

-}

-

-STDMETHODIMP 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::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 (prop.vt != VT_UI4)

-      return E_INVALIDARG;

-    UInt32 v = (UInt32)prop.ulVal;

-    switch (propID)

-    {

-      case NCoderPropID::kUsedMemorySize:

-        if (v < (1 << 16) || v > PPMD7_MAX_MEM_SIZE || (v & 3) != 0)

-          return E_INVALIDARG;

-        props.MemSize = v;

-        break;

-      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;

-}

-

-STDMETHODIMP 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);

-}

-

-HRESULT 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_RangeEnc_Init(&_rangeEnc);

-  Ppmd7_Init(&_ppmd, _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.

-      // Ppmd7_EncodeSymbol(&_ppmd, &_rangeEnc, -1);

-      Ppmd7z_RangeEnc_FlushData(&_rangeEnc);

-      return _outStream.Flush();

-    }

-    for (UInt32 i = 0; i < size; i++)

-    {

-      Ppmd7_EncodeSymbol(&_ppmd, &_rangeEnc, _inBuf[i]);

-      RINOK(_outStream.Res);

-    }

-    processed += size;

-    if (progress)

-    {

-      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 cdb0352..057cccb 100644
--- a/CPP/7zip/Compress/PpmdEncoder.h
+++ b/CPP/7zip/Compress/PpmdEncoder.h
@@ -1,58 +1,49 @@
-// PpmdEncoder.h

-

-#ifndef __COMPRESS_PPMD_ENCODER_H

-#define __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);

-};

-

-class CEncoder :

-  public ICompressCoder,

-  public ICompressSetCoderProperties,

-  public ICompressWriteCoderProperties,

-  public CMyUnknownImp

-{

-  Byte *_inBuf;

-  CByteOutBufWrap _outStream;

-  CPpmd7z_RangeEnc _rangeEnc;

-  CPpmd7 _ppmd;

-  CEncProps _props;

-public:

-  MY_UNKNOWN_IMP3(

-      ICompressCoder,

-      ICompressSetCoderProperties,

-      ICompressWriteCoderProperties)

-  STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,

-      const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);

-  STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);

-  STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStream);

-  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 c748696..fb5619c 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 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
new file mode 100644
index 0000000..5039131
--- /dev/null
+++ b/CPP/7zip/Compress/PpmdZip.cpp
@@ -0,0 +1,300 @@
+// PpmdZip.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "../Common/RegisterCodec.h"
+#include "../Common/StreamUtils.h"
+
+#include "PpmdZip.h"
+
+namespace NCompress {
+namespace NPpmdZip {
+
+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 UInt32 val = (UInt32)(((unsigned)_props.Order - 1) + ((_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
new file mode 100644
index 0000000..a23d008
--- /dev/null
+++ b/CPP/7zip/Compress/PpmdZip.h
@@ -0,0 +1,85 @@
+// 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 {
+
+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);
+  }
+};
+
+
+Z7_CLASS_IMP_NOQIB_3(
+  CDecoder
+  , ICompressCoder
+  , ICompressSetFinishMode
+  , ICompressGetInStreamProcessedSize
+)
+  CByteInBufWrap _inStream;
+  CBuf _outStream;
+  CPpmd8 _ppmd;
+  bool _fullFileMode;
+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
new file mode 100644
index 0000000..16ef0fc
--- /dev/null
+++ b/CPP/7zip/Compress/QuantumDecoder.cpp
@@ -0,0 +1,195 @@
+// QuantumDecoder.cpp
+
+#include "StdAfx.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 kNumSimplePosSlots = 4;
+static const unsigned kNumSimpleLenSlots = 6;
+
+static const UInt16 kUpdateStep = 8;
+static const UInt16 kFreqSumMax = 3800;
+static const unsigned kReorderCountStart = 4;
+static const unsigned kReorderCount = 50;
+
+void CModelDecoder::Init(unsigned numItems)
+{
+  NumItems = numItems;
+  ReorderCount = kReorderCountStart;
+  for (unsigned i = 0; i < numItems; i++)
+  {
+    Freqs[i] = (UInt16)(numItems - i);
+    Vals[i] = (Byte)i;
+  }
+  Freqs[numItems] = 0;
+}
+
+unsigned CModelDecoder::Decode(CRangeDecoder *rc)
+{
+  const UInt32 threshold = rc->GetThreshold(Freqs[0]);
+  unsigned i;
+  for (i = 1; Freqs[i] > threshold; i++);
+  
+  rc->Decode(Freqs[i], Freqs[(size_t)i - 1], Freqs[0]);
+  const unsigned res = Vals[--i];
+  
+  do
+    Freqs[i] = (UInt16)(Freqs[i] + kUpdateStep);
+  while (i--);
+  
+  if (Freqs[0] > kFreqSumMax)
+  {
+    if (--ReorderCount == 0)
+    {
+      ReorderCount = kReorderCount;
+      for (i = 0; i < NumItems; i++)
+        Freqs[i] = (UInt16)(((Freqs[i] - Freqs[(size_t)i + 1]) + 1) >> 1);
+      for (i = 0; i < NumItems - 1; i++)
+        for (unsigned j = i + 1; j < NumItems; j++)
+          if (Freqs[i] < Freqs[j])
+          {
+            const UInt16 tmpFreq = Freqs[i];
+            const Byte tmpVal = Vals[i];
+            Freqs[i] = Freqs[j];
+            Vals[i] = Vals[j];
+            Freqs[j] = tmpFreq;
+            Vals[j] = tmpVal;
+          }
+      
+      do
+        Freqs[i] = (UInt16)(Freqs[i] + Freqs[(size_t)i + 1]);
+      while (i--);
+    }
+    else
+    {
+      i = NumItems - 1;
+      do
+      {
+        Freqs[i] = (UInt16)(Freqs[i] >> 1);
+        if (Freqs[i] <= Freqs[(size_t)i + 1])
+          Freqs[i] = (UInt16)(Freqs[(size_t)i + 1] + 1);
+      }
+      while (i--);
+    }
+  }
+  
+  return res;
+}
+
+
+void CDecoder::Init()
+{
+  m_Selector.Init(kNumSelectors);
+  unsigned i;
+  for (i = 0; i < kNumLitSelectors; i++)
+    m_Literals[i].Init(kNumLitSymbols);
+  const unsigned numItems = (_numDictBits == 0 ? 1 : (_numDictBits << 1));
+  const unsigned kNumPosSymbolsMax[kNumMatchSelectors] = { 24, 36, 42 };
+  for (i = 0; i < kNumMatchSelectors; i++)
+    m_PosSlot[i].Init(MyMin(numItems, kNumPosSymbolsMax[i]));
+  m_LenSlot.Init(kNumLenSymbols);
+}
+
+
+HRESULT CDecoder::CodeSpec(const Byte *inData, size_t inSize, UInt32 outSize)
+{
+  if (inSize < 2)
+    return S_FALSE;
+
+  CRangeDecoder rc;
+  rc.Stream.SetStreamAndInit(inData, inSize);
+  rc.Init();
+
+  while (outSize != 0)
+  {
+    if (rc.Stream.WasExtraRead())
+      return S_FALSE;
+
+    unsigned selector = m_Selector.Decode(&rc);
+    
+    if (selector < kNumLitSelectors)
+    {
+      const Byte b = (Byte)((selector << (8 - kNumLitSelectorBits)) + m_Literals[selector].Decode(&rc));
+      _outWindow.PutByte(b);
+      outSize--;
+    }
+    else
+    {
+      selector -= kNumLitSelectors;
+      unsigned len = selector + kMatchMinLen;
+    
+      if (selector == 2)
+      {
+        unsigned lenSlot = m_LenSlot.Decode(&rc);
+        if (lenSlot >= kNumSimpleLenSlots)
+        {
+          lenSlot -= 2;
+          const unsigned numDirectBits = (unsigned)(lenSlot >> 2);
+          len += ((4 | (lenSlot & 3)) << numDirectBits) - 2;
+          if (numDirectBits < 6)
+            len += rc.Stream.ReadBits(numDirectBits);
+        }
+        else
+          len += lenSlot;
+      }
+      
+      UInt32 dist = m_PosSlot[selector].Decode(&rc);
+      
+      if (dist >= kNumSimplePosSlots)
+      {
+        unsigned numDirectBits = (unsigned)((dist >> 1) - 1);
+        dist = ((2 | (dist & 1)) << numDirectBits) + rc.Stream.ReadBits(numDirectBits);
+      }
+      
+      unsigned locLen = len;
+      if (len > outSize)
+        locLen = (unsigned)outSize;
+      if (!_outWindow.CopyBlock(dist, locLen))
+        return S_FALSE;
+      outSize -= locLen;
+      len -= locLen;
+      if (len != 0)
+        return S_FALSE;
+    }
+  }
+
+  return rc.Finish() ? S_OK : S_FALSE;
+}
+
+HRESULT CDecoder::Code(const Byte *inData, size_t inSize,
+      ISequentialOutStream *outStream, UInt32 outSize,
+      bool keepHistory)
+{
+  try
+  {
+    _outWindow.SetStream(outStream);
+    _outWindow.Init(keepHistory);
+    if (!keepHistory)
+      Init();
+    
+    const HRESULT res = CodeSpec(inData, inSize, outSize);
+    const HRESULT res2 = _outWindow.Flush();
+    return res != S_OK ? res : res2;
+  }
+  catch(const CLzOutWindowException &e) { return e.ErrorCode; }
+  catch(...) { return S_FALSE; }
+}
+
+HRESULT CDecoder::SetParams(unsigned numDictBits)
+{
+  if (numDictBits > 21)
+    return E_INVALIDARG;
+  _numDictBits = numDictBits;
+  if (!_outWindow.Create((UInt32)1 << _numDictBits))
+    return E_OUTOFMEMORY;
+  return S_OK;
+}
+
+}}
diff --git a/CPP/7zip/Compress/QuantumDecoder.h b/CPP/7zip/Compress/QuantumDecoder.h
new file mode 100644
index 0000000..925989a
--- /dev/null
+++ b/CPP/7zip/Compress/QuantumDecoder.h
@@ -0,0 +1,169 @@
+// QuantumDecoder.h
+
+#ifndef ZIP7_INC_COMPRESS_QUANTUM_DECODER_H
+#define ZIP7_INC_COMPRESS_QUANTUM_DECODER_H
+
+#include "../../Common/MyCom.h"
+
+#include "LzOutWindow.h"
+
+namespace NCompress {
+namespace NQuantum {
+
+class CBitDecoder
+{
+  UInt32 Value;
+  bool _extra;
+  const Byte *_buf;
+  const Byte *_bufLim;
+public:
+  void SetStreamAndInit(const Byte *inData, size_t inSize)
+  {
+    _buf = inData;
+    _bufLim = inData + inSize;
+    Value = 0x10000;
+    _extra = false;
+  }
+
+  bool WasExtraRead() const { return _extra; }
+
+  bool WasFinishedOK() const
+  {
+    return !_extra && _buf == _bufLim;
+  }
+  
+  UInt32 ReadBit()
+  {
+    if (Value >= 0x10000)
+    {
+      Byte b;
+      if (_buf >= _bufLim)
+      {
+        b = 0xFF;
+        _extra = true;
+      }
+      else
+        b = *_buf++;
+      Value = 0x100 | b;
+    }
+    UInt32 res = (Value >> 7) & 1;
+    Value <<= 1;
+    return res;
+  }
+
+  UInt32 ReadStart16Bits()
+  {
+    // we use check for extra read in another code.
+    UInt32 val = ((UInt32)*_buf << 8) | _buf[1];
+    _buf += 2;
+    return val;
+  }
+
+  UInt32 ReadBits(unsigned numBits) // numBits > 0
+  {
+    UInt32 res = 0;
+    do
+      res = (res << 1) | ReadBit();
+    while (--numBits);
+    return res;
+  }
+};
+
+
+class CRangeDecoder
+{
+  UInt32 Low;
+  UInt32 Range;
+  UInt32 Code;
+public:
+  CBitDecoder Stream;
+
+  void Init()
+  {
+    Low = 0;
+    Range = 0x10000;
+    Code = Stream.ReadStart16Bits();
+  }
+
+  bool Finish()
+  {
+    // do all streams use these two bits at end?
+    if (Stream.ReadBit() != 0) return false;
+    if (Stream.ReadBit() != 0) return false;
+    return Stream.WasFinishedOK();
+  }
+
+  UInt32 GetThreshold(UInt32 total) const
+  {
+    return ((Code + 1) * total - 1) / Range; // & 0xFFFF is not required;
+  }
+
+  void Decode(UInt32 start, UInt32 end, UInt32 total)
+  {
+    UInt32 high = Low + end * Range / total - 1;
+    UInt32 offset = start * Range / total;
+    Code -= offset;
+    Low += offset;
+    for (;;)
+    {
+      if ((Low & 0x8000) != (high & 0x8000))
+      {
+        if ((Low & 0x4000) == 0 || (high & 0x4000) != 0)
+          break;
+        Low &= 0x3FFF;
+        high |= 0x4000;
+      }
+      Low = (Low << 1) & 0xFFFF;
+      high = ((high << 1) | 1) & 0xFFFF;
+      Code = ((Code << 1) | Stream.ReadBit());
+    }
+    Range = high - Low + 1;
+  }
+};
+
+
+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 CModelDecoder
+{
+  unsigned NumItems;
+  unsigned ReorderCount;
+  UInt16 Freqs[kNumSymbolsMax + 1];
+  Byte Vals[kNumSymbolsMax];
+public:
+  void Init(unsigned numItems);
+  unsigned Decode(CRangeDecoder *rc);
+};
+
+
+Z7_CLASS_IMP_COM_0(
+  CDecoder
+)
+  CLzOutWindow _outWindow;
+  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,
+      ISequentialOutStream *outStream, UInt32 outSize,
+      bool keepHistory);
+  HRESULT SetParams(unsigned numDictBits);
+
+  CDecoder(): _numDictBits(0) {}
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Compress/Rar1Decoder.cpp b/CPP/7zip/Compress/Rar1Decoder.cpp
new file mode 100644
index 0000000..050cde2
--- /dev/null
+++ b/CPP/7zip/Compress/Rar1Decoder.cpp
@@ -0,0 +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;
+}
+
+}}
diff --git a/CPP/7zip/Compress/Rar1Decoder.h b/CPP/7zip/Compress/Rar1Decoder.h
new file mode 100644
index 0000000..6d0e31d
--- /dev/null
+++ b/CPP/7zip/Compress/Rar1Decoder.h
@@ -0,0 +1,71 @@
+// 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 "HuffmanDecoder.h"
+#include "LzOutWindow.h"
+
+namespace NCompress {
+namespace NRar1 {
+
+const UInt32 kNumRepDists = 4;
+
+Z7_CLASS_IMP_COM_2(
+  CDecoder
+  , ICompressCoder
+  , ICompressSetDecoderProperties2
+)
+  CLzOutWindow m_OutWindowStream;
+  NBitm::CDecoder<CInBuffer> m_InBitStream;
+
+  UInt64 m_UnpackSize;
+
+  UInt32 LastDist;
+  UInt32 LastLength;
+
+  UInt32 m_RepDistPtr;
+  UInt32 m_RepDists[kNumRepDists];
+
+  bool _isSolid;
+  bool _solidAllowed;
+
+  bool StMode;
+  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
new file mode 100644
index 0000000..92404b6
--- /dev/null
+++ b/CPP/7zip/Compress/Rar2Decoder.cpp
@@ -0,0 +1,441 @@
+// Rar2Decoder.cpp
+// According to unRAR license, this code may not be used to develop
+// a program that creates RAR archives
+ 
+#include "StdAfx.h"
+
+#include <stdlib.h>
+
+#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 < kNumRepDists; 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; }
+
+bool CDecoder::ReadTables(void)
+{
+  m_TablesOK = false;
+
+  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 * kMMTableSize;
+  }
+  else
+    numLevels = kHeapTablesSizesSum;
+ 
+  unsigned i;
+  for (i = 0; i < kLevelTableSize; i++)
+    levelLevels[i] = (Byte)ReadBits(4);
+  RIF(m_LevelDecoder.Build(levelLevels))
+  
+  i = 0;
+  
+  do
+  {
+    const UInt32 sym = m_LevelDecoder.Decode(&m_InBitStream);
+    if (sym < kTableDirectLevels)
+    {
+      lens[i] = (Byte)((sym + m_LastLevels[i]) & kLevelMask);
+      i++;
+    }
+    else
+    {
+      if (sym == kTableLevelRepNumber)
+      {
+        unsigned num = ReadBits(2) + 3;
+        if (i == 0)
+          return false;
+        num += i;
+        if (num > numLevels)
+        {
+          // return false;
+          num = numLevels; // original unRAR
+        }
+        const Byte v = lens[(size_t)i - 1];
+        do
+          lens[i++] = v;
+        while (i < num);
+      }
+      else
+      {
+        unsigned num;
+        if (sym == kTableLevel0Number)
+          num = ReadBits(3) + 3;
+        else if (sym == kTableLevel0Number2)
+          num = ReadBits(7) + 11;
+        else
+          return false;
+        num += i;
+        if (num > numLevels)
+        {
+          // return false;
+          num = numLevels; // original unRAR
+        }
+        do
+          lens[i++] = 0;
+        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[i * kMMTableSize]))
+    }
+  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 UInt32 symbol = m_MMDecoders[m_MmFilter.CurrentChannel].Decode(&m_InBitStream);
+      if (symbol == 256)
+        return ReadTables();
+      if (symbol >= kMMTableSize)
+        return false;
+    }
+    else
+    {
+      const UInt32 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 UInt32 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;
+}
+
+bool CDecoder::DecodeLz(Int32 pos)
+{
+  while (pos > 0)
+  {
+    UInt32 sym = m_MainDecoder.Decode(&m_InBitStream);
+    if (m_InBitStream.ExtraBitsWereRead())
+      return false;
+    UInt32 length, distance;
+    if (sym < 256)
+    {
+      m_OutWindowStream.PutByte(Byte(sym));
+      pos--;
+      continue;
+    }
+    else if (sym >= kMatchNumber)
+    {
+      if (sym >= kMainTableSize)
+        return false;
+      sym -= kMatchNumber;
+      length = kNormalMatchMinLen + UInt32(kLenStart[sym]) +
+        m_InBitStream.ReadBits(kLenDirectBits[sym]);
+      sym = m_DistDecoder.Decode(&m_InBitStream);
+      if (sym >= kDistTableSize)
+        return false;
+      distance = kDistStart[sym] + m_InBitStream.ReadBits(kDistDirectBits[sym]);
+      if (distance >= kDistLimit3)
+      {
+        length += 2 - ((distance - kDistLimit4) >> 31);
+        // length++;
+        // if (distance >= kDistLimit4)
+        //  length++;
+      }
+    }
+    else if (sym == kRepBothNumber)
+    {
+      length = m_LastLength;
+      if (length == 0)
+        return false;
+      distance = m_RepDists[(m_RepDistPtr + 4 - 1) & 3];
+    }
+    else if (sym < kLen2Number)
+    {
+      distance = m_RepDists[(m_RepDistPtr - (sym - kRepNumber + 1)) & 3];
+      sym = m_LenDecoder.Decode(&m_InBitStream);
+      if (sym >= kLenTableSize)
+        return false;
+      length = 2 + kLenStart[sym] + m_InBitStream.ReadBits(kLenDirectBits[sym]);
+      if (distance >= kDistLimit2)
+      {
+        length++;
+        if (distance >= kDistLimit3)
+        {
+          length += 2 - ((distance - kDistLimit4) >> 31);
+          // length++;
+          // if (distance >= kDistLimit4)
+          //   length++;
+        }
+      }
+    }
+    else if (sym < kReadTableNumber)
+    {
+      sym -= kLen2Number;
+      distance = kLen2DistStarts[sym] +
+        m_InBitStream.ReadBits(kLen2DistDirectBits[sym]);
+      length = 2;
+    }
+    else // (sym == kReadTableNumber)
+      return true;
+
+    m_RepDists[m_RepDistPtr++ & 3] = distance;
+    m_LastLength = length;
+    if (!m_OutWindowStream.CopyBlock(distance, length))
+      return false;
+    pos -= length;
+  }
+  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
new file mode 100644
index 0000000..d77bfc1
--- /dev/null
+++ b/CPP/7zip/Compress/Rar2Decoder.h
@@ -0,0 +1,164 @@
+// 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 kNumRepDists = 4;
+const unsigned kDistTableSize = 48;
+
+const unsigned kMMTableSize = 256 + 1;
+
+const UInt32 kMainTableSize = 298;
+const UInt32 kLenTableSize = 28;
+
+const UInt32 kDistTableStart = kMainTableSize;
+const UInt32 kLenTableStart = kDistTableStart + kDistTableSize;
+
+const UInt32 kHeapTablesSizesSum = kMainTableSize + kDistTableSize + kLenTableSize;
+
+const UInt32 kLevelTableSize = 19;
+
+const UInt32 kMMTablesSizesSum = kMMTableSize * 4;
+
+const UInt32 kMaxTableSize = kMMTablesSizesSum;
+
+const UInt32 kTableDirectLevels = 16;
+const UInt32 kTableLevelRepNumber = kTableDirectLevels;
+const UInt32 kTableLevel0Number = kTableLevelRepNumber + 1;
+const UInt32 kTableLevel0Number2 = kTableLevel0Number + 1;
+
+const UInt32 kLevelMask = 0xF;
+
+
+const UInt32 kRepBothNumber = 256;
+const UInt32 kRepNumber = kRepBothNumber + 1;
+const UInt32 kLen2Number = kRepNumber + 4;
+
+const UInt32 kLen2NumNumbers = 8;
+const UInt32 kReadTableNumber = kLen2Number + kLen2NumNumbers;
+const UInt32 kMatchNumber = kReadTableNumber + 1;
+
+const Byte kLenStart     [kLenTableSize] = {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};
+const Byte kLenDirectBits[kLenTableSize] = {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};
+
+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};
+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};
+
+const Byte kLevelDirectBits[kLevelTableSize] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7};
+
+const Byte kLen2DistStarts[kLen2NumNumbers]={0,4,8,16,32,64,128,192};
+const Byte kLen2DistDirectBits[kLen2NumNumbers]={2,2,3, 4, 5, 6,  6,  6};
+
+const UInt32 kDistLimit2 = 0x101 - 1;
+const UInt32 kDistLimit3 = 0x2000 - 1;
+const UInt32 kDistLimit4 = 0x40000 - 1;
+
+const UInt32 kMatchMaxLen = 255 + 2;
+const UInt32 kMatchMaxLenMax = 255 + 5;
+const UInt32 kNormalMatchMinLen = 3;
+
+namespace NMultimedia {
+
+struct CFilter
+{
+  int K1,K2,K3,K4,K5;
+  int D1,D2,D3,D4;
+  int LastDelta;
+  UInt32 Dif[11];
+  UInt32 ByteCount;
+  int LastChar;
+
+  Byte Decode(int &channelDelta, Byte delta);
+
+  void Init() { memset(this, 0, sizeof(*this)); }
+
+};
+
+const unsigned kNumChanelsMax = 4;
+
+class CFilter2
+{
+public:
+  CFilter  m_Filters[kNumChanelsMax];
+  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<CInBuffer> CBitDecoder;
+
+const unsigned kNumHuffmanBits = 15;
+
+Z7_CLASS_IMP_NOQIB_2(
+  CDecoder
+  , ICompressCoder
+  , ICompressSetDecoderProperties2
+)
+  CLzOutWindow m_OutWindowStream;
+  CBitDecoder m_InBitStream;
+
+  UInt32 m_RepDistPtr;
+  UInt32 m_RepDists[kNumRepDists];
+
+  UInt32 m_LastLength;
+
+  bool _isSolid;
+  bool _solidAllowed;
+  bool m_TablesOK;
+  bool m_AudioMode;
+
+  NHuffman::CDecoder<kNumHuffmanBits, kMainTableSize> m_MainDecoder;
+  NHuffman::CDecoder<kNumHuffmanBits, kDistTableSize> m_DistDecoder;
+  NHuffman::CDecoder<kNumHuffmanBits, kLenTableSize> m_LenDecoder;
+  NHuffman::CDecoder<kNumHuffmanBits, kMMTableSize> m_MMDecoders[NMultimedia::kNumChanelsMax];
+  NHuffman::CDecoder<kNumHuffmanBits, kLevelTableSize> m_LevelDecoder;
+
+  UInt64 m_PackSize;
+
+  unsigned m_NumChannels;
+  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
new file mode 100644
index 0000000..a4943ad
--- /dev/null
+++ b/CPP/7zip/Compress/Rar3Decoder.cpp
@@ -0,0 +1,935 @@
+// 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 UInt32 kSymbolReadTable = 256;
+static const UInt32 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():
+  _window(NULL),
+  _winPos(0),
+  _wrPtr(0),
+  _lzSize(0),
+  _writtenFileSize(0),
+  _vmData(NULL),
+  _vmCode(NULL),
+  _isSolid(false),
+  _solidAllowed(false)
+{
+  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)
+  {
+    unsigned num = _tempFilters.Size();
+    CTempFilter **tempFilters = &_tempFilters.Front();
+    
+    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<Byte> &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;
+
+  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;
+  }
+  
+  RIF(m_LevelDecoder.Build(levelLevels))
+  
+  i = 0;
+  
+  do
+  {
+    const UInt32 sym = m_LevelDecoder.Decode(&m_InBitStream.BitDecoder);
+    if (sym < 16)
+    {
+      lens[i] = Byte((sym + m_LastLevels[i]) & 15);
+      i++;
+    }
+    else if (sym > kLevelTableSize)
+      return S_FALSE;
+    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;
+
+    UInt32 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 UInt32 sym2 = m_LenDecoder.Decode(&m_InBitStream.BitDecoder);
+      if (sym2 >= kLenTableSize)
+        return S_FALSE;
+      len = 2 + sym2;
+      if (sym2 >= 8)
+      {
+        unsigned num = (sym2 >> 2) - 1;
+        len = 2 + ((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 + ((4 + (sym & 3)) << num) + m_InBitStream.BitDecoder.ReadBits_upto8(num);
+        }
+        const UInt32 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 UInt32 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
new file mode 100644
index 0000000..4711052
--- /dev/null
+++ b/CPP/7zip/Compress/Rar3Decoder.h
@@ -0,0 +1,275 @@
+// 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 UInt32 kWindowSize = 1 << 22;
+const UInt32 kWindowMask = (kWindowSize - 1);
+
+const UInt32 kNumReps = 4;
+const UInt32 kNumLen2Symbols = 8;
+const UInt32 kLenTableSize = 28;
+const UInt32 kMainTableSize = 256 + 1 + 1 + 1 + kNumReps + kNumLen2Symbols + kLenTableSize;
+const UInt32 kDistTableSize = 60;
+
+const unsigned kNumAlignBits = 4;
+const UInt32 kAlignTableSize = (1 << kNumAlignBits) + 1;
+
+const UInt32 kLevelTableSize = 20;
+
+const UInt32 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);
+  }
+  
+  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);
+  }
+  
+  void MovePos(unsigned numBits)
+  {
+    _bitPos -= numBits;
+    _value = _value & ((1 << _bitPos) - 1);
+  }
+  
+  UInt32 ReadBits(unsigned numBits)
+  {
+    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;
+    UInt32 res = _value >> _bitPos;
+    _value = _value & ((1 << _bitPos) - 1);
+    return res;
+  }
+
+  Byte ReadByteFromAligned()
+  {
+    if (_bitPos == 0)
+      return Stream.ReadByte();
+    unsigned bitsPos = _bitPos - 8;
+    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<Byte> 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();
+  }
+};
+
+const unsigned kNumHuffmanBits = 15;
+
+Z7_CLASS_IMP_NOQIB_2(
+  CDecoder
+  , ICompressCoder
+  , ICompressSetDecoderProperties2
+)
+  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<kNumHuffmanBits, kMainTableSize> m_MainDecoder;
+  UInt32 kDistStart[kDistTableSize];
+  NHuffman::CDecoder<kNumHuffmanBits, kDistTableSize> m_DistDecoder;
+  NHuffman::CDecoder<kNumHuffmanBits, kAlignTableSize> m_AlignDecoder;
+  NHuffman::CDecoder<kNumHuffmanBits, kLenTableSize> m_LenDecoder;
+  NHuffman::CDecoder<kNumHuffmanBits, kLevelTableSize> m_LevelDecoder;
+
+  UInt32 _reps[kNumReps];
+  UInt32 _lastLength;
+  
+  Byte m_LastLevels[kTablesSizesSum];
+
+  Byte *_vmData;
+  Byte *_vmCode;
+  NVm::CVm _vm;
+  CRecordVector<CFilter *> _filters;
+  CRecordVector<CTempFilter *>  _tempFilters;
+  unsigned _numEmptyTempFilters;
+  UInt32 _lastFilter;
+
+  bool _isSolid;
+  bool _solidAllowed;
+  // bool _errorMode;
+
+  bool _lzMode;
+  bool _unsupportedFilter;
+
+  UInt32 PrevAlignBits;
+  UInt32 PrevAlignCount;
+
+  bool TablesRead;
+  bool TablesOK;
+
+  CPpmd7 _ppmd;
+  int PpmEscChar;
+  bool PpmError;
+  
+  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
new file mode 100644
index 0000000..9b728ef
--- /dev/null
+++ b/CPP/7zip/Compress/Rar3Vm.cpp
@@ -0,0 +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 <stdlib.h>
+
+#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<Byte> &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 int predicted;
+      if (i < width)
+        predicted = prevByte;
+      else
+      {
+        const unsigned int upperLeftByte = destData[i - width];
+        const unsigned int 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
new file mode 100644
index 0000000..fde7e95
--- /dev/null
+++ b/CPP/7zip/Compress/Rar3Vm.h
@@ -0,0 +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<CCommand> Commands;
+  #endif
+  
+public:
+  #ifdef Z7_RARVM_STANDARD_FILTERS
+  int StandardFilterIndex;
+  #endif
+  
+  bool IsSupported;
+  CRecordVector<Byte> StaticData;
+
+  bool PrepareProgram(const Byte *code, UInt32 codeSize);
+};
+
+
+struct CProgramInitState
+{
+  UInt32 InitR[kNumGpRegs];
+  CRecordVector<Byte> 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<Byte> &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
new file mode 100644
index 0000000..e55d7de
--- /dev/null
+++ b/CPP/7zip/Compress/Rar5Decoder.cpp
@@ -0,0 +1,980 @@
+// Rar5Decoder.cpp
+// According to unRAR license, this code may not be used to develop
+// a program that creates RAR archives
+
+#include "StdAfx.h"
+
+// #include <stdio.h>
+
+#include "../Common/StreamUtils.h"
+
+#include "Rar5Decoder.h"
+
+namespace NCompress {
+namespace NRar5 {
+
+static const size_t kInputBufSize = 1 << 20;
+ 
+void CBitDecoder::Prepare2() throw()
+{
+  const unsigned kSize = 16;
+  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;
+
+  if (!_wasFinished)
+  {
+    UInt32 processed = (UInt32)(kInputBufSize - rem);
+    _hres = _stream->Read(_bufLim, (UInt32)processed, &processed);
+    _bufLim += processed;
+    _wasFinished = (processed == 0);
+    if (_hres != S_OK)
+    {
+      _wasFinished = true;
+      // throw CInBufferException(result);
+    }
+  }
+
+  rem = (size_t)(_bufLim - _buf);
+  _bufCheck = _buf;
+  if (rem < kSize)
+    memset(_bufLim, 0xFF, kSize - rem);
+  else
+    _bufCheck = _bufLim - kSize;
+
+  SetCheck2();
+}
+
+
+enum FilterType
+{
+  FILTER_DELTA = 0,
+  FILTER_E8,
+  FILTER_E8E9,
+  FILTER_ARM
+};
+
+static const size_t kWriteStep = (size_t)1 << 22;
+
+CDecoder::CDecoder():
+    _isSolid(false),
+    _solidAllowed(false),
+    _wasInit(false),
+    _dictSizeLog(0),
+    _window(NULL),
+    _winPos(0),
+    _lzSize(0),
+    _lzEnd(0),
+    _writtenFileSize(0),
+    _winSizeAllocated(0),
+    _inputBuf(NULL)
+{
+}
+
+CDecoder::~CDecoder()
+{
+  ::MidFree(_window);
+  ::MidFree(_inputBuf);
+}
+
+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;
+}
+
+HRESULT CDecoder::ExecuteFilter(const CFilter &f)
+{
+  bool useDest = false;
+
+  Byte *data = _filterSrc;
+  UInt32 dataSize = f.Size;
+  
+  // printf("\nType = %d offset = %9d  size = %5d", f.Type, (unsigned)(f.Start - _lzFileStart), dataSize);
+  
+  switch (f.Type)
+  {
+    case FILTER_E8:
+    case FILTER_E8E9:
+    {
+      // printf("  FILTER_E8");
+      if (dataSize > 4)
+      {
+        dataSize -= 4;
+        const UInt32 fileOffset = (UInt32)(f.Start - _lzFileStart);
+        
+        const UInt32 kFileSize = (UInt32)1 << 24;
+        const Byte cmpMask = (Byte)(f.Type == FILTER_E8 ? 0xFF : 0xFE);
+        
+        for (UInt32 curPos = 0; curPos < dataSize;)
+        {
+          curPos++;
+          if (((*data++) & cmpMask) == 0xE8)
+          {
+            const UInt32 offset = (curPos + fileOffset) & (kFileSize - 1);
+            const UInt32 addr = GetUi32(data);
+            
+            if (addr < kFileSize)
+            {
+              SetUi32(data, addr - offset)
+            }
+            else if (addr > ((UInt32)0xFFFFFFFF - offset)) // (addr > ~(offset))
+            {
+              SetUi32(data, addr + kFileSize)
+            }
+              
+            data += 4;
+            curPos += 4;
+          }
+        }
+      }
+      break;
+    }
+
+    case FILTER_ARM:
+    {
+      if (dataSize >= 4)
+      {
+        dataSize -= 4;
+        const UInt32 fileOffset = (UInt32)(f.Start - _lzFileStart);
+        
+        for (UInt32 curPos = 0; curPos <= dataSize; curPos += 4)
+        {
+          Byte *d = data + curPos;
+          if (d[3] == 0xEB)
+          {
+            UInt32 offset = d[0] | ((UInt32)d[1] << 8) | ((UInt32)d[2] << 16);
+            offset -= (fileOffset + curPos) >> 2;
+            d[0] = (Byte)offset;
+            d[1] = (Byte)(offset >> 8);
+            d[2] = (Byte)(offset >> 16);
+          }
+        }
+      }
+      break;
+    }
+    
+    case FILTER_DELTA:
+    {
+      // printf("  channels = %d", f.Channels);
+      _filterDst.AllocAtLeast(dataSize);
+      if (!_filterDst.IsAllocated())
+        return E_OUTOFMEMORY;
+
+      Byte *dest = _filterDst;
+      const UInt32 numChannels = f.Channels;
+      
+      for (UInt32 curChannel = 0; curChannel < numChannels; curChannel++)
+      {
+        Byte prevByte = 0;
+        for (UInt32 destPos = curChannel; destPos < dataSize; destPos += numChannels)
+          dest[destPos] = (prevByte = (Byte)(prevByte - *data++));
+      }
+      useDest = true;
+      break;
+    }
+
+    default:
+      _unsupportedFilter = true;
+      memset(_filterSrc, 0, f.Size);
+      // return S_OK;  // unrar
+  }
+
+  return WriteData(useDest ?
+      (const Byte *)_filterDst :
+      (const Byte *)_filterSrc,
+      f.Size);
+}
+
+
+HRESULT CDecoder::WriteBuf()
+{
+  DeleteUnusedFilters();
+
+  for (unsigned i = 0; i < _filters.Size();)
+  {
+    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)
+      {
+        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(blockSize);
+      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 (!_filters.IsEmpty())
+    return S_OK;
+  
+  const size_t lzAvail = (size_t)(_lzSize - _lzWritten);
+  RINOK(WriteData(_window + _winPos - lzAvail, lzAvail))
+  _lzWritten += lzAvail;
+  return S_OK;
+}
+
+
+static UInt32 ReadUInt32(CBitDecoder &bi)
+{
+  const unsigned numBytes = bi.ReadBits9fix(2) + 1;
+  UInt32 v = 0;
+  for (unsigned i = 0; i < numBytes; i++)
+    v += ((UInt32)bi.ReadBits9fix(8) << (i * 8));
+  return v;
+}
+
+
+static const unsigned MAX_UNPACK_FILTERS = 8192;
+
+HRESULT CDecoder::AddFilter(CBitDecoder &_bitStream)
+{
+  DeleteUnusedFilters();
+
+  if (_filters.Size() >= MAX_UNPACK_FILTERS)
+  {
+    RINOK(WriteBuf())
+    DeleteUnusedFilters();
+    if (_filters.Size() >= MAX_UNPACK_FILTERS)
+    {
+      _unsupportedFilter = true;
+      InitFilters();
+    }
+  }
+
+  _bitStream.Prepare();
+
+  CFilter f;
+  const UInt32 blockStart = ReadUInt32(_bitStream);
+  f.Size = ReadUInt32(_bitStream);
+
+  if (f.Size > ((UInt32)1 << 22))
+  {
+    _unsupportedFilter = true;
+    f.Size = 0;  // unrar 5.5.5
+  }
+
+  f.Type = (Byte)_bitStream.ReadBits9fix(3);
+  f.Channels = 0;
+  if (f.Type == FILTER_DELTA)
+    f.Channels = (Byte)(_bitStream.ReadBits9fix(5) + 1);
+  f.Start = _lzSize + blockStart;
+
+  if (f.Start < _filterEnd)
+    _unsupportedFilter = true;
+  else
+  {
+    _filterEnd = f.Start + f.Size;
+    if (f.Size != 0)
+      _filters.Add(f);
+  }
+
+  return S_OK;
+}
+
+
+#define RIF(x) { if (!(x)) return S_FALSE; }
+
+HRESULT CDecoder::ReadTables(CBitDecoder &_bitStream)
+{
+  if (_progress)
+  {
+    const UInt64 packSize = _bitStream.GetProcessedSize();
+    RINOK(_progress->SetRatioInfo(&packSize, &_writtenFileSize))
+  }
+
+  _bitStream.AlignToByte();
+  _bitStream.Prepare();
+  
+  {
+    const unsigned flags = _bitStream.ReadByteInAligned();
+    unsigned checkSum = _bitStream.ReadByteInAligned();
+    checkSum ^= flags;
+    const unsigned num = (flags >> 3) & 3;
+    if (num == 3)
+      return S_FALSE;
+    UInt32 blockSize = _bitStream.ReadByteInAligned();
+    checkSum ^= blockSize;
+
+    if (num != 0)
+    {
+      unsigned b = _bitStream.ReadByteInAligned();
+      checkSum ^= b;
+      blockSize += (UInt32)b << 8;
+      if (num > 1)
+      {
+        b = _bitStream.ReadByteInAligned();
+        checkSum ^= b;
+        blockSize += (UInt32)b << 16;
+      }
+    }
+    
+    if (checkSum != 0x5A)
+      return S_FALSE;
+
+    unsigned blockSizeBits7 = (flags & 7) + 1;
+    blockSize += (blockSizeBits7 >> 3);
+    if (blockSize == 0)
+      return S_FALSE;
+    blockSize--;
+    blockSizeBits7 &= 7;
+
+    _bitStream._blockEndBits7 = (Byte)blockSizeBits7;
+    _bitStream._blockEnd = _bitStream.GetProcessedSize_Round() + blockSize;
+    
+    _bitStream.SetCheck2();
+    
+    _isLastBlock = ((flags & 0x40) != 0);
+    
+    if ((flags & 0x80) == 0)
+    {
+      if (!_tableWasFilled)
+        if (blockSize != 0 || blockSizeBits7 != 0)
+          return S_FALSE;
+      return S_OK;
+    }
+    
+    _tableWasFilled = false;
+  }
+
+  {
+    Byte lens2[kLevelTableSize];
+    
+    for (unsigned i = 0; i < kLevelTableSize;)
+    {
+      _bitStream.Prepare();
+      const unsigned len = (unsigned)_bitStream.ReadBits9fix(4);
+      if (len == 15)
+      {
+        unsigned num = (unsigned)_bitStream.ReadBits9fix(4);
+        if (num != 0)
+        {
+          num += 2;
+          num += i;
+          if (num > kLevelTableSize)
+            num = kLevelTableSize;
+          do
+            lens2[i++] = 0;
+          while (i < num);
+          continue;
+        }
+      }
+      lens2[i++] = (Byte)len;
+    }
+
+    if (_bitStream.IsBlockOverRead())
+      return S_FALSE;
+    
+    RIF(m_LevelDecoder.Build(lens2))
+  }
+  
+  Byte lens[kTablesSizesSum];
+  unsigned i = 0;
+  
+  do
+  {
+    if (_bitStream._buf >= _bitStream._bufCheck2)
+    {
+      if (_bitStream._buf >= _bitStream._bufCheck)
+        _bitStream.Prepare();
+      if (_bitStream.IsBlockOverRead())
+        return S_FALSE;
+    }
+    
+    const UInt32 sym = m_LevelDecoder.Decode(&_bitStream);
+    
+    if (sym < 16)
+      lens[i++] = (Byte)sym;
+    else if (sym > kLevelTableSize)
+      return S_FALSE;
+    else
+    {
+      unsigned num = ((sym - 16) & 1) * 4;
+      num += num + 3 + (unsigned)_bitStream.ReadBits9(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 (_bitStream.IsBlockOverRead())
+    return S_FALSE;
+  if (_bitStream.InputEofError())
+    return S_FALSE;
+
+  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]))
+
+  _useAlignBits = false;
+  // _useAlignBits = true;
+  for (i = 0; i < kAlignTableSize; i++)
+    if (lens[kMainTableSize + kDistTableSize + (size_t)i] != kNumAlignBits)
+    {
+      _useAlignBits = true;
+      break;
+    }
+
+  _tableWasFilled = true;
+  return S_OK;
+}
+
+
+static inline unsigned SlotToLen(CBitDecoder &_bitStream, unsigned slot)
+{
+  if (slot < 8)
+    return slot + 2;
+  const unsigned numBits = (slot >> 2) - 1;
+  return 2 + ((4 | (slot & 3)) << numBits) + _bitStream.ReadBits9(numBits);
+}
+
+
+static const UInt32 kSymbolRep = 258;
+// static const unsigned kMaxMatchLen = 0x1001 + 3;
+
+HRESULT CDecoder::DecodeLZ()
+{
+  CBitDecoder _bitStream;
+  _bitStream._stream = _inStream;
+  _bitStream._bufBase = _inputBuf;
+  _bitStream.Init();
+
+  UInt32 rep0 = _reps[0];
+
+  UInt32 remLen = 0;
+
+  size_t limit;
+  {
+    size_t rem = _winSize - _winPos;
+    if (rem > kWriteStep)
+      rem = kWriteStep;
+    limit = _winPos + rem;
+  }
+  
+  for (;;)
+  {
+    if (_winPos >= limit)
+    {
+      RINOK(WriteBuf())
+      if (_unpackSize_Defined && _writtenFileSize > _unpackSize)
+        break; // return S_FALSE;
+      
+      {
+        size_t rem = _winSize - _winPos;
+        
+        if (rem == 0)
+        {
+          _winPos = 0;
+          rem = _winSize;
+        }
+        if (rem > kWriteStep)
+          rem = kWriteStep;
+        limit = _winPos + rem;
+      }
+
+      if (remLen != 0)
+      {
+        size_t winPos = _winPos;
+        const size_t winMask = _winMask;
+        size_t pos = (winPos - (size_t)rep0 - 1) & winMask;
+        
+        Byte *win = _window;
+        do
+        {
+          if (winPos >= limit)
+            break;
+          win[winPos] = win[pos];
+          winPos++;
+          pos = (pos + 1) & winMask;
+        }
+        while (--remLen != 0);
+        
+        _lzSize += winPos - _winPos;
+        _winPos = winPos;
+        continue;
+      }
+    }
+
+    if (_bitStream._buf >= _bitStream._bufCheck2)
+    {
+      if (_bitStream.InputEofError())
+        break; // return S_FALSE;
+      if (_bitStream._buf >= _bitStream._bufCheck)
+        _bitStream.Prepare2();
+
+      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)
+            break; // return S_FALSE;
+          if (bits7 == _bitStream._blockEndBits7)
+          {
+            if (_isLastBlock)
+            {
+              _reps[0] = rep0;
+              
+              if (_bitStream.InputEofError())
+                break;
+              
+              /*
+              // packSize can be 15 bytes larger for encrypted archive
+              if (_packSize_Defined && _packSize < _bitStream.GetProcessedSize())
+                break;
+              */
+              
+              return _bitStream._hres;
+              // break;
+            }
+            RINOK(ReadTables(_bitStream))
+            continue;
+          }
+        }
+      }
+
+      // that check is not required, but it can help, if there is BUG in another code
+      if (!_tableWasFilled)
+        break; // return S_FALSE;
+    }
+
+    const UInt32 sym = m_MainDecoder.Decode(&_bitStream);
+    
+    if (sym < 256)
+    {
+      size_t winPos = _winPos;
+      _window[winPos] = (Byte)sym;
+      _winPos = winPos + 1;
+      _lzSize++;
+      continue;
+    }
+   
+    UInt32 len;
+
+    if (sym < kSymbolRep + kNumReps)
+    {
+      if (sym >= kSymbolRep)
+      {
+        if (sym != kSymbolRep)
+        {
+          UInt32 dist;
+          if (sym == kSymbolRep + 1)
+            dist = _reps[1];
+          else
+          {
+            if (sym == kSymbolRep + 2)
+              dist = _reps[2];
+            else
+            {
+              dist = _reps[3];
+              _reps[3] = _reps[2];
+            }
+            _reps[2] = _reps[1];
+          }
+          _reps[1] = rep0;
+          rep0 = dist;
+        }
+        
+        const UInt32 sym2 = m_LenDecoder.Decode(&_bitStream);
+        if (sym2 >= kLenTableSize)
+          break; // return S_FALSE;
+        len = SlotToLen(_bitStream, sym2);
+      }
+      else
+      {
+        if (sym == 256)
+        {
+          RINOK(AddFilter(_bitStream))
+          continue;
+        }
+        else // if (sym == 257)
+        {
+          len = _lastLen;
+          // if (len = 0), we ignore that symbol, like original unRAR code, but it can mean error in stream.
+          // if (len == 0) return S_FALSE;
+          if (len == 0)
+            continue;
+        }
+      }
+    }
+    else if (sym >= kMainTableSize)
+      break; // return S_FALSE;
+    else
+    {
+      _reps[3] = _reps[2];
+      _reps[2] = _reps[1];
+      _reps[1] = rep0;
+      len = SlotToLen(_bitStream, sym - (kSymbolRep + kNumReps));
+      
+      rep0 = m_DistDecoder.Decode(&_bitStream);
+      
+      if (rep0 >= 4)
+      {
+        if (rep0 >= _numCorrectDistSymbols)
+          break; // return S_FALSE;
+        const unsigned numBits = (rep0 >> 1) - 1;
+        rep0 = (2 | (rep0 & 1)) << numBits;
+        
+        if (numBits < kNumAlignBits)
+          rep0 += _bitStream.ReadBits9(numBits);
+        else
+        {
+          len += (numBits >= 7);
+          len += (numBits >= 12);
+          len += (numBits >= 17);
+        
+          if (_useAlignBits)
+          {
+            // if (numBits > kNumAlignBits)
+              rep0 += (_bitStream.ReadBits32(numBits - kNumAlignBits) << kNumAlignBits);
+            const UInt32 a = m_AlignDecoder.Decode(&_bitStream);
+            if (a >= kAlignTableSize)
+              break; // return S_FALSE;
+            rep0 += a;
+          }
+          else
+            rep0 += _bitStream.ReadBits32(numBits);
+        }
+      }
+    }
+
+    _lastLen = len;
+
+    if (rep0 >= _lzSize)
+      _lzError = true;
+    
+    {
+      UInt32 lenCur = len;
+      size_t winPos = _winPos;
+      size_t pos = (winPos - (size_t)rep0 - 1) & _winMask;
+      {
+        const size_t rem = limit - winPos;
+        // size_t rem = _winSize - winPos;
+
+        if (lenCur > rem)
+        {
+          lenCur = (UInt32)rem;
+          remLen = len - lenCur;
+        }
+      }
+      
+      Byte *win = _window;
+      _lzSize += lenCur;
+      _winPos = winPos + lenCur;
+      if (_winSize - pos >= lenCur)
+      {
+        const Byte *src = win + pos;
+        Byte *dest = win + winPos;
+        do
+          *dest++ = *src++;
+        while (--lenCur != 0);
+      }
+      else
+      {
+        do
+        {
+          win[winPos] = win[pos];
+          winPos++;
+          pos = (pos + 1) & _winMask;
+        }
+        while (--lenCur != 0);
+      }
+    }
+  }
+  
+  if (_bitStream._hres != S_OK)
+    return _bitStream._hres;
+
+  return S_FALSE;
+}
+
+
+HRESULT CDecoder::CodeReal()
+{
+  _unsupportedFilter = false;
+  _lzError = false;
+  _writeError = false;
+
+  if (!_isSolid || !_wasInit)
+  {
+    size_t clearSize = _winSize;
+    if (_lzSize < _winSize)
+      clearSize = (size_t)_lzSize;
+    memset(_window, 0, clearSize);
+
+    _wasInit = true;
+    _lzSize = 0;
+    _lzWritten = 0;
+    _winPos = 0;
+    
+    for (unsigned i = 0; i < kNumReps; i++)
+      _reps[i] = (UInt32)0 - 1;
+
+    _lastLen = 0;
+    _tableWasFilled = false;
+  }
+
+  _isLastBlock = false;
+
+  InitFilters();
+
+  _filterEnd = 0;
+  _writtenFileSize = 0;
+
+  _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;
+}
+
+
+// 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 (1 << 18) for "extra safety and possible filter area size expansion"
+// We can use any win size.
+
+static const unsigned kWinSize_Log_Min = 17;
+
+Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+    const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress))
+{
+  try
+  {
+    if (_isSolid && !_solidAllowed)
+      return S_FALSE;
+    _solidAllowed = false;
+
+    if (_dictSizeLog >= sizeof(size_t) * 8)
+      return E_NOTIMPL;
+
+    if (!_isSolid)
+      _lzEnd = 0;
+    else
+    {
+      if (_lzSize < _lzEnd)
+      {
+        if (_window)
+        {
+          UInt64 rem = _lzEnd - _lzSize;
+          if (rem >= _winSize)
+            memset(_window, 0, _winSize);
+          else
+          {
+            const size_t pos = (size_t)_lzSize & _winSize;
+            size_t rem2 = _winSize - pos;
+            if (rem2 > rem)
+              rem2 = (size_t)rem;
+            memset(_window + pos, 0, rem2);
+            rem -= rem2;
+            memset(_window, 0, (size_t)rem);
+          }
+        }
+        _lzEnd &= ((((UInt64)1) << 33) - 1);
+        _lzSize = _lzEnd;
+        _winPos = (size_t)(_lzSize & _winSize);
+      }
+      _lzEnd = _lzSize;
+    }
+
+    size_t newSize;
+    {
+      unsigned newSizeLog = _dictSizeLog;
+      if (newSizeLog < kWinSize_Log_Min)
+        newSizeLog = kWinSize_Log_Min;
+      newSize = (size_t)1 << newSizeLog;
+      _numCorrectDistSymbols = newSizeLog * 2;
+    }
+
+    // If dictionary was reduced, we use allocated dictionary block
+    // for compatibility with original unRAR decoder.
+
+    if (_window && newSize < _winSizeAllocated)
+      _winSize = _winSizeAllocated;
+    else if (!_window || _winSize != newSize)
+    {
+      if (!_isSolid)
+      {
+        ::MidFree(_window);
+        _window = NULL;
+        _winSizeAllocated = 0;
+      }
+
+      Byte *win;
+
+      {
+        win = (Byte *)::MidAlloc(newSize);
+        if (!win)
+          return E_OUTOFMEMORY;
+        memset(win, 0, newSize);
+      }
+      
+      if (_isSolid && _window)
+      {
+        // original unRAR claims:
+        // "Archiving code guarantees that win size does not grow in the same solid stream",
+        // but the original unRAR decoder still supports such grow case.
+        
+        Byte *winOld = _window;
+        const size_t oldSize = _winSize;
+        const size_t newMask = newSize - 1;
+        const size_t oldMask = _winSize - 1;
+        const size_t winPos = _winPos;
+        for (size_t i = 1; i <= oldSize; i++)
+          win[(winPos - i) & newMask] = winOld[(winPos - i) & oldMask];
+        ::MidFree(_window);
+      }
+      
+      _window = win;
+      _winSizeAllocated = newSize;
+      _winSize = newSize;
+    }
+
+    _winMask = _winSize - 1;
+    _winPos &= _winMask;
+
+    if (!_inputBuf)
+    {
+      _inputBuf = (Byte *)::MidAlloc(kInputBufSize);
+      if (!_inputBuf)
+        return E_OUTOFMEMORY;
+    }
+
+    _inStream = inStream;
+    _outStream = outStream;
+
+    /*
+    _packSize = 0;
+    _packSize_Defined = (inSize != NULL);
+    if (_packSize_Defined)
+      _packSize = *inSize;
+    */
+    
+    _unpackSize = 0;
+    _unpackSize_Defined = (outSize != NULL);
+    if (_unpackSize_Defined)
+      _unpackSize = *outSize;
+
+    if ((Int64)_unpackSize >= 0)
+      _lzEnd += _unpackSize;
+    else
+      _lzEnd = 0;
+    
+    _progress = progress;
+    
+    const HRESULT res = CodeReal();
+    
+    if (res != S_OK)
+      return res;
+    if (_lzError)
+      return S_FALSE;
+    if (_unsupportedFilter)
+      return E_NOTIMPL;
+    return S_OK;
+  }
+  // catch(const CInBufferException &e)  { return e.ErrorCode; }
+  // catch(...) { return S_FALSE; }
+  catch(...) { return E_OUTOFMEMORY; }
+  // 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 != 2)
+    return E_NOTIMPL;
+  _dictSizeLog = (Byte)((data[0] & 0xF) + 17);
+  _isSolid = ((data[1] & 1) != 0);
+  return S_OK;
+}
+
+}}
diff --git a/CPP/7zip/Compress/Rar5Decoder.h b/CPP/7zip/Compress/Rar5Decoder.h
new file mode 100644
index 0000000..daf05dd
--- /dev/null
+++ b/CPP/7zip/Compress/Rar5Decoder.h
@@ -0,0 +1,299 @@
+// 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 "../../../C/CpuArch.h"
+
+#include "../../Common/MyBuffer2.h"
+#include "../../Common/MyCom.h"
+#include "../../Common/MyException.h"
+#include "../../Common/MyVector.h"
+
+#include "../ICoder.h"
+
+#include "HuffmanDecoder.h"
+
+namespace NCompress {
+namespace NRar5 {
+
+/*
+struct CInBufferException: public CSystemException
+{
+  CInBufferException(HRESULT errorCode): CSystemException(errorCode) {}
+};
+*/
+
+class CBitDecoder
+{
+public:
+  const Byte *_buf;
+  unsigned _bitPos;
+  bool _wasFinished;
+  Byte _blockEndBits7;
+  const Byte *_bufCheck2;
+  const Byte *_bufCheck;
+  Byte *_bufLim;
+  Byte *_bufBase;
+
+  UInt64 _processedSize;
+  UInt64 _blockEnd;
+
+  ISequentialInStream *_stream;
+  HRESULT _hres;
+
+  void SetCheck2()
+  {
+    _bufCheck2 = _bufCheck;
+    if (_bufCheck > _buf)
+    {
+      UInt64 processed = GetProcessedSize_Round();
+      if (_blockEnd < processed)
+        _bufCheck2 = _buf;
+      else
+      {
+        const UInt64 delta = _blockEnd - processed;
+        if ((size_t)(_bufCheck - _buf) > delta)
+          _bufCheck2 = _buf + (size_t)delta;
+      }
+    }
+  }
+
+  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)
+      {}
+  */
+
+  void Init() throw()
+  {
+    _blockEnd = 0;
+    _blockEndBits7 = 0;
+
+    _bitPos = 0;
+    _processedSize = 0;
+    _buf = _bufBase;
+    _bufLim = _bufBase;
+    _bufCheck = _buf;
+    _bufCheck2 = _buf;
+    _wasFinished = false;
+  }
+
+  void Prepare2() throw();
+
+  void Prepare() throw()
+  {
+    if (_buf >= _bufCheck)
+      Prepare2();
+  }
+
+  bool ExtraBitsWereRead() const
+  {
+    return _buf >= _bufLim && (_buf > _bufLim || _bitPos != 0);
+  }
+
+  bool InputEofError() const { return ExtraBitsWereRead(); }
+
+  unsigned GetProcessedBits7() const { return _bitPos; }
+  UInt64 GetProcessedSize_Round() const { return _processedSize + (size_t)(_buf - _bufBase); }
+  UInt64 GetProcessedSize() const { return _processedSize + (size_t)(_buf - _bufBase) + ((_bitPos + 7) >> 3); }
+
+  void AlignToByte()
+  {
+    _buf += (_bitPos + 7) >> 3;
+    _bitPos = 0;
+  }
+
+  Byte ReadByteInAligned()
+  {
+    return *_buf++;
+  }
+
+  UInt32 GetValue(unsigned numBits) const
+  {
+    UInt32 v = ((UInt32)_buf[0] << 16) | ((UInt32)_buf[1] << 8) | (UInt32)_buf[2];
+    v >>= (24 - numBits - _bitPos);
+    return v & ((1 << numBits) - 1);
+  }
+  
+  void MovePos(unsigned numBits)
+  {
+    _bitPos += numBits;
+    _buf += (_bitPos >> 3);
+    _bitPos &= 7;
+  }
+
+  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;
+  }
+
+  UInt32 ReadBits9fix(unsigned numBits)
+  {
+    const Byte *buf = _buf;
+    UInt32 v = ((UInt32)buf[0] << 8) | (UInt32)buf[1];
+    const UInt32 mask = ((1 << numBits) - 1);
+    numBits += _bitPos;
+    v >>= (16 - numBits);
+    _buf = buf + (numBits >> 3);
+    _bitPos = numBits & 7;
+    return v & mask;
+  }
+
+  UInt32 ReadBits32(unsigned numBits)
+  {
+    const UInt32 mask = ((1 << numBits) - 1);
+    numBits += _bitPos;
+    const Byte *buf = _buf;
+    UInt32 v = GetBe32(buf);
+    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;
+  }
+};
+
+
+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 kDistTableSize = 64;
+const unsigned kNumAlignBits = 4;
+const unsigned kAlignTableSize = (1 << kNumAlignBits);
+const unsigned kLevelTableSize = 20;
+const unsigned kTablesSizesSum = kMainTableSize + kDistTableSize + kAlignTableSize + kLenTableSize;
+
+const unsigned kNumHuffmanBits = 15;
+
+Z7_CLASS_IMP_NOQIB_2(
+  CDecoder
+  , ICompressCoder
+  , ICompressSetDecoderProperties2
+)
+  bool _useAlignBits;
+  bool _isLastBlock;
+  bool _unpackSize_Defined;
+  // bool _packSize_Defined;
+  
+  bool _unsupportedFilter;
+  bool _lzError;
+  bool _writeError;
+
+  bool _isSolid;
+  bool _solidAllowed;
+  bool _tableWasFilled;
+  bool _wasInit;
+
+  Byte _dictSizeLog;
+  
+  // CBitDecoder _bitStream;
+  Byte *_window;
+  size_t _winPos;
+  size_t _winSize;
+  size_t _winMask;
+
+  UInt64 _lzSize;
+
+  unsigned _numCorrectDistSymbols;
+  unsigned _numUnusedFilters;
+
+  UInt64 _lzWritten;
+  UInt64 _lzFileStart;
+  UInt64 _unpackSize;
+  // UInt64 _packSize;
+  UInt64 _lzEnd;
+  UInt64 _writtenFileSize;
+  size_t _winSizeAllocated;
+
+  UInt32 _reps[kNumReps];
+  UInt32 _lastLen;
+  
+  UInt64 _filterEnd;
+  CMidBuffer _filterSrc;
+  CMidBuffer _filterDst;
+
+  CRecordVector<CFilter> _filters;
+
+  ISequentialInStream *_inStream;
+  ISequentialOutStream *_outStream;
+  ICompressProgressInfo *_progress;
+  Byte *_inputBuf;
+
+  NHuffman::CDecoder<kNumHuffmanBits, kMainTableSize> m_MainDecoder;
+  NHuffman::CDecoder<kNumHuffmanBits, kDistTableSize> m_DistDecoder;
+  NHuffman::CDecoder<kNumHuffmanBits, kAlignTableSize> m_AlignDecoder;
+  NHuffman::CDecoder<kNumHuffmanBits, kLenTableSize> m_LenDecoder;
+  NHuffman::CDecoder<kNumHuffmanBits, kLevelTableSize> m_LevelDecoder;
+
+
+  void InitFilters()
+  {
+    _numUnusedFilters = 0;
+    _filters.Clear();
+  }
+
+  void DeleteUnusedFilters()
+  {
+    if (_numUnusedFilters != 0)
+    {
+      _filters.DeleteFrontal(_numUnusedFilters);
+      _numUnusedFilters = 0;
+    }
+  }
+
+  HRESULT WriteData(const Byte *data, size_t size);
+  HRESULT ExecuteFilter(const CFilter &f);
+  HRESULT WriteBuf();
+  HRESULT AddFilter(CBitDecoder &_bitStream);
+
+  HRESULT ReadTables(CBitDecoder &_bitStream);
+  HRESULT DecodeLZ();
+  HRESULT CodeReal();
+  
+public:
+  CDecoder();
+  ~CDecoder();
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Compress/RarCodecsRegister.cpp b/CPP/7zip/Compress/RarCodecsRegister.cpp
new file mode 100644
index 0000000..e1bc3d9
--- /dev/null
+++ b/CPP/7zip/Compress/RarCodecsRegister.cpp
@@ -0,0 +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)
+
+}
diff --git a/CPP/7zip/Compress/ShrinkDecoder.cpp b/CPP/7zip/Compress/ShrinkDecoder.cpp
new file mode 100644
index 0000000..c8e2083
--- /dev/null
+++ b/CPP/7zip/Compress/ShrinkDecoder.cpp
@@ -0,0 +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<CInBuffer> 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
new file mode 100644
index 0000000..5e7f78f
--- /dev/null
+++ b/CPP/7zip/Compress/ShrinkDecoder.h
@@ -0,0 +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
diff --git a/CPP/7zip/Compress/StdAfx.h b/CPP/7zip/Compress/StdAfx.h
index 42a088f..8086655 100644
--- a/CPP/7zip/Compress/StdAfx.h
+++ b/CPP/7zip/Compress/StdAfx.h
@@ -1,8 +1,11 @@
-// StdAfx.h

-

-#ifndef __STDAFX_H

-#define __STDAFX_H

-

-#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
new file mode 100644
index 0000000..8816a12
--- /dev/null
+++ b/CPP/7zip/Compress/XpressDecoder.cpp
@@ -0,0 +1,131 @@
+// XpressDecoder.cpp
+
+#include "StdAfx.h"
+
+// #include <stdio.h>
+
+#include "../../../C/CpuArch.h"
+
+#include "HuffmanDecoder.h"
+#include "XpressDecoder.h"
+
+namespace NCompress {
+namespace NXpress {
+
+struct CBitStream
+{
+  UInt32 Value;
+  unsigned BitPos;
+
+  UInt32 GetValue(unsigned numBits) const
+  {
+    return (Value >> (BitPos - numBits)) & ((1 << numBits) - 1);
+  }
+  
+  void MovePos(unsigned numBits)
+  {
+    BitPos -= numBits;
+  }
+};
+
+#define BIT_STREAM_NORMALIZE \
+    if (bs.BitPos < 16) { \
+      if (in >= lim) return S_FALSE; \
+      bs.Value = (bs.Value << 16) | GetUi16(in); \
+      in += 2; bs.BitPos += 16; }
+ 
+static const unsigned kNumHuffBits = 15;
+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(const Byte *in, size_t inSize, Byte *out, size_t outSize)
+{
+  NCompress::NHuffman::CDecoder<kNumHuffBits, kNumSyms> huff;
+  
+  if (inSize < kNumSyms / 2 + 4)
+    return S_FALSE;
+  {
+    Byte levels[kNumSyms];
+    for (unsigned i = 0; i < kNumSyms / 2; i++)
+    {
+      const Byte b = in[i];
+      levels[(size_t)i * 2] = (Byte)(b & 0xF);
+      levels[(size_t)i * 2 + 1] = (Byte)(b >> 4);
+    }
+    if (!huff.BuildFull(levels))
+      return S_FALSE;
+  }
+
+
+  CBitStream bs;
+
+  const Byte *lim = in + inSize - 1;
+
+  in += kNumSyms / 2;
+  bs.Value = ((UInt32)GetUi16(in) << 16) | GetUi16(in + 2);
+  in += 4;
+  bs.BitPos = 32;
+
+  size_t pos = 0;
+
+  for (;;)
+  {
+    // printf("\n%d", pos);
+    UInt32 sym = huff.DecodeFull(&bs);
+    // printf(" sym = %d", sym);
+    BIT_STREAM_NORMALIZE
+
+    if (pos >= outSize)
+      return (sym == 256 && in == lim + 1) ? S_OK : S_FALSE;
+
+    if (sym < 256)
+      out[pos++] = (Byte)sym;
+    else
+    {
+      sym -= 256;
+      UInt32 dist = sym >> kNumLenBits;
+      UInt32 len = sym & kLenMask;
+      
+      if (len == kLenMask)
+      {
+        if (in > lim)
+          return S_FALSE;
+        len = *in++;
+        if (len == 0xFF)
+        {
+          if (in >= lim)
+            return S_FALSE;
+          len = GetUi16(in);
+          in += 2;
+        }
+        else
+          len += kLenMask;
+      }
+
+      bs.BitPos -= dist;
+      dist = (UInt32)1 << dist;
+      dist += ((bs.Value >> bs.BitPos) & (dist - 1));
+
+      BIT_STREAM_NORMALIZE
+      
+      if (len + 3 > outSize - pos)
+        return S_FALSE;
+      if (dist > pos)
+        return S_FALSE;
+
+      Byte *dest = out + pos;
+      const Byte *src = dest - dist;
+      pos += len + 3;
+      len += 1;
+      *dest++ = *src++;
+      *dest++ = *src++;
+      do
+        *dest++ = *src++;
+      while (--len);
+    }
+  }
+}
+
+}}
diff --git a/CPP/7zip/Compress/XpressDecoder.h b/CPP/7zip/Compress/XpressDecoder.h
new file mode 100644
index 0000000..aaa5b25
--- /dev/null
+++ b/CPP/7zip/Compress/XpressDecoder.h
@@ -0,0 +1,15 @@
+// XpressDecoder.h
+
+#ifndef ZIP7_INC_XPRESS_DECODER_H
+#define ZIP7_INC_XPRESS_DECODER_H
+
+#include "../../Common/MyWindows.h"
+
+namespace NCompress {
+namespace NXpress {
+
+HRESULT Decode(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 4fcd09f..420bd71 100644
--- a/CPP/7zip/Compress/XzDecoder.cpp
+++ b/CPP/7zip/Compress/XzDecoder.cpp
@@ -1,150 +1,150 @@
-// 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;

-  }

-  return S_FALSE;

-}

-

-

-HRESULT CDecoder::Decode(ISequentialInStream *seqInStream, ISequentialOutStream *outStream,

-    const UInt64 *outSizeLimit, bool finishStream, ICompressProgressInfo *progress)

-{

-  MainDecodeSRes = S_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 _7ZIP_ST

-  {

-    props.numThreads = 1;

-    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 _7ZIP_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;

-

-  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);

-}

-

-

-HRESULT CComDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,

-    const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)

-{

-  return Decode(inStream, outStream, outSize, _finishStream, progress);

-}

-

-STDMETHODIMP CComDecoder::SetFinishMode(UInt32 finishMode)

-{

-  _finishStream = (finishMode != 0);

-  return S_OK;

-}

-

-STDMETHODIMP CComDecoder::GetInStreamProcessedSize(UInt64 *value)

-{

-  *value = Stat.InSize;

-  return S_OK;

-}

-

-#ifndef _7ZIP_ST

-

-STDMETHODIMP CComDecoder::SetNumberOfThreads(UInt32 numThreads)

-{

-  _numThreads = numThreads;

-  return S_OK;

-}

-

-STDMETHODIMP 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;
+  }
+  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 76694ee..40ed4f5 100644
--- a/CPP/7zip/Compress/XzDecoder.h
+++ b/CPP/7zip/Compress/XzDecoder.h
@@ -1,92 +1,86 @@
-// XzDecoder.h

-

-#ifndef __XZ_DECODER_H

-#define __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 ERROR code only if there is progress or stream error.

-     Decode() returns S_OK in case of xz decoding error, but DecodeRes and CStatInfo contain error information */

-  HRESULT Decode(ISequentialInStream *seqInStream, ISequentialOutStream *outStream,

-      const UInt64 *outSizeLimit, bool finishStream, ICompressProgressInfo *compressProgress);

-};

-

-

-class CComDecoder:

-  public ICompressCoder,

-  public ICompressSetFinishMode,

-  public ICompressGetInStreamProcessedSize,

-

-  #ifndef _7ZIP_ST

-  public ICompressSetCoderMt,

-  public ICompressSetMemLimit,

-  #endif

-

-  public CMyUnknownImp,

-  public CDecoder

-{

-  bool _finishStream;

-

-public:

-  MY_QUERYINTERFACE_BEGIN2(ICompressCoder)

-

-  MY_QUERYINTERFACE_ENTRY(ICompressSetFinishMode)

-  MY_QUERYINTERFACE_ENTRY(ICompressGetInStreamProcessedSize)

-

-  #ifndef _7ZIP_ST

-  MY_QUERYINTERFACE_ENTRY(ICompressSetCoderMt)

-  MY_QUERYINTERFACE_ENTRY(ICompressSetMemLimit)

-  #endif

-  

-  MY_QUERYINTERFACE_END

-  MY_ADDREF_RELEASE

-

-  STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,

-      const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);

-  STDMETHOD(SetFinishMode)(UInt32 finishMode);

-  STDMETHOD(GetInStreamProcessedSize)(UInt64 *value);

-

-  #ifndef _7ZIP_ST

-  STDMETHOD(SetNumberOfThreads)(UInt32 numThreads);

-  STDMETHOD(SetMemLimit)(UInt64 memUsage);

-  #endif

-

-  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 458a928..33f0bde 100644
--- a/CPP/7zip/Compress/XzEncoder.cpp
+++ b/CPP/7zip/Compress/XzEncoder.cpp
@@ -1,245 +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 < 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)

-    {

-      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

-        {

-          int filterId = FilterIdFromName(prop.bstrVal);

-          if (filterId < 0 /* || filterId == XZ_ID_LZMA2 */)

-            return E_INVALIDARG;

-          id32 = filterId;

-        }

-      }

-      

-      if (id32 == XZ_ID_Delta)

-      {

-        wchar_t c = *name;

-        if (c != '-' && c != ':')

-          return E_INVALIDARG;

-        name++;

-        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);

-}

-

-

-STDMETHODIMP 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));

-}

-

-

-STDMETHODIMP CEncoder::SetCoderPropertiesOpt(const PROPID *propIDs,

-    const PROPVARIANT *coderProps, UInt32 numProps)

-{

-  for (UInt32 i = 0; i < numProps; i++)

-  {

-    const PROPVARIANT &prop = coderProps[i];

-    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;

-

-STDMETHODIMP 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 = (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 79d81f7..434f582 100644
--- a/CPP/7zip/Compress/XzEncoder.h
+++ b/CPP/7zip/Compress/XzEncoder.h
@@ -1,46 +1,35 @@
-// XzEncoder.h

-

-#ifndef __XZ_ENCODER_H

-#define __XZ_ENCODER_H

-

-#include "../../../C/XzEnc.h"

-

-#include "../../Common/MyCom.h"

-

-#include "../ICoder.h"

-

-namespace NCompress {

-namespace NXz {

-

-

-class CEncoder:

-  public ICompressCoder,

-  public ICompressSetCoderProperties,

-  public ICompressSetCoderPropertiesOpt,

-  public CMyUnknownImp

-{

-  CXzEncHandle _encoder;

-public:

-  CXzProps xzProps;

-

-  MY_UNKNOWN_IMP3(

-      ICompressCoder,

-      ICompressSetCoderProperties,

-      ICompressSetCoderPropertiesOpt)

-

-  void InitCoderProps();

-  HRESULT SetCheckSize(UInt32 checkSizeInBytes);

-  HRESULT SetCoderProp(PROPID propID, const PROPVARIANT &prop);

-  

-  STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,

-      const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);

-  STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);

-  STDMETHOD(SetCoderPropertiesOpt)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);

-

-  CEncoder();

-  virtual ~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
new file mode 100644
index 0000000..07c5fe5
--- /dev/null
+++ b/CPP/7zip/Compress/ZDecoder.cpp
@@ -0,0 +1,237 @@
+// ZDecoder.cpp
+
+#include "StdAfx.h"
+
+// #include <stdio.h>
+
+#include "../../../C/Alloc.h"
+
+#include "../Common/InBuffer.h"
+#include "../Common/OutBuffer.h"
+
+#include "ZDecoder.h"
+
+namespace NCompress {
+namespace NZ {
+
+static const UInt32 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::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+    const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
+{
+  CInBuffer inBuffer;
+  COutBuffer outBuffer;
+
+  PackSize = 0;
+  
+  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;
+  }
+  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 = 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 &= (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;
+}
+
+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(...) { 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 = 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 &= (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
new file mode 100644
index 0000000..390b013
--- /dev/null
+++ b/CPP/7zip/Compress/ZDecoder.h
@@ -0,0 +1,49 @@
+// 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.
+  
+Z7_CLASS_IMP_COM_1(
+  CDecoder
+  , ICompressCoder
+)
+  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 CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+      const UInt64 *inSize, const UInt64 *outSize, 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
new file mode 100644
index 0000000..a066932
--- /dev/null
+++ b/CPP/7zip/Compress/ZlibDecoder.cpp
@@ -0,0 +1,95 @@
+// 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 *buf, size_t size);
+UInt32 Adler32_Update(UInt32 adler, const Byte *buf, size_t size)
+{
+  UInt32 a = adler & 0xFFFF;
+  UInt32 b = (adler >> 16) & 0xFFFF;
+  while (size > 0)
+  {
+    const unsigned curSize = (size > ADLER_LOOP_MAX) ? ADLER_LOOP_MAX : (unsigned )size;
+    unsigned i;
+    for (i = 0; i < curSize; i++)
+    {
+      a += buf[i];
+      b += a;
+    }
+    buf += curSize;
+    size -= curSize;
+    a %= ADLER_MOD;
+    b %= ADLER_MOD;
+  }
+  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
+  if (!AdlerStream)
+    AdlerStream = AdlerSpec = new COutStreamWithAdler;
+  if (!DeflateDecoder)
+  {
+    DeflateDecoderSpec = new NDeflate::NDecoder::CCOMCoder;
+    DeflateDecoderSpec->ZlibMode = true;
+    DeflateDecoder = DeflateDecoderSpec;
+  }
+
+  if (inSize && *inSize < 2)
+    return S_FALSE;
+  Byte buf[2];
+  RINOK(ReadStream_FALSE(inStream, buf, 2))
+  if (!IsZlib(buf))
+    return S_FALSE;
+
+  AdlerSpec->SetStream(outStream);
+  AdlerSpec->Init();
+  
+  UInt64 inSize2 = 0;
+  if (inSize)
+    inSize2 = *inSize - 2;
+
+  const HRESULT res = DeflateDecoder->Code(inStream, AdlerStream, inSize ? &inSize2 : NULL, outSize, progress);
+  AdlerSpec->ReleaseStream();
+
+  if (res == S_OK)
+  {
+    const Byte *p = DeflateDecoderSpec->ZlibFooter;
+    const UInt32 adler = GetBe32(p);
+    if (adler != AdlerSpec->GetAdler())
+      return S_FALSE;
+  }
+  return res;
+  DEFLATE_TRY_END
+}
+
+}}
diff --git a/CPP/7zip/Compress/ZlibDecoder.h b/CPP/7zip/Compress/ZlibDecoder.h
new file mode 100644
index 0000000..1dc5c67
--- /dev/null
+++ b/CPP/7zip/Compress/ZlibDecoder.h
@@ -0,0 +1,71 @@
+// 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
+)
+  CMyComPtr<ISequentialOutStream> _stream;
+  UInt32 _adler;
+  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
+)
+  COutStreamWithAdler *AdlerSpec;
+  CMyComPtr<ISequentialOutStream> AdlerStream;
+  NCompress::NDeflate::NDecoder::CCOMCoder *DeflateDecoderSpec;
+  CMyComPtr<ICompressCoder> DeflateDecoder;
+public:
+  UInt64 GetInputProcessedSize() const { return DeflateDecoderSpec->GetInputProcessedSize() + 2; }
+  UInt64 GetOutputProcessedSize() const { return AdlerSpec->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
new file mode 100644
index 0000000..3670d30
--- /dev/null
+++ b/CPP/7zip/Compress/ZlibEncoder.cpp
@@ -0,0 +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
+}
+
+}}
diff --git a/CPP/7zip/Compress/ZlibEncoder.h b/CPP/7zip/Compress/ZlibEncoder.h
new file mode 100644
index 0000000..484a307
--- /dev/null
+++ b/CPP/7zip/Compress/ZlibEncoder.h
@@ -0,0 +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<ISequentialInStream> _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<ISequentialInStream> AdlerStream;
+  CMyComPtr<ICompressCoder> DeflateEncoder;
+public:
+  NCompress::NDeflate::NEncoder::CCOMCoder *DeflateEncoderSpec;
+  
+  void Create();
+  UInt64 GetInputProcessedSize() const { return AdlerSpec->GetSize(); }
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Compress/makefile b/CPP/7zip/Compress/makefile
new file mode 100644
index 0000000..e981319
--- /dev/null
+++ b/CPP/7zip/Compress/makefile
@@ -0,0 +1,7 @@
+DIRS = \
+  LZMA_Alone\~ \
+  
+all: $(DIRS)
+
+$(DIRS):
+!include "../SubBuild.mak"
diff --git a/CPP/7zip/Crc.mak b/CPP/7zip/Crc.mak
index 66b35c1..815142d 100644
--- a/CPP/7zip/Crc.mak
+++ b/CPP/7zip/Crc.mak
@@ -1,8 +1,8 @@
-C_OBJS = $(C_OBJS) \

-  $O\7zCrc.obj

-!IF "$(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 "$(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 6df9b40..d58a483 100644
--- a/CPP/7zip/Crc64.mak
+++ b/CPP/7zip/Crc64.mak
@@ -1,8 +1,8 @@
-C_OBJS = $(C_OBJS) \

-  $O\XzCrc64.obj

-!IF "$(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 "$(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 55e40f3..6b1c648 100644
--- a/CPP/7zip/Crypto/7zAes.cpp
+++ b/CPP/7zip/Crypto/7zAes.cpp
@@ -1,280 +1,317 @@
-// 7zAes.cpp

-

-#include "StdAfx.h"

-

-#include "../../../C/Sha256.h"

-

-#include "../../Common/ComTry.h"

-

-#ifndef _7ZIP_ST

-#include "../../Windows/Synchronization.h"

-#endif

-

-#include "../Common/StreamUtils.h"

-

-#include "7zAes.h"

-#include "MyAes.h"

-

-#ifndef 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

-  {

-    size_t bufSize = 8 + SaltSize + Password.Size();

-    CObjArray<Byte> buf(bufSize);

-    memcpy(buf, Salt, SaltSize);

-    memcpy(buf + SaltSize, Password, Password.Size());

-    

-    CSha256 sha;

-    Sha256_Init(&sha);

-    

-    Byte *ctr = buf + SaltSize + Password.Size();

-    

-    for (unsigned i = 0; i < 8; i++)

-      ctr[i] = 0;

-    

-    UInt64 numRounds = (UInt64)1 << NumCyclesPower;

-

-    do

-    {

-      Sha256_Update(&sha, buf, bufSize);

-      for (unsigned i = 0; i < 8; i++)

-        if (++(ctr[i]) != 0)

-          break;

-    }

-    while (--numRounds != 0);

-

-    Sha256_Final(&sha, Key);

-  }

-}

-

-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 _7ZIP_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 EXTRACT_ONLY

-

-/*

-STDMETHODIMP CEncoder::ResetSalt()

-{

-  _key.SaltSize = 4;

-  g_RandomGenerator.Generate(_key.Salt, _key.SaltSize);

-  return S_OK;

-}

-*/

-

-STDMETHODIMP CEncoder::ResetInitVector()

-{

-  for (unsigned i = 0; i < sizeof(_iv); i++)

-    _iv[i] = 0;

-  _ivSize = 16;

-  MY_RAND_GEN(_iv, _ivSize);

-  return S_OK;

-}

-

-STDMETHODIMP 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);

-}

-

-STDMETHODIMP 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;

-  

-  Byte b0 = data[0];

-

-  _key.NumCyclesPower = b0 & 0x3F;

-  if ((b0 & 0xC0) == 0)

-    return size == 1 ? S_OK : E_INVALIDARG;

-

-  if (size <= 1)

-    return E_INVALIDARG;

-

-  Byte b1 = data[1];

-

-  unsigned saltSize = ((b0 >> 7) & 1) + (b1 >> 4);

-  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;

-}

-

-

-STDMETHODIMP CBaseCoder::CryptoSetPassword(const Byte *data, UInt32 size)

-{

-  COM_TRY_BEGIN

-  

-  _key.Password.CopyFrom(data, (size_t)size);

-  return S_OK;

-  

-  COM_TRY_END

-}

-

-STDMETHODIMP CBaseCoder::Init()

-{

-  COM_TRY_BEGIN

-  

-  PrepareKey();

-  CMyComPtr<ICryptoProperties> 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

-}

-

-STDMETHODIMP_(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;
+    CAlignedBuffer sha(sizeof(CSha256) + unrollSize + bufSize * 2);
+    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, sha.Size());
+  }
+}
+
+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;
+  
+  Byte b0 = data[0];
+
+  _key.NumCyclesPower = b0 & 0x3F;
+  if ((b0 & 0xC0) == 0)
+    return size == 1 ? S_OK : E_INVALIDARG;
+
+  if (size <= 1)
+    return E_INVALIDARG;
+
+  Byte b1 = data[1];
+
+  unsigned saltSize = ((b0 >> 7) & 1) + (b1 >> 4);
+  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<ICryptoProperties> 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 5a09436..8f7bf03 100644
--- a/CPP/7zip/Crypto/7zAes.h
+++ b/CPP/7zip/Crypto/7zAes.h
@@ -1,118 +1,130 @@
-// 7zAes.h

-

-#ifndef __CRYPTO_7Z_AES_H

-#define __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;

-  }

-};

-

-class CKeyInfoCache

-{

-  unsigned Size;

-  CObjectVector<CKeyInfo> 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

-{

-protected:

-  CMyComPtr<ICompressFilter> _aesFilter;

-

-public:

-  INTERFACE_ICompressFilter(;)

-  

-  STDMETHOD(CryptoSetPassword)(const Byte *data, UInt32 size);

-};

-

-#ifndef EXTRACT_ONLY

-

-class CEncoder:

-  public CBaseCoder,

-  public ICompressWriteCoderProperties,

-  // public ICryptoResetSalt,

-  public ICryptoResetInitVector

-{

-public:

-  MY_UNKNOWN_IMP4(

-      ICompressFilter,

-      ICryptoSetPassword,

-      ICompressWriteCoderProperties,

-      // ICryptoResetSalt,

-      ICryptoResetInitVector)

-  STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStream);

-  // STDMETHOD(ResetSalt)();

-  STDMETHOD(ResetInitVector)();

-  CEncoder();

-};

-

-#endif

-

-class CDecoder:

-  public CBaseCoder,

-  public ICompressSetDecoderProperties2

-{

-public:

-  MY_UNKNOWN_IMP3(

-      ICompressFilter,

-      ICryptoSetPassword,

-      ICompressSetDecoderProperties2)

-  STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);

-  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<CKeyInfo> 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<ICompressFilter> _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 c0b2060..69d0890 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(7zAES,

-    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
new file mode 100644
index 0000000..ebf73a3
--- /dev/null
+++ b/CPP/7zip/Crypto/Codec.def
@@ -0,0 +1,4 @@
+EXPORTS
+  CreateObject PRIVATE
+  GetNumberOfMethods PRIVATE
+  GetMethodProperty PRIVATE
diff --git a/CPP/7zip/Crypto/HmacSha1.cpp b/CPP/7zip/Crypto/HmacSha1.cpp
new file mode 100644
index 0000000..30b1a8f
--- /dev/null
+++ b/CPP/7zip/Crypto/HmacSha1.cpp
@@ -0,0 +1,94 @@
+// HmacSha1.cpp
+
+#include "StdAfx.h"
+
+#include <string.h>
+
+#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
new file mode 100644
index 0000000..a36c78e
--- /dev/null
+++ b/CPP/7zip/Crypto/HmacSha1.h
@@ -0,0 +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
diff --git a/CPP/7zip/Crypto/HmacSha256.cpp b/CPP/7zip/Crypto/HmacSha256.cpp
new file mode 100644
index 0000000..56f8ede
--- /dev/null
+++ b/CPP/7zip/Crypto/HmacSha256.cpp
@@ -0,0 +1,53 @@
+// HmacSha256.cpp
+
+#include "StdAfx.h"
+
+#include <string.h>
+
+#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
new file mode 100644
index 0000000..4039c0c
--- /dev/null
+++ b/CPP/7zip/Crypto/HmacSha256.h
@@ -0,0 +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
diff --git a/CPP/7zip/Crypto/MyAes.cpp b/CPP/7zip/Crypto/MyAes.cpp
index 1d399d7..6abc388 100644
--- a/CPP/7zip/Crypto/MyAes.cpp
+++ b/CPP/7zip/Crypto/MyAes.cpp
@@ -1,112 +1,246 @@
-// Crypto/MyAes.cpp

-

-#include "StdAfx.h"

-

-#include "../../../C/CpuArch.h"

-

-#include "MyAes.h"

-

-namespace NCrypto {

-

-static struct CAesTabInit { CAesTabInit() { AesGenTables();} } g_AesTabInit;

-

-CAesCbcCoder::CAesCbcCoder(bool encodeMode, unsigned keySize):

-  _keySize(keySize),

-  _keyIsSet(false),

-  _encodeMode(encodeMode)

-{

-  _offset = ((0 - (unsigned)(ptrdiff_t)_aes) & 0xF) / sizeof(UInt32);

-  memset(_iv, 0, AES_BLOCK_SIZE);

-  SetFunctions(0);

-}

-

-STDMETHODIMP CAesCbcCoder::Init()

-{

-  AesCbc_Init(_aes + _offset, _iv);

-  return _keyIsSet ? S_OK : E_FAIL;

-}

-

-STDMETHODIMP_(UInt32) CAesCbcCoder::Filter(Byte *data, UInt32 size)

-{

-  if (!_keyIsSet)

-    return 0;

-  if (size == 0)

-    return 0;

-  if (size < AES_BLOCK_SIZE)

-    return AES_BLOCK_SIZE;

-  size >>= 4;

-  _codeFunc(_aes + _offset, data, size);

-  return size << 4;

-}

-

-STDMETHODIMP CAesCbcCoder::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;

-  AES_SET_KEY_FUNC setKeyFunc = _encodeMode ? Aes_SetKey_Enc : Aes_SetKey_Dec;

-  setKeyFunc(_aes + _offset + 4, data, size);

-  _keyIsSet = true;

-  return S_OK;

-}

-

-STDMETHODIMP CAesCbcCoder::SetInitVector(const Byte *data, UInt32 size)

-{

-  if (size != AES_BLOCK_SIZE)

-    return E_INVALIDARG;

-  memcpy(_iv, data, size);

-  CAesCbcCoder::Init(); // don't call virtual function here !!!

-  return S_OK;

-}

-

-EXTERN_C_BEGIN

-

-void MY_FAST_CALL AesCbc_Encode(UInt32 *ivAes, Byte *data, size_t numBlocks);

-void MY_FAST_CALL AesCbc_Decode(UInt32 *ivAes, Byte *data, size_t numBlocks);

-void MY_FAST_CALL AesCtr_Code(UInt32 *ivAes, Byte *data, size_t numBlocks);

-

-void MY_FAST_CALL AesCbc_Encode_Intel(UInt32 *ivAes, Byte *data, size_t numBlocks);

-void MY_FAST_CALL AesCbc_Decode_Intel(UInt32 *ivAes, Byte *data, size_t numBlocks);

-void MY_FAST_CALL AesCtr_Code_Intel(UInt32 *ivAes, Byte *data, size_t numBlocks);

-

-EXTERN_C_END

-

-bool CAesCbcCoder::SetFunctions(UInt32 algo)

-{

-  _codeFunc = _encodeMode ?

-      g_AesCbc_Encode :

-      g_AesCbc_Decode;

-  if (algo == 1)

-  {

-    _codeFunc = _encodeMode ?

-        AesCbc_Encode:

-        AesCbc_Decode;

-  }

-  if (algo == 2)

-  {

-    #ifdef MY_CPU_X86_OR_AMD64

-    if (g_AesCbc_Encode != AesCbc_Encode_Intel)

-    #endif

-      return false;

-  }

-  return true;

-}

-

-STDMETHODIMP CAesCbcCoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps)

-{

-  for (UInt32 i = 0; i < numProps; i++)

-  {

-    const PROPVARIANT &prop = coderProps[i];

-    if (propIDs[i] == NCoderPropID::kDefaultProp)

-    {

-      if (prop.vt != VT_UI4)

-        return E_INVALIDARG;

-      if (!SetFunctions(prop.ulVal))

-        return E_NOTIMPL;

-    }

-  }

-  return S_OK;

-}

-

-}

+// 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(__clang__)
+    #if (__clang_major__ >= 8) // fix that check
+      #define USE_HW_AES
+    #endif
+  #elif defined(__GNUC__)
+    #if (__GNUC__ >= 6) // fix that check
+      #define USE_HW_AES
+    #endif
+  #elif defined(_MSC_VER)
+    #if _MSC_VER >= 1910
+      #define USE_HW_AES
+    #endif
+  #endif
+#endif
+
+#ifdef 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 8d5ed98..a3c1c27 100644
--- a/CPP/7zip/Crypto/MyAes.h
+++ b/CPP/7zip/Crypto/MyAes.h
@@ -1,57 +1,122 @@
-// Crypto/MyAes.h

-

-#ifndef __CRYPTO_MY_AES_H

-#define __CRYPTO_MY_AES_H

-

-#include "../../../C/Aes.h"

-

-#include "../../Common/MyCom.h"

-

-#include "../ICoder.h"

-

-namespace NCrypto {

-

-class CAesCbcCoder:

-  public ICompressFilter,

-  public ICryptoProperties,

-  public ICompressSetCoderProperties,

-  public CMyUnknownImp

-{

-  AES_CODE_FUNC _codeFunc;

-  unsigned _offset;

-  unsigned _keySize;

-  bool _keyIsSet;

-  bool _encodeMode;

-  UInt32 _aes[AES_NUM_IVMRK_WORDS + 3];

-  Byte _iv[AES_BLOCK_SIZE];

-

-  bool SetFunctions(UInt32 algo);

-

-public:

-  CAesCbcCoder(bool encodeMode, unsigned keySize);

-  

-  virtual ~CAesCbcCoder() {};   // we need virtual destructor for derived classes

-  

-  MY_UNKNOWN_IMP3(ICompressFilter, ICryptoProperties, ICompressSetCoderProperties)

-  

-  INTERFACE_ICompressFilter(;)

-  

-  STDMETHOD(SetKey)(const Byte *data, UInt32 size);

-  STDMETHOD(SetInitVector)(const Byte *data, UInt32 size);

-  

-  STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);

-};

-

-struct CAesCbcEncoder: public CAesCbcCoder

-{

-  CAesCbcEncoder(unsigned keySize = 0): CAesCbcCoder(true, keySize) {}

-};

-

-struct CAesCbcDecoder: public CAesCbcCoder

-{

-  CAesCbcDecoder(unsigned keySize = 0): CAesCbcCoder(false, keySize) {}

-};

-

-}

-

-#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 3427ad6..e2b4f72 100644
--- a/CPP/7zip/Crypto/MyAesReg.cpp
+++ b/CPP/7zip/Crypto/MyAesReg.cpp
@@ -1,16 +1,29 @@
-// MyAesReg.cpp

-

-#include "StdAfx.h"

-

-#include "../Common/RegisterCodec.h"

-

-#include "MyAes.h"

-

-namespace NCrypto {

-

-REGISTER_FILTER_E(AES256CBC,

-    CAesCbcDecoder(32),

-    CAesCbcEncoder(32),

-    0x6F00181, "AES256CBC")

-

-}

+// 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
new file mode 100644
index 0000000..3d9e4c1
--- /dev/null
+++ b/CPP/7zip/Crypto/Pbkdf2HmacSha1.cpp
@@ -0,0 +1,48 @@
+// Pbkdf2HmacSha1.cpp
+
+#include "StdAfx.h"
+
+#include <string.h>
+
+#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
new file mode 100644
index 0000000..89cbe41
--- /dev/null
+++ b/CPP/7zip/Crypto/Pbkdf2HmacSha1.h
@@ -0,0 +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 <stddef.h>
+
+#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 791275f..05a6c06 100644
--- a/CPP/7zip/Crypto/RandGen.cpp
+++ b/CPP/7zip/Crypto/RandGen.cpp
@@ -1,233 +1,241 @@
-// RandGen.cpp

-

-#include "StdAfx.h"

-

-#include "RandGen.h"

-

-#ifndef USE_STATIC_SYSTEM_RAND

-

-#ifndef _7ZIP_ST

-#include "../../Windows/Synchronization.h"

-#endif

-

-

-#ifdef _WIN32

-

-#ifdef _WIN64

-#define USE_STATIC_RtlGenRandom

-#endif

-

-#ifdef USE_STATIC_RtlGenRandom

-

-#include <ntsecapi.h>

-

-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 <unistd.h>

-#include <sys/types.h>

-#include <sys/stat.h>

-#include <fcntl.h>

-#define USE_POSIX_TIME

-#define USE_POSIX_TIME2

-#endif

-

-#ifdef USE_POSIX_TIME

-#include <time.h>

-#ifdef USE_POSIX_TIME2

-#include <sys/time.h>

-#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()

-{

-  CSha256 hash;

-  Sha256_Init(&hash);

-

-  unsigned numIterations = 1000;

-

-  {

-  #ifndef UNDER_CE

-  const unsigned kNumIterations_Small = 100;

-  const unsigned kBufSize = 32;

-  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

-  {

-    HMODULE hModule = ::LoadLibrary(TEXT("Advapi32.dll"));

-    if (hModule)

-    {

-      // SystemFunction036() is real name of RtlGenRandom() function

-      Func_RtlGenRandom my_RtlGenRandom = (Func_RtlGenRandom)GetProcAddress(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

-      {

-        int n = read(f, buf, numBytes);

-        if (n <= 0)

-          break;

-        Sha256_Update(&hash, buf, n);

-        numBytes -= 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, 0) == 0)

-    {

-      HASH_UPD(v.tv_sec);

-      HASH_UPD(v.tv_usec);

-    }

-    #endif

-    time_t v2 = time(NULL);

-    HASH_UPD(v2);

-    #endif

-

-    #ifdef _WIN32

-    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 _7ZIP_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)

-  {

-    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);

-    Byte buff[SHA256_DIGEST_SIZE];

-    Sha256_Final(&hash, buff);

-    for (unsigned i = 0; i < SHA256_DIGEST_SIZE && size != 0; i++, size--)

-      *data++ = buff[i];

-  }

-}

-

-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 <NTSecAPI.h>
+
+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 <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#define USE_POSIX_TIME
+#define USE_POSIX_TIME2
+#endif
+
+#ifdef USE_POSIX_TIME
+#include <time.h>
+#ifdef USE_POSIX_TIME2
+#include <sys/time.h>
+#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 dc5a338..3bd69ec 100644
--- a/CPP/7zip/Crypto/RandGen.h
+++ b/CPP/7zip/Crypto/RandGen.h
@@ -1,40 +1,41 @@
-// RandGen.h

-

-#ifndef __CRYPTO_RAND_GEN_H

-#define __CRYPTO_RAND_GEN_H

-

-#include "../../../C/Sha256.h"

-

-#ifdef _WIN64

-// #define USE_STATIC_SYSTEM_RAND

-#endif

-

-#ifdef USE_STATIC_SYSTEM_RAND

-

-#ifdef _WIN32

-#include <ntsecapi.h>

-#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);

-};

-

-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 <ntsecapi.h>
+#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
new file mode 100644
index 0000000..8e55763
--- /dev/null
+++ b/CPP/7zip/Crypto/Rar20Crypto.cpp
@@ -0,0 +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;
+}
+
+}}
diff --git a/CPP/7zip/Crypto/Rar20Crypto.h b/CPP/7zip/Crypto/Rar20Crypto.h
new file mode 100644
index 0000000..8550718
--- /dev/null
+++ b/CPP/7zip/Crypto/Rar20Crypto.h
@@ -0,0 +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
diff --git a/CPP/7zip/Crypto/Rar5Aes.cpp b/CPP/7zip/Crypto/Rar5Aes.cpp
new file mode 100644
index 0000000..26c6100
--- /dev/null
+++ b/CPP/7zip/Crypto/Rar5Aes.cpp
@@ -0,0 +1,265 @@
+// 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;
+}
+
+}}
diff --git a/CPP/7zip/Crypto/Rar5Aes.h b/CPP/7zip/Crypto/Rar5Aes.h
new file mode 100644
index 0000000..3cd7992
--- /dev/null
+++ b/CPP/7zip/Crypto/Rar5Aes.h
@@ -0,0 +1,98 @@
+// 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
diff --git a/CPP/7zip/Crypto/RarAes.cpp b/CPP/7zip/Crypto/RarAes.cpp
new file mode 100644
index 0000000..878ea3a
--- /dev/null
+++ b/CPP/7zip/Crypto/RarAes.cpp
@@ -0,0 +1,194 @@
+// 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;
+}
+
+}}
diff --git a/CPP/7zip/Crypto/RarAes.h b/CPP/7zip/Crypto/RarAes.h
new file mode 100644
index 0000000..d3c104c
--- /dev/null
+++ b/CPP/7zip/Crypto/RarAes.h
@@ -0,0 +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
diff --git a/CPP/7zip/Crypto/Sha1Cls.h b/CPP/7zip/Crypto/Sha1Cls.h
new file mode 100644
index 0000000..56ae040
--- /dev/null
+++ b/CPP/7zip/Crypto/Sha1Cls.h
@@ -0,0 +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
diff --git a/CPP/7zip/Crypto/StdAfx.h b/CPP/7zip/Crypto/StdAfx.h
index 42a088f..8086655 100644
--- a/CPP/7zip/Crypto/StdAfx.h
+++ b/CPP/7zip/Crypto/StdAfx.h
@@ -1,8 +1,11 @@
-// StdAfx.h

-

-#ifndef __STDAFX_H

-#define __STDAFX_H

-

-#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
new file mode 100644
index 0000000..3f2adab
--- /dev/null
+++ b/CPP/7zip/Crypto/WzAes.cpp
@@ -0,0 +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;
+}
+
+}}
diff --git a/CPP/7zip/Crypto/WzAes.h b/CPP/7zip/Crypto/WzAes.h
new file mode 100644
index 0000000..113ec81
--- /dev/null
+++ b/CPP/7zip/Crypto/WzAes.h
@@ -0,0 +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<ICompressFilter> _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
new file mode 100644
index 0000000..047e2bd
--- /dev/null
+++ b/CPP/7zip/Crypto/ZipCrypto.cpp
@@ -0,0 +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;
+}
+
+}}
diff --git a/CPP/7zip/Crypto/ZipCrypto.h b/CPP/7zip/Crypto/ZipCrypto.h
new file mode 100644
index 0000000..485470e
--- /dev/null
+++ b/CPP/7zip/Crypto/ZipCrypto.h
@@ -0,0 +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
diff --git a/CPP/7zip/Crypto/ZipStrong.cpp b/CPP/7zip/Crypto/ZipStrong.cpp
new file mode 100644
index 0000000..59698d8
--- /dev/null
+++ b/CPP/7zip/Crypto/ZipStrong.cpp
@@ -0,0 +1,264 @@
+// 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;
+}
+
+}}
diff --git a/CPP/7zip/Crypto/ZipStrong.h b/CPP/7zip/Crypto/ZipStrong.h
new file mode 100644
index 0000000..a2b5cdd
--- /dev/null
+++ b/CPP/7zip/Crypto/ZipStrong.h
@@ -0,0 +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<ICompressFilter> _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 565ee70..b67409b 100644
--- a/CPP/7zip/GuiCommon.rc
+++ b/CPP/7zip/GuiCommon.rc
@@ -1,84 +1,84 @@
-#include <windows.h>

-

-// #include <winnt.h>

-// #include <WinUser.h>

-

-// for Windows CE:

-#include <CommCtrl.h>

-

-

-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 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           DIALOG 0, 0, xs, ys  MY_PAGE_STYLE  MY_FONT

-

-#define OK_CANCEL \

-  DEFPUSHBUTTON  "OK",     IDOK,     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 MY_TEXT_NOPREFIX 8, SS_NOPREFIX

+#include <windows.h>
+
+// #include <winnt.h>
+// #include <WinUser.h>
+
+// for Windows CE:
+#include <CommCtrl.h>
+
+
+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 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           DIALOG 0, 0, xs, ys  MY_PAGE_STYLE  MY_FONT
+
+#define OK_CANCEL \
+  DEFPUSHBUTTON  "OK",     IDOK,     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 MY_TEXT_NOPREFIX 8, SS_NOPREFIX
diff --git a/CPP/7zip/Guid.txt b/CPP/7zip/Guid.txt
index e5e0612..eee28f7 100644
--- a/CPP/7zip/Guid.txt
+++ b/CPP/7zip/Guid.txt
@@ -1,220 +1,237 @@
-{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

-  

-  20  IFileExtractCallback.h::IGetProp

-  30  IFileExtractCallback.h::IFolderExtractToStreamCallback

-

-03 IStream.h

-

-  01  ISequentialInStream

-  02  ISequentialOutStream

-  03  IInStream

-  04  IOutStream

-  06  IStreamGetSize

-  07  IOutStreamFinish

-  08  IStreamGetProps

-  09  IStreamGetProps2

-

-

-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

-

-  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

-

-  10  IArchiveOpenCallback

-  

-  20  IArchiveExtractCallback

-  21  IArchiveExtractCallbackMessage

-  

-  30  IArchiveOpenVolumeCallback

-  40  IInArchiveGetStream

-  50  IArchiveOpenSetSubArchiveName

-  60  IInArchive

-  61  IArchiveOpenSeq

-  70  IArchiveGetRawProps

-  71  IArchiveGetRootProps

-

-  80  IArchiveUpdateCallback

-  82  IArchiveUpdateCallback2

-  83  IArchiveUpdateCallbackFile

-

-  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

-

-  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
+  
+  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
+
+  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
+
+  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 54b2476..aec2834 100644
--- a/CPP/7zip/ICoder.h
+++ b/CPP/7zip/ICoder.h
@@ -1,399 +1,477 @@
-// ICoder.h

-

-#ifndef __ICODER_H

-#define __ICODER_H

-

-#include "IStream.h"

-

-#define CODER_INTERFACE(i, x) DECL_INTERFACE(i, 4, x)

-

-CODER_INTERFACE(ICompressProgressInfo, 0x04)

-{

-  STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize) PURE;

-  

-  /* (inSize) can be NULL, if unknown

-     (outSize) can be NULL, if unknown

-

-  returns:

-    S_OK

-    E_ABORT  : Break by user

-    another error codes

-  */

-};

-

-CODER_INTERFACE(ICompressCoder, 0x05)

-{

-  STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,

-      const UInt64 *inSize, const UInt64 *outSize,

-      ICompressProgressInfo *progress) PURE;

-};

-

-CODER_INTERFACE(ICompressCoder2, 0x18)

-{

-  STDMETHOD(Code)(ISequentialInStream * const *inStreams, const UInt64 * const *inSizes, UInt32 numInStreams,

-      ISequentialOutStream * const *outStreams, const UInt64 * const *outSizes, UInt32 numOutStreams,

-      ICompressProgressInfo *progress) PURE;

-};

-

-/*

-  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 decoder 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

-  };

-}

-

-CODER_INTERFACE(ICompressSetCoderPropertiesOpt, 0x1F)

-{

-  STDMETHOD(SetCoderPropertiesOpt)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps) PURE;

-};

-

-CODER_INTERFACE(ICompressSetCoderProperties, 0x20)

-{

-  STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps) PURE;

-};

-

-/*

-CODER_INTERFACE(ICompressSetCoderProperties, 0x21)

-{

-  STDMETHOD(SetDecoderProperties)(ISequentialInStream *inStream) PURE;

-};

-*/

-

-CODER_INTERFACE(ICompressSetDecoderProperties2, 0x22)

-{

-  /* returns:

-    S_OK

-    E_NOTIMP      : unsupported properties

-    E_INVALIDARG  : incorrect (or unsupported) properties

-    E_OUTOFMEMORY : memory allocation error

-  */

-  STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size) PURE;

-};

-

-CODER_INTERFACE(ICompressWriteCoderProperties, 0x23)

-{

-  STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStream) PURE;

-};

-

-CODER_INTERFACE(ICompressGetInStreamProcessedSize, 0x24)

-{

-  STDMETHOD(GetInStreamProcessedSize)(UInt64 *value) PURE;

-};

-

-CODER_INTERFACE(ICompressSetCoderMt, 0x25)

-{

-  STDMETHOD(SetNumberOfThreads)(UInt32 numThreads) PURE;

-};

-

-CODER_INTERFACE(ICompressSetFinishMode, 0x26)

-{

-  STDMETHOD(SetFinishMode)(UInt32 finishMode) PURE;

-

-  /* 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. */

-};

-

-CODER_INTERFACE(ICompressGetInStreamProcessedSize2, 0x27)

-{

-  STDMETHOD(GetInStreamProcessedSize2)(UInt32 streamIndex, UInt64 *value) PURE;

-};

-

-CODER_INTERFACE(ICompressSetMemLimit, 0x28)

-{

-  STDMETHOD(SetMemLimit)(UInt64 memUsage) PURE;

-};

-

-

-

-CODER_INTERFACE(ICompressGetSubStreamSize, 0x30)

-{

-  STDMETHOD(GetSubStreamSize)(UInt64 subStream, UInt64 *value) PURE;

-

-  /* 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++;

-    }

-  */

-};

-

-CODER_INTERFACE(ICompressSetInStream, 0x31)

-{

-  STDMETHOD(SetInStream)(ISequentialInStream *inStream) PURE;

-  STDMETHOD(ReleaseInStream)() PURE;

-};

-

-CODER_INTERFACE(ICompressSetOutStream, 0x32)

-{

-  STDMETHOD(SetOutStream)(ISequentialOutStream *outStream) PURE;

-  STDMETHOD(ReleaseOutStream)() PURE;

-};

-

-/*

-CODER_INTERFACE(ICompressSetInStreamSize, 0x33)

-{

-  STDMETHOD(SetInStreamSize)(const UInt64 *inSize) PURE;

-};

-*/

-

-CODER_INTERFACE(ICompressSetOutStreamSize, 0x34)

-{

-  STDMETHOD(SetOutStreamSize)(const UInt64 *outSize) PURE;

-

-  /* 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. */

-};

-

-CODER_INTERFACE(ICompressSetBufSize, 0x35)

-{

-  STDMETHOD(SetInBufSize)(UInt32 streamIndex, UInt32 size) PURE;

-  STDMETHOD(SetOutBufSize)(UInt32 streamIndex, UInt32 size) PURE;

-};

-

-CODER_INTERFACE(ICompressInitEncoder, 0x36)

-{

-  STDMETHOD(InitEncoder)() PURE;

-

-  /* That function initializes encoder structures.

-     Call this function only for stream version of encoder. */

-};

-

-CODER_INTERFACE(ICompressSetInStream2, 0x37)

-{

-  STDMETHOD(SetInStream2)(UInt32 streamIndex, ISequentialInStream *inStream) PURE;

-  STDMETHOD(ReleaseInStream2)(UInt32 streamIndex) PURE;

-};

-

-/*

-CODER_INTERFACE(ICompressSetOutStream2, 0x38)

-{

-  STDMETHOD(SetOutStream2)(UInt32 streamIndex, ISequentialOutStream *outStream) PURE;

-  STDMETHOD(ReleaseOutStream2)(UInt32 streamIndex) PURE;

-};

-

-CODER_INTERFACE(ICompressSetInStreamSize2, 0x39)

-{

-  STDMETHOD(SetInStreamSize2)(UInt32 streamIndex, const UInt64 *inSize) PURE;

-};

-*/

-

-

-/*

-  ICompressFilter

-  Filter() converts as most as possible bytes

-     returns: (outSize):

-       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 INTERFACE_ICompressFilter(x) \

-  STDMETHOD(Init)() x; \

-  STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size) x; \

-

-CODER_INTERFACE(ICompressFilter, 0x40)

-{

-  INTERFACE_ICompressFilter(PURE);

-};

-

-

-CODER_INTERFACE(ICompressCodecsInfo, 0x60)

-{

-  STDMETHOD(GetNumMethods)(UInt32 *numMethods) PURE;

-  STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value) PURE;

-  STDMETHOD(CreateDecoder)(UInt32 index, const GUID *iid, void **coder) PURE;

-  STDMETHOD(CreateEncoder)(UInt32 index, const GUID *iid, void **coder) PURE;

-};

-

-CODER_INTERFACE(ISetCompressCodecsInfo, 0x61)

-{

-  STDMETHOD(SetCompressCodecsInfo)(ICompressCodecsInfo *compressCodecsInfo) PURE;

-};

-

-CODER_INTERFACE(ICryptoProperties, 0x80)

-{

-  STDMETHOD(SetKey)(const Byte *data, UInt32 size) PURE;

-  STDMETHOD(SetInitVector)(const Byte *data, UInt32 size) PURE;

-};

-

-/*

-CODER_INTERFACE(ICryptoResetSalt, 0x88)

-{

-  STDMETHOD(ResetSalt)() PURE;

-};

-*/

-

-CODER_INTERFACE(ICryptoResetInitVector, 0x8C)

-{

-  STDMETHOD(ResetInitVector)() PURE;

-

-  /* Call ResetInitVector() only for encoding.

-     Call ResetInitVector() before encoding and before WriteCoderProperties().

-     Crypto encoder can create random IV in that function. */

-};

-

-CODER_INTERFACE(ICryptoSetPassword, 0x90)

-{

-  STDMETHOD(CryptoSetPassword)(const Byte *data, UInt32 size) PURE;

-};

-

-CODER_INTERFACE(ICryptoSetCRC, 0xA0)

-{

-  STDMETHOD(CryptoSetCRC)(UInt32 crc) PURE;

-};

-

-

-namespace NMethodPropID

-{

-  enum EEnum

-  {

-    kID,

-    kName,

-    kDecoder,

-    kEncoder,

-    kPackStreams,

-    kUnpackStreams,

-    kDescription,

-    kDecoderIsAssigned,

-    kEncoderIsAssigned,

-    kDigestSize

-  };

-}

-

-

-#define INTERFACE_IHasher(x) \

-  STDMETHOD_(void, Init)() throw() x; \

-  STDMETHOD_(void, Update)(const void *data, UInt32 size) throw() x; \

-  STDMETHOD_(void, Final)(Byte *digest) throw() x; \

-  STDMETHOD_(UInt32, GetDigestSize)() throw() x; \

-

-CODER_INTERFACE(IHasher, 0xC0)

-{

-  INTERFACE_IHasher(PURE)

-};

-

-CODER_INTERFACE(IHashers, 0xC1)

-{

-  STDMETHOD_(UInt32, GetNumHashers)() PURE;

-  STDMETHOD(GetHasherProp)(UInt32 index, PROPID propID, PROPVARIANT *value) PURE;

-  STDMETHOD(CreateHasher)(UInt32 index, IHasher **hasher) PURE;

-};

-

-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);

-}

-

-#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 5a34b0e..c4d4541 100644
--- a/CPP/7zip/IDecl.h
+++ b/CPP/7zip/IDecl.h
@@ -1,28 +1,76 @@
-// IDecl.h

-

-#ifndef __IDECL_H

-#define __IDECL_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 DECL_INTERFACE_SUB(i, base, groupId, subId) \

-  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 i: public base

-

-#define DECL_INTERFACE(i, groupId, subId) DECL_INTERFACE_SUB(i, IUnknown, groupId, subId)

-

-#endif

+// IDecl.h
+
+#ifndef ZIP7_INC_IDECL_H
+#define ZIP7_INC_IDECL_H
+
+#include "../Common/Common.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 e366007..689f08c 100644
--- a/CPP/7zip/IPassword.h
+++ b/CPP/7zip/IPassword.h
@@ -1,23 +1,54 @@
-// IPassword.h

-

-#ifndef __IPASSWORD_H

-#define __IPASSWORD_H

-

-#include "../Common/MyTypes.h"

-#include "../Common/MyUnknown.h"

-

-#include "IDecl.h"

-

-#define PASSWORD_INTERFACE(i, x) DECL_INTERFACE(i, 5, x)

-

-PASSWORD_INTERFACE(ICryptoGetTextPassword, 0x10)

-{

-  STDMETHOD(CryptoGetTextPassword)(BSTR *password) PURE;

-};

-

-PASSWORD_INTERFACE(ICryptoGetTextPassword2, 0x11)

-{

-  STDMETHOD(CryptoGetTextPassword2)(Int32 *passwordIsDefined, BSTR *password) PURE;

-};

-

-#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 d54529c..6714983 100644
--- a/CPP/7zip/IProgress.h
+++ b/CPP/7zip/IProgress.h
@@ -1,19 +1,20 @@
-// IProgress.h

-

-#ifndef __IPROGRESS_H

-#define __IPROGRESS_H

-

-#include "../Common/MyTypes.h"

-

-#include "IDecl.h"

-

-#define INTERFACE_IProgress(x) \

-  STDMETHOD(SetTotal)(UInt64 total) x; \

-  STDMETHOD(SetCompleted)(const UInt64 *completeValue) x; \

-

-DECL_INTERFACE(IProgress, 0, 5)

-{

-  INTERFACE_IProgress(PURE)

-};

-

-#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 436e919..4a58bc9 100644
--- a/CPP/7zip/IStream.h
+++ b/CPP/7zip/IStream.h
@@ -1,127 +1,207 @@
-// IStream.h

-

-#ifndef __ISTREAM_H

-#define __ISTREAM_H

-

-#include "../Common/MyTypes.h"

-#include "../Common/MyWindows.h"

-

-#include "IDecl.h"

-

-#define STREAM_INTERFACE_SUB(i, base, x) DECL_INTERFACE_SUB(i, base, 3, x)

-#define STREAM_INTERFACE(i, x) STREAM_INTERFACE_SUB(i, IUnknown, x)

-

-STREAM_INTERFACE(ISequentialInStream, 0x01)

-{

-  STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize) PURE;

-  

-  /*

-  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().

-  */

-};

-

-STREAM_INTERFACE(ISequentialOutStream, 0x02)

-{

-  STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize) PURE;

-  

-  /*

-  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.

-  */

-};

-

-#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

-

-/*  Seek() Function

-  If you seek 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.

-*/

-

-STREAM_INTERFACE_SUB(IInStream, ISequentialInStream, 0x03)

-{

-  STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) PURE;

-};

-

-STREAM_INTERFACE_SUB(IOutStream, ISequentialOutStream, 0x04)

-{

-  STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) PURE;

-  STDMETHOD(SetSize)(UInt64 newSize) PURE;

-};

-

-STREAM_INTERFACE(IStreamGetSize, 0x06)

-{

-  STDMETHOD(GetSize)(UInt64 *size) PURE;

-};

-

-STREAM_INTERFACE(IOutStreamFinish, 0x07)

-{

-  STDMETHOD(OutStreamFinish)() PURE;

-};

-

-

-STREAM_INTERFACE(IStreamGetProps, 0x08)

-{

-  STDMETHOD(GetProps)(UInt64 *size, FILETIME *cTime, FILETIME *aTime, FILETIME *mTime, UInt32 *attrib) PURE;

-};

-

-struct CStreamFileProps

-{

-  UInt64 Size;

-  UInt64 VolID;

-  UInt64 FileID_Low;

-  UInt64 FileID_High;

-  UInt32 NumLinks;

-  UInt32 Attrib;

-  FILETIME CTime;

-  FILETIME ATime;

-  FILETIME MTime;

-};

-

-STREAM_INTERFACE(IStreamGetProps2, 0x09)

-{

-  STDMETHOD(GetProps2)(CStreamFileProps *props) PURE;

-};

-

-#endif

+// IStream.h
+
+#ifndef ZIP7_INC_ISTREAM_H
+#define ZIP7_INC_ISTREAM_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)
+  to change data 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.
+
+inputs:
+ 
+  (begin > end) is not allowed, and returns E_FAIL;
+  
+  if (begin == end)
+  {
+    it means that there is no region restriction for flushing.
+    The callee is allowed to flush already written data and
+    is allowed to flush all data in future calls of
+    ISequentialOutStream::Write(), but before next call of SetRestriction().
+    The pair of values (begin == 0 && end == 0) is recommended to
+    remove all restrictions.
+  }
+  
+  if (begin < end)
+  {
+    it means that callee must NOT to 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
+    }
+
+    Note: it's not expected that some already written region was marked as
+    non-restricted by old call SetRestriction() and later the part of
+    that region was marked as restricted with new call SetRestriction().
+    For example, for different calls with non-empty restricted regions:
+     (begin_new >= begin_old) is expected :
+     {
+       SetRestriction(begin_old, ...)
+       ...
+       SetRestriction(begin_new, ...)
+     }
+  }
+
+ 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 unrestricted already written region.
+*/
+
+#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
new file mode 100644
index 0000000..169e10f
--- /dev/null
+++ b/CPP/7zip/LzFindOpt.mak
@@ -0,0 +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
diff --git a/CPP/7zip/LzmaDec.mak b/CPP/7zip/LzmaDec.mak
index 9aa3086..3beb505 100644
--- a/CPP/7zip/LzmaDec.mak
+++ b/CPP/7zip/LzmaDec.mak
@@ -1,5 +1,7 @@
-!IF "$(PLATFORM)" == "x64"

-CFLAGS_C_SPEC = -D_LZMA_DEC_OPT

-ASM_OBJS = $(ASM_OBJS) \

-  $O\LzmaDecOpt.obj

-!ENDIF

+!IF "$(PLATFORM)" == "x64"
+!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
new file mode 100644
index 0000000..51924f5
--- /dev/null
+++ b/CPP/7zip/LzmaDec_gcc.mak
@@ -0,0 +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
diff --git a/CPP/7zip/MyVersion.h b/CPP/7zip/MyVersion.h
index 0d50f94..8f52a12 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 eddf893..fc63d79 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 126af67..e074794 100644
--- a/CPP/7zip/PropID.h
+++ b/CPP/7zip/PropID.h
@@ -1,127 +1,178 @@
-// PropID.h

-

-#ifndef __7ZIP_PROP_ID_H

-#define __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,

-

-  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;

-

-#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
new file mode 100644
index 0000000..1b5f605
--- /dev/null
+++ b/CPP/7zip/Sha1.mak
@@ -0,0 +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
diff --git a/CPP/7zip/Sha256.mak b/CPP/7zip/Sha256.mak
new file mode 100644
index 0000000..0bdbcb6
--- /dev/null
+++ b/CPP/7zip/Sha256.mak
@@ -0,0 +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
diff --git a/CPP/7zip/SubBuild.mak b/CPP/7zip/SubBuild.mak
index 0c49d3b..f86ce43 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
new file mode 100644
index 0000000..6761b28
--- /dev/null
+++ b/CPP/7zip/UI/Agent/Agent.cpp
@@ -0,0 +1,1966 @@
+// Agent.cpp
+
+#include "StdAfx.h"
+
+#include <wchar.h>
+
+#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<IUnknown> g_CodecsRef;
+  CMyComPtr<IUnknown> 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<IFolderFolder> 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<IFolderFolder> 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<IFolderFolder> 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<IFolderFolder> 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<IFolderFolder> 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<IFolderFolder> 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<IFolderFolder> 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<IFolderArcProps> 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.Front(), 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<IArchiveExtractCallback> 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())
+    if (!NFile::NName::IsAltStreamPrefixWithColon(pathU))
+    {
+      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.Front(),
+        realIndices.Size(), testMode, extractCallback);
+    
+    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<COpenType> types;
+  if (!ParseOpenTypes(*g_CodecsObj, arcFormat, types))
+    return S_FALSE;
+
+  /*
+  CObjectVector<COptionalOpenProperties> 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<COpenType> 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<IFolderFolder> 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<IArchiveExtractCallback> 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
new file mode 100644
index 0000000..ea81aa8
--- /dev/null
+++ b/CPP/7zip/UI/Agent/Agent.h
@@ -0,0 +1,353 @@
+// 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<IFolderFolder> _parentFolder;
+  CMyComPtr<IInFolderArchive> _agent;
+  CAgent *_agentSpec;
+
+  CRecordVector<CProxyItem> _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<UString> m_PropNames;
+  CObjectVector<NWindows::NCOM::CPropVariant> 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<CIconPair> 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<CCodecIcons> 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
new file mode 100644
index 0000000..b5a25a3
--- /dev/null
+++ b/CPP/7zip/UI/Agent/AgentOut.cpp
@@ -0,0 +1,725 @@
+// 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<CArcItem> &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<CArcItem> &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<CArcItem> *_arcItems;
+  IFolderArchiveUpdateCallback *_callback;
+  
+  CAgUpCallbackImp(const CObjectVector<CArcItem> *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<IFolderScanProgress> 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<IOutArchive> 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<ISetCompressCodecsInfo> 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<CArcItem> 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<CUpdatePair2> updatePairs2;
+
+  {
+    CRecordVector<CUpdatePair> 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);
+  CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback;
+  CMyComPtr<IArchiveUpdateCallback> updateCallback(updateCallbackSpec );
+
+  updateCallbackSpec->DirItems = &dirItems;
+  updateCallbackSpec->ArcItems = &arcItems;
+  updateCallbackSpec->UpdatePairs = &updatePairs2;
+  
+  SetInArchiveInterfaces(this, updateCallbackSpec);
+  
+  updateCallbackSpec->Callback = &updateCallbackAgent;
+
+  CByteBuffer processedItems;
+  if (processedPaths)
+  {
+    unsigned num = dirItems.Items.Size();
+    processedItems.Alloc(num);
+    for (unsigned i = 0; i < num; i++)
+      processedItems[i] = 0;
+    updateCallbackSpec->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<const wchar_t *> 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.Front(), propValues, names.Size()))
+      }
+      catch(...)
+      {
+        delete []propValues;
+        return E_FAIL;
+      }
+      delete []propValues;
+    }
+  }
+  m_PropNames.Clear();
+  m_PropValues.Clear();
+
+  if (sfxModule != NULL)
+  {
+    CInFileStream *sfxStreamSpec = new CInFileStream;
+    CMyComPtr<IInStream> sfxStream(sfxStreamSpec);
+    if (!sfxStreamSpec->Open(us2fs(sfxModule)))
+      return E_FAIL;
+      // throw "Can't open sfx module";
+    RINOK(NCompress::CopyStream(sfxStream, outArchiveStream, NULL))
+  }
+
+  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<IOutArchive> 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<CUpdatePair2> updatePairs;
+  CUpdateCallbackAgent updateCallbackAgent;
+  updateCallbackAgent.SetCallback(updateCallback100);
+  CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback;
+  CMyComPtr<IArchiveUpdateCallback> updateCallback(updateCallbackSpec);
+  
+  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);
+  }
+  updateCallbackSpec->UpdatePairs = &updatePairs;
+
+  SetInArchiveInterfaces(this, updateCallbackSpec);
+
+  updateCallbackSpec->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<CUpdatePair2> updatePairs;
+  CDirItems dirItems;
+  CUpdateCallbackAgent updateCallbackAgent;
+  updateCallbackAgent.SetCallback(updateCallback100);
+  CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback;
+  CMyComPtr<IArchiveUpdateCallback> updateCallback(updateCallbackSpec);
+
+  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);
+
+  updateCallbackSpec->Callback = &updateCallbackAgent;
+  updateCallbackSpec->DirItems = &dirItems;
+  updateCallbackSpec->UpdatePairs = &updatePairs;
+  
+  SetInArchiveInterfaces(this, updateCallbackSpec);
+  
+  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<CUpdatePair2> updatePairs;
+  CUpdateCallbackAgent updateCallbackAgent;
+  updateCallbackAgent.SetCallback(updateCallback100);
+  CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback;
+  CMyComPtr<IArchiveUpdateCallback> updateCallback(updateCallbackSpec);
+  
+  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);
+  }
+  
+  updateCallbackSpec->Callback = &updateCallbackAgent;
+  updateCallbackSpec->UpdatePairs = &updatePairs;
+  updateCallbackSpec->NewNames = &newNames;
+
+  SetInArchiveInterfaces(this, updateCallbackSpec);
+
+  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<CUpdatePair2> updatePairs;
+  CUpdateCallbackAgent updateCallbackAgent;
+  updateCallbackAgent.SetCallback(updateCallback100);
+  CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback;
+  CMyComPtr<IArchiveUpdateCallback> updateCallback(updateCallbackSpec);
+  
+  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);
+  }
+  
+  updateCallbackSpec->Callback = &updateCallbackAgent;
+  updateCallbackSpec->UpdatePairs = &updatePairs;
+  updateCallbackSpec->CommentIndex = mainRealIndex;
+  updateCallbackSpec->Comment = &newName;
+
+  SetInArchiveInterfaces(this, updateCallbackSpec);
+
+  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<CUpdatePair2> updatePairs;
+  CDirItems dirItems;
+  CUpdateCallbackAgent updateCallbackAgent;
+  updateCallbackAgent.SetCallback(updateCallback100);
+  CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback;
+  CMyComPtr<IArchiveUpdateCallback> updateCallback(updateCallbackSpec);
+  
+  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);
+  }
+  updateCallbackSpec->DirItems = &dirItems;
+  updateCallbackSpec->Callback = &updateCallbackAgent;
+  updateCallbackSpec->UpdatePairs = &updatePairs;
+ 
+  SetInArchiveInterfaces(this, updateCallbackSpec);
+  
+  updateCallbackSpec->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
new file mode 100644
index 0000000..df9f315
--- /dev/null
+++ b/CPP/7zip/UI/Agent/AgentProxy.cpp
@@ -0,0 +1,752 @@
+// AgentProxy.cpp
+
+#include "StdAfx.h"
+
+// #include <stdio.h>
+#ifdef _WIN32
+#include <wchar.h>
+#else
+#include <ctype.h>
+#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<unsigned> &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];
+  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++)
+  {
+    UInt32 index = indices[i];
+    unsigned numDirItems = dir.SubDirs.Size();
+    if (index < numDirItems)
+      AddRealIndices(dir.SubDirs[index], realIndices);
+    else
+      realIndices.Add(dir.SubFiles[index - numDirItems]);
+  }
+  HeapSort(&realIndices.Front(), 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++)
+  {
+    UInt32 index = (UInt32)dir.SubFiles[i];
+    UInt64 size, packSize;
+    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(&currentItemIndex))
+    }
+    
+    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<unsigned> &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.Front(), 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;
+    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<unsigned> &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(&currentItemIndex))
+    }
+    
+    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
new file mode 100644
index 0000000..c24dd91
--- /dev/null
+++ b/CPP/7zip/UI/Agent/AgentProxy.h
@@ -0,0 +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<unsigned> SubDirs;
+  CRecordVector<unsigned> 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<CProxyDir> Dirs; // Dirs[0] - root
+  CObjArray<CProxyFile> 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<unsigned> 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<CProxyDir2> Dirs;  // Dirs[0] - root folder
+                                   // Dirs[1] - for alt streams of root dir
+  CObjArray<CProxyFile2> 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
new file mode 100644
index 0000000..89b20dc
--- /dev/null
+++ b/CPP/7zip/UI/Agent/ArchiveFolder.cpp
@@ -0,0 +1,51 @@
+// 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<IFolderArchiveExtractCallback> extractCallback2;
+  {
+    CMyComPtr<IFolderOperationsExtractCallback> 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
new file mode 100644
index 0000000..3fa027d
--- /dev/null
+++ b/CPP/7zip/UI/Agent/ArchiveFolderOpen.cpp
@@ -0,0 +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<IArchiveOpenCallback> openArchiveCallback;
+  if (progress)
+  {
+    CMyComPtr<IProgress> progressWrapper = progress;
+    progressWrapper.QueryInterface(IID_IArchiveOpenCallback, &openArchiveCallback);
+  }
+  CAgent *agent = new CAgent();
+  CMyComPtr<IInFolderArchive> 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
new file mode 100644
index 0000000..0189224
--- /dev/null
+++ b/CPP/7zip/UI/Agent/ArchiveFolderOut.cpp
@@ -0,0 +1,386 @@
+// 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<FString> 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<IFolderArchiveUpdateCallback> 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<IOutStream> 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<IArchiveOpenCallback> 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<IFolderFolder> 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<IFolderAltStreams> folderAltStreams;
+    archiveFolder.QueryInterface(IID_IFolderAltStreams, &folderAltStreams);
+    if (folderAltStreams)
+    {
+      CMyComPtr<IFolderFolder> newFolder;
+      folderAltStreams->BindToAltStreams((UInt32)(Int32)-1, &newFolder);
+      if (newFolder)
+        archiveFolder = newFolder;
+    }
+  }
+
+  FOR_VECTOR (i, pathParts)
+  {
+    CMyComPtr<IFolderFolder> newFolder;
+  
+    if (isAltStreamFolder && i == pathParts.Size() - 1)
+    {
+      CMyComPtr<IFolderAltStreams> 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<IArchiveFolderInternal> 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
new file mode 100644
index 0000000..55f1423
--- /dev/null
+++ b/CPP/7zip/UI/Agent/IFolderArchive.h
@@ -0,0 +1,107 @@
+// 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
diff --git a/CPP/7zip/UI/Agent/StdAfx.h b/CPP/7zip/UI/Agent/StdAfx.h
new file mode 100644
index 0000000..035267c
--- /dev/null
+++ b/CPP/7zip/UI/Agent/StdAfx.h
@@ -0,0 +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
diff --git a/CPP/7zip/UI/Agent/UpdateCallbackAgent.cpp b/CPP/7zip/UI/Agent/UpdateCallbackAgent.cpp
new file mode 100644
index 0000000..8299902
--- /dev/null
+++ b/CPP/7zip/UI/Agent/UpdateCallbackAgent.cpp
@@ -0,0 +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<ICryptoGetTextPassword> 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
new file mode 100644
index 0000000..179ce98
--- /dev/null
+++ b/CPP/7zip/UI/Agent/UpdateCallbackAgent.h
@@ -0,0 +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<ICryptoGetTextPassword2> _cryptoGetTextPassword;
+  CMyComPtr<IFolderArchiveUpdateCallback> Callback;
+  CMyComPtr<IFolderArchiveUpdateCallback2> Callback2;
+  CMyComPtr<ICompressProgressInfo> _compressProgress;
+public:
+  void SetCallback(IFolderArchiveUpdateCallback *callback);
+};
+
+#endif
diff --git a/CPP/7zip/UI/Client7z/Client7z.cpp b/CPP/7zip/UI/Client7z/Client7z.cpp
index 9a06cdc..121a2f1 100644
--- a/CPP/7zip/UI/Client7z/Client7z.cpp
+++ b/CPP/7zip/UI/Client7z/Client7z.cpp
@@ -1,993 +1,1122 @@
-// Client7z.cpp

-

-#include "StdAfx.h"

-

-#include <stdio.h>

-

-#include "../../../Common/MyWindows.h"

-

-#include "../../../Common/Defs.h"

-#include "../../../Common/MyInitGuid.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"

-

-#include "../../IPassword.h"

-#include "../../../../C/7zVersion.h"

-

-#ifdef _WIN32

-HINSTANCE g_hInstance = 0;

-#endif

-

-// Tou can find the list of all GUIDs in Guid.txt file.

-// use another CLSIDs, if you want to support other formats (zip, rar, ...).

-// {23170F69-40C1-278A-1000-000110070000}

-

-DEFINE_GUID(CLSID_CFormat7z,

-  0x23170F69, 0x40C1, 0x278A, 0x10, 0x00, 0x00, 0x01, 0x10, 0x07, 0x00, 0x00);

-DEFINE_GUID(CLSID_CFormatXz,

-  0x23170F69, 0x40C1, 0x278A, 0x10, 0x00, 0x00, 0x01, 0x10, 0x0C, 0x00, 0x00);

-

-#define CLSID_Format CLSID_CFormat7z

-// #define CLSID_Format CLSID_CFormatXz

-

-using namespace NWindows;

-using namespace NFile;

-using namespace NDir;

-

-#define kDllName "7z.dll"

-

-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:

-  public IArchiveOpenCallback,

-  public ICryptoGetTextPassword,

-  public CMyUnknownImp

-{

-public:

-  MY_UNKNOWN_IMP1(ICryptoGetTextPassword)

-

-  STDMETHOD(SetTotal)(const UInt64 *files, const UInt64 *bytes);

-  STDMETHOD(SetCompleted)(const UInt64 *files, const UInt64 *bytes);

-

-  STDMETHOD(CryptoGetTextPassword)(BSTR *password);

-

-  bool PasswordIsDefined;

-  UString Password;

-

-  CArchiveOpenCallback() : PasswordIsDefined(false) {}

-};

-

-STDMETHODIMP CArchiveOpenCallback::SetTotal(const UInt64 * /* files */, const UInt64 * /* bytes */)

-{

-  return S_OK;

-}

-

-STDMETHODIMP CArchiveOpenCallback::SetCompleted(const UInt64 * /* files */, const UInt64 * /* bytes */)

-{

-  return S_OK;

-}

-  

-STDMETHODIMP CArchiveOpenCallback::CryptoGetTextPassword(BSTR *password)

-{

-  if (!PasswordIsDefined)

-  {

-    // You can ask real password here from user

-    // Password = GetPassword(OutStream);

-    // PasswordIsDefined = true;

-    PrintError("Password is not defined");

-    return E_ABORT;

-  }

-  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 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";

-

-

-class CArchiveExtractCallback:

-  public IArchiveExtractCallback,

-  public ICryptoGetTextPassword,

-  public CMyUnknownImp

-{

-public:

-  MY_UNKNOWN_IMP1(ICryptoGetTextPassword)

-

-  // IProgress

-  STDMETHOD(SetTotal)(UInt64 size);

-  STDMETHOD(SetCompleted)(const UInt64 *completeValue);

-

-  // IArchiveExtractCallback

-  STDMETHOD(GetStream)(UInt32 index, ISequentialOutStream **outStream, Int32 askExtractMode);

-  STDMETHOD(PrepareOperation)(Int32 askExtractMode);

-  STDMETHOD(SetOperationResult)(Int32 resultEOperationResult);

-

-  // ICryptoGetTextPassword

-  STDMETHOD(CryptoGetTextPassword)(BSTR *aPassword);

-

-private:

-  CMyComPtr<IInArchive> _archiveHandler;

-  FString _directoryPath;  // Output directory

-  UString _filePath;       // name inside arcvhive

-  FString _diskFilePath;   // full path to file on disk

-  bool _extractMode;

-  struct CProcessedFileInfo

-  {

-    FILETIME MTime;

-    UInt32 Attrib;

-    bool isDir;

-    bool AttribDefined;

-    bool MTimeDefined;

-  } _processedFileInfo;

-

-  COutFileStream *_outFileStreamSpec;

-  CMyComPtr<ISequentialOutStream> _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);

-}

-

-STDMETHODIMP CArchiveExtractCallback::SetTotal(UInt64 /* size */)

-{

-  return S_OK;

-}

-

-STDMETHODIMP CArchiveExtractCallback::SetCompleted(const UInt64 * /* completeValue */)

-{

-  return S_OK;

-}

-

-STDMETHODIMP CArchiveExtractCallback::GetStream(UInt32 index,

-    ISequentialOutStream **outStream, Int32 askExtractMode)

-{

-  *outStream = 0;

-  _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.AttribDefined = false;

-    }

-    else

-    {

-      if (prop.vt != VT_UI4)

-        return E_FAIL;

-      _processedFileInfo.Attrib = prop.ulVal;

-      _processedFileInfo.AttribDefined = true;

-    }

-  }

-

-  RINOK(IsArchiveItemFolder(_archiveHandler, index, _processedFileInfo.isDir));

-

-  {

-    // Get Modified Time

-    NCOM::CPropVariant prop;

-    RINOK(_archiveHandler->GetProperty(index, kpidMTime, &prop));

-    _processedFileInfo.MTimeDefined = false;

-    switch (prop.vt)

-    {

-      case VT_EMPTY:

-        // _processedFileInfo.MTime = _utcMTimeDefault;

-        break;

-      case VT_FILETIME:

-        _processedFileInfo.MTime = prop.filetime;

-        _processedFileInfo.MTimeDefined = true;

-        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("Can not delete output file", fullProcessedPath);

-        return E_ABORT;

-      }

-    }

-    

-    _outFileStreamSpec = new COutFileStream;

-    CMyComPtr<ISequentialOutStream> outStreamLoc(_outFileStreamSpec);

-    if (!_outFileStreamSpec->Open(fullProcessedPath, CREATE_ALWAYS))

-    {

-      PrintError("Can not open output file", fullProcessedPath);

-      return E_ABORT;

-    }

-    _outFileStream = outStreamLoc;

-    *outStream = outStreamLoc.Detach();

-  }

-  return S_OK;

-}

-

-STDMETHODIMP 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;

-  };

-  Print(_filePath);

-  return S_OK;

-}

-

-STDMETHODIMP 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(operationResult, temp);

-        Print("Error #");

-        Print(temp);

-      }

-    }

-  }

-

-  if (_outFileStream)

-  {

-    if (_processedFileInfo.MTimeDefined)

-      _outFileStreamSpec->SetMTime(&_processedFileInfo.MTime);

-    RINOK(_outFileStreamSpec->Close());

-  }

-  _outFileStream.Release();

-  if (_extractMode && _processedFileInfo.AttribDefined)

-    SetFileAttrib_PosixHighDetect(_diskFilePath, _processedFileInfo.Attrib);

-  PrintNewLine();

-  return S_OK;

-}

-

-

-STDMETHODIMP CArchiveExtractCallback::CryptoGetTextPassword(BSTR *password)

-{

-  if (!PasswordIsDefined)

-  {

-    // You can ask real password here from user

-    // Password = GetPassword(OutStream);

-    // PasswordIsDefined = true;

-    PrintError("Password is not defined");

-    return E_ABORT;

-  }

-  return StringToBstr(Password, password);

-}

-

-

-

-//////////////////////////////////////////////////////////////

-// Archive Creating callback class

-

-struct CDirItem

-{

-  UInt64 Size;

-  FILETIME CTime;

-  FILETIME ATime;

-  FILETIME MTime;

-  UString Name;

-  FString FullPath;

-  UInt32 Attrib;

-

-  bool isDir() const { return (Attrib & FILE_ATTRIBUTE_DIRECTORY) != 0 ; }

-};

-

-class CArchiveUpdateCallback:

-  public IArchiveUpdateCallback2,

-  public ICryptoGetTextPassword2,

-  public CMyUnknownImp

-{

-public:

-  MY_UNKNOWN_IMP2(IArchiveUpdateCallback2, ICryptoGetTextPassword2)

-

-  // IProgress

-  STDMETHOD(SetTotal)(UInt64 size);

-  STDMETHOD(SetCompleted)(const UInt64 *completeValue);

-

-  // IUpdateCallback2

-  STDMETHOD(GetUpdateItemInfo)(UInt32 index,

-      Int32 *newData, Int32 *newProperties, UInt32 *indexInArchive);

-  STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value);

-  STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **inStream);

-  STDMETHOD(SetOperationResult)(Int32 operationResult);

-  STDMETHOD(GetVolumeSize)(UInt32 index, UInt64 *size);

-  STDMETHOD(GetVolumeStream)(UInt32 index, ISequentialOutStream **volumeStream);

-

-  STDMETHOD(CryptoGetTextPassword2)(Int32 *passwordIsDefined, BSTR *password);

-

-public:

-  CRecordVector<UInt64> VolumesSizes;

-  UString VolName;

-  UString VolExt;

-

-  FString DirPrefix;

-  const CObjectVector<CDirItem> *DirItems;

-

-  bool PasswordIsDefined;

-  UString Password;

-  bool AskPassword;

-

-  bool m_NeedBeClosed;

-

-  FStringVector FailedFiles;

-  CRecordVector<HRESULT> FailedCodes;

-

-  CArchiveUpdateCallback(): PasswordIsDefined(false), AskPassword(false), DirItems(0) {};

-

-  ~CArchiveUpdateCallback() { Finilize(); }

-  HRESULT Finilize();

-

-  void Init(const CObjectVector<CDirItem> *dirItems)

-  {

-    DirItems = dirItems;

-    m_NeedBeClosed = false;

-    FailedFiles.Clear();

-    FailedCodes.Clear();

-  }

-};

-

-STDMETHODIMP CArchiveUpdateCallback::SetTotal(UInt64 /* size */)

-{

-  return S_OK;

-}

-

-STDMETHODIMP CArchiveUpdateCallback::SetCompleted(const UInt64 * /* completeValue */)

-{

-  return S_OK;

-}

-

-STDMETHODIMP 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;

-}

-

-STDMETHODIMP CArchiveUpdateCallback::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)

-{

-  NCOM::CPropVariant prop;

-  

-  if (propID == kpidIsAnti)

-  {

-    prop = false;

-    prop.Detach(value);

-    return S_OK;

-  }

-

-  {

-    const CDirItem &dirItem = (*DirItems)[index];

-    switch (propID)

-    {

-      case kpidPath:  prop = dirItem.Name; break;

-      case kpidIsDir:  prop = dirItem.isDir(); break;

-      case kpidSize:  prop = dirItem.Size; break;

-      case kpidAttrib:  prop = dirItem.Attrib; break;

-      case kpidCTime:  prop = dirItem.CTime; break;

-      case kpidATime:  prop = dirItem.ATime; break;

-      case kpidMTime:  prop = dirItem.MTime; 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);

-}

-

-STDMETHODIMP CArchiveUpdateCallback::GetStream(UInt32 index, ISequentialInStream **inStream)

-{

-  RINOK(Finilize());

-

-  const CDirItem &dirItem = (*DirItems)[index];

-  GetStream2(dirItem.Name);

- 

-  if (dirItem.isDir())

-    return S_OK;

-

-  {

-    CInFileStream *inStreamSpec = new CInFileStream;

-    CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec);

-    FString path = DirPrefix + dirItem.FullPath;

-    if (!inStreamSpec->Open(path))

-    {

-      DWORD sysError = ::GetLastError();

-      FailedCodes.Add(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;

-}

-

-STDMETHODIMP CArchiveUpdateCallback::SetOperationResult(Int32 /* operationResult */)

-{

-  m_NeedBeClosed = true;

-  return S_OK;

-}

-

-STDMETHODIMP 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;

-}

-

-STDMETHODIMP 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 += '.';

-  fileName += res;

-  fileName += VolExt;

-  COutFileStream *streamSpec = new COutFileStream;

-  CMyComPtr<ISequentialOutStream> streamLoc(streamSpec);

-  if (!streamSpec->Create(us2fs(fileName), false))

-    return ::GetLastError();

-  *volumeStream = streamLoc.Detach();

-  return S_OK;

-}

-

-STDMETHODIMP CArchiveUpdateCallback::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password)

-{

-  if (!PasswordIsDefined)

-  {

-    if (AskPassword)

-    {

-      // You can ask real password here from user

-      // Password = GetPassword(OutStream);

-      // PasswordIsDefined = true;

-      PrintError("Password is not defined");

-      return E_ABORT;

-    }

-  }

-  *passwordIsDefined = BoolToInt(PasswordIsDefined);

-  return StringToBstr(Password, password);

-}

-

-

-// Main function

-

-#define NT_CHECK_FAIL_ACTION PrintError("Unsupported Windows version"); return 1;

-

-int MY_CDECL main(int numArgs, const char *args[])

-{

-  NT_CHECK

-

-  PrintStringLn(kCopyrightString);

-

-  if (numArgs < 2)

-  {

-    PrintStringLn(kHelpString);

-    return 0;

-  }

-

-  if (numArgs < 3)

-  {

-    PrintError(kIncorrectCommand);

-    return 1;

-  }

-

-  

-  NDLL::CLibrary lib;

-  if (!lib.Load(NDLL::GetModuleDirPrefix() + FTEXT(kDllName)))

-  {

-    PrintError("Can not load 7-zip library");

-    return 1;

-  }

-

-  Func_CreateObject createObjectFunc = (Func_CreateObject)lib.GetProc("CreateObject");

-  if (!createObjectFunc)

-  {

-    PrintError("Can not get CreateObject");

-    return 1;

-  }

-

-  char c;

-  {

-    AString command (args[1]);

-    if (command.Len() != 1)

-    {

-      PrintError(kIncorrectCommand);

-      return 1;

-    }

-    c = (char)MyCharLower_Ascii(command[0]);

-  }

-

-  FString archiveName = CmdStringToFString(args[2]);

-  

-  if (c == 'a')

-  {

-    // create archive command

-    if (numArgs < 4)

-    {

-      PrintError(kIncorrectCommand);

-      return 1;

-    }

-    CObjectVector<CDirItem> dirItems;

-    {

-      int i;

-      for (i = 3; i < numArgs; i++)

-      {

-        CDirItem di;

-        FString name = CmdStringToFString(args[i]);

-        

-        NFind::CFileInfo fi;

-        if (!fi.Find(name))

-        {

-          PrintError("Can't find file", name);

-          return 1;

-        }

-        

-        di.Attrib = fi.Attrib;

-        di.Size = fi.Size;

-        di.CTime = fi.CTime;

-        di.ATime = fi.ATime;

-        di.MTime = fi.MTime;

-        di.Name = fs2us(name);

-        di.FullPath = name;

-        dirItems.Add(di);

-      }

-    }

-

-    COutFileStream *outFileStreamSpec = new COutFileStream;

-    CMyComPtr<IOutStream> outFileStream = outFileStreamSpec;

-    if (!outFileStreamSpec->Create(archiveName, false))

-    {

-      PrintError("can't create archive file");

-      return 1;

-    }

-

-    CMyComPtr<IOutArchive> outArchive;

-    if (createObjectFunc(&CLSID_Format, &IID_IOutArchive, (void **)&outArchive) != S_OK)

-    {

-      PrintError("Can not get class object");

-      return 1;

-    }

-

-    CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback;

-    CMyComPtr<IArchiveUpdateCallback2> updateCallback(updateCallbackSpec);

-    updateCallbackSpec->Init(&dirItems);

-    // updateCallbackSpec->PasswordIsDefined = true;

-    // updateCallbackSpec->Password = L"1";

-

-    /*

-    {

-      const wchar_t *names[] =

-      {

-        L"s",

-        L"x"

-      };

-      const unsigned kNumProps = ARRAY_SIZE(names);

-      NCOM::CPropVariant values[kNumProps] =

-      {

-        false,    // solid mode OFF

-        (UInt32)9 // compression level = 9 - ultra

-      };

-      CMyComPtr<ISetProperties> setProperties;

-      outArchive->QueryInterface(IID_ISetProperties, (void **)&setProperties);

-      if (!setProperties)

-      {

-        PrintError("ISetProperties unsupported");

-        return 1;

-      }

-      RINOK(setProperties->SetProperties(names, values, kNumProps));

-    }

-    */

-    

-    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 (numArgs != 3)

-    {

-      PrintError(kIncorrectCommand);

-      return 1;

-    }

-

-    bool listCommand;

-    

-    if (c == 'l')

-      listCommand = true;

-    else if (c == 'x')

-      listCommand = false;

-    else

-    {

-      PrintError(kIncorrectCommand);

-      return 1;

-    }

-  

-    CMyComPtr<IInArchive> archive;

-    if (createObjectFunc(&CLSID_Format, &IID_IInArchive, (void **)&archive) != S_OK)

-    {

-      PrintError("Can not get class object");

-      return 1;

-    }

-    

-    CInFileStream *fileSpec = new CInFileStream;

-    CMyComPtr<IInStream> file = fileSpec;

-    

-    if (!fileSpec->Open(archiveName))

-    {

-      PrintError("Can not open archive file", archiveName);

-      return 1;

-    }

-

-    {

-      CArchiveOpenCallback *openCallbackSpec = new CArchiveOpenCallback;

-      CMyComPtr<IArchiveOpenCallback> openCallback(openCallbackSpec);

-      openCallbackSpec->PasswordIsDefined = false;

-      // openCallbackSpec->PasswordIsDefined = true;

-      // openCallbackSpec->Password = L"1";

-      

-      const UInt64 scanSize = 1 << 23;

-      if (archive->Open(file, &scanSize, openCallback) != S_OK)

-      {

-        PrintError("Can not 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[32];

-          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<IArchiveExtractCallback> extractCallback(extractCallbackSpec);

-      extractCallbackSpec->Init(archive, FString()); // second parameter is output folder path

-      extractCallbackSpec->PasswordIsDefined = false;

-      // extractCallbackSpec->PasswordIsDefined = true;

-      // extractCallbackSpec->Password = "1";

-

-      /*

-      const wchar_t *names[] =

-      {

-        L"mt",

-        L"mtf"

-      };

-      const unsigned kNumProps = sizeof(names) / sizeof(names[0]);

-      NCOM::CPropVariant values[kNumProps] =

-      {

-        (UInt32)1,

-        false

-      };

-      CMyComPtr<ISetProperties> setProperties;

-      archive->QueryInterface(IID_ISetProperties, (void **)&setProperties);

-      if (setProperties)

-        setProperties->SetProperties(names, values, kNumProps);

-      */

-

-      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 <stdio.h>
+
+#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"
+
+#include "../../IPassword.h"
+#include "../../../../C/7zVersion.h"
+
+#ifdef _WIN32
+extern
+HINSTANCE g_hInstance;
+HINSTANCE g_hInstance = NULL;
+#endif
+
+// 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
+    // Password = GetPassword(OutStream);
+    // PasswordIsDefined = true;
+    PrintError("Password is not defined");
+    return E_ABORT;
+  }
+  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<IInArchive> _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<ISequentialOutStream> _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<ISequentialOutStream> outStreamLoc(_outFileStreamSpec);
+    if (!_outFileStreamSpec->Open(fullProcessedPath, CREATE_ALWAYS))
+    {
+      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)
+  {
+    // You can ask real password here from user
+    // Password = GetPassword(OutStream);
+    // PasswordIsDefined = true;
+    PrintError("Password is not defined");
+    return E_ABORT;
+  }
+  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<UInt64> VolumesSizes;
+  UString VolName;
+  UString VolExt;
+
+  FString DirPrefix;
+  const CObjectVector<CDirItem> *DirItems;
+
+  bool PasswordIsDefined;
+  UString Password;
+  bool AskPassword;
+
+  bool m_NeedBeClosed;
+
+  FStringVector FailedFiles;
+  CRecordVector<HRESULT> FailedCodes;
+
+  CArchiveUpdateCallback():
+      DirItems(NULL),
+      PasswordIsDefined(false),
+      AskPassword(false)
+      {}
+
+  ~CArchiveUpdateCallback() { Finilize(); }
+  HRESULT Finilize();
+
+  void Init(const CObjectVector<CDirItem> *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<ISequentialInStream> 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<ISequentialOutStream> streamLoc(streamSpec);
+  if (!streamSpec->Create(us2fs(fileName), false))
+    return GetLastError_noZero_HRESULT();
+  *volumeStream = streamLoc.Detach();
+  return S_OK;
+}
+
+Z7_COM7F_IMF(CArchiveUpdateCallback::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password))
+{
+  if (!PasswordIsDefined)
+  {
+    if (AskPassword)
+    {
+      // You can ask real password here from user
+      // Password = GetPassword(OutStream);
+      // PasswordIsDefined = true;
+      PrintError("Password is not defined");
+      return E_ABORT;
+    }
+  }
+  *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;
+  }
+
+  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<FString> 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<CDirItem> 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<IOutStream> outFileStream = outFileStreamSpec;
+    if (!outFileStreamSpec->Create(archiveName, false))
+    {
+      PrintError("can't create archive file");
+      return 1;
+    }
+
+    CMyComPtr<IOutArchive> outArchive;
+    if (f_CreateObject(&CLSID_Format, &IID_IOutArchive, (void **)&outArchive) != S_OK)
+    {
+      PrintError("Cannot get class object");
+      return 1;
+    }
+
+    CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback;
+    CMyComPtr<IArchiveUpdateCallback2> 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<ISetProperties> 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<IInArchive> archive;
+    if (f_CreateObject(&CLSID_Format, &IID_IInArchive, (void **)&archive) != S_OK)
+    {
+      PrintError("Cannot get class object");
+      return 1;
+    }
+    
+    CInFileStream *fileSpec = new CInFileStream;
+    CMyComPtr<IInStream> file = fileSpec;
+    
+    if (!fileSpec->Open(archiveName))
+    {
+      PrintError("Cannot open archive file", archiveName);
+      return 1;
+    }
+
+    {
+      CArchiveOpenCallback *openCallbackSpec = new CArchiveOpenCallback;
+      CMyComPtr<IArchiveOpenCallback> 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[32];
+          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<IArchiveExtractCallback> 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<ISetProperties> 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 d9ec4ca..d46300f 100644
--- a/CPP/7zip/UI/Client7z/Client7z.dsp
+++ b/CPP/7zip/UI/Client7z/Client7z.dsp
@@ -1,235 +1,327 @@
-# 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\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\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

-# End Group

-# Begin Group "Common"

-

-# PROP Default_Filter ""

-# 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\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

-# End Group

-# Begin Source File

-

-SOURCE=.\Client7z.cpp

-# End Source File

-# Begin Source File

-

-SOURCE=..\..\..\..\C\Sort.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.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 4c26851..598a6d3 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 c6d3b1f..d0feea8 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 59d9ac1..035267c 100644
--- a/CPP/7zip/UI/Client7z/StdAfx.h
+++ b/CPP/7zip/UI/Client7z/StdAfx.h
@@ -1,8 +1,11 @@
-// StdAfx.h

-

-#ifndef __STDAFX_H

-#define __STDAFX_H

-

-#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 9f68f16..988701e 100644
--- a/CPP/7zip/UI/Client7z/makefile
+++ b/CPP/7zip/UI/Client7z/makefile
@@ -1,28 +1,28 @@
-PROG = 7zcl.exe

-MY_CONSOLE = 1

-

-CURRENT_OBJS = \

-  $O\Client7z.obj \

-

-COMMON_OBJS = \

-  $O\IntToString.obj \

-  $O\NewHandler.obj \

-  $O\MyString.obj \

-  $O\StringConvert.obj \

-  $O\StringToInt.obj \

-  $O\MyVector.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 \

-

-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 \
+
+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
new file mode 100644
index 0000000..3f97205
--- /dev/null
+++ b/CPP/7zip/UI/Client7z/makefile.gcc
@@ -0,0 +1,69 @@
+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
diff --git a/CPP/7zip/UI/Client7z/resource.rc b/CPP/7zip/UI/Client7z/resource.rc
index 701a783..462df6f 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 35dbd74..2bdbc41 100644
--- a/CPP/7zip/UI/Common/ArchiveCommandLine.cpp
+++ b/CPP/7zip/UI/Common/ArchiveCommandLine.cpp
@@ -1,1295 +1,1700 @@
-// ArchiveCommandLine.cpp

-

-#include "StdAfx.h"

-#undef printf

-#undef sprintf

-

-#ifdef _WIN32

-#ifndef UNDER_CE

-#include <io.h>

-#endif

-#else

-// for isatty()

-#include <unistd.h>

-#endif

-

-#include <stdio.h>

-

-#ifdef _7ZIP_LARGE_PAGES

-#include "../../../../C/Alloc.h"

-#endif

-

-#include "../../../Common/ListFileUtils.h"

-#include "../../../Common/StringConvert.h"

-#include "../../../Common/StringToInt.h"

-

-#include "../../../Windows/ErrorMsg.h"

-#include "../../../Windows/FileDir.h"

-#include "../../../Windows/FileName.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 _7ZIP_LARGE_PAGES

-bool g_LargePagesMode = false;

-#endif

-

-#ifdef UNDER_CE

-

-#define MY_IS_TERMINAL(x) false;

-

-#else

-

-#if _MSC_VER >= 1400

-#define MY_isatty_fileno(x) _isatty(_fileno(x))

-#else

-#define MY_isatty_fileno(x) isatty(fileno(x))

-#endif

-

-#define MY_IS_TERMINAL(x) (MY_isatty_fileno(x) != 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;

-}

-

-

-int g_CodePage = -1;

-

-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,

- 

-  kStdIn,

-  kStdOut,

-

-  kLargePages,

-  kListfileCharSet,

-  kConsoleCharSet,

-  kTechMode,

-  

-  kShareForWrite,

-  kStopAfterOpenError,

-  kCaseSensitive,

-  kArcNameMode,

-

-  kDisableWildcardParsing,

-  kElimDup,

-  kFullPathMode,

-  

-  kHardLinks,

-  kSymLinks,

-  kNtSecurity,

-  

-  kAltStreams,

-  kReplaceColonForAltStream,

-  kWriteToAltStreamIfColon,

-

-  kNameTrailReplace,

-

-  kDeleteAfterCompressing,

-  kSetArcMTime

-

-  #ifndef _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 const 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 kImmediateNameID = '!';

-static const char kMapNameID = '#';

-static const char kFileListID = '@';

-

-static const char kSomeCludePostStringMinSize = 2; // at least <@|!><N>ame must be

-static const char kSomeCludeAfterRecursedPostStringMinSize = 2; // at least <@|!><N>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

-};

-

-static const CSwitchForm kSwitchForms[] =

-{

-  { "?" },

-  { "h" },

-  { "-help" },

-  

-  { "ba" },

-  { "bd" },

-  { "bt" },

-  { "bb", NSwitchType::kString, false, 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" },

-  

-  { "ad" },

-  { "ao", NSwitchType::kChar, false, 1, kOverwritePostCharSet},

-

-  { "t",  NSwitchType::kString, false, 1 },

-  { "stx", NSwitchType::kString, true, 1 },

-  

-  { "m",  NSwitchType::kString, true, 1 },

-  { "o",  NSwitchType::kString, false, 1 },

-  { "w",  NSwitchType::kString },

-

-  { "i",  NSwitchType::kString, true, kSomeCludePostStringMinSize},

-  { "x",  NSwitchType::kString, true, kSomeCludePostStringMinSize},

-  { "ai", NSwitchType::kString, true, kSomeCludePostStringMinSize},

-  { "ax", NSwitchType::kString, true, kSomeCludePostStringMinSize},

-  { "an" },

-  

-  { "u",  NSwitchType::kString, true, 1},

-  { "v",  NSwitchType::kString, true, 1},

-  { "r",  NSwitchType::kChar, false, 0, kRecursedPostCharSet },

-  

-  { "stm", NSwitchType::kString },

-  { "sfx", NSwitchType::kString },

-  { "seml", NSwitchType::kString, false, 0},

-  { "scrc", NSwitchType::kString, true, 0 },

-  

-  { "si", NSwitchType::kString },

-  { "so" },

-

-  { "slp", NSwitchType::kString },

-  { "scs", NSwitchType::kString },

-  { "scc", NSwitchType::kString },

-  { "slt" },

-

-  { "ssw" },

-  { "sse" },

-  { "ssc", NSwitchType::kMinus },

-  { "sa",  NSwitchType::kChar, false, 1, k_ArcNameMode_PostCharSet },

-  

-  { "spd" },

-  { "spe", NSwitchType::kMinus },

-  { "spf", NSwitchType::kString, false, 0 },

-  

-  { "snh", NSwitchType::kMinus },

-  { "snl", NSwitchType::kMinus },

-  { "sni" },

-  

-  { "sns", NSwitchType::kMinus },

-  { "snr" },

-  { "snc" },

-  

-  { "snt", NSwitchType::kMinus },

-  

-  { "sdel" },

-  { "stl" }

-

-  #ifndef _NO_CRYPTO

-  , { "p",  NSwitchType::kString }

-  #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 (CommandType)

-  {

-    case NCommandType::kTest:

-    case NCommandType::kExtract:

-    case NCommandType::kExtractFull:

-      return true;

-  }

-  return false;

-}

-

-NExtract::NPathMode::EEnum CArcCommand::GetPathMode() const

-{

-  switch (CommandType)

-  {

-    case NCommandType::kTest:

-    case NCommandType::kExtractFull:

-      return NExtract::NPathMode::kFullPaths;

-  }

-  return NExtract::NPathMode::kNoPaths;

-}

-

-bool CArcCommand::IsFromUpdateGroup() const

-{

-  switch (CommandType)

-  {

-    case NCommandType::kAdd:

-    case NCommandType::kUpdate:

-    case NCommandType::kDelete:

-    case NCommandType::kRename:

-      return true;

-  }

-  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

-

-static void AddNameToCensor(NWildcard::CCensor &censor,

-    const UString &name, bool include, NRecursedType::EEnum type, bool wildcardMatching)

-{

-  bool recursed = false;

-

-  switch (type)

-  {

-    case NRecursedType::kWildcardOnlyRecursed:

-      recursed = DoesNameContainWildcard(name);

-      break;

-    case NRecursedType::kRecursed:

-      recursed = true;

-      break;

-  }

-  censor.AddPreItem(include, name, recursed, wildcardMatching);

-}

-

-static void AddRenamePair(CObjectVector<CRenamePair> *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);

-  }

-}

-

-static void AddToCensorFromListFile(

-    CObjectVector<CRenamePair> *renamePairs,

-    NWildcard::CCensor &censor,

-    LPCWSTR fileName, bool include, NRecursedType::EEnum type, bool wildcardMatching, Int32 codePage)

-{

-  UStringVector names;

-  if (!NFind::DoesFileExist(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)

-  {

-    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], type, wildcardMatching);

-    }

-  }

-  else

-    FOR_VECTOR (i, names)

-      AddNameToCensor(censor, names[i], include, type, wildcardMatching);

-}

-

-static void AddToCensorFromNonSwitchesStrings(

-    CObjectVector<CRenamePair> *renamePairs,

-    unsigned startIndex,

-    NWildcard::CCensor &censor,

-    const UStringVector &nonSwitchStrings,

-    int stopSwitchIndex,

-    NRecursedType::EEnum type,

-    bool wildcardMatching,

-    bool thereAreSwitchIncludes, Int32 codePage)

-{

-  if ((renamePairs || nonSwitchStrings.Size() == startIndex) && !thereAreSwitchIncludes)

-    AddNameToCensor(censor, UString(kUniversalWildcard), true, type,

-        true // wildcardMatching

-        );

-

-  int oldIndex = -1;

-  

-  if (stopSwitchIndex < 0)

-    stopSwitchIndex = 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, s.Ptr(1), true, type, wildcardMatching, codePage);

-    else if (renamePairs)

-    {

-      if (oldIndex == -1)

-        oldIndex = i;

-      else

-      {

-        // NRecursedType::EEnum type is used for global wildcard (-i! switches)

-        AddRenamePair(renamePairs, nonSwitchStrings[oldIndex], s, NRecursedType::kNonRecursed, wildcardMatching);

-        // AddRenamePair(renamePairs, nonSwitchStrings[oldIndex], s, type);

-        oldIndex = -1;

-      }

-    }

-    else

-      AddNameToCensor(censor, s, true, type, wildcardMatching);

-  }

-  

-  if (oldIndex != -1)

-  {

-    throw CArcCmdLineException("There is no second file name for rename pair:", nonSwitchStrings[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, bool include,

-    NRecursedType::EEnum commonRecursedType,

-    bool wildcardMatching)

-{

-  UString s (s2);

-  int pos = s.Find(L':');

-  if (pos < 0)

-    return k_IncorrectMapCommand;

-  int pos2 = s.Find(L':', pos + 1);

-  if (pos2 < 0)

-    return k_IncorrectMapCommand;

-

-  CEventSetEnd eventSetEnd((const wchar_t *)s + ((unsigned)pos2 + 1));

-  s.DeleteFrom(pos2);

-  UInt32 size;

-  if (!StringToUInt32(s.Ptr(pos + 1), size)

-      || size < sizeof(wchar_t)

-      || size > ((UInt32)1 << 31)

-      || size % sizeof(wchar_t) != 0)

-    return "Unsupported Map data size";

-

-  s.DeleteFrom(pos);

-  CFileMapping map;

-  if (map.Open(FILE_MAP_READ, GetSystemString(s)) != 0)

-    return "Can not open mapping";

-  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";

-  UInt32 numChars = size / sizeof(wchar_t);

-  for (UInt32 i = 1; i < numChars; i++)

-  {

-    wchar_t c = p[i];

-    if (c == 0)

-    {

-      // MessageBoxW(0, name, L"7-Zip", 0);

-      AddNameToCensor(censor, name, include, commonRecursedType, wildcardMatching);

-      name.Empty();

-    }

-    else

-      name += c;

-  }

-  if (!name.IsEmpty())

-    return "Map data error";

-

-  return NULL;

-}

-

-#endif

-

-static void AddSwitchWildcardsToCensor(

-    NWildcard::CCensor &censor,

-    const UStringVector &strings, bool include,

-    NRecursedType::EEnum commonRecursedType,

-    bool wildcardMatching,

-    Int32 codePage)

-{

-  const char *errorMessage = NULL;

-  unsigned i;

-  for (i = 0; i < strings.Size(); i++)

-  {

-    const UString &name = strings[i];

-    NRecursedType::EEnum recursedType;

-    unsigned pos = 0;

-    

-    if (name.Len() < kSomeCludePostStringMinSize)

-    {

-      errorMessage = "Too short switch";

-      break;

-    }

-    

-    if (::MyCharLower_Ascii(name[pos]) == kRecursedIDChar)

-    {

-      pos++;

-      wchar_t c = name[pos];

-      int index = -1;

-      if (c <= 0x7F)

-        index = FindCharPosInString(kRecursedPostCharSet, (char)c);

-      recursedType = GetRecursedTypeFromIndex(index);

-      if (index >= 0)

-        pos++;

-    }

-    else

-      recursedType = commonRecursedType;

-    

-    if (name.Len() < pos + kSomeCludeAfterRecursedPostStringMinSize)

-    {

-      errorMessage = "Too short switch";

-      break;

-    }

-    

-    const UString tail = name.Ptr(pos + 1);

-    

-    if (name[pos] == kImmediateNameID)

-      AddNameToCensor(censor, tail, include, recursedType, wildcardMatching);

-    else if (name[pos] == kFileListID)

-      AddToCensorFromListFile(NULL, censor, tail, include, recursedType, wildcardMatching, codePage);

-    #ifdef _WIN32

-    else if (name[pos] == kMapNameID)

-    {

-      errorMessage = ParseMapWithPaths(censor, tail, include, recursedType, wildcardMatching);

-      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 >= '0' + kNumUpdatePairActions)

-      return false;

-    unsigned actionPos = 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 (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) || size == 0)

-        throw CArcCmdLineException("Incorrect volume size:", sv[i]);

-      options.VolumesSizes.Add(size);

-    }

-  }

-}

-

-static void SetMethodOptions(const CParser &parser, CObjectVector<CProperty> &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(index + 1);

-        prop.Name.DeleteFrom(index);

-      }

-      properties.Add(prop);

-    }

-  }

-}

-

-

-static inline void SetStreamMode(const CSwitchResult &sw, unsigned &res)

-{

-  if (sw.ThereIs)

-    res = sw.PostCharIndex;

-}

-

-

-void CArcCmdLineParser::Parse1(const UStringVector &commandStrings,

-    CArcCmdLineOptions &options)

-{

-  if (!parser.ParseStrings(kSwitchForms, 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.StdInMode = parser[NKey::kStdIn].ThereIs;

-  options.StdOutMode = parser[NKey::kStdOut].ThereIs;

-  options.EnableHeaders = !parser[NKey::kDisableHeaders].ThereIs;

-  options.TechMode = parser[NKey::kTechMode].ThereIs;

-  options.ShowTime = parser[NKey::kShowTime].ThereIs;

-

-  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)

-  {

-    g_CaseSensitive = !parser[NKey::kCaseSensitive].WithMinus;

-    options.CaseSensitiveChange = true;

-    options.CaseSensitive = g_CaseSensitive;

-  }

-

-

-  #if defined(_WIN32) && !defined(UNDER_CE)

-  NSecurity::EnablePrivilege_SymLink();

-  #endif

-  

-  // options.LargePages = false;

-

-  if (parser[NKey::kLargePages].ThereIs)

-  {

-    unsigned 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 _7ZIP_LARGE_PAGES

-    if (slp >

-          #ifndef UNDER_CE

-            (unsigned)NSecurity::Get_LargePages_RiskLevel()

-          #else

-            0

-          #endif

-        )

-    {

-      SetLargePageSize();

-      // 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())

-    {

-      UInt32 v = 0;

-      AString a;

-      a.SetFromWStr_if_Ascii(s);

-      if (!a.IsEmpty())

-      {

-        const char *end;

-        v = ConvertHexStringToUInt32(a, &end);

-        if (*end != 0)

-          a.Empty();

-      }

-      if (a.IsEmpty())

-        throw CArcCmdLineException("Unsupported switch postfix -stm", s);

-      

-      #ifdef _WIN32

-      SetProcessAffinityMask(GetCurrentProcess(), v);

-      #endif

-    }

-  }

-

-  #endif

-}

-

-struct CCodePagePair

-{

-  const char *Name;

-  Int32 CodePage;

-};

-

-static const unsigned kNumByteOnlyCodePages = 3;

-

-static const CCodePagePair g_CodePagePairs[] =

-{

-  { "utf-8", CP_UTF8 },

-  { "win", CP_ACP },

-  { "dos", CP_OEMCP },

-  { "utf-16le", MY__CP_UTF16 },

-  { "utf-16be", MY__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();

-  unsigned num = byteOnlyCodePages ? kNumByteOnlyCodePages : 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 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;

-}

-

-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::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;

-

-  NRecursedType::EEnum recursedType;

-  if (parser[NKey::kRecursed].ThereIs)

-    recursedType = GetRecursedTypeFromIndex(parser[NKey::kRecursed].PostCharIndex);

-  else

-    recursedType = NRecursedType::kNonRecursed;

-

-  bool wildcardMatching = true;

-  if (parser[NKey::kDisableWildcardParsing].ThereIs)

-    wildcardMatching = false;

-

-  g_CodePage = FindCharset(parser, NKey::kConsoleCharSet, true, -1);

-  Int32 codePage = FindCharset(parser, NKey::kListfileCharSet, false, CP_UTF8);

-

-  bool thereAreSwitchIncludes = false;

-  

-  if (parser[NKey::kInclude].ThereIs)

-  {

-    thereAreSwitchIncludes = true;

-    AddSwitchWildcardsToCensor(options.Censor,

-        parser[NKey::kInclude].PostStrings, true, recursedType, wildcardMatching, codePage);

-  }

-

-  if (parser[NKey::kExclude].ThereIs)

-    AddSwitchWildcardsToCensor(options.Censor,

-        parser[NKey::kExclude].PostStrings, false, recursedType, wildcardMatching, 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;

-

-  bool isExtractGroupCommand = options.Command.IsFromExtractGroup();

-  bool isExtractOrList = isExtractGroupCommand || options.Command.CommandType == NCommandType::kList;

-  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

-  }

-

-  AddToCensorFromNonSwitchesStrings(isRename ? &options.UpdateOptions.RenamePairs : NULL,

-      curCommandIndex, options.Censor,

-      nonSwitchStrings, parser.StopSwitchIndex,

-      recursedType, wildcardMatching,

-      thereAreSwitchIncludes, codePage);

-

-  options.YesToAll = parser[NKey::kYes].ThereIs;

-

-

-  #ifndef _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);

-

-  if (isExtractOrList)

-  {

-    CExtractOptionsBase &eo = options.ExtractOptions;

-

-    {

-      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.ReplaceColonForAltStream = parser[NKey::kReplaceColonForAltStream].ThereIs;

-      nt.WriteToAltStreamIfColon = parser[NKey::kWriteToAltStreamIfColon].ThereIs;

-    }

-      

-    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;

-

-    if (parser[NKey::kArInclude].ThereIs)

-      AddSwitchWildcardsToCensor(arcCensor, parser[NKey::kArInclude].PostStrings, true, NRecursedType::kNonRecursed, wildcardMatching, codePage);

-    if (parser[NKey::kArExclude].ThereIs)

-      AddSwitchWildcardsToCensor(arcCensor, parser[NKey::kArExclude].PostStrings, false, NRecursedType::kNonRecursed, wildcardMatching, codePage);

-

-    if (thereIsArchiveName)

-      AddNameToCensor(arcCensor, options.ArchiveName, true, NRecursedType::kNonRecursed, wildcardMatching);

-

-    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]);

-        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::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.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;

-    if (curCommandIndex < numNonSwitchStrings)

-    {

-      if (!StringToUInt32(nonSwitchStrings[curCommandIndex], options.NumIterations))

-        throw CArcCmdLineException("Incorrect Number of benmchmark iterations", nonSwitchStrings[curCommandIndex]);

-      curCommandIndex++;

-    }

-  }

-  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;

-    if (parser[NKey::kShareForWrite].ThereIs)

-      hashOptions.OpenShareForWrite = true;

-    hashOptions.StdInMode = options.StdInMode;

-    hashOptions.AltStreamsMode = options.AltStreams.Val;

-  }

-  else if (options.Command.CommandType == NCommandType::kInfo)

-  {

-  }

-  else

-    throw 20150919;

-}

+// ArchiveCommandLine.cpp
+
+#include "StdAfx.h"
+#undef printf
+#undef sprintf
+
+#ifdef _WIN32
+#ifndef UNDER_CE
+#include <io.h>
+#endif
+#else
+// for isatty()
+#include <unistd.h>
+#endif
+
+#include <stdio.h>
+
+#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/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,
+ 
+  kStdIn,
+  kStdOut,
+
+  kLargePages,
+  kListfileCharSet,
+  kConsoleCharSet,
+  kTechMode,
+  kListFields,
+  
+  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 <@|!><N>ame must be
+static const Byte kSomeCludeAfterRecursedPostStringMinSize = 2; // at least <@|!><N>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) },
+  
+  { "si", SWFRM_STRING },
+  { "so", SWFRM_SIMPLE },
+
+  { "slp", SWFRM_STRING },
+  { "scs", SWFRM_STRING },
+  { "scc", SWFRM_STRING },
+  { "slt", SWFRM_SIMPLE },
+  { "slf", SWFRM_STRING_SINGL(1) },
+
+  { "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);
+}
+
+static void AddRenamePair(CObjectVector<CRenamePair> *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);
+  }
+}
+
+static void AddToCensorFromListFile(
+    CObjectVector<CRenamePair> *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)
+  {
+    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
+    FOR_VECTOR (i, names)
+      AddNameToCensor(censor, nop, names[i]);
+}
+
+static void AddToCensorFromNonSwitchesStrings(
+    CObjectVector<CRenamePair> *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)
+    {
+      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
+      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);
+  int pos = s.Find(L':');
+  if (pos < 0)
+    return k_IncorrectMapCommand;
+  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";
+  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";
+  UInt32 numChars = size / sizeof(wchar_t);
+  for (UInt32 i = 1; i < numChars; i++)
+  {
+    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<CProperty> &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.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);
+  }
+  options.TechMode = parser[NKey::kTechMode].ThereIs;
+  options.ShowTime = parser[NKey::kShowTime].ThereIs;
+
+  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: ";
+
+      #ifdef _WIN32
+
+      UInt64 v = 0;
+      {
+        const char *end;
+        v = ConvertHexStringToUInt64(a, &end);
+        if (*end != 0)
+          a.Empty();
+      }
+      if (a.IsEmpty())
+        throw CArcCmdLineException("Unsupported switch postfix -stm", s);
+
+      {
+        #ifndef _WIN64
+        if (v >= ((UInt64)1 << 32))
+          throw CArcCmdLineException("unsupported value -stm", s);
+        #endif
+        {
+          PrintHex(Parse1Log, v);
+          if (!SetProcessAffinityMask(GetCurrentProcess(), (DWORD_PTR)v))
+          {
+            DWORD lastError = GetLastError();
+            Parse1Log += " : ERROR : ";
+            Parse1Log += NError::MyFormatMessage(lastError);
+          }
+        }
+      }
+      
+      #else // _WIN32
+      
+      {
+        Parse1Log += a;
+        NSystem::CProcessAffinity aff;
+        aff.CpuZero();
+        for (unsigned i = 0; i < a.Len(); i++)
+        {
+          char c = a[i];
+          unsigned v;
+               if (c >= '0' && c <= '9') v =      (unsigned)(c - '0');
+          else if (c >= 'A' && c <= 'F') v = 10 + (unsigned)(c - 'A');
+          else if (c >= 'a' && c <= 'f') v = 10 + (unsigned)(c - 'a');
+          else
+            throw CArcCmdLineException("Unsupported switch postfix -stm", s);
+          for (unsigned k = 0; k < 4; k++)
+          {
+            const unsigned cpu = (a.Len() - 1 - i) * 4 + k;
+            if (v & ((unsigned)1 << k))
+              aff.CpuSet(cpu);
+          }
+        }
+        
+        if (!aff.SetProcAffinity())
+        {
+          DWORD lastError = GetLastError();
+          Parse1Log += " : ERROR : ";
+          Parse1Log += NError::MyFormatMessage(lastError);
+        }
+      }
+      #endif // _WIN32
+
+      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;
+}
+
+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::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);
+
+  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);
+
+  options.YesToAll = parser[NKey::kYes].ThereIs;
+
+
+  #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 bba3c98..9e375b5 100644
--- a/CPP/7zip/UI/Common/ArchiveCommandLine.h
+++ b/CPP/7zip/UI/Common/ArchiveCommandLine.h
@@ -1,136 +1,160 @@
-// ArchiveCommandLine.h

-

-#ifndef __ARCHIVE_COMMAND_LINE_H

-#define __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 CaseSensitiveChange;

-  bool CaseSensitive;

-

-  bool IsInTerminal;

-  bool IsStdOutTerminal;

-  bool IsStdErrTerminal;

-  bool StdInMode;

-  bool StdOutMode;

-  bool EnableHeaders;

-

-  bool YesToAll;

-  bool ShowDialog;

-  NWildcard::CCensor Censor;

-

-  CArcCommand Command;

-  UString ArchiveName;

-

-  #ifndef _NO_CRYPTO

-  bool PasswordEnabled;

-  UString Password;

-  #endif

-

-  bool TechMode;

-  bool ShowTime;

-  

-  UStringVector HashMethods;

-

-  bool AppendName;

-  // UStringVector ArchivePathsSorted;

-  // UStringVector ArchivePathsFullSorted;

-  NWildcard::CCensor arcCensor;

-  UString ArcName_for_StdInMode;

-

-  CObjectVector<CProperty> Properties;

-

-  CExtractOptionsBase ExtractOptions;

-

-  CBoolPair NtSecurity;

-  CBoolPair AltStreams;

-  CBoolPair HardLinks;

-  CBoolPair SymLinks;

-

-  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;

-

-  CArcCmdLineOptions():

-      // LargePages(false),

-      CaseSensitiveChange(false),

-      CaseSensitive(false),

-

-      StdInMode(false),

-      StdOutMode(false),

-

-      Number_for_Out(k_OutStream_stdout),

-      Number_for_Errors(k_OutStream_stderr),

-      Number_for_Percents(k_OutStream_stdout),

-

-      LogLevel(0)

-  {

-  };

-};

-

-class CArcCmdLineParser

-{

-  NCommandLineParser::CParser parser;

-public:

-  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 YesToAll;
+  bool ShowDialog;
+  bool TechMode;
+  bool ShowTime;
+
+  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<CProperty> 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),
+      
+      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)
+  {
+  }
+};
+
+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 aae08ad..4b0cbed 100644
--- a/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp
+++ b/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp
@@ -1,1715 +1,2592 @@
-// ArchiveExtractCallback.cpp

-

-#include "StdAfx.h"

-

-#undef sprintf

-#undef printf

-

-// #include <stdio.h>

-// #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/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(_SFX)

-#define _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 = "Can not create file with auto name";

-static const char * const kCantRenameFile = "Can not rename existing file";

-static const char * const kCantDeleteOutputFile = "Can not delete output file";

-static const char * const kCantDeleteOutputDir = "Can not delete output folder";

-static const char * const kCantCreateHardLink = "Can not create hard link";

-static const char * const kCantCreateSymLink = "Can not create symbolic link";

-static const char * const kCantOpenOutFile = "Can not open output file";

-static const char * const kCantSetFileLen = "Can not set length for output file";

-

-

-#ifndef _SFX

-

-STDMETHODIMP 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

-

-#ifdef _USE_SECURITY_CODE

-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

-

-#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<UInt32> *realIndices)

-{

-  _hardLinks.Clear();

-

-  if (!_arc->Ask_INode)

-    return S_OK;

-  

-  IInArchive *archive = _arc->Archive;

-  CRecordVector<CHardLinkNode> &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;

-      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)

-          hardIDs.Add(h);

-      }

-    }

-  }

-  

-  hardIDs.Sort2();

-  

-  {

-    // wee 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

-

-CArchiveExtractCallback::CArchiveExtractCallback():

-    _arc(NULL),

-    WriteCTime(true),

-    WriteATime(true),

-    WriteMTime(true),

-    _multiArchives(false)

-{

-  LocalProgressSpec = new CLocalProgress();

-  _localProgress = LocalProgressSpec;

-

-  #ifdef _USE_SECURITY_CODE

-  _saclEnabled = InitLocalPrivileges();

-  #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();

-  

-  #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);

-  _extractCallback2.QueryInterface(IID_IArchiveExtractCallbackMessage, &_callbackMessage);

-  _extractCallback2.QueryInterface(IID_IFolderArchiveExtractCallback2, &_folderArchiveExtractCallback2);

-

-  #ifndef _SFX

-

-  _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 _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);

-  }

-}

-

-STDMETHODIMP 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;

-}

-

-STDMETHODIMP 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

-}

-

-STDMETHODIMP 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)

-{

-  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);

-    #if defined(_WIN32) && !defined(UNDER_CE)

-    if (_pathMode == NExtract::NPathMode::kAbsPaths)

-      if (i == 0 && s.Len() == 2 && NName::IsDrivePath2(s))

-        continue;

-    #endif

-    CreateDir(fullPath);

-  }

-}

-

-HRESULT CArchiveExtractCallback::GetTime(UInt32 index, PROPID propID, FILETIME &filetime, bool &filetimeIsDefined)

-{

-  filetimeIsDefined = false;

-  filetime.dwLowDateTime = 0;

-  filetime.dwHighDateTime = 0;

-  NCOM::CPropVariant prop;

-  RINOK(_arc->Archive->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;

-}

-

-HRESULT CArchiveExtractCallback::GetUnpackSize()

-{

-  return _arc->GetItemSize(_index, _curSize, _curSizeDefined);

-}

-

-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_LastError(const char *message, const FString &path)

-{

-  DWORD errorCode = GetLastError();

-  UString s (message);

-  if (errorCode != 0)

-  {

-    s += " : ";

-    s += NError::MyFormatMessage(errorCode);

-  }

-  AddPathToMessage(s, path);

-  return _extractCallback2->MessageError(s);

-}

-

-HRESULT CArchiveExtractCallback::SendMessageError2(const char *message, const FString &path1, const FString &path2)

-{

-  UString s (message);

-  AddPathToMessage(s, path1);

-  AddPathToMessage(s, path2);

-  return _extractCallback2->MessageError(s);

-}

-

-#ifndef _SFX

-

-STDMETHODIMP 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

-

-

-#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(pos + 1);

-  }

-  return s;

-}

-

-#endif

-

-

-bool IsSafePath(const UString &path)

-{

-  if (NName::IsAbsolutePath(path))

-    return false;

-

-  UStringVector parts;

-  SplitPathToParts(path, parts);

-  unsigned level = 0;

-  

-  FOR_VECTOR (i, parts)

-  {

-    const UString &s = parts[i];

-    if (s.IsEmpty())

-    {

-      if (i == 0)

-        return false;

-      continue;

-    }

-    if (s == L".")

-      continue;

-    if (s == L"..")

-    {

-      if (level == 0)

-        return false;

-      level--;

-    }

-    else

-      level++;

-  }

-  

-  return level > 0;

-}

-

-

-bool CensorNode_CheckPath2(const NWildcard::CCensorNode &node, const CReadArcItem &item, bool &include)

-{

-  bool found = false;

-  

-  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 += ':';

-  back += item.AltStreamName;

-  bool include2;

-  

-  if (node.CheckPathVect(pathParts2,

-      true, // isFile,

-      include2))

-  {

-    include = include2;

-    return true;

-  }

-

-  #endif

-

-  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));

-  }

-}

-

-#endif

-*/

-

-

-STDMETHODIMP CArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStream **outStream, Int32 askExtractMode)

-{

-  COM_TRY_BEGIN

-

-  *outStream = NULL;

-

-  #ifndef _SFX

-  if (_hashStream)

-    _hashStreamSpec->ReleaseStream();

-  _hashStreamWasUsed = false;

-  #endif

-

-  _outFileStream.Release();

-

-  _encrypted = false;

-  _position = 0;

-  _isSplit = false;

-  

-  _curSize = 0;

-  _curSizeDefined = false;

-  _fileLengthWasSet = false;

-  _index = index;

-

-  _diskFilePath.Empty();

-

-  // _fi.Clear();

-

-  #ifdef SUPPORT_LINKS

-  // _CopyFile_Path.Empty();

-  linkPath.Empty();

-  #endif

-

-  IInArchive *archive = _arc->Archive;

-

-  #ifndef _SFX

-  _item._use_baseParentFolder_mode = _use_baseParentFolder_mode;

-  if (_use_baseParentFolder_mode)

-  {

-    _item._baseParentFolder = _baseParentFolder;

-    if (_pathMode == NExtract::NPathMode::kFullPaths ||

-        _pathMode == NExtract::NPathMode::kAbsPaths)

-      _item._baseParentFolder = -1;

-  }

-  #endif

-

-  #ifdef SUPPORT_ALT_STREAMS

-  _item.WriteToAltStreamIfColon = _ntOptions.WriteToAltStreamIfColon;

-  #endif

-

-  RINOK(_arc->GetItem(index, _item));

-

-  {

-    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

-  

-  // bool isCopyLink = false;

-  bool isHardLink = false;

-  bool isJunction = false;

-  bool isRelative = false;

-

-  {

-    NCOM::CPropVariant prop;

-    RINOK(archive->GetProperty(index, kpidHardLink, &prop));

-    if (prop.vt == VT_BSTR)

-    {

-      isHardLink = true;

-      // isCopyLink = false;

-      isRelative = false; // RAR5, TAR: hard links are from root folder of archive

-      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)

-    {

-      isHardLink = false;

-      isCopyLink = true;

-      isRelative = false; // RAR5: copy links are from root folder of archive

-      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)

-    {

-      isHardLink = false;

-      // isCopyLink = false;

-      isRelative = true; // RAR5, TAR: symbolic links can be relative

-      linkPath.SetFromBstr(prop.bstrVal);

-    }

-    else if (prop.vt != VT_EMPTY)

-      return E_FAIL;

-  }

-

-

-  bool isOkReparse = false;

-

-  if (linkPath.IsEmpty() && _arc->GetRawProps)

-  {

-    const void *data;

-    UInt32 dataSize;

-    UInt32 propType;

-    

-    _arc->GetRawProps->GetRawProp(_index, kpidNtReparse, &data, &dataSize, &propType);

-    

-    if (dataSize != 0)

-    {

-      if (propType != NPropDataType::kRaw)

-        return E_FAIL;

-      UString s;

-      CReparseAttr reparse;

-      DWORD errorCode = 0;

-      isOkReparse = reparse.Parse((const Byte *)data, dataSize, errorCode);

-      if (isOkReparse)

-      {

-        isHardLink = false;

-        // isCopyLink = false;

-        linkPath = reparse.GetPath();

-        isJunction = reparse.IsMountPoint();

-        isRelative = reparse.IsRelative();

-        #ifndef _WIN32

-        linkPath.Replace(L'\\', WCHAR_PATH_SEPARATOR);

-        #endif

-      }

-    }

-  }

-

-  if (!linkPath.IsEmpty())

-  {

-    #ifdef _WIN32

-    linkPath.Replace(L'/', WCHAR_PATH_SEPARATOR);

-    #endif

-

-    // rar5 uses "\??\" prefix for absolute links

-    if (linkPath.IsPrefixedBy(WSTRING_PATH_SEPARATOR L"??" WSTRING_PATH_SEPARATOR))

-    {

-      isRelative = false;

-      linkPath.DeleteFrontal(4);

-    }

-    

-    for (;;)

-    // while (NName::IsAbsolutePath(linkPath))

-    {

-      unsigned n = NName::GetRootPrefixSize(linkPath);

-      if (n == 0)

-        break;

-      isRelative = false;

-      linkPath.DeleteFrontal(n);

-    }

-  }

-

-  if (!linkPath.IsEmpty() && !isRelative && _removePathParts.Size() != 0)

-  {

-    UStringVector pathParts;

-    SplitPathToParts(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());

-    linkPath = MakePathFromParts(pathParts);

-  }

-

-  #endif

-  

-  RINOK(Archive_GetItemBoolProp(archive, index, kpidEncrypted, _encrypted));

-

-  RINOK(GetUnpackSize());

-

-  #ifdef SUPPORT_ALT_STREAMS

-  

-  if (!_ntOptions.AltStreams.Val && _item.IsAltStream)

-    return S_OK;

-

-  #endif

-

-

-  UStringVector &pathParts = _item.PathParts;

-

-  if (_wildcardCensor)

-  {

-    if (!CensorNode_CheckPath(*_wildcardCensor, _item))

-      return S_OK;

-  }

-

-  #ifndef _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

-  {

-    if (pathParts.IsEmpty())

-    {

-      if (_item.IsDir)

-        return S_OK;

-      /*

-      #ifdef SUPPORT_ALT_STREAMS

-      if (!_item.IsAltStream)

-      #endif

-        return E_FAIL;

-      */

-    }

-

-    unsigned numRemovePathParts = 0;

-    

-    switch (_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();

-        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::kFullPaths:

-      case NExtract::NPathMode::kAbsPaths:

-        break;

-      */

-    }

-    

-    pathParts.DeleteFrontal(numRemovePathParts);

-  }

-

-  #ifndef _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 += ':';

-      name += _item.AltStreamName;

-    }

-    #endif

-

-    return ExtractToStreamCallback->GetStream7(name, BoolToInt(_item.IsDir), outStream, askExtractMode, GetProp);

-  }

-

-  #endif

-

-  CMyComPtr<ISequentialOutStream> outStreamLoc;

-

-if (askExtractMode == NArchive::NExtract::NAskMode::kExtract && !_testMode)

-{

-  if (_stdOutMode)

-  {

-    outStreamLoc = new CStdOutFileStream;

-  }

-  else

-  {

-    {

-      NCOM::CPropVariant prop;

-      RINOK(archive->GetProperty(index, kpidAttrib, &prop));

-      if (prop.vt == VT_UI4)

-      {

-        _fi.Attrib = prop.ulVal;

-        _fi.AttribDefined = true;

-      }

-      else if (prop.vt == VT_EMPTY)

-        _fi.AttribDefined = false;

-      else

-        return E_FAIL;

-    }

-

-    RINOK(GetTime(index, kpidCTime, _fi.CTime, _fi.CTimeDefined));

-    RINOK(GetTime(index, kpidATime, _fi.ATime, _fi.ATimeDefined));

-    RINOK(GetTime(index, kpidMTime, _fi.MTime, _fi.MTimeDefined));

-

-    bool isAnti = false;

-    RINOK(_arc->IsItemAnti(index, isAnti));

-

-    #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;

-      }

-      else if (_pathMode == NExtract::NPathMode::kAbsPaths &&

-          NWildcard::GetNumPrefixParts_if_DrivePath(pathParts) == pathParts.Size())

-        pathParts.AddNew();

-

-      UString &name = pathParts.Back();

-      if (needColon)

-        name += (char)(_ntOptions.ReplaceColonForAltStream ? '_' : ':');

-      name += s;

-    }

-    

-    #endif

-

-    UString processedPath (MakePathFromParts(pathParts));

-    

-    if (!isAnti)

-    {

-      if (!_item.IsDir)

-      {

-        if (!pathParts.IsEmpty())

-          pathParts.DeleteBack();

-      }

-    

-      if (!pathParts.IsEmpty())

-      {

-        FString fullPathNew;

-        CreateComplexDirectory(pathParts, fullPathNew);

-        

-        if (_item.IsDir)

-        {

-          CDirPathTime &pt = _extractedFolders.AddNew();

-          

-          pt.CTime = _fi.CTime;

-          pt.CTimeDefined = (WriteCTime && _fi.CTimeDefined);

-          

-          pt.ATime = _fi.ATime;

-          pt.ATimeDefined = (WriteATime && _fi.ATimeDefined);

-          

-          pt.MTimeDefined = false;

-

-          if (WriteMTime)

-          {

-            if (_fi.MTimeDefined)

-            {

-              pt.MTime = _fi.MTime;

-              pt.MTimeDefined = true;

-            }

-            else if (_arc->MTimeDefined)

-            {

-              pt.MTime = _arc->MTime;

-              pt.MTimeDefined = true;

-            }

-          }

-

-          pt.Path = fullPathNew;

-

-          pt.SetDirTime();

-        }

-      }

-    }

-

-

-    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)

-    {

-      int renIndex = _renamedFiles.FindInSorted(CIndexToPathPair(_item.ParentIndex));

-      if (renIndex >= 0)

-      {

-        const CIndexToPathPair &pair = _renamedFiles[renIndex];

-        fullProcessedPath = pair.Path;

-        fullProcessedPath += ':';

-        UString s (_item.AltStreamName);

-        Correct_AltStream_Name(s);

-        fullProcessedPath += us2fs(s);

-      }

-    }

-    

-    #endif

-

-    bool isRenamed = false;

-

-    if (_item.IsDir)

-    {

-      _diskFilePath = fullProcessedPath;

-      if (isAnti)

-        RemoveDir(_diskFilePath);

-      #ifdef SUPPORT_LINKS

-      if (linkPath.IsEmpty())

-      #endif

-        return S_OK;

-    }

-    else if (!_isSplit)

-    {

-    

-    // ----- Is file (not split) -----

-    NFind::CFileInfo fileInfo;

-    if (fileInfo.Find(fullProcessedPath))

-    {

-      switch (_overwriteMode)

-      {

-        case NExtract::NOverwriteMode::kSkip:

-          return S_OK;

-        case NExtract::NOverwriteMode::kAsk:

-        {

-          int slashPos = fullProcessedPath.ReverseFind_PathSepar();

-          FString realFullProcessedPath (fullProcessedPath.Left(slashPos + 1) + fileInfo.Name);

-

-          Int32 overwriteResult;

-          RINOK(_extractCallback2->AskOverwrite(

-              fs2us(realFullProcessedPath), &fileInfo.MTime, &fileInfo.Size, _item.Path,

-              _fi.MTimeDefined ? &_fi.MTime : NULL,

-              _curSizeDefined ? &_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;

-          }

-        }

-      }

-      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 raname folders. So it's OK to use it for folders too

-        if (!MyMoveFile(fullProcessedPath, existPath))

-        {

-          RINOK(SendMessageError2(kCantRenameFile, existPath, fullProcessedPath));

-          return E_FAIL;

-        }

-      }

-      else

-      {

-        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

-        {

-          bool needDelete = true;

-          if (needDelete)

-          {

-            if (NFind::DoesFileExist(fullProcessedPath))

-            if (!DeleteFileAlways(fullProcessedPath))

-            if (GetLastError() != ERROR_FILE_NOT_FOUND)

-            {

-              RINOK(SendMessageError_with_LastError(kCantDeleteOutputFile, fullProcessedPath));

-              return S_OK;

-              // return E_FAIL;

-            }

-          }

-        }

-      }

-    }

-    else // not Find(fullProcessedPath)

-    {

-      // we need to clear READ-ONLY of parent before creating alt stream

-      #if defined(_WIN32) && !defined(UNDER_CE)

-      int colonPos = NName::FindAltStreamColon(fullProcessedPath);

-      if (colonPos >= 0 && fullProcessedPath[(unsigned)colonPos + 1] != 0)

-      {

-        FString parentFsPath (fullProcessedPath);

-        parentFsPath.DeleteFrom(colonPos);

-        NFind::CFileInfo parentFi;

-        if (parentFi.Find(parentFsPath))

-        {

-          if (parentFi.IsReadOnly())

-            SetFileAttrib(parentFsPath, parentFi.Attrib & ~FILE_ATTRIBUTE_READONLY);

-        }

-      }

-      #endif

-    }

-    // ----- END of code for    Is file (not split) -----

-

-    }

-    _diskFilePath = fullProcessedPath;

-    

-

-    if (!isAnti)

-    {

-      #ifdef SUPPORT_LINKS

-

-      if (!linkPath.IsEmpty())

-      {

-        #ifndef UNDER_CE

-

-        UString relatPath;

-        if (isRelative)

-          relatPath = GetDirPrefixOf(_item.Path);

-        relatPath += linkPath;

-        

-        if (!IsSafePath(relatPath))

-        {

-          RINOK(SendMessageError("Dangerous link path was ignored", us2fs(relatPath)));

-        }

-        else

-        {

-          FString existPath;

-          if (isHardLink /* || isCopyLink */ || !isRelative)

-          {

-            if (!NName::GetFullPath(_dirPathPrefix_Full, us2fs(relatPath), existPath))

-            {

-              RINOK(SendMessageError("Incorrect path", us2fs(relatPath)));

-            }

-          }

-          else

-          {

-            existPath = us2fs(linkPath);

-          }

-          

-          if (!existPath.IsEmpty())

-          {

-            if (isHardLink /* || isCopyLink */)

-            {

-              // if (isHardLink)

-              {

-                if (!MyCreateHardLink(fullProcessedPath, existPath))

-                {

-                  RINOK(SendMessageError2(kCantCreateHardLink, fullProcessedPath, existPath));

-                  // return S_OK;

-                }

-              }

-              /*

-              else

-              {

-                NFind::CFileInfo fi;

-                if (!fi.Find(existPath))

-                {

-                  RINOK(SendMessageError2("Can not find the file for copying", existPath, fullProcessedPath));

-                }

-                else

-                {

-                  if (_curSizeDefined && _curSize == fi.Size)

-                    _CopyFile_Path = existPath;

-                  else

-                  {

-                    RINOK(SendMessageError2("File size collision for file copying", existPath, fullProcessedPath));

-                  }

-

-                  // RINOK(MyCopyFile(existPath, fullProcessedPath));

-                }

-              }

-              */

-            }

-            else if (_ntOptions.SymLinks.Val)

-            {

-              // bool isSymLink = true; // = false for junction

-              if (_item.IsDir && !isRelative)

-              {

-                // if it's before Vista we use Junction Point

-                // isJunction = true;

-                // convertToAbs = true;

-              }

-              

-              CByteBuffer data;

-              if (FillLinkData(data, fs2us(existPath), !isJunction))

-              {

-                CReparseAttr attr;

-                DWORD errorCode = 0;

-                if (!attr.Parse(data, data.Size(), errorCode))

-                {

-                  RINOK(SendMessageError("Internal error for symbolic link file", us2fs(_item.Path)));

-                  // return E_FAIL;

-                }

-                else

-                if (!NFile::NIO::SetReparseData(fullProcessedPath, _item.IsDir, data, (DWORD)data.Size()))

-                {

-                  RINOK(SendMessageError_with_LastError(kCantCreateSymLink, fullProcessedPath));

-                }

-              }

-            }

-          }

-        }

-        

-        #endif

-      }

-      

-      if (linkPath.IsEmpty() /* || !_CopyFile_Path.IsEmpty() */)

-      #endif // SUPPORT_LINKS

-      {

-        bool needWriteFile = true;

-        

-        #ifdef SUPPORT_LINKS

-        if (!_hardLinks.IDs.IsEmpty() && !_item.IsAltStream)

-        {

-          CHardLinkNode h;

-          bool defined;

-          RINOK(Archive_Get_HardLinkNode(archive, index, h, defined));

-          if (defined)

-          {

-            {

-              int linkIndex = _hardLinks.IDs.FindInSorted2(h);

-              if (linkIndex >= 0)

-              {

-                FString &hl = _hardLinks.Links[linkIndex];

-                if (hl.IsEmpty())

-                  hl = fullProcessedPath;

-                else

-                {

-                  if (!MyCreateHardLink(fullProcessedPath, hl))

-                  {

-                    RINOK(SendMessageError2(kCantCreateHardLink, fullProcessedPath, hl));

-                    return S_OK;

-                  }

-                  needWriteFile = false;

-                }

-              }

-            }

-          }

-        }

-        #endif

-        

-        if (needWriteFile)

-        {

-          _outFileStreamSpec = new COutFileStream;

-          CMyComPtr<ISequentialOutStream> outStreamLoc2(_outFileStreamSpec);

-          if (!_outFileStreamSpec->Open(fullProcessedPath, _isSplit ? OPEN_ALWAYS: CREATE_ALWAYS))

-          {

-            // if (::GetLastError() != ERROR_FILE_EXISTS || !isSplit)

-            {

-              RINOK(SendMessageError_with_LastError(kCantOpenOutFile, fullProcessedPath));

-              return S_OK;

-            }

-          }

-

-          if (_ntOptions.PreAllocateOutFile && !_isSplit && _curSizeDefined && _curSize > (1 << 12))

-          {

-            // UInt64 ticks = GetCpuTicks();

-            bool res = _outFileStreamSpec->File.SetLength(_curSize);

-            _fileLengthWasSet = 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->File.SeekToBegin();

-            if (!res)

-            {

-              RINOK(SendMessageError_with_LastError("Can not seek to begin of file", fullProcessedPath));

-            }

-          }

-

-          #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

-

-          if (_isSplit)

-          {

-            RINOK(_outFileStreamSpec->Seek(_position, STREAM_SEEK_SET, NULL));

-          }

-         

-          _outFileStream = outStreamLoc2;

-        }

-      }

-    }

-    

-    outStreamLoc = _outFileStream;

-  }

-}

-

-  #ifndef _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

-

-  

-  if (outStreamLoc)

-  {

-    /*

-    #ifdef SUPPORT_LINKS

-    

-    if (!_CopyFile_Path.IsEmpty())

-    {

-      RINOK(PrepareOperation(askExtractMode));

-      RINOK(MyCopyFile(outStreamLoc));

-      return SetOperationResult(NArchive::NExtract::NOperationResult::kOK);

-    }

-

-    if (isCopyLink && _testMode)

-      return S_OK;

-    

-    #endif

-    */

-

-    *outStream = outStreamLoc.Detach();

-  }

-  

-  return S_OK;

-

-  COM_TRY_END

-}

-

-

-STDMETHODIMP CArchiveExtractCallback::PrepareOperation(Int32 askExtractMode)

-{

-  COM_TRY_BEGIN

-

-  #ifndef _SFX

-  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;

-  };

-  

-  return _extractCallback2->PrepareOperation(_item.Path, BoolToInt(_item.IsDir),

-      askExtractMode, _isSplit ? &_position: 0);

-  

-  COM_TRY_END

-}

-

-

-HRESULT CArchiveExtractCallback::CloseFile()

-{

-  if (!_outFileStream)

-    return S_OK;

-  

-  HRESULT hres = S_OK;

-  _outFileStreamSpec->SetTime(

-      (WriteCTime && _fi.CTimeDefined) ? &_fi.CTime : NULL,

-      (WriteATime && _fi.ATimeDefined) ? &_fi.ATime : NULL,

-      (WriteMTime && _fi.MTimeDefined) ? &_fi.MTime : (_arc->MTimeDefined ? &_arc->MTime : NULL));

-  

-  const UInt64 processedSize = _outFileStreamSpec->ProcessedSize;

-  if (_fileLengthWasSet && _curSize > processedSize)

-  {

-    bool res = _outFileStreamSpec->File.SetLength(processedSize);

-    _fileLengthWasSet = res;

-    if (!res)

-      hres = SendMessageError_with_LastError(kCantSetFileLen, us2fs(_item.Path));

-  }

-  _curSize = processedSize;

-  _curSizeDefined = true;

-  RINOK(_outFileStreamSpec->Close());

-  _outFileStream.Release();

-  return hres;

-}

-

-

-STDMETHODIMP CArchiveExtractCallback::SetOperationResult(Int32 opRes)

-{

-  COM_TRY_BEGIN

-

-  #ifndef _SFX

-  if (ExtractToStreamCallback)

-    return ExtractToStreamCallback->SetOperationResult7(opRes, BoolToInt(_encrypted));

-  #endif

-

-  #ifndef _SFX

-

-  if (_hashStreamWasUsed)

-  {

-    _hashStreamSpec->_hash->Final(_item.IsDir,

-        #ifdef SUPPORT_ALT_STREAMS

-          _item.IsAltStream

-        #else

-          false

-        #endif

-        , _item.Path);

-    _curSize = _hashStreamSpec->GetSize();

-    _curSizeDefined = true;

-    _hashStreamSpec->ReleaseStream();

-    _hashStreamWasUsed = false;

-  }

-

-  #endif

-

-  RINOK(CloseFile());

-  

-  #ifdef _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 *)data);

-      }

-    }

-  }

-  #endif

-

-  if (!_curSizeDefined)

-    GetUnpackSize();

-  

-  if (_curSizeDefined)

-  {

-    #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 (!_stdOutMode && _extractMode && _fi.AttribDefined)

-    SetFileAttrib_PosixHighDetect(_diskFilePath, _fi.Attrib);

-  

-  RINOK(_extractCallback2->SetOperationResult(opRes, BoolToInt(_encrypted)));

-  

-  return S_OK;

-  

-  COM_TRY_END

-}

-

-STDMETHODIMP 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;

-}

-

-

-STDMETHODIMP CArchiveExtractCallback::CryptoGetTextPassword(BSTR *password)

-{

-  COM_TRY_BEGIN

-  if (!_cryptoGetTextPassword)

-  {

-    RINOK(_extractCallback2.QueryInterface(IID_ICryptoGetTextPassword,

-        &_cryptoGetTextPassword));

-  }

-  return _cryptoGetTextPassword->CryptoGetTextPassword(password);

-  COM_TRY_END

-}

-

-

-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()

-{

-  return NDir::SetDirTime(Path,

-      CTimeDefined ? &CTime : NULL,

-      ATimeDefined ? &ATime : NULL,

-      MTimeDefined ? &MTime : NULL);

-}

-

-

-HRESULT CArchiveExtractCallback::SetDirsTimes()

-{

-  if (!_arc)

-    return S_OK;

-

-  CRecordVector<CDirPathSortPair> 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();

-  

-  for (i = 0; i < pairs.Size(); i++)

-  {

-    _extractedFolders[pairs[i].Index].SetDirTime();

-    // if (!) return GetLastError();

-  }

-

-  ClearExtractedDirsInfo();

-  return S_OK;

-}

-

-

-HRESULT CArchiveExtractCallback::CloseArc()

-{

-  HRESULT res = CloseFile();

-  HRESULT res2 = SetDirsTimes();

-  if (res == S_OK)

-    res = res2;

-  _arc = NULL;

-  return res;

-}

+// ArchiveExtractCallback.cpp
+
+#include "StdAfx.h"
+
+#undef sprintf
+#undef printf
+
+// #include <stdio.h>
+// #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";
+static const char * const kCantOpenInFile = "Cannot open input file";
+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 += (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();
+}
+
+static bool WriteZoneFile(CFSTR fileName, const CByteBuffer &buf)
+{
+  NIO::COutFile file;
+  if (!file.Create(fileName, true))
+    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<UInt32> *realIndices)
+{
+  _hardLinks.Clear();
+
+  if (!_arc->Ask_INode)
+    return S_OK;
+  
+  IInArchive *archive = _arc->Archive;
+  CRecordVector<CHardLinkNode> &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),
+    _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
+
+    // bool res =
+    CreateDir(fullPath);
+    // if (!res)
+    if (isFinalDir)
+    {
+      if (!NFile::NFind::DoesDirExist(fullPath))
+      {
+        _itemFailure = true;
+        SendMessageError("Cannot create folder", fullPath);
+        // SendMessageError_with_LastError()
+      }
+    }
+  }
+}
+
+
+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_LastError(const char *message, const FString &path)
+{
+  DWORD errorCode = GetLastError();
+  if (errorCode == 0)
+    errorCode = (DWORD)E_FAIL;
+  UString s (message);
+  {
+    s += " : ";
+    s += NError::MyFormatMessage(errorCode);
+  }
+  AddPathToMessage(s, path);
+  return _extractCallback2->MessageError(s);
+}
+
+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 += ':';
+  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 += (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;
+
+  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();
+  }
+    
+  if (pathParts.IsEmpty())
+    return;
+
+  FString fullPathNew;
+  CreateComplexDirectory(pathParts, fullPathNew);
+        
+  if (!_item.IsDir)
+    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<ISequentialOutStream> &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 += ':';
+      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))
+          {
+            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<IOutStream> outFileStream_Loc(_outFileStreamSpec);
+  
+  if (!_outFileStreamSpec->Open(fullProcessedPath, _isSplit ? OPEN_ALWAYS: CREATE_ALWAYS))
+  {
+    // 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;
+
+  #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;
+  }
+
+
+  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 (_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();
+        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 += ':';
+      name += _item.AltStreamName;
+    }
+    #endif
+
+    return ExtractToStreamCallback->GetStream7(name, BoolToInt(_item.IsDir), outStream, askExtractMode, GetProp);
+  }
+
+  #endif // Z7_SFX
+
+
+  CMyComPtr<ISequentialOutStream> 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 (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;
+  }
+  
+  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
+      const FString path = _diskFilePath + k_ZoneId_StreamName;
+      if (!WriteZoneFile(path, 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))
+      }
+      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
+}
+
+
+// ---------- 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<ISequentialInStream> 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
+}
+
+
+// ------------ 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<CDirPathSortPair> 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 af38f13..5ed20f3 100644
--- a/CPP/7zip/UI/Common/ArchiveExtractCallback.h
+++ b/CPP/7zip/UI/Common/ArchiveExtractCallback.h
@@ -1,403 +1,584 @@
-// ArchiveExtractCallback.h

-

-#ifndef __ARCHIVE_EXTRACT_CALLBACK_H

-#define __ARCHIVE_EXTRACT_CALLBACK_H

-

-#include "../../../Common/MyCom.h"

-#include "../../../Common/Wildcard.h"

-

-#include "../../IPassword.h"

-

-#include "../../Common/FileStreams.h"

-#include "../../Common/ProgressUtils.h"

-

-#include "../../Archive/IArchive.h"

-

-#include "ExtractMode.h"

-#include "IFileExtractCallback.h"

-#include "OpenArchive.h"

-

-#include "HashCalc.h"

-

-#ifndef _SFX

-

-class COutStreamWithHash:

-  public ISequentialOutStream,

-  public CMyUnknownImp

-{

-  CMyComPtr<ISequentialOutStream> _stream;

-  UInt64 _size;

-  bool _calculate;

-public:

-  IHashCalc *_hash;

-

-  MY_UNKNOWN_IMP

-  STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);

-  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 HardLinks;

-  CBoolPair AltStreams;

-  bool ReplaceColonForAltStream;

-  bool WriteToAltStreamIfColon;

-

-  bool PreAllocateOutFile;

-

-  CExtractNtOptions():

-      ReplaceColonForAltStream(false),

-      WriteToAltStreamIfColon(false)

-  {

-    SymLinks.Val = true;

-    HardLinks.Val = true;

-    AltStreams.Val = true;

-    

-    PreAllocateOutFile =

-      #ifdef _WIN32

-        true;

-      #else

-        false;

-      #endif

-  }

-};

-

-#ifndef _SFX

-

-class CGetProp:

-  public IGetProp,

-  public CMyUnknownImp

-{

-public:

-  const CArc *Arc;

-  UInt32 IndexInArc;

-  // UString Name; // relative path

-

-  MY_UNKNOWN_IMP1(IGetProp)

-  INTERFACE_IGetProp(;)

-};

-

-#endif

-

-#ifndef _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<CHardLinkNode> IDs;

-  CObjectVector<FString> 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 CDirPathTime

-{

-  FILETIME CTime;

-  FILETIME ATime;

-  FILETIME MTime;

-

-  bool CTimeDefined;

-  bool ATimeDefined;

-  bool MTimeDefined;

-

-  FString Path;

-  

-  bool SetDirTime();

-};

-

-

-

-class CArchiveExtractCallback:

-  public IArchiveExtractCallback,

-  public IArchiveExtractCallbackMessage,

-  public ICryptoGetTextPassword,

-  public ICompressProgressInfo,

-  public CMyUnknownImp

-{

-  const CArc *_arc;

-  CExtractNtOptions _ntOptions;

-

-  const NWildcard::CCensorNode *_wildcardCensor; // we need wildcard for single pass mode (stdin)

-  CMyComPtr<IFolderArchiveExtractCallback> _extractCallback2;

-  CMyComPtr<ICompressProgressInfo> _compressProgress;

-  CMyComPtr<ICryptoGetTextPassword> _cryptoGetTextPassword;

-  CMyComPtr<IArchiveExtractCallbackMessage> _callbackMessage;

-  CMyComPtr<IFolderArchiveExtractCallback2> _folderArchiveExtractCallback2;

-

-  FString _dirPathPrefix;

-  FString _dirPathPrefix_Full;

-  NExtract::NPathMode::EEnum _pathMode;

-  NExtract::NOverwriteMode::EEnum _overwriteMode;

-  bool _keepAndReplaceEmptyDirPrefixes; // replace them to "_";

-

-  #ifndef _SFX

-

-  CMyComPtr<IFolderExtractToStreamCallback> ExtractToStreamCallback;

-  CGetProp *GetProp_Spec;

-  CMyComPtr<IGetProp> GetProp;

-  

-  #endif

-

-  CReadArcItem _item;

-  FString _diskFilePath;

-  UInt64 _position;

-  bool _isSplit;

-

-  bool _extractMode;

-

-  bool WriteCTime;

-  bool WriteATime;

-  bool WriteMTime;

-

-  bool _encrypted;

-

-  struct CProcessedFileInfo

-  {

-    FILETIME CTime;

-    FILETIME ATime;

-    FILETIME MTime;

-    UInt32 Attrib;

-  

-    bool CTimeDefined;

-    bool ATimeDefined;

-    bool MTimeDefined;

-    bool AttribDefined;

-  } _fi;

-

-  UInt32 _index;

-  UInt64 _curSize;

-  bool _curSizeDefined;

-  bool _fileLengthWasSet;

-  COutFileStream *_outFileStreamSpec;

-  CMyComPtr<ISequentialOutStream> _outFileStream;

-

-  #ifndef _SFX

-  

-  COutStreamWithHash *_hashStreamSpec;

-  CMyComPtr<ISequentialOutStream> _hashStream;

-  bool _hashStreamWasUsed;

-  

-  #endif

-

-  bool _removePartsForAltStreams;

-  UStringVector _removePathParts;

-  

-  #ifndef _SFX

-  bool _use_baseParentFolder_mode;

-  UInt32 _baseParentFolder;

-  #endif

-

-  bool _stdOutMode;

-  bool _testMode;

-  bool _multiArchives;

-

-  CMyComPtr<ICompressProgressInfo> _localProgress;

-  UInt64 _packTotal;

-  

-  UInt64 _progressTotal;

-  bool _progressTotal_Defined;

-

-  CObjectVector<CDirPathTime> _extractedFolders;

-

-  #if defined(_WIN32) && !defined(UNDER_CE) && !defined(_SFX)

-  bool _saclEnabled;

-  #endif

-

-  void CreateComplexDirectory(const UStringVector &dirPathParts, FString &fullPath);

-  HRESULT GetTime(UInt32 index, PROPID propID, FILETIME &filetime, bool &filetimeIsDefined);

-  HRESULT GetUnpackSize();

-

-  HRESULT SendMessageError(const char *message, const FString &path);

-  HRESULT SendMessageError_with_LastError(const char *message, const FString &path);

-  HRESULT SendMessageError2(const char *message, const FString &path1, const FString &path2);

-

-public:

-

-  CLocalProgress *LocalProgressSpec;

-

-  UInt64 NumFolders;

-  UInt64 NumFiles;

-  UInt64 NumAltStreams;

-  UInt64 UnpackSize;

-  UInt64 AltStreams_UnpackSize;

-  

-  MY_UNKNOWN_IMP3(IArchiveExtractCallbackMessage, ICryptoGetTextPassword, ICompressProgressInfo)

-

-  INTERFACE_IArchiveExtractCallback(;)

-  INTERFACE_IArchiveExtractCallbackMessage(;)

-

-  STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);

-

-  STDMETHOD(CryptoGetTextPassword)(BSTR *password);

-

-  CArchiveExtractCallback();

-

-  void InitForMulti(bool multiArchives,

-      NExtract::NPathMode::EEnum pathMode,

-      NExtract::NOverwriteMode::EEnum overwriteMode,

-      bool keepAndReplaceEmptyDirPrefixes)

-  {

-    _multiArchives = multiArchives;

-    _pathMode = pathMode;

-    _overwriteMode = overwriteMode;

-    _keepAndReplaceEmptyDirPrefixes = keepAndReplaceEmptyDirPrefixes;

-    NumFolders = NumFiles = NumAltStreams = UnpackSize = AltStreams_UnpackSize = 0;

-  }

-

-  #ifndef _SFX

-

-  void SetHashMethods(IHashCalc *hash)

-  {

-    if (!hash)

-      return;

-    _hashStreamSpec = new COutStreamWithHash;

-    _hashStream = _hashStreamSpec;

-    _hashStreamSpec->_hash = hash;

-  }

-

-  #endif

-

-  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;

-  UString linkPath;

-

-  // FString _CopyFile_Path;

-  // HRESULT MyCopyFile(ISequentialOutStream *outStream);

-

-public:

-  // call PrepareHardLinks() after Init()

-  HRESULT PrepareHardLinks(const CRecordVector<UInt32> *realIndices);  // NULL means all items

-

-  #endif

-

-

-  #ifdef SUPPORT_ALT_STREAMS

-  CObjectVector<CIndexToPathPair> _renamedFiles;

-  #endif

-

-  // call it after Init()

-

-  #ifndef _SFX

-  void SetBaseParentFolderIndex(UInt32 indexInArc)

-  {

-    _baseParentFolder = indexInArc;

-    _use_baseParentFolder_mode = true;

-  }

-  #endif

-

-  HRESULT CloseArc();

-

-private:

-  void ClearExtractedDirsInfo()

-  {

-    _extractedFolders.Clear();

-  }

-

-  HRESULT CloseFile();

-  HRESULT SetDirsTimes();

-};

-

-

-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);

-

-#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
+)
+  CMyComPtr<ISequentialOutStream> _stream;
+  UInt64 _size;
+  bool _calculate;
+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;
+
+  CExtractNtOptions():
+      ReplaceColonForAltStream(false),
+      WriteToAltStreamIfColon(false),
+      ExtractOwner(false),
+      PreserveATime(false),
+      OpenShareForWrite(false)
+  {
+    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<CHardLinkNode> IDs;
+  CObjectVector<FString> 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,
+  public IArchiveUpdateCallbackFile,
+  public IArchiveGetDiskProperty,
+  public CMyUnknownImp
+{
+  Z7_COM_UNKNOWN_IMP_5(
+      /* IArchiveExtractCallback, */
+      IArchiveExtractCallbackMessage2,
+      ICryptoGetTextPassword,
+      ICompressProgressInfo,
+      IArchiveUpdateCallbackFile,
+      IArchiveGetDiskProperty)
+
+  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)
+  Z7_IFACE_COM7_IMP(IArchiveUpdateCallbackFile)
+  Z7_IFACE_COM7_IMP(IArchiveGetDiskProperty)
+
+  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 _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<IFolderArchiveExtractCallback> _extractCallback2;
+  // CMyComPtr<ICompressProgressInfo> _compressProgress;
+  // CMyComPtr<IArchiveExtractCallbackMessage2> _callbackMessage;
+  CMyComPtr<IFolderArchiveExtractCallback2> _folderArchiveExtractCallback2;
+  CMyComPtr<ICryptoGetTextPassword> _cryptoGetTextPassword;
+
+  FString _dirPathPrefix;
+  FString _dirPathPrefix_Full;
+
+  #ifndef Z7_SFX
+
+  CMyComPtr<IFolderExtractToStreamCallback> ExtractToStreamCallback;
+  CGetProp *GetProp_Spec;
+  CMyComPtr<IGetProp> GetProp;
+  
+  #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<ISequentialOutStream> _outFileStream;
+
+  CByteBuffer _outMemBuf;
+  CBufPtrSeqOutStream *_bufPtrSeqOutStream_Spec;
+  CMyComPtr<ISequentialOutStream> _bufPtrSeqOutStream;
+
+
+ #ifndef Z7_SFX
+  
+  COutStreamWithHash *_hashStreamSpec;
+  CMyComPtr<ISequentialOutStream> _hashStream;
+  bool _hashStreamWasUsed;
+  
+  bool _use_baseParentFolder_mode;
+  UInt32 _baseParentFolder;
+ #endif
+
+  UStringVector _removePathParts;
+
+  CMyComPtr<ICompressProgressInfo> _localProgress;
+  UInt64 _packTotal;
+  
+  UInt64 _progressTotal;
+  bool _progressTotal_Defined;
+
+  CObjectVector<CDirPathTime> _extractedFolders;
+  
+  #ifndef _WIN32
+  // CObjectVector<NWindows::NFile::NDir::CDelayedSymLink> _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_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<UInt32> *realIndices);  // NULL means all items
+
+  #endif
+
+
+  #ifdef SUPPORT_ALT_STREAMS
+  CObjectVector<CIndexToPathPair> _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<ISequentialOutStream> &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);
+
+#endif
diff --git a/CPP/7zip/UI/Common/ArchiveName.cpp b/CPP/7zip/UI/Common/ArchiveName.cpp
index b07d46c..1c0c3a8 100644
--- a/CPP/7zip/UI/Common/ArchiveName.cpp
+++ b/CPP/7zip/UI/Common/ArchiveName.cpp
@@ -1,155 +1,176 @@
-// ArchiveName.cpp

-

-#include "StdAfx.h"

-

-#include "../../../Common/Wildcard.h"

-

-#include "../../../Windows/FileDir.h"

-#include "../../../Windows/FileName.h"

-

-#include "ExtractingFilePath.h"

-#include "ArchiveName.h"

-

-using namespace NWindows;

-using namespace NFile;

-

-static UString CreateArchiveName(const NFind::CFileInfo &fi, bool keepName)

-{

-  FString resultName = fi.Name;

-  if (!fi.IsDir() && !keepName)

-  {

-    int dotPos = resultName.ReverseFind_Dot();

-    if (dotPos > 0)

-    {

-      FString archiveName2 = resultName.Left(dotPos);

-      if (archiveName2.ReverseFind_Dot() < 0)

-        resultName = archiveName2;

-    }

-  }

-  return Get_Correct_FsFile_Name(fs2us(resultName));

-}

-

-static FString CreateArchiveName2(const FString &path, bool fromPrev, bool keepName)

-{

-  FString resultName ("Archive");

-  if (fromPrev)

-  {

-    FString dirPrefix;

-    if (NDir::GetOnlyDirPrefix(path, dirPrefix))

-    {

-      if (!dirPrefix.IsEmpty() && IsPathSepar(dirPrefix.Back()))

-      {

-        #if defined(_WIN32) && !defined(UNDER_CE)

-        if (NName::IsDriveRootPath_SuperAllowed(dirPrefix))

-          resultName = dirPrefix[dirPrefix.Len() - 3]; // only letter

-        else

-        #endif

-        {

-          dirPrefix.DeleteBack();

-          NFind::CFileInfo fi;

-          if (fi.Find(dirPrefix))

-            resultName = fi.Name;

-        }

-      }

-    }

-  }

-  else

-  {

-    NFind::CFileInfo fi;

-    if (fi.Find(path))

-    {

-      resultName = fi.Name;

-      if (!fi.IsDir() && !keepName)

-      {

-        int dotPos = resultName.ReverseFind_Dot();

-        if (dotPos > 0)

-        {

-          FString name2 = resultName.Left(dotPos);

-          if (name2.ReverseFind_Dot() < 0)

-            resultName = name2;

-        }

-      }

-    }

-  }

-  return resultName;

-}

-

-

-UString CreateArchiveName(const UStringVector &paths, const NFind::CFileInfo *fi)

-{

-  bool keepName = false;

-  /*

-  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;

-  if (fi)

-    name = CreateArchiveName(*fi, keepName);

-  else

-  {

-    if (paths.IsEmpty())

-      return L"archive";

-    bool fromPrev = (paths.Size() > 1);

-    name = Get_Correct_FsFile_Name(fs2us(CreateArchiveName2(us2fs(paths.Front()), fromPrev, keepName)));

-  }

-

-  UStringVector names;

-

-  {

-    FOR_VECTOR (i, paths)

-    {

-      NFind::CFileInfo fi2;

-      const NFind::CFileInfo *fp;

-      if (fi && paths.Size() == 1)

-        fp = fi;

-      else

-      {

-        if (!fi2.Find(us2fs(paths[i])))

-          continue;

-        fp = &fi2;

-      }

-      names.Add(fs2us(fp->Name));

-    }

-  }

-

-  UString postfix;

-  UInt32 index = 1;

-

-  for (;;)

-  {

-    // we don't want cases when we include archive to itself.

-    // so we find first available name for archive

-    const UString name2 = name + postfix;

-    const UString name2_zip = name2 + L".zip";

-    const UString name2_7z = name2 + L".7z";

-    const UString name2_tar = name2 + L".tar";

-    const UString name2_wim = name2 + L".wim";

-    

-    unsigned i = 0;

-

-    for (i = 0; i < names.Size(); i++)

-    {

-      const UString &fname = names[i];

-      if (   0 == CompareFileNames(fname, name2_zip)

-          || 0 == CompareFileNames(fname, name2_7z)

-          || 0 == CompareFileNames(fname, name2_tar)

-          || 0 == CompareFileNames(fname, name2_wim))

-        break;

-    }

-    

-    if (i == names.Size())

-      break;

-    index++;

-    postfix = "_";

-    postfix.Add_UInt32(index);

-  }

-  

-  name += postfix;

-  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<UInt32> 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.Front(), 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 += '_';
+    name.Add_UInt32(v);
+  }
+  return name;
+}
diff --git a/CPP/7zip/UI/Common/ArchiveName.h b/CPP/7zip/UI/Common/ArchiveName.h
index ce2d192..9b6b7fe 100644
--- a/CPP/7zip/UI/Common/ArchiveName.h
+++ b/CPP/7zip/UI/Common/ArchiveName.h
@@ -1,10 +1,16 @@
-// ArchiveName.h

-

-#ifndef __ARCHIVE_NAME_H

-#define __ARCHIVE_NAME_H

-

-#include "../../../Windows/FileFind.h"

-

-UString CreateArchiveName(const UStringVector &paths, const NWindows::NFile::NFind::CFileInfo *fi = NULL);

-

-#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 fd8f9f8..4e5f1f5 100644
--- a/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp
+++ b/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp
@@ -1,161 +1,393 @@
-// ArchiveOpenCallback.cpp

-

-#include "StdAfx.h"

-

-#include "../../../Common/ComTry.h"

-

-#include "../../../Windows/FileName.h"

-#include "../../../Windows/PropVariant.h"

-

-#include "../../Common/FileStreams.h"

-

-#include "ArchiveOpenCallback.h"

-

-using namespace NWindows;

-

-STDMETHODIMP 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

-}

-

-STDMETHODIMP 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

-}

-  

-STDMETHODIMP 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

-    }

-  else

-    switch (propID)

-    {

-      case kpidName:  prop = _fileInfo.Name; break;

-      case kpidIsDir:  prop = _fileInfo.IsDir(); break;

-      case kpidSize:  prop = _fileInfo.Size; break;

-      case kpidAttrib:  prop = (UInt32)_fileInfo.Attrib; break;

-      case kpidCTime:  prop = _fileInfo.CTime; break;

-      case kpidATime:  prop = _fileInfo.ATime; break;

-      case kpidMTime:  prop = _fileInfo.MTime; break;

-    }

-  prop.Detach(value);

-  return S_OK;

-  COM_TRY_END

-}

-

-struct CInFileStreamVol: public CInFileStream

-{

-  int FileNameIndex;

-  COpenCallbackImp *OpenCallbackImp;

-  CMyComPtr<IArchiveOpenCallback> OpenCallbackRef;

- 

-  ~CInFileStreamVol()

-  {

-    if (OpenCallbackRef)

-      OpenCallbackImp->FileNames_WasUsed[FileNameIndex] = false;

-  }

-};

-

-

-// from ArchiveExtractCallback.cpp

-bool IsSafePath(const UString &path);

-

-STDMETHODIMP 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 _SFX

-  

-  #ifdef _WIN32

-  name2.Replace(L'/', WCHAR_PATH_SEPARATOR);

-  #endif

-

-  // if (!allowAbsVolPaths)

-  if (!IsSafePath(name2))

-    return S_FALSE;

-

-  // #ifdef _WIN32

-  // we don't want to support wildcards in names here here

-  if (name2.Find(L'?') >= 0 ||

-      name2.Find(L'*') >= 0)

-    return S_FALSE;

-  // #endif

-

-  #endif

-

-

-  FString fullPath;

-  if (!NFile::NName::GetFullPath(_folderPrefix, us2fs(name2), fullPath))

-    return S_FALSE;

-  if (!_fileInfo.Find(fullPath))

-    return S_FALSE;

-  if (_fileInfo.IsDir())

-    return S_FALSE;

-  CInFileStreamVol *inFile = new CInFileStreamVol;

-  CMyComPtr<IInStream> inStreamTemp = inFile;

-  if (!inFile->Open(fullPath))

-  {

-    DWORD lastError = ::GetLastError();

-    if (lastError == 0)

-      return E_FAIL;

-    return HRESULT_FROM_WIN32(lastError);

-  }

-

-  FileSizes.Add(_fileInfo.Size);

-  FileNames.Add(name2);

-  inFile->FileNameIndex = FileNames_WasUsed.Add(true);

-  inFile->OpenCallbackImp = this;

-  inFile->OpenCallbackRef = this;

-  // TotalSize += _fileInfo.Size;

-  *inStream = inStreamTemp.Detach();

-  return S_OK;

-  COM_TRY_END

-}

-

-#ifndef _NO_CRYPTO

-STDMETHODIMP COpenCallbackImp::CryptoGetTextPassword(BSTR *password)

-{

-  COM_TRY_BEGIN

-  if (ReOpenCallback)

-  {

-    CMyComPtr<ICryptoGetTextPassword> getTextPassword;

-    ReOpenCallback.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword);

-    if (getTextPassword)

-      return getTextPassword->CryptoGetTextPassword(password);

-  }

-  if (!Callback)

-    return E_NOTIMPL;

-  PasswordWasAsked = true;

-  return Callback->Open_CryptoGetTextPassword(password);

-  COM_TRY_END

-}

-#endif

+// 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 <stdio.h>
+#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
+    }
+  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;
+    }
+  prop.Detach(value);
+  return S_OK;
+  COM_TRY_END
+}
+
+
+// ---------- CInFileStreamVol ----------
+
+Z7_CLASS_IMP_COM_2(
+  CInFileStreamVol
+  , IInStream
+  , IStreamGetSize
+)
+  Z7_IFACE_COM7_IMP(ISequentialInStream)
+public:
+  unsigned FileIndex;
+  COpenCallbackImp *OpenCallbackImp;
+  CMyComPtr<IArchiveOpenCallback> 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<IInStream> 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<IInStream> 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<IInStream> 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 7f7548f..4e44c9d 100644
--- a/CPP/7zip/UI/Common/ArchiveOpenCallback.h
+++ b/CPP/7zip/UI/Common/ArchiveOpenCallback.h
@@ -1,112 +1,181 @@
-// ArchiveOpenCallback.h

-

-#ifndef __ARCHIVE_OPEN_CALLBACK_H

-#define __ARCHIVE_OPEN_CALLBACK_H

-

-#include "../../../Common/MyCom.h"

-

-#include "../../../Windows/FileFind.h"

-

-#ifndef _NO_CRYPTO

-#include "../../IPassword.h"

-#endif

-#include "../../Archive/IArchive.h"

-

-#ifdef _NO_CRYPTO

-

-#define INTERFACE_IOpenCallbackUI_Crypto(x)

-

-#else

-

-#define INTERFACE_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 INTERFACE_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; \

-  INTERFACE_IOpenCallbackUI_Crypto(x)

-

-struct IOpenCallbackUI

-{

-  INTERFACE_IOpenCallbackUI(=0)

-};

-

-class COpenCallbackImp:

-  public IArchiveOpenCallback,

-  public IArchiveOpenVolumeCallback,

-  public IArchiveOpenSetSubArchiveName,

-  #ifndef _NO_CRYPTO

-  public ICryptoGetTextPassword,

-  #endif

-  public CMyUnknownImp

-{

-public:

-  MY_QUERYINTERFACE_BEGIN2(IArchiveOpenVolumeCallback)

-  MY_QUERYINTERFACE_ENTRY(IArchiveOpenSetSubArchiveName)

-  #ifndef _NO_CRYPTO

-  MY_QUERYINTERFACE_ENTRY(ICryptoGetTextPassword)

-  #endif

-  MY_QUERYINTERFACE_END

-  MY_ADDREF_RELEASE

-

-  INTERFACE_IArchiveOpenCallback(;)

-  INTERFACE_IArchiveOpenVolumeCallback(;)

-

-  #ifndef _NO_CRYPTO

-  STDMETHOD(CryptoGetTextPassword)(BSTR *password);

-  #endif

-

-  STDMETHOD(SetSubArchiveName(const wchar_t *name))

-  {

-    _subArchiveMode = true;

-    _subArchiveName = name;

-    // TotalSize = 0;

-    return S_OK;

-  }

-

-private:

-  FString _folderPrefix;

-  NWindows::NFile::NFind::CFileInfo _fileInfo;

-  bool _subArchiveMode;

-  UString _subArchiveName;

-

-public:

-  UStringVector FileNames;

-  CBoolVector FileNames_WasUsed;

-  CRecordVector<UInt64> FileSizes;

-  

-  bool PasswordWasAsked;

-

-  IOpenCallbackUI *Callback;

-  CMyComPtr<IArchiveOpenCallback> ReOpenCallback;

-  // UInt64 TotalSize;

-

-  COpenCallbackImp(): Callback(NULL), _subArchiveMode(false) {}

-  

-  void Init(const FString &folderPrefix, const FString &fileName)

-  {

-    _folderPrefix = folderPrefix;

-    if (!_fileInfo.Find(_folderPrefix + fileName))

-      throw 20121118;

-    FileNames.Clear();

-    FileNames_WasUsed.Clear();

-    FileSizes.Clear();

-    _subArchiveMode = false;

-    // TotalSize = 0;

-    PasswordWasAsked = false;

-  }

-

-  bool SetSecondFileInfo(CFSTR newName)

-  {

-    return _fileInfo.Find(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<IInStream> 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<CSubStream> 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<UInt64> 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<IArchiveOpenCallback> ReOpenCallback;
+  IOpenCallbackUI *Callback;
+  // CMyComPtr<IUnknown> Callback_Ref;
+
+private:
+  FString _folderPrefix;
+  UString _subArchiveName;
+  NWindows::NFile::NFind::CFileInfo _fileInfo;
+
+public:
+  CMultiStreams Volumes;
+  
+  // UInt64 TotalSize;
+
+  COpenCallbackImp():
+      _subArchiveMode(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 3fb0758..5da9783 100644
--- a/CPP/7zip/UI/Common/Bench.cpp
+++ b/CPP/7zip/UI/Common/Bench.cpp
@@ -1,3618 +1,4872 @@
-// Bench.cpp

-

-#include "StdAfx.h"

-

-#include <stdio.h>

-

-#ifndef _WIN32

-#define USE_POSIX_TIME

-#define USE_POSIX_TIME2

-#endif

-

-#ifdef USE_POSIX_TIME

-#include <time.h>

-#ifdef USE_POSIX_TIME2

-#include <sys/time.h>

-#endif

-#endif

-

-#ifdef _WIN32

-#define USE_ALLOCA

-#endif

-

-#ifdef USE_ALLOCA

-#ifdef _WIN32

-#include <malloc.h>

-#else

-#include <stdlib.h>

-#endif

-#endif

-

-#include "../../../../C/7zCrc.h"

-#include "../../../../C/CpuArch.h"

-

-#ifndef _7ZIP_ST

-#include "../../../Windows/Synchronization.h"

-#include "../../../Windows/Thread.h"

-#endif

-

-#if defined(_WIN32) || defined(UNIX_USE_WIN_FILE)

-#define USE_WIN_FILE

-#endif

-

-#ifdef USE_WIN_FILE

-#include "../../../Windows/FileIO.h"

-#endif

-

-

-#include "../../../Common/IntToString.h"

-#include "../../../Common/MyBuffer2.h"

-#include "../../../Common/StringConvert.h"

-#include "../../../Common/StringToInt.h"

-

-#include "../../Common/MethodProps.h"

-#include "../../Common/StreamUtils.h"

-

-#include "Bench.h"

-

-using namespace NWindows;

-

-static const UInt32 k_LZMA = 0x030101;

-

-static const UInt64 kComplexInCommands = (UInt64)1 <<

-  #ifdef UNDER_CE

-    31;

-  #else

-    34;

-  #endif

-

-static const UInt32 kComplexInSeconds = 4;

-

-static void SetComplexCommands(UInt32 complexInSeconds,

-    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 (complexInSeconds != 0)

-      complexInCommands = complexInSeconds * cpuFreq;

-    else

-      complexInCommands = cpuFreq >> 2;

-  }

-}

-

-static const unsigned kNumHashDictBits = 17;

-static const UInt32 kFilterUnpackSize = (48 << 10);

-

-static const unsigned kOldLzmaDictBits = 30;

-

-static const UInt32 kAdditionalSize = (1 << 16);

-static const UInt32 kCompressedAdditionalSize = (1 << 10);

-static const UInt32 kMaxLzmaPropSize = 5;

-

-

-

-#define ALLOC_WITH_HRESULT(_buffer_, _size_) \

-  (_buffer_)->Alloc(_size_); \

-  if (!(_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;}

-  UInt32 GetRnd()

-  {

-    return Salt ^

-    (

-      ((A1 = 36969 * (A1 & 0xffff) + (A1 >> 16)) << 16) +

-      ((A2 = 18000 * (A2 & 0xffff) + (A2 >> 16)) )

-    );

-  }

-};

-

-

-class CBenchRandomGenerator: public CAlignedBuffer

-{

-  static UInt32 GetVal(UInt32 &res, unsigned numBits)

-  {

-    UInt32 val = res & (((UInt32)1 << numBits) - 1);

-    res >>= numBits;

-    return val;

-  }

-  

-  static UInt32 GetLen(UInt32 &r)

-  {

-    UInt32 len = 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);

-    UInt32 pos = 0;

-    UInt32 rep0 = 1;

-    const size_t bufSize = Size();

-    Byte *buf = (Byte *)*this;

-    unsigned posBits = 1;

-    

-    while (pos < bufSize)

-    {

-      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 (((UInt32)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 (;;)

-          {

-            UInt32 ppp = GetVal(r, numLogBits) + kAddBits;

-            r = rg.GetRnd();

-            if (ppp > numBitsMax)

-              continue;

-            rep0 = GetVal(r, ppp);

-            if (rep0 < pos)

-              break;

-            r = rg.GetRnd();

-          }

-          rep0++;

-        }

-

-        {

-          UInt32 rem = (UInt32)bufSize - pos;

-          if (len > rem)

-            len = rem;

-        }

-        Byte *dest = buf + pos;

-        const Byte *src = dest - rep0;

-        pos += len;

-        for (UInt32 i = 0; i < len; i++)

-          *dest++ = *src++;

-      }

-    }

-  }

-};

-

-

-class CBenchmarkInStream:

-  public ISequentialInStream,

-  public CMyUnknownImp

-{

-  const Byte *Data;

-  size_t Pos;

-  size_t Size;

-public:

-  MY_UNKNOWN_IMP

-  void Init(const Byte *data, size_t size)

-  {

-    Data = data;

-    Size = size;

-    Pos = 0;

-  }

-  STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);

-};

-

-STDMETHODIMP CBenchmarkInStream::Read(void *data, UInt32 size, UInt32 *processedSize)

-{

-  size_t remain = Size - Pos;

-  UInt32 kMaxBlockSize = (1 << 20);

-  if (size > kMaxBlockSize)

-    size = kMaxBlockSize;

-  if (size > remain)

-    size = (UInt32)remain;

-  for (UInt32 i = 0; i < size; i++)

-    ((Byte *)data)[i] = Data[Pos + i];

-  Pos += size;

-  if (processedSize)

-    *processedSize = size;

-  return S_OK;

-}

-  

-class CBenchmarkOutStream:

-  public ISequentialOutStream,

-  public CAlignedBuffer,

-  public CMyUnknownImp

-{

-  // 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 Print() { printf("\n%8d %8d\n", (unsigned)BufferSize, (unsigned)Pos); }

-

-  MY_UNKNOWN_IMP

-  STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);

-};

-

-STDMETHODIMP 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)

-      Crc = CrcUpdate(Crc, data, curSize);

-    Pos += curSize;

-  }

-  if (processedSize)

-    *processedSize = (UInt32)curSize;

-  if (curSize != size)

-  {

-    // _overflow = true;

-    return E_FAIL;

-  }

-  return S_OK;

-}

-  

-class CCrcOutStream:

-  public ISequentialOutStream,

-  public CMyUnknownImp

-{

-public:

-  bool CalcCrc;

-  UInt32 Crc;

-  MY_UNKNOWN_IMP

-    

-  CCrcOutStream(): CalcCrc(true) {};

-  void Init() { Crc = CRC_INIT_VAL; }

-  STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);

-};

-

-STDMETHODIMP CCrcOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)

-{

-  if (CalcCrc)

-    Crc = CrcUpdate(Crc, data, size);

-  if (processedSize)

-    *processedSize = size;

-  return S_OK;

-}

-  

-static UInt64 GetTimeCount()

-{

-  #ifdef USE_POSIX_TIME

-  #ifdef USE_POSIX_TIME2

-  timeval v;

-  if (gettimeofday(&v, 0) == 0)

-    return (UInt64)(v.tv_sec) * 1000000 + v.tv_usec;

-  return (UInt64)time(NULL) * 1000000;

-  #else

-  return time(NULL);

-  #endif

-  #else

-  /*

-  LARGE_INTEGER value;

-  if (::QueryPerformanceCounter(&value))

-    return 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 value.QuadPart;

-  */

-  return 1000;

-  #endif

-}

-

-#ifdef USE_POSIX_TIME

-

-struct CUserTime

-{

-  UInt64 Sum;

-  clock_t Prev;

-  

-  void Init()

-  {

-    Prev = clock();

-    Sum = 0;

-  }

-

-  UInt64 GetUserTime()

-  {

-    clock_t v = clock();

-    Sum += v - Prev;

-    Prev = v;

-    return Sum;

-  }

-};

-

-#else

-

-static inline UInt64 GetTime64(const FILETIME &t) { return ((UInt64)t.dwHighDateTime << 32) | t.dwLowDateTime; }

-UInt64 GetWinUserTime()

-{

-  FILETIME creationTime, exitTime, kernelTime, userTime;

-  if (

-  #ifdef UNDER_CE

-    ::GetThreadTimes(::GetCurrentThread()

-  #else

-    ::GetProcessTimes(::GetCurrentProcess()

-  #endif

-    , &creationTime, &exitTime, &kernelTime, &userTime) != 0)

-    return GetTime64(userTime) + GetTime64(kernelTime);

-  return (UInt64)GetTickCount() * 10000;

-}

-

-struct CUserTime

-{

-  UInt64 StartTime;

-

-  void Init() { StartTime = GetWinUserTime(); }

-  UInt64 GetUserTime() { return GetWinUserTime() - StartTime; }

-};

-

-#endif

-

-static UInt64 GetUserFreq()

-{

-  #ifdef USE_POSIX_TIME

-  return CLOCKS_PER_SEC;

-  #else

-  return 10000000;

-  #endif

-}

-

-class CBenchProgressStatus

-{

-  #ifndef _7ZIP_ST

-  NSynchronization::CCriticalSection CS;

-  #endif

-public:

-  HRESULT Res;

-  bool EncodeMode;

-  void SetResult(HRESULT res)

-  {

-    #ifndef _7ZIP_ST

-    NSynchronization::CCriticalSectionLock lock(CS);

-    #endif

-    Res = res;

-  }

-  HRESULT GetResult()

-  {

-    #ifndef _7ZIP_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:

-  public ICompressProgressInfo,

-  public CMyUnknownImp,

-  public CBenchInfoCalc

-{

-public:

-  CBenchProgressStatus *Status;

-  IBenchCallback *Callback;

-

-  CBenchProgressInfo(): Callback(NULL) {}

-  MY_UNKNOWN_IMP

-  STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);

-};

-

-STDMETHODIMP CBenchProgressInfo::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)

-{

-  HRESULT res = Status->GetResult();

-  if (res != S_OK)

-    return res;

-  if (!Callback)

-    return res;

-  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 UInt32 GetLogSize(UInt32 size)

-{

-  for (unsigned i = kSubBits; i < 32; i++)

-    for (UInt32 j = 0; j < (1 << kSubBits); j++)

-      if (size <= (((UInt32)1) << i) + (j << (i - kSubBits)))

-        return (i << kSubBits) + j;

-  return (32 << kSubBits);

-}

-

-static void NormalizeVals(UInt64 &v1, UInt64 &v2)

-{

-  while (v1 > 1000000)

-  {

-    v1 >>= 1;

-    v2 >>= 1;

-  }

-}

-

-UInt64 CBenchInfo::GetUsage() const

-{

-  UInt64 userTime = UserTime;

-  UInt64 userFreq = UserFreq;

-  UInt64 globalTime = GlobalTime;

-  UInt64 globalFreq = GlobalFreq;

-  NormalizeVals(userTime, userFreq);

-  NormalizeVals(globalFreq, globalTime);

-  if (userFreq == 0)

-    userFreq = 1;

-  if (globalTime == 0)

-    globalTime = 1;

-  return userTime * globalFreq * 1000000 / userFreq / globalTime;

-}

-

-UInt64 CBenchInfo::GetRatingPerUsage(UInt64 rating) const

-{

-  UInt64 userTime = UserTime;

-  UInt64 userFreq = UserFreq;

-  UInt64 globalTime = GlobalTime;

-  UInt64 globalFreq = GlobalFreq;

-  NormalizeVals(userFreq, userTime);

-  NormalizeVals(globalTime, globalFreq);

-  if (globalFreq == 0)

-    globalFreq = 1;

-  if (userTime == 0)

-    userTime = 1;

-  return userFreq * globalTime / globalFreq * rating / userTime;

-}

-

-static UInt64 MyMultDiv64(UInt64 value, UInt64 elapsedTime, UInt64 freq)

-{

-  UInt64 elTime = elapsedTime;

-  NormalizeVals(freq, elTime);

-  if (elTime == 0)

-    elTime = 1;

-  return value * freq / elTime;

-}

-

-UInt64 CBenchInfo::GetSpeed(UInt64 numCommands) const

-{

-  return MyMultDiv64(numCommands, GlobalTime, GlobalFreq);

-}

-

-struct CBenchProps

-{

-  bool LzmaRatingMode;

-  

-  UInt32 EncComplex;

-  UInt32 DecComplexCompr;

-  UInt32 DecComplexUnc;

-

-  CBenchProps(): LzmaRatingMode(false) {}

-  void SetLzmaCompexity();

-

-  UInt64 GeComprCommands(UInt64 unpackSize)

-  {

-    return unpackSize * EncComplex;

-  }

-

-  UInt64 GeDecomprCommands(UInt64 packSize, UInt64 unpackSize)

-  {

-    return (packSize * DecComplexCompr + unpackSize * DecComplexUnc);

-  }

-

-  UInt64 GetCompressRating(UInt32 dictSize, UInt64 elapsedTime, UInt64 freq, UInt64 size);

-  UInt64 GetDecompressRating(UInt64 elapsedTime, UInt64 freq, UInt64 outSize, UInt64 inSize, UInt64 numIterations);

-};

-

-void CBenchProps::SetLzmaCompexity()

-{

-  EncComplex = 1200;

-  DecComplexUnc = 4;

-  DecComplexCompr = 190;

-  LzmaRatingMode = true;

-}

-

-UInt64 CBenchProps::GetCompressRating(UInt32 dictSize, UInt64 elapsedTime, UInt64 freq, UInt64 size)

-{

-  if (dictSize < (1 << kBenchMinDicLogSize))

-    dictSize = (1 << kBenchMinDicLogSize);

-  UInt64 encComplex = EncComplex;

-  if (LzmaRatingMode)

-  {

-    UInt64 t = GetLogSize(dictSize) - (kBenchMinDicLogSize << kSubBits);

-    encComplex = 870 + ((t * t * 5) >> (2 * kSubBits));

-  }

-  UInt64 numCommands = (UInt64)size * encComplex;

-  return MyMultDiv64(numCommands, elapsedTime, freq);

-}

-

-UInt64 CBenchProps::GetDecompressRating(UInt64 elapsedTime, UInt64 freq, UInt64 outSize, UInt64 inSize, UInt64 numIterations)

-{

-  UInt64 numCommands = (inSize * DecComplexCompr + outSize * DecComplexUnc) * numIterations;

-  return MyMultDiv64(numCommands, elapsedTime, freq);

-}

-

-UInt64 GetCompressRating(UInt32 dictSize, UInt64 elapsedTime, UInt64 freq, UInt64 size)

-{

-  CBenchProps props;

-  props.SetLzmaCompexity();

-  return props.GetCompressRating(dictSize, elapsedTime, freq, size);

-}

-

-UInt64 GetDecompressRating(UInt64 elapsedTime, UInt64 freq, UInt64 outSize, UInt64 inSize, UInt64 numIterations)

-{

-  CBenchProps props;

-  props.SetLzmaCompexity();

-  return props.GetDecompressRating(elapsedTime, freq, outSize, inSize, numIterations);

-}

-

-

-

-

-#ifndef _7ZIP_ST

-struct CBenchSyncCommon

-{

-  bool ExitMode;

-  NSynchronization::CManualResetEvent StartEvent;

-

-  CBenchSyncCommon(): ExitMode(false) {}

-};

-#endif

-

-

-struct CEncoderInfo;

-

-struct CEncoderInfo

-{

-  #ifndef _7ZIP_ST

-  NWindows::CThread thread[2];

-  NSynchronization::CManualResetEvent ReadyEvent;

-  UInt32 NumDecoderSubThreads;

-  CBenchSyncCommon *Common;

-  #endif

-

-  CMyComPtr<ICompressCoder> _encoder;

-  CMyComPtr<ICompressFilter> _encoderFilter;

-  CBenchProgressInfo *progressInfoSpec[2];

-  CMyComPtr<ICompressProgressInfo> progressInfo[2];

-  UInt64 NumIterations;

-

-  UInt32 Salt;

-

-  #ifdef USE_ALLOCA

-  size_t AllocaSize;

-  #endif

-

-  Byte _key[32];

-  Byte _iv[16];

-  Byte _psw[16];

-  bool CheckCrc_Enc;

-  bool CheckCrc_Dec;

-

-  struct CDecoderInfo

-  {

-    CEncoderInfo *Encoder;

-    UInt32 DecoderIndex;

-    bool CallbackMode;

-    

-    #ifdef USE_ALLOCA

-    size_t AllocaSize;

-    #endif

-  };

-  CDecoderInfo decodersInfo[2];

-

-  CMyComPtr<ICompressCoder> _decoders[2];

-  CMyComPtr<ICompressFilter> _decoderFilter;

-

-  HRESULT Results[2];

-  CBenchmarkOutStream *outStreamSpec;

-  CMyComPtr<ISequentialOutStream> outStream;

-  IBenchCallback *callback;

-  IBenchPrintCallback *printCallback;

-  UInt32 crc;

-  size_t kBufferSize;

-  size_t compressedSize;

-  const Byte *uncompressedDataPtr;

-

-  const Byte *fileData;

-  CBenchRandomGenerator rg;

-

-  CAlignedBuffer rgCopy; // it must be 16-byte aligned !!!

-  CBenchmarkOutStream *propStreamSpec;

-  CMyComPtr<ISequentialOutStream> propStream;

-

-  unsigned generateDictBits;

-  COneMethodInfo _method;

-  

-  // for decode

-  size_t _uncompressedDataSize;

-

-  HRESULT Generate();

-  HRESULT Encode();

-  HRESULT Decode(UInt32 decoderIndex);

-

-  CEncoderInfo():

-    #ifndef _7ZIP_ST

-    Common(NULL),

-    #endif

-    Salt(0),

-    fileData(NULL),

-    CheckCrc_Enc(true),

-    CheckCrc_Dec(true),

-    outStreamSpec(NULL), callback(NULL), printCallback(NULL), propStreamSpec(NULL) {}

-

-  #ifndef _7ZIP_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 0;

-  }

-  

-  static THREAD_FUNC_DECL DecodeThreadFunction(void *param)

-  {

-    CDecoderInfo *decoder = (CDecoderInfo *)param;

-    

-    #ifdef USE_ALLOCA

-    alloca(decoder->AllocaSize);

-    #endif

-    

-    CEncoderInfo *encoder = decoder->Encoder;

-    encoder->Results[decoder->DecoderIndex] = encoder->Decode(decoder->DecoderIndex);

-    return 0;

-  }

-

-  HRESULT CreateEncoderThread()

-  {

-    WRes res = 0;

-    if (!ReadyEvent.IsCreated())

-      res = ReadyEvent.Create();

-    if (res == 0)

-      res = thread[0].Create(EncodeThreadFunction, this);

-    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;

-    return thread[index].Create(DecodeThreadFunction, &decoder);

-  }

-  

-  #endif

-};

-

-

-HRESULT CEncoderInfo::Generate()

-{

-  const COneMethodInfo &method = _method;

-

-  // we need extra space, if input data is already compressed

-  const size_t kCompressedBufferSize =

-      kCompressedAdditionalSize +

-      kBufferSize + kBufferSize / 16;

-      // kBufferSize / 2;

-

-  if (kCompressedBufferSize < kBufferSize)

-    return E_FAIL;

-

-  uncompressedDataPtr = fileData;

-  

-  if (!fileData)

-  {

-    ALLOC_WITH_HRESULT(&rg, kBufferSize);

-    

-    // DWORD ttt = GetTickCount();

-    if (generateDictBits == 0)

-      rg.GenerateSimpleRandom(Salt);

-    else

-      rg.GenerateLz(generateDictBits, Salt);

-    // printf("\n%d\n            ", GetTickCount() - ttt);

-

-    crc = CrcCalc((const Byte *)rg, rg.Size());

-    uncompressedDataPtr = (const Byte *)rg;

-  }

-  

-  if (_encoderFilter)

-  {

-    ALLOC_WITH_HRESULT(&rgCopy, kBufferSize);

-  }

-

-

-  if (!outStream)

-  {

-    outStreamSpec = new CBenchmarkOutStream;

-    outStream = outStreamSpec;

-  }

-

-  ALLOC_WITH_HRESULT(outStreamSpec, kCompressedBufferSize)

-

-  if (!propStream)

-  {

-    propStreamSpec = new CBenchmarkOutStream;

-    propStream = propStreamSpec;

-  }

-  ALLOC_WITH_HRESULT(propStreamSpec, kMaxLzmaPropSize);

-  propStreamSpec->Init(true, false);

-  

- 

-  CMyComPtr<IUnknown> coder;

-  if (_encoderFilter)

-    coder = _encoderFilter;

-  else

-    coder = _encoder;

-  {

-    CMyComPtr<ICompressSetCoderProperties> scp;

-    coder.QueryInterface(IID_ICompressSetCoderProperties, &scp);

-    if (scp)

-    {

-      UInt64 reduceSize = kBufferSize;

-      RINOK(method.SetCoderProps(scp, &reduceSize));

-    }

-    else

-    {

-      if (method.AreThereNonOptionalProps())

-        return E_INVALIDARG;

-    }

-

-    CMyComPtr<ICompressWriteCoderProperties> writeCoderProps;

-    coder.QueryInterface(IID_ICompressWriteCoderProperties, &writeCoderProps);

-    if (writeCoderProps)

-    {

-      RINOK(writeCoderProps->WriteCoderProperties(propStream));

-    }

-

-    {

-      CMyComPtr<ICryptoSetPassword> 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<ISequentialInStream> inStream = inStreamSpec;

-          inStreamSpec->Init(temp, sizeof(temp));

-          

-          CCrcOutStream *crcStreamSpec = new CCrcOutStream;

-          CMyComPtr<ISequentialOutStream> crcStream = crcStreamSpec;

-          crcStreamSpec->Init();

-

-          RINOK(_encoder->Code(inStream, crcStream, 0, 0, NULL));

-        }

-      }

-    }

-  }

-

-  return S_OK;

-}

-

-

-static void My_FilterBench(ICompressFilter *filter, Byte *data, size_t size)

-{

-  while (size != 0)

-  {

-    UInt32 cur = (UInt32)1 << 31;

-    if (cur > size)

-      cur = (UInt32)size;

-    UInt32 processed = filter->Filter(data, cur);

-    data += processed;

-    // 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 > size || processed == 0)

-      break;

-    size -= processed;

-  }

-}

-

-

-HRESULT CEncoderInfo::Encode()

-{

-  RINOK(Generate());

-

-  #ifndef _7ZIP_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<ICryptoProperties> cp;

-  CMyComPtr<IUnknown> coder;

-  if (_encoderFilter)

-    coder = _encoderFilter;

-  else

-    coder = _encoder;

-  coder.QueryInterface(IID_ICryptoProperties, &cp);

-  CBenchmarkInStream *inStreamSpec = new CBenchmarkInStream;

-  CMyComPtr<ISequentialInStream> inStream = inStreamSpec;

-  UInt64 prev = 0;

-

-  UInt32 crcPrev = 0;

-

-  if (cp)

-  {

-    RINOK(cp->SetKey(_key, sizeof(_key)));

-    RINOK(cp->SetInitVector(_iv, sizeof(_iv)));

-  }

-

-  for (UInt64 i = 0; i < NumIterations; i++)

-  {

-    if (printCallback && bi.UnpackSize - prev > (1 << 20))

-    {

-      RINOK(printCallback->CheckBreak());

-      prev = bi.UnpackSize;

-    }

-    

-    bool isLast = (i == NumIterations - 1);

-    bool calcCrc = ((isLast || (i & 0x7F) == 0 || CheckCrc_Enc) && NumIterations != 1);

-    outStreamSpec->Init(isLast, calcCrc);

-    

-    if (_encoderFilter)

-    {

-      memcpy((Byte *)rgCopy, uncompressedDataPtr, kBufferSize);

-      _encoderFilter->Init();

-      My_FilterBench(_encoderFilter, (Byte *)rgCopy, kBufferSize);

-      RINOK(WriteStream(outStream, (const Byte *)rgCopy, kBufferSize));

-    }

-    else

-    {

-      inStreamSpec->Init(uncompressedDataPtr, kBufferSize);

-      RINOK(_encoder->Code(inStream, outStream, NULL, NULL, progressInfo[0]));

-    }

-

-    // outStreamSpec->Print();

-

-    UInt32 crcNew = CRC_GET_DIGEST(outStreamSpec->Crc);

-    if (i == 0)

-      crcPrev = crcNew;

-    else if (calcCrc && crcPrev != crcNew)

-      return E_FAIL;

-    

-    compressedSize = outStreamSpec->Pos;

-    bi.UnpackSize += kBufferSize;

-    bi.PackSize += compressedSize;

-  }

-  

-  _encoder.Release();

-  _encoderFilter.Release();

-  return S_OK;

-}

-

-

-HRESULT CEncoderInfo::Decode(UInt32 decoderIndex)

-{

-  CBenchmarkInStream *inStreamSpec = new CBenchmarkInStream;

-  CMyComPtr<ISequentialInStream> inStream = inStreamSpec;

-  CMyComPtr<ICompressCoder> &decoder = _decoders[decoderIndex];

-  CMyComPtr<IUnknown> coder;

-  if (_decoderFilter)

-  {

-    if (decoderIndex != 0)

-      return E_FAIL;

-    coder = _decoderFilter;

-  }

-  else

-    coder = decoder;

-

-  CMyComPtr<ICompressSetDecoderProperties2> setDecProps;

-  coder.QueryInterface(IID_ICompressSetDecoderProperties2, &setDecProps);

-  if (!setDecProps && propStreamSpec->Pos != 0)

-    return E_FAIL;

-

-  CCrcOutStream *crcOutStreamSpec = new CCrcOutStream;

-  CMyComPtr<ISequentialOutStream> crcOutStream = crcOutStreamSpec;

-    

-  CBenchProgressInfo *pi = progressInfoSpec[decoderIndex];

-  pi->BenchInfo.UnpackSize = 0;

-  pi->BenchInfo.PackSize = 0;

-

-  #ifndef _7ZIP_ST

-  {

-    CMyComPtr<ICompressSetCoderMt> setCoderMt;

-    coder.QueryInterface(IID_ICompressSetCoderMt, &setCoderMt);

-    if (setCoderMt)

-    {

-      RINOK(setCoderMt->SetNumberOfThreads(NumDecoderSubThreads));

-    }

-  }

-  #endif

-

-  CMyComPtr<ICompressSetCoderProperties> scp;

-  coder.QueryInterface(IID_ICompressSetCoderProperties, &scp);

-  if (scp)

-  {

-    UInt64 reduceSize = _uncompressedDataSize;

-    RINOK(_method.SetCoderProps(scp, &reduceSize));

-  }

-

-  CMyComPtr<ICryptoProperties> cp;

-  coder.QueryInterface(IID_ICryptoProperties, &cp);

-  

-  if (setDecProps)

-  {

-    RINOK(setDecProps->SetDecoderProperties2((const Byte *)*propStreamSpec, (UInt32)propStreamSpec->Pos));

-  }

-

-  {

-    CMyComPtr<ICryptoSetPassword> sp;

-    coder.QueryInterface(IID_ICryptoSetPassword, &sp);

-    if (sp)

-    {

-      RINOK(sp->CryptoSetPassword(_psw, sizeof(_psw)));

-    }

-  }

-

-  UInt64 prev = 0;

-  

-  if (cp)

-  {

-    RINOK(cp->SetKey(_key, sizeof(_key)));

-    RINOK(cp->SetInitVector(_iv, sizeof(_iv)));

-  }

-

-  for (UInt64 i = 0; i < NumIterations; i++)

-  {

-    if (printCallback && pi->BenchInfo.UnpackSize - prev > (1 << 20))

-    {

-      RINOK(printCallback->CheckBreak());

-      prev = pi->BenchInfo.UnpackSize;

-    }

-

-    inStreamSpec->Init((const Byte *)*outStreamSpec, compressedSize);

-    crcOutStreamSpec->Init();

-    

-    UInt64 outSize = kBufferSize;

-    crcOutStreamSpec->CalcCrc = ((i & 0x7F) == 0 || CheckCrc_Dec);

-    

-    if (_decoderFilter)

-    {

-      if (compressedSize > rgCopy.Size())

-        return E_FAIL;

-      memcpy((Byte *)rgCopy, (const Byte *)*outStreamSpec, compressedSize);

-      _decoderFilter->Init();

-      My_FilterBench(_decoderFilter, (Byte *)rgCopy, compressedSize);

-      RINOK(WriteStream(crcOutStream, (const Byte *)rgCopy, compressedSize));

-    }

-    else

-    {

-      RINOK(decoder->Code(inStream, crcOutStream, 0, &outSize, progressInfo[decoderIndex]));

-    }

-  

-    if (crcOutStreamSpec->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 _7ZIP_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();

-      if (res2 == 0)

-        res2 = t.Close();

-      if (res == S_OK)

-        res = res2;

-    }

-  }

-  NeedClose = false;

-  return res;

-}

-

-#endif

-

-

-

-static HRESULT MethodBench(

-    DECL_EXTERNAL_CODECS_LOC_VARS

-    UInt64 complexInCommands,

-    bool

-      #ifndef _7ZIP_ST

-        oldLzmaBenchMode

-      #endif

-    ,

-    UInt32

-      #ifndef _7ZIP_ST

-        numThreads

-      #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;

-  int codecIndex = FindMethod_Index(

-      EXTERNAL_CODECS_LOC_VARS

-      method.MethodName, true,

-      methodId, numStreams);

-  if (codecIndex < 0)

-    return E_NOTIMPL;

-  if (numStreams != 1)

-    return E_INVALIDARG;

-

-  UInt32 numEncoderThreads = 1;

-  UInt32 numSubDecoderThreads = 1;

-  

-  #ifndef _7ZIP_ST

-    numEncoderThreads = numThreads;

-

-    if (oldLzmaBenchMode && 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 / 2;

-        numSubDecoderThreads = 2;

-      }

-    }

-

-  bool mtEncMode = (numEncoderThreads > 1);

-  #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 : 0;

-    encoder.printCallback = printCallback;

-

-    {

-      CCreatedCoder cod;

-      RINOK(CreateCoder_Index(EXTERNAL_CODECS_LOC_VARS codecIndex, true, encoder._encoderFilter, cod));

-      encoder._encoder = cod.Coder;

-      if (!encoder._encoder && !encoder._encoderFilter)

-        return E_NOTIMPL;

-    }

-

-    encoder.CheckCrc_Enc = (benchProps->EncComplex) > 30 ;

-    encoder.CheckCrc_Dec = (benchProps->DecComplexCompr + benchProps->DecComplexUnc) > 30 ;

-

-    memset(encoder._iv, 0, sizeof(encoder._iv));

-    memset(encoder._key, 0, sizeof(encoder._key));

-    memset(encoder._psw, 0, sizeof(encoder._psw));

-

-    for (UInt32 j = 0; j < numSubDecoderThreads; j++)

-    {

-      CCreatedCoder cod;

-      CMyComPtr<ICompressCoder> &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;

-    }

-  }

-

-  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 _7ZIP_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->GeComprCommands(uncompressedDataSize), complexInCommands);

-    encoder.Salt = g_CrcTable[i & 0xFF];

-    encoder.Salt ^= (g_CrcTable[(i >> 8) & 0xFF] << 3);

-    // (g_CrcTable[0] == 0), and (encoder.Salt == 0) for first thread

-    // printf(" %8x", encoder.Salt);

-

-    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 _7ZIP_ST

-    if (mtEncMode)

-    {

-      #ifdef USE_ALLOCA

-      encoder.AllocaSize = (i * 16 * 21) & 0x7FF;

-      #endif

-

-      encoder.Common = &encoderFlusher.Common;

-      RINOK(encoder.CreateEncoderThread())

-    }

-    #endif

-  }

-

-  if (printCallback)

-  {

-    RINOK(printCallback->CheckBreak());

-  }

-

-  #ifndef _7ZIP_ST

-  if (mtEncMode)

-  {

-    for (i = 0; i < numEncoderThreads; i++)

-    {

-      CEncoderInfo &encoder = encoders[i];

-      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();

-

-    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++)

-  {

-    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;

-

-  UInt32 numDecoderThreads = numEncoderThreads * numSubDecoderThreads;

-  

-  for (i = 0; i < numEncoderThreads; i++)

-  {

-    CEncoderInfo &encoder = encoders[i];

-

-    if (i == 0)

-    {

-      encoder.NumIterations = GetNumIterations(benchProps->GeDecomprCommands(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 _7ZIP_ST

-    {

-      int numSubThreads = method.Get_NumThreads();

-      encoder.NumDecoderSubThreads = (numSubThreads <= 0) ? 1 : numSubThreads;

-    }

-    if (numDecoderThreads > 1)

-    {

-      for (UInt32 j = 0; j < numSubDecoderThreads; j++)

-      {

-        HRESULT res = encoder.CreateDecoderThread(j, (i == 0 && j == 0)

-            #ifdef USE_ALLOCA

-            , ((i * numSubDecoderThreads + j) * 16 * 21) & 0x7FF

-            #endif

-            );

-        RINOK(res);

-      }

-    }

-    else

-    #endif

-    {

-      RINOK(encoder.Decode(0));

-    }

-  }

-  

-  #ifndef _7ZIP_ST

-  HRESULT res = S_OK;

-  if (numDecoderThreads > 1)

-    for (i = 0; i < numEncoderThreads; i++)

-      for (UInt32 j = 0; j < numSubDecoderThreads; j++)

-      {

-        CEncoderInfo &encoder = encoders[i];

-        encoder.thread[j].Wait();

-        if (encoder.Results[j] != S_OK)

-          res = encoder.Results[j];

-      }

-  RINOK(res);

-  #endif

-  

-  RINOK(status.Res);

-  encoders[0].progressInfoSpec[0]->SetFinishTime(info);

-  

-  #ifndef _7ZIP_ST

-  #ifdef UNDER_CE

-  if (numDecoderThreads > 1)

-    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++)

-  {

-    CEncoderInfo &encoder = encoders[i];

-    info.UnpackSize += encoder.kBufferSize;

-    info.PackSize += encoder.compressedSize;

-  }

-  

-  RINOK(callback->SetDecodeResult(info, false));

-  RINOK(callback->SetDecodeResult(info, true));

-  

-  return S_OK;

-}

-

-

-static inline UInt64 GetLZMAUsage(bool multiThread, UInt32 dictionary)

-{

-  UInt32 hs = dictionary - 1;

-  hs |= (hs >> 1);

-  hs |= (hs >> 2);

-  hs |= (hs >> 4);

-  hs |= (hs >> 8);

-  hs >>= 1;

-  hs |= 0xFFFF;

-  if (hs > (1 << 24))

-    hs >>= 1;

-  hs++;

-  return ((hs + (1 << 16)) + (UInt64)dictionary * 2) * 4 + (UInt64)dictionary * 3 / 2 +

-      (1 << 20) + (multiThread ? (6 << 20) : 0);

-}

-

-UInt64 GetBenchMemoryUsage(UInt32 numThreads, UInt32 dictionary, bool totalBench)

-{

-  const UInt32 kBufferSize = dictionary;

-  const UInt32 kCompressedBufferSize = kBufferSize; // / 2;

-  bool lzmaMt = (totalBench || numThreads > 1);

-  UInt32 numBigThreads = numThreads;

-  if (!totalBench && lzmaMt)

-    numBigThreads /= 2;

-  return ((UInt64)kBufferSize + kCompressedBufferSize +

-    GetLZMAUsage(lzmaMt, dictionary) + (2 << 20)) * numBigThreads;

-}

-

-static HRESULT CrcBig(const void *data, UInt32 size, UInt64 numIterations,

-    const UInt32 *checkSum, IHasher *hf,

-    IBenchPrintCallback *callback)

-{

-  Byte hash[64];

-  UInt64 i;

-  for (i = 0; i < sizeof(hash); i++)

-    hash[i] = 0;

-  for (i = 0; i < numIterations; i++)

-  {

-    if (callback && (i & 0xFF) == 0)

-    {

-      RINOK(callback->CheckBreak());

-    }

-    hf->Init();

-    hf->Update(data, size);

-    hf->Final(hash);

-    UInt32 hashSize = hf->GetDigestSize();

-    if (hashSize > sizeof(hash))

-      return S_FALSE;

-    UInt32 sum = 0;

-    for (UInt32 j = 0; j < hashSize; j += 4)

-      sum ^= GetUi32(hash + j);

-    if (checkSum && sum != *checkSum)

-    {

-      return S_FALSE;

-    }

-  }

-  return S_OK;

-}

-

-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 _7ZIP_ST

-

-struct CFreqInfo

-{

-  NWindows::CThread Thread;

-  IBenchPrintCallback *Callback;

-  HRESULT CallbackRes;

-  UInt32 ValRes;

-  UInt32 Size;

-  UInt64 NumIterations;

-

-  void Wait()

-  {

-    Thread.Wait();

-    Thread.Close();

-  }

-};

-

-static THREAD_FUNC_DECL FreqThreadFunction(void *param)

-{

-  CFreqInfo *p = (CFreqInfo *)param;

-

-  UInt32 sum = g_BenchCpuFreqTemp;

-  for (UInt64 k = p->NumIterations; k > 0; k--)

-  {

-    p->CallbackRes = p->Callback->CheckBreak();

-    if (p->CallbackRes != S_OK)

-      return 0;

-    sum = CountCpuFreq(sum, p->Size, g_BenchCpuFreqTemp);

-  }

-  p->ValRes = sum;

-  return 0;

-}

-

-struct CFreqThreads

-{

-  CFreqInfo *Items;

-  UInt32 NumThreads;

-

-  CFreqThreads(): Items(NULL), NumThreads(0) {}

-  void WaitAll()

-  {

-    for (UInt32 i = 0; i < NumThreads; i++)

-      Items[i].Wait();

-    NumThreads = 0;

-  }

-  ~CFreqThreads()

-  {

-    WaitAll();

-    delete []Items;

-  }

-};

-

-struct CCrcInfo

-{

-  NWindows::CThread Thread;

-  IBenchPrintCallback *Callback;

-  HRESULT CallbackRes;

-

-  const Byte *Data;

-  UInt32 Size;

-  UInt64 NumIterations;

-  bool CheckSumDefined;

-  UInt32 CheckSum;

-  CMyComPtr<IHasher> Hasher;

-  HRESULT Res;

-

-  #ifdef USE_ALLOCA

-  size_t AllocaSize;

-  #endif

-

-  void Wait()

-  {

-    Thread.Wait();

-    Thread.Close();

-  }

-};

-

-static THREAD_FUNC_DECL CrcThreadFunction(void *param)

-{

-  CCrcInfo *p = (CCrcInfo *)param;

-  

-  #ifdef USE_ALLOCA

-  alloca(p->AllocaSize);

-  #endif

-

-  p->Res = CrcBig(p->Data, p->Size, p->NumIterations,

-      p->CheckSumDefined ? &p->CheckSum : NULL, p->Hasher,

-      p->Callback);

-  return 0;

-}

-

-struct CCrcThreads

-{

-  CCrcInfo *Items;

-  UInt32 NumThreads;

-

-  CCrcThreads(): Items(NULL), NumThreads(0) {}

-  void WaitAll()

-  {

-    for (UInt32 i = 0; i < NumThreads; i++)

-      Items[i].Wait();

-    NumThreads = 0;

-  }

-  ~CCrcThreads()

-  {

-    WaitAll();

-    delete []Items;

-  }

-};

-

-#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 void RandGen(Byte *buf, size_t size, CBaseRandomGenerator &RG)

-{

-  for (size_t i = 0; i < size; i++)

-    buf[i] = (Byte)RG.GetRnd();

-}

-

-static UInt32 RandGenCrc(Byte *buf, size_t size, CBaseRandomGenerator &RG)

-{

-  RandGen(buf, size, RG);

-  return CrcCalc1(buf, size);

-}

-

-bool CrcInternalTest()

-{

-  CAlignedBuffer buffer;

-  const size_t kBufferSize0 = (1 << 8);

-  const size_t kBufferSize1 = (1 << 10);

-  const unsigned kCheckSize = (1 << 5);

-  buffer.Alloc(kBufferSize0 + kBufferSize1);

-  if (!buffer.IsAllocated())

-    return false;

-  Byte *buf = (Byte *)buffer;

-  size_t i;

-  for (i = 0; i < kBufferSize0; i++)

-    buf[i] = (Byte)i;

-  UInt32 crc1 = CrcCalc1(buf, kBufferSize0);

-  if (crc1 != 0x29058C73)

-    return false;

-  CBaseRandomGenerator RG;

-  RandGen(buf + kBufferSize0, kBufferSize1, RG);

-  for (i = 0; i < kBufferSize0 + kBufferSize1 - kCheckSize; i++)

-    for (unsigned j = 0; j < kCheckSize; j++)

-      if (CrcCalc1(buf + i, j) != CrcCalc(buf + i, j))

-        return false;

-  return true;

-}

-

-struct CBenchMethod

-{

-  unsigned Weight;

-  unsigned DictBits;

-  UInt32 EncComplex;

-  UInt32 DecComplexCompr;

-  UInt32 DecComplexUnc;

-  const char *Name;

-};

-

-static const CBenchMethod g_Bench[] =

-{

-  { 40, 17,  357,  145,   20, "LZMA:x1" },

-  { 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, "PPMD:x1" },

-  { 10, 22, 1655,    0, 1830, "PPMD:x5" },

-

-  {  2,  0,    6,    0,    6, "Delta:4" },

-  {  2,  0,    4,    0,    4, "BCJ" },

-

-  { 10,  0,   24,    0,   24, "AES256CBC:1" },

-  {  2,  0,    8,    0,    2, "AES256CBC:2" }

-};

-

-struct CBenchHash

-{

-  unsigned Weight;

-  UInt32 Complex;

-  UInt32 CheckSum;

-  const char *Name;

-};

-

-static const CBenchHash g_Hash[] =

-{

-  {  1,  1820, 0x8F8FEDAB, "CRC32:1" },

-  { 10,   558, 0x8F8FEDAB, "CRC32:4" },

-  { 10,   339, 0x8F8FEDAB, "CRC32:8" },

-  { 10,   512, 0xDF1C17CC, "CRC64" },

-  { 10,  5100, 0x2D79FF2E, "SHA256" },

-  { 10,  2340, 0x4C25132B, "SHA1" },

-  {  2,  5500, 0xE084E913, "BLAKE2sp" }

-};

-

-struct CTotalBenchRes

-{

-  // UInt64 NumIterations1; // for Usage

-  UInt64 NumIterations2; // for Rating / RPU

-

-  UInt64 Rating;

-  UInt64 Usage;

-  UInt64 RPU;

-  

-  void Init() { /* NumIterations1 = 0; */ NumIterations2 = 0; Rating = 0; Usage = 0; RPU = 0; }

-

-  void SetSum(const CTotalBenchRes &r1, const CTotalBenchRes &r2)

-  {

-    Rating = (r1.Rating + r2.Rating);

-    Usage = (r1.Usage + r2.Usage);

-    RPU = (r1.RPU + r2.RPU);

-    // NumIterations1 = (r1.NumIterations1 + r2.NumIterations1);

-    NumIterations2 = (r1.NumIterations2 + r2.NumIterations2);

-  }

-};

-

-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)

-  {

-    startPos -= (size - len);

-    if (startPos < 0)

-      startPos = 0;

-  }

-  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_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)

-{

-  PrintNumber(f, (val * 100 + divider / 2) / divider, 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 PrintResults(IBenchPrintCallback &f, UInt64 usage, UInt64 rpu, UInt64 rating, bool showFreq, UInt64 cpuFreq)

-{

-  PrintNumber(f, (usage + 5000) / 10000, kFieldSize_Usage);

-  PrintRating(f, rpu, kFieldSize_RU);

-  PrintRating(f, rating, kFieldSize_Rating);

-  if (showFreq)

-  {

-    if (cpuFreq == 0)

-      PrintSpaces(f, kFieldSize_EUAndEffec);

-    else

-    {

-      UInt64 ddd = cpuFreq * usage / 100;

-      if (ddd == 0)

-        ddd = 1;

-      PrintPercents(f, (rating * 10000), ddd, kFieldSize_EU);

-      PrintPercents(f, rating, cpuFreq, kFieldSize_Effec);

-    }

-  }

-}

-

-static void PrintResults(IBenchPrintCallback *f,

-    const CBenchInfo &info,

-    unsigned weight,

-    UInt64 rating,

-    bool showFreq, UInt64 cpuFreq,

-    CTotalBenchRes *res)

-{

-  UInt64 speed = info.GetSpeed(info.UnpackSize * info.NumIterations);

-  if (f)

-  {

-    if (speed != 0)

-      PrintNumber(*f, speed / 1024, kFieldSize_Speed);

-    else

-      PrintSpaces(*f, 1 + kFieldSize_Speed);

-  }

-  UInt64 usage = info.GetUsage();

-  UInt64 rpu = info.GetRatingPerUsage(rating);

-  if (f)

-  {

-    PrintResults(*f, usage, rpu, rating, showFreq, cpuFreq);

-  }

-

-  if (res)

-  {

-    // res->NumIterations1++;

-    res->NumIterations2 += weight;

-    res->RPU += (rpu * weight);

-    res->Rating += (rating * weight);

-    res->Usage += (usage * weight);

-  }

-}

-

-static void PrintTotals(IBenchPrintCallback &f, bool showFreq, UInt64 cpuFreq, const CTotalBenchRes &res)

-{

-  PrintSpaces(f, 1 + kFieldSize_Speed);

-  // UInt64 numIterations1 = res.NumIterations1; if (numIterations1 == 0) numIterations1 = 1;

-  UInt64 numIterations2 = res.NumIterations2; if (numIterations2 == 0) numIterations2 = 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);

-  if (ti.processAffinityMask != ti.systemAffinityMask)

-  {

-    // if (ti.numProcessThreads != ti.numSysThreads)

-    {

-      s += " / ";

-      s.Add_UInt32(ti.GetNumSystemThreads());

-    }

-    s += " : ";

-    PrintHex(s, ti.processAffinityMask);

-    s += " / ";

-    PrintHex(s, ti.systemAffinityMask);

-  }

-  return s;

-}

-

-

-static void PrintSize(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

-  {

-    PrintHex(s, v);

-    return;

-  }

-  char temp[32];

-  ConvertUInt64ToString(v, temp);

-  s += temp;

-  if (c)

-    s += c;

-}

-

-

-#ifdef _7ZIP_LARGE_PAGES

-

-extern bool g_LargePagesMode;

-

-extern "C"

-{

-  extern SIZE_T g_LargePageSize;

-}

-

-void Add_LargePages_String(AString &s)

-{

-  if (g_LargePagesMode || g_LargePageSize != 0)

-  {

-    s += " (LP-";

-    PrintSize(s, g_LargePageSize);

-    #ifdef MY_CPU_X86_OR_AMD64

-    if (CPU_IsSupported_PageGB())

-      s += "-1G";

-    #endif

-    if (!g_LargePagesMode)

-      s += "-NA";

-    s += ")";

-  }

-}

-

-#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 _7ZIP_LARGE_PAGES

-  {

-    AString s;

-    Add_LargePages_String(s);

-    f.Print(s);

-  }

-  #endif

-  

-  f.Print(",  # ");

-  f.Print(threadsString);

-  PrintNumber(f, numThreads, 3);

-}

-

-

-

-struct CBenchCallbackToPrint: public IBenchCallback

-{

-  CBenchProps BenchProps;

-  CTotalBenchRes EncodeRes;

-  CTotalBenchRes DecodeRes;

-  IBenchPrintCallback *_file;

-  UInt32 DictSize;

-

-  bool Use2Columns;

-  unsigned NameFieldSize;

-

-  bool ShowFreq;

-  UInt64 CpuFreq;

-

-  unsigned EncodeWeight;

-  unsigned DecodeWeight;

-

-  CBenchCallbackToPrint():

-      Use2Columns(false),

-      NameFieldSize(0),

-      ShowFreq(false),

-      CpuFreq(0),

-      EncodeWeight(1),

-      DecodeWeight(1)

-      {}

-

-  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);

-  HRESULT SetDecodeResult(const CBenchInfo &info, bool final);

-};

-

-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)

-  {

-    UInt64 rating = BenchProps.GetCompressRating(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)

-  {

-    UInt64 rating = BenchProps.GetDecompressRating(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();

-}

-

-void PrintLeft(IBenchPrintCallback &f, const char *s, unsigned size)

-{

-  f.Print(s);

-  int numSpaces = size - MyStringLen(s);

-  if (numSpaces > 0)

-    PrintSpaces(f, numSpaces);

-}

-

-void PrintRight(IBenchPrintCallback &f, const char *s, unsigned size)

-{

-  int numSpaces = size - MyStringLen(s);

-  if (numSpaces > 0)

-    PrintSpaces(f, numSpaces);

-  f.Print(s);

-}

-

-static HRESULT TotalBench(

-    DECL_EXTERNAL_CODECS_LOC_VARS

-    UInt64 complexInCommands,

-    UInt32 numThreads,

-    bool forceUnpackSize,

-    size_t unpackSize,

-    const Byte *fileData,

-    IBenchPrintCallback *printCallback, CBenchCallbackToPrint *callback)

-{

-  for (unsigned i = 0; i < ARRAY_SIZE(g_Bench); i++)

-  {

-    const CBenchMethod &bench = g_Bench[i];

-    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));

-

-    size_t unpackSize2 = unpackSize;

-    if (!forceUnpackSize && bench.DictBits == 0)

-      unpackSize2 = kFilterUnpackSize;

-

-    callback->EncodeWeight = bench.Weight;

-    callback->DecodeWeight = bench.Weight;

-

-    HRESULT res = MethodBench(

-        EXTERNAL_CODECS_LOC_VARS

-        complexInCommands,

-        false, numThreads, 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;

-}

-

-

-static HRESULT FreqBench(

-    UInt64 complexInCommands,

-    UInt32 numThreads,

-    IBenchPrintCallback *_file,

-    bool showFreq,

-    UInt64 specifiedFreq,

-    UInt64 &cpuFreq,

-    UInt32 &res)

-{

-  res = 0;

-  cpuFreq = 0;

-

-  UInt32 bufferSize = 1 << 20;

-  UInt32 complexity = kNumFreqCommands;

-  if (numThreads == 0)

-    numThreads = 1;

-

-  #ifdef _7ZIP_ST

-  numThreads = 1;

-  #endif

-

-  UInt32 bsize = (bufferSize == 0 ? 1 : bufferSize);

-  UInt64 numIterations = complexInCommands / complexity / bsize;

-  if (numIterations == 0)

-    numIterations = 1;

-

-  CBenchInfoCalc progressInfoSpec;

-

-  #ifndef _7ZIP_ST

-  CFreqThreads threads;

-  if (numThreads > 1)

-  {

-    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 = bufferSize;

-    }

-    progressInfoSpec.SetStartTime();

-    for (i = 0; i < numThreads; i++)

-    {

-      CFreqInfo &info = threads.Items[i];

-      RINOK(info.Thread.Create(FreqThreadFunction, &info));

-      threads.NumThreads++;

-    }

-    threads.WaitAll();

-    for (i = 0; i < numThreads; i++)

-    {

-      RINOK(threads.Items[i].CallbackRes);

-    }

-  }

-  else

-  #endif

-  {

-    progressInfoSpec.SetStartTime();

-    UInt32 sum = g_BenchCpuFreqTemp;

-    for (UInt64 k = numIterations; k > 0; k--)

-    {

-      RINOK(_file->CheckBreak());

-      sum = CountCpuFreq(sum, bufferSize, g_BenchCpuFreqTemp);

-    }

-    res += sum;

-  }

-  

-  CBenchInfo info;

-  progressInfoSpec.SetFinishTime(info);

-

-  info.UnpackSize = 0;

-  info.PackSize = 0;

-  info.NumIterations = 1;

-

-  if (_file)

-  {

-    {

-      UInt64 numCommands = (UInt64)numIterations * bufferSize * numThreads * complexity;

-      UInt64 rating = info.GetSpeed(numCommands);

-      cpuFreq = rating / numThreads;

-      PrintResults(_file, info,

-          0, // weight

-          rating,

-          showFreq, showFreq ? (specifiedFreq != 0 ? specifiedFreq : cpuFreq) : 0, NULL);

-    }

-    RINOK(_file->CheckBreak());

-  }

-

-  return S_OK;

-}

-

-

-

-static HRESULT CrcBench(

-    DECL_EXTERNAL_CODECS_LOC_VARS

-    UInt64 complexInCommands,

-    UInt32 numThreads, UInt32 bufferSize,

-    UInt64 &speed,

-    UInt32 complexity, unsigned benchWeight,

-    const UInt32 *checkSum,

-    const COneMethodInfo &method,

-    IBenchPrintCallback *_file,

-    CTotalBenchRes *encodeRes,

-    bool showFreq, UInt64 cpuFreq)

-{

-  if (numThreads == 0)

-    numThreads = 1;

-

-  #ifdef _7ZIP_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;

-

-  CAlignedBuffer buffer;

-  size_t totalSize = (size_t)bufferSize * numThreads;

-  if (totalSize / numThreads != bufferSize)

-    return E_OUTOFMEMORY;

-  ALLOC_WITH_HRESULT(&buffer, totalSize)

-

-  Byte *buf = (Byte *)buffer;

-  CBaseRandomGenerator RG;

-  UInt32 bsize = (bufferSize == 0 ? 1 : bufferSize);

-  UInt64 numIterations = complexInCommands * 256 / complexity / bsize;

-  if (numIterations == 0)

-    numIterations = 1;

-

-  CBenchInfoCalc progressInfoSpec;

-

-  #ifndef _7ZIP_ST

-  CCrcThreads threads;

-  if (numThreads > 1)

-  {

-    threads.Items = new CCrcInfo[numThreads];

-    

-    UInt32 i;

-    for (i = 0; i < numThreads; i++)

-    {

-      CCrcInfo &info = threads.Items[i];

-      AString name;

-      RINOK(CreateHasher(EXTERNAL_CODECS_LOC_VARS hashID, name, info.Hasher));

-      if (!info.Hasher)

-        return E_NOTIMPL;

-      CMyComPtr<ICompressSetCoderProperties> scp;

-      info.Hasher.QueryInterface(IID_ICompressSetCoderProperties, &scp);

-      if (scp)

-      {

-        UInt64 reduceSize = 1;

-        RINOK(method.SetCoderProps(scp, &reduceSize));

-      }

-

-      Byte *data = buf + (size_t)bufferSize * i;

-      info.Callback = _file;

-      info.Data = data;

-      info.NumIterations = numIterations;

-      info.Size = bufferSize;

-      /* info.Crc = */ RandGenCrc(data, bufferSize, RG);

-      info.CheckSumDefined = false;

-      if (checkSum)

-      {

-        info.CheckSum = *checkSum;

-        info.CheckSumDefined = (checkSum && (i == 0));

-      }

-

-      #ifdef USE_ALLOCA

-      info.AllocaSize = (i * 16 * 21) & 0x7FF;

-      #endif

-    }

-

-    progressInfoSpec.SetStartTime();

-    

-    for (i = 0; i < numThreads; i++)

-    {

-      CCrcInfo &info = threads.Items[i];

-      RINOK(info.Thread.Create(CrcThreadFunction, &info));

-      threads.NumThreads++;

-    }

-    threads.WaitAll();

-    for (i = 0; i < numThreads; i++)

-    {

-      RINOK(threads.Items[i].Res);

-    }

-  }

-  else

-  #endif

-  {

-    /* UInt32 crc = */ RandGenCrc(buf, bufferSize, RG);

-    progressInfoSpec.SetStartTime();

-    CMyComPtr<IHasher> hasher;

-    AString name;

-    RINOK(CreateHasher(EXTERNAL_CODECS_LOC_VARS hashID, name, hasher));

-    if (!hasher)

-      return E_NOTIMPL;

-    CMyComPtr<ICompressSetCoderProperties> scp;

-    hasher.QueryInterface(IID_ICompressSetCoderProperties, &scp);

-    if (scp)

-    {

-      UInt64 reduceSize = 1;

-      RINOK(method.SetCoderProps(scp, &reduceSize));

-    }

-    RINOK(CrcBig(buf, bufferSize, numIterations, checkSum, hasher, _file));

-  }

-

-  CBenchInfo info;

-  progressInfoSpec.SetFinishTime(info);

-

-  UInt64 unpSize = numIterations * bufferSize;

-  UInt64 unpSizeThreads = unpSize * numThreads;

-  info.UnpackSize = unpSizeThreads;

-  info.PackSize = unpSizeThreads;

-  info.NumIterations = 1;

-

-  if (_file)

-  {

-    {

-      UInt64 numCommands = unpSizeThreads * complexity / 256;

-      UInt64 rating = info.GetSpeed(numCommands);

-      PrintResults(_file, info,

-          benchWeight, rating,

-          showFreq, cpuFreq, encodeRes);

-    }

-    RINOK(_file->CheckBreak());

-  }

-

-  speed = info.GetSpeed(unpSizeThreads);

-

-  return S_OK;

-}

-

-static HRESULT TotalBench_Hash(

-    DECL_EXTERNAL_CODECS_LOC_VARS

-    UInt64 complexInCommands,

-    UInt32 numThreads, UInt32 bufSize,

-    IBenchPrintCallback *printCallback, CBenchCallbackToPrint *callback,

-    CTotalBenchRes *encodeRes,

-    bool showFreq, UInt64 cpuFreq)

-{

-  for (unsigned i = 0; i < ARRAY_SIZE(g_Hash); i++)

-  {

-    const CBenchHash &bench = g_Hash[i];

-    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;

-    HRESULT res = CrcBench(

-        EXTERNAL_CODECS_LOC_VARS

-        complexInCommands,

-        numThreads, bufSize,

-        speed,

-        bench.Complex, bench.Weight,

-        &bench.CheckSum, method,

-        printCallback, encodeRes, showFreq, cpuFreq);

-    if (res == E_NOTIMPL)

-    {

-      // callback->Print(" ---");

-    }

-    else

-    {

-      RINOK(res);

-    }

-    callback->NewLine();

-  }

-  return S_OK;

-}

-

-struct CTempValues

-{

-  UInt64 *Values;

-  CTempValues(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 UInt32 GetNumThreadsNext(unsigned i, UInt32 numThreads)

-{

-  if (i < 2)

-    return i + 1;

-  i -= 1;

-  UInt32 num = (UInt32)(2 + (i & 1)) << (i >> 1);

-  return (num <= numThreads) ? num : numThreads;

-}

-

-static bool AreSameMethodNames(const char *fullName, const char *shortName)

-{

-  return StringsAreEqualNoCase_Ascii(fullName, shortName);

-}

-

-

-#ifdef MY_CPU_X86_OR_AMD64

-

-static void PrintCpuChars(AString &s, UInt32 v)

-{

-  for (int j = 0; j < 4; j++)

-  {

-    Byte b = (Byte)(v & 0xFF);

-    v >>= 8;

-    if (b == 0)

-      break;

-    s += (char)b;

-  }

-}

-

-static void x86cpuid_to_String(const Cx86cpuid &c, AString &s)

-{

-  s.Empty();

-

-  UInt32 maxFunc2 = 0;

-  UInt32 t[3];

-

-  MyCPUID(0x80000000, &maxFunc2, &t[0], &t[1], &t[2]);

-

-  bool fullNameIsAvail = (maxFunc2 >= 0x80000004);

-  

-  if (!fullNameIsAvail)

-  {

-    for (int i = 0; i < 3; i++)

-      PrintCpuChars(s, c.vendor[i]);

-  }

-  else

-  {

-    for (int i = 0; i < 3; i++)

-    {

-      UInt32 d[4] = { 0 };

-      MyCPUID(0x80000002 + i, &d[0], &d[1], &d[2], &d[3]);

-      for (int j = 0; j < 4; j++)

-        PrintCpuChars(s, d[j]);

-    }

-  }

-

-  s.Add_Space_if_NotEmpty();

-  {

-    char temp[32];

-    ConvertUInt32ToHex(c.ver, temp);

-    s += '(';

-    s += temp;

-    s += ')';

-  }

-}

-

-#endif

-

-

-

-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 MY__PROCESSOR_ARCHITECTURE_INTEL 0

-#define MY__PROCESSOR_ARCHITECTURE_AMD64 9

-

-

-#define MY__PROCESSOR_INTEL_PENTIUM  586

-#define MY__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

-*/

-

-#ifdef _WIN32

-

-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"

-};

-

-#endif

-

-

-

-

-static void PrintPage(AString &s, UInt32 v)

-{

-  if ((v & 0x3FF) == 0)

-  {

-    s.Add_UInt32(v >> 10);

-    s += "K";

-  }

-  else

-    s.Add_UInt32(v >> 10);

-}

-

-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;

-}

-

-#ifdef _WIN32

-

-static void SysInfo_To_String(AString &s, const SYSTEM_INFO &si)

-{

-  s += TypeToString2(k_PROCESSOR_ARCHITECTURE, ARRAY_SIZE(k_PROCESSOR_ARCHITECTURE), si.wProcessorArchitecture);

-

-  if (!(   si.wProcessorArchitecture == MY__PROCESSOR_ARCHITECTURE_INTEL && si.dwProcessorType == MY__PROCESSOR_INTEL_PENTIUM

-      || si.wProcessorArchitecture == MY__PROCESSOR_ARCHITECTURE_AMD64 && si.dwProcessorType == MY__PROCESSOR_AMD_X8664))

-  {

-    s += " ";

-    // s += TypePairToString(k_PROCESSOR, ARRAY_SIZE(k_PROCESSOR), si.dwProcessorType);

-    s.Add_UInt32(si.dwProcessorType);

-  }

-  s += " ";

-  PrintHex(s, si.wProcessorLevel);

-  s += ".";

-  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 += " cpus:";

-  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 += " ";

-

-  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(s, minAdd);

-    s += "-";

-  }

-  else

-  {

-    if ((maxSize & (kReserveSize - 1)) == 0)

-      maxSize += kReserveSize;

-  }

-  PrintSize(s, maxSize);

-}

-

-#ifndef _WIN64

-typedef VOID (WINAPI *Func_GetNativeSystemInfo)(LPSYSTEM_INFO lpSystemInfo);

-#endif

-

-#endif

-

-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)

-    Func_GetNativeSystemInfo fn_GetNativeSystemInfo = (Func_GetNativeSystemInfo)GetProcAddress(

-        GetModuleHandleA("kernel32.dll"), "GetNativeSystemInfo");

-    if (fn_GetNativeSystemInfo)

-    {

-      SYSTEM_INFO si2;

-      fn_GetNativeSystemInfo(&si2);

-      // if (memcmp(&si, &si2, sizeof(si)) != 0)

-      {

-        // s += " - ";

-        SysInfo_To_String(s2, si2);

-      }

-    }

-    #endif

-  #endif

-}

-

-

-void GetCpuName(AString &s)

-{

-  s.Empty();

-

-  #ifdef MY_CPU_X86_OR_AMD64

-  {

-    Cx86cpuid cpuid;

-    if (x86cpuid_CheckAndRead(&cpuid))

-    {

-      AString s2;

-      x86cpuid_to_String(cpuid, s2);

-      s += s2;

-    }

-    else

-    {

-    #ifdef MY_CPU_AMD64

-    s += "x64";

-    #else

-    s += "x86";

-    #endif

-    }

-  }

-  #else

-  

-    #ifdef MY_CPU_LE

-      s += "LE";

-    #elif defined(MY_CPU_BE)

-      s += "BE";

-    #endif

-

-  #endif

-

-  #ifdef _7ZIP_LARGE_PAGES

-  Add_LargePages_String(s);

-  #endif

-}

-

-

-void GetCpuFeatures(AString &s)

-{

-  s.Empty();

-  

-  #ifdef _WIN32

-  const unsigned kNumFeatures_Extra = 32; // we check also for unknown features

-  const unsigned kNumFeatures = ARRAY_SIZE(k_PF) + kNumFeatures_Extra;

-  for (unsigned i = 0; i < kNumFeatures; i++)

-  {

-    if (IsProcessorFeaturePresent(i))

-    {

-      s.Add_Space_if_NotEmpty();

-      s += TypeToString2(k_PF, ARRAY_SIZE(k_PF), i);

-    }

-  }

-  #endif

-}

-

-

-#ifdef _WIN32

-#ifndef UNDER_CE

-

-typedef void (WINAPI * Func_RtlGetVersion) (OSVERSIONINFOEXW *);

-

-static BOOL My_RtlGetVersion(OSVERSIONINFOEXW *vi)

-{

-  HMODULE ntdll = ::GetModuleHandleW(L"ntdll.dll");

-  if (!ntdll)

-    return FALSE;

-  Func_RtlGetVersion func = (Func_RtlGetVersion)GetProcAddress(ntdll, "RtlGetVersion");

-  if (!func)

-    return FALSE;

-  func(vi);

-  return TRUE;

-}

-

-#endif

-#endif

-

-

-HRESULT Bench(

-    DECL_EXTERNAL_CODECS_LOC_VARS

-    IBenchPrintCallback *printCallback,

-    IBenchCallback *benchCallback,

-    // IBenchFreqCallback *freqCallback,

-    const CObjectVector<CProperty> &props,

-    UInt32 numIterations,

-    bool multiDict)

-{

-  if (!CrcInternalTest())

-    return E_FAIL;

-

-  UInt32 numCPUs = 1;

-  UInt64 ramSize = (UInt64)(sizeof(size_t)) << 29;

-

-  NSystem::CProcessAffinity threadsInfo;

-  threadsInfo.InitST();

-

-  #ifndef _7ZIP_ST

-

-  if (threadsInfo.Get() && threadsInfo.processAffinityMask != 0)

-    numCPUs = threadsInfo.GetNumProcessThreads();

-  else

-    numCPUs = NSystem::GetNumberOfProcessors();

-

-  #endif

-  

-  bool ramSize_Defined = NSystem::GetRamSize(ramSize);

-

-  UInt32 numThreadsSpecified = numCPUs;

-

-  UInt32 testTime = kComplexInSeconds;

-

-  UInt64 specifiedFreq = 0;

-

-  bool multiThreadTests = false;

-

-  COneMethodInfo method;

-

-  CAlignedBuffer fileDataBuffer;

-

-  {

-  unsigned i;

-  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;

-

-      #ifdef USE_WIN_FILE

-      

-      NFile::NIO::CInFile file;

-      if (!file.Open(us2fs(property.Value)))

-        return E_INVALIDARG;

-      UInt64 len;

-      if (!file.GetLength(len))

-        return E_FAIL;

-      if (len >= ((UInt32)1 << 31) || len == 0)

-        return E_INVALIDARG;

-      ALLOC_WITH_HRESULT(&fileDataBuffer, (size_t)len);

-      UInt32 processedSize;

-      file.Read((Byte *)fileDataBuffer, (UInt32)len, processedSize);

-      if (processedSize != len)

-        return E_FAIL;

-      if (printCallback)

-      {

-        printCallback->Print("file size =");

-        PrintNumber(*printCallback, len, 0);

-        printCallback->NewLine();

-      }

-      continue;

-

-      #else

-

-      return E_NOTIMPL;

-      

-      #endif

-    }

-

-    NCOM::CPropVariant propVariant;

-    if (!property.Value.IsEmpty())

-      ParseNumberString(property.Value, propVariant);

-    

-    if (name.IsEqualTo("time"))

-    {

-      RINOK(ParsePropToUInt32(UString(), propVariant, testTime));

-      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"))

-    {

-      UString s = name.Ptr(2);

-      if (s.IsEqualTo("*")

-          || s.IsEmpty() && propVariant.vt == VT_BSTR && StringsAreEqual_Ascii(propVariant.bstrVal, "*"))

-      {

-        multiThreadTests = true;

-        continue;

-      }

-      #ifndef _7ZIP_ST

-      RINOK(ParseMtProp(s, propVariant, numCPUs, numThreadsSpecified));

-      #endif

-      continue;

-    }

-    

-    RINOK(method.ParseMethodFromPROPVARIANT(name, propVariant));

-  }

-  }

-

-  if (printCallback)

-  {

-    #ifdef _WIN32

-    #ifndef UNDER_CE

-    {

-      AString s;

-      // 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 += " "; s.Add_UInt32(vi.dwMajorVersion);

-        s += "."; s.Add_UInt32(vi.dwMinorVersion);

-        s += " "; s.Add_UInt32(vi.dwBuildNumber);

-        // s += " "; s += GetAnsiString(vi.szCSDVersion);

-      }

-      printCallback->Print(s);

-      printCallback->NewLine();

-    }

-    #endif

-    #endif

-

-    {

-      AString s1, s2;

-      GetSysInfo(s1, s2);

-      if (!s1.IsEmpty() || !s2.IsEmpty())

-      {

-        printCallback->Print(s1);

-        if (s1 != s2 && !s2.IsEmpty())

-        {

-          printCallback->Print(" - ");

-          printCallback->Print(s2);

-        }

-        printCallback->NewLine();

-      }

-    }

-    {

-      AString s;

-      GetCpuFeatures(s);

-      if (!s.IsEmpty())

-      {

-        printCallback->Print(s);

-        printCallback->NewLine();

-      }

-    }

-    {

-      AString s;

-      GetCpuName(s);

-      if (!s.IsEmpty())

-      {

-        printCallback->Print(s);

-        printCallback->NewLine();

-      }

-    }

-  }

-

-  if (printCallback)

-  {

-    printCallback->Print("CPU Freq:");

-  }

-

-  UInt64 complexInCommands = kComplexInCommands;

-

-  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;

-      UInt64 freq = GetFreq();

-      // mips is constant in some compilers

-      const UInt64 mipsVal = numMilCommands * freq / start;

-      if (printCallback)

-      {

-        if (realDelta == 0)

-        {

-          printCallback->Print(" -");

-        }

-        else

-        {

-          // PrintNumber(*printCallback, start, 0);

-          PrintNumber(*printCallback, mipsVal, 5);

-        }

-      }

-      /*

-      if (freqCallback)

-        freqCallback->AddCpuFreq(mipsVal);

-      */

-

-      if (jj >= 3)

-      {

-        SetComplexCommands(testTime, false, mipsVal * 1000000, complexInCommands);

-        if (jj >= 8 || start >= freq)

-          break;

-        // break; // change it

-        numMilCommands <<= 1;

-      }

-    }

-  }

-

-  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;

-

-  UInt32 dict;

-  bool dictIsDefined = method.Get_DicSize(dict);

-

-  if (method.MethodName.IsEmpty())

-    method.MethodName = "LZMA";

-

-  if (benchCallback)

-  {

-    CBenchProps benchProps;

-    benchProps.SetLzmaCompexity();

-    UInt32 dictSize = method.Get_Lzma_DicSize();

-    UInt32 uncompressedDataSize = kAdditionalSize + dictSize;

-    return MethodBench(

-        EXTERNAL_CODECS_LOC_VARS

-        complexInCommands,

-        true, numThreadsSpecified,

-        method,

-        uncompressedDataSize, (const Byte *)fileDataBuffer,

-        kOldLzmaDictBits, printCallback, benchCallback, &benchProps);

-  }

-

-  AString methodName (method.MethodName);

-  if (methodName.IsEqualTo_Ascii_NoCase("CRC"))

-    methodName = "crc32";

-  method.MethodName = methodName;

-  CMethodId hashID;

-  

-  if (FindHashMethod(EXTERNAL_CODECS_LOC_VARS methodName, hashID))

-  {

-    if (!printCallback)

-      return S_FALSE;

-    IBenchPrintCallback &f = *printCallback;

-    if (!dictIsDefined)

-      dict = (1 << 24);

-

-

-    // methhodName.RemoveChar(L'-');

-    UInt32 complexity = 10000;

-    const UInt32 *checkSum = NULL;

-    {

-      unsigned i;

-      for (i = 0; i < ARRAY_SIZE(g_Hash); i++)

-      {

-        const CBenchHash &h = g_Hash[i];

-        AString benchMethod (h.Name);

-        AString benchProps;

-        int propPos = benchMethod.Find(':');

-        if (propPos >= 0)

-        {

-          benchProps = benchMethod.Ptr(propPos + 1);

-          benchMethod.DeleteFrom(propPos);

-        }

-

-        if (AreSameMethodNames(benchMethod, methodName))

-        {

-          if (benchProps.IsEmpty()

-              || benchMethod.IsEqualTo_Ascii_NoCase("crc32") && benchProps == "8" && method.PropsString.IsEmpty()

-              || method.PropsString.IsPrefixedBy_Ascii_NoCase(benchProps))

-          {

-            complexity = h.Complex;

-            checkSum = &h.CheckSum;

-            if (method.PropsString.IsEqualTo_Ascii_NoCase(benchProps))

-              break;

-          }

-        }

-      }

-      if (i == ARRAY_SIZE(g_Hash))

-        return E_NOTIMPL;

-    }

-

-    f.NewLine();

-    f.Print("Size");

-    const unsigned kFieldSize_CrcSpeed = 6;

-    unsigned numThreadsTests = 0;

-    for (;;)

-    {

-      UInt32 t = GetNumThreadsNext(numThreadsTests, numThreadsSpecified);

-      PrintNumber(f, t, kFieldSize_CrcSpeed);

-      numThreadsTests++;

-      if (t >= numThreadsSpecified)

-        break;

-    }

-    f.NewLine();

-    f.NewLine();

-    CTempValues speedTotals(numThreadsTests);

-    {

-      for (unsigned ti = 0; ti < numThreadsTests; ti++)

-        speedTotals.Values[ti] = 0;

-    }

-    

-    UInt64 numSteps = 0;

-    for (UInt32 i = 0; i < numIterations; i++)

-    {

-      for (unsigned pow = 10; pow < 32; pow++)

-      {

-        UInt32 bufSize = (UInt32)1 << pow;

-        if (bufSize > dict)

-          break;

-        char s[16];

-        ConvertUInt32ToString(pow, s);

-        unsigned pos = MyStringLen(s);

-        s[pos++] = ':';

-        s[pos++] = ' ';

-        s[pos] = 0;

-        f.Print(s);

-

-        for (unsigned ti = 0; ti < numThreadsTests; ti++)

-        {

-          RINOK(f.CheckBreak());

-          UInt32 t = GetNumThreadsNext(ti, numThreadsSpecified);

-          UInt64 speed = 0;

-          RINOK(CrcBench(EXTERNAL_CODECS_LOC_VARS complexInCommands,

-              t, bufSize, speed,

-              complexity,

-              1, // benchWeight,

-              (pow == kNumHashDictBits) ? checkSum : NULL, method, NULL, NULL, false, 0));

-          PrintNumber(f, (speed >> 20), kFieldSize_CrcSpeed);

-          speedTotals.Values[ti] += speed;

-        }

-        f.NewLine();

-        numSteps++;

-      }

-    }

-    if (numSteps != 0)

-    {

-      f.NewLine();

-      f.Print("Avg:");

-      for (unsigned ti = 0; ti < numThreadsTests; ti++)

-      {

-        PrintNumber(f, ((speedTotals.Values[ti] / numSteps) >> 20), kFieldSize_CrcSpeed);

-      }

-      f.NewLine();

-    }

-    return S_OK;

-  }

-

-  bool use2Columns = false;

-

-  bool totalBenchMode = (method.MethodName.IsEqualTo_Ascii_NoCase("*"));

-  bool onlyHashBench = false;

-  if (method.MethodName.IsEqualTo_Ascii_NoCase("hash"))

-  {

-    onlyHashBench = true;

-    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;

-    }

-  }

- 

-  CBenchCallbackToPrint callback;

-  callback.Init();

-  callback._file = printCallback;

-  

-  IBenchPrintCallback &f = *printCallback;

-

-  if (threadsPassIndex > 0)

-  {

-    f.NewLine();

-    f.NewLine();

-  }

-

-  if (!dictIsDefined)

-  {

-    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, ((UInt32)1 << dicSizeLog), totalBenchMode) + (8 << 20) <= ramSize)

-        break;

-

-    dict = (UInt32)1 << dicSizeLog;

-

-    if (totalBenchMode && dicSizeLog != dicSizeLog_Main)

-    {

-      f.Print("Dictionary reduced to: ");

-      PrintNumber(f, dicSizeLog, 1);

-      f.NewLine();

-    }

-  }

-

-  PrintRequirements(f, "usage:", true, GetBenchMemoryUsage(numThreads, dict, totalBenchMode), "Benchmark threads:   ", 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;

-

-

-  if (totalBenchMode)

-  {

-    for (UInt32 i = 0; i < numIterations; i++)

-    {

-      if (i != 0)

-        printCallback->NewLine();

-      HRESULT res;

-

-      const unsigned kNumCpuTests = 3;

-      for (unsigned freqTest = 0; freqTest < kNumCpuTests; freqTest++)

-      {

-        PrintLeft(f, "CPU", kFieldSize_Name);

-        UInt32 resVal;

-        RINOK(FreqBench(complexInCommands, numThreads, printCallback,

-            (freqTest == kNumCpuTests - 1 || specifiedFreq != 0), // showFreq

-            specifiedFreq,

-            cpuFreq, resVal));

-        callback.NewLine();

-

-        if (specifiedFreq != 0)

-          cpuFreq = specifiedFreq;

-

-        if (freqTest == kNumCpuTests - 1)

-          SetComplexCommands(testTime, specifiedFreq != 0, cpuFreq, complexInCommands);

-      }

-      callback.NewLine();

-

-      callback.SetFreq(true, cpuFreq);

-

-      if (!onlyHashBench)

-      {

-        res = TotalBench(EXTERNAL_CODECS_LOC_VARS

-            complexInCommands, numThreads,

-            dictIsDefined || fileDataBuffer.IsAllocated(), // forceUnpackSize

-            fileDataBuffer.IsAllocated() ? fileDataBuffer.Size() : dict,

-            (const Byte *)fileDataBuffer,

-            printCallback, &callback);

-        RINOK(res);

-      }

-

-      res = TotalBench_Hash(EXTERNAL_CODECS_LOC_VARS complexInCommands, numThreads,

-          1 << kNumHashDictBits, printCallback, &callback, &callback.EncodeRes, true, cpuFreq);

-      RINOK(res);

-

-      callback.NewLine();

-      {

-        PrintLeft(f, "CPU", kFieldSize_Name);

-        UInt32 resVal;

-        UInt64 cpuFreqLastTemp = cpuFreq;

-        RINOK(FreqBench(complexInCommands, numThreads, printCallback,

-            specifiedFreq != 0, // showFreq

-            specifiedFreq,

-            cpuFreqLastTemp, resVal));

-        callback.NewLine();

-      }

-    }

-  }

-  else

-  {

-    bool needSetComplexity = true;

-    if (!methodName.IsEqualTo_Ascii_NoCase("LZMA"))

-    {

-      unsigned i;

-      for (i = 0; i < ARRAY_SIZE(g_Bench); i++)

-      {

-        const CBenchMethod &h = g_Bench[i];

-        AString benchMethod (h.Name);

-        AString benchProps;

-        int propPos = benchMethod.Find(':');

-        if (propPos >= 0)

-        {

-          benchProps = benchMethod.Ptr(propPos + 1);

-          benchMethod.DeleteFrom(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 == ARRAY_SIZE(g_Bench))

-        return E_NOTIMPL;

-    }

-    if (needSetComplexity)

-      callback.BenchProps.SetLzmaCompexity();

-

-  for (unsigned i = 0; i < numIterations; i++)

-  {

-    const unsigned kStartDicLog = 22;

-    unsigned pow = (dict < ((UInt32)1 << kStartDicLog)) ? kBenchMinDicLogSize : kStartDicLog;

-    if (!multiDict)

-      pow = 31;

-    while (((UInt32)1 << pow) > dict && pow > 0)

-      pow--;

-    for (; ((UInt32)1 << pow) <= dict; pow++)

-    {

-      char s[16];

-      ConvertUInt32ToString(pow, s);

-      unsigned pos = MyStringLen(s);

-      s[pos++] = ':';

-      s[pos] = 0;

-      PrintLeft(f, s, kFieldSize_SmallName);

-      callback.DictSize = (UInt32)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 (fileDataBuffer.IsAllocated())

-      {

-        uncompressedDataSize = fileDataBuffer.Size();

-      }

-      else

-      {

-        uncompressedDataSize = callback.DictSize;

-        if (uncompressedDataSize >= (1 << 18))

-          uncompressedDataSize += kAdditionalSize;

-      }

-

-      HRESULT res = MethodBench(

-          EXTERNAL_CODECS_LOC_VARS

-          complexInCommands,

-          true, numThreads,

-          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, callback.EncodeRes);

-    f.Print(kSep);

-    PrintTotals(f, showFreq, cpuFreq, callback.DecodeRes);

-    f.NewLine();

-  }

-  

-  PrintLeft(f, "Tot:", callback.NameFieldSize);

-  CTotalBenchRes midRes;

-  midRes.SetSum(callback.EncodeRes, callback.DecodeRes);

-  PrintTotals(f, showFreq, cpuFreq, midRes);

-  f.NewLine();

-

-  }

-  return S_OK;

-}

+// Bench.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/CpuArch.h"
+
+// #include <stdio.h>
+
+#ifndef _WIN32
+
+#define USE_POSIX_TIME
+#define USE_POSIX_TIME2
+#endif // _WIN32
+
+#ifdef USE_POSIX_TIME
+#include <time.h>
+#include <unistd.h>
+#ifdef USE_POSIX_TIME2
+#include <sys/time.h>
+#include <sys/times.h>
+#endif
+#endif // USE_POSIX_TIME
+
+#ifdef _WIN32
+#define USE_ALLOCA
+#endif
+
+#ifdef USE_ALLOCA
+#ifdef _WIN32
+#include <malloc.h>
+#else
+#include <stdlib.h>
+#endif
+#endif
+
+#include "../../../../C/7zCrc.h"
+#include "../../../../C/RotateDefs.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 UInt32 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()
+  {
+    return Salt ^
+    (
+      ((A1 = 36969 * (A1 & 0xffff) + (A1 >> 16)) << 16) +
+      ((A2 = 18000 * (A2 & 0xffff) + (A2 >> 16)) )
+    );
+  }
+};
+
+
+Z7_NO_INLINE
+static void RandGen(Byte *buf, size_t size)
+{
+  CBaseRandomGenerator RG;
+  const size_t size4 = size & ~((size_t)3);
+  size_t i;
+  for (i = 0; i < size4; i += 4)
+  {
+    const UInt32 v = RG.GetRnd();
+    SetUi32(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)
+  {
+    UInt32 val = res & (((UInt32)1 << numBits) - 1);
+    res >>= numBits;
+    return val;
+  }
+  
+  static UInt32 GetLen(UInt32 &r)
+  {
+    UInt32 len = 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 != 0)
+    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<ICompressCoder> _encoder;
+  CMyComPtr<ICompressFilter> _encoderFilter;
+  CBenchProgressInfo *progressInfoSpec[2];
+  CMyComPtr<ICompressProgressInfo> 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<ICompressCoder> _decoders[2];
+  CMyComPtr<ICompressFilter> _decoderFilter;
+
+  HRESULT Results[2];
+  CBenchmarkOutStream *outStreamSpec;
+  CMyComPtr<ISequentialOutStream> 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<ISequentialOutStream> 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);
+    #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<IUnknown> coder;
+  if (_encoderFilter)
+    coder = _encoderFilter;
+  else
+    coder = _encoder;
+  {
+    CMyComPtr<ICompressSetCoderProperties> 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<ICompressWriteCoderProperties> writeCoderProps;
+    coder.QueryInterface(IID_ICompressWriteCoderProperties, &writeCoderProps);
+    if (writeCoderProps)
+    {
+      RINOK(writeCoderProps->WriteCoderProperties(propStream))
+    }
+
+    {
+      CMyComPtr<ICryptoSetPassword> 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<ISequentialInStream> inStream = inStreamSpec;
+          inStreamSpec->Init(temp, sizeof(temp));
+          
+          CCrcOutStream *crcStreamSpec = new CCrcOutStream;
+          CMyComPtr<ISequentialOutStream> 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<ICryptoProperties> cp;
+  CMyComPtr<IUnknown> coder;
+  if (_encoderFilter)
+    coder = _encoderFilter;
+  else
+    coder = _encoder;
+  coder.QueryInterface(IID_ICryptoProperties, &cp);
+  CBenchmarkInStream *inStreamSpec = new CBenchmarkInStream;
+  CMyComPtr<ISequentialInStream> 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)
+      {
+        filterData = (Byte *)*outStreamSpec;
+        if (data_Was_Changed)
+          memcpy(filterData, uncompressedDataPtr, kBufferSize);
+        data_Was_Changed = true;
+      }
+      _encoderFilter->Init();
+      if (calcCrc)
+        outStreamSpec->InitCrc();
+      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<ISequentialInStream> inStream = inStreamSpec;
+  CMyComPtr<ICompressCoder> &decoder = _decoders[decoderIndex];
+  CMyComPtr<IUnknown> coder;
+  if (_decoderFilter)
+  {
+    if (decoderIndex != 0)
+      return E_FAIL;
+    coder = _decoderFilter;
+  }
+  else
+    coder = decoder;
+
+  CMyComPtr<ICompressSetDecoderProperties2> setDecProps;
+  coder.QueryInterface(IID_ICompressSetDecoderProperties2, &setDecProps);
+  if (!setDecProps && propStreamSpec->GetPos() != 0)
+    return E_FAIL;
+
+  CCrcOutStream *crcOutStreamSpec = new CCrcOutStream;
+  CMyComPtr<ISequentialOutStream> crcOutStream = crcOutStreamSpec;
+    
+  CBenchProgressInfo *pi = progressInfoSpec[decoderIndex];
+  pi->BenchInfo.UnpackSize = 0;
+  pi->BenchInfo.PackSize = 0;
+
+  #ifndef Z7_ST
+  {
+    CMyComPtr<ICompressSetCoderMt> setCoderMt;
+    coder.QueryInterface(IID_ICompressSetCoderMt, &setCoderMt);
+    if (setCoderMt)
+    {
+      RINOK(setCoderMt->SetNumberOfThreads(NumDecoderSubThreads))
+    }
+  }
+  #endif
+
+  CMyComPtr<ICompressSetCoderProperties> scp;
+  coder.QueryInterface(IID_ICompressSetCoderProperties, &scp);
+  if (scp)
+  {
+    const UInt64 reduceSize = _uncompressedDataSize;
+    RINOK(_method.SetCoderProps(scp, &reduceSize))
+  }
+
+  CMyComPtr<ICryptoProperties> cp;
+  coder.QueryInterface(IID_ICryptoProperties, &cp);
+  
+  if (setDecProps)
+  {
+    RINOK(setDecProps->SetDecoderProperties2(
+        /* (const Byte *)*propStreamSpec, */
+        propsData,
+        (UInt32)propStreamSpec->GetPos()))
+  }
+
+  {
+    CMyComPtr<ICryptoSetPassword> 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<ICompressSetFinishMode> 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<ICompressGetInStreamProcessedSize> 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<ICompressCoder> &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;
+    encoder.Salt = g_CrcTable[i & 0xFF];
+    encoder.Salt ^= (g_CrcTable[(i >> 8) & 0xFF] << 3);
+    // (g_CrcTable[0] == 0), and (encoder.Salt == 0) for first thread
+    // printf(" %8x", 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 = (i * 16 * 21) & 0x7FF;
+      #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
+    {
+      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
+            , ((i * numSubDecoderThreads + j) * 16 * 21) & 0x7FF
+            #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;
+  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);
+};
+
+
+HRESULT CCrcInfo_Base::Generate(const Byte *data, size_t size)
+{
+  Size = size;
+  Data = data;
+  if (!data || CreateLocalBuf)
+  {
+    ALLOC_WITH_HRESULT(&Buffer, size)
+    Data = Buffer;
+  }
+  if (!data)
+    RandGen(Buffer, size);
+  else if (CreateLocalBuf && size != 0)
+    memcpy(Buffer, data, size);
+  return S_OK;
+}
+
+
+HRESULT CCrcInfo_Base::CrcProcess(UInt64 numIterations,
+    const UInt32 *checkSum, IHasher *hf,
+    IBenchPrintCallback *callback)
+{
+  MY_ALIGN(16)
+  Byte hash[64];
+  memset(hash, 0, sizeof(hash));
+
+  CheckSum_Res = 0;
+
+  const UInt32 hashSize = hf->GetDigestSize();
+  if (hashSize > sizeof(hash))
+    return S_FALSE;
+
+  const Byte *buf = Data;
+  const size_t size = Size;
+  UInt32 checkSum_Prev = 0;
+
+  UInt64 prev = 0;
+  UInt64 cur = 0;
+
+  for (UInt64 i = 0; i < numIterations; i++)
+  {
+    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(hash);
+    UInt32 sum = 0;
+    for (UInt32 j = 0; j < hashSize; j += 4)
+    {
+      sum = rotlFixed(sum, 11);
+      sum += GetUi32(hash + 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())
+      }
+    }
+  }
+  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<IHasher> 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 kBufferSize0 = (1 << 8);
+  const size_t kBufferSize1 = (1 << 10);
+  const unsigned kCheckSize = (1 << 5);
+  buffer.Alloc(kBufferSize0 + kBufferSize1);
+  if (!buffer.IsAllocated())
+    return false;
+  Byte *buf = (Byte *)buffer;
+  size_t i;
+  for (i = 0; i < kBufferSize0; i++)
+    buf[i] = (Byte)i;
+  UInt32 crc1 = CrcCalc1(buf, kBufferSize0);
+  if (crc1 != 0x29058C73)
+    return false;
+  RandGen(buf + kBufferSize0, kBufferSize1);
+  for (i = 0; i < kBufferSize0 + kBufferSize1 - kCheckSize; i++)
+    for (unsigned j = 0; j < kCheckSize; j++)
+      if (CrcCalc1(buf + i, j) != CrcCalc(buf + i, j))
+        return false;
+  return true;
+}
+
+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" },
+  
+  // { 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, CMPLX(1), "AES128CBC:3" },
+  // {  1,  0, CMPLX(7), 0, CMPLX(1), "AES192CBC:3" },
+  {  1,  0, CMPLX(8), 0, CMPLX(1), "AES256CBC:3" }
+  
+  // {  1,  0, CMPLX(1), 0, CMPLX(1), "AES128CTR:3" },
+  // {  1,  0, CMPLX(1), 0, CMPLX(1), "AES192CTR:3" },
+  // {  1,  0, CMPLX(1), 0, CMPLX(1), "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[] =
+{
+  // {  1,  1820, 0x21e207bb, "CRC32:1" },
+  // { 10,   558, 0x21e207bb, "CRC32:4" },
+  { 20,   339, 0x21e207bb, "CRC32:8" } ,
+  {  2,   128 *ARM_CRC_MUL, 0x21e207bb, "CRC32:32" },
+  {  2,    64 *ARM_CRC_MUL, 0x21e207bb, "CRC32:64" },
+  { 10,   512, 0x41b901d1, "CRC64" },
+  
+  { 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,  5500, 0x85189d02, "BLAKE2sp" }
+};
+
+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;
+    for (UInt64 k = numIterations; k > 0; k--)
+    {
+      sum = CountCpuFreq(sum, numIterations2, g_BenchCpuFreqTemp);
+      if (_file)
+      {
+        RINOK(_file->CheckBreak())
+      }
+    }
+    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<ICompressSetCoderProperties> 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 = (i * 16 * 21) & 0x7FF;
+      #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<IHasher> hasher;
+    AString name;
+    RINOK(CreateHasher(EXTERNAL_CODECS_LOC_VARS hashID, name, hasher))
+    if (!hasher)
+      return E_NOTIMPL;
+    CMyComPtr<ICompressSetCoderProperties> 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<CProperty> &props,
+    UInt32 numIterations,
+    bool multiDict,
+    IBenchFreqCallback *freqCallback)
+{
+  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;
+  }
+  */
+  
+  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;
+    
+   #ifndef _WIN32
+    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 hz = 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, hz, 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 (numThreadsSpecified >= 2)
+  if (printCallback || freqCallback)
+  {
+    if (printCallback)
+      printCallback->NewLine();
+
+    /* it can show incorrect frequency for HT threads.
+       so we reduce freq test to (numCPUs / 2) */
+
+    UInt32 numThreads = numThreadsSpecified >= numCPUs / 2 ? numCPUs / 2: numThreadsSpecified;
+    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;
+}
diff --git a/CPP/7zip/UI/Common/Bench.h b/CPP/7zip/UI/Common/Bench.h
index 1d052aa..313676d 100644
--- a/CPP/7zip/UI/Common/Bench.h
+++ b/CPP/7zip/UI/Common/Bench.h
@@ -1,77 +1,121 @@
-// Bench.h

-

-#ifndef __7ZIP_BENCH_H

-#define __7ZIP_BENCH_H

-

-#include "../../../Windows/System.h"

-

-#include "../../Common/CreateCoder.h"

-#include "../../UI/Common/Property.h"

-

-struct CBenchInfo

-{

-  UInt64 GlobalTime;

-  UInt64 GlobalFreq;

-  UInt64 UserTime;

-  UInt64 UserFreq;

-  UInt64 UnpackSize;

-  UInt64 PackSize;

-  UInt64 NumIterations;

-  

-  CBenchInfo(): NumIterations(0) {}

-  UInt64 GetUsage() const;

-  UInt64 GetRatingPerUsage(UInt64 rating) const;

-  UInt64 GetSpeed(UInt64 numCommands) const;

-};

-

-struct 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;

-};

-

-UInt64 GetCompressRating(UInt32 dictSize, UInt64 elapsedTime, UInt64 freq, UInt64 size);

-UInt64 GetDecompressRating(UInt64 elapsedTime, UInt64 freq, UInt64 outSize, UInt64 inSize, UInt64 numIterations);

-

-const unsigned kBenchMinDicLogSize = 18;

-

-UInt64 GetBenchMemoryUsage(UInt32 numThreads, UInt32 dictionary, bool totalBench = false);

-

-struct IBenchPrintCallback

-{

-  virtual void Print(const char *s) = 0;

-  virtual void NewLine() = 0;

-  virtual HRESULT CheckBreak() = 0;

-};

-

-/*

-struct IBenchFreqCallback

-{

-  virtual void AddCpuFreq(UInt64 freq) = 0;

-};

-*/

-

-HRESULT Bench(

-    DECL_EXTERNAL_CODECS_LOC_VARS

-    IBenchPrintCallback *printCallback,

-    IBenchCallback *benchCallback,

-    // IBenchFreqCallback *freqCallback,

-    const CObjectVector<CProperty> &props,

-    UInt32 numIterations,

-    bool multiDict

-    );

-

-AString GetProcessThreadsInfo(const NWindows::NSystem::CProcessAffinity &ti);

-

-void GetSysInfo(AString &s1, AString &s2);

-void GetCpuName(AString &s);

-void GetCpuFeatures(AString &s);

-

-#ifdef _7ZIP_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<CProperty> &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
new file mode 100644
index 0000000..42bae2a
--- /dev/null
+++ b/CPP/7zip/UI/Common/CompressCall.cpp
@@ -0,0 +1,343 @@
+// CompressCall.cpp
+
+#include "StdAfx.h"
+
+#include <wchar.h>
+
+#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 += '\"';
+  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 &params,
+    // 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 &params)
+{
+  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 &params)
+{
+  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 += '#';
+  params += mappingName;
+  params += ':';
+  char temp[32];
+  ConvertUInt64ToString(totalSize, temp);
+  params += temp;
+  
+  params += ':';
+  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 &params, 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
new file mode 100644
index 0000000..f2da163
--- /dev/null
+++ b/CPP/7zip/UI/Common/CompressCall.h
@@ -0,0 +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
diff --git a/CPP/7zip/UI/Common/CompressCall2.cpp b/CPP/7zip/UI/Common/CompressCall2.cpp
new file mode 100644
index 0000000..21eb472
--- /dev/null
+++ b/CPP/7zip/UI/Common/CompressCall2.cpp
@@ -0,0 +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<ICompressCodecsInfo> 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<IUnknown> 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 += '\"';
+  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<COpenType> 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<IFolderArchiveExtractCallback> 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<COpenType> 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<CProperty> 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 0c13e9e..8c34ffc 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(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 4484c3b..46f6e9e 100644
--- a/CPP/7zip/UI/Common/DefaultName.h
+++ b/CPP/7zip/UI/Common/DefaultName.h
@@ -1,11 +1,11 @@
-// DefaultName.h

-

-#ifndef __DEFAULT_NAME_H

-#define __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 47485be..ae84937 100644
--- a/CPP/7zip/UI/Common/DirItem.h
+++ b/CPP/7zip/UI/Common/DirItem.h
@@ -1,190 +1,404 @@
-// DirItem.h

-

-#ifndef __DIR_ITEM_H

-#define __DIR_ITEM_H

-

-#include "../../../Common/MyString.h"

-

-#include "../../../Windows/FileFind.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)

-    {}

-};

-

-

-

-#define INTERFACE_IDirItemsCallback(x) \

-  virtual HRESULT ScanError(const FString &path, DWORD systemError) x; \

-  virtual HRESULT ScanProgress(const CDirItemsStat &st, const FString &path, bool isDir) x; \

-

-struct IDirItemsCallback

-{

-  INTERFACE_IDirItemsCallback(=0)

-};

-

-struct CDirItem

-{

-  UInt64 Size;

-  FILETIME CTime;

-  FILETIME ATime;

-  FILETIME MTime;

-  UString Name;

-  

-  #if defined(_WIN32) && !defined(UNDER_CE)

-  // UString ShortName;

-  CByteBuffer ReparseData;

-  CByteBuffer ReparseData2; // fixed (reduced) absolute links

-

-  bool AreReparseData() const { return ReparseData.Size() != 0 || ReparseData2.Size() != 0; }

-  #endif

-  

-  UInt32 Attrib;

-  int PhyParent;

-  int LogParent;

-  int SecureIndex;

-

-  bool IsAltStream;

-  

-  CDirItem(): PhyParent(-1), LogParent(-1), SecureIndex(-1), IsAltStream(false) {}

-  bool IsDir() const { return (Attrib & FILE_ATTRIBUTE_DIRECTORY) != 0 ; }

-};

-

-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<CDirItem> Items;

-

-  bool SymLinks;

-

-  bool ScanAltStreams;

-  

-  CDirItemsStat Stat;

-

-  #ifndef 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);

-

-  #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 EnumerateItems2(

-    const FString &phyPrefix,

-    const UString &logPrefix,

-    const FStringVector &filePaths,

-    FStringVector *requestedPaths);

-

-  #if defined(_WIN32) && !defined(UNDER_CE)

-  void FillFixedReparse();

-  #endif

-

-  void ReserveDown();

-};

-

-struct CArcItem

-{

-  UInt64 Size;

-  FILETIME MTime;

-  UString Name;

-  bool IsDir;

-  bool IsAltStream;

-  bool SizeDefined;

-  bool MTimeDefined;

-  bool Censored;

-  UInt32 IndexInServer;

-  int TimeType;

-  

-  CArcItem(): IsDir(false), IsAltStream(false), SizeDefined(false), MTimeDefined(false), Censored(false), TimeType(-1) {}

-};

-

-#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
+
+  CDirItem():
+      PhyParent(-1)
+    , LogParent(-1)
+    , SecureIndex(-1)
+   #ifdef _WIN32
+   #else
+    , OwnerNameIndex(-1)
+    , OwnerGroupIndex(-1)
+   #endif
+  {
+  }
+
+
+  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<CDirItem> 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<NWindows::NFile::NFind::CDirEntry> &files);
+  HRESULT EnumerateOneDir(const FString &phyPrefix, CObjectVector<NWindows::NFile::NFind::CFileInfo> &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 2c941e1..d536c47 100644
--- a/CPP/7zip/UI/Common/EnumDirItems.cpp
+++ b/CPP/7zip/UI/Common/EnumDirItems.cpp
@@ -1,1096 +1,1656 @@
-// EnumDirItems.cpp

-

-#include "StdAfx.h"

-

-#include <wchar.h>

-

-#include "../../../Common/Wildcard.h"

-

-#include "../../../Windows/FileDir.h"

-#include "../../../Windows/FileIO.h"

-#include "../../../Windows/FileName.h"

-

-#if defined(_WIN32) && !defined(UNDER_CE)

-#define _USE_SECURITY_CODE

-#include "../../../Windows/SecurityUtils.h"

-#endif

-

-#include "EnumDirItems.h"

-#include "SortUtils.h"

-

-using namespace NWindows;

-using namespace NFile;

-using namespace NName;

-

-void CDirItems::AddDirFileInfo(int phyParent, int logParent, int secureIndex,

-    const NFind::CFileInfo &fi)

-{

-  CDirItem di;

-  di.Size = fi.Size;

-  di.CTime = fi.CTime;

-  di.ATime = fi.ATime;

-  di.MTime = fi.MTime;

-  di.Attrib = fi.Attrib;

-  di.IsAltStream = fi.IsAltStream;

-  di.PhyParent = phyParent;

-  di.LogParent = logParent;

-  di.SecureIndex = secureIndex;

-  di.Name = fs2us(fi.Name);

-  #if defined(_WIN32) && !defined(UNDER_CE)

-  // di.ShortName = fs2us(fi.ShortName);

-  #endif

-  Items.Add(di);

-  

-  if (fi.IsDir())

-    Stat.NumDirs++;

-  else if (fi.IsAltStream)

-  {

-    Stat.NumAltStreams++;

-    Stat.AltStreamsSize += fi.Size;

-  }

-  else

-  {

-    Stat.NumFiles++;

-    Stat.FilesSize += fi.Size;

-  }

-}

-

-HRESULT CDirItems::AddError(const FString &path, DWORD errorCode)

-{

-  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[i])

-    len += Prefixes[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[i])

-  {

-    const UString &s = Prefixes[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)

-    #ifdef _USE_SECURITY_CODE

-    , ReadSecure(false)

-    #endif

-    , Callback(NULL)

-{

-  #ifdef _USE_SECURITY_CODE

-  _saclEnabled = InitLocalPrivileges();

-  #endif

-}

-

-#ifdef _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)(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)(Byte *)TempSecureBuf, (DWORD)TempSecureBuf.Size(), &secureSize);

-        if (res)

-        {

-          if (secureSize != TempSecureBuf.Size())

-            errorCode = ERROR_INVALID_FUNCTION;;

-        }

-        else

-          errorCode = GetLastError();

-      }

-    }

-  }

-  

-  if (res)

-  {

-    secureIndex = SecureBlocks.AddUniq(TempSecureBuf, secureSize);

-    return S_OK;

-  }

-  

-  if (errorCode == 0)

-    errorCode = ERROR_INVALID_FUNCTION;

-  return AddError(path, errorCode);

-}

-

-#endif

-

-HRESULT CDirItems::EnumerateDir(int phyParent, int logParent, const FString &phyPrefix)

-{

-  RINOK(ScanProgress(phyPrefix));

-

-  NFind::CEnumerator enumerator;

-  enumerator.SetDirPrefix(phyPrefix);

-  for (unsigned ttt = 0; ; ttt++)

-  {

-    NFind::CFileInfo fi;

-    bool found;

-    if (!enumerator.Next(fi, found))

-    {

-      return AddError(phyPrefix);

-    }

-    if (!found)

-      return S_OK;

-

-    int secureIndex = -1;

-    #ifdef _USE_SECURITY_CODE

-    if (ReadSecure)

-    {

-      RINOK(AddSecurityItem(phyPrefix + fi.Name, secureIndex));

-    }

-    #endif

-    

-    AddDirFileInfo(phyParent, logParent, secureIndex, fi);

-    

-    if (Callback && (ttt & 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(parent, parent, phyPrefix + name2));

-    }

-  }

-}

-

-HRESULT CDirItems::EnumerateItems2(

-    const FString &phyPrefix,

-    const UString &logPrefix,

-    const FStringVector &filePaths,

-    FStringVector *requestedPaths)

-{

-  int phyParent = phyPrefix.IsEmpty() ? -1 : AddPrefix(-1, -1, fs2us(phyPrefix));

-  int logParent = logPrefix.IsEmpty() ? -1 : AddPrefix(-1, -1, logPrefix);

-

-  FOR_VECTOR (i, filePaths)

-  {

-    const FString &filePath = filePaths[i];

-    NFind::CFileInfo fi;

-    const FString phyPath = phyPrefix + filePath;

-    if (!fi.Find(phyPath))

-    {

-      RINOK(AddError(phyPath));

-      continue;

-    }

-    if (requestedPaths)

-      requestedPaths->Add(phyPath);

-

-    int delimiter = filePath.ReverseFind_PathSepar();

-    FString phyPrefixCur;

-    int phyParentCur = phyParent;

-    if (delimiter >= 0)

-    {

-      phyPrefixCur.SetFrom(filePath, delimiter + 1);

-      phyParentCur = AddPrefix(phyParent, logParent, fs2us(phyPrefixCur));

-    }

-

-    int secureIndex = -1;

-    #ifdef _USE_SECURITY_CODE

-    if (ReadSecure)

-    {

-      RINOK(AddSecurityItem(phyPath, secureIndex));

-    }

-    #endif

-

-    AddDirFileInfo(phyParentCur, logParent, secureIndex, fi);

-    

-    if (fi.IsDir())

-    {

-      const FString name2 = fi.Name + FCHAR_PATH_SEPARATOR;

-      unsigned parent = AddPrefix(phyParentCur, logParent, fs2us(name2));

-      RINOK(EnumerateDir(parent, parent, phyPrefix + phyPrefixCur + name2));

-    }

-  }

-  

-  ReserveDown();

-  return S_OK;

-}

-

-

-

-

-

-

-static HRESULT EnumerateDirItems(

-    const NWildcard::CCensorNode &curNode,

-    int phyParent, int logParent, const FString &phyPrefix,

-    const UStringVector &addArchivePrefix,

-    CDirItems &dirItems,

-    bool enterToSubFolders);

-

-static HRESULT EnumerateDirItems_Spec(

-    const NWildcard::CCensorNode &curNode,

-    int phyParent, int logParent, const FString &curFolderName,

-    const FString &phyPrefix,

-    const UStringVector &addArchivePrefix,

-    CDirItems &dirItems,

-    bool enterToSubFolders)

-{

-  const FString name2 = curFolderName + FCHAR_PATH_SEPARATOR;

-  unsigned parent = dirItems.AddPrefix(phyParent, logParent, fs2us(name2));

-  unsigned numItems = dirItems.Items.Size();

-  HRESULT res = EnumerateDirItems(

-      curNode, parent, parent, phyPrefix + name2,

-      addArchivePrefix, 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,

-    int phyParent, int logParent, const FString &fullPath,

-    const UStringVector &addArchivePrefix,  // prefix from curNode

-    bool addAllItems,

-    CDirItems &dirItems)

-{

-  NFind::CStreamEnumerator enumerator(fullPath);

-  for (;;)

-  {

-    NFind::CStreamInfo si;

-    bool found;

-    if (!enumerator.Next(si, found))

-    {

-      return dirItems.AddError(fullPath + FTEXT(":*")); // , (DWORD)E_FAIL

-    }

-    if (!found)

-      return S_OK;

-    if (si.IsMainStream())

-      continue;

-    UStringVector addArchivePrefixNew = addArchivePrefix;

-    UString reducedName = si.GetReducedName();

-    addArchivePrefixNew.Back() += reducedName;

-    if (curNode.CheckPathToRoot(false, addArchivePrefixNew, true))

-      continue;

-    if (!addAllItems)

-      if (!curNode.CheckPathToRoot(true, addArchivePrefixNew, true))

-        continue;

-

-    NFind::CFileInfo fi2 = fi;

-    fi2.Name += us2fs(reducedName);

-    fi2.Size = si.Size;

-    fi2.Attrib &= ~FILE_ATTRIBUTE_DIRECTORY;

-    fi2.IsAltStream = true;

-    dirItems.AddDirFileInfo(phyParent, logParent, -1, fi2);

-  }

-}

-

-#endif

-

-HRESULT CDirItems::SetLinkInfo(CDirItem &dirItem, const NFind::CFileInfo &fi,

-    const FString &phyPrefix)

-{

-  if (!SymLinks || !fi.HasReparsePoint())

-    return S_OK;

-  const FString path = phyPrefix + fi.Name;

-  CByteBuffer &buf = dirItem.ReparseData;

-  DWORD res = 0;

-  if (NIO::GetReparseData(path, buf))

-  {

-    CReparseAttr attr;

-    if (attr.Parse(buf, buf.Size(), res))

-      return S_OK;

-    // we ignore unknown reparse points

-    if (res != ERROR_INVALID_REPARSE_DATA)

-      res = 0;

-  }

-  else

-  {

-    res = ::GetLastError();

-    if (res == 0)

-      res = ERROR_INVALID_FUNCTION;

-  }

-

-  buf.Free();

-  if (res == 0)

-    return S_OK;

-  return AddError(path, res);

-}

-

-#endif

-

-static HRESULT EnumerateForItem(

-    NFind::CFileInfo &fi,

-    const NWildcard::CCensorNode &curNode,

-    int phyParent, int logParent, const FString &phyPrefix,

-    const UStringVector &addArchivePrefix,  // prefix from curNode

-    CDirItems &dirItems,

-    bool enterToSubFolders)

-{

-  const UString name = fs2us(fi.Name);

-  bool enterToSubFolders2 = enterToSubFolders;

-  UStringVector addArchivePrefixNew = addArchivePrefix;

-  addArchivePrefixNew.Add(name);

-  {

-    UStringVector addArchivePrefixNewTemp(addArchivePrefixNew);

-    if (curNode.CheckPathToRoot(false, addArchivePrefixNewTemp, !fi.IsDir()))

-      return S_OK;

-  }

-  int dirItemIndex = -1;

-  

-  bool addAllSubStreams = false;

-

-  if (curNode.CheckPathToRoot(true, addArchivePrefixNew, !fi.IsDir()))

-  {

-    int secureIndex = -1;

-    #ifdef _USE_SECURITY_CODE

-    if (dirItems.ReadSecure)

-    {

-      RINOK(dirItems.AddSecurityItem(phyPrefix + fi.Name, secureIndex));

-    }

-    #endif

-    

-    dirItemIndex = dirItems.Items.Size();

-    dirItems.AddDirFileInfo(phyParent, logParent, secureIndex, fi);

-    if (fi.IsDir())

-      enterToSubFolders2 = true;

-

-    addAllSubStreams = true;

-  }

-

-  #ifndef UNDER_CE

-  if (dirItems.ScanAltStreams)

-  {

-    RINOK(EnumerateAltStreams(fi, curNode, phyParent, logParent,

-        phyPrefix + fi.Name,

-        addArchivePrefixNew,

-        addAllSubStreams,

-        dirItems));

-  }

-

-  if (dirItemIndex >= 0)

-  {

-    CDirItem &dirItem = dirItems.Items[dirItemIndex];

-    RINOK(dirItems.SetLinkInfo(dirItem, fi, phyPrefix));

-    if (dirItem.ReparseData.Size() != 0)

-      return S_OK;

-  }

-  #endif

-  

-  if (!fi.IsDir())

-    return S_OK;

-  

-  const NWildcard::CCensorNode *nextNode = 0;

-  if (addArchivePrefix.IsEmpty())

-  {

-    int index = curNode.FindSubNode(name);

-    if (index >= 0)

-      nextNode = &curNode.SubNodes[index];

-  }

-  if (!enterToSubFolders2 && nextNode == 0)

-    return S_OK;

-  

-  addArchivePrefixNew = addArchivePrefix;

-  if (nextNode == 0)

-  {

-    nextNode = &curNode;

-    addArchivePrefixNew.Add(name);

-  }

-  

-  return EnumerateDirItems_Spec(

-      *nextNode, phyParent, logParent, fi.Name, phyPrefix,

-      addArchivePrefixNew,

-      dirItems,

-      enterToSubFolders2);

-}

-

-

-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 */

-    /*

-    if (!item.WildcardParsing)

-      continue;

-    */

-    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();

-  return IsPathSepar(s[0]) && GetRootPrefixSize(s) == 0;

-}

-

-#endif

-

-static HRESULT EnumerateDirItems(

-    const NWildcard::CCensorNode &curNode,

-    int phyParent, int logParent, const FString &phyPrefix,

-    const UStringVector &addArchivePrefix,  // prefix from curNode

-    CDirItems &dirItems,

-    bool enterToSubFolders)

-{

-  if (!enterToSubFolders)

-    if (curNode.NeedCheckSubDirs())

-      enterToSubFolders = true;

-  

-  RINOK(dirItems.ScanProgress(phyPrefix));

-

-  // try direct_names case at first

-  if (addArchivePrefix.IsEmpty() && !enterToSubFolders)

-  {

-    if (CanUseFsDirect(curNode))

-    {

-      // all names are direct (no wildcards)

-      // so we don't need file_system's dir enumerator

-      CRecordVector<bool> 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);

-

-        #if defined(_WIN32) && !defined(UNDER_CE)

-        bool needAltStreams = true;

-        #endif

-

-        #ifdef _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 _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 (!fi.Find(fullPath))

-        {

-          RINOK(dirItems.AddError(fullPath));

-          continue;

-        }

-

-        bool isDir = fi.IsDir();

-        if (isDir && !item.ForDir || !isDir && !item.ForFile)

-        {

-          RINOK(dirItems.AddError(fullPath, (DWORD)E_FAIL));

-          continue;

-        }

-        {

-          UStringVector pathParts;

-          pathParts.Add(fs2us(fi.Name));

-          if (curNode.CheckPathToRoot(false, pathParts, !isDir))

-            continue;

-        }

-        

-        int secureIndex = -1;

-        #ifdef _USE_SECURITY_CODE

-        if (needSecurity && dirItems.ReadSecure)

-        {

-          RINOK(dirItems.AddSecurityItem(fullPath, secureIndex));

-        }

-        #endif

-

-        dirItems.AddDirFileInfo(phyParent, logParent, secureIndex, fi);

-

-        #ifndef UNDER_CE

-        {

-          CDirItem &dirItem = dirItems.Items.Back();

-          RINOK(dirItems.SetLinkInfo(dirItem, fi, phyPrefix));

-          if (dirItem.ReparseData.Size() != 0)

-          {

-            if (fi.IsAltStream)

-              dirItems.Stat.AltStreamsSize -= fi.Size;

-            else

-              dirItems.Stat.FilesSize -= fi.Size;

-            continue;

-          }

-        }

-        #endif

-

-

-        #ifndef UNDER_CE

-        if (needAltStreams && dirItems.ScanAltStreams)

-        {

-          UStringVector pathParts;

-          pathParts.Add(fs2us(fi.Name));

-          RINOK(EnumerateAltStreams(fi, curNode, phyParent, logParent,

-              fullPath, pathParts,

-              true, /* addAllSubStreams */

-              dirItems));

-        }

-        #endif

-

-        if (!isDir)

-          continue;

-        

-        UStringVector addArchivePrefixNew;

-        const NWildcard::CCensorNode *nextNode = 0;

-        int index = curNode.FindSubNode(name);

-        if (index >= 0)

-        {

-          for (int t = needEnterVector.Size(); t <= index; t++)

-            needEnterVector.Add(true);

-          needEnterVector[index] = false;

-          nextNode = &curNode.SubNodes[index];

-        }

-        else

-        {

-          nextNode = &curNode;

-          addArchivePrefixNew.Add(name); // don't change it to fi.Name. It's for shortnames support

-        }

-

-        RINOK(EnumerateDirItems_Spec(*nextNode, phyParent, logParent, fi.Name, phyPrefix,

-            addArchivePrefixNew, 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 (phyPrefix.IsEmpty())

-        {

-          {

-            if (nextNode.Name.IsEmpty())

-              fullPath = CHAR_PATH_SEPARATOR;

-            #ifdef _WIN32

-            else 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 (!fi.Find(fullPath))

-          {

-            if (!nextNode.AreThereIncludeItems())

-              continue;

-            RINOK(dirItems.AddError(fullPath));

-            continue;

-          }

-        

-          if (!fi.IsDir())

-          {

-            RINOK(dirItems.AddError(fullPath, (DWORD)E_FAIL));

-            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,

-            addArchivePrefix, dirItems, enterToSubFolders));

-      }

-      return S_OK;

-    }

-  }

-  

-  #endif

-  #endif

-

-  NFind::CEnumerator enumerator;

-  enumerator.SetDirPrefix(phyPrefix);

-

-  for (unsigned ttt = 0; ; ttt++)

-  {

-    NFind::CFileInfo fi;

-    bool found;

-    if (!enumerator.Next(fi, found))

-    {

-      RINOK(dirItems.AddError(phyPrefix));

-      break;

-    }

-    if (!found)

-      break;

-

-    if (dirItems.Callback && (ttt & kScanProgressStepMask) == kScanProgressStepMask)

-    {

-      RINOK(dirItems.ScanProgress(phyPrefix));

-    }

-

-    RINOK(EnumerateForItem(fi, curNode, phyParent, logParent, phyPrefix,

-          addArchivePrefix, dirItems, enterToSubFolders));

-  }

-

-  return S_OK;

-}

-

-HRESULT EnumerateItems(

-    const NWildcard::CCensor &censor,

-    const NWildcard::ECensorPathMode pathMode,

-    const UString &addPathPrefix,

-    CDirItems &dirItems)

-{

-  FOR_VECTOR (i, censor.Pairs)

-  {

-    const NWildcard::CPair &pair = censor.Pairs[i];

-    int phyParent = pair.Prefix.IsEmpty() ? -1 : dirItems.AddPrefix(-1, -1, pair.Prefix);

-    int logParent = -1;

-    

-    if (pathMode == NWildcard::k_AbsPath)

-      logParent = phyParent;

-    else

-    {

-      if (!addPathPrefix.IsEmpty())

-        logParent = 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)

-  dirItems.FillFixedReparse();

-  #endif

-

-  return S_OK;

-}

-

-#if defined(_WIN32) && !defined(UNDER_CE)

-

-void CDirItems::FillFixedReparse()

-{

-  /* imagex/WIM reduces absolute pathes in links (raparse data),

-     if we archive non root folder. We do same thing here */

-

-  if (!SymLinks)

-    return;

-  

-  FOR_VECTOR(i, Items)

-  {

-    CDirItem &item = Items[i];

-    if (item.ReparseData.Size() == 0)

-      continue;

-    

-    CReparseAttr attr;

-    DWORD errorCode = 0;

-    if (!attr.Parse(item.ReparseData, item.ReparseData.Size(), errorCode))

-      continue;

-    if (attr.IsRelative())

-      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;

-    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;

-

-    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;

-    if (!FillLinkData(data, newLink, attr.IsSymLink()))

-      continue;

-    item.ReparseData2 = data;

-  }

-}

-

-#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

-

-// This code converts all short file names to long file names.

-

-static void ConvertToLongName(const UString &prefix, UString &name)

-{

-  if (name.IsEmpty() || DoesNameContainWildcard(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<NWildcard::CItem> &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 <wchar.h>
+// #include <stdio.h>
+
+#ifndef _WIN32
+#include <grp.h>
+#include <pwd.h>
+#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<NFind::CFileInfo> &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<NFind::CDirEntry> entries;
+
+  for (unsigned ttt = 0; ; ttt++)
+  {
+    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<NFind::CFileInfo> 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<bool> 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<NFind::CFileInfo> 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<NWildcard::CItem> &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 ae1d226..24f1c8b 100644
--- a/CPP/7zip/UI/Common/EnumDirItems.h
+++ b/CPP/7zip/UI/Common/EnumDirItems.h
@@ -1,42 +1,38 @@
-// EnumDirItems.h

-

-#ifndef __ENUM_DIR_ITEMS_H

-#define __ENUM_DIR_ITEMS_H

-

-#include "../../../Common/Wildcard.h"

-

-#include "../../../Windows/FileFind.h"

-

-#include "DirItem.h"

-

-void AddDirFileInfo(int phyParent, int logParent, int secureIndex,

-    const NWindows::NFile::NFind::CFileInfo &fi, CObjectVector<CDirItem> &dirItems);

-

-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 d03ec6d..2d7b029 100644
--- a/CPP/7zip/UI/Common/ExitCode.h
+++ b/CPP/7zip/UI/Common/ExitCode.h
@@ -1,27 +1,27 @@
-// ExitCode.h

-

-#ifndef __EXIT_CODE_H

-#define __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 2cb2c9b..34b4871 100644
--- a/CPP/7zip/UI/Common/Extract.cpp
+++ b/CPP/7zip/UI/Common/Extract.cpp
@@ -1,482 +1,570 @@
-// Extract.cpp

-

-#include "StdAfx.h"

-

-#include "../../../../C/Sort.h"

-

-#include "../../../Common/StringConvert.h"

-

-#include "../../../Windows/FileDir.h"

-#include "../../../Windows/PropVariant.h"

-#include "../../../Windows/PropVariantConv.h"

-

-#include "../Common/ExtractingFilePath.h"

-

-#include "Extract.h"

-#include "SetProperties.h"

-

-using namespace NWindows;

-using namespace NFile;

-using namespace NDir;

-

-static HRESULT DecompressArchive(

-    CCodecs *codecs,

-    const CArchiveLink &arcLink,

-    UInt64 packSize,

-    const NWildcard::CCensorNode &wildcardCensor,

-    const CExtractOptions &options,

-    bool calcCrc,

-    IExtractCallbackUI *callback,

-    CArchiveExtractCallback *ecs,

-    UString &errorMessage,

-    UInt64 &stdInProcessed)

-{

-  const CArc &arc = arcLink.Arcs.Back();

-  stdInProcessed = 0;

-  IInArchive *archive = arc.Archive;

-  CRecordVector<UInt32> 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 (StringsAreEqualNoCase_Ascii(codecs->Formats[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;

-      }

-    }

-  }

-

-  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)

-      {

-        RINOK(arc.GetItem(i, item));

-      }

-      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))

-  {

-    HRESULT res = ::GetLastError();

-    if (res == S_OK)

-      res = E_FAIL;

-    errorMessage = "Can not create output directory: ";

-    errorMessage += fs2us(outDir);

-    return res;

-  }

-

-  ecs->Init(

-      options.NtOptions,

-      options.StdInMode ? &wildcardCensor : NULL,

-      &arc,

-      callback,

-      options.StdOutMode, options.TestMode,

-      outDir,

-      removePathParts, false,

-      packSize);

-

-  

-  #ifdef SUPPORT_LINKS

-  

-  if (!options.StdInMode &&

-      !options.TestMode &&

-      options.NtOptions.HardLinks.Val)

-  {

-    RINOK(ecs->PrepareHardLinks(&realIndices));

-  }

-    

-  #endif

-

-  

-  HRESULT result;

-  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

-    result = archive->Extract(&realIndices.Front(), realIndices.Size(), testMode, ecs);

-  

-  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 &fileName, const UString &name)

-{

-  unsigned left = 0, right = fileName.Size();

-  while (left != right)

-  {

-    unsigned mid = (left + right) / 2;

-    const UString &midValue = fileName[mid];

-    int compare = CompareFileNames(name, midValue);

-    if (compare == 0)

-      return mid;

-    if (compare < 0)

-      right = mid;

-    else

-      left = mid + 1;

-  }

-  return -1;

-}

-

-HRESULT Extract(

-    CCodecs *codecs,

-    const CObjectVector<COpenType> &types,

-    const CIntVector &excludedFormats,

-    UStringVector &arcPaths, UStringVector &arcPathsFull,

-    const NWildcard::CCensorNode &wildcardCensor,

-    const CExtractOptions &options,

-    IOpenCallbackUI *openCallback,

-    IExtractCallbackUI *extractCallback,

-    #ifndef _SFX

-    IHashCalc *hash,

-    #endif

-    UString &errorMessage,

-    CDecompressStat &st)

-{

-  st.Clear();

-  UInt64 totalPackSize = 0;

-  CRecordVector<UInt64> 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(arcPath))

-        throw "there is no such archive";

-      if (fi.IsDir())

-        throw "can't decompress folder";

-    }

-    arcSizes.Add(fi.Size);

-    totalPackSize += fi.Size;

-  }

-

-  CBoolArr skipArcs(numArcs);

-  for (i = 0; i < numArcs; i++)

-    skipArcs[i] = false;

-

-  CArchiveExtractCallback *ecs = new CArchiveExtractCallback;

-  CMyComPtr<IArchiveExtractCallback> ec(ecs);

-  bool multi = (numArcs > 1);

-  ecs->InitForMulti(multi, options.PathMode, options.OverwriteMode,

-      false // keepEmptyDirParts

-      );

-  #ifndef _SFX

-  ecs->SetHashMethods(hash);

-  #endif

-

-  if (multi)

-  {

-    RINOK(extractCallback->SetTotal(totalPackSize));

-  }

-

-  UInt64 totalPackProcessed = 0;

-  bool thereAreNotOpenArcs = false;

-  

-  for (i = 0; i < numArcs; i++)

-  {

-    if (skipArcs[i])

-      continue;

-

-    const UString &arcPath = arcPaths[i];

-    NFind::CFileInfo fi;

-    if (options.StdInMode)

-    {

-      fi.Size = 0;

-      fi.Attrib = 0;

-    }

-    else

-    {

-      if (!fi.Find(us2fs(arcPath)) || fi.IsDir())

-        throw "there is no such archive";

-    }

-

-    /*

-    #ifndef _NO_CRYPTO

-    openCallback->Open_Clear_PasswordWasAsked_Flag();

-    #endif

-    */

-

-    RINOK(extractCallback->BeforeOpen(arcPath, options.TestMode));

-    CArchiveLink arcLink;

-

-    CObjectVector<COpenType> types2 = types;

-    /*

-    #ifndef _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 _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)

-      {

-        NFind::CFileInfo fi2;

-        if (fi2.Find(us2fs(arcPath)))

-          if (!fi2.IsDir())

-            totalPackProcessed += fi2.Size;

-      }

-      continue;

-    }

-

-    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 = 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 = newPackSize;

-          RINOK(extractCallback->SetTotal(totalPackSize));

-        }

-      }

-    }

-

-    /*

-    // Now openCallback and extractCallback use same object. So we don't need to send password.

-

-    #ifndef _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.MTimeDefined = (!options.StdInMode && !fi.IsDevice);

-    arc.MTime = fi.MTime;

-

-    UInt64 packProcessed;

-    bool calcCrc =

-        #ifndef _SFX

-          (hash != NULL);

-        #else

-          false;

-        #endif

-

-    RINOK(DecompressArchive(

-        codecs,

-        arcLink,

-        fi.Size + arcLink.VolumesSize,

-        wildcardCensor,

-        options,

-        calcCrc,

-        extractCallback, 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(extractCallback->SetTotal(totalPackSize));

-    RINOK(extractCallback->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 "../../../../C/Sort.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<UInt32> 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);
+
+  
+  #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
+    result = archive->Extract(&realIndices.Front(), realIndices.Size(), testMode, ecs);
+  
+  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<COpenType> &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<UInt64> 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<IArchiveExtractCallback> 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;
+      fi.SetAsFile();
+      // NTime::GetCurUtc_FiTime(fi.MTime);
+      // fi.CTime = fi.ATime = fi.MTime;
+    }
+    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<COpenType> 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 9c806be..b20f607 100644
--- a/CPP/7zip/UI/Common/Extract.h
+++ b/CPP/7zip/UI/Common/Extract.h
@@ -1,94 +1,106 @@
-// Extract.h

-

-#ifndef __EXTRACT_H

-#define __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 PathMode_Force;

-  bool OverwriteMode_Force;

-  NExtract::NPathMode::EEnum PathMode;

-  NExtract::NOverwriteMode::EEnum OverwriteMode;

-  

-  FString OutputDir;

-  CExtractNtOptions NtOptions;

-

-  CExtractOptionsBase():

-      PathMode_Force(false),

-      OverwriteMode_Force(false),

-      PathMode(NExtract::NPathMode::kFullPaths),

-      OverwriteMode(NExtract::NOverwriteMode::kAsk)

-      {}

-};

-

-struct CExtractOptions: public CExtractOptionsBase

-{

-  bool StdInMode;

-  bool StdOutMode;

-  bool YesToAll;

-  bool TestMode;

-  

-  // bool ShowDialog;

-  // bool PasswordEnabled;

-  // UString Password;

-  #ifndef _SFX

-  CObjectVector<CProperty> Properties;

-  #endif

-

-  #ifdef EXTERNAL_CODECS

-  CCodecs *Codecs;

-  #endif

-

-  CExtractOptions():

-      TestMode(false),

-      StdInMode(false),

-      StdOutMode(false),

-      YesToAll(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(

-    CCodecs *codecs,

-    const CObjectVector<COpenType> &types,

-    const CIntVector &excludedFormats,

-    UStringVector &archivePaths, UStringVector &archivePathsFull,

-    const NWildcard::CCensorNode &wildcardCensor,

-    const CExtractOptions &options,

-    IOpenCallbackUI *openCallback,

-    IExtractCallbackUI *extractCallback,

-    #ifndef _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;
+  
+  FString OutputDir;
+  CExtractNtOptions NtOptions;
+  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<CProperty> 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<COpenType> &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 c28b7cc..6e38f26 100644
--- a/CPP/7zip/UI/Common/ExtractMode.h
+++ b/CPP/7zip/UI/Common/ExtractMode.h
@@ -1,34 +1,44 @@
-// ExtractMode.h

-

-#ifndef __EXTRACT_MODE_H

-#define __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

-  };

-}

-

-}

-

-#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 13665de..88da4ad 100644
--- a/CPP/7zip/UI/Common/ExtractingFilePath.cpp
+++ b/CPP/7zip/UI/Common/ExtractingFilePath.cpp
@@ -1,280 +1,296 @@
-// ExtractingFilePath.cpp

-

-#include "StdAfx.h"

-

-#include "../../../Common/Wildcard.h"

-

-#include "../../../Windows/FileName.h"

-

-#include "ExtractingFilePath.h"

-

-bool g_PathTrailReplaceMode =

-    #ifdef _WIN32

-      true

-    #else

-      false

-    #endif

-    ;

-

-

-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)

-        s.ReplaceOneCharAtPos(i, '_');

-    }

-  }

-  

-  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);

-      }

-      */

-    }

-  }

-}

-

-#ifdef _WIN32

-

-/* 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 = '_';

-}

-

-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 < 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 12eb0ba..bb1732f 100644
--- a/CPP/7zip/UI/Common/ExtractingFilePath.h
+++ b/CPP/7zip/UI/Common/ExtractingFilePath.h
@@ -1,31 +1,31 @@
-// ExtractingFilePath.h

-

-#ifndef __EXTRACTING_FILE_PATH_H

-#define __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 822018d..94c8a06 100644
--- a/CPP/7zip/UI/Common/HashCalc.cpp
+++ b/CPP/7zip/UI/Common/HashCalc.cpp
@@ -1,347 +1,2110 @@
-// HashCalc.cpp

-

-#include "StdAfx.h"

-

-#include "../../../../C/Alloc.h"

-

-#include "../../../Common/StringToInt.h"

-

-#include "../../Common/FileStreams.h"

-#include "../../Common/StreamUtils.h"

-

-#include "EnumDirItems.h"

-#include "HashCalc.h"

-

-using namespace NWindows;

-

-class CHashMidBuf

-{

-  void *_data;

-public:

-  CHashMidBuf(): _data(0) {}

-  operator void *() { return _data; }

-  bool Alloc(size_t size)

-  {

-    if (_data != 0)

-      return false;

-    _data = ::MidAlloc(size);

-    return _data != 0;

-  }

-  ~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<CMethodId> ids;

-  CObjectVector<COneMethodInfo> 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<CMethodId> 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<IHasher> 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<ICompressSetCoderProperties> scp;

-      hasher.QueryInterface(IID_ICompressSetCoderProperties, &scp);

-      if (scp)

-        RINOK(m.SetCoderProps(scp, NULL));

-    }

-    UInt32 digestSize = hasher->GetDigestSize();

-    if (digestSize > k_HashCalc_DigestSize_Max)

-      return E_NOTIMPL;

-    CHasherState &h = Hashers.AddNew();

-    h.Hasher = hasher;

-    h.Name = name;

-    h.DigestSize = digestSize;

-    for (unsigned k = 0; k < k_HashCalc_NumGroups; k++)

-      memset(h.Digests[k], 0, digestSize);

-  }

-

-  return S_OK;

-}

-

-void CHashBundle::InitForNewFile()

-{

-  CurSize = 0;

-  FOR_VECTOR (i, Hashers)

-  {

-    CHasherState &h = Hashers[i];

-    h.Hasher->Init();

-    memset(h.Digests[k_HashCalc_Index_Current], 0, h.DigestSize);

-  }

-}

-

-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;

-  for (UInt32 i = 0; i < size; i++)

-  {

-    next += (unsigned)dest[i] + (unsigned)src[i];

-    dest[i] = (Byte)next;

-    next >>= 8;

-  }

-}

-

-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]);

-      if (!isAltStream)

-        AddDigests(h.Digests[k_HashCalc_Index_DataSum], h.Digests[0], h.DigestSize);

-    }

-

-    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];

-      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)

-      AddDigests(h.Digests[k_HashCalc_Index_NamesSum], tempDigest, h.DigestSize);

-    AddDigests(h.Digests[k_HashCalc_Index_StreamsSum], tempDigest, h.DigestSize);

-  }

-}

-

-

-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;

-    di.Size = (UInt64)(Int64)-1;

-    di.Attrib = 0;

-    di.MTime.dwLowDateTime = 0;

-    di.MTime.dwHighDateTime = 0;

-    di.CTime = di.ATime = di.MTime;

-    dirItems.Items.Add(di);

-  }

-  else

-  {

-    RINOK(callback->StartScanning());

-    dirItems.ScanAltStreams = options.AltStreamsMode;

-

-    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;

-  

-  if (options.StdInMode)

-  {

-    RINOK(callback->SetNumFiles(1));

-  }

-  else

-  {

-    RINOK(callback->SetTotal(dirItems.Stat.GetTotalBytes()));

-  }

-

-  const UInt32 kBufSize = 1 << 15;

-  CHashMidBuf buf;

-  if (!buf.Alloc(kBufSize))

-    return E_OUTOFMEMORY;

-

-  UInt64 completeValue = 0;

-

-  RINOK(callback->BeforeFirstFile(hb));

-

-  for (i = 0; i < dirItems.Items.Size(); i++)

-  {

-    CMyComPtr<ISequentialInStream> inStream;

-    UString path;

-    bool isDir = false;

-    bool isAltStream = false;

-    if (options.StdInMode)

-    {

-      inStream = new CStdInFileStream;

-    }

-    else

-    {

-      CInFileStream *inStreamSpec = new CInFileStream;

-      inStream = inStreamSpec;

-      const CDirItem &dirItem = dirItems.Items[i];

-      isDir = dirItem.IsDir();

-      isAltStream = dirItem.IsAltStream;

-      path = dirItems.GetLogPath(i);

-      if (!isDir)

-      {

-        FString phyPath = dirItems.GetPhyPath(i);

-        if (!inStreamSpec->OpenShared(phyPath, options.OpenShareForWrite))

-        {

-          HRESULT res = callback->OpenFileError(phyPath, ::GetLastError());

-          hb.NumErrors++;

-          if (res != S_FALSE)

-            return res;

-          continue;

-        }

-      }

-    }

-    RINOK(callback->GetStream(path, isDir));

-    UInt64 fileSize = 0;

-

-    hb.InitForNewFile();

-    if (!isDir)

-    {

-      for (UInt32 step = 0;; step++)

-      {

-        if ((step & 0xFF) == 0)

-          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);

-    RINOK(callback->SetOperationResult(fileSize, hb, !isDir));

-    RINOK(callback->SetCompleted(&completeValue));

-  }

-  return callback->AfterLastFile(hb);

-}

-

-

-static inline char GetHex(unsigned v)

-{

-  return (char)((v < 10) ? ('0' + v) : ('A' + (v - 10)));

-}

-

-void AddHashHexToString(char *dest, const Byte *data, UInt32 size)

-{

-  dest[size * 2] = 0;

-  

-  if (!data)

-  {

-    for (UInt32 i = 0; i < size; i++)

-    {

-      dest[0] = ' ';

-      dest[1] = ' ';

-      dest += 2;

-    }

-    return;

-  }

-  

-  int step = 2;

-  if (size <= 8)

-  {

-    step = -2;

-    dest += size * 2 - 2;

-  }

-  

-  for (UInt32 i = 0; i < size; i++)

-  {

-    unsigned b = data[i];

-    dest[0] = GetHex((b >> 4) & 0xF);

-    dest[1] = GetHex(b & 0xF);

-    dest += step;

-  }

-}

+// 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<CMethodId> ids;
+  CObjectVector<COneMethodInfo> 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<CMethodId> 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<IHasher> 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<ICompressSetCoderProperties> 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 += '\\';
+      c = 'n';
+    }
+    else if (c == '\\')
+      dest += '\\';
+    dest += 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 += 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<CHasherState> &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 += '/';
+  
+  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;
+    di.Size = (UInt64)(Int64)-1;
+    di.SetAsFile();
+    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<ISequentialInStream> inStream;
+    UString path;
+    bool isDir = false;
+    bool isAltStream = false;
+    
+    if (options.StdInMode)
+    {
+      inStream = new CStdInFileStream;
+    }
+    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))
+          {
+            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);
+}
+
+
+static inline char GetHex_Upper(unsigned v)
+{
+  return (char)((v < 10) ? ('0' + v) : ('A' + (v - 10)));
+}
+
+static inline char GetHex_Lower(unsigned v)
+{
+  return (char)((v < 10) ? ('0' + v) : ('a' + (v - 10)));
+}
+
+void HashHexToString(char *dest, const Byte *data, UInt32 size)
+{
+  dest[size * 2] = 0;
+  
+  if (!data)
+  {
+    for (UInt32 i = 0; i < size; i++)
+    {
+      dest[0] = ' ';
+      dest[1] = ' ';
+      dest += 2;
+    }
+    return;
+  }
+  
+  if (size <= 8)
+  {
+    dest += size * 2;
+    for (UInt32 i = 0; i < size; i++)
+    {
+      const unsigned b = data[i];
+      dest -= 2;
+      dest[0] = GetHex_Upper((b >> 4) & 0xF);
+      dest[1] = GetHex_Upper(b & 0xF);
+    }
+  }
+  else
+  {
+    for (UInt32 i = 0; i < size; i++)
+    {
+      const unsigned b = data[i];
+      dest[0] = GetHex_Lower((b >> 4) & 0xF);
+      dest[1] = GetHex_Lower(b & 0xF);
+      dest += 2;
+    }
+  }
+}
+
+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 {
+
+static size_t ParseHexString(const char *s, Byte *dest) throw()
+{
+  size_t num;
+  for (num = 0;; num++, s += 2)
+  {
+    unsigned c = (Byte)s[0];
+    unsigned v0;
+         if (c >= '0' && c <= '9') v0 =      (c - '0');
+    else if (c >= 'A' && c <= 'F') v0 = 10 + (c - 'A');
+    else if (c >= 'a' && c <= 'f') v0 = 10 + (c - 'a');
+    else
+      return num;
+    c = (Byte)s[1];
+    unsigned v1;
+         if (c >= '0' && c <= '9') v1 =      (c - '0');
+    else if (c >= 'A' && c <= 'F') v1 = 10 + (c - 'A');
+    else if (c >= 'a' && c <= 'f') v1 = 10 + (c - 'a');
+    else
+      return num;
+    if (dest)
+      dest[num] = (Byte)(v1 | (v0 << 4));
+  }
+}
+
+
+#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[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;
+  }
+  
+  // const char *kMethod = GetMethod_from_FileName(s);
+  // if (kMethod)
+  if (ParseHexString(s, NULL) < 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 num = ParseHexString(s, NULL);
+    Hash.Alloc(num);
+    ParseHexString(s, Hash);
+    const size_t numChars = num * 2;
+    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))
+{
+  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;
+    }
+    */
+    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 += ":";
+          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;
+    }
+  }
+  prop.Detach(value);
+  return S_OK;
+}
+
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
+{
+  // COM_TRY_BEGIN
+  NWindows::NCOM::CPropVariant prop;
+  CHashPair &hp = HashPairs[index];
+  switch (propID)
+  {
+    case kpidIsDir:
+    {
+      prop = hp.IsDir();
+      break;
+    }
+    case kpidPath:
+    {
+      UString path;
+      hp.Get_UString_Path(path);
+
+      NArchive::NItemName::ReplaceToOsSlashes_Remove_TailSlash(path,
+          true); // 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;
+    }
+  }
+  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<CHashPair> &pairs = HashPairs;
+
+    bool zeroMode = false;
+    bool cr_lf_Mode = false;
+    {
+      for (size_t i = 0; i < buf.Size(); i++)
+        if (buf[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;
+
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> progress = lps;
+  lps->Init(extractCallback, false);
+  lps->InSize = lps->OutSize = 0;
+
+  UInt32 i;
+  for (i = 0; i < numItems; i++)
+  {
+    RINOK(lps->SetCur())
+    const UInt32 index = allFilesMode ? i : indices[i];
+
+    CHashPair &hp = HashPairs[index];
+    
+    UString path;
+    hp.Get_UString_Path(path);
+
+    CMyComPtr<ISequentialInStream> 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<ISequentialOutStream> realOutStream;
+    RINOK(extractCallback->GetStream(index, &realOutStream, askMode))
+
+    /* PrepareOperation() can expect kExtract to set
+       Attrib and security of output file */
+    askMode = NArchive::NExtract::NAskMode::kReadExternal;
+
+    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(progress->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 lps->SetCur();
+
+  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<CUpdateItem> 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))
+
+  CLocalProgress *lps = new CLocalProgress;
+  CMyComPtr<ICompressProgressInfo> progress = 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;
+
+  lps->OutSize = 0;
+  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<ISequentialInStream> 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 = NWindows::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(progress->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.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);
+  }
+}
diff --git a/CPP/7zip/UI/Common/HashCalc.h b/CPP/7zip/UI/Common/HashCalc.h
index 524bd3b..0b527c1 100644
--- a/CPP/7zip/UI/Common/HashCalc.h
+++ b/CPP/7zip/UI/Common/HashCalc.h
@@ -1,110 +1,328 @@
-// HashCalc.h

-

-#ifndef __HASH_CALC_H

-#define __HASH_CALC_H

-

-#include "../../../Common/Wildcard.h"

-

-#include "../../Common/CreateCoder.h"

-#include "../../Common/MethodProps.h"

-

-#include "DirItem.h"

-

-const unsigned k_HashCalc_DigestSize_Max = 64;

-

-const unsigned k_HashCalc_NumGroups = 4;

-

-enum

-{

-  k_HashCalc_Index_Current,

-  k_HashCalc_Index_DataSum,

-  k_HashCalc_Index_NamesSum,

-  k_HashCalc_Index_StreamsSum

-};

-

-struct CHasherState

-{

-  CMyComPtr<IHasher> Hasher;

-  AString Name;

-  UInt32 DigestSize;

-  Byte Digests[k_HashCalc_NumGroups][k_HashCalc_DigestSize_Max];

-};

-

-struct 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;

-};

-

-struct CHashBundle: public IHashCalc

-{

-  CObjectVector<CHasherState> 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();

-  void Update(const void *data, UInt32 size);

-  void SetSize(UInt64 size);

-  void Final(bool isDir, bool isAltStream, const UString &path);

-};

-

-#define INTERFACE_IHashCallbackUI(x) \

-  INTERFACE_IDirItemsCallback(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; \

-

-struct IHashCallbackUI: public IDirItemsCallback

-{

-  INTERFACE_IHashCallbackUI(=0)

-};

-

-struct CHashOptions

-{

-  UStringVector Methods;

-  bool OpenShareForWrite;

-  bool StdInMode;

-  bool AltStreamsMode;

-  NWildcard::ECensorPathMode PathMode;

- 

-  CHashOptions(): StdInMode(false), OpenShareForWrite(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);

-

-void AddHashHexToString(char *dest, const Byte *data, UInt32 size);

-

-#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, UInt32 size);
+
+enum
+{
+  k_HashCalc_Index_Current,
+  k_HashCalc_Index_DataSum,
+  k_HashCalc_Index_NamesSum,
+  k_HashCalc_Index_StreamsSum
+};
+
+struct CHasherState
+{
+  CMyComPtr<IHasher> 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<CHasherState> 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 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)
+      , 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;
+  UInt64 _phySize;
+  CObjectVector<CHashPair> 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;
+
+  bool _crcSize_WasSet;
+  UInt32 _crcSize;
+  UStringVector _methods;
+
+  void ClearVars();
+
+  void InitProps()
+  {
+    _crcSize_WasSet = false;
+    _crcSize = 4;
+    _methods.Clear();
+    _options.Init_HashOptionsLocal();
+  }
+
+  CHashOptionsLocal _options;
+
+  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 3f554ef..dd5c0d7 100644
--- a/CPP/7zip/UI/Common/IFileExtractCallback.h
+++ b/CPP/7zip/UI/Common/IFileExtractCallback.h
@@ -1,114 +1,112 @@
-// IFileExtractCallback.h

-

-#ifndef __I_FILE_EXTRACT_CALLBACK_H

-#define __I_FILE_EXTRACT_CALLBACK_H

-

-#include "../../../Common/MyString.h"

-

-#include "../../IDecl.h"

-

-#include "LoadCodecs.h"

-#include "OpenArchive.h"

-

-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 INTERFACE_IFolderArchiveExtractCallback(x) \

-  STDMETHOD(AskOverwrite)( \

-      const wchar_t *existName, const FILETIME *existTime, const UInt64 *existSize, \

-      const wchar_t *newName, const FILETIME *newTime, const UInt64 *newSize, \

-      Int32 *answer) x; \

-  STDMETHOD(PrepareOperation)(const wchar_t *name, Int32 isFolder, Int32 askExtractMode, const UInt64 *position) x; \

-  STDMETHOD(MessageError)(const wchar_t *message) x; \

-  STDMETHOD(SetOperationResult)(Int32 opRes, Int32 encrypted) x; \

-

-DECL_INTERFACE_SUB(IFolderArchiveExtractCallback, IProgress, 0x01, 0x07)

-{

-  INTERFACE_IFolderArchiveExtractCallback(PURE)

-};

-

-#define INTERFACE_IFolderArchiveExtractCallback2(x) \

-  STDMETHOD(ReportExtractResult)(Int32 opRes, Int32 encrypted, const wchar_t *name) x; \

-

-DECL_INTERFACE_SUB(IFolderArchiveExtractCallback2, IUnknown, 0x01, 0x08)

-{

-  INTERFACE_IFolderArchiveExtractCallback2(PURE)

-};

-

-/* ---------- IExtractCallbackUI ----------

-is implemented by

-  Console/ExtractCallbackConsole.h  CExtractCallbackConsole

-  FileManager/ExtractCallback.h     CExtractCallbackImp

-*/

-

-#ifdef _NO_CRYPTO

-  #define INTERFACE_IExtractCallbackUI_Crypto(x)

-#else

-  #define INTERFACE_IExtractCallbackUI_Crypto(x) \

-  virtual HRESULT SetPassword(const UString &password) x;

-#endif

-

-#define INTERFACE_IExtractCallbackUI(x) \

-  virtual HRESULT BeforeOpen(const wchar_t *name, bool testMode) x; \

-  virtual HRESULT OpenResult(const CCodecs *codecs, const CArchiveLink &arcLink, const wchar_t *name, HRESULT result) x; \

-  virtual HRESULT ThereAreNoFiles() x; \

-  virtual HRESULT ExtractResult(HRESULT result) x; \

-  INTERFACE_IExtractCallbackUI_Crypto(x)

-

-struct IExtractCallbackUI: IFolderArchiveExtractCallback

-{

-  INTERFACE_IExtractCallbackUI(PURE)

-};

-

-

-

-#define INTERFACE_IGetProp(x) \

-  STDMETHOD(GetProp)(PROPID propID, PROPVARIANT *value) x; \

-

-DECL_INTERFACE_SUB(IGetProp, IUnknown, 0x01, 0x20)

-{

-  INTERFACE_IGetProp(PURE)

-};

-

-#define INTERFACE_IFolderExtractToStreamCallback(x) \

-  STDMETHOD(UseExtractToStream)(Int32 *res) x; \

-  STDMETHOD(GetStream7)(const wchar_t *name, Int32 isDir, ISequentialOutStream **outStream, Int32 askExtractMode, IGetProp *getProp) x; \

-  STDMETHOD(PrepareOperation7)(Int32 askExtractMode) x; \

-  STDMETHOD(SetOperationResult7)(Int32 resultEOperationResult, Int32 encrypted) x; \

-

-DECL_INTERFACE_SUB(IFolderExtractToStreamCallback, IUnknown, 0x01, 0x30)

-{

-  INTERFACE_IFolderExtractToStreamCallback(PURE)

-};

-

-

-#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 d31e05f..5a65bdc 100644
--- a/CPP/7zip/UI/Common/LoadCodecs.cpp
+++ b/CPP/7zip/UI/Common/LoadCodecs.cpp
@@ -1,1074 +1,1333 @@
-// LoadCodecs.cpp

-

-/*

-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 (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 "../../../../C/7zVersion.h"

-

-#include "../../../Common/MyCom.h"

-#include "../../../Common/StringToInt.h"

-#include "../../../Common/StringConvert.h"

-

-#include "../../../Windows/PropVariant.h"

-

-#include "LoadCodecs.h"

-

-using namespace NWindows;

-

-#ifdef NEW_FOLDER_INTERFACE

-#include "../../../Common/StringToInt.h"

-#endif

-

-#include "../../ICoder.h"

-#include "../../Common/RegisterArc.h"

-

-#ifdef EXTERNAL_CODECS

-

-// #define EXPORT_CODECS

-

-#endif

-

-#ifdef NEW_FOLDER_INTERFACE

-extern HINSTANCE g_hInstance;

-#include "../../../Windows/ResourceString.h"

-static const UINT kIconTypesResId = 100;

-#endif

-

-#ifdef EXTERNAL_CODECS

-

-#include "../../../Windows/FileFind.h"

-#include "../../../Windows/DLL.h"

-

-#ifdef _WIN32

-#include "../../../Windows/FileName.h"

-#include "../../../Windows/Registry.h"

-#endif

-

-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(path + kMainDll);

-    }

-  }

-  return false;

-}

-

-#endif // _WIN32

-

-#endif // EXTERNAL_CODECS

-

-

-static const unsigned kNumArcsMax = 64;

-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++;

-  }

-}

-

-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 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 _SFX

-

-static bool ParseSignatures(const Byte *data, unsigned size, CObjectVector<CByteBuffer> &signatures)

-{

-  signatures.Clear();

-  while (size > 0)

-  {

-    unsigned len = *data++;

-    size--;

-    if (len > size)

-      return false;

-    signatures.AddNew().CopyFrom(data, len);

-    data += len;

-    size -= len;

-  }

-  return true;

-}

-

-#endif // _SFX

-

-#ifdef EXTERNAL_CODECS

-

-static FString GetBaseFolderPrefixFromRegistry()

-{

-  FString moduleFolderPrefix = NDLL::GetModuleDirPrefix();

-  #ifdef _WIN32

-  if (!NFind::DoesFileExist(moduleFolderPrefix + kMainDll) &&

-      !NFind::DoesDirExist(moduleFolderPrefix + kCodecsFolderName) &&

-      !NFind::DoesDirExist(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

-  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 *)prop.bstrVal;

-  }

-  else if (prop.vt != VT_EMPTY)

-    return E_FAIL;

-  return S_OK;

-}

-

-HRESULT CCodecs::LoadCodecs()

-{

-  CCodecLib &lib = Libs.Back();

-

-  lib.CreateDecoder = (Func_CreateDecoder)lib.Lib.GetProc("CreateDecoder");

-  lib.CreateEncoder = (Func_CreateEncoder)lib.Lib.GetProc("CreateEncoder");

-  lib.GetMethodProperty = (Func_GetMethodProperty)lib.Lib.GetProc("GetMethodProperty");

-

-  if (lib.GetMethodProperty)

-  {

-    UInt32 numMethods = 1;

-    Func_GetNumberOfMethods getNumberOfMethods = (Func_GetNumberOfMethods)lib.Lib.GetProc("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));

-      Codecs.Add(info);

-    }

-  }

-

-  Func_GetHashers getHashers = (Func_GetHashers)lib.Lib.GetProc("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;

-  Func_GetHandlerProperty2 getProp2 = (Func_GetHandlerProperty2)lib.GetProc("GetHandlerProperty2");

-  Func_GetIsArc getIsArc = (Func_GetIsArc)lib.GetProc("GetIsArc");

-  

-  UInt32 numFormats = 1;

-

-  if (getProp2)

-  {

-    Func_GetNumberOfFormats getNumberOfFormats = (Func_GetNumberOfFormats)lib.GetProc("GetNumberOfFormats");

-    if (getNumberOfFormats)

-    {

-      RINOK(getNumberOfFormats(&numFormats));

-    }

-  }

-  else

-  {

-    getProp = (Func_GetHandlerProperty)lib.GetProc("GetHandlerProperty");

-    if (!getProp)

-      return S_OK;

-  }

-  

-  for (UInt32 i = 0; i < numFormats; i++)

-  {

-    CArcInfoEx item;

-    item.LibIndex = 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 *)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 < ARRAY_SIZE(kArcFlagsPars); j += 2)

-      {

-        bool val = false;

-        GetProp_Bool(getProp, getProp2, i, kArcFlagsPars[j], val);

-        if (val)

-          item.Flags |= kArcFlagsPars[j + 1];

-      }

-    }

-    

-    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 _7ZIP_LARGE_PAGES

-extern "C"

-{

-  extern SIZE_T g_LargePageSize;

-}

-#endif

-

-HRESULT CCodecs::LoadDll(const FString &dllPath, bool needCheckDll, bool *loadedOK)

-{

-  if (loadedOK)

-    *loadedOK = false;

-

-  if (needCheckDll)

-  {

-    NDLL::CLibrary lib;

-    if (!lib.LoadEx(dllPath, LOAD_LIBRARY_AS_DATAFILE))

-      return S_OK;

-  }

-  

-  Libs.AddNew();

-  CCodecLib &lib = Libs.Back();

-  lib.Path = dllPath;

-  bool used = false;

-  HRESULT res = S_OK;

-  

-  if (lib.Lib.Load(dllPath))

-  {

-    if (loadedOK)

-      *loadedOK = true;

-    #ifdef NEW_FOLDER_INTERFACE

-    lib.LoadIcons();

-    #endif

-

-    #ifdef _7ZIP_LARGE_PAGES

-    if (g_LargePageSize != 0)

-    {

-      Func_SetLargePageMode setLargePageMode = (Func_SetLargePageMode)lib.Lib.GetProc("SetLargePageMode");

-      if (setLargePageMode)

-        setLargePageMode();

-    }

-    #endif

-

-    if (CaseSensitiveChange)

-    {

-      Func_SetCaseSensitive setCaseSensitive = (Func_SetCaseSensitive)lib.Lib.GetProc("SetCaseSensitive");

-      if (setCaseSensitive)

-        setCaseSensitive(CaseSensitive ? 1 : 0);

-    }

-

-    lib.CreateObject = (Func_CreateObject)lib.Lib.GetProc("CreateObject");

-    {

-      unsigned startSize = Codecs.Size() + Hashers.Size();

-      res = LoadCodecs();

-      used = (startSize != Codecs.Size() + Hashers.Size());

-      if (res == S_OK && lib.CreateObject)

-      {

-        startSize = Formats.Size();

-        res = LoadFormats();

-        if (startSize != Formats.Size())

-          used = true;

-      }

-    }

-  }

-  

-  if (!used)

-    Libs.DeleteBack();

-

-  return res;

-}

-

-HRESULT CCodecs::LoadDllsFromFolder(const FString &folderPrefix)

-{

-  NFile::NFind::CEnumerator enumerator;

-  enumerator.SetDirPrefix(folderPrefix);

-  NFile::NFind::CFileInfo fi;

-  while (enumerator.Next(fi))

-  {

-    if (fi.IsDir())

-      continue;

-    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 // EXTERNAL_CODECS

-

-

-HRESULT CCodecs::Load()

-{

-  #ifdef NEW_FOLDER_INTERFACE

-  InternalIcons.LoadIcons(g_hInstance);

-  #endif

-

-  Formats.Clear();

-  

-  #ifdef EXTERNAL_CODECS

-    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 _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

-      item.Signatures.AddNew().CopyFrom(arc.Signature, arc.SignatureSize);

-    

-    #endif

-

-    Formats.Add(item);

-  }

-  

-  #ifdef EXTERNAL_CODECS

-    const FString baseFolder = GetBaseFolderPrefixFromRegistry();

-    {

-      bool loadedOK;

-      RINOK(LoadDll(baseFolder + kMainDll, false, &loadedOK));

-      if (!loadedOK)

-        MainDll_ErrorPath = kMainDll;

-    }

-    RINOK(LoadDllsFromFolder(baseFolder + kCodecsFolderName FSTRING_PATH_SEPARATOR));

-    RINOK(LoadDllsFromFolder(baseFolder + kFormatsFolderName FSTRING_PATH_SEPARATOR));

-

-  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];

-      lib.SetCodecs = (Func_SetCodecs)lib.Lib.GetProc("SetCodecs");

-      if (lib.SetCodecs)

-      {

-        RINOK(lib.SetCodecs(this));

-      }

-    }

-  }

-

-  #endif

-

-  return S_OK;

-}

-

-#ifndef _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(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 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 i;

-  return -1;

-}

-

-int CCodecs::FindFormatForArchiveType(const UString &arcType) const

-{

-  FOR_VECTOR (i, Formats)

-    if (Formats[i].Name.IsEqualTo_NoCase(arcType))

-      return 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 = arcType.Len();

-    const UString name = arcType.Mid(pos, pos2 - pos);

-    if (name.IsEmpty())

-      return false;

-    int index = FindFormatForArchiveType(name);

-    if (index < 0 && name != L"*")

-    {

-      formatIndices.Clear();

-      return false;

-    }

-    formatIndices.Add(index);

-    pos = pos2 + 1;

-  }

-  return true;

-}

-

-#endif // _SFX

-

-

-#ifdef NEW_FOLDER_INTERFACE

-

-void CCodecIcons::LoadIcons(HMODULE m)

-{

-  UString iconTypes;

-  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 = s.Len();

-    else

-    {

-      UString num = s.Ptr(pos + 1);

-      if (!num.IsEmpty())

-      {

-        const wchar_t *end;

-        iconPair.IconIndex = ConvertStringToUInt32(num, &end);

-        if (*end != 0)

-          continue;

-      }

-    }

-    iconPair.Ext = s.Left(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;

-}

-

-#endif // NEW_FOLDER_INTERFACE

-

-

-#ifdef 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

-

-STDMETHODIMP CCodecs::GetNumMethods(UInt32 *numMethods)

-{

-  *numMethods = NUM_EXPORT_CODECS

-    #ifdef EXTERNAL_CODECS

-    + Codecs.Size()

-    #endif

-    ;

-  return S_OK;

-}

-

-STDMETHODIMP CCodecs::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)

-{

-  #ifdef EXPORT_CODECS

-  if (index < g_NumCodecs)

-    return GetMethodProperty(index, propID, value);

-  #endif

-

-  #ifdef 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;

-  }

-  const CCodecLib &lib = Libs[ci.LibIndex];

-  return lib.GetMethodProperty(ci.CodecIndex, propID, value);

-  #else

-  return E_FAIL;

-  #endif

-}

-

-STDMETHODIMP CCodecs::CreateDecoder(UInt32 index, const GUID *iid, void **coder)

-{

-  #ifdef EXPORT_CODECS

-  if (index < g_NumCodecs)

-    return CreateDecoder(index, iid, coder);

-  #endif

-  

-  #ifdef 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

-}

-

-STDMETHODIMP CCodecs::CreateEncoder(UInt32 index, const GUID *iid, void **coder)

-{

-  #ifdef EXPORT_CODECS

-  if (index < g_NumCodecs)

-    return CreateEncoder(index, iid, coder);

-  #endif

-

-  #ifdef 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

-}

-

-

-STDMETHODIMP_(UInt32) CCodecs::GetNumHashers()

-{

-  return NUM_EXPORT_HASHERS

-    #ifdef EXTERNAL_CODECS

-    + Hashers.Size()

-    #endif

-    ;

-}

-

-STDMETHODIMP CCodecs::GetHasherProp(UInt32 index, PROPID propID, PROPVARIANT *value)

-{

-  #ifdef EXPORT_CODECS

-  if (index < g_NumHashers)

-    return ::GetHasherProp(index, propID, value);

-  #endif

-

-  #ifdef 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

-}

-

-STDMETHODIMP CCodecs::CreateHasher(UInt32 index, IHasher **hasher)

-{

-  #ifdef EXPORT_CODECS

-  if (index < g_NumHashers)

-    return CreateHasher(index, hasher);

-  #endif

-  #ifdef 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 EXTERNAL_CODECS

-  const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS];

-  return ci.LibIndex;

-  #else

-  return -1;

-  #endif

-}

-

-int CCodecs::GetHasherLibIndex(UInt32 index)

-{

-  #ifdef EXPORT_CODECS

-  if (index < g_NumHashers)

-    return -1;

-  #endif

-  

-  #ifdef EXTERNAL_CODECS

-  const CDllHasherInfo &ci = Hashers[index - NUM_EXPORT_HASHERS];

-  return 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 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 EXTERNAL_CODECS

-  return Codecs[index - NUM_EXPORT_CODECS].EncoderIsAssigned;

-  #else

-  return false;

-  #endif

-}

-

-UInt32 CCodecs::GetCodec_NumStreams(UInt32 index)

-{

-  NCOM::CPropVariant prop;

-  RINOK(GetProperty(index, NMethodPropID::kPackStreams, &prop));

-  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;

-  RINOK(GetHasherProp(index, NMethodPropID::kDigestSize, &prop));

-  if (prop.vt != VT_UI4)

-    return 0;

-  return prop.ulVal;

-}

-

-#endif // EXTERNAL_CODECS

+// 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<CByteBuffer> &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 <stdio.h>
+
+#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
+
+#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<CCodecInfoUser> &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 9ba36d3..a81bb5c 100644
--- a/CPP/7zip/UI/Common/LoadCodecs.h
+++ b/CPP/7zip/UI/Common/LoadCodecs.h
@@ -1,424 +1,482 @@
-// LoadCodecs.h

-

-#ifndef __LOAD_CODECS_H

-#define __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

-

-EXTERNAL_CODECS

----------------

-

-  if 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 EXTERNAL_CODECS defined:

-       - 7z.exe, 7zG.exe, 7zFM.exe

-    

-     Note: 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 EXTERNAL_CODECS:

-    - SFX modules: 7z.sfx, 7zCon.sfx

-    - standalone versions of console 7-Zip: 7za.exe, 7zr.exe

-

-  if 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 EXTERNAL_CODECS

-#include "../../../Windows/DLL.h"

-#endif

-

-#include "../../ICoder.h"

-

-#include "../../Archive/IArchive.h"

-

-

-#ifdef EXTERNAL_CODECS

-

-struct CDllCodecInfo

-{

-  unsigned LibIndex;

-  UInt32 CodecIndex;

-  bool EncoderIsAssigned;

-  bool DecoderIsAssigned;

-  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;

-  

-  Func_CreateInArchive CreateInArchive;

-  Func_IsArc IsArcFunc;

-

-  UString Name;

-  CObjectVector<CArcExtInfo> Exts;

-  

-  #ifndef _SFX

-    Func_CreateOutArchive CreateOutArchive;

-    bool UpdateEnabled;

-    bool NewInterface;

-    // UInt32 Version;

-    UInt32 SignatureOffset;

-    CObjectVector<CByteBuffer> Signatures;

-    #ifdef NEW_FOLDER_INTERFACE

-      UStringVector AssociateExts;

-    #endif

-  #endif

-  

-  #ifdef EXTERNAL_CODECS

-    int LibIndex;

-    UInt32 FormatIndex;

-    CLSID ClassID;

-  #endif

-

-  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_NtSecure() 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; }

-  

-  UString GetMainExt() const

-  {

-    if (Exts.IsEmpty())

-      return UString();

-    return Exts[0].Ext;

-  }

-  int FindExtension(const UString &ext) const;

-  

-  /*

-  UString GetAllExtensions() const

-  {

-    UString s;

-    for (int i = 0; i < Exts.Size(); i++)

-    {

-      if (i > 0)

-        s += ' ';

-      s += Exts[i].Ext;

-    }

-    return s;

-  }

-  */

-

-  void AddExts(const UString &ext, const UString &addExt);

-

-  bool IsSplit() const { return StringsAreEqualNoCase_Ascii(Name, "Split"); }

-  // bool IsRar() const { return StringsAreEqualNoCase_Ascii(Name, "Rar"); }

-

-  CArcInfoEx():

-      Flags(0),

-      CreateInArchive(NULL),

-      IsArcFunc(NULL)

-      #ifndef _SFX

-      , CreateOutArchive(NULL)

-      , UpdateEnabled(false)

-      , NewInterface(false)

-      // , Version(0)

-      , SignatureOffset(0)

-      #endif

-      #ifdef EXTERNAL_CODECS

-      , LibIndex(-1)

-      #endif

-  {}

-};

-

-#ifdef NEW_FOLDER_INTERFACE

-

-struct CCodecIcons

-{

-  struct CIconPair

-  {

-    UString Ext;

-    int IconIndex;

-  };

-  CObjectVector<CIconPair> IconPairs;

-

-  void LoadIcons(HMODULE m);

-  bool FindIconIndex(const UString &ext, int &iconIndex) const;

-};

-

-#endif

-

-#ifdef EXTERNAL_CODECS

-

-struct CCodecLib

-  #ifdef NEW_FOLDER_INTERFACE

-    : public CCodecIcons

-  #endif

-{

-  NWindows::NDLL::CLibrary Lib;

-  FString Path;

-  

-  Func_CreateObject CreateObject;

-  Func_GetMethodProperty GetMethodProperty;

-  Func_CreateDecoder CreateDecoder;

-  Func_CreateEncoder CreateEncoder;

-  Func_SetCodecs SetCodecs;

-

-  CMyComPtr<IHashers> ComHashers;

-  

-  #ifdef NEW_FOLDER_INTERFACE

-  void LoadIcons() { CCodecIcons::LoadIcons((HMODULE)Lib); }

-  #endif

-  

-  CCodecLib():

-      CreateObject(NULL),

-      GetMethodProperty(NULL),

-      CreateDecoder(NULL),

-      CreateEncoder(NULL),

-      SetCodecs(NULL)

-      {}

-};

-

-#endif

-

-

-class CCodecs:

-  #ifdef EXTERNAL_CODECS

-    public ICompressCodecsInfo,

-    public IHashers,

-  #else

-    public IUnknown,

-  #endif

-  public CMyUnknownImp

-{

-  CLASS_NO_COPY(CCodecs);

-public:

-  #ifdef EXTERNAL_CODECS

-  

-  CObjectVector<CCodecLib> Libs;

-  FString MainDll_ErrorPath;

-

-  void CloseLibs();

-

-  class CReleaser

-  {

-    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[ai.LibIndex].CreateObject(&ai.ClassID, outHandler ? &IID_IOutArchive : &IID_IInArchive, (void **)archive);

-  }

-  

-  #endif

-

-  #ifdef NEW_FOLDER_INTERFACE

-  CCodecIcons InternalIcons;

-  #endif

-

-  CObjectVector<CArcInfoEx> Formats;

-  

-  #ifdef EXTERNAL_CODECS

-  CRecordVector<CDllCodecInfo> Codecs;

-  CRecordVector<CDllHasherInfo> Hashers;

-  #endif

-

-  bool CaseSensitiveChange;

-  bool CaseSensitive;

-

-  CCodecs():

-      #ifdef EXTERNAL_CODECS

-      NeedSetLibCodecs(true),

-      #endif

-      CaseSensitiveChange(false),

-      CaseSensitive(false)

-      {}

-

-  ~CCodecs()

-  {

-    // OutputDebugStringA("~CCodecs");

-  }

- 

-  const wchar_t *GetFormatNamePtr(int formatIndex) const

-  {

-    return formatIndex < 0 ? L"#" : (const wchar_t *)Formats[formatIndex].Name;

-  }

-

-  HRESULT Load();

-  

-  #ifndef _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 EXTERNAL_CODECS

-

-  MY_UNKNOWN_IMP2(ICompressCodecsInfo, IHashers)

-    

-  STDMETHOD(GetNumMethods)(UInt32 *numMethods);

-  STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value);

-  STDMETHOD(CreateDecoder)(UInt32 index, const GUID *iid, void **coder);

-  STDMETHOD(CreateEncoder)(UInt32 index, const GUID *iid, void **coder);

-

-  STDMETHOD_(UInt32, GetNumHashers)();

-  STDMETHOD(GetHasherProp)(UInt32 index, PROPID propID, PROPVARIANT *value);

-  STDMETHOD(CreateHasher)(UInt32 index, IHasher **hasher);

-

-  #else

-

-  MY_UNKNOWN_IMP

-

-  #endif // EXTERNAL_CODECS

-

-  

-  #ifdef EXTERNAL_CODECS

-

-  int GetCodec_LibIndex(UInt32 index) const;

-  bool GetCodec_DecoderIsAssigned(UInt32 index) const;

-  bool GetCodec_EncoderIsAssigned(UInt32 index) 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);

-

-  #endif

-

-  HRESULT CreateInArchive(unsigned formatIndex, CMyComPtr<IInArchive> &archive) const

-  {

-    const CArcInfoEx &ai = Formats[formatIndex];

-    #ifdef EXTERNAL_CODECS

-    if (ai.LibIndex < 0)

-    #endif

-    {

-      COM_TRY_BEGIN

-      archive = ai.CreateInArchive();

-      return S_OK;

-      COM_TRY_END

-    }

-    #ifdef EXTERNAL_CODECS

-    return CreateArchiveHandler(ai, false, (void **)&archive);

-    #endif

-  }

-  

-  #ifndef _SFX

-

-  HRESULT CreateOutArchive(unsigned formatIndex, CMyComPtr<IOutArchive> &archive) const

-  {

-    const CArcInfoEx &ai = Formats[formatIndex];

-    #ifdef EXTERNAL_CODECS

-    if (ai.LibIndex < 0)

-    #endif

-    {

-      COM_TRY_BEGIN

-      archive = ai.CreateOutArchive();

-      return S_OK;

-      COM_TRY_END

-    }

-    

-    #ifdef 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 i;

-    }

-    return -1;

-  }

-

-  #endif // _SFX

-};

-

-#ifdef 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<IUnknown> __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<CArcExtInfo> Exts;
+  
+  #ifndef Z7_SFX
+    Func_CreateOutArchive CreateOutArchive;
+    bool UpdateEnabled;
+    bool NewInterface;
+    // UInt32 Version;
+    UInt32 SignatureOffset;
+    CObjectVector<CByteBuffer> 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<IHashers> 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<CCodecLib> Libs;
+  FString MainDll_ErrorPath;
+  CObjectVector<CCodecError> 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<CArcInfoEx> Formats;
+  
+  #ifdef Z7_EXTERNAL_CODECS
+  CRecordVector<CDllCodecInfo> Codecs;
+  CRecordVector<CDllHasherInfo> 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<IInArchive> &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<IOutArchive> &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<CCodecInfoUser> &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<IUnknown> _codecsRef = codecs;
+#endif
+
+#endif
diff --git a/CPP/7zip/UI/Common/OpenArchive.cpp b/CPP/7zip/UI/Common/OpenArchive.cpp
index d72454c..a501b86 100644
--- a/CPP/7zip/UI/Common/OpenArchive.cpp
+++ b/CPP/7zip/UI/Common/OpenArchive.cpp
@@ -1,3553 +1,3695 @@
-// OpenArchive.cpp

-

-#include "StdAfx.h"

-

-// #define SHOW_DEBUG_INFO

-

-#ifdef SHOW_DEBUG_INFO

-#include <stdio.h>

-#endif

-

-#include "../../../../C/CpuArch.h"

-

-#include "../../../Common/ComTry.h"

-#include "../../../Common/IntToString.h"

-#include "../../../Common/StringConvert.h"

-#include "../../../Common/StringToInt.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 _SFX

-#include "SetProperties.h"

-#endif

-

-#ifdef SHOW_DEBUG_INFO

-#define PRF(x) x

-#else

-#define PRF(x)

-#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 can not 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 _SFX

-#define OPEN_PROPS_PARAM

-#else

-#define OPEN_PROPS_PARAM  , props

-#endif

-*/

-

-/*

-CArc::~CArc()

-{

-  GetRawProps.Release();

-  Archive.Release();

-  printf("\nCArc::~CArc()\n");

-}

-*/

-

-#ifndef _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():

-      LenIsUnknown(false),

-      FileTime_Defined(false),

-      UnpackSize_Defined(false),

-      NumSubFiles_Defined(false),

-      NumSubDirs_Defined(false),

-      IsSelfExe(false),

-      IsNotArcType(false)

-      // OkSize(0)

-    {}

-

-  /*

-  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;

-    }

-  }

-};

-

-class CHandler:

-  public IInArchive,

-  public IInArchiveGetStream,

-  public CMyUnknownImp

-{

-public:

-  CObjectVector<CParseItem> _items;

-  UInt64 _maxEndOffset;

-  CMyComPtr<IInStream> _stream;

-

-  MY_UNKNOWN_IMP2(

-    IInArchive,

-    IInArchiveGetStream)

-

-  INTERFACE_IInArchive(;)

-  STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **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)

-  {

-    unsigned mid = (left + 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 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);

-  int pos = FindInsertPos(item);

-  if (pos >= 0)

-  {

-    _items.Insert(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

-

-STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback * /* openArchiveCallback */)

-{

-  COM_TRY_BEGIN

-  {

-    Close();

-    _stream = stream;

-  }

-  return S_OK;

-  COM_TRY_END

-}

-

-STDMETHODIMP CHandler::Close()

-{

-  _items.Clear();

-  _stream.Release();

-  return S_OK;

-}

-

-STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)

-{

-  *numItems = _items.Size();

-  return S_OK;

-}

-

-STDMETHODIMP 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 += '.';

-        s += item.Name;

-      }

-      if (!item.Extension.IsEmpty())

-      {

-        s += '.';

-        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;

-  }

-  prop.Detach(value);

-  return S_OK;

-  COM_TRY_END

-}

-

-HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,

-    Int32 testMode, IArchiveExtractCallback *extractCallback)

-{

-  COM_TRY_BEGIN

-  

-  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<ICompressProgressInfo> progress = lps;

-  lps->Init(extractCallback, false);

-

-  CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;

-  CMyComPtr<ISequentialInStream> inStream(streamSpec);

-  streamSpec->SetStream(_stream);

-

-  CLimitedSequentialOutStream *outStreamSpec = new CLimitedSequentialOutStream;

-  CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);

-

-  NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();

-  CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;

-

-  for (i = 0; i < numItems; i++)

-  {

-    lps->InSize = totalSize;

-    lps->OutSize = totalSize;

-    RINOK(lps->SetCur());

-    CMyComPtr<ISequentialOutStream> realOutStream;

-    Int32 askMode = testMode ?

-        NExtract::NAskMode::kTest :

-        NExtract::NAskMode::kExtract;

-    Int32 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(_stream->Seek(item.Offset, STREAM_SEEK_SET, NULL));

-    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

-}

-

-

-STDMETHODIMP 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_GetArcBoolProp(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; defined = true; break;

-    case VT_I4: result = (Int64)prop.lVal; defined = true; break;

-    case VT_UI8: result = (UInt64)prop.uhVal.QuadPart; defined = true; break;

-    case VT_I8: result = (UInt64)prop.hVal.QuadPart; defined = true; break;

-    case VT_EMPTY: break;

-    default: return E_FAIL;

-  }

-  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; defined = true; break;

-    case VT_I4: result = prop.lVal; defined = true; break;

-    case VT_UI8: result = (Int64)prop.uhVal.QuadPart; defined = true; break;

-    case VT_I8: result = (Int64)prop.hVal.QuadPart; defined = true; break;

-    case VT_EMPTY: break;

-    default: return E_FAIL;

-  }

-  return S_OK;

-}

-

-#ifndef _SFX

-

-HRESULT CArc::GetItemPathToParent(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 += ':';

-        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::GetItemPath(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;

-        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;

-          #endif

-          *s++ = c;

-        }

-        *s = 0;

-        result.ReleaseBuf_SetLen(len);

-        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 GetDefaultItemPath(index, result);

-  return S_OK;

-}

-

-HRESULT CArc::GetDefaultItemPath(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 += '.';

-      result += prop.bstrVal;

-    }

-    else if (prop.vt != VT_EMPTY)

-      return E_FAIL;

-  }

-  return S_OK;

-}

-

-HRESULT CArc::GetItemPath2(UInt32 index, UString &result) const

-{

-  RINOK(GetItemPath(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 = 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(GetItemPath2(index, item.Path));

-

-  #ifndef _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(GetItemPath2(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(colon);

-      item.AltStreamName = item.Path.Ptr(colon + 1);

-      item.MainIsDir = (colon == 0 || IsPathSepar(item.Path[(unsigned)colon - 1]));

-      item.IsAltStream = true;

-    }

-  }

-

-  #endif

-  

-  #ifndef _SFX

-  if (item._use_baseParentFolder_mode)

-  {

-    RINOK(GetItemPathToParent(mainIndex, 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(colon + 1);

-          item.MainIsDir = (colon == 0 || IsPathSepar(s[(unsigned)colon - 1]));

-          item.IsAltStream = true;

-          s.DeleteFrom(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 _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::GetItemSize(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::GetItemMTime(UInt32 index, FILETIME &ft, bool &defined) const

-{

-  NCOM::CPropVariant prop;

-  defined = false;

-  ft.dwHighDateTime = ft.dwLowDateTime = 0;

-  RINOK(Archive->GetProperty(index, kpidMTime, &prop));

-  if (prop.vt == VT_FILETIME)

-  {

-    ft = prop.filetime;

-    defined = true;

-  }

-  else if (prop.vt != VT_EMPTY)

-    return E_FAIL;

-  else if (MTimeDefined)

-  {

-    ft = MTime;

-    defined = true;

-  }

-  return S_OK;

-}

-

-#ifndef _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++)

-  {

-    int index = orderIndices[i];

-    if (index < 0)

-      continue;

-    const CArcInfoEx &ai = codecs->Formats[(unsigned)index];

-    if (ai.SignatureOffset != 0)

-    {

-      orderIndices2.Add(index);

-      orderIndices[i] = -1;

-      continue;

-    }

-

-    const CObjectVector<CByteBuffer> &sigs = ai.Signatures;

-    FOR_VECTOR (k, sigs)

-    {

-      const CByteBuffer &sig = sigs[k];

-      if (sig.Size() == 0 && dataSize == 0 ||

-          sig.Size() != 0 && sig.Size() <= dataSize &&

-          TestSignature(data, sig, sig.Size()))

-      {

-        orderIndices2.Add(index);

-        orderIndices[i] = -1;

-        break;

-      }

-    }

-  }

-}

-

-#endif

-

-#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

-

-

-#ifndef _SFX

-

-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, 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, ARRAY_SIZE(k_Formats_with_simple_signuature));

-}

-

-class CArchiveOpenCallback_Offset:

-  public IArchiveOpenCallback,

-  public IArchiveOpenVolumeCallback,

-  #ifndef _NO_CRYPTO

-  public ICryptoGetTextPassword,

-  #endif

-  public CMyUnknownImp

-{

-public:

-  CMyComPtr<IArchiveOpenCallback> Callback;

-  CMyComPtr<IArchiveOpenVolumeCallback> OpenVolumeCallback;

-  UInt64 Files;

-  UInt64 Offset;

-  

-  #ifndef _NO_CRYPTO

-  CMyComPtr<ICryptoGetTextPassword> GetTextPassword;

-  #endif

-

-  MY_QUERYINTERFACE_BEGIN2(IArchiveOpenCallback)

-  MY_QUERYINTERFACE_ENTRY(IArchiveOpenVolumeCallback)

-  #ifndef _NO_CRYPTO

-  MY_QUERYINTERFACE_ENTRY(ICryptoGetTextPassword)

-  #endif

-  MY_QUERYINTERFACE_END

-  MY_ADDREF_RELEASE

-

-  INTERFACE_IArchiveOpenCallback(;)

-  INTERFACE_IArchiveOpenVolumeCallback(;)

-  #ifndef _NO_CRYPTO

-  STDMETHOD(CryptoGetTextPassword)(BSTR *password);

-  #endif

-};

-

-#ifndef _NO_CRYPTO

-STDMETHODIMP CArchiveOpenCallback_Offset::CryptoGetTextPassword(BSTR *password)

-{

-  COM_TRY_BEGIN

-  if (GetTextPassword)

-    return GetTextPassword->CryptoGetTextPassword(password);

-  return E_NOTIMPL;

-  COM_TRY_END

-}

-#endif

-

-STDMETHODIMP CArchiveOpenCallback_Offset::SetTotal(const UInt64 *, const UInt64 *)

-{

-  return S_OK;

-}

-

-STDMETHODIMP 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);

-}

-

-STDMETHODIMP CArchiveOpenCallback_Offset::GetProperty(PROPID propID, PROPVARIANT *value)

-{

-  if (OpenVolumeCallback)

-    return OpenVolumeCallback->GetProperty(propID, value);

-  NCOM::PropVariant_Clear(value);

-  return S_OK;

-  // return E_NOTIMPL;

-}

-

-STDMETHODIMP 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;

-  PhySizeDefined = 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, PhySizeDefined));

-    /*

-    RINOK(Archive_GetArcProp_UInt(archive, kpidOkPhySize, OkPhySize, OkPhySize_Defined));

-    if (!OkPhySize_Defined)

-    {

-      OkPhySize_Defined = PhySizeDefined;

-      OkPhySize = PhySize;

-    }

-    */

-

-    bool offsetDefined;

-    RINOK(Archive_GetArcProp_Int(archive, kpidOffset, Offset, offsetDefined));

-

-    Int64 globalOffset = startPos + Offset;

-    AvailPhySize = FileSize - globalOffset;

-    if (PhySizeDefined)

-    {

-      UInt64 endPos = globalOffset + PhySize;

-      if (endPos < FileSize)

-      {

-        AvailPhySize = PhySize;

-        ErrorInfo.ThereIsTail = true;

-        ErrorInfo.TailSize = FileSize - endPos;

-      }

-      else if (endPos > FileSize)

-        ErrorInfo.UnexpecedEnd = true;

-    }

-  }

-

-  return S_OK;

-}

-

-/*

-static PrintNumber(const char *s, int n)

-{

-  char temp[100];

-  sprintf(temp, "%s %d", s, n);

-  OutputDebugStringA(temp);

-}

-*/

-

-HRESULT CArc::PrepareToOpen(const COpenOptions &op, unsigned formatIndex, CMyComPtr<IInArchive> &archive)

-{

-  // OutputDebugStringA("a1");

-  // PrintNumber("formatIndex", formatIndex);

-    

-  RINOK(op.codecs->CreateInArchive(formatIndex, archive));

-  // OutputDebugStringA("a2");

-  if (!archive)

-    return S_OK;

-

-  #ifdef EXTERNAL_CODECS

-  if (op.codecs->NeedSetLibCodecs)

-  {

-    const CArcInfoEx &ai = op.codecs->Formats[formatIndex];

-    if (ai.LibIndex >= 0 ?

-        !op.codecs->Libs[ai.LibIndex].SetCodecs :

-        !op.codecs->Libs.IsEmpty())

-    {

-      CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo;

-      archive.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo);

-      if (setCompressCodecsInfo)

-      {

-        RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(op.codecs));

-      }

-    }

-  }

-  #endif

-  

-  

-  #ifndef _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<IArchiveAllowTail> 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 _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_GetArcBoolProp(archive, kpidIsNotArcType, pi.IsNotArcType));

-

-  // RINOK(Archive_GetArcBoolProp(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(op.stream->Seek(offset, STREAM_SEEK_SET, NULL));

-  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 _SFX

-

-class CExtractCallback_To_OpenCallback:

-  public IArchiveExtractCallback,

-  public ICompressProgressInfo,

-  public CMyUnknownImp

-{

-public:

-  CMyComPtr<IArchiveOpenCallback> Callback;

-  UInt64 Files;

-  UInt64 Offset;

-

-  MY_UNKNOWN_IMP2(IArchiveExtractCallback, ICompressProgressInfo)

-  INTERFACE_IArchiveExtractCallback(;)

-  STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);

-  void Init(IArchiveOpenCallback *callback)

-  {

-    Callback = callback;

-    Files = 0;

-    Offset = 0;

-  }

-};

-

-STDMETHODIMP CExtractCallback_To_OpenCallback::SetTotal(UInt64 /* size */)

-{

-  return S_OK;

-}

-

-STDMETHODIMP CExtractCallback_To_OpenCallback::SetCompleted(const UInt64 * /* completeValue */)

-{

-  return S_OK;

-}

-

-STDMETHODIMP 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;

-}

-

-STDMETHODIMP CExtractCallback_To_OpenCallback::GetStream(UInt32 /* index */, ISequentialOutStream **outStream, Int32 /* askExtractMode */)

-{

-  *outStream = 0;

-  return S_OK;

-}

-

-STDMETHODIMP CExtractCallback_To_OpenCallback::PrepareOperation(Int32 /* askExtractMode */)

-{

-  return S_OK;

-}

-

-STDMETHODIMP 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)

-  {

-    CMyComPtr<IArchiveOpen2> open2;

-    archive->QueryInterface(IID_IArchiveOpen2, (void **)&open2);

-    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_GetArcBoolProp(archive, kpidPhySizeCantBeDetected, phySizeCantBeDetected));

-

-    if (!phySizeCantBeDetected)

-    {

-      RINOK(archive->Extract(0, (UInt32)(Int32)-1, BoolToInt(true), extractCallback));

-    }

-  }

-  return S_OK;

-}

-

-static int FindFormatForArchiveType(CCodecs *codecs, CIntVector orderIndices, const char *name)

-{

-  FOR_VECTOR (i, orderIndices)

-    if (StringsAreEqualNoCase_Ascii(codecs->Formats[orderIndices[i]].Name, name))

-      return 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;

-  {

-    int dotPos = fileName.ReverseFind_Dot();

-    if (dotPos >= 0)

-      extension = fileName.Ptr(dotPos + 1);

-  }

-  

-  CIntVector orderIndices;

-  

-  bool searchMarkerInHandler = false;

-  #ifdef _SFX

-    searchMarkerInHandler = true;

-  #endif

-

-  CBoolArr isMainFormatArr(op.codecs->Formats.Size());

-  {

-    FOR_VECTOR(i, op.codecs->Formats)

-      isMainFormatArr[i] = false;

-  }

-

-  UInt64 maxStartOffset =

-      op.openType.MaxStartOffset_Defined ?

-      op.openType.MaxStartOffset :

-      kMaxCheckStartPosition;

-

-  #ifndef _SFX

-  bool isUnknownExt = false;

-  #endif

-

-  bool isForced = false;

-  unsigned numMainTypes = 0;

-  int formatIndex = op.openType.FormatIndex;

-

-  if (formatIndex >= 0)

-  {

-    isForced = true;

-    orderIndices.Add(formatIndex);

-    numMainTypes = 1;

-    isMainFormatArr[(unsigned)formatIndex] = true;

-

-    searchMarkerInHandler = true;

-  }

-  else

-  {

-    unsigned numFinded = 0;

-    #ifndef _SFX

-    bool isPrearcExt = false;

-    #endif

-    

-    {

-      #ifndef _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.IsSplit())

-            continue;

-        if (op.excludedFormats->FindInSorted(i) >= 0)

-          continue;

-

-        #ifndef _SFX

-        if (IsPreArcFormat(ai))

-          isPrearcExt = true;

-        #endif

-

-        if (ai.FindExtension(extension) >= 0

-            #ifndef _SFX

-            || isZip && StringsAreEqualNoCase_Ascii(ai.Name, "zip")

-            || isRar && StringsAreEqualNoCase_Ascii(ai.Name, "rar")

-            #endif

-            )

-        {

-          // PrintNumber("orderIndices.Insert", i);

-          orderIndices.Insert(numFinded++, i);

-          isMainFormatArr[i] = true;

-        }

-        else

-          orderIndices.Add(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 _SFX

-

-      if (op.stream && orderIndices.Size() >= 2)

-      {

-        RINOK(op.stream->Seek(0, STREAM_SEEK_SET, NULL));

-        CByteBuffer byteBuffer;

-        CIntVector orderIndices2;

-        if (numFinded == 0 || IsExeExt(extension))

-        {

-          // signature search was here

-        }

-        else if (extension.IsEqualTo("000") || extension.IsEqualTo("001"))

-        {

-          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[i]);

-                orderIndices[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:

-            1) matched extension, no signuature

-            2) matched extension, matched signuature

-            // 3) no signuature

-            // 4) matched signuature

-          */

-

-          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)

-        {

-          int val = orderIndices[i];

-          if (val != -1)

-            orderIndices2.Add(val);

-        }

-        orderIndices = orderIndices2;

-      }

-      

-      if (orderIndices.Size() >= 2)

-      {

-        int iIso = FindFormatForArchiveType(op.codecs, orderIndices, "iso");

-        int iUdf = FindFormatForArchiveType(op.codecs, orderIndices, "udf");

-        if (iUdf > iIso && iIso >= 0)

-        {

-          int isoIndex = orderIndices[iIso];

-          int udfIndex = orderIndices[iUdf];

-          orderIndices[iUdf] = isoIndex;

-          orderIndices[iIso] = udfIndex;

-        }

-      }

-

-      numMainTypes = numFinded;

-      isUnknownExt = (numMainTypes == 0) || isPrearcExt;

-

-    #else // _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(op.stream->Seek(0, STREAM_SEEK_END, &fileSize));

-    RINOK(op.stream->Seek(0, STREAM_SEEK_SET, NULL));

-  }

-  FileSize = fileSize;

-

-

-  #ifndef _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];

-      

-      bool exactOnly = false;

-

-      #ifndef _SFX

-    

-      const CArcInfoEx &ai = op.codecs->Formats[FormatIndex];

-      // OutputDebugStringW(ai.Name);

-      if (i >= numMainTypes)

-      {

-        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(op.stream->Seek(0, STREAM_SEEK_SET, NULL));

-      }

-      

-      CMyComPtr<IInArchive> archive;

-      

-      RINOK(PrepareToOpen(op, 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<IArchiveOpenSeq> 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 _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 _SFX

-              if (!IsPreArcFormat(ai) /* || !mode.SkipSfxStub */)

-              #endif

-                return S_FALSE;

-            }

-          }

-        }

-        

-        /*

-        #ifndef _SFX

-        if (IsExeExt(extension) || ai.Flags_PreArc())

-        {

-        // openOnlyFullArc = false;

-        // canReturnTailArc = true;

-        // limitSignatureSearch = true;

-        }

-        #endif

-        */

-        

-        continue;

-      }

-      

-      RINOK(result);

-      

-      #ifndef _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, Offset + 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 _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<IInArchive> handler = handlerSpec;

-

-  CExtractCallback_To_OpenCallback *extractCallback_To_OpenCallback_Spec = new CExtractCallback_To_OpenCallback;

-  CMyComPtr<IArchiveExtractCallback> 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(op.stream->Seek(0, STREAM_SEEK_SET, NULL));

-      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++)

-    {

-      unsigned form = orderIndices[i];

-      if (skipFrontalFormat[form])

-        continue;

-      const CArcInfoEx &ai = op.codecs->Formats[form];

-      if (ai.IsSplit())

-      {

-        splitIndex = form;

-        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;

-      }

-

-      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];

-          UInt32 signatureEnd = ai.SignatureOffset + (UInt32)sig.Size();

-          if (processedSize < signatureEnd)

-          {

-            if (!endOfFile)

-              needCheck = true;

-          }

-          else if (memcmp(sig, byteBuffer + ai.SignatureOffset, sig.Size()) == 0)

-            break;

-        }

-        if (k != ai.Signatures.Size())

-        {

-          sortedFormats.Insert(0, form);

-          continue;

-        }

-      }

-      if (needCheck)

-        sortedFormats.Add(form);

-    }

-

-    if (splitIndex >= 0)

-      sortedFormats.Insert(0, splitIndex);

-

-    for (i = 0; i < sortedFormats.Size(); i++)

-    {

-      FormatIndex = sortedFormats[i];

-      const CArcInfoEx &ai = op.codecs->Formats[FormatIndex];

-

-      if (op.callback)

-        RINOK(op.callback->SetTotal(NULL, &fileSize));

-

-      RINOK(op.stream->Seek(0, STREAM_SEEK_SET, NULL));

-

-      CMyComPtr<IInArchive> archive;

-      RINOK(PrepareToOpen(op, 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

-        */

-        result = OpenArchiveSpec(archive, !mode.CanReturnArc, 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 = Offset;

-      pi.Size = AvailPhySize;

-      

-      // bool needScan = false;

-

-      if (!PhySizeDefined)

-      {

-        // 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)

-      {

-        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, Offset + 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<CByteBuffer> &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];

-      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(index);

-        difficultBools[(unsigned)index] = true;

-      }

-    }

-    

-    if (!thereAreHandlersForSearch)

-    {

-      // openOnlyFullArc = true;

-      // canReturnTailArc = true;

-    }

-    

-    RINOK(op.stream->Seek(0, STREAM_SEEK_SET, NULL));

-

-    CLimitedCachedInStream *limitedStreamSpec = new CLimitedCachedInStream;

-    CMyComPtr<IInStream> limitedStream = limitedStreamSpec;

-    limitedStreamSpec->SetStream(op.stream);

-

-    CArchiveOpenCallback_Offset *openCallback_Offset_Spec = NULL;

-    CMyComPtr<IArchiveOpenCallback> 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 _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(op.stream->Seek(bufPhyPos + bytesInBuf, STREAM_SEEK_SET, NULL));

-          RINOK(ReadStream(op.stream, byteBuffer + 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 + 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 + 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_Spec->SetCompleted(NULL, NULL));

-          callbackPrev = pos;

-        }

-      }

-

-      {

-        UInt64 endPos = bufPhyPos + bytesInBuf;

-        if (fileSize < endPos)

-        {

-          FileSize = fileSize; // why ????

-          fileSize = endPos;

-        }

-      }

-

-      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 + (size_t)posInBuf;

-      const Byte *bufLimit = buf + scanSize;

-      size_t ppp = 0;

-      

-      if (!needCheckStartOpen)

-      {

-        for (; buf < bufLimit && hash[HASH_VAL(buf)] == 0xFF; buf++);

-        ppp = buf - (byteBuffer + (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)

-        {

-          size_t offsetInBuf = (size_t)(startArcPos - bufPhyPos);

-          if (offsetInBuf < bytesInBuf)

-          {

-            UInt32 isArcRes = ai.IsArcFunc(byteBuffer + 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);

-        }

-        

-        /*

-        if (pos == 67109888)

-          pos = pos;

-        */

-        PRF(printf("\npos = %9I64d : %S", pos, (const wchar_t *)ai.Name));

-

-        bool isMainFormat = isMainFormatArr[index];

-        const COpenSpecFlags &specFlags = mode.GetSpec(isForced, isMainFormat, isUnknownExt);

-        

-        CMyComPtr<IInArchive> archive;

-        RINOK(PrepareToOpen(op, index, archive));

-        if (!archive)

-          return E_FAIL;

-        

-        // OutputDebugStringW(ai.Name);

-        

-        UInt64 rem = fileSize - startArcPos;

-        

-        UInt64 arcStreamOffset = 0;

-

-        if (ai.Flags_UseGlobalOffset())

-        {

-          limitedStreamSpec->InitAndSeek(0, fileSize);

-          limitedStream->Seek(startArcPos, STREAM_SEEK_SET, NULL);

-        }

-        else

-        {

-          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, 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 = index;

-              NonOpen_ErrorInfo = ErrorInfo;

-              // if archive was detected, we don't need additional open attempts

-              return S_FALSE;

-            }

-            continue;

-          }

-          if (!ErrorInfo.IsArc_After_NonOpen() || !PhySizeDefined || PhySize == 0)

-            continue;

-        }

-        else

-        {

-          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 = Offset;

-        else if (Offset != 0)

-          return E_FAIL;

-        UInt64 arcRem = FileSize - pi.Offset;

-        UInt64 phySize = arcRem;

-        bool phySizeDefined = PhySizeDefined;

-        if (phySizeDefined)

-        {

-          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 && !phySizeDefined)

-        {

-          // it's for Z format

-          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 && phySizeDefined && 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 /* && phySizeDefined */)

-        {

-          /* 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 && phySizeDefined)

-        {

-          // if (pi.Offset + pi.Size >= fileSize)

-          bool openCur = false;

-

-          bool thereIsTail = ErrorInfo.ThereIsTail;

-          if (thereIsTail && mode.ZerosTailIsAllowed)

-          {

-            RINOK(CheckZerosTail(op, arcStreamOffset + Offset + 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 = index;

-            ArcStreamOffset = arcStreamOffset;

-            return S_OK;

-          }

-        }

-

-        /*

-        if (openOnlyFullArc)

-        {

-          ErrorInfo.ClearErrors();

-          return S_FALSE;

-        }

-        */

-

-        pi.FormatIndex = 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_GetArcBoolProp(Archive, kpidIsTree, IsTree));

-    RINOK(Archive_GetArcBoolProp(Archive, kpidIsDeleted, Ask_Deleted));

-    RINOK(Archive_GetArcBoolProp(Archive, kpidIsAltStream, Ask_AltStream));

-    RINOK(Archive_GetArcBoolProp(Archive, kpidIsAux, Ask_Aux));

-    RINOK(Archive_GetArcBoolProp(Archive, kpidINode, Ask_INode));

-    RINOK(Archive_GetArcBoolProp(Archive, kpidReadOnly, IsReadOnly));

-

-    const UString fileName = ExtractFileNameFromPath(Path);

-    UString extension;

-    {

-      int dotPos = fileName.ReverseFind_Dot();

-      if (dotPos >= 0)

-        extension = fileName.Ptr(dotPos + 1);

-    }

-    

-    DefaultName.Empty();

-    if (FormatIndex >= 0)

-    {

-      const CArcInfoEx &ai = op.codecs->Formats[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[subExtIndex];

-        DefaultName = GetDefaultName2(fileName, extInfo.Ext, extInfo.AddExt);

-      }

-    }

-  }

-

-  return S_OK;

-}

-

-#ifdef _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<IInStream> fileStream;

-  CMyComPtr<ISequentialInStream> seqStream;

-  CInFileStream *fileStreamSpec = NULL;

-  

-  if (op.stdInMode)

-  {

-    seqStream = new CStdInFileStream;

-    op.seqStream = seqStream;

-  }

-  else if (!op.stream)

-  {

-    fileStreamSpec = new CInFileStream;

-    fileStream = fileStreamSpec;

-    Path = filePath;

-    if (!fileStreamSpec->Open(us2fs(Path)))

-    {

-      return GetLastError();

-    }

-    op.stream = fileStream;

-    #ifdef _SFX

-    IgnoreSplit = true;

-    #endif

-  }

-

-  /*

-  if (callback)

-  {

-    UInt64 fileSize;

-    RINOK(op.stream->Seek(0, STREAM_SEEK_END, &fileSize));

-    RINOK(op.callback->SetTotal(NULL, &fileSize))

-  }

-  */

-

-  HRESULT res = OpenStream(op);

-  IgnoreSplit = false;

-  

-  #ifdef _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.IsSplit())

-          continue;

-        UString path3 = path2;

-        path3 += '.';

-        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<IArchiveKeepModeForNextOpen> 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<IInArchiveGetStream> getStream;

-    if (arc.Archive->QueryInterface(IID_IInArchiveGetStream, (void **)&getStream) != S_OK || !getStream)

-      break;

-    

-    CMyComPtr<ISequentialInStream> subSeqStream;

-    if (getStream->GetStream(mainSubfile, &subSeqStream) != S_OK || !subSeqStream)

-      break;

-    

-    CMyComPtr<IInStream> subStream;

-    if (subSeqStream.QueryInterface(IID_IInStream, &subStream) != S_OK || !subStream)

-      break;

-    

-    CArc arc2;

-    RINOK(arc.GetItemPath(mainSubfile, arc2.Path));

-

-    bool zerosTailIsAllowed;

-    RINOK(Archive_GetItemBoolProp(arc.Archive, mainSubfile, kpidZerosTailIsAllowed, zerosTailIsAllowed));

-

-

-    if (op.callback)

-    {

-      CMyComPtr<IArchiveOpenSetSubArchiveName> setSubArchiveName;

-      op.callback->QueryInterface(IID_IArchiveOpenSetSubArchiveName, (void **)&setSubArchiveName);

-      if (setSubArchiveName)

-        setSubArchiveName->SetSubArchiveName(arc2.Path);

-    }

-    

-    arc2.SubfileIndex = mainSubfile;

-

-    // CIntVector incl;

-    CIntVector excl;

-

-    COpenOptions op2;

-    #ifndef _SFX

-    op2.props = op.props;

-    #endif

-    op2.codecs = op.codecs;

-    // op2.types = &incl;

-    op2.openType = op.openType;

-    op2.openType.ZerosTailIsAllowed = zerosTailIsAllowed;

-    op2.excludedFormats = &excl;

-    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.GetItemMTime(mainSubfile, arc2.MTime, arc2.MTimeDefined));

-    Arcs.Add(arc2);

-  }

-  IsOpen = !Arcs.IsEmpty();

-  return resSpec;

-}

-

-HRESULT CArchiveLink::Open2(COpenOptions &op, IOpenCallbackUI *callbackUI)

-{

-  VolumesSize = 0;

-  COpenCallbackImp *openCallbackSpec = new COpenCallbackImp;

-  CMyComPtr<IArchiveOpenCallback> callback = openCallbackSpec;

-  openCallbackSpec->Callback = callbackUI;

-

-  FString prefix, name;

-  

-  if (!op.stream && !op.stdInMode)

-  {

-    NFile::NDir::GetFullPathAndSplit(us2fs(op.filePath), prefix, name);

-    openCallbackSpec->Init(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)

-{

-  ErrorInfo.ClearErrors();

-  ErrorInfo.ErrorFormatIndex = -1;

-

-  UInt64 fileSize = 0;

-  if (op.stream)

-  {

-    RINOK(op.stream->Seek(0, STREAM_SEEK_END, &fileSize));

-    RINOK(op.stream->Seek(0, STREAM_SEEK_SET, NULL));

-  }

-  FileSize = fileSize;

-

-  CMyComPtr<IInStream> stream2;

-  Int64 globalOffset = GetGlobalOffset();

-  if (globalOffset <= 0)

-    stream2 = op.stream;

-  else

-  {

-    CTailInStream *tailStreamSpec = new CTailInStream;

-    stream2 = tailStreamSpec;

-    tailStreamSpec->Stream = op.stream;

-    tailStreamSpec->Offset = 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;

-  HRESULT res = Archive->Open(stream2, &maxStartPosition, op.callback);

-  

-  if (res == S_OK)

-  {

-    RINOK(ReadBasicProps(Archive, globalOffset, res));

-    ArcStreamOffset = 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<COpenType> inc;

-  CIntVector excl;

-

-  op.types = &inc;

-  op.excludedFormats = &excl;

-  op.stdInMode = false;

-  op.stream = NULL;

-  if (Arcs.Size() == 0) // ???

-    return Open2(op, NULL);

-

-  COpenCallbackImp *openCallbackSpec = new COpenCallbackImp;

-  CMyComPtr<IArchiveOpenCallback> openCallbackNew = openCallbackSpec;

-

-  openCallbackSpec->Callback = NULL;

-  openCallbackSpec->ReOpenCallback = op.callback;

-  {

-    FString dirPrefix, fileName;

-    NFile::NDir::GetFullPathAndSplit(us2fs(op.filePath), dirPrefix, fileName);

-    openCallbackSpec->Init(dirPrefix, fileName);

-  }

-

-

-  CInFileStream *fileStreamSpec = new CInFileStream;

-  CMyComPtr<IInStream> stream(fileStreamSpec);

-  if (!fileStreamSpec->Open(us2fs(op.filePath)))

-    return GetLastError();

-  op.stream = stream;

-

-  CArc &arc = Arcs[0];

-  HRESULT res = arc.ReOpen(op);

-  

-  PasswordWasAsked = openCallbackSpec->PasswordWasAsked;

-  // Password = openCallbackSpec->Password;

-  

-  IsOpen = (res == S_OK);

-  return res;

-}

-

-#ifndef _SFX

-

-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;

-    }

-    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;

-}

-

-bool ParseType(CCodecs &codecs, const UString &s, COpenType &type)

-{

-  int pos2 = s.Find(L':');

-

-  {

-  UString name;

-  if (pos2 < 0)

-  {

-    name = s;

-    pos2 = s.Len();

-  }

-  else

-  {

-    name = s.Left(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

-      return false;

-  }

-  

-  type.FormatIndex = index;

-

-  }

- 

-  for (unsigned i = pos2; i < s.Len();)

-  {

-    int next = s.Find(L':', i);

-    if (next < 0)

-      next = s.Len();

-    const UString name = s.Mid(i, next - i);

-    if (name.IsEmpty())

-      return false;

-    if (!ParseTypeParams(name, type))

-      return false;

-    i = next + 1;

-  }

-  

-  return true;

-}

-

-bool ParseOpenTypes(CCodecs &codecs, const UString &s, CObjectVector<COpenType> &types)

-{

-  types.Clear();

-  for (unsigned pos = 0; pos < s.Len();)

-  {

-    int pos2 = s.Find(L'.', pos);

-    if (pos2 < 0)

-      pos2 = s.Len();

-    UString name = s.Mid(pos, pos2 - pos);

-    if (name.IsEmpty())

-      return false;

-    COpenType type;

-    if (!ParseType(codecs, name, type))

-      return false;

-    types.Add(type);

-    pos = pos2 + 1;

-  }

-  return true;

-}

-

-#endif

+// OpenArchive.cpp
+
+#include "StdAfx.h"
+
+// #define SHOW_DEBUG_INFO
+
+#ifdef SHOW_DEBUG_INFO
+#include <stdio.h>
+#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<CParseItem> _items;
+  UInt64 _maxEndOffset;
+  CMyComPtr<IInStream> _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;
+  }
+  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<ICompressProgressInfo> progress = lps;
+  lps->Init(extractCallback, false);
+
+  CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+  CMyComPtr<ISequentialInStream> inStream(streamSpec);
+  streamSpec->SetStream(_stream);
+
+  CLimitedSequentialOutStream *outStreamSpec = new CLimitedSequentialOutStream;
+  CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+
+  NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+  CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+  for (i = 0; i < numItems; i++)
+  {
+    lps->InSize = totalSize;
+    lps->OutSize = totalSize;
+    RINOK(lps->SetCur())
+    CMyComPtr<ISequentialOutStream> 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 += ':';
+        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<CByteBuffer> &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<IArchiveOpenCallback> Callback;
+  CMyComPtr<IArchiveOpenVolumeCallback> OpenVolumeCallback;
+  UInt64 Files;
+  UInt64 Offset;
+  
+  #ifndef Z7_NO_CRYPTO
+  CMyComPtr<ICryptoGetTextPassword> 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<IInArchive> &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<ISetCompressCodecsInfo> 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<IArchiveAllowTail> 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<IArchiveOpenCallback> 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<IInArchive> 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<IArchiveOpenSeq> 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<IInArchive> handler = handlerSpec;
+
+  CExtractCallback_To_OpenCallback *extractCallback_To_OpenCallback_Spec = new CExtractCallback_To_OpenCallback;
+  CMyComPtr<IArchiveExtractCallback> 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<IInArchive> 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<CByteBuffer> &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<IInStream> limitedStream = limitedStreamSpec;
+    limitedStreamSpec->SetStream(op.stream);
+
+    CArchiveOpenCallback_Offset *openCallback_Offset_Spec = NULL;
+    CMyComPtr<IArchiveOpenCallback> 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 + 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 + 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 + 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 + (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 + (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 + 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<IInArchive> 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<IInStream> fileStream;
+  CMyComPtr<ISequentialInStream> seqStream;
+  CInFileStream *fileStreamSpec = NULL;
+  
+  if (op.stdInMode)
+  {
+    seqStream = new CStdInFileStream;
+    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<IArchiveKeepModeForNextOpen> 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<IInArchiveGetStream> getStream;
+    if (arc.Archive->QueryInterface(IID_IInArchiveGetStream, (void **)&getStream) != S_OK || !getStream)
+      break;
+    
+    CMyComPtr<ISequentialInStream> subSeqStream;
+    if (getStream->GetStream(mainSubfile, &subSeqStream) != S_OK || !subSeqStream)
+      break;
+    
+    CMyComPtr<IInStream> 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 = &excl;
+    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<IArchiveOpenCallback> 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<IInStream> 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<COpenType> inc;
+  CIntVector excl;
+
+  op.types = &inc;
+  op.excludedFormats = &excl;
+  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<IArchiveOpenCallback> 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<IInStream> 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;
+    }
+    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<COpenType> &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<COpenType> &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 033cb96..5c3bfe5 100644
--- a/CPP/7zip/UI/Common/OpenArchive.h
+++ b/CPP/7zip/UI/Common/OpenArchive.h
@@ -1,436 +1,469 @@
-// OpenArchive.h

-

-#ifndef __OPEN_ARCHIVE_H

-#define __OPEN_ARCHIVE_H

-

-#include "../../../Windows/PropVariant.h"

-

-#include "ArchiveOpenCallback.h"

-#include "LoadCodecs.h"

-#include "Property.h"

-

-#ifndef _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<CProperty> Props;

-};

-*/

-

-#ifdef _SFX

-#define OPEN_PROPS_DECL

-#else

-#define OPEN_PROPS_DECL const CObjectVector<CProperty> *props;

-// #define OPEN_PROPS_DECL , const CObjectVector<COptionalOpenProperties> *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 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),

-      EachPos(false),

-      CanReturnArc(true),

-      CanReturnParser(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<COpenType> *types;

-  const CIntVector *excludedFormats;

-

-  IInStream *stream;

-  ISequentialInStream *seqStream;

-  IArchiveOpenCallback *callback;

-  COpenCallbackImp *callbackSpec;

-  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 _SFX

-  bool _use_baseParentFolder_mode;

-  int _baseParentFolder;

-  #endif

-

-  CReadArcItem()

-  {

-    #ifdef SUPPORT_ALT_STREAMS

-    WriteToAltStreamIfColon = false;

-    #endif

-

-    #ifndef _SFX

-    _use_baseParentFolder_mode = false;

-    _baseParentFolder = -1;

-    #endif

-  }

-};

-

-class CArc

-{

-  HRESULT PrepareToOpen(const COpenOptions &op, unsigned formatIndex, CMyComPtr<IInArchive> &archive);

-  HRESULT CheckZerosTail(const COpenOptions &op, UInt64 offset);

-  HRESULT OpenStream2(const COpenOptions &options);

-

-  #ifndef _SFX

-  // parts.Back() can contain alt stream name "nams:AltName"

-  HRESULT GetItemPathToParent(UInt32 index, UInt32 parent, UStringVector &parts) const;

-  #endif

-

-public:

-  CMyComPtr<IInArchive> Archive;

-  CMyComPtr<IInStream> InStream;

-          // we use InStream in 2 cases (ArcStreamOffset != 0):

-          // 1) if we use additional cache stream

-          // 2) we reopen sfx archive with CTailInStream

-  

-  CMyComPtr<IArchiveGetRawProps> GetRawProps;

-  CMyComPtr<IArchiveGetRootProps> GetRootProps;

-

-  CArcErrorInfo ErrorInfo; // for OK archives

-  CArcErrorInfo NonOpen_ErrorInfo; // ErrorInfo for mainArchive (false OPEN)

-

-  UString Path;

-  UString filePath;

-  UString DefaultName;

-  int FormatIndex; // - 1 means Parser.

-  int SubfileIndex;

-  FILETIME MTime;

-  bool MTimeDefined;

-  

-  Int64 Offset; // it's offset of start of archive inside stream that is open by Archive Handler

-  UInt64 PhySize;

-  // UInt64 OkPhySize;

-  bool PhySizeDefined;

-  // bool OkPhySize_Defined;

-  UInt64 FileSize;

-  UInt64 AvailPhySize; // PhySize, but it's reduced if exceed end of file

-  // bool offsetDefined;

-

-  UInt64 GetEstmatedPhySize() const { return PhySizeDefined ? PhySize : FileSize; }

-

-  UInt64 ArcStreamOffset; // offset of stream that is open by Archive Handler

-  Int64 GetGlobalOffset() const { return ArcStreamOffset + Offset; } // it's global offset of archive

-

-  // AString ErrorFlagsText;

-

-  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

-

-  // void Set_ErrorFlagsText();

-

-  CArc():

-    MTimeDefined(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);

-

-  // ~CArc();

-

-  HRESULT Close()

-  {

-    InStream.Release();

-    return Archive->Close();

-  }

-

-  HRESULT GetItemPath(UInt32 index, UString &result) const;

-  HRESULT GetDefaultItemPath(UInt32 index, UString &result) const;

-  

-  // GetItemPath2 adds [DELETED] dir prefix for deleted items.

-  HRESULT GetItemPath2(UInt32 index, UString &result) const;

-

-  HRESULT GetItem(UInt32 index, CReadArcItem &item) const;

-  

-  HRESULT GetItemSize(UInt32 index, UInt64 &size, bool &defined) const;

-  HRESULT GetItemMTime(UInt32 index, FILETIME &ft, bool &defined) const;

-  HRESULT IsItemAnti(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);

-  

-  HRESULT CreateNewTailStream(CMyComPtr<IInStream> &stream);

-};

-

-struct CArchiveLink

-{

-  CObjectVector<CArc> 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; }

-

-  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<COpenType> &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<CProperty> Props;
+};
+*/
+
+#ifdef Z7_SFX
+#define OPEN_PROPS_DECL
+#else
+#define OPEN_PROPS_DECL const CObjectVector<CProperty> *props;
+// #define OPEN_PROPS_DECL , const CObjectVector<COptionalOpenProperties> *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<COpenType> *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<IInArchive> &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<IInArchive> Archive;
+  CMyComPtr<IInStream> InStream;
+          // we use InStream in 2 cases (ArcStreamOffset != 0):
+          // 1) if we use additional cache stream
+          // 2) we reopen sfx archive with CTailInStream
+  
+  CMyComPtr<IArchiveGetRawProps> GetRawProps;
+  CMyComPtr<IArchiveGetRootProps> 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<IInStream> &stream);
+
+  bool IsHashHandler(const COpenOptions &options) const
+  {
+    if (FormatIndex < 0)
+      return false;
+    return options.codecs->Formats[(unsigned)FormatIndex].Flags_HashHandler();
+  }
+};
+
+struct CArchiveLink
+{
+  CObjectVector<CArc> 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<COpenType> &types);
+
+// bool IsHashType(const CObjectVector<COpenType> &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 bb9c89f..ee9ff32 100644
--- a/CPP/7zip/UI/Common/PropIDUtils.cpp
+++ b/CPP/7zip/UI/Common/PropIDUtils.cpp
@@ -1,668 +1,741 @@
-// 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"

-

-#define Get16(x) GetUi16(x)

-#define Get32(x) GetUi32(x)

-

-using namespace NWindows;

-

-static const unsigned kNumWinAtrribFlags = 21;

-static const char g_WinAttribChars[kNumWinAtrribFlags + 1] = "RHS8DAdNTsLCOIEV.X.PU";

-

-/*

-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

-22 RECALL_ON_DATA_ACCESS

-*/

-

-

-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');

-  if ((a & 0x400) != 0) s[6] = ((a & (1 << 3)) ? 's' : 'S');

-  if ((a & 0x200) != 0) s[9] = ((a & (1 << 0)) ? 't' : 'T');

-  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.

-  */

-  

-  bool isPosix = ((wa & 0xF0000000) != 0);

-  

-  UInt32 posix = 0;

-  if (isPosix)

-  {

-    posix = wa >> 16;

-    wa &= (UInt32)0x3FFF;

-  }

-

-  for (unsigned i = 0; i < kNumWinAtrribFlags; i++)

-  {

-    UInt32 flag = (1 << i);

-    if ((wa & flag) != 0)

-    {

-      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;

-    if ((ft.dwHighDateTime == 0 &&

-         ft.dwLowDateTime == 0))

-      return;

-    ConvertUtcFileTimeToString(prop.filetime, 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;

-      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++ = '-';

-      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;

-    }

-  }

-  

-  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;

-}

-

-static inline unsigned GetHex(unsigned v)

-{

-  return (v < 10) ? ('0' + v) : ('A' + (v - 10));

-}

-

-#ifndef _SFX

-

-static inline void AddHexToString(AString &res, unsigned v)

-{

-  res += (char)GetHex(v >> 4);

-  res += (char)GetHex(v & 0xF);

-}

-

-/*

-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 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, UInt32 lim, UInt32 &sidSize)

-{

-  sidSize = 0;

-  if (lim < 8)

-  {

-    s += "ERROR";

-    return;

-  }

-  UInt32 rev = p[0];

-  if (rev != 1)

-  {

-    s += "UNSUPPORTED";

-    return;

-  }

-  UInt32 num = p[1];

-  if (8 + num * 4 > lim)

-  {

-    s += "ERROR";

-    return;

-  }

-  sidSize = 8 + num * 4;

-  UInt32 authority = GetBe32(p + 4);

-

-  if (p[2] == 0 && p[3] == 0 && authority == 5 && num >= 1)

-  {

-    UInt32 v0 = Get32(p + 8);

-    if (v0 < ARRAY_SIZE(sidNames))

-    {

-      s += sidNames[v0];

-      return;

-    }

-    if (v0 == 32 && num == 2)

-    {

-      UInt32 v1 = Get32(p + 12);

-      int index = FindPairIndex(sid_32_Names, 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);

-      int index = FindPairIndex(sid_21_Names, 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 < 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 += '-';

-    s.Add_UInt32(Get32(p + 8 + i * 4));

-  }

-}

-

-static void ParseOwner(AString &s, const Byte *p, UInt32 size, UInt32 pos)

-{

-  if (pos > size)

-  {

-    s += "ERROR";

-    return;

-  }

-  UInt32 sidSize = 0;

-  ParseSid(s, p + pos, size - pos, sidSize);

-}

-

-static void ParseAcl(AString &s, const Byte *p, UInt32 size, const char *strName, UInt32 flags, UInt32 offset)

-{

-  UInt32 control = Get16(p + 2);

-  if ((flags & control) == 0)

-    return;

-  UInt32 pos = Get32(p + offset);

-  s.Add_Space();

-  s += strName;

-  if (pos >= size)

-    return;

-  p += pos;

-  size -= pos;

-  if (size < 8)

-    return;

-  if (Get16(p) != 2) // revision

-    return;

-  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, UInt32 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(size);

-  // s += '\n';

-  // s += Data_To_Hex(data, size);

-}

-

-#ifdef _WIN32

-

-static bool CheckSid(const Byte *data, UInt32 size, UInt32 pos) throw()

-{

-  if (pos >= size)

-    return false;

-  size -= pos;

-  if (size < 8)

-    return false;

-  UInt32 rev = data[pos];

-  if (rev != 1)

-    return false;

-  UInt32 num = data[pos + 1];

-  return (8 + num * 4 <= size);

-}

-

-static bool CheckAcl(const Byte *p, UInt32 size, UInt32 flags, UInt32 offset) throw()

-{

-  UInt32 control = Get16(p + 2);

-  if ((flags & control) == 0)

-    return true;

-  UInt32 pos = Get32(p + offset);

-  if (pos >= size)

-    return false;

-  p += pos;

-  size -= pos;

-  if (size < 8)

-    return false;

-  UInt32 aclSize = Get16(p + 2);

-  return (aclSize <= size);

-}

-

-bool CheckNtSecure(const Byte *data, UInt32 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" }

-};

-

-bool ConvertNtReparseToString(const Byte *data, UInt32 size, UString &s)

-{

-  s.Empty();

-  NFile::CReparseAttr attr;

-  DWORD errorCode = 0;

-  if (attr.Parse(data, size, errorCode))

-  {

-    if (!attr.IsSymLink())

-      s += "Junction: ";

-    s += attr.GetPath();

-    if (!attr.IsOkNamePair())

-    {

-      s += " : ";

-      s += attr.PrintName;

-    }

-    return true;

-  }

-

-  if (size < 8)

-    return false;

-  UInt32 tag = Get32(data);

-  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)

-  {

-  }

-  */

-

-  {

-    int index = FindPairIndex(k_ReparseTags, 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 += ":";

-  s.Add_UInt32(len);

-

-  if (len != 0)

-  {

-    s.Add_Space();

-    

-    data += 8;

-    

-    for (UInt32 i = 0; i < len; i++)

-    {

-      if (i >= 8)

-      {

-        s += "...";

-        break;

-      }

-      unsigned b = data[i];

-      s += (char)GetHex((b >> 4) & 0xF);

-      s += (char)GetHex(b & 0xF);

-    }

-  }

-

-  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 = 21;
+static const char g_WinAttribChars[kNumWinAtrribFlags + 1] = "RHS8DAdNTsLCOIEV.X.PU";
+
+/*
+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
+22 RECALL_ON_DATA_ACCESS
+*/
+
+
+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.
+  */
+  
+  const bool isPosix = ((wa & 0xF0000000) != 0);
+  
+  UInt32 posix = 0;
+  if (isPosix)
+  {
+    posix = wa >> 16;
+    wa &= (UInt32)0x3FFF;
+  }
+
+  for (unsigned i = 0; i < kNumWinAtrribFlags; i++)
+  {
+    UInt32 flag = (1 << i);
+    if ((wa & flag) != 0)
+    {
+      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;
+    }
+    */
+  }
+  
+  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 unsigned GetHex(unsigned v)
+{
+  return (v < 10) ? ('0' + v) : ('A' + (v - 10));
+}
+
+static inline void AddHexToString(AString &res, unsigned v)
+{
+  res += (char)GetHex(v >> 4);
+  res += (char)GetHex(v & 0xF);
+}
+
+/*
+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, UInt32 lim, UInt32 &sidSize)
+{
+  sidSize = 0;
+  if (lim < 8)
+  {
+    s += "ERROR";
+    return;
+  }
+  const UInt32 rev = p[0];
+  if (rev != 1)
+  {
+    s += "UNSUPPORTED";
+    return;
+  }
+  const UInt32 num = p[1];
+  if (8 + num * 4 > lim)
+  {
+    s += "ERROR";
+    return;
+  }
+  sidSize = 8 + num * 4;
+  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, UInt32 size, UInt32 pos)
+{
+  if (pos > size)
+  {
+    s += "ERROR";
+    return;
+  }
+  UInt32 sidSize = 0;
+  ParseSid(s, p + pos, size - pos, sidSize);
+}
+
+static void ParseAcl(AString &s, const Byte *p, UInt32 size, const char *strName, UInt32 flags, UInt32 offset)
+{
+  const UInt32 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 -= 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, UInt32 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(size);
+  // s += '\n';
+  // s += Data_To_Hex(data, size);
+}
+
+#ifdef _WIN32
+
+static bool CheckSid(const Byte *data, UInt32 size, UInt32 pos) throw()
+{
+  if (pos >= size)
+    return false;
+  size -= pos;
+  if (size < 8)
+    return false;
+  const UInt32 rev = data[pos];
+  if (rev != 1)
+    return false;
+  const UInt32 num = data[pos + 1];
+  return (8 + num * 4 <= size);
+}
+
+static bool CheckAcl(const Byte *p, UInt32 size, UInt32 flags, UInt32 offset) throw()
+{
+  const UInt32 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 UInt32 aclSize = Get16(p + 2);
+  return (aclSize <= size);
+}
+
+bool CheckNtSecure(const Byte *data, UInt32 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, UInt32 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 += " "; // 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 += ":";
+  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 += (char)GetHex((b >> 4) & 0xF);
+      s += (char)GetHex(b & 0xF);
+    }
+  }
+
+  return true;
+}
+
+#endif
diff --git a/CPP/7zip/UI/Common/PropIDUtils.h b/CPP/7zip/UI/Common/PropIDUtils.h
index e94e6d7..6df1e94 100644
--- a/CPP/7zip/UI/Common/PropIDUtils.h
+++ b/CPP/7zip/UI/Common/PropIDUtils.h
@@ -1,18 +1,18 @@
-// PropIDUtils.h

-

-#ifndef __PROPID_UTILS_H

-#define __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, UInt32 size, UString &s);

-void ConvertNtSecureToString(const Byte *data, UInt32 size, AString &s);

-bool CheckNtSecure(const Byte *data, UInt32 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, UInt32 size, UString &s);
+void ConvertNtSecureToString(const Byte *data, UInt32 size, AString &s);
+bool CheckNtSecure(const Byte *data, UInt32 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 31234ad..0462809 100644
--- a/CPP/7zip/UI/Common/Property.h
+++ b/CPP/7zip/UI/Common/Property.h
@@ -1,14 +1,14 @@
-// Property.h

-

-#ifndef __7Z_PROPERTY_H

-#define __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 3cd4d57..5e15d9c 100644
--- a/CPP/7zip/UI/Common/SetProperties.cpp
+++ b/CPP/7zip/UI/Common/SetProperties.cpp
@@ -1,80 +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;

-  UInt64 result = ConvertStringToUInt64(s, &end);

-  if (*end != 0 || s.IsEmpty())

-    prop = s;

-  else if (result <= (UInt32)0xFFFFFFFF)

-    prop = (UInt32)result;

-  else

-    prop = result;

-}

-

-HRESULT SetProperties(IUnknown *unknown, const CObjectVector<CProperty> &properties)

-{

-  if (properties.IsEmpty())

-    return S_OK;

-  CMyComPtr<ISetProperties> setProperties;

-  unknown->QueryInterface(IID_ISetProperties, (void **)&setProperties);

-  if (!setProperties)

-    return S_OK;

-

-  UStringVector realNames;

-  CPropVariant *values = new CPropVariant[properties.Size()];

-  try

-  {

-    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())

-        {

-          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[i] = propVariant;

-    }

-    CRecordVector<const wchar_t *> names;

-    for (i = 0; i < realNames.Size(); i++)

-      names.Add((const wchar_t *)realNames[i]);

-    

-    RINOK(setProperties->SetProperties(&names.Front(), values, names.Size()));

-  }

-  catch(...)

-  {

-    delete []values;

-    throw;

-  }

-  delete []values;

-  return S_OK;

-}

+// 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<CProperty> &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<const wchar_t *> names;
+    for (i = 0; i < realNames.Size(); i++)
+      names.Add((const wchar_t *)realNames[i]);
+    
+    return setProperties->SetProperties(&names.Front(), values.values, names.Size());
+  }
+}
diff --git a/CPP/7zip/UI/Common/SetProperties.h b/CPP/7zip/UI/Common/SetProperties.h
index 64c947c..0676c45 100644
--- a/CPP/7zip/UI/Common/SetProperties.h
+++ b/CPP/7zip/UI/Common/SetProperties.h
@@ -1,10 +1,10 @@
-// SetProperties.h

-

-#ifndef __SETPROPERTIES_H

-#define __SETPROPERTIES_H

-

-#include "Property.h"

-

-HRESULT SetProperties(IUnknown *unknown, const CObjectVector<CProperty> &properties);

-

-#endif

+// SetProperties.h
+
+#ifndef ZIP7_INC_SETPROPERTIES_H
+#define ZIP7_INC_SETPROPERTIES_H
+
+#include "Property.h"
+
+HRESULT SetProperties(IUnknown *unknown, const CObjectVector<CProperty> &properties);
+
+#endif
diff --git a/CPP/7zip/UI/Common/SortUtils.cpp b/CPP/7zip/UI/Common/SortUtils.cpp
index f73ece8..5f29249 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 82d5e4c..07aa24d 100644
--- a/CPP/7zip/UI/Common/SortUtils.h
+++ b/CPP/7zip/UI/Common/SortUtils.h
@@ -1,10 +1,10 @@
-// SortUtils.h

-

-#ifndef __SORT_UTLS_H

-#define __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 59d9ac1..035267c 100644
--- a/CPP/7zip/UI/Common/StdAfx.h
+++ b/CPP/7zip/UI/Common/StdAfx.h
@@ -1,8 +1,11 @@
-// StdAfx.h

-

-#ifndef __STDAFX_H

-#define __STDAFX_H

-

-#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 56bba9a..2f86838 100644
--- a/CPP/7zip/UI/Common/TempFiles.cpp
+++ b/CPP/7zip/UI/Common/TempFiles.cpp
@@ -1,19 +1,19 @@
-// 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())
+  {
+    NDir::DeleteFileAlways(Paths.Back());
+    Paths.DeleteBack();
+  }
+}
diff --git a/CPP/7zip/UI/Common/TempFiles.h b/CPP/7zip/UI/Common/TempFiles.h
index f62192d..dd4ac20 100644
--- a/CPP/7zip/UI/Common/TempFiles.h
+++ b/CPP/7zip/UI/Common/TempFiles.h
@@ -1,16 +1,16 @@
-// TempFiles.h

-

-#ifndef __TEMP_FILES_H

-#define __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;
+  ~CTempFiles() { Clear(); }
+};
+
+#endif
diff --git a/CPP/7zip/UI/Common/Update.cpp b/CPP/7zip/UI/Common/Update.cpp
index 2f1b365..27625ae 100644
--- a/CPP/7zip/UI/Common/Update.cpp
+++ b/CPP/7zip/UI/Common/Update.cpp
@@ -1,1704 +1,1857 @@
-// Update.cpp

-

-#include "StdAfx.h"

-

-#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 "../../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 kUpdateIsNotSupoorted_MultiVol =

-  "Updating for multivolume archives is not implemented";

-

-using namespace NWindows;

-using namespace NCOM;

-using namespace NFile;

-using namespace NDir;

-using namespace NName;

-

-static CFSTR const kTempFolderPrefix = FTEXT("7zE");

-

-

-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();

-}

-

-static bool DeleteEmptyFolderAndEmptySubFolders(const FString &path)

-{

-  NFind::CFileInfo fileInfo;

-  FString pathPrefix = path + FCHAR_PATH_SEPARATOR;

-  {

-    NFind::CEnumerator enumerator;

-    enumerator.SetDirPrefix(pathPrefix);

-    while (enumerator.Next(fileInfo))

-    {

-      if (fileInfo.IsDir())

-        if (!DeleteEmptyFolderAndEmptySubFolders(pathPrefix + fileInfo.Name))

-          return false;

-    }

-  }

-  /*

-  // we don't need clear read-only for folders

-  if (!MySetFileAttributes(path, 0))

-    return false;

-  */

-  return RemoveDir(path);

-}

-

-

-using namespace NUpdateArchive;

-

-class COutMultiVolStream:

-  public IOutStream,

-  public CMyUnknownImp

-{

-  unsigned _streamIndex; // required stream

-  UInt64 _offsetPos; // offset from start of _streamIndex index

-  UInt64 _absPos;

-  UInt64 _length;

-

-  struct CAltStreamInfo

-  {

-    COutFileStream *StreamSpec;

-    CMyComPtr<IOutStream> Stream;

-    FString Name;

-    UInt64 Pos;

-    UInt64 RealSize;

-  };

-  CObjectVector<CAltStreamInfo> Streams;

-public:

-  // CMyComPtr<IArchiveUpdateCallback2> VolumeCallback;

-  CRecordVector<UInt64> Sizes;

-  FString Prefix;

-  CTempFiles *TempFiles;

-

-  void Init()

-  {

-    _streamIndex = 0;

-    _offsetPos = 0;

-    _absPos = 0;

-    _length = 0;

-  }

-

-  bool SetMTime(const FILETIME *mTime);

-  HRESULT Close();

-

-  UInt64 GetSize() const { return _length; }

-

-  MY_UNKNOWN_IMP1(IOutStream)

-

-  STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);

-  STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);

-  STDMETHOD(SetSize)(UInt64 newSize);

-};

-

-// static NSynchronization::CCriticalSection g_TempPathsCS;

-

-HRESULT COutMultiVolStream::Close()

-{

-  HRESULT res = S_OK;

-  FOR_VECTOR (i, Streams)

-  {

-    COutFileStream *s = Streams[i].StreamSpec;

-    if (s)

-    {

-      HRESULT res2 = s->Close();

-      if (res2 != S_OK)

-        res = res2;

-    }

-  }

-  return res;

-}

-

-bool COutMultiVolStream::SetMTime(const FILETIME *mTime)

-{

-  bool res = true;

-  FOR_VECTOR (i, Streams)

-  {

-    COutFileStream *s = Streams[i].StreamSpec;

-    if (s)

-      if (!s->SetMTime(mTime))

-        res = false;

-  }

-  return res;

-}

-

-STDMETHODIMP COutMultiVolStream::Write(const void *data, UInt32 size, UInt32 *processedSize)

-{

-  if (processedSize)

-    *processedSize = 0;

-  while (size > 0)

-  {

-    if (_streamIndex >= Streams.Size())

-    {

-      CAltStreamInfo altStream;

-

-      FString name;

-      name.Add_UInt32(_streamIndex + 1);

-      while (name.Len() < 3)

-        name.InsertAtFront(FTEXT('0'));

-      name.Insert(0, Prefix);

-      altStream.StreamSpec = new COutFileStream;

-      altStream.Stream = altStream.StreamSpec;

-      if (!altStream.StreamSpec->Create(name, false))

-        return ::GetLastError();

-      {

-        // NSynchronization::CCriticalSectionLock lock(g_TempPathsCS);

-        TempFiles->Paths.Add(name);

-      }

-

-      altStream.Pos = 0;

-      altStream.RealSize = 0;

-      altStream.Name = name;

-      Streams.Add(altStream);

-      continue;

-    }

-    CAltStreamInfo &altStream = Streams[_streamIndex];

-

-    unsigned index = _streamIndex;

-    if (index >= Sizes.Size())

-      index = Sizes.Size() - 1;

-    UInt64 volSize = Sizes[index];

-

-    if (_offsetPos >= volSize)

-    {

-      _offsetPos -= volSize;

-      _streamIndex++;

-      continue;

-    }

-    if (_offsetPos != altStream.Pos)

-    {

-      // CMyComPtr<IOutStream> outStream;

-      // RINOK(altStream.Stream.QueryInterface(IID_IOutStream, &outStream));

-      RINOK(altStream.Stream->Seek(_offsetPos, STREAM_SEEK_SET, NULL));

-      altStream.Pos = _offsetPos;

-    }

-

-    UInt32 curSize = (UInt32)MyMin((UInt64)size, volSize - altStream.Pos);

-    UInt32 realProcessed;

-    RINOK(altStream.Stream->Write(data, curSize, &realProcessed));

-    data = (void *)((Byte *)data + realProcessed);

-    size -= realProcessed;

-    altStream.Pos += realProcessed;

-    _offsetPos += realProcessed;

-    _absPos += realProcessed;

-    if (_absPos > _length)

-      _length = _absPos;

-    if (_offsetPos > altStream.RealSize)

-      altStream.RealSize = _offsetPos;

-    if (processedSize)

-      *processedSize += realProcessed;

-    if (altStream.Pos == volSize)

-    {

-      _streamIndex++;

-      _offsetPos = 0;

-    }

-    if (realProcessed == 0 && curSize != 0)

-      return E_FAIL;

-    break;

-  }

-  return S_OK;

-}

-

-STDMETHODIMP COutMultiVolStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)

-{

-  if (seekOrigin >= 3)

-    return STG_E_INVALIDFUNCTION;

-  switch (seekOrigin)

-  {

-    case STREAM_SEEK_SET: _absPos = offset; break;

-    case STREAM_SEEK_CUR: _absPos += offset; break;

-    case STREAM_SEEK_END: _absPos = _length + offset; break;

-  }

-  _offsetPos = _absPos;

-  if (newPosition)

-    *newPosition = _absPos;

-  _streamIndex = 0;

-  return S_OK;

-}

-

-STDMETHODIMP COutMultiVolStream::SetSize(UInt64 newSize)

-{

-  unsigned i = 0;

-  while (i < Streams.Size())

-  {

-    CAltStreamInfo &altStream = Streams[i++];

-    if ((UInt64)newSize < altStream.RealSize)

-    {

-      RINOK(altStream.Stream->SetSize(newSize));

-      altStream.RealSize = newSize;

-      break;

-    }

-    newSize -= altStream.RealSize;

-  }

-  while (i < Streams.Size())

-  {

-    {

-      CAltStreamInfo &altStream = Streams.Back();

-      altStream.Stream.Release();

-      DeleteFileAlways(altStream.Name);

-    }

-    Streams.DeleteBack();

-  }

-  _offsetPos = _absPos;

-  _streamIndex = 0;

-  _length = newSize;

-  return S_OK;

-}

-

-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(dotPos + 1);

-      if (BaseExtension.IsEqualTo_NoCase(ext))

-      {

-        BaseExtension = ext;

-        Name.DeleteFrom(dotPos);

-        return;

-      }

-    }

-  }

-

-  BaseExtension.Empty();

-}

-

-UString CArchivePath::GetFinalPath() const

-{

-  UString path = GetPathWithoutExt();

-  if (!BaseExtension.IsEmpty())

-  {

-    path += '.';

-    path += BaseExtension;

-  }

-  return path;

-}

-

-UString CArchivePath::GetFinalVolPath() const

-{

-  UString path = GetPathWithoutExt();

-  // if BaseExtension is empty, we must ignore VolExtension also.

-  if (!BaseExtension.IsEmpty())

-  {

-    path += '.';

-    path += VolExtension;

-  }

-  return path;

-}

-

-FString CArchivePath::GetTempPath() const

-{

-  FString path = TempPrefix;

-  path += us2fs(Name);

-  if (!BaseExtension.IsEmpty())

-  {

-    path += '.';

-    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<COpenType> &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[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: public IUpdateProduceCallback

-{

-  const CObjectVector<CArcItem> *_arcItems;

-  IUpdateCallbackUI *_callback;

-  CDirItemsStat *_stat;

-  

-  CUpdateProduceCallbackImp(

-      const CObjectVector<CArcItem> *a,

-      CDirItemsStat *stat,

-      IUpdateCallbackUI *callback):

-    _arcItems(a),

-    _stat(stat),

-    _callback(callback) {}

-  

-  virtual HRESULT ShowDeleteFile(unsigned arcIndex);

-};

-

-

-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<CArcItem> &arcItems,

-    Byte *processedItemsStatuses,

-    const CDirItems &dirItems,

-    const CDirItem *parentDirItem,

-    CTempFiles &tempFiles,

-    CUpdateErrorInfo &errorInfo,

-    IUpdateCallbackUI *callback,

-    CFinishArchiveStat &st)

-{

-  CMyComPtr<IOutArchive> outArchive;

-  int formatIndex = options.MethodMode.Type.FormatIndex;

-  

-  if (arc)

-  {

-    formatIndex = arc->FormatIndex;

-    if (formatIndex < 0)

-      return E_NOTIMPL;

-    CMyComPtr<IInArchive> archive2 = arc->Archive;

-    HRESULT result = archive2.QueryInterface(IID_IOutArchive, &outArchive);

-    if (result != S_OK)

-      throw kUpdateIsNotSupoorted;

-  }

-  else

-  {

-    RINOK(codecs->CreateOutArchive(formatIndex, outArchive));

-

-    #ifdef EXTERNAL_CODECS

-    {

-      CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo;

-      outArchive.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo);

-      if (setCompressCodecsInfo)

-      {

-        RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(codecs));

-      }

-    }

-    #endif

-  }

-  

-  if (outArchive == 0)

-    throw kUpdateIsNotSupoorted;

-  

-  NFileTimeType::EEnum fileTimeType;

-  {

-    UInt32 value;

-    RINOK(outArchive->GetFileTimeType(&value));

-    

-    switch (value)

-    {

-      case NFileTimeType::kWindows:

-      case NFileTimeType::kUnix:

-      case NFileTimeType::kDOS:

-        fileTimeType = (NFileTimeType::EEnum)value;

-        break;

-      default:

-        return E_FAIL;

-    }

-  }

-

-  {

-    const CArcInfoEx &arcInfo = codecs->Formats[formatIndex];

-    if (options.AltStreams.Val && !arcInfo.Flags_AltStreams())

-      return E_NOTIMPL;

-    if (options.NtSecurity.Val && !arcInfo.Flags_NtSecure())

-      return E_NOTIMPL;

-  }

-

-  CRecordVector<CUpdatePair2> 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(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 += ':';

-                dest += ai.Name.Ptr(colonPos + 1);

-                break;

-              }

-            }

-          }

-          #endif

-        }

-      }

-      

-      CUpdatePair2 up2;

-      up2.SetAs_NoChangeArcItem(ai.IndexInServer);

-      if (needRename)

-      {

-        up2.NewProps = true;

-        RINOK(arc->IsItemAnti(i, up2.IsAnti));

-        up2.NewNameIndex = newNames.Add(dest);

-      }

-      updatePairs2.Add(up2);

-    }

-  }

-  else

-  {

-    CRecordVector<CUpdatePair> 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[up.DirIndex];

-          if (di.IsDir())

-          {

-            if (up.IsAnti)

-              stat.Anti_NumDirs++;

-            else

-              stat.NumDirs++;

-          }

-          else if (di.IsAltStream)

-          {

-            if (up.IsAnti)

-              stat.Anti_NumAltStreams++;

-            else

-            {

-              stat.NumAltStreams++;

-              stat.AltStreamsSize += di.Size;

-            }

-          }

-          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[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<IArchiveUpdateCallback> updateCallback(updateCallbackSpec);

-  

-  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->Arc = arc;

-  updateCallbackSpec->ArcItems = &arcItems;

-  updateCallbackSpec->UpdatePairs = &updatePairs2;

-

-  updateCallbackSpec->ProcessedItemsStatuses = processedItemsStatuses;

-

-  if (options.RenamePairs.Size() != 0)

-    updateCallbackSpec->NewNames = &newNames;

-

-  CMyComPtr<IOutStream> outSeekStream;

-  CMyComPtr<ISequentialOutStream> outStream;

-

-  if (!options.StdOutMode)

-  {

-    FString dirPrefix;

-    if (!GetOnlyDirPrefix(us2fs(archivePath.GetFinalPath()), dirPrefix))

-      throw 1417161;

-    CreateComplexDir(dirPrefix);

-  }

-

-  COutFileStream *outStreamSpec = NULL;

-  CStdOutFileStream *stdOutFileStreamSpec = NULL;

-  COutMultiVolStream *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(realPath, false))

-        {

-          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 COutMultiVolStream;

-    outSeekStream = volStreamSpec;

-    outStream = outSeekStream;

-    volStreamSpec->Sizes = options.VolumesSizes;

-    volStreamSpec->Prefix = us2fs(archivePath.GetFinalVolPath());

-    volStreamSpec->Prefix += '.';

-    volStreamSpec->TempFiles = &tempFiles;

-    volStreamSpec->Init();

-

-    /*

-    updateCallbackSpec->VolumesSizes = volumesSizes;

-    updateCallbackSpec->VolName = archivePath.Prefix + archivePath.Name;

-    if (!archivePath.VolExtension.IsEmpty())

-      updateCallbackSpec->VolExt = UString('.') + archivePath.VolExtension;

-    */

-  }

-

-  RINOK(SetProperties(outArchive, options.MethodMode.Properties));

-

-  if (options.SfxMode)

-  {

-    CInFileStream *sfxStreamSpec = new CInFileStream;

-    CMyComPtr<IInStream> sfxStream(sfxStreamSpec);

-    if (!sfxStreamSpec->Open(options.SfxModule))

-      return errorInfo.SetFromLastError("cannot open SFX module", options.SfxModule);

-

-    CMyComPtr<ISequentialOutStream> sfxOutStream;

-    COutFileStream *outStreamSpec2 = NULL;

-    if (options.VolumesSizes.Size() == 0)

-      sfxOutStream = outStream;

-    else

-    {

-      outStreamSpec2 = new COutFileStream;

-      sfxOutStream = outStreamSpec2;

-      FString realPath = us2fs(archivePath.GetFinalPath());

-      if (!outStreamSpec2->Create(realPath, false))

-        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<ISequentialOutStream> tailStream;

-

-  if (options.SfxMode || !arc || arc->ArcStreamOffset == 0)

-    tailStream = outStream;

-  else

-  {

-    // Int64 globalOffset = arc->GetGlobalOffset();

-    RINOK(arc->InStream->Seek(0, STREAM_SEEK_SET, NULL));

-    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();

-    }

-  }

-

-

-  HRESULT result = outArchive->UpdateItems(tailStream, updatePairs2.Size(), updateCallback);

-  // callback->Finalize();

-  RINOK(result);

-

-  if (!updateCallbackSpec->AreAllFilesClosed())

-  {

-    errorInfo.Message = "There are unclosed input file:";

-    errorInfo.FileNames = updateCallbackSpec->_openFiles_Paths;

-    return E_FAIL;

-  }

-

-  if (options.SetArcMTime)

-  {

-    FILETIME ft;

-    ft.dwLowDateTime = 0;

-    ft.dwHighDateTime = 0;

-    FOR_VECTOR (i, updatePairs2)

-    {

-      CUpdatePair2 &pair2 = updatePairs2[i];

-      const FILETIME *ft2 = NULL;

-      if (pair2.NewProps && pair2.DirIndex >= 0)

-        ft2 = &dirItems.Items[pair2.DirIndex].MTime;

-      else if (pair2.UseArcProps && pair2.ArcIndex >= 0)

-        ft2 = &arcItems[pair2.ArcIndex].MTime;

-      if (ft2)

-      {

-        if (::CompareFileTime(&ft, ft2) < 0)

-          ft = *ft2;

-      }

-    }

-    if (ft.dwLowDateTime != 0 || ft.dwHighDateTime != 0)

-    {

-      if (outStreamSpec)

-        outStreamSpec->SetMTime(&ft);

-      else if (volStreamSpec)

-        volStreamSpec->SetMTime(&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->Close();

-  return result;

-}

-

-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)

-  {

-    bool include;

-    if (CensorNode_CheckPath2(censor.Pairs[i].Head, item, include))

-    {

-      if (!include)

-        return false;

-      finded = true;

-    }

-  }

-  return finded;

-}

-

-static HRESULT EnumerateInArchiveItems(

-    // bool storeStreamsMode,

-    const NWildcard::CCensor &censor,

-    const CArc &arc,

-    CObjectVector<CArcItem> &arcItems)

-{

-  arcItems.Clear();

-  UInt32 numItems;

-  IInArchive *archive = arc.Archive;

-  RINOK(archive->GetNumberOfItems(&numItems));

-  arcItems.ClearAndReserve(numItems);

-

-  CReadArcItem item;

-

-  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;

-    */

-    ai.Censored = Censor_CheckPath(censor, item);

-

-    RINOK(arc.GetItemMTime(i, ai.MTime, ai.MTimeDefined));

-    RINOK(arc.GetItemSize(i, ai.Size, ai.SizeDefined));

-

-    {

-      CPropVariant prop;

-      RINOK(archive->GetProperty(i, kpidTimeType, &prop));

-      if (prop.vt == VT_UI4)

-      {

-        ai.TimeType = (int)(NFileTimeType::EEnum)prop.ulVal;

-        switch (ai.TimeType)

-        {

-          case NFileTimeType::kWindows:

-          case NFileTimeType::kUnix:

-          case NFileTimeType::kDOS:

-            break;

-          default:

-            return E_FAIL;

-        }

-      }

-    }

-

-    ai.IndexInServer = i;

-    arcItems.AddInReserved(ai);

-  }

-  return S_OK;

-}

-

-#if defined(_WIN32) && !defined(UNDER_CE)

-

-#include <mapi.h>

-

-#endif

-

-HRESULT UpdateArchive(

-    CCodecs *codecs,

-    const CObjectVector<COpenType> &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 (int 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(fullName))

-      {

-        options.SfxModule = fullName;

-        found = true;

-      }

-    }

-    if (!found)

-    {

-      if (!NFind::DoesFileExist(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 += '.';

-    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(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())

-        throw "there is no such archive";

-      if (fi.IsDevice)

-        return E_NOTIMPL;

-

-      if (!options.StdOutMode && options.UpdateArchiveItself)

-        if (fi.IsReadOnly())

-        {

-          errorInfo.SystemError = ERROR_ACCESS_DENIED;

-          errorInfo.Message = "The file is read-only";

-          errorInfo.FileNames.Add(us2fs(arcPath));

-          return errorInfo.Get_HRESULT_Error();

-        }

-

-      if (options.VolumesSizes.Size() > 0)

-      {

-        errorInfo.FileNames.Add(us2fs(arcPath));

-        errorInfo.SystemError = (DWORD)E_NOTIMPL;

-        errorInfo.Message = kUpdateIsNotSupoorted_MultiVol;

-        return E_NOTIMPL;

-      }

-      CObjectVector<COpenType> 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 _SFX

-      op.props = &options.MethodMode.Properties;

-      #endif

-      op.codecs = codecs;

-      op.types = &types2;

-      op.excludedFormats = &excl;

-      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 = kUpdateIsNotSupoorted_MultiVol;

-        return E_NOTIMPL;

-      }

-      

-      CArc &arc = arcLink.Arcs.Back();

-      arc.MTimeDefined = !fi.IsDevice;

-      arc.MTime = 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.Name = options.StdInFileName;

-    di.Size = (UInt64)(Int64)-1;

-    di.Attrib = 0;

-    NTime::GetCurUtcFileTime(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;

-

-      HRESULT res = EnumerateItems(censor,

-          options.PathMode,

-          options.AddPathPrefix,

-          dirItems);

-

-      if (res != S_OK)

-      {

-        if (res != E_ABORT)

-          errorInfo.Message = "Scanning error";

-        return res;

-      }

-      

-      RINOK(callback->FinishScanning(dirItems.Stat));

-

-      if (censor.Pairs.Size() == 1)

-      {

-        NFind::CFileInfo fi;

-        FString prefix = us2fs(censor.Pairs[0].Prefix);

-        prefix += '.';

-        // UString prefix = censor.Pairs[0].Prefix;

-        /*

-        if (prefix.Back() == WCHAR_PATH_SEPARATOR)

-        {

-          prefix.DeleteBack();

-        }

-        */

-        if (fi.Find(prefix))

-          if (fi.IsDir())

-          {

-            parentDirItem.Size = fi.Size;

-            parentDirItem.CTime = fi.CTime;

-            parentDirItem.ATime = fi.ATime;

-            parentDirItem.MTime = fi.MTime;

-            parentDirItem.Attrib = fi.Attrib;

-            parentDirItem_Ptr = &parentDirItem;

-

-            int secureIndex = -1;

-            #if defined(_WIN32) && !defined(UNDER_CE)

-            if (options.NtSecurity.Val)

-              dirItems.AddSecurityItem(prefix, secureIndex);

-            #endif

-            parentDirItem.SecureIndex = secureIndex;

-

-            parentDirItem_Ptr = &parentDirItem;

-          }

-      }

-    }

-  }

-

-  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 += 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<CArcItem> 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)

-  {

-    unsigned num = dirItems.Items.Size();

-    processedItems.Alloc(num);

-    for (unsigned i = 0; i < num; i++)

-      processedItems[i] = 0;

-  }

-

-  /*

-  #ifndef _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,

-        errorInfo, callback, st));

-

-    RINOK(callback->FinishArchive(st));

-  }

-

-

-  if (thereIsInArchive)

-  {

-    RINOK(arcLink.Close());

-    arcLink.Release();

-  }

-

-  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.SetFromLastError("cannot move the file", 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)

-  

-  if (options.EMailMode)

-  {

-    NDLL::CLibrary mapiLib;

-    if (!mapiLib.Load(FTEXT("Mapi32.dll")))

-    {

-      errorInfo.SetFromLastError("cannot load Mapi32.dll");

-      return errorInfo.Get_HRESULT_Error();

-    }

-

-    /*

-    LPMAPISENDDOCUMENTS fnSend = (LPMAPISENDDOCUMENTS)mapiLib.GetProc("MAPISendDocuments");

-    if (fnSend == 0)

-    {

-      errorInfo.SetFromLastError)("7-Zip cannot find MAPISendDocuments function");

-      return errorInfo.Get_HRESULT_Error();

-    }

-    */

-    

-    LPMAPISENDMAIL sendMail = (LPMAPISENDMAIL)mapiLib.GetProc("MAPISendMail");

-    if (sendMail == 0)

-    {

-      errorInfo.SetFromLastError("7-Zip cannot find MAPISendMail function");

-      return errorInfo.Get_HRESULT_Error();;

-    }

-

-    FStringVector fullPaths;

-    unsigned i;

-    

-    for (i = 0; i < options.Commands.Size(); i++)

-    {

-      CArchivePath &ap = options.Commands[i].ArchivePath;

-      FString finalPath = us2fs(ap.GetFinalPath());

-      FString arcPath2;

-      if (!MyGetFullPathName(finalPath, arcPath2))

-        return errorInfo.SetFromLastError("GetFullPathName error", finalPath);

-      fullPaths.Add(arcPath2);

-    }

-

-    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<MapiFileDesc> 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 = (char *)(const char *)paths[i];

-      f.lpszFileName = (char *)(const char *)names[i];

-    }

-

-    {

-      MapiMessage m;

-      memset(&m, 0, sizeof(m));

-      m.nFileCount = files.Size();

-      m.lpFiles = &files.Front();

-      

-      const AString addr (GetAnsiString(options.EMailAddress));

-      MapiRecipDesc rec;

-      if (!addr.IsEmpty())

-      {

-        memset(&rec, 0, sizeof(rec));

-        rec.ulRecipClass = MAPI_TO;

-        rec.lpszAddress = (char *)(const char *)addr;

-        m.nRecipCount = 1;

-        m.lpRecips = &rec;

-      }

-      

-      sendMail((LHANDLE)0, 0, &m, MAPI_DIALOG, 0);

-    }

-  }

-  

-  #endif

-

-  if (options.DeleteAfterCompressing)

-  {

-    CRecordVector<CDirPathSortPair> 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

-      {

-        if (processedItems[i] != 0 || dirItem.Size == 0)

-        {

-          NFind::CFileInfo fileInfo;

-          if (fileInfo.Find(phyPath))

-          {

-            // maybe we must exclude also files with archive name: "a a.7z * -sdel"

-            if (fileInfo.Size == dirItem.Size

-                && CompareFileTime(&fileInfo.MTime, &dirItem.MTime) == 0

-                && CompareFileTime(&fileInfo.CTime, &dirItem.CTime) == 0)

-            {

-              RINOK(callback->DeletingAfterArchiving(phyPath, false));

-              DeleteFileAlways(phyPath);

-            }

-          }

-        }

-        else

-        {

-          // file was skipped

-          /*

-          errorInfo.SystemError = 0;

-          errorInfo.Message = "file was not processed";

-          errorInfo.FileName = 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  <stdio.h>
+
+#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<IOutStream> Ref;
+};
+
+struct CMultiOutStream_Bunch
+{
+  CObjectVector<CMultiOutStream_Rec> 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<COpenType> &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<CArcItem> *_arcItems;
+  CDirItemsStat *_stat;
+  IUpdateCallbackUI *_callback;
+  
+  CUpdateProduceCallbackImp(
+      const CObjectVector<CArcItem> *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<CArcItem> &arcItems,
+    Byte *processedItemsStatuses,
+    const CDirItems &dirItems,
+    const CDirItem *parentDirItem,
+    CTempFiles &tempFiles,
+    CMultiOutStream_Bunch &multiStreams,
+    CUpdateErrorInfo &errorInfo,
+    IUpdateCallbackUI *callback,
+    CFinishArchiveStat &st)
+{
+  CMyComPtr<IOutArchive> outArchive;
+  int formatIndex = options.MethodMode.Type.FormatIndex;
+  
+  if (arc)
+  {
+    formatIndex = arc->FormatIndex;
+    if (formatIndex < 0)
+      return E_NOTIMPL;
+    CMyComPtr<IInArchive> 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<ISetCompressCodecsInfo> 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<CUpdatePair2> 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 += ':';
+                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<CUpdatePair> 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<IArchiveUpdateCallback> 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<IOutStream> outSeekStream;
+  CMyComPtr<ISequentialOutStream> 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(realPath, false))
+        {
+          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<IInStream> sfxStream(sfxStreamSpec);
+    if (!sfxStreamSpec->Open(options.SfxModule))
+      return errorInfo.SetFromLastError("cannot open SFX module", options.SfxModule);
+
+    CMyComPtr<ISequentialOutStream> 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(realPath, false))
+        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<ISequentialOutStream> 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 file:";
+    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<CArcItem> &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 <mapi.h>
+#else
+#include <MAPI.h>
+#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<COpenType> &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<COpenType> 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 = &excl;
+      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.Name = options.StdInFileName;
+    di.Size = (UInt64)(Int64)-1;
+    di.SetAsFile();
+    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<CArcItem> 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.SetFromLastError("cannot move the file", 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)
+  
+  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<Z7_WIN_MapiFileDescW> 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.Front();
+      
+      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<MapiFileDesc> 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.Front();
+      
+      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<CDirPathSortPair> 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 45b02d7..a9459ff 100644
--- a/CPP/7zip/UI/Common/Update.h
+++ b/CPP/7zip/UI/Common/Update.h
@@ -1,200 +1,218 @@
-// Update.h

-

-#ifndef __COMMON_UPDATE_H

-#define __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<CProperty> 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

-{

-  CCompressionMethodMode MethodMode;

-

-  CObjectVector<CUpdateArchiveCommand> Commands;

-  bool UpdateArchiveItself;

-  CArchivePath ArchivePath;

-  EArcNameMode ArcNameMode;

-

-  bool SfxMode;

-  FString SfxModule;

-  

-  bool OpenShareForWrite;

-  bool StopAfterOpenError;

-

-  bool StdInMode;

-  UString StdInFileName;

-  bool StdOutMode;

-  

-  bool EMailMode;

-  bool EMailRemoveAfter;

-  UString EMailAddress;

-

-  FString WorkingDir;

-  NWildcard::ECensorPathMode PathMode;

-  UString AddPathPrefix;

-

-  CBoolPair NtSecurity;

-  CBoolPair AltStreams;

-  CBoolPair HardLinks;

-  CBoolPair SymLinks;

-

-  bool DeleteAfterCompressing;

-

-  bool SetArcMTime;

-

-  CObjectVector<CRenamePair> RenamePairs;

-

-  bool InitFormatIndex(const CCodecs *codecs, const CObjectVector<COpenType> &types, const UString &arcPath);

-  bool SetArcPath(const CCodecs *codecs, const UString &arcPath);

-

-  CUpdateOptions():

-    UpdateArchiveItself(true),

-    SfxMode(false),

-    StdInMode(false),

-    StdOutMode(false),

-    EMailMode(false),

-    EMailRemoveAfter(false),

-    OpenShareForWrite(false),

-    StopAfterOpenError(false),

-    ArcNameMode(k_ArcNameMode_Smart),

-    PathMode(NWildcard::k_RelatPath),

-    

-    DeleteAfterCompressing(false),

-    SetArcMTime(false)

-

-      {};

-

-  void SetActionCommand_Add()

-  {

-    Commands.Clear();

-    CUpdateArchiveCommand c;

-    c.ActionSet = NUpdateArchive::k_ActionSet_Add;

-    Commands.Add(c);

-  }

-

-  CRecordVector<UInt64> VolumesSizes;

-};

-

-struct CUpdateErrorInfo

-{

-  DWORD SystemError;

-  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);

-

-  CUpdateErrorInfo(): SystemError(0) {};

-};

-

-struct CFinishArchiveStat

-{

-  UInt64 OutArcFileSize;

-

-  CFinishArchiveStat(): OutArcFileSize(0) {}

-};

-

-#define INTERFACE_IUpdateCallbackUI2(x) \

-  INTERFACE_IUpdateCallbackUI(x) \

-  INTERFACE_IDirItemsCallback(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; \

-

-struct IUpdateCallbackUI2: public IUpdateCallbackUI, public IDirItemsCallback

-{

-  INTERFACE_IUpdateCallbackUI2(=0)

-};

-

-HRESULT UpdateArchive(

-    CCodecs *codecs,

-    const CObjectVector<COpenType> &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"
+
+#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<CProperty> 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<CUpdateArchiveCommand> Commands;
+  CArchivePath ArchivePath;
+
+  FString SfxModule;
+  UString StdInFileName;
+  UString EMailAddress;
+  FString WorkingDir;
+  // UString AddPathPrefix;
+
+  CObjectVector<CRenamePair> RenamePairs;
+  CRecordVector<UInt64> VolumesSizes;
+
+  bool InitFormatIndex(const CCodecs *codecs, const CObjectVector<COpenType> &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<COpenType> &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 ba138d2..a80db72 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 8d6002f..6a3565e 100644
--- a/CPP/7zip/UI/Common/UpdateAction.h
+++ b/CPP/7zip/UI/Common/UpdateAction.h
@@ -1,66 +1,66 @@
-// UpdateAction.h

-

-#ifndef __UPDATE_ACTION_H

-#define __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 9c165fe..5e2860d 100644
--- a/CPP/7zip/UI/Common/UpdateCallback.cpp
+++ b/CPP/7zip/UI/Common/UpdateCallback.cpp
@@ -1,771 +1,1026 @@
-// UpdateCallback.cpp

-

-#include "StdAfx.h"

-

-#ifndef _7ZIP_ST

-#include "../../../Windows/Synchronization.h"

-#endif

-

-#include "../../../Common/ComTry.h"

-#include "../../../Common/IntToString.h"

-#include "../../../Common/StringConvert.h"

-#include "../../../Common/Wildcard.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 _USE_SECURITY_CODE

-#include "../../../Windows/SecurityUtils.h"

-#endif

-

-using namespace NWindows;

-using namespace NFile;

-

-#ifndef _7ZIP_ST

-static NSynchronization::CCriticalSection g_CriticalSection;

-#define MT_LOCK NSynchronization::CCriticalSectionLock lock(g_CriticalSection);

-#else

-#define MT_LOCK

-#endif

-

-

-#ifdef _USE_SECURITY_CODE

-bool InitLocalPrivileges();

-#endif

-

-CArchiveUpdateCallback::CArchiveUpdateCallback():

-    _hardIndex_From((UInt32)(Int32)-1),

-    

-    Callback(NULL),

-  

-    DirItems(NULL),

-    ParentDirItem(NULL),

-    

-    Arc(NULL),

-    ArcItems(NULL),

-    UpdatePairs(NULL),

-    NewNames(NULL),

-    CommentIndex(-1),

-    Comment(NULL),

-    

-    ShareForWrite(false),

-    StopAfterOpenError(false),

-    StdInMode(false),

-    

-    KeepOriginalItemNames(false),

-    StoreNtSecurity(false),

-    StoreHardLinks(false),

-    StoreSymLinks(false),

-    

-    ProcessedItemsStatuses(NULL)

-{

-  #ifdef _USE_SECURITY_CODE

-  _saclEnabled = InitLocalPrivileges();

-  #endif

-}

-

-

-STDMETHODIMP CArchiveUpdateCallback::SetTotal(UInt64 size)

-{

-  COM_TRY_BEGIN

-  return Callback->SetTotal(size);

-  COM_TRY_END

-}

-

-STDMETHODIMP CArchiveUpdateCallback::SetCompleted(const UInt64 *completeValue)

-{

-  COM_TRY_BEGIN

-  return Callback->SetCompleted(completeValue);

-  COM_TRY_END

-}

-

-STDMETHODIMP 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}

-};

-

-STDMETHODIMP CArchiveUpdateCallback::EnumProperties(IEnumSTATPROPSTG **)

-{

-  return CStatPropEnumerator::CreateEnumerator(kProps, ARRAY_SIZE(kProps), enumerator);

-}

-*/

-

-STDMETHODIMP 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 == 0) ? up.ArcIndex : (*ArcItems)[up.ArcIndex].IndexInServer;

-  }

-  return S_OK;

-  COM_TRY_END

-}

-

-STDMETHODIMP CArchiveUpdateCallback::GetRootProp(PROPID propID, PROPVARIANT *value)

-{

-  NCOM::CPropVariant prop;

-  switch (propID)

-  {

-    case kpidIsDir:  prop = true; break;

-    case kpidAttrib: if (ParentDirItem) prop = ParentDirItem->Attrib; break;

-    case kpidCTime:  if (ParentDirItem) prop = ParentDirItem->CTime; break;

-    case kpidATime:  if (ParentDirItem) prop = ParentDirItem->ATime; break;

-    case kpidMTime:  if (ParentDirItem) prop = ParentDirItem->MTime; break;

-  }

-  prop.Detach(value);

-  return S_OK;

-}

-

-STDMETHODIMP CArchiveUpdateCallback::GetParent(UInt32 /* index */, UInt32 *parent, UInt32 *parentType)

-{

-  *parentType = NParentType::kDir;

-  *parent = (UInt32)(Int32)-1;

-  return S_OK;

-}

-

-STDMETHODIMP CArchiveUpdateCallback::GetNumRawProps(UInt32 *numProps)

-{

-  *numProps = 0;

-  if (StoreNtSecurity)

-    *numProps = 1;

-  return S_OK;

-}

-

-STDMETHODIMP CArchiveUpdateCallback::GetRawPropInfo(UInt32 /* index */, BSTR *name, PROPID *propID)

-{

-  *name = NULL;

-  *propID = kpidNtSecure;

-  return S_OK;

-}

-

-STDMETHODIMP CArchiveUpdateCallback::GetRootRawProp(PROPID

-    #ifdef _USE_SECURITY_CODE

-    propID

-    #endif

-    , const void **data, UInt32 *dataSize, UInt32 *propType)

-{

-  *data = 0;

-  *dataSize = 0;

-  *propType = 0;

-  if (!StoreNtSecurity)

-    return S_OK;

-  #ifdef _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[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;

-}

-

-//    #ifdef _USE_SECURITY_CODE

-//    #endif

-

-STDMETHODIMP CArchiveUpdateCallback::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType)

-{

-  *data = 0;

-  *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)[up.ArcIndex].IndexInServer : up.ArcIndex,

-          propID, data, dataSize, propType);

-    {

-      /*

-      if (!up.NewData)

-        return E_FAIL;

-      */

-      if (up.IsAnti)

-        return S_OK;

-      

-      #ifndef UNDER_CE

-      const CDirItem &di = DirItems->Items[up.DirIndex];

-      #endif

-

-      #ifdef _USE_SECURITY_CODE

-      if (propID == kpidNtSecure)

-      {

-        if (!StoreNtSecurity)

-          return S_OK;

-        if (di.SecureIndex < 0)

-          return S_OK;

-        const CByteBuffer &buf = DirItems->SecureBlocks.Bufs[di.SecureIndex];

-        *data = buf;

-        *dataSize = (UInt32)buf.Size();

-        *propType = NPropDataType::kRaw;

-      }

-      else

-      #endif

-      {

-        // propID == kpidNtReparse

-        if (!StoreSymLinks)

-          return S_OK;

-        #ifndef UNDER_CE

-        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;

-}

-

-#ifndef 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

-

-STDMETHODIMP 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 (up.DirIndex >= 0)

-      {

-        #ifndef UNDER_CE

-        const CDirItem &di = DirItems->Items[up.DirIndex];

-        // if (di.IsDir())

-        {

-          CReparseAttr attr;

-          DWORD errorCode = 0;

-          if (attr.Parse(di.ReparseData, di.ReparseData.Size(), errorCode))

-          {

-            UString simpleName = attr.GetPath();

-            if (attr.IsRelative())

-              prop = simpleName;

-            else

-            {

-              const FString phyPath = DirItems->GetPhyPath(up.DirIndex);

-              FString fullPath;

-              if (NDir::MyGetFullPathName(phyPath, fullPath))

-              {

-                prop = GetRelativePath(simpleName, fs2us(fullPath));

-              }

-            }

-            prop.Detach(value);

-            return S_OK;

-          }

-        }

-        #endif

-      }

-    }

-    else if (propID == kpidHardLink)

-    {

-      if (index == _hardIndex_From)

-      {

-        const CKeyKeyValPair &pair = _map[_hardIndex_To];

-        const CUpdatePair2 &up2 = (*UpdatePairs)[pair.Value];

-        prop = DirItems->GetLogPath(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;

-    }

-  }

-  else if (propID == kpidPath && up.NewNameIndex >= 0)

-    prop = (*NewNames)[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)[up.ArcIndex].IndexInServer : up.ArcIndex, propID, value);

-  else if (up.ExistOnDisk())

-  {

-    const CDirItem &di = DirItems->Items[up.DirIndex];

-    switch (propID)

-    {

-      case kpidPath:  prop = DirItems->GetLogPath(up.DirIndex); break;

-      case kpidIsDir:  prop = di.IsDir(); break;

-      case kpidSize:  prop = di.IsDir() ? (UInt64)0 : di.Size; break;

-      case kpidAttrib:  prop = di.Attrib; break;

-      case kpidCTime:  prop = di.CTime; break;

-      case kpidATime:  prop = di.ATime; break;

-      case kpidMTime:  prop = di.MTime; break;

-      case kpidIsAltStream:  prop = di.IsAltStream; break;

-      #if defined(_WIN32) && !defined(UNDER_CE)

-      // case kpidShortName:  prop = di.ShortName; break;

-      #endif

-    }

-  }

-  prop.Detach(value);

-  return S_OK;

-  COM_TRY_END

-}

-

-#ifndef _7ZIP_ST

-static NSynchronization::CCriticalSection CS;

-#endif

-

-STDMETHODIMP 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)[up.ArcIndex].Name;

-    else if (up.DirIndex >= 0)

-      name = DirItems->GetLogPath(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<ISequentialInStream> inStreamLoc = inStreamSpec;

-      inStreamSpec->Init(NULL, 0);

-      *inStream = inStreamLoc.Detach();

-    }

-    return S_OK;

-  }

-  

-  RINOK(Callback->GetStream(DirItems->GetLogPath(up.DirIndex), isDir, false, mode));

- 

-  if (isDir)

-    return S_OK;

-

-  if (StdInMode)

-  {

-    if (mode != NUpdateNotifyOp::kAdd &&

-        mode != NUpdateNotifyOp::kUpdate)

-      return S_OK;

-

-    CStdInFileStream *inStreamSpec = new CStdInFileStream;

-    CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec);

-    *inStream = inStreamLoc.Detach();

-  }

-  else

-  {

-    CInFileStream *inStreamSpec = new CInFileStream;

-    CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec);

-

-    inStreamSpec->SupportHardLinks = StoreHardLinks;

-    inStreamSpec->Callback = this;

-    inStreamSpec->CallbackRef = index;

-

-    const FString path = DirItems->GetPhyPath(up.DirIndex);

-    _openFiles_Indexes.Add(index);

-    _openFiles_Paths.Add(path);

-

-    #if defined(_WIN32) && !defined(UNDER_CE)

-    if (DirItems->Items[up.DirIndex].AreReparseData())

-    {

-      if (!inStreamSpec->File.OpenReparse(path))

-      {

-        return Callback->OpenFileError(path, ::GetLastError());

-      }

-    }

-    else

-    #endif

-    if (!inStreamSpec->OpenShared(path, ShareForWrite))

-    {

-      DWORD error = ::GetLastError();

-      HRESULT hres = Callback->OpenFileError(path, error);

-      if (StopAfterOpenError)

-        if (hres == S_OK || hres == S_FALSE)

-          return HRESULT_FROM_WIN32(error);

-      return hres;

-    }

-

-    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;

-          unsigned numItems = _map.Size();

-          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;

-          }

-        }

-      }

-    }

-

-    if (ProcessedItemsStatuses)

-    {

-      #ifndef _7ZIP_ST

-      NSynchronization::CCriticalSectionLock lock(CS);

-      #endif

-      ProcessedItemsStatuses[(unsigned)up.DirIndex] = 1;

-    }

-    *inStream = inStreamLoc.Detach();

-  }

-  

-  return S_OK;

-  COM_TRY_END

-}

-

-STDMETHODIMP CArchiveUpdateCallback::SetOperationResult(Int32 opRes)

-{

-  COM_TRY_BEGIN

-  return Callback->SetOperationResult(opRes);

-  COM_TRY_END

-}

-

-STDMETHODIMP CArchiveUpdateCallback::GetStream(UInt32 index, ISequentialInStream **inStream)

-{

-  COM_TRY_BEGIN

-  return GetStream2(index, inStream,

-      (*UpdatePairs)[index].ArcIndex < 0 ?

-          NUpdateNotifyOp::kAdd :

-          NUpdateNotifyOp::kUpdate);

-  COM_TRY_END

-}

-

-STDMETHODIMP CArchiveUpdateCallback::ReportOperation(UInt32 indexType, UInt32 index, UInt32 op)

-{

-  COM_TRY_BEGIN

-

-  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(up.DirIndex);

-        isDir = DirItems->Items[up.DirIndex].IsDir();

-      }

-    }

-    return Callback->ReportUpdateOpeartion(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->GetItemPath(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->ReportUpdateOpeartion(op, s, isDir);

-

-  COM_TRY_END

-}

-

-STDMETHODIMP 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->GetItemPath(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

-}

-

-STDMETHODIMP 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;

-}

-

-STDMETHODIMP 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 += '.';

-  fileName += res;

-  fileName += VolExt;

-  COutFileStream *streamSpec = new COutFileStream;

-  CMyComPtr<ISequentialOutStream> streamLoc(streamSpec);

-  if (!streamSpec->Create(fileName, false))

-    return ::GetLastError();

-  *volumeStream = streamLoc.Detach();

-  return S_OK;

-  COM_TRY_END

-}

-

-STDMETHODIMP CArchiveUpdateCallback::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password)

-{

-  COM_TRY_BEGIN

-  return Callback->CryptoGetTextPassword2(passwordIsDefined, password);

-  COM_TRY_END

-}

-

-STDMETHODIMP CArchiveUpdateCallback::CryptoGetTextPassword(BSTR *password)

-{

-  COM_TRY_BEGIN

-  return Callback->CryptoGetTextPassword(password);

-  COM_TRY_END

-}

-

-HRESULT CArchiveUpdateCallback::InFileStream_On_Error(UINT_PTR val, DWORD error)

-{

-  if (error == ERROR_LOCK_VIOLATION)

-  {

-    MT_LOCK

-    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(UINT_PTR val)

-{

-  MT_LOCK

-  UInt32 index = (UInt32)val;

-  FOR_VECTOR(i, _openFiles_Indexes)

-  {

-    if (_openFiles_Indexes[i] == index)

-    {

-      _openFiles_Indexes.Delete(i);

-      _openFiles_Paths.Delete(i);

-      return;

-    }

-  }

-  throw 20141125;

-}

+// UpdateCallback.cpp
+
+#include "StdAfx.h"
+
+// #include <stdio.h>
+
+#ifndef _WIN32
+// #include <grp.h>
+// #include <pwd.h>
+/*
+inclusion of <sys/sysmacros.h> by <sys/types.h> 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()
+*/
+// for major()/minor():
+#include <sys/types.h>
+#if defined(__FreeBSD__) || defined(BSD) || defined(__APPLE__)
+#else
+#ifndef major
+#include <sys/sysmacros.h>
+#endif
+#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;
+  }
+  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;
+    }
+  }
+  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:  prop = (UInt32)di.GetWinAttrib(); break;
+      case kpidPosixAttrib: 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
+    }
+  }
+  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<ISequentialInStream> 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;
+
+    CStdInFileStream *inStreamSpec = new CStdInFileStream;
+    CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec);
+    *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<ISequentialInStream> 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<ISequentialInStream> 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<ISequentialOutStream> streamLoc(streamSpec);
+  if (!streamSpec->Create(fileName, false))
+    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 1b5d1ee..379b814 100644
--- a/CPP/7zip/UI/Common/UpdateCallback.h
+++ b/CPP/7zip/UI/Common/UpdateCallback.h
@@ -1,162 +1,197 @@
-// UpdateCallback.h

-

-#ifndef __UPDATE_CALLBACK_H

-#define __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();

-  }

-};

-

-#define INTERFACE_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 ReportUpdateOpeartion(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 CloseProgress() { return S_OK; } */

-

-struct IUpdateCallbackUI

-{

-  INTERFACE_IUpdateCallbackUI(=0)

-};

-

-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:

-  public IArchiveUpdateCallback2,

-  public IArchiveUpdateCallbackFile,

-  public IArchiveExtractCallbackMessage,

-  public IArchiveGetRawProps,

-  public IArchiveGetRootProps,

-  public ICryptoGetTextPassword2,

-  public ICryptoGetTextPassword,

-  public ICompressProgressInfo,

-  public IInFileStream_Callback,

-  public CMyUnknownImp

-{

-  #if defined(_WIN32) && !defined(UNDER_CE)

-  bool _saclEnabled;

-  #endif

-  CRecordVector<CKeyKeyValPair> _map;

-

-  UInt32 _hardIndex_From;

-  UInt32 _hardIndex_To;

-

-public:

-  MY_QUERYINTERFACE_BEGIN2(IArchiveUpdateCallback2)

-    MY_QUERYINTERFACE_ENTRY(IArchiveUpdateCallbackFile)

-    MY_QUERYINTERFACE_ENTRY(IArchiveExtractCallbackMessage)

-    MY_QUERYINTERFACE_ENTRY(IArchiveGetRawProps)

-    MY_QUERYINTERFACE_ENTRY(IArchiveGetRootProps)

-    MY_QUERYINTERFACE_ENTRY(ICryptoGetTextPassword2)

-    MY_QUERYINTERFACE_ENTRY(ICryptoGetTextPassword)

-    MY_QUERYINTERFACE_ENTRY(ICompressProgressInfo)

-  MY_QUERYINTERFACE_END

-  MY_ADDREF_RELEASE

-

-

-  STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);

-

-  INTERFACE_IArchiveUpdateCallback2(;)

-  INTERFACE_IArchiveUpdateCallbackFile(;)

-  INTERFACE_IArchiveExtractCallbackMessage(;)

-  INTERFACE_IArchiveGetRawProps(;)

-  INTERFACE_IArchiveGetRootProps(;)

-

-  STDMETHOD(CryptoGetTextPassword2)(Int32 *passwordIsDefined, BSTR *password);

-  STDMETHOD(CryptoGetTextPassword)(BSTR *password);

-

-  CRecordVector<UInt32> _openFiles_Indexes;

-  FStringVector _openFiles_Paths;

-

-  bool AreAllFilesClosed() const { return _openFiles_Indexes.IsEmpty(); }

-  virtual HRESULT InFileStream_On_Error(UINT_PTR val, DWORD error);

-  virtual void InFileStream_On_Destroy(UINT_PTR val);

-

-  CRecordVector<UInt64> VolumesSizes;

-  FString VolName;

-  FString VolExt;

-

-  IUpdateCallbackUI *Callback;

-

-  const CDirItems *DirItems;

-  const CDirItem *ParentDirItem;

-  

-  const CArc *Arc;

-  CMyComPtr<IInArchive> Archive;

-  const CObjectVector<CArcItem> *ArcItems;

-  const CRecordVector<CUpdatePair2> *UpdatePairs;

-  const UStringVector *NewNames;

-  int CommentIndex;

-  const UString *Comment;

-

-  bool ShareForWrite;

-  bool StopAfterOpenError;

-  bool StdInMode;

-

-  bool KeepOriginalItemNames;

-  bool StoreNtSecurity;

-  bool StoreHardLinks;

-  bool StoreSymLinks;

-

-  Byte *ProcessedItemsStatuses;

-

-

-  CArchiveUpdateCallback();

-

-  bool IsDir(const CUpdatePair2 &up) const

-  {

-    if (up.DirIndex >= 0)

-      return DirItems->Items[up.DirIndex].IsDir();

-    else if (up.ArcIndex >= 0)

-      return (*ArcItems)[up.ArcIndex].IsDir;

-    return false;

-  }

-};

-

-#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<UInt32> _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<IInArchive> Archive;
+  const CObjectVector<CArcItem> *ArcItems;
+  const CRecordVector<CUpdatePair2> *UpdatePairs;
+
+  CRecordVector<UInt64> 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<CKeyKeyValPair> _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 5153671..99b0aaf 100644
--- a/CPP/7zip/UI/Common/UpdatePair.cpp
+++ b/CPP/7zip/UI/Common/UpdatePair.cpp
@@ -1,233 +1,302 @@
-// UpdatePair.cpp

-

-#include "StdAfx.h"

-

-#include <time.h>

-

-#include "../../../Common/Wildcard.h"

-

-#include "../../../Windows/TimeUtils.h"

-

-#include "SortUtils.h"

-#include "UpdatePair.h"

-

-using namespace NWindows;

-using namespace NTime;

-

-static int MyCompareTime(NFileTimeType::EEnum fileTimeType, const FILETIME &time1, const FILETIME &time2)

-{

-  switch (fileTimeType)

-  {

-    case NFileTimeType::kWindows:

-      return ::CompareFileTime(&time1, &time2);

-    case NFileTimeType::kUnix:

-      {

-        UInt32 unixTime1, unixTime2;

-        FileTimeToUnixTime(time1, unixTime1);

-        FileTimeToUnixTime(time2, unixTime2);

-        return MyCompare(unixTime1, unixTime2);

-      }

-    case NFileTimeType::kDOS:

-      {

-        UInt32 dosTime1, dosTime2;

-        FileTimeToDosTime(time1, dosTime1);

-        FileTimeToDosTime(time2, dosTime2);

-        return MyCompare(dosTime1, dosTime2);

-      }

-  }

-  throw 4191618;

-}

-

-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):";

-

-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)

-{

-  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)

-{

-  unsigned i1 = *p1;

-  unsigned i2 = *p2;

-  const CObjectVector<CArcItem> &arcItems = *(const CObjectVector<CArcItem> *)param;

-  int res = CompareArcItemsBase(arcItems[i1], arcItems[i2]);

-  if (res != 0)

-    return res;

-  return MyCompare(i1, i2);

-}

-

-void GetUpdatePairInfoList(

-    const CDirItems &dirItems,

-    const CObjectVector<CArcItem> &arcItems,

-    NFileTimeType::EEnum fileTimeType,

-    CRecordVector<CUpdatePair> &updatePairs)

-{

-  CUIntVector dirIndices, arcIndices;

-  

-  unsigned numDirItems = dirItems.Items.Size();

-  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 = dirIndices[dirIndex];

-      di = &dirItems.Items[dirIndex2];

-    }

-

-    if (arcIndex < numArcItems)

-    {

-      arcIndex2 = arcIndices[arcIndex];

-      ai = &arcItems[arcIndex2];

-      compareResult = 1;

-      if (dirIndex < numDirItems)

-      {

-        compareResult = CompareFileNames(dirNames[dirIndex2], ai->Name);

-        if (compareResult == 0)

-        {

-          if (di->IsDir() != ai->IsDir)

-            compareResult = (ai->IsDir ? 1 : -1);

-        }

-      }

-    }

-    

-    if (compareResult < 0)

-    {

-      name = &dirNames[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

-    {

-      int dupl = duplicatedArcItem[arcIndex];

-      if (dupl != 0)

-        ThrowError(k_Duplicate_inArc_Message, ai->Name, arcItems[arcIndices[arcIndex + dupl]].Name);

-

-      name = &dirNames[dirIndex2];

-      if (!ai->Censored)

-        ThrowError(k_NotCensoredCollision_Message, *name, ai->Name);

-      

-      pair.DirIndex = dirIndex2;

-      pair.ArcIndex = arcIndex2;

-

-      switch (ai->MTimeDefined ? MyCompareTime(

-          ai->TimeType != - 1 ? (NFileTimeType::EEnum)ai->TimeType : fileTimeType,

-          di->MTime, ai->MTime): 0)

-      {

-        case -1: pair.State = NUpdateArchive::NPairState::kNewInArchive; break;

-        case  1: pair.State = NUpdateArchive::NPairState::kOldInArchive; break;

-        default:

-          pair.State = (ai->SizeDefined && di->Size == ai->Size) ?

-              NUpdateArchive::NPairState::kSameFiles :

-              NUpdateArchive::NPairState::kUnknowNewerFiles;

-      }

-      

-      dirIndex++;

-      arcIndex++;

-    }

-    

-    if ((di && di->IsAltStream) ||

-        (ai && ai->IsAltStream))

-    {

-      if (prevHostName)

-      {

-        unsigned hostLen = prevHostName->Len();

-        if (name->Len() > hostLen)

-          if ((*name)[hostLen] == ':' && CompareFileNames(*prevHostName, name->Left(hostLen)) == 0)

-            pair.HostIndex = prevHostFile;

-      }

-    }

-    else

-    {

-      prevHostFile = updatePairs.Size();

-      prevHostName = name;

-    }

-    

-    updatePairs.Add(pair);

-  }

-

-  updatePairs.ReserveDown();

-}

+// UpdatePair.cpp
+
+#include "StdAfx.h"
+
+#include <time.h>
+// #include <stdio.h>
+
+#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<CArcItem> &arcItems = *(const CObjectVector<CArcItem> *)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<CArcItem> &arcItems,
+    NFileTimeType::EEnum fileTimeType,
+    CRecordVector<CUpdatePair> &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 36da243..13228b0 100644
--- a/CPP/7zip/UI/Common/UpdatePair.h
+++ b/CPP/7zip/UI/Common/UpdatePair.h
@@ -1,27 +1,27 @@
-// UpdatePair.h

-

-#ifndef __UPDATE_PAIR_H

-#define __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<CArcItem> &arcItems,

-    NFileTimeType::EEnum fileTimeType,

-    CRecordVector<CUpdatePair> &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<CArcItem> &arcItems,
+    NFileTimeType::EEnum fileTimeType,
+    CRecordVector<CUpdatePair> &updatePairs);
+
+#endif
diff --git a/CPP/7zip/UI/Common/UpdateProduce.cpp b/CPP/7zip/UI/Common/UpdateProduce.cpp
index c025ac4..e921dc3 100644
--- a/CPP/7zip/UI/Common/UpdateProduce.cpp
+++ b/CPP/7zip/UI/Common/UpdateProduce.cpp
@@ -1,70 +1,72 @@
-// 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<CUpdatePair> &updatePairs,

-    const CActionSet &actionSet,

-    CRecordVector<CUpdatePair2> &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 (actionSet.StateActions[(unsigned)pair.State])

-    {

-      case NPairAction::kIgnore:

-        if (pair.ArcIndex >= 0 && callback)

-          callback->ShowDeleteFile(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[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;

-    }

-

-    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<CUpdatePair> &updatePairs,
+    const CActionSet &actionSet,
+    CRecordVector<CUpdatePair2> &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 (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;
+    }
+
+    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 8467543..9db6c1e 100644
--- a/CPP/7zip/UI/Common/UpdateProduce.h
+++ b/CPP/7zip/UI/Common/UpdateProduce.h
@@ -1,55 +1,60 @@
-// UpdateProduce.h

-

-#ifndef __UPDATE_PRODUCE_H

-#define __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;

-

-  void SetAs_NoChangeArcItem(int arcIndex)

-  {

-    NewData = NewProps = false;

-    UseArcProps = true;

-    IsAnti = false;

-    ArcIndex = 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)

-      {}

-};

-

-struct IUpdateProduceCallback

-{

-  virtual HRESULT ShowDeleteFile(unsigned arcIndex) = 0;

-};

-

-void UpdateProduce(

-    const CRecordVector<CUpdatePair> &updatePairs,

-    const NUpdateArchive::CActionSet &actionSet,

-    CRecordVector<CUpdatePair2> &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<CUpdatePair> &updatePairs,
+    const NUpdateArchive::CActionSet &actionSet,
+    CRecordVector<CUpdatePair2> &operationChain,
+    IUpdateProduceCallback *callback);
+
+#endif
diff --git a/CPP/7zip/UI/Common/WorkDir.cpp b/CPP/7zip/UI/Common/WorkDir.cpp
index 03d6eed..cfec635 100644
--- a/CPP/7zip/UI/Common/WorkDir.cpp
+++ b/CPP/7zip/UI/Common/WorkDir.cpp
@@ -1,94 +1,86 @@
-// WorkDir.cpp

-

-#include "StdAfx.h"

-

-#include "../../../Common/StringConvert.h"

-#include "../../../Common/Wildcard.h"

-

-#include "../../../Windows/FileName.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;

-    FString prefix = path.Left(3);

-    if (prefix[1] == FTEXT(':') && prefix[2] == FTEXT('\\'))

-    {

-      UINT driveType = GetDriveType(GetSystemString(prefix, ::AreFileApisANSI() ? CP_ACP : CP_OEMCP));

-      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

-  

-  int pos = path.ReverseFind_PathSepar() + 1;

-  fileName = path.Ptr(pos);

-  

-  switch (mode)

-  {

-    case NWorkDir::NMode::kCurrent:

-    {

-      return path.Left(pos);

-    }

-    case NWorkDir::NMode::kSpecified:

-    {

-      FString tempDir = workDirInfo.Path;

-      NName::NormalizeDirPathPrefix(tempDir);

-      return tempDir;

-    }

-    default:

-    {

-      FString tempDir;

-      if (!MyGetTempPath(tempDir))

-        throw 141717;

-      return tempDir;

-    }

-  }

-}

-

-HRESULT CWorkDirTempFile::CreateTempFile(const FString &originalPath)

-{

-  NWorkDir::CInfo workDirInfo;

-  workDirInfo.Load();

-  FString namePart;

-  FString workDir = GetWorkDir(workDirInfo, originalPath, namePart);

-  CreateComplexDir(workDir);

-  CTempFile tempFile;

-  _outStreamSpec = new COutFileStream;

-  OutStream = _outStreamSpec;

-  if (!_tempFile.Create(workDir + namePart, &_outStreamSpec->File))

-  {

-    DWORD error = GetLastError();

-    return error ? error : E_FAIL;

-  }

-  _originalPath = originalPath;

-  return S_OK;

-}

-

-HRESULT CWorkDirTempFile::MoveToOriginal(bool deleteOriginal)

-{

-  OutStream.Release();

-  if (!_tempFile.MoveTo(_originalPath, deleteOriginal))

-  {

-    DWORD error = GetLastError();

-    return error ? error : E_FAIL;

-  }

-  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;
+  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;
+}
diff --git a/CPP/7zip/UI/Common/WorkDir.h b/CPP/7zip/UI/Common/WorkDir.h
index 13d4ed9..d32ab9d 100644
--- a/CPP/7zip/UI/Common/WorkDir.h
+++ b/CPP/7zip/UI/Common/WorkDir.h
@@ -1,26 +1,26 @@
-// WorkDir.h

-

-#ifndef __WORK_DIR_H

-#define __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<IOutStream> 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
+{
+  FString _originalPath;
+  NWindows::NFile::NDir::CTempFile _tempFile;
+  COutFileStream *_outStreamSpec;
+public:
+  CMyComPtr<IOutStream> OutStream;
+
+  HRESULT CreateTempFile(const FString &originalPath);
+  HRESULT MoveToOriginal(bool deleteOriginal);
+};
+
+#endif
diff --git a/CPP/7zip/UI/Common/ZipRegistry.cpp b/CPP/7zip/UI/Common/ZipRegistry.cpp
new file mode 100644
index 0000000..6c1b9c8
--- /dev/null
+++ b/CPP/7zip/UI/Common/ZipRegistry.cpp
@@ -0,0 +1,580 @@
+// 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");
+
+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 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;
+}
+
+}
+
+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);
+}
diff --git a/CPP/7zip/UI/Common/ZipRegistry.h b/CPP/7zip/UI/Common/ZipRegistry.h
index 4c16b61..6bc6977 100644
--- a/CPP/7zip/UI/Common/ZipRegistry.h
+++ b/CPP/7zip/UI/Common/ZipRegistry.h
@@ -1,130 +1,209 @@
-// ZipRegistry.h

-

-#ifndef __ZIP_REGISTRY_H

-#define __ZIP_REGISTRY_H

-

-#include "../../../Common/MyTypes.h"

-#include "../../../Common/MyString.h"

-

-#include "ExtractMode.h"

-

-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();

-}

-

-namespace NCompression

-{

-  struct CFormatOptions

-  {

-    UInt32 Level;

-    UInt32 Dictionary;

-    UInt32 Order;

-    UInt32 BlockLogSize;

-    UInt32 NumThreads;

-    

-    CSysString FormatID;

-    UString Method;

-    UString Options;

-    UString EncryptionMethod;

-

-    void Reset_BlockLogSize()

-    {

-      BlockLogSize = (UInt32)(Int32)-1;

-    }

-

-    void ResetForLevelChange()

-    {

-      BlockLogSize = NumThreads = Level = Dictionary = Order = (UInt32)(Int32)-1;

-      Method.Empty();

-      // Options.Empty();

-      // EncryptionMethod.Empty();

-    }

-    CFormatOptions() { ResetForLevelChange(); }

-  };

-

-  struct CInfo

-  {

-    UInt32 Level;

-    bool ShowPassword;

-    bool EncryptHeaders;

-    UString ArcType;

-    UStringVector ArcPaths;

-

-    CObjectVector<CFormatOptions> Formats;

-

-    CBoolPair NtSecurity;

-    CBoolPair AltStreams;

-    CBoolPair HardLinks;

-    CBoolPair SymLinks;

-

-    void Save() const;

-    void Load();

-  };

-}

-

-namespace NWorkDir

-{

-  namespace NMode

-  {

-    enum EEnum

-    {

-      kSystem,

-      kCurrent,

-      kSpecified

-    };

-  }

-  struct CInfo

-  {

-    NMode::EEnum Mode;

-    FString Path;

-    bool ForRemovableOnly;

-

-    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;

-

-  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();
+}
+
+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<CFormatOptions> 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 9cf8dd6..113f584 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: public IBenchPrintCallback

-{

-  FILE *_file;

-

-  void Print(const char *s);

-  void NewLine();

-  HRESULT CheckBreak();

-};

-

-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<CProperty> &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<CProperty> &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 ef235ee..844cc2a 100644
--- a/CPP/7zip/UI/Console/BenchCon.h
+++ b/CPP/7zip/UI/Console/BenchCon.h
@@ -1,14 +1,14 @@
-// BenchCon.h

-

-#ifndef __BENCH_CON_H

-#define __BENCH_CON_H

-

-#include <stdio.h>

-

-#include "../../Common/CreateCoder.h"

-#include "../../UI/Common/Property.h"

-

-HRESULT BenchCon(DECL_EXTERNAL_CODECS_LOC_VARS

-    const CObjectVector<CProperty> &props, UInt32 numIterations, FILE *f);

-

-#endif

+// BenchCon.h
+
+#ifndef ZIP7_INC_BENCH_CON_H
+#define ZIP7_INC_BENCH_CON_H
+
+#include <stdio.h>
+
+#include "../../Common/CreateCoder.h"
+#include "../../UI/Common/Property.h"
+
+HRESULT BenchCon(DECL_EXTERNAL_CODECS_LOC_VARS
+    const CObjectVector<CProperty> &props, UInt32 numIterations, FILE *f);
+
+#endif
diff --git a/CPP/7zip/UI/Console/Console.dsp b/CPP/7zip/UI/Console/Console.dsp
new file mode 100644
index 0000000..26e8c7f
--- /dev/null
+++ b/CPP/7zip/UI/Console/Console.dsp
@@ -0,0 +1,1040 @@
+# 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\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\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\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
new file mode 100644
index 0000000..0d93da2
--- /dev/null
+++ b/CPP/7zip/UI/Console/Console.dsw
@@ -0,0 +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>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/CPP/7zip/UI/Console/Console.mak b/CPP/7zip/UI/Console/Console.mak
index d4268c5..1a47bfa 100644
--- a/CPP/7zip/UI/Console/Console.mak
+++ b/CPP/7zip/UI/Console/Console.mak
@@ -1,43 +1,45 @@
-MY_CONSOLE = 1

-

-!IFNDEF UNDER_CE

-CFLAGS = $(CFLAGS) -DWIN_LONG_PATH -D_7ZIP_LARGE_PAGES -DSUPPORT_DEVICE_FILE

-!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 \

+MY_CONSOLE = 1
+
+!IFNDEF UNDER_CE
+CFLAGS = $(CFLAGS) -DZ7_LONG_PATH -DZ7_LARGE_PAGES -DZ7_DEVICE_FILE
+!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 77ecaad..c932b28 100644
--- a/CPP/7zip/UI/Console/Console.manifest
+++ b/CPP/7zip/UI/Console/Console.manifest
@@ -1,13 +1,16 @@
-<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">

-<assemblyIdentity version="1.0.0.0" processorArchitecture="*" name="7z" type="win32"></assemblyIdentity>

-<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">

-<security><requestedPrivileges><requestedExecutionLevel level="asInvoker" uiAccess="false">

-</requestedExecutionLevel></requestedPrivileges></security></trustInfo>

-<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"><application>

-<!-- Vista   --> <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>

-<!-- Win 7   --> <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>

-<!-- Win 8   --> <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>

-<!-- Win 8.1 --> <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>

-<!-- Win 10  --> <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>

-</application></compatibility>

+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+<assemblyIdentity version="1.0.0.0" processorArchitecture="*" name="7z" type="win32"></assemblyIdentity>
+<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
+<security><requestedPrivileges><requestedExecutionLevel level="asInvoker" uiAccess="false">
+</requestedExecutionLevel></requestedPrivileges></security></trustInfo>
+<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"><application>
+<!-- Vista   --> <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
+<!-- Win 7   --> <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
+<!-- Win 8   --> <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
+<!-- Win 8.1 --> <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
+<!-- Win 10  --> <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
+</application></compatibility>
+<application xmlns="urn:schemas-microsoft-com:asm.v3">
+<windowsSettings xmlns:ws2="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
+<ws2:longPathAware>true</ws2:longPathAware></windowsSettings></application>
 </assembly>
\ No newline at end of file
diff --git a/CPP/7zip/UI/Console/ConsoleClose.cpp b/CPP/7zip/UI/Console/ConsoleClose.cpp
index a6f17af..9e4c040 100644
--- a/CPP/7zip/UI/Console/ConsoleClose.cpp
+++ b/CPP/7zip/UI/Console/ConsoleClose.cpp
@@ -1,69 +1,100 @@
-// ConsoleClose.cpp

-

-#include "StdAfx.h"

-

-#include "ConsoleClose.h"

-

-#if !defined(UNDER_CE) && defined(_WIN32)

-#include "../../../Common/MyWindows.h"

-#endif

-

-namespace NConsoleClose {

-

-unsigned g_BreakCounter = 0;

-static const unsigned kBreakAbortThreshold = 2;

-

-#if !defined(UNDER_CE) && defined(_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;

-  */

-}

-#endif

-

-/*

-void CheckCtrlBreak()

-{

-  if (TestBreakSignal())

-    throw CCtrlBreakException();

-}

-*/

-

-CCtrlHandlerSetter::CCtrlHandlerSetter()

-{

-  #if !defined(UNDER_CE) && defined(_WIN32)

-  if (!SetConsoleCtrlHandler(HandlerRoutine, TRUE))

-    throw "SetConsoleCtrlHandler fails";

-  #endif

-}

-

-CCtrlHandlerSetter::~CCtrlHandlerSetter()

-{

-  #if !defined(UNDER_CE) && defined(_WIN32)

-  if (!SetConsoleCtrlHandler(HandlerRoutine, FALSE))

-  {

-    // warning for throw in destructor.

-    // throw "SetConsoleCtrlHandler fails";

-  }

-  #endif

-}

-

-}

+// ConsoleClose.cpp
+
+#include "StdAfx.h"
+
+#include "ConsoleClose.h"
+
+#ifndef UNDER_CE
+
+#ifdef _WIN32
+#include "../../../Common/MyWindows.h"
+#else
+#include <stdlib.h>
+#include <signal.h>
+#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
diff --git a/CPP/7zip/UI/Console/ConsoleClose.h b/CPP/7zip/UI/Console/ConsoleClose.h
index 0a0bbf0..25c5d0c 100644
--- a/CPP/7zip/UI/Console/ConsoleClose.h
+++ b/CPP/7zip/UI/Console/ConsoleClose.h
@@ -1,33 +1,39 @@
-// ConsoleClose.h

-

-#ifndef __CONSOLE_CLOSE_H

-#define __CONSOLE_CLOSE_H

-

-namespace NConsoleClose {

-

-extern unsigned g_BreakCounter;

-

-inline bool TestBreakSignal()

-{

-  #ifdef UNDER_CE

-  return false;

-  #else

-  return (g_BreakCounter != 0);

-  #endif

-}

-

-class CCtrlHandlerSetter

-{

-public:

-  CCtrlHandlerSetter();

-  virtual ~CCtrlHandlerSetter();

-};

-

-class CCtrlBreakException

-{};

-

-// void CheckCtrlBreak();

-

-}

-

-#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 bdf9549..dd7a214 100644
--- a/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp
+++ b/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp
@@ -1,825 +1,849 @@
-// 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 _7ZIP_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)

-{

-  ClosePercentsAndFlush();

-  

-  if (_se)

-  {

-    *_se << endl << kError << NError::MyFormatMessage(systemError) << endl;

-    _se->NormalizePrint_UString(fs2us(path));

-    *_se << endl << endl;

-    _se->Flush();

-  }

-  return HRESULT_FROM_WIN32(systemError);

-}

-

-

-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)

-{

-  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 += ')';

-}

-

-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)

-{

-  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)

-{

-  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 _7ZIP_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 kCantAutoRename = "can not create file with auto name\n";

-// static const char * const kCantRenameFile = "can not rename existing file\n";

-// static const char * const kCantDeleteOutputFile = "can not 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"

-};

-

-STDMETHODIMP CExtractCallbackConsole::SetTotal(UInt64 size)

-{

-  MT_LOCK

-

-  if (NeedPercents())

-  {

-    _percent.Total = size;

-    _percent.Print();

-  }

-  return CheckBreak2();

-}

-

-STDMETHODIMP 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);

-  *_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;

-  }

-}

-

-STDMETHODIMP 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 (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();

-}

-

-STDMETHODIMP 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;

-    default: s = "???"; requiredLevel = 2;

-  };

-

-  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(_tempU);

-    }

-    _so->PrintUString(_tempU, _tempA);

-    if (position)

-      *_so << " <" << *position << ">";

-    *_so << endl;

- 

-    if (NeedFlush)

-      _so->Flush();

-  }

-

-  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();

-}

-

-STDMETHODIMP 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)

-{

-  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;

-    }

-    

-    dest += kError;

-    if (s)

-      dest += s;

-    else

-    {

-      dest += "Error #";

-      dest.Add_UInt32(opRes);

-    }

-}

-

-STDMETHODIMP 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(_currentName);

-      }

-      *_se << endl;

-      _se->Flush();

-    }

-  }

-  

-  return CheckBreak2();

-}

-

-STDMETHODIMP 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 _NO_CRYPTO

-

-HRESULT CExtractCallbackConsole::SetPassword(const UString &password)

-{

-  PasswordIsDefined = true;

-  Password = password;

-  return S_OK;

-}

-

-STDMETHODIMP CExtractCallbackConsole::CryptoGetTextPassword(BSTR *password)

-{

-  COM_TRY_BEGIN

-  MT_LOCK

-  return Open_CryptoGetTextPassword(password);

-  COM_TRY_END

-}

-

-#endif

-

-HRESULT CExtractCallbackConsole::BeforeOpen(const wchar_t *name, bool testMode)

-{

-  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(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 < 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)

-{

-  if (errorFlags == 0)

-    return;

-  so << s << endl << GetOpenArcErrorMessage(errorFlags) << endl;

-}

-

-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)

-{

-  const CArcErrorInfo &er = arc.ErrorInfo;

-  

-  *_so << "WARNING:\n";

-  _so->NormalizePrint_UString(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, "Can not 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)

-{

-  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(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(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(name);

-      *_se << endl;

-      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

-  {

-    NumArcsWithError++;

-    if (result == E_ABORT || result == ERROR_DISK_FULL)

-      return result;

-    

-    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(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 += ')';
+}
+
+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);
+  *_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;
+  }
+
+  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(_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();
+  }
+
+  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;
+    }
+    
+    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(_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
+
+HRESULT CExtractCallbackConsole::BeforeOpen(const wchar_t *name, bool testMode)
+{
+  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(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(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)
+{
+  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(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(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(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
+  {
+    NumArcsWithError++;
+    if (result == E_ABORT
+        || result == HRESULT_FROM_WIN32(ERROR_DISK_FULL)
+        )
+      return result;
+    
+    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 5de6c5b..478b293 100644
--- a/CPP/7zip/UI/Console/ExtractCallbackConsole.h
+++ b/CPP/7zip/UI/Console/ExtractCallbackConsole.h
@@ -1,164 +1,181 @@
-// ExtractCallbackConsole.h

-

-#ifndef __EXTRACT_CALLBACK_CONSOLE_H

-#define __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"

-

-class CExtractScanConsole: public IDirItemsCallback

-{

-  CStdOutStream *_so;

-  CStdOutStream *_se;

-  CPercentPrinter _percent;

-

-  bool NeedPercents() const { return _percent._so != NULL; }

-  

-  void ClosePercentsAndFlush()

-  {

-    if (NeedPercents())

-      _percent.ClosePrint(true);

-    if (_so)

-      _so->Flush();

-  }

-

-public:

-  void Init(CStdOutStream *outStream, CStdOutStream *errorStream, CStdOutStream *percentStream)

-  {

-    _so = outStream;

-    _se = errorStream;

-    _percent._so = percentStream;

-  }

-  

-  void SetWindowWidth(unsigned width) { _percent.MaxLen = width - 1; }

-

-  void StartScanning();

-  

-  INTERFACE_IDirItemsCallback(;)

-

-  void CloseScanning()

-  {

-    if (NeedPercents())

-      _percent.ClosePrint(true);

-  }

-

-  void PrintStat(const CDirItemsStat &st);

-};

-

-

-

-

-class CExtractCallbackConsole:

-  public IExtractCallbackUI,

-  // public IArchiveExtractCallbackMessage,

-  public IFolderArchiveExtractCallback2,

-  #ifndef _NO_CRYPTO

-  public ICryptoGetTextPassword,

-  #endif

-  public COpenCallbackConsole,

-  public CMyUnknownImp

-{

-  AString _tempA;

-  UString _tempU;

-

-  UString _currentName;

-

-  void ClosePercents_for_so()

-  {

-    if (NeedPercents() && _so == _percent._so)

-      _percent.ClosePrint(false);

-  }

-  

-  void ClosePercentsAndFlush()

-  {

-    if (NeedPercents())

-      _percent.ClosePrint(true);

-    if (_so)

-      _so->Flush();

-  }

-

-public:

-  MY_QUERYINTERFACE_BEGIN2(IFolderArchiveExtractCallback)

-  // MY_QUERYINTERFACE_ENTRY(IArchiveExtractCallbackMessage)

-  MY_QUERYINTERFACE_ENTRY(IFolderArchiveExtractCallback2)

-  #ifndef _NO_CRYPTO

-  MY_QUERYINTERFACE_ENTRY(ICryptoGetTextPassword)

-  #endif

-  MY_QUERYINTERFACE_END

-  MY_ADDREF_RELEASE

-

-  STDMETHOD(SetTotal)(UInt64 total);

-  STDMETHOD(SetCompleted)(const UInt64 *completeValue);

-

-  INTERFACE_IFolderArchiveExtractCallback(;)

-

-  INTERFACE_IExtractCallbackUI(;)

-  // INTERFACE_IArchiveExtractCallbackMessage(;)

-  INTERFACE_IFolderArchiveExtractCallback2(;)

-

-  #ifndef _NO_CRYPTO

-

-  STDMETHOD(CryptoGetTextPassword)(BSTR *password);

-

-  #endif

-  

-  UInt64 NumTryArcs;

-  

-  bool ThereIsError_in_Current;

-  bool ThereIsWarning_in_Current;

-

-  UInt64 NumOkArcs;

-  UInt64 NumCantOpenArcs;

-  UInt64 NumArcsWithError;

-  UInt64 NumArcsWithWarnings;

-

-  UInt64 NumOpenArcErrors;

-  UInt64 NumOpenArcWarnings;

-  

-  UInt64 NumFileErrors;

-  UInt64 NumFileErrors_in_Current;

-

-  bool NeedFlush;

-  unsigned PercentsNameLevel;

-  unsigned LogLevel;

-

-  CExtractCallbackConsole():

-      NeedFlush(false),

-      PercentsNameLevel(1),

-      LogLevel(0)

-      {}

-

-  void SetWindowWidth(unsigned width) { _percent.MaxLen = width - 1; }

-

-  void Init(CStdOutStream *outStream, CStdOutStream *errorStream, CStdOutStream *percentStream)

-  {

-    COpenCallbackConsole::Init(outStream, errorStream, percentStream);

-

-    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<DWORD> 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 != NULL; }
+  
+  void ClosePercentsAndFlush()
+  {
+    if (NeedPercents())
+      _percent.ClosePrint(true);
+    if (_so)
+      _so->Flush();
+  }
+
+public:
+
+  void Init(CStdOutStream *outStream, CStdOutStream *errorStream, CStdOutStream *percentStream)
+  {
+    _so = outStream;
+    _se = errorStream;
+    _percent._so = percentStream;
+  }
+  
+  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
+  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
+  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
+  
+
+  AString _tempA;
+  UString _tempU;
+
+  UString _currentName;
+
+  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;
+  
+  bool ThereIsError_in_Current;
+  bool ThereIsWarning_in_Current;
+
+  UInt64 NumOkArcs;
+  UInt64 NumCantOpenArcs;
+  UInt64 NumArcsWithError;
+  UInt64 NumArcsWithWarnings;
+
+  UInt64 NumOpenArcErrors;
+  UInt64 NumOpenArcWarnings;
+  
+  UInt64 NumFileErrors;
+  UInt64 NumFileErrors_in_Current;
+
+  bool NeedFlush;
+  unsigned PercentsNameLevel;
+  unsigned LogLevel;
+
+  CExtractCallbackConsole():
+      NeedFlush(false),
+      PercentsNameLevel(1),
+      LogLevel(0)
+      {}
+
+  void SetWindowWidth(unsigned width) { _percent.MaxLen = width - 1; }
+
+  void Init(CStdOutStream *outStream, CStdOutStream *errorStream, CStdOutStream *percentStream)
+  {
+    COpenCallbackConsole::Init(outStream, errorStream, percentStream);
+
+    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 3ade0fd..c0e69e2 100644
--- a/CPP/7zip/UI/Console/HashCon.cpp
+++ b/CPP/7zip/UI/Console/HashCon.cpp
@@ -1,367 +1,426 @@
-// HashCon.cpp

-

-#include "StdAfx.h"

-

-#include "../../../Common/IntToString.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);

-    _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 += '-';

-}

-

-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 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;

-}

-

-void CHashCallbackConsole::PrintSeparatorLine(const CObjectVector<CHasherState> &hashers)

-{

-  _s.Empty();

-  

-  for (unsigned i = 0; i < hashers.Size(); i++)

-  {

-    if (i != 0)

-      _s.Add_Space();

-    const CHasherState &h = hashers[i];

-    AddMinuses(_s, GetColumnWidth(h.DigestSize));

-  }

-

-  if (PrintSize)

-  {

-    _s.Add_Space();

-    AddMinuses(_s, kSizeField_Len);

-  }

-

-  if (PrintName)

-  {

-    AddSpacesBeforeName();

-    AddMinuses(_s, kNameField_Len);

-  }

-  

-  *_so << _s << endl;

-}

-

-HRESULT CHashCallbackConsole::BeforeFirstFile(const CHashBundle &hb)

-{

-  if (PrintHeaders && _so)

-  {

-    _s.Empty();

-    ClosePercents_for_so();

-    

-    FOR_VECTOR (i, hb.Hashers)

-    {

-      if (i != 0)

-        _s.Add_Space();

-      const CHasherState &h = hb.Hashers[i];

-      _s += h.Name;

-      AddSpaces_if_Positive(_s, (int)GetColumnWidth(h.DigestSize) - (int)h.Name.Len());

-    }

-    

-    if (PrintSize)

-    {

-      _s.Add_Space();

-      const AString s2 ("Size");

-      AddSpaces_if_Positive(_s, (int)kSizeField_Len - (int)s2.Len());

-      _s += s2;

-    }

-    

-    if (PrintName)

-    {

-      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 /* isFolder */)

-{

-  _fileName = name;

-

-  if (NeedPercents())

-  {

-    if (PrintNameInPercents)

-    {

-      _percent.FileName.Empty();

-      if (name)

-        _percent.FileName = name;

-    }

-   _percent.Print();

-  }

-  return CheckBreak2();

-}

-

-void CHashCallbackConsole::PrintResultLine(UInt64 fileSize,

-    const CObjectVector<CHasherState> &hashers, unsigned digestIndex, bool showHash)

-{

-  ClosePercents_for_so();

-

-  _s.Empty();

-

-  FOR_VECTOR (i, hashers)

-  {

-    const CHasherState &h = hashers[i];

-    char s[k_HashCalc_DigestSize_Max * 2 + 64];

-    s[0] = 0;

-    if (showHash)

-      AddHashHexToString(s, h.Digests[digestIndex], h.DigestSize);

-    SetSpacesAndNul(s + strlen(s), (int)GetColumnWidth(h.DigestSize) - (int)strlen(s));

-    if (i != 0)

-      _s.Add_Space();

-    _s += s;

-  }

-  

-  if (PrintSize)

-  {

-    _s.Add_Space();

-

-    char s[kSizeField_Len + 32];

-    char *p = s;

-    

-    if (showHash)

-    {

-      p = s + kSizeField_Len;

-      ConvertUInt64ToString(fileSize, p);

-      int numSpaces = kSizeField_Len - (int)strlen(p);

-      if (numSpaces > 0)

-      {

-        p -= (unsigned)numSpaces;

-        for (unsigned i = 0; i < (unsigned)numSpaces; i++)

-          p[i] = ' ';

-      }

-    }

-    else

-      SetSpacesAndNul(s, kSizeField_Len);

-    

-    _s += p;

-  }

-

-  if (PrintName)

-    AddSpacesBeforeName();

-  

-  *_so << _s;

-}

-

-HRESULT CHashCallbackConsole::SetOperationResult(UInt64 fileSize, const CHashBundle &hb, bool showHash)

-{

-  if (_so)

-  {

-    PrintResultLine(fileSize, hb.Hashers, k_HashCalc_Index_Current, showHash);

-    if (PrintName)

-    {

-      if (_fileName.IsEmpty())

-        *_so << kEmptyFileAlias;

-      else

-        _so->NormalizePrint_UString(_fileName);

-    }

-    *_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_HashCalc_DigestSize_Max * 2 + 64];

-  s[0] = 0;

-  AddHashHexToString(s, h.Digests[digestIndex], h.DigestSize);

-  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);

-    

-    *_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<CHasherState> &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<CHasherState> &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(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 9c12869..ebccb6f 100644
--- a/CPP/7zip/UI/Console/HashCon.h
+++ b/CPP/7zip/UI/Console/HashCon.h
@@ -1,48 +1,58 @@
-// HashCon.h

-

-#ifndef __HASH_CON_H

-#define __HASH_CON_H

-

-#include "../Common/HashCalc.h"

-

-#include "UpdateCallbackConsole.h"

-

-class CHashCallbackConsole: public IHashCallbackUI, public CCallbackConsoleBase

-{

-  UString _fileName;

-  AString _s;

-

-  void AddSpacesBeforeName()

-  {

-    _s.Add_Space();

-    _s.Add_Space();

-  }

-

-  void PrintSeparatorLine(const CObjectVector<CHasherState> &hashers);

-  void PrintResultLine(UInt64 fileSize,

-      const CObjectVector<CHasherState> &hashers, unsigned digestIndex, bool showHash);

-  void PrintProperty(const char *name, UInt64 value);

-

-public:

-  bool PrintNameInPercents;

-

-  bool PrintHeaders;

-  

-  bool PrintSize;

-  bool PrintName;

-

-  CHashCallbackConsole():

-      PrintNameInPercents(true),

-      PrintHeaders(false),

-      PrintSize(true),

-      PrintName(true)

-    {}

-  

-  ~CHashCallbackConsole() { }

-

-  INTERFACE_IHashCallbackUI(;)

-};

-

-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<CHasherState> &hashers);
+  void PrintResultLine(UInt64 fileSize,
+      const CObjectVector<CHasherState> &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 c56e2e2..46819f1 100644
--- a/CPP/7zip/UI/Console/List.cpp
+++ b/CPP/7zip/UI/Console/List.cpp
@@ -1,1359 +1,1390 @@
-// 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"

-};

-

-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 (adj)

-    {

-      case kLeft:   numLeftSpaces = 0; break;

-      case kCenter: numLeftSpaces = numSpaces / 2; break;

-      case kRight:  numLeftSpaces = numSpaces; 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 (adj)

-    {

-      case kLeft:   numLeftSpaces = 0; break;

-      case kCenter: numLeftSpaces = numSpaces / 2; break;

-      case kRight:  numLeftSpaces = numSpaces; 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 (adj)

-    {

-      case kLeft:   numLeftSpaces = 0; break;

-      case kCenter: numLeftSpaces = numSpaces / 2; break;

-      case kRight:  numLeftSpaces = numSpaces; 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

-{

-  FILETIME Val;

-  bool Def;

-

-  CListFileTimeDef(): Def(false) { Val.dwLowDateTime = 0; Val.dwHighDateTime = 0; }

-  void Update(const CListFileTimeDef &t)

-  {

-    if (t.Def && (!Def || CompareFileTime(&Val, &t.Val) < 0))

-    {

-      Val = t.Val;

-      Def = true;

-    }

-  }

-};

-

-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;

-  }

-  const UInt64 GetNumStreams() const { return MainFiles.NumFiles + AltStreams.NumFiles; }

-  CListStat &GetStat(bool altStreamsMode) { return altStreamsMode ? AltStreams : MainFiles; }

-};

-

-class CFieldPrinter

-{

-  CObjectVector<CFieldInfo> _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 += '-';

-  }

-}

-

-static void GetPropName(PROPID propID, const wchar_t *name, AString &nameA, UString &nameU)

-{

-  if (propID < 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++)

-    {

-      wchar_t c = s[i];

-      if (c >= 0x80)

-        break;

-      sA += (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 FILETIME *ft)

-{

-  *dest = 0;

-  if (ft->dwLowDateTime == 0 && ft->dwHighDateTime == 0)

-    return;

-  ConvertUtcFileTimeToString(*ft, dest, kTimestampPrintLevel_SEC);

-}

-

-#ifndef _SFX

-

-static inline char GetHex(Byte value)

-{

-  return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10)));

-}

-

-static void HexToString(char *dest, const Byte *data, UInt32 size)

-{

-  for (UInt32 i = 0; i < size; i++)

-  {

-    Byte b = data[i];

-    dest[0] = GetHex((Byte)((b >> 4) & 0xF));

-    dest[1] = GetHex((Byte)(b & 0xF));

-    dest += 2;

-  }

-  *dest = 0;

-}

-

-#endif

-

-#define MY_ENDL endl

-

-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(FilePath, TempWString, TempAString);

-      if (techMode)

-        g_StdOut << MY_ENDL;

-      continue;

-    }

-

-    const unsigned width = f.Width;

-    

-    if (f.IsRawProp)

-    {

-      #ifndef _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 _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];

-            HexToString(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: if (st.MTime.Def) prop = st.MTime.Val; 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)

-      {

-        PrintTime(temp + tempPos, &prop.filetime);

-        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 ?

-        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.Val);

-      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)

-{

-  t.Val.dwLowDateTime = 0;

-  t.Val.dwHighDateTime = 0;

-  t.Def = false;

-  CPropVariant prop;

-  RINOK(archive->GetProperty(index, kpidMTime, &prop));

-  if (prop.vt == VT_FILETIME)

-  {

-    t.Val = prop.filetime;

-    t.Def = true;

-  }

-  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 < 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)(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);

-    so.Normalize_UString__LF_Allowed(s);

-    so << s;

-    so << endl;

-    so << "}";

-  }

-  else

-  {

-    so.Normalize_UString(s);

-    so << s;

-  }

-  so << endl;

-}

-

-

-static void PrintPropPair(CStdOutStream &so, const char *name, const wchar_t *val, bool multiLine)

-{

-  so << name << " = ";

-  if (multiLine)

-  {

-    PrintPropVal_MultiLine(so, val);

-    return;

-  }

-  UString s = val;

-  so.Normalize_UString(s);

-  so << s;

-  so << endl;

-}

-

-

-static void PrintPropertyPair2(CStdOutStream &so, PROPID propID, const wchar_t *name, const CPropVariant &prop)

-{

-  UString s;

-  ConvertPropertyToString2(s, prop, propID);

-  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")

-    << ": Can not 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)

-{

-  FOR_VECTOR (r, arcLink.Arcs)

-  {

-    const CArc &arc = arcLink.Arcs[r];

-    const CArcErrorInfo &er = arc.ErrorInfo;

-    

-    so << "--\n";

-    PrintPropPair(so, "Path", arc.Path, false);

-    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)

-{

-  #ifndef _NO_CRYPTO

-  if (arcLink.PasswordWasAsked)

-    so << "Can not open encrypted archive. Wrong password?";

-  else

-  #endif

-  {

-    if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0)

-    {

-      so.NormalizePrint_UString(arcLink.NonOpen_ArcPath);

-      so << endl;

-      PrintArcTypeError(so, codecs->Formats[arcLink.NonOpen_ErrorInfo.ErrorFormatIndex].Name, false);

-    }

-    else

-      so << "Can not 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(CCodecs *codecs,

-    const CObjectVector<COpenType> &types,

-    const CIntVector &excludedFormats,

-    bool stdInMode,

-    UStringVector &arcPaths, UStringVector &arcPathsFull,

-    bool processAltStreams, bool showAltStreams,

-    const NWildcard::CCensorNode &wildcardCensor,

-    bool enableHeaders, bool techMode,

-    #ifndef _NO_CRYPTO

-    bool &passwordEnabled, UString &password,

-    #endif

-    #ifndef _SFX

-    const CObjectVector<CProperty> *props,

-    #endif

-    UInt64 &numErrors,

-    UInt64 &numWarnings)

-{

-  bool allFilesAreAllowed = wildcardCensor.AreAllAllowed();

-

-  numErrors = 0;

-  numWarnings = 0;

-

-  CFieldPrinter fp;

-  if (!techMode)

-    fp.Init(kStandardFieldTable, 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(us2fs(arcPath)))

-      {

-        DWORD errorCode = GetLastError();

-        if (errorCode == 0)

-          errorCode = ERROR_FILE_NOT_FOUND;

-        lastError = HRESULT_FROM_WIN32(lastError);;

-        g_StdOut.Flush();

-        if (g_ErrStream)

-        {

-          *g_ErrStream << endl << kError << NError::MyFormatMessage(errorCode) << endl;

-          g_ErrStream->NormalizePrint_UString(arcPath);

-          *g_ErrStream << endl << endl;

-        }

-        numErrors++;

-        continue;

-      }

-      if (fi.IsDir())

-      {

-        g_StdOut.Flush();

-        if (g_ErrStream)

-        {

-          *g_ErrStream << endl << kError;

-          g_ErrStream->NormalizePrint_UString(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);

-

-    #ifndef _NO_CRYPTO

-

-    openCallback.PasswordIsDefined = passwordEnabled;

-    openCallback.Password = password;

-

-    #endif

-

-    /*

-    CObjectVector<COptionalOpenProperties> optPropsVector;

-    COptionalOpenProperties &optProps = optPropsVector.AddNew();

-    optProps.Props = *props;

-    */

-    

-    COpenOptions options;

-    #ifndef _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(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(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.GetItemPath2(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 (!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(g_StdOut, "Path", arcLink.NonOpen_ArcPath, false);

-        PrintArcTypeError(g_StdOut, codecs->Formats[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 (adj)
+    {
+      case kLeft:   numLeftSpaces = 0; break;
+      case kCenter: numLeftSpaces = numSpaces / 2; break;
+      case kRight:  numLeftSpaces = numSpaces; 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 (adj)
+    {
+      case kLeft:   numLeftSpaces = 0; break;
+      case kCenter: numLeftSpaces = numSpaces / 2; break;
+      case kRight:  numLeftSpaces = numSpaces; 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 (adj)
+    {
+      case kLeft:   numLeftSpaces = 0; break;
+      case kCenter: numLeftSpaces = numSpaces / 2; break;
+      case kRight:  numLeftSpaces = numSpaces; 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<CFieldInfo> _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++)
+    {
+      wchar_t c = s[i];
+      if (c >= 0x80)
+        break;
+      sA += (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;
+  if (showNS)
+  {
+    prec = kTimestampPrintLevel_NTFS;
+    if (t.Prec != 0)
+    {
+      prec = t.GetNumDigits();
+      if (prec < kTimestampPrintLevel_DAY)
+        prec = kTimestampPrintLevel_NTFS;
+    }
+  }
+
+  ConvertUtcFileTimeToString2(t.FT, t.Ns100, dest, prec);
+}
+
+#ifndef Z7_SFX
+
+static inline char GetHex(Byte value)
+{
+  return (char)((value < 10) ? ('0' + value) : ('a' + (value - 10)));
+}
+
+static void HexToString(char *dest, const Byte *data, UInt32 size)
+{
+  for (UInt32 i = 0; i < size; i++)
+  {
+    Byte b = data[i];
+    dest[0] = GetHex((Byte)((b >> 4) & 0xF));
+    dest[1] = GetHex((Byte)(b & 0xF));
+    dest += 2;
+  }
+  *dest = 0;
+}
+
+#endif
+
+#define MY_ENDL endl
+
+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(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];
+            HexToString(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 ?
+        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)(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);
+    so.Normalize_UString_LF_Allowed(s);
+    so << s;
+    so << endl;
+    so << "}";
+  }
+  else
+  {
+    so.Normalize_UString(s);
+    so << s;
+  }
+  so << endl;
+}
+
+
+static void PrintPropPair(CStdOutStream &so, const char *name, const wchar_t *val, bool multiLine)
+{
+  so << name << " = ";
+  if (multiLine)
+  {
+    PrintPropVal_MultiLine(so, val);
+    return;
+  }
+  UString s (val);
+  so.Normalize_UString(s);
+  so << s;
+  so << endl;
+}
+
+
+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(so, "Path", arc.Path, false);
+    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(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<COpenType> &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<CProperty> *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(arcPath);
+          *g_ErrStream << endl << endl;
+        }
+        numErrors++;
+        continue;
+      }
+      if (fi.IsDir())
+      {
+        g_StdOut.Flush();
+        if (g_ErrStream)
+        {
+          *g_ErrStream << endl << kError;
+          g_ErrStream->NormalizePrint_UString(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);
+
+    #ifndef Z7_NO_CRYPTO
+
+    openCallback.PasswordIsDefined = passwordEnabled;
+    openCallback.Password = password;
+
+    #endif
+
+    /*
+    CObjectVector<COptionalOpenProperties> 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(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(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(g_StdOut, "Path", arcLink.NonOpen_ArcPath, false);
+        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 dabbc2a..4969c3e 100644
--- a/CPP/7zip/UI/Console/List.h
+++ b/CPP/7zip/UI/Console/List.h
@@ -1,27 +1,40 @@
-// List.h

-

-#ifndef __LIST_H

-#define __LIST_H

-

-#include "../../../Common/Wildcard.h"

-

-#include "../Common/LoadCodecs.h"

-

-HRESULT ListArchives(CCodecs *codecs,

-    const CObjectVector<COpenType> &types,

-    const CIntVector &excludedFormats,

-    bool stdInMode,

-    UStringVector &archivePaths, UStringVector &archivePathsFull,

-    bool processAltStreams, bool showAltStreams,

-    const NWildcard::CCensorNode &wildcardCensor,

-    bool enableHeaders, bool techMode,

-    #ifndef _NO_CRYPTO

-    bool &passwordEnabled, UString &password,

-    #endif

-    #ifndef _SFX

-    const CObjectVector<CProperty> *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;
+
+  CListOptions():
+    ExcludeDirItems(false),
+    ExcludeFileItems(false)
+    {}
+};
+
+HRESULT ListArchives(
+    const CListOptions &listOptions,
+    CCodecs *codecs,
+    const CObjectVector<COpenType> &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<CProperty> *props,
+  #endif
+    UInt64 &errors,
+    UInt64 &numWarnings);
+
+#endif
diff --git a/CPP/7zip/UI/Console/Main.cpp b/CPP/7zip/UI/Console/Main.cpp
index 4d7aac9..eb9e2a8 100644
--- a/CPP/7zip/UI/Console/Main.cpp
+++ b/CPP/7zip/UI/Console/Main.cpp
@@ -1,1154 +1,1576 @@
-// Main.cpp

-

-#include "StdAfx.h"

-

-#include "../../../Common/MyWindows.h"

-

-#ifdef _WIN32

-#include <Psapi.h>

-#endif

-

-#include "../../../../C/CpuArch.h"

-

-#include "../../../Common/MyInitGuid.h"

-

-#include "../../../Common/CommandLineParser.h"

-#include "../../../Common/IntToString.h"

-#include "../../../Common/MyException.h"

-#include "../../../Common/StringConvert.h"

-#include "../../../Common/StringToInt.h"

-#include "../../../Common/UTFConvert.h"

-

-#include "../../../Windows/ErrorMsg.h"

-

-#include "../../../Windows/TimeUtils.h"

-

-#include "../Common/ArchiveCommandLine.h"

-#include "../Common/Bench.h"

-#include "../Common/ExitCode.h"

-#include "../Common/Extract.h"

-

-#ifdef EXTERNAL_CODECS

-#include "../Common/LoadCodecs.h"

-#endif

-

-#include "../../Common/RegisterCodec.h"

-

-#include "BenchCon.h"

-#include "ConsoleClose.h"

-#include "ExtractCallbackConsole.h"

-#include "List.h"

-#include "OpenCallbackConsole.h"

-#include "UpdateCallbackConsole.h"

-

-#include "HashCon.h"

-

-#ifdef PROG_VARIANT_R

-#include "../../../../C/7zVersion.h"

-#else

-#include "../../MyVersion.h"

-#endif

-

-using namespace NWindows;

-using namespace NFile;

-using namespace NCommandLineParser;

-

-#ifdef _WIN32

-HINSTANCE g_hInstance = 0;

-#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[];

-

-static const char * const kCopyrightString = "\n7-Zip"

-  #ifndef EXTERNAL_CODECS

-    #ifdef PROG_VARIANT_R

-      " (r)"

-    #else

-      " (a)"

-    #endif

-  #endif

-

-  " " MY_VERSION_CPU

-  " : " MY_COPYRIGHT_DATE "\n\n";

-

-static const char * const kHelpString =

-    "Usage: 7z"

-#ifndef EXTERNAL_CODECS

-#ifdef PROG_VARIANT_R

-    "r"

-#else

-    "a"

-#endif

-#endif

-    " <command> [<switches>...] <archive_name> [<file_names>...] [@listfile]\n"

-    "\n"

-    "<Commands>\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"

-    "<Switches>\n"

-    "  -- : Stop switches and @listfile parsing\n"

-    "  -ai[r[-|0]]{@listfile|!wildcard} : Include archives\n"

-    "  -ax[r[-|0]]{@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]]{@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 _NO_CRYPTO

-    "  -p{Password} : set Password\n"

-    #endif

-    "  -r[-|0] : Recurse subdirectories\n"

-    "  -sa{a|e|s} : set Archive name mode\n"

-    "  -scc{UTF-8|WIN|DOS} : set charset for for console input/output\n"

-    "  -scs{UTF-8|UTF-16LE|UTF-16BE|WIN|DOS|{id}} : set charset for list files\n"

-    "  -scrc[CRC32|CRC64|SHA1|SHA256|*] : 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 : 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"

-    "  -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]]{@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";

-

-#define kDefaultSfxModule "7zCon.sfx"

-

-static void ShowMessageAndThrowException(LPCSTR message, NExitCode::EEnum code)

-{

-  if (g_ErrStream)

-    *g_ErrStream << endl << "ERROR: " << message << endl;

-  throw code;

-}

-

-#ifndef _WIN32

-static void GetArguments(int numArgs, const char *args[], UStringVector &parts)

-{

-  parts.Clear();

-  for (int i = 0; i < numArgs; i++)

-  {

-    UString s = MultiByteToUnicodeString(args[i]);

-    parts.Add(s);

-  }

-}

-#endif

-

-static void ShowCopyrightAndHelp(CStdOutStream *so, bool needHelp)

-{

-  if (!so)

-    return;

-  *so << kCopyrightString;

-  // *so << "# CPUs: " << (UInt64)NWindows::NSystem::GetNumberOfProcessors() << 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);

-}

-

-static void PrintLibIndex(CStdOutStream &so, int libIndex)

-{

-  if (libIndex >= 0)

-    PrintUInt32(so, 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 inline char GetHex(unsigned val)

-{

-  return (char)((val < 10) ? ('0' + val) : ('A' + (val - 10)));

-}

-

-static void PrintWarningsPaths(const CErrorPathCodes &pc, CStdOutStream &so)

-{

-  FOR_VECTOR(i, pc.Paths)

-  {

-    so.NormalizePrint_UString(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;

-}

-

-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";

-

-  #ifdef _7ZIP_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::GetCurUtcFileTime(curTimeFT);

-

-  #ifndef UNDER_CE

-  

-  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));

-    */

-

-    HMODULE kern = ::GetModuleHandleW(L"kernel32.dll");

-    Func_GetProcessMemoryInfo my_GetProcessMemoryInfo = (Func_GetProcessMemoryInfo)

-        ::GetProcAddress(kern, "K32GetProcessMemoryInfo");

-    if (!my_GetProcessMemoryInfo)

-    {

-      HMODULE lib = LoadLibraryW(L"Psapi.dll");

-      if (lib)

-        my_GetProcessMemoryInfo = (Func_GetProcessMemoryInfo)::GetProcAddress(lib, "GetProcessMemoryInfo");

-    }

-    if (my_GetProcessMemoryInfo)

-      memDefined = my_GetProcessMemoryInfo(GetCurrentProcess(), &m, sizeof(m));

-    // FreeLibrary(lib);

-

-    Func_QueryProcessCycleTime my_QueryProcessCycleTime = (Func_QueryProcessCycleTime)

-        ::GetProcAddress(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);

-

-  #ifndef UNDER_CE

-  if (cycleDefined)

-  {

-    *g_StdStream << " ";

-    PrintNum(cycleTime / 1000000, 22);

-    *g_StdStream << " MCycles";

-  }

-  #endif

-

-  PrintTime("User   ", userTime, totalTime);

-  

-  PrintTime("Process", kernelTime + userTime, 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;

-}

-

-static void PrintHexId(CStdOutStream &so, UInt64 id)

-{

-  char s[32];

-  ConvertUInt64ToHex(id, s);

-  PrintStringRight(so, s, 8);

-}

-

-

-int Main2(

-  #ifndef _WIN32

-  int numArgs, char *args[]

-  #endif

-)

-{

-  #if defined(_WIN32) && !defined(UNDER_CE)

-  SetFileApisToOEM();

-  #endif

-

-  UStringVector commandStrings;

-  

-  #ifdef _WIN32

-  NCommandLineParser::SplitCommandLine(GetCommandLineW(), commandStrings);

-  #else

-  GetArguments(numArgs, args, commandStrings);

-  #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);

-

-  parser.Parse2(options);

-

-  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 = consoleInfo.dwSize.X;

-    #endif

-    

-    #else

-    

-    struct winsize w;

-    if (ioctl(0, TIOCGWINSZ, &w) == )

-      consoleWidth = w.ws_col;

-    

-    #endif

-  }

-

-  CREATE_CODECS_OBJECT

-

-  codecs->CaseSensitiveChange = options.CaseSensitiveChange;

-  codecs->CaseSensitive = options.CaseSensitive;

-  ThrowException_if_Error(codecs->Load());

-

-  bool isExtractGroupCommand = options.Command.IsFromExtractGroup();

-

-  if (codecs->Formats.Size() == 0 &&

-        (isExtractGroupCommand

-        || options.Command.CommandType == NCommandType::kList

-        || options.Command.IsFromUpdateGroup()))

-  {

-    #ifdef EXTERNAL_CODECS

-    if (!codecs->MainDll_ErrorPath.IsEmpty())

-    {

-      UString s ("Can't load module: ");

-      s += fs2us(codecs->MainDll_ErrorPath);

-      throw s;

-    }

-    #endif

-    

-    throw kNoFormats;

-  }

-

-  CObjectVector<COpenType> 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 EXTERNAL_CODECS

-  if (isExtractGroupCommand

-      || 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 EXTERNAL_CODECS

-    so << endl << "Libs:" << endl;

-    for (i = 0; i < codecs->Libs.Size(); i++)

-    {

-      PrintLibIndex(so, i);

-      so << ' ' << codecs->Libs[i].Path << endl;

-    }

-    #endif

-

-    so << endl << "Formats:" << endl;

-    

-    const char * const kArcFlags = "KSNFMGOPBELH";

-    const unsigned kNumArcFlags = (unsigned)strlen(kArcFlags);

-    

-    for (i = 0; i < codecs->Formats.Size(); i++)

-    {

-      const CArcInfoEx &arc = codecs->Formats[i];

-

-      #ifdef EXTERNAL_CODECS

-      PrintLibIndex(so, arc.LibIndex);

-      #else

-      so << "  ";

-      #endif

-

-      so << (char)(arc.UpdateEnabled ? 'C' : ' ');

-      

-      for (unsigned b = 0; b < kNumArcFlags; b++)

-      {

-        so << (char)

-          ((arc.Flags & ((UInt32)1 << b)) != 0 ? kArcFlags[b] : ' ');

-      }

-        

-      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 += ')';

-        }

-      }

-      

-      PrintString(so, s, 13);

-      so << ' ';

-      

-      if (arc.SignatureOffset != 0)

-        so << "offset=" << arc.SignatureOffset << ' ';

-

-      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 << ' ';

-          Byte b = sig[j];

-          if (b > 0x20 && b < 0x80)

-          {

-            so << (char)b;

-          }

-          else

-          {

-            so << GetHex((b >> 4) & 0xF);

-            so << GetHex(b & 0xF);

-          }

-        }

-      }

-      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 << ' ';

-      PrintHexId(so, cod.Id);

-      so << ' ' << cod.Name << endl;

-    }

-

-

-    #ifdef EXTERNAL_CODECS

-

-    UInt32 numMethods;

-    if (codecs->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' : ' ');

-

-      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 EXTERNAL_CODECS

-    

-    numMethods = codecs->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)

-    {

-      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);

-      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<IFolderArchiveExtractCallback> extractCallback = ecs;

-

-      #ifndef _NO_CRYPTO

-      ecs->PasswordIsDefined = options.PasswordEnabled;

-      ecs->Password = options.Password;

-      #endif

-

-      ecs->Init(g_StdStream, g_ErrStream, percentsStream);

-      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 _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 _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(

-          codecs,

-          types,

-          excludedFormats,

-          ArchivePathsSorted,

-          ArchivePathsFullSorted,

-          options.Censor.Pairs.Front().Head,

-          eo, 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);

-        }

-      }

-    }

-    else

-    {

-      UInt64 numErrors = 0;

-      UInt64 numWarnings = 0;

-      

-      // options.ExtractNtOptions.StoreAltStreams = true, if -sns[-] is not definmed

-

-      hresultMain = ListArchives(

-          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 _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;

-      }

-    }

-  }

-  else if (options.Command.IsFromUpdateGroup())

-  {

-    CUpdateOptions &uo = options.UpdateOptions;

-    if (uo.SfxMode && uo.SfxModule.IsEmpty())

-      uo.SfxModule = kDefaultSfxModule;

-

-    COpenCallbackConsole openCallback;

-    openCallback.Init(g_StdStream, g_ErrStream, percentsStream);

-

-    #ifndef _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 _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);

-

-    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

-        );

-  }

-  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);

-    callback.PrintHeaders = options.EnableHeaders;

-

-    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();

-

-  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 <psapi.h>
+#else
+#include <Psapi.h>
+#endif
+
+#else // Z7_OLD_WIN_SDK
+
+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
+
+#else // _WIN32
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/times.h>
+#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_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
+    " <command> [<switches>...] <archive_name> [<file_names>...] [@listfile]\n"
+    "\n"
+    "<Commands>\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"
+    "<Switches>\n"
+    "  -- : Stop switches and @listfile parsing\n"
+    "  -ai[r[-|0]]{@listfile|!wildcard} : Include archives\n"
+    "  -ax[r[-|0]]{@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]]{@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|SHA1|SHA256|*] : 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]]{@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";
+
+#define kDefaultSfxModule "7zCon.sfx"
+
+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
+  #ifdef __ARM_ARCH_ISA_THUMB
+  << " thumb:" << __ARM_ARCH_ISA_THUMB
+  #endif
+  #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 inline char GetHex(unsigned val)
+{
+  return (char)((val < 10) ? ('0' + val) : ('A' + (val - 10)));
+}
+
+static void PrintWarningsPaths(const CErrorPathCodes &pc, CStdOutStream &so)
+{
+  FOR_VECTOR(i, pc.Paths)
+  {
+    so.NormalizePrint_UString(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
+  
+  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]);
+      /*
+      printf("\n%d %s :", i, a.Ptr());
+      for (unsigned k = 0; k < a.Len(); k++)
+        printf(" %2x", (unsigned)(Byte)a[k]);
+      */
+      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;
+  }
+
+  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 = (unsigned)(unsigned short)consoleInfo.dwSize.X;
+    #endif
+    
+    #else
+    
+    struct winsize w;
+    if (ioctl(0, TIOCGWINSZ, &w) == 0)
+      consoleWidth = w.ws_col;
+    
+    #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<COpenType> 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 += ')';
+        }
+      }
+      
+      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 << ' ';
+          Byte b = sig[j];
+          if (b > 0x20 && b < 0x80)
+          {
+            so << (char)b;
+          }
+          else
+          {
+            so << GetHex((b >> 4) & 0xF);
+            so << GetHex(b & 0xF);
+          }
+        }
+      }
+      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);
+      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<IFolderArchiveExtractCallback> extractCallback = ecs;
+
+      #ifndef Z7_NO_CRYPTO
+      ecs->PasswordIsDefined = options.PasswordEnabled;
+      ecs->Password = options.Password;
+      #endif
+
+      ecs->Init(g_StdStream, g_ErrStream, percentsStream);
+      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;
+
+      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())
+  {
+    CUpdateOptions &uo = options.UpdateOptions;
+    if (uo.SfxMode && uo.SfxModule.IsEmpty())
+      uo.SfxModule = kDefaultSfxModule;
+
+    COpenCallbackConsole openCallback;
+    openCallback.Init(g_StdStream, g_ErrStream, percentsStream);
+
+    #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);
+
+    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
+        );
+  }
+  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);
+    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 1d6c5a4..80f84f5 100644
--- a/CPP/7zip/UI/Console/MainAr.cpp
+++ b/CPP/7zip/UI/Console/MainAr.cpp
@@ -1,175 +1,227 @@
-// MainAr.cpp

-

-#include "StdAfx.h"

-

-#ifdef _WIN32

-#include "../../../../C/DllSecur.h"

-#endif

-

-#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;

-

-CStdOutStream *g_StdStream = NULL;

-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;

-}

-

-#define NT_CHECK_FAIL_ACTION *g_StdStream << "Unsupported Windows version"; return NExitCode::kFatalError;

-

-int MY_CDECL main

-(

-  #ifndef _WIN32

-  int numArgs, char *args[]

-  #endif

-)

-{

-  g_ErrStream = &g_StdErr;

-  g_StdStream = &g_StdOut;

-

-  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
+  {
+    #if 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
+    /*
+    __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 6e58c1f..1e7adf5 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 _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 b9270f8..c5b4b45 100644
--- a/CPP/7zip/UI/Console/OpenCallbackConsole.h
+++ b/CPP/7zip/UI/Console/OpenCallbackConsole.h
@@ -1,66 +1,68 @@
-// OpenCallbackConsole.h

-

-#ifndef __OPEN_CALLBACK_CONSOLE_H

-#define __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;

-

-  bool _totalFilesDefined;

-  // bool _totalBytesDefined;

-  // UInt64 _totalFiles;

-  UInt64 _totalBytes;

-

-  bool NeedPercents() const { return _percent._so != NULL; }

-

-public:

-

-  bool MultiArcMode;

-

-  void ClosePercents()

-  {

-    if (NeedPercents())

-      _percent.ClosePrint(true);

-  }

-

-  COpenCallbackConsole():

-      _totalFilesDefined(false),

-      // _totalBytesDefined(false),

-      _totalBytes(0),

-      MultiArcMode(false)

-      

-      #ifndef _NO_CRYPTO

-      , PasswordIsDefined(false)

-      // , PasswordWasAsked(false)

-      #endif

-      

-      {}

-  

-  void Init(CStdOutStream *outStream, CStdOutStream *errorStream, CStdOutStream *percentStream)

-  {

-    _so = outStream;

-    _se = errorStream;

-    _percent._so = percentStream;

-  }

-

-  INTERFACE_IOpenCallbackUI(;)

-  

-  #ifndef _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 != NULL; }
+
+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)
+  {
+    _so = outStream;
+    _se = errorStream;
+    _percent._so = percentStream;
+  }
+
+  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 20249ed..9d392ab 100644
--- a/CPP/7zip/UI/Console/PercentPrinter.cpp
+++ b/CPP/7zip/UI/Console/PercentPrinter.cpp
@@ -1,183 +1,184 @@
-// 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)

-    {

-      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 += ' ';

-    size++;

-  }

-

-  _s += s;

-}

-

-void CPercentPrinter::Print()

-{

-  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 += ' ';

-    _s += ' ';

-    _s += s;

-    // _s += "f";

-  }

-

-

-  if (!Command.IsEmpty())

-  {

-    _s += ' ';

-    _s += Command;

-  }

-

-  if (!FileName.IsEmpty() && _s.Len() < MaxLen)

-  {

-    _s += ' ';

-

-    _tempU = FileName;

-    _so->Normalize_UString(_tempU);

-    StdOut_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(_tempU);

-        StdOut_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()
+{
+  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(_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(_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 90b4083..4debb3b 100644
--- a/CPP/7zip/UI/Console/PercentPrinter.h
+++ b/CPP/7zip/UI/Console/PercentPrinter.h
@@ -1,62 +1,62 @@
-// PercentPrinter.h

-

-#ifndef __PERCENT_PRINTER_H

-#define __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 NeedFlush;

-  unsigned MaxLen;

-  

-  CPercentPrinter(UInt32 tickStep = 200):

-      _tickStep(tickStep),

-      _prevTick(0),

-      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
+{
+  UInt32 _tickStep;
+  DWORD _prevTick;
+
+  AString _s;
+
+  AString _printedString;
+  AString _temp;
+  UString _tempU;
+
+  CPercentPrinterState _printedState;
+  AString _printedPercents;
+
+  void GetPercents();
+
+public:
+  CStdOutStream *_so;
+
+  bool NeedFlush;
+  unsigned MaxLen;
+  
+  CPercentPrinter(UInt32 tickStep = 200):
+      _tickStep(tickStep),
+      _prevTick(0),
+      NeedFlush(true),
+      MaxLen(80 - 1)
+  {}
+
+  ~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 c6d3b1f..d0feea8 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 59d9ac1..035267c 100644
--- a/CPP/7zip/UI/Console/StdAfx.h
+++ b/CPP/7zip/UI/Console/StdAfx.h
@@ -1,8 +1,11 @@
-// StdAfx.h

-

-#ifndef __STDAFX_H

-#define __STDAFX_H

-

-#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 46ffaba..85496f5 100644
--- a/CPP/7zip/UI/Console/UpdateCallbackConsole.cpp
+++ b/CPP/7zip/UI/Console/UpdateCallbackConsole.cpp
@@ -1,702 +1,885 @@
-// UpdateCallbackConsole.cpp

-

-#include "StdAfx.h"

-

-#include "../../../Common/IntToString.h"

-

-#include "../../../Windows/ErrorMsg.h"

-

-#ifndef _7ZIP_ST

-#include "../../../Windows/Synchronization.h"

-#endif

-

-#include "ConsoleClose.h"

-#include "UserInputUtils.h"

-#include "UpdateCallbackConsole.h"

-

-using namespace NWindows;

-

-#ifndef _7ZIP_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(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(fs2us(path));

-    *_se << endl << 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);

-  /*

-  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 (_so)

-  {

-    *_so << (updating ? kUpdatingArchiveMessage : kCreatingArchiveMessage);

-    if (name)

-      _so->NormalizePrint_wstr(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);

-    s.Add_LF();

-    s += "Archive size: ";

-    PrintSize_bytes_Smart(s, st.OutArcFileSize);

-    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(_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, 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;

-      _so->Normalize_UString(_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();

-}

-

-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, 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)

-{

-  MT_LOCK

-  _percent.Files++;

-  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(name);

-      *_se << endl << endl;

-      _se->Flush();

-    }

-    return S_OK;

-  }

-  return S_OK;

-}

-

-

-HRESULT CUpdateCallbackConsole::ReportUpdateOpeartion(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;

-    default:

-    {

-      temp[0] = 'o';

-      temp[1] = 'p';

-      ConvertUInt64ToString(op, temp + 2);

-      s = temp;

-    }

-  }

-

-  return PrintProgress(name, s, LogLevel >= requiredLevel);

-}

-

-/*

-HRESULT CUpdateCallbackConsole::SetPassword(const UString &

-    #ifndef _NO_CRYPTO

-    password

-    #endif

-    )

-{

-  #ifndef _NO_CRYPTO

-  PasswordIsDefined = true;

-  Password = password;

-  #endif

-  return S_OK;

-}

-*/

-

-HRESULT CUpdateCallbackConsole::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password)

-{

-  COM_TRY_BEGIN

-

-  *password = NULL;

-

-  #ifdef _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 _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, "D", true);

-  }

-  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(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(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(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(_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(_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(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 6765db6..b6c1be4 100644
--- a/CPP/7zip/UI/Console/UpdateCallbackConsole.h
+++ b/CPP/7zip/UI/Console/UpdateCallbackConsole.h
@@ -1,124 +1,133 @@
-// UpdateCallbackConsole.h

-

-#ifndef __UPDATE_CALLBACK_CONSOLE_H

-#define __UPDATE_CALLBACK_CONSOLE_H

-

-#include "../../../Common/StdOutStream.h"

-

-#include "../Common/Update.h"

-

-#include "PercentPrinter.h"

-

-struct CErrorPathCodes

-{

-  FStringVector Paths;

-  CRecordVector<DWORD> 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);

-  

-  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)

-      {}

-  

-  void SetWindowWidth(unsigned width) { _percent.MaxLen = width - 1; }

-

-  void Init(CStdOutStream *outStream, CStdOutStream *errorStream, CStdOutStream *percentStream)

-  {

-    FailedFiles.Clear();

-

-    _so = outStream;

-    _se = errorStream;

-    _percent._so = percentStream;

-  }

-

-  void ClosePercents2()

-  {

-    if (NeedPercents())

-      _percent.ClosePrint(true);

-  }

-

-  void ClosePercents_for_so()

-  {

-    if (NeedPercents() && _so == _percent._so)

-      _percent.ClosePrint(false);

-  }

-

-

-  CErrorPathCodes FailedFiles;

-  CErrorPathCodes ScanErrors;

-

-  HRESULT PrintProgress(const wchar_t *name, const char *command, bool showInLog);

-

-};

-

-class CUpdateCallbackConsole: public IUpdateCallbackUI2, public CCallbackConsoleBase

-{

-  // void PrintPropPair(const char *name, const wchar_t *val);

-

-public:

-  #ifndef _NO_CRYPTO

-  bool PasswordIsDefined;

-  UString Password;

-  bool AskPassword;

-  #endif

-

-  bool DeleteMessageWasShown;

-

-  CUpdateCallbackConsole()

-      : DeleteMessageWasShown(false)

-      #ifndef _NO_CRYPTO

-      , PasswordIsDefined(false)

-      , AskPassword(false)

-      #endif

-      {}

-  

-  /*

-  void Init(CStdOutStream *outStream)

-  {

-    CCallbackConsoleBase::Init(outStream);

-  }

-  */

-  // ~CUpdateCallbackConsole() { if (NeedPercents()) _percent.ClosePrint(); }

-  INTERFACE_IUpdateCallbackUI2(;)

-};

-

-#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<DWORD> 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)
+  {
+    FailedFiles.Clear();
+
+    _so = outStream;
+    _se = errorStream;
+    _percent._so = percentStream;
+  }
+
+  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
diff --git a/CPP/7zip/UI/Console/UserInputUtils.cpp b/CPP/7zip/UI/Console/UserInputUtils.cpp
index 7bdafda..04d675e 100644
--- a/CPP/7zip/UI/Console/UserInputUtils.cpp
+++ b/CPP/7zip/UI/Console/UserInputUtils.cpp
@@ -1,110 +1,117 @@
-// 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;

-      }

-  }

-}

-

-#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

-  

-  HANDLE console = GetStdHandle(STD_INPUT_HANDLE);

-  bool wasChanged = false;

-  DWORD mode = 0;

-  if (console != INVALID_HANDLE_VALUE && console != 0)

-    if (GetConsoleMode(console, &mode))

-      wasChanged = (SetConsoleMode(console, mode & ~ENABLE_ECHO_INPUT) != 0);

-  bool res = g_StdIn.ScanUStringUntilNewLine(psw);

-  if (wasChanged)

-    SetConsoleMode(console, mode);

-  

-  #else

-  

-  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;
+      }
+  }
+}
+
+#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 ebe09c1..695a3e6 100644
--- a/CPP/7zip/UI/Console/UserInputUtils.h
+++ b/CPP/7zip/UI/Console/UserInputUtils.h
@@ -1,27 +1,27 @@
-// UserInputUtils.h

-

-#ifndef __USER_INPUT_UTILS_H

-#define __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 2210e0b..a20b0cc 100644
--- a/CPP/7zip/UI/Console/makefile
+++ b/CPP/7zip/UI/Console/makefile
@@ -1,64 +1,68 @@
-PROG = 7z.exe

-CFLAGS = $(CFLAGS)  \

-  -DEXTERNAL_CODECS \

-

-COMMON_OBJS = \

-  $O\CommandLineParser.obj \

-  $O\CRC.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\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 \

-

-AR_COMMON_OBJS = \

-  $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
new file mode 100644
index 0000000..8a293d8
--- /dev/null
+++ b/CPP/7zip/UI/Console/makefile.gcc
@@ -0,0 +1,186 @@
+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_WIN=
+
+ifdef IS_MINGW
+
+LOCAL_FLAGS_WIN = \
+  -DZ7_LARGE_PAGES \
+  -DZ7_LONG_PATH \
+  -DZ7_DEVICE_FILE \
+
+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_WIN) \
+  $(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 8d721f5..414427f 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
new file mode 100644
index 0000000..cba1c5d
--- /dev/null
+++ b/CPP/7zip/UI/Explorer/7-zip.dll.manifest
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?><assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"><assemblyIdentity version="1.0.0.0" processorArchitecture="*" name="7-Zip.7-Zip.7-zip" type="win32"/><description>7-Zip Extension.</description><dependency> <dependentAssembly><assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"/></dependentAssembly></dependency></assembly>
diff --git a/CPP/7zip/UI/Explorer/ContextMenu.cpp b/CPP/7zip/UI/Explorer/ContextMenu.cpp
new file mode 100644
index 0000000..7815e13
--- /dev/null
+++ b/CPP/7zip/UI/Explorer/ContextMenu.cpp
@@ -0,0 +1,1822 @@
+// 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 <stdio.h>
+#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_SHA1,   "SHA-1",   "SHA1" },
+  { CZipContextMenu::kHash_SHA256, "SHA-256", "SHA256" },
+  { 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<CZipContextMenu::CCommandMapItem> &_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"
+  " wav 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();
+  if (dotPos < 0 || dotPos == (int)name.Len() - 1)
+    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])
+  }
+  */
+
+  if (_fileNames.Size() == 0)
+  {
+    return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 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(SEVERITY_SUCCESS, 0, currentCommandID - commandIDFirst);
+  // return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 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(SEVERITY_SUCCESS, 0, _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_SHA1:
+      case kHash_SHA256:
+      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<IShellItem> 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
new file mode 100644
index 0000000..3f25f6a
--- /dev/null
+++ b/CPP/7zip/UI/Explorer/ContextMenu.h
@@ -0,0 +1,167 @@
+// 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_SHA1,
+    kHash_SHA256,
+    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<CCommandMapItem> _commandMap;
+  CObjectVector<CCommandMapItem> _commandMap_Cur;
+
+  HBITMAP _bitmap;
+  UInt32 _writeZone;
+  CBoolPair _elimDup;
+
+  bool IsSeparator;
+  bool IsRoot;
+  CObjectVector< CMyComPtr<IExplorerCommand> > 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
new file mode 100644
index 0000000..50c177e
--- /dev/null
+++ b/CPP/7zip/UI/Explorer/ContextMenuFlags.h
@@ -0,0 +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
diff --git a/CPP/7zip/UI/Explorer/DllExportsExplorer.cpp b/CPP/7zip/UI/Explorer/DllExportsExplorer.cpp
new file mode 100644
index 0000000..7307b07
--- /dev/null
+++ b/CPP/7zip/UI/Explorer/DllExportsExplorer.cpp
@@ -0,0 +1,264 @@
+// 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
+// <olectl.h> : in new Windows Kit 10.0.2**** (NTDDI_WIN10_MN is defined)
+// <OleCtl.h> : in another Windows Kit versions
+#if defined(NTDDI_WIN10_MN) || defined(__MINGW32__) || defined(__MINGW64__)
+#include <olectl.h>
+#else
+#include <OleCtl.h>
+#endif
+
+#if defined(__MINGW32__) || defined(__MINGW64__)
+#include <shlguid.h>
+#else
+#include <ShlGuid.h>
+#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.
+
+
+// #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
new file mode 100644
index 0000000..034a269
--- /dev/null
+++ b/CPP/7zip/UI/Explorer/Explorer.def
@@ -0,0 +1,9 @@
+; 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
new file mode 100644
index 0000000..ff8503b
--- /dev/null
+++ b/CPP/7zip/UI/Explorer/Explorer.dsp
@@ -0,0 +1,612 @@
+# 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\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
new file mode 100644
index 0000000..beb8df7
--- /dev/null
+++ b/CPP/7zip/UI/Explorer/Explorer.dsw
@@ -0,0 +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>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/CPP/7zip/UI/Explorer/MenuLogo.bmp b/CPP/7zip/UI/Explorer/MenuLogo.bmp
new file mode 100644
index 0000000..906a6c5
--- /dev/null
+++ b/CPP/7zip/UI/Explorer/MenuLogo.bmp
Binary files differ
diff --git a/CPP/7zip/UI/Explorer/MyExplorerCommand.h b/CPP/7zip/UI/Explorer/MyExplorerCommand.h
new file mode 100644
index 0000000..11ac247
--- /dev/null
+++ b/CPP/7zip/UI/Explorer/MyExplorerCommand.h
@@ -0,0 +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 <shobjidl_core.h>
+
+#else
+
+/* IShellItem is defined:
+    ShObjIdl.h      : old Windows SDK
+    ShObjIdl_core.h : new Windows 10 SDK */
+
+#ifndef Z7_OLD_WIN_SDK
+#include <ShObjIdl.h>
+#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 _tagpropertykey
+{
+  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
+
+
+// <shobjidl_core.h>
+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 1ef0d9c..daff7de 100644
--- a/CPP/7zip/UI/Explorer/MyMessages.cpp
+++ b/CPP/7zip/UI/Explorer/MyMessages.cpp
@@ -1,37 +1,40 @@
-// MyMessages.cpp

-

-#include "StdAfx.h"

-

-#include "MyMessages.h"

-

-#include "../../../Windows/ErrorMsg.h"

-#include "../../../Windows/ResourceString.h"

-

-#include "../FileManager/LangUtils.h"

-

-using namespace NWindows;

-

-void ShowErrorMessage(HWND window, LPCWSTR message)

-{

-  ::MessageBoxW(window, message, L"7-Zip", MB_OK | MB_ICONSTOP);

-}

-

-void ShowErrorMessageHwndRes(HWND window, UINT resID)

-{

-  ShowErrorMessage(window, LangString(resID));

-}

-

-void ShowErrorMessageRes(UINT resID)

-{

-  ShowErrorMessageHwndRes(0, resID);

-}

-

-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;
+
+void ShowErrorMessage(HWND window, LPCWSTR message)
+{
+  ::MessageBoxW(window, message, L"7-Zip", MB_OK | MB_ICONSTOP);
+}
+
+void ShowErrorMessageHwndRes(HWND window, UINT resID)
+{
+  UString s = LangString(resID);
+  if (s.IsEmpty())
+    s.Add_UInt32(resID);
+  ShowErrorMessage(window, s);
+}
+
+void ShowErrorMessageRes(UINT 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 c175e8a..47d10db 100644
--- a/CPP/7zip/UI/Explorer/MyMessages.h
+++ b/CPP/7zip/UI/Explorer/MyMessages.h
@@ -1,16 +1,16 @@
-// MyMessages.h

-

-#ifndef __MY_MESSAGES_H

-#define __MY_MESSAGES_H

-

-#include "../../../Common/MyString.h"

-

-void ShowErrorMessage(HWND window, LPCWSTR message);

-inline void ShowErrorMessage(LPCWSTR message) { ShowErrorMessage(0, message); }

-

-void ShowErrorMessageHwndRes(HWND window, UInt32 langID);

-void ShowErrorMessageRes(UInt32 langID);

-

-void ShowLastErrorMessage(HWND window = 0);

-

-#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
new file mode 100644
index 0000000..bc03d6a
--- /dev/null
+++ b/CPP/7zip/UI/Explorer/RegistryContextMenu.cpp
@@ -0,0 +1,227 @@
+// 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 }
+};
+
+
+// can we use static RegDeleteKeyExW in _WIN64 mode?
+// is it supported by Windows 2003 x64?
+
+/*
+#ifdef _WIN64
+
+#define INIT_REG_WOW
+
+#else
+*/
+
+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();
+
+// #endif
+
+static LONG MyRegistry_DeleteKey(HKEY parentKey, LPCTSTR name, UInt32 wow)
+{
+  if (wow == 0)
+    return RegDeleteKey(parentKey, name);
+  
+  /*
+  #ifdef _WIN64
+  return RegDeleteKeyExW
+  #else
+  */
+  if (!func_RegDeleteKeyExW)
+    return E_NOTIMPL;
+  return func_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
new file mode 100644
index 0000000..bf3bb5b
--- /dev/null
+++ b/CPP/7zip/UI/Explorer/RegistryContextMenu.h
@@ -0,0 +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
diff --git a/CPP/7zip/UI/Explorer/StdAfx.cpp b/CPP/7zip/UI/Explorer/StdAfx.cpp
new file mode 100644
index 0000000..d0feea8
--- /dev/null
+++ b/CPP/7zip/UI/Explorer/StdAfx.cpp
@@ -0,0 +1,3 @@
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/CPP/7zip/UI/Explorer/StdAfx.h b/CPP/7zip/UI/Explorer/StdAfx.h
new file mode 100644
index 0000000..130db8a
--- /dev/null
+++ b/CPP/7zip/UI/Explorer/StdAfx.h
@@ -0,0 +1,6 @@
+// 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
new file mode 100644
index 0000000..da63a5c
--- /dev/null
+++ b/CPP/7zip/UI/Explorer/makefile
@@ -0,0 +1,76 @@
+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
+!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\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
new file mode 100644
index 0000000..bbb28b1
--- /dev/null
+++ b/CPP/7zip/UI/Explorer/resource.h
@@ -0,0 +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
diff --git a/CPP/7zip/UI/Explorer/resource.rc b/CPP/7zip/UI/Explorer/resource.rc
new file mode 100644
index 0000000..acfa6e5
--- /dev/null
+++ b/CPP/7zip/UI/Explorer/resource.rc
@@ -0,0 +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"
diff --git a/CPP/7zip/UI/Explorer/resource2.rc b/CPP/7zip/UI/Explorer/resource2.rc
new file mode 100644
index 0000000..de34824
--- /dev/null
+++ b/CPP/7zip/UI/Explorer/resource2.rc
@@ -0,0 +1,19 @@
+#include "resource.h"
+
+STRINGTABLE
+BEGIN
+  IDS_CONTEXT_FOLDER      "<Folder>"
+  IDS_CONTEXT_ARCHIVE     "<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
new file mode 100644
index 0000000..05e9208
--- /dev/null
+++ b/CPP/7zip/UI/Far/ExtractEngine.cpp
@@ -0,0 +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);
+}
diff --git a/CPP/7zip/UI/Far/ExtractEngine.h b/CPP/7zip/UI/Far/ExtractEngine.h
new file mode 100644
index 0000000..2bee2ee
--- /dev/null
+++ b/CPP/7zip/UI/Far/ExtractEngine.h
@@ -0,0 +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
diff --git a/CPP/7zip/UI/Far/Far.cpp b/CPP/7zip/UI/Far/Far.cpp
new file mode 100644
index 0000000..74d5e60
--- /dev/null
+++ b/CPP/7zip/UI/Far/Far.cpp
@@ -0,0 +1,587 @@
+// 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<IInFolderArchive> archiveHandler;
+
+  // CArchiverInfo archiverInfoResult;
+  // ::OutputDebugStringA("before OpenArchive\n");
+  
+  CScreenRestorer screenRestorer;
+  {
+    screenRestorer.Save();
+  }
+
+  COpenArchiveCallback *openArchiveCallbackSpec = new COpenArchiveCallback;
+  CMyComPtr<IArchiveOpenCallback> uiCallback = openArchiveCallbackSpec;
+
+  /* COpenCallbackImp object will exist after Open stage for multivolume archioves */
+  COpenCallbackImp *impSpec = new COpenCallbackImp;
+  CMyComPtr<IArchiveOpenCallback> 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 unsigned char * /* 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 unsigned char *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> 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<char *>(g_StartupInfo.GetMsgString(NMessageID::kOpenArchiveMenuString));
+  pluginMenuStrings[1] = const_cast<char *>(g_StartupInfo.GetMsgString(NMessageID::kCreateArchiveMenuString));
+  info->PluginMenuStrings = (char **)pluginMenuStrings;
+  info->PluginMenuStringsNumber = 2;
+  static char *pluginCfgStrings[1];
+  pluginCfgStrings[0] = const_cast<char *>(g_StartupInfo.GetMsgString(NMessageID::kOpenArchiveMenuString));
+  info->PluginConfigStrings = (char **)pluginCfgStrings;
+  info->PluginConfigStringsNumber = Z7_ARRAY_SIZE(pluginCfgStrings);
+  info->CommandPrefix = const_cast<char *>(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 int 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
new file mode 100644
index 0000000..1de9acd
--- /dev/null
+++ b/CPP/7zip/UI/Far/Far.def
@@ -0,0 +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
diff --git a/CPP/7zip/UI/Far/Far.dsp b/CPP/7zip/UI/Far/Far.dsp
new file mode 100644
index 0000000..823c728
--- /dev/null
+++ b/CPP/7zip/UI/Far/Far.dsp
@@ -0,0 +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
diff --git a/CPP/7zip/UI/Far/Far.dsw b/CPP/7zip/UI/Far/Far.dsw
new file mode 100644
index 0000000..f4ef080
--- /dev/null
+++ b/CPP/7zip/UI/Far/Far.dsw
@@ -0,0 +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>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/CPP/7zip/UI/Far/FarPlugin.h b/CPP/7zip/UI/Far/FarPlugin.h
new file mode 100644
index 0000000..ad3ed38
--- /dev/null
+++ b/CPP/7zip/UI/Far/FarPlugin.h
@@ -0,0 +1,560 @@
+// FarPlugin.h
+
+// #include "plugin.hpp"
+
+const int kInfoPanelLineSize = 80;
+
+// #define __FAR_PLUGIN_H
+
+#ifdef UNDER_CE
+typedef struct _CHAR_INFO {
+    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 int 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 int 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 int 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 int 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 int 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 int 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 unsigned char *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 int 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
new file mode 100644
index 0000000..9fddbc1
--- /dev/null
+++ b/CPP/7zip/UI/Far/FarUtils.cpp
@@ -0,0 +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(unsigned int 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<char *>(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 int)Init[i].Data < 0xFFF)
+      MyStringCopy(destItem.Data, GetMsg((unsigned int)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<PluginPanelItem> &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 int 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<char *>(title),
+      const_cast<char *>(aBottom),
+      const_cast<char *>(helpTopic),
+      breakKeys, breakCode, items, (int)numItems);
+}
+
+int CStartupInfo::Menu(
+    unsigned int 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 int flags,
+    const char *title,
+    const char *helpTopic,
+    const AStringVector &items,
+    int selectedItem)
+{
+  CRecordVector<FarMenuItem> 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.Front(), 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
new file mode 100644
index 0000000..6e6ff3c
--- /dev/null
+++ b/CPP/7zip/UI/Far/FarUtils.h
@@ -0,0 +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;
+  unsigned int 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(unsigned int 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<PluginPanelItem> &pluginPanelItems);
+
+  bool ControlClearPanelSelection();
+
+  int Menu(
+      int x,
+      int y,
+      int maxHeight,
+      unsigned int flags,
+      const char *title,
+      const char *aBottom,
+      const char *helpTopic,
+      int *breakKeys,
+      int *breakCode,
+      FarMenuItem *items,
+      unsigned numItems);
+  int Menu(
+      unsigned int flags,
+      const char *title,
+      const char *helpTopic,
+      FarMenuItem *items,
+      unsigned numItems);
+
+  int Menu(
+      unsigned int 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<char *>(fileName), const_cast<char *>(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<char *>(fileName), const_cast<char *>(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
new file mode 100644
index 0000000..f6b20a3
--- /dev/null
+++ b/CPP/7zip/UI/Far/Messages.h
@@ -0,0 +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
diff --git a/CPP/7zip/UI/Far/OverwriteDialogFar.cpp b/CPP/7zip/UI/Far/OverwriteDialogFar.cpp
new file mode 100644
index 0000000..a45d2b2
--- /dev/null
+++ b/CPP/7zip/UI/Far/OverwriteDialogFar.cpp
@@ -0,0 +1,145 @@
+// OverwriteDialogFar.cpp
+
+#include "StdAfx.h"
+
+#include <stdio.h>
+
+#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[32];
+    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
new file mode 100644
index 0000000..bc6e92b
--- /dev/null
+++ b/CPP/7zip/UI/Far/OverwriteDialogFar.h
@@ -0,0 +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
diff --git a/CPP/7zip/UI/Far/Plugin.cpp b/CPP/7zip/UI/Far/Plugin.cpp
new file mode 100644
index 0000000..fe6fcce
--- /dev/null
+++ b/CPP/7zip/UI/Far/Plugin.cpp
@@ -0,0 +1,939 @@
+// 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<IFolderFolder> 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<IFolderFolder> 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<IFolderFolder> folderItem = _folder;
+  for (;;)
+  {
+    CMyComPtr<IFolderFolder> 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 += ':';
+  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<IFolderProperties> 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<IGetFolderArcProps> getFolderArcProps;
+    _folder.QueryInterface(IID_IGetFolderArcProps, &getFolderArcProps);
+    if (getFolderArcProps)
+    {
+      CMyComPtr<IFolderArcProps> 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_Upper(unsigned v)
+{
+  return (char)((v < 10) ? ('0' + v) : ('A' + (v - 10)));
+}
+
+static inline char GetHex_Lower(unsigned v)
+{
+  return (char)((v < 10) ? ('0' + v) : ('a' + (v - 10)));
+}
+
+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<CArchiveItemProperty> 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<CInitDialogItem> 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<IArchiveGetRawProps> _folderRawProps;
+  _folder.QueryInterface(IID_IArchiveGetRawProps, &_folderRawProps);
+
+  CObjectVector<CArchiveItemProperty> 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 bool needUpper = (dataSize <= 8)
+                && (property.ID == kpidCRC || property.ID == kpidChecksum);
+            for (UInt32 k = 0; k < dataSize; k++)
+            {
+              unsigned b = ((const Byte *)data)[k];
+              if (needUpper)
+              {
+                s += GetHex_Upper((b >> 4) & 0xF);
+                s += GetHex_Upper(b & 0xF);
+              }
+              else
+              {
+                s += GetHex_Lower((b >> 4) & 0xF);
+                s += GetHex_Lower(b & 0xF);
+              }
+            }
+          }
+        }
+
+        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<FarDialogItem> dialogItems(numDialogItems);
+  g_StartupInfo.InitDialogItems(&initDialogItems.Front(), 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 int 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
new file mode 100644
index 0000000..00ccc81
--- /dev/null
+++ b/CPP/7zip/UI/Far/Plugin.h
@@ -0,0 +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<IInFolderArchive> m_ArchiveHandler;
+  CMyComPtr<IFolderFolder> _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 int controlState);
+};
+
+HRESULT CompressFiles(const CObjectVector<PluginPanelItem> &pluginPanelItems);
+
+#endif
diff --git a/CPP/7zip/UI/Far/PluginCommon.cpp b/CPP/7zip/UI/Far/PluginCommon.cpp
new file mode 100644
index 0000000..e1d4458
--- /dev/null
+++ b/CPP/7zip/UI/Far/PluginCommon.cpp
@@ -0,0 +1,50 @@
+// SevenZip/Plugin.cpp
+
+#include "StdAfx.h"
+
+#include "Plugin.h"
+
+/*
+void CPlugin::AddRealIndexOfFile(const CArchiveFolderItem &aFolder,
+    int anIndexInVector, vector<int> &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<int> &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<int> &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
new file mode 100644
index 0000000..fdade1a
--- /dev/null
+++ b/CPP/7zip/UI/Far/PluginDelete.cpp
@@ -0,0 +1,144 @@
+// PluginDelete.cpp
+
+#include "StdAfx.h"
+
+#include <stdio.h>
+
+#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<UInt32> indices(numItems);
+  unsigned i;
+  for (i = 0; i < numItems; i++)
+    indices[i] = (UInt32)panelItems[i].UserData;
+
+  /*
+  UStringVector pathVector;
+  GetPathParts(pathVector);
+  
+  CMyComPtr<IOutFolderArchive> 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<IFolderArchiveUpdateCallback> 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<IFolderOperations> 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
new file mode 100644
index 0000000..7e81ddd
--- /dev/null
+++ b/CPP/7zip/UI/Far/PluginRead.cpp
@@ -0,0 +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<IFolderArchiveExtractCallback> 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<IArchiveFolder> 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<int> realIndices;
+  if (!decompressAllItems)
+    GetRealIndexes(panelItems, itemsNumber, realIndices);
+  */
+  CObjArray<UInt32> 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
new file mode 100644
index 0000000..3f1fba8
--- /dev/null
+++ b/CPP/7zip/UI/Far/PluginWrite.cpp
@@ -0,0 +1,839 @@
+// PluginWrite.cpp
+
+#include "StdAfx.h"
+
+#include <stdio.h>
+
+#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<ISetProperties> setProperties;
+  if (outArchive->QueryInterface(IID_ISetProperties, (void **)&setProperties) == S_OK)
+  {
+    /*
+    UStringVector realNames;
+    realNames.Add(UString("x"));
+    NCOM::CPropVariant value = (UInt32)method;
+    CRecordVector<const wchar_t *> 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<IFolderFolder> 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<const wchar_t *> fileNamePointers(numItems);
+  for (i = 0; i < (unsigned)numItems; i++)
+    fileNamePointers[i] = fileNames[i];
+
+  CMyComPtr<IOutFolderArchive> 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<IFolderArchiveUpdateCallback> 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<IArchiveFolderInternal> 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:
+    {
+      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 += 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<PluginPanelItem> &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<ICompressCodecsInfo> 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<IOutFolderArchive> outArchive;
+
+  CMyComPtr<IInFolderArchive> 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<const wchar_t *> 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<IFolderArchiveUpdateCallback> 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<IFolderArchiveUpdateCallback> updateCallback(updateCallbackSpec);
+  
+  updateCallbackSpec->Init(/* m_ArchiveHandler, */ progressBoxPointer);
+  updateCallbackSpec->PasswordIsDefined = PasswordIsDefined;
+  updateCallbackSpec->Password = Password;
+
+  HRESULT result;
+  {
+    CMyComPtr<IFolderOperations> 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
new file mode 100644
index 0000000..ab25a10
--- /dev/null
+++ b/CPP/7zip/UI/Far/ProgressBox.cpp
@@ -0,0 +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;
+}
diff --git a/CPP/7zip/UI/Far/ProgressBox.h b/CPP/7zip/UI/Far/ProgressBox.h
new file mode 100644
index 0000000..6e8b487
--- /dev/null
+++ b/CPP/7zip/UI/Far/ProgressBox.h
@@ -0,0 +1,83 @@
+// 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
diff --git a/CPP/7zip/UI/Far/StdAfx.cpp b/CPP/7zip/UI/Far/StdAfx.cpp
new file mode 100644
index 0000000..d0feea8
--- /dev/null
+++ b/CPP/7zip/UI/Far/StdAfx.cpp
@@ -0,0 +1,3 @@
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/CPP/7zip/UI/Far/StdAfx.h b/CPP/7zip/UI/Far/StdAfx.h
new file mode 100644
index 0000000..035267c
--- /dev/null
+++ b/CPP/7zip/UI/Far/StdAfx.h
@@ -0,0 +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
diff --git a/CPP/7zip/UI/Far/UpdateCallbackFar.cpp b/CPP/7zip/UI/Far/UpdateCallbackFar.cpp
new file mode 100644
index 0000000..94f0a47
--- /dev/null
+++ b/CPP/7zip/UI/Far/UpdateCallbackFar.cpp
@@ -0,0 +1,237 @@
+// 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);
+}
diff --git a/CPP/7zip/UI/Far/UpdateCallbackFar.h b/CPP/7zip/UI/Far/UpdateCallbackFar.h
new file mode 100644
index 0000000..4ec5eed
--- /dev/null
+++ b/CPP/7zip/UI/Far/UpdateCallbackFar.h
@@ -0,0 +1,44 @@
+// 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<IInFolderArchive> _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
diff --git a/CPP/7zip/UI/Far/makefile b/CPP/7zip/UI/Far/makefile
new file mode 100644
index 0000000..f3809a8
--- /dev/null
+++ b/CPP/7zip/UI/Far/makefile
@@ -0,0 +1,106 @@
+PROG = 7-ZipFar.dll
+DEF_FILE = Far.def
+CFLAGS = $(CFLAGS)  \
+  -DZ7_EXTERNAL_CODECS \
+
+!IFNDEF UNDER_CE
+CFLAGS = $(CFLAGS) -DZ7_LONG_PATH
+!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
new file mode 100644
index 0000000..a5c2e2f
--- /dev/null
+++ b/CPP/7zip/UI/Far/resource.rc
@@ -0,0 +1,3 @@
+#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
new file mode 100644
index 0000000..69c7f0b
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/7zFM.exe.manifest
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
+  <assemblyIdentity version="1.0.0.0" processorArchitecture="*" name="7-Zip.7-Zip.7zFM" type="win32"/>
+  <description>7-Zip File Manager.</description>
+  <dependency>
+    <dependentAssembly><assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"/></dependentAssembly>
+  </dependency>
+<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"><application>
+<!-- Vista   --> <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
+<!-- Win 7   --> <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
+<!-- Win 8   --> <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
+<!-- Win 8.1 --> <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
+<!-- Win 10  --> <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
+</application></compatibility>
+  <asmv3:application>
+    <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
+      <dpiAware>true</dpiAware>
+    </asmv3:windowsSettings>
+  </asmv3:application>
+<application xmlns="urn:schemas-microsoft-com:asm.v3">
+<windowsSettings xmlns:ws2="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
+<ws2:longPathAware>true</ws2:longPathAware></windowsSettings></application>
+</assembly>
diff --git a/CPP/7zip/UI/FileManager/7zipLogo.ico b/CPP/7zip/UI/FileManager/7zipLogo.ico
new file mode 100644
index 0000000..973241c
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/7zipLogo.ico
Binary files differ
diff --git a/CPP/7zip/UI/FileManager/AboutDialog.cpp b/CPP/7zip/UI/FileManager/AboutDialog.cpp
new file mode 100644
index 0000000..efc74cc
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/AboutDialog.cpp
@@ -0,0 +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;
+}
diff --git a/CPP/7zip/UI/FileManager/AboutDialog.h b/CPP/7zip/UI/FileManager/AboutDialog.h
new file mode 100644
index 0000000..1d11d74
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/AboutDialog.h
@@ -0,0 +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
diff --git a/CPP/7zip/UI/FileManager/AboutDialog.rc b/CPP/7zip/UI/FileManager/AboutDialog.rc
new file mode 100644
index 0000000..b235df0
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/AboutDialog.rc
@@ -0,0 +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)
+}
diff --git a/CPP/7zip/UI/FileManager/AboutDialogRes.h b/CPP/7zip/UI/FileManager/AboutDialogRes.h
new file mode 100644
index 0000000..b416558
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/AboutDialogRes.h
@@ -0,0 +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
diff --git a/CPP/7zip/UI/FileManager/Add.bmp b/CPP/7zip/UI/FileManager/Add.bmp
new file mode 100644
index 0000000..a8577fc
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/Add.bmp
Binary files differ
diff --git a/CPP/7zip/UI/FileManager/Add2.bmp b/CPP/7zip/UI/FileManager/Add2.bmp
new file mode 100644
index 0000000..252fc25
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/Add2.bmp
Binary files differ
diff --git a/CPP/7zip/UI/FileManager/AltStreamsFolder.cpp b/CPP/7zip/UI/FileManager/AltStreamsFolder.cpp
new file mode 100644
index 0000000..b3d354d
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/AltStreamsFolder.cpp
@@ -0,0 +1,952 @@
+// AltStreamsFolder.cpp
+
+#include "StdAfx.h"
+
+#ifdef __MINGW32_VERSION
+// #if !defined(_MSC_VER) && (__GNUC__) && (__GNUC__ < 10)
+// for old mingw
+#include <ddk/ntddk.h>
+#else
+#ifndef Z7_OLD_WIN_SDK
+  #if !defined(_M_IA64)
+    #include <winternl.h>
+  #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<IFolderFolder> parentFolder = _parentFolder;
+    *resultFolder = parentFolder.Detach();
+    return S_OK;
+  }
+  */
+
+  if (IsDriveRootPath_SuperAllowed(_pathBaseFile))
+  {
+    CFSDrives *drivesFolderSpec = new CFSDrives;
+    CMyComPtr<IFolderFolder> 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<IFolderFolder> 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<IFolderFolder> netFolder = netFolderSpec;
+    netFolderSpec->Init(fs2us(parentPath));
+    *resultFolder = netFolder.Detach();
+    return S_OK;
+  }
+  #endif
+  
+  CFSFolder *parentFolderSpec = new CFSFolder;
+  CMyComPtr<IFolderFolder> 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;
+    }
+
+    DWORD waitResult = ::WaitForSingleObject(_findChangeNotification, 0);
+    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<IFolderFolder> 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(absPath, false))
+    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_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<IFolderArchiveUpdateCallback> 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];
+  *iconIndex = 0;
+  int iconIndexTemp;
+  if (GetRealIconIndex(_pathPrefix + us2fs(ss.Name),
+    0 // fi.Attrib
+    , iconIndexTemp) != 0)
+  {
+    *iconIndex = iconIndexTemp;
+    return S_OK;
+  }
+  return GetLastError_noZero_HRESULT();
+}
+
+/*
+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<IGetProp> 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<ISequentialOutStream> 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<IFolderArchiveUpdateCallback> 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
new file mode 100644
index 0000000..ccb6d6f
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/AltStreamsFolder.h
@@ -0,0 +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<CAltStream> Streams;
+  // CMyComPtr<IFolderFolder> _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
new file mode 100644
index 0000000..3461c92
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/App.cpp
@@ -0,0 +1,998 @@
+// 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 DWORD g_ComCtl32Version;
+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<UInt32> &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<UInt32> 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.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<IFolderFolder> 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
new file mode 100644
index 0000000..fc54501
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/App.h
@@ -0,0 +1,306 @@
+// 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<IDropTarget> _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)
+  {
+    unsigned i;
+    for (i = 0; i < kNumPanelsMax; i++)
+    {
+      CPanel &panel = Panels[i];
+      panel._timestampLevel = level;
+      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
new file mode 100644
index 0000000..6630b96
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/AppState.h
@@ -0,0 +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
diff --git a/CPP/7zip/UI/FileManager/BrowseDialog.cpp b/CPP/7zip/UI/FileManager/BrowseDialog.cpp
index d5c981c..5170302 100644
--- a/CPP/7zip/UI/FileManager/BrowseDialog.cpp
+++ b/CPP/7zip/UI/FileManager/BrowseDialog.cpp
@@ -1,1025 +1,1088 @@
-// BrowseDialog.cpp

- 

-#include "StdAfx.h"

-

-#include "../../../Common/MyWindows.h"

-

-#include <commctrl.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 <commdlg.h>

-#endif

-

-#include "BrowseDialog.h"

-

-#define USE_MY_BROWSE_DIALOG

-

-#ifdef USE_MY_BROWSE_DIALOG

-

-#include "../../../Common/Defs.h"

-#include "../../../Common/IntToString.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 _SFX

-#include "RegistryUtils.h"

-#endif

-

-#endif

-

-#include "ComboDialog.h"

-#include "LangUtils.h"

-

-#include "resource.h"

-

-using namespace NWindows;

-using namespace NFile;

-using namespace NName;

-using namespace NFind;

-

-#ifdef USE_MY_BROWSE_DIALOG

-

-extern bool g_LVN_ITEMACTIVATE_Support;

-

-static const int kParentIndex = -1;

-static const UINT k_Message_RefreshPathEdit = WM_APP + 1;

-

-static HRESULT GetNormalizedError()

-{

-  DWORD errorCode = GetLastError();

-  return errorCode == 0 ? E_FAIL : errorCode;

-}

-

-extern UString HResultToMessage(HRESULT errorCode);

-

-static void MessageBox_Error_Global(HWND wnd, const wchar_t *message)

-{

-  ::MessageBoxW(wnd, message, L"7-Zip", MB_ICONERROR);

-}

-

-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<CFileInfo> _files;

-

-  CExtToIconMap _extToIconMap;

-  int _sortIndex;

-  bool _ascending;

-  bool _showDots;

-  UString _topDirPrefix; // we don't open parent of that folder

-  UString DirPrefix;

-

-  virtual bool OnInit();

-  virtual bool OnSize(WPARAM wParam, int xSize, int ySize);

-  virtual bool OnMessage(UINT message, WPARAM wParam, LPARAM lParam);

-  virtual bool OnNotify(UINT controlID, LPNMHDR header);

-  virtual bool OnKeyDown(LPNMLVKEYDOWN keyDownInfo);

-  virtual bool OnButtonClicked(int buttonID, HWND buttonHWND);

-  virtual void OnOK();

-

-  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(indexInListView, param))

-      return (int)-1;

-    return (int)param;

-  }

-

-public:

-  bool FolderMode;

-  UString Title;

-  UString FilePath;  // input/ result path

-  bool ShowAllFiles;

-  UStringVector Filters;

-  UString FilterDescription;

-

-  CBrowseDialog(): FolderMode(false), _showDots(false), ShowAllFiles(true) {}

-  void SetFilter(const UString &s);

-  INT_PTR Create(HWND parent = 0) { return CModalDialog::Create(IDD_BROWSE, parent); }

-  int CompareItems(LPARAM lParam1, LPARAM lParam2);

-};

-

-void CBrowseDialog::SetFilter(const UString &s)

-{

-  Filters.Clear();

-  UString mask;

-  unsigned i;

-  for (i = 0; i < s.Len(); i++)

-  {

-    wchar_t c = s[i];

-    if (c == ';')

-    {

-      if (!mask.IsEmpty())

-        Filters.Add(mask);

-      mask.Empty();

-    }

-    else

-      mask += c;

-  }

-  if (!mask.IsEmpty())

-    Filters.Add(mask);

-  ShowAllFiles = Filters.IsEmpty();

-  for (i = 0; i < Filters.Size(); i++)

-  {

-    const UString &f = Filters[i];

-    if (f == L"*.*" || f == L"*")

-    {

-      ShowAllFiles = true;

-      break;

-    }

-  }

-}

-

-bool CBrowseDialog::OnInit()

-{

-  #ifdef 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));

-

-  if (FolderMode)

-    HideItem(IDC_BROWSE_FILTER);

-  else

-    EnableItem(IDC_BROWSE_FILTER, false);

-

-  #ifndef UNDER_CE

-  _list.SetUnicodeFormat();

-  #endif

-

-  #ifndef _SFX

-  CFmSettings st;

-  st.Load();

-  if (st.SingleClick)

-    _list.SetExtendedListViewStyle(LVS_EX_ONECLICKACTIVATE | LVS_EX_TRACKSELECT);

-  _showDots = st.ShowDots;

-  #endif

-

-  {

-    UString s;

-    if (!FilterDescription.IsEmpty())

-      s = FilterDescription;

-    else if (ShowAllFiles)

-      s = "*.*";

-    else

-    {

-      FOR_VECTOR (i, Filters)

-      {

-        if (i != 0)

-          s.Add_Space();

-        s += Filters[i];

-      }

-    }

-    _filterCombo.AddString(s);

-    _filterCombo.SetCurSel(0);

-  }

-

-  _list.SetImageList(GetSysImageList(true), LVSIL_SMALL);

-  _list.SetImageList(GetSysImageList(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 = (wchar_t *)(const wchar_t *)s;

-    _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();

-  {

-    int 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(MY__WM_UPDATEUISTATE, MAKEWPARAM(MY__UIS_CLEAR, MY__UISF_HIDEFOCUS));

-  #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::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: // probabably it's unused

-      if (!g_LVN_ITEMACTIVATE_Support)

-        OnItemEnter();

-      break;

-    case LVN_COLUMNCLICK:

-    {

-      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)

-{

-  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(int 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;

-  int pos = s.ReverseFind_PathSepar();

-  parentPrefix.SetFrom(s, pos + 1);

-  name = s.Ptr(pos + 1);

-  return true;

-}

-

-int CBrowseDialog::CompareItems(LPARAM lParam1, LPARAM lParam2)

-{

-  if (lParam1 == kParentIndex) return -1;

-  if (lParam2 == kParentIndex) return 1;

-  const CFileInfo &f1 = _files[(int)lParam1];

-  const CFileInfo &f2 = _files[(int)lParam2];

-

-  bool isDir1 = f1.IsDir();

-  bool isDir2 = f2.IsDir();

-  if (isDir1 && !isDir2) return -1;

-  if (isDir2 && !isDir1) 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);

-}

-

-static void ConvertSizeToString(UInt64 v, wchar_t *s)

-{

-  Byte 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'; }

-  ConvertUInt64ToString(v, s);

-  if (c != 0)

-  {

-    s += MyStringLen(s);

-    *s++ = ' ';

-    *s++ = c;

-    *s++ = 0;

-  }

-}

-

-// Reload changes DirPrefix. Don't send DirPrefix in pathPrefix parameter

-

-HRESULT CBrowseDialog::Reload(const UString &pathPrefix, const UString &selectedName)

-{

-  CObjectVector<CFileInfo> files;

-  

-  #ifndef UNDER_CE

-  bool isDrive = false;

-  if (pathPrefix.IsEmpty() || pathPrefix.IsEqualTo(kSuperPathPrefix))

-  {

-    isDrive = true;

-    FStringVector drives;

-    if (!MyGetLogicalDriveStrings(drives))

-      return GetNormalizedError();

-    FOR_VECTOR (i, drives)

-    {

-      FString d = drives[i];

-      if (d.Len() < 3 || d.Back() != '\\')

-        return E_FAIL;

-      d.DeleteBack();

-      CFileInfo &fi = files.AddNew();

-      fi.SetAsDir();

-      fi.Name = d;

-    }

-  }

-  else

-  #endif

-  {

-    CEnumerator enumerator;

-    enumerator.SetDirPrefix(us2fs(pathPrefix));

-    for (;;)

-    {

-      bool found;

-      CFileInfo fi;

-      if (!enumerator.Next(fi, found))

-        return GetNormalizedError();

-      if (!found)

-        break;

-      if (!fi.IsDir())

-      {

-        if (FolderMode)

-          continue;

-        if (!ShowAllFiles)

-        {

-          unsigned i;

-          for (i = 0; i < Filters.Size(); i++)

-            if (DoesWildcardMatchName(Filters[i], fs2us(fi.Name)))

-              break;

-          if (i == Filters.Size())

-            continue;

-        }

-      }

-      files.Add(fi);

-    }

-  }

-

-  DirPrefix = pathPrefix;

-

-  _files = files;

-

-  SetItemText(IDT_BROWSE_FOLDER, DirPrefix);

-

-  _list.SetRedraw(false);

-  _list.DeleteAllItems();

-

-  LVITEMW item;

-

-  int index = 0;

-  int cursorIndex = -1;

-

-  #ifndef _SFX

-  if (_showDots && _topDirPrefix != DirPrefix)

-  {

-    item.iItem = index;

-    const UString itemName ("..");

-    if (selectedName.IsEmpty())

-      cursorIndex = index;

-    item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;

-    int subItem = 0;

-    item.iSubItem = subItem++;

-    item.lParam = kParentIndex;

-    item.pszText = (wchar_t *)(const wchar_t *)itemName;

-    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 = index;

-    const CFileInfo &fi = _files[i];

-    const UString name = fs2us(fi.Name);

-    if (!selectedName.IsEmpty() && CompareFileNames(name, selectedName) == 0)

-      cursorIndex = index;

-    item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;

-    int subItem = 0;

-    item.iSubItem = subItem++;

-    item.lParam = i;

-    item.pszText = (wchar_t *)(const wchar_t *)name;

-

-    const UString fullPath = DirPrefix + name;

-    #ifndef UNDER_CE

-    if (isDrive)

-    {

-      if (GetRealIconIndex(fi.Name + FCHAR_PATH_SEPARATOR, FILE_ATTRIBUTE_DIRECTORY, item.iImage) == 0)

-        item.iImage = 0;

-    }

-    else

-    #endif

-      item.iImage = _extToIconMap.GetIconIndex(fi.Attrib, fullPath);

-    if (item.iImage < 0)

-      item.iImage = 0;

-    _list.InsertItem(&item);

-    wchar_t s[32];

-    {

-      s[0] = 0;

-      ConvertUtcFileTimeToString(fi.MTime, s,

-            #ifndef UNDER_CE

-              kTimestampPrintLevel_MIN

-            #else

-              kTimestampPrintLevel_DAY

-            #endif

-              );

-      _list.SetSubItem(index, subItem++, s);

-    }

-    {

-      s[0] = 0;

-      if (!fi.IsDir())

-        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;

-  int index = _list.GetNextSelectedItem(-1);

-  if (index >= 0)

-  {

-    int fileIndex = GetRealItemIndex(index);

-    if (fileIndex != kParentIndex)

-      selected = fs2us(_files[fileIndex].Name);

-  }

-  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()

-{

-  int index = _list.GetNextSelectedItem(-1);

-  if (index < 0)

-  {

-    if (FolderMode)

-      _pathEdit.SetText(DirPrefix);

-    return;

-  }

-  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, GetNormalizedError(), fs2us(destPath));

-    }

-    else

-    {

-      UString tempPath = DirPrefix;

-      Reload(tempPath, name);

-      SetPathEditText();

-    }

-    _list.SetFocus();

-  }

-}

-

-void CBrowseDialog::OnItemEnter()

-{

-  int index = _list.GetNextSelectedItem(-1);

-  if (index < 0)

-    return;

-  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();

-    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);

-  End(IDOK);

-}

-

-#endif

-

-bool MyBrowseForFolder(HWND owner, LPCWSTR title, LPCWSTR path, UString &resultPath)

-{

-  resultPath.Empty();

-

-  #ifndef UNDER_CE

-

-  #ifdef USE_MY_BROWSE_DIALOG

-  if (!IsSuperOrDevicePath(path))

-  #endif

-    return NShell::BrowseForFolder(owner, title, path, resultPath);

-

-  #endif

-

-  #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;

-  #endif

-

-  return true;

-}

-

-bool MyBrowseForFile(HWND owner, LPCWSTR title, LPCWSTR path,

-    LPCWSTR filterDescription, LPCWSTR filter, UString &resultPath)

-{

-  resultPath.Empty();

-

-  #ifndef UNDER_CE

-

-  #ifdef USE_MY_BROWSE_DIALOG

-  if (!IsSuperOrDevicePath(path))

-  #endif

-  {

-    if (MyGetOpenFileName(owner, title, NULL, path, filterDescription, filter, resultPath))

-      return true;

-    #ifdef UNDER_CE

-    return false;

-    #else

-    // maybe we must use GetLastError in WinCE.

-    DWORD errorCode = CommDlgExtendedError();

-    const char *errorMessage = NULL;

-    switch (errorCode)

-    {

-      case 0: return false; // cancel or close obn dialog

-      case FNERR_INVALIDFILENAME: errorMessage = "Invalid File Name"; break;

-      default: errorMessage = "Open Dialog Error";

-    }

-    if (!errorMessage)

-      return false;

-    {

-      UString s (errorMessage);

-      s.Add_LF();

-      s += path;

-      MessageBox_Error_Global(owner, s);

-    }

-    #endif

-  }

-

-  #endif

-  

-  #ifdef USE_MY_BROWSE_DIALOG

-  CBrowseDialog dialog;

-  if (title)

-    dialog.Title = title;

-  if (path)

-    dialog.FilePath = path;

-  dialog.FolderMode = false;

-  if (filter)

-    dialog.SetFilter(filter);

-  if (filterDescription)

-    dialog.FilterDescription = filterDescription;

-  if (dialog.Create(owner) != IDOK)

-    return false;

-  resultPath = dialog.FilePath;

-  #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;

-  path.Replace(L'/', WCHAR_PATH_SEPARATOR);

-  unsigned start = 0;

-  UString base;

-  

-  if (IsAbsolutePath(path))

-  {

-    #if defined(_WIN32) && !defined(UNDER_CE)

-    if (IsSuperOrDevicePath(path))

-    {

-      result = path;

-      return true;

-    }

-    #endif

-    int pos = GetRootPrefixSize(path);

-    if (pos > 0)

-      start = pos;

-  }

-  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;

-    int slashPos = path.Find(WCHAR_PATH_SEPARATOR, start);

-    cur.SetFrom(path.Ptr(start), (slashPos < 0 ? path.Len() : 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;

-    result.Add_PathSepar();

-    start = slashPos + 1;

-  }

-  

-  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 <commdlg.h>
+#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
+
+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<CFileInfo> _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<CBrowseFilterInfo> 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(GetSysImageList(true), LVSIL_SMALL);
+  _list.SetImageList(GetSysImageList(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
+
+  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: // probabably 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 == kParentIndex) return -1;
+  if (lParam2 == kParentIndex) return 1;
+  const CFileInfo &f1 = _files[(int)lParam1];
+  const CFileInfo &f2 = _files[(int)lParam2];
+
+  const bool isDir1 = f1.IsDir();
+  const bool isDir2 = f2.IsDir();
+  if (isDir1 && !isDir2) return -1;
+  if (isDir2 && !isDir1) 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);
+}
+
+static void 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;
+  }
+}
+
+// Reload changes DirPrefix. Don't send DirPrefix in pathPrefix parameter
+
+HRESULT CBrowseDialog::Reload(const UString &pathPrefix, const UString &selectedName)
+{
+  CObjectVector<CFileInfo> 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)
+    {
+      if (GetRealIconIndex(fi.Name + FCHAR_PATH_SEPARATOR, FILE_ATTRIBUTE_DIRECTORY, item.iImage) == 0)
+        item.iImage = 0;
+    }
+    else
+    #endif
+      item.iImage = _extToIconMap.GetIconIndex(fi.Attrib, fullPath);
+    if (item.iImage < 0)
+      item.iImage = 0;
+    _list.InsertItem(&item);
+    wchar_t s[32];
+    {
+      s[0] = 0;
+      ConvertUtcFileTimeToString(fi.MTime, s,
+            #ifndef UNDER_CE
+              kTimestampPrintLevel_MIN
+            #else
+              kTimestampPrintLevel_DAY
+            #endif
+              );
+      _list.SetSubItem(index, subItem++, s);
+    }
+    {
+      s[0] = 0;
+      if (!fi.IsDir())
+        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<CBrowseFilterInfo> &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 be51085..2ad8d54 100644
--- a/CPP/7zip/UI/FileManager/BrowseDialog.h
+++ b/CPP/7zip/UI/FileManager/BrowseDialog.h
@@ -1,21 +1,32 @@
-// BrowseDialog.h

-

-#ifndef __BROWSE_DIALOG_H

-#define __BROWSE_DIALOG_H

-

-#include "../../../Common/MyString.h"

-

-bool MyBrowseForFolder(HWND owner, LPCWSTR title, LPCWSTR path, UString &resultPath);

-bool MyBrowseForFile(HWND owner, LPCWSTR title, LPCWSTR path, LPCWSTR filterDescription, LPCWSTR filter, UString &resultPath);

-

-/* 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<CBrowseFilterInfo> &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
new file mode 100644
index 0000000..04a6ad6
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/BrowseDialog.rc
@@ -0,0 +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
+}
diff --git a/CPP/7zip/UI/FileManager/BrowseDialogRes.h b/CPP/7zip/UI/FileManager/BrowseDialogRes.h
index f211b73..aff84ec 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
new file mode 100644
index 0000000..5c26904
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/ClassDefs.cpp
@@ -0,0 +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"
diff --git a/CPP/7zip/UI/FileManager/ComboDialog.cpp b/CPP/7zip/UI/FileManager/ComboDialog.cpp
index e846c56..921972e 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 LANG

-#include "LangUtils.h"

-#endif

-

-using namespace NWindows;

-

-bool CComboDialog::OnInit()

-{

-  #ifdef 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 6869cff..bb0fda8 100644
--- a/CPP/7zip/UI/FileManager/ComboDialog.h
+++ b/CPP/7zip/UI/FileManager/ComboDialog.h
@@ -1,28 +1,28 @@
-// ComboDialog.h

-

-#ifndef __COMBO_DIALOG_H

-#define __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();

-  virtual bool OnInit();

-  virtual bool OnSize(WPARAM wParam, int xSize, int ySize);

-public:

-  // bool Sorted;

-  UString Title;

-  UString Static;

-  UString Value;

-  UStringVector Strings;

-  

-  // CComboDialog(): Sorted(false) {};

-  INT_PTR Create(HWND parentWindow = 0) { 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
new file mode 100644
index 0000000..fddb748
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/ComboDialog.rc
@@ -0,0 +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
diff --git a/CPP/7zip/UI/FileManager/ComboDialogRes.h b/CPP/7zip/UI/FileManager/ComboDialogRes.h
index 98938b6..a044797 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/Copy.bmp b/CPP/7zip/UI/FileManager/Copy.bmp
new file mode 100644
index 0000000..0f28a32
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/Copy.bmp
Binary files differ
diff --git a/CPP/7zip/UI/FileManager/Copy2.bmp b/CPP/7zip/UI/FileManager/Copy2.bmp
new file mode 100644
index 0000000..ba88ded
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/Copy2.bmp
Binary files differ
diff --git a/CPP/7zip/UI/FileManager/CopyDialog.cpp b/CPP/7zip/UI/FileManager/CopyDialog.cpp
new file mode 100644
index 0000000..9bc01d0
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/CopyDialog.cpp
@@ -0,0 +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();
+}
diff --git a/CPP/7zip/UI/FileManager/CopyDialog.h b/CPP/7zip/UI/FileManager/CopyDialog.h
new file mode 100644
index 0000000..3782420
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/CopyDialog.h
@@ -0,0 +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
diff --git a/CPP/7zip/UI/FileManager/CopyDialog.rc b/CPP/7zip/UI/FileManager/CopyDialog.rc
new file mode 100644
index 0000000..73d3ea8
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/CopyDialog.rc
@@ -0,0 +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
diff --git a/CPP/7zip/UI/FileManager/CopyDialogRes.h b/CPP/7zip/UI/FileManager/CopyDialogRes.h
new file mode 100644
index 0000000..85f5a39
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/CopyDialogRes.h
@@ -0,0 +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
diff --git a/CPP/7zip/UI/FileManager/Delete.bmp b/CPP/7zip/UI/FileManager/Delete.bmp
new file mode 100644
index 0000000..d1004d8
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/Delete.bmp
Binary files differ
diff --git a/CPP/7zip/UI/FileManager/Delete2.bmp b/CPP/7zip/UI/FileManager/Delete2.bmp
new file mode 100644
index 0000000..60e08c6
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/Delete2.bmp
Binary files differ
diff --git a/CPP/7zip/UI/FileManager/DialogSize.h b/CPP/7zip/UI/FileManager/DialogSize.h
index bbce159..9f2270b 100644
--- a/CPP/7zip/UI/FileManager/DialogSize.h
+++ b/CPP/7zip/UI/FileManager/DialogSize.h
@@ -1,16 +1,16 @@
-// DialogSize.h

-

-#ifndef __DIALOG_SIZE_H

-#define __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
new file mode 100644
index 0000000..e97d9ea
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/EditDialog.cpp
@@ -0,0 +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;
+}
diff --git a/CPP/7zip/UI/FileManager/EditDialog.h b/CPP/7zip/UI/FileManager/EditDialog.h
new file mode 100644
index 0000000..6970b14
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/EditDialog.h
@@ -0,0 +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
diff --git a/CPP/7zip/UI/FileManager/EditDialog.rc b/CPP/7zip/UI/FileManager/EditDialog.rc
new file mode 100644
index 0000000..cdb0b44
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/EditDialog.rc
@@ -0,0 +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
+}
diff --git a/CPP/7zip/UI/FileManager/EditDialogRes.h b/CPP/7zip/UI/FileManager/EditDialogRes.h
new file mode 100644
index 0000000..58c5ca9
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/EditDialogRes.h
@@ -0,0 +1,2 @@
+#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
new file mode 100644
index 0000000..a2a0321
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/EditPage.cpp
@@ -0,0 +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 &params);
+
+static void Edit_BrowseForFile(NWindows::NControl::CEdit &edit, HWND hwnd)
+{
+  UString cmd;
+  edit.GetText(cmd);
+
+  UString param;
+  UString prg;
+  
+  SplitCmdLineSmart(cmd, prg, param);
+
+  CObjectVector<CBrowseFilterInfo> 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
new file mode 100644
index 0000000..a70fad7
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/EditPage.h
@@ -0,0 +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
diff --git a/CPP/7zip/UI/FileManager/EditPage.rc b/CPP/7zip/UI/FileManager/EditPage.rc
new file mode 100644
index 0000000..38f74ea
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/EditPage.rc
@@ -0,0 +1,19 @@
+#include "EditPageRes.h"
+#include "../../GuiCommon.rc"
+
+#define xc 240
+#define yc 80
+
+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
new file mode 100644
index 0000000..2d6554f
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/EditPage2.rc
@@ -0,0 +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
+}
diff --git a/CPP/7zip/UI/FileManager/EditPageRes.h b/CPP/7zip/UI/FileManager/EditPageRes.h
new file mode 100644
index 0000000..017d702
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/EditPageRes.h
@@ -0,0 +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
diff --git a/CPP/7zip/UI/FileManager/EnumFormatEtc.cpp b/CPP/7zip/UI/FileManager/EnumFormatEtc.cpp
new file mode 100644
index 0000000..fc2fd6c
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/EnumFormatEtc.cpp
@@ -0,0 +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;
+}
diff --git a/CPP/7zip/UI/FileManager/EnumFormatEtc.h b/CPP/7zip/UI/FileManager/EnumFormatEtc.h
new file mode 100644
index 0000000..12df225
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/EnumFormatEtc.h
@@ -0,0 +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
diff --git a/CPP/7zip/UI/FileManager/Extract.bmp b/CPP/7zip/UI/FileManager/Extract.bmp
new file mode 100644
index 0000000..0aeba92
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/Extract.bmp
Binary files differ
diff --git a/CPP/7zip/UI/FileManager/Extract2.bmp b/CPP/7zip/UI/FileManager/Extract2.bmp
new file mode 100644
index 0000000..a7e5775
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/Extract2.bmp
Binary files differ
diff --git a/CPP/7zip/UI/FileManager/ExtractCallback.cpp b/CPP/7zip/UI/FileManager/ExtractCallback.cpp
index f230594..f674044 100644
--- a/CPP/7zip/UI/FileManager/ExtractCallback.cpp
+++ b/CPP/7zip/UI/FileManager/ExtractCallback.cpp
@@ -1,1037 +1,1056 @@
-// 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 _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 _NO_CRYPTO

-#include "PasswordDialog.h"

-#endif

-#include "PropertyName.h"

-

-using namespace NWindows;

-using namespace NFile;

-using namespace NFind;

-

-CExtractCallbackImp::~CExtractCallbackImp() {}

-

-void CExtractCallbackImp::Init()

-{

-  _lang_Extracting = LangString(IDS_PROGRESS_EXTRACTING);

-  _lang_Testing = LangString(IDS_PROGRESS_TESTING);

-  _lang_Skipping = LangString(IDS_PROGRESS_SKIPPING);

-

-  NumArchiveErrors = 0;

-  ThereAreMessageErrors = false;

-  #ifndef _SFX

-  NumFolders = NumFiles = 0;

-  NeedAddFile = false;

-  #endif

-}

-

-void CExtractCallbackImp::AddError_Message(LPCWSTR s)

-{

-  ThereAreMessageErrors = true;

-  ProgressDialog->Sync.AddError_Message(s);

-}

-

-#ifndef _SFX

-

-STDMETHODIMP CExtractCallbackImp::SetNumFiles(UInt64

-  #ifndef _SFX

-  numFiles

-  #endif

-  )

-{

-  #ifndef _SFX

-  ProgressDialog->Sync.Set_NumFilesTotal(numFiles);

-  #endif

-  return S_OK;

-}

-

-#endif

-

-STDMETHODIMP CExtractCallbackImp::SetTotal(UInt64 total)

-{

-  ProgressDialog->Sync.Set_NumBytesTotal(total);

-  return S_OK;

-}

-

-STDMETHODIMP 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 _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 _SFX

-STDMETHODIMP CExtractCallbackImp::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)

-{

-  ProgressDialog->Sync.Set_Ratio(inSize, outSize);

-  return S_OK;

-}

-#endif

-

-/*

-STDMETHODIMP CExtractCallbackImp::SetTotalFiles(UInt64 total)

-{

-  ProgressDialog->Sync.SetNumFilesTotal(total);

-  return S_OK;

-}

-

-STDMETHODIMP CExtractCallbackImp::SetCompletedFiles(const UInt64 *value)

-{

-  if (value != NULL)

-    ProgressDialog->Sync.SetNumFilesCur(*value);

-  return S_OK;

-}

-*/

-

-STDMETHODIMP 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.SetTime(existTime);

-  dialog.OldFileInfo.SetSize(existSize);

-  dialog.OldFileInfo.Name = existName;

-

-  dialog.NewFileInfo.SetTime(newTime);

-  dialog.NewFileInfo.SetSize(newSize);

-  dialog.NewFileInfo.Name = newName;

-  

-  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;

-}

-

-

-STDMETHODIMP 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;

-    // default: s = "Unknown operation";

-  }

-

-  return ProgressDialog->Sync.Set_Status2(*msg, name, IntToBool(isFolder));

-}

-

-STDMETHODIMP 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 _SFX

-

-STDMETHODIMP 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)

-{

-  s.Empty();

-

-  if (opRes == NArchive::NExtract::NOperationResult::kOK)

-    return;

-

-  UINT messageID = 0;

-  UINT id = 0;

-

-  switch (opRes)

-  {

-    case NArchive::NExtract::NOperationResult::kUnsupportedMethod:

-      messageID = IDS_EXTRACT_MESSAGE_UNSUPPORTED_METHOD;

-      id = IDS_EXTRACT_MSG_UNSUPPORTED_METHOD;

-      break;

-    case NArchive::NExtract::NOperationResult::kDataError:

-      messageID = encrypted ?

-          IDS_EXTRACT_MESSAGE_DATA_ERROR_ENCRYPTED:

-          IDS_EXTRACT_MESSAGE_DATA_ERROR;

-      id = IDS_EXTRACT_MSG_DATA_ERROR;

-      break;

-    case NArchive::NExtract::NOperationResult::kCRCError:

-      messageID = encrypted ?

-          IDS_EXTRACT_MESSAGE_CRC_ERROR_ENCRYPTED:

-          IDS_EXTRACT_MESSAGE_CRC_ERROR;

-      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;

-  UString msgOld;

-

-  #ifndef _SFX

-  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

-  {

-    if (msg.IsEmpty() && id != 0)

-      LangString(id, msg);

-    if (!msg.IsEmpty())

-      s += msg;

-    else

-    {

-      s += "Error #";

-      s.Add_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;

-  }

-}

-

-STDMETHODIMP CExtractCallbackImp::SetOperationResult(Int32 opRes, Int32 encrypted)

-{

-  switch (opRes)

-  {

-    case NArchive::NExtract::NOperationResult::kOK:

-      break;

-    default:

-    {

-      UString s;

-      SetExtractErrorMessage(opRes, encrypted, _currentFilePath, s);

-      Add_ArchiveName_Error();

-      AddError_Message(s);

-    }

-  }

-  

-  #ifndef _SFX

-  if (_isFolder)

-    NumFolders++;

-  else

-    NumFiles++;

-  ProgressDialog->Sync.Set_NumFilesCur(NumFiles);

-  #endif

-  

-  return S_OK;

-}

-

-STDMETHODIMP CExtractCallbackImp::ReportExtractResult(Int32 opRes, Int32 encrypted, const wchar_t *name)

-{

-  if (opRes != NArchive::NExtract::NOperationResult::kOK)

-  {

-    UString s;

-    SetExtractErrorMessage(opRes, encrypted, name, s);

-    Add_ArchiveName_Error();

-    AddError_Message(s);

-  }

-  return S_OK;

-}

-

-////////////////////////////////////////

-// IExtractCallbackUI

-

-HRESULT CExtractCallbackImp::BeforeOpen(const wchar_t *name, bool /* testMode */)

-{

-  #ifndef _SFX

-  RINOK(ProgressDialog->Sync.CheckStop());

-  ProgressDialog->Sync.Set_TitleFileName(name);

-  #endif

-  _currentArchivePath = name;

-  return S_OK;

-}

-

-HRESULT CExtractCallbackImp::SetCurrentFilePath2(const wchar_t *path)

-{

-  _currentFilePath = path;

-  #ifndef _SFX

-  ProgressDialog->Sync.Set_FilePath(path);

-  #endif

-  return S_OK;

-}

-

-#ifndef _SFX

-

-HRESULT CExtractCallbackImp::SetCurrentFilePath(const wchar_t *path)

-{

-  #ifndef _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 s;

-

-  for (unsigned i = 0; i < 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 += ']';

-  return s;

-}

-

-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)

-{

-  if (result == S_OK)

-    return result;

-  NumArchiveErrors++;

-  if (result == E_ABORT || result == ERROR_DISK_FULL)

-    return result;

-

-  Add_ArchiveName_Error();

-  if (!_currentFilePath.IsEmpty())

-    MessageError(_currentFilePath);

-  MessageError(NError::MyFormatMessage(result));

-  return S_OK;

-}

-

-#ifndef _NO_CRYPTO

-

-HRESULT CExtractCallbackImp::SetPassword(const UString &password)

-{

-  PasswordIsDefined = true;

-  Password = password;

-  return S_OK;

-}

-

-STDMETHODIMP CExtractCallbackImp::CryptoGetTextPassword(BSTR *password)

-{

-  PasswordWasAsked = true;

-  if (!PasswordIsDefined)

-  {

-    CPasswordDialog dialog;

-    #ifndef _SFX

-    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 _SFX

-    if (dialog.ShowPassword != showPassword)

-      NExtract::Save_ShowPassword(dialog.ShowPassword);

-    #endif

-  }

-  return StringToBstr(Password, password);

-}

-

-#endif

-

-#ifndef _SFX

-

-STDMETHODIMP 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 = 0;

-  *writeAnswer = BoolToInt(false);

-

-  FString destPathSys = us2fs(destPath);

-  bool srcIsFolderSpec = IntToBool(srcIsFolder);

-  CFileInfo destFileInfo;

-  

-  if (destFileInfo.Find(destPathSys))

-  {

-    if (srcIsFolderSpec)

-    {

-      if (!destFileInfo.IsDir())

-      {

-        RINOK(MessageError("can not replace file with folder with same name", destPathSys));

-        return E_ABORT;

-      }

-      *writeAnswer = BoolToInt(false);

-      return S_OK;

-    }

-  

-    if (destFileInfo.IsDir())

-    {

-      RINOK(MessageError("can not replace folder with file with same name", destPathSys));

-      *writeAnswer = BoolToInt(false);

-      return S_OK;

-    }

-

-    switch (OverwriteMode)

-    {

-      case NExtract::NOverwriteMode::kSkip:

-        return S_OK;

-      case NExtract::NOverwriteMode::kAsk:

-      {

-        Int32 overwriteResult;

-        UString destPathSpec = destPath;

-        int slashPos = destPathSpec.ReverseFind_PathSepar();

-        destPathSpec.DeleteFrom(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;

-        }

-      }

-    }

-    

-    if (OverwriteMode == NExtract::NOverwriteMode::kRename)

-    {

-      if (!AutoRenamePath(destPathSys))

-      {

-        RINOK(MessageError("can not create name for file", destPathSys));

-        return E_ABORT;

-      }

-      destPathResultTemp = fs2us(destPathSys);

-    }

-    else

-    {

-      if (NFind::DoesFileExist(destPathSys))

-      if (!NDir::DeleteFileAlways(destPathSys))

-      if (GetLastError() != ERROR_FILE_NOT_FOUND)

-      {

-        RINOK(MessageError("can not delete output file", destPathSys));

-        return E_ABORT;

-      }

-    }

-  }

-  *writeAnswer = BoolToInt(true);

-  return StringToBstr(destPathResultTemp, destPathResult);

-}

-

-

-STDMETHODIMP 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;

-}

-

-

-STDMETHODIMP CExtractCallbackImp::GetStream7(const wchar_t *name,

-    Int32 isDir,

-    ISequentialOutStream **outStream, Int32 askExtractMode,

-    IGetProp *getProp)

-{

-  COM_TRY_BEGIN

-  *outStream = 0;

-  _newVirtFileWasAdded = false;

-  _hashStreamWasUsed = false;

-  _needUpdateStat = false;

-

-  if (_hashStream)

-    _hashStreamSpec->ReleaseStream();

-

-  GetItemBoolProp(getProp, kpidIsAltStream, _isAltStream);

-

-  if (!ProcessAltStreams && _isAltStream)

-    return S_OK;

-

-  _filePath = name;

-  _isFolder = IntToBool(isDir);

-  _curSize = 0;

-  _curSizeDefined = false;

-

-  UInt64 size = 0;

-  bool sizeDefined;

-  {

-    NCOM::CPropVariant prop;

-    RINOK(getProp->GetProp(kpidSize, &prop));

-    sizeDefined = ConvertPropVariantToUInt64(prop, size);

-  }

-

-  if (sizeDefined)

-  {

-    _curSize = size;

-    _curSizeDefined = true;

-  }

-

-  if (askExtractMode != NArchive::NExtract::NAskMode::kExtract &&

-      askExtractMode != NArchive::NExtract::NAskMode::kTest)

-    return S_OK;

-

-  _needUpdateStat = true;

-  

-  CMyComPtr<ISequentialOutStream> 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)

-  {

-    {

-      _hashStreamSpec->SetStream(outStreamLoc);

-      outStreamLoc = _hashStream;

-      _hashStreamSpec->Init(true);

-      _hashStreamWasUsed = true;

-    }

-  }

-

-  if (outStreamLoc)

-    *outStream = outStreamLoc.Detach();

-  return S_OK;

-  COM_TRY_END

-}

-

-STDMETHODIMP CExtractCallbackImp::PrepareOperation7(Int32 askExtractMode)

-{

-  COM_TRY_BEGIN

-  _needUpdateStat = (

-      askExtractMode == NArchive::NExtract::NAskMode::kExtract ||

-      askExtractMode == NArchive::NExtract::NAskMode::kTest);

-

-  /*

-  _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

-}

-

-STDMETHODIMP CExtractCallbackImp::SetOperationResult7(Int32 opRes, Int32 encrypted)

-{

-  COM_TRY_BEGIN

-  if (VirtFileSystem && _newVirtFileWasAdded)

-  {

-    // FIXME: probably we must request file size from VirtFileSystem

-    // _curSize = VirtFileSystem->GetLastFileSize()

-    // _curSizeDefined = true;

-    RINOK(VirtFileSystemSpec->CloseMemFile());

-  }

-  if (_hashStream && _hashStreamWasUsed)

-  {

-    _hashStreamSpec->_hash->Final(_isFolder, _isAltStream, _filePath);

-    _curSize = _hashStreamSpec->GetSize();

-    _curSizeDefined = true;

-    _hashStreamSpec->ReleaseStream();

-    _hashStreamWasUsed = false;

-  }

-  else if (_hashCalc && _needUpdateStat)

-  {

-    _hashCalc->SetSize(_curSize);

-    _hashCalc->Final(_isFolder, _isAltStream, _filePath);

-  }

-  return SetOperationResult(opRes, encrypted);

-  COM_TRY_END

-}

-

-

-static const size_t k_SizeT_MAX = (size_t)((size_t)0 - 1);

-

-static const UInt32 kBlockSize = ((UInt32)1 << 31);

-

-STDMETHODIMP 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;

-      if (b <= k_SizeT_MAX && b <= MaxTotalAllocSize)

-        useMem = file.Data.ReAlloc_KeepData((size_t)b, (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->Write(data, size, processedSize);

-}

-

-HRESULT CVirtFileSystem::FlushToDisk(bool closeLast)

-{

-  if (!_outFileStream)

-  {

-    _outFileStreamSpec = new COutFileStream;

-    _outFileStream = _outFileStreamSpec;

-  }

-  while (_numFlushed < Files.Size())

-  {

-    const CVirtFile &file = Files[_numFlushed];

-    const FString path = DirPrefix + us2fs(Get_Correct_FsFile_Name(file.Name));

-    if (!_fileIsOpen)

-    {

-      if (!_outFileStreamSpec->Create(path, false))

-      {

-        _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)

-      _outFileStreamSpec->SetTime(

-          file.CTimeDefined ? &file.CTime : NULL,

-          file.ATimeDefined ? &file.ATime : NULL,

-          file.MTimeDefined ? &file.MTime : NULL);

-    _outFileStreamSpec->Close();

-    _numFlushed++;

-    _fileIsOpen = false;

-    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 "OverwriteDialog.h"
+#ifndef Z7_NO_CRYPTO
+#include "PasswordDialog.h"
+#endif
+#include "PropertyName.h"
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NFind;
+
+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);
+}
+
+#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.SetTime(existTime);
+  dialog.OldFileInfo.SetSize(existSize);
+  dialog.OldFileInfo.Name = existName;
+
+  dialog.NewFileInfo.SetTime(newTime);
+  dialog.NewFileInfo.SetSize(newSize);
+  dialog.NewFileInfo.Name = newName;
+  
+  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);
+      Add_ArchiveName_Error();
+      AddError_Message(s);
+    }
+  }
+  
+  #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);
+    Add_ArchiveName_Error();
+    AddError_Message(s);
+  }
+  return S_OK;
+}
+
+////////////////////////////////////////
+// IExtractCallbackUI
+
+HRESULT CExtractCallbackImp::BeforeOpen(const wchar_t *name, bool /* testMode */)
+{
+  #ifndef Z7_SFX
+  RINOK(ProgressDialog->Sync.CheckStop())
+  ProgressDialog->Sync.Set_TitleFileName(name);
+  #endif
+  _currentArchivePath = name;
+  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 += ']';
+  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)
+{
+  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;
+  _hashStreamWasUsed = false;
+  _needUpdateStat = false;
+
+  if (_hashStream)
+    _hashStreamSpec->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<ISequentialOutStream> 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)
+  {
+    {
+      _hashStreamSpec->SetStream(outStreamLoc);
+      outStreamLoc = _hashStream;
+      _hashStreamSpec->Init(true);
+      _hashStreamWasUsed = 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 && _hashStreamWasUsed)
+  {
+    _hashStreamSpec->_hash->Final(_isFolder, _isAltStream, _filePath);
+    _curSize = _hashStreamSpec->GetSize();
+    _curSize_Defined = true;
+    _hashStreamSpec->ReleaseStream();
+    _hashStreamWasUsed = false;
+  }
+  else if (_hashCalc && _needUpdateStat)
+  {
+    _hashCalc->SetSize(size); // (_curSize) before 21.04
+    _hashCalc->Final(_isFolder, _isAltStream, _filePath);
+  }
+  return SetOperationResult(opRes, encrypted);
+  COM_TRY_END
+}
+
+
+
+// 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->Write(data, size, processedSize);
+}
+
+HRESULT CVirtFileSystem::FlushToDisk(bool closeLast)
+{
+  if (!_outFileStream)
+  {
+    _outFileStreamSpec = new COutFileStream;
+    _outFileStream = _outFileStreamSpec;
+  }
+  while (_numFlushed < Files.Size())
+  {
+    const CVirtFile &file = Files[_numFlushed];
+    const FString path = DirPrefix + us2fs(Get_Correct_FsFile_Name(file.Name));
+    if (!_fileIsOpen)
+    {
+      if (!_outFileStreamSpec->Create(path, false))
+      {
+        _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)
+      _outFileStreamSpec->SetTime(
+          file.CTimeDefined ? &file.CTime : NULL,
+          file.ATimeDefined ? &file.ATime : NULL,
+          file.MTimeDefined ? &file.MTime : NULL);
+    _outFileStreamSpec->Close();
+    _numFlushed++;
+    _fileIsOpen = false;
+    if (file.AttribDefined)
+      NDir::SetFileAttrib_PosixHighDetect(path, file.Attrib);
+  }
+  return S_OK;
+}
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/ExtractCallback.h b/CPP/7zip/UI/FileManager/ExtractCallback.h
index a6d5ae3..c2aa470 100644
--- a/CPP/7zip/UI/FileManager/ExtractCallback.h
+++ b/CPP/7zip/UI/FileManager/ExtractCallback.h
@@ -1,328 +1,310 @@
-// ExtractCallback.h

-

-#ifndef __EXTRACT_CALLBACK_H

-#define __EXTRACT_CALLBACK_H

-

-#include "../../../../C/Alloc.h"

-

-#include "../../../Common/MyCom.h"

-#include "../../../Common/StringConvert.h"

-

-#ifndef _SFX

-#include "../Agent/IFolderArchive.h"

-#endif

-

-#include "../Common/ArchiveExtractCallback.h"

-#include "../Common/ArchiveOpenCallback.h"

-

-#ifndef _NO_CRYPTO

-#include "../../IPassword.h"

-#endif

-

-#ifndef _SFX

-#include "IFolder.h"

-#endif

-

-#include "ProgressDialog2.h"

-

-#ifdef LANG

-#include "LangUtils.h"

-#endif

-

-#ifndef _SFX

-

-class CGrowBuf

-{

-  Byte *_items;

-  size_t _size;

-

-  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(0), _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) {}

-};

-

-class CVirtFileSystem:

-  public ISequentialOutStream,

-  public CMyUnknownImp

-{

-  UInt64 _totalAllocSize;

-

-  size_t _pos;

-  unsigned _numFlushed;

-  bool _fileIsOpen;

-  bool _fileMode;

-  COutFileStream *_outFileStreamSpec;

-  CMyComPtr<ISequentialOutStream> _outFileStream;

-public:

-  CObjectVector<CVirtFile> Files;

-  UInt64 MaxTotalAllocSize;

-  FString DirPrefix;

- 

-  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(): _outFileStreamSpec(NULL), 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; }

-

-  MY_UNKNOWN_IMP

-  STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);

-};

-

-#endif

-  

-class CExtractCallbackImp:

-  public IExtractCallbackUI, // it includes IFolderArchiveExtractCallback

-  public IOpenCallbackUI,

-  public IFolderArchiveExtractCallback2,

-  #ifndef _SFX

-  public IFolderOperationsExtractCallback,

-  public IFolderExtractToStreamCallback,

-  public ICompressProgressInfo,

-  #endif

-  #ifndef _NO_CRYPTO

-  public ICryptoGetTextPassword,

-  #endif

-  public CMyUnknownImp

-{

-  HRESULT MessageError(const char *message, const FString &path);

-  void Add_ArchiveName_Error();

-public:

-  MY_QUERYINTERFACE_BEGIN2(IFolderArchiveExtractCallback)

-  MY_QUERYINTERFACE_ENTRY(IFolderArchiveExtractCallback2)

-  #ifndef _SFX

-  MY_QUERYINTERFACE_ENTRY(IFolderOperationsExtractCallback)

-  MY_QUERYINTERFACE_ENTRY(IFolderExtractToStreamCallback)

-  MY_QUERYINTERFACE_ENTRY(ICompressProgressInfo)

-  #endif

-  #ifndef _NO_CRYPTO

-  MY_QUERYINTERFACE_ENTRY(ICryptoGetTextPassword)

-  #endif

-  MY_QUERYINTERFACE_END

-  MY_ADDREF_RELEASE

-

-  INTERFACE_IProgress(;)

-  INTERFACE_IOpenCallbackUI(;)

-  INTERFACE_IFolderArchiveExtractCallback(;)

-  INTERFACE_IFolderArchiveExtractCallback2(;)

-  // STDMETHOD(SetTotalFiles)(UInt64 total);

-  // STDMETHOD(SetCompletedFiles)(const UInt64 *value);

-

-  INTERFACE_IExtractCallbackUI(;)

-

-  #ifndef _SFX

-  // IFolderOperationsExtractCallback

-  STDMETHOD(AskWrite)(

-      const wchar_t *srcPath,

-      Int32 srcIsFolder,

-      const FILETIME *srcTime,

-      const UInt64 *srcSize,

-      const wchar_t *destPathRequest,

-      BSTR *destPathResult,

-      Int32 *writeAnswer);

-  STDMETHOD(ShowMessage)(const wchar_t *message);

-  STDMETHOD(SetCurrentFilePath)(const wchar_t *filePath);

-  STDMETHOD(SetNumFiles)(UInt64 numFiles);

-  INTERFACE_IFolderExtractToStreamCallback(;)

-  STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);

-  #endif

-

-  // ICryptoGetTextPassword

-  #ifndef _NO_CRYPTO

-  STDMETHOD(CryptoGetTextPassword)(BSTR *password);

-  #endif

-

-private:

-  UString _currentArchivePath;

-  bool _needWriteArchivePath;

-

-  UString _currentFilePath;

-  bool _isFolder;

-

-  bool _isAltStream;

-  UInt64 _curSize;

-  bool _curSizeDefined;

-  UString _filePath;

-  // bool _extractMode;

-  // bool _testMode;

-  bool _newVirtFileWasAdded;

-  bool _needUpdateStat;

-

-

-  HRESULT SetCurrentFilePath2(const wchar_t *filePath);

-  void AddError_Message(LPCWSTR message);

-

-  #ifndef _SFX

-  bool _hashStreamWasUsed;

-  COutStreamWithHash *_hashStreamSpec;

-  CMyComPtr<ISequentialOutStream> _hashStream;

-  IHashCalc *_hashCalc; // it's for stat in Test operation

-  #endif

-

-public:

-

-  #ifndef _SFX

-  CVirtFileSystem *VirtFileSystemSpec;

-  CMyComPtr<ISequentialOutStream> VirtFileSystem;

-  #endif

-

-  bool ProcessAltStreams;

-

-  bool StreamMode;

-

-  CProgressDialog *ProgressDialog;

-  #ifndef _SFX

-  UInt64 NumFolders;

-  UInt64 NumFiles;

-  bool NeedAddFile;

-  #endif

-  UInt32 NumArchiveErrors;

-  bool ThereAreMessageErrors;

-  NExtract::NOverwriteMode::EEnum OverwriteMode;

-

-  #ifndef _NO_CRYPTO

-  bool PasswordIsDefined;

-  bool PasswordWasAsked;

-  UString Password;

-  #endif

-

-

-  UString _lang_Extracting;

-  UString _lang_Testing;

-  UString _lang_Skipping;

-  UString _lang_Empty;

-

-  bool _totalFilesDefined;

-  bool _totalBytesDefined;

-  bool MultiArcMode;

-

-  CExtractCallbackImp():

-    #ifndef _NO_CRYPTO

-    PasswordIsDefined(false),

-    PasswordWasAsked(false),

-    #endif

-    OverwriteMode(NExtract::NOverwriteMode::kAsk),

-    StreamMode(false),

-    ProcessAltStreams(true),

-    

-    _totalFilesDefined(false),

-    _totalBytesDefined(false),

-    MultiArcMode(false)

-    

-    #ifndef _SFX

-    , _hashCalc(NULL)

-    #endif

-    {}

-   

-  ~CExtractCallbackImp();

-  void Init();

-

-  #ifndef _SFX

-  void SetHashCalc(IHashCalc *hashCalc) { _hashCalc = hashCalc; }

-

-  void SetHashMethods(IHashCalc *hash)

-  {

-    if (!hash)

-      return;

-    _hashStreamSpec = new COutStreamWithHash;

-    _hashStream = _hashStreamSpec;

-    _hashStreamSpec->_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"
+
+#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;
+  COutFileStream *_outFileStreamSpec;
+  CMyComPtr<ISequentialOutStream> _outFileStream;
+public:
+  CObjectVector<CVirtFile> Files;
+  UInt64 MaxTotalAllocSize;
+  FString DirPrefix;
+ 
+  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(): _outFileStreamSpec(NULL), 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,
+ #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)
+ #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)
+ #endif
+ #ifndef Z7_NO_CRYPTO
+  Z7_IFACE_COM7_IMP(ICryptoGetTextPassword)
+ #endif
+
+
+  UString _currentArchivePath;
+  bool _needWriteArchivePath;
+
+  bool _isFolder;
+  UString _currentFilePath;
+  UString _filePath;
+
+ #ifndef Z7_SFX
+  bool _needUpdateStat;
+  bool _newVirtFileWasAdded;
+  bool _isAltStream;
+  bool _curSize_Defined;
+  UInt64 _curSize;
+  // bool _extractMode;
+  // bool _testMode;
+  bool _hashStreamWasUsed;
+  COutStreamWithHash *_hashStreamSpec;
+  CMyComPtr<ISequentialOutStream> _hashStream;
+  IHashCalc *_hashCalc; // it's for stat in Test operation
+ #endif
+
+  HRESULT SetCurrentFilePath2(const wchar_t *filePath);
+  void AddError_Message(LPCWSTR message);
+  HRESULT MessageError(const char *message, const FString &path);
+  void Add_ArchiveName_Error();
+
+public:
+
+  #ifndef Z7_SFX
+  CVirtFileSystem *VirtFileSystemSpec;
+  CMyComPtr<ISequentialOutStream> VirtFileSystem;
+  #endif
+
+  bool ProcessAltStreams;
+
+  bool StreamMode;
+
+  CProgressDialog *ProgressDialog;
+  #ifndef Z7_SFX
+  UInt64 NumFolders;
+  UInt64 NumFiles;
+  bool NeedAddFile;
+  #endif
+  UInt32 NumArchiveErrors;
+  bool ThereAreMessageErrors;
+  NExtract::NOverwriteMode::EEnum OverwriteMode;
+
+  #ifndef Z7_NO_CRYPTO
+  bool PasswordIsDefined;
+  bool PasswordWasAsked;
+  UString Password;
+  #endif
+
+
+  UString _lang_Extracting;
+  UString _lang_Testing;
+  UString _lang_Skipping;
+  UString _lang_Reading;
+  UString _lang_Empty;
+
+  bool _totalFilesDefined;
+  bool _totalBytesDefined;
+  bool MultiArcMode;
+
+  CExtractCallbackImp():
+    #ifndef Z7_SFX
+    _hashCalc(NULL),
+    #endif
+    ProcessAltStreams(true),
+    StreamMode(false),
+    OverwriteMode(NExtract::NOverwriteMode::kAsk),
+    #ifndef Z7_NO_CRYPTO
+    PasswordIsDefined(false),
+    PasswordWasAsked(false),
+    #endif
+    _totalFilesDefined(false),
+    _totalBytesDefined(false),
+    MultiArcMode(false)
+    {}
+   
+  ~CExtractCallbackImp();
+  void Init();
+
+  #ifndef Z7_SFX
+  void SetHashCalc(IHashCalc *hashCalc) { _hashCalc = hashCalc; }
+
+  void SetHashMethods(IHashCalc *hash)
+  {
+    if (!hash)
+      return;
+    _hashStreamSpec = new COutStreamWithHash;
+    _hashStream = _hashStreamSpec;
+    _hashStreamSpec->_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
new file mode 100644
index 0000000..13189a7
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/FM.cpp
@@ -0,0 +1,1116 @@
+// FM.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/MyWindows.h"
+
+#if defined(__MINGW32__) || defined(__MINGW64__)
+#include <shlwapi.h>
+#else
+#include <Shlwapi.h>
+#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_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
+
+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
+
+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
+
+//  FUNCTION: InitInstance(HANDLE, int)
+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;
+
+  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();
+
+  #ifndef UNDER_CE
+  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);
+  }
+}
diff --git a/CPP/7zip/UI/FileManager/FM.dsp b/CPP/7zip/UI/FileManager/FM.dsp
new file mode 100644
index 0000000..1ae054d
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/FM.dsp
@@ -0,0 +1,1667 @@
+# 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=.\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=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\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\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\Common.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
new file mode 100644
index 0000000..1c955d9
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/FM.dsw
@@ -0,0 +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>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/CPP/7zip/UI/FileManager/FM.ico b/CPP/7zip/UI/FileManager/FM.ico
new file mode 100644
index 0000000..3a0a34d
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/FM.ico
Binary files differ
diff --git a/CPP/7zip/UI/FileManager/FM.mak b/CPP/7zip/UI/FileManager/FM.mak
new file mode 100644
index 0000000..8331285
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/FM.mak
@@ -0,0 +1,100 @@
+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_LONG_PATH -DZ7_DEVICE_FILE
+LFLAGS = $(LFLAGS) /DELAYLOAD:mpr.dll
+LIBS = $(LIBS) delayimp.lib
+!ENDIF
+
+FM_OBJS = \
+  $O\App.obj \
+  $O\BrowseDialog.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\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
new file mode 100644
index 0000000..985d7c4
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/FSDrives.cpp
@@ -0,0 +1,518 @@
+// 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(toPath, true))
+      return GetLastError_noZero_HRESULT();
+  
+  CPhysTempBuffer tempBuffer;
+  tempBuffer.buffer = MidAlloc(bufferSize);
+  if (!tempBuffer.buffer)
+    return E_OUTOFMEMORY;
+ 
+  for (UInt64 pos = 0; pos < fileSize;)
+  {
+    UInt64 progressCur = progressStart + pos;
+    RINOK(progress->SetCompleted(&progressCur))
+    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;
+      di.FullSystemName = fullPath;
+      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 >= (UInt32)_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<IFolderFolder> 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 >= (UInt32)_drives.Size())
+    return E_INVALIDARG;
+  const CDriveInfo &di = _drives[index];
+  /*
+  if (_volumeMode)
+  {
+    *resultFolder = 0;
+    CPhysDriveFolder *folderSpec = new CPhysDriveFolder;
+    CMyComPtr<IFolderFolder> 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 = 0;
+  const CDriveInfo &di = _drives[index];
+  if (di.IsPhysicalDrive)
+    return S_OK;
+  int iconIndexTemp;
+  if (GetRealIconIndex(di.FullSystemName, 0, iconIndexTemp) != 0)
+  {
+    *iconIndex = iconIndexTemp;
+    return S_OK;
+  }
+  return GetLastError_noZero_HRESULT();
+}
+
+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))
+  
+  FString destPath = us2fs(path);
+  if (destPath.IsEmpty())
+    return E_INVALIDARG;
+
+  bool isAltDest = NName::IsAltPathPrefix(destPath);
+  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++)
+  {
+    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;
+    }
+    
+    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
new file mode 100644
index 0000000..8ae831c
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/FSDrives.h
@@ -0,0 +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<CDriveInfo> _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
new file mode 100644
index 0000000..06c572d
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/FSFolder.cpp
@@ -0,0 +1,1200 @@
+// FSFolder.cpp
+
+#include "StdAfx.h"
+
+#ifdef __MINGW32_VERSION
+// #if !defined(_MSC_VER) && (__GNUC__) && (__GNUC__ < 10)
+// for old mingw
+#include <ddk/ntddk.h>
+#else
+#ifndef Z7_OLD_WIN_SDK
+  #if !defined(_M_IA64)
+    #include <winternl.h>
+  #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 _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)
+{
+  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 += '*'; // 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.CreateAlways(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 (_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;
+
+
+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 >= (UInt32)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 >= (UInt32)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 >= (UInt32)Files.Size()) { ss1 = &Streams[index1 - Files.Size()]; index1 = ss1->Parent; }
+  if (index2 >= (UInt32)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<IFolderFolder> 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<IFolderFolder> 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<IFolderFolder> 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(pos);
+  pos = parentPath.ReverseFind_PathSepar();
+  parentPath.DeleteFrom((unsigned)(pos + 1));
+
+  if (NName::IsDrivePath_SuperAllowed(parentPath))
+  {
+    CFSFolder *parentFolderSpec = new CFSFolder;
+    CMyComPtr<IFolderFolder> 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<IFolderFolder> 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<IFolderFolder> 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 >= (UInt32)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(absPath, false))
+    return GetLastError_noZero_HRESULT();
+  return S_OK;
+}
+
+Z7_COM7F_IMF(CFSFolder::Rename(UInt32 index, const wchar_t *newName, IProgress * /* progress */))
+{
+  if (index >= (UInt32)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 >= (UInt32)Files.Size())
+    {
+      const CAltStream &ss = Streams[index - (UInt32)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 >= (UInt32)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))
+{
+  if (index >= (UInt32)Files.Size())
+    return E_INVALIDARG;
+  const CDirItem &fi = Files[index];
+  *iconIndex = 0;
+  int iconIndexTemp;
+  if (GetRealIconIndex(_path + GetRelPath(fi), fi.Attrib, iconIndexTemp) != 0)
+  {
+    *iconIndex = iconIndexTemp;
+    return S_OK;
+  }
+  return GetLastError_noZero_HRESULT();
+}
+
+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
new file mode 100644
index 0000000..fe8538a
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/FSFolder.h
@@ -0,0 +1,221 @@
+// 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;
+
+  #ifndef UNDER_CE
+  CByteBuffer Reparse;
+  #endif
+  
+  UInt64 NumFolders;
+  UInt64 NumFiles;
+  
+  int Parent;
+};
+
+/*
+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)
+
+private:
+  FString _path;
+  
+  CObjectVector<CDirItem> Files;
+  FStringVector Folders;
+  // CObjectVector<CAltStream> Streams;
+  // CMyComPtr<IFolderFolder> _parentFolder;
+
+  bool _commentsAreLoaded;
+  CPairsStorage _comments;
+
+  // bool _scanAltStreams;
+  bool _flatMode;
+
+  #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)
+    // , _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
new file mode 100644
index 0000000..db4ae0a
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/FSFolderCopy.cpp
@@ -0,0 +1,810 @@
+// 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(outPath, true))
+    {
+      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);
+}
+
+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
+    );
+
+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
+    );
+
+typedef BOOL (WINAPI * Func_MoveFileWithProgressW)(
+    IN LPCWSTR lpExistingFileName,
+    IN LPCWSTR lpNewFileName,
+    IN LPPROGRESS_ROUTINE lpProgressRoutine OPTIONAL,
+    IN LPVOID lpData OPTIONAL,
+    IN DWORD dwFlags
+    );
+
+struct CCopyState
+{
+  CProgressInfo ProgressInfo;
+  IFolderOperationsExtractCallback *Callback;
+  bool MoveMode;
+  bool UseReadWriteMode;
+  bool IsAltStreamsDest;
+
+  Func_CopyFileExW my_CopyFileExW;
+  #ifndef UNDER_CE
+  Func_MoveFileWithProgressW my_MoveFileWithProgressW;
+  #endif
+  #ifndef _UNICODE
+  Func_CopyFileExA my_CopyFileExA;
+  #endif
+
+  void Prepare();
+  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);
+}
+
+void CCopyState::Prepare()
+{
+  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
+  }
+}
+
+/* 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;
+  if (my_CopyFileExW)
+    return BOOLToBool(my_CopyFileExW(oldFile, newFile, CopyProgressRoutine,
+        &ProgressInfo, &cancelFlag, COPY_FILE_FAIL_IF_EXISTS));
+  return BOOLToBool(::CopyFileW(oldFile, newFile, TRUE));
+}
+
+bool CCopyState::CopyFile_Sys(CFSTR oldFile, CFSTR newFile)
+{
+  #ifndef _UNICODE
+  if (!g_IsNT)
+  {
+    if (my_CopyFileExA)
+    {
+      BOOL cancelFlag = FALSE;
+      if (my_CopyFileExA(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())
+  // {
+    if (my_MoveFileWithProgressW)
+    {
+      IF_USE_MAIN_PATH_2(oldFile, newFile)
+      {
+        if (my_MoveFileWithProgressW(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 (my_MoveFileWithProgressW(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)
+      {
+        // GetLastError() is ERROR_REQUEST_ABORTED in case of PROGRESS_CANCEL.
+        RINOK(SendMessageError(state.Callback, GetLastErrorMessage(), 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;
+  state.Prepare();
+
+  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;
+  state.Prepare();
+
+  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
new file mode 100644
index 0000000..e4e9997
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/FileFolderPluginOpen.cpp
@@ -0,0 +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<IInStream> InStream;
+  CMyComPtr<IFolderManager> FolderManager;
+  CMyComPtr<IProgress> OpenCallbackProgress;
+  
+  COpenArchiveCallback *OpenCallbackSpec;
+  /*
+  CMyComPtr<IUnknown>
+  // CMyComPtr<IProgress>
+  // CMyComPtr<IArchiveOpenCallback>
+    OpenCallbackSpec_Ref;
+  */
+
+  CMyComPtr<IFolderFolder> 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<CPluginInfo> &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<CArcLevelInfo> Levels; // LastLevel Is NON-OPEN
+};
+
+
+UString GetOpenArcErrorMessage(UInt32 errorFlags);
+
+
+static void GetFolderLevels(CMyComPtr<IFolderFolder> &folder, CArcLevelsInfo &levels)
+{
+  levels.Levels.Clear();
+
+  CMyComPtr<IGetFolderArcProps> getFolderArcProps;
+  folder.QueryInterface(IID_IGetFolderArcProps, &getFolderArcProps);
+  
+  if (!getFolderArcProps)
+    return;
+  CMyComPtr<IFolderArcProps> 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 += ']';
+  return s;
+}
+
+static void GetFolderError(CMyComPtr<IFolderFolder> &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<CPluginInfo> 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
new file mode 100644
index 0000000..8802765
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/FileFolderPluginOpen.h
@@ -0,0 +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<IFolderFolder> 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
new file mode 100644
index 0000000..cf20970
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/FilePlugins.cpp
@@ -0,0 +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<IFolderManager> 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
new file mode 100644
index 0000000..db8ec39
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/FilePlugins.h
@@ -0,0 +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<CPluginToIcon> Plugins;
+};
+
+class CExtDatabase
+{
+  int FindExt(const UString &ext) const;
+public:
+  CObjectVector<CExtPlugins> Exts;
+  // CObjectVector<CPluginInfo> Plugins;
+  
+  void Read();
+};
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/FoldersPage.cpp b/CPP/7zip/UI/FileManager/FoldersPage.cpp
new file mode 100644
index 0000000..7e74635
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/FoldersPage.cpp
@@ -0,0 +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);
+}
diff --git a/CPP/7zip/UI/FileManager/FoldersPage.h b/CPP/7zip/UI/FileManager/FoldersPage.h
new file mode 100644
index 0000000..09b6cdd
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/FoldersPage.h
@@ -0,0 +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
diff --git a/CPP/7zip/UI/FileManager/FoldersPage.rc b/CPP/7zip/UI/FileManager/FoldersPage.rc
new file mode 100644
index 0000000..cb345ea
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/FoldersPage.rc
@@ -0,0 +1,23 @@
+#include "FoldersPageRes.h"
+#include "../../GuiCommon.rc"
+
+#define xc 240
+#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
new file mode 100644
index 0000000..9b9276e
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/FoldersPage2.rc
@@ -0,0 +1,16 @@
+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
+  CONTROL    "&System temp folder", IDR_FOLDERS_WORK_SYSTEM,    "Button", BS_AUTORADIOBUTTON | WS_GROUP,
+             m, 20, xc, 10
+  CONTROL    "&Current",            IDR_FOLDERS_WORK_CURRENT,   "Button", BS_AUTORADIOBUTTON,
+             m, 34, xc, 10
+  CONTROL    "Specified:",          IDR_FOLDERS_WORK_SPECIFIED, "Button", BS_AUTORADIOBUTTON,
+             m, 48, xc, 10
+  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
+  CONTROL    "Use for removable drives only", IDX_FOLDERS_WORK_FOR_REMOVABLE, MY_CHECKBOX,
+             m, 86, xc, 10
+END
diff --git a/CPP/7zip/UI/FileManager/FoldersPageRes.h b/CPP/7zip/UI/FileManager/FoldersPageRes.h
new file mode 100644
index 0000000..ba9ab73
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/FoldersPageRes.h
@@ -0,0 +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
diff --git a/CPP/7zip/UI/FileManager/FormatUtils.cpp b/CPP/7zip/UI/FileManager/FormatUtils.cpp
index 4f7ef74..2143c3f 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 f221cd2..1db08ef 100644
--- a/CPP/7zip/UI/FileManager/FormatUtils.h
+++ b/CPP/7zip/UI/FileManager/FormatUtils.h
@@ -1,14 +1,14 @@
-// FormatUtils.h

-

-#ifndef __FORMAT_UTILS_H

-#define __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
new file mode 100644
index 0000000..d5b6a58
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/HelpUtils.cpp
@@ -0,0 +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 <HtmlHelp.h>
+#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
new file mode 100644
index 0000000..d7bdf45
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/HelpUtils.h
@@ -0,0 +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
diff --git a/CPP/7zip/UI/FileManager/IFolder.h b/CPP/7zip/UI/FileManager/IFolder.h
new file mode 100644
index 0000000..1ebdf7e
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/IFolder.h
@@ -0,0 +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
diff --git a/CPP/7zip/UI/FileManager/Info.bmp b/CPP/7zip/UI/FileManager/Info.bmp
new file mode 100644
index 0000000..d769a66
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/Info.bmp
Binary files differ
diff --git a/CPP/7zip/UI/FileManager/Info2.bmp b/CPP/7zip/UI/FileManager/Info2.bmp
new file mode 100644
index 0000000..af724d2
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/Info2.bmp
Binary files differ
diff --git a/CPP/7zip/UI/FileManager/LangPage.cpp b/CPP/7zip/UI/FileManager/LangPage.cpp
new file mode 100644
index 0000000..ec1dd2e
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/LangPage.cpp
@@ -0,0 +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 = 429;
+
+#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 += ')';
+}
+
+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<CLangListRecord> 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
new file mode 100644
index 0000000..e37ba05
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/LangPage.h
@@ -0,0 +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<CLangInfo> _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
new file mode 100644
index 0000000..506f102
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/LangPage.rc
@@ -0,0 +1,40 @@
+#include "LangPageRes.h"
+#include "../../GuiCommon.rc"
+
+#define xc 240
+#define yc 252
+
+#define y 32
+
+IDD_LANG  DIALOG  0, 0, xs, ys  MY_PAGE_STYLE  MY_FONT
+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
new file mode 100644
index 0000000..a1ad30f
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/LangPageRes.h
@@ -0,0 +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
diff --git a/CPP/7zip/UI/FileManager/LangUtils.cpp b/CPP/7zip/UI/FileManager/LangUtils.cpp
new file mode 100644
index 0000000..4c9d16f
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/LangUtils.cpp
@@ -0,0 +1,326 @@
+// 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);
+  }
+}
+
+static const CIDLangPair kLangPairs[] =
+{
+  { IDOK,     401 },
+  { IDCANCEL, 402 },
+  { IDYES,    406 },
+  { IDNO,     407 },
+  { IDCLOSE,  408 },
+  { IDHELP,   409 }
+};
+
+
+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 += ':';
+      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.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 += (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;
+  const LANGID sysLang = GetSystemDefaultLangID(); // "Language for non-Unicode programs" in XP64
+  const LANGID userLang = GetUserDefaultLangID(); // "Standards and formats" language in XP64
+
+  if (sysLang != 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 c694423..d53d270 100644
--- a/CPP/7zip/UI/FileManager/LangUtils.h
+++ b/CPP/7zip/UI/FileManager/LangUtils.h
@@ -1,40 +1,48 @@
-// LangUtils.h

-

-#ifndef __LANG_UTILS_H

-#define __LANG_UTILS_H

-

-#include "../../../Windows/ResourceString.h"

-

-#ifdef LANG

-

-extern UString g_LangID;

-

-struct CIDLangPair

-{

-  UInt32 ControlID;

-  UInt32 LangID;

-};

-

-void ReloadLang();

-void LoadLangOneTime();

-FString GetLangDirPrefix();

-

-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 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

-

-#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
new file mode 100644
index 0000000..0f24761
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/LinkDialog.cpp
@@ -0,0 +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<UInt32> 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
new file mode 100644
index 0000000..dd768f7
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/LinkDialog.h
@@ -0,0 +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
diff --git a/CPP/7zip/UI/FileManager/LinkDialog.rc b/CPP/7zip/UI/FileManager/LinkDialog.rc
new file mode 100644
index 0000000..a9e220b
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/LinkDialog.rc
@@ -0,0 +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
diff --git a/CPP/7zip/UI/FileManager/LinkDialogRes.h b/CPP/7zip/UI/FileManager/LinkDialogRes.h
new file mode 100644
index 0000000..3f7b3f2
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/LinkDialogRes.h
@@ -0,0 +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
diff --git a/CPP/7zip/UI/FileManager/ListViewDialog.cpp b/CPP/7zip/UI/FileManager/ListViewDialog.cpp
new file mode 100644
index 0000000..6767e4c
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/ListViewDialog.cpp
@@ -0,0 +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();
+}
diff --git a/CPP/7zip/UI/FileManager/ListViewDialog.h b/CPP/7zip/UI/FileManager/ListViewDialog.h
new file mode 100644
index 0000000..5f0b66d
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/ListViewDialog.h
@@ -0,0 +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
diff --git a/CPP/7zip/UI/FileManager/ListViewDialog.rc b/CPP/7zip/UI/FileManager/ListViewDialog.rc
new file mode 100644
index 0000000..4343b75
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/ListViewDialog.rc
@@ -0,0 +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
+}
diff --git a/CPP/7zip/UI/FileManager/ListViewDialogRes.h b/CPP/7zip/UI/FileManager/ListViewDialogRes.h
new file mode 100644
index 0000000..9abdb9d
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/ListViewDialogRes.h
@@ -0,0 +1,2 @@
+#define IDD_LISTVIEW  99
+#define IDL_LISTVIEW 100
diff --git a/CPP/7zip/UI/FileManager/MenuPage.cpp b/CPP/7zip/UI/FileManager/MenuPage.cpp
new file mode 100644
index 0000000..2da7f3a
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/MenuPage.cpp
@@ -0,0 +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 += '(';
+    s += bit64;
+    s += ')';
+    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
new file mode 100644
index 0000000..3b62a8b
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/MenuPage.h
@@ -0,0 +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
diff --git a/CPP/7zip/UI/FileManager/MenuPage.rc b/CPP/7zip/UI/FileManager/MenuPage.rc
new file mode 100644
index 0000000..fc21107
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/MenuPage.rc
@@ -0,0 +1,24 @@
+#include "MenuPageRes.h"
+#include "../../GuiCommon.rc"
+
+#define xc 240
+#define yc 252
+
+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
new file mode 100644
index 0000000..4d1ba21
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/MenuPage2.rc
@@ -0,0 +1,28 @@
+#include "../GUI/ExtractDialogRes.h"
+
+#define y 96
+
+#define zoneX 90
+
+CAPTION "7-Zip"
+BEGIN
+  CONTROL  "Integrate 7-Zip to shell context menu", IDX_SYSTEM_INTEGRATE_TO_MENU, MY_CHECKBOX, m, m, xc, 10
+  CONTROL  "(32-bit)", IDX_SYSTEM_INTEGRATE_TO_MENU_2, MY_CHECKBOX, m, m + 14, xc, 10
+  CONTROL  "Cascaded context menu", IDX_SYSTEM_CASCADED_MENU, MY_CHECKBOX, m, m + 28, xc, 10
+  CONTROL  "Icons in context menu", IDX_SYSTEM_ICON_IN_MENU, MY_CHECKBOX, m, m + 42, xc, 10
+  CONTROL   "Eliminate duplication of root folder", IDX_EXTRACT_ELIM_DUP, MY_CHECKBOX, m, m + 56, xc, 10
+
+  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
new file mode 100644
index 0000000..e2cf798
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/MenuPageRes.h
@@ -0,0 +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
diff --git a/CPP/7zip/UI/FileManager/MessagesDialog.cpp b/CPP/7zip/UI/FileManager/MessagesDialog.cpp
new file mode 100644
index 0000000..57e56bc
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/MessagesDialog.cpp
@@ -0,0 +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;
+}
diff --git a/CPP/7zip/UI/FileManager/MessagesDialog.h b/CPP/7zip/UI/FileManager/MessagesDialog.h
new file mode 100644
index 0000000..40b0379
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/MessagesDialog.h
@@ -0,0 +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
diff --git a/CPP/7zip/UI/FileManager/MessagesDialog.rc b/CPP/7zip/UI/FileManager/MessagesDialog.rc
new file mode 100644
index 0000000..49b73e8
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/MessagesDialog.rc
@@ -0,0 +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
+}
diff --git a/CPP/7zip/UI/FileManager/MessagesDialogRes.h b/CPP/7zip/UI/FileManager/MessagesDialogRes.h
new file mode 100644
index 0000000..c8fffff
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/MessagesDialogRes.h
@@ -0,0 +1,3 @@
+#define IDD_MESSAGES  6602
+#define IDS_MESSAGE   6603
+#define IDL_MESSAGE    100
diff --git a/CPP/7zip/UI/FileManager/Move.bmp b/CPP/7zip/UI/FileManager/Move.bmp
new file mode 100644
index 0000000..eb5f20f
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/Move.bmp
Binary files differ
diff --git a/CPP/7zip/UI/FileManager/Move2.bmp b/CPP/7zip/UI/FileManager/Move2.bmp
new file mode 100644
index 0000000..58679ef
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/Move2.bmp
Binary files differ
diff --git a/CPP/7zip/UI/FileManager/MyCom2.h b/CPP/7zip/UI/FileManager/MyCom2.h
new file mode 100644
index 0000000..d3b49fe
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/MyCom2.h
@@ -0,0 +1,55 @@
+// MyCom2.h
+
+#ifndef ZIP7_INC_MYCOM2_H
+#define ZIP7_INC_MYCOM2_H
+
+#include "../../../Common/MyCom.h"
+
+#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_UNKNOWN_IMP_SPEC_MT2(i1, i) \
+  Z7_COM_QI_BEGIN \
+  Z7_COM_QI_ENTRY_UNKNOWN(i1) \
+  i \
+  Z7_COM_QI_END \
+  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
new file mode 100644
index 0000000..9453536
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/MyLoadMenu.cpp
@@ -0,0 +1,918 @@
+// MyLoadMenu.cpp
+
+#include "StdAfx.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 "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;
+
+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);
+      }
+    }
+  }
+  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 += c;
+      s += "\tAlt+Shift+";
+      s += 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 += (char)('0' + i);
+      menu.AppendItem(MF_STRING, k_MenuID_OpenBookmark + i, s);
+    }
+  }
+}
+
+/*
+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_SHA1: g_App.CalculateCrc("SHA1"); break;
+    case IDM_SHA256: g_App.CalculateCrc("SHA256"); 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;
+
+    // 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;
+    }
+    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
new file mode 100644
index 0000000..e71dbbf
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/MyLoadMenu.h
@@ -0,0 +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
diff --git a/CPP/7zip/UI/FileManager/MyWindowsNew.h b/CPP/7zip/UI/FileManager/MyWindowsNew.h
index c0fe843..325babc 100644
--- a/CPP/7zip/UI/FileManager/MyWindowsNew.h
+++ b/CPP/7zip/UI/FileManager/MyWindowsNew.h
@@ -1,76 +1,119 @@
-// MyWindowsNew.h

-

-#ifndef __MY_WINDOWS_NEW_H

-#define __MY_WINDOWS_NEW_H

-

-#ifdef _MSC_VER

-

-#include <ShObjIdl.h>

-

-#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 <pshpack8.h>

-

-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

-

-#endif

-

-#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 <shobjidl.h>
+
+#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 <ShObjIdl.h>
+#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 <pshpack8.h>
+
+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
new file mode 100644
index 0000000..879f1db
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/NetFolder.cpp
@@ -0,0 +1,281 @@
+// 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<IFolderFolder> subFolder = fsFolderSpec;
+    RINOK(fsFolderSpec->Init(us2fs(resource.RemoteName + WCHAR_PATH_SEPARATOR))) // , this
+    *resultFolder = subFolder.Detach();
+  }
+  else
+  {
+    CNetFolder *netFolder = new CNetFolder;
+    CMyComPtr<IFolderFolder> 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<IFolderFolder> 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<IFolderFolder> 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))
+{
+  if (index >= (UInt32)_items.Size())
+    return E_INVALIDARG;
+  *iconIndex = 0;
+  const CResourceW &resource = _items[index];
+  int iconIndexTemp;
+  if (resource.DisplayType == RESOURCEDISPLAYTYPE_SERVER ||
+      resource.Usage == RESOURCEUSAGE_CONNECTABLE)
+  {
+    if (GetRealIconIndex(us2fs(resource.RemoteName), 0, iconIndexTemp))
+    {
+      *iconIndex = iconIndexTemp;
+      return S_OK;
+    }
+  }
+  else
+  {
+    if (GetRealIconIndex(FTEXT(""), FILE_ATTRIBUTE_DIRECTORY, iconIndexTemp))
+    {
+      *iconIndex = iconIndexTemp;
+      return S_OK;
+    }
+    // *anIconIndex = GetRealIconIndex(0, L"\\\\HOME");
+  }
+  return GetLastError_noZero_HRESULT();
+}
diff --git a/CPP/7zip/UI/FileManager/NetFolder.h b/CPP/7zip/UI/FileManager/NetFolder.h
new file mode 100644
index 0000000..352f5bd
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/NetFolder.h
@@ -0,0 +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<CResourceEx> _items;
+
+  CMyComPtr<IFolderFolder> _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
new file mode 100644
index 0000000..5b6df50
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/OpenCallback.cpp
@@ -0,0 +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
diff --git a/CPP/7zip/UI/FileManager/OpenCallback.h b/CPP/7zip/UI/FileManager/OpenCallback.h
new file mode 100644
index 0000000..8f4638c
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/OpenCallback.h
@@ -0,0 +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
diff --git a/CPP/7zip/UI/FileManager/OptionsDialog.cpp b/CPP/7zip/UI/FileManager/OptionsDialog.cpp
new file mode 100644
index 0000000..b71c323
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/OptionsDialog.cpp
@@ -0,0 +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<NControl::CPageInfo> 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 3f0180d..096527c 100644
--- a/CPP/7zip/UI/FileManager/OverwriteDialog.cpp
+++ b/CPP/7zip/UI/FileManager/OverwriteDialog.cpp
@@ -1,122 +1,138 @@
-// OverwriteDialog.cpp

-

-#include "StdAfx.h"

-

-#include "../../../Common/StringConvert.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 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 = 82;

-static const unsigned kCurrentFileNameSizeLimit2 = 30;

-

-void COverwriteDialog::ReduceString(UString &s)

-{

-  unsigned size = _isBig ? kCurrentFileNameSizeLimit : kCurrentFileNameSizeLimit2;

-  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);

-    s.InsertAtFront(L'\"');

-    s += L'\"';

-  }

-}

-

-void COverwriteDialog::SetFileInfoControl(int textID, int iconID,

-    const NOverwriteDialog::CFileInfo &fileInfo)

-{

-  UString sizeString;

-  if (fileInfo.SizeIsDefined)

-    sizeString = MyFormatNew(IDS_FILE_SIZE, NumberToString(fileInfo.Size));

-

-  const UString &fileName = fileInfo.Name;

-  int slashPos = fileName.ReverseFind_PathSepar();

-  UString s1 = fileName.Left(slashPos + 1);

-  UString s2 = fileName.Ptr(slashPos + 1);

-

-  ReduceString(s1);

-  ReduceString(s2);

-  

-  UString s = s1;

-  s.Add_LF();

-  s += s2;

-  s.Add_LF();

-  s += sizeString;

-  s.Add_LF();

-

-  if (fileInfo.TimeIsDefined)

-  {

-    AddLangString(s, IDS_PROP_MTIME);

-    s += ": ";

-    char t[32];

-    ConvertUtcFileTimeToString(fileInfo.Time, t);

-    s += t;

-  }

-

-  NControl::CDialogChildControl control;

-  control.Init(*this, textID);

-  control.SetText(s);

-

-  SHFILEINFO shellFileInfo;

-  if (::SHGetFileInfo(

-      GetSystemString(fileInfo.Name), FILE_ATTRIBUTE_NORMAL, &shellFileInfo,

-      sizeof(shellFileInfo), SHGFI_ICON | SHGFI_USEFILEATTRIBUTES | SHGFI_LARGEICON))

-  {

-    NControl::CStatic staticContol;

-    staticContol.Attach(GetItem(iconID));

-    staticContol.SetIcon(shellFileInfo.hIcon);

-  }

-}

-

-bool COverwriteDialog::OnInit()

-{

-  #ifdef LANG

-  LangSetWindowText(*this, IDD_OVERWRITE);

-  LangSetDlgItems(*this, kLangIDs, ARRAY_SIZE(kLangIDs));

-  #endif

-  SetFileInfoControl(IDT_OVERWRITE_OLD_FILE_SIZE_TIME, IDI_OVERWRITE_OLD_FILE, OldFileInfo);

-  SetFileInfoControl(IDT_OVERWRITE_NEW_FILE_SIZE_TIME, IDI_OVERWRITE_NEW_FILE, NewFileInfo);

-  NormalizePosition();

-  return CModalDialog::OnInit();

-}

-

-bool COverwriteDialog::OnButtonClicked(int buttonID, HWND buttonHWND)

-{

-  switch (buttonID)

-  {

-    case IDYES:

-    case IDNO:

-    case IDB_YES_TO_ALL:

-    case IDB_NO_TO_ALL:

-    case IDB_AUTO_RENAME:

-      End(buttonID);

-      return true;

-  }

-  return CModalDialog::OnButtonClicked(buttonID, buttonHWND);

-}

+// OverwriteDialog.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/StringConvert.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 = 82;
+static const unsigned kCurrentFileNameSizeLimit2 = 30;
+
+void COverwriteDialog::ReduceString(UString &s)
+{
+  unsigned size = _isBig ? kCurrentFileNameSizeLimit : kCurrentFileNameSizeLimit2;
+  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);
+    s.InsertAtFront(L'\"');
+    s += L'\"';
+  }
+}
+
+void COverwriteDialog::SetFileInfoControl(unsigned textID, unsigned iconID,
+    const NOverwriteDialog::CFileInfo &fileInfo)
+{
+  UString sizeString;
+  if (fileInfo.SizeIsDefined)
+    sizeString = MyFormatNew(IDS_FILE_SIZE, NumberToString(fileInfo.Size));
+
+  const UString &fileName = fileInfo.Name;
+  int slashPos = fileName.ReverseFind_PathSepar();
+  UString s1 = fileName.Left((unsigned)(slashPos + 1));
+  UString s2 = fileName.Ptr((unsigned)(slashPos + 1));
+
+  ReduceString(s1);
+  ReduceString(s2);
+  
+  UString s = s1;
+  s.Add_LF();
+  s += s2;
+  s.Add_LF();
+  s += sizeString;
+  s.Add_LF();
+
+  if (fileInfo.TimeIsDefined)
+  {
+    AddLangString(s, IDS_PROP_MTIME);
+    s += ": ";
+    char t[32];
+    ConvertUtcFileTimeToString(fileInfo.Time, t);
+    s += t;
+  }
+
+  NControl::CDialogChildControl control;
+  control.Init(*this, textID);
+  control.SetText(s);
+
+  SHFILEINFO shellFileInfo;
+  if (::SHGetFileInfo(
+      GetSystemString(fileInfo.Name), FILE_ATTRIBUTE_NORMAL, &shellFileInfo,
+      sizeof(shellFileInfo), SHGFI_ICON | SHGFI_USEFILEATTRIBUTES | SHGFI_LARGEICON))
+  {
+    NControl::CStatic staticContol;
+    staticContol.Attach(GetItem(iconID));
+    staticContol.SetIcon(shellFileInfo.hIcon);
+  }
+}
+
+bool COverwriteDialog::OnInit()
+{
+  #ifdef Z7_LANG
+  LangSetWindowText(*this, IDD_OVERWRITE);
+  LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs));
+  #endif
+  SetFileInfoControl(IDT_OVERWRITE_OLD_FILE_SIZE_TIME, IDI_OVERWRITE_OLD_FILE, OldFileInfo);
+  SetFileInfoControl(IDT_OVERWRITE_NEW_FILE_SIZE_TIME, IDI_OVERWRITE_NEW_FILE, NewFileInfo);
+  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::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 4564a47..a9ca991 100644
--- a/CPP/7zip/UI/FileManager/OverwriteDialog.h
+++ b/CPP/7zip/UI/FileManager/OverwriteDialog.h
@@ -1,69 +1,79 @@
-// OverwriteDialog.h

-

-#ifndef __OVERWRITE_DIALOG_H

-#define __OVERWRITE_DIALOG_H

-

-#include "../../../Windows/Control/Dialog.h"

-

-#include "DialogSize.h"

-#include "OverwriteDialogRes.h"

-

-namespace NOverwriteDialog

-{

-  struct CFileInfo

-  {

-    bool SizeIsDefined;

-    bool TimeIsDefined;

-    UInt64 Size;

-    FILETIME Time;

-    UString Name;

-    

-    void SetTime(const FILETIME *t)

-    {

-      if (t == 0)

-        TimeIsDefined = false;

-      else

-      {

-        TimeIsDefined = true;

-        Time = *t;

-      }

-    }

-    void SetSize(const UInt64 *size)

-    {

-      if (size == 0)

-        SizeIsDefined = false;

-      else

-      {

-        SizeIsDefined = true;

-        Size = *size;

-      }

-    }

-  };

-}

-

-class COverwriteDialog: public NWindows::NControl::CModalDialog

-{

-  bool _isBig;

-

-  void SetFileInfoControl(int textID, int iconID, const NOverwriteDialog::CFileInfo &fileInfo);

-  virtual bool OnInit();

-  bool OnButtonClicked(int buttonID, HWND buttonHWND);

-  void ReduceString(UString &s);

-

-public:

-  INT_PTR Create(HWND parent = 0)

-  {

-    BIG_DIALOG_SIZE(280, 200);

-    #ifdef UNDER_CE

-    _isBig = isBig;

-    #else

-    _isBig = true;

-    #endif

-    return CModalDialog::Create(SIZED_DIALOG(IDD_OVERWRITE), parent);

-  }

-

-  NOverwriteDialog::CFileInfo OldFileInfo;

-  NOverwriteDialog::CFileInfo NewFileInfo;

-};

-

-#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 SizeIsDefined;
+    bool TimeIsDefined;
+    UInt64 Size;
+    FILETIME Time;
+    UString Name;
+    
+    void SetTime(const FILETIME *t)
+    {
+      if (!t)
+        TimeIsDefined = false;
+      else
+      {
+        TimeIsDefined = true;
+        Time = *t;
+      }
+    }
+
+    void SetSize(UInt64 size)
+    {
+      SizeIsDefined = true;
+      Size = size;
+    }
+
+    void SetSize(const UInt64 *size)
+    {
+      if (!size)
+        SizeIsDefined = false;
+      else
+        SetSize(*size);
+    }
+  };
+}
+
+class COverwriteDialog: public NWindows::NControl::CModalDialog
+{
+  bool _isBig;
+
+  void SetFileInfoControl(unsigned textID, unsigned iconID, const NOverwriteDialog::CFileInfo &fileInfo);
+  virtual bool OnInit() Z7_override;
+  virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override;
+  void ReduceString(UString &s);
+
+public:
+  bool ShowExtraButtons;
+  bool DefaultButton_is_NO;
+
+
+  COverwriteDialog(): ShowExtraButtons(true), DefaultButton_is_NO(false) {}
+
+  INT_PTR Create(HWND parent = NULL)
+  {
+    BIG_DIALOG_SIZE(280, 200);
+    #ifdef UNDER_CE
+    _isBig = isBig;
+    #else
+    _isBig = true;
+    #endif
+    return CModalDialog::Create(SIZED_DIALOG(IDD_OVERWRITE), parent);
+  }
+
+  NOverwriteDialog::CFileInfo OldFileInfo;
+  NOverwriteDialog::CFileInfo NewFileInfo;
+};
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/OverwriteDialog.rc b/CPP/7zip/UI/FileManager/OverwriteDialog.rc
index 80f48b0..29f9912 100644
--- a/CPP/7zip/UI/FileManager/OverwriteDialog.rc
+++ b/CPP/7zip/UI/FileManager/OverwriteDialog.rc
@@ -1,91 +1,91 @@
-#include "OverwriteDialogRes.h"

-#include "../../GuiCommon.rc"

-

-#define xc 280

-#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

-  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

-  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 280
+#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
+  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
+  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 28bc0d0..b480ba1 100644
--- a/CPP/7zip/UI/FileManager/OverwriteDialogRes.h
+++ b/CPP/7zip/UI/FileManager/OverwriteDialogRes.h
@@ -1,17 +1,17 @@
-#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_NEW_FILE             101

-

-#define IDT_OVERWRITE_OLD_FILE_SIZE_TIME   102

-#define IDT_OVERWRITE_NEW_FILE_SIZE_TIME   103

+#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_NEW_FILE             101
+
+#define IDT_OVERWRITE_OLD_FILE_SIZE_TIME   102
+#define IDT_OVERWRITE_NEW_FILE_SIZE_TIME   103
diff --git a/CPP/7zip/UI/FileManager/Panel.cpp b/CPP/7zip/UI/FileManager/Panel.cpp
new file mode 100644
index 0000000..72b72c6
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/Panel.cpp
@@ -0,0 +1,1182 @@
+// Panel.cpp
+
+#include "StdAfx.h"
+
+#include <windowsx.h>
+
+#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;
+extern DWORD g_ComCtl32Version;
+
+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 &currentFolderPrefix,
+    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(GetSysImageList(true), LVSIL_SMALL);
+  _listView.SetImageList(GetSysImageList(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},
+  };
+
+  #ifndef UNDER_CE
+  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, 520,
+      (_headerReBar ? _headerToolBar : (HWND)*this),
+      (HMENU)(UINT_PTR)(_comboBoxID),
+      g_hInstance, NULL);
+  #ifndef UNDER_CE
+  _headerComboBox.SetUnicodeFormat(true);
+
+  _headerComboBox.SetImageList(GetSysImageList(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<UInt32> 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<UInt32> &operatedIndices) const
+{
+  const bool *isDirVector = &_isDirVector.Front();
+  const UInt32 *indices = &operatedIndices.Front();
+  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<UInt32> &operatedIndices, UStringVector &paths) const
+{
+  paths.ClearAndReserve(operatedIndices.Size());
+  UString path = GetFsPath();
+  const unsigned prefixLen = path.Len();
+  const UInt32 *indices = &operatedIndices.Front();
+  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<UInt32> 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 += '*';
+  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<UInt32> Indices;
+  CExtractCallbackImp *ExtractCallbackSpec;
+  CMyComPtr<IFolderArchiveExtractCallback> ExtractCallback;
+  CMyComPtr<IArchiveFolder> 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<UInt32> indices;
+  Get_ItemIndices_OperSmart(indices);
+  CMyComPtr<IArchiveFolder> 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
new file mode 100644
index 0000000..e512cad
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/Panel.h
@@ -0,0 +1,1016 @@
+// Panel.h
+
+#ifndef ZIP7_INC_PANEL_H
+#define ZIP7_INC_PANEL_H
+
+#include "../../../Common/MyWindows.h"
+
+#if defined(__MINGW32__) || defined(__MINGW64__)
+#include <shlobj.h>
+#else
+#include <ShlObj.h>
+#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
+
+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<CPropColumn>
+{
+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
+  UString RelPath;   // Relative path of file from Folder
+  FString FolderPath;
+  FString FilePath;
+  NWindows::NFile::NFind::CFileInfo FileInfo;
+  bool NeedDelete;
+
+  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
+{
+  NWindows::NDLL::CLibrary Library;
+  CMyComPtr<IFolderFolder> 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)
+  bool UsePassword;
+  UString Password;
+  bool IsVirtual;
+
+  UString VirtualPath; // without tail slash
+  CFolderLink(): UsePassword(false), IsVirtual(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, int 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<PROPID> 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<CFolderLink> _parentFolders;
+  NWindows::NDLL::CLibrary _library;
+  
+  CMyComPtr<IFolderFolder> _folder;
+  CBoolVector _isDirVector;
+  CMyComPtr<IFolderCompare> _folderCompare;
+  CMyComPtr<IFolderGetItemName> _folderGetItemName;
+  CMyComPtr<IArchiveGetRawProps> _folderRawProps;
+  CMyComPtr<IFolderAltStreams> _folderAltStreams;
+  CMyComPtr<IFolderOperations> _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<IFolderGetSystemIconIndex> _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 &currentFolderPrefix,
+      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<IContextMenu> _sevenZipContextMenu;
+  CMyComPtr<IContextMenu> _systemContextMenu;
+  
+  HRESULT CreateShellContextMenu(
+      const CRecordVector<UInt32> &operatedIndices,
+      CMyComPtr<IContextMenu> &systemContextMenu);
+  
+  void CreateSystemMenu(HMENU menu,
+      bool showExtendedVerbs,
+      const CRecordVector<UInt32> &operatedIndices,
+      CMyComPtr<IContextMenu> &systemContextMenu);
+  
+  void CreateSevenZipMenu(HMENU menu,
+      bool showExtendedVerbs,
+      const CRecordVector<UInt32> &operatedIndices,
+      int firstDirIndex,
+      CMyComPtr<IContextMenu> &sevenZipContextMenu);
+  
+  void CreateFileMenu(HMENU menu,
+      CMyComPtr<IContextMenu> &sevenZipContextMenu,
+      CMyComPtr<IContextMenu> &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<UInt32> &indices) const;
+  void Get_ItemIndices_Operated(CRecordVector<UInt32> &indices) const;
+  void Get_ItemIndices_All(CRecordVector<UInt32> &indices) const;
+  void Get_ItemIndices_OperSmart(CRecordVector<UInt32> &indices) const;
+  // void GetOperatedListViewIndices(CRecordVector<UInt32> &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<UInt32> &indices) const;
+  void GetFilePaths(const CRecordVector<UInt32> &indices, UStringVector &paths) const;
+  void ExtractArchives();
+  void TestArchives();
+
+
+  HRESULT CopyTo(CCopyToOptions &options,
+      const CRecordVector<UInt32> &indices,
+      UStringVector *messages,
+      bool &usePassword, UString &password,
+      const UStringVector *filePaths = NULL);
+
+  HRESULT CopyTo(CCopyToOptions &options,
+      const CRecordVector<UInt32> &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<UInt32> 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<UInt32> &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
diff --git a/CPP/7zip/UI/FileManager/PanelCopy.cpp b/CPP/7zip/UI/FileManager/PanelCopy.cpp
new file mode 100644
index 0000000..de3d764
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/PanelCopy.cpp
@@ -0,0 +1,435 @@
+/// 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<IFolderOperations> FolderOperations;
+  CRecordVector<UInt32> Indices;
+  CExtractCallbackImp *ExtractCallbackSpec;
+  CMyComPtr<IFolderOperationsExtractCallback> 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<IFolderSetReplaceAltStreamCharsMode> iReplace;
+  FolderOperations.QueryInterface(IID_IFolderSetReplaceAltStreamCharsMode, &iReplace);
+  if (iReplace)
+  {
+    RINOK(iReplace->SetReplaceAltStreamCharsMode(ReplaceAltStreamChars ? 1 : 0));
+  }
+  */
+
+  HRESULT result2;
+
+  if (FolderOperations)
+  {
+    CMyComPtr<IFolderSetZoneIdMode> 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<IArchiveFolder> archiveFolder;
+    FolderOperations.QueryInterface(IID_IArchiveFolder, &archiveFolder);
+    if (!archiveFolder)
+      return E_NOTIMPL;
+    CMyComPtr<IFolderArchiveExtractCallback> extractCallback2;
+    RINOK(ExtractCallback.QueryInterface(IID_IFolderArchiveExtractCallback, &extractCallback2))
+    NExtract::NPathMode::EEnum pathMode =
+        NExtract::NPathMode::kCurPaths;
+        // NExtract::NPathMode::kFullPathnames;
+    result2 = archiveFolder->Extract(&Indices.Front(), 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.Front(), 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<UInt32> &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.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<IFolderOperations> FolderOperations;
+  UString FolderPrefix;
+  UStringVector FileNames;
+  CRecordVector<const wchar_t *> FileNamePointers;
+  CProgressDialog ProgressDialog;
+  CMyComPtr<IFolderArchiveUpdateCallback> UpdateCallback;
+  CUpdateCallback100Imp *UpdateCallbackSpec;
+  HRESULT Result;
+  bool MoveMode;
+  
+  void Process()
+  {
+    try
+    {
+      CProgressCloser closer(ProgressDialog);
+      Result = FolderOperations->CopyFrom(
+        MoveMode,
+        FolderPrefix,
+        &FileNamePointers.Front(),
+        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
new file mode 100644
index 0000000..df0b733
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/PanelCrc.cpp
@@ -0,0 +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<NFind::CEnumerator> 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<UInt32> 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
new file mode 100644
index 0000000..040444c
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/PanelDrag.cpp
@@ -0,0 +1,3006 @@
+// PanelDrag.cpp
+
+#include "StdAfx.h"
+
+#ifdef UNDER_CE
+#include <winuserm.h>
+#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<IDataObject> 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<UInt32> 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<IDataObject> 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<UInt32> 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<IDataObject> 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<IDropSource> 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;
+}
diff --git a/CPP/7zip/UI/FileManager/PanelFolderChange.cpp b/CPP/7zip/UI/FileManager/PanelFolderChange.cpp
new file mode 100644
index 0000000..a13b88d
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/PanelFolderChange.cpp
@@ -0,0 +1,913 @@
+// 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<IFolderFolder> 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<IFolderFolder> 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<IFolderFolder> 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(CFSTR path, DWORD attributes)
+{
+  int index = -1;
+  if (GetRealIconIndex(path, attributes, index) != 0)
+    return index;
+  return -1;
+}
+
+void CPanel::LoadFullPathAndShow()
+{
+  LoadFullPath();
+  _appState->FolderHistory.AddString(_currentFolderPrefix);
+
+  _headerComboBox.SetText(_currentFolderPrefix);
+
+  #ifndef UNDER_CE
+
+  COMBOBOXEXITEM item;
+  item.mask = 0;
+
+  UString path = _currentFolderPrefix;
+  if (path.Len() >
+      #ifdef _WIN32
+      3
+      #else
+      1
+      #endif
+      && IS_PATH_SEPAR(path.Back()))
+    path.DeleteBack();
+
+  DWORD attrib = FILE_ATTRIBUTE_DIRECTORY;
+
+  // GetRealIconIndex is slow for direct DVD/UDF path. So we use dummy path
+  if (path.IsPrefixedBy(L"\\\\.\\"))
+    path = "_TestFolder_";
+  else
+  {
+    CFileInfo fi;
+    if (fi.Find(us2fs(path)))
+      attrib = fi.Attrib;
+  }
+  item.iImage = GetRealIconIndex(us2fs(path), attrib);
+
+  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, int indent, bool addToList)
+{
+  #ifdef UNDER_CE
+
+  UString s;
+  iconIndex = iconIndex;
+  for (int i = 0; i < indent; i++)
+    s += "  ";
+  _headerComboBox.AddString(s + name);
+  
+  #else
+  
+  COMBOBOXEXITEMW item;
+  item.mask = CBEIF_TEXT | CBEIF_INDENT;
+  item.iSelectedImage = item.iImage = iconIndex;
+  if (iconIndex >= 0)
+    item.mask |= (CBEIF_IMAGE | CBEIF_SELECTEDIMAGE);
+  item.iItem = -1;
+  item.iIndent = indent;
+  item.pszText = name.Ptr_non_const();
+  _headerComboBox.InsertItem(&item);
+  
+  #endif
+
+  if (addToList)
+    ComboBoxPaths.Add(name);
+}
+
+extern UString RootFolder_GetName_Computer(int &iconIndex);
+extern UString RootFolder_GetName_Network(int &iconIndex);
+extern UString RootFolder_GetName_Documents(int &iconIndex);
+
+bool CPanel::OnComboBoxCommand(UINT code, LPARAM /* param */, LRESULT &result)
+{
+  result = FALSE;
+  switch (code)
+  {
+    case CBN_DROPDOWN:
+    {
+      ComboBoxPaths.Clear();
+      _headerComboBox.ResetContent();
+      
+      unsigned i;
+      UStringVector pathParts;
+      
+      SplitPathToParts(_currentFolderPrefix, pathParts);
+      UString sumPass;
+      if (!pathParts.IsEmpty())
+        pathParts.DeleteBack();
+      for (i = 0; i < pathParts.Size(); i++)
+      {
+        const UString name = pathParts[i];
+        sumPass += name;
+        sumPass.Add_PathSepar();
+        CFileInfo info;
+        DWORD attrib = FILE_ATTRIBUTE_DIRECTORY;
+        if (info.Find(us2fs(sumPass)))
+          attrib = info.Attrib;
+        AddComboBoxItem(
+            name.IsEmpty() ? L"\\" : name,
+            GetRealIconIndex(us2fs(sumPass), attrib),
+            (int)i, // iIndent
+            false); // addToList
+        ComboBoxPaths.Add(sumPass);
+      }
+
+      #ifndef UNDER_CE
+
+      int iconIndex;
+      UString name;
+      name = RootFolder_GetName_Documents(iconIndex);
+      AddComboBoxItem(name, iconIndex, 0, true);
+
+      name = RootFolder_GetName_Computer(iconIndex);
+      AddComboBoxItem(name, iconIndex, 0, true);
+        
+      FStringVector driveStrings;
+      MyGetLogicalDriveStrings(driveStrings);
+      for (i = 0; i < driveStrings.Size(); i++)
+      {
+        FString s = driveStrings[i];
+        ComboBoxPaths.Add(fs2us(s));
+        int iconIndex2 = GetRealIconIndex(s, 0);
+        if (s.Len() > 0 && s.Back() == FCHAR_PATH_SEPARATOR)
+          s.DeleteBack();
+        AddComboBoxItem(fs2us(s), iconIndex2, 1, false);
+      }
+
+      name = RootFolder_GetName_Network(iconIndex);
+      AddComboBoxItem(name, iconIndex, 0, true);
+
+      #endif
+    
+      return false;
+    }
+
+    case CBN_SELENDOK:
+    {
+      int index = _headerComboBox.GetCurSel();
+      if (index >= 0)
+      {
+        UString pass = ComboBoxPaths[index];
+        _headerComboBox.SetCurSel(-1);
+        // _headerComboBox.SetText(pass); // it's fix for seclecting by mouse.
+        if (BindToPathAndRefresh(pass) == 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<IFolderFolder> 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<IFolderFolder> 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<UInt32> indices;
+  Get_ItemIndices_Operated(indices);
+  Int32 realIndex = -1;
+  if (indices.Size() > 1)
+    return;
+  if (indices.Size() == 1)
+    realIndex = (Int32)indices[0];
+
+  if (_folderAltStreams)
+  {
+    CMyComPtr<IFolderFolder> 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 += ':';
+  BindToPathAndRefresh(path);
+  #endif
+}
diff --git a/CPP/7zip/UI/FileManager/PanelItemOpen.cpp b/CPP/7zip/UI/FileManager/PanelItemOpen.cpp
new file mode 100644
index 0000000..bd65aef
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/PanelItemOpen.cpp
@@ -0,0 +1,1869 @@
+// PanelItemOpen.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/MyWindows.h"
+
+#include <TlHelp32.h>
+
+#include "../../../Common/IntToString.h"
+
+#include "../../../Common/AutoPtr.h"
+#include "../../../Common/StringConvert.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);
+}
+*/
+
+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<CSnapshotProcess> &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<DWORD> _ids;
+  #endif
+
+public:
+  // bool ProgsWereUsed;
+  CRecordVector<HANDLE> Handles;
+  CRecordVector<bool> 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<CSnapshotProcess> 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<IFolderFolder> &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_OKCANCEL | MB_ICONQUESTION) == IDOK)
+      {
+        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"
+  " ";
+
+static const char * const kStartExtensions =
+  #ifdef UNDER_CE
+  " cab"
+  #endif
+  " exe bat ps1 com"
+  " 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 &params);
+void SplitCmdLineSmart(const UString &cmd, UString &prg, UString &params)
+{
+  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 &paramVector, 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<UInt32> 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<UInt32> 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);
+}
+
+
+#ifndef _UNICODE
+typedef BOOL (WINAPI * Func_ShellExecuteExW)(LPSHELLEXECUTEINFOW lpExecInfo);
+#endif
+
+static HRESULT StartApplication(const UString &dir, const UString &path, HWND window, CProcess &process)
+{
+  UString path2 = path;
+
+  #ifdef _WIN32
+  {
+    int dot = path2.ReverseFind_Dot();
+    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;
+    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:
+        ::MessageBoxW(window,
+          NError::MyFormatMessage(::GetLastError()),
+          // L"There is no application associated with the given file name extension",
+          L"7-Zip", MB_OK | MB_ICONSTOP);
+    }
+    
+    return E_FAIL; // fixed in 15.13. Can we use it for any Windows version?
+  }
+  
+  return S_OK;
+}
+
+static void StartApplicationDontWait(const UString &dir, const UString &path, HWND window)
+{
+  CProcess process;
+  StartApplication(dir, path, window, process);
+}
+
+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<IFolderOperations> FolderOperations;
+  CMyComPtr<IProgress> 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 ====");
+
+  CMyAutoPtr<CTmpProcessInfo> tmpProcessInfoPtr((CTmpProcessInfo *)param);
+  CTmpProcessInfo *tpi = tmpProcessInfoPtr.get();
+  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<HANDLE> 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.Front());
+      
+      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_OKCANCEL | MB_ICONQUESTION) == IDOK)
+          {
+            // DEBUG_PRINT_NUM("SendMessage", GetCurrentThreadId());
+            if (SendMessage(tpi->Window, kOpenItemChanged, 0, (LONG_PTR)tpi) != 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<ISequentialOutStream> 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<IInArchiveGetStream> getStream;
+    _folder.QueryInterface(IID_IInArchiveGetStream, &getStream);
+    if (getStream)
+    {
+      CMyComPtr<ISequentialInStream> subSeqStream;
+      getStream->GetStream(index, &subSeqStream);
+      if (subSeqStream)
+      {
+        CMyComPtr<IInStream> 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<UInt32> 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<ISequentialOutStream> 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;
+      // 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<IInStream> 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;
+
+  CMyAutoPtr<CTmpProcessInfo> tmpProcessInfoPtr(new CTmpProcessInfo());
+  CTmpProcessInfo *tpi = tmpProcessInfoPtr.get();
+  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) != 0)
+    throw 271824;
+  g_ExitEventLauncher._threads.Add(th);
+  g_ExitEventLauncher._numActiveThreads++;
+
+  tempDirectory.DisableDeleting();
+  tmpProcessInfoPtr.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
new file mode 100644
index 0000000..0cb33d8
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/PanelItems.cpp
@@ -0,0 +1,1391 @@
+// 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();
+
+  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;
+      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<wchar_t *>((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<UInt32> 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<IFolderSetFlatMode> folderSetFlatMode;
+    _folder.QueryInterface(IID_IFolderSetFlatMode, &folderSetFlatMode);
+    if (folderSetFlatMode)
+      folderSetFlatMode->SetFlatMode(BoolToInt(_flatMode));
+  }
+
+  /*
+  {
+    CMyComPtr<IFolderSetShowNtfsStreamsMode> 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 = (bool *)&_isDirVector.Front();
+    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<IFolderGetSystemIconIndex> folderGetSystemIconIndex;
+  if (!Is_Slow_Icon_Folder() || _showRealFileIcons)
+    _folder.QueryInterface(IID_IFolderGetSystemIconIndex, &folderGetSystemIconIndex);
+
+  if (!IsFSFolder())
+  {
+    CMyComPtr<IGetFolderArcProps> getFolderArcProps;
+    _folder.QueryInterface(IID_IGetFolderArcProps, &getFolderArcProps);
+    _thereAreDeletedItems = false;
+    if (getFolderArcProps)
+    {
+      CMyComPtr<IFolderArcProps> 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<wchar_t *>((const wchar_t *)itemName);
+    #else
+    item.pszText = LPSTR_TEXTCALLBACKW;
+    #endif
+    const UInt32 attrib = FILE_ATTRIBUTE_DIRECTORY;
+    item.iImage = _extToIconMap.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<wchar_t *>((const wchar_t *)correctedName);
+    }
+    else
+    */
+    {
+      #ifdef USE_EMBED_ITEM
+      item.pszText = const_cast<wchar_t *>((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;
+  
+    if (folderGetSystemIconIndex)
+    {
+      folderGetSystemIconIndex->GetSystemIconIndex(i, &item.iImage);
+      defined = (item.iImage > 0);
+    }
+
+    if (!defined)
+    {
+      UInt32 attrib = 0;
+      {
+        NCOM::CPropVariant prop;
+        RINOK(_folder->GetProperty(i, kpidAttrib, &prop))
+        if (prop.vt == VT_UI4)
+          attrib = prop.ulVal;
+      }
+      if (IsItem_Folder(i))
+        attrib |= FILE_ATTRIBUTE_DIRECTORY;
+
+      if (_currentFolderPrefix.IsEmpty())
+      {
+        int iconIndexTemp;
+        GetRealIconIndex(us2fs((UString)name) + FCHAR_PATH_SEPARATOR, attrib, iconIndexTemp);
+        item.iImage = iconIndexTemp;
+      }
+      else
+      {
+        item.iImage = _extToIconMap.GetIconIndex(attrib, name);
+      }
+    }
+    
+    if (item.iImage < 0)
+      item.iImage = 0;
+
+    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",
+      // _extToIconMap._attribMap.Size(),
+      // _extToIconMap._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<UInt32> &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.Front();
+  const unsigned size = _selectedStatusVector.Size();
+  for (unsigned i = 0; i < size; i++)
+    if (v[i])
+      indices.Add(i);
+}
+
+
+void CPanel::Get_ItemIndices_Operated(CRecordVector<UInt32> &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<UInt32> &indices) const
+{
+  indices.Clear();
+  UInt32 numItems;
+  if (_folder->GetNumberOfItems(&numItems) != S_OK)
+    return;
+  indices.ClearAndSetSize(numItems);
+  UInt32 *vec = (UInt32 *)&indices.Front();
+  for (UInt32 i = 0; i < numItems; i++)
+    vec[i] = i;
+}
+
+void CPanel::Get_ItemIndices_OperSmart(CRecordVector<UInt32> &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<UInt32> &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<IFolderCalcItemFullSize> calcItemFullSize;
+    _folder.QueryInterface(IID_IFolderCalcItemFullSize, &calcItemFullSize);
+    if (calcItemFullSize)
+    {
+      bool needRefresh = false;
+      CRecordVector<UInt32> 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<UInt32> 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;
+  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 *itemActiveate, LRESULT &result)
+{
+  if (itemActiveate->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<IFolderWasChanged> 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
+}
diff --git a/CPP/7zip/UI/FileManager/PanelKey.cpp b/CPP/7zip/UI/FileManager/PanelKey.cpp
new file mode 100644
index 0000000..a4ea489
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/PanelKey.cpp
@@ -0,0 +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;
+}
diff --git a/CPP/7zip/UI/FileManager/PanelListNotify.cpp b/CPP/7zip/UI/FileManager/PanelListNotify.cpp
new file mode 100644
index 0000000..2fb0e87
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/PanelListNotify.cpp
@@ -0,0 +1,870 @@
+// 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++] = (unsigned char)('0' + (unsigned)(v % 10)); v /= 10; } \
+  *s++ = (unsigned char)('0' + (unsigned)v);
+
+static void ConvertSizeToString(UInt64 val, wchar_t *s) throw()
+{
+  unsigned char 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;
+}
+
+static inline unsigned GetHex_Upper(unsigned v)
+{
+  return (v < 10) ? ('0' + v) : ('A' + (v - 10));
+}
+
+static inline unsigned GetHex_Lower(unsigned v)
+{
+  return (v < 10) ? ('0' + v) : ('a' + (v - 10));
+}
+
+/*
+static void HexToString(char *dest, const Byte *data, UInt32 size)
+{
+  for (UInt32 i = 0; i < size; i++)
+  {
+    unsigned b = data[i];
+    dest[0] = GetHex((b >> 4) & 0xF);
+    dest[1] = GetHex(b & 0xF);
+    dest += 2;
+  }
+  *dest = 0;
+}
+*/
+
+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 <stdio.h>
+
+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<IFolderGetSystemIconIndex> 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;
+  
+  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))
+    const unsigned limit = (unsigned)item.cchTextMax - 1;
+    if (dataSize == 0)
+    {
+      text[0] = 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++)
+        {
+          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++)
+        {
+          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[i] = c;
+        }
+        text[i] = 0;
+      }
+      else
+      {
+        if (dataSize > limit)
+          dataSize = limit;
+        WCHAR *dest = text;
+        const bool needUpper = (dataSize <= 8)
+            && (propID == kpidCRC || propID == kpidChecksum);
+        for (UInt32 i = 0; i < dataSize; i++)
+        {
+          unsigned b = ((const Byte *)data)[i];
+          if (needUpper)
+          {
+            dest[0] = (WCHAR)GetHex_Upper((b >> 4) & 0xF);
+            dest[1] = (WCHAR)GetHex_Upper(b & 0xF);
+          }
+          else
+          {
+            dest[0] = (WCHAR)GetHex_Lower((b >> 4) & 0xF);
+            dest[1] = (WCHAR)GetHex_Lower(b & 0xF);
+          }
+          dest += 2;
+        }
+        *dest = 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<IFolderGetItemFullSize> 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;
+}
+
+#ifndef UNDER_CE
+extern DWORD g_ComCtl32Version;
+#endif
+
+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)
+        #ifndef UNDER_CE
+        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<UInt32> 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[32];
+        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
new file mode 100644
index 0000000..f0afe15
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/PanelMenu.cpp
@@ -0,0 +1,1176 @@
+#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<UInt32> operatedIndices;
+  Get_ItemIndices_Operated(operatedIndices);
+  if (operatedIndices.IsEmpty())
+    return;
+  CMyComPtr<IContextMenu> 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 inline unsigned GetHex_Upper(unsigned v)
+{
+  return (v < 10) ? ('0' + v) : ('A' + (v - 10));
+}
+
+static inline unsigned GetHex_Lower(unsigned v)
+{
+  return (v < 10) ? ('0' + v) : ('a' + (v - 10));
+}
+
+static const Byte kSpecProps[] =
+{
+  kpidPath,
+  kpidType,
+  kpidErrorType,
+  kpidError,
+  kpidErrorFlags,
+  kpidWarning,
+  kpidWarningFlags,
+  kpidOffset,
+  kpidPhySize,
+  kpidTailSize
+};
+
+void CPanel::Properties()
+{
+  CMyComPtr<IGetFolderArcProps> getFolderArcProps;
+  _folder.QueryInterface(IID_IGetFolderArcProps, &getFolderArcProps);
+  if (!getFolderArcProps)
+  {
+    InvokeSystemCommand("properties");
+    return;
+  }
+  
+  {
+    CListViewDialog message;
+    // message.DeleteIsAllowed = false;
+    // message.SelectFirst = false;
+
+    CRecordVector<UInt32> 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 UInt32 kMaxDataSize = 64;
+              if (dataSize > kMaxDataSize)
+              {
+                s += "data:";
+                s.Add_UInt32(dataSize);
+              }
+              else
+              {
+                const bool needUpper = (dataSize <= 8)
+                    && (propID == kpidCRC || propID == kpidChecksum);
+                for (UInt32 k = 0; k < dataSize; k++)
+                {
+                  const Byte b = ((const Byte *)data)[k];
+                  if (needUpper)
+                  {
+                    s += (char)GetHex_Upper((b >> 4) & 0xF);
+                    s += (char)GetHex_Upper(b & 0xF);
+                  }
+                  else
+                  {
+                    s += (char)GetHex_Lower((b >> 4) & 0xF);
+                    s += (char)GetHex_Lower(b & 0xF);
+                  }
+                }
+              }
+            }
+            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<IFolderProperties> 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<IFolderArcProps> 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<IGetFolderArcProps> getFolderArcProps;
+  _folder.QueryInterface(IID_IGetFolderArcProps, &getFolderArcProps);
+  if (!getFolderArcProps)
+  {
+    InvokeSystemCommand("copy");
+    return;
+  }
+  */
+  UString s;
+  CRecordVector<UInt32> 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<LPITEMIDLIST> 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<UInt32> &operatedIndices,
+    CMyComPtr<IContextMenu> &systemContextMenu)
+{
+  ODS("==== CPanel::CreateShellContextMenu");
+  systemContextMenu.Release();
+  UString folderPath = GetFsPath();
+
+  CMyComPtr<IShellFolder> 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<IShellFolder> 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.Front(),
+      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<UInt32> &operatedIndices,
+    CMyComPtr<IContextMenu> &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<UInt32> &operatedIndices,
+    int firstDirIndex,
+    CMyComPtr<IContextMenu> &sevenZipContextMenu)
+{
+  sevenZipContextMenu.Release();
+
+  CMenu menu;
+  menu.Attach(menuSpec);
+  // CMenuDestroyer menuDestroyer(menu);
+  // menu.CreatePopup();
+
+  CZipContextMenu *contextMenuSpec = new CZipContextMenu;
+  CMyComPtr<IContextMenu> contextMenu = contextMenuSpec;
+  // if (contextMenu.CoCreateInstance(CLSID_CZipContextMenu, IID_IContextMenu) == S_OK)
+  {
+    /*
+    CMyComPtr<IInitContextMenu> 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<IContextMenu> &sevenZipContextMenu,
+    CMyComPtr<IContextMenu> &systemContextMenu,
+    bool programMenu)
+{
+  sevenZipContextMenu.Release();
+  systemContextMenu.Release();
+
+  const bool showExtendedVerbs = IsKeyDown(VK_SHIFT);
+
+  CRecordVector<UInt32> 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<UInt32> 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<IContextMenu> sevenZipContextMenu;
+  CMyComPtr<IContextMenu> 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
new file mode 100644
index 0000000..b61f4e9
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/PanelOperations.cpp
@@ -0,0 +1,528 @@
+// 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<UInt32> Indices;
+
+  CMyComPtr<IFolderOperations> FolderOperations;
+  CMyComPtr<IProgress> 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.Front(), 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<UInt32> 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<CHAR> 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<WCHAR> 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
+        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_OKCANCEL | MB_ICONQUESTION) != IDOK)
+    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);
+
+
+  CDisableNotify disableNotify(*this);
+  {
+    CThreadFolderOperations op(FOLDER_TYPE_RENAME);
+    op.FolderOperations = _folderOperations;
+    op.Index = realIndex;
+    op.Name = newName;
+    /* HRESULTres = */ 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)
+      return FALSE;
+    */
+  }
+
+  // Can't use RefreshListCtrl here.
+  // RefreshListCtrlSaveFocused();
+  _selectedState.FocusedName = prefix + newName;
+  _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
new file mode 100644
index 0000000..f7a16dd
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/PanelSelect.cpp
@@ -0,0 +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;
+}
diff --git a/CPP/7zip/UI/FileManager/PanelSort.cpp b/CPP/7zip/UI/FileManager/PanelSort.cpp
new file mode 100644
index 0000000..f95f8ee
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/PanelSort.cpp
@@ -0,0 +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);
+}
diff --git a/CPP/7zip/UI/FileManager/PanelSplitFile.cpp b/CPP/7zip/UI/FileManager/PanelSplitFile.cpp
new file mode 100644
index 0000000..64aa039
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/PanelSplitFile.cpp
@@ -0,0 +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 += '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<UInt64> 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(name, false))
+      {
+        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<UInt32> 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.Front())
+  {
+    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(OutputPath, false))
+  {
+    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<UInt32> 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 95e83fe..bf99580 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 LANG

-#include "LangUtils.h"

-#endif

-

-#ifdef 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 LANG

-  LangSetWindowText(*this, IDD_PASSWORD);

-  LangSetDlgItems(*this, kLangIDs, ARRAY_SIZE(kLangIDs));

-  #endif

-  _passwordEdit.Attach(GetItem(IDE_PASSWORD_PASSWORD));

-  CheckButton(IDX_PASSWORD_SHOW, ShowPassword);

-  SetTextSpec();

-  return CModalDialog::OnInit();

-}

-

-bool CPasswordDialog::OnButtonClicked(int 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 b756a1c..e05c4ad 100644
--- a/CPP/7zip/UI/FileManager/PasswordDialog.h
+++ b/CPP/7zip/UI/FileManager/PasswordDialog.h
@@ -1,28 +1,28 @@
-// PasswordDialog.h

-

-#ifndef __PASSWORD_DIALOG_H

-#define __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();

-  virtual bool OnInit();

-  virtual bool OnButtonClicked(int buttonID, HWND buttonHWND);

-  void SetTextSpec();

-  void ReadControls();

-public:

-  UString Password;

-  bool ShowPassword;

-  

-  CPasswordDialog(): ShowPassword(false) {}

-  INT_PTR Create(HWND parentWindow = 0) { 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 51dd5bc..90c57ef 100644
--- a/CPP/7zip/UI/FileManager/PasswordDialog.rc
+++ b/CPP/7zip/UI/FileManager/PasswordDialog.rc
@@ -1,14 +1,14 @@
-#include "PasswordDialogRes.h"

-#include "../../GuiCommon.rc"

-

-#define xc 140

-#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"
+
+#define xc 140
+#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 f9300d6..1fe32e1 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
new file mode 100644
index 0000000..dcb1b4b
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/PluginInterface.h
@@ -0,0 +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
diff --git a/CPP/7zip/UI/FileManager/PluginLoader.h b/CPP/7zip/UI/FileManager/PluginLoader.h
new file mode 100644
index 0000000..d9309f2
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/PluginLoader.h
@@ -0,0 +1,31 @@
+// PluginLoader.h
+
+#ifndef ZIP7_INC_PLUGIN_LOADER_H
+#define ZIP7_INC_PLUGIN_LOADER_H
+
+#include "../../../Windows/DLL.h"
+
+#include "IFolder.h"
+
+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
new file mode 100644
index 0000000..50ca5ca
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/ProgramLocation.cpp
@@ -0,0 +1,3 @@
+// ProgramLocation.cpp
+
+#include "StdAfx.h"
diff --git a/CPP/7zip/UI/FileManager/ProgramLocation.h b/CPP/7zip/UI/FileManager/ProgramLocation.h
new file mode 100644
index 0000000..0cd9c74
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/ProgramLocation.h
@@ -0,0 +1,6 @@
+// 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 27d42b2..fc6f559 100644
--- a/CPP/7zip/UI/FileManager/ProgressDialog.cpp
+++ b/CPP/7zip/UI/FileManager/ProgressDialog.cpp
@@ -1,196 +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 LANG

-#include "LangUtils.h"

-#endif

-

-HRESULT CProgressSync::ProcessStopAndPause()

-{

-  for (;;)

-  {

-    if (GetStopped())

-      return E_ABORT;

-    if (!GetPaused())

-      break;

-    ::Sleep(100);

-  }

-  return S_OK;

-}

-

-#ifndef _SFX

-CProgressDialog::~CProgressDialog()

-{

-  AddToTitle(L"");

-}

-void CProgressDialog::AddToTitle(LPCWSTR s)

-{

-  if (MainWindow != 0)

-    MySetWindowText(MainWindow, UString(s) + MainTitle);

-}

-#endif

-

-

-bool CProgressDialog::OnInit()

-{

-  _range = (UInt64)(Int64)-1;

-  _prevPercentValue = -1;

-

-  _wasCreated = true;

-  _dialogCreatedEvent.Set();

-

-  #ifdef 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;

-

-  int percentValue = (int)(completed * 100 / total);

-  if (percentValue != _prevPercentValue)

-  {

-    wchar_t s[64];

-    ConvertUInt64ToString(percentValue, s);

-    UString title = s;

-    title += "% ";

-    SetText(title + _title);

-    #ifndef _SFX

-    AddToTitle(title + MainAddTitle);

-    #endif

-    _prevPercentValue = percentValue;

-  }

-  return true;

-}

-

-bool CProgressDialog::OnMessage(UINT message, WPARAM wParam, LPARAM lParam)

-{

-  switch (message)

-  {

-    case kCloseMessage:

-    {

-      KillTimer(_timer);

-      _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(int 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 2a9d26d..1fe9587 100644
--- a/CPP/7zip/UI/FileManager/ProgressDialog.h
+++ b/CPP/7zip/UI/FileManager/ProgressDialog.h
@@ -1,170 +1,171 @@
-// ProgressDialog.h

-

-#ifndef __PROGRESS_DIALOG_H

-#define __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;

-

-  int _prevPercentValue;

-

-  bool _wasCreated;

-  bool _needClose;

-  bool _inCancelMessageBox;

-  bool _externalCloseMessageWasReceived;

-

-  bool OnTimer(WPARAM timerID, LPARAM callback);

-  void SetRange(UInt64 range);

-  void SetPos(UInt64 pos);

-  virtual bool OnInit();

-  virtual void OnCancel();

-  virtual void OnOK();

-  NWindows::NSynchronization::CManualResetEvent _dialogCreatedEvent;

-  #ifndef _SFX

-  void AddToTitle(LPCWSTR string);

-  #endif

-  bool OnButtonClicked(int buttonID, HWND buttonHWND);

-

-  void WaitCreating() { _dialogCreatedEvent.Lock(); }

-  void CheckNeedClose();

-  bool OnExternalCloseMessage();

-public:

-  CProgressSync Sync;

-  int IconID;

-

-  #ifndef _SFX

-  HWND MainWindow;

-  UString MainTitle;

-  UString MainAddTitle;

-  ~CProgressDialog();

-  #endif

-

-  CProgressDialog(): _timer(0)

-    #ifndef _SFX

-    ,MainWindow(0)

-    #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 = 0)

-  {

-    _title = title;

-    INT_PTR res = CModalDialog::Create(IDD_PROGRESS, wndParent);

-    thread.Wait();

-    return res;

-  }

-

-  enum

-  {

-    kCloseMessage = WM_APP + 1

-  };

-

-  virtual bool OnMessage(UINT message, WPARAM wParam, LPARAM lParam);

-

-  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 5af370f..55d9923 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 bdb2be3..1521d83 100644
--- a/CPP/7zip/UI/FileManager/ProgressDialog2.cpp
+++ b/CPP/7zip/UI/FileManager/ProgressDialog2.cpp
@@ -1,1337 +1,1467 @@
-// ProgressDialog2.cpp

-

-#include "StdAfx.h"

-

-#include "../../../Common/IntToString.h"

-#include "../../../Common/StringConvert.h"

-

-#include "../../../Windows/Control/Static.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;

-

-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 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),

-    _totalBytes(UNDEFINED_VAL), _completedBytes(0),

-    _totalFiles(UNDEFINED_VAL), _curFiles(0),

-    _inSize(UNDEFINED_VAL),

-    _outSize(UNDEFINED_VAL),

-    _isDir(false)

-    {}

-

-#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(DWORD 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(0)

-{

-  _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 _SFX

-

-CProgressDialog::~CProgressDialog()

-{

-  #ifdef __ITaskbarList3_INTERFACE_DEFINED__

-  SetTaskbarProgressState(TBPF_NOPROGRESS);

-  #endif

-  AddToTitle(L"");

-}

-void CProgressDialog::AddToTitle(LPCWSTR s)

-{

-  if (MainWindow != 0)

-  {

-    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();

-

-  _foreground = true;

-

-  m_ProgressBar.Attach(GetItem(IDC_PROGRESS1));

-  _messageList.Attach(GetItem(IDL_PROGRESS_MESSAGES));

-  _messageList.SetUnicodeFormat();

-

-  _wasCreated = true;

-  _dialogCreatedEvent.Set();

-

-  #ifdef LANG

-  LangSetDlgItems(*this, kLangIDs, ARRAY_SIZE(kLangIDs));

-  LangSetDlgItems_Colon(*this, kLangIDs_Colon, 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,

-  IDT_PROGRESS_RATIO,     IDT_PROGRESS_RATIO_VAL,

-  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

-};

-

-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);

-

-  int xSizeClient = xSize - mx * 2;

-

-  {

-    int i;

-    for (i = 800; i > 40; i = i * 9 / 10)

-      if (Units_To_Pixels_X(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--)

-  {

-    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);

-    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);

-  int requiredSize = (labelSize + valueSize) * 2 + padSize;

-

-  int gSize;

-  {

-    if (requiredSize < xSizeClient)

-    {

-      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 (int i = 0; i < ARRAY_SIZE(kIDs); i += 2)

-  {

-    int x = mx;

-    const int kNumColumn1Items = 5 * 2;

-    if (i >= kNumColumn1Items)

-    {

-      if (i == kNumColumn1Items)

-        yPos = my;

-      x = mx + gSize + padSize;

-    }

-    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)

-{

-  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++ = 0;

-  }

-}

-

-void CProgressDialog::ShowSize(int 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);

-        }

-      }

-      {

-        UInt64 elapsedTime = (_elapsedTime == 0) ? 1 : _elapsedTime;

-        UInt64 v = (progressCompleted * 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 (IS_DEFINED_VAL(totalFiles))

-      {

-        MyStringCat(s, L" / ");

-        ConvertUInt64ToString(totalFiles, s + MyStringLen(s));

-      }

-      if (_filesStr_Prev != s)

-      {

-        _filesStr_Prev = s;

-        SetItemText(IDT_PROGRESS_FILES_VAL, 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, slashPos + 1);

-        s2 = _filePath.Ptr(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 };

-      

-      WRes res2 = WaitForMultipleObjects(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();

-    res = res;

-  }

-  thread.Wait();

-  if (!MessagesDisplayed)

-    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";

-    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";

-      MessageBoxW(*this, fm.OkMessage.Message, fm.OkMessage.Title, MB_OK);

-    }

-  }

-

-  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:

-    {

-      KillTimer(_timer);

-      _timer = 0;

-      if (_inCancelMessageBox)

-      {

-        _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 += '%';

-  }

-  if (!_foreground)

-  {

-    s.Add_Space();

-    s += _backgrounded_String;

-  }

-

-  s.Add_Space();

-  #ifndef _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)

-{

-  int itemIndex = _messageList.GetItemCount();

-  wchar_t sz[16];

-  sz[0] = 0;

-  if (needNumber)

-    ConvertUInt32ToString(_numMessages + 1, sz);

-  _messageList.InsertItem(itemIndex, sz);

-  _messageList.SetSubItem(itemIndex, 1, message);

-}

-

-void CProgressDialog::AddMessage(LPCWSTR message)

-{

-  UString s = message;

-  bool needNumber = true;

-  while (!s.IsEmpty())

-  {

-    int pos = s.Find(L'\n');

-    if (pos < 0)

-      break;

-    AddMessageDirect(s.Left(pos), needNumber);

-    needNumber = false;

-    s.DeleteFrontal(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(int buttonID, HWND buttonHWND)

-{

-  switch (buttonID)

-  {

-    // case IDOK: // if IDCANCEL is not DEFPUSHBUTTON

-    case IDCANCEL:

-    {

-      if (_waitCloseByCancelButton)

-      {

-        MessagesDisplayed = true;

-        End(IDCLOSE);

-        break;

-      }

-        

-      bool paused = Sync.Get_Paused();

-      if (!paused)

-        OnPauseButton();

-      _inCancelMessageBox = true;

-      int res = ::MessageBoxW(*this, LangString(IDS_PROGRESS_ASK_CANCEL), _title, MB_YESNOCANCEL);

-      _inCancelMessageBox = false;

-      if (!paused)

-        OnPauseButton();

-      if (res == IDCANCEL || res == IDNO)

-      {

-        if (_externalCloseMessageWasReceived)

-          OnExternalCloseMessage();

-        return true;

-      }

-

-      _cancelWasPressed = true;

-      MessagesDisplayed = true;

-      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;

-}

-

-

-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;

-  RINOK(thread.Create(MyThreadFunction, this));

-  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(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 <ShlGuid.h>
+#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;
+
+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)
+    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";
+    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";
+      MessageBoxW(*this, fm.OkMessage.Message, fm.OkMessage.Title, MB_OK);
+    }
+  }
+
+  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 += '%';
+  }
+  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);
+}
diff --git a/CPP/7zip/UI/FileManager/ProgressDialog2.h b/CPP/7zip/UI/FileManager/ProgressDialog2.h
index 5e916e6..4ca9be7 100644
--- a/CPP/7zip/UI/FileManager/ProgressDialog2.h
+++ b/CPP/7zip/UI/FileManager/ProgressDialog2.h
@@ -1,351 +1,358 @@
-// ProgressDialog2.h

-

-#ifndef __PROGRESS_DIALOG_2_H

-#define __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;

-  UInt64 _totalBytes;

-  UInt64 _completedBytes;

-  UInt64 _totalFiles;

-  UInt64 _curFiles;

-  UInt64 _inSize;

-  UInt64 _outSize;

-  

-  UString _titleFileName;

-  UString _status;

-  UString _filePath;

-  bool _isDir;

-

-  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);

-

-  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;

-  

-  int _numMessages;

-

-  #ifdef __ITaskbarList3_INTERFACE_DEFINED__

-  CMyComPtr<ITaskbarList3> _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;

-

-  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);

-  bool OnTimer(WPARAM timerID, LPARAM callback);

-  void SetProgressRange(UInt64 range);

-  void SetProgressPos(UInt64 pos);

-  virtual bool OnInit();

-  virtual bool OnSize(WPARAM wParam, int xSize, int ySize);

-  virtual void OnCancel();

-  virtual void OnOK();

-  NWindows::NSynchronization::CManualResetEvent _createDialogEvent;

-  NWindows::NSynchronization::CManualResetEvent _dialogCreatedEvent;

-  #ifndef _SFX

-  void AddToTitle(LPCWSTR string);

-  #endif

-

-  void SetPauseText();

-  void SetPriorityText();

-  void OnPauseButton();

-  void OnPriorityButton();

-  bool OnButtonClicked(int buttonID, HWND buttonHWND);

-  bool OnMessage(UINT message, WPARAM wParam, LPARAM lParam);

-

-  void SetTitleText();

-  void ShowSize(int 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 _SFX

-  UString MainTitle;

-  UString MainAddTitle;

-  ~CProgressDialog();

-  #endif

-

-  CProgressDialog();

-  void WaitCreating()

-  {

-    _createDialogEvent.Set();

-    _dialogCreatedEvent.Lock();

-  }

-

-  INT_PTR Create(const UString &title, NWindows::CThread &thread, HWND wndParent = 0);

-

-

-  /* 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 = 0);

-  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()

-{

-  {

-    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 _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<ITaskbarList3> _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
diff --git a/CPP/7zip/UI/FileManager/ProgressDialog2.rc b/CPP/7zip/UI/FileManager/ProgressDialog2.rc
index 535a008..4d0e0c7 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 54f02f0..736c717 100644
--- a/CPP/7zip/UI/FileManager/ProgressDialog2Res.h
+++ b/CPP/7zip/UI/FileManager/ProgressDialog2Res.h
@@ -1,48 +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_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  76

-#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 f1daec7..dc7d797 100644
--- a/CPP/7zip/UI/FileManager/ProgressDialog2a.rc
+++ b/CPP/7zip/UI/FileManager/ProgressDialog2a.rc
@@ -1,80 +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  "Compression ratio:", IDT_PROGRESS_RATIO,     m, y3, 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

-

-  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_RATIO_VAL,     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

-

-  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 a281418..cbf3beb 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 a955241..838b6e3 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 a1061b7..fa6e5c5 100644
--- a/CPP/7zip/UI/FileManager/PropertyName.h
+++ b/CPP/7zip/UI/FileManager/PropertyName.h
@@ -1,10 +1,10 @@
-// PropertyName.h

-

-#ifndef __PROPERTY_NAME_H

-#define __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
new file mode 100644
index 0000000..618875b
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/PropertyName.rc
@@ -0,0 +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
diff --git a/CPP/7zip/UI/FileManager/PropertyNameRes.h b/CPP/7zip/UI/FileManager/PropertyNameRes.h
index 1315b89..913887e 100644
--- a/CPP/7zip/UI/FileManager/PropertyNameRes.h
+++ b/CPP/7zip/UI/FileManager/PropertyNameRes.h
@@ -1,95 +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_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
new file mode 100644
index 0000000..16e4675
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/RegistryAssociations.cpp
@@ -0,0 +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 += ',';
+      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
new file mode 100644
index 0000000..3d7b63d
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/RegistryAssociations.h
@@ -0,0 +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
diff --git a/CPP/7zip/UI/FileManager/RegistryPlugins.cpp b/CPP/7zip/UI/FileManager/RegistryPlugins.cpp
new file mode 100644
index 0000000..87e5fa1
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/RegistryPlugins.cpp
@@ -0,0 +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<CPluginInfo> &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
new file mode 100644
index 0000000..1cb765a
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/RegistryPlugins.h
@@ -0,0 +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<CPluginInfo> &plugins);
+// void ReadFileFolderPluginInfoList(CObjectVector<CPluginInfo> &plugins);
+*/
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/RegistryUtils.cpp b/CPP/7zip/UI/FileManager/RegistryUtils.cpp
new file mode 100644
index 0000000..7e61998
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/RegistryUtils.cpp
@@ -0,0 +1,196 @@
+// 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); }
+*/
diff --git a/CPP/7zip/UI/FileManager/RegistryUtils.h b/CPP/7zip/UI/FileManager/RegistryUtils.h
new file mode 100644
index 0000000..8b4cdf0
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/RegistryUtils.h
@@ -0,0 +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
diff --git a/CPP/7zip/UI/FileManager/RootFolder.cpp b/CPP/7zip/UI/FileManager/RootFolder.cpp
new file mode 100644
index 0000000..34dd638
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/RootFolder.cpp
@@ -0,0 +1,326 @@
+// RootFolder.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/MyWindows.h"
+
+#if defined(__MINGW32__) || defined(__MINGW64__)
+#include <shlobj.h>
+#else
+#include <ShlObj.h>
+#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 = GetIconIndexForCSIDL(CSIDL_DRIVES);
+  #else
+  GetRealIconIndex(FSTRING_PATH_SEPARATOR, FILE_ATTRIBUTE_DIRECTORY, iconIndex);
+  #endif
+  return LangString(IDS_COMPUTER);
+}
+
+UString RootFolder_GetName_Network(int &iconIndex);
+UString RootFolder_GetName_Network(int &iconIndex)
+{
+  iconIndex = GetIconIndexForCSIDL(CSIDL_NETWORK);
+  return LangString(IDS_NETWORK);
+}
+
+UString RootFolder_GetName_Documents(int &iconIndex);
+UString RootFolder_GetName_Documents(int &iconIndex)
+{
+  iconIndex = GetIconIndexForCSIDL(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] = GetIconIndexForCSIDL(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;
+}
+
+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);
+
+static UString GetMyDocsPath()
+{
+  UString us;
+  WCHAR s[MAX_PATH + 1];
+#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(NULL, s, CSIDL_PERSONAL, FALSE))
+    us = s;
+  #ifndef _UNICODE
+  else
+  {
+    Func_SHGetSpecialFolderPathA getA = Z7_GET_PROC_ADDRESS(
+    Func_SHGetSpecialFolderPathA, ::GetModuleHandleA("shell32.dll"),
+        "SHGetSpecialFolderPathA");
+    CHAR s2[MAX_PATH + 1];
+    if (getA && getA(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<IFolderFolder> 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<IFolderFolder> 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<IFolderFolder> subFolder = this;
+    *resultFolder = subFolder.Detach();
+    return S_OK;
+  }
+
+  if (name2.Len() < 2)
+    return E_INVALIDARG;
+
+  CMyComPtr<IFolderFolder> 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
new file mode 100644
index 0000000..3f0a31b
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/RootFolder.h
@@ -0,0 +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
diff --git a/CPP/7zip/UI/FileManager/SettingsPage.cpp b/CPP/7zip/UI/FileManager/SettingsPage.cpp
new file mode 100644
index 0000000..784b8c7
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/SettingsPage.cpp
@@ -0,0 +1,354 @@
+// SettingsPage.cpp
+
+#include "StdAfx.h"
+
+// #include "../../../Common/IntToString.h"
+// #include "../../../Common/StringConvert.h"
+
+#ifndef UNDER_CE
+#include "../../../Windows/MemoryLock.h"
+// #include "../../../Windows/System.h"
+#endif
+
+// #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_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()
+{
+  _wasChanged = false;
+  _largePages_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();
+
+  return CPropertyPage::OnInit();
+}
+
+/*
+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 (_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 (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;
+
+    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
new file mode 100644
index 0000000..91b9828
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/SettingsPage.h
@@ -0,0 +1,33 @@
+// 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 _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;
+public:
+};
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/SettingsPage.rc b/CPP/7zip/UI/FileManager/SettingsPage.rc
new file mode 100644
index 0000000..baab484
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/SettingsPage.rc
@@ -0,0 +1,22 @@
+#include "SettingsPageRes.h"
+#include "../../GuiCommon.rc"
+
+#define xc 240
+#define yc 250
+
+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
new file mode 100644
index 0000000..cf90742
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/SettingsPage2.rc
@@ -0,0 +1,19 @@
+// #define g1xs 60
+
+CAPTION "Settings"
+BEGIN 
+  CONTROL  "Show "".."" item",      IDX_SETTINGS_SHOW_DOTS,            MY_CHECKBOX, m,  8, xc, 10
+  CONTROL  "Show real file &icons", IDX_SETTINGS_SHOW_REAL_FILE_ICONS, MY_CHECKBOX, m, 22, xc, 10
+  CONTROL  "&Full row select",      IDX_SETTINGS_FULL_ROW,             MY_CHECKBOX, m, 36, xc, 10
+  CONTROL  "Show &grid lines",      IDX_SETTINGS_SHOW_GRID,            MY_CHECKBOX, m, 50, xc, 10
+  CONTROL  "&Single-click to open an item", IDX_SETTINGS_SINGLE_CLICK, MY_CHECKBOX, m, 64, xc, 10
+  CONTROL  "&Alternative selection mode", IDX_SETTINGS_ALTERNATIVE_SELECTION, MY_CHECKBOX, m, 78, xc, 10
+
+  CONTROL  "Show system &menu",     IDX_SETTINGS_SHOW_SYSTEM_MENU,     MY_CHECKBOX, m, 100, xc, 10
+
+  CONTROL  "Use &large memory pages", IDX_SETTINGS_LARGE_PAGES,        MY_CHECKBOX, m, 122, xc, 10
+
+  // 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
diff --git a/CPP/7zip/UI/FileManager/SettingsPageRes.h b/CPP/7zip/UI/FileManager/SettingsPageRes.h
new file mode 100644
index 0000000..e990bab
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/SettingsPageRes.h
@@ -0,0 +1,17 @@
+#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_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
new file mode 100644
index 0000000..21d812c
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/SplitDialog.cpp
@@ -0,0 +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();
+}
diff --git a/CPP/7zip/UI/FileManager/SplitDialog.h b/CPP/7zip/UI/FileManager/SplitDialog.h
new file mode 100644
index 0000000..f897136
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/SplitDialog.h
@@ -0,0 +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<UInt64> 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
new file mode 100644
index 0000000..5a026e8
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/SplitDialog.rc
@@ -0,0 +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
diff --git a/CPP/7zip/UI/FileManager/SplitDialogRes.h b/CPP/7zip/UI/FileManager/SplitDialogRes.h
new file mode 100644
index 0000000..50584a1
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/SplitDialogRes.h
@@ -0,0 +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
diff --git a/CPP/7zip/UI/FileManager/SplitUtils.cpp b/CPP/7zip/UI/FileManager/SplitUtils.cpp
new file mode 100644
index 0000000..1982afb
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/SplitUtils.cpp
@@ -0,0 +1,96 @@
+// SplitUtils.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/StringToInt.h"
+
+#include "SplitUtils.h"
+
+bool ParseVolumeSizes(const UString &s, CRecordVector<UInt64> &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<UInt64> &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
new file mode 100644
index 0000000..d1d44e4
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/SplitUtils.h
@@ -0,0 +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<UInt64> &values);
+void AddVolumeItems(NWindows::NControl::CComboBox &volumeCombo);
+UInt64 GetNumberOfVolumes(UInt64 size, const CRecordVector<UInt64> &volSizes);
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/StdAfx.cpp b/CPP/7zip/UI/FileManager/StdAfx.cpp
new file mode 100644
index 0000000..d0feea8
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/StdAfx.cpp
@@ -0,0 +1,3 @@
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/CPP/7zip/UI/FileManager/StdAfx.h b/CPP/7zip/UI/FileManager/StdAfx.h
new file mode 100644
index 0000000..789cc6e
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/StdAfx.h
@@ -0,0 +1,83 @@
+// 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 "../../../../C/Compiler.h"
+
+Z7_DIAGNOSCTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER
+#ifndef _WIN32_WINNT
+// #define _WIN32_WINNT 0x0400
+#define _WIN32_WINNT 0x0500
+// #define _WIN32_WINNT 0x0600
+// #define _WIN32_WINNT 0x0A00
+#endif
+#ifndef WINVER
+#define WINVER _WIN32_WINNT
+#endif
+// #define _WIN32_IE 0x400 // for debug
+Z7_DIAGNOSCTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER
+
+#include "../../../Common/Common.h"
+#include "../../../Common/MyWindows.h"
+
+#endif
+
+/*
+WINVER and _WIN32_WINNT
+
+MSVC6 / 2003sdk:
+{
+  <windows.h> doesn't set _WIN32_WINNT
+  if WINVER is not set <windows.h> sets WINVER to value:
+    0x0400 : MSVC6
+    0x0501 : Windows Server 2003 PSDK / 2003 R2 PSDK
+}
+
+SDK for Win7 (and later)
+{
+  <windows.h> sets _WIN32_WINNT if it's not set.
+  <windows.h> sets WINVER if it's not set.
+<windows.h> includes <sdkddkver.h> 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 <windows.h> probably is OK for us.
+So we don't set _WIN32_IE here.
+default _WIN32_IE value set by <windows.h>:
+  0x501 2003sdk
+  0xa00 win10 sdk
+*/
diff --git a/CPP/7zip/UI/FileManager/StringUtils.cpp b/CPP/7zip/UI/FileManager/StringUtils.cpp
new file mode 100644
index 0000000..4641d15
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/StringUtils.cpp
@@ -0,0 +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;
+}
+*/
diff --git a/CPP/7zip/UI/FileManager/StringUtils.h b/CPP/7zip/UI/FileManager/StringUtils.h
new file mode 100644
index 0000000..37aad3a
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/StringUtils.h
@@ -0,0 +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
diff --git a/CPP/7zip/UI/FileManager/SysIconUtils.cpp b/CPP/7zip/UI/FileManager/SysIconUtils.cpp
index 2100e82..1c7cab0 100644
--- a/CPP/7zip/UI/FileManager/SysIconUtils.cpp
+++ b/CPP/7zip/UI/FileManager/SysIconUtils.cpp
@@ -1,255 +1,278 @@
-// SysIconUtils.cpp

-

-#include "StdAfx.h"

-

-#ifndef _UNICODE

-#include "../../../Common/StringConvert.h"

-#endif

-

-#include "../../../Windows/FileDir.h"

-

-#include "SysIconUtils.h"

-

-#include <ShlObj.h>

-

-#ifndef _UNICODE

-extern bool g_IsNT;

-#endif

-

-int GetIconIndexForCSIDL(int csidl)

-{

-  LPITEMIDLIST pidl = 0;

-  SHGetSpecialFolderLocation(NULL, csidl, &pidl);

-  if (pidl)

-  {

-    SHFILEINFO shellInfo;

-    SHGetFileInfo(LPCTSTR(pidl), FILE_ATTRIBUTE_NORMAL,

-      &shellInfo, sizeof(shellInfo),

-      SHGFI_PIDL | SHGFI_SYSICONINDEX);

-    IMalloc  *pMalloc;

-    SHGetMalloc(&pMalloc);

-    if (pMalloc)

-    {

-      pMalloc->Free(pidl);

-      pMalloc->Release();

-    }

-    return shellInfo.iIcon;

-  }

-  return 0;

-}

-

-#ifndef _UNICODE

-typedef int (WINAPI * SHGetFileInfoWP)(LPCWSTR pszPath, DWORD attrib, SHFILEINFOW *psfi, UINT cbFileInfo, UINT uFlags);

-

-struct CSHGetFileInfoInit

-{

-  SHGetFileInfoWP shGetFileInfoW;

-  CSHGetFileInfoInit()

-  {

-    shGetFileInfoW = (SHGetFileInfoWP)

-    ::GetProcAddress(::GetModuleHandleW(L"shell32.dll"), "SHGetFileInfoW");

-  }

-} g_SHGetFileInfoInit;

-#endif

-

-static DWORD_PTR MySHGetFileInfoW(LPCWSTR pszPath, DWORD attrib, SHFILEINFOW *psfi, UINT cbFileInfo, UINT uFlags)

-{

-  #ifdef _UNICODE

-  return SHGetFileInfo

-  #else

-  if (g_SHGetFileInfoInit.shGetFileInfoW == 0)

-    return 0;

-  return g_SHGetFileInfoInit.shGetFileInfoW

-  #endif

-  (pszPath, attrib, psfi, cbFileInfo, uFlags);

-}

-

-DWORD_PTR GetRealIconIndex(CFSTR path, DWORD attrib, int &iconIndex)

-{

-  #ifndef _UNICODE

-  if (!g_IsNT)

-  {

-    SHFILEINFO shellInfo;

-    DWORD_PTR res = ::SHGetFileInfo(fs2fas(path), FILE_ATTRIBUTE_NORMAL | attrib, &shellInfo,

-      sizeof(shellInfo), SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX);

-    iconIndex = shellInfo.iIcon;

-    return res;

-  }

-  else

-  #endif

-  {

-    SHFILEINFOW shellInfo;

-    DWORD_PTR res = ::MySHGetFileInfoW(fs2us(path), FILE_ATTRIBUTE_NORMAL | attrib, &shellInfo,

-      sizeof(shellInfo), SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX);

-    iconIndex = shellInfo.iIcon;

-    return res;

-  }

-}

-

-/*

-DWORD_PTR GetRealIconIndex(const UString &fileName, DWORD attrib, int &iconIndex, UString *typeName)

-{

-  #ifndef _UNICODE

-  if (!g_IsNT)

-  {

-    SHFILEINFO shellInfo;

-    shellInfo.szTypeName[0] = 0;

-    DWORD_PTR res = ::SHGetFileInfoA(GetSystemString(fileName), FILE_ATTRIBUTE_NORMAL | attrib, &shellInfo,

-        sizeof(shellInfo), SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX | SHGFI_TYPENAME);

-    if (typeName)

-      *typeName = GetUnicodeString(shellInfo.szTypeName);

-    iconIndex = shellInfo.iIcon;

-    return res;

-  }

-  else

-  #endif

-  {

-    SHFILEINFOW shellInfo;

-    shellInfo.szTypeName[0] = 0;

-    DWORD_PTR res = ::MySHGetFileInfoW(fileName, FILE_ATTRIBUTE_NORMAL | attrib, &shellInfo,

-        sizeof(shellInfo), SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX | SHGFI_TYPENAME);

-    if (typeName)

-      *typeName = shellInfo.szTypeName;

-    iconIndex = shellInfo.iIcon;

-    return res;

-  }

-}

-*/

-

-static int FindInSorted_Attrib(const CRecordVector<CAttribIconPair> &vect, DWORD attrib, int &insertPos)

-{

-  unsigned left = 0, right = vect.Size();

-  while (left != right)

-  {

-    unsigned mid = (left + right) / 2;

-    DWORD midAttrib = vect[mid].Attrib;

-    if (attrib == midAttrib)

-      return mid;

-    if (attrib < midAttrib)

-      right = mid;

-    else

-      left = mid + 1;

-  }

-  insertPos = left;

-  return -1;

-}

-

-static int FindInSorted_Ext(const CObjectVector<CExtIconPair> &vect, const wchar_t *ext, int &insertPos)

-{

-  unsigned left = 0, right = vect.Size();

-  while (left != right)

-  {

-    unsigned mid = (left + right) / 2;

-    int compare = MyStringCompareNoCase(ext, vect[mid].Ext);

-    if (compare == 0)

-      return mid;

-    if (compare < 0)

-      right = mid;

-    else

-      left = mid + 1;

-  }

-  insertPos = left;

-  return -1;

-}

-

-int CExtToIconMap::GetIconIndex(DWORD attrib, const wchar_t *fileName /*, UString *typeName */)

-{

-  int dotPos = -1;

-  unsigned i;

-  for (i = 0;; i++)

-  {

-    wchar_t c = fileName[i];

-    if (c == 0)

-      break;

-    if (c == '.')

-      dotPos = i;

-  }

-

-  /*

-  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) != 0 || dotPos < 0)

-  {

-    int insertPos = 0;

-    int index = FindInSorted_Attrib(_attribMap, attrib, insertPos);

-    if (index >= 0)

-    {

-      // if (typeName) *typeName = _attribMap[index].TypeName;

-      return _attribMap[index].IconIndex;

-    }

-    CAttribIconPair pair;

-    GetRealIconIndex(

-        #ifdef UNDER_CE

-        FTEXT("\\")

-        #endif

-        FTEXT("__DIR__")

-        , attrib, pair.IconIndex

-        // , pair.TypeName

-        );

-

-    /*

-    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;

-  }

-

-  const wchar_t *ext = fileName + dotPos + 1;

-  int insertPos = 0;

-  int index = FindInSorted_Ext(_extMap, ext, insertPos);

-  if (index >= 0)

-  {

-    const CExtIconPair &pa = _extMap[index];

-    // if (typeName) *typeName = pa.TypeName;

-    return pa.IconIndex;

-  }

-

-  for (i = 0;; i++)

-  {

-    wchar_t c = ext[i];

-    if (c == 0)

-      break;

-    if (c < L'0' || c > L'9')

-      break;

-  }

-  if (i != 0 && ext[i] == 0)

-  {

-    // GetRealIconIndex is too slow for big number of split extensions: .001, .002, .003

-    if (!SplitIconIndex_Defined)

-    {

-      GetRealIconIndex(

-          #ifdef UNDER_CE

-          FTEXT("\\")

-          #endif

-          FTEXT("__FILE__.001"), 0, SplitIconIndex);

-      SplitIconIndex_Defined = true;

-    }

-    return SplitIconIndex;

-  }

-

-  CExtIconPair pair;

-  pair.Ext = ext;

-  GetRealIconIndex(us2fs(fileName + dotPos), attrib, pair.IconIndex);

-  _extMap.Insert(insertPos, pair);

-  // if (typeName) *typeName = pair.TypeName;

-  return pair.IconIndex;

-}

-

-/*

-int CExtToIconMap::GetIconIndex(DWORD attrib, const UString &fileName)

-{

-  return GetIconIndex(attrib, fileName, NULL);

-}

-*/

+// 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 <shlobj.h>
+#else
+#include <ShlObj.h>
+#endif
+
+#ifndef _UNICODE
+extern bool g_IsNT;
+#endif
+
+int GetIconIndexForCSIDL(int csidl)
+{
+  LPITEMIDLIST pidl = NULL;
+  SHGetSpecialFolderLocation(NULL, csidl, &pidl);
+  if (pidl)
+  {
+    SHFILEINFO shellInfo;
+    shellInfo.iIcon = 0;
+    const DWORD_PTR res = SHGetFileInfo((LPCTSTR)(const void *)(pidl), FILE_ATTRIBUTE_NORMAL,
+        &shellInfo, sizeof(shellInfo),
+        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 shellInfo.iIcon;
+  }
+  return 0;
+}
+
+#ifndef _UNICODE
+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");
+  }
+} g_SHGetFileInfo_Init;
+#endif
+
+static DWORD_PTR My_SHGetFileInfoW(LPCWSTR pszPath, DWORD attrib, SHFILEINFOW *psfi, UINT cbFileInfo, UINT uFlags)
+{
+  #ifdef _UNICODE
+  return SHGetFileInfo
+  #else
+  if (!g_SHGetFileInfo_Init.f_SHGetFileInfoW)
+    return 0;
+  return g_SHGetFileInfo_Init.f_SHGetFileInfoW
+  #endif
+  (pszPath, attrib, psfi, cbFileInfo, uFlags);
+}
+
+DWORD_PTR GetRealIconIndex(CFSTR path, DWORD attrib, int &iconIndex)
+{
+  #ifndef _UNICODE
+  if (!g_IsNT)
+  {
+    SHFILEINFO shellInfo;
+    const DWORD_PTR res = ::SHGetFileInfo(fs2fas(path), FILE_ATTRIBUTE_NORMAL | attrib, &shellInfo,
+      sizeof(shellInfo), SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX);
+    iconIndex = shellInfo.iIcon;
+    return res;
+  }
+  else
+  #endif
+  {
+    SHFILEINFOW shellInfo;
+    const DWORD_PTR res = ::My_SHGetFileInfoW(fs2us(path), FILE_ATTRIBUTE_NORMAL | attrib, &shellInfo,
+      sizeof(shellInfo), SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX);
+    iconIndex = shellInfo.iIcon;
+    return res;
+  }
+}
+
+/*
+DWORD_PTR GetRealIconIndex(const UString &fileName, DWORD attrib, int &iconIndex, UString *typeName)
+{
+  #ifndef _UNICODE
+  if (!g_IsNT)
+  {
+    SHFILEINFO shellInfo;
+    shellInfo.szTypeName[0] = 0;
+    DWORD_PTR res = ::SHGetFileInfoA(GetSystemString(fileName), FILE_ATTRIBUTE_NORMAL | attrib, &shellInfo,
+        sizeof(shellInfo), SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX | SHGFI_TYPENAME);
+    if (typeName)
+      *typeName = GetUnicodeString(shellInfo.szTypeName);
+    iconIndex = shellInfo.iIcon;
+    return res;
+  }
+  else
+  #endif
+  {
+    SHFILEINFOW shellInfo;
+    shellInfo.szTypeName[0] = 0;
+    DWORD_PTR res = ::My_SHGetFileInfoW(fileName, FILE_ATTRIBUTE_NORMAL | attrib, &shellInfo,
+        sizeof(shellInfo), SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX | SHGFI_TYPENAME);
+    if (typeName)
+      *typeName = shellInfo.szTypeName;
+    iconIndex = shellInfo.iIcon;
+    return res;
+  }
+}
+*/
+
+static int FindInSorted_Attrib(const CRecordVector<CAttribIconPair> &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<CExtIconPair> &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;
+}
+
+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;
+  }
+
+  /*
+  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) != 0 || dotPos < 0)
+  {
+    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;
+    GetRealIconIndex(
+        #ifdef UNDER_CE
+        FTEXT("\\")
+        #endif
+        FTEXT("__DIR__")
+        , attrib, pair.IconIndex
+        // , pair.TypeName
+        );
+
+    /*
+    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;
+  }
+
+  const wchar_t *ext = fileName + dotPos + 1;
+  unsigned insertPos = 0;
+  const int index = FindInSorted_Ext(_extMap, ext, insertPos);
+  if (index >= 0)
+  {
+    const CExtIconPair &pa = _extMap[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)
+  {
+    // GetRealIconIndex is too slow for big number of split extensions: .001, .002, .003
+    if (!SplitIconIndex_Defined)
+    {
+      GetRealIconIndex(
+          #ifdef UNDER_CE
+          FTEXT("\\")
+          #endif
+          FTEXT("__FILE__.001"), 0, SplitIconIndex);
+      SplitIconIndex_Defined = true;
+    }
+    return SplitIconIndex;
+  }
+
+  CExtIconPair pair;
+  pair.Ext = ext;
+  GetRealIconIndex(us2fs(fileName + dotPos), attrib, pair.IconIndex);
+  _extMap.Insert(insertPos, pair);
+  // if (typeName) *typeName = pair.TypeName;
+  return pair.IconIndex;
+}
+
+/*
+int CExtToIconMap::GetIconIndex(DWORD attrib, const UString &fileName)
+{
+  return GetIconIndex(attrib, fileName, NULL);
+}
+*/
+
+HIMAGELIST GetSysImageList(bool smallIcons)
+{
+  SHFILEINFO shellInfo;
+  return (HIMAGELIST)SHGetFileInfo(TEXT(""),
+      FILE_ATTRIBUTE_NORMAL |
+      FILE_ATTRIBUTE_DIRECTORY,
+      &shellInfo, sizeof(shellInfo),
+      SHGFI_USEFILEATTRIBUTES |
+      SHGFI_SYSICONINDEX |
+      (smallIcons ? SHGFI_SMALLICON : SHGFI_ICON));
+}
diff --git a/CPP/7zip/UI/FileManager/SysIconUtils.h b/CPP/7zip/UI/FileManager/SysIconUtils.h
index 2eedc4b..1d34ef6 100644
--- a/CPP/7zip/UI/FileManager/SysIconUtils.h
+++ b/CPP/7zip/UI/FileManager/SysIconUtils.h
@@ -1,62 +1,55 @@
-// SysIconUtils.h

-

-#ifndef __SYS_ICON_UTILS_H

-#define __SYS_ICON_UTILS_H

-

-#include "../../../Common/MyWindows.h"

-

-#include <commctrl.h>

-

-#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); }

-};

-

-class CExtToIconMap

-{

-public:

-  CRecordVector<CAttribIconPair> _attribMap;

-  CObjectVector<CExtIconPair> _extMap;

-  int SplitIconIndex;

-  int SplitIconIndex_Defined;

-  

-  CExtToIconMap(): SplitIconIndex_Defined(false) {}

-

-  void Clear()

-  {

-    SplitIconIndex_Defined = false;

-    _extMap.Clear();

-    _attribMap.Clear();

-  }

-  int GetIconIndex(DWORD attrib, const wchar_t *fileName /* , UString *typeName */);

-  // int GetIconIndex(DWORD attrib, const UString &fileName);

-};

-

-DWORD_PTR GetRealIconIndex(CFSTR path, DWORD attrib, int &iconIndex);

-int GetIconIndexForCSIDL(int csidl);

-

-inline HIMAGELIST GetSysImageList(bool smallIcons)

-{

-  SHFILEINFO shellInfo;

-  return (HIMAGELIST)SHGetFileInfo(TEXT(""),

-      FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_DIRECTORY,

-      &shellInfo, sizeof(shellInfo),

-      SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX | (smallIcons ? SHGFI_SMALLICON : SHGFI_ICON));

-}

-

-#endif

+// SysIconUtils.h
+
+#ifndef ZIP7_INC_SYS_ICON_UTILS_H
+#define ZIP7_INC_SYS_ICON_UTILS_H
+
+#include "../../../Common/MyWindows.h"
+
+#include <CommCtrl.h>
+
+#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); }
+};
+
+class CExtToIconMap
+{
+public:
+  CRecordVector<CAttribIconPair> _attribMap;
+  CObjectVector<CExtIconPair> _extMap;
+  int SplitIconIndex;
+  int SplitIconIndex_Defined;
+  
+  CExtToIconMap(): SplitIconIndex_Defined(false) {}
+
+  void Clear()
+  {
+    SplitIconIndex_Defined = false;
+    _extMap.Clear();
+    _attribMap.Clear();
+  }
+  int GetIconIndex(DWORD attrib, const wchar_t *fileName /* , UString *typeName */);
+  // int GetIconIndex(DWORD attrib, const UString &fileName);
+};
+
+DWORD_PTR GetRealIconIndex(CFSTR path, DWORD attrib, int &iconIndex);
+int GetIconIndexForCSIDL(int csidl);
+
+HIMAGELIST GetSysImageList(bool smallIcons);
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/SystemPage.cpp b/CPP/7zip/UI/FileManager/SystemPage.cpp
new file mode 100644
index 0000000..09d8a72
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/SystemPage.cpp
@@ -0,0 +1,472 @@
+// SystemPage.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/MyWindows.h"
+
+#if defined(__MINGW32__) || defined(__MINGW64__)
+#include <shlobj.h>
+#else
+#include <ShlObj.h>
+#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), 72);
+
+  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 = 128;
+  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
new file mode 100644
index 0000000..6f2ed0c
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/SystemPage.h
@@ -0,0 +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<CAssoc> _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
new file mode 100644
index 0000000..3bb143a
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/SystemPage.rc
@@ -0,0 +1,43 @@
+#include "SystemPageRes.h"
+#include "../../GuiCommon.rc"
+
+#define xc 240
+#define yc 252
+
+IDD_SYSTEM  DIALOG  0, 0, xs, ys  MY_PAGE_STYLE  MY_FONT
+CAPTION "System"
+BEGIN
+  LTEXT       "Associate 7-Zip with:", IDT_SYSTEM_ASSOCIATE, m, m, xc, 8
+  PUSHBUTTON  "+", IDB_SYSTEM_CURRENT, 80, m + 12, 40, bys
+  PUSHBUTTON  "+", IDB_SYSTEM_ALL,    166, 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  0, 0, xs, ys  MY_PAGE_STYLE  MY_FONT
+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
new file mode 100644
index 0000000..c894448
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/SystemPageRes.h
@@ -0,0 +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
diff --git a/CPP/7zip/UI/FileManager/Test.bmp b/CPP/7zip/UI/FileManager/Test.bmp
new file mode 100644
index 0000000..ef85ba2
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/Test.bmp
Binary files differ
diff --git a/CPP/7zip/UI/FileManager/Test2.bmp b/CPP/7zip/UI/FileManager/Test2.bmp
new file mode 100644
index 0000000..99b7dbf
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/Test2.bmp
Binary files differ
diff --git a/CPP/7zip/UI/FileManager/TextPairs.cpp b/CPP/7zip/UI/FileManager/TextPairs.cpp
new file mode 100644
index 0000000..1ac7098
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/TextPairs.cpp
@@ -0,0 +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<CTextPair> &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 += '\"';
+    text += pair.ID;
+    if (multiWord)
+      text += '\"';
+    text.Add_Space();
+    text += pair.Value;
+    text += '\x0D';
+    text.Add_LF();
+  }
+}
diff --git a/CPP/7zip/UI/FileManager/TextPairs.h b/CPP/7zip/UI/FileManager/TextPairs.h
new file mode 100644
index 0000000..d18233d
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/TextPairs.h
@@ -0,0 +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<CTextPair> 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
new file mode 100644
index 0000000..71ad710
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/UpdateCallback100.cpp
@@ -0,0 +1,124 @@
+// 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);
+}
diff --git a/CPP/7zip/UI/FileManager/UpdateCallback100.h b/CPP/7zip/UI/FileManager/UpdateCallback100.h
new file mode 100644
index 0000000..5d56dfb
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/UpdateCallback100.h
@@ -0,0 +1,46 @@
+// 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
diff --git a/CPP/7zip/UI/FileManager/VerCtrl.cpp b/CPP/7zip/UI/FileManager/VerCtrl.cpp
new file mode 100644
index 0000000..0c894b8
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/VerCtrl.cpp
@@ -0,0 +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(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<UInt32> 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(path, OPEN_EXISTING))
+          {
+            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.Name = fs2us(path);
+        
+        dialog.NewFileInfo.SetTime(&fdi2.Info.ftLastWriteTime);
+        dialog.NewFileInfo.SetSize(fdi2.GetSize());
+        dialog.NewFileInfo.Name = 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
new file mode 100644
index 0000000..3d64602
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/ViewSettings.cpp
@@ -0,0 +1,314 @@
+// 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);
+}
diff --git a/CPP/7zip/UI/FileManager/ViewSettings.h b/CPP/7zip/UI/FileManager/ViewSettings.h
new file mode 100644
index 0000000..02af0a1
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/ViewSettings.h
@@ -0,0 +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<CColumnInfo> 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
new file mode 100644
index 0000000..df08c98
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/makefile
@@ -0,0 +1,108 @@
+PROG = 7zFM.exe
+CFLAGS = $(CFLAGS) \
+  -DZ7_EXTERNAL_CODECS \
+
+!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 4666269..9d605c6 100644
--- a/CPP/7zip/UI/FileManager/resource.h
+++ b/CPP/7zip/UI/FileManager/resource.h
@@ -1,177 +1,192 @@
-#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_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_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            761

-

-#define IDS_BOOKMARK             801

-

-#define IDM_OPTIONS              900

-#define IDM_BENCHMARK            901

-#define IDM_BENCHMARK2           902

-

-#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_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_ADD_TO_FAVORITES     800
+#define IDS_BOOKMARK             801
+
+#define IDM_OPTIONS              900
+#define IDM_BENCHMARK            901
+#define IDM_BENCHMARK2           902
+
+#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
new file mode 100644
index 0000000..002265a
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/resource.rc
@@ -0,0 +1,286 @@
+#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 "SHA-1",                     IDM_SHA1
+      MENUITEM "SHA-256",                   IDM_SHA256
+      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
+  #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 "ComboDialog.rc"
+#include "CopyDialog.rc"
+#include "EditDialog.rc"
+#include "EditPage.rc"
+#include "FoldersPage.rc"
+#include "LangPage.rc"
+#include "LinkDialog.rc"
+#include "ListViewDialog.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 025f316..7c1b40e 100644
--- a/CPP/7zip/UI/FileManager/resourceGui.h
+++ b/CPP/7zip/UI/FileManager/resourceGui.h
@@ -1,15 +1,15 @@
-#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 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
diff --git a/CPP/7zip/UI/FileManager/resourceGui.rc b/CPP/7zip/UI/FileManager/resourceGui.rc
new file mode 100644
index 0000000..f748e0b
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/resourceGui.rc
@@ -0,0 +1,19 @@
+#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..."
+END
diff --git a/CPP/7zip/UI/GUI/7zG.exe.manifest b/CPP/7zip/UI/GUI/7zG.exe.manifest
new file mode 100644
index 0000000..ae964d8
--- /dev/null
+++ b/CPP/7zip/UI/GUI/7zG.exe.manifest
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
+  <assemblyIdentity version="1.0.0.0" processorArchitecture="*" name="7-Zip.7-Zip.7zG" type="win32"/>
+  <description>7-Zip GUI.</description>
+  <dependency>
+    <dependentAssembly><assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"/></dependentAssembly>
+  </dependency>
+<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"><application>
+<!-- Vista   --> <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
+<!-- Win 7   --> <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
+<!-- Win 8   --> <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
+<!-- Win 8.1 --> <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
+<!-- Win 10  --> <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
+</application></compatibility>
+  <asmv3:application>
+    <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
+      <dpiAware>true</dpiAware>
+    </asmv3:windowsSettings>
+  </asmv3:application>
+<application xmlns="urn:schemas-microsoft-com:asm.v3">
+<windowsSettings xmlns:ws2="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
+<ws2:longPathAware>true</ws2:longPathAware></windowsSettings></application>
+</assembly>
diff --git a/CPP/7zip/UI/GUI/BenchmarkDialog.cpp b/CPP/7zip/UI/GUI/BenchmarkDialog.cpp
new file mode 100644
index 0000000..539d689
--- /dev/null
+++ b/CPP/7zip/UI/GUI/BenchmarkDialog.cpp
@@ -0,0 +1,1920 @@
+// 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 "../../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<CBenchPassResult> 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<CProperty> 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(IDT_BENCH_MEMORY);
+    if (s2.IsEmpty())
+      GetItemText(IDT_BENCH_MEMORY, s2);
+    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 += " ";
+  // 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 += " ";
+
+  AddRatingString(s, enc);
+  s += "  ";
+  AddRatingString(s, dec);
+  
+  CTotalBenchRes tot_BenchRes;
+  tot_BenchRes.SetSum(enc, dec);
+  
+  s += "  ";
+  AddRatingString(s, tot_BenchRes);
+  
+  s += " "; AddUsageString(s, tot_BenchRes);
+
+  
+  #ifdef PRINT_ITER_TIME
+  s += " ";
+  {
+    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<CBenchPassResult> 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 += " ";
+      */
+      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 += " ";
+    if (numThreads != 1)
+    {
+      s.Add_UInt64(GetUsagePercents(usage));
+      s += '%';
+      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<CProperty> 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 += '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<CProperty> &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 += (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
new file mode 100644
index 0000000..63c6ded
--- /dev/null
+++ b/CPP/7zip/UI/GUI/BenchmarkDialog.h
@@ -0,0 +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<CProperty> &props, UInt32 numIterations, HWND hwndParent = NULL);
+
+#endif
diff --git a/CPP/7zip/UI/GUI/BenchmarkDialog.rc b/CPP/7zip/UI/GUI/BenchmarkDialog.rc
new file mode 100644
index 0000000..3e73e46
--- /dev/null
+++ b/CPP/7zip/UI/GUI/BenchmarkDialog.rc
@@ -0,0 +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
+}
diff --git a/CPP/7zip/UI/GUI/BenchmarkDialogRes.h b/CPP/7zip/UI/GUI/BenchmarkDialogRes.h
new file mode 100644
index 0000000..b7d54b7
--- /dev/null
+++ b/CPP/7zip/UI/GUI/BenchmarkDialogRes.h
@@ -0,0 +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)
diff --git a/CPP/7zip/UI/GUI/CompressDialog.cpp b/CPP/7zip/UI/GUI/CompressDialog.cpp
new file mode 100644
index 0000000..c2aee6c
--- /dev/null
+++ b/CPP/7zip/UI/GUI/CompressDialog.cpp
@@ -0,0 +1,3820 @@
+// 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 "../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<CCodecInfoUser> &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 &reg)
+{
+  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<CBrowseFilterInfo> &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<CBrowseFilterInfo> 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)
+{
+  const UInt64 v2 = size + ((UInt32)1 << 20) - 1;
+  if (size <= v2)
+    size = v2;
+  s.Add_UInt64(size >> 20);
+  s += " MB";
+}
+
+
+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)
+{
+  s += "The operation was blocked by 7-Zip";
+  s.Add_LF();
+  s += "The operation can require big amount of RAM (memory):";
+  s.Add_LF();
+  s.Add_LF();
+  AddSize_MB(s, reqSize);
+
+  if (!usageString.IsEmpty())
+  {
+    s += " : ";
+    s += usageString;
+  }
+
+  s.Add_LF();
+  AddSize_MB(s, ramSize);
+  s += " : RAM";
+
+  // if (ramLimit != 0)
+  {
+    s.Add_LF();
+    AddSize_MB(s, ramLimit);
+    s += " : 7-Zip limit";
+  }
+  
+  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 s;
+        UString s2 = LangString(IDT_COMPRESS_MEMORY);
+        if (s2.IsEmpty())
+          GetItemText(IDT_COMPRESS_MEMORY, s2);
+        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 += c;
+  s += '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 += c;
+  s += '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 += c;
+  res += 'B';
+}
+
+
+int CCompressDialog::AddMemComboItem(UInt64 val, bool isPercent, bool isDefault)
+{
+  UString sUser;
+  UString sRegistry;
+  if (isPercent)
+  {
+    UString s;
+    s.Add_UInt64(val);
+    s += '%';
+    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 += ":";
+      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
new file mode 100644
index 0000000..c2d2699
--- /dev/null
+++ b/CPP/7zip/UI/GUI/CompressDialog.h
@@ -0,0 +1,481 @@
+// 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<UInt64> 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<CArcInfoEx> *ArcFormats;
+  CUIntVector ArcIndices; // can not be empty, must contain Info.FormatIndex, if Info.FormatIndex >= 0
+  AStringVector ExternalMethods;
+  
+  void SetMethods(const CObjectVector<CCodecInfoUser> &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
new file mode 100644
index 0000000..f04329e
--- /dev/null
+++ b/CPP/7zip/UI/GUI/CompressDialog.rc
@@ -0,0 +1,231 @@
+#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"
+END
+
+
+#include "CompressOptionsDialog.rc"
diff --git a/CPP/7zip/UI/GUI/CompressDialogRes.h b/CPP/7zip/UI/GUI/CompressDialogRes.h
new file mode 100644
index 0000000..aa25b89
--- /dev/null
+++ b/CPP/7zip/UI/GUI/CompressDialogRes.h
@@ -0,0 +1,123 @@
+#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
diff --git a/CPP/7zip/UI/GUI/CompressOptionsDialog.rc b/CPP/7zip/UI/GUI/CompressOptionsDialog.rc
new file mode 100644
index 0000000..0578227
--- /dev/null
+++ b/CPP/7zip/UI/GUI/CompressOptionsDialog.rc
@@ -0,0 +1,76 @@
+#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)
+
+#define ceSize 18
+#define ceString ":"
+
+
+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
+
+  CONTROL   "Store symbolic links", IDX_COMPRESS_NT_SYM_LINKS, MY_CHECKBOX,
+            ntPosX, ntPosY + 12, ntSizeX, 10
+  CONTROL   "Store hard links", IDX_COMPRESS_NT_HARD_LINKS, MY_CHECKBOX,
+            ntPosX, ntPosY + 26, ntSizeX, 10
+  CONTROL   "Store alternate data streams", IDX_COMPRESS_NT_ALT_STREAMS, MY_CHECKBOX,
+            ntPosX, ntPosY + 40, ntSizeX, 10
+  CONTROL   "Store file security", IDX_COMPRESS_NT_SECUR, MY_CHECKBOX,
+            ntPosX, ntPosY + 54, ntSizeX, 10
+
+  LTEXT     "", IDT_COMPRESS_TIME_INFO, g5x, timePosY - 14, g5xs, 8
+
+  
+  GROUPBOX  "Time", IDG_COMPRESS_TIME, g5x, timePosY, g5xs, 112
+  
+//   CONTROL   "Default", IDX_COMPRESS_TIME_DEFAULT, MY_CHECKBOX,
+//             ntPosX, timePosY + 10, ntSizeX, 16
+
+  CONTROL   ceString, IDX_COMPRESS_PREC_SET, MY_CHECKBOX, ntPosX, timePosY + 14, ceSize, 10
+  LTEXT     "Timestamp precision:", IDT_COMPRESS_TIME_PREC,
+            ntPosX + ceSize, timePosY + 14, ntSizeX - precSizeX - ceSize, 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
+
+  CONTROL   ceString, IDX_COMPRESS_MTIME_SET, MY_CHECKBOX, ntPosX, timePosY + 28, ceSize, 10
+  CONTROL   "Store modification time", IDX_COMPRESS_MTIME, MY_CHECKBOX,
+            ntPosX + ceSize, timePosY + 28, ntSizeX - ceSize, 10
+
+  CONTROL   ceString, IDX_COMPRESS_CTIME_SET, MY_CHECKBOX, ntPosX, timePosY + 42, ceSize, 10
+  CONTROL   "Store creation time", IDX_COMPRESS_CTIME, MY_CHECKBOX,
+            ntPosX + ceSize, timePosY + 42, ntSizeX - ceSize, 10
+
+  CONTROL   ceString, IDX_COMPRESS_ATIME_SET, MY_CHECKBOX, ntPosX, timePosY + 56, ceSize, 10
+  CONTROL   "Store last access time", IDX_COMPRESS_ATIME, MY_CHECKBOX,
+            ntPosX + ceSize, timePosY + 56, ntSizeX - ceSize, 10
+
+  CONTROL   ceString, IDX_COMPRESS_ZTIME_SET, MY_CHECKBOX | BS_MULTILINE, ntPosX, timePosY + 72, ceSize, 16
+  CONTROL   "Set archive time to latest file time", IDX_COMPRESS_ZTIME, MY_CHECKBOX | BS_MULTILINE,
+            ntPosX + ceSize, timePosY + 72, ntSizeX - ceSize, 16
+
+  CONTROL   "Do not change source files last access time", IDX_COMPRESS_PRESERVE_ATIME, MY_CHECKBOX | BS_MULTILINE,
+            ntPosX, timePosY + 92, ntSizeX, 16
+  
+  
+  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 6bda89e..36bfb00 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  "Can not open file '{0}' as archive"

-  IDS_CANT_OPEN_ENCRYPTED_ARCHIVE  "Can not open encrypted archive '{0}'. Wrong password?"

-  IDS_UNSUPPORTED_ARCHIVE_TYPE  "Unsupported archive type"

-

-  IDS_CANT_OPEN_AS_TYPE   "Can not 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 71c2a3b..4628482 100644
--- a/CPP/7zip/UI/GUI/ExtractDialog.cpp
+++ b/CPP/7zip/UI/GUI/ExtractDialog.cpp
@@ -1,418 +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 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;

-

-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

-};

-

-#ifndef _SFX

-

-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 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 NO_REGISTRY

-static const unsigned kHistorySize = 16;

-#endif

-

-#ifndef _SFX

-

-// it's used in CompressDialog also

-void AddComboItems(NControl::CComboBox &combo, const UInt32 *langIDs, unsigned numItems, const int *values, int curVal)

-{

-  int curSel = 0;

-  for (unsigned i = 0; i < numItems; i++)

-  {

-    UString s = LangString(langIDs[i]);

-    s.RemoveChar(L'&');

-    int index = (int)combo.AddString(s);

-    combo.SetItemData(index, i);

-    if (values[i] == curVal)

-      curSel = i;

-  }

-  combo.SetCurSel(curSel);

-}

-

-// it's used in CompressDialog also

-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)

-{

-  bool val = IsButtonCheckedBool(id);

-  bool oldVal = GetBoolsVal(b1, b2);

-  if (val != oldVal)

-    b1.Def = b2.Def = true;

-  b1.Val = b2.Val = val;

-}

-

-#endif

-

-bool CExtractDialog::OnInit()

-{

-  #ifdef 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, ARRAY_SIZE(kLangIDs));

-  }

-  #endif

-  

-  #ifndef _SFX

-  _passwordControl.Attach(GetItem(IDE_EXTRACT_PASSWORD));

-  _passwordControl.SetText(Password);

-  _passwordControl.SetPasswordChar(TEXT('*'));

-  _pathName.Attach(GetItem(IDE_EXTRACT_NAME));

-  #endif

-

-  #ifdef 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 _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 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 _SFX

-

-  _pathMode.Attach(GetItem(IDC_EXTRACT_PATH_MODE));

-  _overwriteMode.Attach(GetItem(IDC_EXTRACT_OVERWRITE_MODE));

-

-  AddComboItems(_pathMode, kPathMode_IDs, ARRAY_SIZE(kPathMode_IDs), kPathModeButtonsVals, PathMode);

-  AddComboItems(_overwriteMode, kOverwriteMode_IDs, 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 _SFX

-void CExtractDialog::UpdatePasswordControl()

-{

-  _passwordControl.SetPasswordChar(IsShowPasswordChecked() ? 0 : TEXT('*'));

-  UString password;

-  _passwordControl.GetText(password);

-  _passwordControl.SetText(password);

-}

-#endif

-

-bool CExtractDialog::OnButtonClicked(int buttonID, HWND buttonHWND)

-{

-  switch (buttonID)

-  {

-    case IDB_EXTRACT_SET_PATH:

-      OnButtonSetPath();

-      return true;

-    #ifndef _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 NO_REGISTRY

-  _path.SetCurSel(-1);

-  #endif

-  _path.SetText(resultPath);

-}

-

-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 _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 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 NO_REGISTRY

-  

-  _path.GetText(s);

-  

-  #else

-

-  int currentItem = _path.GetCurSel();

-  if (currentItem == CB_ERR)

-  {

-    _path.GetText(s);

-    if (_path.GetCount() >= kHistorySize)

-      currentItem = _path.GetCount() - 1;

-  }

-  else

-    _path.GetLBText(currentItem, s);

-  

-  #endif

-

-  s.Trim();

-  NName::NormalizeDirPathPrefix(s);

-  

-  #ifndef _SFX

-  

-  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 NO_REGISTRY

-  _info.Paths.Clear();

-  #ifndef _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 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 308c786..1565fb8 100644
--- a/CPP/7zip/UI/GUI/ExtractDialog.h
+++ b/CPP/7zip/UI/GUI/ExtractDialog.h
@@ -1,113 +1,113 @@
-// ExtractDialog.h

-

-#ifndef __EXTRACT_DIALOG_H

-#define __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 NO_REGISTRY

-#include "../Common/ZipRegistry.h"

-#endif

-

-namespace NExtractionDialog

-{

-  /*

-  namespace NFilesMode

-  {

-    enum EEnum

-    {

-      kSelected,

-      kAll,

-      kSpecified

-    };

-  }

-  */

-}

-

-class CExtractDialog: public NWindows::NControl::CModalDialog

-{

-  #ifdef NO_REGISTRY

-  NWindows::NControl::CDialogChildControl _path;

-  #else

-  NWindows::NControl::CComboBox _path;

-  #endif

-

-  #ifndef _SFX

-  NWindows::NControl::CEdit _pathName;

-  NWindows::NControl::CEdit _passwordControl;

-  NWindows::NControl::CComboBox _pathMode;

-  NWindows::NControl::CComboBox _overwriteMode;

-  #endif

-

-  #ifndef _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();

-  virtual bool OnButtonClicked(int buttonID, HWND buttonHWND);

-  virtual void OnOK();

-  

-  #ifndef NO_REGISTRY

-

-  virtual void OnHelp();

-

-  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 _SFX

-  UString Password;

-  #endif

-  bool PathMode_Force;

-  bool OverwriteMode_Force;

-  NExtract::NPathMode::EEnum PathMode;

-  NExtract::NOverwriteMode::EEnum OverwriteMode;

-

-  #ifndef _SFX

-  // CBoolPair AltStreams;

-  CBoolPair NtSecurity;

-  #endif

-

-  CBoolPair ElimDup;

-

-  INT_PTR Create(HWND aWndParent = 0)

-  {

-    #ifdef _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 f5d6528..3728b96 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 e198796..ed12bfb 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 99db743..fdf3cc7 100644
--- a/CPP/7zip/UI/GUI/ExtractGUI.cpp
+++ b/CPP/7zip/UI/GUI/ExtractGUI.cpp
@@ -1,280 +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 _SFX

-

-static void AddValuePair(UString &s, UINT resourceID, UInt64 value, bool addColon = true)

-{

-  AddLangString(s, resourceID);

-  if (addColon)

-    s += ':';

-  s.Add_Space();

-  char sz[32];

-  ConvertUInt64ToString(value, sz);

-  s += sz;

-  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();

-public:

-  CCodecs *codecs;

-  CExtractCallbackImp *ExtractCallbackSpec;

-  const CObjectVector<COpenType> *FormatIndices;

-  const CIntVector *ExcludedFormatIndices;

-

-  UStringVector *ArchivePaths;

-  UStringVector *ArchivePathsFull;

-  const NWildcard::CCensorNode *WildcardCensor;

-  const CExtractOptions *Options;

-

-  #ifndef _SFX

-  CHashBundle *HashBundle;

-  virtual void ProcessWasFinished_GuiVirt();

-  #endif

-

-  CMyComPtr<IExtractCallbackUI> ExtractCallback;

-  UString Title;

-

-  CPropNameValPairs Pairs;

-};

-

-

-#ifndef _SFX

-void CThreadExtracting::ProcessWasFinished_GuiVirt()

-{

-  if (HashBundle && !Pairs.IsEmpty())

-    ShowHashResults(Pairs, *this);

-}

-#endif

-

-HRESULT CThreadExtracting::ProcessVirt()

-{

-  CDecompressStat Stat;

-  

-  #ifndef _SFX

-  /*

-  if (HashBundle)

-    HashBundle->Init();

-  */

-  #endif

-

-  HRESULT res = Extract(codecs,

-      *FormatIndices, *ExcludedFormatIndices,

-      *ArchivePaths, *ArchivePathsFull,

-      *WildcardCensor, *Options, ExtractCallbackSpec, ExtractCallback,

-      #ifndef _SFX

-        HashBundle,

-      #endif

-      FinalMessage.ErrorMessage.Message, Stat);

-  

-  #ifndef _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(

-    CCodecs *codecs,

-    const CObjectVector<COpenType> &formatIndices,

-    const CIntVector &excludedFormatIndices,

-    UStringVector &archivePaths,

-    UStringVector &archivePathsFull,

-    const NWildcard::CCensorNode &wildcardCensor,

-    CExtractOptions &options,

-    #ifndef _SFX

-    CHashBundle *hb,

-    #endif

-    bool showDialog,

-    bool &messageWasDisplayed,

-    CExtractCallbackImp *extractCallback,

-    HWND hwndParent)

-{

-  messageWasDisplayed = false;

-

-  CThreadExtracting extracter;

-  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 _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 _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 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.ExtractCallback = extractCallback;

-  extracter.ExtractCallbackSpec->Init();

-

-  extracter.CompressingMode = false;

-

-  extracter.ArchivePaths = &archivePaths;

-  extracter.ArchivePathsFull = &archivePathsFull;

-  extracter.WildcardCensor = &wildcardCensor;

-  extracter.Options = &options;

-  #ifndef _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 += ':';
+  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<COpenType> *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<IFolderArchiveExtractCallback> 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<COpenType> &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 466e524..13ca6ab 100644
--- a/CPP/7zip/UI/GUI/ExtractGUI.h
+++ b/CPP/7zip/UI/GUI/ExtractGUI.h
@@ -1,38 +1,39 @@
-// GUI/ExtractGUI.h

-

-#ifndef __EXTRACT_GUI_H

-#define __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(

-    CCodecs *codecs,

-    const CObjectVector<COpenType> &formatIndices,

-    const CIntVector &excludedFormatIndices,

-    UStringVector &archivePaths,

-    UStringVector &archivePathsFull,

-    const NWildcard::CCensorNode &wildcardCensor,

-    CExtractOptions &options,

-    #ifndef _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<COpenType> &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 6437d95..634ba6b 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/FM.ico b/CPP/7zip/UI/GUI/FM.ico
new file mode 100644
index 0000000..3a0a34d
--- /dev/null
+++ b/CPP/7zip/UI/GUI/FM.ico
Binary files differ
diff --git a/CPP/7zip/UI/GUI/GUI.cpp b/CPP/7zip/UI/GUI/GUI.cpp
new file mode 100644
index 0000000..37e637b
--- /dev/null
+++ b/CPP/7zip/UI/GUI/GUI.cpp
@@ -0,0 +1,478 @@
+// GUI.cpp
+
+#include "StdAfx.h"
+
+#ifdef _WIN32
+#include "../../../../C/DllSecur.h"
+#endif
+
+#include "../../../Common/MyWindows.h"
+#if defined(__MINGW32__) || defined(__MINGW64__)
+#include <shlwapi.h>
+#else
+#include <Shlwapi.h>
+#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;
+
+#ifndef UNDER_CE
+
+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
+
+extern
+bool g_LVN_ITEMACTIVATE_Support;
+bool g_LVN_ITEMACTIVATE_Support = true;
+
+DECLARE_AND_SET_CLIENT_VERSION_VAR
+
+static void ErrorMessage(LPCWSTR message)
+{
+  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);
+  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())
+    {
+      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<COpenType> 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<IFolderArchiveExtractCallback> 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;
+    eo.TestMode = options.Command.IsTestCommand();
+
+    #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();
+
+  #ifndef UNDER_CE
+  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
new file mode 100644
index 0000000..3a6b60f
--- /dev/null
+++ b/CPP/7zip/UI/GUI/GUI.dsp
@@ -0,0 +1,1259 @@
+# 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\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\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\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\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=..\..\..\..\C\Compiler.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
new file mode 100644
index 0000000..85d3348
--- /dev/null
+++ b/CPP/7zip/UI/GUI/GUI.dsw
@@ -0,0 +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>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/CPP/7zip/UI/GUI/HashGUI.cpp b/CPP/7zip/UI/GUI/HashGUI.cpp
new file mode 100644
index 0000000..b96e413
--- /dev/null
+++ b/CPP/7zip/UI/GUI/HashGUI.cpp
@@ -0,0 +1,363 @@
+// 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 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 += (wchar_t)c;
+    s += "iB)";
+  }
+}
+
+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 b626823..1ec9c47 100644
--- a/CPP/7zip/UI/GUI/HashGUI.h
+++ b/CPP/7zip/UI/GUI/HashGUI.h
@@ -1,27 +1,27 @@
-// HashGUI.h

-

-#ifndef __HASH_GUI_H

-#define __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<CProperty> 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<CProperty> 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
new file mode 100644
index 0000000..d0feea8
--- /dev/null
+++ b/CPP/7zip/UI/GUI/StdAfx.cpp
@@ -0,0 +1,3 @@
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/CPP/7zip/UI/GUI/StdAfx.h b/CPP/7zip/UI/GUI/StdAfx.h
new file mode 100644
index 0000000..130db8a
--- /dev/null
+++ b/CPP/7zip/UI/GUI/StdAfx.h
@@ -0,0 +1,6 @@
+// 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
new file mode 100644
index 0000000..26057a7
--- /dev/null
+++ b/CPP/7zip/UI/GUI/UpdateCallbackGUI.cpp
@@ -0,0 +1,280 @@
+// 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
diff --git a/CPP/7zip/UI/GUI/UpdateCallbackGUI.h b/CPP/7zip/UI/GUI/UpdateCallbackGUI.h
new file mode 100644
index 0000000..998249a
--- /dev/null
+++ b/CPP/7zip/UI/GUI/UpdateCallbackGUI.h
@@ -0,0 +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
diff --git a/CPP/7zip/UI/GUI/UpdateCallbackGUI2.cpp b/CPP/7zip/UI/GUI/UpdateCallbackGUI2.cpp
new file mode 100644
index 0000000..966f57e
--- /dev/null
+++ b/CPP/7zip/UI/GUI/UpdateCallbackGUI2.cpp
@@ -0,0 +1,59 @@
+// 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;
+}
diff --git a/CPP/7zip/UI/GUI/UpdateCallbackGUI2.h b/CPP/7zip/UI/GUI/UpdateCallbackGUI2.h
new file mode 100644
index 0000000..e32b602
--- /dev/null
+++ b/CPP/7zip/UI/GUI/UpdateCallbackGUI2.h
@@ -0,0 +1,34 @@
+// 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
diff --git a/CPP/7zip/UI/GUI/UpdateGUI.cpp b/CPP/7zip/UI/GUI/UpdateGUI.cpp
new file mode 100644
index 0000000..aaf7ebd
--- /dev/null
+++ b/CPP/7zip/UI/GUI/UpdateGUI.cpp
@@ -0,0 +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<COpenType> *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<CProperty> &properties,
+    NCompressDialog::CInfo &di)
+{
+  FOR_VECTOR (i, properties)
+  {
+    ParseProp(properties[i], di);
+  }
+}
+
+
+
+
+
+static void AddProp_UString(CObjectVector<CProperty> &properties, const char *name, const UString &value)
+{
+  CProperty prop;
+  prop.Name = name;
+  prop.Value = value;
+  properties.Add(prop);
+}
+
+static void AddProp_UInt32(CObjectVector<CProperty> &properties, const char *name, UInt32 value)
+{
+  UString s;
+  s.Add_UInt32(value);
+  AddProp_UString(properties, name, s);
+}
+
+static void AddProp_bool(CObjectVector<CProperty> &properties, const char *name, bool value)
+{
+  AddProp_UString(properties, name, UString(value ? "on": "off"));
+}
+
+
+static void AddProp_BoolPair(CObjectVector<CProperty> &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<CProperty> &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<CProperty> &properties, const char *name, const UInt64 size)
+{
+  UString s;
+  s.Add_UInt64(size);
+  s += 'b';
+  AddProp_UString(properties, name, s);
+}
+
+
+static void SetOutProperties(
+    CObjectVector<CProperty> &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 += '%';
+      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<NWildcard::CCensorPath> &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<CCodecInfoUser> 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<COpenType> &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
new file mode 100644
index 0000000..0c43a01
--- /dev/null
+++ b/CPP/7zip/UI/GUI/UpdateGUI.h
@@ -0,0 +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<COpenType> &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
new file mode 100644
index 0000000..9e2a9b4
--- /dev/null
+++ b/CPP/7zip/UI/GUI/makefile
@@ -0,0 +1,148 @@
+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_LONG_PATH -DZ7_LARGE_PAGES -DZ7_DEVICE_FILE
+!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\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
new file mode 100644
index 0000000..04af815
--- /dev/null
+++ b/CPP/7zip/UI/GUI/resource.rc
@@ -0,0 +1,25 @@
+#include "../../MyVersionInfo.rc"
+// #include <winnt.h>
+
+#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/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 152e71f..cd88292 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
new file mode 100644
index 0000000..49534f5
--- /dev/null
+++ b/CPP/7zip/UI/GUI/resource2.rc
@@ -0,0 +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
diff --git a/CPP/7zip/UI/GUI/resource3.h b/CPP/7zip/UI/GUI/resource3.h
new file mode 100644
index 0000000..c25737f
--- /dev/null
+++ b/CPP/7zip/UI/GUI/resource3.h
@@ -0,0 +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
diff --git a/CPP/7zip/UI/GUI/resource3.rc b/CPP/7zip/UI/GUI/resource3.rc
new file mode 100644
index 0000000..cfc8bc3
--- /dev/null
+++ b/CPP/7zip/UI/GUI/resource3.rc
@@ -0,0 +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
diff --git a/CPP/7zip/UI/makefile b/CPP/7zip/UI/makefile
new file mode 100644
index 0000000..1b0cdbe
--- /dev/null
+++ b/CPP/7zip/UI/makefile
@@ -0,0 +1,12 @@
+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
new file mode 100644
index 0000000..e62e1e6
--- /dev/null
+++ b/CPP/7zip/cmpl_clang.mak
@@ -0,0 +1,3 @@
+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
new file mode 100644
index 0000000..3f6b02b
--- /dev/null
+++ b/CPP/7zip/cmpl_clang_arm64.mak
@@ -0,0 +1,3 @@
+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
new file mode 100644
index 0000000..b61e2af
--- /dev/null
+++ b/CPP/7zip/cmpl_clang_x64.mak
@@ -0,0 +1,3 @@
+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
new file mode 100644
index 0000000..0e5cb76
--- /dev/null
+++ b/CPP/7zip/cmpl_clang_x86.mak
@@ -0,0 +1,3 @@
+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
new file mode 100644
index 0000000..7a1aef2
--- /dev/null
+++ b/CPP/7zip/cmpl_gcc.mak
@@ -0,0 +1,3 @@
+include ../../var_gcc.mak
+include ../../warn_gcc.mak
+include makefile.gcc
diff --git a/CPP/7zip/cmpl_gcc_arm64.mak b/CPP/7zip/cmpl_gcc_arm64.mak
new file mode 100644
index 0000000..53a8584
--- /dev/null
+++ b/CPP/7zip/cmpl_gcc_arm64.mak
@@ -0,0 +1,3 @@
+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
new file mode 100644
index 0000000..500c30e
--- /dev/null
+++ b/CPP/7zip/cmpl_gcc_x64.mak
@@ -0,0 +1,3 @@
+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
new file mode 100644
index 0000000..e768707
--- /dev/null
+++ b/CPP/7zip/cmpl_gcc_x86.mak
@@ -0,0 +1,3 @@
+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
new file mode 100644
index 0000000..941028e
--- /dev/null
+++ b/CPP/7zip/cmpl_mac_arm64.mak
@@ -0,0 +1,3 @@
+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
new file mode 100644
index 0000000..d3aa039
--- /dev/null
+++ b/CPP/7zip/cmpl_mac_x64.mak
@@ -0,0 +1,3 @@
+include ../../var_mac_x64.mak
+include ../../warn_clang_mac.mak
+include makefile.gcc
diff --git a/CPP/7zip/makefile b/CPP/7zip/makefile
new file mode 100644
index 0000000..9d31e6b
--- /dev/null
+++ b/CPP/7zip/makefile
@@ -0,0 +1,10 @@
+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
new file mode 100644
index 0000000..a6df26e
--- /dev/null
+++ b/CPP/7zip/var_clang.mak
@@ -0,0 +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
diff --git a/CPP/7zip/var_clang_arm64.mak b/CPP/7zip/var_clang_arm64.mak
new file mode 100644
index 0000000..4b35409
--- /dev/null
+++ b/CPP/7zip/var_clang_arm64.mak
@@ -0,0 +1,11 @@
+PLATFORM=arm64
+O=b/c_$(PLATFORM)
+IS_X64=
+IS_X86=
+IS_ARM64=1
+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_x64.mak b/CPP/7zip/var_clang_x64.mak
new file mode 100644
index 0000000..fefed51
--- /dev/null
+++ b/CPP/7zip/var_clang_x64.mak
@@ -0,0 +1,12 @@
+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
new file mode 100644
index 0000000..5f3c2d9
--- /dev/null
+++ b/CPP/7zip/var_clang_x86.mak
@@ -0,0 +1,12 @@
+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
new file mode 100644
index 0000000..664491c
--- /dev/null
+++ b/CPP/7zip/var_gcc.mak
@@ -0,0 +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
diff --git a/CPP/7zip/var_gcc_arm64.mak b/CPP/7zip/var_gcc_arm64.mak
new file mode 100644
index 0000000..4bbb687
--- /dev/null
+++ b/CPP/7zip/var_gcc_arm64.mak
@@ -0,0 +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
diff --git a/CPP/7zip/var_gcc_x64.mak b/CPP/7zip/var_gcc_x64.mak
new file mode 100644
index 0000000..1acf604
--- /dev/null
+++ b/CPP/7zip/var_gcc_x64.mak
@@ -0,0 +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++
diff --git a/CPP/7zip/var_gcc_x86.mak b/CPP/7zip/var_gcc_x86.mak
new file mode 100644
index 0000000..288bf94
--- /dev/null
+++ b/CPP/7zip/var_gcc_x86.mak
@@ -0,0 +1,11 @@
+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
new file mode 100644
index 0000000..adf5fa1
--- /dev/null
+++ b/CPP/7zip/var_mac_arm64.mak
@@ -0,0 +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
diff --git a/CPP/7zip/var_mac_x64.mak b/CPP/7zip/var_mac_x64.mak
new file mode 100644
index 0000000..13d7aa7
--- /dev/null
+++ b/CPP/7zip/var_mac_x64.mak
@@ -0,0 +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
diff --git a/CPP/7zip/warn_clang.mak b/CPP/7zip/warn_clang.mak
new file mode 100644
index 0000000..0d00730
--- /dev/null
+++ b/CPP/7zip/warn_clang.mak
@@ -0,0 +1,3 @@
+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
new file mode 100644
index 0000000..ed936c5
--- /dev/null
+++ b/CPP/7zip/warn_clang_mac.mak
@@ -0,0 +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
diff --git a/CPP/7zip/warn_gcc.mak b/CPP/7zip/warn_gcc.mak
new file mode 100644
index 0000000..7eb1f57
--- /dev/null
+++ b/CPP/7zip/warn_gcc.mak
@@ -0,0 +1,45 @@
+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_9)
+
+# CXX_STD_FLAGS = -std=c++11
+# CXX_STD_FLAGS =
diff --git a/CPP/Build.mak b/CPP/Build.mak
index 5752491..393fa2c 100644
--- a/CPP/Build.mak
+++ b/CPP/Build.mak
@@ -1,156 +1,229 @@
-LIBS = $(LIBS) oleaut32.lib ole32.lib

-

-!IFNDEF MY_NO_UNICODE

-CFLAGS = $(CFLAGS) -DUNICODE -D_UNICODE

-!ENDIF

-

-!IFNDEF O

-!IFDEF PLATFORM

-O=$(PLATFORM)

-!ELSE

-O=o

-!ENDIF

-!ENDIF

-

-# CFLAGS = $(CFLAGS) -FAsc -Fa$O/asm/

-

-

-!IF "$(PLATFORM)" == "x64"

-MY_ML = ml64 -Dx64 -WX

-!ELSEIF "$(PLATFORM)" == "arm"

-MY_ML = armasm -WX

-!ELSE

-MY_ML = ml -WX

-!ENDIF

-

-

-!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

-!ELSE

-COMPL_ASM = $(MY_ML) -c -Fo$O/ $**

-!ENDIF

-

-CFLAGS = $(CFLAGS) -nologo -c -Fo$O/ -W4 -WX -EHsc -Gy -GR- -GF

-

-!IFDEF MY_DYNAMIC_LINK

-CFLAGS = $(CFLAGS) -MD

-!ELSE

-!IFNDEF MY_SINGLE_THREAD

-CFLAGS = $(CFLAGS) -MT

-!ENDIF

-!ENDIF

-

-!IFNDEF OLD_COMPILER

-CFLAGS = $(CFLAGS) -GS- -Zc:forScope -Zc:wchar_t

-!IFNDEF UNDER_CE

-CFLAGS = $(CFLAGS) -MP2

-!IFNDEF PLATFORM

-# CFLAGS = $(CFLAGS) -arch:IA32

-!ENDIF

-!ENDIF

-!ELSE

-CFLAGS = $(CFLAGS)

-!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

-

-!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)" == "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

-

-

-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) -Yu"StdAfx.h" -Fp$O/a.pch $<

-COMPLB_O2 = $(CC) $(CFLAGS_O2) $<

-

-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 $**

-CCOMPL      = $(CC) $(CFLAGS_C_ALL) $**

-CCOMPLB     = $(CC) $(CFLAGS_C_ALL) $<

-

-

-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"

-

-$(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)

+LIBS = $(LIBS) oleaut32.lib ole32.lib
+
+!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
+
+
+!IF "$(PLATFORM)" == "x64"
+MY_ML = ml64 -WX
+#-Dx64
+!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
+!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
+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
+
+
+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 e53fb7f..0be8a7a 100644
--- a/CPP/Common/AutoPtr.h
+++ b/CPP/Common/AutoPtr.h
@@ -1,35 +1,35 @@
-// Common/AutoPtr.h

-

-#ifndef __COMMON_AUTOPTR_H

-#define __COMMON_AUTOPTR_H

-

-template<class T> class CMyAutoPtr

-{

-  T *_p;

-public:

-  CMyAutoPtr(T *p = 0) : _p(p) {}

-  CMyAutoPtr(CMyAutoPtr<T>& p): _p(p.release()) {}

-  CMyAutoPtr<T>& operator=(CMyAutoPtr<T>& p)

-  {

-    reset(p.release());

-    return (*this);

-  }

-  ~CMyAutoPtr() { delete _p; }

-  T& operator*() const { return *_p; }

-  // T* operator->() const { return (&**this); }

-  T* get() const { return _p; }

-  T* release()

-  {

-    T *tmp = _p;

-    _p = 0;

-    return tmp;

-  }

-  void reset(T* p = 0)

-  {

-    if (p != _p)

-      delete _p;

-    _p = p;

-  }

-};

-

-#endif

+// Common/AutoPtr.h
+
+#ifndef ZIP7_INC_COMMON_AUTOPTR_H
+#define ZIP7_INC_COMMON_AUTOPTR_H
+
+template<class T> class CMyAutoPtr
+{
+  T *_p;
+public:
+  CMyAutoPtr(T *p = NULL) : _p(p) {}
+  CMyAutoPtr(CMyAutoPtr<T>& p): _p(p.release()) {}
+  CMyAutoPtr<T>& operator=(CMyAutoPtr<T>& p)
+  {
+    reset(p.release());
+    return (*this);
+  }
+  ~CMyAutoPtr() { delete _p; }
+  T& operator*() const { return *_p; }
+  // T* operator->() const { return (&**this); }
+  T* get() const { return _p; }
+  T* release()
+  {
+    T *tmp = _p;
+    _p = NULL;
+    return tmp;
+  }
+  void reset(T* p = NULL)
+  {
+    if (p != _p)
+      delete _p;
+    _p = p;
+  }
+};
+
+#endif
diff --git a/CPP/Common/CRC.cpp b/CPP/Common/CRC.cpp
index 6ac52c4..c6b7d5e 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"

-

-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 d68a427..4bd3fad 100644
--- a/CPP/Common/C_FileIO.cpp
+++ b/CPP/Common/C_FileIO.cpp
@@ -1,92 +1,3 @@
-// Common/C_FileIO.cpp

-

-#include "C_FileIO.h"

-

-#include <fcntl.h>

-#ifdef _WIN32

-#include <io.h>

-#else

-#include <unistd.h>

-#endif

-

-namespace NC {

-namespace NFile {

-namespace NIO {

-

-bool CFileBase::OpenBinary(const char *name, int flags)

-{

-  #ifdef O_BINARY

-  flags |= O_BINARY;

-  #endif

-  Close();

-  _handle = ::open(name, flags, 0666);

-  return _handle != -1;

-}

-

-bool CFileBase::Close()

-{

-  if (_handle == -1)

-    return true;

-  if (close(_handle) != 0)

-    return false;

-  _handle = -1;

-  return true;

-}

-

-bool CFileBase::GetLength(UInt64 &length) const

-{

-  off_t curPos = Seek(0, SEEK_CUR);

-  off_t lengthTemp = Seek(0, SEEK_END);

-  Seek(curPos, SEEK_SET);

-  length = (UInt64)lengthTemp;

-  return true;

-}

-

-off_t CFileBase::Seek(off_t distanceToMove, int moveMethod) const

-{

-  return ::lseek(_handle, distanceToMove, moveMethod);

-}

-

-/////////////////////////

-// CInFile

-

-bool CInFile::Open(const char *name)

-{

-  return CFileBase::OpenBinary(name, O_RDONLY);

-}

-

-bool CInFile::OpenShared(const char *name, bool)

-{

-  return Open(name);

-}

-

-ssize_t CInFile::Read(void *data, size_t size)

-{

-  return read(_handle, data, size);

-}

-

-/////////////////////////

-// COutFile

-

-bool COutFile::Create(const char *name, bool createAlways)

-{

-  if (createAlways)

-  {

-    Close();

-    _handle = ::creat(name, 0666);

-    return _handle != -1;

-  }

-  return OpenBinary(name, O_CREAT | O_EXCL | O_WRONLY);

-}

-

-bool COutFile::Open(const char *name, DWORD creationDisposition)

-{

-  return Create(name, false);

-}

-

-ssize_t COutFile::Write(const void *data, size_t size)

-{

-  return write(_handle, data, size);

-}

-

-}}}

+// Common/C_FileIO.cpp
+
+#include "StdAfx.h"
diff --git a/CPP/Common/C_FileIO.h b/CPP/Common/C_FileIO.h
index 4c400b4..12d9439 100644
--- a/CPP/Common/C_FileIO.h
+++ b/CPP/Common/C_FileIO.h
@@ -1,53 +1,6 @@
-// Common/C_FileIO.h

-

-#ifndef __COMMON_C_FILEIO_H

-#define __COMMON_C_FILEIO_H

-

-#include <stdio.h>

-#include <sys/types.h>

-

-#include "MyTypes.h"

-#include "MyWindows.h"

-

-#ifdef _WIN32

-#ifdef _MSC_VER

-typedef size_t ssize_t;

-#endif

-#endif

-

-namespace NC {

-namespace NFile {

-namespace NIO {

-

-class CFileBase

-{

-protected:

-  int _handle;

-  bool OpenBinary(const char *name, int flags);

-public:

-  CFileBase(): _handle(-1) {};

-  ~CFileBase() { Close(); }

-  bool Close();

-  bool GetLength(UInt64 &length) const;

-  off_t Seek(off_t distanceToMove, int moveMethod) const;

-};

-

-class CInFile: public CFileBase

-{

-public:

-  bool Open(const char *name);

-  bool OpenShared(const char *name, bool shareForWrite);

-  ssize_t Read(void *data, size_t size);

-};

-

-class COutFile: public CFileBase

-{

-public:

-  bool Create(const char *name, bool createAlways);

-  bool Open(const char *name, DWORD creationDisposition);

-  ssize_t Write(const void *data, size_t size);

-};

-

-}}}

-

-#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
new file mode 100644
index 0000000..8c9c449
--- /dev/null
+++ b/CPP/Common/CksumReg.cpp
@@ -0,0 +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)
diff --git a/CPP/Common/ComTry.h b/CPP/Common/ComTry.h
index e6b514d..84746a7 100644
--- a/CPP/Common/ComTry.h
+++ b/CPP/Common/ComTry.h
@@ -1,21 +1,21 @@
-// ComTry.h

-

-#ifndef __COM_TRY_H

-#define __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 94aabce..465e0fd 100644
--- a/CPP/Common/CommandLineParser.cpp
+++ b/CPP/Common/CommandLineParser.cpp
@@ -1,197 +1,197 @@
-// CommandLineParser.cpp

-

-#include "StdAfx.h"

-

-#include "CommandLineParser.h"

-

-namespace NCommandLineParser {

-

-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++)

-  {

-    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)

-{

-  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;

-  }

-}

-

-

-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;

-    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 = switchLen;

-    }

-  }

-

-  if (maxLen < 0)

-  {

-    ErrorMessage = "Unknown switch:";

-    return false;

-  }

-

-  pos += 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;

-

-  int 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)

-      {

-        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;

-    }

-  }

-

-  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 = 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 {
+
+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++)
+  {
+    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)
+{
+  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;
+  }
+}
+
+
+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;
+    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)
+      {
+        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;
+    }
+  }
+
+  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 ec6336c..fc6f028 100644
--- a/CPP/Common/CommandLineParser.h
+++ b/CPP/Common/CommandLineParser.h
@@ -1,63 +1,63 @@
-// Common/CommandLineParser.h

-

-#ifndef __COMMON_COMMAND_LINE_PARSER_H

-#define __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 c1ecc7e..0c77ab4 100644
--- a/CPP/Common/Common.h
+++ b/CPP/Common/Common.h
@@ -1,43 +1,313 @@
-// Common.h

-

-#ifndef __COMMON_COMMON_H

-#define __COMMON_COMMON_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

-

-If you use 7-Zip code, you must include "Common.h" before other h files of 7-zip.

-If you don't need some things that are used in 7-Zip,

-you can change this h file or h files included in this file.

-*/

-

-// compiler pragmas to disable some warnings

-#include "../../C/Compiler.h"

-

-// it's <windows.h> or code that defines windows things, if it's not _WIN32

-#include "MyWindows.h"

-

-// 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]))

-

-

-/* 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 MY_ARRAY_NEW macro instead of new[] operator. */

-

-#if defined(_MSC_VER) && (_MSC_VER == 1200) && !defined(_WIN64)

-  #define MY_ARRAY_NEW(p, T, size) p = new T[(size > (unsigned)0xFFFFFFFF / sizeof(T)) ? (unsigned)0xFFFFFFFF / sizeof(T) : size];

-#else

-  #define MY_ARRAY_NEW(p, T, size) p = new T[size];

-#endif

-

-#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/Compiler.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
+
+If you use 7-Zip code, you must include "Common.h" before other h files of 7-zip.
+If you don't need some things that are used in 7-Zip,
+you can change this h file or h files included in this file.
+*/
+
+#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__)
+
+// 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
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+#pragma GCC diagnostic ignored "-Wglobal-constructors"
+#pragma GCC diagnostic ignored "-Wexit-time-destructors"
+
+// #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) > (unsigned)0xFFFFFFFF / sizeof(T)) ? (unsigned)0xFFFFFFFF / 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<t>(reinterpret_cast<Z7_void_Function>(e))
+#else
+#define Z7_CAST_FUNC(t, e) reinterpret_cast<t>(reinterpret_cast<void*>(e))
+// #define Z7_CAST_FUNC(t, e) reinterpret_cast<t>(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_COMMON_H
+
+
+
+// #define Z7_REDEFINE_NULL
+
+#if defined(Z7_REDEFINE_NULL) /* && (!defined(__clang__) || defined(_MSC_VER)) */
+
+// NULL is defined in <stddef.h>
+#include <stddef.h>
+#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 1d9d009..6cda892 100644
--- a/CPP/Common/CrcReg.cpp
+++ b/CPP/Common/CrcReg.cpp
@@ -1,98 +1,92 @@
-// 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

-

-typedef UInt32 (MY_FAST_CALL *CRC_FUNC)(UInt32 v, const void *data, size_t size, const UInt32 *table);

-

-UInt32 MY_FAST_CALL CrcUpdateT1(UInt32 v, const void *data, size_t size, const UInt32 *table);

-

-extern CRC_FUNC g_CrcUpdate;

-extern CRC_FUNC g_CrcUpdateT8;

-extern CRC_FUNC g_CrcUpdateT4;

-

-EXTERN_C_END

-

-class CCrcHasher:

-  public IHasher,

-  public ICompressSetCoderProperties,

-  public CMyUnknownImp

-{

-  UInt32 _crc;

-  CRC_FUNC _updateFunc;

-  Byte mtDummy[1 << 7];

-  

-  bool SetFunctions(UInt32 tSize);

-public:

-  CCrcHasher(): _crc(CRC_INIT_VAL) { SetFunctions(0); }

-

-  MY_UNKNOWN_IMP2(IHasher, ICompressSetCoderProperties)

-  INTERFACE_IHasher(;)

-  STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);

-};

-

-bool CCrcHasher::SetFunctions(UInt32 tSize)

-{

-  _updateFunc = g_CrcUpdate;

-  

-  if (tSize == 1)

-    _updateFunc = CrcUpdateT1;

-  else if (tSize == 4)

-  {

-    if (g_CrcUpdateT4)

-      _updateFunc = g_CrcUpdateT4;

-    else

-      return false;

-  }

-  else if (tSize == 8)

-  {

-    if (g_CrcUpdateT8)

-      _updateFunc = g_CrcUpdateT8;

-    else

-      return false;

-  }

-  

-  return true;

-}

-

-STDMETHODIMP CCrcHasher::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps)

-{

-  for (UInt32 i = 0; i < numProps; i++)

-  {

-    const PROPVARIANT &prop = coderProps[i];

-    if (propIDs[i] == NCoderPropID::kDefaultProp)

-    {

-      if (prop.vt != VT_UI4)

-        return E_INVALIDARG;

-      if (!SetFunctions(prop.ulVal))

-        return E_NOTIMPL;

-    }

-  }

-  return S_OK;

-}

-

-STDMETHODIMP_(void) CCrcHasher::Init() throw()

-{

-  _crc = CRC_INIT_VAL;

-}

-

-STDMETHODIMP_(void) CCrcHasher::Update(const void *data, UInt32 size) throw()

-{

-  _crc = _updateFunc(_crc, data, size, g_CrcTable);

-}

-

-STDMETHODIMP_(void) CCrcHasher::Final(Byte *digest) throw()

-{

-  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
+
+// UInt32 Z7_FASTCALL CrcUpdateT1(UInt32 v, const void *data, size_t size, const UInt32 *table);
+
+extern CRC_FUNC g_CrcUpdate;
+// extern CRC_FUNC g_CrcUpdateT4;
+extern CRC_FUNC g_CrcUpdateT8;
+extern CRC_FUNC g_CrcUpdateT0_32;
+extern CRC_FUNC g_CrcUpdateT0_64;
+
+EXTERN_C_END
+
+Z7_CLASS_IMP_COM_2(
+  CCrcHasher
+  , IHasher
+  , ICompressSetCoderProperties
+)
+  UInt32 _crc;
+  CRC_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)
+{
+  CRC_FUNC f = NULL;
+       if (tSize ==  0) f = g_CrcUpdate;
+  // else if (tSize ==  1) f = CrcUpdateT1;
+  // else if (tSize ==  4) f = g_CrcUpdateT4;
+  else if (tSize ==  8) f = g_CrcUpdateT8;
+  else if (tSize == 32) f = g_CrcUpdateT0_32;
+  else if (tSize == 64) f = g_CrcUpdateT0_64;
+  
+  if (!f)
+  {
+    _updateFunc = g_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, g_CrcTable);
+}
+
+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 9416098..e302f35 100644
--- a/CPP/Common/Defs.h
+++ b/CPP/Common/Defs.h
@@ -1,15 +1,16 @@
-// Common/Defs.h

-

-#ifndef __COMMON_DEFS_H

-#define __COMMON_DEFS_H

-

-template <class T> inline T MyMin(T a, T b) { return a < b ? a : b; }

-template <class T> inline T MyMax(T a, T b) { return a > b ? a : b; }

-

-template <class T> 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 bool IntToBool(int v) { return (v != 0); }

-

-#endif

+// Common/Defs.h
+
+#ifndef ZIP7_INC_COMMON_DEFS_H
+#define ZIP7_INC_COMMON_DEFS_H
+
+template <class T> inline T MyMin(T a, T b) { return a < b ? a : b; }
+template <class T> inline T MyMax(T a, T b) { return a > b ? a : b; }
+
+template <class T> 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
new file mode 100644
index 0000000..1d92af3
--- /dev/null
+++ b/CPP/Common/DynLimBuf.cpp
@@ -0,0 +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;
+}
diff --git a/CPP/Common/DynLimBuf.h b/CPP/Common/DynLimBuf.h
new file mode 100644
index 0000000..af22f07
--- /dev/null
+++ b/CPP/Common/DynLimBuf.h
@@ -0,0 +1,41 @@
+// Common/DynLimBuf.h
+
+#ifndef ZIP7_INC_COMMON_DYN_LIM_BUF_H
+#define ZIP7_INC_COMMON_DYN_LIM_BUF_H
+
+#include <string.h>
+
+#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 16c9250..714be4a 100644
--- a/CPP/Common/DynamicBuffer.h
+++ b/CPP/Common/DynamicBuffer.h
@@ -1,64 +1,68 @@
-// Common/DynamicBuffer.h

-

-#ifndef __COMMON_DYNAMIC_BUFFER_H

-#define __COMMON_DYNAMIC_BUFFER_H

-

-template <class T> 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(0), _size(0), _pos(0) {}

-  // operator T *() { return _items; }

-  operator const T *() const { return _items; }

-  ~CDynamicBuffer() { delete []_items; }

-

-  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));

-  }

-

-  const size_t GetPos() const { return _pos; }

-

-  // void Empty() { _pos = 0; }

-};

-

-typedef CDynamicBuffer<unsigned char> CByteDynamicBuffer;

-

-#endif

+// Common/DynamicBuffer.h
+
+#ifndef ZIP7_INC_COMMON_DYNAMIC_BUFFER_H
+#define ZIP7_INC_COMMON_DYNAMIC_BUFFER_H
+
+#include <string.h>
+
+#include "Common.h"
+
+template <class T> 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; }
+
+  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<unsigned char> CByteDynamicBuffer;
+
+#endif
diff --git a/CPP/Common/IntToString.cpp b/CPP/Common/IntToString.cpp
index da627ca..21b0680 100644
--- a/CPP/Common/IntToString.cpp
+++ b/CPP/Common/IntToString.cpp
@@ -1,193 +1,192 @@
-// Common/IntToString.cpp

-

-#include "StdAfx.h"

-

-#include "../../C/CpuArch.h"

-

-#include "IntToString.h"

-

-#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++ = temp[i]; } \

-  *s = 0;

-

-void ConvertUInt32ToString(UInt32 val, char *s) throw()

-{

-  CONVERT_INT_TO_STR(char, 16);

-}

-

-void ConvertUInt64ToString(UInt64 val, char *s) throw()

-{

-  if (val <= (UInt32)0xFFFFFFFF)

-  {

-    ConvertUInt32ToString((UInt32)val, s);

-    return;

-  }

-  CONVERT_INT_TO_STR(char, 24);

-}

-

-void ConvertUInt64ToOct(UInt64 val, char *s) throw()

-{

-  UInt64 v = val;

-  unsigned i;

-  for (i = 1;; i++)

-  {

-    v >>= 3;

-    if (v == 0)

-      break;

-  }

-  s[i] = 0;

-  do

-  {

-    unsigned t = (unsigned)(val & 0x7);

-    val >>= 3;

-    s[--i] = (char)('0' + t);

-  }

-  while (i);

-}

-

-

-#define GET_HEX_CHAR(t) ((char)(((t < 10) ? ('0' + t) : ('A' + (t - 10)))))

-

-static inline char GetHexChar(unsigned t) { return GET_HEX_CHAR(t); }

-

-

-void ConvertUInt32ToHex(UInt32 val, char *s) throw()

-{

-  UInt32 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);

-}

-

-

-void ConvertUInt64ToHex(UInt64 val, char *s) throw()

-{

-  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);

-}

-

-void ConvertUInt32ToHex8Digits(UInt32 val, char *s) throw()

-{

-  s[8] = 0;

-  for (int i = 7; i >= 0; i--)

-  {

-    unsigned t = val & 0xF;

-    val >>= 4;

-    s[i] = GET_HEX_CHAR(t);;

-  }

-}

-

-/*

-void ConvertUInt32ToHex8Digits(UInt32 val, wchar_t *s)

-{

-  s[8] = 0;

-  for (int i = 7; i >= 0; i--)

-  {

-    unsigned t = val & 0xF;

-    val >>= 4;

-    s[i] = (wchar_t)(((t < 10) ? ('0' + t) : ('A' + (t - 10))));

-  }

-}

-*/

-

-void ConvertUInt32ToString(UInt32 val, wchar_t *s) throw()

-{

-  CONVERT_INT_TO_STR(wchar_t, 16);

-}

-

-void ConvertUInt64ToString(UInt64 val, wchar_t *s) throw()

-{

-  if (val <= (UInt32)0xFFFFFFFF)

-  {

-    ConvertUInt32ToString((UInt32)val, s);

-    return;

-  }

-  CONVERT_INT_TO_STR(wchar_t, 24);

-}

-

-void ConvertInt64ToString(Int64 val, char *s) throw()

-{

-  if (val < 0)

-  {

-    *s++ = '-';

-    val = -val;

-  }

-  ConvertUInt64ToString(val, s);

-}

-

-void ConvertInt64ToString(Int64 val, wchar_t *s) throw()

-{

-  if (val < 0)

-  {

-    *s++ = L'-';

-    val = -val;

-  }

-  ConvertUInt64ToString(val, s);

-}

-

-

-static void ConvertByteToHex2Digits(unsigned v, char *s) throw()

-{

-  s[0] = GetHexChar(v >> 4);

-  s[1] = GetHexChar(v & 0xF);

-}

-

-static void ConvertUInt16ToHex4Digits(UInt32 val, char *s) throw()

-{

-  ConvertByteToHex2Digits(val >> 8, s);

-  ConvertByteToHex2Digits(val & 0xFF, s + 2);

-}

-

-char *RawLeGuidToString(const Byte *g, char *s) throw()

-{

-  ConvertUInt32ToHex8Digits(GetUi32(g   ),  s);  s += 8;  *s++ = '-';

-  ConvertUInt16ToHex4Digits(GetUi16(g + 4), s);  s += 4;  *s++ = '-';

-  ConvertUInt16ToHex4Digits(GetUi16(g + 6), s);  s += 4;  *s++ = '-';

-  for (unsigned i = 0; i < 8; i++)

-  {

-    if (i == 2)

-      *s++ = '-';

-    ConvertByteToHex2Digits(g[8 + i], s);

-    s += 2;

-  }

-  *s = 0;

-  return s;

-}

-

-char *RawLeGuidToString_Braced(const Byte *g, char *s) throw()

-{

-  *s++ = '{';

-  s = RawLeGuidToString(g, s);

-  *s++ = '}';

-  *s = 0;

-  return s;

-}

+// Common/IntToString.cpp
+
+#include "StdAfx.h"
+
+#include "../../C/CpuArch.h"
+
+#include "IntToString.h"
+
+#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;
+
+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)
+}
+
+void ConvertUInt64ToOct(UInt64 val, char *s) throw()
+{
+  UInt64 v = val;
+  unsigned i;
+  for (i = 1;; i++)
+  {
+    v >>= 3;
+    if (v == 0)
+      break;
+  }
+  s[i] = 0;
+  do
+  {
+    unsigned t = (unsigned)(val & 0x7);
+    val >>= 3;
+    s[--i] = (char)('0' + t);
+  }
+  while (i);
+}
+
+
+#define GET_HEX_CHAR(t) ((char)(((t < 10) ? ('0' + t) : ('A' + (t - 10)))))
+
+static inline char GetHexChar(unsigned t) { return GET_HEX_CHAR(t); }
+
+
+void ConvertUInt32ToHex(UInt32 val, char *s) throw()
+{
+  UInt32 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);
+}
+
+
+void ConvertUInt64ToHex(UInt64 val, char *s) throw()
+{
+  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);
+}
+
+void ConvertUInt32ToHex8Digits(UInt32 val, char *s) throw()
+{
+  s[8] = 0;
+  for (int i = 7; i >= 0; i--)
+  {
+    unsigned t = val & 0xF;
+    val >>= 4;
+    s[i] = GET_HEX_CHAR(t);
+  }
+}
+
+/*
+void ConvertUInt32ToHex8Digits(UInt32 val, wchar_t *s)
+{
+  s[8] = 0;
+  for (int i = 7; i >= 0; i--)
+  {
+    unsigned t = val & 0xF;
+    val >>= 4;
+    s[i] = (wchar_t)(((t < 10) ? ('0' + t) : ('A' + (t - 10))));
+  }
+}
+*/
+
+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);
+}
+
+
+static void ConvertByteToHex2Digits(unsigned v, char *s) throw()
+{
+  s[0] = GetHexChar(v >> 4);
+  s[1] = GetHexChar(v & 0xF);
+}
+
+static void ConvertUInt16ToHex4Digits(UInt32 val, char *s) throw()
+{
+  ConvertByteToHex2Digits(val >> 8, s);
+  ConvertByteToHex2Digits(val & 0xFF, s + 2);
+}
+
+char *RawLeGuidToString(const Byte *g, char *s) throw()
+{
+  ConvertUInt32ToHex8Digits(GetUi32(g   ),  s);  s += 8;  *s++ = '-';
+  ConvertUInt16ToHex4Digits(GetUi16(g + 4), s);  s += 4;  *s++ = '-';
+  ConvertUInt16ToHex4Digits(GetUi16(g + 6), s);  s += 4;  *s++ = '-';
+  for (unsigned i = 0; i < 8; i++)
+  {
+    if (i == 2)
+      *s++ = '-';
+    ConvertByteToHex2Digits(g[8 + i], s);
+    s += 2;
+  }
+  *s = 0;
+  return s;
+}
+
+char *RawLeGuidToString_Braced(const Byte *g, char *s) throw()
+{
+  *s++ = '{';
+  s = RawLeGuidToString(g, s);
+  *s++ = '}';
+  *s = 0;
+  return s;
+}
diff --git a/CPP/Common/IntToString.h b/CPP/Common/IntToString.h
index 07b67c3..f4fc662 100644
--- a/CPP/Common/IntToString.h
+++ b/CPP/Common/IntToString.h
@@ -1,28 +1,30 @@
-// Common/IntToString.h

-

-#ifndef __COMMON_INT_TO_STRING_H

-#define __COMMON_INT_TO_STRING_H

-

-#include "MyTypes.h"

-

-void ConvertUInt32ToString(UInt32 value, char *s) throw();

-void ConvertUInt64ToString(UInt64 value, char *s) throw();

-

-void ConvertUInt32ToString(UInt32 value, wchar_t *s) throw();

-void ConvertUInt64ToString(UInt64 value, wchar_t *s) throw();

-

-void ConvertUInt64ToOct(UInt64 value, char *s) throw();

-

-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();

-

-void ConvertInt64ToString(Int64 value, char *s) throw();

-void ConvertInt64ToString(Int64 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();

-

-#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 ConvertUInt64ToOct(UInt64 value, char *s) throw();
+
+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();
+
+void ConvertInt64ToString(Int64 value, char *s) throw();
+void ConvertInt64ToString(Int64 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();
+
+#endif
diff --git a/CPP/Common/Lang.cpp b/CPP/Common/Lang.cpp
new file mode 100644
index 0000000..b0b4342
--- /dev/null
+++ b/CPP/Common/Lang.cpp
@@ -0,0 +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];
+}
diff --git a/CPP/Common/Lang.h b/CPP/Common/Lang.h
index e95de68..76d5418 100644
--- a/CPP/Common/Lang.h
+++ b/CPP/Common/Lang.h
@@ -1,23 +1,30 @@
-// Common/Lang.h

-

-#ifndef __COMMON_LANG_H

-#define __COMMON_LANG_H

-

-#include "MyString.h"

-

-class CLang

-{

-  wchar_t *_text;

-  CRecordVector<UInt32> _ids;

-  CRecordVector<UInt32> _offsets;

-

-  bool OpenFromString(const AString &s);

-public:

-  CLang(): _text(0) {}

-  ~CLang() { Clear(); }

-  bool Open(CFSTR fileName, const char *id);

-  void Clear() throw();

-  const wchar_t *Get(UInt32 id) const throw();

-};

-

-#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<UInt32> _ids;
+  CRecordVector<UInt32> _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 2fdde6d..e43dbc9 100644
--- a/CPP/Common/ListFileUtils.cpp
+++ b/CPP/Common/ListFileUtils.cpp
@@ -1,132 +1,150 @@
-// Common/ListFileUtils.cpp

-

-#include "StdAfx.h"

-

-#include "../../C/CpuArch.h"

-

-#include "../Windows/FileIO.h"

-

-#include "ListFileUtils.h"

-#include "MyBuffer.h"

-#include "StringConvert.h"

-#include "UTFConvert.h"

-

-static const char 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);

-}

-

-bool ReadNamesFromListFile2(CFSTR fileName, UStringVector &strings, UINT codePage, DWORD &lastError)

-{

-  lastError = 0;

-  NWindows::NFile::NIO::CInFile file;

-  if (!file.Open(fileName))

-  {

-    lastError = ::GetLastError();

-    return false;

-  }

-  UInt64 fileSize;

-  if (!file.GetLength(fileSize))

-  {

-    lastError = ::GetLastError();

-    return false;

-  }

-  if (fileSize >= ((UInt32)1 << 31) - 32)

-    return false;

-  UString u;

-  if (codePage == MY__CP_UTF16 || codePage == MY__CP_UTF16BE)

-  {

-    if ((fileSize & 1) != 0)

-      return false;

-    CByteArr buf((size_t)fileSize);

-    UInt32 processed;

-    if (!file.Read(buf, (UInt32)fileSize, processed))

-    {

-      lastError = ::GetLastError();

-      return false;

-    }

-    if (processed != fileSize)

-      return false;

-    file.Close();

-    unsigned num = (unsigned)fileSize / 2;

-    wchar_t *p = u.GetBuf(num);

-    if (codePage == MY__CP_UTF16)

-      for (unsigned i = 0; i < num; i++)

-      {

-        wchar_t c = GetUi16(buf + (size_t)i * 2);

-        if (c == 0)

-          return false;

-        p[i] = c;

-      }

-    else

-      for (unsigned i = 0; i < num; i++)

-      {

-        wchar_t c = (wchar_t)GetBe16(buf + (size_t)i * 2);

-        if (c == 0)

-          return false;

-        p[i] = c;

-      }

-    p[num] = 0;

-    u.ReleaseBuf_SetLen(num);

-  }

-  else

-  {

-    AString s;

-    char *p = s.GetBuf((unsigned)fileSize);

-    UInt32 processed;

-    if (!file.Read(p, (UInt32)fileSize, processed))

-    {

-      lastError = ::GetLastError();

-      return false;

-    }

-    if (processed != fileSize)

-      return false;

-    file.Close();

-    s.ReleaseBuf_CalcLen((unsigned)processed);

-    if (s.Len() != processed)

-      return false;

-    

-    // #ifdef CP_UTF8

-    if (codePage == CP_UTF8)

-    {

-      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 unsigned num = (unsigned)fileSize / 2;
+    wchar_t *p = u.GetBuf(num);
+    if (codePage == Z7_WIN_CP_UTF16)
+      for (unsigned i = 0; i < num; i++)
+      {
+        wchar_t c = GetUi16(buf + (size_t)i * 2);
+        if (c == 0)
+          return false;
+        p[i] = c;
+      }
+    else
+      for (unsigned i = 0; i < num; i++)
+      {
+        wchar_t c = (wchar_t)GetBe16(buf + (size_t)i * 2);
+        if (c == 0)
+          return false;
+        p[i] = c;
+      }
+    p[num] = 0;
+    u.ReleaseBuf_SetLen(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 a4f0d16..d43cc37 100644
--- a/CPP/Common/ListFileUtils.h
+++ b/CPP/Common/ListFileUtils.h
@@ -1,18 +1,18 @@
-// Common/ListFileUtils.h

-

-#ifndef __COMMON_LIST_FILE_UTILS_H

-#define __COMMON_LIST_FILE_UTILS_H

-

-#include "MyString.h"

-#include "MyTypes.h"

-

-#define MY__CP_UTF16   1200

-#define MY__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
new file mode 100644
index 0000000..8845e4a
--- /dev/null
+++ b/CPP/Common/LzFindPrepare.cpp
@@ -0,0 +1,7 @@
+// Sha256Prepare.cpp
+
+#include "StdAfx.h"
+
+#include "../../C/LzFind.h"
+
+static struct CLzFindPrepare { CLzFindPrepare() { LzFindPrepare(); } } g_CLzFindPrepare;
diff --git a/CPP/Common/MyBuffer.h b/CPP/Common/MyBuffer.h
index ae320ee..bc829f4 100644
--- a/CPP/Common/MyBuffer.h
+++ b/CPP/Common/MyBuffer.h
@@ -1,259 +1,286 @@
-// Common/MyBuffer.h

-

-#ifndef __COMMON_MY_BUFFER_H

-#define __COMMON_MY_BUFFER_H

-

-#include "Defs.h"

-

-/* 7-Zip now uses CBuffer only as CByteBuffer.

-   So there is no need to use MY_ARRAY_NEW macro in CBuffer code. */

-

-template <class T> class CBuffer

-{

-  T *_items;

-  size_t _size;

-

-public:

-  void Free()

-  {

-    if (_items)

-    {

-      delete []_items;

-      _items = 0;

-    }

-    _size = 0;

-  }

-  

-  CBuffer(): _items(0), _size(0) {};

-  CBuffer(size_t size): _items(0), _size(0) { _items = new T[size]; _size = size; }

-  CBuffer(const CBuffer &buffer): _items(0), _size(0)

-  {

-    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; }

-  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;

-  }

-

-  CBuffer& operator=(const CBuffer &buffer)

-  {

-    if (&buffer != this)

-      CopyFrom(buffer, buffer._size);

-    return *this;

-  }

-};

-

-template <class T>

-bool operator==(const CBuffer<T>& b1, const CBuffer<T>& 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 <class T>

-bool operator!=(const CBuffer<T>& b1, const CBuffer<T>& 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<char> CCharBuffer;

-// typedef CBuffer<wchar_t> CWCharBuffer;

-typedef CBuffer<unsigned char> CByteBuffer;

-

-

-template <class T> class CObjArray

-{

-protected:

-  T *_items;

-private:

-  // we disable copy

-  CObjArray(const CObjArray &buffer);

-  void operator=(const CObjArray &buffer);

-public:

-  void Free()

-  {

-    delete []_items;

-    _items = 0;

-  }

-  CObjArray(size_t size): _items(0)

-  {

-    if (size != 0)

-    {

-      MY_ARRAY_NEW(_items, T, size)

-      // _items = new T[size];

-    }

-  }

-  CObjArray(): _items(0) {};

-  ~CObjArray() { delete []_items; }

-  

-  operator       T *()       { return _items; }

-  operator const T *() const { return _items; }

-  

-  void Alloc(size_t newSize)

-  {

-    delete []_items;

-    _items = 0;

-    MY_ARRAY_NEW(_items, T, newSize)

-    // _items = new T[newSize];

-  }

-};

-

-typedef CObjArray<unsigned char> CByteArr;

-typedef CObjArray<bool> CBoolArr;

-typedef CObjArray<int> CIntArr;

-typedef CObjArray<unsigned> CUIntArr;

-

-

-template <class T> class CObjArray2

-{

-  T *_items;

-  unsigned _size;

-

-  // we disable copy

-  CObjArray2(const CObjArray2 &buffer);

-  void operator=(const CObjArray2 &buffer);

-public:

-  

-  void Free()

-  {

-    delete []_items;

-    _items = 0;

-    _size = 0;

-  }

-  CObjArray2(): _items(0), _size(0) {};

-  /*

-  CObjArray2(const CObjArray2 &buffer): _items(0), _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(0), _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)

-    {

-      MY_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 <string.h>
+
+#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 T> 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; }
+  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 <class T>
+bool operator==(const CBuffer<T>& b1, const CBuffer<T>& 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 <class T>
+bool operator!=(const CBuffer<T>& b1, const CBuffer<T>& 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<char> CCharBuffer;
+// typedef CBuffer<wchar_t> CWCharBuffer;
+typedef CBuffer<unsigned char> CByteBuffer;
+
+
+class CByteBuffer_Wipe: public CByteBuffer
+{
+  Z7_CLASS_NO_COPY(CByteBuffer_Wipe)
+public:
+  // CByteBuffer_Wipe(): CBuffer<unsigned char>() {}
+  CByteBuffer_Wipe(size_t size): CBuffer<unsigned char>(size) {}
+  ~CByteBuffer_Wipe() { Wipe(); }
+};
+
+
+
+template <class T> 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; }
+  
+  void Alloc(size_t newSize)
+  {
+    delete []_items;
+    _items = NULL;
+    Z7_ARRAY_NEW(_items, T, newSize)
+    // _items = new T[newSize];
+  }
+};
+
+typedef CObjArray<unsigned char> CByteArr;
+typedef CObjArray<bool> CBoolArr;
+typedef CObjArray<int> CIntArr;
+typedef CObjArray<unsigned> CUIntArr;
+
+
+template <class T> 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 10edcb1..23394f8 100644
--- a/CPP/Common/MyBuffer2.h
+++ b/CPP/Common/MyBuffer2.h
@@ -1,100 +1,164 @@
-// Common/MyBuffer2.h

-

-#ifndef __COMMON_MY_BUFFER2_H

-#define __COMMON_MY_BUFFER2_H

-

-#include "../../C/Alloc.h"

-

-#include "MyTypes.h"

-

-class CMidBuffer

-{

-  Byte *_data;

-  size_t _size;

-

-  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 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 CAlignedBuffer

-{

-  Byte *_data;

-  size_t _size;

-

-  CLASS_NO_COPY(CAlignedBuffer)

-

-public:

-  CAlignedBuffer(): _data(NULL), _size(0) {}

-  ~CAlignedBuffer()

-  {

-    ISzAlloc_Free(&g_AlignedAlloc, _data);

-  }

-

-  void Free()

-  {

-    ISzAlloc_Free(&g_AlignedAlloc, _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)

-    {

-      ISzAlloc_Free(&g_AlignedAlloc, _data);

-      _size = 0;

-      _data = NULL;

-      _data = (Byte *)ISzAlloc_Alloc(&g_AlignedAlloc, size);

-      if (_data)

-        _size = size;

-    }

-  }

-

-  void AllocAtLeast(size_t size)

-  {

-    if (!_data || size > _size)

-    {

-      ISzAlloc_Free(&g_AlignedAlloc, _data);

-      _size = 0;

-      _data = NULL;

-      _data = (Byte *)ISzAlloc_Alloc(&g_AlignedAlloc, size);

-      if (_data)

-        _size = size;

-    }

-  }

-};

-

-

-#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()
+  {
+    ISzAlloc_Free(&g_AlignedAlloc, _data);
+  }
+
+  CAlignedBuffer1(size_t size)
+  {
+    _data = NULL;
+    _data = (Byte *)ISzAlloc_Alloc(&g_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()
+  {
+    ISzAlloc_Free(&g_AlignedAlloc, _data);
+  }
+
+  CAlignedBuffer(size_t size): _size(0)
+  {
+    _data = NULL;
+    _data = (Byte *)ISzAlloc_Alloc(&g_AlignedAlloc, size);
+    if (!_data)
+      throw 1;
+    _size = size;
+  }
+
+  void Free()
+  {
+    ISzAlloc_Free(&g_AlignedAlloc, _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)
+    {
+      ISzAlloc_Free(&g_AlignedAlloc, _data);
+      _size = 0;
+      _data = NULL;
+      _data = (Byte *)ISzAlloc_Alloc(&g_AlignedAlloc, size);
+      if (_data)
+        _size = size;
+    }
+  }
+
+  void AllocAtLeast(size_t size)
+  {
+    if (!_data || size > _size)
+    {
+      ISzAlloc_Free(&g_AlignedAlloc, _data);
+      _size = 0;
+      _data = NULL;
+      _data = (Byte *)ISzAlloc_Alloc(&g_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 ca49ead..65c4330 100644
--- a/CPP/Common/MyCom.h
+++ b/CPP/Common/MyCom.h
@@ -1,277 +1,509 @@
-// MyCom.h

-

-#ifndef __MY_COM_H

-#define __MY_COM_H

-

-#include "MyWindows.h"

-

-#ifndef RINOK

-#define RINOK(x) { HRESULT __result_ = (x); if (__result_ != S_OK) return __result_; }

-#endif

-

-template <class T>

-class CMyComPtr

-{

-  T* _p;

-public:

-  CMyComPtr(): _p(NULL) {}

-  CMyComPtr(T* p) throw() { if ((_p = p) != NULL) p->AddRef(); }

-  CMyComPtr(const CMyComPtr<T>& 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& 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<T>& 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 <class Q>

-  HRESULT QueryInterface(REFGUID iid, Q** pp) const throw()

-  {

-    return _p->QueryInterface(iid, (void**)pp);

-  }

-};

-

-//////////////////////////////////////////////////////////

-

-inline HRESULT StringToBstr(LPCOLESTR src, BSTR *bstr)

-{

-  *bstr = ::SysAllocString(src);

-  return (*bstr) ? S_OK : E_OUTOFMEMORY;

-}

-

-class CMyComBSTR

-{

-  BSTR m_str;

-

-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; }

-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;

-  }

-};

-

-

-

-/*

-  If CMyUnknownImp doesn't use virtual destructor, the code size is smaller.

-  But if some class_1 derived from CMyUnknownImp

-    uses MY_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.

-

-  Also you can use virtual ~CMyUnknownImp(), if you want to disable warning

-    "class has virtual functions, but destructor is not virtual".

-*/

-

-class CMyUnknownImp

-{

-public:

-  ULONG __m_RefCount;

-  CMyUnknownImp(): __m_RefCount(0) {}

-

-  // virtual

-  ~CMyUnknownImp() {}

-};

-

-

-

-#define MY_QUERYINTERFACE_BEGIN STDMETHOD(QueryInterface) \

-(REFGUID iid, void **outObject) throw() { *outObject = NULL;

-

-#define MY_QUERYINTERFACE_ENTRY(i) else if (iid == IID_ ## i) \

-    { *outObject = (void *)(i *)this; }

-

-#define MY_QUERYINTERFACE_ENTRY_UNKNOWN(i) if (iid == IID_IUnknown) \

-    { *outObject = (void *)(IUnknown *)(i *)this; }

-

-#define MY_QUERYINTERFACE_BEGIN2(i) MY_QUERYINTERFACE_BEGIN \

-    MY_QUERYINTERFACE_ENTRY_UNKNOWN(i) \

-    MY_QUERYINTERFACE_ENTRY(i)

-

-#define MY_QUERYINTERFACE_END else return E_NOINTERFACE; ++__m_RefCount; /* AddRef(); */ return S_OK; }

-

-#define MY_ADDREF_RELEASE \

-STDMETHOD_(ULONG, AddRef)() throw() { return ++__m_RefCount; } \

-STDMETHOD_(ULONG, Release)() { if (--__m_RefCount != 0)  \

-  return __m_RefCount; delete this; return 0; }

-

-#define MY_UNKNOWN_IMP_SPEC(i) \

-  MY_QUERYINTERFACE_BEGIN \

-  i \

-  MY_QUERYINTERFACE_END \

-  MY_ADDREF_RELEASE

-

-

-#define MY_UNKNOWN_IMP MY_QUERYINTERFACE_BEGIN \

-  MY_QUERYINTERFACE_ENTRY_UNKNOWN(IUnknown) \

-  MY_QUERYINTERFACE_END \

-  MY_ADDREF_RELEASE

-

-#define MY_UNKNOWN_IMP1(i) MY_UNKNOWN_IMP_SPEC( \

-  MY_QUERYINTERFACE_ENTRY_UNKNOWN(i) \

-  MY_QUERYINTERFACE_ENTRY(i) \

-  )

-

-#define MY_UNKNOWN_IMP2(i1, i2) MY_UNKNOWN_IMP_SPEC( \

-  MY_QUERYINTERFACE_ENTRY_UNKNOWN(i1) \

-  MY_QUERYINTERFACE_ENTRY(i1) \

-  MY_QUERYINTERFACE_ENTRY(i2) \

-  )

-

-#define MY_UNKNOWN_IMP3(i1, i2, i3) MY_UNKNOWN_IMP_SPEC( \

-  MY_QUERYINTERFACE_ENTRY_UNKNOWN(i1) \

-  MY_QUERYINTERFACE_ENTRY(i1) \

-  MY_QUERYINTERFACE_ENTRY(i2) \

-  MY_QUERYINTERFACE_ENTRY(i3) \

-  )

-

-#define MY_UNKNOWN_IMP4(i1, i2, i3, i4) MY_UNKNOWN_IMP_SPEC( \

-  MY_QUERYINTERFACE_ENTRY_UNKNOWN(i1) \

-  MY_QUERYINTERFACE_ENTRY(i1) \

-  MY_QUERYINTERFACE_ENTRY(i2) \

-  MY_QUERYINTERFACE_ENTRY(i3) \

-  MY_QUERYINTERFACE_ENTRY(i4) \

-  )

-

-#define MY_UNKNOWN_IMP5(i1, i2, i3, i4, i5) MY_UNKNOWN_IMP_SPEC( \

-  MY_QUERYINTERFACE_ENTRY_UNKNOWN(i1) \

-  MY_QUERYINTERFACE_ENTRY(i1) \

-  MY_QUERYINTERFACE_ENTRY(i2) \

-  MY_QUERYINTERFACE_ENTRY(i3) \

-  MY_QUERYINTERFACE_ENTRY(i4) \

-  MY_QUERYINTERFACE_ENTRY(i5) \

-  )

-

-#define MY_UNKNOWN_IMP6(i1, i2, i3, i4, i5, i6) MY_UNKNOWN_IMP_SPEC( \

-  MY_QUERYINTERFACE_ENTRY_UNKNOWN(i1) \

-  MY_QUERYINTERFACE_ENTRY(i1) \

-  MY_QUERYINTERFACE_ENTRY(i2) \

-  MY_QUERYINTERFACE_ENTRY(i3) \

-  MY_QUERYINTERFACE_ENTRY(i4) \

-  MY_QUERYINTERFACE_ENTRY(i5) \

-  MY_QUERYINTERFACE_ENTRY(i6) \

-  )

-

-#define MY_UNKNOWN_IMP7(i1, i2, i3, i4, i5, i6, i7) MY_UNKNOWN_IMP_SPEC( \

-  MY_QUERYINTERFACE_ENTRY_UNKNOWN(i1) \

-  MY_QUERYINTERFACE_ENTRY(i1) \

-  MY_QUERYINTERFACE_ENTRY(i2) \

-  MY_QUERYINTERFACE_ENTRY(i3) \

-  MY_QUERYINTERFACE_ENTRY(i4) \

-  MY_QUERYINTERFACE_ENTRY(i5) \

-  MY_QUERYINTERFACE_ENTRY(i6) \

-  MY_QUERYINTERFACE_ENTRY(i7) \

-  )

-

-const HRESULT 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 T>
+class CMyComPtr
+{
+  T* _p;
+public:
+  CMyComPtr(): _p(NULL) {}
+  CMyComPtr(T* p) throw() { if ((_p = p) != NULL) p->AddRef(); }
+  CMyComPtr(const CMyComPtr<T>& 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& 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<T>& 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 <class Q>
+  HRESULT QueryInterface(REFGUID iid, Q** pp) const throw()
+  {
+    // if (*pp) throw 20220216; // for debug
+    return _p->QueryInterface(iid, (void**)pp);
+  }
+};
+
+#define Z7_DECL_CMyComPtr_QI_FROM(i, v, unk) \
+  CMyComPtr<i> 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_QI_END \
+  else return E_NOINTERFACE; \
+  ++_m_RefCount; /* AddRef(); */ return S_OK; }
+
+#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_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
diff --git a/CPP/Common/MyException.h b/CPP/Common/MyException.h
index cd9fe69..06fbdea 100644
--- a/CPP/Common/MyException.h
+++ b/CPP/Common/MyException.h
@@ -1,14 +1,14 @@
-// Common/Exception.h

-

-#ifndef __COMMON_EXCEPTION_H

-#define __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 e0359e2..ab9993b 100644
--- a/CPP/Common/MyGuidDef.h
+++ b/CPP/Common/MyGuidDef.h
@@ -1,54 +1,63 @@
-// Common/MyGuidDef.h

-

-#ifndef GUID_DEFINED

-#define GUID_DEFINED

-

-#include "MyTypes.h"

-

-typedef struct {

-  UInt32 Data1;

-  UInt16 Data2;

-  UInt16 Data3;

-  unsigned char Data4[8];

-} GUID;

-

-#ifdef __cplusplus

-#define REFGUID const GUID &

-#else

-#define REFGUID const GUID *

-#endif

-

-#define REFCLSID REFGUID

-#define REFIID REFGUID

-

-#ifdef __cplusplus

-inline int operator==(REFGUID g1, REFGUID g2)

-{

-  for (int i = 0; i < (int)sizeof(g1); i++)

-    if (((unsigned char *)&g1)[i] != ((unsigned char *)&g2)[i])

-      return 0;

-  return 1;

-}

-inline int operator!=(REFGUID g1, REFGUID g2) { return !(g1 == g2); }

-#endif

-

-#ifdef __cplusplus

-  #define MY_EXTERN_C extern "C"

-#else

-  #define MY_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) \

-    MY_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) \

-    MY_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;
+  unsigned char 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 unsigned char *)&g1)[i] != ((const unsigned char *)&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 79fea19..3745c79 100644
--- a/CPP/Common/MyInitGuid.h
+++ b/CPP/Common/MyInitGuid.h
@@ -1,45 +1,57 @@
-// Common/MyInitGuid.h

-

-#ifndef __COMMON_MY_INITGUID_H

-#define __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

-*/

-

-#ifdef _WIN32

-

-#ifdef UNDER_CE

-#include <basetyps.h>

-#endif

-

-#include <initguid.h>

-

-#ifdef UNDER_CE

-DEFINE_GUID(IID_IUnknown,

-0x00000000, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);

-#endif

-

-#else

-

-#define INITGUID

-#include "MyGuidDef.h"

-DEFINE_GUID(IID_IUnknown,

-0x00000000, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);

-

-#endif

-

-

-#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 <objbase.h> before <initguid.h>,
+   but it doesn't work in new msvc.
+   So we include full "MyWindows.h" instead of <objbase.h> */
+// #include <objbase.h>
+#include "MyWindows.h"
+
+#ifdef _WIN32
+
+#ifdef __clang__
+  // #pragma GCC diagnostic ignored "-Wmissing-variable-declarations"
+#endif
+
+#ifdef UNDER_CE
+#include <basetyps.h>
+#endif
+
+// for vc6 without sdk we must define INITGUID here
+#define INITGUID
+#include <initguid.h>
+
+#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 b4e7605..a8454d7 100644
--- a/CPP/Common/MyLinux.h
+++ b/CPP/Common/MyLinux.h
@@ -1,42 +1,75 @@
-// MyLinux.h

-

-#ifndef __MY_LIN_LINUX_H

-#define __MY_LIN_LINUX_H

-

-#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

-

-#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
new file mode 100644
index 0000000..0a200f0
--- /dev/null
+++ b/CPP/Common/MyMap.cpp
@@ -0,0 +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] = 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] = Nodes.Size();
+
+      Nodes.Add(e2);
+      return false;
+    }
+    cur = (unsigned)n.Keys[bit];
+  }
+}
diff --git a/CPP/Common/MyMap.h b/CPP/Common/MyMap.h
new file mode 100644
index 0000000..9ca5566
--- /dev/null
+++ b/CPP/Common/MyMap.h
@@ -0,0 +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<CNode> 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 bf62303..51c1c3b 100644
--- a/CPP/Common/MyString.cpp
+++ b/CPP/Common/MyString.cpp
@@ -1,1659 +1,1859 @@
-// Common/MyString.cpp

-

-#include "StdAfx.h"

-

-#ifdef _WIN32

-#include <wchar.h>

-#else

-#include <ctype.h>

-#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 (;;)

-  {

-    char c = *s;

-    if (c == 0)

-      return;

-    *s++ = MyCharUpper_Ascii(c);

-  }

-}

-

-void MyStringUpper_Ascii(wchar_t *s) throw()

-{

-  for (;;)

-  {

-    wchar_t c = *s;

-    if (c == 0)

-      return;

-    *s++ = MyCharUpper_Ascii(c);

-  }

-}

-*/

-

-void MyStringLower_Ascii(char *s) throw()

-{

-  for (;;)

-  {

-    char c = *s;

-    if (c == 0)

-      return;

-    *s++ = MyCharLower_Ascii(c);

-  }

-}

-

-void MyStringLower_Ascii(wchar_t *s) throw()

-{

-  for (;;)

-  {

-    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 (;;)

-  {

-    unsigned char c2 = (unsigned char)*s2++; if (c2 == 0) return true;

-    unsigned char c1 = (unsigned char)*s1++; if (c1 != c2) return false;

-  }

-}

-

-bool StringsAreEqualNoCase(const wchar_t *s1, const wchar_t *s2) throw()

-{

-  for (;;)

-  {

-    wchar_t c1 = *s1++;

-    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 (;;)

-  {

-    char c2 = *s++;

-    if (c2 == 0)

-      return true;

-    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 (;;)

-  {

-    char c2 = *s++;

-    if (c2 == 0)

-      return true;

-    wchar_t c1 = *s1++;

-    if (MyCharLower_Ascii(c1) != (unsigned char)MyCharLower_Ascii(c2))

-      return false;

-  }

-}

-

-bool StringsAreEqual_Ascii(const wchar_t *u, const char *a) throw()

-{

-  for (;;)

-  {

-    unsigned char c = *a;

-    if (c != *u)

-      return false;

-    if (c == 0)

-      return true;

-    a++;

-    u++;

-  }

-}

-

-bool StringsAreEqualNoCase_Ascii(const char *s1, const char *s2) throw()

-{

-  for (;;)

-  {

-    char c1 = *s1++;

-    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 (;;)

-  {

-    wchar_t c1 = *s1++;

-    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 (;;)

-  {

-    wchar_t c1 = *s1++;

-    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 (;;)

-  {

-    wchar_t c2 = *s2++; if (c2 == 0) return true;

-    wchar_t c1 = *s1++; if (c1 != c2) return false;

-  }

-}

-

-bool IsString1PrefixedByString2(const wchar_t *s1, const char *s2) throw()

-{

-  for (;;)

-  {

-    unsigned char c2 = (unsigned char)(*s2++); if (c2 == 0) return true;

-    wchar_t c1 = *s1++; if (c1 != c2) return false;

-  }

-}

-

-bool IsString1PrefixedByString2_NoCase_Ascii(const wchar_t *s1, const char *s2) throw()

-{

-  for (;;)

-  {

-    char c2 = *s2++; if (c2 == 0) return true;

-    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 (;;)

-  {

-    wchar_t c2 = *s2++; if (c2 == 0) return true;

-    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 (;;)

-  {

-    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;

-  }

-}

-

-/*

-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

-

-void AString::ReAlloc(unsigned newLimit)

-{

-  if (newLimit < _len || newLimit >= k_Alloc_Len_Limit) throw 20130220;

-  // MY_STRING_REALLOC(_chars, char, newLimit + 1, _len + 1);

-  char *newBuf = MY_STRING_NEW_char(newLimit + 1);

-  memcpy(newBuf, _chars, (size_t)(_len + 1));

-  MY_STRING_DELETE(_chars);

-  _chars = newBuf;

-  _limit = newLimit;

-}

-

-void AString::ReAlloc2(unsigned newLimit)

-{

-  if (newLimit >= k_Alloc_Len_Limit) throw 20130220;

-  // MY_STRING_REALLOC(_chars, char, newLimit + 1, 0);

-  char *newBuf = MY_STRING_NEW_char(newLimit + 1);

-  newBuf[0] = 0;

-  MY_STRING_DELETE(_chars);

-  _chars = newBuf;

-  _limit = newLimit;

-}

-

-void AString::SetStartLen(unsigned len)

-{

-  _chars = 0;

-  _chars = MY_STRING_NEW_char(len + 1);

-  _len = len;

-  _limit = len;

-}

-

-void AString::Grow_1()

-{

-  unsigned next = _len;

-  next += next / 2;

-  next += 16;

-  next &= ~(unsigned)15;

-  ReAlloc(next - 1);

-}

-

-void AString::Grow(unsigned n)

-{

-  unsigned freeSize = _limit - _len;

-  if (n <= freeSize)

-    return;

-  

-  unsigned next = _len + n;

-  next += next / 2;

-  next += 16;

-  next &= ~(unsigned)15;

-  ReAlloc(next - 1);

-}

-

-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 = 0;

-  _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(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(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(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(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_Space() { operator+=(' '); }

-void AString::Add_Space_if_NotEmpty() { if (!IsEmpty()) Add_Space(); }

-void AString::Add_LF() { operator+=('\n'); }

-

-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)

-{

-  char sz[16];

-  ConvertUInt32ToString(v, sz);

-  (*this) += sz;

-}

-

-void AString::SetFrom(const char *s, unsigned len) // no check

-{

-  if (len > _limit)

-  {

-    char *newBuf = MY_STRING_NEW_char(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_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 (;;)

-  {

-    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, 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;

-  unsigned oldLen = oldString.Len();

-  unsigned newLen = newString.Len();

-  // unsigned number = 0;

-  int pos = 0;

-  while ((unsigned)pos < _len)

-  {

-    pos = Find(oldString, pos);

-    if (pos < 0)

-      break;

-    Delete(pos, oldLen);

-    Insert(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)

-{

-  if (newLimit < _len || newLimit >= k_Alloc_Len_Limit) throw 20130221;

-  // MY_STRING_REALLOC(_chars, wchar_t, newLimit + 1, _len + 1);

-  wchar_t *newBuf = MY_STRING_NEW_wchar_t(newLimit + 1);

-  wmemcpy(newBuf, _chars, _len + 1);

-  MY_STRING_DELETE(_chars);

-  _chars = newBuf;

-  _limit = newLimit;

-}

-

-void UString::ReAlloc2(unsigned newLimit)

-{

-  if (newLimit >= k_Alloc_Len_Limit) throw 20130221;

-  // MY_STRING_REALLOC(_chars, wchar_t, newLimit + 1, 0);

-  wchar_t *newBuf = MY_STRING_NEW_wchar_t(newLimit + 1);

-  newBuf[0] = 0;

-  MY_STRING_DELETE(_chars);

-  _chars = newBuf;

-  _limit = newLimit;

-}

-

-void UString::SetStartLen(unsigned len)

-{

-  _chars = 0;

-  _chars = MY_STRING_NEW_wchar_t(len + 1);

-  _len = len;

-  _limit = len;

-}

-

-void UString::Grow_1()

-{

-  unsigned next = _len;

-  next += next / 2;

-  next += 16;

-  next &= ~(unsigned)15;

-  ReAlloc(next - 1);

-}

-

-void UString::Grow(unsigned n)

-{

-  unsigned freeSize = _limit - _len;

-  if (n <= freeSize)

-    return;

-  

-  unsigned next = _len + n;

-  next += next / 2;

-  next += 16;

-  next &= ~(unsigned)15;

-  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 = 0;

-  _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)

-{

-  unsigned len = MyStringLen(s);

-  SetStartLen(len);

-  wmemcpy(_chars, s, len + 1);

-}

-

-UString::UString(const char *s)

-{

-  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 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(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(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)

-  {

-    wchar_t *newBuf = MY_STRING_NEW_wchar_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(BSTR s)

-{

-  unsigned len = ::SysStringLen(s);

-  if (len > _limit)

-  {

-    wchar_t *newBuf = MY_STRING_NEW_wchar_t(len + 1);

-    MY_STRING_DELETE(_chars);

-    _chars = newBuf;

-    _limit = len;

-  }

-  _len = len;

-  // if (s)

-    wmemcpy(_chars, s, len + 1);

-}

-

-UString &UString::operator=(const char *s)

-{

-  unsigned len = MyStringLen(s);

-  if (len > _limit)

-  {

-    wchar_t *newBuf = MY_STRING_NEW_wchar_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_Space() { operator+=(L' '); }

-void UString::Add_Space_if_NotEmpty() { if (!IsEmpty()) Add_Space(); }

-

-void UString::Add_LF()

-{

-  if (_limit == _len)

-    Grow_1();

-  unsigned len = _len;

-  wchar_t *chars = _chars;

-  chars[len++] = L'\n';

-  chars[len] = 0;

-  _len = len;

-}

-

-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)

-{

-  char sz[16];

-  ConvertUInt32ToString(v, sz);

-  (*this) += sz;

-}

-

-

-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 - 1;

-  for (;;)

-  {

-    if (*p == c)

-      return (int)(p - _chars);

-    if (p == _chars)

-      return -1;

-    p--;

-  }

-}

-

-int UString::ReverseFind_PathSepar() const throw()

-{

-  if (_len == 0)

-    return -1;

-  const wchar_t *p = _chars + _len - 1;

-  for (;;)

-  {

-    wchar_t c = *p;

-    if (IS_PATH_SEPAR(c))

-      return (int)(p - _chars);

-    if (p == _chars)

-      return -1;

-    p--;

-  }

-}

-

-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(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, 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, pos);

-    if (pos < 0)

-      break;

-    Delete(pos, oldLen);

-    Insert(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)

-{

-  if (newLimit >= k_Alloc_Len_Limit) throw 20130221;

-  // MY_STRING_REALLOC(_chars, wchar_t, newLimit + 1, 0);

-  _chars = MY_STRING_NEW_wchar_t(newLimit + 1);

-}

-

-void UString2::SetStartLen(unsigned len)

-{

-  _chars = 0;

-  _chars = MY_STRING_NEW_wchar_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)

-{

-  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(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(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(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));

-}

-*/

-

-static inline UINT GetCurrentCodePage()

-{

-  #if defined(UNDER_CE) || !defined(_WIN32)

-  return CP_ACP;

-  #else

-  return ::AreFileApisANSI() ? CP_ACP : CP_OEMCP;

-  #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

-

-#else

-

-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

+// Common/MyString.cpp
+
+#include "StdAfx.h"
+
+#ifdef _WIN32
+#include <wchar.h>
+#else
+#include <ctype.h>
+#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 (;;)
+  {
+    char c = *s;
+    if (c == 0)
+      return;
+    *s++ = MyCharUpper_Ascii(c);
+  }
+}
+
+void MyStringUpper_Ascii(wchar_t *s) throw()
+{
+  for (;;)
+  {
+    wchar_t c = *s;
+    if (c == 0)
+      return;
+    *s++ = MyCharUpper_Ascii(c);
+  }
+}
+*/
+
+void MyStringLower_Ascii(char *s) throw()
+{
+  for (;;)
+  {
+    char c = *s;
+    if (c == 0)
+      return;
+    *s++ = MyCharLower_Ascii(c);
+  }
+}
+
+void MyStringLower_Ascii(wchar_t *s) throw()
+{
+  for (;;)
+  {
+    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 unsigned char c2 = (unsigned char)*s2++; if (c2 == 0) return true;
+    const unsigned char c1 = (unsigned char)*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)
+
+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;
+}
+
+void AString::ReAlloc2(unsigned newLimit)
+{
+  if (newLimit > k_Alloc_Len_Limit) throw 20130220;
+  // 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;
+}
+
+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 20130220;
+  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 20130220;
+  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_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+=('-'); }
+
+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)
+  {
+    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_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;
+  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 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)
+{
+  if (newLimit > k_Alloc_Len_Limit) throw 20130221;
+  // 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;
+}
+
+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 20130220;
+  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 20130220;
+  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)
+  {
+    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 < 0x10000)
+      {
+        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 < 0x10000)
+      {
+        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_Dot() { operator+=(L'.'); }
+void UString::Add_Space() { operator+=(L' '); }
+void UString::Add_Space_if_NotEmpty() { if (!IsEmpty()) Add_Space(); }
+
+void UString::Add_LF()
+{
+  if (_limit == _len)
+    Grow_1();
+  unsigned len = _len;
+  wchar_t *chars = _chars;
+  chars[len++] = L'\n';
+  chars[len] = 0;
+  _len = len;
+}
+
+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
+  if (newLimit > k_Alloc_Len_Limit) throw 20130221;
+  // 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 += (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 45cea98..e5ce18a 100644
--- a/CPP/Common/MyString.h
+++ b/CPP/Common/MyString.h
@@ -1,868 +1,1064 @@
-// Common/String.h

-

-#ifndef __COMMON_STRING_H

-#define __COMMON_STRING_H

-

-#include <string.h>

-

-#ifndef _WIN32

-#include <wctype.h>

-#include <wchar.h>

-#endif

-

-#include "MyWindows.h"

-#include "MyTypes.h"

-#include "MyVector.h"

-

-

-#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 (;;)

-  {

-    char c = *src;

-    *dest = c;

-    if (c == 0)

-      return dest;

-    src++;

-    dest++;

-  }

-}

-

-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)

-{

-  MyStringCopy(dest + MyStringLen(dest), src);

-}

-

-

-/*

-inline wchar_t *MyWcpCpy(wchar_t *dest, const wchar_t *src)

-{

-  for (;;)

-  {

-    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(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 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 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);

-  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)

-

-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; }

-  const char *Ptr() const { return _chars; }

-  const char *Ptr(unsigned pos) const { return _chars + 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);

-

-  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;

-  }

-  

-  void Add_Space();

-  void Add_Space_if_NotEmpty();

-  void Add_OptSpaced(const char *s);

-  void Add_LF();

-  void Add_PathSepar() { operator+=(CHAR_PATH_SEPARATOR); }

-

-  AString &operator+=(const char *s);

-  AString &operator+=(const AString &s);

-

-  void Add_UInt32(UInt32 v);

-

-  void SetFrom(const char *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

-  {

-    int pos = FindCharPosInString(_chars + startIndex, c);

-    return pos < 0 ? -1 : (int)startIndex + pos;

-  }

-  

-  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;

-    }

-  }

-};

-

-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)

-

-public:

-  UString();

-  explicit UString(wchar_t c);

-  explicit UString(char c);

-  explicit UString(const char *s);

-  // 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; }

-  const wchar_t *Ptr() const { return _chars; }

-  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(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(BSTR s);

-  UString &operator=(const char *s);

-  UString &operator=(const AString &s) { return operator=(s.Ptr()); }

-

-  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;

-  }

-

-  UString &operator+=(char c) { return (*this)+=((wchar_t)(unsigned char)c); }

-

-  void Add_Space();

-  void Add_Space_if_NotEmpty();

-  void Add_LF();

-  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);

-

-  UString Mid(unsigned startIndex, unsigned count) const { return UString(count, _chars + startIndex); }

-  UString Left(unsigned count) const { return UString(count, *this); }

-

-  // 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(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(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;

-    }

-  }

-};

-

-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(wchar_t c);

-

-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<AString> AStringVector;

-typedef CObjectVector<UString> UStringVector;

-

-#ifdef _UNICODE

-  typedef UString CSysString;

-#else

-  typedef AString CSysString;

-#endif

-

-typedef CObjectVector<CSysString> CSysStringVector;

-

-

-// ---------- FString ----------

-

-#ifdef _WIN32

-  #define USE_UNICODE_FSTRING

-#endif

-

-#ifdef USE_UNICODE_FSTRING

-

-  #define __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

-

-  #define __FTEXT(quote) quote

-

-  typedef char FChar;

-  typedef AString FString;

-

-  UString fs2us(const FChar *s);

-  UString fs2us(const FString &s);

-  FString us2fs(const wchar_t *s);

-  #define fas2fs(_x_) (_x_)

-  #define fs2fas(_x_) (_x_)

-

-#endif

-

-#define FTEXT(quote) __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<FString> FStringVector;

-

-#endif

+// Common/MyString.h
+
+#ifndef ZIP7_INC_COMMON_MY_STRING_H
+#define ZIP7_INC_COMMON_MY_STRING_H
+
+#include <string.h>
+
+#ifndef _WIN32
+#include <wctype.h>
+#include <wchar.h>
+#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);
+  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);
+
+  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;
+  }
+  
+  void Add_Space();
+  void Add_Space_if_NotEmpty();
+  void Add_OptSpaced(const char *s);
+  void Add_LF();
+  void Add_Slash();
+  void Add_Dot();
+  void Add_Minus();
+  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(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()); }
+
+  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;
+  }
+
+  UString &operator+=(char c) { return (*this)+=((wchar_t)(unsigned char)c); }
+
+  void Add_Space();
+  void Add_Space_if_NotEmpty();
+  void Add_LF();
+  void Add_Dot();
+  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<AString> AStringVector;
+typedef CObjectVector<UString> UStringVector;
+
+#ifdef _UNICODE
+  typedef UString CSysString;
+#else
+  typedef AString CSysString;
+#endif
+
+typedef CObjectVector<CSysString> 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<FString> 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.h>
+  // 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 6e73aca..8f44f67 100644
--- a/CPP/Common/MyTypes.h
+++ b/CPP/Common/MyTypes.h
@@ -1,35 +1,37 @@
-// Common/MyTypes.h

-

-#ifndef __COMMON_MY_TYPES_H

-#define __COMMON_MY_TYPES_H

-

-#include "../../C/7zTypes.h"

-

-typedef int HRes;

-

-struct CBoolPair

-{

-  bool Val;

-  bool Def;

-

-  CBoolPair(): Val(false), Def(false) {}

-  

-  void Init()

-  {

-    Val = false;

-    Def = false;

-  }

-

-  void SetTrueTrue()

-  {

-    Val = true;

-    Def = true;

-  }

-};

-

-#define CLASS_NO_COPY(cls) \

-  private: \

-  cls(const cls &); \

-  cls &operator=(const cls &);

-

-#endif

+// Common/MyTypes.h
+
+#ifndef ZIP7_INC_COMMON_MY_TYPES_H
+#define ZIP7_INC_COMMON_MY_TYPES_H
+
+#include "../../C/7zTypes.h"
+#include "Common.h"
+
+typedef int 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 b1d476f..75ee96f 100644
--- a/CPP/Common/MyUnknown.h
+++ b/CPP/Common/MyUnknown.h
@@ -1,17 +1,8 @@
-// MyUnknown.h

-

-#ifndef __MY_UNKNOWN_H

-#define __MY_UNKNOWN_H

-

-#include "MyWindows.h"

-

-/*

-#ifdef _WIN32

-#include <basetyps.h>

-#include <unknwn.h>

-#else

-#include "MyWindows.h"

-#endif

-*/

-  

-#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 9a6d1d5..0b1baf4 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 21125fa..9ee7105 100644
--- a/CPP/Common/MyVector.h
+++ b/CPP/Common/MyVector.h
@@ -1,634 +1,710 @@
-// Common/MyVector.h

-

-#ifndef __COMMON_MY_VECTOR_H

-#define __COMMON_MY_VECTOR_H

-

-#include <string.h>

-

-template <class T>

-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 ReserveOnePosition()

-  {

-    if (_size == _capacity)

-    {

-      unsigned newCapacity = _capacity + (_capacity >> 2) + 1;

-      T *p;

-      MY_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:

-

-  CRecordVector(): _items(0), _size(0), _capacity(0) {}

-  

-  CRecordVector(const CRecordVector &v): _items(0), _size(0), _capacity(0)

-  {

-    unsigned size = v.Size();

-    if (size != 0)

-    {

-      _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)

-    {

-      MY_ARRAY_NEW(_items, T, size)

-      // _items = new T[size];

-      _capacity = size;

-    }

-  }

-

-  void Reserve(unsigned newCapacity)

-  {

-    if (newCapacity > _capacity)

-    {

-      T *p;

-      MY_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;

-    }

-  }

-

-  void ClearAndReserve(unsigned newCapacity)

-  {

-    Clear();

-    if (newCapacity > _capacity)

-    {

-      delete []_items;

-      _items = NULL;

-      _capacity = 0;

-      MY_ARRAY_NEW(_items, T, newCapacity)

-      // _items = new T[newCapacity];

-      _capacity = newCapacity;

-    }

-  }

-

-  void ClearAndSetSize(unsigned newSize)

-  {

-    ClearAndReserve(newSize);

-    _size = newSize;

-  }

-

-  void ChangeSize_KeepData(unsigned newSize)

-  {

-    if (newSize > _capacity)

-    {

-      T *p;

-      MY_ARRAY_NEW(p, T, newSize)

-      // p = new T[newSize];

-      if (_size != 0)

-        memcpy(p, _items, (size_t)_size * sizeof(T));

-      delete []_items;

-      _items = p;

-      _capacity = newSize;

-    }

-    _size = newSize;

-  }

-

-  void ReserveDown()

-  {

-    if (_size == _capacity)

-      return;

-    T *p = NULL;

-    if (_size != 0)

-    {

-      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;

-    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)

-  {

-    unsigned size = v.Size();

-    Reserve(_size + size);

-    if (size != 0)

-      memcpy(_items + _size, v._items, (size_t)size * sizeof(T));

-    _size += size;

-    return *this;

-  }

-  

-  unsigned Add(const T item)

-  {

-    ReserveOnePosition();

-    _items[_size] = item;

-    return _size++;

-  }

-

-  void AddInReserved(const T item)

-  {

-    _items[_size++] = item;

-  }

-

-  void Insert(unsigned index, const T item)

-  {

-    ReserveOnePosition();

-    MoveItems(index + 1, index);

-    _items[index] = item;

-    _size++;

-  }

-

-  void MoveToFront(unsigned index)

-  {

-    if (index != 0)

-    {

-      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& 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)

-  {

-    T temp = _items[i];

-    _items[i] = _items[j];

-    _items[j] = temp;

-  }

-  */

-

-  int FindInSorted(const T item, unsigned left, unsigned right) const

-  {

-    while (left != right)

-    {

-      unsigned mid = (left + right) / 2;

-      const T midVal = (*this)[mid];

-      if (item == midVal)

-        return 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)

-    {

-      unsigned mid = (left + right) / 2;

-      const T& midVal = (*this)[mid];

-      int comp = item.Compare(midVal);

-      if (comp == 0)

-        return 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)

-    {

-      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)

-    {

-      unsigned mid = (left + right) / 2;

-      const T& midVal = (*this)[mid];

-      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)

-  {

-    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 = (&Front()) - 1;

-    {

-      unsigned i = size >> 1;

-      do

-        SortRefDown(p, i, size, compare, param);

-      while (--i != 0);

-    }

-    do

-    {

-      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)

-  {

-    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 = (&Front()) - 1;

-    {

-      unsigned i = size >> 1;

-      do

-        SortRefDown2(p, i, size);

-      while (--i != 0);

-    }

-    do

-    {

-      T temp = p[size];

-      p[size--] = p[1];

-      p[1] = temp;

-      SortRefDown2(p, 1, size);

-    }

-    while (size > 1);

-  }

-};

-

-typedef CRecordVector<int> CIntVector;

-typedef CRecordVector<unsigned int> CUIntVector;

-typedef CRecordVector<bool> CBoolVector;

-typedef CRecordVector<unsigned char> CByteVector;

-typedef CRecordVector<void *> CPointerVector;

-

-template <class T>

-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)

-  {

-    unsigned size = v.Size();

-    _v.ConstructReserve(size);

-    for (unsigned i = 0; i < size; i++)

-      _v.AddInReserved(new T(v[i]));

-  }

-  CObjectVector& operator=(const CObjectVector &v)

-  {

-    if (&v == this)

-      return *this;

-    Clear();

-    unsigned size = v.Size();

-    _v.Reserve(size);

-    for (unsigned i = 0; i < size; i++)

-      _v.AddInReserved(new T(v[i]));

-    return *this;

-  }

-

-  CObjectVector& operator+=(const CObjectVector &v)

-  {

-    unsigned size = v.Size();

-    _v.Reserve(Size() + size);

-    for (unsigned i = 0; i < size; i++)

-      _v.AddInReserved(new T(v[i]));

-    return *this;

-  }

-  

-  const T& operator[](unsigned index) const { return *((T *)_v[index]); }

-        T& operator[](unsigned index)       { return *((T *)_v[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) { return _v.Add(new T(item)); }

-  

-  void AddInReserved(const T& item) { _v.AddInReserved(new T(item)); }

-  

-  T& AddNew()

-  {

-    T *p = new T;

-    _v.Add(p);

-    return *p;

-  }

-  

-  T& AddNewInReserved()

-  {

-    T *p = new T;

-    _v.AddInReserved(p);

-    return *p;

-  }

-  

-  void Insert(unsigned index, const T& item) { _v.Insert(index, new T(item)); }

-  

-  T& InsertNew(unsigned index)

-  {

-    T *p = new T;

-    _v.Insert(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)

-  {

-    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(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)

-    {

-      unsigned mid = (left + right) / 2;

-      const T& midVal = (*this)[mid];

-      int comp = item.Compare(midVal);

-      if (comp == 0)

-        return 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)

-    {

-      unsigned mid = (left + right) / 2;

-      const T& midVal = (*this)[mid];

-      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)

-    {

-      unsigned mid = (left + right) / 2;

-      const T& midVal = (*this)[mid];

-      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 **)a1))).Compare(*(*((const T **)a2))); }

-

-  void Sort() { _v.Sort(CompareObjectItems, 0); }

-};

-

-#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 <string.h>
+
+#include "Common.h"
+
+const unsigned k_VectorSizeMax = ((unsigned)1 << 31) - 1;
+
+template <class T>
+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)
+    {
+      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& 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)
+  {
+    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)
+  {
+    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 = (&Front()) - 1;
+    {
+      unsigned i = size >> 1;
+      do
+        SortRefDown(p, i, size, compare, param);
+      while (--i != 0);
+    }
+    do
+    {
+      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)
+  {
+    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 = (&Front()) - 1;
+    {
+      unsigned i = size >> 1;
+      do
+        SortRefDown2(p, i, size);
+      while (--i != 0);
+    }
+    do
+    {
+      T temp = p[size];
+      p[size--] = p[1];
+      p[1] = temp;
+      SortRefDown2(p, 1, size);
+    }
+    while (size > 1);
+  }
+};
+
+typedef CRecordVector<int> CIntVector;
+typedef CRecordVector<unsigned int> CUIntVector;
+typedef CRecordVector<bool> CBoolVector;
+typedef CRecordVector<unsigned char> CByteVector;
+typedef CRecordVector<void *> CPointerVector;
+
+template <class T>
+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 bc9f7be..ae284eb 100644
--- a/CPP/Common/MyWindows.cpp
+++ b/CPP/Common/MyWindows.cpp
@@ -1,145 +1,292 @@
-// MyWindows.cpp

-

-#include "StdAfx.h"

-

-#ifndef _WIN32

-

-#include <stdlib.h>

-

-#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 - sizeof(OLECHAR) - sizeof(OLECHAR) - sizeof(CBstrSizeType)))

-    return NULL;

-

-  UINT size = (len + sizeof(OLECHAR) + sizeof(OLECHAR) - 1) & ~(sizeof(OLECHAR) - 1);

-  void *p = AllocateForBSTR(size + 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 - sizeof(OLECHAR) - sizeof(CBstrSizeType)) / sizeof(OLECHAR))

-    return NULL;

-

-  UINT size = len * sizeof(OLECHAR);

-  void *p = AllocateForBSTR(size + sizeof(CBstrSizeType) + 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 0;

-  const OLECHAR *s2 = s;

-  while (*s2 != 0)

-    s2++;

-  return SysAllocStringLen(s, (UINT)(s2 - s));

-}

-

-void SysFreeString(BSTR bstr)

-{

-  if (bstr)

-    FreeForBSTR((CBstrSizeType *)bstr - 1);

-}

-

-UINT SysStringByteLen(BSTR bstr)

-{

-  if (!bstr)

-    return 0;

-  return *((CBstrSizeType *)bstr - 1);

-}

-

-UINT SysStringLen(BSTR bstr)

-{

-  if (!bstr)

-    return 0;

-  return *((CBstrSizeType *)bstr - 1) / 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 0;

-}

-

-#endif

+// MyWindows.cpp
+
+#include "StdAfx.h"
+
+#ifndef _WIN32
+
+#include <stdlib.h>
+#include <time.h>
+#ifdef __GNUC__
+#include <sys/time.h>
+#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 *)bstr - 1);
+}
+
+UINT SysStringByteLen(BSTR bstr)
+{
+  if (!bstr)
+    return 0;
+  return *((CBstrSizeType *)bstr - 1);
+}
+
+UINT SysStringLen(BSTR bstr)
+{
+  if (!bstr)
+    return 0;
+  return *((CBstrSizeType *)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 cc78478..a76e14b 100644
--- a/CPP/Common/MyWindows.h
+++ b/CPP/Common/MyWindows.h
@@ -1,231 +1,324 @@
-// MyWindows.h

-

-#ifndef __MY_WINDOWS_H

-#define __MY_WINDOWS_H

-

-#ifdef _WIN32

-

-#include <windows.h>

-

-#ifdef UNDER_CE

-  #undef VARIANT_TRUE

-  #define VARIANT_TRUE ((VARIANT_BOOL)-1)

-#endif

-

-#else

-

-#include <stddef.h> // for wchar_t

-#include <string.h>

-// #include <stdint.h> // for uintptr_t

-

-#include "MyGuidDef.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;

-

-typedef int INT;

-typedef Int32 INT32;

-typedef unsigned int UINT;

-typedef UInt32 UINT32;

-typedef INT32 LONG;   // LONG, ULONG and DWORD must be 32-bit

-typedef UINT32 ULONG;

-

-#undef DWORD

-typedef UINT32 DWORD;

-

-typedef long 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 _LARGE_INTEGER { LONGLONG QuadPart; } LARGE_INTEGER;

-typedef struct _ULARGE_INTEGER { 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 _FILETIME

-{

-  DWORD dwLowDateTime;

-  DWORD dwHighDateTime;

-} FILETIME;

-

-#define HRESULT LONG

-#define FAILED(Status) ((HRESULT)(Status)<0)

-typedef ULONG PROPID;

-typedef LONG SCODE;

-

-#define ERROR_NEGATIVE_SEEK 131L

-

-#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 E_OUTOFMEMORY ((HRESULT)0x8007000EL)

-#define E_INVALIDARG ((HRESULT)0x80070057L)

-

-#ifdef _MSC_VER

-#define STDMETHODCALLTYPE __stdcall

-#else

-#define STDMETHODCALLTYPE

-#endif

-

-#define STDMETHOD_(t, f) virtual t STDMETHODCALLTYPE f

-#define STDMETHOD(f) STDMETHOD_(HRESULT, f)

-#define STDMETHODIMP_(type) type STDMETHODCALLTYPE

-#define STDMETHODIMP STDMETHODIMP_(HRESULT)

-

-#define PURE = 0

-

-#define MIDL_INTERFACE(x) struct

-

-#ifdef __cplusplus

-

-DEFINE_GUID(IID_IUnknown,

-0x00000000, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);

-struct IUnknown

-{

-  STDMETHOD(QueryInterface) (REFIID iid, void **outObject) PURE;

-  STDMETHOD_(ULONG, AddRef)() PURE;

-  STDMETHOD_(ULONG, Release)() PURE;

-  #ifndef _WIN32

-  virtual ~IUnknown() {}

-  #endif

-};

-

-typedef IUnknown *LPUNKNOWN;

-

-#endif

-

-#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;

-

-MY_EXTERN_C HRESULT VariantClear(VARIANTARG *prop);

-MY_EXTERN_C HRESULT VariantCopy(VARIANTARG *dest, const VARIANTARG *src);

-

-typedef struct tagSTATPROPSTG

-{

-  LPOLESTR lpwstrName;

-  PROPID propid;

-  VARTYPE vt;

-} STATPROPSTG;

-

-MY_EXTERN_C BSTR SysAllocStringByteLen(LPCSTR psz, UINT len);

-MY_EXTERN_C BSTR SysAllocStringLen(const OLECHAR *sz, UINT len);

-MY_EXTERN_C BSTR SysAllocString(const OLECHAR *sz);

-MY_EXTERN_C void SysFreeString(BSTR bstr);

-MY_EXTERN_C UINT SysStringByteLen(BSTR bstr);

-MY_EXTERN_C UINT SysStringLen(BSTR bstr);

-

-MY_EXTERN_C DWORD GetLastError();

-MY_EXTERN_C LONG CompareFileTime(const FILETIME* ft1, const FILETIME* ft2);

-

-#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;

-

-#endif

-#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 <stddef.h> // for wchar_t
+#include <string.h>
+// #include <stdint.h> // 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 _LARGE_INTEGER { LONGLONG QuadPart; } LARGE_INTEGER;
+typedef struct _ULARGE_INTEGER { 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 _FILETIME
+{
+  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 _SYSTEMTIME
+{
+  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
new file mode 100644
index 0000000..a879d34
--- /dev/null
+++ b/CPP/Common/MyXml.cpp
@@ -0,0 +1,260 @@
+// MyXml.cpp
+
+#include "StdAfx.h"
+
+#include "MyXml.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
+{
+  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;
+}
+
+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
+{
+  int index = FindSubTag(tag);
+  if (index >= 0)
+    return SubItems[(unsigned)index].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;
+  if (s != beg)
+  {
+    IsTag = false;
+    Name.SetFrom(beg, (unsigned)(s - beg));
+    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(beg, (unsigned)(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;
+      unsigned len = Name.Len();
+      for (unsigned i = 0; i < len; i++)
+        if (s[i] != Name[i])
+          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(beg, (unsigned)(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(beg, (unsigned)(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, "<?xml",    "?>"); if (!s) return false;
+  s = SkipHeader(s, "<!DOCTYPE", ">"); 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);
+}
+*/
diff --git a/CPP/Common/MyXml.h b/CPP/Common/MyXml.h
new file mode 100644
index 0000000..5362602
--- /dev/null
+++ b/CPP/Common/MyXml.h
@@ -0,0 +1,43 @@
+// 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<CXmlProp> Props;
+  CObjectVector<CXmlItem> 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();
+  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;
+};
+
+#endif
diff --git a/CPP/Common/NewHandler.cpp b/CPP/Common/NewHandler.cpp
index 18d2d18..c95833e 100644
--- a/CPP/Common/NewHandler.cpp
+++ b/CPP/Common/NewHandler.cpp
@@ -1,163 +1,298 @@
-// NewHandler.cpp

- 

-#include "StdAfx.h"

-

-#include <stdlib.h>

-

-#include "NewHandler.h"

-

-// #define DEBUG_MEMORY_LEAK

-

-#ifndef DEBUG_MEMORY_LEAK

-

-#ifdef _7ZIP_REDEFINE_OPERATOR_NEW

-

-/*

-void * my_new(size_t size)

-{

-  // void *p = ::HeapAlloc(::GetProcessHeap(), 0, size);

-  void *p = ::malloc(size);

-  if (p == 0)

-    throw CNewException();

-  return p;

-}

-

-void my_delete(void *p) throw()

-{

-  // if (p == 0) 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)

-{

-  // void *p = ::HeapAlloc(::GetProcessHeap(), 0, size);

-  void *p = ::malloc(size);

-  if (p == 0)

-    throw CNewException();

-  return p;

-}

-

-void

-#ifdef _MSC_VER

-__cdecl

-#endif

-operator delete(void *p) throw()

-{

-  // if (p == 0) return; ::HeapFree(::GetProcessHeap(), 0, p);

-  ::free(p);

-}

-

-/*

-void *

-#ifdef _MSC_VER

-__cdecl

-#endif

-operator new[](size_t size)

-{

-  // void *p = ::HeapAlloc(::GetProcessHeap(), 0, size);

-  void *p = ::malloc(size);

-  if (p == 0)

-    throw CNewException();

-  return p;

-}

-

-void

-#ifdef _MSC_VER

-__cdecl

-#endif

-operator delete[](void *p) throw()

-{

-  // if (p == 0) return; ::HeapFree(::GetProcessHeap(), 0, p);

-  ::free(p);

-}

-*/

-

-#endif

-

-#else

-

-#include <stdio.h>

-

-// #pragma init_seg(lib)

-const int kDebugSize = 1000000;

-static void *a[kDebugSize];

-static int index = 0;

-

-static int numAllocs = 0;

-void * __cdecl operator new(size_t size)

-{

-  numAllocs++;

-  void *p = HeapAlloc(GetProcessHeap(), 0, size);

-  if (index < kDebugSize)

-  {

-    a[index] = p;

-    index++;

-  }

-  if (p == 0)

-    throw CNewException();

-  printf("Alloc %6d, size = %8u\n", numAllocs, (unsigned)size);

-  return p;

-}

-

-class CC

-{

-public:

-  CC()

-  {

-    for (int i = 0; i < kDebugSize; i++)

-      a[i] = 0;

-  }

-  ~CC()

-  {

-    for (int i = 0; i < kDebugSize; i++)

-      if (a[i] != 0)

-        return;

-  }

-} g_CC;

-

-

-void __cdecl operator delete(void *p)

-{

-  if (p == 0)

-    return;

-  /*

-  for (int i = 0; i < index; i++)

-    if (a[i] == p)

-      a[i] = 0;

-  */

-  HeapFree(GetProcessHeap(), 0, p);

-  numAllocs--;

-  printf("Free %d\n", numAllocs);

-}

-

-#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 <stdlib.h>
+
+#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;
+}
+
+void
+#ifdef _MSC_VER
+__cdecl
+#endif
+operator delete(void *p) throw()
+{
+  // if (!p) return; ::HeapFree(::GetProcessHeap(), 0, p);
+  // MyFree(p);
+  ::free(p);
+}
+
+/*
+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 <stdio.h>
+
+// #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 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 9d20ee1..50f6d0a 100644
--- a/CPP/Common/NewHandler.h
+++ b/CPP/Common/NewHandler.h
@@ -1,88 +1,98 @@
-// Common/NewHandler.h

-

-#ifndef __COMMON_NEW_HANDLER_H

-#define __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.

-

-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 <stddef.h>

-

-#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 < 1900)

-  // If you want to use default operator new(), you can disable the following line

-  #define _7ZIP_REDEFINE_OPERATOR_NEW

-#endif

-

-

-#ifdef _7ZIP_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);

-

-void

-#ifdef _MSC_VER

-__cdecl

-#endif

-operator delete(void *p) throw();

-

-#else

-

-#include <new>

-

-#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 <stddef.h>
+
+#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);
+
+void
+#ifdef _MSC_VER
+__cdecl
+#endif
+operator delete(void *p) throw();
+
+#else
+
+#include <new>
+
+#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
new file mode 100644
index 0000000..fbdb8c9
--- /dev/null
+++ b/CPP/Common/Random.cpp
@@ -0,0 +1,28 @@
+// Common/Random.cpp
+
+#include "StdAfx.h"
+
+#include <stdlib.h>
+
+#ifndef _WIN32
+#include <time.h>
+#else
+#include "MyWindows.h"
+#endif
+
+#include "Random.h"
+
+void CRandom::Init(unsigned int seed) { srand(seed); }
+
+void CRandom::Init()
+{
+  Init((unsigned int)
+    #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
new file mode 100644
index 0000000..283869e
--- /dev/null
+++ b/CPP/Common/Random.h
@@ -0,0 +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 int seed);
+  int Generate() const;
+};
+
+#endif
diff --git a/CPP/Common/Sha1Prepare.cpp b/CPP/Common/Sha1Prepare.cpp
new file mode 100644
index 0000000..2652f00
--- /dev/null
+++ b/CPP/Common/Sha1Prepare.cpp
@@ -0,0 +1,7 @@
+// 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
new file mode 100644
index 0000000..64eef34
--- /dev/null
+++ b/CPP/Common/Sha1Reg.cpp
@@ -0,0 +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)
diff --git a/CPP/Common/Sha256Prepare.cpp b/CPP/Common/Sha256Prepare.cpp
new file mode 100644
index 0000000..1ec242b
--- /dev/null
+++ b/CPP/Common/Sha256Prepare.cpp
@@ -0,0 +1,7 @@
+// 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 14a3652..b5689c4 100644
--- a/CPP/Common/Sha256Reg.cpp
+++ b/CPP/Common/Sha256Reg.cpp
@@ -1,40 +1,67 @@
-// Sha256Reg.cpp

-

-#include "StdAfx.h"

-

-#include "../../C/Sha256.h"

-

-#include "../Common/MyCom.h"

-

-#include "../7zip/Common/RegisterCodec.h"

-

-class CSha256Hasher:

-  public IHasher,

-  public CMyUnknownImp

-{

-  CSha256 _sha;

-  Byte mtDummy[1 << 7];

-

-public:

-  CSha256Hasher() { Sha256_Init(&_sha); }

-

-  MY_UNKNOWN_IMP1(IHasher)

-  INTERFACE_IHasher(;)

-};

-

-STDMETHODIMP_(void) CSha256Hasher::Init() throw()

-{

-  Sha256_Init(&_sha);

-}

-

-STDMETHODIMP_(void) CSha256Hasher::Update(const void *data, UInt32 size) throw()

-{

-  Sha256_Update(&_sha, (const Byte *)data, size);

-}

-

-STDMETHODIMP_(void) CSha256Hasher::Final(Byte *digest) throw()

-{

-  Sha256_Final(&_sha, digest);

-}

-

-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/StdAfx.h b/CPP/Common/StdAfx.h
index 3f1890a..a5228b0 100644
--- a/CPP/Common/StdAfx.h
+++ b/CPP/Common/StdAfx.h
@@ -1,8 +1,8 @@
-// StdAfx.h

-

-#ifndef __STDAFX_H

-#define __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 f547b54..7b209f1 100644
--- a/CPP/Common/StdInStream.cpp
+++ b/CPP/Common/StdInStream.cpp
@@ -1,89 +1,98 @@
-// Common/StdInStream.cpp

-

-#include "StdAfx.h"

-

-#include <tchar.h>

-

-#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"

-

-#define kFileOpenMode TEXT("r")

-

-extern int g_CodePage;

-

-CStdInStream g_StdIn(stdin);

-

-bool CStdInStream::Open(LPCTSTR fileName) throw()

-{

-  Close();

-  _stream = _tfopen(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 (;;)

-  {

-    int intChar = GetChar();

-    if (intChar == EOF)

-      return true;

-    char c = (char)intChar;

-    if (c == 0)

-      return false;

-    if (c == '\n')

-      return true;

-    s += c;

-  }

-}

-

-bool CStdInStream::ScanUStringUntilNewLine(UString &dest)

-{

-  dest.Empty();

-  AString s;

-  bool res = ScanAStringUntilNewLine(s);

-  int codePage = g_CodePage;

-  if (codePage == -1)

-    codePage = CP_OEMCP;

-  if (codePage == CP_UTF8)

-    ConvertUTF8ToUnicode(s, dest);

-  else

-    MultiByteToUnicodeString2(dest, s, (UINT)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 <tchar.h>
+#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 (;;)
+  {
+    int intChar = GetChar();
+    if (intChar == EOF)
+      return true;
+    char c = (char)intChar;
+    if (c == 0)
+      return false;
+    if (c == '\n')
+      return true;
+    s += c;
+  }
+}
+
+bool CStdInStream::ScanUStringUntilNewLine(UString &dest)
+{
+  dest.Empty();
+  AString s;
+  bool res = ScanAStringUntilNewLine(s);
+  int codePage = CodePage;
+  if (codePage == -1)
+    codePage = CP_OEMCP;
+  if (codePage == CP_UTF8)
+    ConvertUTF8ToUnicode(s, dest);
+  else
+    MultiByteToUnicodeString2(dest, s, (UINT)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 20f9ce3..81ca3bf 100644
--- a/CPP/Common/StdInStream.h
+++ b/CPP/Common/StdInStream.h
@@ -1,38 +1,46 @@
-// Common/StdInStream.h

-

-#ifndef __COMMON_STD_IN_STREAM_H

-#define __COMMON_STD_IN_STREAM_H

-

-#include <stdio.h>

-

-#include "MyString.h"

-#include "MyTypes.h"

-

-class CStdInStream

-{

-  FILE *_stream;

-  bool _streamIsOpen;

-public:

-  CStdInStream(): _stream(0), _streamIsOpen(false) {};

-  CStdInStream(FILE *stream): _stream(stream), _streamIsOpen(false) {};

-  ~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 <stdio.h>
+
+#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 dc6d4bd..cfa5fde 100644
--- a/CPP/Common/StdOutStream.cpp
+++ b/CPP/Common/StdOutStream.cpp
@@ -1,163 +1,160 @@
-// Common/StdOutStream.cpp

-

-#include "StdAfx.h"

-

-#include <tchar.h>

-

-#include "IntToString.h"

-#include "StdOutStream.h"

-#include "StringConvert.h"

-#include "UTFConvert.h"

-

-#define kFileOpenMode "wt"

-

-extern int g_CodePage;

-

-CStdOutStream g_StdOut(stdout);

-CStdOutStream g_StdErr(stderr);

-

-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)

-{

-  int codePage = g_CodePage;

-  if (codePage == -1)

-    codePage = CP_OEMCP;

-  AString dest;

-  if (codePage == CP_UTF8)

-    ConvertUnicodeToUTF8(s, dest);

-  else

-    UnicodeStringToMultiByte2(dest, s, (UINT)codePage);

-  return operator<<((const char *)dest);

-}

-

-void StdOut_Convert_UString_to_AString(const UString &s, AString &temp)

-{

-  int codePage = g_CodePage;

-  if (codePage == -1)

-    codePage = CP_OEMCP;

-  if (codePage == CP_UTF8)

-    ConvertUnicodeToUTF8(s, temp);

-  else

-    UnicodeStringToMultiByte2(temp, s, (UINT)codePage);

-}

-

-void CStdOutStream::PrintUString(const UString &s, AString &temp)

-{

-  StdOut_Convert_UString_to_AString(s, temp);

-  *this << (const char *)temp;

-}

-

-

-static const wchar_t kReplaceChar = '_';

-

-void CStdOutStream::Normalize_UString__LF_Allowed(UString &s)

-{

-  unsigned len = s.Len();

-  wchar_t *d = s.GetBuf();

-

-  if (IsTerminalMode)

-    for (unsigned i = 0; i < len; i++)

-    {

-      wchar_t c = d[i];

-      if (c <= 13 && c >= 7 && c != '\n')

-        d[i] = kReplaceChar;

-    }

-}

-

-void CStdOutStream::Normalize_UString(UString &s)

-{

-  unsigned len = s.Len();

-  wchar_t *d = s.GetBuf();

-

-  if (IsTerminalMode)

-    for (unsigned i = 0; i < len; i++)

-    {

-      wchar_t c = d[i];

-      if (c <= 13 && c >= 7)

-        d[i] = kReplaceChar;

-    }

-  else

-    for (unsigned i = 0; i < len; i++)

-    {

-      wchar_t c = d[i];

-      if (c == '\n')

-        d[i] = kReplaceChar;

-    }

-}

-

-void CStdOutStream::NormalizePrint_UString(const UString &s, UString &tempU, AString &tempA)

-{

-  tempU = s;

-  Normalize_UString(tempU);

-  PrintUString(tempU, tempA);

-}

-

-void CStdOutStream::NormalizePrint_UString(const UString &s)

-{

-  NormalizePrint_wstr(s);

-}

-

-void CStdOutStream::NormalizePrint_wstr(const wchar_t *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 <tchar.h>
+#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 (codePage == CP_UTF8)
+    ConvertUnicodeToUTF8(src, dest);
+  else
+    UnicodeStringToMultiByte2(dest, src, (UINT)codePage);
+}
+
+
+static const wchar_t kReplaceChar = '_';
+
+void CStdOutStream::Normalize_UString_LF_Allowed(UString &s)
+{
+  unsigned len = s.Len();
+  wchar_t *d = s.GetBuf();
+
+  if (IsTerminalMode)
+    for (unsigned i = 0; i < len; i++)
+    {
+      wchar_t c = d[i];
+      if (c <= 13 && c >= 7 && c != '\n')
+        d[i] = kReplaceChar;
+    }
+}
+
+void CStdOutStream::Normalize_UString(UString &s)
+{
+  unsigned len = s.Len();
+  wchar_t *d = s.GetBuf();
+
+  if (IsTerminalMode)
+    for (unsigned i = 0; i < len; i++)
+    {
+      wchar_t c = d[i];
+      if (c <= 13 && c >= 7)
+        d[i] = kReplaceChar;
+    }
+  else
+    for (unsigned i = 0; i < len; i++)
+    {
+      wchar_t c = d[i];
+      if (c == '\n')
+        d[i] = kReplaceChar;
+    }
+}
+
+void CStdOutStream::NormalizePrint_UString(const UString &s, UString &tempU, AString &tempA)
+{
+  tempU = s;
+  Normalize_UString(tempU);
+  PrintUString(tempU, tempA);
+}
+
+void CStdOutStream::NormalizePrint_UString(const UString &s)
+{
+  NormalizePrint_wstr(s);
+}
+
+void CStdOutStream::NormalizePrint_wstr(const wchar_t *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 475954c..bd15d7c 100644
--- a/CPP/Common/StdOutStream.h
+++ b/CPP/Common/StdOutStream.h
@@ -1,71 +1,78 @@
-// Common/StdOutStream.h

-

-#ifndef __COMMON_STD_OUT_STREAM_H

-#define __COMMON_STD_OUT_STREAM_H

-

-#include <stdio.h>

-

-#include "MyString.h"

-#include "MyTypes.h"

-

-class CStdOutStream

-{

-  FILE *_stream;

-  bool _streamIsOpen;

-public:

-  bool IsTerminalMode;

-

-  CStdOutStream(): _stream(0), _streamIsOpen(false), IsTerminalMode(false) {};

-  CStdOutStream(FILE *stream): _stream(stream), _streamIsOpen(false) {};

-  ~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 Normalize_UString__LF_Allowed(UString &s);

-  void Normalize_UString(UString &s);

-

-  void NormalizePrint_UString(const UString &s, UString &tempU, AString &tempA);

-  void NormalizePrint_UString(const UString &s);

-  void NormalizePrint_wstr(const wchar_t *s);

-};

-

-CStdOutStream & endl(CStdOutStream & outStream) throw();

-

-extern CStdOutStream g_StdOut;

-extern CStdOutStream g_StdErr;

-

-void StdOut_Convert_UString_to_AString(const UString &s, AString &temp);

-

-#endif

+// Common/StdOutStream.h
+
+#ifndef ZIP7_INC_COMMON_STD_OUT_STREAM_H
+#define ZIP7_INC_COMMON_STD_OUT_STREAM_H
+
+#include <stdio.h>
+
+#include "MyString.h"
+#include "MyTypes.h"
+
+class CStdOutStream
+{
+  FILE *_stream;
+  // bool _streamIsOpen;
+public:
+  bool IsTerminalMode;
+  int CodePage;
+
+  CStdOutStream(FILE *stream = NULL):
+      _stream(stream),
+      // _streamIsOpen(false),
+      IsTerminalMode(false),
+      CodePage(-1)
+      {}
+
+  // ~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_LF_Allowed(UString &s);
+  void Normalize_UString(UString &s);
+
+  void NormalizePrint_UString(const UString &s, UString &tempU, AString &tempA);
+  void NormalizePrint_UString(const UString &s);
+  void NormalizePrint_wstr(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 b8f33cd..f25396a 100644
--- a/CPP/Common/StringConvert.cpp
+++ b/CPP/Common/StringConvert.cpp
@@ -1,319 +1,756 @@
-// Common/StringConvert.cpp

-

-#include "StdAfx.h"

-

-#include "StringConvert.h"

-

-#ifndef _WIN32

-#include <stdlib.h>

-#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 = MultiByteToWideChar(codePage, 0, src, src.Len(), NULL, 0);

-    if (len == 0)

-    {

-      if (GetLastError() != 0)

-        throw 282228;

-    }

-    else

-    {

-      len = MultiByteToWideChar(codePage, 0, src, src.Len(), dest.GetBuf(len), 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 = WideCharToMultiByte(codePage, 0, src, 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 = WideCharToMultiByte(codePage, 0, src, src.Len(),

-          dest.GetBuf(len), 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

-

-void MultiByteToUnicodeString2(UString &dest, const AString &src, UINT /* codePage */)

-{

-  dest.Empty();

-  if (src.IsEmpty())

-    return;

-

-  size_t limit = ((size_t)src.Len() + 1) * 2;

-  wchar_t *d = dest.GetBuf((unsigned)limit);

-  size_t len = mbstowcs(d, src, limit);

-  if (len != (size_t)-1)

-  {

-    dest.ReleaseBuf_SetEnd((unsigned)len);

-    return;

-  }

-  

-  {

-    unsigned i;

-    const char *s = (const char *)src;

-    for (i = 0;;)

-    {

-      Byte c = (Byte)s[i];

-      if (c == 0)

-        break;

-      d[i++] = (wchar_t)c;

-    }

-    d[i] = 0;

-    dest.ReleaseBuf_SetLen(i);

-  }

-}

-

-static void UnicodeStringToMultiByte2(AString &dest, const UString &src, UINT /* codePage */, char defaultChar, bool &defaultCharWasUsed)

-{

-  dest.Empty();

-  defaultCharWasUsed = false;

-  if (src.IsEmpty())

-    return;

-

-  size_t limit = ((size_t)src.Len() + 1) * 6;

-  char *d = dest.GetBuf((unsigned)limit);

-  size_t len = wcstombs(d, src, limit);

-  if (len != (size_t)-1)

-  {

-    dest.ReleaseBuf_SetEnd((unsigned)len);

-    return;

-  }

-

-  {

-    const wchar_t *s = (const wchar_t *)src;

-    unsigned i;

-    for (i = 0;;)

-    {

-      wchar_t c = s[i];

-      if (c == 0)

-        break;

-      if (c >= 0x100)

-      {

-        c = defaultChar;

-        defaultCharWasUsed = true;

-      }

-      d[i++] = (char)c;

-    }

-    d[i] = 0;

-    dest.ReleaseBuf_SetLen(i);

-  }

-}

-

-#endif

-

-

-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;

-}

+// Common/StringConvert.cpp
+
+#include "StdAfx.h"
+
+#include "StringConvert.h"
+
+#ifndef _WIN32
+// #include <stdio.h>
+#include <stdlib.h>
+#endif
+
+#if !defined(_WIN32) || defined(ENV_HAVE_LOCALE)
+#include "UTFConvert.h"
+#endif
+
+#ifdef ENV_HAVE_LOCALE
+#include <locale.h>
+#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 <stdio.h>
+/*
+  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)
+  {
+    ConvertUTF8ToUnicode(src, dest);
+    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);
+
+    #if WCHAR_MAX > 0xffff
+    d = dest.GetBuf();
+    for (size_t i = 0;; i++)
+    {
+      // wchar_t c = dest[i];
+      wchar_t c = d[i];
+      if (c == 0)
+        break;
+      if (c >= 0x10000 && c < 0x110000)
+      {
+        /*
+        c -= 0x10000;
+        unsigned c0 = 0xd800 + ((c >> 10) & 0x3FF);
+        dest.ReplaceOneCharAtPos(i, c0);
+        i++;
+        c = 0xdc00 + (c & 0x3FF);
+        dest.Insert_wchar_t(i, c);
+        */
+        UString temp = d + i;
+
+        for (size_t t = 0;; t++)
+        {
+          wchar_t w = temp[t];
+          if (w == 0)
+            break;
+          if (i == limit)
+            break; // unexpected error
+          if (w >= 0x10000 && w < 0x110000)
+          {
+            if (i + 1 == limit)
+              break; // unexpected error
+            w -= 0x10000;
+            d[i++] = (unsigned)0xd800 + (((unsigned)w >> 10) & 0x3FF);
+            w = 0xdc00 + (w & 0x3FF);
+          }
+          d[i++] = w;
+        }
+        dest.ReleaseBuf_SetEnd((unsigned)i);
+      }
+    }
+
+    #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)
+  {
+    defaultCharWasUsed = false;
+    ConvertUnicodeToUTF8(src2, dest);
+    return;
+  }
+
+  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 + 1 != src2.Len())
+      {
+        const wchar_t c2 = src2[i + 1];
+        if (c2 >= 0xdc00 && c2 < 0x10000)
+        {
+          // printf("\nSurragate [%d]: %4x %4x -> ", i, (int)c, (int)c2);
+          c = 0x10000 + ((c & 0x3ff) << 10) + (c2 & 0x3ff);
+          // printf("%4x\n", (int)c);
+          i++;
+        }
+      }
+      src += c;
+      i++;
+    }
+  }
+  #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 05a2155..2092a2d 100644
--- a/CPP/Common/StringConvert.h
+++ b/CPP/Common/StringConvert.h
@@ -1,88 +1,110 @@
-// Common/StringConvert.h

-

-#ifndef __COMMON_STRING_CONVERT_H

-#define __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

-

-#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 295816e..bc4926e 100644
--- a/CPP/Common/StringToInt.cpp
+++ b/CPP/Common/StringToInt.cpp
@@ -1,144 +1,171 @@
-// Common/StringToInt.cpp

-

-#include "StdAfx.h"

-

-#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 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++) { \

-      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; \

-      unsigned v = (c - '0'); \

-      if (res > (k_ ## uintType ## _max) - v) return 0; \

-      res += v; }}

-

-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++;

-  if (*s2 == 0)

-    return 0;

-  const wchar_t *end2;

-  UInt32 res = ConvertStringToUInt32(s2, &end2);

-  if (*s == '-')

-  {

-    if (res > ((UInt32)1 << (32 - 1)))

-      return 0;

-  }

-  else if ((res & ((UInt32)1 << (32 - 1))) != 0)

-    return 0;

-  if (end)

-    *end = end2;

-  if (*s == '-')

-    return -(Int32)res;

-  return (Int32)res;

-}

-

-UInt32 ConvertOctStringToUInt32(const char *s, const char **end) throw()

-{

-  if (end)

-    *end = s;

-  UInt32 res = 0;

-  for (;; s++)

-  {

-    unsigned c = (unsigned char)*s;

-    if (c < '0' || c > '7')

-    {

-      if (end)

-        *end = s;

-      return res;

-    }

-    if ((res & (UInt32)7 << (32 - 3)) != 0)

-      return 0;

-    res <<= 3;

-    res |= (unsigned)(c - '0');

-  }

-}

-

-UInt64 ConvertOctStringToUInt64(const char *s, const char **end) throw()

-{

-  if (end)

-    *end = s;

-  UInt64 res = 0;

-  for (;; s++)

-  {

-    unsigned c = (unsigned char)*s;

-    if (c < '0' || c > '7')

-    {

-      if (end)

-        *end = s;

-      return res;

-    }

-    if ((res & (UInt64)7 << (64 - 3)) != 0)

-      return 0;

-    res <<= 3;

-    res |= (unsigned)(c - '0');

-  }

-}

-

-UInt32 ConvertHexStringToUInt32(const char *s, const char **end) throw()

-{

-  if (end)

-    *end = s;

-  UInt32 res = 0;

-  for (;; s++)

-  {

-    unsigned c = (Byte)*s;

-    unsigned v;

-    if (c >= '0' && c <= '9') v = (c - '0');

-    else if (c >= 'A' && c <= 'F') v = 10 + (c - 'A');

-    else if (c >= 'a' && c <= 'f') v = 10 + (c - 'a');

-    else

-    {

-      if (end)

-        *end = s;

-      return res;

-    }

-    if ((res & (UInt32)0xF << (32 - 4)) != 0)

-      return 0;

-    res <<= 4;

-    res |= v;

-  }

-}

-

-UInt64 ConvertHexStringToUInt64(const char *s, const char **end) throw()

-{

-  if (end)

-    *end = s;

-  UInt64 res = 0;

-  for (;; s++)

-  {

-    unsigned c = (Byte)*s;

-    unsigned v;

-    if (c >= '0' && c <= '9') v = (c - '0');

-    else if (c >= 'A' && c <= 'F') v = 10 + (c - 'A');

-    else if (c >= 'a' && c <= 'f') v = 10 + (c - 'a');

-    else

-    {

-      if (end)

-        *end = s;

-      return res;

-    }

-    if ((res & (UInt64)0xF << (64 - 4)) != 0)

-      return 0;

-    res <<= 4;

-    res |= v;

-  }

-}

+// Common/StringToInt.cpp
+
+#include "StdAfx.h"
+
+#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 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++) { \
+      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; \
+      unsigned v = (unsigned)(c - '0'); \
+      if (res > (k_ ## uintType ## _max) - v) return 0; \
+      res += v; }}
+
+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 char *s, const char **end) throw()
+{
+  if (end)
+    *end = s;
+  const char *s2 = s;
+  if (*s == '-')
+    s2++;
+  if (*s2 == 0)
+    return 0;
+  const char *end2;
+  UInt32 res = ConvertStringToUInt32(s2, &end2);
+  if (*s == '-')
+  {
+    if (res > ((UInt32)1 << (32 - 1)))
+      return 0;
+  }
+  else if ((res & ((UInt32)1 << (32 - 1))) != 0)
+    return 0;
+  if (end)
+    *end = end2;
+  if (*s == '-')
+    return -(Int32)res;
+  return (Int32)res;
+}
+*/
+
+Int32 ConvertStringToInt32(const wchar_t *s, const wchar_t **end) throw()
+{
+  if (end)
+    *end = s;
+  const wchar_t *s2 = s;
+  if (*s == '-')
+    s2++;
+  if (*s2 == 0)
+    return 0;
+  const wchar_t *end2;
+  UInt32 res = ConvertStringToUInt32(s2, &end2);
+  if (*s == '-')
+  {
+    if (res > ((UInt32)1 << (32 - 1)))
+      return 0;
+  }
+  else if ((res & ((UInt32)1 << (32 - 1))) != 0)
+    return 0;
+  if (end)
+    *end = end2;
+  if (*s == '-')
+    return -(Int32)res;
+  return (Int32)res;
+}
+
+UInt32 ConvertOctStringToUInt32(const char *s, const char **end) throw()
+{
+  if (end)
+    *end = s;
+  UInt32 res = 0;
+  for (;; s++)
+  {
+    unsigned c = (unsigned char)*s;
+    if (c < '0' || c > '7')
+    {
+      if (end)
+        *end = s;
+      return res;
+    }
+    if ((res & (UInt32)7 << (32 - 3)) != 0)
+      return 0;
+    res <<= 3;
+    res |= (unsigned)(c - '0');
+  }
+}
+
+UInt64 ConvertOctStringToUInt64(const char *s, const char **end) throw()
+{
+  if (end)
+    *end = s;
+  UInt64 res = 0;
+  for (;; s++)
+  {
+    unsigned c = (unsigned char)*s;
+    if (c < '0' || c > '7')
+    {
+      if (end)
+        *end = s;
+      return res;
+    }
+    if ((res & (UInt64)7 << (64 - 3)) != 0)
+      return 0;
+    res <<= 3;
+    res |= (unsigned)(c - '0');
+  }
+}
+
+UInt32 ConvertHexStringToUInt32(const char *s, const char **end) throw()
+{
+  if (end)
+    *end = s;
+  UInt32 res = 0;
+  for (;; s++)
+  {
+    unsigned c = (Byte)*s;
+    unsigned v;
+    if (c >= '0' && c <= '9') v = (c - '0');
+    else if (c >= 'A' && c <= 'F') v = 10 + (c - 'A');
+    else if (c >= 'a' && c <= 'f') v = 10 + (c - 'a');
+    else
+    {
+      if (end)
+        *end = s;
+      return res;
+    }
+    if ((res & (UInt32)0xF << (32 - 4)) != 0)
+      return 0;
+    res <<= 4;
+    res |= v;
+  }
+}
+
+UInt64 ConvertHexStringToUInt64(const char *s, const char **end) throw()
+{
+  if (end)
+    *end = s;
+  UInt64 res = 0;
+  for (;; s++)
+  {
+    unsigned c = (Byte)*s;
+    unsigned v;
+    if (c >= '0' && c <= '9') v = (c - '0');
+    else if (c >= 'A' && c <= 'F') v = 10 + (c - 'A');
+    else if (c >= 'a' && c <= 'f') v = 10 + (c - 'a');
+    else
+    {
+      if (end)
+        *end = s;
+      return res;
+    }
+    if ((res & (UInt64)0xF << (64 - 4)) != 0)
+      return 0;
+    res <<= 4;
+    res |= v;
+  }
+}
diff --git a/CPP/Common/StringToInt.h b/CPP/Common/StringToInt.h
index 140d1ee..c9dce7d 100644
--- a/CPP/Common/StringToInt.h
+++ b/CPP/Common/StringToInt.h
@@ -1,21 +1,22 @@
-// Common/StringToInt.h

-

-#ifndef __COMMON_STRING_TO_INT_H

-#define __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 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();

-

-#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();
+
+#endif
diff --git a/CPP/Common/TextConfig.cpp b/CPP/Common/TextConfig.cpp
index f54aa3f..d3e561c 100644
--- a/CPP/Common/TextConfig.cpp
+++ b/CPP/Common/TextConfig.cpp
@@ -1,124 +1,124 @@
-// 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++)

-  {

-    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++)

-  {

-    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<CTextConfigPair> &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': message += '\n'; break;

-          case 't': message += '\t'; break;

-          case '\\': message += '\\'; break;

-          case '\"': message += '\"'; break;

-          default: message += '\\'; message += c; break;

-        }

-      }

-      else

-        message += c;

-    }

-    if (!ConvertUTF8ToUnicode(message, pair.String))

-      return false;

-    pairs.Add(pair);

-  }

-  return true;

-}

-

-int FindTextConfigItem(const CObjectVector<CTextConfigPair> &pairs, const char *id) throw()

-{

-  FOR_VECTOR (i, pairs)

-    if (pairs[i].ID.IsEqualTo(id))

-      return i;

-  return -1;

-}

-

-UString GetTextConfigValue(const CObjectVector<CTextConfigPair> &pairs, const char *id)

-{

-  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<CTextConfigPair> &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': message += '\n'; break;
+          case 't': message += '\t'; break;
+          case '\\': message += '\\'; break;
+          case '\"': message += '\"'; break;
+          default: message += '\\'; message += c; break;
+        }
+      }
+      else
+        message += c;
+    }
+    if (!ConvertUTF8ToUnicode(message, pair.String))
+      return false;
+    pairs.Add(pair);
+  }
+  return true;
+}
+
+int FindTextConfigItem(const CObjectVector<CTextConfigPair> &pairs, const char *id) throw()
+{
+  FOR_VECTOR (i, pairs)
+    if (pairs[i].ID.IsEqualTo(id))
+      return (int)i;
+  return -1;
+}
+
+UString GetTextConfigValue(const CObjectVector<CTextConfigPair> &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 c39e363..2263a44 100644
--- a/CPP/Common/TextConfig.h
+++ b/CPP/Common/TextConfig.h
@@ -1,19 +1,19 @@
-// Common/TextConfig.h

-

-#ifndef __COMMON_TEXT_CONFIG_H

-#define __COMMON_TEXT_CONFIG_H

-

-#include "MyString.h"

-

-struct CTextConfigPair

-{

-  UString ID;

-  UString String;

-};

-

-bool GetTextConfig(const AString &text, CObjectVector<CTextConfigPair> &pairs);

-

-int FindTextConfigItem(const CObjectVector<CTextConfigPair> &pairs, const char *id) throw();

-UString GetTextConfigValue(const CObjectVector<CTextConfigPair> &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<CTextConfigPair> &pairs);
+
+int FindTextConfigItem(const CObjectVector<CTextConfigPair> &pairs, const char *id) throw();
+UString GetTextConfigValue(const CObjectVector<CTextConfigPair> &pairs, const char *id);
+
+#endif
diff --git a/CPP/Common/UTFConvert.cpp b/CPP/Common/UTFConvert.cpp
index b09bbcd..fb166b7 100644
--- a/CPP/Common/UTFConvert.cpp
+++ b/CPP/Common/UTFConvert.cpp
@@ -1,288 +1,863 @@
-// UTFConvert.cpp

-

-#include "StdAfx.h"

-

-#include "MyTypes.h"

-#include "UTFConvert.h"

-

-#ifdef _WIN32

-#define _WCHART_IS_16BIT 1

-#endif

-

-/*

-  _UTF8_START(n) - is a base value for start byte (head), if there are (n) additional bytes after start byte

-  

-  n : _UTF8_START(n) : Bits of code point

-

-  0 : 0x80 :    : unused

-  1 : 0xC0 : 11 :

-  2 : 0xE0 : 16 : Basic Multilingual Plane

-  3 : 0xF0 : 21 : Unicode space

-  3 : 0xF8 : 26 :

-  5 : 0xFC : 31 : UCS-4

-  6 : 0xFE : 36 : We can use it, if we want to encode any 32-bit value

-  7 : 0xFF :

-*/

-

-#define _UTF8_START(n) (0x100 - (1 << (7 - (n))))

-

-#define _UTF8_HEAD_PARSE2(n) if (c < _UTF8_START((n) + 1)) { numBytes = (n); c -= _UTF8_START(n); }

-

-#define _UTF8_HEAD_PARSE \

-         _UTF8_HEAD_PARSE2(1) \

-    else _UTF8_HEAD_PARSE2(2) \

-    else _UTF8_HEAD_PARSE2(3) \

-    else _UTF8_HEAD_PARSE2(4) \

-    else _UTF8_HEAD_PARSE2(5) \

-

-    // else _UTF8_HEAD_PARSE2(6)

-

-bool CheckUTF8(const char *src, bool allowReduced) throw()

-{

-  for (;;)

-  {

-    Byte c = *src++;

-    if (c == 0)

-      return true;

-

-    if (c < 0x80)

-      continue;

-    if (c < 0xC0)   // (c < 0xC0 + 2) // if we support only optimal encoding chars

-      return false;

-    

-    unsigned numBytes;

-    _UTF8_HEAD_PARSE

-    else

-      return false;

-    

-    UInt32 val = c;

-

-    do

-    {

-      Byte c2 = *src++;

-      if (c2 < 0x80 || c2 >= 0xC0)

-        return allowReduced && c2 == 0;

-      val <<= 6;

-      val |= (c2 - 0x80);

-    }

-    while (--numBytes);

-    

-    if (val >= 0x110000)

-      return false;

-  }

-}

-

-

-#define _ERROR_UTF8 \

-  { if (dest) dest[destPos] = (wchar_t)0xFFFD; destPos++; ok = false; continue; }

-

-static bool Utf8_To_Utf16(wchar_t *dest, size_t *destLen, const char *src, const char *srcLim) throw()

-{

-  size_t destPos = 0;

-  bool ok = true;

-

-  for (;;)

-  {

-    Byte c;

-    if (src == srcLim)

-    {

-      *destLen = destPos;

-      return ok;

-    }

-    c = *src++;

-

-    if (c < 0x80)

-    {

-      if (dest)

-        dest[destPos] = (wchar_t)c;

-      destPos++;

-      continue;

-    }

-    if (c < 0xC0)

-      _ERROR_UTF8

-

-    unsigned numBytes;

-    _UTF8_HEAD_PARSE

-    else

-      _ERROR_UTF8

-    

-    UInt32 val = c;

-

-    do

-    {

-      Byte c2;

-      if (src == srcLim)

-        break;

-      c2 = *src;

-      if (c2 < 0x80 || c2 >= 0xC0)

-        break;

-      src++;

-      val <<= 6;

-      val |= (c2 - 0x80);

-    }

-    while (--numBytes);

-

-    if (numBytes != 0)

-      _ERROR_UTF8

-

-    if (val < 0x10000)

-    {

-      if (dest)

-        dest[destPos] = (wchar_t)val;

-      destPos++;

-    }

-    else

-    {

-      val -= 0x10000;

-      if (val >= 0x100000)

-        _ERROR_UTF8

-      if (dest)

-      {

-        dest[destPos + 0] = (wchar_t)(0xD800 + (val >> 10));

-        dest[destPos + 1] = (wchar_t)(0xDC00 + (val & 0x3FF));

-      }

-      destPos += 2;

-    }

-  }

-}

-

-#define _UTF8_RANGE(n) (((UInt32)1) << ((n) * 5 + 6))

-

-#define _UTF8_HEAD(n, val) ((char)(_UTF8_START(n) + (val >> (6 * (n)))))

-#define _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)

-{

-  size_t size = srcLim - src;

-  for (;;)

-  {

-    if (src == srcLim)

-      return size;

-    

-    UInt32 val = *src++;

-   

-    if (val < 0x80)

-      continue;

-

-    if (val < _UTF8_RANGE(1))

-    {

-      size++;

-      continue;

-    }

-

-    if (val >= 0xD800 && val < 0xDC00 && src != srcLim)

-    {

-      UInt32 c2 = *src;

-      if (c2 >= 0xDC00 && c2 < 0xE000)

-      {

-        src++;

-        size += 2;

-        continue;

-      }

-    }

-

-    #ifdef _WCHART_IS_16BIT

-    

-    size += 2;

-    

-    #else

-

-         if (val < _UTF8_RANGE(2)) size += 2;

-    else if (val < _UTF8_RANGE(3)) size += 3;

-    else if (val < _UTF8_RANGE(4)) size += 4;

-    else if (val < _UTF8_RANGE(5)) size += 5;

-    else                           size += 6;

-    

-    #endif

-  }

-}

-

-static char *Utf16_To_Utf8(char *dest, const wchar_t *src, const wchar_t *srcLim)

-{

-  for (;;)

-  {

-    if (src == srcLim)

-      return dest;

-    

-    UInt32 val = *src++;

-    

-    if (val < 0x80)

-    {

-      *dest++ = (char)val;

-      continue;

-    }

-

-    if (val < _UTF8_RANGE(1))

-    {

-      dest[0] = _UTF8_HEAD(1, val);

-      dest[1] = _UTF8_CHAR(0, val);

-      dest += 2;

-      continue;

-    }

-

-    if (val >= 0xD800 && val < 0xDC00 && src != srcLim)

-    {

-      UInt32 c2 = *src;

-      if (c2 >= 0xDC00 && c2 < 0xE000)

-      {

-        src++;

-        val = (((val - 0xD800) << 10) | (c2 - 0xDC00)) + 0x10000;

-        dest[0] = _UTF8_HEAD(3, val);

-        dest[1] = _UTF8_CHAR(2, val);

-        dest[2] = _UTF8_CHAR(1, val);

-        dest[3] = _UTF8_CHAR(0, val);

-        dest += 4;

-        continue;

-      }

-    }

-    

-    #ifndef _WCHART_IS_16BIT

-    if (val < _UTF8_RANGE(2))

-    #endif

-    {

-      dest[0] = _UTF8_HEAD(2, val);

-      dest[1] = _UTF8_CHAR(1, val);

-      dest[2] = _UTF8_CHAR(0, val);

-      dest += 3;

-      continue;

-    }

-    

-    #ifndef _WCHART_IS_16BIT

-

-    UInt32 b;

-    unsigned numBits;

-         if (val < _UTF8_RANGE(3)) { numBits = 6 * 3; b = _UTF8_HEAD(3, val); }

-    else if (val < _UTF8_RANGE(4)) { numBits = 6 * 4; b = _UTF8_HEAD(4, val); }

-    else if (val < _UTF8_RANGE(5)) { numBits = 6 * 5; b = _UTF8_HEAD(5, val); }

-    else                           { numBits = 6 * 6; b = _UTF8_START(6); }

-    

-    *dest++ = (Byte)b;

-    

-    do

-    {

-      numBits -= 6;

-      *dest++ = (char)(0x80 + ((val >> numBits) & 0x3F));

-    }

-    while (numBits != 0);

-

-    #endif

-  }

-}

-

-bool ConvertUTF8ToUnicode(const AString &src, UString &dest)

-{

-  dest.Empty();

-  size_t destLen = 0;

-  Utf8_To_Utf16(NULL, &destLen, src, src.Ptr(src.Len()));

-  bool res = Utf8_To_Utf16(dest.GetBuf((unsigned)destLen), &destLen, src, src.Ptr(src.Len()));

-  dest.ReleaseBuf_SetEnd((unsigned)destLen);

-  return res;

-}

-

-void ConvertUnicodeToUTF8(const UString &src, AString &dest)

-{

-  dest.Empty();

-  size_t destLen = Utf16_To_Utf8_Calc(src, src.Ptr(src.Len()));

-  Utf16_To_Utf8(dest.GetBuf((unsigned)destLen), src, src.Ptr(src.Len()));

-  dest.ReleaseBuf_SetEnd((unsigned)destLen);

-}

+// UTFConvert.cpp
+
+#include "StdAfx.h"
+
+// #include <stdio.h>
+
+#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) // it's limit for 0x140000 unicode codes : win32 compatibility
+      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(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 < 0x10000)
+      {
+        // 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 1183170..94a8024 100644
--- a/CPP/Common/UTFConvert.h
+++ b/CPP/Common/UTFConvert.h
@@ -1,12 +1,384 @@
-// Common/UTFConvert.h

-

-#ifndef __COMMON_UTF_CONVERT_H

-#define __COMMON_UTF_CONVERT_H

-

-#include "MyString.h"

-

-bool CheckUTF8(const char *src, bool allowReduced = false) throw();

-bool ConvertUTF8ToUnicode(const AString &utfString, UString &resultString);

-void ConvertUnicodeToUTF8(const UString &unicodeString, AString &resultString);

-

-#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 <stdio.h>
+
+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 43e4baa..798cbd9 100644
--- a/CPP/Common/Wildcard.cpp
+++ b/CPP/Common/Wildcard.cpp
@@ -1,676 +1,788 @@
-// Common/Wildcard.cpp

-

-#include "StdAfx.h"

-

-#include "Wildcard.h"

-

-bool g_CaseSensitive =

-  #ifdef _WIN32

-    false;

-  #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);

-}

-

-int CompareFileNames(const wchar_t *s1, const wchar_t *s2) STRING_UNICODE_THROW

-{

-  if (g_CaseSensitive)

-    return MyStringCompare(s1, s2);

-  return MyStringCompareNoCase(s1, s2);

-}

-

-#ifndef USE_UNICODE_FSTRING

-int CompareFileNames(const char *s1, const char *s2)

-{

-  const UString u1 = fs2us(s1);

-  const UString u2 = fs2us(s2);

-  if (g_CaseSensitive)

-    return MyStringCompare(u1, u2);

-  return MyStringCompareNoCase(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 (;;)

-  {

-    wchar_t m = *mask;

-    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(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<N   [0, M) ... [N-M-1, N-1)  same as ForBoth-File

-!ForFile nonrec         [0, M)                   same as ForBoth-File

-

-ForFile     rec   m<=N  [0, M) ... [N-M, N)      same as ForBoth-File

-ForDir   nonrec         [0, M)                   same as ForBoth-File

-

-*/

-

-bool CItem::AreAllAllowed() const

-{

-  return ForFile && ForDir && WildcardMatching && PathParts.Size() == 1 && PathParts.Front() == L"*";

-}

-

-bool CItem::CheckPath(const UStringVector &pathParts, bool isFile) const

-{

-  if (!isFile && !ForDir)

-    return false;

-

-  /*

-  if (PathParts.IsEmpty())

-  {

-    // PathParts.IsEmpty() means all items (universal wildcard)

-    if (!isFile)

-      return true;

-    if (pathParts.Size() <= 1)

-      return ForFile;

-    return (ForDir || Recursive && ForFile);

-  }

-  */

-

-  int delta = (int)pathParts.Size() - (int)PathParts.Size();

-  if (delta < 0)

-    return false;

-  int start = 0;

-  int finish = 0;

-  

-  if (isFile)

-  {

-    if (!ForDir)

-    {

-      if (Recursive)

-        start = delta;

-      else if (delta !=0)

-        return false;

-    }

-    if (!ForFile && delta == 0)

-      return false;

-  }

-  

-  if (Recursive)

-  {

-    finish = delta;

-    if (isFile && !ForFile)

-      finish = delta - 1;

-  }

-  

-  for (int d = start; d <= finish; d++)

-  {

-    unsigned i;

-    for (i = 0; i < PathParts.Size(); i++)

-    {

-      if (WildcardMatching)

-      {

-        if (!DoesWildcardMatchName(PathParts[i], pathParts[i + d]))

-          break;

-      }

-      else

-      {

-        if (CompareFileNames(PathParts[i], pathParts[i + d]) != 0)

-          break;

-      }

-    }

-    if (i == PathParts.Size())

-      return true;

-  }

-  return false;

-}

-

-bool CCensorNode::AreAllAllowed() const

-{

-  if (!Name.IsEmpty() ||

-      !SubNodes.IsEmpty() ||

-      !ExcludeItems.IsEmpty() ||

-      IncludeItems.Size() != 1)

-    return false;

-  return IncludeItems.Front().AreAllAllowed();

-}

-

-int CCensorNode::FindSubNode(const UString &name) const

-{

-  FOR_VECTOR (i, SubNodes)

-    if (CompareFileNames(SubNodes[i].Name, name) == 0)

-      return i;

-  return -1;

-}

-

-void CCensorNode::AddItemSimple(bool include, CItem &item)

-{

-  if (include)

-    IncludeItems.Add(item);

-  else

-    ExcludeItems.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;

-  }

-  int index = FindSubNode(front);

-  if (index < 0)

-    index = SubNodes.Add(CCensorNode(front, this));

-  item.PathParts.Delete(0);

-  SubNodes[index].AddItem(include, item, ignoreWildcardIndex - 1);

-}

-

-void CCensorNode::AddItem(bool include, const UString &path, bool recursive, bool forFile, bool forDir, bool wildcardMatching)

-{

-  CItem item;

-  SplitPathToParts(path, item.PathParts);

-  item.Recursive = recursive;

-  item.ForFile = forFile;

-  item.ForDir = forDir;

-  item.WildcardMatching = 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<CItem> &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;

-  }

-  include = true;

-  bool finded = CheckPathCurrent(true, pathParts, isFile);

-  if (pathParts.Size() <= 1)

-    return finded;

-  int index = FindSubNode(pathParts.Front());

-  if (index >= 0)

-  {

-    UStringVector pathParts2 = pathParts;

-    pathParts2.Delete(0);

-    if (SubNodes[index].CheckPathVect(pathParts2, isFile, include))

-      return true;

-  }

-  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(bool include, UStringVector &pathParts, bool isFile) const

-{

-  if (CheckPathCurrent(include, pathParts, isFile))

-    return true;

-  if (Parent == 0)

-    return false;

-  pathParts.Insert(0, Name);

-  return Parent->CheckPathToRoot(include, pathParts, isFile);

-}

-

-/*

-bool CCensorNode::CheckPathToRoot(bool include, const UString &path, bool isFile) const

-{

-  UStringVector pathParts;

-  SplitPathToParts(path, pathParts);

-  return CheckPathToRoot(include, pathParts, isFile);

-}

-*/

-

-void CCensorNode::AddItem2(bool include, const UString &path, bool recursive, bool wildcardMatching)

-{

-  if (path.IsEmpty())

-    return;

-  bool forFile = true;

-  bool forFolder = true;

-  UString path2 (path);

-  if (IsPathSepar(path.Back()))

-  {

-    path2.DeleteBack();

-    forFile = false;

-  }

-  AddItem(include, path2, recursive, forFile, forFolder, wildcardMatching);

-}

-

-void CCensorNode::ExtendExclude(const CCensorNode &fromNodes)

-{

-  ExcludeItems += fromNodes.ExcludeItems;

-  FOR_VECTOR (i, fromNodes.SubNodes)

-  {

-    const CCensorNode &node = fromNodes.SubNodes[i];

-    int subNodeIndex = FindSubNode(node.Name);

-    if (subNodeIndex < 0)

-      subNodeIndex = SubNodes.Add(CCensorNode(node.Name, this));

-    SubNodes[subNodeIndex].ExtendExclude(node);

-  }

-}

-

-int CCensor::FindPrefix(const UString &prefix) const

-{

-  FOR_VECTOR (i, Pairs)

-    if (CompareFileNames(Pairs[i].Prefix, prefix) == 0)

-      return i;

-  return -1;

-}

-

-#ifdef _WIN32

-

-bool IsDriveColonName(const wchar_t *s)

-{

-  wchar_t c = s[0];

-  return c != 0 && s[1] == ':' && s[2] == 0 && (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z');

-}

-

-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;

-  

-  #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, bool recursive, bool wildcardMatching)

-{

-  if (path.IsEmpty())

-    throw "Empty file path";

-

-  UStringVector pathParts;

-  SplitPathToParts(path, pathParts);

-

-  bool forFile = true;

-  if (pathParts.Back().IsEmpty())

-  {

-    forFile = false;

-    pathParts.DeleteBack();

-  }

-  

-  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)

-  {

-    ignoreWildcardIndex = -1;

-

-    const unsigned numPrefixParts = GetNumPrefixParts(pathParts);

-    unsigned numSkipParts = numPrefixParts;

-

-    if (pathMode != k_FullPath)

-    {

-      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 = i;

-      }

-

-      if (dotsIndex >= 0)

-        if (dotsIndex == (int)pathParts.Size() - 1)

-          numSkipParts = pathParts.Size();

-        else

-          numSkipParts = pathParts.Size() - 1;

-    }

-

-    for (unsigned i = 0; i < numSkipParts; i++)

-    {

-      {

-        const UString &front = pathParts.Front();

-        // WIN32 doesn't support wildcards in file names

-        if (wildcardMatching)

-          if (i >= numPrefixParts && DoesNameContainWildcard(front))

-            break;

-        prefix += front;

-        prefix.Add_PathSepar();

-      }

-      pathParts.Delete(0);

-    }

-  }

-

-  int index = FindPrefix(prefix);

-  if (index < 0)

-    index = Pairs.Add(CPair(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;

-      wildcardMatching = true;

-      recursive = false;

-    }

-  }

-

-  CItem item;

-  item.PathParts = pathParts;

-  item.ForDir = true;

-  item.ForFile = forFile;

-  item.Recursive = recursive;

-  item.WildcardMatching = wildcardMatching;

-  Pairs[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.Recursive, cp.WildcardMatching);

-  }

-  CensorPaths.Clear();

-}

-

-void CCensor::AddPreItem(bool include, const UString &path, bool recursive, bool wildcardMatching)

-{

-  CCensorPath &cp = CensorPaths.AddNew();

-  cp.Path = path;

-  cp.Include = include;

-  cp.Recursive = recursive;

-  cp.WildcardMatching = wildcardMatching;

-}

-

-}

+// 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 <stdio.h>
+
+/*
+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<N   [0, M) ... [N-M-1, N-1)  same as ForBoth-File
+!ForFile nonrec         [0, M)                   same as ForBoth-File
+
+ForFile     rec   m<=N  [0, M) ... [N-M, N)      same as ForBoth-File
+ForDir   nonrec         [0, M)                   same as ForBoth-File
+
+*/
+
+bool CItem::AreAllAllowed() const
+{
+  return ForFile && ForDir && WildcardMatching && PathParts.Size() == 1 && PathParts.Front() == L"*";
+}
+
+bool CItem::CheckPath(const UStringVector &pathParts, bool isFile) const
+{
+  if (!isFile && !ForDir)
+    return false;
+
+  /*
+  if (PathParts.IsEmpty())
+  {
+    // PathParts.IsEmpty() means all items (universal wildcard)
+    if (!isFile)
+      return true;
+    if (pathParts.Size() <= 1)
+      return ForFile;
+    return (ForDir || Recursive && ForFile);
+  }
+  */
+
+  int delta = (int)pathParts.Size() - (int)PathParts.Size();
+  if (delta < 0)
+    return false;
+  int start = 0;
+  int finish = 0;
+  
+  if (isFile)
+  {
+    if (!ForDir)
+    {
+      if (Recursive)
+        start = delta;
+      else if (delta !=0)
+        return false;
+    }
+    if (!ForFile && delta == 0)
+      return false;
+  }
+  
+  if (Recursive)
+  {
+    finish = delta;
+    if (isFile && !ForFile)
+      finish = delta - 1;
+  }
+  
+  for (int d = start; d <= finish; d++)
+  {
+    unsigned i;
+    for (i = 0; i < PathParts.Size(); i++)
+    {
+      if (WildcardMatching)
+      {
+        if (!DoesWildcardMatchName(PathParts[i], pathParts[i + (unsigned)d]))
+          break;
+      }
+      else
+      {
+        if (CompareFileNames(PathParts[i], pathParts[i + (unsigned)d]) != 0)
+          break;
+      }
+    }
+    if (i == PathParts.Size())
+      return true;
+  }
+  return false;
+}
+
+bool CCensorNode::AreAllAllowed() const
+{
+  if (!Name.IsEmpty() ||
+      !SubNodes.IsEmpty() ||
+      !ExcludeItems.IsEmpty() ||
+      IncludeItems.Size() != 1)
+    return false;
+  return IncludeItems.Front().AreAllAllowed();
+}
+
+int CCensorNode::FindSubNode(const UString &name) const
+{
+  FOR_VECTOR (i, SubNodes)
+    if (CompareFileNames(SubNodes[i].Name, name) == 0)
+      return (int)i;
+  return -1;
+}
+
+void CCensorNode::AddItemSimple(bool include, CItem &item)
+{
+  CObjectVector<CItem> &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<CItem> &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 6e5f013..4f81da9 100644
--- a/CPP/Common/Wildcard.h
+++ b/CPP/Common/Wildcard.h
@@ -1,149 +1,231 @@
-// Common/Wildcard.h

-

-#ifndef __COMMON_WILDCARD_H

-#define __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;

-};

-

-class CCensorNode

-{

-  CCensorNode *Parent;

-  

-  bool CheckPathCurrent(bool include, const UStringVector &pathParts, bool isFile) const;

-  void AddItemSimple(bool include, CItem &item);

-public:

-  bool CheckPathVect(const UStringVector &pathParts, bool isFile, bool &include) const;

-

-  CCensorNode(): Parent(0) { };

-  CCensorNode(const UString &name, CCensorNode *parent): Name(name), Parent(parent) { };

-

-  UString Name; // WIN32 doesn't support wildcards in file names

-  CObjectVector<CCensorNode> SubNodes;

-  CObjectVector<CItem> IncludeItems;

-  CObjectVector<CItem> ExcludeItems;

-

-  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, bool recursive, bool forFile, bool forDir, bool wildcardMatching);

-  void AddItem2(bool include, const UString &path, bool recursive, bool wildcardMatching);

-

-  bool NeedCheckSubDirs() const;

-  bool AreThereIncludeItems() const;

-

-  // bool CheckPath2(bool isAltStream, const UString &path, bool isFile, bool &include) const;

-  // bool CheckPath(bool isAltStream, const UString &path, bool isFile) const;

-

-  bool CheckPathToRoot(bool include, UStringVector &pathParts, bool isFile) const;

-  // bool CheckPathToRoot(const UString &path, bool isFile, bool include) const;

-  void ExtendExclude(const CCensorNode &fromNodes);

-};

-

-struct CPair

-{

-  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;

-  bool Recursive;

-  bool WildcardMatching;

-

-  CCensorPath():

-    Include(true),

-    Recursive(false),

-    WildcardMatching(true)

-    {}

-};

-

-class CCensor

-{

-  int FindPrefix(const UString &prefix) const;

-public:

-  CObjectVector<CPair> Pairs;

-

-  CObjectVector<NWildcard::CCensorPath> CensorPaths;

-  

-  bool AllAreRelative() const

-    { return (Pairs.Size() == 1 && Pairs.Front().Prefix.IsEmpty()); }

-  

-  void AddItem(ECensorPathMode pathMode, bool include, const UString &path, bool recursive, bool wildcardMatching);

-  // bool CheckPath(bool isAltStream, const UString &path, bool isFile) const;

-  void ExtendExclude();

-

-  void AddPathsToCensor(NWildcard::ECensorPathMode censorPathMode);

-  void AddPreItem(bool include, const UString &path, bool recursive, bool wildcardMatching);

-  void AddPreItem(const UString &path)

-  {

-    AddPreItem(true, path, false, false);

-  }

-  void AddPreItem_Wildcard()

-  {

-    AddPreItem(true, UString("*"), false, true);

-  }

-};

-

-

-}

-

-#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<CCensorNode> SubNodes;
+  CObjectVector<CItem> IncludeItems;
+  CObjectVector<CItem> 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<CPair> Pairs;
+
+  bool ExcludeDirItems;
+  bool ExcludeFileItems;
+
+  CCensor():
+      ExcludeDirItems(false),
+      ExcludeFileItems(false)
+      {}
+
+  CObjectVector<NWildcard::CCensorPath> 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/XzCrc64Init.cpp b/CPP/Common/XzCrc64Init.cpp
index 1eae72a..5cb8e67 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 92fce0a..e9e67ef 100644
--- a/CPP/Common/XzCrc64Reg.cpp
+++ b/CPP/Common/XzCrc64Reg.cpp
@@ -1,42 +1,39 @@
-// XzCrc64Reg.cpp

-

-#include "StdAfx.h"

-

-#include "../../C/CpuArch.h"

-#include "../../C/XzCrc64.h"

-

-#include "../Common/MyCom.h"

-

-#include "../7zip/Common/RegisterCodec.h"

-

-class CXzCrc64Hasher:

-  public IHasher,

-  public CMyUnknownImp

-{

-  UInt64 _crc;

-  Byte mtDummy[1 << 7];

-

-public:

-  CXzCrc64Hasher(): _crc(CRC64_INIT_VAL) {}

-

-  MY_UNKNOWN_IMP1(IHasher)

-  INTERFACE_IHasher(;)

-};

-

-STDMETHODIMP_(void) CXzCrc64Hasher::Init() throw()

-{

-  _crc = CRC64_INIT_VAL;

-}

-

-STDMETHODIMP_(void) CXzCrc64Hasher::Update(const void *data, UInt32 size) throw()

-{

-  _crc = Crc64Update(_crc, data, size);

-}

-

-STDMETHODIMP_(void) CXzCrc64Hasher::Final(Byte *digest) throw()

-{

-  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
new file mode 100644
index 0000000..d0cb321
--- /dev/null
+++ b/CPP/Windows/COM.cpp
@@ -0,0 +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);
+}
+
+}}
+
+*/
diff --git a/CPP/Windows/COM.h b/CPP/Windows/COM.h
index e2cb002..a8780ca 100644
--- a/CPP/Windows/COM.h
+++ b/CPP/Windows/COM.h
@@ -1,70 +1,86 @@
-// Windows/COM.h

-

-#ifndef __WINDOWS_COM_H

-#define __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 CStgMedium

-{

-  STGMEDIUM _object;

-public:

-  bool _mustBeReleased;

-  CStgMedium(): _mustBeReleased(false) {}

-  ~CStgMedium() { Free(); }

-  void Free()

-  {

-    if (_mustBeReleased)

-      ReleaseStgMedium(&_object);

-    _mustBeReleased = false;

-  }

-  const STGMEDIUM* operator->() const { return &_object;}

-  STGMEDIUM* operator->() { return &_object;}

-  STGMEDIUM* operator&() { return &_object; }

-};

-

-#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
new file mode 100644
index 0000000..bc7e201
--- /dev/null
+++ b/CPP/Windows/Clipboard.cpp
@@ -0,0 +1,130 @@
+// Windows/Clipboard.cpp
+
+#include "StdAfx.h"
+
+#ifdef UNDER_CE
+#include <winuserm.h>
+#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
new file mode 100644
index 0000000..3b4f2fe
--- /dev/null
+++ b/CPP/Windows/Clipboard.h
@@ -0,0 +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
diff --git a/CPP/Windows/CommonDialog.cpp b/CPP/Windows/CommonDialog.cpp
index 8b3828c..7a92d5f 100644
--- a/CPP/Windows/CommonDialog.cpp
+++ b/CPP/Windows/CommonDialog.cpp
@@ -1,185 +1,269 @@
-// Windows/CommonDialog.cpp

-

-#include "StdAfx.h"

-

-#include "../Common/MyWindows.h"

-

-#ifdef UNDER_CE

-#include <commdlg.h>

-#endif

-

-#ifndef _UNICODE

-#include "../Common/StringConvert.h"

-#endif

-

-#include "CommonDialog.h"

-#include "Defs.h"

-

-#ifndef _UNICODE

-extern bool g_IsNT;

-#endif

-

-namespace NWindows {

-

-#ifndef _UNICODE

-

-class CDoubleZeroStringListA

-{

-  LPTSTR Buf;

-  unsigned Size;

-public:

-  CDoubleZeroStringListA(LPSTR buf, unsigned size): Buf(buf), Size(size) {}

-  bool Add(LPCSTR s) throw();

-  void Finish() { *Buf = 0; }

-};

-

-bool CDoubleZeroStringListA::Add(LPCSTR s) throw()

-{

-  unsigned len = MyStringLen(s) + 1;

-  if (len >= Size)

-    return false;

-  MyStringCopy(Buf, s);

-  Buf += len;

-  Size -= len;

-  return true;

-}

-

-#endif

-

-class CDoubleZeroStringListW

-{

-  LPWSTR Buf;

-  unsigned Size;

-public:

-  CDoubleZeroStringListW(LPWSTR buf, unsigned size): Buf(buf), Size(size) {}

-  bool Add(LPCWSTR s) throw();

-  void Finish() { *Buf = 0; }

-};

-

-bool CDoubleZeroStringListW::Add(LPCWSTR s) throw()

-{

-  unsigned len = MyStringLen(s) + 1;

-  if (len >= Size)

-    return false;

-  MyStringCopy(Buf, s);

-  Buf += len;

-  Size -= len;

-  return true;

-}

-

-#define MY__OFN_PROJECT  0x00400000

-#define MY__OFN_SHOW_ALL 0x01000000

-

-/* if (lpstrFilter == NULL && nFilterIndex == 0)

-  MSDN : "the system doesn't show any files",

-  but WinXP-64 shows all files. Why ??? */

-

-/*

-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*).

-So we use size of old version of structure. */

-

-#if defined(UNDER_CE) || defined(_WIN64) || (_WIN32_WINNT < 0x0500)

-// || !defined(WINVER)

-  #define my_compatib_OPENFILENAMEA_size sizeof(OPENFILENAMEA)

-  #define my_compatib_OPENFILENAMEW_size sizeof(OPENFILENAMEW)

-#else

-  #define my_compatib_OPENFILENAMEA_size OPENFILENAME_SIZE_VERSION_400A

-  #define my_compatib_OPENFILENAMEW_size OPENFILENAME_SIZE_VERSION_400W

-#endif

-

-#define CONV_U_To_A(dest, src, temp) AString temp; if (src) { temp = GetSystemString(src); dest = temp; }

-

-bool MyGetOpenFileName(HWND hwnd, LPCWSTR title,

-    LPCWSTR initialDir,

-    LPCWSTR filePath,

-    LPCWSTR filterDescription,

-    LPCWSTR filter,

-    UString &resPath

-    #ifdef UNDER_CE

-    , bool openFolder

-    #endif

-    )

-{

-  const unsigned kBufSize = MAX_PATH * 2;

-  const unsigned kFilterBufSize = MAX_PATH;

-  if (!filter)

-    filter = L"*.*";

-  #ifndef _UNICODE

-  if (!g_IsNT)

-  {

-    CHAR buf[kBufSize];

-    MyStringCopy(buf, (const char *)GetSystemString(filePath));

-    // OPENFILENAME_NT4A

-    OPENFILENAMEA p;

-    memset(&p, 0, sizeof(p));

-    p.lStructSize = my_compatib_OPENFILENAMEA_size;

-    p.hwndOwner = hwnd;

-    CHAR filterBuf[kFilterBufSize];

-    {

-      CDoubleZeroStringListA dz(filterBuf, kFilterBufSize);

-      dz.Add(GetSystemString(filterDescription ? filterDescription : filter));

-      dz.Add(GetSystemString(filter));

-      dz.Finish();

-      p.lpstrFilter = filterBuf;

-      p.nFilterIndex = 1;

-    }

-    

-    p.lpstrFile = buf;

-    p.nMaxFile = kBufSize;

-    CONV_U_To_A(p.lpstrInitialDir, initialDir, initialDirA);

-    CONV_U_To_A(p.lpstrTitle, title, titleA);

-    p.Flags = OFN_EXPLORER | OFN_HIDEREADONLY;

-

-    bool res = BOOLToBool(::GetOpenFileNameA(&p));

-    resPath = GetUnicodeString(buf);

-    return res;

-  }

-  else

-  #endif

-  {

-    WCHAR buf[kBufSize];

-    MyStringCopy(buf, filePath);

-    // OPENFILENAME_NT4W

-    OPENFILENAMEW p;

-    memset(&p, 0, sizeof(p));

-    p.lStructSize = my_compatib_OPENFILENAMEW_size;

-    p.hwndOwner = hwnd;

-    

-    WCHAR filterBuf[kFilterBufSize];

-    {

-      CDoubleZeroStringListW dz(filterBuf, kFilterBufSize);

-      dz.Add(filterDescription ? filterDescription : filter);

-      dz.Add(filter);

-      dz.Finish();

-      p.lpstrFilter = filterBuf;

-      p.nFilterIndex = 1;

-    }

-        

-    p.lpstrFile = buf;

-    p.nMaxFile = kBufSize;

-    p.lpstrInitialDir = initialDir;

-    p.lpstrTitle = title;

-    p.Flags = OFN_EXPLORER | OFN_HIDEREADONLY

-        #ifdef UNDER_CE

-        | (openFolder ? (MY__OFN_PROJECT | MY__OFN_SHOW_ALL) : 0)

-        #endif

-        ;

-

-    bool res = BOOLToBool(::GetOpenFileNameW(&p));

-    resPath = buf;

-    return res;

-  }

-}

-

-}

+// Windows/CommonDialog.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/MyBuffer.h"
+
+#ifdef UNDER_CE
+#include <commdlg.h>
+#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<char> 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<wchar_t> 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 2bfec28..85b071f 100644
--- a/CPP/Windows/CommonDialog.h
+++ b/CPP/Windows/CommonDialog.h
@@ -1,23 +1,43 @@
-// Windows/CommonDialog.h

-

-#ifndef __WINDOWS_COMMON_DIALOG_H

-#define __WINDOWS_COMMON_DIALOG_H

-

-#include "../Common/MyString.h"

-

-namespace NWindows {

-

-bool MyGetOpenFileName(HWND hwnd, LPCWSTR title,

-    LPCWSTR initialDir,  // can be NULL, so dir prefix in filePath will be used

-    LPCWSTR filePath,    // full path

-    LPCWSTR filterDescription,  // like "All files (*.*)"

-    LPCWSTR filter,             // like "*.exe"

-    UString &resPath

-    #ifdef UNDER_CE

-    , bool openFolder = false

-    #endif

-);

-

-}

-

-#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
new file mode 100644
index 0000000..28ba1c4
--- /dev/null
+++ b/CPP/Windows/Console.cpp
@@ -0,0 +1,10 @@
+// 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
new file mode 100644
index 0000000..818b8d4
--- /dev/null
+++ b/CPP/Windows/Console.h
@@ -0,0 +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
diff --git a/CPP/Windows/Control/ComboBox.cpp b/CPP/Windows/Control/ComboBox.cpp
index 6ab4717..8da487d 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, index, 0);

-    if (len == CB_ERR)

-      return len;

-    LRESULT len2 = SendMsgW(CB_GETLBTEXT, 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;

-  LRESULT len = GetLBText(index, sa);

-  if (len == CB_ERR)

-    return len;

-  s = GetUnicodeString(sa);

-  return 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 3439655..2a60b8a 100644
--- a/CPP/Windows/Control/ComboBox.h
+++ b/CPP/Windows/Control/ComboBox.h
@@ -1,65 +1,77 @@
-// Windows/Control/ComboBox.h

-

-#ifndef __WINDOWS_CONTROL_COMBOBOX_H

-#define __WINDOWS_CONTROL_COMBOBOX_H

-

-#include "../../Common/MyWindows.h"

-

-#include <commctrl.h>

-

-#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

-  LRESULT SetCurSel(int index) { return SendMsg(CB_SETCURSEL, index, 0); }

-  int GetCurSel() { return (int)SendMsg(CB_GETCURSEL, 0, 0); }

-  int GetCount() { return (int)SendMsg(CB_GETCOUNT, 0, 0); }

-  

-  LRESULT GetLBTextLen(int index) { return SendMsg(CB_GETLBTEXTLEN, index, 0); }

-  LRESULT GetLBText(int index, LPTSTR s) { return SendMsg(CB_GETLBTEXT, 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, index, lParam); }

-  LRESULT GetItemData(int 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)); }

-

-  LRESULT DeleteItem(int index) { return SendMsg(CBEM_DELETEITEM, 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, 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 <CommCtrl.h>
+
+#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 c435568..d1b2f17 100644
--- a/CPP/Windows/Control/CommandBar.h
+++ b/CPP/Windows/Control/CommandBar.h
@@ -1,52 +1,52 @@
-// Windows/Control/CommandBar.h

-  

-#ifndef __WINDOWS_CONTROL_COMMANDBAR_H

-#define __WINDOWS_CONTROL_COMMANDBAR_H

-

-#ifdef UNDER_CE

-

-#include "../../Common/MyWindows.h"

-

-#include <commctrl.h>

-

-#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(int 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 <commctrl.h>
+
+#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 8e61a2b..c8f1bd2 100644
--- a/CPP/Windows/Control/Dialog.cpp
+++ b/CPP/Windows/Control/Dialog.cpp
@@ -1,251 +1,445 @@
-// Windows/Control/Dialog.cpp

-

-#include "StdAfx.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 INT_PTR 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);

-  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(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_HELP: OnHelp(); return true;

-    /*

-        OnHelp(

-          #ifdef UNDER_CE

-          (void *)

-          #else

-          (LPHELPINFO)

-          #endif

-          lParam);

-        return true;

-    */

-    default: return false;

-  }

-}

-

-bool CDialog::OnCommand(WPARAM wParam, LPARAM lParam)

-{

-  return OnCommand(HIWORD(wParam), LOWORD(wParam), lParam);

-}

-

-bool CDialog::OnCommand(int code, int itemID, LPARAM lParam)

-{

-  if (code == BN_CLICKED)

-    return OnButtonClicked(itemID, (HWND)lParam);

-  return false;

-}

-

-bool CDialog::OnButtonClicked(int buttonID, HWND /* buttonHWND */)

-{

-  switch (buttonID)

-  {

-    case IDOK: OnOK(); break;

-    case IDCANCEL: OnCancel(); break;

-    case IDCLOSE: OnClose(); break;

-    case IDHELP: OnHelp(); break;

-    default: return false;

-  }

-  return true;

-}

-

-static bool GetWorkAreaRect(RECT *rect)

-{

-  // use another function for multi-monitor.

-  return BOOLToBool(::SystemParametersInfo(SPI_GETWORKAREA, 0, rect, 0));

-}

-

-bool IsDialogSizeOK(int xSize, int ySize)

-{

-  // it returns for system font. Real font uses another values

-  LONG v = GetDialogBaseUnits();

-  int x = LOWORD(v);

-  int y = HIWORD(v);

-

-  RECT rect;

-  GetWorkAreaRect(&rect);

-  int wx = RECT_SIZE_X(rect);

-  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(int 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(int id, RECT &rect)

-{

-  ::GetWindowRect(GetItem(id), &rect);

-  ScreenToClient(&rect);

-}

-

-bool CDialog::MoveItem(int id, int x, int y, int width, int height, bool repaint)

-{

-  return BOOLToBool(::MoveWindow(GetItem(id), x, y, width, height, BoolToBOOL(repaint)));

-}

-

-void CDialog::NormalizeSize(bool fullNormalize)

-{

-  RECT workRect;

-  GetWorkAreaRect(&workRect);

-  int xSize = RECT_SIZE_X(workRect);

-  int ySize = RECT_SIZE_Y(workRect);

-  RECT rect;

-  GetWindowRect(&rect);

-  int xSize2 = RECT_SIZE_X(rect);

-  int ySize2 = RECT_SIZE_Y(rect);

-  bool needMove = (xSize2 > xSize || ySize2 > ySize);

-  if (xSize2 > xSize || (needMove && fullNormalize))

-  {

-    rect.left = workRect.left;

-    rect.right = workRect.right;

-    xSize2 = xSize;

-  }

-  if (ySize2 > ySize || (needMove && fullNormalize))

-  {

-    rect.top = workRect.top;

-    rect.bottom = workRect.bottom;

-    ySize2 = ySize;

-  }

-  if (needMove)

-  {

-    if (fullNormalize)

-      Show(SW_SHOWMAXIMIZED);

-    else

-      Move(rect.left, rect.top, xSize2, ySize2, true);

-  }

-}

-

-void CDialog::NormalizePosition()

-{

-  RECT workRect, rect;

-  GetWorkAreaRect(&workRect);

-  GetWindowRect(&rect);

-  if (rect.bottom > workRect.bottom && rect.top > workRect.top)

-    Move(rect.left, workRect.top, RECT_SIZE_X(rect), RECT_SIZE_Y(rect), true);

-}

-

-bool CModelessDialog::Create(LPCTSTR templateName, HWND parentWindow)

-{

-  HWND aHWND = CreateDialogParam(g_hInstance, templateName, parentWindow, DialogProcedure, (LPARAM)this);

-  if (aHWND == 0)

-    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 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 f9c3442..06be4bf 100644
--- a/CPP/Windows/Control/Dialog.h
+++ b/CPP/Windows/Control/Dialog.h
@@ -1,170 +1,194 @@
-// Windows/Control/Dialog.h

-

-#ifndef __WINDOWS_CONTROL_DIALOG_H

-#define __WINDOWS_CONTROL_DIALOG_H

-

-#include "../Window.h"

-

-namespace NWindows {

-namespace NControl {

-

-class CDialog: public CWindow

-{

-public:

-  CDialog(HWND wnd = NULL): CWindow(wnd){};

-  virtual ~CDialog() {};

-

-  HWND GetItem(int itemID) const

-    { return GetDlgItem(_window, itemID); }

-

-  bool EnableItem(int itemID, bool enable) const

-    { return BOOLToBool(::EnableWindow(GetItem(itemID), BoolToBOOL(enable))); }

-

-  bool ShowItem(int itemID, int cmdShow) const

-    { return BOOLToBool(::ShowWindow(GetItem(itemID), cmdShow)); }

-

-  bool ShowItem_Bool(int itemID, bool show) const

-    { return ShowItem(itemID, show ? SW_SHOW: SW_HIDE); }

-

-  bool HideItem(int itemID) const { return ShowItem(itemID, SW_HIDE); }

-

-  bool SetItemText(int itemID, LPCTSTR s)

-    { return BOOLToBool(SetDlgItemText(_window, itemID, s)); }

-

-  #ifndef _UNICODE

-  bool SetItemText(int itemID, LPCWSTR s)

-  {

-    CWindow window(GetItem(itemID));

-    return window.SetText(s);

-  }

-  #endif

-

-  UINT GetItemText(int itemID, LPTSTR string, int maxCount)

-    { return GetDlgItemText(_window, itemID, string, maxCount); }

-  #ifndef _UNICODE

-  /*

-  bool GetItemText(int itemID, LPWSTR string, int maxCount)

-  {

-    CWindow window(GetItem(itemID));

-    return window.GetText(string, maxCount);

-  }

-  */

-  #endif

-

-  bool SetItemInt(int itemID, UINT value, bool isSigned)

-    { return BOOLToBool(SetDlgItemInt(_window, itemID, value, BoolToBOOL(isSigned))); }

-  bool GetItemInt(int itemID, bool isSigned, UINT &value)

-  {

-    BOOL result;

-    value = GetDlgItemInt(_window, itemID, &result, BoolToBOOL(isSigned));

-    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)); }

-

-  bool MapRect(LPRECT rect)

-    { return BOOLToBool(MapDialogRect(_window, rect)); }

-

-  bool IsMessage(LPMSG message)

-    { return BOOLToBool(IsDialogMessage(_window, message)); }

-

-  LRESULT SendItemMessage(int itemID, UINT message, WPARAM wParam, LPARAM lParam)

-    { return SendDlgItemMessage(_window, itemID, message, wParam, lParam); }

-

-  bool CheckButton(int buttonID, UINT checkState)

-    { return BOOLToBool(CheckDlgButton(_window, buttonID, checkState)); }

-  bool CheckButton(int buttonID, bool checkState)

-    { return CheckButton(buttonID, UINT(checkState ? BST_CHECKED : BST_UNCHECKED)); }

-

-  UINT IsButtonChecked(int buttonID) const

-    { return IsDlgButtonChecked(_window, buttonID); }

-  bool IsButtonCheckedBool(int buttonID) const

-    { return (IsButtonChecked(buttonID) == BST_CHECKED); }

-

-  bool CheckRadioButton(int firstButtonID, int lastButtonID, int checkButtonID)

-    { return BOOLToBool(::CheckRadioButton(_window, firstButtonID, lastButtonID, checkButtonID)); }

-

-  virtual bool OnMessage(UINT message, WPARAM wParam, LPARAM lParam);

-  virtual bool OnInit() { return true; }

-  virtual bool OnCommand(WPARAM wParam, LPARAM lParam);

-  virtual bool OnCommand(int code, int itemID, LPARAM lParam);

-  virtual bool OnSize(WPARAM /* wParam */, int /* xSize */, int /* ySize */) { return false; }

-

-  /*

-  #ifdef UNDER_CE

-  virtual void OnHelp(void *) { OnHelp(); }

-  #else

-  virtual void OnHelp(LPHELPINFO) { OnHelp(); }

-  #endif

-  */

-  virtual void OnHelp() {};

-

-  virtual bool OnButtonClicked(int buttonID, HWND buttonHWND);

-  virtual void OnOK() {};

-  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(int id, int &x, int &y);

-  void GetClientRectOfItem(int id, RECT &rect);

-  bool MoveItem(int id, int x, int y, int width, int height, bool repaint = true);

-

-  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() { Destroy(); }

-  virtual void OnCancel() { Destroy(); }

-  virtual void OnClose() { 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() { End(IDOK); }

-  virtual void OnCancel() { End(IDCANCEL); }

-  virtual void OnClose() { End(IDCLOSE); }

-};

-

-class CDialogChildControl: public NWindows::CWindow

-{

-  int m_ID;

-public:

-  void Init(const NWindows::NControl::CDialog &parentDialog, int id)

-  {

-    m_ID = id;

-    Attach(parentDialog.GetItem(id));

-  }

-};

-

-bool IsDialogSizeOK(int xSize, int ySize);

-

-}}

-

-#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 {
+
+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 GetItemInt(unsigned itemID, bool isSigned, UINT &value)
+  {
+    BOOL result;
+    value = GetDlgItemInt(_window, (int)itemID, &result, BoolToBOOL(isSigned));
+    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 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 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 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 4f503aa..963470d 100644
--- a/CPP/Windows/Control/Edit.h
+++ b/CPP/Windows/Control/Edit.h
@@ -1,19 +1,19 @@
-// Windows/Control/Edit.h

-

-#ifndef __WINDOWS_CONTROL_EDIT_H

-#define __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 d201c8f..3e22b95 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 f72ea0d..688f177 100644
--- a/CPP/Windows/Control/ImageList.h
+++ b/CPP/Windows/Control/ImageList.h
@@ -1,87 +1,87 @@
-// Windows/Control/ImageList.h

-

-#ifndef __WINDOWS_CONTROL_IMAGE_LIST_H

-#define __WINDOWS_CONTROL_IMAGE_LIST_H

-

-#include <commctrl.h>

-

-#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 = 0)

-    { 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 <CommCtrl.h>
+
+#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 fb22f95..3e8786a 100644
--- a/CPP/Windows/Control/ListView.cpp
+++ b/CPP/Windows/Control/ListView.cpp
@@ -1,155 +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);

-}

-

-bool CListView::GetItemParam(int index, LPARAM &param) const

-{

-  LVITEM item;

-  item.iItem = index;

-  item.iSubItem = 0;

-  item.mask = LVIF_PARAM;

-  bool aResult = GetItem(&item);

-  param = item.lParam;

-  return aResult;

-}

-

-int CListView::InsertColumn(int columnIndex, LPCTSTR text, int width)

-{

-  LVCOLUMN ci;

-  ci.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;

-  ci.pszText = (LPTSTR)text;

-  ci.iSubItem = columnIndex;

-  ci.cx = width;

-  return InsertColumn(columnIndex, &ci);

-}

-

-int CListView::InsertItem(int index, LPCTSTR text)

-{

-  LVITEM item;

-  item.mask = LVIF_TEXT | LVIF_PARAM;

-  item.iItem = index;

-  item.lParam = index;

-  item.pszText = (LPTSTR)text;

-  item.iSubItem = 0;

-  return InsertItem(&item);

-}

-

-int CListView::SetSubItem(int index, int subIndex, LPCTSTR text)

-{

-  LVITEM item;

-  item.mask = LVIF_TEXT;

-  item.iItem = index;

-  item.pszText = (LPTSTR)text;

-  item.iSubItem = subIndex;

-  return SetItem(&item);

-}

-

-#ifndef _UNICODE

-

-int CListView::InsertColumn(int columnIndex, LPCWSTR text, int width)

-{

-  LVCOLUMNW ci;

-  ci.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;

-  ci.pszText = (LPWSTR)text;

-  ci.iSubItem = columnIndex;

-  ci.cx = width;

-  return InsertColumn(columnIndex, &ci);

-}

-

-int CListView::InsertItem(int index, LPCWSTR text)

-{

-  LVITEMW item;

-  item.mask = LVIF_TEXT | LVIF_PARAM;

-  item.iItem = index;

-  item.lParam = index;

-  item.pszText = (LPWSTR)text;

-  item.iSubItem = 0;

-  return InsertItem(&item);

-}

-

-int CListView::SetSubItem(int index, int subIndex, LPCWSTR text)

-{

-  LVITEMW item;

-  item.mask = LVIF_TEXT;

-  item.iItem = index;

-  item.pszText = (LPWSTR)text;

-  item.iSubItem = 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 &param) 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 1ed496d..11a33a0 100644
--- a/CPP/Windows/Control/ListView.h
+++ b/CPP/Windows/Control/ListView.h
@@ -1,146 +1,156 @@
-// Windows/Control/ListView.h

-

-#ifndef __WINDOWS_CONTROL_LISTVIEW_H

-#define __WINDOWS_CONTROL_LISTVIEW_H

-

-#include "../../Common/MyWindows.h"

-

-#include <commctrl.h>

-

-#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(int columnIndex) { return BOOLToBool(ListView_DeleteColumn(_window, columnIndex)); }

-

-  int InsertColumn(int columnIndex, const LVCOLUMN *columnInfo) { return ListView_InsertColumn(_window, columnIndex, columnInfo); }

-  int InsertColumn(int columnIndex, LPCTSTR text, int width);

-  bool SetColumnOrderArray(int count, const int *columns) { return BOOLToBool(ListView_SetColumnOrderArray(_window, count, 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(int index, LPCTSTR text);

-  bool SetItem(const LVITEM* item) { return BOOLToBool(ListView_SetItem(_window, item)); }

-  int SetSubItem(int index, int subIndex, LPCTSTR text);

-

-  #ifndef _UNICODE

-

-  int InsertColumn(int columnIndex, const LVCOLUMNW *columnInfo) { return (int)SendMsg(LVM_INSERTCOLUMNW, (WPARAM)columnIndex, (LPARAM)columnInfo); }

-  int InsertColumn(int columnIndex, LPCWSTR text, int width);

-  int InsertItem(const LV_ITEMW* item) { return (int)SendMsg(LVM_INSERTITEMW, 0, (LPARAM)item); }

-  int InsertItem(int index, LPCWSTR text);

-  bool SetItem(const LV_ITEMW* item) { return BOOLToBool((BOOL)SendMsg(LVM_SETITEMW, 0, (LPARAM)item)); }

-  int SetSubItem(int index, int subIndex, LPCWSTR text);

-

-  #endif

-

-  bool DeleteItem(int 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(int numItems) { ListView_SetItemCount(_window, numItems); }

-  void SetItemCountEx(int numItems, DWORD flags) {  ListView_SetItemCountEx(_window, numItems, flags); }

-

-  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(int itemIndex, LPARAM &param) const;

-  void GetItemText(int itemIndex, int subItemIndex, LPTSTR text, int textSizeMax) const

-    { ListView_GetItemText(_window, itemIndex, subItemIndex, text, textSizeMax); }

-  bool SortItems(PFNLVCOMPARE compareFunction, LPARAM dataParam)

-    { return BOOLToBool(ListView_SortItems(_window, compareFunction, dataParam)); }

-

-  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(int 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;

-public:

-  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 <CommCtrl.h>
+
+#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 &param) 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 f18d89c..2256aa9 100644
--- a/CPP/Windows/Control/ProgressBar.h
+++ b/CPP/Windows/Control/ProgressBar.h
@@ -1,35 +1,35 @@
-// Windows/Control/ProgressBar.h

-

-#ifndef __WINDOWS_CONTROL_PROGRESSBAR_H

-#define __WINDOWS_CONTROL_PROGRESSBAR_H

-

-#include "../../Common/MyWindows.h"

-

-#include <commctrl.h>

-

-#include "../Window.h"

-

-namespace NWindows {

-namespace NControl {

-

-class CProgressBar: public CWindow

-{

-public:

-  LRESULT SetPos(int pos) { return SendMsg(PBM_SETPOS, 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, minValue, 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, color); }

-  COLORREF SetBackgroundColor(COLORREF color) { return (COLORREF)SendMsg(PBM_SETBKCOLOR, 0, 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 <CommCtrl.h>
+
+#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 48947c0..f8effe6 100644
--- a/CPP/Windows/Control/PropertyPage.cpp
+++ b/CPP/Windows/Control/PropertyPage.cpp
@@ -1,143 +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 INT_PTR 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(OnApply(LPPSHNOTIFY(lParam))); break;

-    case PSN_KILLACTIVE: SetMsgResult(BoolToBOOL(OnKillActive(LPPSHNOTIFY(lParam)))); break;

-    case PSN_SETACTIVE: SetMsgResult(OnSetActive(LPPSHNOTIFY(lParam))); break;

-    case PSN_RESET: OnReset(LPPSHNOTIFY(lParam)); break;

-    case PSN_HELP: OnNotifyHelp(LPPSHNOTIFY(lParam)); break;

-    default: return false;

-  }

-  return true;

-}

-

-INT_PTR MyPropertySheet(const CObjectVector<CPageInfo> &pagesInfo, HWND hwndParent, const UString &title)

-{

-  #ifndef _UNICODE

-  AStringVector titles;

-  #endif

-  #ifndef _UNICODE

-  CRecordVector<PROPSHEETPAGEA> pagesA;

-  #endif

-  CRecordVector<PROPSHEETPAGEW> pagesW;

-

-  unsigned i;

-  #ifndef _UNICODE

-  for (i = 0; i < pagesInfo.Size(); i++)

-    titles.Add(GetSystemString(pagesInfo[i].Title));

-  #endif

-

-  for (i = 0; i < pagesInfo.Size(); i++)

-  {

-    const CPageInfo &pageInfo = pagesInfo[i];

-    #ifndef _UNICODE

-    {

-      PROPSHEETPAGE page;

-      page.dwSize = sizeof(page);

-      page.dwFlags = PSP_HASHELP;

-      page.hInstance = g_hInstance;

-      page.pszTemplate = MAKEINTRESOURCE(pageInfo.ID);

-      page.pszIcon = NULL;

-      page.pfnDlgProc = NWindows::NControl::MyProperyPageProcedure;

-      

-      if (titles[i].IsEmpty())

-        page.pszTitle = NULL;

-      else

-      {

-        page.dwFlags |= PSP_USETITLE;

-        page.pszTitle = titles[i];

-      }

-      page.lParam = (LPARAM)pageInfo.Page;

-      page.pfnCallback = NULL;

-      pagesA.Add(page);

-    }

-    #endif

-    {

-      PROPSHEETPAGEW 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 = NULL;

-      else

-      {

-        page.dwFlags |= PSP_USETITLE;

-        page.pszTitle = pageInfo.Title;

-      }

-      page.lParam = (LPARAM)pageInfo.Page;

-      page.pfnCallback = NULL;

-      pagesW.Add(page);

-    }

-  }

-

-  #ifndef _UNICODE

-  if (!g_IsNT)

-  {

-    PROPSHEETHEADER 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 = pagesInfo.Size();

-    sheet.nStartPage = 0;

-    sheet.ppsp = &pagesA.Front();

-    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 = pagesInfo.Size();

-    sheet.nStartPage = 0;

-    sheet.ppsp = &pagesW.Front();

-    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<CPageInfo> &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<my_compatib_PROPSHEETPAGEA> pagesA;
+  #endif
+  CRecordVector<my_compatib_PROPSHEETPAGEW> 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.Front();
+    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.Front();
+    sheet.pfnCallback = NULL;
+    return ::PropertySheetW(&sheet);
+  }
+}
+
+}}
diff --git a/CPP/Windows/Control/PropertyPage.h b/CPP/Windows/Control/PropertyPage.h
index 551c959..264a5d2 100644
--- a/CPP/Windows/Control/PropertyPage.h
+++ b/CPP/Windows/Control/PropertyPage.h
@@ -1,50 +1,50 @@
-// Windows/Control/PropertyPage.h

-

-#ifndef __WINDOWS_CONTROL_PROPERTYPAGE_H

-#define __WINDOWS_CONTROL_PROPERTYPAGE_H

-

-#include "../../Common/MyWindows.h"

-

-#include <prsht.h>

-

-#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);

-

-  virtual bool OnKillActive() { return false; } // false = OK

-  virtual bool OnKillActive(const PSHNOTIFY *) { return OnKillActive(); }

-  virtual LONG OnSetActive() { return false; } // false = OK

-  virtual LONG OnSetActive(const PSHNOTIFY *) { return OnSetActive(); }

-  virtual LONG OnApply() { return PSNRET_NOERROR; }

-  virtual LONG OnApply(const PSHNOTIFY *) { return OnApply(); }

-  virtual void OnNotifyHelp() {}

-  virtual void OnNotifyHelp(const PSHNOTIFY *) { OnNotifyHelp(); }

-  virtual void OnReset() {}

-  virtual void OnReset(const PSHNOTIFY *) { OnReset(); }

-};

-

-struct CPageInfo

-{

-  CPropertyPage *Page;

-  UString Title;

-  UINT ID;

-};

-

-INT_PTR MyPropertySheet(const CObjectVector<CPageInfo> &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 <prsht.h>
+
+#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<CPageInfo> &pagesInfo, HWND hwndParent, const UString &title);
+
+}}
+
+#endif
diff --git a/CPP/Windows/Control/ReBar.h b/CPP/Windows/Control/ReBar.h
index 26fa311..b56f018 100644
--- a/CPP/Windows/Control/ReBar.h
+++ b/CPP/Windows/Control/ReBar.h
@@ -1,34 +1,34 @@
-// Windows/Control/ReBar.h

-  

-#ifndef __WINDOWS_CONTROL_REBAR_H

-#define __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, 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 936dd3c..ceeedf9 100644
--- a/CPP/Windows/Control/Static.h
+++ b/CPP/Windows/Control/Static.h
@@ -1,28 +1,28 @@
-// Windows/Control/Static.h

-

-#ifndef __WINDOWS_CONTROL_STATIC_H

-#define __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 7f7d66b..38aca47 100644
--- a/CPP/Windows/Control/StatusBar.h
+++ b/CPP/Windows/Control/StatusBar.h
@@ -1,42 +1,42 @@
-// Windows/Control/StatusBar.h

-

-#ifndef __WINDOWS_CONTROL_STATUSBAR_H

-#define __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)) != 0; }

-  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)) != 0; }

-  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, 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 42a088f..8086655 100644
--- a/CPP/Windows/Control/StdAfx.h
+++ b/CPP/Windows/Control/StdAfx.h
@@ -1,8 +1,11 @@
-// StdAfx.h

-

-#ifndef __STDAFX_H

-#define __STDAFX_H

-

-#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 02ed9a1..2bf20a5 100644
--- a/CPP/Windows/Control/ToolBar.h
+++ b/CPP/Windows/Control/ToolBar.h
@@ -1,43 +1,43 @@
-// Windows/Control/ToolBar.h

-  

-#ifndef __WINDOWS_CONTROL_TOOLBAR_H

-#define __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

-    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 afc9bf2..18d1b29 100644
--- a/CPP/Windows/Control/Trackbar.h
+++ b/CPP/Windows/Control/Trackbar.h
@@ -1,27 +1,27 @@
-// Windows/Control/Trackbar.h

-

-#ifndef __WINDOWS_CONTROL_TRACKBAR_H

-#define __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 b6e6d67..8fe908e 100644
--- a/CPP/Windows/Control/Window2.cpp
+++ b/CPP/Windows/Control/Window2.cpp
@@ -1,200 +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 != NULL && message == MY_START_WM_CREATE)

-    window->Attach(aHWND);

-  if (window == 0)

-  {

-    #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(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::OnCommand(WPARAM wParam, LPARAM lParam, LRESULT &result)

-{

-  return OnCommand(HIWORD(wParam), LOWORD(wParam), lParam, result);

-}

-

-bool CWindow2::OnCommand(int /* code */, int /* itemID */, LPARAM /* lParam */, LRESULT & /* result */)

-{

-  return false;

-  // return DefProc(message, wParam, lParam);

-  /*

-  if (code == BN_CLICKED)

-    return OnButtonClicked(itemID, (HWND)lParam);

-  */

-}

-

-/*

-bool CDialog::OnButtonClicked(int 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 d632b86..ebb5979 100644
--- a/CPP/Windows/Control/Window2.h
+++ b/CPP/Windows/Control/Window2.h
@@ -1,51 +1,53 @@
-// Windows/Control/Window2.h

-

-#ifndef __WINDOWS_CONTROL_WINDOW2_H

-#define __WINDOWS_CONTROL_WINDOW2_H

-

-#include "../Window.h"

-

-namespace NWindows {

-namespace NControl {

-

-class CWindow2: public CWindow

-{

-  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);

-  virtual bool OnCommand(WPARAM wParam, LPARAM lParam, LRESULT &result);

-  virtual bool OnCommand(int code, int 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(int 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 efee379..b2499ec 100644
--- a/CPP/Windows/DLL.cpp
+++ b/CPP/Windows/DLL.cpp
@@ -1,109 +1,179 @@
-// Windows/DLL.cpp

-

-#include "StdAfx.h"

-

-#include "DLL.h"

-

-#ifndef _UNICODE

-extern bool g_IsNT;

-#endif

-

-extern HINSTANCE g_hInstance;

-

-namespace NWindows {

-namespace NDLL {

-

-bool CLibrary::Free() throw()

-{

-  if (_module == 0)

-    return true;

-  if (!::FreeLibrary(_module))

-    return false;

-  _module = 0;

-  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)

-{

-  HMODULE hModule = g_hInstance;

-  path.Empty();

-  #ifndef _UNICODE

-  if (!g_IsNT)

-  {

-    TCHAR s[MAX_PATH + 2];

-    s[0] = 0;

-    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;

-    DWORD size = ::GetModuleFileNameW(hModule, s, MAX_PATH + 1);

-    if (size <= MAX_PATH && size != 0)

-    {

-      path = us2fs(s);

-      return true;

-    }

-  }

-  return false;

-}

-

-#ifndef _SFX

-

-FString GetModuleDirPrefix()

-{

-  FString s;

-  if (MyGetModuleFileName(s))

-  {

-    int pos = s.ReverseFind_PathSepar();

-    if (pos >= 0)

-      s.DeleteFrom(pos + 1);

-  }

-  if (s.IsEmpty())

-    s = "." STRING_PATH_SEPARATOR;

-  return s;

-}

-

-#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)
+{
+  HMODULE hModule = g_hInstance;
+  path.Empty();
+  #ifndef _UNICODE
+  if (!g_IsNT)
+  {
+    TCHAR s[MAX_PATH + 2];
+    s[0] = 0;
+    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;
+    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))
+  {
+    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 <dlfcn.h>
+#include <stdlib.h>
+#include "../Common/Common.h"
+
+// 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 58bcf19..19a82b3 100644
--- a/CPP/Windows/DLL.h
+++ b/CPP/Windows/DLL.h
@@ -1,58 +1,103 @@
-// Windows/DLL.h

-

-#ifndef __WINDOWS_DLL_H

-#define __WINDOWS_DLL_H

-

-#include "../Common/MyString.h"

-

-namespace NWindows {

-namespace NDLL {

-

-#ifdef UNDER_CE

-#define My_GetProcAddress(module, procName) ::GetProcAddressA(module, procName)

-#else

-#define My_GetProcAddress(module, procName) ::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;

-

-  // CLASS_NO_COPY(CLibrary);

-public:

-  CLibrary(): _module(NULL) {};

-  ~CLibrary() { Free(); }

-

-  operator HMODULE() const { return _module; }

-  HMODULE* operator&() { return &_module; }

-  bool IsLoaded() const { return (_module != NULL); }

-

-  void Attach(HMODULE m)

-  {

-    Free();

-    _module = m;

-  }

-  HMODULE Detach()

-  {

-    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 GetProc(LPCSTR procName) const { return My_GetProcAddress(_module, procName); }

-};

-

-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 f3d692f..8ab9cf5 100644
--- a/CPP/Windows/Defs.h
+++ b/CPP/Windows/Defs.h
@@ -1,17 +1,17 @@
-// Windows/Defs.h

-

-#ifndef __WINDOWS_DEFS_H

-#define __WINDOWS_DEFS_H

-

-#include "../Common/MyWindows.h"

-

-#ifdef _WIN32

-inline bool LRESULTToBool(LRESULT v) { return (v != FALSE); }

-inline bool BOOLToBool(BOOL v) { return (v != FALSE); }

-inline BOOL BoolToBOOL(bool v) { return (v ? TRUE: FALSE); }

-#endif

-

-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 6434ec2..5acf3ad 100644
--- a/CPP/Windows/ErrorMsg.cpp
+++ b/CPP/Windows/ErrorMsg.cpp
@@ -1,66 +1,133 @@
-// Windows/ErrorMsg.h

-

-#include "StdAfx.h"

-

-#ifndef _UNICODE

-#include "../Common/StringConvert.h"

-#endif

-

-#include "ErrorMsg.h"

-

-#ifndef _UNICODE

-extern bool g_IsNT;

-#endif

-

-namespace NWindows {

-namespace NError {

-

-static bool MyFormatMessage(DWORD errorCode, UString &message)

-{

-  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;

-}

-

-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 e05e950..6142b4e 100644
--- a/CPP/Windows/ErrorMsg.h
+++ b/CPP/Windows/ErrorMsg.h
@@ -1,15 +1,16 @@
-// Windows/ErrorMsg.h

-

-#ifndef __WINDOWS_ERROR_MSG_H

-#define __WINDOWS_ERROR_MSG_H

-

-#include "../Common/MyString.h"

-

-namespace NWindows {

-namespace NError {

-

-UString 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 124569e..5b1f340 100644
--- a/CPP/Windows/FileDir.cpp
+++ b/CPP/Windows/FileDir.cpp
@@ -1,714 +1,1229 @@
-// Windows/FileDir.cpp

-

-#include "StdAfx.h"

-

-#ifndef _UNICODE

-#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;

-

-namespace NWindows {

-namespace NFile {

-namespace NDir {

-

-#ifndef UNDER_CE

-

-bool GetWindowsDir(FString &path)

-{

-  UINT needLength;

-  #ifndef _UNICODE

-  if (!g_IsNT)

-  {

-    TCHAR s[MAX_PATH + 2];

-    s[0] = 0;

-    needLength = ::GetWindowsDirectory(s, MAX_PATH + 1);

-    path = fas2fs(s);

-  }

-  else

-  #endif

-  {

-    WCHAR s[MAX_PATH + 2];

-    s[0] = 0;

-    needLength = ::GetWindowsDirectoryW(s, MAX_PATH + 1);

-    path = us2fs(s);

-  }

-  return (needLength > 0 && needLength <= MAX_PATH);

-}

-

-bool GetSystemDir(FString &path)

-{

-  UINT needLength;

-  #ifndef _UNICODE

-  if (!g_IsNT)

-  {

-    TCHAR s[MAX_PATH + 2];

-    s[0] = 0;

-    needLength = ::GetSystemDirectory(s, MAX_PATH + 1);

-    path = fas2fs(s);

-  }

-  else

-  #endif

-  {

-    WCHAR s[MAX_PATH + 2];

-    s[0] = 0;

-    needLength = ::GetSystemDirectoryW(s, MAX_PATH + 1);

-    path = us2fs(s);

-  }

-  return (needLength > 0 && needLength <= MAX_PATH);

-}

-#endif

-

-bool SetDirTime(CFSTR path, const FILETIME *cTime, const FILETIME *aTime, const FILETIME *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 WIN_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 WIN_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)

-{

-  if ((attrib & 0xF0000000) != 0)

-    attrib &= 0x3FFF;

-  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 WIN_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 WIN_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

-

-EXTERN_C_BEGIN

-typedef BOOL (WINAPI *Func_CreateHardLinkW)(

-    LPCWSTR lpFileName,

-    LPCWSTR lpExistingFileName,

-    LPSECURITY_ATTRIBUTES lpSecurityAttributes

-    );

-EXTERN_C_END

-

-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

-  {

-    Func_CreateHardLinkW my_CreateHardLinkW = (Func_CreateHardLinkW)

-        ::GetProcAddress(::GetModuleHandleW(L"kernel32.dll"), "CreateHardLinkW");

-    if (!my_CreateHardLinkW)

-      return false;

-    IF_USE_MAIN_PATH_2(newFileName, existFileName)

-      if (my_CreateHardLinkW(fs2us(newFileName), fs2us(existFileName), NULL))

-        return true;

-    #ifdef WIN_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;

-}

-

-#endif

-

-/*

-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 WIN_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 WIN_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();

-}

-

-bool CreateComplexDir(CFSTR _path)

-{

-  #ifdef _WIN32

-  

-  {

-    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;

-  

-  unsigned prefixSize = GetRootPrefixSize(_path);

-  

-  #endif

-  

-  #endif

-

-  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 = 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(pos);

-  }

-  

-  while (pos < (int)path2.Len())

-  {

-    int pos2 = NName::FindSepar(path2.Ptr(pos + 1));

-    if (pos2 < 0)

-      pos = path2.Len();

-    else

-      pos += 1 + pos2;

-    path.SetFrom(path2, pos);

-    if (!CreateDir(path))

-      return false;

-  }

-  

-  return true;

-}

-

-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 & ~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 WIN_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::CFileInfo fi;

-    while (enumerator.Next(fi))

-    {

-      s.DeleteFrom(prefixSize);

-      s += fi.Name;

-      if (fi.IsDir())

-      {

-        if (!RemoveDirWithSubItems(s))

-          return false;

-      }

-      else if (!DeleteFileAlways(s))

-        return false;

-    }

-  }

-  

-  if (!SetFileAttrib(path, 0))

-    return false;

-  return RemoveDir(path);

-}

-

-#ifdef UNDER_CE

-

-bool MyGetFullPathName(CFSTR path, FString &resFullPath)

-{

-  resFullPath = path;

-  return true;

-}

-

-#else

-

-bool MyGetFullPathName(CFSTR path, FString &resFullPath)

-{

-  return GetFullPath(path, resFullPath);

-}

-

-bool SetCurrentDir(CFSTR path)

-{

-  // SetCurrentDirectory doesn't support \\?\ prefix

-  #ifndef _UNICODE

-  if (!g_IsNT)

-  {

-    return BOOLToBool(::SetCurrentDirectory(fs2fas(path)));

-  }

-  else

-  #endif

-  {

-    return BOOLToBool(::SetCurrentDirectoryW(fs2us(path)));

-  }

-}

-

-bool GetCurrentDir(FString &path)

-{

-  path.Empty();

-  DWORD needLength;

-  #ifndef _UNICODE

-  if (!g_IsNT)

-  {

-    TCHAR s[MAX_PATH + 2];

-    s[0] = 0;

-    needLength = ::GetCurrentDirectory(MAX_PATH + 1, s);

-    path = fas2fs(s);

-  }

-  else

-  #endif

-  {

-    WCHAR s[MAX_PATH + 2];

-    s[0] = 0;

-    needLength = ::GetCurrentDirectoryW(MAX_PATH + 1, s);

-    path = us2fs(s);

-  }

-  return (needLength > 0 && needLength <= MAX_PATH);

-}

-

-#endif

-

-bool GetFullPathAndSplit(CFSTR path, FString &resDirPrefix, FString &resFileName)

-{

-  bool res = MyGetFullPathName(path, resDirPrefix);

-  if (!res)

-    resDirPrefix = path;

-  int pos = resDirPrefix.ReverseFind_PathSepar();

-  resFileName = resDirPrefix.Ptr(pos + 1);

-  resDirPrefix.DeleteFrom(pos + 1);

-  return res;

-}

-

-bool GetOnlyDirPrefix(CFSTR path, FString &resDirPrefix)

-{

-  FString resFileName;

-  return GetFullPathAndSplit(path, resDirPrefix, resFileName);

-}

-

-bool MyGetTempPath(FString &path)

-{

-  path.Empty();

-  DWORD needLength;

-  #ifndef _UNICODE

-  if (!g_IsNT)

-  {

-    TCHAR s[MAX_PATH + 2];

-    s[0] = 0;

-    needLength = ::GetTempPath(MAX_PATH + 1, s);

-    path = fas2fs(s);

-  }

-  else

-  #endif

-  {

-    WCHAR s[MAX_PATH + 2];

-    s[0] = 0;

-    needLength = ::GetTempPathW(MAX_PATH + 1, s);;

-    path = us2fs(s);

-  }

-  return (needLength > 0 && needLength <= MAX_PATH);

-}

-

-static bool CreateTempFile(CFSTR prefix, bool addRandom, FString &path, NIO::COutFile *outFile)

-{

-  UInt32 d = (GetTickCount() << 12) ^ (GetCurrentThreadId() << 14) ^ GetCurrentProcessId();

-  for (unsigned i = 0; i < 100; i++)

-  {

-    path = prefix;

-    if (addRandom)

-    {

-      char s[16];

-      UInt32 val = d;

-      unsigned k;

-      for (k = 0; k < 8; k++)

-      {

-        unsigned t = val & 0xF;

-        val >>= 4;

-        s[k] = (char)((t < 10) ? ('0' + t) : ('A' + (t - 10)));

-      }

-      s[k] = '\0';

-      if (outFile)

-        path += '.';

-      path += s;

-      UInt32 step = GetTickCount() + 2;

-      if (step == 0)

-        step = 1;

-      d += step;

-    }

-    addRandom = true;

-    if (outFile)

-      path += ".tmp";

-    if (NFind::DoesFileOrDirExist(path))

-    {

-      SetLastError(ERROR_ALREADY_EXISTS);

-      continue;

-    }

-    if (outFile)

-    {

-      if (outFile->Create(path, false))

-        return true;

-    }

-    else

-    {

-      if (CreateDir(path))

-        return true;

-    }

-    DWORD error = GetLastError();

-    if (error != ERROR_FILE_EXISTS &&

-        error != ERROR_ALREADY_EXISTS)

-      break;

-  }

-  path.Empty();

-  return false;

-}

-

-bool CTempFile::Create(CFSTR prefix, NIO::COutFile *outFile)

-{

-  if (!Remove())

-    return false;

-  if (!CreateTempFile(prefix, false, _path, outFile))

-    return false;

-  _mustBeDeleted = true;

-  return true;

-}

-

-bool CTempFile::CreateRandomInTempFolder(CFSTR namePrefix, NIO::COutFile *outFile)

-{

-  if (!Remove())

-    return false;

-  FString tempPath;

-  if (!MyGetTempPath(tempPath))

-    return false;

-  if (!CreateTempFile(tempPath + namePrefix, true, _path, outFile))

-    return false;

-  _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(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);

-  }

-  */

-}

-

-bool CTempDir::Create(CFSTR prefix)

-{

-  if (!Remove())

-    return false;

-  FString tempPath;

-  if (!MyGetTempPath(tempPath))

-    return false;

-  if (!CreateTempFile(tempPath + prefix, true, _path, NULL))

-    return false;

-  _mustBeDeleted = true;

-  return true;

-}

-

-bool CTempDir::Remove()

-{

-  if (!_mustBeDeleted)

-    return true;

-  _mustBeDeleted = !RemoveDirWithSubItems(_path);

-  return !_mustBeDeleted;

-}

-

-}}}

+// Windows/FileDir.cpp
+
+#include "StdAfx.h"
+
+
+#ifndef _WIN32
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <limits.h>
+#include <unistd.h>
+#include <time.h>
+#include <utime.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#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)
+  {
+    ts = *ft;
+    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
+EXTERN_C_BEGIN
+typedef BOOL (WINAPI *Func_CreateHardLinkW)(
+    LPCWSTR lpFileName,
+    LPCWSTR lpExistingFileName,
+    LPSECURITY_ATTRIBUTES lpSecurityAttributes
+    );
+EXTERN_C_END
+#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
+  {
+    const
+    Func_CreateHardLinkW
+      my_CreateHardLinkW = Z7_GET_PROC_ADDRESS(
+    Func_CreateHardLinkW, ::GetModuleHandleW(L"kernel32.dll"),
+        "CreateHardLinkW");
+    if (!my_CreateHardLinkW)
+      return false;
+    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 = 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(path, false))
+        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(newFile, false))
+    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
+
+}}}
diff --git a/CPP/Windows/FileDir.h b/CPP/Windows/FileDir.h
index 8d2b56a..573ffa2 100644
--- a/CPP/Windows/FileDir.h
+++ b/CPP/Windows/FileDir.h
@@ -1,117 +1,135 @@
-// Windows/FileDir.h

-

-#ifndef __WINDOWS_FILE_DIR_H

-#define __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);

-

-bool SetDirTime(CFSTR path, const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime);

-

-

-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.

-*/

-

-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);

-

-class CTempFile

-{

-  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);

-};

-

-class CTempDir

-{

-  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();

-};

-

-#if !defined(UNDER_CE)

-class CCurrentDirRestorer

-{

-  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);
+
+
+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
diff --git a/CPP/Windows/FileFind.cpp b/CPP/Windows/FileFind.cpp
index 8c6255b..c562a90 100644
--- a/CPP/Windows/FileFind.cpp
+++ b/CPP/Windows/FileFind.cpp
@@ -1,749 +1,1329 @@
-// Windows/FileFind.cpp

-

-#include "StdAfx.h"

-

-#ifndef _UNICODE

-#include "../Common/StringConvert.h"

-#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)

-

-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 WINBASEAPI HANDLE (WINAPI *FindFirstStreamW_Ptr)(LPCWSTR fileName, MY_STREAM_INFO_LEVELS infoLevel,

-    LPVOID findStreamData, DWORD flags);

-

-typedef WINBASEAPI BOOL (APIENTRY *FindNextStreamW_Ptr)(HANDLE findStream, LPVOID findStreamData);

-

-EXTERN_C_END

-

-#endif

-

-namespace NWindows {

-namespace NFile {

-

-#ifdef SUPPORT_DEVICE_FILE

-namespace NSystem

-{

-bool MyGetDiskFreeSpace(CFSTR rootPath, UInt64 &clusterSize, UInt64 &totalSize, UInt64 &freeSize);

-}

-#endif

-

-namespace NFind {

-

-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] == '.');

-}

-

-#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.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

-  

-  c:\* - ERROR_FILE_NOT_FOUND, if thare are no item in that folder

-*/

-

-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 WIN_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

-

-static FindFirstStreamW_Ptr g_FindFirstStreamW;

-static FindNextStreamW_Ptr g_FindNextStreamW;

-

-struct CFindStreamLoader

-{

-  CFindStreamLoader()

-  {

-    g_FindFirstStreamW = (FindFirstStreamW_Ptr)::GetProcAddress(::GetModuleHandleA("kernel32.dll"), "FindFirstStreamW");

-    g_FindNextStreamW = (FindNextStreamW_Ptr)::GetProcAddress(::GetModuleHandleA("kernel32.dll"), "FindNextStreamW");

-  }

-} g_FindStreamLoader;

-

-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 = 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;

-  if (!g_FindFirstStreamW)

-  {

-    ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);

-    return false;

-  }

-  {

-    MY_WIN32_FIND_STREAM_DATA sd;

-    SetLastError(0);

-    IF_USE_MAIN_PATH

-      _handle = g_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 WIN_LONG_PATH

-      if (USE_SUPER_PATH)

-      {

-        UString superPath;

-        if (GetSuperPath(path, superPath, USE_MAIN_PATH))

-          _handle = g_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)

-{

-  if (!g_FindNextStreamW)

-  {

-    ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);

-    return false;

-  }

-  {

-    MY_WIN32_FIND_STREAM_DATA sd;

-    if (!g_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

-

-

-#define MY_CLEAR_FILETIME(ft) ft.dwLowDateTime = ft.dwHighDateTime = 0;

-

-void CFileInfoBase::ClearBase() throw()

-{

-  Size = 0;

-  MY_CLEAR_FILETIME(CTime);

-  MY_CLEAR_FILETIME(ATime);

-  MY_CLEAR_FILETIME(MTime);

-  Attrib = 0;

-  IsAltStream = false;

-  IsDevice = false;

-}

-

-/*

-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 WIN_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)

-{

-  #ifdef SUPPORT_DEVICE_FILE

-  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)

-

-  int colonPos = FindAltStreamColon(path);

-  if (colonPos >= 0 && path[(unsigned)colonPos + 1] != 0)

-  {

-    UString streamName = fs2us(path + (unsigned)colonPos);

-    FString filePath (path);

-    filePath.DeleteFrom(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);

-

-    if (isOk)

-    {

-      Attrib &= ~(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); // we don't need backslash (C:)

-        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)

-          {

-            FString s (path);

-            s.Add_PathSepar();

-            s += '*'; // 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 */

-            }

-            {

-              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

-

-  return finder.FindFirst(path, *this);

-}

-

-

-bool DoesFileExist(CFSTR name)

-{

-  CFileInfo fi;

-  return fi.Find(name) && !fi.IsDir();

-}

-

-bool DoesDirExist(CFSTR name)

-{

-  CFileInfo fi;

-  return fi.Find(name) && fi.IsDir();

-}

-

-bool DoesFileOrDirExist(CFSTR name)

-{

-  CFileInfo fi;

-  return fi.Find(name);

-}

-

-

-void CEnumerator::SetDirPrefix(const FString &dirPrefix)

-{

-  _wildcard = dirPrefix;

-  _wildcard += '*';

-}

-

-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)

-{

-  if (Next(fi))

-  {

-    found = true;

-    return true;

-  }

-  found = false;

-  return (::GetLastError() == ERROR_NO_MORE_FILES);

-}

-

-////////////////////////////////

-// 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 WIN_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<FString> &driveStrings)

-{

-  driveStrings.Clear();

-  #ifndef _UNICODE

-  if (!g_IsNT)

-  {

-    driveStrings.Clear();

-    UINT32 size = GetLogicalDriveStrings(0, NULL);

-    if (size == 0)

-      return false;

-    CObjArray<char> 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<wchar_t> 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

-

-}}}

+// Windows/FileFind.cpp
+
+#include "StdAfx.h"
+
+// #include <stdio.h>
+
+#ifndef _WIN32
+#include <fcntl.h>           /* Definition of AT_* constants */
+#include "TimeUtils.h"
+// for major
+// #include <sys/sysmacros.h>
+#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)
+
+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
+
+#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 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
+
+static Func_FindFirstStreamW g_FindFirstStreamW;
+static Func_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;
+
+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;
+  if (!g_FindFirstStreamW)
+  {
+    ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+    return false;
+  }
+  {
+    MY_WIN32_FIND_STREAM_DATA sd;
+    SetLastError(0);
+    IF_USE_MAIN_PATH
+      _handle = g_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 = g_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)
+{
+  if (!g_FindNextStreamW)
+  {
+    ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+    return false;
+  }
+  {
+    MY_WIN32_FIND_STREAM_DATA sd;
+    if (!g_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 += '*'; // 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 */
+            }
+            {
+              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 += '*';
+}
+
+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<FString> &driveStrings)
+{
+  driveStrings.Clear();
+  #ifndef _UNICODE
+  if (!g_IsNT)
+  {
+    driveStrings.Clear();
+    UINT32 size = GetLogicalDriveStrings(0, NULL);
+    if (size == 0)
+      return false;
+    CObjArray<char> 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<wchar_t> 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);
+  }
+  /*
+  printf("\nres = %d\n", res);
+  printf("\n st_dev = %lld \n", (long long)(st->st_dev));
+  printf("\n st_ino = %lld \n", (long long)(st->st_ino));
+  printf("\n st_mode = %lld \n", (long long)(st->st_mode));
+  printf("\n st_nlink = %lld \n", (long long)(st->st_nlink));
+  printf("\n st_uid = %lld \n", (long long)(st->st_uid));
+  printf("\n st_gid = %lld \n", (long long)(st->st_gid));
+  printf("\n st_size = %lld \n", (long long)(st->st_size));
+  printf("\n st_blksize = %lld \n", (long long)(st->st_blksize));
+  printf("\n st_blocks = %lld \n", (long long)(st->st_blocks));
+  */
+
+  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 CFileInfo::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)
+  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)
+  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 77d8dc3..11408d0 100644
--- a/CPP/Windows/FileFind.h
+++ b/CPP/Windows/FileFind.h
@@ -1,161 +1,348 @@
-// Windows/FileFind.h

-

-#ifndef __WINDOWS_FILE_FIND_H

-#define __WINDOWS_FILE_FIND_H

-

-#include "../Common/MyString.h"

-#include "Defs.h"

-

-namespace NWindows {

-namespace NFile {

-namespace NFind {

-

-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; }

-}

-

-class CFileInfoBase

-{

-  bool MatchesMask(UINT32 mask) const { return ((Attrib & mask) != 0); }

-public:

-  UInt64 Size;

-  FILETIME CTime;

-  FILETIME ATime;

-  FILETIME MTime;

-  DWORD Attrib;

-  bool IsAltStream;

-  bool IsDevice;

-

-  /*

-  #ifdef UNDER_CE

-  DWORD ObjectID;

-  #else

-  UINT32 ReparseTag;

-  #endif

-  */

-

-  CFileInfoBase() { ClearBase(); }

-  void ClearBase() throw();

-

-  void SetAsDir() { Attrib = FILE_ATTRIBUTE_DIRECTORY; }

-

-  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); }

-};

-

-struct CFileInfo: public CFileInfoBase

-{

-  FString Name;

-  #if defined(_WIN32) && !defined(UNDER_CE)

-  // FString ShortName;

-  #endif

-

-  bool IsDots() const throw();

-  bool Find(CFSTR path);

-};

-

-class CFindFileBase

-{

-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

-{

-  CFindStream _find;

-  FString _filePath;

-

-  bool NextAny(CFileInfo &fileInfo);

-public:

-  CStreamEnumerator(const FString &filePath): _filePath(filePath) {}

-  bool Next(CStreamInfo &streamInfo, bool &found);

-};

-

-#endif

-

-bool DoesFileExist(CFSTR name);

-bool DoesDirExist(CFSTR name);

-bool DoesFileOrDirExist(CFSTR name);

-

-DWORD GetFileAttrib(CFSTR path);

-

-class CEnumerator

-{

-  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

-{

-  HANDLE _handle;

-public:

-  operator HANDLE () { return _handle; }

-  bool IsHandleAllocated() const { return _handle != INVALID_HANDLE_VALUE && _handle != 0; }

-  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<FString> &driveStrings);

-#endif

-

-}}}

-

-#endif

+// Windows/FileFind.h
+
+#ifndef ZIP7_INC_WINDOWS_FILE_FIND_H
+#define ZIP7_INC_WINDOWS_FILE_FIND_H
+
+#ifndef _WIN32
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <dirent.h>
+#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();
+
+ #ifdef _WIN32
+ 
+  bool Fill_From_ByHandleFileInfo(CFSTR path);
+  void SetAsDir()  { Attrib = FILE_ATTRIBUTE_DIRECTORY; } // |= (FILE_ATTRIBUTE_UNIX_EXTENSION + (S_IFDIR << 16));
+  void SetAsFile() { Attrib = 0; }
+
+  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; }
+  void SetAsFile() { mode = S_IFREG; }
+
+  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);
+  void SetFrom_stat(const struct stat &st);
+  #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<FString> &driveStrings);
+#endif
+
+typedef CFileInfo CDirEntry;
+
+
+#else // WIN32
+
+
+struct CDirEntry
+{
+  ino_t iNode;
+  #if !defined(_AIX)
+  Byte Type;
+  #endif
+  FString Name;
+
+  /*
+  #if !defined(_AIX)
+  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)
+    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 a1d52c0..4ecbb7e 100644
--- a/CPP/Windows/FileIO.cpp
+++ b/CPP/Windows/FileIO.cpp
@@ -1,432 +1,905 @@
-// Windows/FileIO.cpp

-

-#include "StdAfx.h"

-

-#ifdef SUPPORT_DEVICE_FILE

-#include "../../C/Alloc.h"

-#endif

-

-#include "FileIO.h"

-#include "FileName.h"

-

-#ifndef _UNICODE

-extern bool g_IsNT;

-#endif

-

-using namespace NWindows;

-using namespace NFile;

-using namespace NName;

-

-namespace NWindows {

-namespace NFile {

-

-#ifdef SUPPORT_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 SUPPORT_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 WIN_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

-  }

-  return (_handle != INVALID_HANDLE_VALUE);

-}

-

-bool CFileBase::Close() throw()

-{

-  if (_handle == INVALID_HANDLE_VALUE)

-    return true;

-  if (!::CloseHandle(_handle))

-    return false;

-  _handle = INVALID_HANDLE_VALUE;

-  return true;

-}

-

-bool CFileBase::GetPosition(UInt64 &position) const throw()

-{

-  return Seek(0, FILE_CURRENT, position);

-}

-

-bool CFileBase::GetLength(UInt64 &length) const throw()

-{

-  #ifdef SUPPORT_DEVICE_FILE

-  if (IsDeviceFile && SizeDefined)

-  {

-    length = Size;

-    return true;

-  }

-  #endif

-

-  DWORD sizeHigh;

-  DWORD sizeLow = ::GetFileSize(_handle, &sizeHigh);

-  if (sizeLow == 0xFFFFFFFF)

-    if (::GetLastError() != NO_ERROR)

-      return false;

-  length = (((UInt64)sizeHigh) << 32) + sizeLow;

-  return true;

-}

-

-bool CFileBase::Seek(Int64 distanceToMove, DWORD moveMethod, UInt64 &newPosition) const throw()

-{

-  #ifdef SUPPORT_DEVICE_FILE

-  if (IsDeviceFile && SizeDefined && moveMethod == FILE_END)

-  {

-    distanceToMove += Size;

-    moveMethod = FILE_BEGIN;

-  }

-  #endif

-

-  LONG high = (LONG)(distanceToMove >> 32);

-  DWORD low = ::SetFilePointer(_handle, (LONG)(distanceToMove & 0xFFFFFFFF), &high, moveMethod);

-  if (low == 0xFFFFFFFF)

-    if (::GetLastError() != NO_ERROR)

-      return false;

-  newPosition = (((UInt64)(UInt32)high) << 32) + low;

-  return true;

-}

-

-bool CFileBase::Seek(UInt64 position, UInt64 &newPosition) const throw()

-{

-  return Seek(position, FILE_BEGIN, newPosition);

-}

-

-bool CFileBase::SeekToBegin() const throw()

-{

-  UInt64 newPosition;

-  return Seek(0, newPosition);

-}

-

-bool CFileBase::SeekToEnd(UInt64 &newPosition) const throw()

-{

-  return Seek(0, FILE_END, newPosition);

-}

-

-// ---------- CInFile ---------

-

-#ifdef SUPPORT_DEVICE_FILE

-

-void CInFile::CorrectDeviceSize()

-{

-  // maybe we must decrease kClusterSize to 1 << 12, if we want correct size at tail

-  static 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 = 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 = geomEx.DiskSize.QuadPart;

-    else

-    {

-      DISK_GEOMETRY geom;

-      SizeDefined = GetGeometry(&geom);

-      if (!SizeDefined)

-        SizeDefined = GetCdRomGeometry(&geom);

-      if (SizeDefined)

-        Size = 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)

-{

-  bool res = Create(fileName, GENERIC_READ, shareMode, creationDisposition, flagsAndAttributes);

-  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 UInt32 kChunkSizeMax = (1 << 22);

-

-bool CInFile::Read1(void *data, UInt32 size, UInt32 &processedSize) throw()

-{

-  DWORD processedLoc = 0;

-  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 (size > kChunkSizeMax)

-    size = kChunkSizeMax;

-  return Read1(data, size, processedSize);

-}

-

-bool CInFile::Read(void *data, UInt32 size, UInt32 &processedSize) throw()

-{

-  processedSize = 0;

-  do

-  {

-    UInt32 processedLoc = 0;

-    bool res = ReadPart(data, size, processedLoc);

-    processedSize += processedLoc;

-    if (!res)

-      return false;

-    if (processedLoc == 0)

-      return true;

-    data = (void *)((unsigned char *)data + processedLoc);

-    size -= processedLoc;

-  }

-  while (size > 0);

-  return true;

-}

-

-// ---------- COutFile ---------

-

-static inline DWORD GetCreationDisposition(bool createAlways)

-  { return createAlways? CREATE_ALWAYS: CREATE_NEW; }

-

-bool COutFile::Open(CFSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes)

-  { return CFileBase::Create(fileName, GENERIC_WRITE, shareMode, creationDisposition, flagsAndAttributes); }

-

-bool COutFile::Open(CFSTR fileName, DWORD creationDisposition)

-  { return Open(fileName, FILE_SHARE_READ, creationDisposition, FILE_ATTRIBUTE_NORMAL); }

-

-bool COutFile::Create(CFSTR fileName, bool createAlways)

-  { return Open(fileName, GetCreationDisposition(createAlways)); }

-

-bool COutFile::CreateAlways(CFSTR fileName, DWORD flagsAndAttributes)

-  { return Open(fileName, FILE_SHARE_READ, GetCreationDisposition(true), 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;

-    bool res = WritePart(data, size, processedLoc);

-    processedSize += processedLoc;

-    if (!res)

-      return false;

-    if (processedLoc == 0)

-      return true;

-    data = (const void *)((const unsigned char *)data + processedLoc);

-    size -= processedLoc;

-  }

-  while (size > 0);

-  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();

-}

-

-}}}

+// Windows/FileIO.cpp
+
+#include "StdAfx.h"
+
+#ifdef Z7_DEVICE_FILE
+#include "../../C/Alloc.h"
+#endif
+
+// #include <stdio.h>
+
+/*
+#ifndef _WIN32
+// for ioctl BLKGETSIZE64
+#include <sys/ioctl.h>
+#include <linux/fs.h>
+#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 (!::CloseHandle(_handle))
+    return false;
+  _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 (size > kChunkSizeMax)
+    size = kChunkSizeMax;
+  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 *)((unsigned char *)data + processedLoc);
+    size -= processedLoc;
+  }
+  while (size > 0);
+  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 *)((unsigned char *)data + processedLoc);
+    size -= processedLoc;
+  }
+  while (size > 0);
+  return true;
+}
+
+// ---------- COutFile ---------
+
+static inline DWORD GetCreationDisposition(bool createAlways)
+  { return createAlways? CREATE_ALWAYS: CREATE_NEW; }
+
+bool COutFile::Open(CFSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes)
+  { return CFileBase::Create(fileName, GENERIC_WRITE, shareMode, creationDisposition, flagsAndAttributes); }
+
+bool COutFile::Open(CFSTR fileName, DWORD creationDisposition)
+  { return Open(fileName, FILE_SHARE_READ, creationDisposition, FILE_ATTRIBUTE_NORMAL); }
+
+bool COutFile::Create(CFSTR fileName, bool createAlways)
+  { return Open(fileName, GetCreationDisposition(createAlways)); }
+
+bool COutFile::CreateAlways(CFSTR fileName, DWORD flagsAndAttributes)
+  { return Open(fileName, FILE_SHARE_READ, GetCreationDisposition(true), 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 unsigned char *)data + processedLoc);
+    size -= processedLoc;
+  }
+  while (size != 0);
+  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 unsigned char *)data + processedLoc);
+    size -= processedLoc;
+  }
+  while (size != 0);
+  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 <fcntl.h>
+#include <unistd.h>
+
+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 <linux/fs.h>
+  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 *)((unsigned char *)data + (size_t)res);
+    size -= (size_t)res;
+    processed += (size_t)res;
+  }
+  while (size > 0);
+  return true;
+}
+
+
+/////////////////////////
+// COutFile
+
+bool COutFile::Create(const char *name, bool createAlways)
+{
+  Path = name; // change it : set it only if open is success.
+  if (createAlways)
+  {
+    Close();
+    _handle = ::creat(name, mode_for_Create);
+    return _handle != -1;
+  }
+  return OpenBinary(name, O_CREAT | O_EXCL | O_WRONLY, mode_for_Create);
+}
+
+bool COutFile::Open(const char *name, DWORD creationDisposition)
+{
+  UNUSED_VAR(creationDisposition) // FIXME
+  return Create(name, false);
+}
+
+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 unsigned char *)data + (size_t)res);
+    size -= (size_t)res;
+    processed += (size_t)res;
+  }
+  while (size > 0);
+  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 e31bc20..03e061a 100644
--- a/CPP/Windows/FileIO.h
+++ b/CPP/Windows/FileIO.h
@@ -1,212 +1,390 @@
-// Windows/FileIO.h

-

-#ifndef __WINDOWS_FILE_IO_H

-#define __WINDOWS_FILE_IO_H

-

-#include "../Common/MyWindows.h"

-

-#if defined(_WIN32) && !defined(UNDER_CE)

-#include <winioctl.h>

-#endif

-

-#include "../Common/MyString.h"

-#include "../Common/MyBuffer.h"

-

-#include "Defs.h"

-

-#define _my_IO_REPARSE_TAG_MOUNT_POINT  (0xA0000003L)

-#define _my_IO_REPARSE_TAG_SYMLINK      (0xA000000CL)

-

-#define _my_SYMLINK_FLAG_RELATIVE 1

-

-#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

-

-namespace NWindows {

-namespace NFile {

-

-#if defined(_WIN32) && !defined(UNDER_CE)

-bool FillLinkData(CByteBuffer &dest, const wchar_t *path, bool isSymLink);

-#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;

-

-  CReparseAttr(): Tag(0), Flags(0) {}

-

-  // Parse()

-  // returns true and (errorCode = 0), if (correct MOUNT_POINT or SYMLINK)

-  // returns false and (errorCode = ERROR_REPARSE_TAG_MISMATCH), if not (MOUNT_POINT or SYMLINK)

-  bool Parse(const Byte *p, size_t size, DWORD &errorCode);

-

-  bool IsMountPoint() const { return Tag == _my_IO_REPARSE_TAG_MOUNT_POINT; } // it's Junction

-  bool IsSymLink() const { return Tag == _my_IO_REPARSE_TAG_SYMLINK; }

-  bool IsRelative() const { return Flags == _my_SYMLINK_FLAG_RELATIVE; }

-  // bool IsVolume() const;

-

-  bool IsOkNamePair() const;

-  UString GetPath() const;

-};

-

-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);

-

-class CFileBase

-{

-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:

-  #ifdef SUPPORT_DEVICE_FILE

-  bool IsDeviceFile;

-  bool SizeDefined;

-  UInt64 Size; // it can be larger than real available size

-  #endif

-

-  CFileBase(): _handle(INVALID_HANDLE_VALUE) {};

-  ~CFileBase() { Close(); }

-

-  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)

-  {

-    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 SUPPORT_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);

-

-  #ifndef UNDER_CE

-

-  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();

-};

-

-class COutFile: public CFileBase

-{

-public:

-  bool Open(CFSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes);

-  bool Open(CFSTR fileName, DWORD creationDisposition);

-  bool Create(CFSTR fileName, bool createAlways);

-  bool CreateAlways(CFSTR fileName, DWORD flagsAndAttributes);

-

-  bool SetTime(const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime) throw();

-  bool SetMTime(const FILETIME *mTime) throw();

-  bool WritePart(const void *data, UInt32 size, UInt32 &processedSize) throw();

-  bool Write(const void *data, UInt32 size, UInt32 &processedSize) throw();

-  bool SetEndOfFile() throw();

-  bool SetLength(UInt64 length) throw();

-};

-

-}}}

-

-#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 <winioctl.h>
+#endif
+
+#else
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#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;
+  #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) {}
+  ~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);
+
+  #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
+{
+public:
+  bool Open(CFSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes);
+  bool Open(CFSTR fileName, DWORD creationDisposition);
+  bool Create(CFSTR fileName, bool createAlways);
+  bool CreateAlways(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;
+
+  CFileBase(): _handle(-1), PreserveATime(false) {}
+  ~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);
+  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();
+public:
+  mode_t mode_for_Create;
+
+  COutFile():
+      CTime_defined(false),
+      ATime_defined(false),
+      MTime_defined(false),
+      mode_for_Create(0666)
+      {}
+
+  bool Close();
+  bool Create(const char *name, bool createAlways);
+  bool Open(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 b5e47e7..2b9fa1a 100644
--- a/CPP/Windows/FileLink.cpp
+++ b/CPP/Windows/FileLink.cpp
@@ -1,440 +1,622 @@
-// Windows/FileLink.cpp

-

-#include "StdAfx.h"

-

-#include "../../C/CpuArch.h"

-

-#ifdef SUPPORT_DEVICE_FILE

-#include "../../C/Alloc.h"

-#endif

-

-#include "FileDir.h"

-#include "FileFind.h"

-#include "FileIO.h"

-#include "FileName.h"

-

-#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

-*/

-

-/*

-static const UInt32 kReparseFlags_Alias       = (1 << 29);

-static const UInt32 kReparseFlags_HighLatency = (1 << 30);

-static const UInt32 kReparseFlags_Microsoft   = ((UInt32)1 << 31);

-

-#define _my_IO_REPARSE_TAG_HSM          (0xC0000004L)

-#define _my_IO_REPARSE_TAG_HSM2         (0x80000006L)

-#define _my_IO_REPARSE_TAG_SIS          (0x80000007L)

-#define _my_IO_REPARSE_TAG_WIM          (0x80000008L)

-#define _my_IO_REPARSE_TAG_CSV          (0x80000009L)

-#define _my_IO_REPARSE_TAG_DFS          (0x8000000AL)

-#define _my_IO_REPARSE_TAG_DFSR         (0x80000012L)

-*/

-

-#define Get16(p) GetUi16(p)

-#define Get32(p) GetUi32(p)

-

-#define Set16(p, v) SetUi16(p, v)

-#define Set32(p, v) SetUi32(p, v)

-

-static const wchar_t * const k_LinkPrefix = L"\\??\\";

-static const unsigned k_LinkPrefix_Size = 4;

-

-static const 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);

-}

-*/

-

-void WriteString(Byte *dest, const wchar_t *path)

-{

-  for (;;)

-  {

-    wchar_t c = *path++;

-    if (c == 0)

-      return;

-    Set16(dest, (UInt16)c);

-    dest += 2;

-  }

-}

-

-#if defined(_WIN32) && !defined(UNDER_CE)

-

-bool FillLinkData(CByteBuffer &dest, const wchar_t *path, bool isSymLink)

-{

-  bool isAbs = IsAbsolutePath(path);

-  if (!isAbs && !isSymLink)

-    return false;

-

-  bool needPrintName = true;

-

-  if (IsSuperPath(path))

-  {

-    path += kSuperPathPrefixSize;

-    if (!IsDrivePath(path))

-      needPrintName = false;

-  }

-

-  const unsigned add_Prefix_Len = isAbs ? k_LinkPrefix_Size : 0;

-    

-  unsigned len2 = MyStringLen(path) * 2;

-  const unsigned len1 = len2 + add_Prefix_Len * 2;

-  if (!needPrintName)

-    len2 = 0;

-

-  unsigned 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;

-  dest.Alloc(size);

-  memset(dest, 0, size);

-  const UInt32 tag = isSymLink ?

-      _my_IO_REPARSE_TAG_SYMLINK :

-      _my_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 = len2;

-  else

-    printOffs = 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 : _my_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

-

-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, DWORD &errorCode)

-{

-  errorCode = ERROR_INVALID_REPARSE_DATA;

-  if (size < 8)

-    return false;

-  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 != _my_IO_REPARSE_TAG_MOUNT_POINT &&

-      Tag != _my_IO_REPARSE_TAG_SYMLINK)

-  {

-    errorCode = ERROR_REPARSE_TAG_MISMATCH; // ERROR_REPARSE_TAG_INVALID

-    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;

-

-  Flags = 0;

-  if (Tag == _my_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 != _my_IO_REPARSE_TAG_MOUNT_POINT &&

-      Tag != _my_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 == _my_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

-{

-  UString s (SubsName);

-  if (IsLinkPrefix(s))

-  {

-    s.ReplaceOneCharAtPos(1, '\\');

-    if (IsDrivePath(s.Ptr(k_LinkPrefix_Size)))

-      s.DeleteFrontal(k_LinkPrefix_Size);

-  }

-  return s;

-}

-

-

-#ifdef SUPPORT_DEVICE_FILE

-

-namespace NSystem

-{

-bool MyGetDiskFreeSpace(CFSTR rootPath, UInt64 &clusterSize, UInt64 &totalSize, UInt64 &freeSize);

-}

-#endif

-

-#ifndef 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(pos);

-  return NDir::CreateComplexDir(path2);

-}

-

-// If there is Reprase 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(path, CREATE_NEW))

-        return false;

-    }

-  }

-

-  COutFile file;

-  if (!file.Open(path,

-      FILE_SHARE_WRITE,

-      OPEN_EXISTING,

-      FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS))

-    return false;

-

-  DWORD returnedSize;

-  if (!file.DeviceIoControl(my_FSCTL_SET_REPARSE_POINT, (void *)data, size, NULL, 0, &returnedSize))

-    return false;

-  return true;

-}

-

-}

-

-#endif

-

-}}

+// Windows/FileLink.cpp
+
+#include "StdAfx.h"
+
+#include "../../C/CpuArch.h"
+
+#ifndef _WIN32
+#include <unistd.h>
+#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);
+  UInt32 len = Get16(p + 4);
+  if (len + 8 != size)
+  // if (len + 8 > size)
+    return false;
+  /*
+  if ((type & kReparseFlags_Alias) == 0 ||
+      (type & kReparseFlags_Microsoft) == 0 ||
+      (type & 0xFFFF) != 3)
+  */
+
+  if (Get16(p + 6) != 0) // padding
+    return false;
+
+  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;
+ 
+  p += 8;
+  size -= 8;
+  
+  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(path, CREATE_NEW))
+        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 01c4a94..1933f7c 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 27d076b..caa7ea3 100644
--- a/CPP/Windows/FileMapping.h
+++ b/CPP/Windows/FileMapping.h
@@ -1,66 +1,66 @@
-// Windows/FileMapping.h

-

-#ifndef __WINDOWS_FILEMAPPING_H

-#define __WINDOWS_FILEMAPPING_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 != 0)

-      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 2a227dc..c9c4f8b 100644
--- a/CPP/Windows/FileName.cpp
+++ b/CPP/Windows/FileName.cpp
@@ -1,839 +1,894 @@
-// Windows/FileName.cpp

-

-#include "StdAfx.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();

-}

-

-#define IS_LETTER_CHAR(c) ((c) >= 'a' && (c) <= 'z' || (c) >= 'A' && (c) <= 'Z')

-

-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 = "\\\\?\\";

-static const char * const kSuperUncPrefix = "\\\\?\\UNC\\";

-

-#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;

-  }

-  int pos = FindSepar(s + prefixSize);

-  if (pos < 0)

-    return 0;

-  return prefixSize + pos + 1;

-}

-

-bool IsNetworkShareRootPath(CFSTR s) throw()

-{

-  unsigned prefixSize = GetNetworkServerPrefixSize(s);

-  if (prefixSize == 0)

-    return false;

-  s += prefixSize;

-  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)); }

-

-#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 = 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

-  int pos = FindSepar(s);

-  if (pos < 0)

-    return 0;

-  int pos2 = FindSepar(s + (unsigned)pos + 1);

-  if (pos2 < 0)

-    return 0;

-  return pos + 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;

-  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))

-  {

-    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 + 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 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 + 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) { return IS_SEPAR(s[0]); }

-

-#ifndef USE_UNICODE_FSTRING

-unsigned GetRootPrefixSize(CFSTR s) { return IS_SEPAR(s[0]) ? 1 : 0; }

-#endif

-unsigned GetRootPrefixSize(const wchar_t *s) { return IS_SEPAR(s[0]) ? 1 : 0; }

-

-#endif // _WIN32

-

-

-#ifndef UNDER_CE

-

-static bool GetCurDir(UString &path)

-{

-  path.Empty();

-  DWORD needLength;

-  #ifndef _UNICODE

-  if (!g_IsNT)

-  {

-    TCHAR s[MAX_PATH + 2];

-    s[0] = 0;

-    needLength = ::GetCurrentDirectory(MAX_PATH + 1, s);

-    path = fs2us(fas2fs(s));

-  }

-  else

-  #endif

-  {

-    WCHAR s[MAX_PATH + 2];

-    s[0] = 0;

-    needLength = ::GetCurrentDirectoryW(MAX_PATH + 1, s);

-    path = s;

-  }

-  return (needLength > 0 && needLength <= MAX_PATH);

-}

-

-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 = 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 - k;

-            i = 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 WIN_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);

-    unsigned fixedSize = GetRootPrefixSize_Of_SuperPath(temp);

-    if (fixedSize == 0)

-      return true;

-

-    UString rem = &temp[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);

-      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[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 unknow

-                                                  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);

-    }

-    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;

-  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 // WIN_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

-

-  unsigned prefixSize = GetRootPrefixSize(s);

-  if (prefixSize != 0)

-  {

-    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;

-  }

-

-  /*

-  FChar c = s[0];

-  if (c == 0)

-    return true;

-  if (c == '.' && (s[1] == 0 || (s[1] == '.' && s[2] == 0)))

-    return true;

-  if (IS_SEPAR(c) && IS_SEPAR(s[1]))

-    return true;

-  if (IsDrivePath(s))

-    return true;

-  */

-

-  UString curDir;

-  if (dirPrefix)

-    curDir = fs2us(dirPrefix);

-  else

-  {

-    if (!GetCurDir(curDir))

-      return false;

-  }

-  NormalizeDirPathPrefix(curDir);

-

-  unsigned fixedSize = 0;

-

-  #ifdef _WIN32

-

-  if (IsSuperPath(curDir))

-  {

-    fixedSize = GetRootPrefixSize_Of_SuperPath(curDir);

-    if (fixedSize == 0)

-      return false;

-  }

-  else

-  {

-    if (IsDrivePath(curDir))

-      fixedSize = kDrivePrefixSize;

-    else

-    {

-      if (!IsPathSepar(curDir[0]) || !IsPathSepar(curDir[1]))

-        return false;

-      fixedSize = GetRootPrefixSize_Of_NetworkPath(curDir.Ptr(2));

-      if (fixedSize == 0)

-        return false;

-      fixedSize += 2;

-    }

-  }

-

-  #endif // _WIN32

-  

-  UString temp;

-  if (IS_SEPAR(s[0]))

-  {

-    temp = fs2us(s + 1);

-  }

-  else

-  {

-    temp += curDir.Ptr(fixedSize);

-    temp += fs2us(s);

-  }

-  if (!ResolveDotsFolders(temp))

-    return false;

-  curDir.DeleteFrom(fixedSize);

-  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 <limits.h>
+#include <unistd.h>
+#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
+  int pos = FindSepar(s);
+  if (pos < 0)
+    return 0;
+  int pos2 = FindSepar(s + (unsigned)pos + 1);
+  if (pos2 < 0)
+    return 0;
+  return pos + 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 + 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 1e47098..219b656 100644
--- a/CPP/Windows/FileName.h
+++ b/CPP/Windows/FileName.h
@@ -1,115 +1,133 @@
-// Windows/FileName.h

-

-#ifndef __WINDOWS_FILE_NAME_H

-#define __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);

-

-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();

-

-#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 WIN_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 // WIN_LONG_PATH

-

-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 9861062..6a262d9 100644
--- a/CPP/Windows/FileSystem.cpp
+++ b/CPP/Windows/FileSystem.cpp
@@ -1,131 +1,139 @@
-// 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 {

-

-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));

-  }

-}

-

-typedef BOOL (WINAPI * GetDiskFreeSpaceExA_Pointer)(

-  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 * GetDiskFreeSpaceExW_Pointer)(

-  LPCWSTR lpDirectoryName,                 // directory name

-  PULARGE_INTEGER lpFreeBytesAvailable,    // bytes available to caller

-  PULARGE_INTEGER lpTotalNumberOfBytes,    // bytes on disk

-  PULARGE_INTEGER lpTotalNumberOfFreeBytes // free bytes on disk

-);

-

-bool MyGetDiskFreeSpace(CFSTR rootPath, UInt64 &clusterSize, UInt64 &totalSize, UInt64 &freeSize)

-{

-  DWORD numSectorsPerCluster, bytesPerSector, numFreeClusters, numClusters;

-  bool sizeIsDetected = false;

-  #ifndef _UNICODE

-  if (!g_IsNT)

-  {

-    GetDiskFreeSpaceExA_Pointer pGetDiskFreeSpaceEx = (GetDiskFreeSpaceExA_Pointer)GetProcAddress(

-        GetModuleHandle(TEXT("kernel32.dll")), "GetDiskFreeSpaceExA");

-    if (pGetDiskFreeSpaceEx)

-    {

-      ULARGE_INTEGER freeBytesToCaller2, totalSize2, freeSize2;

-      sizeIsDetected = BOOLToBool(pGetDiskFreeSpaceEx(fs2fas(rootPath), &freeBytesToCaller2, &totalSize2, &freeSize2));

-      totalSize = totalSize2.QuadPart;

-      freeSize = freeSize2.QuadPart;

-    }

-    if (!::GetDiskFreeSpace(fs2fas(rootPath), &numSectorsPerCluster, &bytesPerSector, &numFreeClusters, &numClusters))

-      return false;

-  }

-  else

-  #endif

-  {

-    GetDiskFreeSpaceExW_Pointer pGetDiskFreeSpaceEx = (GetDiskFreeSpaceExW_Pointer)GetProcAddress(

-        GetModuleHandle(TEXT("kernel32.dll")), "GetDiskFreeSpaceExW");

-    if (pGetDiskFreeSpaceEx)

-    {

-      ULARGE_INTEGER freeBytesToCaller2, totalSize2, freeSize2;

-      sizeIsDetected = BOOLToBool(pGetDiskFreeSpaceEx(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

+// 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));
+  }
+}
+
+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
+);
+
+bool MyGetDiskFreeSpace(CFSTR rootPath, UInt64 &clusterSize, UInt64 &totalSize, UInt64 &freeSize)
+{
+  DWORD numSectorsPerCluster, bytesPerSector, numFreeClusters, numClusters;
+  bool sizeIsDetected = false;
+  #ifndef _UNICODE
+  if (!g_IsNT)
+  {
+    const
+    Func_GetDiskFreeSpaceExA f = Z7_GET_PROC_ADDRESS(
+    Func_GetDiskFreeSpaceExA, GetModuleHandle(TEXT("kernel32.dll")),
+        "GetDiskFreeSpaceExA");
+    if (f)
+    {
+      ULARGE_INTEGER freeBytesToCaller2, totalSize2, freeSize2;
+      sizeIsDetected = BOOLToBool(f(fs2fas(rootPath), &freeBytesToCaller2, &totalSize2, &freeSize2));
+      totalSize = totalSize2.QuadPart;
+      freeSize = freeSize2.QuadPart;
+    }
+    if (!::GetDiskFreeSpace(fs2fas(rootPath), &numSectorsPerCluster, &bytesPerSector, &numFreeClusters, &numClusters))
+      return false;
+  }
+  else
+  #endif
+  {
+    const
+    Func_GetDiskFreeSpaceExW f = Z7_GET_PROC_ADDRESS(
+    Func_GetDiskFreeSpaceExW, GetModuleHandle(TEXT("kernel32.dll")),
+        "GetDiskFreeSpaceExW");
+    if (f)
+    {
+      ULARGE_INTEGER freeBytesToCaller2, totalSize2, freeSize2;
+      sizeIsDetected = BOOLToBool(f(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
+
+}}}
+
+#endif
diff --git a/CPP/Windows/FileSystem.h b/CPP/Windows/FileSystem.h
index b0149de..9f9e399 100644
--- a/CPP/Windows/FileSystem.h
+++ b/CPP/Windows/FileSystem.h
@@ -1,27 +1,31 @@
-// Windows/FileSystem.h

-

-#ifndef __WINDOWS_FILE_SYSTEM_H

-#define __WINDOWS_FILE_SYSTEM_H

-

-#include "../Common/MyString.h"

-#include "../Common/MyTypes.h"

-

-namespace NWindows {

-namespace NFile {

-namespace NSystem {

-

-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

+// 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 755eeb8..6ae09ec 100644
--- a/CPP/Windows/Handle.h
+++ b/CPP/Windows/Handle.h
@@ -1,37 +1,39 @@
-// Windows/Handle.h

-

-#ifndef __WINDOWS_HANDLE_H

-#define __WINDOWS_HANDLE_H

-

-namespace NWindows {

-

-class CHandle

-{

-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()

-  {

-    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
new file mode 100644
index 0000000..2a22394
--- /dev/null
+++ b/CPP/Windows/MemoryGlobal.cpp
@@ -0,0 +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;
+}
+
+}}
diff --git a/CPP/Windows/MemoryGlobal.h b/CPP/Windows/MemoryGlobal.h
new file mode 100644
index 0000000..6852591
--- /dev/null
+++ b/CPP/Windows/MemoryGlobal.h
@@ -0,0 +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
diff --git a/CPP/Windows/MemoryLock.cpp b/CPP/Windows/MemoryLock.cpp
index d1b3bcc..0bd7504 100644
--- a/CPP/Windows/MemoryLock.cpp
+++ b/CPP/Windows/MemoryLock.cpp
@@ -1,112 +1,124 @@
-// 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) Func_ ## fff  my_ ## fff  = (Func_ ## fff)GetProcAddress(hModule, name)

-#endif

-

-bool EnablePrivilege(LPCTSTR privilegeName, bool enable)

-{

-  bool res = false;

-

-  #ifndef _UNICODE

-

-  HMODULE hModule = ::LoadLibrary(TEXT("Advapi32.dll"));

-  if (hModule == NULL)

-    return false;

-  

-  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;

-}

-

-

-

-typedef void (WINAPI * Func_RtlGetVersion) (OSVERSIONINFOEXW *);

-

-/*

-  We suppose that Window 10 works incorrectly with "Large Pages" at:

-    - Windows 10 1703 (15063)

-    - Windows 10 1709 (16299)

-

-    - Windows 10 1809 (17763) on some CPUs that have no 1 GB page support.

-         We need more information about that new BUG in Windows.

-*/

-

-unsigned Get_LargePages_RiskLevel()

-{

-  OSVERSIONINFOEXW vi;

-  HMODULE ntdll = ::GetModuleHandleW(L"ntdll.dll");

-  if (!ntdll)

-    return 0;

-  Func_RtlGetVersion func = (Func_RtlGetVersion)GetProcAddress(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 (!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;
+  
+  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;
+}
+
+
+
+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 d82910f..2b85002 100644
--- a/CPP/Windows/MemoryLock.h
+++ b/CPP/Windows/MemoryLock.h
@@ -1,40 +1,40 @@
-// Windows/MemoryLock.h

-

-#ifndef __WINDOWS_MEMORY_LOCK_H

-#define __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
new file mode 100644
index 0000000..af54c66
--- /dev/null
+++ b/CPP/Windows/Menu.cpp
@@ -0,0 +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
+
+}
diff --git a/CPP/Windows/Menu.h b/CPP/Windows/Menu.h
new file mode 100644
index 0000000..e1de4c4
--- /dev/null
+++ b/CPP/Windows/Menu.h
@@ -0,0 +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
diff --git a/CPP/Windows/NationalTime.cpp b/CPP/Windows/NationalTime.cpp
new file mode 100644
index 0000000..d3c38de
--- /dev/null
+++ b/CPP/Windows/NationalTime.cpp
@@ -0,0 +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);
+}
+
+}}}
diff --git a/CPP/Windows/NationalTime.h b/CPP/Windows/NationalTime.h
new file mode 100644
index 0000000..32ba479
--- /dev/null
+++ b/CPP/Windows/NationalTime.h
@@ -0,0 +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
diff --git a/CPP/Windows/Net.cpp b/CPP/Windows/Net.cpp
new file mode 100644
index 0000000..0ac82d4
--- /dev/null
+++ b/CPP/Windows/Net.cpp
@@ -0,0 +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
+
+}}
diff --git a/CPP/Windows/Net.h b/CPP/Windows/Net.h
new file mode 100644
index 0000000..a954bdb
--- /dev/null
+++ b/CPP/Windows/Net.h
@@ -0,0 +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
diff --git a/CPP/Windows/NtCheck.h b/CPP/Windows/NtCheck.h
index 401e239..362a05a 100644
--- a/CPP/Windows/NtCheck.h
+++ b/CPP/Windows/NtCheck.h
@@ -1,46 +1,58 @@
-// Windows/NtCheck.h

-

-#ifndef __WINDOWS_NT_CHECK_H

-#define __WINDOWS_NT_CHECK_H

-

-#ifdef _WIN32

-

-#include "../Common/MyWindows.h"

-

-#if !defined(_WIN64) && !defined(UNDER_CE)

-static inline bool IsItWindowsNT()

-{

-  OSVERSIONINFO vi;

-  vi.dwOSVersionInfoSize = sizeof(vi);

-  return (::GetVersionEx(&vi) && vi.dwPlatformId == VER_PLATFORM_WIN32_NT);

-}

-#endif

-

-#ifndef _UNICODE

-  #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
new file mode 100644
index 0000000..0f48aee
--- /dev/null
+++ b/CPP/Windows/ProcessMessages.cpp
@@ -0,0 +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);
+    }
+  }
+}
+
+}
diff --git a/CPP/Windows/ProcessMessages.h b/CPP/Windows/ProcessMessages.h
new file mode 100644
index 0000000..aa98bbb
--- /dev/null
+++ b/CPP/Windows/ProcessMessages.h
@@ -0,0 +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
diff --git a/CPP/Windows/ProcessUtils.cpp b/CPP/Windows/ProcessUtils.cpp
new file mode 100644
index 0000000..607b4bb
--- /dev/null
+++ b/CPP/Windows/ProcessUtils.cpp
@@ -0,0 +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 += '\"';
+  return s2;
+}
+#endif
+
+WRes CProcess::Create(LPCWSTR imageName, const UString &params, 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 &params)
+{
+  CProcess process;
+  return process.Create(imageName, params, NULL);
+}
+
+}
diff --git a/CPP/Windows/ProcessUtils.h b/CPP/Windows/ProcessUtils.h
new file mode 100644
index 0000000..b1fce3a
--- /dev/null
+++ b/CPP/Windows/ProcessUtils.h
@@ -0,0 +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 <psapi.h>
+#else
+#include <Psapi.h>
+#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 &params, LPCWSTR curDir);
+
+  DWORD Wait() { return ::WaitForSingleObject(_handle, INFINITE); }
+};
+
+WRes MyCreateProcess(LPCWSTR imageName, const UString &params);
+
+}
+
+#endif
diff --git a/CPP/Windows/PropVariant.cpp b/CPP/Windows/PropVariant.cpp
index 6d9fb48..457b1dc 100644
--- a/CPP/Windows/PropVariant.cpp
+++ b/CPP/Windows/PropVariant.cpp
@@ -1,347 +1,391 @@
-// 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_FUNC(type, id, dest) \

-  CPropVariant& CPropVariant::operator=(type value) throw() \

-  { if (vt != id) { InternalClear(); vt = id; } \

-    dest = value; 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)

-

-HRESULT PropVariant_Clear(PROPVARIANT *prop) throw()

-{

-  switch (prop->vt)

-  {

-    case VT_EMPTY:

-    case VT_UI1:

-    case VT_I1:

-    case VT_I2:

-    case VT_UI2:

-    case VT_BOOL:

-    case VT_I4:

-    case VT_UI4:

-    case VT_R4:

-    case VT_INT:

-    case VT_UINT:

-    case VT_ERROR:

-    case VT_FILETIME:

-    case VT_UI8:

-    case VT_R8:

-    case VT_CY:

-    case VT_DATE:

-      prop->vt = VT_EMPTY;

-      prop->wReserved1 = 0;

-      prop->wReserved2 = 0;

-      prop->wReserved3 = 0;

-      prop->uhVal.QuadPart = 0;

-      return S_OK;

-  }

-  return ::VariantClear((VARIANTARG *)prop);

-  // return ::PropVariantClear(prop);

-  // PropVariantClear can clear VT_BLOB.

-}

-

-HRESULT CPropVariant::Clear() throw()

-{

-  if (vt == VT_EMPTY)

-    return S_OK;

-  return PropVariant_Clear(this);

-}

-

-HRESULT CPropVariant::Copy(const PROPVARIANT* pSrc) throw()

-{

-  ::VariantClear((tagVARIANT *)this);

-  switch (pSrc->vt)

-  {

-    case VT_UI1:

-    case VT_I1:

-    case VT_I2:

-    case VT_UI2:

-    case VT_BOOL:

-    case VT_I4:

-    case VT_UI4:

-    case VT_R4:

-    case VT_INT:

-    case VT_UINT:

-    case VT_ERROR:

-    case VT_FILETIME:

-    case VT_UI8:

-    case VT_R8:

-    case VT_CY:

-    case VT_DATE:

-      memmove((PROPVARIANT*)this, pSrc, sizeof(PROPVARIANT));

-      return S_OK;

-  }

-  return ::VariantCopy((tagVARIANT *)this, (tagVARIANT *)const_cast<PROPVARIANT *>(pSrc));

-}

-

-

-HRESULT CPropVariant::Attach(PROPVARIANT *pSrc) throw()

-{

-  HRESULT hr = Clear();

-  if (FAILED(hr))

-    return hr;

-  memcpy(this, pSrc, sizeof(PROPVARIANT));

-  pSrc->vt = VT_EMPTY;

-  return S_OK;

-}

-

-HRESULT CPropVariant::Detach(PROPVARIANT *pDest) throw()

-{

-  if (pDest->vt != VT_EMPTY)

-  {

-    HRESULT hr = PropVariant_Clear(pDest);

-    if (FAILED(hr))

-      return hr;

-  }

-  memcpy(pDest, this, sizeof(PROPVARIANT));

-  vt = VT_EMPTY;

-  return S_OK;

-}

-

-HRESULT CPropVariant::InternalClear() throw()

-{

-  if (vt == VT_EMPTY)

-    return S_OK;

-  HRESULT hr = Clear();

-  if (FAILED(hr))

-  {

-    vt = VT_ERROR;

-    scode = hr;

-  }

-  return hr;

-}

-

-void CPropVariant::InternalCopy(const PROPVARIANT *pSrc)

-{

-  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 (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: return ::CompareFileTime(&filetime, &a.filetime);

-    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;
+  }
+  ::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;
+  }
+  return ::VariantCopy((tagVARIANT *)this, (tagVARIANT *)const_cast<PROPVARIANT *>(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 f2eaba2..f358fde 100644
--- a/CPP/Windows/PropVariant.h
+++ b/CPP/Windows/PropVariant.h
@@ -1,114 +1,173 @@
-// Windows/PropVariant.h

-

-#ifndef __WINDOWS_PROP_VARIANT_H

-#define __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(PROPVARIANT *p, UInt64 v) throw()

-{

-  p->vt = VT_FILETIME;

-  p->filetime.dwLowDateTime = (DWORD)v;

-  p->filetime.dwHighDateTime = (DWORD)(v >> 32);

-}

-

-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

-{

-public:

-  CPropVariant()

-  {

-    vt = VT_EMPTY;

-    wReserved1 = 0;

-    // wReserved2 = 0;

-    // wReserved3 = 0;

-    // uhVal.QuadPart = 0;

-    bstrVal = 0;

-  }

-  ~CPropVariant() throw() { Clear(); }

-  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(Int16 value); // { vt = VT_I2; wReserved1 = 0; iVal = value; }

-  CPropVariant(Int32 value); // { vt = VT_I4; wReserved1 = 0; lVal = value; }

-

-public:

-  CPropVariant(UInt32 value) { vt = VT_UI4; wReserved1 = 0; ulVal = value; }

-  CPropVariant(UInt64 value) { vt = VT_UI8; wReserved1 = 0; uhVal.QuadPart = value; }

-  CPropVariant(Int64 value) { vt = VT_I8; wReserved1 = 0; hVal.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();

-

-public:

-  CPropVariant& operator=(Int32 value) throw();

-  CPropVariant& operator=(UInt32 value) throw();

-  CPropVariant& operator=(UInt64 value) throw();

-  CPropVariant& operator=(Int64 value) throw();

-  CPropVariant& operator=(const FILETIME &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 c5ac212..5fb96a7 100644
--- a/CPP/Windows/PropVariantConv.cpp
+++ b/CPP/Windows/PropVariantConv.cpp
@@ -1,138 +1,190 @@
-// PropVariantConvert.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; }

-

-bool ConvertUtcFileTimeToString(const FILETIME &utc, char *s, int level) throw()

-{

-  *s = 0;

-  FILETIME ft;

-  if (!FileTimeToLocalFileTime(&utc, &ft))

-    return false;

-

-  SYSTEMTIME st;

-  if (!BOOLToBool(FileTimeToSystemTime(&ft, &st)))

-    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)

-  {

-    UINT_TO_STR_2(' ', 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;

-        }

-      }

-    }

-  }

-  

-  *s = 0;

-  return true;

-}

-

-

-bool ConvertUtcFileTimeToString(const FILETIME &ft, wchar_t *dest, int level) throw()

-{

-  char s[32];

-  bool res = ConvertUtcFileTimeToString(ft, s, level);

-  for (unsigned i = 0;; i++)

-  {

-    unsigned char c = 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: ConvertUtcFileTimeToString(prop.filetime, dest); 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: ConvertUtcFileTimeToString(prop.filetime, dest); 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; }
+
+bool ConvertUtcFileTimeToString2(const FILETIME &utc, unsigned ns100, char *s, int level) throw()
+{
+  *s = 0;
+  FILETIME ft;
+  if (!FileTimeToLocalFileTime(&utc, &ft))
+    return false;
+
+  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)
+  {
+    UINT_TO_STR_2(' ', 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));
+        }
+      }
+    }
+  }
+  
+  *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[32];
+  bool res = ConvertUtcFileTimeToString2(ft, ns100, s, level);
+  for (unsigned i = 0;; i++)
+  {
+    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[32];
+  bool res = ConvertUtcFileTimeToString(ft, s, level);
+  for (unsigned i = 0;; i++)
+  {
+    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 3e24569..ec5223b 100644
--- a/CPP/Windows/PropVariantConv.h
+++ b/CPP/Windows/PropVariantConv.h
@@ -1,37 +1,40 @@
-// Windows/PropVariantConv.h

-

-#ifndef __PROP_VARIANT_CONV_H

-#define __PROP_VARIANT_CONV_H

-

-#include "../Common/MyTypes.h"

-

-// provide at least 32 bytes for buffer including zero-end

-

-#define kTimestampPrintLevel_DAY -3

-// #define kTimestampPrintLevel_HOUR -2

-#define kTimestampPrintLevel_MIN -1

-#define kTimestampPrintLevel_SEC 0

-#define kTimestampPrintLevel_NTFS 7

-

-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();

-

-// 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
+
+#define kTimestampPrintLevel_DAY -3
+// #define kTimestampPrintLevel_HOUR -2
+#define kTimestampPrintLevel_MIN -1
+#define kTimestampPrintLevel_SEC  0
+#define kTimestampPrintLevel_NTFS 7
+#define kTimestampPrintLevel_NS   9
+
+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) 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
new file mode 100644
index 0000000..6daee83
--- /dev/null
+++ b/CPP/Windows/PropVariantUtils.cpp
@@ -0,0 +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);
+}
diff --git a/CPP/Windows/PropVariantUtils.h b/CPP/Windows/PropVariantUtils.h
new file mode 100644
index 0000000..78adb50
--- /dev/null
+++ b/CPP/Windows/PropVariantUtils.h
@@ -0,0 +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
diff --git a/CPP/Windows/Registry.cpp b/CPP/Windows/Registry.cpp
index 0146621..b20157d 100644
--- a/CPP/Windows/Registry.cpp
+++ b/CPP/Windows/Registry.cpp
@@ -1,390 +1,406 @@
-// Windows/Registry.cpp

-

-#include "StdAfx.h"

-

-#include <wchar.h>

-

-#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)

-

-LONG CKey::Create(HKEY parentKey, LPCTSTR keyName,

-    LPTSTR keyClass, DWORD options, REGSAM accessMask,

-    LPSECURITY_ATTRIBUTES securityAttributes, LPDWORD disposition) throw()

-{

-  MYASSERT(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()

-{

-  MYASSERT(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()

-{

-  MYASSERT(_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()

-{

-  MYASSERT(_object != NULL);

-  return ::RegDeleteValue(_object, name);

-}

-

-#ifndef _UNICODE

-LONG CKey::DeleteValue(LPCWSTR name)

-{

-  MYASSERT(_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()

-{

-  MYASSERT(_object != NULL);

-  return RegSetValueEx(_object, name, 0, REG_DWORD,

-      (BYTE * const)&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);

-  MYASSERT(_object != NULL);

-  return RegSetValueEx(_object, name, 0, REG_SZ,

-      (const BYTE * )value, (lstrlen(value) + 1) * sizeof(TCHAR));

-}

-

-/*

-LONG CKey::SetValue(LPCTSTR name, const CSysString &value)

-{

-  MYASSERT(value != NULL);

-  MYASSERT(_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);

-  MYASSERT(_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);

-  MYASSERT(_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, (LPTSTR)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;

-  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, (LPTSTR)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;

-  UInt32 curSize = 0;

-  LONG res = RegQueryValueEx(_object, (LPTSTR)name, NULL, &type, NULL, (DWORD *)&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;

-  UInt32 curSize = 0;

-

-  LONG res;

-

-  if (g_IsNT)

-  {

-    res = RegQueryValueExW(_object, name, NULL, &type, NULL, (DWORD *)&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, (LPTSTR)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, (LPTSTR)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<wchar_t> 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;

-  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 Byte  *)buffer;

-  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 <wchar.h>
+// #include <stdio.h>
+
+#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;
+  UInt32 curSize = 0;
+  LONG res = RegQueryValueEx(_object, name, NULL, &type, NULL, (DWORD *)&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;
+  UInt32 curSize = 0;
+
+  LONG res;
+
+  if (g_IsNT)
+  {
+    res = RegQueryValueExW(_object, name, NULL, &type, NULL, (DWORD *)&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<wchar_t> 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;
+  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;
+  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;
+}
+
+}}
diff --git a/CPP/Windows/Registry.h b/CPP/Windows/Registry.h
index 0a31230..0d3b4fc 100644
--- a/CPP/Windows/Registry.h
+++ b/CPP/Windows/Registry.h
@@ -1,84 +1,84 @@
-// Windows/Registry.h

-

-#ifndef __WINDOWS_REGISTRY_H

-#define __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;
+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
diff --git a/CPP/Windows/ResourceString.cpp b/CPP/Windows/ResourceString.cpp
index c28e60e..ae8182e 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(size - 1), size);

-  }

-  while (size - len <= 1);

-  s.ReleaseBuf_CalcLen(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(size - 1), size);

-  }

-  while (size - len <= 1);

-  s.ReleaseBuf_CalcLen(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 cbaef4b..773307b 100644
--- a/CPP/Windows/ResourceString.h
+++ b/CPP/Windows/ResourceString.h
@@ -1,16 +1,17 @@
-// Windows/ResourceString.h

-

-#ifndef __WINDOWS_RESOURCE_STRING_H

-#define __WINDOWS_RESOURCE_STRING_H

-

-#include "../Common/MyString.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 8646cc9..d4282d0 100644
--- a/CPP/Windows/SecurityUtils.cpp
+++ b/CPP/Windows/SecurityUtils.cpp
@@ -1,181 +1,186 @@
-// Windows/SecurityUtils.cpp

-

-#include "StdAfx.h"

-

-#include "../Common/MyString.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)

-{

-  int len = (int)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);

-}

-*/

-

-#ifndef _UNICODE

-typedef BOOL (WINAPI * LookupAccountNameWP)(

-    LPCWSTR lpSystemName,

-    LPCWSTR lpAccountName,

-    PSID Sid,

-    LPDWORD cbSid,

-    LPWSTR ReferencedDomainName,

-    LPDWORD cchReferencedDomainName,

-    PSID_NAME_USE peUse

-    );

-#endif

-

-static PSID GetSid(LPWSTR accountName)

-{

-  #ifndef _UNICODE

-  HMODULE hModule = GetModuleHandle(TEXT("Advapi32.dll"));

-  if (hModule == NULL)

-    return NULL;

-  LookupAccountNameWP lookupAccountNameW = (LookupAccountNameWP)GetProcAddress(hModule, "LookupAccountNameW");

-  if (lookupAccountNameW == NULL)

-    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)

-    {

-      PSID pSid = ::HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sidLen);

-      LPWSTR domainName = (LPWSTR)::HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (domainLen + 1) * sizeof(WCHAR));

-      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 MY__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] = MY__SE_LOCK_MEMORY_NAME;

-  SetLsaString(s, &userRights);

-  WCHAR userName[256 + 2];

-  DWORD size = 256;

-  if (!GetUserNameW(userName, &size))

-    return false;

-  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;

-    }

-    */

-    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 16b6606..4ef3939 100644
--- a/CPP/Windows/SecurityUtils.h
+++ b/CPP/Windows/SecurityUtils.h
@@ -1,167 +1,148 @@
-// Windows/SecurityUtils.h

-

-#ifndef __WINDOWS_SECURITY_UTILS_H

-#define __WINDOWS_SECURITY_UTILS_H

-

-#include <NTSecAPI.h>

-

-#include "Defs.h"

-

-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); }

-

-};

-

-#ifndef _UNICODE

-typedef NTSTATUS (NTAPI *LsaOpenPolicyP)(PLSA_UNICODE_STRING SystemName,

-    PLSA_OBJECT_ATTRIBUTES ObjectAttributes, ACCESS_MASK DesiredAccess, PLSA_HANDLE PolicyHandle);

-typedef NTSTATUS (NTAPI *LsaCloseP)(LSA_HANDLE ObjectHandle);

-typedef NTSTATUS (NTAPI *LsaAddAccountRightsP)(LSA_HANDLE PolicyHandle,

-    PSID AccountSid, PLSA_UNICODE_STRING UserRights, ULONG CountOfRights );

-#define MY_STATUS_NOT_IMPLEMENTED           ((NTSTATUS)0xC0000002L)

-#endif

-

-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)

-  {

-    #ifndef _UNICODE

-    if (hModule == NULL)

-      return MY_STATUS_NOT_IMPLEMENTED;

-    LsaOpenPolicyP lsaOpenPolicy = (LsaOpenPolicyP)GetProcAddress(hModule, "LsaOpenPolicy");

-    if (lsaOpenPolicy == NULL)

-      return MY_STATUS_NOT_IMPLEMENTED;

-    #endif

-

-    Close();

-    return

-      #ifdef _UNICODE

-      ::LsaOpenPolicy

-      #else

-      lsaOpenPolicy

-      #endif

-      (systemName, objectAttributes, desiredAccess, &_handle);

-  }

-  

-  NTSTATUS Close()

-  {

-    if (_handle == NULL)

-      return 0;

-

-    #ifndef _UNICODE

-    if (hModule == NULL)

-      return MY_STATUS_NOT_IMPLEMENTED;

-    LsaCloseP lsaClose = (LsaCloseP)GetProcAddress(hModule, "LsaClose");

-    if (lsaClose == NULL)

-      return MY_STATUS_NOT_IMPLEMENTED;

-    #endif

-

-    NTSTATUS res =

-      #ifdef _UNICODE

-      ::LsaClose

-      #else

-      lsaClose

-      #endif

-      (_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)

-  {

-    #ifndef _UNICODE

-    if (hModule == NULL)

-      return MY_STATUS_NOT_IMPLEMENTED;

-    LsaAddAccountRightsP lsaAddAccountRights = (LsaAddAccountRightsP)GetProcAddress(hModule, "LsaAddAccountRights");

-    if (lsaAddAccountRights == NULL)

-      return MY_STATUS_NOT_IMPLEMENTED;

-    #endif

-

-    return

-      #ifdef _UNICODE

-      ::LsaAddAccountRights

-      #else

-      lsaAddAccountRights

-      #endif

-      (_handle, accountSid, userRights, countOfRights);

-  }

-  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 <NTSecAPI.h>
+
+#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)
+}
+
+#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 7ba82d4..b2a3489 100644
--- a/CPP/Windows/Shell.cpp
+++ b/CPP/Windows/Shell.cpp
@@ -1,358 +1,821 @@
-// Windows/Shell.cpp

-

-#include "StdAfx.h"

-

-/*

-#include <stdio.h>

-#include <string.h>

-*/

-

-#include "../Common/MyCom.h"

-#ifndef _UNICODE

-#include "../Common/StringConvert.h"

-#endif

-

-#include "COM.h"

-#include "Shell.h"

-

-#ifndef _UNICODE

-extern bool g_IsNT;

-#endif

-

-namespace NWindows {

-namespace NShell {

-

-#ifndef UNDER_CE

-

-// SHGetMalloc is unsupported in Windows Mobile?

-

-void CItemIDList::Free()

-{

-  if (m_Object == NULL)

-    return;

-  CMyComPtr<IMalloc> shellMalloc;

-  if (::SHGetMalloc(&shellMalloc) != NOERROR)

-    throw 41099;

-  shellMalloc->Free(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;

-}

-*/

-

-/////////////////////////////

-// CDrop

-

-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);

-}

-

-UString CDrop::QueryFileName(UINT fileIndex)

-{

-  UString fileName;

-  #ifndef _UNICODE

-  if (!g_IsNT)

-  {

-    AString fileNameA;

-    UINT bufferSize = QueryFile(fileIndex, (LPTSTR)NULL, 0);

-    const unsigned len = bufferSize + 2;

-    QueryFile(fileIndex, fileNameA.GetBuf(len), bufferSize + 1);

-    fileNameA.ReleaseBuf_CalcLen(len);

-    fileName = GetUnicodeString(fileNameA);

-  }

-  else

-  #endif

-  {

-    UINT bufferSize = QueryFile(fileIndex, (LPWSTR)NULL, 0);

-    const unsigned len = bufferSize + 2;

-    QueryFile(fileIndex, fileName.GetBuf(len), bufferSize + 1);

-    fileName.ReleaseBuf_CalcLen(len);

-  }

-  return fileName;

-}

-

-void CDrop::QueryFileNames(UStringVector &fileNames)

-{

-  UINT numFiles = QueryCountOfFiles();

-  /*

-  char s[100];

-  sprintf(s, "QueryFileNames: %d files", numFiles);

-  OutputDebugStringA(s);

-  */

-  fileNames.ClearAndReserve(numFiles);

-  for (UINT i = 0; i < numFiles; i++)

-  {

-    const UString s2 = QueryFileName(i);

-    if (!s2.IsEmpty())

-      fileNames.AddInReserved(s2);

-    /*

-    OutputDebugStringW(L"file ---");

-    OutputDebugStringW(s2);

-    */

-  }

-}

-

-

-bool GetPathFromIDList(LPCITEMIDLIST itemIDList, CSysString &path)

-{

-  const unsigned len = MAX_PATH * 2;

-  bool result = BOOLToBool(::SHGetPathFromIDList(itemIDList, path.GetBuf(len)));

-  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

-

-bool BrowseForFolder(LPBROWSEINFO browseInfo, CSysString &resultPath)

-{

-  NWindows::NCOM::CComInitializer comInitializer;

-  LPITEMIDLIST itemIDList = ::SHBrowseForFolder(browseInfo);

-  if (itemIDList == NULL)

-    return false;

-  CItemIDList itemIDListHolder;

-  itemIDListHolder.Attach(itemIDList);

-  return GetPathFromIDList(itemIDList, resultPath);

-}

-

-

-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;

-}

-

-

-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 != NULL) ? BrowseCallbackProc : NULL;

-  browseInfo.lParam = (LPARAM)initialFolder;

-  return BrowseForFolder(&browseInfo, resultPath);

-}

-

-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

-

-typedef BOOL (WINAPI * SHGetPathFromIDListWP)(LPCITEMIDLIST pidl, LPWSTR pszPath);

-

-bool GetPathFromIDList(LPCITEMIDLIST itemIDList, UString &path)

-{

-  path.Empty();

-  SHGetPathFromIDListWP shGetPathFromIDListW = (SHGetPathFromIDListWP)

-    ::GetProcAddress(::GetModuleHandleW(L"shell32.dll"), "SHGetPathFromIDListW");

-  if (shGetPathFromIDListW == 0)

-    return false;

-  const unsigned len = MAX_PATH * 2;

-  bool result = BOOLToBool(shGetPathFromIDListW(itemIDList, path.GetBuf(len)));

-  path.ReleaseBuf_CalcLen(len);

-  return result;

-}

-

-typedef LPITEMIDLIST (WINAPI * SHBrowseForFolderWP)(LPBROWSEINFOW lpbi);

-

-bool BrowseForFolder(LPBROWSEINFOW browseInfo, UString &resultPath)

-{

-  NWindows::NCOM::CComInitializer comInitializer;

-  SHBrowseForFolderWP shBrowseForFolderW = (SHBrowseForFolderWP)

-    ::GetProcAddress(::GetModuleHandleW(L"shell32.dll"), "SHBrowseForFolderW");

-  if (shBrowseForFolderW == 0)

-    return false;

-  LPITEMIDLIST itemIDList = shBrowseForFolderW(browseInfo);

-  if (itemIDList == NULL)

-    return false;

-  CItemIDList itemIDListHolder;

-  itemIDListHolder.Attach(itemIDList);

-  return GetPathFromIDList(itemIDList, resultPath);

-}

-

-

-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 != NULL) ? 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<IMalloc> 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 += 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<IShellFolder> parentFolder;
+  {
+    const UINT offset = cida->aoffset[0];
+    if (offset < start || offset >= blockSize
+        // || offset != start
+        )
+      return E_INVALIDARG;
+
+    CMyComPtr<IShellFolder> 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" {
+typedef BOOL (WINAPI * Func_SHGetPathFromIDListW)(LPCITEMIDLIST pidl, LPWSTR pszPath);
+typedef BOOL (WINAPI * Func_SHGetPathFromIDListEx)(LPCITEMIDLIST pidl, PWSTR pszPath, DWORD cchPath, Z7_WIN_GPFIDL_FLAGS uOpts);
+}
+
+#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 "\\\\?\\". */
+    const
+    Func_SHGetPathFromIDListEx
+    func_SHGetPathFromIDListEx = Z7_GET_PROC_ADDRESS(
+    Func_SHGetPathFromIDListEx, ::GetModuleHandleW(L"shell32.dll"),
+        "SHGetPathFromIDListEx");
+    if (func_SHGetPathFromIDListEx)
+    {
+      ODS("==== GetPathFromIDList() (SHGetPathFromIDListEx)")
+      do
+      {
+        len *= 4;
+        result = BOOLToBool(func_SHGetPathFromIDListEx(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 9068040..b4cdb30 100644
--- a/CPP/Windows/Shell.h
+++ b/CPP/Windows/Shell.h
@@ -1,94 +1,130 @@
-// Windows/Shell.h

-

-#ifndef __WINDOWS_SHELL_H

-#define __WINDOWS_SHELL_H

-

-#include <windows.h>

-#include <shlobj.h>

-

-#include "../Common/MyString.h"

-

-#include "Defs.h"

-

-namespace NWindows{

-namespace NShell{

-

-/////////////////////////

-// CItemIDList

-#ifndef UNDER_CE

-

-class CItemIDList

-{

-  LPITEMIDLIST m_Object;

-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 fileNameSize)

-    { return ::DragQueryFile(m_Object, fileIndex, fileName, fileNameSize); }

-  #ifndef _UNICODE

-  UINT QueryFile(UINT fileIndex, LPWSTR fileName, UINT fileNameSize)

-    { return ::DragQueryFileW(m_Object, fileIndex, fileName, fileNameSize); }

-  #endif

-  UINT QueryCountOfFiles();

-  UString QueryFileName(UINT fileIndex);

-  void QueryFileNames(UStringVector &fileNames);

-};

-

-#endif

-

-/////////////////////////////

-// Functions

-

-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/Common.h"
+#include "../Common/MyWindows.h"
+#if defined(__MINGW32__) || defined(__MINGW64__)
+#include <shlobj.h>
+#else
+#include <ShlObj.h>
+#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<DWORD> Vals;
+  // CRecordVector<bool> 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 47a4895..bd5084f 100644
--- a/CPP/Windows/StdAfx.h
+++ b/CPP/Windows/StdAfx.h
@@ -1,8 +1,12 @@
-// StdAfx.h

-

-#ifndef __STDAFX_H

-#define __STDAFX_H

-

-#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 01f1ad9..d5542af 100644
--- a/CPP/Windows/Synchronization.cpp
+++ b/CPP/Windows/Synchronization.cpp
@@ -1,10 +1,87 @@
-// Windows/Synchronization.cpp

-

-#include "StdAfx.h"

-

-#include "Synchronization.h"

-

-namespace NWindows {

-namespace NSynchronization {

-

-}}

+// 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 786da00..afd03d2 100644
--- a/CPP/Windows/Synchronization.h
+++ b/CPP/Windows/Synchronization.h
@@ -1,164 +1,381 @@
-// Windows/Synchronization.h

-

-#ifndef __WINDOWS_SYNCHRONIZATION_H

-#define __WINDOWS_SYNCHRONIZATION_H

-

-#include "../../C/Threads.h"

-

-#include "Defs.h"

-

-#ifdef _WIN32

-#include "Handle.h"

-#endif

-

-namespace NWindows {

-namespace NSynchronization {

-

-class CBaseEvent

-{

-protected:

-  ::CEvent _object;

-public:

-  bool IsCreated() { return Event_IsCreated(&_object) != 0; }

-  operator HANDLE() { return _object; }

-  CBaseEvent() { Event_Construct(&_object); }

-  ~CBaseEvent() { Close(); }

-  WRes Close() { return Event_Close(&_object); }

-  #ifdef _WIN32

-  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 != 0)

-      return 0;

-    return ::GetLastError();

-  }

-  WRes Open(DWORD desiredAccess, bool inheritHandle, LPCTSTR name)

-  {

-    _object = ::OpenEvent(desiredAccess, BoolToBOOL(inheritHandle), name);

-    if (_object != 0)

-      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()

-  {

-    if (IsCreated())

-      return 0;

-    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()

-  {

-    if (IsCreated())

-      return 0;

-    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

-{

-  CMutex *_object;

-public:

-  CMutexLock(CMutex &object): _object(&object) { _object->Lock(); }

-  ~CMutexLock() { _object->Release(); }

-};

-#endif

-

-class CSemaphore

-{

-  ::CSemaphore _object;

-public:

-  CSemaphore() { Semaphore_Construct(&_object); }

-  ~CSemaphore() { Close(); }

-  WRes Close() {  return Semaphore_Close(&_object); }

-  operator HANDLE() { return _object; }

-  WRes Create(UInt32 initiallyCount, UInt32 maxCount)

-  {

-    return Semaphore_Create(&_object, initiallyCount, maxCount);

-  }

-  WRes Release() { return Semaphore_Release1(&_object); }

-  WRes Release(UInt32 releaseCount) { return Semaphore_ReleaseN(&_object, releaseCount); }

-  WRes Lock() { return Semaphore_Wait(&_object); }

-};

-

-class CCriticalSection

-{

-  ::CCriticalSection _object;

-public:

-  CCriticalSection() { CriticalSection_Init(&_object); }

-  ~CCriticalSection() { CriticalSection_Delete(&_object); }

-  void Enter() { CriticalSection_Enter(&_object); }

-  void Leave() { CriticalSection_Leave(&_object); }

-};

-

-class CCriticalSectionLock

-{

-  CCriticalSection *_object;

-  void Unlock()  { _object->Leave(); }

-public:

-  CCriticalSectionLock(CCriticalSection &object): _object(&object) {_object->Enter(); }

-  ~CCriticalSectionLock() { Unlock(); }

-};

-

-}}

-

-#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()
+  {
+    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 c6f8275..dbe287a 100644
--- a/CPP/Windows/System.cpp
+++ b/CPP/Windows/System.cpp
@@ -1,142 +1,278 @@
-// Windows/System.cpp

-

-#include "StdAfx.h"

-

-#include "../Common/MyWindows.h"

-

-#include "../Common/Defs.h"

-

-#include "System.h"

-

-namespace NWindows {

-namespace NSystem {

-

-UInt32 CountAffinity(DWORD_PTR mask)

-{

-  UInt32 num = 0;

-  for (unsigned i = 0; i < sizeof(mask) * 8; i++)

-    num += (UInt32)((mask >> i) & 1);

-  return num;

-}

-

-#ifdef _WIN32

-

-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

-

-UInt32 GetNumberOfProcessors()

-{

-  return 1;

-}

-

-#endif

-

-

-#ifdef _WIN32

-

-#ifndef UNDER_CE

-

-#if !defined(_WIN64) && defined(__GNUC__)

-

-typedef struct _MY_MEMORYSTATUSEX {

-  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 *GlobalMemoryStatusExP)(MY_LPMEMORYSTATUSEX lpBuffer);

-

-#endif

-

-#endif

-

-

-bool GetRamSize(UInt64 &size)

-{

-  size = (UInt64)(sizeof(size_t)) << 29;

-

-  #ifdef _WIN32

-  

-  #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

-      GlobalMemoryStatusExP globalMemoryStatusEx = (GlobalMemoryStatusExP)

-          ::GetProcAddress(::GetModuleHandle(TEXT("kernel32.dll")), "GlobalMemoryStatusEx");

-      if (globalMemoryStatusEx && globalMemoryStatusEx(&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

-

-  return false;

-

-  #endif

-}

-

-}}

+// Windows/System.cpp
+
+#include "StdAfx.h"
+
+#ifndef _WIN32
+#include <unistd.h>
+#include <limits.h>
+#ifdef __APPLE__
+#include <sys/sysctl.h>
+#else
+#include <sys/sysinfo.h>
+#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 >> i) & 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 _MY_MEMORYSTATUSEX {
+  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 <stdio.h>
+
+bool GetRamSize(UInt64 &size)
+{
+  size = (UInt64)(sizeof(size_t)) << 29;
+
+  #ifdef __APPLE__
+
+    #ifdef HW_MEMSIZE
+      uint64_t val = 0; // support 2Gb+ RAM
+      int mib[2] = { CTL_HW, HW_MEMSIZE };
+    #elif defined(HW_PHYSMEM64)
+      uint64_t val = 0; // support 2Gb+ RAM
+      int mib[2] = { CTL_HW, HW_PHYSMEM64 };
+    #else
+      unsigned int val = 0; // For old system
+      int mib[2] = { CTL_HW, HW_PHYSMEM };
+    #endif // HW_MEMSIZE
+      size_t size_sys = sizeof(val);
+
+      sysctl(mib, 2, &val, &size_sys, NULL, 0);
+      if (val)
+        size = val;
+
+  #elif defined(_AIX)
+  // fixme
+  #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;
+  const UInt64 kLimit = (UInt64)1 << (sizeof(size_t) * 8 - 1);
+  if (size > kLimit)
+    size = kLimit;
+
+  /*
+  printf("\n mem_unit  = %lld", (UInt64)info.mem_unit);
+  printf("\n totalram  = %lld", (UInt64)info.totalram);
+  printf("\n freeram   = %lld", (UInt64)info.freeram);
+  */
+
+  #endif
+
+  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 : <stdio.h>
+   #ifdef _POSIX_OPEN_MAX
+    n = _POSIX_OPEN_MAX; // = 20 : <limits.h>
+   #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 = (UInt32)(UInt32)-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 bc28f47..0650007 100644
--- a/CPP/Windows/System.h
+++ b/CPP/Windows/System.h
@@ -1,40 +1,132 @@
-// Windows/System.h

-

-#ifndef __WINDOWS_SYSTEM_H

-#define __WINDOWS_SYSTEM_H

-

-#include "../Common/MyTypes.h"

-

-namespace NWindows {

-namespace NSystem {

-

-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;

-  }

-

-  UInt32 GetNumProcessThreads() const { return CountAffinity(processAffinityMask); }

-  UInt32 GetNumSystemThreads() const { return CountAffinity(systemAffinityMask); }

-

-  BOOL Get();

-};

-

-UInt32 GetNumberOfProcessors();

-

-bool GetRamSize(UInt64 &size); // returns false, if unknown ram size

-

-}}

-

-#endif

+// Windows/System.h
+
+#ifndef ZIP7_INC_WINDOWS_SYSTEM_H
+#define ZIP7_INC_WINDOWS_SYSTEM_H
+
+#ifndef _WIN32
+// #include <sched.h>
+#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
diff --git a/CPP/Windows/SystemInfo.cpp b/CPP/Windows/SystemInfo.cpp
new file mode 100644
index 0000000..6bafc80
--- /dev/null
+++ b/CPP/Windows/SystemInfo.cpp
@@ -0,0 +1,1022 @@
+// Windows/SystemInfo.cpp
+
+#include "StdAfx.h"
+
+#include "../../C/CpuArch.h"
+
+#include "../Common/IntToString.h"
+
+#ifdef _WIN32
+
+#include "Registry.h"
+
+#else
+
+#include <unistd.h>
+#include <sys/utsname.h>
+#ifdef __APPLE__
+#include <sys/sysctl.h>
+#elif !defined(_AIX)
+
+#include <sys/auxv.h>
+
+// #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 MY_CPU_ARM_OR_ARM64
+#include <asm/hwcap.h>
+#endif
+#endif
+
+#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 + 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++)
+  {
+    Byte b = (Byte)(v & 0xFF);
+    v >>= 8;
+    if (b == 0)
+      break;
+    if (b >= 0x20 && b <= 0x7f)
+      s += (char)b;
+    else
+    {
+      s += '[';
+      char temp[16];
+      ConvertUInt32ToHex(b, temp);
+      s += temp;
+      s += ']';
+    }
+  }
+}
+
+
+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, 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 += c;
+  s += '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 += " cpus:";
+  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 += "-";
+  }
+  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
+}
+
+
+void GetCpuName(AString &s);
+
+static void AddBracedString(AString &dest, AString &src)
+{
+  if (!src.IsEmpty())
+  {
+    AString s;
+    s += '(';
+    s += src;
+    s += ')';
+    dest.Add_OptSpaced(s);
+  }
+}
+
+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())
+      s += "x86";
+    else
+    #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);
+  }
+  #endif
+
+
+  if (s.IsEmpty())
+  {
+    #ifdef MY_CPU_LE
+      s += "LE";
+    #elif defined(MY_CPU_BE)
+      s += "BE";
+    #endif
+  }
+  
+  #ifdef __APPLE__
+  {
+    AString s2;
+    UInt32 v = 0;
+    if (z7_sysctlbyname_Get_UInt32("machdep.cpu.core_count", &v) == 0)
+    {
+      s2.Add_UInt32(v);
+      s2 += 'C';
+    }
+    if (z7_sysctlbyname_Get_UInt32("machdep.cpu.thread_count", &v) == 0)
+    {
+      s2.Add_UInt32(v);
+      s2 += 'T';
+    }
+    if (!s2.IsEmpty())
+    {
+      s.Add_Space_if_NotEmpty();
+      s += s2;
+    }
+  }
+  #endif
+
+  
+  #ifdef _WIN32
+  {
+    NRegistry::CKey key;
+    if (key.Open(HKEY_LOCAL_MACHINE, TEXT("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"), KEY_READ) == ERROR_SUCCESS)
+    {
+      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)
+          {
+            UInt32 high = GetUi32(buf);
+            if (high != 0)
+            {
+              PrintHex(Microcode, high);
+              Microcode += ".";
+            }
+            PrintHex(Microcode, GetUi32(buf + 4));
+          }
+        }
+      }
+    }
+  }
+  #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(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 = 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 = 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
+
+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(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(AString &s);
+void GetCpuName(AString &s)
+{
+  CCpuName cpuName;
+  cpuName.Fill();
+  s = cpuName.CpuName;
+  AString s2;
+  cpuName.Get_Revision_Microcode_LargePages(s2);
+  s.Add_OptSpaced(s2);
+}
+
+
+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 __VERSION__
+    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 __clang__
+    s += " CLANG ";
+    s.Add_UInt32(__clang_major__);
+    s.Add_Dot();
+    s.Add_UInt32(__clang_minor__);
+  #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
+
+  #ifdef _MSC_VER
+    s += " MSC ";
+    s.Add_UInt32(_MSC_VER);
+  #endif
+
+    #if 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
+
+
+  #ifdef MY_CPU_COMPILE_ISA
+    s += ':';
+    s.Add_OptSpaced(MY_CPU_COMPILE_ISA);
+  #endif
+}
diff --git a/CPP/Windows/SystemInfo.h b/CPP/Windows/SystemInfo.h
new file mode 100644
index 0000000..c2e2e3b
--- /dev/null
+++ b/CPP/Windows/SystemInfo.h
@@ -0,0 +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
diff --git a/CPP/Windows/Thread.h b/CPP/Windows/Thread.h
index 1b5863c..d72f64c 100644
--- a/CPP/Windows/Thread.h
+++ b/CPP/Windows/Thread.h
@@ -1,38 +1,44 @@
-// Windows/Thread.h

-

-#ifndef __WINDOWS_THREAD_H

-#define __WINDOWS_THREAD_H

-

-#include "../../C/Threads.h"

-

-#include "Defs.h"

-

-namespace NWindows {

-

-class CThread

-{

-  ::CThread thread;

-public:

-  CThread() { Thread_Construct(&thread); }

-  ~CThread() { Close(); }

-  bool IsCreated() { return Thread_WasCreated(&thread) != 0; }

-  WRes Close()  { return Thread_Close(&thread); }

-  WRes Create(THREAD_FUNC_RET_TYPE (THREAD_FUNC_CALL_TYPE *startAddress)(void *), LPVOID parameter)

-    { return Thread_Create(&thread, startAddress, parameter); }

-  WRes Wait() { return Thread_Wait(&thread); }

-  

-  #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 3fc02bc..e80ae13 100644
--- a/CPP/Windows/TimeUtils.cpp
+++ b/CPP/Windows/TimeUtils.cpp
@@ -1,213 +1,404 @@
-// Windows/TimeUtils.cpp

-

-#include "StdAfx.h"

-

-#include "Defs.h"

-#include "TimeUtils.h"

-

-namespace NWindows {

-namespace NTime {

-

-static const UInt32 kNumTimeQuantumsInSecond = 10000000;

-static const UInt32 kFileTimeStartYear = 1601;

-static const UInt32 kDosTimeStartYear = 1980;

-static const UInt32 kUnixTimeStartYear = 1970;

-static const UInt64 kUnixTimeOffset =

-    (UInt64)60 * 60 * 24 * (89 + 365 * (kUnixTimeStartYear - kFileTimeStartYear));

-static const UInt64 kNumSecondsInFileTime = (UInt64)(Int64)-1 / kNumTimeQuantumsInSecond;

-

-bool DosTimeToFileTime(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 + (dosTime >> 25), (dosTime >> 21) & 0xF, (dosTime >> 16) & 0x1F,

-      (dosTime >> 11) & 0x1F, (dosTime >> 5) & 0x3F, (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;

-

-#define PERIOD_4 (4 * 365 + 1)

-#define PERIOD_100 (PERIOD_4 * 25 - 1)

-#define PERIOD_400 (PERIOD_100 * 4 + 1)

-

-bool FileTimeToDosTime(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

-

-  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 = (unsigned)(kFileTimeStartYear + 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 = (year << 25) | (mon << 21) | (day << 16) | (hour << 11) | (min << 5) | (sec >> 1);

-  #endif

-  return true;

-}

-

-UInt64 UnixTimeToFileTime64(UInt32 unixTime) throw()

-{

-  return (kUnixTimeOffset + (UInt64)unixTime) * kNumTimeQuantumsInSecond;

-}

-

-void UnixTimeToFileTime(UInt32 unixTime, FILETIME &ft) throw()

-{

-  UInt64 v = UnixTimeToFileTime64(unixTime);

-  ft.dwLowDateTime = (DWORD)v;

-  ft.dwHighDateTime = (DWORD)(v >> 32);

-}

-

-UInt64 UnixTime64ToFileTime64(Int64 unixTime) throw()

-{

-  return (UInt64)(kUnixTimeOffset + unixTime) * kNumTimeQuantumsInSecond;

-}

-

-bool UnixTime64ToFileTime(Int64 unixTime, FILETIME &ft) throw()

-{

-  if (unixTime > (Int64)(kNumSecondsInFileTime - kUnixTimeOffset))

-  {

-    ft.dwLowDateTime = ft.dwHighDateTime = (UInt32)(Int32)-1;

-    return false;

-  }

-  Int64 v = (Int64)kUnixTimeOffset + unixTime;

-  if (v < 0)

-  {

-    ft.dwLowDateTime = ft.dwHighDateTime = 0;

-    return false;

-  }

-  UInt64 v2 = (UInt64)v * kNumTimeQuantumsInSecond;

-  ft.dwLowDateTime = (DWORD)v2;

-  ft.dwHighDateTime = (DWORD)(v2 >> 32);

-  return true;

-}

-

-Int64 FileTimeToUnixTime64(const FILETIME &ft) throw()

-{

-  UInt64 winTime = (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime;

-  return (Int64)(winTime / kNumTimeQuantumsInSecond) - (Int64)kUnixTimeOffset;

-}

-

-bool FileTimeToUnixTime(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 > 0xFFFFFFFF)

-  {

-    unixTime = 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;

-  UInt32 numYears = year - kFileTimeStartYear;

-  UInt32 numDays = 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 += day - 1;

-  resSeconds = ((UInt64)(numDays * 24 + hour) * 60 + min) * 60 + sec;

-  return true;

-}

-

-void GetCurUtcFileTime(FILETIME &ft) throw()

-{

-  // 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

-}

-

-}}

+// Windows/TimeUtils.cpp
+
+#include "StdAfx.h"
+
+#ifndef _WIN32
+#include <sys/time.h>
+#endif
+
+#include "Defs.h"
+#include "TimeUtils.h"
+
+namespace NWindows {
+namespace NTime {
+
+static const UInt32 kNumTimeQuantumsInSecond = 10000000;
+static const UInt32 kFileTimeStartYear = 1601;
+#if !defined(_WIN32) || defined(UNDER_CE)
+static const UInt32 kDosTimeStartYear = 1980;
+#endif
+static const UInt32 kUnixTimeStartYear = 1970;
+static const UInt64 kUnixTimeOffset =
+    (UInt64)60 * 60 * 24 * (89 + 365 * (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 + (dosTime >> 25), (dosTime >> 21) & 0xF, (dosTime >> 16) & 0x1F,
+      (dosTime >> 11) & 0x1F, (dosTime >> 5) & 0x3F, (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 = (unsigned)(kFileTimeStartYear + 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 = (year << 25) | (mon << 21) | (day << 16) | (hour << 11) | (min << 5) | (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;
+  UInt32 numYears = year - kFileTimeStartYear;
+  UInt32 numDays = 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 += day - 1;
+  resSeconds = ((UInt64)(numDays * 24 + hour) * 60 + min) * 60 + sec;
+  return true;
+}
+
+
+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);
+  struct timeval now;
+  if (gettimeofday(&now, NULL) == 0)
+  {
+    ft.tv_sec = now.tv_sec;
+    ft.tv_nsec = now.tv_usec * 1000;
+  }
+
+ #endif
+}
+
+#ifndef _WIN32
+void GetCurUtcFileTime(FILETIME &ft) throw()
+{
+  UInt64 v = 0;
+  struct timeval now;
+  if (gettimeofday(&now, NULL) == 0)
+  {
+    v = ((UInt64)now.tv_sec + kUnixTimeOffset) *
+      kNumTimeQuantumsInSecond + (UInt64)now.tv_usec * 10;
+  }
+  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, timespec &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 = (long)(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 b0092f8..4a9d0f2 100644
--- a/CPP/Windows/TimeUtils.h
+++ b/CPP/Windows/TimeUtils.h
@@ -1,32 +1,146 @@
-// Windows/TimeUtils.h

-

-#ifndef __WINDOWS_TIME_UTILS_H

-#define __WINDOWS_TIME_UTILS_H

-

-#include "../Common/MyTypes.h"

-#include "../Common/MyWindows.h"

-

-namespace NWindows {

-namespace NTime {

-

-bool DosTimeToFileTime(UInt32 dosTime, FILETIME &fileTime) throw();

-bool FileTimeToDosTime(const FILETIME &fileTime, UInt32 &dosTime) throw();

-

-// UInt32 Unix Time : for dates 1970-2106

-UInt64 UnixTimeToFileTime64(UInt32 unixTime) throw();

-void UnixTimeToFileTime(UInt32 unixTime, FILETIME &fileTime) throw();

-

-// Int64 Unix Time : negative values for dates before 1970

-UInt64 UnixTime64ToFileTime64(Int64 unixTime) throw();

-bool UnixTime64ToFileTime(Int64 unixTime, FILETIME &fileTime) throw();

-

-bool FileTimeToUnixTime(const FILETIME &fileTime, UInt32 &unixTime) throw();

-Int64 FileTimeToUnixTime64(const FILETIME &ft) throw();

-

-bool GetSecondsSince1601(unsigned year, unsigned month, unsigned day,

-  unsigned hour, unsigned min, unsigned sec, UInt64 &resSeconds) throw();

-void GetCurUtcFileTime(FILETIME &ft) throw();

-

-}}

-

-#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 <sys/stat.h>
+
+ #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 0c74222..102c503 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)

-{

-  s.Empty();

-  int len = GetTextLength();

-  if (len == 0)

-    return (::GetLastError() == ERROR_SUCCESS);

-  TCHAR *p = s.GetBuf(len);

-  {

-    int len2 = GetText(p, 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)

-{

-  if (g_IsNT)

-  {

-    s.Empty();

-    int len = GetWindowTextLengthW(_window);

-    if (len == 0)

-      return (::GetLastError() == ERROR_SUCCESS);

-    wchar_t *p = s.GetBuf(len);

-    {

-      int len2 = GetWindowTextW(_window, p, len + 1);

-      if (len > len2)

-        len = len2;

-    }

-    s.ReleaseBuf_CalcLen(len);

-    if (len == 0)

-      return (::GetLastError() == ERROR_SUCCESS);

-    return true;

-  }

-  CSysString sysString;

-  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 4c80a5b..a99143b 100644
--- a/CPP/Windows/Window.h
+++ b/CPP/Windows/Window.h
@@ -1,284 +1,363 @@
-// Windows/Window.h

-

-#ifndef __WINDOWS_WINDOW_H

-#define __WINDOWS_WINDOW_H

-

-#include "../Common/MyWindows.h"

-#include "../Common/MyString.h"

-

-#include "Defs.h"

-

-#ifndef UNDER_CE

-

-#define MY__WM_CHANGEUISTATE  0x0127

-#define MY__WM_UPDATEUISTATE  0x0128

-#define MY__WM_QUERYUISTATE   0x0129

-

-// LOWORD(wParam) values in WM_*UISTATE

-#define MY__UIS_SET         1

-#define MY__UIS_CLEAR       2

-#define MY__UIS_INITIALIZE  3

-

-// HIWORD(wParam) values in WM_*UISTATE

-#define MY__UISF_HIDEFOCUS  0x1

-#define MY__UISF_HIDEACCEL  0x2

-#define MY__UISF_ACTIVE     0x4

-

-#endif

-

-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

-{

-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, BoolToBOOL(redraw), 0); }

-

-  LONG_PTR SetStyle(LONG_PTR style) { return SetLongPtr(GWL_STYLE, 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); }

-  UINT GetText(LPTSTR string, int maxCount) const

-    { return GetWindowText(_window, string, maxCount); }

-  bool GetText(CSysString &s);

-  #ifndef _UNICODE

-  /*

-  UINT GetText(LPWSTR string, int maxCount) const

-    { return GetWindowTextW(_window, string, maxCount); }

-  */

-  bool GetText(UString &s);

-  #endif

-

-  bool Enable(bool enable)

-    { return BOOLToBool(::EnableWindow(_window, BoolToBOOL(enable))); }

-  

-  bool IsEnabled()

-    { 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 = 0)

-    { 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/CS/7zip/Common/CRC.cs b/CS/7zip/Common/CRC.cs
deleted file mode 100644
index 62bb847..0000000
--- a/CS/7zip/Common/CRC.cs
+++ /dev/null
@@ -1,55 +0,0 @@
-// Common/CRC.cs

-

-namespace SevenZip

-{

-	class CRC

-	{

-		public static readonly uint[] Table;

-

-		static CRC()

-		{

-			Table = new uint[256];

-			const uint kPoly = 0xEDB88320;

-			for (uint i = 0; i < 256; i++)

-			{

-				uint r = i;

-				for (int j = 0; j < 8; j++)

-					if ((r & 1) != 0)

-						r = (r >> 1) ^ kPoly;

-					else

-						r >>= 1;

-				Table[i] = r;

-			}

-		}

-

-		uint _value = 0xFFFFFFFF;

-

-		public void Init() { _value = 0xFFFFFFFF; }

-

-		public void UpdateByte(byte b)

-		{

-			_value = Table[(((byte)(_value)) ^ b)] ^ (_value >> 8);

-		}

-

-		public void Update(byte[] data, uint offset, uint size)

-		{

-			for (uint i = 0; i < size; i++)

-				_value = Table[(((byte)(_value)) ^ data[offset + i])] ^ (_value >> 8);

-		}

-

-		public uint GetDigest() { return _value ^ 0xFFFFFFFF; }

-

-		static uint CalculateDigest(byte[] data, uint offset, uint size)

-		{

-			CRC crc = new CRC();

-			// crc.Init();

-			crc.Update(data, offset, size);

-			return crc.GetDigest();

-		}

-

-		static bool VerifyDigest(uint digest, byte[] data, uint offset, uint size)

-		{

-			return (CalculateDigest(data, offset, size) == digest);

-		}

-	}

-}

diff --git a/CS/7zip/Common/CommandLineParser.cs b/CS/7zip/Common/CommandLineParser.cs
deleted file mode 100644
index b46f6f2..0000000
--- a/CS/7zip/Common/CommandLineParser.cs
+++ /dev/null
@@ -1,274 +0,0 @@
-// CommandLineParser.cs

-

-using System;

-using System.Collections;

-

-namespace SevenZip.CommandLineParser

-{

-	public enum SwitchType

-	{

-		Simple,

-		PostMinus,

-		LimitedPostString,

-		UnLimitedPostString,

-		PostChar

-	}

-

-	public class SwitchForm

-	{

-		public string IDString;

-		public SwitchType Type;

-		public bool Multi;

-		public int MinLen;

-		public int MaxLen;

-		public string PostCharSet;

-

-		public SwitchForm(string idString, SwitchType type, bool multi,

-			int minLen, int maxLen, string postCharSet)

-		{

-			IDString = idString;

-			Type = type;

-			Multi = multi;

-			MinLen = minLen;

-			MaxLen = maxLen;

-			PostCharSet = postCharSet;

-		}

-		public SwitchForm(string idString, SwitchType type, bool multi, int minLen):

-			this(idString, type, multi, minLen, 0, "")

-		{

-		}

-		public SwitchForm(string idString, SwitchType type, bool multi):

-			this(idString, type, multi, 0)

-		{

-		}

-	}

-

-	public class SwitchResult

-	{

-		public bool ThereIs;

-		public bool WithMinus;

-		public ArrayList PostStrings = new ArrayList();

-		public int PostCharIndex;

-		public SwitchResult()

-		{

-			ThereIs = false;

-		}

-	}

-

-	public class Parser

-	{

-		public ArrayList NonSwitchStrings = new ArrayList();

-		SwitchResult[] _switches;

-

-		public Parser(int numSwitches)

-		{

-			_switches = new SwitchResult[numSwitches];

-			for (int i = 0; i < numSwitches; i++)

-				_switches[i] = new SwitchResult();

-		}

-

-		bool ParseString(string srcString, SwitchForm[] switchForms)

-		{

-			int len = srcString.Length;

-			if (len == 0)

-				return false;

-			int pos = 0;

-			if (!IsItSwitchChar(srcString[pos]))

-				return false;

-			while (pos < len)

-			{

-				if (IsItSwitchChar(srcString[pos]))

-					pos++;

-				const int kNoLen = -1;

-				int matchedSwitchIndex = 0;

-				int maxLen = kNoLen;

-				for (int switchIndex = 0; switchIndex < _switches.Length; switchIndex++)

-				{

-					int switchLen = switchForms[switchIndex].IDString.Length;

-					if (switchLen <= maxLen || pos + switchLen > len)

-						continue;

-					if (String.Compare(switchForms[switchIndex].IDString, 0,

-							srcString, pos, switchLen, true) == 0)

-					{

-						matchedSwitchIndex = switchIndex;

-						maxLen = switchLen;

-					}

-				}

-				if (maxLen == kNoLen)

-					throw new Exception("maxLen == kNoLen");

-				SwitchResult matchedSwitch = _switches[matchedSwitchIndex];

-				SwitchForm switchForm = switchForms[matchedSwitchIndex];

-				if ((!switchForm.Multi) && matchedSwitch.ThereIs)

-					throw new Exception("switch must be single");

-				matchedSwitch.ThereIs = true;

-				pos += maxLen;

-				int tailSize = len - pos;

-				SwitchType type = switchForm.Type;

-				switch (type)

-				{

-					case SwitchType.PostMinus:

-						{

-							if (tailSize == 0)

-								matchedSwitch.WithMinus = false;

-							else

-							{

-								matchedSwitch.WithMinus = (srcString[pos] == kSwitchMinus);

-								if (matchedSwitch.WithMinus)

-									pos++;

-							}

-							break;

-						}

-					case SwitchType.PostChar:

-						{

-							if (tailSize < switchForm.MinLen)

-								throw new Exception("switch is not full");

-							string charSet = switchForm.PostCharSet;

-							const int kEmptyCharValue = -1;

-							if (tailSize == 0)

-								matchedSwitch.PostCharIndex = kEmptyCharValue;

-							else

-							{

-								int index = charSet.IndexOf(srcString[pos]);

-								if (index < 0)

-									matchedSwitch.PostCharIndex = kEmptyCharValue;

-								else

-								{

-									matchedSwitch.PostCharIndex = index;

-									pos++;

-								}

-							}

-							break;

-						}

-					case SwitchType.LimitedPostString:

-					case SwitchType.UnLimitedPostString:

-						{

-							int minLen = switchForm.MinLen;

-							if (tailSize < minLen)

-								throw new Exception("switch is not full");

-							if (type == SwitchType.UnLimitedPostString)

-							{

-								matchedSwitch.PostStrings.Add(srcString.Substring(pos));

-								return true;

-							}

-							String stringSwitch = srcString.Substring(pos, minLen);

-							pos += minLen;

-							for (int i = minLen; i < switchForm.MaxLen && pos < len; i++, pos++)

-							{

-								char c = srcString[pos];

-								if (IsItSwitchChar(c))

-									break;

-								stringSwitch += c;

-							}

-							matchedSwitch.PostStrings.Add(stringSwitch);

-							break;

-						}

-				}

-			}

-			return true;

-

-		}

-

-		public void ParseStrings(SwitchForm[] switchForms, string[] commandStrings)

-		{

-			int numCommandStrings = commandStrings.Length;

-			bool stopSwitch = false;

-			for (int i = 0; i < numCommandStrings; i++)

-			{

-				string s = commandStrings[i];

-				if (stopSwitch)

-					NonSwitchStrings.Add(s);

-				else

-					if (s == kStopSwitchParsing)

-					stopSwitch = true;

-				else

-					if (!ParseString(s, switchForms))

-					NonSwitchStrings.Add(s);

-			}

-		}

-

-		public SwitchResult this[int index] { get { return _switches[index]; } }

-

-		public static int ParseCommand(CommandForm[] commandForms, string commandString,

-			out string postString)

-		{

-			for (int i = 0; i < commandForms.Length; i++)

-			{

-				string id = commandForms[i].IDString;

-				if (commandForms[i].PostStringMode)

-				{

-					if (commandString.IndexOf(id) == 0)

-					{

-						postString = commandString.Substring(id.Length);

-						return i;

-					}

-				}

-				else

-					if (commandString == id)

-				{

-					postString = "";

-					return i;

-				}

-			}

-			postString = "";

-			return -1;

-		}

-

-		static bool ParseSubCharsCommand(int numForms, CommandSubCharsSet[] forms,

-			string commandString, ArrayList indices)

-		{

-			indices.Clear();

-			int numUsedChars = 0;

-			for (int i = 0; i < numForms; i++)

-			{

-				CommandSubCharsSet charsSet = forms[i];

-				int currentIndex = -1;

-				int len = charsSet.Chars.Length;

-				for (int j = 0; j < len; j++)

-				{

-					char c = charsSet.Chars[j];

-					int newIndex = commandString.IndexOf(c);

-					if (newIndex >= 0)

-					{

-						if (currentIndex >= 0)

-							return false;

-						if (commandString.IndexOf(c, newIndex + 1) >= 0)

-							return false;

-						currentIndex = j;

-						numUsedChars++;

-					}

-				}

-				if (currentIndex == -1 && !charsSet.EmptyAllowed)

-					return false;

-				indices.Add(currentIndex);

-			}

-			return (numUsedChars == commandString.Length);

-		}

-		const char kSwitchID1 = '-';

-		const char kSwitchID2 = '/';

-

-		const char kSwitchMinus = '-';

-		const string kStopSwitchParsing = "--";

-

-		static bool IsItSwitchChar(char c)

-		{

-			return (c == kSwitchID1 || c == kSwitchID2);

-		}

-	}

-

-	public class CommandForm

-	{

-		public string IDString = "";

-		public bool PostStringMode = false;

-		public CommandForm(string idString, bool postStringMode)

-		{

-			IDString = idString;

-			PostStringMode = postStringMode;

-		}

-	}

-

-	class CommandSubCharsSet

-	{

-		public string Chars = "";

-		public bool EmptyAllowed = false;

-	}

-}

diff --git a/CS/7zip/Common/InBuffer.cs b/CS/7zip/Common/InBuffer.cs
deleted file mode 100644
index 9c47c73..0000000
--- a/CS/7zip/Common/InBuffer.cs
+++ /dev/null
@@ -1,72 +0,0 @@
-// InBuffer.cs

-

-namespace SevenZip.Buffer

-{

-	public class InBuffer

-	{

-		byte[] m_Buffer;

-		uint m_Pos;

-		uint m_Limit;

-		uint m_BufferSize;

-		System.IO.Stream m_Stream;

-		bool m_StreamWasExhausted;

-		ulong m_ProcessedSize;

-

-		public InBuffer(uint bufferSize)

-		{

-			m_Buffer = new byte[bufferSize];

-			m_BufferSize = bufferSize;

-		}

-

-		public void Init(System.IO.Stream stream)

-		{

-			m_Stream = stream;

-			m_ProcessedSize = 0;

-			m_Limit = 0;

-			m_Pos = 0;

-			m_StreamWasExhausted = false;

-		}

-

-		public bool ReadBlock()

-		{

-			if (m_StreamWasExhausted)

-				return false;

-			m_ProcessedSize += m_Pos;

-			int aNumProcessedBytes = m_Stream.Read(m_Buffer, 0, (int)m_BufferSize);

-			m_Pos = 0;

-			m_Limit = (uint)aNumProcessedBytes;

-			m_StreamWasExhausted = (aNumProcessedBytes == 0);

-			return (!m_StreamWasExhausted);

-		}

-

-

-		public void ReleaseStream()

-		{

-			// m_Stream.Close(); 

-			m_Stream = null;

-		}

-

-		public bool ReadByte(byte b) // check it

-		{

-			if (m_Pos >= m_Limit)

-				if (!ReadBlock())

-					return false;

-			b = m_Buffer[m_Pos++];

-			return true;

-		}

-

-		public byte ReadByte()

-		{

-			// return (byte)m_Stream.ReadByte();

-			if (m_Pos >= m_Limit)

-				if (!ReadBlock())

-					return 0xFF;

-			return m_Buffer[m_Pos++];

-		}

-

-		public ulong GetProcessedSize()

-		{

-			return m_ProcessedSize + m_Pos;

-		}

-	}

-}

diff --git a/CS/7zip/Common/OutBuffer.cs b/CS/7zip/Common/OutBuffer.cs
deleted file mode 100644
index c205aa6..0000000
--- a/CS/7zip/Common/OutBuffer.cs
+++ /dev/null
@@ -1,47 +0,0 @@
-// OutBuffer.cs

-

-namespace SevenZip.Buffer

-{

-	public class OutBuffer

-	{

-		byte[] m_Buffer;

-		uint m_Pos;

-		uint m_BufferSize;

-		System.IO.Stream m_Stream;

-		ulong m_ProcessedSize;

-

-		public OutBuffer(uint bufferSize)

-		{

-			m_Buffer = new byte[bufferSize];

-			m_BufferSize = bufferSize;

-		}

-

-		public void SetStream(System.IO.Stream stream) { m_Stream = stream; }

-		public void FlushStream() { m_Stream.Flush(); }

-		public void CloseStream() { m_Stream.Close(); }

-		public void ReleaseStream() { m_Stream = null; }

-

-		public void Init()

-		{

-			m_ProcessedSize = 0;

-			m_Pos = 0;

-		}

-

-		public void WriteByte(byte b)

-		{

-			m_Buffer[m_Pos++] = b;

-			if (m_Pos >= m_BufferSize)

-				FlushData();

-		}

-

-		public void FlushData()

-		{

-			if (m_Pos == 0)

-				return;

-			m_Stream.Write(m_Buffer, 0, (int)m_Pos);

-			m_Pos = 0;

-		}

-

-		public ulong GetProcessedSize() { return m_ProcessedSize + m_Pos; }

-	}

-}

diff --git a/CS/7zip/Compress/LZ/IMatchFinder.cs b/CS/7zip/Compress/LZ/IMatchFinder.cs
deleted file mode 100644
index 30fab86..0000000
--- a/CS/7zip/Compress/LZ/IMatchFinder.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-// IMatchFinder.cs

-

-using System;

-

-namespace SevenZip.Compression.LZ

-{

-	interface IInWindowStream

-	{

-		void SetStream(System.IO.Stream inStream);

-		void Init();

-		void ReleaseStream();

-		Byte GetIndexByte(Int32 index);

-		UInt32 GetMatchLen(Int32 index, UInt32 distance, UInt32 limit);

-		UInt32 GetNumAvailableBytes();

-	}

-

-	interface IMatchFinder : IInWindowStream

-	{

-		void Create(UInt32 historySize, UInt32 keepAddBufferBefore,

-				UInt32 matchMaxLen, UInt32 keepAddBufferAfter);

-		UInt32 GetMatches(UInt32[] distances);

-		void Skip(UInt32 num);

-	}

-}

diff --git a/CS/7zip/Compress/LZ/LzBinTree.cs b/CS/7zip/Compress/LZ/LzBinTree.cs
deleted file mode 100644
index 7a9ca20..0000000
--- a/CS/7zip/Compress/LZ/LzBinTree.cs
+++ /dev/null
@@ -1,367 +0,0 @@
-// LzBinTree.cs

-

-using System;

-

-namespace SevenZip.Compression.LZ

-{

-	public class BinTree : InWindow, IMatchFinder

-	{

-		UInt32 _cyclicBufferPos;

-		UInt32 _cyclicBufferSize = 0;

-		UInt32 _matchMaxLen;

-

-		UInt32[] _son;

-		UInt32[] _hash;

-

-		UInt32 _cutValue = 0xFF;

-		UInt32 _hashMask;

-		UInt32 _hashSizeSum = 0;

-

-		bool HASH_ARRAY = true;

-

-		const UInt32 kHash2Size = 1 << 10;

-		const UInt32 kHash3Size = 1 << 16;

-		const UInt32 kBT2HashSize = 1 << 16;

-		const UInt32 kStartMaxLen = 1;

-		const UInt32 kHash3Offset = kHash2Size;

-		const UInt32 kEmptyHashValue = 0;

-		const UInt32 kMaxValForNormalize = ((UInt32)1 << 31) - 1;

-	

-		UInt32 kNumHashDirectBytes = 0;

-		UInt32 kMinMatchCheck = 4;

-		UInt32 kFixHashSize = kHash2Size + kHash3Size;

-		

-		public void SetType(int numHashBytes)

-		{

-			HASH_ARRAY = (numHashBytes > 2);

-			if (HASH_ARRAY)

-			{

-				kNumHashDirectBytes = 0;

-				kMinMatchCheck = 4;

-				kFixHashSize = kHash2Size + kHash3Size;

-			}

-			else

-			{

-				kNumHashDirectBytes = 2;

-				kMinMatchCheck = 2 + 1;

-				kFixHashSize = 0;

-			}

-		}

-

-		public new void SetStream(System.IO.Stream stream) { base.SetStream(stream); }

-		public new void ReleaseStream() { base.ReleaseStream(); }

-		

-		public new void Init()

-		{

-			base.Init();

-			for (UInt32 i = 0; i < _hashSizeSum; i++)

-				_hash[i] = kEmptyHashValue;

-			_cyclicBufferPos = 0;

-			ReduceOffsets(-1);

-		}

-

-		public new void MovePos()

-		{

-			if (++_cyclicBufferPos >= _cyclicBufferSize)

-				_cyclicBufferPos = 0;

-			base.MovePos();

-			if (_pos == kMaxValForNormalize)

-				Normalize();

-		}

-

-		public new Byte GetIndexByte(Int32 index) { return base.GetIndexByte(index); }

-

-		public new UInt32 GetMatchLen(Int32 index, UInt32 distance, UInt32 limit)

-		{ return base.GetMatchLen(index, distance, limit); }

-

-		public new UInt32 GetNumAvailableBytes() { return base.GetNumAvailableBytes(); }

-

-		public void Create(UInt32 historySize, UInt32 keepAddBufferBefore,

-				UInt32 matchMaxLen, UInt32 keepAddBufferAfter)

-		{

-			if (historySize > kMaxValForNormalize - 256)

-				throw new Exception();

-			_cutValue = 16 + (matchMaxLen >> 1);

-				

-			UInt32 windowReservSize = (historySize + keepAddBufferBefore +

-					matchMaxLen + keepAddBufferAfter) / 2 + 256;

-

-			base.Create(historySize + keepAddBufferBefore, matchMaxLen + keepAddBufferAfter, windowReservSize);

-

-			_matchMaxLen = matchMaxLen;

-

-			UInt32 cyclicBufferSize = historySize + 1;

-			if (_cyclicBufferSize != cyclicBufferSize)

-				_son = new UInt32[(_cyclicBufferSize = cyclicBufferSize) * 2];

-

-			UInt32 hs = kBT2HashSize;

-

-			if (HASH_ARRAY)

-			{

-				hs = historySize - 1;

-				hs |= (hs >> 1);

-				hs |= (hs >> 2);

-				hs |= (hs >> 4);

-				hs |= (hs >> 8);

-				hs >>= 1;

-				hs |= 0xFFFF;

-				if (hs > (1 << 24))

-					hs >>= 1;

-				_hashMask = hs;

-				hs++;

-				hs += kFixHashSize;

-			}

-			if (hs != _hashSizeSum)

-				_hash = new UInt32[_hashSizeSum = hs];

-		}

-

-		public UInt32 GetMatches(UInt32[] distances)

-		{

-			UInt32 lenLimit;

-			if (_pos + _matchMaxLen <= _streamPos)

-				lenLimit = _matchMaxLen;

-			else

-			{

-				lenLimit = _streamPos - _pos;

-				if (lenLimit < kMinMatchCheck)

-				{

-					MovePos();

-					return 0;

-				}

-			}

-

-			UInt32 offset = 0;

-			UInt32 matchMinPos = (_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0;

-			UInt32 cur = _bufferOffset + _pos;

-			UInt32 maxLen = kStartMaxLen; // to avoid items for len < hashSize;

-			UInt32 hashValue, hash2Value = 0, hash3Value = 0;

-

-			if (HASH_ARRAY)

-			{

-				UInt32 temp = CRC.Table[_bufferBase[cur]] ^ _bufferBase[cur + 1];

-				hash2Value = temp & (kHash2Size - 1);

-				temp ^= ((UInt32)(_bufferBase[cur + 2]) << 8);

-				hash3Value = temp & (kHash3Size - 1);

-				hashValue = (temp ^ (CRC.Table[_bufferBase[cur + 3]] << 5)) & _hashMask;

-			}

-			else

-				hashValue = _bufferBase[cur] ^ ((UInt32)(_bufferBase[cur + 1]) << 8);

-

-			UInt32 curMatch = _hash[kFixHashSize + hashValue];

-			if (HASH_ARRAY)

-			{

-				UInt32 curMatch2 = _hash[hash2Value];

-				UInt32 curMatch3 = _hash[kHash3Offset + hash3Value];

-				_hash[hash2Value] = _pos;

-				_hash[kHash3Offset + hash3Value] = _pos;

-				if (curMatch2 > matchMinPos)

-					if (_bufferBase[_bufferOffset + curMatch2] == _bufferBase[cur])

-					{

-						distances[offset++] = maxLen = 2;

-						distances[offset++] = _pos - curMatch2 - 1;

-					}

-				if (curMatch3 > matchMinPos)

-					if (_bufferBase[_bufferOffset + curMatch3] == _bufferBase[cur])

-					{

-						if (curMatch3 == curMatch2)

-							offset -= 2;

-						distances[offset++] = maxLen = 3;

-						distances[offset++] = _pos - curMatch3 - 1;

-						curMatch2 = curMatch3;

-					}

-				if (offset != 0 && curMatch2 == curMatch)

-				{

-					offset -= 2;

-					maxLen = kStartMaxLen;

-				}

-			}

-

-			_hash[kFixHashSize + hashValue] = _pos;

-

-			UInt32 ptr0 = (_cyclicBufferPos << 1) + 1;

-			UInt32 ptr1 = (_cyclicBufferPos << 1);

-

-			UInt32 len0, len1;

-			len0 = len1 = kNumHashDirectBytes;

-			

-			if (kNumHashDirectBytes != 0)

-			{

-				if (curMatch > matchMinPos)

-				{

-					if (_bufferBase[_bufferOffset + curMatch + kNumHashDirectBytes] !=

-							_bufferBase[cur + kNumHashDirectBytes])

-					{

-						distances[offset++] = maxLen = kNumHashDirectBytes;

-						distances[offset++] = _pos - curMatch - 1;

-					}

-				}

-			}

-			

-			UInt32 count = _cutValue;

-			

-			while(true)

-			{

-				if(curMatch <= matchMinPos || count-- == 0)

-				{

-					_son[ptr0] = _son[ptr1] = kEmptyHashValue;

-					break;

-				}

-				UInt32 delta = _pos - curMatch;

-				UInt32 cyclicPos = ((delta <= _cyclicBufferPos) ?

-							(_cyclicBufferPos - delta) :

-							(_cyclicBufferPos - delta + _cyclicBufferSize)) << 1;

-

-				UInt32 pby1 = _bufferOffset + curMatch;

-				UInt32 len = Math.Min(len0, len1);

-				if (_bufferBase[pby1 + len] == _bufferBase[cur + len])

-				{

-					while(++len != lenLimit)

-						if (_bufferBase[pby1 + len] != _bufferBase[cur + len])

-							break;

-					if (maxLen < len)

-					{

-						distances[offset++] = maxLen = len;

-						distances[offset++] = delta - 1;

-						if (len == lenLimit)

-						{

-							_son[ptr1] = _son[cyclicPos];

-							_son[ptr0] = _son[cyclicPos + 1];

-							break;

-						}

-					}

-				}

-				if (_bufferBase[pby1 + len] < _bufferBase[cur + len])

-				{

-					_son[ptr1] = curMatch;

-					ptr1 = cyclicPos + 1;

-					curMatch = _son[ptr1];

-					len1 = len;

-				}

-				else

-				{

-					_son[ptr0] = curMatch;

-					ptr0 = cyclicPos;

-					curMatch = _son[ptr0];

-					len0 = len;

-				}

-			}

-			MovePos();

-			return offset;

-		}

-

-		public void Skip(UInt32 num)

-		{

-			do

-			{

-				UInt32 lenLimit;

-				if (_pos + _matchMaxLen <= _streamPos)

-					lenLimit = _matchMaxLen;

-				else

-				{

-					lenLimit = _streamPos - _pos;

-					if (lenLimit < kMinMatchCheck)

-					{

-						MovePos();

-						continue;

-					}

-				}

-

-				UInt32 matchMinPos = (_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0;

-				UInt32 cur = _bufferOffset + _pos;

-

-				UInt32 hashValue;

-

-				if (HASH_ARRAY)

-				{

-					UInt32 temp = CRC.Table[_bufferBase[cur]] ^ _bufferBase[cur + 1];

-					UInt32 hash2Value = temp & (kHash2Size - 1);

-					_hash[hash2Value] = _pos;

-					temp ^= ((UInt32)(_bufferBase[cur + 2]) << 8);

-					UInt32 hash3Value = temp & (kHash3Size - 1);

-					_hash[kHash3Offset + hash3Value] = _pos;

-					hashValue = (temp ^ (CRC.Table[_bufferBase[cur + 3]] << 5)) & _hashMask;

-				}

-				else

-					hashValue = _bufferBase[cur] ^ ((UInt32)(_bufferBase[cur + 1]) << 8);

-

-				UInt32 curMatch = _hash[kFixHashSize + hashValue];

-				_hash[kFixHashSize + hashValue] = _pos;

-

-				UInt32 ptr0 = (_cyclicBufferPos << 1) + 1;

-				UInt32 ptr1 = (_cyclicBufferPos << 1);

-

-				UInt32 len0, len1;

-				len0 = len1 = kNumHashDirectBytes;

-

-				UInt32 count = _cutValue;

-				while (true)

-				{

-					if (curMatch <= matchMinPos || count-- == 0)

-					{

-						_son[ptr0] = _son[ptr1] = kEmptyHashValue;

-						break;

-					}

-

-					UInt32 delta = _pos - curMatch;

-					UInt32 cyclicPos = ((delta <= _cyclicBufferPos) ?

-								(_cyclicBufferPos - delta) :

-								(_cyclicBufferPos - delta + _cyclicBufferSize)) << 1;

-

-					UInt32 pby1 = _bufferOffset + curMatch;

-					UInt32 len = Math.Min(len0, len1);

-					if (_bufferBase[pby1 + len] == _bufferBase[cur + len])

-					{

-						while (++len != lenLimit)

-							if (_bufferBase[pby1 + len] != _bufferBase[cur + len])

-								break;

-						if (len == lenLimit)

-						{

-							_son[ptr1] = _son[cyclicPos];

-							_son[ptr0] = _son[cyclicPos + 1];

-							break;

-						}

-					}

-					if (_bufferBase[pby1 + len] < _bufferBase[cur + len])

-					{

-						_son[ptr1] = curMatch;

-						ptr1 = cyclicPos + 1;

-						curMatch = _son[ptr1];

-						len1 = len;

-					}

-					else

-					{

-						_son[ptr0] = curMatch;

-						ptr0 = cyclicPos;

-						curMatch = _son[ptr0];

-						len0 = len;

-					}

-				}

-				MovePos();

-			}

-			while (--num != 0);

-		}

-

-		void NormalizeLinks(UInt32[] items, UInt32 numItems, UInt32 subValue)

-		{

-			for (UInt32 i = 0; i < numItems; i++)

-			{

-				UInt32 value = items[i];

-				if (value <= subValue)

-					value = kEmptyHashValue;

-				else

-					value -= subValue;

-				items[i] = value;

-			}

-		}

-

-		void Normalize()

-		{

-			UInt32 subValue = _pos - _cyclicBufferSize;

-			NormalizeLinks(_son, _cyclicBufferSize * 2, subValue);

-			NormalizeLinks(_hash, _hashSizeSum, subValue);

-			ReduceOffsets((Int32)subValue);

-		}

-

-		public void SetCutValue(UInt32 cutValue) { _cutValue = cutValue; }

-	}

-}

diff --git a/CS/7zip/Compress/LZ/LzInWindow.cs b/CS/7zip/Compress/LZ/LzInWindow.cs
deleted file mode 100644
index f1974ce..0000000
--- a/CS/7zip/Compress/LZ/LzInWindow.cs
+++ /dev/null
@@ -1,132 +0,0 @@
-// LzInWindow.cs

-

-using System;

-

-namespace SevenZip.Compression.LZ

-{

-	public class InWindow

-	{

-		public Byte[] _bufferBase = null; // pointer to buffer with data

-		System.IO.Stream _stream;

-		UInt32 _posLimit; // offset (from _buffer) of first byte when new block reading must be done

-		bool _streamEndWasReached; // if (true) then _streamPos shows real end of stream

-

-		UInt32 _pointerToLastSafePosition;

-

-		public UInt32 _bufferOffset;

-

-		public UInt32 _blockSize; // Size of Allocated memory block

-		public UInt32 _pos; // offset (from _buffer) of curent byte

-		UInt32 _keepSizeBefore; // how many BYTEs must be kept in buffer before _pos

-		UInt32 _keepSizeAfter; // how many BYTEs must be kept buffer after _pos

-		public UInt32 _streamPos; // offset (from _buffer) of first not read byte from Stream

-

-		public void MoveBlock()

-		{

-			UInt32 offset = (UInt32)(_bufferOffset) + _pos - _keepSizeBefore;

-			// we need one additional byte, since MovePos moves on 1 byte.

-			if (offset > 0)

-				offset--;

-			

-			UInt32 numBytes = (UInt32)(_bufferOffset) + _streamPos - offset;

-

-			// check negative offset ????

-			for (UInt32 i = 0; i < numBytes; i++)

-				_bufferBase[i] = _bufferBase[offset + i];

-			_bufferOffset -= offset;

-		}

-

-		public virtual void ReadBlock()

-		{

-			if (_streamEndWasReached)

-				return;

-			while (true)

-			{

-				int size = (int)((0 - _bufferOffset) + _blockSize - _streamPos);

-				if (size == 0)

-					return;

-				int numReadBytes = _stream.Read(_bufferBase, (int)(_bufferOffset + _streamPos), size);

-				if (numReadBytes == 0)

-				{

-					_posLimit = _streamPos;

-					UInt32 pointerToPostion = _bufferOffset + _posLimit;

-					if (pointerToPostion > _pointerToLastSafePosition)

-						_posLimit = (UInt32)(_pointerToLastSafePosition - _bufferOffset);

-

-					_streamEndWasReached = true;

-					return;

-				}

-				_streamPos += (UInt32)numReadBytes;

-				if (_streamPos >= _pos + _keepSizeAfter)

-					_posLimit = _streamPos - _keepSizeAfter;

-			}

-		}

-

-		void Free() { _bufferBase = null; }

-

-		public void Create(UInt32 keepSizeBefore, UInt32 keepSizeAfter, UInt32 keepSizeReserv)

-		{

-			_keepSizeBefore = keepSizeBefore;

-			_keepSizeAfter = keepSizeAfter;

-			UInt32 blockSize = keepSizeBefore + keepSizeAfter + keepSizeReserv;

-			if (_bufferBase == null || _blockSize != blockSize)

-			{

-				Free();

-				_blockSize = blockSize;

-				_bufferBase = new Byte[_blockSize];

-			}

-			_pointerToLastSafePosition = _blockSize - keepSizeAfter;

-		}

-

-		public void SetStream(System.IO.Stream stream) { _stream = stream; }

-		public void ReleaseStream() { _stream = null; }

-

-		public void Init()

-		{

-			_bufferOffset = 0;

-			_pos = 0;

-			_streamPos = 0;

-			_streamEndWasReached = false;

-			ReadBlock();

-		}

-

-		public void MovePos()

-		{

-			_pos++;

-			if (_pos > _posLimit)

-			{

-				UInt32 pointerToPostion = _bufferOffset + _pos;

-				if (pointerToPostion > _pointerToLastSafePosition)

-					MoveBlock();

-				ReadBlock();

-			}

-		}

-

-		public Byte GetIndexByte(Int32 index) { return _bufferBase[_bufferOffset + _pos + index]; }

-

-		// index + limit have not to exceed _keepSizeAfter;

-		public UInt32 GetMatchLen(Int32 index, UInt32 distance, UInt32 limit)

-		{

-			if (_streamEndWasReached)

-				if ((_pos + index) + limit > _streamPos)

-					limit = _streamPos - (UInt32)(_pos + index);

-			distance++;

-			// Byte *pby = _buffer + (size_t)_pos + index;

-			UInt32 pby = _bufferOffset + _pos + (UInt32)index;

-

-			UInt32 i;

-			for (i = 0; i < limit && _bufferBase[pby + i] == _bufferBase[pby + i - distance]; i++);

-			return i;

-		}

-

-		public UInt32 GetNumAvailableBytes() { return _streamPos - _pos; }

-

-		public void ReduceOffsets(Int32 subValue)

-		{

-			_bufferOffset += (UInt32)subValue;

-			_posLimit -= (UInt32)subValue;

-			_pos -= (UInt32)subValue;

-			_streamPos -= (UInt32)subValue;

-		}

-	}

-}

diff --git a/CS/7zip/Compress/LZ/LzOutWindow.cs b/CS/7zip/Compress/LZ/LzOutWindow.cs
deleted file mode 100644
index 84914f0..0000000
--- a/CS/7zip/Compress/LZ/LzOutWindow.cs
+++ /dev/null
@@ -1,110 +0,0 @@
-// LzOutWindow.cs

-

-namespace SevenZip.Compression.LZ

-{

-	public class OutWindow

-	{

-		byte[] _buffer = null;

-		uint _pos;

-		uint _windowSize = 0;

-		uint _streamPos;

-		System.IO.Stream _stream;

-

-		public uint TrainSize = 0;

-

-		public void Create(uint windowSize)

-		{

-			if (_windowSize != windowSize)

-			{

-				// System.GC.Collect();

-				_buffer = new byte[windowSize];

-			}

-			_windowSize = windowSize;

-			_pos = 0;

-			_streamPos = 0;

-		}

-

-		public void Init(System.IO.Stream stream, bool solid)

-		{

-			ReleaseStream();

-			_stream = stream;

-			if (!solid)

-			{

-				_streamPos = 0;

-				_pos = 0;

-				TrainSize = 0;

-			}

-		}

-	

-		public bool Train(System.IO.Stream stream)

-		{

-			long len = stream.Length;

-			uint size = (len < _windowSize) ? (uint)len : _windowSize;

-			TrainSize = size;

-			stream.Position = len - size;

-			_streamPos = _pos = 0;

-			while (size > 0)

-			{

-				uint curSize = _windowSize - _pos;

-				if (size < curSize)

-					curSize = size;

-				int numReadBytes = stream.Read(_buffer, (int)_pos, (int)curSize);

-				if (numReadBytes == 0)

-					return false;

-				size -= (uint)numReadBytes;

-				_pos += (uint)numReadBytes;

-				_streamPos += (uint)numReadBytes;

-				if (_pos == _windowSize)

-					_streamPos = _pos = 0;

-			}

-			return true;

-		}

-

-		public void ReleaseStream()

-		{

-			Flush();

-			_stream = null;

-		}

-

-		public void Flush()

-		{

-			uint size = _pos - _streamPos;

-			if (size == 0)

-				return;

-			_stream.Write(_buffer, (int)_streamPos, (int)size);

-			if (_pos >= _windowSize)

-				_pos = 0;

-			_streamPos = _pos;

-		}

-

-		public void CopyBlock(uint distance, uint len)

-		{

-			uint pos = _pos - distance - 1;

-			if (pos >= _windowSize)

-				pos += _windowSize;

-			for (; len > 0; len--)

-			{

-				if (pos >= _windowSize)

-					pos = 0;

-				_buffer[_pos++] = _buffer[pos++];

-				if (_pos >= _windowSize)

-					Flush();

-			}

-		}

-

-		public void PutByte(byte b)

-		{

-			_buffer[_pos++] = b;

-			if (_pos >= _windowSize)

-				Flush();

-		}

-

-		public byte GetByte(uint distance)

-		{

-			uint pos = _pos - distance - 1;

-			if (pos >= _windowSize)

-				pos += _windowSize;

-			return _buffer[pos];

-		}

-	}

-}

diff --git a/CS/7zip/Compress/LZMA/LzmaBase.cs b/CS/7zip/Compress/LZMA/LzmaBase.cs
deleted file mode 100644
index 8447a2a..0000000
--- a/CS/7zip/Compress/LZMA/LzmaBase.cs
+++ /dev/null
@@ -1,76 +0,0 @@
-// LzmaBase.cs

-

-namespace SevenZip.Compression.LZMA

-{

-	internal abstract class Base

-	{

-		public const uint kNumRepDistances = 4;

-		public const uint kNumStates = 12;

-

-		// static byte []kLiteralNextStates  = {0, 0, 0, 0, 1, 2, 3, 4,  5,  6,   4, 5};

-		// static byte []kMatchNextStates    = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10};

-		// static byte []kRepNextStates      = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11};

-		// static byte []kShortRepNextStates = {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11};

-

-		public struct State

-		{

-			public uint Index;

-			public void Init() { Index = 0; }

-			public void UpdateChar()

-			{

-				if (Index < 4) Index = 0;

-				else if (Index < 10) Index -= 3;

-				else Index -= 6;

-			}

-			public void UpdateMatch() { Index = (uint)(Index < 7 ? 7 : 10); }

-			public void UpdateRep() { Index = (uint)(Index < 7 ? 8 : 11); }

-			public void UpdateShortRep() { Index = (uint)(Index < 7 ? 9 : 11); }

-			public bool IsCharState() { return Index < 7; }

-		}

-

-		public const int kNumPosSlotBits = 6;

-		public const int kDicLogSizeMin = 0;

-		// public const int kDicLogSizeMax = 30;

-		// public const uint kDistTableSizeMax = kDicLogSizeMax * 2;

-

-		public const int kNumLenToPosStatesBits = 2; // it's for speed optimization

-		public const uint kNumLenToPosStates = 1 << kNumLenToPosStatesBits;

-

-		public const uint kMatchMinLen = 2;

-

-		public static uint GetLenToPosState(uint len)

-		{

-			len -= kMatchMinLen;

-			if (len < kNumLenToPosStates)

-				return len;

-			return (uint)(kNumLenToPosStates - 1);

-		}

-

-		public const int kNumAlignBits = 4;

-		public const uint kAlignTableSize = 1 << kNumAlignBits;

-		public const uint kAlignMask = (kAlignTableSize - 1);

-

-		public const uint kStartPosModelIndex = 4;

-		public const uint kEndPosModelIndex = 14;

-		public const uint kNumPosModels = kEndPosModelIndex - kStartPosModelIndex;

-

-		public const uint kNumFullDistances = 1 << ((int)kEndPosModelIndex / 2);

-

-		public const uint kNumLitPosStatesBitsEncodingMax = 4;

-		public const uint kNumLitContextBitsMax = 8;

-

-		public const int kNumPosStatesBitsMax = 4;

-		public const uint kNumPosStatesMax = (1 << kNumPosStatesBitsMax);

-		public const int kNumPosStatesBitsEncodingMax = 4;

-		public const uint kNumPosStatesEncodingMax = (1 << kNumPosStatesBitsEncodingMax);

-

-		public const int kNumLowLenBits = 3;

-		public const int kNumMidLenBits = 3;

-		public const int kNumHighLenBits = 8;

-		public const uint kNumLowLenSymbols = 1 << kNumLowLenBits;

-		public const uint kNumMidLenSymbols = 1 << kNumMidLenBits;

-		public const uint kNumLenSymbols = kNumLowLenSymbols + kNumMidLenSymbols +

-				(1 << kNumHighLenBits);

-		public const uint kMatchMaxLen = kMatchMinLen + kNumLenSymbols - 1;

-	}

-}

diff --git a/CS/7zip/Compress/LZMA/LzmaDecoder.cs b/CS/7zip/Compress/LZMA/LzmaDecoder.cs
deleted file mode 100644
index 00bfe63..0000000
--- a/CS/7zip/Compress/LZMA/LzmaDecoder.cs
+++ /dev/null
@@ -1,398 +0,0 @@
-// LzmaDecoder.cs

-

-using System;

-

-namespace SevenZip.Compression.LZMA

-{

-	using RangeCoder;

-

-	public class Decoder : ICoder, ISetDecoderProperties // ,System.IO.Stream

-	{

-		class LenDecoder

-		{

-			BitDecoder m_Choice = new BitDecoder();

-			BitDecoder m_Choice2 = new BitDecoder();

-			BitTreeDecoder[] m_LowCoder = new BitTreeDecoder[Base.kNumPosStatesMax];

-			BitTreeDecoder[] m_MidCoder = new BitTreeDecoder[Base.kNumPosStatesMax];

-			BitTreeDecoder m_HighCoder = new BitTreeDecoder(Base.kNumHighLenBits);

-			uint m_NumPosStates = 0;

-

-			public void Create(uint numPosStates)

-			{

-				for (uint posState = m_NumPosStates; posState < numPosStates; posState++)

-				{

-					m_LowCoder[posState] = new BitTreeDecoder(Base.kNumLowLenBits);

-					m_MidCoder[posState] = new BitTreeDecoder(Base.kNumMidLenBits);

-				}

-				m_NumPosStates = numPosStates;

-			}

-

-			public void Init()

-			{

-				m_Choice.Init();

-				for (uint posState = 0; posState < m_NumPosStates; posState++)

-				{

-					m_LowCoder[posState].Init();

-					m_MidCoder[posState].Init();

-				}

-				m_Choice2.Init();

-				m_HighCoder.Init();

-			}

-

-			public uint Decode(RangeCoder.Decoder rangeDecoder, uint posState)

-			{

-				if (m_Choice.Decode(rangeDecoder) == 0)

-					return m_LowCoder[posState].Decode(rangeDecoder);

-				else

-				{

-					uint symbol = Base.kNumLowLenSymbols;

-					if (m_Choice2.Decode(rangeDecoder) == 0)

-						symbol += m_MidCoder[posState].Decode(rangeDecoder);

-					else

-					{

-						symbol += Base.kNumMidLenSymbols;

-						symbol += m_HighCoder.Decode(rangeDecoder);

-					}

-					return symbol;

-				}

-			}

-		}

-

-		class LiteralDecoder

-		{

-			struct Decoder2

-			{

-				BitDecoder[] m_Decoders;

-				public void Create() { m_Decoders = new BitDecoder[0x300]; }

-				public void Init() { for (int i = 0; i < 0x300; i++) m_Decoders[i].Init(); }

-

-				public byte DecodeNormal(RangeCoder.Decoder rangeDecoder)

-				{

-					uint symbol = 1;

-					do

-						symbol = (symbol << 1) | m_Decoders[symbol].Decode(rangeDecoder);

-					while (symbol < 0x100);

-					return (byte)symbol;

-				}

-

-				public byte DecodeWithMatchByte(RangeCoder.Decoder rangeDecoder, byte matchByte)

-				{

-					uint symbol = 1;

-					do

-					{

-						uint matchBit = (uint)(matchByte >> 7) & 1;

-						matchByte <<= 1;

-						uint bit = m_Decoders[((1 + matchBit) << 8) + symbol].Decode(rangeDecoder);

-						symbol = (symbol << 1) | bit;

-						if (matchBit != bit)

-						{

-							while (symbol < 0x100)

-								symbol = (symbol << 1) | m_Decoders[symbol].Decode(rangeDecoder);

-							break;

-						}

-					}

-					while (symbol < 0x100);

-					return (byte)symbol;

-				}

-			}

-

-			Decoder2[] m_Coders;

-			int m_NumPrevBits;

-			int m_NumPosBits;

-			uint m_PosMask;

-

-			public void Create(int numPosBits, int numPrevBits)

-			{

-				if (m_Coders != null && m_NumPrevBits == numPrevBits &&

-					m_NumPosBits == numPosBits)

-					return;

-				m_NumPosBits = numPosBits;

-				m_PosMask = ((uint)1 << numPosBits) - 1;

-				m_NumPrevBits = numPrevBits;

-				uint numStates = (uint)1 << (m_NumPrevBits + m_NumPosBits);

-				m_Coders = new Decoder2[numStates];

-				for (uint i = 0; i < numStates; i++)

-					m_Coders[i].Create();

-			}

-

-			public void Init()

-			{

-				uint numStates = (uint)1 << (m_NumPrevBits + m_NumPosBits);

-				for (uint i = 0; i < numStates; i++)

-					m_Coders[i].Init();

-			}

-

-			uint GetState(uint pos, byte prevByte)

-			{ return ((pos & m_PosMask) << m_NumPrevBits) + (uint)(prevByte >> (8 - m_NumPrevBits)); }

-

-			public byte DecodeNormal(RangeCoder.Decoder rangeDecoder, uint pos, byte prevByte)

-			{ return m_Coders[GetState(pos, prevByte)].DecodeNormal(rangeDecoder); }

-

-			public byte DecodeWithMatchByte(RangeCoder.Decoder rangeDecoder, uint pos, byte prevByte, byte matchByte)

-			{ return m_Coders[GetState(pos, prevByte)].DecodeWithMatchByte(rangeDecoder, matchByte); }

-		};

-

-		LZ.OutWindow m_OutWindow = new LZ.OutWindow();

-		RangeCoder.Decoder m_RangeDecoder = new RangeCoder.Decoder();

-

-		BitDecoder[] m_IsMatchDecoders = new BitDecoder[Base.kNumStates << Base.kNumPosStatesBitsMax];

-		BitDecoder[] m_IsRepDecoders = new BitDecoder[Base.kNumStates];

-		BitDecoder[] m_IsRepG0Decoders = new BitDecoder[Base.kNumStates];

-		BitDecoder[] m_IsRepG1Decoders = new BitDecoder[Base.kNumStates];

-		BitDecoder[] m_IsRepG2Decoders = new BitDecoder[Base.kNumStates];

-		BitDecoder[] m_IsRep0LongDecoders = new BitDecoder[Base.kNumStates << Base.kNumPosStatesBitsMax];

-

-		BitTreeDecoder[] m_PosSlotDecoder = new BitTreeDecoder[Base.kNumLenToPosStates];

-		BitDecoder[] m_PosDecoders = new BitDecoder[Base.kNumFullDistances - Base.kEndPosModelIndex];

-

-		BitTreeDecoder m_PosAlignDecoder = new BitTreeDecoder(Base.kNumAlignBits);

-

-		LenDecoder m_LenDecoder = new LenDecoder();

-		LenDecoder m_RepLenDecoder = new LenDecoder();

-

-		LiteralDecoder m_LiteralDecoder = new LiteralDecoder();

-

-		uint m_DictionarySize;

-		uint m_DictionarySizeCheck;

-

-		uint m_PosStateMask;

-

-		public Decoder()

-		{

-			m_DictionarySize = 0xFFFFFFFF;

-			for (int i = 0; i < Base.kNumLenToPosStates; i++)

-				m_PosSlotDecoder[i] = new BitTreeDecoder(Base.kNumPosSlotBits);

-		}

-

-		void SetDictionarySize(uint dictionarySize)

-		{

-			if (m_DictionarySize != dictionarySize)

-			{

-				m_DictionarySize = dictionarySize;

-				m_DictionarySizeCheck = Math.Max(m_DictionarySize, 1);

-				uint blockSize = Math.Max(m_DictionarySizeCheck, (1 << 12));

-				m_OutWindow.Create(blockSize);

-			}

-		}

-

-		void SetLiteralProperties(int lp, int lc)

-		{

-			if (lp > 8)

-				throw new InvalidParamException();

-			if (lc > 8)

-				throw new InvalidParamException();

-			m_LiteralDecoder.Create(lp, lc);

-		}

-

-		void SetPosBitsProperties(int pb)

-		{

-			if (pb > Base.kNumPosStatesBitsMax)

-				throw new InvalidParamException();

-			uint numPosStates = (uint)1 << pb;

-			m_LenDecoder.Create(numPosStates);

-			m_RepLenDecoder.Create(numPosStates);

-			m_PosStateMask = numPosStates - 1;

-		}

-

-		bool _solid = false;

-		void Init(System.IO.Stream inStream, System.IO.Stream outStream)

-		{

-			m_RangeDecoder.Init(inStream);

-			m_OutWindow.Init(outStream, _solid);

-

-			uint i;

-			for (i = 0; i < Base.kNumStates; i++)

-			{

-				for (uint j = 0; j <= m_PosStateMask; j++)

-				{

-					uint index = (i << Base.kNumPosStatesBitsMax) + j;

-					m_IsMatchDecoders[index].Init();

-					m_IsRep0LongDecoders[index].Init();

-				}

-				m_IsRepDecoders[i].Init();

-				m_IsRepG0Decoders[i].Init();

-				m_IsRepG1Decoders[i].Init();

-				m_IsRepG2Decoders[i].Init();

-			}

-

-			m_LiteralDecoder.Init();

-			for (i = 0; i < Base.kNumLenToPosStates; i++)

-				m_PosSlotDecoder[i].Init();

-			// m_PosSpecDecoder.Init();

-			for (i = 0; i < Base.kNumFullDistances - Base.kEndPosModelIndex; i++)

-				m_PosDecoders[i].Init();

-

-			m_LenDecoder.Init();

-			m_RepLenDecoder.Init();

-			m_PosAlignDecoder.Init();

-		}

-

-		public void Code(System.IO.Stream inStream, System.IO.Stream outStream,

-			Int64 inSize, Int64 outSize, ICodeProgress progress)

-		{

-			Init(inStream, outStream);

-

-			Base.State state = new Base.State();

-			state.Init();

-			uint rep0 = 0, rep1 = 0, rep2 = 0, rep3 = 0;

-

-			UInt64 nowPos64 = 0;

-			UInt64 outSize64 = (UInt64)outSize;

-			if (nowPos64 < outSize64)

-			{

-				if (m_IsMatchDecoders[state.Index << Base.kNumPosStatesBitsMax].Decode(m_RangeDecoder) != 0)

-					throw new DataErrorException();

-				state.UpdateChar();

-				byte b = m_LiteralDecoder.DecodeNormal(m_RangeDecoder, 0, 0);

-				m_OutWindow.PutByte(b);

-				nowPos64++;

-			}

-			while (nowPos64 < outSize64)

-			{

-				// UInt64 next = Math.Min(nowPos64 + (1 << 18), outSize64);

-					// while(nowPos64 < next)

-				{

-					uint posState = (uint)nowPos64 & m_PosStateMask;

-					if (m_IsMatchDecoders[(state.Index << Base.kNumPosStatesBitsMax) + posState].Decode(m_RangeDecoder) == 0)

-					{

-						byte b;

-						byte prevByte = m_OutWindow.GetByte(0);

-						if (!state.IsCharState())

-							b = m_LiteralDecoder.DecodeWithMatchByte(m_RangeDecoder,

-								(uint)nowPos64, prevByte, m_OutWindow.GetByte(rep0));

-						else

-							b = m_LiteralDecoder.DecodeNormal(m_RangeDecoder, (uint)nowPos64, prevByte);

-						m_OutWindow.PutByte(b);

-						state.UpdateChar();

-						nowPos64++;

-					}

-					else

-					{

-						uint len;

-						if (m_IsRepDecoders[state.Index].Decode(m_RangeDecoder) == 1)

-						{

-							if (m_IsRepG0Decoders[state.Index].Decode(m_RangeDecoder) == 0)

-							{

-								if (m_IsRep0LongDecoders[(state.Index << Base.kNumPosStatesBitsMax) + posState].Decode(m_RangeDecoder) == 0)

-								{

-									state.UpdateShortRep();

-									m_OutWindow.PutByte(m_OutWindow.GetByte(rep0));

-									nowPos64++;

-									continue;

-								}

-							}

-							else

-							{

-								UInt32 distance;

-								if (m_IsRepG1Decoders[state.Index].Decode(m_RangeDecoder) == 0)

-								{

-									distance = rep1;

-								}

-								else

-								{

-									if (m_IsRepG2Decoders[state.Index].Decode(m_RangeDecoder) == 0)

-										distance = rep2;

-									else

-									{

-										distance = rep3;

-										rep3 = rep2;

-									}

-									rep2 = rep1;

-								}

-								rep1 = rep0;

-								rep0 = distance;

-							}

-							len = m_RepLenDecoder.Decode(m_RangeDecoder, posState) + Base.kMatchMinLen;

-							state.UpdateRep();

-						}

-						else

-						{

-							rep3 = rep2;

-							rep2 = rep1;

-							rep1 = rep0;

-							len = Base.kMatchMinLen + m_LenDecoder.Decode(m_RangeDecoder, posState);

-							state.UpdateMatch();

-							uint posSlot = m_PosSlotDecoder[Base.GetLenToPosState(len)].Decode(m_RangeDecoder);

-							if (posSlot >= Base.kStartPosModelIndex)

-							{

-								int numDirectBits = (int)((posSlot >> 1) - 1);

-								rep0 = ((2 | (posSlot & 1)) << numDirectBits);

-								if (posSlot < Base.kEndPosModelIndex)

-									rep0 += BitTreeDecoder.ReverseDecode(m_PosDecoders,

-											rep0 - posSlot - 1, m_RangeDecoder, numDirectBits);

-								else

-								{

-									rep0 += (m_RangeDecoder.DecodeDirectBits(

-										numDirectBits - Base.kNumAlignBits) << Base.kNumAlignBits);

-									rep0 += m_PosAlignDecoder.ReverseDecode(m_RangeDecoder);

-								}

-							}

-							else

-								rep0 = posSlot;

-						}

-						if (rep0 >= m_OutWindow.TrainSize + nowPos64 || rep0 >= m_DictionarySizeCheck)

-						{

-							if (rep0 == 0xFFFFFFFF)

-								break;

-							throw new DataErrorException();

-						}

-						m_OutWindow.CopyBlock(rep0, len);

-						nowPos64 += len;

-					}

-				}

-			}

-			m_OutWindow.Flush();

-			m_OutWindow.ReleaseStream();

-			m_RangeDecoder.ReleaseStream();

-		}

-

-		public void SetDecoderProperties(byte[] properties)

-		{

-			if (properties.Length < 5)

-				throw new InvalidParamException();

-			int lc = properties[0] % 9;

-			int remainder = properties[0] / 9;

-			int lp = remainder % 5;

-			int pb = remainder / 5;

-			if (pb > Base.kNumPosStatesBitsMax)

-				throw new InvalidParamException();

-			UInt32 dictionarySize = 0;

-			for (int i = 0; i < 4; i++)

-				dictionarySize += ((UInt32)(properties[1 + i])) << (i * 8);

-			SetDictionarySize(dictionarySize);

-			SetLiteralProperties(lp, lc);

-			SetPosBitsProperties(pb);

-		}

-

-		public bool Train(System.IO.Stream stream)

-		{

-			_solid = true;

-			return m_OutWindow.Train(stream);

-		}

-

-		/*

-		public override bool CanRead { get { return true; }}

-		public override bool CanWrite { get { return true; }}

-		public override bool CanSeek { get { return true; }}

-		public override long Length { get { return 0; }}

-		public override long Position

-		{

-			get { return 0;	}

-			set { }

-		}

-		public override void Flush() { }

-		public override int Read(byte[] buffer, int offset, int count) 

-		{

-			return 0;

-		}

-		public override void Write(byte[] buffer, int offset, int count)

-		{

-		}

-		public override long Seek(long offset, System.IO.SeekOrigin origin)

-		{

-			return 0;

-		}

-		public override void SetLength(long value) {}

-		*/

-	}

-}

diff --git a/CS/7zip/Compress/LZMA/LzmaEncoder.cs b/CS/7zip/Compress/LZMA/LzmaEncoder.cs
deleted file mode 100644
index 6dc2708..0000000
--- a/CS/7zip/Compress/LZMA/LzmaEncoder.cs
+++ /dev/null
@@ -1,1480 +0,0 @@
-// LzmaEncoder.cs

-

-using System;

-

-namespace SevenZip.Compression.LZMA

-{

-	using RangeCoder;

-

-	public class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties

-	{

-		enum EMatchFinderType

-		{

-			BT2,

-			BT4,

-		};

-

-		const UInt32 kIfinityPrice = 0xFFFFFFF;

-

-		static Byte[] g_FastPos = new Byte[1 << 11];

-

-		static Encoder()

-		{

-			const Byte kFastSlots = 22;

-			int c = 2;

-			g_FastPos[0] = 0;

-			g_FastPos[1] = 1;

-			for (Byte slotFast = 2; slotFast < kFastSlots; slotFast++)

-			{

-				UInt32 k = ((UInt32)1 << ((slotFast >> 1) - 1));

-				for (UInt32 j = 0; j < k; j++, c++)

-					g_FastPos[c] = slotFast;

-			}

-		}

-

-		static UInt32 GetPosSlot(UInt32 pos)

-		{

-			if (pos < (1 << 11))

-				return g_FastPos[pos];

-			if (pos < (1 << 21))

-				return (UInt32)(g_FastPos[pos >> 10] + 20);

-			return (UInt32)(g_FastPos[pos >> 20] + 40);

-		}

-

-		static UInt32 GetPosSlot2(UInt32 pos)

-		{

-			if (pos < (1 << 17))

-				return (UInt32)(g_FastPos[pos >> 6] + 12);

-			if (pos < (1 << 27))

-				return (UInt32)(g_FastPos[pos >> 16] + 32);

-			return (UInt32)(g_FastPos[pos >> 26] + 52);

-		}

-

-		Base.State _state = new Base.State();

-		Byte _previousByte;

-		UInt32[] _repDistances = new UInt32[Base.kNumRepDistances];

-

-		void BaseInit()

-		{

-			_state.Init();

-			_previousByte = 0;

-			for (UInt32 i = 0; i < Base.kNumRepDistances; i++)

-				_repDistances[i] = 0;

-		}

-

-		const int kDefaultDictionaryLogSize = 22;

-		const UInt32 kNumFastBytesDefault = 0x20;

-

-		class LiteralEncoder

-		{

-			public struct Encoder2

-			{

-				BitEncoder[] m_Encoders;

-

-				public void Create() { m_Encoders = new BitEncoder[0x300]; }

-

-				public void Init() { for (int i = 0; i < 0x300; i++) m_Encoders[i].Init(); }

-

-				public void Encode(RangeCoder.Encoder rangeEncoder, byte symbol)

-				{

-					uint context = 1;

-					for (int i = 7; i >= 0; i--)

-					{

-						uint bit = (uint)((symbol >> i) & 1);

-						m_Encoders[context].Encode(rangeEncoder, bit);

-						context = (context << 1) | bit;

-					}

-				}

-

-				public void EncodeMatched(RangeCoder.Encoder rangeEncoder, byte matchByte, byte symbol)

-				{

-					uint context = 1;

-					bool same = true;

-					for (int i = 7; i >= 0; i--)

-					{

-						uint bit = (uint)((symbol >> i) & 1);

-						uint state = context;

-						if (same)

-						{

-							uint matchBit = (uint)((matchByte >> i) & 1);

-							state += ((1 + matchBit) << 8);

-							same = (matchBit == bit);

-						}

-						m_Encoders[state].Encode(rangeEncoder, bit);

-						context = (context << 1) | bit;

-					}

-				}

-

-				public uint GetPrice(bool matchMode, byte matchByte, byte symbol)

-				{

-					uint price = 0;

-					uint context = 1;

-					int i = 7;

-					if (matchMode)

-					{

-						for (; i >= 0; i--)

-						{

-							uint matchBit = (uint)(matchByte >> i) & 1;

-							uint bit = (uint)(symbol >> i) & 1;

-							price += m_Encoders[((1 + matchBit) << 8) + context].GetPrice(bit);

-							context = (context << 1) | bit;

-							if (matchBit != bit)

-							{

-								i--;

-								break;

-							}

-						}

-					}

-					for (; i >= 0; i--)

-					{

-						uint bit = (uint)(symbol >> i) & 1;

-						price += m_Encoders[context].GetPrice(bit);

-						context = (context << 1) | bit;

-					}

-					return price;

-				}

-			}

-

-			Encoder2[] m_Coders;

-			int m_NumPrevBits;

-			int m_NumPosBits;

-			uint m_PosMask;

-

-			public void Create(int numPosBits, int numPrevBits)

-			{

-				if (m_Coders != null && m_NumPrevBits == numPrevBits && m_NumPosBits == numPosBits)

-					return;

-				m_NumPosBits = numPosBits;

-				m_PosMask = ((uint)1 << numPosBits) - 1;

-				m_NumPrevBits = numPrevBits;

-				uint numStates = (uint)1 << (m_NumPrevBits + m_NumPosBits);

-				m_Coders = new Encoder2[numStates];

-				for (uint i = 0; i < numStates; i++)

-					m_Coders[i].Create();

-			}

-

-			public void Init()

-			{

-				uint numStates = (uint)1 << (m_NumPrevBits + m_NumPosBits);

-				for (uint i = 0; i < numStates; i++)

-					m_Coders[i].Init();

-			}

-

-			public Encoder2 GetSubCoder(UInt32 pos, Byte prevByte)

-			{ return m_Coders[((pos & m_PosMask) << m_NumPrevBits) + (uint)(prevByte >> (8 - m_NumPrevBits))]; }

-		}

-

-		class LenEncoder

-		{

-			RangeCoder.BitEncoder _choice = new RangeCoder.BitEncoder();

-			RangeCoder.BitEncoder _choice2 = new RangeCoder.BitEncoder();

-			RangeCoder.BitTreeEncoder[] _lowCoder = new RangeCoder.BitTreeEncoder[Base.kNumPosStatesEncodingMax];

-			RangeCoder.BitTreeEncoder[] _midCoder = new RangeCoder.BitTreeEncoder[Base.kNumPosStatesEncodingMax];

-			RangeCoder.BitTreeEncoder _highCoder = new RangeCoder.BitTreeEncoder(Base.kNumHighLenBits);

-

-			public LenEncoder()

-			{

-				for (UInt32 posState = 0; posState < Base.kNumPosStatesEncodingMax; posState++)

-				{

-					_lowCoder[posState] = new RangeCoder.BitTreeEncoder(Base.kNumLowLenBits);

-					_midCoder[posState] = new RangeCoder.BitTreeEncoder(Base.kNumMidLenBits);

-				}

-			}

-

-			public void Init(UInt32 numPosStates)

-			{

-				_choice.Init();

-				_choice2.Init();

-				for (UInt32 posState = 0; posState < numPosStates; posState++)

-				{

-					_lowCoder[posState].Init();

-					_midCoder[posState].Init();

-				}

-				_highCoder.Init();

-			}

-

-			public void Encode(RangeCoder.Encoder rangeEncoder, UInt32 symbol, UInt32 posState)

-			{

-				if (symbol < Base.kNumLowLenSymbols)

-				{

-					_choice.Encode(rangeEncoder, 0);

-					_lowCoder[posState].Encode(rangeEncoder, symbol);

-				}

-				else

-				{

-					symbol -= Base.kNumLowLenSymbols;

-					_choice.Encode(rangeEncoder, 1);

-					if (symbol < Base.kNumMidLenSymbols)

-					{

-						_choice2.Encode(rangeEncoder, 0);

-						_midCoder[posState].Encode(rangeEncoder, symbol);

-					}

-					else

-					{

-						_choice2.Encode(rangeEncoder, 1);

-						_highCoder.Encode(rangeEncoder, symbol - Base.kNumMidLenSymbols);

-					}

-				}

-			}

-

-			public void SetPrices(UInt32 posState, UInt32 numSymbols, UInt32[] prices, UInt32 st)

-			{

-				UInt32 a0 = _choice.GetPrice0();

-				UInt32 a1 = _choice.GetPrice1();

-				UInt32 b0 = a1 + _choice2.GetPrice0();

-				UInt32 b1 = a1 + _choice2.GetPrice1();

-				UInt32 i = 0;

-				for (i = 0; i < Base.kNumLowLenSymbols; i++)

-				{

-					if (i >= numSymbols)

-						return;

-					prices[st + i] = a0 + _lowCoder[posState].GetPrice(i);

-				}

-				for (; i < Base.kNumLowLenSymbols + Base.kNumMidLenSymbols; i++)

-				{

-					if (i >= numSymbols)

-						return;

-					prices[st + i] = b0 + _midCoder[posState].GetPrice(i - Base.kNumLowLenSymbols);

-				}

-				for (; i < numSymbols; i++)

-					prices[st + i] = b1 + _highCoder.GetPrice(i - Base.kNumLowLenSymbols - Base.kNumMidLenSymbols);

-			}

-		};

-

-		const UInt32 kNumLenSpecSymbols = Base.kNumLowLenSymbols + Base.kNumMidLenSymbols;

-

-		class LenPriceTableEncoder : LenEncoder

-		{

-			UInt32[] _prices = new UInt32[Base.kNumLenSymbols << Base.kNumPosStatesBitsEncodingMax];

-			UInt32 _tableSize;

-			UInt32[] _counters = new UInt32[Base.kNumPosStatesEncodingMax];

-

-			public void SetTableSize(UInt32 tableSize) { _tableSize = tableSize; }

-

-			public UInt32 GetPrice(UInt32 symbol, UInt32 posState)

-			{

-				return _prices[posState * Base.kNumLenSymbols + symbol];

-			}

-

-			void UpdateTable(UInt32 posState)

-			{

-				SetPrices(posState, _tableSize, _prices, posState * Base.kNumLenSymbols);

-				_counters[posState] = _tableSize;

-			}

-

-			public void UpdateTables(UInt32 numPosStates)

-			{

-				for (UInt32 posState = 0; posState < numPosStates; posState++)

-					UpdateTable(posState);

-			}

-

-			public new void Encode(RangeCoder.Encoder rangeEncoder, UInt32 symbol, UInt32 posState)

-			{

-				base.Encode(rangeEncoder, symbol, posState);

-				if (--_counters[posState] == 0)

-					UpdateTable(posState);

-			}

-		}

-

-		const UInt32 kNumOpts = 1 << 12;

-		class Optimal

-		{

-			public Base.State State;

-

-			public bool Prev1IsChar;

-			public bool Prev2;

-

-			public UInt32 PosPrev2;

-			public UInt32 BackPrev2;

-

-			public UInt32 Price;

-			public UInt32 PosPrev;

-			public UInt32 BackPrev;

-

-			public UInt32 Backs0;

-			public UInt32 Backs1;

-			public UInt32 Backs2;

-			public UInt32 Backs3;

-

-			public void MakeAsChar() { BackPrev = 0xFFFFFFFF; Prev1IsChar = false; }

-			public void MakeAsShortRep() { BackPrev = 0; ; Prev1IsChar = false; }

-			public bool IsShortRep() { return (BackPrev == 0); }

-		};

-		Optimal[] _optimum = new Optimal[kNumOpts];

-		LZ.IMatchFinder _matchFinder = null;

-		RangeCoder.Encoder _rangeEncoder = new RangeCoder.Encoder();

-

-		RangeCoder.BitEncoder[] _isMatch = new RangeCoder.BitEncoder[Base.kNumStates << Base.kNumPosStatesBitsMax];

-		RangeCoder.BitEncoder[] _isRep = new RangeCoder.BitEncoder[Base.kNumStates];

-		RangeCoder.BitEncoder[] _isRepG0 = new RangeCoder.BitEncoder[Base.kNumStates];

-		RangeCoder.BitEncoder[] _isRepG1 = new RangeCoder.BitEncoder[Base.kNumStates];

-		RangeCoder.BitEncoder[] _isRepG2 = new RangeCoder.BitEncoder[Base.kNumStates];

-		RangeCoder.BitEncoder[] _isRep0Long = new RangeCoder.BitEncoder[Base.kNumStates << Base.kNumPosStatesBitsMax];

-

-		RangeCoder.BitTreeEncoder[] _posSlotEncoder = new RangeCoder.BitTreeEncoder[Base.kNumLenToPosStates];

-		

-		RangeCoder.BitEncoder[] _posEncoders = new RangeCoder.BitEncoder[Base.kNumFullDistances - Base.kEndPosModelIndex];

-		RangeCoder.BitTreeEncoder _posAlignEncoder = new RangeCoder.BitTreeEncoder(Base.kNumAlignBits);

-

-		LenPriceTableEncoder _lenEncoder = new LenPriceTableEncoder();

-		LenPriceTableEncoder _repMatchLenEncoder = new LenPriceTableEncoder();

-

-		LiteralEncoder _literalEncoder = new LiteralEncoder();

-

-		UInt32[] _matchDistances = new UInt32[Base.kMatchMaxLen * 2 + 2];

-		

-		UInt32 _numFastBytes = kNumFastBytesDefault;

-		UInt32 _longestMatchLength;

-		UInt32 _numDistancePairs;

-

-		UInt32 _additionalOffset;

-

-		UInt32 _optimumEndIndex;

-		UInt32 _optimumCurrentIndex;

-

-		bool _longestMatchWasFound;

-

-		UInt32[] _posSlotPrices = new UInt32[1 << (Base.kNumPosSlotBits + Base.kNumLenToPosStatesBits)];

-		UInt32[] _distancesPrices = new UInt32[Base.kNumFullDistances << Base.kNumLenToPosStatesBits];

-		UInt32[] _alignPrices = new UInt32[Base.kAlignTableSize];

-		UInt32 _alignPriceCount;

-

-		UInt32 _distTableSize = (kDefaultDictionaryLogSize * 2);

-

-		int _posStateBits = 2;

-		UInt32 _posStateMask = (4 - 1);

-		int _numLiteralPosStateBits = 0;

-		int _numLiteralContextBits = 3;

-

-		UInt32 _dictionarySize = (1 << kDefaultDictionaryLogSize);

-		UInt32 _dictionarySizePrev = 0xFFFFFFFF;

-		UInt32 _numFastBytesPrev = 0xFFFFFFFF;

-

-		Int64 nowPos64;

-		bool _finished;

-		System.IO.Stream _inStream;

-

-		EMatchFinderType _matchFinderType = EMatchFinderType.BT4;

-		bool _writeEndMark = false;

-		

-		bool _needReleaseMFStream;

-

-		void Create()

-		{

-			if (_matchFinder == null)

-			{

-				LZ.BinTree bt = new LZ.BinTree();

-				int numHashBytes = 4;

-				if (_matchFinderType == EMatchFinderType.BT2)

-					numHashBytes = 2;

-				bt.SetType(numHashBytes);

-				_matchFinder = bt;

-			}

-			_literalEncoder.Create(_numLiteralPosStateBits, _numLiteralContextBits);

-

-			if (_dictionarySize == _dictionarySizePrev && _numFastBytesPrev == _numFastBytes)

-				return;

-			_matchFinder.Create(_dictionarySize, kNumOpts, _numFastBytes, Base.kMatchMaxLen + 1);

-			_dictionarySizePrev = _dictionarySize;

-			_numFastBytesPrev = _numFastBytes;

-		}

-

-		public Encoder()

-		{

-			for (int i = 0; i < kNumOpts; i++)

-				_optimum[i] = new Optimal();

-			for (int i = 0; i < Base.kNumLenToPosStates; i++)

-				_posSlotEncoder[i] = new RangeCoder.BitTreeEncoder(Base.kNumPosSlotBits);

-		}

-

-		void SetWriteEndMarkerMode(bool writeEndMarker)

-		{

-			_writeEndMark = writeEndMarker;

-		}

-

-		void Init()

-		{

-			BaseInit();

-			_rangeEncoder.Init();

-

-			uint i;

-			for (i = 0; i < Base.kNumStates; i++)

-			{

-				for (uint j = 0; j <= _posStateMask; j++)

-				{

-					uint complexState = (i << Base.kNumPosStatesBitsMax) + j;

-					_isMatch[complexState].Init();

-					_isRep0Long[complexState].Init();

-				}

-				_isRep[i].Init();

-				_isRepG0[i].Init();

-				_isRepG1[i].Init();

-				_isRepG2[i].Init();

-			}

-			_literalEncoder.Init();

-			for (i = 0; i < Base.kNumLenToPosStates; i++)

-				_posSlotEncoder[i].Init();

-			for (i = 0; i < Base.kNumFullDistances - Base.kEndPosModelIndex; i++)

-				_posEncoders[i].Init();

-

-			_lenEncoder.Init((UInt32)1 << _posStateBits);

-			_repMatchLenEncoder.Init((UInt32)1 << _posStateBits);

-

-			_posAlignEncoder.Init();

-

-			_longestMatchWasFound = false;

-			_optimumEndIndex = 0;

-			_optimumCurrentIndex = 0;

-			_additionalOffset = 0;

-		}

-

-		void ReadMatchDistances(out UInt32 lenRes, out UInt32 numDistancePairs)

-		{

-			lenRes = 0;

-			numDistancePairs = _matchFinder.GetMatches(_matchDistances);

-			if (numDistancePairs > 0)

-			{

-				lenRes = _matchDistances[numDistancePairs - 2];

-				if (lenRes == _numFastBytes)

-					lenRes += _matchFinder.GetMatchLen((int)lenRes - 1, _matchDistances[numDistancePairs - 1],

-						Base.kMatchMaxLen - lenRes);

-			}

-			_additionalOffset++;

-		}

-

-

-		void MovePos(UInt32 num)

-		{

-			if (num > 0)

-			{

-				_matchFinder.Skip(num);

-				_additionalOffset += num;

-			}

-		}

-

-		UInt32 GetRepLen1Price(Base.State state, UInt32 posState)

-		{

-			return _isRepG0[state.Index].GetPrice0() +

-					_isRep0Long[(state.Index << Base.kNumPosStatesBitsMax) + posState].GetPrice0();

-		}

-

-		UInt32 GetPureRepPrice(UInt32 repIndex, Base.State state, UInt32 posState)

-		{

-			UInt32 price;

-			if (repIndex == 0)

-			{

-				price = _isRepG0[state.Index].GetPrice0();

-				price += _isRep0Long[(state.Index << Base.kNumPosStatesBitsMax) + posState].GetPrice1();

-			}

-			else

-			{

-				price = _isRepG0[state.Index].GetPrice1();

-				if (repIndex == 1)

-					price += _isRepG1[state.Index].GetPrice0();

-				else

-				{

-					price += _isRepG1[state.Index].GetPrice1();

-					price += _isRepG2[state.Index].GetPrice(repIndex - 2);

-				}

-			}

-			return price;

-		}

-

-		UInt32 GetRepPrice(UInt32 repIndex, UInt32 len, Base.State state, UInt32 posState)

-		{

-			UInt32 price = _repMatchLenEncoder.GetPrice(len - Base.kMatchMinLen, posState);

-			return price + GetPureRepPrice(repIndex, state, posState);

-		}

-	

-		UInt32 GetPosLenPrice(UInt32 pos, UInt32 len, UInt32 posState)

-		{

-			UInt32 price;

-			UInt32 lenToPosState = Base.GetLenToPosState(len);

-			if (pos < Base.kNumFullDistances)

-				price = _distancesPrices[(lenToPosState * Base.kNumFullDistances) + pos];

-			else

-				price = _posSlotPrices[(lenToPosState << Base.kNumPosSlotBits) + GetPosSlot2(pos)] +

-					_alignPrices[pos & Base.kAlignMask];

-			return price + _lenEncoder.GetPrice(len - Base.kMatchMinLen, posState);

-		}

-

-		UInt32 Backward(out UInt32 backRes, UInt32 cur)

-		{

-			_optimumEndIndex = cur;

-			UInt32 posMem = _optimum[cur].PosPrev;

-			UInt32 backMem = _optimum[cur].BackPrev;

-			do

-			{

-				if (_optimum[cur].Prev1IsChar)

-				{

-					_optimum[posMem].MakeAsChar();

-					_optimum[posMem].PosPrev = posMem - 1;

-					if (_optimum[cur].Prev2)

-					{

-						_optimum[posMem - 1].Prev1IsChar = false;

-						_optimum[posMem - 1].PosPrev = _optimum[cur].PosPrev2;

-						_optimum[posMem - 1].BackPrev = _optimum[cur].BackPrev2;

-					}

-				}

-				UInt32 posPrev = posMem;

-				UInt32 backCur = backMem;

-

-				backMem = _optimum[posPrev].BackPrev;

-				posMem = _optimum[posPrev].PosPrev;

-

-				_optimum[posPrev].BackPrev = backCur;

-				_optimum[posPrev].PosPrev = cur;

-				cur = posPrev;

-			}

-			while (cur > 0);

-			backRes = _optimum[0].BackPrev;

-			_optimumCurrentIndex = _optimum[0].PosPrev;

-			return _optimumCurrentIndex;

-		}

-

-		UInt32[] reps = new UInt32[Base.kNumRepDistances];

-		UInt32[] repLens = new UInt32[Base.kNumRepDistances];

-

-

-		UInt32 GetOptimum(UInt32 position, out UInt32 backRes)

-		{

-			if (_optimumEndIndex != _optimumCurrentIndex)

-			{

-				UInt32 lenRes = _optimum[_optimumCurrentIndex].PosPrev - _optimumCurrentIndex;

-				backRes = _optimum[_optimumCurrentIndex].BackPrev;

-				_optimumCurrentIndex = _optimum[_optimumCurrentIndex].PosPrev;

-				return lenRes;

-			}

-			_optimumCurrentIndex = _optimumEndIndex = 0;

-

-			UInt32 lenMain, numDistancePairs;

-			if (!_longestMatchWasFound)

-			{

-				ReadMatchDistances(out lenMain, out numDistancePairs);

-			}

-			else

-			{

-				lenMain = _longestMatchLength;

-				numDistancePairs = _numDistancePairs;

-				_longestMatchWasFound = false;

-			}

-

-			UInt32 numAvailableBytes = _matchFinder.GetNumAvailableBytes() + 1;

-			if (numAvailableBytes < 2)

-			{

-				backRes = 0xFFFFFFFF;

-				return 1;

-			}

-			if (numAvailableBytes > Base.kMatchMaxLen)

-				numAvailableBytes = Base.kMatchMaxLen;

-

-			UInt32 repMaxIndex = 0;

-			UInt32 i;			

-			for (i = 0; i < Base.kNumRepDistances; i++)

-			{

-				reps[i] = _repDistances[i];

-				repLens[i] = _matchFinder.GetMatchLen(0 - 1, reps[i], Base.kMatchMaxLen);

-				if (repLens[i] > repLens[repMaxIndex])

-					repMaxIndex = i;

-			}

-			if (repLens[repMaxIndex] >= _numFastBytes)

-			{

-				backRes = repMaxIndex;

-				UInt32 lenRes = repLens[repMaxIndex];

-				MovePos(lenRes - 1);

-				return lenRes;

-			}

-

-			if (lenMain >= _numFastBytes)

-			{

-				backRes = _matchDistances[numDistancePairs - 1] + Base.kNumRepDistances;

-				MovePos(lenMain - 1);

-				return lenMain;

-			}

-			

-			Byte currentByte = _matchFinder.GetIndexByte(0 - 1);

-			Byte matchByte = _matchFinder.GetIndexByte((Int32)(0 - _repDistances[0] - 1 - 1));

-

-			if (lenMain < 2 && currentByte != matchByte && repLens[repMaxIndex] < 2)

-			{

-				backRes = (UInt32)0xFFFFFFFF;

-				return 1;

-			}

-

-			_optimum[0].State = _state;

-

-			UInt32 posState = (position & _posStateMask);

-

-			_optimum[1].Price = _isMatch[(_state.Index << Base.kNumPosStatesBitsMax) + posState].GetPrice0() +

-					_literalEncoder.GetSubCoder(position, _previousByte).GetPrice(!_state.IsCharState(), matchByte, currentByte);

-			_optimum[1].MakeAsChar();

-

-			UInt32 matchPrice = _isMatch[(_state.Index << Base.kNumPosStatesBitsMax) + posState].GetPrice1();

-			UInt32 repMatchPrice = matchPrice + _isRep[_state.Index].GetPrice1();

-

-			if (matchByte == currentByte)

-			{

-				UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(_state, posState);

-				if (shortRepPrice < _optimum[1].Price)

-				{

-					_optimum[1].Price = shortRepPrice;

-					_optimum[1].MakeAsShortRep();

-				}

-			}

-

-			UInt32 lenEnd = ((lenMain >= repLens[repMaxIndex]) ? lenMain : repLens[repMaxIndex]);

-

-			if(lenEnd < 2)

-			{

-				backRes = _optimum[1].BackPrev;

-				return 1;

-			}

-			

-			_optimum[1].PosPrev = 0;

-

-			_optimum[0].Backs0 = reps[0];

-			_optimum[0].Backs1 = reps[1];

-			_optimum[0].Backs2 = reps[2];

-			_optimum[0].Backs3 = reps[3];

-

-			UInt32 len = lenEnd;

-			do

-				_optimum[len--].Price = kIfinityPrice;

-			while (len >= 2);

-

-			for (i = 0; i < Base.kNumRepDistances; i++)

-			{

-				UInt32 repLen = repLens[i];

-				if (repLen < 2)

-					continue;

-				UInt32 price = repMatchPrice + GetPureRepPrice(i, _state, posState);

-				do

-				{

-					UInt32 curAndLenPrice = price + _repMatchLenEncoder.GetPrice(repLen - 2, posState);

-					Optimal optimum = _optimum[repLen];

-					if (curAndLenPrice < optimum.Price)

-					{

-						optimum.Price = curAndLenPrice;

-						optimum.PosPrev = 0;

-						optimum.BackPrev = i;

-						optimum.Prev1IsChar = false;

-					}

-				}

-				while (--repLen >= 2);

-			}

-

-			UInt32 normalMatchPrice = matchPrice + _isRep[_state.Index].GetPrice0();

-			

-			len = ((repLens[0] >= 2) ? repLens[0] + 1 : 2);

-			if (len <= lenMain)

-			{

-				UInt32 offs = 0;

-				while (len > _matchDistances[offs])

-					offs += 2;

-				for (; ; len++)

-				{

-					UInt32 distance = _matchDistances[offs + 1];

-					UInt32 curAndLenPrice = normalMatchPrice + GetPosLenPrice(distance, len, posState);

-					Optimal optimum = _optimum[len];

-					if (curAndLenPrice < optimum.Price)

-					{

-						optimum.Price = curAndLenPrice;

-						optimum.PosPrev = 0;

-						optimum.BackPrev = distance + Base.kNumRepDistances;

-						optimum.Prev1IsChar = false;

-					}

-					if (len == _matchDistances[offs])

-					{

-						offs += 2;

-						if (offs == numDistancePairs)

-							break;

-					}

-				}

-			}

-

-			UInt32 cur = 0;

-

-			while (true)

-			{

-				cur++;

-				if (cur == lenEnd)

-					return Backward(out backRes, cur);

-				UInt32 newLen;

-				ReadMatchDistances(out newLen, out numDistancePairs);

-				if (newLen >= _numFastBytes)

-				{

-					_numDistancePairs = numDistancePairs;

-					_longestMatchLength = newLen;

-					_longestMatchWasFound = true;

-					return Backward(out backRes, cur);

-				}

-				position++;

-				UInt32 posPrev = _optimum[cur].PosPrev;

-				Base.State state;

-				if (_optimum[cur].Prev1IsChar)

-				{

-					posPrev--;

-					if (_optimum[cur].Prev2)

-					{

-						state = _optimum[_optimum[cur].PosPrev2].State;

-						if (_optimum[cur].BackPrev2 < Base.kNumRepDistances)

-							state.UpdateRep();

-						else

-							state.UpdateMatch();

-					}

-					else

-						state = _optimum[posPrev].State;

-					state.UpdateChar();

-				}

-				else

-					state = _optimum[posPrev].State;

-				if (posPrev == cur - 1)

-				{

-					if (_optimum[cur].IsShortRep())

-						state.UpdateShortRep();

-					else

-						state.UpdateChar();

-				}

-				else

-				{

-					UInt32 pos;

-					if (_optimum[cur].Prev1IsChar && _optimum[cur].Prev2)

-					{

-						posPrev = _optimum[cur].PosPrev2;

-						pos = _optimum[cur].BackPrev2;

-						state.UpdateRep();

-					}

-					else

-					{

-						pos = _optimum[cur].BackPrev;

-						if (pos < Base.kNumRepDistances)

-							state.UpdateRep();

-						else

-							state.UpdateMatch();

-					}

-					Optimal opt = _optimum[posPrev];

-					if (pos < Base.kNumRepDistances)

-					{

-						if (pos == 0)

-						{

-							reps[0] = opt.Backs0;

-							reps[1] = opt.Backs1;

-							reps[2] = opt.Backs2;

-							reps[3] = opt.Backs3;

-						}

-						else if (pos == 1)

-						{

-							reps[0] = opt.Backs1;

-							reps[1] = opt.Backs0;

-							reps[2] = opt.Backs2;

-							reps[3] = opt.Backs3;

-						}

-						else if (pos == 2)

-						{

-							reps[0] = opt.Backs2;

-							reps[1] = opt.Backs0;

-							reps[2] = opt.Backs1;

-							reps[3] = opt.Backs3;

-						}

-						else

-						{

-							reps[0] = opt.Backs3;

-							reps[1] = opt.Backs0;

-							reps[2] = opt.Backs1;

-							reps[3] = opt.Backs2;

-						}

-					}

-					else

-					{

-						reps[0] = (pos - Base.kNumRepDistances);

-						reps[1] = opt.Backs0;

-						reps[2] = opt.Backs1;

-						reps[3] = opt.Backs2;

-					}

-				}

-				_optimum[cur].State = state;

-				_optimum[cur].Backs0 = reps[0];

-				_optimum[cur].Backs1 = reps[1];

-				_optimum[cur].Backs2 = reps[2];

-				_optimum[cur].Backs3 = reps[3];

-				UInt32 curPrice = _optimum[cur].Price;

-

-				currentByte = _matchFinder.GetIndexByte(0 - 1);

-				matchByte = _matchFinder.GetIndexByte((Int32)(0 - reps[0] - 1 - 1));

-

-				posState = (position & _posStateMask);

-

-				UInt32 curAnd1Price = curPrice +

-					_isMatch[(state.Index << Base.kNumPosStatesBitsMax) + posState].GetPrice0() +

-					_literalEncoder.GetSubCoder(position, _matchFinder.GetIndexByte(0 - 2)).

-					GetPrice(!state.IsCharState(), matchByte, currentByte);

-

-				Optimal nextOptimum = _optimum[cur + 1];

-

-				bool nextIsChar = false;

-				if (curAnd1Price < nextOptimum.Price)

-				{

-					nextOptimum.Price = curAnd1Price;

-					nextOptimum.PosPrev = cur;

-					nextOptimum.MakeAsChar();

-					nextIsChar = true;

-				}

-

-				matchPrice = curPrice + _isMatch[(state.Index << Base.kNumPosStatesBitsMax) + posState].GetPrice1();

-				repMatchPrice = matchPrice + _isRep[state.Index].GetPrice1();

-

-				if (matchByte == currentByte &&

-					!(nextOptimum.PosPrev < cur && nextOptimum.BackPrev == 0))

-				{

-					UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(state, posState);

-					if (shortRepPrice <= nextOptimum.Price)

-					{

-						nextOptimum.Price = shortRepPrice;

-						nextOptimum.PosPrev = cur;

-						nextOptimum.MakeAsShortRep();

-						nextIsChar = true;

-					}

-				}

-

-				UInt32 numAvailableBytesFull = _matchFinder.GetNumAvailableBytes() + 1;

-				numAvailableBytesFull = Math.Min(kNumOpts - 1 - cur, numAvailableBytesFull);

-				numAvailableBytes = numAvailableBytesFull;

-

-				if (numAvailableBytes < 2)

-					continue;

-				if (numAvailableBytes > _numFastBytes)

-					numAvailableBytes = _numFastBytes;

-				if (!nextIsChar && matchByte != currentByte)

-				{

-					// try Literal + rep0

-					UInt32 t = Math.Min(numAvailableBytesFull - 1, _numFastBytes);

-					UInt32 lenTest2 = _matchFinder.GetMatchLen(0, reps[0], t);

-					if (lenTest2 >= 2)

-					{

-						Base.State state2 = state;

-						state2.UpdateChar();

-						UInt32 posStateNext = (position + 1) & _posStateMask;

-						UInt32 nextRepMatchPrice = curAnd1Price +

-							_isMatch[(state2.Index << Base.kNumPosStatesBitsMax) + posStateNext].GetPrice1() +

-							_isRep[state2.Index].GetPrice1();

-						{

-							UInt32 offset = cur + 1 + lenTest2;

-							while (lenEnd < offset)

-								_optimum[++lenEnd].Price = kIfinityPrice;

-							UInt32 curAndLenPrice = nextRepMatchPrice + GetRepPrice(

-								0, lenTest2, state2, posStateNext);

-							Optimal optimum = _optimum[offset];

-							if (curAndLenPrice < optimum.Price)

-							{

-								optimum.Price = curAndLenPrice;

-								optimum.PosPrev = cur + 1;

-								optimum.BackPrev = 0;

-								optimum.Prev1IsChar = true;

-								optimum.Prev2 = false;

-							}

-						}

-					}

-				}

-

-				UInt32 startLen = 2; // speed optimization 

-

-				for (UInt32 repIndex = 0; repIndex < Base.kNumRepDistances; repIndex++)

-				{

-					UInt32 lenTest = _matchFinder.GetMatchLen(0 - 1, reps[repIndex], numAvailableBytes);

-					if (lenTest < 2)

-						continue;

-					UInt32 lenTestTemp = lenTest;

-					do

-					{

-						while (lenEnd < cur + lenTest)

-							_optimum[++lenEnd].Price = kIfinityPrice;

-						UInt32 curAndLenPrice = repMatchPrice + GetRepPrice(repIndex, lenTest, state, posState);

-						Optimal optimum = _optimum[cur + lenTest];

-						if (curAndLenPrice < optimum.Price)

-						{

-							optimum.Price = curAndLenPrice;

-							optimum.PosPrev = cur;

-							optimum.BackPrev = repIndex;

-							optimum.Prev1IsChar = false;

-						}

-					}

-					while(--lenTest >= 2);

-					lenTest = lenTestTemp;

-

-					if (repIndex == 0)

-						startLen = lenTest + 1;

-

-					// if (_maxMode)

-					if (lenTest < numAvailableBytesFull)

-					{

-						UInt32 t = Math.Min(numAvailableBytesFull - 1 - lenTest, _numFastBytes);

-						UInt32 lenTest2 = _matchFinder.GetMatchLen((Int32)lenTest, reps[repIndex], t);

-						if (lenTest2 >= 2)

-						{

-							Base.State state2 = state;

-							state2.UpdateRep();

-							UInt32 posStateNext = (position + lenTest) & _posStateMask;

-							UInt32 curAndLenCharPrice = 

-									repMatchPrice + GetRepPrice(repIndex, lenTest, state, posState) + 

-									_isMatch[(state2.Index << Base.kNumPosStatesBitsMax) + posStateNext].GetPrice0() +

-									_literalEncoder.GetSubCoder(position + lenTest, 

-									_matchFinder.GetIndexByte((Int32)lenTest - 1 - 1)).GetPrice(true,

-									_matchFinder.GetIndexByte((Int32)((Int32)lenTest - 1 - (Int32)(reps[repIndex] + 1))), 

-									_matchFinder.GetIndexByte((Int32)lenTest - 1));

-							state2.UpdateChar();

-							posStateNext = (position + lenTest + 1) & _posStateMask;

-							UInt32 nextMatchPrice = curAndLenCharPrice + _isMatch[(state2.Index << Base.kNumPosStatesBitsMax) + posStateNext].GetPrice1();

-							UInt32 nextRepMatchPrice = nextMatchPrice + _isRep[state2.Index].GetPrice1();

-							

-							// for(; lenTest2 >= 2; lenTest2--)

-							{

-								UInt32 offset = lenTest + 1 + lenTest2;

-								while(lenEnd < cur + offset)

-									_optimum[++lenEnd].Price = kIfinityPrice;

-								UInt32 curAndLenPrice = nextRepMatchPrice + GetRepPrice(0, lenTest2, state2, posStateNext);

-								Optimal optimum = _optimum[cur + offset];

-								if (curAndLenPrice < optimum.Price) 

-								{

-									optimum.Price = curAndLenPrice;

-									optimum.PosPrev = cur + lenTest + 1;

-									optimum.BackPrev = 0;

-									optimum.Prev1IsChar = true;

-									optimum.Prev2 = true;

-									optimum.PosPrev2 = cur;

-									optimum.BackPrev2 = repIndex;

-								}

-							}

-						}

-					}

-				}

-

-				if (newLen > numAvailableBytes)

-				{

-					newLen = numAvailableBytes;

-					for (numDistancePairs = 0; newLen > _matchDistances[numDistancePairs]; numDistancePairs += 2) ;

-					_matchDistances[numDistancePairs] = newLen;

-					numDistancePairs += 2;

-				}

-				if (newLen >= startLen)

-				{

-					normalMatchPrice = matchPrice + _isRep[state.Index].GetPrice0();

-					while (lenEnd < cur + newLen)

-						_optimum[++lenEnd].Price = kIfinityPrice;

-

-					UInt32 offs = 0;

-					while (startLen > _matchDistances[offs])

-						offs += 2;

-

-					for (UInt32 lenTest = startLen; ; lenTest++)

-					{

-						UInt32 curBack = _matchDistances[offs + 1];

-						UInt32 curAndLenPrice = normalMatchPrice + GetPosLenPrice(curBack, lenTest, posState);

-						Optimal optimum = _optimum[cur + lenTest];

-						if (curAndLenPrice < optimum.Price)

-						{

-							optimum.Price = curAndLenPrice;

-							optimum.PosPrev = cur;

-							optimum.BackPrev = curBack + Base.kNumRepDistances;

-							optimum.Prev1IsChar = false;

-						}

-

-						if (lenTest == _matchDistances[offs])

-						{

-							if (lenTest < numAvailableBytesFull)

-							{

-								UInt32 t = Math.Min(numAvailableBytesFull - 1 - lenTest, _numFastBytes);

-								UInt32 lenTest2 = _matchFinder.GetMatchLen((Int32)lenTest, curBack, t);

-								if (lenTest2 >= 2)

-								{

-									Base.State state2 = state;

-									state2.UpdateMatch();

-									UInt32 posStateNext = (position + lenTest) & _posStateMask;

-									UInt32 curAndLenCharPrice = curAndLenPrice +

-										_isMatch[(state2.Index << Base.kNumPosStatesBitsMax) + posStateNext].GetPrice0() +

-										_literalEncoder.GetSubCoder(position + lenTest,

-										_matchFinder.GetIndexByte((Int32)lenTest - 1 - 1)).

-										GetPrice(true,

-										_matchFinder.GetIndexByte((Int32)lenTest - (Int32)(curBack + 1) - 1),

-										_matchFinder.GetIndexByte((Int32)lenTest - 1));

-									state2.UpdateChar();

-									posStateNext = (position + lenTest + 1) & _posStateMask;

-									UInt32 nextMatchPrice = curAndLenCharPrice + _isMatch[(state2.Index << Base.kNumPosStatesBitsMax) + posStateNext].GetPrice1();

-									UInt32 nextRepMatchPrice = nextMatchPrice + _isRep[state2.Index].GetPrice1();

-

-									UInt32 offset = lenTest + 1 + lenTest2;

-									while (lenEnd < cur + offset)

-										_optimum[++lenEnd].Price = kIfinityPrice;

-									curAndLenPrice = nextRepMatchPrice + GetRepPrice(0, lenTest2, state2, posStateNext);

-									optimum = _optimum[cur + offset];

-									if (curAndLenPrice < optimum.Price)

-									{

-										optimum.Price = curAndLenPrice;

-										optimum.PosPrev = cur + lenTest + 1;

-										optimum.BackPrev = 0;

-										optimum.Prev1IsChar = true;

-										optimum.Prev2 = true;

-										optimum.PosPrev2 = cur;

-										optimum.BackPrev2 = curBack + Base.kNumRepDistances;

-									}

-								}

-							}

-							offs += 2;

-							if (offs == numDistancePairs)

-								break;

-						}

-					}

-				}

-			}

-		}

-

-		bool ChangePair(UInt32 smallDist, UInt32 bigDist)

-		{

-			const int kDif = 7;

-			return (smallDist < ((UInt32)(1) << (32 - kDif)) && bigDist >= (smallDist << kDif));

-		}

-

-		void WriteEndMarker(UInt32 posState)

-		{

-			if (!_writeEndMark)

-				return;

-

-			_isMatch[(_state.Index << Base.kNumPosStatesBitsMax) + posState].Encode(_rangeEncoder, 1);

-			_isRep[_state.Index].Encode(_rangeEncoder, 0);

-			_state.UpdateMatch();

-			UInt32 len = Base.kMatchMinLen;

-			_lenEncoder.Encode(_rangeEncoder, len - Base.kMatchMinLen, posState);

-			UInt32 posSlot = (1 << Base.kNumPosSlotBits) - 1;

-			UInt32 lenToPosState = Base.GetLenToPosState(len);

-			_posSlotEncoder[lenToPosState].Encode(_rangeEncoder, posSlot);

-			int footerBits = 30;

-			UInt32 posReduced = (((UInt32)1) << footerBits) - 1;

-			_rangeEncoder.EncodeDirectBits(posReduced >> Base.kNumAlignBits, footerBits - Base.kNumAlignBits);

-			_posAlignEncoder.ReverseEncode(_rangeEncoder, posReduced & Base.kAlignMask);

-		}

-

-		void Flush(UInt32 nowPos)

-		{

-			ReleaseMFStream();

-			WriteEndMarker(nowPos & _posStateMask);

-			_rangeEncoder.FlushData();

-			_rangeEncoder.FlushStream();

-		}

-

-		public void CodeOneBlock(out Int64 inSize, out Int64 outSize, out bool finished)

-		{

-			inSize = 0;

-			outSize = 0;

-			finished = true;

-

-			if (_inStream != null)

-			{

-				_matchFinder.SetStream(_inStream);

-				_matchFinder.Init();

-				_needReleaseMFStream = true;

-				_inStream = null;

-				if (_trainSize > 0)

-					_matchFinder.Skip(_trainSize);

-			}

-

-			if (_finished)

-				return;

-			_finished = true;

-

-

-			Int64 progressPosValuePrev = nowPos64;

-			if (nowPos64 == 0)

-			{

-				if (_matchFinder.GetNumAvailableBytes() == 0)

-				{

-					Flush((UInt32)nowPos64);

-					return;

-				}

-				UInt32 len, numDistancePairs; // it's not used

-				ReadMatchDistances(out len, out numDistancePairs);

-				UInt32 posState = (UInt32)(nowPos64) & _posStateMask;

-				_isMatch[(_state.Index << Base.kNumPosStatesBitsMax) + posState].Encode(_rangeEncoder, 0);

-				_state.UpdateChar();

-				Byte curByte = _matchFinder.GetIndexByte((Int32)(0 - _additionalOffset));

-				_literalEncoder.GetSubCoder((UInt32)(nowPos64), _previousByte).Encode(_rangeEncoder, curByte);

-				_previousByte = curByte;

-				_additionalOffset--;

-				nowPos64++;

-			}

-			if (_matchFinder.GetNumAvailableBytes() == 0)

-			{

-				Flush((UInt32)nowPos64);

-				return;

-			}

-			while (true)

-			{

-				UInt32 pos;

-				UInt32 len = GetOptimum((UInt32)nowPos64, out pos);

-				

-				UInt32 posState = ((UInt32)nowPos64) & _posStateMask;

-				UInt32 complexState = (_state.Index << Base.kNumPosStatesBitsMax) + posState;

-				if (len == 1 && pos == 0xFFFFFFFF)

-				{

-					_isMatch[complexState].Encode(_rangeEncoder, 0);

-					Byte curByte = _matchFinder.GetIndexByte((Int32)(0 - _additionalOffset));

-					LiteralEncoder.Encoder2 subCoder = _literalEncoder.GetSubCoder((UInt32)nowPos64, _previousByte);

-					if (!_state.IsCharState())

-					{

-						Byte matchByte = _matchFinder.GetIndexByte((Int32)(0 - _repDistances[0] - 1 - _additionalOffset));

-						subCoder.EncodeMatched(_rangeEncoder, matchByte, curByte);

-					}

-					else

-						subCoder.Encode(_rangeEncoder, curByte);

-					_previousByte = curByte;

-					_state.UpdateChar();

-				}

-				else

-				{

-					_isMatch[complexState].Encode(_rangeEncoder, 1);

-					if (pos < Base.kNumRepDistances)

-					{

-						_isRep[_state.Index].Encode(_rangeEncoder, 1);

-						if (pos == 0)

-						{

-							_isRepG0[_state.Index].Encode(_rangeEncoder, 0);

-							if (len == 1)

-								_isRep0Long[complexState].Encode(_rangeEncoder, 0);

-							else

-								_isRep0Long[complexState].Encode(_rangeEncoder, 1);

-						}

-						else

-						{

-							_isRepG0[_state.Index].Encode(_rangeEncoder, 1);

-							if (pos == 1)

-								_isRepG1[_state.Index].Encode(_rangeEncoder, 0);

-							else

-							{

-								_isRepG1[_state.Index].Encode(_rangeEncoder, 1);

-								_isRepG2[_state.Index].Encode(_rangeEncoder, pos - 2);

-							}

-						}

-						if (len == 1)

-							_state.UpdateShortRep();

-						else

-						{

-							_repMatchLenEncoder.Encode(_rangeEncoder, len - Base.kMatchMinLen, posState);

-							_state.UpdateRep();

-						}

-						UInt32 distance = _repDistances[pos];

-						if (pos != 0)

-						{

-							for (UInt32 i = pos; i >= 1; i--)

-								_repDistances[i] = _repDistances[i - 1];

-							_repDistances[0] = distance;

-						}

-					}

-					else

-					{

-						_isRep[_state.Index].Encode(_rangeEncoder, 0);

-						_state.UpdateMatch();

-						_lenEncoder.Encode(_rangeEncoder, len - Base.kMatchMinLen, posState);

-						pos -= Base.kNumRepDistances;

-						UInt32 posSlot = GetPosSlot(pos);

-						UInt32 lenToPosState = Base.GetLenToPosState(len);

-						_posSlotEncoder[lenToPosState].Encode(_rangeEncoder, posSlot);

-

-						if (posSlot >= Base.kStartPosModelIndex)

-						{

-							int footerBits = (int)((posSlot >> 1) - 1);

-							UInt32 baseVal = ((2 | (posSlot & 1)) << footerBits);

-							UInt32 posReduced = pos - baseVal;

-

-							if (posSlot < Base.kEndPosModelIndex)

-								RangeCoder.BitTreeEncoder.ReverseEncode(_posEncoders,

-										baseVal - posSlot - 1, _rangeEncoder, footerBits, posReduced);

-							else

-							{

-								_rangeEncoder.EncodeDirectBits(posReduced >> Base.kNumAlignBits, footerBits - Base.kNumAlignBits);

-								_posAlignEncoder.ReverseEncode(_rangeEncoder, posReduced & Base.kAlignMask);

-								_alignPriceCount++;

-							}

-						}

-						UInt32 distance = pos;

-						for (UInt32 i = Base.kNumRepDistances - 1; i >= 1; i--)

-							_repDistances[i] = _repDistances[i - 1];

-						_repDistances[0] = distance;

-						_matchPriceCount++;

-					}

-					_previousByte = _matchFinder.GetIndexByte((Int32)(len - 1 - _additionalOffset));

-				}

-				_additionalOffset -= len;

-				nowPos64 += len;

-				if (_additionalOffset == 0)

-				{

-					// if (!_fastMode)

-					if (_matchPriceCount >= (1 << 7))

-						FillDistancesPrices();

-					if (_alignPriceCount >= Base.kAlignTableSize)

-						FillAlignPrices();

-					inSize = nowPos64;

-					outSize = _rangeEncoder.GetProcessedSizeAdd();

-					if (_matchFinder.GetNumAvailableBytes() == 0)

-					{

-						Flush((UInt32)nowPos64);

-						return;

-					}

-

-					if (nowPos64 - progressPosValuePrev >= (1 << 12))

-					{

-						_finished = false;

-						finished = false;

-						return;

-					}

-				}

-			}

-		}

-

-		void ReleaseMFStream()

-		{

-			if (_matchFinder != null && _needReleaseMFStream)

-			{

-				_matchFinder.ReleaseStream();

-				_needReleaseMFStream = false;

-			}

-		}

-

-		void SetOutStream(System.IO.Stream outStream) { _rangeEncoder.SetStream(outStream); }

-		void ReleaseOutStream() { _rangeEncoder.ReleaseStream(); }

-

-		void ReleaseStreams()

-		{

-			ReleaseMFStream();

-			ReleaseOutStream();

-		}

-

-		void SetStreams(System.IO.Stream inStream, System.IO.Stream outStream,

-				Int64 inSize, Int64 outSize)

-		{

-			_inStream = inStream;

-			_finished = false;

-			Create();

-			SetOutStream(outStream);

-			Init();

-

-			// if (!_fastMode)

-			{

-				FillDistancesPrices();

-				FillAlignPrices();

-			}

-

-			_lenEncoder.SetTableSize(_numFastBytes + 1 - Base.kMatchMinLen);

-			_lenEncoder.UpdateTables((UInt32)1 << _posStateBits);

-			_repMatchLenEncoder.SetTableSize(_numFastBytes + 1 - Base.kMatchMinLen);

-			_repMatchLenEncoder.UpdateTables((UInt32)1 << _posStateBits);

-

-			nowPos64 = 0;

-		}

-

-

-		public void Code(System.IO.Stream inStream, System.IO.Stream outStream,

-			Int64 inSize, Int64 outSize, ICodeProgress progress)

-		{

-			_needReleaseMFStream = false;

-			try

-			{

-				SetStreams(inStream, outStream, inSize, outSize);

-				while (true)

-				{

-					Int64 processedInSize;

-					Int64 processedOutSize;

-					bool finished;

-					CodeOneBlock(out processedInSize, out processedOutSize, out finished);

-					if (finished)

-						return;

-					if (progress != null)

-					{

-						progress.SetProgress(processedInSize, processedOutSize);

-					}

-				}

-			}

-			finally

-			{

-				ReleaseStreams();

-			}

-		}

-

-		const int kPropSize = 5;

-		Byte[] properties = new Byte[kPropSize];

-

-		public void WriteCoderProperties(System.IO.Stream outStream)

-		{

-			properties[0] = (Byte)((_posStateBits * 5 + _numLiteralPosStateBits) * 9 + _numLiteralContextBits);

-			for (int i = 0; i < 4; i++)

-				properties[1 + i] = (Byte)((_dictionarySize >> (8 * i)) & 0xFF);

-			outStream.Write(properties, 0, kPropSize);

-		}

-		

-		UInt32[] tempPrices = new UInt32[Base.kNumFullDistances];

-		UInt32 _matchPriceCount;

-

-		void FillDistancesPrices()

-		{

-			for (UInt32 i = Base.kStartPosModelIndex; i < Base.kNumFullDistances; i++)

-			{ 

-				UInt32 posSlot = GetPosSlot(i);

-				int footerBits = (int)((posSlot >> 1) - 1);

-				UInt32 baseVal = ((2 | (posSlot & 1)) << footerBits);

-				tempPrices[i] = BitTreeEncoder.ReverseGetPrice(_posEncoders, 

-					baseVal - posSlot - 1, footerBits, i - baseVal);

-			}

-

-			for (UInt32 lenToPosState = 0; lenToPosState < Base.kNumLenToPosStates; lenToPosState++)

-			{

-				UInt32 posSlot;

-				RangeCoder.BitTreeEncoder encoder = _posSlotEncoder[lenToPosState];

-			

-				UInt32 st = (lenToPosState << Base.kNumPosSlotBits);

-				for (posSlot = 0; posSlot < _distTableSize; posSlot++)

-					_posSlotPrices[st + posSlot] = encoder.GetPrice(posSlot);

-				for (posSlot = Base.kEndPosModelIndex; posSlot < _distTableSize; posSlot++)

-					_posSlotPrices[st + posSlot] += ((((posSlot >> 1) - 1) - Base.kNumAlignBits) << RangeCoder.BitEncoder.kNumBitPriceShiftBits);

-

-				UInt32 st2 = lenToPosState * Base.kNumFullDistances;

-				UInt32 i;

-				for (i = 0; i < Base.kStartPosModelIndex; i++)

-					_distancesPrices[st2 + i] = _posSlotPrices[st + i];

-				for (; i < Base.kNumFullDistances; i++)

-					_distancesPrices[st2 + i] = _posSlotPrices[st + GetPosSlot(i)] + tempPrices[i];

-			}

-			_matchPriceCount = 0;

-		}

-

-		void FillAlignPrices()

-		{

-			for (UInt32 i = 0; i < Base.kAlignTableSize; i++)

-				_alignPrices[i] = _posAlignEncoder.ReverseGetPrice(i);

-			_alignPriceCount = 0;

-		}

-

-

-		static string[] kMatchFinderIDs = 

-		{

-			"BT2",

-			"BT4",

-		};

-

-		static int FindMatchFinder(string s)

-		{

-			for (int m = 0; m < kMatchFinderIDs.Length; m++)

-				if (s == kMatchFinderIDs[m])

-					return m;

-			return -1;

-		}

-	

-		public void SetCoderProperties(CoderPropID[] propIDs, object[] properties)

-		{

-			for (UInt32 i = 0; i < properties.Length; i++)

-			{

-				object prop = properties[i];

-				switch (propIDs[i])

-				{

-					case CoderPropID.NumFastBytes:

-					{

-						if (!(prop is Int32))

-							throw new InvalidParamException();

-						Int32 numFastBytes = (Int32)prop;

-						if (numFastBytes < 5 || numFastBytes > Base.kMatchMaxLen)

-							throw new InvalidParamException();

-						_numFastBytes = (UInt32)numFastBytes;

-						break;

-					}

-					case CoderPropID.Algorithm:

-					{

-						/*

-						if (!(prop is Int32))

-							throw new InvalidParamException();

-						Int32 maximize = (Int32)prop;

-						_fastMode = (maximize == 0);

-						_maxMode = (maximize >= 2);

-						*/

-						break;

-					}

-					case CoderPropID.MatchFinder:

-					{

-						if (!(prop is String))

-							throw new InvalidParamException();

-						EMatchFinderType matchFinderIndexPrev = _matchFinderType;

-						int m = FindMatchFinder(((string)prop).ToUpper());

-						if (m < 0)

-							throw new InvalidParamException();

-						_matchFinderType = (EMatchFinderType)m;

-						if (_matchFinder != null && matchFinderIndexPrev != _matchFinderType)

-							{

-							_dictionarySizePrev = 0xFFFFFFFF;

-							_matchFinder = null;

-							}

-						break;

-					}

-					case CoderPropID.DictionarySize:

-					{

-						const int kDicLogSizeMaxCompress = 30;

-						if (!(prop is Int32))

-							throw new InvalidParamException(); ;

-						Int32 dictionarySize = (Int32)prop;

-						if (dictionarySize < (UInt32)(1 << Base.kDicLogSizeMin) ||

-							dictionarySize > (UInt32)(1 << kDicLogSizeMaxCompress))

-							throw new InvalidParamException();

-						_dictionarySize = (UInt32)dictionarySize;

-						int dicLogSize;

-						for (dicLogSize = 0; dicLogSize < (UInt32)kDicLogSizeMaxCompress; dicLogSize++)

-							if (dictionarySize <= ((UInt32)(1) << dicLogSize))

-								break;

-						_distTableSize = (UInt32)dicLogSize * 2;

-						break;

-					}

-					case CoderPropID.PosStateBits:

-					{

-						if (!(prop is Int32))

-							throw new InvalidParamException();

-						Int32 v = (Int32)prop;

-						if (v < 0 || v > (UInt32)Base.kNumPosStatesBitsEncodingMax)

-							throw new InvalidParamException();

-						_posStateBits = (int)v;

-						_posStateMask = (((UInt32)1) << (int)_posStateBits) - 1;

-						break;

-					}

-					case CoderPropID.LitPosBits:

-					{

-						if (!(prop is Int32))

-							throw new InvalidParamException();

-						Int32 v = (Int32)prop;

-						if (v < 0 || v > (UInt32)Base.kNumLitPosStatesBitsEncodingMax)

-							throw new InvalidParamException();

-						_numLiteralPosStateBits = (int)v;

-						break;

-					}

-					case CoderPropID.LitContextBits:

-					{

-						if (!(prop is Int32))

-							throw new InvalidParamException();

-						Int32 v = (Int32)prop;

-						if (v < 0 || v > (UInt32)Base.kNumLitContextBitsMax)

-							throw new InvalidParamException(); ;

-						_numLiteralContextBits = (int)v;

-						break;

-					}

-					case CoderPropID.EndMarker:

-					{

-						if (!(prop is Boolean))

-							throw new InvalidParamException();

-						SetWriteEndMarkerMode((Boolean)prop);

-						break;

-					}

-					default:

-						throw new InvalidParamException();

-				}

-			}

-		}

-

-		uint _trainSize = 0;

-		public void SetTrainSize(uint trainSize)

-		{

-			_trainSize = trainSize;

-		}

-		

-	}

-}

diff --git a/CS/7zip/Compress/LzmaAlone/LzmaAlone.cs b/CS/7zip/Compress/LzmaAlone/LzmaAlone.cs
deleted file mode 100644
index 8aa4462..0000000
--- a/CS/7zip/Compress/LzmaAlone/LzmaAlone.cs
+++ /dev/null
@@ -1,364 +0,0 @@
-using System;

-using System.IO;

-namespace SevenZip

-{

-	using CommandLineParser;

-	

-	public class CDoubleStream: Stream

-	{

-		public System.IO.Stream s1;

-		public System.IO.Stream s2;

-		public int fileIndex;

-		public long skipSize;

-		

-		public override bool CanRead { get { return true; }}

-		public override bool CanWrite { get { return false; }}

-		public override bool CanSeek { get { return false; }}

-		public override long Length { get { return s1.Length + s2.Length - skipSize; } }

-		public override long Position

-		{

-			get { return 0;	}

-			set { }

-		}

-		public override void Flush() { }

-		public override int Read(byte[] buffer, int offset, int count) 

-		{

-			int numTotal = 0;

-			while (count > 0)

-			{

-				if (fileIndex == 0)

-				{

-					int num = s1.Read(buffer, offset, count);

-					offset += num;

-					count -= num;

-					numTotal += num;

-					if (num == 0)

-						fileIndex++;

-				}

-				if (fileIndex == 1)

-				{

-					numTotal += s2.Read(buffer, offset, count);

-					return numTotal;

-				}

-			}

-			return numTotal;

-		}

-		public override void Write(byte[] buffer, int offset, int count)

-		{

-			throw (new Exception("can't Write"));

-		}

-		public override long Seek(long offset, System.IO.SeekOrigin origin)

-		{

-			throw (new Exception("can't Seek"));

-		}

-		public override void SetLength(long value)

-		{

-			throw (new Exception("can't SetLength"));

-		}

-	}

-	

-	class LzmaAlone

-	{

-		enum Key

-		{

-			Help1 = 0,

-			Help2,

-			Mode,

-			Dictionary,

-			FastBytes,

-			LitContext,

-			LitPos,

-			PosBits,

-			MatchFinder,

-			EOS,

-			StdIn,

-			StdOut,

-			Train

-		};

-

-		static void PrintHelp()

-		{

-			System.Console.WriteLine("\nUsage:  LZMA <e|d> [<switches>...] inputFile outputFile\n" +

-				"  e: encode file\n" +

-				"  d: decode file\n" +

-				"  b: Benchmark\n" +

-				"<Switches>\n" +

-				// "  -a{N}:  set compression mode - [0, 1], default: 1 (max)\n" +

-				"  -d{N}:  set dictionary - [0, 29], default: 23 (8MB)\n" +

-				"  -fb{N}: set number of fast bytes - [5, 273], default: 128\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{MF_ID}: set Match Finder: [bt2, bt4], default: bt4\n" +

-				"  -eos:   write End Of Stream marker\n"

-				// + "  -si:    read data from stdin\n"

-				// + "  -so:    write data to stdout\n"

-				);

-		}

-

-		static bool GetNumber(string s, out Int32 v)

-		{

-			v = 0;

-			for (int i = 0; i < s.Length; i++)

-			{

-				char c = s[i];

-				if (c < '0' || c > '9')

-					return false;

-				v *= 10;

-				v += (Int32)(c - '0');

-			}

-			return true;

-		}

-

-		static int IncorrectCommand()

-		{

-			throw (new Exception("Command line error"));

-			// System.Console.WriteLine("\nCommand line error\n");

-			// return 1;

-		}

-		static int Main2(string[] args)

-		{

-			System.Console.WriteLine("\nLZMA# 4.61  2008-11-23\n");

-

-			if (args.Length == 0)

-			{

-				PrintHelp();

-				return 0;

-			}

-

-			SwitchForm[] kSwitchForms = new SwitchForm[13];

-			int sw = 0;

-			kSwitchForms[sw++] = new SwitchForm("?", SwitchType.Simple, false);

-			kSwitchForms[sw++] = new SwitchForm("H", SwitchType.Simple, false);

-			kSwitchForms[sw++] = new SwitchForm("A", SwitchType.UnLimitedPostString, false, 1);

-			kSwitchForms[sw++] = new SwitchForm("D", SwitchType.UnLimitedPostString, false, 1);

-			kSwitchForms[sw++] = new SwitchForm("FB", SwitchType.UnLimitedPostString, false, 1);

-			kSwitchForms[sw++] = new SwitchForm("LC", SwitchType.UnLimitedPostString, false, 1);

-			kSwitchForms[sw++] = new SwitchForm("LP", SwitchType.UnLimitedPostString, false, 1);

-			kSwitchForms[sw++] = new SwitchForm("PB", SwitchType.UnLimitedPostString, false, 1);

-			kSwitchForms[sw++] = new SwitchForm("MF", SwitchType.UnLimitedPostString, false, 1);

-			kSwitchForms[sw++] = new SwitchForm("EOS", SwitchType.Simple, false);

-			kSwitchForms[sw++] = new SwitchForm("SI", SwitchType.Simple, false);

-			kSwitchForms[sw++] = new SwitchForm("SO", SwitchType.Simple, false);

-			kSwitchForms[sw++] = new SwitchForm("T", SwitchType.UnLimitedPostString, false, 1);

-

-

-			Parser parser = new Parser(sw);

-			try

-			{

-				parser.ParseStrings(kSwitchForms, args);

-			}

-			catch

-			{

-				return IncorrectCommand();

-			}

-

-			if (parser[(int)Key.Help1].ThereIs || parser[(int)Key.Help2].ThereIs)

-			{

-				PrintHelp();

-				return 0;

-			}

-

-			System.Collections.ArrayList nonSwitchStrings = parser.NonSwitchStrings;

-

-			int paramIndex = 0;

-			if (paramIndex >= nonSwitchStrings.Count)

-				return IncorrectCommand();

-			string command = (string)nonSwitchStrings[paramIndex++];

-			command = command.ToLower();

-

-			bool dictionaryIsDefined = false;

-			Int32 dictionary = 1 << 21;

-			if (parser[(int)Key.Dictionary].ThereIs)

-			{

-				Int32 dicLog;

-				if (!GetNumber((string)parser[(int)Key.Dictionary].PostStrings[0], out dicLog))

-					IncorrectCommand();

-				dictionary = (Int32)1 << dicLog;

-				dictionaryIsDefined = true;

-			}

-			string mf = "bt4";

-			if (parser[(int)Key.MatchFinder].ThereIs)

-				mf = (string)parser[(int)Key.MatchFinder].PostStrings[0];

-			mf = mf.ToLower();

-

-			if (command == "b")

-			{

-				const Int32 kNumDefaultItereations = 10;

-				Int32 numIterations = kNumDefaultItereations;

-				if (paramIndex < nonSwitchStrings.Count)

-					if (!GetNumber((string)nonSwitchStrings[paramIndex++], out numIterations))

-						numIterations = kNumDefaultItereations;

-				return LzmaBench.LzmaBenchmark(numIterations, (UInt32)dictionary);

-			}

-

-			string train = "";

-			if (parser[(int)Key.Train].ThereIs)

-				train = (string)parser[(int)Key.Train].PostStrings[0];

-

-			bool encodeMode = false;

-			if (command == "e")

-				encodeMode = true;

-			else if (command == "d")

-				encodeMode = false;

-			else

-				IncorrectCommand();

-

-			bool stdInMode = parser[(int)Key.StdIn].ThereIs;

-			bool stdOutMode = parser[(int)Key.StdOut].ThereIs;

-

-			Stream inStream = null;

-			if (stdInMode)

-			{

-				throw (new Exception("Not implemeted"));

-			}

-			else

-			{

-				if (paramIndex >= nonSwitchStrings.Count)

-					IncorrectCommand();

-				string inputName = (string)nonSwitchStrings[paramIndex++];

-				inStream = new FileStream(inputName, FileMode.Open, FileAccess.Read);

-			}

-

-			FileStream outStream = null;

-			if (stdOutMode)

-			{

-				throw (new Exception("Not implemeted"));

-			}

-			else

-			{

-				if (paramIndex >= nonSwitchStrings.Count)

-					IncorrectCommand();

-				string outputName = (string)nonSwitchStrings[paramIndex++];

-				outStream = new FileStream(outputName, FileMode.Create, FileAccess.Write);

-			}

-

-			FileStream trainStream = null;

-			if (train.Length != 0)

-				trainStream = new FileStream(train, FileMode.Open, FileAccess.Read);

-

-			if (encodeMode)

-			{

-				if (!dictionaryIsDefined)

-					dictionary = 1 << 23;

-

-				Int32 posStateBits = 2;

-				Int32 litContextBits = 3; // for normal files

-				// UInt32 litContextBits = 0; // for 32-bit data

-				Int32 litPosBits = 0;

-				// UInt32 litPosBits = 2; // for 32-bit data

-				Int32 algorithm = 2;

-				Int32 numFastBytes = 128;

-

-				bool eos = parser[(int)Key.EOS].ThereIs || stdInMode;

-

-				if (parser[(int)Key.Mode].ThereIs)

-					if (!GetNumber((string)parser[(int)Key.Mode].PostStrings[0], out algorithm))

-						IncorrectCommand();

-

-				if (parser[(int)Key.FastBytes].ThereIs)

-					if (!GetNumber((string)parser[(int)Key.FastBytes].PostStrings[0], out numFastBytes))

-						IncorrectCommand();

-				if (parser[(int)Key.LitContext].ThereIs)

-					if (!GetNumber((string)parser[(int)Key.LitContext].PostStrings[0], out litContextBits))

-						IncorrectCommand();

-				if (parser[(int)Key.LitPos].ThereIs)

-					if (!GetNumber((string)parser[(int)Key.LitPos].PostStrings[0], out litPosBits))

-						IncorrectCommand();

-				if (parser[(int)Key.PosBits].ThereIs)

-					if (!GetNumber((string)parser[(int)Key.PosBits].PostStrings[0], out posStateBits))

-						IncorrectCommand();

-

-				CoderPropID[] propIDs = 

-				{

-					CoderPropID.DictionarySize,

-					CoderPropID.PosStateBits,

-					CoderPropID.LitContextBits,

-					CoderPropID.LitPosBits,

-					CoderPropID.Algorithm,

-					CoderPropID.NumFastBytes,

-					CoderPropID.MatchFinder,

-					CoderPropID.EndMarker

-				};

-				object[] properties = 

-				{

-					(Int32)(dictionary),

-					(Int32)(posStateBits),

-					(Int32)(litContextBits),

-					(Int32)(litPosBits),

-					(Int32)(algorithm),

-					(Int32)(numFastBytes),

-					mf,

-					eos

-				};

-

-				Compression.LZMA.Encoder encoder = new Compression.LZMA.Encoder();

-				encoder.SetCoderProperties(propIDs, properties);

-				encoder.WriteCoderProperties(outStream);

-				Int64 fileSize;

-				if (eos || stdInMode)

-					fileSize = -1;

-				else

-					fileSize = inStream.Length;

-				for (int i = 0; i < 8; i++)

-					outStream.WriteByte((Byte)(fileSize >> (8 * i)));

-				if (trainStream != null)

-				{

-					CDoubleStream doubleStream = new CDoubleStream();

-					doubleStream.s1 = trainStream;

-					doubleStream.s2 = inStream;

-					doubleStream.fileIndex = 0;

-					inStream = doubleStream;

-					long trainFileSize = trainStream.Length;

-					doubleStream.skipSize = 0;

-					if (trainFileSize > dictionary)

-						doubleStream.skipSize = trainFileSize - dictionary;

-					trainStream.Seek(doubleStream.skipSize, SeekOrigin.Begin);

-					encoder.SetTrainSize((uint)(trainFileSize - doubleStream.skipSize));

-				}

-				encoder.Code(inStream, outStream, -1, -1, null);

-			}

-			else if (command == "d")

-			{

-				byte[] properties = new byte[5];

-				if (inStream.Read(properties, 0, 5) != 5)

-					throw (new Exception("input .lzma is too short"));

-				Compression.LZMA.Decoder decoder = new Compression.LZMA.Decoder();

-				decoder.SetDecoderProperties(properties);

-				if (trainStream != null)

-				{

-					if (!decoder.Train(trainStream))

-						throw (new Exception("can't train"));

-				}

-				long outSize = 0;

-				for (int i = 0; i < 8; i++)

-				{

-					int v = inStream.ReadByte();

-					if (v < 0)

-						throw (new Exception("Can't Read 1"));

-					outSize |= ((long)(byte)v) << (8 * i);

-				}

-				long compressedSize = inStream.Length - inStream.Position;

-				decoder.Code(inStream, outStream, compressedSize, outSize, null);

-			}

-			else

-				throw (new Exception("Command Error"));

-			return 0;

-		}

-

-		[STAThread]

-		static int Main(string[] args)

-		{

-			try

-			{

-				return Main2(args);

-			}

-			catch (Exception e)

-			{

-				Console.WriteLine("{0} Caught exception #1.", e);

-				// throw e;

-				return 1;

-			}

-		}

-	}

-}

diff --git a/CS/7zip/Compress/LzmaAlone/LzmaAlone.csproj b/CS/7zip/Compress/LzmaAlone/LzmaAlone.csproj
deleted file mode 100644
index ceb7073..0000000
--- a/CS/7zip/Compress/LzmaAlone/LzmaAlone.csproj
+++ /dev/null
@@ -1,90 +0,0 @@
-<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

-  <PropertyGroup>

-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>

-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>

-    <ProductVersion>8.0.50727</ProductVersion>

-    <SchemaVersion>2.0</SchemaVersion>

-    <ProjectGuid>{CE33DF18-F9C8-4D6F-9057-DBB4DB96E973}</ProjectGuid>

-    <OutputType>Exe</OutputType>

-    <RootNamespace>LzmaAlone</RootNamespace>

-    <AssemblyName>Lzma#</AssemblyName>

-    <WarningLevel>4</WarningLevel>

-  </PropertyGroup>

-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">

-    <DebugSymbols>true</DebugSymbols>

-    <DebugType>full</DebugType>

-    <Optimize>false</Optimize>

-    <OutputPath>.\bin\Debug\</OutputPath>

-    <DefineConstants>DEBUG;TRACE</DefineConstants>

-  </PropertyGroup>

-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">

-    <DebugSymbols>false</DebugSymbols>

-    <Optimize>true</Optimize>

-    <OutputPath>.\bin\Release\</OutputPath>

-    <DefineConstants>TRACE</DefineConstants>

-    <PlatformTarget>AnyCPU</PlatformTarget>

-  </PropertyGroup>

-  <ItemGroup>

-    <Reference Include="System" />

-    <Reference Include="System.Data" />

-    <Reference Include="System.Xml" />

-  </ItemGroup>

-  <ItemGroup>

-    <Compile Include="..\..\Common\CommandLineParser.cs">

-      <Link>Common\CommandLineParser.cs</Link>

-    </Compile>

-    <Compile Include="..\..\Common\CRC.cs">

-      <Link>Common\CRC.cs</Link>

-    </Compile>

-    <Compile Include="..\..\ICoder.cs">

-      <Link>ICoder.cs</Link>

-    </Compile>

-    <Compile Include="..\LZ\IMatchFinder.cs">

-      <Link>LZ\IMatchFinder.cs</Link>

-    </Compile>

-    <Compile Include="..\LZ\LzBinTree.cs">

-      <Link>LZ\LzBinTree.cs</Link>

-    </Compile>

-    <Compile Include="..\LZ\LzInWindow.cs">

-      <Link>LZ\LzInWindow.cs</Link>

-    </Compile>

-    <Compile Include="..\LZ\LzOutWindow.cs">

-      <Link>LZ\LzOutWindow.cs</Link>

-    </Compile>

-    <Compile Include="..\LZMA\LzmaBase.cs">

-      <Link>LZMA\LzmaBase.cs</Link>

-    </Compile>

-    <Compile Include="..\LZMA\LzmaDecoder.cs">

-      <Link>LZMA\LzmaDecoder.cs</Link>

-    </Compile>

-    <Compile Include="..\LZMA\LzmaEncoder.cs">

-      <Link>LZMA\LzmaEncoder.cs</Link>

-    </Compile>

-    <Compile Include="..\RangeCoder\RangeCoder.cs">

-      <Link>RangeCoder\RangeCoder.cs</Link>

-    </Compile>

-    <Compile Include="..\RangeCoder\RangeCoderBit.cs">

-      <Link>RangeCoder\RangeCoderBit.cs</Link>

-    </Compile>

-    <Compile Include="..\RangeCoder\RangeCoderBitTree.cs">

-      <Link>RangeCoder\RangeCoderBitTree.cs</Link>

-    </Compile>

-    <Compile Include="LzmaAlone.cs">

-      <SubType>Code</SubType>

-    </Compile>

-    <Compile Include="LzmaBench.cs">

-      <SubType>Code</SubType>

-    </Compile>

-    <Compile Include="Properties\AssemblyInfo.cs" />

-    <Compile Include="Properties\Settings.cs">

-      <AutoGen>True</AutoGen>

-      <DependentUpon>Settings.settings</DependentUpon>

-    </Compile>

-    <None Include="Properties\Settings.settings">

-      <Generator>SettingsSingleFileGenerator</Generator>

-      <LastGenOutput>Settings.cs</LastGenOutput>

-    </None>

-    <AppDesigner Include="Properties\" />

-  </ItemGroup>

-  <Import Project="$(MSBuildBinPath)\Microsoft.CSHARP.Targets" />

-</Project>
\ No newline at end of file
diff --git a/CS/7zip/Compress/LzmaAlone/LzmaAlone.sln b/CS/7zip/Compress/LzmaAlone/LzmaAlone.sln
deleted file mode 100644
index a96ee3e..0000000
--- a/CS/7zip/Compress/LzmaAlone/LzmaAlone.sln
+++ /dev/null
@@ -1,20 +0,0 @@
-

-Microsoft Visual Studio Solution File, Format Version 9.00

-# Visual C# Express 2005

-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LzmaAlone", "LzmaAlone.csproj", "{CE33DF18-F9C8-4D6F-9057-DBB4DB96E973}"

-EndProject

-Global

-	GlobalSection(SolutionConfigurationPlatforms) = preSolution

-		Debug|Any CPU = Debug|Any CPU

-		Release|Any CPU = Release|Any CPU

-	EndGlobalSection

-	GlobalSection(ProjectConfigurationPlatforms) = postSolution

-		{CE33DF18-F9C8-4D6F-9057-DBB4DB96E973}.Debug|Any CPU.ActiveCfg = Debug|Any CPU

-		{CE33DF18-F9C8-4D6F-9057-DBB4DB96E973}.Debug|Any CPU.Build.0 = Debug|Any CPU

-		{CE33DF18-F9C8-4D6F-9057-DBB4DB96E973}.Release|Any CPU.ActiveCfg = Release|Any CPU

-		{CE33DF18-F9C8-4D6F-9057-DBB4DB96E973}.Release|Any CPU.Build.0 = Release|Any CPU

-	EndGlobalSection

-	GlobalSection(SolutionProperties) = preSolution

-		HideSolutionNode = FALSE

-	EndGlobalSection

-EndGlobal

diff --git a/CS/7zip/Compress/LzmaAlone/LzmaBench.cs b/CS/7zip/Compress/LzmaAlone/LzmaBench.cs
deleted file mode 100644
index 6a1ffe2..0000000
--- a/CS/7zip/Compress/LzmaAlone/LzmaBench.cs
+++ /dev/null
@@ -1,340 +0,0 @@
-// LzmaBench.cs

-

-using System;

-using System.IO;

-

-namespace SevenZip

-{

-	/// <summary>

-	/// LZMA Benchmark

-	/// </summary>

-	internal abstract class LzmaBench

-	{

-		const UInt32 kAdditionalSize = (6 << 20);

-		const UInt32 kCompressedAdditionalSize = (1 << 10);

-		const UInt32 kMaxLzmaPropSize = 10;

-

-		class CRandomGenerator

-		{

-			UInt32 A1;

-			UInt32 A2;

-			public CRandomGenerator() { Init(); }

-			public void Init() { A1 = 362436069; A2 = 521288629; }

-			public UInt32 GetRnd()

-			{

-				return

-					((A1 = 36969 * (A1 & 0xffff) + (A1 >> 16)) << 16) ^

-					((A2 = 18000 * (A2 & 0xffff) + (A2 >> 16)));

-			}

-		};

-

-		class CBitRandomGenerator

-		{

-			CRandomGenerator RG = new CRandomGenerator();

-			UInt32 Value;

-			int NumBits;

-			public void Init()

-			{

-				Value = 0;

-				NumBits = 0;

-			}

-			public UInt32 GetRnd(int numBits)

-			{

-				UInt32 result;

-				if (NumBits > numBits)

-				{

-					result = Value & (((UInt32)1 << numBits) - 1);

-					Value >>= numBits;

-					NumBits -= numBits;

-					return result;

-				}

-				numBits -= NumBits;

-				result = (Value << numBits);

-				Value = RG.GetRnd();

-				result |= Value & (((UInt32)1 << numBits) - 1);

-				Value >>= numBits;

-				NumBits = 32 - numBits;

-				return result;

-			}

-		};

-

-		class CBenchRandomGenerator

-		{

-			CBitRandomGenerator RG = new CBitRandomGenerator();

-			UInt32 Pos;

-			UInt32 Rep0;

-			

-			public UInt32 BufferSize;

-			public Byte[] Buffer = null;

-

-			public CBenchRandomGenerator() { }

-

-			public void Set(UInt32 bufferSize)

-			{

-				Buffer = new Byte[bufferSize];

-				Pos = 0;

-				BufferSize = bufferSize;

-			}

-			UInt32 GetRndBit() { return RG.GetRnd(1); }

-			UInt32 GetLogRandBits(int numBits)

-			{

-				UInt32 len = RG.GetRnd(numBits);

-				return RG.GetRnd((int)len);

-			}

-			UInt32 GetOffset()

-			{

-				if (GetRndBit() == 0)

-					return GetLogRandBits(4);

-				return (GetLogRandBits(4) << 10) | RG.GetRnd(10);

-			}

-			UInt32 GetLen1() { return RG.GetRnd(1 + (int)RG.GetRnd(2)); }

-			UInt32 GetLen2() { return RG.GetRnd(2 + (int)RG.GetRnd(2)); }

-			public void Generate()

-			{

-				RG.Init();

-				Rep0 = 1;

-				while (Pos < BufferSize)

-				{

-					if (GetRndBit() == 0 || Pos < 1)

-						Buffer[Pos++] = (Byte)RG.GetRnd(8);

-					else

-					{

-						UInt32 len;

-						if (RG.GetRnd(3) == 0)

-							len = 1 + GetLen1();

-						else

-						{

-							do

-								Rep0 = GetOffset();

-							while (Rep0 >= Pos);

-							Rep0++;

-							len = 2 + GetLen2();

-						}

-						for (UInt32 i = 0; i < len && Pos < BufferSize; i++, Pos++)

-							Buffer[Pos] = Buffer[Pos - Rep0];

-					}

-				}

-			}

-		};

-

-		class CrcOutStream : System.IO.Stream

-		{

-			public CRC CRC = new CRC();

-			public void Init() { CRC.Init(); }

-			public UInt32 GetDigest() { return CRC.GetDigest(); }

-

-			public override bool CanRead { get { return false; } }

-			public override bool CanSeek { get { return false; } }

-			public override bool CanWrite { get { return true; } }

-			public override Int64 Length { get { return 0; } }

-			public override Int64 Position { get { return 0; } set { } }

-			public override void Flush() { }

-			public override long Seek(long offset, SeekOrigin origin) { return 0; }

-			public override void SetLength(long value) { }

-			public override int Read(byte[] buffer, int offset, int count) { return 0; }

-

-			public override void WriteByte(byte b)

-			{

-				CRC.UpdateByte(b);

-			}

-			public override void Write(byte[] buffer, int offset, int count)

-			{

-				CRC.Update(buffer, (uint)offset, (uint)count);

-			}

-		};

-

-		class CProgressInfo : ICodeProgress

-		{

-			public Int64 ApprovedStart;

-			public Int64 InSize;

-			public System.DateTime Time;

-			public void Init() { InSize = 0; }

-			public void SetProgress(Int64 inSize, Int64 outSize)

-			{

-				if (inSize >= ApprovedStart && InSize == 0)

-				{

-					Time = DateTime.UtcNow;

-					InSize = inSize;

-				}

-			}

-		}

-		const int kSubBits = 8;

-

-		static UInt32 GetLogSize(UInt32 size)

-		{

-			for (int i = kSubBits; i < 32; i++)

-				for (UInt32 j = 0; j < (1 << kSubBits); j++)

-					if (size <= (((UInt32)1) << i) + (j << (i - kSubBits)))

-						return (UInt32)(i << kSubBits) + j;

-			return (32 << kSubBits);

-		}

-

-		static UInt64 MyMultDiv64(UInt64 value, UInt64 elapsedTime)

-		{

-			UInt64 freq = TimeSpan.TicksPerSecond;

-			UInt64 elTime = elapsedTime;

-			while (freq > 1000000)

-			{

-				freq >>= 1;

-				elTime >>= 1;

-			}

-			if (elTime == 0)

-				elTime = 1;

-			return value * freq / elTime;

-		}

-

-		static UInt64 GetCompressRating(UInt32 dictionarySize, UInt64 elapsedTime, UInt64 size)

-		{

-			UInt64 t = GetLogSize(dictionarySize) - (18 << kSubBits);

-			UInt64 numCommandsForOne = 1060 + ((t * t * 10) >> (2 * kSubBits));

-			UInt64 numCommands = (UInt64)(size) * numCommandsForOne;

-			return MyMultDiv64(numCommands, elapsedTime);

-		}

-

-		static UInt64 GetDecompressRating(UInt64 elapsedTime, UInt64 outSize, UInt64 inSize)

-		{

-			UInt64 numCommands = inSize * 220 + outSize * 20;

-			return MyMultDiv64(numCommands, elapsedTime);

-		}

-

-		static UInt64 GetTotalRating(

-			UInt32 dictionarySize,

-			UInt64 elapsedTimeEn, UInt64 sizeEn,

-			UInt64 elapsedTimeDe,

-			UInt64 inSizeDe, UInt64 outSizeDe)

-		{

-			return (GetCompressRating(dictionarySize, elapsedTimeEn, sizeEn) +

-				GetDecompressRating(elapsedTimeDe, inSizeDe, outSizeDe)) / 2;

-		}

-

-		static void PrintValue(UInt64 v)

-		{

-			string s = v.ToString();

-			for (int i = 0; i + s.Length < 6; i++)

-				System.Console.Write(" ");

-			System.Console.Write(s);

-		}

-

-		static void PrintRating(UInt64 rating)

-		{

-			PrintValue(rating / 1000000);

-			System.Console.Write(" MIPS");

-		}

-

-		static void PrintResults(

-			UInt32 dictionarySize,

-			UInt64 elapsedTime,

-			UInt64 size,

-			bool decompressMode, UInt64 secondSize)

-		{

-			UInt64 speed = MyMultDiv64(size, elapsedTime);

-			PrintValue(speed / 1024);

-			System.Console.Write(" KB/s  ");

-			UInt64 rating;

-			if (decompressMode)

-				rating = GetDecompressRating(elapsedTime, size, secondSize);

-			else

-				rating = GetCompressRating(dictionarySize, elapsedTime, size);

-			PrintRating(rating);

-		}

-

-		static public int LzmaBenchmark(Int32 numIterations, UInt32 dictionarySize)

-		{

-			if (numIterations <= 0)

-				return 0;

-			if (dictionarySize < (1 << 18))

-			{

-				System.Console.WriteLine("\nError: dictionary size for benchmark must be >= 19 (512 KB)");

-				return 1;

-			}

-			System.Console.Write("\n       Compressing                Decompressing\n\n");

-

-			Compression.LZMA.Encoder encoder = new Compression.LZMA.Encoder();

-			Compression.LZMA.Decoder decoder = new Compression.LZMA.Decoder();

-

-

-			CoderPropID[] propIDs = 

-			{ 

-				CoderPropID.DictionarySize,

-			};

-			object[] properties = 

-			{

-				(Int32)(dictionarySize),

-			};

-

-			UInt32 kBufferSize = dictionarySize + kAdditionalSize;

-			UInt32 kCompressedBufferSize = (kBufferSize / 2) + kCompressedAdditionalSize;

-

-			encoder.SetCoderProperties(propIDs, properties);

-			System.IO.MemoryStream propStream = new System.IO.MemoryStream();

-			encoder.WriteCoderProperties(propStream);

-			byte[] propArray = propStream.ToArray();

-

-			CBenchRandomGenerator rg = new CBenchRandomGenerator();

-

-			rg.Set(kBufferSize);

-			rg.Generate();

-			CRC crc = new CRC();

-			crc.Init();

-			crc.Update(rg.Buffer, 0, rg.BufferSize);

-

-			CProgressInfo progressInfo = new CProgressInfo();

-			progressInfo.ApprovedStart = dictionarySize;

-

-			UInt64 totalBenchSize = 0;

-			UInt64 totalEncodeTime = 0;

-			UInt64 totalDecodeTime = 0;

-			UInt64 totalCompressedSize = 0;

-

-			MemoryStream inStream = new MemoryStream(rg.Buffer, 0, (int)rg.BufferSize);

-			MemoryStream compressedStream = new MemoryStream((int)kCompressedBufferSize);

-			CrcOutStream crcOutStream = new CrcOutStream();

-			for (Int32 i = 0; i < numIterations; i++)

-			{

-				progressInfo.Init();

-				inStream.Seek(0, SeekOrigin.Begin);

-				compressedStream.Seek(0, SeekOrigin.Begin);

-				encoder.Code(inStream, compressedStream, -1, -1, progressInfo);

-				TimeSpan sp2 = DateTime.UtcNow - progressInfo.Time;

-				UInt64 encodeTime = (UInt64)sp2.Ticks;

-

-				long compressedSize = compressedStream.Position;

-				if (progressInfo.InSize == 0)

-					throw (new Exception("Internal ERROR 1282"));

-

-				UInt64 decodeTime = 0;

-				for (int j = 0; j < 2; j++)

-				{

-					compressedStream.Seek(0, SeekOrigin.Begin);

-					crcOutStream.Init();

-

-					decoder.SetDecoderProperties(propArray);

-					UInt64 outSize = kBufferSize;

-					System.DateTime startTime = DateTime.UtcNow;

-					decoder.Code(compressedStream, crcOutStream, 0, (Int64)outSize, null);

-					TimeSpan sp = (DateTime.UtcNow - startTime);

-					decodeTime = (ulong)sp.Ticks;

-					if (crcOutStream.GetDigest() != crc.GetDigest())

-						throw (new Exception("CRC Error"));

-				}

-				UInt64 benchSize = kBufferSize - (UInt64)progressInfo.InSize;

-				PrintResults(dictionarySize, encodeTime, benchSize, false, 0);

-				System.Console.Write("     ");

-				PrintResults(dictionarySize, decodeTime, kBufferSize, true, (ulong)compressedSize);

-				System.Console.WriteLine();

-

-				totalBenchSize += benchSize;

-				totalEncodeTime += encodeTime;

-				totalDecodeTime += decodeTime;

-				totalCompressedSize += (ulong)compressedSize;

-			}

-			System.Console.WriteLine("---------------------------------------------------");

-			PrintResults(dictionarySize, totalEncodeTime, totalBenchSize, false, 0);

-			System.Console.Write("     ");

-			PrintResults(dictionarySize, totalDecodeTime,

-					kBufferSize * (UInt64)numIterations, true, totalCompressedSize);

-			System.Console.WriteLine("    Average");

-			return 0;

-		}

-	}

-}

diff --git a/CS/7zip/Compress/LzmaAlone/Properties/AssemblyInfo.cs b/CS/7zip/Compress/LzmaAlone/Properties/AssemblyInfo.cs
deleted file mode 100644
index a394aee..0000000
--- a/CS/7zip/Compress/LzmaAlone/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-#region Using directives

-

-using System.Reflection;

-using System.Runtime.CompilerServices;

-

-#endregion

-

-// General Information about an assembly is controlled through the following 

-// set of attributes. Change these attribute values to modify the information

-// associated with an assembly.

-[assembly: AssemblyTitle("LZMA#")]

-[assembly: AssemblyDescription("")]

-[assembly: AssemblyConfiguration("")]

-[assembly: AssemblyCompany("Igor Pavlov")]

-[assembly: AssemblyProduct("LZMA# SDK")]

-[assembly: AssemblyCopyright("Copyright @ Igor Pavlov 1999-2004")]

-[assembly: AssemblyTrademark("")]

-[assembly: AssemblyCulture("")]

-

-// Version information for an assembly consists of the following four values:

-//

-//      Major Version

-//      Minor Version 

-//      Build Number

-//      Revision

-//

-// You can specify all the values or you can default the Revision and Build Numbers 

-// by using the '*' as shown below:

-[assembly: AssemblyVersion("4.12.*")]

diff --git a/CS/7zip/Compress/LzmaAlone/Properties/Resources.cs b/CS/7zip/Compress/LzmaAlone/Properties/Resources.cs
deleted file mode 100644
index efe4ee9..0000000
--- a/CS/7zip/Compress/LzmaAlone/Properties/Resources.cs
+++ /dev/null
@@ -1,70 +0,0 @@
-//------------------------------------------------------------------------------

-// <autogenerated>

-//     This code was generated by a tool.

-//     Runtime Version:2.0.40607.42

-//

-//     Changes to this file may cause incorrect behavior and will be lost if

-//     the code is regenerated.

-// </autogenerated>

-//------------------------------------------------------------------------------

-

-namespace LzmaAlone.Properties

-{

-	using System;

-	using System.IO;

-	using System.Resources;

-

-	/// <summary>

-	///    A strongly-typed resource class, for looking up localized strings, etc.

-	/// </summary>

-	// This class was auto-generated by the Strongly Typed Resource Builder

-	// class via a tool like ResGen or Visual Studio.NET.

-	// To add or remove a member, edit your .ResX file then rerun ResGen

-	// with the /str option, or rebuild your VS project.

-	class Resources

-	{

-

-		private static System.Resources.ResourceManager _resMgr;

-

-		private static System.Globalization.CultureInfo _resCulture;

-

-		/*FamANDAssem*/

-		internal Resources()

-		{

-		}

-

-		/// <summary>

-		///    Returns the cached ResourceManager instance used by this class.

-		/// </summary>

-		[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]

-		public static System.Resources.ResourceManager ResourceManager

-		{

-			get

-			{

-				if ((_resMgr == null))

-				{

-					System.Resources.ResourceManager temp = new System.Resources.ResourceManager("Resources", typeof(Resources).Assembly);

-					_resMgr = temp;

-				}

-				return _resMgr;

-			}

-		}

-

-		/// <summary>

-		///    Overrides the current thread's CurrentUICulture property for all

-		///    resource lookups using this strongly typed resource class.

-		/// </summary>

-		[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]

-		public static System.Globalization.CultureInfo Culture

-		{

-			get

-			{

-				return _resCulture;

-			}

-			set

-			{

-				_resCulture = value;

-			}

-		}

-	}

-}

diff --git a/CS/7zip/Compress/LzmaAlone/Properties/Settings.cs b/CS/7zip/Compress/LzmaAlone/Properties/Settings.cs
deleted file mode 100644
index 1281fd2..0000000
--- a/CS/7zip/Compress/LzmaAlone/Properties/Settings.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-//------------------------------------------------------------------------------

-// <autogenerated>

-//     This code was generated by a tool.

-//     Runtime Version:2.0.40607.42

-//

-//     Changes to this file may cause incorrect behavior and will be lost if

-//     the code is regenerated.

-// </autogenerated>

-//------------------------------------------------------------------------------

-

-namespace LzmaAlone.Properties

-{

-	public partial class Settings : System.Configuration.ApplicationSettingsBase

-	{

-		private static Settings m_Value;

-

-		private static object m_SyncObject = new object();

-

-		public static Settings Value

-		{

-			get

-			{

-				if ((Settings.m_Value == null))

-				{

-					System.Threading.Monitor.Enter(Settings.m_SyncObject);

-					if ((Settings.m_Value == null))

-					{

-						try

-						{

-							Settings.m_Value = new Settings();

-						}

-						finally

-						{

-							System.Threading.Monitor.Exit(Settings.m_SyncObject);

-						}

-					}

-				}

-				return Settings.m_Value;

-			}

-		}

-	}

-}

diff --git a/CS/7zip/Compress/RangeCoder/RangeCoder.cs b/CS/7zip/Compress/RangeCoder/RangeCoder.cs
deleted file mode 100644
index 4ced247..0000000
--- a/CS/7zip/Compress/RangeCoder/RangeCoder.cs
+++ /dev/null
@@ -1,234 +0,0 @@
-using System;

-

-namespace SevenZip.Compression.RangeCoder

-{

-	class Encoder

-	{

-		public const uint kTopValue = (1 << 24);

-

-		System.IO.Stream Stream;

-

-		public UInt64 Low;

-		public uint Range;

-		uint _cacheSize;

-		byte _cache;

-

-		long StartPosition;

-

-		public void SetStream(System.IO.Stream stream)

-		{

-			Stream = stream;

-		}

-

-		public void ReleaseStream()

-		{

-			Stream = null;

-		}

-

-		public void Init()

-		{

-			StartPosition = Stream.Position;

-

-			Low = 0;

-			Range = 0xFFFFFFFF;

-			_cacheSize = 1;

-			_cache = 0;

-		}

-

-		public void FlushData()

-		{

-			for (int i = 0; i < 5; i++)

-				ShiftLow();

-		}

-

-		public void FlushStream()

-		{

-			Stream.Flush();

-		}

-

-		public void CloseStream()

-		{

-			Stream.Close();

-		}

-

-		public void Encode(uint start, uint size, uint total)

-		{

-			Low += start * (Range /= total);

-			Range *= size;

-			while (Range < kTopValue)

-			{

-				Range <<= 8;

-				ShiftLow();

-			}

-		}

-

-		public void ShiftLow()

-		{

-			if ((uint)Low < (uint)0xFF000000 || (uint)(Low >> 32) == 1)

-			{

-				byte temp = _cache;

-				do

-				{

-					Stream.WriteByte((byte)(temp + (Low >> 32)));

-					temp = 0xFF;

-				}

-				while (--_cacheSize != 0);

-				_cache = (byte)(((uint)Low) >> 24);

-			}

-			_cacheSize++;

-			Low = ((uint)Low) << 8;

-		}

-

-		public void EncodeDirectBits(uint v, int numTotalBits)

-		{

-			for (int i = numTotalBits - 1; i >= 0; i--)

-			{

-				Range >>= 1;

-				if (((v >> i) & 1) == 1)

-					Low += Range;

-				if (Range < kTopValue)

-				{

-					Range <<= 8;

-					ShiftLow();

-				}

-			}

-		}

-

-		public void EncodeBit(uint size0, int numTotalBits, uint symbol)

-		{

-			uint newBound = (Range >> numTotalBits) * size0;

-			if (symbol == 0)

-				Range = newBound;

-			else

-			{

-				Low += newBound;

-				Range -= newBound;

-			}

-			while (Range < kTopValue)

-			{

-				Range <<= 8;

-				ShiftLow();

-			}

-		}

-

-		public long GetProcessedSizeAdd()

-		{

-			return _cacheSize +

-				Stream.Position - StartPosition + 4;

-			// (long)Stream.GetProcessedSize();

-		}

-	}

-

-	class Decoder

-	{

-		public const uint kTopValue = (1 << 24);

-		public uint Range;

-		public uint Code;

-		// public Buffer.InBuffer Stream = new Buffer.InBuffer(1 << 16);

-		public System.IO.Stream Stream;

-

-		public void Init(System.IO.Stream stream)

-		{

-			// Stream.Init(stream);

-			Stream = stream;

-

-			Code = 0;

-			Range = 0xFFFFFFFF;

-			for (int i = 0; i < 5; i++)

-				Code = (Code << 8) | (byte)Stream.ReadByte();

-		}

-

-		public void ReleaseStream()

-		{

-			// Stream.ReleaseStream();

-			Stream = null;

-		}

-

-		public void CloseStream()

-		{

-			Stream.Close();

-		}

-

-		public void Normalize()

-		{

-			while (Range < kTopValue)

-			{

-				Code = (Code << 8) | (byte)Stream.ReadByte();

-				Range <<= 8;

-			}

-		}

-

-		public void Normalize2()

-		{

-			if (Range < kTopValue)

-			{

-				Code = (Code << 8) | (byte)Stream.ReadByte();

-				Range <<= 8;

-			}

-		}

-

-		public uint GetThreshold(uint total)

-		{

-			return Code / (Range /= total);

-		}

-

-		public void Decode(uint start, uint size, uint total)

-		{

-			Code -= start * Range;

-			Range *= size;

-			Normalize();

-		}

-

-		public uint DecodeDirectBits(int numTotalBits)

-		{

-			uint range = Range;

-			uint code = Code;

-			uint result = 0;

-			for (int i = numTotalBits; i > 0; i--)

-			{

-				range >>= 1;

-				/*

-				result <<= 1;

-				if (code >= range)

-				{

-					code -= range;

-					result |= 1;

-				}

-				*/

-				uint t = (code - range) >> 31;

-				code -= range & (t - 1);

-				result = (result << 1) | (1 - t);

-

-				if (range < kTopValue)

-				{

-					code = (code << 8) | (byte)Stream.ReadByte();

-					range <<= 8;

-				}

-			}

-			Range = range;

-			Code = code;

-			return result;

-		}

-

-		public uint DecodeBit(uint size0, int numTotalBits)

-		{

-			uint newBound = (Range >> numTotalBits) * size0;

-			uint symbol;

-			if (Code < newBound)

-			{

-				symbol = 0;

-				Range = newBound;

-			}

-			else

-			{

-				symbol = 1;

-				Code -= newBound;

-				Range -= newBound;

-			}

-			Normalize();

-			return symbol;

-		}

-

-		// ulong GetProcessedSize() {return Stream.GetProcessedSize(); }

-	}

-}

diff --git a/CS/7zip/Compress/RangeCoder/RangeCoderBit.cs b/CS/7zip/Compress/RangeCoder/RangeCoderBit.cs
deleted file mode 100644
index 000a5a0..0000000
--- a/CS/7zip/Compress/RangeCoder/RangeCoderBit.cs
+++ /dev/null
@@ -1,117 +0,0 @@
-using System;

-

-namespace SevenZip.Compression.RangeCoder

-{

-	struct BitEncoder

-	{

-		public const int kNumBitModelTotalBits = 11;

-		public const uint kBitModelTotal = (1 << kNumBitModelTotalBits);

-		const int kNumMoveBits = 5;

-		const int kNumMoveReducingBits = 2;

-		public const int kNumBitPriceShiftBits = 6;

-

-		uint Prob;

-

-		public void Init() { Prob = kBitModelTotal >> 1; }

-

-		public void UpdateModel(uint symbol)

-		{

-			if (symbol == 0)

-				Prob += (kBitModelTotal - Prob) >> kNumMoveBits;

-			else

-				Prob -= (Prob) >> kNumMoveBits;

-		}

-

-		public void Encode(Encoder encoder, uint symbol)

-		{

-			// encoder.EncodeBit(Prob, kNumBitModelTotalBits, symbol);

-			// UpdateModel(symbol);

-			uint newBound = (encoder.Range >> kNumBitModelTotalBits) * Prob;

-			if (symbol == 0)

-			{

-				encoder.Range = newBound;

-				Prob += (kBitModelTotal - Prob) >> kNumMoveBits;

-			}

-			else

-			{

-				encoder.Low += newBound;

-				encoder.Range -= newBound;

-				Prob -= (Prob) >> kNumMoveBits;

-			}

-			if (encoder.Range < Encoder.kTopValue)

-			{

-				encoder.Range <<= 8;

-				encoder.ShiftLow();

-			}

-		}

-

-		private static UInt32[] ProbPrices = new UInt32[kBitModelTotal >> kNumMoveReducingBits];

-

-		static BitEncoder()

-		{

-			const int kNumBits = (kNumBitModelTotalBits - kNumMoveReducingBits);

-			for (int i = kNumBits - 1; i >= 0; i--)

-			{

-				UInt32 start = (UInt32)1 << (kNumBits - i - 1);

-				UInt32 end = (UInt32)1 << (kNumBits - i);

-				for (UInt32 j = start; j < end; j++)

-					ProbPrices[j] = ((UInt32)i << kNumBitPriceShiftBits) +

-						(((end - j) << kNumBitPriceShiftBits) >> (kNumBits - i - 1));

-			}

-		}

-

-		public uint GetPrice(uint symbol)

-		{

-			return ProbPrices[(((Prob - symbol) ^ ((-(int)symbol))) & (kBitModelTotal - 1)) >> kNumMoveReducingBits];

-		}

-	  public uint GetPrice0() { return ProbPrices[Prob >> kNumMoveReducingBits]; }

-		public uint GetPrice1() { return ProbPrices[(kBitModelTotal - Prob) >> kNumMoveReducingBits]; }

-	}

-

-	struct BitDecoder

-	{

-		public const int kNumBitModelTotalBits = 11;

-		public const uint kBitModelTotal = (1 << kNumBitModelTotalBits);

-		const int kNumMoveBits = 5;

-

-		uint Prob;

-

-		public void UpdateModel(int numMoveBits, uint symbol)

-		{

-			if (symbol == 0)

-				Prob += (kBitModelTotal - Prob) >> numMoveBits;

-			else

-				Prob -= (Prob) >> numMoveBits;

-		}

-

-		public void Init() { Prob = kBitModelTotal >> 1; }

-

-		public uint Decode(RangeCoder.Decoder rangeDecoder)

-		{

-			uint newBound = (uint)(rangeDecoder.Range >> kNumBitModelTotalBits) * (uint)Prob;

-			if (rangeDecoder.Code < newBound)

-			{

-				rangeDecoder.Range = newBound;

-				Prob += (kBitModelTotal - Prob) >> kNumMoveBits;

-				if (rangeDecoder.Range < Decoder.kTopValue)

-				{

-					rangeDecoder.Code = (rangeDecoder.Code << 8) | (byte)rangeDecoder.Stream.ReadByte();

-					rangeDecoder.Range <<= 8;

-				}

-				return 0;

-			}

-			else

-			{

-				rangeDecoder.Range -= newBound;

-				rangeDecoder.Code -= newBound;

-				Prob -= (Prob) >> kNumMoveBits;

-				if (rangeDecoder.Range < Decoder.kTopValue)

-				{

-					rangeDecoder.Code = (rangeDecoder.Code << 8) | (byte)rangeDecoder.Stream.ReadByte();

-					rangeDecoder.Range <<= 8;

-				}

-				return 1;

-			}

-		}

-	}

-}

diff --git a/CS/7zip/Compress/RangeCoder/RangeCoderBitTree.cs b/CS/7zip/Compress/RangeCoder/RangeCoderBitTree.cs
deleted file mode 100644
index 3309c14..0000000
--- a/CS/7zip/Compress/RangeCoder/RangeCoderBitTree.cs
+++ /dev/null
@@ -1,157 +0,0 @@
-using System;

-

-namespace SevenZip.Compression.RangeCoder

-{

-	struct BitTreeEncoder

-	{

-		BitEncoder[] Models;

-		int NumBitLevels;

-

-		public BitTreeEncoder(int numBitLevels)

-		{

-			NumBitLevels = numBitLevels;

-			Models = new BitEncoder[1 << numBitLevels];

-		}

-

-		public void Init()

-		{

-			for (uint i = 1; i < (1 << NumBitLevels); i++)

-				Models[i].Init();

-		}

-

-		public void Encode(Encoder rangeEncoder, UInt32 symbol)

-		{

-			UInt32 m = 1;

-			for (int bitIndex = NumBitLevels; bitIndex > 0; )

-			{

-				bitIndex--;

-				UInt32 bit = (symbol >> bitIndex) & 1;

-				Models[m].Encode(rangeEncoder, bit);

-				m = (m << 1) | bit;

-			}

-		}

-

-		public void ReverseEncode(Encoder rangeEncoder, UInt32 symbol)

-		{

-			UInt32 m = 1;

-			for (UInt32 i = 0; i < NumBitLevels; i++)

-			{

-				UInt32 bit = symbol & 1;

-				Models[m].Encode(rangeEncoder, bit);

-				m = (m << 1) | bit;

-				symbol >>= 1;

-			}

-		}

-

-		public UInt32 GetPrice(UInt32 symbol)

-		{

-			UInt32 price = 0;

-			UInt32 m = 1;

-			for (int bitIndex = NumBitLevels; bitIndex > 0; )

-			{

-				bitIndex--;

-				UInt32 bit = (symbol >> bitIndex) & 1;

-				price += Models[m].GetPrice(bit);

-				m = (m << 1) + bit;

-			}

-			return price;

-		}

-

-		public UInt32 ReverseGetPrice(UInt32 symbol)

-		{

-			UInt32 price = 0;

-			UInt32 m = 1;

-			for (int i = NumBitLevels; i > 0; i--)

-			{

-				UInt32 bit = symbol & 1;

-				symbol >>= 1;

-				price += Models[m].GetPrice(bit);

-				m = (m << 1) | bit;

-			}

-			return price;

-		}

-

-		public static UInt32 ReverseGetPrice(BitEncoder[] Models, UInt32 startIndex,

-			int NumBitLevels, UInt32 symbol)

-		{

-			UInt32 price = 0;

-			UInt32 m = 1;

-			for (int i = NumBitLevels; i > 0; i--)

-			{

-				UInt32 bit = symbol & 1;

-				symbol >>= 1;

-				price += Models[startIndex + m].GetPrice(bit);

-				m = (m << 1) | bit;

-			}

-			return price;

-		}

-

-		public static void ReverseEncode(BitEncoder[] Models, UInt32 startIndex,

-			Encoder rangeEncoder, int NumBitLevels, UInt32 symbol)

-		{

-			UInt32 m = 1;

-			for (int i = 0; i < NumBitLevels; i++)

-			{

-				UInt32 bit = symbol & 1;

-				Models[startIndex + m].Encode(rangeEncoder, bit);

-				m = (m << 1) | bit;

-				symbol >>= 1;

-			}

-		}

-	}

-

-	struct BitTreeDecoder

-	{

-		BitDecoder[] Models;

-		int NumBitLevels;

-

-		public BitTreeDecoder(int numBitLevels)

-		{

-			NumBitLevels = numBitLevels;

-			Models = new BitDecoder[1 << numBitLevels];

-		}

-

-		public void Init()

-		{

-			for (uint i = 1; i < (1 << NumBitLevels); i++)

-				Models[i].Init();

-		}

-

-		public uint Decode(RangeCoder.Decoder rangeDecoder)

-		{

-			uint m = 1;

-			for (int bitIndex = NumBitLevels; bitIndex > 0; bitIndex--)

-				m = (m << 1) + Models[m].Decode(rangeDecoder);

-			return m - ((uint)1 << NumBitLevels);

-		}

-

-		public uint ReverseDecode(RangeCoder.Decoder rangeDecoder)

-		{

-			uint m = 1;

-			uint symbol = 0;

-			for (int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++)

-			{

-				uint bit = Models[m].Decode(rangeDecoder);

-				m <<= 1;

-				m += bit;

-				symbol |= (bit << bitIndex);

-			}

-			return symbol;

-		}

-

-		public static uint ReverseDecode(BitDecoder[] Models, UInt32 startIndex,

-			RangeCoder.Decoder rangeDecoder, int NumBitLevels)

-		{

-			uint m = 1;

-			uint symbol = 0;

-			for (int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++)

-			{

-				uint bit = Models[startIndex + m].Decode(rangeDecoder);

-				m <<= 1;

-				m += bit;

-				symbol |= (bit << bitIndex);

-			}

-			return symbol;

-		}

-	}

-}

diff --git a/CS/7zip/ICoder.cs b/CS/7zip/ICoder.cs
deleted file mode 100644
index 875cb27..0000000
--- a/CS/7zip/ICoder.cs
+++ /dev/null
@@ -1,157 +0,0 @@
-// ICoder.h

-

-using System;

-

-namespace SevenZip

-{

-	/// <summary>

-	/// The exception that is thrown when an error in input stream occurs during decoding.

-	/// </summary>

-	class DataErrorException : ApplicationException

-	{

-		public DataErrorException(): base("Data Error") { }

-	}

-

-	/// <summary>

-	/// The exception that is thrown when the value of an argument is outside the allowable range.

-	/// </summary>

-	class InvalidParamException : ApplicationException

-	{

-		public InvalidParamException(): base("Invalid Parameter") { }

-	}

-

-	public interface ICodeProgress

-	{

-		/// <summary>

-		/// Callback progress.

-		/// </summary>

-		/// <param name="inSize">

-		/// input size. -1 if unknown.

-		/// </param>

-		/// <param name="outSize">

-		/// output size. -1 if unknown.

-		/// </param>

-		void SetProgress(Int64 inSize, Int64 outSize);

-	};

-

-	public interface ICoder

-	{

-		/// <summary>

-		/// Codes streams.

-		/// </summary>

-		/// <param name="inStream">

-		/// input Stream.

-		/// </param>

-		/// <param name="outStream">

-		/// output Stream.

-		/// </param>

-		/// <param name="inSize">

-		/// input Size. -1 if unknown.

-		/// </param>

-		/// <param name="outSize">

-		/// output Size. -1 if unknown.

-		/// </param>

-		/// <param name="progress">

-		/// callback progress reference.

-		/// </param>

-		/// <exception cref="SevenZip.DataErrorException">

-		/// if input stream is not valid

-		/// </exception>

-		void Code(System.IO.Stream inStream, System.IO.Stream outStream,

-			Int64 inSize, Int64 outSize, ICodeProgress progress);

-	};

-

-	/*

-	public interface ICoder2

-	{

-		 void Code(ISequentialInStream []inStreams,

-				const UInt64 []inSizes, 

-				ISequentialOutStream []outStreams, 

-				UInt64 []outSizes,

-				ICodeProgress progress);

-	};

-  */

-

-	/// <summary>

-	/// Provides the fields that represent properties idenitifiers for compressing.

-	/// </summary>

-	public enum CoderPropID

-	{

-		/// <summary>

-		/// Specifies default property.

-		/// </summary>

-		DefaultProp = 0,

-		/// <summary>

-		/// Specifies size of dictionary.

-		/// </summary>

-		DictionarySize,

-		/// <summary>

-		/// Specifies size of memory for PPM*.

-		/// </summary>

-		UsedMemorySize,

-		/// <summary>

-		/// Specifies order for PPM methods.

-		/// </summary>

-		Order,

-		/// <summary>

-		/// Specifies Block Size.

-		/// </summary>

-		BlockSize,

-		/// <summary>

-		/// Specifies number of postion state bits for LZMA (0 <= x <= 4).

-		/// </summary>

-		PosStateBits,

-		/// <summary>

-		/// Specifies number of literal context bits for LZMA (0 <= x <= 8).

-		/// </summary>

-		LitContextBits,

-		/// <summary>

-		/// Specifies number of literal position bits for LZMA (0 <= x <= 4).

-		/// </summary>

-		LitPosBits,

-		/// <summary>

-		/// Specifies number of fast bytes for LZ*.

-		/// </summary>

-		NumFastBytes,

-		/// <summary>

-		/// Specifies match finder. LZMA: "BT2", "BT4" or "BT4B".

-		/// </summary>

-		MatchFinder,

-		/// <summary>

-		/// Specifies the number of match finder cyckes.

-		/// </summary>

-		MatchFinderCycles,

-		/// <summary>

-		/// Specifies number of passes.

-		/// </summary>

-		NumPasses,

-		/// <summary>

-		/// Specifies number of algorithm.

-		/// </summary>

-		Algorithm,

-		/// <summary>

-		/// Specifies the number of threads.

-		/// </summary>

-		NumThreads,

-		/// <summary>

-		/// Specifies mode with end marker.

-		/// </summary>

-		EndMarker

-	};

-

-

-	public interface ISetCoderProperties

-	{

-		void SetCoderProperties(CoderPropID[] propIDs, object[] properties);

-	};

-

-	public interface IWriteCoderProperties

-	{

-		void WriteCoderProperties(System.IO.Stream outStream);

-	}

-

-	public interface ISetDecoderProperties

-	{

-		void SetDecoderProperties(byte[] properties);

-	}

-}

diff --git a/DOC/7zC.txt b/DOC/7zC.txt
index 4927678..939b720 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 <command> <archive_name>

-

-<Command>:

-  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 <command> <archive_name>
+
+<Command>:
+  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 9239e93..74cdfa4 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
new file mode 100644
index 0000000..6c6bd70
--- /dev/null
+++ b/DOC/7zip.hhp
@@ -0,0 +1,83 @@
+[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\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
new file mode 100644
index 0000000..df1d320
--- /dev/null
+++ b/DOC/7zip.wxs
@@ -0,0 +1,403 @@
+<?xml version="1.0"?>
+
+<?define VerMajor = "23" ?>
+<?define VerMinor = "01" ?>
+<?define VerBuild = "00" ?>
+<?define MmVer = "$(var.VerMajor).$(var.VerMinor)" ?>
+<?define MmHex = "$(var.VerMajor)$(var.VerMinor)" ?>
+<?define MmmmVer = "$(var.MmVer).$(var.VerBuild).0" ?>
+<?define UpgradeMinVer = "4.38" ?>
+
+<?define ProductName = "7-Zip" ?>
+
+<?ifndef MyCPU?>
+  <?define MyCPU = "Intel" ?>
+<?endif?>
+
+<?if $(var.MyCPU) = "x64" ?>
+  <?define CpuId = "2" ?>
+  <?define PFilesFolder = "ProgramFiles64Folder" ?>
+  <?define Platforms = "x64" ?>
+  <?define CpuPostfix = " (x64 edition)" ?>
+  <?define Is64 = "yes" ?>
+  <?define NumBits = "64" ?>
+<?elseif $(var.MyCPU) = "ia64" ?>
+  <?define CpuId = "3" ?>
+  <?define PFilesFolder = "ProgramFiles64Folder" ?>
+  <?define Platforms = "Intel64" ?>
+  <?define CpuPostfix = " (ia64 edition)" ?>
+  <?define Is64 = "yes" ?>
+  <?define NumBits = "64" ?>
+<?else ?>
+  <?define CpuId = "1" ?>
+  <?define PFilesFolder = "ProgramFilesFolder" ?>
+  <?define Platforms = "Intel" ?>
+  <?define CpuPostfix = "" ?>
+  <?define Is64 = "no" ?>
+  <?define NumBits = "32" ?>
+<?endif ?>
+
+
+<?define ShellExtId = "{23170F69-40C1-278A-1000-000100020000}" ?>
+
+<?define BaseId = "23170F69-40C1-270$(var.CpuId)" ?>
+<?define BaseIdVer = "$(var.BaseId)-$(var.MmHex)-$(var.VerBuild)00" ?>
+<?define ProductId   = "$(var.BaseIdVer)01000000" ?>
+<?define PackageId   = "$(var.BaseIdVer)02000000" ?>
+<?define CompId      = "$(var.BaseIdVer)030000" ?>
+<?define UpgradeCode = "$(var.BaseId)-0000-000004000000" ?>
+
+<?define CompFm       = "$(var.CompId)01" ?>
+<?define CompShellExt = "$(var.CompId)02" ?>
+<?define CompCmdLine  = "$(var.CompId)03" ?>
+<?define CompCmdLineA = "$(var.CompId)04" ?>
+<?define CompGui      = "$(var.CompId)05" ?>
+<?define CompGuiSfx   = "$(var.CompId)06" ?>
+<?define CompConSfx   = "$(var.CompId)07" ?>
+<?define CompHelp     = "$(var.CompId)08" ?>
+<?define CompDocs     = "$(var.CompId)09" ?>
+<?define CompFormats  = "$(var.CompId)10" ?>
+<?define CompCodecs   = "$(var.CompId)11" ?>
+<?define CompLang     = "$(var.CompId)12" ?>
+<?define CompShellExt2 = "$(var.CompId)13" ?>
+<?define CompInstallRegCU         = "$(var.CompId)80" ?>
+<?define CompInstallRegLM         = "$(var.CompId)81" ?>
+<?define CompInstallRegWild       = "$(var.CompId)82" ?>
+<?define CompInstallRegDirectory  = "$(var.CompId)83" ?>
+<?define CompInstallRegDirDD      = "$(var.CompId)84" ?>
+<?define CompInstallRegDriveDD    = "$(var.CompId)85" ?>
+<?define CompInstallRegApproved   = "$(var.CompId)86" ?>
+<?define CompInstallRegAppPath    = "$(var.CompId)87" ?>
+<?define CompInstallRegFolder     = "$(var.CompId)88" ?>
+
+
+<?define Manufacturer = "Igor Pavlov" ?>
+<?define HomePage = "http://www.7-zip.org/" ?>
+<?define AboutURL = "$(var.HomePage)" ?>
+<?define UpdatesURL = "$(var.HomePage)download.html" ?>
+<?define SupportURL = "$(var.HomePage)support.html" ?>
+
+<Wix xmlns="http://schemas.microsoft.com/wix/2003/01/wi">
+  <Product
+      Id="$(var.ProductId)"
+      UpgradeCode="$(var.UpgradeCode)"
+      Name="$(var.ProductName) $(var.MmVer)$(var.CpuPostfix)"
+      Language="1033"
+      Version="$(var.MmmmVer)"
+      Manufacturer="$(var.Manufacturer)">
+   
+    <Package
+        Id="$(var.PackageId)"
+        Description="$(var.ProductName)$(var.CpuPostfix) Package"
+        Comments="$(var.ProductName)$(var.CpuPostfix) Package"
+        Manufacturer="$(var.Manufacturer)"
+        InstallerVersion="200"
+        Compressed="yes"
+        Platforms="$(var.Platforms)"
+        />
+
+    <!-- Major upgrade -->
+    <Upgrade Id="$(var.UpgradeCode)">
+      <UpgradeVersion Minimum="$(var.UpgradeMinVer)" IncludeMinimum="yes"
+           Maximum="$(var.MmmmVer)" IncludeMaximum="no" Property="OLDERVERSIONBEINGUPGRADED" />
+    </Upgrade>
+
+    <Media Id="1" Cabinet="product.cab" EmbedCab="yes" CompressionLevel="high" />
+
+    <Property Id="MSIRMSHUTDOWN" Value="2"/>
+
+    <Property Id="INSTALLDIR">
+      <RegistrySearch Id="My7zipPathLM"  Type="raw" Root="HKLM" Key="Software\7-Zip" Name="Path" />
+      <RegistrySearch Id="My7zipPathLM2" Type="raw" Root="HKLM" Key="Software\7-Zip" Name="Path$(var.NumBits)" />
+      <RegistrySearch Id="My7zipPath"    Type="raw" Root="HKCU" Key="Software\7-Zip" Name="Path" />
+      <RegistrySearch Id="My7zipPath2"   Type="raw" Root="HKCU" Key="Software\7-Zip" Name="Path$(var.NumBits)" />
+    </Property>
+
+    <Property Id="ALLUSERS">2</Property>
+
+    <Property Id="LicenseAccepted">1</Property>
+
+    <Property Id="ARPURLINFOABOUT" Value="$(var.AboutURL)" />
+    <Property Id="ARPHELPLINK" Value="$(var.SupportURL)" />
+    <Property Id="ARPURLUPDATEINFO" Value="$(var.UpdatesURL)" />
+
+
+    <Directory Id="TARGETDIR" Name="SourceDir">
+      <Directory Id="$(var.PFilesFolder)" Name="Files">
+        <Directory Id="INSTALLDIR" Name="7-Zip">
+
+          <Component Id="InstallRegCU" Guid="$(var.CompInstallRegCU)" DiskId="1" Win64="$(var.Is64)">
+            <Registry Id="MyInstallRegCU"  Root="HKCU" Key="Software\7-Zip" Name="Path" Action="write" Type="string" Value="[INSTALLDIR]" />
+            <Registry Id="MyInstallRegCU2" Root="HKCU" Key="Software\7-Zip" Name="Path$(var.NumBits)" Action="write" Type="string" Value="[INSTALLDIR]" />
+          </Component>
+          <Component Id="InstallRegLM" Guid="$(var.CompInstallRegLM)" DiskId="1" Win64="$(var.Is64)">
+            <Condition>Privileged</Condition>
+            <Registry Id="MyInstallRegLM"  Root="HKLM" Key="Software\7-Zip" Name="Path" Action="write" Type="string" Value="[INSTALLDIR]" />
+            <Registry Id="MyInstallRegLM2" Root="HKLM" Key="Software\7-Zip" Name="Path$(var.NumBits)" Action="write" Type="string" Value="[INSTALLDIR]" />
+          </Component>
+          
+
+          <Component Id="InstallRegWild" Guid="$(var.CompInstallRegWild)" DiskId="1" Win64="$(var.Is64)">
+            <Registry Id="MyInstallRegWild" Action="write" Type="string"
+               Root="HKCR" Key="*\shellex\ContextMenuHandlers\7-Zip"
+               Value="$(var.ShellExtId)" />
+          </Component>
+
+          <Component Id="InstallRegDirectory" Guid="$(var.CompInstallRegDirectory)" DiskId="1" Win64="$(var.Is64)">
+            <Registry Id="MyInstallRegDirectory" Action="write" Type="string"
+               Root="HKCR" Key="Directory\shellex\ContextMenuHandlers\7-Zip"
+               Value="$(var.ShellExtId)" />
+          </Component>
+
+          <Component Id="InstallRegFolder" Guid="$(var.CompInstallRegFolder)" DiskId="1" Win64="$(var.Is64)">
+            <Registry Id="MyInstallRegFolder" Action="write" Type="string"
+               Root="HKCR" Key="Folder\shellex\ContextMenuHandlers\7-Zip"
+               Value="$(var.ShellExtId)" />
+          </Component>
+
+          <Component Id="InstallRegDirDD" Guid="$(var.CompInstallRegDirDD)" DiskId="1" Win64="$(var.Is64)">
+            <Registry Id="MyInstallRegDirDD" Action="write" Type="string"
+               Root="HKCR" Key="Directory\shellex\DragDropHandlers\7-Zip"
+               Value="$(var.ShellExtId)" />
+          </Component>
+
+          <Component Id="InstallRegDriveDD" Guid="$(var.CompInstallRegDriveDD)" DiskId="1" Win64="$(var.Is64)">
+            <Registry Id="MyInstallRegDriveDD" Action="write" Type="string"
+               Root="HKCR" Key="Drive\shellex\DragDropHandlers\7-Zip"
+               Value="$(var.ShellExtId)" />
+          </Component>
+
+          <Component Id="InstallRegApproved" Guid="$(var.CompInstallRegApproved)" DiskId="1" Win64="$(var.Is64)">
+            <Condition>Privileged</Condition>
+            <Registry Id="MyInstallRegApproved" Action="write" Type="string"
+               Root="HKLM" Key="Software\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved"
+               Name="$(var.ShellExtId)" Value="7-Zip Shell Extension" />
+          </Component>
+
+
+          <Component Id="InstallRegAppPath" Guid="$(var.CompInstallRegAppPath)" DiskId="1" Win64="$(var.Is64)">
+            <Condition>Privileged</Condition>
+            <Registry Id="MyInstallRegAppPath" Action="write" Type="string"
+               Root="HKLM" Key="Software\Microsoft\Windows\CurrentVersion\App Paths\7zFM.exe"
+               Value="[INSTALLDIR]7zFM.exe" />
+            <Registry Id="MyInstallRegAppPath2" Action="write" Type="string"
+               Root="HKLM" Key="Software\Microsoft\Windows\CurrentVersion\App Paths\7zFM.exe" Name="Path"
+               Value="[INSTALLDIR]" />
+          </Component>
+
+          <Component Id="Fm" Guid="$(var.CompFm)" DiskId="1" Win64="$(var.Is64)">
+            <File Id="_7zFM.exe" Name="7zFM.exe">
+              <Shortcut Id="startmenuFmShortcut" Directory="PMenu" Name="7zipFM" LongName="7-Zip File Manager" />
+            </File>
+          </Component>
+
+          <?if $(var.MyCPU) = "x64" ?>
+
+          <Component Id="ShellExt32" Guid="$(var.CompShellExt2)" DiskId="1" Win64="no">
+            <File Id="_7zip32.dll" Name="7-zip32.dll" />
+            <Registry Id="shellReg0_32" Action="write" Type="string" Root="HKCR"
+               Key="CLSID\$(var.ShellExtId)\InprocServer32"
+               Value="[INSTALLDIR]7-zip32.dll" />
+            <Registry Id="shellReg1_32" Action="write" Type="string" Root="HKCR"
+               Key="CLSID\$(var.ShellExtId)\InprocServer32"
+               Name="ThreadingModel"
+               Value="Apartment" />
+          </Component>
+
+          <?endif ?>
+
+          <Component Id="ShellExt" Guid="$(var.CompShellExt)" DiskId="1" Win64="$(var.Is64)">
+            <File Id="_7zip.dll" Name="7-zip.dll" />
+            <Registry Id="shellReg0" Action="write" Type="string" Root="HKCR"
+               Key="CLSID\$(var.ShellExtId)\InprocServer32"
+               Value="[INSTALLDIR]7-zip.dll" />
+            <Registry Id="shellReg1" Action="write" Type="string" Root="HKCR"
+               Key="CLSID\$(var.ShellExtId)\InprocServer32"
+               Name="ThreadingModel"
+               Value="Apartment" />
+          </Component>
+
+          <Component Id="Gui" Guid="$(var.CompGui)" DiskId="1" Win64="$(var.Is64)">
+            <File Id="_7zG.exe" Name="7zG.exe" />
+          </Component>
+
+          <Component Id="Formats" Guid="$(var.CompFormats)" DiskId="1" Win64="$(var.Is64)">
+              <File Id="_7z.dll" Name="7z.dll" />
+          </Component>
+
+          <Component Id="CmdLine" Guid="$(var.CompCmdLine)" DiskId="1" Win64="$(var.Is64)">
+            <File Id="_7z.exe" Name="7z.exe" />
+          </Component>
+
+          <Component Id="GuiSfx" Guid="$(var.CompGuiSfx)" DiskId="1" Win64="$(var.Is64)">
+            <File Id="_7z.sfx" Name="7z.sfx" />
+          </Component>
+
+          <Component Id="ConSfx" Guid="$(var.CompConSfx)" DiskId="1" Win64="$(var.Is64)">
+            <File Id="_7zCon.sfx" Name="7zCon.sfx" />
+          </Component>
+
+          <Component Id="Docs" Guid="$(var.CompDocs)" DiskId="1" Win64="$(var.Is64)">
+            <File Id="descript.ion" Name="descript.ion" />
+            <File Id="History.txt" Name="History.txt" />
+            <File Id="License.txt" Name="License.txt" />
+            <File Id="readme.txt" Name="readme.txt" />
+          </Component>
+
+
+          <Component Id="Help" Guid="$(var.CompHelp)">
+            <File Id="_7zip.chm" Name="7-zip.chm" DiskId="1" >
+              <Shortcut Id="startmenuHelpShortcut" Directory="PMenu" Name="7zipHelp" LongName="7-Zip Help" />
+            </File>
+          </Component>
+
+          <Directory Id="MyLang" Name="Lang">
+            <Component Id="Lang" Guid="$(var.CompLang)" DiskId="1" Win64="$(var.Is64)">
+              <File Id="en.ttt" Name="en.ttt" />
+              <File Id="af.txt" Name="af.txt" />
+              <File Id="an.txt" Name="an.txt" />
+              <File Id="ar.txt" Name="ar.txt" />
+              <File Id="ast.txt" Name="ast.txt" />
+              <File Id="az.txt" Name="az.txt" />
+              <File Id="ba.txt" Name="ba.txt" />
+              <File Id="be.txt" Name="be.txt" />
+              <File Id="bg.txt" Name="bg.txt" />
+              <File Id="bn.txt" Name="bn.txt" />
+              <File Id="br.txt" Name="br.txt" />
+              <File Id="ca.txt" Name="ca.txt" />
+              <File Id="co.txt" Name="co.txt" />
+              <File Id="cs.txt" Name="cs.txt" />
+              <File Id="cy.txt" Name="cy.txt" />
+              <File Id="da.txt" Name="da.txt" />
+              <File Id="de.txt" Name="de.txt" />
+              <File Id="el.txt" Name="el.txt" />
+              <File Id="eo.txt" Name="eo.txt" />
+              <File Id="es.txt" Name="es.txt" />
+              <File Id="et.txt" Name="et.txt" />
+              <File Id="eu.txt" Name="eu.txt" />
+              <File Id="ext.txt" Name="ext.txt" />
+              <File Id="fa.txt" Name="fa.txt" />
+              <File Id="fi.txt" Name="fi.txt" />
+              <File Id="fr.txt" Name="fr.txt" />
+              <File Id="fur.txt" Name="fur.txt" />
+              <File Id="fy.txt" Name="fy.txt" />
+              <File Id="ga.txt" Name="ga.txt" />
+              <File Id="gl.txt" Name="gl.txt" />
+              <File Id="gu.txt" Name="gu.txt" />
+              <File Id="he.txt" Name="he.txt" />
+              <File Id="hi.txt" Name="hi.txt" />
+              <File Id="hr.txt" Name="hr.txt" />
+              <File Id="hu.txt" Name="hu.txt" />
+              <File Id="hy.txt" Name="hy.txt" />
+              <File Id="id.txt" Name="id.txt" />
+              <File Id="io.txt" Name="io.txt" />
+              <File Id="is.txt" Name="is.txt" />
+              <File Id="it.txt" Name="it.txt" />
+              <File Id="ja.txt" Name="ja.txt" />
+              <File Id="ka.txt" Name="ka.txt" />
+              <File Id="kaa.txt" Name="kaa.txt" />
+              <File Id="kab.txt" Name="kab.txt" />
+              <File Id="kk.txt" Name="kk.txt" />
+              <File Id="ko.txt" Name="ko.txt" />
+              <File Id="ku.txt" Name="ku.txt" />
+              <File Id="ku_ckb.txt" Name="ku-ckb.txt" />
+              <File Id="ky.txt" Name="ky.txt" />
+              <File Id="lij.txt" Name="lij.txt" />
+              <File Id="lt.txt" Name="lt.txt" />
+              <File Id="lv.txt" Name="lv.txt" />
+              <File Id="mk.txt" Name="mk.txt" />
+              <File Id="mn.txt" Name="mn.txt" />
+              <File Id="mng.txt" Name="mng.txt" />
+              <File Id="mng2.txt" Name="mng2.txt" />
+              <File Id="mr.txt" Name="mr.txt" />
+              <File Id="ms.txt" Name="ms.txt" />
+              <File Id="ne.txt" Name="ne.txt" />
+              <File Id="nl.txt" Name="nl.txt" />
+              <File Id="nb.txt" Name="nb.txt" />
+              <File Id="nn.txt" Name="nn.txt" />
+              <File Id="pa_in.txt" Name="pa-in.txt" />
+              <File Id="pl.txt" Name="pl.txt" />
+              <File Id="ps.txt" Name="ps.txt" />
+              <File Id="pt.txt" Name="pt.txt" />
+              <File Id="pt_br.txt" Name="pt-br.txt" />
+              <File Id="ro.txt" Name="ro.txt" />
+              <File Id="ru.txt" Name="ru.txt" />
+              <File Id="sa.txt" Name="sa.txt" />
+              <File Id="si.txt" Name="si.txt" />
+              <File Id="sk.txt" Name="sk.txt" />
+              <File Id="sl.txt" Name="sl.txt" />
+              <File Id="sq.txt" Name="sq.txt" />
+              <File Id="sr_spl.txt" Name="sr-spl.txt" />
+              <File Id="sr_spc.txt" Name="sr-spc.txt" />
+              <File Id="sv.txt" Name="sv.txt" />
+              <File Id="sw.txt" Name="sw.txt" />
+              <File Id="ta.txt" Name="ta.txt" />
+              <File Id="tg.txt" Name="tg.txt" />
+              <File Id="th.txt" Name="th.txt" />
+              <File Id="tk.txt" Name="tk.txt" />
+              <File Id="tr.txt" Name="tr.txt" />
+              <File Id="tt.txt" Name="tt.txt" />
+              <File Id="ug.txt" Name="ug.txt" />
+              <File Id="uk.txt" Name="uk.txt" />
+              <File Id="uz.txt" Name="uz.txt" />
+              <File Id="uz_cyrl.txt" Name="uz-cyrl.txt" />
+              <File Id="va.txt" Name="va.txt" />
+              <File Id="vi.txt" Name="vi.txt" />
+              <File Id="yo.txt" Name="yo.txt" />
+              <File Id="zh_cn.txt" Name="zh-cn.txt" />
+              <File Id="zh_tw.txt" Name="zh-tw.txt" />
+            </Component>
+          </Directory>
+
+
+        </Directory>
+      </Directory>
+
+      <Directory Id="ProgramMenuFolder" Name="PMenu" LongName="Programs">
+        <Directory Id="PMenu" Name="7zip" LongName="7-Zip" />
+      </Directory>
+    </Directory>
+
+    <Feature Id="Complete" Title="7-Zip" Description="The complete package."
+         Display="expand" Level="1" ConfigurableDirectory="INSTALLDIR"
+         Absent="disallow" AllowAdvertise="no" >
+      <Feature Id="Program" Title="Program files" Description="Program files." Level="1"
+         Absent="disallow" AllowAdvertise="no">
+        <ComponentRef Id="Fm" />
+        <ComponentRef Id="ShellExt" />
+        <?if $(var.MyCPU) = "x64" ?>
+        <ComponentRef Id="ShellExt32" />
+        <?endif ?>
+        <ComponentRef Id="CmdLine" />
+        <ComponentRef Id="Gui" />
+        <ComponentRef Id="GuiSfx" />
+        <ComponentRef Id="ConSfx" />
+        <ComponentRef Id="Formats" />
+        <ComponentRef Id="Docs" />
+        <ComponentRef Id="Help" />
+        <ComponentRef Id="InstallRegCU" />
+        <ComponentRef Id="InstallRegLM" />
+        <ComponentRef Id="InstallRegWild" />
+        <ComponentRef Id="InstallRegDirectory" />
+        <ComponentRef Id="InstallRegDirDD" />
+        <ComponentRef Id="InstallRegDriveDD" />
+        <ComponentRef Id="InstallRegApproved" />
+        <ComponentRef Id="InstallRegAppPath" />
+        <ComponentRef Id="InstallRegFolder" />
+
+      </Feature>
+      <Feature Id="LanguageFiles" Title="Localization files" Description="Localization files for 71 languages."
+          Level="1" AllowAdvertise="no">
+        <ComponentRef Id="Lang" />
+      </Feature>
+    </Feature>
+
+    <UIRef Id="WixUI" />
+
+    <!-- Install Sequences -->
+    <InstallExecuteSequence>
+      <RemoveExistingProducts After="InstallValidate" />
+    </InstallExecuteSequence>
+
+  </Product>
+</Wix>
diff --git a/DOC/License.txt b/DOC/License.txt
new file mode 100644
index 0000000..c9e858f
--- /dev/null
+++ b/DOC/License.txt
@@ -0,0 +1,90 @@
+  7-Zip source code
+  ~~~~~~~~~~~~~~~~~
+  License for use and distribution
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+  7-Zip Copyright (C) 1999-2020 Igor Pavlov.
+
+  The licenses for files are:
+
+    1) CPP/7zip/Compress/Rar* files: the "GNU LGPL" with "unRAR license restriction"
+    2) CPP/7zip/Compress/LzfseDecoder.cpp: the "BSD 3-clause License"
+    3) Some files are "public domain" files, if "public domain" status is stated in source file.
+    4) 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, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+
+
+  BSD 3-clause License
+  --------------------
+
+    The "BSD 3-clause License" is used for the code in LzfseDecoder.cpp that implements LZFSE data decompression.
+    That code was derived from the code in the "LZFSE compression library" developed by Apple Inc,
+    that also uses 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.
+    ----
+
+
+
+
+  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.
+
+
+  --
+  Igor Pavlov
diff --git a/DOC/Methods.txt b/DOC/Methods.txt
index 6d0641b..541f1c1 100644
--- a/DOC/Methods.txt
+++ b/DOC/Methods.txt
@@ -1,173 +1,176 @@
-7-Zip method IDs for 7z and xz archives

----------------------------------------

-

-Version: 18.06

-Date: 2018-06-30

-

-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

-

-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)

-      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: 23.01
+Date: 2023-06-30
+
+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
+
+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
new file mode 100644
index 0000000..4362b49
--- /dev/null
+++ b/DOC/copying.txt
@@ -0,0 +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.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/DOC/installer.txt b/DOC/installer.txt
deleted file mode 100644
index 70ad7dc..0000000
--- a/DOC/installer.txt
+++ /dev/null
@@ -1,166 +0,0 @@
-7-Zip for installers 9.38

--------------------------

-

-7-Zip is a file archiver for Windows NT/2000/2003/2008/XP/Vista/7/8/10. 

-

-7-Zip for installers is part of LZMA SDK.

-LZMA SDK is written and placed in the public domain by Igor Pavlov.

-

-It's allowed to join 7-Zip SFX module with another software.

-It's allowed to change resources of 7-Zip's SFX modules.

-

-

-HOW to use

------------

-

-7zr.exe is reduced version of 7za.exe of 7-Zip.

-7zr.exe supports only format with these codecs: LZMA, LZMA2, BCJ, BCJ2, ARM, Copy.

-

-Example of compressing command for installation packages:

-

-7zr a archive.7z files

-

-7zSD.sfx is SFX module for installers. 7zSD.sfx uses msvcrt.dll.

-

-SFX modules for installers allow to create installation program. 

-Such module extracts archive to temp folder and then runs specified program and removes 

-temp files after program finishing. Self-extract archive for installers must be created 

-as joining 3 files: SFX_Module, Installer_Config, 7z_Archive. 

-Installer_Config is optional file. You can use the following command to create installer 

-self-extract archive:

-

-copy /b 7zSD.sfx + config.txt + archive.7z archive.exe

-

-The smallest installation package size can be achieved, if installation files was 

-uncompressed before including to 7z archive.

-

--y switch for installer module (at runtime) specifies quiet mode for extracting.

-

-Installer Config file format

-~~~~~~~~~~~~~~~~~~~~~~~~~~~~

-Config file contains commands for Installer. File begins from string 

-;!@Install@!UTF-8! and ends with ;!@InstallEnd@!. File must be written 

-in UTF-8 encoding. File contains string pairs: 

-

-ID_String="Value"

-

-ID_String          Description 

-

-Title              Title for messages 

-BeginPrompt        Begin Prompt message 

-Progress           Value can be "yes" or "no". Default value is "yes". 

-RunProgram         Command for executing. Default value is "setup.exe". 

-                   Substring %%T will be replaced with path to temporary 

-                   folder, where files were extracted 

-Directory          Directory prefix for "RunProgram". Default value is ".\\" 

-ExecuteFile        Name of file for executing 

-ExecuteParameters  Parameters for "ExecuteFile" 

-

-

-You can omit any string pair.

-

-There are two ways to run program: RunProgram and ExecuteFile. 

-Use RunProgram, if you want to run some program from .7z archive. 

-Use ExecuteFile, if you want to open some document from .7z archive or 

-if you want to execute some command from Windows.

-

-If you use RunProgram and if you specify empty directory prefix: Directory="", 

-the system searches for the executable file in the following sequence:

-

-1. The directory from which the application (installer) loaded. 

-2. The temporary folder, where files were extracted. 

-3. The Windows system directory. 

-

-

-Config file Examples

-~~~~~~~~~~~~~~~~~~~~

-

-;!@Install@!UTF-8!

-Title="7-Zip 4.00"

-BeginPrompt="Do you want to install the 7-Zip 4.00?"

-RunProgram="setup.exe"

-;!@InstallEnd@!

-

-

-

-;!@Install@!UTF-8!

-Title="7-Zip 4.00"

-BeginPrompt="Do you want to install the 7-Zip 4.00?"

-ExecuteFile="7zip.msi"

-;!@InstallEnd@!

-

-

-

-;!@Install@!UTF-8!

-Title="7-Zip 4.01 Update"

-BeginPrompt="Do you want to install the 7-Zip 4.01 Update?"

-ExecuteFile="msiexec.exe"

-ExecuteParameters="/i 7zip.msi REINSTALL=ALL REINSTALLMODE=vomus"

-;!@InstallEnd@!

-

-

-

-Small SFX modules for installers

---------------------------------

-

-7zS2.sfx     - small SFX module (GUI version)

-7zS2con.sfx  - small SFX module (Console version)

-

-Small SFX modules support this codecs: LZMA, LZMA2, BCJ, BCJ2, ARM, COPY

-

-Small SFX module is similar to common SFX module for installers.

-The difference (what's new in small version):

- - Smaller size (30 KB vs 100 KB)

- - C source code instead of Ñ++

- - No installer Configuration file

- - No extracting progress window

- - It decompresses solid 7z blocks (it can be whole 7z archive) to RAM.

-   So user that calls SFX installer must have free RAM of size of largest 

-   solid 7z block (size of 7z archive at simplest case).

-

-How to use

-----------

-

-copy /b 7zS2.sfx + archive.7z sfx.exe

-

-When you run installer sfx module (sfx.exe)

-1) It creates "7zNNNNNNNN" temp folder in system temp folder.

-2) It extracts .7z archive to that folder

-3) It executes one file from "7zNNNNNNNN" temp folder. 

-4) It removes "7zNNNNNNNN" temp folder

-

-You can send parameters to installer, and installer will transfer them to extracted .exe file.

-

-Small SFX uses 3 levels of priorities to select file to execute:

-

-  1) Files in root folder have higher priority than files in subfolders.

-  2) File extension priorities (from high to low priority order): 

-       bat, cmd, exe, inf, msi, cab (under Windows CE), html, htm

-  3) File name priorities (from high to low priority order): 

-       setup, install, run, start

-

-Windows CE (ARM) version of 7zS2.sfx is included to 7-Zip for Windows Mobile package.

-

-

-Examples

---------

-

-1) To create compressed console 7-Zip:

-

-7zr a c.7z 7z.exe 7z.dll -mx

-copy /b 7zS2con.sfx + c.7z 7zCompr.exe

-7zCompr.exe b -md22

-

-

-2) To create compressed GUI 7-Zip:

-

-7zr a g.7z 7zg.exe 7z.dll -mx

-copy /b 7zS2.sfx + g.7z 7zgCompr.exe

-7zgCompr.exe b -md22

-

-

-3) To open some file:

-

-7zr a h.7z readme.txt -mx

-copy /b 7zS2.sfx + h.7z 7zTxt.exe 

-7zTxt.exe

diff --git a/DOC/lzma-history.txt b/DOC/lzma-history.txt
deleted file mode 100644
index 3a6f0f3..0000000
--- a/DOC/lzma-history.txt
+++ /dev/null
@@ -1,446 +0,0 @@
-HISTORY of the LZMA SDK

------------------------

-

-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.

-- The bug in 7zIn.c code was 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.

-- 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).

-- The BUG was fixed in Lzma2Enc.c

-    Lzma2Enc_Encode2() function worked incorretly,

-      if (inStream == NULL) and the number of block threads is more than 1.

-

-

-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.

-

-

-18.01          2019-01-28

--------------------------

-- The BUG in 17.01 - 18.00 beta was fixed:

-  XzDec.c : random block unpacking and XzUnpacker_IsBlockFinished()

-  didn't work correctly for xz archives without checksum (CRC).

-

-

-18.00 beta     2019-01-10

--------------------------

-- The BUG in xz encoder was fixed:

-  There was memory leak of 16 KB for each file compressed with 

-  xz compression method, if additional filter was used.

-

-

-17.01 beta     2017-08-28

--------------------------

-- Minor speed optimization for LZMA2 (xz and 7z) multi-threading compression.

-  7-Zip now uses additional memory buffers for multi-block LZMA2 compression.

-  CPU utilization was slightly improved.

-- 7-zip now creates multi-block xz archives by default. Block size can be 

-  specified with -ms[Size]{m|g} switch.

-- xz decoder now can unpack random block from multi-block xz archives.

-- 7-Zip command line: @listfile now doesn't work after -- switch.

-  Use -i@listfile before -- switch instead.

-- The BUGs were fixed:

-  7-Zip 17.00 beta crashed for commands that write anti-item to 7z archive.

-

-

-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.04          2016-10-04

--------------------------

-- The bug was fixed in DllSecur.c.

-

-

-16.03          2016-09-28

--------------------------

-- SFX modules now use some protection against DLL preloading attack.

-- Some bugs in 7z code were fixed.

-

-

-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 internal changes to reduce the number of compiler warnings.

-

-

-16.00          2016-05-10

--------------------------	

-- 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.35 beta      2014-12-07

--------------------------	

-- 7zr.exe now support AES encryption.

-- SFX mudules were added to LZMA SDK

-- Some bugs were fixed.

-

-

-9.21 beta      2011-04-11

--------------------------	

-- New class FString for file names at file systems.

-- Speed optimization in CRC code for big-endian CPUs.

-- The BUG in Lzma2Dec.c was fixed:

-    Lzma2Decode function didn't work.

-

-

-9.18 beta      2010-11-02

--------------------------	

-- New small SFX module for installers (SfxSetup).

-

-

-9.12 beta      2010-03-24

--------------------------

-- The BUG in LZMA SDK 9.* was fixed: LZMA2 codec didn't work,

-  if more than 10 threads were used (or more than 20 threads in some modes).

-

-

-9.11 beta      2010-03-15

--------------------------

-- PPMd compression method support

-   

-

-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.

-- Some bugs were fixed

-

-

-9.06           2009-08-17

--------------------------

-- Some changes in ANSI-C 7z Decoder interfaces.

-

-

-9.04           2009-05-30

--------------------------

-- LZMA2 compression method support

-- xz format support

-

-

-4.65           2009-02-03

--------------------------

-- Some minor fixes

-

-

-4.63           2008-12-31

--------------------------

-- Some minor fixes

-

-

-4.61 beta      2008-11-23

--------------------------

-- The bug in ANSI-C LZMA Decoder was fixed:

-    If encoded stream was corrupted, decoder could access memory 

-    outside of allocated range.

-- Some changes in ANSI-C 7z Decoder interfaces.

-- LZMA SDK is placed in the public domain.

-

-

-4.60 beta      2008-08-19

--------------------------

-- Some minor fixes.

-

-

-4.59 beta      2008-08-13

--------------------------

-- The bug was fixed:

-    LZMA Encoder in fast compression mode could access memory outside of 

-    allocated range in some rare cases.

-

-

-4.58 beta      2008-05-05

--------------------------

-- ANSI-C LZMA Decoder was rewritten for speed optimizations.

-- ANSI-C LZMA Encoder was included to LZMA SDK.

-- C++ LZMA code now is just wrapper over ANSI-C code.

-

-

-4.57           2007-12-12

--------------------------

-- Speed optimizations in Ñ++ LZMA Decoder. 

-- Small changes for more compatibility with some C/C++ compilers.

-

-

-4.49 beta      2007-07-05

--------------------------

-- .7z ANSI-C Decoder:

-     - now it supports BCJ and BCJ2 filters

-     - now it supports files larger than 4 GB.

-     - now it supports "Last Write Time" field for files.

-- C++ code for .7z archives compressing/decompressing from 7-zip 

-  was included to LZMA SDK.

-  

-

-4.43           2006-06-04

--------------------------

-- Small changes for more compatibility with some C/C++ compilers.

-  

-

-4.42           2006-05-15

--------------------------

-- Small changes in .h files in ANSI-C version.

-  

-

-4.39 beta      2006-04-14

--------------------------

-- The bug in versions 4.33b:4.38b was fixed:

-  C++ version of LZMA encoder could not correctly compress 

-  files larger than 2 GB with HC4 match finder (-mfhc4).

-  

-

-4.37 beta      2005-04-06

--------------------------

-- Fixes in C++ code: code could no be compiled if _NO_EXCEPTIONS was defined. 

-

-

-4.35 beta      2005-03-02

--------------------------

-- The bug was fixed in C++ version of LZMA Decoder:

-    If encoded stream was corrupted, decoder could access memory 

-    outside of allocated range.

-

-

-4.34 beta      2006-02-27

--------------------------

-- Compressing speed and memory requirements for compressing were increased

-- LZMA now can use only these match finders: HC4, BT2, BT3, BT4

-

-

-4.32           2005-12-09

--------------------------

-- Java version of LZMA SDK was included

-

-

-4.30           2005-11-20

--------------------------

-- Compression ratio was improved in -a2 mode

-- Speed optimizations for compressing in -a2 mode

-- -fb switch now supports values up to 273

-- The bug in 7z_C (7zIn.c) was fixed:

-  It used Alloc/Free functions from different memory pools.

-  So if program used two memory pools, it worked incorrectly.

-- 7z_C: .7z format supporting was improved

-- LZMA# SDK (C#.NET version) was included

-

-

-4.27 (Updated) 2005-09-21

--------------------------

-- Some GUIDs/interfaces in C++ were changed.

- IStream.h:

-   ISequentialInStream::Read now works as old ReadPart

-   ISequentialOutStream::Write now works as old WritePart

-

-

-4.27           2005-08-07

--------------------------

-- The bug in LzmaDecodeSize.c was fixed:

-   if _LZMA_IN_CB and _LZMA_OUT_READ were defined,

-   decompressing worked incorrectly.

-

-

-4.26           2005-08-05

--------------------------

-- Fixes in 7z_C code and LzmaTest.c:

-  previous versions could work incorrectly,

-  if malloc(0) returns 0

-

-

-4.23           2005-06-29

--------------------------

-- Small fixes in C++ code

-

-

-4.22           2005-06-10

--------------------------

-- Small fixes

-

-

-4.21           2005-06-08

--------------------------

-- Interfaces for ANSI-C LZMA Decoder (LzmaDecode.c) were changed

-- New additional version of ANSI-C LZMA Decoder with zlib-like interface:

-    - LzmaStateDecode.h

-    - LzmaStateDecode.c

-    - LzmaStateTest.c

-- ANSI-C LZMA Decoder now can decompress files larger than 4 GB

-

-

-4.17           2005-04-18

--------------------------

-- New example for RAM->RAM compressing/decompressing: 

-  LZMA + BCJ (filter for x86 code):

-    - LzmaRam.h

-    - LzmaRam.cpp

-    - LzmaRamDecode.h

-    - LzmaRamDecode.c

-    - -f86 switch for lzma.exe

-

-

-4.16           2005-03-29

--------------------------

-- The bug was fixed in LzmaDecode.c (ANSI-C LZMA Decoder): 

-   If _LZMA_OUT_READ was defined, and if encoded stream was corrupted,

-   decoder could access memory outside of allocated range.

-- Speed optimization of ANSI-C LZMA Decoder (now it's about 20% faster).

-  Old version of LZMA Decoder now is in file LzmaDecodeSize.c. 

-  LzmaDecodeSize.c can provide slightly smaller code than LzmaDecode.c

-- Small speed optimization in LZMA C++ code

-- filter for SPARC's code was added

-- Simplified version of .7z ANSI-C Decoder was included

-

-

-4.06           2004-09-05

--------------------------

-- The bug in v4.05 was fixed:

-    LZMA-Encoder didn't release output stream in some cases.

-

-

-4.05           2004-08-25

--------------------------

-- Source code of filters for x86, IA-64, ARM, ARM-Thumb 

-  and PowerPC code was included to SDK

-- Some internal minor changes

-

-

-4.04           2004-07-28

--------------------------

-- More compatibility with some C++ compilers

-

-

-4.03           2004-06-18

--------------------------

-- "Benchmark" command was added. It measures compressing 

-  and decompressing speed and shows rating values. 

-  Also it checks hardware errors.

-

-

-4.02           2004-06-10

--------------------------

-- C++ LZMA Encoder/Decoder code now is more portable

-  and it can be compiled by GCC on Linux.

-

-

-4.01           2004-02-15

--------------------------

-- Some detection of data corruption was enabled.

-    LzmaDecode.c / RangeDecoderReadByte

-    .....

-    {

-      rd->ExtraBytes = 1;

-      return 0xFF;

-    }

-

-

-4.00           2004-02-13

--------------------------

-- Original version of LZMA SDK

-

-

-

-HISTORY of the LZMA

--------------------

-  2001-2008:  Improvements to LZMA compressing/decompressing code, 

-              keeping compatibility with original LZMA format

-  1996-2001:  Development of LZMA compression format

-

-  Some milestones:

-

-  2001-08-30: LZMA compression was added to 7-Zip

-  1999-01-02: First version of 7-Zip was released

-  

-

-End of document

diff --git a/DOC/lzma-sdk.txt b/DOC/lzma-sdk.txt
deleted file mode 100644
index 1bde6db..0000000
--- a/DOC/lzma-sdk.txt
+++ /dev/null
@@ -1,357 +0,0 @@
-LZMA SDK 19.00

---------------

-

-LZMA SDK provides the documentation, samples, header files,

-libraries, and tools you need to develop applications that 

-use 7z / LZMA / LZMA2 / XZ compression.

-

-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.

-

-LZMA2 is a LZMA based compression method. LZMA2 provides better 

-multithreading support for compression than LZMA and some other improvements.

-

-7z is a file format for data compression and file archiving.

-7z is a main file format for 7-Zip compression program (www.7-zip.org).

-7z format supports different compression methods: LZMA, LZMA2 and others.

-7z also supports AES-256 based encryption.

-

-XZ is a file format for data compression that uses LZMA2 compression.

-XZ format provides additional features: SHA/CRC check, filters for 

-improved compression ratio, splitting to blocks and streams,

-

-

-

-LICENSE

--------

-

-LZMA SDK is written and placed in the public domain by Igor Pavlov.

-

-Some code in LZMA SDK is based on public domain code from another developers:

-  1) PPMd var.H (2001): Dmitry Shkarin

-  2) SHA-256: Wei Dai (Crypto++ library)

-

-Anyone is free to copy, modify, publish, use, compile, sell, or distribute the 

-original LZMA SDK code, either in source code form or as a compiled binary, for 

-any purpose, commercial or non-commercial, and by any means.

-

-LZMA SDK code is compatible with open source licenses, for example, you can 

-include it to GNU GPL or GNU LGPL code.

-

-

-LZMA SDK Contents

------------------

-

-  Source code:

-

-    - C / C++ / C# / Java   - LZMA compression and decompression

-    - C / C++               - LZMA2 compression and decompression

-    - C / C++               - XZ compression and decompression

-    - C                     - 7z decompression

-    -     C++               - 7z compression and decompression

-    - C                     - small SFXs for installers (7z decompression)

-    -     C++               - SFXs and SFXs for installers (7z decompression)

-

-  Precomiled binaries:

-

-    - console programs for lzma / 7z / xz compression and decompression

-    - SFX modules for installers.

-

-

-UNIX/Linux version 

-------------------

-To compile C++ version of file->file LZMA encoding, go to directory

-CPP/7zip/Bundles/LzmaCon

-and call make to recompile it:

-  make -f makefile.gcc clean all

-

-In some UNIX/Linux versions you must compile LZMA with static libraries.

-To compile with static libraries, you can use 

-LIB = -lm -static

-

-Also you can use p7zip (port of 7-Zip for POSIX systems like Unix or Linux):

-  

-  http://p7zip.sourceforge.net/

-

-

-Files

------

-

-DOC/7zC.txt          - 7z ANSI-C Decoder description

-DOC/7zFormat.txt     - 7z Format description

-DOC/installer.txt    - information about 7-Zip for installers

-DOC/lzma.txt         - LZMA compression description

-DOC/lzma-sdk.txt     - LZMA SDK description (this file)

-DOC/lzma-history.txt - history of LZMA SDK

-DOC/lzma-specification.txt - Specification of LZMA

-DOC/Methods.txt      - Compression method IDs for .7z

-

-bin/installer/   - example script to create installer that uses SFX module,

-

-bin/7zdec.exe    - simplified 7z archive decoder

-bin/7zr.exe      - 7-Zip console program (reduced version)

-bin/x64/7zr.exe  - 7-Zip console program (reduced version) (x64 version)

-bin/lzma.exe     - file->file LZMA encoder/decoder for Windows

-bin/7zS2.sfx     - small SFX module for installers (GUI version)

-bin/7zS2con.sfx  - small SFX module for installers (Console version)

-bin/7zSD.sfx     - SFX module for installers.

-

-

-7zDec.exe

----------

-7zDec.exe is simplified 7z archive decoder.

-It supports only LZMA, LZMA2, and PPMd methods.

-7zDec decodes whole solid block from 7z archive to RAM.

-The RAM consumption can be high.

-

-

-

-

-Source code structure

----------------------

-

-

-Asm/ - asm files (optimized code for CRC calculation and Intel-AES encryption)

-

-C/  - C files (compression / decompression and other)

-  Util/

-    7z       - 7z decoder program (decoding 7z files)

-    Lzma     - LZMA program (file->file LZMA encoder/decoder).

-    LzmaLib  - LZMA library (.DLL for Windows)

-    SfxSetup - small SFX module for installers 

-

-CPP/ -- CPP files

-

-  Common  - common files for C++ projects

-  Windows - common files for Windows related code

-

-  7zip    - files related to 7-Zip

-

-    Archive - files related to archiving

-

-      Common   - common files for archive handling

-      7z       - 7z C++ Encoder/Decoder

-

-    Bundles  - Modules that are bundles of other modules (files)

-  

-      Alone7z       - 7zr.exe: Standalone 7-Zip console program (reduced version)

-      Format7zExtractR  - 7zxr.dll: Reduced version of 7z DLL: extracting from 7z/LZMA/BCJ/BCJ2.

-      Format7zR         - 7zr.dll:  Reduced version of 7z DLL: extracting/compressing to 7z/LZMA/BCJ/BCJ2

-      LzmaCon       - lzma.exe: LZMA compression/decompression

-      LzmaSpec      - example code for LZMA Specification

-      SFXCon        - 7zCon.sfx: Console 7z SFX module

-      SFXSetup      - 7zS.sfx: 7z SFX module for installers

-      SFXWin        - 7z.sfx: GUI 7z SFX module

-

-    Common   - common files for 7-Zip

-

-    Compress - files for compression/decompression

-

-    Crypto   - files for encryption / decompression

-

-    UI       - User Interface files

-         

-      Client7z - Test application for 7za.dll, 7zr.dll, 7zxr.dll

-      Common   - Common UI files

-      Console  - Code for console program (7z.exe)

-      Explorer    - Some code from 7-Zip Shell extension

-      FileManager - Some GUI code from 7-Zip File Manager

-      GUI         - Some GUI code from 7-Zip

-

-

-CS/ - C# files

-  7zip

-    Common   - some common files for 7-Zip

-    Compress - files related to compression/decompression

-      LZ     - files related to LZ (Lempel-Ziv) compression algorithm

-      LZMA         - LZMA compression/decompression

-      LzmaAlone    - file->file LZMA compression/decompression

-      RangeCoder   - Range Coder (special code of compression/decompression)

-

-Java/  - Java files

-  SevenZip

-    Compression    - files related to compression/decompression

-      LZ           - files related to LZ (Lempel-Ziv) compression algorithm

-      LZMA         - LZMA compression/decompression

-      RangeCoder   - Range Coder (special code of compression/decompression)

-

-

-Note: 

-  Asm / C / C++ source code of LZMA SDK is part of 7-Zip's source code.

-  7-Zip's source code can be downloaded from 7-Zip's SourceForge page:

-

-  http://sourceforge.net/projects/sevenzip/

-

-

-

-LZMA features

--------------

-  - Variable dictionary size (up to 1 GB)

-  - Estimated compressing speed: about 2 MB/s on 2 GHz CPU

-  - Estimated decompressing speed: 

-      - 20-30 MB/s on modern 2 GHz cpu

-      - 1-2 MB/s on 200 MHz simple RISC cpu: (ARM, MIPS, PowerPC)

-  - Small memory requirements for decompressing (16 KB + DictionarySize)

-  - Small code size for decompressing: 5-8 KB

-

-LZMA decoder uses only integer operations and can be 

-implemented in any modern 32-bit CPU (or on 16-bit CPU with some conditions).

-

-Some critical operations that affect the speed of LZMA decompression:

-  1) 32*16 bit integer multiply

-  2) Mispredicted branches (penalty mostly depends from pipeline length)

-  3) 32-bit shift and arithmetic operations

-

-The speed of LZMA decompressing mostly depends from CPU speed.

-Memory speed has no big meaning. But if your CPU has small data cache, 

-overall weight of memory speed will slightly increase.

-

-

-How To Use

-----------

-

-Using LZMA encoder/decoder executable

---------------------------------------

-

-Usage:  LZMA <e|d> inputFile outputFile [<switches>...]

-

-  e: encode file

-

-  d: decode file

-

-  b: Benchmark. There are two tests: compressing and decompressing 

-     with LZMA method. Benchmark shows rating in MIPS (million 

-     instructions per second). Rating value is calculated from 

-     measured speed and it is normalized with Intel's Core 2 results.

-     Also Benchmark checks possible hardware errors (RAM 

-     errors in most cases). Benchmark uses these settings:

-     (-a1, -d21, -fb32, -mfbt4). You can change only -d parameter. 

-     Also you can change the number of iterations. Example for 30 iterations:

-       LZMA b 30

-     Default number of iterations is 10.

-

-<Switches>

-  

-

-  -a{N}:  set compression mode 0 = fast, 1 = normal

-          default: 1 (normal)

-

-  d{N}:   Sets Dictionary size - [0, 30], default: 23 (8MB)

-          The maximum value for dictionary size is 1 GB = 2^30 bytes.

-          Dictionary size is calculated as DictionarySize = 2^N bytes. 

-          For decompressing file compressed by LZMA method with dictionary 

-          size D = 2^N you need about D bytes of memory (RAM).

-

-  -fb{N}: set number of fast bytes - [5, 273], default: 128

-          Usually big number gives a little bit better compression ratio 

-          and slower compression process.

-

-  -lc{N}: set number of literal context bits - [0, 8], default: 3

-          Sometimes lc=4 gives gain for big files.

-

-  -lp{N}: set number of literal pos bits - [0, 4], default: 0

-          lp switch is intended for periodical data when period is 

-          equal 2^N. For example, for 32-bit (4 bytes) 

-          periodical data you can use lp=2. Often it's better to set lc0, 

-          if you change lp switch.

-

-  -pb{N}: set number of pos bits - [0, 4], default: 2

-          pb switch is intended for periodical data 

-          when period is equal 2^N.

-

-  -mf{MF_ID}: set Match Finder. Default: bt4. 

-              Algorithms from hc* group doesn't provide good compression 

-              ratio, but they often works pretty fast in combination with 

-              fast mode (-a0).

-

-              Memory requirements depend from dictionary size 

-              (parameter "d" in table below). 

-

-               MF_ID     Memory                   Description

-

-                bt2    d *  9.5 + 4MB  Binary Tree with 2 bytes hashing.

-                bt3    d * 11.5 + 4MB  Binary Tree with 3 bytes hashing.

-                bt4    d * 11.5 + 4MB  Binary Tree with 4 bytes hashing.

-                hc4    d *  7.5 + 4MB  Hash Chain with 4 bytes hashing.

-

-  -eos:   write End Of Stream marker. By default LZMA doesn't write 

-          eos marker, since LZMA decoder knows uncompressed size 

-          stored in .lzma file header.

-

-  -si:    Read data from stdin (it will write End Of Stream marker).

-  -so:    Write data to stdout

-

-

-Examples:

-

-1) LZMA e file.bin file.lzma -d16 -lc0 

-

-compresses file.bin to file.lzma with 64 KB dictionary (2^16=64K)  

-and 0 literal context bits. -lc0 allows to reduce memory requirements 

-for decompression.

-

-

-2) LZMA e file.bin file.lzma -lc0 -lp2

-

-compresses file.bin to file.lzma with settings suitable 

-for 32-bit periodical data (for example, ARM or MIPS code).

-

-3) LZMA d file.lzma file.bin

-

-decompresses file.lzma to file.bin.

-

-

-Compression ratio hints

------------------------

-

-Recommendations

----------------

-

-To increase the compression ratio for LZMA compressing it's desirable 

-to have aligned data (if it's possible) and also it's desirable to locate

-data in such order, where code is grouped in one place and data is 

-grouped in other place (it's better than such mixing: code, data, code,

-data, ...).

-

-

-Filters

--------

-You can increase the compression ratio for some data types, using

-special filters before compressing. For example, it's possible to 

-increase the compression ratio on 5-10% for code for those CPU ISAs: 

-x86, IA-64, ARM, ARM-Thumb, PowerPC, SPARC.

-

-You can find C source code of such filters in C/Bra*.* files

-

-You can check the compression ratio gain of these filters with such 

-7-Zip commands (example for ARM code):

-No filter:

-  7z a a1.7z a.bin -m0=lzma

-

-With filter for little-endian ARM code:

-  7z a a2.7z a.bin -m0=arm -m1=lzma        

-

-It works in such manner:

-Compressing    = Filter_encoding + LZMA_encoding

-Decompressing  = LZMA_decoding + Filter_decoding

-

-Compressing and decompressing speed of such filters is very high,

-so it will not increase decompressing time too much.

-Moreover, it reduces decompression time for LZMA_decoding, 

-since compression ratio with filtering is higher.

-

-These filters convert CALL (calling procedure) instructions 

-from relative offsets to absolute addresses, so such data becomes more 

-compressible.

-

-For some ISAs (for example, for MIPS) it's impossible to get gain from such filter.

-

-

-

----

-

-http://www.7-zip.org

-http://www.7-zip.org/sdk.html

-http://www.7-zip.org/support.html

diff --git a/DOC/lzma-specification.txt b/DOC/lzma-specification.txt
deleted file mode 100644
index b6796df..0000000
--- a/DOC/lzma-specification.txt
+++ /dev/null
@@ -1,1176 +0,0 @@
-LZMA specification (DRAFT version)

-----------------------------------

-

-Author: Igor Pavlov

-Date: 2015-06-14

-

-This specification defines the format of LZMA compressed data and lzma file format.

-

-Notation 

---------

-

-We use the syntax of C++ programming language.

-We use the following types in C++ code:

-  unsigned - unsigned integer, at least 16 bits in size

-  int      - signed integer, at least 16 bits in size

-  UInt64   - 64-bit unsigned integer

-  UInt32   - 32-bit unsigned integer

-  UInt16   - 16-bit unsigned integer

-  Byte     - 8-bit unsigned integer

-  bool     - boolean type with two possible values: false, true

-

-

-lzma file format

-================

-

-The lzma file contains the raw LZMA stream and the header with related properties.

-

-The files in that format use ".lzma" extension.

-

-The lzma file format layout:

-

-Offset Size Description

-

-  0     1   LZMA model properties (lc, lp, pb) in encoded form

-  1     4   Dictionary size (32-bit unsigned integer, little-endian)

-  5     8   Uncompressed size (64-bit unsigned integer, little-endian)

- 13         Compressed data (LZMA stream)

-

-LZMA properties:

-

-    name  Range          Description

-

-      lc  [0, 8]         the number of "literal context" bits

-      lp  [0, 4]         the number of "literal pos" bits

-      pb  [0, 4]         the number of "pos" bits

-dictSize  [0, 2^32 - 1]  the dictionary size 

-

-The following code encodes LZMA properties:

-

-void EncodeProperties(Byte *properties)

-{

-  properties[0] = (Byte)((pb * 5 + lp) * 9 + lc);

-  Set_UInt32_LittleEndian(properties + 1, dictSize);

-}

-

-If the value of dictionary size in properties is smaller than (1 << 12),

-the LZMA decoder must set the dictionary size variable to (1 << 12).

-

-#define LZMA_DIC_MIN (1 << 12)

-

-  unsigned lc, pb, lp;

-  UInt32 dictSize;

-  UInt32 dictSizeInProperties;

-

-  void DecodeProperties(const Byte *properties)

-  {

-    unsigned d = properties[0];

-    if (d >= (9 * 5 * 5))

-      throw "Incorrect LZMA properties";

-    lc = d % 9;

-    d /= 9;

-    pb = d / 5;

-    lp = d % 5;

-    dictSizeInProperties = 0;

-    for (int i = 0; i < 4; i++)

-      dictSizeInProperties |= (UInt32)properties[i + 1] << (8 * i);

-    dictSize = dictSizeInProperties;

-    if (dictSize < LZMA_DIC_MIN)

-      dictSize = LZMA_DIC_MIN;

-  }

-

-If "Uncompressed size" field contains ones in all 64 bits, it means that

-uncompressed size is unknown and there is the "end marker" in stream,

-that indicates the end of decoding point.

-In opposite case, if the value from "Uncompressed size" field is not

-equal to ((2^64) - 1), the LZMA stream decoding must be finished after

-specified number of bytes (Uncompressed size) is decoded. And if there 

-is the "end marker", the LZMA decoder must read that marker also.

-

-

-The new scheme to encode LZMA properties

-----------------------------------------

-

-If LZMA compression is used for some another format, it's recommended to

-use a new improved scheme to encode LZMA properties. That new scheme was

-used in xz format that uses the LZMA2 compression algorithm.

-The LZMA2 is a new compression algorithm that is based on the LZMA algorithm.

-

-The dictionary size in LZMA2 is encoded with just one byte and LZMA2 supports

-only reduced set of dictionary sizes:

-  (2 << 11), (3 << 11),

-  (2 << 12), (3 << 12),

-  ...

-  (2 << 30), (3 << 30),

-  (2 << 31) - 1

-

-The dictionary size can be extracted from encoded value with the following code:

-

-  dictSize = (p == 40) ? 0xFFFFFFFF : (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11));

-

-Also there is additional limitation (lc + lp <= 4) in LZMA2 for values of 

-"lc" and "lp" properties:

-

-  if (lc + lp > 4)

-    throw "Unsupported properties: (lc + lp) > 4";

-

-There are some advantages for LZMA decoder with such (lc + lp) value

-limitation. It reduces the maximum size of tables allocated by decoder.

-And it reduces the complexity of initialization procedure, that can be 

-important to keep high speed of decoding of big number of small LZMA streams.

-

-It's recommended to use that limitation (lc + lp <= 4) for any new format

-that uses LZMA compression. Note that the combinations of "lc" and "lp" 

-parameters, where (lc + lp > 4), can provide significant improvement in 

-compression ratio only in some rare cases.

-

-The LZMA properties can be encoded into two bytes in new scheme:

-

-Offset Size Description

-

-  0     1   The dictionary size encoded with LZMA2 scheme

-  1     1   LZMA model properties (lc, lp, pb) in encoded form

-

-

-The RAM usage 

-=============

-

-The RAM usage for LZMA decoder is determined by the following parts:

-

-1) The Sliding Window (from 4 KiB to 4 GiB).

-2) The probability model counter arrays (arrays of 16-bit variables).

-3) Some additional state variables (about 10 variables of 32-bit integers).

-

-

-The RAM usage for Sliding Window

---------------------------------

-

-There are two main scenarios of decoding:

-

-1) The decoding of full stream to one RAM buffer.

-

-  If we decode full LZMA stream to one output buffer in RAM, the decoder 

-  can use that output buffer as sliding window. So the decoder doesn't 

-  need additional buffer allocated for sliding window.

-

-2) The decoding to some external storage.

-

-  If we decode LZMA stream to external storage, the decoder must allocate

-  the buffer for sliding window. The size of that buffer must be equal 

-  or larger than the value of dictionary size from properties of LZMA stream.

-

-In this specification we describe the code for decoding to some external

-storage. The optimized version of code for decoding of full stream to one

-output RAM buffer can require some minor changes in code.

-

-

-The RAM usage for the probability model counters

-------------------------------------------------

-

-The size of the probability model counter arrays is calculated with the 

-following formula:

-

-size_of_prob_arrays = 1846 + 768 * (1 << (lp + lc))

-

-Each probability model counter is 11-bit unsigned integer.

-If we use 16-bit integer variables (2-byte integers) for these probability 

-model counters, the RAM usage required by probability model counter arrays 

-can be estimated with the following formula:

-

-  RAM = 4 KiB + 1.5 KiB * (1 << (lp + lc))

-

-For example, for default LZMA parameters (lp = 0 and lc = 3), the RAM usage is

-

-  RAM_lc3_lp0 = 4 KiB + 1.5 KiB * 8 = 16 KiB

-

-The maximum RAM state usage is required for decoding the stream with lp = 4 

-and lc = 8:

-

-  RAM_lc8_lp4 = 4 KiB + 1.5 KiB * 4096 = 6148 KiB

-

-If the decoder uses LZMA2's limited property condition 

-(lc + lp <= 4), the RAM usage will be not larger than

-

-  RAM_lc_lp_4 = 4 KiB + 1.5 KiB * 16 = 28 KiB

-

-

-The RAM usage for encoder

--------------------------

-

-There are many variants for LZMA encoding code.

-These variants have different values for memory consumption.

-Note that memory consumption for LZMA Encoder can not be 

-smaller than memory consumption of LZMA Decoder for same stream.

-

-The RAM usage required by modern effective implementation of 

-LZMA Encoder can be estimated with the following formula:

-

-  Encoder_RAM_Usage = 4 MiB + 11 * dictionarySize.

-

-But there are some modes of the encoder that require less memory.

-

-

-LZMA Decoding

-=============

-

-The LZMA compression algorithm uses LZ-based compression with Sliding Window

-and Range Encoding as entropy coding method.

-

-

-Sliding Window

---------------

-

-LZMA uses Sliding Window compression similar to LZ77 algorithm.

-

-LZMA stream must be decoded to the sequence that consists

-of MATCHES and LITERALS:

-  

-  - a LITERAL is a 8-bit character (one byte).

-    The decoder just puts that LITERAL to the uncompressed stream.

-  

-  - a MATCH is a pair of two numbers (DISTANCE-LENGTH pair).

-    The decoder takes one byte exactly "DISTANCE" characters behind

-    current position in the uncompressed stream and puts it to 

-    uncompressed stream. The decoder must repeat it "LENGTH" times.

-

-The "DISTANCE" can not be larger than dictionary size.

-And the "DISTANCE" can not be larger than the number of bytes in

-the uncompressed stream that were decoded before that match.

-

-In this specification we use cyclic buffer to implement Sliding Window

-for LZMA decoder:

-

-class COutWindow

-{

-  Byte *Buf;

-  UInt32 Pos;

-  UInt32 Size;

-  bool IsFull;

-

-public:

-  unsigned TotalPos;

-  COutStream OutStream;

-

-  COutWindow(): Buf(NULL) {}

-  ~COutWindow() { delete []Buf; }

- 

-  void Create(UInt32 dictSize)

-  {

-    Buf = new Byte[dictSize];

-    Pos = 0;

-    Size = dictSize;

-    IsFull = false;

-    TotalPos = 0;

-  }

-

-  void PutByte(Byte b)

-  {

-    TotalPos++;

-    Buf[Pos++] = b;

-    if (Pos == Size)

-    {

-      Pos = 0;

-      IsFull = true;

-    }

-    OutStream.WriteByte(b);

-  }

-

-  Byte GetByte(UInt32 dist) const

-  {

-    return Buf[dist <= Pos ? Pos - dist : Size - dist + Pos];

-  }

-

-  void CopyMatch(UInt32 dist, unsigned len)

-  {

-    for (; len > 0; len--)

-      PutByte(GetByte(dist));

-  }

-

-  bool CheckDistance(UInt32 dist) const

-  {

-    return dist <= Pos || IsFull;

-  }

-

-  bool IsEmpty() const

-  {

-    return Pos == 0 && !IsFull;

-  }

-};

-

-

-In another implementation it's possible to use one buffer that contains 

-Sliding Window and the whole data stream after uncompressing.

-

-

-Range Decoder

--------------

-

-LZMA algorithm uses Range Encoding (1) as entropy coding method.

-

-LZMA stream contains just one very big number in big-endian encoding.

-LZMA decoder uses the Range Decoder to extract a sequence of binary

-symbols from that big number.

-

-The state of the Range Decoder:

-

-struct CRangeDecoder

-{

-  UInt32 Range; 

-  UInt32 Code;

-  InputStream *InStream;

-

-  bool Corrupted;

-}

-

-The notes about UInt32 type for the "Range" and "Code" variables:

-

-  It's possible to use 64-bit (unsigned or signed) integer type

-  for the "Range" and the "Code" variables instead of 32-bit unsigned,

-  but some additional code must be used to truncate the values to 

-  low 32-bits after some operations.

-

-  If the programming language does not support 32-bit unsigned integer type 

-  (like in case of JAVA language), it's possible to use 32-bit signed integer, 

-  but some code must be changed. For example, it's required to change the code

-  that uses comparison operations for UInt32 variables in this specification.

-

-The Range Decoder can be in some states that can be treated as 

-"Corruption" in LZMA stream. The Range Decoder uses the variable "Corrupted":

-

-  (Corrupted == false), if the Range Decoder has not detected any corruption.

-  (Corrupted == true), if the Range Decoder has detected some corruption.

-

-The reference LZMA Decoder ignores the value of the "Corrupted" variable.

-So it continues to decode the stream, even if the corruption can be detected

-in the Range Decoder. To provide the full compatibility with output of the 

-reference LZMA Decoder, another LZMA Decoder implementations must also 

-ignore the value of the "Corrupted" variable.

-

-The LZMA Encoder is required to create only such LZMA streams, that will not 

-lead the Range Decoder to states, where the "Corrupted" variable is set to true.

-

-The Range Decoder reads first 5 bytes from input stream to initialize

-the state:

-

-bool CRangeDecoder::Init()

-{

-  Corrupted = false;

-  Range = 0xFFFFFFFF;

-  Code = 0;

-

-  Byte b = InStream->ReadByte();

-  

-  for (int i = 0; i < 4; i++)

-    Code = (Code << 8) | InStream->ReadByte();

-  

-  if (b != 0 || Code == Range)

-    Corrupted = true;

-  return b == 0;

-}

-

-The LZMA Encoder always writes ZERO in initial byte of compressed stream.

-That scheme allows to simplify the code of the Range Encoder in the 

-LZMA Encoder. If initial byte is not equal to ZERO, the LZMA Decoder must

-stop decoding and report error.

-

-After the last bit of data was decoded by Range Decoder, the value of the

-"Code" variable must be equal to 0. The LZMA Decoder must check it by 

-calling the IsFinishedOK() function:

-

-  bool IsFinishedOK() const { return Code == 0; }

-

-If there is corruption in data stream, there is big probability that

-the "Code" value will be not equal to 0 in the Finish() function. So that

-check in the IsFinishedOK() function provides very good feature for 

-corruption detection.

-

-The value of the "Range" variable before each bit decoding can not be smaller 

-than ((UInt32)1 << 24). The Normalize() function keeps the "Range" value in 

-described range.

-

-#define kTopValue ((UInt32)1 << 24)

-

-void CRangeDecoder::Normalize()

-{

-  if (Range < kTopValue)

-  {

-    Range <<= 8;

-    Code = (Code << 8) | InStream->ReadByte();

-  }

-}

-

-Notes: if the size of the "Code" variable is larger than 32 bits, it's

-required to keep only low 32 bits of the "Code" variable after the change

-in Normalize() function.

-

-If the LZMA Stream is not corrupted, the value of the "Code" variable is

-always smaller than value of the "Range" variable.

-But the Range Decoder ignores some types of corruptions, so the value of

-the "Code" variable can be equal or larger than value of the "Range" variable

-for some "Corrupted" archives.

-

-

-LZMA uses Range Encoding only with binary symbols of two types:

-  1) binary symbols with fixed and equal probabilities (direct bits)

-  2) binary symbols with predicted probabilities

-

-The DecodeDirectBits() function decodes the sequence of direct bits:

-

-UInt32 CRangeDecoder::DecodeDirectBits(unsigned numBits)

-{

-  UInt32 res = 0;

-  do

-  {

-    Range >>= 1;

-    Code -= Range;

-    UInt32 t = 0 - ((UInt32)Code >> 31);

-    Code += Range & t;

-    

-    if (Code == Range)

-      Corrupted = true;

-    

-    Normalize();

-    res <<= 1;

-    res += t + 1;

-  }

-  while (--numBits);

-  return res;

-}

-

-

-The Bit Decoding with Probability Model

----------------------------------------

-

-The task of Bit Probability Model is to estimate probabilities of binary

-symbols. And then it provides the Range Decoder with that information.

-The better prediction provides better compression ratio.

-The Bit Probability Model uses statistical data of previous decoded

-symbols.

-

-That estimated probability is presented as 11-bit unsigned integer value

-that represents the probability of symbol "0".

-

-#define kNumBitModelTotalBits 11

-

-Mathematical probabilities can be presented with the following formulas:

-     probability(symbol_0) = prob / 2048.

-     probability(symbol_1) =  1 - Probability(symbol_0) =  

-                           =  1 - prob / 2048 =  

-                           =  (2048 - prob) / 2048

-where the "prob" variable contains 11-bit integer probability counter.

-

-It's recommended to use 16-bit unsigned integer type, to store these 11-bit

-probability values:

-

-typedef UInt16 CProb;

-

-Each probability value must be initialized with value ((1 << 11) / 2),

-that represents the state, where probabilities of symbols 0 and 1 

-are equal to 0.5:

-

-#define PROB_INIT_VAL ((1 << kNumBitModelTotalBits) / 2)

-

-The INIT_PROBS macro is used to initialize the array of CProb variables:

-

-#define INIT_PROBS(p) \

- { for (unsigned i = 0; i < sizeof(p) / sizeof(p[0]); i++) p[i] = PROB_INIT_VAL; }

-

-

-The DecodeBit() function decodes one bit.

-The LZMA decoder provides the pointer to CProb variable that contains 

-information about estimated probability for symbol 0 and the Range Decoder 

-updates that CProb variable after decoding. The Range Decoder increases 

-estimated probability of the symbol that was decoded:

-

-#define kNumMoveBits 5

-

-unsigned CRangeDecoder::DecodeBit(CProb *prob)

-{

-  unsigned v = *prob;

-  UInt32 bound = (Range >> kNumBitModelTotalBits) * v;

-  unsigned symbol;

-  if (Code < bound)

-  {

-    v += ((1 << kNumBitModelTotalBits) - v) >> kNumMoveBits;

-    Range = bound;

-    symbol = 0;

-  }

-  else

-  {

-    v -= v >> kNumMoveBits;

-    Code -= bound;

-    Range -= bound;

-    symbol = 1;

-  }

-  *prob = (CProb)v;

-  Normalize();

-  return symbol;

-}

-

-

-The Binary Tree of bit model counters

--------------------------------------

-

-LZMA uses a tree of Bit model variables to decode symbol that needs

-several bits for storing. There are two versions of such trees in LZMA:

-  1) the tree that decodes bits from high bit to low bit (the normal scheme).

-  2) the tree that decodes bits from low bit to high bit (the reverse scheme).

-

-Each binary tree structure supports different size of decoded symbol

-(the size of binary sequence that contains value of symbol).

-If that size of decoded symbol is "NumBits" bits, the tree structure 

-uses the array of (2 << NumBits) counters of CProb type. 

-But only ((2 << NumBits) - 1) items are used by encoder and decoder.

-The first item (the item with index equal to 0) in array is unused.

-That scheme with unused array's item allows to simplify the code.

-

-unsigned BitTreeReverseDecode(CProb *probs, unsigned numBits, CRangeDecoder *rc)

-{

-  unsigned m = 1;

-  unsigned symbol = 0;

-  for (unsigned i = 0; i < numBits; i++)

-  {

-    unsigned bit = rc->DecodeBit(&probs[m]);

-    m <<= 1;

-    m += bit;

-    symbol |= (bit << i);

-  }

-  return symbol;

-}

-

-template <unsigned NumBits>

-class CBitTreeDecoder

-{

-  CProb Probs[(unsigned)1 << NumBits];

-

-public:

-

-  void Init()

-  {

-    INIT_PROBS(Probs);

-  }

-

-  unsigned Decode(CRangeDecoder *rc)

-  {

-    unsigned m = 1;

-    for (unsigned i = 0; i < NumBits; i++)

-      m = (m << 1) + rc->DecodeBit(&Probs[m]);

-    return m - ((unsigned)1 << NumBits);

-  }

-

-  unsigned ReverseDecode(CRangeDecoder *rc)

-  {

-    return BitTreeReverseDecode(Probs, NumBits, rc);

-  }

-};

-

-

-LZ part of LZMA 

----------------

-

-LZ part of LZMA describes details about the decoding of MATCHES and LITERALS.

-

-

-The Literal Decoding

---------------------

-

-The LZMA Decoder uses (1 << (lc + lp)) tables with CProb values, where 

-each table contains 0x300 CProb values:

-

-  CProb *LitProbs;

-

-  void CreateLiterals()

-  {

-    LitProbs = new CProb[(UInt32)0x300 << (lc + lp)];

-  }

-  

-  void InitLiterals()

-  {

-    UInt32 num = (UInt32)0x300 << (lc + lp);

-    for (UInt32 i = 0; i < num; i++)

-      LitProbs[i] = PROB_INIT_VAL;

-  }

-

-To select the table for decoding it uses the context that consists of

-(lc) high bits from previous literal and (lp) low bits from value that

-represents current position in outputStream.

-

-If (State > 7), the Literal Decoder also uses "matchByte" that represents 

-the byte in OutputStream at position the is the DISTANCE bytes before 

-current position, where the DISTANCE is the distance in DISTANCE-LENGTH pair

-of latest decoded match.

-

-The following code decodes one literal and puts it to Sliding Window buffer:

-

-  void DecodeLiteral(unsigned state, UInt32 rep0)

-  {

-    unsigned prevByte = 0;

-    if (!OutWindow.IsEmpty())

-      prevByte = OutWindow.GetByte(1);

-    

-    unsigned symbol = 1;

-    unsigned litState = ((OutWindow.TotalPos & ((1 << lp) - 1)) << lc) + (prevByte >> (8 - lc));

-    CProb *probs = &LitProbs[(UInt32)0x300 * litState];

-    

-    if (state >= 7)

-    {

-      unsigned matchByte = OutWindow.GetByte(rep0 + 1);

-      do

-      {

-        unsigned matchBit = (matchByte >> 7) & 1;

-        matchByte <<= 1;

-        unsigned bit = RangeDec.DecodeBit(&probs[((1 + matchBit) << 8) + symbol]);

-        symbol = (symbol << 1) | bit;

-        if (matchBit != bit)

-          break;

-      }

-      while (symbol < 0x100);

-    }

-    while (symbol < 0x100)

-      symbol = (symbol << 1) | RangeDec.DecodeBit(&probs[symbol]);

-    OutWindow.PutByte((Byte)(symbol - 0x100));

-  }

-

-

-The match length decoding

--------------------------

-

-The match length decoder returns normalized (zero-based value) 

-length of match. That value can be converted to real length of the match 

-with the following code:

-

-#define kMatchMinLen 2

-

-    matchLen = len + kMatchMinLen;

-

-The match length decoder can return the values from 0 to 271.

-And the corresponded real match length values can be in the range 

-from 2 to 273.

-

-The following scheme is used for the match length encoding:

-

-  Binary encoding    Binary Tree structure    Zero-based match length 

-  sequence                                    (binary + decimal):

-

-  0 xxx              LowCoder[posState]       xxx

-  1 0 yyy            MidCoder[posState]       yyy + 8

-  1 1 zzzzzzzz       HighCoder                zzzzzzzz + 16

-

-LZMA uses bit model variable "Choice" to decode the first selection bit.

-

-If the first selection bit is equal to 0, the decoder uses binary tree 

-  LowCoder[posState] to decode 3-bit zero-based match length (xxx).

-

-If the first selection bit is equal to 1, the decoder uses bit model 

-  variable "Choice2" to decode the second selection bit.

-

-  If the second selection bit is equal to 0, the decoder uses binary tree 

-    MidCoder[posState] to decode 3-bit "yyy" value, and zero-based match

-    length is equal to (yyy + 8).

-

-  If the second selection bit is equal to 1, the decoder uses binary tree 

-    HighCoder to decode 8-bit "zzzzzzzz" value, and zero-based 

-    match length is equal to (zzzzzzzz + 16).

-

-LZMA uses "posState" value as context to select the binary tree 

-from LowCoder and MidCoder binary tree arrays:

-

-    unsigned posState = OutWindow.TotalPos & ((1 << pb) - 1);

-

-The full code of the length decoder:

-

-class CLenDecoder

-{

-  CProb Choice;

-  CProb Choice2;

-  CBitTreeDecoder<3> LowCoder[1 << kNumPosBitsMax];

-  CBitTreeDecoder<3> MidCoder[1 << kNumPosBitsMax];

-  CBitTreeDecoder<8> HighCoder;

-

-public:

-

-  void Init()

-  {

-    Choice = PROB_INIT_VAL;

-    Choice2 = PROB_INIT_VAL;

-    HighCoder.Init();

-    for (unsigned i = 0; i < (1 << kNumPosBitsMax); i++)

-    {

-      LowCoder[i].Init();

-      MidCoder[i].Init();

-    }

-  }

-

-  unsigned Decode(CRangeDecoder *rc, unsigned posState)

-  {

-    if (rc->DecodeBit(&Choice) == 0)

-      return LowCoder[posState].Decode(rc);

-    if (rc->DecodeBit(&Choice2) == 0)

-      return 8 + MidCoder[posState].Decode(rc);

-    return 16 + HighCoder.Decode(rc);

-  }

-};

-

-The LZMA decoder uses two instances of CLenDecoder class.

-The first instance is for the matches of "Simple Match" type,

-and the second instance is for the matches of "Rep Match" type:

-

-  CLenDecoder LenDecoder;

-  CLenDecoder RepLenDecoder;

-

-

-The match distance decoding

----------------------------

-

-LZMA supports dictionary sizes up to 4 GiB minus 1.

-The value of match distance (decoded by distance decoder) can be 

-from 1 to 2^32. But the distance value that is equal to 2^32 is used to

-indicate the "End of stream" marker. So real largest match distance 

-that is used for LZ-window match is (2^32 - 1).

-

-LZMA uses normalized match length (zero-based length) 

-to calculate the context state "lenState" do decode the distance value:

-

-#define kNumLenToPosStates 4

-

-    unsigned lenState = len;

-    if (lenState > kNumLenToPosStates - 1)

-      lenState = kNumLenToPosStates - 1;

-

-The distance decoder returns the "dist" value that is zero-based value 

-of match distance. The real match distance can be calculated with the

-following code:

-  

-  matchDistance = dist + 1; 

-

-The state of the distance decoder and the initialization code: 

-

-  #define kEndPosModelIndex 14

-  #define kNumFullDistances (1 << (kEndPosModelIndex >> 1))

-  #define kNumAlignBits 4

-

-  CBitTreeDecoder<6> PosSlotDecoder[kNumLenToPosStates];

-  CProb PosDecoders[1 + kNumFullDistances - kEndPosModelIndex];

-  CBitTreeDecoder<kNumAlignBits> AlignDecoder;

-

-  void InitDist()

-  {

-    for (unsigned i = 0; i < kNumLenToPosStates; i++)

-      PosSlotDecoder[i].Init();

-    AlignDecoder.Init();

-    INIT_PROBS(PosDecoders);

-  }

-

-At first stage the distance decoder decodes 6-bit "posSlot" value with bit

-tree decoder from PosSlotDecoder array. It's possible to get 2^6=64 different 

-"posSlot" values.

-

-    unsigned posSlot = PosSlotDecoder[lenState].Decode(&RangeDec);

-

-The encoding scheme for distance value is shown in the following table:

-

-posSlot (decimal) /

-      zero-based distance (binary)

- 0    0

- 1    1

- 2    10

- 3    11

-

- 4    10 x

- 5    11 x

- 6    10 xx

- 7    11 xx

- 8    10 xxx

- 9    11 xxx

-10    10 xxxx

-11    11 xxxx

-12    10 xxxxx

-13    11 xxxxx

-

-14    10 yy zzzz

-15    11 yy zzzz

-16    10 yyy zzzz

-17    11 yyy zzzz

-...

-62    10 yyyyyyyyyyyyyyyyyyyyyyyyyy zzzz

-63    11 yyyyyyyyyyyyyyyyyyyyyyyyyy zzzz

-

-where 

-  "x ... x" means the sequence of binary symbols encoded with binary tree and 

-      "Reverse" scheme. It uses separated binary tree for each posSlot from 4 to 13.

-  "y" means direct bit encoded with range coder.

-  "zzzz" means the sequence of four binary symbols encoded with binary

-      tree with "Reverse" scheme, where one common binary tree "AlignDecoder"

-      is used for all posSlot values.

-

-If (posSlot < 4), the "dist" value is equal to posSlot value.

-

-If (posSlot >= 4), the decoder uses "posSlot" value to calculate the value of

-  the high bits of "dist" value and the number of the low bits.

-

-  If (4 <= posSlot < kEndPosModelIndex), the decoder uses bit tree decoders.

-    (one separated bit tree decoder per one posSlot value) and "Reverse" scheme.

-    In this implementation we use one CProb array "PosDecoders" that contains 

-    all CProb variables for all these bit decoders.

-  

-  if (posSlot >= kEndPosModelIndex), the middle bits are decoded as direct 

-    bits from RangeDecoder and the low 4 bits are decoded with a bit tree 

-    decoder "AlignDecoder" with "Reverse" scheme.

-

-The code to decode zero-based match distance:

-  

-  unsigned DecodeDistance(unsigned len)

-  {

-    unsigned lenState = len;

-    if (lenState > kNumLenToPosStates - 1)

-      lenState = kNumLenToPosStates - 1;

-    

-    unsigned posSlot = PosSlotDecoder[lenState].Decode(&RangeDec);

-    if (posSlot < 4)

-      return posSlot;

-    

-    unsigned numDirectBits = (unsigned)((posSlot >> 1) - 1);

-    UInt32 dist = ((2 | (posSlot & 1)) << numDirectBits);

-    if (posSlot < kEndPosModelIndex)

-      dist += BitTreeReverseDecode(PosDecoders + dist - posSlot, numDirectBits, &RangeDec);

-    else

-    {

-      dist += RangeDec.DecodeDirectBits(numDirectBits - kNumAlignBits) << kNumAlignBits;

-      dist += AlignDecoder.ReverseDecode(&RangeDec);

-    }

-    return dist;

-  }

-

-

-

-LZMA Decoding modes

--------------------

-

-There are 2 types of LZMA streams:

-

-1) The stream with "End of stream" marker.

-2) The stream without "End of stream" marker.

-

-And the LZMA Decoder supports 3 modes of decoding:

-

-1) The unpack size is undefined. The LZMA decoder stops decoding after 

-   getting "End of stream" marker. 

-   The input variables for that case:

-    

-      markerIsMandatory = true

-      unpackSizeDefined = false

-      unpackSize contains any value

-

-2) The unpack size is defined and LZMA decoder supports both variants, 

-   where the stream can contain "End of stream" marker or the stream is

-   finished without "End of stream" marker. The LZMA decoder must detect 

-   any of these situations.

-   The input variables for that case:

-    

-      markerIsMandatory = false

-      unpackSizeDefined = true

-      unpackSize contains unpack size

-

-3) The unpack size is defined and the LZMA stream must contain 

-   "End of stream" marker

-   The input variables for that case:

-    

-      markerIsMandatory = true

-      unpackSizeDefined = true

-      unpackSize contains unpack size

-

-

-The main loop of decoder

-------------------------

-

-The main loop of LZMA decoder:

-

-Initialize the LZMA state.

-loop

-{

-  // begin of loop

-  Check "end of stream" conditions.

-  Decode Type of MATCH / LITERAL. 

-    If it's LITERAL, decode LITERAL value and put the LITERAL to Window.

-    If it's MATCH, decode the length of match and the match distance. 

-        Check error conditions, check end of stream conditions and copy

-        the sequence of match bytes from sliding window to current position

-        in window.

-  Go to begin of loop

-}

-

-The reference implementation of LZMA decoder uses "unpackSize" variable

-to keep the number of remaining bytes in output stream. So it reduces 

-"unpackSize" value after each decoded LITERAL or MATCH.

-

-The following code contains the "end of stream" condition check at the start

-of the loop:

-

-    if (unpackSizeDefined && unpackSize == 0 && !markerIsMandatory)

-      if (RangeDec.IsFinishedOK())

-        return LZMA_RES_FINISHED_WITHOUT_MARKER;

-

-LZMA uses three types of matches:

-

-1) "Simple Match" -     the match with distance value encoded with bit models.

-

-2) "Rep Match" -        the match that uses the distance from distance

-                        history table.

-

-3) "Short Rep Match" -  the match of single byte length, that uses the latest 

-                        distance from distance history table.

-

-The LZMA decoder keeps the history of latest 4 match distances that were used 

-by decoder. That set of 4 variables contains zero-based match distances and 

-these variables are initialized with zero values:

-

-  UInt32 rep0 = 0, rep1 = 0, rep2 = 0, rep3 = 0;

-

-The LZMA decoder uses binary model variables to select type of MATCH or LITERAL:

-

-#define kNumStates 12

-#define kNumPosBitsMax 4

-

-  CProb IsMatch[kNumStates << kNumPosBitsMax];

-  CProb IsRep[kNumStates];

-  CProb IsRepG0[kNumStates];

-  CProb IsRepG1[kNumStates];

-  CProb IsRepG2[kNumStates];

-  CProb IsRep0Long[kNumStates << kNumPosBitsMax];

-

-The decoder uses "state" variable value to select exact variable 

-from "IsRep", "IsRepG0", "IsRepG1" and "IsRepG2" arrays.

-The "state" variable can get the value from 0 to 11.

-Initial value for "state" variable is zero:

-

-  unsigned state = 0;

-

-The "state" variable is updated after each LITERAL or MATCH with one of the

-following functions:

-

-unsigned UpdateState_Literal(unsigned state)

-{

-  if (state < 4) return 0;

-  else if (state < 10) return state - 3;

-  else return state - 6;

-}

-unsigned UpdateState_Match   (unsigned state) { return state < 7 ? 7 : 10; }

-unsigned UpdateState_Rep     (unsigned state) { return state < 7 ? 8 : 11; }

-unsigned UpdateState_ShortRep(unsigned state) { return state < 7 ? 9 : 11; }

-

-The decoder calculates "state2" variable value to select exact variable from 

-"IsMatch" and "IsRep0Long" arrays:

-

-unsigned posState = OutWindow.TotalPos & ((1 << pb) - 1);

-unsigned state2 = (state << kNumPosBitsMax) + posState;

-

-The decoder uses the following code flow scheme to select exact 

-type of LITERAL or MATCH:

-

-IsMatch[state2] decode

-  0 - the Literal

-  1 - the Match

-    IsRep[state] decode

-      0 - Simple Match

-      1 - Rep Match

-        IsRepG0[state] decode

-          0 - the distance is rep0

-            IsRep0Long[state2] decode

-              0 - Short Rep Match

-              1 - Rep Match 0

-          1 - 

-            IsRepG1[state] decode

-              0 - Rep Match 1

-              1 - 

-                IsRepG2[state] decode

-                  0 - Rep Match 2

-                  1 - Rep Match 3

-

-

-LITERAL symbol

---------------

-If the value "0" was decoded with IsMatch[state2] decoding, we have "LITERAL" type.

-

-At first the LZMA decoder must check that it doesn't exceed 

-specified uncompressed size:

-

-      if (unpackSizeDefined && unpackSize == 0)

-        return LZMA_RES_ERROR;

-

-Then it decodes literal value and puts it to sliding window:

-

-      DecodeLiteral(state, rep0);

-

-Then the decoder must update the "state" value and "unpackSize" value;

-

-      state = UpdateState_Literal(state);

-      unpackSize--;

-

-Then the decoder must go to the begin of main loop to decode next Match or Literal.

-

-

-Simple Match

-------------

-

-If the value "1" was decoded with IsMatch[state2] decoding,

-we have the "Simple Match" type.

-

-The distance history table is updated with the following scheme:

-    

-      rep3 = rep2;

-      rep2 = rep1;

-      rep1 = rep0;

-

-The zero-based length is decoded with "LenDecoder":

-

-      len = LenDecoder.Decode(&RangeDec, posState);

-

-The state is update with UpdateState_Match function:

-

-      state = UpdateState_Match(state);

-

-and the new "rep0" value is decoded with DecodeDistance:

-

-      rep0 = DecodeDistance(len);

-

-That "rep0" will be used as zero-based distance for current match.

-

-If the value of "rep0" is equal to 0xFFFFFFFF, it means that we have 

-"End of stream" marker, so we can stop decoding and check finishing 

-condition in Range Decoder:

-

-      if (rep0 == 0xFFFFFFFF)

-        return RangeDec.IsFinishedOK() ?

-            LZMA_RES_FINISHED_WITH_MARKER :

-            LZMA_RES_ERROR;

-

-If uncompressed size is defined, LZMA decoder must check that it doesn't 

-exceed that specified uncompressed size:

-

-      if (unpackSizeDefined && unpackSize == 0)

-        return LZMA_RES_ERROR;

-

-Also the decoder must check that "rep0" value is not larger than dictionary size

-and is not larger than the number of already decoded bytes:

-

-      if (rep0 >= dictSize || !OutWindow.CheckDistance(rep0))

-        return LZMA_RES_ERROR;

-

-Then the decoder must copy match bytes as described in 

-"The match symbols copying" section.

-

-

-Rep Match

----------

-

-If the LZMA decoder has decoded the value "1" with IsRep[state] variable,

-we have "Rep Match" type.

-

-At first the LZMA decoder must check that it doesn't exceed 

-specified uncompressed size:

-

-      if (unpackSizeDefined && unpackSize == 0)

-        return LZMA_RES_ERROR;

-

-Also the decoder must return error, if the LZ window is empty:

-

-      if (OutWindow.IsEmpty())

-        return LZMA_RES_ERROR;

-

-If the match type is "Rep Match", the decoder uses one of the 4 variables of

-distance history table to get the value of distance for current match.

-And there are 4 corresponding ways of decoding flow. 

-

-The decoder updates the distance history with the following scheme 

-depending from type of match:

-

-- "Rep Match 0" or "Short Rep Match":

-      ; LZMA doesn't update the distance history    

-

-- "Rep Match 1":

-      UInt32 dist = rep1;

-      rep1 = rep0;

-      rep0 = dist;

-

-- "Rep Match 2":

-      UInt32 dist = rep2;

-      rep2 = rep1;

-      rep1 = rep0;

-      rep0 = dist;

-

-- "Rep Match 3":

-      UInt32 dist = rep3;

-      rep3 = rep2;

-      rep2 = rep1;

-      rep1 = rep0;

-      rep0 = dist;

-

-Then the decoder decodes exact subtype of "Rep Match" using "IsRepG0", "IsRep0Long",

-"IsRepG1", "IsRepG2".

-

-If the subtype is "Short Rep Match", the decoder updates the state, puts 

-the one byte from window to current position in window and goes to next 

-MATCH/LITERAL symbol (the begin of main loop):

-

-          state = UpdateState_ShortRep(state);

-          OutWindow.PutByte(OutWindow.GetByte(rep0 + 1));

-          unpackSize--;

-          continue;

-

-In other cases (Rep Match 0/1/2/3), it decodes the zero-based 

-length of match with "RepLenDecoder" decoder:

-

-      len = RepLenDecoder.Decode(&RangeDec, posState);

-

-Then it updates the state:

-

-      state = UpdateState_Rep(state);

-

-Then the decoder must copy match bytes as described in 

-"The Match symbols copying" section.

-

-

-The match symbols copying

--------------------------

-

-If we have the match (Simple Match or Rep Match 0/1/2/3), the decoder must

-copy the sequence of bytes with calculated match distance and match length.

-If uncompressed size is defined, LZMA decoder must check that it doesn't 

-exceed that specified uncompressed size:

-

-    len += kMatchMinLen;

-    bool isError = false;

-    if (unpackSizeDefined && unpackSize < len)

-    {

-      len = (unsigned)unpackSize;

-      isError = true;

-    }

-    OutWindow.CopyMatch(rep0 + 1, len);

-    unpackSize -= len;

-    if (isError)

-      return LZMA_RES_ERROR;

-

-Then the decoder must go to the begin of main loop to decode next MATCH or LITERAL.

-

-

-

-NOTES

------

-

-This specification doesn't describe the variant of decoder implementation 

-that supports partial decoding. Such partial decoding case can require some 

-changes in "end of stream" condition checks code. Also such code 

-can use additional status codes, returned by decoder.

-

-This specification uses C++ code with templates to simplify describing.

-The optimized version of LZMA decoder doesn't need templates.

-Such optimized version can use just two arrays of CProb variables:

-  1) The dynamic array of CProb variables allocated for the Literal Decoder.

-  2) The one common array that contains all other CProb variables.

-

-

-References:      

-

-1. G. N. N. Martin, Range encoding: an algorithm for removing redundancy 

-   from a digitized message, Video & Data Recording Conference, 

-   Southampton, UK, July 24-27, 1979.

diff --git a/DOC/lzma.txt b/DOC/lzma.txt
index 1f92142..142feb1 100644
--- a/DOC/lzma.txt
+++ b/DOC/lzma.txt
@@ -1,328 +1,345 @@
-LZMA compression

-----------------

-Version: 9.35

-

-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	

-  LzmaEnc.h

-  LzmaEnc.c

-  LzFind.h

-  LzFind.c

-  LzFindMt.h

-  LzFindMt.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

--------

-

-_LZMA_SIZE_OPT - Enable some optimizations in LZMA Decoder to get smaller executable code.

-

-_LZMA_PROB32   - It can increase the speed on some 32-bit CPUs, but memory usage for 

-                 some structures will be doubled in that case.

-

-_LZMA_UINT32_IS_ULONG  - Define it if int is 16-bit on your compiler and long is 32-bit.

-

-_LZMA_NO_SYSTEM_SIZE_T  - Define it if you don't want to use size_t type.

-

-

-_7ZIP_PPMD_SUPPPORT - Define it if you don't want to support PPMD method in AMSI-C .7z decoder.

-

-

-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 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:

-operator new(size_t size)

-{

-  void *p = ::malloc(size);

-  if (p == 0)

-    throw CNewException();

-  return p;

-}

-If you use MSCV that throws exception for "new" operator, you can compile without 

-"NewHandler.cpp". So standard exception will be used. Actually 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: 23.01
+
+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
new file mode 100644
index 0000000..5cd90c5
--- /dev/null
+++ b/DOC/readme.txt
@@ -0,0 +1,273 @@
+7-Zip 23.01 Sources
+-------------------
+
+7-Zip is a file archiver for Windows. 
+
+7-Zip Copyright (C) 1999-2023 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
diff --git a/DOC/src-history.txt b/DOC/src-history.txt
new file mode 100644
index 0000000..c1c1b71
--- /dev/null
+++ b/DOC/src-history.txt
@@ -0,0 +1,709 @@
+HISTORY of the 7-Zip source code
+--------------------------------
+
+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<ISequentialInStream> 
+  OutBuffer.h: COutBuffer uses ISequentialOutStream *_stream; instead of CMyComPtr<ISequentialOutStream> 
+	
+
+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.
+
diff --git a/DOC/unRarLicense.txt b/DOC/unRarLicense.txt
new file mode 100644
index 0000000..5f78b72
--- /dev/null
+++ b/DOC/unRarLicense.txt
@@ -0,0 +1,41 @@
+ ******    *****   ******   unRAR - free utility for RAR archives
+ **   **  **   **  **   **  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ******   *******  ******    License for use and distribution of
+ **   **  **   **  **   **   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ **   **  **   **  **   **         FREE portable version
+                                   ~~~~~~~~~~~~~~~~~~~~~
+
+      The source code of unRAR utility is freeware. This means:
+
+   1. All copyrights to RAR and the utility unRAR are exclusively
+      owned by the author - Alexander Roshal.
+
+   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.
+
+   3. The unRAR utility may be freely distributed. No person or company 
+      may charge a fee for the distribution of unRAR without written
+      permission from the copyright holder.
+
+   4. THE RAR ARCHIVER AND THE UNRAR UTILITY ARE DISTRIBUTED "AS IS".
+      NO WARRANTY OF ANY KIND IS EXPRESSED OR IMPLIED.  YOU USE AT 
+      YOUR OWN RISK. THE AUTHOR WILL NOT BE LIABLE FOR DATA LOSS, 
+      DAMAGES, LOSS OF PROFITS OR ANY OTHER KIND OF LOSS WHILE USING
+      OR MISUSING THIS SOFTWARE.
+
+   5. Installing and using the unRAR utility signifies acceptance of
+      these terms and conditions of the license.
+
+   6. If you don't agree with terms of the license you must remove
+      unRAR files from your storage devices and cease to use the
+      utility.
+
+      Thank you for your interest in RAR and unRAR.
+
+
+                                            Alexander L. Roshal
\ No newline at end of file
diff --git a/Java/SevenZip/CRC.java b/Java/SevenZip/CRC.java
deleted file mode 100644
index f2f791f..0000000
--- a/Java/SevenZip/CRC.java
+++ /dev/null
@@ -1,52 +0,0 @@
-// SevenZip/CRC.java

-

-package SevenZip;

-

-public class CRC

-{

-	static public int[] Table = new int[256];

-	

-	static

-	{

-		for (int i = 0; i < 256; i++)

-		{

-			int r = i;

-			for (int j = 0; j < 8; j++)

-				if ((r & 1) != 0)

-					r = (r >>> 1) ^ 0xEDB88320;

-				else

-					r >>>= 1;

-			Table[i] = r;

-		}

-	}

-	

-	int _value = -1;

-	

-	public void Init()

-	{

-		_value = -1;

-	}

-	

-	public void Update(byte[] data, int offset, int size)

-	{

-		for (int i = 0; i < size; i++)

-			_value = Table[(_value ^ data[offset + i]) & 0xFF] ^ (_value >>> 8);

-	}

-	

-	public void Update(byte[] data)

-	{

-		int size = data.length;

-		for (int i = 0; i < size; i++)

-			_value = Table[(_value ^ data[i]) & 0xFF] ^ (_value >>> 8);

-	}

-	

-	public void UpdateByte(int b)

-	{

-		_value = Table[(_value ^ b) & 0xFF] ^ (_value >>> 8);

-	}

-	

-	public int GetDigest()

-	{

-		return _value ^ (-1);

-	}

-}

diff --git a/Java/SevenZip/Compression/LZ/BinTree.java b/Java/SevenZip/Compression/LZ/BinTree.java
deleted file mode 100644
index 63d58c0..0000000
--- a/Java/SevenZip/Compression/LZ/BinTree.java
+++ /dev/null
@@ -1,382 +0,0 @@
-// LZ.BinTree

-

-package SevenZip.Compression.LZ;

-import java.io.IOException;

-

-

-public class BinTree extends InWindow

-{

-	int _cyclicBufferPos;

-	int _cyclicBufferSize = 0;

-	int _matchMaxLen;

-	

-	int[] _son;

-	int[] _hash;

-	

-	int _cutValue = 0xFF;

-	int _hashMask;

-	int _hashSizeSum = 0;

-	

-	boolean HASH_ARRAY = true;

-

-	static final int kHash2Size = 1 << 10;

-	static final int kHash3Size = 1 << 16;

-	static final int kBT2HashSize = 1 << 16;

-	static final int kStartMaxLen = 1;

-	static final int kHash3Offset = kHash2Size;

-	static final int kEmptyHashValue = 0;

-	static final int kMaxValForNormalize = (1 << 30) - 1;

-	

-	int kNumHashDirectBytes = 0;

-	int kMinMatchCheck = 4;

-	int kFixHashSize = kHash2Size + kHash3Size;

-

-	public void SetType(int numHashBytes)

-	{

-		HASH_ARRAY = (numHashBytes > 2);

-		if (HASH_ARRAY)

-		{

-			kNumHashDirectBytes = 0;

-			kMinMatchCheck = 4;

-			kFixHashSize = kHash2Size + kHash3Size;

-		}

-		else

-		{

-			kNumHashDirectBytes = 2;

-			kMinMatchCheck = 2 + 1;

-			kFixHashSize = 0;

-		}

-	}

-	

-

-	

-

-	public void Init() throws IOException

-	{

-		super.Init();

-		for (int i = 0; i < _hashSizeSum; i++)

-			_hash[i] = kEmptyHashValue;

-		_cyclicBufferPos = 0;

-		ReduceOffsets(-1);

-	}

-	

-	public void MovePos() throws IOException

-	{

-		if (++_cyclicBufferPos >= _cyclicBufferSize)

-			_cyclicBufferPos = 0;

-		super.MovePos();

-		if (_pos == kMaxValForNormalize)

-			Normalize();

-	}

-	

-

-	

-	

-	

-	

-	

-	

-	public boolean Create(int historySize, int keepAddBufferBefore,

-			int matchMaxLen, int keepAddBufferAfter)

-	{

-		if (historySize > kMaxValForNormalize - 256)

-			return false;

-		_cutValue = 16 + (matchMaxLen >> 1);

-

-		int windowReservSize = (historySize + keepAddBufferBefore +

-				matchMaxLen + keepAddBufferAfter) / 2 + 256;

-		

-		super.Create(historySize + keepAddBufferBefore, matchMaxLen + keepAddBufferAfter, windowReservSize);

-		

-		_matchMaxLen = matchMaxLen;

-

-		int cyclicBufferSize = historySize + 1;

-		if (_cyclicBufferSize != cyclicBufferSize)

-			_son = new int[(_cyclicBufferSize = cyclicBufferSize) * 2];

-

-		int hs = kBT2HashSize;

-

-		if (HASH_ARRAY)

-		{

-			hs = historySize - 1;

-			hs |= (hs >> 1);

-			hs |= (hs >> 2);

-			hs |= (hs >> 4);

-			hs |= (hs >> 8);

-			hs >>= 1;

-			hs |= 0xFFFF;

-			if (hs > (1 << 24))

-				hs >>= 1;

-			_hashMask = hs;

-			hs++;

-			hs += kFixHashSize;

-		}

-		if (hs != _hashSizeSum)

-			_hash = new int [_hashSizeSum = hs];

-		return true;

-	}

-	public int GetMatches(int[] distances) throws IOException

-	{

-		int lenLimit;

-		if (_pos + _matchMaxLen <= _streamPos)

-			lenLimit = _matchMaxLen;

-		else

-		{

-			lenLimit = _streamPos - _pos;

-			if (lenLimit < kMinMatchCheck)

-			{

-				MovePos();

-				return 0;

-			}

-		}

-

-		int offset = 0;

-		int matchMinPos = (_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0;

-		int cur = _bufferOffset + _pos;

-		int maxLen = kStartMaxLen; // to avoid items for len < hashSize;

-		int hashValue, hash2Value = 0, hash3Value = 0;

-		

-		if (HASH_ARRAY)

-		{

-			int temp = CrcTable[_bufferBase[cur] & 0xFF] ^ (_bufferBase[cur + 1] & 0xFF);

-			hash2Value = temp & (kHash2Size - 1);

-			temp ^= ((int)(_bufferBase[cur + 2] & 0xFF) << 8);

-			hash3Value = temp & (kHash3Size - 1);

-			hashValue = (temp ^ (CrcTable[_bufferBase[cur + 3] & 0xFF] << 5)) & _hashMask;

-		}

-		else

-			hashValue = ((_bufferBase[cur] & 0xFF) ^ ((int)(_bufferBase[cur + 1] & 0xFF) << 8));

-

-		int curMatch = _hash[kFixHashSize + hashValue];

-		if (HASH_ARRAY)

-		{

-			int curMatch2 = _hash[hash2Value];

-			int curMatch3 = _hash[kHash3Offset + hash3Value];

-			_hash[hash2Value] = _pos;

-			_hash[kHash3Offset + hash3Value] = _pos;

-			if (curMatch2 > matchMinPos)

-				if (_bufferBase[_bufferOffset + curMatch2] == _bufferBase[cur])

-				{

-					distances[offset++] = maxLen = 2;

-					distances[offset++] = _pos - curMatch2 - 1;

-				}

-			if (curMatch3 > matchMinPos)

-				if (_bufferBase[_bufferOffset + curMatch3] == _bufferBase[cur])

-				{

-					if (curMatch3 == curMatch2)

-						offset -= 2;

-					distances[offset++] = maxLen = 3;

-					distances[offset++] = _pos - curMatch3 - 1;

-					curMatch2 = curMatch3;

-				}

-			if (offset != 0 && curMatch2 == curMatch)

-			{

-				offset -= 2;

-				maxLen = kStartMaxLen;

-			}

-		}

-

-		_hash[kFixHashSize + hashValue] = _pos;

-

-		int ptr0 = (_cyclicBufferPos << 1) + 1;

-		int ptr1 = (_cyclicBufferPos << 1);

-

-		int len0, len1;

-		len0 = len1 = kNumHashDirectBytes;

-

-		if (kNumHashDirectBytes != 0)

-		{

-			if (curMatch > matchMinPos)

-			{

-				if (_bufferBase[_bufferOffset + curMatch + kNumHashDirectBytes] !=

-						_bufferBase[cur + kNumHashDirectBytes])

-				{

-					distances[offset++] = maxLen = kNumHashDirectBytes;

-					distances[offset++] = _pos - curMatch - 1;

-				}

-			}

-		}

-

-		int count = _cutValue;

-

-		while (true)

-		{

-			if (curMatch <= matchMinPos || count-- == 0)

-			{

-				_son[ptr0] = _son[ptr1] = kEmptyHashValue;

-				break;

-			}

-			int delta = _pos - curMatch;

-			int cyclicPos = ((delta <= _cyclicBufferPos) ?

-				(_cyclicBufferPos - delta) :

-				(_cyclicBufferPos - delta + _cyclicBufferSize)) << 1;

-

-			int pby1 = _bufferOffset + curMatch;

-			int len = Math.min(len0, len1);

-			if (_bufferBase[pby1 + len] == _bufferBase[cur + len])

-			{

-				while(++len != lenLimit)

-					if (_bufferBase[pby1 + len] != _bufferBase[cur + len])

-						break;

-				if (maxLen < len)

-				{

-					distances[offset++] = maxLen = len;

-					distances[offset++] = delta - 1;

-					if (len == lenLimit)

-					{

-						_son[ptr1] = _son[cyclicPos];

-						_son[ptr0] = _son[cyclicPos + 1];

-						break;

-					}

-				}

-			}

-			if ((_bufferBase[pby1 + len] & 0xFF) < (_bufferBase[cur + len] & 0xFF))

-			{

-				_son[ptr1] = curMatch;

-				ptr1 = cyclicPos + 1;

-				curMatch = _son[ptr1];

-				len1 = len;

-			}

-			else

-			{

-				_son[ptr0] = curMatch;

-				ptr0 = cyclicPos;

-				curMatch = _son[ptr0];

-				len0 = len;

-			}

-		}

-		MovePos();

-		return offset;

-	}

-

-	public void Skip(int num) throws IOException

-	{

-		do

-		{

-			int lenLimit;

-			if (_pos + _matchMaxLen <= _streamPos)

-			lenLimit = _matchMaxLen;

-			else

-			{

-				lenLimit = _streamPos - _pos;

-				if (lenLimit < kMinMatchCheck)

-				{

-					MovePos();

-					continue;

-				}

-			}

-

-			int matchMinPos = (_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0;

-			int cur = _bufferOffset + _pos;

-			

-			int hashValue;

-

-			if (HASH_ARRAY)

-			{

-				int temp = CrcTable[_bufferBase[cur] & 0xFF] ^ (_bufferBase[cur + 1] & 0xFF);

-				int hash2Value = temp & (kHash2Size - 1);

-				_hash[hash2Value] = _pos;

-				temp ^= ((int)(_bufferBase[cur + 2] & 0xFF) << 8);

-				int hash3Value = temp & (kHash3Size - 1);

-				_hash[kHash3Offset + hash3Value] = _pos;

-				hashValue = (temp ^ (CrcTable[_bufferBase[cur + 3] & 0xFF] << 5)) & _hashMask;

-			}

-			else

-				hashValue = ((_bufferBase[cur] & 0xFF) ^ ((int)(_bufferBase[cur + 1] & 0xFF) << 8));

-

-			int curMatch = _hash[kFixHashSize + hashValue];

-			_hash[kFixHashSize + hashValue] = _pos;

-

-			int ptr0 = (_cyclicBufferPos << 1) + 1;

-			int ptr1 = (_cyclicBufferPos << 1);

-

-			int len0, len1;

-			len0 = len1 = kNumHashDirectBytes;

-

-			int count = _cutValue;

-			while (true)

-			{

-				if (curMatch <= matchMinPos || count-- == 0)

-				{

-					_son[ptr0] = _son[ptr1] = kEmptyHashValue;

-					break;

-				}

-

-				int delta = _pos - curMatch;

-				int cyclicPos = ((delta <= _cyclicBufferPos) ?

-					(_cyclicBufferPos - delta) :

-					(_cyclicBufferPos - delta + _cyclicBufferSize)) << 1;

-

-				int pby1 = _bufferOffset + curMatch;

-				int len = Math.min(len0, len1);

-				if (_bufferBase[pby1 + len] == _bufferBase[cur + len])

-				{

-					while (++len != lenLimit)

-						if (_bufferBase[pby1 + len] != _bufferBase[cur + len])

-							break;

-					if (len == lenLimit)

-					{

-						_son[ptr1] = _son[cyclicPos];

-						_son[ptr0] = _son[cyclicPos + 1];

-						break;

-					}

-				}

-				if ((_bufferBase[pby1 + len] & 0xFF) < (_bufferBase[cur + len] & 0xFF))

-				{

-					_son[ptr1] = curMatch;

-					ptr1 = cyclicPos + 1;

-					curMatch = _son[ptr1];

-					len1 = len;

-				}

-				else

-				{

-					_son[ptr0] = curMatch;

-					ptr0 = cyclicPos;

-					curMatch = _son[ptr0];

-					len0 = len;

-				}

-			}

-			MovePos();

-		}

-		while (--num != 0);

-	}

-	

-	void NormalizeLinks(int[] items, int numItems, int subValue)

-	{

-		for (int i = 0; i < numItems; i++)

-		{

-			int value = items[i];

-			if (value <= subValue)

-				value = kEmptyHashValue;

-			else

-				value -= subValue;

-			items[i] = value;

-		}

-	}

-	

-	void Normalize()

-	{

-		int subValue = _pos - _cyclicBufferSize;

-		NormalizeLinks(_son, _cyclicBufferSize * 2, subValue);

-		NormalizeLinks(_hash, _hashSizeSum, subValue);

-		ReduceOffsets(subValue);

-	}

-	

-	public void SetCutValue(int cutValue) { _cutValue = cutValue; }

-

-	private static final int[] CrcTable = new int[256];

-

-	static

-	{

-		for (int i = 0; i < 256; i++)

-		{

-			int r = i;

-			for (int j = 0; j < 8; j++)

-				if ((r & 1) != 0)

-					r = (r >>> 1) ^ 0xEDB88320;

-				else

-					r >>>= 1;

-			CrcTable[i] = r;

-		}

-	}

-}

diff --git a/Java/SevenZip/Compression/LZ/InWindow.java b/Java/SevenZip/Compression/LZ/InWindow.java
deleted file mode 100644
index 5f3f0b4..0000000
--- a/Java/SevenZip/Compression/LZ/InWindow.java
+++ /dev/null
@@ -1,131 +0,0 @@
-// LZ.InWindow

-

-package SevenZip.Compression.LZ;

-

-import java.io.IOException;

-

-public class InWindow

-{

-	public byte[] _bufferBase; // pointer to buffer with data

-	java.io.InputStream _stream;

-	int _posLimit;  // offset (from _buffer) of first byte when new block reading must be done

-	boolean _streamEndWasReached; // if (true) then _streamPos shows real end of stream

-	

-	int _pointerToLastSafePosition;

-	

-	public int _bufferOffset;

-	

-	public int _blockSize;  // Size of Allocated memory block

-	public int _pos;             // offset (from _buffer) of curent byte

-	int _keepSizeBefore;  // how many BYTEs must be kept in buffer before _pos

-	int _keepSizeAfter;   // how many BYTEs must be kept buffer after _pos

-	public int _streamPos;   // offset (from _buffer) of first not read byte from Stream

-	

-	public void MoveBlock()

-	{

-		int offset = _bufferOffset + _pos - _keepSizeBefore;

-		// we need one additional byte, since MovePos moves on 1 byte.

-		if (offset > 0)

-			offset--;

-

-		int numBytes = _bufferOffset + _streamPos - offset;

-		

-		// check negative offset ????

-		for (int i = 0; i < numBytes; i++)

-			_bufferBase[i] = _bufferBase[offset + i];

-		_bufferOffset -= offset;

-	}

-	

-	public void ReadBlock() throws IOException

-	{

-		if (_streamEndWasReached)

-			return;

-		while (true)

-		{

-			int size = (0 - _bufferOffset) + _blockSize - _streamPos;

-			if (size == 0)

-				return;

-			int numReadBytes = _stream.read(_bufferBase, _bufferOffset + _streamPos, size);

-			if (numReadBytes == -1)

-			{

-				_posLimit = _streamPos;

-				int pointerToPostion = _bufferOffset + _posLimit;

-				if (pointerToPostion > _pointerToLastSafePosition)

-					_posLimit = _pointerToLastSafePosition - _bufferOffset;

-				

-				_streamEndWasReached = true;

-				return;

-			}

-			_streamPos += numReadBytes;

-			if (_streamPos >= _pos + _keepSizeAfter)

-				_posLimit = _streamPos - _keepSizeAfter;

-		}

-	}

-	

-	void Free() { _bufferBase = null; }

-	

-	public void Create(int keepSizeBefore, int keepSizeAfter, int keepSizeReserv)

-	{

-		_keepSizeBefore = keepSizeBefore;

-		_keepSizeAfter = keepSizeAfter;

-		int blockSize = keepSizeBefore + keepSizeAfter + keepSizeReserv;

-		if (_bufferBase == null || _blockSize != blockSize)

-		{

-			Free();

-			_blockSize = blockSize;

-			_bufferBase = new byte[_blockSize];

-		}

-		_pointerToLastSafePosition = _blockSize - keepSizeAfter;

-	}

-	

-	public void SetStream(java.io.InputStream stream) { _stream = stream; 	}

-	public void ReleaseStream() { _stream = null; }

-

-	public void Init() throws IOException

-	{

-		_bufferOffset = 0;

-		_pos = 0;

-		_streamPos = 0;

-		_streamEndWasReached = false;

-		ReadBlock();

-	}

-	

-	public void MovePos() throws IOException

-	{

-		_pos++;

-		if (_pos > _posLimit)

-		{

-			int pointerToPostion = _bufferOffset + _pos;

-			if (pointerToPostion > _pointerToLastSafePosition)

-				MoveBlock();

-			ReadBlock();

-		}

-	}

-	

-	public byte GetIndexByte(int index)	{ return _bufferBase[_bufferOffset + _pos + index]; }

-	

-	// index + limit have not to exceed _keepSizeAfter;

-	public int GetMatchLen(int index, int distance, int limit)

-	{

-		if (_streamEndWasReached)

-			if ((_pos + index) + limit > _streamPos)

-				limit = _streamPos - (_pos + index);

-		distance++;

-		// Byte *pby = _buffer + (size_t)_pos + index;

-		int pby = _bufferOffset + _pos + index;

-		

-		int i;

-		for (i = 0; i < limit && _bufferBase[pby + i] == _bufferBase[pby + i - distance]; i++);

-		return i;

-	}

-	

-	public int GetNumAvailableBytes()	{ return _streamPos - _pos; }

-	

-	public void ReduceOffsets(int subValue)

-	{

-		_bufferOffset += subValue;

-		_posLimit -= subValue;

-		_pos -= subValue;

-		_streamPos -= subValue;

-	}

-}

diff --git a/Java/SevenZip/Compression/LZ/OutWindow.java b/Java/SevenZip/Compression/LZ/OutWindow.java
deleted file mode 100644
index 620cb41..0000000
--- a/Java/SevenZip/Compression/LZ/OutWindow.java
+++ /dev/null
@@ -1,85 +0,0 @@
-// LZ.OutWindow

-

-package SevenZip.Compression.LZ;

-

-import java.io.IOException;

-

-public class OutWindow

-{

-	byte[] _buffer;

-	int _pos;

-	int _windowSize = 0;

-	int _streamPos;

-	java.io.OutputStream _stream;

-	

-	public void Create(int windowSize)

-	{

-		if (_buffer == null || _windowSize != windowSize)

-			_buffer = new byte[windowSize];

-		_windowSize = windowSize;

-		_pos = 0;

-		_streamPos = 0;

-	}

-	

-	public void SetStream(java.io.OutputStream stream) throws IOException

-	{

-		ReleaseStream();

-		_stream = stream;

-	}

-	

-	public void ReleaseStream() throws IOException

-	{

-		Flush();

-		_stream = null;

-	}

-	

-	public void Init(boolean solid)

-	{

-		if (!solid)

-		{

-			_streamPos = 0;

-			_pos = 0;

-		}

-	}

-	

-	public void Flush() throws IOException

-	{

-		int size = _pos - _streamPos;

-		if (size == 0)

-			return;

-		_stream.write(_buffer, _streamPos, size);

-		if (_pos >= _windowSize)

-			_pos = 0;

-		_streamPos = _pos;

-	}

-	

-	public void CopyBlock(int distance, int len) throws IOException

-	{

-		int pos = _pos - distance - 1;

-		if (pos < 0)

-			pos += _windowSize;

-		for (; len != 0; len--)

-		{

-			if (pos >= _windowSize)

-				pos = 0;

-			_buffer[_pos++] = _buffer[pos++];

-			if (_pos >= _windowSize)

-				Flush();

-		}

-	}

-	

-	public void PutByte(byte b) throws IOException

-	{

-		_buffer[_pos++] = b;

-		if (_pos >= _windowSize)

-			Flush();

-	}

-	

-	public byte GetByte(int distance)

-	{

-		int pos = _pos - distance - 1;

-		if (pos < 0)

-			pos += _windowSize;

-		return _buffer[pos];

-	}

-}

diff --git a/Java/SevenZip/Compression/LZMA/Base.java b/Java/SevenZip/Compression/LZMA/Base.java
deleted file mode 100644
index 18deed9..0000000
--- a/Java/SevenZip/Compression/LZMA/Base.java
+++ /dev/null
@@ -1,88 +0,0 @@
-// Base.java

-

-package SevenZip.Compression.LZMA;

-

-public class Base

-{

-	public static final int kNumRepDistances = 4;

-	public static final int kNumStates = 12;

-	

-	public static final int StateInit()

-	{

-		return 0;

-	}

-	

-	public static final int StateUpdateChar(int index)

-	{

-		if (index < 4) 

-			return 0;

-		if (index < 10) 

-			return index - 3;

-		return index - 6;

-	}

-	

-	public static final int StateUpdateMatch(int index)

-	{

-		return (index < 7 ? 7 : 10); 

-	}

-

-	public static final int StateUpdateRep(int index)

-	{ 

-		return (index < 7 ? 8 : 11); 

-	}

-	

-	public static final int StateUpdateShortRep(int index)

-	{ 

-		return (index < 7 ? 9 : 11); 

-	}

-

-	public static final boolean StateIsCharState(int index)

-	{ 

-		return index < 7; 

-	}

-	

-	public static final int kNumPosSlotBits = 6;

-	public static final int kDicLogSizeMin = 0;

-	// public static final int kDicLogSizeMax = 28;

-	// public static final int kDistTableSizeMax = kDicLogSizeMax * 2;

-	

-	public static final int kNumLenToPosStatesBits = 2; // it's for speed optimization

-	public static final int kNumLenToPosStates = 1 << kNumLenToPosStatesBits;

-	

-	public static final int kMatchMinLen = 2;

-	

-	public static final int GetLenToPosState(int len)

-	{

-		len -= kMatchMinLen;

-		if (len < kNumLenToPosStates)

-			return len;

-		return (int)(kNumLenToPosStates - 1);

-	}

-	

-	public static final int kNumAlignBits = 4;

-	public static final int kAlignTableSize = 1 << kNumAlignBits;

-	public static final int kAlignMask = (kAlignTableSize - 1);

-	

-	public static final int kStartPosModelIndex = 4;

-	public static final int kEndPosModelIndex = 14;

-	public static final int kNumPosModels = kEndPosModelIndex - kStartPosModelIndex;

-	

-	public static final  int kNumFullDistances = 1 << (kEndPosModelIndex / 2);

-	

-	public static final  int kNumLitPosStatesBitsEncodingMax = 4;

-	public static final  int kNumLitContextBitsMax = 8;

-	

-	public static final  int kNumPosStatesBitsMax = 4;

-	public static final  int kNumPosStatesMax = (1 << kNumPosStatesBitsMax);

-	public static final  int kNumPosStatesBitsEncodingMax = 4;

-	public static final  int kNumPosStatesEncodingMax = (1 << kNumPosStatesBitsEncodingMax);

-	

-	public static final  int kNumLowLenBits = 3;

-	public static final  int kNumMidLenBits = 3;

-	public static final  int kNumHighLenBits = 8;

-	public static final  int kNumLowLenSymbols = 1 << kNumLowLenBits;

-	public static final  int kNumMidLenSymbols = 1 << kNumMidLenBits;

-	public static final  int kNumLenSymbols = kNumLowLenSymbols + kNumMidLenSymbols +

-			(1 << kNumHighLenBits);

-	public static final  int kMatchMaxLen = kMatchMinLen + kNumLenSymbols - 1;

-}

diff --git a/Java/SevenZip/Compression/LZMA/Decoder.java b/Java/SevenZip/Compression/LZMA/Decoder.java
deleted file mode 100644
index 4ebd571..0000000
--- a/Java/SevenZip/Compression/LZMA/Decoder.java
+++ /dev/null
@@ -1,329 +0,0 @@
-package SevenZip.Compression.LZMA;

-

-import SevenZip.Compression.RangeCoder.BitTreeDecoder;

-import SevenZip.Compression.LZMA.Base;

-import SevenZip.Compression.LZ.OutWindow;

-import java.io.IOException;

-

-public class Decoder

-{

-	class LenDecoder

-	{

-		short[] m_Choice = new short[2];

-		BitTreeDecoder[] m_LowCoder = new BitTreeDecoder[Base.kNumPosStatesMax];

-		BitTreeDecoder[] m_MidCoder = new BitTreeDecoder[Base.kNumPosStatesMax];

-		BitTreeDecoder m_HighCoder = new BitTreeDecoder(Base.kNumHighLenBits);

-		int m_NumPosStates = 0;

-		

-		public void Create(int numPosStates)

-		{

-			for (; m_NumPosStates < numPosStates; m_NumPosStates++)

-			{

-				m_LowCoder[m_NumPosStates] = new BitTreeDecoder(Base.kNumLowLenBits);

-				m_MidCoder[m_NumPosStates] = new BitTreeDecoder(Base.kNumMidLenBits);

-			}

-		}

-		

-		public void Init()

-		{

-			SevenZip.Compression.RangeCoder.Decoder.InitBitModels(m_Choice);

-			for (int posState = 0; posState < m_NumPosStates; posState++)

-			{

-				m_LowCoder[posState].Init();

-				m_MidCoder[posState].Init();

-			}

-			m_HighCoder.Init();

-		}

-		

-		public int Decode(SevenZip.Compression.RangeCoder.Decoder rangeDecoder, int posState) throws IOException

-		{

-			if (rangeDecoder.DecodeBit(m_Choice, 0) == 0)

-				return m_LowCoder[posState].Decode(rangeDecoder);

-			int symbol = Base.kNumLowLenSymbols;

-			if (rangeDecoder.DecodeBit(m_Choice, 1) == 0)

-				symbol += m_MidCoder[posState].Decode(rangeDecoder);

-			else

-				symbol += Base.kNumMidLenSymbols + m_HighCoder.Decode(rangeDecoder);

-			return symbol;

-		}

-	}

-	

-	class LiteralDecoder

-	{

-		class Decoder2

-		{

-			short[] m_Decoders = new short[0x300];

-			

-			public void Init()

-			{

-				SevenZip.Compression.RangeCoder.Decoder.InitBitModels(m_Decoders);

-			}

-			

-			public byte DecodeNormal(SevenZip.Compression.RangeCoder.Decoder rangeDecoder) throws IOException

-			{

-				int symbol = 1;

-				do

-					symbol = (symbol << 1) | rangeDecoder.DecodeBit(m_Decoders, symbol);

-				while (symbol < 0x100);

-				return (byte)symbol;

-			}

-			

-			public byte DecodeWithMatchByte(SevenZip.Compression.RangeCoder.Decoder rangeDecoder, byte matchByte) throws IOException

-			{

-				int symbol = 1;

-				do

-				{

-					int matchBit = (matchByte >> 7) & 1;

-					matchByte <<= 1;

-					int bit = rangeDecoder.DecodeBit(m_Decoders, ((1 + matchBit) << 8) + symbol);

-					symbol = (symbol << 1) | bit;

-					if (matchBit != bit)

-					{

-						while (symbol < 0x100)

-							symbol = (symbol << 1) | rangeDecoder.DecodeBit(m_Decoders, symbol);

-						break;

-					}

-				}

-				while (symbol < 0x100);

-				return (byte)symbol;

-			}

-		}

-		

-		Decoder2[] m_Coders;

-		int m_NumPrevBits;

-		int m_NumPosBits;

-		int m_PosMask;

-		

-		public void Create(int numPosBits, int numPrevBits)

-		{

-			if (m_Coders != null && m_NumPrevBits == numPrevBits && m_NumPosBits == numPosBits)

-				return;

-			m_NumPosBits = numPosBits;

-			m_PosMask = (1 << numPosBits) - 1;

-			m_NumPrevBits = numPrevBits;

-			int numStates = 1 << (m_NumPrevBits + m_NumPosBits);

-			m_Coders = new Decoder2[numStates];

-			for (int i = 0; i < numStates; i++)

-				m_Coders[i] = new Decoder2();

-		}

-		

-		public void Init()

-		{

-			int numStates = 1 << (m_NumPrevBits + m_NumPosBits);

-			for (int i = 0; i < numStates; i++)

-				m_Coders[i].Init();

-		}

-		

-		Decoder2 GetDecoder(int pos, byte prevByte)

-		{

-			return m_Coders[((pos & m_PosMask) << m_NumPrevBits) + ((prevByte & 0xFF) >>> (8 - m_NumPrevBits))];

-		}

-	}

-	

-	OutWindow m_OutWindow = new OutWindow();

-	SevenZip.Compression.RangeCoder.Decoder m_RangeDecoder = new SevenZip.Compression.RangeCoder.Decoder();

-	

-	short[] m_IsMatchDecoders = new short[Base.kNumStates << Base.kNumPosStatesBitsMax];

-	short[] m_IsRepDecoders = new short[Base.kNumStates];

-	short[] m_IsRepG0Decoders = new short[Base.kNumStates];

-	short[] m_IsRepG1Decoders = new short[Base.kNumStates];

-	short[] m_IsRepG2Decoders = new short[Base.kNumStates];

-	short[] m_IsRep0LongDecoders = new short[Base.kNumStates << Base.kNumPosStatesBitsMax];

-	

-	BitTreeDecoder[] m_PosSlotDecoder = new BitTreeDecoder[Base.kNumLenToPosStates];

-	short[] m_PosDecoders = new short[Base.kNumFullDistances - Base.kEndPosModelIndex];

-	

-	BitTreeDecoder m_PosAlignDecoder = new BitTreeDecoder(Base.kNumAlignBits);

-	

-	LenDecoder m_LenDecoder = new LenDecoder();

-	LenDecoder m_RepLenDecoder = new LenDecoder();

-	

-	LiteralDecoder m_LiteralDecoder = new LiteralDecoder();

-	

-	int m_DictionarySize = -1;

-	int m_DictionarySizeCheck =  -1;

-	

-	int m_PosStateMask;

-	

-	public Decoder()

-	{

-		for (int i = 0; i < Base.kNumLenToPosStates; i++)

-			m_PosSlotDecoder[i] = new BitTreeDecoder(Base.kNumPosSlotBits);

-	}

-	

-	boolean SetDictionarySize(int dictionarySize)

-	{

-		if (dictionarySize < 0)

-			return false;

-		if (m_DictionarySize != dictionarySize)

-		{

-			m_DictionarySize = dictionarySize;

-			m_DictionarySizeCheck = Math.max(m_DictionarySize, 1);

-			m_OutWindow.Create(Math.max(m_DictionarySizeCheck, (1 << 12)));

-		}

-		return true;

-	}

-	

-	boolean SetLcLpPb(int lc, int lp, int pb)

-	{

-		if (lc > Base.kNumLitContextBitsMax || lp > 4 || pb > Base.kNumPosStatesBitsMax)

-			return false;

-		m_LiteralDecoder.Create(lp, lc);

-		int numPosStates = 1 << pb;

-		m_LenDecoder.Create(numPosStates);

-		m_RepLenDecoder.Create(numPosStates);

-		m_PosStateMask = numPosStates - 1;

-		return true;

-	}

-	

-	void Init() throws IOException

-	{

-		m_OutWindow.Init(false);

-		

-		SevenZip.Compression.RangeCoder.Decoder.InitBitModels(m_IsMatchDecoders);

-		SevenZip.Compression.RangeCoder.Decoder.InitBitModels(m_IsRep0LongDecoders);

-		SevenZip.Compression.RangeCoder.Decoder.InitBitModels(m_IsRepDecoders);

-		SevenZip.Compression.RangeCoder.Decoder.InitBitModels(m_IsRepG0Decoders);

-		SevenZip.Compression.RangeCoder.Decoder.InitBitModels(m_IsRepG1Decoders);

-		SevenZip.Compression.RangeCoder.Decoder.InitBitModels(m_IsRepG2Decoders);

-		SevenZip.Compression.RangeCoder.Decoder.InitBitModels(m_PosDecoders);

-		

-		m_LiteralDecoder.Init();

-		int i;

-		for (i = 0; i < Base.kNumLenToPosStates; i++)

-			m_PosSlotDecoder[i].Init();

-		m_LenDecoder.Init();

-		m_RepLenDecoder.Init();

-		m_PosAlignDecoder.Init();

-		m_RangeDecoder.Init();

-	}

-	

-	public boolean Code(java.io.InputStream inStream, java.io.OutputStream outStream,

-			long outSize) throws IOException

-	{

-		m_RangeDecoder.SetStream(inStream);

-		m_OutWindow.SetStream(outStream);

-		Init();

-		

-		int state = Base.StateInit();

-		int rep0 = 0, rep1 = 0, rep2 = 0, rep3 = 0;

-		

-		long nowPos64 = 0;

-		byte prevByte = 0;

-		while (outSize < 0 || nowPos64 < outSize)

-		{

-			int posState = (int)nowPos64 & m_PosStateMask;

-			if (m_RangeDecoder.DecodeBit(m_IsMatchDecoders, (state << Base.kNumPosStatesBitsMax) + posState) == 0)

-			{

-				LiteralDecoder.Decoder2 decoder2 = m_LiteralDecoder.GetDecoder((int)nowPos64, prevByte);

-				if (!Base.StateIsCharState(state))

-					prevByte = decoder2.DecodeWithMatchByte(m_RangeDecoder, m_OutWindow.GetByte(rep0));

-				else

-					prevByte = decoder2.DecodeNormal(m_RangeDecoder);

-				m_OutWindow.PutByte(prevByte);

-				state = Base.StateUpdateChar(state);

-				nowPos64++;

-			}

-			else

-			{

-				int len;

-				if (m_RangeDecoder.DecodeBit(m_IsRepDecoders, state) == 1)

-				{

-					len = 0;

-					if (m_RangeDecoder.DecodeBit(m_IsRepG0Decoders, state) == 0)

-					{

-						if (m_RangeDecoder.DecodeBit(m_IsRep0LongDecoders, (state << Base.kNumPosStatesBitsMax) + posState) == 0)

-						{

-							state = Base.StateUpdateShortRep(state);

-							len = 1;

-						}

-					}

-					else

-					{

-						int distance;

-						if (m_RangeDecoder.DecodeBit(m_IsRepG1Decoders, state) == 0)

-							distance = rep1;

-						else

-						{

-							if (m_RangeDecoder.DecodeBit(m_IsRepG2Decoders, state) == 0)

-								distance = rep2;

-							else

-							{

-								distance = rep3;

-								rep3 = rep2;

-							}

-							rep2 = rep1;

-						}

-						rep1 = rep0;

-						rep0 = distance;

-					}

-					if (len == 0)

-					{

-						len = m_RepLenDecoder.Decode(m_RangeDecoder, posState) + Base.kMatchMinLen;

-						state = Base.StateUpdateRep(state);

-					}

-				}

-				else

-				{

-					rep3 = rep2;

-					rep2 = rep1;

-					rep1 = rep0;

-					len = Base.kMatchMinLen + m_LenDecoder.Decode(m_RangeDecoder, posState);

-					state = Base.StateUpdateMatch(state);

-					int posSlot = m_PosSlotDecoder[Base.GetLenToPosState(len)].Decode(m_RangeDecoder);

-					if (posSlot >= Base.kStartPosModelIndex)

-					{

-						int numDirectBits = (posSlot >> 1) - 1;

-						rep0 = ((2 | (posSlot & 1)) << numDirectBits);

-						if (posSlot < Base.kEndPosModelIndex)

-							rep0 += BitTreeDecoder.ReverseDecode(m_PosDecoders,

-									rep0 - posSlot - 1, m_RangeDecoder, numDirectBits);

-						else

-						{

-							rep0 += (m_RangeDecoder.DecodeDirectBits(

-									numDirectBits - Base.kNumAlignBits) << Base.kNumAlignBits);

-							rep0 += m_PosAlignDecoder.ReverseDecode(m_RangeDecoder);

-							if (rep0 < 0)

-							{

-								if (rep0 == -1)

-									break;

-								return false;

-							}

-						}

-					}

-					else

-						rep0 = posSlot;

-				}

-				if (rep0 >= nowPos64 || rep0 >= m_DictionarySizeCheck)

-				{

-					// m_OutWindow.Flush();

-					return false;

-				}

-				m_OutWindow.CopyBlock(rep0, len);

-				nowPos64 += len;

-				prevByte = m_OutWindow.GetByte(0);

-			}

-		}

-		m_OutWindow.Flush();

-		m_OutWindow.ReleaseStream();

-		m_RangeDecoder.ReleaseStream();

-		return true;

-	}

-	

-	public boolean SetDecoderProperties(byte[] properties)

-	{

-		if (properties.length < 5)

-			return false;

-		int val = properties[0] & 0xFF;

-		int lc = val % 9;

-		int remainder = val / 9;

-		int lp = remainder % 5;

-		int pb = remainder / 5;

-		int dictionarySize = 0;

-		for (int i = 0; i < 4; i++)

-			dictionarySize += ((int)(properties[1 + i]) & 0xFF) << (i * 8);

-		if (!SetLcLpPb(lc, lp, pb))

-			return false;

-		return SetDictionarySize(dictionarySize);

-	}

-}

diff --git a/Java/SevenZip/Compression/LZMA/Encoder.java b/Java/SevenZip/Compression/LZMA/Encoder.java
deleted file mode 100644
index 771fb21..0000000
--- a/Java/SevenZip/Compression/LZMA/Encoder.java
+++ /dev/null
@@ -1,1416 +0,0 @@
-package SevenZip.Compression.LZMA;

-

-import SevenZip.Compression.RangeCoder.BitTreeEncoder;

-import SevenZip.Compression.LZMA.Base;

-import SevenZip.Compression.LZ.BinTree;

-import SevenZip.ICodeProgress;

-import java.io.IOException;

-

-public class Encoder

-{

-	public static final int EMatchFinderTypeBT2 = 0;

-	public static final int EMatchFinderTypeBT4 = 1;

-

-

-

-

-	static final int kIfinityPrice = 0xFFFFFFF;

-

-	static byte[] g_FastPos = new byte[1 << 11];

-

-	static

-	{

-		int kFastSlots = 22;

-		int c = 2;

-		g_FastPos[0] = 0;

-		g_FastPos[1] = 1;

-		for (int slotFast = 2; slotFast < kFastSlots; slotFast++)

-		{

-			int k = (1 << ((slotFast >> 1) - 1));

-			for (int j = 0; j < k; j++, c++)

-				g_FastPos[c] = (byte)slotFast;

-		}

-	}

-

-	static int GetPosSlot(int pos)

-	{

-		if (pos < (1 << 11))

-			return g_FastPos[pos];

-		if (pos < (1 << 21))

-			return (g_FastPos[pos >> 10] + 20);

-		return (g_FastPos[pos >> 20] + 40);

-	}

-

-	static int GetPosSlot2(int pos)

-	{

-		if (pos < (1 << 17))

-			return (g_FastPos[pos >> 6] + 12);

-		if (pos < (1 << 27))

-			return (g_FastPos[pos >> 16] + 32);

-		return (g_FastPos[pos >> 26] + 52);

-	}

-

-	int _state = Base.StateInit();

-	byte _previousByte;

-	int[] _repDistances = new int[Base.kNumRepDistances];

-

-	void BaseInit()

-	{

-		_state = Base.StateInit();

-		_previousByte = 0;

-		for (int i = 0; i < Base.kNumRepDistances; i++)

-			_repDistances[i] = 0;

-	}

-

-	static final int kDefaultDictionaryLogSize = 22;

-	static final int kNumFastBytesDefault = 0x20;

-

-	class LiteralEncoder

-	{

-		class Encoder2

-		{

-			short[] m_Encoders = new short[0x300];

-

-			public void Init() { SevenZip.Compression.RangeCoder.Encoder.InitBitModels(m_Encoders); }

-

-

-

-			public void Encode(SevenZip.Compression.RangeCoder.Encoder rangeEncoder, byte symbol) throws IOException

-			{

-				int context = 1;

-				for (int i = 7; i >= 0; i--)

-				{

-					int bit = ((symbol >> i) & 1);

-					rangeEncoder.Encode(m_Encoders, context, bit);

-					context = (context << 1) | bit;

-				}

-			}

-

-			public void EncodeMatched(SevenZip.Compression.RangeCoder.Encoder rangeEncoder, byte matchByte, byte symbol) throws IOException

-			{

-				int context = 1;

-				boolean same = true;

-				for (int i = 7; i >= 0; i--)

-				{

-					int bit = ((symbol >> i) & 1);

-					int state = context;

-					if (same)

-					{

-						int matchBit = ((matchByte >> i) & 1);

-						state += ((1 + matchBit) << 8);

-						same = (matchBit == bit);

-					}

-					rangeEncoder.Encode(m_Encoders, state, bit);

-					context = (context << 1) | bit;

-				}

-			}

-

-			public int GetPrice(boolean matchMode, byte matchByte, byte symbol)

-			{

-				int price = 0;

-				int context = 1;

-				int i = 7;

-				if (matchMode)

-				{

-					for (; i >= 0; i--)

-					{

-						int matchBit = (matchByte >> i) & 1;

-						int bit = (symbol >> i) & 1;

-						price += SevenZip.Compression.RangeCoder.Encoder.GetPrice(m_Encoders[((1 + matchBit) << 8) + context], bit);

-						context = (context << 1) | bit;

-						if (matchBit != bit)

-						{

-							i--;

-							break;

-						}

-					}

-				}

-				for (; i >= 0; i--)

-				{

-					int bit = (symbol >> i) & 1;

-					price += SevenZip.Compression.RangeCoder.Encoder.GetPrice(m_Encoders[context], bit);

-					context = (context << 1) | bit;

-				}

-				return price;

-			}

-		}

-

-		Encoder2[] m_Coders;

-		int m_NumPrevBits;

-		int m_NumPosBits;

-		int m_PosMask;

-

-		public void Create(int numPosBits, int numPrevBits)

-		{

-			if (m_Coders != null && m_NumPrevBits == numPrevBits && m_NumPosBits == numPosBits)

-				return;

-			m_NumPosBits = numPosBits;

-			m_PosMask = (1 << numPosBits) - 1;

-			m_NumPrevBits = numPrevBits;

-			int numStates = 1 << (m_NumPrevBits + m_NumPosBits);

-			m_Coders = new Encoder2[numStates];

-			for (int i = 0; i < numStates; i++)

-				m_Coders[i] = new Encoder2();

-		}

-

-		public void Init()

-		{

-			int numStates = 1 << (m_NumPrevBits + m_NumPosBits);

-			for (int i = 0; i < numStates; i++)

-				m_Coders[i].Init();

-		}

-

-		public Encoder2 GetSubCoder(int pos, byte prevByte)

-		{ return m_Coders[((pos & m_PosMask) << m_NumPrevBits) + ((prevByte & 0xFF) >>> (8 - m_NumPrevBits))]; }

-	}

-

-	class LenEncoder

-	{

-		short[] _choice = new short[2];

-		BitTreeEncoder[] _lowCoder = new BitTreeEncoder[Base.kNumPosStatesEncodingMax];

-		BitTreeEncoder[] _midCoder = new BitTreeEncoder[Base.kNumPosStatesEncodingMax];

-		BitTreeEncoder _highCoder = new BitTreeEncoder(Base.kNumHighLenBits);

-

-

-		public LenEncoder()

-		{

-			for (int posState = 0; posState < Base.kNumPosStatesEncodingMax; posState++)

-			{

-				_lowCoder[posState] = new BitTreeEncoder(Base.kNumLowLenBits);

-				_midCoder[posState] = new BitTreeEncoder(Base.kNumMidLenBits);

-			}

-		}

-

-		public void Init(int numPosStates)

-		{

-			SevenZip.Compression.RangeCoder.Encoder.InitBitModels(_choice);

-

-			for (int posState = 0; posState < numPosStates; posState++)

-			{

-				_lowCoder[posState].Init();

-				_midCoder[posState].Init();

-			}

-			_highCoder.Init();

-		}

-

-		public void Encode(SevenZip.Compression.RangeCoder.Encoder rangeEncoder, int symbol, int posState) throws IOException

-		{

-			if (symbol < Base.kNumLowLenSymbols)

-			{

-				rangeEncoder.Encode(_choice, 0, 0);

-				_lowCoder[posState].Encode(rangeEncoder, symbol);

-			}

-			else

-			{

-				symbol -= Base.kNumLowLenSymbols;

-				rangeEncoder.Encode(_choice, 0, 1);

-				if (symbol < Base.kNumMidLenSymbols)

-				{

-					rangeEncoder.Encode(_choice, 1, 0);

-					_midCoder[posState].Encode(rangeEncoder, symbol);

-				}

-				else

-				{

-					rangeEncoder.Encode(_choice, 1, 1);

-					_highCoder.Encode(rangeEncoder, symbol - Base.kNumMidLenSymbols);

-				}

-			}

-		}

-

-		public void SetPrices(int posState, int numSymbols, int[] prices, int st)

-		{

-			int a0 = SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_choice[0]);

-			int a1 = SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_choice[0]);

-			int b0 = a1 + SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_choice[1]);

-			int b1 = a1 + SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_choice[1]);

-			int i = 0;

-			for (i = 0; i < Base.kNumLowLenSymbols; i++)

-			{

-				if (i >= numSymbols)

-					return;

-				prices[st + i] = a0 + _lowCoder[posState].GetPrice(i);

-			}

-			for (; i < Base.kNumLowLenSymbols + Base.kNumMidLenSymbols; i++)

-			{

-				if (i >= numSymbols)

-					return;

-				prices[st + i] = b0 + _midCoder[posState].GetPrice(i - Base.kNumLowLenSymbols);

-			}

-			for (; i < numSymbols; i++)

-				prices[st + i] = b1 + _highCoder.GetPrice(i - Base.kNumLowLenSymbols - Base.kNumMidLenSymbols);

-		}

-	};

-

-	public static final int kNumLenSpecSymbols = Base.kNumLowLenSymbols + Base.kNumMidLenSymbols;

-

-	class LenPriceTableEncoder extends LenEncoder

-	{

-		int[] _prices = new int[Base.kNumLenSymbols<<Base.kNumPosStatesBitsEncodingMax];

-		int _tableSize;

-		int[] _counters = new int[Base.kNumPosStatesEncodingMax];

-

-		public void SetTableSize(int tableSize) { _tableSize = tableSize; }

-

-		public int GetPrice(int symbol, int posState)

-		{

-			return _prices[posState * Base.kNumLenSymbols + symbol];

-		}

-

-		void UpdateTable(int posState)

-		{

-			SetPrices(posState, _tableSize, _prices, posState * Base.kNumLenSymbols);

-			_counters[posState] = _tableSize;

-		}

-

-		public void UpdateTables(int numPosStates)

-		{

-			for (int posState = 0; posState < numPosStates; posState++)

-				UpdateTable(posState);

-		}

-

-		public void Encode(SevenZip.Compression.RangeCoder.Encoder rangeEncoder, int symbol, int posState) throws IOException

-		{

-			super.Encode(rangeEncoder, symbol, posState);

-			if (--_counters[posState] == 0)

-				UpdateTable(posState);

-		}

-	}

-

-	static final int kNumOpts = 1 << 12;

-	class Optimal

-	{

-		public int State;

-

-		public boolean Prev1IsChar;

-		public boolean Prev2;

-

-		public int PosPrev2;

-		public int BackPrev2;

-

-		public int Price;

-		public int PosPrev;

-		public int BackPrev;

-

-		public int Backs0;

-		public int Backs1;

-		public int Backs2;

-		public int Backs3;

-

-		public void MakeAsChar() { BackPrev = -1; Prev1IsChar = false; }

-		public void MakeAsShortRep() { BackPrev = 0; ; Prev1IsChar = false; }

-		public boolean IsShortRep() { return (BackPrev == 0); }

-	};

-	Optimal[] _optimum = new Optimal[kNumOpts];

-	SevenZip.Compression.LZ.BinTree _matchFinder = null;

-	SevenZip.Compression.RangeCoder.Encoder _rangeEncoder = new SevenZip.Compression.RangeCoder.Encoder();

-

-	short[] _isMatch = new short[Base.kNumStates<<Base.kNumPosStatesBitsMax];

-	short[] _isRep = new short[Base.kNumStates];

-	short[] _isRepG0 = new short[Base.kNumStates];

-	short[] _isRepG1 = new short[Base.kNumStates];

-	short[] _isRepG2 = new short[Base.kNumStates];

-	short[] _isRep0Long = new short[Base.kNumStates<<Base.kNumPosStatesBitsMax];

-

-	BitTreeEncoder[] _posSlotEncoder = new BitTreeEncoder[Base.kNumLenToPosStates]; // kNumPosSlotBits

-

-	short[] _posEncoders = new short[Base.kNumFullDistances-Base.kEndPosModelIndex];

-	BitTreeEncoder _posAlignEncoder = new BitTreeEncoder(Base.kNumAlignBits);

-

-	LenPriceTableEncoder _lenEncoder = new LenPriceTableEncoder();

-	LenPriceTableEncoder _repMatchLenEncoder = new LenPriceTableEncoder();

-

-	LiteralEncoder _literalEncoder = new LiteralEncoder();

-

-	int[] _matchDistances = new int[Base.kMatchMaxLen*2+2];

-

-	int _numFastBytes = kNumFastBytesDefault;

-	int _longestMatchLength;

-	int _numDistancePairs;

-

-	int _additionalOffset;

-

-	int _optimumEndIndex;

-	int _optimumCurrentIndex;

-

-	boolean _longestMatchWasFound;

-

-	int[] _posSlotPrices = new int[1<<(Base.kNumPosSlotBits+Base.kNumLenToPosStatesBits)];

-	int[] _distancesPrices = new int[Base.kNumFullDistances<<Base.kNumLenToPosStatesBits];

-	int[] _alignPrices = new int[Base.kAlignTableSize];

-	int _alignPriceCount;

-

-	int _distTableSize = (kDefaultDictionaryLogSize * 2);

-

-	int _posStateBits = 2;

-	int _posStateMask = (4 - 1);

-	int _numLiteralPosStateBits = 0;

-	int _numLiteralContextBits = 3;

-

-	int _dictionarySize = (1 << kDefaultDictionaryLogSize);

-	int _dictionarySizePrev = -1;

-	int _numFastBytesPrev = -1;

-

-	long nowPos64;

-	boolean _finished;

-	java.io.InputStream _inStream;

-

-	int _matchFinderType = EMatchFinderTypeBT4;

-	boolean _writeEndMark = false;

-

-	boolean _needReleaseMFStream = false;

-

-	void Create()

-	{

-		if (_matchFinder == null)

-		{

-			SevenZip.Compression.LZ.BinTree bt = new SevenZip.Compression.LZ.BinTree();

-			int numHashBytes = 4;

-			if (_matchFinderType == EMatchFinderTypeBT2)

-				numHashBytes = 2;

-			bt.SetType(numHashBytes);

-			_matchFinder = bt;

-		}

-		_literalEncoder.Create(_numLiteralPosStateBits, _numLiteralContextBits);

-

-		if (_dictionarySize == _dictionarySizePrev && _numFastBytesPrev == _numFastBytes)

-			return;

-		_matchFinder.Create(_dictionarySize, kNumOpts, _numFastBytes, Base.kMatchMaxLen + 1);

-		_dictionarySizePrev = _dictionarySize;

-		_numFastBytesPrev = _numFastBytes;

-	}

-

-	public Encoder()

-	{

-		for (int i = 0; i < kNumOpts; i++)

-			_optimum[i] = new Optimal();

-		for (int i = 0; i < Base.kNumLenToPosStates; i++)

-			_posSlotEncoder[i] = new BitTreeEncoder(Base.kNumPosSlotBits);

-	}

-

-	void SetWriteEndMarkerMode(boolean writeEndMarker)

-	{

-		_writeEndMark = writeEndMarker;

-	}

-

-	void Init()

-	{

-		BaseInit();

-		_rangeEncoder.Init();

-

-		SevenZip.Compression.RangeCoder.Encoder.InitBitModels(_isMatch);

-		SevenZip.Compression.RangeCoder.Encoder.InitBitModels(_isRep0Long);

-		SevenZip.Compression.RangeCoder.Encoder.InitBitModels(_isRep);

-		SevenZip.Compression.RangeCoder.Encoder.InitBitModels(_isRepG0);

-		SevenZip.Compression.RangeCoder.Encoder.InitBitModels(_isRepG1);

-		SevenZip.Compression.RangeCoder.Encoder.InitBitModels(_isRepG2);

-		SevenZip.Compression.RangeCoder.Encoder.InitBitModels(_posEncoders);

-

-

-

-

-

-

-

-		_literalEncoder.Init();

-		for (int i = 0; i < Base.kNumLenToPosStates; i++)

-			_posSlotEncoder[i].Init();

-

-

-

-		_lenEncoder.Init(1 << _posStateBits);

-		_repMatchLenEncoder.Init(1 << _posStateBits);

-

-		_posAlignEncoder.Init();

-

-		_longestMatchWasFound = false;

-		_optimumEndIndex = 0;

-		_optimumCurrentIndex = 0;

-		_additionalOffset = 0;

-	}

-

-	int ReadMatchDistances() throws java.io.IOException

-	{

-		int lenRes = 0;

-		_numDistancePairs = _matchFinder.GetMatches(_matchDistances);

-		if (_numDistancePairs > 0)

-		{

-			lenRes = _matchDistances[_numDistancePairs - 2];

-			if (lenRes == _numFastBytes)

-				lenRes += _matchFinder.GetMatchLen((int)lenRes - 1, _matchDistances[_numDistancePairs - 1],

-					Base.kMatchMaxLen - lenRes);

-		}

-		_additionalOffset++;

-		return lenRes;

-	}

-

-	void MovePos(int num) throws java.io.IOException

-	{

-		if (num > 0)

-		{

-			_matchFinder.Skip(num);

-			_additionalOffset += num;

-		}

-	}

-

-	int GetRepLen1Price(int state, int posState)

-	{

-		return SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isRepG0[state]) +

-				SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isRep0Long[(state << Base.kNumPosStatesBitsMax) + posState]);

-	}

-

-	int GetPureRepPrice(int repIndex, int state, int posState)

-	{

-		int price;

-		if (repIndex == 0)

-		{

-			price = SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isRepG0[state]);

-			price += SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isRep0Long[(state << Base.kNumPosStatesBitsMax) + posState]);

-		}

-		else

-		{

-			price = SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isRepG0[state]);

-			if (repIndex == 1)

-				price += SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isRepG1[state]);

-			else

-			{

-				price += SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isRepG1[state]);

-				price += SevenZip.Compression.RangeCoder.Encoder.GetPrice(_isRepG2[state], repIndex - 2);

-			}

-		}

-		return price;

-	}

-

-	int GetRepPrice(int repIndex, int len, int state, int posState)

-	{

-		int price = _repMatchLenEncoder.GetPrice(len - Base.kMatchMinLen, posState);

-		return price + GetPureRepPrice(repIndex, state, posState);

-	}

-

-	int GetPosLenPrice(int pos, int len, int posState)

-	{

-		int price;

-		int lenToPosState = Base.GetLenToPosState(len);

-		if (pos < Base.kNumFullDistances)

-			price = _distancesPrices[(lenToPosState * Base.kNumFullDistances) + pos];

-		else

-			price = _posSlotPrices[(lenToPosState << Base.kNumPosSlotBits) + GetPosSlot2(pos)] +

-				_alignPrices[pos & Base.kAlignMask];

-		return price + _lenEncoder.GetPrice(len - Base.kMatchMinLen, posState);

-	}

-

-	int Backward(int cur)

-	{

-		_optimumEndIndex = cur;

-		int posMem = _optimum[cur].PosPrev;

-		int backMem = _optimum[cur].BackPrev;

-		do

-		{

-			if (_optimum[cur].Prev1IsChar)

-			{

-				_optimum[posMem].MakeAsChar();

-				_optimum[posMem].PosPrev = posMem - 1;

-				if (_optimum[cur].Prev2)

-				{

-					_optimum[posMem - 1].Prev1IsChar = false;

-					_optimum[posMem - 1].PosPrev = _optimum[cur].PosPrev2;

-					_optimum[posMem - 1].BackPrev = _optimum[cur].BackPrev2;

-				}

-			}

-			int posPrev = posMem;

-			int backCur = backMem;

-

-			backMem = _optimum[posPrev].BackPrev;

-			posMem = _optimum[posPrev].PosPrev;

-

-			_optimum[posPrev].BackPrev = backCur;

-			_optimum[posPrev].PosPrev = cur;

-			cur = posPrev;

-		}

-		while (cur > 0);

-		backRes = _optimum[0].BackPrev;

-		_optimumCurrentIndex = _optimum[0].PosPrev;

-		return _optimumCurrentIndex;

-	}

-

-	int[] reps = new int[Base.kNumRepDistances];

-	int[] repLens = new int[Base.kNumRepDistances];

-	int backRes;

-

-	int GetOptimum(int position) throws IOException

-	{

-		if (_optimumEndIndex != _optimumCurrentIndex)

-		{

-			int lenRes = _optimum[_optimumCurrentIndex].PosPrev - _optimumCurrentIndex;

-			backRes = _optimum[_optimumCurrentIndex].BackPrev;

-			_optimumCurrentIndex = _optimum[_optimumCurrentIndex].PosPrev;

-			return lenRes;

-		}

-		_optimumCurrentIndex = _optimumEndIndex = 0;

-

-		int lenMain, numDistancePairs;

-		if (!_longestMatchWasFound)

-		{

-			lenMain = ReadMatchDistances();

-		}

-		else

-		{

-			lenMain = _longestMatchLength;

-			_longestMatchWasFound = false;

-		}

-		numDistancePairs = _numDistancePairs;

-

-		int numAvailableBytes = _matchFinder.GetNumAvailableBytes() + 1;

-		if (numAvailableBytes < 2)

-		{

-			backRes = -1;

-			return 1;

-		}

-		if (numAvailableBytes > Base.kMatchMaxLen)

-			numAvailableBytes = Base.kMatchMaxLen;

-

-		int repMaxIndex = 0;

-		int i;

-		for (i = 0; i < Base.kNumRepDistances; i++)

-		{

-			reps[i] = _repDistances[i];

-			repLens[i] = _matchFinder.GetMatchLen(0 - 1, reps[i], Base.kMatchMaxLen);

-			if (repLens[i] > repLens[repMaxIndex])

-				repMaxIndex = i;

-		}

-		if (repLens[repMaxIndex] >= _numFastBytes)

-		{

-			backRes = repMaxIndex;

-			int lenRes = repLens[repMaxIndex];

-			MovePos(lenRes - 1);

-			return lenRes;

-		}

-

-		if (lenMain >= _numFastBytes)

-		{

-			backRes = _matchDistances[numDistancePairs - 1] + Base.kNumRepDistances;

-			MovePos(lenMain - 1);

-			return lenMain;

-		}

-

-		byte currentByte = _matchFinder.GetIndexByte(0 - 1);

-		byte matchByte = _matchFinder.GetIndexByte(0 - _repDistances[0] - 1 - 1);

-

-		if (lenMain < 2 && currentByte != matchByte && repLens[repMaxIndex] < 2)

-		{

-			backRes = -1;

-			return 1;

-		}

-

-		_optimum[0].State = _state;

-

-		int posState = (position & _posStateMask);

-

-		_optimum[1].Price = SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isMatch[(_state << Base.kNumPosStatesBitsMax) + posState]) +

-				_literalEncoder.GetSubCoder(position, _previousByte).GetPrice(!Base.StateIsCharState(_state), matchByte, currentByte);

-		_optimum[1].MakeAsChar();

-

-		int matchPrice = SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isMatch[(_state << Base.kNumPosStatesBitsMax) + posState]);

-		int repMatchPrice = matchPrice + SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isRep[_state]);

-

-		if (matchByte == currentByte)

-		{

-			int shortRepPrice = repMatchPrice + GetRepLen1Price(_state, posState);

-			if (shortRepPrice < _optimum[1].Price)

-			{

-				_optimum[1].Price = shortRepPrice;

-				_optimum[1].MakeAsShortRep();

-			}

-		}

-

-		int lenEnd = ((lenMain >= repLens[repMaxIndex]) ? lenMain : repLens[repMaxIndex]);

-

-		if (lenEnd < 2)

-		{

-			backRes = _optimum[1].BackPrev;

-			return 1;

-		}

-

-		_optimum[1].PosPrev = 0;

-

-		_optimum[0].Backs0 = reps[0];

-		_optimum[0].Backs1 = reps[1];

-		_optimum[0].Backs2 = reps[2];

-		_optimum[0].Backs3 = reps[3];

-

-		int len = lenEnd;

-		do

-			_optimum[len--].Price = kIfinityPrice;

-		while (len >= 2);

-

-		for (i = 0; i < Base.kNumRepDistances; i++)

-		{

-			int repLen = repLens[i];

-			if (repLen < 2)

-				continue;

-			int price = repMatchPrice + GetPureRepPrice(i, _state, posState);

-			do

-			{

-				int curAndLenPrice = price + _repMatchLenEncoder.GetPrice(repLen - 2, posState);

-				Optimal optimum = _optimum[repLen];

-				if (curAndLenPrice < optimum.Price)

-				{

-					optimum.Price = curAndLenPrice;

-					optimum.PosPrev = 0;

-					optimum.BackPrev = i;

-					optimum.Prev1IsChar = false;

-				}

-			}

-			while (--repLen >= 2);

-		}

-

-		int normalMatchPrice = matchPrice + SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isRep[_state]);

-

-		len = ((repLens[0] >= 2) ? repLens[0] + 1 : 2);

-		if (len <= lenMain)

-		{

-			int offs = 0;

-			while (len > _matchDistances[offs])

-				offs += 2;

-			for (; ; len++)

-			{

-				int distance = _matchDistances[offs + 1];

-				int curAndLenPrice = normalMatchPrice + GetPosLenPrice(distance, len, posState);

-				Optimal optimum = _optimum[len];

-				if (curAndLenPrice < optimum.Price)

-				{

-					optimum.Price = curAndLenPrice;

-					optimum.PosPrev = 0;

-					optimum.BackPrev = distance + Base.kNumRepDistances;

-					optimum.Prev1IsChar = false;

-				}

-				if (len == _matchDistances[offs])

-				{

-					offs += 2;

-					if (offs == numDistancePairs)

-						break;

-				}

-			}

-		}

-

-		int cur = 0;

-

-		while (true)

-		{

-			cur++;

-			if (cur == lenEnd)

-				return Backward(cur);

-			int newLen = ReadMatchDistances();

-			numDistancePairs = _numDistancePairs;

-			if (newLen >= _numFastBytes)

-			{

-

-				_longestMatchLength = newLen;

-				_longestMatchWasFound = true;

-				return Backward(cur);

-			}

-			position++;

-			int posPrev = _optimum[cur].PosPrev;

-			int state;

-			if (_optimum[cur].Prev1IsChar)

-			{

-				posPrev--;

-				if (_optimum[cur].Prev2)

-				{

-					state = _optimum[_optimum[cur].PosPrev2].State;

-					if (_optimum[cur].BackPrev2 < Base.kNumRepDistances)

-						state = Base.StateUpdateRep(state);

-					else

-						state = Base.StateUpdateMatch(state);

-				}

-				else

-					state = _optimum[posPrev].State;

-				state = Base.StateUpdateChar(state);

-			}

-			else

-				state = _optimum[posPrev].State;

-			if (posPrev == cur - 1)

-			{

-				if (_optimum[cur].IsShortRep())

-					state = Base.StateUpdateShortRep(state);

-				else

-					state = Base.StateUpdateChar(state);

-			}

-			else

-			{

-				int pos;

-				if (_optimum[cur].Prev1IsChar && _optimum[cur].Prev2)

-				{

-					posPrev = _optimum[cur].PosPrev2;

-					pos = _optimum[cur].BackPrev2;

-					state = Base.StateUpdateRep(state);

-				}

-				else

-				{

-					pos = _optimum[cur].BackPrev;

-					if (pos < Base.kNumRepDistances)

-						state = Base.StateUpdateRep(state);

-					else

-						state = Base.StateUpdateMatch(state);

-				}

-				Optimal opt = _optimum[posPrev];

-				if (pos < Base.kNumRepDistances)

-				{

-					if (pos == 0)

-					{

-						reps[0] = opt.Backs0;

-						reps[1] = opt.Backs1;

-						reps[2] = opt.Backs2;

-						reps[3] = opt.Backs3;

-					}

-					else if (pos == 1)

-					{

-						reps[0] = opt.Backs1;

-						reps[1] = opt.Backs0;

-						reps[2] = opt.Backs2;

-						reps[3] = opt.Backs3;

-					}

-					else if (pos == 2)

-					{

-						reps[0] = opt.Backs2;

-						reps[1] = opt.Backs0;

-						reps[2] = opt.Backs1;

-						reps[3] = opt.Backs3;

-					}

-					else

-					{

-						reps[0] = opt.Backs3;

-						reps[1] = opt.Backs0;

-						reps[2] = opt.Backs1;

-						reps[3] = opt.Backs2;

-					}

-				}

-				else

-				{

-					reps[0] = (pos - Base.kNumRepDistances);

-					reps[1] = opt.Backs0;

-					reps[2] = opt.Backs1;

-					reps[3] = opt.Backs2;

-				}

-			}

-			_optimum[cur].State = state;

-			_optimum[cur].Backs0 = reps[0];

-			_optimum[cur].Backs1 = reps[1];

-			_optimum[cur].Backs2 = reps[2];

-			_optimum[cur].Backs3 = reps[3];

-			int curPrice = _optimum[cur].Price;

-

-			currentByte = _matchFinder.GetIndexByte(0 - 1);

-			matchByte = _matchFinder.GetIndexByte(0 - reps[0] - 1 - 1);

-

-			posState = (position & _posStateMask);

-

-			int curAnd1Price = curPrice +

-				SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isMatch[(state << Base.kNumPosStatesBitsMax) + posState]) +

-				_literalEncoder.GetSubCoder(position, _matchFinder.GetIndexByte(0 - 2)).

-				GetPrice(!Base.StateIsCharState(state), matchByte, currentByte);

-

-			Optimal nextOptimum = _optimum[cur + 1];

-

-			boolean nextIsChar = false;

-			if (curAnd1Price < nextOptimum.Price)

-			{

-				nextOptimum.Price = curAnd1Price;

-				nextOptimum.PosPrev = cur;

-				nextOptimum.MakeAsChar();

-				nextIsChar = true;

-			}

-

-			matchPrice = curPrice + SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isMatch[(state << Base.kNumPosStatesBitsMax) + posState]);

-			repMatchPrice = matchPrice + SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isRep[state]);

-

-			if (matchByte == currentByte &&

-				!(nextOptimum.PosPrev < cur && nextOptimum.BackPrev == 0))

-			{

-				int shortRepPrice = repMatchPrice + GetRepLen1Price(state, posState);

-				if (shortRepPrice <= nextOptimum.Price)

-				{

-					nextOptimum.Price = shortRepPrice;

-					nextOptimum.PosPrev = cur;

-					nextOptimum.MakeAsShortRep();

-					nextIsChar = true;

-				}

-			}

-

-			int numAvailableBytesFull = _matchFinder.GetNumAvailableBytes() + 1;

-			numAvailableBytesFull = Math.min(kNumOpts - 1 - cur, numAvailableBytesFull);

-			numAvailableBytes = numAvailableBytesFull;

-

-			if (numAvailableBytes < 2)

-				continue;

-			if (numAvailableBytes > _numFastBytes)

-				numAvailableBytes = _numFastBytes;

-			if (!nextIsChar && matchByte != currentByte)

-			{

-				// try Literal + rep0

-				int t = Math.min(numAvailableBytesFull - 1, _numFastBytes);

-				int lenTest2 = _matchFinder.GetMatchLen(0, reps[0], t);

-				if (lenTest2 >= 2)

-				{

-					int state2 = Base.StateUpdateChar(state);

-

-					int posStateNext = (position + 1) & _posStateMask;

-					int nextRepMatchPrice = curAnd1Price +

-						SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isMatch[(state2 << Base.kNumPosStatesBitsMax) + posStateNext]) +

-						SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isRep[state2]);

-					{

-						int offset = cur + 1 + lenTest2;

-						while (lenEnd < offset)

-							_optimum[++lenEnd].Price = kIfinityPrice;

-						int curAndLenPrice = nextRepMatchPrice + GetRepPrice(

-								0, lenTest2, state2, posStateNext);

-						Optimal optimum = _optimum[offset];

-						if (curAndLenPrice < optimum.Price)

-						{

-							optimum.Price = curAndLenPrice;

-							optimum.PosPrev = cur + 1;

-							optimum.BackPrev = 0;

-							optimum.Prev1IsChar = true;

-							optimum.Prev2 = false;

-						}

-					}

-				}

-			}

-

-			int startLen = 2; // speed optimization 

-

-			for (int repIndex = 0; repIndex < Base.kNumRepDistances; repIndex++)

-			{

-				int lenTest = _matchFinder.GetMatchLen(0 - 1, reps[repIndex], numAvailableBytes);

-				if (lenTest < 2)

-					continue;

-				int lenTestTemp = lenTest;

-				do

-				{

-					while (lenEnd < cur + lenTest)

-						_optimum[++lenEnd].Price = kIfinityPrice;

-					int curAndLenPrice = repMatchPrice + GetRepPrice(repIndex, lenTest, state, posState);

-					Optimal optimum = _optimum[cur + lenTest];

-					if (curAndLenPrice < optimum.Price)

-					{

-						optimum.Price = curAndLenPrice;

-						optimum.PosPrev = cur;

-						optimum.BackPrev = repIndex;

-						optimum.Prev1IsChar = false;

-					}

-				}

-				while (--lenTest >= 2);

-				lenTest = lenTestTemp;

-

-				if (repIndex == 0)

-					startLen = lenTest + 1;

-

-				// if (_maxMode)

-				if (lenTest < numAvailableBytesFull)

-				{

-					int t = Math.min(numAvailableBytesFull - 1 - lenTest, _numFastBytes);

-					int lenTest2 = _matchFinder.GetMatchLen(lenTest, reps[repIndex], t);

-					if (lenTest2 >= 2)

-					{

-						int state2 = Base.StateUpdateRep(state);

-

-						int posStateNext = (position + lenTest) & _posStateMask;

-						int curAndLenCharPrice =

-								repMatchPrice + GetRepPrice(repIndex, lenTest, state, posState) +

-								SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isMatch[(state2 << Base.kNumPosStatesBitsMax) + posStateNext]) +

-								_literalEncoder.GetSubCoder(position + lenTest,

-								_matchFinder.GetIndexByte(lenTest - 1 - 1)).GetPrice(true,

-								_matchFinder.GetIndexByte(lenTest - 1 - (reps[repIndex] + 1)),

-								_matchFinder.GetIndexByte(lenTest - 1));

-						state2 = Base.StateUpdateChar(state2);

-						posStateNext = (position + lenTest + 1) & _posStateMask;

-						int nextMatchPrice = curAndLenCharPrice + SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isMatch[(state2 << Base.kNumPosStatesBitsMax) + posStateNext]);

-						int nextRepMatchPrice = nextMatchPrice + SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isRep[state2]);

-

-						// for(; lenTest2 >= 2; lenTest2--)

-						{

-							int offset = lenTest + 1 + lenTest2;

-							while (lenEnd < cur + offset)

-								_optimum[++lenEnd].Price = kIfinityPrice;

-							int curAndLenPrice = nextRepMatchPrice + GetRepPrice(0, lenTest2, state2, posStateNext);

-							Optimal optimum = _optimum[cur + offset];

-							if (curAndLenPrice < optimum.Price)

-							{

-								optimum.Price = curAndLenPrice;

-								optimum.PosPrev = cur + lenTest + 1;

-								optimum.BackPrev = 0;

-								optimum.Prev1IsChar = true;

-								optimum.Prev2 = true;

-								optimum.PosPrev2 = cur;

-								optimum.BackPrev2 = repIndex;

-							}

-						}

-					}

-				}

-			}

-

-			if (newLen > numAvailableBytes)

-			{

-				newLen = numAvailableBytes;

-				for (numDistancePairs = 0; newLen > _matchDistances[numDistancePairs]; numDistancePairs += 2) ;

-				_matchDistances[numDistancePairs] = newLen;

-				numDistancePairs += 2;

-			}

-			if (newLen >= startLen)

-			{

-				normalMatchPrice = matchPrice + SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isRep[state]);

-				while (lenEnd < cur + newLen)

-					_optimum[++lenEnd].Price = kIfinityPrice;

-

-				int offs = 0;

-				while (startLen > _matchDistances[offs])

-					offs += 2;

-

-				for (int lenTest = startLen; ; lenTest++)

-				{

-					int curBack = _matchDistances[offs + 1];

-					int curAndLenPrice = normalMatchPrice + GetPosLenPrice(curBack, lenTest, posState);

-					Optimal optimum = _optimum[cur + lenTest];

-					if (curAndLenPrice < optimum.Price)

-					{

-						optimum.Price = curAndLenPrice;

-						optimum.PosPrev = cur;

-						optimum.BackPrev = curBack + Base.kNumRepDistances;

-						optimum.Prev1IsChar = false;

-					}

-

-					if (lenTest == _matchDistances[offs])

-					{

-						if (lenTest < numAvailableBytesFull)

-						{

-							int t = Math.min(numAvailableBytesFull - 1 - lenTest, _numFastBytes);

-							int lenTest2 = _matchFinder.GetMatchLen(lenTest, curBack, t);

-							if (lenTest2 >= 2)

-							{

-								int state2 = Base.StateUpdateMatch(state);

-

-								int posStateNext = (position + lenTest) & _posStateMask;

-								int curAndLenCharPrice = curAndLenPrice +

-									SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isMatch[(state2 << Base.kNumPosStatesBitsMax) + posStateNext]) +

-									_literalEncoder.GetSubCoder(position + lenTest,

-									_matchFinder.GetIndexByte(lenTest - 1 - 1)).

-									GetPrice(true,

-									_matchFinder.GetIndexByte(lenTest - (curBack + 1) - 1),

-									_matchFinder.GetIndexByte(lenTest - 1));

-								state2 = Base.StateUpdateChar(state2);

-								posStateNext = (position + lenTest + 1) & _posStateMask;

-								int nextMatchPrice = curAndLenCharPrice + SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isMatch[(state2 << Base.kNumPosStatesBitsMax) + posStateNext]);

-								int nextRepMatchPrice = nextMatchPrice + SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isRep[state2]);

-

-								int offset = lenTest + 1 + lenTest2;

-								while (lenEnd < cur + offset)

-									_optimum[++lenEnd].Price = kIfinityPrice;

-								curAndLenPrice = nextRepMatchPrice + GetRepPrice(0, lenTest2, state2, posStateNext);

-								optimum = _optimum[cur + offset];

-								if (curAndLenPrice < optimum.Price)

-								{

-									optimum.Price = curAndLenPrice;

-									optimum.PosPrev = cur + lenTest + 1;

-									optimum.BackPrev = 0;

-									optimum.Prev1IsChar = true;

-									optimum.Prev2 = true;

-									optimum.PosPrev2 = cur;

-									optimum.BackPrev2 = curBack + Base.kNumRepDistances;

-								}

-							}

-						}

-						offs += 2;

-						if (offs == numDistancePairs)

-							break;

-					}

-				}

-			}

-		}

-	}

-

-	boolean ChangePair(int smallDist, int bigDist)

-	{

-		int kDif = 7;

-		return (smallDist < (1 << (32 - kDif)) && bigDist >= (smallDist << kDif));

-	}

-

-	void WriteEndMarker(int posState) throws IOException

-	{

-		if (!_writeEndMark)

-			return;

-

-		_rangeEncoder.Encode(_isMatch, (_state << Base.kNumPosStatesBitsMax) + posState, 1);

-		_rangeEncoder.Encode(_isRep, _state, 0);

-		_state = Base.StateUpdateMatch(_state);

-		int len = Base.kMatchMinLen;

-		_lenEncoder.Encode(_rangeEncoder, len - Base.kMatchMinLen, posState);

-		int posSlot = (1 << Base.kNumPosSlotBits) - 1;

-		int lenToPosState = Base.GetLenToPosState(len);

-		_posSlotEncoder[lenToPosState].Encode(_rangeEncoder, posSlot);

-		int footerBits = 30;

-		int posReduced = (1 << footerBits) - 1;

-		_rangeEncoder.EncodeDirectBits(posReduced >> Base.kNumAlignBits, footerBits - Base.kNumAlignBits);

-		_posAlignEncoder.ReverseEncode(_rangeEncoder, posReduced & Base.kAlignMask);

-	}

-

-	void Flush(int nowPos) throws IOException

-	{

-		ReleaseMFStream();

-		WriteEndMarker(nowPos & _posStateMask);

-		_rangeEncoder.FlushData();

-		_rangeEncoder.FlushStream();

-	}

-

-	public void CodeOneBlock(long[] inSize, long[] outSize, boolean[] finished) throws IOException

-	{

-		inSize[0] = 0;

-		outSize[0] = 0;

-		finished[0] = true;

-

-		if (_inStream != null)

-		{

-			_matchFinder.SetStream(_inStream);

-			_matchFinder.Init();

-			_needReleaseMFStream = true;

-			_inStream = null;

-		}

-

-		if (_finished)

-			return;

-		_finished = true;

-

-

-		long progressPosValuePrev = nowPos64;

-		if (nowPos64 == 0)

-		{

-			if (_matchFinder.GetNumAvailableBytes() == 0)

-			{

-				Flush((int)nowPos64);

-				return;

-			}

-

-			ReadMatchDistances();

-			int posState = (int)(nowPos64) & _posStateMask;

-			_rangeEncoder.Encode(_isMatch, (_state << Base.kNumPosStatesBitsMax) + posState, 0);

-			_state = Base.StateUpdateChar(_state);

-			byte curByte = _matchFinder.GetIndexByte(0 - _additionalOffset);

-			_literalEncoder.GetSubCoder((int)(nowPos64), _previousByte).Encode(_rangeEncoder, curByte);

-			_previousByte = curByte;

-			_additionalOffset--;

-			nowPos64++;

-		}

-		if (_matchFinder.GetNumAvailableBytes() == 0)

-		{

-			Flush((int)nowPos64);

-			return;

-		}

-		while (true)

-		{

-

-			int len = GetOptimum((int)nowPos64);

-			int pos = backRes;

-			int posState = ((int)nowPos64) & _posStateMask;

-			int complexState = (_state << Base.kNumPosStatesBitsMax) + posState;

-			if (len == 1 && pos == -1)

-			{

-				_rangeEncoder.Encode(_isMatch, complexState, 0);

-				byte curByte = _matchFinder.GetIndexByte((int)(0 - _additionalOffset));

-				LiteralEncoder.Encoder2 subCoder = _literalEncoder.GetSubCoder((int)nowPos64, _previousByte);

-				if (!Base.StateIsCharState(_state))

-				{

-					byte matchByte = _matchFinder.GetIndexByte((int)(0 - _repDistances[0] - 1 - _additionalOffset));

-					subCoder.EncodeMatched(_rangeEncoder, matchByte, curByte);

-				}

-				else

-					subCoder.Encode(_rangeEncoder, curByte);

-				_previousByte = curByte;

-				_state = Base.StateUpdateChar(_state);

-			}

-			else

-			{

-				_rangeEncoder.Encode(_isMatch, complexState, 1);

-				if (pos < Base.kNumRepDistances)

-				{

-					_rangeEncoder.Encode(_isRep, _state, 1);

-					if (pos == 0)

-					{

-						_rangeEncoder.Encode(_isRepG0, _state, 0);

-						if (len == 1)

-							_rangeEncoder.Encode(_isRep0Long, complexState, 0);

-						else

-							_rangeEncoder.Encode(_isRep0Long, complexState, 1);

-					}

-					else

-					{

-						_rangeEncoder.Encode(_isRepG0, _state, 1);

-						if (pos == 1)

-							_rangeEncoder.Encode(_isRepG1, _state, 0);

-						else

-						{

-							_rangeEncoder.Encode(_isRepG1, _state, 1);

-							_rangeEncoder.Encode(_isRepG2, _state, pos - 2);

-						}

-					}

-					if (len == 1)

-						_state = Base.StateUpdateShortRep(_state);

-					else

-					{

-						_repMatchLenEncoder.Encode(_rangeEncoder, len - Base.kMatchMinLen, posState);

-						_state = Base.StateUpdateRep(_state);

-					}

-					int distance = _repDistances[pos];

-					if (pos != 0)

-					{

-						for (int i = pos; i >= 1; i--)

-							_repDistances[i] = _repDistances[i - 1];

-						_repDistances[0] = distance;

-					}

-				}

-				else

-				{

-					_rangeEncoder.Encode(_isRep, _state, 0);

-					_state = Base.StateUpdateMatch(_state);

-					_lenEncoder.Encode(_rangeEncoder, len - Base.kMatchMinLen, posState);

-					pos -= Base.kNumRepDistances;

-					int posSlot = GetPosSlot(pos);

-					int lenToPosState = Base.GetLenToPosState(len);

-					_posSlotEncoder[lenToPosState].Encode(_rangeEncoder, posSlot);

-

-					if (posSlot >= Base.kStartPosModelIndex)

-					{

-						int footerBits = (int)((posSlot >> 1) - 1);

-						int baseVal = ((2 | (posSlot & 1)) << footerBits);

-						int posReduced = pos - baseVal;

-

-						if (posSlot < Base.kEndPosModelIndex)

-							BitTreeEncoder.ReverseEncode(_posEncoders,

-									baseVal - posSlot - 1, _rangeEncoder, footerBits, posReduced);

-						else

-						{

-							_rangeEncoder.EncodeDirectBits(posReduced >> Base.kNumAlignBits, footerBits - Base.kNumAlignBits);

-							_posAlignEncoder.ReverseEncode(_rangeEncoder, posReduced & Base.kAlignMask);

-							_alignPriceCount++;

-						}

-					}

-					int distance = pos;

-					for (int i = Base.kNumRepDistances - 1; i >= 1; i--)

-						_repDistances[i] = _repDistances[i - 1];

-					_repDistances[0] = distance;

-					_matchPriceCount++;

-				}

-				_previousByte = _matchFinder.GetIndexByte(len - 1 - _additionalOffset);

-			}

-			_additionalOffset -= len;

-			nowPos64 += len;

-			if (_additionalOffset == 0)

-			{

-				// if (!_fastMode)

-				if (_matchPriceCount >= (1 << 7))

-					FillDistancesPrices();

-				if (_alignPriceCount >= Base.kAlignTableSize)

-					FillAlignPrices();

-				inSize[0] = nowPos64;

-				outSize[0] = _rangeEncoder.GetProcessedSizeAdd();

-				if (_matchFinder.GetNumAvailableBytes() == 0)

-				{

-					Flush((int)nowPos64);

-					return;

-				}

-

-				if (nowPos64 - progressPosValuePrev >= (1 << 12))

-				{

-					_finished = false;

-					finished[0] = false;

-					return;

-				}

-			}

-		}

-	}

-

-	void ReleaseMFStream()

-	{

-		if (_matchFinder != null && _needReleaseMFStream)

-		{

-			_matchFinder.ReleaseStream();

-			_needReleaseMFStream = false;

-		}

-	}

-

-	void SetOutStream(java.io.OutputStream outStream)

-	{ _rangeEncoder.SetStream(outStream); }

-	void ReleaseOutStream()

-	{ _rangeEncoder.ReleaseStream(); }

-

-	void ReleaseStreams()

-	{

-		ReleaseMFStream();

-		ReleaseOutStream();

-	}

-

-	void SetStreams(java.io.InputStream inStream, java.io.OutputStream outStream,

-			long inSize, long outSize)

-	{

-		_inStream = inStream;

-		_finished = false;

-		Create();

-		SetOutStream(outStream);

-		Init();

-

-		// if (!_fastMode)

-		{

-			FillDistancesPrices();

-			FillAlignPrices();

-		}

-

-		_lenEncoder.SetTableSize(_numFastBytes + 1 - Base.kMatchMinLen);

-		_lenEncoder.UpdateTables(1 << _posStateBits);

-		_repMatchLenEncoder.SetTableSize(_numFastBytes + 1 - Base.kMatchMinLen);

-		_repMatchLenEncoder.UpdateTables(1 << _posStateBits);

-

-		nowPos64 = 0;

-	}

-

-	long[] processedInSize = new long[1]; long[] processedOutSize = new long[1]; boolean[] finished = new boolean[1];

-	public void Code(java.io.InputStream inStream, java.io.OutputStream outStream,

-			long inSize, long outSize, ICodeProgress progress) throws IOException

-	{

-		_needReleaseMFStream = false;

-		try

-		{

-			SetStreams(inStream, outStream, inSize, outSize);

-			while (true)

-			{

-

-

-

-				CodeOneBlock(processedInSize, processedOutSize, finished);

-				if (finished[0])

-					return;

-				if (progress != null)

-				{

-					progress.SetProgress(processedInSize[0], processedOutSize[0]);

-				}

-			}

-		}

-		finally

-		{

-			ReleaseStreams();

-		}

-	}

-

-	public static final int kPropSize = 5;

-	byte[] properties = new byte[kPropSize];

-

-	public void WriteCoderProperties(java.io.OutputStream outStream) throws IOException

-	{

-		properties[0] = (byte)((_posStateBits * 5 + _numLiteralPosStateBits) * 9 + _numLiteralContextBits);

-		for (int i = 0; i < 4; i++)

-			properties[1 + i] = (byte)(_dictionarySize >> (8 * i));

-		outStream.write(properties, 0, kPropSize);

-	}

-

-	int[] tempPrices = new int[Base.kNumFullDistances];

-	int _matchPriceCount;

-

-	void FillDistancesPrices()

-	{

-		for (int i = Base.kStartPosModelIndex; i < Base.kNumFullDistances; i++)

-		{

-			int posSlot = GetPosSlot(i);

-			int footerBits = (int)((posSlot >> 1) - 1);

-			int baseVal = ((2 | (posSlot & 1)) << footerBits);

-			tempPrices[i] = BitTreeEncoder.ReverseGetPrice(_posEncoders,

-				baseVal - posSlot - 1, footerBits, i - baseVal);

-		}

-

-		for (int lenToPosState = 0; lenToPosState < Base.kNumLenToPosStates; lenToPosState++)

-		{

-			int posSlot;

-			BitTreeEncoder encoder = _posSlotEncoder[lenToPosState];

-

-			int st = (lenToPosState << Base.kNumPosSlotBits);

-			for (posSlot = 0; posSlot < _distTableSize; posSlot++)

-				_posSlotPrices[st + posSlot] = encoder.GetPrice(posSlot);

-			for (posSlot = Base.kEndPosModelIndex; posSlot < _distTableSize; posSlot++)

-				_posSlotPrices[st + posSlot] += ((((posSlot >> 1) - 1) - Base.kNumAlignBits) << SevenZip.Compression.RangeCoder.Encoder.kNumBitPriceShiftBits);

-

-			int st2 = lenToPosState * Base.kNumFullDistances;

-			int i;

-			for (i = 0; i < Base.kStartPosModelIndex; i++)

-				_distancesPrices[st2 + i] = _posSlotPrices[st + i];

-			for (; i < Base.kNumFullDistances; i++)

-				_distancesPrices[st2 + i] = _posSlotPrices[st + GetPosSlot(i)] + tempPrices[i];

-		}

-		_matchPriceCount = 0;

-	}

-

-	void FillAlignPrices()

-	{

-		for (int i = 0; i < Base.kAlignTableSize; i++)

-			_alignPrices[i] = _posAlignEncoder.ReverseGetPrice(i);

-		_alignPriceCount = 0;

-	}

-

-

-	public boolean SetAlgorithm(int algorithm)

-	{

-		/*

-		_fastMode = (algorithm == 0);

-		_maxMode = (algorithm >= 2);

-		*/

-		return true;

-	}

-

-	public boolean SetDictionarySize(int dictionarySize)

-	{

-		int kDicLogSizeMaxCompress = 29;

-		if (dictionarySize < (1 << Base.kDicLogSizeMin) || dictionarySize > (1 << kDicLogSizeMaxCompress))

-			return false;

-		_dictionarySize = dictionarySize;

-		int dicLogSize;

-		for (dicLogSize = 0; dictionarySize > (1 << dicLogSize); dicLogSize++) ;

-		_distTableSize = dicLogSize * 2;

-		return true;

-	}

-

-	public boolean SetNumFastBytes(int numFastBytes)

-	{

-		if (numFastBytes < 5 || numFastBytes > Base.kMatchMaxLen)

-			return false;

-		_numFastBytes = numFastBytes;

-		return true;

-	}

-

-	public boolean SetMatchFinder(int matchFinderIndex)

-	{

-		if (matchFinderIndex < 0 || matchFinderIndex > 2)

-			return false;

-		int matchFinderIndexPrev = _matchFinderType;

-		_matchFinderType = matchFinderIndex;

-		if (_matchFinder != null && matchFinderIndexPrev != _matchFinderType)

-		{

-			_dictionarySizePrev = -1;

-			_matchFinder = null;

-		}

-		return true;

-	}

-

-	public boolean SetLcLpPb(int lc, int lp, int pb)

-	{

-		if (

-				lp < 0 || lp > Base.kNumLitPosStatesBitsEncodingMax ||

-				lc < 0 || lc > Base.kNumLitContextBitsMax ||

-				pb < 0 || pb > Base.kNumPosStatesBitsEncodingMax)

-			return false;

-		_numLiteralPosStateBits = lp;

-		_numLiteralContextBits = lc;

-		_posStateBits = pb;

-		_posStateMask = ((1) << _posStateBits) - 1;

-		return true;

-	}

-

-	public void SetEndMarkerMode(boolean endMarkerMode)

-	{

-		_writeEndMark = endMarkerMode;

-	}

-}

-

diff --git a/Java/SevenZip/Compression/RangeCoder/BitTreeDecoder.java b/Java/SevenZip/Compression/RangeCoder/BitTreeDecoder.java
deleted file mode 100644
index 6864c69..0000000
--- a/Java/SevenZip/Compression/RangeCoder/BitTreeDecoder.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package SevenZip.Compression.RangeCoder;

-

-public class BitTreeDecoder

-{

-	short[] Models;

-	int NumBitLevels;

-	

-	public BitTreeDecoder(int numBitLevels)

-	{

-		NumBitLevels = numBitLevels;

-		Models = new short[1 << numBitLevels];

-	}

-	

-	public void Init()

-	{

-		Decoder.InitBitModels(Models);

-	}

-	

-	public int Decode(Decoder rangeDecoder) throws java.io.IOException

-	{

-		int m = 1;

-		for (int bitIndex = NumBitLevels; bitIndex != 0; bitIndex--)

-			m = (m << 1) + rangeDecoder.DecodeBit(Models, m);

-		return m - (1 << NumBitLevels);

-	}

-	

-	public int ReverseDecode(Decoder rangeDecoder) throws java.io.IOException

-	{

-		int m = 1;

-		int symbol = 0;

-		for (int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++)

-		{

-			int bit = rangeDecoder.DecodeBit(Models, m);

-			m <<= 1;

-			m += bit;

-			symbol |= (bit << bitIndex);

-		}

-		return symbol;

-	}

-	

-	public static int ReverseDecode(short[] Models, int startIndex,

-			Decoder rangeDecoder, int NumBitLevels) throws java.io.IOException

-	{

-		int m = 1;

-		int symbol = 0;

-		for (int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++)

-		{

-			int bit = rangeDecoder.DecodeBit(Models, startIndex + m);

-			m <<= 1;

-			m += bit;

-			symbol |= (bit << bitIndex);

-		}

-		return symbol;

-	}

-}

diff --git a/Java/SevenZip/Compression/RangeCoder/BitTreeEncoder.java b/Java/SevenZip/Compression/RangeCoder/BitTreeEncoder.java
deleted file mode 100644
index b4c0a07..0000000
--- a/Java/SevenZip/Compression/RangeCoder/BitTreeEncoder.java
+++ /dev/null
@@ -1,99 +0,0 @@
-package SevenZip.Compression.RangeCoder;

-import java.io.IOException;

-

-public class BitTreeEncoder

-{

-	short[] Models;

-	int NumBitLevels;

-	

-	public BitTreeEncoder(int numBitLevels)

-	{

-		NumBitLevels = numBitLevels;

-		Models = new short[1 << numBitLevels];

-	}

-	

-	public void Init()

-	{

-		Decoder.InitBitModels(Models);

-	}

-	

-	public void Encode(Encoder rangeEncoder, int symbol) throws IOException

-	{

-		int m = 1;

-		for (int bitIndex = NumBitLevels; bitIndex != 0; )

-		{

-			bitIndex--;

-			int bit = (symbol >>> bitIndex) & 1;

-			rangeEncoder.Encode(Models, m, bit);

-			m = (m << 1) | bit;

-		}

-	}

-	

-	public void ReverseEncode(Encoder rangeEncoder, int symbol) throws IOException

-	{

-		int m = 1;

-		for (int  i = 0; i < NumBitLevels; i++)

-		{

-			int bit = symbol & 1;

-			rangeEncoder.Encode(Models, m, bit);

-			m = (m << 1) | bit;

-			symbol >>= 1;

-		}

-	}

-	

-	public int GetPrice(int symbol)

-	{

-		int price = 0;

-		int m = 1;

-		for (int bitIndex = NumBitLevels; bitIndex != 0; )

-		{

-			bitIndex--;

-			int bit = (symbol >>> bitIndex) & 1;

-			price += Encoder.GetPrice(Models[m], bit);

-			m = (m << 1) + bit;

-		}

-		return price;

-	}

-	

-	public int ReverseGetPrice(int symbol)

-	{

-		int price = 0;

-		int m = 1;

-		for (int i = NumBitLevels; i != 0; i--)

-		{

-			int bit = symbol & 1;

-			symbol >>>= 1;

-			price += Encoder.GetPrice(Models[m], bit);

-			m = (m << 1) | bit;

-		}

-		return price;

-	}

-	

-	public static int ReverseGetPrice(short[] Models, int startIndex,

-			int NumBitLevels, int symbol)

-	{

-		int price = 0;

-		int m = 1;

-		for (int i = NumBitLevels; i != 0; i--)

-		{

-			int bit = symbol & 1;

-			symbol >>>= 1;

-			price += Encoder.GetPrice(Models[startIndex + m], bit);

-			m = (m << 1) | bit;

-		}

-		return price;

-	}

-	

-	public static void ReverseEncode(short[] Models, int startIndex,

-			Encoder rangeEncoder, int NumBitLevels, int symbol) throws IOException

-	{

-		int m = 1;

-		for (int i = 0; i < NumBitLevels; i++)

-		{

-			int bit = symbol & 1;

-			rangeEncoder.Encode(Models, startIndex + m, bit);

-			m = (m << 1) | bit;

-			symbol >>= 1;

-		}

-	}

-}

diff --git a/Java/SevenZip/Compression/RangeCoder/Decoder.java b/Java/SevenZip/Compression/RangeCoder/Decoder.java
deleted file mode 100644
index 7453383..0000000
--- a/Java/SevenZip/Compression/RangeCoder/Decoder.java
+++ /dev/null
@@ -1,88 +0,0 @@
-package SevenZip.Compression.RangeCoder;

-import java.io.IOException;

-

-public class Decoder

-{

-	static final int kTopMask = ~((1 << 24) - 1);

-	

-	static final int kNumBitModelTotalBits = 11;

-	static final int kBitModelTotal = (1 << kNumBitModelTotalBits);

-	static final int kNumMoveBits = 5;

-	

-	int Range;

-	int Code;

-

-	java.io.InputStream Stream;

-	

-	public final void SetStream(java.io.InputStream stream)

-	{ 

-		Stream = stream; 

-	}

-	

-	public final void ReleaseStream()

-	{ 

-		Stream = null; 

-	}

-	

-	public final void Init() throws IOException

-	{

-		Code = 0;

-		Range = -1;

-		for (int i = 0; i < 5; i++)

-			Code = (Code << 8) | Stream.read();

-	}

-	

-	public final int DecodeDirectBits(int numTotalBits) throws IOException

-	{

-		int result = 0;

-		for (int i = numTotalBits; i != 0; i--)

-		{

-			Range >>>= 1;

-			int t = ((Code - Range) >>> 31);

-			Code -= Range & (t - 1);

-			result = (result << 1) | (1 - t);

-			

-			if ((Range & kTopMask) == 0)

-			{

-				Code = (Code << 8) | Stream.read();

-				Range <<= 8;

-			}

-		}

-		return result;

-	}

-	

-	public int DecodeBit(short []probs, int index) throws IOException

-	{

-		int prob = probs[index];

-		int newBound = (Range >>> kNumBitModelTotalBits) * prob;

-		if ((Code ^ 0x80000000) < (newBound ^ 0x80000000))

-		{

-			Range = newBound;

-			probs[index] = (short)(prob + ((kBitModelTotal - prob) >>> kNumMoveBits));

-			if ((Range & kTopMask) == 0)

-			{

-				Code = (Code << 8) | Stream.read();

-				Range <<= 8;

-			}

-			return 0;

-		}

-		else

-		{

-			Range -= newBound;

-			Code -= newBound;

-			probs[index] = (short)(prob - ((prob) >>> kNumMoveBits));

-			if ((Range & kTopMask) == 0)

-			{

-				Code = (Code << 8) | Stream.read();

-				Range <<= 8;

-			}

-			return 1;

-		}

-	}

-	

-	public static void InitBitModels(short []probs)

-	{

-		for (int i = 0; i < probs.length; i++)

-			probs[i] = (kBitModelTotal >>> 1);

-	}

-}

diff --git a/Java/SevenZip/Compression/RangeCoder/Encoder.java b/Java/SevenZip/Compression/RangeCoder/Encoder.java
deleted file mode 100644
index 2273e92..0000000
--- a/Java/SevenZip/Compression/RangeCoder/Encoder.java
+++ /dev/null
@@ -1,151 +0,0 @@
-package SevenZip.Compression.RangeCoder;

-import java.io.IOException;

-

-public class Encoder

-{

-	static final int kTopMask = ~((1 << 24) - 1);

-	

-	static final int kNumBitModelTotalBits = 11;

-	static final int kBitModelTotal = (1 << kNumBitModelTotalBits);

-	static final int kNumMoveBits = 5;

-	

-	java.io.OutputStream Stream;

-

-	long Low;

-	int Range;

-	int _cacheSize;

-	int _cache;

-	

-	long _position;

-	

-	public void SetStream(java.io.OutputStream stream)

-	{

-		Stream = stream;

-	}

-	

-	public void ReleaseStream()

-	{

-		Stream = null;

-	}

-	

-	public void Init()

-	{

-		_position = 0;

-		Low = 0;

-		Range = -1;

-		_cacheSize = 1;

-		_cache = 0;

-	}

-	

-	public void FlushData() throws IOException

-	{

-		for (int i = 0; i < 5; i++)

-			ShiftLow();

-	}

-	

-	public void FlushStream() throws IOException

-	{

-		Stream.flush();

-	}

-	

-	public void ShiftLow() throws IOException

-	{

-		int LowHi = (int)(Low >>> 32);

-		if (LowHi != 0 || Low < 0xFF000000L)

-		{

-			_position += _cacheSize;

-			int temp = _cache;

-			do

-			{

-				Stream.write(temp + LowHi);

-				temp = 0xFF;

-			}

-			while(--_cacheSize != 0);

-			_cache = (((int)Low) >>> 24);

-		}

-		_cacheSize++;

-		Low = (Low & 0xFFFFFF) << 8;

-	}

-	

-	public void EncodeDirectBits(int v, int numTotalBits) throws IOException

-	{

-		for (int i = numTotalBits - 1; i >= 0; i--)

-		{

-			Range >>>= 1;

-			if (((v >>> i) & 1) == 1)

-				Low += Range;

-			if ((Range & Encoder.kTopMask) == 0)

-			{

-				Range <<= 8;

-				ShiftLow();

-			}

-		}

-	}

-	

-	

-	public long GetProcessedSizeAdd()

-	{

-		return _cacheSize + _position + 4;

-	}

-	

-	

-	

-	static final int kNumMoveReducingBits = 2;

-	public static final int kNumBitPriceShiftBits = 6;

-	

-	public static void InitBitModels(short []probs)

-	{

-		for (int i = 0; i < probs.length; i++)

-			probs[i] = (kBitModelTotal >>> 1);

-	}

-	

-	public void Encode(short []probs, int index, int symbol) throws IOException

-	{

-		int prob = probs[index];

-		int newBound = (Range >>> kNumBitModelTotalBits) * prob;

-		if (symbol == 0)

-		{

-			Range = newBound;

-			probs[index] = (short)(prob + ((kBitModelTotal - prob) >>> kNumMoveBits));

-		}

-		else

-		{

-			Low += (newBound & 0xFFFFFFFFL);

-			Range -= newBound;

-			probs[index] = (short)(prob - ((prob) >>> kNumMoveBits));

-		}

-		if ((Range & kTopMask) == 0)

-		{

-			Range <<= 8;

-			ShiftLow();

-		}

-	}

-	

-	private static int[] ProbPrices = new int[kBitModelTotal >>> kNumMoveReducingBits];

-	

-	static

-	{

-		int kNumBits = (kNumBitModelTotalBits - kNumMoveReducingBits);

-		for (int i = kNumBits - 1; i >= 0; i--)

-		{

-			int start = 1 << (kNumBits - i - 1);

-			int end = 1 << (kNumBits - i);

-			for (int j = start; j < end; j++)

-				ProbPrices[j] = (i << kNumBitPriceShiftBits) +

-						(((end - j) << kNumBitPriceShiftBits) >>> (kNumBits - i - 1));

-		}

-	}

-	

-	static public int GetPrice(int Prob, int symbol)

-	{

-		return ProbPrices[(((Prob - symbol) ^ ((-symbol))) & (kBitModelTotal - 1)) >>> kNumMoveReducingBits];

-	}

-	static public int GetPrice0(int Prob)

-	{ 

-		return ProbPrices[Prob >>> kNumMoveReducingBits]; 

-	}

-	static public int GetPrice1(int Prob)

-	{ 

-		return ProbPrices[(kBitModelTotal - Prob) >>> kNumMoveReducingBits]; 

-	}

-}

diff --git a/Java/SevenZip/ICodeProgress.java b/Java/SevenZip/ICodeProgress.java
deleted file mode 100644
index 290bd2d..0000000
--- a/Java/SevenZip/ICodeProgress.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package SevenZip;

-

-public interface ICodeProgress

-{

-	public void SetProgress(long inSize, long outSize);

-}

diff --git a/Java/SevenZip/LzmaAlone.java b/Java/SevenZip/LzmaAlone.java
deleted file mode 100644
index de39a22..0000000
--- a/Java/SevenZip/LzmaAlone.java
+++ /dev/null
@@ -1,253 +0,0 @@
-package SevenZip;

-

-public class LzmaAlone

-{

-	static public class CommandLine

-	{

-		public static final int kEncode = 0;

-		public static final int kDecode = 1;

-		public static final int kBenchmak = 2;

-		

-		public int Command = -1;

-		public int NumBenchmarkPasses = 10;

-		

-		public int DictionarySize = 1 << 23;

-		public boolean DictionarySizeIsDefined = false;

-		

-		public int Lc = 3;

-		public int Lp = 0;

-		public int Pb = 2;

-		

-		public int Fb = 128;

-		public boolean FbIsDefined = false;

-		

-		public boolean Eos = false;

-		

-		public int Algorithm = 2;

-		public int MatchFinder = 1;

-		

-		public String InFile;

-		public String OutFile;

-		

-		boolean ParseSwitch(String s)

-		{

-			if (s.startsWith("d"))

-			{

-				DictionarySize = 1 << Integer.parseInt(s.substring(1));

-				DictionarySizeIsDefined = true;

-			}

-			else if (s.startsWith("fb"))

-			{

-				Fb = Integer.parseInt(s.substring(2));

-				FbIsDefined = true;

-			}

-			else if (s.startsWith("a"))

-				Algorithm = Integer.parseInt(s.substring(1));

-			else if (s.startsWith("lc"))

-				Lc = Integer.parseInt(s.substring(2));

-			else if (s.startsWith("lp"))

-				Lp = Integer.parseInt(s.substring(2));

-			else if (s.startsWith("pb"))

-				Pb = Integer.parseInt(s.substring(2));

-			else if (s.startsWith("eos"))

-				Eos = true;

-			else if (s.startsWith("mf"))

-			{

-				String mfs = s.substring(2);

-				if (mfs.equals("bt2"))

-					MatchFinder = 0;

-				else if (mfs.equals("bt4"))

-					MatchFinder = 1;

-				else if (mfs.equals("bt4b"))

-					MatchFinder = 2;

-				else

-					return false;

-			}

-			else

-				return false;

-			return true;

-		}

-		

-		public boolean Parse(String[] args) throws Exception

-		{

-			int pos = 0;

-			boolean switchMode = true;

-			for (int i = 0; i < args.length; i++)

-			{

-				String s = args[i];

-				if (s.length() == 0)

-					return false;

-				if (switchMode)

-				{

-					if (s.compareTo("--") == 0)

-					{

-						switchMode = false;

-						continue;

-					}

-					if (s.charAt(0) == '-')

-					{

-						String sw = s.substring(1).toLowerCase();

-						if (sw.length() == 0)

-							return false;

-						try

-						{

-							if (!ParseSwitch(sw))

-								return false;

-						}

-						catch (NumberFormatException e)

-						{

-							return false;

-						}

-						continue;

-					}

-				}

-				if (pos == 0)

-				{

-					if (s.equalsIgnoreCase("e"))

-						Command = kEncode;

-					else if (s.equalsIgnoreCase("d"))

-						Command = kDecode;

-					else if (s.equalsIgnoreCase("b"))

-						Command = kBenchmak;

-					else

-						return false;

-				}

-				else if(pos == 1)

-				{

-					if (Command == kBenchmak)

-					{

-						try

-						{

-							NumBenchmarkPasses = Integer.parseInt(s);

-							if (NumBenchmarkPasses < 1)

-								return false;

-						}

-						catch (NumberFormatException e)

-						{

-							return false;

-						}

-					}

-					else

-						InFile = s;

-				}

-				else if(pos == 2)

-					OutFile = s;

-				else

-					return false;

-				pos++;

-				continue;

-			}

-			return true;

-		}

-	}

-	

-	

-	static void PrintHelp()

-	{

-		System.out.println(

-				"\nUsage:  LZMA <e|d> [<switches>...] inputFile outputFile\n" +

-				"  e: encode file\n" +

-				"  d: decode file\n" +

-				"  b: Benchmark\n" +

-				"<Switches>\n" +

-				// "  -a{N}:  set compression mode - [0, 1], default: 1 (max)\n" +

-				"  -d{N}:  set dictionary - [0,28], default: 23 (8MB)\n" +

-				"  -fb{N}: set number of fast bytes - [5, 273], default: 128\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{MF_ID}: set Match Finder: [bt2, bt4], default: bt4\n" +

-				"  -eos:   write End Of Stream marker\n"

-				);

-	}

-	

-	public static void main(String[] args) throws Exception

-	{

-		System.out.println("\nLZMA (Java) 4.61  2008-11-23\n");

-		

-		if (args.length < 1)

-		{

-			PrintHelp();

-			return;

-		}

-		

-		CommandLine params = new CommandLine();

-		if (!params.Parse(args))

-		{

-			System.out.println("\nIncorrect command");

-			return;

-		}

-		

-		if (params.Command == CommandLine.kBenchmak)

-		{

-			int dictionary = (1 << 21);

-			if (params.DictionarySizeIsDefined)

-				dictionary = params.DictionarySize;

-			if (params.MatchFinder > 1)

-				throw new Exception("Unsupported match finder");

-			SevenZip.LzmaBench.LzmaBenchmark(params.NumBenchmarkPasses, dictionary);

-		}

-		else if (params.Command == CommandLine.kEncode || params.Command == CommandLine.kDecode)

-		{

-			java.io.File inFile = new java.io.File(params.InFile);

-			java.io.File outFile = new java.io.File(params.OutFile);

-			

-			java.io.BufferedInputStream inStream  = new java.io.BufferedInputStream(new java.io.FileInputStream(inFile));

-			java.io.BufferedOutputStream outStream = new java.io.BufferedOutputStream(new java.io.FileOutputStream(outFile));

-			

-			boolean eos = false;

-			if (params.Eos)

-				eos = true;

-			if (params.Command == CommandLine.kEncode)

-			{

-				SevenZip.Compression.LZMA.Encoder encoder = new SevenZip.Compression.LZMA.Encoder();

-				if (!encoder.SetAlgorithm(params.Algorithm))

-					throw new Exception("Incorrect compression mode");

-				if (!encoder.SetDictionarySize(params.DictionarySize))

-					throw new Exception("Incorrect dictionary size");

-				if (!encoder.SetNumFastBytes(params.Fb))

-					throw new Exception("Incorrect -fb value");

-				if (!encoder.SetMatchFinder(params.MatchFinder))

-					throw new Exception("Incorrect -mf value");

-				if (!encoder.SetLcLpPb(params.Lc, params.Lp, params.Pb))

-					throw new Exception("Incorrect -lc or -lp or -pb value");

-				encoder.SetEndMarkerMode(eos);

-				encoder.WriteCoderProperties(outStream);

-				long fileSize;

-				if (eos)

-					fileSize = -1;

-				else

-					fileSize = inFile.length();

-				for (int i = 0; i < 8; i++)

-					outStream.write((int)(fileSize >>> (8 * i)) & 0xFF);

-				encoder.Code(inStream, outStream, -1, -1, null);

-			}

-			else

-			{

-				int propertiesSize = 5;

-				byte[] properties = new byte[propertiesSize];

-				if (inStream.read(properties, 0, propertiesSize) != propertiesSize)

-					throw new Exception("input .lzma file is too short");

-				SevenZip.Compression.LZMA.Decoder decoder = new SevenZip.Compression.LZMA.Decoder();

-				if (!decoder.SetDecoderProperties(properties))

-					throw new Exception("Incorrect stream properties");

-				long outSize = 0;

-				for (int i = 0; i < 8; i++)

-				{

-					int v = inStream.read();

-					if (v < 0)

-						throw new Exception("Can't read stream size");

-					outSize |= ((long)v) << (8 * i);

-				}

-				if (!decoder.Code(inStream, outStream, outSize))

-					throw new Exception("Error in data stream");

-			}

-			outStream.flush();

-			outStream.close();

-			inStream.close();

-		}

-		else

-			throw new Exception("Incorrect command");

-		return;

-	}

-}

diff --git a/Java/SevenZip/LzmaBench.java b/Java/SevenZip/LzmaBench.java
deleted file mode 100644
index cceda24..0000000
--- a/Java/SevenZip/LzmaBench.java
+++ /dev/null
@@ -1,392 +0,0 @@
-package SevenZip;

-

-import java.io.ByteArrayOutputStream;

-import java.io.ByteArrayInputStream;

-import java.io.IOException;

-

-public class LzmaBench

-{

-	static final int kAdditionalSize = (1 << 21);

-	static final int kCompressedAdditionalSize = (1 << 10);

-	

-	static class CRandomGenerator

-	{

-		int A1;

-		int A2;

-		public CRandomGenerator() { Init(); }

-		public void Init() { A1 = 362436069; A2 = 521288629; }

-		public int GetRnd()

-		{

-			return

-				((A1 = 36969 * (A1 & 0xffff) + (A1 >>> 16)) << 16) ^

-				((A2 = 18000 * (A2 & 0xffff) + (A2 >>> 16)));

-		}

-	};

-	

-	static class CBitRandomGenerator

-	{

-		CRandomGenerator RG = new CRandomGenerator();

-		int Value;

-		int NumBits;

-		public void Init()

-		{

-			Value = 0;

-			NumBits = 0;

-		}

-		public int GetRnd(int numBits)

-		{

-			int result;

-			if (NumBits > numBits)

-			{

-				result = Value & ((1 << numBits) - 1);

-				Value >>>= numBits;

-				NumBits -= numBits;

-				return result;

-			}

-			numBits -= NumBits;

-			result = (Value << numBits);

-			Value = RG.GetRnd();

-			result |= Value & (((int)1 << numBits) - 1);

-			Value >>>= numBits;

-			NumBits = 32 - numBits;

-			return result;

-		}

-	};

-	

-	static class CBenchRandomGenerator

-	{

-		CBitRandomGenerator RG = new CBitRandomGenerator();

-		int Pos;

-		int Rep0;

-

-		public int BufferSize;

-		public byte[] Buffer = null;

-

-		public CBenchRandomGenerator() { }

-		public void Set(int bufferSize)

-		{

-			Buffer = new byte[bufferSize];

-			Pos = 0;

-			BufferSize = bufferSize;

-		}

-		int GetRndBit() { return RG.GetRnd(1); }

-		int GetLogRandBits(int numBits)

-		{

-			int len = RG.GetRnd(numBits);

-			return RG.GetRnd((int)len);

-		}

-		int GetOffset()

-		{

-			if (GetRndBit() == 0)

-				return GetLogRandBits(4);

-			return (GetLogRandBits(4) << 10) | RG.GetRnd(10);

-		}

-		int GetLen1() { return RG.GetRnd(1 + (int)RG.GetRnd(2)); }

-		int GetLen2() { return RG.GetRnd(2 + (int)RG.GetRnd(2)); }

-		public void Generate()

-		{

-			RG.Init();

-			Rep0 = 1;

-			while (Pos < BufferSize)

-			{

-				if (GetRndBit() == 0 || Pos < 1)

-					Buffer[Pos++] = (byte)(RG.GetRnd(8));

-				else

-				{

-					int len;

-					if (RG.GetRnd(3) == 0)

-						len = 1 + GetLen1();

-					else

-					{

-						do

-							Rep0 = GetOffset();

-						while (Rep0 >= Pos);

-						Rep0++;

-						len = 2 + GetLen2();

-					}

-					for (int i = 0; i < len && Pos < BufferSize; i++, Pos++)

-						Buffer[Pos] = Buffer[Pos - Rep0];

-				}

-			}

-		}

-	};

-	

-	static class CrcOutStream extends java.io.OutputStream

-	{

-		public CRC CRC = new CRC();

-		

-		public void Init()

-		{ 

-			CRC.Init(); 

-		}

-		public int GetDigest()

-		{ 

-			return CRC.GetDigest(); 

-		}

-		public void write(byte[] b)

-		{

-			CRC.Update(b);

-		}

-		public void write(byte[] b, int off, int len)

-		{

-			CRC.Update(b, off, len);

-		}

-		public void write(int b)

-		{

-			CRC.UpdateByte(b);

-		}

-	};

-

-	static class MyOutputStream extends java.io.OutputStream

-	{

-		byte[] _buffer;

-		int _size;

-		int _pos;

-		

-		public MyOutputStream(byte[] buffer)

-		{

-			_buffer = buffer;

-			_size = _buffer.length;

-		}

-		

-		public void reset()

-		{ 

-			_pos = 0; 

-		}

-		

-		public void write(int b) throws IOException

-		{

-			if (_pos >= _size)

-				throw new IOException("Error");

-			_buffer[_pos++] = (byte)b;

-		}

-		

-		public int size()

-		{

-			return _pos;

-		}

-	};

-

-	static class MyInputStream extends java.io.InputStream

-	{

-		byte[] _buffer;

-		int _size;

-		int _pos;

-		

-		public MyInputStream(byte[] buffer, int size)

-		{

-			_buffer = buffer;

-			_size = size;

-		}

-		

-		public void reset()

-		{ 

-			_pos = 0; 

-		}

-		

-		public int read()

-		{

-			if (_pos >= _size)

-				return -1;

-			return _buffer[_pos++] & 0xFF;

-		}

-	};

-	

-	static class CProgressInfo implements ICodeProgress

-	{

-		public long ApprovedStart;

-		public long InSize;

-		public long Time;

-		public void Init()

-		{ InSize = 0; }

-		public void SetProgress(long inSize, long outSize)

-		{

-			if (inSize >= ApprovedStart && InSize == 0)

-			{

-				Time = System.currentTimeMillis();

-				InSize = inSize;

-			}

-		}

-	}

-	static final int kSubBits = 8;

-	

-	static int GetLogSize(int size)

-	{

-		for (int i = kSubBits; i < 32; i++)

-			for (int j = 0; j < (1 << kSubBits); j++)

-				if (size <= ((1) << i) + (j << (i - kSubBits)))

-					return (i << kSubBits) + j;

-		return (32 << kSubBits);

-	}

-	

-	static long MyMultDiv64(long value, long elapsedTime)

-	{

-		long freq = 1000; // ms

-		long elTime = elapsedTime;

-		while (freq > 1000000)

-		{

-			freq >>>= 1;

-			elTime >>>= 1;

-		}

-		if (elTime == 0)

-			elTime = 1;

-		return value * freq / elTime;

-	}

-	

-	static long GetCompressRating(int dictionarySize, long elapsedTime, long size)

-	{

-		long t = GetLogSize(dictionarySize) - (18 << kSubBits);

-		long numCommandsForOne = 1060 + ((t * t * 10) >> (2 * kSubBits));

-		long numCommands = (long)(size) * numCommandsForOne;

-		return MyMultDiv64(numCommands, elapsedTime);

-	}

-	

-	static long GetDecompressRating(long elapsedTime, long outSize, long inSize)

-	{

-		long numCommands = inSize * 220 + outSize * 20;

-		return MyMultDiv64(numCommands, elapsedTime);

-	}

-	

-	static long GetTotalRating(

-			int dictionarySize,

-			long elapsedTimeEn, long sizeEn,

-			long elapsedTimeDe,

-			long inSizeDe, long outSizeDe)

-	{

-		return (GetCompressRating(dictionarySize, elapsedTimeEn, sizeEn) +

-				GetDecompressRating(elapsedTimeDe, inSizeDe, outSizeDe)) / 2;

-	}

-	

-	static void PrintValue(long v)

-	{

-		String s = "";

-		s += v;

-		for (int i = 0; i + s.length() < 6; i++)

-			System.out.print(" ");

-		System.out.print(s);

-	}

-	

-	static void PrintRating(long rating)

-	{

-		PrintValue(rating / 1000000);

-		System.out.print(" MIPS");

-	}

-	

-	static void PrintResults(

-			int dictionarySize,

-			long elapsedTime,

-			long size,

-			boolean decompressMode, long secondSize)

-	{

-		long speed = MyMultDiv64(size, elapsedTime);

-		PrintValue(speed / 1024);

-		System.out.print(" KB/s  ");

-		long rating;

-		if (decompressMode)

-			rating = GetDecompressRating(elapsedTime, size, secondSize);

-		else

-			rating = GetCompressRating(dictionarySize, elapsedTime, size);

-		PrintRating(rating);

-	}

-	

-	static public int LzmaBenchmark(int numIterations, int dictionarySize) throws Exception

-	{

-		if (numIterations <= 0)

-			return 0;

-		if (dictionarySize < (1 << 18))

-		{

-			System.out.println("\nError: dictionary size for benchmark must be >= 18 (256 KB)");

-			return 1;

-		}

-		System.out.print("\n       Compressing                Decompressing\n\n");

-		

-		SevenZip.Compression.LZMA.Encoder encoder = new SevenZip.Compression.LZMA.Encoder();

-		SevenZip.Compression.LZMA.Decoder decoder = new SevenZip.Compression.LZMA.Decoder();

-		

-		if (!encoder.SetDictionarySize(dictionarySize))

-			throw new Exception("Incorrect dictionary size");

-		

-		int kBufferSize = dictionarySize + kAdditionalSize;

-		int kCompressedBufferSize = (kBufferSize / 2) + kCompressedAdditionalSize;

-		

-		ByteArrayOutputStream propStream = new ByteArrayOutputStream();

-		encoder.WriteCoderProperties(propStream);

-		byte[] propArray = propStream.toByteArray();

-		decoder.SetDecoderProperties(propArray);

-		

-		CBenchRandomGenerator rg = new CBenchRandomGenerator();

-

-		rg.Set(kBufferSize);

-		rg.Generate();

-		CRC crc = new CRC();

-		crc.Init();

-		crc.Update(rg.Buffer, 0, rg.BufferSize);

-		

-		CProgressInfo progressInfo = new CProgressInfo();

-		progressInfo.ApprovedStart = dictionarySize;

-		

-		long totalBenchSize = 0;

-		long totalEncodeTime = 0;

-		long totalDecodeTime = 0;

-		long totalCompressedSize = 0;

-		

-		MyInputStream inStream = new MyInputStream(rg.Buffer, rg.BufferSize);

-

-		byte[] compressedBuffer = new byte[kCompressedBufferSize];

-		MyOutputStream compressedStream = new MyOutputStream(compressedBuffer);

-		CrcOutStream crcOutStream = new CrcOutStream();

-		MyInputStream inputCompressedStream = null;

-		int compressedSize = 0;

-		for (int i = 0; i < numIterations; i++)

-		{

-			progressInfo.Init();

-			inStream.reset();

-			compressedStream.reset();

-			encoder.Code(inStream, compressedStream, -1, -1, progressInfo);

-			long encodeTime = System.currentTimeMillis() - progressInfo.Time;

-			

-			if (i == 0)

-			{

-				compressedSize = compressedStream.size();

-				inputCompressedStream = new MyInputStream(compressedBuffer, compressedSize);

-			}

-			else if (compressedSize != compressedStream.size())

-				throw (new Exception("Encoding error"));

-				

-			if (progressInfo.InSize == 0)

-				throw (new Exception("Internal ERROR 1282"));

-

-			long decodeTime = 0;

-			for (int j = 0; j < 2; j++)

-			{

-				inputCompressedStream.reset();

-				crcOutStream.Init();

-				

-				long outSize = kBufferSize;

-				long startTime = System.currentTimeMillis();

-				if (!decoder.Code(inputCompressedStream, crcOutStream, outSize))

-					throw (new Exception("Decoding Error"));;

-				decodeTime = System.currentTimeMillis() - startTime;

-				if (crcOutStream.GetDigest() != crc.GetDigest())

-					throw (new Exception("CRC Error"));

-			}

-			long benchSize = kBufferSize - (long)progressInfo.InSize;

-			PrintResults(dictionarySize, encodeTime, benchSize, false, 0);

-			System.out.print("     ");

-			PrintResults(dictionarySize, decodeTime, kBufferSize, true, compressedSize);

-			System.out.println();

-			

-			totalBenchSize += benchSize;

-			totalEncodeTime += encodeTime;

-			totalDecodeTime += decodeTime;

-			totalCompressedSize += compressedSize;

-		}

-		System.out.println("---------------------------------------------------");

-		PrintResults(dictionarySize, totalEncodeTime, totalBenchSize, false, 0);

-		System.out.print("     ");

-		PrintResults(dictionarySize, totalDecodeTime,

-				kBufferSize * (long)numIterations, true, totalCompressedSize);

-		System.out.println("    Average");

-		return 0;

-	}

-}

diff --git a/METADATA b/METADATA
index 102ab5b..50c7d6e 100644
--- a/METADATA
+++ b/METADATA
@@ -1,19 +1,20 @@
+# This project was upgraded with external_updater.
+# Usage: tools/external_updater/updater.sh update external/lzma
+# For more info, check https://cs.android.com/android/platform/superproject/+/main:tools/external_updater/README.md
+
 name: "lzma"
 description: "LZMA is default and general compression method of 7z format."
 third_party {
-  url {
-    type: HOMEPAGE
-    value: "https://7-zip.org/"
-  }
-  url {
-    type: ARCHIVE
-    value: "https://7-zip.org/a/lzma1900.7z"
-  }
-  version: "19.00"
   license_type: UNENCUMBERED
   last_upgrade_date {
-    year: 2023
-    month: 2
-    day: 14
+    year: 2024
+    month: 4
+    day: 18
+  }
+  homepage: "https://7-zip.org/"
+  identifier {
+    type: "Archive"
+    value: "https://github.com/ip7z/7zip/archive/23.01.tar.gz"
+    version: "23.01"
   }
 }
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..e1e4514
--- /dev/null
+++ b/README.md
@@ -0,0 +1,2 @@
+# 7-Zip on GitHub
+7-Zip website: [7-zip.org](https://7-zip.org)