Project import
diff --git a/lzma/Android.bp b/lzma/Android.bp
new file mode 100644
index 0000000..e0454ba
--- /dev/null
+++ b/lzma/Android.bp
@@ -0,0 +1 @@
+subdirs = ["C"]
diff --git a/lzma/Android.mk b/lzma/Android.mk
new file mode 100644
index 0000000..93dd9d4
--- /dev/null
+++ b/lzma/Android.mk
@@ -0,0 +1,4 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(call first-makefiles-under,$(LOCAL_PATH))
+
diff --git a/lzma/Asm/arm/7zCrcOpt.asm b/lzma/Asm/arm/7zCrcOpt.asm
new file mode 100644
index 0000000..f008d65
--- /dev/null
+++ b/lzma/Asm/arm/7zCrcOpt.asm
@@ -0,0 +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
diff --git a/lzma/Asm/x86/7zAsm.asm b/lzma/Asm/x86/7zAsm.asm
new file mode 100644
index 0000000..53a9e3f
--- /dev/null
+++ b/lzma/Asm/x86/7zAsm.asm
@@ -0,0 +1,105 @@
+; 7zAsm.asm -- ASM macros
+; 2012-12-30 : 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_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
+ 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
diff --git a/lzma/Asm/x86/7zCrcOpt.asm b/lzma/Asm/x86/7zCrcOpt.asm
new file mode 100644
index 0000000..2de5171
--- /dev/null
+++ b/lzma/Asm/x86/7zCrcOpt.asm
@@ -0,0 +1,147 @@
+; 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
diff --git a/lzma/Asm/x86/AesOpt.asm b/lzma/Asm/x86/AesOpt.asm
new file mode 100644
index 0000000..c32e48f
--- /dev/null
+++ b/lzma/Asm/x86/AesOpt.asm
@@ -0,0 +1,237 @@
+; 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
diff --git a/lzma/Asm/x86/XzCrc64Opt.asm b/lzma/Asm/x86/XzCrc64Opt.asm
new file mode 100644
index 0000000..3e6d490
--- /dev/null
+++ b/lzma/Asm/x86/XzCrc64Opt.asm
@@ -0,0 +1,205 @@
+; 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
diff --git a/lzma/C/7z.h b/lzma/C/7z.h
new file mode 100644
index 0000000..dc25f53
--- /dev/null
+++ b/lzma/C/7z.h
@@ -0,0 +1,216 @@
+/* 7z.h -- 7z interface
+2013-01-18 : Igor Pavlov : Public domain */
+
+#ifndef __7Z_H
+#define __7Z_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+#define k7zStartHeaderSize 0x20
+#define k7zSignatureSize 6
+
+extern 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 NumInStreams;
+ Byte NumOutStreams;
+ Byte PropsSize;
+} CSzCoderInfo;
+
+typedef struct
+{
+ UInt32 InIndex;
+ UInt32 OutIndex;
+} CSzBindPair;
+
+#define SZ_NUM_CODERS_IN_FOLDER_MAX 4
+#define SZ_NUM_BINDS_IN_FOLDER_MAX 3
+#define SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX 4
+#define SZ_NUM_CODERS_OUT_STREAMS_IN_FOLDER_MAX 4
+
+typedef struct
+{
+ UInt32 NumCoders;
+ UInt32 NumBindPairs;
+ UInt32 NumPackStreams;
+ UInt32 MainOutStream;
+ UInt32 PackStreams[SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX];
+ CSzBindPair BindPairs[SZ_NUM_BINDS_IN_FOLDER_MAX];
+ CSzCoderInfo Coders[SZ_NUM_CODERS_IN_FOLDER_MAX];
+ UInt64 CodersUnpackSizes[SZ_NUM_CODERS_OUT_STREAMS_IN_FOLDER_MAX];
+} CSzFolder;
+
+/*
+typedef struct
+{
+ size_t CodersDataOffset;
+ size_t UnpackSizeDataOffset;
+ // UInt32 StartCoderUnpackSizesIndex;
+ UInt32 StartPackStreamIndex;
+ // UInt32 IndexOfMainOutStream;
+} CSzFolder2;
+*/
+
+SRes SzGetNextFolderItem(CSzFolder *f, CSzData *sd, CSzData *sdSizes);
+
+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;
+
+ size_t *FoCodersOffsets;
+ size_t *FoSizesOffsets;
+ // UInt32 StartCoderUnpackSizesIndex;
+ UInt32 *FoStartPackStreamIndex;
+
+ // CSzFolder2 *Folders; // +1 item for sum values
+ Byte *CodersData;
+ Byte *UnpackSizesData;
+ size_t UnpackSizesDataSize;
+ // UInt64 *CoderUnpackSizes;
+} CSzAr;
+
+
+SRes SzAr_DecodeFolder(const CSzAr *p, UInt32 folderIndex,
+ ILookInStream *stream, UInt64 startPos,
+ Byte *outBuffer, size_t outSize,
+ ISzAlloc *allocMain);
+
+/*
+ SzExtract 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.
+*/
+
+typedef struct
+{
+ CSzAr db;
+
+ UInt64 startPosAfterHeader;
+ UInt64 dataPos;
+
+ UInt32 NumFiles;
+
+ UInt64 *UnpackPositions;
+ // Byte *IsEmptyFiles;
+ Byte *IsDirs;
+ CSzBitUi32s CRCs;
+
+ CSzBitUi32s Attribs;
+ // CSzBitUi32s Parents;
+ CSzBitUi64s MTime;
+ CSzBitUi64s CTime;
+
+ // UInt32 *FolderStartPackStreamIndex;
+ UInt32 *FolderStartFileIndex; // + 1
+ UInt32 *FileIndexToFolderIndexMap;
+
+ 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, ISzAlloc *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);
+*/
+
+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 */
+ ISzAlloc *allocMain,
+ ISzAlloc *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,
+ ISzAlloc *allocMain, ISzAlloc *allocTemp);
+
+EXTERN_C_END
+
+#endif
diff --git a/lzma/C/7zAlloc.c b/lzma/C/7zAlloc.c
new file mode 100644
index 0000000..698071c
--- /dev/null
+++ b/lzma/C/7zAlloc.c
@@ -0,0 +1,78 @@
+/* 7zAlloc.c -- Allocation functions
+2010-10-29 : Igor Pavlov : Public domain */
+
+#include "Precomp.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(void *p, size_t size)
+{
+ p = p;
+ if (size == 0)
+ return 0;
+ #ifdef _SZ_ALLOC_DEBUG
+ fprintf(stderr, "\nAlloc %10d bytes; count = %10d", size, g_allocCount);
+ g_allocCount++;
+ #endif
+ return malloc(size);
+}
+
+void SzFree(void *p, void *address)
+{
+ p = p;
+ #ifdef _SZ_ALLOC_DEBUG
+ if (address != 0)
+ {
+ g_allocCount--;
+ fprintf(stderr, "\nFree; count = %10d", g_allocCount);
+ }
+ #endif
+ free(address);
+}
+
+void *SzAllocTemp(void *p, size_t size)
+{
+ p = p;
+ if (size == 0)
+ return 0;
+ #ifdef _SZ_ALLOC_DEBUG
+ fprintf(stderr, "\nAlloc_temp %10d bytes; count = %10d", size, g_allocCountTemp);
+ g_allocCountTemp++;
+ #ifdef _WIN32
+ return HeapAlloc(GetProcessHeap(), 0, size);
+ #endif
+ #endif
+ return malloc(size);
+}
+
+void SzFreeTemp(void *p, void *address)
+{
+ p = 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);
+}
diff --git a/lzma/C/7zAlloc.h b/lzma/C/7zAlloc.h
new file mode 100644
index 0000000..860f116
--- /dev/null
+++ b/lzma/C/7zAlloc.h
@@ -0,0 +1,15 @@
+/* 7zAlloc.h -- Allocation functions
+2010-10-29 : Igor Pavlov : Public domain */
+
+#ifndef __7Z_ALLOC_H
+#define __7Z_ALLOC_H
+
+#include <stdlib.h>
+
+void *SzAlloc(void *p, size_t size);
+void SzFree(void *p, void *address);
+
+void *SzAllocTemp(void *p, size_t size);
+void SzFreeTemp(void *p, void *address);
+
+#endif
diff --git a/lzma/C/7zArcIn.c b/lzma/C/7zArcIn.c
new file mode 100644
index 0000000..5fd4f6b
--- /dev/null
+++ b/lzma/C/7zArcIn.c
@@ -0,0 +1,1839 @@
+/* 7zArcIn.c -- 7z Input functions
+2014-06-16 : 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 ((size) == 0) p = 0; else \
+ if ((p = (T *)IAlloc_Alloc(alloc, (size) * sizeof(T))) == 0) return SZ_ERROR_MEM; }
+
+#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
+};
+
+Byte k7zSignature[k7zSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C};
+
+#define NUM_FOLDER_CODERS_MAX 32
+#define NUM_CODER_STREAMS_MAX 32
+
+/*
+static int SzFolder_FindBindPairForInStream(const CSzFolder *p, UInt32 inStreamIndex)
+{
+ UInt32 i;
+ for (i = 0; i < p->NumBindPairs; i++)
+ if (p->BindPairs[i].InIndex == inStreamIndex)
+ return i;
+ return -1;
+}
+*/
+
+#define SzBitUi32s_Init(p) { (p)->Defs = 0; (p)->Vals = 0; }
+
+static SRes SzBitUi32s_Alloc(CSzBitUi32s *p, size_t num, ISzAlloc *alloc)
+{
+ MY_ALLOC(Byte, p->Defs, (num + 7) >> 3, alloc);
+ MY_ALLOC(UInt32, p->Vals, num, alloc);
+ return SZ_OK;
+}
+
+void SzBitUi32s_Free(CSzBitUi32s *p, ISzAlloc *alloc)
+{
+ IAlloc_Free(alloc, p->Defs); p->Defs = 0;
+ IAlloc_Free(alloc, p->Vals); p->Vals = 0;
+}
+
+#define SzBitUi64s_Init(p) { (p)->Defs = 0; (p)->Vals = 0; }
+
+void SzBitUi64s_Free(CSzBitUi64s *p, ISzAlloc *alloc)
+{
+ IAlloc_Free(alloc, p->Defs); p->Defs = 0;
+ IAlloc_Free(alloc, p->Vals); p->Vals = 0;
+}
+
+static void SzAr_Init(CSzAr *p)
+{
+ p->NumPackStreams = 0;
+ p->NumFolders = 0;
+ p->PackPositions = 0;
+ SzBitUi32s_Init(&p->FolderCRCs);
+ // p->Folders = 0;
+ p->FoCodersOffsets = 0;
+ p->FoSizesOffsets = 0;
+ p->FoStartPackStreamIndex = 0;
+
+ p->CodersData = 0;
+ // p->CoderUnpackSizes = 0;
+ p->UnpackSizesData = 0;
+}
+
+static void SzAr_Free(CSzAr *p, ISzAlloc *alloc)
+{
+ IAlloc_Free(alloc, p->UnpackSizesData);
+ IAlloc_Free(alloc, p->CodersData);
+ // IAlloc_Free(alloc, p->CoderUnpackSizes);
+
+ IAlloc_Free(alloc, p->PackPositions);
+
+ // IAlloc_Free(alloc, p->Folders);
+ IAlloc_Free(alloc, p->FoCodersOffsets);
+ IAlloc_Free(alloc, p->FoSizesOffsets);
+ IAlloc_Free(alloc, p->FoStartPackStreamIndex);
+
+ SzBitUi32s_Free(&p->FolderCRCs, alloc);
+
+ SzAr_Init(p);
+}
+
+
+void SzArEx_Init(CSzArEx *p)
+{
+ SzAr_Init(&p->db);
+ p->NumFiles = 0;
+ p->dataPos = 0;
+ // p->Files = 0;
+ p->UnpackPositions = 0;
+ // p->IsEmptyFiles = 0;
+ p->IsDirs = 0;
+ // p->FolderStartPackStreamIndex = 0;
+ // p->PackStreamStartPositions = 0;
+ p->FolderStartFileIndex = 0;
+ p->FileIndexToFolderIndexMap = 0;
+ p->FileNameOffsets = 0;
+ p->FileNames = 0;
+ 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, ISzAlloc *alloc)
+{
+ // IAlloc_Free(alloc, p->FolderStartPackStreamIndex);
+ // IAlloc_Free(alloc, p->PackStreamStartPositions);
+ IAlloc_Free(alloc, p->FolderStartFileIndex);
+ IAlloc_Free(alloc, p->FileIndexToFolderIndexMap);
+
+ IAlloc_Free(alloc, p->FileNameOffsets);
+ IAlloc_Free(alloc, p->FileNames);
+
+ SzBitUi64s_Free(&p->CTime, alloc);
+ SzBitUi64s_Free(&p->MTime, alloc);
+ SzBitUi32s_Free(&p->CRCs, alloc);
+ // SzBitUi32s_Free(&p->Parents, alloc);
+ SzBitUi32s_Free(&p->Attribs, alloc);
+ IAlloc_Free(alloc, p->IsDirs);
+ // IAlloc_Free(alloc, p->IsEmptyFiles);
+ IAlloc_Free(alloc, p->UnpackPositions);
+ // IAlloc_Free(alloc, p->Files);
+
+ SzAr_Free(&p->db, alloc);
+ SzArEx_Init(p);
+}
+
+static int TestSignatureCandidate(Byte *testBytes)
+{
+ size_t i;
+ for (i = 0; i < k7zSignatureSize; i++)
+ if (testBytes[i] != k7zSignature[i])
+ return 0;
+ return 1;
+}
+
+#define SzData_Clear(p) { (p)->Data = 0; (p)->Size = 0; }
+
+static SRes SzReadByte(CSzData *sd, Byte *b)
+{
+ if (sd->Size == 0)
+ return SZ_ERROR_ARCHIVE;
+ sd->Size--;
+ *b = *sd->Data++;
+ return SZ_OK;
+}
+
+#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 = firstByte & (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 const Byte *SzReadNumbers(const Byte *data, const Byte *dataLim, UInt64 *values, UInt32 num)
+{
+ for (; num != 0; num--)
+ {
+ Byte firstByte;
+ Byte mask;
+
+ unsigned i;
+ UInt32 v;
+ UInt64 value;
+
+ if (data == dataLim)
+ return NULL;
+ firstByte = *data++;
+
+ if ((firstByte & 0x80) == 0)
+ {
+ *values++ = firstByte;
+ continue;
+ }
+ if (data == dataLim)
+ return NULL;
+ v = *data++;
+ if ((firstByte & 0x40) == 0)
+ {
+ *values++ = (((UInt32)firstByte & 0x3F) << 8) | v;
+ continue;
+ }
+ if (data == dataLim)
+ return NULL;
+ value = v | ((UInt32)*data++ << 8);
+ mask = 0x20;
+ for (i = 2; i < 8; i++)
+ {
+ if ((firstByte & mask) == 0)
+ {
+ UInt64 highPart = firstByte & (mask - 1);
+ value |= (highPart << (8 * i));
+ break;
+ }
+ if (data == dataLim)
+ return NULL;
+ value |= ((UInt64)*data++ << (8 * i));
+ mask >>= 1;
+ }
+ *values++ = value;
+ }
+ return data;
+}
+*/
+
+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, UInt64 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, ISzAlloc *alloc)
+{
+ Byte allAreDefined;
+ UInt32 i;
+ Byte *v2;
+ UInt32 numBytes = (numItems + 7) >> 3;
+ RINOK(SzReadByte(sd, &allAreDefined));
+ if (allAreDefined == 0)
+ {
+ if (numBytes > sd->Size)
+ return SZ_ERROR_ARCHIVE;
+ MY_ALLOC(Byte, *v, numBytes, alloc);
+ memcpy(*v, sd->Data, numBytes);
+ SKIP_DATA(sd, numBytes);
+ return SZ_OK;
+ }
+ MY_ALLOC(Byte, *v, numBytes, alloc);
+ v2 = *v;
+ for (i = 0; i < numBytes; i++)
+ v2[i] = 0xFF;
+ {
+ unsigned numBits = (unsigned)numItems & 7;
+ if (numBits != 0)
+ v2[numBytes - 1] = (Byte)((((UInt32)1 << numBits) - 1) << (8 - numBits));
+ }
+ return SZ_OK;
+}
+
+static MY_NO_INLINE SRes ReadUi32s(CSzData *sd2, UInt32 numItems, CSzBitUi32s *crcs, ISzAlloc *alloc)
+{
+ UInt32 i;
+ CSzData sd;
+ UInt32 *vals;
+ const Byte *defs;
+ MY_ALLOC(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, ISzAlloc *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;
+ RINOK(SzReadByte(sd, &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, ISzAlloc *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 SZ_NUM_IN_STREAMS_IN_FOLDER_MAX 16
+
+SRes SzGetNextFolderItem(CSzFolder *f, CSzData *sd, CSzData *sdSizes)
+{
+ UInt32 numCoders, numBindPairs, numPackStreams, i;
+ UInt32 numInStreams = 0, numOutStreams = 0;
+ const Byte *dataStart = sd->Data;
+ Byte inStreamUsed[SZ_NUM_IN_STREAMS_IN_FOLDER_MAX];
+
+ RINOK(SzReadNumber32(sd, &numCoders));
+ if (numCoders > SZ_NUM_CODERS_IN_FOLDER_MAX)
+ return SZ_ERROR_UNSUPPORTED;
+ f->NumCoders = numCoders;
+
+ for (i = 0; i < numCoders; i++)
+ {
+ Byte mainByte;
+ CSzCoderInfo *coder = f->Coders + i;
+ unsigned idSize, j;
+ UInt64 id;
+ RINOK(SzReadByte(sd, &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->NumInStreams = 1;
+ coder->NumOutStreams = 1;
+ coder->PropsOffset = 0;
+ coder->PropsSize = 0;
+
+ if ((mainByte & 0x10) != 0)
+ {
+ UInt32 numStreams;
+ RINOK(SzReadNumber32(sd, &numStreams));
+ if (numStreams > NUM_CODER_STREAMS_MAX)
+ return SZ_ERROR_UNSUPPORTED;
+ coder->NumInStreams = (Byte)numStreams;
+ RINOK(SzReadNumber32(sd, &numStreams));
+ if (numStreams > NUM_CODER_STREAMS_MAX)
+ return SZ_ERROR_UNSUPPORTED;
+ coder->NumOutStreams = (Byte)numStreams;
+ }
+ if ((mainByte & 0x20) != 0)
+ {
+ UInt32 propsSize = 0;
+ RINOK(SzReadNumber32(sd, &propsSize));
+ if (propsSize >= 0x40)
+ return SZ_ERROR_UNSUPPORTED;
+ if (propsSize > sd->Size)
+ return SZ_ERROR_ARCHIVE;
+ coder->PropsOffset = sd->Data - dataStart;
+ coder->PropsSize = (Byte)propsSize;
+ sd->Data += (size_t)propsSize;
+ sd->Size -= (size_t)propsSize;
+ }
+ numInStreams += coder->NumInStreams;
+ numOutStreams += coder->NumOutStreams;
+ }
+
+ if (numOutStreams == 0)
+ return SZ_ERROR_UNSUPPORTED;
+
+ f->NumBindPairs = numBindPairs = numOutStreams - 1;
+ if (numInStreams < numBindPairs)
+ return SZ_ERROR_ARCHIVE;
+ if (numInStreams > SZ_NUM_IN_STREAMS_IN_FOLDER_MAX)
+ return SZ_ERROR_UNSUPPORTED;
+ f->MainOutStream = 0;
+ f->NumPackStreams = numPackStreams = numInStreams - numBindPairs;
+ if (numPackStreams > SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX)
+ return SZ_ERROR_UNSUPPORTED;
+ for (i = 0; i < numInStreams; i++)
+ inStreamUsed[i] = False;
+ if (numBindPairs != 0)
+ {
+ Byte outStreamUsed[SZ_NUM_CODERS_OUT_STREAMS_IN_FOLDER_MAX];
+
+ if (numBindPairs > SZ_NUM_BINDS_IN_FOLDER_MAX)
+ return SZ_ERROR_UNSUPPORTED;
+
+ for (i = 0; i < numOutStreams; i++)
+ outStreamUsed[i] = False;
+
+ for (i = 0; i < numBindPairs; i++)
+ {
+ CSzBindPair *bp = f->BindPairs + i;
+ RINOK(SzReadNumber32(sd, &bp->InIndex));
+ if (bp->InIndex >= numInStreams)
+ return SZ_ERROR_ARCHIVE;
+ inStreamUsed[bp->InIndex] = True;
+ RINOK(SzReadNumber32(sd, &bp->OutIndex));
+ if (bp->OutIndex >= numInStreams)
+ return SZ_ERROR_ARCHIVE;
+ outStreamUsed[bp->OutIndex] = True;
+ }
+ for (i = 0; i < numOutStreams; i++)
+ if (!outStreamUsed[i])
+ {
+ f->MainOutStream = i;
+ break;
+ }
+ if (i == numOutStreams)
+ return SZ_ERROR_ARCHIVE;
+ }
+
+ if (numPackStreams == 1)
+ {
+ for (i = 0; i < numInStreams; i++)
+ if (!inStreamUsed[i])
+ break;
+ if (i == numInStreams)
+ return SZ_ERROR_ARCHIVE;
+ f->PackStreams[0] = i;
+ }
+ else
+ for (i = 0; i < numPackStreams; i++)
+ {
+ RINOK(SzReadNumber32(sd, f->PackStreams + i));
+ }
+
+ for (i = 0; i < numOutStreams; i++)
+ {
+ RINOK(ReadNumber(sdSizes, f->CodersUnpackSizes + i));
+ }
+
+ 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_InStreamUsed_MAX 64
+#define k_OutStreamUsed_MAX 64
+
+static SRes ReadUnpackInfo(CSzAr *p,
+ CSzData *sd2,
+ UInt32 numFoldersMax, const CBuf *tempBufs, UInt32 numTempBufs,
+ ISzAlloc *alloc)
+{
+ CSzData sd;
+ Byte inStreamUsed[k_InStreamUsed_MAX];
+ Byte outStreamUsed[k_OutStreamUsed_MAX];
+ UInt32 fo, numFolders, numCodersOutStreams, packStreamIndex;
+ const Byte *startBufPtr;
+ Byte external;
+
+ RINOK(WaitId(sd2, k7zIdFolder));
+ RINOK(SzReadNumber32(sd2, &numFolders));
+ if (p->NumFolders > numFoldersMax)
+ return SZ_ERROR_UNSUPPORTED;
+ p->NumFolders = numFolders;
+
+ SZ_READ_BYTE_SD(sd2, external);
+ if (external == 0)
+ sd = *sd2;
+ else
+ {
+ UInt32 index;
+ 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(size_t, p->FoSizesOffsets, (size_t)numFolders + 1, alloc);
+ MY_ALLOC(UInt32, p->FoStartPackStreamIndex, (size_t)numFolders + 1, alloc);
+
+ startBufPtr = sd.Data;
+
+ packStreamIndex = 0;
+ numCodersOutStreams = 0;
+
+ for (fo = 0; fo < numFolders; fo++)
+ {
+ UInt32 numCoders, ci, numInStreams = 0, numOutStreams = 0;
+
+ p->FoCodersOffsets[fo] = sd.Data - startBufPtr;
+ RINOK(SzReadNumber32(&sd, &numCoders));
+ if (numCoders > NUM_FOLDER_CODERS_MAX)
+ return SZ_ERROR_UNSUPPORTED;
+
+ for (ci = 0; ci < numCoders; ci++)
+ {
+ Byte mainByte;
+ unsigned idSize;
+ UInt32 coderInStreams, coderOutStreams;
+
+ 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;
+ coderOutStreams = 1;
+ if ((mainByte & 0x10) != 0)
+ {
+ RINOK(SzReadNumber32(&sd, &coderInStreams));
+ RINOK(SzReadNumber32(&sd, &coderOutStreams));
+ if (coderInStreams > NUM_CODER_STREAMS_MAX ||
+ coderOutStreams > NUM_CODER_STREAMS_MAX)
+ return SZ_ERROR_UNSUPPORTED;
+ }
+ numInStreams += coderInStreams;
+ numOutStreams += coderOutStreams;
+ 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 (numOutStreams != 1 || numInStreams != 1)
+ {
+ UInt32 i;
+ UInt32 numBindPairs = numOutStreams - 1;
+ if (numOutStreams == 0 || numInStreams < numBindPairs)
+ return SZ_ERROR_ARCHIVE;
+
+ if (numInStreams > k_InStreamUsed_MAX ||
+ numOutStreams > k_OutStreamUsed_MAX)
+ return SZ_ERROR_UNSUPPORTED;
+
+ for (i = 0; i < numInStreams; i++)
+ inStreamUsed[i] = False;
+ for (i = 0; i < numOutStreams; i++)
+ outStreamUsed[i] = False;
+
+ for (i = 0; i < numBindPairs; i++)
+ {
+ UInt32 index;
+ RINOK(SzReadNumber32(&sd, &index));
+ if (index >= numInStreams || inStreamUsed[index])
+ return SZ_ERROR_ARCHIVE;
+ inStreamUsed[index] = True;
+ RINOK(SzReadNumber32(&sd, &index));
+ if (index >= numInStreams || outStreamUsed[index])
+ return SZ_ERROR_ARCHIVE;
+ outStreamUsed[index] = True;
+ }
+
+ numPackStreams = numInStreams - numBindPairs;
+
+ if (numPackStreams != 1)
+ for (i = 0; i < numPackStreams; i++)
+ {
+ UInt32 temp;
+ RINOK(SzReadNumber32(&sd, &temp));
+ if (temp >= numInStreams)
+ return SZ_ERROR_ARCHIVE;
+ }
+
+ for (i = 0; i < numOutStreams; i++)
+ if (!outStreamUsed[i])
+ {
+ indexOfMainStream = i;
+ break;
+ }
+
+ if (i == numOutStreams)
+ return SZ_ERROR_ARCHIVE;
+ }
+ p->FoStartPackStreamIndex[fo] = packStreamIndex;
+ p->FoSizesOffsets[fo] = (numOutStreams << 8) | indexOfMainStream;
+ numCodersOutStreams += numOutStreams;
+ if (numCodersOutStreams < numOutStreams)
+ return SZ_ERROR_UNSUPPORTED;
+ packStreamIndex += numPackStreams;
+ if (packStreamIndex < numPackStreams)
+ return SZ_ERROR_UNSUPPORTED;
+ if (packStreamIndex > p->NumPackStreams)
+ return SZ_ERROR_ARCHIVE;
+ }
+ }
+
+ {
+ size_t dataSize = sd.Data - startBufPtr;
+ p->FoStartPackStreamIndex[fo] = packStreamIndex;
+ p->FoCodersOffsets[fo] = dataSize;
+ MY_ALLOC(Byte, p->CodersData, dataSize, alloc);
+ memcpy(p->CodersData, startBufPtr, dataSize);
+ }
+
+ if (external != 0)
+ {
+ if (sd.Size != 0)
+ return SZ_ERROR_ARCHIVE;
+ sd = *sd2;
+ }
+
+ RINOK(WaitId(&sd, k7zIdCodersUnpackSize));
+
+ // MY_ALLOC(UInt64, p->CoderUnpackSizes, (size_t)numCodersOutStreams, alloc);
+ {
+ size_t dataSize = sd.Size;
+ /*
+ UInt32 i;
+ for (i = 0; i < numCodersOutStreams; i++)
+ {
+ RINOK(ReadNumber(&sd, p->CoderUnpackSizes + i));
+ }
+ */
+ RINOK(SkipNumbers(&sd, numCodersOutStreams));
+ dataSize -= sd.Size;
+ MY_ALLOC(Byte, p->UnpackSizesData, dataSize, alloc);
+ memcpy(p->UnpackSizesData, sd.Data - dataSize, dataSize);
+ p->UnpackSizesDataSize = dataSize;
+ /*
+ const Byte *data = SzReadNumbers(sd.Data, sd.Data + sd.Size, p->CoderUnpackSizes, numCodersOutStreams);
+ if (data == NULL)
+ return SZ_ERROR_ARCHIVE;
+ sd.Size = sd.Data + sd.Size - data;
+ sd.Data = data;
+ */
+ }
+
+ 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));
+ }
+}
+
+typedef struct
+{
+ UInt32 NumTotalSubStreams;
+ UInt32 NumSubDigests;
+ CSzData sdNumSubStreams;
+ CSzData sdSizes;
+ CSzData sdCRCs;
+} CSubStreamInfo;
+
+#define SzUi32IndexMax (((UInt32)1 << 31) - 2)
+
+static SRes ReadSubStreamsInfo(CSzAr *p, CSzData *sd, CSubStreamInfo *ssi)
+{
+ UInt64 type = 0;
+ UInt32 i;
+ UInt32 numSubDigests = 0;
+ UInt32 numFolders = p->NumFolders;
+ UInt32 numUnpackStreams = numFolders;
+ UInt32 numUnpackSizesInData = 0;
+
+ for (;;)
+ {
+ RINOK(ReadID(sd, &type));
+ if (type == k7zIdNumUnpackStream)
+ {
+ 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,
+ ISzAlloc *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,
+ ISzAlloc *allocTemp)
+{
+ UInt64 dataStartPos;
+ UInt32 fo;
+ CSubStreamInfo ssi;
+ CSzData sdCodersUnpSizes;
+
+ RINOK(SzReadStreamsInfo(p, sd, numFoldersMax, NULL, 0, &dataStartPos, &ssi, allocTemp));
+
+ dataStartPos += baseOffset;
+ if (p->NumFolders == 0)
+ return SZ_ERROR_ARCHIVE;
+
+ sdCodersUnpSizes.Data = p->UnpackSizesData;
+ sdCodersUnpSizes.Size = p->UnpackSizesDataSize;
+ for (fo = 0; fo < p->NumFolders; fo++)
+ Buf_Init(tempBufs + fo);
+ for (fo = 0; fo < p->NumFolders; fo++)
+ {
+ CBuf *tempBuf = tempBufs + fo;
+ // folder = p->Folders;
+ // unpackSize = SzAr_GetFolderUnpackSize(p, 0);
+ UInt32 mix = (UInt32)p->FoSizesOffsets[fo];
+ UInt32 mainIndex = mix & 0xFF;
+ UInt32 numOutStreams = mix >> 8;
+ UInt32 si;
+ UInt64 unpackSize = 0;
+ p->FoSizesOffsets[fo] = sdCodersUnpSizes.Data - p->UnpackSizesData;
+ for (si = 0; si < numOutStreams; si++)
+ {
+ UInt64 curSize;
+ RINOK(ReadNumber(&sdCodersUnpSizes, &curSize));
+ if (si == mainIndex)
+ {
+ unpackSize = curSize;
+ break;
+ }
+ }
+ if (si == numOutStreams)
+ return SZ_ERROR_FAIL;
+ if ((size_t)unpackSize != unpackSize)
+ return SZ_ERROR_MEM;
+ if (!Buf_Create(tempBuf, (size_t)unpackSize, allocTemp))
+ return SZ_ERROR_MEM;
+ }
+ p->FoSizesOffsets[fo] = sdCodersUnpSizes.Data - p->UnpackSizesData;
+
+ 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));
+ if (SzBitWithVals_Check(&p->FolderCRCs, fo))
+ if (CrcCalc(tempBuf->data, tempBuf->size) != p->FolderCRCs.Vals[fo])
+ return SZ_ERROR_CRC;
+ }
+ 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 (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,
+ ISzAlloc *alloc)
+{
+ CSzData sd;
+ UInt32 i;
+ CNtfsFileTime *vals;
+ Byte *defs;
+ Byte external;
+ RINOK(ReadBitVector(sd2, num, &p->Defs, alloc));
+ RINOK(SzReadByte(sd2, &external));
+ if (external == 0)
+ sd = *sd2;
+ else
+ {
+ UInt32 index;
+ SzReadNumber32(sd2, &index);
+ if (index >= numTempBufs)
+ return SZ_ERROR_ARCHIVE;
+ sd.Data = tempBufs[index].data;
+ sd.Size = tempBufs[index].size;
+ }
+ MY_ALLOC(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,
+ // Byte **emptyStreamVector, /* allocTemp */
+ // Byte **emptyFileVector, /* allocTemp */
+ // Byte **lwtVector, /* allocTemp */
+ ILookInStream *inStream,
+ CBuf *tempBufs,
+ UInt32 *numTempBufs,
+ ISzAlloc *allocMain,
+ ISzAlloc *allocTemp
+ )
+{
+ UInt64 type;
+ UInt32 numFiles = 0;
+ UInt32 numEmptyStreams = 0;
+ UInt32 i;
+ CSubStreamInfo ssi;
+ const Byte *emptyStreams = 0;
+ const Byte *emptyFiles = 0;
+
+ 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 type;
+ RINOK(ReadID(sd, &type));
+ if (type == k7zIdEnd)
+ break;
+ RINOK(SkipData(sd));
+ }
+ RINOK(ReadID(sd, &type));
+ }
+
+ // if (type == k7zIdAdditionalStreamsInfo) return SZ_ERROR_UNSUPPORTED;
+
+ if (type == k7zIdAdditionalStreamsInfo)
+ {
+ CSzAr tempAr;
+ SRes res;
+ UInt32 numTempFolders;
+
+ SzAr_Init(&tempAr);
+ res = SzReadAndDecodePackedStreams(inStream, sd, tempBufs, NUM_ADDITIONAL_STREAMS_MAX,
+ p->startPosAfterHeader, &tempAr, allocTemp);
+ numTempFolders = tempAr.NumFolders;
+ SzAr_Free(&tempAr, allocTemp);
+ if (res != SZ_OK)
+ return res;
+ *numTempBufs = numTempFolders;
+ 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)
+ {
+ // *sd2 = sd;
+ return SZ_OK;
+ }
+ if (type != k7zIdFilesInfo)
+ return SZ_ERROR_ARCHIVE;
+
+ 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 ((UInt64)(int)type != type)
+ {
+ SKIP_DATA(sd, size);
+ }
+ else switch((int)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;
+ 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(Byte, p->FileNames, namesSize, allocMain);
+ MY_ALLOC(size_t, p->FileNameOffsets, numFiles + 1, allocMain);
+ memcpy(p->FileNames, namesData, namesSize);
+ 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);
+ 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;
+ 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 emptyFileIndex = 0;
+
+ UInt32 folderIndex = 0;
+ UInt32 indexInFolder = 0;
+ UInt64 unpackPos = 0;
+ const Byte *digestsDefs = 0;
+ const Byte *digestsVals = 0;
+ UInt32 digestsValsIndex = 0;
+ UInt32 digestIndex;
+ Byte allDigestsDefined = 0;
+ UInt32 curNumSubStreams = (UInt32)(Int32)-1;
+ Byte isDirMask = 0;
+ Byte crcMask = 0;
+ Byte mask = 0x80;
+ // size_t unpSizesOffset = 0;
+ CSzData sdCodersUnpSizes;
+ sdCodersUnpSizes.Data = p->db.UnpackSizesData;
+ sdCodersUnpSizes.Size = p->db.UnpackSizesDataSize;
+
+ MY_ALLOC(UInt32, p->FolderStartFileIndex, p->db.NumFolders + 1, allocMain);
+ MY_ALLOC(UInt32, p->FileIndexToFolderIndexMap, p->NumFiles, allocMain);
+ MY_ALLOC(UInt64, p->UnpackPositions, p->NumFiles + 1, allocMain);
+ MY_ALLOC(Byte, p->IsDirs, (p->NumFiles + 7) >> 3, allocMain);
+
+ RINOK(SzBitUi32s_Alloc(&p->CRCs, p->NumFiles, allocMain));
+
+ if (ssi.sdCRCs.Size != 0)
+ {
+ RINOK(SzReadByte(&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;
+ // p->CRCs.Defs[i] = 0;
+ if (emptyStreams && SzBitArray_Check(emptyStreams , i))
+ {
+ if (!emptyFiles || !SzBitArray_Check(emptyFiles, emptyFileIndex))
+ isDirMask |= mask;
+ emptyFileIndex++;
+ if (indexInFolder == 0)
+ {
+ p->FileIndexToFolderIndexMap[i] = (UInt32)-1;
+ continue;
+ }
+ }
+ if (indexInFolder == 0)
+ {
+ /*
+ v3.13 incorrectly worked with empty folders
+ v4.07: Loop for skipping empty folders
+ */
+ for (;;)
+ {
+ if (folderIndex >= p->db.NumFolders)
+ return SZ_ERROR_ARCHIVE;
+ p->FolderStartFileIndex[folderIndex] = i;
+ if (curNumSubStreams == (UInt32)(Int32)-1);
+ {
+ curNumSubStreams = 1;
+ if (ssi.sdNumSubStreams.Data != 0)
+ {
+ RINOK(SzReadNumber32(&ssi.sdNumSubStreams, &curNumSubStreams));
+ }
+ }
+ if (curNumSubStreams != 0)
+ break;
+ curNumSubStreams = (UInt32)(Int32)-1;
+ folderIndex++; // check it
+ }
+ }
+ p->FileIndexToFolderIndexMap[i] = folderIndex;
+ if (emptyStreams && SzBitArray_Check(emptyStreams , i))
+ continue;
+
+ indexInFolder++;
+ if (indexInFolder >= curNumSubStreams)
+ {
+ UInt64 folderUnpackSize = 0;
+ UInt64 startFolderUnpackPos;
+ {
+ UInt32 mix = (UInt32)p->db.FoSizesOffsets[folderIndex];
+ UInt32 mainIndex = mix & 0xFF;
+ UInt32 numOutStreams = mix >> 8;
+ UInt32 si;
+ p->db.FoSizesOffsets[folderIndex] = sdCodersUnpSizes.Data - p->db.UnpackSizesData;
+ for (si = 0; si < numOutStreams; si++)
+ {
+ UInt64 curSize;
+ RINOK(ReadNumber(&sdCodersUnpSizes, &curSize));
+ if (si == mainIndex)
+ {
+ folderUnpackSize = curSize;
+ break;
+ }
+ }
+ if (si == numOutStreams)
+ return SZ_ERROR_FAIL;
+ }
+
+ // UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex);
+ startFolderUnpackPos = p->UnpackPositions[p->FolderStartFileIndex[folderIndex]];
+ if (folderUnpackSize < unpackPos - startFolderUnpackPos)
+ return SZ_ERROR_ARCHIVE;
+ unpackPos = startFolderUnpackPos + folderUnpackSize;
+
+ if (curNumSubStreams == 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++;
+ indexInFolder = 0;
+ }
+ else
+ {
+ UInt64 v;
+ RINOK(ReadNumber(&ssi.sdSizes, &v));
+ unpackPos += v;
+ 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;
+ p->FolderStartFileIndex[folderIndex] = i;
+ p->db.FoSizesOffsets[folderIndex] = sdCodersUnpSizes.Data - p->db.UnpackSizesData;
+ }
+ return SZ_OK;
+}
+
+static SRes SzReadHeader(
+ CSzArEx *p,
+ CSzData *sd,
+ ILookInStream *inStream,
+ ISzAlloc *allocMain
+ ,ISzAlloc *allocTemp
+ )
+{
+ // Byte *emptyStreamVector = 0;
+ // Byte *emptyFileVector = 0;
+ // Byte *lwtVector = 0;
+ 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);
+ // SzBitUi32s_Init(&digests);
+
+ res = SzReadHeader2(p, sd,
+ // &emptyStreamVector,
+ // &emptyFileVector,
+ // &lwtVector,
+ inStream,
+ tempBufs, &numTempBufs,
+ allocMain, allocTemp
+ );
+
+ for (i = 0; i < numTempBufs; i++)
+ Buf_Free(tempBufs + i, allocTemp);
+
+ // IAlloc_Free(allocTemp, emptyStreamVector);
+ // IAlloc_Free(allocTemp, emptyFileVector);
+ // IAlloc_Free(allocTemp, lwtVector);
+
+ RINOK(res);
+ {
+ if (sd->Size != 0)
+ return SZ_ERROR_FAIL;
+ }
+
+ return res;
+}
+
+/*
+static UInt64 SzAr_GetFolderUnpackSize(const CSzAr *p, UInt32 folderIndex)
+{
+ const CSzFolder2 *f = p->Folders + folderIndex;
+
+ // return p->CoderUnpackSizes[f->StartCoderUnpackSizesIndex + f->IndexOfMainOutStream];
+
+ UInt32 si;
+ CSzData sdCodersUnpSizes;
+ sdCodersUnpSizes.Data = p->UnpackSizesData + f->UnpackSizeDataOffset;
+ sdCodersUnpSizes.Size = p->UnpackSizesDataSize - f->UnpackSizeDataOffset;
+ for (si = 0; si < numOutStreams; si++)
+ {
+ UInt64 curSize;
+ ReadNumber(&sdCodersUnpSizes, &curSize);
+ if (si == mainIndex)
+ return curSize;
+ }
+ return 0;
+}
+*/
+
+static SRes SzArEx_Open2(
+ CSzArEx *p,
+ ILookInStream *inStream,
+ ISzAlloc *allocMain,
+ ISzAlloc *allocTemp)
+{
+ Byte header[k7zStartHeaderSize];
+ Int64 startArcPos;
+ UInt64 nextHeaderOffset, nextHeaderSize;
+ size_t nextHeaderSizeT;
+ UInt32 nextHeaderCRC;
+ CBuf buf;
+ SRes res;
+
+ startArcPos = 0;
+ RINOK(inStream->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(inStream->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;
+ int ttt;
+ for (ttt = 0; ttt < 1; 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, allocMain, allocTemp);
+ }
+ else
+ res = SZ_ERROR_UNSUPPORTED;
+ }
+ }
+ }
+ Buf_Free(&buf, allocTemp);
+ return res;
+}
+
+// #include <stdio.h>
+
+SRes SzArEx_Open(CSzArEx *p, ILookInStream *inStream,
+ ISzAlloc *allocMain, ISzAlloc *allocTemp)
+{
+ SRes res = SzArEx_Open2(p, inStream, allocMain, allocTemp);
+ if (res != SZ_OK)
+ SzArEx_Free(p, allocMain);
+ // printf ("\nrrr=%d\n", rrr);
+ 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,
+ ISzAlloc *allocMain,
+ ISzAlloc *allocTemp)
+{
+ UInt32 folderIndex = p->FileIndexToFolderIndexMap[fileIndex];
+ SRes res = SZ_OK;
+ *offset = 0;
+ *outSizeProcessed = 0;
+ if (folderIndex == (UInt32)-1)
+ {
+ IAlloc_Free(allocMain, *tempBuf);
+ *blockIndex = folderIndex;
+ *tempBuf = 0;
+ *outBufferSize = 0;
+ return SZ_OK;
+ }
+
+ if (*tempBuf == 0 || *blockIndex != folderIndex)
+ {
+ // UInt64 unpackSizeSpec = SzAr_GetFolderUnpackSize(&p->db, folderIndex);
+ UInt64 unpackSizeSpec =
+ p->UnpackPositions[p->FolderStartFileIndex[folderIndex + 1]] -
+ p->UnpackPositions[p->FolderStartFileIndex[folderIndex]];
+ size_t unpackSize = (size_t)unpackSizeSpec;
+
+ if (unpackSize != unpackSizeSpec)
+ return SZ_ERROR_MEM;
+ *blockIndex = folderIndex;
+ IAlloc_Free(allocMain, *tempBuf);
+ *tempBuf = 0;
+
+ // RINOK(LookInStream_SeekTo(inStream, startOffset));
+
+ if (res == SZ_OK)
+ {
+ *outBufferSize = unpackSize;
+ if (unpackSize != 0)
+ {
+ *tempBuf = (Byte *)IAlloc_Alloc(allocMain, unpackSize);
+ if (*tempBuf == 0)
+ res = SZ_ERROR_MEM;
+ }
+ if (res == SZ_OK)
+ {
+ res = SzAr_DecodeFolder(&p->db, folderIndex,
+ inStream,
+ p->dataPos,
+ *tempBuf, unpackSize, allocTemp);
+ if (res == SZ_OK)
+ {
+ if (SzBitWithVals_Check(&p->db.FolderCRCs, folderIndex))
+ {
+ if (CrcCalc(*tempBuf, unpackSize) != p->db.FolderCRCs.Vals[folderIndex])
+ res = SZ_ERROR_CRC;
+ }
+ }
+ }
+ }
+ }
+ if (res == SZ_OK)
+ {
+ UInt64 unpackPos = p->UnpackPositions[fileIndex];
+ *offset = (size_t)(unpackPos - p->UnpackPositions[p->FolderStartFileIndex[folderIndex]]);
+ *outSizeProcessed = (size_t)(p->UnpackPositions[fileIndex + 1] - unpackPos);
+ if (*offset + *outSizeProcessed > *outBufferSize)
+ return SZ_ERROR_FAIL;
+ if (SzBitWithVals_Check(&p->CRCs, fileIndex) && 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)
+{
+ Bool 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/lzma/C/7zBuf.c b/lzma/C/7zBuf.c
new file mode 100644
index 0000000..b0ac110
--- /dev/null
+++ b/lzma/C/7zBuf.c
@@ -0,0 +1,36 @@
+/* 7zBuf.c -- Byte Buffer
+2013-01-21 : 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, ISzAlloc *alloc)
+{
+ p->size = 0;
+ if (size == 0)
+ {
+ p->data = 0;
+ return 1;
+ }
+ p->data = (Byte *)alloc->Alloc(alloc, size);
+ if (p->data != 0)
+ {
+ p->size = size;
+ return 1;
+ }
+ return 0;
+}
+
+void Buf_Free(CBuf *p, ISzAlloc *alloc)
+{
+ alloc->Free(alloc, p->data);
+ p->data = 0;
+ p->size = 0;
+}
diff --git a/lzma/C/7zBuf.h b/lzma/C/7zBuf.h
new file mode 100644
index 0000000..e5f9218
--- /dev/null
+++ b/lzma/C/7zBuf.h
@@ -0,0 +1,35 @@
+/* 7zBuf.h -- Byte Buffer
+2013-01-18 : 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, ISzAlloc *alloc);
+void Buf_Free(CBuf *p, ISzAlloc *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, ISzAlloc *alloc);
+void DynBuf_Free(CDynBuf *p, ISzAlloc *alloc);
+
+EXTERN_C_END
+
+#endif
diff --git a/lzma/C/7zBuf2.c b/lzma/C/7zBuf2.c
new file mode 100644
index 0000000..9633796
--- /dev/null
+++ b/lzma/C/7zBuf2.c
@@ -0,0 +1,48 @@
+/* 7zBuf2.c -- Byte Buffer
+2013-11-12 : 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, ISzAlloc *alloc)
+{
+ if (size > p->size - p->pos)
+ {
+ size_t newSize = p->pos + size;
+ Byte *data;
+ newSize += newSize / 4;
+ data = (Byte *)alloc->Alloc(alloc, newSize);
+ if (data == 0)
+ return 0;
+ p->size = newSize;
+ memcpy(data, p->data, p->pos);
+ alloc->Free(alloc, p->data);
+ p->data = data;
+ }
+ memcpy(p->data + p->pos, buf, size);
+ p->pos += size;
+ return 1;
+}
+
+void DynBuf_Free(CDynBuf *p, ISzAlloc *alloc)
+{
+ alloc->Free(alloc, p->data);
+ p->data = 0;
+ p->size = 0;
+ p->pos = 0;
+}
diff --git a/lzma/C/7zCrc.c b/lzma/C/7zCrc.c
new file mode 100644
index 0000000..161d4d1
--- /dev/null
+++ b/lzma/C/7zCrc.c
@@ -0,0 +1,85 @@
+/* 7zCrc.c -- CRC32 init
+2013-11-12 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "7zCrc.h"
+#include "CpuArch.h"
+
+#define kCrcPoly 0xEDB88320
+
+#ifdef MY_CPU_X86_OR_AMD64
+ #define CRC_NUM_TABLES 8
+ UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table);
+#elif defined(MY_CPU_LE)
+ #define CRC_NUM_TABLES 4
+#else
+ #define CRC_NUM_TABLES 5
+ #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);
+#endif
+
+#ifndef MY_CPU_BE
+ UInt32 MY_FAST_CALL CrcUpdateT4(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_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;
+}
+
+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 & ~((r & 1) - 1));
+ g_CrcTable[i] = r;
+ }
+ for (; i < 256 * CRC_NUM_TABLES; i++)
+ {
+ UInt32 r = g_CrcTable[i - 256];
+ g_CrcTable[i] = g_CrcTable[r & 0xFF] ^ (r >> 8);
+ }
+
+ #ifdef MY_CPU_LE
+
+ g_CrcUpdate = CrcUpdateT4;
+
+ #if CRC_NUM_TABLES == 8
+ if (!CPU_Is_InOrder())
+ g_CrcUpdate = CrcUpdateT8;
+ #endif
+
+ #else
+ {
+ #ifndef MY_CPU_BE
+ UInt32 k = 1;
+ if (*(const Byte *)&k == 1)
+ g_CrcUpdate = CrcUpdateT4;
+ else
+ #endif
+ {
+ for (i = 256 * CRC_NUM_TABLES - 1; i >= 256; i--)
+ {
+ UInt32 x = g_CrcTable[i - 256];
+ g_CrcTable[i] = CRC_UINT32_SWAP(x);
+ }
+ g_CrcUpdate = CrcUpdateT1_BeT4;
+ }
+ }
+ #endif
+}
diff --git a/lzma/C/7zCrc.h b/lzma/C/7zCrc.h
new file mode 100644
index 0000000..3b04594
--- /dev/null
+++ b/lzma/C/7zCrc.h
@@ -0,0 +1,25 @@
+/* 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
diff --git a/lzma/C/7zCrcOpt.c b/lzma/C/7zCrcOpt.c
new file mode 100644
index 0000000..48b0136
--- /dev/null
+++ b/lzma/C/7zCrcOpt.c
@@ -0,0 +1,66 @@
+/* 7zCrcOpt.c -- CRC32 calculation
+2013-11-12 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "CpuArch.h"
+
+#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
+
+#ifndef MY_CPU_BE
+
+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)
+{
+ return CrcUpdateT4(v, data, size, table);
+}
+
+#endif
+
+
+#ifndef MY_CPU_LE
+
+#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)
+{
+ const Byte *p = (const Byte *)data;
+ for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++)
+ v = CRC_UPDATE_BYTE_2(v, *p);
+ v = CRC_UINT32_SWAP(v);
+ table += 0x100;
+ 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))];
+ }
+ table -= 0x100;
+ v = CRC_UINT32_SWAP(v);
+ for (; size > 0; size--, p++)
+ v = CRC_UPDATE_BYTE_2(v, *p);
+ return v;
+}
+
+#endif
diff --git a/lzma/C/7zDec.c b/lzma/C/7zDec.c
new file mode 100644
index 0000000..1c363a5
--- /dev/null
+++ b/lzma/C/7zDec.c
@@ -0,0 +1,493 @@
+/* 7zDec.c -- Decoding from 7z folder
+2014-06-16 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include <string.h>
+
+/* #define _7ZIP_PPMD_SUPPPORT */
+
+#include "7z.h"
+
+#include "Bcj2.h"
+#include "Bra.h"
+#include "CpuArch.h"
+#include "LzmaDec.h"
+#include "Lzma2Dec.h"
+#ifdef _7ZIP_PPMD_SUPPPORT
+#include "Ppmd7.h"
+#endif
+
+#define k_Copy 0
+#define k_LZMA2 0x21
+#define k_LZMA 0x30101
+#define k_BCJ 0x03030103
+#define k_PPC 0x03030205
+#define k_ARM 0x03030501
+#define k_ARMT 0x03030701
+#define k_SPARC 0x03030805
+#define k_BCJ2 0x0303011B
+
+#ifdef _7ZIP_PPMD_SUPPPORT
+
+#define k_PPMD 0x30401
+
+typedef struct
+{
+ IByteIn p;
+ const Byte *cur;
+ const Byte *end;
+ const Byte *begin;
+ UInt64 processed;
+ Bool extra;
+ SRes res;
+ ILookInStream *inStream;
+} CByteInToLook;
+
+static Byte ReadByte(void *pp)
+{
+ CByteInToLook *p = (CByteInToLook *)pp;
+ 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 = p->inStream->Skip(p->inStream, size);
+ size = (1 << 25);
+ p->res = p->inStream->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, ILookInStream *inStream,
+ Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain)
+{
+ CPpmd7 ppmd;
+ CByteInToLook s;
+ SRes res = SZ_OK;
+
+ s.p.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.p;
+ 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.p);
+ 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, ISzAlloc *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 (;;)
+ {
+ Byte *inBuf = NULL;
+ size_t lookahead = (1 << 18);
+ if (lookahead > inSize)
+ lookahead = (size_t)inSize;
+ res = inStream->Look((void *)inStream, (const void **)&inBuf, &lookahead);
+ if (res != SZ_OK)
+ break;
+
+ {
+ SizeT inProcessed = (SizeT)lookahead, dicPos = state.dicPos;
+ ELzmaStatus status;
+ res = LzmaDec_DecodeToDic(&state, outSize, inBuf, &inProcessed, LZMA_FINISH_END, &status);
+ lookahead -= inProcessed;
+ inSize -= inProcessed;
+ if (res != SZ_OK)
+ break;
+ if (state.dicPos == state.dicBufSize || (inProcessed == 0 && dicPos == state.dicPos))
+ {
+ if (state.dicBufSize != outSize || lookahead != 0 ||
+ (status != LZMA_STATUS_FINISHED_WITH_MARK &&
+ status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK))
+ res = SZ_ERROR_DATA;
+ break;
+ }
+ res = inStream->Skip((void *)inStream, inProcessed);
+ if (res != SZ_OK)
+ break;
+ }
+ }
+
+ LzmaDec_FreeProbs(&state, allocMain);
+ return res;
+}
+
+static SRes SzDecodeLzma2(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStream *inStream,
+ Byte *outBuffer, SizeT outSize, ISzAlloc *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 (;;)
+ {
+ Byte *inBuf = NULL;
+ size_t lookahead = (1 << 18);
+ if (lookahead > inSize)
+ lookahead = (size_t)inSize;
+ res = inStream->Look((void *)inStream, (const void **)&inBuf, &lookahead);
+ if (res != SZ_OK)
+ break;
+
+ {
+ SizeT inProcessed = (SizeT)lookahead, dicPos = state.decoder.dicPos;
+ ELzmaStatus status;
+ res = Lzma2Dec_DecodeToDic(&state, outSize, inBuf, &inProcessed, LZMA_FINISH_END, &status);
+ lookahead -= inProcessed;
+ inSize -= inProcessed;
+ if (res != SZ_OK)
+ break;
+ if (state.decoder.dicPos == state.decoder.dicBufSize || (inProcessed == 0 && dicPos == state.decoder.dicPos))
+ {
+ if (state.decoder.dicBufSize != outSize || lookahead != 0 ||
+ (status != LZMA_STATUS_FINISHED_WITH_MARK))
+ res = SZ_ERROR_DATA;
+ break;
+ }
+ res = inStream->Skip((void *)inStream, inProcessed);
+ if (res != SZ_OK)
+ break;
+ }
+ }
+
+ Lzma2Dec_FreeProbs(&state, allocMain);
+ return res;
+}
+
+static SRes SzDecodeCopy(UInt64 inSize, ILookInStream *inStream, Byte *outBuffer)
+{
+ while (inSize > 0)
+ {
+ void *inBuf;
+ size_t curSize = (1 << 18);
+ if (curSize > inSize)
+ curSize = (size_t)inSize;
+ RINOK(inStream->Look((void *)inStream, (const void **)&inBuf, &curSize));
+ if (curSize == 0)
+ return SZ_ERROR_INPUT_EOF;
+ memcpy(outBuffer, inBuf, curSize);
+ outBuffer += curSize;
+ inSize -= curSize;
+ RINOK(inStream->Skip((void *)inStream, curSize));
+ }
+ return SZ_OK;
+}
+
+static Bool IS_MAIN_METHOD(UInt32 m)
+{
+ switch (m)
+ {
+ case k_Copy:
+ case k_LZMA:
+ case k_LZMA2:
+ #ifdef _7ZIP_PPMD_SUPPPORT
+ case k_PPMD:
+ #endif
+ return True;
+ }
+ return False;
+}
+
+static Bool IS_SUPPORTED_CODER(const CSzCoderInfo *c)
+{
+ return
+ c->NumInStreams == 1 &&
+ c->NumOutStreams == 1 &&
+ /* c->MethodID <= (UInt32)0xFFFFFFFF && */
+ IS_MAIN_METHOD((UInt32)c->MethodID);
+}
+
+#define IS_BCJ2(c) ((c)->MethodID == k_BCJ2 && (c)->NumInStreams == 4 && (c)->NumOutStreams == 1)
+
+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->NumBindPairs != 0)
+ return SZ_ERROR_UNSUPPORTED;
+ return SZ_OK;
+ }
+ if (f->NumCoders == 2)
+ {
+ const CSzCoderInfo *c = &f->Coders[1];
+ if (
+ /* c->MethodID > (UInt32)0xFFFFFFFF || */
+ c->NumInStreams != 1 ||
+ c->NumOutStreams != 1 ||
+ f->NumPackStreams != 1 ||
+ f->PackStreams[0] != 0 ||
+ f->NumBindPairs != 1 ||
+ f->BindPairs[0].InIndex != 1 ||
+ f->BindPairs[0].OutIndex != 0)
+ return SZ_ERROR_UNSUPPORTED;
+ switch ((UInt32)c->MethodID)
+ {
+ case k_BCJ:
+ case k_ARM:
+ break;
+ default:
+ return SZ_ERROR_UNSUPPORTED;
+ }
+ return SZ_OK;
+ }
+ 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->NumBindPairs != 3 ||
+ f->BindPairs[0].InIndex != 5 || f->BindPairs[0].OutIndex != 0 ||
+ f->BindPairs[1].InIndex != 4 || f->BindPairs[1].OutIndex != 1 ||
+ f->BindPairs[2].InIndex != 3 || f->BindPairs[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, ISzAlloc *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 *)IAlloc_Alloc(allocMain, outSizeCur);
+ if (temp == 0 && 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[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));
+ }
+ else if (coder->MethodID == k_LZMA2)
+ {
+ RINOK(SzDecodeLzma2(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain));
+ }
+ else
+ {
+ #ifdef _7ZIP_PPMD_SUPPPORT
+ RINOK(SzDecodePpmd(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain));
+ #else
+ return SZ_ERROR_UNSUPPORTED;
+ #endif
+ }
+ }
+ else if (coder->MethodID == k_BCJ2)
+ {
+ UInt64 offset = packPositions[1];
+ UInt64 s3Size = packPositions[2] - offset;
+ SRes res;
+ if (ci != 3)
+ return SZ_ERROR_UNSUPPORTED;
+ RINOK(LookInStream_SeekTo(inStream, startPos + offset));
+ tempSizes[2] = (SizeT)s3Size;
+ if (tempSizes[2] != s3Size)
+ return SZ_ERROR_MEM;
+ tempBuf[2] = (Byte *)IAlloc_Alloc(allocMain, tempSizes[2]);
+ if (tempBuf[2] == 0 && tempSizes[2] != 0)
+ return SZ_ERROR_MEM;
+ res = SzDecodeCopy(s3Size, inStream, tempBuf[2]);
+ RINOK(res)
+
+ res = Bcj2_Decode(
+ tempBuf3, tempSize3,
+ tempBuf[0], tempSizes[0],
+ tempBuf[1], tempSizes[1],
+ tempBuf[2], tempSizes[2],
+ outBuffer, outSize);
+ RINOK(res)
+ }
+ else
+ {
+ if (ci != 1)
+ 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(ARM)
+ default:
+ return SZ_ERROR_UNSUPPORTED;
+ }
+ }
+ }
+ return SZ_OK;
+}
+
+SRes SzAr_DecodeFolder(const CSzAr *p, UInt32 folderIndex,
+ ILookInStream *inStream, UInt64 startPos,
+ Byte *outBuffer, size_t outSize,
+ ISzAlloc *allocMain)
+{
+ SRes res;
+ CSzFolder folder;
+ CSzData sd;
+ CSzData sdSizes;
+
+ const Byte *data = p->CodersData + p->FoCodersOffsets[folderIndex];
+ sd.Data = data;
+ sd.Size = p->FoCodersOffsets[folderIndex + 1] - p->FoCodersOffsets[folderIndex];
+
+ sdSizes.Data = p->UnpackSizesData + p->FoSizesOffsets[folderIndex];
+ sdSizes.Size =
+ p->FoSizesOffsets[folderIndex + 1] -
+ p->FoSizesOffsets[folderIndex];
+
+ res = SzGetNextFolderItem(&folder, &sd, &sdSizes);
+
+ if (res != SZ_OK)
+ return res;
+
+ if (sd.Size != 0 || outSize != folder.CodersUnpackSizes[folder.MainOutStream])
+ return SZ_ERROR_FAIL;
+ {
+ int i;
+ Byte *tempBuf[3] = { 0, 0, 0};
+ res = SzFolder_Decode2(&folder, data, folder.CodersUnpackSizes,
+ p->PackPositions + p->FoStartPackStreamIndex[folderIndex],
+ inStream, startPos,
+ outBuffer, (SizeT)outSize, allocMain, tempBuf);
+ for (i = 0; i < 3; i++)
+ IAlloc_Free(allocMain, tempBuf[i]);
+ return res;
+ }
+}
diff --git a/lzma/C/7zFile.c b/lzma/C/7zFile.c
new file mode 100644
index 0000000..98fe716
--- /dev/null
+++ b/lzma/C/7zFile.c
@@ -0,0 +1,286 @@
+/* 7zFile.c -- File IO
+2009-11-24 : 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(void *pp, void *buf, size_t *size)
+{
+ CFileSeqInStream *p = (CFileSeqInStream *)pp;
+ return File_Read(&p->file, buf, size) == 0 ? SZ_OK : SZ_ERROR_READ;
+}
+
+void FileSeqInStream_CreateVTable(CFileSeqInStream *p)
+{
+ p->s.Read = FileSeqInStream_Read;
+}
+
+
+/* ---------- FileInStream ---------- */
+
+static SRes FileInStream_Read(void *pp, void *buf, size_t *size)
+{
+ CFileInStream *p = (CFileInStream *)pp;
+ return (File_Read(&p->file, buf, size) == 0) ? SZ_OK : SZ_ERROR_READ;
+}
+
+static SRes FileInStream_Seek(void *pp, Int64 *pos, ESzSeek origin)
+{
+ CFileInStream *p = (CFileInStream *)pp;
+ return File_Seek(&p->file, pos, origin);
+}
+
+void FileInStream_CreateVTable(CFileInStream *p)
+{
+ p->s.Read = FileInStream_Read;
+ p->s.Seek = FileInStream_Seek;
+}
+
+
+/* ---------- FileOutStream ---------- */
+
+static size_t FileOutStream_Write(void *pp, const void *data, size_t size)
+{
+ CFileOutStream *p = (CFileOutStream *)pp;
+ File_Write(&p->file, data, &size);
+ return size;
+}
+
+void FileOutStream_CreateVTable(CFileOutStream *p)
+{
+ p->s.Write = FileOutStream_Write;
+}
diff --git a/lzma/C/7zFile.h b/lzma/C/7zFile.h
new file mode 100644
index 0000000..d62a192
--- /dev/null
+++ b/lzma/C/7zFile.h
@@ -0,0 +1,83 @@
+/* 7zFile.h -- File IO
+2013-01-18 : 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 s;
+ CSzFile file;
+} CFileSeqInStream;
+
+void FileSeqInStream_CreateVTable(CFileSeqInStream *p);
+
+
+typedef struct
+{
+ ISeekInStream s;
+ CSzFile file;
+} CFileInStream;
+
+void FileInStream_CreateVTable(CFileInStream *p);
+
+
+typedef struct
+{
+ ISeqOutStream s;
+ CSzFile file;
+} CFileOutStream;
+
+void FileOutStream_CreateVTable(CFileOutStream *p);
+
+EXTERN_C_END
+
+#endif
diff --git a/lzma/C/7zStream.c b/lzma/C/7zStream.c
new file mode 100644
index 0000000..5a92d53
--- /dev/null
+++ b/lzma/C/7zStream.c
@@ -0,0 +1,171 @@
+/* 7zStream.c -- 7z Stream functions
+2013-11-12 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include <string.h>
+
+#include "7zTypes.h"
+
+SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType)
+{
+ while (size != 0)
+ {
+ size_t processed = size;
+ RINOK(stream->Read(stream, buf, &processed));
+ if (processed == 0)
+ return errorType;
+ buf = (void *)((Byte *)buf + processed);
+ size -= processed;
+ }
+ return SZ_OK;
+}
+
+SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size)
+{
+ return SeqInStream_Read2(stream, buf, size, SZ_ERROR_INPUT_EOF);
+}
+
+SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf)
+{
+ size_t processed = 1;
+ RINOK(stream->Read(stream, buf, &processed));
+ return (processed == 1) ? SZ_OK : SZ_ERROR_INPUT_EOF;
+}
+
+SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset)
+{
+ Int64 t = offset;
+ return stream->Seek(stream, &t, SZ_SEEK_SET);
+}
+
+SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size)
+{
+ const void *lookBuf;
+ if (*size == 0)
+ return SZ_OK;
+ RINOK(stream->Look(stream, &lookBuf, size));
+ memcpy(buf, lookBuf, *size);
+ return stream->Skip(stream, *size);
+}
+
+SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType)
+{
+ while (size != 0)
+ {
+ size_t processed = size;
+ RINOK(stream->Read(stream, buf, &processed));
+ if (processed == 0)
+ return errorType;
+ buf = (void *)((Byte *)buf + processed);
+ size -= processed;
+ }
+ return SZ_OK;
+}
+
+SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size)
+{
+ return LookInStream_Read2(stream, buf, size, SZ_ERROR_INPUT_EOF);
+}
+
+static SRes LookToRead_Look_Lookahead(void *pp, const void **buf, size_t *size)
+{
+ SRes res = SZ_OK;
+ CLookToRead *p = (CLookToRead *)pp;
+ size_t size2 = p->size - p->pos;
+ if (size2 == 0 && *size > 0)
+ {
+ p->pos = 0;
+ size2 = LookToRead_BUF_SIZE;
+ res = p->realStream->Read(p->realStream, p->buf, &size2);
+ p->size = size2;
+ }
+ if (size2 < *size)
+ *size = size2;
+ *buf = p->buf + p->pos;
+ return res;
+}
+
+static SRes LookToRead_Look_Exact(void *pp, const void **buf, size_t *size)
+{
+ SRes res = SZ_OK;
+ CLookToRead *p = (CLookToRead *)pp;
+ size_t size2 = p->size - p->pos;
+ if (size2 == 0 && *size > 0)
+ {
+ p->pos = 0;
+ if (*size > LookToRead_BUF_SIZE)
+ *size = LookToRead_BUF_SIZE;
+ res = p->realStream->Read(p->realStream, p->buf, size);
+ size2 = p->size = *size;
+ }
+ if (size2 < *size)
+ *size = size2;
+ *buf = p->buf + p->pos;
+ return res;
+}
+
+static SRes LookToRead_Skip(void *pp, size_t offset)
+{
+ CLookToRead *p = (CLookToRead *)pp;
+ p->pos += offset;
+ return SZ_OK;
+}
+
+static SRes LookToRead_Read(void *pp, void *buf, size_t *size)
+{
+ CLookToRead *p = (CLookToRead *)pp;
+ size_t rem = p->size - p->pos;
+ if (rem == 0)
+ return p->realStream->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 LookToRead_Seek(void *pp, Int64 *pos, ESzSeek origin)
+{
+ CLookToRead *p = (CLookToRead *)pp;
+ p->pos = p->size = 0;
+ return p->realStream->Seek(p->realStream, pos, origin);
+}
+
+void LookToRead_CreateVTable(CLookToRead *p, int lookahead)
+{
+ p->s.Look = lookahead ?
+ LookToRead_Look_Lookahead :
+ LookToRead_Look_Exact;
+ p->s.Skip = LookToRead_Skip;
+ p->s.Read = LookToRead_Read;
+ p->s.Seek = LookToRead_Seek;
+}
+
+void LookToRead_Init(CLookToRead *p)
+{
+ p->pos = p->size = 0;
+}
+
+static SRes SecToLook_Read(void *pp, void *buf, size_t *size)
+{
+ CSecToLook *p = (CSecToLook *)pp;
+ return LookInStream_LookRead(p->realStream, buf, size);
+}
+
+void SecToLook_CreateVTable(CSecToLook *p)
+{
+ p->s.Read = SecToLook_Read;
+}
+
+static SRes SecToRead_Read(void *pp, void *buf, size_t *size)
+{
+ CSecToRead *p = (CSecToRead *)pp;
+ return p->realStream->Read(p->realStream, buf, size);
+}
+
+void SecToRead_CreateVTable(CSecToRead *p)
+{
+ p->s.Read = SecToRead_Read;
+}
diff --git a/lzma/C/7zTypes.h b/lzma/C/7zTypes.h
new file mode 100644
index 0000000..903047b
--- /dev/null
+++ b/lzma/C/7zTypes.h
@@ -0,0 +1,256 @@
+/* 7zTypes.h -- Basic types
+2013-11-12 : 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;
+#else
+typedef int WRes;
+#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 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_CDECL __cdecl
+#define MY_FAST_CALL __fastcall
+
+#else
+
+#define MY_NO_INLINE
+#define MY_CDECL
+#define MY_FAST_CALL
+
+#endif
+
+
+/* The following interfaces use first parameter as pointer to structure */
+
+typedef struct
+{
+ Byte (*Read)(void *p); /* reads one byte, returns 0 in case of EOF or error */
+} IByteIn;
+
+typedef struct
+{
+ void (*Write)(void *p, Byte b);
+} IByteOut;
+
+typedef struct
+{
+ SRes (*Read)(void *p, void *buf, size_t *size);
+ /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream.
+ (output(*size) < input(*size)) is allowed */
+} ISeqInStream;
+
+/* it can return SZ_ERROR_INPUT_EOF */
+SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size);
+SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType);
+SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf);
+
+typedef struct
+{
+ size_t (*Write)(void *p, const void *buf, size_t size);
+ /* Returns: result - the number of actually written bytes.
+ (result < size) means error */
+} ISeqOutStream;
+
+typedef enum
+{
+ SZ_SEEK_SET = 0,
+ SZ_SEEK_CUR = 1,
+ SZ_SEEK_END = 2
+} ESzSeek;
+
+typedef struct
+{
+ SRes (*Read)(void *p, void *buf, size_t *size); /* same as ISeqInStream::Read */
+ SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin);
+} ISeekInStream;
+
+typedef struct
+{
+ SRes (*Look)(void *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)(void *p, size_t offset);
+ /* offset must be <= output(*size) of Look */
+
+ SRes (*Read)(void *p, void *buf, size_t *size);
+ /* reads directly (without buffer). It's same as ISeqInStream::Read */
+ SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin);
+} ILookInStream;
+
+SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size);
+SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset);
+
+/* reads via ILookInStream::Read */
+SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType);
+SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size);
+
+#define LookToRead_BUF_SIZE (1 << 14)
+
+typedef struct
+{
+ ILookInStream s;
+ ISeekInStream *realStream;
+ size_t pos;
+ size_t size;
+ Byte buf[LookToRead_BUF_SIZE];
+} CLookToRead;
+
+void LookToRead_CreateVTable(CLookToRead *p, int lookahead);
+void LookToRead_Init(CLookToRead *p);
+
+typedef struct
+{
+ ISeqInStream s;
+ ILookInStream *realStream;
+} CSecToLook;
+
+void SecToLook_CreateVTable(CSecToLook *p);
+
+typedef struct
+{
+ ISeqInStream s;
+ ILookInStream *realStream;
+} CSecToRead;
+
+void SecToRead_CreateVTable(CSecToRead *p);
+
+typedef struct
+{
+ SRes (*Progress)(void *p, UInt64 inSize, UInt64 outSize);
+ /* Returns: result. (result != SZ_OK) means break.
+ Value (UInt64)(Int64)-1 for size means unknown value. */
+} ICompressProgress;
+
+typedef struct
+{
+ void *(*Alloc)(void *p, size_t size);
+ void (*Free)(void *p, void *address); /* address can be 0 */
+} ISzAlloc;
+
+#define IAlloc_Alloc(p, size) (p)->Alloc((p), size)
+#define IAlloc_Free(p, a) (p)->Free((p), a)
+
+#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
diff --git a/lzma/C/7zVersion.h b/lzma/C/7zVersion.h
new file mode 100644
index 0000000..feedd30
--- /dev/null
+++ b/lzma/C/7zVersion.h
@@ -0,0 +1,10 @@
+#define MY_VER_MAJOR 9
+#define MY_VER_MINOR 38
+#define MY_VER_BUILD 00
+#define MY_VERSION "9.38 beta"
+// #define MY_7ZIP_VERSION "9.38"
+#define MY_DATE "2015-01-03"
+#undef MY_COPYRIGHT
+#undef MY_VERSION_COPYRIGHT_DATE
+#define MY_COPYRIGHT ": Igor Pavlov : Public domain"
+#define MY_VERSION_COPYRIGHT_DATE MY_VERSION " " MY_COPYRIGHT " : " MY_DATE
diff --git a/lzma/C/7zVersion.rc b/lzma/C/7zVersion.rc
new file mode 100644
index 0000000..6ed26de
--- /dev/null
+++ b/lzma/C/7zVersion.rc
@@ -0,0 +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")
diff --git a/lzma/C/Aes.c b/lzma/C/Aes.c
new file mode 100644
index 0000000..06bf9d3
--- /dev/null
+++ b/lzma/C/Aes.c
@@ -0,0 +1,284 @@
+/* Aes.c -- AES encryption / decryption
+2013-11-12 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "Aes.h"
+#include "CpuArch.h"
+
+static UInt32 T[256 * 4];
+static 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 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)) & 0xFF)
+
+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;
+ T[ i] = Ui32(a2, a1, a1, a3);
+ T[0x100 + i] = Ui32(a3, a2, a1, a1);
+ T[0x200 + i] = Ui32(a1, a3, a2, a1);
+ T[0x300 + 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;
+ D[ i] = Ui32(aE, a9, aD, aB);
+ D[0x100 + i] = Ui32(aB, aE, a9, aD);
+ D[0x200 + i] = Ui32(aD, aB, aE, a9);
+ D[0x300 + 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) (T + (x << 8))[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]
+/* such order (2031) in HT16 is for VC6/K8 speed optimization) */
+#define HT16(m, s, p) \
+ HT4(m, 2, s, p); \
+ HT4(m, 0, s, p); \
+ HT4(m, 3, s, p); \
+ HT4(m, 1, 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) (D + (x << 8))[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];
+/* such order (0231) in HD16 is for VC6/K8 speed optimization) */
+#define HD16(m, s, p) \
+ HD4(m, 0, s, p); \
+ HD4(m, 2, s, p); \
+ HD4(m, 3, s, p); \
+ HD4(m, 1, 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[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] =
+ D[ Sbox[gb0(r)]] ^
+ D[0x100 + Sbox[gb1(r)]] ^
+ D[0x200 + Sbox[gb2(r)]] ^
+ D[0x300 + Sbox[gb3(r)]];
+ }
+}
+
+/* Aes_Encode and Aes_Decode functions work with little-endian words.
+ src and dest are pointers to 4 UInt32 words.
+ arc 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];
+ Byte buf[16];
+ int i;
+ if (++p[0] == 0)
+ p[1]++;
+ Aes_Encode(p + 4, temp, p);
+ SetUi32(buf, temp[0]);
+ SetUi32(buf + 4, temp[1]);
+ SetUi32(buf + 8, temp[2]);
+ SetUi32(buf + 12, temp[3]);
+ for (i = 0; i < 16; i++)
+ *data++ ^= buf[i];
+ }
+}
diff --git a/lzma/C/Aes.h b/lzma/C/Aes.h
new file mode 100644
index 0000000..381e979
--- /dev/null
+++ b/lzma/C/Aes.h
@@ -0,0 +1,38 @@
+/* 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
diff --git a/lzma/C/AesOpt.c b/lzma/C/AesOpt.c
new file mode 100644
index 0000000..e5d4d26
--- /dev/null
+++ b/lzma/C/AesOpt.c
@@ -0,0 +1,184 @@
+/* AesOpt.c -- Intel's AES
+2013-11-12 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "CpuArch.h"
+
+#ifdef MY_CPU_X86_OR_AMD64
+#if _MSC_VER >= 1500
+#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
diff --git a/lzma/C/Alloc.c b/lzma/C/Alloc.c
new file mode 100644
index 0000000..8e2839a
--- /dev/null
+++ b/lzma/C/Alloc.c
@@ -0,0 +1,127 @@
+/* Alloc.c -- Memory allocation functions
+2013-11-12 : Igor Pavlov : Public domain */
+
+#include "Precomp.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;
+#endif
+
+void *MyAlloc(size_t size)
+{
+ if (size == 0)
+ return 0;
+ #ifdef _SZ_ALLOC_DEBUG
+ {
+ void *p = malloc(size);
+ fprintf(stderr, "\nAlloc %10d bytes, count = %10d, addr = %8X", size, g_allocCount++, (unsigned)p);
+ return p;
+ }
+ #else
+ return malloc(size);
+ #endif
+}
+
+void MyFree(void *address)
+{
+ #ifdef _SZ_ALLOC_DEBUG
+ if (address != 0)
+ fprintf(stderr, "\nFree; count = %10d, addr = %8X", --g_allocCount, (unsigned)address);
+ #endif
+ free(address);
+}
+
+#ifdef _WIN32
+
+void *MidAlloc(size_t size)
+{
+ if (size == 0)
+ return 0;
+ #ifdef _SZ_ALLOC_DEBUG
+ fprintf(stderr, "\nAlloc_Mid %10d bytes; count = %10d", size, g_allocCountMid++);
+ #endif
+ return VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE);
+}
+
+void MidFree(void *address)
+{
+ #ifdef _SZ_ALLOC_DEBUG
+ if (address != 0)
+ fprintf(stderr, "\nFree_Mid; count = %10d", --g_allocCountMid);
+ #endif
+ if (address == 0)
+ 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 = 0;
+ GetLargePageMinimumP largePageMinimum = (GetLargePageMinimumP)
+ GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "GetLargePageMinimum");
+ if (largePageMinimum == 0)
+ return;
+ size = largePageMinimum();
+ if (size == 0 || (size & (size - 1)) != 0)
+ return;
+ g_LargePageSize = size;
+ #endif
+}
+
+
+void *BigAlloc(size_t size)
+{
+ if (size == 0)
+ return 0;
+ #ifdef _SZ_ALLOC_DEBUG
+ fprintf(stderr, "\nAlloc_Big %10d bytes; count = %10d", size, g_allocCountBig++);
+ #endif
+
+ #ifdef _7ZIP_LARGE_PAGES
+ if (g_LargePageSize != 0 && g_LargePageSize <= (1 << 30) && size >= (1 << 18))
+ {
+ void *res = VirtualAlloc(0, (size + g_LargePageSize - 1) & (~(g_LargePageSize - 1)),
+ MEM_COMMIT | MEM_LARGE_PAGES, PAGE_READWRITE);
+ if (res != 0)
+ return res;
+ }
+ #endif
+ return VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE);
+}
+
+void BigFree(void *address)
+{
+ #ifdef _SZ_ALLOC_DEBUG
+ if (address != 0)
+ fprintf(stderr, "\nFree_Big; count = %10d", --g_allocCountBig);
+ #endif
+
+ if (address == 0)
+ return;
+ VirtualFree(address, 0, MEM_RELEASE);
+}
+
+#endif
diff --git a/lzma/C/Alloc.h b/lzma/C/Alloc.h
new file mode 100644
index 0000000..6b3f034
--- /dev/null
+++ b/lzma/C/Alloc.h
@@ -0,0 +1,38 @@
+/* Alloc.h -- Memory allocation functions
+2009-02-07 : Igor Pavlov : Public domain */
+
+#ifndef __COMMON_ALLOC_H
+#define __COMMON_ALLOC_H
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+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
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/lzma/C/Android.bp b/lzma/C/Android.bp
new file mode 100644
index 0000000..1971bf3
--- /dev/null
+++ b/lzma/C/Android.bp
@@ -0,0 +1,59 @@
+// Copyright 2015 The Android Open Source Project
+
+cc_library {
+ name: "liblzma",
+ host_supported: true,
+ sdk_version: "9",
+ stl: "none",
+
+ cflags: ["-D_7ZIP_ST", "-Wno-empty-body"],
+ clang_cflags: ["-Wno-self-assign"],
+
+ export_include_dirs: ["."],
+
+ srcs: [
+ "7zAlloc.c",
+ "7zArcIn.c",
+ "7zBuf2.c",
+ "7zBuf.c",
+ "7zCrc.c",
+ "7zCrcOpt.c",
+ "7zDec.c",
+ "7zFile.c",
+ "7zStream.c",
+ "Aes.c",
+ "AesOpt.c",
+ "Alloc.c",
+ "Bcj2.c",
+ "Bra86.c",
+ "Bra.c",
+ "BraIA64.c",
+ "CpuArch.c",
+ "Delta.c",
+ "LzFind.c",
+ "Lzma2Dec.c",
+ "Lzma2Enc.c",
+ "Lzma86Dec.c",
+ "Lzma86Enc.c",
+ "LzmaDec.c",
+ "LzmaEnc.c",
+ "LzmaLib.c",
+ "Ppmd7.c",
+ "Ppmd7Dec.c",
+ "Ppmd7Enc.c",
+ "Sha256.c",
+ "Sort.c",
+ "Xz.c",
+ "XzCrc64.c",
+ "XzCrc64Opt.c",
+ "XzDec.c",
+ "XzEnc.c",
+ "XzIn.c",
+ ],
+
+ target: {
+ windows: {
+ enabled: true,
+ },
+ },
+}
diff --git a/lzma/C/Bcj2.c b/lzma/C/Bcj2.c
new file mode 100644
index 0000000..ac4ca0c
--- /dev/null
+++ b/lzma/C/Bcj2.c
@@ -0,0 +1,134 @@
+/* Bcj2.c -- Converter for x86 code (BCJ2)
+2008-10-04 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "Bcj2.h"
+
+#ifdef _LZMA_PROB32
+#define CProb UInt32
+#else
+#define CProb UInt16
+#endif
+
+#define IsJcc(b0, b1) ((b0) == 0x0F && ((b1) & 0xF0) == 0x80)
+#define IsJ(b0, b1) ((b1 & 0xFE) == 0xE8 || IsJcc(b0, b1))
+
+#define kNumTopBits 24
+#define kTopValue ((UInt32)1 << kNumTopBits)
+
+#define kNumBitModelTotalBits 11
+#define kBitModelTotal (1 << kNumBitModelTotalBits)
+#define kNumMoveBits 5
+
+#define RC_READ_BYTE (*buffer++)
+#define RC_TEST { if (buffer == bufferLim) return SZ_ERROR_DATA; }
+#define RC_INIT2 code = 0; range = 0xFFFFFFFF; \
+ { int i; for (i = 0; i < 5; i++) { RC_TEST; code = (code << 8) | RC_READ_BYTE; }}
+
+#define NORMALIZE if (range < kTopValue) { RC_TEST; range <<= 8; code = (code << 8) | RC_READ_BYTE; }
+
+#define IF_BIT_0(p) ttt = *(p); bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound)
+#define UPDATE_0(p) range = bound; *(p) = (CProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); NORMALIZE;
+#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CProb)(ttt - (ttt >> kNumMoveBits)); NORMALIZE;
+
+int Bcj2_Decode(
+ const Byte *buf0, SizeT size0,
+ const Byte *buf1, SizeT size1,
+ const Byte *buf2, SizeT size2,
+ const Byte *buf3, SizeT size3,
+ Byte *outBuf, SizeT outSize)
+{
+ CProb p[256 + 2];
+ SizeT inPos = 0, outPos = 0;
+
+ const Byte *buffer, *bufferLim;
+ UInt32 range, code;
+ Byte prevByte = 0;
+
+ unsigned int i;
+ for (i = 0; i < sizeof(p) / sizeof(p[0]); i++)
+ p[i] = kBitModelTotal >> 1;
+
+ buffer = buf3;
+ bufferLim = buffer + size3;
+ RC_INIT2
+
+ if (outSize == 0)
+ return SZ_OK;
+
+ for (;;)
+ {
+ Byte b;
+ CProb *prob;
+ UInt32 bound;
+ UInt32 ttt;
+
+ SizeT limit = size0 - inPos;
+ if (outSize - outPos < limit)
+ limit = outSize - outPos;
+ while (limit != 0)
+ {
+ Byte b = buf0[inPos];
+ outBuf[outPos++] = b;
+ if (IsJ(prevByte, b))
+ break;
+ inPos++;
+ prevByte = b;
+ limit--;
+ }
+
+ if (limit == 0 || outPos == outSize)
+ break;
+
+ b = buf0[inPos++];
+
+ if (b == 0xE8)
+ prob = p + prevByte;
+ else if (b == 0xE9)
+ prob = p + 256;
+ else
+ prob = p + 257;
+
+ IF_BIT_0(prob)
+ {
+ UPDATE_0(prob)
+ prevByte = b;
+ }
+ else
+ {
+ UInt32 dest;
+ const Byte *v;
+ UPDATE_1(prob)
+ if (b == 0xE8)
+ {
+ v = buf1;
+ if (size1 < 4)
+ return SZ_ERROR_DATA;
+ buf1 += 4;
+ size1 -= 4;
+ }
+ else
+ {
+ v = buf2;
+ if (size2 < 4)
+ return SZ_ERROR_DATA;
+ buf2 += 4;
+ size2 -= 4;
+ }
+ dest = (((UInt32)v[0] << 24) | ((UInt32)v[1] << 16) |
+ ((UInt32)v[2] << 8) | ((UInt32)v[3])) - ((UInt32)outPos + 4);
+ outBuf[outPos++] = (Byte)dest;
+ if (outPos == outSize)
+ break;
+ outBuf[outPos++] = (Byte)(dest >> 8);
+ if (outPos == outSize)
+ break;
+ outBuf[outPos++] = (Byte)(dest >> 16);
+ if (outPos == outSize)
+ break;
+ outBuf[outPos++] = prevByte = (Byte)(dest >> 24);
+ }
+ }
+ return (outPos == outSize) ? SZ_OK : SZ_ERROR_DATA;
+}
diff --git a/lzma/C/Bcj2.h b/lzma/C/Bcj2.h
new file mode 100644
index 0000000..e8304c5
--- /dev/null
+++ b/lzma/C/Bcj2.h
@@ -0,0 +1,34 @@
+/* Bcj2.h -- Converter for x86 code (BCJ2)
+2013-01-18 : Igor Pavlov : Public domain */
+
+#ifndef __BCJ2_H
+#define __BCJ2_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+/*
+Conditions:
+ outSize <= FullOutputSize,
+ where FullOutputSize is full size of output stream of x86_2 filter.
+
+If buf0 overlaps outBuf, there are two required conditions:
+ 1) (buf0 >= outBuf)
+ 2) (buf0 + size0 >= outBuf + FullOutputSize).
+
+Returns:
+ SZ_OK
+ SZ_ERROR_DATA - Data error
+*/
+
+int Bcj2_Decode(
+ const Byte *buf0, SizeT size0,
+ const Byte *buf1, SizeT size1,
+ const Byte *buf2, SizeT size2,
+ const Byte *buf3, SizeT size3,
+ Byte *outBuf, SizeT outSize);
+
+EXTERN_C_END
+
+#endif
diff --git a/lzma/C/Bra.c b/lzma/C/Bra.c
new file mode 100644
index 0000000..976810c
--- /dev/null
+++ b/lzma/C/Bra.c
@@ -0,0 +1,135 @@
+/* Bra.c -- Converters for RISC code
+2010-04-16 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "Bra.h"
+
+SizeT ARM_Convert(Byte *data, SizeT size, UInt32 ip, int encoding)
+{
+ SizeT i;
+ if (size < 4)
+ return 0;
+ size -= 4;
+ ip += 8;
+ for (i = 0; i <= size; i += 4)
+ {
+ if (data[i + 3] == 0xEB)
+ {
+ UInt32 dest;
+ UInt32 src = ((UInt32)data[i + 2] << 16) | ((UInt32)data[i + 1] << 8) | (data[i + 0]);
+ src <<= 2;
+ if (encoding)
+ dest = ip + (UInt32)i + src;
+ else
+ dest = src - (ip + (UInt32)i);
+ dest >>= 2;
+ data[i + 2] = (Byte)(dest >> 16);
+ data[i + 1] = (Byte)(dest >> 8);
+ data[i + 0] = (Byte)dest;
+ }
+ }
+ return i;
+}
+
+SizeT ARMT_Convert(Byte *data, SizeT size, UInt32 ip, int encoding)
+{
+ SizeT i;
+ if (size < 4)
+ return 0;
+ size -= 4;
+ ip += 4;
+ for (i = 0; i <= size; i += 2)
+ {
+ if ((data[i + 1] & 0xF8) == 0xF0 &&
+ (data[i + 3] & 0xF8) == 0xF8)
+ {
+ UInt32 dest;
+ UInt32 src =
+ (((UInt32)data[i + 1] & 0x7) << 19) |
+ ((UInt32)data[i + 0] << 11) |
+ (((UInt32)data[i + 3] & 0x7) << 8) |
+ (data[i + 2]);
+
+ src <<= 1;
+ if (encoding)
+ dest = ip + (UInt32)i + src;
+ else
+ dest = src - (ip + (UInt32)i);
+ dest >>= 1;
+
+ data[i + 1] = (Byte)(0xF0 | ((dest >> 19) & 0x7));
+ data[i + 0] = (Byte)(dest >> 11);
+ data[i + 3] = (Byte)(0xF8 | ((dest >> 8) & 0x7));
+ data[i + 2] = (Byte)dest;
+ i += 2;
+ }
+ }
+ return i;
+}
+
+SizeT PPC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding)
+{
+ SizeT i;
+ if (size < 4)
+ return 0;
+ size -= 4;
+ for (i = 0; i <= size; i += 4)
+ {
+ if ((data[i] >> 2) == 0x12 && (data[i + 3] & 3) == 1)
+ {
+ UInt32 src = ((UInt32)(data[i + 0] & 3) << 24) |
+ ((UInt32)data[i + 1] << 16) |
+ ((UInt32)data[i + 2] << 8) |
+ ((UInt32)data[i + 3] & (~3));
+
+ UInt32 dest;
+ if (encoding)
+ dest = ip + (UInt32)i + src;
+ else
+ dest = src - (ip + (UInt32)i);
+ data[i + 0] = (Byte)(0x48 | ((dest >> 24) & 0x3));
+ data[i + 1] = (Byte)(dest >> 16);
+ data[i + 2] = (Byte)(dest >> 8);
+ data[i + 3] &= 0x3;
+ data[i + 3] |= dest;
+ }
+ }
+ return i;
+}
+
+SizeT SPARC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding)
+{
+ UInt32 i;
+ if (size < 4)
+ return 0;
+ size -= 4;
+ for (i = 0; i <= size; i += 4)
+ {
+ if ((data[i] == 0x40 && (data[i + 1] & 0xC0) == 0x00) ||
+ (data[i] == 0x7F && (data[i + 1] & 0xC0) == 0xC0))
+ {
+ UInt32 src =
+ ((UInt32)data[i + 0] << 24) |
+ ((UInt32)data[i + 1] << 16) |
+ ((UInt32)data[i + 2] << 8) |
+ ((UInt32)data[i + 3]);
+ UInt32 dest;
+
+ src <<= 2;
+ if (encoding)
+ dest = ip + i + src;
+ else
+ dest = src - (ip + i);
+ dest >>= 2;
+
+ dest = (((0 - ((dest >> 22) & 1)) << 22) & 0x3FFFFFFF) | (dest & 0x3FFFFF) | 0x40000000;
+
+ data[i + 0] = (Byte)(dest >> 24);
+ data[i + 1] = (Byte)(dest >> 16);
+ data[i + 2] = (Byte)(dest >> 8);
+ data[i + 3] = (Byte)dest;
+ }
+ }
+ return i;
+}
diff --git a/lzma/C/Bra.h b/lzma/C/Bra.h
new file mode 100644
index 0000000..aba8dce
--- /dev/null
+++ b/lzma/C/Bra.h
@@ -0,0 +1,64 @@
+/* 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
diff --git a/lzma/C/Bra86.c b/lzma/C/Bra86.c
new file mode 100644
index 0000000..8dd3ed4
--- /dev/null
+++ b/lzma/C/Bra86.c
@@ -0,0 +1,82 @@
+/* Bra86.c -- Converter for x86 code (BCJ)
+2013-11-12 : 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[(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++;
+ }
+ }
+}
diff --git a/lzma/C/BraIA64.c b/lzma/C/BraIA64.c
new file mode 100644
index 0000000..813830c
--- /dev/null
+++ b/lzma/C/BraIA64.c
@@ -0,0 +1,69 @@
+/* BraIA64.c -- Converter for IA-64 code
+2013-11-12 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "Bra.h"
+
+static const Byte kBranchTable[32] =
+{
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 4, 4, 6, 6, 0, 0, 7, 7,
+ 4, 4, 0, 0, 4, 4, 0, 0
+};
+
+SizeT IA64_Convert(Byte *data, SizeT size, UInt32 ip, int encoding)
+{
+ SizeT i;
+ if (size < 16)
+ return 0;
+ size -= 16;
+ for (i = 0; i <= size; i += 16)
+ {
+ UInt32 instrTemplate = data[i] & 0x1F;
+ UInt32 mask = kBranchTable[instrTemplate];
+ UInt32 bitPos = 5;
+ int slot;
+ for (slot = 0; slot < 3; slot++, bitPos += 41)
+ {
+ UInt32 bytePos, bitRes;
+ UInt64 instruction, instNorm;
+ int j;
+ if (((mask >> slot) & 1) == 0)
+ continue;
+ bytePos = (bitPos >> 3);
+ bitRes = bitPos & 0x7;
+ instruction = 0;
+ for (j = 0; j < 6; j++)
+ instruction += (UInt64)data[i + j + bytePos] << (8 * j);
+
+ instNorm = instruction >> bitRes;
+ if (((instNorm >> 37) & 0xF) == 0x5 && ((instNorm >> 9) & 0x7) == 0)
+ {
+ UInt32 src = (UInt32)((instNorm >> 13) & 0xFFFFF);
+ UInt32 dest;
+ src |= ((UInt32)(instNorm >> 36) & 1) << 20;
+
+ src <<= 4;
+
+ if (encoding)
+ dest = ip + (UInt32)i + src;
+ else
+ dest = src - (ip + (UInt32)i);
+
+ dest >>= 4;
+
+ instNorm &= ~((UInt64)(0x8FFFFF) << 13);
+ instNorm |= ((UInt64)(dest & 0xFFFFF) << 13);
+ instNorm |= ((UInt64)(dest & 0x100000) << (36 - 20));
+
+ instruction &= (1 << bitRes) - 1;
+ instruction |= (instNorm << bitRes);
+ for (j = 0; j < 6; j++)
+ data[i + j + bytePos] = (Byte)(instruction >> (8 * j));
+ }
+ }
+ }
+ return i;
+}
diff --git a/lzma/C/Compiler.h b/lzma/C/Compiler.h
new file mode 100644
index 0000000..0f76670
--- /dev/null
+++ b/lzma/C/Compiler.h
@@ -0,0 +1,28 @@
+/* Compiler.h -- Compiler ypes
+2013-11-12 : 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 : 4702) // unreachable code
+ #pragma warning(disable : 4710) // not inlined
+ #pragma warning(disable : 4786) // identifier was truncated to '255' characters in the debug information
+ #endif
+
+#endif
+
+#endif
diff --git a/lzma/C/CpuArch.c b/lzma/C/CpuArch.c
new file mode 100644
index 0000000..f8ac0c2
--- /dev/null
+++ b/lzma/C/CpuArch.c
@@ -0,0 +1,190 @@
+/* CpuArch.c -- CPU specific code
+2012-05-29: 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));
+ #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
+
+static 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_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
+}
+
+Bool 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 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;
+}
+
+Bool CPU_Is_InOrder()
+{
+ Cx86cpuid p;
+ int firm;
+ UInt32 family, model;
+ if (!x86cpuid_CheckAndRead(&p))
+ return True;
+ family = x86cpuid_GetFamily(&p);
+ model = x86cpuid_GetModel(&p);
+ firm = x86cpuid_GetFirm(&p);
+ switch (firm)
+ {
+ case CPU_FIRM_INTEL: return (family < 6 || (family == 6 && (
+ /* Atom CPU */
+ model == 0x100C /* 45 nm, N4xx, D4xx, N5xx, D5xx, 230, 330 */
+ || model == 0x2006 /* 45 nm, Z6xx */
+ || model == 0x2007 /* 32 nm, Z2460 */
+ || model == 0x3005 /* 32 nm, Z2760 */
+ || model == 0x3006 /* 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 Bool 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
+
+Bool CPU_Is_Aes_Supported()
+{
+ Cx86cpuid p;
+ CHECK_SYS_SSE_SUPPORT
+ if (!x86cpuid_CheckAndRead(&p))
+ return False;
+ return (p.c >> 25) & 1;
+}
+
+#endif
diff --git a/lzma/C/CpuArch.h b/lzma/C/CpuArch.h
new file mode 100644
index 0000000..2316205
--- /dev/null
+++ b/lzma/C/CpuArch.h
@@ -0,0 +1,157 @@
+/* CpuArch.h -- CPU specific code
+2013-11-12: 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.
+If MY_CPU_LE is not defined, we don't know about that property of platform (it can be LITTLE ENDIAN).
+
+MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned memory accesses.
+If MY_CPU_LE_UNALIGN is not defined, we don't know about these properties of platform.
+*/
+
+#if defined(_M_X64) || defined(_M_AMD64) || defined(__x86_64__)
+#define MY_CPU_AMD64
+#endif
+
+#if defined(MY_CPU_AMD64) || defined(_M_IA64)
+#define MY_CPU_64BIT
+#endif
+
+#if defined(_M_IX86) || defined(__i386__)
+#define MY_CPU_X86
+#endif
+
+#if defined(MY_CPU_X86) || defined(MY_CPU_AMD64)
+#define MY_CPU_X86_OR_AMD64
+#endif
+
+#if defined(MY_CPU_X86) || defined(_M_ARM)
+#define MY_CPU_32BIT
+#endif
+
+#if defined(_WIN32) && defined(_M_ARM)
+#define MY_CPU_ARM_LE
+#endif
+
+#if defined(_WIN32) && defined(_M_IA64)
+#define MY_CPU_IA64_LE
+#endif
+
+#if defined(MY_CPU_X86_OR_AMD64)
+#define MY_CPU_LE_UNALIGN
+#endif
+
+#if defined(MY_CPU_X86_OR_AMD64) || defined(MY_CPU_ARM_LE) || defined(MY_CPU_IA64_LE) || defined(__ARMEL__) || defined(__MIPSEL__) || defined(__LITTLE_ENDIAN__)
+#define MY_CPU_LE
+#endif
+
+#if defined(__BIG_ENDIAN__) || defined(__m68k__) || defined(__ARMEB__) || defined(__MIPSEB__)
+#define MY_CPU_BE
+#endif
+
+#if defined(MY_CPU_LE) && defined(MY_CPU_BE)
+Stop_Compiling_Bad_Endian
+#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, d) *(UInt16 *)(p) = (d);
+#define SetUi32(p, d) *(UInt32 *)(p) = (d);
+#define SetUi64(p, d) *(UInt64 *)(p) = (d);
+
+#else
+
+#define GetUi16(p) (((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, d) { UInt32 _x_ = (d); \
+ ((Byte *)(p))[0] = (Byte)_x_; \
+ ((Byte *)(p))[1] = (Byte)(_x_ >> 8); }
+
+#define SetUi32(p, d) { UInt32 _x_ = (d); \
+ ((Byte *)(p))[0] = (Byte)_x_; \
+ ((Byte *)(p))[1] = (Byte)(_x_ >> 8); \
+ ((Byte *)(p))[2] = (Byte)(_x_ >> 16); \
+ ((Byte *)(p))[3] = (Byte)(_x_ >> 24); }
+
+#define SetUi64(p, d) { UInt64 _x64_ = (d); \
+ SetUi32(p, (UInt32)_x64_); \
+ SetUi32(((Byte *)(p)) + 4, (UInt32)(_x64_ >> 32)); }
+
+#endif
+
+#if defined(MY_CPU_LE_UNALIGN) && defined(_WIN64) && (_MSC_VER >= 1300)
+
+#include <stdlib.h>
+
+#pragma intrinsic(_byteswap_ulong)
+#pragma intrinsic(_byteswap_uint64)
+#define GetBe32(p) _byteswap_ulong(*(const UInt32 *)(const Byte *)(p))
+#define GetBe64(p) _byteswap_uint64(*(const UInt64 *)(const Byte *)(p))
+
+#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))
+
+#endif
+
+#define GetBe16(p) ((UInt16)(((UInt16)((const Byte *)(p))[0] << 8) | ((const Byte *)(p))[1]))
+
+
+#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
+};
+
+Bool x86cpuid_CheckAndRead(Cx86cpuid *p);
+int x86cpuid_GetFirm(const Cx86cpuid *p);
+
+#define x86cpuid_GetFamily(p) (((p)->ver >> 8) & 0xFF00F)
+#define x86cpuid_GetModel(p) (((p)->ver >> 4) & 0xF00F)
+#define x86cpuid_GetStepping(p) ((p)->ver & 0xF)
+
+Bool CPU_Is_InOrder();
+Bool CPU_Is_Aes_Supported();
+
+#endif
+
+EXTERN_C_END
+
+#endif
diff --git a/lzma/C/Delta.c b/lzma/C/Delta.c
new file mode 100644
index 0000000..6cbbe46
--- /dev/null
+++ b/lzma/C/Delta.c
@@ -0,0 +1,64 @@
+/* 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);
+}
diff --git a/lzma/C/Delta.h b/lzma/C/Delta.h
new file mode 100644
index 0000000..e59d5a2
--- /dev/null
+++ b/lzma/C/Delta.h
@@ -0,0 +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
diff --git a/lzma/C/LzFind.c b/lzma/C/LzFind.c
new file mode 100644
index 0000000..df79867
--- /dev/null
+++ b/lzma/C/LzFind.c
@@ -0,0 +1,763 @@
+/* LzFind.c -- Match finder for LZ algorithms
+2009-04-22 : 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 (~(kNormalizeStepMin - 1))
+#define kMaxHistorySize ((UInt32)3 << 30)
+
+#define kStartMaxLen 3
+
+static void LzInWindow_Free(CMatchFinder *p, ISzAlloc *alloc)
+{
+ if (!p->directInput)
+ {
+ alloc->Free(alloc, p->bufferBase);
+ p->bufferBase = 0;
+ }
+}
+
+/* keepSizeBefore + keepSizeAfter + keepSizeReserv must be < 4G) */
+
+static int LzInWindow_Create(CMatchFinder *p, UInt32 keepSizeReserv, ISzAlloc *alloc)
+{
+ UInt32 blockSize = p->keepSizeBefore + p->keepSizeAfter + keepSizeReserv;
+ if (p->directInput)
+ {
+ p->blockSize = blockSize;
+ return 1;
+ }
+ if (p->bufferBase == 0 || p->blockSize != blockSize)
+ {
+ LzInWindow_Free(p, alloc);
+ p->blockSize = blockSize;
+ p->bufferBase = (Byte *)alloc->Alloc(alloc, (size_t)blockSize);
+ }
+ return (p->bufferBase != 0);
+}
+
+Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; }
+Byte MatchFinder_GetIndexByte(CMatchFinder *p, Int32 index) { return p->buffer[index]; }
+
+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;
+ if (p->directInput)
+ {
+ UInt32 curSize = 0xFFFFFFFF - p->streamPos;
+ 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 = p->stream->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)
+{
+ UInt32 i;
+ p->bufferBase = 0;
+ p->directInput = 0;
+ p->hash = 0;
+ MatchFinder_SetDefaultSettings(p);
+
+ for (i = 0; i < 256; i++)
+ {
+ UInt32 r = i;
+ int j;
+ for (j = 0; j < 8; j++)
+ r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1));
+ p->crc[i] = r;
+ }
+}
+
+static void MatchFinder_FreeThisClassMemory(CMatchFinder *p, ISzAlloc *alloc)
+{
+ alloc->Free(alloc, p->hash);
+ p->hash = 0;
+}
+
+void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc)
+{
+ MatchFinder_FreeThisClassMemory(p, alloc);
+ LzInWindow_Free(p, alloc);
+}
+
+static CLzRef* AllocRefs(UInt32 num, ISzAlloc *alloc)
+{
+ size_t sizeInBytes = (size_t)num * sizeof(CLzRef);
+ if (sizeInBytes / sizeof(CLzRef) != num)
+ return 0;
+ return (CLzRef *)alloc->Alloc(alloc, sizeInBytes);
+}
+
+int MatchFinder_Create(CMatchFinder *p, UInt32 historySize,
+ UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
+ ISzAlloc *alloc)
+{
+ UInt32 sizeReserv;
+ if (historySize > kMaxHistorySize)
+ {
+ MatchFinder_Free(p, alloc);
+ return 0;
+ }
+ sizeReserv = historySize >> 1;
+ 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 - 1;
+ 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;
+ }
+ }
+ 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;
+ }
+
+ {
+ UInt32 prevSize = p->hashSizeSum + p->numSons;
+ UInt32 newSize;
+ p->historySize = historySize;
+ p->hashSizeSum = hs;
+ p->cyclicBufferSize = newCyclicBufferSize;
+ p->numSons = (p->btMode ? newCyclicBufferSize * 2 : newCyclicBufferSize);
+ newSize = p->hashSizeSum + p->numSons;
+ if (p->hash != 0 && prevSize == newSize)
+ return 1;
+ MatchFinder_FreeThisClassMemory(p, alloc);
+ p->hash = AllocRefs(newSize, alloc);
+ if (p->hash != 0)
+ {
+ 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(CMatchFinder *p)
+{
+ UInt32 i;
+ for (i = 0; i < p->hashSizeSum; i++)
+ p->hash[i] = kEmptyHashValue;
+ p->cyclicBufferPos = 0;
+ p->buffer = p->bufferBase;
+ p->pos = p->streamPos = p->cyclicBufferSize;
+ p->result = SZ_OK;
+ p->streamEndWasReached = 0;
+ MatchFinder_ReadBlock(p);
+ MatchFinder_SetLimits(p);
+}
+
+static UInt32 MatchFinder_GetSubValue(CMatchFinder *p)
+{
+ return (p->pos - p->historySize - 1) & kNormalizeMask;
+}
+
+void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems)
+{
+ UInt32 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->hashSizeSum + p->numSons);
+ MatchFinder_ReduceOffsets(p, subValue);
+}
+
+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);
+}
+
+static UInt32 * Hc_GetMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
+ UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue,
+ UInt32 *distances, UInt32 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)
+ {
+ *distances++ = maxLen = len;
+ *distances++ = delta - 1;
+ if (len == lenLimit)
+ return distances;
+ }
+ }
+ }
+ }
+}
+
+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 + (_cyclicBufferPos << 1) + 1;
+ CLzRef *ptr1 = son + (_cyclicBufferPos << 1);
+ UInt32 len0 = 0, len1 = 0;
+ for (;;)
+ {
+ UInt32 delta = pos - curMatch;
+ if (cutValue-- == 0 || delta >= _cyclicBufferSize)
+ {
+ *ptr0 = *ptr1 = kEmptyHashValue;
+ return distances;
+ }
+ {
+ CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
+ const Byte *pb = cur - delta;
+ UInt32 len = (len0 < len1 ? len0 : len1);
+ if (pb[len] == cur[len])
+ {
+ if (++len != lenLimit && pb[len] == cur[len])
+ while (++len != lenLimit)
+ if (pb[len] != cur[len])
+ break;
+ if (maxLen < len)
+ {
+ *distances++ = maxLen = len;
+ *distances++ = delta - 1;
+ if (len == lenLimit)
+ {
+ *ptr1 = pair[0];
+ *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 + (_cyclicBufferPos << 1) + 1;
+ CLzRef *ptr1 = son + (_cyclicBufferPos << 1);
+ UInt32 len0 = 0, len1 = 0;
+ for (;;)
+ {
+ UInt32 delta = pos - curMatch;
+ if (cutValue-- == 0 || delta >= _cyclicBufferSize)
+ {
+ *ptr0 = *ptr1 = kEmptyHashValue;
+ return;
+ }
+ {
+ CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
+ const Byte *pb = cur - delta;
+ UInt32 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 offset;
+
+static void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; }
+
+#define GET_MATCHES_HEADER2(minLen, ret_op) \
+ UInt32 lenLimit; UInt32 hashValue; const Byte *cur; UInt32 curMatch; \
+ lenLimit = 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 = (UInt32)(GetMatchesSpec1(lenLimit, curMatch, MF_PARAMS(p), \
+ distances + offset, maxLen) - distances); MOVE_POS_RET;
+
+#define SKIP_FOOTER \
+ SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS;
+
+static UInt32 Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ UInt32 offset;
+ GET_MATCHES_HEADER(2)
+ HASH2_CALC;
+ curMatch = p->hash[hashValue];
+ p->hash[hashValue] = p->pos;
+ offset = 0;
+ GET_MATCHES_FOOTER(offset, 1)
+}
+
+UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ UInt32 offset;
+ GET_MATCHES_HEADER(3)
+ HASH_ZIP_CALC;
+ curMatch = p->hash[hashValue];
+ p->hash[hashValue] = p->pos;
+ offset = 0;
+ GET_MATCHES_FOOTER(offset, 2)
+}
+
+static UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ UInt32 hash2Value, delta2, maxLen, offset;
+ GET_MATCHES_HEADER(3)
+
+ HASH3_CALC;
+
+ delta2 = p->pos - p->hash[hash2Value];
+ curMatch = p->hash[kFix3HashSize + hashValue];
+
+ p->hash[hash2Value] =
+ p->hash[kFix3HashSize + hashValue] = p->pos;
+
+
+ maxLen = 2;
+ offset = 0;
+ if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
+ {
+ for (; maxLen != lenLimit; maxLen++)
+ if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
+ break;
+ distances[0] = maxLen;
+ distances[1] = delta2 - 1;
+ offset = 2;
+ if (maxLen == lenLimit)
+ {
+ SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
+ MOVE_POS_RET;
+ }
+ }
+ GET_MATCHES_FOOTER(offset, maxLen)
+}
+
+static UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset;
+ GET_MATCHES_HEADER(4)
+
+ HASH4_CALC;
+
+ delta2 = p->pos - p->hash[ hash2Value];
+ delta3 = p->pos - p->hash[kFix3HashSize + hash3Value];
+ curMatch = p->hash[kFix4HashSize + hashValue];
+
+ p->hash[ hash2Value] =
+ p->hash[kFix3HashSize + hash3Value] =
+ p->hash[kFix4HashSize + hashValue] = p->pos;
+
+ maxLen = 1;
+ offset = 0;
+ if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
+ {
+ distances[0] = maxLen = 2;
+ distances[1] = delta2 - 1;
+ offset = 2;
+ }
+ if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur)
+ {
+ maxLen = 3;
+ distances[offset + 1] = delta3 - 1;
+ offset += 2;
+ delta2 = delta3;
+ }
+ if (offset != 0)
+ {
+ for (; maxLen != lenLimit; maxLen++)
+ if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
+ break;
+ distances[offset - 2] = maxLen;
+ if (maxLen == lenLimit)
+ {
+ SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
+ MOVE_POS_RET;
+ }
+ }
+ if (maxLen < 3)
+ maxLen = 3;
+ GET_MATCHES_FOOTER(offset, maxLen)
+}
+
+static UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset;
+ GET_MATCHES_HEADER(4)
+
+ HASH4_CALC;
+
+ delta2 = p->pos - p->hash[ hash2Value];
+ delta3 = p->pos - p->hash[kFix3HashSize + hash3Value];
+ curMatch = p->hash[kFix4HashSize + hashValue];
+
+ p->hash[ hash2Value] =
+ p->hash[kFix3HashSize + hash3Value] =
+ p->hash[kFix4HashSize + hashValue] = p->pos;
+
+ maxLen = 1;
+ offset = 0;
+ if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
+ {
+ distances[0] = maxLen = 2;
+ distances[1] = delta2 - 1;
+ offset = 2;
+ }
+ if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur)
+ {
+ maxLen = 3;
+ distances[offset + 1] = delta3 - 1;
+ offset += 2;
+ delta2 = delta3;
+ }
+ if (offset != 0)
+ {
+ for (; maxLen != lenLimit; maxLen++)
+ if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
+ break;
+ distances[offset - 2] = maxLen;
+ if (maxLen == lenLimit)
+ {
+ p->son[p->cyclicBufferPos] = curMatch;
+ MOVE_POS_RET;
+ }
+ }
+ if (maxLen < 3)
+ maxLen = 3;
+ offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
+ distances + offset, maxLen) - (distances));
+ MOVE_POS_RET
+}
+
+UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ UInt32 offset;
+ GET_MATCHES_HEADER(3)
+ HASH_ZIP_CALC;
+ curMatch = p->hash[hashValue];
+ p->hash[hashValue] = p->pos;
+ offset = (UInt32)(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[hashValue];
+ p->hash[hashValue] = 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[hashValue];
+ p->hash[hashValue] = p->pos;
+ SKIP_FOOTER
+ }
+ while (--num != 0);
+}
+
+static void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ do
+ {
+ UInt32 hash2Value;
+ SKIP_HEADER(3)
+ HASH3_CALC;
+ curMatch = p->hash[kFix3HashSize + hashValue];
+ p->hash[hash2Value] =
+ p->hash[kFix3HashSize + hashValue] = p->pos;
+ SKIP_FOOTER
+ }
+ while (--num != 0);
+}
+
+static void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ do
+ {
+ UInt32 hash2Value, hash3Value;
+ SKIP_HEADER(4)
+ HASH4_CALC;
+ curMatch = p->hash[kFix4HashSize + hashValue];
+ p->hash[ hash2Value] =
+ p->hash[kFix3HashSize + hash3Value] = p->pos;
+ p->hash[kFix4HashSize + hashValue] = p->pos;
+ SKIP_FOOTER
+ }
+ while (--num != 0);
+}
+
+static void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ do
+ {
+ UInt32 hash2Value, hash3Value;
+ SKIP_HEADER(4)
+ HASH4_CALC;
+ curMatch = p->hash[kFix4HashSize + hashValue];
+ p->hash[ hash2Value] =
+ p->hash[kFix3HashSize + hash3Value] =
+ p->hash[kFix4HashSize + hashValue] = 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[hashValue];
+ p->hash[hashValue] = 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->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinder_GetIndexByte;
+ vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes;
+ vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos;
+ if (!p->btMode)
+ {
+ vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches;
+ vTable->Skip = (Mf_Skip_Func)Hc4_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
+ {
+ vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches;
+ vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip;
+ }
+}
diff --git a/lzma/C/LzFind.h b/lzma/C/LzFind.h
new file mode 100644
index 0000000..bad5000
--- /dev/null
+++ b/lzma/C/LzFind.h
@@ -0,0 +1,111 @@
+/* LzFind.h -- Match finder for LZ algorithms
+2013-01-18 : 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) */
+
+ UInt32 matchMaxLen;
+ CLzRef *hash;
+ CLzRef *son;
+ UInt32 hashMask;
+ UInt32 cutValue;
+
+ Byte *bufferBase;
+ ISeqInStream *stream;
+ int streamEndWasReached;
+
+ UInt32 blockSize;
+ UInt32 keepSizeBefore;
+ UInt32 keepSizeAfter;
+
+ UInt32 numHashBytes;
+ int directInput;
+ size_t directInputRem;
+ int btMode;
+ int bigHash;
+ UInt32 historySize;
+ UInt32 fixedHashSize;
+ UInt32 hashSizeSum;
+ UInt32 numSons;
+ SRes result;
+ UInt32 crc[256];
+} CMatchFinder;
+
+#define Inline_MatchFinder_GetPointerToCurrentPos(p) ((p)->buffer)
+#define Inline_MatchFinder_GetIndexByte(p, index) ((p)->buffer[(Int32)(index)])
+
+#define Inline_MatchFinder_GetNumAvailableBytes(p) ((p)->streamPos - (p)->pos)
+
+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,
+ ISzAlloc *alloc);
+void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc);
+void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 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 Byte (*Mf_GetIndexByte_Func)(void *object, Int32 index);
+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_GetIndexByte_Func GetIndexByte;
+ 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(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
diff --git a/lzma/C/LzFindMt.c b/lzma/C/LzFindMt.c
new file mode 100644
index 0000000..5356d4a
--- /dev/null
+++ b/lzma/C/LzFindMt.c
@@ -0,0 +1,794 @@
+/* LzFindMt.c -- multithreaded Match finder for LZ algorithms
+2014-12-29 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "LzHash.h"
+
+#include "LzFindMt.h"
+
+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);
+}
+
+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);
+ }
+ 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 */
+
+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;
+}
+
+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)), hashMask = hashMask; crc = 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) */
+
+void HashThreadFunc(CMatchFinderMt *mt)
+{
+ CMtSync *p = &mt->hashSync;
+ for (;;)
+ {
+ UInt32 numProcessedBlocks = 0;
+ Event_Wait(&p->canStart);
+ Event_Set(&p->wasStarted);
+ 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 = MatchFinder_GetPointerToCurrentPos(mf);
+ const Byte *afterPtr;
+ MatchFinder_MoveBlock(mf);
+ afterPtr = MatchFinder_GetPointerToCurrentPos(mf);
+ mt->pointerToCurPos -= beforePtr - afterPtr;
+ mt->buffer -= beforePtr - afterPtr;
+ }
+ 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, 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] += num;
+ }
+ mf->pos += num;
+ mf->buffer += num;
+ }
+ }
+
+ Semaphore_Release1(&p->filledSemaphore);
+ }
+ }
+}
+
+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
+
+#define NO_INLINE MY_FAST_CALL
+
+Int32 NO_INLINE GetMatchesSpecN(UInt32 lenLimit, UInt32 pos, const Byte *cur, CLzRef *son,
+ UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue,
+ UInt32 *_distances, UInt32 _maxLen, const UInt32 *hash, Int32 limit, UInt32 size, UInt32 *posRes)
+{
+ do
+ {
+ UInt32 *distances = _distances + 1;
+ UInt32 curMatch = pos - *hash++;
+
+ CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1;
+ CLzRef *ptr1 = son + (_cyclicBufferPos << 1);
+ UInt32 len0 = 0, len1 = 0;
+ UInt32 cutValue = _cutValue;
+ UInt32 maxLen = _maxLen;
+ for (;;)
+ {
+ UInt32 delta = pos - curMatch;
+ if (cutValue-- == 0 || delta >= _cyclicBufferSize)
+ {
+ *ptr0 = *ptr1 = kEmptyHashValue;
+ break;
+ }
+ {
+ CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
+ const Byte *pb = cur - delta;
+ UInt32 len = (len0 < len1 ? len0 : len1);
+ if (pb[len] == cur[len])
+ {
+ if (++len != lenLimit && pb[len] == cur[len])
+ while (++len != lenLimit)
+ if (pb[len] != cur[len])
+ break;
+ if (maxLen < len)
+ {
+ *distances++ = maxLen = len;
+ *distances++ = delta - 1;
+ if (len == lenLimit)
+ {
+ *ptr1 = pair[0];
+ *ptr0 = pair[1];
+ break;
+ }
+ }
+ }
+ if (pb[len] < cur[len])
+ {
+ *ptr1 = curMatch;
+ ptr1 = pair + 1;
+ curMatch = *ptr1;
+ len1 = len;
+ }
+ else
+ {
+ *ptr0 = curMatch;
+ ptr0 = pair;
+ curMatch = *ptr0;
+ len0 = len;
+ }
+ }
+ }
+ pos++;
+ _cyclicBufferPos++;
+ cur++;
+ {
+ UInt32 num = (UInt32)(distances - _distances);
+ *_distances = num - 1;
+ _distances += num;
+ limit -= num;
+ }
+ }
+ while (limit > 0 && --size != 0);
+ *posRes = pos;
+ return limit;
+}
+
+#endif
+
+void BtGetMatches(CMatchFinderMt *p, UInt32 *distances)
+{
+ UInt32 numProcessed = 0;
+ UInt32 curPos = 2;
+ UInt32 limit = kMtBtBlockSize - (p->matchMaxLen * 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;
+ for (; p->hashNumAvail != 0; p->hashNumAvail--)
+ distances[curPos++] = 0;
+ break;
+ }
+ {
+ 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 = limit - GetMatchesSpecN(lenLimit, pos, p->buffer, p->son, cyclicBufferPos, p->cyclicBufferSize, p->cutValue,
+ distances + curPos, p->numHashBytes - 1, p->hashBuf + p->hashBufPos, (Int32)(limit - curPos) , size, &posRes);
+ 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;
+}
+
+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, 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 = 0;
+ MtSync_Construct(&p->hashSync);
+ MtSync_Construct(&p->btSync);
+}
+
+void MatchFinderMt_FreeMem(CMatchFinderMt *p, ISzAlloc *alloc)
+{
+ alloc->Free(alloc, p->hashBuf);
+ p->hashBuf = 0;
+}
+
+void MatchFinderMt_Destruct(CMatchFinderMt *p, ISzAlloc *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];
+ allocaDummy[0] = 0;
+ allocaDummy[1] = allocaDummy[0];
+ BtThreadFunc((CMatchFinderMt *)p);
+ return 0;
+}
+
+SRes MatchFinderMt_Create(CMatchFinderMt *p, UInt32 historySize, UInt32 keepAddBufferBefore,
+ UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ISzAlloc *alloc)
+{
+ CMatchFinder *mf = p->MatchFinder;
+ p->historySize = historySize;
+ if (kMtBtBlockSize <= matchMaxLen * 4)
+ return SZ_ERROR_PARAM;
+ if (p->hashBuf == 0)
+ {
+ p->hashBuf = (UInt32 *)alloc->Alloc(alloc, (kHashBufferSize + kBtBufferSize) * sizeof(UInt32));
+ if (p->hashBuf == 0)
+ 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 */
+void MatchFinderMt_Init(CMatchFinderMt *p)
+{
+ CMatchFinder *mf = p->MatchFinder;
+ p->btBufPos = p->btBufPosLimit = 0;
+ p->hashBufPos = p->hashBufPosLimit = 0;
+ MatchFinder_Init(mf);
+ p->pointerToCurPos = 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(); */
+}
+
+void MatchFinderMt_Normalize(CMatchFinderMt *p)
+{
+ MatchFinder_Normalize3(p->lzPos - p->historySize - 1, p->hash, p->fixedHashSize);
+ p->lzPos = p->historySize + 1;
+}
+
+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);
+}
+
+const Byte * MatchFinderMt_GetPointerToCurrentPos(CMatchFinderMt *p)
+{
+ return p->pointerToCurPos;
+}
+
+#define GET_NEXT_BLOCK_IF_REQUIRED if (p->btBufPos == p->btBufPosLimit) MatchFinderMt_GetNextBlock_Bt(p);
+
+UInt32 MatchFinderMt_GetNumAvailableBytes(CMatchFinderMt *p)
+{
+ GET_NEXT_BLOCK_IF_REQUIRED;
+ return p->btNumAvailBytes;
+}
+
+Byte MatchFinderMt_GetIndexByte(CMatchFinderMt *p, Int32 index)
+{
+ return p->pointerToCurPos[index];
+}
+
+UInt32 * MixMatches2(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances)
+{
+ UInt32 hash2Value, curMatch2;
+ UInt32 *hash = p->hash;
+ const Byte *cur = p->pointerToCurPos;
+ UInt32 lzPos = p->lzPos;
+ MT_HASH2_CALC
+
+ curMatch2 = hash[hash2Value];
+ hash[hash2Value] = lzPos;
+
+ if (curMatch2 >= matchMinPos)
+ if (cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0])
+ {
+ *distances++ = 2;
+ *distances++ = lzPos - curMatch2 - 1;
+ }
+ return distances;
+}
+
+UInt32 * MixMatches3(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances)
+{
+ UInt32 hash2Value, hash3Value, curMatch2, curMatch3;
+ UInt32 *hash = p->hash;
+ const Byte *cur = p->pointerToCurPos;
+ UInt32 lzPos = p->lzPos;
+ MT_HASH3_CALC
+
+ curMatch2 = hash[ hash2Value];
+ curMatch3 = hash[kFix3HashSize + hash3Value];
+
+ hash[ hash2Value] =
+ hash[kFix3HashSize + hash3Value] =
+ 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;
+}
+
+/*
+UInt32 *MixMatches4(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances)
+{
+ UInt32 hash2Value, hash3Value, hash4Value, curMatch2, curMatch3, curMatch4;
+ UInt32 *hash = p->hash;
+ const Byte *cur = p->pointerToCurPos;
+ UInt32 lzPos = p->lzPos;
+ MT_HASH4_CALC
+
+ curMatch2 = hash[ hash2Value];
+ curMatch3 = hash[kFix3HashSize + hash3Value];
+ curMatch4 = hash[kFix4HashSize + hash4Value];
+
+ hash[ hash2Value] =
+ hash[kFix3HashSize + hash3Value] =
+ hash[kFix4HashSize + hash4Value] =
+ 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++;
+
+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)
+ {
+ *distances++ = *btBuf++;
+ *distances++ = *btBuf++;
+ }
+ }
+ INCREASE_LZ_POS
+ return len;
+}
+
+UInt32 MatchFinderMt_GetMatches(CMatchFinderMt *p, UInt32 *distances)
+{
+ const UInt32 *btBuf = p->btBuf + p->btBufPos;
+ UInt32 len = *btBuf++;
+ p->btBufPos += 1 + len;
+
+ if (len == 0)
+ {
+ 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
+ {
+ *distances2++ = *btBuf++;
+ *distances2++ = *btBuf++;
+ }
+ 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);
+
+void MatchFinderMt0_Skip(CMatchFinderMt *p, UInt32 num)
+{
+ SKIP_HEADER2_MT { p->btNumAvailBytes--;
+ SKIP_FOOTER_MT
+}
+
+void MatchFinderMt2_Skip(CMatchFinderMt *p, UInt32 num)
+{
+ SKIP_HEADER_MT(2)
+ UInt32 hash2Value;
+ MT_HASH2_CALC
+ hash[hash2Value] = p->lzPos;
+ SKIP_FOOTER_MT
+}
+
+void MatchFinderMt3_Skip(CMatchFinderMt *p, UInt32 num)
+{
+ SKIP_HEADER_MT(3)
+ UInt32 hash2Value, hash3Value;
+ MT_HASH3_CALC
+ hash[kFix3HashSize + hash3Value] =
+ hash[ hash2Value] =
+ p->lzPos;
+ SKIP_FOOTER_MT
+}
+
+/*
+void MatchFinderMt4_Skip(CMatchFinderMt *p, UInt32 num)
+{
+ SKIP_HEADER_MT(4)
+ UInt32 hash2Value, hash3Value, hash4Value;
+ MT_HASH4_CALC
+ hash[kFix4HashSize + hash4Value] =
+ hash[kFix3HashSize + hash3Value] =
+ hash[ hash2Value] =
+ p->lzPos;
+ SKIP_FOOTER_MT
+}
+*/
+
+void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder *vTable)
+{
+ vTable->Init = (Mf_Init_Func)MatchFinderMt_Init;
+ vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinderMt_GetIndexByte;
+ 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)0;
+ 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->GetHeadsFunc = 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;
+ */
+ }
+}
diff --git a/lzma/C/LzFindMt.h b/lzma/C/LzFindMt.h
new file mode 100644
index 0000000..320d87c
--- /dev/null
+++ b/lzma/C/LzFindMt.h
@@ -0,0 +1,101 @@
+/* LzFindMt.h -- multithreaded Match finder for LZ algorithms
+2013-01-18 : 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
+{
+ Bool wasCreated;
+ Bool needStart;
+ Bool exit;
+ Bool stopWriting;
+
+ CThread thread;
+ CAutoResetEvent canStart;
+ CAutoResetEvent wasStarted;
+ CAutoResetEvent wasStopped;
+ CSemaphore freeSemaphore;
+ CSemaphore filledSemaphore;
+ Bool csWasInitialized;
+ Bool 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;
+ 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, ISzAlloc *alloc);
+SRes MatchFinderMt_Create(CMatchFinderMt *p, UInt32 historySize, UInt32 keepAddBufferBefore,
+ UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ISzAlloc *alloc);
+void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder *vTable);
+void MatchFinderMt_ReleaseStream(CMatchFinderMt *p);
+
+EXTERN_C_END
+
+#endif
diff --git a/lzma/C/LzHash.h b/lzma/C/LzHash.h
new file mode 100644
index 0000000..b2f0e3c
--- /dev/null
+++ b/lzma/C/LzHash.h
@@ -0,0 +1,54 @@
+/* LzHash.h -- HASH functions for LZ algorithms
+2009-02-07 : 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 hashValue = cur[0] | ((UInt32)cur[1] << 8);
+
+#define HASH3_CALC { \
+ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
+ hash2Value = temp & (kHash2Size - 1); \
+ hashValue = (temp ^ ((UInt32)cur[2] << 8)) & p->hashMask; }
+
+#define HASH4_CALC { \
+ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
+ hash2Value = temp & (kHash2Size - 1); \
+ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
+ hashValue = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & p->hashMask; }
+
+#define HASH5_CALC { \
+ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
+ hash2Value = temp & (kHash2Size - 1); \
+ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
+ hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)); \
+ hashValue = (hash4Value ^ (p->crc[cur[4]] << 3)) & p->hashMask; \
+ hash4Value &= (kHash4Size - 1); }
+
+/* #define HASH_ZIP_CALC hashValue = ((cur[0] | ((UInt32)cur[1] << 8)) ^ p->crc[cur[2]]) & 0xFFFF; */
+#define HASH_ZIP_CALC hashValue = ((cur[2] | ((UInt32)cur[0] << 8)) ^ p->crc[cur[1]]) & 0xFFFF;
+
+
+#define MT_HASH2_CALC \
+ hash2Value = (p->crc[cur[0]] ^ cur[1]) & (kHash2Size - 1);
+
+#define MT_HASH3_CALC { \
+ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
+ hash2Value = temp & (kHash2Size - 1); \
+ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); }
+
+#define MT_HASH4_CALC { \
+ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
+ hash2Value = temp & (kHash2Size - 1); \
+ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
+ hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & (kHash4Size - 1); }
+
+#endif
diff --git a/lzma/C/Lzma2Dec.c b/lzma/C/Lzma2Dec.c
new file mode 100644
index 0000000..ed91619
--- /dev/null
+++ b/lzma/C/Lzma2Dec.c
@@ -0,0 +1,352 @@
+/* Lzma2Dec.c -- LZMA2 Decoder
+2010-12-15 : 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 - EOS
+00000001 U U - Uncompressed Reset Dic
+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 + new prop
+111uuuuu U U P P S - LZMA reset state + new prop + reset dic
+
+ u, U - Unpack Size
+ P - Pack Size
+ S - Props
+*/
+
+#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_IS_UNCOMPRESSED_STATE(p) (((p)->control & LZMA2_CONTROL_LZMA) == 0)
+
+#define LZMA2_GET_LZMA_MODE(p) (((p)->control >> 5) & 3)
+#define LZMA2_IS_THERE_PROP(mode) ((mode) >= 2)
+
+#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, ISzAlloc *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, ISzAlloc *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->needInitDic = True;
+ p->needInitState = True;
+ p->needInitProp = True;
+ LzmaDec_Init(&p->decoder);
+}
+
+static ELzma2State Lzma2Dec_UpdateState(CLzma2Dec *p, Byte b)
+{
+ switch(p->state)
+ {
+ case LZMA2_STATE_CONTROL:
+ p->control = b;
+ PRF(printf("\n %4X ", p->decoder.dicPos));
+ PRF(printf(" %2X", b));
+ if (p->control == 0)
+ return LZMA2_STATE_FINISHED;
+ if (LZMA2_IS_UNCOMPRESSED_STATE(p))
+ {
+ if ((p->control & 0x7F) > 2)
+ return LZMA2_STATE_ERROR;
+ p->unpackSize = 0;
+ }
+ else
+ p->unpackSize = (UInt32)(p->control & 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(" %8d", 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++;
+ PRF(printf(" %8d", p->packSize));
+ return LZMA2_IS_THERE_PROP(LZMA2_GET_LZMA_MODE(p)) ? LZMA2_STATE_PROP:
+ (p->needInitProp ? LZMA2_STATE_ERROR : LZMA2_STATE_DATA);
+
+ case LZMA2_STATE_PROP:
+ {
+ int lc, lp;
+ if (b >= (9 * 5 * 5))
+ return LZMA2_STATE_ERROR;
+ lc = b % 9;
+ b /= 9;
+ p->decoder.prop.pb = b / 5;
+ lp = b % 5;
+ if (lc + lp > LZMA2_LCLP_MAX)
+ return LZMA2_STATE_ERROR;
+ p->decoder.prop.lc = lc;
+ p->decoder.prop.lp = lp;
+ p->needInitProp = False;
+ 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, Bool initDic, Bool 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_FINISHED)
+ {
+ SizeT dicPos = p->decoder.dicPos;
+ if (p->state == LZMA2_STATE_ERROR)
+ return SZ_ERROR_DATA;
+ 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++);
+ continue;
+ }
+ {
+ SizeT destSizeCur = dicLimit - dicPos;
+ SizeT srcSizeCur = inSize - *srcLen;
+ ELzmaFinishMode curFinishMode = LZMA_FINISH_ANY;
+
+ if (p->unpackSize <= destSizeCur)
+ {
+ destSizeCur = (SizeT)p->unpackSize;
+ curFinishMode = LZMA_FINISH_END;
+ }
+
+ if (LZMA2_IS_UNCOMPRESSED_STATE(p))
+ {
+ if (*srcLen == inSize)
+ {
+ *status = LZMA_STATUS_NEEDS_MORE_INPUT;
+ return SZ_OK;
+ }
+
+ if (p->state == LZMA2_STATE_DATA)
+ {
+ Bool initDic = (p->control == LZMA2_CONTROL_COPY_RESET_DIC);
+ if (initDic)
+ p->needInitProp = p->needInitState = True;
+ else if (p->needInitDic)
+ return SZ_ERROR_DATA;
+ p->needInitDic = False;
+ LzmaDec_InitDicAndState(&p->decoder, initDic, False);
+ }
+
+ if (srcSizeCur > destSizeCur)
+ srcSizeCur = destSizeCur;
+
+ if (srcSizeCur == 0)
+ return SZ_ERROR_DATA;
+
+ LzmaDec_UpdateWithUncompressed(&p->decoder, src, srcSizeCur);
+
+ src += srcSizeCur;
+ *srcLen += srcSizeCur;
+ p->unpackSize -= (UInt32)srcSizeCur;
+ p->state = (p->unpackSize == 0) ? LZMA2_STATE_CONTROL : LZMA2_STATE_DATA_CONT;
+ }
+ else
+ {
+ SizeT outSizeProcessed;
+ SRes res;
+
+ if (p->state == LZMA2_STATE_DATA)
+ {
+ int mode = LZMA2_GET_LZMA_MODE(p);
+ Bool initDic = (mode == 3);
+ Bool initState = (mode > 0);
+ if ((!initDic && p->needInitDic) || (!initState && p->needInitState))
+ return SZ_ERROR_DATA;
+
+ LzmaDec_InitDicAndState(&p->decoder, initDic, initState);
+ p->needInitDic = False;
+ p->needInitState = False;
+ p->state = LZMA2_STATE_DATA_CONT;
+ }
+ if (srcSizeCur > p->packSize)
+ srcSizeCur = (SizeT)p->packSize;
+
+ res = LzmaDec_DecodeToDic(&p->decoder, dicPos + destSizeCur, src, &srcSizeCur, curFinishMode, status);
+
+ src += srcSizeCur;
+ *srcLen += srcSizeCur;
+ p->packSize -= (UInt32)srcSizeCur;
+
+ outSizeProcessed = p->decoder.dicPos - dicPos;
+ p->unpackSize -= (UInt32)outSizeProcessed;
+
+ RINOK(res);
+ if (*status == LZMA_STATUS_NEEDS_MORE_INPUT)
+ return res;
+
+ if (srcSizeCur == 0 && outSizeProcessed == 0)
+ {
+ if (*status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK ||
+ p->unpackSize != 0 || p->packSize != 0)
+ return SZ_ERROR_DATA;
+ p->state = LZMA2_STATE_CONTROL;
+ }
+ if (*status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK)
+ *status = LZMA_STATUS_NOT_FINISHED;
+ }
+ }
+ }
+ *status = LZMA_STATUS_FINISHED_WITH_MARK;
+ return SZ_OK;
+}
+
+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 srcSizeCur = inSize, outSizeCur, dicPos;
+ ELzmaFinishMode curFinishMode;
+ SRes res;
+ if (p->decoder.dicPos == p->decoder.dicBufSize)
+ p->decoder.dicPos = 0;
+ dicPos = p->decoder.dicPos;
+ if (outSize > p->decoder.dicBufSize - dicPos)
+ {
+ outSizeCur = p->decoder.dicBufSize;
+ curFinishMode = LZMA_FINISH_ANY;
+ }
+ else
+ {
+ outSizeCur = dicPos + outSize;
+ curFinishMode = finishMode;
+ }
+
+ res = Lzma2Dec_DecodeToDic(p, outSizeCur, src, &srcSizeCur, curFinishMode, status);
+ src += srcSizeCur;
+ inSize -= srcSizeCur;
+ *srcLen += srcSizeCur;
+ outSizeCur = p->decoder.dicPos - dicPos;
+ memcpy(dest, p->decoder.dic + dicPos, outSizeCur);
+ dest += outSizeCur;
+ outSize -= outSizeCur;
+ *destLen += outSizeCur;
+ if (res != 0)
+ return res;
+ if (outSizeCur == 0 || outSize == 0)
+ return SZ_OK;
+ }
+}
+
+SRes Lzma2Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+ Byte prop, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAlloc *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;
+}
diff --git a/lzma/C/Lzma2Dec.h b/lzma/C/Lzma2Dec.h
new file mode 100644
index 0000000..9254523
--- /dev/null
+++ b/lzma/C/Lzma2Dec.h
@@ -0,0 +1,80 @@
+/* Lzma2Dec.h -- LZMA2 Decoder
+2013-01-18 : Igor Pavlov : Public domain */
+
+#ifndef __LZMA2_DEC_H
+#define __LZMA2_DEC_H
+
+#include "LzmaDec.h"
+
+EXTERN_C_BEGIN
+
+/* ---------- State Interface ---------- */
+
+typedef struct
+{
+ CLzmaDec decoder;
+ UInt32 packSize;
+ UInt32 unpackSize;
+ int state;
+ Byte control;
+ Bool needInitDic;
+ Bool needInitState;
+ Bool needInitProp;
+} 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, ISzAlloc *alloc);
+SRes Lzma2Dec_Allocate(CLzma2Dec *p, Byte prop, ISzAlloc *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);
+
+
+/* ---------- 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, ISzAlloc *alloc);
+
+EXTERN_C_END
+
+#endif
diff --git a/lzma/C/Lzma2Enc.c b/lzma/C/Lzma2Enc.c
new file mode 100644
index 0000000..34a97f3
--- /dev/null
+++ b/lzma/C/Lzma2Enc.c
@@ -0,0 +1,493 @@
+/* Lzma2Enc.c -- LZMA2 Encoder
+2012-06-19 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+/* #include <stdio.h> */
+#include <string.h>
+
+/* #define _7ZIP_ST */
+
+#include "Lzma2Enc.h"
+
+#ifndef _7ZIP_ST
+#include "MtCoder.h"
+#else
+#define NUM_MT_CODER_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 */
+
+/* ---------- CLzma2EncInt ---------- */
+
+typedef struct
+{
+ CLzmaEncHandle enc;
+ UInt64 srcPos;
+ Byte props;
+ Bool needInitState;
+ Bool needInitProp;
+} CLzma2EncInt;
+
+static SRes Lzma2EncInt_Init(CLzma2EncInt *p, const CLzma2EncProps *props)
+{
+ Byte propsEncoded[LZMA_PROPS_SIZE];
+ SizeT propsSize = LZMA_PROPS_SIZE;
+ RINOK(LzmaEnc_SetProps(p->enc, &props->lzmaProps));
+ RINOK(LzmaEnc_WriteProperties(p->enc, propsEncoded, &propsSize));
+ p->srcPos = 0;
+ p->props = propsEncoded[0];
+ p->needInitState = True;
+ p->needInitProp = True;
+ return SZ_OK;
+}
+
+SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp, ISeqInStream *inStream, UInt32 keepWindowSize,
+ ISzAlloc *alloc, ISzAlloc *allocBig);
+SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen,
+ UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig);
+SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, Bool 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);
+
+
+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);
+ Bool 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 (outStream->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->props;
+
+ p->needInitProp = False;
+ p->needInitState = False;
+ destPos += packSize;
+ p->srcPos += unpackSize;
+
+ if (outStream)
+ if (outStream->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->numTotalThreads = -1;
+ p->numBlockThreads = -1;
+ p->blockSize = 0;
+}
+
+void Lzma2EncProps_Normalize(CLzma2EncProps *p)
+{
+ int t1, t1n, t2, t3;
+ {
+ CLzmaEncProps lzmaProps = p->lzmaProps;
+ LzmaEncProps_Normalize(&lzmaProps);
+ t1n = lzmaProps.numThreads;
+ }
+
+ t1 = p->lzmaProps.numThreads;
+ t2 = p->numBlockThreads;
+ t3 = p->numTotalThreads;
+
+ if (t2 > NUM_MT_CODER_THREADS_MAX)
+ t2 = NUM_MT_CODER_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 > NUM_MT_CODER_THREADS_MAX)
+ t2 = NUM_MT_CODER_THREADS_MAX;
+ }
+ else if (t1 <= 0)
+ {
+ t1 = t3 / t2;
+ if (t1 == 0)
+ t1 = 1;
+ }
+ else
+ t3 = t1n * t2;
+
+ p->lzmaProps.numThreads = t1;
+
+ LzmaEncProps_Normalize(&p->lzmaProps);
+
+ if (p->blockSize == 0)
+ {
+ UInt32 dictSize = p->lzmaProps.dictSize;
+ UInt64 blockSize = (UInt64)dictSize << 2;
+ const UInt32 kMinSize = (UInt32)1 << 20;
+ const UInt32 kMaxSize = (UInt32)1 << 28;
+ if (blockSize < kMinSize) blockSize = kMinSize;
+ if (blockSize > kMaxSize) blockSize = kMaxSize;
+ if (blockSize < dictSize) blockSize = dictSize;
+ p->blockSize = (size_t)blockSize;
+ }
+ if (t2 > 1)
+ {
+ UInt64 temp = p->lzmaProps.reduceSize + p->blockSize - 1;
+ if (temp > p->lzmaProps.reduceSize)
+ {
+ UInt64 numBlocks = temp / p->blockSize;
+ if (numBlocks < t2)
+ {
+ t2 = (UInt32)numBlocks;
+ t3 = t1 * t2;
+ }
+ }
+ }
+ p->numBlockThreads = t2;
+ p->numTotalThreads = t3;
+}
+
+static SRes Progress(ICompressProgress *p, UInt64 inSize, UInt64 outSize)
+{
+ return (p && p->Progress(p, inSize, outSize) != SZ_OK) ? SZ_ERROR_PROGRESS : SZ_OK;
+}
+
+/* ---------- Lzma2 ---------- */
+
+typedef struct
+{
+ Byte propEncoded;
+ CLzma2EncProps props;
+
+ Byte *outBuf;
+
+ ISzAlloc *alloc;
+ ISzAlloc *allocBig;
+
+ CLzma2EncInt coders[NUM_MT_CODER_THREADS_MAX];
+
+ #ifndef _7ZIP_ST
+ CMtCoder mtCoder;
+ #endif
+
+} CLzma2Enc;
+
+
+/* ---------- Lzma2EncThread ---------- */
+
+static SRes Lzma2Enc_EncodeMt1(CLzma2EncInt *p, CLzma2Enc *mainEncoder,
+ ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress)
+{
+ UInt64 packTotal = 0;
+ SRes res = SZ_OK;
+
+ if (mainEncoder->outBuf == 0)
+ {
+ mainEncoder->outBuf = (Byte *)IAlloc_Alloc(mainEncoder->alloc, LZMA2_CHUNK_SIZE_COMPRESSED_MAX);
+ if (mainEncoder->outBuf == 0)
+ return SZ_ERROR_MEM;
+ }
+ RINOK(Lzma2EncInt_Init(p, &mainEncoder->props));
+ RINOK(LzmaEnc_PrepareForLzma2(p->enc, inStream, LZMA2_KEEP_WINDOW_SIZE,
+ mainEncoder->alloc, mainEncoder->allocBig));
+ for (;;)
+ {
+ size_t packSize = LZMA2_CHUNK_SIZE_COMPRESSED_MAX;
+ res = Lzma2EncInt_EncodeSubblock(p, mainEncoder->outBuf, &packSize, outStream);
+ if (res != SZ_OK)
+ break;
+ packTotal += packSize;
+ res = Progress(progress, p->srcPos, packTotal);
+ if (res != SZ_OK)
+ break;
+ if (packSize == 0)
+ break;
+ }
+ LzmaEnc_Finish(p->enc);
+ if (res == SZ_OK)
+ {
+ Byte b = 0;
+ if (outStream->Write(outStream, &b, 1) != 1)
+ return SZ_ERROR_WRITE;
+ }
+ return res;
+}
+
+#ifndef _7ZIP_ST
+
+typedef struct
+{
+ IMtCoderCallback funcTable;
+ CLzma2Enc *lzma2Enc;
+} CMtCallbackImp;
+
+static SRes MtCallbackImp_Code(void *pp, unsigned index, Byte *dest, size_t *destSize,
+ const Byte *src, size_t srcSize, int finished)
+{
+ CMtCallbackImp *imp = (CMtCallbackImp *)pp;
+ CLzma2Enc *mainEncoder = imp->lzma2Enc;
+ CLzma2EncInt *p = &mainEncoder->coders[index];
+
+ SRes res = SZ_OK;
+ {
+ size_t destLim = *destSize;
+ *destSize = 0;
+
+ if (srcSize != 0)
+ {
+ RINOK(Lzma2EncInt_Init(p, &mainEncoder->props));
+
+ RINOK(LzmaEnc_MemPrepare(p->enc, src, srcSize, LZMA2_KEEP_WINDOW_SIZE,
+ mainEncoder->alloc, mainEncoder->allocBig));
+
+ while (p->srcPos < srcSize)
+ {
+ size_t packSize = destLim - *destSize;
+ res = Lzma2EncInt_EncodeSubblock(p, dest + *destSize, &packSize, NULL);
+ if (res != SZ_OK)
+ break;
+ *destSize += packSize;
+
+ if (packSize == 0)
+ {
+ res = SZ_ERROR_FAIL;
+ break;
+ }
+
+ if (MtProgress_Set(&mainEncoder->mtCoder.mtProgress, index, p->srcPos, *destSize) != SZ_OK)
+ {
+ res = SZ_ERROR_PROGRESS;
+ break;
+ }
+ }
+ LzmaEnc_Finish(p->enc);
+ if (res != SZ_OK)
+ return res;
+ }
+ if (finished)
+ {
+ if (*destSize == destLim)
+ return SZ_ERROR_OUTPUT_EOF;
+ dest[(*destSize)++] = 0;
+ }
+ }
+ return res;
+}
+
+#endif
+
+/* ---------- Lzma2Enc ---------- */
+
+CLzma2EncHandle Lzma2Enc_Create(ISzAlloc *alloc, ISzAlloc *allocBig)
+{
+ CLzma2Enc *p = (CLzma2Enc *)alloc->Alloc(alloc, sizeof(CLzma2Enc));
+ if (p == 0)
+ return NULL;
+ Lzma2EncProps_Init(&p->props);
+ Lzma2EncProps_Normalize(&p->props);
+ p->outBuf = 0;
+ p->alloc = alloc;
+ p->allocBig = allocBig;
+ {
+ unsigned i;
+ for (i = 0; i < NUM_MT_CODER_THREADS_MAX; i++)
+ p->coders[i].enc = 0;
+ }
+ #ifndef _7ZIP_ST
+ MtCoder_Construct(&p->mtCoder);
+ #endif
+
+ return p;
+}
+
+void Lzma2Enc_Destroy(CLzma2EncHandle pp)
+{
+ CLzma2Enc *p = (CLzma2Enc *)pp;
+ unsigned i;
+ for (i = 0; i < NUM_MT_CODER_THREADS_MAX; i++)
+ {
+ CLzma2EncInt *t = &p->coders[i];
+ if (t->enc)
+ {
+ LzmaEnc_Destroy(t->enc, p->alloc, p->allocBig);
+ t->enc = 0;
+ }
+ }
+
+ #ifndef _7ZIP_ST
+ MtCoder_Destruct(&p->mtCoder);
+ #endif
+
+ IAlloc_Free(p->alloc, p->outBuf);
+ IAlloc_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;
+}
+
+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;
+}
+
+SRes Lzma2Enc_Encode(CLzma2EncHandle pp,
+ ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress)
+{
+ CLzma2Enc *p = (CLzma2Enc *)pp;
+ int i;
+
+ for (i = 0; i < p->props.numBlockThreads; i++)
+ {
+ CLzma2EncInt *t = &p->coders[i];
+ if (t->enc == NULL)
+ {
+ t->enc = LzmaEnc_Create(p->alloc);
+ if (t->enc == NULL)
+ return SZ_ERROR_MEM;
+ }
+ }
+
+ #ifndef _7ZIP_ST
+ if (p->props.numBlockThreads <= 1)
+ #endif
+ return Lzma2Enc_EncodeMt1(&p->coders[0], p, outStream, inStream, progress);
+
+ #ifndef _7ZIP_ST
+
+ {
+ CMtCallbackImp mtCallback;
+
+ mtCallback.funcTable.Code = MtCallbackImp_Code;
+ mtCallback.lzma2Enc = p;
+
+ p->mtCoder.progress = progress;
+ p->mtCoder.inStream = inStream;
+ p->mtCoder.outStream = outStream;
+ p->mtCoder.alloc = p->alloc;
+ p->mtCoder.mtCallback = &mtCallback.funcTable;
+
+ p->mtCoder.blockSize = p->props.blockSize;
+ p->mtCoder.destBlockSize = p->props.blockSize + (p->props.blockSize >> 10) + 16;
+ p->mtCoder.numThreads = p->props.numBlockThreads;
+
+ return MtCoder_Code(&p->mtCoder);
+ }
+ #endif
+}
diff --git a/lzma/C/Lzma2Enc.h b/lzma/C/Lzma2Enc.h
new file mode 100644
index 0000000..061178a
--- /dev/null
+++ b/lzma/C/Lzma2Enc.h
@@ -0,0 +1,62 @@
+/* Lzma2Enc.h -- LZMA2 Encoder
+2013-01-18 : Igor Pavlov : Public domain */
+
+#ifndef __LZMA2_ENC_H
+#define __LZMA2_ENC_H
+
+#include "LzmaEnc.h"
+
+EXTERN_C_BEGIN
+
+typedef struct
+{
+ CLzmaEncProps lzmaProps;
+ size_t blockSize;
+ int numBlockThreads;
+ int numTotalThreads;
+} CLzma2EncProps;
+
+void Lzma2EncProps_Init(CLzma2EncProps *p);
+void Lzma2EncProps_Normalize(CLzma2EncProps *p);
+
+/* ---------- CLzmaEnc2Handle Interface ---------- */
+
+/* Lzma2Enc_* functions can return the following exit codes:
+Returns:
+ SZ_OK - OK
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_PARAM - Incorrect paramater in props
+ SZ_ERROR_WRITE - Write callback error
+ SZ_ERROR_PROGRESS - some break from progress callback
+ SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version)
+*/
+
+typedef void * CLzma2EncHandle;
+
+CLzma2EncHandle Lzma2Enc_Create(ISzAlloc *alloc, ISzAlloc *allocBig);
+void Lzma2Enc_Destroy(CLzma2EncHandle p);
+SRes Lzma2Enc_SetProps(CLzma2EncHandle p, const CLzma2EncProps *props);
+Byte Lzma2Enc_WriteProperties(CLzma2EncHandle p);
+SRes Lzma2Enc_Encode(CLzma2EncHandle p,
+ ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress);
+
+/* ---------- One Call Interface ---------- */
+
+/* Lzma2Encode
+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)
+*/
+
+/*
+SRes Lzma2Encode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
+ const CLzmaEncProps *props, Byte *propsEncoded, int writeEndMark,
+ ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
+*/
+
+EXTERN_C_END
+
+#endif
diff --git a/lzma/C/Lzma86.h b/lzma/C/Lzma86.h
new file mode 100644
index 0000000..83057e5
--- /dev/null
+++ b/lzma/C/Lzma86.h
@@ -0,0 +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
diff --git a/lzma/C/Lzma86Dec.c b/lzma/C/Lzma86Dec.c
new file mode 100644
index 0000000..760a447
--- /dev/null
+++ b/lzma/C/Lzma86Dec.c
@@ -0,0 +1,56 @@
+/* Lzma86Dec.c -- LZMA + x86 (BCJ) Filter Decoder
+2009-08-14 : Igor Pavlov : Public domain */
+
+#include "Lzma86.h"
+
+#include "Alloc.h"
+#include "Bra.h"
+#include "LzmaDec.h"
+
+static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); }
+static void SzFree(void *p, void *address) { p = p; MyFree(address); }
+
+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)
+{
+ ISzAlloc g_Alloc = { SzAlloc, SzFree };
+ 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;
+}
diff --git a/lzma/C/Lzma86Enc.c b/lzma/C/Lzma86Enc.c
new file mode 100644
index 0000000..41b488c
--- /dev/null
+++ b/lzma/C/Lzma86Enc.c
@@ -0,0 +1,108 @@
+/* Lzma86Enc.c -- LZMA + x86 (BCJ) Filter Encoder
+2009-08-14 : Igor Pavlov : Public domain */
+
+#include <string.h>
+
+#include "Lzma86.h"
+
+#include "Alloc.h"
+#include "Bra.h"
+#include "LzmaEnc.h"
+
+#define SZE_OUT_OVERFLOW SZE_DATA_ERROR
+
+static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); }
+static void SzFree(void *p, void *address) { p = p; MyFree(address); }
+
+int Lzma86_Encode(Byte *dest, size_t *destLen, const Byte *src, size_t srcLen,
+ int level, UInt32 dictSize, int filterMode)
+{
+ ISzAlloc g_Alloc = { SzAlloc, SzFree };
+ size_t outSize2 = *destLen;
+ Byte *filteredStream;
+ Bool 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;
+ Bool 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;
+ Bool 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/lzma/C/LzmaDec.c b/lzma/C/LzmaDec.c
new file mode 100644
index 0000000..38cd9d6
--- /dev/null
+++ b/lzma/C/LzmaDec.c
@@ -0,0 +1,1025 @@
+/* LzmaDec.c -- LZMA Decoder
+2015-01-01 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "LzmaDec.h"
+
+#include <string.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) * 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 GET_BIT(p, i) GET_BIT2(p, i, ; , ;)
+
+#define TREE_GET_BIT(probs, i) { GET_BIT((probs + i), i); }
+#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 GET_BIT(prob + symbol, symbol)
+#define MATCHED_LITER_DEC \
+ matchByte <<= 1; \
+ bit = (matchByte & offs); \
+ probLit = prob + offs + bit + symbol; \
+ GET_BIT2(probLit, symbol, offs &= ~bit, 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) * 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 kNumPosBitsMax 4
+#define kNumPosStatesMax (1 << kNumPosBitsMax)
+
+#define kLenNumLowBits 3
+#define kLenNumLowSymbols (1 << kLenNumLowBits)
+#define kLenNumMidBits 3
+#define kLenNumMidSymbols (1 << kLenNumMidBits)
+#define kLenNumHighBits 8
+#define kLenNumHighSymbols (1 << kLenNumHighBits)
+
+#define LenChoice 0
+#define LenChoice2 (LenChoice + 1)
+#define LenLow (LenChoice2 + 1)
+#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits))
+#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits))
+#define kNumLenProbs (LenHigh + kLenNumHighSymbols)
+
+
+#define kNumStates 12
+#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 + kLenNumMidSymbols + kLenNumHighSymbols)
+
+#define IsMatch 0
+#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax))
+#define IsRepG0 (IsRep + kNumStates)
+#define IsRepG1 (IsRepG0 + kNumStates)
+#define IsRepG2 (IsRepG1 + kNumStates)
+#define IsRep0Long (IsRepG2 + kNumStates)
+#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax))
+#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
+#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex)
+#define LenCoder (Align + kAlignTableSize)
+#define RepLenCoder (LenCoder + kNumLenProbs)
+#define Literal (RepLenCoder + kNumLenProbs)
+
+#define LZMA_BASE_SIZE 1846
+#define LZMA_LIT_SIZE 768
+
+#define LzmaProps_GetNumProbs(p) ((UInt32)LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((p)->lc + (p)->lp)))
+
+#if Literal != LZMA_BASE_SIZE
+StopCompilingDueBUG
+#endif
+
+#define LZMA_DIC_MIN (1 << 12)
+
+/* First LZMA-symbol is always decoded.
+And it decodes new LZMA-symbols while (buf < bufLimit), but "buf" is without last normalization
+Out:
+ Result:
+ SZ_OK - OK
+ SZ_ERROR_DATA - Error
+ p->remainLen:
+ < kMatchSpecLenStart : normal remain
+ = kMatchSpecLenStart : finished
+ = kMatchSpecLenStart + 1 : Flush marker
+ = kMatchSpecLenStart + 2 : State Init Marker
+*/
+
+static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte *bufLimit)
+{
+ CLzmaProb *probs = p->probs;
+
+ unsigned state = 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 lpMask = ((unsigned)1 << (p->prop.lp)) - 1;
+ unsigned lc = p->prop.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 = processedPos & pbMask;
+
+ prob = probs + IsMatch + (state << kNumPosBitsMax) + posState;
+ IF_BIT_0(prob)
+ {
+ unsigned symbol;
+ UPDATE_0(prob);
+ prob = probs + Literal;
+ if (checkDicSize != 0 || processedPos != 0)
+ prob += (LZMA_LIT_SIZE * (((processedPos & lpMask) << lc) +
+ (dic[(dicPos == 0 ? dicBufSize : dicPos) - 1] >> (8 - lc))));
+
+ 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;
+ processedPos++;
+ continue;
+ }
+ else
+ {
+ UPDATE_1(prob);
+ prob = probs + IsRep + state;
+ IF_BIT_0(prob)
+ {
+ UPDATE_0(prob);
+ state += kNumStates;
+ prob = probs + LenCoder;
+ }
+ else
+ {
+ UPDATE_1(prob);
+ if (checkDicSize == 0 && processedPos == 0)
+ return SZ_ERROR_DATA;
+ prob = probs + IsRepG0 + state;
+ IF_BIT_0(prob)
+ {
+ UPDATE_0(prob);
+ prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState;
+ 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;
+ }
+ {
+ unsigned limit, offset;
+ CLzmaProb *probLen = prob + LenChoice;
+ IF_BIT_0(probLen)
+ {
+ UPDATE_0(probLen);
+ probLen = prob + LenLow + (posState << kLenNumLowBits);
+ offset = 0;
+ limit = (1 << kLenNumLowBits);
+ }
+ else
+ {
+ UPDATE_1(probLen);
+ probLen = prob + LenChoice2;
+ IF_BIT_0(probLen)
+ {
+ UPDATE_0(probLen);
+ probLen = prob + LenMid + (posState << kLenNumMidBits);
+ offset = kLenNumLowSymbols;
+ limit = (1 << kLenNumMidBits);
+ }
+ else
+ {
+ UPDATE_1(probLen);
+ probLen = prob + LenHigh;
+ offset = kLenNumLowSymbols + kLenNumMidSymbols;
+ limit = (1 << kLenNumHighBits);
+ }
+ }
+ TREE_DECODE(probLen, limit, len);
+ len += offset;
+ }
+
+ 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;
+ int numDirectBits = (int)(((distance >> 1) - 1));
+ distance = (2 | (distance & 1));
+ if (posSlot < kEndPosModelIndex)
+ {
+ distance <<= numDirectBits;
+ prob = probs + SpecPos + distance - posSlot - 1;
+ {
+ UInt32 mask = 1;
+ unsigned i = 1;
+ do
+ {
+ GET_BIT2(prob + i, i, ; , distance |= mask);
+ mask <<= 1;
+ }
+ while (--numDirectBits != 0);
+ }
+ }
+ 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 != 0);
+ prob = probs + Align;
+ distance <<= kNumAlignBits;
+ {
+ unsigned i = 1;
+ GET_BIT2(prob + i, i, ; , distance |= 1);
+ GET_BIT2(prob + i, i, ; , distance |= 2);
+ GET_BIT2(prob + i, i, ; , distance |= 4);
+ GET_BIT2(prob + i, i, ; , distance |= 8);
+ }
+ if (distance == (UInt32)0xFFFFFFFF)
+ {
+ len += kMatchSpecLenStart;
+ state -= kNumStates;
+ break;
+ }
+ }
+ }
+ rep3 = rep2;
+ rep2 = rep1;
+ rep1 = rep0;
+ rep0 = distance + 1;
+ if (checkDicSize == 0)
+ {
+ if (distance >= processedPos)
+ return SZ_ERROR_DATA;
+ }
+ else if (distance >= checkDicSize)
+ return SZ_ERROR_DATA;
+ state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3;
+ }
+
+ len += kMatchMinLen;
+
+ if (limit == dicPos)
+ return SZ_ERROR_DATA;
+ {
+ SizeT rem = limit - dicPos;
+ unsigned curLen = ((rem < len) ? (unsigned)rem : len);
+ SizeT pos = (dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0);
+
+ processedPos += curLen;
+
+ len -= curLen;
+ if (pos + curLen <= dicBufSize)
+ {
+ Byte *dest = dic + dicPos;
+ ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos;
+ const Byte *lim = dest + curLen;
+ dicPos += 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 = 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 = state;
+
+ return SZ_OK;
+}
+
+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 = p->remainLen;
+ UInt32 rep0 = p->reps[0];
+ if (limit - dicPos < len)
+ len = (unsigned)(limit - dicPos);
+
+ if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len)
+ p->checkDicSize = p->prop.dicSize;
+
+ p->processedPos += len;
+ p->remainLen -= len;
+ while (len != 0)
+ {
+ len--;
+ dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)];
+ dicPos++;
+ }
+ p->dicPos = dicPos;
+ }
+}
+
+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;
+ }
+ RINOK(LzmaDec_DecodeReal(p, limit2, bufLimit));
+ if (p->processedPos >= p->prop.dicSize)
+ p->checkDicSize = p->prop.dicSize;
+ LzmaDec_WriteRem(p, limit);
+ }
+ while (p->dicPos < limit && p->buf < bufLimit && p->remainLen < kMatchSpecLenStart);
+
+ if (p->remainLen > kMatchSpecLenStart)
+ {
+ 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;
+ CLzmaProb *probs = p->probs;
+ unsigned state = p->state;
+ ELzmaDummy res;
+
+ {
+ CLzmaProb *prob;
+ UInt32 bound;
+ unsigned ttt;
+ unsigned posState = (p->processedPos) & ((1 << p->prop.pb) - 1);
+
+ prob = probs + IsMatch + (state << kNumPosBitsMax) + posState;
+ 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 += (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;
+ CLzmaProb *probLit;
+ matchByte <<= 1;
+ bit = (matchByte & offs);
+ probLit = prob + offs + bit + symbol;
+ GET_BIT2_CHECK(probLit, symbol, offs &= ~bit, 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 + (state << kNumPosBitsMax) + posState;
+ 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;
+ CLzmaProb *probLen = prob + LenChoice;
+ IF_BIT_0_CHECK(probLen)
+ {
+ UPDATE_0_CHECK;
+ probLen = prob + LenLow + (posState << kLenNumLowBits);
+ offset = 0;
+ limit = 1 << kLenNumLowBits;
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ probLen = prob + LenChoice2;
+ IF_BIT_0_CHECK(probLen)
+ {
+ UPDATE_0_CHECK;
+ probLen = prob + LenMid + (posState << kLenNumMidBits);
+ offset = kLenNumLowSymbols;
+ limit = 1 << kLenNumMidBits;
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ probLen = prob + LenHigh;
+ offset = kLenNumLowSymbols + kLenNumMidSymbols;
+ limit = 1 << kLenNumHighBits;
+ }
+ }
+ TREE_DECODE_CHECK(probLen, limit, len);
+ len += offset;
+ }
+
+ if (state < 4)
+ {
+ unsigned posSlot;
+ prob = probs + PosSlot +
+ ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) <<
+ kNumPosSlotBits);
+ TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot);
+ if (posSlot >= kStartPosModelIndex)
+ {
+ int numDirectBits = ((posSlot >> 1) - 1);
+
+ /* if (bufLimit - buf >= 8) return DUMMY_MATCH; */
+
+ if (posSlot < kEndPosModelIndex)
+ {
+ prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits) - posSlot - 1;
+ }
+ else
+ {
+ numDirectBits -= kNumAlignBits;
+ do
+ {
+ NORMALIZE_CHECK
+ range >>= 1;
+ code -= range & (((code - range) >> 31) - 1);
+ /* if (code >= range) code -= range; */
+ }
+ while (--numDirectBits != 0);
+ prob = probs + Align;
+ numDirectBits = kNumAlignBits;
+ }
+ {
+ unsigned i = 1;
+ do
+ {
+ GET_BIT_CHECK(prob + i, i);
+ }
+ while (--numDirectBits != 0);
+ }
+ }
+ }
+ }
+ }
+ NORMALIZE_CHECK;
+ return res;
+}
+
+
+static void LzmaDec_InitRc(CLzmaDec *p, const Byte *data)
+{
+ p->code = ((UInt32)data[1] << 24) | ((UInt32)data[2] << 16) | ((UInt32)data[3] << 8) | ((UInt32)data[4]);
+ p->range = 0xFFFFFFFF;
+ p->needFlush = 0;
+}
+
+void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState)
+{
+ p->needFlush = 1;
+ p->remainLen = 0;
+ p->tempBufSize = 0;
+
+ if (initDic)
+ {
+ p->processedPos = 0;
+ p->checkDicSize = 0;
+ p->needInitState = 1;
+ }
+ if (initState)
+ p->needInitState = 1;
+}
+
+void LzmaDec_Init(CLzmaDec *p)
+{
+ p->dicPos = 0;
+ LzmaDec_InitDicAndState(p, True, True);
+}
+
+static void LzmaDec_InitStateReal(CLzmaDec *p)
+{
+ UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (p->prop.lc + p->prop.lp));
+ UInt32 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->needInitState = 0;
+}
+
+SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen,
+ ELzmaFinishMode finishMode, ELzmaStatus *status)
+{
+ SizeT inSize = *srcLen;
+ (*srcLen) = 0;
+ LzmaDec_WriteRem(p, dicLimit);
+
+ *status = LZMA_STATUS_NOT_SPECIFIED;
+
+ while (p->remainLen != kMatchSpecLenStart)
+ {
+ int checkEndMarkNow;
+
+ if (p->needFlush != 0)
+ {
+ for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--)
+ p->tempBuf[p->tempBufSize++] = *src++;
+ if (p->tempBufSize < RC_INIT_SIZE)
+ {
+ *status = LZMA_STATUS_NEEDS_MORE_INPUT;
+ return SZ_OK;
+ }
+ if (p->tempBuf[0] != 0)
+ return SZ_ERROR_DATA;
+
+ LzmaDec_InitRc(p, p->tempBuf);
+ p->tempBufSize = 0;
+ }
+
+ 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->needInitState)
+ LzmaDec_InitStateReal(p);
+
+ 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, rem);
+ if (dummyRes == DUMMY_ERROR)
+ {
+ (*srcLen) += 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;
+ lookAhead -= (rem - (unsigned)(p->buf - p->tempBuf));
+ (*srcLen) += lookAhead;
+ src += lookAhead;
+ inSize -= lookAhead;
+ p->tempBufSize = 0;
+ }
+ }
+ if (p->code == 0)
+ *status = LZMA_STATUS_FINISHED_WITH_MARK;
+ return (p->code == 0) ? SZ_OK : SZ_ERROR_DATA;
+}
+
+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, ISzAlloc *alloc)
+{
+ alloc->Free(alloc, p->probs);
+ p->probs = 0;
+}
+
+static void LzmaDec_FreeDict(CLzmaDec *p, ISzAlloc *alloc)
+{
+ alloc->Free(alloc, p->dic);
+ p->dic = 0;
+}
+
+void LzmaDec_Free(CLzmaDec *p, ISzAlloc *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 = d % 9;
+ d /= 9;
+ p->pb = d / 5;
+ p->lp = d % 5;
+
+ return SZ_OK;
+}
+
+static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAlloc *alloc)
+{
+ UInt32 numProbs = LzmaProps_GetNumProbs(propNew);
+ if (p->probs == 0 || numProbs != p->numProbs)
+ {
+ LzmaDec_FreeProbs(p, alloc);
+ p->probs = (CLzmaProb *)alloc->Alloc(alloc, numProbs * sizeof(CLzmaProb));
+ p->numProbs = numProbs;
+ if (p->probs == 0)
+ return SZ_ERROR_MEM;
+ }
+ return SZ_OK;
+}
+
+SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *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, ISzAlloc *alloc)
+{
+ CLzmaProps propNew;
+ SizeT dicBufSize;
+ RINOK(LzmaProps_Decode(&propNew, props, propsSize));
+ RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc));
+ dicBufSize = propNew.dicSize;
+ if (p->dic == 0 || dicBufSize != p->dicBufSize)
+ {
+ LzmaDec_FreeDict(p, alloc);
+ p->dic = (Byte *)alloc->Alloc(alloc, dicBufSize);
+ if (p->dic == 0)
+ {
+ 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, ISzAlloc *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/lzma/C/LzmaDec.h b/lzma/C/LzmaDec.h
new file mode 100644
index 0000000..2633abe
--- /dev/null
+++ b/lzma/C/LzmaDec.h
@@ -0,0 +1,227 @@
+/* LzmaDec.h -- LZMA Decoder
+2013-01-18 : 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 */
+
+#ifdef _LZMA_PROB32
+#define CLzmaProb UInt32
+#else
+#define CLzmaProb UInt16
+#endif
+
+
+/* ---------- LZMA Properties ---------- */
+
+#define LZMA_PROPS_SIZE 5
+
+typedef struct _CLzmaProps
+{
+ unsigned lc, lp, pb;
+ 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
+{
+ CLzmaProps prop;
+ CLzmaProb *probs;
+ Byte *dic;
+ const Byte *buf;
+ UInt32 range, code;
+ SizeT dicPos;
+ SizeT dicBufSize;
+ UInt32 processedPos;
+ UInt32 checkDicSize;
+ unsigned state;
+ UInt32 reps[4];
+ unsigned remainLen;
+ int needFlush;
+ int needInitState;
+ UInt32 numProbs;
+ unsigned tempBufSize;
+ Byte tempBuf[LZMA_REQUIRED_INPUT_MAX];
+} CLzmaDec;
+
+#define LzmaDec_Construct(p) { (p)->dic = 0; (p)->probs = 0; }
+
+void LzmaDec_Init(CLzmaDec *p);
+
+/* There are two types of LZMA streams:
+ 0) Stream with end mark. That end mark adds about 6 bytes to compressed size.
+ 1) 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, ISzAlloc *alloc);
+void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc);
+
+SRes LzmaDec_Allocate(CLzmaDec *state, const Byte *prop, unsigned propsSize, ISzAlloc *alloc);
+void LzmaDec_Free(CLzmaDec *state, ISzAlloc *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_Constr()
+ 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, ISzAlloc *alloc);
+
+EXTERN_C_END
+
+#endif
diff --git a/lzma/C/LzmaEnc.c b/lzma/C/LzmaEnc.c
new file mode 100644
index 0000000..40ee6a4
--- /dev/null
+++ b/lzma/C/LzmaEnc.c
@@ -0,0 +1,2278 @@
+/* LzmaEnc.c -- LZMA Encoder
+2014-12-29 : 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 kBlockSizeMax ((1 << LZMA_NUM_BLOCK_SIZE_BITS) - 1)
+
+#define kBlockSize (9 << 10)
+#define kUnpackBlockSize (1 << 18)
+#define kMatchArraySize (1 << 21)
+#define kMatchRecordMaxSize ((LZMA_MATCH_LEN_MAX * 2 + 3) * LZMA_MATCH_LEN_MAX)
+
+#define kNumMaxDirectBits (31)
+
+#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)
+
+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 == 6 ? (1 << 25) : (1 << 26)));
+ if (p->dictSize > p->reduceSize)
+ {
+ unsigned i;
+ for (i = 11; i <= 30; i++)
+ {
+ if ((UInt32)p->reduceSize <= ((UInt32)2 << i)) { p->dictSize = ((UInt32)2 << i); break; }
+ if ((UInt32)p->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;
+}
+
+/* #define LZMA_LOG_BSR */
+/* Define it for Intel's CPU */
+
+
+#ifdef LZMA_LOG_BSR
+
+#define kDicLogSizeMaxCompress 30
+
+#define BSR2_RET(pos, res) { unsigned long i; _BitScanReverse(&i, (pos)); res = (i + i) + ((pos >> (i - 1)) & 1); }
+
+UInt32 GetPosSlot1(UInt32 pos)
+{
+ UInt32 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 + (int)sizeof(size_t) / 2)
+#define kDicLogSizeMaxCompress ((kNumLogBits - 1) * 2 + 7)
+
+void LzmaEnc_FastPosInit(Byte *g_FastPos)
+{
+ int c = 2, slotFast;
+ g_FastPos[0] = 0;
+ g_FastPos[1] = 1;
+
+ for (slotFast = 2; slotFast < kNumLogBits * 2; slotFast++)
+ {
+ UInt32 k = (1 << ((slotFast >> 1) - 1));
+ UInt32 j;
+ for (j = 0; j < k; j++, c++)
+ g_FastPos[c] = (Byte)slotFast;
+ }
+}
+
+#define BSR2_RET(pos, res) { UInt32 i = 6 + ((kNumLogBits - 1) & \
+ (0 - (((((UInt32)1 << (kNumLogBits + 6)) - 1) - pos) >> 31))); \
+ res = p->g_FastPos[pos >> i] + (i * 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]; else BSR2_RET(pos, res); }
+
+#endif
+
+
+#define LZMA_NUM_REPS 4
+
+typedef unsigned CState;
+
+typedef struct
+{
+ UInt32 price;
+
+ CState state;
+ int prev1IsChar;
+ int prev2;
+
+ UInt32 posPrev2;
+ UInt32 backPrev2;
+
+ UInt32 posPrev;
+ UInt32 backPrev;
+ UInt32 backs[LZMA_NUM_REPS];
+} COptimal;
+
+#define kNumOpts (1 << 12)
+
+#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 kNumPosModels (kEndPosModelIndex - kStartPosModelIndex)
+
+#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
+
+#ifdef _LZMA_PROB32
+#define CLzmaProb UInt32
+#else
+#define CLzmaProb UInt16
+#endif
+
+#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 kLenNumMidBits 3
+#define kLenNumMidSymbols (1 << kLenNumMidBits)
+#define kLenNumHighBits 8
+#define kLenNumHighSymbols (1 << kLenNumHighBits)
+
+#define kLenNumSymbolsTotal (kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols)
+
+#define LZMA_MATCH_LEN_MIN 2
+#define LZMA_MATCH_LEN_MAX (LZMA_MATCH_LEN_MIN + kLenNumSymbolsTotal - 1)
+
+#define kNumStates 12
+
+typedef struct
+{
+ CLzmaProb choice;
+ CLzmaProb choice2;
+ CLzmaProb low[LZMA_NUM_PB_STATES_MAX << kLenNumLowBits];
+ CLzmaProb mid[LZMA_NUM_PB_STATES_MAX << kLenNumMidBits];
+ CLzmaProb high[kLenNumHighSymbols];
+} CLenEnc;
+
+typedef struct
+{
+ CLenEnc p;
+ UInt32 prices[LZMA_NUM_PB_STATES_MAX][kLenNumSymbolsTotal];
+ UInt32 tableSize;
+ UInt32 counters[LZMA_NUM_PB_STATES_MAX];
+} CLenPriceEnc;
+
+typedef struct
+{
+ UInt32 range;
+ Byte cache;
+ UInt64 low;
+ UInt64 cacheSize;
+ Byte *buf;
+ Byte *bufLim;
+ Byte *bufBase;
+ ISeqOutStream *outStream;
+ UInt64 processed;
+ SRes res;
+} CRangeEnc;
+
+typedef struct
+{
+ CLzmaProb *litProbs;
+
+ CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX];
+ CLzmaProb isRep[kNumStates];
+ CLzmaProb isRepG0[kNumStates];
+ CLzmaProb isRepG1[kNumStates];
+ CLzmaProb isRepG2[kNumStates];
+ CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX];
+
+ CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits];
+ CLzmaProb posEncoders[kNumFullDistances - kEndPosModelIndex];
+ CLzmaProb posAlignEncoder[1 << kNumAlignBits];
+
+ CLenPriceEnc lenEnc;
+ CLenPriceEnc repLenEnc;
+
+ UInt32 reps[LZMA_NUM_REPS];
+ UInt32 state;
+} CSaveState;
+
+typedef struct
+{
+ IMatchFinder matchFinder;
+ void *matchFinderObj;
+
+ #ifndef _7ZIP_ST
+ Bool mtMode;
+ CMatchFinderMt matchFinderMt;
+ #endif
+
+ CMatchFinder matchFinderBase;
+
+ #ifndef _7ZIP_ST
+ Byte pad[128];
+ #endif
+
+ UInt32 optimumEndIndex;
+ UInt32 optimumCurrentIndex;
+
+ UInt32 longestMatchLength;
+ UInt32 numPairs;
+ UInt32 numAvail;
+ COptimal opt[kNumOpts];
+
+ #ifndef LZMA_LOG_BSR
+ Byte g_FastPos[1 << kNumLogBits];
+ #endif
+
+ UInt32 ProbPrices[kBitModelTotal >> kNumMoveReducingBits];
+ UInt32 matches[LZMA_MATCH_LEN_MAX * 2 + 2 + 1];
+ UInt32 numFastBytes;
+ UInt32 additionalOffset;
+ UInt32 reps[LZMA_NUM_REPS];
+ UInt32 state;
+
+ UInt32 posSlotPrices[kNumLenToPosStates][kDistTableSizeMax];
+ UInt32 distancesPrices[kNumLenToPosStates][kNumFullDistances];
+ UInt32 alignPrices[kAlignTableSize];
+ UInt32 alignPriceCount;
+
+ UInt32 distTableSize;
+
+ unsigned lc, lp, pb;
+ unsigned lpMask, pbMask;
+
+ CLzmaProb *litProbs;
+
+ CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX];
+ CLzmaProb isRep[kNumStates];
+ CLzmaProb isRepG0[kNumStates];
+ CLzmaProb isRepG1[kNumStates];
+ CLzmaProb isRepG2[kNumStates];
+ CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX];
+
+ CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits];
+ CLzmaProb posEncoders[kNumFullDistances - kEndPosModelIndex];
+ CLzmaProb posAlignEncoder[1 << kNumAlignBits];
+
+ CLenPriceEnc lenEnc;
+ CLenPriceEnc repLenEnc;
+
+ unsigned lclp;
+
+ Bool fastMode;
+
+ CRangeEnc rc;
+
+ Bool writeEndMark;
+ UInt64 nowPos64;
+ UInt32 matchPriceCount;
+ Bool finished;
+ Bool multiThread;
+
+ SRes result;
+ UInt32 dictSize;
+
+ int needInit;
+
+ CSaveState saveState;
+} CLzmaEnc;
+
+void LzmaEnc_SaveState(CLzmaEncHandle pp)
+{
+ CLzmaEnc *p = (CLzmaEnc *)pp;
+ CSaveState *dest = &p->saveState;
+ int i;
+ dest->lenEnc = p->lenEnc;
+ dest->repLenEnc = p->repLenEnc;
+ dest->state = p->state;
+
+ for (i = 0; i < kNumStates; i++)
+ {
+ memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i]));
+ memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i]));
+ }
+ for (i = 0; i < kNumLenToPosStates; i++)
+ memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i]));
+ memcpy(dest->isRep, p->isRep, sizeof(p->isRep));
+ memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0));
+ memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1));
+ memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2));
+ memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders));
+ memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder));
+ memcpy(dest->reps, p->reps, sizeof(p->reps));
+ memcpy(dest->litProbs, p->litProbs, (0x300 << p->lclp) * sizeof(CLzmaProb));
+}
+
+void LzmaEnc_RestoreState(CLzmaEncHandle pp)
+{
+ CLzmaEnc *dest = (CLzmaEnc *)pp;
+ const CSaveState *p = &dest->saveState;
+ int i;
+ dest->lenEnc = p->lenEnc;
+ dest->repLenEnc = p->repLenEnc;
+ dest->state = p->state;
+
+ for (i = 0; i < kNumStates; i++)
+ {
+ memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i]));
+ memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i]));
+ }
+ for (i = 0; i < kNumLenToPosStates; i++)
+ memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i]));
+ memcpy(dest->isRep, p->isRep, sizeof(p->isRep));
+ memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0));
+ memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1));
+ memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2));
+ memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders));
+ memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder));
+ memcpy(dest->reps, p->reps, sizeof(p->reps));
+ memcpy(dest->litProbs, p->litProbs, (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 > ((UInt32)1 << kDicLogSizeMaxCompress) || props.dictSize > ((UInt32)1 << 30))
+ 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->matchFinderBase.btMode = props.btMode;
+ {
+ UInt32 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;
+}
+
+static const int kLiteralNextStates[kNumStates] = {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5};
+static const int kMatchNextStates[kNumStates] = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10};
+static const int kRepNextStates[kNumStates] = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11};
+static const int kShortRepNextStates[kNumStates]= {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11};
+
+#define IsCharState(s) ((s) < 7)
+
+#define GetLenToPosState(len) (((len) < kNumLenToPosStates + 1) ? (len) - 2 : kNumLenToPosStates - 1)
+
+#define kInfinityPrice (1 << 30)
+
+static void RangeEnc_Construct(CRangeEnc *p)
+{
+ p->outStream = 0;
+ p->bufBase = 0;
+}
+
+#define RangeEnc_GetProcessed(p) ((p)->processed + ((p)->buf - (p)->bufBase) + (p)->cacheSize)
+
+#define RC_BUF_SIZE (1 << 16)
+static int RangeEnc_Alloc(CRangeEnc *p, ISzAlloc *alloc)
+{
+ if (p->bufBase == 0)
+ {
+ p->bufBase = (Byte *)alloc->Alloc(alloc, RC_BUF_SIZE);
+ if (p->bufBase == 0)
+ return 0;
+ p->bufLim = p->bufBase + RC_BUF_SIZE;
+ }
+ return 1;
+}
+
+static void RangeEnc_Free(CRangeEnc *p, ISzAlloc *alloc)
+{
+ alloc->Free(alloc, p->bufBase);
+ p->bufBase = 0;
+}
+
+static void RangeEnc_Init(CRangeEnc *p)
+{
+ /* Stream.Init(); */
+ p->low = 0;
+ p->range = 0xFFFFFFFF;
+ p->cacheSize = 1;
+ p->cache = 0;
+
+ p->buf = p->bufBase;
+
+ p->processed = 0;
+ p->res = SZ_OK;
+}
+
+static void RangeEnc_FlushStream(CRangeEnc *p)
+{
+ size_t num;
+ if (p->res != SZ_OK)
+ return;
+ num = p->buf - p->bufBase;
+ if (num != p->outStream->Write(p->outStream, p->bufBase, num))
+ p->res = SZ_ERROR_WRITE;
+ p->processed += num;
+ p->buf = p->bufBase;
+}
+
+static void MY_FAST_CALL RangeEnc_ShiftLow(CRangeEnc *p)
+{
+ if ((UInt32)p->low < (UInt32)0xFF000000 || (unsigned)(p->low >> 32) != 0)
+ {
+ Byte temp = p->cache;
+ do
+ {
+ Byte *buf = p->buf;
+ *buf++ = (Byte)(temp + (Byte)(p->low >> 32));
+ p->buf = buf;
+ if (buf == p->bufLim)
+ RangeEnc_FlushStream(p);
+ temp = 0xFF;
+ }
+ while (--p->cacheSize != 0);
+ p->cache = (Byte)((UInt32)p->low >> 24);
+ }
+ p->cacheSize++;
+ p->low = (UInt32)p->low << 8;
+}
+
+static void RangeEnc_FlushData(CRangeEnc *p)
+{
+ int i;
+ for (i = 0; i < 5; i++)
+ RangeEnc_ShiftLow(p);
+}
+
+static void RangeEnc_EncodeDirectBits(CRangeEnc *p, UInt32 value, unsigned numBits)
+{
+ do
+ {
+ p->range >>= 1;
+ p->low += p->range & (0 - ((value >> --numBits) & 1));
+ if (p->range < kTopValue)
+ {
+ p->range <<= 8;
+ RangeEnc_ShiftLow(p);
+ }
+ }
+ while (numBits != 0);
+}
+
+static void RangeEnc_EncodeBit(CRangeEnc *p, CLzmaProb *prob, UInt32 symbol)
+{
+ UInt32 ttt = *prob;
+ UInt32 newBound = (p->range >> kNumBitModelTotalBits) * ttt;
+ if (symbol == 0)
+ {
+ p->range = newBound;
+ ttt += (kBitModelTotal - ttt) >> kNumMoveBits;
+ }
+ else
+ {
+ p->low += newBound;
+ p->range -= newBound;
+ ttt -= ttt >> kNumMoveBits;
+ }
+ *prob = (CLzmaProb)ttt;
+ if (p->range < kTopValue)
+ {
+ p->range <<= 8;
+ RangeEnc_ShiftLow(p);
+ }
+}
+
+static void LitEnc_Encode(CRangeEnc *p, CLzmaProb *probs, UInt32 symbol)
+{
+ symbol |= 0x100;
+ do
+ {
+ RangeEnc_EncodeBit(p, probs + (symbol >> 8), (symbol >> 7) & 1);
+ symbol <<= 1;
+ }
+ while (symbol < 0x10000);
+}
+
+static void LitEnc_EncodeMatched(CRangeEnc *p, CLzmaProb *probs, UInt32 symbol, UInt32 matchByte)
+{
+ UInt32 offs = 0x100;
+ symbol |= 0x100;
+ do
+ {
+ matchByte <<= 1;
+ RangeEnc_EncodeBit(p, probs + (offs + (matchByte & offs) + (symbol >> 8)), (symbol >> 7) & 1);
+ symbol <<= 1;
+ offs &= ~(matchByte ^ symbol);
+ }
+ while (symbol < 0x10000);
+}
+
+void LzmaEnc_InitPriceTables(UInt32 *ProbPrices)
+{
+ UInt32 i;
+ for (i = (1 << kNumMoveReducingBits) / 2; i < kBitModelTotal; i += (1 << kNumMoveReducingBits))
+ {
+ const int kCyclesBits = kNumBitPriceShiftBits;
+ UInt32 w = i;
+ UInt32 bitCount = 0;
+ int j;
+ for (j = 0; j < kCyclesBits; j++)
+ {
+ w = w * w;
+ bitCount <<= 1;
+ while (w >= ((UInt32)1 << 16))
+ {
+ w >>= 1;
+ bitCount++;
+ }
+ }
+ ProbPrices[i >> kNumMoveReducingBits] = ((kNumBitModelTotalBits << kCyclesBits) - 15 - bitCount);
+ }
+}
+
+
+#define GET_PRICE(prob, symbol) \
+ p->ProbPrices[((prob) ^ (((-(int)(symbol))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits];
+
+#define GET_PRICEa(prob, symbol) \
+ ProbPrices[((prob) ^ ((-((int)(symbol))) & (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_PRICE_0a(prob) ProbPrices[(prob) >> kNumMoveReducingBits]
+#define GET_PRICE_1a(prob) ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits]
+
+static UInt32 LitEnc_GetPrice(const CLzmaProb *probs, UInt32 symbol, UInt32 *ProbPrices)
+{
+ UInt32 price = 0;
+ symbol |= 0x100;
+ do
+ {
+ price += GET_PRICEa(probs[symbol >> 8], (symbol >> 7) & 1);
+ symbol <<= 1;
+ }
+ while (symbol < 0x10000);
+ return price;
+}
+
+static UInt32 LitEnc_GetPriceMatched(const CLzmaProb *probs, UInt32 symbol, UInt32 matchByte, UInt32 *ProbPrices)
+{
+ UInt32 price = 0;
+ UInt32 offs = 0x100;
+ symbol |= 0x100;
+ do
+ {
+ matchByte <<= 1;
+ price += GET_PRICEa(probs[offs + (matchByte & offs) + (symbol >> 8)], (symbol >> 7) & 1);
+ symbol <<= 1;
+ offs &= ~(matchByte ^ symbol);
+ }
+ while (symbol < 0x10000);
+ return price;
+}
+
+
+static void RcTree_Encode(CRangeEnc *rc, CLzmaProb *probs, int numBitLevels, UInt32 symbol)
+{
+ UInt32 m = 1;
+ int i;
+ for (i = numBitLevels; i != 0;)
+ {
+ UInt32 bit;
+ i--;
+ bit = (symbol >> i) & 1;
+ RangeEnc_EncodeBit(rc, probs + m, bit);
+ m = (m << 1) | bit;
+ }
+}
+
+static void RcTree_ReverseEncode(CRangeEnc *rc, CLzmaProb *probs, int numBitLevels, UInt32 symbol)
+{
+ UInt32 m = 1;
+ int i;
+ for (i = 0; i < numBitLevels; i++)
+ {
+ UInt32 bit = symbol & 1;
+ RangeEnc_EncodeBit(rc, probs + m, bit);
+ m = (m << 1) | bit;
+ symbol >>= 1;
+ }
+}
+
+static UInt32 RcTree_GetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices)
+{
+ UInt32 price = 0;
+ symbol |= (1 << numBitLevels);
+ while (symbol != 1)
+ {
+ price += GET_PRICEa(probs[symbol >> 1], symbol & 1);
+ symbol >>= 1;
+ }
+ return price;
+}
+
+static UInt32 RcTree_ReverseGetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices)
+{
+ UInt32 price = 0;
+ UInt32 m = 1;
+ int i;
+ for (i = numBitLevels; i != 0; i--)
+ {
+ UInt32 bit = symbol & 1;
+ symbol >>= 1;
+ price += GET_PRICEa(probs[m], bit);
+ m = (m << 1) | bit;
+ }
+ return price;
+}
+
+
+static void LenEnc_Init(CLenEnc *p)
+{
+ unsigned i;
+ p->choice = p->choice2 = kProbInitValue;
+ for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << kLenNumLowBits); i++)
+ p->low[i] = kProbInitValue;
+ for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << kLenNumMidBits); i++)
+ p->mid[i] = kProbInitValue;
+ for (i = 0; i < kLenNumHighSymbols; i++)
+ p->high[i] = kProbInitValue;
+}
+
+static void LenEnc_Encode(CLenEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState)
+{
+ if (symbol < kLenNumLowSymbols)
+ {
+ RangeEnc_EncodeBit(rc, &p->choice, 0);
+ RcTree_Encode(rc, p->low + (posState << kLenNumLowBits), kLenNumLowBits, symbol);
+ }
+ else
+ {
+ RangeEnc_EncodeBit(rc, &p->choice, 1);
+ if (symbol < kLenNumLowSymbols + kLenNumMidSymbols)
+ {
+ RangeEnc_EncodeBit(rc, &p->choice2, 0);
+ RcTree_Encode(rc, p->mid + (posState << kLenNumMidBits), kLenNumMidBits, symbol - kLenNumLowSymbols);
+ }
+ else
+ {
+ RangeEnc_EncodeBit(rc, &p->choice2, 1);
+ RcTree_Encode(rc, p->high, kLenNumHighBits, symbol - kLenNumLowSymbols - kLenNumMidSymbols);
+ }
+ }
+}
+
+static void LenEnc_SetPrices(CLenEnc *p, UInt32 posState, UInt32 numSymbols, UInt32 *prices, UInt32 *ProbPrices)
+{
+ UInt32 a0 = GET_PRICE_0a(p->choice);
+ UInt32 a1 = GET_PRICE_1a(p->choice);
+ UInt32 b0 = a1 + GET_PRICE_0a(p->choice2);
+ UInt32 b1 = a1 + GET_PRICE_1a(p->choice2);
+ UInt32 i = 0;
+ for (i = 0; i < kLenNumLowSymbols; i++)
+ {
+ if (i >= numSymbols)
+ return;
+ prices[i] = a0 + RcTree_GetPrice(p->low + (posState << kLenNumLowBits), kLenNumLowBits, i, ProbPrices);
+ }
+ for (; i < kLenNumLowSymbols + kLenNumMidSymbols; i++)
+ {
+ if (i >= numSymbols)
+ return;
+ prices[i] = b0 + RcTree_GetPrice(p->mid + (posState << kLenNumMidBits), kLenNumMidBits, i - kLenNumLowSymbols, ProbPrices);
+ }
+ for (; i < numSymbols; i++)
+ prices[i] = b1 + RcTree_GetPrice(p->high, kLenNumHighBits, i - kLenNumLowSymbols - kLenNumMidSymbols, ProbPrices);
+}
+
+static void MY_FAST_CALL LenPriceEnc_UpdateTable(CLenPriceEnc *p, UInt32 posState, UInt32 *ProbPrices)
+{
+ LenEnc_SetPrices(&p->p, posState, p->tableSize, p->prices[posState], ProbPrices);
+ p->counters[posState] = p->tableSize;
+}
+
+static void LenPriceEnc_UpdateTables(CLenPriceEnc *p, UInt32 numPosStates, UInt32 *ProbPrices)
+{
+ UInt32 posState;
+ for (posState = 0; posState < numPosStates; posState++)
+ LenPriceEnc_UpdateTable(p, posState, ProbPrices);
+}
+
+static void LenEnc_Encode2(CLenPriceEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState, Bool updatePrice, UInt32 *ProbPrices)
+{
+ LenEnc_Encode(&p->p, rc, symbol, posState);
+ if (updatePrice)
+ if (--p->counters[posState] == 0)
+ LenPriceEnc_UpdateTable(p, posState, ProbPrices);
+}
+
+
+
+
+static void MovePos(CLzmaEnc *p, UInt32 num)
+{
+ #ifdef SHOW_STAT
+ g_STAT_OFFSET += num;
+ printf("\n MovePos %d", num);
+ #endif
+
+ if (num != 0)
+ {
+ p->additionalOffset += num;
+ p->matchFinder.Skip(p->matchFinderObj, num);
+ }
+}
+
+static UInt32 ReadMatchDistances(CLzmaEnc *p, UInt32 *numDistancePairsRes)
+{
+ UInt32 lenRes = 0, numPairs;
+ p->numAvail = p->matchFinder.GetNumAvailableBytes(p->matchFinderObj);
+ numPairs = p->matchFinder.GetMatches(p->matchFinderObj, p->matches);
+
+ #ifdef SHOW_STAT
+ printf("\n i = %d numPairs = %d ", g_STAT_OFFSET, numPairs / 2);
+ g_STAT_OFFSET++;
+ {
+ UInt32 i;
+ for (i = 0; i < numPairs; i += 2)
+ printf("%2d %6d | ", p->matches[i], p->matches[i + 1]);
+ }
+ #endif
+
+ if (numPairs > 0)
+ {
+ lenRes = p->matches[numPairs - 2];
+ if (lenRes == p->numFastBytes)
+ {
+ const Byte *pby = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
+ UInt32 distance = p->matches[numPairs - 1] + 1;
+ UInt32 numAvail = p->numAvail;
+ if (numAvail > LZMA_MATCH_LEN_MAX)
+ numAvail = LZMA_MATCH_LEN_MAX;
+ {
+ const Byte *pby2 = pby - distance;
+ for (; lenRes < numAvail && pby[lenRes] == pby2[lenRes]; lenRes++);
+ }
+ }
+ }
+ p->additionalOffset++;
+ *numDistancePairsRes = numPairs;
+ return lenRes;
+}
+
+
+#define MakeAsChar(p) (p)->backPrev = (UInt32)(-1); (p)->prev1IsChar = False;
+#define MakeAsShortRep(p) (p)->backPrev = 0; (p)->prev1IsChar = False;
+#define IsShortRep(p) ((p)->backPrev == 0)
+
+static UInt32 GetRepLen1Price(CLzmaEnc *p, UInt32 state, UInt32 posState)
+{
+ return
+ GET_PRICE_0(p->isRepG0[state]) +
+ GET_PRICE_0(p->isRep0Long[state][posState]);
+}
+
+static UInt32 GetPureRepPrice(CLzmaEnc *p, UInt32 repIndex, UInt32 state, UInt32 posState)
+{
+ UInt32 price;
+ if (repIndex == 0)
+ {
+ price = GET_PRICE_0(p->isRepG0[state]);
+ price += GET_PRICE_1(p->isRep0Long[state][posState]);
+ }
+ else
+ {
+ price = GET_PRICE_1(p->isRepG0[state]);
+ if (repIndex == 1)
+ price += GET_PRICE_0(p->isRepG1[state]);
+ else
+ {
+ price += GET_PRICE_1(p->isRepG1[state]);
+ price += GET_PRICE(p->isRepG2[state], repIndex - 2);
+ }
+ }
+ return price;
+}
+
+static UInt32 GetRepPrice(CLzmaEnc *p, UInt32 repIndex, UInt32 len, UInt32 state, UInt32 posState)
+{
+ return p->repLenEnc.prices[posState][len - LZMA_MATCH_LEN_MIN] +
+ GetPureRepPrice(p, repIndex, state, posState);
+}
+
+static UInt32 Backward(CLzmaEnc *p, UInt32 *backRes, UInt32 cur)
+{
+ UInt32 posMem = p->opt[cur].posPrev;
+ UInt32 backMem = p->opt[cur].backPrev;
+ p->optimumEndIndex = cur;
+ do
+ {
+ if (p->opt[cur].prev1IsChar)
+ {
+ MakeAsChar(&p->opt[posMem])
+ p->opt[posMem].posPrev = posMem - 1;
+ if (p->opt[cur].prev2)
+ {
+ p->opt[posMem - 1].prev1IsChar = False;
+ p->opt[posMem - 1].posPrev = p->opt[cur].posPrev2;
+ p->opt[posMem - 1].backPrev = p->opt[cur].backPrev2;
+ }
+ }
+ {
+ UInt32 posPrev = posMem;
+ UInt32 backCur = backMem;
+
+ backMem = p->opt[posPrev].backPrev;
+ posMem = p->opt[posPrev].posPrev;
+
+ p->opt[posPrev].backPrev = backCur;
+ p->opt[posPrev].posPrev = cur;
+ cur = posPrev;
+ }
+ }
+ while (cur != 0);
+ *backRes = p->opt[0].backPrev;
+ p->optimumCurrentIndex = p->opt[0].posPrev;
+ return p->optimumCurrentIndex;
+}
+
+#define LIT_PROBS(pos, prevByte) (p->litProbs + ((((pos) & p->lpMask) << p->lc) + ((prevByte) >> (8 - p->lc))) * 0x300)
+
+static UInt32 GetOptimum(CLzmaEnc *p, UInt32 position, UInt32 *backRes)
+{
+ UInt32 numAvail, mainLen, numPairs, repMaxIndex, i, posState, lenEnd, len, cur;
+ UInt32 matchPrice, repMatchPrice, normalMatchPrice;
+ UInt32 reps[LZMA_NUM_REPS], repLens[LZMA_NUM_REPS];
+ UInt32 *matches;
+ const Byte *data;
+ Byte curByte, matchByte;
+ if (p->optimumEndIndex != p->optimumCurrentIndex)
+ {
+ const COptimal *opt = &p->opt[p->optimumCurrentIndex];
+ UInt32 lenRes = opt->posPrev - p->optimumCurrentIndex;
+ *backRes = opt->backPrev;
+ p->optimumCurrentIndex = opt->posPrev;
+ return lenRes;
+ }
+ p->optimumCurrentIndex = p->optimumEndIndex = 0;
+
+ if (p->additionalOffset == 0)
+ mainLen = ReadMatchDistances(p, &numPairs);
+ else
+ {
+ mainLen = p->longestMatchLength;
+ numPairs = p->numPairs;
+ }
+
+ numAvail = p->numAvail;
+ if (numAvail < 2)
+ {
+ *backRes = (UInt32)(-1);
+ 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++)
+ {
+ UInt32 lenTest;
+ const Byte *data2;
+ reps[i] = p->reps[i];
+ data2 = data - (reps[i] + 1);
+ if (data[0] != data2[0] || data[1] != data2[1])
+ {
+ repLens[i] = 0;
+ continue;
+ }
+ for (lenTest = 2; lenTest < numAvail && data[lenTest] == data2[lenTest]; lenTest++);
+ repLens[i] = lenTest;
+ if (lenTest > repLens[repMaxIndex])
+ repMaxIndex = i;
+ }
+ if (repLens[repMaxIndex] >= p->numFastBytes)
+ {
+ UInt32 lenRes;
+ *backRes = repMaxIndex;
+ lenRes = repLens[repMaxIndex];
+ MovePos(p, lenRes - 1);
+ return lenRes;
+ }
+
+ matches = p->matches;
+ if (mainLen >= p->numFastBytes)
+ {
+ *backRes = matches[numPairs - 1] + LZMA_NUM_REPS;
+ MovePos(p, mainLen - 1);
+ return mainLen;
+ }
+ curByte = *data;
+ matchByte = *(data - (reps[0] + 1));
+
+ if (mainLen < 2 && curByte != matchByte && repLens[repMaxIndex] < 2)
+ {
+ *backRes = (UInt32)-1;
+ 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]) +
+ (!IsCharState(p->state) ?
+ LitEnc_GetPriceMatched(probs, curByte, matchByte, p->ProbPrices) :
+ LitEnc_GetPrice(probs, curByte, p->ProbPrices));
+ }
+
+ MakeAsChar(&p->opt[1]);
+
+ matchPrice = GET_PRICE_1(p->isMatch[p->state][posState]);
+ repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[p->state]);
+
+ if (matchByte == curByte)
+ {
+ UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(p, p->state, posState);
+ if (shortRepPrice < p->opt[1].price)
+ {
+ p->opt[1].price = shortRepPrice;
+ MakeAsShortRep(&p->opt[1]);
+ }
+ }
+ lenEnd = ((mainLen >= repLens[repMaxIndex]) ? mainLen : repLens[repMaxIndex]);
+
+ if (lenEnd < 2)
+ {
+ *backRes = p->opt[1].backPrev;
+ return 1;
+ }
+
+ p->opt[1].posPrev = 0;
+ for (i = 0; i < LZMA_NUM_REPS; i++)
+ p->opt[0].backs[i] = reps[i];
+
+ len = lenEnd;
+ do
+ p->opt[len--].price = kInfinityPrice;
+ while (len >= 2);
+
+ for (i = 0; i < LZMA_NUM_REPS; i++)
+ {
+ UInt32 repLen = repLens[i];
+ UInt32 price;
+ if (repLen < 2)
+ continue;
+ price = repMatchPrice + GetPureRepPrice(p, i, p->state, posState);
+ do
+ {
+ UInt32 curAndLenPrice = price + p->repLenEnc.prices[posState][repLen - 2];
+ COptimal *opt = &p->opt[repLen];
+ if (curAndLenPrice < opt->price)
+ {
+ opt->price = curAndLenPrice;
+ opt->posPrev = 0;
+ opt->backPrev = i;
+ opt->prev1IsChar = False;
+ }
+ }
+ while (--repLen >= 2);
+ }
+
+ normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[p->state]);
+
+ len = ((repLens[0] >= 2) ? repLens[0] + 1 : 2);
+ if (len <= mainLen)
+ {
+ UInt32 offs = 0;
+ while (len > matches[offs])
+ offs += 2;
+ for (; ; len++)
+ {
+ COptimal *opt;
+ UInt32 distance = matches[offs + 1];
+
+ UInt32 curAndLenPrice = normalMatchPrice + p->lenEnc.prices[posState][len - LZMA_MATCH_LEN_MIN];
+ UInt32 lenToPosState = GetLenToPosState(len);
+ if (distance < kNumFullDistances)
+ curAndLenPrice += p->distancesPrices[lenToPosState][distance];
+ else
+ {
+ UInt32 slot;
+ GetPosSlot2(distance, slot);
+ curAndLenPrice += p->alignPrices[distance & kAlignMask] + p->posSlotPrices[lenToPosState][slot];
+ }
+ opt = &p->opt[len];
+ if (curAndLenPrice < opt->price)
+ {
+ opt->price = curAndLenPrice;
+ opt->posPrev = 0;
+ opt->backPrev = distance + LZMA_NUM_REPS;
+ opt->prev1IsChar = False;
+ }
+ 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 <= lenEnd; i++)
+ printf("\nprice[%4X] = %d", position - cur + i, p->opt[i].price);
+ }
+ #endif
+
+ for (;;)
+ {
+ UInt32 numAvailFull, newLen, numPairs, posPrev, state, posState, startLen;
+ UInt32 curPrice, curAnd1Price, matchPrice, repMatchPrice;
+ Bool nextIsChar;
+ Byte curByte, matchByte;
+ const Byte *data;
+ COptimal *curOpt;
+ COptimal *nextOpt;
+
+ cur++;
+ if (cur == lenEnd)
+ return Backward(p, backRes, cur);
+
+ newLen = ReadMatchDistances(p, &numPairs);
+ if (newLen >= p->numFastBytes)
+ {
+ p->numPairs = numPairs;
+ p->longestMatchLength = newLen;
+ return Backward(p, backRes, cur);
+ }
+ position++;
+ curOpt = &p->opt[cur];
+ posPrev = curOpt->posPrev;
+ if (curOpt->prev1IsChar)
+ {
+ posPrev--;
+ if (curOpt->prev2)
+ {
+ state = p->opt[curOpt->posPrev2].state;
+ if (curOpt->backPrev2 < LZMA_NUM_REPS)
+ state = kRepNextStates[state];
+ else
+ state = kMatchNextStates[state];
+ }
+ else
+ state = p->opt[posPrev].state;
+ state = kLiteralNextStates[state];
+ }
+ else
+ state = p->opt[posPrev].state;
+ if (posPrev == cur - 1)
+ {
+ if (IsShortRep(curOpt))
+ state = kShortRepNextStates[state];
+ else
+ state = kLiteralNextStates[state];
+ }
+ else
+ {
+ UInt32 pos;
+ const COptimal *prevOpt;
+ if (curOpt->prev1IsChar && curOpt->prev2)
+ {
+ posPrev = curOpt->posPrev2;
+ pos = curOpt->backPrev2;
+ state = kRepNextStates[state];
+ }
+ else
+ {
+ pos = curOpt->backPrev;
+ if (pos < LZMA_NUM_REPS)
+ state = kRepNextStates[state];
+ else
+ state = kMatchNextStates[state];
+ }
+ prevOpt = &p->opt[posPrev];
+ if (pos < LZMA_NUM_REPS)
+ {
+ UInt32 i;
+ reps[0] = prevOpt->backs[pos];
+ for (i = 1; i <= pos; i++)
+ reps[i] = prevOpt->backs[i - 1];
+ for (; i < LZMA_NUM_REPS; i++)
+ reps[i] = prevOpt->backs[i];
+ }
+ else
+ {
+ UInt32 i;
+ reps[0] = (pos - LZMA_NUM_REPS);
+ for (i = 1; i < LZMA_NUM_REPS; i++)
+ reps[i] = prevOpt->backs[i - 1];
+ }
+ }
+ curOpt->state = (CState)state;
+
+ curOpt->backs[0] = reps[0];
+ curOpt->backs[1] = reps[1];
+ curOpt->backs[2] = reps[2];
+ curOpt->backs[3] = reps[3];
+
+ curPrice = curOpt->price;
+ nextIsChar = False;
+ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
+ curByte = *data;
+ matchByte = *(data - (reps[0] + 1));
+
+ posState = (position & p->pbMask);
+
+ curAnd1Price = curPrice + GET_PRICE_0(p->isMatch[state][posState]);
+ {
+ const CLzmaProb *probs = LIT_PROBS(position, *(data - 1));
+ curAnd1Price +=
+ (!IsCharState(state) ?
+ LitEnc_GetPriceMatched(probs, curByte, matchByte, p->ProbPrices) :
+ LitEnc_GetPrice(probs, curByte, p->ProbPrices));
+ }
+
+ nextOpt = &p->opt[cur + 1];
+
+ if (curAnd1Price < nextOpt->price)
+ {
+ nextOpt->price = curAnd1Price;
+ nextOpt->posPrev = cur;
+ MakeAsChar(nextOpt);
+ nextIsChar = True;
+ }
+
+ matchPrice = curPrice + GET_PRICE_1(p->isMatch[state][posState]);
+ repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[state]);
+
+ if (matchByte == curByte && !(nextOpt->posPrev < cur && nextOpt->backPrev == 0))
+ {
+ UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(p, state, posState);
+ if (shortRepPrice <= nextOpt->price)
+ {
+ nextOpt->price = shortRepPrice;
+ nextOpt->posPrev = cur;
+ MakeAsShortRep(nextOpt);
+ nextIsChar = True;
+ }
+ }
+ numAvailFull = p->numAvail;
+ {
+ UInt32 temp = kNumOpts - 1 - cur;
+ if (temp < numAvailFull)
+ numAvailFull = temp;
+ }
+
+ if (numAvailFull < 2)
+ continue;
+ numAvail = (numAvailFull <= p->numFastBytes ? numAvailFull : p->numFastBytes);
+
+ if (!nextIsChar && matchByte != curByte) /* speed optimization */
+ {
+ /* try Literal + rep0 */
+ UInt32 temp;
+ UInt32 lenTest2;
+ const Byte *data2 = data - (reps[0] + 1);
+ UInt32 limit = p->numFastBytes + 1;
+ if (limit > numAvailFull)
+ limit = numAvailFull;
+
+ for (temp = 1; temp < limit && data[temp] == data2[temp]; temp++);
+ lenTest2 = temp - 1;
+ if (lenTest2 >= 2)
+ {
+ UInt32 state2 = kLiteralNextStates[state];
+ UInt32 posStateNext = (position + 1) & p->pbMask;
+ UInt32 nextRepMatchPrice = curAnd1Price +
+ GET_PRICE_1(p->isMatch[state2][posStateNext]) +
+ GET_PRICE_1(p->isRep[state2]);
+ /* for (; lenTest2 >= 2; lenTest2--) */
+ {
+ UInt32 curAndLenPrice;
+ COptimal *opt;
+ UInt32 offset = cur + 1 + lenTest2;
+ while (lenEnd < offset)
+ p->opt[++lenEnd].price = kInfinityPrice;
+ curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext);
+ opt = &p->opt[offset];
+ if (curAndLenPrice < opt->price)
+ {
+ opt->price = curAndLenPrice;
+ opt->posPrev = cur + 1;
+ opt->backPrev = 0;
+ opt->prev1IsChar = True;
+ opt->prev2 = False;
+ }
+ }
+ }
+ }
+
+ startLen = 2; /* speed optimization */
+ {
+ UInt32 repIndex;
+ for (repIndex = 0; repIndex < LZMA_NUM_REPS; repIndex++)
+ {
+ UInt32 lenTest;
+ UInt32 lenTestTemp;
+ UInt32 price;
+ const Byte *data2 = data - (reps[repIndex] + 1);
+ if (data[0] != data2[0] || data[1] != data2[1])
+ continue;
+ for (lenTest = 2; lenTest < numAvail && data[lenTest] == data2[lenTest]; lenTest++);
+ while (lenEnd < cur + lenTest)
+ p->opt[++lenEnd].price = kInfinityPrice;
+ lenTestTemp = lenTest;
+ price = repMatchPrice + GetPureRepPrice(p, repIndex, state, posState);
+ do
+ {
+ UInt32 curAndLenPrice = price + p->repLenEnc.prices[posState][lenTest - 2];
+ COptimal *opt = &p->opt[cur + lenTest];
+ if (curAndLenPrice < opt->price)
+ {
+ opt->price = curAndLenPrice;
+ opt->posPrev = cur;
+ opt->backPrev = repIndex;
+ opt->prev1IsChar = False;
+ }
+ }
+ while (--lenTest >= 2);
+ lenTest = lenTestTemp;
+
+ if (repIndex == 0)
+ startLen = lenTest + 1;
+
+ /* if (_maxMode) */
+ {
+ UInt32 lenTest2 = lenTest + 1;
+ UInt32 limit = lenTest2 + p->numFastBytes;
+ UInt32 nextRepMatchPrice;
+ if (limit > numAvailFull)
+ limit = numAvailFull;
+ for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++);
+ lenTest2 -= lenTest + 1;
+ if (lenTest2 >= 2)
+ {
+ UInt32 state2 = kRepNextStates[state];
+ UInt32 posStateNext = (position + lenTest) & p->pbMask;
+ UInt32 curAndLenCharPrice =
+ price + p->repLenEnc.prices[posState][lenTest - 2] +
+ GET_PRICE_0(p->isMatch[state2][posStateNext]) +
+ LitEnc_GetPriceMatched(LIT_PROBS(position + lenTest, data[lenTest - 1]),
+ data[lenTest], data2[lenTest], p->ProbPrices);
+ state2 = kLiteralNextStates[state2];
+ posStateNext = (position + lenTest + 1) & p->pbMask;
+ nextRepMatchPrice = curAndLenCharPrice +
+ GET_PRICE_1(p->isMatch[state2][posStateNext]) +
+ GET_PRICE_1(p->isRep[state2]);
+
+ /* for (; lenTest2 >= 2; lenTest2--) */
+ {
+ UInt32 curAndLenPrice;
+ COptimal *opt;
+ UInt32 offset = cur + lenTest + 1 + lenTest2;
+ while (lenEnd < offset)
+ p->opt[++lenEnd].price = kInfinityPrice;
+ curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext);
+ opt = &p->opt[offset];
+ if (curAndLenPrice < opt->price)
+ {
+ opt->price = curAndLenPrice;
+ opt->posPrev = cur + lenTest + 1;
+ opt->backPrev = 0;
+ opt->prev1IsChar = True;
+ opt->prev2 = True;
+ opt->posPrev2 = cur;
+ opt->backPrev2 = repIndex;
+ }
+ }
+ }
+ }
+ }
+ }
+ /* for (UInt32 lenTest = 2; lenTest <= newLen; lenTest++) */
+ if (newLen > numAvail)
+ {
+ newLen = numAvail;
+ for (numPairs = 0; newLen > matches[numPairs]; numPairs += 2);
+ matches[numPairs] = newLen;
+ numPairs += 2;
+ }
+ if (newLen >= startLen)
+ {
+ UInt32 normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[state]);
+ UInt32 offs, curBack, posSlot;
+ UInt32 lenTest;
+ while (lenEnd < cur + newLen)
+ p->opt[++lenEnd].price = kInfinityPrice;
+
+ offs = 0;
+ while (startLen > matches[offs])
+ offs += 2;
+ curBack = matches[offs + 1];
+ GetPosSlot2(curBack, posSlot);
+ for (lenTest = /*2*/ startLen; ; lenTest++)
+ {
+ UInt32 curAndLenPrice = normalMatchPrice + p->lenEnc.prices[posState][lenTest - LZMA_MATCH_LEN_MIN];
+ UInt32 lenToPosState = GetLenToPosState(lenTest);
+ COptimal *opt;
+ if (curBack < kNumFullDistances)
+ curAndLenPrice += p->distancesPrices[lenToPosState][curBack];
+ else
+ curAndLenPrice += p->posSlotPrices[lenToPosState][posSlot] + p->alignPrices[curBack & kAlignMask];
+
+ opt = &p->opt[cur + lenTest];
+ if (curAndLenPrice < opt->price)
+ {
+ opt->price = curAndLenPrice;
+ opt->posPrev = cur;
+ opt->backPrev = curBack + LZMA_NUM_REPS;
+ opt->prev1IsChar = False;
+ }
+
+ if (/*_maxMode && */lenTest == matches[offs])
+ {
+ /* Try Match + Literal + Rep0 */
+ const Byte *data2 = data - (curBack + 1);
+ UInt32 lenTest2 = lenTest + 1;
+ UInt32 limit = lenTest2 + p->numFastBytes;
+ UInt32 nextRepMatchPrice;
+ if (limit > numAvailFull)
+ limit = numAvailFull;
+ for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++);
+ lenTest2 -= lenTest + 1;
+ if (lenTest2 >= 2)
+ {
+ UInt32 state2 = kMatchNextStates[state];
+ UInt32 posStateNext = (position + lenTest) & p->pbMask;
+ UInt32 curAndLenCharPrice = curAndLenPrice +
+ GET_PRICE_0(p->isMatch[state2][posStateNext]) +
+ LitEnc_GetPriceMatched(LIT_PROBS(position + lenTest, data[lenTest - 1]),
+ data[lenTest], data2[lenTest], p->ProbPrices);
+ state2 = kLiteralNextStates[state2];
+ posStateNext = (posStateNext + 1) & p->pbMask;
+ nextRepMatchPrice = curAndLenCharPrice +
+ GET_PRICE_1(p->isMatch[state2][posStateNext]) +
+ GET_PRICE_1(p->isRep[state2]);
+
+ /* for (; lenTest2 >= 2; lenTest2--) */
+ {
+ UInt32 offset = cur + lenTest + 1 + lenTest2;
+ UInt32 curAndLenPrice;
+ COptimal *opt;
+ while (lenEnd < offset)
+ p->opt[++lenEnd].price = kInfinityPrice;
+ curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext);
+ opt = &p->opt[offset];
+ if (curAndLenPrice < opt->price)
+ {
+ opt->price = curAndLenPrice;
+ opt->posPrev = cur + lenTest + 1;
+ opt->backPrev = 0;
+ opt->prev1IsChar = True;
+ opt->prev2 = True;
+ opt->posPrev2 = cur;
+ opt->backPrev2 = curBack + LZMA_NUM_REPS;
+ }
+ }
+ }
+ offs += 2;
+ if (offs == numPairs)
+ break;
+ curBack = matches[offs + 1];
+ if (curBack >= kNumFullDistances)
+ GetPosSlot2(curBack, posSlot);
+ }
+ }
+ }
+ }
+}
+
+#define ChangePair(smallDist, bigDist) (((bigDist) >> 7) > (smallDist))
+
+static UInt32 GetOptimumFast(CLzmaEnc *p, UInt32 *backRes)
+{
+ UInt32 numAvail, mainLen, mainDist, numPairs, repIndex, repLen, i;
+ const Byte *data;
+ const UInt32 *matches;
+
+ if (p->additionalOffset == 0)
+ mainLen = ReadMatchDistances(p, &numPairs);
+ else
+ {
+ mainLen = p->longestMatchLength;
+ numPairs = p->numPairs;
+ }
+
+ numAvail = p->numAvail;
+ *backRes = (UInt32)-1;
+ if (numAvail < 2)
+ return 1;
+ 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++)
+ {
+ UInt32 len;
+ const Byte *data2 = data - (p->reps[i] + 1);
+ if (data[0] != data2[0] || data[1] != data2[1])
+ continue;
+ for (len = 2; len < numAvail && data[len] == data2[len]; len++);
+ if (len >= p->numFastBytes)
+ {
+ *backRes = i;
+ MovePos(p, len - 1);
+ return len;
+ }
+ if (len > repLen)
+ {
+ repIndex = i;
+ repLen = len;
+ }
+ }
+
+ matches = p->matches;
+ if (mainLen >= p->numFastBytes)
+ {
+ *backRes = matches[numPairs - 1] + LZMA_NUM_REPS;
+ MovePos(p, mainLen - 1);
+ return mainLen;
+ }
+
+ mainDist = 0; /* for GCC */
+ if (mainLen >= 2)
+ {
+ mainDist = matches[numPairs - 1];
+ while (numPairs > 2 && mainLen == matches[numPairs - 4] + 1)
+ {
+ if (!ChangePair(matches[numPairs - 3], mainDist))
+ break;
+ numPairs -= 2;
+ mainLen = matches[numPairs - 2];
+ mainDist = matches[numPairs - 1];
+ }
+ if (mainLen == 2 && mainDist >= 0x80)
+ mainLen = 1;
+ }
+
+ if (repLen >= 2 && (
+ (repLen + 1 >= mainLen) ||
+ (repLen + 2 >= mainLen && mainDist >= (1 << 9)) ||
+ (repLen + 3 >= mainLen && mainDist >= (1 << 15))))
+ {
+ *backRes = repIndex;
+ MovePos(p, repLen - 1);
+ return repLen;
+ }
+
+ if (mainLen < 2 || numAvail <= 2)
+ return 1;
+
+ p->longestMatchLength = ReadMatchDistances(p, &p->numPairs);
+ if (p->longestMatchLength >= 2)
+ {
+ UInt32 newDistance = matches[p->numPairs - 1];
+ if ((p->longestMatchLength >= mainLen && newDistance < mainDist) ||
+ (p->longestMatchLength == mainLen + 1 && !ChangePair(mainDist, newDistance)) ||
+ (p->longestMatchLength > mainLen + 1) ||
+ (p->longestMatchLength + 1 >= mainLen && mainLen >= 3 && ChangePair(newDistance, mainDist)))
+ return 1;
+ }
+
+ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
+ for (i = 0; i < LZMA_NUM_REPS; i++)
+ {
+ UInt32 len, limit;
+ const Byte *data2 = data - (p->reps[i] + 1);
+ if (data[0] != data2[0] || data[1] != data2[1])
+ continue;
+ limit = mainLen - 1;
+ for (len = 2; len < limit && data[len] == data2[len]; len++);
+ if (len >= limit)
+ return 1;
+ }
+ *backRes = mainDist + LZMA_NUM_REPS;
+ MovePos(p, mainLen - 2);
+ return mainLen;
+}
+
+static void WriteEndMarker(CLzmaEnc *p, UInt32 posState)
+{
+ UInt32 len;
+ RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 1);
+ RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 0);
+ p->state = kMatchNextStates[p->state];
+ len = LZMA_MATCH_LEN_MIN;
+ LenEnc_Encode2(&p->lenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices);
+ RcTree_Encode(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], kNumPosSlotBits, (1 << kNumPosSlotBits) - 1);
+ RangeEnc_EncodeDirectBits(&p->rc, (((UInt32)1 << 30) - 1) >> kNumAlignBits, 30 - kNumAlignBits);
+ RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, kAlignMask);
+}
+
+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;
+}
+
+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);
+}
+
+static void FillAlignPrices(CLzmaEnc *p)
+{
+ UInt32 i;
+ for (i = 0; i < kAlignTableSize; i++)
+ p->alignPrices[i] = RcTree_ReverseGetPrice(p->posAlignEncoder, kNumAlignBits, i, p->ProbPrices);
+ p->alignPriceCount = 0;
+}
+
+static void FillDistancesPrices(CLzmaEnc *p)
+{
+ UInt32 tempPrices[kNumFullDistances];
+ UInt32 i, lenToPosState;
+ for (i = kStartPosModelIndex; i < kNumFullDistances; i++)
+ {
+ UInt32 posSlot = GetPosSlot1(i);
+ UInt32 footerBits = ((posSlot >> 1) - 1);
+ UInt32 base = ((2 | (posSlot & 1)) << footerBits);
+ tempPrices[i] = RcTree_ReverseGetPrice(p->posEncoders + base - posSlot - 1, footerBits, i - base, p->ProbPrices);
+ }
+
+ for (lenToPosState = 0; lenToPosState < kNumLenToPosStates; lenToPosState++)
+ {
+ UInt32 posSlot;
+ const CLzmaProb *encoder = p->posSlotEncoder[lenToPosState];
+ UInt32 *posSlotPrices = p->posSlotPrices[lenToPosState];
+ for (posSlot = 0; posSlot < p->distTableSize; posSlot++)
+ posSlotPrices[posSlot] = RcTree_GetPrice(encoder, kNumPosSlotBits, posSlot, p->ProbPrices);
+ for (posSlot = kEndPosModelIndex; posSlot < p->distTableSize; posSlot++)
+ posSlotPrices[posSlot] += ((((posSlot >> 1) - 1) - kNumAlignBits) << kNumBitPriceShiftBits);
+
+ {
+ UInt32 *distancesPrices = p->distancesPrices[lenToPosState];
+ UInt32 i;
+ for (i = 0; i < kStartPosModelIndex; i++)
+ distancesPrices[i] = posSlotPrices[i];
+ for (; i < kNumFullDistances; i++)
+ distancesPrices[i] = posSlotPrices[GetPosSlot1(i)] + tempPrices[i];
+ }
+ }
+ p->matchPriceCount = 0;
+}
+
+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 = 0;
+ p->saveState.litProbs = 0;
+}
+
+CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc)
+{
+ void *p;
+ p = alloc->Alloc(alloc, sizeof(CLzmaEnc));
+ if (p != 0)
+ LzmaEnc_Construct((CLzmaEnc *)p);
+ return p;
+}
+
+void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAlloc *alloc)
+{
+ alloc->Free(alloc, p->litProbs);
+ alloc->Free(alloc, p->saveState.litProbs);
+ p->litProbs = 0;
+ p->saveState.litProbs = 0;
+}
+
+void LzmaEnc_Destruct(CLzmaEnc *p, ISzAlloc *alloc, ISzAlloc *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, ISzAlloc *alloc, ISzAlloc *allocBig)
+{
+ LzmaEnc_Destruct((CLzmaEnc *)p, alloc, allocBig);
+ alloc->Free(alloc, p);
+}
+
+static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, Bool useLimits, 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)
+ {
+ UInt32 numPairs;
+ Byte curByte;
+ if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0)
+ return Flush(p, nowPos32);
+ ReadMatchDistances(p, &numPairs);
+ RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][0], 0);
+ p->state = kLiteralNextStates[p->state];
+ curByte = p->matchFinder.GetIndexByte(p->matchFinderObj, 0 - p->additionalOffset);
+ LitEnc_Encode(&p->rc, p->litProbs, curByte);
+ p->additionalOffset--;
+ nowPos32++;
+ }
+
+ if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) != 0)
+ for (;;)
+ {
+ UInt32 pos, len, posState;
+
+ if (p->fastMode)
+ len = GetOptimumFast(p, &pos);
+ else
+ len = GetOptimum(p, nowPos32, &pos);
+
+ #ifdef SHOW_STAT2
+ printf("\n pos = %4X, len = %d pos = %d", nowPos32, len, pos);
+ #endif
+
+ posState = nowPos32 & p->pbMask;
+ if (len == 1 && pos == (UInt32)-1)
+ {
+ Byte curByte;
+ CLzmaProb *probs;
+ const Byte *data;
+
+ RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 0);
+ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset;
+ curByte = *data;
+ probs = LIT_PROBS(nowPos32, *(data - 1));
+ if (IsCharState(p->state))
+ LitEnc_Encode(&p->rc, probs, curByte);
+ else
+ LitEnc_EncodeMatched(&p->rc, probs, curByte, *(data - p->reps[0] - 1));
+ p->state = kLiteralNextStates[p->state];
+ }
+ else
+ {
+ RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 1);
+ if (pos < LZMA_NUM_REPS)
+ {
+ RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 1);
+ if (pos == 0)
+ {
+ RangeEnc_EncodeBit(&p->rc, &p->isRepG0[p->state], 0);
+ RangeEnc_EncodeBit(&p->rc, &p->isRep0Long[p->state][posState], ((len == 1) ? 0 : 1));
+ }
+ else
+ {
+ UInt32 distance = p->reps[pos];
+ RangeEnc_EncodeBit(&p->rc, &p->isRepG0[p->state], 1);
+ if (pos == 1)
+ RangeEnc_EncodeBit(&p->rc, &p->isRepG1[p->state], 0);
+ else
+ {
+ RangeEnc_EncodeBit(&p->rc, &p->isRepG1[p->state], 1);
+ RangeEnc_EncodeBit(&p->rc, &p->isRepG2[p->state], pos - 2);
+ if (pos == 3)
+ p->reps[3] = p->reps[2];
+ p->reps[2] = p->reps[1];
+ }
+ p->reps[1] = p->reps[0];
+ p->reps[0] = distance;
+ }
+ if (len == 1)
+ p->state = kShortRepNextStates[p->state];
+ else
+ {
+ LenEnc_Encode2(&p->repLenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices);
+ p->state = kRepNextStates[p->state];
+ }
+ }
+ else
+ {
+ UInt32 posSlot;
+ RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 0);
+ p->state = kMatchNextStates[p->state];
+ LenEnc_Encode2(&p->lenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices);
+ pos -= LZMA_NUM_REPS;
+ GetPosSlot(pos, posSlot);
+ RcTree_Encode(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], kNumPosSlotBits, posSlot);
+
+ if (posSlot >= kStartPosModelIndex)
+ {
+ UInt32 footerBits = ((posSlot >> 1) - 1);
+ UInt32 base = ((2 | (posSlot & 1)) << footerBits);
+ UInt32 posReduced = pos - base;
+
+ if (posSlot < kEndPosModelIndex)
+ RcTree_ReverseEncode(&p->rc, p->posEncoders + base - posSlot - 1, footerBits, posReduced);
+ else
+ {
+ RangeEnc_EncodeDirectBits(&p->rc, posReduced >> kNumAlignBits, footerBits - kNumAlignBits);
+ RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, posReduced & kAlignMask);
+ p->alignPriceCount++;
+ }
+ }
+ p->reps[3] = p->reps[2];
+ p->reps[2] = p->reps[1];
+ p->reps[1] = p->reps[0];
+ p->reps[0] = pos;
+ p->matchPriceCount++;
+ }
+ }
+ p->additionalOffset -= len;
+ nowPos32 += len;
+ if (p->additionalOffset == 0)
+ {
+ UInt32 processed;
+ if (!p->fastMode)
+ {
+ if (p->matchPriceCount >= (1 << 7))
+ FillDistancesPrices(p);
+ if (p->alignPriceCount >= kAlignTableSize)
+ FillAlignPrices(p);
+ }
+ if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0)
+ break;
+ processed = nowPos32 - startPos32;
+ if (useLimits)
+ {
+ if (processed + kNumOpts + 300 >= maxUnpackSize ||
+ RangeEnc_GetProcessed(&p->rc) + kNumOpts * 2 >= maxPackSize)
+ break;
+ }
+ else if (processed >= (1 << 15))
+ {
+ 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, ISzAlloc *alloc, ISzAlloc *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 == 0 || p->saveState.litProbs == 0 || p->lclp != lclp)
+ {
+ LzmaEnc_FreeLits(p, alloc);
+ p->litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb));
+ p->saveState.litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb));
+ if (p->litProbs == 0 || p->saveState.litProbs == 0)
+ {
+ LzmaEnc_FreeLits(p, alloc);
+ return SZ_ERROR_MEM;
+ }
+ p->lclp = lclp;
+ }
+ }
+
+ p->matchFinderBase.bigHash = (p->dictSize > kBigHashDicLimit);
+
+ 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, allocBig));
+ p->matchFinderObj = &p->matchFinderMt;
+ 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)
+{
+ UInt32 i;
+ p->state = 0;
+ for (i = 0 ; i < LZMA_NUM_REPS; i++)
+ p->reps[i] = 0;
+
+ RangeEnc_Init(&p->rc);
+
+
+ for (i = 0; i < kNumStates; i++)
+ {
+ UInt32 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;
+ }
+
+ {
+ UInt32 num = 0x300 << (p->lp + p->lc);
+ for (i = 0; i < num; i++)
+ p->litProbs[i] = kProbInitValue;
+ }
+
+ {
+ for (i = 0; i < kNumLenToPosStates; i++)
+ {
+ CLzmaProb *probs = p->posSlotEncoder[i];
+ UInt32 j;
+ for (j = 0; j < (1 << kNumPosSlotBits); j++)
+ probs[j] = kProbInitValue;
+ }
+ }
+ {
+ for (i = 0; i < kNumFullDistances - kEndPosModelIndex; i++)
+ p->posEncoders[i] = kProbInitValue;
+ }
+
+ LenEnc_Init(&p->lenEnc.p);
+ LenEnc_Init(&p->repLenEnc.p);
+
+ for (i = 0; i < (1 << kNumAlignBits); i++)
+ p->posAlignEncoder[i] = kProbInitValue;
+
+ p->optimumEndIndex = 0;
+ p->optimumCurrentIndex = 0;
+ p->additionalOffset = 0;
+
+ p->pbMask = (1 << p->pb) - 1;
+ p->lpMask = (1 << p->lp) - 1;
+}
+
+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;
+ LenPriceEnc_UpdateTables(&p->lenEnc, 1 << p->pb, p->ProbPrices);
+ LenPriceEnc_UpdateTables(&p->repLenEnc, 1 << p->pb, p->ProbPrices);
+}
+
+static SRes LzmaEnc_AllocAndInit(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig)
+{
+ UInt32 i;
+ for (i = 0; i < (UInt32)kDicLogSizeMaxCompress; 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,
+ ISzAlloc *alloc, ISzAlloc *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,
+ ISzAlloc *alloc, ISzAlloc *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, ISzAlloc *alloc, ISzAlloc *allocBig)
+{
+ CLzmaEnc *p = (CLzmaEnc *)pp;
+ LzmaEnc_SetInputBuf(p, src, srcLen);
+ p->needInit = 1;
+
+ 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
+ pp = pp;
+ #endif
+}
+
+typedef struct
+{
+ ISeqOutStream funcTable;
+ Byte *data;
+ SizeT rem;
+ Bool overflow;
+} CSeqOutStreamBuf;
+
+static size_t MyWrite(void *pp, const void *data, size_t size)
+{
+ CSeqOutStreamBuf *p = (CSeqOutStreamBuf *)pp;
+ 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, Bool reInit,
+ Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize)
+{
+ CLzmaEnc *p = (CLzmaEnc *)pp;
+ UInt64 nowPos64;
+ SRes res;
+ CSeqOutStreamBuf outStream;
+
+ outStream.funcTable.Write = MyWrite;
+ 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.funcTable;
+
+ res = LzmaEnc_CodeOneBlock(p, True, 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, False, 0, 0);
+ if (res != SZ_OK || p->finished != 0)
+ break;
+ if (progress != 0)
+ {
+ res = progress->Progress(progress, p->nowPos64, RangeEnc_GetProcessed(&p->rc));
+ if (res != SZ_OK)
+ {
+ res = SZ_ERROR_PROGRESS;
+ break;
+ }
+ }
+ }
+ LzmaEnc_Finish(p);
+ return res;
+}
+
+SRes LzmaEnc_Encode(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress,
+ ISzAlloc *alloc, ISzAlloc *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;
+ int 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);
+
+ 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;
+}
+
+SRes LzmaEnc_MemEncode(CLzmaEncHandle pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
+ int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig)
+{
+ SRes res;
+ CLzmaEnc *p = (CLzmaEnc *)pp;
+
+ CSeqOutStreamBuf outStream;
+
+ LzmaEnc_SetInputBuf(p, src, srcLen);
+
+ outStream.funcTable.Write = MyWrite;
+ outStream.data = dest;
+ outStream.rem = *destLen;
+ outStream.overflow = False;
+
+ p->writeEndMark = writeEndMark;
+
+ p->rc.outStream = &outStream.funcTable;
+ res = LzmaEnc_MemPrepare(pp, src, srcLen, 0, alloc, allocBig);
+ if (res == SZ_OK)
+ res = LzmaEnc_Encode2(p, progress);
+
+ *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, ISzAlloc *alloc, ISzAlloc *allocBig)
+{
+ CLzmaEnc *p = (CLzmaEnc *)LzmaEnc_Create(alloc);
+ SRes res;
+ if (p == 0)
+ 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;
+}
diff --git a/lzma/C/LzmaEnc.h b/lzma/C/LzmaEnc.h
new file mode 100644
index 0000000..c2806b4
--- /dev/null
+++ b/lzma/C/LzmaEnc.h
@@ -0,0 +1,78 @@
+/* LzmaEnc.h -- LZMA Encoder
+2013-01-18 : 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 <= (1 << 30) for 64-bit version
+ default = (1 << 24) */
+ UInt64 reduceSize; /* estimated size of data that will be compressed. default = 0xFFFFFFFF.
+ Encoder uses this value to reduce dictionary size */
+ 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 */
+} 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:
+Returns:
+ SZ_OK - OK
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_PARAM - Incorrect paramater in props
+ SZ_ERROR_WRITE - Write callback error.
+ SZ_ERROR_PROGRESS - some break from progress callback
+ SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version)
+*/
+
+typedef void * CLzmaEncHandle;
+
+CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc);
+void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig);
+SRes LzmaEnc_SetProps(CLzmaEncHandle p, const CLzmaEncProps *props);
+SRes LzmaEnc_WriteProperties(CLzmaEncHandle p, Byte *properties, SizeT *size);
+SRes LzmaEnc_Encode(CLzmaEncHandle p, ISeqOutStream *outStream, ISeqInStream *inStream,
+ ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
+SRes LzmaEnc_MemEncode(CLzmaEncHandle p, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
+ int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
+
+/* ---------- One Call Interface ---------- */
+
+/* LzmaEncode
+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)
+*/
+
+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);
+
+EXTERN_C_END
+
+#endif
diff --git a/lzma/C/LzmaLib.c b/lzma/C/LzmaLib.c
new file mode 100644
index 0000000..3e3cf40
--- /dev/null
+++ b/lzma/C/LzmaLib.c
@@ -0,0 +1,46 @@
+/* LzmaLib.c -- LZMA library wrapper
+2008-08-05
+Igor Pavlov
+Public domain */
+
+#include "LzmaEnc.h"
+#include "LzmaDec.h"
+#include "Alloc.h"
+#include "LzmaLib.h"
+
+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 };
+
+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);
+}
diff --git a/lzma/C/LzmaLib.h b/lzma/C/LzmaLib.h
new file mode 100644
index 0000000..5c35e53
--- /dev/null
+++ b/lzma/C/LzmaLib.h
@@ -0,0 +1,131 @@
+/* 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
diff --git a/lzma/C/MtCoder.c b/lzma/C/MtCoder.c
new file mode 100644
index 0000000..303b435
--- /dev/null
+++ b/lzma/C/MtCoder.c
@@ -0,0 +1,329 @@
+/* MtCoder.c -- Multi-thread Coder
+2010-09-24 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include <stdio.h>
+
+#include "MtCoder.h"
+
+void LoopThread_Construct(CLoopThread *p)
+{
+ Thread_Construct(&p->thread);
+ Event_Construct(&p->startEvent);
+ Event_Construct(&p->finishedEvent);
+}
+
+void LoopThread_Close(CLoopThread *p)
+{
+ Thread_Close(&p->thread);
+ Event_Close(&p->startEvent);
+ Event_Close(&p->finishedEvent);
+}
+
+static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE LoopThreadFunc(void *pp)
+{
+ CLoopThread *p = (CLoopThread *)pp;
+ for (;;)
+ {
+ if (Event_Wait(&p->startEvent) != 0)
+ return SZ_ERROR_THREAD;
+ if (p->stop)
+ return 0;
+ p->res = p->func(p->param);
+ if (Event_Set(&p->finishedEvent) != 0)
+ return SZ_ERROR_THREAD;
+ }
+}
+
+WRes LoopThread_Create(CLoopThread *p)
+{
+ p->stop = 0;
+ RINOK(AutoResetEvent_CreateNotSignaled(&p->startEvent));
+ RINOK(AutoResetEvent_CreateNotSignaled(&p->finishedEvent));
+ return Thread_Create(&p->thread, LoopThreadFunc, p);
+}
+
+WRes LoopThread_StopAndWait(CLoopThread *p)
+{
+ p->stop = 1;
+ if (Event_Set(&p->startEvent) != 0)
+ return SZ_ERROR_THREAD;
+ return Thread_Wait(&p->thread);
+}
+
+WRes LoopThread_StartSubThread(CLoopThread *p) { return Event_Set(&p->startEvent); }
+WRes LoopThread_WaitSubThread(CLoopThread *p) { return Event_Wait(&p->finishedEvent); }
+
+static SRes Progress(ICompressProgress *p, UInt64 inSize, UInt64 outSize)
+{
+ return (p && p->Progress(p, inSize, outSize) != SZ_OK) ? SZ_ERROR_PROGRESS : SZ_OK;
+}
+
+static void MtProgress_Init(CMtProgress *p, ICompressProgress *progress)
+{
+ unsigned i;
+ for (i = 0; i < NUM_MT_CODER_THREADS_MAX; i++)
+ p->inSizes[i] = p->outSizes[i] = 0;
+ p->totalInSize = p->totalOutSize = 0;
+ p->progress = progress;
+ p->res = SZ_OK;
+}
+
+static void MtProgress_Reinit(CMtProgress *p, unsigned index)
+{
+ p->inSizes[index] = 0;
+ p->outSizes[index] = 0;
+}
+
+#define UPDATE_PROGRESS(size, prev, total) \
+ if (size != (UInt64)(Int64)-1) { total += size - prev; prev = size; }
+
+SRes MtProgress_Set(CMtProgress *p, unsigned index, UInt64 inSize, UInt64 outSize)
+{
+ SRes res;
+ CriticalSection_Enter(&p->cs);
+ UPDATE_PROGRESS(inSize, p->inSizes[index], p->totalInSize)
+ UPDATE_PROGRESS(outSize, p->outSizes[index], p->totalOutSize)
+ if (p->res == SZ_OK)
+ p->res = Progress(p->progress, p->totalInSize, p->totalOutSize);
+ res = p->res;
+ CriticalSection_Leave(&p->cs);
+ return res;
+}
+
+static void MtProgress_SetError(CMtProgress *p, SRes res)
+{
+ CriticalSection_Enter(&p->cs);
+ if (p->res == SZ_OK)
+ p->res = res;
+ CriticalSection_Leave(&p->cs);
+}
+
+static void MtCoder_SetError(CMtCoder* p, SRes res)
+{
+ CriticalSection_Enter(&p->cs);
+ if (p->res == SZ_OK)
+ p->res = res;
+ CriticalSection_Leave(&p->cs);
+}
+
+/* ---------- MtThread ---------- */
+
+void CMtThread_Construct(CMtThread *p, CMtCoder *mtCoder)
+{
+ p->mtCoder = mtCoder;
+ p->outBuf = 0;
+ p->inBuf = 0;
+ Event_Construct(&p->canRead);
+ Event_Construct(&p->canWrite);
+ LoopThread_Construct(&p->thread);
+}
+
+#define RINOK_THREAD(x) { if((x) != 0) return SZ_ERROR_THREAD; }
+
+static void CMtThread_CloseEvents(CMtThread *p)
+{
+ Event_Close(&p->canRead);
+ Event_Close(&p->canWrite);
+}
+
+static void CMtThread_Destruct(CMtThread *p)
+{
+ CMtThread_CloseEvents(p);
+
+ if (Thread_WasCreated(&p->thread.thread))
+ {
+ LoopThread_StopAndWait(&p->thread);
+ LoopThread_Close(&p->thread);
+ }
+
+ if (p->mtCoder->alloc)
+ IAlloc_Free(p->mtCoder->alloc, p->outBuf);
+ p->outBuf = 0;
+
+ if (p->mtCoder->alloc)
+ IAlloc_Free(p->mtCoder->alloc, p->inBuf);
+ p->inBuf = 0;
+}
+
+#define MY_BUF_ALLOC(buf, size, newSize) \
+ if (buf == 0 || size != newSize) \
+ { IAlloc_Free(p->mtCoder->alloc, buf); \
+ size = newSize; buf = (Byte *)IAlloc_Alloc(p->mtCoder->alloc, size); \
+ if (buf == 0) return SZ_ERROR_MEM; }
+
+static SRes CMtThread_Prepare(CMtThread *p)
+{
+ MY_BUF_ALLOC(p->inBuf, p->inBufSize, p->mtCoder->blockSize)
+ MY_BUF_ALLOC(p->outBuf, p->outBufSize, p->mtCoder->destBlockSize)
+
+ p->stopReading = False;
+ p->stopWriting = False;
+ RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->canRead));
+ RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->canWrite));
+
+ return SZ_OK;
+}
+
+static SRes FullRead(ISeqInStream *stream, Byte *data, size_t *processedSize)
+{
+ size_t size = *processedSize;
+ *processedSize = 0;
+ while (size != 0)
+ {
+ size_t curSize = size;
+ SRes res = stream->Read(stream, data, &curSize);
+ *processedSize += curSize;
+ data += curSize;
+ size -= curSize;
+ RINOK(res);
+ if (curSize == 0)
+ return SZ_OK;
+ }
+ return SZ_OK;
+}
+
+#define GET_NEXT_THREAD(p) &p->mtCoder->threads[p->index == p->mtCoder->numThreads - 1 ? 0 : p->index + 1]
+
+static SRes MtThread_Process(CMtThread *p, Bool *stop)
+{
+ CMtThread *next;
+ *stop = True;
+ if (Event_Wait(&p->canRead) != 0)
+ return SZ_ERROR_THREAD;
+
+ next = GET_NEXT_THREAD(p);
+
+ if (p->stopReading)
+ {
+ next->stopReading = True;
+ return Event_Set(&next->canRead) == 0 ? SZ_OK : SZ_ERROR_THREAD;
+ }
+
+ {
+ size_t size = p->mtCoder->blockSize;
+ size_t destSize = p->outBufSize;
+
+ RINOK(FullRead(p->mtCoder->inStream, p->inBuf, &size));
+ next->stopReading = *stop = (size != p->mtCoder->blockSize);
+ if (Event_Set(&next->canRead) != 0)
+ return SZ_ERROR_THREAD;
+
+ RINOK(p->mtCoder->mtCallback->Code(p->mtCoder->mtCallback, p->index,
+ p->outBuf, &destSize, p->inBuf, size, *stop));
+
+ MtProgress_Reinit(&p->mtCoder->mtProgress, p->index);
+
+ if (Event_Wait(&p->canWrite) != 0)
+ return SZ_ERROR_THREAD;
+ if (p->stopWriting)
+ return SZ_ERROR_FAIL;
+ if (p->mtCoder->outStream->Write(p->mtCoder->outStream, p->outBuf, destSize) != destSize)
+ return SZ_ERROR_WRITE;
+ return Event_Set(&next->canWrite) == 0 ? SZ_OK : SZ_ERROR_THREAD;
+ }
+}
+
+static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE ThreadFunc(void *pp)
+{
+ CMtThread *p = (CMtThread *)pp;
+ for (;;)
+ {
+ Bool stop;
+ CMtThread *next = GET_NEXT_THREAD(p);
+ SRes res = MtThread_Process(p, &stop);
+ if (res != SZ_OK)
+ {
+ MtCoder_SetError(p->mtCoder, res);
+ MtProgress_SetError(&p->mtCoder->mtProgress, res);
+ next->stopReading = True;
+ next->stopWriting = True;
+ Event_Set(&next->canRead);
+ Event_Set(&next->canWrite);
+ return res;
+ }
+ if (stop)
+ return 0;
+ }
+}
+
+void MtCoder_Construct(CMtCoder* p)
+{
+ unsigned i;
+ p->alloc = 0;
+ for (i = 0; i < NUM_MT_CODER_THREADS_MAX; i++)
+ {
+ CMtThread *t = &p->threads[i];
+ t->index = i;
+ CMtThread_Construct(t, p);
+ }
+ CriticalSection_Init(&p->cs);
+ CriticalSection_Init(&p->mtProgress.cs);
+}
+
+void MtCoder_Destruct(CMtCoder* p)
+{
+ unsigned i;
+ for (i = 0; i < NUM_MT_CODER_THREADS_MAX; i++)
+ CMtThread_Destruct(&p->threads[i]);
+ CriticalSection_Delete(&p->cs);
+ CriticalSection_Delete(&p->mtProgress.cs);
+}
+
+SRes MtCoder_Code(CMtCoder *p)
+{
+ unsigned i, numThreads = p->numThreads;
+ SRes res = SZ_OK;
+ p->res = SZ_OK;
+
+ MtProgress_Init(&p->mtProgress, p->progress);
+
+ for (i = 0; i < numThreads; i++)
+ {
+ RINOK(CMtThread_Prepare(&p->threads[i]));
+ }
+
+ for (i = 0; i < numThreads; i++)
+ {
+ CMtThread *t = &p->threads[i];
+ CLoopThread *lt = &t->thread;
+
+ if (!Thread_WasCreated(<->thread))
+ {
+ lt->func = ThreadFunc;
+ lt->param = t;
+
+ if (LoopThread_Create(lt) != SZ_OK)
+ {
+ res = SZ_ERROR_THREAD;
+ break;
+ }
+ }
+ }
+
+ if (res == SZ_OK)
+ {
+ unsigned j;
+ for (i = 0; i < numThreads; i++)
+ {
+ CMtThread *t = &p->threads[i];
+ if (LoopThread_StartSubThread(&t->thread) != SZ_OK)
+ {
+ res = SZ_ERROR_THREAD;
+ p->threads[0].stopReading = True;
+ break;
+ }
+ }
+
+ Event_Set(&p->threads[0].canWrite);
+ Event_Set(&p->threads[0].canRead);
+
+ for (j = 0; j < i; j++)
+ LoopThread_WaitSubThread(&p->threads[j].thread);
+ }
+
+ for (i = 0; i < numThreads; i++)
+ CMtThread_CloseEvents(&p->threads[i]);
+ return (res == SZ_OK) ? p->res : res;
+}
diff --git a/lzma/C/MtCoder.h b/lzma/C/MtCoder.h
new file mode 100644
index 0000000..705208e
--- /dev/null
+++ b/lzma/C/MtCoder.h
@@ -0,0 +1,98 @@
+/* MtCoder.h -- Multi-thread Coder
+2009-11-19 : Igor Pavlov : Public domain */
+
+#ifndef __MT_CODER_H
+#define __MT_CODER_H
+
+#include "Threads.h"
+
+EXTERN_C_BEGIN
+
+typedef struct
+{
+ CThread thread;
+ CAutoResetEvent startEvent;
+ CAutoResetEvent finishedEvent;
+ int stop;
+
+ THREAD_FUNC_TYPE func;
+ LPVOID param;
+ THREAD_FUNC_RET_TYPE res;
+} CLoopThread;
+
+void LoopThread_Construct(CLoopThread *p);
+void LoopThread_Close(CLoopThread *p);
+WRes LoopThread_Create(CLoopThread *p);
+WRes LoopThread_StopAndWait(CLoopThread *p);
+WRes LoopThread_StartSubThread(CLoopThread *p);
+WRes LoopThread_WaitSubThread(CLoopThread *p);
+
+#ifndef _7ZIP_ST
+#define NUM_MT_CODER_THREADS_MAX 32
+#else
+#define NUM_MT_CODER_THREADS_MAX 1
+#endif
+
+typedef struct
+{
+ UInt64 totalInSize;
+ UInt64 totalOutSize;
+ ICompressProgress *progress;
+ SRes res;
+ CCriticalSection cs;
+ UInt64 inSizes[NUM_MT_CODER_THREADS_MAX];
+ UInt64 outSizes[NUM_MT_CODER_THREADS_MAX];
+} CMtProgress;
+
+SRes MtProgress_Set(CMtProgress *p, unsigned index, UInt64 inSize, UInt64 outSize);
+
+struct _CMtCoder;
+
+typedef struct
+{
+ struct _CMtCoder *mtCoder;
+ Byte *outBuf;
+ size_t outBufSize;
+ Byte *inBuf;
+ size_t inBufSize;
+ unsigned index;
+ CLoopThread thread;
+
+ Bool stopReading;
+ Bool stopWriting;
+ CAutoResetEvent canRead;
+ CAutoResetEvent canWrite;
+} CMtThread;
+
+typedef struct
+{
+ SRes (*Code)(void *p, unsigned index, Byte *dest, size_t *destSize,
+ const Byte *src, size_t srcSize, int finished);
+} IMtCoderCallback;
+
+typedef struct _CMtCoder
+{
+ size_t blockSize;
+ size_t destBlockSize;
+ unsigned numThreads;
+
+ ISeqInStream *inStream;
+ ISeqOutStream *outStream;
+ ICompressProgress *progress;
+ ISzAlloc *alloc;
+
+ IMtCoderCallback *mtCallback;
+ CCriticalSection cs;
+ SRes res;
+
+ CMtProgress mtProgress;
+ CMtThread threads[NUM_MT_CODER_THREADS_MAX];
+} CMtCoder;
+
+void MtCoder_Construct(CMtCoder* p);
+void MtCoder_Destruct(CMtCoder* p);
+SRes MtCoder_Code(CMtCoder *p);
+
+EXTERN_C_END
+
+#endif
diff --git a/lzma/C/Ppmd.h b/lzma/C/Ppmd.h
new file mode 100644
index 0000000..25ce2d2
--- /dev/null
+++ b/lzma/C/Ppmd.h
@@ -0,0 +1,85 @@
+/* Ppmd.h -- PPMD codec common code
+2013-01-18 : 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) \
+ { unsigned i; for (i = 0; i < 256 / sizeof(p[0]); i += 8) { \
+ p[i+7] = p[i+6] = p[i+5] = p[i+4] = p[i+3] = p[i+2] = p[i+1] = p[i+0] = ~(size_t)0; }}
+
+EXTERN_C_END
+
+#endif
diff --git a/lzma/C/Ppmd7.c b/lzma/C/Ppmd7.c
new file mode 100644
index 0000000..798c118
--- /dev/null
+++ b/lzma/C/Ppmd7.c
@@ -0,0 +1,710 @@
+/* Ppmd7.c -- PPMdH codec
+2010-03-12 : Igor Pavlov : Public domain
+This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */
+
+#include "Precomp.h"
+
+#include <memory.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[(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, ISzAlloc *alloc)
+{
+ alloc->Free(alloc, p->Base);
+ p->Size = 0;
+ p->Base = 0;
+}
+
+Bool Ppmd7_Alloc(CPpmd7 *p, UInt32 size, ISzAlloc *alloc)
+{
+ if (p->Base == 0 || p->Size != size)
+ {
+ Ppmd7_Free(p, alloc);
+ p->AlignOffset =
+ #ifdef PPMD_32BIT
+ (4 - size) & 3;
+ #else
+ 4 - (size & 3);
+ #endif
+ if ((p->Base = (Byte *)alloc->Alloc(alloc, p->AlignOffset + size
+ #ifndef PPMD_32BIT
+ + UNIT_SIZE
+ #endif
+ )) == 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, Bool 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(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[p->NS2Indx[nonMasked - 1]] +
+ (nonMasked < (unsigned)SUFFIX(p->MinContext)->NumStats - p->MinContext->NumStats) +
+ 2 * (p->MinContext->SummFreq < 11 * p->MinContext->NumStats) +
+ 4 * (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);
+}
diff --git a/lzma/C/Ppmd7.h b/lzma/C/Ppmd7.h
new file mode 100644
index 0000000..56e81eb
--- /dev/null
+++ b/lzma/C/Ppmd7.h
@@ -0,0 +1,140 @@
+/* Ppmd7.h -- PPMdH compression codec
+2010-03-12 : 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);
+Bool Ppmd7_Alloc(CPpmd7 *p, UInt32 size, ISzAlloc *alloc);
+void Ppmd7_Free(CPpmd7 *p, ISzAlloc *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[Ppmd7Context_OneState(p->MinContext)->Freq - 1][p->PrevSuccess + \
+ p->NS2BSIndx[Ppmd7_GetContext(p, p->MinContext->Suffix)->NumStats - 1] + \
+ (p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol]) + \
+ 2 * p->HB2Flag[Ppmd7Context_OneState(p->MinContext)->Symbol] + \
+ ((p->RunLength >> 26) & 0x20)]
+
+CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, UInt32 *scale);
+
+
+/* ---------- Decode ---------- */
+
+typedef struct
+{
+ UInt32 (*GetThreshold)(void *p, UInt32 total);
+ void (*Decode)(void *p, UInt32 start, UInt32 size);
+ UInt32 (*DecodeBit)(void *p, UInt32 size0);
+} IPpmd7_RangeDec;
+
+typedef struct
+{
+ IPpmd7_RangeDec p;
+ UInt32 Range;
+ UInt32 Code;
+ IByteIn *Stream;
+} CPpmd7z_RangeDec;
+
+void Ppmd7z_RangeDec_CreateVTable(CPpmd7z_RangeDec *p);
+Bool Ppmd7z_RangeDec_Init(CPpmd7z_RangeDec *p);
+#define Ppmd7z_RangeDec_IsFinishedOK(p) ((p)->Code == 0)
+
+int Ppmd7_DecodeSymbol(CPpmd7 *p, 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
diff --git a/lzma/C/Ppmd7Dec.c b/lzma/C/Ppmd7Dec.c
new file mode 100644
index 0000000..3d01d76
--- /dev/null
+++ b/lzma/C/Ppmd7Dec.c
@@ -0,0 +1,189 @@
+/* Ppmd7Dec.c -- PPMdH Decoder
+2010-03-12 : 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)
+
+Bool Ppmd7z_RangeDec_Init(CPpmd7z_RangeDec *p)
+{
+ unsigned i;
+ p->Code = 0;
+ p->Range = 0xFFFFFFFF;
+ if (p->Stream->Read((void *)p->Stream) != 0)
+ return False;
+ for (i = 0; i < 4; i++)
+ p->Code = (p->Code << 8) | p->Stream->Read((void *)p->Stream);
+ return (p->Code < 0xFFFFFFFF);
+}
+
+static UInt32 Range_GetThreshold(void *pp, UInt32 total)
+{
+ CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp;
+ return (p->Code) / (p->Range /= total);
+}
+
+static void Range_Normalize(CPpmd7z_RangeDec *p)
+{
+ if (p->Range < kTopValue)
+ {
+ p->Code = (p->Code << 8) | p->Stream->Read((void *)p->Stream);
+ p->Range <<= 8;
+ if (p->Range < kTopValue)
+ {
+ p->Code = (p->Code << 8) | p->Stream->Read((void *)p->Stream);
+ p->Range <<= 8;
+ }
+ }
+}
+
+static void Range_Decode(void *pp, UInt32 start, UInt32 size)
+{
+ CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp;
+ p->Code -= start * p->Range;
+ p->Range *= size;
+ Range_Normalize(p);
+}
+
+static UInt32 Range_DecodeBit(void *pp, UInt32 size0)
+{
+ CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp;
+ 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->p.GetThreshold = Range_GetThreshold;
+ p->p.Decode = Range_Decode;
+ p->p.DecodeBit = Range_DecodeBit;
+}
+
+
+#define MASK(sym) ((signed char *)charMask)[sym]
+
+int Ppmd7_DecodeSymbol(CPpmd7 *p, 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);
+ }
+}
diff --git a/lzma/C/Ppmd7Enc.c b/lzma/C/Ppmd7Enc.c
new file mode 100644
index 0000000..d82ea90
--- /dev/null
+++ b/lzma/C/Ppmd7Enc.c
@@ -0,0 +1,187 @@
+/* Ppmd7Enc.c -- PPMdH Encoder
+2010-03-12 : 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
+ {
+ p->Stream->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);
+ }
+}
diff --git a/lzma/C/Precomp.h b/lzma/C/Precomp.h
new file mode 100644
index 0000000..edb5814
--- /dev/null
+++ b/lzma/C/Precomp.h
@@ -0,0 +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
diff --git a/lzma/C/RotateDefs.h b/lzma/C/RotateDefs.h
new file mode 100644
index 0000000..ad7d164
--- /dev/null
+++ b/lzma/C/RotateDefs.h
@@ -0,0 +1,26 @@
+/* RotateDefs.h -- Rotate functions
+2013-11-12 : Igor Pavlov : Public domain */
+
+#ifndef __ROTATE_DEFS_H
+#define __ROTATE_DEFS_H
+
+#ifdef _MSC_VER
+
+#include <stdlib.h>
+
+// #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
+
+#define rotlFixed(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
+#define rotrFixed(x, n) (((x) >> (n)) | ((x) << (32 - (n))))
+
+#endif
+
+#endif
diff --git a/lzma/C/Sha256.c b/lzma/C/Sha256.c
new file mode 100644
index 0000000..91208d3
--- /dev/null
+++ b/lzma/C/Sha256.c
@@ -0,0 +1,206 @@
+/* Crypto/Sha256.c -- SHA-256 Hash
+2010-06-11 : Igor Pavlov : Public domain
+This code is based on public domain code from Wei Dai's Crypto++ library. */
+
+#include "Precomp.h"
+
+#include "RotateDefs.h"
+#include "Sha256.h"
+
+/* define it for speed optimization */
+/* #define _SHA256_UNROLL */
+/* #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] = data[i])
+#define blk2(i) (W[i&15] += 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)))
+
+#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]
+
+
+#ifdef _SHA256_UNROLL2
+
+#define R(a,b,c,d,e,f,g,h, i) h += S1(e) + Ch(e,f,g) + K[i+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)
+
+#else
+
+#define R(i) h(i) += S1(e(i)) + Ch(e(i),f(i),g(i)) + K[i+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);
+
+#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_Transform(UInt32 *state, const UInt32 *data)
+{
+ UInt32 W[16];
+ unsigned j;
+ #ifdef _SHA256_UNROLL2
+ UInt32 a,b,c,d,e,f,g,h;
+ 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
+ UInt32 T[8];
+ for (j = 0; j < 8; j++)
+ T[j] = state[j];
+ #endif
+
+ for (j = 0; j < 64; j += 16)
+ {
+ #if defined(_SHA256_UNROLL) || defined(_SHA256_UNROLL2)
+ RX_8(0); RX_8(8);
+ #else
+ unsigned i;
+ for (i = 0; i < 16; i++) { R(i); }
+ #endif
+ }
+
+ #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
+
+static void Sha256_WriteByteBlock(CSha256 *p)
+{
+ UInt32 data32[16];
+ unsigned i;
+ for (i = 0; i < 16; i++)
+ data32[i] =
+ ((UInt32)(p->buffer[i * 4 ]) << 24) +
+ ((UInt32)(p->buffer[i * 4 + 1]) << 16) +
+ ((UInt32)(p->buffer[i * 4 + 2]) << 8) +
+ ((UInt32)(p->buffer[i * 4 + 3]));
+ Sha256_Transform(p->state, data32);
+}
+
+void Sha256_Update(CSha256 *p, const Byte *data, size_t size)
+{
+ UInt32 curBufferPos = (UInt32)p->count & 0x3F;
+ while (size > 0)
+ {
+ p->buffer[curBufferPos++] = *data++;
+ p->count++;
+ size--;
+ if (curBufferPos == 64)
+ {
+ curBufferPos = 0;
+ Sha256_WriteByteBlock(p);
+ }
+ }
+}
+
+void Sha256_Final(CSha256 *p, Byte *digest)
+{
+ UInt64 lenInBits = (p->count << 3);
+ UInt32 curBufferPos = (UInt32)p->count & 0x3F;
+ unsigned i;
+ p->buffer[curBufferPos++] = 0x80;
+ while (curBufferPos != (64 - 8))
+ {
+ curBufferPos &= 0x3F;
+ if (curBufferPos == 0)
+ Sha256_WriteByteBlock(p);
+ p->buffer[curBufferPos++] = 0;
+ }
+ for (i = 0; i < 8; i++)
+ {
+ p->buffer[curBufferPos++] = (Byte)(lenInBits >> 56);
+ lenInBits <<= 8;
+ }
+ Sha256_WriteByteBlock(p);
+
+ for (i = 0; i < 8; i++)
+ {
+ *digest++ = (Byte)(p->state[i] >> 24);
+ *digest++ = (Byte)(p->state[i] >> 16);
+ *digest++ = (Byte)(p->state[i] >> 8);
+ *digest++ = (Byte)(p->state[i]);
+ }
+ Sha256_Init(p);
+}
diff --git a/lzma/C/Sha256.h b/lzma/C/Sha256.h
new file mode 100644
index 0000000..7f17ccf
--- /dev/null
+++ b/lzma/C/Sha256.h
@@ -0,0 +1,26 @@
+/* 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
diff --git a/lzma/C/Sort.c b/lzma/C/Sort.c
new file mode 100644
index 0000000..73dcbf0
--- /dev/null
+++ b/lzma/C/Sort.c
@@ -0,0 +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);
+}
+*/
diff --git a/lzma/C/Sort.h b/lzma/C/Sort.h
new file mode 100644
index 0000000..7209d78
--- /dev/null
+++ b/lzma/C/Sort.h
@@ -0,0 +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
diff --git a/lzma/C/Threads.c b/lzma/C/Threads.c
new file mode 100644
index 0000000..18ba1e8
--- /dev/null
+++ b/lzma/C/Threads.c
@@ -0,0 +1,93 @@
+/* Threads.c -- multithreading library
+2013-11-12 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#ifndef _WIN32_WCE
+#include <process.h>
+#endif
+
+#include "Threads.h"
+
+static WRes GetError()
+{
+ DWORD res = GetLastError();
+ return (res) ? (WRes)(res) : 1;
+}
+
+WRes HandleToWRes(HANDLE h) { return (h != 0) ? 0 : GetError(); }
+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);
+}
+
+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;
+}
diff --git a/lzma/C/Threads.h b/lzma/C/Threads.h
new file mode 100644
index 0000000..e927208
--- /dev/null
+++ b/lzma/C/Threads.h
@@ -0,0 +1,67 @@
+/* Threads.h -- multithreading library
+2013-11-12 : 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_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
diff --git a/lzma/C/Util/7z/7z.dsp b/lzma/C/Util/7z/7z.dsp
new file mode 100644
index 0000000..73122f7
--- /dev/null
+++ b/lzma/C/Util/7z/7z.dsp
@@ -0,0 +1,229 @@
+# 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" /FAs /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=..\..\CpuArch.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\CpuArch.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/lzma/C/Util/7z/7z.dsw b/lzma/C/Util/7z/7z.dsw
new file mode 100644
index 0000000..23089fb
--- /dev/null
+++ b/lzma/C/Util/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/lzma/C/Util/7z/7zMain.c b/lzma/C/Util/7z/7zMain.c
new file mode 100644
index 0000000..736a7fe
--- /dev/null
+++ b/lzma/C/Util/7z/7zMain.c
@@ -0,0 +1,546 @@
+/* 7zMain.c - Test application for 7z Decoder
+2015-01-02 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include <stdio.h>
+#include <string.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
+
+static ISzAlloc g_Alloc = { SzAlloc, SzFree };
+
+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
+
+static Byte kUtf8Limits[5] = { 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
+
+static Bool Utf16_To_Utf8(Byte *dest, size_t *destLen, const UInt16 *src, size_t srcLen)
+{
+ size_t destPos = 0, srcPos = 0;
+ for (;;)
+ {
+ unsigned numAdds;
+ UInt32 value;
+ if (srcPos == srcLen)
+ {
+ *destLen = destPos;
+ return True;
+ }
+ value = src[srcPos++];
+ if (value < 0x80)
+ {
+ if (dest)
+ dest[destPos] = (char)value;
+ destPos++;
+ continue;
+ }
+ 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;
+ }
+ for (numAdds = 1; numAdds < 5; numAdds++)
+ if (value < (((UInt32)1) << (numAdds * 5 + 6)))
+ break;
+ if (dest)
+ dest[destPos] = (char)(kUtf8Limits[numAdds - 1] + (value >> (6 * numAdds)));
+ destPos++;
+ do
+ {
+ numAdds--;
+ if (dest)
+ dest[destPos] = (char)(0x80 + ((value >> (6 * numAdds)) & 0x3F));
+ destPos++;
+ }
+ while (numAdds != 0);
+ }
+ *destLen = destPos;
+ return False;
+}
+
+static SRes Utf16_To_Utf8Buf(CBuf *dest, const UInt16 *src, size_t srcLen)
+{
+ size_t destLen = 0;
+ Bool res;
+ Utf16_To_Utf8(NULL, &destLen, src, srcLen);
+ destLen += 1;
+ if (!Buf_EnsureSize(dest, destLen))
+ return SZ_ERROR_MEM;
+ res = Utf16_To_Utf8(dest->data, &destLen, src, srcLen);
+ dest->data[destLen] = 0;
+ return res ? SZ_OK : SZ_ERROR_FAIL;
+}
+
+#endif
+
+static SRes Utf16_To_Char(CBuf *buf, const UInt16 *s
+ #ifdef _WIN32
+ , UINT codePage
+ #endif
+ )
+{
+ unsigned len = 0;
+ for (len = 0; s[len] != 0; len++);
+
+ #ifdef _WIN32
+ {
+ 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, 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(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, 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
+ #ifdef _WIN32
+ , CP_OEMCP
+ #endif
+ );
+ if (res == SZ_OK)
+ fputs((const char *)buf.data, stdout);
+ Buf_Free(&buf, &g_Alloc);
+ return res;
+}
+
+static void UInt64ToStr(UInt64 value, char *s)
+{
+ char temp[32];
+ int pos = 0;
+ do
+ {
+ temp[pos++] = (char)('0' + (unsigned)(value % 10));
+ value /= 10;
+ }
+ while (value != 0);
+ 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 s = ms[mon];
+ if (v < s)
+ break;
+ v -= s;
+ }
+ 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;
+}
+
+void PrintError(const char *sz)
+{
+ printf("\nERROR: %s\n", sz);
+}
+
+#ifdef USE_WINDOWS_FILE
+static void GetAttribString(UInt32 wa, Bool isDir, char *s)
+{
+ 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
+static void GetAttribString(UInt32, Bool, char *s)
+{
+ s[0] = '\0';
+}
+#endif
+
+// #define NUM_PARENTS_MAX 128
+
+int MY_CDECL main(int numargs, char *args[])
+{
+ CFileInStream archiveStream;
+ CLookToRead lookStream;
+ CSzArEx db;
+ SRes res;
+ ISzAlloc allocImp;
+ ISzAlloc allocTempImp;
+ UInt16 *temp = NULL;
+ size_t tempSize = 0;
+ // UInt32 parents[NUM_PARENTS_MAX];
+
+ printf("\n7z ANSI-C Decoder " MY_VERSION_COPYRIGHT_DATE "\n\n");
+ if (numargs == 1)
+ {
+ printf(
+ "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.Alloc = SzAlloc;
+ allocImp.Free = SzFree;
+
+ allocTempImp.Alloc = SzAllocTemp;
+ allocTempImp.Free = SzFreeTemp;
+
+ #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);
+ LookToRead_CreateVTable(&lookStream, False);
+
+ lookStream.realStream = &archiveStream.s;
+ LookToRead_Init(&lookStream);
+
+ CrcGenerateTable();
+
+ SzArEx_Init(&db);
+ res = SzArEx_Open(&db, &lookStream.s, &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;
+ int 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);
+ 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';
+ }
+
+ printf("%s %s %10s ", t, attr, s);
+ res = PrintString(temp);
+ if (res != SZ_OK)
+ break;
+ if (isDir)
+ printf("/");
+ printf("\n");
+ continue;
+ }
+ fputs(testCommand ?
+ "Testing ":
+ "Extracting ",
+ stdout);
+ res = PrintString(temp);
+ if (res != SZ_OK)
+ break;
+ if (isDir)
+ printf("/");
+ else
+ {
+ res = SzArEx_Extract(&db, &lookStream.s, 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);
+ printf("\n");
+ 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;
+ }
+ 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))
+ SetFileAttributesW(destPath, db.Attribs.Vals[i]);
+ #endif
+ }
+ printf("\n");
+ }
+ IAlloc_Free(&allocImp, outBuffer);
+ }
+ }
+ SzArEx_Free(&db, &allocImp);
+ SzFree(NULL, temp);
+
+ File_Close(&archiveStream.file);
+ if (res == SZ_OK)
+ {
+ printf("\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
+ printf("\nERROR #%d\n", res);
+ return 1;
+}
diff --git a/lzma/C/Util/7z/Precomp.c b/lzma/C/Util/7z/Precomp.c
new file mode 100644
index 0000000..34b60f8
--- /dev/null
+++ b/lzma/C/Util/7z/Precomp.c
@@ -0,0 +1,4 @@
+/* Precomp.c -- StdAfx
+2013-01-21 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
diff --git a/lzma/C/Util/7z/Precomp.h b/lzma/C/Util/7z/Precomp.h
new file mode 100644
index 0000000..9f398d0
--- /dev/null
+++ b/lzma/C/Util/7z/Precomp.h
@@ -0,0 +1,10 @@
+/* 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
diff --git a/lzma/C/Util/7z/makefile b/lzma/C/Util/7z/makefile
new file mode 100644
index 0000000..08e6f68
--- /dev/null
+++ b/lzma/C/Util/7z/makefile
@@ -0,0 +1,39 @@
+# MY_STATIC_LINK=1
+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\CpuArch.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/lzma/C/Util/7z/makefile.gcc b/lzma/C/Util/7z/makefile.gcc
new file mode 100644
index 0000000..63c59ca
--- /dev/null
+++ b/lzma/C/Util/7z/makefile.gcc
@@ -0,0 +1,70 @@
+PROG = 7zDec
+CXX = g++
+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 LzmaDec.o Lzma2Dec.o Bra.o Bra86.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
+
+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
+
+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)
+
diff --git a/lzma/C/Util/Lzma/LzmaUtil.c b/lzma/C/Util/Lzma/LzmaUtil.c
new file mode 100644
index 0000000..ee659ba
--- /dev/null
+++ b/lzma/C/Util/Lzma/LzmaUtil.c
@@ -0,0 +1,254 @@
+/* LzmaUtil.c -- Test application for LZMA compression
+2014-12-31 : Igor Pavlov : Public domain */
+
+#include "../../Precomp.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../../Alloc.h"
+#include "../../7zFile.h"
+#include "../../7zVersion.h"
+#include "../../LzmaDec.h"
+#include "../../LzmaEnc.h"
+
+const char *kCantReadMessage = "Can not read input file";
+const char *kCantWriteMessage = "Can not write output file";
+const char *kCantAllocateMessage = "Can not allocate memory";
+const char *kDataErrorMessage = "Data error";
+
+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 };
+
+void PrintHelp(char *buffer)
+{
+ strcat(buffer, "\nLZMA Utility " MY_VERSION_COPYRIGHT_DATE "\n"
+ "\nUsage: lzma <e|d> inputFile outputFile\n"
+ " e: encode file\n"
+ " d: decode file\n");
+}
+
+int PrintError(char *buffer, const char *message)
+{
+ strcat(buffer, "\nError: ");
+ strcat(buffer, message);
+ strcat(buffer, "\n");
+ return 1;
+}
+
+int PrintErrorNumber(char *buffer, SRes val)
+{
+ sprintf(buffer + strlen(buffer), "\nError code: %x\n", (unsigned)val);
+ return 1;
+}
+
+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;
+
+ rs = 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;
+}
+
+int main2(int numArgs, const char *args[], char *rs)
+{
+ CFileSeqInStream inStream;
+ CFileOutStream outStream;
+ char c;
+ int res;
+ int encodeMode;
+ Bool 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.s, &inStream.s, fileSize, rs);
+ }
+ else
+ {
+ res = Decode(&outStream.s, useOutFile ? &inStream.s : 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;
+}
diff --git a/lzma/C/Util/Lzma/LzmaUtil.dsp b/lzma/C/Util/Lzma/LzmaUtil.dsp
new file mode 100644
index 0000000..df1f0cb
--- /dev/null
+++ b/lzma/C/Util/Lzma/LzmaUtil.dsp
@@ -0,0 +1,168 @@
+# 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=..\..\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
+# Begin Source File
+
+SOURCE=..\..\Types.h
+# End Source File
+# End Target
+# End Project
diff --git a/lzma/C/Util/Lzma/LzmaUtil.dsw b/lzma/C/Util/Lzma/LzmaUtil.dsw
new file mode 100644
index 0000000..f435487
--- /dev/null
+++ b/lzma/C/Util/Lzma/LzmaUtil.dsw
@@ -0,0 +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>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/lzma/C/Util/Lzma/makefile b/lzma/C/Util/Lzma/makefile
new file mode 100644
index 0000000..3b825f2
--- /dev/null
+++ b/lzma/C/Util/Lzma/makefile
@@ -0,0 +1,28 @@
+# 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)
diff --git a/lzma/C/Util/Lzma/makefile.gcc b/lzma/C/Util/Lzma/makefile.gcc
new file mode 100644
index 0000000..12a72bb
--- /dev/null
+++ b/lzma/C/Util/Lzma/makefile.gcc
@@ -0,0 +1,44 @@
+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)
diff --git a/lzma/C/Util/LzmaLib/LzmaLib.def b/lzma/C/Util/LzmaLib/LzmaLib.def
new file mode 100644
index 0000000..43b9597
--- /dev/null
+++ b/lzma/C/Util/LzmaLib/LzmaLib.def
@@ -0,0 +1,4 @@
+EXPORTS
+ LzmaCompress
+ LzmaUncompress
+
diff --git a/lzma/C/Util/LzmaLib/LzmaLib.dsp b/lzma/C/Util/LzmaLib/LzmaLib.dsp
new file mode 100644
index 0000000..0d4c981
--- /dev/null
+++ b/lzma/C/Util/LzmaLib/LzmaLib.dsp
@@ -0,0 +1,178 @@
+# 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
diff --git a/lzma/C/Util/LzmaLib/LzmaLib.dsw b/lzma/C/Util/LzmaLib/LzmaLib.dsw
new file mode 100644
index 0000000..f6c5559
--- /dev/null
+++ b/lzma/C/Util/LzmaLib/LzmaLib.dsw
@@ -0,0 +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>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/lzma/C/Util/LzmaLib/LzmaLibExports.c b/lzma/C/Util/LzmaLib/LzmaLibExports.c
new file mode 100644
index 0000000..7434536
--- /dev/null
+++ b/lzma/C/Util/LzmaLib/LzmaLibExports.c
@@ -0,0 +1,12 @@
+/* LzmaLibExports.c -- LZMA library DLL Entry point
+2008-10-04 : Igor Pavlov : Public domain */
+
+#include <windows.h>
+
+BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
+{
+ hInstance = hInstance;
+ dwReason = dwReason;
+ lpReserved = lpReserved;
+ return TRUE;
+}
diff --git a/lzma/C/Util/LzmaLib/makefile b/lzma/C/Util/LzmaLib/makefile
new file mode 100644
index 0000000..e0f3114
--- /dev/null
+++ b/lzma/C/Util/LzmaLib/makefile
@@ -0,0 +1,34 @@
+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)
diff --git a/lzma/C/Util/LzmaLib/resource.rc b/lzma/C/Util/LzmaLib/resource.rc
new file mode 100644
index 0000000..d95e3f3
--- /dev/null
+++ b/lzma/C/Util/LzmaLib/resource.rc
@@ -0,0 +1,3 @@
+#include "../../7zVersion.rc"
+
+MY_VERSION_INFO_DLL("LZMA library", "LZMA")
diff --git a/lzma/C/Util/SfxSetup/Precomp.c b/lzma/C/Util/SfxSetup/Precomp.c
new file mode 100644
index 0000000..34b60f8
--- /dev/null
+++ b/lzma/C/Util/SfxSetup/Precomp.c
@@ -0,0 +1,4 @@
+/* Precomp.c -- StdAfx
+2013-01-21 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
diff --git a/lzma/C/Util/SfxSetup/Precomp.h b/lzma/C/Util/SfxSetup/Precomp.h
new file mode 100644
index 0000000..9f398d0
--- /dev/null
+++ b/lzma/C/Util/SfxSetup/Precomp.h
@@ -0,0 +1,10 @@
+/* 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
diff --git a/lzma/C/Util/SfxSetup/SfxSetup.c b/lzma/C/Util/SfxSetup/SfxSetup.c
new file mode 100644
index 0000000..5714e43
--- /dev/null
+++ b/lzma/C/Util/SfxSetup/SfxSetup.c
@@ -0,0 +1,617 @@
+/* SfxSetup.c - 7z SFX Setup
+2014-12-07 : 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"
+
+#define k_EXE_ExtIndex 2
+
+static const char *kExts[] =
+{
+ "bat"
+ , "cmd"
+ , "exe"
+ , "inf"
+ , "msi"
+ #ifdef UNDER_CE
+ , "cab"
+ #endif
+ , "html"
+ , "htm"
+};
+
+static const char *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 **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 = 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)
+{
+ ctrlType = 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 Bool 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 (; buf[pos] != '7' && pos <= processed; 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 Bool 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;
+ CLookToRead 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;
+ Bool useShellExecute = True;
+
+ #ifdef _CONSOLE
+ SetConsoleCtrlHandler(HandlerRoutine, TRUE);
+ #else
+ hInstance = hInstance;
+ hPrevInstance = hPrevInstance;
+ lpCmdLine = lpCmdLine;
+ nCmdShow = nCmdShow;
+ #endif
+
+ CrcGenerateTable();
+
+ allocImp.Alloc = SzAlloc;
+ allocImp.Free = SzFree;
+
+ allocTempImp.Alloc = SzAllocTemp;
+ allocTempImp.Free = SzFreeTemp;
+
+ FileInStream_CreateVTable(&archiveStream);
+ LookToRead_CreateVTable(&lookStream, False);
+
+ winRes = GetModuleFileNameW(NULL, sfxPath, MAX_PATH);
+ if (winRes == 0 || winRes > MAX_PATH)
+ return 1;
+ {
+ cmdLineParams = GetCommandLineW();
+ #ifndef UNDER_CE
+ {
+ Bool 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] = (char)((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.realStream = &archiveStream.s;
+ LookToRead_Init(&lookStream);
+ }
+
+ SzArEx_Init(&db);
+ if (res == SZ_OK)
+ {
+ res = SzArEx_Open(&db, &lookStream.s, &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;
+ size_t len;
+ WCHAR *temp;
+ len = SzArEx_GetFileNameUtf16(&db, i, NULL);
+
+ if (len >= MAX_PATH)
+ {
+ res = SZ_ERROR_FAIL;
+ break;
+ }
+
+ temp = path + pathLen;
+
+ SzArEx_GetFileNameUtf16(&db, i, temp);
+ {
+ res = SzArEx_Extract(&db, &lookStream.s, 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, temp);
+ for (j = 0; temp[j] != 0; j++)
+ if (temp[j] == '/')
+ temp[j] = CHAR_PATH_SEPARATOR;
+ }
+ }
+ IAlloc_Free(&allocImp, outBuffer);
+ }
+ SzArEx_Free(&db, &allocImp);
+
+ 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);
+ CloseHandle(hProcess);
+ }
+
+ #ifndef UNDER_CE
+ SetCurrentDirectory(oldCurDir);
+ #endif
+ }
+
+ path[pathLen] = L'\0';
+ RemoveDirWithSubItems(path);
+
+ if (res == SZ_OK)
+ return 0;
+
+ {
+ 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/lzma/C/Util/SfxSetup/SfxSetup.dsp b/lzma/C/Util/SfxSetup/SfxSetup.dsp
new file mode 100644
index 0000000..1d5fdd8
--- /dev/null
+++ b/lzma/C/Util/SfxSetup/SfxSetup.dsp
@@ -0,0 +1,211 @@
+# 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=..\..\CpuArch.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\CpuArch.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/lzma/C/Util/SfxSetup/SfxSetup.dsw b/lzma/C/Util/SfxSetup/SfxSetup.dsw
new file mode 100644
index 0000000..128fcdd
--- /dev/null
+++ b/lzma/C/Util/SfxSetup/SfxSetup.dsw
@@ -0,0 +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>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/lzma/C/Util/SfxSetup/makefile b/lzma/C/Util/SfxSetup/makefile
new file mode 100644
index 0000000..cc9878a
--- /dev/null
+++ b/lzma/C/Util/SfxSetup/makefile
@@ -0,0 +1,33 @@
+PROG = 7zS2.sfx
+
+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\CpuArch.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/lzma/C/Util/SfxSetup/makefile_con b/lzma/C/Util/SfxSetup/makefile_con
new file mode 100644
index 0000000..f8bbb1f
--- /dev/null
+++ b/lzma/C/Util/SfxSetup/makefile_con
@@ -0,0 +1,34 @@
+PROG = 7zS2con.sfx
+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\CpuArch.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/lzma/C/Util/SfxSetup/resource.rc b/lzma/C/Util/SfxSetup/resource.rc
new file mode 100644
index 0000000..64f4e2c
--- /dev/null
+++ b/lzma/C/Util/SfxSetup/resource.rc
@@ -0,0 +1,5 @@
+#include "../../7zVersion.rc"
+
+MY_VERSION_INFO_APP("7z Setup SFX small", "7zS2.sfx")
+
+1 ICON "setup.ico"
diff --git a/lzma/C/Util/SfxSetup/setup.ico b/lzma/C/Util/SfxSetup/setup.ico
new file mode 100644
index 0000000..dbb6ca8
--- /dev/null
+++ b/lzma/C/Util/SfxSetup/setup.ico
Binary files differ
diff --git a/lzma/C/Xz.c b/lzma/C/Xz.c
new file mode 100644
index 0000000..f7b5c24
--- /dev/null
+++ b/lzma/C/Xz.c
@@ -0,0 +1,90 @@
+/* Xz.c - Xz
+2009-04-15 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "7zCrc.h"
+#include "CpuArch.h"
+#include "Xz.h"
+#include "XzCrc64.h"
+
+Byte XZ_SIG[XZ_SIG_SIZE] = { 0xFD, '7', 'z', 'X', 'Z', 0 };
+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[i - 1] &= 0x7F;
+ return i;
+}
+
+void Xz_Construct(CXzStream *p)
+{
+ p->numBlocks = p->numBlocksAllocated = 0;
+ p->blocks = 0;
+ p->flags = 0;
+}
+
+void Xz_Free(CXzStream *p, ISzAlloc *alloc)
+{
+ alloc->Free(alloc, p->blocks);
+ p->numBlocks = p->numBlocksAllocated = 0;
+ p->blocks = 0;
+}
+
+unsigned XzFlags_GetCheckSize(CXzStreamFlags f)
+{
+ int t = XzFlags_GetCheckType(f);
+ return (t == 0) ? 0 : (4 << ((t - 1) / 3));
+}
+
+void XzCheck_Init(CXzCheck *p, int 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/lzma/C/Xz.h b/lzma/C/Xz.h
new file mode 100644
index 0000000..2512fd1
--- /dev/null
+++ b/lzma/C/Xz.h
@@ -0,0 +1,275 @@
+/* Xz.h - Xz interface
+2014-12-30 : 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)
+
+SRes XzBlock_Parse(CXzBlock *p, const Byte *header);
+SRes XzBlock_ReadHeader(CXzBlock *p, ISeqInStream *inStream, Bool *isIndex, UInt32 *headerSizeRes);
+
+/* ---------- xz stream ---------- */
+
+#define XZ_SIG_SIZE 6
+#define XZ_FOOTER_SIG_SIZE 2
+
+extern Byte XZ_SIG[XZ_SIG_SIZE];
+extern Byte XZ_FOOTER_SIG[XZ_FOOTER_SIG_SIZE];
+
+#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
+{
+ int mode;
+ UInt32 crc;
+ UInt64 crc64;
+ CSha256 sha;
+} CXzCheck;
+
+void XzCheck_Init(CXzCheck *p, int 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;
+ size_t numBlocksAllocated;
+ CXzBlockSizes *blocks;
+ UInt64 startOffset;
+} CXzStream;
+
+void Xz_Construct(CXzStream *p);
+void Xz_Free(CXzStream *p, ISzAlloc *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, ISzAlloc *alloc);
+SRes Xzs_ReadBackward(CXzs *p, ILookInStream *inStream, Int64 *startOffset, ICompressProgress *progress, ISzAlloc *alloc);
+
+UInt64 Xzs_GetNumBlocks(const CXzs *p);
+UInt64 Xzs_GetUnpackSize(const CXzs *p);
+
+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;
+
+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, ISzAlloc *alloc);
+ SRes (*SetProps)(void *p, const Byte *props, size_t propSize, ISzAlloc *alloc);
+ void (*Init)(void *p);
+ SRes (*Code)(void *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+ int srcWasFinished, ECoderFinishMode finishMode, int *wasFinished);
+} IStateCoder;
+
+#define MIXCODER_NUM_FILTERS_MAX 4
+
+typedef struct
+{
+ ISzAlloc *alloc;
+ Byte *buf;
+ int numCoders;
+ 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];
+ IStateCoder coders[MIXCODER_NUM_FILTERS_MAX];
+} CMixCoder;
+
+void MixCoder_Construct(CMixCoder *p, ISzAlloc *alloc);
+void MixCoder_Free(CMixCoder *p);
+void MixCoder_Init(CMixCoder *p);
+SRes MixCoder_SetFromMethod(CMixCoder *p, int coderIndex, UInt64 methodId);
+SRes MixCoder_Code(CMixCoder *p, Byte *dest, SizeT *destLen,
+ const Byte *src, SizeT *srcLen, int srcWasFinished,
+ ECoderFinishMode finishMode, ECoderStatus *status);
+
+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;
+ UInt64 indexSize;
+ UInt64 indexPos;
+ UInt64 padSize;
+
+ UInt64 numStartedStreams;
+ UInt64 numFinishedStreams;
+ UInt64 numTotalBlocks;
+
+ UInt32 crc;
+ CMixCoder decoder;
+ CXzBlock block;
+ CXzCheck check;
+ CSha256 sha;
+ Byte shaDigest[SHA256_DIGEST_SIZE];
+ Byte buf[XZ_BLOCK_HEADER_SIZE_MAX];
+} CXzUnpacker;
+
+void XzUnpacker_Construct(CXzUnpacker *p, ISzAlloc *alloc);
+void XzUnpacker_Init(CXzUnpacker *p);
+void XzUnpacker_Free(CXzUnpacker *p);
+
+/*
+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, ECoderFinishMode finishMode,
+ ECoderStatus *status);
+
+Bool XzUnpacker_IsStreamWasFinished(CXzUnpacker *p);
+
+/*
+Call XzUnpacker_GetExtraSize after XzUnpacker_Code function to detect real size of
+xz stream in two cases:
+XzUnpacker_Code() returns:
+ res == SZ_OK && status == CODER_STATUS_NEEDS_MORE_INPUT
+ res == SZ_ERROR_NO_ARCHIVE
+*/
+
+UInt64 XzUnpacker_GetExtraSize(CXzUnpacker *p);
+
+EXTERN_C_END
+
+#endif
diff --git a/lzma/C/XzCrc64.c b/lzma/C/XzCrc64.c
new file mode 100644
index 0000000..667e41b
--- /dev/null
+++ b/lzma/C/XzCrc64.c
@@ -0,0 +1,90 @@
+/* XzCrc64.c -- CRC64 calculation
+2011-06-28 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "XzCrc64.h"
+#include "CpuArch.h"
+
+#define kCrc64Poly UINT64_CONST(0xC96C5795D7870F42)
+
+#ifdef MY_CPU_LE
+ #define CRC_NUM_TABLES 4
+#else
+ #define CRC_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 *CRC_FUNC)(UInt64 v, const void *data, size_t size, const UInt64 *table);
+
+static CRC_FUNC g_Crc64Update;
+UInt64 g_Crc64Table[256 * CRC_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 & ~((r & 1) - 1));
+ g_Crc64Table[i] = r;
+ }
+ for (; i < 256 * CRC_NUM_TABLES; i++)
+ {
+ UInt64 r = g_Crc64Table[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 * CRC_NUM_TABLES - 1; i >= 256; i--)
+ {
+ UInt64 x = g_Crc64Table[i - 256];
+ g_Crc64Table[i] = CRC_UINT64_SWAP(x);
+ }
+ g_Crc64Update = XzCrc64UpdateT1_BeT4;
+ }
+ }
+ #endif
+}
diff --git a/lzma/C/XzCrc64.h b/lzma/C/XzCrc64.h
new file mode 100644
index 0000000..71b10d5
--- /dev/null
+++ b/lzma/C/XzCrc64.h
@@ -0,0 +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
diff --git a/lzma/C/XzCrc64Opt.c b/lzma/C/XzCrc64Opt.c
new file mode 100644
index 0000000..65be5cd
--- /dev/null
+++ b/lzma/C/XzCrc64Opt.c
@@ -0,0 +1,69 @@
+/* XzCrc64Opt.c -- CRC64 calculation
+2011-06-28 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "CpuArch.h"
+
+#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
+
+#ifndef MY_CPU_BE
+
+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 = CRC_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 = CRC_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))
+
+UInt64 MY_FAST_CALL XzCrc64UpdateT1_BeT4(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 = CRC_UPDATE_BYTE_2(v, *p);
+ v = CRC_UINT64_SWAP(v);
+ table += 0x100;
+ 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))];
+ }
+ table -= 0x100;
+ v = CRC_UINT64_SWAP(v);
+ for (; size > 0; size--, p++)
+ v = CRC_UPDATE_BYTE_2(v, *p);
+ return v;
+}
+
+#endif
diff --git a/lzma/C/XzDec.c b/lzma/C/XzDec.c
new file mode 100644
index 0000000..e23f221
--- /dev/null
+++ b/lzma/C/XzDec.c
@@ -0,0 +1,909 @@
+/* XzDec.c -- Xz Decode
+2014-12-30 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+/* #define XZ_DUMP */
+
+#ifdef XZ_DUMP
+#include <stdio.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "7zCrc.h"
+#include "Alloc.h"
+#include "Bra.h"
+#include "CpuArch.h"
+#include "Delta.h"
+#include "Lzma2Dec.h"
+
+#ifdef USE_SUBBLOCK
+#include "Bcj3Dec.c"
+#include "SbDec.c"
+#endif
+
+#include "Xz.h"
+
+#define XZ_CHECK_SIZE_MAX 64
+
+#define CODER_BUF_SIZE (1 << 17)
+
+unsigned Xz_ReadVarInt(const Byte *p, size_t maxSize, UInt64 *value)
+{
+ int i, limit;
+ *value = 0;
+ limit = (maxSize > 9) ? 9 : (int)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;
+
+ UInt32 methodId;
+ int encodeMode;
+ UInt32 delta;
+ UInt32 ip;
+ UInt32 x86State;
+ Byte deltaState[DELTA_STATE_SIZE];
+
+ Byte buf[BRA_BUF_SIZE];
+} CBraState;
+
+void BraState_Free(void *pp, ISzAlloc *alloc)
+{
+ alloc->Free(alloc, pp);
+}
+
+SRes BraState_SetProps(void *pp, const Byte *props, size_t propSize, ISzAlloc *alloc)
+{
+ CBraState *p = ((CBraState *)pp);
+ alloc = 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;
+}
+
+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: p->bufConv = isa ## _Convert(p->buf, p->bufTotal, p->ip, p->encodeMode); break;
+
+static SRes BraState_Code(void *pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+ int srcWasFinished, ECoderFinishMode finishMode, int *wasFinished)
+{
+ CBraState *p = ((CBraState *)pp);
+ SizeT destLenOrig = *destLen;
+ SizeT srcLenOrig = *srcLen;
+ *destLen = 0;
+ *srcLen = 0;
+ finishMode = finishMode;
+ *wasFinished = 0;
+ while (destLenOrig > 0)
+ {
+ if (p->bufPos != p->bufConv)
+ {
+ size_t curSize = p->bufConv - p->bufPos;
+ if (curSize > destLenOrig)
+ curSize = destLenOrig;
+ memcpy(dest, p->buf + p->bufPos, curSize);
+ p->bufPos += curSize;
+ *destLen += curSize;
+ dest += curSize;
+ destLenOrig -= curSize;
+ continue;
+ }
+ p->bufTotal -= p->bufPos;
+ memmove(p->buf, p->buf + p->bufPos, p->bufTotal);
+ p->bufPos = 0;
+ p->bufConv = 0;
+ {
+ size_t curSize = BRA_BUF_SIZE - p->bufTotal;
+ if (curSize > srcLenOrig)
+ curSize = srcLenOrig;
+ memcpy(p->buf + p->bufTotal, src, curSize);
+ *srcLen += curSize;
+ src += curSize;
+ srcLenOrig -= curSize;
+ p->bufTotal += curSize;
+ }
+ if (p->bufTotal == 0)
+ break;
+ switch(p->methodId)
+ {
+ case XZ_ID_Delta:
+ if (p->encodeMode)
+ Delta_Encode(p->deltaState, p->delta, p->buf, p->bufTotal);
+ else
+ Delta_Decode(p->deltaState, p->delta, p->buf, p->bufTotal);
+ p->bufConv = p->bufTotal;
+ break;
+ case XZ_ID_X86:
+ p->bufConv = x86_Convert(p->buf, p->bufTotal, 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)
+ default:
+ return SZ_ERROR_UNSUPPORTED;
+ }
+ p->ip += (UInt32)p->bufConv;
+
+ if (p->bufConv == 0)
+ {
+ if (!srcWasFinished)
+ break;
+ p->bufConv = p->bufTotal;
+ }
+ }
+ if (p->bufTotal == p->bufPos && srcLenOrig == 0 && srcWasFinished)
+ *wasFinished = 1;
+ return SZ_OK;
+}
+
+SRes BraState_SetFromMethod(IStateCoder *p, UInt64 id, int encodeMode, ISzAlloc *alloc)
+{
+ CBraState *decoder;
+ if (id != XZ_ID_Delta &&
+ id != XZ_ID_X86 &&
+ id != XZ_ID_PPC &&
+ id != XZ_ID_IA64 &&
+ id != XZ_ID_ARM &&
+ id != XZ_ID_ARMT &&
+ id != XZ_ID_SPARC)
+ return SZ_ERROR_UNSUPPORTED;
+ p->p = 0;
+ decoder = (CBraState *)alloc->Alloc(alloc, sizeof(CBraState));
+ if (decoder == 0)
+ return SZ_ERROR_MEM;
+ decoder->methodId = (UInt32)id;
+ decoder->encodeMode = encodeMode;
+ p->p = decoder;
+ p->Free = BraState_Free;
+ p->SetProps = BraState_SetProps;
+ p->Init = BraState_Init;
+ p->Code = BraState_Code;
+ return SZ_OK;
+}
+
+/* ---------- SbState ---------- */
+
+#ifdef USE_SUBBLOCK
+
+static void SbState_Free(void *pp, ISzAlloc *alloc)
+{
+ CSbDec *p = (CSbDec *)pp;
+ SbDec_Free(p);
+ alloc->Free(alloc, pp);
+}
+
+static SRes SbState_SetProps(void *pp, const Byte *props, size_t propSize, ISzAlloc *alloc)
+{
+ pp = pp;
+ props = props;
+ alloc = alloc;
+ return (propSize == 0) ? SZ_OK : SZ_ERROR_UNSUPPORTED;
+}
+
+static void SbState_Init(void *pp)
+{
+ SbDec_Init((CSbDec *)pp);
+}
+
+static SRes SbState_Code(void *pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+ int srcWasFinished, ECoderFinishMode finishMode, int *wasFinished)
+{
+ CSbDec *p = (CSbDec *)pp;
+ SRes res;
+ srcWasFinished = 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 */
+ return res;
+}
+
+SRes SbState_SetFromMethod(IStateCoder *p, ISzAlloc *alloc)
+{
+ CSbDec *decoder;
+ p->p = 0;
+ decoder = alloc->Alloc(alloc, sizeof(CSbDec));
+ if (decoder == 0)
+ return SZ_ERROR_MEM;
+ p->p = decoder;
+ p->Free = SbState_Free;
+ p->SetProps = SbState_SetProps;
+ p->Init = SbState_Init;
+ p->Code = SbState_Code;
+ SbDec_Construct(decoder);
+ SbDec_SetAlloc(decoder, alloc);
+ return SZ_OK;
+}
+#endif
+
+/* ---------- Lzma2State ---------- */
+
+static void Lzma2State_Free(void *pp, ISzAlloc *alloc)
+{
+ Lzma2Dec_Free((CLzma2Dec *)pp, alloc);
+ alloc->Free(alloc, pp);
+}
+
+static SRes Lzma2State_SetProps(void *pp, const Byte *props, size_t propSize, ISzAlloc *alloc)
+{
+ if (propSize != 1)
+ return SZ_ERROR_UNSUPPORTED;
+ return Lzma2Dec_Allocate((CLzma2Dec *)pp, props[0], alloc);
+}
+
+static void Lzma2State_Init(void *pp)
+{
+ Lzma2Dec_Init((CLzma2Dec *)pp);
+}
+
+static SRes Lzma2State_Code(void *pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+ int srcWasFinished, ECoderFinishMode finishMode, int *wasFinished)
+{
+ ELzmaStatus status;
+ /* ELzmaFinishMode fm = (finishMode == LZMA_FINISH_ANY) ? LZMA_FINISH_ANY : LZMA_FINISH_END; */
+ SRes res = Lzma2Dec_DecodeToBuf((CLzma2Dec *)pp, dest, destLen, src, srcLen, (ELzmaFinishMode)finishMode, &status);
+ srcWasFinished = srcWasFinished;
+ *wasFinished = (status == LZMA_STATUS_FINISHED_WITH_MARK);
+ return res;
+}
+
+static SRes Lzma2State_SetFromMethod(IStateCoder *p, ISzAlloc *alloc)
+{
+ CLzma2Dec *decoder = (CLzma2Dec *)alloc->Alloc(alloc, sizeof(CLzma2Dec));
+ p->p = decoder;
+ if (decoder == 0)
+ return SZ_ERROR_MEM;
+ p->Free = Lzma2State_Free;
+ p->SetProps = Lzma2State_SetProps;
+ p->Init = Lzma2State_Init;
+ p->Code = Lzma2State_Code;
+ Lzma2Dec_Construct(decoder);
+ return SZ_OK;
+}
+
+
+void MixCoder_Construct(CMixCoder *p, ISzAlloc *alloc)
+{
+ int i;
+ p->alloc = alloc;
+ p->buf = 0;
+ p->numCoders = 0;
+ for (i = 0; i < MIXCODER_NUM_FILTERS_MAX; i++)
+ p->coders[i].p = NULL;
+}
+
+void MixCoder_Free(CMixCoder *p)
+{
+ int i;
+ for (i = 0; i < p->numCoders; i++)
+ {
+ IStateCoder *sc = &p->coders[i];
+ if (p->alloc && sc->p)
+ sc->Free(sc->p, p->alloc);
+ }
+ p->numCoders = 0;
+ if (p->buf)
+ {
+ p->alloc->Free(p->alloc, p->buf);
+ p->buf = 0; /* 9.31: the BUG was fixed */
+ }
+}
+
+void MixCoder_Init(CMixCoder *p)
+{
+ int i;
+ for (i = 0; i < p->numCoders - 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);
+ }
+}
+
+SRes MixCoder_SetFromMethod(CMixCoder *p, int coderIndex, UInt64 methodId)
+{
+ IStateCoder *sc = &p->coders[coderIndex];
+ p->ids[coderIndex] = methodId;
+ switch(methodId)
+ {
+ case XZ_ID_LZMA2: return Lzma2State_SetFromMethod(sc, 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);
+}
+
+SRes MixCoder_Code(CMixCoder *p, Byte *dest, SizeT *destLen,
+ const Byte *src, SizeT *srcLen, int srcWasFinished,
+ ECoderFinishMode finishMode, ECoderStatus *status)
+{
+ SizeT destLenOrig = *destLen;
+ SizeT srcLenOrig = *srcLen;
+ Bool allFinished = True;
+ *destLen = 0;
+ *srcLen = 0;
+ *status = CODER_STATUS_NOT_FINISHED;
+
+ if (p->buf == 0)
+ {
+ p->buf = (Byte *)p->alloc->Alloc(p->alloc, CODER_BUF_SIZE * (MIXCODER_NUM_FILTERS_MAX - 1));
+ if (p->buf == 0)
+ return SZ_ERROR_MEM;
+ }
+
+ if (p->numCoders != 1)
+ finishMode = CODER_FINISH_ANY;
+
+ for (;;)
+ {
+ Bool processed = False;
+ int i;
+ /*
+ 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 *destCur;
+ SizeT destLenCur, srcLenCur;
+ const Byte *srcCur;
+ int srcFinishedCur;
+ int encodingWasFinished;
+
+ if (i == 0)
+ {
+ srcCur = src;
+ srcLenCur = srcLenOrig - *srcLen;
+ srcFinishedCur = srcWasFinished;
+ }
+ else
+ {
+ srcCur = p->buf + (CODER_BUF_SIZE * (i - 1)) + p->pos[i - 1];
+ srcLenCur = p->size[i - 1] - p->pos[i - 1];
+ srcFinishedCur = p->finished[i - 1];
+ }
+
+ if (i == p->numCoders - 1)
+ {
+ destCur = dest;
+ destLenCur = destLenOrig - *destLen;
+ }
+ else
+ {
+ if (p->pos[i] != p->size[i])
+ continue;
+ destCur = p->buf + (CODER_BUF_SIZE * i);
+ destLenCur = CODER_BUF_SIZE;
+ }
+
+ res = coder->Code(coder->p, destCur, &destLenCur, srcCur, &srcLenCur, srcFinishedCur, finishMode, &encodingWasFinished);
+
+ if (!encodingWasFinished)
+ allFinished = False;
+
+ if (i == 0)
+ {
+ *srcLen += srcLenCur;
+ src += srcLenCur;
+ }
+ else
+ {
+ p->pos[i - 1] += srcLenCur;
+ }
+
+ if (i == p->numCoders - 1)
+ {
+ *destLen += destLenCur;
+ dest += destLenCur;
+ }
+ else
+ {
+ p->size[i] = destLenCur;
+ p->pos[i] = 0;
+ p->finished[i] = encodingWasFinished;
+ }
+
+ if (res != SZ_OK)
+ return res;
+
+ if (destLenCur != 0 || srcLenCur != 0)
+ processed = True;
+ }
+ if (!processed)
+ break;
+ }
+ if (allFinished)
+ *status = CODER_STATUS_FINISHED_WITH_MARK;
+ return SZ_OK;
+}
+
+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 Bool 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) &&
+ memcmp(buf + 10, XZ_FOOTER_SIG, XZ_FOOTER_SIG_SIZE) == 0);
+}
+
+#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_Parse(CXzBlock *p, const Byte *header)
+{
+ unsigned pos;
+ int numFilters, i;
+ UInt32 headerSize = (UInt32)header[0] << 2;
+
+ if (CrcCalc(header, headerSize) != GetUi32(header + headerSize))
+ return SZ_ERROR_ARCHIVE;
+
+ pos = 1;
+ if (pos == headerSize)
+ return SZ_ERROR_ARCHIVE;
+ p->flags = header[pos++];
+
+ 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;
+ }
+
+ 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[%d] = %2X: ", i, filter->id);
+ {
+ int i;
+ for (i = 0; i < size; i++)
+ printf(" %2X", filter->props[i]);
+ }
+ #endif
+ }
+
+ while (pos < headerSize)
+ if (header[pos++] != 0)
+ return SZ_ERROR_ARCHIVE;
+ return SZ_OK;
+}
+
+SRes XzDec_Init(CMixCoder *p, const CXzBlock *block)
+{
+ int i;
+ Bool needReInit = True;
+ int numFilters = XzBlock_GetNumFilters(block);
+ if (numFilters == p->numCoders)
+ {
+ for (i = 0; i < numFilters; i++)
+ if (p->ids[i] != block->filters[numFilters - 1 - i].id)
+ break;
+ needReInit = (i != numFilters);
+ }
+ if (needReInit)
+ {
+ MixCoder_Free(p);
+ p->numCoders = numFilters;
+ for (i = 0; i < numFilters; i++)
+ {
+ const CXzFilter *f = &block->filters[numFilters - 1 - i];
+ RINOK(MixCoder_SetFromMethod(p, i, f->id));
+ }
+ }
+ 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;
+}
+
+void XzUnpacker_Construct(CXzUnpacker *p, ISzAlloc *alloc)
+{
+ MixCoder_Construct(&p->decoder, alloc);
+ XzUnpacker_Init(p);
+}
+
+void XzUnpacker_Free(CXzUnpacker *p)
+{
+ MixCoder_Free(&p->decoder);
+}
+
+SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen,
+ const Byte *src, SizeT *srcLen, ECoderFinishMode finishMode, ECoderStatus *status)
+{
+ SizeT destLenOrig = *destLen;
+ SizeT srcLenOrig = *srcLen;
+ *destLen = 0;
+ *srcLen = 0;
+ *status = CODER_STATUS_NOT_SPECIFIED;
+ for (;;)
+ {
+ SizeT srcRem = srcLenOrig - *srcLen;
+
+ if (p->state == XZ_STATE_BLOCK)
+ {
+ SizeT destLen2 = destLenOrig - *destLen;
+ SizeT srcLen2 = srcLenOrig - *srcLen;
+ SRes res;
+ if (srcLen2 == 0 && destLen2 == 0)
+ {
+ *status = CODER_STATUS_NOT_FINISHED;
+ return SZ_OK;
+ }
+
+ res = MixCoder_Code(&p->decoder, dest, &destLen2, src, &srcLen2, False, finishMode, status);
+ XzCheck_Update(&p->check, dest, destLen2);
+
+ (*srcLen) += srcLen2;
+ src += srcLen2;
+ p->packSize += srcLen2;
+
+ (*destLen) += destLen2;
+ dest += destLen2;
+ p->unpackSize += destLen2;
+
+ RINOK(res);
+
+ if (*status == CODER_STATUS_FINISHED_WITH_MARK)
+ {
+ Byte temp[32];
+ unsigned num = Xz_WriteVarInt(temp, p->packSize + p->blockHeaderSize + XzFlags_GetCheckSize(p->streamFlags));
+ num += Xz_WriteVarInt(temp + num, p->unpackSize);
+ Sha256_Update(&p->sha, temp, num);
+ p->indexSize += num;
+ p->numBlocks++;
+
+ p->state = XZ_STATE_BLOCK_FOOTER;
+ p->pos = 0;
+ p->alignPos = 0;
+ }
+ else if (srcLen2 == 0 && destLen2 == 0)
+ return SZ_OK;
+
+ continue;
+ }
+
+ if (srcRem == 0)
+ {
+ *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;
+ p->buf[p->pos++] = *src++;
+ (*srcLen)++;
+ }
+ else
+ {
+ RINOK(Xz_ParseHeader(&p->streamFlags, p->buf));
+ p->numStartedStreams++;
+ p->state = XZ_STATE_BLOCK_HEADER;
+ Sha256_Init(&p->sha);
+ p->indexSize = 0;
+ p->numBlocks = 0;
+ p->pos = 0;
+ }
+ break;
+ }
+
+ case XZ_STATE_BLOCK_HEADER:
+ {
+ if (p->pos == 0)
+ {
+ p->buf[p->pos++] = *src++;
+ (*srcLen)++;
+ if (p->buf[0] == 0)
+ {
+ 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;
+ }
+ p->blockHeaderSize = ((UInt32)p->buf[0] << 2) + 4;
+ }
+ else 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));
+ p->numTotalBlocks++;
+ p->state = XZ_STATE_BLOCK;
+ p->packSize = 0;
+ p->unpackSize = 0;
+ XzCheck_Init(&p->check, XzFlags_GetCheckType(p->streamFlags));
+ RINOK(XzDec_Init(&p->decoder, &p->block));
+ }
+ break;
+ }
+
+ case XZ_STATE_BLOCK_FOOTER:
+ {
+ if (((p->packSize + p->alignPos) & 3) != 0)
+ {
+ (*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 (cur > srcRem)
+ cur = (UInt32)srcRem;
+ memcpy(p->buf + p->pos, src, cur);
+ p->pos += cur;
+ (*srcLen) += cur;
+ src += cur;
+ }
+ else
+ {
+ 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;
+ }
+ }
+ 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;
+ */
+}
+
+Bool XzUnpacker_IsStreamWasFinished(CXzUnpacker *p)
+{
+ return (p->state == XZ_STATE_STREAM_PADDING) && (((UInt32)p->padSize & 3) == 0);
+}
+
+UInt64 XzUnpacker_GetExtraSize(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;
+}
diff --git a/lzma/C/XzEnc.c b/lzma/C/XzEnc.c
new file mode 100644
index 0000000..3263519
--- /dev/null
+++ b/lzma/C/XzEnc.c
@@ -0,0 +1,522 @@
+/* XzEnc.c -- Xz Encode
+2014-12-30 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "7zCrc.h"
+#include "Alloc.h"
+#include "Bra.h"
+#include "CpuArch.h"
+#ifdef USE_SUBBLOCK
+#include "Bcj3Enc.c"
+#include "SbFind.c"
+#include "SbEnc.c"
+#endif
+
+#include "XzEnc.h"
+
+static void *SzBigAlloc(void *p, size_t size) { p = p; return BigAlloc(size); }
+static void SzBigFree(void *p, void *address) { p = p; BigFree(address); }
+static ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree };
+
+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 };
+
+#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, UInt32 size)
+{
+ return (s->Write(s, buf, size) == size) ? SZ_OK : SZ_ERROR_WRITE;
+}
+
+static SRes WriteBytesAndCrc(ISeqOutStream *s, const void *buf, UInt32 size, UInt32 *crc)
+{
+ *crc = CrcUpdate(*crc, buf, size);
+ return WriteBytes(s, buf, size);
+}
+
+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);
+}
+
+SRes XzBlock_WriteHeader(const CXzBlock *p, ISeqOutStream *s)
+{
+ Byte header[XZ_BLOCK_HEADER_SIZE_MAX];
+
+ unsigned pos = 1;
+ int 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);
+}
+
+SRes Xz_WriteFooter(CXzStream *p, ISeqOutStream *s)
+{
+ Byte buf[32];
+ UInt64 globalPos;
+ {
+ UInt32 crc = CRC_INIT_VAL;
+ unsigned pos = 1 + Xz_WriteVarInt(buf + 1, p->numBlocks);
+ size_t i;
+
+ globalPos = pos;
+ buf[0] = 0;
+ RINOK(WriteBytesAndCrc(s, buf, pos, &crc));
+ for (i = 0; i < p->numBlocks; i++)
+ {
+ const CXzBlockSizes *block = &p->blocks[i];
+ pos = Xz_WriteVarInt(buf, block->totalSize);
+ pos += Xz_WriteVarInt(buf + pos, block->unpackSize);
+ globalPos += pos;
+ RINOK(WriteBytesAndCrc(s, buf, pos, &crc));
+ }
+ pos = ((unsigned)globalPos & 3);
+ if (pos != 0)
+ {
+ buf[0] = buf[1] = buf[2] = 0;
+ RINOK(WriteBytesAndCrc(s, buf, 4 - pos, &crc));
+ globalPos += 4 - pos;
+ }
+ {
+ SetUi32(buf, CRC_GET_DIGEST(crc));
+ RINOK(WriteBytes(s, buf, 4));
+ globalPos += 4;
+ }
+ }
+
+ {
+ UInt32 indexSize = (UInt32)((globalPos >> 2) - 1);
+ SetUi32(buf + 4, indexSize);
+ buf[8] = (Byte)(p->flags >> 8);
+ buf[9] = (Byte)(p->flags & 0xFF);
+ SetUi32(buf, CrcCalc(buf + 4, 6));
+ memcpy(buf + 10, XZ_FOOTER_SIG, XZ_FOOTER_SIG_SIZE);
+ return WriteBytes(s, buf, 12);
+ }
+}
+
+SRes Xz_AddIndexRecord(CXzStream *p, UInt64 unpackSize, UInt64 totalSize, ISzAlloc *alloc)
+{
+ if (p->blocks == 0 || p->numBlocksAllocated == p->numBlocks)
+ {
+ size_t num = (p->numBlocks + 1) * 2;
+ size_t newSize = sizeof(CXzBlockSizes) * num;
+ CXzBlockSizes *blocks;
+ if (newSize / sizeof(CXzBlockSizes) != num)
+ return SZ_ERROR_MEM;
+ blocks = (CXzBlockSizes *)alloc->Alloc(alloc, newSize);
+ if (blocks == 0)
+ return SZ_ERROR_MEM;
+ if (p->numBlocks != 0)
+ {
+ memcpy(blocks, p->blocks, p->numBlocks * sizeof(CXzBlockSizes));
+ Xz_Free(p, alloc);
+ }
+ p->blocks = blocks;
+ p->numBlocksAllocated = num;
+ }
+ {
+ CXzBlockSizes *block = &p->blocks[p->numBlocks++];
+ block->totalSize = totalSize;
+ block->unpackSize = unpackSize;
+ }
+ return SZ_OK;
+}
+
+/* ---------- CSeqCheckInStream ---------- */
+
+typedef struct
+{
+ ISeqInStream p;
+ ISeqInStream *realStream;
+ UInt64 processed;
+ CXzCheck check;
+} CSeqCheckInStream;
+
+void SeqCheckInStream_Init(CSeqCheckInStream *p, int mode)
+{
+ p->processed = 0;
+ XzCheck_Init(&p->check, mode);
+}
+
+void SeqCheckInStream_GetDigest(CSeqCheckInStream *p, Byte *digest)
+{
+ XzCheck_Final(&p->check, digest);
+}
+
+static SRes SeqCheckInStream_Read(void *pp, void *data, size_t *size)
+{
+ CSeqCheckInStream *p = (CSeqCheckInStream *)pp;
+ SRes res = p->realStream->Read(p->realStream, data, size);
+ XzCheck_Update(&p->check, data, *size);
+ p->processed += *size;
+ return res;
+}
+
+/* ---------- CSeqSizeOutStream ---------- */
+
+typedef struct
+{
+ ISeqOutStream p;
+ ISeqOutStream *realStream;
+ UInt64 processed;
+} CSeqSizeOutStream;
+
+static size_t MyWrite(void *pp, const void *data, size_t size)
+{
+ CSeqSizeOutStream *p = (CSeqSizeOutStream *)pp;
+ size = p->realStream->Write(p->realStream, 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;
+
+static SRes SeqInFilter_Read(void *pp, void *data, size_t *size)
+{
+ CSeqInFilter *p = (CSeqInFilter *)pp;
+ 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(p->realStream->Read(p->realStream, p->buf, &p->endPos));
+ if (p->endPos == 0)
+ p->srcWasFinished = 1;
+ }
+ {
+ SizeT srcLen = p->endPos - p->curPos;
+ int wasFinished;
+ SRes res;
+ *size = sizeOriginal;
+ res = p->StateCoder.Code(p->StateCoder.p, data, size, p->buf + p->curPos, &srcLen,
+ p->srcWasFinished, CODER_FINISH_ANY, &wasFinished);
+ p->curPos += srcLen;
+ if (*size != 0 || srcLen == 0 || res != 0)
+ return res;
+ }
+ }
+}
+
+static void SeqInFilter_Construct(CSeqInFilter *p)
+{
+ p->buf = NULL;
+ p->p.Read = SeqInFilter_Read;
+}
+
+static void SeqInFilter_Free(CSeqInFilter *p)
+{
+ if (p->buf)
+ {
+ g_Alloc.Free(&g_Alloc, p->buf);
+ p->buf = NULL;
+ }
+}
+
+SRes BraState_SetFromMethod(IStateCoder *p, UInt64 id, int encodeMode, ISzAlloc *alloc);
+
+static SRes SeqInFilter_Init(CSeqInFilter *p, const CXzFilter *props)
+{
+ if (!p->buf)
+ {
+ p->buf = g_Alloc.Alloc(&g_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, &g_Alloc));
+ RINOK(p->StateCoder.SetProps(p->StateCoder.p, props->props, props->propsSize, &g_Alloc));
+ p->StateCoder.Init(p->StateCoder.p);
+ return SZ_OK;
+}
+
+/* ---------- CSbEncInStream ---------- */
+
+#ifdef USE_SUBBLOCK
+
+typedef struct
+{
+ ISeqInStream p;
+ ISeqInStream *inStream;
+ CSbEnc enc;
+} CSbEncInStream;
+
+static SRes SbEncInStream_Read(void *pp, void *data, size_t *size)
+{
+ CSbEncInStream *p = (CSbEncInStream *)pp;
+ size_t sizeOriginal = *size;
+ if (sizeOriginal == 0)
+ return S_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 S_OK;
+ }
+}
+
+void SbEncInStream_Construct(CSbEncInStream *p, ISzAlloc *alloc)
+{
+ SbEnc_Construct(&p->enc, alloc);
+ p->p.Read = SbEncInStream_Read;
+}
+
+SRes SbEncInStream_Init(CSbEncInStream *p)
+{
+ return SbEnc_Init(&p->enc);
+}
+
+void SbEncInStream_Free(CSbEncInStream *p)
+{
+ SbEnc_Free(&p->enc);
+}
+
+#endif
+
+
+typedef struct
+{
+ CLzma2EncHandle lzma2;
+ #ifdef USE_SUBBLOCK
+ CSbEncInStream sb;
+ #endif
+ CSeqInFilter filter;
+ ISzAlloc *alloc;
+ ISzAlloc *bigAlloc;
+} CLzma2WithFilters;
+
+
+static void Lzma2WithFilters_Construct(CLzma2WithFilters *p, ISzAlloc *alloc, ISzAlloc *bigAlloc)
+{
+ p->alloc = alloc;
+ p->bigAlloc = bigAlloc;
+ p->lzma2 = NULL;
+ #ifdef USE_SUBBLOCK
+ SbEncInStream_Construct(&p->sb, alloc);
+ #endif
+ SeqInFilter_Construct(&p->filter);
+}
+
+static SRes Lzma2WithFilters_Create(CLzma2WithFilters *p)
+{
+ p->lzma2 = Lzma2Enc_Create(p->alloc, p->bigAlloc);
+ if (p->lzma2 == 0)
+ return SZ_ERROR_MEM;
+ return SZ_OK;
+}
+
+static void Lzma2WithFilters_Free(CLzma2WithFilters *p)
+{
+ SeqInFilter_Free(&p->filter);
+ #ifdef USE_SUBBLOCK
+ SbEncInStream_Free(&p->sb);
+ #endif
+ if (p->lzma2)
+ {
+ Lzma2Enc_Destroy(p->lzma2);
+ p->lzma2 = NULL;
+ }
+}
+
+void XzProps_Init(CXzProps *p)
+{
+ p->lzma2Props = 0;
+ p->filterProps = 0;
+ p->checkId = XZ_CHECK_CRC32;
+}
+
+void XzFilterProps_Init(CXzFilterProps *p)
+{
+ p->id = 0;
+ p->delta = 0;
+ p->ip= 0;
+ p->ipDefined = False;
+}
+
+static SRes Xz_Compress(CXzStream *xz, CLzma2WithFilters *lzmaf,
+ ISeqOutStream *outStream, ISeqInStream *inStream,
+ const CXzProps *props, ICompressProgress *progress)
+{
+ xz->flags = (Byte)props->checkId;
+
+ RINOK(Lzma2Enc_SetProps(lzmaf->lzma2, props->lzma2Props));
+ RINOK(Xz_WriteHeader(xz->flags, outStream));
+
+ {
+ CSeqCheckInStream checkInStream;
+ CSeqSizeOutStream seqSizeOutStream;
+ CXzBlock block;
+ int filterIndex = 0;
+ CXzFilter *filter = NULL;
+ const CXzFilterProps *fp = props->filterProps;
+
+ 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.p.Write = MyWrite;
+ seqSizeOutStream.realStream = outStream;
+ seqSizeOutStream.processed = 0;
+
+ RINOK(XzBlock_WriteHeader(&block, &seqSizeOutStream.p));
+
+ checkInStream.p.Read = SeqCheckInStream_Read;
+ checkInStream.realStream = inStream;
+ SeqCheckInStream_Init(&checkInStream, XzFlags_GetCheckType(xz->flags));
+
+ if (fp)
+ {
+ #ifdef USE_SUBBLOCK
+ if (fp->id == XZ_ID_Subblock)
+ {
+ lzmaf->sb.inStream = &checkInStream.p;
+ RINOK(SbEncInStream_Init(&lzmaf->sb));
+ }
+ else
+ #endif
+ {
+ lzmaf->filter.realStream = &checkInStream.p;
+ RINOK(SeqInFilter_Init(&lzmaf->filter, filter));
+ }
+ }
+
+ {
+ UInt64 packPos = seqSizeOutStream.processed;
+ SRes res = Lzma2Enc_Encode(lzmaf->lzma2, &seqSizeOutStream.p,
+ fp ?
+ #ifdef USE_SUBBLOCK
+ (fp->id == XZ_ID_Subblock) ? &lzmaf->sb.p:
+ #endif
+ &lzmaf->filter.p:
+ &checkInStream.p,
+ progress);
+ RINOK(res);
+ block.unpackSize = checkInStream.processed;
+ block.packSize = seqSizeOutStream.processed - packPos;
+ }
+
+ {
+ unsigned padSize = 0;
+ Byte buf[128];
+ while((((unsigned)block.packSize + padSize) & 3) != 0)
+ buf[padSize++] = 0;
+ SeqCheckInStream_GetDigest(&checkInStream, buf + padSize);
+ RINOK(WriteBytes(&seqSizeOutStream.p, buf, padSize + XzFlags_GetCheckSize(xz->flags)));
+ RINOK(Xz_AddIndexRecord(xz, block.unpackSize, seqSizeOutStream.processed - padSize, &g_Alloc));
+ }
+ }
+ return Xz_WriteFooter(xz, outStream);
+}
+
+SRes Xz_Encode(ISeqOutStream *outStream, ISeqInStream *inStream,
+ const CXzProps *props, ICompressProgress *progress)
+{
+ SRes res;
+ CXzStream xz;
+ CLzma2WithFilters lzmaf;
+ Xz_Construct(&xz);
+ Lzma2WithFilters_Construct(&lzmaf, &g_Alloc, &g_BigAlloc);
+ res = Lzma2WithFilters_Create(&lzmaf);
+ if (res == SZ_OK)
+ res = Xz_Compress(&xz, &lzmaf, outStream, inStream, props, progress);
+ Lzma2WithFilters_Free(&lzmaf);
+ Xz_Free(&xz, &g_Alloc);
+ return res;
+}
+
+SRes Xz_EncodeEmpty(ISeqOutStream *outStream)
+{
+ SRes res;
+ CXzStream xz;
+ Xz_Construct(&xz);
+ res = Xz_WriteHeader(xz.flags, outStream);
+ if (res == SZ_OK)
+ res = Xz_WriteFooter(&xz, outStream);
+ Xz_Free(&xz, &g_Alloc);
+ return res;
+}
diff --git a/lzma/C/XzEnc.h b/lzma/C/XzEnc.h
new file mode 100644
index 0000000..e9cea34
--- /dev/null
+++ b/lzma/C/XzEnc.h
@@ -0,0 +1,39 @@
+/* XzEnc.h -- Xz Encode
+2011-02-07 : Igor Pavlov : Public domain */
+
+#ifndef __XZ_ENC_H
+#define __XZ_ENC_H
+
+#include "Lzma2Enc.h"
+
+#include "Xz.h"
+
+EXTERN_C_BEGIN
+
+typedef struct
+{
+ UInt32 id;
+ UInt32 delta;
+ UInt32 ip;
+ int ipDefined;
+} CXzFilterProps;
+
+void XzFilterProps_Init(CXzFilterProps *p);
+
+typedef struct
+{
+ const CLzma2EncProps *lzma2Props;
+ const CXzFilterProps *filterProps;
+ unsigned checkId;
+} CXzProps;
+
+void XzProps_Init(CXzProps *p);
+
+SRes Xz_Encode(ISeqOutStream *outStream, ISeqInStream *inStream,
+ const CXzProps *props, ICompressProgress *progress);
+
+SRes Xz_EncodeEmpty(ISeqOutStream *outStream);
+
+EXTERN_C_END
+
+#endif
diff --git a/lzma/C/XzIn.c b/lzma/C/XzIn.c
new file mode 100644
index 0000000..c99d71c
--- /dev/null
+++ b/lzma/C/XzIn.c
@@ -0,0 +1,307 @@
+/* XzIn.c - Xz input
+2014-12-30 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include <string.h>
+
+#include "7zCrc.h"
+#include "CpuArch.h"
+#include "Xz.h"
+
+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, Bool *isIndex, UInt32 *headerSizeRes)
+{
+ Byte header[XZ_BLOCK_HEADER_SIZE_MAX];
+ unsigned headerSize;
+ *headerSizeRes = 0;
+ RINOK(SeqInStream_ReadByte(inStream, &header[0]));
+ headerSize = ((unsigned)header[0] << 2) + 4;
+ if (headerSize == 0)
+ {
+ *headerSizeRes = 1;
+ *isIndex = True;
+ return SZ_OK;
+ }
+
+ *isIndex = False;
+ *headerSizeRes = headerSize;
+ RINOK(SeqInStream_Read(inStream, header + 1, headerSize - 1));
+ return XzBlock_Parse(p, header);
+}
+
+#define ADD_SIZE_CHECH(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_CHECH(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_CHECH(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, ISzAlloc *alloc)
+{
+ size_t i, 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)
+ {
+ p->numBlocks = numBlocks;
+ p->numBlocksAllocated = numBlocks;
+ p->blocks = alloc->Alloc(alloc, sizeof(CXzBlockSizes) * numBlocks);
+ if (p->blocks == 0)
+ 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, ISzAlloc *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 = alloc->Alloc(alloc, size);
+ if (buf == 0)
+ return SZ_ERROR_MEM;
+ res = LookInStream_Read2(stream, buf, size, SZ_ERROR_UNSUPPORTED);
+ if (res == SZ_OK)
+ res = Xz_ReadIndex2(p, buf, size, alloc);
+ alloc->Free(alloc, buf);
+ return res;
+}
+
+static SRes SeekFromCur(ILookInStream *inStream, Int64 *res)
+{
+ return inStream->Seek(inStream, res, SZ_SEEK_CUR);
+}
+
+static SRes Xz_ReadBackward(CXzStream *p, ILookInStream *stream, Int64 *startOffset, ISzAlloc *alloc)
+{
+ UInt64 indexSize;
+ Byte buf[XZ_STREAM_FOOTER_SIZE];
+
+ if ((*startOffset & 3) != 0 || *startOffset < XZ_STREAM_FOOTER_SIZE)
+ return SZ_ERROR_NO_ARCHIVE;
+ *startOffset = -XZ_STREAM_FOOTER_SIZE;
+ RINOK(SeekFromCur(stream, startOffset));
+
+ RINOK(LookInStream_Read2(stream, buf, XZ_STREAM_FOOTER_SIZE, SZ_ERROR_NO_ARCHIVE));
+
+ if (memcmp(buf + 10, XZ_FOOTER_SIG, XZ_FOOTER_SIG_SIZE) != 0)
+ {
+ UInt32 total = 0;
+ *startOffset += XZ_STREAM_FOOTER_SIZE;
+ for (;;)
+ {
+ size_t i;
+ #define TEMP_BUF_SIZE (1 << 10)
+ Byte tempBuf[TEMP_BUF_SIZE];
+ if (*startOffset < XZ_STREAM_FOOTER_SIZE || total > (1 << 16))
+ return SZ_ERROR_NO_ARCHIVE;
+ i = (*startOffset > TEMP_BUF_SIZE) ? TEMP_BUF_SIZE : (size_t)*startOffset;
+ total += (UInt32)i;
+ *startOffset = -(Int64)i;
+ RINOK(SeekFromCur(stream, startOffset));
+ RINOK(LookInStream_Read2(stream, tempBuf, i, SZ_ERROR_NO_ARCHIVE));
+ for (; i != 0; i--)
+ if (tempBuf[i - 1] != 0)
+ break;
+ if (i != 0)
+ {
+ if ((i & 3) != 0)
+ return SZ_ERROR_NO_ARCHIVE;
+ *startOffset += i;
+ break;
+ }
+ }
+ if (*startOffset < XZ_STREAM_FOOTER_SIZE)
+ return SZ_ERROR_NO_ARCHIVE;
+ *startOffset -= XZ_STREAM_FOOTER_SIZE;
+ RINOK(stream->Seek(stream, startOffset, SZ_SEEK_SET));
+ RINOK(LookInStream_Read2(stream, buf, XZ_STREAM_FOOTER_SIZE, SZ_ERROR_NO_ARCHIVE));
+ if (memcmp(buf + 10, XZ_FOOTER_SIG, XZ_FOOTER_SIG_SIZE) != 0)
+ 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;
+
+ *startOffset = -(Int64)(indexSize + XZ_STREAM_FOOTER_SIZE);
+ RINOK(SeekFromCur(stream, startOffset));
+
+ RINOK(Xz_ReadIndex(p, stream, indexSize, alloc));
+
+ {
+ UInt64 totalSize = Xz_GetPackSize(p);
+ UInt64 sum = XZ_STREAM_HEADER_SIZE + totalSize + indexSize;
+ if (totalSize == XZ_SIZE_OVERFLOW ||
+ sum >= ((UInt64)1 << 63) ||
+ totalSize >= ((UInt64)1 << 63))
+ return SZ_ERROR_ARCHIVE;
+ *startOffset = -(Int64)sum;
+ RINOK(SeekFromCur(stream, startOffset));
+ }
+ {
+ CXzStreamFlags headerFlags;
+ CSecToRead secToRead;
+ SecToRead_CreateVTable(&secToRead);
+ secToRead.realStream = stream;
+
+ RINOK(Xz_ReadHeader(&headerFlags, &secToRead.s));
+ 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, ISzAlloc *alloc)
+{
+ size_t i;
+ for (i = 0; i < p->num; i++)
+ Xz_Free(&p->streams[i], alloc);
+ alloc->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_CHECH(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_CHECH(size, Xz_GetTotalSize(&p->streams[i]));
+ return size;
+}
+*/
+
+SRes Xzs_ReadBackward(CXzs *p, ILookInStream *stream, Int64 *startOffset, ICompressProgress *progress, ISzAlloc *alloc)
+{
+ Int64 endOffset = 0;
+ RINOK(stream->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 *)alloc->Alloc(alloc, newNum * sizeof(CXzStream));
+ if (data == 0)
+ return SZ_ERROR_MEM;
+ p->numAllocated = newNum;
+ if (p->num != 0)
+ memcpy(data, p->streams, p->num * sizeof(CXzStream));
+ alloc->Free(alloc, p->streams);
+ p->streams = (CXzStream *)data;
+ }
+ p->streams[p->num++] = st;
+ if (*startOffset == 0)
+ break;
+ RINOK(stream->Seek(stream, startOffset, SZ_SEEK_SET));
+ if (progress && progress->Progress(progress, endOffset - *startOffset, (UInt64)(Int64)-1) != SZ_OK)
+ return SZ_ERROR_PROGRESS;
+ }
+ return SZ_OK;
+}
diff --git a/lzma/CPP/7zip/7zip.mak b/lzma/CPP/7zip/7zip.mak
new file mode 100644
index 0000000..7fec27c
--- /dev/null
+++ b/lzma/CPP/7zip/7zip.mak
@@ -0,0 +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"
diff --git a/lzma/CPP/7zip/Aes.mak b/lzma/CPP/7zip/Aes.mak
new file mode 100644
index 0000000..7ce28cf
--- /dev/null
+++ b/lzma/CPP/7zip/Aes.mak
@@ -0,0 +1,7 @@
+C_OBJS = $(C_OBJS) \
+ $O\Aes.obj
+
+!IF "$(CPU)" != "IA64" && "$(CPU)" != "MIPS" && "$(CPU)" != "ARM"
+ASM_OBJS = $(ASM_OBJS) \
+ $O\AesOpt.obj
+!ENDIF
diff --git a/lzma/CPP/7zip/Archive/7z/7zCompressionMode.cpp b/lzma/CPP/7zip/Archive/7z/7zCompressionMode.cpp
new file mode 100644
index 0000000..232c638
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/7z/7zCompressionMode.cpp
@@ -0,0 +1,3 @@
+// CompressionMethod.cpp
+
+#include "StdAfx.h"
diff --git a/lzma/CPP/7zip/Archive/7z/7zCompressionMode.h b/lzma/CPP/7zip/Archive/7z/7zCompressionMode.h
new file mode 100644
index 0000000..3301b93
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/7z/7zCompressionMode.h
@@ -0,0 +1,49 @@
+// 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 CProps
+{
+ CMethodId Id;
+ UInt32 NumInStreams;
+ UInt32 NumOutStreams;
+
+ bool IsSimpleCoder() const { return (NumInStreams == 1) && (NumOutStreams == 1); }
+};
+
+struct CBind
+{
+ UInt32 InCoder;
+ UInt32 InStream;
+ UInt32 OutCoder;
+ UInt32 OutStream;
+};
+
+struct CCompressionMethodMode
+{
+ CObjectVector<CMethodFull> Methods;
+ CRecordVector<CBind> Binds;
+ #ifndef _7ZIP_ST
+ UInt32 NumThreads;
+ #endif
+ bool PasswordIsDefined;
+ UString Password;
+
+ bool IsEmpty() const { return (Methods.IsEmpty() && !PasswordIsDefined); }
+ CCompressionMethodMode(): PasswordIsDefined(false)
+ #ifndef _7ZIP_ST
+ , NumThreads(1)
+ #endif
+ {}
+};
+
+}}
+
+#endif
diff --git a/lzma/CPP/7zip/Archive/7z/7zDecode.cpp b/lzma/CPP/7zip/Archive/7z/7zDecode.cpp
new file mode 100644
index 0000000..d58fb02
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/7z/7zDecode.cpp
@@ -0,0 +1,343 @@
+// 7zDecode.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/LimitedStreams.h"
+#include "../../Common/LockedStream.h"
+#include "../../Common/ProgressUtils.h"
+#include "../../Common/StreamObjects.h"
+
+#include "7zDecode.h"
+
+namespace NArchive {
+namespace N7z {
+
+static void ConvertFolderItemInfoToBindInfo(const CFolder &folder,
+ CBindInfoEx &bindInfo)
+{
+ bindInfo.Clear();
+ bindInfo.BindPairs.ClearAndSetSize(folder.BindPairs.Size());
+ unsigned i;
+ for (i = 0; i < folder.BindPairs.Size(); i++)
+ {
+ NCoderMixer::CBindPair &bindPair = bindInfo.BindPairs[i];
+ bindPair.InIndex = (UInt32)folder.BindPairs[i].InIndex;
+ bindPair.OutIndex = (UInt32)folder.BindPairs[i].OutIndex;
+ }
+
+ bindInfo.Coders.ClearAndSetSize(folder.Coders.Size());
+ bindInfo.CoderMethodIDs.ClearAndSetSize(folder.Coders.Size());
+
+ UInt32 outStreamIndex = 0;
+ for (i = 0; i < folder.Coders.Size(); i++)
+ {
+ NCoderMixer::CCoderStreamsInfo &coderStreamsInfo = bindInfo.Coders[i];
+ const CCoderInfo &coderInfo = folder.Coders[i];
+ coderStreamsInfo.NumInStreams = (UInt32)coderInfo.NumInStreams;
+ coderStreamsInfo.NumOutStreams = (UInt32)coderInfo.NumOutStreams;
+ bindInfo.CoderMethodIDs[i] = coderInfo.MethodID;
+ for (UInt32 j = 0; j < coderStreamsInfo.NumOutStreams; j++, outStreamIndex++)
+ if (folder.FindBindPairForOutStream(outStreamIndex) < 0)
+ bindInfo.OutStreams.Add(outStreamIndex);
+ }
+ bindInfo.InStreams.ClearAndSetSize(folder.PackStreams.Size());
+ for (i = 0; i < folder.PackStreams.Size(); i++)
+ bindInfo.InStreams[i] = (UInt32)folder.PackStreams[i];
+}
+
+static bool AreCodersEqual(const NCoderMixer::CCoderStreamsInfo &a1,
+ const NCoderMixer::CCoderStreamsInfo &a2)
+{
+ return (a1.NumInStreams == a2.NumInStreams) &&
+ (a1.NumOutStreams == a2.NumOutStreams);
+}
+
+static bool AreBindPairsEqual(const NCoderMixer::CBindPair &a1, const NCoderMixer::CBindPair &a2)
+{
+ return (a1.InIndex == a2.InIndex) &&
+ (a1.OutIndex == a2.OutIndex);
+}
+
+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.BindPairs.Size() != a2.BindPairs.Size())
+ return false;
+ for (i = 0; i < a1.BindPairs.Size(); i++)
+ if (!AreBindPairsEqual(a1.BindPairs[i], a2.BindPairs[i]))
+ return false;
+ for (i = 0; i < a1.CoderMethodIDs.Size(); i++)
+ if (a1.CoderMethodIDs[i] != a2.CoderMethodIDs[i])
+ return false;
+ if (a1.InStreams.Size() != a2.InStreams.Size())
+ return false;
+ if (a1.OutStreams.Size() != a2.OutStreams.Size())
+ return false;
+ return true;
+}
+
+CDecoder::CDecoder(bool multiThread)
+{
+ #ifndef _ST_MODE
+ multiThread = true;
+ #endif
+ _multiThread = multiThread;
+ _bindInfoExPrevIsDefined = false;
+}
+
+HRESULT CDecoder::Decode(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ IInStream *inStream,
+ UInt64 startPos,
+ const CFolders &folders, int folderIndex,
+ ISequentialOutStream *outStream,
+ ICompressProgressInfo *compressProgress
+ _7Z_DECODER_CRYPRO_VARS_DECL
+ #if !defined(_7ZIP_ST) && !defined(_SFX)
+ , bool mtMode, UInt32 numThreads
+ #endif
+ )
+{
+ const UInt64 *packPositions = &folders.PackPositions[folders.FoStartPackStreamIndex[folderIndex]];
+ CFolder folderInfo;
+ folders.ParseFolderInfo(folderIndex, folderInfo);
+
+ if (!folderInfo.CheckStructure(folders.GetNumFolderUnpackSizes(folderIndex)))
+ return E_NOTIMPL;
+
+ /*
+ We don't need to init isEncrypted and passwordIsDefined
+ We must upgrade them only
+ #ifndef _NO_CRYPTO
+ isEncrypted = false;
+ passwordIsDefined = false;
+ #endif
+ */
+
+ CObjectVector< CMyComPtr<ISequentialInStream> > inStreams;
+
+ CLockedInStream lockedInStream;
+ lockedInStream.Init(inStream);
+
+ for (unsigned j = 0; j < folderInfo.PackStreams.Size(); j++)
+ {
+ CLockedSequentialInStreamImp *lockedStreamImpSpec = new CLockedSequentialInStreamImp;
+ CMyComPtr<ISequentialInStream> lockedStreamImp = lockedStreamImpSpec;
+ lockedStreamImpSpec->Init(&lockedInStream, startPos + packPositions[j]);
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStream = streamSpec;
+ streamSpec->SetStream(lockedStreamImp);
+ streamSpec->Init(packPositions[j + 1] - packPositions[j]);
+ inStreams.Add(inStream);
+ }
+
+ unsigned numCoders = folderInfo.Coders.Size();
+
+ CBindInfoEx bindInfo;
+ ConvertFolderItemInfoToBindInfo(folderInfo, bindInfo);
+ bool createNewCoders;
+ if (!_bindInfoExPrevIsDefined)
+ createNewCoders = true;
+ else
+ createNewCoders = !AreBindInfoExEqual(bindInfo, _bindInfoExPrev);
+ if (createNewCoders)
+ {
+ unsigned i;
+ _decoders.Clear();
+ // _decoders2.Clear();
+
+ _mixerCoder.Release();
+
+ if (_multiThread)
+ {
+ _mixerCoderMTSpec = new NCoderMixer::CCoderMixer2MT;
+ _mixerCoder = _mixerCoderMTSpec;
+ _mixerCoderCommon = _mixerCoderMTSpec;
+ }
+ else
+ {
+ #ifdef _ST_MODE
+ _mixerCoderSTSpec = new NCoderMixer::CCoderMixer2ST;
+ _mixerCoder = _mixerCoderSTSpec;
+ _mixerCoderCommon = _mixerCoderSTSpec;
+ #endif
+ }
+ RINOK(_mixerCoderCommon->SetBindInfo(bindInfo));
+
+ for (i = 0; i < numCoders; i++)
+ {
+ const CCoderInfo &coderInfo = folderInfo.Coders[i];
+
+
+ CMyComPtr<ICompressCoder> decoder;
+ CMyComPtr<ICompressCoder2> decoder2;
+ RINOK(CreateCoder(
+ EXTERNAL_CODECS_LOC_VARS
+ coderInfo.MethodID, decoder, decoder2, false));
+ CMyComPtr<IUnknown> decoderUnknown;
+ if (coderInfo.IsSimpleCoder())
+ {
+ if (decoder == 0)
+ return E_NOTIMPL;
+
+ decoderUnknown = (IUnknown *)decoder;
+
+ if (_multiThread)
+ _mixerCoderMTSpec->AddCoder(decoder);
+ #ifdef _ST_MODE
+ else
+ _mixerCoderSTSpec->AddCoder(decoder, false);
+ #endif
+ }
+ else
+ {
+ if (decoder2 == 0)
+ return E_NOTIMPL;
+ decoderUnknown = (IUnknown *)decoder2;
+ if (_multiThread)
+ _mixerCoderMTSpec->AddCoder2(decoder2);
+ #ifdef _ST_MODE
+ else
+ _mixerCoderSTSpec->AddCoder2(decoder2, false);
+ #endif
+ }
+ _decoders.Add(decoderUnknown);
+ #ifdef EXTERNAL_CODECS
+ CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo;
+ decoderUnknown.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo);
+ if (setCompressCodecsInfo)
+ {
+ RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(__externalCodecs->GetCodecs));
+ }
+ #endif
+ }
+ _bindInfoExPrev = bindInfo;
+ _bindInfoExPrevIsDefined = true;
+ }
+ unsigned i;
+ _mixerCoderCommon->ReInit();
+
+ UInt32 packStreamIndex = 0;
+ UInt32 unpackStreamIndexStart = folders.FoToCoderUnpackSizes[folderIndex];
+ UInt32 unpackStreamIndex = unpackStreamIndexStart;
+ UInt32 coderIndex = 0;
+ // UInt32 coder2Index = 0;
+
+ for (i = 0; i < numCoders; i++)
+ {
+ const CCoderInfo &coderInfo = folderInfo.Coders[i];
+ CMyComPtr<IUnknown> &decoder = _decoders[coderIndex];
+
+ {
+ CMyComPtr<ICompressSetDecoderProperties2> setDecoderProperties;
+ decoder.QueryInterface(IID_ICompressSetDecoderProperties2, &setDecoderProperties);
+ if (setDecoderProperties)
+ {
+ const CByteBuffer &props = coderInfo.Props;
+ size_t size = props.Size();
+ if (size > 0xFFFFFFFF)
+ return E_NOTIMPL;
+ // if (size > 0)
+ {
+ RINOK(setDecoderProperties->SetDecoderProperties2((const Byte *)props, (UInt32)size));
+ }
+ }
+ }
+
+ #if !defined(_7ZIP_ST) && !defined(_SFX)
+ if (mtMode)
+ {
+ CMyComPtr<ICompressSetCoderMt> setCoderMt;
+ decoder.QueryInterface(IID_ICompressSetCoderMt, &setCoderMt);
+ if (setCoderMt)
+ {
+ RINOK(setCoderMt->SetNumberOfThreads(numThreads));
+ }
+ }
+ #endif
+
+ #ifndef _NO_CRYPTO
+ {
+ CMyComPtr<ICryptoSetPassword> cryptoSetPassword;
+ decoder.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword);
+ if (cryptoSetPassword)
+ {
+ isEncrypted = true;
+ if (!getTextPassword)
+ return E_NOTIMPL;
+ CMyComBSTR passwordBSTR;
+ RINOK(getTextPassword->CryptoGetTextPassword(&passwordBSTR));
+ passwordIsDefined = true;
+ size_t len = 0;
+ if (passwordBSTR)
+ len = MyStringLen((BSTR)passwordBSTR);
+ CByteBuffer buffer(len * 2);
+ for (size_t i = 0; i < len; i++)
+ {
+ wchar_t c = passwordBSTR[i];
+ ((Byte *)buffer)[i * 2] = (Byte)c;
+ ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8);
+ }
+ RINOK(cryptoSetPassword->CryptoSetPassword((const Byte *)buffer, (UInt32)buffer.Size()));
+ }
+ }
+ #endif
+
+ coderIndex++;
+
+ UInt32 numInStreams = (UInt32)coderInfo.NumInStreams;
+ UInt32 numOutStreams = (UInt32)coderInfo.NumOutStreams;
+ CObjArray<UInt64> packSizes(numInStreams);
+ CObjArray<const UInt64 *> packSizesPointers(numInStreams);
+ CObjArray<const UInt64 *> unpackSizesPointers(numOutStreams);
+ UInt32 j;
+
+ for (j = 0; j < numOutStreams; j++, unpackStreamIndex++)
+ unpackSizesPointers[j] = &folders.CoderUnpackSizes[unpackStreamIndex];
+
+ for (j = 0; j < numInStreams; j++, packStreamIndex++)
+ {
+ int bindPairIndex = folderInfo.FindBindPairForInStream(packStreamIndex);
+ if (bindPairIndex >= 0)
+ packSizesPointers[j] = &folders.CoderUnpackSizes[unpackStreamIndexStart + (UInt32)folderInfo.BindPairs[bindPairIndex].OutIndex];
+ else
+ {
+ int index = folderInfo.FindPackStreamArrayIndex(packStreamIndex);
+ if (index < 0)
+ return S_FALSE; // check it
+ packSizes[j] = packPositions[index + 1] - packPositions[index];
+ packSizesPointers[j] = &packSizes[j];
+ }
+ }
+
+ _mixerCoderCommon->SetCoderInfo(i, packSizesPointers, unpackSizesPointers);
+ }
+ UInt32 mainCoder, temp;
+ bindInfo.FindOutStream(bindInfo.OutStreams[0], mainCoder, temp);
+
+ if (_multiThread)
+ _mixerCoderMTSpec->SetProgressCoderIndex(mainCoder);
+ /*
+ else
+ _mixerCoderSTSpec->SetProgressCoderIndex(mainCoder);;
+ */
+
+ if (numCoders == 0)
+ return 0;
+ unsigned num = inStreams.Size();
+ CObjArray<ISequentialInStream *> inStreamPointers(num);
+ for (i = 0; i < num; i++)
+ inStreamPointers[i] = inStreams[i];
+ ISequentialOutStream *outStreamPointer = outStream;
+ return _mixerCoder->Code(
+ inStreamPointers, NULL, num,
+ &outStreamPointer, NULL, 1,
+ compressProgress);
+}
+
+}}
diff --git a/lzma/CPP/7zip/Archive/7z/7zDecode.h b/lzma/CPP/7zip/Archive/7z/7zDecode.h
new file mode 100644
index 0000000..f27170d
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/7z/7zDecode.h
@@ -0,0 +1,65 @@
+// 7zDecode.h
+
+#ifndef __7Z_DECODE_H
+#define __7Z_DECODE_H
+
+#include "../../IStream.h"
+#include "../../IPassword.h"
+
+#include "../Common/CoderMixer2.h"
+#include "../Common/CoderMixer2MT.h"
+#ifdef _ST_MODE
+#include "../Common/CoderMixer2ST.h"
+#endif
+
+#include "../../Common/CreateCoder.h"
+
+#include "7zIn.h"
+
+namespace NArchive {
+namespace N7z {
+
+struct CBindInfoEx: public NCoderMixer::CBindInfo
+{
+ CRecordVector<CMethodId> CoderMethodIDs;
+ void Clear()
+ {
+ CBindInfo::Clear();
+ CoderMethodIDs.Clear();
+ }
+};
+
+class CDecoder
+{
+ bool _bindInfoExPrevIsDefined;
+ CBindInfoEx _bindInfoExPrev;
+
+ bool _multiThread;
+ #ifdef _ST_MODE
+ NCoderMixer::CCoderMixer2ST *_mixerCoderSTSpec;
+ #endif
+ NCoderMixer::CCoderMixer2MT *_mixerCoderMTSpec;
+ NCoderMixer::CCoderMixer2 *_mixerCoderCommon;
+
+ CMyComPtr<ICompressCoder2> _mixerCoder;
+ CObjectVector<CMyComPtr<IUnknown> > _decoders;
+ // CObjectVector<CMyComPtr<ICompressCoder2> > _decoders2;
+public:
+ CDecoder(bool multiThread);
+ HRESULT Decode(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ IInStream *inStream,
+ UInt64 startPos,
+ const CFolders &folders, int folderIndex,
+ ISequentialOutStream *outStream,
+ ICompressProgressInfo *compressProgress
+ _7Z_DECODER_CRYPRO_VARS_DECL
+ #if !defined(_7ZIP_ST) && !defined(_SFX)
+ , bool mtMode, UInt32 numThreads
+ #endif
+ );
+};
+
+}}
+
+#endif
diff --git a/lzma/CPP/7zip/Archive/7z/7zEncode.cpp b/lzma/CPP/7zip/Archive/7z/7zEncode.cpp
new file mode 100644
index 0000000..365489c
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/7z/7zEncode.cpp
@@ -0,0 +1,464 @@
+// 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"
+
+static const UInt64 k_Delta = 0x03;
+static const UInt64 k_BCJ = 0x03030103;
+static const UInt64 k_BCJ2 = 0x0303011B;
+
+namespace NArchive {
+namespace N7z {
+
+static void ConvertBindInfoToFolderItemInfo(const NCoderMixer::CBindInfo &bindInfo,
+ const CRecordVector<CMethodId> decompressionMethods,
+ CFolder &folder)
+{
+ // bindInfo.CoderMethodIDs.Clear();
+ // folder.OutStreams.Clear();
+ folder.BindPairs.SetSize(bindInfo.BindPairs.Size());
+ unsigned i;
+ for (i = 0; i < bindInfo.BindPairs.Size(); i++)
+ {
+ CBindPair &bp = folder.BindPairs[i];
+ const NCoderMixer::CBindPair &mixerBp = bindInfo.BindPairs[i];
+ bp.InIndex = mixerBp.InIndex;
+ bp.OutIndex = mixerBp.OutIndex;
+ }
+ folder.Coders.SetSize(bindInfo.Coders.Size());
+ for (i = 0; i < bindInfo.Coders.Size(); i++)
+ {
+ CCoderInfo &coderInfo = folder.Coders[i];
+ const NCoderMixer::CCoderStreamsInfo &coderStreamsInfo = bindInfo.Coders[i];
+ coderInfo.NumInStreams = coderStreamsInfo.NumInStreams;
+ coderInfo.NumOutStreams = coderStreamsInfo.NumOutStreams;
+ coderInfo.MethodID = decompressionMethods[i];
+ // coderInfo.Props can be nonFree;
+ }
+ folder.PackStreams.SetSize(bindInfo.InStreams.Size());
+ for (i = 0; i < bindInfo.InStreams.Size(); i++)
+ folder.PackStreams[i] = bindInfo.InStreams[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;
+}
+
+HRESULT CEncoder::CreateMixerCoder(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ const UInt64 *inSizeForReduce)
+{
+ _mixerCoderSpec = new NCoderMixer::CCoderMixer2MT;
+ _mixerCoder = _mixerCoderSpec;
+ RINOK(_mixerCoderSpec->SetBindInfo(_bindInfo));
+ FOR_VECTOR (i, _options.Methods)
+ {
+ const CMethodFull &methodFull = _options.Methods[i];
+ CCoderInfo &encodingInfo = _codersInfo.AddNew();
+ encodingInfo.MethodID = methodFull.Id;
+ CMyComPtr<ICompressCoder> encoder;
+ CMyComPtr<ICompressCoder2> encoder2;
+
+
+ RINOK(CreateCoder(
+ EXTERNAL_CODECS_LOC_VARS
+ methodFull.Id, encoder, encoder2, true));
+
+ if (!encoder && !encoder2)
+ return E_FAIL;
+
+ CMyComPtr<IUnknown> encoderCommon = encoder ? (IUnknown *)encoder : (IUnknown *)encoder2;
+
+ #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();
+ }
+ */
+
+ #ifdef EXTERNAL_CODECS
+ CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo;
+ encoderCommon.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo);
+ if (setCompressCodecsInfo)
+ {
+ RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(__externalCodecs->GetCodecs));
+ }
+ #endif
+
+ CMyComPtr<ICryptoSetPassword> cryptoSetPassword;
+ encoderCommon.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword);
+
+ if (cryptoSetPassword)
+ {
+ const UInt32 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, sizeInBytes));
+ }
+
+ if (encoder)
+ _mixerCoderSpec->AddCoder(encoder);
+ else
+ _mixerCoderSpec->AddCoder2(encoder2);
+ }
+ return S_OK;
+}
+
+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 (!_mixerCoderSpec)
+ {
+ RINOK(CreateMixerCoder(EXTERNAL_CODECS_LOC_VARS inSizeForReduce));
+ }
+ _mixerCoderSpec->ReInit();
+ // _mixerCoderSpec->SetCoderInfo(0, NULL, NULL, progress);
+
+ CObjectVector<CInOutTempBuffer> inOutTempBuffers;
+ CObjectVector<CSequentialOutTempBufferImp *> tempBufferSpecs;
+ CObjectVector<CMyComPtr<ISequentialOutStream> > tempBuffers;
+ unsigned numMethods = _bindInfo.Coders.Size();
+ unsigned i;
+ for (i = 1; i < _bindInfo.OutStreams.Size(); i++)
+ {
+ CInOutTempBuffer &iotb = inOutTempBuffers.AddNew();
+ iotb.Create();
+ iotb.InitWriting();
+ }
+ for (i = 1; i < _bindInfo.OutStreams.Size(); i++)
+ {
+ CSequentialOutTempBufferImp *tempBufferSpec = new CSequentialOutTempBufferImp;
+ CMyComPtr<ISequentialOutStream> tempBuffer = tempBufferSpec;
+ tempBufferSpec->Init(&inOutTempBuffers[i - 1]);
+ tempBuffers.Add(tempBuffer);
+ tempBufferSpecs.Add(tempBufferSpec);
+ }
+
+ for (i = 0; i < numMethods; i++)
+ _mixerCoderSpec->SetCoderInfo(i, NULL, NULL);
+
+ if (_bindInfo.InStreams.IsEmpty())
+ return E_FAIL;
+ UInt32 mainCoderIndex, mainStreamIndex;
+ _bindInfo.FindInStream(_bindInfo.InStreams[0], mainCoderIndex, mainStreamIndex);
+
+ if (inStreamSize)
+ {
+ CRecordVector<const UInt64 *> sizePointers;
+ for (UInt32 i = 0; i < _bindInfo.Coders[mainCoderIndex].NumInStreams; i++)
+ if (i == mainStreamIndex)
+ sizePointers.Add(inStreamSize);
+ else
+ sizePointers.Add(NULL);
+ _mixerCoderSpec->SetCoderInfo(mainCoderIndex, &sizePointers.Front(), NULL);
+ }
+
+
+ // UInt64 outStreamStartPos;
+ // RINOK(stream->Seek(0, STREAM_SEEK_CUR, &outStreamStartPos));
+
+ CSequentialInStreamSizeCount2 *inStreamSizeCountSpec = new CSequentialInStreamSizeCount2;
+ CMyComPtr<ISequentialInStream> inStreamSizeCount = inStreamSizeCountSpec;
+ CSequentialOutStreamSizeCount *outStreamSizeCountSpec = NULL;
+ CMyComPtr<ISequentialOutStream> outStreamSizeCount;
+
+ inStreamSizeCountSpec->Init(inStream);
+
+ CRecordVector<ISequentialInStream *> inStreamPointers;
+ CRecordVector<ISequentialOutStream *> outStreamPointers;
+ inStreamPointers.Add(inStreamSizeCount);
+
+ if (_bindInfo.OutStreams.Size() != 0)
+ {
+ outStreamSizeCountSpec = new CSequentialOutStreamSizeCount;
+ outStreamSizeCount = outStreamSizeCountSpec;
+ outStreamSizeCountSpec->SetStream(outStream);
+ outStreamSizeCountSpec->Init();
+ outStreamPointers.Add(outStreamSizeCount);
+ }
+
+ for (i = 1; i < _bindInfo.OutStreams.Size(); i++)
+ outStreamPointers.Add(tempBuffers[i - 1]);
+
+ for (i = 0; i < _codersInfo.Size(); i++)
+ {
+ CCoderInfo &encodingInfo = _codersInfo[i];
+
+ CMyComPtr<ICryptoResetInitVector> resetInitVector;
+ _mixerCoderSpec->_coders[i].QueryInterface(IID_ICryptoResetInitVector, (void **)&resetInitVector);
+ if (resetInitVector)
+ {
+ resetInitVector->ResetInitVector();
+ }
+
+ CMyComPtr<ICompressWriteCoderProperties> writeCoderProperties;
+ _mixerCoderSpec->_coders[i].QueryInterface(IID_ICompressWriteCoderProperties, (void **)&writeCoderProperties);
+ if (writeCoderProperties)
+ {
+ CDynBufSeqOutStream *outStreamSpec = new CDynBufSeqOutStream;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+ outStreamSpec->Init();
+ writeCoderProperties->WriteCoderProperties(outStream);
+ outStreamSpec->CopyToBuffer(encodingInfo.Props);
+ }
+ }
+
+ UInt32 progressIndex = mainCoderIndex;
+
+ for (i = 0; i + 1 < _codersInfo.Size(); i++)
+ {
+ UInt64 m = _codersInfo[i].MethodID;
+ if (m == k_Delta || m == k_BCJ || m == k_BCJ2)
+ progressIndex = i + 1;
+ }
+
+ _mixerCoderSpec->SetProgressCoderIndex(progressIndex);
+
+ RINOK(_mixerCoder->Code(&inStreamPointers.Front(), NULL, 1,
+ &outStreamPointers.Front(), NULL, outStreamPointers.Size(), compressProgress));
+
+ ConvertBindInfoToFolderItemInfo(_decompressBindInfo, _decompressionMethods, folderItem);
+
+ if (_bindInfo.OutStreams.Size() != 0)
+ packSizes.Add(outStreamSizeCountSpec->GetSize());
+
+ for (i = 1; i < _bindInfo.OutStreams.Size(); i++)
+ {
+ CInOutTempBuffer &inOutTempBuffer = inOutTempBuffers[i - 1];
+ RINOK(inOutTempBuffer.WriteToStream(outStream));
+ packSizes.Add(inOutTempBuffer.GetDataSize());
+ }
+
+ unpackSize = 0;
+ for (i = 0; i < (int)_bindReverseConverter->NumSrcInStreams; i++)
+ {
+ int binder = _bindInfo.FindBinderForInStream(
+ _bindReverseConverter->DestOutToSrcInMap[i]);
+ UInt64 streamSize;
+ if (binder < 0)
+ {
+ streamSize = inStreamSizeCountSpec->GetSize();
+ unpackSize = streamSize;
+ }
+ else
+ streamSize = _mixerCoderSpec->GetWriteProcessedSize(binder);
+ coderUnpackSizes.Add(streamSize);
+ }
+ for (i = 0; i < numMethods; i++)
+ folderItem.Coders[numMethods - 1 - i].Props = _codersInfo[i].Props;
+ return S_OK;
+}
+
+
+CEncoder::CEncoder(const CCompressionMethodMode &options):
+ _bindReverseConverter(0),
+ _constructed(false)
+{
+ if (options.IsEmpty())
+ throw 1;
+
+ _options = options;
+ _mixerCoderSpec = 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.Binds.IsEmpty())
+ throw 1;
+ NCoderMixer::CCoderStreamsInfo coderStreamsInfo;
+ CMethodFull method;
+
+ method.NumInStreams = 1;
+ method.NumOutStreams = 1;
+ coderStreamsInfo.NumInStreams = 1;
+ coderStreamsInfo.NumOutStreams = 1;
+ method.Id = k_AES;
+
+ _options.Methods.Add(method);
+ _bindInfo.Coders.Add(coderStreamsInfo);
+
+ _bindInfo.InStreams.Add(0);
+ _bindInfo.OutStreams.Add(0);
+ }
+ else
+ {
+
+ UInt32 numInStreams = 0, numOutStreams = 0;
+ unsigned i;
+ for (i = 0; i < _options.Methods.Size(); i++)
+ {
+ const CMethodFull &methodFull = _options.Methods[i];
+ NCoderMixer::CCoderStreamsInfo coderStreamsInfo;
+ coderStreamsInfo.NumInStreams = methodFull.NumOutStreams;
+ coderStreamsInfo.NumOutStreams = methodFull.NumInStreams;
+ if (_options.Binds.IsEmpty())
+ {
+ if (i < _options.Methods.Size() - 1)
+ {
+ NCoderMixer::CBindPair bindPair;
+ bindPair.InIndex = numInStreams + coderStreamsInfo.NumInStreams;
+ bindPair.OutIndex = numOutStreams;
+ _bindInfo.BindPairs.Add(bindPair);
+ }
+ else if (coderStreamsInfo.NumOutStreams != 0)
+ _bindInfo.OutStreams.Insert(0, numOutStreams);
+ for (UInt32 j = 1; j < coderStreamsInfo.NumOutStreams; j++)
+ _bindInfo.OutStreams.Add(numOutStreams + j);
+ }
+
+ numInStreams += coderStreamsInfo.NumInStreams;
+ numOutStreams += coderStreamsInfo.NumOutStreams;
+
+ _bindInfo.Coders.Add(coderStreamsInfo);
+ }
+
+ if (!_options.Binds.IsEmpty())
+ {
+ for (i = 0; i < _options.Binds.Size(); i++)
+ {
+ NCoderMixer::CBindPair bindPair;
+ const CBind &bind = _options.Binds[i];
+ bindPair.InIndex = _bindInfo.GetCoderInStreamIndex(bind.InCoder) + bind.InStream;
+ bindPair.OutIndex = _bindInfo.GetCoderOutStreamIndex(bind.OutCoder) + bind.OutStream;
+ _bindInfo.BindPairs.Add(bindPair);
+ }
+ for (i = 0; i < (int)numOutStreams; i++)
+ if (_bindInfo.FindBinderForOutStream(i) == -1)
+ _bindInfo.OutStreams.Add(i);
+ }
+
+ for (i = 0; i < (int)numInStreams; i++)
+ if (_bindInfo.FindBinderForInStream(i) == -1)
+ _bindInfo.InStreams.Add(i);
+
+ if (_bindInfo.InStreams.IsEmpty())
+ throw 1; // this is error
+
+ // Make main stream first in list
+ int inIndex = _bindInfo.InStreams[0];
+ for (;;)
+ {
+ UInt32 coderIndex, coderStreamIndex;
+ _bindInfo.FindInStream(inIndex, coderIndex, coderStreamIndex);
+ UInt32 outIndex = _bindInfo.GetCoderOutStreamIndex(coderIndex);
+ int binder = _bindInfo.FindBinderForOutStream(outIndex);
+ if (binder >= 0)
+ {
+ inIndex = _bindInfo.BindPairs[binder].InIndex;
+ continue;
+ }
+ for (i = 0; i < _bindInfo.OutStreams.Size(); i++)
+ if (_bindInfo.OutStreams[i] == outIndex)
+ {
+ _bindInfo.OutStreams.Delete(i);
+ _bindInfo.OutStreams.Insert(0, outIndex);
+ break;
+ }
+ break;
+ }
+
+ if (_options.PasswordIsDefined)
+ {
+ unsigned numCryptoStreams = _bindInfo.OutStreams.Size();
+
+ for (i = 0; i < numCryptoStreams; i++)
+ {
+ NCoderMixer::CBindPair bindPair;
+ bindPair.InIndex = numInStreams + i;
+ bindPair.OutIndex = _bindInfo.OutStreams[i];
+ _bindInfo.BindPairs.Add(bindPair);
+ }
+ _bindInfo.OutStreams.Clear();
+
+ /*
+ if (numCryptoStreams == 0)
+ numCryptoStreams = 1;
+ */
+
+ for (i = 0; i < numCryptoStreams; i++)
+ {
+ NCoderMixer::CCoderStreamsInfo coderStreamsInfo;
+ CMethodFull method;
+ method.NumInStreams = 1;
+ method.NumOutStreams = 1;
+ coderStreamsInfo.NumInStreams = method.NumOutStreams;
+ coderStreamsInfo.NumOutStreams = method.NumInStreams;
+ method.Id = k_AES;
+
+ _options.Methods.Add(method);
+ _bindInfo.Coders.Add(coderStreamsInfo);
+ _bindInfo.OutStreams.Add(numOutStreams + i);
+ }
+ }
+
+ }
+
+ for (int i = _options.Methods.Size() - 1; i >= 0; i--)
+ {
+ const CMethodFull &methodFull = _options.Methods[i];
+ _decompressionMethods.Add(methodFull.Id);
+ }
+
+ _bindReverseConverter = new NCoderMixer::CBindReverseConverter(_bindInfo);
+ _bindReverseConverter->CreateReverseBindInfo(_decompressBindInfo);
+ _constructed = true;
+ return S_OK;
+}
+
+CEncoder::~CEncoder()
+{
+ delete _bindReverseConverter;
+}
+
+}}
diff --git a/lzma/CPP/7zip/Archive/7z/7zEncode.h b/lzma/CPP/7zip/Archive/7z/7zEncode.h
new file mode 100644
index 0000000..0f28cfb
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/7z/7zEncode.h
@@ -0,0 +1,57 @@
+// 7zEncode.h
+
+#ifndef __7Z_ENCODE_H
+#define __7Z_ENCODE_H
+
+// #include "../../Common/StreamObjects.h"
+
+#include "7zCompressionMode.h"
+
+#include "../Common/CoderMixer2.h"
+#include "../Common/CoderMixer2MT.h"
+#ifdef _ST_MODE
+#include "../Common/CoderMixer2ST.h"
+#endif
+#include "7zItem.h"
+
+#include "../../Common/CreateCoder.h"
+
+namespace NArchive {
+namespace N7z {
+
+class CEncoder
+{
+ NCoderMixer::CCoderMixer2MT *_mixerCoderSpec;
+ CMyComPtr<ICompressCoder2> _mixerCoder;
+
+ CObjectVector<CCoderInfo> _codersInfo;
+
+ CCompressionMethodMode _options;
+ NCoderMixer::CBindInfo _bindInfo;
+ NCoderMixer::CBindInfo _decompressBindInfo;
+ NCoderMixer::CBindReverseConverter *_bindReverseConverter;
+ CRecordVector<CMethodId> _decompressionMethods;
+
+ 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
diff --git a/lzma/CPP/7zip/Archive/7z/7zExtract.cpp b/lzma/CPP/7zip/Archive/7z/7zExtract.cpp
new file mode 100644
index 0000000..9310762
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/7z/7zExtract.cpp
@@ -0,0 +1,262 @@
+// 7zExtract.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/ComTry.h"
+
+#include "../../Common/ProgressUtils.h"
+
+#include "7zDecode.h"
+// #include "7z1Decode.h"
+#include "7zFolderOutStream.h"
+#include "7zHandler.h"
+
+namespace NArchive {
+namespace N7z {
+
+struct CExtractFolderInfo
+{
+ #ifdef _7Z_VOL
+ int VolumeIndex;
+ #endif
+ CNum FileIndex;
+ CNum FolderIndex;
+ CBoolVector ExtractStatuses;
+ UInt64 UnpackSize;
+ CExtractFolderInfo(
+ #ifdef _7Z_VOL
+ int volumeIndex,
+ #endif
+ CNum fileIndex, CNum folderIndex):
+ #ifdef _7Z_VOL
+ VolumeIndex(volumeIndex),
+ #endif
+ FileIndex(fileIndex),
+ FolderIndex(folderIndex),
+ UnpackSize(0)
+ {
+ if (fileIndex != kNumNoIndex)
+ {
+ ExtractStatuses.ClearAndSetSize(1);
+ ExtractStatuses[0] = true;
+ }
+ };
+};
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testModeSpec, IArchiveExtractCallback *extractCallbackSpec)
+{
+ COM_TRY_BEGIN
+ bool testMode = (testModeSpec != 0);
+ CMyComPtr<IArchiveExtractCallback> extractCallback = extractCallbackSpec;
+ UInt64 importantTotalUnpacked = 0;
+
+ bool allFilesMode = (numItems == (UInt32)(Int32)-1);
+ if (allFilesMode)
+ numItems =
+ #ifdef _7Z_VOL
+ _refs.Size();
+ #else
+ _db.Files.Size();
+ #endif
+
+ if(numItems == 0)
+ return S_OK;
+
+ /*
+ if(_volumes.Size() != 1)
+ return E_FAIL;
+ const CVolume &volume = _volumes.Front();
+ const CDbEx &_db = volume.Database;
+ IInStream *_inStream = volume.Stream;
+ */
+
+ CObjectVector<CExtractFolderInfo> extractFolderInfoVector;
+ for (UInt32 ii = 0; ii < numItems; ii++)
+ {
+ // UInt32 fileIndex = allFilesMode ? indexIndex : indices[indexIndex];
+ UInt32 ref2Index = allFilesMode ? ii : indices[ii];
+ // const CRef2 &ref2 = _refs[ref2Index];
+
+ // for (UInt32 ri = 0; ri < ref2.Refs.Size(); ri++)
+ {
+ #ifdef _7Z_VOL
+ // const CRef &ref = ref2.Refs[ri];
+ const CRef &ref = _refs[ref2Index];
+
+ int volumeIndex = ref.VolumeIndex;
+ const CVolume &volume = _volumes[volumeIndex];
+ const CDbEx &db = volume.Database;
+ UInt32 fileIndex = ref.ItemIndex;
+ #else
+ const CDbEx &db = _db;
+ UInt32 fileIndex = ref2Index;
+ #endif
+
+ CNum folderIndex = db.FileIndexToFolderIndexMap[fileIndex];
+ if (folderIndex == kNumNoIndex)
+ {
+ extractFolderInfoVector.Add(CExtractFolderInfo(
+ #ifdef _7Z_VOL
+ volumeIndex,
+ #endif
+ fileIndex, kNumNoIndex));
+ continue;
+ }
+ if (extractFolderInfoVector.IsEmpty() ||
+ folderIndex != extractFolderInfoVector.Back().FolderIndex
+ #ifdef _7Z_VOL
+ || volumeIndex != extractFolderInfoVector.Back().VolumeIndex
+ #endif
+ )
+ {
+ extractFolderInfoVector.Add(CExtractFolderInfo(
+ #ifdef _7Z_VOL
+ volumeIndex,
+ #endif
+ kNumNoIndex, folderIndex));
+ UInt64 unpackSize = db.GetFolderUnpackSize(folderIndex);
+ importantTotalUnpacked += unpackSize;
+ extractFolderInfoVector.Back().UnpackSize = unpackSize;
+ }
+
+ CExtractFolderInfo &efi = extractFolderInfoVector.Back();
+
+ // const CFolderInfo &folderInfo = m_dam_Folders[folderIndex];
+ CNum startIndex = db.FolderStartFileIndex[folderIndex];
+ for (CNum index = efi.ExtractStatuses.Size();
+ index <= fileIndex - startIndex; index++)
+ {
+ // UInt64 unpackSize = _db.Files[startIndex + index].UnpackSize;
+ // Count partial_folder_size
+ // efi.UnpackSize += unpackSize;
+ // importantTotalUnpacked += unpackSize;
+ efi.ExtractStatuses.Add(index == fileIndex - startIndex);
+ }
+ }
+ }
+
+ RINOK(extractCallback->SetTotal(importantTotalUnpacked));
+
+ CDecoder decoder(
+ #ifdef _ST_MODE
+ false
+ #else
+ true
+ #endif
+ );
+ // CDecoder1 decoder;
+
+ UInt64 totalPacked = 0;
+ UInt64 totalUnpacked = 0;
+ UInt64 curPacked, curUnpacked;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ for (unsigned i = 0;; i++, totalUnpacked += curUnpacked, totalPacked += curPacked)
+ {
+ lps->OutSize = totalUnpacked;
+ lps->InSize = totalPacked;
+ RINOK(lps->SetCur());
+
+ if (i >= extractFolderInfoVector.Size())
+ break;
+
+ const CExtractFolderInfo &efi = extractFolderInfoVector[i];
+ curUnpacked = efi.UnpackSize;
+ curPacked = 0;
+
+ CFolderOutStream *folderOutStream = new CFolderOutStream;
+ CMyComPtr<ISequentialOutStream> outStream(folderOutStream);
+
+ #ifdef _7Z_VOL
+ const CVolume &volume = _volumes[efi.VolumeIndex];
+ const CDbEx &db = volume.Database;
+ #else
+ const CDbEx &db = _db;
+ #endif
+
+ CNum startIndex;
+ if (efi.FileIndex != kNumNoIndex)
+ startIndex = efi.FileIndex;
+ else
+ startIndex = db.FolderStartFileIndex[efi.FolderIndex];
+
+ HRESULT result = folderOutStream->Init(&db,
+ #ifdef _7Z_VOL
+ volume.StartRef2Index,
+ #else
+ 0,
+ #endif
+ startIndex,
+ &efi.ExtractStatuses, extractCallback, testMode, _crcSize != 0);
+
+ RINOK(result);
+
+ if (efi.FileIndex != kNumNoIndex)
+ continue;
+
+ CNum folderIndex = efi.FolderIndex;
+ curPacked = _db.GetFolderFullPackSize(folderIndex);
+
+ #ifndef _NO_CRYPTO
+ CMyComPtr<ICryptoGetTextPassword> getTextPassword;
+ if (extractCallback)
+ extractCallback.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword);
+ #endif
+
+ try
+ {
+ #ifndef _NO_CRYPTO
+ bool isEncrypted = false;
+ bool passwordIsDefined = false;
+ #endif
+
+ HRESULT result = decoder.Decode(
+ EXTERNAL_CODECS_VARS
+ #ifdef _7Z_VOL
+ volume.Stream,
+ #else
+ _inStream,
+ #endif
+ db.ArcInfo.DataStartPosition,
+ db, folderIndex,
+ outStream,
+ progress
+ _7Z_DECODER_CRYPRO_VARS
+ #if !defined(_7ZIP_ST) && !defined(_SFX)
+ , true, _numThreads
+ #endif
+ );
+
+ if (result == S_FALSE)
+ {
+ RINOK(folderOutStream->FlushCorrupted(NExtract::NOperationResult::kDataError));
+ continue;
+ }
+ if (result == E_NOTIMPL)
+ {
+ RINOK(folderOutStream->FlushCorrupted(NExtract::NOperationResult::kUnsupportedMethod));
+ continue;
+ }
+ if (result != S_OK)
+ return result;
+ if (folderOutStream->WasWritingFinished() != S_OK)
+ {
+ RINOK(folderOutStream->FlushCorrupted(NExtract::NOperationResult::kDataError));
+ continue;
+ }
+ }
+ catch(...)
+ {
+ RINOK(folderOutStream->FlushCorrupted(NExtract::NOperationResult::kDataError));
+ continue;
+ }
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+}}
diff --git a/lzma/CPP/7zip/Archive/7z/7zFolderInStream.cpp b/lzma/CPP/7zip/Archive/7z/7zFolderInStream.cpp
new file mode 100644
index 0000000..7971191
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/7z/7zFolderInStream.cpp
@@ -0,0 +1,123 @@
+// 7zFolderInStream.cpp
+
+#include "StdAfx.h"
+
+#include "7zFolderInStream.h"
+
+namespace NArchive {
+namespace N7z {
+
+CFolderInStream::CFolderInStream()
+{
+ _inStreamWithHashSpec = new CSequentialInStreamWithCRC;
+ _inStreamWithHash = _inStreamWithHashSpec;
+}
+
+void CFolderInStream::Init(IArchiveUpdateCallback *updateCallback,
+ const UInt32 *fileIndices, UInt32 numFiles)
+{
+ _updateCallback = updateCallback;
+ _numFiles = numFiles;
+ _fileIndex = 0;
+ _fileIndices = fileIndices;
+ Processed.Clear();
+ CRCs.Clear();
+ Sizes.Clear();
+ _fileIsOpen = false;
+ _currentSizeIsDefined = false;
+}
+
+HRESULT CFolderInStream::OpenStream()
+{
+ _filePos = 0;
+ while (_fileIndex < _numFiles)
+ {
+ CMyComPtr<ISequentialInStream> stream;
+ HRESULT result = _updateCallback->GetStream(_fileIndices[_fileIndex], &stream);
+ if (result != S_OK && result != S_FALSE)
+ return result;
+ _fileIndex++;
+ _inStreamWithHashSpec->SetStream(stream);
+ _inStreamWithHashSpec->Init();
+ if (stream)
+ {
+ _fileIsOpen = true;
+ CMyComPtr<IStreamGetSize> streamGetSize;
+ stream.QueryInterface(IID_IStreamGetSize, &streamGetSize);
+ if (streamGetSize)
+ {
+ RINOK(streamGetSize->GetSize(&_currentSize));
+ _currentSizeIsDefined = true;
+ }
+ return S_OK;
+ }
+ RINOK(_updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
+ Sizes.Add(0);
+ Processed.Add(result == S_OK);
+ AddDigest();
+ }
+ return S_OK;
+}
+
+void CFolderInStream::AddDigest()
+{
+ CRCs.Add(_inStreamWithHashSpec->GetCRC());
+}
+
+HRESULT CFolderInStream::CloseStream()
+{
+ RINOK(_updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
+ _inStreamWithHashSpec->ReleaseStream();
+ _fileIsOpen = false;
+ _currentSizeIsDefined = false;
+ Processed.Add(true);
+ Sizes.Add(_filePos);
+ AddDigest();
+ return S_OK;
+}
+
+STDMETHODIMP CFolderInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize != 0)
+ *processedSize = 0;
+ while (size > 0)
+ {
+ if (_fileIsOpen)
+ {
+ UInt32 processed2;
+ RINOK(_inStreamWithHash->Read(data, size, &processed2));
+ if (processed2 == 0)
+ {
+ RINOK(CloseStream());
+ continue;
+ }
+ if (processedSize != 0)
+ *processedSize = processed2;
+ _filePos += processed2;
+ break;
+ }
+ if (_fileIndex >= _numFiles)
+ break;
+ RINOK(OpenStream());
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CFolderInStream::GetSubStreamSize(UInt64 subStream, UInt64 *value)
+{
+ *value = 0;
+ unsigned index2 = (unsigned)subStream;
+ if (subStream > Sizes.Size())
+ return E_FAIL;
+ if (index2 < Sizes.Size())
+ {
+ *value = Sizes[index2];
+ return S_OK;
+ }
+ if (!_currentSizeIsDefined)
+ return S_FALSE;
+ *value = _currentSize;
+ return S_OK;
+}
+
+}}
diff --git a/lzma/CPP/7zip/Archive/7z/7zFolderInStream.h b/lzma/CPP/7zip/Archive/7z/7zFolderInStream.h
new file mode 100644
index 0000000..e516dff
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/7z/7zFolderInStream.h
@@ -0,0 +1,58 @@
+// 7zFolderInStream.h
+
+#ifndef __7Z_FOLDER_IN_STREAM_H
+#define __7Z_FOLDER_IN_STREAM_H
+
+#include "../../ICoder.h"
+#include "../IArchive.h"
+#include "../Common/InStreamWithCRC.h"
+
+#include "7zItem.h"
+
+namespace NArchive {
+namespace N7z {
+
+class CFolderInStream:
+ public ISequentialInStream,
+ public ICompressGetSubStreamSize,
+ public CMyUnknownImp
+{
+ CSequentialInStreamWithCRC *_inStreamWithHashSpec;
+ CMyComPtr<ISequentialInStream> _inStreamWithHash;
+ CMyComPtr<IArchiveUpdateCallback> _updateCallback;
+
+ bool _currentSizeIsDefined;
+ bool _fileIsOpen;
+ UInt64 _currentSize;
+ UInt64 _filePos;
+ const UInt32 *_fileIndices;
+ UInt32 _numFiles;
+ UInt32 _fileIndex;
+
+ HRESULT OpenStream();
+ HRESULT CloseStream();
+ void AddDigest();
+
+public:
+ CRecordVector<bool> Processed;
+ CRecordVector<UInt32> CRCs;
+ CRecordVector<UInt64> Sizes;
+
+ MY_UNKNOWN_IMP1(ICompressGetSubStreamSize)
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+ STDMETHOD(GetSubStreamSize)(UInt64 subStream, UInt64 *value);
+
+ CFolderInStream();
+ void Init(IArchiveUpdateCallback *updateCallback, const UInt32 *fileIndices, UInt32 numFiles);
+ UInt64 GetFullSize() const
+ {
+ UInt64 size = 0;
+ FOR_VECTOR (i, Sizes)
+ size += Sizes[i];
+ return size;
+ }
+};
+
+}}
+
+#endif
diff --git a/lzma/CPP/7zip/Archive/7z/7zFolderOutStream.cpp b/lzma/CPP/7zip/Archive/7z/7zFolderOutStream.cpp
new file mode 100644
index 0000000..d206d7c
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/7z/7zFolderOutStream.cpp
@@ -0,0 +1,149 @@
+// 7zFolderOutStream.cpp
+
+#include "StdAfx.h"
+
+#include "7zFolderOutStream.h"
+
+namespace NArchive {
+namespace N7z {
+
+CFolderOutStream::CFolderOutStream()
+{
+ _crcStreamSpec = new COutStreamWithCRC;
+ _crcStream = _crcStreamSpec;
+}
+
+HRESULT CFolderOutStream::Init(
+ const CDbEx *db,
+ UInt32 ref2Offset, UInt32 startIndex,
+ const CBoolVector *extractStatuses,
+ IArchiveExtractCallback *extractCallback,
+ bool testMode, bool checkCrc)
+{
+ _db = db;
+ _ref2Offset = ref2Offset;
+ _startIndex = startIndex;
+
+ _extractStatuses = extractStatuses;
+ _extractCallback = extractCallback;
+ _testMode = testMode;
+ _checkCrc = checkCrc;
+
+ _currentIndex = 0;
+ _fileIsOpen = false;
+ return ProcessEmptyFiles();
+}
+
+HRESULT CFolderOutStream::OpenFile()
+{
+ Int32 askMode = ((*_extractStatuses)[_currentIndex]) ? (_testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract) :
+ NExtract::NAskMode::kSkip;
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ UInt32 index = _startIndex + _currentIndex;
+ RINOK(_extractCallback->GetStream(_ref2Offset + index, &realOutStream, askMode));
+ _crcStreamSpec->SetStream(realOutStream);
+ _crcStreamSpec->Init(_checkCrc);
+ _fileIsOpen = true;
+ const CFileItem &fi = _db->Files[index];
+ _rem = fi.Size;
+ if (askMode == NExtract::NAskMode::kExtract && !realOutStream &&
+ !_db->IsItemAnti(index) && !fi.IsDir)
+ askMode = NExtract::NAskMode::kSkip;
+ return _extractCallback->PrepareOperation(askMode);
+}
+
+HRESULT CFolderOutStream::CloseFileAndSetResult(Int32 res)
+{
+ _crcStreamSpec->ReleaseStream();
+ _fileIsOpen = false;
+ _currentIndex++;
+ return _extractCallback->SetOperationResult(res);
+}
+
+HRESULT CFolderOutStream::CloseFileAndSetResult()
+{
+ const CFileItem &fi = _db->Files[_startIndex + _currentIndex];
+ return CloseFileAndSetResult(
+ (fi.IsDir || !fi.CrcDefined || !_checkCrc || fi.Crc == _crcStreamSpec->GetCRC()) ?
+ NExtract::NOperationResult::kOK :
+ NExtract::NOperationResult::kCRCError);
+}
+
+HRESULT CFolderOutStream::ProcessEmptyFiles()
+{
+ while (_currentIndex < _extractStatuses->Size() && _db->Files[_startIndex + _currentIndex].Size == 0)
+ {
+ RINOK(OpenFile());
+ RINOK(CloseFileAndSetResult());
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CFolderOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize != NULL)
+ *processedSize = 0;
+ while (size != 0)
+ {
+ if (_fileIsOpen)
+ {
+ UInt32 cur = size < _rem ? size : (UInt32)_rem;
+ RINOK(_crcStream->Write(data, cur, &cur));
+ if (cur == 0)
+ break;
+ data = (const Byte *)data + cur;
+ size -= cur;
+ _rem -= cur;
+ if (processedSize != NULL)
+ *processedSize += cur;
+ if (_rem == 0)
+ {
+ RINOK(CloseFileAndSetResult());
+ RINOK(ProcessEmptyFiles());
+ continue;
+ }
+ }
+ else
+ {
+ RINOK(ProcessEmptyFiles());
+ if (_currentIndex == _extractStatuses->Size())
+ {
+ // we support partial extracting
+ if (processedSize != NULL)
+ *processedSize += size;
+ break;
+ }
+ RINOK(OpenFile());
+ }
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CFolderOutStream::GetSubStreamSize(UInt64 subStream, UInt64 *value)
+{
+ *value = 0;
+ if ((int)subStream >= _extractStatuses->Size())
+ return S_FALSE;
+ *value = _db->Files[_startIndex + (int)subStream].Size;
+ return S_OK;
+}
+
+HRESULT CFolderOutStream::FlushCorrupted(Int32 resultEOperationResult)
+{
+ while (_currentIndex < _extractStatuses->Size())
+ {
+ if (_fileIsOpen)
+ {
+ RINOK(CloseFileAndSetResult(resultEOperationResult));
+ }
+ else
+ {
+ RINOK(OpenFile());
+ }
+ }
+ return S_OK;
+}
+
+}}
diff --git a/lzma/CPP/7zip/Archive/7z/7zFolderOutStream.h b/lzma/CPP/7zip/Archive/7z/7zFolderOutStream.h
new file mode 100644
index 0000000..c00aba7
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/7z/7zFolderOutStream.h
@@ -0,0 +1,58 @@
+// 7zFolderOutStream.h
+
+#ifndef __7Z_FOLDER_OUT_STREAM_H
+#define __7Z_FOLDER_OUT_STREAM_H
+
+#include "../../IStream.h"
+#include "../IArchive.h"
+#include "../Common/OutStreamWithCRC.h"
+
+#include "7zIn.h"
+
+namespace NArchive {
+namespace N7z {
+
+class CFolderOutStream:
+ public ISequentialOutStream,
+ public ICompressGetSubStreamSize,
+ public CMyUnknownImp
+{
+ COutStreamWithCRC *_crcStreamSpec;
+ CMyComPtr<ISequentialOutStream> _crcStream;
+ const CDbEx *_db;
+ const CBoolVector *_extractStatuses;
+ CMyComPtr<IArchiveExtractCallback> _extractCallback;
+ UInt32 _ref2Offset;
+ UInt32 _startIndex;
+ unsigned _currentIndex;
+ bool _testMode;
+ bool _checkCrc;
+ bool _fileIsOpen;
+ UInt64 _rem;
+
+ HRESULT OpenFile();
+ HRESULT CloseFileAndSetResult(Int32 res);
+ HRESULT CloseFileAndSetResult();
+ HRESULT ProcessEmptyFiles();
+public:
+ MY_UNKNOWN_IMP1(ICompressGetSubStreamSize)
+
+ CFolderOutStream();
+
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+ STDMETHOD(GetSubStreamSize)(UInt64 subStream, UInt64 *value);
+
+ HRESULT Init(
+ const CDbEx *db,
+ UInt32 ref2Offset, UInt32 startIndex,
+ const CBoolVector *extractStatuses,
+ IArchiveExtractCallback *extractCallback,
+ bool testMode, bool checkCrc);
+ HRESULT FlushCorrupted(Int32 resultEOperationResult);
+ HRESULT WasWritingFinished() const
+ { return (_currentIndex == _extractStatuses->Size()) ? S_OK: E_FAIL; }
+};
+
+}}
+
+#endif
diff --git a/lzma/CPP/7zip/Archive/7z/7zHandler.cpp b/lzma/CPP/7zip/Archive/7z/7zHandler.cpp
new file mode 100644
index 0000000..6104440
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/7z/7zHandler.cpp
@@ -0,0 +1,753 @@
+// 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
+ _numThreads = NSystem::GetNumberOfProcessors();
+ #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)
+{
+ UString methodName;
+ FindMethod(EXTERNAL_CODECS_VARS id, methodName);
+ if (methodName.IsEmpty())
+ {
+ for (unsigned i = 0; i < methodName.Len(); i++)
+ if (methodName[i] >= 0x80)
+ {
+ methodName.Empty();
+ break;
+ }
+ }
+ if (methodName.IsEmpty())
+ ConvertMethodIdToString(s, id);
+ else
+ for (unsigned i = 0; i < methodName.Len(); i++)
+ s += (char)methodName[i];
+}
+
+#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];
+ if (!s.IsEmpty())
+ s += ' ';
+ 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;
+ }
+ }
+ 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 p = props[0];
+ if ((p & 1) == 0)
+ ConvertUInt32ToString((UInt32)((p >> 1) + 12), s);
+ else
+ GetStringForSizeValue(s, 3 << ((p >> 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
+ {
+ UString methodName;
+ FindMethod(EXTERNAL_CODECS_VARS id64, methodName);
+ if (methodName.IsEmpty())
+ {
+ for (unsigned j = 0; j < methodName.Len(); j++)
+ if (methodName[j] >= 0x80)
+ {
+ methodName.Empty();
+ break;
+ }
+ }
+ 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] = (char)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];
+ 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 (item.AttribDefined) PropVarEm_Set_UInt32(value, item.Attrib); 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)
+ {
+ const CFolder &folderInfo = _db.Folders[folderIndex];
+ if (_db.FolderStartFileIndex[folderIndex] == (CNum)index2 &&
+ folderInfo.PackStreams.Size() > (int)(propID - kpidPackedSize0))
+ {
+ prop = _db.GetFolderPackStreamSize(folderIndex, propID - kpidPackedSize0);
+ }
+ else
+ prop = (UInt64)0;
+ }
+ else
+ prop = (UInt64)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;
+ _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
+ #endif
+ );
+ RINOK(result);
+
+ _inStream = stream;
+ }
+ catch(...)
+ {
+ Close();
+ // return E_INVALIDARG;
+ // we must return out_of_memory here
+ return S_FALSE;
+ }
+ // _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;
+ #endif
+ return S_OK;
+ COM_TRY_END
+}
+
+#ifdef __7Z_SET_PROPERTIES
+#ifdef EXTRACT_ONLY
+
+STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps)
+{
+ COM_TRY_BEGIN
+ const UInt32 numProcessors = NSystem::GetNumberOfProcessors();
+ _numThreads = numProcessors;
+
+ 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;
+ int index = ParseStringToUInt32(name, number);
+ if (index == 0)
+ {
+ if (name.IsPrefixedBy(L"mt"))
+ {
+ RINOK(ParseMtProp(name.Ptr(2), value, numProcessors, _numThreads));
+ continue;
+ }
+ else
+ return E_INVALIDARG;
+ }
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+#endif
+#endif
+
+IMPL_ISetCompressCodecsInfo
+
+}}
diff --git a/lzma/CPP/7zip/Archive/7z/7zHandler.h b/lzma/CPP/7zip/Archive/7z/7zHandler.h
new file mode 100644
index 0000000..e7a80d8
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/7z/7zHandler.h
@@ -0,0 +1,179 @@
+// 7z/Handler.h
+
+#ifndef __7Z_HANDLER_H
+#define __7Z_HANDLER_H
+
+#include "../../ICoder.h"
+#include "../IArchive.h"
+
+#include "../../Common/CreateCoder.h"
+
+#ifndef EXTRACT_ONLY
+#include "../Common/HandlerOut.h"
+#endif
+
+#include "7zCompressionMode.h"
+#include "7zIn.h"
+
+namespace NArchive {
+namespace N7z {
+
+const UInt32 k_Copy = 0x0;
+const UInt32 k_Delta = 3;
+const UInt32 k_LZMA2 = 0x21;
+const UInt32 k_LZMA = 0x030101;
+const UInt32 k_PPMD = 0x030401;
+const UInt32 k_BCJ = 0x03030103;
+const UInt32 k_BCJ2 = 0x0303011B;
+const UInt32 k_Deflate = 0x040108;
+const UInt32 k_BZip2 = 0x040202;
+
+#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
+
+
+#ifndef EXTRACT_ONLY
+
+class COutHandler: public CMultiMethodProps
+{
+ HRESULT SetSolidFromString(const UString &s);
+ HRESULT SetSolidFromPROPVARIANT(const PROPVARIANT &value);
+public:
+ bool _removeSfxBlock;
+
+ UInt64 _numSolidFiles;
+ UInt64 _numSolidBytes;
+ bool _numSolidBytesDefined;
+ bool _solidExtension;
+
+ bool _compressHeaders;
+ bool _encryptHeadersSpecified;
+ bool _encryptHeaders;
+ // bool _useParents; 9.26
+
+ CBoolPair Write_CTime;
+ CBoolPair Write_ATime;
+ CBoolPair Write_MTime;
+
+ bool _volumeMode;
+
+ void InitSolidFiles() { _numSolidFiles = (UInt64)(Int64)(-1); }
+ void InitSolidSize() { _numSolidBytes = (UInt64)(Int64)(-1); }
+ void InitSolid()
+ {
+ InitSolidFiles();
+ InitSolidSize();
+ _solidExtension = false;
+ _numSolidBytesDefined = false;
+ }
+
+ void InitProps();
+
+ COutHandler() { InitProps(); }
+
+ 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
+ #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 **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;
+ #endif
+
+ #ifdef EXTRACT_ONLY
+
+ #ifdef __7Z_SET_PROPERTIES
+ UInt32 _numThreads;
+ #endif
+
+ UInt32 _crcSize;
+
+ #else
+
+ CRecordVector<CBind> _binds;
+
+ HRESULT PropsMethod_To_FullMethod(CMethodFull &dest, const COneMethodInfo &m);
+ HRESULT SetHeaderMethod(CCompressionMethodMode &headerMethod);
+ void AddDefaultMethod();
+ HRESULT SetMainMethod(CCompressionMethodMode &method,
+ CObjectVector<COneMethodInfo> &methodsInfo
+ #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
diff --git a/lzma/CPP/7zip/Archive/7z/7zHandlerOut.cpp b/lzma/CPP/7zip/Archive/7z/7zHandlerOut.cpp
new file mode 100644
index 0000000..aff5809
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/7z/7zHandlerOut.cpp
@@ -0,0 +1,875 @@
+// 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"
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace N7z {
+
+static const wchar_t *k_LZMA_Name = L"LZMA";
+static const wchar_t *kDefaultMethodName = L"LZMA2";
+static const wchar_t *k_Copy_Name = L"Copy";
+
+static const wchar_t *k_MatchFinder_ForHeaders = L"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)
+{
+ if (!FindMethod(
+ EXTERNAL_CODECS_VARS
+ m.MethodName, dest.Id, dest.NumInStreams, dest.NumOutStreams))
+ 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.AddPropString(NCoderPropID::kMatchFinder, k_MatchFinder_ForHeaders);
+ m.AddProp32(NCoderPropID::kLevel, k_Level_ForHeaders);
+ m.AddProp32(NCoderPropID::kNumFastBytes, k_NumFastBytes_ForHeaders);
+ m.AddProp32(NCoderPropID::kDictionarySize, k_Dictionary_ForHeaders);
+ m.AddNumThreadsProp(1);
+
+ CMethodFull methodFull;
+ RINOK(PropsMethod_To_FullMethod(methodFull, m));
+ headerMethod.Methods.Add(methodFull);
+ return S_OK;
+}
+
+void CHandler::AddDefaultMethod()
+{
+ FOR_VECTOR (i, _methods)
+ {
+ UString &methodName = _methods[i].MethodName;
+ if (methodName.IsEmpty())
+ methodName = kDefaultMethodName;
+ }
+ if (_methods.IsEmpty())
+ {
+ COneMethodInfo m;
+ m.MethodName = (GetLevel() == 0 ? k_Copy_Name : kDefaultMethodName);
+ _methods.Add(m);
+ }
+}
+
+HRESULT CHandler::SetMainMethod(
+ CCompressionMethodMode &methodMode,
+ CObjectVector<COneMethodInfo> &methods
+ #ifndef _7ZIP_ST
+ , UInt32 numThreads
+ #endif
+ )
+{
+ AddDefaultMethod();
+
+ 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];
+ SetGlobalLevelAndThreads(oneMethodInfo
+ #ifndef _7ZIP_ST
+ , numThreads
+ #endif
+ );
+
+ CMethodFull methodFull;
+ RINOK(PropsMethod_To_FullMethod(methodFull, oneMethodInfo));
+ methodMode.Methods.Add(methodFull);
+
+ 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
+
+ /*
+ 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);
+ if (db)
+ {
+ 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();
+ }
+
+ UString s;
+
+ 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;
+
+ UString name;
+ // 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;
+ {
+ 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 = NItemName::MakeLegalName(prop.bstrVal);
+ }
+ }
+ {
+ 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)
+ {
+ 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, _methods
+ #ifndef _7ZIP_ST
+ , _numThreads
+ #endif
+ );
+ RINOK(res);
+ methodMode.Binds = _binds;
+
+ RINOK(SetHeaderMethod(headerMethod));
+ #ifndef _7ZIP_ST
+ methodMode.NumThreads = _numThreads;
+ headerMethod.NumThreads = 1;
+ #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 && (BSTR)password)
+ methodMode.Password = password;
+ }
+
+ bool compressMainHeader = _compressHeaders; // check it
+
+ bool encryptHeaders = false;
+
+ 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;
+
+ CUpdateOptions options;
+ options.Method = &methodMode;
+ options.HeaderMethod = (_compressHeaders || encryptHeaders) ? &headerMethod : 0;
+ int level = GetLevel();
+ options.UseFilters = level != 0 && _autoFilter;
+ options.MaxFilter = level >= 8;
+
+ options.HeaderOptions.CompressMainHeader = compressMainHeader;
+ /*
+ options.HeaderOptions.WriteCTime = Write_CTime;
+ options.HeaderOptions.WriteATime = Write_ATime;
+ options.HeaderOptions.WriteMTime = Write_MTime;
+ */
+
+ options.NumSolidFiles = _numSolidFiles;
+ options.NumSolidBytes = _numSolidBytes;
+ options.SolidExtension = _solidExtension;
+ options.RemoveSfxBlock = _removeSfxBlock;
+ options.VolumeMode = _volumeMode;
+
+ 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 GetBindInfoPart(UString &srcString, UInt32 &coder, UInt32 &stream)
+{
+ stream = 0;
+ int index = ParseStringToUInt32(srcString, coder);
+ if (index == 0)
+ return E_INVALIDARG;
+ srcString.Delete(0, index);
+ if (srcString[0] == 's')
+ {
+ srcString.Delete(0);
+ int index = ParseStringToUInt32(srcString, stream);
+ if (index == 0)
+ return E_INVALIDARG;
+ srcString.Delete(0, index);
+ }
+ return S_OK;
+}
+
+void COutHandler::InitProps()
+{
+ CMultiMethodProps::Init();
+
+ _removeSfxBlock = false;
+ _compressHeaders = true;
+ _encryptHeadersSpecified = false;
+ _encryptHeaders = false;
+ // _useParents = false;
+
+ Write_CTime.Init();
+ Write_ATime.Init();
+ Write_MTime.Init();
+
+ _volumeMode = false;
+ InitSolid();
+}
+
+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;
+ }
+ }
+ 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("v")) return PROPVARIANT_to_bool(value, _volumeMode);
+ }
+ return CMultiMethodProps::SetProperty(name, value);
+}
+
+STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps)
+{
+ COM_TRY_BEGIN
+ _binds.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);
+ CBind bind;
+ RINOK(GetBindInfoPart(name, bind.OutCoder, bind.OutStream));
+ if (name[0] != ':')
+ return E_INVALIDARG;
+ name.Delete(0);
+ RINOK(GetBindInfoPart(name, bind.InCoder, bind.InStream));
+ if (!name.IsEmpty())
+ return E_INVALIDARG;
+ _binds.Add(bind);
+ continue;
+ }
+
+ RINOK(SetProperty(name, value));
+ }
+
+ unsigned numEmptyMethods = GetNumEmptyMethods();
+ if (numEmptyMethods > 0)
+ {
+ unsigned k;
+ for (k = 0; k < _binds.Size(); k++)
+ {
+ const CBind &bind = _binds[k];
+ if (bind.InCoder < (UInt32)numEmptyMethods ||
+ bind.OutCoder < (UInt32)numEmptyMethods)
+ return E_INVALIDARG;
+ }
+ for (k = 0; k < _binds.Size(); k++)
+ {
+ CBind &bind = _binds[k];
+ bind.InCoder -= (UInt32)numEmptyMethods;
+ bind.OutCoder -= (UInt32)numEmptyMethods;
+ }
+ _methods.DeleteFrontal(numEmptyMethods);
+ }
+
+ AddDefaultMethod();
+
+ if (!_filterMethod.MethodName.IsEmpty())
+ {
+ FOR_VECTOR (k, _binds)
+ {
+ CBind &bind = _binds[k];
+ bind.InCoder++;
+ bind.OutCoder++;
+ }
+ _methods.Insert(0, _filterMethod);
+ }
+
+ FOR_VECTOR (k, _binds)
+ {
+ const CBind &bind = _binds[k];
+ if (bind.InCoder >= (UInt32)_methods.Size() ||
+ bind.OutCoder >= (UInt32)_methods.Size())
+ return E_INVALIDARG;
+ }
+
+ return S_OK;
+ COM_TRY_END
+}
+
+}}
diff --git a/lzma/CPP/7zip/Archive/7z/7zHeader.cpp b/lzma/CPP/7zip/Archive/7z/7zHeader.cpp
new file mode 100644
index 0000000..de39909
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/7z/7zHeader.cpp
@@ -0,0 +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;
+
+}}
diff --git a/lzma/CPP/7zip/Archive/7z/7zHeader.h b/lzma/CPP/7zip/Archive/7z/7zHeader.h
new file mode 100644
index 0000000..78b5061
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/7z/7zHeader.h
@@ -0,0 +1,101 @@
+// 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
+ };
+}
+
+}}
+
+#endif
diff --git a/lzma/CPP/7zip/Archive/7z/7zIn.cpp b/lzma/CPP/7zip/Archive/7z/7zIn.cpp
new file mode 100644
index 0000000..5a85507
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/7z/7zIn.cpp
@@ -0,0 +1,1679 @@
+// 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 {
+
+static const UInt32 k_LZMA2 = 0x21;
+static const UInt32 k_LZMA = 0x030101;
+
+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;
+}
+
+static bool BoolVector_GetAndSet(CBoolVector &v, UInt32 index)
+{
+ if (index >= (UInt32)v.Size())
+ return true;
+ bool res = v[index];
+ v[index] = true;
+ return res;
+}
+
+bool CFolder::CheckStructure(unsigned numUnpackSizes) const
+{
+ const unsigned kNumCodersMax = sizeof(UInt32) * 8; // don't change it
+ const unsigned kMaskSize = sizeof(UInt32) * 8; // it must be >= kNumCodersMax
+ const unsigned kNumBindsMax = 32;
+
+ if (Coders.Size() > kNumCodersMax || BindPairs.Size() > kNumBindsMax)
+ return false;
+
+ {
+ CBoolVector v;
+ BoolVector_Fill_False(v, BindPairs.Size() + PackStreams.Size());
+
+ unsigned i;
+ for (i = 0; i < BindPairs.Size(); i++)
+ if (BoolVector_GetAndSet(v, BindPairs[i].InIndex))
+ return false;
+ for (i = 0; i < PackStreams.Size(); i++)
+ if (BoolVector_GetAndSet(v, PackStreams[i]))
+ return false;
+
+ BoolVector_Fill_False(v, numUnpackSizes);
+ for (i = 0; i < BindPairs.Size(); i++)
+ if (BoolVector_GetAndSet(v, BindPairs[i].OutIndex))
+ return false;
+ }
+
+ UInt32 mask[kMaskSize];
+ unsigned i;
+ for (i = 0; i < kMaskSize; i++)
+ mask[i] = 0;
+
+ {
+ CUIntVector inStreamToCoder, outStreamToCoder;
+ for (i = 0; i < Coders.Size(); i++)
+ {
+ CNum j;
+ const CCoderInfo &coder = Coders[i];
+ for (j = 0; j < coder.NumInStreams; j++)
+ inStreamToCoder.Add(i);
+ for (j = 0; j < coder.NumOutStreams; j++)
+ outStreamToCoder.Add(i);
+ }
+
+ for (i = 0; i < BindPairs.Size(); i++)
+ {
+ const CBindPair &bp = BindPairs[i];
+ mask[inStreamToCoder[bp.InIndex]] |= (1 << outStreamToCoder[bp.OutIndex]);
+ }
+ }
+
+ for (i = 0; i < kMaskSize; i++)
+ for (unsigned j = 0; j < kMaskSize; j++)
+ if (((1 << j) & mask[i]) != 0)
+ mask[i] |= mask[j];
+
+ for (i = 0; i < kMaskSize; i++)
+ if (((1 << i) & mask[i]) != 0)
+ return false;
+
+ return true;
+}
+
+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)
+ {
+ 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 > _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;
+ }
+ Byte firstByte = *p++;
+ size--;
+ if ((firstByte & 0x80) == 0)
+ {
+ processed = 1;
+ return firstByte;
+ }
+ Byte mask = 0x40;
+ if (size == 0)
+ {
+ processed = 0;
+ return 0;
+ }
+ UInt64 value = (UInt64)*p;
+ p++;
+ size--;
+ for (unsigned i = 1; i < 8; i++)
+ {
+ if ((firstByte & mask) == 0)
+ {
+ UInt64 highPart = firstByte & (mask - 1);
+ value += (highPart << (i * 8));
+ processed = i + 1;
+ return value;
+ }
+ if (size == 0)
+ {
+ processed = 0;
+ return 0;
+ }
+ value |= ((UInt64)*p << (i * 8));
+ p++;
+ size--;
+ mask >>= 1;
+ }
+ 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;
+ {
+ 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)
+{
+ CNum numCoders = ReadNum();
+
+ folder.Coders.SetSize(numCoders);
+
+ CNum numInStreams = 0;
+ CNum numOutStreams = 0;
+ CNum 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.NumInStreams = ReadNum();
+ coder.NumOutStreams = ReadNum();
+ }
+ else
+ {
+ coder.NumInStreams = 1;
+ coder.NumOutStreams = 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.NumInStreams;
+ numOutStreams += coder.NumOutStreams;
+ }
+
+ CNum numBindPairs = numOutStreams - 1;
+ folder.BindPairs.SetSize(numBindPairs);
+ for (i = 0; i < numBindPairs; i++)
+ {
+ CBindPair &bp = folder.BindPairs[i];
+ bp.InIndex = ReadNum();
+ bp.OutIndex = ReadNum();
+ }
+
+ if (numInStreams < numBindPairs)
+ ThrowUnsupported();
+ CNum numPackStreams = numInStreams - numBindPairs;
+ folder.PackStreams.SetSize(numPackStreams);
+ if (numPackStreams == 1)
+ {
+ for (i = 0; i < numInStreams; i++)
+ if (folder.FindBindPairForInStream(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 - 1;
+
+ if (size >= (1 << 20))
+ return;
+
+ wchar_t *s = path.GetBuffer((unsigned)size);
+
+ 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.ReleaseBuffer((unsigned)size);
+}
+
+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;
+ do
+ {
+ p -= 2;
+ --s;
+ wchar_t c = Get16(p);
+ if (c == '/')
+ c = WCHAR_PATH_SEPARATOR;
+ *s = c;
+ }
+ while (--len);
+ 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::ReadHashDigests(unsigned numItems, CUInt32DefVector &crcs)
+{
+ ReadBoolVector2(numItems, crcs.Defs);
+ crcs.Vals.ClearAndSetSize(numItems);
+ UInt32 *p = &crcs.Vals[0];
+ const bool *defs = &crcs.Defs[0];
+ for (unsigned i = 0; i < numItems; i++)
+ {
+ UInt32 crc = 0;
+ if (defs[i])
+ crc = ReadUInt32();
+ p[i] = crc;
+ }
+}
+
+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);
+
+ CRecordVector<bool> InStreamUsed;
+ CRecordVector<bool> OutStreamUsed;
+
+ CNum packStreamIndex = 0;
+ CNum fo;
+ CInByte2 *inByte = _inByteBack;
+ for (fo = 0; fo < numFolders; fo++)
+ {
+ UInt32 numOutStreams = 0;
+ UInt32 indexOfMainStream = 0;
+ UInt32 numPackStreams = 0;
+ folders.FoCodersDataOffset[fo] = _inByteBack->GetPtr() - startBufPtr;
+
+ numOutStreams = 0;
+ CNum numInStreams = 0;
+ CNum numCoders = inByte->ReadNum();
+ 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;
+ CNum coderOutStreams = 1;
+ if ((mainByte & 0x10) != 0)
+ {
+ coderInStreams = inByte->ReadNum();
+ coderOutStreams = inByte->ReadNum();
+ }
+ numInStreams += coderInStreams;
+ if (numInStreams < coderInStreams)
+ ThrowUnsupported();
+ numOutStreams += coderOutStreams;
+ if (numOutStreams < coderOutStreams)
+ 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 (numOutStreams == 1 && numInStreams == 1)
+ {
+ indexOfMainStream = 0;
+ numPackStreams = 1;
+ }
+ else
+ {
+ UInt32 i;
+ if (numOutStreams == 0)
+ ThrowUnsupported();
+ CNum numBindPairs = numOutStreams - 1;
+ if (numInStreams < numBindPairs)
+ ThrowUnsupported();
+ if (numInStreams >= 256 || numOutStreams >= 256)
+ ThrowUnsupported();
+
+ InStreamUsed.ClearAndSetSize(numInStreams);
+ for (i = 0; i < numInStreams; i++)
+ InStreamUsed[i] = false;
+
+ OutStreamUsed.ClearAndSetSize(numOutStreams);
+ for (i = 0; i < numOutStreams; i++)
+ OutStreamUsed[i] = false;
+
+ for (i = 0; i < numBindPairs; i++)
+ {
+ CNum index = ReadNum();
+ if (index >= numInStreams || InStreamUsed[index])
+ ThrowUnsupported();
+ InStreamUsed[index] = true;
+ index = ReadNum();
+ if (index >= numOutStreams || OutStreamUsed[index])
+ ThrowUnsupported();
+ OutStreamUsed[index] = true;
+ }
+
+ numPackStreams = numInStreams - numBindPairs;
+
+ if (numPackStreams != 1)
+ for (i = 0; i < numPackStreams; i++)
+ inByte->ReadNum(); // PackStreams
+
+ for (i = 0; i < numOutStreams; i++)
+ if (!OutStreamUsed[i])
+ {
+ indexOfMainStream = i;
+ break;
+ }
+ if (i == numOutStreams)
+ ThrowUnsupported();
+ }
+ folders.FoToCoderUnpackSizes[fo] = numCodersOutStreams;
+ numCodersOutStreams += numOutStreams;
+ folders.FoStartPackStreamIndex[fo] = packStreamIndex;
+ 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);
+ }
+
+ 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(
+ #ifdef _ST_MODE
+ false
+ #else
+ true
+ #endif
+ );
+
+ 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);
+
+ HRESULT result = decoder.Decode(
+ EXTERNAL_CODECS_LOC_VARS
+ _stream, baseOffset + dataOffset,
+ folders, i,
+ outStream, NULL
+ _7Z_DECODER_CRYPRO_VARS
+ #if !defined(_7ZIP_ST) && !defined(_SFX)
+ , false, 1
+ #endif
+ );
+ RINOK(result);
+
+ if (folders.FolderCRCs.ValidAndDefined(i))
+ if (CrcCalc(data, unpackSize) != folders.FolderCRCs.Vals[i])
+ ThrowIncorrect();
+ }
+ 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();
+ }
+
+ db.Files.Clear();
+
+ if (type == NID::kFilesInfo)
+ {
+
+ CNum numFiles = ReadNum();
+ db.Files.ClearAndSetSize(numFiles);
+ CNum i;
+ /*
+ db.Files.Reserve(numFiles);
+ CNum i;
+ for (i = 0; i < numFiles; i++)
+ db.Files.Add(CFileItem());
+ */
+
+ 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;
+ BoolVector_Fill_False(emptyStreamVector, (unsigned)numFiles);
+ CBoolVector emptyFileVector;
+ CBoolVector antiFileVector;
+ CNum numEmptyStreams = 0;
+
+ for (;;)
+ {
+ UInt64 type = ReadID();
+ if (type == 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 (type > ((UInt32)1 << 30))
+ isKnownType = false;
+ else switch((UInt32)type)
+ {
+ 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(db.Files.Size() + 1);
+ size_t pos = 0;
+ unsigned i;
+ for (i = 0; i < db.Files.Size(); 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:
+ {
+ CBoolVector boolVector;
+ ReadBoolVector2(db.Files.Size(), boolVector);
+ CStreamSwitch streamSwitch;
+ streamSwitch.Set(this, &dataVector);
+ for (i = 0; i < numFiles; i++)
+ {
+ CFileItem &file = db.Files[i];
+ file.AttribDefined = boolVector[i];
+ if (file.AttribDefined)
+ file.Attrib = ReadUInt32();
+ }
+ break;
+ }
+ /*
+ case NID::kIsAux:
+ {
+ ReadBoolVector(db.Files.Size(), db.IsAux);
+ break;
+ }
+ case NID::kParent:
+ {
+ db.IsTree = true;
+ // CBoolVector boolVector;
+ // ReadBoolVector2(db.Files.Size(), boolVector);
+ // CStreamSwitch streamSwitch;
+ // streamSwitch.Set(this, &dataVector);
+ CBoolVector boolVector;
+ ReadBoolVector2(db.Files.Size(), 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 = 0;
+ for (i = 0; i < (CNum)emptyStreamVector.Size(); i++)
+ if (emptyStreamVector[i])
+ numEmptyStreams++;
+
+ BoolVector_Fill_False(emptyFileVector, numEmptyStreams);
+ BoolVector_Fill_False(antiFileVector, numEmptyStreams);
+
+ 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 < db.Files.Size(); 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(type);
+ }
+ else
+ {
+ db.UnsupportedFeatureWarning = true;
+ _inByteBack->SkipRem();
+ }
+ // SkipData worked incorrectly in some versions before v4.59 (7zVer <= 00.02)
+ if (_inByteBack->GetRem() != 0)
+ ThrowIncorrect();
+ }
+
+ type = ReadID(); // Read (NID::kEnd) end of headers
+
+ CNum emptyFileIndex = 0;
+ CNum sizeIndex = 0;
+
+ CNum numAntiItems = 0;
+ for (i = 0; i < numEmptyStreams; i++)
+ if (antiFileVector[i])
+ numAntiItems++;
+
+ for (i = 0; i < numFiles; i++)
+ {
+ CFileItem &file = db.Files[i];
+ bool isAnti;
+ file.HasStream = !emptyStreamVector[i];
+ file.Crc = 0;
+ if (file.HasStream)
+ {
+ 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.IsDir = !emptyFileVector[emptyFileIndex];
+ isAnti = antiFileVector[emptyFileIndex];
+ emptyFileIndex++;
+ file.Size = 0;
+ file.CrcDefined = false;
+ }
+ if (numAntiItems != 0)
+ db.IsAnti.Add(isAnti);
+ }
+ }
+ db.FillLinks();
+ /*
+ if (type != NID::kEnd)
+ ThrowIncorrect();
+ if (_inByteBack->GetRem() != 0)
+ ThrowIncorrect();
+ */
+ return S_OK;
+}
+
+void CDbEx::FillLinks()
+{
+ FolderStartFileIndex.ClearAndSetSize(NumFolders);
+
+ FileIndexToFolderIndexMap.ClearAndSetSize(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++;
+ /*
+ if (indexInFolder != 0)
+ ThrowIncorrect();
+ */
+ for (;;)
+ {
+ if (folderIndex >= NumFolders)
+ return;
+ FolderStartFileIndex[folderIndex] = i;
+ /*
+ if (NumUnpackStreamsVector[folderIndex] != 0)
+ 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;
+ }
+}
+
+}}
diff --git a/lzma/CPP/7zip/Archive/7z/7zIn.h b/lzma/CPP/7zip/Archive/7z/7zIn.h
new file mode 100644
index 0000000..d78eca2
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/7z/7zIn.h
@@ -0,0 +1,412 @@
+// 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
+#define _7Z_DECODER_CRYPRO_VARS , getTextPassword, isEncrypted, passwordIsDefined
+#endif
+
+struct CParsedMethods
+{
+ Byte Lzma2Prop;
+ UInt32 LzmaDic;
+ CRecordVector<UInt64> IDs;
+
+ CParsedMethods(): Lzma2Prop(0), LzmaDic(0) {}
+};
+
+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 bind 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;
+
+ unsigned GetNumFolderUnpackSizes(unsigned folderIndex) const
+ {
+ return 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];
+ }
+
+ 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;
+ CRecordVector<bool> IsAnti;
+ /*
+ CRecordVector<bool> 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();
+ 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 (const 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;
+ CRecordVector<CNum> FolderStartFileIndex;
+ CRecordVector<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.Clear();
+ FileIndexToFolderIndexMap.Clear();
+
+ HeadersSize = 0;
+ PhySize = 0;
+ }
+
+ void FillLinks();
+
+ UInt64 GetFolderStreamPos(unsigned folderIndex, unsigned indexInFolder) const
+ {
+ return ArcInfo.DataStartPosition +
+ PackPositions[FoStartPackStreamIndex[folderIndex] + indexInFolder];
+ }
+
+ UInt64 GetFolderFullPackSize(unsigned folderIndex) const
+ {
+ return
+ PackPositions[FoStartPackStreamIndex[folderIndex + 1]] -
+ PackPositions[FoStartPackStreamIndex[folderIndex]];
+ }
+
+ UInt64 GetFolderPackStreamSize(unsigned folderIndex, unsigned streamIndex) const
+ {
+ unsigned 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;
+
+ 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;
+ }
+ }
+
+private:
+ 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 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(): _numInByteBufs(0) { }
+ 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
diff --git a/lzma/CPP/7zip/Archive/7z/7zItem.h b/lzma/CPP/7zip/Archive/7z/7zItem.h
new file mode 100644
index 0000000..90e6869
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/7z/7zItem.h
@@ -0,0 +1,186 @@
+// 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 {
+
+const UInt64 k_AES = 0x06F10701;
+
+typedef UInt32 CNum;
+const CNum kNumMax = 0x7FFFFFFF;
+const CNum kNumNoIndex = 0xFFFFFFFF;
+
+struct CCoderInfo
+{
+ CMethodId MethodID;
+ CByteBuffer Props;
+ CNum NumInStreams;
+ CNum NumOutStreams;
+
+ bool IsSimpleCoder() const { return (NumInStreams == 1) && (NumOutStreams == 1); }
+};
+
+struct CBindPair
+{
+ CNum InIndex;
+ CNum OutIndex;
+};
+
+struct CFolder
+{
+ CObjArray2<CCoderInfo> Coders;
+ CObjArray2<CBindPair> BindPairs;
+ CObjArray2<CNum> PackStreams;
+
+ CNum GetNumOutStreams() const
+ {
+ CNum result = 0;
+ FOR_VECTOR(i, Coders)
+ result += Coders[i].NumOutStreams;
+ return result;
+ }
+
+ int FindBindPairForInStream(CNum inStreamIndex) const
+ {
+ FOR_VECTOR(i, BindPairs)
+ if (BindPairs[i].InIndex == inStreamIndex)
+ return i;
+ return -1;
+ }
+ int FindBindPairForOutStream(CNum outStreamIndex) const
+ {
+ FOR_VECTOR(i, BindPairs)
+ if (BindPairs[i].OutIndex == outStreamIndex)
+ return i;
+ return -1;
+ }
+ int FindPackStreamArrayIndex(CNum inStreamIndex) const
+ {
+ FOR_VECTOR(i, PackStreams)
+ if (PackStreams[i] == inStreamIndex)
+ return i;
+ return -1;
+ }
+
+ int GetIndexOfMainOutStream() const
+ {
+ for (int i = (int)GetNumOutStreams() - 1; i >= 0; i--)
+ if (FindBindPairForOutStream(i) < 0)
+ return i;
+ throw 1;
+ }
+
+ bool IsEncrypted() const
+ {
+ for (int i = Coders.Size() - 1; i >= 0; i--)
+ if (Coders[i].MethodID == k_AES)
+ return true;
+ return false;
+ }
+
+ bool CheckStructure(unsigned numUnpackSizes) const;
+};
+
+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 ValidAndDefined(unsigned i) const { return i < Defs.Size() && Defs[i]; }
+};
+
+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;
+ }
+
+ void SetItem(unsigned index, bool defined, UInt64 value);
+
+ bool CheckSize(unsigned size) const { return Defs.Size() == size || Defs.Size() == 0; }
+};
+
+struct CFileItem
+{
+ UInt64 Size;
+ UInt32 Attrib;
+ 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;
+ bool AttribDefined;
+
+ CFileItem():
+ /*
+ Parent(-1),
+ IsAltStream(false),
+ */
+ HasStream(true),
+ IsDir(false),
+ CrcDefined(false),
+ AttribDefined(false)
+ {}
+ void SetAttrib(UInt32 attrib)
+ {
+ AttribDefined = true;
+ Attrib = attrib;
+ }
+};
+
+}}
+
+#endif
diff --git a/lzma/CPP/7zip/Archive/7z/7zOut.cpp b/lzma/CPP/7zip/Archive/7z/7zOut.cpp
new file mode 100644
index 0000000..cf776ce
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/7z/7zOut.cpp
@@ -0,0 +1,903 @@
+// 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];
+ {
+ size_t propsSize = coder.Props.Size();
+
+ UInt64 id = coder.MethodID;
+ int idSize;
+ for (idSize = 1; idSize < sizeof(id); idSize++)
+ if ((id >> (8 * idSize)) == 0)
+ break;
+ Byte longID[15];
+ for (int t = idSize - 1; t >= 0 ; t--, id >>= 8)
+ longID[t] = (Byte)(id & 0xFF);
+ Byte b;
+ b = (Byte)(idSize & 0xF);
+ bool isComplex = !coder.IsSimpleCoder();
+ b |= (isComplex ? 0x10 : 0);
+ b |= ((propsSize != 0) ? 0x20 : 0 );
+ WriteByte(b);
+ WriteBytes(longID, idSize);
+ if (isComplex)
+ {
+ WriteNumber(coder.NumInStreams);
+ WriteNumber(coder.NumOutStreams);
+ }
+ if (propsSize == 0)
+ continue;
+ WriteNumber(propsSize);
+ WriteBytes(coder.Props, propsSize);
+ }
+ }
+ for (i = 0; i < folder.BindPairs.Size(); i++)
+ {
+ const CBindPair &bindPair = folder.BindPairs[i];
+ WriteNumber(bindPair.InIndex);
+ WriteNumber(bindPair.OutIndex);
+ }
+ 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);
+}
+
+void COutArchive::WriteHashDigests(const CUInt32DefVector &digests)
+{
+ unsigned numDefined = 0;
+ unsigned i;
+ for (i = 0; i < digests.Defs.Size(); i++)
+ if (digests.Defs[i])
+ numDefined++;
+ if (numDefined == 0)
+ return;
+
+ WriteByte(NID::kCRC);
+ if (numDefined == digests.Defs.Size())
+ WriteByte(1);
+ else
+ {
+ WriteByte(0);
+ WriteBoolVector(digests.Defs);
+ }
+ for (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::SkipAlign(unsigned pos, unsigned alignSize)
+{
+ if (!_useAlign)
+ return;
+ 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::WriteAlignedBoolHeader(const CBoolVector &v, unsigned numDefined, Byte type, unsigned itemSize)
+{
+ const unsigned bvSize = (numDefined == v.Size()) ? 0 : Bv_GetSizeInBytes(v);
+ const UInt64 dataSize = (UInt64)numDefined * itemSize + bvSize + 2;
+ SkipAlign(3 + (unsigned)bvSize + (unsigned)GetBigNumberSize(dataSize), itemSize);
+
+ WriteByte(type);
+ WriteNumber(dataSize);
+ if (numDefined == v.Size())
+ WriteByte(1);
+ else
+ {
+ WriteByte(0);
+ WriteBoolVector(v);
+ }
+ WriteByte(0);
+}
+
+void COutArchive::WriteUInt64DefVector(const CUInt64DefVector &v, Byte type)
+{
+ unsigned numDefined = 0;
+
+ unsigned i;
+ for (i = 0; i < v.Defs.Size(); i++)
+ if (v.Defs[i])
+ numDefined++;
+
+ if (numDefined == 0)
+ return;
+
+ WriteAlignedBoolHeader(v.Defs, numDefined, type, 8);
+
+ for (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;
+ 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;
+
+ unsigned i;
+
+ UInt64 packedSize = 0;
+ for (i = 0; i < db.PackSizes.Size(); i++)
+ packedSize += db.PackSizes[i];
+
+ headerOffset = packedSize;
+
+ 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 (i = 0; i < db.Files.Size(); i++)
+ {
+ 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 (i = 0; i < db.Files.Size(); i++)
+ 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 (i = 0; i < db.Files.Size(); i++)
+ {
+ 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++;
+ SkipAlign(2 + GetBigNumberSize(namesDataSize), 16);
+
+ 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 ---------- */
+ CBoolVector boolVector;
+ boolVector.ClearAndSetSize(db.Files.Size());
+ unsigned numDefined = 0;
+ for (i = 0; i < db.Files.Size(); i++)
+ {
+ bool defined = db.Files[i].AttribDefined;
+ boolVector[i] = defined;
+ if (defined)
+ numDefined++;
+ }
+ if (numDefined != 0)
+ {
+ WriteAlignedBoolHeader(boolVector, numDefined, NID::kWinAttrib, 4);
+ for (i = 0; i < db.Files.Size(); i++)
+ {
+ const CFileItem &file = db.Files[i];
+ if (file.AttribDefined)
+ WriteUInt32(file.Attrib);
+ }
+ }
+ }
+
+ /*
+ {
+ // ---------- Write IsAux ----------
+ unsigned numAux = 0;
+ const CBoolVector &isAux = db.IsAux;
+ for (i = 0; i < isAux.Size(); i++)
+ if (isAux[i])
+ numAux++;
+ if (numAux > 0)
+ {
+ const unsigned bvSize = Bv_GetSizeInBytes(isAux);
+ WriteByte(NID::kIsAux);
+ WriteNumber(bvSize);
+ WriteBoolVector(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)
+ {
+ // WriteAlignedBoolHeader(boolVector, numDefined, NID::kParent, 4);
+ const unsigned bvSize = (numIsDir == boolVector.Size()) ? 0 : Bv_GetSizeInBytes(boolVector);
+ const UInt64 dataSize = (UInt64)db.Files.Size() * 4 + bvSize + 1;
+ SkipAlign(2 + (unsigned)bvSize + (unsigned)GetBigNumberSize(dataSize), 4);
+
+ 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]);
+ SkipAlign(2 + GetBigNumberSize(secureDataSize), 4);
+ 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 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);
+ SetItem_Anti(index, file2.IsAnti);
+ // SetItem_Aux(index, file2.IsAux);
+ Names.Add(name);
+ Files.Add(file);
+}
+
+}}
diff --git a/lzma/CPP/7zip/Archive/7z/7zOut.h b/lzma/CPP/7zip/Archive/7z/7zOut.h
new file mode 100644
index 0000000..07dbd63
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/7z/7zOut.h
@@ -0,0 +1,319 @@
+// 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 > _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;
+ bool CTimeDefined;
+ bool ATimeDefined;
+ bool MTimeDefined;
+ bool StartPosDefined;
+ bool IsAnti;
+ // bool IsAux;
+
+ void Init()
+ {
+ CTimeDefined = false;
+ ATimeDefined = false;
+ MTimeDefined = false;
+ StartPosDefined = 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 bind 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;
+ CRecordVector<bool> IsAnti;
+
+ /*
+ CRecordVector<bool> 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();
+ 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();
+ 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) &&
+ (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 SkipAlign(unsigned pos, unsigned alignSize);
+ void WriteAlignedBoolHeader(const CBoolVector &v, unsigned numDefined, Byte type, unsigned itemSize);
+ 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
diff --git a/lzma/CPP/7zip/Archive/7z/7zProperties.cpp b/lzma/CPP/7zip/Archive/7z/7zProperties.cpp
new file mode 100644
index 0000000..345c61b
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/7z/7zProperties.cpp
@@ -0,0 +1,170 @@
+// 7zProperties.cpp
+
+#include "StdAfx.h"
+
+#include "7zProperties.h"
+#include "7zHeader.h"
+#include "7zHandler.h"
+
+// #define _MULTI_PACK
+
+namespace NArchive {
+namespace N7z {
+
+struct CPropMap
+{
+ UInt64 FilePropID;
+ STATPROPSTG StatPROPSTG;
+};
+
+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, { L"Pack0", kpidPackedSize0, VT_UI8 } },
+ { 101, { L"Pack1", kpidPackedSize1, VT_UI8 } },
+ { 102, { L"Pack2", kpidPackedSize2, VT_UI8 } },
+ { 103, { L"Pack3", kpidPackedSize3, VT_UI8 } },
+ { 104, { L"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_UI4 } },
+
+ { 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 int FindPropInMap(UInt64 filePropID)
+{
+ for (int i = 0; i < ARRAY_SIZE(kPropMap); i++)
+ if (kPropMap[i].FilePropID == filePropID)
+ return i;
+ return -1;
+}
+
+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 ((int)index >= _fileInfoPopIDs.Size())
+ return E_INVALIDARG;
+ int indexInMap = FindPropInMap(_fileInfoPopIDs[index]);
+ if (indexInMap == -1)
+ return E_INVALIDARG;
+ const STATPROPSTG &srcItem = kPropMap[indexInMap].StatPROPSTG;
+ *propID = srcItem.propid;
+ *varType = srcItem.vt;
+ *name = 0;
+ return S_OK;
+}
+
+}}
diff --git a/lzma/CPP/7zip/Archive/7z/7zProperties.h b/lzma/CPP/7zip/Archive/7z/7zProperties.h
new file mode 100644
index 0000000..7b78130
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/7z/7zProperties.h
@@ -0,0 +1,22 @@
+// 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
diff --git a/lzma/CPP/7zip/Archive/7z/7zRegister.cpp b/lzma/CPP/7zip/Archive/7z/7zRegister.cpp
new file mode 100644
index 0000000..ae4e890
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/7z/7zRegister.cpp
@@ -0,0 +1,25 @@
+// 7zRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/RegisterArc.h"
+
+#include "7zHandler.h"
+
+namespace NArchive {
+namespace N7z {
+
+IMP_CreateArcIn
+IMP_CreateArcOut
+
+static CArcInfo g_ArcInfo =
+ { "7z", "7z", 0, 7,
+ 6, {'7' + 1, 'z', 0xBC, 0xAF, 0x27, 0x1C},
+ 0,
+ NArcInfoFlags::kFindSignature,
+ REF_CreateArc_Pair };
+
+REGISTER_ARC_DEC_SIG(7z)
+// REGISTER_ARC(7z)
+
+}}
diff --git a/lzma/CPP/7zip/Archive/7z/7zSpecStream.cpp b/lzma/CPP/7zip/Archive/7z/7zSpecStream.cpp
new file mode 100644
index 0000000..e9671a8
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/7z/7zSpecStream.cpp
@@ -0,0 +1,22 @@
+// 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);
+}
diff --git a/lzma/CPP/7zip/Archive/7z/7zSpecStream.h b/lzma/CPP/7zip/Archive/7z/7zSpecStream.h
new file mode 100644
index 0000000..0058ac2
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/7z/7zSpecStream.h
@@ -0,0 +1,35 @@
+// 7zSpecStream.h
+
+#ifndef __7Z_SPEC_STREAM_H
+#define __7Z_SPEC_STREAM_H
+
+#include "../../IStream.h"
+#include "../../ICoder.h"
+#include "../../../Common/MyCom.h"
+
+class CSequentialInStreamSizeCount2:
+ public ISequentialInStream,
+ public ICompressGetSubStreamSize,
+ public CMyUnknownImp
+{
+ CMyComPtr<ISequentialInStream> _stream;
+ CMyComPtr<ICompressGetSubStreamSize> _getSubStreamSize;
+ UInt64 _size;
+public:
+ void Init(ISequentialInStream *stream)
+ {
+ _stream = stream;
+ _getSubStreamSize = 0;
+ _stream.QueryInterface(IID_ICompressGetSubStreamSize, &_getSubStreamSize);
+ _size = 0;
+ }
+ UInt64 GetSize() const { return _size; }
+
+ MY_UNKNOWN_IMP1(ICompressGetSubStreamSize)
+
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+
+ STDMETHOD(GetSubStreamSize)(UInt64 subStream, UInt64 *value);
+};
+
+#endif
diff --git a/lzma/CPP/7zip/Archive/7z/7zUpdate.cpp b/lzma/CPP/7zip/Archive/7z/7zUpdate.cpp
new file mode 100644
index 0000000..87f3e0d
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/7z/7zUpdate.cpp
@@ -0,0 +1,1363 @@
+// 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 "../Common/OutStreamWithCRC.h"
+
+#include "7zDecode.h"
+#include "7zEncode.h"
+#include "7zFolderInStream.h"
+#include "7zHandler.h"
+#include "7zOut.h"
+#include "7zUpdate.h"
+
+namespace NArchive {
+namespace N7z {
+
+#ifdef MY_CPU_X86_OR_AMD64
+#define USE_86_FILTER
+#endif
+
+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);
+}
+
+static int GetReverseSlashPos(const UString &name)
+{
+ int slashPos = name.ReverseFind(L'/');
+ #ifdef _WIN32
+ int slash1Pos = name.ReverseFind(L'\\');
+ slashPos = MyMax(slashPos, slash1Pos);
+ #endif
+ return slashPos;
+}
+
+int CUpdateItem::GetExtensionPos() const
+{
+ int slashPos = GetReverseSlashPos(Name);
+ int dotPos = Name.ReverseFind(L'.');
+ if (dotPos < 0 || (dotPos < slashPos && slashPos >= 0))
+ 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 CompareBindPairs(const CBindPair &b1, const CBindPair &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.BindPairs.Size();
+ s2 = f2.BindPairs.Size();
+ RINOZ_COMP(s1, s2);
+ for (i = 0; i < s1; i++)
+ RINOZ(CompareBindPairs(f1.BindPairs[i], f2.BindPairs[i]));
+ return 0;
+}
+*/
+
+/*
+static int CompareFiles(const CFileItem &f1, const CFileItem &f2)
+{
+ return CompareFileNames(f1.Name, f2.Name);
+}
+*/
+
+struct CFolderRepack
+{
+ int FolderIndex;
+ int Group;
+ CNum NumCopyFiles;
+};
+
+static int CompareFolderRepacks(const CFolderRepack *p1, const CFolderRepack *p2, void * /* param */)
+{
+ RINOZ_COMP(p1->Group, p2->Group);
+ 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 int *p1, const int *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 =
+ " lzma 7z ace arc arj bz bz2 deb lzo lzx gz pak rpm sit tgz tbz tbz2 tgz cab ha lha lzh rar 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 rc java cs pas bas vb cls ctl frm dlg def"
+ " f77 f f90 f95"
+ " asm sql manifest dep "
+ " mak clw csproj vcproj sln dsp dsw "
+ " class "
+ " bat cmd"
+ " xml xsd xsl xslt hxk hxc htm html xhtml xht mht mhtml htw asp aspx css cgi jsp shtml"
+ " awk sed hta js php php3 php4 php5 phptml pl pm py pyo rb sh tcl 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 int GetExtIndex(const char *ext)
+{
+ int extIndex = 1;
+ const char *p = g_Exts;
+ for (;;)
+ {
+ char c = *p++;
+ if (c == 0)
+ return extIndex;
+ if (c == ' ')
+ continue;
+ int 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;
+ UInt32 ExtensionPos;
+ UInt32 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 = GetReverseSlashPos(ui.Name);
+ NamePos = slashPos + 1;
+ int dotPos = ui.Name.ReverseFind(L'.');
+ if (dotPos < 0 || 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;
+};
+
+static const wchar_t *g_ExeExts[] =
+{
+ L"dll"
+ , L"exe"
+ , L"ocx"
+ , L"sfx"
+ , L"sys"
+};
+
+static bool IsExeExt(const wchar_t *ext)
+{
+ for (int i = 0; i < ARRAY_SIZE(g_ExeExts); i++)
+ if (MyStringCompareNoCase(ext, g_ExeExts[i]) == 0)
+ return true;
+ return false;
+}
+
+
+static inline void GetMethodFull(UInt64 methodID, UInt32 numInStreams, CMethodFull &m)
+{
+ m.Id = methodID;
+ m.NumInStreams = numInStreams;
+ m.NumOutStreams = 1;
+}
+
+static void AddBcj2Methods(CCompressionMethodMode &mode)
+{
+ 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.AddPropString(NCoderPropID::kMatchFinder, L"BT2");
+
+ mode.Methods.Add(m);
+ mode.Methods.Add(m);
+
+ CBind bind;
+ bind.OutCoder = 0;
+ bind.InStream = 0;
+ bind.InCoder = 1; bind.OutStream = 0; mode.Binds.Add(bind);
+ bind.InCoder = 2; bind.OutStream = 1; mode.Binds.Add(bind);
+ bind.InCoder = 3; bind.OutStream = 2; mode.Binds.Add(bind);
+}
+
+static void MakeExeMethod(CCompressionMethodMode &mode,
+ bool useFilters, bool addFilter, bool bcj2Filter)
+{
+ if (!mode.Binds.IsEmpty() || !useFilters || mode.Methods.Size() > 2)
+ return;
+ if (mode.Methods.Size() == 2)
+ {
+ if (mode.Methods[0].Id == k_BCJ2)
+ AddBcj2Methods(mode);
+ return;
+ }
+ if (!addFilter)
+ return;
+ bcj2Filter = bcj2Filter;
+ #ifdef USE_86_FILTER
+ if (bcj2Filter)
+ {
+ CMethodFull m;
+ GetMethodFull(k_BCJ2, 4, m);
+ mode.Methods.Insert(0, m);
+ AddBcj2Methods(mode);
+ }
+ else
+ {
+ CMethodFull m;
+ GetMethodFull(k_BCJ, 1, m);
+ mode.Methods.Insert(0, m);
+ CBind bind;
+ bind.OutCoder = 0;
+ bind.InStream = 0;
+ bind.InCoder = 1;
+ bind.OutStream = 0;
+ mode.Binds.Add(bind);
+ }
+ #endif
+}
+
+
+static void FromUpdateItemToFileItem(const CUpdateItem &ui,
+ CFileItem &file, CFileItem2 &file2)
+{
+ if (ui.AttribDefined)
+ file.SetAttrib(ui.Attrib);
+
+ 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;
+
+ file.Size = ui.Size;
+ file.IsDir = ui.IsDir;
+ file.HasStream = ui.HasStream();
+ // file.IsAltStream = ui.IsAltStream;
+}
+
+class CFolderOutStream2:
+ public ISequentialOutStream,
+ public CMyUnknownImp
+{
+ COutStreamWithCRC *_crcStreamSpec;
+ CMyComPtr<ISequentialOutStream> _crcStream;
+ const CDbEx *_db;
+ const CBoolVector *_extractStatuses;
+ CMyComPtr<ISequentialOutStream> _outStream;
+ UInt32 _startIndex;
+ unsigned _currentIndex;
+ bool _fileIsOpen;
+ UInt64 _rem;
+
+ void OpenFile();
+ void CloseFile();
+ HRESULT CloseFileAndSetResult();
+ HRESULT ProcessEmptyFiles();
+public:
+ MY_UNKNOWN_IMP
+
+ CFolderOutStream2()
+ {
+ _crcStreamSpec = new COutStreamWithCRC;
+ _crcStream = _crcStreamSpec;
+ }
+
+ HRESULT Init(const CDbEx *db, UInt32 startIndex,
+ const CBoolVector *extractStatuses, ISequentialOutStream *outStream);
+ void ReleaseOutStream();
+ HRESULT CheckFinishedState() const { return (_currentIndex == _extractStatuses->Size()) ? S_OK: E_FAIL; }
+
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+};
+
+HRESULT CFolderOutStream2::Init(const CDbEx *db, UInt32 startIndex,
+ const CBoolVector *extractStatuses, ISequentialOutStream *outStream)
+{
+ _db = db;
+ _startIndex = startIndex;
+ _extractStatuses = extractStatuses;
+ _outStream = outStream;
+
+ _currentIndex = 0;
+ _fileIsOpen = false;
+ return ProcessEmptyFiles();
+}
+
+void CFolderOutStream2::ReleaseOutStream()
+{
+ _outStream.Release();
+ _crcStreamSpec->ReleaseStream();
+}
+
+void CFolderOutStream2::OpenFile()
+{
+ _crcStreamSpec->SetStream((*_extractStatuses)[_currentIndex] ? _outStream : NULL);
+ _crcStreamSpec->Init(true);
+ _fileIsOpen = true;
+ _rem = _db->Files[_startIndex + _currentIndex].Size;
+}
+
+void CFolderOutStream2::CloseFile()
+{
+ _crcStreamSpec->ReleaseStream();
+ _fileIsOpen = false;
+ _currentIndex++;
+}
+
+HRESULT CFolderOutStream2::CloseFileAndSetResult()
+{
+ const CFileItem &file = _db->Files[_startIndex + _currentIndex];
+ CloseFile();
+ return (file.IsDir || !file.CrcDefined || file.Crc == _crcStreamSpec->GetCRC()) ? S_OK: S_FALSE;
+}
+
+HRESULT CFolderOutStream2::ProcessEmptyFiles()
+{
+ while (_currentIndex < _extractStatuses->Size() && _db->Files[_startIndex + _currentIndex].Size == 0)
+ {
+ OpenFile();
+ RINOK(CloseFileAndSetResult());
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CFolderOutStream2::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize != NULL)
+ *processedSize = 0;
+ while (size != 0)
+ {
+ if (_fileIsOpen)
+ {
+ UInt32 cur = size < _rem ? size : (UInt32)_rem;
+ RINOK(_crcStream->Write(data, cur, &cur));
+ if (cur == 0)
+ break;
+ data = (const Byte *)data + cur;
+ size -= cur;
+ _rem -= cur;
+ if (processedSize != NULL)
+ *processedSize += cur;
+ if (_rem == 0)
+ {
+ RINOK(CloseFileAndSetResult());
+ RINOK(ProcessEmptyFiles());
+ continue;
+ }
+ }
+ else
+ {
+ RINOK(ProcessEmptyFiles());
+ if (_currentIndex == _extractStatuses->Size())
+ {
+ // we don't support partial extracting
+ return E_FAIL;
+ }
+ OpenFile();
+ }
+ }
+ return S_OK;
+}
+
+class CThreadDecoder: public CVirtThread
+{
+public:
+ HRESULT Result;
+ CMyComPtr<IInStream> InStream;
+
+ CFolderOutStream2 *FosSpec;
+ CMyComPtr<ISequentialOutStream> Fos;
+
+ UInt64 StartPos;
+ const CFolders *Folders;
+ int FolderIndex;
+ #ifndef _NO_CRYPTO
+ CMyComPtr<ICryptoGetTextPassword> getTextPassword;
+ #endif
+
+ DECL_EXTERNAL_CODECS_LOC_VARS2;
+ CDecoder Decoder;
+
+ #ifndef _7ZIP_ST
+ bool MtMode;
+ UInt32 NumThreads;
+ #endif
+
+ CThreadDecoder():
+ Decoder(true)
+ {
+ #ifndef _7ZIP_ST
+ MtMode = false;
+ NumThreads = 1;
+ #endif
+ FosSpec = new CFolderOutStream2;
+ Fos = FosSpec;
+ Result = E_FAIL;
+ }
+ ~CThreadDecoder() { CVirtThread::WaitThreadFinish(); }
+ virtual void Execute();
+};
+
+void CThreadDecoder::Execute()
+{
+ try
+ {
+ #ifndef _NO_CRYPTO
+ bool isEncrypted = false;
+ bool passwordIsDefined = false;
+ #endif
+
+ Result = Decoder.Decode(
+ EXTERNAL_CODECS_LOC_VARS
+ InStream,
+ StartPos,
+ *Folders, FolderIndex,
+ Fos,
+ NULL
+ _7Z_DECODER_CRYPRO_VARS
+ #ifndef _7ZIP_ST
+ , MtMode, NumThreads
+ #endif
+ );
+ }
+ catch(...)
+ {
+ Result = E_FAIL;
+ }
+ if (Result == S_OK)
+ Result = FosSpec->CheckFinishedState();
+ FosSpec->ReleaseOutStream();
+}
+
+bool static Is86FilteredFolder(const CFolder &f)
+{
+ FOR_VECTOR(i, f.Coders)
+ {
+ CMethodId m = f.Coders[i].MethodID;
+ if (m == k_BCJ || m == k_BCJ2)
+ return true;
+ }
+ return false;
+}
+
+#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 const int kNumGroupsMax = 4;
+
+static bool Is86Group(int group) { return (group & 1) != 0; }
+static bool IsEncryptedGroup(int group) { return (group & 2) != 0; }
+static int GetGroupIndex(bool encrypted, int bcjFiltered)
+ { return (encrypted ? 2 : 0) + (bcjFiltered ? 1 : 0); }
+
+static void GetFile(const CDatabase &inDb, int 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.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;
+
+ // 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 != 0 ? db->ArcInfo.StartPosition: 0;
+ if (startBlockSize > 0 && !options.RemoveSfxBlock)
+ {
+ RINOK(WriteRange(inStream, seqOutStream, 0, startBlockSize, NULL));
+ }
+
+ CIntArr fileIndexToUpdateIndexMap;
+ CRecordVector<CFolderRepack> folderRefs;
+ UInt64 complexity = 0;
+ UInt64 inSizeForReduce2 = 0;
+ bool needEncryptedRepack = false;
+ if (db != 0)
+ {
+ 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[index] = i;
+ }
+
+ for (i = 0; i < (int)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++)
+ {
+ 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;
+ CFolder f;
+ db->ParseFolderInfo(i, f);
+ bool isEncrypted = f.IsEncrypted();
+ rep.Group = GetGroupIndex(isEncrypted, Is86FilteredFolder(f));
+ folderRefs.Add(rep);
+ if (numCopyItems == numUnpackStreams)
+ complexity += db->GetFolderFullPackSize(i);
+ else
+ {
+ complexity += repackSize;
+ if (repackSize > inSizeForReduce2)
+ inSizeForReduce2 = repackSize;
+ if (isEncrypted)
+ needEncryptedRepack = true;
+ }
+ }
+ folderRefs.Sort(CompareFolderRepacks, (void *)db);
+ }
+
+ UInt64 inSizeForReduce = 0;
+ unsigned i;
+ for (i = 0; i < updateItems.Size(); i++)
+ {
+ const CUpdateItem &ui = updateItems[i];
+ if (ui.NewData)
+ {
+ complexity += ui.Size;
+ if (numSolidFiles != 1)
+ inSizeForReduce += ui.Size;
+ else if (ui.Size > inSizeForReduce)
+ inSizeForReduce = ui.Size;
+ }
+ }
+
+ if (inSizeForReduce2 > inSizeForReduce)
+ inSizeForReduce = inSizeForReduce2;
+
+ RINOK(updateCallback->SetTotal(complexity));
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(updateCallback, true);
+
+ CStreamBinder sb;
+ RINOK(sb.CreateEvents());
+
+ CThreadDecoder threadDecoder;
+ if (!folderRefs.IsEmpty())
+ {
+ #ifdef EXTERNAL_CODECS
+ threadDecoder.__externalCodecs = __externalCodecs;
+ #endif
+ RINOK(threadDecoder.Create());
+ }
+
+ CObjectVector<CSolidGroup> groups;
+ for (i = 0; i < kNumGroupsMax; i++)
+ groups.AddNew();
+
+ {
+ // ---------- Split files to groups ----------
+
+ bool useFilters = options.UseFilters;
+ const CCompressionMethodMode &method = *options.Method;
+ if (method.Methods.Size() != 1 || method.Binds.Size() != 0)
+ useFilters = false;
+ for (i = 0; i < updateItems.Size(); i++)
+ {
+ const CUpdateItem &ui = updateItems[i];
+ if (!ui.NewData || !ui.HasStream())
+ continue;
+ bool filteredGroup = false;
+ if (useFilters)
+ {
+ int dotPos = ui.Name.ReverseFind(L'.');
+ if (dotPos >= 0)
+ filteredGroup = IsExeExt(ui.Name.Ptr(dotPos + 1));
+ }
+ groups[GetGroupIndex(method.PasswordIsDefined, filteredGroup)].Indices.Add(i);
+ }
+ }
+
+ #ifndef _NO_CRYPTO
+
+ CCryptoGetTextPassword *getPasswordSpec = NULL;
+ if (needEncryptedRepack)
+ {
+ getPasswordSpec = new CCryptoGetTextPassword;
+ threadDecoder.getTextPassword = getPasswordSpec;
+
+ if (options.Method->PasswordIsDefined)
+ getPasswordSpec->Password = options.Method->Password;
+ else
+ {
+ if (!getDecoderPassword)
+ return E_NOTIMPL;
+ CMyComBSTR password;
+ RINOK(getDecoderPassword->CryptoGetTextPassword(&password));
+ if ((BSTR)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)
+ FromUpdateItemToFileItem(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 ---------- */
+ CRecordVector<int> emptyRefs;
+ 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)
+ {
+ FromUpdateItemToFileItem(ui, file, file2);
+ 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);
+ }
+ }
+
+ unsigned folderRefIndex = 0;
+ lps->ProgressOffset = 0;
+
+ for (int groupIndex = 0; groupIndex < kNumGroupsMax; groupIndex++)
+ {
+ const CSolidGroup &group = groups[groupIndex];
+
+ CCompressionMethodMode method = *options.Method;
+ MakeExeMethod(method, options.UseFilters, Is86Group(groupIndex), options.MaxFilter);
+
+ if (IsEncryptedGroup(groupIndex))
+ {
+ 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);
+
+ for (; folderRefIndex < folderRefs.Size(); folderRefIndex++)
+ {
+ const CFolderRepack &rep = folderRefs[folderRefIndex];
+ if (rep.Group != groupIndex)
+ break;
+ int folderIndex = rep.FolderIndex;
+
+ if (rep.NumCopyFiles == db->NumUnpackStreamsVector[folderIndex])
+ {
+ 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 (unsigned j = 0; j < folder.PackStreams.Size(); j++)
+ {
+ newDatabase.PackSizes.Add(db->GetStreamPackSize(startIndex + j));
+ // newDatabase.PackCRCsDefined.Add(db.PackCRCsDefined[startIndex + j]);
+ // newDatabase.PackCRCs.Add(db.PackCRCs[startIndex + j]);
+ }
+
+ UInt32 indexStart = db->FoToCoderUnpackSizes[folderIndex];
+ UInt32 indexEnd = db->FoToCoderUnpackSizes[folderIndex + 1];
+ for (; indexStart < indexEnd; indexStart++)
+ newDatabase.CoderUnpackSizes.Add(db->CoderUnpackSizes[indexStart]);
+ }
+ else
+ {
+ CBoolVector extractStatuses;
+
+ CNum numUnpackStreams = db->NumUnpackStreamsVector[folderIndex];
+ CNum indexInFolder = 0;
+
+ for (CNum fi = db->FolderStartFileIndex[folderIndex]; indexInFolder < numUnpackStreams; fi++)
+ {
+ bool needExtract = false;
+ if (db->Files[fi].HasStream)
+ {
+ indexInFolder++;
+ int updateIndex = fileIndexToUpdateIndexMap[fi];
+ if (updateIndex >= 0 && !updateItems[updateIndex].NewData)
+ needExtract = true;
+ }
+ extractStatuses.Add(needExtract);
+ }
+
+ unsigned startPackIndex = newDatabase.PackSizes.Size();
+ UInt64 curUnpackSize;
+ {
+ CMyComPtr<ISequentialInStream> sbInStream;
+ {
+ CMyComPtr<ISequentialOutStream> sbOutStream;
+ sb.CreateStreams(&sbInStream, &sbOutStream);
+ sb.ReInit();
+ RINOK(threadDecoder.FosSpec->Init(db, db->FolderStartFileIndex[folderIndex], &extractStatuses, sbOutStream));
+ }
+
+ threadDecoder.InStream = inStream;
+ threadDecoder.Folders = (const CFolders *)db;
+ threadDecoder.FolderIndex = folderIndex;
+ threadDecoder.StartPos = db->ArcInfo.DataStartPosition; // db->GetFolderStreamPos(folderIndex, 0);
+
+ threadDecoder.Start();
+
+ RINOK(encoder.Encode(
+ EXTERNAL_CODECS_LOC_VARS
+ sbInStream, NULL, &inSizeForReduce,
+ newDatabase.Folders.AddNew(), newDatabase.CoderUnpackSizes, curUnpackSize,
+ archive.SeqStream, newDatabase.PackSizes, progress));
+
+ threadDecoder.WaitExecuteFinish();
+ }
+
+ RINOK(threadDecoder.Result);
+
+ for (; startPackIndex < newDatabase.PackSizes.Size(); startPackIndex++)
+ lps->OutSize += newDatabase.PackSizes[startPackIndex];
+ lps->InSize += curUnpackSize;
+ }
+
+ newDatabase.NumUnpackStreamsVector.Add(rep.NumCopyFiles);
+
+ CNum numUnpackStreams = db->NumUnpackStreamsVector[folderIndex];
+
+ CNum indexInFolder = 0;
+ for (CNum fi = db->FolderStartFileIndex[folderIndex]; indexInFolder < numUnpackStreams; fi++)
+ {
+ CFileItem file;
+ CFileItem2 file2;
+ GetFile(*db, fi, file, file2);
+ UString name;
+ db->GetPath(fi, name);
+ if (file.HasStream)
+ {
+ indexInFolder++;
+ int updateIndex = fileIndexToUpdateIndexMap[fi];
+ if (updateIndex >= 0)
+ {
+ const CUpdateItem &ui = updateItems[updateIndex];
+ if (ui.NewData)
+ continue;
+ if (ui.NewProps)
+ {
+ CFileItem uf;
+ FromUpdateItemToFileItem(ui, uf, file2);
+ uf.Size = file.Size;
+ uf.Crc = file.Crc;
+ uf.CrcDefined = file.CrcDefined;
+ uf.HasStream = file.HasStream;
+ file = uf;
+ name = ui.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);
+ }
+ }
+ }
+ }
+
+ unsigned numFiles = group.Indices.Size();
+ if (numFiles == 0)
+ continue;
+ CRecordVector<CRefItem> refItems;
+ refItems.ClearAndSetSize(numFiles);
+ bool sortByType = (numSolidFiles > 1);
+ 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)
+ FromUpdateItemToFileItem(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;
+ int numSubFiles;
+ UString prevExtension;
+ 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)
+ {
+ UString ext = ui.GetExtension();
+ if (numSubFiles == 0)
+ prevExtension = ext;
+ else
+ if (!ext.IsEqualToNoCase(prevExtension))
+ break;
+ }
+ }
+ if (numSubFiles < 1)
+ numSubFiles = 1;
+
+ CFolderInStream *inStreamSpec = new CFolderInStream;
+ CMyComPtr<ISequentialInStream> solidInStream(inStreamSpec);
+ inStreamSpec->Init(updateCallback, &indices[i], numSubFiles);
+
+ unsigned startPackIndex = newDatabase.PackSizes.Size();
+ UInt64 curFolderUnpackSize;
+ RINOK(encoder.Encode(
+ EXTERNAL_CODECS_LOC_VARS
+ solidInStream, NULL, &inSizeForReduce,
+ newDatabase.Folders.AddNew(), newDatabase.CoderUnpackSizes, curFolderUnpackSize,
+ archive.SeqStream, newDatabase.PackSizes, progress));
+
+ 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;
+ for (int subIndex = 0; subIndex < numSubFiles; subIndex++)
+ {
+ const CUpdateItem &ui = updateItems[indices[i + subIndex]];
+ CFileItem file;
+ CFileItem2 file2;
+ UString name;
+ if (ui.NewProps)
+ {
+ FromUpdateItemToFileItem(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])
+ {
+ continue;
+ // file.Name += L".locked";
+ }
+
+ file.Crc = inStreamSpec->CRCs[subIndex];
+ file.Size = inStreamSpec->Sizes[subIndex];
+ 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 (folderRefIndex != folderRefs.Size())
+ return E_FAIL;
+
+ RINOK(lps->SetCur());
+
+ /*
+ folderRefs.ClearAndFree();
+ 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();
+ memcpy(newDatabase.SecureBuf + pos, buf, size);
+ newDatabase.SecureSizes.Add((UInt32)size);
+ pos += size;
+ }
+ }
+ */
+ newDatabase.ReserveDown();
+ return S_OK;
+}
+
+}}
diff --git a/lzma/CPP/7zip/Archive/7z/7zUpdate.h b/lzma/CPP/7zip/Archive/7z/7zUpdate.h
new file mode 100644
index 0000000..070bc30
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/7z/7zUpdate.h
@@ -0,0 +1,120 @@
+// 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; }
+
+ 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); };
+
+ int GetExtensionPos() const;
+ UString GetExtension() const;
+};
+
+struct CUpdateOptions
+{
+ const CCompressionMethodMode *Method;
+ const CCompressionMethodMode *HeaderMethod;
+ bool UseFilters;
+ bool MaxFilter;
+
+ CHeaderOptions HeaderOptions;
+
+ UInt64 NumSolidFiles;
+ UInt64 NumSolidBytes;
+ bool SolidExtension;
+ bool RemoveSfxBlock;
+ bool VolumeMode;
+};
+
+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
diff --git a/lzma/CPP/7zip/Archive/7z/StdAfx.cpp b/lzma/CPP/7zip/Archive/7z/StdAfx.cpp
new file mode 100644
index 0000000..c6d3b1f
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/7z/StdAfx.cpp
@@ -0,0 +1,3 @@
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/lzma/CPP/7zip/Archive/7z/StdAfx.h b/lzma/CPP/7zip/Archive/7z/StdAfx.h
new file mode 100644
index 0000000..59d9ac1
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/7z/StdAfx.h
@@ -0,0 +1,8 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "../../../Common/Common.h"
+
+#endif
diff --git a/lzma/CPP/7zip/Archive/Archive.def b/lzma/CPP/7zip/Archive/Archive.def
new file mode 100644
index 0000000..839245e
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/Archive.def
@@ -0,0 +1,6 @@
+EXPORTS
+ CreateObject PRIVATE
+ GetHandlerProperty PRIVATE
+ GetNumberOfFormats PRIVATE
+ GetHandlerProperty2 PRIVATE
+ CreateObject PRIVATE
diff --git a/lzma/CPP/7zip/Archive/Archive2.def b/lzma/CPP/7zip/Archive/Archive2.def
new file mode 100644
index 0000000..09bd9b9
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/Archive2.def
@@ -0,0 +1,11 @@
+EXPORTS
+ CreateObject PRIVATE
+ GetHandlerProperty PRIVATE
+ GetNumberOfFormats PRIVATE
+ GetHandlerProperty2 PRIVATE
+ GetNumberOfMethods PRIVATE
+ GetMethodProperty PRIVATE
+ GetHashers PRIVATE
+ SetLargePageMode PRIVATE
+ SetCaseSensitive PRIVATE
+ GetIsArc PRIVATE
\ No newline at end of file
diff --git a/lzma/CPP/7zip/Archive/ArchiveExports.cpp b/lzma/CPP/7zip/Archive/ArchiveExports.cpp
new file mode 100644
index 0000000..1295331
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/ArchiveExports.cpp
@@ -0,0 +1,149 @@
+// 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;
+ g_NumArcs++;
+ }
+}
+
+DEFINE_GUID(CLSID_CArchiveHandler,
+0x23170F69, 0x40C1, 0x278A, 0x10, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00);
+
+#define CLS_ARC_ID_ITEM(cls) ((cls).Data4[5])
+
+static inline HRESULT SetPropString(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 SetPropString((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]->ClassId == 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.ClassId;
+ 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.IsMultiSignature())
+ return SetPropString((const char *)arc.Signature, arc.SignatureSize, value);
+ break;
+ case NArchive::NHandlerPropID::kMultiSignature:
+ if (arc.IsMultiSignature())
+ return SetPropString((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;
+}
diff --git a/lzma/CPP/7zip/Archive/Common/CoderMixer2.cpp b/lzma/CPP/7zip/Archive/Common/CoderMixer2.cpp
new file mode 100644
index 0000000..ed82d98
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/Common/CoderMixer2.cpp
@@ -0,0 +1,119 @@
+// CoderMixer2.cpp
+
+#include "StdAfx.h"
+
+#include "CoderMixer2.h"
+
+namespace NCoderMixer {
+
+CBindReverseConverter::CBindReverseConverter(const CBindInfo &srcBindInfo):
+ _srcBindInfo(srcBindInfo)
+{
+ srcBindInfo.GetNumStreams(NumSrcInStreams, _numSrcOutStreams);
+
+ UInt32 j;
+ _srcInToDestOutMap.ClearAndSetSize(NumSrcInStreams);
+ DestOutToSrcInMap.ClearAndSetSize(NumSrcInStreams);
+
+ for (j = 0; j < NumSrcInStreams; j++)
+ {
+ _srcInToDestOutMap[j] = 0;
+ DestOutToSrcInMap[j] = 0;
+ }
+
+ _srcOutToDestInMap.ClearAndSetSize(_numSrcOutStreams);
+ _destInToSrcOutMap.ClearAndSetSize(_numSrcOutStreams);
+
+ for (j = 0; j < _numSrcOutStreams; j++)
+ {
+ _srcOutToDestInMap[j] = 0;
+ _destInToSrcOutMap[j] = 0;
+ }
+
+ UInt32 destInOffset = 0;
+ UInt32 destOutOffset = 0;
+ UInt32 srcInOffset = NumSrcInStreams;
+ UInt32 srcOutOffset = _numSrcOutStreams;
+
+ for (int i = srcBindInfo.Coders.Size() - 1; i >= 0; i--)
+ {
+ const CCoderStreamsInfo &srcCoderInfo = srcBindInfo.Coders[i];
+
+ srcInOffset -= srcCoderInfo.NumInStreams;
+ srcOutOffset -= srcCoderInfo.NumOutStreams;
+
+ UInt32 j;
+ for (j = 0; j < srcCoderInfo.NumInStreams; j++, destOutOffset++)
+ {
+ UInt32 index = srcInOffset + j;
+ _srcInToDestOutMap[index] = destOutOffset;
+ DestOutToSrcInMap[destOutOffset] = index;
+ }
+ for (j = 0; j < srcCoderInfo.NumOutStreams; j++, destInOffset++)
+ {
+ UInt32 index = srcOutOffset + j;
+ _srcOutToDestInMap[index] = destInOffset;
+ _destInToSrcOutMap[destInOffset] = index;
+ }
+ }
+}
+
+void CBindReverseConverter::CreateReverseBindInfo(CBindInfo &destBindInfo)
+{
+ destBindInfo.Coders.ClearAndReserve(_srcBindInfo.Coders.Size());
+ destBindInfo.BindPairs.ClearAndReserve(_srcBindInfo.BindPairs.Size());
+ destBindInfo.InStreams.ClearAndReserve(_srcBindInfo.OutStreams.Size());
+ destBindInfo.OutStreams.ClearAndReserve(_srcBindInfo.InStreams.Size());
+
+ unsigned i;
+ for (i = _srcBindInfo.Coders.Size(); i != 0;)
+ {
+ i--;
+ const CCoderStreamsInfo &srcCoderInfo = _srcBindInfo.Coders[i];
+ CCoderStreamsInfo destCoderInfo;
+ destCoderInfo.NumInStreams = srcCoderInfo.NumOutStreams;
+ destCoderInfo.NumOutStreams = srcCoderInfo.NumInStreams;
+ destBindInfo.Coders.AddInReserved(destCoderInfo);
+ }
+ for (i = _srcBindInfo.BindPairs.Size(); i != 0;)
+ {
+ i--;
+ const CBindPair &srcBindPair = _srcBindInfo.BindPairs[i];
+ CBindPair destBindPair;
+ destBindPair.InIndex = _srcOutToDestInMap[srcBindPair.OutIndex];
+ destBindPair.OutIndex = _srcInToDestOutMap[srcBindPair.InIndex];
+ destBindInfo.BindPairs.AddInReserved(destBindPair);
+ }
+ for (i = 0; i < _srcBindInfo.InStreams.Size(); i++)
+ destBindInfo.OutStreams.AddInReserved(_srcInToDestOutMap[_srcBindInfo.InStreams[i]]);
+ for (i = 0; i < _srcBindInfo.OutStreams.Size(); i++)
+ destBindInfo.InStreams.AddInReserved(_srcOutToDestInMap[_srcBindInfo.OutStreams[i]]);
+}
+
+void SetSizes(const UInt64 **srcSizes, CRecordVector<UInt64> &sizes,
+ CRecordVector<const UInt64 *> &sizePointers, UInt32 numItems)
+{
+ sizes.ClearAndSetSize(numItems);
+ sizePointers.ClearAndSetSize(numItems);
+ for(UInt32 i = 0; i < numItems; i++)
+ {
+ if (!srcSizes || !srcSizes[i])
+ {
+ sizes[i] = 0;
+ sizePointers[i] = NULL;
+ }
+ else
+ {
+ sizes[i] = *(srcSizes[i]);
+ sizePointers[i] = &sizes[i];
+ }
+ }
+}
+
+void CCoderInfo2::SetCoderInfo(const UInt64 **inSizes, const UInt64 **outSizes)
+{
+ SetSizes(inSizes, InSizes, InSizePointers, NumInStreams);
+ SetSizes(outSizes, OutSizes, OutSizePointers, NumOutStreams);
+}
+
+}
diff --git a/lzma/CPP/7zip/Archive/Common/CoderMixer2.h b/lzma/CPP/7zip/Archive/Common/CoderMixer2.h
new file mode 100644
index 0000000..7618bb2
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/Common/CoderMixer2.h
@@ -0,0 +1,179 @@
+// CoderMixer2.h
+
+#ifndef __CODER_MIXER2_H
+#define __CODER_MIXER2_H
+
+#include "../../../Common/MyCom.h"
+#include "../../../Common/MyVector.h"
+
+#include "../../ICoder.h"
+
+namespace NCoderMixer {
+
+struct CBindPair
+{
+ UInt32 InIndex;
+ UInt32 OutIndex;
+};
+
+struct CCoderStreamsInfo
+{
+ UInt32 NumInStreams;
+ UInt32 NumOutStreams;
+};
+
+struct CBindInfo
+{
+ CRecordVector<CCoderStreamsInfo> Coders;
+ CRecordVector<CBindPair> BindPairs;
+ CRecordVector<UInt32> InStreams;
+ CRecordVector<UInt32> OutStreams;
+
+ void Clear()
+ {
+ Coders.Clear();
+ BindPairs.Clear();
+ InStreams.Clear();
+ OutStreams.Clear();
+ }
+
+ /*
+ UInt32 GetCoderStartOutStream(UInt32 coderIndex) const
+ {
+ UInt32 numOutStreams = 0;
+ for (UInt32 i = 0; i < coderIndex; i++)
+ numOutStreams += Coders[i].NumOutStreams;
+ return numOutStreams;
+ }
+ */
+
+
+ void GetNumStreams(UInt32 &numInStreams, UInt32 &numOutStreams) const
+ {
+ numInStreams = 0;
+ numOutStreams = 0;
+ FOR_VECTOR (i, Coders)
+ {
+ const CCoderStreamsInfo &coderStreamsInfo = Coders[i];
+ numInStreams += coderStreamsInfo.NumInStreams;
+ numOutStreams += coderStreamsInfo.NumOutStreams;
+ }
+ }
+
+ int FindBinderForInStream(UInt32 inStream) const
+ {
+ FOR_VECTOR (i, BindPairs)
+ if (BindPairs[i].InIndex == inStream)
+ return i;
+ return -1;
+ }
+ int FindBinderForOutStream(UInt32 outStream) const
+ {
+ FOR_VECTOR (i, BindPairs)
+ if (BindPairs[i].OutIndex == outStream)
+ return i;
+ return -1;
+ }
+
+ UInt32 GetCoderInStreamIndex(UInt32 coderIndex) const
+ {
+ UInt32 streamIndex = 0;
+ for (UInt32 i = 0; i < coderIndex; i++)
+ streamIndex += Coders[i].NumInStreams;
+ return streamIndex;
+ }
+
+ UInt32 GetCoderOutStreamIndex(UInt32 coderIndex) const
+ {
+ UInt32 streamIndex = 0;
+ for (UInt32 i = 0; i < coderIndex; i++)
+ streamIndex += Coders[i].NumOutStreams;
+ return streamIndex;
+ }
+
+
+ void FindInStream(UInt32 streamIndex, UInt32 &coderIndex,
+ UInt32 &coderStreamIndex) const
+ {
+ for (coderIndex = 0; coderIndex < (UInt32)Coders.Size(); coderIndex++)
+ {
+ UInt32 curSize = Coders[coderIndex].NumInStreams;
+ if (streamIndex < curSize)
+ {
+ coderStreamIndex = streamIndex;
+ return;
+ }
+ streamIndex -= curSize;
+ }
+ throw 1;
+ }
+ void FindOutStream(UInt32 streamIndex, UInt32 &coderIndex,
+ UInt32 &coderStreamIndex) const
+ {
+ for (coderIndex = 0; coderIndex < (UInt32)Coders.Size(); coderIndex++)
+ {
+ UInt32 curSize = Coders[coderIndex].NumOutStreams;
+ if (streamIndex < curSize)
+ {
+ coderStreamIndex = streamIndex;
+ return;
+ }
+ streamIndex -= curSize;
+ }
+ throw 1;
+ }
+};
+
+class CBindReverseConverter
+{
+ UInt32 _numSrcOutStreams;
+ NCoderMixer::CBindInfo _srcBindInfo;
+ CRecordVector<UInt32> _srcInToDestOutMap;
+ CRecordVector<UInt32> _srcOutToDestInMap;
+ CRecordVector<UInt32> _destInToSrcOutMap;
+public:
+ UInt32 NumSrcInStreams;
+ CRecordVector<UInt32> DestOutToSrcInMap;
+
+ CBindReverseConverter(const NCoderMixer::CBindInfo &srcBindInfo);
+ void CreateReverseBindInfo(NCoderMixer::CBindInfo &destBindInfo);
+};
+
+void SetSizes(const UInt64 **srcSizes, CRecordVector<UInt64> &sizes,
+ CRecordVector<const UInt64 *> &sizePointers, UInt32 numItems);
+
+struct CCoderInfo2
+{
+ CMyComPtr<ICompressCoder> Coder;
+ CMyComPtr<ICompressCoder2> Coder2;
+ UInt32 NumInStreams;
+ UInt32 NumOutStreams;
+
+ CRecordVector<UInt64> InSizes;
+ CRecordVector<UInt64> OutSizes;
+ CRecordVector<const UInt64 *> InSizePointers;
+ CRecordVector<const UInt64 *> OutSizePointers;
+
+ CCoderInfo2(UInt32 numInStreams, UInt32 numOutStreams):
+ NumInStreams(numInStreams),
+ NumOutStreams(numOutStreams) {}
+ void SetCoderInfo(const UInt64 **inSizes, const UInt64 **outSizes);
+
+ HRESULT QueryInterface(REFGUID iid, void** pp) const
+ {
+ IUnknown *p = Coder ? (IUnknown *)Coder : (IUnknown *)Coder2;
+ return p->QueryInterface(iid, pp);
+ }
+};
+
+class CCoderMixer2
+{
+public:
+ virtual HRESULT SetBindInfo(const CBindInfo &bindInfo) = 0;
+ virtual void ReInit() = 0;
+ virtual void SetCoderInfo(UInt32 coderIndex, const UInt64 **inSizes, const UInt64 **outSizes) = 0;
+};
+
+}
+
+#endif
diff --git a/lzma/CPP/7zip/Archive/Common/CoderMixer2MT.cpp b/lzma/CPP/7zip/Archive/Common/CoderMixer2MT.cpp
new file mode 100644
index 0000000..1e9c13e
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/Common/CoderMixer2MT.cpp
@@ -0,0 +1,218 @@
+// CoderMixer2MT.cpp
+
+#include "StdAfx.h"
+
+#include "CoderMixer2MT.h"
+
+namespace NCoderMixer {
+
+CCoder2::CCoder2(UInt32 numInStreams, UInt32 numOutStreams):
+ CCoderInfo2(numInStreams, numOutStreams)
+{
+ InStreams.ClearAndReserve(NumInStreams);
+ OutStreams.ClearAndReserve(NumOutStreams);
+}
+
+void CCoder2::Execute() { Code(NULL); }
+
+void CCoder2::Code(ICompressProgressInfo *progress)
+{
+ InStreamPointers.ClearAndReserve(NumInStreams);
+ OutStreamPointers.ClearAndReserve(NumOutStreams);
+ UInt32 i;
+ for (i = 0; i < NumInStreams; i++)
+ {
+ if (InSizePointers[i])
+ InSizePointers[i] = &InSizes[i];
+ InStreamPointers.AddInReserved((ISequentialInStream *)InStreams[i]);
+ }
+ for (i = 0; i < NumOutStreams; i++)
+ {
+ if (OutSizePointers[i])
+ OutSizePointers[i] = &OutSizes[i];
+ OutStreamPointers.AddInReserved((ISequentialOutStream *)OutStreams[i]);
+ }
+ if (Coder)
+ Result = Coder->Code(InStreamPointers[0], OutStreamPointers[0],
+ InSizePointers[0], OutSizePointers[0], progress);
+ else
+ Result = Coder2->Code(&InStreamPointers.Front(), &InSizePointers.Front(), NumInStreams,
+ &OutStreamPointers.Front(), &OutSizePointers.Front(), NumOutStreams, progress);
+ {
+ unsigned i;
+ for (i = 0; i < InStreams.Size(); i++)
+ InStreams[i].Release();
+ for (i = 0; i < OutStreams.Size(); i++)
+ OutStreams[i].Release();
+ }
+}
+
+/*
+void CCoder2::SetCoderInfo(const UInt64 **inSizes, const UInt64 **outSizes)
+{
+ SetSizes(inSizes, InSizes, InSizePointers, NumInStreams);
+ SetSizes(outSizes, OutSizes, OutSizePointers, NumOutStreams);
+}
+*/
+
+//////////////////////////////////////
+// CCoderMixer2MT
+
+HRESULT CCoderMixer2MT::SetBindInfo(const CBindInfo &bindInfo)
+{
+ _bindInfo = bindInfo;
+ _streamBinders.Clear();
+ FOR_VECTOR (i, _bindInfo.BindPairs)
+ {
+ RINOK(_streamBinders.AddNew().CreateEvents());
+ }
+ return S_OK;
+}
+
+void CCoderMixer2MT::AddCoderCommon()
+{
+ const CCoderStreamsInfo &c = _bindInfo.Coders[_coders.Size()];
+ CCoder2 threadCoderInfo(c.NumInStreams, c.NumOutStreams);
+ _coders.Add(threadCoderInfo);
+}
+
+void CCoderMixer2MT::AddCoder(ICompressCoder *coder)
+{
+ AddCoderCommon();
+ _coders.Back().Coder = coder;
+}
+
+void CCoderMixer2MT::AddCoder2(ICompressCoder2 *coder)
+{
+ AddCoderCommon();
+ _coders.Back().Coder2 = coder;
+}
+
+
+void CCoderMixer2MT::ReInit()
+{
+ FOR_VECTOR (i, _streamBinders)
+ _streamBinders[i].ReInit();
+}
+
+
+HRESULT CCoderMixer2MT::Init(ISequentialInStream **inStreams, ISequentialOutStream **outStreams)
+{
+ /*
+ if (_coders.Size() != _bindInfo.Coders.Size())
+ throw 0;
+ */
+ unsigned i;
+ for (i = 0; i < _coders.Size(); i++)
+ {
+ CCoder2 &coderInfo = _coders[i];
+ const CCoderStreamsInfo &coderStreamsInfo = _bindInfo.Coders[i];
+ coderInfo.InStreams.Clear();
+ UInt32 j;
+ for (j = 0; j < coderStreamsInfo.NumInStreams; j++)
+ coderInfo.InStreams.Add(NULL);
+ coderInfo.OutStreams.Clear();
+ for (j = 0; j < coderStreamsInfo.NumOutStreams; j++)
+ coderInfo.OutStreams.Add(NULL);
+ }
+
+ for (i = 0; i < _bindInfo.BindPairs.Size(); i++)
+ {
+ const CBindPair &bindPair = _bindInfo.BindPairs[i];
+ UInt32 inCoderIndex, inCoderStreamIndex;
+ UInt32 outCoderIndex, outCoderStreamIndex;
+ _bindInfo.FindInStream(bindPair.InIndex, inCoderIndex, inCoderStreamIndex);
+ _bindInfo.FindOutStream(bindPair.OutIndex, outCoderIndex, outCoderStreamIndex);
+
+ _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);
+ }
+ }
+
+ for (i = 0; i < _bindInfo.InStreams.Size(); i++)
+ {
+ UInt32 inCoderIndex, inCoderStreamIndex;
+ _bindInfo.FindInStream(_bindInfo.InStreams[i], inCoderIndex, inCoderStreamIndex);
+ _coders[inCoderIndex].InStreams[inCoderStreamIndex] = inStreams[i];
+ }
+
+ for (i = 0; i < _bindInfo.OutStreams.Size(); i++)
+ {
+ UInt32 outCoderIndex, outCoderStreamIndex;
+ _bindInfo.FindOutStream(_bindInfo.OutStreams[i], outCoderIndex, outCoderStreamIndex);
+ _coders[outCoderIndex].OutStreams[outCoderStreamIndex] = outStreams[i];
+ }
+ return S_OK;
+}
+
+HRESULT CCoderMixer2MT::ReturnIfError(HRESULT code)
+{
+ FOR_VECTOR (i, _coders)
+ if (_coders[i].Result == code)
+ return code;
+ return S_OK;
+}
+
+STDMETHODIMP CCoderMixer2MT::Code(ISequentialInStream **inStreams,
+ const UInt64 ** /* inSizes */,
+ UInt32 numInStreams,
+ ISequentialOutStream **outStreams,
+ const UInt64 ** /* outSizes */,
+ UInt32 numOutStreams,
+ ICompressProgressInfo *progress)
+{
+ if (numInStreams != (UInt32)_bindInfo.InStreams.Size() ||
+ numOutStreams != (UInt32)_bindInfo.OutStreams.Size())
+ return E_INVALIDARG;
+
+ Init(inStreams, outStreams);
+
+ unsigned i;
+ for (i = 0; i < _coders.Size(); i++)
+ if (i != _progressCoderIndex)
+ {
+ RINOK(_coders[i].Create());
+ }
+
+ for (i = 0; i < _coders.Size(); i++)
+ if (i != _progressCoderIndex)
+ _coders[i].Start();
+
+ _coders[_progressCoderIndex].Code(progress);
+
+ for (i = 0; i < _coders.Size(); i++)
+ if (i != _progressCoderIndex)
+ _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 != E_FAIL && result != S_FALSE)
+ return result;
+ }
+
+ RINOK(ReturnIfError(S_FALSE));
+
+ for (i = 0; i < _coders.Size(); i++)
+ {
+ HRESULT result = _coders[i].Result;
+ if (result != S_OK)
+ return result;
+ }
+ return S_OK;
+}
+
+}
diff --git a/lzma/CPP/7zip/Archive/Common/CoderMixer2MT.h b/lzma/CPP/7zip/Archive/Common/CoderMixer2MT.h
new file mode 100644
index 0000000..78d0c19
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/Common/CoderMixer2MT.h
@@ -0,0 +1,83 @@
+// CoderMixer2MT.h
+
+#ifndef __CODER_MIXER2_MT_H
+#define __CODER_MIXER2_MT_H
+
+#include "CoderMixer2.h"
+#include "../../../Common/MyCom.h"
+#include "../../Common/StreamBinder.h"
+#include "../../Common/VirtThread.h"
+
+namespace NCoderMixer {
+
+struct CCoder2: public CCoderInfo2, public CVirtThread
+{
+ CRecordVector<ISequentialInStream*> InStreamPointers;
+ CRecordVector<ISequentialOutStream*> OutStreamPointers;
+
+public:
+ HRESULT Result;
+ CObjectVector< CMyComPtr<ISequentialInStream> > InStreams;
+ CObjectVector< CMyComPtr<ISequentialOutStream> > OutStreams;
+
+ CCoder2(UInt32 numInStreams, UInt32 numOutStreams);
+ ~CCoder2() { CVirtThread::WaitThreadFinish(); }
+ // void SetCoderInfo(const UInt64 **inSizes, const UInt64 **outSizes);
+ virtual void Execute();
+ void Code(ICompressProgressInfo *progress);
+};
+
+
+/*
+ SetBindInfo()
+ for each coder
+ AddCoder[2]()
+ SetProgressIndex(UInt32 coderIndex);
+
+ for each file
+ {
+ ReInit()
+ for each coder
+ SetCoderInfo
+ Code
+ }
+*/
+
+class CCoderMixer2MT:
+ public ICompressCoder2,
+ public CCoderMixer2,
+ public CMyUnknownImp
+{
+ CBindInfo _bindInfo;
+ CObjectVector<CStreamBinder> _streamBinders;
+ unsigned _progressCoderIndex;
+
+ void AddCoderCommon();
+ HRESULT Init(ISequentialInStream **inStreams, ISequentialOutStream **outStreams);
+ HRESULT ReturnIfError(HRESULT code);
+public:
+ CObjectVector<CCoder2> _coders;
+ MY_UNKNOWN_IMP
+
+ STDMETHOD(Code)(ISequentialInStream **inStreams,
+ const UInt64 **inSizes,
+ UInt32 numInStreams,
+ ISequentialOutStream **outStreams,
+ const UInt64 **outSizes,
+ UInt32 numOutStreams,
+ ICompressProgressInfo *progress);
+
+ HRESULT SetBindInfo(const CBindInfo &bindInfo);
+ void AddCoder(ICompressCoder *coder);
+ void AddCoder2(ICompressCoder2 *coder);
+ void SetProgressCoderIndex(unsigned coderIndex) { _progressCoderIndex = coderIndex; }
+
+ void ReInit();
+ void SetCoderInfo(UInt32 coderIndex, const UInt64 **inSizes, const UInt64 **outSizes)
+ { _coders[coderIndex].SetCoderInfo(inSizes, outSizes); }
+ UInt64 GetWriteProcessedSize(UInt32 binderIndex) const
+ { return _streamBinders[binderIndex].ProcessedSize; }
+};
+
+}
+#endif
diff --git a/lzma/CPP/7zip/Archive/Common/CrossThreadProgress.cpp b/lzma/CPP/7zip/Archive/Common/CrossThreadProgress.cpp
new file mode 100644
index 0000000..62d05af
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/Common/CrossThreadProgress.cpp
@@ -0,0 +1,15 @@
+// CrossThreadProgress.cpp
+
+#include "StdAfx.h"
+
+#include "CrossThreadProgress.h"
+
+STDMETHODIMP CCrossThreadProgress::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)
+{
+ InSize = inSize;
+ OutSize = outSize;
+ ProgressEvent.Set();
+ WaitEvent.Lock();
+ return Result;
+}
+
diff --git a/lzma/CPP/7zip/Archive/Common/CrossThreadProgress.h b/lzma/CPP/7zip/Archive/Common/CrossThreadProgress.h
new file mode 100644
index 0000000..d414958
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/Common/CrossThreadProgress.h
@@ -0,0 +1,37 @@
+// CrossThreadProgress.h
+
+#ifndef __CROSSTHREADPROGRESS_H
+#define __CROSSTHREADPROGRESS_H
+
+#include "../../ICoder.h"
+#include "../../../Windows/Synchronization.h"
+#include "../../../Common/MyCom.h"
+
+class CCrossThreadProgress:
+ public ICompressProgressInfo,
+ public CMyUnknownImp
+{
+public:
+ const UInt64 *InSize;
+ const UInt64 *OutSize;
+ HRESULT Result;
+ NWindows::NSynchronization::CAutoResetEvent ProgressEvent;
+ NWindows::NSynchronization::CAutoResetEvent WaitEvent;
+
+ HRes Create()
+ {
+ RINOK(ProgressEvent.CreateIfNotCreated());
+ return WaitEvent.CreateIfNotCreated();
+ }
+ void Init()
+ {
+ ProgressEvent.Reset();
+ WaitEvent.Reset();
+ }
+
+ MY_UNKNOWN_IMP
+
+ STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
+};
+
+#endif
diff --git a/lzma/CPP/7zip/Archive/Common/DummyOutStream.cpp b/lzma/CPP/7zip/Archive/Common/DummyOutStream.cpp
new file mode 100644
index 0000000..c7d45e7
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/Common/DummyOutStream.cpp
@@ -0,0 +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;
+}
diff --git a/lzma/CPP/7zip/Archive/Common/DummyOutStream.h b/lzma/CPP/7zip/Archive/Common/DummyOutStream.h
new file mode 100644
index 0000000..30e84c5
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/Common/DummyOutStream.h
@@ -0,0 +1,25 @@
+// 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
diff --git a/lzma/CPP/7zip/Archive/Common/HandlerOut.cpp b/lzma/CPP/7zip/Archive/Common/HandlerOut.cpp
new file mode 100644
index 0000000..2c920bc
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/Common/HandlerOut.cpp
@@ -0,0 +1,141 @@
+// HandlerOut.cpp
+
+#include "StdAfx.h"
+
+#ifndef _7ZIP_ST
+#include "../../../Windows/System.h"
+#endif
+
+#include "../Common/ParseProperties.h"
+
+#include "HandlerOut.h"
+
+using namespace NWindows;
+
+namespace NArchive {
+
+static void SetMethodProp32(COneMethodInfo &m, PROPID propID, UInt32 value)
+{
+ if (m.FindProp(propID) < 0)
+ m.AddProp32(propID, value);
+}
+
+void CMultiMethodProps::SetGlobalLevelAndThreads(COneMethodInfo &oneMethodInfo
+ #ifndef _7ZIP_ST
+ , UInt32 numThreads
+ #endif
+ )
+{
+ UInt32 level = _level;
+ if (level != (UInt32)(Int32)-1)
+ SetMethodProp32(oneMethodInfo, NCoderPropID::kLevel, (UInt32)level);
+ #ifndef _7ZIP_ST
+ SetMethodProp32(oneMethodInfo, NCoderPropID::kNumThreads, numThreads);
+ #endif
+}
+
+void CMultiMethodProps::Init()
+{
+ #ifndef _7ZIP_ST
+ _numProcessors = _numThreads = NSystem::GetNumberOfProcessors();
+ #endif
+
+ _level = (UInt32)(Int32)-1;
+ _autoFilter = true;
+ _crcSize = 4;
+ _filterMethod.Clear();
+ _methods.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 == L"crc")
+ {
+ name.Delete(0, 3);
+ _crcSize = 4;
+ return ParsePropToUInt32(name, value, _crcSize);
+ }
+
+ UInt32 number;
+ int index = ParseStringToUInt32(name, number);
+ UString realName = name.Ptr(index);
+ if (index == 0)
+ {
+ if (name.IsPrefixedBy(L"mt"))
+ {
+ #ifndef _7ZIP_ST
+ RINOK(ParseMtProp(name.Ptr(2), value, _numProcessors, _numThreads));
+ #endif
+ return S_OK;
+ }
+ 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(L"", 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()
+{
+ Clear();
+ #ifndef _7ZIP_ST
+ _numProcessors = _numThreads = NWindows::NSystem::GetNumberOfProcessors();
+ AddNumThreadsProp(_numThreads);
+ #endif
+ _level = (UInt32)(Int32)-1;
+}
+
+HRESULT CSingleMethodProps::SetProperties(const wchar_t **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;
+ AddLevelProp(a);
+ }
+ else if (name.IsPrefixedBy(L"mt"))
+ {
+ #ifndef _7ZIP_ST
+ RINOK(ParseMtProp(name.Ptr(2), value, _numProcessors, _numThreads));
+ AddNumThreadsProp(_numThreads);
+ #endif
+ }
+ else
+ return ParseMethodFromPROPVARIANT(names[i], value);
+ }
+ return S_OK;
+}
+
+}
diff --git a/lzma/CPP/7zip/Archive/Common/HandlerOut.h b/lzma/CPP/7zip/Archive/Common/HandlerOut.h
new file mode 100644
index 0000000..8fc3d26
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/Common/HandlerOut.h
@@ -0,0 +1,65 @@
+// HandlerOut.h
+
+#ifndef __HANDLER_OUT_H
+#define __HANDLER_OUT_H
+
+#include "../../Common/MethodProps.h"
+
+namespace NArchive {
+
+class CMultiMethodProps
+{
+ UInt32 _level;
+public:
+ #ifndef _7ZIP_ST
+ UInt32 _numThreads;
+ UInt32 _numProcessors;
+ #endif
+
+ UInt32 _crcSize;
+ CObjectVector<COneMethodInfo> _methods;
+ COneMethodInfo _filterMethod;
+ bool _autoFilter;
+
+ void SetGlobalLevelAndThreads(COneMethodInfo &oneMethodInfo
+ #ifndef _7ZIP_ST
+ , 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; }
+
+ void Init();
+
+ CMultiMethodProps() { Init(); }
+ HRESULT SetProperty(const wchar_t *name, const PROPVARIANT &value);
+};
+
+class CSingleMethodProps: public COneMethodInfo
+{
+ UInt32 _level;
+
+public:
+ #ifndef _7ZIP_ST
+ UInt32 _numThreads;
+ UInt32 _numProcessors;
+ #endif
+
+ void Init();
+ CSingleMethodProps() { Init(); }
+ int GetLevel() const { return _level == (UInt32)(Int32)-1 ? 5 : (int)_level; }
+ HRESULT SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps);
+};
+
+}
+
+#endif
diff --git a/lzma/CPP/7zip/Archive/Common/InStreamWithCRC.cpp b/lzma/CPP/7zip/Archive/Common/InStreamWithCRC.cpp
new file mode 100644
index 0000000..cddc083
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/Common/InStreamWithCRC.cpp
@@ -0,0 +1,46 @@
+// 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);
+}
diff --git a/lzma/CPP/7zip/Archive/Common/InStreamWithCRC.h b/lzma/CPP/7zip/Archive/Common/InStreamWithCRC.h
new file mode 100644
index 0000000..1a4b2c9
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/Common/InStreamWithCRC.h
@@ -0,0 +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
diff --git a/lzma/CPP/7zip/Archive/Common/ItemNameUtils.cpp b/lzma/CPP/7zip/Archive/Common/ItemNameUtils.cpp
new file mode 100644
index 0000000..1608949
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/Common/ItemNameUtils.cpp
@@ -0,0 +1,88 @@
+// Archive/Common/ItemNameUtils.cpp
+
+#include "StdAfx.h"
+
+#include "ItemNameUtils.h"
+
+namespace NArchive {
+namespace NItemName {
+
+static const wchar_t kOSDirDelimiter = WCHAR_PATH_SEPARATOR;
+static const wchar_t kDirDelimiter = L'/';
+
+void ReplaceToOsPathSeparator(wchar_t *s)
+{
+ #ifdef _WIN32
+ for (;;)
+ {
+ wchar_t c = *s;
+ if (c == 0)
+ break;
+ if (c == kDirDelimiter)
+ *s = kOSDirDelimiter;
+ s++;
+ }
+ #endif
+}
+
+UString MakeLegalName(const UString &name)
+{
+ UString zipName = name;
+ zipName.Replace(kOSDirDelimiter, kDirDelimiter);
+ return zipName;
+}
+
+UString GetOSName(const UString &name)
+{
+ UString newName = name;
+ newName.Replace(kDirDelimiter, kOSDirDelimiter);
+ return newName;
+}
+
+UString GetOSName2(const UString &name)
+{
+ if (name.IsEmpty())
+ return UString();
+ UString newName = GetOSName(name);
+ if (newName.Back() == kOSDirDelimiter)
+ newName.DeleteBack();
+ return newName;
+}
+
+void ConvertToOSName2(UString &name)
+{
+ if (!name.IsEmpty())
+ {
+ name.Replace(kDirDelimiter, kOSDirDelimiter);
+ if (name.Back() == kOSDirDelimiter)
+ name.DeleteBack();
+ }
+}
+
+bool HasTailSlash(const AString &name, UINT
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ codePage
+ #endif
+ )
+{
+ if (name.IsEmpty())
+ return false;
+ LPCSTR prev =
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ CharPrevExA((WORD)codePage, name, &name[name.Len()], 0);
+ #else
+ (LPCSTR)(name) + (name.Len() - 1);
+ #endif
+ return (*prev == '/');
+}
+
+#ifndef _WIN32
+UString WinNameToOSName(const UString &name)
+{
+ UString newName = name;
+ newName.Replace(L'\\', kOSDirDelimiter);
+ return newName;
+}
+#endif
+
+}}
diff --git a/lzma/CPP/7zip/Archive/Common/ItemNameUtils.h b/lzma/CPP/7zip/Archive/Common/ItemNameUtils.h
new file mode 100644
index 0000000..8ee2d0f
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/Common/ItemNameUtils.h
@@ -0,0 +1,27 @@
+// 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 ReplaceToOsPathSeparator(wchar_t *s);
+
+ UString MakeLegalName(const UString &name);
+ UString GetOSName(const UString &name);
+ UString GetOSName2(const UString &name);
+ void ConvertToOSName2(UString &name);
+ bool HasTailSlash(const AString &name, UINT codePage);
+
+ #ifdef _WIN32
+ inline UString WinNameToOSName(const UString &name) { return name; }
+ #else
+ UString WinNameToOSName(const UString &name);
+ #endif
+
+}}
+
+#endif
diff --git a/lzma/CPP/7zip/Archive/Common/MultiStream.cpp b/lzma/CPP/7zip/Archive/Common/MultiStream.cpp
new file mode 100644
index 0000000..3613ab2
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/Common/MultiStream.cpp
@@ -0,0 +1,191 @@
+// 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 != NULL)
+ *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 != NULL)
+ *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;
+}
+*/
diff --git a/lzma/CPP/7zip/Archive/Common/MultiStream.h b/lzma/CPP/7zip/Archive/Common/MultiStream.h
new file mode 100644
index 0000000..39e041d
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/Common/MultiStream.h
@@ -0,0 +1,89 @@
+// 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
diff --git a/lzma/CPP/7zip/Archive/Common/OutStreamWithCRC.cpp b/lzma/CPP/7zip/Archive/Common/OutStreamWithCRC.cpp
new file mode 100644
index 0000000..e0d3894
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/Common/OutStreamWithCRC.cpp
@@ -0,0 +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;
+}
diff --git a/lzma/CPP/7zip/Archive/Common/OutStreamWithCRC.h b/lzma/CPP/7zip/Archive/Common/OutStreamWithCRC.h
new file mode 100644
index 0000000..0cc9a85
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/Common/OutStreamWithCRC.h
@@ -0,0 +1,37 @@
+// 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
diff --git a/lzma/CPP/7zip/Archive/Common/ParseProperties.cpp b/lzma/CPP/7zip/Archive/Common/ParseProperties.cpp
new file mode 100644
index 0000000..0fe89b3
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/Common/ParseProperties.cpp
@@ -0,0 +1,3 @@
+// ParseProperties.cpp
+
+#include "StdAfx.h"
diff --git a/lzma/CPP/7zip/Archive/Common/ParseProperties.h b/lzma/CPP/7zip/Archive/Common/ParseProperties.h
new file mode 100644
index 0000000..f4367a7
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/Common/ParseProperties.h
@@ -0,0 +1,6 @@
+// ParseProperties.h
+
+#ifndef __PARSE_PROPERTIES_H
+#define __PARSE_PROPERTIES_H
+
+#endif
diff --git a/lzma/CPP/7zip/Archive/Common/StdAfx.h b/lzma/CPP/7zip/Archive/Common/StdAfx.h
new file mode 100644
index 0000000..59d9ac1
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/Common/StdAfx.h
@@ -0,0 +1,8 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "../../../Common/Common.h"
+
+#endif
diff --git a/lzma/CPP/7zip/Archive/DllExports2.cpp b/lzma/CPP/7zip/Archive/DllExports2.cpp
new file mode 100644
index 0000000..4267d46
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/DllExports2.cpp
@@ -0,0 +1,82 @@
+// DLLExports2.cpp
+
+#include "StdAfx.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 "IArchive.h"
+
+HINSTANCE g_hInstance;
+
+#define NT_CHECK_FAIL_ACTION return FALSE;
+
+extern "C"
+BOOL WINAPI DllMain(
+ #ifdef UNDER_CE
+ HANDLE
+ #else
+ HINSTANCE
+ #endif
+ hInstance, DWORD dwReason, LPVOID /*lpReserved*/)
+{
+ if (dwReason == DLL_PROCESS_ATTACH)
+ {
+ g_hInstance = (HINSTANCE)hInstance;
+ NT_CHECK;
+ }
+ return TRUE;
+}
+
+DEFINE_GUID(CLSID_CArchiveHandler,
+0x23170F69, 0x40C1, 0x278A, 0x10, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00);
+
+static const UInt16 kDecodeId = 0x2790;
+
+DEFINE_GUID(CLSID_CCodec,
+0x23170F69, 0x40C1, kDecodeId, 0, 0, 0, 0, 0, 0, 0, 0);
+
+STDAPI CreateCoder(const GUID *clsid, const GUID *iid, void **outObject);
+STDAPI CreateHasher(const GUID *clsid, IHasher **hasher);
+STDAPI CreateArchiver(const GUID *classID, 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;
+}
diff --git a/lzma/CPP/7zip/Archive/IArchive.h b/lzma/CPP/7zip/Archive/IArchive.h
new file mode 100644
index 0000000..5e831c9
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/IArchive.h
@@ -0,0 +1,476 @@
+// 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
+ };
+ }
+ }
+
+ 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::GetStream
+ Result:
+ (*inStream == NULL) - for directories
+ (*inStream == NULL) - if link (hard link or symbolic link) was created
+*/
+
+#define INTERFACE_IArchiveExtractCallback(x) \
+ INTERFACE_IProgress(x) \
+ STDMETHOD(GetStream)(UInt32 index, ISequentialOutStream **outStream, Int32 askExtractMode) x; \
+ STDMETHOD(PrepareOperation)(Int32 askExtractMode) x; \
+ STDMETHOD(SetOperationResult)(Int32 resultEOperationResult) x; \
+
+ARCHIVE_INTERFACE_SUB(IArchiveExtractCallback, IProgress, 0x20)
+{
+ INTERFACE_IArchiveExtractCallback(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.
+*/
+
+/* MSVC allows the code where there is throw() in declaration of function,
+ but there is no throw() in definition of function. */
+
+#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 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)
+
+*/
+
+#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);
+};
+
+/*
+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)
+};
+
+
+ARCHIVE_INTERFACE(ISetProperties, 0x03)
+{
+ STDMETHOD(SetProperties)(const wchar_t **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; } \
+
+#define IMP_IInArchive_GetProp_WITH_NAME(k) \
+ (UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) \
+ { if (index >= ARRAY_SIZE(k)) return E_INVALIDARG; \
+ const STATPROPSTG &srcItem = k[index]; \
+ *propID = srcItem.propid; *varType = srcItem.vt; \
+ if (srcItem.lpwstrName == 0) *name = 0; else *name = ::SysAllocString(srcItem.lpwstrName); 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
diff --git a/lzma/CPP/7zip/Archive/Icons/7z.ico b/lzma/CPP/7zip/Archive/Icons/7z.ico
new file mode 100644
index 0000000..319753a
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/Icons/7z.ico
Binary files differ
diff --git a/lzma/CPP/7zip/Archive/LzmaHandler.cpp b/lzma/CPP/7zip/Archive/LzmaHandler.cpp
new file mode 100644
index 0000000..a372033
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/LzmaHandler.cpp
@@ -0,0 +1,604 @@
+// LzmaHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "../../Common/ComTry.h"
+#include "../../Common/IntToString.h"
+
+#include "../../Windows/PropVariant.h"
+
+#include "../Common/CreateCoder.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.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
+};
+
+struct CHeader
+{
+ UInt64 Size;
+ Byte FilterID;
+ Byte LzmaProps[5];
+
+ 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<ICompressCoder> _lzmaDecoder;
+ CMyComPtr<ISequentialOutStream> _bcjStream;
+public:
+ NCompress::NLzma::CDecoder *_lzmaDecoderSpec;
+
+ ~CDecoder();
+ HRESULT Create(DECL_EXTERNAL_CODECS_LOC_VARS
+ 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); }
+};
+
+static const UInt32 k_BCJ = 0x03030103;
+
+HRESULT CDecoder::Create(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ bool filteredMode, ISequentialInStream *inStream)
+{
+ if (!_lzmaDecoder)
+ {
+ _lzmaDecoderSpec = new NCompress::NLzma::CDecoder;
+ _lzmaDecoderSpec->FinishStream = true;
+ _lzmaDecoder = _lzmaDecoderSpec;
+ }
+
+ if (filteredMode)
+ {
+ if (!_bcjStream)
+ {
+ CMyComPtr<ICompressCoder> coder;
+ RINOK(CreateCoder(EXTERNAL_CODECS_LOC_VARS k_BCJ, coder, false));
+ if (!coder)
+ return E_NOTIMPL;
+ coder.QueryInterface(IID_ISequentialOutStream, &_bcjStream);
+ if (!_bcjStream)
+ return E_NOTIMPL;
+ }
+ }
+
+ return _lzmaDecoderSpec->SetInStream(inStream);
+}
+
+CDecoder::~CDecoder()
+{
+ ReleaseInStream();
+}
+
+HRESULT CDecoder::Code(const CHeader &header, ISequentialOutStream *outStream,
+ ICompressProgressInfo *progress)
+{
+ if (header.FilterID > 1)
+ return E_NOTIMPL;
+
+ {
+ CMyComPtr<ICompressSetDecoderProperties2> setDecoderProperties;
+ _lzmaDecoder.QueryInterface(IID_ICompressSetDecoderProperties2, &setDecoderProperties);
+ if (!setDecoderProperties)
+ return E_NOTIMPL;
+ RINOK(setDecoderProperties->SetDecoderProperties2(header.LzmaProps, 5));
+ }
+
+ CMyComPtr<ICompressSetOutStream> setOutStream;
+
+ bool filteredMode = (header.FilterID == 1);
+
+ if (filteredMode)
+ {
+ _bcjStream.QueryInterface(IID_ICompressSetOutStream, &setOutStream);
+ if (!setOutStream)
+ return E_NOTIMPL;
+ RINOK(setOutStream->SetOutStream(outStream));
+ outStream = _bcjStream;
+ }
+
+ const UInt64 *Size = header.HasSize() ? &header.Size : NULL;
+ HRESULT res = _lzmaDecoderSpec->CodeResume(outStream, Size, progress);
+
+ if (filteredMode)
+ {
+ CMyComPtr<IOutStreamFlush> flush;
+ _bcjStream.QueryInterface(IID_IOutStreamFlush, &flush);
+ if (flush)
+ {
+ HRESULT res2 = flush->Flush();
+ if (res == S_OK)
+ res = res2;
+ }
+ HRESULT res2 = setOutStream->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_ISetCompressCodecsInfo
+ 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;
+
+ DECL_EXTERNAL_CODECS_VARS
+ DECL_ISetCompressCodecsInfo
+
+public:
+ MY_QUERYINTERFACE_BEGIN2(IInArchive)
+ MY_QUERYINTERFACE_ENTRY(IArchiveOpenSeq)
+ QUERY_ENTRY_ISetCompressCodecsInfo
+ MY_QUERYINTERFACE_END
+ MY_ADDREF_RELEASE
+
+ 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 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;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = 1;
+ return S_OK;
+}
+
+static void DictSizeToString(UInt32 value, char *s)
+{
+ for (int i = 0; i <= 31; i++)
+ if (((UInt32)1 << i) == value)
+ {
+ ::ConvertUInt32ToString(i, s);
+ return;
+ }
+ char c = 'b';
+ if ((value & ((1 << 20) - 1)) == 0) { value >>= 20; c = 'm'; }
+ else if ((value & ((1 << 10) - 1)) == 0) { value >>= 10; c = 'k'; }
+ ::ConvertUInt32ToString(value, s);
+ s += MyStringLen(s);
+ *s++ = c;
+ *s = 0;
+}
+
+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:
+ if (_stream)
+ {
+ char sz[64];
+ char *s = sz;
+ if (_header.FilterID != 0)
+ s = MyStpCpy(s, "BCJ ");
+ s = MyStpCpy(s, "LZMA:");
+ DictSizeToString(_header.GetDicSize(), s);
+ prop = sz;
+ }
+ 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 UInt32 kBufSize = 1 + 5 + 8 + 2;
+ Byte buf[kBufSize];
+
+ RINOK(ReadStream_FALSE(inStream, buf, kBufSize));
+
+ if (!_header.Parse(buf, _lzma86))
+ return S_FALSE;
+ const Byte *start = buf + GetHeaderSize();
+ 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));
+ if (_packSize >= 24 && _header.Size == 0 && _header.FilterID == 0 && _header.LzmaProps[0] == 0)
+ 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)
+ {
+ UInt64 files = 0;
+ UInt64 value = Offset + *inSize;
+ return Callback->SetCompleted(&files, &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;
+
+ 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(
+ EXTERNAL_CODECS_VARS
+ _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->NeedMoreInput)
+ _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
+}
+
+IMPL_ISetCompressCodecsInfo
+
+namespace NLzmaAr {
+
+IMP_CreateArcIn_2(CHandler(false))
+
+static CArcInfo g_ArcInfo =
+ { "lzma", "lzma", 0, 0xA,
+ 0, { 0 },
+ // 2, { 0x5D, 0x00 },
+ 0,
+ NArcInfoFlags::kStartOpen |
+ NArcInfoFlags::kKeepName,
+ CreateArc, NULL,
+ IsArc_Lzma };
+
+REGISTER_ARC(Lzma)
+
+}
+
+namespace NLzma86Ar {
+
+IMP_CreateArcIn_2(CHandler(true))
+
+static CArcInfo g_ArcInfo =
+ { "lzma86", "lzma86", 0, 0xB,
+ 0, { 0 },
+ 0,
+ NArcInfoFlags::kKeepName,
+ CreateArc, NULL,
+ IsArc_Lzma86 };
+
+REGISTER_ARC(Lzma86)
+
+}
+
+}}
diff --git a/lzma/CPP/7zip/Archive/SplitHandler.cpp b/lzma/CPP/7zip/Archive/SplitHandler.cpp
new file mode 100644
index 0000000..47829f3
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/SplitHandler.cpp
@@ -0,0 +1,369 @@
+// 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;
+
+ UString GetNextName()
+ {
+ UString newName;
+ if (_splitStyle)
+ {
+ int i;
+ int numLetters = _changedPart.Len();
+ for (i = numLetters - 1; i >= 0; i--)
+ {
+ wchar_t c = _changedPart[i];
+ if (c == 'z')
+ {
+ newName.InsertAtFront('a');
+ continue;
+ }
+ else if (c == 'Z')
+ {
+ newName.InsertAtFront('A');
+ continue;
+ }
+ c++;
+ if ((c == 'z' || c == 'Z') && i == 0)
+ {
+ _unchangedPart += c;
+ wchar_t newChar = (c == 'z') ? L'a' : L'A';
+ newName.Empty();
+ numLetters++;
+ for (int k = 0; k < numLetters; k++)
+ newName += newChar;
+ break;
+ }
+ newName.InsertAtFront(c);
+ i--;
+ for (; i >= 0; i--)
+ newName.InsertAtFront(_changedPart[i]);
+ break;
+ }
+ }
+ else
+ {
+ int i;
+ int numLetters = _changedPart.Len();
+ for (i = numLetters - 1; i >= 0; i--)
+ {
+ wchar_t c = _changedPart[i];
+ if (c == '9')
+ {
+ newName.InsertAtFront('0');
+ if (i == 0)
+ newName.InsertAtFront('1');
+ continue;
+ }
+ c++;
+ newName.InsertAtFront(c);
+ i--;
+ for (; i >= 0; i--)
+ newName.InsertAtFront(_changedPart[i]);
+ break;
+ }
+ }
+ _changedPart = newName;
+ return _unchangedPart + _changedPart;
+ }
+};
+
+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('.');
+ 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 = L"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;
+ }
+
+ _totalSize += size;
+ _sizes.Add(size);
+ _streams.Add(stream);
+
+ {
+ UInt64 numFiles = _streams.Size();
+ RINOK(callback->SetCompleted(&numFiles, NULL));
+ }
+
+ for (;;)
+ {
+ const UString fullName = seqName.GetNextName();
+ CMyComPtr<IInStream> nextStream;
+ HRESULT result = volumeCallback->GetStream(fullName, &nextStream);
+ if (result == S_FALSE)
+ break;
+ if (result != S_OK)
+ return result;
+ if (!stream)
+ break;
+ {
+ NCOM::CPropVariant prop;
+ RINOK(volumeCallback->GetProperty(kpidSize, &prop));
+ if (prop.vt != VT_UI8)
+ return E_INVALIDARG;
+ size = prop.uhVal.QuadPart;
+ }
+ _totalSize += size;
+ _sizes.Add(size);
+ _streams.Add(nextStream);
+ {
+ 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
+}
+
+IMP_CreateArcIn
+
+static CArcInfo g_ArcInfo =
+ { "Split", "001", 0, 0xEA,
+ 0, { 0 },
+ 0,
+ 0,
+ CreateArc };
+
+REGISTER_ARC(Split)
+
+}}
diff --git a/lzma/CPP/7zip/Archive/StdAfx.h b/lzma/CPP/7zip/Archive/StdAfx.h
new file mode 100644
index 0000000..42a088f
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/StdAfx.h
@@ -0,0 +1,8 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "../../Common/Common.h"
+
+#endif
diff --git a/lzma/CPP/7zip/Archive/XzHandler.cpp b/lzma/CPP/7zip/Archive/XzHandler.cpp
new file mode 100644
index 0000000..e787c16
--- /dev/null
+++ b/lzma/CPP/7zip/Archive/XzHandler.cpp
@@ -0,0 +1,991 @@
+// XzHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+#include "../../../C/XzCrc64.h"
+#include "../../../C/XzEnc.h"
+
+#include "../../Common/ComTry.h"
+#include "../../Common/Defs.h"
+#include "../../Common/IntToString.h"
+
+#include "../ICoder.h"
+
+#include "../Common/CWrappers.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+
+#include "IArchive.h"
+
+#include "Common/HandlerOut.h"
+
+using namespace NWindows;
+
+namespace NCompress {
+namespace NLzma2 {
+
+HRESULT SetLzma2Prop(PROPID propID, const PROPVARIANT &prop, CLzma2EncProps &lzma2Props);
+
+}}
+
+static void *SzAlloc(void *, size_t size) { return MyAlloc(size); }
+static void SzFree(void *, void *address) { MyFree(address); }
+static ISzAlloc g_Alloc = { SzAlloc, SzFree };
+
+namespace NArchive {
+namespace NXz {
+
+struct CCrc64Gen { CCrc64Gen() { Crc64GenerateTable(); } } g_Crc64TableInit;
+
+static const wchar_t *k_LZMA2_Name = L"LZMA2";
+
+struct CStatInfo
+{
+ UInt64 InSize;
+ UInt64 OutSize;
+ UInt64 PhySize;
+
+ UInt64 NumStreams;
+ UInt64 NumBlocks;
+
+ bool UnpackSize_Defined;
+
+ bool NumStreams_Defined;
+ bool NumBlocks_Defined;
+
+ bool IsArc;
+ bool UnexpectedEnd;
+ bool DataAfterEnd;
+ bool Unsupported;
+ bool HeadersError;
+ bool DataError;
+ bool CrcError;
+
+ CStatInfo() { Clear(); }
+
+ void Clear()
+ {
+ InSize = 0;
+ OutSize = 0;
+ PhySize = 0;
+
+ NumStreams = 0;
+ NumBlocks = 0;
+
+ UnpackSize_Defined = false;
+
+ NumStreams_Defined = false;
+ NumBlocks_Defined = false;
+
+ UnexpectedEnd = false;
+ DataAfterEnd = false;
+ Unsupported = false;
+ HeadersError = false;
+ DataError = false;
+ CrcError = false;
+ IsArc = false;
+ }
+
+};
+
+struct IDecodeState: public CStatInfo
+{
+ SRes DecodeRes;
+
+ IDecodeState(): DecodeRes(SZ_OK) {}
+ virtual HRESULT Progress() = 0;
+
+ HRESULT Decode(ISequentialInStream *seqInStream, ISequentialOutStream *outStream);
+};
+
+struct CVirtProgress_To_LocalProgress: public IDecodeState
+{
+ CLocalProgress *lps;
+ CMyComPtr<ICompressProgressInfo> progress;
+
+ HRESULT Progress();
+};
+
+HRESULT CVirtProgress_To_LocalProgress::Progress()
+{
+ lps->InSize = InSize;
+ lps->OutSize = OutSize;
+ return lps->SetCur();
+}
+
+
+class CHandler:
+ public IInArchive,
+ public IArchiveOpenSeq,
+ #ifndef EXTRACT_ONLY
+ public IOutArchive,
+ public ISetProperties,
+ public CMultiMethodProps,
+ #endif
+ public CMyUnknownImp
+{
+ CStatInfo _stat;
+
+ bool _isArc;
+ bool _needSeekToStart;
+ bool _phySize_Defined;
+
+ CMyComPtr<IInStream> _stream;
+ CMyComPtr<ISequentialInStream> _seqStream;
+
+ UInt32 _filterId;
+ AString _methodsString;
+
+ void Init()
+ {
+ _filterId = 0;
+ CMultiMethodProps::Init();
+ }
+
+ HRESULT Open2(IInStream *inStream, /* UInt32 flags, */ IArchiveOpenCallback *callback);
+
+ HRESULT Decode2(ISequentialInStream *seqInStream, ISequentialOutStream *outStream, IDecodeState &progress)
+ {
+ RINOK(progress.Decode(seqInStream, outStream));
+ _stat = progress;
+ _phySize_Defined = true;
+ return S_OK;
+ }
+
+public:
+ MY_QUERYINTERFACE_BEGIN2(IInArchive)
+ MY_QUERYINTERFACE_ENTRY(IArchiveOpenSeq)
+ #ifndef EXTRACT_ONLY
+ MY_QUERYINTERFACE_ENTRY(IOutArchive)
+ MY_QUERYINTERFACE_ENTRY(ISetProperties)
+ #endif
+ MY_QUERYINTERFACE_END
+ MY_ADDREF_RELEASE
+
+ INTERFACE_IInArchive(;)
+ STDMETHOD(OpenSeq)(ISequentialInStream *stream);
+
+ #ifndef EXTRACT_ONLY
+ INTERFACE_IOutArchive(;)
+ STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps);
+ #endif
+
+ CHandler();
+};
+
+CHandler::CHandler()
+{
+ Init();
+}
+
+static const Byte kProps[] =
+{
+ kpidSize,
+ kpidPackSize,
+ kpidMethod
+};
+
+static const Byte kArcProps[] =
+{
+ kpidMethod,
+ kpidNumStreams,
+ kpidNumBlocks
+};
+
+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 AddUInt32ToString(AString &s, UInt32 value)
+{
+ char temp[16];
+ ConvertUInt32ToString(value, temp);
+ s += temp;
+}
+
+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';
+ }
+ }
+ AddUInt32ToString(s, 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 AString GetMethodString(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;
+ }
+
+ AString 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)
+ AddUInt32ToString(s, (UInt32)f.props[0] + 1);
+ else
+ {
+ s += '[';
+ for (UInt32 bi = 0; bi < f.propsSize; bi++)
+ AddHexToString(s, f.props[bi]);
+ s += ']';
+ }
+ }
+ return s;
+}
+
+static void AddString(AString &dest, const AString &src)
+{
+ if (!dest.IsEmpty())
+ dest += ' ';
+ dest += src;
+}
+
+static const char *kChecks[] =
+{
+ "NoCheck"
+ , "CRC32"
+ , NULL
+ , NULL
+ , "CRC64"
+ , NULL
+ , NULL
+ , NULL
+ , NULL
+ , NULL
+ , "SHA256"
+ , NULL
+ , NULL
+ , NULL
+ , NULL
+ , NULL
+};
+
+static AString GetCheckString(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));
+ AString s;
+ for (i = 0; i <= XZ_CHECK_MASK; i++)
+ if (((mask >> i) & 1) != 0)
+ {
+ AString s2;
+ if (kChecks[i])
+ s2 = kChecks[i];
+ else
+ {
+ s2 = "Check-";
+ AddUInt32ToString(s2, (UInt32)i);
+ }
+ AddString(s, s2);
+ }
+ return s;
+}
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidPhySize: if (_phySize_Defined) prop = _stat.PhySize; 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 kpidMethod: if (!_methodsString.IsEmpty()) prop = _methodsString; break;
+ case kpidErrorFlags:
+ {
+ UInt32 v = 0;
+ if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;;
+ if (_stat.UnexpectedEnd) v |= kpv_ErrorFlags_UnexpectedEnd;
+ if (_stat.DataAfterEnd) v |= kpv_ErrorFlags_DataAfterEnd;
+ if (_stat.HeadersError) v |= kpv_ErrorFlags_HeadersError;
+ if (_stat.Unsupported) v |= kpv_ErrorFlags_UnsupportedMethod;
+ if (_stat.DataError) v |= kpv_ErrorFlags_DataError;
+ if (_stat.CrcError) v |= kpv_ErrorFlags_CrcError;
+ prop = v;
+ }
+ }
+ 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.PhySize; break;
+ case kpidMethod: if (!_methodsString.IsEmpty()) prop = _methodsString; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+
+struct COpenCallbackWrap
+{
+ ICompressProgress p;
+ IArchiveOpenCallback *OpenCallback;
+ HRESULT Res;
+ COpenCallbackWrap(IArchiveOpenCallback *progress);
+};
+
+static SRes OpenCallbackProgress(void *pp, UInt64 inSize, UInt64 /* outSize */)
+{
+ COpenCallbackWrap *p = (COpenCallbackWrap *)pp;
+ p->Res = p->OpenCallback->SetCompleted(NULL, &inSize);
+ return (SRes)p->Res;
+}
+
+COpenCallbackWrap::COpenCallbackWrap(IArchiveOpenCallback *callback)
+{
+ p.Progress = OpenCallbackProgress;
+ OpenCallback = callback;
+ Res = SZ_OK;
+}
+
+struct CXzsCPP
+{
+ CXzs p;
+ CXzsCPP() { Xzs_Construct(&p); }
+ ~CXzsCPP() { Xzs_Free(&p, &g_Alloc); }
+};
+
+
+struct CVirtProgress_To_OpenProgress: public IDecodeState
+{
+ IArchiveOpenCallback *Callback;
+ UInt64 Offset;
+
+ HRESULT Progress();
+};
+
+HRESULT CVirtProgress_To_OpenProgress::Progress()
+{
+ if (Callback)
+ {
+ UInt64 files = 0;
+ UInt64 value = Offset + InSize;
+ return Callback->SetCompleted(&files, &value);
+ }
+ return S_OK;
+}
+
+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(inStream);
+ SRes res = Xz_ReadHeader(&st, &inStreamWrap.p);
+ if (res != SZ_OK)
+ return SRes_to_Open_HRESULT(res);
+
+ {
+ CXzBlock block;
+ Bool isIndex;
+ UInt32 headerSizeRes;
+ SRes res2 = XzBlock_ReadHeader(&block, &inStreamWrap.p, &isIndex, &headerSizeRes);
+ if (res2 == SZ_OK && !isIndex)
+ {
+ unsigned numFilters = XzBlock_GetNumFilters(&block);
+ for (unsigned i = 0; i < numFilters; i++)
+ AddString(_methodsString, GetMethodString(block.filters[i]));
+ }
+ }
+ }
+
+ RINOK(inStream->Seek(0, STREAM_SEEK_END, &_stat.PhySize));
+ RINOK(callback->SetTotal(NULL, &_stat.PhySize));
+
+ CSeekInStreamWrap inStreamImp(inStream);
+
+ CLookToRead lookStream;
+ LookToRead_CreateVTable(&lookStream, True);
+ lookStream.realStream = &inStreamImp.p;
+ LookToRead_Init(&lookStream);
+
+ COpenCallbackWrap openWrap(callback);
+
+ CXzsCPP xzs;
+ Int64 startPosition;
+ SRes res = Xzs_ReadBackward(&xzs.p, &lookStream.s, &startPosition, &openWrap.p, &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;
+
+ AddString(_methodsString, GetCheckString(xzs.p));
+ }
+ 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, /* 0, */ callback);
+ }
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream)
+{
+ Close();
+ _seqStream = stream;
+ _isArc = true;
+ _needSeekToStart = false;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _stat.Clear();
+
+ _isArc = false;
+ _needSeekToStart = false;
+
+ _phySize_Defined = false;
+
+ _methodsString.Empty();
+ _stream.Release();
+ _seqStream.Release();
+ return S_OK;
+}
+
+class CSeekToSeqStream:
+ public IInStream,
+ public CMyUnknownImp
+{
+public:
+ CMyComPtr<ISequentialInStream> Stream;
+ MY_UNKNOWN_IMP1(IInStream)
+
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+ STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
+};
+
+STDMETHODIMP CSeekToSeqStream::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ return Stream->Read(data, size, processedSize);
+}
+
+STDMETHODIMP CSeekToSeqStream::Seek(Int64, UInt32, UInt64 *) { return E_NOTIMPL; }
+
+struct CXzUnpackerCPP
+{
+ Byte *InBuf;
+ Byte *OutBuf;
+ CXzUnpacker p;
+
+ CXzUnpackerCPP(): InBuf(0), OutBuf(0)
+ {
+ XzUnpacker_Construct(&p, &g_Alloc);
+ }
+ ~CXzUnpackerCPP()
+ {
+ XzUnpacker_Free(&p);
+ MyFree(InBuf);
+ MyFree(OutBuf);
+ }
+};
+
+HRESULT IDecodeState::Decode(ISequentialInStream *seqInStream, ISequentialOutStream *outStream)
+{
+ const size_t kInBufSize = 1 << 15;
+ const size_t kOutBufSize = 1 << 21;
+
+ DecodeRes = SZ_OK;
+
+ CXzUnpackerCPP xzu;
+ XzUnpacker_Init(&xzu.p);
+ xzu.InBuf = (Byte *)MyAlloc(kInBufSize);
+ xzu.OutBuf = (Byte *)MyAlloc(kOutBufSize);
+ if (!xzu.InBuf || !xzu.OutBuf)
+ return E_OUTOFMEMORY;
+
+ UInt32 inSize = 0;
+ SizeT inPos = 0;
+ SizeT outPos = 0;
+
+ for (;;)
+ {
+ if (inPos == inSize)
+ {
+ inPos = inSize = 0;
+ RINOK(seqInStream->Read(xzu.InBuf, kInBufSize, &inSize));
+ }
+
+ SizeT inLen = inSize - inPos;
+ SizeT outLen = kOutBufSize - outPos;
+ ECoderStatus status;
+
+ SRes res = XzUnpacker_Code(&xzu.p,
+ xzu.OutBuf + outPos, &outLen,
+ xzu.InBuf + inPos, &inLen,
+ (inSize == 0 ? CODER_FINISH_END : CODER_FINISH_ANY), &status);
+
+ inPos += inLen;
+ outPos += outLen;
+
+ InSize += inLen;
+ OutSize += outLen;
+
+ DecodeRes = res;
+
+ bool finished = ((inLen == 0 && outLen == 0) || res != SZ_OK);
+
+ if (outStream)
+ {
+ if (outPos == kOutBufSize || finished)
+ {
+ if (outPos != 0)
+ {
+ RINOK(WriteStream(outStream, xzu.OutBuf, outPos));
+ outPos = 0;
+ }
+ }
+ }
+ else
+ outPos = 0;
+
+ RINOK(Progress());
+
+ if (finished)
+ {
+ PhySize = InSize;
+ NumStreams = xzu.p.numStartedStreams;
+ if (NumStreams > 0)
+ IsArc = true;
+ NumBlocks = xzu.p.numTotalBlocks;
+
+ UnpackSize_Defined = true;
+ NumStreams_Defined = true;
+ NumBlocks_Defined = true;
+
+ UInt64 extraSize = XzUnpacker_GetExtraSize(&xzu.p);
+
+ if (res == SZ_OK)
+ {
+ if (status == CODER_STATUS_NEEDS_MORE_INPUT)
+ {
+ extraSize = 0;
+ if (!XzUnpacker_IsStreamWasFinished(&xzu.p))
+ {
+ // finished at padding bytes, but padding is not aligned for 4
+ UnexpectedEnd = true;
+ res = SZ_ERROR_DATA;
+ }
+ }
+ else // status == CODER_STATUS_NOT_FINISHED
+ res = SZ_ERROR_DATA;
+ }
+ else if (res == SZ_ERROR_NO_ARCHIVE)
+ {
+ if (InSize == extraSize)
+ IsArc = false;
+ else
+ {
+ if (extraSize != 0 || inPos != inSize)
+ {
+ DataAfterEnd = true;
+ res = SZ_OK;
+ }
+ }
+ }
+
+ DecodeRes = res;
+ PhySize -= extraSize;
+
+ switch (res)
+ {
+ case SZ_OK: break;
+ case SZ_ERROR_NO_ARCHIVE: IsArc = false; break;
+ case SZ_ERROR_ARCHIVE: HeadersError = true; break;
+ case SZ_ERROR_UNSUPPORTED: Unsupported = true; break;
+ case SZ_ERROR_CRC: CrcError = true; break;
+ case SZ_ERROR_DATA: DataError = true; break;
+ default: DataError = true; break;
+ }
+
+ break;
+ }
+ }
+
+ 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;
+
+ extractCallback->SetTotal(_stat.PhySize);
+ UInt64 currentTotalPacked = 0;
+ RINOK(extractCallback->SetCompleted(¤tTotalPacked));
+ 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);
+
+ CVirtProgress_To_LocalProgress vp;
+ vp.lps = new CLocalProgress;
+ vp.progress = vp.lps;
+ vp.lps->Init(extractCallback, true);
+
+
+ if (_needSeekToStart)
+ {
+ if (!_stream)
+ return E_FAIL;
+ RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL));
+ }
+ else
+ _needSeekToStart = true;
+
+ RINOK(Decode2(_seqStream, realOutStream, vp));
+
+ Int32 opRes;
+
+ if (!vp.IsArc)
+ opRes = NExtract::NOperationResult::kIsNotArc;
+ else if (vp.UnexpectedEnd)
+ opRes = NExtract::NOperationResult::kUnexpectedEnd;
+ else if (vp.DataAfterEnd)
+ opRes = NExtract::NOperationResult::kDataAfterEnd;
+ else if (vp.CrcError)
+ opRes = NExtract::NOperationResult::kCRCError;
+ else if (vp.Unsupported)
+ opRes = NExtract::NOperationResult::kUnsupportedMethod;
+ else if (vp.HeadersError)
+ opRes = NExtract::NOperationResult::kDataError;
+ else if (vp.DataError)
+ opRes = NExtract::NOperationResult::kDataError;
+ else if (vp.DecodeRes != SZ_OK)
+ opRes = NExtract::NOperationResult::kDataError;
+ else
+ opRes = NExtract::NOperationResult::kOK;
+
+ 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)
+{
+ CSeqOutStreamWrap seqOutStream(outStream);
+
+ if (numItems == 0)
+ {
+ SRes res = Xz_EncodeEmpty(&seqOutStream.p);
+ 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));
+ }
+
+ CLzma2EncProps lzma2Props;
+ Lzma2EncProps_Init(&lzma2Props);
+
+ lzma2Props.lzmaProps.level = GetLevel();
+
+ CMyComPtr<ISequentialInStream> fileInStream;
+ RINOK(updateCallback->GetStream(0, &fileInStream));
+
+ CSeqInStreamWrap seqInStream(fileInStream);
+
+ {
+ NCOM::CPropVariant prop = (UInt64)size;
+ RINOK(NCompress::NLzma2::SetLzma2Prop(NCoderPropID::kReduceSize, prop, lzma2Props));
+ }
+
+ FOR_VECTOR (i, _methods)
+ {
+ COneMethodInfo &m = _methods[i];
+ SetGlobalLevelAndThreads(m
+ #ifndef _7ZIP_ST
+ , _numThreads
+ #endif
+ );
+ {
+ FOR_VECTOR (j, m.Props)
+ {
+ const CProp &prop = m.Props[j];
+ RINOK(NCompress::NLzma2::SetLzma2Prop(prop.Id, prop.Value, lzma2Props));
+ }
+ }
+ }
+
+ #ifndef _7ZIP_ST
+ lzma2Props.numTotalThreads = _numThreads;
+ #endif
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(updateCallback, true);
+
+ CCompressProgressWrap progressWrap(progress);
+ CXzProps xzProps;
+ CXzFilterProps filter;
+ XzProps_Init(&xzProps);
+ XzFilterProps_Init(&filter);
+ xzProps.lzma2Props = &lzma2Props;
+ xzProps.filterProps = (_filterId != 0 ? &filter : NULL);
+ switch (_crcSize)
+ {
+ case 0: xzProps.checkId = XZ_CHECK_NO; break;
+ case 4: xzProps.checkId = XZ_CHECK_CRC32; break;
+ case 8: xzProps.checkId = XZ_CHECK_CRC64; break;
+ case 32: xzProps.checkId = XZ_CHECK_SHA256; break;
+ default: return E_INVALIDARG;
+ }
+ filter.id = _filterId;
+ 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;
+ }
+ }
+ if (!deltaDefined)
+ return E_INVALIDARG;
+ }
+ SRes res = Xz_Encode(&seqOutStream.p, &seqInStream.p, &xzProps, &progressWrap.p);
+ if (res == SZ_OK)
+ return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK);
+ return SResToHRESULT(res);
+ }
+ if (indexInArchive != 0)
+ return E_INVALIDARG;
+ if (_stream)
+ RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL));
+ return NCompress::CopyStream(_stream, outStream, NULL);
+}
+
+STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps)
+{
+ COM_TRY_BEGIN
+ Init();
+ for (UInt32 i = 0; i < numProps; i++)
+ {
+ RINOK(SetProperty(names[i], values[i]));
+ }
+
+ 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)
+ {
+ UString &methodName = _methods[0].MethodName;
+ if (methodName.IsEmpty())
+ methodName = k_LZMA2_Name;
+ else if (!methodName.IsEqualToNoCase(k_LZMA2_Name))
+ return E_INVALIDARG;
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+#endif
+
+IMP_CreateArcIn
+IMP_CreateArcOut
+
+static CArcInfo g_ArcInfo =
+ { "xz", "xz txz", "* .tar", 0xC,
+ 6, { 0xFD, '7' , 'z', 'X', 'Z', 0 },
+ 0,
+ NArcInfoFlags::kKeepName,
+ REF_CreateArc_Pair };
+
+REGISTER_ARC(xz)
+
+}}
diff --git a/lzma/CPP/7zip/Asm.mak b/lzma/CPP/7zip/Asm.mak
new file mode 100644
index 0000000..1012b16
--- /dev/null
+++ b/lzma/CPP/7zip/Asm.mak
@@ -0,0 +1,9 @@
+!IFDEF ASM_OBJS
+!IF "$(CPU)" == "ARM"
+$(ASM_OBJS): ../../../../Asm/Arm/$(*B).asm
+ $(COMPL_ASM)
+!ELSEIF "$(CPU)" != "IA64" && "$(CPU)" != "MIPS"
+$(ASM_OBJS): ../../../../Asm/x86/$(*B).asm
+ $(COMPL_ASM)
+!ENDIF
+!ENDIF
diff --git a/lzma/CPP/7zip/Bundles/Alone7z/Alone.dsp b/lzma/CPP/7zip/Bundles/Alone7z/Alone.dsp
new file mode 100644
index 0000000..f96ad74
--- /dev/null
+++ b/lzma/CPP/7zip/Bundles/Alone7z/Alone.dsp
@@ -0,0 +1,1801 @@
+# 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 /Gz /MT /W3 /GX /O1 /I "..\..\..\\" /D "NDEBUG" /D "_MBCS" /D "WIN32" /D "_CONSOLE" /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 /Gz /MDd /W3 /Gm /GX /ZI /Od /I "..\..\..\\" /D "_DEBUG" /D "_MBCS" /D "WIN32" /D "_CONSOLE" /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 /Gz /MD /W4 /GX /O1 /I "..\..\..\\" /D "NDEBUG" /D "UNICODE" /D "_UNICODE" /D "WIN32" /D "_CONSOLE" /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 /Gz /MDd /W4 /Gm /GX /ZI /Od /I "..\..\..\\" /D "_DEBUG" /D "_UNICODE" /D "UNICODE" /D "WIN32" /D "_CONSOLE" /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\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\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=..\..\Archive\Common\CrossThreadProgress.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\CrossThreadProgress.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\BranchCoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BranchCoder.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\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\RangeCoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\RangeCoderBit.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\7zFolderOutStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zFolderOutStream.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\CoderMixer2MT.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\CoderMixer2MT.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\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\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\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\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\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
diff --git a/lzma/CPP/7zip/Bundles/Alone7z/Alone.dsw b/lzma/CPP/7zip/Bundles/Alone7z/Alone.dsw
new file mode 100644
index 0000000..036aab4
--- /dev/null
+++ b/lzma/CPP/7zip/Bundles/Alone7z/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/lzma/CPP/7zip/Bundles/Alone7z/StdAfx.cpp b/lzma/CPP/7zip/Bundles/Alone7z/StdAfx.cpp
new file mode 100644
index 0000000..c6d3b1f
--- /dev/null
+++ b/lzma/CPP/7zip/Bundles/Alone7z/StdAfx.cpp
@@ -0,0 +1,3 @@
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/lzma/CPP/7zip/Bundles/Alone7z/StdAfx.h b/lzma/CPP/7zip/Bundles/Alone7z/StdAfx.h
new file mode 100644
index 0000000..59d9ac1
--- /dev/null
+++ b/lzma/CPP/7zip/Bundles/Alone7z/StdAfx.h
@@ -0,0 +1,8 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "../../../Common/Common.h"
+
+#endif
diff --git a/lzma/CPP/7zip/Bundles/Alone7z/makefile b/lzma/CPP/7zip/Bundles/Alone7z/makefile
new file mode 100644
index 0000000..c68a42e
--- /dev/null
+++ b/lzma/CPP/7zip/Bundles/Alone7z/makefile
@@ -0,0 +1,154 @@
+PROG = 7zr.exe
+MY_CONSOLE = 1
+CFLAGS = $(CFLAGS) -DPROG_VARIANT_R
+
+!IFNDEF UNDER_CE
+CFLAGS = $(CFLAGS) -DWIN_LONG_PATH
+!ENDIF
+
+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\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\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\LockedStream.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\CoderMixer2MT.obj \
+ $O\CrossThreadProgress.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\7zFolderOutStream.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\BranchCoder.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 \
+
+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\Bra.obj \
+ $O\Bra86.obj \
+ $O\BraIA64.obj \
+ $O\CpuArch.obj \
+ $O\Delta.obj \
+ $O\LzFind.obj \
+ $O\LzFindMt.obj \
+ $O\Lzma2Dec.obj \
+ $O\Lzma2Enc.obj \
+ $O\LzmaDec.obj \
+ $O\LzmaEnc.obj \
+ $O\MtCoder.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 "../../7zip.mak"
diff --git a/lzma/CPP/7zip/Bundles/Alone7z/resource.rc b/lzma/CPP/7zip/Bundles/Alone7z/resource.rc
new file mode 100644
index 0000000..3be08c9
--- /dev/null
+++ b/lzma/CPP/7zip/Bundles/Alone7z/resource.rc
@@ -0,0 +1,3 @@
+#include "../../../../C/7zVersion.rc"
+
+MY_VERSION_INFO_APP("7-Zip Reduced Standalone Console", "7zr")
diff --git a/lzma/CPP/7zip/Bundles/Format7zExtractR/StdAfx.cpp b/lzma/CPP/7zip/Bundles/Format7zExtractR/StdAfx.cpp
new file mode 100644
index 0000000..c6d3b1f
--- /dev/null
+++ b/lzma/CPP/7zip/Bundles/Format7zExtractR/StdAfx.cpp
@@ -0,0 +1,3 @@
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/lzma/CPP/7zip/Bundles/Format7zExtractR/StdAfx.h b/lzma/CPP/7zip/Bundles/Format7zExtractR/StdAfx.h
new file mode 100644
index 0000000..59d9ac1
--- /dev/null
+++ b/lzma/CPP/7zip/Bundles/Format7zExtractR/StdAfx.h
@@ -0,0 +1,8 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "../../../Common/Common.h"
+
+#endif
diff --git a/lzma/CPP/7zip/Bundles/Format7zExtractR/makefile b/lzma/CPP/7zip/Bundles/Format7zExtractR/makefile
new file mode 100644
index 0000000..0b2f581
--- /dev/null
+++ b/lzma/CPP/7zip/Bundles/Format7zExtractR/makefile
@@ -0,0 +1,97 @@
+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\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 \
+
+AR_OBJS = \
+ $O\ArchiveExports.obj \
+ $O\DllExports2.obj \
+
+AR_COMMON_OBJS = \
+ $O\CoderMixer2.obj \
+ $O\CoderMixer2MT.obj \
+ $O\CrossThreadProgress.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\7zFolderOutStream.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\BranchCoder.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\Bra.obj \
+ $O\Bra86.obj \
+ $O\BraIA64.obj \
+ $O\CpuArch.obj \
+ $O\Delta.obj \
+ $O\Lzma2Dec.obj \
+ $O\LzmaDec.obj \
+ $O\Threads.obj \
+
+!include "../../Crc.mak"
+
+!include "../../7zip.mak"
diff --git a/lzma/CPP/7zip/Bundles/Format7zExtractR/resource.rc b/lzma/CPP/7zip/Bundles/Format7zExtractR/resource.rc
new file mode 100644
index 0000000..dac02a6
--- /dev/null
+++ b/lzma/CPP/7zip/Bundles/Format7zExtractR/resource.rc
@@ -0,0 +1,5 @@
+#include "../../../../C/7zVersion.rc"
+
+MY_VERSION_INFO_DLL("7z Extracting Reduced Standalone Plugin", "7zxr")
+
+101 ICON "../../Archive/Icons/7z.ico"
diff --git a/lzma/CPP/7zip/Bundles/Format7zR/StdAfx.cpp b/lzma/CPP/7zip/Bundles/Format7zR/StdAfx.cpp
new file mode 100644
index 0000000..c6d3b1f
--- /dev/null
+++ b/lzma/CPP/7zip/Bundles/Format7zR/StdAfx.cpp
@@ -0,0 +1,3 @@
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/lzma/CPP/7zip/Bundles/Format7zR/StdAfx.h b/lzma/CPP/7zip/Bundles/Format7zR/StdAfx.h
new file mode 100644
index 0000000..59d9ac1
--- /dev/null
+++ b/lzma/CPP/7zip/Bundles/Format7zR/StdAfx.h
@@ -0,0 +1,8 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "../../../Common/Common.h"
+
+#endif
diff --git a/lzma/CPP/7zip/Bundles/Format7zR/makefile b/lzma/CPP/7zip/Bundles/Format7zR/makefile
new file mode 100644
index 0000000..0e885c0
--- /dev/null
+++ b/lzma/CPP/7zip/Bundles/Format7zR/makefile
@@ -0,0 +1,116 @@
+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\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\UniqBlocks.obj \
+ $O\VirtThread.obj \
+
+AR_OBJS = \
+ $O\ArchiveExports.obj \
+ $O\DllExports2.obj \
+
+AR_COMMON_OBJS = \
+ $O\CoderMixer2.obj \
+ $O\CoderMixer2MT.obj \
+ $O\CrossThreadProgress.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\7zFolderOutStream.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\BranchCoder.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\Bra.obj \
+ $O\Bra86.obj \
+ $O\BraIA64.obj \
+ $O\CpuArch.obj \
+ $O\Delta.obj \
+ $O\LzFind.obj \
+ $O\LzFindMt.obj \
+ $O\Lzma2Dec.obj \
+ $O\Lzma2Enc.obj \
+ $O\LzmaDec.obj \
+ $O\LzmaEnc.obj \
+ $O\MtCoder.obj \
+ $O\Threads.obj \
+
+!include "../../Crc.mak"
+
+!include "../../7zip.mak"
diff --git a/lzma/CPP/7zip/Bundles/Format7zR/resource.rc b/lzma/CPP/7zip/Bundles/Format7zR/resource.rc
new file mode 100644
index 0000000..262125c
--- /dev/null
+++ b/lzma/CPP/7zip/Bundles/Format7zR/resource.rc
@@ -0,0 +1,5 @@
+#include "../../../../C/7zVersion.rc"
+
+MY_VERSION_INFO_DLL("7z Reduced Standalone Plugin", "7zr")
+
+101 ICON "../../Archive/Icons/7z.ico"
diff --git a/lzma/CPP/7zip/Bundles/LzmaCon/LzmaAlone.cpp b/lzma/CPP/7zip/Bundles/LzmaCon/LzmaAlone.cpp
new file mode 100644
index 0000000..677fb8f
--- /dev/null
+++ b/lzma/CPP/7zip/Bundles/LzmaCon/LzmaAlone.cpp
@@ -0,0 +1,571 @@
+// 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 "../../../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/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"
+
+
+using namespace NCommandLineParser;
+
+static const char *kCantAllocate = "Can not allocate memory";
+static const char *kReadError = "Read error";
+static const char *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 PrintMessage(const char *s)
+{
+ fputs(s, stderr);
+}
+
+static void PrintHelp()
+{
+ PrintMessage("\nUsage: LZMA <e|d> inputFile outputFile [<switches>...]\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: 23 (8MB)\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{MF_ID}: set Match Finder: [bt2, bt3, bt4, hc4], 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 void PrintHelpAndExit(const char *s)
+{
+ fprintf(stderr, "\nError: %s\n\n", s);
+ PrintHelp();
+ throw -1;
+}
+
+static void IncorrectCommand()
+{
+ PrintHelpAndExit("Incorrect command");
+}
+
+static void WriteArgumentsToStringList(int numArgs, const char *args[], UStringVector &strings)
+{
+ for (int i = 1; i < numArgs; i++)
+ strings.Add(MultiByteToUnicodeString(args[i]));
+}
+
+static bool GetNumber(const wchar_t *s, UInt32 &value)
+{
+ value = 0;
+ if (*s == 0)
+ return false;
+ const wchar_t *end;
+ value = ConvertStringToUInt32(s, &end);
+ return *end == 0;
+}
+
+static void ParseUInt32(const CParser &parser, unsigned index, UInt32 &res)
+{
+ if (parser[index].ThereIs)
+ if (!GetNumber(parser[index].PostStrings[0], res))
+ IncorrectCommand();
+}
+
+#define NT_CHECK_FAIL_ACTION PrintMessage("Unsupported Windows version"); return 1;
+
+int main2(int numArgs, const char *args[])
+{
+ NT_CHECK
+
+ PrintMessage("\nLZMA " MY_VERSION_COPYRIGHT_DATE "\n");
+
+ if (numArgs == 1)
+ {
+ PrintHelp();
+ return 0;
+ }
+
+ bool unsupportedTypes = (sizeof(Byte) != 1 || sizeof(UInt32) < 4 || sizeof(UInt64) < 4);
+ if (unsupportedTypes)
+ {
+ PrintMessage("Unsupported base types. Edit Common/Types.h and recompile");
+ return 1;
+ }
+
+ UStringVector commandStrings;
+ WriteArgumentsToStringList(numArgs, args, commandStrings);
+
+ CParser parser(ARRAY_SIZE(kSwitchForms));
+ try
+ {
+ parser.ParseStrings(kSwitchForms, commandStrings);
+ }
+ catch(...)
+ {
+ IncorrectCommand();
+ }
+
+ if (parser[NKey::kHelp1].ThereIs || parser[NKey::kHelp2].ThereIs)
+ {
+ PrintHelp();
+ return 0;
+ }
+ const UStringVector &nonSwitchStrings = parser.NonSwitchStrings;
+
+ unsigned paramIndex = 0;
+ if (paramIndex >= nonSwitchStrings.Size())
+ IncorrectCommand();
+ const UString &command = nonSwitchStrings[paramIndex++];
+
+ CObjectVector<CProperty> props;
+ bool dictDefined = false;
+ UInt32 dict = (UInt32)(Int32)-1;
+ if (parser[NKey::kDict].ThereIs)
+ {
+ UInt32 dicLog;
+ const UString &s = parser[NKey::kDict].PostStrings[0];
+ if (!GetNumber(s, dicLog))
+ IncorrectCommand();
+ dict = 1 << dicLog;
+ dictDefined = true;
+ CProperty prop;
+ prop.Name = L"d";
+ prop.Value = s;
+ props.Add(prop);
+ }
+ if (parser[NKey::kLevel].ThereIs)
+ {
+ UInt32 level = 5;
+ const UString &s = parser[NKey::kLevel].PostStrings[0];
+ if (!GetNumber(s, level))
+ IncorrectCommand();
+ CProperty prop;
+ prop.Name = L"x";
+ prop.Value = s;
+ props.Add(prop);
+ }
+ UString mf = L"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)
+ {
+ UInt32 numCPUs = NWindows::NSystem::GetNumberOfProcessors();
+ const UString &s = parser[NKey::kMultiThread].PostStrings[0];
+ if (s.IsEmpty())
+ numThreads = numCPUs;
+ else
+ if (!GetNumber(s, numThreads))
+ IncorrectCommand();
+ CProperty prop;
+ prop.Name = L"mt";
+ prop.Value = s;
+ props.Add(prop);
+ }
+ #endif
+
+ if (parser[NKey::kMethod].ThereIs)
+ {
+ UString s = parser[NKey::kMethod].PostStrings[0];
+ if (s.IsEmpty() || s[0] != '=')
+ IncorrectCommand();
+ CProperty prop;
+ prop.Name = L"m";
+ prop.Value = s.Ptr(1);
+ props.Add(prop);
+ }
+
+ if (MyStringCompareNoCase(command, L"b") == 0)
+ {
+ const UInt32 kNumDefaultItereations = 1;
+ UInt32 numIterations = kNumDefaultItereations;
+ {
+ if (paramIndex < nonSwitchStrings.Size())
+ if (!GetNumber(nonSwitchStrings[paramIndex++], numIterations))
+ numIterations = kNumDefaultItereations;
+ }
+ HRESULT res = BenchCon(props, numIterations, stderr);
+ if (res != S_OK)
+ {
+ if (res != E_ABORT)
+ {
+ PrintMessage("Benchmark Error");
+ return 1;
+ }
+ }
+ return 0;
+ }
+
+ if (numThreads == (UInt32)(Int32)-1)
+ numThreads = 1;
+
+ bool encodeMode = false;
+ if (MyStringCompareNoCase(command, L"e") == 0)
+ encodeMode = true;
+ else if (MyStringCompareNoCase(command, L"d") == 0)
+ encodeMode = false;
+ else
+ IncorrectCommand();
+
+ bool stdInMode = parser[NKey::kStdIn].ThereIs;
+ bool stdOutMode = parser[NKey::kStdOut].ThereIs;
+
+ CMyComPtr<ISequentialInStream> inStream;
+ CInFileStream *inStreamSpec = 0;
+ if (stdInMode)
+ {
+ inStream = new CStdInFileStream;
+ MY_SET_BINARY_MODE(stdin);
+ }
+ else
+ {
+ if (paramIndex >= nonSwitchStrings.Size())
+ IncorrectCommand();
+ const UString &inputName = nonSwitchStrings[paramIndex++];
+ inStreamSpec = new CInFileStream;
+ inStream = inStreamSpec;
+ if (!inStreamSpec->Open(us2fs(inputName)))
+ {
+ fprintf(stderr, "\nError: can not open input file %s\n",
+ (const char *)GetOemString(inputName));
+ return 1;
+ }
+ }
+
+ CMyComPtr<ISequentialOutStream> outStream;
+ COutFileStream *outStreamSpec = NULL;
+ if (stdOutMode)
+ {
+ outStream = new CStdOutFileStream;
+ MY_SET_BINARY_MODE(stdout);
+ }
+ else
+ {
+ if (paramIndex >= nonSwitchStrings.Size())
+ IncorrectCommand();
+ const UString &outputName = nonSwitchStrings[paramIndex++];
+ outStreamSpec = new COutFileStream;
+ outStream = outStreamSpec;
+ if (!outStreamSpec->Create(us2fs(outputName), true))
+ {
+ fprintf(stderr, "\nError: can not open output file %s\n",
+ (const char *)GetOemString(outputName));
+ return 1;
+ }
+ }
+
+ if (parser[NKey::kFilter86].ThereIs)
+ {
+ // -f86 switch is for x86 filtered mode: BCJ + LZMA.
+ if (parser[NKey::kEOS].ThereIs || stdInMode)
+ throw "Can not use stdin in this mode";
+ UInt64 fileSize;
+ inStreamSpec->File.GetLength(fileSize);
+ if (fileSize > 0xF0000000)
+ throw "File is too big";
+ size_t inSize = (size_t)fileSize;
+ Byte *inBuffer = 0;
+ if (inSize != 0)
+ {
+ inBuffer = (Byte *)MyAlloc((size_t)inSize);
+ if (inBuffer == 0)
+ throw kCantAllocate;
+ }
+
+ if (ReadStream_FAIL(inStream, inBuffer, inSize) != S_OK)
+ throw "Can not read";
+
+ Byte *outBuffer = 0;
+ size_t outSize;
+ if (encodeMode)
+ {
+ // we allocate 105% of original size for output buffer
+ outSize = (size_t)fileSize / 20 * 21 + (1 << 16);
+ if (outSize != 0)
+ {
+ outBuffer = (Byte *)MyAlloc((size_t)outSize);
+ if (outBuffer == 0)
+ throw kCantAllocate;
+ }
+ if (!dictDefined)
+ dict = 1 << 23;
+ int res = Lzma86_Encode(outBuffer, &outSize, inBuffer, inSize,
+ 5, dict, parser[NKey::kFilter86].PostCharIndex == 0 ? SZ_FILTER_YES : SZ_FILTER_AUTO);
+ if (res != 0)
+ {
+ fprintf(stderr, "\nEncoder error = %d\n", (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 "too big";
+ if (outSize != 0)
+ {
+ outBuffer = (Byte *)MyAlloc(outSize);
+ if (outBuffer == 0)
+ throw kCantAllocate;
+ }
+ int res = Lzma86_Decode(outBuffer, &outSize, inBuffer, &inSize);
+ if (inSize != (size_t)fileSize)
+ throw "incorrect processed size";
+ if (res != 0)
+ throw "LzmaDecoder error";
+ }
+ if (WriteStream(outStream, outBuffer, outSize) != S_OK)
+ throw kWriteError;
+ MyFree(outBuffer);
+ MyFree(inBuffer);
+ return 0;
+ }
+
+
+ UInt64 fileSize;
+ if (encodeMode)
+ {
+ NCompress::NLzma::CEncoder *encoderSpec = new NCompress::NLzma::CEncoder;
+ CMyComPtr<ICompressCoder> encoder = encoderSpec;
+
+ if (!dictDefined)
+ dict = 1 << 23;
+
+ 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)
+ if (!GetNumber(parser[NKey::kMc].PostStrings[0], mc))
+ IncorrectCommand();
+
+ 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--;
+
+ if (encoderSpec->SetCoderProperties(propIDs, props, numProps) != S_OK)
+ IncorrectCommand();
+ encoderSpec->WriteCoderProperties(outStream);
+
+ if (eos || stdInMode)
+ fileSize = (UInt64)(Int64)-1;
+ else
+ inStreamSpec->File.GetLength(fileSize);
+
+ for (int i = 0; i < 8; i++)
+ {
+ Byte b = Byte(fileSize >> (8 * i));
+ if (outStream->Write(&b, 1, 0) != S_OK)
+ {
+ PrintMessage(kWriteError);
+ return 1;
+ }
+ }
+ HRESULT result = encoder->Code(inStream, outStream, 0, 0, 0);
+ if (result == E_OUTOFMEMORY)
+ {
+ PrintMessage("\nError: Can not allocate memory\n");
+ return 1;
+ }
+ else if (result != S_OK)
+ {
+ fprintf(stderr, "\nEncoder error = %X\n", (unsigned)result);
+ return 1;
+ }
+ }
+ else
+ {
+ NCompress::NLzma::CDecoder *decoderSpec = new NCompress::NLzma::CDecoder;
+ CMyComPtr<ICompressCoder> decoder = decoderSpec;
+ decoderSpec->FinishStream = true;
+ const UInt32 kPropertiesSize = 5;
+ Byte header[kPropertiesSize + 8];
+ if (ReadStream_FALSE(inStream, header, kPropertiesSize + 8) != S_OK)
+ {
+ PrintMessage(kReadError);
+ return 1;
+ }
+ if (decoderSpec->SetDecoderProperties2(header, kPropertiesSize) != S_OK)
+ {
+ PrintMessage("SetDecoderProperties error");
+ return 1;
+ }
+ fileSize = 0;
+ for (int i = 0; i < 8; i++)
+ fileSize |= ((UInt64)header[kPropertiesSize + i]) << (8 * i);
+
+ bool isSizeDefined = (fileSize != (UInt64)(Int64)-1);
+ HRESULT res = decoder->Code(inStream, outStream, 0, isSizeDefined ? &fileSize : NULL, 0) != S_OK;
+ if (res != S_OK)
+ {
+ PrintMessage("Decoder error");
+ return 1;
+ }
+ if (isSizeDefined && decoderSpec->GetOutputProcessedSize() != fileSize)
+ {
+ PrintMessage("Error: incorrect uncompressed size in header");
+ return 1;
+ }
+ }
+ if (outStreamSpec != NULL)
+ {
+ if (outStreamSpec->Close() != S_OK)
+ {
+ PrintMessage("File closing error");
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int MY_CDECL main(int numArgs, const char *args[])
+{
+ try { return main2(numArgs, args); }
+ catch (const char *s)
+ {
+ fprintf(stderr, "\nError: %s\n", s);
+ return 1;
+ }
+ catch(...)
+ {
+ PrintMessage("\nError\n");
+ return 1;
+ }
+}
diff --git a/lzma/CPP/7zip/Bundles/LzmaCon/LzmaCon.dsp b/lzma/CPP/7zip/Bundles/LzmaCon/LzmaCon.dsp
new file mode 100644
index 0000000..3e43804
--- /dev/null
+++ b/lzma/CPP/7zip/Bundles/LzmaCon/LzmaCon.dsp
@@ -0,0 +1,477 @@
+# 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\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
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Types.h
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=.\LzmaAlone.cpp
+# End Source File
+# End Target
+# End Project
diff --git a/lzma/CPP/7zip/Bundles/LzmaCon/LzmaCon.dsw b/lzma/CPP/7zip/Bundles/LzmaCon/LzmaCon.dsw
new file mode 100644
index 0000000..c6a6662
--- /dev/null
+++ b/lzma/CPP/7zip/Bundles/LzmaCon/LzmaCon.dsw
@@ -0,0 +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>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/lzma/CPP/7zip/Bundles/LzmaCon/StdAfx.cpp b/lzma/CPP/7zip/Bundles/LzmaCon/StdAfx.cpp
new file mode 100644
index 0000000..c6d3b1f
--- /dev/null
+++ b/lzma/CPP/7zip/Bundles/LzmaCon/StdAfx.cpp
@@ -0,0 +1,3 @@
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/lzma/CPP/7zip/Bundles/LzmaCon/StdAfx.h b/lzma/CPP/7zip/Bundles/LzmaCon/StdAfx.h
new file mode 100644
index 0000000..59d9ac1
--- /dev/null
+++ b/lzma/CPP/7zip/Bundles/LzmaCon/StdAfx.h
@@ -0,0 +1,8 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "../../../Common/Common.h"
+
+#endif
diff --git a/lzma/CPP/7zip/Bundles/LzmaCon/makefile b/lzma/CPP/7zip/Bundles/LzmaCon/makefile
new file mode 100644
index 0000000..2609763
--- /dev/null
+++ b/lzma/CPP/7zip/Bundles/LzmaCon/makefile
@@ -0,0 +1,59 @@
+PROG = lzma.exe
+MY_CONSOLE = 1
+CFLAGS = $(CFLAGS)
+
+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 "../../7zip.mak"
diff --git a/lzma/CPP/7zip/Bundles/LzmaCon/makefile.gcc b/lzma/CPP/7zip/Bundles/LzmaCon/makefile.gcc
new file mode 100644
index 0000000..ae9e27a
--- /dev/null
+++ b/lzma/CPP/7zip/Bundles/LzmaCon/makefile.gcc
@@ -0,0 +1,198 @@
+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 = \
+ System.o \
+ 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 \
+ 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
+
+ifdef MT_FILES
+System.o: ../../../Windows/System.cpp
+ $(CXX) $(CFLAGS) ../../../Windows/System.cpp
+endif
+
+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)
+
diff --git a/lzma/CPP/7zip/Bundles/LzmaCon/resource.rc b/lzma/CPP/7zip/Bundles/LzmaCon/resource.rc
new file mode 100644
index 0000000..6b5918d
--- /dev/null
+++ b/lzma/CPP/7zip/Bundles/LzmaCon/resource.rc
@@ -0,0 +1,3 @@
+#include "../../../../C/7zVersion.rc"
+
+MY_VERSION_INFO_APP("LZMA", "lzma")
diff --git a/lzma/CPP/7zip/Bundles/LzmaSpec/LzmaSpec.cpp b/lzma/CPP/7zip/Bundles/LzmaSpec/LzmaSpec.cpp
new file mode 100644
index 0000000..bd79123
--- /dev/null
+++ b/lzma/CPP/7zip/Bundles/LzmaSpec/LzmaSpec.cpp
@@ -0,0 +1,713 @@
+/* LzmaSpec.c -- LZMA Reference Decoder
+2013-07-28 : 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;
+
+ void Init();
+ bool IsFinishedOK() const { return Code == 0; }
+
+ UInt32 DecodeDirectBits(unsigned numBits);
+ unsigned DecodeBit(CProb *prob);
+};
+
+void CRangeDecoder::Init()
+{
+ Corrupted = false;
+
+ if (InStream->ReadByte() != 0)
+ Corrupted = true;
+
+ Range = 0xFFFFFFFF;
+ Code = 0;
+ for (int i = 0; i < 4; i++)
+ Code = (Code << 8) | InStream->ReadByte();
+
+ if (Code == Range)
+ Corrupted = true;
+}
+
+#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)
+{
+ Init();
+ RangeDec.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 9.31 : Igor Pavlov : Public domain : 2013-02-06\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();
+ // we support the streams that have uncompressed size and marker.
+ 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/lzma/CPP/7zip/Bundles/SFXCon/7z.ico b/lzma/CPP/7zip/Bundles/SFXCon/7z.ico
new file mode 100644
index 0000000..47ffb78
--- /dev/null
+++ b/lzma/CPP/7zip/Bundles/SFXCon/7z.ico
Binary files differ
diff --git a/lzma/CPP/7zip/Bundles/SFXCon/SFXCon.dsp b/lzma/CPP/7zip/Bundles/SFXCon/SFXCon.dsp
new file mode 100644
index 0000000..6f380b1
--- /dev/null
+++ b/lzma/CPP/7zip/Bundles/SFXCon/SFXCon.dsp
@@ -0,0 +1,837 @@
+# 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\CoderMixer2MT.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\CoderMixer2MT.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\CrossThreadProgress.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\CrossThreadProgress.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\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\7zFolderOutStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zFolderOutStream.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\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\BranchCoder.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\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 "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
+# 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\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\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\CpuArch.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\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\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
diff --git a/lzma/CPP/7zip/Bundles/SFXCon/SFXCon.dsw b/lzma/CPP/7zip/Bundles/SFXCon/SFXCon.dsw
new file mode 100644
index 0000000..bfbc2b7
--- /dev/null
+++ b/lzma/CPP/7zip/Bundles/SFXCon/SFXCon.dsw
@@ -0,0 +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>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/lzma/CPP/7zip/Bundles/SFXCon/SfxCon.cpp b/lzma/CPP/7zip/Bundles/SFXCon/SfxCon.cpp
new file mode 100644
index 0000000..ae525fe
--- /dev/null
+++ b/lzma/CPP/7zip/Bundles/SFXCon/SfxCon.cpp
@@ -0,0 +1,453 @@
+// Main.cpp
+
+#include "StdAfx.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"
+
+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 *kCopyrightString =
+"\n7-Zip SFX " MY_VERSION_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';
+static const wchar_t *kRecursedPostCharSet = L"0-";
+
+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 wchar_t *kUniversalWildcard = L"*";
+static const int kCommandIndex = 0;
+
+static const char *kHelpString =
+ "\nUsage: 7zSFX [<command>] [<switches>...]\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 *kUserErrorMessage = "Incorrect command line"; // NExitCode::kUserError
+// static const char *kIncorrectListFile = "Incorrect wildcard in listfile";
+static const char *kIncorrectWildcardInCommandLine = "Incorrect wildcard in command line";
+
+// static const CSysString kFileIsNotArchiveMessageBefore = "File \"";
+// static const CSysString kFileIsNotArchiveMessageAfter = "\" is not archive";
+
+// static const char *kProcessArchiveMessage = " archive: ";
+
+static const char *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);
+}
+
+void AddToCensorFromNonSwitchesStrings(NWildcard::CCensor &wildcardCensor,
+ const UStringVector & /* nonSwitchStrings */, NRecursedType::EEnum type,
+ bool /* thereAreSwitchIncludeWildcards */)
+{
+ AddCommandLineWildcardToCensor(wildcardCensor, kUniversalWildcard, true, type);
+}
+
+
+#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
+)
+{
+ #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
+
+ commandStrings.Delete(0);
+
+ NCommandLineParser::CParser parser(kNumSwitches);
+ try
+ {
+ parser.ParseStrings(kSwitchForms, commandStrings);
+ }
+ catch(...)
+ {
+ PrintHelpAndExit();
+ }
+
+ if (parser[NKey::kHelp1].ThereIs || parser[NKey::kHelp2].ThereIs)
+ {
+ PrintHelp();
+ return 0;
+ }
+ const UStringVector &nonSwitchStrings = parser.NonSwitchStrings;
+
+ int numNonSwitchStrings = nonSwitchStrings.Size();
+
+ CArchiveCommand command;
+ if (numNonSwitchStrings == 0)
+ command.CommandType = NCommandType::kFullExtract;
+ else
+ {
+ if (numNonSwitchStrings > 1)
+ PrintHelpAndExit();
+ if (!ParseArchiveCommand(nonSwitchStrings[kCommandIndex], command))
+ PrintHelpAndExit();
+ }
+
+
+ NRecursedType::EEnum recursedType;
+ recursedType = command.DefaultRecursedType();
+
+ NWildcard::CCensor wildcardCensor;
+
+ bool thereAreSwitchIncludeWildcards;
+ thereAreSwitchIncludeWildcards = false;
+
+ AddToCensorFromNonSwitchesStrings(wildcardCensor, nonSwitchStrings, recursedType,
+ thereAreSwitchIncludeWildcards);
+
+ 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->OutStream = g_StdStream;
+
+ #ifndef _NO_CRYPTO
+ ecs->PasswordIsDefined = passwordEnabled;
+ ecs->Password = password;
+ #endif
+
+ ecs->Init();
+
+ COpenCallbackConsole openCallback;
+ openCallback.OutStream = 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, &openCallback, 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
+ {
+ 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;
+}
diff --git a/lzma/CPP/7zip/Bundles/SFXCon/StdAfx.cpp b/lzma/CPP/7zip/Bundles/SFXCon/StdAfx.cpp
new file mode 100644
index 0000000..c6d3b1f
--- /dev/null
+++ b/lzma/CPP/7zip/Bundles/SFXCon/StdAfx.cpp
@@ -0,0 +1,3 @@
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/lzma/CPP/7zip/Bundles/SFXCon/StdAfx.h b/lzma/CPP/7zip/Bundles/SFXCon/StdAfx.h
new file mode 100644
index 0000000..59d9ac1
--- /dev/null
+++ b/lzma/CPP/7zip/Bundles/SFXCon/StdAfx.h
@@ -0,0 +1,8 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "../../../Common/Common.h"
+
+#endif
diff --git a/lzma/CPP/7zip/Bundles/SFXCon/makefile b/lzma/CPP/7zip/Bundles/SFXCon/makefile
new file mode 100644
index 0000000..4d35d7e
--- /dev/null
+++ b/lzma/CPP/7zip/Bundles/SFXCon/makefile
@@ -0,0 +1,124 @@
+PROG = 7zCon.sfx
+MY_CONSOLE = 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\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 \
+
+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\LockedStream.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\CoderMixer2MT.obj \
+ $O\CrossThreadProgress.obj \
+ $O\ItemNameUtils.obj \
+ $O\MultiStream.obj \
+ $O\OutStreamWithCRC.obj \
+
+
+7Z_OBJS = \
+ $O\7zDecode.obj \
+ $O\7zExtract.obj \
+ $O\7zFolderOutStream.obj \
+ $O\7zHandler.obj \
+ $O\7zIn.obj \
+ $O\7zRegister.obj \
+
+COMPRESS_OBJS = \
+ $O\BranchCoder.obj \
+ $O\Bcj2Coder.obj \
+ $O\Bcj2Register.obj \
+ $O\BcjCoder.obj \
+ $O\BcjRegister.obj \
+ $O\CopyCoder.obj \
+ $O\CopyRegister.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\Bra86.obj \
+ $O\CpuArch.obj \
+ $O\Lzma2Dec.obj \
+ $O\LzmaDec.obj \
+ $O\Ppmd7.obj \
+ $O\Ppmd7Dec.obj \
+ $O\Sha256.obj \
+ $O\Threads.obj \
+
+!include "../../Aes.mak"
+!include "../../Crc.mak"
+
+!include "../../7zip.mak"
diff --git a/lzma/CPP/7zip/Bundles/SFXCon/resource.rc b/lzma/CPP/7zip/Bundles/SFXCon/resource.rc
new file mode 100644
index 0000000..1c34357
--- /dev/null
+++ b/lzma/CPP/7zip/Bundles/SFXCon/resource.rc
@@ -0,0 +1,5 @@
+#include "../../../../C/7zVersion.rc"
+
+MY_VERSION_INFO_APP("7z Console SFX", "7z.sfx")
+
+101 ICON "7z.ico"
\ No newline at end of file
diff --git a/lzma/CPP/7zip/Bundles/SFXSetup/ExtractCallbackSfx.cpp b/lzma/CPP/7zip/Bundles/SFXSetup/ExtractCallbackSfx.cpp
new file mode 100644
index 0000000..0811978
--- /dev/null
+++ b/lzma/CPP/7zip/Bundles/SFXSetup/ExtractCallbackSfx.cpp
@@ -0,0 +1,238 @@
+// 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 LPCWSTR kCantDeleteFile = L"Can not delete output file";
+static LPCWSTR kCantOpenFile = L"Can not open output file";
+static LPCWSTR kUnsupportedMethod = L"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
+}
+
+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 += FCHAR_PATH_SEPARATOR;
+ }
+}
+
+STDMETHODIMP CExtractCallbackImp::GetStream(UInt32 index,
+ ISequentialOutStream **outStream, Int32 askExtractMode)
+{
+ #ifndef _NO_PROGRESS
+ if (ProgressDialog.Sync.GetStopped())
+ return E_ABORT;
+ #endif
+ _outFileStream.Release();
+ NCOM::CPropVariant propVariantName;
+ RINOK(_archiveHandler->GetProperty(index, kpidPath, &propVariantName));
+ UString fullPath;
+ if (propVariantName.vt == VT_EMPTY)
+ fullPath = _itemDefaultName;
+ else
+ {
+ if (propVariantName.vt != VT_BSTR)
+ return E_FAIL;
+ fullPath = propVariantName.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;
+}
diff --git a/lzma/CPP/7zip/Bundles/SFXSetup/ExtractCallbackSfx.h b/lzma/CPP/7zip/Bundles/SFXSetup/ExtractCallbackSfx.h
new file mode 100644
index 0000000..b7f04e0
--- /dev/null
+++ b/lzma/CPP/7zip/Bundles/SFXSetup/ExtractCallbackSfx.h
@@ -0,0 +1,86 @@
+// 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
diff --git a/lzma/CPP/7zip/Bundles/SFXSetup/ExtractEngine.cpp b/lzma/CPP/7zip/Bundles/SFXSetup/ExtractEngine.cpp
new file mode 100644
index 0000000..ba0e960
--- /dev/null
+++ b/lzma/CPP/7zip/Bundles/SFXSetup/ExtractEngine.cpp
@@ -0,0 +1,138 @@
+// 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 LPCWSTR kCantFindArchive = L"Can not find archive file";
+static LPCWSTR kCantOpenArchive = L"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 = !
+ options.filePath = fs2us(FileName);
+
+ Result = ArchiveLink.Open2(options, ExtractCallbackSpec);
+ if (Result != S_OK)
+ {
+ 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, L"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;
+}
diff --git a/lzma/CPP/7zip/Bundles/SFXSetup/ExtractEngine.h b/lzma/CPP/7zip/Bundles/SFXSetup/ExtractEngine.h
new file mode 100644
index 0000000..8aa9724
--- /dev/null
+++ b/lzma/CPP/7zip/Bundles/SFXSetup/ExtractEngine.h
@@ -0,0 +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
diff --git a/lzma/CPP/7zip/Bundles/SFXSetup/SFXSetup.dsp b/lzma/CPP/7zip/Bundles/SFXSetup/SFXSetup.dsp
new file mode 100644
index 0000000..1024311
--- /dev/null
+++ b/lzma/CPP/7zip/Bundles/SFXSetup/SFXSetup.dsp
@@ -0,0 +1,752 @@
+# 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\7zFolderOutStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zFolderOutStream.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\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\CoderMixer2MT.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\CoderMixer2MT.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\CrossThreadProgress.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\CrossThreadProgress.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\BranchCoder.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\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\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\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 "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\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\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\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\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\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
diff --git a/lzma/CPP/7zip/Bundles/SFXSetup/SFXSetup.dsw b/lzma/CPP/7zip/Bundles/SFXSetup/SFXSetup.dsw
new file mode 100644
index 0000000..2970370
--- /dev/null
+++ b/lzma/CPP/7zip/Bundles/SFXSetup/SFXSetup.dsw
@@ -0,0 +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>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/lzma/CPP/7zip/Bundles/SFXSetup/SfxSetup.cpp b/lzma/CPP/7zip/Bundles/SFXSetup/SfxSetup.cpp
new file mode 100644
index 0000000..202c262
--- /dev/null
+++ b/lzma/CPP/7zip/Bundles/SFXSetup/SfxSetup.cpp
@@ -0,0 +1,356 @@
+// Main.cpp
+
+#include "StdAfx.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;
+
+HINSTANCE g_hInstance;
+
+static CFSTR 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[] = ",!@Install@!UTF-8!";
+static char kEndID[] = ",!@InstallEnd@!";
+
+class CInstallIDInit
+{
+public:
+ 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
+
+ // 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 (MyStringCompareNoCase_N(switches, L"-y", 2) == 0)
+ {
+ 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 = L"." WSTRING_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, L"Title");
+ UString installPrompt = GetTextConfigValue(pairs, L"BeginPrompt");
+ UString progress = GetTextConfigValue(pairs, L"Progress");
+ if (progress.IsEqualToNoCase(L"no"))
+ showProgress = false;
+ int index = FindTextConfigItem(pairs, L"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, L"RunProgram");
+
+ #ifdef _SHELL_EXECUTE
+ executeFile = GetTextConfigValue(pairs, L"ExecuteFile");
+ executeParameters = GetTextConfigValue(pairs, L"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())
+ {
+ if (!executeParameters.IsEmpty())
+ executeParameters += L' ';
+ 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 += L' ';
+ 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;
+}
diff --git a/lzma/CPP/7zip/Bundles/SFXSetup/StdAfx.cpp b/lzma/CPP/7zip/Bundles/SFXSetup/StdAfx.cpp
new file mode 100644
index 0000000..c6d3b1f
--- /dev/null
+++ b/lzma/CPP/7zip/Bundles/SFXSetup/StdAfx.cpp
@@ -0,0 +1,3 @@
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/lzma/CPP/7zip/Bundles/SFXSetup/StdAfx.h b/lzma/CPP/7zip/Bundles/SFXSetup/StdAfx.h
new file mode 100644
index 0000000..72410ee
--- /dev/null
+++ b/lzma/CPP/7zip/Bundles/SFXSetup/StdAfx.h
@@ -0,0 +1,13 @@
+// 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
diff --git a/lzma/CPP/7zip/Bundles/SFXSetup/makefile b/lzma/CPP/7zip/Bundles/SFXSetup/makefile
new file mode 100644
index 0000000..47c65f9
--- /dev/null
+++ b/lzma/CPP/7zip/Bundles/SFXSetup/makefile
@@ -0,0 +1,107 @@
+PROG = 7zS.sfx
+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\Window.obj \
+
+WIN_CTRL_OBJS = \
+ $O\Dialog.obj \
+
+7ZIP_COMMON_OBJS = \
+ $O\CreateCoder.obj \
+ $O\FileStreams.obj \
+ $O\InBuffer.obj \
+ $O\FilterCoder.obj \
+ $O\LimitedStreams.obj \
+ $O\LockedStream.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\CoderMixer2MT.obj \
+ $O\CrossThreadProgress.obj \
+ $O\ItemNameUtils.obj \
+ $O\OutStreamWithCRC.obj \
+
+7Z_OBJS = \
+ $O\7zDecode.obj \
+ $O\7zExtract.obj \
+ $O\7zFolderOutStream.obj \
+ $O\7zHandler.obj \
+ $O\7zIn.obj \
+ $O\7zRegister.obj \
+
+COMPRESS_OBJS = \
+ $O\BranchCoder.obj \
+ $O\Bcj2Coder.obj \
+ $O\Bcj2Register.obj \
+ $O\BcjCoder.obj \
+ $O\BcjRegister.obj \
+ $O\CopyCoder.obj \
+ $O\CopyRegister.obj \
+ $O\Lzma2Decoder.obj \
+ $O\Lzma2Register.obj \
+ $O\LzmaDecoder.obj \
+ $O\LzmaRegister.obj \
+
+C_OBJS = \
+ $O\Alloc.obj \
+ $O\Bra86.obj \
+ $O\CpuArch.obj \
+ $O\Lzma2Dec.obj \
+ $O\LzmaDec.obj \
+ $O\Threads.obj \
+
+!include "../../Crc.mak"
+
+!include "../../7zip.mak"
diff --git a/lzma/CPP/7zip/Bundles/SFXSetup/resource.h b/lzma/CPP/7zip/Bundles/SFXSetup/resource.h
new file mode 100644
index 0000000..533197e
--- /dev/null
+++ b/lzma/CPP/7zip/Bundles/SFXSetup/resource.h
@@ -0,0 +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
diff --git a/lzma/CPP/7zip/Bundles/SFXSetup/resource.rc b/lzma/CPP/7zip/Bundles/SFXSetup/resource.rc
new file mode 100644
index 0000000..7a16044
--- /dev/null
+++ b/lzma/CPP/7zip/Bundles/SFXSetup/resource.rc
@@ -0,0 +1,16 @@
+#include "../../../../C/7zVersion.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/lzma/CPP/7zip/Bundles/SFXSetup/setup.ico b/lzma/CPP/7zip/Bundles/SFXSetup/setup.ico
new file mode 100644
index 0000000..bb455be
--- /dev/null
+++ b/lzma/CPP/7zip/Bundles/SFXSetup/setup.ico
Binary files differ
diff --git a/lzma/CPP/7zip/Bundles/SFXWin/7z.ico b/lzma/CPP/7zip/Bundles/SFXWin/7z.ico
new file mode 100644
index 0000000..47ffb78
--- /dev/null
+++ b/lzma/CPP/7zip/Bundles/SFXWin/7z.ico
Binary files differ
diff --git a/lzma/CPP/7zip/Bundles/SFXWin/SFXWin.dsp b/lzma/CPP/7zip/Bundles/SFXWin/SFXWin.dsp
new file mode 100644
index 0000000..711582f
--- /dev/null
+++ b/lzma/CPP/7zip/Bundles/SFXWin/SFXWin.dsp
@@ -0,0 +1,937 @@
+# 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\7zFolderOutStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zFolderOutStream.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\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\CoderMixer2MT.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\CoderMixer2MT.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\CrossThreadProgress.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\CrossThreadProgress.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\BranchCoder.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\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\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
+# 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\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\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\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\CpuArch.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\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\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
diff --git a/lzma/CPP/7zip/Bundles/SFXWin/SFXWin.dsw b/lzma/CPP/7zip/Bundles/SFXWin/SFXWin.dsw
new file mode 100644
index 0000000..6695803
--- /dev/null
+++ b/lzma/CPP/7zip/Bundles/SFXWin/SFXWin.dsw
@@ -0,0 +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>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/lzma/CPP/7zip/Bundles/SFXWin/SfxWin.cpp b/lzma/CPP/7zip/Bundles/SFXWin/SfxWin.cpp
new file mode 100644
index 0000000..42e940f
--- /dev/null
+++ b/lzma/CPP/7zip/Bundles/SFXWin/SfxWin.cpp
@@ -0,0 +1,233 @@
+// Main.cpp
+
+#include "StdAfx.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"
+
+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 *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
+ {
+ return WinMain2();
+ }
+ catch(const CNewException &)
+ {
+ ErrorMessageForHRESULT(E_OUTOFMEMORY);
+ return NExitCode::kMemoryError;
+ }
+ catch(...)
+ {
+ ShowErrorMessage(kUnknownExceptionMessage);
+ return NExitCode::kFatalError;
+ }
+}
diff --git a/lzma/CPP/7zip/Bundles/SFXWin/StdAfx.cpp b/lzma/CPP/7zip/Bundles/SFXWin/StdAfx.cpp
new file mode 100644
index 0000000..c6d3b1f
--- /dev/null
+++ b/lzma/CPP/7zip/Bundles/SFXWin/StdAfx.cpp
@@ -0,0 +1,3 @@
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/lzma/CPP/7zip/Bundles/SFXWin/StdAfx.h b/lzma/CPP/7zip/Bundles/SFXWin/StdAfx.h
new file mode 100644
index 0000000..f263ecb
--- /dev/null
+++ b/lzma/CPP/7zip/Bundles/SFXWin/StdAfx.h
@@ -0,0 +1,14 @@
+// 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
diff --git a/lzma/CPP/7zip/Bundles/SFXWin/makefile b/lzma/CPP/7zip/Bundles/SFXWin/makefile
new file mode 100644
index 0000000..36806c8
--- /dev/null
+++ b/lzma/CPP/7zip/Bundles/SFXWin/makefile
@@ -0,0 +1,143 @@
+PROG = 7z.sfx
+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\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\LockedStream.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\SysIconUtils.obj \
+
+AR_OBJS = \
+ $O\SplitHandler.obj \
+
+AR_COMMON_OBJS = \
+ $O\CoderMixer2.obj \
+ $O\CoderMixer2MT.obj \
+ $O\CrossThreadProgress.obj \
+ $O\ItemNameUtils.obj \
+ $O\MultiStream.obj \
+ $O\OutStreamWithCRC.obj \
+
+7Z_OBJS = \
+ $O\7zDecode.obj \
+ $O\7zExtract.obj \
+ $O\7zFolderOutStream.obj \
+ $O\7zHandler.obj \
+ $O\7zIn.obj \
+ $O\7zRegister.obj \
+
+COMPRESS_OBJS = \
+ $O\BranchCoder.obj \
+ $O\Bcj2Coder.obj \
+ $O\Bcj2Register.obj \
+ $O\BcjCoder.obj \
+ $O\BcjRegister.obj \
+ $O\CopyCoder.obj \
+ $O\CopyRegister.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\Bra86.obj \
+ $O\CpuArch.obj \
+ $O\Lzma2Dec.obj \
+ $O\LzmaDec.obj \
+ $O\Ppmd7.obj \
+ $O\Ppmd7Dec.obj \
+ $O\Sha256.obj \
+ $O\Threads.obj \
+
+!include "../../Aes.mak"
+!include "../../Crc.mak"
+
+!include "../../7zip.mak"
diff --git a/lzma/CPP/7zip/Bundles/SFXWin/resource.h b/lzma/CPP/7zip/Bundles/SFXWin/resource.h
new file mode 100644
index 0000000..d9fae1b
--- /dev/null
+++ b/lzma/CPP/7zip/Bundles/SFXWin/resource.h
@@ -0,0 +1 @@
+#define IDI_ICON 1
diff --git a/lzma/CPP/7zip/Bundles/SFXWin/resource.rc b/lzma/CPP/7zip/Bundles/SFXWin/resource.rc
new file mode 100644
index 0000000..3e24fa6
--- /dev/null
+++ b/lzma/CPP/7zip/Bundles/SFXWin/resource.rc
@@ -0,0 +1,50 @@
+#include "../../../../C/7zVersion.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
diff --git a/lzma/CPP/7zip/Common/CWrappers.cpp b/lzma/CPP/7zip/Common/CWrappers.cpp
new file mode 100644
index 0000000..14424d5
--- /dev/null
+++ b/lzma/CPP/7zip/Common/CWrappers.cpp
@@ -0,0 +1,230 @@
+// CWrappers.h
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+
+#include "CWrappers.h"
+
+#include "StreamUtils.h"
+
+#define PROGRESS_UNKNOWN_VALUE ((UInt64)(Int64)-1)
+
+#define CONVERT_PR_VAL(x) (x == PROGRESS_UNKNOWN_VALUE ? NULL : &x)
+
+static SRes CompressProgress(void *pp, UInt64 inSize, UInt64 outSize) throw()
+{
+ CCompressProgressWrap *p = (CCompressProgressWrap *)pp;
+ p->Res = p->Progress->SetRatioInfo(CONVERT_PR_VAL(inSize), CONVERT_PR_VAL(outSize));
+ return (SRes)p->Res;
+}
+
+CCompressProgressWrap::CCompressProgressWrap(ICompressProgressInfo *progress) throw()
+{
+ p.Progress = CompressProgress;
+ Progress = progress;
+ Res = SZ_OK;
+}
+
+static const UInt32 kStreamStepSize = (UInt32)1 << 31;
+
+SRes HRESULT_To_SRes(HRESULT res, SRes defaultRes)
+{
+ 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;
+}
+
+static SRes MyRead(void *object, void *data, size_t *size) throw()
+{
+ CSeqInStreamWrap *p = (CSeqInStreamWrap *)object;
+ 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(void *object, const void *data, size_t size) throw()
+{
+ CSeqOutStreamWrap *p = (CSeqOutStreamWrap *)object;
+ 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;
+}
+
+CSeqInStreamWrap::CSeqInStreamWrap(ISequentialInStream *stream) throw()
+{
+ p.Read = MyRead;
+ Stream = stream;
+ Processed = 0;
+}
+
+CSeqOutStreamWrap::CSeqOutStreamWrap(ISequentialOutStream *stream) throw()
+{
+ p.Write = MyWrite;
+ Stream = stream;
+ Res = SZ_OK;
+ Processed = 0;
+}
+
+HRESULT SResToHRESULT(SRes res) throw()
+{
+ 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_PROGRESS: return E_ABORT;
+ case SZ_ERROR_DATA: return S_FALSE;
+ case SZ_ERROR_UNSUPPORTED: return E_NOTIMPL;
+ }
+ return E_FAIL;
+}
+
+static SRes InStreamWrap_Read(void *pp, void *data, size_t *size) throw()
+{
+ CSeekInStreamWrap *p = (CSeekInStreamWrap *)pp;
+ 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(void *pp, Int64 *offset, ESzSeek origin) throw()
+{
+ CSeekInStreamWrap *p = (CSeekInStreamWrap *)pp;
+ 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;
+}
+
+CSeekInStreamWrap::CSeekInStreamWrap(IInStream *stream) throw()
+{
+ Stream = stream;
+ p.Read = InStreamWrap_Read;
+ p.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(void *pp) throw()
+{
+ CByteInBufWrap *p = (CByteInBufWrap *)pp;
+ if (p->Cur != p->Lim)
+ return *p->Cur++;
+ return p->ReadByteFromNewBlock();
+}
+
+CByteInBufWrap::CByteInBufWrap(): Buf(0)
+{
+ p.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(void *pp, Byte b) throw()
+{
+ CByteOutBufWrap *p = (CByteOutBufWrap *)pp;
+ Byte *dest = p->Cur;
+ *dest = b;
+ p->Cur = ++dest;
+ if (dest == p->Lim)
+ p->Flush();
+}
+
+CByteOutBufWrap::CByteOutBufWrap() throw(): Buf(0)
+{
+ p.Write = Wrap_WriteByte;
+}
diff --git a/lzma/CPP/7zip/Common/CWrappers.h b/lzma/CPP/7zip/Common/CWrappers.h
new file mode 100644
index 0000000..0872133
--- /dev/null
+++ b/lzma/CPP/7zip/Common/CWrappers.h
@@ -0,0 +1,114 @@
+// CWrappers.h
+
+#ifndef __C_WRAPPERS_H
+#define __C_WRAPPERS_H
+
+#include "../ICoder.h"
+#include "../../Common/MyCom.h"
+
+struct CCompressProgressWrap
+{
+ ICompressProgress p;
+ ICompressProgressInfo *Progress;
+ HRESULT Res;
+
+ CCompressProgressWrap(ICompressProgressInfo *progress) throw();
+};
+
+struct CSeqInStreamWrap
+{
+ ISeqInStream p;
+ ISequentialInStream *Stream;
+ HRESULT Res;
+ UInt64 Processed;
+
+ CSeqInStreamWrap(ISequentialInStream *stream) throw();
+};
+
+struct CSeekInStreamWrap
+{
+ ISeekInStream p;
+ IInStream *Stream;
+ HRESULT Res;
+
+ CSeekInStreamWrap(IInStream *stream) throw();
+};
+
+struct CSeqOutStreamWrap
+{
+ ISeqOutStream p;
+ ISequentialOutStream *Stream;
+ HRESULT Res;
+ UInt64 Processed;
+
+ CSeqOutStreamWrap(ISequentialOutStream *stream) throw();
+};
+
+HRESULT SResToHRESULT(SRes res) throw();
+
+struct CByteInBufWrap
+{
+ IByteIn p;
+ 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 p;
+ 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
diff --git a/lzma/CPP/7zip/Common/CreateCoder.cpp b/lzma/CPP/7zip/Common/CreateCoder.cpp
new file mode 100644
index 0000000..8be4e05
--- /dev/null
+++ b/lzma/CPP/7zip/Common/CreateCoder.cpp
@@ -0,0 +1,391 @@
+// 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 int kNumCodecsMax = 64;
+unsigned int 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 int kNumHashersMax = 16;
+unsigned int 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::LoadCodecs()
+{
+ if (GetCodecs)
+ {
+ UInt32 num;
+ RINOK(GetCodecs->GetNumberOfMethods(&num));
+ for (UInt32 i = 0; i < num; i++)
+ {
+ CCodecInfoEx info;
+ NWindows::NCOM::CPropVariant prop;
+ RINOK(GetCodecs->GetProperty(i, NMethodPropID::kID, &prop));
+ // if (prop.vt != VT_BSTR)
+ // info.Id.IDSize = (Byte)SysStringByteLen(prop.bstrVal);
+ // memcpy(info.Id.ID, prop.bstrVal, info.Id.IDSize);
+ if (prop.vt != VT_UI8)
+ continue; // old Interface
+ info.Id = prop.uhVal.QuadPart;
+ prop.Clear();
+
+ RINOK(GetCodecs->GetProperty(i, NMethodPropID::kName, &prop));
+ if (prop.vt == VT_BSTR)
+ info.Name = prop.bstrVal;
+ else if (prop.vt != VT_EMPTY)
+ return E_INVALIDARG;
+
+ RINOK(ReadNumberOfStreams(GetCodecs, i, NMethodPropID::kInStreams, info.NumInStreams));
+ RINOK(ReadNumberOfStreams(GetCodecs, i, NMethodPropID::kOutStreams, info.NumOutStreams));
+ 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();
+ for (UInt32 i = 0; i < num; i++)
+ {
+ CHasherInfoEx info;
+ NWindows::NCOM::CPropVariant prop;
+ RINOK(GetHashers->GetHasherProp(i, NMethodPropID::kID, &prop));
+ if (prop.vt != VT_UI8)
+ continue;
+ info.Id = prop.uhVal.QuadPart;
+ prop.Clear();
+
+ RINOK(GetHashers->GetHasherProp(i, NMethodPropID::kName, &prop));
+ if (prop.vt == VT_BSTR)
+ info.Name = prop.bstrVal;
+ else if (prop.vt != VT_EMPTY)
+ return E_INVALIDARG;
+
+ Hashers.Add(info);
+ }
+ }
+ return S_OK;
+}
+
+#endif
+
+bool FindMethod(DECL_EXTERNAL_CODECS_LOC_VARS
+ const UString &name, CMethodId &methodId, UInt32 &numInStreams, UInt32 &numOutStreams)
+{
+ UInt32 i;
+ for (i = 0; i < g_NumCodecs; i++)
+ {
+ const CCodecInfo &codec = *g_Codecs[i];
+ if (name.IsEqualToNoCase(codec.Name))
+ {
+ methodId = codec.Id;
+ numInStreams = codec.NumInStreams;
+ numOutStreams = 1;
+ return true;
+ }
+ }
+ #ifdef EXTERNAL_CODECS
+ if (__externalCodecs)
+ for (i = 0; i < (UInt32)__externalCodecs->Codecs.Size(); i++)
+ {
+ const CCodecInfoEx &codec = __externalCodecs->Codecs[i];
+ if (codec.Name.IsEqualToNoCase(name))
+ {
+ methodId = codec.Id;
+ numInStreams = codec.NumInStreams;
+ numOutStreams = codec.NumOutStreams;
+ return true;
+ }
+ }
+ #endif
+ return false;
+}
+
+bool FindMethod(DECL_EXTERNAL_CODECS_LOC_VARS
+ CMethodId methodId, UString &name)
+{
+ UInt32 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
+ if (__externalCodecs)
+ for (i = 0; i < (UInt32)__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 UString &name,
+ CMethodId &methodId)
+{
+ UInt32 i;
+ for (i = 0; i < g_NumHashers; i++)
+ {
+ const CHasherInfo &codec = *g_Hashers[i];
+ if (name.IsEqualToNoCase(codec.Name))
+ {
+ methodId = codec.Id;
+ return true;
+ }
+ }
+ #ifdef EXTERNAL_CODECS
+ if (__externalCodecs)
+ for (i = 0; i < (UInt32)__externalCodecs->Hashers.Size(); i++)
+ {
+ const CHasherInfoEx &codec = __externalCodecs->Hashers[i];
+ if (codec.Name.IsEqualToNoCase(name))
+ {
+ methodId = codec.Id;
+ return true;
+ }
+ }
+ #endif
+ return false;
+}
+
+void GetHashMethods(DECL_EXTERNAL_CODECS_LOC_VARS
+ CRecordVector<CMethodId> &methods)
+{
+ methods.ClearAndSetSize(g_NumHashers);
+ UInt32 i;
+ for (i = 0; i < g_NumHashers; i++)
+ methods[i] = (*g_Hashers[i]).Id;
+ #ifdef EXTERNAL_CODECS
+ if (__externalCodecs)
+ for (i = 0; i < (UInt32)__externalCodecs->Hashers.Size(); i++)
+ methods.Add(__externalCodecs->Hashers[i].Id);
+ #endif
+}
+
+HRESULT CreateCoder(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CMethodId methodId,
+ CMyComPtr<ICompressFilter> &filter,
+ CMyComPtr<ICompressCoder> &coder,
+ CMyComPtr<ICompressCoder2> &coder2,
+ bool encode, bool onlyCoder)
+{
+ UInt32 i;
+ for (i = 0; i < g_NumCodecs; i++)
+ {
+ 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.NumInStreams == 1) coder = (ICompressCoder *)p;
+ else coder2 = (ICompressCoder2 *)p;
+ break;
+ }
+ }
+ else
+ if (codec.CreateDecoder)
+ {
+ void *p = codec.CreateDecoder();
+ if (codec.IsFilter) filter = (ICompressFilter *)p;
+ else if (codec.NumInStreams == 1) coder = (ICompressCoder *)p;
+ else coder2 = (ICompressCoder2 *)p;
+ break;
+ }
+ }
+ }
+
+ #ifdef EXTERNAL_CODECS
+ if (!filter && !coder && !coder2 && __externalCodecs)
+ for (i = 0; i < (UInt32)__externalCodecs->Codecs.Size(); i++)
+ {
+ const CCodecInfoEx &codec = __externalCodecs->Codecs[i];
+ if (codec.Id == methodId)
+ {
+ if (encode)
+ {
+ if (codec.EncoderIsAssigned)
+ {
+ if (codec.IsSimpleCodec())
+ {
+ HRESULT result = __externalCodecs->GetCodecs->CreateEncoder(i, &IID_ICompressCoder, (void **)&coder);
+ if (result != S_OK && result != E_NOINTERFACE && result != CLASS_E_CLASSNOTAVAILABLE)
+ return result;
+ if (!coder)
+ {
+ RINOK(__externalCodecs->GetCodecs->CreateEncoder(i, &IID_ICompressFilter, (void **)&filter));
+ }
+ }
+ else
+ {
+ RINOK(__externalCodecs->GetCodecs->CreateEncoder(i, &IID_ICompressCoder2, (void **)&coder2));
+ }
+ break;
+ }
+ }
+ else
+ if (codec.DecoderIsAssigned)
+ {
+ if (codec.IsSimpleCodec())
+ {
+ HRESULT result = __externalCodecs->GetCodecs->CreateDecoder(i, &IID_ICompressCoder, (void **)&coder);
+ if (result != S_OK && result != E_NOINTERFACE && result != CLASS_E_CLASSNOTAVAILABLE)
+ return result;
+ if (!coder)
+ {
+ RINOK(__externalCodecs->GetCodecs->CreateDecoder(i, &IID_ICompressFilter, (void **)&filter));
+ }
+ }
+ else
+ {
+ RINOK(__externalCodecs->GetCodecs->CreateDecoder(i, &IID_ICompressCoder2, (void **)&coder2));
+ }
+ break;
+ }
+ }
+ }
+ #endif
+
+ if (onlyCoder && filter)
+ {
+ CFilterCoder *coderSpec = new CFilterCoder;
+ coder = coderSpec;
+ coderSpec->Filter = filter;
+ }
+ return S_OK;
+}
+
+HRESULT CreateCoder(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CMethodId methodId,
+ CMyComPtr<ICompressCoder> &coder,
+ CMyComPtr<ICompressCoder2> &coder2,
+ bool encode)
+{
+ CMyComPtr<ICompressFilter> filter;
+ return CreateCoder(
+ EXTERNAL_CODECS_LOC_VARS
+ methodId,
+ filter, coder, coder2, encode, true);
+}
+
+HRESULT CreateCoder(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CMethodId methodId,
+ CMyComPtr<ICompressCoder> &coder, bool encode)
+{
+ CMyComPtr<ICompressFilter> filter;
+ CMyComPtr<ICompressCoder2> coder2;
+ return CreateCoder(
+ EXTERNAL_CODECS_LOC_VARS
+ methodId,
+ coder, coder2, encode);
+}
+
+HRESULT CreateFilter(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CMethodId methodId,
+ CMyComPtr<ICompressFilter> &filter,
+ bool encode)
+{
+ CMyComPtr<ICompressCoder> coder;
+ CMyComPtr<ICompressCoder2> coder2;
+ return CreateCoder(
+ EXTERNAL_CODECS_LOC_VARS
+ methodId,
+ filter, coder, coder2, encode, false);
+}
+
+HRESULT CreateHasher(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CMethodId methodId,
+ UString &name,
+ CMyComPtr<IHasher> &hasher)
+{
+ UInt32 i;
+ for (i = 0; i < g_NumHashers; i++)
+ {
+ const CHasherInfo &codec = *g_Hashers[i];
+ if (codec.Id == methodId)
+ {
+ hasher = (IHasher *)codec.CreateHasher();
+ name = codec.Name;
+ break;
+ }
+ }
+
+ #ifdef EXTERNAL_CODECS
+ if (!hasher && __externalCodecs)
+ for (i = 0; i < (UInt32)__externalCodecs->Hashers.Size(); i++)
+ {
+ const CHasherInfoEx &codec = __externalCodecs->Hashers[i];
+ if (codec.Id == methodId)
+ {
+ name = codec.Name;
+ return __externalCodecs->GetHashers->CreateHasher(i, &hasher);
+ }
+ }
+ #endif
+
+ return S_OK;
+}
diff --git a/lzma/CPP/7zip/Common/CreateCoder.h b/lzma/CPP/7zip/Common/CreateCoder.h
new file mode 100644
index 0000000..50dc148
--- /dev/null
+++ b/lzma/CPP/7zip/Common/CreateCoder.h
@@ -0,0 +1,127 @@
+// CreateCoder.h
+
+#ifndef __CREATE_CODER_H
+#define __CREATE_CODER_H
+
+#include "../../Common/MyCom.h"
+#include "../../Common/MyString.h"
+#include "../ICoder.h"
+
+#include "MethodId.h"
+
+#ifdef EXTERNAL_CODECS
+
+struct CCodecInfoEx
+{
+ UString Name;
+ CMethodId Id;
+ UInt32 NumInStreams;
+ UInt32 NumOutStreams;
+ bool EncoderIsAssigned;
+ bool DecoderIsAssigned;
+
+ bool IsSimpleCodec() const { return NumOutStreams == 1 && NumInStreams == 1; }
+ CCodecInfoEx(): EncoderIsAssigned(false), DecoderIsAssigned(false) {}
+};
+
+struct CHasherInfoEx
+{
+ UString Name;
+ CMethodId Id;
+};
+
+#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.LoadCodecs(); COM_TRY_END }
+#define IMPL_ISetCompressCodecsInfo IMPL_ISetCompressCodecsInfo2(CHandler)
+
+struct CExternalCodecs
+{
+ CMyComPtr<ICompressCodecsInfo> GetCodecs;
+ CMyComPtr<IHashers> GetHashers;
+
+ CObjectVector<CCodecInfoEx> Codecs;
+ CObjectVector<CHasherInfoEx> Hashers;
+
+ HRESULT LoadCodecs();
+};
+
+#define EXTERNAL_CODECS_VARS2 &__externalCodecs
+
+#define DECL_EXTERNAL_CODECS_VARS CExternalCodecs __externalCodecs;
+#define EXTERNAL_CODECS_VARS EXTERNAL_CODECS_VARS2,
+
+#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 EXTERNAL_CODECS_VARS2
+#define DECL_EXTERNAL_CODECS_LOC_VARS2
+#define EXTERNAL_CODECS_LOC_VARS2
+#define DECL_EXTERNAL_CODECS_LOC_VARS
+#define EXTERNAL_CODECS_LOC_VARS
+
+#endif
+
+bool FindMethod(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ const UString &name, CMethodId &methodId, UInt32 &numInStreams, UInt32 &numOutStreams);
+
+bool FindMethod(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CMethodId methodId, UString &name);
+
+bool FindHashMethod(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ const UString &name, CMethodId &methodId);
+
+void GetHashMethods(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CRecordVector<CMethodId> &methods);
+
+HRESULT CreateCoder(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CMethodId methodId,
+ CMyComPtr<ICompressFilter> &filter,
+ CMyComPtr<ICompressCoder> &coder,
+ CMyComPtr<ICompressCoder2> &coder2,
+ bool encode, bool onlyCoder);
+
+HRESULT CreateCoder(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CMethodId methodId,
+ CMyComPtr<ICompressCoder> &coder,
+ CMyComPtr<ICompressCoder2> &coder2,
+ bool encode);
+
+HRESULT CreateCoder(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CMethodId methodId,
+ CMyComPtr<ICompressCoder> &coder, bool encode);
+
+HRESULT CreateFilter(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CMethodId methodId,
+ CMyComPtr<ICompressFilter> &filter,
+ bool encode);
+
+HRESULT CreateHasher(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CMethodId methodId,
+ UString &name,
+ CMyComPtr<IHasher> &hacher);
+
+#endif
diff --git a/lzma/CPP/7zip/Common/FilePathAutoRename.cpp b/lzma/CPP/7zip/Common/FilePathAutoRename.cpp
new file mode 100644
index 0000000..db151c0
--- /dev/null
+++ b/lzma/CPP/7zip/Common/FilePathAutoRename.cpp
@@ -0,0 +1,55 @@
+// FilePathAutoRename.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/Defs.h"
+#include "../../Common/IntToString.h"
+
+#include "../../Windows/FileFind.h"
+
+#include "FilePathAutoRename.h"
+
+using namespace NWindows;
+
+static bool MakeAutoName(const FString &name,
+ const FString &extension, unsigned value, FString &path)
+{
+ FChar number[16];
+ ConvertUInt32ToString(value, number);
+ path = name;
+ path += number;
+ path += extension;
+ return NFile::NFind::DoesFileOrDirExist(path);
+}
+
+bool AutoRenamePath(FString &fullProcessedPath)
+{
+ FString path;
+ int dotPos = fullProcessedPath.ReverseFind(FTEXT('.'));
+
+ int slashPos = fullProcessedPath.ReverseFind(FTEXT('/'));
+ #ifdef _WIN32
+ int slash1Pos = fullProcessedPath.ReverseFind(FTEXT('\\'));
+ slashPos = MyMax(slashPos, slash1Pos);
+ #endif
+
+ FString name, extension;
+ if (dotPos > slashPos && dotPos > 0)
+ {
+ name.SetFrom(fullProcessedPath, dotPos);
+ extension = fullProcessedPath.Ptr(dotPos);
+ }
+ else
+ name = fullProcessedPath;
+ name += L'_';
+ unsigned left = 1, right = (1 << 30);
+ while (left != right)
+ {
+ unsigned mid = (left + right) / 2;
+ if (MakeAutoName(name, extension, mid, path))
+ left = mid + 1;
+ else
+ right = mid;
+ }
+ return !MakeAutoName(name, extension, right, fullProcessedPath);
+}
diff --git a/lzma/CPP/7zip/Common/FilePathAutoRename.h b/lzma/CPP/7zip/Common/FilePathAutoRename.h
new file mode 100644
index 0000000..cb2d71b
--- /dev/null
+++ b/lzma/CPP/7zip/Common/FilePathAutoRename.h
@@ -0,0 +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
diff --git a/lzma/CPP/7zip/Common/FileStreams.cpp b/lzma/CPP/7zip/Common/FileStreams.cpp
new file mode 100644
index 0000000..96f79a0
--- /dev/null
+++ b/lzma/CPP/7zip/Common/FileStreams.cpp
@@ -0,0 +1,435 @@
+// 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
+}
+
+#ifdef SUPPORT_DEVICE_FILE
+
+static const UInt32 kClusterSize = 1 << 18;
+CInFileStream::CInFileStream():
+ VirtPos(0),
+ PhyPos(0),
+ Buf(0),
+ BufSize(0),
+ SupportHardLinks(false)
+{
+}
+
+#endif
+
+CInFileStream::~CInFileStream()
+{
+ #ifdef SUPPORT_DEVICE_FILE
+ MidFree(Buf);
+ #endif
+}
+
+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
+ return ConvertBoolToHRESULT(result);
+
+ #else
+
+ if (processedSize)
+ *processedSize = 0;
+ ssize_t res = File.Read(data, (size_t)size);
+ if (res == -1)
+ 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.WritePart(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
+}
+
+#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;
+ 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;
+ if (processedSize)
+ *processedSize = (UInt32)res;
+ return S_OK;
+
+ return S_OK;
+ #endif
+}
+
+#endif
diff --git a/lzma/CPP/7zip/Common/FileStreams.h b/lzma/CPP/7zip/Common/FileStreams.h
new file mode 100644
index 0000000..1cd2d1a
--- /dev/null
+++ b/lzma/CPP/7zip/Common/FileStreams.h
@@ -0,0 +1,148 @@
+// 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"
+
+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;
+
+ virtual ~CInFileStream();
+
+ #ifdef SUPPORT_DEVICE_FILE
+ CInFileStream();
+ #endif
+
+ 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);
+};
+
+class CStdOutFileStream:
+ public ISequentialOutStream,
+ public CMyUnknownImp
+{
+public:
+ MY_UNKNOWN_IMP
+
+ virtual ~CStdOutFileStream() {}
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+};
+
+#endif
diff --git a/lzma/CPP/7zip/Common/FilterCoder.cpp b/lzma/CPP/7zip/Common/FilterCoder.cpp
new file mode 100644
index 0000000..bed8298
--- /dev/null
+++ b/lzma/CPP/7zip/Common/FilterCoder.cpp
@@ -0,0 +1,265 @@
+// FilterCoder.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+
+#include "../../Common/Defs.h"
+
+#include "FilterCoder.h"
+#include "StreamUtils.h"
+
+static const UInt32 kBufferSize = 1 << 17;
+
+CFilterCoder::CFilterCoder()
+{
+ _buffer = (Byte *)::MidAlloc(kBufferSize);
+ if (_buffer == 0)
+ throw 1;
+}
+
+CFilterCoder::~CFilterCoder()
+{
+ ::MidFree(_buffer);
+}
+
+HRESULT CFilterCoder::WriteWithLimit(ISequentialOutStream *outStream, UInt32 size)
+{
+ if (_outSizeIsDefined)
+ {
+ UInt64 remSize = _outSize - _nowPos64;
+ if (size > remSize)
+ size = (UInt32)remSize;
+ }
+ RINOK(WriteStream(outStream, _buffer, size));
+ _nowPos64 += size;
+ return S_OK;
+}
+
+STDMETHODIMP CFilterCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ RINOK(Init());
+ UInt32 bufferPos = 0;
+ _outSizeIsDefined = (outSize != 0);
+ if (_outSizeIsDefined)
+ _outSize = *outSize;
+
+ while (!_outSizeIsDefined || _nowPos64 < _outSize)
+ {
+ size_t processedSize = kBufferSize - bufferPos;
+
+ // Change it: It can be optimized using ReadPart
+ RINOK(ReadStream(inStream, _buffer + bufferPos, &processedSize));
+
+ UInt32 endPos = bufferPos + (UInt32)processedSize;
+
+ bufferPos = Filter->Filter(_buffer, endPos);
+ if (bufferPos > endPos)
+ {
+ for (; endPos < bufferPos; endPos++)
+ _buffer[endPos] = 0;
+ bufferPos = Filter->Filter(_buffer, endPos);
+ }
+
+ if (bufferPos == 0)
+ {
+ if (endPos == 0)
+ return S_OK;
+ return WriteWithLimit(outStream, endPos);
+ }
+ RINOK(WriteWithLimit(outStream, bufferPos));
+ if (progress != NULL)
+ {
+ RINOK(progress->SetRatioInfo(&_nowPos64, &_nowPos64));
+ }
+ UInt32 i = 0;
+ while (bufferPos < endPos)
+ _buffer[i++] = _buffer[bufferPos++];
+ bufferPos = i;
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CFilterCoder::SetOutStream(ISequentialOutStream *outStream)
+{
+ _bufferPos = 0;
+ _outStream = outStream;
+ return Init();
+}
+
+STDMETHODIMP CFilterCoder::ReleaseOutStream()
+{
+ _outStream.Release();
+ return S_OK;
+}
+
+
+STDMETHODIMP CFilterCoder::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize != NULL)
+ *processedSize = 0;
+ while (size > 0)
+ {
+ UInt32 sizeTemp = MyMin(size, kBufferSize - _bufferPos);
+ memcpy(_buffer + _bufferPos, data, sizeTemp);
+ size -= sizeTemp;
+ if (processedSize != NULL)
+ *processedSize += sizeTemp;
+ data = (const Byte *)data + sizeTemp;
+ UInt32 endPos = _bufferPos + sizeTemp;
+ _bufferPos = Filter->Filter(_buffer, endPos);
+ if (_bufferPos == 0)
+ {
+ _bufferPos = endPos;
+ break;
+ }
+ if (_bufferPos > endPos)
+ {
+ if (size != 0)
+ return E_FAIL;
+ break;
+ }
+ RINOK(WriteWithLimit(_outStream, _bufferPos));
+ UInt32 i = 0;
+ while (_bufferPos < endPos)
+ _buffer[i++] = _buffer[_bufferPos++];
+ _bufferPos = i;
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CFilterCoder::Flush()
+{
+ if (_bufferPos != 0)
+ {
+ // _buffer contains only data refused by previous Filter->Filter call.
+ UInt32 endPos = Filter->Filter(_buffer, _bufferPos);
+ if (endPos > _bufferPos)
+ {
+ for (; _bufferPos < endPos; _bufferPos++)
+ _buffer[_bufferPos] = 0;
+ if (Filter->Filter(_buffer, endPos) != endPos)
+ return E_FAIL;
+ }
+ RINOK(WriteWithLimit(_outStream, _bufferPos));
+ _bufferPos = 0;
+ }
+ CMyComPtr<IOutStreamFlush> flush;
+ _outStream.QueryInterface(IID_IOutStreamFlush, &flush);
+ if (flush)
+ return flush->Flush();
+ return S_OK;
+}
+
+
+void CFilterCoder::SetInStream_NoSubFilterInit(ISequentialInStream *inStream)
+{
+ _convertedPosBegin = _convertedPosEnd = _bufferPos = 0;
+ _inStream = inStream;
+ Init2();
+}
+
+STDMETHODIMP CFilterCoder::SetInStream(ISequentialInStream *inStream)
+{
+ SetInStream_NoSubFilterInit(inStream);
+ return Init();
+}
+
+STDMETHODIMP CFilterCoder::ReleaseInStream()
+{
+ _inStream.Release();
+ return S_OK;
+}
+
+STDMETHODIMP CFilterCoder::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize != NULL)
+ *processedSize = 0;
+ while (size > 0)
+ {
+ if (_convertedPosBegin != _convertedPosEnd)
+ {
+ UInt32 sizeTemp = MyMin(size, _convertedPosEnd - _convertedPosBegin);
+ memcpy(data, _buffer + _convertedPosBegin, sizeTemp);
+ _convertedPosBegin += sizeTemp;
+ data = (void *)((Byte *)data + sizeTemp);
+ size -= sizeTemp;
+ if (processedSize != NULL)
+ *processedSize += sizeTemp;
+ break;
+ }
+ UInt32 i;
+ for (i = 0; _convertedPosEnd + i < _bufferPos; i++)
+ _buffer[i] = _buffer[_convertedPosEnd + i];
+ _bufferPos = i;
+ _convertedPosBegin = _convertedPosEnd = 0;
+ size_t processedSizeTemp = kBufferSize - _bufferPos;
+ RINOK(ReadStream(_inStream, _buffer + _bufferPos, &processedSizeTemp));
+ _bufferPos += (UInt32)processedSizeTemp;
+ _convertedPosEnd = Filter->Filter(_buffer, _bufferPos);
+ if (_convertedPosEnd == 0)
+ {
+ if (_bufferPos == 0)
+ break;
+ _convertedPosEnd = _bufferPos; // check it
+ continue;
+ }
+ if (_convertedPosEnd > _bufferPos)
+ {
+ for (; _bufferPos < _convertedPosEnd; _bufferPos++)
+ _buffer[_bufferPos] = 0;
+ _convertedPosEnd = Filter->Filter(_buffer, _bufferPos);
+ }
+ }
+ 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 _setDecoderProperties->SetDecoderProperties2(data, size);
+}
diff --git a/lzma/CPP/7zip/Common/FilterCoder.h b/lzma/CPP/7zip/Common/FilterCoder.h
new file mode 100644
index 0000000..35e877f
--- /dev/null
+++ b/lzma/CPP/7zip/Common/FilterCoder.h
@@ -0,0 +1,142 @@
+// FilterCoder.h
+
+#ifndef __FILTER_CODER_H
+#define __FILTER_CODER_H
+
+#include "../../Common/MyCom.h"
+#include "../ICoder.h"
+#include "../IPassword.h"
+
+#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; }
+
+class CFilterCoder:
+ public ICompressCoder,
+ public ICompressSetInStream,
+ public ISequentialInStream,
+ public ICompressSetOutStream,
+ public ISequentialOutStream,
+ public IOutStreamFlush,
+
+ #ifndef _NO_CRYPTO
+ public ICryptoSetPassword,
+ public ICryptoProperties,
+ #endif
+ #ifndef EXTRACT_ONLY
+ public ICompressSetCoderProperties,
+ public ICompressWriteCoderProperties,
+ // public ICryptoResetSalt,
+ public ICryptoResetInitVector,
+ #endif
+ public ICompressSetDecoderProperties2,
+ public CMyUnknownImp
+{
+protected:
+ Byte *_buffer;
+ CMyComPtr<ISequentialInStream> _inStream;
+ CMyComPtr<ISequentialOutStream> _outStream;
+ UInt32 _bufferPos;
+ UInt32 _convertedPosBegin;
+ UInt32 _convertedPosEnd;
+ bool _outSizeIsDefined;
+ UInt64 _outSize;
+ UInt64 _nowPos64;
+
+ void Init2()
+ {
+ _nowPos64 = 0;
+ _outSizeIsDefined = false;
+ }
+
+ HRESULT Init()
+ {
+ Init2();
+ return Filter->Init();
+ }
+
+ CMyComPtr<ICryptoSetPassword> _setPassword;
+ CMyComPtr<ICryptoProperties> _cryptoProperties;
+ #ifndef EXTRACT_ONLY
+ CMyComPtr<ICompressSetCoderProperties> _SetCoderProperties;
+ CMyComPtr<ICompressWriteCoderProperties> _writeCoderProperties;
+ // CMyComPtr<ICryptoResetSalt> _CryptoResetSalt;
+ CMyComPtr<ICryptoResetInitVector> _CryptoResetInitVector;
+ #endif
+ CMyComPtr<ICompressSetDecoderProperties2> _setDecoderProperties;
+public:
+ CMyComPtr<ICompressFilter> Filter;
+
+ CFilterCoder();
+ ~CFilterCoder();
+ HRESULT WriteWithLimit(ISequentialOutStream *outStream, UInt32 size);
+
+public:
+ MY_QUERYINTERFACE_BEGIN2(ICompressCoder)
+ MY_QUERYINTERFACE_ENTRY(ICompressSetInStream)
+ MY_QUERYINTERFACE_ENTRY(ISequentialInStream)
+ MY_QUERYINTERFACE_ENTRY(ICompressSetOutStream)
+ MY_QUERYINTERFACE_ENTRY(ISequentialOutStream)
+ MY_QUERYINTERFACE_ENTRY(IOutStreamFlush)
+
+ #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, _setDecoderProperties)
+ MY_QUERYINTERFACE_END
+ MY_ADDREF_RELEASE
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+ STDMETHOD(ReleaseInStream)();
+ STDMETHOD(SetInStream)(ISequentialInStream *inStream);
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); \
+ STDMETHOD(SetOutStream)(ISequentialOutStream *outStream);
+ STDMETHOD(ReleaseOutStream)();
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+ STDMETHOD(Flush)();
+
+ #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);
+
+ void SetInStream_NoSubFilterInit(ISequentialInStream *inStream);
+
+};
+
+class CInStreamReleaser
+{
+public:
+ CFilterCoder *FilterCoder;
+ CInStreamReleaser(): FilterCoder(0) {}
+ ~CInStreamReleaser() { if (FilterCoder) FilterCoder->ReleaseInStream(); }
+};
+
+class COutStreamReleaser
+{
+public:
+ CFilterCoder *FilterCoder;
+ COutStreamReleaser(): FilterCoder(0) {}
+ ~COutStreamReleaser() { if (FilterCoder) FilterCoder->ReleaseOutStream(); }
+};
+
+#endif
diff --git a/lzma/CPP/7zip/Common/InBuffer.cpp b/lzma/CPP/7zip/Common/InBuffer.cpp
new file mode 100644
index 0000000..7765d1b
--- /dev/null
+++ b/lzma/CPP/7zip/Common/InBuffer.cpp
@@ -0,0 +1,135 @@
+// 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)
+{
+ 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;
+ }
+}
diff --git a/lzma/CPP/7zip/Common/InBuffer.h b/lzma/CPP/7zip/Common/InBuffer.h
new file mode 100644
index 0000000..f353b37
--- /dev/null
+++ b/lzma/CPP/7zip/Common/InBuffer.h
@@ -0,0 +1,90 @@
+// 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();
+
+ bool ReadByte(Byte &b)
+ {
+ if (_buf >= _bufLim)
+ return ReadByte_FromNewBlock(b);
+ b = *_buf++;
+ return true;
+ }
+
+ 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/lzma/CPP/7zip/Common/InOutTempBuffer.cpp b/lzma/CPP/7zip/Common/InOutTempBuffer.cpp
new file mode 100644
index 0000000..591d01e
--- /dev/null
+++ b/lzma/CPP/7zip/Common/InOutTempBuffer.cpp
@@ -0,0 +1,119 @@
+// 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 UInt32 kTempBufSize = (1 << 20);
+
+static CFSTR 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 (_bufPos < kTempBufSize)
+ {
+ UInt32 cur = MyMin(kTempBufSize - _bufPos, size);
+ memcpy(_buf + _bufPos, data, cur);
+ _crc = CrcUpdate(_crc, data, cur);
+ _bufPos += cur;
+ size -= cur;
+ data = ((const Byte *)data) + cur;
+ _size += 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 != NULL)
+ *processed = 0;
+ return E_FAIL;
+ }
+ if (processed != NULL)
+ *processed = size;
+ return S_OK;
+}
diff --git a/lzma/CPP/7zip/Common/InOutTempBuffer.h b/lzma/CPP/7zip/Common/InOutTempBuffer.h
new file mode 100644
index 0000000..710e474
--- /dev/null
+++ b/lzma/CPP/7zip/Common/InOutTempBuffer.h
@@ -0,0 +1,46 @@
+// 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;
+ UInt32 _bufPos;
+ bool _tempFileCreated;
+ UInt64 _size;
+ UInt32 _crc;
+
+ 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
diff --git a/lzma/CPP/7zip/Common/LimitedStreams.cpp b/lzma/CPP/7zip/Common/LimitedStreams.cpp
new file mode 100644
index 0000000..174cac1
--- /dev/null
+++ b/lzma/CPP/7zip/Common/LimitedStreams.cpp
@@ -0,0 +1,349 @@
+// LimitedStreams.cpp
+
+#include "StdAfx.h"
+
+#include "LimitedStreams.h"
+#include "../../Common/Defs.h"
+
+STDMETHODIMP CLimitedSequentialInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ UInt32 realProcessedSize = 0;
+ UInt32 sizeToRead = (UInt32)MyMin((_size - _pos), (UInt64)size);
+ HRESULT result = S_OK;
+ if (sizeToRead > 0)
+ {
+ result = _stream->Read(data, sizeToRead, &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
+ }
+ UInt64 rem = _size - _virtPos;
+ if (rem < size)
+ 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;
+
+ if (_curRem == 0)
+ {
+ UInt32 blockSize = (UInt32)1 << BlockSizeLog;
+ UInt32 virtBlock = (UInt32)(_virtPos >> BlockSizeLog);
+ UInt32 offsetInBlock = (UInt32)_virtPos & (blockSize - 1);
+ 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;
+ UInt64 rem = Size - _virtPos;
+ if (_curRem > rem)
+ _curRem = (UInt32)rem;
+ }
+ 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)
+ 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);
+}
diff --git a/lzma/CPP/7zip/Common/LimitedStreams.h b/lzma/CPP/7zip/Common/LimitedStreams.h
new file mode 100644
index 0000000..8c89502
--- /dev/null
+++ b/lzma/CPP/7zip/Common/LimitedStreams.h
@@ -0,0 +1,251 @@
+// 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; }
+ 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:
+ CMyComPtr<IInStream> Stream;
+ UInt64 StartOffset;
+ UInt64 Size;
+ unsigned BlockSizeLog;
+ CRecordVector<UInt32> Vector;
+
+ 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
diff --git a/lzma/CPP/7zip/Common/LockedStream.cpp b/lzma/CPP/7zip/Common/LockedStream.cpp
new file mode 100644
index 0000000..d1bbf6d
--- /dev/null
+++ b/lzma/CPP/7zip/Common/LockedStream.cpp
@@ -0,0 +1,23 @@
+// LockedStream.cpp
+
+#include "StdAfx.h"
+
+#include "LockedStream.h"
+
+HRESULT CLockedInStream::Read(UInt64 startPos, void *data, UInt32 size,
+ UInt32 *processedSize)
+{
+ NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection);
+ RINOK(_stream->Seek(startPos, STREAM_SEEK_SET, NULL));
+ return _stream->Read(data, size, processedSize);
+}
+
+STDMETHODIMP CLockedSequentialInStreamImp::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ UInt32 realProcessedSize = 0;
+ HRESULT result = _lockedInStream->Read(_pos, data, size, &realProcessedSize);
+ _pos += realProcessedSize;
+ if (processedSize != NULL)
+ *processedSize = realProcessedSize;
+ return result;
+}
diff --git a/lzma/CPP/7zip/Common/LockedStream.h b/lzma/CPP/7zip/Common/LockedStream.h
new file mode 100644
index 0000000..e12e22a
--- /dev/null
+++ b/lzma/CPP/7zip/Common/LockedStream.h
@@ -0,0 +1,38 @@
+// LockedStream.h
+
+#ifndef __LOCKEDSTREAM_H
+#define __LOCKEDSTREAM_H
+
+#include "../../Windows/Synchronization.h"
+#include "../../Common/MyCom.h"
+#include "../IStream.h"
+
+class CLockedInStream
+{
+ CMyComPtr<IInStream> _stream;
+ NWindows::NSynchronization::CCriticalSection _criticalSection;
+public:
+ void Init(IInStream *stream)
+ { _stream = stream; }
+ HRESULT Read(UInt64 startPos, void *data, UInt32 size, UInt32 *processedSize);
+};
+
+class CLockedSequentialInStreamImp:
+ public ISequentialInStream,
+ public CMyUnknownImp
+{
+ CLockedInStream *_lockedInStream;
+ UInt64 _pos;
+public:
+ void Init(CLockedInStream *lockedInStream, UInt64 startPos)
+ {
+ _lockedInStream = lockedInStream;
+ _pos = startPos;
+ }
+
+ MY_UNKNOWN_IMP
+
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+};
+
+#endif
diff --git a/lzma/CPP/7zip/Common/MethodId.cpp b/lzma/CPP/7zip/Common/MethodId.cpp
new file mode 100644
index 0000000..9a07e4c
--- /dev/null
+++ b/lzma/CPP/7zip/Common/MethodId.cpp
@@ -0,0 +1,3 @@
+// MethodId.cpp
+
+#include "StdAfx.h"
diff --git a/lzma/CPP/7zip/Common/MethodId.h b/lzma/CPP/7zip/Common/MethodId.h
new file mode 100644
index 0000000..1ba9f49
--- /dev/null
+++ b/lzma/CPP/7zip/Common/MethodId.h
@@ -0,0 +1,10 @@
+// MethodId.h
+
+#ifndef __7Z_METHOD_ID_H
+#define __7Z_METHOD_ID_H
+
+#include "../../Common/MyTypes.h"
+
+typedef UInt64 CMethodId;
+
+#endif
diff --git a/lzma/CPP/7zip/Common/MethodProps.cpp b/lzma/CPP/7zip/Common/MethodProps.cpp
new file mode 100644
index 0000000..0773511
--- /dev/null
+++ b/lzma/CPP/7zip/Common/MethodProps.cpp
@@ -0,0 +1,441 @@
+// MethodProps.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/StringToInt.h"
+
+#include "MethodProps.h"
+
+using namespace NWindows;
+
+bool StringToBool(const UString &s, bool &res)
+{
+ if (s.IsEmpty() || s == L"+" || StringsAreEqualNoCase_Ascii(s, "ON"))
+ {
+ res = true;
+ return true;
+ }
+ if (s == L"-" || 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);
+}
+
+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, UInt32 &dicSize)
+{
+ const wchar_t *end;
+ UInt32 number = ConvertStringToUInt32(s, &end);
+ unsigned numDigits = (unsigned)(end - s);
+ if (numDigits == 0 || s.Len() > numDigits + 1)
+ return E_INVALIDARG;
+ const unsigned kLogDictSizeLimit = 32;
+ if (s.Len() == numDigits)
+ {
+ if (number >= kLogDictSizeLimit)
+ return E_INVALIDARG;
+ dicSize = (UInt32)1 << (unsigned)number;
+ return S_OK;
+ }
+ unsigned numBits;
+ switch (MyCharLower_Ascii(s[numDigits]))
+ {
+ case 'b': dicSize = 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 << (kLogDictSizeLimit - numBits)))
+ return E_INVALIDARG;
+ dicSize = number << numBits;
+ return S_OK;
+}
+
+static HRESULT PROPVARIANT_to_DictSize(const PROPVARIANT &prop, UInt32 &resValue)
+{
+ if (prop.vt == VT_UI4)
+ {
+ UInt32 v = prop.ulVal;
+ if (v >= 32)
+ return E_INVALIDARG;
+ resValue = (UInt32)1 << v;
+ return S_OK;
+ }
+ if (prop.vt == VT_BSTR)
+ return StringToDictSize(prop.bstrVal, resValue);
+ return E_INVALIDARG;
+}
+
+void CProps::AddProp32(PROPID propid, UInt32 level)
+{
+ CProp prop;
+ prop.IsOptional = true;
+ prop.Id = propid;
+ prop.Value = (UInt32)level;
+ Props.Add(prop);
+}
+
+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;
+};
+
+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_UI4, "reduceSize" }
+};
+
+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_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;
+ int len = srcString.Len();
+ if (len == 0)
+ return;
+ for (int i = 0; i < len; i++)
+ {
+ wchar_t c = srcString[i];
+ if (c == L':')
+ {
+ subStrings.Add(s);
+ s.Empty();
+ }
+ else
+ s += c;
+ }
+ subStrings.Add(s);
+}
+
+static void SplitParam(const UString ¶m, UString &name, UString &value)
+{
+ int eqPos = param.Find(L'=');
+ if (eqPos >= 0)
+ {
+ name.SetFrom(param, 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::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[index];
+ CProp prop;
+ prop.Id = index;
+
+ if (IsLogSizeProp(prop.Id))
+ {
+ UInt32 dicSize;
+ RINOK(StringToDictSize(value, dicSize));
+ prop.Value = dicSize;
+ }
+ 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())
+ {
+ UInt32 number;
+ if (ParseStringToUInt32(value, number) == value.Len())
+ propValue = number;
+ else
+ propValue = value;
+ }
+ if (!ConvertProperty(propValue, nameToPropID.VarType, prop.Value))
+ return E_INVALIDARG;
+ }
+ Props.Add(prop);
+ return S_OK;
+}
+
+HRESULT CMethodProps::ParseParamsFromString(const UString &srcString)
+{
+ UStringVector params;
+ SplitParams(srcString, params);
+ FOR_VECTOR (i, params)
+ {
+ const UString ¶m = params[i];
+ UString name, value;
+ SplitParam(param, name, value);
+ RINOK(SetParam(name, value));
+ }
+ return S_OK;
+}
+
+HRESULT CMethodProps::ParseParamsFromPROPVARIANT(const UString &realName, const PROPVARIANT &value)
+{
+ if (realName.Len() == 0)
+ {
+ // [empty]=method
+ return E_INVALIDARG;
+ }
+ if (value.vt == VT_EMPTY)
+ {
+ // {realName}=[empty]
+ UString name, value;
+ SplitParam(realName, name, value);
+ return SetParam(name, value);
+ }
+
+ // {realName}=value
+ int index = FindPropIdExact(realName);
+ if (index < 0)
+ return E_INVALIDARG;
+ const CNameToPropID &nameToPropID = g_NameToPropID[index];
+ CProp prop;
+ prop.Id = index;
+
+ if (IsLogSizeProp(prop.Id))
+ {
+ UInt32 dicSize;
+ RINOK(PROPVARIANT_to_DictSize(value, dicSize));
+ prop.Value = dicSize;
+ }
+ else
+ {
+ if (!ConvertProperty(value, nameToPropID.VarType, prop.Value))
+ return E_INVALIDARG;
+ }
+ Props.Add(prop);
+ return S_OK;
+}
+
+HRESULT COneMethodInfo::ParseMethodFromString(const UString &s)
+{
+ int splitPos = s.Find(':');
+ MethodName = s;
+ if (splitPos < 0)
+ return S_OK;
+ MethodName.DeleteFrom(splitPos);
+ return ParseParamsFromString(s.Ptr(splitPos + 1));
+}
+
+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;
+ return ParseMethodFromString(value.bstrVal);
+}
diff --git a/lzma/CPP/7zip/Common/MethodProps.h b/lzma/CPP/7zip/Common/MethodProps.h
new file mode 100644
index 0000000..cc2b276
--- /dev/null
+++ b/lzma/CPP/7zip/Common/MethodProps.h
@@ -0,0 +1,185 @@
+// MethodProps.h
+
+#ifndef __7Z_METHOD_PROPS_H
+#define __7Z_METHOD_PROPS_H
+
+#include "../../Common/MyString.h"
+
+#include "../../Windows/PropVariant.h"
+
+#include "../ICoder.h"
+
+bool StringToBool(const UString &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 level);
+
+ void AddPropString(PROPID propid, const wchar_t *s)
+ {
+ CProp prop;
+ prop.IsOptional = true;
+ prop.Id = propid;
+ prop.Value = s;
+ Props.Add(prop);
+ }
+
+ 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));
+ }
+
+ UInt32 Get_Lzma_NumThreads(bool &fixedNumber) const
+ {
+ fixedNumber = false;
+ int numThreads = Get_NumThreads();
+ if (numThreads >= 0)
+ {
+ fixedNumber = true;
+ return numThreads < 2 ? 1 : 2;
+ }
+ return Get_Lzma_Algo() == 0 ? 1 : 2;
+ }
+
+ UInt32 Get_BZip2_NumThreads(bool &fixedNumber) const
+ {
+ fixedNumber = false;
+ int numThreads = Get_NumThreads();
+ if (numThreads >= 0)
+ {
+ fixedNumber = true;
+ if (numThreads < 1) return 1;
+ if (numThreads > 64) return 64;
+ 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 AddLevelProp(UInt32 level)
+ {
+ AddProp32(NCoderPropID::kLevel, level);
+ }
+
+ void AddNumThreadsProp(UInt32 numThreads)
+ {
+ AddProp32(NCoderPropID::kNumThreads, numThreads);
+ }
+
+ HRESULT ParseParamsFromString(const UString &srcString);
+ HRESULT ParseParamsFromPROPVARIANT(const UString &realName, const PROPVARIANT &value);
+};
+
+class COneMethodInfo: public CMethodProps
+{
+public:
+ UString MethodName;
+
+ void Clear()
+ {
+ CMethodProps::Clear();
+ MethodName.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/lzma/CPP/7zip/Common/OffsetStream.cpp b/lzma/CPP/7zip/Common/OffsetStream.cpp
new file mode 100644
index 0000000..3b01c7f
--- /dev/null
+++ b/lzma/CPP/7zip/Common/OffsetStream.cpp
@@ -0,0 +1,39 @@
+// 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);
+}
diff --git a/lzma/CPP/7zip/Common/OffsetStream.h b/lzma/CPP/7zip/Common/OffsetStream.h
new file mode 100644
index 0000000..ad835f2
--- /dev/null
+++ b/lzma/CPP/7zip/Common/OffsetStream.h
@@ -0,0 +1,26 @@
+// 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
diff --git a/lzma/CPP/7zip/Common/OutBuffer.cpp b/lzma/CPP/7zip/Common/OutBuffer.cpp
new file mode 100644
index 0000000..fb8dc8d
--- /dev/null
+++ b/lzma/CPP/7zip/Common/OutBuffer.cpp
@@ -0,0 +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
+}
diff --git a/lzma/CPP/7zip/Common/OutBuffer.h b/lzma/CPP/7zip/Common/OutBuffer.h
new file mode 100644
index 0000000..90ce25d
--- /dev/null
+++ b/lzma/CPP/7zip/Common/OutBuffer.h
@@ -0,0 +1,63 @@
+// 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)
+ {
+ _buf[_pos++] = b;
+ 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/lzma/CPP/7zip/Common/ProgressUtils.cpp b/lzma/CPP/7zip/Common/ProgressUtils.cpp
new file mode 100644
index 0000000..cfe504a
--- /dev/null
+++ b/lzma/CPP/7zip/Common/ProgressUtils.cpp
@@ -0,0 +1,42 @@
+// ProgressUtils.cpp
+
+#include "StdAfx.h"
+
+#include "ProgressUtils.h"
+
+CLocalProgress::CLocalProgress()
+{
+ ProgressOffset = InSize = OutSize = 0;
+ SendRatio = 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 inSizeNew = InSize, outSizeNew = OutSize;
+ if (inSize)
+ inSizeNew += (*inSize);
+ if (outSize)
+ outSizeNew += (*outSize);
+ if (SendRatio && _ratioProgress)
+ {
+ RINOK(_ratioProgress->SetRatioInfo(&inSizeNew, &outSizeNew));
+ }
+ inSizeNew += ProgressOffset;
+ outSizeNew += ProgressOffset;
+ if (SendProgress)
+ return _progress->SetCompleted(_inSizeIsMain ? &inSizeNew : &outSizeNew);
+ return S_OK;
+}
+
+HRESULT CLocalProgress::SetCur()
+{
+ return SetRatioInfo(NULL, NULL);
+}
diff --git a/lzma/CPP/7zip/Common/ProgressUtils.h b/lzma/CPP/7zip/Common/ProgressUtils.h
new file mode 100644
index 0000000..c620484
--- /dev/null
+++ b/lzma/CPP/7zip/Common/ProgressUtils.h
@@ -0,0 +1,34 @@
+// ProgressUtils.h
+
+#ifndef __PROGRESSUTILS_H
+#define __PROGRESSUTILS_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_IMP
+
+ STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
+};
+
+#endif
diff --git a/lzma/CPP/7zip/Common/PropId.cpp b/lzma/CPP/7zip/Common/PropId.cpp
new file mode 100644
index 0000000..b82b944
--- /dev/null
+++ b/lzma/CPP/7zip/Common/PropId.cpp
@@ -0,0 +1,99 @@
+// PropId.cpp
+
+#include "StdAfx.h"
+
+#include "../PropID.h"
+
+// VARTYPE
+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
+};
diff --git a/lzma/CPP/7zip/Common/RegisterArc.h b/lzma/CPP/7zip/Common/RegisterArc.h
new file mode 100644
index 0000000..b4cf1bf
--- /dev/null
+++ b/lzma/CPP/7zip/Common/RegisterArc.h
@@ -0,0 +1,55 @@
+// RegisterArc.h
+
+#ifndef __REGISTER_ARC_H
+#define __REGISTER_ARC_H
+
+#include "../Archive/IArchive.h"
+
+struct CArcInfo
+{
+ const char *Name;
+ const char *Ext;
+ const char *AddExt;
+
+ Byte ClassId;
+
+ Byte SignatureSize;
+ Byte Signature[20];
+ UInt16 SignatureOffset;
+
+ UInt16 Flags;
+
+ Func_CreateInArchive CreateInArchive;
+ Func_CreateOutArchive CreateOutArchive;
+ Func_IsArc IsArc;
+
+ bool IsMultiSignature() const { return (Flags & NArcInfoFlags::kMultiSignature) != 0; }
+};
+
+void RegisterArc(const CArcInfo *arcInfo) throw();
+
+#define REGISTER_ARC_NAME(x) CRegister ## x
+
+#define REGISTER_ARC(x) struct REGISTER_ARC_NAME(x) { \
+ REGISTER_ARC_NAME(x)() { RegisterArc(&g_ArcInfo); }}; \
+ static REGISTER_ARC_NAME(x) g_RegisterArc;
+
+#define REGISTER_ARC_DEC_SIG(x) struct REGISTER_ARC_NAME(x) { \
+ REGISTER_ARC_NAME(x)() { g_ArcInfo.Signature[0]--; RegisterArc(&g_ArcInfo); }}; \
+ static REGISTER_ARC_NAME(x) g_RegisterArc;
+
+
+#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 REF_CreateArc_Pair CreateArc, NULL
+#else
+ #define IMP_CreateArcOut static IOutArchive *CreateArcOut() { return new CHandler; }
+ #define REF_CreateArc_Pair CreateArc, CreateArcOut
+#endif
+
+#endif
diff --git a/lzma/CPP/7zip/Common/RegisterCodec.h b/lzma/CPP/7zip/Common/RegisterCodec.h
new file mode 100644
index 0000000..d51dccb
--- /dev/null
+++ b/lzma/CPP/7zip/Common/RegisterCodec.h
@@ -0,0 +1,51 @@
+// 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 wchar_t *Name;
+ UInt32 NumInStreams;
+ bool IsFilter;
+};
+
+void RegisterCodec(const CCodecInfo *codecInfo) throw();
+
+#define REGISTER_CODEC_NAME(x) CRegisterCodec ## x
+
+#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(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;
+
+
+struct CHasherInfo
+{
+ IHasher * (*CreateHasher)();
+ CMethodId Id;
+ const wchar_t *Name;
+ UInt32 DigestSize;
+};
+
+void RegisterHasher(const CHasherInfo *hasher) throw();
+
+#define REGISTER_HASHER_NAME(x) CRegisterHasher ## x
+
+#define REGISTER_HASHER(x) struct REGISTER_HASHER_NAME(x) { \
+ REGISTER_HASHER_NAME(x)() { RegisterHasher(&g_HasherInfo); }}; \
+ static REGISTER_HASHER_NAME(x) g_RegisterHasher;
+
+#endif
diff --git a/lzma/CPP/7zip/Common/StdAfx.h b/lzma/CPP/7zip/Common/StdAfx.h
new file mode 100644
index 0000000..42a088f
--- /dev/null
+++ b/lzma/CPP/7zip/Common/StdAfx.h
@@ -0,0 +1,8 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "../../Common/Common.h"
+
+#endif
diff --git a/lzma/CPP/7zip/Common/StreamBinder.cpp b/lzma/CPP/7zip/Common/StreamBinder.cpp
new file mode 100644
index 0000000..b3d056d
--- /dev/null
+++ b/lzma/CPP/7zip/Common/StreamBinder.cpp
@@ -0,0 +1,126 @@
+// StreamBinder.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/MyCom.h"
+
+#include "StreamBinder.h"
+
+class CBinderInStream:
+ public ISequentialInStream,
+ public CMyUnknownImp
+{
+ CStreamBinder *_binder;
+public:
+ MY_UNKNOWN_IMP
+ 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_IMP
+ 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(true));
+ RINOK(_canRead_Event.Create());
+ return _readingWasClosed_Event.Create();
+}
+
+void CStreamBinder::ReInit()
+{
+ _waitWrite = true;
+ _canRead_Event.Reset();
+ _readingWasClosed_Event.Reset();
+ ProcessedSize = 0;
+}
+
+
+void CStreamBinder::CreateStreams(ISequentialInStream **inStream, ISequentialOutStream **outStream)
+{
+ _waitWrite = true;
+ _bufSize = 0;
+ _buf = NULL;
+ ProcessedSize = 0;
+
+ 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)
+ {
+ _buf = data;
+ _bufSize = size;
+ _canWrite_Event.Reset();
+ _canRead_Event.Set();
+
+ HANDLE events[2] = { _canWrite_Event, _readingWasClosed_Event };
+ DWORD waitResult = ::WaitForMultipleObjects(2, events, FALSE, INFINITE);
+ if (waitResult != WAIT_OBJECT_0 + 0)
+ return S_FALSE;
+ if (processedSize)
+ *processedSize = size;
+ }
+ return S_OK;
+}
diff --git a/lzma/CPP/7zip/Common/StreamBinder.h b/lzma/CPP/7zip/Common/StreamBinder.h
new file mode 100644
index 0000000..52733f9
--- /dev/null
+++ b/lzma/CPP/7zip/Common/StreamBinder.h
@@ -0,0 +1,34 @@
+// StreamBinder.h
+
+#ifndef __STREAM_BINDER_H
+#define __STREAM_BINDER_H
+
+#include "../../Windows/Synchronization.h"
+
+#include "../IStream.h"
+
+class CStreamBinder
+{
+ NWindows::NSynchronization::CManualResetEvent _canWrite_Event;
+ NWindows::NSynchronization::CManualResetEvent _canRead_Event;
+ NWindows::NSynchronization::CManualResetEvent _readingWasClosed_Event;
+ 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(); }
+ void CloseWrite()
+ {
+ // _bufSize must be = 0
+ _canRead_Event.Set();
+ }
+};
+
+#endif
diff --git a/lzma/CPP/7zip/Common/StreamObjects.cpp b/lzma/CPP/7zip/Common/StreamObjects.cpp
new file mode 100644
index 0000000..6709842
--- /dev/null
+++ b/lzma/CPP/7zip/Common/StreamObjects.cpp
@@ -0,0 +1,250 @@
+// StreamObjects.cpp
+
+#include "StdAfx.h"
+
+#include <stdlib.h>
+
+#include "../../../C/Alloc.h"
+
+#include "StreamObjects.h"
+
+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, ISequentialInStream **stream)
+{
+ CBufInStream *inStreamSpec = new CBufInStream;
+ CMyComPtr<ISequentialInStream> streamTemp = inStreamSpec;
+ inStreamSpec->Init((const Byte *)data, size);
+ *stream = streamTemp.Detach();
+}
+*/
+
+void Create_BufInStream_WithNewBuf(const void *data, size_t size, ISequentialInStream **stream)
+{
+ CReferenceBuf *referenceBuf = new CReferenceBuf;
+ CMyComPtr<IUnknown> ref = referenceBuf;
+ referenceBuf->Buf.CopyFrom((const Byte *)data, size);
+
+ CBufInStream *inStreamSpec = new CBufInStream;
+ CMyComPtr<ISequentialInStream> streamTemp = inStreamSpec;
+ inStreamSpec->Init(referenceBuf);
+ *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;
+ 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;
+}
diff --git a/lzma/CPP/7zip/Common/StreamObjects.h b/lzma/CPP/7zip/Common/StreamObjects.h
new file mode 100644
index 0000000..16c35b8
--- /dev/null
+++ b/lzma/CPP/7zip/Common/StreamObjects.h
@@ -0,0 +1,140 @@
+// 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"
+
+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, ISequentialInStream **stream);
+void Create_BufInStream_WithNewBuf(const void *data, size_t size, ISequentialInStream **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
diff --git a/lzma/CPP/7zip/Common/StreamUtils.cpp b/lzma/CPP/7zip/Common/StreamUtils.cpp
new file mode 100644
index 0000000..a79de23
--- /dev/null
+++ b/lzma/CPP/7zip/Common/StreamUtils.cpp
@@ -0,0 +1,56 @@
+// 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;
+}
diff --git a/lzma/CPP/7zip/Common/StreamUtils.h b/lzma/CPP/7zip/Common/StreamUtils.h
new file mode 100644
index 0000000..799a8b9
--- /dev/null
+++ b/lzma/CPP/7zip/Common/StreamUtils.h
@@ -0,0 +1,13 @@
+// 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
diff --git a/lzma/CPP/7zip/Common/UniqBlocks.cpp b/lzma/CPP/7zip/Common/UniqBlocks.cpp
new file mode 100644
index 0000000..8808f96
--- /dev/null
+++ b/lzma/CPP/7zip/Common/UniqBlocks.cpp
@@ -0,0 +1,56 @@
+// UniqBlocks.cpp
+
+#include "StdAfx.h"
+
+#include "UniqBlocks.h"
+
+int CUniqBlocks::AddUniq(const Byte *data, size_t size)
+{
+ unsigned left = 0, right = Sorted.Size();
+ while (left != right)
+ {
+ unsigned mid = (left + right) / 2;
+ int 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
+ {
+ int cmp = memcmp(data, buf, size);
+ if (cmp == 0)
+ return index;
+ if (cmp < 0)
+ right = mid;
+ else
+ left = mid + 1;
+ }
+ }
+ int index = Bufs.Size();
+ Sorted.Insert(left, index);
+ CByteBuffer &buf = Bufs.AddNew();
+ buf.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);
+ int *p = &BufIndexToSortedIndex[0];
+ unsigned i;
+ for (i = 0; i < num; i++)
+ p[i] = 0;
+ for (i = 0; i < num; i++)
+ p[Sorted[i]] = i;
+}
diff --git a/lzma/CPP/7zip/Common/UniqBlocks.h b/lzma/CPP/7zip/Common/UniqBlocks.h
new file mode 100644
index 0000000..5b0dfb8
--- /dev/null
+++ b/lzma/CPP/7zip/Common/UniqBlocks.h
@@ -0,0 +1,30 @@
+// 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;
+ CIntVector Sorted;
+ CIntVector BufIndexToSortedIndex;
+
+ int AddUniq(const Byte *data, size_t size);
+ UInt64 GetTotalSizeInBytes() const;
+ void GetReverseMap();
+
+ bool IsOnlyEmpty() const
+ {
+ if (Bufs.Size() == 0)
+ return true;
+ if (Bufs.Size() > 1)
+ return false;
+ return Bufs[0].Size() == 0;
+ }
+};
+
+#endif
diff --git a/lzma/CPP/7zip/Common/VirtThread.cpp b/lzma/CPP/7zip/Common/VirtThread.cpp
new file mode 100644
index 0000000..3cf9acd
--- /dev/null
+++ b/lzma/CPP/7zip/Common/VirtThread.cpp
@@ -0,0 +1,48 @@
+// 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();
+ }
+}
diff --git a/lzma/CPP/7zip/Common/VirtThread.h b/lzma/CPP/7zip/Common/VirtThread.h
new file mode 100644
index 0000000..a271103
--- /dev/null
+++ b/lzma/CPP/7zip/Common/VirtThread.h
@@ -0,0 +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
diff --git a/lzma/CPP/7zip/Compress/Bcj2Coder.cpp b/lzma/CPP/7zip/Compress/Bcj2Coder.cpp
new file mode 100644
index 0000000..636994c
--- /dev/null
+++ b/lzma/CPP/7zip/Compress/Bcj2Coder.cpp
@@ -0,0 +1,366 @@
+// Bcj2Coder.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+
+#include "Bcj2Coder.h"
+
+namespace NCompress {
+namespace NBcj2 {
+
+inline bool IsJcc(Byte b0, Byte b1) { return (b0 == 0x0F && (b1 & 0xF0) == 0x80); }
+inline bool IsJ(Byte b0, Byte b1) { return ((b1 & 0xFE) == 0xE8 || IsJcc(b0, b1)); }
+inline unsigned GetIndex(Byte b0, Byte b1) { return ((b1 == 0xE8) ? b0 : ((b1 == 0xE9) ? 256 : 257)); }
+
+#ifndef EXTRACT_ONLY
+
+static const unsigned kBufSize = 1 << 17;
+
+#define NUM_BITS 2
+#define SIGN_BIT (1 << NUM_BITS)
+#define MASK_HIGH (0x100 - (1 << (NUM_BITS + 1)))
+
+static const UInt32 kDefaultLimit = (1 << (24 + NUM_BITS));
+
+static bool inline Test86MSByte(Byte b)
+{
+ return (((b) + SIGN_BIT) & MASK_HIGH) == 0;
+}
+
+CEncoder::~CEncoder()
+{
+ ::MidFree(_buf);
+}
+
+HRESULT CEncoder::Flush()
+{
+ RINOK(_mainStream.Flush());
+ RINOK(_callStream.Flush());
+ RINOK(_jumpStream.Flush());
+ _rc.FlushData();
+ return _rc.FlushStream();
+}
+
+HRESULT CEncoder::CodeReal(ISequentialInStream **inStreams, const UInt64 **inSizes, UInt32 numInStreams,
+ ISequentialOutStream **outStreams, const UInt64 ** /* outSizes */, UInt32 numOutStreams,
+ ICompressProgressInfo *progress)
+{
+ if (numInStreams != 1 || numOutStreams != 4)
+ return E_INVALIDARG;
+
+ if (!_mainStream.Create(1 << 18)) return E_OUTOFMEMORY;
+ if (!_callStream.Create(1 << 18)) return E_OUTOFMEMORY;
+ if (!_jumpStream.Create(1 << 18)) return E_OUTOFMEMORY;
+ if (!_rc.Create(1 << 20)) return E_OUTOFMEMORY;
+ if (_buf == 0)
+ {
+ _buf = (Byte *)MidAlloc(kBufSize);
+ if (_buf == 0)
+ return E_OUTOFMEMORY;
+ }
+
+ bool sizeIsDefined = false;
+ UInt64 inSize = 0;
+ if (inSizes)
+ if (inSizes[0])
+ {
+ inSize = *inSizes[0];
+ if (inSize <= kDefaultLimit)
+ sizeIsDefined = true;
+ }
+
+ ISequentialInStream *inStream = inStreams[0];
+
+ _mainStream.SetStream(outStreams[0]); _mainStream.Init();
+ _callStream.SetStream(outStreams[1]); _callStream.Init();
+ _jumpStream.SetStream(outStreams[2]); _jumpStream.Init();
+ _rc.SetStream(outStreams[3]); _rc.Init();
+ for (unsigned i = 0; i < 256 + 2; i++)
+ _statusEncoder[i].Init();
+
+ CMyComPtr<ICompressGetSubStreamSize> getSubStreamSize;
+ {
+ inStream->QueryInterface(IID_ICompressGetSubStreamSize, (void **)&getSubStreamSize);
+ }
+
+ UInt32 nowPos = 0;
+ UInt64 nowPos64 = 0;
+ UInt32 bufPos = 0;
+
+ Byte prevByte = 0;
+
+ UInt64 subStreamIndex = 0;
+ UInt64 subStreamStartPos = 0;
+ UInt64 subStreamEndPos = 0;
+
+ for (;;)
+ {
+ UInt32 processedSize = 0;
+ for (;;)
+ {
+ UInt32 size = kBufSize - (bufPos + processedSize);
+ UInt32 processedSizeLoc;
+ if (size == 0)
+ break;
+ RINOK(inStream->Read(_buf + bufPos + processedSize, size, &processedSizeLoc));
+ if (processedSizeLoc == 0)
+ break;
+ processedSize += processedSizeLoc;
+ }
+ UInt32 endPos = bufPos + processedSize;
+
+ if (endPos < 5)
+ {
+ // change it
+ for (bufPos = 0; bufPos < endPos; bufPos++)
+ {
+ Byte b = _buf[bufPos];
+ _mainStream.WriteByte(b);
+ UInt32 index;
+ if (b == 0xE8)
+ index = prevByte;
+ else if (b == 0xE9)
+ index = 256;
+ else if (IsJcc(prevByte, b))
+ index = 257;
+ else
+ {
+ prevByte = b;
+ continue;
+ }
+ _statusEncoder[index].Encode(&_rc, 0);
+ prevByte = b;
+ }
+ return Flush();
+ }
+
+ bufPos = 0;
+
+ UInt32 limit = endPos - 5;
+ while (bufPos <= limit)
+ {
+ Byte b = _buf[bufPos];
+ _mainStream.WriteByte(b);
+ if (!IsJ(prevByte, b))
+ {
+ bufPos++;
+ prevByte = b;
+ continue;
+ }
+ Byte nextByte = _buf[bufPos + 4];
+ UInt32 src =
+ (UInt32(nextByte) << 24) |
+ (UInt32(_buf[bufPos + 3]) << 16) |
+ (UInt32(_buf[bufPos + 2]) << 8) |
+ (_buf[bufPos + 1]);
+ UInt32 dest = (nowPos + bufPos + 5) + src;
+ // if (Test86MSByte(nextByte))
+ bool convert;
+ if (getSubStreamSize)
+ {
+ UInt64 currentPos = (nowPos64 + bufPos);
+ while (subStreamEndPos < currentPos)
+ {
+ UInt64 subStreamSize;
+ HRESULT result = getSubStreamSize->GetSubStreamSize(subStreamIndex, &subStreamSize);
+ if (result == S_OK)
+ {
+ subStreamStartPos = subStreamEndPos;
+ subStreamEndPos += subStreamSize;
+ subStreamIndex++;
+ }
+ else if (result == S_FALSE || result == E_NOTIMPL)
+ {
+ getSubStreamSize.Release();
+ subStreamStartPos = 0;
+ subStreamEndPos = subStreamStartPos - 1;
+ }
+ else
+ return result;
+ }
+ if (getSubStreamSize == NULL)
+ {
+ if (sizeIsDefined)
+ convert = (dest < inSize);
+ else
+ convert = Test86MSByte(nextByte);
+ }
+ else if (subStreamEndPos - subStreamStartPos > kDefaultLimit)
+ convert = Test86MSByte(nextByte);
+ else
+ {
+ UInt64 dest64 = (currentPos + 5) + Int64(Int32(src));
+ convert = (dest64 >= subStreamStartPos && dest64 < subStreamEndPos);
+ }
+ }
+ else if (sizeIsDefined)
+ convert = (dest < inSize);
+ else
+ convert = Test86MSByte(nextByte);
+ unsigned index = GetIndex(prevByte, b);
+ if (convert)
+ {
+ _statusEncoder[index].Encode(&_rc, 1);
+ bufPos += 5;
+ COutBuffer &s = (b == 0xE8) ? _callStream : _jumpStream;
+ for (int i = 24; i >= 0; i -= 8)
+ s.WriteByte((Byte)(dest >> i));
+ prevByte = nextByte;
+ }
+ else
+ {
+ _statusEncoder[index].Encode(&_rc, 0);
+ bufPos++;
+ prevByte = b;
+ }
+ }
+ nowPos += bufPos;
+ nowPos64 += bufPos;
+
+ if (progress)
+ {
+ /*
+ const UInt64 compressedSize =
+ _mainStream.GetProcessedSize() +
+ _callStream.GetProcessedSize() +
+ _jumpStream.GetProcessedSize() +
+ _rc.GetProcessedSize();
+ */
+ RINOK(progress->SetRatioInfo(&nowPos64, NULL));
+ }
+
+ UInt32 i = 0;
+ while (bufPos < endPos)
+ _buf[i++] = _buf[bufPos++];
+ bufPos = i;
+ }
+}
+
+STDMETHODIMP CEncoder::Code(ISequentialInStream **inStreams, const UInt64 **inSizes, UInt32 numInStreams,
+ ISequentialOutStream **outStreams, const UInt64 **outSizes, UInt32 numOutStreams,
+ ICompressProgressInfo *progress)
+{
+ try
+ {
+ return CodeReal(inStreams, inSizes, numInStreams, outStreams, outSizes,numOutStreams, progress);
+ }
+ catch(const COutBufferException &e) { return e.ErrorCode; }
+ catch(...) { return S_FALSE; }
+}
+
+#endif
+
+
+STDMETHODIMP CDecoder::SetInBufSize(UInt32 streamIndex, UInt32 size) { _inBufSizes[streamIndex] = size; return S_OK; }
+STDMETHODIMP CDecoder::SetOutBufSize(UInt32 , UInt32 size) { _outBufSize = size; return S_OK; }
+
+CDecoder::CDecoder():
+ _outBufSize(1 << 16)
+{
+ _inBufSizes[0] = 1 << 20;
+ _inBufSizes[1] = 1 << 20;
+ _inBufSizes[2] = 1 << 20;
+ _inBufSizes[3] = 1 << 20;
+}
+
+HRESULT CDecoder::CodeReal(ISequentialInStream **inStreams, const UInt64 ** /* inSizes */, UInt32 numInStreams,
+ ISequentialOutStream **outStreams, const UInt64 ** /* outSizes */, UInt32 numOutStreams,
+ ICompressProgressInfo *progress)
+{
+ if (numInStreams != 4 || numOutStreams != 1)
+ return E_INVALIDARG;
+
+ if (!_mainStream.Create(_inBufSizes[0])) return E_OUTOFMEMORY;
+ if (!_callStream.Create(_inBufSizes[1])) return E_OUTOFMEMORY;
+ if (!_jumpStream.Create(_inBufSizes[2])) return E_OUTOFMEMORY;
+ if (!_rc.Create(_inBufSizes[3])) return E_OUTOFMEMORY;
+ if (!_outStream.Create(_outBufSize)) return E_OUTOFMEMORY;
+
+ _mainStream.SetStream(inStreams[0]);
+ _callStream.SetStream(inStreams[1]);
+ _jumpStream.SetStream(inStreams[2]);
+ _rc.SetStream(inStreams[3]);
+ _outStream.SetStream(outStreams[0]);
+
+ _mainStream.Init();
+ _callStream.Init();
+ _jumpStream.Init();
+ _rc.Init();
+ _outStream.Init();
+
+ for (unsigned i = 0; i < 256 + 2; i++)
+ _statusDecoder[i].Init();
+
+ Byte prevByte = 0;
+ UInt32 processedBytes = 0;
+ for (;;)
+ {
+ if (processedBytes >= (1 << 20) && progress)
+ {
+ /*
+ const UInt64 compressedSize =
+ _mainStream.GetProcessedSize() +
+ _callStream.GetProcessedSize() +
+ _jumpStream.GetProcessedSize() +
+ _rc.GetProcessedSize();
+ */
+ const UInt64 nowPos64 = _outStream.GetProcessedSize();
+ RINOK(progress->SetRatioInfo(NULL, &nowPos64));
+ processedBytes = 0;
+ }
+ UInt32 i;
+ Byte b = 0;
+ const UInt32 kBurstSize = (1 << 18);
+ for (i = 0; i < kBurstSize; i++)
+ {
+ if (!_mainStream.ReadByte(b))
+ return _outStream.Flush();
+ _outStream.WriteByte(b);
+ if (IsJ(prevByte, b))
+ break;
+ prevByte = b;
+ }
+ processedBytes += i;
+ if (i == kBurstSize)
+ continue;
+ unsigned index = GetIndex(prevByte, b);
+ if (_statusDecoder[index].Decode(&_rc) == 1)
+ {
+ UInt32 src = 0;
+ CInBuffer &s = (b == 0xE8) ? _callStream : _jumpStream;
+ for (unsigned i = 0; i < 4; i++)
+ {
+ Byte b0;
+ if (!s.ReadByte(b0))
+ return S_FALSE;
+ src <<= 8;
+ src |= ((UInt32)b0);
+ }
+ UInt32 dest = src - (UInt32(_outStream.GetProcessedSize()) + 4) ;
+ _outStream.WriteByte((Byte)(dest));
+ _outStream.WriteByte((Byte)(dest >> 8));
+ _outStream.WriteByte((Byte)(dest >> 16));
+ _outStream.WriteByte((Byte)(dest >> 24));
+ prevByte = (Byte)(dest >> 24);
+ processedBytes += 4;
+ }
+ else
+ prevByte = b;
+ }
+}
+
+STDMETHODIMP CDecoder::Code(ISequentialInStream **inStreams, const UInt64 **inSizes, UInt32 numInStreams,
+ ISequentialOutStream **outStreams, const UInt64 **outSizes, UInt32 numOutStreams,
+ ICompressProgressInfo *progress)
+{
+ try
+ {
+ return CodeReal(inStreams, inSizes, numInStreams, outStreams, outSizes,numOutStreams, progress);
+ }
+ catch(const CInBufferException &e) { return e.ErrorCode; }
+ catch(const COutBufferException &e) { return e.ErrorCode; }
+ catch(...) { return S_FALSE; }
+}
+
+}}
diff --git a/lzma/CPP/7zip/Compress/Bcj2Coder.h b/lzma/CPP/7zip/Compress/Bcj2Coder.h
new file mode 100644
index 0000000..4d6994f
--- /dev/null
+++ b/lzma/CPP/7zip/Compress/Bcj2Coder.h
@@ -0,0 +1,82 @@
+// Bcj2Coder.h
+
+#ifndef __COMPRESS_BCJ2_CODER_H
+#define __COMPRESS_BCJ2_CODER_H
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+#include "RangeCoderBit.h"
+
+namespace NCompress {
+namespace NBcj2 {
+
+const unsigned kNumMoveBits = 5;
+
+#ifndef EXTRACT_ONLY
+
+class CEncoder:
+ public ICompressCoder2,
+ public CMyUnknownImp
+{
+ Byte *_buf;
+
+ COutBuffer _mainStream;
+ COutBuffer _callStream;
+ COutBuffer _jumpStream;
+ NRangeCoder::CEncoder _rc;
+ NRangeCoder::CBitEncoder<kNumMoveBits> _statusEncoder[256 + 2];
+
+ HRESULT Flush();
+
+public:
+ MY_UNKNOWN_IMP
+
+ HRESULT CodeReal(ISequentialInStream **inStreams, const UInt64 **inSizes, UInt32 numInStreams,
+ ISequentialOutStream **outStreams, const UInt64 **outSizes, UInt32 numOutStreams,
+ ICompressProgressInfo *progress);
+ STDMETHOD(Code)(ISequentialInStream **inStreams, const UInt64 **inSizes, UInt32 numInStreams,
+ ISequentialOutStream **outStreams, const UInt64 **outSizes, UInt32 numOutStreams,
+ ICompressProgressInfo *progress);
+
+ CEncoder(): _buf(0) {};
+ ~CEncoder();
+};
+
+#endif
+
+class CDecoder:
+ public ICompressCoder2,
+ public ICompressSetBufSize,
+ public CMyUnknownImp
+{
+ CInBuffer _mainStream;
+ CInBuffer _callStream;
+ CInBuffer _jumpStream;
+ NRangeCoder::CDecoder _rc;
+ NRangeCoder::CBitDecoder<kNumMoveBits> _statusDecoder[256 + 2];
+
+ COutBuffer _outStream;
+ UInt32 _inBufSizes[4];
+ UInt32 _outBufSize;
+
+public:
+ MY_UNKNOWN_IMP1(ICompressSetBufSize);
+
+ HRESULT CodeReal(ISequentialInStream **inStreams, const UInt64 **inSizes, UInt32 numInStreams,
+ ISequentialOutStream **outStreams, const UInt64 **outSizes, UInt32 numOutStreams,
+ ICompressProgressInfo *progress);
+ STDMETHOD(Code)(ISequentialInStream **inStreams, const UInt64 **inSizes, UInt32 numInStreams,
+ ISequentialOutStream **outStreams, const UInt64 **outSizes, UInt32 numOutStreams,
+ ICompressProgressInfo *progress);
+
+ STDMETHOD(SetInBufSize)(UInt32 streamIndex, UInt32 size);
+ STDMETHOD(SetOutBufSize)(UInt32 streamIndex, UInt32 size);
+
+ CDecoder();
+};
+
+}}
+
+#endif
diff --git a/lzma/CPP/7zip/Compress/Bcj2Register.cpp b/lzma/CPP/7zip/Compress/Bcj2Register.cpp
new file mode 100644
index 0000000..b063f3f
--- /dev/null
+++ b/lzma/CPP/7zip/Compress/Bcj2Register.cpp
@@ -0,0 +1,19 @@
+// Bcj2Register.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/RegisterCodec.h"
+
+#include "Bcj2Coder.h"
+
+static void *CreateCodec() { return (void *)(ICompressCoder2 *)(new NCompress::NBcj2::CDecoder()); }
+#ifndef EXTRACT_ONLY
+static void *CreateCodecOut() { return (void *)(ICompressCoder2 *)(new NCompress::NBcj2::CEncoder()); }
+#else
+#define CreateCodecOut 0
+#endif
+
+static CCodecInfo g_CodecInfo =
+ { CreateCodec, CreateCodecOut, 0x0303011B, L"BCJ2", 4, false };
+
+REGISTER_CODEC(BCJ2)
diff --git a/lzma/CPP/7zip/Compress/BcjCoder.cpp b/lzma/CPP/7zip/Compress/BcjCoder.cpp
new file mode 100644
index 0000000..108c573
--- /dev/null
+++ b/lzma/CPP/7zip/Compress/BcjCoder.cpp
@@ -0,0 +1,15 @@
+// BcjCoder.cpp
+
+#include "StdAfx.h"
+
+#include "BcjCoder.h"
+
+UInt32 CBCJ_x86_Encoder::SubFilter(Byte *data, UInt32 size)
+{
+ return (UInt32)::x86_Convert(data, size, _bufferPos, &_prevMask, 1);
+}
+
+UInt32 CBCJ_x86_Decoder::SubFilter(Byte *data, UInt32 size)
+{
+ return (UInt32)::x86_Convert(data, size, _bufferPos, &_prevMask, 0);
+}
diff --git a/lzma/CPP/7zip/Compress/BcjCoder.h b/lzma/CPP/7zip/Compress/BcjCoder.h
new file mode 100644
index 0000000..c86d5fc
--- /dev/null
+++ b/lzma/CPP/7zip/Compress/BcjCoder.h
@@ -0,0 +1,19 @@
+// BcjCoder.h
+
+#ifndef __COMPRESS_BCJ_CODER_H
+#define __COMPRESS_BCJ_CODER_H
+
+#include "../../../C/Bra.h"
+
+#include "BranchCoder.h"
+
+struct CBranch86
+{
+ UInt32 _prevMask;
+ void x86Init() { x86_Convert_Init(_prevMask); }
+};
+
+MyClassB(BCJ_x86, 0x01, 3, CBranch86 ,
+ virtual void SubInit() { x86Init(); })
+
+#endif
diff --git a/lzma/CPP/7zip/Compress/BcjRegister.cpp b/lzma/CPP/7zip/Compress/BcjRegister.cpp
new file mode 100644
index 0000000..09e53c6
--- /dev/null
+++ b/lzma/CPP/7zip/Compress/BcjRegister.cpp
@@ -0,0 +1,19 @@
+// BcjRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/RegisterCodec.h"
+
+#include "BcjCoder.h"
+
+static void *CreateCodec() { return (void *)(ICompressFilter *)(new CBCJ_x86_Decoder()); }
+#ifndef EXTRACT_ONLY
+static void *CreateCodecOut() { return (void *)(ICompressFilter *)(new CBCJ_x86_Encoder()); }
+#else
+#define CreateCodecOut 0
+#endif
+
+static CCodecInfo g_CodecInfo =
+ { CreateCodec, CreateCodecOut, 0x03030103, L"BCJ", 1, true };
+
+REGISTER_CODEC(BCJ)
diff --git a/lzma/CPP/7zip/Compress/BranchCoder.cpp b/lzma/CPP/7zip/Compress/BranchCoder.cpp
new file mode 100644
index 0000000..6cacc66
--- /dev/null
+++ b/lzma/CPP/7zip/Compress/BranchCoder.cpp
@@ -0,0 +1,19 @@
+// BranchCoder.cpp
+
+#include "StdAfx.h"
+
+#include "BranchCoder.h"
+
+STDMETHODIMP CBranchConverter::Init()
+{
+ _bufferPos = 0;
+ SubInit();
+ return S_OK;
+}
+
+STDMETHODIMP_(UInt32) CBranchConverter::Filter(Byte *data, UInt32 size)
+{
+ UInt32 processedSize = SubFilter(data, size);
+ _bufferPos += processedSize;
+ return processedSize;
+}
diff --git a/lzma/CPP/7zip/Compress/BranchCoder.h b/lzma/CPP/7zip/Compress/BranchCoder.h
new file mode 100644
index 0000000..473286a
--- /dev/null
+++ b/lzma/CPP/7zip/Compress/BranchCoder.h
@@ -0,0 +1,44 @@
+// BranchCoder.h
+
+#ifndef __COMPRESS_BRANCH_CODER_H
+#define __COMPRESS_BRANCH_CODER_H
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+class CBranchConverter:
+ public ICompressFilter,
+ public CMyUnknownImp
+{
+protected:
+ UInt32 _bufferPos;
+ virtual void SubInit() {}
+ virtual UInt32 SubFilter(Byte *data, UInt32 size) = 0;
+public:
+ MY_UNKNOWN_IMP;
+ STDMETHOD(Init)();
+ STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size);
+};
+
+#define MyClassEncoderA(Name) class C ## Name: public CBranchConverter \
+ { public: UInt32 SubFilter(Byte *data, UInt32 size); };
+
+#define MyClassDecoderA(Name) class C ## Name: public CBranchConverter \
+ { public: UInt32 SubFilter(Byte *data, UInt32 size); };
+
+#define MyClassEncoderB(Name, ADD_ITEMS, ADD_INIT) class C ## Name: public CBranchConverter, public ADD_ITEMS \
+ { public: UInt32 SubFilter(Byte *data, UInt32 size); ADD_INIT};
+
+#define MyClassDecoderB(Name, ADD_ITEMS, ADD_INIT) class C ## Name: public CBranchConverter, public ADD_ITEMS \
+ { public: UInt32 SubFilter(Byte *data, UInt32 size); ADD_INIT};
+
+#define MyClassA(Name, id, subId) \
+MyClassEncoderA(Name ## _Encoder) \
+MyClassDecoderA(Name ## _Decoder)
+
+#define MyClassB(Name, id, subId, ADD_ITEMS, ADD_INIT) \
+MyClassEncoderB(Name ## _Encoder, ADD_ITEMS, ADD_INIT) \
+MyClassDecoderB(Name ## _Decoder, ADD_ITEMS, ADD_INIT)
+
+#endif
diff --git a/lzma/CPP/7zip/Compress/BranchMisc.cpp b/lzma/CPP/7zip/Compress/BranchMisc.cpp
new file mode 100644
index 0000000..1ac7949
--- /dev/null
+++ b/lzma/CPP/7zip/Compress/BranchMisc.cpp
@@ -0,0 +1,21 @@
+// BranchMisc.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Bra.h"
+
+#include "BranchMisc.h"
+
+#define SUB_FILTER_IMP2(name, coderStr, coderNum) \
+ UInt32 CBC_ ## name ## coderStr::SubFilter(Byte *data, UInt32 size) \
+ { return (UInt32)::name ## Convert(data, size, _bufferPos, coderNum); }
+
+#define SUB_FILTER_IMP(name) \
+ SUB_FILTER_IMP2(name, Encoder, 1) \
+ SUB_FILTER_IMP2(name, Decoder, 0) \
+
+SUB_FILTER_IMP(ARM_)
+SUB_FILTER_IMP(ARMT_)
+SUB_FILTER_IMP(PPC_)
+SUB_FILTER_IMP(SPARC_)
+SUB_FILTER_IMP(IA64_)
diff --git a/lzma/CPP/7zip/Compress/BranchMisc.h b/lzma/CPP/7zip/Compress/BranchMisc.h
new file mode 100644
index 0000000..053e923
--- /dev/null
+++ b/lzma/CPP/7zip/Compress/BranchMisc.h
@@ -0,0 +1,14 @@
+// BranchMisc.h
+
+#ifndef __COMPRESS_BRANCH_MISC_H
+#define __COMPRESS_BRANCH_MISC_H
+
+#include "BranchCoder.h"
+
+MyClassA(BC_ARM, 0x05, 1)
+MyClassA(BC_ARMT, 0x07, 1)
+MyClassA(BC_PPC, 0x02, 5)
+MyClassA(BC_SPARC, 0x08, 5)
+MyClassA(BC_IA64, 0x04, 1)
+
+#endif
diff --git a/lzma/CPP/7zip/Compress/BranchRegister.cpp b/lzma/CPP/7zip/Compress/BranchRegister.cpp
new file mode 100644
index 0000000..bc55dd6
--- /dev/null
+++ b/lzma/CPP/7zip/Compress/BranchRegister.cpp
@@ -0,0 +1,30 @@
+// BranchRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/RegisterCodec.h"
+
+#include "BranchMisc.h"
+
+#define CREATE_CODEC(x) \
+ static void *CreateCodec ## x() { return (void *)(ICompressFilter *)(new C ## x ## _Decoder); } \
+ static void *CreateCodec ## x ## Out() { return (void *)(ICompressFilter *)(new C ## x ## _Encoder); }
+
+CREATE_CODEC(BC_PPC)
+CREATE_CODEC(BC_IA64)
+CREATE_CODEC(BC_ARM)
+CREATE_CODEC(BC_ARMT)
+CREATE_CODEC(BC_SPARC)
+
+#define METHOD_ITEM(x, id1, id2, name) { CreateCodec ## x, CreateCodec ## x ## Out, 0x03030000 + (id1 * 256) + id2, name, 1, true }
+
+static CCodecInfo g_CodecsInfo[] =
+{
+ METHOD_ITEM(BC_PPC, 0x02, 0x05, L"PPC"),
+ METHOD_ITEM(BC_IA64, 0x04, 1, L"IA64"),
+ METHOD_ITEM(BC_ARM, 0x05, 1, L"ARM"),
+ METHOD_ITEM(BC_ARMT, 0x07, 1, L"ARMT"),
+ METHOD_ITEM(BC_SPARC, 0x08, 0x05, L"SPARC")
+};
+
+REGISTER_CODECS(Branch)
diff --git a/lzma/CPP/7zip/Compress/ByteSwap.cpp b/lzma/CPP/7zip/Compress/ByteSwap.cpp
new file mode 100644
index 0000000..7f028fb
--- /dev/null
+++ b/lzma/CPP/7zip/Compress/ByteSwap.cpp
@@ -0,0 +1,73 @@
+// ByteSwap.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+#include "../Common/RegisterCodec.h"
+
+class CByteSwap2:
+ public ICompressFilter,
+ public CMyUnknownImp
+{
+public:
+ MY_UNKNOWN_IMP
+ STDMETHOD(Init)();
+ STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size);
+};
+
+class CByteSwap4:
+ public ICompressFilter,
+ public CMyUnknownImp
+{
+public:
+ MY_UNKNOWN_IMP
+ STDMETHOD(Init)();
+ STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size);
+};
+
+STDMETHODIMP CByteSwap2::Init() { return S_OK; }
+
+STDMETHODIMP_(UInt32) CByteSwap2::Filter(Byte *data, UInt32 size)
+{
+ const UInt32 kStep = 2;
+ UInt32 i;
+ for (i = 0; i + kStep <= size; i += kStep)
+ {
+ Byte b = data[i];
+ data[i] = data[i + 1];
+ data[i + 1] = b;
+ }
+ return i;
+}
+
+STDMETHODIMP CByteSwap4::Init() { return S_OK; }
+
+STDMETHODIMP_(UInt32) CByteSwap4::Filter(Byte *data, UInt32 size)
+{
+ const UInt32 kStep = 4;
+ UInt32 i;
+ for (i = 0; i + kStep <= size; i += kStep)
+ {
+ Byte b0 = data[i];
+ Byte b1 = data[i + 1];
+ data[i] = data[i + 3];
+ data[i + 1] = data[i + 2];
+ data[i + 2] = b1;
+ data[i + 3] = b0;
+ }
+ return i;
+}
+
+static void *CreateCodec2() { return (void *)(ICompressFilter *)(new CByteSwap2); }
+static void *CreateCodec4() { return (void *)(ICompressFilter *)(new CByteSwap4); }
+
+static CCodecInfo g_CodecsInfo[] =
+{
+ { CreateCodec2, CreateCodec2, 0x020302, L"Swap2", 1, true },
+ { CreateCodec4, CreateCodec4, 0x020304, L"Swap4", 1, true }
+};
+
+REGISTER_CODECS(ByteSwap)
diff --git a/lzma/CPP/7zip/Compress/CodecExports.cpp b/lzma/CPP/7zip/Compress/CodecExports.cpp
new file mode 100644
index 0000000..8691d5d
--- /dev/null
+++ b/lzma/CPP/7zip/Compress/CodecExports.cpp
@@ -0,0 +1,283 @@
+// CodecExports.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "../../Common/ComTry.h"
+#include "../../Common/MyCom.h"
+
+#include "../../Windows/PropVariant.h"
+
+#include "../ICoder.h"
+
+#include "../Common/RegisterCodec.h"
+
+extern unsigned int g_NumCodecs;
+extern const CCodecInfo *g_Codecs[];
+
+extern unsigned int g_NumHashers;
+extern const CHasherInfo *g_Hashers[];
+
+static const UInt16 kDecodeId = 0x2790;
+static const UInt16 kEncodeId = 0x2791;
+static const UInt16 kHasherId = 0x2792;
+
+DEFINE_GUID(CLSID_CCodec,
+0x23170F69, 0x40C1, kDecodeId, 0, 0, 0, 0, 0, 0, 0, 0);
+
+static inline HRESULT SetPropString(const char *s, unsigned int 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 SetPropString((const char *)&guid, sizeof(GUID), value);
+}
+
+static HRESULT SetClassID(CMethodId id, UInt16 typeId, PROPVARIANT *value)
+{
+ GUID clsId;
+ clsId.Data1 = CLSID_CCodec.Data1;
+ clsId.Data2 = CLSID_CCodec.Data2;
+ clsId.Data3 = typeId;
+ SetUi64(clsId.Data4, id);
+ return SetPropGUID(clsId, value);
+}
+
+static HRESULT FindCodecClassId(const GUID *clsID, UInt32 isCoder2, bool isFilter, bool &encode, int &index)
+{
+ index = -1;
+ if (clsID->Data1 != CLSID_CCodec.Data1 ||
+ clsID->Data2 != CLSID_CCodec.Data2)
+ return S_OK;
+ encode = true;
+ if (clsID->Data3 == kDecodeId)
+ encode = false;
+ else if (clsID->Data3 != kEncodeId)
+ 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 || !encode && !codec.CreateDecoder)
+ continue;
+ if (!isFilter && codec.IsFilter || isFilter && !codec.IsFilter ||
+ codec.NumInStreams != 1 && !isCoder2 || codec.NumInStreams == 1 && isCoder2)
+ return E_NOINTERFACE;
+ index = i;
+ return S_OK;
+ }
+ return S_OK;
+}
+
+STDAPI CreateCoder2(bool encode, int index, const GUID *iid, void **outObject)
+{
+ COM_TRY_BEGIN
+ *outObject = 0;
+ bool isCoder = (*iid == IID_ICompressCoder) != 0;
+ bool isCoder2 = (*iid == IID_ICompressCoder2) != 0;
+ bool isFilter = (*iid == IID_ICompressFilter) != 0;
+ const CCodecInfo &codec = *g_Codecs[index];
+ if (!isFilter && codec.IsFilter || isFilter && !codec.IsFilter ||
+ codec.NumInStreams != 1 && !isCoder2 || codec.NumInStreams == 1 && isCoder2)
+ return E_NOINTERFACE;
+ if (encode)
+ {
+ if (!codec.CreateEncoder)
+ return CLASS_E_CLASSNOTAVAILABLE;
+ *outObject = codec.CreateEncoder();
+ }
+ else
+ {
+ if (!codec.CreateDecoder)
+ return CLASS_E_CLASSNOTAVAILABLE;
+ *outObject = codec.CreateDecoder();
+ }
+ if (*outObject)
+ {
+ if (isCoder)
+ ((ICompressCoder *)*outObject)->AddRef();
+ else if (isCoder2)
+ ((ICompressCoder2 *)*outObject)->AddRef();
+ else
+ ((ICompressFilter *)*outObject)->AddRef();
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDAPI CreateCoder(const GUID *clsid, const GUID *iid, void **outObject)
+{
+ COM_TRY_BEGIN
+ *outObject = 0;
+ bool isCoder = (*iid == IID_ICompressCoder) != 0;
+ bool isCoder2 = (*iid == IID_ICompressCoder2) != 0;
+ bool isFilter = (*iid == IID_ICompressFilter) != 0;
+ if (!isCoder && !isCoder2 && !isFilter)
+ 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;
+
+ const CCodecInfo &codec = *g_Codecs[codecIndex];
+ if (encode)
+ *outObject = codec.CreateEncoder();
+ else
+ *outObject = codec.CreateDecoder();
+ if (*outObject)
+ {
+ if (isCoder)
+ ((ICompressCoder *)*outObject)->AddRef();
+ else if (isCoder2)
+ ((ICompressCoder2 *)*outObject)->AddRef();
+ else
+ ((ICompressFilter *)*outObject)->AddRef();
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+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:
+ if ((value->bstrVal = ::SysAllocString(codec.Name)) != 0)
+ value->vt = VT_BSTR;
+ break;
+ case NMethodPropID::kDecoder:
+ if (codec.CreateDecoder)
+ return SetClassID(codec.Id, kDecodeId, value);
+ break;
+ case NMethodPropID::kEncoder:
+ if (codec.CreateEncoder)
+ return SetClassID(codec.Id, kEncodeId, value);
+ break;
+ case NMethodPropID::kInStreams:
+ if (codec.NumInStreams != 1)
+ {
+ value->vt = VT_UI4;
+ value->ulVal = (ULONG)codec.NumInStreams;
+ }
+ break;
+ }
+ return S_OK;
+}
+
+STDAPI GetNumberOfMethods(UINT32 *numCodecs)
+{
+ *numCodecs = g_NumCodecs;
+ return S_OK;
+}
+
+
+static int FindHasherClassId(const GUID *clsID)
+{
+ if (clsID->Data1 != CLSID_CCodec.Data1 ||
+ clsID->Data2 != CLSID_CCodec.Data2 ||
+ clsID->Data3 != kHasherId)
+ 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:
+ if ((value->bstrVal = ::SysAllocString(codec.Name)) != 0)
+ value->vt = VT_BSTR;
+ break;
+ case NMethodPropID::kEncoder:
+ if (codec.CreateHasher)
+ return SetClassID(codec.Id, kHasherId, 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);
+}
diff --git a/lzma/CPP/7zip/Compress/CopyCoder.cpp b/lzma/CPP/7zip/Compress/CopyCoder.cpp
new file mode 100644
index 0000000..66ab85e
--- /dev/null
+++ b/lzma/CPP/7zip/Compress/CopyCoder.cpp
@@ -0,0 +1,74 @@
+// Compress/CopyCoder.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+
+#include "../Common/StreamUtils.h"
+
+#include "CopyCoder.h"
+
+namespace NCompress {
+
+static const UInt32 kBufferSize = 1 << 17;
+
+CCopyCoder::~CCopyCoder()
+{
+ ::MidFree(_buffer);
+}
+
+STDMETHODIMP CCopyCoder::Code(ISequentialInStream *inStream,
+ ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 *outSize,
+ ICompressProgressInfo *progress)
+{
+ if (!_buffer)
+ {
+ _buffer = (Byte *)::MidAlloc(kBufferSize);
+ if (!_buffer)
+ return E_OUTOFMEMORY;
+ }
+
+ TotalSize = 0;
+ for (;;)
+ {
+ UInt32 size = kBufferSize;
+ if (outSize && size > *outSize - TotalSize)
+ size = (UInt32)(*outSize - TotalSize);
+ RINOK(inStream->Read(_buffer, size, &size));
+ if (size == 0)
+ break;
+ if (outStream)
+ {
+ RINOK(WriteStream(outStream, _buffer, size));
+ }
+ TotalSize += size;
+ if (progress)
+ {
+ RINOK(progress->SetRatioInfo(&TotalSize, &TotalSize));
+ }
+ }
+ return S_OK;
+}
+
+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;
+}
+
+}
diff --git a/lzma/CPP/7zip/Compress/CopyCoder.h b/lzma/CPP/7zip/Compress/CopyCoder.h
new file mode 100644
index 0000000..254266a
--- /dev/null
+++ b/lzma/CPP/7zip/Compress/CopyCoder.h
@@ -0,0 +1,35 @@
+// 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 ICompressGetInStreamProcessedSize,
+ public CMyUnknownImp
+{
+ Byte *_buffer;
+public:
+ UInt64 TotalSize;
+ CCopyCoder(): TotalSize(0), _buffer(0) {};
+ ~CCopyCoder();
+
+ MY_UNKNOWN_IMP1(ICompressGetInStreamProcessedSize)
+
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+ STDMETHOD(GetInStreamProcessedSize)(UInt64 *value);
+};
+
+HRESULT CopyStream(ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress);
+HRESULT CopyStream_ExactSize(ISequentialInStream *inStream, ISequentialOutStream *outStream, UInt64 size, ICompressProgressInfo *progress);
+
+}
+
+#endif
diff --git a/lzma/CPP/7zip/Compress/CopyRegister.cpp b/lzma/CPP/7zip/Compress/CopyRegister.cpp
new file mode 100644
index 0000000..3ef2459
--- /dev/null
+++ b/lzma/CPP/7zip/Compress/CopyRegister.cpp
@@ -0,0 +1,14 @@
+// CopyRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/RegisterCodec.h"
+
+#include "CopyCoder.h"
+
+static void *CreateCodec() { return (void *)(ICompressCoder *)(new NCompress::CCopyCoder); }
+
+static CCodecInfo g_CodecInfo =
+{ CreateCodec, CreateCodec, 0x00, L"Copy", 1, false };
+
+REGISTER_CODEC(Copy)
diff --git a/lzma/CPP/7zip/Compress/DeltaFilter.cpp b/lzma/CPP/7zip/Compress/DeltaFilter.cpp
new file mode 100644
index 0000000..a7f70fe
--- /dev/null
+++ b/lzma/CPP/7zip/Compress/DeltaFilter.cpp
@@ -0,0 +1,125 @@
+// DeltaFilter.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Delta.h"
+
+#include "../Common/RegisterCodec.h"
+
+#include "BranchCoder.h"
+
+struct CDelta
+{
+ unsigned _delta;
+ Byte _state[DELTA_STATE_SIZE];
+ CDelta(): _delta(1) {}
+ void DeltaInit() { Delta_Init(_state); }
+};
+
+class CDeltaEncoder:
+ public ICompressFilter,
+ public ICompressSetCoderProperties,
+ public ICompressWriteCoderProperties,
+ CDelta,
+ public CMyUnknownImp
+{
+public:
+ MY_UNKNOWN_IMP2(ICompressSetCoderProperties, ICompressWriteCoderProperties)
+ STDMETHOD(Init)();
+ STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size);
+ STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
+ STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStream);
+};
+
+class CDeltaDecoder:
+ public ICompressFilter,
+ public ICompressSetDecoderProperties2,
+ CDelta,
+ public CMyUnknownImp
+{
+public:
+ MY_UNKNOWN_IMP1(ICompressSetDecoderProperties2)
+ STDMETHOD(Init)();
+ STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size);
+ STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
+};
+
+STDMETHODIMP CDeltaEncoder::Init()
+{
+ DeltaInit();
+ return S_OK;
+}
+
+STDMETHODIMP_(UInt32) CDeltaEncoder::Filter(Byte *data, UInt32 size)
+{
+ Delta_Encode(_state, _delta, data, size);
+ return size;
+}
+
+STDMETHODIMP CDeltaEncoder::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 CDeltaEncoder::WriteCoderProperties(ISequentialOutStream *outStream)
+{
+ Byte prop = (Byte)(_delta - 1);
+ return outStream->Write(&prop, 1, NULL);
+}
+
+STDMETHODIMP CDeltaDecoder::Init()
+{
+ DeltaInit();
+ return S_OK;
+}
+
+STDMETHODIMP_(UInt32) CDeltaDecoder::Filter(Byte *data, UInt32 size)
+{
+ Delta_Decode(_state, _delta, data, size);
+ return size;
+}
+
+STDMETHODIMP CDeltaDecoder::SetDecoderProperties2(const Byte *props, UInt32 size)
+{
+ if (size != 1)
+ return E_INVALIDARG;
+ _delta = (unsigned)props[0] + 1;
+ return S_OK;
+}
+
+#define CREATE_CODEC(x) \
+ static void *CreateCodec ## x() { return (void *)(ICompressFilter *)(new C ## x ## Decoder); } \
+ static void *CreateCodec ## x ## Out() { return (void *)(ICompressFilter *)(new C ## x ## Encoder); }
+
+CREATE_CODEC(Delta)
+
+#define METHOD_ITEM(x, id, name) { CreateCodec ## x, CreateCodec ## x ## Out, id, name, 1, true }
+
+static CCodecInfo g_CodecsInfo[] =
+{
+ METHOD_ITEM(Delta, 3, L"Delta")
+};
+
+REGISTER_CODECS(Delta)
diff --git a/lzma/CPP/7zip/Compress/Lzma2Decoder.cpp b/lzma/CPP/7zip/Compress/Lzma2Decoder.cpp
new file mode 100644
index 0000000..8d3d830
--- /dev/null
+++ b/lzma/CPP/7zip/Compress/Lzma2Decoder.cpp
@@ -0,0 +1,189 @@
+// Lzma2Decoder.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+
+#include "../Common/StreamUtils.h"
+
+#include "Lzma2Decoder.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_PROGRESS: return E_ABORT;
+ case SZ_ERROR_DATA: return S_FALSE;
+ }
+ return E_FAIL;
+}
+
+namespace NCompress {
+namespace NLzma2 {
+
+static const UInt32 kInBufSize = 1 << 20;
+
+CDecoder::CDecoder(): _inBuf(0), _outSizeDefined(false)
+{
+ Lzma2Dec_Construct(&_state);
+}
+
+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 };
+
+CDecoder::~CDecoder()
+{
+ Lzma2Dec_Free(&_state, &g_Alloc);
+ MyFree(_inBuf);
+}
+
+STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *prop, UInt32 size)
+{
+ if (size != 1) return SZ_ERROR_UNSUPPORTED;
+ RINOK(SResToHRESULT(Lzma2Dec_Allocate(&_state, prop[0], &g_Alloc)));
+ if (_inBuf == 0)
+ {
+ _inBuf = (Byte *)MyAlloc(kInBufSize);
+ if (_inBuf == 0)
+ return E_OUTOFMEMORY;
+ }
+
+ return S_OK;
+}
+
+STDMETHODIMP CDecoder::GetInStreamProcessedSize(UInt64 *value) { *value = _inSizeProcessed; return S_OK; }
+STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream) { _inStream = inStream; return S_OK; }
+STDMETHODIMP CDecoder::ReleaseInStream() { _inStream.Release(); return S_OK; }
+
+STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)
+{
+ _outSizeDefined = (outSize != NULL);
+ if (_outSizeDefined)
+ _outSize = *outSize;
+
+ Lzma2Dec_Init(&_state);
+
+ _inPos = _inSize = 0;
+ _inSizeProcessed = _outSizeProcessed = 0;
+ return S_OK;
+}
+
+STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream,
+ ISequentialOutStream *outStream, const UInt64 * /* inSize */,
+ const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ if (_inBuf == 0)
+ return S_FALSE;
+ SetOutStreamSize(outSize);
+
+ for (;;)
+ {
+ if (_inPos == _inSize)
+ {
+ _inPos = _inSize = 0;
+ RINOK(inStream->Read(_inBuf, kInBufSize, &_inSize));
+ }
+
+ SizeT dicPos = _state.decoder.dicPos;
+ SizeT curSize = _state.decoder.dicBufSize - dicPos;
+ const UInt32 kStepSize = ((UInt32)1 << 22);
+ if (curSize > kStepSize)
+ curSize = (SizeT)kStepSize;
+
+ ELzmaFinishMode finishMode = LZMA_FINISH_ANY;
+ if (_outSizeDefined)
+ {
+ const UInt64 rem = _outSize - _outSizeProcessed;
+ if (rem < curSize)
+ {
+ curSize = (SizeT)rem;
+ /*
+ // finishMode = LZMA_FINISH_END;
+ we can't use LZMA_FINISH_END here to allow partial decoding
+ */
+ }
+ }
+
+ SizeT inSizeProcessed = _inSize - _inPos;
+ ELzmaStatus status;
+ SRes res = Lzma2Dec_DecodeToDic(&_state, dicPos + curSize, _inBuf + _inPos, &inSizeProcessed, finishMode, &status);
+
+ _inPos += (UInt32)inSizeProcessed;
+ _inSizeProcessed += inSizeProcessed;
+ SizeT outSizeProcessed = _state.decoder.dicPos - dicPos;
+ _outSizeProcessed += outSizeProcessed;
+
+ bool finished = (inSizeProcessed == 0 && outSizeProcessed == 0);
+ bool stopDecoding = (_outSizeDefined && _outSizeProcessed >= _outSize);
+
+ if (res != 0 || _state.decoder.dicPos == _state.decoder.dicBufSize || finished || stopDecoding)
+ {
+ HRESULT res2 = WriteStream(outStream, _state.decoder.dic, _state.decoder.dicPos);
+ if (res != 0)
+ return S_FALSE;
+ RINOK(res2);
+ if (stopDecoding)
+ return S_OK;
+ if (finished)
+ return (status == LZMA_STATUS_FINISHED_WITH_MARK ? S_OK : S_FALSE);
+ }
+ if (_state.decoder.dicPos == _state.decoder.dicBufSize)
+ _state.decoder.dicPos = 0;
+
+ if (progress != NULL)
+ {
+ RINOK(progress->SetRatioInfo(&_inSizeProcessed, &_outSizeProcessed));
+ }
+ }
+}
+
+#ifndef NO_READ_FROM_CODER
+
+STDMETHODIMP CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize)
+ *processedSize = 0;
+ do
+ {
+ if (_inPos == _inSize)
+ {
+ _inPos = _inSize = 0;
+ RINOK(_inStream->Read(_inBuf, kInBufSize, &_inSize));
+ }
+ {
+ SizeT inProcessed = _inSize - _inPos;
+
+ if (_outSizeDefined)
+ {
+ const UInt64 rem = _outSize - _outSizeProcessed;
+ if (rem < size)
+ size = (UInt32)rem;
+ }
+
+ SizeT outProcessed = size;
+ ELzmaStatus status;
+ SRes res = Lzma2Dec_DecodeToBuf(&_state, (Byte *)data, &outProcessed,
+ _inBuf + _inPos, &inProcessed, LZMA_FINISH_ANY, &status);
+ _inPos += (UInt32)inProcessed;
+ _inSizeProcessed += inProcessed;
+ _outSizeProcessed += outProcessed;
+ size -= (UInt32)outProcessed;
+ data = (Byte *)data + outProcessed;
+ if (processedSize)
+ *processedSize += (UInt32)outProcessed;
+ RINOK(SResToHRESULT(res));
+ if (inProcessed == 0 && outProcessed == 0)
+ return S_OK;
+ }
+ }
+ while (size != 0);
+ return S_OK;
+}
+
+#endif
+
+}}
diff --git a/lzma/CPP/7zip/Compress/Lzma2Decoder.h b/lzma/CPP/7zip/Compress/Lzma2Decoder.h
new file mode 100644
index 0000000..3540097
--- /dev/null
+++ b/lzma/CPP/7zip/Compress/Lzma2Decoder.h
@@ -0,0 +1,73 @@
+// Lzma2Decoder.h
+
+#ifndef __LZMA2_DECODER_H
+#define __LZMA2_DECODER_H
+
+#include "../../../C/Lzma2Dec.h"
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+namespace NCompress {
+namespace NLzma2 {
+
+class CDecoder:
+ public ICompressCoder,
+ public ICompressSetDecoderProperties2,
+ public ICompressGetInStreamProcessedSize,
+ #ifndef NO_READ_FROM_CODER
+ public ICompressSetInStream,
+ public ICompressSetOutStreamSize,
+ public ISequentialInStream,
+ #endif
+ public CMyUnknownImp
+{
+ CMyComPtr<ISequentialInStream> _inStream;
+ Byte *_inBuf;
+ UInt32 _inPos;
+ UInt32 _inSize;
+ CLzma2Dec _state;
+ bool _outSizeDefined;
+ UInt64 _outSize;
+ UInt64 _inSizeProcessed;
+ UInt64 _outSizeProcessed;
+public:
+
+ #ifndef NO_READ_FROM_CODER
+ MY_UNKNOWN_IMP5(
+ ICompressSetDecoderProperties2,
+ ICompressGetInStreamProcessedSize,
+ ICompressSetInStream,
+ ICompressSetOutStreamSize,
+ ISequentialInStream)
+ #else
+ MY_UNKNOWN_IMP2(
+ ICompressSetDecoderProperties2,
+ ICompressGetInStreamProcessedSize)
+ #endif
+
+ 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(SetInStream)(ISequentialInStream *inStream);
+ STDMETHOD(ReleaseInStream)();
+ STDMETHOD(SetOutStreamSize)(const UInt64 *outSize);
+
+ #ifndef NO_READ_FROM_CODER
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+ #endif
+
+ CDecoder();
+ virtual ~CDecoder();
+
+};
+
+}}
+
+#endif
diff --git a/lzma/CPP/7zip/Compress/Lzma2Encoder.cpp b/lzma/CPP/7zip/Compress/Lzma2Encoder.cpp
new file mode 100644
index 0000000..871f146
--- /dev/null
+++ b/lzma/CPP/7zip/Compress/Lzma2Encoder.cpp
@@ -0,0 +1,94 @@
+// 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 {
+
+static void *SzBigAlloc(void *, size_t size) { return BigAlloc(size); }
+static void SzBigFree(void *, void *address) { BigFree(address); }
+static ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree };
+
+static void *SzAlloc(void *, size_t size) { return MyAlloc(size); }
+static void SzFree(void *, void *address) { MyFree(address); }
+static ISzAlloc g_Alloc = { SzAlloc, SzFree };
+
+CEncoder::CEncoder()
+{
+ _encoder = 0;
+ _encoder = Lzma2Enc_Create(&g_Alloc, &g_BigAlloc);
+ if (_encoder == 0)
+ throw 1;
+}
+
+CEncoder::~CEncoder()
+{
+ if (_encoder != 0)
+ Lzma2Enc_Destroy(_encoder);
+}
+
+HRESULT SetLzma2Prop(PROPID propID, const PROPVARIANT &prop, CLzma2EncProps &lzma2Props)
+{
+ switch (propID)
+ {
+ case NCoderPropID::kBlockSize:
+ if (prop.vt != VT_UI4) return E_INVALIDARG; lzma2Props.blockSize = prop.ulVal; 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::WriteCoderProperties(ISequentialOutStream *outStream)
+{
+ Byte prop = Lzma2Enc_WriteProperties(_encoder);
+ return WriteStream(outStream, &prop, 1);
+}
+
+STDMETHODIMP CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
+{
+ CSeqInStreamWrap inWrap(inStream);
+ CSeqOutStreamWrap outWrap(outStream);
+ CCompressProgressWrap progressWrap(progress);
+
+ SRes res = Lzma2Enc_Encode(_encoder, &outWrap.p, &inWrap.p, progress ? &progressWrap.p : NULL);
+ if (res == SZ_ERROR_READ && inWrap.Res != S_OK)
+ return inWrap.Res;
+ if (res == SZ_ERROR_WRITE && outWrap.Res != S_OK)
+ return outWrap.Res;
+ if (res == SZ_ERROR_PROGRESS && progressWrap.Res != S_OK)
+ return progressWrap.Res;
+ return SResToHRESULT(res);
+}
+
+}}
diff --git a/lzma/CPP/7zip/Compress/Lzma2Encoder.h b/lzma/CPP/7zip/Compress/Lzma2Encoder.h
new file mode 100644
index 0000000..fc43702
--- /dev/null
+++ b/lzma/CPP/7zip/Compress/Lzma2Encoder.h
@@ -0,0 +1,36 @@
+// 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 CMyUnknownImp
+{
+ CLzma2EncHandle _encoder;
+public:
+ MY_UNKNOWN_IMP2(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();
+ virtual ~CEncoder();
+};
+
+}}
+
+#endif
diff --git a/lzma/CPP/7zip/Compress/Lzma2Register.cpp b/lzma/CPP/7zip/Compress/Lzma2Register.cpp
new file mode 100644
index 0000000..28430b4
--- /dev/null
+++ b/lzma/CPP/7zip/Compress/Lzma2Register.cpp
@@ -0,0 +1,20 @@
+// Lzma2Register.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/RegisterCodec.h"
+
+#include "Lzma2Decoder.h"
+
+static void *CreateCodec() { return (void *)(ICompressCoder *)(new NCompress::NLzma2::CDecoder); }
+#ifndef EXTRACT_ONLY
+#include "Lzma2Encoder.h"
+static void *CreateCodecOut() { return (void *)(ICompressCoder *)(new NCompress::NLzma2::CEncoder); }
+#else
+#define CreateCodecOut 0
+#endif
+
+static CCodecInfo g_CodecInfo =
+ { CreateCodec, CreateCodecOut, 0x21, L"LZMA2", 1, false };
+
+REGISTER_CODEC(LZMA2)
diff --git a/lzma/CPP/7zip/Compress/LzmaDecoder.cpp b/lzma/CPP/7zip/Compress/LzmaDecoder.cpp
new file mode 100644
index 0000000..4ffb750
--- /dev/null
+++ b/lzma/CPP/7zip/Compress/LzmaDecoder.cpp
@@ -0,0 +1,266 @@
+// 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(0), _propsWereSet(false), _outSizeDefined(false),
+ _inBufSize(1 << 20),
+ _outBufSize(1 << 22),
+ FinishStream(false),
+ NeedMoreInput(false)
+{
+ _inSizeProcessed = 0;
+ _inPos = _inSize = 0;
+ LzmaDec_Construct(&_state);
+}
+
+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 };
+
+CDecoder::~CDecoder()
+{
+ LzmaDec_Free(&_state, &g_Alloc);
+ MyFree(_inBuf);
+}
+
+STDMETHODIMP CDecoder::SetInBufSize(UInt32 , UInt32 size) { _inBufSize = size; return S_OK; }
+STDMETHODIMP CDecoder::SetOutBufSize(UInt32 , UInt32 size) { _outBufSize = size; return S_OK; }
+
+HRESULT CDecoder::CreateInputBuffer()
+{
+ if (_inBuf == 0 || _inBufSize != _inBufSizeAllocated)
+ {
+ MyFree(_inBuf);
+ _inBuf = (Byte *)MyAlloc(_inBufSize);
+ if (_inBuf == 0)
+ return E_OUTOFMEMORY;
+ _inBufSizeAllocated = _inBufSize;
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *prop, UInt32 size)
+{
+ RINOK(SResToHRESULT(LzmaDec_Allocate(&_state, prop, size, &g_Alloc)));
+ _propsWereSet = true;
+ return CreateInputBuffer();
+}
+
+void CDecoder::SetOutStreamSizeResume(const UInt64 *outSize)
+{
+ _outSizeDefined = (outSize != NULL);
+ if (_outSizeDefined)
+ _outSize = *outSize;
+ _outSizeProcessed = 0;
+ _wrPos = 0;
+ LzmaDec_Init(&_state);
+}
+
+STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)
+{
+ _inSizeProcessed = 0;
+ _inPos = _inSize = 0;
+ NeedMoreInput = false;
+ SetOutStreamSizeResume(outSize);
+ return S_OK;
+}
+
+HRESULT CDecoder::CodeSpec(ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress)
+{
+ if (_inBuf == 0 || !_propsWereSet)
+ return S_FALSE;
+
+ UInt64 startInProgress = _inSizeProcessed;
+
+ SizeT next = (_state.dicBufSize - _state.dicPos < _outBufSize) ? _state.dicBufSize : (_state.dicPos + _outBufSize);
+ for (;;)
+ {
+ if (_inPos == _inSize)
+ {
+ _inPos = _inSize = 0;
+ RINOK(inStream->Read(_inBuf, _inBufSizeAllocated, &_inSize));
+ }
+
+ SizeT dicPos = _state.dicPos;
+ SizeT curSize = next - dicPos;
+
+ ELzmaFinishMode finishMode = LZMA_FINISH_ANY;
+ if (_outSizeDefined)
+ {
+ const UInt64 rem = _outSize - _outSizeProcessed;
+ if (rem <= curSize)
+ {
+ curSize = (SizeT)rem;
+ if (FinishStream)
+ finishMode = LZMA_FINISH_END;
+ }
+ }
+
+ SizeT inSizeProcessed = _inSize - _inPos;
+ ELzmaStatus status;
+ SRes res = LzmaDec_DecodeToDic(&_state, dicPos + curSize, _inBuf + _inPos, &inSizeProcessed, finishMode, &status);
+
+ _inPos += (UInt32)inSizeProcessed;
+ _inSizeProcessed += inSizeProcessed;
+ SizeT outSizeProcessed = _state.dicPos - dicPos;
+ _outSizeProcessed += outSizeProcessed;
+
+ bool finished = (inSizeProcessed == 0 && outSizeProcessed == 0);
+ bool stopDecoding = (_outSizeDefined && _outSizeProcessed >= _outSize);
+
+ if (res != 0 || _state.dicPos == next || finished || stopDecoding)
+ {
+ HRESULT res2 = WriteStream(outStream, _state.dic + _wrPos, _state.dicPos - _wrPos);
+
+ _wrPos = _state.dicPos;
+ if (_state.dicPos == _state.dicBufSize)
+ {
+ _state.dicPos = 0;
+ _wrPos = 0;
+ }
+ next = (_state.dicBufSize - _state.dicPos < _outBufSize) ? _state.dicBufSize : (_state.dicPos + _outBufSize);
+
+ if (res != 0)
+ return S_FALSE;
+ RINOK(res2);
+ if (stopDecoding)
+ {
+ if (status == LZMA_STATUS_NEEDS_MORE_INPUT)
+ NeedMoreInput = true;
+ if (FinishStream &&
+ status != LZMA_STATUS_FINISHED_WITH_MARK &&
+ status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK)
+ return S_FALSE;
+ return S_OK;
+ }
+ if (finished)
+ {
+ if (status == LZMA_STATUS_NEEDS_MORE_INPUT)
+ NeedMoreInput = true;
+ return (status == LZMA_STATUS_FINISHED_WITH_MARK ? S_OK : S_FALSE);
+ }
+ }
+ if (progress)
+ {
+ UInt64 inSize = _inSizeProcessed - startInProgress;
+ RINOK(progress->SetRatioInfo(&inSize, &_outSizeProcessed));
+ }
+ }
+}
+
+STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ if (_inBuf == 0)
+ return E_INVALIDARG;
+ SetOutStreamSize(outSize);
+ return CodeSpec(inStream, outStream, progress);
+}
+
+#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;
+ do
+ {
+ if (_inPos == _inSize)
+ {
+ _inPos = _inSize = 0;
+ RINOK(_inStream->Read(_inBuf, _inBufSizeAllocated, &_inSize));
+ }
+ {
+ SizeT inProcessed = _inSize - _inPos;
+
+ if (_outSizeDefined)
+ {
+ const UInt64 rem = _outSize - _outSizeProcessed;
+ if (rem < size)
+ size = (UInt32)rem;
+ }
+
+ SizeT outProcessed = size;
+ ELzmaStatus status;
+ SRes res = LzmaDec_DecodeToBuf(&_state, (Byte *)data, &outProcessed,
+ _inBuf + _inPos, &inProcessed, LZMA_FINISH_ANY, &status);
+ _inPos += (UInt32)inProcessed;
+ _inSizeProcessed += inProcessed;
+ _outSizeProcessed += outProcessed;
+ size -= (UInt32)outProcessed;
+ data = (Byte *)data + outProcessed;
+ if (processedSize)
+ *processedSize += (UInt32)outProcessed;
+ RINOK(SResToHRESULT(res));
+ if (inProcessed == 0 && outProcessed == 0)
+ return S_OK;
+ }
+ }
+ while (size != 0);
+ return S_OK;
+}
+
+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;
+ while (size > 0)
+ {
+ if (_inPos == _inSize)
+ {
+ _inPos = _inSize = 0;
+ RINOK(_inStream->Read(_inBuf, _inBufSizeAllocated, &_inSize));
+ if (_inSize == 0)
+ break;
+ }
+ {
+ UInt32 curSize = _inSize - _inPos;
+ if (curSize > size)
+ curSize = size;
+ memcpy(data, _inBuf + _inPos, curSize);
+ _inPos += curSize;
+ _inSizeProcessed += curSize;
+ size -= curSize;
+ data = (Byte *)data + curSize;
+ if (processedSize)
+ *processedSize += curSize;
+ }
+ }
+ return S_OK;
+}
+
+#endif
+
+}}
diff --git a/lzma/CPP/7zip/Compress/LzmaDecoder.h b/lzma/CPP/7zip/Compress/LzmaDecoder.h
new file mode 100644
index 0000000..191fbf9
--- /dev/null
+++ b/lzma/CPP/7zip/Compress/LzmaDecoder.h
@@ -0,0 +1,88 @@
+// LzmaDecoder.h
+
+#ifndef __LZMA_DECODER_H
+#define __LZMA_DECODER_H
+
+#include "../../../C/LzmaDec.h"
+
+#include "../../Common/MyCom.h"
+#include "../ICoder.h"
+
+namespace NCompress {
+namespace NLzma {
+
+class CDecoder:
+ public ICompressCoder,
+ public ICompressSetDecoderProperties2,
+ public ICompressSetBufSize,
+ #ifndef NO_READ_FROM_CODER
+ public ICompressSetInStream,
+ public ICompressSetOutStreamSize,
+ public ISequentialInStream,
+ #endif
+ public CMyUnknownImp
+{
+ CMyComPtr<ISequentialInStream> _inStream;
+ Byte *_inBuf;
+ UInt32 _inPos;
+ UInt32 _inSize;
+ CLzmaDec _state;
+ bool _propsWereSet;
+ bool _outSizeDefined;
+ UInt64 _outSize;
+ UInt64 _inSizeProcessed;
+ UInt64 _outSizeProcessed;
+
+ UInt32 _inBufSizeAllocated;
+ UInt32 _inBufSize;
+ UInt32 _outBufSize;
+ SizeT _wrPos;
+
+ 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(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(SetOutStreamSize)(const UInt64 *outSize);
+ STDMETHOD(SetInBufSize)(UInt32 streamIndex, UInt32 size);
+ STDMETHOD(SetOutBufSize)(UInt32 streamIndex, UInt32 size);
+
+ #ifndef NO_READ_FROM_CODER
+
+ 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);
+ UInt64 GetInputProcessedSize() const { return _inSizeProcessed; }
+
+ #endif
+
+ bool FinishStream; // set it before decoding, if you need to decode full LZMA stream
+
+ bool NeedMoreInput; // it's set by decoder, if it needs more input data to decode stream
+
+ CDecoder();
+ virtual ~CDecoder();
+
+ UInt64 GetOutputProcessedSize() const { return _outSizeProcessed; }
+};
+
+}}
+
+#endif
diff --git a/lzma/CPP/7zip/Compress/LzmaEncoder.cpp b/lzma/CPP/7zip/Compress/LzmaEncoder.cpp
new file mode 100644
index 0000000..e6feb79
--- /dev/null
+++ b/lzma/CPP/7zip/Compress/LzmaEncoder.cpp
@@ -0,0 +1,161 @@
+// LzmaEncoder.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+
+#include "../Common/CWrappers.h"
+#include "../Common/StreamUtils.h"
+
+#include "LzmaEncoder.h"
+
+namespace NCompress {
+namespace NLzma {
+
+static void *SzBigAlloc(void *, size_t size) { return BigAlloc(size); }
+static void SzBigFree(void *, void *address) { BigFree(address); }
+static ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree };
+
+static void *SzAlloc(void *, size_t size) { return MyAlloc(size); }
+static void SzFree(void *, void *address) { MyFree(address); }
+static ISzAlloc g_Alloc = { SzAlloc, SzFree };
+
+CEncoder::CEncoder()
+{
+ _encoder = 0;
+ _encoder = LzmaEnc_Create(&g_Alloc);
+ if (_encoder == 0)
+ throw 1;
+}
+
+CEncoder::~CEncoder()
+{
+ if (_encoder != 0)
+ LzmaEnc_Destroy(_encoder, &g_Alloc, &g_BigAlloc);
+}
+
+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;
+ c = GetUpperChar(*s++);
+ if (c != L'\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;
+ 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::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);
+}
+
+STDMETHODIMP CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
+{
+ CSeqInStreamWrap inWrap(inStream);
+ CSeqOutStreamWrap outWrap(outStream);
+ CCompressProgressWrap progressWrap(progress);
+
+ SRes res = LzmaEnc_Encode(_encoder, &outWrap.p, &inWrap.p, progress ? &progressWrap.p : NULL, &g_Alloc, &g_BigAlloc);
+ _inputProcessed = inWrap.Processed;
+ if (res == SZ_ERROR_READ && inWrap.Res != S_OK)
+ return inWrap.Res;
+ if (res == SZ_ERROR_WRITE && outWrap.Res != S_OK)
+ return outWrap.Res;
+ if (res == SZ_ERROR_PROGRESS && progressWrap.Res != S_OK)
+ return progressWrap.Res;
+ return SResToHRESULT(res);
+}
+
+}}
diff --git a/lzma/CPP/7zip/Compress/LzmaEncoder.h b/lzma/CPP/7zip/Compress/LzmaEncoder.h
new file mode 100644
index 0000000..3db30a9
--- /dev/null
+++ b/lzma/CPP/7zip/Compress/LzmaEncoder.h
@@ -0,0 +1,38 @@
+// 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 CMyUnknownImp
+{
+ CLzmaEncHandle _encoder;
+ UInt64 _inputProcessed;
+public:
+ MY_UNKNOWN_IMP2(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();
+ virtual ~CEncoder();
+ UInt64 GetInputProcessedSize() const { return _inputProcessed; }
+};
+
+}}
+
+#endif
diff --git a/lzma/CPP/7zip/Compress/LzmaRegister.cpp b/lzma/CPP/7zip/Compress/LzmaRegister.cpp
new file mode 100644
index 0000000..9c67eaf
--- /dev/null
+++ b/lzma/CPP/7zip/Compress/LzmaRegister.cpp
@@ -0,0 +1,20 @@
+// LzmaRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/RegisterCodec.h"
+
+#include "LzmaDecoder.h"
+
+static void *CreateCodec() { return (void *)(ICompressCoder *)(new NCompress::NLzma::CDecoder); }
+#ifndef EXTRACT_ONLY
+#include "LzmaEncoder.h"
+static void *CreateCodecOut() { return (void *)(ICompressCoder *)(new NCompress::NLzma::CEncoder); }
+#else
+#define CreateCodecOut 0
+#endif
+
+static CCodecInfo g_CodecInfo =
+ { CreateCodec, CreateCodecOut, 0x030101, L"LZMA", 1, false };
+
+REGISTER_CODEC(LZMA)
diff --git a/lzma/CPP/7zip/Compress/PpmdDecoder.cpp b/lzma/CPP/7zip/Compress/PpmdDecoder.cpp
new file mode 100644
index 0000000..2373185
--- /dev/null
+++ b/lzma/CPP/7zip/Compress/PpmdDecoder.cpp
@@ -0,0 +1,167 @@
+// 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
+};
+
+static void *SzBigAlloc(void *, size_t size) { return BigAlloc(size); }
+static void SzBigFree(void *, void *address) { BigFree(address); }
+static ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree };
+
+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.p);
+ 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;
+}
+
+#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
+
+}}
diff --git a/lzma/CPP/7zip/Compress/PpmdDecoder.h b/lzma/CPP/7zip/Compress/PpmdDecoder.h
new file mode 100644
index 0000000..c61d1d0
--- /dev/null
+++ b/lzma/CPP/7zip/Compress/PpmdDecoder.h
@@ -0,0 +1,78 @@
+// 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,
+ #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;
+ MY_UNKNOWN_IMP4(
+ ICompressSetDecoderProperties2,
+ ICompressSetInStream,
+ ICompressSetOutStreamSize,
+ ISequentialInStream)
+ #else
+ MY_UNKNOWN_IMP1(
+ ICompressSetDecoderProperties2)
+ #endif
+
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+ STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
+ 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.p;
+ Ppmd7_Construct(&_ppmd);
+ }
+
+ ~CDecoder();
+};
+
+}}
+
+#endif
diff --git a/lzma/CPP/7zip/Compress/PpmdEncoder.cpp b/lzma/CPP/7zip/Compress/PpmdEncoder.cpp
new file mode 100644
index 0000000..e232077
--- /dev/null
+++ b/lzma/CPP/7zip/Compress/PpmdEncoder.cpp
@@ -0,0 +1,156 @@
+// 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 void *SzBigAlloc(void *, size_t size) { return BigAlloc(size); }
+static void SzBigFree(void *, void *address) { BigFree(address); }
+static ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree };
+
+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[level];
+}
+
+CEncoder::CEncoder():
+ _inBuf(NULL)
+{
+ _props.Normalize(-1);
+ _rangeEnc.Stream = &_outStream.p;
+ 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));
+ }
+ }
+}
+
+}}
diff --git a/lzma/CPP/7zip/Compress/PpmdEncoder.h b/lzma/CPP/7zip/Compress/PpmdEncoder.h
new file mode 100644
index 0000000..66ce437
--- /dev/null
+++ b/lzma/CPP/7zip/Compress/PpmdEncoder.h
@@ -0,0 +1,57 @@
+// 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_IMP2(
+ 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
diff --git a/lzma/CPP/7zip/Compress/PpmdRegister.cpp b/lzma/CPP/7zip/Compress/PpmdRegister.cpp
new file mode 100644
index 0000000..e2fd007
--- /dev/null
+++ b/lzma/CPP/7zip/Compress/PpmdRegister.cpp
@@ -0,0 +1,21 @@
+// PpmdRegister.cpp
+// 2009-05-30 : Igor Pavlov : Public domain
+
+#include "StdAfx.h"
+
+#include "../Common/RegisterCodec.h"
+
+#include "PpmdDecoder.h"
+
+static void *CreateCodec() { return (void *)(ICompressCoder *)(new NCompress::NPpmd::CDecoder); }
+#ifndef EXTRACT_ONLY
+#include "PpmdEncoder.h"
+static void *CreateCodecOut() { return (void *)(ICompressCoder *)(new NCompress::NPpmd::CEncoder); }
+#else
+#define CreateCodecOut 0
+#endif
+
+static CCodecInfo g_CodecInfo =
+ { CreateCodec, CreateCodecOut, 0x030401, L"PPMD", 1, false };
+
+REGISTER_CODEC(PPMD)
diff --git a/lzma/CPP/7zip/Compress/RangeCoder.h b/lzma/CPP/7zip/Compress/RangeCoder.h
new file mode 100644
index 0000000..2c254a5
--- /dev/null
+++ b/lzma/CPP/7zip/Compress/RangeCoder.h
@@ -0,0 +1,201 @@
+// Compress/RangeCoder.h
+// 2013-01-10 : Igor Pavlov : Public domain
+
+#ifndef __COMPRESS_RANGE_CODER_H
+#define __COMPRESS_RANGE_CODER_H
+
+#include "../Common/InBuffer.h"
+#include "../Common/OutBuffer.h"
+
+namespace NCompress {
+namespace NRangeCoder {
+
+const unsigned kNumTopBits = 24;
+const UInt32 kTopValue = (1 << kNumTopBits);
+
+class CEncoder
+{
+ UInt32 _cacheSize;
+ Byte _cache;
+public:
+ UInt64 Low;
+ UInt32 Range;
+ COutBuffer Stream;
+ bool Create(UInt32 bufSize) { return Stream.Create(bufSize); }
+
+ void SetStream(ISequentialOutStream *stream) { Stream.SetStream(stream); }
+ void Init()
+ {
+ Stream.Init();
+ Low = 0;
+ Range = 0xFFFFFFFF;
+ _cacheSize = 1;
+ _cache = 0;
+ }
+
+ void FlushData()
+ {
+ // Low += 1;
+ for (int i = 0; i < 5; i++)
+ ShiftLow();
+ }
+
+ HRESULT FlushStream() { return Stream.Flush(); }
+
+ void Encode(UInt32 start, UInt32 size, UInt32 total)
+ {
+ Low += start * (Range /= total);
+ Range *= size;
+ while (Range < kTopValue)
+ {
+ Range <<= 8;
+ ShiftLow();
+ }
+ }
+
+ void ShiftLow()
+ {
+ if ((UInt32)Low < (UInt32)0xFF000000 || (unsigned)(Low >> 32) != 0)
+ {
+ Byte temp = _cache;
+ do
+ {
+ Stream.WriteByte((Byte)(temp + (Byte)(Low >> 32)));
+ temp = 0xFF;
+ }
+ while (--_cacheSize != 0);
+ _cache = (Byte)((UInt32)Low >> 24);
+ }
+ _cacheSize++;
+ Low = (UInt32)Low << 8;
+ }
+
+ void EncodeDirectBits(UInt32 value, int numBits)
+ {
+ for (numBits--; numBits >= 0; numBits--)
+ {
+ Range >>= 1;
+ Low += Range & (0 - ((value >> numBits) & 1));
+ if (Range < kTopValue)
+ {
+ Range <<= 8;
+ ShiftLow();
+ }
+ }
+ }
+
+ void EncodeBit(UInt32 size0, UInt32 numTotalBits, UInt32 symbol)
+ {
+ UInt32 newBound = (Range >> numTotalBits) * size0;
+ if (symbol == 0)
+ Range = newBound;
+ else
+ {
+ Low += newBound;
+ Range -= newBound;
+ }
+ while (Range < kTopValue)
+ {
+ Range <<= 8;
+ ShiftLow();
+ }
+ }
+
+ UInt64 GetProcessedSize() { return Stream.GetProcessedSize() + _cacheSize + 4; }
+};
+
+class CDecoder
+{
+public:
+ CInBuffer Stream;
+ UInt32 Range;
+ UInt32 Code;
+ bool Create(UInt32 bufSize) { return Stream.Create(bufSize); }
+
+ void Normalize()
+ {
+ while (Range < kTopValue)
+ {
+ Code = (Code << 8) | Stream.ReadByte();
+ Range <<= 8;
+ }
+ }
+
+ void SetStream(ISequentialInStream *stream) { Stream.SetStream(stream); }
+ void Init()
+ {
+ Stream.Init();
+ Code = 0;
+ Range = 0xFFFFFFFF;
+ for (int i = 0; i < 5; i++)
+ Code = (Code << 8) | Stream.ReadByte();
+ }
+
+ UInt32 GetThreshold(UInt32 total)
+ {
+ return (Code) / (Range /= total);
+ }
+
+ void Decode(UInt32 start, UInt32 size)
+ {
+ Code -= start * Range;
+ Range *= size;
+ Normalize();
+ }
+
+ UInt32 DecodeDirectBits(int numTotalBits)
+ {
+ UInt32 range = Range;
+ UInt32 code = Code;
+ UInt32 result = 0;
+ for (int i = numTotalBits; i != 0; i--)
+ {
+ range >>= 1;
+ /*
+ result <<= 1;
+ if (code >= range)
+ {
+ code -= range;
+ result |= 1;
+ }
+ */
+ UInt32 t = (code - range) >> 31;
+ code -= range & (t - 1);
+ result = (result << 1) | (1 - t);
+
+ if (range < kTopValue)
+ {
+ code = (code << 8) | Stream.ReadByte();
+ range <<= 8;
+ }
+ }
+ Range = range;
+ Code = code;
+ return result;
+ }
+
+ UInt32 DecodeBit(UInt32 size0, UInt32 numTotalBits)
+ {
+ UInt32 newBound = (Range >> numTotalBits) * size0;
+ UInt32 symbol;
+ if (Code < newBound)
+ {
+ symbol = 0;
+ Range = newBound;
+ }
+ else
+ {
+ symbol = 1;
+ Code -= newBound;
+ Range -= newBound;
+ }
+ Normalize();
+ return symbol;
+ }
+
+ UInt64 GetProcessedSize() { return Stream.GetProcessedSize(); }
+};
+
+}}
+
+#endif
diff --git a/lzma/CPP/7zip/Compress/RangeCoderBit.h b/lzma/CPP/7zip/Compress/RangeCoderBit.h
new file mode 100644
index 0000000..927a8dd
--- /dev/null
+++ b/lzma/CPP/7zip/Compress/RangeCoderBit.h
@@ -0,0 +1,114 @@
+// Compress/RangeCoderBit.h
+// 2013-01-10 : Igor Pavlov : Public domain
+
+#ifndef __COMPRESS_RANGE_CODER_BIT_H
+#define __COMPRESS_RANGE_CODER_BIT_H
+
+#include "RangeCoder.h"
+
+namespace NCompress {
+namespace NRangeCoder {
+
+const unsigned kNumBitModelTotalBits = 11;
+const UInt32 kBitModelTotal = (1 << kNumBitModelTotalBits);
+
+const unsigned kNumMoveReducingBits = 4;
+
+const unsigned kNumBitPriceShiftBits = 4;
+const UInt32 kBitPrice = 1 << kNumBitPriceShiftBits;
+
+extern UInt32 ProbPrices[kBitModelTotal >> kNumMoveReducingBits];
+
+template <unsigned numMoveBits>
+class CBitModel
+{
+public:
+ UInt32 Prob;
+ void UpdateModel(UInt32 symbol)
+ {
+ /*
+ Prob -= (Prob + ((symbol - 1) & ((1 << numMoveBits) - 1))) >> numMoveBits;
+ Prob += (1 - symbol) << (kNumBitModelTotalBits - numMoveBits);
+ */
+ if (symbol == 0)
+ Prob += (kBitModelTotal - Prob) >> numMoveBits;
+ else
+ Prob -= (Prob) >> numMoveBits;
+ }
+public:
+ void Init() { Prob = kBitModelTotal / 2; }
+};
+
+template <unsigned numMoveBits>
+class CBitEncoder: public CBitModel<numMoveBits>
+{
+public:
+ void Encode(CEncoder *encoder, UInt32 symbol)
+ {
+ /*
+ encoder->EncodeBit(this->Prob, kNumBitModelTotalBits, symbol);
+ this->UpdateModel(symbol);
+ */
+ UInt32 newBound = (encoder->Range >> kNumBitModelTotalBits) * this->Prob;
+ if (symbol == 0)
+ {
+ encoder->Range = newBound;
+ this->Prob += (kBitModelTotal - this->Prob) >> numMoveBits;
+ }
+ else
+ {
+ encoder->Low += newBound;
+ encoder->Range -= newBound;
+ this->Prob -= (this->Prob) >> numMoveBits;
+ }
+ if (encoder->Range < kTopValue)
+ {
+ encoder->Range <<= 8;
+ encoder->ShiftLow();
+ }
+ }
+ UInt32 GetPrice(UInt32 symbol) const
+ {
+ return ProbPrices[(this->Prob ^ ((-(int)(Int32)symbol)) & (kBitModelTotal - 1)) >> kNumMoveReducingBits];
+ }
+ UInt32 GetPrice0() const { return ProbPrices[this->Prob >> kNumMoveReducingBits]; }
+ UInt32 GetPrice1() const { return ProbPrices[(this->Prob ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits]; }
+};
+
+
+template <unsigned numMoveBits>
+class CBitDecoder: public CBitModel<numMoveBits>
+{
+public:
+ UInt32 Decode(CDecoder *decoder)
+ {
+ UInt32 newBound = (decoder->Range >> kNumBitModelTotalBits) * this->Prob;
+ if (decoder->Code < newBound)
+ {
+ decoder->Range = newBound;
+ this->Prob += (kBitModelTotal - this->Prob) >> numMoveBits;
+ if (decoder->Range < kTopValue)
+ {
+ decoder->Code = (decoder->Code << 8) | decoder->Stream.ReadByte();
+ decoder->Range <<= 8;
+ }
+ return 0;
+ }
+ else
+ {
+ decoder->Range -= newBound;
+ decoder->Code -= newBound;
+ this->Prob -= (this->Prob) >> numMoveBits;
+ if (decoder->Range < kTopValue)
+ {
+ decoder->Code = (decoder->Code << 8) | decoder->Stream.ReadByte();
+ decoder->Range <<= 8;
+ }
+ return 1;
+ }
+ }
+};
+
+}}
+
+#endif
diff --git a/lzma/CPP/7zip/Compress/StdAfx.h b/lzma/CPP/7zip/Compress/StdAfx.h
new file mode 100644
index 0000000..42a088f
--- /dev/null
+++ b/lzma/CPP/7zip/Compress/StdAfx.h
@@ -0,0 +1,8 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "../../Common/Common.h"
+
+#endif
diff --git a/lzma/CPP/7zip/Crc.mak b/lzma/CPP/7zip/Crc.mak
new file mode 100644
index 0000000..444f8fe
--- /dev/null
+++ b/lzma/CPP/7zip/Crc.mak
@@ -0,0 +1,8 @@
+C_OBJS = $(C_OBJS) \
+ $O\7zCrc.obj
+!IF "$(CPU)" == "IA64" || "$(CPU)" == "MIPS"
+C_OBJS = $(C_OBJS) \
+!ELSE
+ASM_OBJS = $(ASM_OBJS) \
+!ENDIF
+ $O\7zCrcOpt.obj
diff --git a/lzma/CPP/7zip/Crc64.mak b/lzma/CPP/7zip/Crc64.mak
new file mode 100644
index 0000000..08e56f9
--- /dev/null
+++ b/lzma/CPP/7zip/Crc64.mak
@@ -0,0 +1,8 @@
+C_OBJS = $(C_OBJS) \
+ $O\XzCrc64.obj
+!IF "$(CPU)" == "IA64" || "$(CPU)" == "MIPS" || "$(CPU)" == "ARM"
+C_OBJS = $(C_OBJS) \
+!ELSE
+ASM_OBJS = $(ASM_OBJS) \
+!ENDIF
+ $O\XzCrc64Opt.obj
diff --git a/lzma/CPP/7zip/Crypto/7zAes.cpp b/lzma/CPP/7zip/Crypto/7zAes.cpp
new file mode 100644
index 0000000..70c8473
--- /dev/null
+++ b/lzma/CPP/7zip/Crypto/7zAes.cpp
@@ -0,0 +1,240 @@
+// 7zAes.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Sha256.h"
+
+#include "../../Windows/Synchronization.h"
+
+#include "../Common/StreamObjects.h"
+#include "../Common/StreamUtils.h"
+
+#include "7zAes.h"
+#include "MyAes.h"
+
+#ifndef EXTRACT_ONLY
+#include "RandGen.h"
+#endif
+
+using namespace NWindows;
+
+namespace NCrypto {
+namespace NSevenZ {
+
+bool CKeyInfo::IsEqualTo(const CKeyInfo &a) const
+{
+ if (SaltSize != a.SaltSize || NumCyclesPower != a.NumCyclesPower)
+ return false;
+ for (UInt32 i = 0; i < SaltSize; i++)
+ if (Salt[i] != a.Salt[i])
+ return false;
+ return (Password == a.Password);
+}
+
+void CKeyInfo::CalculateDigest()
+{
+ if (NumCyclesPower == 0x3F)
+ {
+ UInt32 pos;
+ for (pos = 0; pos < SaltSize; pos++)
+ Key[pos] = Salt[pos];
+ for (UInt32 i = 0; i < Password.Size() && pos < kKeySize; i++)
+ Key[pos++] = Password[i];
+ for (; pos < kKeySize; pos++)
+ Key[pos] = 0;
+ }
+ else
+ {
+ CSha256 sha;
+ Sha256_Init(&sha);
+ const UInt64 numRounds = (UInt64)1 << NumCyclesPower;
+ Byte temp[8] = { 0,0,0,0,0,0,0,0 };
+ for (UInt64 round = 0; round < numRounds; round++)
+ {
+ Sha256_Update(&sha, Salt, (size_t)SaltSize);
+ Sha256_Update(&sha, Password, Password.Size());
+ Sha256_Update(&sha, temp, 8);
+ for (int i = 0; i < 8; i++)
+ if (++(temp[i]) != 0)
+ break;
+ }
+ Sha256_Final(&sha, Key);
+ }
+}
+
+bool CKeyInfoCache::Find(CKeyInfo &key)
+{
+ FOR_VECTOR (i, Keys)
+ {
+ const CKeyInfo &cached = Keys[i];
+ if (key.IsEqualTo(cached))
+ {
+ for (int j = 0; j < kKeySize; j++)
+ key.Key[j] = cached.Key[j];
+ if (i != 0)
+ Keys.MoveToFront(i);
+ return true;
+ }
+ }
+ return false;
+}
+
+void CKeyInfoCache::Add(CKeyInfo &key)
+{
+ if (Find(key))
+ return;
+ if (Keys.Size() >= Size)
+ Keys.DeleteBack();
+ Keys.Insert(0, key);
+}
+
+static CKeyInfoCache g_GlobalKeyCache(32);
+static NSynchronization::CCriticalSection g_GlobalKeyCacheCriticalSection;
+
+CBase::CBase():
+ _cachedKeys(16),
+ _ivSize(0)
+{
+ for (int i = 0; i < sizeof(_iv); i++)
+ _iv[i] = 0;
+}
+
+void CBase::CalculateDigest()
+{
+ NSynchronization::CCriticalSectionLock lock(g_GlobalKeyCacheCriticalSection);
+ if (_cachedKeys.Find(_key))
+ g_GlobalKeyCache.Add(_key);
+ else
+ {
+ if (!g_GlobalKeyCache.Find(_key))
+ {
+ _key.CalculateDigest();
+ g_GlobalKeyCache.Add(_key);
+ }
+ _cachedKeys.Add(_key);
+ }
+}
+
+#ifndef EXTRACT_ONLY
+
+/*
+STDMETHODIMP CEncoder::ResetSalt()
+{
+ _key.SaltSize = 4;
+ g_RandomGenerator.Generate(_key.Salt, _key.SaltSize);
+ return S_OK;
+}
+*/
+
+STDMETHODIMP CEncoder::ResetInitVector()
+{
+ _ivSize = 8;
+ g_RandomGenerator.Generate(_iv, (unsigned)_ivSize);
+ return S_OK;
+}
+
+STDMETHODIMP CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)
+{
+ // _key.Init();
+ for (UInt32 i = _ivSize; i < sizeof(_iv); i++)
+ _iv[i] = 0;
+
+ UInt32 ivSize = _ivSize;
+
+ // _key.NumCyclesPower = 0x3F;
+ _key.NumCyclesPower = 19;
+
+ Byte firstByte = (Byte)(_key.NumCyclesPower |
+ (((_key.SaltSize == 0) ? 0 : 1) << 7) |
+ (((ivSize == 0) ? 0 : 1) << 6));
+ RINOK(outStream->Write(&firstByte, 1, NULL));
+ if (_key.SaltSize == 0 && ivSize == 0)
+ return S_OK;
+ Byte saltSizeSpec = (Byte)((_key.SaltSize == 0) ? 0 : (_key.SaltSize - 1));
+ Byte ivSizeSpec = (Byte)((ivSize == 0) ? 0 : (ivSize - 1));
+ Byte secondByte = (Byte)(((saltSizeSpec) << 4) | ivSizeSpec);
+ RINOK(outStream->Write(&secondByte, 1, NULL));
+ if (_key.SaltSize > 0)
+ {
+ RINOK(WriteStream(outStream, _key.Salt, _key.SaltSize));
+ }
+ if (ivSize > 0)
+ {
+ RINOK(WriteStream(outStream, _iv, ivSize));
+ }
+ return S_OK;
+}
+
+HRESULT CEncoder::CreateFilter()
+{
+ _aesFilter = new CAesCbcEncoder(kKeySize);
+ return S_OK;
+}
+
+#endif
+
+STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)
+{
+ _key.Init();
+ UInt32 i;
+ for (i = 0; i < sizeof(_iv); i++)
+ _iv[i] = 0;
+ if (size == 0)
+ return S_OK;
+ UInt32 pos = 0;
+ Byte firstByte = data[pos++];
+
+ _key.NumCyclesPower = firstByte & 0x3F;
+ if ((firstByte & 0xC0) == 0)
+ return S_OK;
+ _key.SaltSize = (firstByte >> 7) & 1;
+ UInt32 ivSize = (firstByte >> 6) & 1;
+
+ if (pos >= size)
+ return E_INVALIDARG;
+ Byte secondByte = data[pos++];
+
+ _key.SaltSize += (secondByte >> 4);
+ ivSize += (secondByte & 0x0F);
+
+ if (pos + _key.SaltSize + ivSize > size)
+ return E_INVALIDARG;
+ for (i = 0; i < _key.SaltSize; i++)
+ _key.Salt[i] = data[pos++];
+ for (i = 0; i < ivSize; i++)
+ _iv[i] = data[pos++];
+ return (_key.NumCyclesPower <= 24) ? S_OK : E_NOTIMPL;
+}
+
+STDMETHODIMP CBaseCoder::CryptoSetPassword(const Byte *data, UInt32 size)
+{
+ _key.Password.CopyFrom(data, (size_t)size);
+ return S_OK;
+}
+
+STDMETHODIMP CBaseCoder::Init()
+{
+ CalculateDigest();
+ if (_aesFilter == 0)
+ {
+ RINOK(CreateFilter());
+ }
+ CMyComPtr<ICryptoProperties> cp;
+ RINOK(_aesFilter.QueryInterface(IID_ICryptoProperties, &cp));
+ RINOK(cp->SetKey(_key.Key, sizeof(_key.Key)));
+ RINOK(cp->SetInitVector(_iv, sizeof(_iv)));
+ return _aesFilter->Init();
+}
+
+STDMETHODIMP_(UInt32) CBaseCoder::Filter(Byte *data, UInt32 size)
+{
+ return _aesFilter->Filter(data, size);
+}
+
+HRESULT CDecoder::CreateFilter()
+{
+ _aesFilter = new CAesCbcDecoder(kKeySize);
+ return S_OK;
+}
+
+}}
diff --git a/lzma/CPP/7zip/Crypto/7zAes.h b/lzma/CPP/7zip/Crypto/7zAes.h
new file mode 100644
index 0000000..baa1258
--- /dev/null
+++ b/lzma/CPP/7zip/Crypto/7zAes.h
@@ -0,0 +1,117 @@
+// 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 NSevenZ {
+
+const int kKeySize = 32;
+
+class CKeyInfo
+{
+public:
+ int NumCyclesPower;
+ UInt32 SaltSize;
+ Byte Salt[16];
+ CByteBuffer Password;
+ Byte Key[kKeySize];
+
+ bool IsEqualTo(const CKeyInfo &a) const;
+ void CalculateDigest();
+
+ CKeyInfo() { Init(); }
+ void Init()
+ {
+ NumCyclesPower = 0;
+ SaltSize = 0;
+ for (int i = 0; i < sizeof(Salt); i++)
+ Salt[i] = 0;
+ }
+};
+
+class CKeyInfoCache
+{
+ unsigned Size;
+ CObjectVector<CKeyInfo> Keys;
+public:
+ CKeyInfoCache(unsigned size): Size(size) {}
+ bool Find(CKeyInfo &key);
+ // HRESULT Calculate(CKeyInfo &key);
+ void Add(CKeyInfo &key);
+};
+
+class CBase
+{
+ CKeyInfoCache _cachedKeys;
+protected:
+ CKeyInfo _key;
+ Byte _iv[16];
+ UInt32 _ivSize;
+ void CalculateDigest();
+ CBase();
+};
+
+class CBaseCoder:
+ public ICompressFilter,
+ public ICryptoSetPassword,
+ public CMyUnknownImp,
+ public CBase
+{
+protected:
+ CMyComPtr<ICompressFilter> _aesFilter;
+
+ virtual HRESULT CreateFilter() = 0;
+ #ifndef CRYPTO_AES
+ HRESULT CreateFilterFromDLL(REFCLSID clsID);
+ #endif
+public:
+ STDMETHOD(Init)();
+ STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size);
+
+ STDMETHOD(CryptoSetPassword)(const Byte *data, UInt32 size);
+};
+
+#ifndef EXTRACT_ONLY
+
+class CEncoder:
+ public CBaseCoder,
+ public ICompressWriteCoderProperties,
+ // public ICryptoResetSalt,
+ public ICryptoResetInitVector
+{
+ virtual HRESULT CreateFilter();
+public:
+ MY_UNKNOWN_IMP3(
+ ICryptoSetPassword,
+ ICompressWriteCoderProperties,
+ // ICryptoResetSalt,
+ ICryptoResetInitVector)
+ STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStream);
+ // STDMETHOD(ResetSalt)();
+ STDMETHOD(ResetInitVector)();
+};
+#endif
+
+class CDecoder:
+ public CBaseCoder,
+ public ICompressSetDecoderProperties2
+{
+ virtual HRESULT CreateFilter();
+public:
+ MY_UNKNOWN_IMP2(
+ ICryptoSetPassword,
+ ICompressSetDecoderProperties2)
+ STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
+};
+
+}}
+
+#endif
diff --git a/lzma/CPP/7zip/Crypto/7zAesRegister.cpp b/lzma/CPP/7zip/Crypto/7zAesRegister.cpp
new file mode 100644
index 0000000..87f8ae9
--- /dev/null
+++ b/lzma/CPP/7zip/Crypto/7zAesRegister.cpp
@@ -0,0 +1,18 @@
+// 7zAesRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/RegisterCodec.h"
+#include "7zAes.h"
+
+static void *CreateCodec() { return (void *)(ICompressFilter *)(new NCrypto::NSevenZ::CDecoder()); }
+#ifndef EXTRACT_ONLY
+static void *CreateCodecOut() { return (void *)(ICompressFilter *)(new NCrypto::NSevenZ::CEncoder()); }
+#else
+#define CreateCodecOut 0
+#endif
+
+static CCodecInfo g_CodecInfo =
+ { CreateCodec, CreateCodecOut, 0x06F10701, L"7zAES", 1, true };
+
+REGISTER_CODEC(7zAES)
diff --git a/lzma/CPP/7zip/Crypto/MyAes.cpp b/lzma/CPP/7zip/Crypto/MyAes.cpp
new file mode 100644
index 0000000..1d399d7
--- /dev/null
+++ b/lzma/CPP/7zip/Crypto/MyAes.cpp
@@ -0,0 +1,112 @@
+// 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;
+}
+
+}
diff --git a/lzma/CPP/7zip/Crypto/MyAes.h b/lzma/CPP/7zip/Crypto/MyAes.h
new file mode 100644
index 0000000..71f3fa7
--- /dev/null
+++ b/lzma/CPP/7zip/Crypto/MyAes.h
@@ -0,0 +1,52 @@
+// 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);
+ MY_UNKNOWN_IMP2(ICryptoProperties, ICompressSetCoderProperties)
+ STDMETHOD(Init)();
+ STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size);
+ 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
diff --git a/lzma/CPP/7zip/Crypto/MyAesReg.cpp b/lzma/CPP/7zip/Crypto/MyAesReg.cpp
new file mode 100644
index 0000000..2815b1d
--- /dev/null
+++ b/lzma/CPP/7zip/Crypto/MyAesReg.cpp
@@ -0,0 +1,19 @@
+// MyAesReg.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/RegisterCodec.h"
+
+#include "MyAes.h"
+
+static void *CreateCodecCbc() { return (void *)(ICompressFilter *)(new NCrypto::CAesCbcDecoder(32)); }
+#ifndef EXTRACT_ONLY
+static void *CreateCodecCbcOut() { return (void *)(ICompressFilter *)(new NCrypto::CAesCbcEncoder(32)); }
+#else
+#define CreateCodecCbcOut 0
+#endif
+
+static CCodecInfo g_CodecInfo =
+ { CreateCodecCbc, CreateCodecCbcOut, 0x06F00181, L"AES256CBC", 1, true };
+REGISTER_CODEC(AES256CBC)
+
diff --git a/lzma/CPP/7zip/Crypto/RandGen.cpp b/lzma/CPP/7zip/Crypto/RandGen.cpp
new file mode 100644
index 0000000..983662a
--- /dev/null
+++ b/lzma/CPP/7zip/Crypto/RandGen.cpp
@@ -0,0 +1,115 @@
+// RandGen.cpp
+
+#include "StdAfx.h"
+
+#include "../../Windows/Synchronization.h"
+
+#include "RandGen.h"
+
+#ifndef _WIN32
+#include <unistd.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
+
+// This is not very good random number generator.
+// Please use it only for salt.
+// First generated data block depends from timer and processID.
+// Other generated data blocks depend from previous state
+// Maybe it's possible to restore original timer value from generated value.
+
+#define HASH_UPD(x) Sha256_Update(&hash, (const Byte *)&x, sizeof(x));
+
+void CRandomGenerator::Init()
+{
+ CSha256 hash;
+ Sha256_Init(&hash);
+
+ #ifdef _WIN32
+ DWORD w = ::GetCurrentProcessId();
+ HASH_UPD(w);
+ w = ::GetCurrentThreadId();
+ HASH_UPD(w);
+ #else
+ pid_t pid = getpid();
+ HASH_UPD(pid);
+ pid = getppid();
+ HASH_UPD(pid);
+ #endif
+
+ for (unsigned i = 0; i <
+ #ifdef _DEBUG
+ 2;
+ #else
+ 1000;
+ #endif
+ i++)
+ {
+ #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
+
+ DWORD tickCount = ::GetTickCount();
+ HASH_UPD(tickCount);
+
+ for (unsigned j = 0; j < 100; j++)
+ {
+ Sha256_Final(&hash, _buff);
+ Sha256_Init(&hash);
+ Sha256_Update(&hash, _buff, SHA256_DIGEST_SIZE);
+ }
+ }
+ Sha256_Final(&hash, _buff);
+ _needInit = false;
+}
+
+static NWindows::NSynchronization::CCriticalSection g_CriticalSection;
+
+void CRandomGenerator::Generate(Byte *data, unsigned size)
+{
+ g_CriticalSection.Enter();
+ 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];
+ }
+ g_CriticalSection.Leave();
+}
+
+CRandomGenerator g_RandomGenerator;
diff --git a/lzma/CPP/7zip/Crypto/RandGen.h b/lzma/CPP/7zip/Crypto/RandGen.h
new file mode 100644
index 0000000..ff44450
--- /dev/null
+++ b/lzma/CPP/7zip/Crypto/RandGen.h
@@ -0,0 +1,21 @@
+// RandGen.h
+
+#ifndef __CRYPTO_RAND_GEN_H
+#define __CRYPTO_RAND_GEN_H
+
+#include "../../../C/Sha256.h"
+
+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;
+
+#endif
diff --git a/lzma/CPP/7zip/Crypto/StdAfx.h b/lzma/CPP/7zip/Crypto/StdAfx.h
new file mode 100644
index 0000000..42a088f
--- /dev/null
+++ b/lzma/CPP/7zip/Crypto/StdAfx.h
@@ -0,0 +1,8 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "../../Common/Common.h"
+
+#endif
diff --git a/lzma/CPP/7zip/GuiCommon.rc b/lzma/CPP/7zip/GuiCommon.rc
new file mode 100644
index 0000000..c11017b
--- /dev/null
+++ b/lzma/CPP/7zip/GuiCommon.rc
@@ -0,0 +1,81 @@
+#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_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/lzma/CPP/7zip/Guid.txt b/lzma/CPP/7zip/Guid.txt
new file mode 100644
index 0000000..2b01644
--- /dev/null
+++ b/lzma/CPP/7zip/Guid.txt
@@ -0,0 +1,192 @@
+{23170F69-40C1-278A-0000-00yy00xx0000}
+
+00 IProgress.h
+
+ 05 IProgress
+
+01 IFolderArchive.h
+
+ // 05 IArchiveFolder // old
+ // 06 IInFolderArchive // old
+ 07 IFileExtractCallback.h::IFolderArchiveExtractCallback
+ // 0A IOutFolderArchive
+ 0B IFolderArchiveUpdateCallback
+ 0C Agent.h::IArchiveFolderInternal
+ 0D IArchiveFolder
+ 0E IInFolderArchive
+ 0F IOutFolderArchive
+ 20 IFileExtractCallback.h::IGetProp
+ 30 IFileExtractCallback.h::IFolderExtractToStreamCallback
+
+03 IStream.h
+
+ 01 ISequentialInStream
+ 02 ISequentialOutStream
+ 03 IInStream
+ 04 IOutStream
+ 06 IStreamGetSize
+ 07 IOutStreamFlush
+ 08 IStreamGetProps
+ 09 IStreamGetProps2
+
+
+04 ICoder.h
+
+ 04 ICompressProgressInfo
+ 05 ICompressCoder
+ 18 ICompressCoder2
+ 20 ICompressSetCoderProperties
+ 21 ICompressSetDecoderProperties //
+ 22 ICompressSetDecoderProperties2
+ 23 ICompressWriteCoderProperties
+ 24 ICompressGetInStreamProcessedSize
+ 25 ICompressSetCoderMt
+ 30 ICompressGetSubStreamSize
+ 31 ICompressSetInStream
+ 32 ICompressSetOutStream
+ 33 ICompressSetInStreamSize
+ 34 ICompressSetOutStreamSize
+ 35 ICompressSetBufSize
+ 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
+ 30 IArchiveOpenVolumeCallback
+ 40 IInArchiveGetStream
+ 50 IArchiveOpenSetSubArchiveName
+ 60 IInArchive
+ 61 IArchiveOpenSeq
+ 70 IArchiveGetRawProps
+ 71 IArchiveGetRootProps
+
+ 80 IArchiveUpdateCallback
+ 82 IArchiveUpdateCallback2
+ 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
+
+
+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
+
+ 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-000100030000} CAgentArchiveHandle
+{23170F69-40C1-278A-1000-000100020000} ContextMenu.h::CZipContextMenu
+
+{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/lzma/CPP/7zip/ICoder.h b/lzma/CPP/7zip/ICoder.h
new file mode 100644
index 0000000..9153adc
--- /dev/null
+++ b/lzma/CPP/7zip/ICoder.h
@@ -0,0 +1,211 @@
+// 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;
+};
+
+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 **inStreams, const UInt64 **inSizes, UInt32 numInStreams,
+ ISequentialOutStream **outStreams, const UInt64 **outSizes, UInt32 numOutStreams,
+ ICompressProgressInfo *progress) PURE;
+};
+
+namespace NCoderPropID
+{
+ enum EEnum
+ {
+ kDefaultProp = 0,
+ kDictionarySize,
+ kUsedMemorySize,
+ kOrder,
+ kBlockSize,
+ kPosStateBits,
+ kLitContextBits,
+ kLitPosBits,
+ kNumFastBytes,
+ kMatchFinder,
+ kMatchFinderCycles,
+ kNumPasses,
+ kAlgorithm,
+ kNumThreads,
+ kEndMarker,
+ kLevel,
+ kReduceSize // estimated size of data that will be compressed. Encoder can use this value to reduce dictionary size.
+ };
+}
+
+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)
+{
+ 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(ICompressGetSubStreamSize, 0x30)
+{
+ STDMETHOD(GetSubStreamSize)(UInt64 subStream, UInt64 *value) PURE;
+};
+
+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;
+};
+
+CODER_INTERFACE(ICompressSetBufSize, 0x35)
+{
+ STDMETHOD(SetInBufSize)(UInt32 streamIndex, UInt32 size) PURE;
+ STDMETHOD(SetOutBufSize)(UInt32 streamIndex, UInt32 size) PURE;
+};
+
+CODER_INTERFACE(ICompressFilter, 0x40)
+{
+ STDMETHOD(Init)() PURE;
+ STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size) PURE;
+ // Filter converts as most as possible bytes
+ // Filter return outSize (UInt32)
+ // 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).
+};
+
+CODER_INTERFACE(ICompressCodecsInfo, 0x60)
+{
+ STDMETHOD(GetNumberOfMethods)(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;
+};
+
+CODER_INTERFACE(ICryptoSetPassword, 0x90)
+{
+ STDMETHOD(CryptoSetPassword)(const Byte *data, UInt32 size) PURE;
+};
+
+CODER_INTERFACE(ICryptoSetCRC, 0xA0)
+{
+ STDMETHOD(CryptoSetCRC)(UInt32 crc) PURE;
+};
+
+//////////////////////
+// It's for DLL file
+namespace NMethodPropID
+{
+ enum EEnum
+ {
+ kID,
+ kName,
+ kDecoder,
+ kEncoder,
+ kInStreams,
+ kOutStreams,
+ kDescription,
+ kDecoderIsAssigned,
+ kEncoderIsAssigned,
+ kDigestSize
+ };
+}
+
+CODER_INTERFACE(IHasher, 0xC0)
+{
+ STDMETHOD_(void, Init)() PURE;
+ STDMETHOD_(void, Update)(const void *data, UInt32 size) PURE;
+ STDMETHOD_(void, Final)(Byte *digest) PURE;
+ STDMETHOD_(UInt32, GetDigestSize)() 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_GetHashers)(IHashers **hashers);
+}
+
+#endif
diff --git a/lzma/CPP/7zip/IDecl.h b/lzma/CPP/7zip/IDecl.h
new file mode 100644
index 0000000..768bbe7
--- /dev/null
+++ b/lzma/CPP/7zip/IDecl.h
@@ -0,0 +1,15 @@
+// IDecl.h
+
+#ifndef __IDECL_H
+#define __IDECL_H
+
+#include "../Common/MyUnknown.h"
+
+#define DECL_INTERFACE_SUB(i, base, groupId, subId) \
+DEFINE_GUID(IID_ ## i, \
+0x23170F69, 0x40C1, 0x278A, 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
diff --git a/lzma/CPP/7zip/IPassword.h b/lzma/CPP/7zip/IPassword.h
new file mode 100644
index 0000000..e366007
--- /dev/null
+++ b/lzma/CPP/7zip/IPassword.h
@@ -0,0 +1,23 @@
+// 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
diff --git a/lzma/CPP/7zip/IProgress.h b/lzma/CPP/7zip/IProgress.h
new file mode 100644
index 0000000..b98f480
--- /dev/null
+++ b/lzma/CPP/7zip/IProgress.h
@@ -0,0 +1,33 @@
+// Interface/IProgress.h
+
+#ifndef __IPROGRESS_H
+#define __IPROGRESS_H
+
+#include "../Common/MyTypes.h"
+#include "../Common/MyUnknown.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)
+};
+
+/*
+// {23170F69-40C1-278A-0000-000000050002}
+DEFINE_GUID(IID_IProgress2,
+0x23170F69, 0x40C1, 0x278A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x02);
+MIDL_INTERFACE("23170F69-40C1-278A-0000-000000050002")
+IProgress2: public IUnknown
+{
+public:
+ STDMETHOD(SetTotal)(const UInt64 *total) PURE;
+ STDMETHOD(SetCompleted)(const UInt64 *completeValue) PURE;
+};
+*/
+
+#endif
diff --git a/lzma/CPP/7zip/IStream.h b/lzma/CPP/7zip/IStream.h
new file mode 100644
index 0000000..d347def
--- /dev/null
+++ b/lzma/CPP/7zip/IStream.h
@@ -0,0 +1,127 @@
+// IStream.h
+
+#ifndef __ISTREAM_H
+#define __ISTREAM_H
+
+#include "../Common/MyTypes.h"
+#include "../Common/MyUnknown.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(IOutStreamFlush, 0x07)
+{
+ STDMETHOD(Flush)() 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
diff --git a/lzma/CPP/7zip/MyVersion.h b/lzma/CPP/7zip/MyVersion.h
new file mode 100644
index 0000000..06e6c58
--- /dev/null
+++ b/lzma/CPP/7zip/MyVersion.h
@@ -0,0 +1,6 @@
+#include "..\..\C\7zVersion.h"
+
+#undef MY_COPYRIGHT
+#undef MY_VERSION_COPYRIGHT_DATE
+#define MY_COPYRIGHT "Copyright (c) 1999-2014 Igor Pavlov"
+#define MY_VERSION_COPYRIGHT_DATE MY_VERSION " " MY_COPYRIGHT " " MY_DATE
diff --git a/lzma/CPP/7zip/MyVersionInfo.rc b/lzma/CPP/7zip/MyVersionInfo.rc
new file mode 100644
index 0000000..eddf893
--- /dev/null
+++ b/lzma/CPP/7zip/MyVersionInfo.rc
@@ -0,0 +1,2 @@
+#include "MyVersion.h"
+#include "..\..\C\7zVersion.rc"
diff --git a/lzma/CPP/7zip/PropID.h b/lzma/CPP/7zip/PropID.h
new file mode 100644
index 0000000..da2acd7
--- /dev/null
+++ b/lzma/CPP/7zip/PropID.h
@@ -0,0 +1,124 @@
+// 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,
+
+ kpid_NUM_DEFINED,
+
+ kpidUserDefined = 0x10000
+};
+
+extern 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
diff --git a/lzma/CPP/7zip/SubBuild.mak b/lzma/CPP/7zip/SubBuild.mak
new file mode 100644
index 0000000..0c49d3b
--- /dev/null
+++ b/lzma/CPP/7zip/SubBuild.mak
@@ -0,0 +1,3 @@
+ cd $(@D)
+ $(MAKE) -nologo $(TARGETS)
+ cd ..
diff --git a/lzma/CPP/7zip/UI/Client7z/Client7z.cpp b/lzma/CPP/7zip/UI/Client7z/Client7z.cpp
new file mode 100644
index 0000000..011eb56
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Client7z/Client7z.cpp
@@ -0,0 +1,923 @@
+// Client7z.cpp
+
+#include "StdAfx.h"
+
+#include <stdio.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);
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NDir;
+
+#define kDllName "7z.dll"
+
+static const char *kCopyrightString = "\n7-Zip " MY_VERSION
+" (" kDllName " client) "
+MY_COPYRIGHT " " MY_DATE "\n";
+
+static const char *kHelpString =
+"Usage: Client7z.exe [a | l | x ] archive.7z [fileName ...]\n"
+"Examples:\n"
+" Client7z.exe a archive.7z f1.txt f2.txt : compress two files to archive.7z\n"
+" Client7z.exe l archive.7z : List contents of archive.7z\n"
+" Client7z.exe x archive.7z : eXtract files from archive.7z\n";
+
+
+static AString FStringToConsoleString(const FString &s)
+{
+ return GetOemString(fs2us(s));
+}
+
+static FString CmdStringToFString(const char *s)
+{
+ return us2fs(GetUnicodeString(s));
+}
+
+static void PrintString(const UString &s)
+{
+ printf("%s", (LPCSTR)GetOemString(s));
+}
+
+static void PrintString(const AString &s)
+{
+ printf("%s", (LPCSTR)s);
+}
+
+static void PrintNewLine()
+{
+ PrintString("\n");
+}
+
+static void PrintStringLn(const AString &s)
+{
+ PrintString(s);
+ PrintNewLine();
+}
+
+static void PrintError(const char *message, const FString &name)
+{
+ printf("Error: %s", (LPCSTR)message);
+ PrintNewLine();
+ PrintString(FStringToConsoleString(name));
+ PrintNewLine();
+}
+
+static void PrintError(const AString &s)
+{
+ PrintNewLine();
+ PrintString(s);
+ PrintNewLine();
+}
+
+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 *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);
+}
+
+
+//////////////////////////////////////////////////////////////
+// Archive Extracting callback class
+
+static const char *kTestingString = "Testing ";
+static const char *kExtractingString = "Extracting ";
+static const char *kSkippingString = "Skipping ";
+
+static const char *kUnsupportedMethod = "Unsupported Method";
+static const char *kCRCFailed = "CRC Failed";
+static const char *kDataError = "Data Error";
+static const char *kUnavailableData = "Unavailable data";
+static const char *kUnexpectedEnd = "Unexpected end of data";
+static const char *kDataAfterEnd = "There are some data after the end of the payload data";
+static const char *kIsNotArc = "Is not archive";
+static const char *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(WCHAR_PATH_SEPARATOR);
+ 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: PrintString(kExtractingString); break;
+ case NArchive::NExtract::NAskMode::kTest: PrintString(kTestingString); break;
+ case NArchive::NExtract::NAskMode::kSkip: PrintString(kSkippingString); break;
+ };
+ PrintString(_filePath);
+ return S_OK;
+}
+
+STDMETHODIMP CArchiveExtractCallback::SetOperationResult(Int32 operationResult)
+{
+ switch (operationResult)
+ {
+ case NArchive::NExtract::NOperationResult::kOK:
+ break;
+ default:
+ {
+ NumErrors++;
+ PrintString(" : ");
+ 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)
+ {
+ PrintString("Error : ");
+ PrintString(s);
+ }
+ else
+ {
+ char temp[16];
+ ConvertUInt32ToString(operationResult, temp);
+ PrintString("Error #");
+ PrintString(temp);
+ }
+ }
+ }
+
+ if (_outFileStream != NULL)
+ {
+ if (_processedFileInfo.MTimeDefined)
+ _outFileStreamSpec->SetMTime(&_processedFileInfo.MTime);
+ RINOK(_outFileStreamSpec->Close());
+ }
+ _outFileStream.Release();
+ if (_extractMode && _processedFileInfo.AttribDefined)
+ SetFileAttrib(_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(EnumProperties)(IEnumSTATPROPSTG **enumerator);
+ 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::EnumProperties(IEnumSTATPROPSTG ** /* enumerator */)
+{
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CArchiveUpdateCallback::GetUpdateItemInfo(UInt32 /* index */,
+ Int32 *newData, Int32 *newProperties, UInt32 *indexInArchive)
+{
+ if (newData != NULL)
+ *newData = BoolToInt(true);
+ if (newProperties != NULL)
+ *newProperties = BoolToInt(true);
+ if (indexInArchive != NULL)
+ *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)
+{
+ PrintString("Compressing ");
+ if (name[0] == 0)
+ name = kEmptyFileAlias;
+ PrintString(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");
+ // PrintString(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 = UString(L'0') + res;
+ UString fileName = VolName;
+ fileName += L'.';
+ 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 < 3)
+ {
+ PrintStringLn(kHelpString);
+ 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("incorrect command");
+ return 1;
+ }
+ c = (char)MyCharLower_Ascii(command[0]);
+ }
+ FString archiveName = CmdStringToFString(args[2]);
+ if (c == 'a')
+ {
+ // create archive command
+ if (numArgs < 4)
+ {
+ PrintStringLn(kHelpString);
+ 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_CFormat7z, &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)
+ {
+ PrintStringLn(kHelpString);
+ return 1;
+ }
+
+ bool listCommand;
+ if (c == 'l')
+ listCommand = true;
+ else if (c == 'x')
+ listCommand = false;
+ else
+ {
+ PrintError("incorrect command");
+ return 1;
+ }
+
+ CMyComPtr<IInArchive> archive;
+ if (createObjectFunc(&CLSID_CFormat7z, &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";
+
+ if (archive->Open(file, 0, 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);
+ PrintString(s);
+ PrintString(" ");
+ }
+ {
+ // Get name of file
+ NCOM::CPropVariant prop;
+ archive->GetProperty(i, kpidPath, &prop);
+ if (prop.vt == VT_BSTR)
+ PrintString(prop.bstrVal);
+ else if (prop.vt != VT_EMPTY)
+ PrintString("ERROR!");
+ }
+ PrintNewLine();
+ }
+ }
+ else
+ {
+ // Extract command
+ CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback;
+ CMyComPtr<IArchiveExtractCallback> extractCallback(extractCallbackSpec);
+ extractCallbackSpec->Init(archive, FTEXT("")); // second parameter is output folder path
+ extractCallbackSpec->PasswordIsDefined = false;
+ // extractCallbackSpec->PasswordIsDefined = true;
+ // extractCallbackSpec->Password = L"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/lzma/CPP/7zip/UI/Client7z/Client7z.dsp b/lzma/CPP/7zip/UI/Client7z/Client7z.dsp
new file mode 100644
index 0000000..4a4711c
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Client7z/Client7z.dsp
@@ -0,0 +1,235 @@
+# 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 /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
diff --git a/lzma/CPP/7zip/UI/Client7z/Client7z.dsw b/lzma/CPP/7zip/UI/Client7z/Client7z.dsw
new file mode 100644
index 0000000..4c26851
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Client7z/Client7z.dsw
@@ -0,0 +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>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/lzma/CPP/7zip/UI/Client7z/StdAfx.cpp b/lzma/CPP/7zip/UI/Client7z/StdAfx.cpp
new file mode 100644
index 0000000..c6d3b1f
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Client7z/StdAfx.cpp
@@ -0,0 +1,3 @@
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/lzma/CPP/7zip/UI/Client7z/StdAfx.h b/lzma/CPP/7zip/UI/Client7z/StdAfx.h
new file mode 100644
index 0000000..59d9ac1
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Client7z/StdAfx.h
@@ -0,0 +1,8 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "../../../Common/Common.h"
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Client7z/makefile b/lzma/CPP/7zip/UI/Client7z/makefile
new file mode 100644
index 0000000..9f68f16
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Client7z/makefile
@@ -0,0 +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"
diff --git a/lzma/CPP/7zip/UI/Client7z/resource.rc b/lzma/CPP/7zip/UI/Client7z/resource.rc
new file mode 100644
index 0000000..97086e9
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Client7z/resource.rc
@@ -0,0 +1,3 @@
+#include "../../../../C/7zVersion.rc"
+
+MY_VERSION_INFO_APP("7-Zip client", "7zcl")
diff --git a/lzma/CPP/7zip/UI/Common/ArchiveCommandLine.cpp b/lzma/CPP/7zip/UI/Common/ArchiveCommandLine.cpp
new file mode 100644
index 0000000..9e0eab0
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Common/ArchiveCommandLine.cpp
@@ -0,0 +1,1257 @@
+// ArchiveCommandLine.cpp
+
+#include "StdAfx.h"
+#undef printf
+#undef sprintf
+
+#ifdef _WIN32
+#ifndef UNDER_CE
+#include <io.h>
+#endif
+#endif
+#include <stdio.h>
+
+#include "../../../Common/ListFileUtils.h"
+#include "../../../Common/StringConvert.h"
+#include "../../../Common/StringToInt.h"
+
+#include "../../../Windows/FileDir.h"
+#include "../../../Windows/FileName.h"
+#ifdef _WIN32
+#include "../../../Windows/FileMapping.h"
+#include "../../../Windows/Synchronization.h"
+#endif
+
+#include "ArchiveCommandLine.h"
+#include "EnumDirItems.h"
+#include "SortUtils.h"
+#include "Update.h"
+#include "UpdateAction.h"
+
+extern bool g_CaseSensitive;
+
+#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;
+}
+
+static void AddNewLine(UString &s)
+{
+ s += L'\n';
+}
+
+CArcCmdLineException::CArcCmdLineException(const char *a, const wchar_t *u)
+{
+ (*this) += MultiByteToUnicodeString(a);
+ if (u)
+ {
+ AddNewLine(*this);
+ (*this) += u;
+ }
+}
+
+int g_CodePage = -1;
+
+namespace NKey {
+enum Enum
+{
+ kHelp1 = 0,
+ kHelp2,
+ kHelp3,
+ kDisableHeaders,
+ kDisablePercents,
+ kArchiveType,
+ kYes,
+ #ifndef _NO_CRYPTO
+ kPassword,
+ #endif
+ kProperty,
+ kOutputDir,
+ kWorkingDir,
+ kInclude,
+ kExclude,
+ kArInclude,
+ kArExclude,
+ kNoArName,
+ kUpdate,
+ kVolume,
+ kRecursed,
+ kSfx,
+ kStdIn,
+ kStdOut,
+ kOverwrite,
+ kEmail,
+ kShowDialog,
+ kLargePages,
+ kListfileCharSet,
+ kConsoleCharSet,
+ kTechMode,
+ kShareForWrite,
+ kCaseSensitive,
+ kHash,
+ kArcNameMode,
+
+ kDisableWildcardParsing,
+ kElimDup,
+ kFullPathMode,
+
+ kHardLinks,
+ kSymLinks,
+ kNtSecurity,
+ kAltStreams,
+ kReplaceColonForAltStream,
+ kWriteToAltStreamIfColon,
+
+ kDeleteAfterCompressing,
+ kSetArcMTime,
+ kExcludedArcType
+};
+
+}
+
+
+static const wchar_t kRecursedIDChar = 'r';
+static const char *kRecursedPostCharSet = "0-";
+
+static const char *k_ArcNameMode_PostCharSet = "sea";
+
+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 *kOverwritePostCharSet = "asut";
+
+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" },
+ { "t", NSwitchType::kString, false, 1 },
+ { "y" },
+ #ifndef _NO_CRYPTO
+ { "p", NSwitchType::kString },
+ #endif
+ { "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 },
+ { "sfx", NSwitchType::kString },
+ { "si", NSwitchType::kString },
+ { "so" },
+ { "ao", NSwitchType::kChar, false, 1, kOverwritePostCharSet},
+ { "seml", NSwitchType::kString, false, 0},
+ { "ad" },
+ { "slp", NSwitchType::kMinus },
+ { "scs", NSwitchType::kString },
+ { "scc", NSwitchType::kString },
+ { "slt" },
+ { "ssw" },
+ { "ssc", NSwitchType::kMinus },
+ { "scrc", NSwitchType::kString, true, 0 },
+ { "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" },
+
+ { "sdel" },
+ { "stl" },
+ { "stx", NSwitchType::kString, true, 1 }
+};
+
+static const wchar_t *kUniversalWildcard = L"*";
+static const int kMinNonSwitchWords = 1;
+static const int kCommandIndex = 0;
+
+// static const char *kUserErrorMessage = "Incorrect command line";
+static const char *kCannotFindListFile = "Cannot find listfile";
+static const char *kIncorrectListFile = "Incorrect item in listfile.\nCheck charset encoding and -scs switch.";
+// static const char *kIncorrectWildcardInListFile = "Incorrect wildcard in listfile";
+// static const char *kIncorrectWildcardInCommandLine = "Incorrect wildcard in command line";
+static const char *kTerminalOutError = "I won't write compressed data to a terminal";
+static const char *kSameTerminalError = "I won't write data and program's messages to same terminal";
+static const char *kEmptyFilePath = "Empty file path";
+static const char *kCannotFindArchive = "Cannot find archive";
+
+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;
+ AddNewLine(val);
+ val += pair.NewName;
+ AddNewLine(val);
+ if (type == NRecursedType::kRecursed)
+ val += L"-r";
+ else if (type == NRecursedType::kRecursed)
+ val += L"-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);
+ if (!ReadNamesFromListFile(us2fs(fileName), names, codePage))
+ 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, NRecursedType::EEnum type,
+ bool wildcardMatching,
+ bool thereAreSwitchIncludes, Int32 codePage)
+{
+ if ((renamePairs || nonSwitchStrings.Size() == startIndex) && !thereAreSwitchIncludes)
+ AddNameToCensor(censor, kUniversalWildcard, true, type,
+ true // wildcardMatching
+ );
+
+ int oldIndex = -1;
+
+ for (unsigned i = startIndex; i < nonSwitchStrings.Size(); i++)
+ {
+ const UString &s = nonSwitchStrings[i];
+ if (s.IsEmpty())
+ throw CArcCmdLineException(kEmptyFilePath);
+ if (s[0] == kFileListID)
+ AddToCensorFromListFile(renamePairs, censor, s.Ptr(1), true, type, wildcardMatching, codePage);
+ else if (renamePairs)
+ {
+ if (oldIndex == -1)
+ oldIndex = startIndex;
+ 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();
+ }
+};
+
+const char *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 + (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;
+ }
+
+ 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 wildcarc type marker";
+ break;
+ }
+ }
+ if (i != strings.Size())
+ throw CArcCmdLineException(errorMessage, strings[i]);
+}
+
+#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);
+ if (NFile::NName::IsDevicePath(path))
+ return;
+ 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.IsEqualToNoCase(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
+
+/*
+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 wchar_t *kUpdatePairStateIDSet = L"pqrxyzw";
+static const int kUpdatePairStateNotSupportedActions[] = {2, 2, 1, -1, -1, -1, -1};
+
+static const unsigned kNumUpdatePairActions = 4;
+static const char *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, c);
+ if (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;
+ int actionPos = c - '0';
+ actionSet.StateActions[statePos] = (NUpdateArchive::NPairAction::EEnum)(actionPos);
+ if (kUpdatePairStateNotSupportedActions[statePos] == 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);
+ }
+ }
+}
+
+CArcCmdLineParser::CArcCmdLineParser(): parser(ARRAY_SIZE(kSwitchForms)) {}
+
+void CArcCmdLineParser::Parse1(const UStringVector &commandStrings,
+ CArcCmdLineOptions &options)
+{
+ if (!parser.ParseStrings(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.StdInMode = parser[NKey::kStdIn].ThereIs;
+ options.StdOutMode = parser[NKey::kStdOut].ThereIs;
+ options.EnableHeaders = !parser[NKey::kDisableHeaders].ThereIs;
+ options.HelpMode = parser[NKey::kHelp1].ThereIs || parser[NKey::kHelp2].ThereIs || parser[NKey::kHelp3].ThereIs;
+
+ if (parser[NKey::kCaseSensitive].ThereIs)
+ {
+ g_CaseSensitive = !parser[NKey::kCaseSensitive].WithMinus;
+ options.CaseSensitiveChange = true;
+ options.CaseSensitive = g_CaseSensitive;
+ }
+
+ #ifdef _WIN32
+ options.LargePages = false;
+ if (parser[NKey::kLargePages].ThereIs)
+ {
+ options.LargePages = !parser[NKey::kLargePages].WithMinus;
+ }
+ #endif
+}
+
+struct CCodePagePair
+{
+ const char *Name;
+ Int32 CodePage;
+};
+
+static const unsigned kNumByteOnlyCodePages = 3;
+
+static 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, int 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;
+ }
+}
+
+void EnumerateDirItemsAndSort(
+ bool storeAltStreams,
+ NWildcard::CCensor &censor,
+ NWildcard::ECensorPathMode censorPathMode,
+ const UString &addPathPrefix,
+ UStringVector &sortedPaths,
+ UStringVector &sortedFullPaths)
+{
+ UStringVector paths;
+ {
+ CDirItems dirItems;
+ {
+ dirItems.ScanAltStreams = storeAltStreams;
+ HRESULT res = EnumerateItems(censor, censorPathMode, addPathPrefix, dirItems, NULL);
+ if (res != S_OK || dirItems.ErrorPaths.Size() > 0)
+ {
+ UString errorPath;
+ if (dirItems.ErrorPaths.Size() > 0)
+ errorPath = fs2us(dirItems.ErrorPaths[0]);
+ throw CArcCmdLineException(kCannotFindArchive,
+ dirItems.ErrorPaths.Size() > 0 ? (const wchar_t *)errorPath : NULL);
+ }
+ }
+ FOR_VECTOR (i, dirItems.Items)
+ {
+ const CDirItem &dirItem = dirItems.Items[i];
+ if (!dirItem.IsDir())
+ paths.Add(dirItems.GetPhyPath(i));
+ }
+ }
+
+ if (paths.Size() == 0)
+ throw CArcCmdLineException(kCannotFindArchive);
+
+ UStringVector fullPaths;
+
+ unsigned i;
+ for (i = 0; i < paths.Size(); i++)
+ {
+ FString fullPath;
+ NFile::NDir::MyGetFullPathName(us2fs(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(paths[index]);
+ sortedFullPaths.AddInReserved(fullPaths[index]);
+ if (i > 0 && CompareFileNames(sortedFullPaths[i], sortedFullPaths[i - 1]) == 0)
+ throw CArcCmdLineException("Duplicate archive path:", sortedFullPaths[i]);
+ }
+}
+
+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;
+ int numNonSwitchStrings = nonSwitchStrings.Size();
+ if (numNonSwitchStrings < kMinNonSwitchWords)
+ throw CArcCmdLineException("The command must be spcified");
+
+ if (!ParseArchiveCommand(nonSwitchStrings[kCommandIndex], options.Command))
+ throw CArcCmdLineException("Unsupported command:", nonSwitchStrings[kCommandIndex]);
+
+ options.TechMode = parser[NKey::kTechMode].ThereIs;
+ 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);
+ }
+ }
+
+ 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);
+
+ int 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");
+ }
+
+ AddToCensorFromNonSwitchesStrings(isRename ? &options.UpdateOptions.RenamePairs : NULL,
+ curCommandIndex, options.Censor,
+ nonSwitchStrings, 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);
+
+ options.EnablePercents = !parser[NKey::kDisablePercents].ThereIs;
+
+ if (options.EnablePercents)
+ {
+ if ((options.StdOutMode && !options.IsStdErrTerminal) ||
+ (!options.StdOutMode && !options.IsStdOutTerminal))
+ options.EnablePercents = false;
+ }
+
+ 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;
+
+ 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)
+ {
+ UString arcName = parser[NKey::kStdIn].PostStrings.Front();
+ options.ArchivePathsSorted.Add(arcName);
+ options.ArchivePathsFullSorted.Add(arcName);
+ }
+ else
+ {
+ EnumerateDirItemsAndSort(
+ false, // scanAltStreams
+ arcCensor,
+ NWildcard::k_RelatPath,
+ UString(), // addPathPrefix
+ options.ArchivePathsSorted,
+ options.ArchivePathsFullSorted);
+ }
+
+ if (isExtractGroupCommand)
+ {
+ if (options.StdOutMode && options.IsStdOutTerminal && options.IsStdErrTerminal)
+ 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[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;
+
+ 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 && options.IsStdOutTerminal)
+ throw CArcCmdLineException(kTerminalOutError);
+ 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 9815676711;
+}
diff --git a/lzma/CPP/7zip/UI/Common/ArchiveCommandLine.h b/lzma/CPP/7zip/UI/Common/ArchiveCommandLine.h
new file mode 100644
index 0000000..3f4186f
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Common/ArchiveCommandLine.h
@@ -0,0 +1,122 @@
+// ArchiveCommandLine.h
+
+#ifndef __ARCHIVE_COMMAND_LINE_H
+#define __ARCHIVE_COMMAND_LINE_H
+
+#include "../../../Common/CommandLineParser.h"
+#include "../../../Common/Wildcard.h"
+
+#include "Extract.h"
+#include "HashCalc.h"
+#include "Update.h"
+
+struct CArcCmdLineException: public UString
+{
+ CArcCmdLineException(const char *a, const wchar_t *u = NULL);
+};
+
+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;
+};
+
+struct CArcCmdLineOptions
+{
+ bool HelpMode;
+
+ #ifdef _WIN32
+ bool LargePages;
+ #endif
+ 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;
+
+ UStringVector HashMethods;
+
+ bool AppendName;
+ UStringVector ArchivePathsSorted;
+ UStringVector ArchivePathsFullSorted;
+ CObjectVector<CProperty> Properties;
+
+ CExtractOptionsBase ExtractOptions;
+
+ CBoolPair NtSecurity;
+ CBoolPair AltStreams;
+ CBoolPair HardLinks;
+ CBoolPair SymLinks;
+
+ CUpdateOptions UpdateOptions;
+ CHashOptions HashOptions;
+ UString ArcType;
+ UStringVector ExcludedArcTypes;
+ bool EnablePercents;
+
+ // Benchmark
+ UInt32 NumIterations;
+
+ CArcCmdLineOptions():
+ StdInMode(false),
+ StdOutMode(false),
+ CaseSensitiveChange(false),
+ CaseSensitive(false)
+ {};
+};
+
+class CArcCmdLineParser
+{
+ NCommandLineParser::CParser parser;
+public:
+ CArcCmdLineParser();
+ void Parse1(const UStringVector &commandStrings, CArcCmdLineOptions &options);
+ void Parse2(CArcCmdLineOptions &options);
+};
+
+void EnumerateDirItemsAndSort(
+ bool storeAltStreams,
+ NWildcard::CCensor &censor,
+ NWildcard::ECensorPathMode pathMode,
+ const UString &addPathPrefix,
+ UStringVector &sortedPaths,
+ UStringVector &sortedFullPaths);
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp b/lzma/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp
new file mode 100644
index 0000000..315945b
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp
@@ -0,0 +1,1191 @@
+// ArchiveExtractCallback.cpp
+
+#include "StdAfx.h"
+
+#undef sprintf
+#undef printf
+
+#include "../../../Common/ComTry.h"
+#include "../../../Common/StringConvert.h"
+#include "../../../Common/Wildcard.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/ExtractingFilePath.h"
+#include "../Common/PropIDUtils.h"
+
+#include "ArchiveExtractCallback.h"
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NDir;
+
+static const char *kCantAutoRename = "Can not create file with auto name";
+static const char *kCantRenameFile = "Can not rename existing file";
+static const char *kCantDeleteOutputFile = "Can not delete output file";
+static const char *kCantDeleteOutputDir = "Can not delete output folder";
+
+
+#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);
+}
+
+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;
+ RINOK(Archive_Get_HardLinkNode(archive, realIndices ? (*realIndices)[i] : i, h, defined));
+ if (defined)
+ 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():
+ 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,
+ UInt64 packSize)
+{
+ _extractedFolderPaths.Clear();
+ _extractedFolderIndices.Clear();
+
+ #ifdef SUPPORT_LINKS
+ _hardLinks.Clear();
+ #endif
+
+ _ntOptions = ntOptions;
+ _wildcardCensor = wildcardCensor;
+
+ _stdOutMode = stdOutMode;
+ _testMode = testMode;
+ _unpTotal = 1;
+ _packTotal = packSize;
+
+ _extractCallback2 = extractCallback2;
+ _compressProgress.Release();
+ _extractCallback2.QueryInterface(IID_ICompressProgressInfo, &_compressProgress);
+
+ #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;
+ _baseParentFolder = (UInt32)(Int32)-1;
+ _use_baseParentFolder_mode = false;
+
+ _arc = arc;
+ _directoryPath = directoryPath;
+ NName::NormalizeDirPathPrefix(_directoryPath);
+ NDir::MyGetFullPathName(directoryPath, _directoryPathFull);
+}
+
+STDMETHODIMP CArchiveExtractCallback::SetTotal(UInt64 size)
+{
+ COM_TRY_BEGIN
+ _unpTotal = size;
+ 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;
+
+ if (_multiArchives)
+ {
+ if (completeValue != NULL)
+ {
+ UInt64 packCur = LocalProgressSpec->InSize + MyMultDiv64(*completeValue, _unpTotal, _packTotal);
+ return _extractCallback2->SetCompleted(&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
+}
+
+#define IS_LETTER_CHAR(c) ((c) >= 'a' && (c) <= 'z' || (c) >= 'A' && (c) <= 'Z')
+
+static inline bool IsDriveName(const UString &s)
+{
+ return s.Len() == 2 && s[1] == ':' && IS_LETTER_CHAR(s[0]);
+}
+
+void CArchiveExtractCallback::CreateComplexDirectory(const UStringVector &dirPathParts, FString &fullPath)
+{
+ bool isAbsPath = false;
+
+ if (!dirPathParts.IsEmpty())
+ {
+ const UString &s = dirPathParts[0];
+ if (s.IsEmpty())
+ isAbsPath = true;
+ #ifdef _WIN32
+ else
+ {
+ if (dirPathParts.Size() > 1 && IsDriveName(s))
+ isAbsPath = true;
+ }
+ #endif
+ }
+
+ if (_pathMode == NExtract::NPathMode::kAbsPaths && isAbsPath)
+ fullPath.Empty();
+ else
+ fullPath = _directoryPath;
+
+ FOR_VECTOR (i, dirPathParts)
+ {
+ if (i > 0)
+ fullPath += FCHAR_PATH_SEPARATOR;
+ const UString &s = dirPathParts[i];
+ fullPath += us2fs(s);
+ #ifdef _WIN32
+ if (_pathMode == NExtract::NPathMode::kAbsPaths)
+ if (i == 0 && IsDriveName(s))
+ continue;
+ #endif
+ CreateDir(fullPath);
+ }
+}
+
+HRESULT CArchiveExtractCallback::GetTime(int index, PROPID propID, FILETIME &filetime, bool &filetimeIsDefined)
+{
+ filetimeIsDefined = false;
+ 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);
+}
+
+HRESULT CArchiveExtractCallback::SendMessageError(const char *message, const FString &path)
+{
+ return _extractCallback2->MessageError(
+ UString(L"ERROR: ") +
+ GetUnicodeString(message) + L": " + fs2us(path));
+}
+
+HRESULT CArchiveExtractCallback::SendMessageError2(const char *message, const FString &path1, const FString &path2)
+{
+ return _extractCallback2->MessageError(
+ UString(L"ERROR: ") +
+ GetUnicodeString(message) + UString(L": ") + fs2us(path1) + UString(L" : ") + fs2us(path2));
+}
+
+#ifndef _SFX
+
+STDMETHODIMP CGetProp::GetProp(PROPID propID, PROPVARIANT *value)
+{
+ if (propID == kpidName)
+ {
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop = Name.Ptr();
+ 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 (s.Back() == WCHAR_PATH_SEPARATOR)
+ s.DeleteBack();
+ int pos = s.ReverseFind(WCHAR_PATH_SEPARATOR);
+ s.DeleteFrom(pos + 1);
+ }
+ return s;
+}
+
+static bool IsSafePath(const UString &path)
+{
+ UStringVector parts;
+ SplitPathToParts(path, parts);
+ int level = 0;
+ FOR_VECTOR(i, parts)
+ {
+ const UString &s = parts[i];
+ if (s.IsEmpty())
+ continue;
+ if (s == L".")
+ continue;
+ if (s == L"..")
+ {
+ if (level <= 0)
+ return false;
+ level--;
+ }
+ else
+ level++;
+ }
+ return level > 0;
+}
+
+#endif
+
+
+STDMETHODIMP CArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStream **outStream, Int32 askExtractMode)
+{
+ COM_TRY_BEGIN
+
+ *outStream = 0;
+
+ #ifndef _SFX
+ if (_hashStream)
+ _hashStreamSpec->ReleaseStream();
+ _hashStreamWasUsed = false;
+ #endif
+
+ _outFileStream.Release();
+
+ _encrypted = false;
+ _isSplit = false;
+ _isAltStream = false;
+ _curSize = 0;
+ _curSizeDefined = false;
+ _index = index;
+
+ UString fullPath;
+
+ IInArchive *archive = _arc->Archive;
+ RINOK(_arc->GetItemPath(index, fullPath));
+ RINOK(Archive_IsItem_Folder(archive, index, _fi.IsDir));
+
+ _filePath = fullPath;
+
+ {
+ 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 isHardLink = false;
+ bool isJunction = false;
+ bool isRelative = false;
+
+ UString linkPath;
+ // RINOK(Archive_GetItemBoolProp(archive, index, kpidIsHardLink, isHardLink));
+ // if (isHardLink)
+ {
+ NCOM::CPropVariant prop;
+ RINOK(archive->GetProperty(index, kpidHardLink, &prop));
+ if (prop.vt == VT_BSTR)
+ {
+ isHardLink = true;
+ linkPath = prop.bstrVal;
+ isRelative = false; // TAR: hard links are from root folder of archive
+ }
+ else if (prop.vt == VT_EMPTY)
+ {
+ // linkPath.Empty();
+ }
+ else
+ return E_FAIL;
+ }
+ {
+ NCOM::CPropVariant prop;
+ RINOK(archive->GetProperty(index, kpidSymLink, &prop));
+ if (prop.vt == VT_BSTR)
+ {
+ isHardLink = false;
+ linkPath = prop.bstrVal;
+ isRelative = true; // TAR: symbolic links are relative
+ }
+ else if (prop.vt == VT_EMPTY)
+ {
+ // linkPath.Empty();
+ }
+ else
+ 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;
+ isOkReparse = reparse.Parse((const Byte *)data, dataSize);
+ if (isOkReparse)
+ {
+ isHardLink = false;
+ linkPath = reparse.GetPath();
+ isJunction = reparse.IsMountPoint();
+ isRelative = reparse.IsRelative();
+ #ifndef _WIN32
+ linkPath.Replace(WCHAR_PATH_SEPARATOR, '/', );
+ #endif
+ }
+ }
+ }
+
+ if (!linkPath.IsEmpty())
+ {
+ #ifdef _WIN32
+ linkPath.Replace('/', WCHAR_PATH_SEPARATOR);
+ #endif
+
+ 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 = MakePathNameFromParts(pathParts);
+ }
+
+ #endif
+
+ RINOK(Archive_GetItemBoolProp(archive, index, kpidEncrypted, _encrypted));
+
+ RINOK(GetUnpackSize());
+
+ RINOK(Archive_IsItem_AltStream(archive, index, _isAltStream));
+
+ if (!_ntOptions.AltStreams.Val && _isAltStream)
+ return S_OK;
+
+ if (_wildcardCensor)
+ {
+ if (!_wildcardCensor->CheckPath(_isAltStream, fullPath, !_fi.IsDir))
+ return S_OK;
+ }
+
+
+ UStringVector pathParts;
+
+ if (_use_baseParentFolder_mode)
+ {
+ int baseParent = _baseParentFolder;
+ if (_pathMode == NExtract::NPathMode::kFullPaths ||
+ _pathMode == NExtract::NPathMode::kAbsPaths)
+ baseParent = -1;
+ RINOK(_arc->GetItemPathToParent(index, baseParent, pathParts));
+ if (_pathMode == NExtract::NPathMode::kNoPaths && !pathParts.IsEmpty())
+ pathParts.DeleteFrontal(pathParts.Size() - 1);
+ }
+ else
+ {
+ SplitPathToParts(fullPath, pathParts);
+
+ if (pathParts.IsEmpty())
+ return E_FAIL;
+ unsigned numRemovePathParts = 0;
+
+ switch (_pathMode)
+ {
+ case NExtract::NPathMode::kCurPaths:
+ {
+ bool badPrefix = false;
+ if (pathParts.Size() <= _removePathParts.Size())
+ badPrefix = true;
+ else
+ {
+ FOR_VECTOR (i, _removePathParts)
+ {
+ if (!_removePathParts[i].IsEqualToNoCase(pathParts[i]))
+ {
+ badPrefix = true;
+ break;
+ }
+ }
+ }
+ if (badPrefix)
+ {
+ if (askExtractMode == NArchive::NExtract::NAskMode::kExtract && !_testMode)
+ return E_FAIL;
+ }
+ else
+ numRemovePathParts = _removePathParts.Size();
+ break;
+ }
+ case NExtract::NPathMode::kNoPaths:
+ {
+ 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;
+ GetProp_Spec->Name = MakePathNameFromParts(pathParts);
+
+ return ExtractToStreamCallback->GetStream7(GetProp_Spec->Name, _fi.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));
+
+ bool replace = _isAltStream ?
+ _ntOptions.ReplaceColonForAltStream :
+ !_ntOptions.WriteToAltStreamIfColon;
+
+ if (_pathMode != NExtract::NPathMode::kAbsPaths)
+ MakeCorrectPath(_directoryPath.IsEmpty(), pathParts, replace);
+ Correct_IfEmptyLastPart(pathParts);
+ UString processedPath = MakePathNameFromParts(pathParts);
+
+ if (!isAnti)
+ {
+ if (!_fi.IsDir)
+ {
+ if (!pathParts.IsEmpty())
+ pathParts.DeleteBack();
+ }
+
+ if (!pathParts.IsEmpty())
+ {
+ FString fullPathNew;
+ CreateComplexDirectory(pathParts, fullPathNew);
+ if (_fi.IsDir)
+ {
+ _extractedFolderPaths.Add(fullPathNew);
+ _extractedFolderIndices.Add(index);
+ SetDirTime(fullPathNew,
+ (WriteCTime && _fi.CTimeDefined) ? &_fi.CTime : NULL,
+ (WriteATime && _fi.ATimeDefined) ? &_fi.ATime : NULL,
+ (WriteMTime && _fi.MTimeDefined) ? &_fi.MTime : (_arc->MTimeDefined ? &_arc->MTime : NULL));
+ }
+ }
+ }
+
+
+ FString fullProcessedPath = us2fs(processedPath);
+ if (_pathMode != NExtract::NPathMode::kAbsPaths ||
+ !NName::IsAbsolutePath(processedPath))
+ fullProcessedPath = _directoryPath + fullProcessedPath;
+
+ if (_fi.IsDir)
+ {
+ _diskFilePath = fullProcessedPath;
+ if (isAnti)
+ RemoveDir(_diskFilePath);
+ #ifdef SUPPORT_LINKS
+ if (linkPath.IsEmpty())
+ #endif
+ return S_OK;
+ }
+ else if (!_isSplit)
+ {
+ NFind::CFileInfo fileInfo;
+ if (fileInfo.Find(fullProcessedPath))
+ {
+ switch (_overwriteMode)
+ {
+ case NExtract::NOverwriteMode::kSkip:
+ return S_OK;
+ case NExtract::NOverwriteMode::kAsk:
+ {
+ int slashPos = fullProcessedPath.ReverseFind(FTEXT('/'));
+ #ifdef _WIN32
+ int slash1Pos = fullProcessedPath.ReverseFind(FTEXT('\\'));
+ slashPos = MyMax(slashPos, slash1Pos);
+ #endif
+ FString realFullProcessedPath = fullProcessedPath.Left(slashPos + 1) + fileInfo.Name;
+
+ Int32 overwiteResult;
+ RINOK(_extractCallback2->AskOverwrite(
+ fs2us(realFullProcessedPath), &fileInfo.MTime, &fileInfo.Size, fullPath,
+ _fi.MTimeDefined ? &_fi.MTime : NULL,
+ _curSizeDefined ? &_curSize : NULL,
+ &overwiteResult))
+
+ switch (overwiteResult)
+ {
+ 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;
+ }
+ }
+ 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 folders too
+ if (!MyMoveFile(fullProcessedPath, existPath))
+ {
+ RINOK(SendMessageError(kCantRenameFile, fullProcessedPath));
+ return E_FAIL;
+ }
+ }
+ else
+ {
+ if (fileInfo.IsDir())
+ {
+ // do we need to delete all files in folder?
+ if (!RemoveDir(fullProcessedPath))
+ {
+ RINOK(SendMessageError(kCantDeleteOutputDir, fullProcessedPath));
+ return S_OK;
+ }
+ }
+ else if (!DeleteFileAlways(fullProcessedPath))
+ {
+ RINOK(SendMessageError(kCantDeleteOutputFile, fullProcessedPath));
+ return S_OK;
+ // return E_FAIL;
+ }
+ }
+ }
+ }
+ _diskFilePath = fullProcessedPath;
+
+
+ if (!isAnti)
+ {
+ #ifdef SUPPORT_LINKS
+
+ if (!linkPath.IsEmpty())
+ {
+ #ifndef UNDER_CE
+
+ UString relatPath;
+ if (isRelative)
+ relatPath = GetDirPrefixOf(_filePath);
+ relatPath += linkPath;
+
+ if (!IsSafePath(relatPath))
+ {
+ RINOK(SendMessageError("Dangerous link path was ignored", us2fs(relatPath)));
+ }
+ else
+ {
+ FString existPath;
+ if (isHardLink || !isRelative)
+ {
+ if (!NName::GetFullPath(_directoryPathFull, us2fs(relatPath), existPath))
+ {
+ RINOK(SendMessageError("Incorrect path", us2fs(relatPath)));
+ }
+ }
+ else
+ {
+ existPath = us2fs(linkPath);
+ }
+
+ if (!existPath.IsEmpty())
+ {
+ if (isHardLink)
+ {
+ if (!MyCreateHardLink(fullProcessedPath, existPath))
+ {
+ RINOK(SendMessageError2("Can not create hard link", fullProcessedPath, existPath));
+ // return S_OK;
+ }
+ }
+ else if (_ntOptions.SymLinks.Val)
+ {
+ // bool isSymLink = true; // = false for junction
+ if (_fi.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;
+ if (!attr.Parse(data, data.Size()))
+ {
+ return E_FAIL; // "Internal conversion error";
+ }
+
+ if (!NFile::NIO::SetReparseData(fullProcessedPath, _fi.IsDir, data, (DWORD)data.Size()))
+ {
+ RINOK(SendMessageError("Can not set reparse data", fullProcessedPath));
+ }
+ }
+ }
+ }
+ }
+
+ #endif
+ }
+ else
+ #endif // SUPPORT_LINKS
+ {
+ bool needWriteFile = true;
+
+ #ifdef SUPPORT_LINKS
+ if (!_hardLinks.IDs.IsEmpty())
+ {
+ 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("Can not create hard link", fullProcessedPath, hl));
+ return S_OK;
+ }
+ needWriteFile = false;
+ }
+ }
+ }
+ }
+ }
+ #endif
+
+ if (needWriteFile)
+ {
+ _outFileStreamSpec = new COutFileStream;
+ CMyComPtr<ISequentialOutStream> outStreamLoc(_outFileStreamSpec);
+ if (!_outFileStreamSpec->Open(fullProcessedPath, _isSplit ? OPEN_ALWAYS: CREATE_ALWAYS))
+ {
+ // if (::GetLastError() != ERROR_FILE_EXISTS || !isSplit)
+ {
+ RINOK(SendMessageError("Can not open output file ", fullProcessedPath));
+ return S_OK;
+ }
+ }
+ if (_isSplit)
+ {
+ RINOK(_outFileStreamSpec->Seek(_position, STREAM_SEEK_SET, NULL));
+ }
+ _outFileStream = outStreamLoc;
+ }
+ }
+ }
+
+ 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)
+ *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(_filePath, _fi.IsDir,
+ askExtractMode, _isSplit ? &_position: 0);
+ COM_TRY_END
+}
+
+STDMETHODIMP CArchiveExtractCallback::SetOperationResult(Int32 operationResult)
+{
+ COM_TRY_BEGIN
+
+ #ifndef _SFX
+ if (ExtractToStreamCallback)
+ return ExtractToStreamCallback->SetOperationResult7(operationResult, _encrypted);
+ #endif
+
+ #ifndef _SFX
+
+ if (_hashStreamWasUsed)
+ {
+ _hashStreamSpec->_hash->Final(_fi.IsDir, _isAltStream, _filePath);
+ _curSize = _hashStreamSpec->GetSize();
+ _curSizeDefined = true;
+ _hashStreamSpec->ReleaseStream();
+ _hashStreamWasUsed = false;
+ }
+
+ #endif
+
+ if (_outFileStream)
+ {
+ _outFileStreamSpec->SetTime(
+ (WriteCTime && _fi.CTimeDefined) ? &_fi.CTime : NULL,
+ (WriteATime && _fi.ATimeDefined) ? &_fi.ATime : NULL,
+ (WriteMTime && _fi.MTimeDefined) ? &_fi.MTime : (_arc->MTimeDefined ? &_arc->MTime : NULL));
+ _curSize = _outFileStreamSpec->ProcessedSize;
+ _curSizeDefined = true;
+ RINOK(_outFileStreamSpec->Close());
+ _outFileStream.Release();
+ }
+
+ #ifdef _USE_SECURITY_CODE
+ if (_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)
+ {
+ if (_isAltStream)
+ AltStreams_UnpackSize += _curSize;
+ else
+ UnpackSize += _curSize;
+ }
+
+ if (_fi.IsDir)
+ NumFolders++;
+ else if (_isAltStream)
+ NumAltStreams++;
+ else
+ NumFiles++;
+
+ if (_extractMode && _fi.AttribDefined)
+ SetFileAttrib(_diskFilePath, _fi.Attrib);
+ RINOK(_extractCallback2->SetOperationResult(operationResult, _encrypted));
+ return S_OK;
+ COM_TRY_END
+}
+
+/*
+STDMETHODIMP CArchiveExtractCallback::GetInStream(
+ const wchar_t *name, ISequentialInStream **inStream)
+{
+ COM_TRY_BEGIN
+ CInFileStream *inFile = new CInFileStream;
+ CMyComPtr<ISequentialInStream> inStreamTemp = inFile;
+ if (!inFile->Open(_srcDirectoryPrefix + name))
+ return ::GetLastError();
+ *inStream = inStreamTemp.Detach();
+ return S_OK;
+ COM_TRY_END
+}
+*/
+
+STDMETHODIMP CArchiveExtractCallback::CryptoGetTextPassword(BSTR *password)
+{
+ COM_TRY_BEGIN
+ if (!_cryptoGetTextPassword)
+ {
+ RINOK(_extractCallback2.QueryInterface(IID_ICryptoGetTextPassword,
+ &_cryptoGetTextPassword));
+ }
+ return _cryptoGetTextPassword->CryptoGetTextPassword(password);
+ COM_TRY_END
+}
+
+
+struct CExtrRefSortPair
+{
+ int Len;
+ int Index;
+
+ int Compare(const CExtrRefSortPair &a) const;
+};
+
+#define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; }
+
+int CExtrRefSortPair::Compare(const CExtrRefSortPair &a) const
+{
+ RINOZ(-MyCompare(Len, a.Len));
+ return MyCompare(Index, a.Index);
+}
+
+static int GetNumSlashes(const FChar *s)
+{
+ for (int numSlashes = 0;;)
+ {
+ FChar c = *s++;
+ if (c == 0)
+ return numSlashes;
+ if (
+ #ifdef _WIN32
+ c == FTEXT('\\') ||
+ #endif
+ c == FTEXT('/'))
+ numSlashes++;
+ }
+}
+
+HRESULT CArchiveExtractCallback::SetDirsTimes()
+{
+ CRecordVector<CExtrRefSortPair> pairs;
+ pairs.ClearAndSetSize(_extractedFolderPaths.Size());
+ unsigned i;
+
+ for (i = 0; i < _extractedFolderPaths.Size(); i++)
+ {
+ CExtrRefSortPair &pair = pairs[i];
+ pair.Index = i;
+ pair.Len = GetNumSlashes(_extractedFolderPaths[i]);
+ }
+
+ pairs.Sort2();
+
+ for (i = 0; i < pairs.Size(); i++)
+ {
+ int pairIndex = pairs[i].Index;
+ int index = _extractedFolderIndices[pairIndex];
+
+ FILETIME CTime;
+ FILETIME ATime;
+ FILETIME MTime;
+
+ bool CTimeDefined;
+ bool ATimeDefined;
+ bool MTimeDefined;
+
+ RINOK(GetTime(index, kpidCTime, CTime, CTimeDefined));
+ RINOK(GetTime(index, kpidATime, ATime, ATimeDefined));
+ RINOK(GetTime(index, kpidMTime, MTime, MTimeDefined));
+
+ // printf("\n%S", _extractedFolderPaths[pairIndex]);
+ SetDirTime(_extractedFolderPaths[pairIndex],
+ (WriteCTime && CTimeDefined) ? &CTime : NULL,
+ (WriteATime && ATimeDefined) ? &ATime : NULL,
+ (WriteMTime && MTimeDefined) ? &MTime : (_arc->MTimeDefined ? &_arc->MTime : NULL));
+ }
+ return S_OK;
+}
diff --git a/lzma/CPP/7zip/UI/Common/ArchiveExtractCallback.h b/lzma/CPP/7zip/UI/Common/ArchiveExtractCallback.h
new file mode 100644
index 0000000..7000532
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Common/ArchiveExtractCallback.h
@@ -0,0 +1,299 @@
+// 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;
+
+ CExtractNtOptions():
+ ReplaceColonForAltStream(false),
+ WriteToAltStreamIfColon(false)
+ {
+ SymLinks.Val = true;
+ HardLinks.Val = true;
+ AltStreams.Val = true;
+ }
+};
+
+#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
+
+class CArchiveExtractCallback:
+ public IArchiveExtractCallback,
+ // public IArchiveVolumeExtractCallback,
+ public ICryptoGetTextPassword,
+ public ICompressProgressInfo,
+ public CMyUnknownImp
+{
+ const CArc *_arc;
+ CExtractNtOptions _ntOptions;
+
+ const NWildcard::CCensorNode *_wildcardCensor;
+ CMyComPtr<IFolderArchiveExtractCallback> _extractCallback2;
+ CMyComPtr<ICompressProgressInfo> _compressProgress;
+ CMyComPtr<ICryptoGetTextPassword> _cryptoGetTextPassword;
+ FString _directoryPath;
+ FString _directoryPathFull;
+ NExtract::NPathMode::EEnum _pathMode;
+ NExtract::NOverwriteMode::EEnum _overwriteMode;
+
+ #ifndef _SFX
+
+ CMyComPtr<IFolderExtractToStreamCallback> ExtractToStreamCallback;
+ CGetProp *GetProp_Spec;
+ CMyComPtr<IGetProp> GetProp;
+
+ #endif
+
+ FString _diskFilePath;
+ UString _filePath;
+ UInt64 _position;
+ bool _isSplit;
+ bool _isAltStream;
+
+ 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;
+
+ bool IsDir;
+ } _fi;
+
+ UInt32 _index;
+ UInt64 _curSize;
+ bool _curSizeDefined;
+ COutFileStream *_outFileStreamSpec;
+ CMyComPtr<ISequentialOutStream> _outFileStream;
+
+ #ifndef _SFX
+
+ COutStreamWithHash *_hashStreamSpec;
+ CMyComPtr<ISequentialOutStream> _hashStream;
+ bool _hashStreamWasUsed;
+
+ #endif
+
+ UStringVector _removePathParts;
+ bool _use_baseParentFolder_mode;
+ UInt32 _baseParentFolder;
+
+ bool _stdOutMode;
+ bool _testMode;
+ bool _multiArchives;
+
+ CMyComPtr<ICompressProgressInfo> _localProgress;
+ UInt64 _packTotal;
+ UInt64 _unpTotal;
+
+ FStringVector _extractedFolderPaths;
+ CRecordVector<UInt32> _extractedFolderIndices;
+
+ #if defined(_WIN32) && !defined(UNDER_CE) && !defined(_SFX)
+ bool _saclEnabled;
+ #endif
+
+ void CreateComplexDirectory(const UStringVector &dirPathParts, FString &fullPath);
+ HRESULT GetTime(int index, PROPID propID, FILETIME &filetime, bool &filetimeIsDefined);
+ HRESULT GetUnpackSize();
+
+ HRESULT SendMessageError(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_IMP2(ICryptoGetTextPassword, ICompressProgressInfo)
+ // COM_INTERFACE_ENTRY(IArchiveVolumeExtractCallback)
+
+ INTERFACE_IArchiveExtractCallback(;)
+
+ STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
+
+ // IArchiveVolumeExtractCallback
+ // STDMETHOD(GetInStream)(const wchar_t *name, ISequentialInStream **inStream);
+
+ STDMETHOD(CryptoGetTextPassword)(BSTR *password);
+
+ CArchiveExtractCallback();
+
+ void InitForMulti(bool multiArchives,
+ NExtract::NPathMode::EEnum pathMode,
+ NExtract::NOverwriteMode::EEnum overwriteMode)
+ {
+ _multiArchives = multiArchives;
+ _pathMode = pathMode;
+ _overwriteMode = overwriteMode;
+ 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,
+ UInt64 packSize);
+
+ #ifdef SUPPORT_LINKS
+private:
+ CHardLinks _hardLinks;
+public:
+ // call PrepareHardLinks() after Init()
+ HRESULT PrepareHardLinks(const CRecordVector<UInt32> *realIndices); // NULL means all items
+ #endif
+
+ // call it after Init()
+
+ void SetBaseParentFolderIndex(UInt32 indexInArc)
+ {
+ _use_baseParentFolder_mode = true;
+ _baseParentFolder = indexInArc;
+ }
+
+ HRESULT SetDirsTimes();
+};
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Common/ArchiveName.cpp b/lzma/CPP/7zip/UI/Common/ArchiveName.cpp
new file mode 100644
index 0000000..cabc955
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Common/ArchiveName.cpp
@@ -0,0 +1,70 @@
+// ArchiveName.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Windows/FileDir.h"
+
+#include "ExtractingFilePath.h"
+#include "ArchiveName.h"
+
+using namespace NWindows;
+
+UString CreateArchiveName(const NFile::NFind::CFileInfo fileInfo, bool keepName)
+{
+ FString resultName = fileInfo.Name;
+ if (!fileInfo.IsDir() && !keepName)
+ {
+ int dotPos = resultName.ReverseFind(FTEXT('.'));
+ if (dotPos > 0)
+ {
+ FString archiveName2 = resultName.Left(dotPos);
+ if (archiveName2.ReverseFind(FTEXT('.')) < 0)
+ resultName = archiveName2;
+ }
+ }
+ return GetCorrectFsPath(fs2us(resultName));
+}
+
+static FString CreateArchiveName2(const FString &srcName, bool fromPrev, bool keepName)
+{
+ FString resultName = FTEXT("Archive");
+ if (fromPrev)
+ {
+ FString dirPrefix;
+ if (NFile::NDir::GetOnlyDirPrefix(srcName, dirPrefix))
+ {
+ if (dirPrefix.Len() > 0)
+ if (dirPrefix.Back() == FCHAR_PATH_SEPARATOR)
+ {
+ dirPrefix.DeleteBack();
+ NFile::NFind::CFileInfo fileInfo;
+ if (fileInfo.Find(dirPrefix))
+ resultName = fileInfo.Name;
+ }
+ }
+ }
+ else
+ {
+ NFile::NFind::CFileInfo fileInfo;
+ if (!fileInfo.Find(srcName))
+ // return resultName;
+ return srcName;
+ resultName = fileInfo.Name;
+ if (!fileInfo.IsDir() && !keepName)
+ {
+ int dotPos = resultName.ReverseFind('.');
+ if (dotPos > 0)
+ {
+ FString archiveName2 = resultName.Left(dotPos);
+ if (archiveName2.ReverseFind(FTEXT('.')) < 0)
+ resultName = archiveName2;
+ }
+ }
+ }
+ return resultName;
+}
+
+UString CreateArchiveName(const UString &srcName, bool fromPrev, bool keepName)
+{
+ return GetCorrectFsPath(fs2us(CreateArchiveName2(us2fs(srcName), fromPrev, keepName)));
+}
diff --git a/lzma/CPP/7zip/UI/Common/ArchiveName.h b/lzma/CPP/7zip/UI/Common/ArchiveName.h
new file mode 100644
index 0000000..e67cf1e
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Common/ArchiveName.h
@@ -0,0 +1,13 @@
+// ArchiveName.h
+
+#ifndef __ARCHIVE_NAME_H
+#define __ARCHIVE_NAME_H
+
+#include "../../../Common/MyString.h"
+
+#include "../../../Windows/FileFind.h"
+
+UString CreateArchiveName(const UString &srcName, bool fromPrev, bool keepName);
+UString CreateArchiveName(const NWindows::NFile::NFind::CFileInfo fileInfo, bool keepName);
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp b/lzma/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp
new file mode 100644
index 0000000..f268dd9
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp
@@ -0,0 +1,125 @@
+// 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;
+ }
+ 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;
+ }
+};
+
+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());
+ }
+ FString fullPath;
+ if (!NFile::NName::GetFullPath(_folderPrefix, us2fs(name), 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))
+ return ::GetLastError();
+
+ FileSizes.Add(_fileInfo.Size);
+ FileNames.Add(name);
+ 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;
+ return Callback->Open_CryptoGetTextPassword(password);
+ COM_TRY_END
+}
+#endif
diff --git a/lzma/CPP/7zip/UI/Common/ArchiveOpenCallback.h b/lzma/CPP/7zip/UI/Common/ArchiveOpenCallback.h
new file mode 100644
index 0000000..f7b3618
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Common/ArchiveOpenCallback.h
@@ -0,0 +1,111 @@
+// 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_ClearPasswordWasAskedFlag() 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; \
+ 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:
+ #ifndef _NO_CRYPTO
+ MY_UNKNOWN_IMP3(
+ IArchiveOpenVolumeCallback,
+ ICryptoGetTextPassword,
+ IArchiveOpenSetSubArchiveName
+ )
+ #else
+ MY_UNKNOWN_IMP2(
+ IArchiveOpenVolumeCallback,
+ IArchiveOpenSetSubArchiveName
+ )
+ #endif
+
+ 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;
+
+ IOpenCallbackUI *Callback;
+ CMyComPtr<IArchiveOpenCallback> ReOpenCallback;
+ // UInt64 TotalSize;
+
+ COpenCallbackImp(): Callback(NULL) {}
+ 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;
+ }
+ bool SetSecondFileInfo(CFSTR newName)
+ {
+ return _fileInfo.Find(newName) && !_fileInfo.IsDir();
+ }
+};
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Common/Bench.cpp b/lzma/CPP/7zip/UI/Common/Bench.cpp
new file mode 100644
index 0000000..d8dc3a8
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Common/Bench.cpp
@@ -0,0 +1,2544 @@
+// Bench.cpp
+
+#include "StdAfx.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/Alloc.h"
+#include "../../../../C/CpuArch.h"
+
+#if !defined(_7ZIP_ST) || defined(_WIN32)
+#include "../../../Windows/System.h"
+#endif
+
+#ifndef _7ZIP_ST
+#include "../../../Windows/Synchronization.h"
+#include "../../../Windows/Thread.h"
+#endif
+
+#include "../../../Common/IntToString.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 UInt64 kComplexInCommands = (UInt64)1 <<
+ #ifdef UNDER_CE
+ 31;
+ #else
+ 34;
+ #endif
+
+static const UInt64 kComplexInSeconds = 4;
+
+static void SetComplexCommands(UInt32 complexInSeconds, UInt64 cpuFreq, UInt64 &complexInCommands)
+{
+ complexInCommands = kComplexInCommands;
+ const UInt64 kMinFreq = (UInt64)1000000 * 30;
+ const UInt64 kMaxFreq = (UInt64)1000000 * 20000;
+ if (cpuFreq < kMinFreq) cpuFreq = kMinFreq;
+ if (cpuFreq < kMaxFreq)
+ {
+ 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;
+
+class CBaseRandomGenerator
+{
+ UInt32 A1;
+ UInt32 A2;
+public:
+ CBaseRandomGenerator() { Init(); }
+ void Init() { A1 = 362436069; A2 = 521288629;}
+ UInt32 GetRnd()
+ {
+ return
+ ((A1 = 36969 * (A1 & 0xffff) + (A1 >> 16)) << 16) +
+ ((A2 = 18000 * (A2 & 0xffff) + (A2 >> 16)) );
+ }
+};
+
+class CBenchBuffer
+{
+public:
+ size_t BufferSize;
+ Byte *Buffer;
+
+ CBenchBuffer(): Buffer(0) {}
+ virtual ~CBenchBuffer() { Free(); }
+ void Free()
+ {
+ ::MidFree(Buffer);
+ Buffer = 0;
+ }
+ bool Alloc(size_t bufferSize)
+ {
+ if (Buffer != 0 && BufferSize == bufferSize)
+ return true;
+ Free();
+ Buffer = (Byte *)::MidAlloc(bufferSize);
+ BufferSize = bufferSize;
+ return (Buffer != 0 || bufferSize == 0);
+ }
+};
+
+class CBenchRandomGenerator: public CBenchBuffer
+{
+ CBaseRandomGenerator *RG;
+public:
+ void Set(CBaseRandomGenerator *rg) { RG = rg; }
+ UInt32 GetVal(UInt32 &res, unsigned numBits)
+ {
+ UInt32 val = res & (((UInt32)1 << numBits) - 1);
+ res >>= numBits;
+ return val;
+ }
+ UInt32 GetLen(UInt32 &res)
+ {
+ UInt32 len = GetVal(res, 2);
+ return GetVal(res, 1 + len);
+ }
+
+ void GenerateSimpleRandom()
+ {
+ for (UInt32 i = 0; i < BufferSize; i++)
+ Buffer[i] = (Byte)RG->GetRnd();
+ }
+
+ void Generate(unsigned dictBits)
+ {
+ UInt32 pos = 0;
+ UInt32 rep0 = 1;
+ while (pos < BufferSize)
+ {
+ UInt32 res = RG->GetRnd();
+ res >>= 1;
+ if (GetVal(res, 1) == 0 || pos < 1024)
+ Buffer[pos++] = (Byte)(res & 0xFF);
+ else
+ {
+ UInt32 len;
+ len = 1 + GetLen(res);
+ if (GetVal(res, 3) != 0)
+ {
+ len += GetLen(res);
+ do
+ {
+ UInt32 ppp = GetVal(res, 5) + 6;
+ res = RG->GetRnd();
+ if (ppp > dictBits)
+ continue;
+ rep0 = /* (1 << ppp) +*/ GetVal(res, ppp);
+ res = RG->GetRnd();
+ }
+ while (rep0 >= pos);
+ rep0++;
+ }
+
+ for (UInt32 i = 0; i < len && pos < BufferSize; i++, pos++)
+ Buffer[pos] = Buffer[pos - rep0];
+ }
+ }
+ }
+};
+
+
+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 != NULL)
+ *processedSize = size;
+ return S_OK;
+}
+
+class CBenchmarkOutStream:
+ public ISequentialOutStream,
+ public CBenchBuffer,
+ public CMyUnknownImp
+{
+ // bool _overflow;
+public:
+ UInt32 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;
+ }
+ 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 = BufferSize - Pos;
+ if (curSize > size)
+ curSize = size;
+ if (RealCopy)
+ memcpy(Buffer + Pos, data, curSize);
+ if (CalcCrc)
+ Crc = CrcUpdate(Crc, data, curSize);
+ Pos += (UInt32)curSize;
+ if(processedSize != NULL)
+ *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 != NULL)
+ *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;
+ HRESULT Res;
+ IBenchCallback *Callback;
+
+ CBenchProgressInfo(): Callback(0) {}
+ 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 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 (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);
+}
+
+struct CEncoderInfo;
+
+struct CEncoderInfo
+{
+ #ifndef _7ZIP_ST
+ NWindows::CThread thread[2];
+ UInt32 NumDecoderSubThreads;
+ #endif
+ CMyComPtr<ICompressCoder> _encoder;
+ CMyComPtr<ICompressFilter> _encoderFilter;
+ CBenchProgressInfo *progressInfoSpec[2];
+ CMyComPtr<ICompressProgressInfo> progressInfo[2];
+ UInt64 NumIterations;
+ #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;
+ #ifdef USE_ALLOCA
+ size_t AllocaSize;
+ #endif
+ bool CallbackMode;
+ };
+ CDecoderInfo decodersInfo[2];
+
+ CMyComPtr<ICompressCoder> _decoders[2];
+ CMyComPtr<ICompressFilter> _decoderFilter;
+
+ HRESULT Results[2];
+ CBenchmarkOutStream *outStreamSpec;
+ CMyComPtr<ISequentialOutStream> outStream;
+ IBenchCallback *callback;
+ IBenchPrintCallback *printCallback;
+ UInt32 crc;
+ UInt32 kBufferSize;
+ UInt32 compressedSize;
+ CBenchRandomGenerator rg;
+ CBenchBuffer rgCopy; // it must be 16-byte aligned !!!
+ CBenchmarkOutStream *propStreamSpec;
+ CMyComPtr<ISequentialOutStream> propStream;
+
+ // for decode
+ COneMethodInfo _method;
+ UInt32 _uncompressedDataSize;
+
+ HRESULT Init(
+ const COneMethodInfo &method,
+ UInt32 uncompressedDataSize,
+ unsigned generateDictBits,
+ CBaseRandomGenerator *rg);
+ HRESULT Encode();
+ HRESULT Decode(UInt32 decoderIndex);
+
+ CEncoderInfo():
+ CheckCrc_Enc(true),
+ CheckCrc_Dec(true),
+ outStreamSpec(0), callback(0), printCallback(0), propStreamSpec(0) {}
+
+ #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();
+ encoder->Results[0] = res;
+ }
+ catch(...)
+ {
+ res = E_FAIL;
+ }
+ if (res != S_OK)
+ encoder->progressInfoSpec[0]->Status->SetResult(res);
+ 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()
+ {
+ return thread[0].Create(EncodeThreadFunction, this);
+ }
+
+ HRESULT CreateDecoderThread(int 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
+};
+
+static const UInt32 k_LZMA = 0x030101;
+
+HRESULT CEncoderInfo::Init(
+ const COneMethodInfo &method,
+ UInt32 uncompressedDataSize,
+ unsigned generateDictBits,
+ CBaseRandomGenerator *rgLoc)
+{
+ rg.Set(rgLoc);
+ kBufferSize = uncompressedDataSize;
+ UInt32 kCompressedBufferSize =
+ kBufferSize + kCompressedAdditionalSize;
+ // (kBufferSize - kBufferSize / 4) + kCompressedAdditionalSize;
+ if (!rg.Alloc(kBufferSize))
+ return E_OUTOFMEMORY;
+ if (generateDictBits == 0)
+ rg.GenerateSimpleRandom();
+ else
+ rg.Generate(generateDictBits);
+ crc = CrcCalc(rg.Buffer, rg.BufferSize);
+
+ if (_encoderFilter)
+ {
+ if (!rgCopy.Alloc(rg.BufferSize))
+ return E_OUTOFMEMORY;
+ }
+
+
+ outStreamSpec = new CBenchmarkOutStream;
+ if (!outStreamSpec->Alloc(kCompressedBufferSize))
+ return E_OUTOFMEMORY;
+
+ outStream = outStreamSpec;
+
+ propStreamSpec = 0;
+ if (!propStream)
+ {
+ propStreamSpec = new CBenchmarkOutStream;
+ propStream = propStreamSpec;
+ }
+ if (!propStreamSpec->Alloc(kMaxLzmaPropSize))
+ return E_OUTOFMEMORY;
+ 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 = uncompressedDataSize;
+ 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!
+ CBenchmarkInStream *inStreamSpec = new CBenchmarkInStream;
+ CMyComPtr<ISequentialInStream> inStream = inStreamSpec;
+ Byte temp[16];
+ memset(temp, 0, sizeof(temp));
+ inStreamSpec->Init(temp, sizeof(temp));
+
+ CCrcOutStream *outStreamSpec = new CCrcOutStream;
+ CMyComPtr<ISequentialOutStream> outStream = outStreamSpec;
+ outStreamSpec->Init();
+
+ if (_encoderFilter)
+ {
+ _encoderFilter->Init();
+ _encoderFilter->Filter(temp, sizeof(temp));
+ }
+ else
+ {
+ RINOK(_encoder->Code(inStream, outStream, 0, 0, NULL));
+ }
+ }
+ }
+
+ }
+ return S_OK;
+}
+
+HRESULT CEncoderInfo::Encode()
+{
+ 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(rgCopy.Buffer, rg.Buffer, rg.BufferSize);
+ _encoderFilter->Init();
+ _encoderFilter->Filter(rgCopy.Buffer, (UInt32)rg.BufferSize);
+ RINOK(WriteStream(outStream, rgCopy.Buffer, rg.BufferSize));
+ }
+ else
+ {
+ inStreamSpec->Init(rg.Buffer, rg.BufferSize);
+ RINOK(_encoder->Code(inStream, outStream, 0, 0, progressInfo[0]));
+ }
+
+ 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 += rg.BufferSize;
+ 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(propStreamSpec->Buffer, 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(outStreamSpec->Buffer, compressedSize);
+ crcOutStreamSpec->Init();
+
+ UInt64 outSize = kBufferSize;
+ crcOutStreamSpec->CalcCrc = ((i & 0x7F) == 0 || CheckCrc_Dec);
+ if (_decoderFilter)
+ {
+ if (compressedSize > rgCopy.BufferSize)
+ return E_FAIL;
+ memcpy(rgCopy.Buffer, outStreamSpec->Buffer, compressedSize);
+ _decoderFilter->Init();
+ _decoderFilter->Filter(rgCopy.Buffer, compressedSize);
+ RINOK(WriteStream(crcOutStream, rgCopy.Buffer, rg.BufferSize));
+ }
+ 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(0) { 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);
+}
+
+static HRESULT MethodBench(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ UInt64 complexInCommands,
+ bool oldLzmaBenchMode,
+ UInt32 numThreads,
+ const COneMethodInfo &method2,
+ UInt32 uncompressedDataSize,
+ unsigned generateDictBits,
+ IBenchPrintCallback *printCallback,
+ IBenchCallback *callback,
+ CBenchProps *benchProps)
+{
+ COneMethodInfo method = method2;
+ UInt64 methodId;
+ UInt32 numInStreams, numOutStreams;
+ if (!FindMethod(
+ EXTERNAL_CODECS_LOC_VARS
+ method.MethodName, methodId, numInStreams, numOutStreams))
+ return E_NOTIMPL;
+ if (numInStreams != 1 || numOutStreams != 1)
+ return E_INVALIDARG;
+
+ UInt32 numEncoderThreads = 1;
+ UInt32 numSubDecoderThreads = 1;
+
+ #ifndef _7ZIP_ST
+ numEncoderThreads = numThreads;
+
+ if (oldLzmaBenchMode && methodId == k_LZMA)
+ {
+ bool fixedNumber;
+ UInt32 numLzmaThreads = method.Get_Lzma_NumThreads(fixedNumber);
+ if (!fixedNumber && numThreads == 1)
+ method.AddNumThreadsProp(1);
+ if (numThreads > 1 && numLzmaThreads > 1)
+ {
+ numEncoderThreads = numThreads / 2;
+ numSubDecoderThreads = 2;
+ }
+ }
+ #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;
+
+ CMyComPtr<ICompressCoder2> coder2;
+ RINOK(CreateCoder(EXTERNAL_CODECS_LOC_VARS methodId,
+ encoder._encoderFilter, encoder._encoder, coder2, true, false));
+ if (!encoder._encoder && !encoder._encoderFilter)
+ return E_NOTIMPL;
+ // encoder._encoderFilter.Release(); // we can disable filter to check the speed of FilterCoder.
+
+ 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++)
+ {
+ CMyComPtr<ICompressCoder2> coder2de;
+ CMyComPtr<ICompressCoder> &decoder = encoder._decoders[j];
+ RINOK(CreateCoder(EXTERNAL_CODECS_LOC_VARS methodId,
+ encoder._decoderFilter, decoder, coder2de, false, false));
+ if (!encoder._decoderFilter && !decoder)
+ return E_NOTIMPL;
+ }
+ }
+
+ CBaseRandomGenerator rg;
+ rg.Init();
+ for (i = 0; i < numEncoderThreads; i++)
+ {
+ CEncoderInfo &encoder = encoders[i];
+ encoder._method = method;
+ encoder._uncompressedDataSize = uncompressedDataSize;
+ RINOK(encoders[i].Init(method, uncompressedDataSize, generateDictBits, &rg));
+ }
+
+ CBenchProgressStatus status;
+ status.Res = S_OK;
+ status.EncodeMode = true;
+
+ for (i = 0; i < numEncoderThreads; i++)
+ {
+ CEncoderInfo &encoder = encoders[i];
+ encoder.NumIterations = GetNumIterations(benchProps->GeComprCommands(uncompressedDataSize), complexInCommands);
+
+ 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;
+ bpi->SetStartTime();
+ }
+
+ #ifndef _7ZIP_ST
+ if (numEncoderThreads > 1)
+ {
+ #ifdef USE_ALLOCA
+ encoder.AllocaSize = (i * 16 * 21) & 0x7FF;
+ #endif
+ RINOK(encoder.CreateEncoderThread())
+ }
+ else
+ #endif
+ {
+ RINOK(encoder.Encode());
+ }
+ }
+ #ifndef _7ZIP_ST
+ if (numEncoderThreads > 1)
+ for (i = 0; i < numEncoderThreads; i++)
+ encoders[i].thread[0].Wait();
+ #endif
+
+ 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;
+ }
+ RINOK(callback->SetEncodeResult(info, true));
+
+
+ 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;
+}
+
+
+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)
+{
+ const UInt32 kBufferSize = dictionary;
+ const UInt32 kCompressedBufferSize = (kBufferSize / 2);
+ UInt32 numSubThreads = (numThreads > 1) ? 2 : 1;
+ UInt32 numBigThreads = numThreads / numSubThreads;
+ return (kBufferSize + kCompressedBufferSize +
+ GetLZMAUsage((numThreads > 1), 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)
+ {
+ // printf(" %08X ", sum);
+ 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;
+
+static UInt32 CountCpuFreq(UInt32 sum, UInt32 num, UInt32 val)
+{
+ for (UInt32 i = 0; i < num; i++)
+ {
+ YY7
+ }
+ return sum;
+}
+
+#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(0), 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;
+
+ void Wait()
+ {
+ Thread.Wait();
+ Thread.Close();
+ }
+};
+
+static THREAD_FUNC_DECL CrcThreadFunction(void *param)
+{
+ CCrcInfo *p = (CCrcInfo *)param;
+ 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(0), 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, UInt32 size)
+{
+ UInt32 crc = CRC_INIT_VAL;;
+ for (UInt32 i = 0; i < size; i++)
+ crc = CRC_UPDATE_BYTE(crc, buf[i]);
+ return CRC_GET_DIGEST(crc);
+}
+
+static void RandGen(Byte *buf, UInt32 size, CBaseRandomGenerator &RG)
+{
+ for (UInt32 i = 0; i < size; i++)
+ buf[i] = (Byte)RG.GetRnd();
+}
+
+static UInt32 RandGenCrc(Byte *buf, UInt32 size, CBaseRandomGenerator &RG)
+{
+ RandGen(buf, size, RG);
+ return CrcCalc1(buf, size);
+}
+
+bool CrcInternalTest()
+{
+ CBenchBuffer buffer;
+ const UInt32 kBufferSize0 = (1 << 8);
+ const UInt32 kBufferSize1 = (1 << 10);
+ const UInt32 kCheckSize = (1 << 5);
+ if (!buffer.Alloc(kBufferSize0 + kBufferSize1))
+ return false;
+ Byte *buf = buffer.Buffer;
+ UInt32 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 (UInt32 j = 0; j < kCheckSize; j++)
+ if (CrcCalc1(buf + i, j) != CrcCalc(buf + i, j))
+ return false;
+ return true;
+}
+
+struct CBenchMethod
+{
+ unsigned DictBits;
+ UInt32 EncComplex;
+ UInt32 DecComplexCompr;
+ UInt32 DecComplexUnc;
+ const char *Name;
+};
+
+static const CBenchMethod g_Bench[] =
+{
+ { 17, 357, 145, 20, "LZMA:x1" },
+ { 24, 1220, 145, 20, "LZMA:x5:mt1" },
+ { 24, 1220, 145, 20, "LZMA:x5:mt2" },
+ { 16, 124, 40, 14, "Deflate:x1" },
+ { 16, 376, 40, 14, "Deflate:x5" },
+ { 16, 1082, 40, 14, "Deflate:x7" },
+ { 17, 422, 40, 14, "Deflate64:x5" },
+ { 15, 590, 69, 69, "BZip2:x1" },
+ { 19, 815, 122, 122, "BZip2:x5" },
+ { 19, 815, 122, 122, "BZip2:x5:mt2" },
+ { 19, 2530, 122, 122, "BZip2:x7" },
+ { 18, 1010, 0, 1150, "PPMD:x1" },
+ { 22, 1655, 0, 1830, "PPMD:x5" },
+ { 0, 6, 0, 6, "Delta:4" },
+ { 0, 4, 0, 4, "BCJ" },
+ { 0, 24, 0, 24, "AES256CBC:1" },
+ { 0, 8, 0, 2, "AES256CBC:2" }
+};
+
+struct CBenchHash
+{
+ UInt32 Complex;
+ UInt32 CheckSum;
+ const char *Name;
+};
+
+static const CBenchHash g_Hash[] =
+{
+ { 558, 0x8F8FEDAB, "CRC32:4" },
+ { 339, 0x8F8FEDAB, "CRC32:8" },
+ { 512, 0xDF1C17CC, "CRC64" },
+ { 11900, 0x2D79FF2E, "SHA256" },
+ { 5230, 0x4C25132B, "SHA1" }
+};
+
+struct CTotalBenchRes
+{
+ UInt64 NumIterations;
+ UInt64 Rating;
+ UInt64 Usage;
+ UInt64 RPU;
+ void Init() { NumIterations = 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);
+ NumIterations = (r1.NumIterations + r2.NumIterations);
+ }
+};
+
+static void PrintNumber(IBenchPrintCallback &f, UInt64 value, int size)
+{
+ char s[128];
+ int startPos = (int)sizeof(s) - 32;
+ memset(s, ' ', startPos);
+ ConvertUInt64ToString(value, s + startPos);
+ // if (withSpace)
+ {
+ startPos--;
+ size++;
+ }
+ int len = (int)strlen(s + startPos);
+ if (size > len)
+ {
+ startPos -= (size - len);
+ if (startPos < 0)
+ startPos = 0;
+ }
+ f.Print(s + startPos);
+}
+
+static const int kFieldSize_Name = 12;
+static const int kFieldSize_SmallName = 4;
+static const int kFieldSize_Speed = 9;
+static const int kFieldSize_Usage = 5;
+static const int kFieldSize_RU = 6;
+static const int kFieldSize_Rating = 6;
+static const int kFieldSize_EU = 5;
+static const int kFieldSize_Effec = 5;
+
+static const int kFieldSize_TotalSize = 4 + kFieldSize_Speed + kFieldSize_Usage + kFieldSize_RU + kFieldSize_Rating;
+static const int kFieldSize_EUAndEffec = 2 + kFieldSize_EU + kFieldSize_Effec;
+
+
+static void PrintRating(IBenchPrintCallback &f, UInt64 rating, int size)
+{
+ PrintNumber(f, (rating + 500000) / 1000000, size);
+}
+
+
+static void PrintPercents(IBenchPrintCallback &f, UInt64 val, UInt64 divider, int size)
+{
+ PrintNumber(f, (val * 100 + divider / 2) / divider, size);
+}
+
+static void PrintChars(IBenchPrintCallback &f, char c, int size)
+{
+ char s[256];
+ memset(s, (Byte)c, size);
+ s[size] = 0;
+ f.Print(s);
+}
+
+static void PrintSpaces(IBenchPrintCallback &f, int 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, 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->NumIterations++;
+ res->RPU += rpu;
+ res->Rating += rating;
+ res->Usage += usage;
+ }
+}
+
+static void PrintTotals(IBenchPrintCallback &f, bool showFreq, UInt64 cpuFreq, const CTotalBenchRes &res)
+{
+ PrintSpaces(f, 1 + kFieldSize_Speed);
+ UInt64 numIterations = res.NumIterations;
+ if (numIterations == 0)
+ numIterations = 1;
+ PrintResults(f, res.Usage / numIterations, res.RPU / numIterations, res.Rating / numIterations, showFreq, cpuFreq);
+}
+
+static void PrintRequirements(IBenchPrintCallback &f, const char *sizeString, UInt64 size, const char *threadsString, UInt32 numThreads)
+{
+ f.Print("RAM ");
+ f.Print(sizeString);
+ PrintNumber(f, (size >> 20), 6);
+ f.Print(" MB, # ");
+ f.Print(threadsString);
+ PrintNumber(f, numThreads, 3);
+ f.NewLine();
+}
+
+struct CBenchCallbackToPrint: public IBenchCallback
+{
+ CBenchProps BenchProps;
+ CTotalBenchRes EncodeRes;
+ CTotalBenchRes DecodeRes;
+ IBenchPrintCallback *_file;
+ UInt32 DictSize;
+
+ bool Use2Columns;
+ int NameFieldSize;
+
+ bool ShowFreq;
+ UInt64 CpuFreq;
+
+ CBenchCallbackToPrint(): Use2Columns(false), NameFieldSize(0), ShowFreq(false), 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);
+ 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, rating, ShowFreq, CpuFreq, &EncodeRes);
+ }
+ return S_OK;
+}
+
+static const char *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
+ {
+ _file->NewLine();
+ PrintSpaces(*_file, NameFieldSize);
+ }
+ CBenchInfo info2 = info;
+ info2.UnpackSize *= info2.NumIterations;
+ info2.PackSize *= info2.NumIterations;
+ info2.NumIterations = 1;
+ PrintResults(_file, info2, 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, UInt32 unpackSize, IBenchPrintCallback *printCallback, CBenchCallbackToPrint *callback)
+{
+ for (unsigned i = 0; i < ARRAY_SIZE(g_Bench); i++)
+ {
+ 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(L"", propVariant));
+
+ UInt32 unpackSize2 = unpackSize;
+ if (!forceUnpackSize && bench.DictBits == 0)
+ unpackSize2 = kFilterUnpackSize;
+
+ HRESULT res = MethodBench(
+ EXTERNAL_CODECS_LOC_VARS
+ complexInCommands,
+ false, numThreads, method, unpackSize2, 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 &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, rating, showFreq, showFreq ? 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,
+ 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
+
+ UString methodName = method.MethodName;
+ // methodName.RemoveChar(L'-');
+ CMethodId hashID;
+ if (!FindHashMethod(
+ EXTERNAL_CODECS_LOC_VARS
+ methodName, hashID))
+ return E_NOTIMPL;
+
+ CBenchBuffer buffer;
+ size_t totalSize = (size_t)bufferSize * numThreads;
+ if (totalSize / numThreads != bufferSize)
+ return E_OUTOFMEMORY;
+ if (!buffer.Alloc(totalSize))
+ return E_OUTOFMEMORY;
+
+ Byte *buf = buffer.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];
+ UString 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));
+ }
+ }
+ 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;
+ UString 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, 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(L"", propVariant));
+
+ UInt64 speed;
+ HRESULT res = CrcBench(
+ EXTERNAL_CODECS_LOC_VARS
+ complexInCommands,
+ numThreads, bufSize,
+ speed,
+ bench.Complex, &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 wchar_t *shortName)
+{
+ for (;;)
+ {
+ wchar_t c2 = *shortName++;
+ if (c2 == 0)
+ return true;
+ char c1 = *fullName++;
+ if ((unsigned char)MyCharLower_Ascii(c1) != MyCharLower_Ascii(c2))
+ return false;
+ }
+}
+
+HRESULT Bench(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ IBenchPrintCallback *printCallback,
+ IBenchCallback *benchCallback,
+ const CObjectVector<CProperty> &props,
+ UInt32 numIterations,
+ bool multiDict)
+{
+ if (!CrcInternalTest())
+ return S_FALSE;
+
+ UInt32 numCPUs = 1;
+ UInt64 ramSize = (UInt64)512 << 20;
+ #ifndef _7ZIP_ST
+ numCPUs = NSystem::GetNumberOfProcessors();
+ #endif
+ #if !defined(_7ZIP_ST) || defined(_WIN32)
+ ramSize = NSystem::GetRamSize();
+ #endif
+ UInt32 numThreads = numCPUs;
+
+ UInt32 testTime = kComplexInSeconds;
+
+ COneMethodInfo method;
+ unsigned i;
+ for (i = 0; i < props.Size(); i++)
+ {
+ const CProperty &property = props[i];
+ NCOM::CPropVariant propVariant;
+ UString name = property.Name;
+ name.MakeLower_Ascii();
+ if (!property.Value.IsEmpty())
+ ParseNumberString(property.Value, propVariant);
+ if (name.IsEqualTo("testtime"))
+ {
+ RINOK(ParsePropToUInt32(L"", propVariant, testTime));
+ continue;
+ }
+ if (name.IsPrefixedBy(L"mt"))
+ {
+ #ifndef _7ZIP_ST
+ RINOK(ParseMtProp(name.Ptr(2), propVariant, numCPUs, numThreads));
+ #endif
+ continue;
+ }
+ RINOK(method.ParseMethodFromPROPVARIANT(name, propVariant));
+ }
+
+ if (printCallback)
+ {
+ printCallback->Print("CPU Freq:");
+ }
+
+ UInt64 complexInCommands = kComplexInCommands;
+
+ if (printCallback)
+ {
+ UInt64 numMilCommands = (1 << 6);
+
+ for (int jj = 0;; jj++)
+ {
+ UInt64 start = ::GetTimeCount();
+ UInt32 sum = (UInt32)start;
+ sum = CountCpuFreq(sum, (UInt32)(numMilCommands * 1000000 / kNumFreqCommands), g_BenchCpuFreqTemp);
+ start = ::GetTimeCount() - start;
+ if (start == 0)
+ start = 1;
+ UInt64 freq = GetFreq();
+ UInt64 mipsVal = numMilCommands * freq / start;
+ if (printCallback)
+ PrintNumber(*printCallback, mipsVal, 5 + ((sum >> 31) & 1));
+ if (jj >= 3)
+ {
+ SetComplexCommands(testTime, mipsVal * 1000000, complexInCommands);
+ if (jj >= 8 || start >= freq)
+ break;
+ // break; // change it
+ numMilCommands <<= 1;
+ }
+ }
+ }
+ if (printCallback)
+ {
+ printCallback->NewLine();
+ printCallback->NewLine();
+ PrintRequirements(*printCallback, "size: ", ramSize, "CPU hardware threads:", numCPUs);
+ }
+
+ if (numThreads < 1 || numThreads > kNumThreadsMax)
+ return E_INVALIDARG;
+
+ UInt32 dict;
+ bool dictIsDefined = method.Get_DicSize(dict);
+
+ if (method.MethodName.IsEmpty())
+ method.MethodName = L"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, numThreads,
+ method, uncompressedDataSize,
+ kOldLzmaDictBits, printCallback, benchCallback, &benchProps);
+ }
+
+ UString methodName = method.MethodName;
+ if (methodName.IsEqualToNoCase(L"CRC"))
+ methodName = L"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;
+ {
+ for (unsigned i = 0; i < ARRAY_SIZE(g_Hash); i++)
+ {
+ const CBenchHash &h = g_Hash[i];
+ if (AreSameMethodNames(h.Name, methodName))
+ {
+ complexity = h.Complex;
+ checkSum = &h.CheckSum;
+ if (strcmp(h.Name, "CRC32:4") != 0)
+ break;
+ }
+ }
+ }
+
+ f.NewLine();
+ f.Print("Size");
+ const int kFieldSize_CrcSpeed = 6;
+ unsigned numThreadsTests = 0;
+ for (;;)
+ {
+ UInt32 t = GetNumThreadsNext(numThreadsTests, numThreads);
+ PrintNumber(f, t, kFieldSize_CrcSpeed);
+ numThreadsTests++;
+ if (t >= numThreads)
+ 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);
+ int 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, numThreads);
+ UInt64 speed = 0;
+ RINOK(CrcBench(EXTERNAL_CODECS_LOC_VARS complexInCommands,
+ t, bufSize, speed, complexity,
+ (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;
+
+ CBenchCallbackToPrint callback;
+ callback.Init();
+ callback._file = printCallback;
+
+ if (!dictIsDefined)
+ {
+ int dicSizeLog;
+ for (dicSizeLog = 25; dicSizeLog > kBenchMinDicLogSize; dicSizeLog--)
+ if (GetBenchMemoryUsage(numThreads, ((UInt32)1 << dicSizeLog)) + (8 << 20) <= ramSize)
+ break;
+ dict = (1 << dicSizeLog);
+ }
+
+ IBenchPrintCallback &f = *printCallback;
+ PrintRequirements(f, "usage:", GetBenchMemoryUsage(numThreads, dict), "Benchmark threads: ", numThreads);
+
+ bool totalBenchMode = (method.MethodName == L"*");
+ 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;
+ }
+
+ int 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, "KB/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 (totalBenchMode)
+ {
+ if (!dictIsDefined)
+ dict =
+ #ifdef UNDER_CE
+ (UInt64)1 << 20;
+ #else
+ (UInt64)1 << 24;
+ #endif
+ for (UInt32 i = 0; i < numIterations; i++)
+ {
+ if (i != 0)
+ printCallback->NewLine();
+ HRESULT res;
+
+ int freqTest;
+ const int kNumCpuTests = 3;
+ for (freqTest = 0; freqTest < kNumCpuTests; freqTest++)
+ {
+ PrintLeft(f, "CPU", kFieldSize_Name);
+ UInt32 resVal;
+ RINOK(FreqBench(complexInCommands, numThreads, printCallback, freqTest == kNumCpuTests - 1, cpuFreq, resVal));
+ callback.NewLine();
+
+ if (freqTest == kNumCpuTests - 1)
+ SetComplexCommands(testTime, cpuFreq, complexInCommands);
+ }
+ callback.NewLine();
+
+ callback.SetFreq(true, cpuFreq);
+ res = TotalBench(EXTERNAL_CODECS_LOC_VARS complexInCommands, numThreads, dictIsDefined, dict, 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, false, cpuFreqLastTemp, resVal));
+ callback.NewLine();
+ }
+ }
+ }
+ else
+ {
+ bool needSetComplexity = true;
+ if (!methodName.IsEqualToNoCase(L"LZMA"))
+ {
+ for (unsigned i = 0; i < ARRAY_SIZE(g_Bench); i++)
+ {
+ const CBenchMethod &h = g_Bench[i];
+ AString s = h.Name;
+ if (AreSameMethodNames(h.Name, methodName))
+ {
+ callback.BenchProps.EncComplex = h.EncComplex;
+ callback.BenchProps.DecComplexCompr = h.DecComplexCompr;
+ callback.BenchProps.DecComplexUnc = h.DecComplexUnc;;
+ needSetComplexity = false;
+ break;
+ }
+ }
+ }
+ if (needSetComplexity)
+ callback.BenchProps.SetLzmaCompexity();
+
+ for (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, L"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(L"d", propVariant));
+ }
+
+ UInt32 uncompressedDataSize = callback.DictSize;
+ if (uncompressedDataSize >= (1 << 18))
+ uncompressedDataSize += kAdditionalSize;
+
+ HRESULT res = MethodBench(
+ EXTERNAL_CODECS_LOC_VARS
+ complexInCommands,
+ true, numThreads,
+ method2, uncompressedDataSize,
+ 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;
+}
diff --git a/lzma/CPP/7zip/UI/Common/Bench.h b/lzma/CPP/7zip/UI/Common/Bench.h
new file mode 100644
index 0000000..6af2942
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Common/Bench.h
@@ -0,0 +1,55 @@
+// Bench.h
+
+#ifndef __7ZIP_BENCH_H
+#define __7ZIP_BENCH_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 int kBenchMinDicLogSize = 18;
+
+UInt64 GetBenchMemoryUsage(UInt32 numThreads, UInt32 dictionary);
+
+struct IBenchPrintCallback
+{
+ virtual void Print(const char *s) = 0;
+ virtual void NewLine() = 0;
+ virtual HRESULT CheckBreak() = 0;
+};
+
+HRESULT Bench(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ IBenchPrintCallback *printCallback,
+ IBenchCallback *benchCallback,
+ const CObjectVector<CProperty> &props,
+ UInt32 numIterations,
+ bool multiDict
+ );
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Common/DefaultName.cpp b/lzma/CPP/7zip/UI/Common/DefaultName.cpp
new file mode 100644
index 0000000..b568c06
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Common/DefaultName.cpp
@@ -0,0 +1,35 @@
+// DefaultName.cpp
+
+#include "StdAfx.h"
+
+#include "DefaultName.h"
+
+static UString GetDefaultName3(const UString &fileName,
+ const UString &extension, const UString &addSubExtension)
+{
+ int extLength = extension.Len();
+ int fileNameLength = fileName.Len();
+ if (fileNameLength > extLength + 1)
+ {
+ int dotPos = fileNameLength - (extLength + 1);
+ if (fileName[dotPos] == '.')
+ if (extension.IsEqualToNoCase(fileName.Ptr(dotPos + 1)))
+ return fileName.Left(dotPos) + addSubExtension;
+ }
+ int dotPos = fileName.ReverseFind(L'.');
+ 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;
+}
diff --git a/lzma/CPP/7zip/UI/Common/DefaultName.h b/lzma/CPP/7zip/UI/Common/DefaultName.h
new file mode 100644
index 0000000..4484c3b
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Common/DefaultName.h
@@ -0,0 +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
diff --git a/lzma/CPP/7zip/UI/Common/DirItem.h b/lzma/CPP/7zip/UI/Common/DirItem.h
new file mode 100644
index 0000000..6a429ab
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Common/DirItem.h
@@ -0,0 +1,126 @@
+// 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 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;
+
+ void EnumerateDir(int phyParent, int logParent, const FString &phyPrefix);
+
+public:
+ CObjectVector<CDirItem> Items;
+
+ bool SymLinks;
+
+ bool ScanAltStreams;
+ FStringVector ErrorPaths;
+ CRecordVector<DWORD> ErrorCodes;
+ UInt64 TotalSize;
+
+
+ #ifndef UNDER_CE
+ void SetLinkInfo(CDirItem &dirItem, const NWindows::NFile::NFind::CFileInfo &fi,
+ const FString &phyPrefix);
+ #endif
+
+ void AddError(const FString &path, DWORD errorCode)
+ {
+ ErrorCodes.Add(errorCode);
+ ErrorPaths.Add(path);
+ }
+
+ void AddError(const FString &path)
+ {
+ AddError(path, ::GetLastError());
+ }
+
+ #if defined(_WIN32) && !defined(UNDER_CE)
+
+ CUniqBlocks SecureBlocks;
+ CByteBuffer TempSecureBuf;
+ bool _saclEnabled;
+ bool ReadSecure;
+
+ void AddSecurityItem(const FString &path, int &secureIndex);
+
+ #endif
+
+ CDirItems();
+
+ int GetNumFolders() const { return Prefixes.Size(); }
+ UString GetPhyPath(unsigned index) const;
+ UString GetLogPath(unsigned index) const;
+
+ unsigned AddPrefix(int phyParent, int logParent, const UString &prefix);
+ void DeleteLastPrefix();
+ void 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
diff --git a/lzma/CPP/7zip/UI/Common/EnumDirItems.cpp b/lzma/CPP/7zip/UI/Common/EnumDirItems.cpp
new file mode 100644
index 0000000..198a6ae
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Common/EnumDirItems.cpp
@@ -0,0 +1,757 @@
+// EnumDirItems.cpp
+
+#include "StdAfx.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"
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NName;
+
+void AddDirFileInfo(int phyParent, int logParent, int secureIndex,
+ const NFind::CFileInfo &fi, CObjectVector<CDirItem> &dirItems)
+{
+ 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
+ dirItems.Add(di);
+}
+
+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();
+ unsigned totalLen = len;
+ wchar_t *p = path.GetBuffer(len);
+ p[len] = 0;
+ len -= name.Len();
+ memcpy(p + len, (const wchar_t *)name, name.Len() * sizeof(wchar_t));
+ for (i = index; i >= 0; i = parents[i])
+ {
+ const UString &s = Prefixes[i];
+ len -= s.Len();
+ memcpy(p + len, (const wchar_t *)s, s.Len() * sizeof(wchar_t));
+ }
+ path.ReleaseBuffer(totalLen);
+ return path;
+}
+
+UString CDirItems::GetPhyPath(unsigned index) const
+{
+ const CDirItem &di = Items[index];
+ return 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),
+ TotalSize(0)
+ #ifdef _USE_SECURITY_CODE
+ , ReadSecure(false)
+ #endif
+{
+ #ifdef _USE_SECURITY_CODE
+ _saclEnabled = InitLocalPrivileges();
+ #endif
+}
+
+#ifdef _USE_SECURITY_CODE
+
+void 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;
+ 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;
+ }
+ if (errorCode == 0)
+ errorCode = ERROR_INVALID_FUNCTION;
+ AddError(path, errorCode);
+}
+
+#endif
+
+void CDirItems::EnumerateDir(int phyParent, int logParent, const FString &phyPrefix)
+{
+ NFind::CEnumerator enumerator(phyPrefix + FCHAR_ANY_MASK);
+ for (;;)
+ {
+ NFind::CFileInfo fi;
+ bool found;
+ if (!enumerator.Next(fi, found))
+ {
+ AddError(phyPrefix);
+ return;
+ }
+ if (!found)
+ break;
+
+ int secureIndex = -1;
+ #ifdef _USE_SECURITY_CODE
+ if (ReadSecure)
+ AddSecurityItem(phyPrefix + fi.Name, secureIndex);
+ #endif
+
+ AddDirFileInfo(phyParent, logParent, secureIndex, fi, Items);
+
+ if (fi.IsDir())
+ {
+ const FString name2 = fi.Name + FCHAR_PATH_SEPARATOR;
+ unsigned parent = AddPrefix(phyParent, logParent, fs2us(name2));
+ EnumerateDir(parent, parent, phyPrefix + name2);
+ }
+ }
+}
+
+void 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))
+ {
+ AddError(phyPath);
+ continue;
+ }
+ if (requestedPaths)
+ requestedPaths->Add(phyPath);
+
+ int delimiter = filePath.ReverseFind(FCHAR_PATH_SEPARATOR);
+ 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)
+ AddSecurityItem(phyPath, secureIndex);
+ #endif
+
+ AddDirFileInfo(phyParentCur, logParent, secureIndex, fi, Items);
+
+ if (fi.IsDir())
+ {
+ const FString name2 = fi.Name + FCHAR_PATH_SEPARATOR;
+ unsigned parent = AddPrefix(phyParentCur, logParent, fs2us(name2));
+ EnumerateDir(parent, parent, phyPrefix + phyPrefixCur + name2);
+ }
+ }
+ ReserveDown();
+}
+
+
+
+
+
+
+static HRESULT EnumerateDirItems(
+ const NWildcard::CCensorNode &curNode,
+ int phyParent, int logParent, const FString &phyPrefix,
+ const UStringVector &addArchivePrefix,
+ CDirItems &dirItems,
+ bool enterToSubFolders,
+ IEnumDirItemCallback *callback);
+
+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,
+ IEnumDirItemCallback *callback)
+{
+ 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, callback);
+ if (numItems == dirItems.Items.Size())
+ dirItems.DeleteLastPrefix();
+ return res;
+}
+
+#ifndef UNDER_CE
+
+static void EnumerateAltStreams(
+ const NFind::CFileInfo &fi,
+ const NWildcard::CCensorNode &curNode,
+ int phyParent, int logParent, const FString &phyPrefix,
+ const UStringVector &addArchivePrefix, // prefix from curNode
+ CDirItems &dirItems)
+{
+ const FString fullPath = phyPrefix + fi.Name;
+ NFind::CStreamEnumerator enumerator(fullPath);
+ for (;;)
+ {
+ NFind::CStreamInfo si;
+ bool found;
+ if (!enumerator.Next(si, found))
+ {
+ dirItems.AddError(fullPath + FTEXT(":*"), (DWORD)E_FAIL);
+ break;
+ }
+ if (!found)
+ break;
+ if (si.IsMainStream())
+ continue;
+ UStringVector addArchivePrefixNew = addArchivePrefix;
+ UString reducedName = si.GetReducedName();
+ addArchivePrefixNew.Back() += reducedName;
+ if (curNode.CheckPathToRoot(false, addArchivePrefixNew, true))
+ continue;
+ NFind::CFileInfo fi2 = fi;
+ fi2.Name += us2fs(reducedName);
+ fi2.Size = si.Size;
+ fi2.Attrib &= ~FILE_ATTRIBUTE_DIRECTORY;
+ fi2.IsAltStream = true;
+ AddDirFileInfo(phyParent, logParent, -1, fi2, dirItems.Items);
+ dirItems.TotalSize += fi2.Size;
+ }
+}
+
+void CDirItems::SetLinkInfo(CDirItem &dirItem, const NFind::CFileInfo &fi,
+ const FString &phyPrefix)
+{
+ if (!SymLinks || !fi.HasReparsePoint())
+ return;
+ const FString path = phyPrefix + fi.Name;
+ CByteBuffer &buf = dirItem.ReparseData;
+ if (NIO::GetReparseData(path, buf))
+ {
+ CReparseAttr attr;
+ if (attr.Parse(buf, buf.Size()))
+ return;
+ }
+ AddError(path);
+ buf.Free();
+}
+
+#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,
+ IEnumDirItemCallback *callback)
+{
+ 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;
+
+ if (curNode.CheckPathToRoot(true, addArchivePrefixNew, !fi.IsDir()))
+ {
+ int secureIndex = -1;
+ #ifdef _USE_SECURITY_CODE
+ if (dirItems.ReadSecure)
+ dirItems.AddSecurityItem(phyPrefix + fi.Name, secureIndex);
+ #endif
+
+ dirItemIndex = dirItems.Items.Size();
+ AddDirFileInfo(phyParent, logParent, secureIndex, fi, dirItems.Items);
+ dirItems.TotalSize += fi.Size;
+ if (fi.IsDir())
+ enterToSubFolders2 = true;
+ }
+
+ #ifndef UNDER_CE
+ if (dirItems.ScanAltStreams)
+ {
+ EnumerateAltStreams(fi, curNode, phyParent, logParent, phyPrefix,
+ addArchivePrefixNew, dirItems);
+ }
+
+ if (dirItemIndex >= 0)
+ {
+ CDirItem &dirItem = dirItems.Items[dirItemIndex];
+ 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, callback);
+}
+
+
+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;
+}
+
+
+static HRESULT EnumerateDirItems(
+ const NWildcard::CCensorNode &curNode,
+ int phyParent, int logParent, const FString &phyPrefix,
+ const UStringVector &addArchivePrefix, // prefix from curNode
+ CDirItems &dirItems,
+ bool enterToSubFolders,
+ IEnumDirItemCallback *callback)
+{
+ if (!enterToSubFolders)
+ if (curNode.NeedCheckSubDirs())
+ enterToSubFolders = true;
+ if (callback)
+ RINOK(callback->ScanProgress(dirItems.GetNumFolders(), dirItems.Items.Size(), dirItems.TotalSize, fs2us(phyPrefix), true));
+
+ // 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();
+ const FString fullPath = phyPrefix + us2fs(name);
+ NFind::CFileInfo fi;
+ #ifdef _WIN32
+ if (phyPrefix.IsEmpty() && item.IsDriveItem())
+ {
+ fi.SetAsDir();
+ fi.Name = fullPath;
+ }
+ else
+ #endif
+ if (!fi.Find(fullPath))
+ {
+ dirItems.AddError(fullPath);
+ continue;
+ }
+ bool isDir = fi.IsDir();
+ if (isDir && !item.ForDir || !isDir && !item.ForFile)
+ {
+ 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 (dirItems.ReadSecure)
+ dirItems.AddSecurityItem(fullPath, secureIndex);
+ #endif
+
+ AddDirFileInfo(phyParent, logParent, secureIndex, fi, dirItems.Items);
+
+ #ifndef UNDER_CE
+ {
+ CDirItem &dirItem = dirItems.Items.Back();
+ dirItems.SetLinkInfo(dirItem, fi, phyPrefix);
+ if (dirItem.ReparseData.Size() != 0)
+ continue;
+ }
+ #endif
+
+ dirItems.TotalSize += fi.Size;
+
+ #ifndef UNDER_CE
+ if (dirItems.ScanAltStreams)
+ {
+ UStringVector pathParts;
+ pathParts.Add(fs2us(fi.Name));
+ EnumerateAltStreams(fi, curNode, phyParent, logParent, phyPrefix,
+ pathParts, 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, callback));
+ }
+
+ for (i = 0; i < curNode.SubNodes.Size(); i++)
+ {
+ if (i < needEnterVector.Size())
+ if (!needEnterVector[i])
+ continue;
+ const NWildcard::CCensorNode &nextNode = curNode.SubNodes[i];
+ const FString fullPath = phyPrefix + us2fs(nextNode.Name);
+ NFind::CFileInfo fi;
+ #ifdef _WIN32
+ if (phyPrefix.IsEmpty() && NWildcard::IsDriveColonName(nextNode.Name))
+ {
+ fi.SetAsDir();
+ fi.Name = fullPath;
+ }
+ else
+ #endif
+ if (!fi.Find(fullPath))
+ {
+ if (!nextNode.AreThereIncludeItems())
+ continue;
+ dirItems.AddError(fullPath);
+ continue;
+ }
+ if (!fi.IsDir())
+ {
+ dirItems.AddError(fullPath, (DWORD)E_FAIL);
+ continue;
+ }
+
+ RINOK(EnumerateDirItems_Spec(nextNode, phyParent, logParent, fi.Name, phyPrefix,
+ UStringVector(), dirItems, false, callback));
+ }
+
+ 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, callback));
+ }
+ return S_OK;
+ }
+ }
+
+ #endif
+ #endif
+
+ NFind::CEnumerator enumerator(phyPrefix + FCHAR_ANY_MASK);
+ for (unsigned ttt = 0; ; ttt++)
+ {
+ NFind::CFileInfo fi;
+ bool found;
+ if (!enumerator.Next(fi, found))
+ {
+ dirItems.AddError(phyPrefix);
+ break;
+ }
+ if (!found)
+ break;
+
+ if (callback && (ttt & 0xFF) == 0xFF)
+ RINOK(callback->ScanProgress(dirItems.GetNumFolders(), dirItems.Items.Size(), dirItems.TotalSize, fs2us(phyPrefix), true));
+
+ RINOK(EnumerateForItem(fi, curNode, phyParent, logParent, phyPrefix,
+ addArchivePrefix, dirItems, enterToSubFolders, callback));
+ }
+ return S_OK;
+}
+
+HRESULT EnumerateItems(
+ const NWildcard::CCensor &censor,
+ const NWildcard::ECensorPathMode pathMode,
+ const UString &addPathPrefix,
+ CDirItems &dirItems,
+ IEnumDirItemCallback *callback)
+{
+ 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
+ callback));
+ }
+ 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;
+ if (!attr.Parse(item.ReparseData, item.ReparseData.Size()))
+ 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(us2fs(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 (prefix.Back() != WCHAR_PATH_SEPARATOR)
+ 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
diff --git a/lzma/CPP/7zip/UI/Common/EnumDirItems.h b/lzma/CPP/7zip/UI/Common/EnumDirItems.h
new file mode 100644
index 0000000..1739716
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Common/EnumDirItems.h
@@ -0,0 +1,27 @@
+// 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);
+
+struct IEnumDirItemCallback
+{
+ virtual HRESULT ScanProgress(UInt64 numFolders, UInt64 numFiles, UInt64 totalSize, const wchar_t *path, bool isDir) = 0;
+};
+
+HRESULT EnumerateItems(
+ const NWildcard::CCensor &censor,
+ NWildcard::ECensorPathMode pathMode,
+ const UString &addPathPrefix,
+ CDirItems &dirItems,
+ IEnumDirItemCallback *callback);
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Common/ExitCode.h b/lzma/CPP/7zip/UI/Common/ExitCode.h
new file mode 100644
index 0000000..d03ec6d
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Common/ExitCode.h
@@ -0,0 +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
diff --git a/lzma/CPP/7zip/UI/Common/Extract.cpp b/lzma/CPP/7zip/UI/Common/Extract.cpp
new file mode 100644
index 0000000..4bbf2b3
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Common/Extract.cpp
@@ -0,0 +1,475 @@
+// 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_ANY_MASK, us2fs(GetCorrectFsPath(replaceName)));
+
+ bool elimIsPossible = false;
+ UString elimPrefix; // only pure name without dir delimiter
+ FString outDirReduced = outDir;
+
+ if (options.ElimDup.Val)
+ {
+ UString dirPrefix;
+ SplitPathToParts_Smart(fs2us(outDir), dirPrefix, elimPrefix);
+ if (!elimPrefix.IsEmpty())
+ {
+ if (IsCharDirLimiter(elimPrefix.Back()))
+ elimPrefix.DeleteBack();
+ if (!elimPrefix.IsEmpty())
+ {
+ outDirReduced = us2fs(dirPrefix);
+ elimIsPossible = true;
+ }
+ }
+ }
+
+ if (!options.StdInMode)
+ {
+ UInt32 numItems;
+ RINOK(archive->GetNumberOfItems(&numItems));
+
+ UString filePath;
+
+ for (UInt32 i = 0; i < numItems; i++)
+ {
+ RINOK(arc.GetItemPath(i, filePath));
+
+ if (elimIsPossible && options.ElimDup.Val)
+ {
+ if (!IsPath1PrefixedByPath2(filePath, elimPrefix))
+ elimIsPossible = false;
+ else
+ {
+ wchar_t c = filePath[elimPrefix.Len()];
+ if (c != 0 && !IsCharDirLimiter(c))
+ elimIsPossible = false;
+ }
+ }
+
+ bool isFolder;
+ RINOK(Archive_IsItem_Folder(archive, i, isFolder));
+ bool isAltStream;
+ RINOK(Archive_IsItem_AltStream(archive, i, isAltStream));
+ if (!options.NtOptions.AltStreams.Val && isAltStream)
+ continue;
+ if (!wildcardCensor.CheckPath(isAltStream, filePath, !isFolder))
+ continue;
+ realIndices.Add(i);
+ }
+
+ if (realIndices.Size() == 0)
+ {
+ callback->ThereAreNoFiles();
+ return callback->ExtractResult(S_OK);
+ }
+ }
+
+ if (elimIsPossible)
+ outDir = outDirReduced;
+
+ #ifdef _WIN32
+ // GetCorrectFullFsPath doesn't like "..".
+ // outDir.TrimRight();
+ // outDir = GetCorrectFullFsPath(outDir);
+ #endif
+
+ if (outDir.IsEmpty())
+ outDir = FString(FTEXT(".")) + FString(FSTRING_PATH_SEPARATOR);
+ else
+ if (!CreateComplexDir(outDir))
+ {
+ HRESULT res = ::GetLastError();
+ if (res == S_OK)
+ res = E_FAIL;
+ errorMessage = ((UString)L"Can not create output directory ") + fs2us(outDir);
+ return res;
+ }
+
+ ecs->Init(
+ options.NtOptions,
+ options.StdInMode ? &wildcardCensor : NULL,
+ &arc,
+ callback,
+ options.StdOutMode, options.TestMode,
+ outDir,
+ removePathParts,
+ 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;
+ 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);
+ if (result == S_OK && !options.StdInMode)
+ result = ecs->SetDirsTimes();
+ 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 &stat)
+{
+ stat.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);
+ #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_ClearPasswordWasAskedFlag();
+ #endif
+
+ RINOK(extractCallback->BeforeOpen(arcPath));
+ 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.Open2(op, openCallback);
+
+ if (result == E_ABORT)
+ return result;
+
+ bool crypted = false;
+ #ifndef _NO_CRYPTO
+ crypted = openCallback->Open_WasPasswordAsked();
+ #endif
+
+ if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0)
+ result = S_FALSE;
+
+ // arcLink.Set_ErrorsText();
+ RINOK(extractCallback->OpenResult(arcPath, result, crypted));
+
+
+ {
+ FOR_VECTOR (r, arcLink.Arcs)
+ {
+ const CArc &arc = arcLink.Arcs[r];
+ const CArcErrorInfo &er = arc.ErrorInfo;
+ if (er.IsThereErrorOrWarning())
+ {
+ RINOK(extractCallback->SetError(r, arc.Path,
+ er.GetErrorFlags(), er.ErrorMessage,
+ er.GetWarningFlags(), er.WarningMessage));
+ }
+ }
+ }
+
+ if (result != S_OK)
+ {
+ thereAreNotOpenArcs = true;
+ if (!options.StdInMode)
+ {
+ NFind::CFileInfo fi;
+ if (fi.Find(us2fs(arcPath)))
+ if (!fi.IsDir())
+ totalPackProcessed += fi.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[index] = true;
+ correctionSize -= arcSizes[index];
+ }
+ }
+ }
+ if (correctionSize != 0)
+ {
+ Int64 newPackSize = (Int64)totalPackSize + correctionSize;
+ if (newPackSize < 0)
+ newPackSize = 0;
+ totalPackSize = newPackSize;
+ RINOK(extractCallback->SetTotal(totalPackSize));
+ }
+ }
+ }
+
+ #ifndef _NO_CRYPTO
+ bool passwordIsDefined;
+ UString password;
+ RINOK(openCallback->Open_GetPasswordIfAny(passwordIsDefined, password));
+ if (passwordIsDefined)
+ {
+ RINOK(extractCallback->SetPassword(password));
+ }
+ #endif
+
+ FOR_VECTOR (k, arcLink.Arcs)
+ {
+ const CArc &arc = arcLink.Arcs[k];
+ const CArcErrorInfo &er = arc.ErrorInfo;
+
+ if (er.ErrorFormatIndex >= 0)
+ {
+ RINOK(extractCallback->OpenTypeWarning(arc.Path,
+ codecs->GetFormatNamePtr(arc.FormatIndex),
+ codecs->GetFormatNamePtr(er.ErrorFormatIndex)))
+ /*
+ UString s = L"Can not open the file as [" + codecs->Formats[arc.ErrorFormatIndex].Name + L"] archive\n";
+ s += L"The file is open as [" + codecs->Formats[arc.FormatIndex].Name + L"] archive";
+ RINOK(extractCallback->MessageError(s));
+ */
+ }
+ {
+ const UString &s = er.ErrorMessage;
+ if (!s.IsEmpty())
+ {
+ RINOK(extractCallback->MessageError(s));
+ }
+ }
+ }
+
+ 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));
+ }
+ stat.NumFolders = ecs->NumFolders;
+ stat.NumFiles = ecs->NumFiles;
+ stat.NumAltStreams = ecs->NumAltStreams;
+ stat.UnpackSize = ecs->UnpackSize;
+ stat.AltStreams_UnpackSize = ecs->AltStreams_UnpackSize;
+ stat.NumArchives = arcPaths.Size();
+ stat.PackSize = ecs->LocalProgressSpec->InSize;
+ return S_OK;
+}
diff --git a/lzma/CPP/7zip/UI/Common/Extract.h b/lzma/CPP/7zip/UI/Common/Extract.h
new file mode 100644
index 0000000..d42514d
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Common/Extract.h
@@ -0,0 +1,94 @@
+// 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 &stat);
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Common/ExtractMode.h b/lzma/CPP/7zip/UI/Common/ExtractMode.h
new file mode 100644
index 0000000..719aaad
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Common/ExtractMode.h
@@ -0,0 +1,33 @@
+// ExtractMode.h
+
+#ifndef __EXTRACT_MODE_H
+#define __EXTRACT_MODE_H
+
+namespace NExtract {
+
+namespace NPathMode
+{
+ enum EEnum
+ {
+ kFullPaths,
+ kCurPaths,
+ kNoPaths,
+ kAbsPaths
+ };
+}
+
+namespace NOverwriteMode
+{
+ enum EEnum
+ {
+ kAsk,
+ kOverwrite,
+ kSkip,
+ kRename,
+ kRenameExisting
+ };
+}
+
+}
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Common/ExtractingFilePath.cpp b/lzma/CPP/7zip/UI/Common/ExtractingFilePath.cpp
new file mode 100644
index 0000000..e6947f2
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Common/ExtractingFilePath.cpp
@@ -0,0 +1,190 @@
+// ExtractingFilePath.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/Wildcard.h"
+
+#include "../../../Windows/FileName.h"
+
+#include "ExtractingFilePath.h"
+
+static UString ReplaceIncorrectChars(const UString &s, bool repaceColon)
+{
+ #ifdef _WIN32
+ UString res;
+ bool beforeColon = true;
+ {
+ for (unsigned i = 0; i < s.Len(); i++)
+ {
+ wchar_t c = s[i];
+ if (beforeColon)
+ if (c == '*' || c == '?' || c < 0x20 || c == '<' || c == '>' || c == '|' || c == '"')
+ c = '_';
+ if (c == ':')
+ {
+ if (repaceColon)
+ c = '_';
+ else
+ beforeColon = false;
+ }
+ res += c;
+ }
+ }
+ if (beforeColon)
+ {
+ for (int i = res.Len() - 1; i >= 0; i--)
+ {
+ wchar_t c = res[i];
+ if (c != '.' && c != ' ')
+ break;
+ res.ReplaceOneCharAtPos(i, '_');
+ }
+ }
+ return res;
+ #else
+ return s;
+ #endif
+}
+
+#ifdef _WIN32
+
+static const wchar_t *g_ReservedNames[] =
+{
+ L"CON", L"PRN", L"AUX", L"NUL"
+};
+
+static bool CheckTail(const UString &name, unsigned len)
+{
+ int dotPos = name.Find(L'.');
+ if (dotPos < 0)
+ dotPos = name.Len();
+ UString s = name.Left(dotPos);
+ s.TrimRight();
+ return s.Len() != len;
+}
+
+static bool CheckNameNum(const UString &name, const wchar_t *reservedName)
+{
+ unsigned len = MyStringLen(reservedName);
+ if (name.Len() <= len)
+ return true;
+ if (MyStringCompareNoCase_N(name, reservedName, len) != 0)
+ return true;
+ wchar_t c = name[len];
+ if (c < L'0' || c > L'9')
+ return true;
+ return CheckTail(name, len + 1);
+}
+
+static bool IsSupportedName(const UString &name)
+{
+ for (unsigned i = 0; i < ARRAY_SIZE(g_ReservedNames); i++)
+ {
+ const wchar_t *reservedName = g_ReservedNames[i];
+ unsigned len = MyStringLen(reservedName);
+ if (name.Len() < len)
+ continue;
+ if (MyStringCompareNoCase_N(name, reservedName, len) != 0)
+ continue;
+ if (!CheckTail(name, len))
+ return false;
+ }
+ if (!CheckNameNum(name, L"COM"))
+ return false;
+ return CheckNameNum(name, L"LPT");
+}
+
+#endif
+
+static UString GetCorrectFileName(const UString &path, bool repaceColon)
+{
+ if (path == L".." || path == L".")
+ return UString();
+ return ReplaceIncorrectChars(path, repaceColon);
+}
+
+void MakeCorrectPath(bool isPathFromRoot, UStringVector &pathParts, bool replaceAltStreamColon)
+{
+ for (unsigned i = 0; i < pathParts.Size();)
+ {
+ UString &s = pathParts[i];
+ #ifdef _WIN32
+ bool needReplaceColon = (replaceAltStreamColon || i != pathParts.Size() - 1);
+ if (i == 0 && isPathFromRoot && NWindows::NFile::NName::IsDrivePath(s))
+ {
+ UString s2 = s[0];
+ s2 += L'_';
+ s2 += GetCorrectFileName(s.Ptr(2), needReplaceColon);
+ s = s2;
+ }
+ else
+ s = GetCorrectFileName(s, needReplaceColon);
+ #endif
+
+ if (s.IsEmpty())
+ pathParts.Delete(i);
+ else
+ {
+ #ifdef _WIN32
+ if (!IsSupportedName(s))
+ s = (UString)L"_" + s;
+ #endif
+ i++;
+ }
+ }
+}
+
+UString MakePathNameFromParts(const UStringVector &parts)
+{
+ UString result;
+ FOR_VECTOR (i, parts)
+ {
+ if (i != 0)
+ result += WCHAR_PATH_SEPARATOR;
+ result += parts[i];
+ }
+ return result;
+}
+
+static const wchar_t *k_EmptyReplaceName = L"[]";
+
+void Correct_IfEmptyLastPart(UStringVector &parts)
+{
+ if (parts.IsEmpty())
+ parts.Add(k_EmptyReplaceName);
+ else
+ {
+ UString &s = parts.Back();
+ if (s.IsEmpty())
+ s = k_EmptyReplaceName;
+ }
+}
+
+UString GetCorrectFsPath(const UString &path)
+{
+ UString res = GetCorrectFileName(path, true);
+ #ifdef _WIN32
+ if (!IsSupportedName(res))
+ res = (UString)L"_" + res;
+ #endif
+ if (res.IsEmpty())
+ res = k_EmptyReplaceName;
+ return res;
+}
+
+UString GetCorrectFullFsPath(const UString &path)
+{
+ UStringVector parts;
+ SplitPathToParts(path, parts);
+ FOR_VECTOR (i, parts)
+ {
+ UString &s = parts[i];
+ #ifdef _WIN32
+ while (!s.IsEmpty() && (s.Back() == '.' || s.Back() == ' '))
+ s.DeleteBack();
+ if (!IsSupportedName(s))
+ s.InsertAtFront(L'_');
+ #endif
+ }
+ return MakePathNameFromParts(parts);
+}
diff --git a/lzma/CPP/7zip/UI/Common/ExtractingFilePath.h b/lzma/CPP/7zip/UI/Common/ExtractingFilePath.h
new file mode 100644
index 0000000..8d36312
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Common/ExtractingFilePath.h
@@ -0,0 +1,21 @@
+// ExtractingFilePath.h
+
+#ifndef __EXTRACTING_FILE_PATH_H
+#define __EXTRACTING_FILE_PATH_H
+
+#include "../../../Common/MyString.h"
+
+UString MakePathNameFromParts(const UStringVector &parts);
+
+/* for WIN32:
+ if (isRoot == true), and pathParts[0] contains path like "c:name",
+ it thinks that "c:" is drive prefix (it's not ":name alt stream) and
+ the function changes part to c_name */
+void MakeCorrectPath(bool isPathFromRoot, UStringVector &pathParts, bool replaceAltStreamColon);
+
+UString GetCorrectFsPath(const UString &path);
+UString GetCorrectFullFsPath(const UString &path);
+
+void Correct_IfEmptyLastPart(UStringVector &parts);
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Common/HashCalc.cpp b/lzma/CPP/7zip/UI/Common/HashCalc.cpp
new file mode 100644
index 0000000..4ecf6a3
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Common/HashCalc.cpp
@@ -0,0 +1,361 @@
+// 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); }
+};
+
+struct CEnumDirItemCallback_Hash: public IEnumDirItemCallback
+{
+ IHashCallbackUI *Callback;
+
+ HRESULT ScanProgress(UInt64 numFolders, UInt64 numFiles, UInt64 totalSize, const wchar_t *path, bool isDir)
+ {
+ return Callback->ScanProgress(numFolders, numFiles, totalSize, path, isDir);
+ }
+};
+
+static const wchar_t *k_DefaultHashMethod = L"CRC32";
+
+HRESULT CHashBundle::SetMethods(DECL_EXTERNAL_CODECS_LOC_VARS const UStringVector &hashMethods)
+{
+ UStringVector names = hashMethods;
+ if (names.IsEmpty())
+ names.Add(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 == L"*")
+ {
+ CRecordVector<CMethodId> tempMethods;
+ GetHashMethods(EXTERNAL_CODECS_LOC_VARS tempMethods);
+ methods.Clear();
+ ids.Clear();
+ FOR_VECTOR (t, tempMethods)
+ {
+ int 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;
+ int index = ids.AddToUniqueSorted(id);
+ if (ids.Size() != methods.Size())
+ methods.Insert(index, m);
+ }
+ }
+
+ for (i = 0; i < ids.Size(); i++)
+ {
+ CMyComPtr<IHasher> hasher;
+ UString 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 (int i = 0; i < k_HashCalc_NumGroups; i++)
+ memset(h.Digests[i], 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,
+ UString &errorInfo,
+ IHashCallbackUI *callback)
+{
+ CDirItems dirItems;
+
+ UInt64 numErrors = 0;
+ UInt64 totalBytes = 0;
+ 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
+ {
+ CEnumDirItemCallback_Hash enumCallback;
+ enumCallback.Callback = callback;
+ RINOK(callback->StartScanning());
+ dirItems.ScanAltStreams = options.AltStreamsMode;
+ HRESULT res = EnumerateItems(censor,
+ options.PathMode,
+ UString(),
+ dirItems, &enumCallback);
+ totalBytes = dirItems.TotalSize;
+ FOR_VECTOR (i, dirItems.ErrorPaths)
+ {
+ RINOK(callback->CanNotFindError(fs2us(dirItems.ErrorPaths[i]), dirItems.ErrorCodes[i]));
+ }
+ numErrors = dirItems.ErrorPaths.Size();
+ if (res != S_OK)
+ {
+ if (res != E_ABORT)
+ errorInfo = L"Scanning error";
+ return res;
+ }
+ RINOK(callback->FinishScanning());
+ }
+
+ unsigned i;
+ CHashBundle hb;
+ RINOK(hb.SetMethods(EXTERNAL_CODECS_LOC_VARS options.Methods));
+ hb.Init();
+ hb.NumErrors = numErrors;
+
+ if (options.StdInMode)
+ {
+ RINOK(callback->SetNumFiles(1));
+ }
+ else
+ {
+ RINOK(callback->SetTotal(totalBytes));
+ }
+
+ 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)
+ {
+ UString phyPath = dirItems.GetPhyPath(i);
+ if (!inStreamSpec->OpenShared(us2fs(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(Byte value)
+{
+ return (char)((value < 10) ? ('0' + value) : ('A' + (value - 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++)
+ {
+ Byte b = data[i];
+ dest[0] = GetHex((Byte)((b >> 4) & 0xF));
+ dest[1] = GetHex((Byte)(b & 0xF));
+ dest += step;
+ }
+}
diff --git a/lzma/CPP/7zip/UI/Common/HashCalc.h b/lzma/CPP/7zip/UI/Common/HashCalc.h
new file mode 100644
index 0000000..01ee2ce
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Common/HashCalc.h
@@ -0,0 +1,107 @@
+// HashCalc.h
+
+#ifndef __HASH_CALC_H
+#define __HASH_CALC_H
+
+#include "../../../Common/Wildcard.h"
+
+#include "../../Common/CreateCoder.h"
+#include "../../Common/MethodProps.h"
+
+#include "Property.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;
+ UString 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 NumFiles;
+ UInt64 NumDirs;
+ UInt64 NumAltStreams;
+ UInt64 FilesSize;
+ UInt64 AltStreamsSize;
+ UInt64 NumErrors;
+
+ UInt64 CurSize;
+
+ HRESULT SetMethods(DECL_EXTERNAL_CODECS_LOC_VARS const UStringVector &methods);
+
+ void Init()
+ {
+ NumFiles = NumDirs = 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) \
+ virtual HRESULT StartScanning() x; \
+ virtual HRESULT ScanProgress(UInt64 numFolders, UInt64 numFiles, UInt64 totalSize, const wchar_t *path, bool isDir) x; \
+ virtual HRESULT CanNotFindError(const wchar_t *name, DWORD systemError) x; \
+ virtual HRESULT FinishScanning() 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 wchar_t *name, DWORD systemError) x; \
+ virtual HRESULT SetOperationResult(UInt64 fileSize, const CHashBundle &hb, bool showHash) x; \
+ virtual HRESULT AfterLastFile(const CHashBundle &hb) x; \
+
+struct IHashCallbackUI
+{
+ 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,
+ UString &errorInfo,
+ IHashCallbackUI *callback);
+
+void AddHashHexToString(char *dest, const Byte *data, UInt32 size);
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Common/IFileExtractCallback.h b/lzma/CPP/7zip/UI/Common/IFileExtractCallback.h
new file mode 100644
index 0000000..debfc08
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Common/IFileExtractCallback.h
@@ -0,0 +1,72 @@
+// IFileExtractCallback.h
+
+#ifndef __I_FILE_EXTRACT_CALLBACK_H
+#define __I_FILE_EXTRACT_CALLBACK_H
+
+#include "../../../Common/MyString.h"
+
+#include "../../IDecl.h"
+
+namespace NOverwriteAnswer
+{
+ enum EEnum
+ {
+ kYes,
+ kYesToAll,
+ kNo,
+ kNoToAll,
+ kAutoRename,
+ kCancel
+ };
+}
+
+DECL_INTERFACE_SUB(IFolderArchiveExtractCallback, IProgress, 0x01, 0x07)
+{
+public:
+ STDMETHOD(AskOverwrite)(
+ const wchar_t *existName, const FILETIME *existTime, const UInt64 *existSize,
+ const wchar_t *newName, const FILETIME *newTime, const UInt64 *newSize,
+ Int32 *answer) PURE;
+ STDMETHOD(PrepareOperation)(const wchar_t *name, bool isFolder, Int32 askExtractMode, const UInt64 *position) PURE;
+ STDMETHOD(MessageError)(const wchar_t *message) PURE;
+ STDMETHOD(SetOperationResult)(Int32 operationResult, bool encrypted) PURE;
+};
+
+struct IExtractCallbackUI: IFolderArchiveExtractCallback
+{
+ virtual HRESULT BeforeOpen(const wchar_t *name) = 0;
+ virtual HRESULT OpenResult(const wchar_t *name, HRESULT result, bool encrypted) = 0;
+ virtual HRESULT SetError(int level, const wchar_t *name,
+ UInt32 errorFlags, const wchar_t *errors,
+ UInt32 warningFlags, const wchar_t *warnings) = 0;
+ virtual HRESULT ThereAreNoFiles() = 0;
+ virtual HRESULT ExtractResult(HRESULT result) = 0;
+ virtual HRESULT OpenTypeWarning(const wchar_t *name, const wchar_t *okType, const wchar_t *errorType) = 0;
+
+ #ifndef _NO_CRYPTO
+ virtual HRESULT SetPassword(const UString &password) = 0;
+ #endif
+};
+
+
+#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, bool encrypted) x; \
+
+DECL_INTERFACE_SUB(IFolderExtractToStreamCallback, IUnknown, 0x01, 0x30)
+{
+ INTERFACE_IFolderExtractToStreamCallback(PURE)
+};
+
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Common/LoadCodecs.cpp b/lzma/CPP/7zip/UI/Common/LoadCodecs.cpp
new file mode 100644
index 0000000..acbd7e8
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Common/LoadCodecs.cpp
@@ -0,0 +1,900 @@
+// LoadCodecs.cpp
+
+#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
+
+#include "../../../Windows/FileFind.h"
+#include "../../../Windows/DLL.h"
+#ifdef NEW_FOLDER_INTERFACE
+#include "../../../Windows/ResourceString.h"
+static const UINT kIconTypesResId = 100;
+#endif
+
+#ifdef _WIN32
+#include "../../../Windows/FileName.h"
+#include "../../../Windows/Registry.h"
+#endif
+
+using namespace NFile;
+
+#ifdef _WIN32
+extern HINSTANCE g_hInstance;
+#endif
+
+#define kCodecsFolderName FTEXT("Codecs")
+#define kFormatsFolderName FTEXT("Formats")
+static CFSTR kMainDll = FTEXT("7z.dll");
+
+#ifdef _WIN32
+
+static LPCTSTR kRegistryPath = TEXT("Software") TEXT(STRING_PATH_SEPARATOR) TEXT("7-zip");
+static LPCWSTR kProgramPathValue = L"Path";
+static LPCWSTR 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 = 48;
+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.IsEqualToNoCase(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.GetMethodProperty = (Func_GetMethodProperty)lib.Lib.GetProc("GetMethodProperty");
+ if (lib.GetMethodProperty)
+ {
+ UInt32 numMethods = 1;
+ Func_GetNumberOfMethods getNumberOfMethodsFunc = (Func_GetNumberOfMethods)lib.Lib.GetProc("GetNumberOfMethods");
+ if (getNumberOfMethodsFunc)
+ {
+ RINOK(getNumberOfMethodsFunc(&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.Hashers));
+ if (lib.Hashers)
+ {
+ UInt32 numMethods = lib.Hashers->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 = 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 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.IsEqualToNoCase(pair.Ext))
+ {
+ iconIndex = pair.IconIndex;
+ return true;
+ }
+ }
+ return false;
+}
+
+#endif // EXTERNAL_CODECS
+
+#ifdef _7ZIP_LARGE_PAGES
+extern "C"
+{
+ extern SIZE_T g_LargePageSize;
+}
+#endif
+
+HRESULT CCodecs::LoadDll(const FString &dllPath, bool needCheckDll)
+{
+ if (needCheckDll)
+ {
+ NDLL::CLibrary library;
+ if (!library.LoadEx(dllPath, LOAD_LIBRARY_AS_DATAFILE))
+ return S_OK;
+ }
+ Libs.Add(CCodecLib());
+ CCodecLib &lib = Libs.Back();
+ lib.Path = dllPath;
+ bool used = false;
+ HRESULT res = S_OK;
+ if (lib.Lib.Load(dllPath))
+ {
+ #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");
+ if (lib.CreateObject)
+ {
+ unsigned startSize = Codecs.Size() + Hashers.Size();
+ res = LoadCodecs();
+ used = (startSize != Codecs.Size() + Hashers.Size());
+ if (res == S_OK)
+ {
+ 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(folderPrefix + FCHAR_ANY_MASK);
+ NFile::NFind::CFileInfo fi;
+ while (enumerator.Next(fi))
+ {
+ if (fi.IsDir())
+ continue;
+ RINOK(LoadDll(folderPrefix + fi.Name, true));
+ }
+ return S_OK;
+}
+
+#endif
+
+HRESULT CCodecs::Load()
+{
+ #ifdef NEW_FOLDER_INTERFACE
+ InternalIcons.LoadIcons(g_hInstance);
+ #endif
+
+ Formats.Clear();
+
+ #ifdef EXTERNAL_CODECS
+ Codecs.Clear();
+ Hashers.Clear();
+ #endif
+
+ for (UInt32 i = 0; i < g_NumArcs; i++)
+ {
+ const CArcInfo &arc = *g_Arcs[i];
+ CArcInfoEx item;
+
+ item.Name.SetFromAscii(arc.Name);
+ item.CreateInArchive = arc.CreateInArchive;
+ item.IsArcFunc = arc.IsArc;
+ item.Flags = arc.Flags;
+
+ {
+ UString e, ae;
+ if (arc.Ext)
+ e.SetFromAscii(arc.Ext);
+ if (arc.AddExt)
+ ae.SetFromAscii(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();
+ RINOK(LoadDll(baseFolder + kMainDll, false));
+ RINOK(LoadDllsFromFolder(baseFolder + kCodecsFolderName FSTRING_PATH_SEPARATOR));
+ RINOK(LoadDllsFromFolder(baseFolder + kFormatsFolderName FSTRING_PATH_SEPARATOR));
+ #endif
+
+ return S_OK;
+}
+
+#ifndef _SFX
+
+int CCodecs::FindFormatForArchiveName(const UString &arcPath) const
+{
+ int slashPos = arcPath.ReverseFind(WCHAR_PATH_SEPARATOR);
+ int dotPos = arcPath.ReverseFind(L'.');
+ if (dotPos < 0 || dotPos < slashPos)
+ return -1;
+ const UString ext = arcPath.Ptr(dotPos + 1);
+ if (ext.IsEmpty())
+ return -1;
+ if (ext.IsEqualToNoCase(L"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.IsEqualToNoCase(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('.', 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 EXTERNAL_CODECS
+
+// #define EXPORT_CODECS
+
+#ifdef EXPORT_CODECS
+
+extern unsigned g_NumCodecs;
+STDAPI CreateCoder2(bool encode, 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::GetNumberOfMethods(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 = (propID == NMethodPropID::kDecoderIsAssigned) ?
+ ci.DecoderIsAssigned :
+ ci.EncoderIsAssigned;
+ prop.Detach(value);
+ return S_OK;
+ }
+ return Libs[ci.LibIndex].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 CreateCoder2(false, index, iid, coder);
+ #endif
+ #ifdef EXTERNAL_CODECS
+ const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS];
+ if (ci.DecoderIsAssigned)
+ return Libs[ci.LibIndex].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 CreateCoder2(true, index, iid, coder);
+ #endif
+ #ifdef EXTERNAL_CODECS
+ const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS];
+ if (ci.EncoderIsAssigned)
+ return Libs[ci.LibIndex].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].Hashers->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].Hashers->CreateHasher(ci.HasherIndex, hasher);
+ #else
+ return E_FAIL;
+ #endif
+}
+
+int CCodecs::GetCodecLibIndex(UInt32 index)
+{
+ #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::GetCodecEncoderIsAssigned(UInt32 index)
+{
+ #ifdef EXPORT_CODECS
+ if (index < g_NumCodecs)
+ {
+ NCOM::CPropVariant prop;
+ if (GetProperty(index, NMethodPropID::kEncoder, &prop) == S_OK)
+ if (prop.vt != VT_EMPTY)
+ return true;
+ return false;
+ }
+ #endif
+ #ifdef EXTERNAL_CODECS
+ const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS];
+ return ci.EncoderIsAssigned;
+ #else
+ return false;
+ #endif
+}
+
+HRESULT CCodecs::GetCodecId(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;
+}
+
+UString CCodecs::GetCodecName(UInt32 index)
+{
+ UString s;
+ NCOM::CPropVariant prop;
+ if (GetProperty(index, NMethodPropID::kName, &prop) == S_OK)
+ if (prop.vt == VT_BSTR)
+ s = prop.bstrVal;
+ return s;
+}
+
+UInt64 CCodecs::GetHasherId(UInt32 index)
+{
+ NCOM::CPropVariant prop;
+ RINOK(GetHasherProp(index, NMethodPropID::kID, &prop));
+ if (prop.vt != VT_UI8)
+ return 0;
+ return prop.uhVal.QuadPart;
+}
+
+UString CCodecs::GetHasherName(UInt32 index)
+{
+ UString s;
+ NCOM::CPropVariant prop;
+ if (GetHasherProp(index, NMethodPropID::kName, &prop) == S_OK)
+ if (prop.vt == VT_BSTR)
+ s = 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
diff --git a/lzma/CPP/7zip/UI/Common/LoadCodecs.h b/lzma/CPP/7zip/UI/Common/LoadCodecs.h
new file mode 100644
index 0000000..eebb177
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Common/LoadCodecs.h
@@ -0,0 +1,303 @@
+// LoadCodecs.h
+
+#ifndef __LOAD_CODECS_H
+#define __LOAD_CODECS_H
+
+#include "../../../Common/MyBuffer.h"
+#include "../../../Common/MyCom.h"
+#include "../../../Common/MyString.h"
+#include "../../../Common/ComTry.h"
+
+#include "../../ICoder.h"
+
+#ifdef EXTERNAL_CODECS
+#include "../../../Windows/DLL.h"
+#endif
+
+struct CDllCodecInfo
+{
+ CLSID Encoder;
+ CLSID Decoder;
+ bool EncoderIsAssigned;
+ bool DecoderIsAssigned;
+ int LibIndex;
+ UInt32 CodecIndex;
+};
+
+struct CDllHasherInfo
+{
+ int LibIndex;
+ UInt32 HasherIndex;
+};
+
+#include "../../Archive/IArchive.h"
+
+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 EXTERNAL_CODECS
+
+#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
+
+struct CCodecLib
+ #ifdef NEW_FOLDER_INTERFACE
+ : public CCodecIcons
+ #endif
+{
+ NWindows::NDLL::CLibrary Lib;
+ FString Path;
+ Func_GetMethodProperty GetMethodProperty;
+ Func_CreateObject CreateObject;
+ CMyComPtr<IHashers> Hashers;
+
+ #ifdef NEW_FOLDER_INTERFACE
+ void LoadIcons() { CCodecIcons::LoadIcons((HMODULE)Lib); }
+ #endif
+
+ CCodecLib(): GetMethodProperty(NULL) {}
+};
+#endif
+
+class CCodecs:
+ #ifdef EXTERNAL_CODECS
+ public ICompressCodecsInfo,
+ public IHashers,
+ #else
+ public IUnknown,
+ #endif
+ public CMyUnknownImp
+{
+public:
+ #ifdef EXTERNAL_CODECS
+ CObjectVector<CCodecLib> Libs;
+ CRecordVector<CDllCodecInfo> Codecs;
+ CRecordVector<CDllHasherInfo> Hashers;
+
+ #ifdef NEW_FOLDER_INTERFACE
+ CCodecIcons InternalIcons;
+ #endif
+
+ HRESULT LoadCodecs();
+ HRESULT LoadFormats();
+ HRESULT LoadDll(const FString &path, bool needCheckDll);
+ HRESULT LoadDllsFromFolder(const FString &folderPrefix);
+
+ HRESULT CreateArchiveHandler(const CArcInfoEx &ai, void **archive, bool outHandler) const
+ {
+ return Libs[ai.LibIndex].CreateObject(&ai.ClassID, outHandler ? &IID_IOutArchive : &IID_IInArchive, (void **)archive);
+ }
+ #endif
+
+public:
+ CObjectVector<CArcInfoEx> Formats;
+ bool CaseSensitiveChange;
+ bool CaseSensitive;
+
+ CCodecs(): CaseSensitiveChange(false), CaseSensitive(false) {}
+
+ const wchar_t *GetFormatNamePtr(int formatIndex)
+ {
+ 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(GetNumberOfMethods)(UInt32 *numMethods);
+ STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value);
+ STDMETHOD(CreateDecoder)(UInt32 index, const GUID *interfaceID, void **coder);
+ STDMETHOD(CreateEncoder)(UInt32 index, const GUID *interfaceID, 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 GetCodecLibIndex(UInt32 index);
+ bool GetCodecEncoderIsAssigned(UInt32 index);
+ HRESULT GetCodecId(UInt32 index, UInt64 &id);
+ UString GetCodecName(UInt32 index);
+
+ int GetHasherLibIndex(UInt32 index);
+ UInt64 GetHasherId(UInt32 index);
+ UString 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, (void **)&archive, false);
+ #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, (void **)&archive, true);
+ #endif
+ }
+
+ int FindOutFormatFromName(const UString &name) const
+ {
+ FOR_VECTOR (i, Formats)
+ {
+ const CArcInfoEx &arc = Formats[i];
+ if (!arc.UpdateEnabled)
+ continue;
+ if (arc.Name.IsEqualToNoCase(name))
+ return i;
+ }
+ return -1;
+ }
+
+ #endif // _SFX
+};
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Common/OpenArchive.cpp b/lzma/CPP/7zip/UI/Common/OpenArchive.cpp
new file mode 100644
index 0000000..4632be8
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Common/OpenArchive.cpp
@@ -0,0 +1,3211 @@
+// 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 << 22;
+
+/*
+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);
+ void AddItem(const CParseItem &item);
+ // void Init();
+
+ CHandler()
+ {
+ _maxEndOffset = 0;
+ }
+};
+
+int CHandler::FindInsertPos(const CParseItem &item)
+{
+ 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 STATPROPSTG 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:
+ {
+ wchar_t sz[32];
+ ConvertUInt32ToString(index + 1, sz);
+ UString s = sz;
+ if (!item.Name.IsEmpty())
+ {
+ s += L'.';
+ s += item.Name;
+ }
+ if (!item.Extension.IsEmpty())
+ {
+ s += L'.';
+ 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_Folder(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)
+{
+ 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 = 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;
+}
+
+HRESULT CArc::GetItemPathToParent(UInt32 index, UInt32 parent, UStringVector &parts) const
+{
+ if (!GetRawProps)
+ return E_FAIL;
+ UInt32 curIndex = index;
+ bool prevWasAltStream = false;
+ for (;;)
+ {
+ UString s;
+
+ #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)
+ s = prop.bstrVal;
+ else if (prop.vt == VT_EMPTY)
+ s = L"[Content]";
+ else
+ return E_FAIL;
+ }
+
+ if (prevWasAltStream)
+ parts[0] = s + L":" + parts[0];
+ else
+ parts.Insert(0, s);
+
+ UInt32 curParent = (UInt32)(Int32)-1;
+ UInt32 parentType = 0;
+ RINOK(GetRawProps->GetParent(curIndex, &curParent, &parentType));
+ if (parent == curParent)
+ return S_OK;
+ if (curParent == (UInt32)(Int32)-1)
+ return E_FAIL;
+ prevWasAltStream = (parentType == NParentType::kAltStream);
+ curIndex = curParent;
+ }
+}
+
+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.GetBuffer(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;
+ }
+ result.ReleaseBuffer(len);
+ if (len != 0)
+ return S_OK;
+ }
+ }
+ /*
+ else if (GetRawProps->GetRawProp(index, kpidName, &p, &size, &propType) == S_OK &&
+ p && propType == NPropDataType::kUtf16z)
+ {
+ 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)
+ {
+ isOK = true;
+ break;
+ }
+ index2 = parent;
+ UInt32 size2;
+ const void *p2;
+ if (GetRawProps->GetRawProp(index2, kpidName, &p2, &size2, &propType) != S_OK)
+ break;
+ totalSize += size2;
+ }
+ }
+
+ if (isOK)
+ {
+ wchar_t *sz = result.GetBuffer(totalSize / 2);
+ UInt32 pos = totalSize - size;
+ memcpy((Byte *)sz + pos, p, size - 2);
+ 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)
+ 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':';
+ }
+ result.ReleaseBuffer((totalSize - 2) / 2);
+ #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)
+ result = prop.bstrVal;
+ else if (prop.vt == VT_EMPTY)
+ result.Empty();
+ else
+ return E_FAIL;
+ }
+
+ if (result.IsEmpty())
+ {
+ result = DefaultName;
+ NCOM::CPropVariant prop;
+ RINOK(Archive->GetProperty(index, kpidExtension, &prop));
+ if (prop.vt == VT_BSTR)
+ {
+ result += L'.';
+ 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;
+}
+
+#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[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, pos) ((buf)[pos])
+#else
+ static const unsigned kNumHashBytes = 2;
+ #define HASH_VAL(buf, pos) ((buf)[pos] | ((UInt32)(buf)[pos + 1] << 8))
+#endif
+
+
+#ifndef _SFX
+
+static bool IsExeExt(const UString &ext)
+{
+ return ext.IsEqualToNoCase(L"exe");
+}
+
+static const char *k_PreArcFormats[] =
+{
+ "pe"
+ , "elf"
+ , "macho"
+ , "mub"
+ , "te"
+};
+
+static bool IsNameFromList(const UString &s, const char *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 *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,
+ #ifndef _NO_CRYPTO
+ public ICryptoGetTextPassword,
+ #endif
+ public CMyUnknownImp
+{
+public:
+ CMyComPtr<IArchiveOpenCallback> Callback;
+ UInt64 Files;
+ UInt64 Offset;
+
+ #ifndef _NO_CRYPTO
+ CMyComPtr<ICryptoGetTextPassword> GetTextPassword;
+ MY_UNKNOWN_IMP2(
+ IArchiveOpenCallback,
+ ICryptoGetTextPassword)
+ #else
+ MY_UNKNOWN_IMP1(IArchiveOpenCallback)
+ #endif
+ STDMETHOD(SetTotal)(const UInt64 *files, const UInt64 *bytes);
+ STDMETHOD(SetCompleted)(const UInt64 *files, const UInt64 *bytes);
+ #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 * /* files */, const UInt64 * /* bytes */)
+{
+ return S_OK;
+}
+
+STDMETHODIMP CArchiveOpenCallback_Offset::SetCompleted(const UInt64 * /* files */, const UInt64 *bytes)
+{
+ if (!Callback)
+ return S_OK;
+ UInt64 value = Offset;
+ if (bytes)
+ value += *bytes;
+ return Callback->SetCompleted(&Files, &value);
+}
+
+#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)
+{
+ // OutputDebugStringW(L"a1");
+ // PrintNumber("formatIndex", formatIndex);
+
+ RINOK(op.codecs->CreateInArchive(formatIndex, archive));
+ // OutputDebugStringW(L"a2");
+ if (!archive)
+ return S_OK;
+
+ #ifdef EXTERNAL_CODECS
+ {
+ CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo;
+ archive.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo);
+ if (setCompressCodecsInfo)
+ {
+ RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(op.codecs));
+ }
+ }
+ #endif
+
+ // OutputDebugStringW(ai.Name);
+ // OutputDebugStringW(L"a3");
+
+ #ifndef _SFX
+ const CArcInfoEx &ai = op.codecs->Formats[formatIndex];
+ 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 = prop.bstrVal;
+ pi.Extension.Empty();
+ }
+ else
+ {
+ RINOK(archive->GetArchiveProperty(kpidExtension, &prop));
+ if (prop.vt == VT_BSTR)
+ pi.Extension = prop.bstrVal;
+ }
+ }
+
+ {
+ NCOM::CPropVariant prop;
+ RINOK(archive->GetArchiveProperty(kpidShortComment, &prop));
+ if (prop.vt == VT_BSTR)
+ pi.Comment = 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_Folder(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;
+
+ // OutputDebugStringW(L"1");
+ // OutputDebugStringW(Path);
+
+ const UString fileName = ExtractFileNameFromPath(Path);
+ UString extension;
+ {
+ int dotPos = fileName.ReverseFind(L'.');
+ 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[formatIndex] = true;
+
+ searchMarkerInHandler = true;
+ }
+ else
+ {
+ unsigned numFinded = 0;
+ #ifndef _SFX
+ bool isPrearcExt = false;
+ #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)
+ {
+ // 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 == L"000" || extension == L"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();
+
+ #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];
+ const CArcInfoEx &ai = op.codecs->Formats[FormatIndex];
+ // OutputDebugStringW(ai.Name);
+
+ bool exactOnly = false;
+ if (i >= numMainTypes)
+ {
+ if (!ai.Flags_BackwardOpen()
+ // && !ai.Flags_PureStartOpen()
+ )
+ continue;
+ exactOnly = true;
+ }
+
+ // Some handlers do not set total bytes. So we set it here
+ 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[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[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[formatIndex];
+ if (ai.FindExtension(extension) >= 0)
+ {
+ const CArcInfoEx &ai = op.codecs->Formats[formatIndex];
+ 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];
+
+ 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[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[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[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);
+ }
+ }
+
+ {
+ CArchiveOpenCallback_Offset *openCallback_Offset_Spec = new CArchiveOpenCallback_Offset;
+ CMyComPtr<IArchiveOpenCallback> openCallback_Offset = openCallback_Offset_Spec;
+
+ 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[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, 0);
+ unsigned sigIndex = arc2sig[index] + k;
+ prevs[sigIndex] = hash[v];
+ hash[v] = (Byte)sigIndex;
+ }
+ }
+ if (isDifficult)
+ {
+ difficultFormats.Add(index);
+ difficultBools[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);
+
+ openCallback_Offset_Spec->Callback = op.callback;
+
+ #ifndef _NO_CRYPTO
+ if (op.callback)
+ {
+ openCallback_Offset_Spec->Callback.QueryInterface(IID_ICryptoGetTextPassword, &openCallback_Offset_Spec->GetTextPassword);
+ }
+ #endif
+
+ 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 (pos >= callbackPrev + (1 << 23))
+ {
+ openCallback_Offset_Spec->Files = handlerSpec->_items.Size();
+ openCallback_Offset_Spec->Offset = pos;
+ RINOK(openCallback_Offset->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;
+ size_t ppp = 0;
+
+ if (!needCheckStartOpen)
+ {
+ for (; ppp < scanSize && hash[HASH_VAL(buf, ppp)] == 0xFF; ppp++);
+ pos += ppp;
+ if (ppp == scanSize)
+ continue;
+ }
+
+ UInt32 v = HASH_VAL(buf, ppp);
+ 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 + ppp, 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;
+ 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, openCallback_Offset, 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));
+
+ const UString fileName = ExtractFileNameFromPath(Path);
+ UString extension;
+ {
+ int dotPos = fileName.ReverseFind(L'.');
+ 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, L"", L"");
+ 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
+ static const wchar_t *k_ExeExt = L".exe";
+ static const unsigned k_ExeExt_Len = 4;
+#else
+ static const wchar_t *k_ExeExt = L"";
+ 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
+ && MyStringCompareNoCase(filePath.RightPtr(k_ExeExt_Len), k_ExeExt) == 0)
+ {
+ 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 += L".";
+ path3 += ai.GetMainExt(); // "7z" for SFX.
+ Path = path3 + L".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 (int i = Arcs.Size() - 1; i >= 0; i--)
+ {
+ CMyComPtr<IArchiveKeepModeForNextOpen> keep;
+ Arcs[i].Archive->QueryInterface(IID_IArchiveKeepModeForNextOpen, (void **)&keep);
+ if (keep)
+ keep->KeepModeForNextOpen();
+ }
+}
+
+HRESULT CArchiveLink::Close()
+{
+ for (int i = Arcs.Size() - 1; 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 += L'\n';
+ ErrorsText += GetUnicodeString(arc.ErrorFlagsText);
+ }
+ if (!arc.ErrorMessage.IsEmpty())
+ {
+ if (!ErrorsText.IsEmpty())
+ ErrorsText += L'\n';
+ ErrorsText += arc.ErrorMessage;
+ }
+
+ if (!arc.WarningMessage.IsEmpty())
+ {
+ if (!ErrorsText.IsEmpty())
+ ErrorsText += L'\n';
+ 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));
+
+ 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 = !
+ 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;
+}
+
+static void SetCallback(const FString &filePath,
+ IOpenCallbackUI *callbackUI,
+ IArchiveOpenCallback *reOpenCallback,
+ CMyComPtr<IArchiveOpenCallback> &callback)
+{
+ COpenCallbackImp *openCallbackSpec = new COpenCallbackImp;
+ callback = openCallbackSpec;
+ openCallbackSpec->Callback = callbackUI;
+ openCallbackSpec->ReOpenCallback = reOpenCallback;
+
+ FString dirPrefix, fileName;
+ NFile::NDir::GetFullPathAndSplit(filePath, dirPrefix, fileName);
+ openCallbackSpec->Init(dirPrefix, fileName);
+}
+
+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;
+ RINOK(Open(op));
+ // 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::ReOpen(COpenOptions &op)
+{
+ if (Arcs.Size() > 1)
+ return E_NOTIMPL;
+
+ CObjectVector<COpenType> inc;
+ CIntVector excl;
+
+ op.types = &inc;
+ op.excludedFormats = !
+ op.stdInMode = false;
+ op.stream = NULL;
+ if (Arcs.Size() == 0) // ???
+ return Open2(op, NULL);
+
+ CMyComPtr<IArchiveOpenCallback> openCallbackNew;
+ SetCallback(us2fs(op.filePath), NULL, op.callback, openCallbackNew);
+
+ 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);
+ 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(':');
+ 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(':', i);
+ if (next < 0)
+ next = s.Len();
+ 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('.', 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
diff --git a/lzma/CPP/7zip/UI/Common/OpenArchive.h b/lzma/CPP/7zip/UI/Common/OpenArchive.h
new file mode 100644
index 0000000..6f07323
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Common/OpenArchive.h
@@ -0,0 +1,346 @@
+// OpenArchive.h
+
+#ifndef __OPEN_ARCHIVE_H
+#define __OPEN_ARCHIVE_H
+
+#include "../../../Windows/PropVariant.h"
+
+#include "ArchiveOpenCallback.h"
+#include "LoadCodecs.h"
+#include "Property.h"
+
+HRESULT Archive_GetItemBoolProp(IInArchive *arc, UInt32 index, PROPID propID, bool &result) throw();
+HRESULT Archive_IsItem_Folder(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();
+
+/*
+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;
+ }
+};
+
+class CArc
+{
+ HRESULT PrepareToOpen(const COpenOptions &op, unsigned formatIndex, CMyComPtr<IInArchive> &archive);
+ HRESULT CheckZerosTail(const COpenOptions &op, UInt64 offset);
+ HRESULT OpenStream2(const COpenOptions &options);
+
+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 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 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),
+ 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();
+ }
+
+ // AltStream's name is concatenated with base file name in one string in parts.Back()
+ HRESULT GetItemPathToParent(UInt32 index, UInt32 parent, UStringVector &parts) const;
+
+ HRESULT GetItemPath(UInt32 index, UString &result) const;
+
+ // GetItemPath2 adds [DELETED] dir prefix for deleted items.
+ HRESULT GetItemPath2(UInt32 index, UString &result) 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;
+
+ // int NonOpenErrorFormatIndex; // - 1 means no Error.
+ UString NonOpen_ArcPath;
+
+ CArcErrorInfo NonOpen_ErrorInfo;
+
+ // UString ErrorsText;
+ // void Set_ErrorsText();
+
+ CArchiveLink(): VolumesSize(0), IsOpen(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 ReOpen(COpenOptions &options);
+};
+
+bool ParseOpenTypes(CCodecs &codecs, const UString &s, CObjectVector<COpenType> &types);
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Common/PropIDUtils.cpp b/lzma/CPP/7zip/UI/Common/PropIDUtils.cpp
new file mode 100644
index 0000000..a9278cd
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Common/PropIDUtils.cpp
@@ -0,0 +1,553 @@
+// PropIDUtils.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/CpuArch.h"
+
+#include "../../../Common/IntToString.h"
+#include "../../../Common/StringConvert.h"
+
+#include "../../../Windows/FileFind.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 char g_WinAttribChars[16 + 1] = "RHS8DAdNTsLCOnE_";
+/*
+0 READONLY
+1 HIDDEN
+2 SYSTEM
+
+4 DIRECTORY
+5 ARCHIVE
+6 DEVICE
+7 NORMAL
+8 TEMPORARY
+9 SPARSE_FILE
+10 REPARSE_POINT
+11 COMPRESSED
+12 OFFLINE
+13 NOT_CONTENT_INDEXED
+14 ENCRYPTED
+
+16 VIRTUAL
+*/
+
+void ConvertWinAttribToString(char *s, UInt32 wa)
+{
+ for (int i = 0; i < 16; i++)
+ if ((wa & (1 << i)) && i != 7)
+ *s++ = g_WinAttribChars[i];
+ *s = 0;
+}
+
+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 : '-';
+
+void ConvertPropertyToShortString(char *dest, const PROPVARIANT &prop, PROPID propID, bool full) throw()
+{
+ *dest = 0;
+ if (prop.vt == VT_FILETIME)
+ {
+ FILETIME localFileTime;
+ if ((prop.filetime.dwHighDateTime == 0 &&
+ prop.filetime.dwLowDateTime == 0) ||
+ !::FileTimeToLocalFileTime(&prop.filetime, &localFileTime))
+ return;
+ ConvertFileTimeToString(localFileTime, dest, true, full);
+ return;
+ }
+ switch (propID)
+ {
+ case kpidCRC:
+ {
+ if (prop.vt != VT_UI4)
+ break;
+ ConvertUInt32ToHex8Digits(prop.ulVal, dest);
+ return;
+ }
+ case kpidAttrib:
+ {
+ if (prop.vt != VT_UI4)
+ break;
+ ConvertWinAttribToString(dest, prop.ulVal);
+ return;
+ }
+ case kpidPosixAttrib:
+ {
+ if (prop.vt != VT_UI4)
+ break;
+ UString res;
+ UInt32 a = prop.ulVal;
+
+ dest[0] = kPosixTypes[(a >> 12) & 0xF];
+ for (int i = 6; i >= 0; i -= 3)
+ {
+ dest[7 - i] = MY_ATTR_CHAR(a, i + 2, 'r');
+ dest[8 - i] = MY_ATTR_CHAR(a, i + 1, 'w');
+ dest[9 - i] = MY_ATTR_CHAR(a, i + 0, 'x');
+ }
+ if ((a & 0x800) != 0) dest[3] = ((a & (1 << 6)) ? 's' : 'S');
+ if ((a & 0x400) != 0) dest[6] = ((a & (1 << 3)) ? 's' : 'S');
+ if ((a & 0x200) != 0) dest[9] = ((a & (1 << 0)) ? 't' : 'T');
+ dest[10] = 0;
+
+ a &= ~(UInt32)0xFFFF;
+ if (a != 0)
+ {
+ dest[10] = ' ';
+ ConvertUInt32ToHex8Digits(a, dest + 11);
+ }
+ 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 (ConvertPropVariantToUInt64(prop, v))
+ {
+ dest[0] = '0';
+ dest[1] = 'x';
+ ConvertUInt64ToHex(prop.ulVal, dest + 2);
+ return;
+ }
+ break;
+ }
+ }
+ ConvertPropVariantToShortString(prop, dest);
+}
+
+void ConvertPropertyToString(UString &dest, const PROPVARIANT &prop, PROPID propID, bool full)
+{
+ if (prop.vt == VT_BSTR)
+ {
+ dest = prop.bstrVal;
+ return;
+ }
+ char temp[64];
+ ConvertPropertyToShortString(temp, prop, propID, full);
+ int len = MyStringLen(temp);
+ wchar_t *str = dest.GetBuffer(len);
+ for (int i = 0; i < len; i++)
+ str[i] = temp[i];
+ dest.ReleaseBuffer(len);
+}
+
+static inline char GetHex(Byte value)
+{
+ return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10)));
+}
+
+#ifndef _SFX
+
+static inline void AddHexToString(AString &res, Byte value)
+{
+ res += GetHex((Byte)(value >> 4));
+ res += GetHex((Byte)(value & 0xF));
+ res += ' ';
+}
+
+/*
+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 *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;
+};
+
+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);
+ for (int i = 0; i < ARRAY_SIZE(sid_32_Names); i++)
+ if (sid_32_Names[i].n == v1)
+ {
+ s += sid_32_Names[i].sz;
+ return;
+ }
+ }
+ if (v0 == 21 && num == 5)
+ {
+ UInt32 v4 = Get32(p + 8 + 4 * 4);
+ for (int i = 0; i < ARRAY_SIZE(sid_21_Names); i++)
+ if (sid_21_Names[i].n == v4)
+ {
+ s += sid_21_Names[i].sz;
+ return;
+ }
+ }
+ if (v0 == 80 && num == 6)
+ {
+ for (int 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;
+ }
+ }
+ }
+ }
+
+ char sz[16];
+ s += "S-1-";
+ if (p[2] == 0 && p[3] == 0)
+ {
+ ConvertUInt32ToString(authority, sz);
+ s += sz;
+ }
+ else
+ {
+ s += "0x";
+ for (int i = 2; i < 8; i++)
+ AddHexToString(s, p[i]);
+ }
+ for (UInt32 i = 0; i < num; i++)
+ {
+ s += '-';
+ ConvertUInt32ToString(Get32(p + 8 + i * 4), sz);
+ s += sz;
+ }
+}
+
+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 AddUInt32ToString(AString &s, UInt32 val)
+{
+ char sz[16];
+ ConvertUInt32ToString(val, sz);
+ s += sz;
+}
+
+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 += ' ';
+ s += strName;
+ if (pos >= size)
+ return;
+ p += pos;
+ size -= pos;
+ if (size < 8)
+ return;
+ if (Get16(p) != 2) // revision
+ return;
+ // UInt32 aclSize = Get16(p + 2);
+ UInt32 num = Get32(p + 4);
+ AddUInt32ToString(s, num);
+ /*
+ 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 += ' ';
+ s += ParseSid(p, size, sidSize);
+ if (sidSize == 0)
+ return;
+ p += sidSize;
+ size -= sidSize;
+ }
+ 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 += ' ';
+ 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 += ' ';
+ AddUInt32ToString(s, size);
+ // s += '\n';
+ // s += Data_To_Hex(data, size);
+}
+
+#ifdef _WIN32
+
+static bool CheckSid(const Byte *data, UInt32 size, UInt32 pos)
+{
+ 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)
+{
+ 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)
+{
+ 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
+
+bool ConvertNtReparseToString(const Byte *data, UInt32 size, UString &s)
+{
+ s.Empty();
+ NFile::CReparseAttr attr;
+ if (attr.Parse(data, size))
+ {
+ if (!attr.IsSymLink())
+ s += L"Junction: ";
+ s += attr.GetPath();
+ if (!attr.IsOkNamePair())
+ {
+ s += L" : ";
+ 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;
+
+ char hex[16];
+ ConvertUInt32ToHex8Digits(tag, hex);
+ s.AddAsciiStr(hex);
+ s += L' ';
+
+ data += 8;
+
+ for (UInt32 i = 0; i < len; i++)
+ {
+ Byte b = ((const Byte *)data)[i];
+ s += (wchar_t)GetHex((Byte)((b >> 4) & 0xF));
+ s += (wchar_t)GetHex((Byte)(b & 0xF));
+ }
+ return true;
+}
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Common/PropIDUtils.h b/lzma/CPP/7zip/UI/Common/PropIDUtils.h
new file mode 100644
index 0000000..fcfbc8c
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Common/PropIDUtils.h
@@ -0,0 +1,17 @@
+// 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 ConvertPropertyToShortString(char *dest, const PROPVARIANT &propVariant, PROPID propID, bool full = true) throw();
+void ConvertPropertyToString(UString &dest, const PROPVARIANT &propVariant, PROPID propID, bool full = true);
+
+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);
+void ConvertWinAttribToString(char *s, UInt32 wa);
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Common/Property.h b/lzma/CPP/7zip/UI/Common/Property.h
new file mode 100644
index 0000000..31234ad
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Common/Property.h
@@ -0,0 +1,14 @@
+// Property.h
+
+#ifndef __7Z_PROPERTY_H
+#define __7Z_PROPERTY_H
+
+#include "../../../Common/MyString.h"
+
+struct CProperty
+{
+ UString Name;
+ UString Value;
+};
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Common/SetProperties.cpp b/lzma/CPP/7zip/UI/Common/SetProperties.cpp
new file mode 100644
index 0000000..3cd4d57
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Common/SetProperties.cpp
@@ -0,0 +1,80 @@
+// 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;
+}
diff --git a/lzma/CPP/7zip/UI/Common/SetProperties.h b/lzma/CPP/7zip/UI/Common/SetProperties.h
new file mode 100644
index 0000000..64c947c
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Common/SetProperties.h
@@ -0,0 +1,10 @@
+// SetProperties.h
+
+#ifndef __SETPROPERTIES_H
+#define __SETPROPERTIES_H
+
+#include "Property.h"
+
+HRESULT SetProperties(IUnknown *unknown, const CObjectVector<CProperty> &properties);
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Common/SortUtils.cpp b/lzma/CPP/7zip/UI/Common/SortUtils.cpp
new file mode 100644
index 0000000..4510ffd
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Common/SortUtils.cpp
@@ -0,0 +1,23 @@
+// 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)
+{
+ unsigned numItems = strings.Size();
+ indices.ClearAndSetSize(numItems);
+ unsigned *vals = &indices[0];
+ for (unsigned i = 0; i < numItems; i++)
+ vals[i] = i;
+ indices.Sort(CompareStrings, (void *)&strings);
+}
diff --git a/lzma/CPP/7zip/UI/Common/SortUtils.h b/lzma/CPP/7zip/UI/Common/SortUtils.h
new file mode 100644
index 0000000..82d5e4c
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Common/SortUtils.h
@@ -0,0 +1,10 @@
+// SortUtils.h
+
+#ifndef __SORT_UTLS_H
+#define __SORT_UTLS_H
+
+#include "../../../Common/MyString.h"
+
+void SortFileNames(const UStringVector &strings, CUIntVector &indices);
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Common/StdAfx.h b/lzma/CPP/7zip/UI/Common/StdAfx.h
new file mode 100644
index 0000000..59d9ac1
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Common/StdAfx.h
@@ -0,0 +1,8 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "../../../Common/Common.h"
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Common/TempFiles.cpp b/lzma/CPP/7zip/UI/Common/TempFiles.cpp
new file mode 100644
index 0000000..cfbee1a
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Common/TempFiles.cpp
@@ -0,0 +1,21 @@
+// 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/lzma/CPP/7zip/UI/Common/TempFiles.h b/lzma/CPP/7zip/UI/Common/TempFiles.h
new file mode 100644
index 0000000..f62192d
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Common/TempFiles.h
@@ -0,0 +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
diff --git a/lzma/CPP/7zip/UI/Common/Update.cpp b/lzma/CPP/7zip/UI/Common/Update.cpp
new file mode 100644
index 0000000..ee13311
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Common/Update.cpp
@@ -0,0 +1,1477 @@
+// Update.cpp
+
+#include "StdAfx.h"
+
+#include "Update.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/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 *kUpdateIsNotSupoorted =
+ "update operations are not supported for this archive";
+
+using namespace NWindows;
+using namespace NCOM;
+using namespace NFile;
+using namespace NDir;
+using namespace NName;
+
+static CFSTR kTempFolderPrefix = FTEXT("7zE");
+
+
+static bool DeleteEmptyFolderAndEmptySubFolders(const FString &path)
+{
+ NFind::CFileInfo fileInfo;
+ FString pathPrefix = path + FCHAR_PATH_SEPARATOR;
+ {
+ NFind::CEnumerator enumerator(pathPrefix + FCHAR_ANY_MASK);
+ 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();
+
+ 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 != NULL)
+ *processedSize = 0;
+ while (size > 0)
+ {
+ if (_streamIndex >= Streams.Size())
+ {
+ CAltStreamInfo altStream;
+
+ FChar temp[16];
+ ConvertUInt32ToString(_streamIndex + 1, temp);
+ FString res = temp;
+ while (res.Len() < 3)
+ res = FString(FTEXT('0')) + res;
+ FString name = Prefix + res;
+ 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 != NULL)
+ *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 != NULL)
+ *newPosition = _absPos;
+ _streamIndex = 0;
+ return S_OK;
+}
+
+STDMETHODIMP COutMultiVolStream::SetSize(UInt64 newSize)
+{
+ if (newSize < 0)
+ return E_INVALIDARG;
+ 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)
+ {
+ BaseExtension.Empty();
+ return;
+ }
+
+ int dotPos = Name.ReverseFind(L'.');
+ if (dotPos < 0)
+ return;
+ if ((unsigned)dotPos == Name.Len() - 1)
+ {
+ Name.DeleteBack();
+ BaseExtension.Empty();
+ return;
+ }
+ const UString ext = Name.Ptr(dotPos + 1);
+ if (BaseExtension.IsEqualToNoCase(ext))
+ {
+ BaseExtension = ext;
+ Name.DeleteFrom(dotPos);
+ }
+ else
+ BaseExtension.Empty();
+}
+
+UString CArchivePath::GetFinalPath() const
+{
+ UString path = GetPathWithoutExt();
+ if (!BaseExtension.IsEmpty())
+ path += UString(L'.') + BaseExtension;
+ return path;
+}
+
+UString CArchivePath::GetFinalVolPath() const
+{
+ UString path = GetPathWithoutExt();
+ if (!BaseExtension.IsEmpty())
+ path += UString(L'.') + VolExtension;
+ return path;
+}
+
+FString CArchivePath::GetTempPath() const
+{
+ FString path = TempPrefix + us2fs(Name);
+ if (!BaseExtension.IsEmpty())
+ path += FString(FTEXT('.')) + us2fs(BaseExtension);
+ path += FTEXT(".tmp");
+ path += TempPostfix;
+ return path;
+}
+
+static const wchar_t *kDefaultArcType = L"7z";
+static const wchar_t *kDefaultArcExt = L"7z";
+static const wchar_t *kSFXExtension =
+ #ifdef _WIN32
+ L"exe";
+ #else
+ L"";
+ #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;
+
+ CUpdateProduceCallbackImp(const CObjectVector<CArcItem> *a,
+ IUpdateCallbackUI *callback): _arcItems(a), _callback(callback) {}
+ virtual HRESULT ShowDeleteFile(int arcIndex);
+};
+
+HRESULT CUpdateProduceCallbackImp::ShowDeleteFile(int arcIndex)
+{
+ return _callback->ShowDeleteFile((*_arcItems)[arcIndex].Name);
+}
+*/
+
+bool CRenamePair::Prepare()
+{
+ if (RecursedType != NRecursedType::kNonRecursed)
+ return false;
+ if (!WildcardParsing)
+ return true;
+ return !DoesNameContainWildcard(OldName);
+}
+
+extern bool g_CaseSensitive;
+
+static int CompareTwoNames(const wchar_t *s1, const wchar_t *s2)
+{
+ for (int 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 (IsCharDirLimiter(c1) && IsCharDirLimiter(c2))
+ continue;
+ return i;
+ }
+}
+
+bool CRenamePair::GetNewPath(bool isFolder, const UString &src, UString &dest) const
+{
+ int num = CompareTwoNames(OldName, src);
+ if (OldName[num] == 0)
+ {
+ if (src[num] != 0 && !IsCharDirLimiter(src[num]) && num != 0 && !IsCharDirLimiter(src[num - 1]))
+ return false;
+ }
+ else
+ {
+ // OldName[num] != 0
+ // OldName = "1\1a.txt"
+ // src = "1"
+
+ if (!isFolder ||
+ src[num] != 0 ||
+ !IsCharDirLimiter(OldName[num]) ||
+ OldName[num + 1] != 0)
+ return false;
+ }
+ dest = NewName + src.Ptr(num);
+ return true;
+}
+
+static int GetReverseSlashPos(const UString &name)
+{
+ int slashPos = name.ReverseFind(L'/');
+ #ifdef _WIN32
+ int slash1Pos = name.ReverseFind(L'\\');
+ slashPos = MyMax(slashPos, slash1Pos);
+ #endif
+ return slashPos;
+}
+
+static HRESULT Compress(
+ const CUpdateOptions &options,
+ 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)
+{
+ 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;
+
+ 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;
+ }
+ if (ai.IsAltStream)
+ {
+ int colonPos = ai.Name.ReverseFind(':');
+ int slashPosPos = GetReverseSlashPos(ai.Name);
+ if (colonPos > slashPosPos)
+ {
+ 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;
+ }
+ }
+ }
+ }
+ }
+ 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, callback);
+ UpdateProduce(updatePairs, actionSet, updatePairs2, NULL /* &upCallback */);
+ }
+
+ UInt32 numFiles = 0;
+ FOR_VECTOR (i, updatePairs2)
+ if (updatePairs2[i].NewData)
+ numFiles++;
+
+ RINOK(callback->SetNumFiles(numFiles));
+
+ CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback;
+ CMyComPtr<IArchiveUpdateCallback> updateCallback(updateCallbackSpec);
+
+ updateCallbackSpec->ShareForWrite = options.OpenShareForWrite;
+ 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->GetRawProps = arc->GetRawProps;
+ updateCallbackSpec->GetRootProps = arc->GetRootProps;
+ }
+
+ updateCallbackSpec->DirItems = &dirItems;
+ updateCallbackSpec->ParentDirItem = parentDirItem;
+
+ updateCallbackSpec->StoreNtSecurity = options.NtSecurity.Val;
+ updateCallbackSpec->StoreHardLinks = options.HardLinks.Val;
+ updateCallbackSpec->StoreSymLinks = options.SymLinks.Val;
+
+ 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;
+ COutMultiVolStream *volStreamSpec = NULL;
+
+ if (options.VolumesSizes.Size() == 0)
+ {
+ if (options.StdOutMode)
+ outStream = new CStdOutFileStream;
+ else
+ {
+ outStreamSpec = new COutFileStream;
+ outSeekStream = outStreamSpec;
+ outStream = outSeekStream;
+ bool isOK = false;
+ FString realPath;
+ for (int i = 0; i < (1 << 16); i++)
+ {
+ if (archivePath.Temp)
+ {
+ if (i > 0)
+ {
+ FChar s[16];
+ ConvertUInt32ToString(i, s);
+ archivePath.TempPostfix = s;
+ }
+ 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)
+ {
+ errorInfo.SystemError = ::GetLastError();
+ errorInfo.FileName = realPath;
+ errorInfo.Message = L"7-Zip cannot open file";
+ return E_FAIL;
+ }
+ }
+ }
+ 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() + L".");
+ volStreamSpec->TempFiles = &tempFiles;
+ volStreamSpec->Init();
+
+ /*
+ updateCallbackSpec->VolumesSizes = volumesSizes;
+ updateCallbackSpec->VolName = archivePath.Prefix + archivePath.Name;
+ if (!archivePath.VolExtension.IsEmpty())
+ updateCallbackSpec->VolExt = UString(L'.') + archivePath.VolExtension;
+ */
+ }
+
+ RINOK(SetProperties(outArchive, options.MethodMode.Properties));
+
+ if (options.SfxMode)
+ {
+ CInFileStream *sfxStreamSpec = new CInFileStream;
+ CMyComPtr<IInStream> sfxStream(sfxStreamSpec);
+ if (!sfxStreamSpec->Open(options.SfxModule))
+ {
+ errorInfo.SystemError = ::GetLastError();
+ errorInfo.Message = L"7-Zip cannot open SFX module";
+ errorInfo.FileName = options.SfxModule;
+ return E_FAIL;
+ }
+
+ CMyComPtr<ISequentialOutStream> sfxOutStream;
+ COutFileStream *outStreamSpec = NULL;
+ if (options.VolumesSizes.Size() == 0)
+ sfxOutStream = outStream;
+ else
+ {
+ outStreamSpec = new COutFileStream;
+ sfxOutStream = outStreamSpec;
+ FString realPath = us2fs(archivePath.GetFinalPath());
+ if (!outStreamSpec->Create(realPath, false))
+ {
+ errorInfo.SystemError = ::GetLastError();
+ errorInfo.FileName = realPath;
+ errorInfo.Message = L"7-Zip cannot open file";
+ return E_FAIL;
+ }
+ }
+ RINOK(NCompress::CopyStream(sfxStream, sfxOutStream, NULL));
+ if (outStreamSpec)
+ {
+ RINOK(outStreamSpec->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->Finilize();
+ RINOK(result);
+
+
+ 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 (outStreamSpec)
+ result = outStreamSpec->Close();
+ else if (volStreamSpec)
+ result = volStreamSpec->Close();
+ return result;
+}
+
+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);
+ for (UInt32 i = 0; i < numItems; i++)
+ {
+ CArcItem ai;
+
+ RINOK(arc.GetItemPath(i, ai.Name));
+ RINOK(Archive_IsItem_Folder(archive, i, ai.IsDir));
+ RINOK(Archive_IsItem_AltStream(archive, i, ai.IsAltStream));
+ /*
+ if (!storeStreamsMode && ai.IsAltStream)
+ continue;
+ */
+ ai.Censored = censor.CheckPath(ai.IsAltStream, ai.Name, !ai.IsDir);
+ 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;
+}
+
+struct CEnumDirItemUpdateCallback: public IEnumDirItemCallback
+{
+ IUpdateCallbackUI2 *Callback;
+ HRESULT ScanProgress(UInt64 numFolders, UInt64 numFiles, UInt64 totalSize, const wchar_t *path, bool isDir)
+ {
+ return Callback->ScanProgress(numFolders, numFiles, totalSize, path, isDir);
+ }
+};
+
+#if defined(_WIN32) && !defined(UNDER_CE)
+
+#include <mapi.h>
+
+#endif
+
+struct CRefSortPair
+{
+ int Len;
+ int Index;
+};
+
+#define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; }
+
+static int CompareRefSortPair(const CRefSortPair *a1, const CRefSortPair *a2, void *)
+{
+ RINOZ(-MyCompare(a1->Len, a2->Len));
+ return MyCompare(a1->Index, a2->Index);
+}
+
+static int GetNumSlashes(const FChar *s)
+{
+ for (int numSlashes = 0;;)
+ {
+ FChar c = *s++;
+ if (c == 0)
+ return numSlashes;
+ if (
+ #ifdef _WIN32
+ c == FTEXT('\\') ||
+ #endif
+ c == FTEXT('/'))
+ numSlashes++;
+ }
+}
+
+#ifdef _WIN32
+void ConvertToLongNames(NWildcard::CCensor &censor);
+#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 = L"rsfx";
+ property.Value = L"on";
+ options.MethodMode.Properties.Add(property);
+ if (options.SfxModule.IsEmpty())
+ {
+ errorInfo.Message = L"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))
+ {
+ errorInfo.SystemError = ::GetLastError();
+ errorInfo.Message = L"7-Zip cannot find specified SFX module";
+ errorInfo.FileName = options.SfxModule;
+ return E_FAIL;
+ }
+ }
+ }
+
+ CArchiveLink arcLink;
+
+
+ if (needSetPath)
+ {
+ if (!options.InitFormatIndex(codecs, types, cmdArcPath2) ||
+ !options.SetArcPath(codecs, cmdArcPath2))
+ return E_NOTIMPL;
+ }
+ UString arcPath = options.ArchivePath.GetFinalPath();
+
+ 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.VolumesSizes.Size() > 0)
+ return E_NOTIMPL;
+ CObjectVector<COpenType> types;
+ // change it.
+ if (options.MethodMode.Type_Defined)
+ types.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 = &types;
+ op.excludedFormats = !
+ op.stdInMode = false;
+ op.stream = NULL;
+ op.filePath = arcPath;
+
+ HRESULT result = arcLink.Open2(op, openCallback);
+
+ if (result == E_ABORT)
+ return result;
+
+ const wchar_t *errorArcType = NULL;
+ if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex > 0)
+ errorArcType = codecs->Formats[arcLink.NonOpen_ErrorInfo.ErrorFormatIndex].Name;
+ RINOK(callback->OpenResult(arcPath, result, errorArcType));
+ /*
+ if (result == S_FALSE)
+ return E_FAIL;
+ */
+ RINOK(result);
+ if (arcLink.VolumePaths.Size() > 1)
+ {
+ errorInfo.SystemError = (DWORD)E_NOTIMPL;
+ errorInfo.Message = L"Updating for multivolume archives is not implemented";
+ 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 = L"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(kDefaultArcType);
+ if (options.MethodMode.Type.FormatIndex < 0)
+ return E_NOTIMPL;
+ }
+
+ bool thereIsInArchive = arcLink.IsOpen;
+ if (!thereIsInArchive && renameMode)
+ return E_FAIL;
+
+ CDirItems dirItems;
+ 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)
+ {
+ CEnumDirItemUpdateCallback enumCallback;
+ enumCallback.Callback = callback;
+ 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, &enumCallback);
+ FOR_VECTOR (i, dirItems.ErrorPaths)
+ {
+ RINOK(callback->CanNotFindError(fs2us(dirItems.ErrorPaths[i]), dirItems.ErrorCodes[i]));
+ }
+ if (res != S_OK)
+ {
+ if (res != E_ABORT)
+ errorInfo.Message = L"Scanning error";
+ return res;
+ }
+ RINOK(callback->FinishScanning());
+
+ if (censor.Pairs.Size() == 1)
+ {
+ NFind::CFileInfo fi;
+ FString prefix = us2fs(censor.Pairs[0].Prefix) + FTEXT(".");
+ // 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 i;
+ for (i = 0; i < options.Commands.Size(); i++)
+ {
+ CArchivePath &ap = options.Commands[i].ArchivePath;
+ if (usesTempDir)
+ {
+ // Check it
+ ap.Prefix = fs2us(tempDirPrefix);
+ // ap.Temp = true;
+ // ap.TempPrefix = tempDirPrefix;
+ }
+ if (!options.StdOutMode &&
+ (i > 0 || !createTempFile))
+ {
+ const FString path = us2fs(ap.GetFinalPath());
+ if (NFind::DoesFileOrDirExist(path))
+ {
+ errorInfo.SystemError = 0;
+ errorInfo.Message = L"The file already exists";
+ errorInfo.FileName = path;
+ return E_FAIL;
+ }
+ }
+ }
+
+ 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 (i = 0; i < num; i++)
+ processedItems[i] = 0;
+ }
+
+ for (i = 0; i < options.Commands.Size(); i++)
+ {
+ const CArc *arc = thereIsInArchive ? arcLink.GetArc() : 0;
+ // IInArchiveExtra *archiveExtra = thereIsInArchive ? arcLink.GetArchiveExtra() : 0;
+ // IArchiveGetRootProps *archiveGetRootProps = thereIsInArchive ? arcLink.GetArchiveGetRootProps() : 0;
+ CUpdateArchiveCommand &command = options.Commands[i];
+ UString name;
+ bool isUpdating;
+ if (options.StdOutMode)
+ {
+ name = L"stdout";
+ isUpdating = arc != 0;
+ }
+ else
+ {
+ name = command.ArchivePath.GetFinalPath();
+ isUpdating = (i == 0 && options.UpdateArchiveItself && arc != 0);
+ }
+ RINOK(callback->StartArchive(name, isUpdating))
+
+ RINOK(Compress(options,
+ codecs,
+ command.ActionSet,
+ arc,
+ command.ArchivePath,
+ arcItems,
+ options.DeleteAfterCompressing ? (Byte *)processedItems : NULL,
+
+ dirItems,
+ parentDirItem_Ptr,
+
+ tempFiles,
+ errorInfo, callback));
+
+ RINOK(callback->FinishArchive());
+ }
+
+
+ if (thereIsInArchive)
+ {
+ RINOK(arcLink.Close());
+ arcLink.Release();
+ }
+
+ tempFiles.Paths.Clear();
+ if (createTempFile)
+ {
+ try
+ {
+ CArchivePath &ap = options.Commands[0].ArchivePath;
+ const FString &tempPath = ap.GetTempPath();
+ if (thereIsInArchive)
+ if (!DeleteFileAlways(us2fs(arcPath)))
+ {
+ errorInfo.SystemError = ::GetLastError();
+ errorInfo.Message = L"7-Zip cannot delete the file";
+ errorInfo.FileName = us2fs(arcPath);
+ return E_FAIL;
+ }
+ if (!MyMoveFile(tempPath, us2fs(arcPath)))
+ {
+ errorInfo.SystemError = ::GetLastError();
+ errorInfo.Message = L"7-Zip cannot move the file";
+ errorInfo.FileName = tempPath;
+ errorInfo.FileName2 = us2fs(arcPath);
+ return E_FAIL;
+ }
+ }
+ catch(...)
+ {
+ throw;
+ }
+ }
+
+
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ if (options.EMailMode)
+ {
+ NDLL::CLibrary mapiLib;
+ if (!mapiLib.Load(FTEXT("Mapi32.dll")))
+ {
+ errorInfo.SystemError = ::GetLastError();
+ errorInfo.Message = L"7-Zip cannot load Mapi32.dll";
+ return E_FAIL;
+ }
+
+ /*
+ LPMAPISENDDOCUMENTS fnSend = (LPMAPISENDDOCUMENTS)mapiLib.GetProc("MAPISendDocuments");
+ if (fnSend == 0)
+ {
+ errorInfo.SystemError = ::GetLastError();
+ errorInfo.Message = L"7-Zip cannot find MAPISendDocuments function";
+ return E_FAIL;
+ }
+ */
+ LPMAPISENDMAIL sendMail = (LPMAPISENDMAIL)mapiLib.GetProc("MAPISendMail");
+ if (sendMail == 0)
+ {
+ errorInfo.SystemError = ::GetLastError();
+ errorInfo.Message = L"7-Zip cannot find MAPISendMail function";
+ return E_FAIL;
+ }
+
+ FStringVector fullPaths;
+ unsigned i;
+ for (i = 0; i < options.Commands.Size(); i++)
+ {
+ CArchivePath &ap = options.Commands[i].ArchivePath;
+ FString arcPath;
+ if (!MyGetFullPathName(us2fs(ap.GetFinalPath()), arcPath))
+ {
+ errorInfo.SystemError = ::GetLastError();
+ errorInfo.Message = L"GetFullPathName error";
+ return E_FAIL;
+ }
+ fullPaths.Add(arcPath);
+ }
+ CCurrentDirRestorer curDirRestorer;
+ for (i = 0; i < fullPaths.Size(); i++)
+ {
+ UString arcPath = fs2us(fullPaths[i]);
+ UString fileName = ExtractFileNameFromPath(arcPath);
+ AString path = GetAnsiString(arcPath);
+ AString name = GetAnsiString(fileName);
+ // Warning!!! MAPISendDocuments function changes Current directory
+ // fnSend(0, ";", (LPSTR)(LPCSTR)path, (LPSTR)(LPCSTR)name, 0);
+
+ MapiFileDesc f;
+ memset(&f, 0, sizeof(f));
+ f.nPosition = 0xFFFFFFFF;
+ f.lpszPathName = (char *)(const char *)path;
+ f.lpszFileName = (char *)(const char *)name;
+
+ MapiMessage m;
+ memset(&m, 0, sizeof(m));
+ m.nFileCount = 1;
+ m.lpFiles = &f;
+
+ 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<CRefSortPair> pairs;
+ FStringVector foldersNames;
+ for (i = 0; i < dirItems.Items.Size(); i++)
+ {
+ const CDirItem &dirItem = dirItems.Items[i];
+ FString phyPath = us2fs(dirItems.GetPhyPath(i));
+ if (dirItem.IsDir())
+ {
+ CRefSortPair pair;
+ pair.Index = i;
+ pair.Len = GetNumSlashes(phyPath);
+ pairs.Add(pair);
+ }
+ else
+ {
+ if (processedItems[i] != 0 || dirItem.Size == 0)
+ {
+ DeleteFileAlways(phyPath);
+ }
+ else
+ {
+ // file was skipped
+ /*
+ errorInfo.SystemError = 0;
+ errorInfo.Message = L"file was not processed";
+ errorInfo.FileName = phyPath;
+ return E_FAIL;
+ */
+ }
+ }
+ }
+
+ pairs.Sort(CompareRefSortPair, NULL);
+ for (i = 0; i < pairs.Size(); i++)
+ {
+ FString phyPath = us2fs(dirItems.GetPhyPath(pairs[i].Index));
+ if (NFind::DoesDirExist(phyPath))
+ {
+ // printf("delete %S\n", phyPath);
+ RemoveDir(phyPath);
+ }
+ }
+ }
+ return S_OK;
+}
diff --git a/lzma/CPP/7zip/UI/Common/Update.h b/lzma/CPP/7zip/UI/Common/Update.h
new file mode 100644
index 0000000..2d1d131
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Common/Update.h
@@ -0,0 +1,188 @@
+// 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"
+
+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 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),
+ 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 CErrorInfo
+{
+ DWORD SystemError;
+ FString FileName;
+ FString FileName2;
+ UString Message;
+ // UStringVector ErrorPaths;
+ // CRecordVector<DWORD> ErrorCodes;
+ CErrorInfo(): SystemError(0) {};
+};
+
+struct CUpdateErrorInfo: public CErrorInfo
+{
+};
+
+#define INTERFACE_IUpdateCallbackUI2(x) \
+ INTERFACE_IUpdateCallbackUI(x) \
+ virtual HRESULT OpenResult(const wchar_t *name, HRESULT result, const wchar_t *errorArcType) x; \
+ virtual HRESULT StartScanning() x; \
+ virtual HRESULT ScanProgress(UInt64 numFolders, UInt64 numFiles, UInt64 totalSize, const wchar_t *path, bool isDir) x; \
+ virtual HRESULT CanNotFindError(const wchar_t *name, DWORD systemError) x; \
+ virtual HRESULT FinishScanning() x; \
+ virtual HRESULT StartArchive(const wchar_t *name, bool updating) x; \
+ virtual HRESULT FinishArchive() x; \
+
+struct IUpdateCallbackUI2: public IUpdateCallbackUI
+{
+ 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
diff --git a/lzma/CPP/7zip/UI/Common/UpdateAction.cpp b/lzma/CPP/7zip/UI/Common/UpdateAction.cpp
new file mode 100644
index 0000000..ba138d2
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Common/UpdateAction.cpp
@@ -0,0 +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
+}};
+
+}
diff --git a/lzma/CPP/7zip/UI/Common/UpdateAction.h b/lzma/CPP/7zip/UI/Common/UpdateAction.h
new file mode 100644
index 0000000..6e10b7d
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Common/UpdateAction.h
@@ -0,0 +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];
+
+ const 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/lzma/CPP/7zip/UI/Common/UpdateCallback.cpp b/lzma/CPP/7zip/UI/Common/UpdateCallback.cpp
new file mode 100644
index 0000000..8aaddfa
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Common/UpdateCallback.cpp
@@ -0,0 +1,574 @@
+// UpdateCallback.cpp
+
+#include "StdAfx.h"
+
+#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 "../../../Windows/Synchronization.h"
+
+#include "../../Common/FileStreams.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;
+
+#ifdef _USE_SECURITY_CODE
+bool InitLocalPrivileges();
+#endif
+
+CArchiveUpdateCallback::CArchiveUpdateCallback():
+ Callback(0),
+ ShareForWrite(false),
+ StdInMode(false),
+ DirItems(0),
+ ArcItems(0),
+ UpdatePairs(0),
+ NewNames(0),
+ KeepOriginalItemNames(false),
+ ProcessedItemsStatuses(NULL),
+ ParentDirItem(NULL),
+ StoreNtSecurity(false),
+ StoreHardLinks(false),
+ StoreSymLinks(false),
+ _hardIndex_From((UInt32)(Int32)-1)
+{
+ #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 STATPROPSTG 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 (GetRootProps)
+ return 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() && GetRawProps)
+ return GetRawProps->GetRawProp(
+ ArcItems ? (*ArcItems)[up.ArcIndex].IndexInServer : up.ArcIndex,
+ propID, data, dataSize, propType);
+
+ {
+ const CUpdatePair2 &up = (*UpdatePairs)[index];
+ /*
+ 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 += L".." WSTRING_PATH_SEPARATOR;
+
+ for (k = i; k < partsTo.Size(); k++)
+ {
+ if (k != i)
+ s += WCHAR_PATH_SEPARATOR;
+ 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;
+ if (attr.Parse(di.ReparseData, di.ReparseData.Size()))
+ {
+ UString simpleName = attr.GetPath();
+ if (attr.IsRelative())
+ prop = simpleName;
+ else
+ {
+ const UString phyPath = DirItems->GetPhyPath(up.DirIndex);
+ FString fullPath;
+ if (NDir::MyGetFullPathName(us2fs(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 == 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.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
+}
+
+static NSynchronization::CCriticalSection CS;
+
+STDMETHODIMP CArchiveUpdateCallback::GetStream(UInt32 index, ISequentialInStream **inStream)
+{
+ COM_TRY_BEGIN
+ *inStream = NULL;
+ const CUpdatePair2 &up = (*UpdatePairs)[index];
+ if (!up.NewData)
+ return E_FAIL;
+
+ RINOK(Callback->CheckBreak());
+ RINOK(Callback->Finilize());
+
+ 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, true));
+
+ /* 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), false));
+
+ if (isDir)
+ return S_OK;
+
+ if (StdInMode)
+ {
+ CStdInFileStream *inStreamSpec = new CStdInFileStream;
+ CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec);
+ *inStream = inStreamLoc.Detach();
+ }
+ else
+ {
+ CInFileStream *inStreamSpec = new CInFileStream;
+ CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec);
+
+ inStreamSpec->SupportHardLinks = StoreHardLinks;
+
+ const UString path = DirItems->GetPhyPath(up.DirIndex);
+
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ if (DirItems->Items[up.DirIndex].AreReparseData())
+ {
+ if (!inStreamSpec->File.OpenReparse(us2fs(path)))
+ {
+ return Callback->OpenFileError(path, ::GetLastError());
+ }
+ }
+ else
+ #endif
+ if (!inStreamSpec->OpenShared(us2fs(path), ShareForWrite))
+ {
+ return Callback->OpenFileError(path, ::GetLastError());
+ }
+
+ 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)
+ {
+ NSynchronization::CCriticalSectionLock lock(CS);
+ ProcessedItemsStatuses[up.DirIndex] = 1;
+ }
+ *inStream = inStreamLoc.Detach();
+ }
+
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CArchiveUpdateCallback::SetOperationResult(Int32 operationResult)
+{
+ COM_TRY_BEGIN
+ return Callback->SetOperationResult(operationResult);
+ 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
+ FChar temp[16];
+ ConvertUInt32ToString(index + 1, temp);
+ FString res = temp;
+ while (res.Len() < 2)
+ res.InsertAtFront(FTEXT('0'));
+ FString fileName = VolName;
+ fileName += L'.';
+ 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
+}
diff --git a/lzma/CPP/7zip/UI/Common/UpdateCallback.h b/lzma/CPP/7zip/UI/Common/UpdateCallback.h
new file mode 100644
index 0000000..41544db
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Common/UpdateCallback.h
@@ -0,0 +1,122 @@
+// UpdateCallback.h
+
+#ifndef __UPDATE_CALLBACK_H
+#define __UPDATE_CALLBACK_H
+
+#include "../../../Common/MyCom.h"
+
+#include "../../IPassword.h"
+#include "../../ICoder.h"
+
+#include "../Common/UpdatePair.h"
+#include "../Common/UpdateProduce.h"
+
+#define INTERFACE_IUpdateCallbackUI(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 Finilize() x; \
+ virtual HRESULT SetNumFiles(UInt64 numFiles) x; \
+ virtual HRESULT GetStream(const wchar_t *name, bool isAnti) x; \
+ virtual HRESULT OpenFileError(const wchar_t *name, DWORD systemError) x; \
+ virtual HRESULT SetOperationResult(Int32 operationResult) x; \
+ virtual HRESULT CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password) x; \
+ virtual HRESULT CryptoGetTextPassword(BSTR *password) x; \
+ /* virtual HRESULT ShowDeleteFile(const wchar_t *name) 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 IArchiveGetRawProps,
+ public IArchiveGetRootProps,
+ public ICryptoGetTextPassword2,
+ public ICryptoGetTextPassword,
+ public ICompressProgressInfo,
+ public CMyUnknownImp
+{
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ bool _saclEnabled;
+ #endif
+ CRecordVector<CKeyKeyValPair> _map;
+
+ UInt32 _hardIndex_From;
+ UInt32 _hardIndex_To;
+
+public:
+ MY_UNKNOWN_IMP6(
+ IArchiveUpdateCallback2,
+ IArchiveGetRawProps,
+ IArchiveGetRootProps,
+ ICryptoGetTextPassword2,
+ ICryptoGetTextPassword,
+ ICompressProgressInfo)
+
+ STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
+
+ INTERFACE_IArchiveUpdateCallback2(;)
+ INTERFACE_IArchiveGetRawProps(;)
+ INTERFACE_IArchiveGetRootProps(;)
+
+ STDMETHOD(CryptoGetTextPassword2)(Int32 *passwordIsDefined, BSTR *password);
+ STDMETHOD(CryptoGetTextPassword)(BSTR *password);
+
+ CRecordVector<UInt64> VolumesSizes;
+ FString VolName;
+ FString VolExt;
+
+ IUpdateCallbackUI *Callback;
+
+ bool ShareForWrite;
+ bool StdInMode;
+
+ const CDirItems *DirItems;
+ const CDirItem *ParentDirItem;
+
+ const CObjectVector<CArcItem> *ArcItems;
+ const CRecordVector<CUpdatePair2> *UpdatePairs;
+ const UStringVector *NewNames;
+ CMyComPtr<IInArchive> Archive;
+ CMyComPtr<IArchiveGetRawProps> GetRawProps;
+ CMyComPtr<IArchiveGetRootProps> GetRootProps;
+
+ 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
diff --git a/lzma/CPP/7zip/UI/Common/UpdatePair.cpp b/lzma/CPP/7zip/UI/Common/UpdatePair.cpp
new file mode 100644
index 0000000..e9c9c51
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Common/UpdatePair.cpp
@@ -0,0 +1,233 @@
+// 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 *k_Duplicate_inArc_Message = "Duplicate filename in archive:";
+static const char *k_Duplicate_inDir_Message = "Duplicate filename on disk:";
+static const char *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;
+ m.SetFromAscii(message);
+ m += L'\n'; m += s1;
+ m += L'\n'; 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);
+ {
+ 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();
+}
diff --git a/lzma/CPP/7zip/UI/Common/UpdatePair.h b/lzma/CPP/7zip/UI/Common/UpdatePair.h
new file mode 100644
index 0000000..36da243
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Common/UpdatePair.h
@@ -0,0 +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
diff --git a/lzma/CPP/7zip/UI/Common/UpdateProduce.cpp b/lzma/CPP/7zip/UI/Common/UpdateProduce.cpp
new file mode 100644
index 0000000..6726af3
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Common/UpdateProduce.cpp
@@ -0,0 +1,73 @@
+// UpdateProduce.cpp
+
+#include "StdAfx.h"
+
+#include "UpdateProduce.h"
+
+using namespace NUpdateArchive;
+
+static const char *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[pair.State])
+ {
+ case NPairAction::kIgnore:
+ /*
+ if (pair.State != NPairState::kOnlyOnDisk)
+ IgnoreArchiveItem(m_ArchiveItems[pair.ArcIndex]);
+ // cout << "deleting";
+ */
+ if (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();
+}
diff --git a/lzma/CPP/7zip/UI/Common/UpdateProduce.h b/lzma/CPP/7zip/UI/Common/UpdateProduce.h
new file mode 100644
index 0000000..f53055e
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Common/UpdateProduce.h
@@ -0,0 +1,55 @@
+// 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(int arcIndex) = 0;
+};
+
+void UpdateProduce(
+ const CRecordVector<CUpdatePair> &updatePairs,
+ const NUpdateArchive::CActionSet &actionSet,
+ CRecordVector<CUpdatePair2> &operationChain,
+ IUpdateProduceCallback *callback);
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Common/WorkDir.cpp b/lzma/CPP/7zip/UI/Common/WorkDir.cpp
new file mode 100644
index 0000000..6ff225b
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Common/WorkDir.cpp
@@ -0,0 +1,91 @@
+// 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;
+ #ifndef 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(FCHAR_PATH_SEPARATOR) + 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;
+}
diff --git a/lzma/CPP/7zip/UI/Common/WorkDir.h b/lzma/CPP/7zip/UI/Common/WorkDir.h
new file mode 100644
index 0000000..13d4ed9
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Common/WorkDir.h
@@ -0,0 +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
diff --git a/lzma/CPP/7zip/UI/Common/ZipRegistry.h b/lzma/CPP/7zip/UI/Common/ZipRegistry.h
new file mode 100644
index 0000000..df00aac
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Common/ZipRegistry.h
@@ -0,0 +1,122 @@
+// 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 ResetForLevelChange()
+ {
+ BlockLogSize = NumThreads = Level = Dictionary = Order = UInt32(-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
+{
+ bool Cascaded;
+ bool MenuIcons;
+ UInt32 Flags;
+
+ void Save() const;
+ void Load();
+};
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Console/BenchCon.cpp b/lzma/CPP/7zip/UI/Console/BenchCon.cpp
new file mode 100644
index 0000000..16cd24c
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Console/BenchCon.cpp
@@ -0,0 +1,42 @@
+// 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()
+{
+ Print("\n");
+}
+
+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;
+ callback.NewLine();
+ return Bench(EXTERNAL_CODECS_LOC_VARS
+ &callback, NULL, props, numIterations, true);
+}
diff --git a/lzma/CPP/7zip/UI/Console/BenchCon.h b/lzma/CPP/7zip/UI/Console/BenchCon.h
new file mode 100644
index 0000000..ef235ee
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Console/BenchCon.h
@@ -0,0 +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
diff --git a/lzma/CPP/7zip/UI/Console/Console.mak b/lzma/CPP/7zip/UI/Console/Console.mak
new file mode 100644
index 0000000..b0f8301
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Console/Console.mak
@@ -0,0 +1,35 @@
+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 \
+
diff --git a/lzma/CPP/7zip/UI/Console/ConsoleClose.cpp b/lzma/CPP/7zip/UI/Console/ConsoleClose.cpp
new file mode 100644
index 0000000..9fbad17
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Console/ConsoleClose.cpp
@@ -0,0 +1,73 @@
+// ConsoleClose.cpp
+
+#include "StdAfx.h"
+
+#include "ConsoleClose.h"
+
+static int g_BreakCounter = 0;
+static const int kBreakAbortThreshold = 2;
+
+namespace NConsoleClose {
+
+#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
+
+bool TestBreakSignal()
+{
+ #ifdef UNDER_CE
+ return false;
+ #else
+ /*
+ if (g_BreakCounter > 0)
+ return true;
+ */
+ return (g_BreakCounter > 0);
+ #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))
+ throw "SetConsoleCtrlHandler fails";
+ #endif
+}
+
+}
diff --git a/lzma/CPP/7zip/UI/Console/ConsoleClose.h b/lzma/CPP/7zip/UI/Console/ConsoleClose.h
new file mode 100644
index 0000000..7101018
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Console/ConsoleClose.h
@@ -0,0 +1,24 @@
+// ConsoleCloseUtils.h
+
+#ifndef __CONSOLECLOSEUTILS_H
+#define __CONSOLECLOSEUTILS_H
+
+namespace NConsoleClose {
+
+bool TestBreakSignal();
+
+class CCtrlHandlerSetter
+{
+public:
+ CCtrlHandlerSetter();
+ virtual ~CCtrlHandlerSetter();
+};
+
+class CCtrlBreakException
+{};
+
+void CheckCtrlBreak();
+
+}
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp b/lzma/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp
new file mode 100644
index 0000000..0c6f806
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp
@@ -0,0 +1,383 @@
+// ExtractCallbackConsole.cpp
+
+#include "StdAfx.h"
+
+// #undef sprintf
+
+#include "ConsoleClose.h"
+#include "ExtractCallbackConsole.h"
+#include "UserInputUtils.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"
+
+#include "../../Common/FilePathAutoRename.h"
+
+#include "../Common/ExtractingFilePath.h"
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NDir;
+
+static const char *kTestString = "Testing ";
+static const char *kExtractString = "Extracting ";
+static const char *kSkipString = "Skipping ";
+
+// static const char *kCantAutoRename = "can not create file with auto name\n";
+// static const char *kCantRenameFile = "can not rename existing file\n";
+// static const char *kCantDeleteOutputFile = "can not delete output file ";
+static const char *kError = "ERROR: ";
+static const char *kMemoryExceptionMessage = "Can't allocate required memory!";
+
+static const char *kProcessing = "Processing archive: ";
+static const char *kEverythingIsOk = "Everything is Ok";
+static const char *kNoFiles = "No files to process";
+
+static const char *kUnsupportedMethod = "Unsupported Method";
+static const char *kCrcFailed = "CRC Failed";
+static const char *kCrcFailedEncrypted = "CRC Failed in encrypted file. Wrong password?";
+static const char *kDataError = "Data Error";
+static const char *kDataErrorEncrypted = "Data Error in encrypted file. Wrong password?";
+static const char *kUnavailableData = "Unavailable data";
+static const char *kUnexpectedEnd = "Unexpected end of data";
+static const char *kDataAfterEnd = "There are some data after the end of the payload data";
+static const char *kIsNotArc = "Is not archive";
+static const char *kHeadersError = "Headers Error";
+
+static const char *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)
+{
+ if (NConsoleClose::TestBreakSignal())
+ return E_ABORT;
+ return S_OK;
+}
+
+STDMETHODIMP CExtractCallbackConsole::SetCompleted(const UInt64 *)
+{
+ if (NConsoleClose::TestBreakSignal())
+ return E_ABORT;
+ return S_OK;
+}
+
+STDMETHODIMP CExtractCallbackConsole::AskOverwrite(
+ const wchar_t *existName, const FILETIME *, const UInt64 *,
+ const wchar_t *newName, const FILETIME *, const UInt64 *,
+ Int32 *answer)
+{
+ (*OutStream) << "file " << existName << endl <<
+ "already exists. Overwrite with" << endl <<
+ newName;
+
+ NUserAnswerMode::EEnum overwriteAnswer = ScanUserYesNoAllQuit(OutStream);
+
+ 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;
+ default: return E_FAIL;
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CExtractCallbackConsole::PrepareOperation(const wchar_t *name, bool /* isFolder */, Int32 askExtractMode, const UInt64 *position)
+{
+ 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;
+ default: s = ""; // return E_FAIL;
+ };
+ (*OutStream) << s << name;
+ if (position != 0)
+ (*OutStream) << " <" << *position << ">";
+ return S_OK;
+}
+
+STDMETHODIMP CExtractCallbackConsole::MessageError(const wchar_t *message)
+{
+ (*OutStream) << message << endl;
+ NumFileErrorsInCurrent++;
+ NumFileErrors++;
+ return S_OK;
+}
+
+STDMETHODIMP CExtractCallbackConsole::SetOperationResult(Int32 operationResult, bool encrypted)
+{
+ switch (operationResult)
+ {
+ case NArchive::NExtract::NOperationResult::kOK:
+ break;
+ default:
+ {
+ NumFileErrorsInCurrent++;
+ NumFileErrors++;
+ (*OutStream) << " : ";
+ const char *s = NULL;
+ switch (operationResult)
+ {
+ 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;
+ }
+ if (s)
+ (*OutStream) << "Error : " << s;
+ else
+ {
+ char temp[16];
+ ConvertUInt32ToString(operationResult, temp);
+ (*OutStream) << "Error #" << temp;
+ }
+ }
+ }
+ (*OutStream) << endl;
+ return S_OK;
+}
+
+#ifndef _NO_CRYPTO
+
+HRESULT CExtractCallbackConsole::SetPassword(const UString &password)
+{
+ PasswordIsDefined = true;
+ Password = password;
+ return S_OK;
+}
+
+STDMETHODIMP CExtractCallbackConsole::CryptoGetTextPassword(BSTR *password)
+{
+ if (!PasswordIsDefined)
+ {
+ Password = GetPassword(OutStream);
+ PasswordIsDefined = true;
+ }
+ return StringToBstr(Password, password);
+}
+
+#endif
+
+HRESULT CExtractCallbackConsole::BeforeOpen(const wchar_t *name)
+{
+ NumTryArcs++;
+ ThereIsErrorInCurrent = false;
+ ThereIsWarningInCurrent = false;
+ NumFileErrorsInCurrent = 0;
+ (*OutStream) << endl << kProcessing << name << endl;
+ return S_OK;
+}
+
+HRESULT CExtractCallbackConsole::OpenResult(const wchar_t * /* name */, HRESULT result, bool encrypted)
+{
+ (*OutStream) << endl;
+ if (result != S_OK)
+ {
+ (*OutStream) << "Error: ";
+ if (result == S_FALSE)
+ {
+ (*OutStream) << (encrypted ?
+ "Can not open encrypted archive. Wrong password?" :
+ "Can not open file as archive");
+ }
+ else
+ {
+ if (result == E_OUTOFMEMORY)
+ (*OutStream) << "Can't allocate required memory";
+ else
+ (*OutStream) << NError::MyFormatMessage(result);
+ }
+ (*OutStream) << endl;
+ NumCantOpenArcs++;
+ ThereIsErrorInCurrent = true;
+ }
+ return S_OK;
+}
+
+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 += '\n';
+ s += m;
+ errorFlags &= ~f;
+ }
+ if (errorFlags != 0)
+ {
+ char sz[16];
+ sz[0] = '0';
+ sz[1] = 'x';
+ ConvertUInt32ToHex(errorFlags, sz + 2);
+ if (!s.IsEmpty())
+ s += '\n';
+ s += sz;
+ }
+ return s;
+}
+
+
+HRESULT CExtractCallbackConsole::SetError(int level, const wchar_t *name,
+ UInt32 errorFlags, const wchar_t *errors,
+ UInt32 warningFlags, const wchar_t *warnings)
+{
+ if (level != 0)
+ {
+ (*OutStream) << name << endl;
+ }
+
+ if (errorFlags != 0)
+ {
+ (*OutStream) << "Errors: ";
+ (*OutStream) << endl;
+ (*OutStream) << GetOpenArcErrorMessage(errorFlags);
+ (*OutStream) << endl;
+ NumOpenArcErrors++;
+ ThereIsErrorInCurrent = true;
+ }
+
+ if (errors && wcslen(errors) != 0)
+ {
+ (*OutStream) << "Errors: ";
+ (*OutStream) << endl;
+ (*OutStream) << errors;
+ (*OutStream) << endl;
+ NumOpenArcErrors++;
+ ThereIsErrorInCurrent = true;
+ }
+
+ if (warningFlags != 0)
+ {
+ (*OutStream) << "Warnings: ";
+ (*OutStream) << endl;
+ (*OutStream) << GetOpenArcErrorMessage(warningFlags);
+ (*OutStream) << endl;
+ NumOpenArcWarnings++;
+ ThereIsWarningInCurrent = true;
+ }
+
+ if (warnings && wcslen(warnings) != 0)
+ {
+ (*OutStream) << "Warnings: ";
+ (*OutStream) << endl;
+ (*OutStream) << warnings;
+ (*OutStream) << endl;
+ NumOpenArcWarnings++;
+ ThereIsWarningInCurrent = true;
+ }
+
+ (*OutStream) << endl;
+ return S_OK;
+}
+
+HRESULT CExtractCallbackConsole::ThereAreNoFiles()
+{
+ (*OutStream) << endl << kNoFiles << endl;
+ return S_OK;
+}
+
+HRESULT CExtractCallbackConsole::ExtractResult(HRESULT result)
+{
+ if (result == S_OK)
+ {
+ (*OutStream) << endl;
+
+ if (NumFileErrorsInCurrent == 0 && !ThereIsErrorInCurrent)
+ {
+ if (ThereIsWarningInCurrent)
+ NumArcsWithWarnings++;
+ else
+ NumOkArcs++;
+ (*OutStream) << kEverythingIsOk << endl;
+ }
+ else
+ {
+ NumArcsWithError++;
+ if (NumFileErrorsInCurrent != 0)
+ (*OutStream) << "Sub items Errors: " << NumFileErrorsInCurrent << endl;
+ }
+ return S_OK;
+ }
+
+ NumArcsWithError++;
+ if (result == E_ABORT || result == ERROR_DISK_FULL)
+ return result;
+ (*OutStream) << endl << kError;
+ if (result == E_OUTOFMEMORY)
+ (*OutStream) << kMemoryExceptionMessage;
+ else
+ (*OutStream) << NError::MyFormatMessage(result);
+ (*OutStream) << endl;
+ return S_OK;
+}
+
+HRESULT CExtractCallbackConsole::OpenTypeWarning(const wchar_t *name, const wchar_t *okType, const wchar_t *errorType)
+{
+ UString s = L"Warning:\n";
+ if (wcscmp(okType, errorType) == 0)
+ {
+ s += L"The archive is open with offset";
+ }
+ else
+ {
+ s += name;
+ s += L"\nCan not open the file as [";
+ s += errorType;
+ s += L"] archive\n";
+ s += L"The file is open as [";
+ s += okType;
+ s += L"] archive";
+ }
+ (*OutStream) << s << endl << endl;
+ ThereIsWarningInCurrent = true;
+ return S_OK;
+}
diff --git a/lzma/CPP/7zip/UI/Console/ExtractCallbackConsole.h b/lzma/CPP/7zip/UI/Console/ExtractCallbackConsole.h
new file mode 100644
index 0000000..cefa2c2
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Console/ExtractCallbackConsole.h
@@ -0,0 +1,99 @@
+// ExtractCallbackConsole.h
+
+#ifndef __EXTRACTCALLBACKCONSOLE_H
+#define __EXTRACTCALLBACKCONSOLE_H
+
+#include "../../../Common/MyString.h"
+#include "../../../Common/StdOutStream.h"
+
+#include "../../Common/FileStreams.h"
+
+#include "../../IPassword.h"
+
+#include "../../Archive/IArchive.h"
+
+#include "../Common/ArchiveExtractCallback.h"
+
+class CExtractCallbackConsole:
+ public IExtractCallbackUI,
+ #ifndef _NO_CRYPTO
+ public ICryptoGetTextPassword,
+ #endif
+ public CMyUnknownImp
+{
+public:
+ MY_QUERYINTERFACE_BEGIN2(IFolderArchiveExtractCallback)
+ #ifndef _NO_CRYPTO
+ MY_QUERYINTERFACE_ENTRY(ICryptoGetTextPassword)
+ #endif
+ MY_QUERYINTERFACE_END
+ MY_ADDREF_RELEASE
+
+ STDMETHOD(SetTotal)(UInt64 total);
+ STDMETHOD(SetCompleted)(const UInt64 *completeValue);
+
+ // IFolderArchiveExtractCallback
+ STDMETHOD(AskOverwrite)(
+ const wchar_t *existName, const FILETIME *existTime, const UInt64 *existSize,
+ const wchar_t *newName, const FILETIME *newTime, const UInt64 *newSize,
+ Int32 *answer);
+ STDMETHOD (PrepareOperation)(const wchar_t *name, bool isFolder, Int32 askExtractMode, const UInt64 *position);
+
+ STDMETHOD(MessageError)(const wchar_t *message);
+ STDMETHOD(SetOperationResult)(Int32 operationResult, bool encrypted);
+
+ HRESULT BeforeOpen(const wchar_t *name);
+ HRESULT OpenResult(const wchar_t *name, HRESULT result, bool encrypted);
+ HRESULT SetError(int level, const wchar_t *name,
+ UInt32 errorFlags, const wchar_t *errors,
+ UInt32 warningFlags, const wchar_t *warnings);
+
+ HRESULT ThereAreNoFiles();
+ HRESULT ExtractResult(HRESULT result);
+ HRESULT OpenTypeWarning(const wchar_t *name, const wchar_t *okType, const wchar_t *errorType);
+
+
+ #ifndef _NO_CRYPTO
+ HRESULT SetPassword(const UString &password);
+ STDMETHOD(CryptoGetTextPassword)(BSTR *password);
+
+ bool PasswordIsDefined;
+ UString Password;
+
+ #endif
+
+ UInt64 NumTryArcs;
+ bool ThereIsErrorInCurrent;
+ bool ThereIsWarningInCurrent;
+
+ UInt64 NumCantOpenArcs;
+ UInt64 NumOkArcs;
+ UInt64 NumArcsWithError;
+ UInt64 NumArcsWithWarnings;
+
+ UInt64 NumProblemArcsLevs;
+ UInt64 NumOpenArcErrors;
+ UInt64 NumOpenArcWarnings;
+
+ UInt64 NumFileErrors;
+ UInt64 NumFileErrorsInCurrent;
+
+ CStdOutStream *OutStream;
+
+ void Init()
+ {
+ NumTryArcs = 0;
+ NumOkArcs = 0;
+ NumCantOpenArcs = 0;
+ NumArcsWithError = 0;
+ NumArcsWithWarnings = 0;
+
+ NumOpenArcErrors = 0;
+ NumOpenArcWarnings = 0;
+ NumFileErrors = 0;
+ NumFileErrorsInCurrent = 0;
+ }
+
+};
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Console/HashCon.cpp b/lzma/CPP/7zip/UI/Console/HashCon.cpp
new file mode 100644
index 0000000..a9e62c2
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Console/HashCon.cpp
@@ -0,0 +1,274 @@
+// HashCon.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/IntToString.h"
+#include "../../../Common/StringConvert.h"
+
+#include "../../../Windows/ErrorMsg.h"
+
+#include "ConsoleClose.h"
+#include "HashCon.h"
+
+static const wchar_t *kEmptyFileAlias = L"[Content]";
+
+static const char *kScanningMessage = "Scanning";
+
+HRESULT CHashCallbackConsole::CheckBreak()
+{
+ return NConsoleClose::TestBreakSignal() ? E_ABORT : S_OK;
+}
+
+HRESULT CHashCallbackConsole::StartScanning()
+{
+ (*OutStream) << kScanningMessage;
+ return CheckBreak();
+}
+
+HRESULT CHashCallbackConsole::ScanProgress(UInt64 /* numFolders */, UInt64 /* numFiles */, UInt64 /* totalSize */, const wchar_t * /* path */, bool /* isDir */)
+{
+ return CheckBreak();
+}
+
+HRESULT CHashCallbackConsole::CanNotFindError(const wchar_t *name, DWORD systemError)
+{
+ return CanNotFindError_Base(name, systemError);
+}
+
+HRESULT CHashCallbackConsole::FinishScanning()
+{
+ (*OutStream) << endl << endl;
+ return CheckBreak();
+}
+
+HRESULT CHashCallbackConsole::SetNumFiles(UInt64 /* numFiles */)
+{
+ return CheckBreak();
+}
+
+HRESULT CHashCallbackConsole::SetTotal(UInt64 size)
+{
+ if (EnablePercents)
+ m_PercentPrinter.SetTotal(size);
+ return CheckBreak();
+}
+
+HRESULT CHashCallbackConsole::SetCompleted(const UInt64 *completeValue)
+{
+ if (completeValue && EnablePercents)
+ {
+ m_PercentPrinter.SetRatio(*completeValue);
+ m_PercentPrinter.PrintRatio();
+ }
+ return CheckBreak();
+}
+
+static void AddMinuses(AString &s, unsigned num)
+{
+ for (unsigned i = 0; i < num; i++)
+ s += '-';
+}
+
+static void SetSpaces(char *s, int num)
+{
+ for (int i = 0; i < num; i++)
+ s[i] = ' ';
+}
+
+static void SetSpacesAndNul(char *s, int num)
+{
+ SetSpaces(s, num);
+ s[num] = 0;
+}
+
+static void AddSpaces(UString &s, int num)
+{
+ for (int i = 0; i < num; i++)
+ s += ' ';
+}
+
+static const int kSizeField_Len = 13;
+static const int kNameField_Len = 12;
+
+static unsigned GetColumnWidth(unsigned digestSize)
+{
+ unsigned width = digestSize * 2;
+ const unsigned kMinColumnWidth = 8;
+ return width < kMinColumnWidth ? kMinColumnWidth: width;
+}
+
+void CHashCallbackConsole::PrintSeparatorLine(const CObjectVector<CHasherState> &hashers)
+{
+ AString s;
+ for (unsigned i = 0; i < hashers.Size(); i++)
+ {
+ const CHasherState &h = hashers[i];
+ AddMinuses(s, GetColumnWidth(h.DigestSize));
+ s += ' ';
+ }
+ AddMinuses(s, kSizeField_Len);
+ s += " ";
+ AddMinuses(s, kNameField_Len);
+ m_PercentPrinter.PrintString(s);
+ m_PercentPrinter.PrintNewLine();
+}
+
+HRESULT CHashCallbackConsole::BeforeFirstFile(const CHashBundle &hb)
+{
+ UString s;
+ FOR_VECTOR (i, hb.Hashers)
+ {
+ const CHasherState &h = hb.Hashers[i];
+ s += h.Name;
+ AddSpaces(s, (int)GetColumnWidth(h.DigestSize) - h.Name.Len() + 1);
+ }
+ UString s2 = L"Size";
+ AddSpaces(s, kSizeField_Len - s2.Len());
+ s += s2;
+ s += L" ";
+ s += L"Name";
+ m_PercentPrinter.PrintString(s);
+ m_PercentPrinter.PrintNewLine();
+ PrintSeparatorLine(hb.Hashers);
+ return CheckBreak();
+}
+
+HRESULT CHashCallbackConsole::OpenFileError(const wchar_t *name, DWORD systemError)
+{
+ FailedCodes.Add(systemError);
+ FailedFiles.Add(name);
+ // if (systemError == ERROR_SHARING_VIOLATION)
+ {
+ m_PercentPrinter.PrintString(name);
+ m_PercentPrinter.PrintString(": WARNING: ");
+ m_PercentPrinter.PrintString(NWindows::NError::MyFormatMessage(systemError));
+ return S_FALSE;
+ }
+ // return systemError;
+}
+
+HRESULT CHashCallbackConsole::GetStream(const wchar_t *name, bool /* isFolder */)
+{
+ m_FileName = name;
+ return CheckBreak();
+}
+
+void CHashCallbackConsole::PrintResultLine(UInt64 fileSize,
+ const CObjectVector<CHasherState> &hashers, unsigned digestIndex, bool showHash)
+{
+ 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) + 1);
+ m_PercentPrinter.PrintString(s);
+ }
+ char s[64];
+ s[0] = 0;
+ char *p = s;
+ if (showHash && fileSize != 0)
+ {
+ p = s + 32;
+ ConvertUInt64ToString(fileSize, p);
+ int numSpaces = kSizeField_Len - (int)strlen(p);
+ if (numSpaces > 0)
+ {
+ p -= numSpaces;
+ SetSpaces(p, numSpaces);
+ }
+ }
+ else
+ SetSpacesAndNul(s, kSizeField_Len - (int)strlen(s));
+ unsigned len = (unsigned)strlen(p);
+ p[len] = ' ';
+ p[len + 1] = ' ';
+ p[len + 2] = 0;
+ m_PercentPrinter.PrintString(p);
+}
+
+HRESULT CHashCallbackConsole::SetOperationResult(UInt64 fileSize, const CHashBundle &hb, bool showHash)
+{
+ PrintResultLine(fileSize, hb.Hashers, k_HashCalc_Index_Current, showHash);
+ if (m_FileName.IsEmpty())
+ m_PercentPrinter.PrintString(kEmptyFileAlias);
+ else
+ m_PercentPrinter.PrintString(m_FileName);
+ m_PercentPrinter.PrintNewLine();
+ return S_OK;
+}
+
+static const char *k_DigestTitles[] =
+{
+ " :"
+ , " for data: "
+ , " for data and names: "
+ , " for streams and names: "
+};
+
+static void PrintSum(CStdOutStream &p, const CHasherState &h, unsigned digestIndex)
+{
+ char s[k_HashCalc_DigestSize_Max * 2 + 64];
+ UString name = h.Name;
+ AddSpaces(name, 6 - (int)name.Len());
+ p << name;
+ p << k_DigestTitles[digestIndex];
+ s[0] = 0;
+ AddHashHexToString(s, h.Digests[digestIndex], h.DigestSize);
+ p << s;
+ p << "\n";
+}
+
+
+void PrintHashStat(CStdOutStream &p, const CHashBundle &hb)
+{
+ FOR_VECTOR (i, hb.Hashers)
+ {
+ const CHasherState &h = hb.Hashers[i];
+ p << "\n";
+ PrintSum(p, h, k_HashCalc_Index_DataSum);
+ if (hb.NumFiles != 1 || hb.NumDirs != 0)
+ PrintSum(p, h, k_HashCalc_Index_NamesSum);
+ if (hb.NumAltStreams != 0)
+ PrintSum(p, h, k_HashCalc_Index_StreamsSum);
+ }
+}
+
+void CHashCallbackConsole::PrintProperty(const char *name, UInt64 value)
+{
+ char s[32];
+ s[0] = ':';
+ s[1] = ' ';
+ ConvertUInt64ToString(value, s + 2);
+ m_PercentPrinter.PrintString(name);
+ m_PercentPrinter.PrintString(s);
+ m_PercentPrinter.PrintNewLine();
+}
+
+HRESULT CHashCallbackConsole::AfterLastFile(const CHashBundle &hb)
+{
+ PrintSeparatorLine(hb.Hashers);
+
+ PrintResultLine(hb.FilesSize, hb.Hashers, k_HashCalc_Index_DataSum, true);
+ m_PercentPrinter.PrintNewLine();
+ m_PercentPrinter.PrintNewLine();
+
+ 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("AltStreams", hb.NumAltStreams);
+ PrintProperty("AltStreams size", hb.AltStreamsSize);
+ }
+ PrintHashStat(*m_PercentPrinter.OutStream, hb);
+ m_PercentPrinter.PrintNewLine();
+ return S_OK;
+}
diff --git a/lzma/CPP/7zip/UI/Console/HashCon.h b/lzma/CPP/7zip/UI/Console/HashCon.h
new file mode 100644
index 0000000..0e7469d
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Console/HashCon.h
@@ -0,0 +1,26 @@
+// HashCon.h
+
+#ifndef __HASH_CON_H
+#define __HASH_CON_H
+
+#include "../Common/HashCalc.h"
+
+#include "UpdateCallbackConsole.h"
+
+class CHashCallbackConsole: public IHashCallbackUI, public CCallbackConsoleBase
+{
+ UString m_FileName;
+
+ 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:
+ ~CHashCallbackConsole() { }
+
+ INTERFACE_IHashCallbackUI(;)
+};
+
+void PrintHashStat(CStdOutStream &stdStream, const CHashBundle &hb);
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Console/List.cpp b/lzma/CPP/7zip/UI/Console/List.cpp
new file mode 100644
index 0000000..dbbdeae
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Console/List.cpp
@@ -0,0 +1,1192 @@
+// 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;
+
+
+
+static const char *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"
+};
+
+static const char kEmptyAttribChar = '.';
+
+static const char *kListing = "Listing archive: ";
+
+static const char *kString_Files = "files";
+static const char *kString_Dirs = "folders";
+static const char *kString_AltStreams = "alternate streams";
+static const char *kString_Streams = "streams";
+
+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;
+ int PrefixSpacesWidth;
+ int Width;
+};
+
+struct CFieldInfoInit
+{
+ PROPID PropID;
+ const char *Name;
+ EAdjustment TitleAdjustment;
+ EAdjustment TextAdjustment;
+ int PrefixSpacesWidth;
+ int 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 int kNumSpacesMax = 32; // it must be larger than max CFieldInfoInit.Width
+static const char *g_Spaces =
+" " ;
+
+static void PrintSpaces(int numSpaces)
+{
+ if (numSpaces > 0 && numSpaces <= kNumSpacesMax)
+ g_StdOut << g_Spaces + (kNumSpacesMax - numSpaces);
+}
+
+static void PrintSpacesToString(char *dest, int numSpaces)
+{
+ int i;
+ for (i = 0; i < numSpaces; i++)
+ dest[i] = ' ';
+ dest[i] = 0;
+}
+
+static void PrintString(EAdjustment adj, int width, const UString &textString)
+{
+ const int numSpaces = width - textString.Len();
+ int numLeftSpaces = 0;
+ switch (adj)
+ {
+ case kLeft: numLeftSpaces = 0; break;
+ case kCenter: numLeftSpaces = numSpaces / 2; break;
+ case kRight: numLeftSpaces = numSpaces; break;
+ }
+ PrintSpaces(numLeftSpaces);
+ g_StdOut << textString;
+ PrintSpaces(numSpaces - numLeftSpaces);
+}
+
+static void PrintString(EAdjustment adj, int width, const char *textString)
+{
+ const int numSpaces = width - (int)strlen(textString);
+ int numLeftSpaces = 0;
+ switch (adj)
+ {
+ case kLeft: numLeftSpaces = 0; break;
+ case kCenter: numLeftSpaces = numSpaces / 2; break;
+ case kRight: numLeftSpaces = numSpaces; break;
+ }
+ PrintSpaces(numLeftSpaces);
+ g_StdOut << textString;
+ PrintSpaces(numSpaces - numLeftSpaces);
+}
+
+static void PrintStringToString(char *dest, EAdjustment adj, int width, const char *textString)
+{
+ int len = (int)strlen(textString);
+ const int numSpaces = width - len;
+ int numLeftSpaces = 0;
+ switch (adj)
+ {
+ case kLeft: numLeftSpaces = 0; break;
+ case kCenter: numLeftSpaces = numSpaces / 2; break;
+ case kRight: numLeftSpaces = numSpaces; break;
+ }
+ PrintSpacesToString(dest, numLeftSpaces);
+ if (numLeftSpaces > 0)
+ dest += numLeftSpaces;
+ memcpy(dest, textString, len);
+ dest += len;
+ PrintSpacesToString(dest, numSpaces - numLeftSpaces);
+}
+
+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 &stat)
+ {
+ Size.Add(stat.Size);
+ PackSize.Add(stat.PackSize);
+ MTime.Update(stat.MTime);
+ NumFiles += stat.NumFiles;
+ }
+ void SetSizeDefIfNoFiles() { if (NumFiles == 0) Size.Def = true; }
+};
+
+struct CListStat2
+{
+ CListStat MainFiles;
+ CListStat AltStreams;
+ UInt64 NumDirs;
+
+ CListStat2(): NumDirs(0) {}
+
+ void Update(const CListStat2 &stat)
+ {
+ MainFiles.Update(stat.MainFiles);
+ AltStreams.Update(stat.AltStreams);
+ NumDirs += stat.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(BSTR name, PROPID propID, bool isRawProp);
+public:
+ const CArc *Arc;
+ bool TechMode;
+ UString FilePath;
+ AString TempAString;
+ UString TempWString;
+ bool IsFolder;
+
+ AString LinesString;
+
+ void Clear() { _fields.Clear(); LinesString.Empty(); }
+ void Init(const CFieldInfoInit *standardFieldTable, int numItems);
+
+ HRESULT AddMainProps(IInArchive *archive);
+ HRESULT AddRawProps(IArchiveGetRawProps *getRawProps);
+
+ void PrintTitle();
+ void PrintTitleLines();
+ HRESULT PrintItemInfo(UInt32 index, const CListStat &stat);
+ void PrintSum(const CListStat &stat, UInt64 numDirs, const char *str);
+ void PrintSum(const CListStat2 &stat);
+};
+
+void CFieldPrinter::Init(const CFieldInfoInit *standardFieldTable, int numItems)
+{
+ Clear();
+ for (int 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;
+
+ int k;
+ for (k = 0; k < fii.PrefixSpacesWidth; k++)
+ LinesString += ' ';
+ 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
+ {
+ char s[16];
+ ConvertUInt32ToString(propID, s);
+ nameA = s;
+ }
+}
+
+void CFieldPrinter::AddProp(BSTR name, PROPID propID, bool isRawProp)
+{
+ CFieldInfo f;
+ f.PropID = propID;
+ f.IsRawProp = isRawProp;
+ GetPropName(propID, name, f.NameA, f.NameU);
+ f.NameU += L" = ";
+ 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;
+ FILETIME locTime;
+ if (!FileTimeToLocalFileTime(ft, &locTime))
+ throw 20121211;
+ ConvertFileTimeToString(locTime, dest, true, true);
+}
+
+#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 '\n'
+
+HRESULT CFieldPrinter::PrintItemInfo(UInt32 index, const CListStat &stat)
+{
+ 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.PrintUString(FilePath, TempAString);
+ if (techMode)
+ g_StdOut << MY_ENDL;
+ continue;
+ }
+
+ int 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 << s;
+ }
+ }
+
+ 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 (stat.Size.Def) prop = stat.Size.Val; break;
+ case kpidPackSize: if (stat.PackSize.Def) prop = stat.PackSize.Val; break;
+ case kpidMTime: if (stat.MTime.Def) prop = stat.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, IsFolder, 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 = (size_t)f.Width - len;
+ PrintSpacesToString(temp + tempPos, (int)len);
+ tempPos += len;
+ }
+ }
+ }
+ else if (prop.vt == VT_BSTR)
+ {
+ if (techMode)
+ {
+ int len = (int)wcslen(prop.bstrVal);
+ MyStringCopy(TempWString.GetBuffer(len), prop.bstrVal);
+ // replace CR/LF here.
+ TempWString.ReleaseBuffer(len);
+ g_StdOut.PrintUString(TempWString, TempAString);
+ }
+ else
+ PrintString(f.TextAdjustment, width, prop.bstrVal);
+ }
+ else
+ {
+ char s[64];
+ ConvertPropertyToShortString(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, int width, const CListUInt64Def &value)
+{
+ wchar_t s[32];
+ s[0] = 0;
+ if (value.Def)
+ ConvertUInt64ToString(value.Val, s);
+ PrintString(adj, width, s);
+}
+
+static void PrintNumberAndString(AString &s, UInt64 value, const char *text)
+{
+ char t[32];
+ ConvertUInt64ToString(value, t);
+ s += t;
+ s += ' ';
+ s += text;
+}
+
+void CFieldPrinter::PrintSum(const CListStat &stat, 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, stat.Size);
+ else if (f.PropID == kpidPackSize)
+ PrintNumber(f.TextAdjustment, f.Width, stat.PackSize);
+ else if (f.PropID == kpidMTime)
+ {
+ char s[64];
+ s[0] = 0;
+ if (stat.MTime.Def)
+ PrintTime(s, &stat.MTime.Val);
+ PrintString(f.TextAdjustment, f.Width, s);
+ }
+ else if (f.PropID == kpidPath)
+ {
+ AString s;
+ PrintNumberAndString(s, stat.NumFiles, str);
+ if (numDirs != 0)
+ {
+ s += ", ";
+ PrintNumberAndString(s, numDirs, kString_Dirs);
+ }
+ PrintString(f.TextAdjustment, 0, s);
+ }
+ else
+ PrintString(f.TextAdjustment, f.Width, L"");
+ }
+ 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 stat = stat2.MainFiles;
+ stat.Update(stat2.AltStreams);
+ PrintSum(stat, 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(const char *name, UInt64 val)
+{
+ g_StdOut << name << ": " << val << endl;
+}
+
+static void PrintPropName_and_Eq(PROPID propID)
+{
+ const char *s;
+ char temp[16];
+ if (propID < ARRAY_SIZE(kPropIdToName))
+ s = kPropIdToName[propID];
+ else
+ {
+ ConvertUInt32ToString(propID, temp);
+ s = temp;
+ }
+ g_StdOut << s << " = ";
+}
+
+static void PrintPropNameAndNumber(PROPID propID, UInt64 val)
+{
+ PrintPropName_and_Eq(propID);
+ g_StdOut << val << endl;
+}
+
+static void PrintPropNameAndNumber_Signed(PROPID propID, Int64 val)
+{
+ PrintPropName_and_Eq(propID);
+ g_StdOut << val << endl;
+}
+
+static void PrintPropPair(const char *name, const wchar_t *val)
+{
+ g_StdOut << name << " = " << val << endl;
+}
+
+
+static void PrintPropertyPair2(PROPID propID, const wchar_t *name, const CPropVariant &prop)
+{
+ UString s;
+ ConvertPropertyToString(s, prop, propID);
+ if (!s.IsEmpty())
+ {
+ AString nameA;
+ UString nameU;
+ GetPropName(propID, name, nameA, nameU);
+ if (!nameA.IsEmpty())
+ PrintPropPair(nameA, s);
+ else
+ g_StdOut << nameU << " = " << s << endl;
+ }
+}
+
+static HRESULT PrintArcProp(IInArchive *archive, PROPID propID, const wchar_t *name)
+{
+ CPropVariant prop;
+ RINOK(archive->GetArchiveProperty(propID, &prop));
+ PrintPropertyPair2(propID, name, prop);
+ return S_OK;
+}
+
+static void PrintArcTypeError(const UString &type, bool isWarning)
+{
+ g_StdOut << "Open " << (isWarning ? "Warning" : "Error")
+ << ": Can not open the file as ["
+ << type
+ << "] archive"
+ << endl;
+}
+
+int Find_FileName_InSortedVector(const UStringVector &fileName, const UString& name);
+
+AString GetOpenArcErrorMessage(UInt32 errorFlags);
+
+static void PrintErrorFlags(const char *s, UInt32 errorFlags)
+{
+ g_StdOut << s << endl << GetOpenArcErrorMessage(errorFlags) << endl;
+}
+
+static void ErrorInfo_Print(const CArcErrorInfo &er)
+{
+ if (er.AreThereErrors())
+ PrintErrorFlags("Errors:", er.GetErrorFlags());
+ if (!er.ErrorMessage.IsEmpty())
+ PrintPropPair("Error", er.ErrorMessage);
+ if (er.AreThereWarnings())
+ PrintErrorFlags("Warnings:", er.GetWarningFlags());
+ if (!er.WarningMessage.IsEmpty())
+ PrintPropPair("Warning", er.WarningMessage);
+}
+
+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 stat2;
+
+ 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;
+
+ for (arcIndex = 0; arcIndex < arcPaths.Size(); arcIndex++)
+ {
+ if (skipArcs[arcIndex])
+ continue;
+ const UString &archiveName = arcPaths[arcIndex];
+ UInt64 arcPackSize = 0;
+ if (!stdInMode)
+ {
+ NFile::NFind::CFileInfo fi;
+ if (!fi.Find(us2fs(archiveName)) || fi.IsDir())
+ {
+ g_StdOut << endl << "Error: " << archiveName << " is not file" << endl;
+ numErrors++;
+ continue;
+ }
+ arcPackSize = fi.Size;
+ totalArcSizes += arcPackSize;
+ }
+
+ CArchiveLink arcLink;
+
+ COpenCallbackConsole openCallback;
+ openCallback.OutStream = &g_StdOut;
+
+ #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 = archiveName;
+ HRESULT result = arcLink.Open2(options, &openCallback);
+
+ if (result != S_OK)
+ {
+ if (result == E_ABORT)
+ return result;
+ g_StdOut << endl << "Error: " << archiveName << ": ";
+ if (result == S_FALSE)
+ {
+ #ifndef _NO_CRYPTO
+ if (openCallback.Open_WasPasswordAsked())
+ g_StdOut << "Can not open encrypted archive. Wrong password?";
+ else
+ #endif
+ {
+ if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0)
+ {
+ PrintArcTypeError(codecs->Formats[arcLink.NonOpen_ErrorInfo.ErrorFormatIndex].Name, false);
+ }
+ else
+ g_StdOut << "Can not open the file as archive";
+ }
+ g_StdOut << endl;
+ ErrorInfo_Print(arcLink.NonOpen_ErrorInfo);
+ }
+ else if (result == E_OUTOFMEMORY)
+ g_StdOut << "Can't allocate required memory";
+ else
+ g_StdOut << NError::MyFormatMessage(result);
+ g_StdOut << endl;
+ numErrors++;
+ continue;
+ }
+ {
+ if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0)
+ numErrors++;
+
+ 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[index] = true;
+ }
+ }
+
+
+ if (enableHeaders)
+ {
+ g_StdOut << endl << kListing << archiveName << endl << endl;
+
+ FOR_VECTOR (r, arcLink.Arcs)
+ {
+ const CArc &arc = arcLink.Arcs[r];
+ const CArcErrorInfo &er = arc.ErrorInfo;
+
+ g_StdOut << "--\n";
+ PrintPropPair("Path", arc.Path);
+ if (er.ErrorFormatIndex >= 0)
+ {
+ if (er.ErrorFormatIndex == arc.FormatIndex)
+ g_StdOut << "Warning: The archive is open with offset" << endl;
+ else
+ PrintArcTypeError(codecs->GetFormatNamePtr(er.ErrorFormatIndex), true);
+ }
+ PrintPropPair("Type", codecs->GetFormatNamePtr(arc.FormatIndex));
+
+ ErrorInfo_Print(er);
+
+ Int64 offset = arc.GetGlobalOffset();
+ if (offset != 0)
+ PrintPropNameAndNumber_Signed(kpidOffset, offset);
+ IInArchive *archive = arc.Archive;
+ RINOK(PrintArcProp(archive, kpidPhySize, NULL));
+ if (er.TailSize != 0)
+ PrintPropNameAndNumber(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(archive, propID, name));
+ }
+ }
+ if (r != arcLink.Arcs.Size() - 1)
+ {
+ UInt32 numProps;
+ g_StdOut << "----\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(propID, name, prop);
+ }
+ }
+ }
+ }
+ 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 stat;
+
+ UInt32 numItems;
+ RINOK(archive->GetNumberOfItems(&numItems));
+ 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_Folder(archive, i, fp.IsFolder));
+
+ if (!AllFilesAreAllowed)
+ {
+ if (!wildcardCensor.CheckPath(isAltStream, fp.FilePath, !fp.IsFolder))
+ 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.IsFolder)
+ stat.NumDirs++;
+ else
+ st.NumFiles = 1;
+ stat.GetStat(isAltStream).Update(st);
+
+ if (isAltStream && !showAltStreams)
+ continue;
+ RINOK(fp.PrintItemInfo(i, st));
+ }
+
+ UInt64 numStreams = stat.GetNumStreams();
+ if (!stdInMode
+ && !stat.MainFiles.PackSize.Def
+ && !stat.AltStreams.PackSize.Def)
+ {
+ if (arcLink.VolumePaths.Size() != 0)
+ arcPackSize += arcLink.VolumesSize;
+ stat.MainFiles.PackSize.Add((numStreams == 0) ? 0 : arcPackSize);
+ }
+ stat.MainFiles.SetSizeDefIfNoFiles();
+ stat.AltStreams.SetSizeDefIfNoFiles();
+ if (enableHeaders && !techMode)
+ {
+ fp.PrintTitleLines();
+ g_StdOut << endl;
+ fp.PrintSum(stat);
+ }
+
+ if (enableHeaders)
+ {
+ if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0)
+ {
+ g_StdOut << "----------\n";
+ PrintPropPair("Path", arcLink.NonOpen_ArcPath);
+ PrintArcTypeError(codecs->Formats[arcLink.NonOpen_ErrorInfo.ErrorFormatIndex].Name, false);
+ }
+ }
+ stat2.Update(stat);
+ fflush(stdout);
+ }
+ if (enableHeaders && !techMode && (arcPaths.Size() > 1 || numVolumes > 1))
+ {
+ g_StdOut << endl;
+ fp.PrintTitleLines();
+ g_StdOut << endl;
+ fp.PrintSum(stat2);
+ g_StdOut << endl;
+ PrintPropNameAndNumber("Archives", numArcs);
+ PrintPropNameAndNumber("Volumes", numVolumes);
+ PrintPropNameAndNumber("Total archives size", totalArcSizes);
+ }
+ return S_OK;
+}
diff --git a/lzma/CPP/7zip/UI/Console/List.h b/lzma/CPP/7zip/UI/Console/List.h
new file mode 100644
index 0000000..dabbc2a
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Console/List.h
@@ -0,0 +1,27 @@
+// 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
diff --git a/lzma/CPP/7zip/UI/Console/Main.cpp b/lzma/CPP/7zip/UI/Console/Main.cpp
new file mode 100644
index 0000000..f092f36
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Console/Main.cpp
@@ -0,0 +1,887 @@
+// Main.cpp
+
+#include "StdAfx.h"
+
+#include <Psapi.h>
+
+#if defined( _WIN32) && defined( _7ZIP_LARGE_PAGES)
+#include "../../../../C/Alloc.h"
+#endif
+
+#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 "../../../Windows/ErrorMsg.h"
+#ifdef _WIN32
+#include "../../../Windows/MemoryLock.h"
+#endif
+
+#ifndef _7ZIP_ST
+#include "../../../Windows/Synchronization.h"
+#endif
+
+#include "../../../Windows/TimeUtils.h"
+
+#include "../Common/ArchiveCommandLine.h"
+#include "../Common/ExitCode.h"
+#include "../Common/Extract.h"
+#ifdef EXTERNAL_CODECS
+#include "../Common/LoadCodecs.h"
+#endif
+
+#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;
+
+static const char *kCopyrightString = "\n7-Zip"
+#ifndef EXTERNAL_CODECS
+#ifdef PROG_VARIANT_R
+" (r)"
+#else
+" (a)"
+#endif
+#endif
+
+#ifdef _WIN64
+" [64]"
+#endif
+
+" " MY_VERSION_COPYRIGHT_DATE "\n";
+
+static const char *kHelpString =
+ "\nUsage: 7z"
+#ifndef EXTERNAL_CODECS
+#ifdef PROG_VARIANT_R
+ "r"
+#else
+ "a"
+#endif
+#endif
+ " <command> [<switches>...] <archive_name> [<file_names>...]\n"
+ " [<@listfiles...>]\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"
+ " l : List contents of archive\n"
+// " l[a|t][f] : List contents of archive\n"
+// " a - with Additional fields\n"
+// " t - with all fields\n"
+// " f - with Full pathnames\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"
+ "<Switches>\n"
+ " -- : Stop switches parsing\n"
+ " -ai[r[-|0]]{@listfile|!wildcard} : Include archives\n"
+ " -ax[r[-|0]]{@listfile|!wildcard} : eXclude archives\n"
+ " -bd : Disable percentage indicator\n"
+ " -i[r[-|0]]{@listfile|!wildcard} : Include filenames\n"
+ " -m{Parameters} : set compression Method\n"
+ " -o{Directory} : set Output directory\n"
+ #ifndef _NO_CRYPTO
+ " -p{Password} : set Password\n"
+ #endif
+ " -r[-|0] : Recurse subdirectories\n"
+ " -scs{UTF-8|UTF-16LE|UTF-16BE|WIN|DOS|{id}} : set charset for list files\n"
+ " -sfx[{name}] : Create SFX archive\n"
+ " -si[{name}] : read data from stdin\n"
+ " -slt : show technical information for l (List) command\n"
+ " -so : write data to stdout\n"
+ " -ssc[-] : set sensitive case mode\n"
+ " -ssw : compress shared files\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 *kEverythingIsOk = "Everything is Ok";
+static const char *kUserErrorMessage = "Incorrect command line";
+static const char *kNoFormats = "7-Zip cannot find the code that works with archives.";
+static const char *kUnsupportedArcTypeMessage = "Unsupported archive type";
+// static const char *kUnsupportedUpdateArcType = "Can't create archive for that type";
+
+static CFSTR kDefaultSfxModule = FTEXT("7zCon.sfx");
+
+static void ShowMessageAndThrowException(CStdOutStream &s, LPCSTR message, NExitCode::EEnum code)
+{
+ s << 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 &s, bool needHelp)
+{
+ s << kCopyrightString;
+ // s << "# CPUs: " << (UInt64)NWindows::NSystem::GetNumberOfProcessors() << "\n";
+ if (needHelp)
+ s << kHelpString;
+}
+
+#ifdef EXTERNAL_CODECS
+
+static void PrintString(CStdOutStream &stdStream, const AString &s, int size)
+{
+ int len = s.Len();
+ for (int i = len; i < size; i++)
+ stdStream << ' ';
+ stdStream << s;
+}
+
+static void PrintUInt32(CStdOutStream &stdStream, UInt32 val, int size)
+{
+ char s[16];
+ ConvertUInt32ToString(val, s);
+ PrintString(stdStream, s, size);
+}
+
+static void PrintLibIndex(CStdOutStream &stdStream, int libIndex)
+{
+ if (libIndex >= 0)
+ PrintUInt32(stdStream, libIndex, 2);
+ else
+ stdStream << " ";
+ stdStream << ' ';
+}
+
+#endif
+
+static void PrintString(CStdOutStream &stdStream, const UString &s, int size)
+{
+ int len = s.Len();
+ stdStream << s;
+ for (int i = len; i < size; i++)
+ stdStream << ' ';
+}
+
+static inline char GetHex(unsigned val)
+{
+ return (char)((val < 10) ? ('0' + val) : ('A' + (val - 10)));
+}
+
+static int WarningsCheck(HRESULT result, const CCallbackConsoleBase &callback,
+ const CErrorInfo &errorInfo, CStdOutStream &stdStream)
+{
+ int exitCode = NExitCode::kSuccess;
+
+ if (callback.CantFindFiles.Size() > 0)
+ {
+ stdStream << endl;
+ stdStream << "WARNINGS for files:" << endl << endl;
+ unsigned numErrors = callback.CantFindFiles.Size();
+ for (unsigned i = 0; i < numErrors; i++)
+ {
+ stdStream << callback.CantFindFiles[i] << " : ";
+ stdStream << NError::MyFormatMessage(callback.CantFindCodes[i]) << endl;
+ }
+ stdStream << "----------------" << endl;
+ stdStream << "WARNING: Cannot find " << numErrors << " file";
+ if (numErrors > 1)
+ stdStream << "s";
+ stdStream << endl;
+ exitCode = NExitCode::kWarning;
+ }
+
+ if (result != S_OK)
+ {
+ UString message;
+ if (!errorInfo.Message.IsEmpty())
+ {
+ message += errorInfo.Message;
+ message += L"\n";
+ }
+ if (!errorInfo.FileName.IsEmpty())
+ {
+ message += fs2us(errorInfo.FileName);
+ message += L"\n";
+ }
+ if (!errorInfo.FileName2.IsEmpty())
+ {
+ message += fs2us(errorInfo.FileName2);
+ message += L"\n";
+ }
+ if (errorInfo.SystemError != 0)
+ {
+ message += NError::MyFormatMessage(errorInfo.SystemError);
+ message += L"\n";
+ }
+ if (!message.IsEmpty())
+ stdStream << L"\nError:\n" << message;
+
+ // we will work with (result) later
+ // throw CSystemException(result);
+ return NExitCode::kFatalError;
+ }
+
+ unsigned numErrors = callback.FailedFiles.Size();
+ if (numErrors == 0)
+ {
+ if (callback.CantFindFiles.Size() == 0)
+ stdStream << kEverythingIsOk << endl;
+ }
+ else
+ {
+ stdStream << endl;
+ stdStream << "WARNINGS for files:" << endl << endl;
+ for (unsigned i = 0; i < numErrors; i++)
+ {
+ stdStream << callback.FailedFiles[i] << " : ";
+ stdStream << NError::MyFormatMessage(callback.FailedCodes[i]) << endl;
+ }
+ stdStream << "----------------" << endl;
+ stdStream << "WARNING: Cannot open " << numErrors << " file";
+ if (numErrors > 1)
+ stdStream << "s";
+ stdStream << 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";
+}
+
+EXTERN_C_BEGIN
+typedef BOOL (WINAPI *Func_GetProcessMemoryInfo)(HANDLE Process,
+ PPROCESS_MEMORY_COUNTERS ppsmemCounters, DWORD cb);
+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;
+ {
+ /* 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));
+ */
+
+ Func_GetProcessMemoryInfo my_GetProcessMemoryInfo = (Func_GetProcessMemoryInfo)
+ ::GetProcAddress(::GetModuleHandleW(L"kernel32.dll"), "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);
+ }
+
+ #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);
+ 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;
+}
+
+int Main2(
+ #ifndef _WIN32
+ int numArgs, const 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
+
+ if (commandStrings.Size() == 1)
+ {
+ ShowCopyrightAndHelp(g_StdOut, true);
+ return 0;
+ }
+
+ commandStrings.Delete(0);
+
+ CArcCmdLineOptions options;
+
+ CArcCmdLineParser parser;
+
+ parser.Parse1(commandStrings, options);
+
+ if (options.HelpMode)
+ {
+ ShowCopyrightAndHelp(g_StdOut, true);
+ return 0;
+ }
+
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ NSecurity::EnablePrivilege_SymLink();
+ #endif
+ #ifdef _7ZIP_LARGE_PAGES
+ if (options.LargePages)
+ {
+ SetLargePageSize();
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ NSecurity::EnablePrivilege_LockMemory();
+ #endif
+ }
+ #endif
+
+ CStdOutStream &stdStream = options.StdOutMode ? g_StdErr : g_StdOut;
+ g_StdStream = &stdStream;
+
+ if (options.EnableHeaders)
+ ShowCopyrightAndHelp(stdStream, false);
+
+ parser.Parse2(options);
+
+ CCodecs *codecs = new CCodecs;
+ #ifdef EXTERNAL_CODECS
+ CExternalCodecs __externalCodecs;
+ __externalCodecs.GetCodecs = codecs;
+ __externalCodecs.GetHashers = codecs;
+ #else
+ CMyComPtr<IUnknown> compressCodecsInfo = codecs;
+ #endif
+ 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()))
+ 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.LoadCodecs());
+ #endif
+
+ int retCode = NExitCode::kSuccess;
+ HRESULT hresultMain = S_OK;
+
+ bool showStat = true;
+ if (!options.EnableHeaders ||
+ options.TechMode)
+ showStat = false;
+
+
+ if (options.Command.CommandType == NCommandType::kInfo)
+ {
+ unsigned i;
+
+ #ifdef EXTERNAL_CODECS
+ stdStream << endl << "Libs:" << endl;
+ for (i = 0; i < codecs->Libs.Size(); i++)
+ {
+ PrintLibIndex(stdStream, i);
+ stdStream << ' ' << codecs->Libs[i].Path << endl;
+ }
+ #endif
+
+ stdStream << endl << "Formats:" << endl;
+
+ const char *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(stdStream, arc.LibIndex);
+ #else
+ stdStream << " ";
+ #endif
+ stdStream << (char)(arc.UpdateEnabled ? 'C' : ' ');
+ for (unsigned b = 0; b < kNumArcFlags; b++)
+ {
+ stdStream << (char)
+ ((arc.Flags & ((UInt32)1 << b)) != 0 ? kArcFlags[b] : ' ');
+ }
+
+ stdStream << ' ';
+ PrintString(stdStream, arc.Name, 8);
+ stdStream << ' ';
+ UString s;
+ FOR_VECTOR (t, arc.Exts)
+ {
+ if (t != 0)
+ s += L' ';
+ const CArcExtInfo &ext = arc.Exts[t];
+ s += ext.Ext;
+ if (!ext.AddExt.IsEmpty())
+ {
+ s += L" (";
+ s += ext.AddExt;
+ s += L')';
+ }
+ }
+ PrintString(stdStream, s, 13);
+ stdStream << ' ';
+ if (arc.SignatureOffset != 0)
+ stdStream << "offset=" << arc.SignatureOffset << ' ';
+
+ FOR_VECTOR(si, arc.Signatures)
+ {
+ if (si != 0)
+ stdStream << " || ";
+
+ const CByteBuffer &sig = arc.Signatures[si];
+
+ for (size_t j = 0; j < sig.Size(); j++)
+ {
+ if (j != 0)
+ stdStream << ' ';
+ Byte b = sig[j];
+ if (b > 0x20 && b < 0x80)
+ {
+ stdStream << (char)b;
+ }
+ else
+ {
+ stdStream << GetHex((b >> 4) & 0xF);
+ stdStream << GetHex(b & 0xF);
+ }
+ }
+ }
+ stdStream << endl;
+ }
+
+ #ifdef EXTERNAL_CODECS
+
+ stdStream << endl << "Codecs:" << endl << "Lib ID Name" << endl;
+ UInt32 numMethods;
+ if (codecs->GetNumberOfMethods(&numMethods) == S_OK)
+ for (UInt32 j = 0; j < numMethods; j++)
+ {
+ PrintLibIndex(stdStream, codecs->GetCodecLibIndex(j));
+ stdStream << (char)(codecs->GetCodecEncoderIsAssigned(j) ? 'C' : ' ');
+ UInt64 id;
+ stdStream << " ";
+ HRESULT res = codecs->GetCodecId(j, id);
+ if (res != S_OK)
+ id = (UInt64)(Int64)-1;
+ char s[32];
+ ConvertUInt64ToHex(id, s);
+ PrintString(stdStream, s, 8);
+ stdStream << " " << codecs->GetCodecName(j) << endl;
+ }
+
+ stdStream << endl << "Hashers:" << endl << " L Size ID Name" << endl;
+ numMethods = codecs->GetNumHashers();
+ for (UInt32 j = 0; j < numMethods; j++)
+ {
+ PrintLibIndex(stdStream, codecs->GetHasherLibIndex(j));
+ PrintUInt32(stdStream, codecs->GetHasherDigestSize(j), 4);
+ stdStream << ' ';
+ char s[32];
+ ConvertUInt64ToHex(codecs->GetHasherId(j), s);
+ PrintString(stdStream, s, 6);
+ stdStream << " " << codecs->GetHasherName(j) << endl;
+ }
+
+ #endif
+
+ }
+ else if (options.Command.CommandType == NCommandType::kBenchmark)
+ {
+ hresultMain = BenchCon(EXTERNAL_CODECS_VARS
+ options.Properties, options.NumIterations, (FILE *)stdStream);
+ if (hresultMain == S_FALSE)
+ {
+ stdStream << "\nDecoding Error\n";
+ retCode = NExitCode::kFatalError;
+ hresultMain = S_OK;
+ }
+ }
+ else if (isExtractGroupCommand || options.Command.CommandType == NCommandType::kList)
+ {
+ if (isExtractGroupCommand)
+ {
+ CExtractCallbackConsole *ecs = new CExtractCallbackConsole;
+ CMyComPtr<IFolderArchiveExtractCallback> extractCallback = ecs;
+
+ ecs->OutStream = &stdStream;
+
+ #ifndef _NO_CRYPTO
+ ecs->PasswordIsDefined = options.PasswordEnabled;
+ ecs->Password = options.Password;
+ #endif
+
+ ecs->Init();
+
+ COpenCallbackConsole openCallback;
+ openCallback.OutStream = &stdStream;
+
+ #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 options.HashMethods));
+ hb.Init();
+ }
+ hresultMain = Extract(
+ codecs,
+ types,
+ excludedFormats,
+ options.ArchivePathsSorted,
+ options.ArchivePathsFullSorted,
+ options.Censor.Pairs.Front().Head,
+ eo, &openCallback, ecs, hashCalc, errorMessage, stat);
+ if (!errorMessage.IsEmpty())
+ {
+ stdStream << endl << "Error: " << errorMessage;
+ if (hresultMain == S_OK)
+ hresultMain = E_FAIL;
+ }
+
+ stdStream << endl;
+
+ if (ecs->NumTryArcs > 1)
+ {
+ stdStream << "Archives: " << ecs->NumTryArcs << endl;
+ stdStream << "OK archives: " << ecs->NumOkArcs << endl;
+ }
+ bool isError = false;
+ if (ecs->NumCantOpenArcs != 0)
+ {
+ isError = true;
+ stdStream << "Can't open as archive: " << ecs->NumCantOpenArcs << endl;
+ }
+ if (ecs->NumArcsWithError != 0)
+ {
+ isError = true;
+ stdStream << "Archives with Errors: " << ecs->NumArcsWithError << endl;
+ }
+ if (ecs->NumArcsWithWarnings != 0)
+ stdStream << "Archives with Warnings: " << ecs->NumArcsWithWarnings << endl;
+
+ if (ecs->NumOpenArcWarnings != 0)
+ {
+ stdStream << endl;
+ if (ecs->NumOpenArcWarnings != 0)
+ stdStream << "Warnings: " << ecs->NumOpenArcWarnings << endl;
+ }
+
+ if (ecs->NumOpenArcErrors != 0)
+ {
+ isError = true;
+ stdStream << endl;
+ if (ecs->NumOpenArcErrors != 0)
+ stdStream << "Open Errors: " << ecs->NumOpenArcErrors << endl;
+ }
+
+ if (isError)
+ retCode = NExitCode::kFatalError;
+
+ if (ecs->NumArcsWithError != 0 || ecs->NumFileErrors != 0)
+ {
+ // if (ecs->NumArchives > 1)
+ {
+ stdStream << endl;
+ if (ecs->NumFileErrors != 0)
+ stdStream << "Sub items Errors: " << ecs->NumFileErrors << endl;
+ }
+ }
+ else if (hresultMain == S_OK)
+ {
+
+ if (stat.NumFolders != 0)
+ stdStream << "Folders: " << stat.NumFolders << endl;
+ if (stat.NumFiles != 1 || stat.NumFolders != 0 || stat.NumAltStreams != 0)
+ stdStream << "Files: " << stat.NumFiles << endl;
+ if (stat.NumAltStreams != 0)
+ {
+ stdStream << "Alternate Streams: " << stat.NumAltStreams << endl;
+ stdStream << "Alternate Streams Size: " << stat.AltStreams_UnpackSize << endl;
+ }
+
+ stdStream
+ << "Size: " << stat.UnpackSize << endl
+ << "Compressed: " << stat.PackSize << endl;
+ if (hashCalc)
+ PrintHashStat(stdStream, hb);
+ }
+ }
+ else
+ {
+ UInt64 numErrors = 0;
+ UInt64 numWarnings = 0;
+
+ // options.ExtractNtOptions.StoreAltStreams = true, if -sns[-] is not definmed
+
+ hresultMain = ListArchives(
+ codecs,
+ types,
+ excludedFormats,
+ options.StdInMode,
+ options.ArchivePathsSorted,
+ options.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.OutStream = &stdStream;
+
+ #ifndef _NO_CRYPTO
+ bool passwordIsDefined =
+ options.PasswordEnabled && !options.Password.IsEmpty();
+ openCallback.PasswordIsDefined = passwordIsDefined;
+ openCallback.Password = options.Password;
+ #endif
+
+ CUpdateCallbackConsole callback;
+ callback.EnablePercents = options.EnablePercents;
+
+ #ifndef _NO_CRYPTO
+ callback.PasswordIsDefined = passwordIsDefined;
+ callback.AskPassword = options.PasswordEnabled && options.Password.IsEmpty();
+ callback.Password = options.Password;
+ #endif
+ callback.StdOutMode = uo.StdOutMode;
+ callback.Init(&stdStream);
+
+ CUpdateErrorInfo errorInfo;
+
+ /*
+ if (!uo.Init(codecs, types, options.ArchiveName))
+ throw kUnsupportedUpdateArcType;
+ */
+ hresultMain = UpdateArchive(codecs,
+ types,
+ options.ArchiveName,
+ options.Censor,
+ uo,
+ errorInfo, &openCallback, &callback, true);
+ retCode = WarningsCheck(hresultMain, callback, errorInfo, stdStream);
+ }
+ else if (options.Command.CommandType == NCommandType::kHash)
+ {
+ const CHashOptions &uo = options.HashOptions;
+
+ CHashCallbackConsole callback;
+ callback.EnablePercents = options.EnablePercents;
+
+ callback.Init(&stdStream);
+
+ UString errorInfoString;
+ hresultMain = HashCalc(EXTERNAL_CODECS_VARS
+ options.Censor, uo,
+ errorInfoString, &callback);
+ CErrorInfo errorInfo;
+ errorInfo.Message = errorInfoString;
+ retCode = WarningsCheck(hresultMain, callback, errorInfo, stdStream);
+ }
+ else
+ ShowMessageAndThrowException(stdStream, kUserErrorMessage, NExitCode::kUserError);
+
+ if (showStat)
+ PrintStat();
+
+ ThrowException_if_Error(hresultMain);
+
+ return retCode;
+}
diff --git a/lzma/CPP/7zip/UI/Console/MainAr.cpp b/lzma/CPP/7zip/UI/Console/MainAr.cpp
new file mode 100644
index 0000000..0e5cebc
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Console/MainAr.cpp
@@ -0,0 +1,125 @@
+// MainAr.cpp
+
+#include "StdAfx.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;
+
+CStdOutStream *g_StdStream = 0;
+
+extern int Main2(
+ #ifndef _WIN32
+ int numArgs, const char *args[]
+ #endif
+);
+
+static const char *kException_CmdLine_Error_Message = "\n\nCommand Line Error:\n";
+static const char *kExceptionErrorMessage = "\n\nError:\n";
+static const char *kUserBreak = "\nBreak signaled\n";
+static const char *kMemoryExceptionMessage = "\n\nERROR: Can't allocate required memory!\n";
+static const char *kUnknownExceptionMessage = "\n\nUnknown Error\n";
+static const char *kInternalExceptionMessage = "\n\nInternal Error #";
+
+#define NT_CHECK_FAIL_ACTION (*g_StdStream) << "Unsupported Windows version"; return NExitCode::kFatalError;
+
+int MY_CDECL main
+(
+ #ifndef _WIN32
+ int numArgs, const char *args[]
+ #endif
+)
+{
+ g_StdStream = &g_StdOut;
+
+ NT_CHECK
+
+ NConsoleClose::CCtrlHandlerSetter ctrlHandlerSetter;
+ int res = 0;
+ try
+ {
+ res = Main2(
+ #ifndef _WIN32
+ numArgs, args
+ #endif
+ );
+ }
+ catch(const CNewException &)
+ {
+ (*g_StdStream) << kMemoryExceptionMessage;
+ return (NExitCode::kMemoryError);
+ }
+ catch(const NConsoleClose::CCtrlBreakException &)
+ {
+ (*g_StdStream) << endl << kUserBreak;
+ return (NExitCode::kUserBreak);
+ }
+ catch(const CArcCmdLineException &e)
+ {
+ (*g_StdStream) << kException_CmdLine_Error_Message << e << endl;
+ return (NExitCode::kUserError);
+ }
+ catch(const CSystemException &systemError)
+ {
+ if (systemError.ErrorCode == E_OUTOFMEMORY)
+ {
+ (*g_StdStream) << kMemoryExceptionMessage;
+ return (NExitCode::kMemoryError);
+ }
+ if (systemError.ErrorCode == E_ABORT)
+ {
+ (*g_StdStream) << endl << kUserBreak;
+ return (NExitCode::kUserBreak);
+ }
+ (*g_StdStream) << endl << endl << "System error:" << endl <<
+ NError::MyFormatMessage(systemError.ErrorCode) << endl;
+ return (NExitCode::kFatalError);
+ }
+ catch(NExitCode::EEnum &exitCode)
+ {
+ (*g_StdStream) << kInternalExceptionMessage << exitCode << endl;
+ return (exitCode);
+ }
+ /*
+ catch(const NExitCode::CMultipleErrors &multipleErrors)
+ {
+ (*g_StdStream) << endl << multipleErrors.NumErrors << " errors" << endl;
+ return (NExitCode::kFatalError);
+ }
+ */
+ catch(const UString &s)
+ {
+ (*g_StdStream) << kExceptionErrorMessage << s << endl;
+ return (NExitCode::kFatalError);
+ }
+ catch(const AString &s)
+ {
+ (*g_StdStream) << kExceptionErrorMessage << s << endl;
+ return (NExitCode::kFatalError);
+ }
+ catch(const char *s)
+ {
+ (*g_StdStream) << kExceptionErrorMessage << s << endl;
+ return (NExitCode::kFatalError);
+ }
+ catch(int t)
+ {
+ (*g_StdStream) << kInternalExceptionMessage << t << endl;
+ return (NExitCode::kFatalError);
+ }
+ catch(...)
+ {
+ (*g_StdStream) << kUnknownExceptionMessage;
+ return (NExitCode::kFatalError);
+ }
+ return res;
+}
diff --git a/lzma/CPP/7zip/UI/Console/OpenCallbackConsole.cpp b/lzma/CPP/7zip/UI/Console/OpenCallbackConsole.cpp
new file mode 100644
index 0000000..6552d5d
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Console/OpenCallbackConsole.cpp
@@ -0,0 +1,58 @@
+// OpenCallbackConsole.cpp
+
+#include "StdAfx.h"
+
+#include "OpenCallbackConsole.h"
+
+#include "ConsoleClose.h"
+#include "UserInputUtils.h"
+
+HRESULT COpenCallbackConsole::Open_CheckBreak()
+{
+ if (NConsoleClose::TestBreakSignal())
+ return E_ABORT;
+ return S_OK;
+}
+
+HRESULT COpenCallbackConsole::Open_SetTotal(const UInt64 *, const UInt64 *)
+{
+ return Open_CheckBreak();
+}
+
+HRESULT COpenCallbackConsole::Open_SetCompleted(const UInt64 *, const UInt64 *)
+{
+ return Open_CheckBreak();
+}
+
+#ifndef _NO_CRYPTO
+
+HRESULT COpenCallbackConsole::Open_CryptoGetTextPassword(BSTR *password)
+{
+ PasswordWasAsked = true;
+ RINOK(Open_CheckBreak());
+ if (!PasswordIsDefined)
+ {
+ Password = GetPassword(OutStream);
+ 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_ClearPasswordWasAskedFlag()
+{
+ PasswordWasAsked = false;
+}
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Console/OpenCallbackConsole.h b/lzma/CPP/7zip/UI/Console/OpenCallbackConsole.h
new file mode 100644
index 0000000..25d3f72
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Console/OpenCallbackConsole.h
@@ -0,0 +1,25 @@
+// OpenCallbackConsole.h
+
+#ifndef __OPEN_CALLBACK_CONSOLE_H
+#define __OPEN_CALLBACK_CONSOLE_H
+
+#include "../../../Common/StdOutStream.h"
+
+#include "../Common/ArchiveOpenCallback.h"
+
+class COpenCallbackConsole: public IOpenCallbackUI
+{
+public:
+ INTERFACE_IOpenCallbackUI(;)
+
+ CStdOutStream *OutStream;
+
+ #ifndef _NO_CRYPTO
+ bool PasswordIsDefined;
+ bool PasswordWasAsked;
+ UString Password;
+ COpenCallbackConsole(): PasswordIsDefined(false), PasswordWasAsked(false) {}
+ #endif
+};
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Console/PercentPrinter.cpp b/lzma/CPP/7zip/UI/Console/PercentPrinter.cpp
new file mode 100644
index 0000000..edf88b9
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Console/PercentPrinter.cpp
@@ -0,0 +1,102 @@
+// PercentPrinter.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/Defs.h"
+#include "../../../Common/IntToString.h"
+
+#include "PercentPrinter.h"
+
+static const unsigned kPaddingSize = 2;
+static const unsigned kPercentsSize = 4;
+static const unsigned kMaxExtraSize = kPaddingSize + 32 + kPercentsSize;
+
+static void ClearPrev(char *p, unsigned num)
+{
+ unsigned i;
+ for (i = 0; i < num; i++) *p++ = '\b';
+ for (i = 0; i < num; i++) *p++ = ' ';
+ for (i = 0; i < num; i++) *p++ = '\b';
+ *p = '\0';
+}
+
+void CPercentPrinter::ClosePrint()
+{
+ if (m_NumExtraChars == 0)
+ return;
+ char s[kMaxExtraSize * 3 + 1];
+ ClearPrev(s, m_NumExtraChars);
+ (*OutStream) << s;
+ m_NumExtraChars = 0;
+}
+
+void CPercentPrinter::PrintString(const char *s)
+{
+ ClosePrint();
+ (*OutStream) << s;
+}
+
+void CPercentPrinter::PrintString(const wchar_t *s)
+{
+ ClosePrint();
+ (*OutStream) << s;
+}
+
+void CPercentPrinter::PrintNewLine()
+{
+ ClosePrint();
+ (*OutStream) << "\n";
+}
+
+void CPercentPrinter::RePrintRatio()
+{
+ char s[32];
+ unsigned size;
+ {
+ char c = '%';
+ UInt64 value = 0;
+ if (m_Total == (UInt64)(Int64)-1)
+ {
+ value = m_CurValue >> 20;
+ c = 'M';
+ }
+ else if (m_Total != 0)
+ value = m_CurValue * 100 / m_Total;
+ ConvertUInt64ToString(value, s);
+ size = (unsigned)strlen(s);
+ s[size++] = c;
+ s[size] = '\0';
+ }
+
+ unsigned extraSize = kPaddingSize + MyMax(size, kPercentsSize);
+ if (extraSize < m_NumExtraChars)
+ extraSize = m_NumExtraChars;
+
+ char fullString[kMaxExtraSize * 3];
+ char *p = fullString;
+ unsigned i;
+ if (m_NumExtraChars == 0)
+ {
+ for (i = 0; i < extraSize; i++)
+ *p++ = ' ';
+ m_NumExtraChars = extraSize;
+ }
+
+ for (i = 0; i < m_NumExtraChars; i++)
+ *p++ = '\b';
+ m_NumExtraChars = extraSize;
+ for (; size < extraSize; size++)
+ *p++ = ' ';
+ MyStringCopy(p, s);
+ (*OutStream) << fullString;
+ OutStream->Flush();
+ m_PrevValue = m_CurValue;
+}
+
+void CPercentPrinter::PrintRatio()
+{
+ if (m_CurValue < m_PrevValue + m_MinStepSize &&
+ m_CurValue + m_MinStepSize > m_PrevValue && m_NumExtraChars != 0)
+ return;
+ RePrintRatio();
+}
diff --git a/lzma/CPP/7zip/UI/Console/PercentPrinter.h b/lzma/CPP/7zip/UI/Console/PercentPrinter.h
new file mode 100644
index 0000000..b6b357a
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Console/PercentPrinter.h
@@ -0,0 +1,30 @@
+// PercentPrinter.h
+
+#ifndef __PERCENT_PRINTER_H
+#define __PERCENT_PRINTER_H
+
+#include "../../../Common/StdOutStream.h"
+
+class CPercentPrinter
+{
+ UInt64 m_MinStepSize;
+ UInt64 m_PrevValue;
+ UInt64 m_CurValue;
+ UInt64 m_Total;
+ unsigned m_NumExtraChars;
+public:
+ CStdOutStream *OutStream;
+
+ CPercentPrinter(UInt64 minStepSize = 1): m_MinStepSize(minStepSize),
+ m_PrevValue(0), m_CurValue(0), m_Total((UInt64)(Int64)-1), m_NumExtraChars(0) {}
+ void SetTotal(UInt64 total) { m_Total = total; m_PrevValue = 0; }
+ void SetRatio(UInt64 doneValue) { m_CurValue = doneValue; }
+ void PrintString(const char *s);
+ void PrintString(const wchar_t *s);
+ void PrintNewLine();
+ void ClosePrint();
+ void RePrintRatio();
+ void PrintRatio();
+};
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Console/StdAfx.cpp b/lzma/CPP/7zip/UI/Console/StdAfx.cpp
new file mode 100644
index 0000000..c6d3b1f
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Console/StdAfx.cpp
@@ -0,0 +1,3 @@
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/lzma/CPP/7zip/UI/Console/StdAfx.h b/lzma/CPP/7zip/UI/Console/StdAfx.h
new file mode 100644
index 0000000..59d9ac1
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Console/StdAfx.h
@@ -0,0 +1,8 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "../../../Common/Common.h"
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Console/UpdateCallbackConsole.cpp b/lzma/CPP/7zip/UI/Console/UpdateCallbackConsole.cpp
new file mode 100644
index 0000000..033d70b
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Console/UpdateCallbackConsole.cpp
@@ -0,0 +1,276 @@
+// UpdateCallbackConsole.cpp
+
+#include "StdAfx.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 *kEmptyFileAlias = L"[Content]";
+
+static const char *kCreatingArchiveMessage = "Creating archive ";
+static const char *kUpdatingArchiveMessage = "Updating archive ";
+static const char *kScanningMessage = "Scanning";
+
+
+HRESULT CUpdateCallbackConsole::OpenResult(const wchar_t *name, HRESULT result, const wchar_t *errorArcType)
+{
+ (*OutStream) << endl;
+ if (result != S_OK)
+ {
+ (*OutStream) << "Error: " << name;
+ if (errorArcType)
+ (*OutStream) << " : can not open the file as [" << errorArcType << "] archive";
+ else
+ (*OutStream) << " is not supported archive";
+ (*OutStream) << endl;
+ }
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::StartScanning()
+{
+ (*OutStream) << kScanningMessage;
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::ScanProgress(UInt64 /* numFolders */, UInt64 /* numFiles */, UInt64 /* totalSize */, const wchar_t * /* path */, bool /* isDir */)
+{
+ return CheckBreak();
+}
+
+HRESULT CCallbackConsoleBase::CanNotFindError_Base(const wchar_t *name, DWORD systemError)
+{
+ CantFindFiles.Add(name);
+ CantFindCodes.Add(systemError);
+ // m_PercentPrinter.ClosePrint();
+ if (!m_WarningsMode)
+ {
+ (*OutStream) << endl << endl;
+ m_PercentPrinter.PrintNewLine();
+ m_WarningsMode = true;
+ }
+ m_PercentPrinter.PrintString(name);
+ m_PercentPrinter.PrintString(": WARNING: ");
+ m_PercentPrinter.PrintString(NError::MyFormatMessage(systemError));
+ m_PercentPrinter.PrintNewLine();
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::CanNotFindError(const wchar_t *name, DWORD systemError)
+{
+ return CanNotFindError_Base(name, systemError);
+}
+
+HRESULT CUpdateCallbackConsole::FinishScanning()
+{
+ (*OutStream) << endl << endl;
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::StartArchive(const wchar_t *name, bool updating)
+{
+ if(updating)
+ (*OutStream) << kUpdatingArchiveMessage;
+ else
+ (*OutStream) << kCreatingArchiveMessage;
+ if (name != 0)
+ (*OutStream) << name;
+ else
+ (*OutStream) << "StdOut";
+ (*OutStream) << endl << endl;
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::FinishArchive()
+{
+ (*OutStream) << endl;
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::CheckBreak()
+{
+ if (NConsoleClose::TestBreakSignal())
+ return E_ABORT;
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::Finilize()
+{
+ MT_LOCK
+ if (m_NeedBeClosed)
+ {
+ if (EnablePercents)
+ {
+ m_PercentPrinter.ClosePrint();
+ }
+ if (!StdOutMode && m_NeedNewLine)
+ {
+ m_PercentPrinter.PrintNewLine();
+ m_NeedNewLine = false;
+ }
+ m_NeedBeClosed = false;
+ }
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::SetNumFiles(UInt64 /* numFiles */)
+{
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::SetTotal(UInt64 size)
+{
+ MT_LOCK
+ if (EnablePercents)
+ m_PercentPrinter.SetTotal(size);
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::SetCompleted(const UInt64 *completeValue)
+{
+ MT_LOCK
+ if (completeValue != NULL)
+ {
+ if (EnablePercents)
+ {
+ m_PercentPrinter.SetRatio(*completeValue);
+ m_PercentPrinter.PrintRatio();
+ m_NeedBeClosed = true;
+ }
+ }
+ if (NConsoleClose::TestBreakSignal())
+ return E_ABORT;
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::SetRatioInfo(const UInt64 * /* inSize */, const UInt64 * /* outSize */)
+{
+ if (NConsoleClose::TestBreakSignal())
+ return E_ABORT;
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::GetStream(const wchar_t *name, bool isAnti)
+{
+ MT_LOCK
+ if (StdOutMode)
+ return S_OK;
+ if(isAnti)
+ m_PercentPrinter.PrintString("Anti item ");
+ else
+ m_PercentPrinter.PrintString("Compressing ");
+ if (name[0] == 0)
+ name = kEmptyFileAlias;
+ m_PercentPrinter.PrintString(name);
+ if (EnablePercents)
+ m_PercentPrinter.RePrintRatio();
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::OpenFileError(const wchar_t *name, DWORD systemError)
+{
+ MT_LOCK
+ FailedCodes.Add(systemError);
+ FailedFiles.Add(name);
+ /*
+ if (systemError == ERROR_SHARING_VIOLATION)
+ {
+ */
+ m_PercentPrinter.ClosePrint();
+ m_PercentPrinter.PrintNewLine();
+ m_PercentPrinter.PrintString("WARNING: ");
+ m_PercentPrinter.PrintString(NError::MyFormatMessage(systemError));
+ return S_FALSE;
+ /*
+ }
+ return systemError;
+ */
+}
+
+HRESULT CUpdateCallbackConsole::SetOperationResult(Int32 )
+{
+ m_NeedBeClosed = true;
+ m_NeedNewLine = true;
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password)
+{
+ *password = NULL;
+
+ #ifdef _NO_CRYPTO
+
+ *passwordIsDefined = false;
+ return S_OK;
+
+ #else
+
+ if (!PasswordIsDefined)
+ {
+ if (AskPassword)
+ {
+ Password = GetPassword(OutStream);
+ PasswordIsDefined = true;
+ }
+ }
+ *passwordIsDefined = BoolToInt(PasswordIsDefined);
+ return StringToBstr(Password, password);
+
+ #endif
+}
+
+HRESULT CUpdateCallbackConsole::CryptoGetTextPassword(BSTR *password)
+{
+ *password = NULL;
+
+ #ifdef _NO_CRYPTO
+
+ return E_NOTIMPL;
+
+ #else
+
+ if (!PasswordIsDefined)
+ {
+ {
+ Password = GetPassword(OutStream);
+ PasswordIsDefined = true;
+ }
+ }
+ return StringToBstr(Password, password);
+
+ #endif
+}
+
+/*
+HRESULT CUpdateCallbackConsole::ShowDeleteFile(const wchar_t *name)
+{
+ // MT_LOCK
+ if (StdOutMode)
+ return S_OK;
+ RINOK(Finilize());
+ m_PercentPrinter.PrintString("Deleting ");
+ if (name[0] == 0)
+ name = kEmptyFileAlias;
+ m_PercentPrinter.PrintString(name);
+ if (EnablePercents)
+ m_PercentPrinter.RePrintRatio();
+ m_NeedBeClosed = true;
+ m_NeedNewLine = true;
+ return S_OK;
+}
+*/
diff --git a/lzma/CPP/7zip/UI/Console/UpdateCallbackConsole.h b/lzma/CPP/7zip/UI/Console/UpdateCallbackConsole.h
new file mode 100644
index 0000000..c73de67
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Console/UpdateCallbackConsole.h
@@ -0,0 +1,75 @@
+// UpdateCallbackConsole.h
+
+#ifndef __UPDATE_CALLBACK_CONSOLE_H
+#define __UPDATE_CALLBACK_CONSOLE_H
+
+#include "../../../Common/StdOutStream.h"
+
+#include "../Common/Update.h"
+
+#include "PercentPrinter.h"
+
+class CCallbackConsoleBase
+{
+ bool m_WarningsMode;
+protected:
+ CPercentPrinter m_PercentPrinter;
+
+ CStdOutStream *OutStream;
+ HRESULT CanNotFindError_Base(const wchar_t *name, DWORD systemError);
+public:
+ bool EnablePercents;
+ bool StdOutMode;
+
+ CCallbackConsoleBase():
+ m_PercentPrinter(1 << 16),
+ StdOutMode(false),
+ EnablePercents(true),
+ m_WarningsMode(false)
+ {}
+
+ void Init(CStdOutStream *outStream)
+ {
+ FailedFiles.Clear();
+ FailedCodes.Clear();
+ OutStream = outStream;
+ m_PercentPrinter.OutStream = outStream;
+ }
+
+ UStringVector FailedFiles;
+ CRecordVector<HRESULT> FailedCodes;
+
+ UStringVector CantFindFiles;
+ CRecordVector<HRESULT> CantFindCodes;
+};
+
+class CUpdateCallbackConsole: public IUpdateCallbackUI2, public CCallbackConsoleBase
+{
+ bool m_NeedBeClosed;
+ bool m_NeedNewLine;
+public:
+ #ifndef _NO_CRYPTO
+ bool PasswordIsDefined;
+ UString Password;
+ bool AskPassword;
+ #endif
+
+ CUpdateCallbackConsole()
+ #ifndef _NO_CRYPTO
+ :
+ PasswordIsDefined(false),
+ AskPassword(false)
+ #endif
+ {}
+
+ void Init(CStdOutStream *outStream)
+ {
+ m_NeedBeClosed = false;
+ m_NeedNewLine = false;
+ CCallbackConsoleBase::Init(outStream);
+ }
+ ~CUpdateCallbackConsole() { Finilize(); }
+ INTERFACE_IUpdateCallbackUI2(;)
+};
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Console/UserInputUtils.cpp b/lzma/CPP/7zip/UI/Console/UserInputUtils.cpp
new file mode 100644
index 0000000..b060fb0
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Console/UserInputUtils.cpp
@@ -0,0 +1,76 @@
+// 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 *kFirstQuestionMessage = "?\n";
+static const char *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)
+{
+ (*outStream) << kFirstQuestionMessage;
+ for (;;)
+ {
+ (*outStream) << kHelpQuestionMessage;
+ outStream->Flush();
+ AString scannedString = g_StdIn.ScanStringUntilNewLine();
+ scannedString.Trim();
+ if (!scannedString.IsEmpty())
+ 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
+
+UString GetPassword(CStdOutStream *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);
+ UString res = g_StdIn.ScanUStringUntilNewLine();
+ if (wasChanged)
+ SetConsoleMode(console, mode);
+ (*outStream) << "\n";
+ outStream->Flush();
+ return res;
+ #else
+ return g_StdIn.ScanUStringUntilNewLine();
+ #endif
+}
diff --git a/lzma/CPP/7zip/UI/Console/UserInputUtils.h b/lzma/CPP/7zip/UI/Console/UserInputUtils.h
new file mode 100644
index 0000000..df2773d
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Console/UserInputUtils.h
@@ -0,0 +1,24 @@
+// 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
+};
+}
+
+NUserAnswerMode::EEnum ScanUserYesNoAllQuit(CStdOutStream *outStream);
+UString GetPassword(CStdOutStream *outStream);
+
+#endif
diff --git a/lzma/CPP/7zip/UI/Console/makefile b/lzma/CPP/7zip/UI/Console/makefile
new file mode 100644
index 0000000..0181c52
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Console/makefile
@@ -0,0 +1,71 @@
+PROG = 7z.exe
+MY_CONSOLE = 1
+CFLAGS = $(CFLAGS) \
+ -DEXTERNAL_CODECS \
+
+!IFNDEF UNDER_CE
+CFLAGS = $(CFLAGS) -DWIN_LONG_PATH -D_7ZIP_LARGE_PAGES -DSUPPORT_DEVICE_FILE
+!ENDIF
+
+CURRENT_OBJS = \
+
+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 = \
+ $O\Alloc.obj \
+ $O\CpuArch.obj \
+ $O\Sort.obj \
+ $O\Threads.obj \
+
+!include "../../Crc.mak"
+!include "Console.mak"
+
+!include "../../7zip.mak"
diff --git a/lzma/CPP/7zip/UI/Console/resource.rc b/lzma/CPP/7zip/UI/Console/resource.rc
new file mode 100644
index 0000000..20dfee1
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Console/resource.rc
@@ -0,0 +1,3 @@
+#include "../../MyVersionInfo.rc"
+
+MY_VERSION_INFO_APP("7-Zip Console", "7z")
diff --git a/lzma/CPP/7zip/UI/Explorer/MyMessages.cpp b/lzma/CPP/7zip/UI/Explorer/MyMessages.cpp
new file mode 100644
index 0000000..1ef0d9c
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Explorer/MyMessages.cpp
@@ -0,0 +1,37 @@
+// 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());
+}
diff --git a/lzma/CPP/7zip/UI/Explorer/MyMessages.h b/lzma/CPP/7zip/UI/Explorer/MyMessages.h
new file mode 100644
index 0000000..c175e8a
--- /dev/null
+++ b/lzma/CPP/7zip/UI/Explorer/MyMessages.h
@@ -0,0 +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
diff --git a/lzma/CPP/7zip/UI/FileManager/BrowseDialog.cpp b/lzma/CPP/7zip/UI/FileManager/BrowseDialog.cpp
new file mode 100644
index 0000000..fb63835
--- /dev/null
+++ b/lzma/CPP/7zip/UI/FileManager/BrowseDialog.cpp
@@ -0,0 +1,1008 @@
+// BrowseDialog.cpp
+
+#include "StdAfx.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 += L'\n';
+ 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() { PostMessage(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
+ if (ReadSingleClick())
+ _list.SetExtendedListViewStyle(LVS_EX_ONECLICKACTIVATE | LVS_EX_TRACKSELECT);
+ _showDots = ReadShowDots();
+ #endif
+
+ {
+ UString s;
+ if (!FilterDescription.IsEmpty())
+ s = FilterDescription;
+ else if (ShowAllFiles)
+ s = L"*.*";
+ else
+ {
+ FOR_VECTOR (i, Filters)
+ {
+ if (i != 0)
+ s += L' ';
+ 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);
+ // We can go up from root folder to drives list
+ if (NName::IsDrivePath(FilePath))
+ rootSize = 0;
+ else if (IsSuperPath(FilePath))
+ {
+ if (NName::IsDrivePath(&FilePath[kSuperPathPrefixSize]))
+ rootSize = kSuperPathPrefixSize;
+ }
+ _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. */
+ PostMessage(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 (s.Back() == WCHAR_PATH_SEPARATOR)
+ s.DeleteBack();
+ if (s.IsEmpty())
+ return false;
+ if (s.Back() == WCHAR_PATH_SEPARATOR)
+ return false;
+ int pos = s.ReverseFind(WCHAR_PATH_SEPARATOR);
+ 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 == 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(us2fs(pathPrefix + L'*'));
+ 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 = L"..";
+ 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];
+ {
+ FILETIME ft;
+ s[0] = 0;
+ if (FileTimeToLocalFileTime(&fi.MTime, &ft))
+ ConvertFileTimeToString(ft, s,
+ #ifndef UNDER_CE
+ true
+ #else
+ false
+ #endif
+ , false);
+ _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 + fs2us(file.Name) + WCHAR_PATH_SEPARATOR;
+ HRESULT res = Reload(s, L"");
+ 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 wchar_t *errorMessage = NULL;
+ switch (errorCode)
+ {
+ case 0: return false; // cancel or close obn dialog
+ case FNERR_INVALIDFILENAME: errorMessage = L"Invalid File Name"; break;
+ default: errorMessage = L"Open Dialog Error";
+ }
+ if (!errorMessage)
+ return false;
+ {
+ UString s = errorMessage;
+ s += L"\n";
+ 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('/', WCHAR_PATH_SEPARATOR);
+ unsigned start = 0;
+ UString base;
+ if (NName::IsAbsolutePath(path))
+ {
+ if (IsSuperOrDevicePath(path))
+ {
+ result = path;
+ return true;
+ }
+ int pos = GetRootPrefixSize(path);
+ if (pos > 0)
+ start = pos;
+ }
+ else
+ {
+ if (IsSuperOrDevicePath(relBase))
+ {
+ result = path;
+ return true;
+ }
+ 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 += WCHAR_PATH_SEPARATOR;
+ 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;
+}
diff --git a/lzma/CPP/7zip/UI/FileManager/BrowseDialog.h b/lzma/CPP/7zip/UI/FileManager/BrowseDialog.h
new file mode 100644
index 0000000..306d19f
--- /dev/null
+++ b/lzma/CPP/7zip/UI/FileManager/BrowseDialog.h
@@ -0,0 +1,21 @@
+// 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 caes:
+ - 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/lzma/CPP/7zip/UI/FileManager/BrowseDialogRes.h b/lzma/CPP/7zip/UI/FileManager/BrowseDialogRes.h
new file mode 100644
index 0000000..f211b73
--- /dev/null
+++ b/lzma/CPP/7zip/UI/FileManager/BrowseDialogRes.h
@@ -0,0 +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
diff --git a/lzma/CPP/7zip/UI/FileManager/ComboDialog.cpp b/lzma/CPP/7zip/UI/FileManager/ComboDialog.cpp
new file mode 100644
index 0000000..e846c56
--- /dev/null
+++ b/lzma/CPP/7zip/UI/FileManager/ComboDialog.cpp
@@ -0,0 +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();
+}
diff --git a/lzma/CPP/7zip/UI/FileManager/ComboDialog.h b/lzma/CPP/7zip/UI/FileManager/ComboDialog.h
new file mode 100644
index 0000000..6869cff
--- /dev/null
+++ b/lzma/CPP/7zip/UI/FileManager/ComboDialog.h
@@ -0,0 +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
diff --git a/lzma/CPP/7zip/UI/FileManager/ComboDialogRes.h b/lzma/CPP/7zip/UI/FileManager/ComboDialogRes.h
new file mode 100644
index 0000000..98938b6
--- /dev/null
+++ b/lzma/CPP/7zip/UI/FileManager/ComboDialogRes.h
@@ -0,0 +1,4 @@
+#define IDD_COMBO 98
+
+#define IDT_COMBO 100
+#define IDC_COMBO 101
diff --git a/lzma/CPP/7zip/UI/FileManager/DialogSize.h b/lzma/CPP/7zip/UI/FileManager/DialogSize.h
new file mode 100644
index 0000000..bbce159
--- /dev/null
+++ b/lzma/CPP/7zip/UI/FileManager/DialogSize.h
@@ -0,0 +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
diff --git a/lzma/CPP/7zip/UI/FileManager/ExtractCallback.cpp b/lzma/CPP/7zip/UI/FileManager/ExtractCallback.cpp
new file mode 100644
index 0000000..bb14e52
--- /dev/null
+++ b/lzma/CPP/7zip/UI/FileManager/ExtractCallback.cpp
@@ -0,0 +1,898 @@
+// 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 "ExtractCallback.h"
+#include "FormatUtils.h"
+#include "LangUtils.h"
+#include "OverwriteDialog.h"
+#ifndef _NO_CRYPTO
+#include "PasswordDialog.h"
+#endif
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NFind;
+
+CExtractCallbackImp::~CExtractCallbackImp() {}
+
+void CExtractCallbackImp::Init()
+{
+ 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 * /* numFiles */, const UInt64 * /* numBytes */)
+{
+ // if (numFiles != NULL) ProgressDialog->Sync.SetNumFilesTotal(*numFiles);
+ return S_OK;
+}
+
+HRESULT CExtractCallbackImp::Open_SetCompleted(const UInt64 * /* numFiles */, const UInt64 * /* numBytes */)
+{
+ // if (numFiles != NULL) ProgressDialog->Sync.SetNumFilesCur(*numFiles);
+ 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_ClearPasswordWasAskedFlag()
+{
+ 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, bool isFolder, Int32 /* askExtractMode */, const UInt64 * /* position */)
+{
+ _isFolder = isFolder;
+ return SetCurrentFilePath2(name);
+}
+
+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
+
+STDMETHODIMP CExtractCallbackImp::SetOperationResult(Int32 opRes, bool encrypted)
+{
+ switch (opRes)
+ {
+ case NArchive::NExtract::NOperationResult::kOK:
+ break;
+ default:
+ {
+ 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;
+ /*
+ default:
+ messageID = IDS_EXTRACT_MESSAGE_UNKNOWN_ERROR;
+ break;
+ */
+ }
+ if (_needWriteArchivePath)
+ {
+ if (!_currentArchivePath.IsEmpty())
+ AddError_Message(_currentArchivePath);
+ _needWriteArchivePath = false;
+ }
+
+ UString msg;
+ UString msgOld;
+
+ #ifndef _SFX
+ if (id != 0)
+ LangString_OnlyFromLangFile(id, msg);
+ if (messageID != 0 && msg.IsEmpty())
+ LangString_OnlyFromLangFile(messageID, msgOld);
+ #endif
+
+ UString s;
+ if (msg.IsEmpty() && !msgOld.IsEmpty())
+ s = MyFormatNew(msgOld, _currentFilePath);
+ else
+ {
+ if (msg.IsEmpty())
+ LangString(id, msg);
+ if (!msg.IsEmpty())
+ s += msg;
+ else
+ {
+ wchar_t temp[16];
+ ConvertUInt32ToString(opRes, temp);
+ s += L"Error #";
+ s += temp;
+ }
+
+ if (encrypted)
+ {
+ // s += L" : ";
+ // s += LangString(IDS_EXTRACT_MSG_ENCRYPTED);
+ s += L" : ";
+ s += LangString(IDS_EXTRACT_MSG_WRONG_PSW);
+ }
+ s += L" : ";
+ s += _currentFilePath;
+ }
+
+ AddError_Message(s);
+ }
+ }
+
+ #ifndef _SFX
+ if (_isFolder)
+ NumFolders++;
+ else
+ NumFiles++;
+ ProgressDialog->Sync.Set_NumFilesCur(NumFiles);
+ #endif
+
+ return S_OK;
+}
+
+////////////////////////////////////////
+// IExtractCallbackUI
+
+HRESULT CExtractCallbackImp::BeforeOpen(const wchar_t *name)
+{
+ #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);
+
+HRESULT CExtractCallbackImp::OpenResult(const wchar_t *name, HRESULT result, bool encrypted)
+{
+ if (result != S_OK)
+ {
+ UString s;
+ if (result == S_FALSE)
+ s = MyFormatNew(encrypted ? IDS_CANT_OPEN_ENCRYPTED_ARCHIVE : IDS_CANT_OPEN_ARCHIVE, name);
+ else
+ {
+ s = name;
+ s += L": ";
+ s += HResultToMessage(result);
+ }
+ MessageError(s);
+ NumArchiveErrors++;
+ }
+ _currentArchivePath = name;
+ _needWriteArchivePath = true;
+ return S_OK;
+}
+
+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
+};
+
+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 += L" : ";
+ m += LangString(IDS_EXTRACT_MSG_WRONG_PSW);
+ }
+ if (!s.IsEmpty())
+ s += L'\n';
+ s += m;
+ errorFlags &= ~f;
+ }
+ if (errorFlags != 0)
+ {
+ char sz[16];
+ sz[0] = '0';
+ sz[1] = 'x';
+ ConvertUInt32ToHex(errorFlags, sz + 2);
+ if (!s.IsEmpty())
+ s += L'\n';
+ s += GetUnicodeString(AString(sz));
+ }
+ return s;
+}
+
+HRESULT CExtractCallbackImp::SetError(int level, const wchar_t *name,
+ UInt32 errorFlags, const wchar_t *errors,
+ UInt32 warningFlags, const wchar_t *warnings)
+{
+ NumArchiveErrors++;
+
+ if (_needWriteArchivePath)
+ {
+ if (!_currentArchivePath.IsEmpty())
+ AddError_Message(_currentArchivePath);
+ _needWriteArchivePath = false;
+ }
+
+ if (level != 0)
+ {
+ UString s;
+ s += name;
+ s += L": ";
+ MessageError(s);
+ }
+
+ if (errorFlags != 0)
+ MessageError(GetOpenArcErrorMessage(errorFlags));
+
+ if (errors && wcslen(errors) != 0)
+ MessageError(errors);
+
+ if (warningFlags != 0)
+ MessageError((UString)L"Warnings: " + GetOpenArcErrorMessage(warningFlags));
+
+ if (warnings && wcslen(warnings) != 0)
+ MessageError((UString)L"Warnings: " + warnings);
+
+ return S_OK;
+}
+
+HRESULT CExtractCallbackImp::OpenTypeWarning(const wchar_t *name, const wchar_t *okType, const wchar_t *errorType)
+{
+ UString s = L"Warning:\n";
+ s += name;
+ s += L"\n";
+ if (wcscmp(okType, errorType) == 0)
+ {
+ s += L"The archive is open with offset";
+ }
+ else
+ {
+ s += L"Can not open the file as [";
+ s += errorType;
+ s += L"] archive\n";
+ s += L"The file is open as [";
+ s += okType;
+ s += L"] archive";
+ }
+ MessageError(s);
+ NumArchiveErrors++;
+ return S_OK;
+}
+
+HRESULT CExtractCallbackImp::ThereAreNoFiles()
+{
+ return S_OK;
+}
+
+HRESULT CExtractCallbackImp::ExtractResult(HRESULT result)
+{
+ if (result == S_OK)
+ return result;
+ NumArchiveErrors++;
+ if (result == E_ABORT || result == ERROR_DISK_FULL)
+ return result;
+ 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));
+ return E_FAIL;
+ }
+
+ switch (OverwriteMode)
+ {
+ case NExtract::NOverwriteMode::kSkip:
+ return S_OK;
+ case NExtract::NOverwriteMode::kAsk:
+ {
+ Int32 overwiteResult;
+ UString destPathSpec = destPath;
+ int slashPos = destPathSpec.ReverseFind(L'/');
+ #ifdef _WIN32
+ int slash1Pos = destPathSpec.ReverseFind(L'\\');
+ slashPos = MyMax(slashPos, slash1Pos);
+ #endif
+ destPathSpec.DeleteFrom(slashPos + 1);
+ destPathSpec += fs2us(destFileInfo.Name);
+
+ RINOK(AskOverwrite(
+ destPathSpec,
+ &destFileInfo.MTime, &destFileInfo.Size,
+ srcPath,
+ srcTime, srcSize,
+ &overwiteResult));
+
+ switch (overwiteResult)
+ {
+ 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 (!NDir::DeleteFileAlways(destPathSys))
+ {
+ 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, bool 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(GetCorrectFsPath(file.Name));
+ if (!_fileIsOpen)
+ {
+ if (!_outFileStreamSpec->Create(path, false))
+ {
+ _outFileStream.Release();
+ return E_FAIL;
+ // MessageBoxMyError(UString(L"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(path, file.Attrib);
+ }
+ return S_OK;
+}
+
+#endif
diff --git a/lzma/CPP/7zip/UI/FileManager/ExtractCallback.h b/lzma/CPP/7zip/UI/FileManager/ExtractCallback.h
new file mode 100644
index 0000000..fea83d6
--- /dev/null
+++ b/lzma/CPP/7zip/UI/FileManager/ExtractCallback.h
@@ -0,0 +1,330 @@
+// 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;
+
+ CGrowBuf(const CGrowBuf &buffer);
+ void operator=(const CGrowBuf &buffer);
+
+public:
+ bool ReAlloc_KeepData(size_t newSize, size_t keepSize)
+ {
+ void *buf = MyAlloc(newSize);
+ if (!buf)
+ return false;
+ 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,
+ #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);
+public:
+ MY_QUERYINTERFACE_BEGIN2(IFolderArchiveExtractCallback)
+ #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(;)
+
+ // IFolderArchiveExtractCallback
+ // STDMETHOD(SetTotalFiles)(UInt64 total);
+ // STDMETHOD(SetCompletedFiles)(const UInt64 *value);
+ STDMETHOD(AskOverwrite)(
+ const wchar_t *existName, const FILETIME *existTime, const UInt64 *existSize,
+ const wchar_t *newName, const FILETIME *newTime, const UInt64 *newSize,
+ Int32 *answer);
+ STDMETHOD (PrepareOperation)(const wchar_t *name, bool isFolder, Int32 askExtractMode, const UInt64 *position);
+
+ STDMETHOD(MessageError)(const wchar_t *message);
+ STDMETHOD(SetOperationResult)(Int32 operationResult, bool encrypted);
+
+ // IExtractCallbackUI
+
+ HRESULT BeforeOpen(const wchar_t *name);
+ HRESULT OpenResult(const wchar_t *name, HRESULT result, bool encrypted);
+ HRESULT SetError(int level, const wchar_t *name,
+ UInt32 errorFlags, const wchar_t *errors,
+ UInt32 warningFlags, const wchar_t *warnings);
+ HRESULT ThereAreNoFiles();
+ HRESULT ExtractResult(HRESULT result);
+ HRESULT OpenTypeWarning(const wchar_t *name, const wchar_t *okType, const wchar_t *errorType);
+
+ #ifndef _NO_CRYPTO
+ HRESULT SetPassword(const UString &password);
+ #endif
+
+ #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
+
+ CExtractCallbackImp():
+ #ifndef _NO_CRYPTO
+ PasswordIsDefined(false),
+ PasswordWasAsked(false),
+ #endif
+ OverwriteMode(NExtract::NOverwriteMode::kAsk),
+ StreamMode(false),
+ ProcessAltStreams(true)
+ #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
diff --git a/lzma/CPP/7zip/UI/FileManager/FormatUtils.cpp b/lzma/CPP/7zip/UI/FileManager/FormatUtils.cpp
new file mode 100644
index 0000000..4f7ef74
--- /dev/null
+++ b/lzma/CPP/7zip/UI/FileManager/FormatUtils.cpp
@@ -0,0 +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);
+}
diff --git a/lzma/CPP/7zip/UI/FileManager/FormatUtils.h b/lzma/CPP/7zip/UI/FileManager/FormatUtils.h
new file mode 100644
index 0000000..f221cd2
--- /dev/null
+++ b/lzma/CPP/7zip/UI/FileManager/FormatUtils.h
@@ -0,0 +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
diff --git a/lzma/CPP/7zip/UI/FileManager/LangUtils.h b/lzma/CPP/7zip/UI/FileManager/LangUtils.h
new file mode 100644
index 0000000..d1d1477
--- /dev/null
+++ b/lzma/CPP/7zip/UI/FileManager/LangUtils.h
@@ -0,0 +1,38 @@
+// 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 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); }
+
+#endif
+
+#endif
diff --git a/lzma/CPP/7zip/UI/FileManager/MyWindowsNew.h b/lzma/CPP/7zip/UI/FileManager/MyWindowsNew.h
new file mode 100644
index 0000000..c0fe843
--- /dev/null
+++ b/lzma/CPP/7zip/UI/FileManager/MyWindowsNew.h
@@ -0,0 +1,76 @@
+// 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
diff --git a/lzma/CPP/7zip/UI/FileManager/OverwriteDialog.cpp b/lzma/CPP/7zip/UI/FileManager/OverwriteDialog.cpp
new file mode 100644
index 0000000..d945945
--- /dev/null
+++ b/lzma/CPP/7zip/UI/FileManager/OverwriteDialog.cpp
@@ -0,0 +1,119 @@
+// 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" ... ");
+ }
+}
+
+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(WCHAR_PATH_SEPARATOR);
+ UString s1 = fileName.Left(slashPos + 1);
+ UString s2 = fileName.Ptr(slashPos + 1);
+
+ ReduceString(s1);
+ ReduceString(s2);
+
+ UString s = s1;
+ s += L'\n';
+ s += s2;
+ s += L'\n';
+ s += sizeString;
+ s += L'\n';
+
+ if (fileInfo.TimeIsDefined)
+ {
+ FILETIME localFileTime;
+ if (!FileTimeToLocalFileTime(&fileInfo.Time, &localFileTime))
+ throw 4190402;
+ s += LangString(IDS_PROP_MTIME);
+ s += L": ";
+ wchar_t t[32];
+ ConvertFileTimeToString(localFileTime, 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);
+}
diff --git a/lzma/CPP/7zip/UI/FileManager/OverwriteDialog.h b/lzma/CPP/7zip/UI/FileManager/OverwriteDialog.h
new file mode 100644
index 0000000..4564a47
--- /dev/null
+++ b/lzma/CPP/7zip/UI/FileManager/OverwriteDialog.h
@@ -0,0 +1,69 @@
+// 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
diff --git a/lzma/CPP/7zip/UI/FileManager/OverwriteDialog.rc b/lzma/CPP/7zip/UI/FileManager/OverwriteDialog.rc
new file mode 100644
index 0000000..80f48b0
--- /dev/null
+++ b/lzma/CPP/7zip/UI/FileManager/OverwriteDialog.rc
@@ -0,0 +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
diff --git a/lzma/CPP/7zip/UI/FileManager/OverwriteDialogRes.h b/lzma/CPP/7zip/UI/FileManager/OverwriteDialogRes.h
new file mode 100644
index 0000000..28bc0d0
--- /dev/null
+++ b/lzma/CPP/7zip/UI/FileManager/OverwriteDialogRes.h
@@ -0,0 +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
diff --git a/lzma/CPP/7zip/UI/FileManager/PasswordDialog.cpp b/lzma/CPP/7zip/UI/FileManager/PasswordDialog.cpp
new file mode 100644
index 0000000..95e83fe
--- /dev/null
+++ b/lzma/CPP/7zip/UI/FileManager/PasswordDialog.cpp
@@ -0,0 +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();
+}
diff --git a/lzma/CPP/7zip/UI/FileManager/PasswordDialog.h b/lzma/CPP/7zip/UI/FileManager/PasswordDialog.h
new file mode 100644
index 0000000..b756a1c
--- /dev/null
+++ b/lzma/CPP/7zip/UI/FileManager/PasswordDialog.h
@@ -0,0 +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
diff --git a/lzma/CPP/7zip/UI/FileManager/PasswordDialog.rc b/lzma/CPP/7zip/UI/FileManager/PasswordDialog.rc
new file mode 100644
index 0000000..51dd5bc
--- /dev/null
+++ b/lzma/CPP/7zip/UI/FileManager/PasswordDialog.rc
@@ -0,0 +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
diff --git a/lzma/CPP/7zip/UI/FileManager/PasswordDialogRes.h b/lzma/CPP/7zip/UI/FileManager/PasswordDialogRes.h
new file mode 100644
index 0000000..f9300d6
--- /dev/null
+++ b/lzma/CPP/7zip/UI/FileManager/PasswordDialogRes.h
@@ -0,0 +1,5 @@
+#define IDD_PASSWORD 3800
+#define IDT_PASSWORD_ENTER 3801
+#define IDX_PASSWORD_SHOW 3803
+
+#define IDE_PASSWORD_PASSWORD 120
diff --git a/lzma/CPP/7zip/UI/FileManager/ProgressDialog.cpp b/lzma/CPP/7zip/UI/FileManager/ProgressDialog.cpp
new file mode 100644
index 0000000..798b1a4
--- /dev/null
+++ b/lzma/CPP/7zip/UI/FileManager/ProgressDialog.cpp
@@ -0,0 +1,196 @@
+// 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 += L"% ";
+ 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)
+ {
+ PostMessage(kCloseMessage);
+ _needClose = false;
+ }
+}
+
+bool CProgressDialog::OnExternalCloseMessage()
+{
+ End(0);
+ return true;
+}
diff --git a/lzma/CPP/7zip/UI/FileManager/ProgressDialog.h b/lzma/CPP/7zip/UI/FileManager/ProgressDialog.h
new file mode 100644
index 0000000..9c6702f
--- /dev/null
+++ b/lzma/CPP/7zip/UI/FileManager/ProgressDialog.h
@@ -0,0 +1,170 @@
+// 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)
+ PostMessage(kCloseMessage);
+ else
+ _needClose = true;
+ };
+};
+
+
+class CProgressCloser
+{
+ CProgressDialog *_p;
+public:
+ CProgressCloser(CProgressDialog &p) : _p(&p) {}
+ ~CProgressCloser() { _p->ProcessWasFinished(); }
+};
+
+#endif
diff --git a/lzma/CPP/7zip/UI/FileManager/ProgressDialog.rc b/lzma/CPP/7zip/UI/FileManager/ProgressDialog.rc
new file mode 100644
index 0000000..5af370f
--- /dev/null
+++ b/lzma/CPP/7zip/UI/FileManager/ProgressDialog.rc
@@ -0,0 +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
diff --git a/lzma/CPP/7zip/UI/FileManager/ProgressDialog2.cpp b/lzma/CPP/7zip/UI/FileManager/ProgressDialog2.cpp
new file mode 100644
index 0000000..aea37a4
--- /dev/null
+++ b/lzma/CPP/7zip/UI/FileManager/ProgressDialog2.cpp
@@ -0,0 +1,1293 @@
+// ProgressDialog2.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/IntToString.h"
+#include "../../../Common/StringConvert.h"
+
+#include "../../../Windows/Control/Static.h"
+#include "../../../Windows/ErrorMsg.h"
+
+#include "ProgressDialog2.h"
+#include "DialogSize.h"
+
+#include "ProgressDialog2Res.h"
+
+#include "../GUI/ExtractRes.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
+ 100
+ #endif
+ ;
+
+static const UINT kCreateDelay =
+ #ifdef UNDER_CE
+ 2500
+ #else
+ 500
+ #endif
+ ;
+
+static const DWORD kPauseSleepTime = 100;
+
+#include "LangUtils.h"
+
+#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 UString &fileName, bool isDir)
+{
+ {
+ CRITICAL_LOCK
+ _totalFiles = numFiles;
+ _totalBytes = totalSize;
+ _filePath = fileName;
+ _isDir = isDir;
+ // _completedBytes = 0;
+ CHECK_STOP
+ }
+ return CheckStop();
+}
+
+void CProgressSync::Set_NumFilesTotal(UInt64 val)
+{
+ CRITICAL_LOCK
+ _totalFiles = val;
+}
+
+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;
+}
+
+void CProgressSync::Set_FilePath(const UString &path, bool isDir)
+{
+ CRITICAL_LOCK
+ _filePath = path;
+ _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 += L'\n';
+ 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 = L"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();
+
+ {
+ UInt64 progressTotal = bytesProgressMode ? total : totalFiles;
+ 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 (completed != 0)
+ {
+ if (IS_UNDEFINED_VAL(total))
+ {
+ if (IS_DEFINED_VAL(_prevRemainingSec))
+ {
+ INIT_AS_UNDEFINED(_prevRemainingSec);
+ SetItemText(IDT_PROGRESS_REMAINING_VAL, L"");
+ }
+ }
+ else
+ {
+ UInt64 remainingTime = 0;
+ if (completed < total)
+ remainingTime = MyMultAndDiv(_elapsedTime, total - completed, completed);
+ 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 = (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(total))
+ {
+ percent = completed * 100;
+ if (total != 0)
+ percent /= total;
+ }
+ }
+ if (percent != _prevPercentValue)
+ {
+ _prevPercentValue = percent;
+ needSetTitle = true;
+ }
+ }
+
+ {
+ wchar_t s[64];
+ ConvertUInt64ToString(completedFiles, s);
+ if (IS_DEFINED_VAL(totalFiles))
+ {
+ wcscat(s, L" / ");
+ ConvertUInt64ToString(totalFiles, s + wcslen(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);
+ wcscat(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(WCHAR_PATH_SEPARATOR);
+ if (slashPos >= 0)
+ {
+ s1.SetFrom(_filePath, slashPos + 1);
+ s2 = _filePath.Ptr(slashPos + 1);
+ }
+ else
+ s2 = _filePath;
+ }
+ ReduceString(s1, _numReduceSymbols);
+ ReduceString(s2, _numReduceSymbols);
+ s1 += L'\n';
+ 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 res = WaitForMultipleObjects(ARRAY_SIZE(h), h, FALSE, kCreateDelay);
+ if (res == 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);
+
+ 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 = L"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 = L"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 += L' ';
+ }
+ if (IS_DEFINED_VAL(_prevPercentValue))
+ {
+ wchar_t temp[32];
+ ConvertUInt64ToString(_prevPercentValue, temp);
+ s += temp;
+ s += L'%';
+ }
+ if (!_foreground)
+ {
+ s += L' ';
+ s += _backgrounded_String;
+ }
+
+ s += L' ';
+ #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 += L' ';
+ 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)
+ {
+ PostMessage(kCloseMessage);
+ _needClose = false;
+ }
+}
+
+void CProgressDialog::ProcessWasFinished()
+{
+ // Set Window title here.
+ if (!WaitMode)
+ WaitCreating();
+
+ if (_wasCreated)
+ PostMessage(kCloseMessage);
+ else
+ _needClose = true;
+}
+
+
+HRESULT CProgressThreadVirt::Create(const UString &title, HWND parentWindow)
+{
+ NWindows::CThread thread;
+ RINOK(thread.Create(MyThreadFunction, this));
+ ProgressDialog.Create(title, thread, parentWindow);
+ return S_OK;
+}
+
+static void AddMessageToString(UString &dest, const UString &src)
+{
+ if (!src.IsEmpty())
+ {
+ if (!dest.IsEmpty())
+ dest += L'\n';
+ dest += src;
+ }
+}
+
+void CProgressThreadVirt::Process()
+{
+ CProgressCloser closer(ProgressDialog);
+ 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)
+ {
+ wchar_t s[16];
+ ConvertUInt32ToString(v, s);
+ m = L"Error #";
+ m += s;
+ }
+ catch(...) { m = L"Error"; }
+ if (Result != E_ABORT)
+ {
+ if (m.IsEmpty() && Result != S_OK)
+ m = HResultToMessage(Result);
+ }
+ AddMessageToString(m, FinalMessage.ErrorMessage.Message);
+ AddMessageToString(m, fs2us(ErrorPath1));
+ AddMessageToString(m, fs2us(ErrorPath2));
+
+ CProgressSync &sync = ProgressDialog.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/lzma/CPP/7zip/UI/FileManager/ProgressDialog2.h b/lzma/CPP/7zip/UI/FileManager/ProgressDialog2.h
new file mode 100644
index 0000000..35e0f17
--- /dev/null
+++ b/lzma/CPP/7zip/UI/FileManager/ProgressDialog2.h
@@ -0,0 +1,314 @@
+// 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 UString &fileName, bool isDir = false);
+
+ void 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);
+ void Set_FilePath(const UString &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);
+
+ void ProcessWasFinished();
+};
+
+
+class CProgressCloser
+{
+ CProgressDialog *_p;
+public:
+ CProgressCloser(CProgressDialog &p) : _p(&p) {}
+ ~CProgressCloser() { _p->ProcessWasFinished(); }
+};
+
+class CProgressThreadVirt
+{
+ FString ErrorPath1;
+ FString ErrorPath2;
+protected:
+ CProgressFinalMessage FinalMessage;
+
+ // error if any of HRESULT, ErrorMessage, ErrorPath
+ virtual HRESULT ProcessVirt() = 0;
+ void Process();
+public:
+ HRESULT Result;
+ bool ThreadFinishedOK; // if there is no fatal exception
+ CProgressDialog ProgressDialog;
+
+ static THREAD_FUNC_DECL MyThreadFunction(void *param)
+ {
+ CProgressThreadVirt *p = (CProgressThreadVirt *)param;
+ try
+ {
+ p->Process();
+ p->ThreadFinishedOK = true;
+ }
+ catch (...) { p->Result = E_FAIL; }
+ return 0;
+ }
+
+ void SetErrorPath1(const FString &path) { ErrorPath1 = path; }
+ void SetErrorPath2(const FString &path) { ErrorPath2 = 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);
+
+#endif
diff --git a/lzma/CPP/7zip/UI/FileManager/ProgressDialog2.rc b/lzma/CPP/7zip/UI/FileManager/ProgressDialog2.rc
new file mode 100644
index 0000000..535a008
--- /dev/null
+++ b/lzma/CPP/7zip/UI/FileManager/ProgressDialog2.rc
@@ -0,0 +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"
+}
diff --git a/lzma/CPP/7zip/UI/FileManager/ProgressDialog2Res.h b/lzma/CPP/7zip/UI/FileManager/ProgressDialog2Res.h
new file mode 100644
index 0000000..54f02f0
--- /dev/null
+++ b/lzma/CPP/7zip/UI/FileManager/ProgressDialog2Res.h
@@ -0,0 +1,48 @@
+#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
diff --git a/lzma/CPP/7zip/UI/FileManager/ProgressDialog2a.rc b/lzma/CPP/7zip/UI/FileManager/ProgressDialog2a.rc
new file mode 100644
index 0000000..f1daec7
--- /dev/null
+++ b/lzma/CPP/7zip/UI/FileManager/ProgressDialog2a.rc
@@ -0,0 +1,80 @@
+#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
+}
diff --git a/lzma/CPP/7zip/UI/FileManager/ProgressDialogRes.h b/lzma/CPP/7zip/UI/FileManager/ProgressDialogRes.h
new file mode 100644
index 0000000..a281418
--- /dev/null
+++ b/lzma/CPP/7zip/UI/FileManager/ProgressDialogRes.h
@@ -0,0 +1,3 @@
+#define IDD_PROGRESS 97
+
+#define IDC_PROGRESS1 100
diff --git a/lzma/CPP/7zip/UI/FileManager/PropertyNameRes.h b/lzma/CPP/7zip/UI/FileManager/PropertyNameRes.h
new file mode 100644
index 0000000..67c9b6e
--- /dev/null
+++ b/lzma/CPP/7zip/UI/FileManager/PropertyNameRes.h
@@ -0,0 +1,92 @@
+
+
+#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
diff --git a/lzma/CPP/7zip/UI/FileManager/SysIconUtils.cpp b/lzma/CPP/7zip/UI/FileManager/SysIconUtils.cpp
new file mode 100644
index 0000000..4cc99ec
--- /dev/null
+++ b/lzma/CPP/7zip/UI/FileManager/SysIconUtils.cpp
@@ -0,0 +1,253 @@
+// SysIconUtils.cpp
+
+#include "StdAfx.h"
+
+#ifndef _UNICODE
+#include "../../../Common/StringConvert.h"
+#endif
+
+#include "../../../Windows/FileDir.h"
+
+#include "SysIconUtils.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);
+}
+*/
\ No newline at end of file
diff --git a/lzma/CPP/7zip/UI/FileManager/SysIconUtils.h b/lzma/CPP/7zip/UI/FileManager/SysIconUtils.h
new file mode 100644
index 0000000..5655c76
--- /dev/null
+++ b/lzma/CPP/7zip/UI/FileManager/SysIconUtils.h
@@ -0,0 +1,58 @@
+// SysIconUtils.h
+
+#ifndef __SYS_ICON_UTILS_H
+#define __SYS_ICON_UTILS_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
diff --git a/lzma/CPP/7zip/UI/FileManager/resource.h b/lzma/CPP/7zip/UI/FileManager/resource.h
new file mode 100644
index 0000000..bffdc97
--- /dev/null
+++ b/lzma/CPP/7zip/UI/FileManager/resource.h
@@ -0,0 +1,171 @@
+#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_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 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/lzma/CPP/7zip/UI/FileManager/resourceGui.h b/lzma/CPP/7zip/UI/FileManager/resourceGui.h
new file mode 100644
index 0000000..025f316
--- /dev/null
+++ b/lzma/CPP/7zip/UI/FileManager/resourceGui.h
@@ -0,0 +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
diff --git a/lzma/CPP/7zip/UI/GUI/Extract.rc b/lzma/CPP/7zip/UI/GUI/Extract.rc
new file mode 100644
index 0000000..5fb2b3a
--- /dev/null
+++ b/lzma/CPP/7zip/UI/GUI/Extract.rc
@@ -0,0 +1,52 @@
+#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_PROGRESS_EXTRACTING "Extracting"
+
+ 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 "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_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/lzma/CPP/7zip/UI/GUI/ExtractDialog.cpp b/lzma/CPP/7zip/UI/GUI/ExtractDialog.cpp
new file mode 100644
index 0000000..bb0a655
--- /dev/null
+++ b/lzma/CPP/7zip/UI/GUI/ExtractDialog.cpp
@@ -0,0 +1,418 @@
+// 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 += L" : ";
+ 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.IsEqualToNoCase(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
+static LPCWSTR kHelpTopic = L"fm/plugins/7-zip/extract.htm";
+void CExtractDialog::OnHelp()
+{
+ ShowHelpWindow(NULL, kHelpTopic);
+ CModalDialog::OnHelp();
+}
+#endif
diff --git a/lzma/CPP/7zip/UI/GUI/ExtractDialog.h b/lzma/CPP/7zip/UI/GUI/ExtractDialog.h
new file mode 100644
index 0000000..308c786
--- /dev/null
+++ b/lzma/CPP/7zip/UI/GUI/ExtractDialog.h
@@ -0,0 +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
diff --git a/lzma/CPP/7zip/UI/GUI/ExtractDialog.rc b/lzma/CPP/7zip/UI/GUI/ExtractDialog.rc
new file mode 100644
index 0000000..f5d6528
--- /dev/null
+++ b/lzma/CPP/7zip/UI/GUI/ExtractDialog.rc
@@ -0,0 +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
diff --git a/lzma/CPP/7zip/UI/GUI/ExtractDialogRes.h b/lzma/CPP/7zip/UI/GUI/ExtractDialogRes.h
new file mode 100644
index 0000000..61737e4
--- /dev/null
+++ b/lzma/CPP/7zip/UI/GUI/ExtractDialogRes.h
@@ -0,0 +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
diff --git a/lzma/CPP/7zip/UI/GUI/ExtractGUI.cpp b/lzma/CPP/7zip/UI/GUI/ExtractGUI.cpp
new file mode 100644
index 0000000..ff78648
--- /dev/null
+++ b/lzma/CPP/7zip/UI/GUI/ExtractGUI.cpp
@@ -0,0 +1,270 @@
+// 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 *kIncorrectOutDir = L"Incorrect output directory path";
+
+#ifndef _SFX
+
+static void AddValuePair(UString &s, UINT resourceID, UInt64 value, bool addColon = true)
+{
+ wchar_t sz[32];
+ s += LangString(resourceID);
+ if (addColon)
+ s += L':';
+ s += L' ';
+ ConvertUInt64ToString(value, sz);
+ s += sz;
+ s += L'\n';
+}
+
+static void AddSizePair(UString &s, UINT resourceID, UInt64 value)
+{
+ wchar_t sz[32];
+ s += LangString(resourceID);
+ s += L": ";
+ ConvertUInt64ToString(value, sz);
+ s += MyFormatNew(IDS_FILE_SIZE, sz);
+ // s += sz;
+ if (value >= (1 << 20))
+ {
+ ConvertUInt64ToString(value >> 20, sz);
+ s += L" (";
+ s += sz;
+ s += L" MB)";
+ }
+ s += L'\n';
+}
+
+#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;
+ #endif
+ CMyComPtr<IExtractCallbackUI> ExtractCallback;
+ UString Title;
+};
+
+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 && Options->TestMode && ExtractCallbackSpec->IsOK())
+ {
+ UString s;
+
+ AddValuePair(s, IDS_ARCHIVES_COLON, Stat.NumArchives, false);
+ AddSizePair(s, IDS_PROP_PACKED_SIZE, Stat.PackSize);
+
+ if (!HashBundle)
+ {
+ 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 += L'\n';
+ AddValuePair(s, IDS_PROP_NUM_ALT_STREAMS, Stat.NumAltStreams);
+ AddSizePair(s, IDS_PROP_ALT_STREAMS_SIZE, Stat.AltStreams_UnpackSize);
+ }
+ }
+
+ if (HashBundle)
+ {
+ s += L'\n';
+ AddHashBundleRes(s, *HashBundle, UString());
+ }
+
+ s += L'\n';
+ s += LangString(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);
+ MyMessageBox(s2 + UString(L'\n') + s);
+ return E_FAIL;
+ }
+ */
+ }
+
+ UString title = LangString(options.TestMode ? IDS_PROGRESS_TESTING : IDS_PROGRESS_EXTRACTING);
+
+ extracter.Title = title;
+ extracter.ExtractCallbackSpec = extractCallback;
+ extracter.ExtractCallbackSpec->ProgressDialog = &extracter.ProgressDialog;
+ extracter.ExtractCallback = extractCallback;
+ extracter.ExtractCallbackSpec->Init();
+
+ extracter.ProgressDialog.CompressingMode = false;
+
+ extracter.ArchivePaths = &archivePaths;
+ extracter.ArchivePathsFull = &archivePathsFull;
+ extracter.WildcardCensor = &wildcardCensor;
+ extracter.Options = &options;
+ #ifndef _SFX
+ extracter.HashBundle = hb;
+ #endif
+
+ extracter.ProgressDialog.IconID = IDI_ICON;
+
+ RINOK(extracter.Create(title, hwndParent));
+ messageWasDisplayed = extracter.ThreadFinishedOK &
+ extracter.ProgressDialog.MessagesDisplayed;
+ return extracter.Result;
+}
diff --git a/lzma/CPP/7zip/UI/GUI/ExtractGUI.h b/lzma/CPP/7zip/UI/GUI/ExtractGUI.h
new file mode 100644
index 0000000..466e524
--- /dev/null
+++ b/lzma/CPP/7zip/UI/GUI/ExtractGUI.h
@@ -0,0 +1,38 @@
+// 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
diff --git a/lzma/CPP/7zip/UI/GUI/ExtractRes.h b/lzma/CPP/7zip/UI/GUI/ExtractRes.h
new file mode 100644
index 0000000..407ad19
--- /dev/null
+++ b/lzma/CPP/7zip/UI/GUI/ExtractRes.h
@@ -0,0 +1,44 @@
+#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_PROGRESS_EXTRACTING 3300
+
+#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 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_OPEN_MSG_UNAVAILABLE_START 3763
+#define IDS_OPEN_MSG_UNCONFIRMED_START 3764
+#define IDS_OPEN_MSG_UNSUPPORTED_FEATURE 3768
diff --git a/lzma/CPP/7zip/UI/GUI/HashGUI.h b/lzma/CPP/7zip/UI/GUI/HashGUI.h
new file mode 100644
index 0000000..4fb0666
--- /dev/null
+++ b/lzma/CPP/7zip/UI/GUI/HashGUI.h
@@ -0,0 +1,16 @@
+// HashGUI.h
+
+#ifndef __HASH_GUI_H
+#define __HASH_GUI_H
+
+#include "../Common/HashCalc.h"
+
+HRESULT HashCalcGUI(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ const NWildcard::CCensor &censor,
+ const CHashOptions &options,
+ bool &messageWasDisplayed);
+
+void AddHashBundleRes(UString &s, const CHashBundle &hb, const UString &firstFileName);
+
+#endif
diff --git a/lzma/CPP/7zip/UI/GUI/resource2.h b/lzma/CPP/7zip/UI/GUI/resource2.h
new file mode 100644
index 0000000..152e71f
--- /dev/null
+++ b/lzma/CPP/7zip/UI/GUI/resource2.h
@@ -0,0 +1,2 @@
+#define IDS_PROGRESS_COMPRESSING 3301
+#define IDS_ARCHIVES_COLON 3907
diff --git a/lzma/CPP/Build.mak b/lzma/CPP/Build.mak
new file mode 100644
index 0000000..70c9c48
--- /dev/null
+++ b/lzma/CPP/Build.mak
@@ -0,0 +1,119 @@
+LIBS = $(LIBS) oleaut32.lib ole32.lib
+
+!IFNDEF MY_NO_UNICODE
+CFLAGS = $(CFLAGS) -DUNICODE -D_UNICODE
+!ENDIF
+
+# CFLAGS = $(CFLAGS) -FAsc -Fa$O/Asm/
+
+!IFNDEF O
+!IFDEF CPU
+O=$(CPU)
+!ELSE
+O=O
+!ENDIF
+!ENDIF
+
+!IF "$(CPU)" == "AMD64"
+MY_ML = ml64 -Dx64
+!ELSEIF "$(CPU)" == "ARM"
+MY_ML = armasm
+!ELSE
+MY_ML = ml
+!ENDIF
+
+
+!IFDEF UNDER_CE
+RFLAGS = $(RFLAGS) -dUNDER_CE
+!IFDEF MY_CONSOLE
+LFLAGS = $(LFLAGS) /ENTRY:mainACRTStartup
+!ENDIF
+!ELSE
+!IFNDEF NEW_COMPILER
+LFLAGS = $(LFLAGS) -OPT:NOWIN98
+!ENDIF
+CFLAGS = $(CFLAGS) -Gr
+LIBS = $(LIBS) user32.lib advapi32.lib shell32.lib
+!ENDIF
+
+!IF "$(CPU)" == "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-
+
+!IFDEF MY_STATIC_LINK
+!IFNDEF MY_SINGLE_THREAD
+CFLAGS = $(CFLAGS) -MT
+!ENDIF
+!ELSE
+CFLAGS = $(CFLAGS) -MD
+!ENDIF
+
+!IFDEF NEW_COMPILER
+CFLAGS = $(CFLAGS) -GS- -Zc:forScope
+!IFNDEF UNDER_CE
+CFLAGS = $(CFLAGS) -MP2
+!ENDIF
+!ELSE
+CFLAGS = $(CFLAGS)
+!ENDIF
+
+CFLAGS_O1 = $(CFLAGS) -O1
+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)
+!ENDIF
+
+MY_SUB_SYS_VER=6.0
+!IFDEF MY_CONSOLE
+# LFLAGS = $(LFLAGS) /SUBSYSTEM:console,$(MY_SUB_SYS_VER)
+!ELSE
+# LFLAGS = $(LFLAGS) /SUBSYSTEM:windows,$(MY_SUB_SYS_VER)
+!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) $<
+
+CCOMPL_PCH = $(CC) $(CFLAGS_O2) -Yc"Precomp.h" -Fp$O/a.pch $**
+CCOMPL_USE = $(CC) $(CFLAGS_O2) -Yu"Precomp.h" -Fp$O/a.pch $**
+CCOMPL = $(CC) $(CFLAGS_O2) $**
+CCOMPLB = $(CC) $(CFLAGS_O2) $<
+
+
+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)
diff --git a/lzma/CPP/Common/AutoPtr.h b/lzma/CPP/Common/AutoPtr.h
new file mode 100644
index 0000000..e53fb7f
--- /dev/null
+++ b/lzma/CPP/Common/AutoPtr.h
@@ -0,0 +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
diff --git a/lzma/CPP/Common/CRC.cpp b/lzma/CPP/Common/CRC.cpp
new file mode 100644
index 0000000..6ac52c4
--- /dev/null
+++ b/lzma/CPP/Common/CRC.cpp
@@ -0,0 +1,7 @@
+// Common/CRC.cpp
+
+#include "StdAfx.h"
+
+#include "../../C/7zCrc.h"
+
+struct CCRCTableInit { CCRCTableInit() { CrcGenerateTable(); } } g_CRCTableInit;
diff --git a/lzma/CPP/Common/C_FileIO.cpp b/lzma/CPP/Common/C_FileIO.cpp
new file mode 100644
index 0000000..d68a427
--- /dev/null
+++ b/lzma/CPP/Common/C_FileIO.cpp
@@ -0,0 +1,92 @@
+// 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);
+}
+
+}}}
diff --git a/lzma/CPP/Common/C_FileIO.h b/lzma/CPP/Common/C_FileIO.h
new file mode 100644
index 0000000..4c400b4
--- /dev/null
+++ b/lzma/CPP/Common/C_FileIO.h
@@ -0,0 +1,53 @@
+// 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
diff --git a/lzma/CPP/Common/ComTry.h b/lzma/CPP/Common/ComTry.h
new file mode 100644
index 0000000..b2b3029
--- /dev/null
+++ b/lzma/CPP/Common/ComTry.h
@@ -0,0 +1,17 @@
+// 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; }
+
+ // catch(const CNewException &) { return E_OUTOFMEMORY; }
+ // catch(const CSystemException &e) { return e.ErrorCode; }
+ // catch(...) { return E_FAIL; }
+
+#endif
diff --git a/lzma/CPP/Common/CommandLineParser.cpp b/lzma/CPP/Common/CommandLineParser.cpp
new file mode 100644
index 0000000..01269c8
--- /dev/null
+++ b/lzma/CPP/Common/CommandLineParser.cpp
@@ -0,0 +1,198 @@
+// CommandLineParser.cpp
+
+#include "StdAfx.h"
+
+#include "CommandLineParser.h"
+
+static bool IsString1PrefixedByString2_NoCase(const wchar_t *u, const char *a)
+{
+ for (;;)
+ {
+ char c = *a;
+ if (c == 0)
+ return true;
+ if (MyCharLower_Ascii(c) != MyCharLower_Ascii(*u))
+ return false;
+ a++;
+ u++;
+ }
+}
+
+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 *kStopSwitchParsing = "--";
+
+static bool inline IsItSwitchChar(wchar_t c)
+{
+ return (c == '-');
+}
+
+CParser::CParser(unsigned numSwitches):
+ _numSwitches(numSwitches),
+ _switches(0)
+{
+ _switches = new CSwitchResult[numSwitches];
+}
+
+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)
+{
+ 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 *key = switchForms[i].Key;
+ unsigned switchLen = MyStringLen(key);
+ if ((int)switchLen <= maxLen || pos + switchLen > s.Len())
+ continue;
+ if (IsString1PrefixedByString2_NoCase((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 != 0)
+ {
+ sw.WithMinus = (s[pos] == '-');
+ if (sw.WithMinus)
+ pos++;
+ }
+ break;
+
+ case NSwitchType::kChar:
+ if (rem != 0)
+ {
+ wchar_t c = s[pos];
+ if (c <= 0x7F)
+ {
+ sw.PostCharIndex = FindCharPosInString(form.PostCharSet, (char)c);
+ if (sw.PostCharIndex >= 0)
+ pos++;
+ }
+ }
+ break;
+
+ case NSwitchType::kString:
+ sw.PostStrings.Add((const wchar_t *)s + pos);
+ return true;
+ }
+ if (pos != s.Len())
+ {
+ ErrorMessage = "Too long switch:";
+ return false;
+ }
+ return true;
+}
+
+bool CParser::ParseStrings(const CSwitchForm *switchForms, const UStringVector &commandStrings)
+{
+ ErrorLine.Empty();
+ bool stopSwitch = false;
+ FOR_VECTOR (i, commandStrings)
+ {
+ const UString &s = commandStrings[i];
+ if (!stopSwitch)
+ {
+ if (s.IsEqualTo(kStopSwitchParsing))
+ {
+ stopSwitch = true;
+ continue;
+ }
+ if (!s.IsEmpty() && IsItSwitchChar(s[0]))
+ {
+ if (ParseString(s, switchForms))
+ continue;
+ ErrorLine = s;
+ return false;
+ }
+ }
+ NonSwitchStrings.Add(s);
+ }
+ return true;
+}
+
+}
diff --git a/lzma/CPP/Common/CommandLineParser.h b/lzma/CPP/Common/CommandLineParser.h
new file mode 100644
index 0000000..446619c
--- /dev/null
+++ b/lzma/CPP/Common/CommandLineParser.h
@@ -0,0 +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
+{
+ unsigned _numSwitches;
+ CSwitchResult *_switches;
+
+ bool ParseString(const UString &s, const CSwitchForm *switchForms);
+public:
+ UStringVector NonSwitchStrings;
+ AString ErrorMessage;
+ UString ErrorLine;
+
+ CParser(unsigned numSwitches);
+ ~CParser();
+ bool ParseStrings(const CSwitchForm *switchForms, const UStringVector &commandStrings);
+ const CSwitchResult& operator[](size_t index) const { return _switches[index]; }
+};
+
+}
+
+#endif
diff --git a/lzma/CPP/Common/Common.h b/lzma/CPP/Common/Common.h
new file mode 100644
index 0000000..1f99077
--- /dev/null
+++ b/lzma/CPP/Common/Common.h
@@ -0,0 +1,13 @@
+// Common.h
+
+#ifndef __COMMON_COMMON_H
+#define __COMMON_COMMON_H
+
+#include "../../C/Compiler.h"
+
+#include "MyWindows.h"
+#include "NewHandler.h"
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[1]))
+
+#endif
diff --git a/lzma/CPP/Common/CrcReg.cpp b/lzma/CPP/Common/CrcReg.cpp
new file mode 100644
index 0000000..cfa1996
--- /dev/null
+++ b/lzma/CPP/Common/CrcReg.cpp
@@ -0,0 +1,111 @@
+// CrcReg.cpp
+
+#include "StdAfx.h"
+
+#include "../../C/7zCrc.h"
+#include "../../C/CpuArch.h"
+
+#include "../Common/MyCom.h"
+
+#include "../7zip/ICoder.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);
+
+extern CRC_FUNC g_CrcUpdate;
+
+#ifdef MY_CPU_X86_OR_AMD64
+ UInt32 MY_FAST_CALL CrcUpdateT8(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);
+#endif
+
+EXTERN_C_END
+
+class CCrcHasher:
+ public IHasher,
+ public ICompressSetCoderProperties,
+ public CMyUnknownImp
+{
+ UInt32 _crc;
+ CRC_FUNC _updateFunc;
+ bool SetFunctions(UInt32 tSize);
+public:
+ CCrcHasher(): _crc(CRC_INIT_VAL) { SetFunctions(0); }
+
+ MY_UNKNOWN_IMP1(ICompressSetCoderProperties)
+
+ STDMETHOD_(void, Init)();
+ STDMETHOD_(void, Update)(const void *data, UInt32 size);
+ STDMETHOD_(void, Final)(Byte *digest);
+ STDMETHOD_(UInt32, GetDigestSize)();
+ STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
+};
+
+STDMETHODIMP_(void) CCrcHasher::Init()
+{
+ _crc = CRC_INIT_VAL;
+}
+
+STDMETHODIMP_(void) CCrcHasher::Update(const void *data, UInt32 size)
+{
+ _crc = _updateFunc(_crc, data, size, g_CrcTable);
+}
+
+STDMETHODIMP_(void) CCrcHasher::Final(Byte *digest)
+{
+ UInt32 val = CRC_GET_DIGEST(_crc);
+ SetUi32(digest, val);
+}
+
+STDMETHODIMP_(UInt32) CCrcHasher::GetDigestSize()
+{
+ return 4;
+}
+
+bool CCrcHasher::SetFunctions(UInt32 tSize)
+{
+ _updateFunc = g_CrcUpdate;
+ if (tSize == 4)
+ {
+ #ifndef MY_CPU_BE
+ _updateFunc = CrcUpdateT4;
+ #endif
+ }
+ else if (tSize == 8)
+ {
+ #ifdef MY_CPU_X86_OR_AMD64
+ _updateFunc = CrcUpdateT8;
+ #else
+ return false;
+ #endif
+ }
+ 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;
+}
+
+static IHasher *CreateHasher() { return new CCrcHasher(); }
+
+static CHasherInfo g_HasherInfo = { CreateHasher, 0x1, L"CRC32", 4 };
+
+REGISTER_HASHER(Crc32)
diff --git a/lzma/CPP/Common/Defs.h b/lzma/CPP/Common/Defs.h
new file mode 100644
index 0000000..69b8ece
--- /dev/null
+++ b/lzma/CPP/Common/Defs.h
@@ -0,0 +1,20 @@
+// 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 ? -1 : (a == b ? 0 : 1); }
+
+inline int BoolToInt(bool value)
+ { return (value ? 1: 0); }
+
+inline bool IntToBool(int value)
+ { return (value != 0); }
+
+#endif
diff --git a/lzma/CPP/Common/DynamicBuffer.h b/lzma/CPP/Common/DynamicBuffer.h
new file mode 100644
index 0000000..92abf99
--- /dev/null
+++ b/lzma/CPP/Common/DynamicBuffer.h
@@ -0,0 +1,58 @@
+// 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];
+ 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;
+ }
+
+ const size_t GetPos() const { return _pos; }
+
+ // void Empty() { _pos = 0; }
+};
+
+typedef CDynamicBuffer<unsigned char> CByteDynamicBuffer;
+
+#endif
diff --git a/lzma/CPP/Common/IntToString.cpp b/lzma/CPP/Common/IntToString.cpp
new file mode 100644
index 0000000..d035115
--- /dev/null
+++ b/lzma/CPP/Common/IntToString.cpp
@@ -0,0 +1,146 @@
+// Common/IntToString.cpp
+
+#include "StdAfx.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);
+}
+
+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] = (char)((t < 10) ? ('0' + t) : ('A' + (t - 10)));
+ }
+ 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] = (char)((t < 10) ? ('0' + t) : ('A' + (t - 10)));
+ }
+ 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] = (char)(((t < 10) ? ('0' + t) : ('A' + (t - 10))));
+ }
+}
+
+/*
+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);
+}
diff --git a/lzma/CPP/Common/IntToString.h b/lzma/CPP/Common/IntToString.h
new file mode 100644
index 0000000..7750934
--- /dev/null
+++ b/lzma/CPP/Common/IntToString.h
@@ -0,0 +1,24 @@
+// 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();
+
+#endif
diff --git a/lzma/CPP/Common/Lang.h b/lzma/CPP/Common/Lang.h
new file mode 100644
index 0000000..9850e19
--- /dev/null
+++ b/lzma/CPP/Common/Lang.h
@@ -0,0 +1,23 @@
+// 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 wchar_t *id);
+ void Clear() throw();
+ const wchar_t *Get(UInt32 id) const throw();
+};
+
+#endif
diff --git a/lzma/CPP/Common/ListFileUtils.cpp b/lzma/CPP/Common/ListFileUtils.cpp
new file mode 100644
index 0000000..b0e80b1
--- /dev/null
+++ b/lzma/CPP/Common/ListFileUtils.cpp
@@ -0,0 +1,117 @@
+// 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 ReadNamesFromListFile(CFSTR fileName, UStringVector &strings, UINT codePage)
+{
+ NWindows::NFile::NIO::CInFile file;
+ if (!file.Open(fileName))
+ return false;
+ UInt64 fileSize;
+ if (!file.GetLength(fileSize))
+ 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))
+ return false;
+ if (processed != fileSize)
+ return false;
+ file.Close();
+ unsigned num = (unsigned)fileSize / 2;
+ wchar_t *p = u.GetBuffer(num);
+ if (codePage == MY__CP_UTF16)
+ for (unsigned i = 0; i < num; i++)
+ {
+ wchar_t c = GetUi16(buf + 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 + i * 2);
+ if (c == 0)
+ return false;
+ p[i] = c;
+ }
+ u.ReleaseBuffer(num);
+ }
+ else
+ {
+ AString s;
+ char *p = s.GetBuffer((unsigned)fileSize);
+ UInt32 processed;
+ if (!file.Read(p, (UInt32)fileSize, processed))
+ return false;
+ if (processed != fileSize)
+ return false;
+ file.Close();
+ p[processed] = 0;
+ s.ReleaseBuffer();
+ 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 == L'\n' || c == 0xD)
+ {
+ AddName(strings, s);
+ s.Empty();
+ }
+ else
+ s += c;
+ }
+ AddName(strings, s);
+ return true;
+}
diff --git a/lzma/CPP/Common/ListFileUtils.h b/lzma/CPP/Common/ListFileUtils.h
new file mode 100644
index 0000000..ec32d8e
--- /dev/null
+++ b/lzma/CPP/Common/ListFileUtils.h
@@ -0,0 +1,14 @@
+// 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);
+
+#endif
diff --git a/lzma/CPP/Common/MyBuffer.h b/lzma/CPP/Common/MyBuffer.h
new file mode 100644
index 0000000..dabdea6
--- /dev/null
+++ b/lzma/CPP/Common/MyBuffer.h
@@ -0,0 +1,237 @@
+// Common/MyBuffer.h
+
+#ifndef __COMMON_MY_BUFFER_H
+#define __COMMON_MY_BUFFER_H
+
+#include "Defs.h"
+
+template <class T> class CBuffer
+{
+ T *_items;
+ size_t _size;
+
+ void CopyToEmpty(const CBuffer &buffer)
+ {
+ if (buffer._size > 0)
+ {
+ _items = new T[buffer._size];
+ memcpy(_items, buffer._items, buffer._size * sizeof(T));
+ _size = buffer._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) { CopyToEmpty(buffer); }
+ ~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);
+ 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 (_size > 0)
+ memcpy(newBuffer, _items, MyMin(MyMin(_size, keepSize), newSize) * sizeof(T));
+ }
+ delete []_items;
+ _items = newBuffer;
+ _size = newSize;
+ }
+
+ CBuffer& operator=(const CBuffer &buffer)
+ {
+ Free();
+ CopyToEmpty(buffer);
+ 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;
+ 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 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 constructors
+ 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) _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;
+ _items = new T[newSize];
+ }
+};
+
+typedef CObjArray<unsigned char> CByteArr;
+typedef CObjArray<bool> CBoolArr;
+typedef CObjArray<int> CIntArr;
+
+// #define CRecArray CObjArray
+
+template <class T> class CObjArray2
+{
+// protected:
+ T *_items;
+ unsigned _size;
+
+ 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)
+ 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/lzma/CPP/Common/MyCom.h b/lzma/CPP/Common/MyCom.h
new file mode 100644
index 0000000..614a083
--- /dev/null
+++ b/lzma/CPP/Common/MyCom.h
@@ -0,0 +1,242 @@
+// MyCom.h
+
+#ifndef __MY_COM_H
+#define __MY_COM_H
+
+#include "MyWindows.h"
+#include "NewHandler.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 != NULL) ? S_OK : E_OUTOFMEMORY;
+}
+
+class CMyComBSTR
+{
+ BSTR m_str;
+public:
+
+ CMyComBSTR(): m_str(NULL) {}
+ 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() { ::SysFreeString(m_str); }
+ 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); }
+ operator BSTR() const { return m_str; }
+ BSTR* operator&() { return &m_str; }
+ BSTR MyCopy() const
+ {
+ int byteLen = ::SysStringByteLen(m_str);
+ BSTR res = ::SysAllocStringByteLen(NULL, byteLen);
+ 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;
+ }
+ bool operator!() const { return (m_str == NULL); }
+};
+
+//////////////////////////////////////////////////////////
+
+class CMyUnknownImp
+{
+public:
+ ULONG __m_RefCount;
+ CMyUnknownImp(): __m_RefCount(0) {}
+};
+
+#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; 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) \
+ )
+
+#endif
diff --git a/lzma/CPP/Common/MyException.h b/lzma/CPP/Common/MyException.h
new file mode 100644
index 0000000..cd9fe69
--- /dev/null
+++ b/lzma/CPP/Common/MyException.h
@@ -0,0 +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
diff --git a/lzma/CPP/Common/MyGuidDef.h b/lzma/CPP/Common/MyGuidDef.h
new file mode 100644
index 0000000..e0359e2
--- /dev/null
+++ b/lzma/CPP/Common/MyGuidDef.h
@@ -0,0 +1,54 @@
+// 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
diff --git a/lzma/CPP/Common/MyInitGuid.h b/lzma/CPP/Common/MyInitGuid.h
new file mode 100644
index 0000000..79fea19
--- /dev/null
+++ b/lzma/CPP/Common/MyInitGuid.h
@@ -0,0 +1,45 @@
+// 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
diff --git a/lzma/CPP/Common/MyString.cpp b/lzma/CPP/Common/MyString.cpp
new file mode 100644
index 0000000..747a181
--- /dev/null
+++ b/lzma/CPP/Common/MyString.cpp
@@ -0,0 +1,1215 @@
+// Common/MyString.cpp
+
+#include "StdAfx.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#include <wchar.h>
+#else
+#include <ctype.h>
+#endif
+
+#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
+}
+*/
+
+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(wchar_t *s)
+{
+ for (;;)
+ {
+ wchar_t c = *s;
+ if (c == 0)
+ return;
+ *s++ = MyCharUpper_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;
+ }
+}
+
+// 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) throw()
+{
+ 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);
+}
+
+void AString::ReAlloc(unsigned newLimit)
+{
+ if (newLimit < _len || newLimit >= 0x20000000) 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::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[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()); }
+
+AString::AString()
+{
+ _chars = 0;
+ _chars = MY_STRING_NEW(char, 4);
+ _len = 0;
+ _limit = 4 - 1;
+ _chars[0] = 0;
+}
+
+AString::AString(char c)
+{
+ SetStartLen(1);
+ _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;
+ _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;
+}
+
+AString &AString::operator+=(const char *s)
+{
+ unsigned len = MyStringLen(s);
+ Grow(len);
+ MyStringCopy(_chars + _len, s);
+ _len += len;
+ return *this;
+}
+
+AString &AString::operator+=(const AString &s)
+{
+ Grow(s._len);
+ MyStringCopy(_chars + _len, s._chars);
+ _len += s._len;
+ return *this;
+}
+
+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;
+ }
+ memcpy(_chars, s, len);
+ _chars[len] = 0;
+ _len = len;
+}
+
+int AString::Find(const AString &s, unsigned startIndex) const throw()
+{
+ if (s.IsEmpty())
+ return startIndex;
+ for (; startIndex < _len; startIndex++)
+ {
+ unsigned j;
+ for (j = 0; j < s._len && startIndex + j < _len; j++)
+ if (_chars[startIndex + j] != s._chars[j])
+ break;
+ if (j == s._len)
+ return (int)startIndex;
+ }
+ return -1;
+}
+
+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);
+ }
+}
+
+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;
+ int i;
+ for (i = _len - 1; i >= 0; i--)
+ {
+ char c = p[i];
+ if (c != ' ' && c != '\n' && c != '\t')
+ break;
+ }
+ i++;
+ if ((unsigned)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()
+{
+ int pos = Find(ch);
+ if (pos < 0)
+ return;
+ const char *src = _chars;
+ char *dest = _chars + pos;
+ pos++;
+ unsigned len = _len;
+ for (; (unsigned)pos < len; pos++)
+ {
+ char c = src[(unsigned)pos];
+ 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;
+ while ((unsigned)pos < _len)
+ {
+ pos = Find(oldChar, pos);
+ if (pos < 0)
+ break;
+ _chars[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 >= 0x20000000) 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::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[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, 4);
+ _len = 0;
+ _limit = 4 - 1;
+ _chars[0] = 0;
+}
+
+UString::UString(wchar_t c)
+{
+ SetStartLen(1);
+ _chars[0] = c;
+ _chars[1] = 0;
+}
+
+UString::UString(const wchar_t *s)
+{
+ SetStartLen(MyStringLen(s));
+ MyStringCopy(_chars, s);
+}
+
+UString::UString(const UString &s)
+{
+ SetStartLen(s._len);
+ MyStringCopy(_chars, s._chars);
+}
+
+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;
+ _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;
+ MyStringCopy(_chars, s);
+ 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;
+ MyStringCopy(_chars, s._chars);
+ return *this;
+}
+
+UString &UString::operator+=(const wchar_t *s)
+{
+ unsigned len = MyStringLen(s);
+ Grow(len);
+ MyStringCopy(_chars + _len, s);
+ _len += len;
+ return *this;
+}
+
+UString &UString::operator+=(const UString &s)
+{
+ Grow(s._len);
+ MyStringCopy(_chars + _len, s._chars);
+ _len += s._len;
+ 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;
+ }
+ wmemcpy(_chars, s, len);
+ _chars[len] = 0;
+ _len = len;
+}
+
+void UString::SetFromAscii(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] = s[i];
+ chars[len] = 0;
+ _len = len;
+}
+
+void UString::AddAsciiStr(const char *s)
+{
+ unsigned len = MyStringLen(s);
+ Grow(len);
+ wchar_t *chars = _chars + _len;
+ for (unsigned i = 0; i < len; i++)
+ chars[i] = s[i];
+ chars[len] = 0;
+ _len += len;
+}
+
+
+
+int UString::Find(const UString &s, unsigned startIndex) const throw()
+{
+ if (s.IsEmpty())
+ return startIndex;
+ for (; startIndex < _len; startIndex++)
+ {
+ unsigned j;
+ for (j = 0; j < s._len && startIndex + j < _len; j++)
+ if (_chars[startIndex + j] != s._chars[j])
+ break;
+ if (j == s._len)
+ return (int)startIndex;
+ }
+ return -1;
+}
+
+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--;
+ }
+}
+
+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;
+ int i;
+ for (i = _len - 1; i >= 0; i--)
+ {
+ wchar_t c = p[i];
+ if (c != ' ' && c != '\n' && c != '\t')
+ break;
+ }
+ i++;
+ if ((unsigned)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()
+{
+ int pos = Find(ch);
+ if (pos < 0)
+ return;
+ const wchar_t *src = _chars;
+ wchar_t *dest = _chars + pos;
+ pos++;
+ unsigned len = _len;
+ for (; (unsigned)pos < len; pos++)
+ {
+ wchar_t c = src[(unsigned)pos];
+ 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;
+ while ((unsigned)pos < _len)
+ {
+ pos = Find(oldChar, pos);
+ if (pos < 0)
+ break;
+ _chars[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;
+ }
+}
+
+
+// ----------------------------------------
+
+/*
+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 AString &s)
+{
+ return MultiByteToUnicodeString(s, GetCurrentCodePage());
+}
+
+#endif
+
+#else
+
+UString fs2us(const FString &s)
+{
+ return MultiByteToUnicodeString((AString)s, GetCurrentCodePage());
+}
+
+FString us2fs(const wchar_t *s)
+{
+ return UnicodeStringToMultiByte(s, GetCurrentCodePage());
+}
+
+#endif
diff --git a/lzma/CPP/Common/MyString.h b/lzma/CPP/Common/MyString.h
new file mode 100644
index 0000000..018acce
--- /dev/null
+++ b/lzma/CPP/Common/MyString.h
@@ -0,0 +1,525 @@
+// Common/String.h
+
+#ifndef __COMMON_STRING_H
+#define __COMMON_STRING_H
+
+#include <string.h>
+
+#ifndef _WIN32
+#include <wctype.h>
+#include <wchar.h>
+#endif
+
+#include "MyTypes.h"
+#include "MyVector.h"
+
+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);
+}
+
+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)(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)(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(wchar_t *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();
+
+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_);
+
+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 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);
+
+public:
+ AString();
+ AString(char c);
+ 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[_len - 1]; }
+
+ void ReplaceOneCharAtPos(unsigned pos, char c) { _chars[pos] = c; }
+
+ // The minimum size of the character buffer in characters.
+ // This value does not include space for a null terminator.
+ char *GetBuffer(unsigned minBufLen)
+ {
+ if (minBufLen > _limit)
+ ReAlloc(minBufLen);
+ return _chars;
+ }
+ void ReleaseBuffer() { ReleaseBuffer(MyStringLen(_chars)); }
+ void ReleaseBuffer(unsigned newLen) { _len = newLen; _chars[newLen] = 0; }
+
+ AString &operator=(char c);
+ AString &operator=(const char *s);
+ AString &operator=(const AString &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;
+ }
+
+ AString &operator+=(const char *s);
+ AString &operator+=(const AString &s);
+
+ void SetFrom(const char *s, unsigned len); // no check
+ // 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); }
+
+
+ // 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();
+
+ 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 Find(const AString &s) const { return Find(s, 0); }
+ int Find(const AString &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; }
+
+
+
+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 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);
+
+public:
+ UString();
+ UString(wchar_t c);
+ 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[_len - 1]; }
+
+ void ReplaceOneCharAtPos(unsigned pos, wchar_t c) { _chars[pos] = c; }
+
+ // The minimum size of the character buffer in characters.
+ // This value does not include space for a null terminator.
+ wchar_t *GetBuffer(unsigned minBufLen)
+ {
+ if (minBufLen > _limit)
+ ReAlloc(minBufLen);
+ return _chars;
+ }
+ void ReleaseBuffer() { ReleaseBuffer(MyStringLen(_chars)); }
+ void ReleaseBuffer(unsigned newLen) { _len = newLen; _chars[newLen] = 0; }
+
+ UString &operator=(wchar_t c);
+ UString &operator=(const wchar_t *s);
+ UString &operator=(const UString &s);
+
+ 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+=(const wchar_t *s);
+ UString &operator+=(const UString &s);
+
+ void SetFrom(const wchar_t *s, unsigned len); // no check
+
+ void SetFromAscii(const char *s);
+ void AddAsciiStr(const char *s);
+
+ 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 IsEqualToNoCase(const wchar_t *s) const { return StringsAreEqualNoCase(_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_Ascii_NoCase(const char *s) const throw();
+
+ 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 Find(const UString &s) const { return Find(s, 0); }
+ int Find(const UString &s, unsigned startIndex) const throw();
+ int ReverseFind(wchar_t c) 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; }
+
+
+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 AString &s);
+ AString fs2fas(const FChar *s);
+
+#else
+
+ #define __FTEXT(quote) quote
+
+ typedef char FChar;
+ typedef AString FString;
+
+ 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
diff --git a/lzma/CPP/Common/MyTypes.h b/lzma/CPP/Common/MyTypes.h
new file mode 100644
index 0000000..f49739c
--- /dev/null
+++ b/lzma/CPP/Common/MyTypes.h
@@ -0,0 +1,30 @@
+// 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;
+ }
+};
+
+#endif
diff --git a/lzma/CPP/Common/MyUnknown.h b/lzma/CPP/Common/MyUnknown.h
new file mode 100644
index 0000000..7935124
--- /dev/null
+++ b/lzma/CPP/Common/MyUnknown.h
@@ -0,0 +1,13 @@
+// MyUnknown.h
+
+#ifndef __MY_UNKNOWN_H
+#define __MY_UNKNOWN_H
+
+#ifdef _WIN32
+#include <basetyps.h>
+#include <unknwn.h>
+#else
+#include "MyWindows.h"
+#endif
+
+#endif
diff --git a/lzma/CPP/Common/MyVector.cpp b/lzma/CPP/Common/MyVector.cpp
new file mode 100644
index 0000000..9a6d1d5
--- /dev/null
+++ b/lzma/CPP/Common/MyVector.cpp
@@ -0,0 +1,3 @@
+// Common/MyVector.cpp
+
+#include "StdAfx.h"
diff --git a/lzma/CPP/Common/MyVector.h b/lzma/CPP/Common/MyVector.h
new file mode 100644
index 0000000..521aa23
--- /dev/null
+++ b/lzma/CPP/Common/MyVector.h
@@ -0,0 +1,615 @@
+// Common/MyVector.h
+
+#ifndef __COMMON_MY_VECTOR_H
+#define __COMMON_MY_VECTOR_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) * (size_t)sizeof(T));
+ }
+
+ void ReserveOnePosition()
+ {
+ if (_size == _capacity)
+ {
+ unsigned newCapacity = _capacity + (_capacity >> 2) + 1;
+ T *p = new T[newCapacity];
+ memcpy(p, _items, (size_t)_size * (size_t)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 * (size_t)sizeof(T));
+ }
+ }
+
+ unsigned Size() const { return _size; }
+ bool IsEmpty() const { return _size == 0; }
+
+ void ConstructReserve(unsigned size)
+ {
+ if (size != 0)
+ {
+ _items = new T[size];
+ _capacity = size;
+ }
+ }
+
+ void Reserve(unsigned newCapacity)
+ {
+ if (newCapacity > _capacity)
+ {
+ T *p = new T[newCapacity];
+ memcpy(p, _items, (size_t)_size * (size_t)sizeof(T));
+ delete []_items;
+ _items = p;
+ _capacity = newCapacity;
+ }
+ }
+
+ void ClearAndReserve(unsigned newCapacity)
+ {
+ Clear();
+ if (newCapacity > _capacity)
+ {
+ delete []_items;
+ _items = NULL;
+ _capacity = 0;
+ _items = new T[newCapacity];
+ _capacity = newCapacity;
+ }
+ }
+
+ void ClearAndSetSize(unsigned newSize)
+ {
+ ClearAndReserve(newSize);
+ _size = newSize;
+ }
+
+ void ChangeSize_KeepData(unsigned newSize)
+ {
+ if (newSize > _capacity)
+ {
+ T *p = new T[newSize];
+ memcpy(p, _items, (size_t)_size * (size_t)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 * (size_t)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)
+ {
+ unsigned size = v.Size();
+ if (size > _capacity)
+ {
+ delete []_items;
+ _capacity = 0;
+ _size = 0;
+ _items = NULL;
+ _items = new T[size];
+ _capacity = size;
+ }
+ _size = size;
+ memcpy(_items, v._items, (size_t)size * (size_t)sizeof(T));
+ return *this;
+ }
+
+ CRecordVector& operator+=(const CRecordVector &v)
+ {
+ unsigned size = v.Size();
+ Reserve(_size + size);
+ memcpy(_items + _size, v._items, (size_t)size * (size_t)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 * (size_t)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 - 1]; }
+ T& Back() { return _items[_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[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)
+ {
+ 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 operator[](_v.Size() - 1); }
+ T& Back() { return operator[](_v.Size() - 1); }
+
+ 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[_v.Size() - 1];
+ _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
diff --git a/lzma/CPP/Common/MyWindows.cpp b/lzma/CPP/Common/MyWindows.cpp
new file mode 100644
index 0000000..bc9f7be
--- /dev/null
+++ b/lzma/CPP/Common/MyWindows.cpp
@@ -0,0 +1,145 @@
+// 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
diff --git a/lzma/CPP/Common/MyWindows.h b/lzma/CPP/Common/MyWindows.h
new file mode 100644
index 0000000..33145b1
--- /dev/null
+++ b/lzma/CPP/Common/MyWindows.h
@@ -0,0 +1,216 @@
+// 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 "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 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 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
diff --git a/lzma/CPP/Common/NewHandler.cpp b/lzma/CPP/Common/NewHandler.cpp
new file mode 100644
index 0000000..f004889
--- /dev/null
+++ b/lzma/CPP/Common/NewHandler.cpp
@@ -0,0 +1,162 @@
+// NewHandler.cpp
+
+#include "StdAfx.h"
+
+#include <stdlib.h>
+
+#include "NewHandler.h"
+
+// #define DEBUG_MEMORY_LEAK
+
+#ifndef DEBUG_MEMORY_LEAK
+
+#ifdef _WIN32
+
+/*
+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);
+ 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 = %8d\n", numAllocs, 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);
+}
+*/
diff --git a/lzma/CPP/Common/NewHandler.h b/lzma/CPP/Common/NewHandler.h
new file mode 100644
index 0000000..d1f4a14
--- /dev/null
+++ b/lzma/CPP/Common/NewHandler.h
@@ -0,0 +1,68 @@
+// Common/NewHandler.h
+
+#ifndef __COMMON_NEW_HANDLER_H
+#define __COMMON_NEW_HANDLER_H
+
+/*
+This file must be included before any code that uses operators "delete" or "new".
+Also you must compile and link "NewHandler.cpp", if you use MSVC 6.0.
+The operator "new" in MSVC 6.0 doesn't throw exception "bad_alloc".
+So we define another version of operator "new" that throws "CNewException" on failure.
+
+If you use compiler that throws exception in "new" operator (GCC or new version of MSVC),
+you can compile without "NewHandler.cpp". So standard exception "bad_alloc" will be used.
+
+It's still allowed to use redefined version of operator "new" from "NewHandler.cpp"
+with any compiler. 7-Zip's code can work with "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" (that throws CNewException) is not
+problem for your code.
+
+Also we declare delete(void *p) throw() that creates smaller code.
+*/
+
+
+class CNewException {};
+
+#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
+
+#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
+
+/*
+#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/lzma/CPP/Common/Sha256Reg.cpp b/lzma/CPP/Common/Sha256Reg.cpp
new file mode 100644
index 0000000..eaab65c
--- /dev/null
+++ b/lzma/CPP/Common/Sha256Reg.cpp
@@ -0,0 +1,52 @@
+// Sha256Reg.cpp
+
+#include "StdAfx.h"
+
+#include "../../C/Sha256.h"
+
+#include "../Common/MyCom.h"
+
+#include "../7zip/ICoder.h"
+#include "../7zip/Common/RegisterCodec.h"
+
+class CSha256Hasher:
+ public IHasher,
+ public CMyUnknownImp
+{
+ CSha256 _sha;
+public:
+ CSha256Hasher() { Init(); };
+
+ MY_UNKNOWN_IMP
+
+ STDMETHOD_(void, Init)();
+ STDMETHOD_(void, Update)(const void *data, UInt32 size);
+ STDMETHOD_(void, Final)(Byte *digest);
+ STDMETHOD_(UInt32, GetDigestSize)();
+};
+
+STDMETHODIMP_(void) CSha256Hasher::Init()
+{
+ Sha256_Init(&_sha);
+}
+
+STDMETHODIMP_(void) CSha256Hasher::Update(const void *data, UInt32 size)
+{
+ Sha256_Update(&_sha, (const Byte *)data, size);
+}
+
+STDMETHODIMP_(void) CSha256Hasher::Final(Byte *digest)
+{
+ Sha256_Final(&_sha, digest);
+}
+
+STDMETHODIMP_(UInt32) CSha256Hasher::GetDigestSize()
+{
+ return SHA256_DIGEST_SIZE;
+}
+
+static IHasher *CreateHasher() { return new CSha256Hasher; }
+
+static CHasherInfo g_HasherInfo = { CreateHasher, 0xA, L"SHA256", SHA256_DIGEST_SIZE };
+
+REGISTER_HASHER(Sha256)
diff --git a/lzma/CPP/Common/StdAfx.h b/lzma/CPP/Common/StdAfx.h
new file mode 100644
index 0000000..3f1890a
--- /dev/null
+++ b/lzma/CPP/Common/StdAfx.h
@@ -0,0 +1,8 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "Common.h"
+
+#endif
diff --git a/lzma/CPP/Common/StdInStream.cpp b/lzma/CPP/Common/StdInStream.cpp
new file mode 100644
index 0000000..0799c2c
--- /dev/null
+++ b/lzma/CPP/Common/StdInStream.cpp
@@ -0,0 +1,94 @@
+// Common/StdInStream.cpp
+
+#include "StdAfx.h"
+
+#include <tchar.h>
+
+#include "StdInStream.h"
+#include "StringConvert.h"
+#include "UTFConvert.h"
+
+static const char kNewLineChar = '\n';
+
+static const char *kEOFMessage = "Unexpected end of input stream";
+static const char *kReadErrorMessage ="Error reading input stream";
+static const char *kIllegalCharMessage = "Illegal character in input stream";
+
+static LPCTSTR 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;
+}
+
+AString CStdInStream::ScanStringUntilNewLine(bool allowEOF)
+{
+ AString s;
+ for (;;)
+ {
+ int intChar = GetChar();
+ if (intChar == EOF)
+ {
+ if (allowEOF)
+ break;
+ throw kEOFMessage;
+ }
+ char c = (char)intChar;
+ if (c == 0)
+ throw kIllegalCharMessage;
+ if (c == kNewLineChar)
+ break;
+ s += c;
+ }
+ return s;
+}
+
+UString CStdInStream::ScanUStringUntilNewLine()
+{
+ AString s = ScanStringUntilNewLine(true);
+ int codePage = g_CodePage;
+ if (codePage == -1)
+ codePage = CP_OEMCP;
+ UString dest;
+ if (codePage == CP_UTF8)
+ ConvertUTF8ToUnicode(s, dest);
+ else
+ dest = MultiByteToUnicodeString(s, (UINT)codePage);
+ return dest;
+}
+
+void CStdInStream::ReadToString(AString &resultString)
+{
+ resultString.Empty();
+ int c;
+ while ((c = GetChar()) != EOF)
+ resultString += (char)c;
+}
+
+bool CStdInStream::Eof() throw()
+{
+ return (feof(_stream) != 0);
+}
+
+int CStdInStream::GetChar()
+{
+ int c = fgetc(_stream); // getc() doesn't work in BeOS?
+ if (c == EOF && !Eof())
+ throw kReadErrorMessage;
+ return c;
+}
diff --git a/lzma/CPP/Common/StdInStream.h b/lzma/CPP/Common/StdInStream.h
new file mode 100644
index 0000000..c017d0a
--- /dev/null
+++ b/lzma/CPP/Common/StdInStream.h
@@ -0,0 +1,33 @@
+// 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();
+
+ AString ScanStringUntilNewLine(bool allowEOF = false);
+ void ReadToString(AString &resultString);
+ UString ScanUStringUntilNewLine();
+
+ bool Eof() throw();
+ int GetChar();
+};
+
+extern CStdInStream g_StdIn;
+
+#endif
diff --git a/lzma/CPP/Common/StdOutStream.cpp b/lzma/CPP/Common/StdOutStream.cpp
new file mode 100644
index 0000000..eec83bb
--- /dev/null
+++ b/lzma/CPP/Common/StdOutStream.cpp
@@ -0,0 +1,106 @@
+// Common/StdOutStream.cpp
+
+#include "StdAfx.h"
+
+#include <tchar.h>
+
+#include "IntToString.h"
+#include "StdOutStream.h"
+#include "StringConvert.h"
+#include "UTFConvert.h"
+
+static const char kNewLineChar = '\n';
+
+static const char *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 << kNewLineChar;
+}
+
+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;
+}
+
+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/lzma/CPP/Common/StdOutStream.h b/lzma/CPP/Common/StdOutStream.h
new file mode 100644
index 0000000..4ade958
--- /dev/null
+++ b/lzma/CPP/Common/StdOutStream.h
@@ -0,0 +1,62 @@
+// 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:
+ CStdOutStream(): _stream(0), _streamIsOpen(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(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);
+};
+
+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
diff --git a/lzma/CPP/Common/StringConvert.cpp b/lzma/CPP/Common/StringConvert.cpp
new file mode 100644
index 0000000..825b16f
--- /dev/null
+++ b/lzma/CPP/Common/StringConvert.cpp
@@ -0,0 +1,165 @@
+// Common/StringConvert.cpp
+
+#include "StdAfx.h"
+
+#include "StringConvert.h"
+
+#ifndef _WIN32
+#include <stdlib.h>
+#endif
+
+#ifdef _WIN32
+UString MultiByteToUnicodeString(const AString &srcString, UINT codePage)
+{
+ UString resultString;
+ if (!srcString.IsEmpty())
+ {
+ int numChars = MultiByteToWideChar(codePage, 0, srcString,
+ srcString.Len(), resultString.GetBuffer(srcString.Len()),
+ srcString.Len() + 1);
+ if (numChars == 0)
+ throw 282228;
+ resultString.ReleaseBuffer(numChars);
+ }
+ return resultString;
+}
+
+void MultiByteToUnicodeString2(UString &dest, const AString &srcString, UINT codePage)
+{
+ dest.Empty();
+ if (!srcString.IsEmpty())
+ {
+ wchar_t *destBuf = dest.GetBuffer(srcString.Len());
+ const char *sp = (const char *)srcString;
+ unsigned i;
+ for (i = 0;;)
+ {
+ char c = sp[i];
+ if ((Byte)c >= 0x80 || c == 0)
+ break;
+ destBuf[i++] = (wchar_t)c;
+ }
+
+ if (i != srcString.Len())
+ {
+ unsigned numChars = MultiByteToWideChar(codePage, 0, sp + i,
+ srcString.Len() - i, destBuf + i,
+ srcString.Len() + 1 - i);
+ if (numChars == 0)
+ throw 282228;
+ i += numChars;
+ }
+ dest.ReleaseBuffer(i);
+ }
+}
+
+void UnicodeStringToMultiByte2(AString &dest, const UString &s, UINT codePage, char defaultChar, bool &defaultCharWasUsed)
+{
+ dest.Empty();
+ defaultCharWasUsed = false;
+ if (!s.IsEmpty())
+ {
+ unsigned numRequiredBytes = s.Len() * 2;
+ char *destBuf = dest.GetBuffer(numRequiredBytes);
+ unsigned i;
+ const wchar_t *sp = (const wchar_t *)s;
+ for (i = 0;;)
+ {
+ wchar_t c = sp[i];
+ if (c >= 0x80 || c == 0)
+ break;
+ destBuf[i++] = (char)c;
+ }
+ defaultCharWasUsed = false;
+ if (i != s.Len())
+ {
+ BOOL defUsed;
+ unsigned numChars = WideCharToMultiByte(codePage, 0, sp + i, s.Len() - i,
+ destBuf + i, numRequiredBytes + 1 - i,
+ &defaultChar, &defUsed);
+ defaultCharWasUsed = (defUsed != FALSE);
+ if (numChars == 0)
+ throw 282229;
+ i += numChars;
+ }
+ dest.ReleaseBuffer(i);
+ }
+}
+
+void UnicodeStringToMultiByte2(AString &dest, const UString &srcString, UINT codePage)
+{
+ bool defaultCharWasUsed;
+ UnicodeStringToMultiByte2(dest, srcString, codePage, '_', defaultCharWasUsed);
+}
+
+AString UnicodeStringToMultiByte(const UString &s, UINT codePage, char defaultChar, bool &defaultCharWasUsed)
+{
+ AString dest;
+ defaultCharWasUsed = false;
+ if (!s.IsEmpty())
+ {
+ unsigned numRequiredBytes = s.Len() * 2;
+ BOOL defUsed;
+ int numChars = WideCharToMultiByte(codePage, 0, s, s.Len(),
+ dest.GetBuffer(numRequiredBytes), numRequiredBytes + 1,
+ &defaultChar, &defUsed);
+ defaultCharWasUsed = (defUsed != FALSE);
+ if (numChars == 0)
+ throw 282229;
+ dest.ReleaseBuffer(numChars);
+ }
+ return dest;
+}
+
+AString UnicodeStringToMultiByte(const UString &srcString, UINT codePage)
+{
+ bool defaultCharWasUsed;
+ return UnicodeStringToMultiByte(srcString, codePage, '_', defaultCharWasUsed);
+}
+
+#ifndef UNDER_CE
+AString SystemStringToOemString(const CSysString &srcString)
+{
+ AString result;
+ CharToOem(srcString, result.GetBuffer(srcString.Len() * 2));
+ result.ReleaseBuffer();
+ return result;
+}
+#endif
+
+#else
+
+UString MultiByteToUnicodeString(const AString &srcString, UINT codePage)
+{
+ UString resultString;
+ for (unsigned i = 0; i < srcString.Len(); i++)
+ resultString += (wchar_t)srcString[i];
+ /*
+ if (!srcString.IsEmpty())
+ {
+ int numChars = mbstowcs(resultString.GetBuffer(srcString.Len()), srcString, srcString.Len() + 1);
+ if (numChars < 0) throw "Your environment does not support UNICODE";
+ resultString.ReleaseBuffer(numChars);
+ }
+ */
+ return resultString;
+}
+
+AString UnicodeStringToMultiByte(const UString &srcString, UINT codePage)
+{
+ AString resultString;
+ for (unsigned i = 0; i < srcString.Len(); i++)
+ resultString += (char)srcString[i];
+ /*
+ if (!srcString.IsEmpty())
+ {
+ int numRequiredBytes = srcString.Len() * 6 + 1;
+ int numChars = wcstombs(resultString.GetBuffer(numRequiredBytes), srcString, numRequiredBytes);
+ if (numChars < 0) throw "Your environment does not support UNICODE";
+ resultString.ReleaseBuffer(numChars);
+ }
+ */
+ return resultString;
+}
+
+#endif
diff --git a/lzma/CPP/Common/StringConvert.h b/lzma/CPP/Common/StringConvert.h
new file mode 100644
index 0000000..d5518eb
--- /dev/null
+++ b/lzma/CPP/Common/StringConvert.h
@@ -0,0 +1,77 @@
+// Common/StringConvert.h
+
+#ifndef __COMMON_STRING_CONVERT_H
+#define __COMMON_STRING_CONVERT_H
+
+#include "MyString.h"
+#include "MyWindows.h"
+
+UString MultiByteToUnicodeString(const AString &srcString, UINT codePage = CP_ACP);
+
+// optimized versions that work faster for ASCII strings
+void MultiByteToUnicodeString2(UString &dest, const AString &srcString, UINT codePage = CP_ACP);
+void UnicodeStringToMultiByte2(AString &dest, const UString &s, UINT codePage, char defaultChar, bool &defaultCharWasUsed);
+void UnicodeStringToMultiByte2(AString &dest, const UString &srcString, UINT codePage);
+
+AString UnicodeStringToMultiByte(const UString &srcString, UINT codePage, char defaultChar, bool &defaultCharWasUsed);
+AString UnicodeStringToMultiByte(const UString &srcString, UINT codePage = CP_ACP);
+
+inline const wchar_t* GetUnicodeString(const wchar_t* unicodeString)
+ { return unicodeString; }
+inline const UString& GetUnicodeString(const UString &unicodeString)
+ { return unicodeString; }
+inline UString GetUnicodeString(const AString &ansiString)
+ { return MultiByteToUnicodeString(ansiString); }
+inline UString GetUnicodeString(const AString &multiByteString, UINT codePage)
+ { return MultiByteToUnicodeString(multiByteString, codePage); }
+inline const wchar_t* GetUnicodeString(const wchar_t* unicodeString, UINT)
+ { return unicodeString; }
+inline const UString& GetUnicodeString(const UString &unicodeString, UINT)
+ { return unicodeString; }
+
+inline const char* GetAnsiString(const char* ansiString)
+ { return ansiString; }
+inline const AString& GetAnsiString(const AString &ansiString)
+ { return ansiString; }
+inline AString GetAnsiString(const UString &unicodeString)
+ { return UnicodeStringToMultiByte(unicodeString); }
+
+inline const char* GetOemString(const char* oemString)
+ { return oemString; }
+inline const AString& GetOemString(const AString &oemString)
+ { return oemString; }
+inline AString GetOemString(const UString &unicodeString)
+ { return UnicodeStringToMultiByte(unicodeString, CP_OEMCP); }
+
+
+#ifdef _UNICODE
+ inline const wchar_t* GetSystemString(const wchar_t* unicodeString)
+ { return unicodeString;}
+ inline const UString& GetSystemString(const UString &unicodeString)
+ { return unicodeString;}
+ inline const wchar_t* GetSystemString(const wchar_t* unicodeString, UINT /* codePage */)
+ { return unicodeString;}
+ inline const UString& GetSystemString(const UString &unicodeString, UINT /* codePage */)
+ { return unicodeString;}
+ inline UString GetSystemString(const AString &multiByteString, UINT codePage)
+ { return MultiByteToUnicodeString(multiByteString, codePage);}
+ inline UString GetSystemString(const AString &multiByteString)
+ { return MultiByteToUnicodeString(multiByteString);}
+#else
+ inline const char* GetSystemString(const char *ansiString)
+ { return ansiString; }
+ inline const AString& GetSystemString(const AString &multiByteString, UINT)
+ { return multiByteString; }
+ inline const char * GetSystemString(const char *multiByteString, UINT)
+ { return multiByteString; }
+ inline AString GetSystemString(const UString &unicodeString)
+ { return UnicodeStringToMultiByte(unicodeString); }
+ inline AString GetSystemString(const UString &unicodeString, UINT codePage)
+ { return UnicodeStringToMultiByte(unicodeString, codePage); }
+#endif
+
+#ifndef UNDER_CE
+AString SystemStringToOemString(const CSysString &srcString);
+#endif
+
+#endif
diff --git a/lzma/CPP/Common/StringToInt.cpp b/lzma/CPP/Common/StringToInt.cpp
new file mode 100644
index 0000000..f9d483e
--- /dev/null
+++ b/lzma/CPP/Common/StringToInt.cpp
@@ -0,0 +1,144 @@
+// 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) \
+ uintType ConvertStringTo ## uintType(const charType *s, const charType **end) throw() { \
+ if (end) *end = s; \
+ uintType res = 0; \
+ for (;; s++) { \
+ charType c = *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)
+CONVERT_STRING_TO_UINT_FUNC(UInt32, wchar_t)
+CONVERT_STRING_TO_UINT_FUNC(UInt64, char)
+CONVERT_STRING_TO_UINT_FUNC(UInt64, 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++)
+ {
+ char c = *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++)
+ {
+ char c = *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++)
+ {
+ char c = *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++)
+ {
+ char c = *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/lzma/CPP/Common/StringToInt.h b/lzma/CPP/Common/StringToInt.h
new file mode 100644
index 0000000..140d1ee
--- /dev/null
+++ b/lzma/CPP/Common/StringToInt.h
@@ -0,0 +1,21 @@
+// 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
diff --git a/lzma/CPP/Common/TextConfig.cpp b/lzma/CPP/Common/TextConfig.cpp
new file mode 100644
index 0000000..a77e770
--- /dev/null
+++ b/lzma/CPP/Common/TextConfig.cpp
@@ -0,0 +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;
+ 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 == '\\')
+ {
+ char 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 UString &id) throw()
+{
+ FOR_VECTOR (i, pairs)
+ if (pairs[i].ID == id)
+ return i;
+ return -1;
+}
+
+UString GetTextConfigValue(const CObjectVector<CTextConfigPair> &pairs, const UString &id)
+{
+ int index = FindTextConfigItem(pairs, id);
+ if (index < 0)
+ return UString();
+ return pairs[index].String;
+}
diff --git a/lzma/CPP/Common/TextConfig.h b/lzma/CPP/Common/TextConfig.h
new file mode 100644
index 0000000..9281fcf
--- /dev/null
+++ b/lzma/CPP/Common/TextConfig.h
@@ -0,0 +1,21 @@
+// 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 UString &id) throw();
+UString GetTextConfigValue(const CObjectVector<CTextConfigPair> &pairs, const UString &id);
+
+#endif
+
+
diff --git a/lzma/CPP/Common/UTFConvert.cpp b/lzma/CPP/Common/UTFConvert.cpp
new file mode 100644
index 0000000..0d3ff68
--- /dev/null
+++ b/lzma/CPP/Common/UTFConvert.cpp
@@ -0,0 +1,176 @@
+// UTFConvert.cpp
+
+#include "StdAfx.h"
+
+#include "MyTypes.h"
+#include "UTFConvert.h"
+
+static const Byte kUtf8Limits[5] = { 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
+
+bool CheckUTF8(const char *src) throw()
+{
+ for (;;)
+ {
+ Byte c;
+ unsigned numAdds;
+ c = *src++;
+ if (c == 0)
+ return true;
+
+ if (c < 0x80)
+ continue;
+ if (c < 0xC0)
+ return false;
+ for (numAdds = 1; numAdds < 5; numAdds++)
+ if (c < kUtf8Limits[numAdds])
+ break;
+ UInt32 value = (c - kUtf8Limits[numAdds - 1]);
+
+ do
+ {
+ Byte c2 = *src++;
+ if (c2 < 0x80 || c2 >= 0xC0)
+ return false;
+ value <<= 6;
+ value |= (c2 - 0x80);
+ }
+ while (--numAdds);
+
+ if (value >= 0x110000)
+ return false;
+ }
+}
+
+
+static Bool Utf8_To_Utf16(wchar_t *dest, size_t *destLen, const char *src, size_t srcLen) throw()
+{
+ size_t destPos = 0, srcPos = 0;
+ for (;;)
+ {
+ Byte c;
+ unsigned numAdds;
+ if (srcPos == srcLen)
+ {
+ *destLen = destPos;
+ return True;
+ }
+ c = (Byte)src[srcPos++];
+
+ if (c < 0x80)
+ {
+ if (dest)
+ dest[destPos] = (wchar_t)c;
+ destPos++;
+ continue;
+ }
+ if (c < 0xC0)
+ break;
+ for (numAdds = 1; numAdds < 5; numAdds++)
+ if (c < kUtf8Limits[numAdds])
+ break;
+ UInt32 value = (c - kUtf8Limits[numAdds - 1]);
+
+ do
+ {
+ Byte c2;
+ if (srcPos == srcLen)
+ break;
+ c2 = (Byte)src[srcPos++];
+ if (c2 < 0x80 || c2 >= 0xC0)
+ break;
+ value <<= 6;
+ value |= (c2 - 0x80);
+ }
+ while (--numAdds);
+
+ if (value < 0x10000)
+ {
+ if (dest)
+ dest[destPos] = (wchar_t)value;
+ destPos++;
+ }
+ else
+ {
+ value -= 0x10000;
+ if (value >= 0x100000)
+ break;
+ if (dest)
+ {
+ dest[destPos + 0] = (wchar_t)(0xD800 + (value >> 10));
+ dest[destPos + 1] = (wchar_t)(0xDC00 + (value & 0x3FF));
+ }
+ destPos += 2;
+ }
+ }
+ *destLen = destPos;
+ return False;
+}
+
+static Bool Utf16_To_Utf8(char *dest, size_t *destLen, const wchar_t *src, size_t srcLen)
+{
+ size_t destPos = 0, srcPos = 0;
+ for (;;)
+ {
+ unsigned numAdds;
+ UInt32 value;
+ if (srcPos == srcLen)
+ {
+ *destLen = destPos;
+ return True;
+ }
+ value = src[srcPos++];
+ if (value < 0x80)
+ {
+ if (dest)
+ dest[destPos] = (char)value;
+ destPos++;
+ continue;
+ }
+ 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;
+ }
+ for (numAdds = 1; numAdds < 5; numAdds++)
+ if (value < (((UInt32)1) << (numAdds * 5 + 6)))
+ break;
+ if (dest)
+ dest[destPos] = (char)(kUtf8Limits[numAdds - 1] + (value >> (6 * numAdds)));
+ destPos++;
+ do
+ {
+ numAdds--;
+ if (dest)
+ dest[destPos] = (char)(0x80 + ((value >> (6 * numAdds)) & 0x3F));
+ destPos++;
+ }
+ while (numAdds != 0);
+ }
+ *destLen = destPos;
+ return False;
+}
+
+bool ConvertUTF8ToUnicode(const AString &src, UString &dest)
+{
+ dest.Empty();
+ size_t destLen = 0;
+ Utf8_To_Utf16(NULL, &destLen, src, src.Len());
+ Bool res = Utf8_To_Utf16(dest.GetBuffer((unsigned)destLen), &destLen, src, src.Len());
+ dest.ReleaseBuffer((unsigned)destLen);
+ return res ? true : false;
+}
+
+bool ConvertUnicodeToUTF8(const UString &src, AString &dest)
+{
+ dest.Empty();
+ size_t destLen = 0;
+ Utf16_To_Utf8(NULL, &destLen, src, src.Len());
+ Bool res = Utf16_To_Utf8(dest.GetBuffer((unsigned)destLen), &destLen, src, src.Len());
+ dest.ReleaseBuffer((unsigned)destLen);
+ return res ? true : false;
+}
diff --git a/lzma/CPP/Common/UTFConvert.h b/lzma/CPP/Common/UTFConvert.h
new file mode 100644
index 0000000..601b674
--- /dev/null
+++ b/lzma/CPP/Common/UTFConvert.h
@@ -0,0 +1,12 @@
+// Common/UTFConvert.h
+
+#ifndef __COMMON_UTF_CONVERT_H
+#define __COMMON_UTF_CONVERT_H
+
+#include "MyString.h"
+
+bool CheckUTF8(const char *src) throw();
+bool ConvertUTF8ToUnicode(const AString &utfString, UString &resultString);
+bool ConvertUnicodeToUTF8(const UString &unicodeString, AString &resultString);
+
+#endif
diff --git a/lzma/CPP/Common/Wildcard.cpp b/lzma/CPP/Common/Wildcard.cpp
new file mode 100644
index 0000000..a7f47c3
--- /dev/null
+++ b/lzma/CPP/Common/Wildcard.cpp
@@ -0,0 +1,615 @@
+// 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)
+ {
+ for (;;)
+ {
+ wchar_t c2 = *s2++; if (c2 == 0) return true;
+ wchar_t c1 = *s1++;
+ if (MyCharUpper(c1) !=
+ MyCharUpper(c2))
+ return false;
+ }
+ }
+
+ for (;;)
+ {
+ wchar_t c2 = *s2++; if (c2 == 0) return true;
+ wchar_t c1 = *s1++; if (c1 != c2) return false;
+ }
+}
+
+int CompareFileNames(const wchar_t *s1, const wchar_t *s2) STRING_UNICODE_THROW
+{
+ if (g_CaseSensitive)
+ return wcscmp(s1, s2);
+ return MyStringCompareNoCase(s1, s2);
+}
+
+#ifndef USE_UNICODE_FSTRING
+int CompareFileNames(const char *s1, const char *s2)
+{
+ if (g_CaseSensitive)
+ return wcscmp(fs2us(s1), fs2us(s2));
+ return MyStringCompareNoCase(fs2us(s1), fs2us(s2));
+}
+#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 (IsCharDirLimiter(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 (IsCharDirLimiter(*(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 (IsCharDirLimiter(*(p - 1)))
+ p--;
+ for (; p != start; p--)
+ if (IsCharDirLimiter(*(p - 1)))
+ break;
+ }
+ dirPrefix.SetFrom(path, (unsigned)(p - start));
+ name = p;
+}
+
+UString ExtractDirPrefixFromPath(const UString &path)
+{
+ const wchar_t *start = path;
+ const wchar_t *p = start + path.Len();
+ for (; p != start; p--)
+ if (IsCharDirLimiter(*(p - 1)))
+ break;
+ return path.Left((unsigned)(p - start));
+}
+
+UString ExtractFileNameFromPath(const UString &path)
+{
+ const wchar_t *start = path;
+ const wchar_t *p = start + path.Len();
+ for (; p != start; p--)
+ if (IsCharDirLimiter(*(p - 1)))
+ break;
+ return p;
+}
+
+
+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 {
+
+
+#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');
+}
+#endif
+
+/*
+
+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;
+ 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)
+{
+ 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();
+
+ // We can't ignore wildcard, since we don't allow wildcard in SubNodes[].Name
+ // if (item.Wildcard)
+ if (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);
+}
+
+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 (IsCharDirLimiter(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;
+}
+
+void CCensor::AddItem(ECensorPathMode pathMode, bool include, const UString &path, bool recursive, bool wildcardMatching)
+{
+ UStringVector pathParts;
+ if (path.IsEmpty())
+ throw "Empty file path";
+ SplitPathToParts(path, pathParts);
+ bool forFile = true;
+ if (pathParts.Back().IsEmpty())
+ {
+ forFile = false;
+ pathParts.DeleteBack();
+ }
+
+ UString prefix;
+
+ if (pathMode != k_AbsPath)
+ {
+ const UString &front = pathParts.Front();
+ bool isAbs = false;
+
+ if (front.IsEmpty())
+ isAbs = true;
+ else
+ {
+ #ifdef _WIN32
+
+ if (IsDriveColonName(front))
+ isAbs = true;
+ else
+
+ #endif
+
+ FOR_VECTOR (i, pathParts)
+ {
+ const UString &part = pathParts[i];
+ if (part == L".." || part == L".")
+ {
+ isAbs = true;
+ break;
+ }
+ }
+ }
+
+ unsigned numAbsParts = 0;
+ if (isAbs)
+ if (pathParts.Size() > 1)
+ numAbsParts = pathParts.Size() - 1;
+ else
+ numAbsParts = 1;
+
+ #ifdef _WIN32
+
+ // \\?\ case
+ if (numAbsParts >= 3)
+ {
+ if (pathParts[0].IsEmpty() &&
+ pathParts[1].IsEmpty() &&
+ pathParts[2] == L"?")
+ {
+ prefix =
+ WSTRING_PATH_SEPARATOR
+ WSTRING_PATH_SEPARATOR L"?"
+ WSTRING_PATH_SEPARATOR;
+ numAbsParts -= 3;
+ pathParts.DeleteFrontal(3);
+ }
+ }
+
+ #endif
+
+ if (numAbsParts > 1 && pathMode == k_FullPath)
+ numAbsParts = 1;
+
+ // We can't ignore wildcard, since we don't allow wildcard in SubNodes[].Name
+ // if (wildcardMatching)
+ for (unsigned i = 0; i < numAbsParts; i++)
+ {
+ {
+ const UString &front = pathParts.Front();
+ if (DoesNameContainWildcard(front))
+ break;
+ prefix += front;
+ prefix += WCHAR_PATH_SEPARATOR;
+ }
+ pathParts.Delete(0);
+ }
+ }
+
+ int index = FindPrefix(prefix);
+ if (index < 0)
+ index = Pairs.Add(CPair(prefix));
+
+ CItem item;
+ item.PathParts = pathParts;
+ item.ForDir = true;
+ item.ForFile = forFile;
+ item.Recursive = recursive;
+ item.WildcardMatching = wildcardMatching;
+ Pairs[index].Head.AddItem(include, item);
+}
+
+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;
+}
+
+}
diff --git a/lzma/CPP/Common/Wildcard.h b/lzma/CPP/Common/Wildcard.h
new file mode 100644
index 0000000..5db765c
--- /dev/null
+++ b/lzma/CPP/Common/Wildcard.h
@@ -0,0 +1,157 @@
+// 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);
+
+inline bool IsCharDirLimiter(wchar_t c)
+{
+ return c == WCHAR_PATH_SEPARATOR
+ #ifdef _WIN32
+ || c == L'/'
+ #endif
+ ;
+}
+
+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);
+#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);
+ bool CheckPathVect(const UStringVector &pathParts, bool isFile, bool &include) const;
+public:
+ CCensorNode(): Parent(0) { };
+ CCensorNode(const UString &name, CCensorNode *parent): Name(name), Parent(parent) { };
+
+ UString Name; // wildcard is not allowed here
+ CObjectVector<CCensorNode> SubNodes;
+ CObjectVector<CItem> IncludeItems;
+ CObjectVector<CItem> ExcludeItems;
+
+ bool AreAllAllowed() const;
+
+ int FindSubNode(const UString &path) const;
+
+ void AddItem(bool include, CItem &item);
+ 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, L"*", false, true);
+ }
+};
+
+
+}
+
+#endif
diff --git a/lzma/CPP/Common/XzCrc64Reg.cpp b/lzma/CPP/Common/XzCrc64Reg.cpp
new file mode 100644
index 0000000..c69d2e3
--- /dev/null
+++ b/lzma/CPP/Common/XzCrc64Reg.cpp
@@ -0,0 +1,54 @@
+// XzCrc64Reg.cpp
+
+#include "StdAfx.h"
+
+#include "../../C/CpuArch.h"
+#include "../../C/XzCrc64.h"
+
+#include "../Common/MyCom.h"
+
+#include "../7zip/ICoder.h"
+#include "../7zip/Common/RegisterCodec.h"
+
+class CXzCrc64Hasher:
+ public IHasher,
+ public CMyUnknownImp
+{
+ UInt64 _crc;
+public:
+ CXzCrc64Hasher(): _crc(CRC64_INIT_VAL) {}
+
+ MY_UNKNOWN_IMP
+
+ STDMETHOD_(void, Init)();
+ STDMETHOD_(void, Update)(const void *data, UInt32 size);
+ STDMETHOD_(void, Final)(Byte *digest);
+ STDMETHOD_(UInt32, GetDigestSize)();
+};
+
+STDMETHODIMP_(void) CXzCrc64Hasher::Init()
+{
+ _crc = CRC64_INIT_VAL;
+}
+
+STDMETHODIMP_(void) CXzCrc64Hasher::Update(const void *data, UInt32 size)
+{
+ _crc = Crc64Update(_crc, data, size);
+}
+
+STDMETHODIMP_(void) CXzCrc64Hasher::Final(Byte *digest)
+{
+ UInt64 val = CRC64_GET_DIGEST(_crc);
+ SetUi64(digest, val);
+}
+
+STDMETHODIMP_(UInt32) CXzCrc64Hasher::GetDigestSize()
+{
+ return 8;
+}
+
+static IHasher *CreateHasher() { return new CXzCrc64Hasher; }
+
+static CHasherInfo g_HasherInfo = { CreateHasher, 0x4, L"CRC64", 8 };
+
+REGISTER_HASHER(Crc64)
diff --git a/lzma/CPP/Windows/COM.h b/lzma/CPP/Windows/COM.h
new file mode 100644
index 0000000..8aa6d28
--- /dev/null
+++ b/lzma/CPP/Windows/COM.h
@@ -0,0 +1,68 @@
+// 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
diff --git a/lzma/CPP/Windows/CommonDialog.cpp b/lzma/CPP/Windows/CommonDialog.cpp
new file mode 100644
index 0000000..60b5b26
--- /dev/null
+++ b/lzma/CPP/Windows/CommonDialog.cpp
@@ -0,0 +1,183 @@
+// Windows/CommonDialog.cpp
+
+#include "StdAfx.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;
+ }
+}
+
+}
diff --git a/lzma/CPP/Windows/CommonDialog.h b/lzma/CPP/Windows/CommonDialog.h
new file mode 100644
index 0000000..2bfec28
--- /dev/null
+++ b/lzma/CPP/Windows/CommonDialog.h
@@ -0,0 +1,23 @@
+// 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
diff --git a/lzma/CPP/Windows/Control/ComboBox.cpp b/lzma/CPP/Windows/Control/ComboBox.cpp
new file mode 100644
index 0000000..ca102f3
--- /dev/null
+++ b/lzma/CPP/Windows/Control/ComboBox.cpp
@@ -0,0 +1,58 @@
+// 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);
+ if (len == CB_ERR)
+ return len;
+ len = GetLBText(index, s.GetBuffer((int)len + 1));
+ s.ReleaseBuffer();
+ return len;
+}
+
+#ifndef _UNICODE
+LRESULT CComboBox::AddString(LPCWSTR s)
+{
+ if (g_IsNT)
+ return SendMessageW(CB_ADDSTRING, 0, (LPARAM)s);
+ return AddString(GetSystemString(s));
+}
+
+LRESULT CComboBox::GetLBText(int index, UString &s)
+{
+ s.Empty();
+ if (g_IsNT)
+ {
+ LRESULT len = SendMessageW(CB_GETLBTEXTLEN, index, 0);
+ if (len == CB_ERR)
+ return len;
+ len = SendMessageW(CB_GETLBTEXT, index, (LPARAM)s.GetBuffer((int)len + 1));
+ s.ReleaseBuffer();
+ return len;
+ }
+ AString sa;
+ LRESULT len = GetLBText(index, sa);
+ if (len == CB_ERR)
+ return len;
+ s = GetUnicodeString(sa);
+ return s.Len();
+}
+#endif
+
+}}
diff --git a/lzma/CPP/Windows/Control/ComboBox.h b/lzma/CPP/Windows/Control/ComboBox.h
new file mode 100644
index 0000000..25e1730
--- /dev/null
+++ b/lzma/CPP/Windows/Control/ComboBox.h
@@ -0,0 +1,63 @@
+// Windows/Control/ComboBox.h
+
+#ifndef __WINDOWS_CONTROL_COMBOBOX_H
+#define __WINDOWS_CONTROL_COMBOBOX_H
+
+#include <commctrl.h>
+
+#include "../Window.h"
+
+namespace NWindows {
+namespace NControl {
+
+class CComboBox: public CWindow
+{
+public:
+ void ResetContent() { SendMessage(CB_RESETCONTENT, 0, 0); }
+ LRESULT AddString(LPCTSTR s) { return SendMessage(CB_ADDSTRING, 0, (LPARAM)s); }
+ #ifndef _UNICODE
+ LRESULT AddString(LPCWSTR s);
+ #endif
+ LRESULT SetCurSel(int index) { return SendMessage(CB_SETCURSEL, index, 0); }
+ int GetCurSel() { return (int)SendMessage(CB_GETCURSEL, 0, 0); }
+ int GetCount() { return (int)SendMessage(CB_GETCOUNT, 0, 0); }
+
+ LRESULT GetLBTextLen(int index) { return SendMessage(CB_GETLBTEXTLEN, index, 0); }
+ LRESULT GetLBText(int index, LPTSTR s) { return SendMessage(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 SendMessage(CB_SETITEMDATA, index, lParam); }
+ LRESULT GetItemData(int index) { return SendMessage(CB_GETITEMDATA, index, 0); }
+
+ LRESULT GetItemData_of_CurSel() { return GetItemData(GetCurSel()); }
+
+ void ShowDropDown(bool show = true) { SendMessage(CB_SHOWDROPDOWN, show ? TRUE : FALSE, 0); }
+};
+
+#ifndef UNDER_CE
+
+class CComboBoxEx: public CComboBox
+{
+public:
+ bool SetUnicodeFormat(bool fUnicode) { return LRESULTToBool(SendMessage(CBEM_SETUNICODEFORMAT, BOOLToBool(fUnicode), 0)); }
+
+ LRESULT DeleteItem(int index) { return SendMessage(CBEM_DELETEITEM, index, 0); }
+ LRESULT InsertItem(COMBOBOXEXITEM *item) { return SendMessage(CBEM_INSERTITEM, 0, (LPARAM)item); }
+ #ifndef _UNICODE
+ LRESULT InsertItem(COMBOBOXEXITEMW *item) { return SendMessage(CBEM_INSERTITEMW, 0, (LPARAM)item); }
+ #endif
+
+ LRESULT SetItem(COMBOBOXEXITEM *item) { return SendMessage(CBEM_SETITEM, 0, (LPARAM)item); }
+ DWORD SetExtendedStyle(DWORD exMask, DWORD exStyle) { return (DWORD)SendMessage(CBEM_SETEXTENDEDSTYLE, exMask, exStyle); }
+ HWND GetEditControl() { return (HWND)SendMessage(CBEM_GETEDITCONTROL, 0, 0); }
+ HIMAGELIST SetImageList(HIMAGELIST imageList) { return (HIMAGELIST)SendMessage(CBEM_SETIMAGELIST, 0, (LPARAM)imageList); }
+};
+
+#endif
+
+}}
+
+#endif
diff --git a/lzma/CPP/Windows/Control/CommandBar.h b/lzma/CPP/Windows/Control/CommandBar.h
new file mode 100644
index 0000000..00c5df7
--- /dev/null
+++ b/lzma/CPP/Windows/Control/CommandBar.h
@@ -0,0 +1,48 @@
+// Windows/Control/CommandBar.h
+
+#ifndef __WINDOWS_CONTROL_COMMANDBAR_H
+#define __WINDOWS_CONTROL_COMMANDBAR_H
+
+#ifdef UNDER_CE
+
+#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(SendMessage(TB_ADDBUTTONS, (WPARAM)numButtons, (LPARAM)buttons)); }
+ bool InsertButton(int iButton, LPTBBUTTON button) { return BOOLToBool(SendMessage(TB_INSERTBUTTON, (WPARAM)iButton, (LPARAM)button)); }
+ BOOL AddToolTips(UINT numToolTips, LPTSTR toolTips) { return BOOLToBool(SendMessage(TB_SETTOOLTIPS, (WPARAM)numToolTips, (LPARAM)toolTips)); }
+ void AutoSize() { SendMessage(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/lzma/CPP/Windows/Control/Dialog.cpp b/lzma/CPP/Windows/Control/Dialog.cpp
new file mode 100644
index 0000000..c8a09ed
--- /dev/null
+++ b/lzma/CPP/Windows/Control/Dialog.cpp
@@ -0,0 +1,250 @@
+// 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 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
+
+}}
diff --git a/lzma/CPP/Windows/Control/Dialog.h b/lzma/CPP/Windows/Control/Dialog.h
new file mode 100644
index 0000000..66530e5
--- /dev/null
+++ b/lzma/CPP/Windows/Control/Dialog.h
@@ -0,0 +1,167 @@
+// 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 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(); }
+};
+
+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); }
+};
+
+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
diff --git a/lzma/CPP/Windows/Control/Edit.h b/lzma/CPP/Windows/Control/Edit.h
new file mode 100644
index 0000000..40e3899
--- /dev/null
+++ b/lzma/CPP/Windows/Control/Edit.h
@@ -0,0 +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) { SendMessage(EM_SETPASSWORDCHAR, c); }
+};
+
+}}
+
+#endif
diff --git a/lzma/CPP/Windows/Control/ImageList.cpp b/lzma/CPP/Windows/Control/ImageList.cpp
new file mode 100644
index 0000000..d201c8f
--- /dev/null
+++ b/lzma/CPP/Windows/Control/ImageList.cpp
@@ -0,0 +1,10 @@
+// Windows/Control/ImageList.cpp
+
+#include "StdAfx.h"
+
+#include "ImageList.h"
+
+namespace NWindows {
+namespace NControl {
+
+}}
diff --git a/lzma/CPP/Windows/Control/ImageList.h b/lzma/CPP/Windows/Control/ImageList.h
new file mode 100644
index 0000000..f72ea0d
--- /dev/null
+++ b/lzma/CPP/Windows/Control/ImageList.h
@@ -0,0 +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
diff --git a/lzma/CPP/Windows/Control/ListView.cpp b/lzma/CPP/Windows/Control/ListView.cpp
new file mode 100644
index 0000000..fb22f95
--- /dev/null
+++ b/lzma/CPP/Windows/Control/ListView.cpp
@@ -0,0 +1,155 @@
+// 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 ¶m) 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;
+}
+*/
+
+}}
diff --git a/lzma/CPP/Windows/Control/ListView.h b/lzma/CPP/Windows/Control/ListView.h
new file mode 100644
index 0000000..6897c81
--- /dev/null
+++ b/lzma/CPP/Windows/Control/ListView.h
@@ -0,0 +1,132 @@
+// Windows/Control/ListView.h
+
+#ifndef __WINDOWS_CONTROL_LISTVIEW_H
+#define __WINDOWS_CONTROL_LISTVIEW_H
+
+#include "../Window.h"
+
+#include <commctrl.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);
+ 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)SendMessage(LVM_INSERTCOLUMNW, (WPARAM)columnIndex, (LPARAM)columnInfo); }
+ int InsertColumn(int columnIndex, LPCWSTR text, int width);
+ int InsertItem(const LV_ITEMW* item) { return (int)SendMessage(LVM_INSERTITEMW, 0, (LPARAM)item); }
+ int InsertItem(int index, LPCWSTR text);
+ bool SetItem(const LV_ITEMW* item) { return BOOLToBool((BOOL)SendMessage(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 ¶m) 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
diff --git a/lzma/CPP/Windows/Control/ProgressBar.h b/lzma/CPP/Windows/Control/ProgressBar.h
new file mode 100644
index 0000000..71dc912
--- /dev/null
+++ b/lzma/CPP/Windows/Control/ProgressBar.h
@@ -0,0 +1,31 @@
+// Windows/Control/ProgressBar.h
+
+#ifndef __WINDOWS_CONTROL_PROGRESSBAR_H
+#define __WINDOWS_CONTROL_PROGRESSBAR_H
+
+#include "../Window.h"
+
+namespace NWindows {
+namespace NControl {
+
+class CProgressBar: public CWindow
+{
+public:
+ LRESULT SetPos(int pos) { return SendMessage(PBM_SETPOS, pos, 0); }
+ LRESULT DeltaPos(int increment) { return SendMessage(PBM_DELTAPOS, increment, 0); }
+ UINT GetPos() { return (UINT)SendMessage(PBM_GETPOS, 0, 0); }
+ LRESULT SetRange(unsigned short minValue, unsigned short maxValue) { return SendMessage(PBM_SETRANGE, 0, MAKELPARAM(minValue, maxValue)); }
+ DWORD SetRange32(int minValue, int maxValue) { return (DWORD)SendMessage(PBM_SETRANGE32, minValue, maxValue); }
+ int SetStep(int step) { return (int)SendMessage(PBM_SETSTEP, step, 0); }
+ LRESULT StepIt() { return SendMessage(PBM_STEPIT, 0, 0); }
+ INT GetRange(bool minValue, PPBRANGE range) { return (INT)SendMessage(PBM_GETRANGE, BoolToBOOL(minValue), (LPARAM)range); }
+
+ #ifndef UNDER_CE
+ COLORREF SetBarColor(COLORREF color) { return (COLORREF)SendMessage(PBM_SETBARCOLOR, 0, color); }
+ COLORREF SetBackgroundColor(COLORREF color) { return (COLORREF)SendMessage(PBM_SETBKCOLOR, 0, color); }
+ #endif
+};
+
+}}
+
+#endif
diff --git a/lzma/CPP/Windows/Control/PropertyPage.cpp b/lzma/CPP/Windows/Control/PropertyPage.cpp
new file mode 100644
index 0000000..6d940c8
--- /dev/null
+++ b/lzma/CPP/Windows/Control/PropertyPage.cpp
@@ -0,0 +1,143 @@
+// 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);
+ }
+}
+
+}}
diff --git a/lzma/CPP/Windows/Control/PropertyPage.h b/lzma/CPP/Windows/Control/PropertyPage.h
new file mode 100644
index 0000000..053de09
--- /dev/null
+++ b/lzma/CPP/Windows/Control/PropertyPage.h
@@ -0,0 +1,48 @@
+// Windows/Control/PropertyPage.h
+
+#ifndef __WINDOWS_CONTROL_PROPERTYPAGE_H
+#define __WINDOWS_CONTROL_PROPERTYPAGE_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
diff --git a/lzma/CPP/Windows/Control/ReBar.h b/lzma/CPP/Windows/Control/ReBar.h
new file mode 100644
index 0000000..cf47bf4
--- /dev/null
+++ b/lzma/CPP/Windows/Control/ReBar.h
@@ -0,0 +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(SendMessage(RB_SETBARINFO, 0, (LPARAM)barInfo)); }
+ bool InsertBand(int index, LPREBARBANDINFO bandInfo)
+ { return LRESULTToBool(SendMessage(RB_INSERTBAND, index, (LPARAM)bandInfo)); }
+ bool SetBandInfo(unsigned index, LPREBARBANDINFO bandInfo)
+ { return LRESULTToBool(SendMessage(RB_SETBANDINFO, index, (LPARAM)bandInfo)); }
+ void MaximizeBand(unsigned index, bool ideal)
+ { SendMessage(RB_MAXIMIZEBAND, index, BoolToBOOL(ideal)); }
+ bool SizeToRect(LPRECT rect)
+ { return LRESULTToBool(SendMessage(RB_SIZETORECT, 0, (LPARAM)rect)); }
+ UINT GetHeight()
+ { return (UINT)SendMessage(RB_GETBARHEIGHT); }
+ UINT GetBandCount()
+ { return (UINT)SendMessage(RB_GETBANDCOUNT); }
+ bool DeleteBand(UINT index)
+ { return LRESULTToBool(SendMessage(RB_DELETEBAND, index)); }
+};
+
+}}
+
+#endif
diff --git a/lzma/CPP/Windows/Control/Static.h b/lzma/CPP/Windows/Control/Static.h
new file mode 100644
index 0000000..355b9e8
--- /dev/null
+++ b/lzma/CPP/Windows/Control/Static.h
@@ -0,0 +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)SendMessage(STM_SETIMAGE, imageType, (LPARAM)handle); }
+ HANDLE GetImage(WPARAM imageType) { return (HANDLE)SendMessage(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)SendMessage(STM_SETICON, (WPARAM)icon, 0); }
+ HICON GetIcon() { return (HICON)SendMessage(STM_GETICON, 0, 0); }
+ #endif
+};
+
+}}
+
+#endif
diff --git a/lzma/CPP/Windows/Control/StatusBar.h b/lzma/CPP/Windows/Control/StatusBar.h
new file mode 100644
index 0000000..9185c42
--- /dev/null
+++ b/lzma/CPP/Windows/Control/StatusBar.h
@@ -0,0 +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(SendMessage(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(SendMessage(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(SendMessage(SB_SETPARTS, numParts, (LPARAM)edgePostions)); }
+ void Simple(bool simple)
+ { SendMessage(SB_SIMPLE, BoolToBOOL(simple), 0); }
+};
+
+}}
+
+#endif
diff --git a/lzma/CPP/Windows/Control/StdAfx.h b/lzma/CPP/Windows/Control/StdAfx.h
new file mode 100644
index 0000000..42a088f
--- /dev/null
+++ b/lzma/CPP/Windows/Control/StdAfx.h
@@ -0,0 +1,8 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "../../Common/Common.h"
+
+#endif
diff --git a/lzma/CPP/Windows/Control/ToolBar.h b/lzma/CPP/Windows/Control/ToolBar.h
new file mode 100644
index 0000000..6bc4443
--- /dev/null
+++ b/lzma/CPP/Windows/Control/ToolBar.h
@@ -0,0 +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() { SendMessage(TB_AUTOSIZE, 0, 0); }
+ DWORD GetButtonSize() { return (DWORD)SendMessage(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(SendMessage(TB_GETMAXSIZE, 0, (LPARAM)size));
+ }
+ #endif
+
+ bool EnableButton(UINT buttonID, bool enable) { return LRESULTToBool(SendMessage(TB_ENABLEBUTTON, buttonID, MAKELONG(BoolToBOOL(enable), 0))); }
+ void ButtonStructSize() { SendMessage(TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON)); }
+ HIMAGELIST SetImageList(UINT listIndex, HIMAGELIST imageList) { return HIMAGELIST(SendMessage(TB_SETIMAGELIST, listIndex, (LPARAM)imageList)); }
+ bool AddButton(UINT numButtons, LPTBBUTTON buttons) { return LRESULTToBool(SendMessage(TB_ADDBUTTONS, numButtons, (LPARAM)buttons)); }
+ #ifndef _UNICODE
+ bool AddButtonW(UINT numButtons, LPTBBUTTON buttons) { return LRESULTToBool(SendMessage(TB_ADDBUTTONSW, numButtons, (LPARAM)buttons)); }
+ #endif
+};
+
+}}
+
+#endif
diff --git a/lzma/CPP/Windows/Control/Trackbar.h b/lzma/CPP/Windows/Control/Trackbar.h
new file mode 100644
index 0000000..da1936b
--- /dev/null
+++ b/lzma/CPP/Windows/Control/Trackbar.h
@@ -0,0 +1,28 @@
+// Windows/Control/Trackbar.h
+
+#ifndef __WINDOWS_CONTROL_TRACKBAR_H
+#define __WINDOWS_CONTROL_TRACKBAR_H
+
+#include "../Window.h"
+#include "../Defs.h"
+
+namespace NWindows {
+namespace NControl {
+
+class CTrackbar1: public CWindow
+{
+public:
+ void SetRange(int minimum, int maximum, bool redraw = true)
+ { SendMessage(TBM_SETRANGE, BoolToBOOL(redraw), MAKELONG(minimum, maximum)); }
+ void SetPos(int pos, bool redraw = true)
+ { SendMessage(TBM_SETPOS, BoolToBOOL(redraw), pos); }
+ void SetTicFreq(int freq)
+ { SendMessage(TBM_SETTICFREQ, freq); }
+
+ int GetPos()
+ { return (int)SendMessage(TBM_GETPOS); }
+};
+
+}}
+
+#endif
diff --git a/lzma/CPP/Windows/Control/Window2.cpp b/lzma/CPP/Windows/Control/Window2.cpp
new file mode 100644
index 0000000..2588c3a
--- /dev/null
+++ b/lzma/CPP/Windows/Control/Window2.cpp
@@ -0,0 +1,200 @@
+// 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(aButtonID)
+ {
+ case IDOK:
+ OnOK();
+ break;
+ case IDCANCEL:
+ OnCancel();
+ break;
+ case IDHELP:
+ OnHelp();
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+*/
+
+}}
diff --git a/lzma/CPP/Windows/Control/Window2.h b/lzma/CPP/Windows/Control/Window2.h
new file mode 100644
index 0000000..f565daa
--- /dev/null
+++ b/lzma/CPP/Windows/Control/Window2.h
@@ -0,0 +1,51 @@
+// 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
diff --git a/lzma/CPP/Windows/DLL.cpp b/lzma/CPP/Windows/DLL.cpp
new file mode 100644
index 0000000..5485ba3
--- /dev/null
+++ b/lzma/CPP/Windows/DLL.cpp
@@ -0,0 +1,110 @@
+// 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(FCHAR_PATH_SEPARATOR);
+ if (pos >= 0)
+ {
+ s.DeleteFrom(pos + 1);
+ return s;
+ }
+ }
+ return FTEXT(".") FSTRING_PATH_SEPARATOR;
+}
+
+#endif
+
+}}
diff --git a/lzma/CPP/Windows/DLL.h b/lzma/CPP/Windows/DLL.h
new file mode 100644
index 0000000..e61cf89
--- /dev/null
+++ b/lzma/CPP/Windows/DLL.h
@@ -0,0 +1,52 @@
+// 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
+
+class CLibrary
+{
+ HMODULE _module;
+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
diff --git a/lzma/CPP/Windows/Defs.h b/lzma/CPP/Windows/Defs.h
new file mode 100644
index 0000000..f3d692f
--- /dev/null
+++ b/lzma/CPP/Windows/Defs.h
@@ -0,0 +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
diff --git a/lzma/CPP/Windows/ErrorMsg.cpp b/lzma/CPP/Windows/ErrorMsg.cpp
new file mode 100644
index 0000000..e929e75
--- /dev/null
+++ b/lzma/CPP/Windows/ErrorMsg.cpp
@@ -0,0 +1,61 @@
+// 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 message;
+ if (!MyFormatMessage(errorCode, message))
+ {
+ wchar_t s[16];
+ for (int i = 0; i < 8; i++)
+ {
+ unsigned t = errorCode & 0xF;
+ errorCode >>= 4;
+ s[7 - i] = (wchar_t)((t < 10) ? ('0' + t) : ('A' + (t - 10)));
+ }
+ s[8] = '\0';
+ message = (UString)L"Error #" + s;
+ }
+ return message;
+}
+
+}}
diff --git a/lzma/CPP/Windows/ErrorMsg.h b/lzma/CPP/Windows/ErrorMsg.h
new file mode 100644
index 0000000..e05e950
--- /dev/null
+++ b/lzma/CPP/Windows/ErrorMsg.h
@@ -0,0 +1,15 @@
+// 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
diff --git a/lzma/CPP/Windows/FileDir.cpp b/lzma/CPP/Windows/FileDir.cpp
new file mode 100644
index 0000000..c215657
--- /dev/null
+++ b/lzma/CPP/Windows/FileDir.cpp
@@ -0,0 +1,583 @@
+// 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 longPath;
+ if (GetSuperPath(path, longPath, USE_MAIN_PATH))
+ hDir = ::CreateFileW(longPath, 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 longPath;
+ if (GetSuperPath(path, longPath, USE_MAIN_PATH))
+ return BOOLToBool(::SetFileAttributesW(longPath, attrib));
+ }
+ #endif
+ }
+ return false;
+}
+
+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 longPath;
+ if (GetSuperPath(path, longPath, USE_MAIN_PATH))
+ return BOOLToBool(::RemoveDirectoryW(longPath));
+ }
+ #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
+
+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 longPath;
+ if (GetSuperPath(path, longPath, USE_MAIN_PATH))
+ return BOOLToBool(::CreateDirectoryW(longPath, NULL));
+ }
+ #endif
+ }
+ return false;
+}
+
+bool CreateComplexDir(CFSTR _aPathName)
+{
+ FString pathName = _aPathName;
+ int pos = pathName.ReverseFind(FCHAR_PATH_SEPARATOR);
+ if (pos > 0 && (unsigned)pos == pathName.Len() - 1)
+ {
+ if (pathName.Len() == 3 && pathName[1] == L':')
+ return true; // Disk folder;
+ pathName.Delete(pos);
+ }
+ const FString pathName2 = pathName;
+ pos = pathName.Len();
+
+ for (;;)
+ {
+ if (CreateDir(pathName))
+ break;
+ if (::GetLastError() == ERROR_ALREADY_EXISTS)
+ {
+ NFind::CFileInfo fileInfo;
+ if (!fileInfo.Find(pathName)) // For network folders
+ return true;
+ if (!fileInfo.IsDir())
+ return false;
+ break;
+ }
+ pos = pathName.ReverseFind(FCHAR_PATH_SEPARATOR);
+ if (pos < 0 || pos == 0)
+ return false;
+ if (pathName[pos - 1] == L':')
+ return false;
+ pathName.DeleteFrom(pos);
+ }
+
+ while (pos < (int)pathName2.Len())
+ {
+ pos = pathName2.Find(FCHAR_PATH_SEPARATOR, pos + 1);
+ if (pos < 0)
+ pos = pathName2.Len();
+ pathName.SetFrom(pathName2, pos);
+ if (!CreateDir(pathName))
+ return false;
+ }
+
+ return true;
+}
+
+bool DeleteFileAlways(CFSTR path)
+{
+ if (!SetFileAttrib(path, 0))
+ return false;
+ #ifndef _UNICODE
+ if (!g_IsNT)
+ {
+ if (::DeleteFile(fs2fas(path)))
+ return true;
+ }
+ else
+ #endif
+ {
+ IF_USE_MAIN_PATH
+ if (::DeleteFileW(fs2us(path)))
+ return true;
+ #ifdef WIN_LONG_PATH
+ if (USE_SUPER_PATH)
+ {
+ UString longPath;
+ if (GetSuperPath(path, longPath, USE_MAIN_PATH))
+ return BOOLToBool(::DeleteFileW(longPath));
+ }
+ #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 += FCHAR_PATH_SEPARATOR;
+ unsigned prefixSize = s.Len();
+ s += FCHAR_ANY_MASK;
+ NFind::CEnumerator enumerator(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(FCHAR_PATH_SEPARATOR);
+ 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)
+ {
+ FChar s[16];
+ UInt32 value = d;
+ unsigned k;
+ for (k = 0; k < 8; k++)
+ {
+ unsigned t = value & 0xF;
+ value >>= 4;
+ s[k] = (char)((t < 10) ? ('0' + t) : ('A' + (t - 10)));
+ }
+ s[k] = '\0';
+ if (outFile)
+ path += FChar('.');
+ path += s;
+ UInt32 step = GetTickCount() + 2;
+ if (step == 0)
+ step = 1;
+ d += step;
+ }
+ addRandom = true;
+ if (outFile)
+ path += FTEXT(".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)
+{
+ if (deleteDestBefore)
+ if (NFind::DoesFileExist(name))
+ if (!DeleteFileAlways(name))
+ return false;
+ DisableDeleting();
+ return MyMoveFile(_path, name);
+}
+
+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;
+}
+
+}}}
diff --git a/lzma/CPP/Windows/FileDir.h b/lzma/CPP/Windows/FileDir.h
new file mode 100644
index 0000000..1c75788
--- /dev/null
+++ b/lzma/CPP/Windows/FileDir.h
@@ -0,0 +1,97 @@
+// 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);
+bool MyMoveFile(CFSTR existFileName, CFSTR newFileName);
+
+#ifndef UNDER_CE
+bool MyCreateHardLink(CFSTR newFileName, CFSTR existFileName);
+#endif
+
+bool RemoveDir(CFSTR path);
+bool CreateDir(CFSTR path);
+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
diff --git a/lzma/CPP/Windows/FileFind.cpp b/lzma/CPP/Windows/FileFind.cpp
new file mode 100644
index 0000000..35c0bf6
--- /dev/null
+++ b/lzma/CPP/Windows/FileFind.cpp
@@ -0,0 +1,579 @@
+// Windows/FileFind.cpp
+
+#include "StdAfx.h"
+
+#include "FileFind.h"
+#include "FileIO.h"
+#include "FileName.h"
+#ifndef _UNICODE
+#include "../Common/StringConvert.h"
+#endif
+
+#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] != FTEXT('.'))
+ return false;
+ return Name.Len() == 1 || (Name.Len() == 2 && Name[1] == FTEXT('.'));
+}
+
+#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;
+}
+
+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 longPath;
+ if (GetSuperPath(path, longPath, USE_MAIN_PATH))
+ _handle = ::FindFirstFileW(longPath, &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 Name == L"::$DATA";
+};
+
+UString CStreamInfo::GetReducedName() const
+{
+ UString s = Name;
+ if (s.Len() >= 6)
+ if (wcscmp(s.RightPtr(6), L":$DATA") == 0)
+ s.DeleteFrom(s.Len() - 6);
+ 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;
+}
+
+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;
+ 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 longPath;
+ if (GetSuperPath(path, longPath, USE_MAIN_PATH))
+ _handle = g_FindFirstStreamW(longPath, 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::Clear() throw()
+{
+ Size = 0;
+ MY_CLEAR_FILETIME(CTime);
+ MY_CLEAR_FILETIME(ATime);
+ MY_CLEAR_FILETIME(MTime);
+ Attrib = 0;
+ IsAltStream = false;
+ IsDevice = false;
+}
+
+#if defined(_WIN32) && !defined(UNDER_CE)
+
+static int FindAltStreamColon(CFSTR path)
+{
+ for (int i = 0;; i++)
+ {
+ FChar c = path[i];
+ if (c == 0)
+ return -1;
+ if (c == ':')
+ {
+ if (path[i + 1] == '\\')
+ if (i == 1 || (i > 1 && path[i - 2] == '\\'))
+ {
+ wchar_t c0 = path[i - 1];
+ if (c0 >= 'a' && c0 <= 'z' ||
+ c0 >= 'A' && c0 <= 'Z')
+ continue;
+ }
+ return i;
+ }
+ }
+}
+
+#endif
+
+bool CFileInfo::Find(CFSTR path)
+{
+ #ifdef SUPPORT_DEVICE_FILE
+ if (IsDevicePath(path))
+ {
+ Clear();
+ Name = path + 4;
+
+ IsDevice = true;
+ if (/* path[0] == '\\' && path[1] == '\\' && path[2] == '.' && path[3] == '\\' && */
+ path[5] == ':' && 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)
+ {
+ UString streamName = fs2us(path + (unsigned)colonPos);
+ FString filePath = path;
+ filePath.DeleteFrom(colonPos);
+ streamName += L":$DATA"; // change it!!!!
+ if (Find(filePath))
+ {
+ // if (IsDir())
+ Attrib &= ~FILE_ATTRIBUTE_DIRECTORY;
+ 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.IsEqualToNoCase(streamName))
+ {
+ Name += us2fs(si.Name);
+ Name.DeleteFrom(Name.Len() - 6);
+ Size = si.Size;
+ IsAltStream = true;
+ return true;
+ }
+ }
+ }
+ }
+
+ #endif
+
+ CFindFile finder;
+ if (finder.FindFirst(path, *this))
+ return true;
+ #ifdef _WIN32
+ {
+ DWORD lastError = GetLastError();
+ if (lastError == ERROR_BAD_NETPATH ||
+ lastError == ERROR_FILE_NOT_FOUND ||
+ lastError == ERROR_INVALID_NAME // for "\\SERVER\shared" paths that are translated to "\\?\UNC\SERVER\shared"
+ )
+ {
+ unsigned len = MyStringLen(path);
+ if (len > 2 && path[0] == '\\' && path[1] == '\\')
+ {
+ int startPos = 2;
+ if (len > kSuperUncPathPrefixSize && IsSuperUncPath(path))
+ startPos = kSuperUncPathPrefixSize;
+ int pos = FindCharPosInString(path + startPos, FTEXT('\\'));
+ if (pos >= 0)
+ {
+ pos += startPos + 1;
+ len -= pos;
+ int pos2 = FindCharPosInString(path + pos, FTEXT('\\'));
+ if (pos2 < 0 || pos2 == (int)len - 1)
+ {
+ FString s = path;
+ if (pos2 < 0)
+ {
+ pos2 = len;
+ s += FTEXT('\\');
+ }
+ s += FCHAR_ANY_MASK;
+ if (finder.FindFirst(s, *this))
+ if (Name == FTEXT("."))
+ {
+ Name.SetFrom(s.Ptr(pos), pos2);
+ return true;
+ }
+ ::SetLastError(lastError);
+ }
+ }
+ }
+ }
+ }
+ #endif
+ return false;
+}
+
+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);
+}
+
+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 longPath;
+ if (GetSuperPath(path, longPath, USE_MAIN_PATH))
+ _handle = ::FindFirstChangeNotificationW(longPath, 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;
+ AString buf;
+ UINT32 newSize = GetLogicalDriveStrings(size, buf.GetBuffer(size));
+ if (newSize == 0 || newSize > size)
+ return false;
+ AString s;
+ for (UINT32 i = 0; i < newSize; i++)
+ {
+ char c = buf[i];
+ if (c == '\0')
+ {
+ driveStrings.Add(fas2fs(s));
+ s.Empty();
+ }
+ else
+ s += c;
+ }
+ return s.IsEmpty();
+ }
+ else
+ #endif
+ {
+ UINT32 size = GetLogicalDriveStringsW(0, NULL);
+ if (size == 0)
+ return false;
+ UString buf;
+ UINT32 newSize = GetLogicalDriveStringsW(size, buf.GetBuffer(size));
+ if (newSize == 0 || newSize > size)
+ return false;
+ UString s;
+ for (UINT32 i = 0; i < newSize; i++)
+ {
+ WCHAR c = buf[i];
+ if (c == L'\0')
+ {
+ driveStrings.Add(us2fs(s));
+ s.Empty();
+ }
+ else
+ s += c;
+ }
+ return s.IsEmpty();
+ }
+}
+
+#endif
+
+}}}
diff --git a/lzma/CPP/Windows/FileFind.h b/lzma/CPP/Windows/FileFind.h
new file mode 100644
index 0000000..1325253
--- /dev/null
+++ b/lzma/CPP/Windows/FileFind.h
@@ -0,0 +1,158 @@
+// 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() { Clear(); }
+ void Clear() 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 wildcard);
+};
+
+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;
+ 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);
+
+class CEnumerator
+{
+ CFindFile _findFile;
+ FString _wildcard;
+
+ bool NextAny(CFileInfo &fileInfo);
+public:
+ CEnumerator(const FString &wildcard): _wildcard(wildcard) {}
+ 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
diff --git a/lzma/CPP/Windows/FileIO.cpp b/lzma/CPP/Windows/FileIO.cpp
new file mode 100644
index 0000000..3dcf5c1
--- /dev/null
+++ b/lzma/CPP/Windows/FileIO.cpp
@@ -0,0 +1,432 @@
+// 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)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();
+}
+
+}}}
diff --git a/lzma/CPP/Windows/FileIO.h b/lzma/CPP/Windows/FileIO.h
new file mode 100644
index 0000000..96691b9
--- /dev/null
+++ b/lzma/CPP/Windows/FileIO.h
@@ -0,0 +1,201 @@
+// Windows/FileIO.h
+
+#ifndef __WINDOWS_FILE_IO_H
+#define __WINDOWS_FILE_IO_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) {}
+ bool Parse(const Byte *p, size_t size);
+
+ 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)
+ {
+ return 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
diff --git a/lzma/CPP/Windows/FileLink.cpp b/lzma/CPP/Windows/FileLink.cpp
new file mode 100644
index 0000000..1bd1d52
--- /dev/null
+++ b/lzma/CPP/Windows/FileLink.cpp
@@ -0,0 +1,426 @@
+// 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 *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 *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;
+ }
+}
+
+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;
+}
+
+static void GetString(const Byte *p, unsigned len, UString &res)
+{
+ wchar_t *s = res.GetBuffer(len);
+ for (unsigned i = 0; i < len; i++)
+ s[i] = Get16(p + i * 2);
+ s[len] = 0;
+ res.ReleaseBuffer();
+}
+
+bool CReparseAttr::Parse(const Byte *p, size_t size)
+{
+ 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)
+ // 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;
+
+ 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);
+
+ 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(FCHAR_PATH_SEPARATOR);
+ 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
+
+}}
diff --git a/lzma/CPP/Windows/FileMapping.cpp b/lzma/CPP/Windows/FileMapping.cpp
new file mode 100644
index 0000000..01c4a94
--- /dev/null
+++ b/lzma/CPP/Windows/FileMapping.cpp
@@ -0,0 +1,12 @@
+// Windows/FileMapping.cpp
+
+#include "StdAfx.h"
+
+#include "FileMapping.h"
+
+namespace NWindows {
+namespace NFile {
+namespace NMapping {
+
+
+}}}
diff --git a/lzma/CPP/Windows/FileMapping.h b/lzma/CPP/Windows/FileMapping.h
new file mode 100644
index 0000000..27d076b
--- /dev/null
+++ b/lzma/CPP/Windows/FileMapping.h
@@ -0,0 +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
diff --git a/lzma/CPP/Windows/FileName.cpp b/lzma/CPP/Windows/FileName.cpp
new file mode 100644
index 0000000..9189ceb
--- /dev/null
+++ b/lzma/CPP/Windows/FileName.cpp
@@ -0,0 +1,687 @@
+// Windows/FileName.cpp
+
+#include "StdAfx.h"
+
+#include "FileName.h"
+
+#ifndef _UNICODE
+extern bool g_IsNT;
+#endif
+
+namespace NWindows {
+namespace NFile {
+namespace NName {
+
+#ifndef USE_UNICODE_FSTRING
+void NormalizeDirPathPrefix(FString &dirPath)
+{
+ if (dirPath.IsEmpty())
+ return;
+ if (dirPath.Back() != FCHAR_PATH_SEPARATOR)
+ dirPath += FCHAR_PATH_SEPARATOR;
+}
+#endif
+
+void NormalizeDirPathPrefix(UString &dirPath)
+{
+ if (dirPath.IsEmpty())
+ return;
+ if (dirPath.Back() != WCHAR_PATH_SEPARATOR)
+ dirPath += WCHAR_PATH_SEPARATOR;
+}
+
+
+#ifdef _WIN32
+
+const wchar_t *kSuperPathPrefix = L"\\\\?\\";
+static const wchar_t *kSuperUncPrefix = L"\\\\?\\UNC\\";
+
+#define IS_DEVICE_PATH(s) ((s)[0] == '\\' && (s)[1] == '\\' && (s)[2] == '.' && (s)[3] == '\\')
+#define IS_SUPER_PREFIX(s) ((s)[0] == '\\' && (s)[1] == '\\' && (s)[2] == '?' && (s)[3] == '\\')
+#define IS_SUPER_OR_DEVICE_PATH(s) ((s)[0] == '\\' && (s)[1] == '\\' && ((s)[2] == '?' || (s)[2] == '.') && (s)[3] == '\\')
+#define IS_LETTER_CHAR(c) ((c) >= 'a' && (c) <= 'z' || (c) >= 'A' && (c) <= 'Z')
+
+#define IS_UNC_WITH_SLASH(s) ( \
+ ((s)[0] == 'U' || (s)[0] == 'u') && \
+ ((s)[1] == 'N' || (s)[1] == 'n') && \
+ ((s)[2] == 'C' || (s)[2] == 'c') && \
+ (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 || memcmp(s, FTEXT("DSK"), 3 * sizeof(FChar)) != 0)
+ 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 || memcmp(s + kDevicePathPrefixSize, FTEXT("PhysicalDrive"), 13 * sizeof(FChar)) != 0)
+ 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 IsDrivePath(const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && s[2] == '\\'; }
+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) { return (IS_SUPER_PREFIX(s) && IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize)); }
+
+#ifndef USE_UNICODE_FSTRING
+bool IsDrivePath(CFSTR s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && 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 IsAbsolutePath(const wchar_t *s) throw()
+{
+ return s[0] == WCHAR_PATH_SEPARATOR || IsDrivePath(s);
+}
+
+static const unsigned kDrivePrefixSize = 3; /* c:\ */
+
+#ifndef USE_UNICODE_FSTRING
+
+static unsigned GetRootPrefixSize_Of_NetworkPath(CFSTR s) throw()
+{
+ // Network path: we look "server\path\" as root prefix
+ int pos = FindCharPosInString(s, '\\');
+ if (pos < 0)
+ return 0;
+ int pos2 = FindCharPosInString(s + pos + 1, '\\');
+ if (pos2 < 0)
+ return 0;
+ return pos + pos2 + 2;
+}
+
+static unsigned GetRootPrefixSize_Of_SimplePath(CFSTR s) throw()
+{
+ if (IsDrivePath(s))
+ return kDrivePrefixSize;
+ if (s[0] != '\\' || s[1] != '\\')
+ return 0;
+ unsigned size = GetRootPrefixSize_Of_NetworkPath(s + 2);
+ return (size == 0) ? 0 : 2 + size;
+}
+
+static unsigned GetRootPrefixSize_Of_SuperPath(CFSTR 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 = FindCharPosInString(s + kSuperPathPrefixSize, FCHAR_PATH_SEPARATOR);
+ 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 = FindCharPosInString(s, L'\\');
+ if (pos < 0)
+ return 0;
+ int pos2 = FindCharPosInString(s + pos + 1, L'\\');
+ 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 (s[0] != '\\' || s[1] != '\\')
+ return 0;
+ 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 = FindCharPosInString(s + kSuperPathPrefixSize, L'\\');
+ 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) throw() { return s[0] == WCHAR_PATH_SEPARATOR }
+
+#ifndef USE_UNICODE_FSTRING
+unsigned GetRootPrefixSize(CFSTR s) throw() { return s[0] == CHAR_PATH_SEPRATOR ? 1 : 0; }
+#endif
+unsigned GetRootPrefixSize(const wchar_t *s) throw() { return s[0] == CHAR_PATH_SEPRATOR ? 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 (int i = 0;;)
+ {
+ wchar_t c = s[i];
+ if (c == 0)
+ return true;
+ if (c == '.' && (i == 0 || s[i - 1] == WCHAR_PATH_SEPARATOR))
+ {
+ wchar_t c1 = s[i + 1];
+ if (c1 == '.')
+ {
+ wchar_t c2 = s[i + 2];
+ if (c2 == WCHAR_PATH_SEPARATOR || c2 == 0)
+ {
+ if (i == 0)
+ return false;
+ int k = i - 2;
+ for (; k >= 0; k--)
+ if (s[k] == WCHAR_PATH_SEPARATOR)
+ break;
+ unsigned num;
+ if (k >= 0)
+ {
+ num = i + 2 - k;
+ i = k;
+ }
+ else
+ {
+ num = (c2 == 0 ? (i + 2) : (i + 3));
+ i = 0;
+ }
+ s.Delete(i, num);
+ continue;
+ }
+ }
+ else
+ {
+ if (c1 == WCHAR_PATH_SEPARATOR || 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 || s[i - 1] == CHAR_PATH_SEPARATOR))
+ {
+ FChar c1 = s[i + 1];
+ if (c1 == 0 || c1 == CHAR_PATH_SEPARATOR ||
+ (c1 == '.' && (s[i + 2] == 0 || s[i + 2] == CHAR_PATH_SEPARATOR)))
+ 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 || c2 == CHAR_PATH_SEPARATOR)
+ {
+ // if it's "." or "..", it's not bad name.
+ if (c == '.')
+ {
+ if (i == 0 || s[i - 1] == CHAR_PATH_SEPARATOR)
+ continue;
+ if (s[i - 1] == '.')
+ {
+ if (i - 1 == 0 || s[i - 2] == CHAR_PATH_SEPARATOR)
+ 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 (c == CHAR_PATH_SEPARATOR)
+ {
+ if (s[1] == CHAR_PATH_SEPARATOR)
+ {
+ UString temp = fs2us(s + 2);
+ unsigned fixedSize = GetRootPrefixSize_Of_NetworkPath(temp);
+ if (fixedSize == 0) // maybe we must ignore that error to allow short network paths?
+ return false;
+ UString rem = &temp[fixedSize];
+ if (!ResolveDotsFolders(rem))
+ return false;
+ res += kSuperUncPrefix;
+ temp.DeleteFrom(fixedSize);
+ res += temp;
+ res += rem;
+ return true;
+ }
+ }
+ else
+ {
+ if (IsDrivePath(s))
+ {
+ UString temp = fs2us(s);
+ UString rem = &temp[kDrivePrefixSize];
+ if (!ResolveDotsFolders(rem))
+ return true;
+ res += kSuperPathPrefix;
+ temp.DeleteFrom(kDrivePrefixSize);
+ res += temp;
+ res += rem;
+ return true;
+ }
+ }
+
+ UString curDir;
+ if (!GetCurDir(curDir))
+ return false;
+ if (curDir.Back() != WCHAR_PATH_SEPARATOR)
+ curDir += WCHAR_PATH_SEPARATOR;
+
+ unsigned fixedSizeStart = 0;
+ unsigned fixedSize = 0;
+ const wchar_t *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 (curDir[0] != CHAR_PATH_SEPARATOR || curDir[1] != CHAR_PATH_SEPARATOR)
+ return false;
+ fixedSizeStart = 2;
+ fixedSize = GetRootPrefixSize_Of_NetworkPath(&curDir[2]);
+ if (fixedSize == 0)
+ return false;
+ superMarker = kSuperUncPrefix;
+ }
+ }
+
+ UString temp;
+ if (c == CHAR_PATH_SEPARATOR)
+ {
+ 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 (s[0] != CHAR_PATH_SEPARATOR)
+ {
+ 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 (c == CHAR_PATH_SEPARATOR && s[1] == CHAR_PATH_SEPARATOR)
+ return true;
+ if (IsDrivePath(s))
+ return true;
+ */
+
+ UString curDir;
+ if (dirPrefix)
+ curDir = fs2us(dirPrefix);
+ else
+ {
+ if (!GetCurDir(curDir))
+ return false;
+ }
+ if (!curDir.IsEmpty() && curDir.Back() != WCHAR_PATH_SEPARATOR)
+ curDir += WCHAR_PATH_SEPARATOR;
+
+ 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 (curDir[0] != WCHAR_PATH_SEPARATOR || curDir[1] != WCHAR_PATH_SEPARATOR)
+ return false;
+ fixedSize = GetRootPrefixSize_Of_NetworkPath(&curDir[2]);
+ if (fixedSize == 0)
+ return false;
+ fixedSize += 2;
+ }
+ }
+
+ #endif // _WIN32
+
+ UString temp;
+ if (s[0] == CHAR_PATH_SEPARATOR)
+ {
+ 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);
+}
+
+}}}
diff --git a/lzma/CPP/Windows/FileName.h b/lzma/CPP/Windows/FileName.h
new file mode 100644
index 0000000..7455654
--- /dev/null
+++ b/lzma/CPP/Windows/FileName.h
@@ -0,0 +1,74 @@
+// Windows/FileName.h
+
+#ifndef __WINDOWS_FILE_NAME_H
+#define __WINDOWS_FILE_NAME_H
+
+#include "../Common/MyString.h"
+
+namespace NWindows {
+namespace NFile {
+namespace NName {
+
+void NormalizeDirPathPrefix(FString &dirPath); // ensures that it ended with '\\', if dirPath is not epmty
+void NormalizeDirPathPrefix(UString &dirPath);
+
+#ifdef _WIN32
+
+extern const wchar_t *kSuperPathPrefix; /* \\?\ */
+const unsigned kDevicePathPrefixSize = 4;
+const unsigned kSuperPathPrefixSize = 4;
+const unsigned kSuperUncPathPrefixSize = kSuperPathPrefixSize + 4;
+
+bool IsDevicePath(CFSTR s) throw(); /* \\.\ */
+bool IsSuperUncPath(CFSTR s) throw();
+
+bool IsDrivePath(const wchar_t *s) throw();
+bool IsSuperPath(const wchar_t *s) throw();
+bool IsSuperOrDevicePath(const wchar_t *s) throw();
+
+#ifndef USE_UNICODE_FSTRING
+bool IsDrivePath(CFSTR s) throw();
+bool IsSuperPath(CFSTR s) throw();
+bool IsSuperOrDevicePath(CFSTR s) throw();
+#endif
+
+#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 &longPath, 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
diff --git a/lzma/CPP/Windows/FileSystem.cpp b/lzma/CPP/Windows/FileSystem.cpp
new file mode 100644
index 0000000..9861062
--- /dev/null
+++ b/lzma/CPP/Windows/FileSystem.cpp
@@ -0,0 +1,131 @@
+// 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
diff --git a/lzma/CPP/Windows/FileSystem.h b/lzma/CPP/Windows/FileSystem.h
new file mode 100644
index 0000000..b0149de
--- /dev/null
+++ b/lzma/CPP/Windows/FileSystem.h
@@ -0,0 +1,27 @@
+// 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
diff --git a/lzma/CPP/Windows/Handle.h b/lzma/CPP/Windows/Handle.h
new file mode 100644
index 0000000..755eeb8
--- /dev/null
+++ b/lzma/CPP/Windows/Handle.h
@@ -0,0 +1,37 @@
+// 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
diff --git a/lzma/CPP/Windows/MemoryLock.cpp b/lzma/CPP/Windows/MemoryLock.cpp
new file mode 100644
index 0000000..559b6b0
--- /dev/null
+++ b/lzma/CPP/Windows/MemoryLock.cpp
@@ -0,0 +1,70 @@
+// Windows/MemoryLock.cpp
+
+#include "StdAfx.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;
+}
+
+#endif
+
+}}
diff --git a/lzma/CPP/Windows/MemoryLock.h b/lzma/CPP/Windows/MemoryLock.h
new file mode 100644
index 0000000..45c6bcb
--- /dev/null
+++ b/lzma/CPP/Windows/MemoryLock.h
@@ -0,0 +1,36 @@
+// Windows/MemoryLock.h
+
+#ifndef __WINDOWS_MEMORY_LOCK_H
+#define __WINDOWS_MEMORY_LOCK_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 ?
+}
+
+#endif
+
+}}
+
+#endif
diff --git a/lzma/CPP/Windows/NtCheck.h b/lzma/CPP/Windows/NtCheck.h
new file mode 100644
index 0000000..b8fa99b
--- /dev/null
+++ b/lzma/CPP/Windows/NtCheck.h
@@ -0,0 +1,44 @@
+// Windows/NtCheck.h
+
+#ifndef __WINDOWS_NT_CHECK_H
+#define __WINDOWS_NT_CHECK_H
+
+#ifdef _WIN32
+
+#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
diff --git a/lzma/CPP/Windows/PropVariant.cpp b/lzma/CPP/Windows/PropVariant.cpp
new file mode 100644
index 0000000..6ab0e00
--- /dev/null
+++ b/lzma/CPP/Windows/PropVariant.cpp
@@ -0,0 +1,300 @@
+// Windows/PropVariant.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/Defs.h"
+
+#include "PropVariant.h"
+
+namespace NWindows {
+namespace NCOM {
+
+HRESULT PropVarEm_Alloc_Bstr(PROPVARIANT *p, unsigned numChars) throw()
+{
+ p->bstrVal = ::SysAllocStringLen(0, 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()
+{
+ UINT len = (UINT)strlen(s);
+ p->bstrVal = ::SysAllocStringLen(0, len);
+ if (!p->bstrVal)
+ {
+ p->vt = VT_ERROR;
+ p->scode = E_OUTOFMEMORY;
+ return E_OUTOFMEMORY;
+ }
+ p->vt = VT_BSTR;
+ BSTR dest = p->bstrVal;
+ for (UINT i = 0; i <= len; i++)
+ dest[i] = s[i];
+ return S_OK;
+}
+
+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 *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 char *s)
+{
+ InternalClear();
+ vt = VT_BSTR;
+ wReserved1 = 0;
+ UINT len = (UINT)strlen(s);
+ bstrVal = ::SysAllocStringLen(0, len);
+ if (!bstrVal)
+ {
+ throw kMemException;
+ // vt = VT_ERROR;
+ // scode = E_OUTOFMEMORY;
+ }
+ else
+ {
+ for (UINT i = 0; i <= len; i++)
+ bstrVal[i] = s[i];
+ }
+ 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(0, 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;
+ }
+}
+
+}}
diff --git a/lzma/CPP/Windows/PropVariant.h b/lzma/CPP/Windows/PropVariant.h
new file mode 100644
index 0000000..4757705
--- /dev/null
+++ b/lzma/CPP/Windows/PropVariant.h
@@ -0,0 +1,107 @@
+// Windows/PropVariant.h
+
+#ifndef __WINDOWS_PROP_VARIANT_H
+#define __WINDOWS_PROP_VARIANT_H
+
+#include "../Common/MyTypes.h"
+#include "../Common/MyWindows.h"
+
+namespace NWindows {
+namespace NCOM {
+
+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 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
diff --git a/lzma/CPP/Windows/PropVariantConv.cpp b/lzma/CPP/Windows/PropVariantConv.cpp
new file mode 100644
index 0000000..a9a0d97
--- /dev/null
+++ b/lzma/CPP/Windows/PropVariantConv.cpp
@@ -0,0 +1,99 @@
+// 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 ConvertFileTimeToString(const FILETIME &ft, char *s, bool includeTime, bool includeSeconds) throw()
+{
+ SYSTEMTIME st;
+ if (!BOOLToBool(FileTimeToSystemTime(&ft, &st)))
+ {
+ *s = 0;
+ 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 (includeTime)
+ {
+ UINT_TO_STR_2(' ', st.wHour);
+ UINT_TO_STR_2(':', st.wMinute);
+ if (includeSeconds)
+ UINT_TO_STR_2(':', st.wSecond);
+ }
+ *s = 0;
+ return true;
+}
+
+void ConvertFileTimeToString(const FILETIME &ft, wchar_t *dest, bool includeTime, bool includeSeconds) throw()
+{
+ char s[32];
+ ConvertFileTimeToString(ft, s, includeTime, includeSeconds);
+ for (unsigned i = 0;; i++)
+ {
+ unsigned char c = s[i];
+ dest[i] = c;
+ if (c == 0)
+ return;
+ }
+}
+
+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: ConvertFileTimeToString(prop.filetime, dest, true, true); 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: ConvertFileTimeToString(prop.filetime, dest, true, true); 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] = ':'; ConvertUInt32ToString(prop.vt, dest + 2);
+ }
+}
diff --git a/lzma/CPP/Windows/PropVariantConv.h b/lzma/CPP/Windows/PropVariantConv.h
new file mode 100644
index 0000000..3e8297d
--- /dev/null
+++ b/lzma/CPP/Windows/PropVariantConv.h
@@ -0,0 +1,30 @@
+// 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
+bool ConvertFileTimeToString(const FILETIME &ft, char *s, bool includeTime = true, bool includeSeconds = true) throw();
+void ConvertFileTimeToString(const FILETIME &ft, wchar_t *s, bool includeTime = true, bool includeSeconds = true) 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/lzma/CPP/Windows/Registry.cpp b/lzma/CPP/Windows/Registry.cpp
new file mode 100644
index 0000000..8c3a751
--- /dev/null
+++ b/lzma/CPP/Windows/Registry.cpp
@@ -0,0 +1,368 @@
+// Windows/Registry.cpp
+
+#include "StdAfx.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 kBufferSize = MAX_PATH + 1; // 256 in ATL
+ DWORD size = kBufferSize;
+ TCHAR buffer[kBufferSize];
+ while (RegEnumKeyEx(key._object, 0, buffer, &size, NULL, NULL, NULL, &fileTime) == ERROR_SUCCESS)
+ {
+ res = key.RecurseDeleteKey(buffer);
+ if (res != ERROR_SUCCESS)
+ return res;
+ size = kBufferSize;
+ }
+ 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, NULL, 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()
+{
+ MYASSERT(count != NULL);
+ 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 currentSize = 0;
+ LONG res = RegQueryValueEx(_object, (LPTSTR)name, NULL, &type, NULL, (DWORD *)¤tSize);
+ if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA)
+ return res;
+ res = QueryValue(name, value.GetBuffer(currentSize), currentSize);
+ value.ReleaseBuffer();
+ return res;
+}
+
+#ifndef _UNICODE
+LONG CKey::QueryValue(LPCWSTR name, LPWSTR value, UInt32 &count)
+{
+ MYASSERT(count != NULL);
+ 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 currentSize = 0;
+
+ LONG res;
+ if (g_IsNT)
+ {
+ res = RegQueryValueExW(_object, name, NULL, &type, NULL, (DWORD *)¤tSize);
+ if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA)
+ return res;
+ res = QueryValue(name, value.GetBuffer(currentSize), currentSize);
+ value.ReleaseBuffer();
+ }
+ 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 (UInt32 index = 0; ; index++)
+ {
+ const UInt32 kBufferSize = MAX_PATH + 1; // 256 in ATL
+ FILETIME lastWriteTime;
+ UInt32 nameSize = kBufferSize;
+ LONG result = ::RegEnumKeyEx(_object, index, keyName.GetBuffer(kBufferSize),
+ (DWORD *)&nameSize, NULL, NULL, NULL, &lastWriteTime);
+ keyName.ReleaseBuffer();
+ 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) throw()
+{
+ UInt32 numChars = 0;
+ unsigned i;
+ for (i = 0; i < strings.Size(); i++)
+ numChars += strings[i].Len() + 1;
+ CBuffer<wchar_t> buffer(numChars);
+ unsigned pos = 0;
+ for (i = 0; i < strings.Size(); i++)
+ {
+ const UString &s = strings[i];
+ MyStringCopy((wchar_t *)buffer + pos, (const wchar_t *)s);
+ pos += s.Len() + 1;
+ }
+ return SetValue(valueName, buffer, numChars * sizeof(wchar_t));
+}
+
+LONG CKey::GetValue_Strings(LPCTSTR valueName, UStringVector &strings)
+{
+ strings.Clear();
+ CByteBuffer buffer;
+ UInt32 dataSize;
+ LONG res = QueryValue(valueName, buffer, dataSize);
+ if (res != ERROR_SUCCESS)
+ return res;
+ if (dataSize % sizeof(wchar_t) != 0)
+ return E_FAIL;
+ const wchar_t *data = (const wchar_t *)(const Byte *)buffer;
+ unsigned numChars = dataSize / sizeof(wchar_t);
+ UString s;
+ for (unsigned i = 0; i < numChars; i++)
+ {
+ wchar_t c = data[i];
+ if (c == 0)
+ {
+ strings.Add(s);
+ s.Empty();
+ }
+ else
+ s += c;
+ }
+ return res;
+}
+
+}}
diff --git a/lzma/CPP/Windows/Registry.h b/lzma/CPP/Windows/Registry.h
new file mode 100644
index 0000000..4ac6662
--- /dev/null
+++ b/lzma/CPP/Windows/Registry.h
@@ -0,0 +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) throw();
+ 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/lzma/CPP/Windows/ResourceString.cpp b/lzma/CPP/Windows/ResourceString.cpp
new file mode 100644
index 0000000..d20e713
--- /dev/null
+++ b/lzma/CPP/Windows/ResourceString.cpp
@@ -0,0 +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.GetBuffer(size - 1), size);
+ }
+ while (size - len <= 1);
+ s.ReleaseBuffer();
+ 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.GetBuffer(size - 1), size);
+ }
+ while (size - len <= 1);
+ s.ReleaseBuffer();
+}
+
+// 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/lzma/CPP/Windows/ResourceString.h b/lzma/CPP/Windows/ResourceString.h
new file mode 100644
index 0000000..cbaef4b
--- /dev/null
+++ b/lzma/CPP/Windows/ResourceString.h
@@ -0,0 +1,16 @@
+// 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
diff --git a/lzma/CPP/Windows/SecurityUtils.cpp b/lzma/CPP/Windows/SecurityUtils.cpp
new file mode 100644
index 0000000..69ef32c
--- /dev/null
+++ b/lzma/CPP/Windows/SecurityUtils.cpp
@@ -0,0 +1,179 @@
+// 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.GetBuffer(0), &accountNameSize,
+ domainName.GetBuffer(0), &domainNameSize, sidNameUse))
+ {
+ if (::GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+ return false;
+ }
+ bool result = BOOLToBool(::LookupAccountSid(systemName, sid,
+ accountName.GetBuffer(accountNameSize), &accountNameSize,
+ domainName.GetBuffer(domainNameSize), &domainNameSize, sidNameUse));
+ accountName.ReleaseBuffer();
+ domainName.ReleaseBuffer();
+ 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;
+}
+
+}}
+
diff --git a/lzma/CPP/Windows/SecurityUtils.h b/lzma/CPP/Windows/SecurityUtils.h
new file mode 100644
index 0000000..16b6606
--- /dev/null
+++ b/lzma/CPP/Windows/SecurityUtils.h
@@ -0,0 +1,167 @@
+// 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
diff --git a/lzma/CPP/Windows/Shell.cpp b/lzma/CPP/Windows/Shell.cpp
new file mode 100644
index 0000000..d5d61a9
--- /dev/null
+++ b/lzma/CPP/Windows/Shell.cpp
@@ -0,0 +1,334 @@
+// Windows/Shell.cpp
+
+#include "StdAfx.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);
+ QueryFile(fileIndex, fileNameA.GetBuffer(bufferSize + 2), bufferSize + 1);
+ fileNameA.ReleaseBuffer();
+ fileName = GetUnicodeString(fileNameA);
+ }
+ else
+ #endif
+ {
+ UINT bufferSize = QueryFile(fileIndex, (LPWSTR)NULL, 0);
+ QueryFile(fileIndex, fileName.GetBuffer(bufferSize + 2), bufferSize + 1);
+ fileName.ReleaseBuffer();
+ }
+ return fileName;
+}
+
+void CDrop::QueryFileNames(UStringVector &fileNames)
+{
+ UINT numFiles = QueryCountOfFiles();
+ fileNames.ClearAndReserve(numFiles);
+ for (UINT i = 0; i < numFiles; i++)
+ fileNames.AddInReserved(QueryFileName(i));
+}
+
+
+bool GetPathFromIDList(LPCITEMIDLIST itemIDList, CSysString &path)
+{
+ bool result = BOOLToBool(::SHGetPathFromIDList(itemIDList, path.GetBuffer(MAX_PATH * 2)));
+ path.ReleaseBuffer();
+ 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 = L"all files";
+ s += L" (*.*)";
+ 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 WinCE SDK!!!
+ #ifdef UNDER_CE
+ browseInfo.pszDisplayName = (LPSTR)displayName.GetBuffer(MAX_PATH);
+ browseInfo.lpszTitle = (LPCSTR)title;
+ #else
+ browseInfo.pszDisplayName = displayName.GetBuffer(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;
+ bool result = BOOLToBool(shGetPathFromIDListW(itemIDList, path.GetBuffer(MAX_PATH * 2)));
+ path.ReleaseBuffer();
+ 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.GetBuffer(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
+
+}}
diff --git a/lzma/CPP/Windows/Shell.h b/lzma/CPP/Windows/Shell.h
new file mode 100644
index 0000000..9068040
--- /dev/null
+++ b/lzma/CPP/Windows/Shell.h
@@ -0,0 +1,94 @@
+// 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
diff --git a/lzma/CPP/Windows/StdAfx.h b/lzma/CPP/Windows/StdAfx.h
new file mode 100644
index 0000000..47a4895
--- /dev/null
+++ b/lzma/CPP/Windows/StdAfx.h
@@ -0,0 +1,8 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "../Common/Common.h"
+
+#endif
diff --git a/lzma/CPP/Windows/Synchronization.cpp b/lzma/CPP/Windows/Synchronization.cpp
new file mode 100644
index 0000000..01f1ad9
--- /dev/null
+++ b/lzma/CPP/Windows/Synchronization.cpp
@@ -0,0 +1,10 @@
+// Windows/Synchronization.cpp
+
+#include "StdAfx.h"
+
+#include "Synchronization.h"
+
+namespace NWindows {
+namespace NSynchronization {
+
+}}
diff --git a/lzma/CPP/Windows/Synchronization.h b/lzma/CPP/Windows/Synchronization.h
new file mode 100644
index 0000000..786da00
--- /dev/null
+++ b/lzma/CPP/Windows/Synchronization.h
@@ -0,0 +1,164 @@
+// 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
diff --git a/lzma/CPP/Windows/System.cpp b/lzma/CPP/Windows/System.cpp
new file mode 100644
index 0000000..545ea0e
--- /dev/null
+++ b/lzma/CPP/Windows/System.cpp
@@ -0,0 +1,72 @@
+// Windows/System.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/Defs.h"
+
+#include "System.h"
+
+namespace NWindows {
+namespace NSystem {
+
+UInt32 GetNumberOfProcessors()
+{
+ SYSTEM_INFO systemInfo;
+ GetSystemInfo(&systemInfo);
+ return (UInt32)systemInfo.dwNumberOfProcessors;
+}
+
+#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
+
+UInt64 GetRamSize()
+{
+ #ifndef UNDER_CE
+ MY_MEMORYSTATUSEX stat;
+ stat.dwLength = sizeof(stat);
+ #endif
+ #ifdef _WIN64
+ if (!::GlobalMemoryStatusEx(&stat))
+ return 0;
+ return MyMin(stat.ullTotalVirtual, stat.ullTotalPhys);
+ #else
+ #ifndef UNDER_CE
+ GlobalMemoryStatusExP globalMemoryStatusEx = (GlobalMemoryStatusExP)
+ ::GetProcAddress(::GetModuleHandle(TEXT("kernel32.dll")), "GlobalMemoryStatusEx");
+ if (globalMemoryStatusEx != 0 && globalMemoryStatusEx(&stat))
+ return MyMin(stat.ullTotalVirtual, stat.ullTotalPhys);
+ #endif
+ {
+ MEMORYSTATUS stat;
+ stat.dwLength = sizeof(stat);
+ ::GlobalMemoryStatus(&stat);
+ return MyMin(stat.dwTotalVirtual, stat.dwTotalPhys);
+ }
+ #endif
+}
+
+}}
diff --git a/lzma/CPP/Windows/System.h b/lzma/CPP/Windows/System.h
new file mode 100644
index 0000000..78a5e1d
--- /dev/null
+++ b/lzma/CPP/Windows/System.h
@@ -0,0 +1,16 @@
+// Windows/System.h
+
+#ifndef __WINDOWS_SYSTEM_H
+#define __WINDOWS_SYSTEM_H
+
+#include "../Common/MyTypes.h"
+
+namespace NWindows {
+namespace NSystem {
+
+UInt32 GetNumberOfProcessors();
+UInt64 GetRamSize();
+
+}}
+
+#endif
diff --git a/lzma/CPP/Windows/Thread.h b/lzma/CPP/Windows/Thread.h
new file mode 100644
index 0000000..1b5863c
--- /dev/null
+++ b/lzma/CPP/Windows/Thread.h
@@ -0,0 +1,38 @@
+// 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
diff --git a/lzma/CPP/Windows/TimeUtils.cpp b/lzma/CPP/Windows/TimeUtils.cpp
new file mode 100644
index 0000000..32f3108
--- /dev/null
+++ b/lzma/CPP/Windows/TimeUtils.cpp
@@ -0,0 +1,203 @@
+// 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;
+}
+
+void UnixTimeToFileTime(UInt32 unixTime, FILETIME &ft) throw()
+{
+ UInt64 v = (kUnixTimeOffset + (UInt64)unixTime) * kNumTimeQuantumsInSecond;
+ ft.dwLowDateTime = (DWORD)v;
+ ft.dwHighDateTime = (DWORD)(v >> 32);
+}
+
+bool UnixTime64ToFileTime(Int64 unixTime, FILETIME &ft) throw()
+{
+ if (unixTime > 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) - 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
+}
+
+}}
diff --git a/lzma/CPP/Windows/TimeUtils.h b/lzma/CPP/Windows/TimeUtils.h
new file mode 100644
index 0000000..0b1f11f
--- /dev/null
+++ b/lzma/CPP/Windows/TimeUtils.h
@@ -0,0 +1,23 @@
+// Windows/TimeUtils.h
+
+#ifndef __WINDOWS_TIME_UTILS_H
+#define __WINDOWS_TIME_UTILS_H
+
+#include "../Common/MyTypes.h"
+
+namespace NWindows {
+namespace NTime {
+
+bool DosTimeToFileTime(UInt32 dosTime, FILETIME &fileTime) throw();
+bool FileTimeToDosTime(const FILETIME &fileTime, UInt32 &dosTime) throw();
+void UnixTimeToFileTime(UInt32 unixTime, FILETIME &fileTime) 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
diff --git a/lzma/CPP/Windows/Window.cpp b/lzma/CPP/Windows/Window.cpp
new file mode 100644
index 0000000..98b0630
--- /dev/null
+++ b/lzma/CPP/Windows/Window.cpp
@@ -0,0 +1,169 @@
+// 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 length = GetTextLength();
+ if (length == 0)
+ return (::GetLastError() == ERROR_SUCCESS);
+ length = GetText(s.GetBuffer(length), length + 1);
+ s.ReleaseBuffer();
+ if (length == 0)
+ return (::GetLastError() != ERROR_SUCCESS);
+ return true;
+}
+
+#ifndef _UNICODE
+bool CWindow::GetText(UString &s)
+{
+ if (g_IsNT)
+ {
+ s.Empty();
+ int length = GetWindowTextLengthW(_window);
+ if (length == 0)
+ return (::GetLastError() == ERROR_SUCCESS);
+ length = GetWindowTextW(_window, s.GetBuffer(length), length + 1);
+ s.ReleaseBuffer();
+ if (length == 0)
+ return (::GetLastError() == ERROR_SUCCESS);
+ return true;
+ }
+ CSysString sysString;
+ bool result = GetText(sysString);
+ s = GetUnicodeString(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/lzma/CPP/Windows/Window.h b/lzma/CPP/Windows/Window.h
new file mode 100644
index 0000000..3db239d
--- /dev/null
+++ b/lzma/CPP/Windows/Window.h
@@ -0,0 +1,283 @@
+// Windows/Window.h
+
+#ifndef __WINDOWS_WINDOW_H
+#define __WINDOWS_WINDOW_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) { SendMessage(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 SendMessage(UINT message, WPARAM wParam = 0, LPARAM lParam = 0)
+ { return ::SendMessage(_window, message, wParam, lParam) ;}
+ #ifndef _UNICODE
+ LRESULT SendMessageW(UINT message, WPARAM wParam = 0, LPARAM lParam = 0)
+ { return ::SendMessageW(_window, message, wParam, lParam) ;}
+ #endif
+
+ bool PostMessage(UINT message, WPARAM wParam = 0, LPARAM lParam = 0)
+ { return BOOLToBool(::PostMessage(_window, message, wParam, lParam)) ;}
+ #ifndef _UNICODE
+ LRESULT PostMessageW(UINT message, WPARAM wParam = 0, LPARAM lParam = 0)
+ { return ::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)SendMessage(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/lzma/CS/7zip/Common/CRC.cs b/lzma/CS/7zip/Common/CRC.cs
new file mode 100644
index 0000000..62bb847
--- /dev/null
+++ b/lzma/CS/7zip/Common/CRC.cs
@@ -0,0 +1,55 @@
+// 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/lzma/CS/7zip/Common/CommandLineParser.cs b/lzma/CS/7zip/Common/CommandLineParser.cs
new file mode 100644
index 0000000..b46f6f2
--- /dev/null
+++ b/lzma/CS/7zip/Common/CommandLineParser.cs
@@ -0,0 +1,274 @@
+// 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/lzma/CS/7zip/Common/InBuffer.cs b/lzma/CS/7zip/Common/InBuffer.cs
new file mode 100644
index 0000000..9c47c73
--- /dev/null
+++ b/lzma/CS/7zip/Common/InBuffer.cs
@@ -0,0 +1,72 @@
+// 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/lzma/CS/7zip/Common/OutBuffer.cs b/lzma/CS/7zip/Common/OutBuffer.cs
new file mode 100644
index 0000000..c205aa6
--- /dev/null
+++ b/lzma/CS/7zip/Common/OutBuffer.cs
@@ -0,0 +1,47 @@
+// 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/lzma/CS/7zip/Compress/LZ/IMatchFinder.cs b/lzma/CS/7zip/Compress/LZ/IMatchFinder.cs
new file mode 100644
index 0000000..30fab86
--- /dev/null
+++ b/lzma/CS/7zip/Compress/LZ/IMatchFinder.cs
@@ -0,0 +1,24 @@
+// 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/lzma/CS/7zip/Compress/LZ/LzBinTree.cs b/lzma/CS/7zip/Compress/LZ/LzBinTree.cs
new file mode 100644
index 0000000..7a9ca20
--- /dev/null
+++ b/lzma/CS/7zip/Compress/LZ/LzBinTree.cs
@@ -0,0 +1,367 @@
+// 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/lzma/CS/7zip/Compress/LZ/LzInWindow.cs b/lzma/CS/7zip/Compress/LZ/LzInWindow.cs
new file mode 100644
index 0000000..f1974ce
--- /dev/null
+++ b/lzma/CS/7zip/Compress/LZ/LzInWindow.cs
@@ -0,0 +1,132 @@
+// 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/lzma/CS/7zip/Compress/LZ/LzOutWindow.cs b/lzma/CS/7zip/Compress/LZ/LzOutWindow.cs
new file mode 100644
index 0000000..84914f0
--- /dev/null
+++ b/lzma/CS/7zip/Compress/LZ/LzOutWindow.cs
@@ -0,0 +1,110 @@
+// 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/lzma/CS/7zip/Compress/LZMA/LzmaBase.cs b/lzma/CS/7zip/Compress/LZMA/LzmaBase.cs
new file mode 100644
index 0000000..8447a2a
--- /dev/null
+++ b/lzma/CS/7zip/Compress/LZMA/LzmaBase.cs
@@ -0,0 +1,76 @@
+// 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/lzma/CS/7zip/Compress/LZMA/LzmaDecoder.cs b/lzma/CS/7zip/Compress/LZMA/LzmaDecoder.cs
new file mode 100644
index 0000000..00bfe63
--- /dev/null
+++ b/lzma/CS/7zip/Compress/LZMA/LzmaDecoder.cs
@@ -0,0 +1,398 @@
+// 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/lzma/CS/7zip/Compress/LZMA/LzmaEncoder.cs b/lzma/CS/7zip/Compress/LZMA/LzmaEncoder.cs
new file mode 100644
index 0000000..6dc2708
--- /dev/null
+++ b/lzma/CS/7zip/Compress/LZMA/LzmaEncoder.cs
@@ -0,0 +1,1480 @@
+// 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/lzma/CS/7zip/Compress/LzmaAlone/LzmaAlone.cs b/lzma/CS/7zip/Compress/LzmaAlone/LzmaAlone.cs
new file mode 100644
index 0000000..8aa4462
--- /dev/null
+++ b/lzma/CS/7zip/Compress/LzmaAlone/LzmaAlone.cs
@@ -0,0 +1,364 @@
+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/lzma/CS/7zip/Compress/LzmaAlone/LzmaAlone.csproj b/lzma/CS/7zip/Compress/LzmaAlone/LzmaAlone.csproj
new file mode 100644
index 0000000..ceb7073
--- /dev/null
+++ b/lzma/CS/7zip/Compress/LzmaAlone/LzmaAlone.csproj
@@ -0,0 +1,90 @@
+<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/lzma/CS/7zip/Compress/LzmaAlone/LzmaAlone.sln b/lzma/CS/7zip/Compress/LzmaAlone/LzmaAlone.sln
new file mode 100644
index 0000000..a96ee3e
--- /dev/null
+++ b/lzma/CS/7zip/Compress/LzmaAlone/LzmaAlone.sln
@@ -0,0 +1,20 @@
+
+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/lzma/CS/7zip/Compress/LzmaAlone/LzmaBench.cs b/lzma/CS/7zip/Compress/LzmaAlone/LzmaBench.cs
new file mode 100644
index 0000000..6a1ffe2
--- /dev/null
+++ b/lzma/CS/7zip/Compress/LzmaAlone/LzmaBench.cs
@@ -0,0 +1,340 @@
+// 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/lzma/CS/7zip/Compress/LzmaAlone/Properties/AssemblyInfo.cs b/lzma/CS/7zip/Compress/LzmaAlone/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..a394aee
--- /dev/null
+++ b/lzma/CS/7zip/Compress/LzmaAlone/Properties/AssemblyInfo.cs
@@ -0,0 +1,29 @@
+#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/lzma/CS/7zip/Compress/LzmaAlone/Properties/Resources.cs b/lzma/CS/7zip/Compress/LzmaAlone/Properties/Resources.cs
new file mode 100644
index 0000000..efe4ee9
--- /dev/null
+++ b/lzma/CS/7zip/Compress/LzmaAlone/Properties/Resources.cs
@@ -0,0 +1,70 @@
+//------------------------------------------------------------------------------
+// <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/lzma/CS/7zip/Compress/LzmaAlone/Properties/Settings.cs b/lzma/CS/7zip/Compress/LzmaAlone/Properties/Settings.cs
new file mode 100644
index 0000000..1281fd2
--- /dev/null
+++ b/lzma/CS/7zip/Compress/LzmaAlone/Properties/Settings.cs
@@ -0,0 +1,42 @@
+//------------------------------------------------------------------------------
+// <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/lzma/CS/7zip/Compress/RangeCoder/RangeCoder.cs b/lzma/CS/7zip/Compress/RangeCoder/RangeCoder.cs
new file mode 100644
index 0000000..4ced247
--- /dev/null
+++ b/lzma/CS/7zip/Compress/RangeCoder/RangeCoder.cs
@@ -0,0 +1,234 @@
+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/lzma/CS/7zip/Compress/RangeCoder/RangeCoderBit.cs b/lzma/CS/7zip/Compress/RangeCoder/RangeCoderBit.cs
new file mode 100644
index 0000000..000a5a0
--- /dev/null
+++ b/lzma/CS/7zip/Compress/RangeCoder/RangeCoderBit.cs
@@ -0,0 +1,117 @@
+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/lzma/CS/7zip/Compress/RangeCoder/RangeCoderBitTree.cs b/lzma/CS/7zip/Compress/RangeCoder/RangeCoderBitTree.cs
new file mode 100644
index 0000000..3309c14
--- /dev/null
+++ b/lzma/CS/7zip/Compress/RangeCoder/RangeCoderBitTree.cs
@@ -0,0 +1,157 @@
+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/lzma/CS/7zip/ICoder.cs b/lzma/CS/7zip/ICoder.cs
new file mode 100644
index 0000000..875cb27
--- /dev/null
+++ b/lzma/CS/7zip/ICoder.cs
@@ -0,0 +1,157 @@
+// 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/lzma/DOC/7zC.txt b/lzma/DOC/7zC.txt
new file mode 100644
index 0000000..4927678
--- /dev/null
+++ b/lzma/DOC/7zC.txt
@@ -0,0 +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
diff --git a/lzma/DOC/7zFormat.txt b/lzma/DOC/7zFormat.txt
new file mode 100644
index 0000000..6b8678f
--- /dev/null
+++ b/lzma/DOC/7zFormat.txt
@@ -0,0 +1,469 @@
+7z Format description (4.59)
+----------------------------
+
+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 = 2
+ };
+
+ 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)
+ 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/lzma/DOC/Methods.txt b/lzma/DOC/Methods.txt
new file mode 100644
index 0000000..a300d77
--- /dev/null
+++ b/lzma/DOC/Methods.txt
@@ -0,0 +1,132 @@
+7-Zip method IDs (9.24)
+-----------------------
+
+Each compression or crypto method in 7z has unique binary value (ID).
+The length of ID in bytes is arbitrary but it can not exceed 63 bits (8 bytes).
+
+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 only if old codec can not decode data encoded with new version.
+
+
+List of defined IDs
+-------------------
+
+00 - Copy
+
+03 - Delta
+04 - x86 (BCJ)
+05 - PPC (Big Endian)
+06 - IA64
+07 - ARM (little endian)
+08 - ARM Thumb (little endian)
+09 - SPARC
+21 - LZMA2
+
+02.. - Common
+ 03 Swap
+ - 2 Swap2
+ - 4 Swap4
+
+03.. - 7z
+ 01 - LZMA
+ 01 - Version
+
+ 03 - Branch
+ 01 - x86
+ 03 - BCJ
+ 1B - BCJ2
+ 02 - PPC
+ 05 - PPC (Big Endian)
+ 03 - Alpha
+ 01 - Alpha
+ 04 - IA64
+ 01 - IA64
+ 05 - ARM
+ 01 - ARM
+ 06 - M68
+ 05 - M68 (Big Endian)
+ 07 - ARM Thumb
+ 01 - ARMT
+ 08 - SPARC
+ 05 - SPARC
+
+ 04 - PPMD
+ 01 - Version
+
+ 7F -
+ 01 - experimental methods.
+
+
+04.. - Misc
+ 00 - Reserved
+ 01 - Zip
+ 00 - Copy (not used). Use {00} instead
+ 01 - Shrink
+ 06 - Implode
+ 08 - Deflate
+ 09 - Deflate64
+ 10 - Imploding
+ 12 - BZip2 (not used). Use {04 02 02} instead
+ 14 - LZMA
+ 60 - Jpeg
+ 61 - WavPack
+ 62 - PPMd
+ 63 - wzAES
+ 02 - BZip
+ 02 - BZip2
+ 03 - Rar
+ 01 - Rar15
+ 02 - Rar20
+ 03 - Rar29
+ 04 - Arj
+ 01 - Arj (1,2,3)
+ 02 - Arj 4
+ 05 - Z
+ 06 - Lzh
+ 07 - Reserved for 7z
+ 08 - Cab
+ 09 - NSIS
+ 01 - DeflateNSIS
+ 02 - BZip2NSIS
+
+
+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 - Main Zip crypto algo
+ 03 - RAR
+ 02 -
+ 03 - Rar29 AES-128 + (modified SHA-1)
+ 07 - 7z
+ 01 - AES-256 + SHA-256
+
+
+---
+End of document
diff --git a/lzma/DOC/installer.txt b/lzma/DOC/installer.txt
new file mode 100644
index 0000000..70ad7dc
--- /dev/null
+++ b/lzma/DOC/installer.txt
@@ -0,0 +1,166 @@
+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/lzma/DOC/lzma-history.txt b/lzma/DOC/lzma-history.txt
new file mode 100644
index 0000000..6e98358
--- /dev/null
+++ b/lzma/DOC/lzma-history.txt
@@ -0,0 +1,306 @@
+HISTORY of the LZMA SDK
+-----------------------
+
+9.38 beta 2015-01-03
+-------------------------
+- The BUG in 9.30-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/lzma/DOC/lzma-sdk.txt b/lzma/DOC/lzma-sdk.txt
new file mode 100644
index 0000000..86923a4
--- /dev/null
+++ b/lzma/DOC/lzma-sdk.txt
@@ -0,0 +1,356 @@
+LZMA SDK 9.38
+-------------
+
+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)
+
+You can copy, modify, distribute and perform LZMA SDK code, even for commercial purposes,
+all without asking permission.
+
+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/lzma/DOC/lzma-specification.txt b/lzma/DOC/lzma-specification.txt
new file mode 100644
index 0000000..2e3b874
--- /dev/null
+++ b/lzma/DOC/lzma-specification.txt
@@ -0,0 +1,1175 @@
+LZMA specification (DRAFT version)
+----------------------------------
+
+Author: Igor Pavlov
+Date: 2013-07-28
+
+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:
+
+void CRangeDecoder::Init()
+{
+ Corrupted = false;
+
+ if (InStream->ReadByte() != 0)
+ Corrupted = true;
+
+ Range = 0xFFFFFFFF;
+ Code = 0;
+ for (int i = 0; i < 4; i++)
+ Code = (Code << 8) | InStream->ReadByte();
+
+ if (Code == Range)
+ Corrupted = true;
+}
+
+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.
+
+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/lzma/DOC/lzma.txt b/lzma/DOC/lzma.txt
new file mode 100644
index 0000000..f9a80ae
--- /dev/null
+++ b/lzma/DOC/lzma.txt
@@ -0,0 +1,328 @@
+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 + Types.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 + Types.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 + Types.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:
+ Types.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
diff --git a/lzma/Java/SevenZip/CRC.java b/lzma/Java/SevenZip/CRC.java
new file mode 100644
index 0000000..f2f791f
--- /dev/null
+++ b/lzma/Java/SevenZip/CRC.java
@@ -0,0 +1,52 @@
+// 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/lzma/Java/SevenZip/Compression/LZ/BinTree.java b/lzma/Java/SevenZip/Compression/LZ/BinTree.java
new file mode 100644
index 0000000..63d58c0
--- /dev/null
+++ b/lzma/Java/SevenZip/Compression/LZ/BinTree.java
@@ -0,0 +1,382 @@
+// 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/lzma/Java/SevenZip/Compression/LZ/InWindow.java b/lzma/Java/SevenZip/Compression/LZ/InWindow.java
new file mode 100644
index 0000000..5f3f0b4
--- /dev/null
+++ b/lzma/Java/SevenZip/Compression/LZ/InWindow.java
@@ -0,0 +1,131 @@
+// 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/lzma/Java/SevenZip/Compression/LZ/OutWindow.java b/lzma/Java/SevenZip/Compression/LZ/OutWindow.java
new file mode 100644
index 0000000..620cb41
--- /dev/null
+++ b/lzma/Java/SevenZip/Compression/LZ/OutWindow.java
@@ -0,0 +1,85 @@
+// 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/lzma/Java/SevenZip/Compression/LZMA/Base.java b/lzma/Java/SevenZip/Compression/LZMA/Base.java
new file mode 100644
index 0000000..18deed9
--- /dev/null
+++ b/lzma/Java/SevenZip/Compression/LZMA/Base.java
@@ -0,0 +1,88 @@
+// 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/lzma/Java/SevenZip/Compression/LZMA/Decoder.java b/lzma/Java/SevenZip/Compression/LZMA/Decoder.java
new file mode 100644
index 0000000..4ebd571
--- /dev/null
+++ b/lzma/Java/SevenZip/Compression/LZMA/Decoder.java
@@ -0,0 +1,329 @@
+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/lzma/Java/SevenZip/Compression/LZMA/Encoder.java b/lzma/Java/SevenZip/Compression/LZMA/Encoder.java
new file mode 100644
index 0000000..771fb21
--- /dev/null
+++ b/lzma/Java/SevenZip/Compression/LZMA/Encoder.java
@@ -0,0 +1,1416 @@
+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/lzma/Java/SevenZip/Compression/RangeCoder/BitTreeDecoder.java b/lzma/Java/SevenZip/Compression/RangeCoder/BitTreeDecoder.java
new file mode 100644
index 0000000..6864c69
--- /dev/null
+++ b/lzma/Java/SevenZip/Compression/RangeCoder/BitTreeDecoder.java
@@ -0,0 +1,55 @@
+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/lzma/Java/SevenZip/Compression/RangeCoder/BitTreeEncoder.java b/lzma/Java/SevenZip/Compression/RangeCoder/BitTreeEncoder.java
new file mode 100644
index 0000000..b4c0a07
--- /dev/null
+++ b/lzma/Java/SevenZip/Compression/RangeCoder/BitTreeEncoder.java
@@ -0,0 +1,99 @@
+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/lzma/Java/SevenZip/Compression/RangeCoder/Decoder.java b/lzma/Java/SevenZip/Compression/RangeCoder/Decoder.java
new file mode 100644
index 0000000..7453383
--- /dev/null
+++ b/lzma/Java/SevenZip/Compression/RangeCoder/Decoder.java
@@ -0,0 +1,88 @@
+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/lzma/Java/SevenZip/Compression/RangeCoder/Encoder.java b/lzma/Java/SevenZip/Compression/RangeCoder/Encoder.java
new file mode 100644
index 0000000..2273e92
--- /dev/null
+++ b/lzma/Java/SevenZip/Compression/RangeCoder/Encoder.java
@@ -0,0 +1,151 @@
+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/lzma/Java/SevenZip/ICodeProgress.java b/lzma/Java/SevenZip/ICodeProgress.java
new file mode 100644
index 0000000..290bd2d
--- /dev/null
+++ b/lzma/Java/SevenZip/ICodeProgress.java
@@ -0,0 +1,6 @@
+package SevenZip;
+
+public interface ICodeProgress
+{
+ public void SetProgress(long inSize, long outSize);
+}
diff --git a/lzma/Java/SevenZip/LzmaAlone.java b/lzma/Java/SevenZip/LzmaAlone.java
new file mode 100644
index 0000000..de39a22
--- /dev/null
+++ b/lzma/Java/SevenZip/LzmaAlone.java
@@ -0,0 +1,253 @@
+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/lzma/Java/SevenZip/LzmaBench.java b/lzma/Java/SevenZip/LzmaBench.java
new file mode 100644
index 0000000..cceda24
--- /dev/null
+++ b/lzma/Java/SevenZip/LzmaBench.java
@@ -0,0 +1,392 @@
+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/lzma/Java/Tukaani/Android.mk b/lzma/Java/Tukaani/Android.mk
new file mode 100644
index 0000000..240882e
--- /dev/null
+++ b/lzma/Java/Tukaani/Android.mk
@@ -0,0 +1,30 @@
+#
+# Copyright (C) 2011 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION = current
+
+LOCAL_MODULE := xz-java
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_JAVA_RESOURCE_DIRS := src
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
diff --git a/lzma/Java/Tukaani/COPYING b/lzma/Java/Tukaani/COPYING
new file mode 100644
index 0000000..c1d404d
--- /dev/null
+++ b/lzma/Java/Tukaani/COPYING
@@ -0,0 +1,10 @@
+
+Licensing of XZ for Java
+========================
+
+ All the files in this package have been written by Lasse Collin
+ and/or Igor Pavlov. All these files have been put into the
+ public domain. You can do whatever you want with these files.
+
+ This software is provided "as is", without any warranty.
+
diff --git a/lzma/Java/Tukaani/NEWS b/lzma/Java/Tukaani/NEWS
new file mode 100644
index 0000000..88ecd75
--- /dev/null
+++ b/lzma/Java/Tukaani/NEWS
@@ -0,0 +1,56 @@
+
+XZ for Java release notes
+=========================
+
+1.5 (2014-03-08)
+
+ * Fix a wrong assertion in BCJ decoders.
+
+ * Use a field instead of reallocating a temporary one-byte buffer
+ in read() and write() implementations in several classes.
+
+1.4 (2013-09-22)
+
+ * Add LZMAInputStream for decoding .lzma files and raw LZMA streams.
+
+1.3 (2013-05-12)
+
+ * Fix a data corruption bug when flushing the LZMA2 encoder or
+ when using a preset dictionary.
+
+ * Make information about the XZ Block positions and sizes available
+ in SeekableXZInputStream by adding the following public functions:
+ - int getStreamCount()
+ - int getBlockCount()
+ - long getBlockPos(int blockNumber)
+ - long getBlockSize(int blockNumber)
+ - long getBlockCompPos(int blockNumber)
+ - long getBlockCompSize(int blockNumber)
+ - int getBlockCheckType(int blockNumber)
+ - int getBlockNumber(long pos)
+ - void seekToBlock(int blockNumber)
+
+ * Minor improvements to javadoc comments were made.
+
+1.2 (2013-01-29)
+
+ * Use fields instead of reallocating frequently-needed temporary
+ objects in the LZMA encoder.
+
+ * Fix the contents of xz-${version}-sources.jar.
+
+ * Add OSGi attributes to xz.jar.
+
+1.1 (2012-07-05)
+
+ * The depthLimit argument in the LZMA2Options constructor is
+ no longer ignored.
+
+ * LZMA2Options() can no longer throw UnsupportedOptionsException.
+
+ * Fix bugs in the preset dictionary support in the LZMA2 encoder.
+
+1.0 (2011-10-22)
+
+ * The first stable release
+
diff --git a/lzma/Java/Tukaani/README b/lzma/Java/Tukaani/README
new file mode 100644
index 0000000..c230299
--- /dev/null
+++ b/lzma/Java/Tukaani/README
@@ -0,0 +1,50 @@
+
+XZ for Java
+===========
+
+Introduction
+
+ This aims to be a complete implementation of XZ data compression
+ in pure Java. Features:
+ - Full support for the .xz file format specification version 1.0.4
+ - Single-threaded streamed compression and decompression
+ - Single-threaded decompression with limited random access support
+ - Raw streams (no .xz headers) for advanced users, including LZMA2
+ with preset dictionary
+
+ Threading is planned but it is unknown when it will be implemented.
+
+ For the latest source code, see the project home page:
+
+ http://tukaani.org/xz/java.html
+
+ The source code is compatible with Java 1.4 and later.
+
+Building
+
+ It is recommended to use Apache Ant. Type "ant" to compile the
+ classes and create the .jar files. Type "ant doc" to build the
+ javadoc HTML documentation. Note that building the documentation
+ will download a small file named "package-list" from Oracle to
+ enable linking to the documentation of the standard Java classes.
+
+ If you cannot or don't want to use Ant, just compile all .java
+ files under the "src" directory.
+
+Demo programs
+
+ You can test compression with XZEncDemo, which compresses from
+ standard input to standard output:
+
+ java -jar build/jar/XZEncDemo.jar < foo.txt > foo.txt.xz
+
+ You can test decompression with XZDecDemo, which decompresses to
+ standard output:
+
+ java -jar build/jar/XZDecDemo.jar foo.txt.xz
+
+Reporting bugs
+
+ Report bugs to <lasse.collin@tukaani.org> or visit the IRC channel
+ #tukaani on Freenode and talk to Larhzu.
+
diff --git a/lzma/Java/Tukaani/THANKS b/lzma/Java/Tukaani/THANKS
new file mode 100644
index 0000000..f345069
--- /dev/null
+++ b/lzma/Java/Tukaani/THANKS
@@ -0,0 +1,16 @@
+
+Thanks
+======
+
+People (in alphabetical order):
+ - Stefan Bodewig
+ - Carl Hasselskog
+ - Arunesh Mathur
+ - Jim Meyering
+ - Benoit Nadeau
+ - Christian Schlichtherle
+ - Alyosha Vasilieva
+
+Companies:
+ - Red Hat
+
diff --git a/lzma/Java/Tukaani/build.properties b/lzma/Java/Tukaani/build.properties
new file mode 100644
index 0000000..64ceac4
--- /dev/null
+++ b/lzma/Java/Tukaani/build.properties
@@ -0,0 +1,29 @@
+#
+# build.properties
+#
+# Author: Lasse Collin <lasse.collin@tukaani.org>
+#
+# This file has been put into the public domain.
+# You can do whatever you want with this file.
+#
+
+title = XZ data compression
+homepage = http://tukaani.org/xz/java.html
+version = 1.5
+
+debug = false
+sourcever = 1.4
+src_dir = src
+
+build_dir = build
+dist_dir = ${build_dir}/dist
+dist_file = ${dist_dir}/xz-java-${version}.zip
+classes_dir = ${build_dir}/classes
+jar_dir = ${build_dir}/jar
+doc_dir = ${build_dir}/doc
+
+extdoc_url = http://docs.oracle.com/javase/7/docs/api
+extdoc_dir = extdoc
+
+pom_template = maven/pom_template.xml
+maven_dir = ${build_dir}/maven
diff --git a/lzma/Java/Tukaani/build.xml b/lzma/Java/Tukaani/build.xml
new file mode 100644
index 0000000..f22e6d6
--- /dev/null
+++ b/lzma/Java/Tukaani/build.xml
@@ -0,0 +1,143 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ build.xml
+
+ Author: Lasse Collin <lasse.collin@tukaani.org>
+
+ This file has been put into the public domain.
+ You can do whatever you want with this file.
+-->
+
+<project name="XZ" default="jar">
+
+ <property file="build.properties"/>
+
+ <target name="clean"
+ description="Deletes generated files except 'extdoc/package-list'">
+ <delete dir="${build_dir}"/>
+ </target>
+
+ <target name="distclean" depends="clean"
+ description="Deletes all generated files">
+ <delete dir="extdoc"/>
+ </target>
+
+ <target name="dist" description="Creates a source package (.zip)">
+ <mkdir dir="${dist_dir}"/>
+ <zip destfile="${dist_file}">
+ <fileset dir="." includesfile="fileset-misc.txt"/>
+ <fileset dir="." includesfile="fileset-src.txt"/>
+ </zip>
+ </target>
+
+ <target name="doc"
+ description="Generates HTML documentation with javadoc">
+ <mkdir dir="${doc_dir}"/>
+ <mkdir dir="${extdoc_dir}"/>
+ <get src="${extdoc_url}/package-list"
+ dest="${extdoc_dir}/package-list" skipexisting="true"/>
+ <javadoc sourcepath="${src_dir}" destdir="${doc_dir}"
+ source="${sourcever}" packagenames="org.tukaani.xz"
+ windowtitle="XZ data compression"
+ linkoffline="${extdoc_url} ${extdoc_dir}"/>
+ </target>
+
+ <target name="compile" description="Compiles the classes">
+ <mkdir dir="${classes_dir}"/>
+ <javac srcdir="." sourcepath="${src_dir}" destdir="${classes_dir}"
+ includeAntRuntime="false" debug="${debug}"
+ source="${sourcever}" includesfile="fileset-src.txt"
+ excludes="**/package-info.java">
+ <compilerarg compiler="modern" value="-Xlint"/>
+ </javac>
+ </target>
+
+ <target name="jar" depends="compile"
+ description="Creates JAR packages">
+ <mkdir dir="${jar_dir}"/>
+
+ <jar destfile="${jar_dir}/xz.jar" basedir="${classes_dir}"
+ includes="org/tukaani/xz/**">
+ <manifest>
+ <attribute name="Implementation-Title" value="${title}"/>
+ <attribute name="Implementation-Version" value="${version}"/>
+ <attribute name="Implementation-URL" value="${homepage}"/>
+ <attribute name="Sealed" value="true"/>
+ <!-- Attributes required for OSGi bundles. -->
+ <attribute name="Bundle-ManifestVersion" value="2"/>
+ <attribute name="Bundle-SymbolicName" value="org.tukaani.xz"/>
+ <attribute name="Bundle-Version" value="${version}"/>
+ <attribute name="Export-Package" value="org.tukaani.xz"/>
+ <attribute name="Bundle-Name" value="${title}"/>
+ <attribute name="Bundle-DocURL" value="${homepage}"/>
+ </manifest>
+ </jar>
+
+ <jar destfile="${jar_dir}/XZEncDemo.jar" basedir="${classes_dir}"
+ includes="XZEncDemo.class">
+ <manifest>
+ <attribute name="Main-Class" value="XZEncDemo"/>
+ <attribute name="Class-Path" value="xz.jar"/>
+ </manifest>
+ </jar>
+
+ <jar destfile="${jar_dir}/XZDecDemo.jar" basedir="${classes_dir}"
+ includes="XZDecDemo.class">
+ <manifest>
+ <attribute name="Main-Class" value="XZDecDemo"/>
+ <attribute name="Class-Path" value="xz.jar"/>
+ </manifest>
+ </jar>
+
+ <jar destfile="${jar_dir}/XZSeekEncDemo.jar" basedir="${classes_dir}"
+ includes="XZSeekEncDemo.class">
+ <manifest>
+ <attribute name="Main-Class" value="XZSeekEncDemo"/>
+ <attribute name="Class-Path" value="xz.jar"/>
+ </manifest>
+ </jar>
+
+ <jar destfile="${jar_dir}/XZSeekDecDemo.jar" basedir="${classes_dir}"
+ includes="XZSeekDecDemo.class">
+ <manifest>
+ <attribute name="Main-Class" value="XZSeekDecDemo"/>
+ <attribute name="Class-Path" value="xz.jar"/>
+ </manifest>
+ </jar>
+
+ <jar destfile="${jar_dir}/LZMADecDemo.jar" basedir="${classes_dir}"
+ includes="LZMADecDemo.class">
+ <manifest>
+ <attribute name="Main-Class" value="LZMADecDemo"/>
+ <attribute name="Class-Path" value="xz.jar"/>
+ </manifest>
+ </jar>
+ </target>
+
+ <!-- It's an ugly quick hack. Maybe some day there will be a cleaner
+ version (e.g. by using Maven). -->
+ <target name="maven" depends="dist, doc, jar"
+ description="Creates the files for a Maven repository">
+ <mkdir dir="${maven_dir}"/>
+
+ <copy file="${pom_template}" tofile="${maven_dir}/xz-${version}.pom"
+ overwrite="true">
+ <filterset>
+ <filter token="VERSION" value="${version}"/>
+ <filter token="TITLE" value="${title}"/>
+ <filter token="HOMEPAGE" value="${homepage}"/>
+ </filterset>
+ </copy>
+
+ <copy file="${jar_dir}/xz.jar" tofile="${maven_dir}/xz-${version}.jar"
+ preservelastmodified="true" overwrite="true"/>
+
+ <jar destfile="${maven_dir}/xz-${version}-javadoc.jar"
+ basedir="${doc_dir}"/>
+
+ <jar destfile="${maven_dir}/xz-${version}-sources.jar"
+ basedir="${src_dir}" includes="org/tukaani/xz/**"/>
+ </target>
+
+</project>
diff --git a/lzma/Java/Tukaani/fileset-misc.txt b/lzma/Java/Tukaani/fileset-misc.txt
new file mode 100644
index 0000000..9d16359
--- /dev/null
+++ b/lzma/Java/Tukaani/fileset-misc.txt
@@ -0,0 +1,11 @@
+README
+NEWS
+COPYING
+THANKS
+build.xml
+build.properties
+fileset-src.txt
+fileset-misc.txt
+.gitignore
+maven/README
+maven/pom_template.xml
diff --git a/lzma/Java/Tukaani/fileset-src.txt b/lzma/Java/Tukaani/fileset-src.txt
new file mode 100644
index 0000000..c7181fb
--- /dev/null
+++ b/lzma/Java/Tukaani/fileset-src.txt
@@ -0,0 +1,100 @@
+src/LZMADecDemo.java
+src/XZDecDemo.java
+src/XZEncDemo.java
+src/XZSeekDecDemo.java
+src/XZSeekEncDemo.java
+src/org/tukaani/xz/ARMOptions.java
+src/org/tukaani/xz/ARMThumbOptions.java
+src/org/tukaani/xz/BCJCoder.java
+src/org/tukaani/xz/BCJDecoder.java
+src/org/tukaani/xz/BCJEncoder.java
+src/org/tukaani/xz/BCJOptions.java
+src/org/tukaani/xz/BlockInputStream.java
+src/org/tukaani/xz/BlockOutputStream.java
+src/org/tukaani/xz/CorruptedInputException.java
+src/org/tukaani/xz/CountingInputStream.java
+src/org/tukaani/xz/CountingOutputStream.java
+src/org/tukaani/xz/DeltaCoder.java
+src/org/tukaani/xz/DeltaDecoder.java
+src/org/tukaani/xz/DeltaEncoder.java
+src/org/tukaani/xz/DeltaInputStream.java
+src/org/tukaani/xz/DeltaOptions.java
+src/org/tukaani/xz/DeltaOutputStream.java
+src/org/tukaani/xz/FilterCoder.java
+src/org/tukaani/xz/FilterDecoder.java
+src/org/tukaani/xz/FilterEncoder.java
+src/org/tukaani/xz/FilterOptions.java
+src/org/tukaani/xz/FinishableOutputStream.java
+src/org/tukaani/xz/FinishableWrapperOutputStream.java
+src/org/tukaani/xz/IA64Options.java
+src/org/tukaani/xz/IndexIndicatorException.java
+src/org/tukaani/xz/LZMA2Coder.java
+src/org/tukaani/xz/LZMA2Decoder.java
+src/org/tukaani/xz/LZMA2Encoder.java
+src/org/tukaani/xz/LZMA2InputStream.java
+src/org/tukaani/xz/LZMA2Options.java
+src/org/tukaani/xz/LZMA2OutputStream.java
+src/org/tukaani/xz/LZMAInputStream.java
+src/org/tukaani/xz/MemoryLimitException.java
+src/org/tukaani/xz/PowerPCOptions.java
+src/org/tukaani/xz/RawCoder.java
+src/org/tukaani/xz/SPARCOptions.java
+src/org/tukaani/xz/SeekableFileInputStream.java
+src/org/tukaani/xz/SeekableInputStream.java
+src/org/tukaani/xz/SeekableXZInputStream.java
+src/org/tukaani/xz/SimpleInputStream.java
+src/org/tukaani/xz/SimpleOutputStream.java
+src/org/tukaani/xz/SingleXZInputStream.java
+src/org/tukaani/xz/UncompressedLZMA2OutputStream.java
+src/org/tukaani/xz/UnsupportedOptionsException.java
+src/org/tukaani/xz/X86Options.java
+src/org/tukaani/xz/XZ.java
+src/org/tukaani/xz/XZFormatException.java
+src/org/tukaani/xz/XZIOException.java
+src/org/tukaani/xz/XZInputStream.java
+src/org/tukaani/xz/XZOutputStream.java
+src/org/tukaani/xz/check/CRC32.java
+src/org/tukaani/xz/check/CRC64.java
+src/org/tukaani/xz/check/Check.java
+src/org/tukaani/xz/check/None.java
+src/org/tukaani/xz/check/SHA256.java
+src/org/tukaani/xz/common/DecoderUtil.java
+src/org/tukaani/xz/common/EncoderUtil.java
+src/org/tukaani/xz/common/StreamFlags.java
+src/org/tukaani/xz/common/Util.java
+src/org/tukaani/xz/delta/DeltaCoder.java
+src/org/tukaani/xz/delta/DeltaDecoder.java
+src/org/tukaani/xz/delta/DeltaEncoder.java
+src/org/tukaani/xz/index/BlockInfo.java
+src/org/tukaani/xz/index/IndexBase.java
+src/org/tukaani/xz/index/IndexDecoder.java
+src/org/tukaani/xz/index/IndexEncoder.java
+src/org/tukaani/xz/index/IndexHash.java
+src/org/tukaani/xz/index/IndexRecord.java
+src/org/tukaani/xz/lz/BT4.java
+src/org/tukaani/xz/lz/CRC32Hash.java
+src/org/tukaani/xz/lz/HC4.java
+src/org/tukaani/xz/lz/Hash234.java
+src/org/tukaani/xz/lz/LZDecoder.java
+src/org/tukaani/xz/lz/LZEncoder.java
+src/org/tukaani/xz/lz/Matches.java
+src/org/tukaani/xz/lzma/LZMACoder.java
+src/org/tukaani/xz/lzma/LZMADecoder.java
+src/org/tukaani/xz/lzma/LZMAEncoder.java
+src/org/tukaani/xz/lzma/LZMAEncoderFast.java
+src/org/tukaani/xz/lzma/LZMAEncoderNormal.java
+src/org/tukaani/xz/lzma/Optimum.java
+src/org/tukaani/xz/lzma/State.java
+src/org/tukaani/xz/package-info.java
+src/org/tukaani/xz/rangecoder/RangeCoder.java
+src/org/tukaani/xz/rangecoder/RangeDecoder.java
+src/org/tukaani/xz/rangecoder/RangeDecoderFromBuffer.java
+src/org/tukaani/xz/rangecoder/RangeDecoderFromStream.java
+src/org/tukaani/xz/rangecoder/RangeEncoder.java
+src/org/tukaani/xz/simple/ARM.java
+src/org/tukaani/xz/simple/ARMThumb.java
+src/org/tukaani/xz/simple/IA64.java
+src/org/tukaani/xz/simple/PowerPC.java
+src/org/tukaani/xz/simple/SPARC.java
+src/org/tukaani/xz/simple/SimpleFilter.java
+src/org/tukaani/xz/simple/X86.java
diff --git a/lzma/Java/Tukaani/maven/README b/lzma/Java/Tukaani/maven/README
new file mode 100644
index 0000000..2692a97
--- /dev/null
+++ b/lzma/Java/Tukaani/maven/README
@@ -0,0 +1,2 @@
+The pom_template.xml is for a Maven repository but it's not meant
+for building the project. Note that build.xml will replace @foo@ tags.
diff --git a/lzma/Java/Tukaani/maven/pom_template.xml b/lzma/Java/Tukaani/maven/pom_template.xml
new file mode 100644
index 0000000..1adeece
--- /dev/null
+++ b/lzma/Java/Tukaani/maven/pom_template.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ Author: Lasse Collin <lasse.collin@tukaani.org>
+
+ This file has been put into the public domain.
+ You can do whatever you want with this file.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
+ http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>org.tukaani</groupId>
+ <artifactId>xz</artifactId>
+ <version>@VERSION@</version>
+ <packaging>jar</packaging>
+
+ <name>XZ for Java</name>
+ <description>@TITLE@</description>
+ <url>@HOMEPAGE@</url>
+
+ <licenses>
+ <license>
+ <name>Public Domain</name>
+ <comments>You can do whatever you want with this package.</comments>
+ <distribution>repo</distribution>
+ </license>
+ </licenses>
+
+ <scm>
+ <url>http://git.tukaani.org/?p=xz-java.git</url>
+ <connection>scm:git:http://git.tukaani.org/xz-java.git</connection>
+ </scm>
+
+ <developers>
+ <developer>
+ <name>Lasse Collin</name>
+ <email>lasse.collin@tukaani.org</email>
+ </developer>
+ </developers>
+
+ <contributors>
+ <contributor>
+ <!-- According to Maven docs, it's good to only list those people
+ as <developers> that should be contacted if someone wants
+ to talk with an upstream developer. Thus, Igor Pavlov is
+ marked as a <contributor> even though XZ for Java simply
+ couldn't exist without Igor Pavlov's code. -->
+ <name>Igor Pavlov</name>
+ <url>http://7-zip.org/</url>
+ </contributor>
+ </contributors>
+
+</project>
diff --git a/lzma/Java/Tukaani/src/LZMADecDemo.java b/lzma/Java/Tukaani/src/LZMADecDemo.java
new file mode 100644
index 0000000..1098725
--- /dev/null
+++ b/lzma/Java/Tukaani/src/LZMADecDemo.java
@@ -0,0 +1,80 @@
+/*
+ * LZMADecDemo
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+import java.io.*;
+import org.tukaani.xz.*;
+
+/**
+ * Decompresses .lzma files to standard output. If no arguments are given,
+ * reads from standard input.
+ *
+ * NOTE: For most purposes, .lzma is a legacy format and usually you should
+ * use .xz instead.
+ */
+class LZMADecDemo {
+ public static void main(String[] args) {
+ byte[] buf = new byte[8192];
+ String name = null;
+
+ try {
+ if (args.length == 0) {
+ name = "standard input";
+
+ // No need to use BufferedInputStream with System.in which
+ // seems to be fast with one-byte reads.
+ InputStream in = new LZMAInputStream(System.in);
+
+ int size;
+ while ((size = in.read(buf)) != -1)
+ System.out.write(buf, 0, size);
+
+ } else {
+ // Read from files given on the command line.
+ for (int i = 0; i < args.length; ++i) {
+ name = args[i];
+ InputStream in = new FileInputStream(name);
+
+ try {
+ // In contrast to other classes in org.tukaani.xz,
+ // LZMAInputStream doesn't do buffering internally
+ // and reads one byte at a time. BufferedInputStream
+ // gives a huge performance improvement here but even
+ // then it's slower than the other input streams from
+ // org.tukaani.xz.
+ in = new BufferedInputStream(in);
+ in = new LZMAInputStream(in);
+
+ int size;
+ while ((size = in.read(buf)) != -1)
+ System.out.write(buf, 0, size);
+
+ } finally {
+ // Close FileInputStream (directly or indirectly
+ // via LZMAInputStream, it doesn't matter).
+ in.close();
+ }
+ }
+ }
+ } catch (FileNotFoundException e) {
+ System.err.println("LZMADecDemo: Cannot open " + name + ": "
+ + e.getMessage());
+ System.exit(1);
+
+ } catch (EOFException e) {
+ System.err.println("LZMADecDemo: Unexpected end of input on "
+ + name);
+ System.exit(1);
+
+ } catch (IOException e) {
+ System.err.println("LZMADecDemo: Error decompressing from "
+ + name + ": " + e.getMessage());
+ System.exit(1);
+ }
+ }
+}
diff --git a/lzma/Java/Tukaani/src/XZDecDemo.java b/lzma/Java/Tukaani/src/XZDecDemo.java
new file mode 100644
index 0000000..6876eea
--- /dev/null
+++ b/lzma/Java/Tukaani/src/XZDecDemo.java
@@ -0,0 +1,71 @@
+/*
+ * XZDecDemo
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+import java.io.*;
+import org.tukaani.xz.*;
+
+/**
+ * Decompresses .xz files to standard output. If no arguments are given,
+ * reads from standard input.
+ */
+class XZDecDemo {
+ public static void main(String[] args) {
+ byte[] buf = new byte[8192];
+ String name = null;
+
+ try {
+ if (args.length == 0) {
+ name = "standard input";
+ InputStream in = new XZInputStream(System.in);
+
+ int size;
+ while ((size = in.read(buf)) != -1)
+ System.out.write(buf, 0, size);
+
+ } else {
+ // Read from files given on the command line.
+ for (int i = 0; i < args.length; ++i) {
+ name = args[i];
+ InputStream in = new FileInputStream(name);
+
+ try {
+ // Since XZInputStream does some buffering internally
+ // anyway, BufferedInputStream doesn't seem to be
+ // needed here to improve performance.
+ // in = new BufferedInputStream(in);
+ in = new XZInputStream(in);
+
+ int size;
+ while ((size = in.read(buf)) != -1)
+ System.out.write(buf, 0, size);
+
+ } finally {
+ // Close FileInputStream (directly or indirectly
+ // via XZInputStream, it doesn't matter).
+ in.close();
+ }
+ }
+ }
+ } catch (FileNotFoundException e) {
+ System.err.println("XZDecDemo: Cannot open " + name + ": "
+ + e.getMessage());
+ System.exit(1);
+
+ } catch (EOFException e) {
+ System.err.println("XZDecDemo: Unexpected end of input on "
+ + name);
+ System.exit(1);
+
+ } catch (IOException e) {
+ System.err.println("XZDecDemo: Error decompressing from "
+ + name + ": " + e.getMessage());
+ System.exit(1);
+ }
+ }
+}
diff --git a/lzma/Java/Tukaani/src/XZEncDemo.java b/lzma/Java/Tukaani/src/XZEncDemo.java
new file mode 100644
index 0000000..e9ae38a
--- /dev/null
+++ b/lzma/Java/Tukaani/src/XZEncDemo.java
@@ -0,0 +1,41 @@
+/*
+ * XZEncDemo
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+import java.io.*;
+import org.tukaani.xz.*;
+
+/**
+ * Compresses a single file from standard input to standard ouput into
+ * the .xz file format.
+ * <p>
+ * One optional argument is supported: LZMA2 preset level which is an integer
+ * in the range [0, 9]. The default is 6.
+ */
+class XZEncDemo {
+ public static void main(String[] args) throws Exception {
+ LZMA2Options options = new LZMA2Options();
+
+ if (args.length >= 1)
+ options.setPreset(Integer.parseInt(args[0]));
+
+ System.err.println("Encoder memory usage: "
+ + options.getEncoderMemoryUsage() + " KiB");
+ System.err.println("Decoder memory usage: "
+ + options.getDecoderMemoryUsage() + " KiB");
+
+ XZOutputStream out = new XZOutputStream(System.out, options);
+
+ byte[] buf = new byte[8192];
+ int size;
+ while ((size = System.in.read(buf)) != -1)
+ out.write(buf, 0, size);
+
+ out.finish();
+ }
+}
diff --git a/lzma/Java/Tukaani/src/XZSeekDecDemo.java b/lzma/Java/Tukaani/src/XZSeekDecDemo.java
new file mode 100644
index 0000000..5c54a87
--- /dev/null
+++ b/lzma/Java/Tukaani/src/XZSeekDecDemo.java
@@ -0,0 +1,75 @@
+/*
+ * XZSeekDecDemo
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+import java.io.*;
+import org.tukaani.xz.*;
+
+/**
+ * Decompresses a .xz file in random access mode to standard output.
+ * <p>
+ * Arguments: filename [offset1 length1] [offset2 length2] ...
+ * <p>
+ * If only the filename is given, the whole file is decompressed. The only
+ * difference to XZDecDemo is that this will still use the random access code.
+ * <p>
+ * If one or more of the offset-length pairs are given,
+ * for each pair, <code>length</code> number of bytes are
+ * decompressed from <code>offset</code>.
+ */
+class XZSeekDecDemo {
+ public static void main(String[] args) throws Exception {
+ SeekableFileInputStream file = new SeekableFileInputStream(args[0]);
+ SeekableXZInputStream in = new SeekableXZInputStream(file);
+
+ System.err.println("Number of XZ Streams: " + in.getStreamCount());
+ System.err.println("Number of XZ Blocks: " + in.getBlockCount());
+
+ System.err.println("Uncompressed size: " + in.length() + " B");
+
+ System.err.println("Largest XZ Block size: "
+ + in.getLargestBlockSize() + " B");
+
+ System.err.print("List of Check IDs:");
+ int checkTypes = in.getCheckTypes();
+ for (int i = 0; i < 16; ++i)
+ if ((checkTypes & (1 << i)) != 0)
+ System.err.print(" " + i);
+ System.err.println();
+
+ System.err.println("Index memory usage: "
+ + in.getIndexMemoryUsage() + " KiB");
+
+ byte[] buf = new byte[8192];
+ if (args.length == 1) {
+ int size;
+ while ((size = in.read(buf)) != -1)
+ System.out.write(buf, 0, size);
+ } else {
+ for (int i = 1; i < args.length; i += 2) {
+ int pos = Integer.parseInt(args[i]);
+ int len = Integer.parseInt(args[i + 1]);
+
+ in.seek(pos);
+
+ while (len > 0) {
+ int size = Math.min(len, buf.length);
+ size = in.read(buf, 0, size);
+
+ if (size == -1) {
+ System.err.println("Error: End of file reached");
+ System.exit(1);
+ }
+
+ System.out.write(buf, 0, size);
+ len -= size;
+ }
+ }
+ }
+ }
+}
diff --git a/lzma/Java/Tukaani/src/XZSeekEncDemo.java b/lzma/Java/Tukaani/src/XZSeekEncDemo.java
new file mode 100644
index 0000000..157e788
--- /dev/null
+++ b/lzma/Java/Tukaani/src/XZSeekEncDemo.java
@@ -0,0 +1,68 @@
+/*
+ * XZSeekEncDemo
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+import java.io.*;
+import org.tukaani.xz.*;
+
+/**
+ * Compresses a single file from standard input to standard ouput into
+ * a random-accessible .xz file.
+ * <p>
+ * Arguments: [preset [block size]]
+ * <p>
+ * Preset is an LZMA2 preset level which is an integer in the range [0, 9].
+ * The default is 6.
+ * <p>
+ * Block size specifies the amount of uncompressed data to store per
+ * XZ Block. The default is 1 MiB (1048576 bytes). Bigger means better
+ * compression ratio. Smaller means faster random access.
+ */
+class XZSeekEncDemo {
+ public static void main(String[] args) throws Exception {
+ LZMA2Options options = new LZMA2Options();
+
+ if (args.length >= 1)
+ options.setPreset(Integer.parseInt(args[0]));
+
+ int blockSize = 1024 * 1024;
+ if (args.length >= 2)
+ blockSize = Integer.parseInt(args[1]);
+
+ options.setDictSize(Math.min(options.getDictSize(),
+ Math.max(LZMA2Options.DICT_SIZE_MIN,
+ blockSize)));
+
+ System.err.println("Encoder memory usage: "
+ + options.getEncoderMemoryUsage() + " KiB");
+ System.err.println("Decoder memory usage: "
+ + options.getDecoderMemoryUsage() + " KiB");
+ System.err.println("Block size: " + blockSize + " B");
+
+ XZOutputStream out = new XZOutputStream(System.out, options);
+
+ byte[] buf = new byte[8192];
+ int left = blockSize;
+
+ while (true) {
+ int size = System.in.read(buf, 0, Math.min(buf.length, left));
+ if (size == -1)
+ break;
+
+ out.write(buf, 0, size);
+ left -= size;
+
+ if (left == 0) {
+ out.endBlock();
+ left = blockSize;
+ }
+ }
+
+ out.finish();
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/ARMOptions.java b/lzma/Java/Tukaani/src/org/tukaani/xz/ARMOptions.java
new file mode 100644
index 0000000..9577101
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/ARMOptions.java
@@ -0,0 +1,36 @@
+/*
+ * ARMOptions
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz;
+
+import java.io.InputStream;
+import org.tukaani.xz.simple.ARM;
+
+/**
+ * BCJ filter for little endian ARM instructions.
+ */
+public class ARMOptions extends BCJOptions {
+ private static final int ALIGNMENT = 4;
+
+ public ARMOptions() {
+ super(ALIGNMENT);
+ }
+
+ public FinishableOutputStream getOutputStream(FinishableOutputStream out) {
+ return new SimpleOutputStream(out, new ARM(true, startOffset));
+ }
+
+ public InputStream getInputStream(InputStream in) {
+ return new SimpleInputStream(in, new ARM(false, startOffset));
+ }
+
+ FilterEncoder getFilterEncoder() {
+ return new BCJEncoder(this, BCJCoder.ARM_FILTER_ID);
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/ARMThumbOptions.java b/lzma/Java/Tukaani/src/org/tukaani/xz/ARMThumbOptions.java
new file mode 100644
index 0000000..60eb6ec
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/ARMThumbOptions.java
@@ -0,0 +1,36 @@
+/*
+ * ARMThumbOptions
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz;
+
+import java.io.InputStream;
+import org.tukaani.xz.simple.ARMThumb;
+
+/**
+ * BCJ filter for little endian ARM-Thumb instructions.
+ */
+public class ARMThumbOptions extends BCJOptions {
+ private static final int ALIGNMENT = 2;
+
+ public ARMThumbOptions() {
+ super(ALIGNMENT);
+ }
+
+ public FinishableOutputStream getOutputStream(FinishableOutputStream out) {
+ return new SimpleOutputStream(out, new ARMThumb(true, startOffset));
+ }
+
+ public InputStream getInputStream(InputStream in) {
+ return new SimpleInputStream(in, new ARMThumb(false, startOffset));
+ }
+
+ FilterEncoder getFilterEncoder() {
+ return new BCJEncoder(this, BCJCoder.ARMTHUMB_FILTER_ID);
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/BCJCoder.java b/lzma/Java/Tukaani/src/org/tukaani/xz/BCJCoder.java
new file mode 100644
index 0000000..81862f7
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/BCJCoder.java
@@ -0,0 +1,35 @@
+/*
+ * BCJCoder
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz;
+
+abstract class BCJCoder implements FilterCoder {
+ public static final long X86_FILTER_ID = 0x04;
+ public static final long POWERPC_FILTER_ID = 0x05;
+ public static final long IA64_FILTER_ID = 0x06;
+ public static final long ARM_FILTER_ID = 0x07;
+ public static final long ARMTHUMB_FILTER_ID = 0x08;
+ public static final long SPARC_FILTER_ID = 0x09;
+
+ public static boolean isBCJFilterID(long filterID) {
+ return filterID >= 0x04 && filterID <= 0x09;
+ }
+
+ public boolean changesSize() {
+ return false;
+ }
+
+ public boolean nonLastOK() {
+ return true;
+ }
+
+ public boolean lastOK() {
+ return false;
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/BCJDecoder.java b/lzma/Java/Tukaani/src/org/tukaani/xz/BCJDecoder.java
new file mode 100644
index 0000000..f8a6ae2
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/BCJDecoder.java
@@ -0,0 +1,62 @@
+/*
+ * BCJDecoder
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz;
+
+import java.io.InputStream;
+import org.tukaani.xz.simple.*;
+
+class BCJDecoder extends BCJCoder implements FilterDecoder {
+ private final long filterID;
+ private final int startOffset;
+
+ BCJDecoder(long filterID, byte[] props)
+ throws UnsupportedOptionsException {
+ assert isBCJFilterID(filterID);
+ this.filterID = filterID;
+
+ if (props.length == 0) {
+ startOffset = 0;
+ } else if (props.length == 4) {
+ int n = 0;
+ for (int i = 0; i < 4; ++i)
+ n |= (props[i] & 0xFF) << (i * 8);
+
+ startOffset = n;
+ } else {
+ throw new UnsupportedOptionsException(
+ "Unsupported BCJ filter properties");
+ }
+ }
+
+ public int getMemoryUsage() {
+ return SimpleInputStream.getMemoryUsage();
+ }
+
+ public InputStream getInputStream(InputStream in) {
+ SimpleFilter simpleFilter = null;
+
+ if (filterID == X86_FILTER_ID)
+ simpleFilter = new X86(false, startOffset);
+ else if (filterID == POWERPC_FILTER_ID)
+ simpleFilter = new PowerPC(false, startOffset);
+ else if (filterID == IA64_FILTER_ID)
+ simpleFilter = new IA64(false, startOffset);
+ else if (filterID == ARM_FILTER_ID)
+ simpleFilter = new ARM(false, startOffset);
+ else if (filterID == ARMTHUMB_FILTER_ID)
+ simpleFilter = new ARMThumb(false, startOffset);
+ else if (filterID == SPARC_FILTER_ID)
+ simpleFilter = new SPARC(false, startOffset);
+ else
+ assert false;
+
+ return new SimpleInputStream(in, simpleFilter);
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/BCJEncoder.java b/lzma/Java/Tukaani/src/org/tukaani/xz/BCJEncoder.java
new file mode 100644
index 0000000..136bbb7
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/BCJEncoder.java
@@ -0,0 +1,48 @@
+/*
+ * BCJEncoder
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz;
+
+class BCJEncoder extends BCJCoder implements FilterEncoder {
+ private final BCJOptions options;
+ private final long filterID;
+ private final byte[] props;
+
+ BCJEncoder(BCJOptions options, long filterID) {
+ assert isBCJFilterID(filterID);
+ int startOffset = options.getStartOffset();
+
+ if (startOffset == 0) {
+ props = new byte[0];
+ } else {
+ props = new byte[4];
+ for (int i = 0; i < 4; ++i)
+ props[i] = (byte)(startOffset >>> (i * 8));
+ }
+
+ this.filterID = filterID;
+ this.options = (BCJOptions)options.clone();
+ }
+
+ public long getFilterID() {
+ return filterID;
+ }
+
+ public byte[] getFilterProps() {
+ return props;
+ }
+
+ public boolean supportsFlushing() {
+ return false;
+ }
+
+ public FinishableOutputStream getOutputStream(FinishableOutputStream out) {
+ return options.getOutputStream(out);
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/BCJOptions.java b/lzma/Java/Tukaani/src/org/tukaani/xz/BCJOptions.java
new file mode 100644
index 0000000..705a2c0
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/BCJOptions.java
@@ -0,0 +1,57 @@
+/*
+ * BCJOptions
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz;
+
+abstract class BCJOptions extends FilterOptions {
+ private final int alignment;
+ int startOffset = 0;
+
+ BCJOptions(int alignment) {
+ this.alignment = alignment;
+ }
+
+ /**
+ * Sets the start offset for the address conversions.
+ * Normally this is useless so you shouldn't use this function.
+ * The default value is <code>0</code>.
+ */
+ public void setStartOffset(int startOffset)
+ throws UnsupportedOptionsException {
+ if ((startOffset & (alignment - 1)) != 0)
+ throw new UnsupportedOptionsException(
+ "Start offset must be a multiple of " + alignment);
+
+ this.startOffset = startOffset;
+ }
+
+ /**
+ * Gets the start offset.
+ */
+ public int getStartOffset() {
+ return startOffset;
+ }
+
+ public int getEncoderMemoryUsage() {
+ return SimpleOutputStream.getMemoryUsage();
+ }
+
+ public int getDecoderMemoryUsage() {
+ return SimpleInputStream.getMemoryUsage();
+ }
+
+ public Object clone() {
+ try {
+ return super.clone();
+ } catch (CloneNotSupportedException e) {
+ assert false;
+ throw new RuntimeException();
+ }
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/BlockInputStream.java b/lzma/Java/Tukaani/src/org/tukaani/xz/BlockInputStream.java
new file mode 100644
index 0000000..d1e72af
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/BlockInputStream.java
@@ -0,0 +1,284 @@
+/*
+ * BlockInputStream
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz;
+
+import java.io.InputStream;
+import java.io.DataInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.Arrays;
+import org.tukaani.xz.common.DecoderUtil;
+import org.tukaani.xz.check.Check;
+
+class BlockInputStream extends InputStream {
+ private final DataInputStream inData;
+ private final CountingInputStream inCounted;
+ private InputStream filterChain;
+ private final Check check;
+ private final boolean verifyCheck;
+
+ private long uncompressedSizeInHeader = -1;
+ private long compressedSizeInHeader = -1;
+ private long compressedSizeLimit;
+ private final int headerSize;
+ private long uncompressedSize = 0;
+ private boolean endReached = false;
+
+ private final byte[] tempBuf = new byte[1];
+
+ public BlockInputStream(InputStream in,
+ Check check, boolean verifyCheck,
+ int memoryLimit,
+ long unpaddedSizeInIndex,
+ long uncompressedSizeInIndex)
+ throws IOException, IndexIndicatorException {
+ this.check = check;
+ this.verifyCheck = verifyCheck;
+ inData = new DataInputStream(in);
+
+ byte[] buf = new byte[DecoderUtil.BLOCK_HEADER_SIZE_MAX];
+
+ // Block Header Size or Index Indicator
+ inData.readFully(buf, 0, 1);
+
+ // See if this begins the Index field.
+ if (buf[0] == 0x00)
+ throw new IndexIndicatorException();
+
+ // Read the rest of the Block Header.
+ headerSize = 4 * ((buf[0] & 0xFF) + 1);
+ inData.readFully(buf, 1, headerSize - 1);
+
+ // Validate the CRC32.
+ if (!DecoderUtil.isCRC32Valid(buf, 0, headerSize - 4, headerSize - 4))
+ throw new CorruptedInputException("XZ Block Header is corrupt");
+
+ // Check for reserved bits in Block Flags.
+ if ((buf[1] & 0x3C) != 0)
+ throw new UnsupportedOptionsException(
+ "Unsupported options in XZ Block Header");
+
+ // Memory for the Filter Flags field
+ int filterCount = (buf[1] & 0x03) + 1;
+ long[] filterIDs = new long[filterCount];
+ byte[][] filterProps = new byte[filterCount][];
+
+ // Use a stream to parse the fields after the Block Flags field.
+ // Exclude the CRC32 field at the end.
+ ByteArrayInputStream bufStream = new ByteArrayInputStream(
+ buf, 2, headerSize - 6);
+
+ try {
+ // Set the maximum valid compressed size. This is overriden
+ // by the value from the Compressed Size field if it is present.
+ compressedSizeLimit = (DecoderUtil.VLI_MAX & ~3)
+ - headerSize - check.getSize();
+
+ // Decode and validate Compressed Size if the relevant flag
+ // is set in Block Flags.
+ if ((buf[1] & 0x40) != 0x00) {
+ compressedSizeInHeader = DecoderUtil.decodeVLI(bufStream);
+
+ if (compressedSizeInHeader == 0
+ || compressedSizeInHeader > compressedSizeLimit)
+ throw new CorruptedInputException();
+
+ compressedSizeLimit = compressedSizeInHeader;
+ }
+
+ // Decode Uncompressed Size if the relevant flag is set
+ // in Block Flags.
+ if ((buf[1] & 0x80) != 0x00)
+ uncompressedSizeInHeader = DecoderUtil.decodeVLI(bufStream);
+
+ // Decode Filter Flags.
+ for (int i = 0; i < filterCount; ++i) {
+ filterIDs[i] = DecoderUtil.decodeVLI(bufStream);
+
+ long filterPropsSize = DecoderUtil.decodeVLI(bufStream);
+ if (filterPropsSize > bufStream.available())
+ throw new CorruptedInputException();
+
+ filterProps[i] = new byte[(int)filterPropsSize];
+ bufStream.read(filterProps[i]);
+ }
+
+ } catch (IOException e) {
+ throw new CorruptedInputException("XZ Block Header is corrupt");
+ }
+
+ // Check that the remaining bytes are zero.
+ for (int i = bufStream.available(); i > 0; --i)
+ if (bufStream.read() != 0x00)
+ throw new UnsupportedOptionsException(
+ "Unsupported options in XZ Block Header");
+
+ // Validate the Blcok Header against the Index when doing
+ // random access reading.
+ if (unpaddedSizeInIndex != -1) {
+ // Compressed Data must be at least one byte, so if Block Header
+ // and Check alone take as much or more space than the size
+ // stored in the Index, the file is corrupt.
+ int headerAndCheckSize = headerSize + check.getSize();
+ if (headerAndCheckSize >= unpaddedSizeInIndex)
+ throw new CorruptedInputException(
+ "XZ Index does not match a Block Header");
+
+ // The compressed size calculated from Unpadded Size must
+ // match the value stored in the Compressed Size field in
+ // the Block Header.
+ long compressedSizeFromIndex
+ = unpaddedSizeInIndex - headerAndCheckSize;
+ if (compressedSizeFromIndex > compressedSizeLimit
+ || (compressedSizeInHeader != -1
+ && compressedSizeInHeader != compressedSizeFromIndex))
+ throw new CorruptedInputException(
+ "XZ Index does not match a Block Header");
+
+ // The uncompressed size stored in the Index must match
+ // the value stored in the Uncompressed Size field in
+ // the Block Header.
+ if (uncompressedSizeInHeader != -1
+ && uncompressedSizeInHeader != uncompressedSizeInIndex)
+ throw new CorruptedInputException(
+ "XZ Index does not match a Block Header");
+
+ // For further validation, pretend that the values from the Index
+ // were stored in the Block Header.
+ compressedSizeLimit = compressedSizeFromIndex;
+ compressedSizeInHeader = compressedSizeFromIndex;
+ uncompressedSizeInHeader = uncompressedSizeInIndex;
+ }
+
+ // Check if the Filter IDs are supported, decode
+ // the Filter Properties, and check that they are
+ // supported by this decoder implementation.
+ FilterDecoder[] filters = new FilterDecoder[filterIDs.length];
+
+ for (int i = 0; i < filters.length; ++i) {
+ if (filterIDs[i] == LZMA2Coder.FILTER_ID)
+ filters[i] = new LZMA2Decoder(filterProps[i]);
+
+ else if (filterIDs[i] == DeltaCoder.FILTER_ID)
+ filters[i] = new DeltaDecoder(filterProps[i]);
+
+ else if (BCJDecoder.isBCJFilterID(filterIDs[i]))
+ filters[i] = new BCJDecoder(filterIDs[i], filterProps[i]);
+
+ else
+ throw new UnsupportedOptionsException(
+ "Unknown Filter ID " + filterIDs[i]);
+ }
+
+ RawCoder.validate(filters);
+
+ // Check the memory usage limit.
+ if (memoryLimit >= 0) {
+ int memoryNeeded = 0;
+ for (int i = 0; i < filters.length; ++i)
+ memoryNeeded += filters[i].getMemoryUsage();
+
+ if (memoryNeeded > memoryLimit)
+ throw new MemoryLimitException(memoryNeeded, memoryLimit);
+ }
+
+ // Use an input size counter to calculate
+ // the size of the Compressed Data field.
+ inCounted = new CountingInputStream(in);
+
+ // Initialize the filter chain.
+ filterChain = inCounted;
+ for (int i = filters.length - 1; i >= 0; --i)
+ filterChain = filters[i].getInputStream(filterChain);
+ }
+
+ public int read() throws IOException {
+ return read(tempBuf, 0, 1) == -1 ? -1 : (tempBuf[0] & 0xFF);
+ }
+
+ public int read(byte[] buf, int off, int len) throws IOException {
+ if (endReached)
+ return -1;
+
+ int ret = filterChain.read(buf, off, len);
+
+ if (ret > 0) {
+ if (verifyCheck)
+ check.update(buf, off, ret);
+
+ uncompressedSize += ret;
+
+ // Catch invalid values.
+ long compressedSize = inCounted.getSize();
+ if (compressedSize < 0
+ || compressedSize > compressedSizeLimit
+ || uncompressedSize < 0
+ || (uncompressedSizeInHeader != -1
+ && uncompressedSize > uncompressedSizeInHeader))
+ throw new CorruptedInputException();
+
+ // Check the Block integrity as soon as possible:
+ // - The filter chain shouldn't return less than requested
+ // unless it hit the end of the input.
+ // - If the uncompressed size is known, we know when there
+ // shouldn't be more data coming. We still need to read
+ // one byte to let the filter chain catch errors and to
+ // let it read end of payload marker(s).
+ if (ret < len || uncompressedSize == uncompressedSizeInHeader) {
+ if (filterChain.read() != -1)
+ throw new CorruptedInputException();
+
+ validate();
+ endReached = true;
+ }
+ } else if (ret == -1) {
+ validate();
+ endReached = true;
+ }
+
+ return ret;
+ }
+
+ private void validate() throws IOException {
+ long compressedSize = inCounted.getSize();
+
+ // Validate Compressed Size and Uncompressed Size if they were
+ // present in Block Header.
+ if ((compressedSizeInHeader != -1
+ && compressedSizeInHeader != compressedSize)
+ || (uncompressedSizeInHeader != -1
+ && uncompressedSizeInHeader != uncompressedSize))
+ throw new CorruptedInputException();
+
+ // Block Padding bytes must be zeros.
+ while ((compressedSize++ & 3) != 0)
+ if (inData.readUnsignedByte() != 0x00)
+ throw new CorruptedInputException();
+
+ // Validate the integrity check if verifyCheck is true.
+ byte[] storedCheck = new byte[check.getSize()];
+ inData.readFully(storedCheck);
+ if (verifyCheck && !Arrays.equals(check.finish(), storedCheck))
+ throw new CorruptedInputException("Integrity check ("
+ + check.getName() + ") does not match");
+ }
+
+ public int available() throws IOException {
+ return filterChain.available();
+ }
+
+ public long getUnpaddedSize() {
+ return headerSize + inCounted.getSize() + check.getSize();
+ }
+
+ public long getUncompressedSize() {
+ return uncompressedSize;
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/BlockOutputStream.java b/lzma/Java/Tukaani/src/org/tukaani/xz/BlockOutputStream.java
new file mode 100644
index 0000000..03fd0a9
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/BlockOutputStream.java
@@ -0,0 +1,134 @@
+/*
+ * BlockOutputStream
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz;
+
+import java.io.OutputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import org.tukaani.xz.common.EncoderUtil;
+import org.tukaani.xz.check.Check;
+
+class BlockOutputStream extends FinishableOutputStream {
+ private final OutputStream out;
+ private final CountingOutputStream outCounted;
+ private FinishableOutputStream filterChain;
+ private final Check check;
+
+ private final int headerSize;
+ private final long compressedSizeLimit;
+ private long uncompressedSize = 0;
+
+ private final byte[] tempBuf = new byte[1];
+
+ public BlockOutputStream(OutputStream out, FilterEncoder[] filters,
+ Check check) throws IOException {
+ this.out = out;
+ this.check = check;
+
+ // Initialize the filter chain.
+ outCounted = new CountingOutputStream(out);
+ filterChain = outCounted;
+ for (int i = filters.length - 1; i >= 0; --i)
+ filterChain = filters[i].getOutputStream(filterChain);
+
+ // Prepare to encode the Block Header field.
+ ByteArrayOutputStream bufStream = new ByteArrayOutputStream();
+
+ // Write a dummy Block Header Size field. The real value is written
+ // once everything else except CRC32 has been written.
+ bufStream.write(0x00);
+
+ // Write Block Flags. Storing Compressed Size or Uncompressed Size
+ // isn't supported for now.
+ bufStream.write(filters.length - 1);
+
+ // List of Filter Flags
+ for (int i = 0; i < filters.length; ++i) {
+ EncoderUtil.encodeVLI(bufStream, filters[i].getFilterID());
+ byte[] filterProps = filters[i].getFilterProps();
+ EncoderUtil.encodeVLI(bufStream, filterProps.length);
+ bufStream.write(filterProps);
+ }
+
+ // Header Padding
+ while ((bufStream.size() & 3) != 0)
+ bufStream.write(0x00);
+
+ byte[] buf = bufStream.toByteArray();
+
+ // Total size of the Block Header: Take the size of the CRC32 field
+ // into account.
+ headerSize = buf.length + 4;
+
+ // This is just a sanity check.
+ if (headerSize > EncoderUtil.BLOCK_HEADER_SIZE_MAX)
+ throw new UnsupportedOptionsException();
+
+ // Block Header Size
+ buf[0] = (byte)(buf.length / 4);
+
+ // Write the Block Header field to the output stream.
+ out.write(buf);
+ EncoderUtil.writeCRC32(out, buf);
+
+ // Calculate the maximum allowed size of the Compressed Data field.
+ // It is hard to exceed it so this is mostly to be pedantic.
+ compressedSizeLimit = (EncoderUtil.VLI_MAX & ~3)
+ - headerSize - check.getSize();
+ }
+
+ public void write(int b) throws IOException {
+ tempBuf[0] = (byte)b;
+ write(tempBuf, 0, 1);
+ }
+
+ public void write(byte[] buf, int off, int len) throws IOException {
+ filterChain.write(buf, off, len);
+ check.update(buf, off, len);
+ uncompressedSize += len;
+ validate();
+ }
+
+ public void flush() throws IOException {
+ filterChain.flush();
+ validate();
+ }
+
+ public void finish() throws IOException {
+ // Finish the Compressed Data field.
+ filterChain.finish();
+ validate();
+
+ // Block Padding
+ for (long i = outCounted.getSize(); (i & 3) != 0; ++i)
+ out.write(0x00);
+
+ // Check
+ out.write(check.finish());
+ }
+
+ private void validate() throws IOException {
+ long compressedSize = outCounted.getSize();
+
+ // It is very hard to trigger this exception.
+ // This is just to be pedantic.
+ if (compressedSize < 0 || compressedSize > compressedSizeLimit
+ || uncompressedSize < 0)
+ throw new XZIOException("XZ Stream has grown too big");
+ }
+
+ public long getUnpaddedSize() {
+ return headerSize + outCounted.getSize() + check.getSize();
+ }
+
+ public long getUncompressedSize() {
+ return uncompressedSize;
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/CorruptedInputException.java b/lzma/Java/Tukaani/src/org/tukaani/xz/CorruptedInputException.java
new file mode 100644
index 0000000..d7d9520
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/CorruptedInputException.java
@@ -0,0 +1,37 @@
+/*
+ * CorruptedInputException
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz;
+
+/**
+ * Thrown when the compressed input data is corrupt.
+ * However, it is possible that some or all of the data
+ * already read from the input stream was corrupt too.
+ */
+public class CorruptedInputException extends XZIOException {
+ private static final long serialVersionUID = 3L;
+
+ /**
+ * Creates a new CorruptedInputException with
+ * the default error detail message.
+ */
+ public CorruptedInputException() {
+ super("Compressed data is corrupt");
+ }
+
+ /**
+ * Creates a new CorruptedInputException with
+ * the specified error detail message.
+ *
+ * @param s error detail message
+ */
+ public CorruptedInputException(String s) {
+ super(s);
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/CountingInputStream.java b/lzma/Java/Tukaani/src/org/tukaani/xz/CountingInputStream.java
new file mode 100644
index 0000000..ce0935a
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/CountingInputStream.java
@@ -0,0 +1,45 @@
+/*
+ * CountingInputStream
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz;
+
+import java.io.FilterInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+
+/**
+ * Counts the number of bytes read from an input stream.
+ */
+class CountingInputStream extends FilterInputStream {
+ private long size = 0;
+
+ public CountingInputStream(InputStream in) {
+ super(in);
+ }
+
+ public int read() throws IOException {
+ int ret = in.read();
+ if (ret != -1 && size >= 0)
+ ++size;
+
+ return ret;
+ }
+
+ public int read(byte[] b, int off, int len) throws IOException {
+ int ret = in.read(b, off, len);
+ if (ret > 0 && size >= 0)
+ size += ret;
+
+ return ret;
+ }
+
+ public long getSize() {
+ return size;
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/CountingOutputStream.java b/lzma/Java/Tukaani/src/org/tukaani/xz/CountingOutputStream.java
new file mode 100644
index 0000000..9b3eef3
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/CountingOutputStream.java
@@ -0,0 +1,54 @@
+/*
+ * CountingOutputStream
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz;
+
+import java.io.OutputStream;
+import java.io.IOException;
+
+/**
+ * Counts the number of bytes written to an output stream.
+ * <p>
+ * The <code>finish</code> method does nothing.
+ * This is <code>FinishableOutputStream</code> instead
+ * of <code>OutputStream</code> solely because it allows
+ * using this as the output stream for a chain of raw filters.
+ */
+class CountingOutputStream extends FinishableOutputStream {
+ private final OutputStream out;
+ private long size = 0;
+
+ public CountingOutputStream(OutputStream out) {
+ this.out = out;
+ }
+
+ public void write(int b) throws IOException {
+ out.write(b);
+ if (size >= 0)
+ ++size;
+ }
+
+ public void write(byte[] b, int off, int len) throws IOException {
+ out.write(b, off, len);
+ if (size >= 0)
+ size += len;
+ }
+
+ public void flush() throws IOException {
+ out.flush();
+ }
+
+ public void close() throws IOException {
+ out.close();
+ }
+
+ public long getSize() {
+ return size;
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/DeltaCoder.java b/lzma/Java/Tukaani/src/org/tukaani/xz/DeltaCoder.java
new file mode 100644
index 0000000..808834c
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/DeltaCoder.java
@@ -0,0 +1,26 @@
+/*
+ * DeltaCoder
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz;
+
+abstract class DeltaCoder implements FilterCoder {
+ public static final long FILTER_ID = 0x03;
+
+ public boolean changesSize() {
+ return false;
+ }
+
+ public boolean nonLastOK() {
+ return true;
+ }
+
+ public boolean lastOK() {
+ return false;
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/DeltaDecoder.java b/lzma/Java/Tukaani/src/org/tukaani/xz/DeltaDecoder.java
new file mode 100644
index 0000000..445d178
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/DeltaDecoder.java
@@ -0,0 +1,32 @@
+/*
+ * DeltaDecoder
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz;
+
+import java.io.InputStream;
+
+class DeltaDecoder extends DeltaCoder implements FilterDecoder {
+ private final int distance;
+
+ DeltaDecoder(byte[] props) throws UnsupportedOptionsException {
+ if (props.length != 1)
+ throw new UnsupportedOptionsException(
+ "Unsupported Delta filter properties");
+
+ distance = (props[0] & 0xFF) + 1;
+ }
+
+ public int getMemoryUsage() {
+ return 1;
+ }
+
+ public InputStream getInputStream(InputStream in) {
+ return new DeltaInputStream(in, distance);
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/DeltaEncoder.java b/lzma/Java/Tukaani/src/org/tukaani/xz/DeltaEncoder.java
new file mode 100644
index 0000000..384afe4
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/DeltaEncoder.java
@@ -0,0 +1,36 @@
+/*
+ * DeltaEncoder
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz;
+
+class DeltaEncoder extends DeltaCoder implements FilterEncoder {
+ private final DeltaOptions options;
+ private final byte[] props = new byte[1];
+
+ DeltaEncoder(DeltaOptions options) {
+ props[0] = (byte)(options.getDistance() - 1);
+ this.options = (DeltaOptions)options.clone();
+ }
+
+ public long getFilterID() {
+ return FILTER_ID;
+ }
+
+ public byte[] getFilterProps() {
+ return props;
+ }
+
+ public boolean supportsFlushing() {
+ return true;
+ }
+
+ public FinishableOutputStream getOutputStream(FinishableOutputStream out) {
+ return options.getOutputStream(out);
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/DeltaInputStream.java b/lzma/Java/Tukaani/src/org/tukaani/xz/DeltaInputStream.java
new file mode 100644
index 0000000..56478f5
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/DeltaInputStream.java
@@ -0,0 +1,146 @@
+/*
+ * DeltaInputStream
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz;
+
+import java.io.InputStream;
+import java.io.IOException;
+import org.tukaani.xz.delta.DeltaDecoder;
+
+/**
+ * Decodes raw Delta-filtered data (no XZ headers).
+ * <p>
+ * The delta filter doesn't change the size of the data and thus it
+ * cannot have an end-of-payload marker. It will simply decode until
+ * its input stream indicates end of input.
+ */
+public class DeltaInputStream extends InputStream {
+ /**
+ * Smallest supported delta calculation distance.
+ */
+ public static final int DISTANCE_MIN = 1;
+
+ /**
+ * Largest supported delta calculation distance.
+ */
+ public static final int DISTANCE_MAX = 256;
+
+ private InputStream in;
+ private final DeltaDecoder delta;
+
+ private IOException exception = null;
+
+ private final byte[] tempBuf = new byte[1];
+
+ /**
+ * Creates a new Delta decoder with the given delta calculation distance.
+ *
+ * @param in input stream from which Delta filtered data
+ * is read
+ *
+ * @param distance delta calculation distance, must be in the
+ * range [<code>DISTANCE_MIN</code>,
+ * <code>DISTANCE_MAX</code>]
+ */
+ public DeltaInputStream(InputStream in, int distance) {
+ // Check for null because otherwise null isn't detect
+ // in this constructor.
+ if (in == null)
+ throw new NullPointerException();
+
+ this.in = in;
+ this.delta = new DeltaDecoder(distance);
+ }
+
+ /**
+ * Decode the next byte from this input stream.
+ *
+ * @return the next decoded byte, or <code>-1</code> to indicate
+ * the end of input on the input stream <code>in</code>
+ *
+ * @throws IOException may be thrown by <code>in</code>
+ */
+ public int read() throws IOException {
+ return read(tempBuf, 0, 1) == -1 ? -1 : (tempBuf[0] & 0xFF);
+ }
+
+ /**
+ * Decode into an array of bytes.
+ * <p>
+ * This calls <code>in.read(buf, off, len)</code> and defilters the
+ * returned data.
+ *
+ * @param buf target buffer for decoded data
+ * @param off start offset in <code>buf</code>
+ * @param len maximum number of bytes to read
+ *
+ * @return number of bytes read, or <code>-1</code> to indicate
+ * the end of the input stream <code>in</code>
+ *
+ * @throws XZIOException if the stream has been closed
+ *
+ * @throws IOException may be thrown by underlaying input
+ * stream <code>in</code>
+ */
+ public int read(byte[] buf, int off, int len) throws IOException {
+ if (len == 0)
+ return 0;
+
+ if (in == null)
+ throw new XZIOException("Stream closed");
+
+ if (exception != null)
+ throw exception;
+
+ int size;
+ try {
+ size = in.read(buf, off, len);
+ } catch (IOException e) {
+ exception = e;
+ throw e;
+ }
+
+ if (size == -1)
+ return -1;
+
+ delta.decode(buf, off, size);
+ return size;
+ }
+
+ /**
+ * Calls <code>in.available()</code>.
+ *
+ * @return the value returned by <code>in.available()</code>
+ */
+ public int available() throws IOException {
+ if (in == null)
+ throw new XZIOException("Stream closed");
+
+ if (exception != null)
+ throw exception;
+
+ return in.available();
+ }
+
+ /**
+ * Closes the stream and calls <code>in.close()</code>.
+ * If the stream was already closed, this does nothing.
+ *
+ * @throws IOException if thrown by <code>in.close()</code>
+ */
+ public void close() throws IOException {
+ if (in != null) {
+ try {
+ in.close();
+ } finally {
+ in = null;
+ }
+ }
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/DeltaOptions.java b/lzma/Java/Tukaani/src/org/tukaani/xz/DeltaOptions.java
new file mode 100644
index 0000000..145130b
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/DeltaOptions.java
@@ -0,0 +1,102 @@
+/*
+ * DeltaOptions
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz;
+
+import java.io.InputStream;
+
+/**
+ * Delta filter options. The Delta filter can be used only as a non-last
+ * filter in the chain, for example Delta + LZMA2.
+ * <p>
+ * Currently only simple byte-wise delta is supported. The only option
+ * is the delta distance, which you should set to match your data.
+ * It's not possible to provide a generic default value for it.
+ * <p>
+ * For example, with distance = 2 and eight-byte input
+ * A1 B1 A2 B3 A3 B5 A4 B7, the output will be A1 B1 01 02 01 02 01 02.
+ * <p>
+ * The Delta filter can be good with uncompressed bitmap images. It can
+ * also help with PCM audio, although special-purpose compressors like
+ * FLAC will give much smaller result at much better compression speed.
+ */
+public class DeltaOptions extends FilterOptions {
+ /**
+ * Smallest supported delta calculation distance.
+ */
+ public static final int DISTANCE_MIN = 1;
+
+ /**
+ * Largest supported delta calculation distance.
+ */
+ public static final int DISTANCE_MAX = 256;
+
+ private int distance = DISTANCE_MIN;
+
+ /**
+ * Creates new Delta options and sets the delta distance to 1 byte.
+ */
+ public DeltaOptions() {}
+
+ /**
+ * Creates new Delta options and sets the distance to the given value.
+ */
+ public DeltaOptions(int distance) throws UnsupportedOptionsException {
+ setDistance(distance);
+ }
+
+ /**
+ * Sets the delta distance in bytes. The new distance must be in
+ * the range [DISTANCE_MIN, DISTANCE_MAX].
+ */
+ public void setDistance(int distance) throws UnsupportedOptionsException {
+ if (distance < DISTANCE_MIN || distance > DISTANCE_MAX)
+ throw new UnsupportedOptionsException(
+ "Delta distance must be in the range [" + DISTANCE_MIN
+ + ", " + DISTANCE_MAX + "]: " + distance);
+
+ this.distance = distance;
+ }
+
+ /**
+ * Gets the delta distance.
+ */
+ public int getDistance() {
+ return distance;
+ }
+
+ public int getEncoderMemoryUsage() {
+ return DeltaOutputStream.getMemoryUsage();
+ }
+
+ public FinishableOutputStream getOutputStream(FinishableOutputStream out) {
+ return new DeltaOutputStream(out, this);
+ }
+
+ public int getDecoderMemoryUsage() {
+ return 1;
+ }
+
+ public InputStream getInputStream(InputStream in) {
+ return new DeltaInputStream(in, distance);
+ }
+
+ FilterEncoder getFilterEncoder() {
+ return new DeltaEncoder(this);
+ }
+
+ public Object clone() {
+ try {
+ return super.clone();
+ } catch (CloneNotSupportedException e) {
+ assert false;
+ throw new RuntimeException();
+ }
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/DeltaOutputStream.java b/lzma/Java/Tukaani/src/org/tukaani/xz/DeltaOutputStream.java
new file mode 100644
index 0000000..bd880db
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/DeltaOutputStream.java
@@ -0,0 +1,113 @@
+/*
+ * DeltaOutputStream
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz;
+
+import java.io.IOException;
+import org.tukaani.xz.delta.DeltaEncoder;
+
+class DeltaOutputStream extends FinishableOutputStream {
+ private static final int FILTER_BUF_SIZE = 4096;
+
+ private FinishableOutputStream out;
+ private final DeltaEncoder delta;
+ private final byte[] filterBuf = new byte[FILTER_BUF_SIZE];
+
+ private boolean finished = false;
+ private IOException exception = null;
+
+ private final byte[] tempBuf = new byte[1];
+
+ static int getMemoryUsage() {
+ return 1 + FILTER_BUF_SIZE / 1024;
+ }
+
+ DeltaOutputStream(FinishableOutputStream out, DeltaOptions options) {
+ this.out = out;
+ delta = new DeltaEncoder(options.getDistance());
+ }
+
+ public void write(int b) throws IOException {
+ tempBuf[0] = (byte)b;
+ write(tempBuf, 0, 1);
+ }
+
+ public void write(byte[] buf, int off, int len) throws IOException {
+ if (off < 0 || len < 0 || off + len < 0 || off + len > buf.length)
+ throw new IndexOutOfBoundsException();
+
+ if (exception != null)
+ throw exception;
+
+ if (finished)
+ throw new XZIOException("Stream finished");
+
+ try {
+ while (len > FILTER_BUF_SIZE) {
+ delta.encode(buf, off, FILTER_BUF_SIZE, filterBuf);
+ out.write(filterBuf);
+ off += FILTER_BUF_SIZE;
+ len -= FILTER_BUF_SIZE;
+ }
+
+ delta.encode(buf, off, len, filterBuf);
+ out.write(filterBuf, 0, len);
+ } catch (IOException e) {
+ exception = e;
+ throw e;
+ }
+ }
+
+ public void flush() throws IOException {
+ if (exception != null)
+ throw exception;
+
+ if (finished)
+ throw new XZIOException("Stream finished or closed");
+
+ try {
+ out.flush();
+ } catch (IOException e) {
+ exception = e;
+ throw e;
+ }
+ }
+
+ public void finish() throws IOException {
+ if (!finished) {
+ if (exception != null)
+ throw exception;
+
+ try {
+ out.finish();
+ } catch (IOException e) {
+ exception = e;
+ throw e;
+ }
+
+ finished = true;
+ }
+ }
+
+ public void close() throws IOException {
+ if (out != null) {
+ try {
+ out.close();
+ } catch (IOException e) {
+ if (exception == null)
+ exception = e;
+ }
+
+ out = null;
+ }
+
+ if (exception != null)
+ throw exception;
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/FilterCoder.java b/lzma/Java/Tukaani/src/org/tukaani/xz/FilterCoder.java
new file mode 100644
index 0000000..1e95e37
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/FilterCoder.java
@@ -0,0 +1,16 @@
+/*
+ * FilterCoder
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz;
+
+interface FilterCoder {
+ boolean changesSize();
+ boolean nonLastOK();
+ boolean lastOK();
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/FilterDecoder.java b/lzma/Java/Tukaani/src/org/tukaani/xz/FilterDecoder.java
new file mode 100644
index 0000000..8e2d006
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/FilterDecoder.java
@@ -0,0 +1,17 @@
+/*
+ * FilterDecoder
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz;
+
+import java.io.InputStream;
+
+interface FilterDecoder extends FilterCoder {
+ int getMemoryUsage();
+ InputStream getInputStream(InputStream in);
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/FilterEncoder.java b/lzma/Java/Tukaani/src/org/tukaani/xz/FilterEncoder.java
new file mode 100644
index 0000000..4558aad
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/FilterEncoder.java
@@ -0,0 +1,17 @@
+/*
+ * FilterEncoder
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz;
+
+interface FilterEncoder extends FilterCoder {
+ long getFilterID();
+ byte[] getFilterProps();
+ boolean supportsFlushing();
+ FinishableOutputStream getOutputStream(FinishableOutputStream out);
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/FilterOptions.java b/lzma/Java/Tukaani/src/org/tukaani/xz/FilterOptions.java
new file mode 100644
index 0000000..a2398b4
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/FilterOptions.java
@@ -0,0 +1,80 @@
+/*
+ * FilterOptions
+ *
+ * Authors: Lasse Collin <lasse.collin@tukaani.org>
+ * Igor Pavlov <http://7-zip.org/>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz;
+
+import java.io.InputStream;
+import java.io.IOException;
+
+/**
+ * Base class for filter-specific options classes.
+ */
+public abstract class FilterOptions implements Cloneable {
+ /**
+ * Gets how much memory the encoder will need with
+ * the given filter chain. This function simply calls
+ * <code>getEncoderMemoryUsage()</code> for every filter
+ * in the array and returns the sum of the returned values.
+ */
+ public static int getEncoderMemoryUsage(FilterOptions[] options) {
+ int m = 0;
+
+ for (int i = 0; i < options.length; ++i)
+ m += options[i].getEncoderMemoryUsage();
+
+ return m;
+ }
+
+ /**
+ * Gets how much memory the decoder will need with
+ * the given filter chain. This function simply calls
+ * <code>getDecoderMemoryUsage()</code> for every filter
+ * in the array and returns the sum of the returned values.
+ */
+ public static int getDecoderMemoryUsage(FilterOptions[] options) {
+ int m = 0;
+
+ for (int i = 0; i < options.length; ++i)
+ m += options[i].getDecoderMemoryUsage();
+
+ return m;
+ }
+
+ /**
+ * Gets how much memory the encoder will need with these options.
+ */
+ public abstract int getEncoderMemoryUsage();
+
+ /**
+ * Gets a raw (no XZ headers) encoder output stream using these options.
+ * Raw streams are an advanced feature. In most cases you want to store
+ * the compressed data in the .xz container format instead of using
+ * a raw stream. To use this filter in a .xz file, pass this object
+ * to XZOutputStream.
+ */
+ public abstract FinishableOutputStream getOutputStream(
+ FinishableOutputStream out);
+
+ /**
+ * Gets how much memory the decoder will need to decompress the data
+ * that was encoded with these options.
+ */
+ public abstract int getDecoderMemoryUsage();
+
+ /**
+ * Gets a raw (no XZ headers) decoder input stream using these options.
+ */
+ public abstract InputStream getInputStream(InputStream in)
+ throws IOException;
+
+ abstract FilterEncoder getFilterEncoder();
+
+ FilterOptions() {}
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/FinishableOutputStream.java b/lzma/Java/Tukaani/src/org/tukaani/xz/FinishableOutputStream.java
new file mode 100644
index 0000000..b360628
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/FinishableOutputStream.java
@@ -0,0 +1,31 @@
+/*
+ * FinishableOutputStream
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz;
+
+import java.io.OutputStream;
+import java.io.IOException;
+
+/**
+ * Output stream that supports finishing without closing
+ * the underlying stream.
+ */
+public abstract class FinishableOutputStream extends OutputStream {
+ /**
+ * Finish the stream without closing the underlying stream.
+ * No more data may be written to the stream after finishing.
+ * <p>
+ * The <code>finish</code> method of <code>FinishableOutputStream</code>
+ * does nothing. Subclasses should override it if they need finishing
+ * support, which is the case, for example, with compressors.
+ *
+ * @throws IOException
+ */
+ public void finish() throws IOException {};
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/FinishableWrapperOutputStream.java b/lzma/Java/Tukaani/src/org/tukaani/xz/FinishableWrapperOutputStream.java
new file mode 100644
index 0000000..2e0ac99
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/FinishableWrapperOutputStream.java
@@ -0,0 +1,70 @@
+/*
+ * FinishableWrapperOutputStream
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz;
+
+import java.io.OutputStream;
+import java.io.IOException;
+
+/**
+ * Wraps an output stream to a finishable output stream for use with
+ * raw encoders. This is not needed for XZ compression and thus most
+ * people will never need this.
+ */
+public class FinishableWrapperOutputStream extends FinishableOutputStream {
+ /**
+ * The {@link java.io.OutputStream OutputStream} that has been
+ * wrapped into a FinishableWrapperOutputStream.
+ */
+ protected OutputStream out;
+
+ /**
+ * Creates a new output stream which support finishing.
+ * The <code>finish()</code> method will do nothing.
+ */
+ public FinishableWrapperOutputStream(OutputStream out) {
+ this.out = out;
+ }
+
+ /**
+ * Calls {@link java.io.OutputStream#write(int) out.write(b)}.
+ */
+ public void write(int b) throws IOException {
+ out.write(b);
+ }
+
+ /**
+ * Calls {@link java.io.OutputStream#write(byte[]) out.write(buf)}.
+ */
+ public void write(byte[] buf) throws IOException {
+ out.write(buf);
+ }
+
+ /**
+ * Calls {@link java.io.OutputStream#write(byte[],int,int)
+ out.write(buf, off, len)}.
+ */
+ public void write(byte[] buf, int off, int len) throws IOException {
+ out.write(buf, off, len);
+ }
+
+ /**
+ * Calls {@link java.io.OutputStream#flush() out.flush()}.
+ */
+ public void flush() throws IOException {
+ out.flush();
+ }
+
+ /**
+ * Calls {@link java.io.OutputStream#close() out.close()}.
+ */
+ public void close() throws IOException {
+ out.close();
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/IA64Options.java b/lzma/Java/Tukaani/src/org/tukaani/xz/IA64Options.java
new file mode 100644
index 0000000..ba57870
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/IA64Options.java
@@ -0,0 +1,36 @@
+/*
+ * IA64Options
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz;
+
+import java.io.InputStream;
+import org.tukaani.xz.simple.IA64;
+
+/**
+ * BCJ filter for Itanium (IA-64) instructions.
+ */
+public class IA64Options extends BCJOptions {
+ private static final int ALIGNMENT = 16;
+
+ public IA64Options() {
+ super(ALIGNMENT);
+ }
+
+ public FinishableOutputStream getOutputStream(FinishableOutputStream out) {
+ return new SimpleOutputStream(out, new IA64(true, startOffset));
+ }
+
+ public InputStream getInputStream(InputStream in) {
+ return new SimpleInputStream(in, new IA64(false, startOffset));
+ }
+
+ FilterEncoder getFilterEncoder() {
+ return new BCJEncoder(this, BCJCoder.IA64_FILTER_ID);
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/IndexIndicatorException.java b/lzma/Java/Tukaani/src/org/tukaani/xz/IndexIndicatorException.java
new file mode 100644
index 0000000..fc6bc03
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/IndexIndicatorException.java
@@ -0,0 +1,14 @@
+/*
+ * IndexIndicatorException
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz;
+
+class IndexIndicatorException extends Exception {
+ private static final long serialVersionUID = 1L;
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/LZMA2Coder.java b/lzma/Java/Tukaani/src/org/tukaani/xz/LZMA2Coder.java
new file mode 100644
index 0000000..b0963b7
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/LZMA2Coder.java
@@ -0,0 +1,26 @@
+/*
+ * LZMA2Coder
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz;
+
+abstract class LZMA2Coder implements FilterCoder {
+ public static final long FILTER_ID = 0x21;
+
+ public boolean changesSize() {
+ return true;
+ }
+
+ public boolean nonLastOK() {
+ return false;
+ }
+
+ public boolean lastOK() {
+ return true;
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/LZMA2Decoder.java b/lzma/Java/Tukaani/src/org/tukaani/xz/LZMA2Decoder.java
new file mode 100644
index 0000000..82075c2
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/LZMA2Decoder.java
@@ -0,0 +1,35 @@
+/*
+ * LZMA2Decoder
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz;
+
+import java.io.InputStream;
+
+class LZMA2Decoder extends LZMA2Coder implements FilterDecoder {
+ private int dictSize;
+
+ LZMA2Decoder(byte[] props) throws UnsupportedOptionsException {
+ // Up to 1.5 GiB dictionary is supported. The bigger ones
+ // are too big for int.
+ if (props.length != 1 || (props[0] & 0xFF) > 37)
+ throw new UnsupportedOptionsException(
+ "Unsupported LZMA2 properties");
+
+ dictSize = 2 | (props[0] & 1);
+ dictSize <<= (props[0] >>> 1) + 11;
+ }
+
+ public int getMemoryUsage() {
+ return LZMA2InputStream.getMemoryUsage(dictSize);
+ }
+
+ public InputStream getInputStream(InputStream in) {
+ return new LZMA2InputStream(in, dictSize);
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/LZMA2Encoder.java b/lzma/Java/Tukaani/src/org/tukaani/xz/LZMA2Encoder.java
new file mode 100644
index 0000000..7c7facc
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/LZMA2Encoder.java
@@ -0,0 +1,50 @@
+/*
+ * LZMA2Encoder
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz;
+
+import org.tukaani.xz.lzma.LZMAEncoder;
+
+class LZMA2Encoder extends LZMA2Coder implements FilterEncoder {
+ private final LZMA2Options options;
+ private final byte[] props = new byte[1];
+
+ LZMA2Encoder(LZMA2Options options) {
+ if (options.getPresetDict() != null)
+ throw new IllegalArgumentException(
+ "XZ doesn't support a preset dictionary for now");
+
+ if (options.getMode() == LZMA2Options.MODE_UNCOMPRESSED) {
+ props[0] = (byte)0;
+ } else {
+ int d = Math.max(options.getDictSize(),
+ LZMA2Options.DICT_SIZE_MIN);
+ props[0] = (byte)(LZMAEncoder.getDistSlot(d - 1) - 23);
+ }
+
+ // Make a private copy so that the caller is free to change its copy.
+ this.options = (LZMA2Options)options.clone();
+ }
+
+ public long getFilterID() {
+ return FILTER_ID;
+ }
+
+ public byte[] getFilterProps() {
+ return props;
+ }
+
+ public boolean supportsFlushing() {
+ return true;
+ }
+
+ public FinishableOutputStream getOutputStream(FinishableOutputStream out) {
+ return options.getOutputStream(out);
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/LZMA2InputStream.java b/lzma/Java/Tukaani/src/org/tukaani/xz/LZMA2InputStream.java
new file mode 100644
index 0000000..4e865c6
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/LZMA2InputStream.java
@@ -0,0 +1,358 @@
+/*
+ * LZMA2InputStream
+ *
+ * Authors: Lasse Collin <lasse.collin@tukaani.org>
+ * Igor Pavlov <http://7-zip.org/>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz;
+
+import java.io.InputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+import org.tukaani.xz.lz.LZDecoder;
+import org.tukaani.xz.rangecoder.RangeDecoderFromBuffer;
+import org.tukaani.xz.lzma.LZMADecoder;
+
+/**
+ * Decompresses a raw LZMA2 stream (no XZ headers).
+ */
+public class LZMA2InputStream extends InputStream {
+ /**
+ * Smallest valid LZMA2 dictionary size.
+ * <p>
+ * Very tiny dictionaries would be a performance problem, so
+ * the minimum is 4 KiB.
+ */
+ public static final int DICT_SIZE_MIN = 4096;
+
+ /**
+ * Largest dictionary size supported by this implementation.
+ * <p>
+ * The LZMA2 algorithm allows dictionaries up to one byte less than 4 GiB.
+ * This implementation supports only 16 bytes less than 2 GiB for raw
+ * LZMA2 streams, and for .xz files the maximum is 1.5 GiB. This
+ * limitation is due to Java using signed 32-bit integers for array
+ * indexing. The limitation shouldn't matter much in practice since so
+ * huge dictionaries are not normally used.
+ */
+ public static final int DICT_SIZE_MAX = Integer.MAX_VALUE & ~15;
+
+ private static final int COMPRESSED_SIZE_MAX = 1 << 16;
+
+ private DataInputStream in;
+
+ private final LZDecoder lz;
+ private final RangeDecoderFromBuffer rc
+ = new RangeDecoderFromBuffer(COMPRESSED_SIZE_MAX);
+ private LZMADecoder lzma;
+
+ private int uncompressedSize = 0;
+ private boolean isLZMAChunk;
+
+ private boolean needDictReset = true;
+ private boolean needProps = true;
+ private boolean endReached = false;
+
+ private IOException exception = null;
+
+ private final byte[] tempBuf = new byte[1];
+
+ /**
+ * Gets approximate decompressor memory requirements as kibibytes for
+ * the given dictionary size.
+ *
+ * @param dictSize LZMA2 dictionary size as bytes, must be
+ * in the range [<code>DICT_SIZE_MIN</code>,
+ * <code>DICT_SIZE_MAX</code>]
+ *
+ * @return approximate memory requirements as kibibytes (KiB)
+ */
+ public static int getMemoryUsage(int dictSize) {
+ // The base state is around 30-40 KiB (probabilities etc.),
+ // range decoder needs COMPRESSED_SIZE_MAX bytes for buffering,
+ // and LZ decoder needs a dictionary buffer.
+ return 40 + COMPRESSED_SIZE_MAX / 1024 + getDictSize(dictSize) / 1024;
+ }
+
+ private static int getDictSize(int dictSize) {
+ if (dictSize < DICT_SIZE_MIN || dictSize > DICT_SIZE_MAX)
+ throw new IllegalArgumentException(
+ "Unsupported dictionary size " + dictSize);
+
+ // Round dictionary size upward to a multiple of 16. This way LZMA
+ // can use LZDecoder.getPos() for calculating LZMA's posMask.
+ // Note that this check is needed only for raw LZMA2 streams; it is
+ // redundant with .xz.
+ return (dictSize + 15) & ~15;
+ }
+
+ /**
+ * Creates a new input stream that decompresses raw LZMA2 data
+ * from <code>in</code>.
+ * <p>
+ * The caller needs to know the dictionary size used when compressing;
+ * the dictionary size isn't stored as part of a raw LZMA2 stream.
+ * <p>
+ * Specifying a too small dictionary size will prevent decompressing
+ * the stream. Specifying a too big dictionary is waste of memory but
+ * decompression will work.
+ * <p>
+ * There is no need to specify a dictionary bigger than
+ * the uncompressed size of the data even if a bigger dictionary
+ * was used when compressing. If you know the uncompressed size
+ * of the data, this might allow saving some memory.
+ *
+ * @param in input stream from which LZMA2-compressed
+ * data is read
+ *
+ * @param dictSize LZMA2 dictionary size as bytes, must be
+ * in the range [<code>DICT_SIZE_MIN</code>,
+ * <code>DICT_SIZE_MAX</code>]
+ */
+ public LZMA2InputStream(InputStream in, int dictSize) {
+ this(in, dictSize, null);
+ }
+
+ /**
+ * Creates a new LZMA2 decompressor using a preset dictionary.
+ * <p>
+ * This is like <code>LZMA2InputStream(InputStream, int)</code> except
+ * that the dictionary may be initialized using a preset dictionary.
+ * If a preset dictionary was used when compressing the data, the
+ * same preset dictionary must be provided when decompressing.
+ *
+ * @param in input stream from which LZMA2-compressed
+ * data is read
+ *
+ * @param dictSize LZMA2 dictionary size as bytes, must be
+ * in the range [<code>DICT_SIZE_MIN</code>,
+ * <code>DICT_SIZE_MAX</code>]
+ *
+ * @param presetDict preset dictionary or <code>null</code>
+ * to use no preset dictionary
+ */
+ public LZMA2InputStream(InputStream in, int dictSize, byte[] presetDict) {
+ // Check for null because otherwise null isn't detect
+ // in this constructor.
+ if (in == null)
+ throw new NullPointerException();
+
+ this.in = new DataInputStream(in);
+ this.lz = new LZDecoder(getDictSize(dictSize), presetDict);
+
+ if (presetDict != null && presetDict.length > 0)
+ needDictReset = false;
+ }
+
+ /**
+ * Decompresses the next byte from this input stream.
+ * <p>
+ * Reading lots of data with <code>read()</code> from this input stream
+ * may be inefficient. Wrap it in <code>java.io.BufferedInputStream</code>
+ * if you need to read lots of data one byte at a time.
+ *
+ * @return the next decompressed byte, or <code>-1</code>
+ * to indicate the end of the compressed stream
+ *
+ * @throws CorruptedInputException
+ *
+ * @throws XZIOException if the stream has been closed
+ *
+ * @throws EOFException
+ * compressed input is truncated or corrupt
+ *
+ * @throws IOException may be thrown by <code>in</code>
+ */
+ public int read() throws IOException {
+ return read(tempBuf, 0, 1) == -1 ? -1 : (tempBuf[0] & 0xFF);
+ }
+
+ /**
+ * Decompresses into an array of bytes.
+ * <p>
+ * If <code>len</code> is zero, no bytes are read and <code>0</code>
+ * is returned. Otherwise this will block until <code>len</code>
+ * bytes have been decompressed, the end of the LZMA2 stream is reached,
+ * or an exception is thrown.
+ *
+ * @param buf target buffer for uncompressed data
+ * @param off start offset in <code>buf</code>
+ * @param len maximum number of uncompressed bytes to read
+ *
+ * @return number of bytes read, or <code>-1</code> to indicate
+ * the end of the compressed stream
+ *
+ * @throws CorruptedInputException
+ *
+ * @throws XZIOException if the stream has been closed
+ *
+ * @throws EOFException
+ * compressed input is truncated or corrupt
+ *
+ * @throws IOException may be thrown by <code>in</code>
+ */
+ public int read(byte[] buf, int off, int len) throws IOException {
+ if (off < 0 || len < 0 || off + len < 0 || off + len > buf.length)
+ throw new IndexOutOfBoundsException();
+
+ if (len == 0)
+ return 0;
+
+ if (in == null)
+ throw new XZIOException("Stream closed");
+
+ if (exception != null)
+ throw exception;
+
+ if (endReached)
+ return -1;
+
+ try {
+ int size = 0;
+
+ while (len > 0) {
+ if (uncompressedSize == 0) {
+ decodeChunkHeader();
+ if (endReached)
+ return size == 0 ? -1 : size;
+ }
+
+ int copySizeMax = Math.min(uncompressedSize, len);
+
+ if (!isLZMAChunk) {
+ lz.copyUncompressed(in, copySizeMax);
+ } else {
+ lz.setLimit(copySizeMax);
+ lzma.decode();
+ if (!rc.isInBufferOK())
+ throw new CorruptedInputException();
+ }
+
+ int copiedSize = lz.flush(buf, off);
+ off += copiedSize;
+ len -= copiedSize;
+ size += copiedSize;
+ uncompressedSize -= copiedSize;
+
+ if (uncompressedSize == 0)
+ if (!rc.isFinished() || lz.hasPending())
+ throw new CorruptedInputException();
+ }
+
+ return size;
+
+ } catch (IOException e) {
+ exception = e;
+ throw e;
+ }
+ }
+
+ private void decodeChunkHeader() throws IOException {
+ int control = in.readUnsignedByte();
+
+ if (control == 0x00) {
+ endReached = true;
+ return;
+ }
+
+ if (control >= 0xE0 || control == 0x01) {
+ needProps = true;
+ needDictReset = false;
+ lz.reset();
+ } else if (needDictReset) {
+ throw new CorruptedInputException();
+ }
+
+ if (control >= 0x80) {
+ isLZMAChunk = true;
+
+ uncompressedSize = (control & 0x1F) << 16;
+ uncompressedSize += in.readUnsignedShort() + 1;
+
+ int compressedSize = in.readUnsignedShort() + 1;
+
+ if (control >= 0xC0) {
+ needProps = false;
+ decodeProps();
+
+ } else if (needProps) {
+ throw new CorruptedInputException();
+
+ } else if (control >= 0xA0) {
+ lzma.reset();
+ }
+
+ rc.prepareInputBuffer(in, compressedSize);
+
+ } else if (control > 0x02) {
+ throw new CorruptedInputException();
+
+ } else {
+ isLZMAChunk = false;
+ uncompressedSize = in.readUnsignedShort() + 1;
+ }
+ }
+
+ private void decodeProps() throws IOException {
+ int props = in.readUnsignedByte();
+
+ if (props > (4 * 5 + 4) * 9 + 8)
+ throw new CorruptedInputException();
+
+ int pb = props / (9 * 5);
+ props -= pb * 9 * 5;
+ int lp = props / 9;
+ int lc = props - lp * 9;
+
+ if (lc + lp > 4)
+ throw new CorruptedInputException();
+
+ lzma = new LZMADecoder(lz, rc, lc, lp, pb);
+ }
+
+ /**
+ * Returns the number of uncompressed bytes that can be read
+ * without blocking. The value is returned with an assumption
+ * that the compressed input data will be valid. If the compressed
+ * data is corrupt, <code>CorruptedInputException</code> may get
+ * thrown before the number of bytes claimed to be available have
+ * been read from this input stream.
+ * <p>
+ * In LZMA2InputStream, the return value will be non-zero when the
+ * decompressor is in the middle of an LZMA2 chunk. The return value
+ * will then be the number of uncompressed bytes remaining from that
+ * chunk.
+ *
+ * @return the number of uncompressed bytes that can be read
+ * without blocking
+ */
+ public int available() throws IOException {
+ if (in == null)
+ throw new XZIOException("Stream closed");
+
+ if (exception != null)
+ throw exception;
+
+ return uncompressedSize;
+ }
+
+ /**
+ * Closes the stream and calls <code>in.close()</code>.
+ * If the stream was already closed, this does nothing.
+ *
+ * @throws IOException if thrown by <code>in.close()</code>
+ */
+ public void close() throws IOException {
+ if (in != null) {
+ try {
+ in.close();
+ } finally {
+ in = null;
+ }
+ }
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/LZMA2Options.java b/lzma/Java/Tukaani/src/org/tukaani/xz/LZMA2Options.java
new file mode 100644
index 0000000..42777f0
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/LZMA2Options.java
@@ -0,0 +1,581 @@
+/*
+ * LZMA2Options
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz;
+
+import java.io.InputStream;
+import java.io.IOException;
+import org.tukaani.xz.lz.LZEncoder;
+import org.tukaani.xz.lzma.LZMAEncoder;
+
+/**
+ * LZMA2 compression options.
+ * <p>
+ * While this allows setting the LZMA2 compression options in detail,
+ * often you only need <code>LZMA2Options()</code> or
+ * <code>LZMA2Options(int)</code>.
+ */
+public class LZMA2Options extends FilterOptions {
+ /**
+ * Minimum valid compression preset level is 0.
+ */
+ public static final int PRESET_MIN = 0;
+
+ /**
+ * Maximum valid compression preset level is 9.
+ */
+ public static final int PRESET_MAX = 9;
+
+ /**
+ * Default compression preset level is 6.
+ */
+ public static final int PRESET_DEFAULT = 6;
+
+ /**
+ * Minimum dictionary size is 4 KiB.
+ */
+ public static final int DICT_SIZE_MIN = 4096;
+
+ /**
+ * Maximum dictionary size for compression is 768 MiB.
+ * <p>
+ * The decompressor supports bigger dictionaries, up to almost 2 GiB.
+ * With HC4 the encoder would support dictionaries bigger than 768 MiB.
+ * The 768 MiB limit comes from the current implementation of BT4 where
+ * we would otherwise hit the limits of signed ints in array indexing.
+ * <p>
+ * If you really need bigger dictionary for decompression,
+ * use {@link LZMA2InputStream} directly.
+ */
+ public static final int DICT_SIZE_MAX = 768 << 20;
+
+ /**
+ * The default dictionary size is 8 MiB.
+ */
+ public static final int DICT_SIZE_DEFAULT = 8 << 20;
+
+ /**
+ * Maximum value for lc + lp is 4.
+ */
+ public static final int LC_LP_MAX = 4;
+
+ /**
+ * The default number of literal context bits is 3.
+ */
+ public static final int LC_DEFAULT = 3;
+
+ /**
+ * The default number of literal position bits is 0.
+ */
+ public static final int LP_DEFAULT = 0;
+
+ /**
+ * Maximum value for pb is 4.
+ */
+ public static final int PB_MAX = 4;
+
+ /**
+ * The default number of position bits is 2.
+ */
+ public static final int PB_DEFAULT = 2;
+
+ /**
+ * Compression mode: uncompressed.
+ * The data is wrapped into a LZMA2 stream without compression.
+ */
+ public static final int MODE_UNCOMPRESSED = 0;
+
+ /**
+ * Compression mode: fast.
+ * This is usually combined with a hash chain match finder.
+ */
+ public static final int MODE_FAST = LZMAEncoder.MODE_FAST;
+
+ /**
+ * Compression mode: normal.
+ * This is usually combined with a binary tree match finder.
+ */
+ public static final int MODE_NORMAL = LZMAEncoder.MODE_NORMAL;
+
+ /**
+ * Minimum value for <code>niceLen</code> is 8.
+ */
+ public static final int NICE_LEN_MIN = 8;
+
+ /**
+ * Maximum value for <code>niceLen</code> is 273.
+ */
+ public static final int NICE_LEN_MAX = 273;
+
+ /**
+ * Match finder: Hash Chain 2-3-4
+ */
+ public static final int MF_HC4 = LZEncoder.MF_HC4;
+
+ /**
+ * Match finder: Binary tree 2-3-4
+ */
+ public static final int MF_BT4 = LZEncoder.MF_BT4;
+
+ private static final int[] presetToDictSize = {
+ 1 << 18, 1 << 20, 1 << 21, 1 << 22, 1 << 22,
+ 1 << 23, 1 << 23, 1 << 24, 1 << 25, 1 << 26 };
+
+ private static final int[] presetToDepthLimit = { 4, 8, 24, 48 };
+
+ private int dictSize;
+ private byte[] presetDict = null;
+ private int lc;
+ private int lp;
+ private int pb;
+ private int mode;
+ private int niceLen;
+ private int mf;
+ private int depthLimit;
+
+ /**
+ * Creates new LZMA2 options and sets them to the default values.
+ * This is equivalent to <code>LZMA2Options(PRESET_DEFAULT)</code>.
+ */
+ public LZMA2Options() {
+ try {
+ setPreset(PRESET_DEFAULT);
+ } catch (UnsupportedOptionsException e) {
+ assert false;
+ throw new RuntimeException();
+ }
+ }
+
+ /**
+ * Creates new LZMA2 options and sets them to the given preset.
+ *
+ * @throws UnsupportedOptionsException
+ * <code>preset</code> is not supported
+ */
+ public LZMA2Options(int preset) throws UnsupportedOptionsException {
+ setPreset(preset);
+ }
+
+ /**
+ * Creates new LZMA2 options and sets them to the given custom values.
+ *
+ * @throws UnsupportedOptionsException
+ * unsupported options were specified
+ */
+ public LZMA2Options(int dictSize, int lc, int lp, int pb, int mode,
+ int niceLen, int mf, int depthLimit)
+ throws UnsupportedOptionsException {
+ setDictSize(dictSize);
+ setLcLp(lc, lp);
+ setPb(pb);
+ setMode(mode);
+ setNiceLen(niceLen);
+ setMatchFinder(mf);
+ setDepthLimit(depthLimit);
+ }
+
+ /**
+ * Sets the compression options to the given preset.
+ * <p>
+ * The presets 0-3 are fast presets with medium compression.
+ * The presets 4-6 are fairly slow presets with high compression.
+ * The default preset (<code>PRESET_DEFAULT</code>) is 6.
+ * <p>
+ * The presets 7-9 are like the preset 6 but use bigger dictionaries
+ * and have higher compressor and decompressor memory requirements.
+ * Unless the uncompressed size of the file exceeds 8 MiB,
+ * 16 MiB, or 32 MiB, it is waste of memory to use the
+ * presets 7, 8, or 9, respectively.
+ *
+ * @throws UnsupportedOptionsException
+ * <code>preset</code> is not supported
+ */
+ public void setPreset(int preset) throws UnsupportedOptionsException {
+ if (preset < 0 || preset > 9)
+ throw new UnsupportedOptionsException(
+ "Unsupported preset: " + preset);
+
+ lc = LC_DEFAULT;
+ lp = LP_DEFAULT;
+ pb = PB_DEFAULT;
+ dictSize = presetToDictSize[preset];
+
+ if (preset <= 3) {
+ mode = MODE_FAST;
+ mf = MF_HC4;
+ niceLen = preset <= 1 ? 128 : NICE_LEN_MAX;
+ depthLimit = presetToDepthLimit[preset];
+ } else {
+ mode = MODE_NORMAL;
+ mf = MF_BT4;
+ niceLen = (preset == 4) ? 16 : (preset == 5) ? 32 : 64;
+ depthLimit = 0;
+ }
+ }
+
+ /**
+ * Sets the dictionary size in bytes.
+ * <p>
+ * The dictionary (or history buffer) holds the most recently seen
+ * uncompressed data. Bigger dictionary usually means better compression.
+ * However, using a dictioanary bigger than the size of the uncompressed
+ * data is waste of memory.
+ * <p>
+ * Any value in the range [DICT_SIZE_MIN, DICT_SIZE_MAX] is valid,
+ * but sizes of 2^n and 2^n + 2^(n-1) bytes are somewhat
+ * recommended.
+ *
+ * @throws UnsupportedOptionsException
+ * <code>dictSize</code> is not supported
+ */
+ public void setDictSize(int dictSize) throws UnsupportedOptionsException {
+ if (dictSize < DICT_SIZE_MIN)
+ throw new UnsupportedOptionsException(
+ "LZMA2 dictionary size must be at least 4 KiB: "
+ + dictSize + " B");
+
+ if (dictSize > DICT_SIZE_MAX)
+ throw new UnsupportedOptionsException(
+ "LZMA2 dictionary size must not exceed "
+ + (DICT_SIZE_MAX >> 20) + " MiB: " + dictSize + " B");
+
+ this.dictSize = dictSize;
+ }
+
+ /**
+ * Gets the dictionary size in bytes.
+ */
+ public int getDictSize() {
+ return dictSize;
+ }
+
+ /**
+ * Sets a preset dictionary. Use null to disable the use of
+ * a preset dictionary. By default there is no preset dictionary.
+ * <p>
+ * <b>The .xz format doesn't support a preset dictionary for now.
+ * Do not set a preset dictionary unless you use raw LZMA2.</b>
+ * <p>
+ * Preset dictionary can be useful when compressing many similar,
+ * relatively small chunks of data independently from each other.
+ * A preset dictionary should contain typical strings that occur in
+ * the files being compressed. The most probable strings should be
+ * near the end of the preset dictionary. The preset dictionary used
+ * for compression is also needed for decompression.
+ */
+ public void setPresetDict(byte[] presetDict) {
+ this.presetDict = presetDict;
+ }
+
+ /**
+ * Gets the preset dictionary.
+ */
+ public byte[] getPresetDict() {
+ return presetDict;
+ }
+
+ /**
+ * Sets the number of literal context bits and literal position bits.
+ * <p>
+ * The sum of <code>lc</code> and <code>lp</code> is limited to 4.
+ * Trying to exceed it will throw an exception. This function lets
+ * you change both at the same time.
+ *
+ * @throws UnsupportedOptionsException
+ * <code>lc</code> and <code>lp</code>
+ * are invalid
+ */
+ public void setLcLp(int lc, int lp) throws UnsupportedOptionsException {
+ if (lc < 0 || lp < 0 || lc > LC_LP_MAX || lp > LC_LP_MAX
+ || lc + lp > LC_LP_MAX)
+ throw new UnsupportedOptionsException(
+ "lc + lp must not exceed " + LC_LP_MAX + ": "
+ + lc + " + " + lp);
+
+ this.lc = lc;
+ this.lp = lp;
+ }
+
+ /**
+ * Sets the number of literal context bits.
+ * <p>
+ * All bytes that cannot be encoded as matches are encoded as literals.
+ * That is, literals are simply 8-bit bytes that are encoded one at
+ * a time.
+ * <p>
+ * The literal coding makes an assumption that the highest <code>lc</code>
+ * bits of the previous uncompressed byte correlate with the next byte.
+ * For example, in typical English text, an upper-case letter is often
+ * followed by a lower-case letter, and a lower-case letter is usually
+ * followed by another lower-case letter. In the US-ASCII character set,
+ * the highest three bits are 010 for upper-case letters and 011 for
+ * lower-case letters. When <code>lc</code> is at least 3, the literal
+ * coding can take advantage of this property in the uncompressed data.
+ * <p>
+ * The default value (3) is usually good. If you want maximum compression,
+ * try <code>setLc(4)</code>. Sometimes it helps a little, and sometimes it
+ * makes compression worse. If it makes it worse, test for example
+ * <code>setLc(2)</code> too.
+ *
+ * @throws UnsupportedOptionsException
+ * <code>lc</code> is invalid, or the sum
+ * of <code>lc</code> and <code>lp</code>
+ * exceed LC_LP_MAX
+ */
+ public void setLc(int lc) throws UnsupportedOptionsException {
+ setLcLp(lc, lp);
+ }
+
+ /**
+ * Sets the number of literal position bits.
+ * <p>
+ * This affets what kind of alignment in the uncompressed data is
+ * assumed when encoding literals. See {@link #setPb(int) setPb} for
+ * more information about alignment.
+ *
+ * @throws UnsupportedOptionsException
+ * <code>lp</code> is invalid, or the sum
+ * of <code>lc</code> and <code>lp</code>
+ * exceed LC_LP_MAX
+ */
+ public void setLp(int lp) throws UnsupportedOptionsException {
+ setLcLp(lc, lp);
+ }
+
+ /**
+ * Gets the number of literal context bits.
+ */
+ public int getLc() {
+ return lc;
+ }
+
+ /**
+ * Gets the number of literal position bits.
+ */
+ public int getLp() {
+ return lp;
+ }
+
+ /**
+ * Sets the number of position bits.
+ * <p>
+ * This affects what kind of alignment in the uncompressed data is
+ * assumed in general. The default (2) means four-byte alignment
+ * (2^<code>pb</code> = 2^2 = 4), which is often a good choice when
+ * there's no better guess.
+ * <p>
+ * When the alignment is known, setting the number of position bits
+ * accordingly may reduce the file size a little. For example with text
+ * files having one-byte alignment (US-ASCII, ISO-8859-*, UTF-8), using
+ * <code>setPb(0)</code> can improve compression slightly. For UTF-16
+ * text, <code>setPb(1)</code> is a good choice. If the alignment is
+ * an odd number like 3 bytes, <code>setPb(0)</code> might be the best
+ * choice.
+ * <p>
+ * Even though the assumed alignment can be adjusted with
+ * <code>setPb</code> and <code>setLp</code>, LZMA2 still slightly favors
+ * 16-byte alignment. It might be worth taking into account when designing
+ * file formats that are likely to be often compressed with LZMA2.
+ *
+ * @throws UnsupportedOptionsException
+ * <code>pb</code> is invalid
+ */
+ public void setPb(int pb) throws UnsupportedOptionsException {
+ if (pb < 0 || pb > PB_MAX)
+ throw new UnsupportedOptionsException(
+ "pb must not exceed " + PB_MAX + ": " + pb);
+
+ this.pb = pb;
+ }
+
+ /**
+ * Gets the number of position bits.
+ */
+ public int getPb() {
+ return pb;
+ }
+
+ /**
+ * Sets the compression mode.
+ * <p>
+ * This specifies the method to analyze the data produced by
+ * a match finder. The default is <code>MODE_FAST</code> for presets
+ * 0-3 and <code>MODE_NORMAL</code> for presets 4-9.
+ * <p>
+ * Usually <code>MODE_FAST</code> is used with Hash Chain match finders
+ * and <code>MODE_NORMAL</code> with Binary Tree match finders. This is
+ * also what the presets do.
+ * <p>
+ * The special mode <code>MODE_UNCOMPRESSED</code> doesn't try to
+ * compress the data at all (and doesn't use a match finder) and will
+ * simply wrap it in uncompressed LZMA2 chunks.
+ *
+ * @throws UnsupportedOptionsException
+ * <code>mode</code> is not supported
+ */
+ public void setMode(int mode) throws UnsupportedOptionsException {
+ if (mode < MODE_UNCOMPRESSED || mode > MODE_NORMAL)
+ throw new UnsupportedOptionsException(
+ "Unsupported compression mode: " + mode);
+
+ this.mode = mode;
+ }
+
+ /**
+ * Gets the compression mode.
+ */
+ public int getMode() {
+ return mode;
+ }
+
+ /**
+ * Sets the nice length of matches.
+ * Once a match of at least <code>niceLen</code> bytes is found,
+ * the algorithm stops looking for better matches. Higher values tend
+ * to give better compression at the expense of speed. The default
+ * depends on the preset.
+ *
+ * @throws UnsupportedOptionsException
+ * <code>niceLen</code> is invalid
+ */
+ public void setNiceLen(int niceLen) throws UnsupportedOptionsException {
+ if (niceLen < NICE_LEN_MIN)
+ throw new UnsupportedOptionsException(
+ "Minimum nice length of matches is "
+ + NICE_LEN_MIN + " bytes: " + niceLen);
+
+ if (niceLen > NICE_LEN_MAX)
+ throw new UnsupportedOptionsException(
+ "Maximum nice length of matches is " + NICE_LEN_MAX
+ + ": " + niceLen);
+
+ this.niceLen = niceLen;
+ }
+
+ /**
+ * Gets the nice length of matches.
+ */
+ public int getNiceLen() {
+ return niceLen;
+ }
+
+ /**
+ * Sets the match finder type.
+ * <p>
+ * Match finder has a major effect on compression speed, memory usage,
+ * and compression ratio. Usually Hash Chain match finders are faster
+ * than Binary Tree match finders. The default depends on the preset:
+ * 0-3 use <code>MF_HC4</code> and 4-9 use <code>MF_BT4</code>.
+ *
+ * @throws UnsupportedOptionsException
+ * <code>mf</code> is not supported
+ */
+ public void setMatchFinder(int mf) throws UnsupportedOptionsException {
+ if (mf != MF_HC4 && mf != MF_BT4)
+ throw new UnsupportedOptionsException(
+ "Unsupported match finder: " + mf);
+
+ this.mf = mf;
+ }
+
+ /**
+ * Gets the match finder type.
+ */
+ public int getMatchFinder() {
+ return mf;
+ }
+
+ /**
+ * Sets the match finder search depth limit.
+ * <p>
+ * The default is a special value of <code>0</code> which indicates that
+ * the depth limit should be automatically calculated by the selected
+ * match finder from the nice length of matches.
+ * <p>
+ * Reasonable depth limit for Hash Chain match finders is 4-100 and
+ * 16-1000 for Binary Tree match finders. Using very high values can
+ * make the compressor extremely slow with some files. Avoid settings
+ * higher than 1000 unless you are prepared to interrupt the compression
+ * in case it is taking far too long.
+ *
+ * @throws UnsupportedOptionsException
+ * <code>depthLimit</code> is invalid
+ */
+ public void setDepthLimit(int depthLimit)
+ throws UnsupportedOptionsException {
+ if (depthLimit < 0)
+ throw new UnsupportedOptionsException(
+ "Depth limit cannot be negative: " + depthLimit);
+
+ this.depthLimit = depthLimit;
+ }
+
+ /**
+ * Gets the match finder search depth limit.
+ */
+ public int getDepthLimit() {
+ return depthLimit;
+ }
+
+ public int getEncoderMemoryUsage() {
+ return (mode == MODE_UNCOMPRESSED)
+ ? UncompressedLZMA2OutputStream.getMemoryUsage()
+ : LZMA2OutputStream.getMemoryUsage(this);
+ }
+
+ public FinishableOutputStream getOutputStream(FinishableOutputStream out) {
+ if (mode == MODE_UNCOMPRESSED)
+ return new UncompressedLZMA2OutputStream(out);
+
+ return new LZMA2OutputStream(out, this);
+ }
+
+ /**
+ * Gets how much memory the LZMA2 decoder will need to decompress the data
+ * that was encoded with these options and stored in a .xz file.
+ * <p>
+ * The returned value may bigger than the value returned by a direct call
+ * to {@link LZMA2InputStream#getMemoryUsage(int)} if the dictionary size
+ * is not 2^n or 2^n + 2^(n-1) bytes. This is because the .xz
+ * headers store the dictionary size in such a format and other values
+ * are rounded up to the next such value. Such rounding is harmess except
+ * it might waste some memory if an unsual dictionary size is used.
+ * <p>
+ * If you use raw LZMA2 streams and unusual dictioanary size, call
+ * {@link LZMA2InputStream#getMemoryUsage} directly to get raw decoder
+ * memory requirements.
+ */
+ public int getDecoderMemoryUsage() {
+ // Round the dictionary size up to the next 2^n or 2^n + 2^(n-1).
+ int d = dictSize - 1;
+ d |= d >>> 2;
+ d |= d >>> 3;
+ d |= d >>> 4;
+ d |= d >>> 8;
+ d |= d >>> 16;
+ return LZMA2InputStream.getMemoryUsage(d + 1);
+ }
+
+ public InputStream getInputStream(InputStream in) throws IOException {
+ return new LZMA2InputStream(in, dictSize);
+ }
+
+ FilterEncoder getFilterEncoder() {
+ return new LZMA2Encoder(this);
+ }
+
+ public Object clone() {
+ try {
+ return super.clone();
+ } catch (CloneNotSupportedException e) {
+ assert false;
+ throw new RuntimeException();
+ }
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/LZMA2OutputStream.java b/lzma/Java/Tukaani/src/org/tukaani/xz/LZMA2OutputStream.java
new file mode 100644
index 0000000..5724d10
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/LZMA2OutputStream.java
@@ -0,0 +1,261 @@
+/*
+ * LZMA2OutputStream
+ *
+ * Authors: Lasse Collin <lasse.collin@tukaani.org>
+ * Igor Pavlov <http://7-zip.org/>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+import org.tukaani.xz.lz.LZEncoder;
+import org.tukaani.xz.rangecoder.RangeEncoder;
+import org.tukaani.xz.lzma.LZMAEncoder;
+
+class LZMA2OutputStream extends FinishableOutputStream {
+ static final int COMPRESSED_SIZE_MAX = 64 << 10;
+
+ private FinishableOutputStream out;
+ private final DataOutputStream outData;
+
+ private final LZEncoder lz;
+ private final RangeEncoder rc;
+ private final LZMAEncoder lzma;
+
+ private final int props; // Cannot change props on the fly for now.
+ private boolean dictResetNeeded = true;
+ private boolean stateResetNeeded = true;
+ private boolean propsNeeded = true;
+
+ private int pendingSize = 0;
+ private boolean finished = false;
+ private IOException exception = null;
+
+ private final byte[] tempBuf = new byte[1];
+
+ private static int getExtraSizeBefore(int dictSize) {
+ return COMPRESSED_SIZE_MAX > dictSize
+ ? COMPRESSED_SIZE_MAX - dictSize : 0;
+ }
+
+ static int getMemoryUsage(LZMA2Options options) {
+ // 64 KiB buffer for the range encoder + a little extra + LZMAEncoder
+ int dictSize = options.getDictSize();
+ int extraSizeBefore = getExtraSizeBefore(dictSize);
+ return 70 + LZMAEncoder.getMemoryUsage(options.getMode(),
+ dictSize, extraSizeBefore,
+ options.getMatchFinder());
+ }
+
+ LZMA2OutputStream(FinishableOutputStream out, LZMA2Options options) {
+ if (out == null)
+ throw new NullPointerException();
+
+ this.out = out;
+ outData = new DataOutputStream(out);
+ rc = new RangeEncoder(COMPRESSED_SIZE_MAX);
+
+ int dictSize = options.getDictSize();
+ int extraSizeBefore = getExtraSizeBefore(dictSize);
+ lzma = LZMAEncoder.getInstance(rc,
+ options.getLc(), options.getLp(), options.getPb(),
+ options.getMode(),
+ dictSize, extraSizeBefore, options.getNiceLen(),
+ options.getMatchFinder(), options.getDepthLimit());
+
+ lz = lzma.getLZEncoder();
+
+ byte[] presetDict = options.getPresetDict();
+ if (presetDict != null && presetDict.length > 0) {
+ lz.setPresetDict(dictSize, presetDict);
+ dictResetNeeded = false;
+ }
+
+ props = (options.getPb() * 5 + options.getLp()) * 9 + options.getLc();
+ }
+
+ public void write(int b) throws IOException {
+ tempBuf[0] = (byte)b;
+ write(tempBuf, 0, 1);
+ }
+
+ public void write(byte[] buf, int off, int len) throws IOException {
+ if (off < 0 || len < 0 || off + len < 0 || off + len > buf.length)
+ throw new IndexOutOfBoundsException();
+
+ if (exception != null)
+ throw exception;
+
+ if (finished)
+ throw new XZIOException("Stream finished or closed");
+
+ try {
+ while (len > 0) {
+ int used = lz.fillWindow(buf, off, len);
+ off += used;
+ len -= used;
+ pendingSize += used;
+
+ if (lzma.encodeForLZMA2())
+ writeChunk();
+ }
+ } catch (IOException e) {
+ exception = e;
+ throw e;
+ }
+ }
+
+ private void writeChunk() throws IOException {
+ int compressedSize = rc.finish();
+ int uncompressedSize = lzma.getUncompressedSize();
+
+ assert compressedSize > 0 : compressedSize;
+ assert uncompressedSize > 0 : uncompressedSize;
+
+ // +2 because the header of a compressed chunk is 2 bytes
+ // bigger than the header of an uncompressed chunk.
+ if (compressedSize + 2 < uncompressedSize) {
+ writeLZMA(uncompressedSize, compressedSize);
+ } else {
+ lzma.reset();
+ uncompressedSize = lzma.getUncompressedSize();
+ assert uncompressedSize > 0 : uncompressedSize;
+ writeUncompressed(uncompressedSize);
+ }
+
+ pendingSize -= uncompressedSize;
+ lzma.resetUncompressedSize();
+ rc.reset();
+ }
+
+ private void writeLZMA(int uncompressedSize, int compressedSize)
+ throws IOException {
+ int control;
+
+ if (propsNeeded) {
+ if (dictResetNeeded)
+ control = 0x80 + (3 << 5);
+ else
+ control = 0x80 + (2 << 5);
+ } else {
+ if (stateResetNeeded)
+ control = 0x80 + (1 << 5);
+ else
+ control = 0x80;
+ }
+
+ control |= (uncompressedSize - 1) >>> 16;
+ outData.writeByte(control);
+
+ outData.writeShort(uncompressedSize - 1);
+ outData.writeShort(compressedSize - 1);
+
+ if (propsNeeded)
+ outData.writeByte(props);
+
+ rc.write(out);
+
+ propsNeeded = false;
+ stateResetNeeded = false;
+ dictResetNeeded = false;
+ }
+
+ private void writeUncompressed(int uncompressedSize) throws IOException {
+ while (uncompressedSize > 0) {
+ int chunkSize = Math.min(uncompressedSize, COMPRESSED_SIZE_MAX);
+ outData.writeByte(dictResetNeeded ? 0x01 : 0x02);
+ outData.writeShort(chunkSize - 1);
+ lz.copyUncompressed(out, uncompressedSize, chunkSize);
+ uncompressedSize -= chunkSize;
+ dictResetNeeded = false;
+ }
+
+ stateResetNeeded = true;
+ }
+
+ private void writeEndMarker() throws IOException {
+ assert !finished;
+
+ if (exception != null)
+ throw exception;
+
+ lz.setFinishing();
+
+ try {
+ while (pendingSize > 0) {
+ lzma.encodeForLZMA2();
+ writeChunk();
+ }
+
+ out.write(0x00);
+ } catch (IOException e) {
+ exception = e;
+ throw e;
+ }
+
+ finished = true;
+ }
+
+ public void flush() throws IOException {
+ if (exception != null)
+ throw exception;
+
+ if (finished)
+ throw new XZIOException("Stream finished or closed");
+
+ try {
+ lz.setFlushing();
+
+ while (pendingSize > 0) {
+ lzma.encodeForLZMA2();
+ writeChunk();
+ }
+
+ out.flush();
+ } catch (IOException e) {
+ exception = e;
+ throw e;
+ }
+ }
+
+ public void finish() throws IOException {
+ if (!finished) {
+ writeEndMarker();
+
+ try {
+ out.finish();
+ } catch (IOException e) {
+ exception = e;
+ throw e;
+ }
+
+ finished = true;
+ }
+ }
+
+ public void close() throws IOException {
+ if (out != null) {
+ if (!finished) {
+ try {
+ writeEndMarker();
+ } catch (IOException e) {}
+ }
+
+ try {
+ out.close();
+ } catch (IOException e) {
+ if (exception == null)
+ exception = e;
+ }
+
+ out = null;
+ }
+
+ if (exception != null)
+ throw exception;
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/LZMAInputStream.java b/lzma/Java/Tukaani/src/org/tukaani/xz/LZMAInputStream.java
new file mode 100644
index 0000000..9bbd261
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/LZMAInputStream.java
@@ -0,0 +1,569 @@
+/*
+ * LZMAInputStream
+ *
+ * Authors: Lasse Collin <lasse.collin@tukaani.org>
+ * Igor Pavlov <http://7-zip.org/>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz;
+
+import java.io.InputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+import org.tukaani.xz.lz.LZDecoder;
+import org.tukaani.xz.rangecoder.RangeDecoderFromStream;
+import org.tukaani.xz.lzma.LZMADecoder;
+
+/**
+ * Decompresses legacy .lzma files and raw LZMA streams (no .lzma header).
+ * <p>
+ * <b>IMPORTANT:</b> In contrast to other classes in this package, this class
+ * reads data from its input stream one byte at a time. If the input stream
+ * is for example {@link java.io.FileInputStream}, wrapping it into
+ * {@link java.io.BufferedInputStream} tends to improve performance a lot.
+ * This is not automatically done by this class because there may be use
+ * cases where it is desired that this class won't read any bytes past
+ * the end of the LZMA stream.
+ * <p>
+ * Even when using <code>BufferedInputStream</code>, the performance tends
+ * to be worse (maybe 10-20 % slower) than with {@link LZMA2InputStream}
+ * or {@link XZInputStream} (when the .xz file contains LZMA2-compressed data).
+ *
+ * @since 1.4
+ */
+public class LZMAInputStream extends InputStream {
+ /**
+ * Largest dictionary size supported by this implementation.
+ * <p>
+ * LZMA allows dictionaries up to one byte less than 4 GiB. This
+ * implementation supports only 16 bytes less than 2 GiB. This
+ * limitation is due to Java using signed 32-bit integers for array
+ * indexing. The limitation shouldn't matter much in practice since so
+ * huge dictionaries are not normally used.
+ */
+ public static final int DICT_SIZE_MAX = Integer.MAX_VALUE & ~15;
+
+ private InputStream in;
+ private LZDecoder lz;
+ private RangeDecoderFromStream rc;
+ private LZMADecoder lzma;
+
+ private boolean endReached = false;
+
+ private final byte[] tempBuf = new byte[1];
+
+ /**
+ * Number of uncompressed bytes left to be decompressed, or -1 if
+ * the end marker is used.
+ */
+ private long remainingSize;
+
+ private IOException exception = null;
+
+ /**
+ * Gets approximate decompressor memory requirements as kibibytes for
+ * the given dictionary size and LZMA properties byte (lc, lp, and pb).
+ *
+ * @param dictSize LZMA dictionary size as bytes, should be
+ * in the range [<code>0</code>,
+ * <code>DICT_SIZE_MAX</code>]
+ *
+ * @param propsByte LZMA properties byte that encodes the values
+ * of lc, lp, and pb
+ *
+ * @return approximate memory requirements as kibibytes (KiB)
+ *
+ * @throws UnsupportedOptionsException
+ * if <code>dictSize</code> is outside
+ * the range [<code>0</code>,
+ * <code>DICT_SIZE_MAX</code>]
+ *
+ * @throws CorruptedInputException
+ * if <code>propsByte</code> is invalid
+ */
+ public static int getMemoryUsage(int dictSize, byte propsByte)
+ throws UnsupportedOptionsException, CorruptedInputException {
+ if (dictSize < 0 || dictSize > DICT_SIZE_MAX)
+ throw new UnsupportedOptionsException(
+ "LZMA dictionary is too big for this implementation");
+
+ int props = propsByte & 0xFF;
+ if (props > (4 * 5 + 4) * 9 + 8)
+ throw new CorruptedInputException("Invalid LZMA properties byte");
+
+ props %= 9 * 5;
+ int lp = props / 9;
+ int lc = props - lp * 9;
+
+ return getMemoryUsage(dictSize, lc, lp);
+ }
+
+ /**
+ * Gets approximate decompressor memory requirements as kibibytes for
+ * the given dictionary size, lc, and lp. Note that pb isn't needed.
+ *
+ * @param dictSize LZMA dictionary size as bytes, must be
+ * in the range [<code>0</code>,
+ * <code>DICT_SIZE_MAX</code>]
+ *
+ * @param lc number of literal context bits, must be
+ * in the range [0, 8]
+ *
+ * @param lp number of literal position bits, must be
+ * in the range [0, 4]
+ *
+ * @return approximate memory requirements as kibibytes (KiB)
+ */
+ public static int getMemoryUsage(int dictSize, int lc, int lp) {
+ if (lc < 0 || lc > 8 || lp < 0 || lp > 4)
+ throw new IllegalArgumentException("Invalid lc or lp");
+
+ // Probability variables have the type "short". There are
+ // 0x300 (768) probability variables in each literal subcoder.
+ // The number of literal subcoders is 2^(lc + lp).
+ //
+ // Roughly 10 KiB for the base state + LZ decoder's dictionary buffer
+ // + sizeof(short) * number probability variables per literal subcoder
+ // * number of literal subcoders
+ return 10 + getDictSize(dictSize) / 1024
+ + ((2 * 0x300) << (lc + lp)) / 1024;
+ }
+
+ private static int getDictSize(int dictSize) {
+ if (dictSize < 0 || dictSize > DICT_SIZE_MAX)
+ throw new IllegalArgumentException(
+ "LZMA dictionary is too big for this implementation");
+
+ // For performance reasons, use a 4 KiB dictionary if something
+ // smaller was requested. It's a rare situation and the performance
+ // difference isn't huge, and it starts to matter mostly when the
+ // dictionary is just a few bytes. But we need to handle the special
+ // case of dictSize == 0 anyway, which is an allowed value but in
+ // practice means one-byte dictionary.
+ //
+ // Note that using a dictionary bigger than specified in the headers
+ // can hide errors if there is a reference to data beyond the original
+ // dictionary size but is still within 4 KiB.
+ if (dictSize < 4096)
+ dictSize = 4096;
+
+ // Round dictionary size upward to a multiple of 16. This way LZMA
+ // can use LZDecoder.getPos() for calculating LZMA's posMask.
+ return (dictSize + 15) & ~15;
+ }
+
+ /**
+ * Creates a new .lzma file format decompressor without
+ * a memory usage limit.
+ *
+ * @param in input stream from which .lzma data is read;
+ * it might be a good idea to wrap it in
+ * <code>BufferedInputStream</code>, see the
+ * note at the top of this page
+ *
+ * @throws CorruptedInputException
+ * file is corrupt or perhaps not in
+ * the .lzma format at all
+ *
+ * @throws UnsupportedOptionsException
+ * dictionary size or uncompressed size is too
+ * big for this implementation
+ *
+ * @throws EOFException
+ * file is truncated or perhaps not in
+ * the .lzma format at all
+ *
+ * @throws IOException may be thrown by <code>in</code>
+ */
+ public LZMAInputStream(InputStream in) throws IOException {
+ this(in, -1);
+ }
+
+ /**
+ * Creates a new .lzma file format decompressor with an optional
+ * memory usage limit.
+ *
+ * @param in input stream from which .lzma data is read;
+ * it might be a good idea to wrap it in
+ * <code>BufferedInputStream</code>, see the
+ * note at the top of this page
+ *
+ * @param memoryLimit memory usage limit in kibibytes (KiB)
+ * or <code>-1</code> to impose no
+ * memory usage limit
+ *
+ * @throws CorruptedInputException
+ * file is corrupt or perhaps not in
+ * the .lzma format at all
+ *
+ * @throws UnsupportedOptionsException
+ * dictionary size or uncompressed size is too
+ * big for this implementation
+ *
+ * @throws MemoryLimitException
+ * memory usage limit was exceeded
+ *
+ * @throws EOFException
+ * file is truncated or perhaps not in
+ * the .lzma format at all
+ *
+ * @throws IOException may be thrown by <code>in</code>
+ */
+ public LZMAInputStream(InputStream in, int memoryLimit)
+ throws IOException {
+ DataInputStream inData = new DataInputStream(in);
+
+ // Properties byte (lc, lp, and pb)
+ byte propsByte = inData.readByte();
+
+ // Dictionary size is an unsigned 32-bit little endian integer.
+ int dictSize = 0;
+ for (int i = 0; i < 4; ++i)
+ dictSize |= inData.readUnsignedByte() << (8 * i);
+
+ // Uncompressed size is an unsigned 64-bit little endian integer.
+ // The maximum 64-bit value is a special case (becomes -1 here)
+ // which indicates that the end marker is used instead of knowing
+ // the uncompressed size beforehand.
+ long uncompSize = 0;
+ for (int i = 0; i < 8; ++i)
+ uncompSize |= (long)inData.readUnsignedByte() << (8 * i);
+
+ // Check the memory usage limit.
+ int memoryNeeded = getMemoryUsage(dictSize, propsByte);
+ if (memoryLimit != -1 && memoryNeeded > memoryLimit)
+ throw new MemoryLimitException(memoryNeeded, memoryLimit);
+
+ initialize(in, uncompSize, propsByte, dictSize, null);
+ }
+
+ /**
+ * Creates a new input stream that decompresses raw LZMA data (no .lzma
+ * header) from <code>in</code>.
+ * <p>
+ * The caller needs to know if the "end of payload marker (EOPM)" alias
+ * "end of stream marker (EOS marker)" alias "end marker" present.
+ * If the end marker isn't used, the caller must know the exact
+ * uncompressed size of the stream.
+ * <p>
+ * The caller also needs to provide the LZMA properties byte that encodes
+ * the number of literal context bits (lc), literal position bits (lp),
+ * and position bits (pb).
+ * <p>
+ * The dictionary size used when compressing is also needed. Specifying
+ * a too small dictionary size will prevent decompressing the stream.
+ * Specifying a too big dictionary is waste of memory but decompression
+ * will work.
+ * <p>
+ * There is no need to specify a dictionary bigger than
+ * the uncompressed size of the data even if a bigger dictionary
+ * was used when compressing. If you know the uncompressed size
+ * of the data, this might allow saving some memory.
+ *
+ * @param in input stream from which compressed
+ * data is read
+ *
+ * @param uncompSize uncompressed size of the LZMA stream or -1
+ * if the end marker is used in the LZMA stream
+ *
+ * @param propsByte LZMA properties byte that has the encoded
+ * values for literal context bits (lc), literal
+ * position bits (lp), and position bits (pb)
+ *
+ * @param dictSize dictionary size as bytes, must be in the range
+ * [<code>0</code>, <code>DICT_SIZE_MAX</code>]
+ *
+ * @throws CorruptedInputException
+ * if <code>propsByte</code> is invalid or
+ * the first input byte is not 0x00
+ *
+ * @throws UnsupportedOptionsException
+ * dictionary size or uncompressed size is too
+ * big for this implementation
+ *
+ *
+ */
+ public LZMAInputStream(InputStream in, long uncompSize, byte propsByte,
+ int dictSize) throws IOException {
+ initialize(in, uncompSize, propsByte, dictSize, null);
+ }
+
+ /**
+ * Creates a new input stream that decompresses raw LZMA data (no .lzma
+ * header) from <code>in</code> optionally with a preset dictionary.
+ *
+ * @param in input stream from which LZMA-compressed
+ * data is read
+ *
+ * @param uncompSize uncompressed size of the LZMA stream or -1
+ * if the end marker is used in the LZMA stream
+ *
+ * @param propsByte LZMA properties byte that has the encoded
+ * values for literal context bits (lc), literal
+ * position bits (lp), and position bits (pb)
+ *
+ * @param dictSize dictionary size as bytes, must be in the range
+ * [<code>0</code>, <code>DICT_SIZE_MAX</code>]
+ *
+ * @param presetDict preset dictionary or <code>null</code>
+ * to use no preset dictionary
+ *
+ * @throws CorruptedInputException
+ * if <code>propsByte</code> is invalid or
+ * the first input byte is not 0x00
+ *
+ * @throws UnsupportedOptionsException
+ * dictionary size or uncompressed size is too
+ * big for this implementation
+ *
+ * @throws EOFException file is truncated or corrupt
+ *
+ * @throws IOException may be thrown by <code>in</code>
+ */
+ public LZMAInputStream(InputStream in, long uncompSize, byte propsByte,
+ int dictSize, byte[] presetDict)
+ throws IOException {
+ initialize(in, uncompSize, propsByte, dictSize, presetDict);
+ }
+
+ /**
+ * Creates a new input stream that decompresses raw LZMA data (no .lzma
+ * header) from <code>in</code> optionally with a preset dictionary.
+ *
+ * @param in input stream from which LZMA-compressed
+ * data is read
+ *
+ * @param uncompSize uncompressed size of the LZMA stream or -1
+ * if the end marker is used in the LZMA stream
+ *
+ * @param lc number of literal context bits, must be
+ * in the range [0, 8]
+ *
+ * @param lp number of literal position bits, must be
+ * in the range [0, 4]
+ *
+ * @param pb number position bits, must be
+ * in the range [0, 4]
+ *
+ * @param dictSize dictionary size as bytes, must be in the range
+ * [<code>0</code>, <code>DICT_SIZE_MAX</code>]
+ *
+ * @param presetDict preset dictionary or <code>null</code>
+ * to use no preset dictionary
+ *
+ * @throws CorruptedInputException
+ * if the first input byte is not 0x00
+ *
+ * @throws EOFException file is truncated or corrupt
+ *
+ * @throws IOException may be thrown by <code>in</code>
+ */
+ public LZMAInputStream(InputStream in, long uncompSize,
+ int lc, int lp, int pb,
+ int dictSize, byte[] presetDict)
+ throws IOException {
+ initialize(in, uncompSize, lc, lp, pb, dictSize, presetDict);
+ }
+
+ private void initialize(InputStream in, long uncompSize, byte propsByte,
+ int dictSize, byte[] presetDict)
+ throws IOException {
+ // Validate the uncompressed size since the other "initialize" throws
+ // IllegalArgumentException if uncompSize < -1.
+ if (uncompSize < -1)
+ throw new UnsupportedOptionsException(
+ "Uncompressed size is too big");
+
+ // Decode the properties byte. In contrast to LZMA2, there is no
+ // limit of lc + lp <= 4.
+ int props = propsByte & 0xFF;
+ if (props > (4 * 5 + 4) * 9 + 8)
+ throw new CorruptedInputException("Invalid LZMA properties byte");
+
+ int pb = props / (9 * 5);
+ props -= pb * 9 * 5;
+ int lp = props / 9;
+ int lc = props - lp * 9;
+
+ // Validate the dictionary size since the other "initialize" throws
+ // IllegalArgumentException if dictSize is not supported.
+ if (dictSize < 0 || dictSize > DICT_SIZE_MAX)
+ throw new UnsupportedOptionsException(
+ "LZMA dictionary is too big for this implementation");
+
+ initialize(in, uncompSize, lc, lp, pb, dictSize, presetDict);
+ }
+
+ private void initialize(InputStream in, long uncompSize,
+ int lc, int lp, int pb,
+ int dictSize, byte[] presetDict)
+ throws IOException {
+ // getDictSize validates dictSize and gives a message in
+ // the exception too, so skip validating dictSize here.
+ if (uncompSize < -1 || lc < 0 || lc > 8 || lp < 0 || lp > 4
+ || pb < 0 || pb > 4)
+ throw new IllegalArgumentException();
+
+ this.in = in;
+
+ // If uncompressed size is known, use it to avoid wasting memory for
+ // a uselessly large dictionary buffer.
+ dictSize = getDictSize(dictSize);
+ if (uncompSize >= 0 && dictSize > uncompSize)
+ dictSize = getDictSize((int)uncompSize);
+
+ lz = new LZDecoder(getDictSize(dictSize), presetDict);
+ rc = new RangeDecoderFromStream(in);
+ lzma = new LZMADecoder(lz, rc, lc, lp, pb);
+ remainingSize = uncompSize;
+ }
+
+ /**
+ * Decompresses the next byte from this input stream.
+ * <p>
+ * Reading lots of data with <code>read()</code> from this input stream
+ * may be inefficient. Wrap it in <code>java.io.BufferedInputStream</code>
+ * if you need to read lots of data one byte at a time.
+ *
+ * @return the next decompressed byte, or <code>-1</code>
+ * to indicate the end of the compressed stream
+ *
+ * @throws CorruptedInputException
+ *
+ * @throws XZIOException if the stream has been closed
+ *
+ * @throws EOFException
+ * compressed input is truncated or corrupt
+ *
+ * @throws IOException may be thrown by <code>in</code>
+ */
+ public int read() throws IOException {
+ return read(tempBuf, 0, 1) == -1 ? -1 : (tempBuf[0] & 0xFF);
+ }
+
+ /**
+ * Decompresses into an array of bytes.
+ * <p>
+ * If <code>len</code> is zero, no bytes are read and <code>0</code>
+ * is returned. Otherwise this will block until <code>len</code>
+ * bytes have been decompressed, the end of the LZMA stream is reached,
+ * or an exception is thrown.
+ *
+ * @param buf target buffer for uncompressed data
+ * @param off start offset in <code>buf</code>
+ * @param len maximum number of uncompressed bytes to read
+ *
+ * @return number of bytes read, or <code>-1</code> to indicate
+ * the end of the compressed stream
+ *
+ * @throws CorruptedInputException
+ *
+ * @throws XZIOException if the stream has been closed
+ *
+ * @throws EOFException compressed input is truncated or corrupt
+ *
+ * @throws IOException may be thrown by <code>in</code>
+ */
+ public int read(byte[] buf, int off, int len) throws IOException {
+ if (off < 0 || len < 0 || off + len < 0 || off + len > buf.length)
+ throw new IndexOutOfBoundsException();
+
+ if (len == 0)
+ return 0;
+
+ if (in == null)
+ throw new XZIOException("Stream closed");
+
+ if (exception != null)
+ throw exception;
+
+ if (endReached)
+ return -1;
+
+ try {
+ int size = 0;
+
+ while (len > 0) {
+ // If uncompressed size is known and thus no end marker will
+ // be present, set the limit so that the uncompressed size
+ // won't be exceeded.
+ int copySizeMax = len;
+ if (remainingSize >= 0 && remainingSize < len)
+ copySizeMax = (int)remainingSize;
+
+ lz.setLimit(copySizeMax);
+
+ // Decode into the dictionary buffer.
+ try {
+ lzma.decode();
+ } catch (CorruptedInputException e) {
+ // The end marker is encoded with a LZMA symbol that
+ // indicates maximum match distance. This is larger
+ // than any supported dictionary and thus causes
+ // CorruptedInputException from LZDecoder.repeat.
+ if (remainingSize != -1 || !lzma.endMarkerDetected())
+ throw e;
+
+ endReached = true;
+
+ // The exception makes lzma.decode() miss the last range
+ // decoder normalization, so do it here. This might
+ // cause an IOException if it needs to read a byte
+ // from the input stream.
+ rc.normalize();
+ }
+
+ // Copy from the dictionary to buf.
+ int copiedSize = lz.flush(buf, off);
+ off += copiedSize;
+ len -= copiedSize;
+ size += copiedSize;
+
+ if (remainingSize >= 0) {
+ // Update the number of bytes left to be decompressed.
+ remainingSize -= copiedSize;
+ assert remainingSize >= 0;
+
+ if (remainingSize == 0)
+ endReached = true;
+ }
+
+ if (endReached) {
+ // Checking these helps a lot when catching corrupt
+ // or truncated .lzma files. LZMA Utils doesn't do
+ // the first check and thus it accepts many invalid
+ // files that this implementation and XZ Utils don't.
+ if (!rc.isFinished() || lz.hasPending())
+ throw new CorruptedInputException();
+
+ return size == 0 ? -1 : size;
+ }
+ }
+
+ return size;
+
+ } catch (IOException e) {
+ exception = e;
+ throw e;
+ }
+ }
+
+ /**
+ * Closes the stream and calls <code>in.close()</code>.
+ * If the stream was already closed, this does nothing.
+ *
+ * @throws IOException if thrown by <code>in.close()</code>
+ */
+ public void close() throws IOException {
+ if (in != null) {
+ try {
+ in.close();
+ } finally {
+ in = null;
+ }
+ }
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/MemoryLimitException.java b/lzma/Java/Tukaani/src/org/tukaani/xz/MemoryLimitException.java
new file mode 100644
index 0000000..9d766bd
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/MemoryLimitException.java
@@ -0,0 +1,60 @@
+/*
+ * MemoryLimitException
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz;
+
+/**
+ * Thrown when the memory usage limit given to the XZ decompressor
+ * would be exceeded.
+ * <p>
+ * The amount of memory required and the memory usage limit are
+ * included in the error detail message in human readable format.
+ */
+public class MemoryLimitException extends XZIOException {
+ private static final long serialVersionUID = 3L;
+
+ private final int memoryNeeded;
+ private final int memoryLimit;
+
+ /**
+ * Creates a new MemoryLimitException.
+ * <p>
+ * The amount of memory needed and the memory usage limit are
+ * included in the error detail message.
+ *
+ * @param memoryNeeded amount of memory needed as kibibytes (KiB)
+ * @param memoryLimit specified memory usage limit as kibibytes (KiB)
+ */
+ public MemoryLimitException(int memoryNeeded, int memoryLimit) {
+ super("" + memoryNeeded + " KiB of memory would be needed; limit was "
+ + memoryLimit + " KiB");
+
+ this.memoryNeeded = memoryNeeded;
+ this.memoryLimit = memoryLimit;
+ }
+
+ /**
+ * Gets how much memory is required to decompress the data.
+ *
+ * @return amount of memory needed as kibibytes (KiB)
+ */
+ public int getMemoryNeeded() {
+ return memoryNeeded;
+ }
+
+ /**
+ * Gets what the memory usage limit was at the time the exception
+ * was created.
+ *
+ * @return memory usage limit as kibibytes (KiB)
+ */
+ public int getMemoryLimit() {
+ return memoryLimit;
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/PowerPCOptions.java b/lzma/Java/Tukaani/src/org/tukaani/xz/PowerPCOptions.java
new file mode 100644
index 0000000..f36d361
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/PowerPCOptions.java
@@ -0,0 +1,36 @@
+/*
+ * PowerPCOptions
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz;
+
+import java.io.InputStream;
+import org.tukaani.xz.simple.PowerPC;
+
+/**
+ * BCJ filter for big endian PowerPC instructions.
+ */
+public class PowerPCOptions extends BCJOptions {
+ private static final int ALIGNMENT = 4;
+
+ public PowerPCOptions() {
+ super(ALIGNMENT);
+ }
+
+ public FinishableOutputStream getOutputStream(FinishableOutputStream out) {
+ return new SimpleOutputStream(out, new PowerPC(true, startOffset));
+ }
+
+ public InputStream getInputStream(InputStream in) {
+ return new SimpleInputStream(in, new PowerPC(false, startOffset));
+ }
+
+ FilterEncoder getFilterEncoder() {
+ return new BCJEncoder(this, BCJCoder.POWERPC_FILTER_ID);
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/RawCoder.java b/lzma/Java/Tukaani/src/org/tukaani/xz/RawCoder.java
new file mode 100644
index 0000000..12c7da8
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/RawCoder.java
@@ -0,0 +1,33 @@
+/*
+ * RawCoder
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz;
+
+class RawCoder {
+ static void validate(FilterCoder[] filters)
+ throws UnsupportedOptionsException {
+ for (int i = 0; i < filters.length - 1; ++i)
+ if (!filters[i].nonLastOK())
+ throw new UnsupportedOptionsException(
+ "Unsupported XZ filter chain");
+
+ if (!filters[filters.length - 1].lastOK())
+ throw new UnsupportedOptionsException(
+ "Unsupported XZ filter chain");
+
+ int changesSizeCount = 0;
+ for (int i = 0; i < filters.length; ++i)
+ if (filters[i].changesSize())
+ ++changesSizeCount;
+
+ if (changesSizeCount > 3)
+ throw new UnsupportedOptionsException(
+ "Unsupported XZ filter chain");
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/SPARCOptions.java b/lzma/Java/Tukaani/src/org/tukaani/xz/SPARCOptions.java
new file mode 100644
index 0000000..0f20677
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/SPARCOptions.java
@@ -0,0 +1,36 @@
+/*
+ * SPARCOptions
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz;
+
+import java.io.InputStream;
+import org.tukaani.xz.simple.SPARC;
+
+/**
+ * BCJ filter for SPARC.
+ */
+public class SPARCOptions extends BCJOptions {
+ private static final int ALIGNMENT = 4;
+
+ public SPARCOptions() {
+ super(ALIGNMENT);
+ }
+
+ public FinishableOutputStream getOutputStream(FinishableOutputStream out) {
+ return new SimpleOutputStream(out, new SPARC(true, startOffset));
+ }
+
+ public InputStream getInputStream(InputStream in) {
+ return new SimpleInputStream(in, new SPARC(false, startOffset));
+ }
+
+ FilterEncoder getFilterEncoder() {
+ return new BCJEncoder(this, BCJCoder.SPARC_FILTER_ID);
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/SeekableFileInputStream.java b/lzma/Java/Tukaani/src/org/tukaani/xz/SeekableFileInputStream.java
new file mode 100644
index 0000000..fe2d685
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/SeekableFileInputStream.java
@@ -0,0 +1,102 @@
+/*
+ * SeekableFileInputStream
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz;
+
+import java.io.File;
+import java.io.RandomAccessFile;
+import java.io.IOException;
+import java.io.FileNotFoundException;
+
+/**
+ * Wraps a {@link java.io.RandomAccessFile RandomAccessFile}
+ * in a SeekableInputStream.
+ */
+public class SeekableFileInputStream extends SeekableInputStream {
+ /**
+ * The RandomAccessFile that has been wrapped
+ * into a SeekableFileInputStream.
+ */
+ protected RandomAccessFile randomAccessFile;
+
+ /**
+ * Creates a new seekable input stream that reads from the specified file.
+ */
+ public SeekableFileInputStream(File file) throws FileNotFoundException {
+ randomAccessFile = new RandomAccessFile(file, "r");
+ }
+
+ /**
+ * Creates a new seekable input stream that reads from a file with
+ * the specified name.
+ */
+ public SeekableFileInputStream(String name) throws FileNotFoundException {
+ randomAccessFile = new RandomAccessFile(name, "r");
+ }
+
+ /**
+ * Creates a new seekable input stream from an existing
+ * <code>RandomAccessFile</code> object.
+ */
+ public SeekableFileInputStream(RandomAccessFile randomAccessFile) {
+ this.randomAccessFile = randomAccessFile;
+ }
+
+ /**
+ * Calls {@link RandomAccessFile#read() randomAccessFile.read()}.
+ */
+ public int read() throws IOException {
+ return randomAccessFile.read();
+ }
+
+ /**
+ * Calls {@link RandomAccessFile#read(byte[]) randomAccessFile.read(buf)}.
+ */
+ public int read(byte[] buf) throws IOException {
+ return randomAccessFile.read(buf);
+ }
+
+ /**
+ * Calls
+ * {@link RandomAccessFile#read(byte[],int,int)
+ * randomAccessFile.read(buf, off, len)}.
+ */
+ public int read(byte[] buf, int off, int len) throws IOException {
+ return randomAccessFile.read(buf, off, len);
+ }
+
+ /**
+ * Calls {@link RandomAccessFile#close() randomAccessFile.close()}.
+ */
+ public void close() throws IOException {
+ randomAccessFile.close();
+ }
+
+ /**
+ * Calls {@link RandomAccessFile#length() randomAccessFile.length()}.
+ */
+ public long length() throws IOException {
+ return randomAccessFile.length();
+ }
+
+ /**
+ * Calls {@link RandomAccessFile#getFilePointer()
+ randomAccessFile.getFilePointer()}.
+ */
+ public long position() throws IOException {
+ return randomAccessFile.getFilePointer();
+ }
+
+ /**
+ * Calls {@link RandomAccessFile#seek(long) randomAccessFile.seek(long)}.
+ */
+ public void seek(long pos) throws IOException {
+ randomAccessFile.seek(pos);
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/SeekableInputStream.java b/lzma/Java/Tukaani/src/org/tukaani/xz/SeekableInputStream.java
new file mode 100644
index 0000000..a2f908a
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/SeekableInputStream.java
@@ -0,0 +1,81 @@
+/*
+ * SeekableInputStream
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz;
+
+import java.io.InputStream;
+import java.io.IOException;
+
+/**
+ * Input stream with random access support.
+ */
+public abstract class SeekableInputStream extends InputStream {
+ /**
+ * Seeks <code>n</code> bytes forward in this stream.
+ * <p>
+ * This will not seek past the end of the file. If the current position
+ * is already at or past the end of the file, this doesn't seek at all
+ * and returns <code>0</code>. Otherwise, if skipping <code>n</code> bytes
+ * would cause the position to exceed the stream size, this will do
+ * equivalent of <code>seek(length())</code> and the return value will
+ * be adjusted accordingly.
+ * <p>
+ * If <code>n</code> is negative, the position isn't changed and
+ * the return value is <code>0</code>. It doesn't seek backward
+ * because it would conflict with the specification of
+ * {@link java.io.InputStream#skip(long) InputStream.skip}.
+ *
+ * @return <code>0</code> if <code>n</code> is negative,
+ * less than <code>n</code> if skipping <code>n</code>
+ * bytes would seek past the end of the file,
+ * <code>n</code> otherwise
+ *
+ * @throws IOException might be thrown by {@link #seek(long)}
+ */
+ public long skip(long n) throws IOException {
+ if (n <= 0)
+ return 0;
+
+ long size = length();
+ long pos = position();
+ if (pos >= size)
+ return 0;
+
+ if (size - pos < n)
+ n = size - pos;
+
+ seek(pos + n);
+ return n;
+ }
+
+ /**
+ * Gets the size of the stream.
+ */
+ public abstract long length() throws IOException;
+
+ /**
+ * Gets the current position in the stream.
+ */
+ public abstract long position() throws IOException;
+
+ /**
+ * Seeks to the specified absolute position in the stream.
+ * <p>
+ * Seeking past the end of the file should be supported by the subclasses
+ * unless there is a good reason to do otherwise. If one has seeked
+ * past the end of the stream, <code>read</code> will return
+ * <code>-1</code> to indicate end of stream.
+ *
+ * @param pos new read position in the stream
+ *
+ * @throws IOException if <code>pos</code> is negative or if
+ * a stream-specific I/O error occurs
+ */
+ public abstract void seek(long pos) throws IOException;
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/SeekableXZInputStream.java b/lzma/Java/Tukaani/src/org/tukaani/xz/SeekableXZInputStream.java
new file mode 100644
index 0000000..f929d40
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/SeekableXZInputStream.java
@@ -0,0 +1,964 @@
+/*
+ * SeekableXZInputStream
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz;
+
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.EOFException;
+import org.tukaani.xz.common.DecoderUtil;
+import org.tukaani.xz.common.StreamFlags;
+import org.tukaani.xz.check.Check;
+import org.tukaani.xz.index.IndexDecoder;
+import org.tukaani.xz.index.BlockInfo;
+
+/**
+ * Decompresses a .xz file in random access mode.
+ * This supports decompressing concatenated .xz files.
+ * <p>
+ * Each .xz file consist of one or more Streams. Each Stream consist of zero
+ * or more Blocks. Each Stream contains an Index of Streams' Blocks.
+ * The Indexes from all Streams are loaded in RAM by a constructor of this
+ * class. A typical .xz file has only one Stream, and parsing its Index will
+ * need only three or four seeks.
+ * <p>
+ * To make random access possible, the data in a .xz file must be splitted
+ * into multiple Blocks of reasonable size. Decompression can only start at
+ * a Block boundary. When seeking to an uncompressed position that is not at
+ * a Block boundary, decompression starts at the beginning of the Block and
+ * throws away data until the target position is reached. Thus, smaller Blocks
+ * mean faster seeks to arbitrary uncompressed positions. On the other hand,
+ * smaller Blocks mean worse compression. So one has to make a compromise
+ * between random access speed and compression ratio.
+ * <p>
+ * Implementation note: This class uses linear search to locate the correct
+ * Stream from the data structures in RAM. It was the simplest to implement
+ * and should be fine as long as there aren't too many Streams. The correct
+ * Block inside a Stream is located using binary search and thus is fast
+ * even with a huge number of Blocks.
+ *
+ * <h4>Memory usage</h4>
+ * <p>
+ * The amount of memory needed for the Indexes is taken into account when
+ * checking the memory usage limit. Each Stream is calculated to need at
+ * least 1 KiB of memory and each Block 16 bytes of memory, rounded up
+ * to the next kibibyte. So unless the file has a huge number of Streams or
+ * Blocks, these don't take significant amount of memory.
+ *
+ * <h4>Creating random-accessible .xz files</h4>
+ * <p>
+ * When using {@link XZOutputStream}, a new Block can be started by calling
+ * its {@link XZOutputStream#endBlock() endBlock} method. If you know
+ * that the decompressor will only need to seek to certain uncompressed
+ * positions, it can be a good idea to start a new Block at (some of) these
+ * positions (and only at these positions to get better compression ratio).
+ * <p>
+ * liblzma in XZ Utils supports starting a new Block with
+ * <code>LZMA_FULL_FLUSH</code>. XZ Utils 5.1.1alpha added threaded
+ * compression which creates multi-Block .xz files. XZ Utils 5.1.1alpha
+ * also added the option <code>--block-size=SIZE</code> to the xz command
+ * line tool. XZ Utils 5.1.2alpha added a partial implementation of
+ * <code>--block-list=SIZES</code> which allows specifying sizes of
+ * individual Blocks.
+ *
+ * @see SeekableFileInputStream
+ * @see XZInputStream
+ * @see XZOutputStream
+ */
+public class SeekableXZInputStream extends SeekableInputStream {
+ /**
+ * The input stream containing XZ compressed data.
+ */
+ private SeekableInputStream in;
+
+ /**
+ * Memory usage limit after the memory usage of the IndexDecoders have
+ * been substracted.
+ */
+ private final int memoryLimit;
+
+ /**
+ * Memory usage of the IndexDecoders.
+ * <code>memoryLimit + indexMemoryUsage</code> equals the original
+ * memory usage limit that was passed to the constructor.
+ */
+ private int indexMemoryUsage = 0;
+
+ /**
+ * List of IndexDecoders, one for each Stream in the file.
+ * The list is in reverse order: The first element is
+ * the last Stream in the file.
+ */
+ private final ArrayList streams = new ArrayList();
+
+ /**
+ * Bitmask of all Check IDs seen.
+ */
+ private int checkTypes = 0;
+
+ /**
+ * Uncompressed size of the file (all Streams).
+ */
+ private long uncompressedSize = 0;
+
+ /**
+ * Uncompressed size of the largest XZ Block in the file.
+ */
+ private long largestBlockSize = 0;
+
+ /**
+ * Number of XZ Blocks in the file.
+ */
+ private int blockCount = 0;
+
+ /**
+ * Size and position information about the current Block.
+ * If there are no Blocks, all values will be <code>-1</code>.
+ */
+ private final BlockInfo curBlockInfo;
+
+ /**
+ * Temporary (and cached) information about the Block whose information
+ * is queried via <code>getBlockPos</code> and related functions.
+ */
+ private final BlockInfo queriedBlockInfo;
+
+ /**
+ * Integrity Check in the current XZ Stream. The constructor leaves
+ * this to point to the Check of the first Stream.
+ */
+ private Check check;
+
+ /**
+ * Flag indicating if the integrity checks will be verified.
+ */
+ private final boolean verifyCheck;
+
+ /**
+ * Decoder of the current XZ Block, if any.
+ */
+ private BlockInputStream blockDecoder = null;
+
+ /**
+ * Current uncompressed position.
+ */
+ private long curPos = 0;
+
+ /**
+ * Target position for seeking.
+ */
+ private long seekPos;
+
+ /**
+ * True when <code>seek(long)</code> has been called but the actual
+ * seeking hasn't been done yet.
+ */
+ private boolean seekNeeded = false;
+
+ /**
+ * True when end of the file was reached. This can be cleared by
+ * calling <code>seek(long)</code>.
+ */
+ private boolean endReached = false;
+
+ /**
+ * Pending exception from an earlier error.
+ */
+ private IOException exception = null;
+
+ /**
+ * Temporary buffer for read(). This avoids reallocating memory
+ * on every read() call.
+ */
+ private final byte[] tempBuf = new byte[1];
+
+ /**
+ * Creates a new seekable XZ decompressor without a memory usage limit.
+ *
+ * @param in seekable input stream containing one or more
+ * XZ Streams; the whole input stream is used
+ *
+ * @throws XZFormatException
+ * input is not in the XZ format
+ *
+ * @throws CorruptedInputException
+ * XZ data is corrupt or truncated
+ *
+ * @throws UnsupportedOptionsException
+ * XZ headers seem valid but they specify
+ * options not supported by this implementation
+ *
+ * @throws EOFException
+ * less than 6 bytes of input was available
+ * from <code>in</code>, or (unlikely) the size
+ * of the underlying stream got smaller while
+ * this was reading from it
+ *
+ * @throws IOException may be thrown by <code>in</code>
+ */
+ public SeekableXZInputStream(SeekableInputStream in)
+ throws IOException {
+ this(in, -1);
+ }
+
+ /**
+ * Creates a new seekable XZ decomporessor with an optional
+ * memory usage limit.
+ *
+ * @param in seekable input stream containing one or more
+ * XZ Streams; the whole input stream is used
+ *
+ * @param memoryLimit memory usage limit in kibibytes (KiB)
+ * or <code>-1</code> to impose no
+ * memory usage limit
+ *
+ * @throws XZFormatException
+ * input is not in the XZ format
+ *
+ * @throws CorruptedInputException
+ * XZ data is corrupt or truncated
+ *
+ * @throws UnsupportedOptionsException
+ * XZ headers seem valid but they specify
+ * options not supported by this implementation
+ *
+ * @throws MemoryLimitException
+ * decoded XZ Indexes would need more memory
+ * than allowed by the memory usage limit
+ *
+ * @throws EOFException
+ * less than 6 bytes of input was available
+ * from <code>in</code>, or (unlikely) the size
+ * of the underlying stream got smaller while
+ * this was reading from it
+ *
+ * @throws IOException may be thrown by <code>in</code>
+ */
+ public SeekableXZInputStream(SeekableInputStream in, int memoryLimit)
+ throws IOException {
+ this(in, memoryLimit, true);
+ }
+
+ /**
+ * Creates a new seekable XZ decomporessor with an optional
+ * memory usage limit and ability to disable verification
+ * of integrity checks.
+ * <p>
+ * Note that integrity check verification should almost never be disabled.
+ * Possible reasons to disable integrity check verification:
+ * <ul>
+ * <li>Trying to recover data from a corrupt .xz file.</li>
+ * <li>Speeding up decompression. This matters mostly with SHA-256
+ * or with files that have compressed extremely well. It's recommended
+ * that integrity checking isn't disabled for performance reasons
+ * unless the file integrity is verified externally in some other
+ * way.</li>
+ * </ul>
+ * <p>
+ * <code>verifyCheck</code> only affects the integrity check of
+ * the actual compressed data. The CRC32 fields in the headers
+ * are always verified.
+ *
+ * @param in seekable input stream containing one or more
+ * XZ Streams; the whole input stream is used
+ *
+ * @param memoryLimit memory usage limit in kibibytes (KiB)
+ * or <code>-1</code> to impose no
+ * memory usage limit
+ *
+ * @param verifyCheck if <code>true</code>, the integrity checks
+ * will be verified; this should almost never
+ * be set to <code>false</code>
+ *
+ * @throws XZFormatException
+ * input is not in the XZ format
+ *
+ * @throws CorruptedInputException
+ * XZ data is corrupt or truncated
+ *
+ * @throws UnsupportedOptionsException
+ * XZ headers seem valid but they specify
+ * options not supported by this implementation
+ *
+ * @throws MemoryLimitException
+ * decoded XZ Indexes would need more memory
+ * than allowed by the memory usage limit
+ *
+ * @throws EOFException
+ * less than 6 bytes of input was available
+ * from <code>in</code>, or (unlikely) the size
+ * of the underlying stream got smaller while
+ * this was reading from it
+ *
+ * @throws IOException may be thrown by <code>in</code>
+ *
+ * @since 1.6
+ */
+ public SeekableXZInputStream(SeekableInputStream in, int memoryLimit,
+ boolean verifyCheck)
+ throws IOException {
+ this.verifyCheck = verifyCheck;
+ this.in = in;
+ DataInputStream inData = new DataInputStream(in);
+
+ // Check the magic bytes in the beginning of the file.
+ {
+ in.seek(0);
+ byte[] buf = new byte[XZ.HEADER_MAGIC.length];
+ inData.readFully(buf);
+ if (!Arrays.equals(buf, XZ.HEADER_MAGIC))
+ throw new XZFormatException();
+ }
+
+ // Get the file size and verify that it is a multiple of 4 bytes.
+ long pos = in.length();
+ if ((pos & 3) != 0)
+ throw new CorruptedInputException(
+ "XZ file size is not a multiple of 4 bytes");
+
+ // Parse the headers starting from the end of the file.
+ byte[] buf = new byte[DecoderUtil.STREAM_HEADER_SIZE];
+ long streamPadding = 0;
+
+ while (pos > 0) {
+ if (pos < DecoderUtil.STREAM_HEADER_SIZE)
+ throw new CorruptedInputException();
+
+ // Read the potential Stream Footer.
+ in.seek(pos - DecoderUtil.STREAM_HEADER_SIZE);
+ inData.readFully(buf);
+
+ // Skip Stream Padding four bytes at a time.
+ // Skipping more at once would be faster,
+ // but usually there isn't much Stream Padding.
+ if (buf[8] == 0x00 && buf[9] == 0x00 && buf[10] == 0x00
+ && buf[11] == 0x00) {
+ streamPadding += 4;
+ pos -= 4;
+ continue;
+ }
+
+ // It's not Stream Padding. Update pos.
+ pos -= DecoderUtil.STREAM_HEADER_SIZE;
+
+ // Decode the Stream Footer and check if Backward Size
+ // looks reasonable.
+ StreamFlags streamFooter = DecoderUtil.decodeStreamFooter(buf);
+ if (streamFooter.backwardSize >= pos)
+ throw new CorruptedInputException(
+ "Backward Size in XZ Stream Footer is too big");
+
+ // Check that the Check ID is supported. Store it in case this
+ // is the first Stream in the file.
+ check = Check.getInstance(streamFooter.checkType);
+
+ // Remember which Check IDs have been seen.
+ checkTypes |= 1 << streamFooter.checkType;
+
+ // Seek to the beginning of the Index.
+ in.seek(pos - streamFooter.backwardSize);
+
+ // Decode the Index field.
+ IndexDecoder index;
+ try {
+ index = new IndexDecoder(in, streamFooter, streamPadding,
+ memoryLimit);
+ } catch (MemoryLimitException e) {
+ // IndexDecoder doesn't know how much memory we had
+ // already needed so we need to recreate the exception.
+ assert memoryLimit >= 0;
+ throw new MemoryLimitException(
+ e.getMemoryNeeded() + indexMemoryUsage,
+ memoryLimit + indexMemoryUsage);
+ }
+
+ // Update the memory usage and limit counters.
+ indexMemoryUsage += index.getMemoryUsage();
+ if (memoryLimit >= 0) {
+ memoryLimit -= index.getMemoryUsage();
+ assert memoryLimit >= 0;
+ }
+
+ // Remember the uncompressed size of the largest Block.
+ if (largestBlockSize < index.getLargestBlockSize())
+ largestBlockSize = index.getLargestBlockSize();
+
+ // Calculate the offset to the beginning of this XZ Stream and
+ // check that it looks sane.
+ long off = index.getStreamSize() - DecoderUtil.STREAM_HEADER_SIZE;
+ if (pos < off)
+ throw new CorruptedInputException("XZ Index indicates "
+ + "too big compressed size for the XZ Stream");
+
+ // Seek to the beginning of this Stream.
+ pos -= off;
+ in.seek(pos);
+
+ // Decode the Stream Header.
+ inData.readFully(buf);
+ StreamFlags streamHeader = DecoderUtil.decodeStreamHeader(buf);
+
+ // Verify that the Stream Header matches the Stream Footer.
+ if (!DecoderUtil.areStreamFlagsEqual(streamHeader, streamFooter))
+ throw new CorruptedInputException(
+ "XZ Stream Footer does not match Stream Header");
+
+ // Update the total uncompressed size of the file and check that
+ // it doesn't overflow.
+ uncompressedSize += index.getUncompressedSize();
+ if (uncompressedSize < 0)
+ throw new UnsupportedOptionsException("XZ file is too big");
+
+ // Update the Block count and check that it fits into an int.
+ blockCount += index.getRecordCount();
+ if (blockCount < 0)
+ throw new UnsupportedOptionsException(
+ "XZ file has over " + Integer.MAX_VALUE + " Blocks");
+
+ // Add this Stream to the list of Streams.
+ streams.add(index);
+
+ // Reset to be ready to parse the next Stream.
+ streamPadding = 0;
+ }
+
+ assert pos == 0;
+
+ // Save it now that indexMemoryUsage has been substracted from it.
+ this.memoryLimit = memoryLimit;
+
+ // Store the relative offsets of the Streams. This way we don't
+ // need to recalculate them in this class when seeking; the
+ // IndexDecoder instances will handle them.
+ IndexDecoder prev = (IndexDecoder)streams.get(streams.size() - 1);
+ for (int i = streams.size() - 2; i >= 0; --i) {
+ IndexDecoder cur = (IndexDecoder)streams.get(i);
+ cur.setOffsets(prev);
+ prev = cur;
+ }
+
+ // Initialize curBlockInfo to point to the first Stream.
+ // The blockNumber will be left to -1 so that .hasNext()
+ // and .setNext() work to get the first Block when starting
+ // to decompress from the beginning of the file.
+ IndexDecoder first = (IndexDecoder)streams.get(streams.size() - 1);
+ curBlockInfo = new BlockInfo(first);
+
+ // queriedBlockInfo needs to be allocated too. The Stream used for
+ // initialization doesn't matter though.
+ queriedBlockInfo = new BlockInfo(first);
+ }
+
+ /**
+ * Gets the types of integrity checks used in the .xz file.
+ * Multiple checks are possible only if there are multiple
+ * concatenated XZ Streams.
+ * <p>
+ * The returned value has a bit set for every check type that is present.
+ * For example, if CRC64 and SHA-256 were used, the return value is
+ * <code>(1 << XZ.CHECK_CRC64)
+ * | (1 << XZ.CHECK_SHA256)</code>.
+ */
+ public int getCheckTypes() {
+ return checkTypes;
+ }
+
+ /**
+ * Gets the amount of memory in kibibytes (KiB) used by
+ * the data structures needed to locate the XZ Blocks.
+ * This is usually useless information but since it is calculated
+ * for memory usage limit anyway, it is nice to make it available to too.
+ */
+ public int getIndexMemoryUsage() {
+ return indexMemoryUsage;
+ }
+
+ /**
+ * Gets the uncompressed size of the largest XZ Block in bytes.
+ * This can be useful if you want to check that the file doesn't
+ * have huge XZ Blocks which could make seeking to arbitrary offsets
+ * very slow. Note that huge Blocks don't automatically mean that
+ * seeking would be slow, for example, seeking to the beginning of
+ * any Block is always fast.
+ */
+ public long getLargestBlockSize() {
+ return largestBlockSize;
+ }
+
+ /**
+ * Gets the number of Streams in the .xz file.
+ *
+ * @since 1.3
+ */
+ public int getStreamCount() {
+ return streams.size();
+ }
+
+ /**
+ * Gets the number of Blocks in the .xz file.
+ *
+ * @since 1.3
+ */
+ public int getBlockCount() {
+ return blockCount;
+ }
+
+ /**
+ * Gets the uncompressed start position of the given Block.
+ *
+ * @throws IndexOutOfBoundsException if
+ * <code>blockNumber < 0</code> or
+ * <code>blockNumber >= getBlockCount()</code>.
+ *
+ * @since 1.3
+ */
+ public long getBlockPos(int blockNumber) {
+ locateBlockByNumber(queriedBlockInfo, blockNumber);
+ return queriedBlockInfo.uncompressedOffset;
+ }
+
+ /**
+ * Gets the uncompressed size of the given Block.
+ *
+ * @throws IndexOutOfBoundsException if
+ * <code>blockNumber < 0</code> or
+ * <code>blockNumber >= getBlockCount()</code>.
+ *
+ * @since 1.3
+ */
+ public long getBlockSize(int blockNumber) {
+ locateBlockByNumber(queriedBlockInfo, blockNumber);
+ return queriedBlockInfo.uncompressedSize;
+ }
+
+ /**
+ * Gets the position where the given compressed Block starts in
+ * the underlying .xz file.
+ * This information is rarely useful to the users of this class.
+ *
+ * @throws IndexOutOfBoundsException if
+ * <code>blockNumber < 0</code> or
+ * <code>blockNumber >= getBlockCount()</code>.
+ *
+ * @since 1.3
+ */
+ public long getBlockCompPos(int blockNumber) {
+ locateBlockByNumber(queriedBlockInfo, blockNumber);
+ return queriedBlockInfo.compressedOffset;
+ }
+
+ /**
+ * Gets the compressed size of the given Block.
+ * This together with the uncompressed size can be used to calculate
+ * the compression ratio of the specific Block.
+ *
+ * @throws IndexOutOfBoundsException if
+ * <code>blockNumber < 0</code> or
+ * <code>blockNumber >= getBlockCount()</code>.
+ *
+ * @since 1.3
+ */
+ public long getBlockCompSize(int blockNumber) {
+ locateBlockByNumber(queriedBlockInfo, blockNumber);
+ return (queriedBlockInfo.unpaddedSize + 3) & ~3;
+ }
+
+ /**
+ * Gets integrity check type (Check ID) of the given Block.
+ *
+ * @throws IndexOutOfBoundsException if
+ * <code>blockNumber < 0</code> or
+ * <code>blockNumber >= getBlockCount()</code>.
+ *
+ * @see #getCheckTypes()
+ *
+ * @since 1.3
+ */
+ public int getBlockCheckType(int blockNumber) {
+ locateBlockByNumber(queriedBlockInfo, blockNumber);
+ return queriedBlockInfo.getCheckType();
+ }
+
+ /**
+ * Gets the number of the Block that contains the byte at the given
+ * uncompressed position.
+ *
+ * @throws IndexOutOfBoundsException if
+ * <code>pos < 0</code> or
+ * <code>pos >= length()</code>.
+ *
+ * @since 1.3
+ */
+ public int getBlockNumber(long pos) {
+ locateBlockByPos(queriedBlockInfo, pos);
+ return queriedBlockInfo.blockNumber;
+ }
+
+ /**
+ * Decompresses the next byte from this input stream.
+ *
+ * @return the next decompressed byte, or <code>-1</code>
+ * to indicate the end of the compressed stream
+ *
+ * @throws CorruptedInputException
+ * @throws UnsupportedOptionsException
+ * @throws MemoryLimitException
+ *
+ * @throws XZIOException if the stream has been closed
+ *
+ * @throws IOException may be thrown by <code>in</code>
+ */
+ public int read() throws IOException {
+ return read(tempBuf, 0, 1) == -1 ? -1 : (tempBuf[0] & 0xFF);
+ }
+
+ /**
+ * Decompresses into an array of bytes.
+ * <p>
+ * If <code>len</code> is zero, no bytes are read and <code>0</code>
+ * is returned. Otherwise this will try to decompress <code>len</code>
+ * bytes of uncompressed data. Less than <code>len</code> bytes may
+ * be read only in the following situations:
+ * <ul>
+ * <li>The end of the compressed data was reached successfully.</li>
+ * <li>An error is detected after at least one but less than
+ * <code>len</code> bytes have already been successfully
+ * decompressed. The next call with non-zero <code>len</code>
+ * will immediately throw the pending exception.</li>
+ * <li>An exception is thrown.</li>
+ * </ul>
+ *
+ * @param buf target buffer for uncompressed data
+ * @param off start offset in <code>buf</code>
+ * @param len maximum number of uncompressed bytes to read
+ *
+ * @return number of bytes read, or <code>-1</code> to indicate
+ * the end of the compressed stream
+ *
+ * @throws CorruptedInputException
+ * @throws UnsupportedOptionsException
+ * @throws MemoryLimitException
+ *
+ * @throws XZIOException if the stream has been closed
+ *
+ * @throws IOException may be thrown by <code>in</code>
+ */
+ public int read(byte[] buf, int off, int len) throws IOException {
+ if (off < 0 || len < 0 || off + len < 0 || off + len > buf.length)
+ throw new IndexOutOfBoundsException();
+
+ if (len == 0)
+ return 0;
+
+ if (in == null)
+ throw new XZIOException("Stream closed");
+
+ if (exception != null)
+ throw exception;
+
+ int size = 0;
+
+ try {
+ if (seekNeeded)
+ seek();
+
+ if (endReached)
+ return -1;
+
+ while (len > 0) {
+ if (blockDecoder == null) {
+ seek();
+ if (endReached)
+ break;
+ }
+
+ int ret = blockDecoder.read(buf, off, len);
+
+ if (ret > 0) {
+ curPos += ret;
+ size += ret;
+ off += ret;
+ len -= ret;
+ } else if (ret == -1) {
+ blockDecoder = null;
+ }
+ }
+ } catch (IOException e) {
+ // We know that the file isn't simply truncated because we could
+ // parse the Indexes in the constructor. So convert EOFException
+ // to CorruptedInputException.
+ if (e instanceof EOFException)
+ e = new CorruptedInputException();
+
+ exception = e;
+ if (size == 0)
+ throw e;
+ }
+
+ return size;
+ }
+
+ /**
+ * Returns the number of uncompressed bytes that can be read
+ * without blocking. The value is returned with an assumption
+ * that the compressed input data will be valid. If the compressed
+ * data is corrupt, <code>CorruptedInputException</code> may get
+ * thrown before the number of bytes claimed to be available have
+ * been read from this input stream.
+ *
+ * @return the number of uncompressed bytes that can be read
+ * without blocking
+ */
+ public int available() throws IOException {
+ if (in == null)
+ throw new XZIOException("Stream closed");
+
+ if (exception != null)
+ throw exception;
+
+ if (endReached || seekNeeded || blockDecoder == null)
+ return 0;
+
+ return blockDecoder.available();
+ }
+
+ /**
+ * Closes the stream and calls <code>in.close()</code>.
+ * If the stream was already closed, this does nothing.
+ *
+ * @throws IOException if thrown by <code>in.close()</code>
+ */
+ public void close() throws IOException {
+ if (in != null) {
+ try {
+ in.close();
+ } finally {
+ in = null;
+ }
+ }
+ }
+
+ /**
+ * Gets the uncompressed size of this input stream. If there are multiple
+ * XZ Streams, the total uncompressed size of all XZ Streams is returned.
+ */
+ public long length() {
+ return uncompressedSize;
+ }
+
+ /**
+ * Gets the current uncompressed position in this input stream.
+ *
+ * @throws XZIOException if the stream has been closed
+ */
+ public long position() throws IOException {
+ if (in == null)
+ throw new XZIOException("Stream closed");
+
+ return seekNeeded ? seekPos : curPos;
+ }
+
+ /**
+ * Seeks to the specified absolute uncompressed position in the stream.
+ * This only stores the new position, so this function itself is always
+ * very fast. The actual seek is done when <code>read</code> is called
+ * to read at least one byte.
+ * <p>
+ * Seeking past the end of the stream is possible. In that case
+ * <code>read</code> will return <code>-1</code> to indicate
+ * the end of the stream.
+ *
+ * @param pos new uncompressed read position
+ *
+ * @throws XZIOException
+ * if <code>pos</code> is negative, or
+ * if stream has been closed
+ */
+ public void seek(long pos) throws IOException {
+ if (in == null)
+ throw new XZIOException("Stream closed");
+
+ if (pos < 0)
+ throw new XZIOException("Negative seek position: " + pos);
+
+ seekPos = pos;
+ seekNeeded = true;
+ }
+
+ /**
+ * Seeks to the beginning of the given XZ Block.
+ *
+ * @throws XZIOException
+ * if <code>blockNumber < 0</code> or
+ * <code>blockNumber >= getBlockCount()</code>,
+ * or if stream has been closed
+ *
+ * @since 1.3
+ */
+ public void seekToBlock(int blockNumber) throws IOException {
+ if (in == null)
+ throw new XZIOException("Stream closed");
+
+ if (blockNumber < 0 || blockNumber >= blockCount)
+ throw new XZIOException("Invalid XZ Block number: " + blockNumber);
+
+ // This is a bit silly implementation. Here we locate the uncompressed
+ // offset of the specified Block, then when doing the actual seek in
+ // seek(), we need to find the Block number based on seekPos.
+ seekPos = getBlockPos(blockNumber);
+ seekNeeded = true;
+ }
+
+ /**
+ * Does the actual seeking. This is also called when <code>read</code>
+ * needs a new Block to decode.
+ */
+ private void seek() throws IOException {
+ // If seek(long) wasn't called, we simply need to get the next Block
+ // from the same Stream. If there are no more Blocks in this Stream,
+ // then we behave as if seek(long) had been called.
+ if (!seekNeeded) {
+ if (curBlockInfo.hasNext()) {
+ curBlockInfo.setNext();
+ initBlockDecoder();
+ return;
+ }
+
+ seekPos = curPos;
+ }
+
+ seekNeeded = false;
+
+ // Check if we are seeking to or past the end of the file.
+ if (seekPos >= uncompressedSize) {
+ curPos = seekPos;
+ blockDecoder = null;
+ endReached = true;
+ return;
+ }
+
+ endReached = false;
+
+ // Locate the Block that contains the uncompressed target position.
+ locateBlockByPos(curBlockInfo, seekPos);
+
+ // Seek in the underlying stream and create a new Block decoder
+ // only if really needed. We can skip it if the current position
+ // is already in the correct Block and the target position hasn't
+ // been decompressed yet.
+ //
+ // NOTE: If curPos points to the beginning of this Block, it's
+ // because it was left there after decompressing an earlier Block.
+ // In that case, decoding of the current Block hasn't been started
+ // yet. (Decoding of a Block won't be started until at least one
+ // byte will also be read from it.)
+ if (!(curPos > curBlockInfo.uncompressedOffset && curPos <= seekPos)) {
+ // Seek to the beginning of the Block.
+ in.seek(curBlockInfo.compressedOffset);
+
+ // Since it is possible that this Block is from a different
+ // Stream than the previous Block, initialize a new Check.
+ check = Check.getInstance(curBlockInfo.getCheckType());
+
+ // Create a new Block decoder.
+ initBlockDecoder();
+ curPos = curBlockInfo.uncompressedOffset;
+ }
+
+ // If the target wasn't at a Block boundary, decompress and throw
+ // away data to reach the target position.
+ if (seekPos > curPos) {
+ // NOTE: The "if" below is there just in case. In this situation,
+ // blockDecoder.skip will always skip the requested amount
+ // or throw an exception.
+ long skipAmount = seekPos - curPos;
+ if (blockDecoder.skip(skipAmount) != skipAmount)
+ throw new CorruptedInputException();
+
+ curPos = seekPos;
+ }
+ }
+
+ /**
+ * Locates the Block that contains the given uncompressed position.
+ */
+ private void locateBlockByPos(BlockInfo info, long pos) {
+ if (pos < 0 || pos >= uncompressedSize)
+ throw new IndexOutOfBoundsException(
+ "Invalid uncompressed position: " + pos);
+
+ // Locate the Stream that contains the target position.
+ IndexDecoder index;
+ for (int i = 0; ; ++i) {
+ index = (IndexDecoder)streams.get(i);
+ if (index.hasUncompressedOffset(pos))
+ break;
+ }
+
+ // Locate the Block from the Stream that contains the target position.
+ index.locateBlock(info, pos);
+
+ assert (info.compressedOffset & 3) == 0;
+ assert info.uncompressedSize > 0;
+ assert pos >= info.uncompressedOffset;
+ assert pos < info.uncompressedOffset + info.uncompressedSize;
+ }
+
+ /**
+ * Locates the given Block and stores information about it
+ * to <code>info</code>.
+ */
+ private void locateBlockByNumber(BlockInfo info, int blockNumber) {
+ // Validate.
+ if (blockNumber < 0 || blockNumber >= blockCount)
+ throw new IndexOutOfBoundsException(
+ "Invalid XZ Block number: " + blockNumber);
+
+ // Skip the search if info already points to the correct Block.
+ if (info.blockNumber == blockNumber)
+ return;
+
+ // Search the Stream that contains the given Block and then
+ // search the Block from that Stream.
+ for (int i = 0; ; ++i) {
+ IndexDecoder index = (IndexDecoder)streams.get(i);
+ if (index.hasRecord(blockNumber)) {
+ index.setBlockInfo(info, blockNumber);
+ return;
+ }
+ }
+ }
+
+ /**
+ * Initializes a new BlockInputStream. This is a helper function for
+ * <code>seek()</code>.
+ */
+ private void initBlockDecoder() throws IOException {
+ try {
+ // Set it to null first so that GC can collect it if memory
+ // runs tight when initializing a new BlockInputStream.
+ blockDecoder = null;
+ blockDecoder = new BlockInputStream(
+ in, check, verifyCheck, memoryLimit,
+ curBlockInfo.unpaddedSize, curBlockInfo.uncompressedSize);
+ } catch (MemoryLimitException e) {
+ // BlockInputStream doesn't know how much memory we had
+ // already needed so we need to recreate the exception.
+ assert memoryLimit >= 0;
+ throw new MemoryLimitException(
+ e.getMemoryNeeded() + indexMemoryUsage,
+ memoryLimit + indexMemoryUsage);
+ } catch (IndexIndicatorException e) {
+ // It cannot be Index so the file must be corrupt.
+ throw new CorruptedInputException();
+ }
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/SimpleInputStream.java b/lzma/Java/Tukaani/src/org/tukaani/xz/SimpleInputStream.java
new file mode 100644
index 0000000..afd40c7
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/SimpleInputStream.java
@@ -0,0 +1,138 @@
+/*
+ * SimpleInputStream
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz;
+
+import java.io.InputStream;
+import java.io.IOException;
+import org.tukaani.xz.simple.SimpleFilter;
+
+class SimpleInputStream extends InputStream {
+ private static final int FILTER_BUF_SIZE = 4096;
+
+ private InputStream in;
+ private final SimpleFilter simpleFilter;
+
+ private final byte[] filterBuf = new byte[FILTER_BUF_SIZE];
+ private int pos = 0;
+ private int filtered = 0;
+ private int unfiltered = 0;
+
+ private boolean endReached = false;
+ private IOException exception = null;
+
+ private final byte[] tempBuf = new byte[1];
+
+ static int getMemoryUsage() {
+ return 1 + FILTER_BUF_SIZE / 1024;
+ }
+
+ SimpleInputStream(InputStream in, SimpleFilter simpleFilter) {
+ // Check for null because otherwise null isn't detect
+ // in this constructor.
+ if (in == null)
+ throw new NullPointerException();
+
+ // The simpleFilter argument comes from this package
+ // so it is known to be non-null already.
+ assert simpleFilter != null;
+
+ this.in = in;
+ this.simpleFilter = simpleFilter;
+ }
+
+ public int read() throws IOException {
+ return read(tempBuf, 0, 1) == -1 ? -1 : (tempBuf[0] & 0xFF);
+ }
+
+ public int read(byte[] buf, int off, int len) throws IOException {
+ if (off < 0 || len < 0 || off + len < 0 || off + len > buf.length)
+ throw new IndexOutOfBoundsException();
+
+ if (len == 0)
+ return 0;
+
+ if (in == null)
+ throw new XZIOException("Stream closed");
+
+ if (exception != null)
+ throw exception;
+
+ try {
+ int size = 0;
+
+ while (true) {
+ // Copy filtered data into the caller-provided buffer.
+ int copySize = Math.min(filtered, len);
+ System.arraycopy(filterBuf, pos, buf, off, copySize);
+ pos += copySize;
+ filtered -= copySize;
+ off += copySize;
+ len -= copySize;
+ size += copySize;
+
+ // If end of filterBuf was reached, move the pending data to
+ // the beginning of the buffer so that more data can be
+ // copied into filterBuf on the next loop iteration.
+ if (pos + filtered + unfiltered == FILTER_BUF_SIZE) {
+ System.arraycopy(filterBuf, pos, filterBuf, 0,
+ filtered + unfiltered);
+ pos = 0;
+ }
+
+ if (len == 0 || endReached)
+ return size > 0 ? size : -1;
+
+ assert filtered == 0;
+
+ // Get more data into the temporary buffer.
+ int inSize = FILTER_BUF_SIZE - (pos + filtered + unfiltered);
+ inSize = in.read(filterBuf, pos + filtered + unfiltered,
+ inSize);
+
+ if (inSize == -1) {
+ // Mark the remaining unfiltered bytes to be ready
+ // to be copied out.
+ endReached = true;
+ filtered = unfiltered;
+ unfiltered = 0;
+ } else {
+ // Filter the data in filterBuf.
+ unfiltered += inSize;
+ filtered = simpleFilter.code(filterBuf, pos, unfiltered);
+ assert filtered <= unfiltered;
+ unfiltered -= filtered;
+ }
+ }
+ } catch (IOException e) {
+ exception = e;
+ throw e;
+ }
+ }
+
+ public int available() throws IOException {
+ if (in == null)
+ throw new XZIOException("Stream closed");
+
+ if (exception != null)
+ throw exception;
+
+ return filtered;
+ }
+
+ public void close() throws IOException {
+ if (in != null) {
+ try {
+ in.close();
+ } finally {
+ in = null;
+ }
+ }
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/SimpleOutputStream.java b/lzma/Java/Tukaani/src/org/tukaani/xz/SimpleOutputStream.java
new file mode 100644
index 0000000..771b1fb
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/SimpleOutputStream.java
@@ -0,0 +1,151 @@
+/*
+ * SimpleOutputStream
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz;
+
+import java.io.IOException;
+import org.tukaani.xz.simple.SimpleFilter;
+
+class SimpleOutputStream extends FinishableOutputStream {
+ private static final int FILTER_BUF_SIZE = 4096;
+
+ private FinishableOutputStream out;
+ private final SimpleFilter simpleFilter;
+
+ private final byte[] filterBuf = new byte[FILTER_BUF_SIZE];
+ private int pos = 0;
+ private int unfiltered = 0;
+
+ private IOException exception = null;
+ private boolean finished = false;
+
+ private final byte[] tempBuf = new byte[1];
+
+ static int getMemoryUsage() {
+ return 1 + FILTER_BUF_SIZE / 1024;
+ }
+
+ SimpleOutputStream(FinishableOutputStream out,
+ SimpleFilter simpleFilter) {
+ if (out == null)
+ throw new NullPointerException();
+
+ this.out = out;
+ this.simpleFilter = simpleFilter;
+ }
+
+ public void write(int b) throws IOException {
+ tempBuf[0] = (byte)b;
+ write(tempBuf, 0, 1);
+ }
+
+ public void write(byte[] buf, int off, int len) throws IOException {
+ if (off < 0 || len < 0 || off + len < 0 || off + len > buf.length)
+ throw new IndexOutOfBoundsException();
+
+ if (exception != null)
+ throw exception;
+
+ if (finished)
+ throw new XZIOException("Stream finished or closed");
+
+ while (len > 0) {
+ // Copy more unfiltered data into filterBuf.
+ int copySize = Math.min(len, FILTER_BUF_SIZE - (pos + unfiltered));
+ System.arraycopy(buf, off, filterBuf, pos + unfiltered, copySize);
+ off += copySize;
+ len -= copySize;
+ unfiltered += copySize;
+
+ // Filter the data in filterBuf.
+ int filtered = simpleFilter.code(filterBuf, pos, unfiltered);
+ assert filtered <= unfiltered;
+ unfiltered -= filtered;
+
+ // Write out the filtered data.
+ try {
+ out.write(filterBuf, pos, filtered);
+ } catch (IOException e) {
+ exception = e;
+ throw e;
+ }
+
+ pos += filtered;
+
+ // If end of filterBuf was reached, move the pending unfiltered
+ // data to the beginning of the buffer so that more data can
+ // be copied into filterBuf on the next loop iteration.
+ if (pos + unfiltered == FILTER_BUF_SIZE) {
+ System.arraycopy(filterBuf, pos, filterBuf, 0, unfiltered);
+ pos = 0;
+ }
+ }
+ }
+
+ private void writePending() throws IOException {
+ assert !finished;
+
+ if (exception != null)
+ throw exception;
+
+ try {
+ out.write(filterBuf, pos, unfiltered);
+ } catch (IOException e) {
+ exception = e;
+ throw e;
+ }
+
+ finished = true;
+ }
+
+ public void flush() throws IOException {
+ throw new UnsupportedOptionsException("Flushing is not supported");
+ }
+
+ public void finish() throws IOException {
+ if (!finished) {
+ // If it fails, don't call out.finish().
+ writePending();
+
+ try {
+ out.finish();
+ } catch (IOException e) {
+ exception = e;
+ throw e;
+ }
+ }
+ }
+
+ public void close() throws IOException {
+ if (out != null) {
+ if (!finished) {
+ // out.close() must be called even if writePending() fails.
+ // writePending() saves the possible exception so we can
+ // ignore exceptions here.
+ try {
+ writePending();
+ } catch (IOException e) {}
+ }
+
+ try {
+ out.close();
+ } catch (IOException e) {
+ // If there is an earlier exception, the exception
+ // from out.close() is lost.
+ if (exception == null)
+ exception = e;
+ }
+
+ out = null;
+ }
+
+ if (exception != null)
+ throw exception;
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/SingleXZInputStream.java b/lzma/Java/Tukaani/src/org/tukaani/xz/SingleXZInputStream.java
new file mode 100644
index 0000000..f0c5a16
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/SingleXZInputStream.java
@@ -0,0 +1,375 @@
+/*
+ * SingleXZInputStream
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz;
+
+import java.io.InputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.EOFException;
+import org.tukaani.xz.common.DecoderUtil;
+import org.tukaani.xz.common.StreamFlags;
+import org.tukaani.xz.index.IndexHash;
+import org.tukaani.xz.check.Check;
+
+/**
+ * Decompresses exactly one XZ Stream in streamed mode (no seeking).
+ * The decompression stops after the first XZ Stream has been decompressed,
+ * and the read position in the input stream is left at the first byte
+ * after the end of the XZ Stream. This can be useful when XZ data has
+ * been stored inside some other file format or protocol.
+ * <p>
+ * Unless you know what you are doing, don't use this class to decompress
+ * standalone .xz files. For that purpose, use <code>XZInputStream</code>.
+ *
+ * <h4>When uncompressed size is known beforehand</h4>
+ * <p>
+ * If you are decompressing complete XZ streams and your application knows
+ * exactly how much uncompressed data there should be, it is good to try
+ * reading one more byte by calling <code>read()</code> and checking
+ * that it returns <code>-1</code>. This way the decompressor will parse the
+ * file footers and verify the integrity checks, giving the caller more
+ * confidence that the uncompressed data is valid.
+ *
+ * @see XZInputStream
+ */
+public class SingleXZInputStream extends InputStream {
+ private InputStream in;
+ private final int memoryLimit;
+ private final StreamFlags streamHeaderFlags;
+ private final Check check;
+ private final boolean verifyCheck;
+ private BlockInputStream blockDecoder = null;
+ private final IndexHash indexHash = new IndexHash();
+ private boolean endReached = false;
+ private IOException exception = null;
+
+ private final byte[] tempBuf = new byte[1];
+
+ /**
+ * Reads the Stream Header into a buffer.
+ * This is a helper function for the constructors.
+ */
+ private static byte[] readStreamHeader(InputStream in) throws IOException {
+ byte[] streamHeader = new byte[DecoderUtil.STREAM_HEADER_SIZE];
+ new DataInputStream(in).readFully(streamHeader);
+ return streamHeader;
+ }
+
+ /**
+ * Creates a new XZ decompressor that decompresses exactly one
+ * XZ Stream from <code>in</code> without a memory usage limit.
+ * <p>
+ * This constructor reads and parses the XZ Stream Header (12 bytes)
+ * from <code>in</code>. The header of the first Block is not read
+ * until <code>read</code> is called.
+ *
+ * @param in input stream from which XZ-compressed
+ * data is read
+ *
+ * @throws XZFormatException
+ * input is not in the XZ format
+ *
+ * @throws CorruptedInputException
+ * XZ header CRC32 doesn't match
+ *
+ * @throws UnsupportedOptionsException
+ * XZ header is valid but specifies options
+ * not supported by this implementation
+ *
+ * @throws EOFException
+ * less than 12 bytes of input was available
+ * from <code>in</code>
+ *
+ * @throws IOException may be thrown by <code>in</code>
+ */
+ public SingleXZInputStream(InputStream in) throws IOException {
+ this(in, -1);
+ }
+
+ /**
+ * Creates a new XZ decompressor that decompresses exactly one
+ * XZ Stream from <code>in</code> with an optional memory usage limit.
+ * <p>
+ * This is identical to <code>SingleXZInputStream(InputStream)</code>
+ * except that this takes also the <code>memoryLimit</code> argument.
+ *
+ * @param in input stream from which XZ-compressed
+ * data is read
+ *
+ * @param memoryLimit memory usage limit in kibibytes (KiB)
+ * or <code>-1</code> to impose no
+ * memory usage limit
+ *
+ * @throws XZFormatException
+ * input is not in the XZ format
+ *
+ * @throws CorruptedInputException
+ * XZ header CRC32 doesn't match
+ *
+ * @throws UnsupportedOptionsException
+ * XZ header is valid but specifies options
+ * not supported by this implementation
+ *
+ * @throws EOFException
+ * less than 12 bytes of input was available
+ * from <code>in</code>
+ *
+ * @throws IOException may be thrown by <code>in</code>
+ */
+ public SingleXZInputStream(InputStream in, int memoryLimit)
+ throws IOException {
+ this(in, memoryLimit, true, readStreamHeader(in));
+ }
+
+ /**
+ * Creates a new XZ decompressor that decompresses exactly one
+ * XZ Stream from <code>in</code> with an optional memory usage limit
+ * and ability to disable verification of integrity checks.
+ * <p>
+ * This is identical to <code>SingleXZInputStream(InputStream,int)</code>
+ * except that this takes also the <code>verifyCheck</code> argument.
+ * <p>
+ * Note that integrity check verification should almost never be disabled.
+ * Possible reasons to disable integrity check verification:
+ * <ul>
+ * <li>Trying to recover data from a corrupt .xz file.</li>
+ * <li>Speeding up decompression. This matters mostly with SHA-256
+ * or with files that have compressed extremely well. It's recommended
+ * that integrity checking isn't disabled for performance reasons
+ * unless the file integrity is verified externally in some other
+ * way.</li>
+ * </ul>
+ * <p>
+ * <code>verifyCheck</code> only affects the integrity check of
+ * the actual compressed data. The CRC32 fields in the headers
+ * are always verified.
+ *
+ * @param in input stream from which XZ-compressed
+ * data is read
+ *
+ * @param memoryLimit memory usage limit in kibibytes (KiB)
+ * or <code>-1</code> to impose no
+ * memory usage limit
+ *
+ * @param verifyCheck if <code>true</code>, the integrity checks
+ * will be verified; this should almost never
+ * be set to <code>false</code>
+ *
+ * @throws XZFormatException
+ * input is not in the XZ format
+ *
+ * @throws CorruptedInputException
+ * XZ header CRC32 doesn't match
+ *
+ * @throws UnsupportedOptionsException
+ * XZ header is valid but specifies options
+ * not supported by this implementation
+ *
+ * @throws EOFException
+ * less than 12 bytes of input was available
+ * from <code>in</code>
+ *
+ * @throws IOException may be thrown by <code>in</code>
+ *
+ * @since 1.6
+ */
+ public SingleXZInputStream(InputStream in, int memoryLimit,
+ boolean verifyCheck) throws IOException {
+ this(in, memoryLimit, verifyCheck, readStreamHeader(in));
+ }
+
+ SingleXZInputStream(InputStream in, int memoryLimit, boolean verifyCheck,
+ byte[] streamHeader) throws IOException {
+ this.in = in;
+ this.memoryLimit = memoryLimit;
+ this.verifyCheck = verifyCheck;
+ streamHeaderFlags = DecoderUtil.decodeStreamHeader(streamHeader);
+ check = Check.getInstance(streamHeaderFlags.checkType);
+ }
+
+ /**
+ * Gets the ID of the integrity check used in this XZ Stream.
+ *
+ * @return the Check ID specified in the XZ Stream Header
+ */
+ public int getCheckType() {
+ return streamHeaderFlags.checkType;
+ }
+
+ /**
+ * Gets the name of the integrity check used in this XZ Stream.
+ *
+ * @return the name of the check specified in the XZ Stream Header
+ */
+ public String getCheckName() {
+ return check.getName();
+ }
+
+ /**
+ * Decompresses the next byte from this input stream.
+ * <p>
+ * Reading lots of data with <code>read()</code> from this input stream
+ * may be inefficient. Wrap it in {@link java.io.BufferedInputStream}
+ * if you need to read lots of data one byte at a time.
+ *
+ * @return the next decompressed byte, or <code>-1</code>
+ * to indicate the end of the compressed stream
+ *
+ * @throws CorruptedInputException
+ * @throws UnsupportedOptionsException
+ * @throws MemoryLimitException
+ *
+ * @throws XZIOException if the stream has been closed
+ *
+ * @throws EOFException
+ * compressed input is truncated or corrupt
+ *
+ * @throws IOException may be thrown by <code>in</code>
+ */
+ public int read() throws IOException {
+ return read(tempBuf, 0, 1) == -1 ? -1 : (tempBuf[0] & 0xFF);
+ }
+
+ /**
+ * Decompresses into an array of bytes.
+ * <p>
+ * If <code>len</code> is zero, no bytes are read and <code>0</code>
+ * is returned. Otherwise this will try to decompress <code>len</code>
+ * bytes of uncompressed data. Less than <code>len</code> bytes may
+ * be read only in the following situations:
+ * <ul>
+ * <li>The end of the compressed data was reached successfully.</li>
+ * <li>An error is detected after at least one but less <code>len</code>
+ * bytes have already been successfully decompressed.
+ * The next call with non-zero <code>len</code> will immediately
+ * throw the pending exception.</li>
+ * <li>An exception is thrown.</li>
+ * </ul>
+ *
+ * @param buf target buffer for uncompressed data
+ * @param off start offset in <code>buf</code>
+ * @param len maximum number of uncompressed bytes to read
+ *
+ * @return number of bytes read, or <code>-1</code> to indicate
+ * the end of the compressed stream
+ *
+ * @throws CorruptedInputException
+ * @throws UnsupportedOptionsException
+ * @throws MemoryLimitException
+ *
+ * @throws XZIOException if the stream has been closed
+ *
+ * @throws EOFException
+ * compressed input is truncated or corrupt
+ *
+ * @throws IOException may be thrown by <code>in</code>
+ */
+ public int read(byte[] buf, int off, int len) throws IOException {
+ if (off < 0 || len < 0 || off + len < 0 || off + len > buf.length)
+ throw new IndexOutOfBoundsException();
+
+ if (len == 0)
+ return 0;
+
+ if (in == null)
+ throw new XZIOException("Stream closed");
+
+ if (exception != null)
+ throw exception;
+
+ if (endReached)
+ return -1;
+
+ int size = 0;
+
+ try {
+ while (len > 0) {
+ if (blockDecoder == null) {
+ try {
+ blockDecoder = new BlockInputStream(
+ in, check, verifyCheck, memoryLimit, -1, -1);
+ } catch (IndexIndicatorException e) {
+ indexHash.validate(in);
+ validateStreamFooter();
+ endReached = true;
+ return size > 0 ? size : -1;
+ }
+ }
+
+ int ret = blockDecoder.read(buf, off, len);
+
+ if (ret > 0) {
+ size += ret;
+ off += ret;
+ len -= ret;
+ } else if (ret == -1) {
+ indexHash.add(blockDecoder.getUnpaddedSize(),
+ blockDecoder.getUncompressedSize());
+ blockDecoder = null;
+ }
+ }
+ } catch (IOException e) {
+ exception = e;
+ if (size == 0)
+ throw e;
+ }
+
+ return size;
+ }
+
+ private void validateStreamFooter() throws IOException {
+ byte[] buf = new byte[DecoderUtil.STREAM_HEADER_SIZE];
+ new DataInputStream(in).readFully(buf);
+ StreamFlags streamFooterFlags = DecoderUtil.decodeStreamFooter(buf);
+
+ if (!DecoderUtil.areStreamFlagsEqual(streamHeaderFlags,
+ streamFooterFlags)
+ || indexHash.getIndexSize() != streamFooterFlags.backwardSize)
+ throw new CorruptedInputException(
+ "XZ Stream Footer does not match Stream Header");
+ }
+
+ /**
+ * Returns the number of uncompressed bytes that can be read
+ * without blocking. The value is returned with an assumption
+ * that the compressed input data will be valid. If the compressed
+ * data is corrupt, <code>CorruptedInputException</code> may get
+ * thrown before the number of bytes claimed to be available have
+ * been read from this input stream.
+ *
+ * @return the number of uncompressed bytes that can be read
+ * without blocking
+ */
+ public int available() throws IOException {
+ if (in == null)
+ throw new XZIOException("Stream closed");
+
+ if (exception != null)
+ throw exception;
+
+ return blockDecoder == null ? 0 : blockDecoder.available();
+ }
+
+ /**
+ * Closes the stream and calls <code>in.close()</code>.
+ * If the stream was already closed, this does nothing.
+ *
+ * @throws IOException if thrown by <code>in.close()</code>
+ */
+ public void close() throws IOException {
+ if (in != null) {
+ try {
+ in.close();
+ } finally {
+ in = null;
+ }
+ }
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/UncompressedLZMA2OutputStream.java b/lzma/Java/Tukaani/src/org/tukaani/xz/UncompressedLZMA2OutputStream.java
new file mode 100644
index 0000000..1ff9675
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/UncompressedLZMA2OutputStream.java
@@ -0,0 +1,153 @@
+/*
+ * UncompressedLZMA2OutputStream
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+class UncompressedLZMA2OutputStream extends FinishableOutputStream {
+ private FinishableOutputStream out;
+ private final DataOutputStream outData;
+
+ private final byte[] uncompBuf
+ = new byte[LZMA2OutputStream.COMPRESSED_SIZE_MAX];
+ private int uncompPos = 0;
+ private boolean dictResetNeeded = true;
+
+ private boolean finished = false;
+ private IOException exception = null;
+
+ private final byte[] tempBuf = new byte[1];
+
+ static int getMemoryUsage() {
+ // uncompBuf + a little extra
+ return 70;
+ }
+
+ UncompressedLZMA2OutputStream(FinishableOutputStream out) {
+ if (out == null)
+ throw new NullPointerException();
+
+ this.out = out;
+ outData = new DataOutputStream(out);
+ }
+
+ public void write(int b) throws IOException {
+ tempBuf[0] = (byte)b;
+ write(tempBuf, 0, 1);
+ }
+
+ public void write(byte[] buf, int off, int len) throws IOException {
+ if (off < 0 || len < 0 || off + len < 0 || off + len > buf.length)
+ throw new IndexOutOfBoundsException();
+
+ if (exception != null)
+ throw exception;
+
+ if (finished)
+ throw new XZIOException("Stream finished or closed");
+
+ try {
+ while (len > 0) {
+ int copySize = Math.min(uncompBuf.length - uncompPos, len);
+ System.arraycopy(buf, off, uncompBuf, uncompPos, copySize);
+ len -= copySize;
+ uncompPos += copySize;
+
+ if (uncompPos == uncompBuf.length)
+ writeChunk();
+ }
+ } catch (IOException e) {
+ exception = e;
+ throw e;
+ }
+ }
+
+ private void writeChunk() throws IOException {
+ outData.writeByte(dictResetNeeded ? 0x01 : 0x02);
+ outData.writeShort(uncompPos - 1);
+ outData.write(uncompBuf, 0, uncompPos);
+ uncompPos = 0;
+ dictResetNeeded = false;
+ }
+
+ private void writeEndMarker() throws IOException {
+ if (exception != null)
+ throw exception;
+
+ if (finished)
+ throw new XZIOException("Stream finished or closed");
+
+ try {
+ if (uncompPos > 0)
+ writeChunk();
+
+ out.write(0x00);
+ } catch (IOException e) {
+ exception = e;
+ throw e;
+ }
+ }
+
+ public void flush() throws IOException {
+ if (exception != null)
+ throw exception;
+
+ if (finished)
+ throw new XZIOException("Stream finished or closed");
+
+ try {
+ if (uncompPos > 0)
+ writeChunk();
+
+ out.flush();
+ } catch (IOException e) {
+ exception = e;
+ throw e;
+ }
+ }
+
+ public void finish() throws IOException {
+ if (!finished) {
+ writeEndMarker();
+
+ try {
+ out.finish();
+ } catch (IOException e) {
+ exception = e;
+ throw e;
+ }
+
+ finished = true;
+ }
+ }
+
+ public void close() throws IOException {
+ if (out != null) {
+ if (!finished) {
+ try {
+ writeEndMarker();
+ } catch (IOException e) {}
+ }
+
+ try {
+ out.close();
+ } catch (IOException e) {
+ if (exception == null)
+ exception = e;
+ }
+
+ out = null;
+ }
+
+ if (exception != null)
+ throw exception;
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/UnsupportedOptionsException.java b/lzma/Java/Tukaani/src/org/tukaani/xz/UnsupportedOptionsException.java
new file mode 100644
index 0000000..9aa16e8
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/UnsupportedOptionsException.java
@@ -0,0 +1,34 @@
+/*
+ * UnsupportedOptionsException
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz;
+
+/**
+ * Thrown when compression options not supported by this implementation
+ * are detected. Some other implementation might support those options.
+ */
+public class UnsupportedOptionsException extends XZIOException {
+ private static final long serialVersionUID = 3L;
+
+ /**
+ * Creates a new UnsupportedOptionsException with null
+ * as its error detail message.
+ */
+ public UnsupportedOptionsException() {}
+
+ /**
+ * Creates a new UnsupportedOptionsException with the given
+ * error detail message.
+ *
+ * @param s error detail message
+ */
+ public UnsupportedOptionsException(String s) {
+ super(s);
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/X86Options.java b/lzma/Java/Tukaani/src/org/tukaani/xz/X86Options.java
new file mode 100644
index 0000000..e6d241f
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/X86Options.java
@@ -0,0 +1,36 @@
+/*
+ * X86Options
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz;
+
+import java.io.InputStream;
+import org.tukaani.xz.simple.X86;
+
+/**
+ * BCJ filter for x86 (32-bit and 64-bit) instructions.
+ */
+public class X86Options extends BCJOptions {
+ private static final int ALIGNMENT = 1;
+
+ public X86Options() {
+ super(ALIGNMENT);
+ }
+
+ public FinishableOutputStream getOutputStream(FinishableOutputStream out) {
+ return new SimpleOutputStream(out, new X86(true, startOffset));
+ }
+
+ public InputStream getInputStream(InputStream in) {
+ return new SimpleInputStream(in, new X86(false, startOffset));
+ }
+
+ FilterEncoder getFilterEncoder() {
+ return new BCJEncoder(this, BCJCoder.X86_FILTER_ID);
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/XZ.java b/lzma/Java/Tukaani/src/org/tukaani/xz/XZ.java
new file mode 100644
index 0000000..4e0857f
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/XZ.java
@@ -0,0 +1,53 @@
+/*
+ * XZ
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz;
+
+/**
+ * XZ constants.
+ */
+public class XZ {
+ /**
+ * XZ Header Magic Bytes begin a XZ file.
+ * This can be useful to detect XZ compressed data.
+ */
+ public static final byte[] HEADER_MAGIC = {
+ (byte)0xFD, '7', 'z', 'X', 'Z', '\0' };
+
+ /**
+ * XZ Footer Magic Bytes are the last bytes of a XZ Stream.
+ */
+ public static final byte[] FOOTER_MAGIC = { 'Y', 'Z' };
+
+ /**
+ * Integrity check ID indicating that no integrity check is calculated.
+ * <p>
+ * Omitting the integrity check is strongly discouraged except when
+ * the integrity of the data will be verified by other means anyway,
+ * and calculating the check twice would be useless.
+ */
+ public static final int CHECK_NONE = 0;
+
+ /**
+ * Integrity check ID for CRC32.
+ */
+ public static final int CHECK_CRC32 = 1;
+
+ /**
+ * Integrity check ID for CRC64.
+ */
+ public static final int CHECK_CRC64 = 4;
+
+ /**
+ * Integrity check ID for SHA-256.
+ */
+ public static final int CHECK_SHA256 = 10;
+
+ private XZ() {}
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/XZFormatException.java b/lzma/Java/Tukaani/src/org/tukaani/xz/XZFormatException.java
new file mode 100644
index 0000000..6f63020
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/XZFormatException.java
@@ -0,0 +1,24 @@
+/*
+ * XZFormatException
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz;
+
+/**
+ * Thrown when the input data is not in the XZ format.
+ */
+public class XZFormatException extends XZIOException {
+ private static final long serialVersionUID = 3L;
+
+ /**
+ * Creates a new exception with the default error detail message.
+ */
+ public XZFormatException() {
+ super("Input is not in the XZ format");
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/XZIOException.java b/lzma/Java/Tukaani/src/org/tukaani/xz/XZIOException.java
new file mode 100644
index 0000000..14675f5
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/XZIOException.java
@@ -0,0 +1,27 @@
+/*
+ * XZIOException
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz;
+
+/**
+ * Generic {@link java.io.IOException IOException} specific to this package.
+ * The other IOExceptions in this package extend
+ * from <code>XZIOException</code>.
+ */
+public class XZIOException extends java.io.IOException {
+ private static final long serialVersionUID = 3L;
+
+ public XZIOException() {
+ super();
+ }
+
+ public XZIOException(String s) {
+ super(s);
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/XZInputStream.java b/lzma/Java/Tukaani/src/org/tukaani/xz/XZInputStream.java
new file mode 100644
index 0000000..0d460ea
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/XZInputStream.java
@@ -0,0 +1,371 @@
+/*
+ * XZInputStream
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz;
+
+import java.io.InputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.EOFException;
+import org.tukaani.xz.common.DecoderUtil;
+
+/**
+ * Decompresses a .xz file in streamed mode (no seeking).
+ * <p>
+ * Use this to decompress regular standalone .xz files. This reads from
+ * its input stream until the end of the input or until an error occurs.
+ * This supports decompressing concatenated .xz files.
+ *
+ * <h4>Typical use cases</h4>
+ * <p>
+ * Getting an input stream to decompress a .xz file:
+ * <p><blockquote><pre>
+ * InputStream infile = new FileInputStream("foo.xz");
+ * XZInputStream inxz = new XZInputStream(infile);
+ * </pre></blockquote>
+ * <p>
+ * It's important to keep in mind that decompressor memory usage depends
+ * on the settings used to compress the file. The worst-case memory usage
+ * of XZInputStream is currently 1.5 GiB. Still, very few files will
+ * require more than about 65 MiB because that's how much decompressing
+ * a file created with the highest preset level will need, and only a few
+ * people use settings other than the predefined presets.
+ * <p>
+ * It is possible to specify a memory usage limit for
+ * <code>XZInputStream</code>. If decompression requires more memory than
+ * the specified limit, MemoryLimitException will be thrown when reading
+ * from the stream. For example, the following sets the memory usage limit
+ * to 100 MiB:
+ * <p><blockquote><pre>
+ * InputStream infile = new FileInputStream("foo.xz");
+ * XZInputStream inxz = new XZInputStream(infile, 100 * 1024);
+ * </pre></blockquote>
+ *
+ * <h4>When uncompressed size is known beforehand</h4>
+ * <p>
+ * If you are decompressing complete files and your application knows
+ * exactly how much uncompressed data there should be, it is good to try
+ * reading one more byte by calling <code>read()</code> and checking
+ * that it returns <code>-1</code>. This way the decompressor will parse the
+ * file footers and verify the integrity checks, giving the caller more
+ * confidence that the uncompressed data is valid. (This advice seems to
+ * apply to
+ * {@link java.util.zip.GZIPInputStream java.util.zip.GZIPInputStream} too.)
+ *
+ * @see SingleXZInputStream
+ */
+public class XZInputStream extends InputStream {
+ private final int memoryLimit;
+ private InputStream in;
+ private SingleXZInputStream xzIn;
+ private final boolean verifyCheck;
+ private boolean endReached = false;
+ private IOException exception = null;
+
+ private final byte[] tempBuf = new byte[1];
+
+ /**
+ * Creates a new XZ decompressor without a memory usage limit.
+ * <p>
+ * This constructor reads and parses the XZ Stream Header (12 bytes)
+ * from <code>in</code>. The header of the first Block is not read
+ * until <code>read</code> is called.
+ *
+ * @param in input stream from which XZ-compressed
+ * data is read
+ *
+ * @throws XZFormatException
+ * input is not in the XZ format
+ *
+ * @throws CorruptedInputException
+ * XZ header CRC32 doesn't match
+ *
+ * @throws UnsupportedOptionsException
+ * XZ header is valid but specifies options
+ * not supported by this implementation
+ *
+ * @throws EOFException
+ * less than 12 bytes of input was available
+ * from <code>in</code>
+ *
+ * @throws IOException may be thrown by <code>in</code>
+ */
+ public XZInputStream(InputStream in) throws IOException {
+ this(in, -1);
+ }
+
+ /**
+ * Creates a new XZ decompressor with an optional memory usage limit.
+ * <p>
+ * This is identical to <code>XZInputStream(InputStream)</code> except
+ * that this takes also the <code>memoryLimit</code> argument.
+ *
+ * @param in input stream from which XZ-compressed
+ * data is read
+ *
+ * @param memoryLimit memory usage limit in kibibytes (KiB)
+ * or <code>-1</code> to impose no
+ * memory usage limit
+ *
+ * @throws XZFormatException
+ * input is not in the XZ format
+ *
+ * @throws CorruptedInputException
+ * XZ header CRC32 doesn't match
+ *
+ * @throws UnsupportedOptionsException
+ * XZ header is valid but specifies options
+ * not supported by this implementation
+ *
+ * @throws EOFException
+ * less than 12 bytes of input was available
+ * from <code>in</code>
+ *
+ * @throws IOException may be thrown by <code>in</code>
+ */
+ public XZInputStream(InputStream in, int memoryLimit) throws IOException {
+ this(in, memoryLimit, true);
+ }
+
+ /**
+ * Creates a new XZ decompressor with an optional memory usage limit
+ * and ability to disable verification of integrity checks.
+ * <p>
+ * This is identical to <code>XZInputStream(InputStream,int)</code> except
+ * that this takes also the <code>verifyCheck</code> argument.
+ * <p>
+ * Note that integrity check verification should almost never be disabled.
+ * Possible reasons to disable integrity check verification:
+ * <ul>
+ * <li>Trying to recover data from a corrupt .xz file.</li>
+ * <li>Speeding up decompression. This matters mostly with SHA-256
+ * or with files that have compressed extremely well. It's recommended
+ * that integrity checking isn't disabled for performance reasons
+ * unless the file integrity is verified externally in some other
+ * way.</li>
+ * </ul>
+ * <p>
+ * <code>verifyCheck</code> only affects the integrity check of
+ * the actual compressed data. The CRC32 fields in the headers
+ * are always verified.
+ *
+ * @param in input stream from which XZ-compressed
+ * data is read
+ *
+ * @param memoryLimit memory usage limit in kibibytes (KiB)
+ * or <code>-1</code> to impose no
+ * memory usage limit
+ *
+ * @param verifyCheck if <code>true</code>, the integrity checks
+ * will be verified; this should almost never
+ * be set to <code>false</code>
+ *
+ * @throws XZFormatException
+ * input is not in the XZ format
+ *
+ * @throws CorruptedInputException
+ * XZ header CRC32 doesn't match
+ *
+ * @throws UnsupportedOptionsException
+ * XZ header is valid but specifies options
+ * not supported by this implementation
+ *
+ * @throws EOFException
+ * less than 12 bytes of input was available
+ * from <code>in</code>
+ *
+ * @throws IOException may be thrown by <code>in</code>
+ *
+ * @since 1.6
+ */
+ public XZInputStream(InputStream in, int memoryLimit, boolean verifyCheck)
+ throws IOException {
+ this.in = in;
+ this.memoryLimit = memoryLimit;
+ this.verifyCheck = verifyCheck;
+ this.xzIn = new SingleXZInputStream(in, memoryLimit, verifyCheck);
+ }
+
+ /**
+ * Decompresses the next byte from this input stream.
+ * <p>
+ * Reading lots of data with <code>read()</code> from this input stream
+ * may be inefficient. Wrap it in {@link java.io.BufferedInputStream}
+ * if you need to read lots of data one byte at a time.
+ *
+ * @return the next decompressed byte, or <code>-1</code>
+ * to indicate the end of the compressed stream
+ *
+ * @throws CorruptedInputException
+ * @throws UnsupportedOptionsException
+ * @throws MemoryLimitException
+ *
+ * @throws XZIOException if the stream has been closed
+ *
+ * @throws EOFException
+ * compressed input is truncated or corrupt
+ *
+ * @throws IOException may be thrown by <code>in</code>
+ */
+ public int read() throws IOException {
+ return read(tempBuf, 0, 1) == -1 ? -1 : (tempBuf[0] & 0xFF);
+ }
+
+ /**
+ * Decompresses into an array of bytes.
+ * <p>
+ * If <code>len</code> is zero, no bytes are read and <code>0</code>
+ * is returned. Otherwise this will try to decompress <code>len</code>
+ * bytes of uncompressed data. Less than <code>len</code> bytes may
+ * be read only in the following situations:
+ * <ul>
+ * <li>The end of the compressed data was reached successfully.</li>
+ * <li>An error is detected after at least one but less <code>len</code>
+ * bytes have already been successfully decompressed.
+ * The next call with non-zero <code>len</code> will immediately
+ * throw the pending exception.</li>
+ * <li>An exception is thrown.</li>
+ * </ul>
+ *
+ * @param buf target buffer for uncompressed data
+ * @param off start offset in <code>buf</code>
+ * @param len maximum number of uncompressed bytes to read
+ *
+ * @return number of bytes read, or <code>-1</code> to indicate
+ * the end of the compressed stream
+ *
+ * @throws CorruptedInputException
+ * @throws UnsupportedOptionsException
+ * @throws MemoryLimitException
+ *
+ * @throws XZIOException if the stream has been closed
+ *
+ * @throws EOFException
+ * compressed input is truncated or corrupt
+ *
+ * @throws IOException may be thrown by <code>in</code>
+ */
+ public int read(byte[] buf, int off, int len) throws IOException {
+ if (off < 0 || len < 0 || off + len < 0 || off + len > buf.length)
+ throw new IndexOutOfBoundsException();
+
+ if (len == 0)
+ return 0;
+
+ if (in == null)
+ throw new XZIOException("Stream closed");
+
+ if (exception != null)
+ throw exception;
+
+ if (endReached)
+ return -1;
+
+ int size = 0;
+
+ try {
+ while (len > 0) {
+ if (xzIn == null) {
+ prepareNextStream();
+ if (endReached)
+ return size == 0 ? -1 : size;
+ }
+
+ int ret = xzIn.read(buf, off, len);
+
+ if (ret > 0) {
+ size += ret;
+ off += ret;
+ len -= ret;
+ } else if (ret == -1) {
+ xzIn = null;
+ }
+ }
+ } catch (IOException e) {
+ exception = e;
+ if (size == 0)
+ throw e;
+ }
+
+ return size;
+ }
+
+ private void prepareNextStream() throws IOException {
+ DataInputStream inData = new DataInputStream(in);
+ byte[] buf = new byte[DecoderUtil.STREAM_HEADER_SIZE];
+
+ // The size of Stream Padding must be a multiple of four bytes,
+ // all bytes zero.
+ do {
+ // First try to read one byte to see if we have reached the end
+ // of the file.
+ int ret = inData.read(buf, 0, 1);
+ if (ret == -1) {
+ endReached = true;
+ return;
+ }
+
+ // Since we got one byte of input, there must be at least
+ // three more available in a valid file.
+ inData.readFully(buf, 1, 3);
+
+ } while (buf[0] == 0 && buf[1] == 0 && buf[2] == 0 && buf[3] == 0);
+
+ // Not all bytes are zero. In a valid Stream it indicates the
+ // beginning of the next Stream. Read the rest of the Stream Header
+ // and initialize the XZ decoder.
+ inData.readFully(buf, 4, DecoderUtil.STREAM_HEADER_SIZE - 4);
+
+ try {
+ xzIn = new SingleXZInputStream(in, memoryLimit, verifyCheck, buf);
+ } catch (XZFormatException e) {
+ // Since this isn't the first .xz Stream, it is more
+ // logical to tell that the data is corrupt.
+ throw new CorruptedInputException(
+ "Garbage after a valid XZ Stream");
+ }
+ }
+
+ /**
+ * Returns the number of uncompressed bytes that can be read
+ * without blocking. The value is returned with an assumption
+ * that the compressed input data will be valid. If the compressed
+ * data is corrupt, <code>CorruptedInputException</code> may get
+ * thrown before the number of bytes claimed to be available have
+ * been read from this input stream.
+ *
+ * @return the number of uncompressed bytes that can be read
+ * without blocking
+ */
+ public int available() throws IOException {
+ if (in == null)
+ throw new XZIOException("Stream closed");
+
+ if (exception != null)
+ throw exception;
+
+ return xzIn == null ? 0 : xzIn.available();
+ }
+
+ /**
+ * Closes the stream and calls <code>in.close()</code>.
+ * If the stream was already closed, this does nothing.
+ *
+ * @throws IOException if thrown by <code>in.close()</code>
+ */
+ public void close() throws IOException {
+ if (in != null) {
+ try {
+ in.close();
+ } finally {
+ in = null;
+ }
+ }
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/XZOutputStream.java b/lzma/Java/Tukaani/src/org/tukaani/xz/XZOutputStream.java
new file mode 100644
index 0000000..6a37fed
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/XZOutputStream.java
@@ -0,0 +1,488 @@
+/*
+ * XZOutputStream
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz;
+
+import java.io.OutputStream;
+import java.io.IOException;
+import org.tukaani.xz.common.EncoderUtil;
+import org.tukaani.xz.common.StreamFlags;
+import org.tukaani.xz.check.Check;
+import org.tukaani.xz.index.IndexEncoder;
+
+/**
+ * Compresses into the .xz file format.
+ *
+ * <h4>Examples</h4>
+ * <p>
+ * Getting an output stream to compress with LZMA2 using the default
+ * settings and the default integrity check type (CRC64):
+ * <p><blockquote><pre>
+ * FileOutputStream outfile = new FileOutputStream("foo.xz");
+ * XZOutputStream outxz = new XZOutputStream(outfile, new LZMA2Options());
+ * </pre></blockquote>
+ * <p>
+ * Using the preset level <code>8</code> for LZMA2 (the default
+ * is <code>6</code>) and SHA-256 instead of CRC64 for integrity checking:
+ * <p><blockquote><pre>
+ * XZOutputStream outxz = new XZOutputStream(outfile, new LZMA2Options(8),
+ * XZ.CHECK_SHA256);
+ * </pre></blockquote>
+ * <p>
+ * Using the x86 BCJ filter together with LZMA2 to compress x86 executables
+ * and printing the memory usage information before creating the
+ * XZOutputStream:
+ * <p><blockquote><pre>
+ * X86Options x86 = new X86Options();
+ * LZMA2Options lzma2 = new LZMA2Options();
+ * FilterOptions[] options = { x86, lzma2 };
+ * System.out.println("Encoder memory usage: "
+ * + FilterOptions.getEncoderMemoryUsage(options)
+ * + " KiB");
+ * System.out.println("Decoder memory usage: "
+ * + FilterOptions.getDecoderMemoryUsage(options)
+ * + " KiB");
+ * XZOutputStream outxz = new XZOutputStream(outfile, options);
+ * </pre></blockquote>
+ */
+public class XZOutputStream extends FinishableOutputStream {
+ private OutputStream out;
+ private final StreamFlags streamFlags = new StreamFlags();
+ private final Check check;
+ private final IndexEncoder index = new IndexEncoder();
+
+ private BlockOutputStream blockEncoder = null;
+ private FilterEncoder[] filters;
+
+ /**
+ * True if the current filter chain supports flushing.
+ * If it doesn't support flushing, <code>flush()</code>
+ * will use <code>endBlock()</code> as a fallback.
+ */
+ private boolean filtersSupportFlushing;
+
+ private IOException exception = null;
+ private boolean finished = false;
+
+ private final byte[] tempBuf = new byte[1];
+
+ /**
+ * Creates a new XZ compressor using one filter and CRC64 as
+ * the integrity check. This constructor is equivalent to passing
+ * a single-member FilterOptions array to
+ * <code>XZOutputStream(OutputStream, FilterOptions[])</code>.
+ *
+ * @param out output stream to which the compressed data
+ * will be written
+ *
+ * @param filterOptions
+ * filter options to use
+ *
+ * @throws UnsupportedOptionsException
+ * invalid filter chain
+ *
+ * @throws IOException may be thrown from <code>out</code>
+ */
+ public XZOutputStream(OutputStream out, FilterOptions filterOptions)
+ throws IOException {
+ this(out, filterOptions, XZ.CHECK_CRC64);
+ }
+
+ /**
+ * Creates a new XZ compressor using one filter and the specified
+ * integrity check type. This constructor is equivalent to
+ * passing a single-member FilterOptions array to
+ * <code>XZOutputStream(OutputStream, FilterOptions[], int)</code>.
+ *
+ * @param out output stream to which the compressed data
+ * will be written
+ *
+ * @param filterOptions
+ * filter options to use
+ *
+ * @param checkType type of the integrity check,
+ * for example XZ.CHECK_CRC32
+ *
+ * @throws UnsupportedOptionsException
+ * invalid filter chain
+ *
+ * @throws IOException may be thrown from <code>out</code>
+ */
+ public XZOutputStream(OutputStream out, FilterOptions filterOptions,
+ int checkType) throws IOException {
+ this(out, new FilterOptions[] { filterOptions }, checkType);
+ }
+
+ /**
+ * Creates a new XZ compressor using 1-4 filters and CRC64 as
+ * the integrity check. This constructor is equivalent
+ * <code>XZOutputStream(out, filterOptions, XZ.CHECK_CRC64)</code>.
+ *
+ * @param out output stream to which the compressed data
+ * will be written
+ *
+ * @param filterOptions
+ * array of filter options to use
+ *
+ * @throws UnsupportedOptionsException
+ * invalid filter chain
+ *
+ * @throws IOException may be thrown from <code>out</code>
+ */
+ public XZOutputStream(OutputStream out, FilterOptions[] filterOptions)
+ throws IOException {
+ this(out, filterOptions, XZ.CHECK_CRC64);
+ }
+
+ /**
+ * Creates a new XZ compressor using 1-4 filters and the specified
+ * integrity check type.
+ *
+ * @param out output stream to which the compressed data
+ * will be written
+ *
+ * @param filterOptions
+ * array of filter options to use
+ *
+ * @param checkType type of the integrity check,
+ * for example XZ.CHECK_CRC32
+ *
+ * @throws UnsupportedOptionsException
+ * invalid filter chain
+ *
+ * @throws IOException may be thrown from <code>out</code>
+ */
+ public XZOutputStream(OutputStream out, FilterOptions[] filterOptions,
+ int checkType) throws IOException {
+ this.out = out;
+ updateFilters(filterOptions);
+
+ streamFlags.checkType = checkType;
+ check = Check.getInstance(checkType);
+
+ encodeStreamHeader();
+ }
+
+ /**
+ * Updates the filter chain with a single filter.
+ * This is equivalent to passing a single-member FilterOptions array
+ * to <code>updateFilters(FilterOptions[])</code>.
+ *
+ * @param filterOptions
+ * new filter to use
+ *
+ * @throws UnsupportedOptionsException
+ * unsupported filter chain, or trying to change
+ * the filter chain in the middle of a Block
+ */
+ public void updateFilters(FilterOptions filterOptions)
+ throws XZIOException {
+ FilterOptions[] opts = new FilterOptions[1];
+ opts[0] = filterOptions;
+ updateFilters(opts);
+ }
+
+ /**
+ * Updates the filter chain with 1-4 filters.
+ * <p>
+ * Currently this cannot be used to update e.g. LZMA2 options in the
+ * middle of a XZ Block. Use <code>endBlock()</code> to finish the
+ * current XZ Block before calling this function. The new filter chain
+ * will then be used for the next XZ Block.
+ *
+ * @param filterOptions
+ * new filter chain to use
+ *
+ * @throws UnsupportedOptionsException
+ * unsupported filter chain, or trying to change
+ * the filter chain in the middle of a Block
+ */
+ public void updateFilters(FilterOptions[] filterOptions)
+ throws XZIOException {
+ if (blockEncoder != null)
+ throw new UnsupportedOptionsException("Changing filter options "
+ + "in the middle of a XZ Block not implemented");
+
+ if (filterOptions.length < 1 || filterOptions.length > 4)
+ throw new UnsupportedOptionsException(
+ "XZ filter chain must be 1-4 filters");
+
+ filtersSupportFlushing = true;
+ FilterEncoder[] newFilters = new FilterEncoder[filterOptions.length];
+ for (int i = 0; i < filterOptions.length; ++i) {
+ newFilters[i] = filterOptions[i].getFilterEncoder();
+ filtersSupportFlushing &= newFilters[i].supportsFlushing();
+ }
+
+ RawCoder.validate(newFilters);
+ filters = newFilters;
+ }
+
+ /**
+ * Writes one byte to be compressed.
+ *
+ * @throws XZIOException
+ * XZ Stream has grown too big
+ *
+ * @throws XZIOException
+ * <code>finish()</code> or <code>close()</code>
+ * was already called
+ *
+ * @throws IOException may be thrown by the underlying output stream
+ */
+ public void write(int b) throws IOException {
+ tempBuf[0] = (byte)b;
+ write(tempBuf, 0, 1);
+ }
+
+ /**
+ * Writes an array of bytes to be compressed.
+ * The compressors tend to do internal buffering and thus the written
+ * data won't be readable from the compressed output immediately.
+ * Use <code>flush()</code> to force everything written so far to
+ * be written to the underlaying output stream, but be aware that
+ * flushing reduces compression ratio.
+ *
+ * @param buf buffer of bytes to be written
+ * @param off start offset in <code>buf</code>
+ * @param len number of bytes to write
+ *
+ * @throws XZIOException
+ * XZ Stream has grown too big: total file size
+ * about 8 EiB or the Index field exceeds
+ * 16 GiB; you shouldn't reach these sizes
+ * in practice
+ *
+ * @throws XZIOException
+ * <code>finish()</code> or <code>close()</code>
+ * was already called and len > 0
+ *
+ * @throws IOException may be thrown by the underlying output stream
+ */
+ public void write(byte[] buf, int off, int len) throws IOException {
+ if (off < 0 || len < 0 || off + len < 0 || off + len > buf.length)
+ throw new IndexOutOfBoundsException();
+
+ if (exception != null)
+ throw exception;
+
+ if (finished)
+ throw new XZIOException("Stream finished or closed");
+
+ try {
+ if (blockEncoder == null)
+ blockEncoder = new BlockOutputStream(out, filters, check);
+
+ blockEncoder.write(buf, off, len);
+ } catch (IOException e) {
+ exception = e;
+ throw e;
+ }
+ }
+
+ /**
+ * Finishes the current XZ Block (but not the whole XZ Stream).
+ * This doesn't flush the stream so it's possible that not all data will
+ * be decompressible from the output stream when this function returns.
+ * Call also <code>flush()</code> if flushing is wanted in addition to
+ * finishing the current XZ Block.
+ * <p>
+ * If there is no unfinished Block open, this function will do nothing.
+ * (No empty XZ Block will be created.)
+ * <p>
+ * This function can be useful, for example, to create
+ * random-accessible .xz files.
+ * <p>
+ * Starting a new XZ Block means that the encoder state is reset.
+ * Doing this very often will increase the size of the compressed
+ * file a lot (more than plain <code>flush()</code> would do).
+ *
+ * @throws XZIOException
+ * XZ Stream has grown too big
+ *
+ * @throws XZIOException
+ * stream finished or closed
+ *
+ * @throws IOException may be thrown by the underlying output stream
+ */
+ public void endBlock() throws IOException {
+ if (exception != null)
+ throw exception;
+
+ if (finished)
+ throw new XZIOException("Stream finished or closed");
+
+ // NOTE: Once there is threading with multiple Blocks, it's possible
+ // that this function will be more like a barrier that returns
+ // before the last Block has been finished.
+ if (blockEncoder != null) {
+ try {
+ blockEncoder.finish();
+ index.add(blockEncoder.getUnpaddedSize(),
+ blockEncoder.getUncompressedSize());
+ blockEncoder = null;
+ } catch (IOException e) {
+ exception = e;
+ throw e;
+ }
+ }
+ }
+
+ /**
+ * Flushes the encoder and calls <code>out.flush()</code>.
+ * All buffered pending data will then be decompressible from
+ * the output stream.
+ * <p>
+ * Calling this function very often may increase the compressed
+ * file size a lot. The filter chain options may affect the size
+ * increase too. For example, with LZMA2 the HC4 match finder has
+ * smaller penalty with flushing than BT4.
+ * <p>
+ * Some filters don't support flushing. If the filter chain has
+ * such a filter, <code>flush()</code> will call <code>endBlock()</code>
+ * before flushing.
+ *
+ * @throws XZIOException
+ * XZ Stream has grown too big
+ *
+ * @throws XZIOException
+ * stream finished or closed
+ *
+ * @throws IOException may be thrown by the underlying output stream
+ */
+ public void flush() throws IOException {
+ if (exception != null)
+ throw exception;
+
+ if (finished)
+ throw new XZIOException("Stream finished or closed");
+
+ try {
+ if (blockEncoder != null) {
+ if (filtersSupportFlushing) {
+ // This will eventually call out.flush() so
+ // no need to do it here again.
+ blockEncoder.flush();
+ } else {
+ endBlock();
+ out.flush();
+ }
+ } else {
+ out.flush();
+ }
+ } catch (IOException e) {
+ exception = e;
+ throw e;
+ }
+ }
+
+ /**
+ * Finishes compression without closing the underlying stream.
+ * No more data can be written to this stream after finishing
+ * (calling <code>write</code> with an empty buffer is OK).
+ * <p>
+ * Repeated calls to <code>finish()</code> do nothing unless
+ * an exception was thrown by this stream earlier. In that case
+ * the same exception is thrown again.
+ * <p>
+ * After finishing, the stream may be closed normally with
+ * <code>close()</code>. If the stream will be closed anyway, there
+ * usually is no need to call <code>finish()</code> separately.
+ *
+ * @throws XZIOException
+ * XZ Stream has grown too big
+ *
+ * @throws IOException may be thrown by the underlying output stream
+ */
+ public void finish() throws IOException {
+ if (!finished) {
+ // This checks for pending exceptions so we don't need to
+ // worry about it here.
+ endBlock();
+
+ try {
+ index.encode(out);
+ encodeStreamFooter();
+ } catch (IOException e) {
+ exception = e;
+ throw e;
+ }
+
+ // Set it to true only if everything goes fine. Setting it earlier
+ // would cause repeated calls to finish() do nothing instead of
+ // throwing an exception to indicate an earlier error.
+ finished = true;
+ }
+ }
+
+ /**
+ * Finishes compression and closes the underlying stream.
+ * The underlying stream <code>out</code> is closed even if finishing
+ * fails. If both finishing and closing fail, the exception thrown
+ * by <code>finish()</code> is thrown and the exception from the failed
+ * <code>out.close()</code> is lost.
+ *
+ * @throws XZIOException
+ * XZ Stream has grown too big
+ *
+ * @throws IOException may be thrown by the underlying output stream
+ */
+ public void close() throws IOException {
+ if (out != null) {
+ // If finish() throws an exception, it stores the exception to
+ // the variable "exception". So we can ignore the possible
+ // exception here.
+ try {
+ finish();
+ } catch (IOException e) {}
+
+ try {
+ out.close();
+ } catch (IOException e) {
+ // Remember the exception but only if there is no previous
+ // pending exception.
+ if (exception == null)
+ exception = e;
+ }
+
+ out = null;
+ }
+
+ if (exception != null)
+ throw exception;
+ }
+
+ private void encodeStreamFlags(byte[] buf, int off) {
+ buf[off] = 0x00;
+ buf[off + 1] = (byte)streamFlags.checkType;
+ }
+
+ private void encodeStreamHeader() throws IOException {
+ out.write(XZ.HEADER_MAGIC);
+
+ byte[] buf = new byte[2];
+ encodeStreamFlags(buf, 0);
+ out.write(buf);
+
+ EncoderUtil.writeCRC32(out, buf);
+ }
+
+ private void encodeStreamFooter() throws IOException {
+ byte[] buf = new byte[6];
+ long backwardSize = index.getIndexSize() / 4 - 1;
+ for (int i = 0; i < 4; ++i)
+ buf[i] = (byte)(backwardSize >>> (i * 8));
+
+ encodeStreamFlags(buf, 4);
+
+ EncoderUtil.writeCRC32(out, buf);
+ out.write(buf);
+ out.write(XZ.FOOTER_MAGIC);
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/check/CRC32.java b/lzma/Java/Tukaani/src/org/tukaani/xz/check/CRC32.java
new file mode 100644
index 0000000..f182898
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/check/CRC32.java
@@ -0,0 +1,33 @@
+/*
+ * CRC32
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz.check;
+
+public class CRC32 extends Check {
+ private final java.util.zip.CRC32 state = new java.util.zip.CRC32();
+
+ public CRC32() {
+ size = 4;
+ name = "CRC32";
+ }
+
+ public void update(byte[] buf, int off, int len) {
+ state.update(buf, off, len);
+ }
+
+ public byte[] finish() {
+ long value = state.getValue();
+ byte[] buf = { (byte)(value),
+ (byte)(value >>> 8),
+ (byte)(value >>> 16),
+ (byte)(value >>> 24) };
+ state.reset();
+ return buf;
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/check/CRC64.java b/lzma/Java/Tukaani/src/org/tukaani/xz/check/CRC64.java
new file mode 100644
index 0000000..02b15b7
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/check/CRC64.java
@@ -0,0 +1,54 @@
+/*
+ * CRC64
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz.check;
+
+public class CRC64 extends Check {
+ private static final long poly = 0xC96C5795D7870F42L;
+ private static final long[] crcTable = new long[256];
+
+ private long crc = -1;
+
+ static {
+ for (int b = 0; b < crcTable.length; ++b) {
+ long r = b;
+ for (int i = 0; i < 8; ++i) {
+ if ((r & 1) == 1)
+ r = (r >>> 1) ^ poly;
+ else
+ r >>>= 1;
+ }
+
+ crcTable[b] = r;
+ }
+ }
+
+ public CRC64() {
+ size = 8;
+ name = "CRC64";
+ }
+
+ public void update(byte[] buf, int off, int len) {
+ int end = off + len;
+
+ while (off < end)
+ crc = crcTable[(buf[off++] ^ (int)crc) & 0xFF] ^ (crc >>> 8);
+ }
+
+ public byte[] finish() {
+ long value = ~crc;
+ crc = -1;
+
+ byte[] buf = new byte[8];
+ for (int i = 0; i < buf.length; ++i)
+ buf[i] = (byte)(value >> (i * 8));
+
+ return buf;
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/check/Check.java b/lzma/Java/Tukaani/src/org/tukaani/xz/check/Check.java
new file mode 100644
index 0000000..02c011e
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/check/Check.java
@@ -0,0 +1,57 @@
+/*
+ * Check
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz.check;
+
+import org.tukaani.xz.XZ;
+import org.tukaani.xz.UnsupportedOptionsException;
+
+public abstract class Check {
+ int size;
+ String name;
+
+ public abstract void update(byte[] buf, int off, int len);
+ public abstract byte[] finish();
+
+ public void update(byte[] buf) {
+ update(buf, 0, buf.length);
+ }
+
+ public int getSize() {
+ return size;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public static Check getInstance(int checkType)
+ throws UnsupportedOptionsException {
+ switch (checkType) {
+ case XZ.CHECK_NONE:
+ return new None();
+
+ case XZ.CHECK_CRC32:
+ return new CRC32();
+
+ case XZ.CHECK_CRC64:
+ return new CRC64();
+
+ case XZ.CHECK_SHA256:
+ try {
+ return new SHA256();
+ } catch (java.security.NoSuchAlgorithmException e) {}
+
+ break;
+ }
+
+ throw new UnsupportedOptionsException(
+ "Unsupported Check ID " + checkType);
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/check/None.java b/lzma/Java/Tukaani/src/org/tukaani/xz/check/None.java
new file mode 100644
index 0000000..b07c8e6
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/check/None.java
@@ -0,0 +1,24 @@
+/*
+ * None
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz.check;
+
+public class None extends Check {
+ public None() {
+ size = 0;
+ name = "None";
+ }
+
+ public void update(byte[] buf, int off, int len) {}
+
+ public byte[] finish() {
+ byte[] empty = new byte[0];
+ return empty;
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/check/SHA256.java b/lzma/Java/Tukaani/src/org/tukaani/xz/check/SHA256.java
new file mode 100644
index 0000000..66503c7
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/check/SHA256.java
@@ -0,0 +1,30 @@
+/*
+ * SHA256
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz.check;
+
+public class SHA256 extends Check {
+ private final java.security.MessageDigest sha256;
+
+ public SHA256() throws java.security.NoSuchAlgorithmException {
+ size = 32;
+ name = "SHA-256";
+ sha256 = java.security.MessageDigest.getInstance("SHA-256");
+ }
+
+ public void update(byte[] buf, int off, int len) {
+ sha256.update(buf, off, len);
+ }
+
+ public byte[] finish() {
+ byte[] buf = sha256.digest();
+ sha256.reset();
+ return buf;
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/common/DecoderUtil.java b/lzma/Java/Tukaani/src/org/tukaani/xz/common/DecoderUtil.java
new file mode 100644
index 0000000..77ba441
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/common/DecoderUtil.java
@@ -0,0 +1,121 @@
+/*
+ * DecoderUtil
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz.common;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.EOFException;
+import java.util.zip.CRC32;
+import org.tukaani.xz.XZ;
+import org.tukaani.xz.XZFormatException;
+import org.tukaani.xz.CorruptedInputException;
+import org.tukaani.xz.UnsupportedOptionsException;
+
+public class DecoderUtil extends Util {
+ public static boolean isCRC32Valid(byte[] buf, int off, int len,
+ int ref_off) {
+ CRC32 crc32 = new CRC32();
+ crc32.update(buf, off, len);
+ long value = crc32.getValue();
+
+ for (int i = 0; i < 4; ++i)
+ if ((byte)(value >>> (i * 8)) != buf[ref_off + i])
+ return false;
+
+ return true;
+ }
+
+ public static StreamFlags decodeStreamHeader(byte[] buf)
+ throws IOException {
+ for (int i = 0; i < XZ.HEADER_MAGIC.length; ++i)
+ if (buf[i] != XZ.HEADER_MAGIC[i])
+ throw new XZFormatException();
+
+ if (!isCRC32Valid(buf, XZ.HEADER_MAGIC.length, 2,
+ XZ.HEADER_MAGIC.length + 2))
+ throw new CorruptedInputException("XZ Stream Header is corrupt");
+
+ try {
+ return decodeStreamFlags(buf, XZ.HEADER_MAGIC.length);
+ } catch (UnsupportedOptionsException e) {
+ throw new UnsupportedOptionsException(
+ "Unsupported options in XZ Stream Header");
+ }
+ }
+
+ public static StreamFlags decodeStreamFooter(byte[] buf)
+ throws IOException {
+ if (buf[10] != XZ.FOOTER_MAGIC[0] || buf[11] != XZ.FOOTER_MAGIC[1]) {
+ // NOTE: The exception could be XZFormatException too.
+ // It depends on the situation which one is better.
+ throw new CorruptedInputException("XZ Stream Footer is corrupt");
+ }
+
+ if (!isCRC32Valid(buf, 4, 6, 0))
+ throw new CorruptedInputException("XZ Stream Footer is corrupt");
+
+ StreamFlags streamFlags;
+ try {
+ streamFlags = decodeStreamFlags(buf, 8);
+ } catch (UnsupportedOptionsException e) {
+ throw new UnsupportedOptionsException(
+ "Unsupported options in XZ Stream Footer");
+ }
+
+ streamFlags.backwardSize = 0;
+ for (int i = 0; i < 4; ++i)
+ streamFlags.backwardSize |= (buf[i + 4] & 0xFF) << (i * 8);
+
+ streamFlags.backwardSize = (streamFlags.backwardSize + 1) * 4;
+
+ return streamFlags;
+ }
+
+ private static StreamFlags decodeStreamFlags(byte[] buf, int off)
+ throws UnsupportedOptionsException {
+ if (buf[off] != 0x00 || (buf[off + 1] & 0xFF) >= 0x10)
+ throw new UnsupportedOptionsException();
+
+ StreamFlags streamFlags = new StreamFlags();
+ streamFlags.checkType = buf[off + 1];
+
+ return streamFlags;
+ }
+
+ public static boolean areStreamFlagsEqual(StreamFlags a, StreamFlags b) {
+ // backwardSize is intentionally not compared.
+ return a.checkType == b.checkType;
+ }
+
+ public static long decodeVLI(InputStream in) throws IOException {
+ int b = in.read();
+ if (b == -1)
+ throw new EOFException();
+
+ long num = b & 0x7F;
+ int i = 0;
+
+ while ((b & 0x80) != 0x00) {
+ if (++i >= VLI_SIZE_MAX)
+ throw new CorruptedInputException();
+
+ b = in.read();
+ if (b == -1)
+ throw new EOFException();
+
+ if (b == 0x00)
+ throw new CorruptedInputException();
+
+ num |= (long)(b & 0x7F) << (i * 7);
+ }
+
+ return num;
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/common/EncoderUtil.java b/lzma/Java/Tukaani/src/org/tukaani/xz/common/EncoderUtil.java
new file mode 100644
index 0000000..57f688b
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/common/EncoderUtil.java
@@ -0,0 +1,36 @@
+/*
+ * EncoderUtil
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz.common;
+
+import java.io.OutputStream;
+import java.io.IOException;
+import java.util.zip.CRC32;
+
+public class EncoderUtil extends Util {
+ public static void writeCRC32(OutputStream out, byte[] buf)
+ throws IOException {
+ CRC32 crc32 = new CRC32();
+ crc32.update(buf);
+ long value = crc32.getValue();
+
+ for (int i = 0; i < 4; ++i)
+ out.write((byte)(value >>> (i * 8)));
+ }
+
+ public static void encodeVLI(OutputStream out, long num)
+ throws IOException {
+ while (num >= 0x80) {
+ out.write((byte)(num | 0x80));
+ num >>>= 7;
+ }
+
+ out.write((byte)num);
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/common/StreamFlags.java b/lzma/Java/Tukaani/src/org/tukaani/xz/common/StreamFlags.java
new file mode 100644
index 0000000..b306987
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/common/StreamFlags.java
@@ -0,0 +1,15 @@
+/*
+ * StreamFlags
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz.common;
+
+public class StreamFlags {
+ public int checkType = -1;
+ public long backwardSize = -1;
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/common/Util.java b/lzma/Java/Tukaani/src/org/tukaani/xz/common/Util.java
new file mode 100644
index 0000000..c4324ce
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/common/Util.java
@@ -0,0 +1,28 @@
+/*
+ * Util
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz.common;
+
+public class Util {
+ public static final int STREAM_HEADER_SIZE = 12;
+ public static final long BACKWARD_SIZE_MAX = 1L << 34;
+ public static final int BLOCK_HEADER_SIZE_MAX = 1024;
+ public static final long VLI_MAX = Long.MAX_VALUE;
+ public static final int VLI_SIZE_MAX = 9;
+
+ public static int getVLISize(long num) {
+ int size = 0;
+ do {
+ ++size;
+ num >>= 7;
+ } while (num != 0);
+
+ return size;
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/delta/DeltaCoder.java b/lzma/Java/Tukaani/src/org/tukaani/xz/delta/DeltaCoder.java
new file mode 100644
index 0000000..d94eb66
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/delta/DeltaCoder.java
@@ -0,0 +1,27 @@
+/*
+ * DeltaCoder
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz.delta;
+
+abstract class DeltaCoder {
+ static final int DISTANCE_MIN = 1;
+ static final int DISTANCE_MAX = 256;
+ static final int DISTANCE_MASK = DISTANCE_MAX - 1;
+
+ final int distance;
+ final byte[] history = new byte[DISTANCE_MAX];
+ int pos = 0;
+
+ DeltaCoder(int distance) {
+ if (distance < DISTANCE_MIN || distance > DISTANCE_MAX)
+ throw new IllegalArgumentException();
+
+ this.distance = distance;
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/delta/DeltaDecoder.java b/lzma/Java/Tukaani/src/org/tukaani/xz/delta/DeltaDecoder.java
new file mode 100644
index 0000000..154cbf3
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/delta/DeltaDecoder.java
@@ -0,0 +1,24 @@
+/*
+ * DeltaDecoder
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz.delta;
+
+public class DeltaDecoder extends DeltaCoder {
+ public DeltaDecoder(int distance) {
+ super(distance);
+ }
+
+ public void decode(byte[] buf, int off, int len) {
+ int end = off + len;
+ for (int i = off; i < end; ++i) {
+ buf[i] += history[(distance + pos) & DISTANCE_MASK];
+ history[pos-- & DISTANCE_MASK] = buf[i];
+ }
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/delta/DeltaEncoder.java b/lzma/Java/Tukaani/src/org/tukaani/xz/delta/DeltaEncoder.java
new file mode 100644
index 0000000..17accce
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/delta/DeltaEncoder.java
@@ -0,0 +1,24 @@
+/*
+ * DeltaEncoder
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz.delta;
+
+public class DeltaEncoder extends DeltaCoder {
+ public DeltaEncoder(int distance) {
+ super(distance);
+ }
+
+ public void encode(byte[] in, int in_off, int len, byte[] out) {
+ for (int i = 0; i < len; ++i) {
+ byte tmp = history[(distance + pos) & DISTANCE_MASK];
+ history[pos-- & DISTANCE_MASK] = in[in_off + i];
+ out[i] = (byte)(in[in_off + i] - tmp);
+ }
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/index/BlockInfo.java b/lzma/Java/Tukaani/src/org/tukaani/xz/index/BlockInfo.java
new file mode 100644
index 0000000..babae7f
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/index/BlockInfo.java
@@ -0,0 +1,38 @@
+/*
+ * BlockInfo
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz.index;
+
+import org.tukaani.xz.common.StreamFlags;
+
+public class BlockInfo {
+ public int blockNumber = -1;
+ public long compressedOffset = -1;
+ public long uncompressedOffset = -1;
+ public long unpaddedSize = -1;
+ public long uncompressedSize = -1;
+
+ IndexDecoder index;
+
+ public BlockInfo(IndexDecoder indexOfFirstStream) {
+ index = indexOfFirstStream;
+ }
+
+ public int getCheckType() {
+ return index.getStreamFlags().checkType;
+ }
+
+ public boolean hasNext() {
+ return index.hasRecord(blockNumber + 1);
+ }
+
+ public void setNext() {
+ index.setBlockInfo(this, blockNumber + 1);
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/index/IndexBase.java b/lzma/Java/Tukaani/src/org/tukaani/xz/index/IndexBase.java
new file mode 100644
index 0000000..e556105
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/index/IndexBase.java
@@ -0,0 +1,56 @@
+/*
+ * IndexBase
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz.index;
+
+import org.tukaani.xz.common.Util;
+import org.tukaani.xz.XZIOException;
+
+abstract class IndexBase {
+ private final XZIOException invalidIndexException;
+ long blocksSum = 0;
+ long uncompressedSum = 0;
+ long indexListSize = 0;
+ long recordCount = 0;
+
+ IndexBase(XZIOException invalidIndexException) {
+ this.invalidIndexException = invalidIndexException;
+ }
+
+ private long getUnpaddedIndexSize() {
+ // Index Indicator + Number of Records + List of Records + CRC32
+ return 1 + Util.getVLISize(recordCount) + indexListSize + 4;
+ }
+
+ public long getIndexSize() {
+ return (getUnpaddedIndexSize() + 3) & ~3;
+ }
+
+ public long getStreamSize() {
+ return Util.STREAM_HEADER_SIZE + blocksSum + getIndexSize()
+ + Util.STREAM_HEADER_SIZE;
+ }
+
+ int getIndexPaddingSize() {
+ return (int)((4 - getUnpaddedIndexSize()) & 3);
+ }
+
+ void add(long unpaddedSize, long uncompressedSize) throws XZIOException {
+ blocksSum += (unpaddedSize + 3) & ~3;
+ uncompressedSum += uncompressedSize;
+ indexListSize += Util.getVLISize(unpaddedSize)
+ + Util.getVLISize(uncompressedSize);
+ ++recordCount;
+
+ if (blocksSum < 0 || uncompressedSum < 0
+ || getIndexSize() > Util.BACKWARD_SIZE_MAX
+ || getStreamSize() < 0)
+ throw invalidIndexException;
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/index/IndexDecoder.java b/lzma/Java/Tukaani/src/org/tukaani/xz/index/IndexDecoder.java
new file mode 100644
index 0000000..a3ae986
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/index/IndexDecoder.java
@@ -0,0 +1,223 @@
+/*
+ * IndexDecoder
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz.index;
+
+import java.io.IOException;
+import java.io.EOFException;
+import java.util.zip.CheckedInputStream;
+import org.tukaani.xz.common.DecoderUtil;
+import org.tukaani.xz.common.StreamFlags;
+import org.tukaani.xz.SeekableInputStream;
+import org.tukaani.xz.CorruptedInputException;
+import org.tukaani.xz.MemoryLimitException;
+import org.tukaani.xz.UnsupportedOptionsException;
+
+public class IndexDecoder extends IndexBase {
+ private final StreamFlags streamFlags;
+ private final long streamPadding;
+ private final int memoryUsage;
+
+ // Unpadded Size and Uncompressed Size fields
+ private final long[] unpadded;
+ private final long[] uncompressed;
+
+ // Uncompressed size of the largest Block. It is used by
+ // SeekableXZInputStream to find out the largest Block of the .xz file.
+ private long largestBlockSize = 0;
+
+ // Offsets relative to the beginning of the .xz file. These are all zero
+ // for the first Stream in the file.
+ private int recordOffset = 0;
+ private long compressedOffset = 0;
+ private long uncompressedOffset = 0;
+
+ public IndexDecoder(SeekableInputStream in, StreamFlags streamFooterFlags,
+ long streamPadding, int memoryLimit)
+ throws IOException {
+ super(new CorruptedInputException("XZ Index is corrupt"));
+ this.streamFlags = streamFooterFlags;
+ this.streamPadding = streamPadding;
+
+ // If endPos is exceeded before the CRC32 field has been decoded,
+ // the Index is corrupt.
+ long endPos = in.position() + streamFooterFlags.backwardSize - 4;
+
+ java.util.zip.CRC32 crc32 = new java.util.zip.CRC32();
+ CheckedInputStream inChecked = new CheckedInputStream(in, crc32);
+
+ // Index Indicator
+ if (inChecked.read() != 0x00)
+ throw new CorruptedInputException("XZ Index is corrupt");
+
+ try {
+ // Number of Records
+ long count = DecoderUtil.decodeVLI(inChecked);
+
+ // Catch Record counts that obviously too high to be valid.
+ // This test isn't exact because it ignores Index Indicator,
+ // Number of Records, and CRC32 fields, but this is good enough
+ // to catch the most obvious problems.
+ if (count >= streamFooterFlags.backwardSize / 2)
+ throw new CorruptedInputException("XZ Index is corrupt");
+
+ // If the Record count doesn't fit into an int, we cannot
+ // allocate the arrays to hold the Records.
+ if (count > Integer.MAX_VALUE)
+ throw new UnsupportedOptionsException("XZ Index has over "
+ + Integer.MAX_VALUE + " Records");
+
+ // Calculate approximate memory requirements and check the
+ // memory usage limit.
+ memoryUsage = 1 + (int)((16L * count + 1023) / 1024);
+ if (memoryLimit >= 0 && memoryUsage > memoryLimit)
+ throw new MemoryLimitException(memoryUsage, memoryLimit);
+
+ // Allocate the arrays for the Records.
+ unpadded = new long[(int)count];
+ uncompressed = new long[(int)count];
+ int record = 0;
+
+ // Decode the Records.
+ for (int i = (int)count; i > 0; --i) {
+ // Get the next Record.
+ long unpaddedSize = DecoderUtil.decodeVLI(inChecked);
+ long uncompressedSize = DecoderUtil.decodeVLI(inChecked);
+
+ // Check that the input position stays sane. Since this is
+ // checked only once per loop iteration instead of for
+ // every input byte read, it's still possible that
+ // EOFException gets thrown with corrupt input.
+ if (in.position() > endPos)
+ throw new CorruptedInputException("XZ Index is corrupt");
+
+ // Add the new Record.
+ unpadded[record] = blocksSum + unpaddedSize;
+ uncompressed[record] = uncompressedSum + uncompressedSize;
+ ++record;
+ super.add(unpaddedSize, uncompressedSize);
+ assert record == recordCount;
+
+ // Remember the uncompressed size of the largest Block.
+ if (largestBlockSize < uncompressedSize)
+ largestBlockSize = uncompressedSize;
+ }
+ } catch (EOFException e) {
+ // EOFException is caught just in case a corrupt input causes
+ // DecoderUtil.decodeVLI to read too much at once.
+ throw new CorruptedInputException("XZ Index is corrupt");
+ }
+
+ // Validate that the size of the Index field matches
+ // Backward Size.
+ int indexPaddingSize = getIndexPaddingSize();
+ if (in.position() + indexPaddingSize != endPos)
+ throw new CorruptedInputException("XZ Index is corrupt");
+
+ // Index Padding
+ while (indexPaddingSize-- > 0)
+ if (inChecked.read() != 0x00)
+ throw new CorruptedInputException("XZ Index is corrupt");
+
+ // CRC32
+ long value = crc32.getValue();
+ for (int i = 0; i < 4; ++i)
+ if (((value >>> (i * 8)) & 0xFF) != in.read())
+ throw new CorruptedInputException("XZ Index is corrupt");
+ }
+
+ public void setOffsets(IndexDecoder prev) {
+ // NOTE: SeekableXZInputStream checks that the total number of Blocks
+ // in concatenated Streams fits into an int.
+ recordOffset = prev.recordOffset + (int)prev.recordCount;
+ compressedOffset = prev.compressedOffset
+ + prev.getStreamSize() + prev.streamPadding;
+ assert (compressedOffset & 3) == 0;
+ uncompressedOffset = prev.uncompressedOffset + prev.uncompressedSum;
+ }
+
+ public int getMemoryUsage() {
+ return memoryUsage;
+ }
+
+ public StreamFlags getStreamFlags() {
+ return streamFlags;
+ }
+
+ public int getRecordCount() {
+ // It was already checked in the constructor that it fits into an int.
+ // Otherwise we couldn't have allocated the arrays.
+ return (int)recordCount;
+ }
+
+ public long getUncompressedSize() {
+ return uncompressedSum;
+ }
+
+ public long getLargestBlockSize() {
+ return largestBlockSize;
+ }
+
+ public boolean hasUncompressedOffset(long pos) {
+ return pos >= uncompressedOffset
+ && pos < uncompressedOffset + uncompressedSum;
+ }
+
+ public boolean hasRecord(int blockNumber) {
+ return blockNumber >= recordOffset
+ && blockNumber < recordOffset + recordCount;
+ }
+
+ public void locateBlock(BlockInfo info, long target) {
+ assert target >= uncompressedOffset;
+ target -= uncompressedOffset;
+ assert target < uncompressedSum;
+
+ int left = 0;
+ int right = unpadded.length - 1;
+
+ while (left < right) {
+ int i = left + (right - left) / 2;
+
+ if (uncompressed[i] <= target)
+ left = i + 1;
+ else
+ right = i;
+ }
+
+ setBlockInfo(info, recordOffset + left);
+ }
+
+ public void setBlockInfo(BlockInfo info, int blockNumber) {
+ // The caller has checked that the given Block number is inside
+ // this Index.
+ assert blockNumber >= recordOffset;
+ assert blockNumber - recordOffset < recordCount;
+
+ info.index = this;
+ info.blockNumber = blockNumber;
+
+ int pos = blockNumber - recordOffset;
+
+ if (pos == 0) {
+ info.compressedOffset = 0;
+ info.uncompressedOffset = 0;
+ } else {
+ info.compressedOffset = (unpadded[pos - 1] + 3) & ~3;
+ info.uncompressedOffset = uncompressed[pos - 1];
+ }
+
+ info.unpaddedSize = unpadded[pos] - info.compressedOffset;
+ info.uncompressedSize = uncompressed[pos] - info.uncompressedOffset;
+
+ info.compressedOffset += compressedOffset
+ + DecoderUtil.STREAM_HEADER_SIZE;
+ info.uncompressedOffset += uncompressedOffset;
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/index/IndexEncoder.java b/lzma/Java/Tukaani/src/org/tukaani/xz/index/IndexEncoder.java
new file mode 100644
index 0000000..9db40d1
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/index/IndexEncoder.java
@@ -0,0 +1,59 @@
+/*
+ * IndexEncoder
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz.index;
+
+import java.io.OutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.zip.CheckedOutputStream;
+import org.tukaani.xz.common.EncoderUtil;
+import org.tukaani.xz.XZIOException;
+
+public class IndexEncoder extends IndexBase {
+ private final ArrayList records = new ArrayList();
+
+ public IndexEncoder() {
+ super(new XZIOException("XZ Stream or its Index has grown too big"));
+ }
+
+ public void add(long unpaddedSize, long uncompressedSize)
+ throws XZIOException {
+ super.add(unpaddedSize, uncompressedSize);
+ records.add(new IndexRecord(unpaddedSize, uncompressedSize));
+ }
+
+ public void encode(OutputStream out) throws IOException {
+ java.util.zip.CRC32 crc32 = new java.util.zip.CRC32();
+ CheckedOutputStream outChecked = new CheckedOutputStream(out, crc32);
+
+ // Index Indicator
+ outChecked.write(0x00);
+
+ // Number of Records
+ EncoderUtil.encodeVLI(outChecked, recordCount);
+
+ // List of Records
+ for (Iterator i = records.iterator(); i.hasNext(); ) {
+ IndexRecord record = (IndexRecord)i.next();
+ EncoderUtil.encodeVLI(outChecked, record.unpadded);
+ EncoderUtil.encodeVLI(outChecked, record.uncompressed);
+ }
+
+ // Index Padding
+ for (int i = getIndexPaddingSize(); i > 0; --i)
+ outChecked.write(0x00);
+
+ // CRC32
+ long value = crc32.getValue();
+ for (int i = 0; i < 4; ++i)
+ out.write((byte)(value >>> (i * 8)));
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/index/IndexHash.java b/lzma/Java/Tukaani/src/org/tukaani/xz/index/IndexHash.java
new file mode 100644
index 0000000..ab168c6
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/index/IndexHash.java
@@ -0,0 +1,94 @@
+/*
+ * IndexHash
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz.index;
+
+import java.io.InputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.zip.CheckedInputStream;
+import org.tukaani.xz.common.DecoderUtil;
+import org.tukaani.xz.XZIOException;
+import org.tukaani.xz.CorruptedInputException;
+
+public class IndexHash extends IndexBase {
+ private org.tukaani.xz.check.Check hash;
+
+ public IndexHash() {
+ super(new CorruptedInputException());
+
+ try {
+ hash = new org.tukaani.xz.check.SHA256();
+ } catch (java.security.NoSuchAlgorithmException e) {
+ hash = new org.tukaani.xz.check.CRC32();
+ }
+ }
+
+ public void add(long unpaddedSize, long uncompressedSize)
+ throws XZIOException {
+ super.add(unpaddedSize, uncompressedSize);
+
+ ByteBuffer buf = ByteBuffer.allocate(2 * 8);
+ buf.putLong(unpaddedSize);
+ buf.putLong(uncompressedSize);
+ hash.update(buf.array());
+ }
+
+ public void validate(InputStream in) throws IOException {
+ // Index Indicator (0x00) has already been read by BlockInputStream
+ // so add 0x00 to the CRC32 here.
+ java.util.zip.CRC32 crc32 = new java.util.zip.CRC32();
+ crc32.update('\0');
+ CheckedInputStream inChecked = new CheckedInputStream(in, crc32);
+
+ // Get and validate the Number of Records field.
+ long storedRecordCount = DecoderUtil.decodeVLI(inChecked);
+ if (storedRecordCount != recordCount)
+ throw new CorruptedInputException("XZ Index is corrupt");
+
+ // Decode and hash the Index field and compare it to
+ // the hash value calculated from the decoded Blocks.
+ IndexHash stored = new IndexHash();
+ for (long i = 0; i < recordCount; ++i) {
+ long unpaddedSize = DecoderUtil.decodeVLI(inChecked);
+ long uncompressedSize = DecoderUtil.decodeVLI(inChecked);
+
+ try {
+ stored.add(unpaddedSize, uncompressedSize);
+ } catch (XZIOException e) {
+ throw new CorruptedInputException("XZ Index is corrupt");
+ }
+
+ if (stored.blocksSum > blocksSum
+ || stored.uncompressedSum > uncompressedSum
+ || stored.indexListSize > indexListSize)
+ throw new CorruptedInputException("XZ Index is corrupt");
+ }
+
+ if (stored.blocksSum != blocksSum
+ || stored.uncompressedSum != uncompressedSum
+ || stored.indexListSize != indexListSize
+ || !Arrays.equals(stored.hash.finish(), hash.finish()))
+ throw new CorruptedInputException("XZ Index is corrupt");
+
+ // Index Padding
+ DataInputStream inData = new DataInputStream(inChecked);
+ for (int i = getIndexPaddingSize(); i > 0; --i)
+ if (inData.readUnsignedByte() != 0x00)
+ throw new CorruptedInputException("XZ Index is corrupt");
+
+ // CRC32
+ long value = crc32.getValue();
+ for (int i = 0; i < 4; ++i)
+ if (((value >>> (i * 8)) & 0xFF) != inData.readUnsignedByte())
+ throw new CorruptedInputException("XZ Index is corrupt");
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/index/IndexRecord.java b/lzma/Java/Tukaani/src/org/tukaani/xz/index/IndexRecord.java
new file mode 100644
index 0000000..5f6ba0f
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/index/IndexRecord.java
@@ -0,0 +1,20 @@
+/*
+ * IndexRecord
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz.index;
+
+class IndexRecord {
+ final long unpadded;
+ final long uncompressed;
+
+ IndexRecord(long unpadded, long uncompressed) {
+ this.unpadded = unpadded;
+ this.uncompressed = uncompressed;
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/lz/BT4.java b/lzma/Java/Tukaani/src/org/tukaani/xz/lz/BT4.java
new file mode 100644
index 0000000..a73b666
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/lz/BT4.java
@@ -0,0 +1,255 @@
+/*
+ * Binary Tree match finder with 2-, 3-, and 4-byte hashing
+ *
+ * Authors: Lasse Collin <lasse.collin@tukaani.org>
+ * Igor Pavlov <http://7-zip.org/>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz.lz;
+
+final class BT4 extends LZEncoder {
+ private final Hash234 hash;
+ private final int[] tree;
+ private final Matches matches;
+ private final int depthLimit;
+
+ private final int cyclicSize;
+ private int cyclicPos = -1;
+ private int lzPos;
+
+ static int getMemoryUsage(int dictSize) {
+ return Hash234.getMemoryUsage(dictSize) + dictSize / (1024 / 8) + 10;
+ }
+
+ BT4(int dictSize, int beforeSizeMin, int readAheadMax,
+ int niceLen, int matchLenMax, int depthLimit) {
+ super(dictSize, beforeSizeMin, readAheadMax, niceLen, matchLenMax);
+
+ cyclicSize = dictSize + 1;
+ lzPos = cyclicSize;
+
+ hash = new Hash234(dictSize);
+ tree = new int[cyclicSize * 2];
+
+ // Substracting 1 because the shortest match that this match
+ // finder can find is 2 bytes, so there's no need to reserve
+ // space for one-byte matches.
+ matches = new Matches(niceLen - 1);
+
+ this.depthLimit = depthLimit > 0 ? depthLimit : 16 + niceLen / 2;
+ }
+
+ private int movePos() {
+ int avail = movePos(niceLen, 4);
+
+ if (avail != 0) {
+ if (++lzPos == Integer.MAX_VALUE) {
+ int normalizationOffset = Integer.MAX_VALUE - cyclicSize;
+ hash.normalize(normalizationOffset);
+ normalize(tree, normalizationOffset);
+ lzPos -= normalizationOffset;
+ }
+
+ if (++cyclicPos == cyclicSize)
+ cyclicPos = 0;
+ }
+
+ return avail;
+ }
+
+ public Matches getMatches() {
+ matches.count = 0;
+
+ int matchLenLimit = matchLenMax;
+ int niceLenLimit = niceLen;
+ int avail = movePos();
+
+ if (avail < matchLenLimit) {
+ if (avail == 0)
+ return matches;
+
+ matchLenLimit = avail;
+ if (niceLenLimit > avail)
+ niceLenLimit = avail;
+ }
+
+ hash.calcHashes(buf, readPos);
+ int delta2 = lzPos - hash.getHash2Pos();
+ int delta3 = lzPos - hash.getHash3Pos();
+ int currentMatch = hash.getHash4Pos();
+ hash.updateTables(lzPos);
+
+ int lenBest = 0;
+
+ // See if the hash from the first two bytes found a match.
+ // The hashing algorithm guarantees that if the first byte
+ // matches, also the second byte does, so there's no need to
+ // test the second byte.
+ if (delta2 < cyclicSize && buf[readPos - delta2] == buf[readPos]) {
+ lenBest = 2;
+ matches.len[0] = 2;
+ matches.dist[0] = delta2 - 1;
+ matches.count = 1;
+ }
+
+ // See if the hash from the first three bytes found a match that
+ // is different from the match possibly found by the two-byte hash.
+ // Also here the hashing algorithm guarantees that if the first byte
+ // matches, also the next two bytes do.
+ if (delta2 != delta3 && delta3 < cyclicSize
+ && buf[readPos - delta3] == buf[readPos]) {
+ lenBest = 3;
+ matches.dist[matches.count++] = delta3 - 1;
+ delta2 = delta3;
+ }
+
+ // If a match was found, see how long it is.
+ if (matches.count > 0) {
+ while (lenBest < matchLenLimit && buf[readPos + lenBest - delta2]
+ == buf[readPos + lenBest])
+ ++lenBest;
+
+ matches.len[matches.count - 1] = lenBest;
+
+ // Return if it is long enough (niceLen or reached the end of
+ // the dictionary).
+ if (lenBest >= niceLenLimit) {
+ skip(niceLenLimit, currentMatch);
+ return matches;
+ }
+ }
+
+ // Long enough match wasn't found so easily. Look for better matches
+ // from the binary tree.
+ if (lenBest < 3)
+ lenBest = 3;
+
+ int depth = depthLimit;
+
+ int ptr0 = (cyclicPos << 1) + 1;
+ int ptr1 = cyclicPos << 1;
+ int len0 = 0;
+ int len1 = 0;
+
+ while (true) {
+ int delta = lzPos - currentMatch;
+
+ // Return if the search depth limit has been reached or
+ // if the distance of the potential match exceeds the
+ // dictionary size.
+ if (depth-- == 0 || delta >= cyclicSize) {
+ tree[ptr0] = 0;
+ tree[ptr1] = 0;
+ return matches;
+ }
+
+ int pair = (cyclicPos - delta
+ + (delta > cyclicPos ? cyclicSize : 0)) << 1;
+ int len = Math.min(len0, len1);
+
+ if (buf[readPos + len - delta] == buf[readPos + len]) {
+ while (++len < matchLenLimit)
+ if (buf[readPos + len - delta] != buf[readPos + len])
+ break;
+
+ if (len > lenBest) {
+ lenBest = len;
+ matches.len[matches.count] = len;
+ matches.dist[matches.count] = delta - 1;
+ ++matches.count;
+
+ if (len >= niceLenLimit) {
+ tree[ptr1] = tree[pair];
+ tree[ptr0] = tree[pair + 1];
+ return matches;
+ }
+ }
+ }
+
+ if ((buf[readPos + len - delta] & 0xFF)
+ < (buf[readPos + len] & 0xFF)) {
+ tree[ptr1] = currentMatch;
+ ptr1 = pair + 1;
+ currentMatch = tree[ptr1];
+ len1 = len;
+ } else {
+ tree[ptr0] = currentMatch;
+ ptr0 = pair;
+ currentMatch = tree[ptr0];
+ len0 = len;
+ }
+ }
+ }
+
+ private void skip(int niceLenLimit, int currentMatch) {
+ int depth = depthLimit;
+
+ int ptr0 = (cyclicPos << 1) + 1;
+ int ptr1 = cyclicPos << 1;
+ int len0 = 0;
+ int len1 = 0;
+
+ while (true) {
+ int delta = lzPos - currentMatch;
+
+ if (depth-- == 0 || delta >= cyclicSize) {
+ tree[ptr0] = 0;
+ tree[ptr1] = 0;
+ return;
+ }
+
+ int pair = (cyclicPos - delta
+ + (delta > cyclicPos ? cyclicSize : 0)) << 1;
+ int len = Math.min(len0, len1);
+
+ if (buf[readPos + len - delta] == buf[readPos + len]) {
+ // No need to look for longer matches than niceLenLimit
+ // because we only are updating the tree, not returning
+ // matches found to the caller.
+ do {
+ if (++len == niceLenLimit) {
+ tree[ptr1] = tree[pair];
+ tree[ptr0] = tree[pair + 1];
+ return;
+ }
+ } while (buf[readPos + len - delta] == buf[readPos + len]);
+ }
+
+ if ((buf[readPos + len - delta] & 0xFF)
+ < (buf[readPos + len] & 0xFF)) {
+ tree[ptr1] = currentMatch;
+ ptr1 = pair + 1;
+ currentMatch = tree[ptr1];
+ len1 = len;
+ } else {
+ tree[ptr0] = currentMatch;
+ ptr0 = pair;
+ currentMatch = tree[ptr0];
+ len0 = len;
+ }
+ }
+ }
+
+ public void skip(int len) {
+ while (len-- > 0) {
+ int niceLenLimit = niceLen;
+ int avail = movePos();
+
+ if (avail < niceLenLimit) {
+ if (avail == 0)
+ continue;
+
+ niceLenLimit = avail;
+ }
+
+ hash.calcHashes(buf, readPos);
+ int currentMatch = hash.getHash4Pos();
+ hash.updateTables(lzPos);
+
+ skip(niceLenLimit, currentMatch);
+ }
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/lz/CRC32Hash.java b/lzma/Java/Tukaani/src/org/tukaani/xz/lz/CRC32Hash.java
new file mode 100644
index 0000000..2adfdbf
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/lz/CRC32Hash.java
@@ -0,0 +1,35 @@
+/*
+ * CRC32Hash
+ *
+ * Authors: Lasse Collin <lasse.collin@tukaani.org>
+ * Igor Pavlov <http://7-zip.org/>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz.lz;
+
+/**
+ * Provides a CRC32 table using the polynomial from IEEE 802.3.
+ */
+class CRC32Hash {
+ private static final int CRC32_POLY = 0xEDB88320;
+
+ 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) ^ CRC32_POLY;
+ else
+ r >>>= 1;
+ }
+
+ crcTable[i] = r;
+ }
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/lz/HC4.java b/lzma/Java/Tukaani/src/org/tukaani/xz/lz/HC4.java
new file mode 100644
index 0000000..0f49fd4
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/lz/HC4.java
@@ -0,0 +1,200 @@
+/*
+ * Hash Chain match finder with 2-, 3-, and 4-byte hashing
+ *
+ * Authors: Lasse Collin <lasse.collin@tukaani.org>
+ * Igor Pavlov <http://7-zip.org/>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz.lz;
+
+final class HC4 extends LZEncoder {
+ private final Hash234 hash;
+ private final int[] chain;
+ private final Matches matches;
+ private final int depthLimit;
+
+ private final int cyclicSize;
+ private int cyclicPos = -1;
+ private int lzPos;
+
+ /**
+ * Gets approximate memory usage of the match finder as kibibytes.
+ */
+ static int getMemoryUsage(int dictSize) {
+ return Hash234.getMemoryUsage(dictSize) + dictSize / (1024 / 4) + 10;
+ }
+
+ /**
+ * Creates a new LZEncoder with the HC4 match finder.
+ * See <code>LZEncoder.getInstance</code> for parameter descriptions.
+ */
+ HC4(int dictSize, int beforeSizeMin, int readAheadMax,
+ int niceLen, int matchLenMax, int depthLimit) {
+ super(dictSize, beforeSizeMin, readAheadMax, niceLen, matchLenMax);
+
+ hash = new Hash234(dictSize);
+
+ // +1 because we need dictSize bytes of history + the current byte.
+ cyclicSize = dictSize + 1;
+ chain = new int[cyclicSize];
+ lzPos = cyclicSize;
+
+ // Substracting 1 because the shortest match that this match
+ // finder can find is 2 bytes, so there's no need to reserve
+ // space for one-byte matches.
+ matches = new Matches(niceLen - 1);
+
+ // Use a default depth limit if no other value was specified.
+ // The default is just something based on experimentation;
+ // it's nothing magic.
+ this.depthLimit = (depthLimit > 0) ? depthLimit : 4 + niceLen / 4;
+ }
+
+ /**
+ * Moves to the next byte, checks that there is enough available space,
+ * and possibly normalizes the hash tables and the hash chain.
+ *
+ * @return number of bytes available, including the current byte
+ */
+ private int movePos() {
+ int avail = movePos(4, 4);
+
+ if (avail != 0) {
+ if (++lzPos == Integer.MAX_VALUE) {
+ int normalizationOffset = Integer.MAX_VALUE - cyclicSize;
+ hash.normalize(normalizationOffset);
+ normalize(chain, normalizationOffset);
+ lzPos -= normalizationOffset;
+ }
+
+ if (++cyclicPos == cyclicSize)
+ cyclicPos = 0;
+ }
+
+ return avail;
+ }
+
+ public Matches getMatches() {
+ matches.count = 0;
+ int matchLenLimit = matchLenMax;
+ int niceLenLimit = niceLen;
+ int avail = movePos();
+
+ if (avail < matchLenLimit) {
+ if (avail == 0)
+ return matches;
+
+ matchLenLimit = avail;
+ if (niceLenLimit > avail)
+ niceLenLimit = avail;
+ }
+
+ hash.calcHashes(buf, readPos);
+ int delta2 = lzPos - hash.getHash2Pos();
+ int delta3 = lzPos - hash.getHash3Pos();
+ int currentMatch = hash.getHash4Pos();
+ hash.updateTables(lzPos);
+
+ chain[cyclicPos] = currentMatch;
+
+ int lenBest = 0;
+
+ // See if the hash from the first two bytes found a match.
+ // The hashing algorithm guarantees that if the first byte
+ // matches, also the second byte does, so there's no need to
+ // test the second byte.
+ if (delta2 < cyclicSize && buf[readPos - delta2] == buf[readPos]) {
+ lenBest = 2;
+ matches.len[0] = 2;
+ matches.dist[0] = delta2 - 1;
+ matches.count = 1;
+ }
+
+ // See if the hash from the first three bytes found a match that
+ // is different from the match possibly found by the two-byte hash.
+ // Also here the hashing algorithm guarantees that if the first byte
+ // matches, also the next two bytes do.
+ if (delta2 != delta3 && delta3 < cyclicSize
+ && buf[readPos - delta3] == buf[readPos]) {
+ lenBest = 3;
+ matches.dist[matches.count++] = delta3 - 1;
+ delta2 = delta3;
+ }
+
+ // If a match was found, see how long it is.
+ if (matches.count > 0) {
+ while (lenBest < matchLenLimit && buf[readPos + lenBest - delta2]
+ == buf[readPos + lenBest])
+ ++lenBest;
+
+ matches.len[matches.count - 1] = lenBest;
+
+ // Return if it is long enough (niceLen or reached the end of
+ // the dictionary).
+ if (lenBest >= niceLenLimit)
+ return matches;
+ }
+
+ // Long enough match wasn't found so easily. Look for better matches
+ // from the hash chain.
+ if (lenBest < 3)
+ lenBest = 3;
+
+ int depth = depthLimit;
+
+ while (true) {
+ int delta = lzPos - currentMatch;
+
+ // Return if the search depth limit has been reached or
+ // if the distance of the potential match exceeds the
+ // dictionary size.
+ if (depth-- == 0 || delta >= cyclicSize)
+ return matches;
+
+ currentMatch = chain[cyclicPos - delta
+ + (delta > cyclicPos ? cyclicSize : 0)];
+
+ // Test the first byte and the first new byte that would give us
+ // a match that is at least one byte longer than lenBest. This
+ // too short matches get quickly skipped.
+ if (buf[readPos + lenBest - delta] == buf[readPos + lenBest]
+ && buf[readPos - delta] == buf[readPos]) {
+ // Calculate the length of the match.
+ int len = 0;
+ while (++len < matchLenLimit)
+ if (buf[readPos + len - delta] != buf[readPos + len])
+ break;
+
+ // Use the match if and only if it is better than the longest
+ // match found so far.
+ if (len > lenBest) {
+ lenBest = len;
+ matches.len[matches.count] = len;
+ matches.dist[matches.count] = delta - 1;
+ ++matches.count;
+
+ // Return if it is long enough (niceLen or reached the
+ // end of the dictionary).
+ if (len >= niceLenLimit)
+ return matches;
+ }
+ }
+ }
+ }
+
+ public void skip(int len) {
+ assert len >= 0;
+
+ while (len-- > 0) {
+ if (movePos() != 0) {
+ // Update the hash chain and hash tables.
+ hash.calcHashes(buf, readPos);
+ chain[cyclicPos] = hash.getHash4Pos();
+ hash.updateTables(lzPos);
+ }
+ }
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/lz/Hash234.java b/lzma/Java/Tukaani/src/org/tukaani/xz/lz/Hash234.java
new file mode 100644
index 0000000..8253bc0
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/lz/Hash234.java
@@ -0,0 +1,89 @@
+/*
+ * 2-, 3-, and 4-byte hashing
+ *
+ * Authors: Lasse Collin <lasse.collin@tukaani.org>
+ * Igor Pavlov <http://7-zip.org/>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz.lz;
+
+final class Hash234 extends CRC32Hash {
+ private static final int HASH_2_SIZE = 1 << 10;
+ private static final int HASH_2_MASK = HASH_2_SIZE - 1;
+
+ private static final int HASH_3_SIZE = 1 << 16;
+ private static final int HASH_3_MASK = HASH_3_SIZE - 1;
+
+ private final int hash4Mask;
+
+ private final int[] hash2Table = new int[HASH_2_SIZE];
+ private final int[] hash3Table = new int[HASH_3_SIZE];
+ private final int[] hash4Table;
+
+ private int hash2Value = 0;
+ private int hash3Value = 0;
+ private int hash4Value = 0;
+
+ static int getHash4Size(int dictSize) {
+ int h = dictSize - 1;
+ h |= h >>> 1;
+ h |= h >>> 2;
+ h |= h >>> 4;
+ h |= h >>> 8;
+ h >>>= 1;
+ h |= 0xFFFF;
+ if (h > (1 << 24))
+ h >>>= 1;
+
+ return h + 1;
+ }
+
+ static int getMemoryUsage(int dictSize) {
+ // Sizes of the hash arrays + a little extra
+ return (HASH_2_SIZE + HASH_3_SIZE + getHash4Size(dictSize))
+ / (1024 / 4) + 4;
+ }
+
+ Hash234(int dictSize) {
+ hash4Table = new int[getHash4Size(dictSize)];
+ hash4Mask = hash4Table.length - 1;
+ }
+
+ void calcHashes(byte[] buf, int off) {
+ int temp = crcTable[buf[off] & 0xFF] ^ (buf[off + 1] & 0xFF);
+ hash2Value = temp & HASH_2_MASK;
+
+ temp ^= (buf[off + 2] & 0xFF) << 8;
+ hash3Value = temp & HASH_3_MASK;
+
+ temp ^= crcTable[buf[off + 3] & 0xFF] << 5;
+ hash4Value = temp & hash4Mask;
+ }
+
+ int getHash2Pos() {
+ return hash2Table[hash2Value];
+ }
+
+ int getHash3Pos() {
+ return hash3Table[hash3Value];
+ }
+
+ int getHash4Pos() {
+ return hash4Table[hash4Value];
+ }
+
+ void updateTables(int pos) {
+ hash2Table[hash2Value] = pos;
+ hash3Table[hash3Value] = pos;
+ hash4Table[hash4Value] = pos;
+ }
+
+ void normalize(int normalizeOffset) {
+ LZEncoder.normalize(hash2Table, normalizeOffset);
+ LZEncoder.normalize(hash3Table, normalizeOffset);
+ LZEncoder.normalize(hash4Table, normalizeOffset);
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/lz/LZDecoder.java b/lzma/Java/Tukaani/src/org/tukaani/xz/lz/LZDecoder.java
new file mode 100644
index 0000000..680fec1
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/lz/LZDecoder.java
@@ -0,0 +1,126 @@
+/*
+ * LZDecoder
+ *
+ * Authors: Lasse Collin <lasse.collin@tukaani.org>
+ * Igor Pavlov <http://7-zip.org/>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz.lz;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import org.tukaani.xz.CorruptedInputException;
+
+public final class LZDecoder {
+ private final byte[] buf;
+ private int start = 0;
+ private int pos = 0;
+ private int full = 0;
+ private int limit = 0;
+ private int pendingLen = 0;
+ private int pendingDist = 0;
+
+ public LZDecoder(int dictSize, byte[] presetDict) {
+ buf = new byte[dictSize];
+
+ if (presetDict != null) {
+ pos = Math.min(presetDict.length, dictSize);
+ full = pos;
+ start = pos;
+ System.arraycopy(presetDict, presetDict.length - pos, buf, 0, pos);
+ }
+ }
+
+ public void reset() {
+ start = 0;
+ pos = 0;
+ full = 0;
+ limit = 0;
+ buf[buf.length - 1] = 0x00;
+ }
+
+ public void setLimit(int outMax) {
+ if (buf.length - pos <= outMax)
+ limit = buf.length;
+ else
+ limit = pos + outMax;
+ }
+
+ public boolean hasSpace() {
+ return pos < limit;
+ }
+
+ public boolean hasPending() {
+ return pendingLen > 0;
+ }
+
+ public int getPos() {
+ return pos;
+ }
+
+ public int getByte(int dist) {
+ int offset = pos - dist - 1;
+ if (dist >= pos)
+ offset += buf.length;
+
+ return buf[offset] & 0xFF;
+ }
+
+ public void putByte(byte b) {
+ buf[pos++] = b;
+
+ if (full < pos)
+ full = pos;
+ }
+
+ public void repeat(int dist, int len) throws IOException {
+ if (dist < 0 || dist >= full)
+ throw new CorruptedInputException();
+
+ int left = Math.min(limit - pos, len);
+ pendingLen = len - left;
+ pendingDist = dist;
+
+ int back = pos - dist - 1;
+ if (dist >= pos)
+ back += buf.length;
+
+ do {
+ buf[pos++] = buf[back++];
+ if (back == buf.length)
+ back = 0;
+ } while (--left > 0);
+
+ if (full < pos)
+ full = pos;
+ }
+
+ public void repeatPending() throws IOException {
+ if (pendingLen > 0)
+ repeat(pendingDist, pendingLen);
+ }
+
+ public void copyUncompressed(DataInputStream inData, int len)
+ throws IOException {
+ int copySize = Math.min(buf.length - pos, len);
+ inData.readFully(buf, pos, copySize);
+ pos += copySize;
+
+ if (full < pos)
+ full = pos;
+ }
+
+ public int flush(byte[] out, int outOff) {
+ int copySize = pos - start;
+ if (pos == buf.length)
+ pos = 0;
+
+ System.arraycopy(buf, start, out, outOff, copySize);
+ start = pos;
+
+ return copySize;
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/lz/LZEncoder.java b/lzma/Java/Tukaani/src/org/tukaani/xz/lz/LZEncoder.java
new file mode 100644
index 0000000..267d7dd
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/lz/LZEncoder.java
@@ -0,0 +1,419 @@
+/*
+ * LZEncoder
+ *
+ * Authors: Lasse Collin <lasse.collin@tukaani.org>
+ * Igor Pavlov <http://7-zip.org/>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz.lz;
+
+import java.io.OutputStream;
+import java.io.IOException;
+
+public abstract class LZEncoder {
+ public static final int MF_HC4 = 0x04;
+ public static final int MF_BT4 = 0x14;
+
+ /**
+ * Number of bytes to keep available before the current byte
+ * when moving the LZ window.
+ */
+ private final int keepSizeBefore;
+
+ /**
+ * Number of bytes that must be available, the current byte included,
+ * to make hasEnoughData return true. Flushing and finishing are
+ * naturally exceptions to this since there cannot be any data after
+ * the end of the uncompressed input.
+ */
+ private final int keepSizeAfter;
+
+ final int matchLenMax;
+ final int niceLen;
+
+ final byte[] buf;
+
+ int readPos = -1;
+ private int readLimit = -1;
+ private boolean finishing = false;
+ private int writePos = 0;
+ private int pendingSize = 0;
+
+ static void normalize(int[] positions, int normalizationOffset) {
+ for (int i = 0; i < positions.length; ++i) {
+ if (positions[i] <= normalizationOffset)
+ positions[i] = 0;
+ else
+ positions[i] -= normalizationOffset;
+ }
+ }
+
+ /**
+ * Gets the size of the LZ window buffer that needs to be allocated.
+ */
+ private static int getBufSize(
+ int dictSize, int extraSizeBefore, int extraSizeAfter,
+ int matchLenMax) {
+ int keepSizeBefore = extraSizeBefore + dictSize;
+ int keepSizeAfter = extraSizeAfter + matchLenMax;
+ int reserveSize = Math.min(dictSize / 2 + (256 << 10), 512 << 20);
+ return keepSizeBefore + keepSizeAfter + reserveSize;
+ }
+
+ /**
+ * Gets approximate memory usage of the LZEncoder base structure and
+ * the match finder as kibibytes.
+ */
+ public static int getMemoryUsage(
+ int dictSize, int extraSizeBefore, int extraSizeAfter,
+ int matchLenMax, int mf) {
+ // Buffer size + a little extra
+ int m = getBufSize(dictSize, extraSizeBefore, extraSizeAfter,
+ matchLenMax) / 1024 + 10;
+
+ switch (mf) {
+ case MF_HC4:
+ m += HC4.getMemoryUsage(dictSize);
+ break;
+
+ case MF_BT4:
+ m += BT4.getMemoryUsage(dictSize);
+ break;
+
+ default:
+ throw new IllegalArgumentException();
+ }
+
+ return m;
+ }
+
+ /**
+ * Creates a new LZEncoder.
+ * <p>
+ * @param dictSize dictionary size
+ *
+ * @param extraSizeBefore
+ * number of bytes to keep available in the
+ * history in addition to dictSize
+ *
+ * @param extraSizeAfter
+ * number of bytes that must be available
+ * after current position + matchLenMax
+ *
+ * @param niceLen if a match of at least <code>niceLen</code>
+ * bytes is found, be happy with it and don't
+ * stop looking for longer matches
+ *
+ * @param matchLenMax don't test for matches longer than
+ * <code>matchLenMax</code> bytes
+ *
+ * @param mf match finder ID
+ *
+ * @param depthLimit match finder search depth limit
+ */
+ public static LZEncoder getInstance(
+ int dictSize, int extraSizeBefore, int extraSizeAfter,
+ int niceLen, int matchLenMax, int mf, int depthLimit) {
+ switch (mf) {
+ case MF_HC4:
+ return new HC4(dictSize, extraSizeBefore, extraSizeAfter,
+ niceLen, matchLenMax, depthLimit);
+
+ case MF_BT4:
+ return new BT4(dictSize, extraSizeBefore, extraSizeAfter,
+ niceLen, matchLenMax, depthLimit);
+ }
+
+ throw new IllegalArgumentException();
+ }
+
+ /**
+ * Creates a new LZEncoder. See <code>getInstance</code>.
+ */
+ LZEncoder(int dictSize, int extraSizeBefore, int extraSizeAfter,
+ int niceLen, int matchLenMax) {
+ buf = new byte[getBufSize(dictSize, extraSizeBefore, extraSizeAfter,
+ matchLenMax)];
+
+ keepSizeBefore = extraSizeBefore + dictSize;
+ keepSizeAfter = extraSizeAfter + matchLenMax;
+
+ this.matchLenMax = matchLenMax;
+ this.niceLen = niceLen;
+ }
+
+ /**
+ * Sets a preset dictionary. If a preset dictionary is wanted, this
+ * function must be called immediately after creating the LZEncoder
+ * before any data has been encoded.
+ */
+ public void setPresetDict(int dictSize, byte[] presetDict) {
+ assert !isStarted();
+ assert writePos == 0;
+
+ if (presetDict != null) {
+ // If the preset dictionary buffer is bigger than the dictionary
+ // size, copy only the tail of the preset dictionary.
+ int copySize = Math.min(presetDict.length, dictSize);
+ int offset = presetDict.length - copySize;
+ System.arraycopy(presetDict, offset, buf, 0, copySize);
+ writePos += copySize;
+ skip(copySize);
+ }
+ }
+
+ /**
+ * Moves data from the end of the buffer to the beginning, discarding
+ * old data and making space for new input.
+ */
+ private void moveWindow() {
+ // Align the move to a multiple of 16 bytes. LZMA2 needs this
+ // because it uses the lowest bits from readPos to get the
+ // alignment of the uncompressed data.
+ int moveOffset = (readPos + 1 - keepSizeBefore) & ~15;
+ int moveSize = writePos - moveOffset;
+ System.arraycopy(buf, moveOffset, buf, 0, moveSize);
+
+ readPos -= moveOffset;
+ readLimit -= moveOffset;
+ writePos -= moveOffset;
+ }
+
+ /**
+ * Copies new data into the LZEncoder's buffer.
+ */
+ public int fillWindow(byte[] in, int off, int len) {
+ assert !finishing;
+
+ // Move the sliding window if needed.
+ if (readPos >= buf.length - keepSizeAfter)
+ moveWindow();
+
+ // Try to fill the dictionary buffer. If it becomes full,
+ // some of the input bytes may be left unused.
+ if (len > buf.length - writePos)
+ len = buf.length - writePos;
+
+ System.arraycopy(in, off, buf, writePos, len);
+ writePos += len;
+
+ // Set the new readLimit but only if there's enough data to allow
+ // encoding of at least one more byte.
+ if (writePos >= keepSizeAfter)
+ readLimit = writePos - keepSizeAfter;
+
+ processPendingBytes();
+
+ // Tell the caller how much input we actually copied into
+ // the dictionary.
+ return len;
+ }
+
+ /**
+ * Process pending bytes remaining from preset dictionary initialization
+ * or encoder flush operation.
+ */
+ private void processPendingBytes() {
+ // After flushing or setting a preset dictionary there will be
+ // pending data that hasn't been ran through the match finder yet.
+ // Run it through the match finder now if there is enough new data
+ // available (readPos < readLimit) that the encoder may encode at
+ // least one more input byte. This way we don't waste any time
+ // looping in the match finder (and marking the same bytes as
+ // pending again) if the application provides very little new data
+ // per write call.
+ if (pendingSize > 0 && readPos < readLimit) {
+ readPos -= pendingSize;
+ int oldPendingSize = pendingSize;
+ pendingSize = 0;
+ skip(oldPendingSize);
+ assert pendingSize < oldPendingSize;
+ }
+ }
+
+ /**
+ * Returns true if at least one byte has already been run through
+ * the match finder.
+ */
+ public boolean isStarted() {
+ return readPos != -1;
+ }
+
+ /**
+ * Marks that all the input needs to be made available in
+ * the encoded output.
+ */
+ public void setFlushing() {
+ readLimit = writePos - 1;
+ processPendingBytes();
+ }
+
+ /**
+ * Marks that there is no more input remaining. The read position
+ * can be advanced until the end of the data.
+ */
+ public void setFinishing() {
+ readLimit = writePos - 1;
+ finishing = true;
+ processPendingBytes();
+ }
+
+ /**
+ * Tests if there is enough input available to let the caller encode
+ * at least one more byte.
+ */
+ public boolean hasEnoughData(int alreadyReadLen) {
+ return readPos - alreadyReadLen < readLimit;
+ }
+
+ public void copyUncompressed(OutputStream out, int backward, int len)
+ throws IOException {
+ out.write(buf, readPos + 1 - backward, len);
+ }
+
+ /**
+ * Get the number of bytes available, including the current byte.
+ * <p>
+ * Note that the result is undefined if <code>getMatches</code> or
+ * <code>skip</code> hasn't been called yet and no preset dictionary
+ * is being used.
+ */
+ public int getAvail() {
+ assert isStarted();
+ return writePos - readPos;
+ }
+
+ /**
+ * Gets the lowest four bits of the absolute offset of the current byte.
+ * Bits other than the lowest four are undefined.
+ */
+ public int getPos() {
+ return readPos;
+ }
+
+ /**
+ * Gets the byte from the given backward offset.
+ * <p>
+ * The current byte is at <code>0</code>, the previous byte
+ * at <code>1</code> etc. To get a byte at zero-based distance,
+ * use <code>getByte(dist + 1)<code>.
+ * <p>
+ * This function is equivalent to <code>getByte(0, backward)</code>.
+ */
+ public int getByte(int backward) {
+ return buf[readPos - backward] & 0xFF;
+ }
+
+ /**
+ * Gets the byte from the given forward minus backward offset.
+ * The forward offset is added to the current position. This lets
+ * one read bytes ahead of the current byte.
+ */
+ public int getByte(int forward, int backward) {
+ return buf[readPos + forward - backward] & 0xFF;
+ }
+
+ /**
+ * Get the length of a match at the given distance.
+ *
+ * @param dist zero-based distance of the match to test
+ * @param lenLimit don't test for a match longer than this
+ *
+ * @return length of the match; it is in the range [0, lenLimit]
+ */
+ public int getMatchLen(int dist, int lenLimit) {
+ int backPos = readPos - dist - 1;
+ int len = 0;
+
+ while (len < lenLimit && buf[readPos + len] == buf[backPos + len])
+ ++len;
+
+ return len;
+ }
+
+ /**
+ * Get the length of a match at the given distance and forward offset.
+ *
+ * @param forward forward offset
+ * @param dist zero-based distance of the match to test
+ * @param lenLimit don't test for a match longer than this
+ *
+ * @return length of the match; it is in the range [0, lenLimit]
+ */
+ public int getMatchLen(int forward, int dist, int lenLimit) {
+ int curPos = readPos + forward;
+ int backPos = curPos - dist - 1;
+ int len = 0;
+
+ while (len < lenLimit && buf[curPos + len] == buf[backPos + len])
+ ++len;
+
+ return len;
+ }
+
+ /**
+ * Verifies that the matches returned by the match finder are valid.
+ * This is meant to be used in an assert statement. This is totally
+ * useless for actual encoding since match finder's results should
+ * naturally always be valid if it isn't broken.
+ *
+ * @param matches return value from <code>getMatches</code>
+ *
+ * @return true if matches are valid, false if match finder is broken
+ */
+ public boolean verifyMatches(Matches matches) {
+ int lenLimit = Math.min(getAvail(), matchLenMax);
+
+ for (int i = 0; i < matches.count; ++i)
+ if (getMatchLen(matches.dist[i], lenLimit) != matches.len[i])
+ return false;
+
+ return true;
+ }
+
+ /**
+ * Moves to the next byte, checks if there is enough input available,
+ * and returns the amount of input available.
+ *
+ * @param requiredForFlushing
+ * minimum number of available bytes when
+ * flushing; encoding may be continued with
+ * new input after flushing
+ * @param requiredForFinishing
+ * minimum number of available bytes when
+ * finishing; encoding must not be continued
+ * after finishing or the match finder state
+ * may be corrupt
+ *
+ * @return the number of bytes available or zero if there
+ * is not enough input available
+ */
+ int movePos(int requiredForFlushing, int requiredForFinishing) {
+ assert requiredForFlushing >= requiredForFinishing;
+
+ ++readPos;
+ int avail = writePos - readPos;
+
+ if (avail < requiredForFlushing) {
+ if (avail < requiredForFinishing || !finishing) {
+ ++pendingSize;
+ avail = 0;
+ }
+ }
+
+ return avail;
+ }
+
+ /**
+ * Runs match finder for the next byte and returns the matches found.
+ */
+ public abstract Matches getMatches();
+
+ /**
+ * Skips the given number of bytes in the match finder.
+ */
+ public abstract void skip(int len);
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/lz/Matches.java b/lzma/Java/Tukaani/src/org/tukaani/xz/lz/Matches.java
new file mode 100644
index 0000000..2fbee11
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/lz/Matches.java
@@ -0,0 +1,22 @@
+/*
+ * Matches
+ *
+ * Authors: Lasse Collin <lasse.collin@tukaani.org>
+ * Igor Pavlov <http://7-zip.org/>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz.lz;
+
+public final class Matches {
+ public final int[] len;
+ public final int[] dist;
+ public int count = 0;
+
+ Matches(int countMax) {
+ len = new int[countMax];
+ dist = new int[countMax];
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/lzma/LZMACoder.java b/lzma/Java/Tukaani/src/org/tukaani/xz/lzma/LZMACoder.java
new file mode 100644
index 0000000..c31c9a6
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/lzma/LZMACoder.java
@@ -0,0 +1,140 @@
+/*
+ * LZMACoder
+ *
+ * Authors: Lasse Collin <lasse.collin@tukaani.org>
+ * Igor Pavlov <http://7-zip.org/>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz.lzma;
+
+import org.tukaani.xz.rangecoder.RangeCoder;
+
+abstract class LZMACoder {
+ static final int POS_STATES_MAX = 1 << 4;
+
+ static final int MATCH_LEN_MIN = 2;
+ static final int MATCH_LEN_MAX = MATCH_LEN_MIN + LengthCoder.LOW_SYMBOLS
+ + LengthCoder.MID_SYMBOLS
+ + LengthCoder.HIGH_SYMBOLS - 1;
+
+ static final int DIST_STATES = 4;
+ static final int DIST_SLOTS = 1 << 6;
+ static final int DIST_MODEL_START = 4;
+ static final int DIST_MODEL_END = 14;
+ static final int FULL_DISTANCES = 1 << (DIST_MODEL_END / 2);
+
+ static final int ALIGN_BITS = 4;
+ static final int ALIGN_SIZE = 1 << ALIGN_BITS;
+ static final int ALIGN_MASK = ALIGN_SIZE - 1;
+
+ static final int REPS = 4;
+
+ final int posMask;
+
+ final int[] reps = new int[REPS];
+ final State state = new State();
+
+ final short[][] isMatch = new short[State.STATES][POS_STATES_MAX];
+ final short[] isRep = new short[State.STATES];
+ final short[] isRep0 = new short[State.STATES];
+ final short[] isRep1 = new short[State.STATES];
+ final short[] isRep2 = new short[State.STATES];
+ final short[][] isRep0Long = new short[State.STATES][POS_STATES_MAX];
+ final short[][] distSlots = new short[DIST_STATES][DIST_SLOTS];
+ final short[][] distSpecial = { new short[2], new short[2],
+ new short[4], new short[4],
+ new short[8], new short[8],
+ new short[16], new short[16],
+ new short[32], new short[32] };
+ final short[] distAlign = new short[ALIGN_SIZE];
+
+ static final int getDistState(int len) {
+ return len < DIST_STATES + MATCH_LEN_MIN
+ ? len - MATCH_LEN_MIN
+ : DIST_STATES - 1;
+ }
+
+ LZMACoder(int pb) {
+ posMask = (1 << pb) - 1;
+ }
+
+ void reset() {
+ reps[0] = 0;
+ reps[1] = 0;
+ reps[2] = 0;
+ reps[3] = 0;
+ state.reset();
+
+ for (int i = 0; i < isMatch.length; ++i)
+ RangeCoder.initProbs(isMatch[i]);
+
+ RangeCoder.initProbs(isRep);
+ RangeCoder.initProbs(isRep0);
+ RangeCoder.initProbs(isRep1);
+ RangeCoder.initProbs(isRep2);
+
+ for (int i = 0; i < isRep0Long.length; ++i)
+ RangeCoder.initProbs(isRep0Long[i]);
+
+ for (int i = 0; i < distSlots.length; ++i)
+ RangeCoder.initProbs(distSlots[i]);
+
+ for (int i = 0; i < distSpecial.length; ++i)
+ RangeCoder.initProbs(distSpecial[i]);
+
+ RangeCoder.initProbs(distAlign);
+ }
+
+
+ abstract class LiteralCoder {
+ private final int lc;
+ private final int literalPosMask;
+
+ LiteralCoder(int lc, int lp) {
+ this.lc = lc;
+ this.literalPosMask = (1 << lp) - 1;
+ }
+
+ final int getSubcoderIndex(int prevByte, int pos) {
+ int low = prevByte >> (8 - lc);
+ int high = (pos & literalPosMask) << lc;
+ return low + high;
+ }
+
+
+ abstract class LiteralSubcoder {
+ final short[] probs = new short[0x300];
+
+ void reset() {
+ RangeCoder.initProbs(probs);
+ }
+ }
+ }
+
+
+ abstract class LengthCoder {
+ static final int LOW_SYMBOLS = 1 << 3;
+ static final int MID_SYMBOLS = 1 << 3;
+ static final int HIGH_SYMBOLS = 1 << 8;
+
+ final short[] choice = new short[2];
+ final short[][] low = new short[POS_STATES_MAX][LOW_SYMBOLS];
+ final short[][] mid = new short[POS_STATES_MAX][MID_SYMBOLS];
+ final short[] high = new short[HIGH_SYMBOLS];
+
+ void reset() {
+ RangeCoder.initProbs(choice);
+
+ for (int i = 0; i < low.length; ++i)
+ RangeCoder.initProbs(low[i]);
+
+ for (int i = 0; i < low.length; ++i)
+ RangeCoder.initProbs(mid[i]);
+
+ RangeCoder.initProbs(high);
+ }
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/lzma/LZMADecoder.java b/lzma/Java/Tukaani/src/org/tukaani/xz/lzma/LZMADecoder.java
new file mode 100644
index 0000000..ccf1960
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/lzma/LZMADecoder.java
@@ -0,0 +1,199 @@
+/*
+ * LZMADecoder
+ *
+ * Authors: Lasse Collin <lasse.collin@tukaani.org>
+ * Igor Pavlov <http://7-zip.org/>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz.lzma;
+
+import java.io.IOException;
+import org.tukaani.xz.lz.LZDecoder;
+import org.tukaani.xz.rangecoder.RangeDecoder;
+
+public final class LZMADecoder extends LZMACoder {
+ private final LZDecoder lz;
+ private final RangeDecoder rc;
+ private final LiteralDecoder literalDecoder;
+ private final LengthDecoder matchLenDecoder = new LengthDecoder();
+ private final LengthDecoder repLenDecoder = new LengthDecoder();
+
+ public LZMADecoder(LZDecoder lz, RangeDecoder rc, int lc, int lp, int pb) {
+ super(pb);
+ this.lz = lz;
+ this.rc = rc;
+ this.literalDecoder = new LiteralDecoder(lc, lp);
+ reset();
+ }
+
+ public void reset() {
+ super.reset();
+ literalDecoder.reset();
+ matchLenDecoder.reset();
+ repLenDecoder.reset();
+ }
+
+ /**
+ * Returns true if LZMA end marker was detected. It is encoded as
+ * the maximum match distance which with signed ints becomes -1. This
+ * function is needed only for LZMA1. LZMA2 doesn't use the end marker
+ * in the LZMA layer.
+ */
+ public boolean endMarkerDetected() {
+ return reps[0] == -1;
+ }
+
+ public void decode() throws IOException {
+ lz.repeatPending();
+
+ while (lz.hasSpace()) {
+ int posState = lz.getPos() & posMask;
+
+ if (rc.decodeBit(isMatch[state.get()], posState) == 0) {
+ literalDecoder.decode();
+ } else {
+ int len = rc.decodeBit(isRep, state.get()) == 0
+ ? decodeMatch(posState)
+ : decodeRepMatch(posState);
+
+ // NOTE: With LZMA1 streams that have the end marker,
+ // this will throw CorruptedInputException. LZMAInputStream
+ // handles it specially.
+ lz.repeat(reps[0], len);
+ }
+ }
+
+ rc.normalize();
+ }
+
+ private int decodeMatch(int posState) throws IOException {
+ state.updateMatch();
+
+ reps[3] = reps[2];
+ reps[2] = reps[1];
+ reps[1] = reps[0];
+
+ int len = matchLenDecoder.decode(posState);
+ int distSlot = rc.decodeBitTree(distSlots[getDistState(len)]);
+
+ if (distSlot < DIST_MODEL_START) {
+ reps[0] = distSlot;
+ } else {
+ int limit = (distSlot >> 1) - 1;
+ reps[0] = (2 | (distSlot & 1)) << limit;
+
+ if (distSlot < DIST_MODEL_END) {
+ reps[0] |= rc.decodeReverseBitTree(
+ distSpecial[distSlot - DIST_MODEL_START]);
+ } else {
+ reps[0] |= rc.decodeDirectBits(limit - ALIGN_BITS)
+ << ALIGN_BITS;
+ reps[0] |= rc.decodeReverseBitTree(distAlign);
+ }
+ }
+
+ return len;
+ }
+
+ private int decodeRepMatch(int posState) throws IOException {
+ if (rc.decodeBit(isRep0, state.get()) == 0) {
+ if (rc.decodeBit(isRep0Long[state.get()], posState) == 0) {
+ state.updateShortRep();
+ return 1;
+ }
+ } else {
+ int tmp;
+
+ if (rc.decodeBit(isRep1, state.get()) == 0) {
+ tmp = reps[1];
+ } else {
+ if (rc.decodeBit(isRep2, state.get()) == 0) {
+ tmp = reps[2];
+ } else {
+ tmp = reps[3];
+ reps[3] = reps[2];
+ }
+
+ reps[2] = reps[1];
+ }
+
+ reps[1] = reps[0];
+ reps[0] = tmp;
+ }
+
+ state.updateLongRep();
+
+ return repLenDecoder.decode(posState);
+ }
+
+
+ private class LiteralDecoder extends LiteralCoder {
+ private final LiteralSubdecoder[] subdecoders;
+
+ LiteralDecoder(int lc, int lp) {
+ super(lc, lp);
+
+ subdecoders = new LiteralSubdecoder[1 << (lc + lp)];
+ for (int i = 0; i < subdecoders.length; ++i)
+ subdecoders[i] = new LiteralSubdecoder();
+ }
+
+ void reset() {
+ for (int i = 0; i < subdecoders.length; ++i)
+ subdecoders[i].reset();
+ }
+
+ void decode() throws IOException {
+ int i = getSubcoderIndex(lz.getByte(0), lz.getPos());
+ subdecoders[i].decode();
+ }
+
+
+ private class LiteralSubdecoder extends LiteralSubcoder {
+ void decode() throws IOException {
+ int symbol = 1;
+
+ if (state.isLiteral()) {
+ do {
+ symbol = (symbol << 1) | rc.decodeBit(probs, symbol);
+ } while (symbol < 0x100);
+
+ } else {
+ int matchByte = lz.getByte(reps[0]);
+ int offset = 0x100;
+ int matchBit;
+ int bit;
+
+ do {
+ matchByte <<= 1;
+ matchBit = matchByte & offset;
+ bit = rc.decodeBit(probs, offset + matchBit + symbol);
+ symbol = (symbol << 1) | bit;
+ offset &= (0 - bit) ^ ~matchBit;
+ } while (symbol < 0x100);
+ }
+
+ lz.putByte((byte)symbol);
+ state.updateLiteral();
+ }
+ }
+ }
+
+
+ private class LengthDecoder extends LengthCoder {
+ int decode(int posState) throws IOException {
+ if (rc.decodeBit(choice, 0) == 0)
+ return rc.decodeBitTree(low[posState]) + MATCH_LEN_MIN;
+
+ if (rc.decodeBit(choice, 1) == 0)
+ return rc.decodeBitTree(mid[posState])
+ + MATCH_LEN_MIN + LOW_SYMBOLS;
+
+ return rc.decodeBitTree(high)
+ + MATCH_LEN_MIN + LOW_SYMBOLS + MID_SYMBOLS;
+ }
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/lzma/LZMAEncoder.java b/lzma/Java/Tukaani/src/org/tukaani/xz/lzma/LZMAEncoder.java
new file mode 100644
index 0000000..4fdc198
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/lzma/LZMAEncoder.java
@@ -0,0 +1,711 @@
+/*
+ * LZMAEncoder
+ *
+ * Authors: Lasse Collin <lasse.collin@tukaani.org>
+ * Igor Pavlov <http://7-zip.org/>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz.lzma;
+
+import org.tukaani.xz.lz.LZEncoder;
+import org.tukaani.xz.lz.Matches;
+import org.tukaani.xz.rangecoder.RangeEncoder;
+
+public abstract class LZMAEncoder extends LZMACoder {
+ public static final int MODE_FAST = 1;
+ public static final int MODE_NORMAL = 2;
+
+ /**
+ * LZMA2 chunk is considered full when its uncompressed size exceeds
+ * <code>LZMA2_UNCOMPRESSED_LIMIT</code>.
+ * <p>
+ * A compressed LZMA2 chunk can hold 2 MiB of uncompressed data.
+ * A single LZMA symbol may indicate up to MATCH_LEN_MAX bytes
+ * of data, so the LZMA2 chunk is considered full when there is
+ * less space than MATCH_LEN_MAX bytes.
+ */
+ private static final int LZMA2_UNCOMPRESSED_LIMIT
+ = (2 << 20) - MATCH_LEN_MAX;
+
+ /**
+ * LZMA2 chunk is considered full when its compressed size exceeds
+ * <code>LZMA2_COMPRESSED_LIMIT</code>.
+ * <p>
+ * The maximum compressed size of a LZMA2 chunk is 64 KiB.
+ * A single LZMA symbol might use 20 bytes of space even though
+ * it usually takes just one byte or so. Two more bytes are needed
+ * for LZMA2 uncompressed chunks (see LZMA2OutputStream.writeChunk).
+ * Leave a little safety margin and use 26 bytes.
+ */
+ private static final int LZMA2_COMPRESSED_LIMIT = (64 << 10) - 26;
+
+ private static final int DIST_PRICE_UPDATE_INTERVAL = FULL_DISTANCES;
+ private static final int ALIGN_PRICE_UPDATE_INTERVAL = ALIGN_SIZE;
+
+ private final RangeEncoder rc;
+ final LZEncoder lz;
+ final LiteralEncoder literalEncoder;
+ final LengthEncoder matchLenEncoder;
+ final LengthEncoder repLenEncoder;
+ final int niceLen;
+
+ private int distPriceCount = 0;
+ private int alignPriceCount = 0;
+
+ private final int distSlotPricesSize;
+ private final int[][] distSlotPrices;
+ private final int[][] fullDistPrices
+ = new int[DIST_STATES][FULL_DISTANCES];
+ private final int[] alignPrices = new int[ALIGN_SIZE];
+
+ int back = 0;
+ int readAhead = -1;
+ private int uncompressedSize = 0;
+
+ public static int getMemoryUsage(int mode, int dictSize,
+ int extraSizeBefore, int mf) {
+ int m = 80;
+
+ switch (mode) {
+ case MODE_FAST:
+ m += LZMAEncoderFast.getMemoryUsage(
+ dictSize, extraSizeBefore, mf);
+ break;
+
+ case MODE_NORMAL:
+ m += LZMAEncoderNormal.getMemoryUsage(
+ dictSize, extraSizeBefore, mf);
+ break;
+
+ default:
+ throw new IllegalArgumentException();
+ }
+
+ return m;
+ }
+
+ public static LZMAEncoder getInstance(
+ RangeEncoder rc, int lc, int lp, int pb, int mode,
+ int dictSize, int extraSizeBefore,
+ int niceLen, int mf, int depthLimit) {
+ switch (mode) {
+ case MODE_FAST:
+ return new LZMAEncoderFast(rc, lc, lp, pb,
+ dictSize, extraSizeBefore,
+ niceLen, mf, depthLimit);
+
+ case MODE_NORMAL:
+ return new LZMAEncoderNormal(rc, lc, lp, pb,
+ dictSize, extraSizeBefore,
+ niceLen, mf, depthLimit);
+ }
+
+ throw new IllegalArgumentException();
+ }
+
+ /**
+ * Gets an integer [0, 63] matching the highest two bits of an integer.
+ * This is like bit scan reverse (BSR) on x86 except that this also
+ * cares about the second highest bit.
+ */
+ public static int getDistSlot(int dist) {
+ if (dist <= DIST_MODEL_START)
+ return dist;
+
+ int n = dist;
+ int i = 31;
+
+ if ((n & 0xFFFF0000) == 0) {
+ n <<= 16;
+ i = 15;
+ }
+
+ if ((n & 0xFF000000) == 0) {
+ n <<= 8;
+ i -= 8;
+ }
+
+ if ((n & 0xF0000000) == 0) {
+ n <<= 4;
+ i -= 4;
+ }
+
+ if ((n & 0xC0000000) == 0) {
+ n <<= 2;
+ i -= 2;
+ }
+
+ if ((n & 0x80000000) == 0)
+ --i;
+
+ return (i << 1) + ((dist >>> (i - 1)) & 1);
+ }
+
+ /**
+ * Gets the next LZMA symbol.
+ * <p>
+ * There are three types of symbols: literal (a single byte),
+ * repeated match, and normal match. The symbol is indicated
+ * by the return value and by the variable <code>back</code>.
+ * <p>
+ * Literal: <code>back == -1</code> and return value is <code>1</code>.
+ * The literal itself needs to be read from <code>lz</code> separately.
+ * <p>
+ * Repeated match: <code>back</code> is in the range [0, 3] and
+ * the return value is the length of the repeated match.
+ * <p>
+ * Normal match: <code>back - REPS<code> (<code>back - 4</code>)
+ * is the distance of the match and the return value is the length
+ * of the match.
+ */
+ abstract int getNextSymbol();
+
+ LZMAEncoder(RangeEncoder rc, LZEncoder lz,
+ int lc, int lp, int pb, int dictSize, int niceLen) {
+ super(pb);
+ this.rc = rc;
+ this.lz = lz;
+ this.niceLen = niceLen;
+
+ literalEncoder = new LiteralEncoder(lc, lp);
+ matchLenEncoder = new LengthEncoder(pb, niceLen);
+ repLenEncoder = new LengthEncoder(pb, niceLen);
+
+ distSlotPricesSize = getDistSlot(dictSize - 1) + 1;
+ distSlotPrices = new int[DIST_STATES][distSlotPricesSize];
+
+ reset();
+ }
+
+ public LZEncoder getLZEncoder() {
+ return lz;
+ }
+
+ public void reset() {
+ super.reset();
+ literalEncoder.reset();
+ matchLenEncoder.reset();
+ repLenEncoder.reset();
+ distPriceCount = 0;
+ alignPriceCount = 0;
+
+ uncompressedSize += readAhead + 1;
+ readAhead = -1;
+ }
+
+ public int getUncompressedSize() {
+ return uncompressedSize;
+ }
+
+ public void resetUncompressedSize() {
+ uncompressedSize = 0;
+ }
+
+ /**
+ * Compresses for LZMA2.
+ *
+ * @return true if the LZMA2 chunk became full, false otherwise
+ */
+ public boolean encodeForLZMA2() {
+ if (!lz.isStarted() && !encodeInit())
+ return false;
+
+ while (uncompressedSize <= LZMA2_UNCOMPRESSED_LIMIT
+ && rc.getPendingSize() <= LZMA2_COMPRESSED_LIMIT)
+ if (!encodeSymbol())
+ return false;
+
+ return true;
+ }
+
+ private boolean encodeInit() {
+ assert readAhead == -1;
+ if (!lz.hasEnoughData(0))
+ return false;
+
+ // The first symbol must be a literal unless using
+ // a preset dictionary. This code isn't run if using
+ // a preset dictionary.
+ skip(1);
+ rc.encodeBit(isMatch[state.get()], 0, 0);
+ literalEncoder.encodeInit();
+
+ --readAhead;
+ assert readAhead == -1;
+
+ ++uncompressedSize;
+ assert uncompressedSize == 1;
+
+ return true;
+ }
+
+ private boolean encodeSymbol() {
+ if (!lz.hasEnoughData(readAhead + 1))
+ return false;
+
+ int len = getNextSymbol();
+
+ assert readAhead >= 0;
+ int posState = (lz.getPos() - readAhead) & posMask;
+
+ if (back == -1) {
+ // Literal i.e. eight-bit byte
+ assert len == 1;
+ rc.encodeBit(isMatch[state.get()], posState, 0);
+ literalEncoder.encode();
+ } else {
+ // Some type of match
+ rc.encodeBit(isMatch[state.get()], posState, 1);
+ if (back < REPS) {
+ // Repeated match i.e. the same distance
+ // has been used earlier.
+ assert lz.getMatchLen(-readAhead, reps[back], len) == len;
+ rc.encodeBit(isRep, state.get(), 1);
+ encodeRepMatch(back, len, posState);
+ } else {
+ // Normal match
+ assert lz.getMatchLen(-readAhead, back - REPS, len) == len;
+ rc.encodeBit(isRep, state.get(), 0);
+ encodeMatch(back - REPS, len, posState);
+ }
+ }
+
+ readAhead -= len;
+ uncompressedSize += len;
+
+ return true;
+ }
+
+ private void encodeMatch(int dist, int len, int posState) {
+ state.updateMatch();
+ matchLenEncoder.encode(len, posState);
+
+ int distSlot = getDistSlot(dist);
+ rc.encodeBitTree(distSlots[getDistState(len)], distSlot);
+
+ if (distSlot >= DIST_MODEL_START) {
+ int footerBits = (distSlot >>> 1) - 1;
+ int base = (2 | (distSlot & 1)) << footerBits;
+ int distReduced = dist - base;
+
+ if (distSlot < DIST_MODEL_END) {
+ rc.encodeReverseBitTree(
+ distSpecial[distSlot - DIST_MODEL_START],
+ distReduced);
+ } else {
+ rc.encodeDirectBits(distReduced >>> ALIGN_BITS,
+ footerBits - ALIGN_BITS);
+ rc.encodeReverseBitTree(distAlign, distReduced & ALIGN_MASK);
+ --alignPriceCount;
+ }
+ }
+
+ reps[3] = reps[2];
+ reps[2] = reps[1];
+ reps[1] = reps[0];
+ reps[0] = dist;
+
+ --distPriceCount;
+ }
+
+ private void encodeRepMatch(int rep, int len, int posState) {
+ if (rep == 0) {
+ rc.encodeBit(isRep0, state.get(), 0);
+ rc.encodeBit(isRep0Long[state.get()], posState, len == 1 ? 0 : 1);
+ } else {
+ int dist = reps[rep];
+ rc.encodeBit(isRep0, state.get(), 1);
+
+ if (rep == 1) {
+ rc.encodeBit(isRep1, state.get(), 0);
+ } else {
+ rc.encodeBit(isRep1, state.get(), 1);
+ rc.encodeBit(isRep2, state.get(), rep - 2);
+
+ if (rep == 3)
+ reps[3] = reps[2];
+
+ reps[2] = reps[1];
+ }
+
+ reps[1] = reps[0];
+ reps[0] = dist;
+ }
+
+ if (len == 1) {
+ state.updateShortRep();
+ } else {
+ repLenEncoder.encode(len, posState);
+ state.updateLongRep();
+ }
+ }
+
+ Matches getMatches() {
+ ++readAhead;
+ Matches matches = lz.getMatches();
+ assert lz.verifyMatches(matches);
+ return matches;
+ }
+
+ void skip(int len) {
+ readAhead += len;
+ lz.skip(len);
+ }
+
+ int getAnyMatchPrice(State state, int posState) {
+ return RangeEncoder.getBitPrice(isMatch[state.get()][posState], 1);
+ }
+
+ int getNormalMatchPrice(int anyMatchPrice, State state) {
+ return anyMatchPrice
+ + RangeEncoder.getBitPrice(isRep[state.get()], 0);
+ }
+
+ int getAnyRepPrice(int anyMatchPrice, State state) {
+ return anyMatchPrice
+ + RangeEncoder.getBitPrice(isRep[state.get()], 1);
+ }
+
+ int getShortRepPrice(int anyRepPrice, State state, int posState) {
+ return anyRepPrice
+ + RangeEncoder.getBitPrice(isRep0[state.get()], 0)
+ + RangeEncoder.getBitPrice(isRep0Long[state.get()][posState],
+ 0);
+ }
+
+ int getLongRepPrice(int anyRepPrice, int rep, State state, int posState) {
+ int price = anyRepPrice;
+
+ if (rep == 0) {
+ price += RangeEncoder.getBitPrice(isRep0[state.get()], 0)
+ + RangeEncoder.getBitPrice(
+ isRep0Long[state.get()][posState], 1);
+ } else {
+ price += RangeEncoder.getBitPrice(isRep0[state.get()], 1);
+
+ if (rep == 1)
+ price += RangeEncoder.getBitPrice(isRep1[state.get()], 0);
+ else
+ price += RangeEncoder.getBitPrice(isRep1[state.get()], 1)
+ + RangeEncoder.getBitPrice(isRep2[state.get()],
+ rep - 2);
+ }
+
+ return price;
+ }
+
+ int getLongRepAndLenPrice(int rep, int len, State state, int posState) {
+ int anyMatchPrice = getAnyMatchPrice(state, posState);
+ int anyRepPrice = getAnyRepPrice(anyMatchPrice, state);
+ int longRepPrice = getLongRepPrice(anyRepPrice, rep, state, posState);
+ return longRepPrice + repLenEncoder.getPrice(len, posState);
+ }
+
+ int getMatchAndLenPrice(int normalMatchPrice,
+ int dist, int len, int posState) {
+ int price = normalMatchPrice
+ + matchLenEncoder.getPrice(len, posState);
+ int distState = getDistState(len);
+
+ if (dist < FULL_DISTANCES) {
+ price += fullDistPrices[distState][dist];
+ } else {
+ // Note that distSlotPrices includes also
+ // the price of direct bits.
+ int distSlot = getDistSlot(dist);
+ price += distSlotPrices[distState][distSlot]
+ + alignPrices[dist & ALIGN_MASK];
+ }
+
+ return price;
+ }
+
+ private void updateDistPrices() {
+ distPriceCount = DIST_PRICE_UPDATE_INTERVAL;
+
+ for (int distState = 0; distState < DIST_STATES; ++distState) {
+ for (int distSlot = 0; distSlot < distSlotPricesSize; ++distSlot)
+ distSlotPrices[distState][distSlot]
+ = RangeEncoder.getBitTreePrice(
+ distSlots[distState], distSlot);
+
+ for (int distSlot = DIST_MODEL_END; distSlot < distSlotPricesSize;
+ ++distSlot) {
+ int count = (distSlot >>> 1) - 1 - ALIGN_BITS;
+ distSlotPrices[distState][distSlot]
+ += RangeEncoder.getDirectBitsPrice(count);
+ }
+
+ for (int dist = 0; dist < DIST_MODEL_START; ++dist)
+ fullDistPrices[distState][dist]
+ = distSlotPrices[distState][dist];
+ }
+
+ int dist = DIST_MODEL_START;
+ for (int distSlot = DIST_MODEL_START; distSlot < DIST_MODEL_END;
+ ++distSlot) {
+ int footerBits = (distSlot >>> 1) - 1;
+ int base = (2 | (distSlot & 1)) << footerBits;
+
+ int limit = distSpecial[distSlot - DIST_MODEL_START].length;
+ for (int i = 0; i < limit; ++i) {
+ int distReduced = dist - base;
+ int price = RangeEncoder.getReverseBitTreePrice(
+ distSpecial[distSlot - DIST_MODEL_START],
+ distReduced);
+
+ for (int distState = 0; distState < DIST_STATES; ++distState)
+ fullDistPrices[distState][dist]
+ = distSlotPrices[distState][distSlot] + price;
+
+ ++dist;
+ }
+ }
+
+ assert dist == FULL_DISTANCES;
+ }
+
+ private void updateAlignPrices() {
+ alignPriceCount = ALIGN_PRICE_UPDATE_INTERVAL;
+
+ for (int i = 0; i < ALIGN_SIZE; ++i)
+ alignPrices[i] = RangeEncoder.getReverseBitTreePrice(distAlign,
+ i);
+ }
+
+ /**
+ * Updates the lookup tables used for calculating match distance
+ * and length prices. The updating is skipped for performance reasons
+ * if the tables haven't changed much since the previous update.
+ */
+ void updatePrices() {
+ if (distPriceCount <= 0)
+ updateDistPrices();
+
+ if (alignPriceCount <= 0)
+ updateAlignPrices();
+
+ matchLenEncoder.updatePrices();
+ repLenEncoder.updatePrices();
+ }
+
+
+ class LiteralEncoder extends LiteralCoder {
+ private final LiteralSubencoder[] subencoders;
+
+ LiteralEncoder(int lc, int lp) {
+ super(lc, lp);
+
+ subencoders = new LiteralSubencoder[1 << (lc + lp)];
+ for (int i = 0; i < subencoders.length; ++i)
+ subencoders[i] = new LiteralSubencoder();
+ }
+
+ void reset() {
+ for (int i = 0; i < subencoders.length; ++i)
+ subencoders[i].reset();
+ }
+
+ void encodeInit() {
+ // When encoding the first byte of the stream, there is
+ // no previous byte in the dictionary so the encode function
+ // wouldn't work.
+ assert readAhead >= 0;
+ subencoders[0].encode();
+ }
+
+ void encode() {
+ assert readAhead >= 0;
+ int i = getSubcoderIndex(lz.getByte(1 + readAhead),
+ lz.getPos() - readAhead);
+ subencoders[i].encode();
+ }
+
+ int getPrice(int curByte, int matchByte,
+ int prevByte, int pos, State state) {
+ int price = RangeEncoder.getBitPrice(
+ isMatch[state.get()][pos & posMask], 0);
+
+ int i = getSubcoderIndex(prevByte, pos);
+ price += state.isLiteral()
+ ? subencoders[i].getNormalPrice(curByte)
+ : subencoders[i].getMatchedPrice(curByte, matchByte);
+
+ return price;
+ }
+
+ private class LiteralSubencoder extends LiteralSubcoder {
+ void encode() {
+ int symbol = lz.getByte(readAhead) | 0x100;
+
+ if (state.isLiteral()) {
+ int subencoderIndex;
+ int bit;
+
+ do {
+ subencoderIndex = symbol >>> 8;
+ bit = (symbol >>> 7) & 1;
+ rc.encodeBit(probs, subencoderIndex, bit);
+ symbol <<= 1;
+ } while (symbol < 0x10000);
+
+ } else {
+ int matchByte = lz.getByte(reps[0] + 1 + readAhead);
+ int offset = 0x100;
+ int subencoderIndex;
+ int matchBit;
+ int bit;
+
+ do {
+ matchByte <<= 1;
+ matchBit = matchByte & offset;
+ subencoderIndex = offset + matchBit + (symbol >>> 8);
+ bit = (symbol >>> 7) & 1;
+ rc.encodeBit(probs, subencoderIndex, bit);
+ symbol <<= 1;
+ offset &= ~(matchByte ^ symbol);
+ } while (symbol < 0x10000);
+ }
+
+ state.updateLiteral();
+ }
+
+ int getNormalPrice(int symbol) {
+ int price = 0;
+ int subencoderIndex;
+ int bit;
+
+ symbol |= 0x100;
+
+ do {
+ subencoderIndex = symbol >>> 8;
+ bit = (symbol >>> 7) & 1;
+ price += RangeEncoder.getBitPrice(probs[subencoderIndex],
+ bit);
+ symbol <<= 1;
+ } while (symbol < (0x100 << 8));
+
+ return price;
+ }
+
+ int getMatchedPrice(int symbol, int matchByte) {
+ int price = 0;
+ int offset = 0x100;
+ int subencoderIndex;
+ int matchBit;
+ int bit;
+
+ symbol |= 0x100;
+
+ do {
+ matchByte <<= 1;
+ matchBit = matchByte & offset;
+ subencoderIndex = offset + matchBit + (symbol >>> 8);
+ bit = (symbol >>> 7) & 1;
+ price += RangeEncoder.getBitPrice(probs[subencoderIndex],
+ bit);
+ symbol <<= 1;
+ offset &= ~(matchByte ^ symbol);
+ } while (symbol < (0x100 << 8));
+
+ return price;
+ }
+ }
+ }
+
+
+ class LengthEncoder extends LengthCoder {
+ /**
+ * The prices are updated after at least
+ * <code>PRICE_UPDATE_INTERVAL</code> many lengths
+ * have been encoded with the same posState.
+ */
+ private static final int PRICE_UPDATE_INTERVAL = 32; // FIXME?
+
+ private final int[] counters;
+ private final int[][] prices;
+
+ LengthEncoder(int pb, int niceLen) {
+ int posStates = 1 << pb;
+ counters = new int[posStates];
+
+ // Always allocate at least LOW_SYMBOLS + MID_SYMBOLS because
+ // it makes updatePrices slightly simpler. The prices aren't
+ // usually needed anyway if niceLen < 18.
+ int lenSymbols = Math.max(niceLen - MATCH_LEN_MIN + 1,
+ LOW_SYMBOLS + MID_SYMBOLS);
+ prices = new int[posStates][lenSymbols];
+ }
+
+ void reset() {
+ super.reset();
+
+ // Reset counters to zero to force price update before
+ // the prices are needed.
+ for (int i = 0; i < counters.length; ++i)
+ counters[i] = 0;
+ }
+
+ void encode(int len, int posState) {
+ len -= MATCH_LEN_MIN;
+
+ if (len < LOW_SYMBOLS) {
+ rc.encodeBit(choice, 0, 0);
+ rc.encodeBitTree(low[posState], len);
+ } else {
+ rc.encodeBit(choice, 0, 1);
+ len -= LOW_SYMBOLS;
+
+ if (len < MID_SYMBOLS) {
+ rc.encodeBit(choice, 1, 0);
+ rc.encodeBitTree(mid[posState], len);
+ } else {
+ rc.encodeBit(choice, 1, 1);
+ rc.encodeBitTree(high, len - MID_SYMBOLS);
+ }
+ }
+
+ --counters[posState];
+ }
+
+ int getPrice(int len, int posState) {
+ return prices[posState][len - MATCH_LEN_MIN];
+ }
+
+ void updatePrices() {
+ for (int posState = 0; posState < counters.length; ++posState) {
+ if (counters[posState] <= 0) {
+ counters[posState] = PRICE_UPDATE_INTERVAL;
+ updatePrices(posState);
+ }
+ }
+ }
+
+ private void updatePrices(int posState) {
+ int choice0Price = RangeEncoder.getBitPrice(choice[0], 0);
+
+ int i = 0;
+ for (; i < LOW_SYMBOLS; ++i)
+ prices[posState][i] = choice0Price
+ + RangeEncoder.getBitTreePrice(low[posState], i);
+
+ choice0Price = RangeEncoder.getBitPrice(choice[0], 1);
+ int choice1Price = RangeEncoder.getBitPrice(choice[1], 0);
+
+ for (; i < LOW_SYMBOLS + MID_SYMBOLS; ++i)
+ prices[posState][i] = choice0Price + choice1Price
+ + RangeEncoder.getBitTreePrice(mid[posState],
+ i - LOW_SYMBOLS);
+
+ choice1Price = RangeEncoder.getBitPrice(choice[1], 1);
+
+ for (; i < prices[posState].length; ++i)
+ prices[posState][i] = choice0Price + choice1Price
+ + RangeEncoder.getBitTreePrice(high, i - LOW_SYMBOLS
+ - MID_SYMBOLS);
+ }
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/lzma/LZMAEncoderFast.java b/lzma/Java/Tukaani/src/org/tukaani/xz/lzma/LZMAEncoderFast.java
new file mode 100644
index 0000000..072dd09
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/lzma/LZMAEncoderFast.java
@@ -0,0 +1,151 @@
+/*
+ * LZMAEncoderFast
+ *
+ * Authors: Lasse Collin <lasse.collin@tukaani.org>
+ * Igor Pavlov <http://7-zip.org/>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz.lzma;
+
+import org.tukaani.xz.lz.LZEncoder;
+import org.tukaani.xz.lz.Matches;
+import org.tukaani.xz.rangecoder.RangeEncoder;
+
+final class LZMAEncoderFast extends LZMAEncoder {
+ private static final int EXTRA_SIZE_BEFORE = 1;
+ private static final int EXTRA_SIZE_AFTER = MATCH_LEN_MAX - 1;
+
+ private Matches matches = null;
+
+ static int getMemoryUsage(int dictSize, int extraSizeBefore, int mf) {
+ return LZEncoder.getMemoryUsage(
+ dictSize, Math.max(extraSizeBefore, EXTRA_SIZE_BEFORE),
+ EXTRA_SIZE_AFTER, MATCH_LEN_MAX, mf);
+ }
+
+ LZMAEncoderFast(RangeEncoder rc, int lc, int lp, int pb,
+ int dictSize, int extraSizeBefore,
+ int niceLen, int mf, int depthLimit) {
+ super(rc, LZEncoder.getInstance(dictSize,
+ Math.max(extraSizeBefore,
+ EXTRA_SIZE_BEFORE),
+ EXTRA_SIZE_AFTER,
+ niceLen, MATCH_LEN_MAX,
+ mf, depthLimit),
+ lc, lp, pb, dictSize, niceLen);
+ }
+
+ private boolean changePair(int smallDist, int bigDist) {
+ return smallDist < (bigDist >>> 7);
+ }
+
+ int getNextSymbol() {
+ // Get the matches for the next byte unless readAhead indicates
+ // that we already got the new matches during the previous call
+ // to this function.
+ if (readAhead == -1)
+ matches = getMatches();
+
+ back = -1;
+
+ // Get the number of bytes available in the dictionary, but
+ // not more than the maximum match length. If there aren't
+ // enough bytes remaining to encode a match at all, return
+ // immediately to encode this byte as a literal.
+ int avail = Math.min(lz.getAvail(), MATCH_LEN_MAX);
+ if (avail < MATCH_LEN_MIN)
+ return 1;
+
+ // Look for a match from the previous four match distances.
+ int bestRepLen = 0;
+ int bestRepIndex = 0;
+ for (int rep = 0; rep < REPS; ++rep) {
+ int len = lz.getMatchLen(reps[rep], avail);
+ if (len < MATCH_LEN_MIN)
+ continue;
+
+ // If it is long enough, return it.
+ if (len >= niceLen) {
+ back = rep;
+ skip(len - 1);
+ return len;
+ }
+
+ // Remember the index and length of the best repeated match.
+ if (len > bestRepLen) {
+ bestRepIndex = rep;
+ bestRepLen = len;
+ }
+ }
+
+ int mainLen = 0;
+ int mainDist = 0;
+
+ if (matches.count > 0) {
+ mainLen = matches.len[matches.count - 1];
+ mainDist = matches.dist[matches.count - 1];
+
+ if (mainLen >= niceLen) {
+ back = mainDist + REPS;
+ skip(mainLen - 1);
+ return mainLen;
+ }
+
+ while (matches.count > 1
+ && mainLen == matches.len[matches.count - 2] + 1) {
+ if (!changePair(matches.dist[matches.count - 2], mainDist))
+ break;
+
+ --matches.count;
+ mainLen = matches.len[matches.count - 1];
+ mainDist = matches.dist[matches.count - 1];
+ }
+
+ if (mainLen == MATCH_LEN_MIN && mainDist >= 0x80)
+ mainLen = 1;
+ }
+
+ if (bestRepLen >= MATCH_LEN_MIN) {
+ if (bestRepLen + 1 >= mainLen
+ || (bestRepLen + 2 >= mainLen && mainDist >= (1 << 9))
+ || (bestRepLen + 3 >= mainLen && mainDist >= (1 << 15))) {
+ back = bestRepIndex;
+ skip(bestRepLen - 1);
+ return bestRepLen;
+ }
+ }
+
+ if (mainLen < MATCH_LEN_MIN || avail <= MATCH_LEN_MIN)
+ return 1;
+
+ // Get the next match. Test if it is better than the current match.
+ // If so, encode the current byte as a literal.
+ matches = getMatches();
+
+ if (matches.count > 0) {
+ int newLen = matches.len[matches.count - 1];
+ int newDist = matches.dist[matches.count - 1];
+
+ if ((newLen >= mainLen && newDist < mainDist)
+ || (newLen == mainLen + 1
+ && !changePair(mainDist, newDist))
+ || newLen > mainLen + 1
+ || (newLen + 1 >= mainLen
+ && mainLen >= MATCH_LEN_MIN + 1
+ && changePair(newDist, mainDist)))
+ return 1;
+ }
+
+ int limit = Math.max(mainLen - 1, MATCH_LEN_MIN);
+ for (int rep = 0; rep < REPS; ++rep)
+ if (lz.getMatchLen(reps[rep], limit) == limit)
+ return 1;
+
+ back = mainDist + REPS;
+ skip(mainLen - 2);
+ return mainLen;
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/lzma/LZMAEncoderNormal.java b/lzma/Java/Tukaani/src/org/tukaani/xz/lzma/LZMAEncoderNormal.java
new file mode 100644
index 0000000..104afe3
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/lzma/LZMAEncoderNormal.java
@@ -0,0 +1,566 @@
+/*
+ * LZMAEncoderNormal
+ *
+ * Authors: Lasse Collin <lasse.collin@tukaani.org>
+ * Igor Pavlov <http://7-zip.org/>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz.lzma;
+
+import org.tukaani.xz.lz.LZEncoder;
+import org.tukaani.xz.lz.Matches;
+import org.tukaani.xz.rangecoder.RangeEncoder;
+
+final class LZMAEncoderNormal extends LZMAEncoder {
+ private static final int OPTS = 4096;
+
+ private static final int EXTRA_SIZE_BEFORE = OPTS;
+ private static final int EXTRA_SIZE_AFTER = OPTS;
+
+ private final Optimum[] opts = new Optimum[OPTS];
+ private int optCur = 0;
+ private int optEnd = 0;
+
+ private Matches matches;
+
+ // These are fields solely to avoid allocating the objects again and
+ // again on each function call.
+ private final int[] repLens = new int[REPS];
+ private final State nextState = new State();
+
+ static int getMemoryUsage(int dictSize, int extraSizeBefore, int mf) {
+ return LZEncoder.getMemoryUsage(dictSize,
+ Math.max(extraSizeBefore, EXTRA_SIZE_BEFORE),
+ EXTRA_SIZE_AFTER, MATCH_LEN_MAX, mf)
+ + OPTS * 64 / 1024;
+ }
+
+ LZMAEncoderNormal(RangeEncoder rc, int lc, int lp, int pb,
+ int dictSize, int extraSizeBefore,
+ int niceLen, int mf, int depthLimit) {
+ super(rc, LZEncoder.getInstance(dictSize,
+ Math.max(extraSizeBefore,
+ EXTRA_SIZE_BEFORE),
+ EXTRA_SIZE_AFTER,
+ niceLen, MATCH_LEN_MAX,
+ mf, depthLimit),
+ lc, lp, pb, dictSize, niceLen);
+
+ for (int i = 0; i < OPTS; ++i)
+ opts[i] = new Optimum();
+ }
+
+ public void reset() {
+ optCur = 0;
+ optEnd = 0;
+ super.reset();
+ }
+
+ /**
+ * Converts the opts array from backward indexes to forward indexes.
+ * Then it will be simple to get the next symbol from the array
+ * in later calls to <code>getNextSymbol()</code>.
+ */
+ private int convertOpts() {
+ optEnd = optCur;
+
+ int optPrev = opts[optCur].optPrev;
+
+ do {
+ Optimum opt = opts[optCur];
+
+ if (opt.prev1IsLiteral) {
+ opts[optPrev].optPrev = optCur;
+ opts[optPrev].backPrev = -1;
+ optCur = optPrev--;
+
+ if (opt.hasPrev2) {
+ opts[optPrev].optPrev = optPrev + 1;
+ opts[optPrev].backPrev = opt.backPrev2;
+ optCur = optPrev;
+ optPrev = opt.optPrev2;
+ }
+ }
+
+ int temp = opts[optPrev].optPrev;
+ opts[optPrev].optPrev = optCur;
+ optCur = optPrev;
+ optPrev = temp;
+ } while (optCur > 0);
+
+ optCur = opts[0].optPrev;
+ back = opts[optCur].backPrev;
+ return optCur;
+ }
+
+ int getNextSymbol() {
+ // If there are pending symbols from an earlier call to this
+ // function, return those symbols first.
+ if (optCur < optEnd) {
+ int len = opts[optCur].optPrev - optCur;
+ optCur = opts[optCur].optPrev;
+ back = opts[optCur].backPrev;
+ return len;
+ }
+
+ assert optCur == optEnd;
+ optCur = 0;
+ optEnd = 0;
+ back = -1;
+
+ if (readAhead == -1)
+ matches = getMatches();
+
+ // Get the number of bytes available in the dictionary, but
+ // not more than the maximum match length. If there aren't
+ // enough bytes remaining to encode a match at all, return
+ // immediately to encode this byte as a literal.
+ int avail = Math.min(lz.getAvail(), MATCH_LEN_MAX);
+ if (avail < MATCH_LEN_MIN)
+ return 1;
+
+ // Get the lengths of repeated matches.
+ int repBest = 0;
+ for (int rep = 0; rep < REPS; ++rep) {
+ repLens[rep] = lz.getMatchLen(reps[rep], avail);
+
+ if (repLens[rep] < MATCH_LEN_MIN) {
+ repLens[rep] = 0;
+ continue;
+ }
+
+ if (repLens[rep] > repLens[repBest])
+ repBest = rep;
+ }
+
+ // Return if the best repeated match is at least niceLen bytes long.
+ if (repLens[repBest] >= niceLen) {
+ back = repBest;
+ skip(repLens[repBest] - 1);
+ return repLens[repBest];
+ }
+
+ // Initialize mainLen and mainDist to the longest match found
+ // by the match finder.
+ int mainLen = 0;
+ int mainDist = 0;
+ if (matches.count > 0) {
+ mainLen = matches.len[matches.count - 1];
+ mainDist = matches.dist[matches.count - 1];
+
+ // Return if it is at least niceLen bytes long.
+ if (mainLen >= niceLen) {
+ back = mainDist + REPS;
+ skip(mainLen - 1);
+ return mainLen;
+ }
+ }
+
+ int curByte = lz.getByte(0);
+ int matchByte = lz.getByte(reps[0] + 1);
+
+ // If the match finder found no matches and this byte cannot be
+ // encoded as a repeated match (short or long), we must be return
+ // to have the byte encoded as a literal.
+ if (mainLen < MATCH_LEN_MIN && curByte != matchByte
+ && repLens[repBest] < MATCH_LEN_MIN)
+ return 1;
+
+
+ int pos = lz.getPos();
+ int posState = pos & posMask;
+
+ // Calculate the price of encoding the current byte as a literal.
+ {
+ int prevByte = lz.getByte(1);
+ int literalPrice = literalEncoder.getPrice(curByte, matchByte,
+ prevByte, pos, state);
+ opts[1].set1(literalPrice, 0, -1);
+ }
+
+ int anyMatchPrice = getAnyMatchPrice(state, posState);
+ int anyRepPrice = getAnyRepPrice(anyMatchPrice, state);
+
+ // If it is possible to encode this byte as a short rep, see if
+ // it is cheaper than encoding it as a literal.
+ if (matchByte == curByte) {
+ int shortRepPrice = getShortRepPrice(anyRepPrice,
+ state, posState);
+ if (shortRepPrice < opts[1].price)
+ opts[1].set1(shortRepPrice, 0, 0);
+ }
+
+ // Return if there is neither normal nor long repeated match. Use
+ // a short match instead of a literal if is is possible and cheaper.
+ optEnd = Math.max(mainLen, repLens[repBest]);
+ if (optEnd < MATCH_LEN_MIN) {
+ assert optEnd == 0 : optEnd;
+ back = opts[1].backPrev;
+ return 1;
+ }
+
+
+ // Update the lookup tables for distances and lengths before using
+ // those price calculation functions. (The price function above
+ // don't need these tables.)
+ updatePrices();
+
+ // Initialize the state and reps of this position in opts[].
+ // updateOptStateAndReps() will need these to get the new
+ // state and reps for the next byte.
+ opts[0].state.set(state);
+ System.arraycopy(reps, 0, opts[0].reps, 0, REPS);
+
+ // Initialize the prices for latter opts that will be used below.
+ for (int i = optEnd; i >= MATCH_LEN_MIN; --i)
+ opts[i].reset();
+
+ // Calculate the prices of repeated matches of all lengths.
+ for (int rep = 0; rep < REPS; ++rep) {
+ int repLen = repLens[rep];
+ if (repLen < MATCH_LEN_MIN)
+ continue;
+
+ int longRepPrice = getLongRepPrice(anyRepPrice, rep,
+ state, posState);
+ do {
+ int price = longRepPrice + repLenEncoder.getPrice(repLen,
+ posState);
+ if (price < opts[repLen].price)
+ opts[repLen].set1(price, 0, rep);
+ } while (--repLen >= MATCH_LEN_MIN);
+ }
+
+ // Calculate the prices of normal matches that are longer than rep0.
+ {
+ int len = Math.max(repLens[0] + 1, MATCH_LEN_MIN);
+ if (len <= mainLen) {
+ int normalMatchPrice = getNormalMatchPrice(anyMatchPrice,
+ state);
+
+ // Set i to the index of the shortest match that is
+ // at least len bytes long.
+ int i = 0;
+ while (len > matches.len[i])
+ ++i;
+
+ while (true) {
+ int dist = matches.dist[i];
+ int price = getMatchAndLenPrice(normalMatchPrice,
+ dist, len, posState);
+ if (price < opts[len].price)
+ opts[len].set1(price, 0, dist + REPS);
+
+ if (len == matches.len[i])
+ if (++i == matches.count)
+ break;
+
+ ++len;
+ }
+ }
+ }
+
+
+ avail = Math.min(lz.getAvail(), OPTS - 1);
+
+ // Get matches for later bytes and optimize the use of LZMA symbols
+ // by calculating the prices and picking the cheapest symbol
+ // combinations.
+ while (++optCur < optEnd) {
+ matches = getMatches();
+ if (matches.count > 0
+ && matches.len[matches.count - 1] >= niceLen)
+ break;
+
+ --avail;
+ ++pos;
+ posState = pos & posMask;
+
+ updateOptStateAndReps();
+ anyMatchPrice = opts[optCur].price
+ + getAnyMatchPrice(opts[optCur].state, posState);
+ anyRepPrice = getAnyRepPrice(anyMatchPrice, opts[optCur].state);
+
+ calc1BytePrices(pos, posState, avail, anyRepPrice);
+
+ if (avail >= MATCH_LEN_MIN) {
+ int startLen = calcLongRepPrices(pos, posState,
+ avail, anyRepPrice);
+ if (matches.count > 0)
+ calcNormalMatchPrices(pos, posState, avail,
+ anyMatchPrice, startLen);
+ }
+ }
+
+ return convertOpts();
+ }
+
+ /**
+ * Updates the state and reps for the current byte in the opts array.
+ */
+ private void updateOptStateAndReps() {
+ int optPrev = opts[optCur].optPrev;
+ assert optPrev < optCur;
+
+ if (opts[optCur].prev1IsLiteral) {
+ --optPrev;
+
+ if (opts[optCur].hasPrev2) {
+ opts[optCur].state.set(opts[opts[optCur].optPrev2].state);
+ if (opts[optCur].backPrev2 < REPS)
+ opts[optCur].state.updateLongRep();
+ else
+ opts[optCur].state.updateMatch();
+ } else {
+ opts[optCur].state.set(opts[optPrev].state);
+ }
+
+ opts[optCur].state.updateLiteral();
+ } else {
+ opts[optCur].state.set(opts[optPrev].state);
+ }
+
+ if (optPrev == optCur - 1) {
+ // Must be either a short rep or a literal.
+ assert opts[optCur].backPrev == 0 || opts[optCur].backPrev == -1;
+
+ if (opts[optCur].backPrev == 0)
+ opts[optCur].state.updateShortRep();
+ else
+ opts[optCur].state.updateLiteral();
+
+ System.arraycopy(opts[optPrev].reps, 0,
+ opts[optCur].reps, 0, REPS);
+ } else {
+ int back;
+ if (opts[optCur].prev1IsLiteral && opts[optCur].hasPrev2) {
+ optPrev = opts[optCur].optPrev2;
+ back = opts[optCur].backPrev2;
+ opts[optCur].state.updateLongRep();
+ } else {
+ back = opts[optCur].backPrev;
+ if (back < REPS)
+ opts[optCur].state.updateLongRep();
+ else
+ opts[optCur].state.updateMatch();
+ }
+
+ if (back < REPS) {
+ opts[optCur].reps[0] = opts[optPrev].reps[back];
+
+ int rep;
+ for (rep = 1; rep <= back; ++rep)
+ opts[optCur].reps[rep] = opts[optPrev].reps[rep - 1];
+
+ for (; rep < REPS; ++rep)
+ opts[optCur].reps[rep] = opts[optPrev].reps[rep];
+ } else {
+ opts[optCur].reps[0] = back - REPS;
+ System.arraycopy(opts[optPrev].reps, 0,
+ opts[optCur].reps, 1, REPS - 1);
+ }
+ }
+ }
+
+ /**
+ * Calculates prices of a literal, a short rep, and literal + rep0.
+ */
+ private void calc1BytePrices(int pos, int posState,
+ int avail, int anyRepPrice) {
+ // This will be set to true if using a literal or a short rep.
+ boolean nextIsByte = false;
+
+ int curByte = lz.getByte(0);
+ int matchByte = lz.getByte(opts[optCur].reps[0] + 1);
+
+ // Try a literal.
+ int literalPrice = opts[optCur].price
+ + literalEncoder.getPrice(curByte, matchByte, lz.getByte(1),
+ pos, opts[optCur].state);
+ if (literalPrice < opts[optCur + 1].price) {
+ opts[optCur + 1].set1(literalPrice, optCur, -1);
+ nextIsByte = true;
+ }
+
+ // Try a short rep.
+ if (matchByte == curByte && (opts[optCur + 1].optPrev == optCur
+ || opts[optCur + 1].backPrev != 0)) {
+ int shortRepPrice = getShortRepPrice(anyRepPrice,
+ opts[optCur].state,
+ posState);
+ if (shortRepPrice <= opts[optCur + 1].price) {
+ opts[optCur + 1].set1(shortRepPrice, optCur, 0);
+ nextIsByte = true;
+ }
+ }
+
+ // If neither a literal nor a short rep was the cheapest choice,
+ // try literal + long rep0.
+ if (!nextIsByte && matchByte != curByte && avail > MATCH_LEN_MIN) {
+ int lenLimit = Math.min(niceLen, avail - 1);
+ int len = lz.getMatchLen(1, opts[optCur].reps[0], lenLimit);
+
+ if (len >= MATCH_LEN_MIN) {
+ nextState.set(opts[optCur].state);
+ nextState.updateLiteral();
+ int nextPosState = (pos + 1) & posMask;
+ int price = literalPrice
+ + getLongRepAndLenPrice(0, len,
+ nextState, nextPosState);
+
+ int i = optCur + 1 + len;
+ while (optEnd < i)
+ opts[++optEnd].reset();
+
+ if (price < opts[i].price)
+ opts[i].set2(price, optCur, 0);
+ }
+ }
+ }
+
+ /**
+ * Calculates prices of long rep and long rep + literal + rep0.
+ */
+ private int calcLongRepPrices(int pos, int posState,
+ int avail, int anyRepPrice) {
+ int startLen = MATCH_LEN_MIN;
+ int lenLimit = Math.min(avail, niceLen);
+
+ for (int rep = 0; rep < REPS; ++rep) {
+ int len = lz.getMatchLen(opts[optCur].reps[rep], lenLimit);
+ if (len < MATCH_LEN_MIN)
+ continue;
+
+ while (optEnd < optCur + len)
+ opts[++optEnd].reset();
+
+ int longRepPrice = getLongRepPrice(anyRepPrice, rep,
+ opts[optCur].state, posState);
+
+ for (int i = len; i >= MATCH_LEN_MIN; --i) {
+ int price = longRepPrice
+ + repLenEncoder.getPrice(i, posState);
+ if (price < opts[optCur + i].price)
+ opts[optCur + i].set1(price, optCur, rep);
+ }
+
+ if (rep == 0)
+ startLen = len + 1;
+
+ int len2Limit = Math.min(niceLen, avail - len - 1);
+ int len2 = lz.getMatchLen(len + 1, opts[optCur].reps[rep],
+ len2Limit);
+
+ if (len2 >= MATCH_LEN_MIN) {
+ // Rep
+ int price = longRepPrice
+ + repLenEncoder.getPrice(len, posState);
+ nextState.set(opts[optCur].state);
+ nextState.updateLongRep();
+
+ // Literal
+ int curByte = lz.getByte(len, 0);
+ int matchByte = lz.getByte(0); // lz.getByte(len, len)
+ int prevByte = lz.getByte(len, 1);
+ price += literalEncoder.getPrice(curByte, matchByte, prevByte,
+ pos + len, nextState);
+ nextState.updateLiteral();
+
+ // Rep0
+ int nextPosState = (pos + len + 1) & posMask;
+ price += getLongRepAndLenPrice(0, len2,
+ nextState, nextPosState);
+
+ int i = optCur + len + 1 + len2;
+ while (optEnd < i)
+ opts[++optEnd].reset();
+
+ if (price < opts[i].price)
+ opts[i].set3(price, optCur, rep, len, 0);
+ }
+ }
+
+ return startLen;
+ }
+
+ /**
+ * Calculates prices of a normal match and normal match + literal + rep0.
+ */
+ private void calcNormalMatchPrices(int pos, int posState, int avail,
+ int anyMatchPrice, int startLen) {
+ // If the longest match is so long that it would not fit into
+ // the opts array, shorten the matches.
+ if (matches.len[matches.count - 1] > avail) {
+ matches.count = 0;
+ while (matches.len[matches.count] < avail)
+ ++matches.count;
+
+ matches.len[matches.count++] = avail;
+ }
+
+ if (matches.len[matches.count - 1] < startLen)
+ return;
+
+ while (optEnd < optCur + matches.len[matches.count - 1])
+ opts[++optEnd].reset();
+
+ int normalMatchPrice = getNormalMatchPrice(anyMatchPrice,
+ opts[optCur].state);
+
+ int match = 0;
+ while (startLen > matches.len[match])
+ ++match;
+
+ for (int len = startLen; ; ++len) {
+ int dist = matches.dist[match];
+
+ // Calculate the price of a match of len bytes from the nearest
+ // possible distance.
+ int matchAndLenPrice = getMatchAndLenPrice(normalMatchPrice,
+ dist, len, posState);
+ if (matchAndLenPrice < opts[optCur + len].price)
+ opts[optCur + len].set1(matchAndLenPrice,
+ optCur, dist + REPS);
+
+ if (len != matches.len[match])
+ continue;
+
+ // Try match + literal + rep0. First get the length of the rep0.
+ int len2Limit = Math.min(niceLen, avail - len - 1);
+ int len2 = lz.getMatchLen(len + 1, dist, len2Limit);
+
+ if (len2 >= MATCH_LEN_MIN) {
+ nextState.set(opts[optCur].state);
+ nextState.updateMatch();
+
+ // Literal
+ int curByte = lz.getByte(len, 0);
+ int matchByte = lz.getByte(0); // lz.getByte(len, len)
+ int prevByte = lz.getByte(len, 1);
+ int price = matchAndLenPrice
+ + literalEncoder.getPrice(curByte, matchByte,
+ prevByte, pos + len,
+ nextState);
+ nextState.updateLiteral();
+
+ // Rep0
+ int nextPosState = (pos + len + 1) & posMask;
+ price += getLongRepAndLenPrice(0, len2,
+ nextState, nextPosState);
+
+ int i = optCur + len + 1 + len2;
+ while (optEnd < i)
+ opts[++optEnd].reset();
+
+ if (price < opts[i].price)
+ opts[i].set3(price, optCur, dist + REPS, len, 0);
+ }
+
+ if (++match == matches.count)
+ break;
+ }
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/lzma/Optimum.java b/lzma/Java/Tukaani/src/org/tukaani/xz/lzma/Optimum.java
new file mode 100644
index 0000000..845ac97
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/lzma/Optimum.java
@@ -0,0 +1,73 @@
+/*
+ * Optimum
+ *
+ * Authors: Lasse Collin <lasse.collin@tukaani.org>
+ * Igor Pavlov <http://7-zip.org/>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz.lzma;
+
+final class Optimum {
+ private static final int INFINITY_PRICE = 1 << 30;
+
+ final State state = new State();
+ final int[] reps = new int[LZMACoder.REPS];
+
+ /**
+ * Cumulative price of arriving to this byte.
+ */
+ int price;
+
+ int optPrev;
+ int backPrev;
+ boolean prev1IsLiteral;
+
+ boolean hasPrev2;
+ int optPrev2;
+ int backPrev2;
+
+ /**
+ * Resets the price.
+ */
+ void reset() {
+ price = INFINITY_PRICE;
+ }
+
+ /**
+ * Sets to indicate one LZMA symbol (literal, rep, or match).
+ */
+ void set1(int newPrice, int optCur, int back) {
+ price = newPrice;
+ optPrev = optCur;
+ backPrev = back;
+ prev1IsLiteral = false;
+ }
+
+ /**
+ * Sets to indicate two LZMA symbols of which the first one is a literal.
+ */
+ void set2(int newPrice, int optCur, int back) {
+ price = newPrice;
+ optPrev = optCur + 1;
+ backPrev = back;
+ prev1IsLiteral = true;
+ hasPrev2 = false;
+ }
+
+ /**
+ * Sets to indicate three LZMA symbols of which the second one
+ * is a literal.
+ */
+ void set3(int newPrice, int optCur, int back2, int len2, int back) {
+ price = newPrice;
+ optPrev = optCur + len2 + 1;
+ backPrev = back;
+ prev1IsLiteral = true;
+ hasPrev2 = true;
+ optPrev2 = optCur;
+ backPrev2 = back2;
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/lzma/State.java b/lzma/Java/Tukaani/src/org/tukaani/xz/lzma/State.java
new file mode 100644
index 0000000..0ece860
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/lzma/State.java
@@ -0,0 +1,75 @@
+/*
+ * State
+ *
+ * Authors: Lasse Collin <lasse.collin@tukaani.org>
+ * Igor Pavlov <http://7-zip.org/>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz.lzma;
+
+final class State {
+ static final int STATES = 12;
+
+ private static final int LIT_STATES = 7;
+
+ private static final int LIT_LIT = 0;
+ private static final int MATCH_LIT_LIT = 1;
+ private static final int REP_LIT_LIT = 2;
+ private static final int SHORTREP_LIT_LIT = 3;
+ private static final int MATCH_LIT = 4;
+ private static final int REP_LIT = 5;
+ private static final int SHORTREP_LIT = 6;
+ private static final int LIT_MATCH = 7;
+ private static final int LIT_LONGREP = 8;
+ private static final int LIT_SHORTREP = 9;
+ private static final int NONLIT_MATCH = 10;
+ private static final int NONLIT_REP = 11;
+
+ private int state;
+
+ State() {}
+
+ State(State other) {
+ state = other.state;
+ }
+
+ void reset() {
+ state = LIT_LIT;
+ }
+
+ int get() {
+ return state;
+ }
+
+ void set(State other) {
+ state = other.state;
+ }
+
+ void updateLiteral() {
+ if (state <= SHORTREP_LIT_LIT)
+ state = LIT_LIT;
+ else if (state <= LIT_SHORTREP)
+ state -= 3;
+ else
+ state -= 6;
+ }
+
+ void updateMatch() {
+ state = state < LIT_STATES ? LIT_MATCH : NONLIT_MATCH;
+ }
+
+ void updateLongRep() {
+ state = state < LIT_STATES ? LIT_LONGREP : NONLIT_REP;
+ }
+
+ void updateShortRep() {
+ state = state < LIT_STATES ? LIT_SHORTREP : NONLIT_REP;
+ }
+
+ boolean isLiteral() {
+ return state < LIT_STATES;
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/package-info.java b/lzma/Java/Tukaani/src/org/tukaani/xz/package-info.java
new file mode 100644
index 0000000..6d7c1b7
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/package-info.java
@@ -0,0 +1,36 @@
+/**
+ * XZ data compression support.
+ *
+ * <h4>Introduction</h4>
+ * <p>
+ * This aims to be a complete implementation of XZ data compression
+ * in pure Java. Features:
+ * <ul>
+ * <li>Full support for the .xz file format specification version 1.0.4</li>
+ * <li>Single-threaded streamed compression and decompression</li>
+ * <li>Single-threaded decompression with limited random access support</li>
+ * <li>Raw streams (no .xz headers) for advanced users, including LZMA2
+ * with preset dictionary</li>
+ * </ul>
+ * <p>
+ * Threading is planned but it is unknown when it will be implemented.
+ * <p>
+ * For the latest source code, see the
+ * <a href="http://tukaani.org/xz/java.html">home page of XZ for Java</a>.
+ *
+ * <h4>Getting started</h4>
+ * <p>
+ * Start by reading the documentation of {@link org.tukaani.xz.XZOutputStream}
+ * and {@link org.tukaani.xz.XZInputStream}.
+ * If you use XZ inside another file format or protocol,
+ * see also {@link org.tukaani.xz.SingleXZInputStream}.
+ *
+ * <h4>Licensing</h4>
+ * <p>
+ * XZ for Java has been put into the public domain, thus you can do
+ * whatever you want with it. All the files in the package have been
+ * written by Lasse Collin and/or Igor Pavlov.
+ * <p>
+ * This software is provided "as is", without any warranty.
+ */
+package org.tukaani.xz;
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/rangecoder/RangeCoder.java b/lzma/Java/Tukaani/src/org/tukaani/xz/rangecoder/RangeCoder.java
new file mode 100644
index 0000000..df9b0c4
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/rangecoder/RangeCoder.java
@@ -0,0 +1,26 @@
+/*
+ * RangeCoder
+ *
+ * Authors: Lasse Collin <lasse.collin@tukaani.org>
+ * Igor Pavlov <http://7-zip.org/>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz.rangecoder;
+
+import java.util.Arrays;
+
+public abstract class RangeCoder {
+ static final int SHIFT_BITS = 8;
+ static final int TOP_MASK = 0xFF000000;
+ static final int BIT_MODEL_TOTAL_BITS = 11;
+ static final int BIT_MODEL_TOTAL = 1 << BIT_MODEL_TOTAL_BITS;
+ static final short PROB_INIT = (short)(BIT_MODEL_TOTAL / 2);
+ static final int MOVE_BITS = 5;
+
+ public static final void initProbs(short[] probs) {
+ Arrays.fill(probs, PROB_INIT);
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/rangecoder/RangeDecoder.java b/lzma/Java/Tukaani/src/org/tukaani/xz/rangecoder/RangeDecoder.java
new file mode 100644
index 0000000..e63532e
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/rangecoder/RangeDecoder.java
@@ -0,0 +1,83 @@
+/*
+ * RangeDecoder
+ *
+ * Authors: Lasse Collin <lasse.collin@tukaani.org>
+ * Igor Pavlov <http://7-zip.org/>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz.rangecoder;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+public abstract class RangeDecoder extends RangeCoder {
+ int range = 0;
+ int code = 0;
+
+ public abstract void normalize() throws IOException;
+
+ public int decodeBit(short[] probs, int index) throws IOException {
+ normalize();
+
+ int prob = probs[index];
+ int bound = (range >>> BIT_MODEL_TOTAL_BITS) * prob;
+ int bit;
+
+ // Compare code and bound as if they were unsigned 32-bit integers.
+ if ((code ^ 0x80000000) < (bound ^ 0x80000000)) {
+ range = bound;
+ probs[index] = (short)(
+ prob + ((BIT_MODEL_TOTAL - prob) >>> MOVE_BITS));
+ bit = 0;
+ } else {
+ range -= bound;
+ code -= bound;
+ probs[index] = (short)(prob - (prob >>> MOVE_BITS));
+ bit = 1;
+ }
+
+ return bit;
+ }
+
+ public int decodeBitTree(short[] probs) throws IOException {
+ int symbol = 1;
+
+ do {
+ symbol = (symbol << 1) | decodeBit(probs, symbol);
+ } while (symbol < probs.length);
+
+ return symbol - probs.length;
+ }
+
+ public int decodeReverseBitTree(short[] probs) throws IOException {
+ int symbol = 1;
+ int i = 0;
+ int result = 0;
+
+ do {
+ int bit = decodeBit(probs, symbol);
+ symbol = (symbol << 1) | bit;
+ result |= bit << i++;
+ } while (symbol < probs.length);
+
+ return result;
+ }
+
+ public int decodeDirectBits(int count) throws IOException {
+ int result = 0;
+
+ do {
+ normalize();
+
+ range >>>= 1;
+ int t = (code - range) >>> 31;
+ code -= range & (t - 1);
+ result = (result << 1) | (1 - t);
+ } while (--count != 0);
+
+ return result;
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/rangecoder/RangeDecoderFromBuffer.java b/lzma/Java/Tukaani/src/org/tukaani/xz/rangecoder/RangeDecoderFromBuffer.java
new file mode 100644
index 0000000..cac7a7e
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/rangecoder/RangeDecoderFromBuffer.java
@@ -0,0 +1,64 @@
+/*
+ * RangeDecoderFromBuffer
+ *
+ * Authors: Lasse Collin <lasse.collin@tukaani.org>
+ * Igor Pavlov <http://7-zip.org/>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz.rangecoder;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import org.tukaani.xz.CorruptedInputException;
+
+public final class RangeDecoderFromBuffer extends RangeDecoder {
+ private static final int INIT_SIZE = 5;
+
+ private final byte[] buf;
+ private int pos = 0;
+ private int end = 0;
+
+ public RangeDecoderFromBuffer(int inputSizeMax) {
+ buf = new byte[inputSizeMax - INIT_SIZE];
+ }
+
+ public void prepareInputBuffer(DataInputStream in, int len)
+ throws IOException {
+ if (len < INIT_SIZE)
+ throw new CorruptedInputException();
+
+ if (in.readUnsignedByte() != 0x00)
+ throw new CorruptedInputException();
+
+ code = in.readInt();
+ range = 0xFFFFFFFF;
+
+ pos = 0;
+ end = len - INIT_SIZE;
+ in.readFully(buf, 0, end);
+ }
+
+ public boolean isInBufferOK() {
+ return pos <= end;
+ }
+
+ public boolean isFinished() {
+ return pos == end && code == 0;
+ }
+
+ public void normalize() throws IOException {
+ if ((range & TOP_MASK) == 0) {
+ try {
+ // If the input is corrupt, this might throw
+ // ArrayIndexOutOfBoundsException.
+ code = (code << SHIFT_BITS) | (buf[pos++] & 0xFF);
+ range <<= SHIFT_BITS;
+ } catch (ArrayIndexOutOfBoundsException e) {
+ throw new CorruptedInputException();
+ }
+ }
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/rangecoder/RangeDecoderFromStream.java b/lzma/Java/Tukaani/src/org/tukaani/xz/rangecoder/RangeDecoderFromStream.java
new file mode 100644
index 0000000..142b518
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/rangecoder/RangeDecoderFromStream.java
@@ -0,0 +1,41 @@
+/*
+ * RangeDecoderFromStream
+ *
+ * Authors: Lasse Collin <lasse.collin@tukaani.org>
+ * Igor Pavlov <http://7-zip.org/>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz.rangecoder;
+
+import java.io.InputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+import org.tukaani.xz.CorruptedInputException;
+
+public final class RangeDecoderFromStream extends RangeDecoder {
+ private final DataInputStream inData;
+
+ public RangeDecoderFromStream(InputStream in) throws IOException {
+ inData = new DataInputStream(in);
+
+ if (inData.readUnsignedByte() != 0x00)
+ throw new CorruptedInputException();
+
+ code = inData.readInt();
+ range = 0xFFFFFFFF;
+ }
+
+ public boolean isFinished() {
+ return code == 0;
+ }
+
+ public void normalize() throws IOException {
+ if ((range & TOP_MASK) == 0) {
+ code = (code << SHIFT_BITS) | inData.readUnsignedByte();
+ range <<= SHIFT_BITS;
+ }
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/rangecoder/RangeEncoder.java b/lzma/Java/Tukaani/src/org/tukaani/xz/rangecoder/RangeEncoder.java
new file mode 100644
index 0000000..a06fdcc
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/rangecoder/RangeEncoder.java
@@ -0,0 +1,203 @@
+/*
+ * RangeEncoder
+ *
+ * Authors: Lasse Collin <lasse.collin@tukaani.org>
+ * Igor Pavlov <http://7-zip.org/>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz.rangecoder;
+
+import java.io.OutputStream;
+import java.io.IOException;
+
+public final class RangeEncoder extends RangeCoder {
+ private static final int MOVE_REDUCING_BITS = 4;
+ private static final int BIT_PRICE_SHIFT_BITS = 4;
+
+ private static final int[] prices
+ = new int[BIT_MODEL_TOTAL >>> MOVE_REDUCING_BITS];
+
+ private long low;
+ private int range;
+
+ // NOTE: int is OK for LZMA2 because a compressed chunk
+ // is not more than 64 KiB, but with LZMA1 there is no chunking
+ // so in theory cacheSize can grow very big. To be very safe,
+ // use long instead of int if you adapt this code for LZMA1.
+ private int cacheSize;
+ private byte cache;
+
+ private final byte[] buf;
+ private int bufPos;
+
+ static {
+ for (int i = (1 << MOVE_REDUCING_BITS) / 2; i < BIT_MODEL_TOTAL;
+ i += (1 << MOVE_REDUCING_BITS)) {
+ int w = i;
+ int bitCount = 0;
+
+ for (int j = 0; j < BIT_PRICE_SHIFT_BITS; ++j) {
+ w *= w;
+ bitCount <<= 1;
+
+ while ((w & 0xFFFF0000) != 0) {
+ w >>>= 1;
+ ++bitCount;
+ }
+ }
+
+ prices[i >> MOVE_REDUCING_BITS]
+ = (BIT_MODEL_TOTAL_BITS << BIT_PRICE_SHIFT_BITS)
+ - 15 - bitCount;
+ }
+ }
+
+ public RangeEncoder(int bufSize) {
+ buf = new byte[bufSize];
+ reset();
+ }
+
+ public void reset() {
+ low = 0;
+ range = 0xFFFFFFFF;
+ cache = 0x00;
+ cacheSize = 1;
+ bufPos = 0;
+ }
+
+ public int getPendingSize() {
+ return bufPos + cacheSize + 5 - 1;
+ }
+
+ public int finish() {
+ for (int i = 0; i < 5; ++i)
+ shiftLow();
+
+ return bufPos;
+ }
+
+ public void write(OutputStream out) throws IOException {
+ out.write(buf, 0, bufPos);
+ }
+
+ private void shiftLow() {
+ int lowHi = (int)(low >>> 32);
+
+ if (lowHi != 0 || low < 0xFF000000L) {
+ int temp = cache;
+
+ do {
+ buf[bufPos++] = (byte)(temp + lowHi);
+ temp = 0xFF;
+ } while (--cacheSize != 0);
+
+ cache = (byte)(low >>> 24);
+ }
+
+ ++cacheSize;
+ low = (low & 0x00FFFFFF) << 8;
+ }
+
+ public void encodeBit(short[] probs, int index, int bit) {
+ int prob = probs[index];
+ int bound = (range >>> BIT_MODEL_TOTAL_BITS) * prob;
+
+ // NOTE: Any non-zero value for bit is taken as 1.
+ if (bit == 0) {
+ range = bound;
+ probs[index] = (short)(
+ prob + ((BIT_MODEL_TOTAL - prob) >>> MOVE_BITS));
+ } else {
+ low += bound & 0xFFFFFFFFL;
+ range -= bound;
+ probs[index] = (short)(prob - (prob >>> MOVE_BITS));
+ }
+
+ if ((range & TOP_MASK) == 0) {
+ range <<= SHIFT_BITS;
+ shiftLow();
+ }
+ }
+
+ public static int getBitPrice(int prob, int bit) {
+ // NOTE: Unlike in encodeBit(), here bit must be 0 or 1.
+ assert bit == 0 || bit == 1;
+ return prices[(prob ^ ((-bit) & (BIT_MODEL_TOTAL - 1)))
+ >>> MOVE_REDUCING_BITS];
+ }
+
+ public void encodeBitTree(short[] probs, int symbol) {
+ int index = 1;
+ int mask = probs.length;
+
+ do {
+ mask >>>= 1;
+ int bit = symbol & mask;
+ encodeBit(probs, index, bit);
+
+ index <<= 1;
+ if (bit != 0)
+ index |= 1;
+
+ } while (mask != 1);
+ }
+
+ public static int getBitTreePrice(short[] probs, int symbol) {
+ int price = 0;
+ symbol |= probs.length;
+
+ do {
+ int bit = symbol & 1;
+ symbol >>>= 1;
+ price += getBitPrice(probs[symbol], bit);
+ } while (symbol != 1);
+
+ return price;
+ }
+
+ public void encodeReverseBitTree(short[] probs, int symbol) {
+ int index = 1;
+ symbol |= probs.length;
+
+ do {
+ int bit = symbol & 1;
+ symbol >>>= 1;
+ encodeBit(probs, index, bit);
+ index = (index << 1) | bit;
+ } while (symbol != 1);
+ }
+
+ public static int getReverseBitTreePrice(short[] probs, int symbol) {
+ int price = 0;
+ int index = 1;
+ symbol |= probs.length;
+
+ do {
+ int bit = symbol & 1;
+ symbol >>>= 1;
+ price += getBitPrice(probs[index], bit);
+ index = (index << 1) | bit;
+ } while (symbol != 1);
+
+ return price;
+ }
+
+ public void encodeDirectBits(int value, int count) {
+ do {
+ range >>>= 1;
+ low += range & (0 - ((value >>> --count) & 1));
+
+ if ((range & TOP_MASK) == 0) {
+ range <<= SHIFT_BITS;
+ shiftLow();
+ }
+ } while (count != 0);
+ }
+
+ public static int getDirectBitsPrice(int count) {
+ return count << BIT_PRICE_SHIFT_BITS;
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/simple/ARM.java b/lzma/Java/Tukaani/src/org/tukaani/xz/simple/ARM.java
new file mode 100644
index 0000000..6febf78
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/simple/ARM.java
@@ -0,0 +1,50 @@
+/*
+ * BCJ filter for little endian ARM instructions
+ *
+ * Authors: Lasse Collin <lasse.collin@tukaani.org>
+ * Igor Pavlov <http://7-zip.org/>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz.simple;
+
+public final class ARM implements SimpleFilter {
+ private final boolean isEncoder;
+ private int pos;
+
+ public ARM(boolean isEncoder, int startPos) {
+ this.isEncoder = isEncoder;
+ pos = startPos + 8;
+ }
+
+ public int code(byte[] buf, int off, int len) {
+ int end = off + len - 4;
+ int i;
+
+ for (i = off; i <= end; i += 4) {
+ if ((buf[i + 3] & 0xFF) == 0xEB) {
+ int src = ((buf[i + 2] & 0xFF) << 16)
+ | ((buf[i + 1] & 0xFF) << 8)
+ | (buf[i] & 0xFF);
+ src <<= 2;
+
+ int dest;
+ if (isEncoder)
+ dest = src + (pos + i - off);
+ else
+ dest = src - (pos + i - off);
+
+ dest >>>= 2;
+ buf[i + 2] = (byte)(dest >>> 16);
+ buf[i + 1] = (byte)(dest >>> 8);
+ buf[i] = (byte)dest;
+ }
+ }
+
+ i -= off;
+ pos += i;
+ return i;
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/simple/ARMThumb.java b/lzma/Java/Tukaani/src/org/tukaani/xz/simple/ARMThumb.java
new file mode 100644
index 0000000..b8e7ca9
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/simple/ARMThumb.java
@@ -0,0 +1,53 @@
+/*
+ * BCJ filter for little endian ARM-Thumb instructions
+ *
+ * Authors: Lasse Collin <lasse.collin@tukaani.org>
+ * Igor Pavlov <http://7-zip.org/>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz.simple;
+
+public final class ARMThumb implements SimpleFilter {
+ private final boolean isEncoder;
+ private int pos;
+
+ public ARMThumb(boolean isEncoder, int startPos) {
+ this.isEncoder = isEncoder;
+ pos = startPos + 4;
+ }
+
+ public int code(byte[] buf, int off, int len) {
+ int end = off + len - 4;
+ int i;
+
+ for (i = off; i <= end; i += 2) {
+ if ((buf[i + 1] & 0xF8) == 0xF0 && (buf[i + 3] & 0xF8) == 0xF8) {
+ int src = ((buf[i + 1] & 0x07) << 19)
+ | ((buf[i] & 0xFF) << 11)
+ | ((buf[i + 3] & 0x07) << 8)
+ | (buf[i + 2] & 0xFF);
+ src <<= 1;
+
+ int dest;
+ if (isEncoder)
+ dest = src + (pos + i - off);
+ else
+ dest = src - (pos + i - off);
+
+ dest >>>= 1;
+ buf[i + 1] = (byte)(0xF0 | ((dest >>> 19) & 0x07));
+ buf[i] = (byte)(dest >>> 11);
+ buf[i + 3] = (byte)(0xF8 | ((dest >>> 8) & 0x07));
+ buf[i + 2] = (byte)dest;
+ i += 2;
+ }
+ }
+
+ i -= off;
+ pos += i;
+ return i;
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/simple/IA64.java b/lzma/Java/Tukaani/src/org/tukaani/xz/simple/IA64.java
new file mode 100644
index 0000000..776a1b7
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/simple/IA64.java
@@ -0,0 +1,81 @@
+/*
+ * BCJ filter for Itanium (IA-64) instructions
+ *
+ * Authors: Lasse Collin <lasse.collin@tukaani.org>
+ * Igor Pavlov <http://7-zip.org/>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz.simple;
+
+public final class IA64 implements SimpleFilter {
+ private static final int[] BRANCH_TABLE = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 4, 4, 6, 6, 0, 0, 7, 7,
+ 4, 4, 0, 0, 4, 4, 0, 0 };
+
+ private final boolean isEncoder;
+ private int pos;
+
+ public IA64(boolean isEncoder, int startPos) {
+ this.isEncoder = isEncoder;
+ pos = startPos;
+ }
+
+ public int code(byte[] buf, int off, int len) {
+ int end = off + len - 16;
+ int i;
+
+ for (i = off; i <= end; i += 16) {
+ int instrTemplate = buf[i] & 0x1F;
+ int mask = BRANCH_TABLE[instrTemplate];
+
+ for (int slot = 0, bitPos = 5; slot < 3; ++slot, bitPos += 41) {
+ if (((mask >>> slot) & 1) == 0)
+ continue;
+
+ int bytePos = bitPos >>> 3;
+ int bitRes = bitPos & 7;
+
+ long instr = 0;
+ for (int j = 0; j < 6; ++j)
+ instr |= (buf[i + bytePos + j] & 0xFFL) << (8 * j);
+
+ long instrNorm = instr >>> bitRes;
+
+ if (((instrNorm >>> 37) & 0x0F) != 0x05
+ || ((instrNorm >>> 9) & 0x07) != 0x00)
+ continue;
+
+ int src = (int)((instrNorm >>> 13) & 0x0FFFFF);
+ src |= ((int)(instrNorm >>> 36) & 1) << 20;
+ src <<= 4;
+
+ int dest;
+ if (isEncoder)
+ dest = src + (pos + i - off);
+ else
+ dest = src - (pos + i - off);
+
+ dest >>>= 4;
+
+ instrNorm &= ~(0x8FFFFFL << 13);
+ instrNorm |= (dest & 0x0FFFFFL) << 13;
+ instrNorm |= (dest & 0x100000L) << (36 - 20);
+
+ instr &= (1 << bitRes) - 1;
+ instr |= instrNorm << bitRes;
+
+ for (int j = 0; j < 6; ++j)
+ buf[i + bytePos + j] = (byte)(instr >>> (8 * j));
+ }
+ }
+
+ i -= off;
+ pos += i;
+ return i;
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/simple/PowerPC.java b/lzma/Java/Tukaani/src/org/tukaani/xz/simple/PowerPC.java
new file mode 100644
index 0000000..b7400ab
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/simple/PowerPC.java
@@ -0,0 +1,50 @@
+/*
+ * BCJ filter for big endian PowerPC instructions
+ *
+ * Authors: Lasse Collin <lasse.collin@tukaani.org>
+ * Igor Pavlov <http://7-zip.org/>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz.simple;
+
+public final class PowerPC implements SimpleFilter {
+ private final boolean isEncoder;
+ private int pos;
+
+ public PowerPC(boolean isEncoder, int startPos) {
+ this.isEncoder = isEncoder;
+ pos = startPos;
+ }
+
+ public int code(byte[] buf, int off, int len) {
+ int end = off + len - 4;
+ int i;
+
+ for (i = off; i <= end; i += 4) {
+ if ((buf[i] & 0xFC) == 0x48 && (buf[i + 3] & 0x03) == 0x01) {
+ int src = ((buf[i] & 0x03) << 24)
+ | ((buf[i + 1] & 0xFF) << 16)
+ | ((buf[i + 2] & 0xFF) << 8)
+ | (buf[i + 3] & 0xFC);
+
+ int dest;
+ if (isEncoder)
+ dest = src + (pos + i - off);
+ else
+ dest = src - (pos + i - off);
+
+ buf[i] = (byte)(0x48 | ((dest >>> 24) & 0x03));
+ buf[i + 1] = (byte)(dest >>> 16);
+ buf[i + 2] = (byte)(dest >>> 8);
+ buf[i + 3] = (byte)((buf[i + 3] & 0x03) | dest);
+ }
+ }
+
+ i -= off;
+ pos += i;
+ return i;
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/simple/SPARC.java b/lzma/Java/Tukaani/src/org/tukaani/xz/simple/SPARC.java
new file mode 100644
index 0000000..913c8ac
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/simple/SPARC.java
@@ -0,0 +1,56 @@
+/*
+ * BCJ filter for SPARC instructions
+ *
+ * Authors: Lasse Collin <lasse.collin@tukaani.org>
+ * Igor Pavlov <http://7-zip.org/>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz.simple;
+
+public final class SPARC implements SimpleFilter {
+ private final boolean isEncoder;
+ private int pos;
+
+ public SPARC(boolean isEncoder, int startPos) {
+ this.isEncoder = isEncoder;
+ pos = startPos;
+ }
+
+ public int code(byte[] buf, int off, int len) {
+ int end = off + len - 4;
+ int i;
+
+ for (i = off; i <= end; i += 4) {
+ if ((buf[i] == 0x40 && (buf[i + 1] & 0xC0) == 0x00)
+ || (buf[i] == 0x7F && (buf[i + 1] & 0xC0) == 0xC0)) {
+ int src = ((buf[i] & 0xFF) << 24)
+ | ((buf[i + 1] & 0xFF) << 16)
+ | ((buf[i + 2] & 0xFF) << 8)
+ | (buf[i + 3] & 0xFF);
+ src <<= 2;
+
+ int dest;
+ if (isEncoder)
+ dest = src + (pos + i - off);
+ else
+ dest = src - (pos + i - off);
+
+ dest >>>= 2;
+ dest = (((0 - ((dest >>> 22) & 1)) << 22) & 0x3FFFFFFF)
+ | (dest & 0x3FFFFF) | 0x40000000;
+
+ buf[i] = (byte)(dest >>> 24);
+ buf[i + 1] = (byte)(dest >>> 16);
+ buf[i + 2] = (byte)(dest >>> 8);
+ buf[i + 3] = (byte)dest;
+ }
+ }
+
+ i -= off;
+ pos += i;
+ return i;
+ }
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/simple/SimpleFilter.java b/lzma/Java/Tukaani/src/org/tukaani/xz/simple/SimpleFilter.java
new file mode 100644
index 0000000..6f72906
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/simple/SimpleFilter.java
@@ -0,0 +1,14 @@
+/*
+ * BCJ filter for little endian ARM instructions
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz.simple;
+
+public interface SimpleFilter {
+ int code(byte[] buf, int off, int len);
+}
diff --git a/lzma/Java/Tukaani/src/org/tukaani/xz/simple/X86.java b/lzma/Java/Tukaani/src/org/tukaani/xz/simple/X86.java
new file mode 100644
index 0000000..a05e08b
--- /dev/null
+++ b/lzma/Java/Tukaani/src/org/tukaani/xz/simple/X86.java
@@ -0,0 +1,98 @@
+/*
+ * BCJ filter for x86 instructions
+ *
+ * Authors: Lasse Collin <lasse.collin@tukaani.org>
+ * Igor Pavlov <http://7-zip.org/>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+package org.tukaani.xz.simple;
+
+public final class X86 implements SimpleFilter {
+ private static final boolean[] MASK_TO_ALLOWED_STATUS
+ = {true, true, true, false, true, false, false, false};
+
+ private static final int[] MASK_TO_BIT_NUMBER = {0, 1, 2, 2, 3, 3, 3, 3};
+
+ private final boolean isEncoder;
+ private int pos;
+ private int prevMask = 0;
+
+ private static boolean test86MSByte(byte b) {
+ int i = b & 0xFF;
+ return i == 0x00 || i == 0xFF;
+ }
+
+ public X86(boolean isEncoder, int startPos) {
+ this.isEncoder = isEncoder;
+ pos = startPos + 5;
+ }
+
+ public int code(byte[] buf, int off, int len) {
+ int prevPos = off - 1;
+ int end = off + len - 5;
+ int i;
+
+ for (i = off; i <= end; ++i) {
+ if ((buf[i] & 0xFE) != 0xE8)
+ continue;
+
+ prevPos = i - prevPos;
+ if ((prevPos & ~3) != 0) { // (unsigned)prevPos > 3
+ prevMask = 0;
+ } else {
+ prevMask = (prevMask << (prevPos - 1)) & 7;
+ if (prevMask != 0) {
+ if (!MASK_TO_ALLOWED_STATUS[prevMask] || test86MSByte(
+ buf[i + 4 - MASK_TO_BIT_NUMBER[prevMask]])) {
+ prevPos = i;
+ prevMask = (prevMask << 1) | 1;
+ continue;
+ }
+ }
+ }
+
+ prevPos = i;
+
+ if (test86MSByte(buf[i + 4])) {
+ int src = (buf[i + 1] & 0xFF)
+ | ((buf[i + 2] & 0xFF) << 8)
+ | ((buf[i + 3] & 0xFF) << 16)
+ | ((buf[i + 4] & 0xFF) << 24);
+ int dest;
+ while (true) {
+ if (isEncoder)
+ dest = src + (pos + i - off);
+ else
+ dest = src - (pos + i - off);
+
+ if (prevMask == 0)
+ break;
+
+ int index = MASK_TO_BIT_NUMBER[prevMask] * 8;
+ if (!test86MSByte((byte)(dest >>> (24 - index))))
+ break;
+
+ src = dest ^ ((1 << (32 - index)) - 1);
+ }
+
+ buf[i + 1] = (byte)dest;
+ buf[i + 2] = (byte)(dest >>> 8);
+ buf[i + 3] = (byte)(dest >>> 16);
+ buf[i + 4] = (byte)(~(((dest >>> 24) & 1) - 1));
+ i += 4;
+ } else {
+ prevMask = (prevMask << 1) | 1;
+ }
+ }
+
+ prevPos = i - prevPos;
+ prevMask = ((prevPos & ~3) != 0) ? 0 : prevMask << (prevPos - 1);
+
+ i -= off;
+ pos += i;
+ return i;
+ }
+}
diff --git a/lzma/MODULE_LICENSE_PUBLIC_DOMAIN b/lzma/MODULE_LICENSE_PUBLIC_DOMAIN
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/lzma/MODULE_LICENSE_PUBLIC_DOMAIN
diff --git a/lzma/NOTICE b/lzma/NOTICE
new file mode 100644
index 0000000..8677bf6
--- /dev/null
+++ b/lzma/NOTICE
@@ -0,0 +1,11 @@
+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)
+
+You can copy, modify, distribute and perform LZMA SDK code, even for commercial purposes,
+all without asking permission.
+
+LZMA SDK code is compatible with open source licenses, for example, you can
+include it to GNU GPL or GNU LGPL code.
diff --git a/lzma/xz-embedded/Android.mk b/lzma/xz-embedded/Android.mk
new file mode 100644
index 0000000..20dd88f
--- /dev/null
+++ b/lzma/xz-embedded/Android.mk
@@ -0,0 +1,21 @@
+# Copyright 2013 The Android Open Source Project
+#
+LOCAL_PATH := $(call my-dir)
+
+xz_embedded_sources := \
+ xz_crc32.c \
+ xz_dec_bcj.c \
+ xz_dec_lzma2.c \
+ xz_dec_stream.c
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libxz
+LOCAL_SRC_FILES := $(xz_embedded_sources)
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libxz-host
+LOCAL_SRC_FILES := $(xz_embedded_sources)
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+include $(BUILD_HOST_STATIC_LIBRARY)
diff --git a/lzma/xz-embedded/xz.h b/lzma/xz-embedded/xz.h
new file mode 100644
index 0000000..0a4b38d
--- /dev/null
+++ b/lzma/xz-embedded/xz.h
@@ -0,0 +1,304 @@
+/*
+ * XZ decompressor
+ *
+ * Authors: Lasse Collin <lasse.collin@tukaani.org>
+ * Igor Pavlov <http://7-zip.org/>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+#ifndef XZ_H
+#define XZ_H
+
+#ifdef __KERNEL__
+# include <linux/stddef.h>
+# include <linux/types.h>
+#else
+# include <stddef.h>
+# include <stdint.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* In Linux, this is used to make extern functions static when needed. */
+#ifndef XZ_EXTERN
+# define XZ_EXTERN extern
+#endif
+
+/**
+ * enum xz_mode - Operation mode
+ *
+ * @XZ_SINGLE: Single-call mode. This uses less RAM than
+ * than multi-call modes, because the LZMA2
+ * dictionary doesn't need to be allocated as
+ * part of the decoder state. All required data
+ * structures are allocated at initialization,
+ * so xz_dec_run() cannot return XZ_MEM_ERROR.
+ * @XZ_PREALLOC: Multi-call mode with preallocated LZMA2
+ * dictionary buffer. All data structures are
+ * allocated at initialization, so xz_dec_run()
+ * cannot return XZ_MEM_ERROR.
+ * @XZ_DYNALLOC: Multi-call mode. The LZMA2 dictionary is
+ * allocated once the required size has been
+ * parsed from the stream headers. If the
+ * allocation fails, xz_dec_run() will return
+ * XZ_MEM_ERROR.
+ *
+ * It is possible to enable support only for a subset of the above
+ * modes at compile time by defining XZ_DEC_SINGLE, XZ_DEC_PREALLOC,
+ * or XZ_DEC_DYNALLOC. The xz_dec kernel module is always compiled
+ * with support for all operation modes, but the preboot code may
+ * be built with fewer features to minimize code size.
+ */
+enum xz_mode {
+ XZ_SINGLE,
+ XZ_PREALLOC,
+ XZ_DYNALLOC
+};
+
+/**
+ * enum xz_ret - Return codes
+ * @XZ_OK: Everything is OK so far. More input or more
+ * output space is required to continue. This
+ * return code is possible only in multi-call mode
+ * (XZ_PREALLOC or XZ_DYNALLOC).
+ * @XZ_STREAM_END: Operation finished successfully.
+ * @XZ_UNSUPPORTED_CHECK: Integrity check type is not supported. Decoding
+ * is still possible in multi-call mode by simply
+ * calling xz_dec_run() again.
+ * Note that this return value is used only if
+ * XZ_DEC_ANY_CHECK was defined at build time,
+ * which is not used in the kernel. Unsupported
+ * check types return XZ_OPTIONS_ERROR if
+ * XZ_DEC_ANY_CHECK was not defined at build time.
+ * @XZ_MEM_ERROR: Allocating memory failed. This return code is
+ * possible only if the decoder was initialized
+ * with XZ_DYNALLOC. The amount of memory that was
+ * tried to be allocated was no more than the
+ * dict_max argument given to xz_dec_init().
+ * @XZ_MEMLIMIT_ERROR: A bigger LZMA2 dictionary would be needed than
+ * allowed by the dict_max argument given to
+ * xz_dec_init(). This return value is possible
+ * only in multi-call mode (XZ_PREALLOC or
+ * XZ_DYNALLOC); the single-call mode (XZ_SINGLE)
+ * ignores the dict_max argument.
+ * @XZ_FORMAT_ERROR: File format was not recognized (wrong magic
+ * bytes).
+ * @XZ_OPTIONS_ERROR: This implementation doesn't support the requested
+ * compression options. In the decoder this means
+ * that the header CRC32 matches, but the header
+ * itself specifies something that we don't support.
+ * @XZ_DATA_ERROR: Compressed data is corrupt.
+ * @XZ_BUF_ERROR: Cannot make any progress. Details are slightly
+ * different between multi-call and single-call
+ * mode; more information below.
+ *
+ * In multi-call mode, XZ_BUF_ERROR is returned when two consecutive calls
+ * to XZ code cannot consume any input and cannot produce any new output.
+ * This happens when there is no new input available, or the output buffer
+ * is full while at least one output byte is still pending. Assuming your
+ * code is not buggy, you can get this error only when decoding a compressed
+ * stream that is truncated or otherwise corrupt.
+ *
+ * In single-call mode, XZ_BUF_ERROR is returned only when the output buffer
+ * is too small or the compressed input is corrupt in a way that makes the
+ * decoder produce more output than the caller expected. When it is
+ * (relatively) clear that the compressed input is truncated, XZ_DATA_ERROR
+ * is used instead of XZ_BUF_ERROR.
+ */
+enum xz_ret {
+ XZ_OK,
+ XZ_STREAM_END,
+ XZ_UNSUPPORTED_CHECK,
+ XZ_MEM_ERROR,
+ XZ_MEMLIMIT_ERROR,
+ XZ_FORMAT_ERROR,
+ XZ_OPTIONS_ERROR,
+ XZ_DATA_ERROR,
+ XZ_BUF_ERROR
+};
+
+/**
+ * struct xz_buf - Passing input and output buffers to XZ code
+ * @in: Beginning of the input buffer. This may be NULL if and only
+ * if in_pos is equal to in_size.
+ * @in_pos: Current position in the input buffer. This must not exceed
+ * in_size.
+ * @in_size: Size of the input buffer
+ * @out: Beginning of the output buffer. This may be NULL if and only
+ * if out_pos is equal to out_size.
+ * @out_pos: Current position in the output buffer. This must not exceed
+ * out_size.
+ * @out_size: Size of the output buffer
+ *
+ * Only the contents of the output buffer from out[out_pos] onward, and
+ * the variables in_pos and out_pos are modified by the XZ code.
+ */
+struct xz_buf {
+ const uint8_t *in;
+ size_t in_pos;
+ size_t in_size;
+
+ uint8_t *out;
+ size_t out_pos;
+ size_t out_size;
+};
+
+/**
+ * struct xz_dec - Opaque type to hold the XZ decoder state
+ */
+struct xz_dec;
+
+/**
+ * xz_dec_init() - Allocate and initialize a XZ decoder state
+ * @mode: Operation mode
+ * @dict_max: Maximum size of the LZMA2 dictionary (history buffer) for
+ * multi-call decoding. This is ignored in single-call mode
+ * (mode == XZ_SINGLE). LZMA2 dictionary is always 2^n bytes
+ * or 2^n + 2^(n-1) bytes (the latter sizes are less common
+ * in practice), so other values for dict_max don't make sense.
+ * In the kernel, dictionary sizes of 64 KiB, 128 KiB, 256 KiB,
+ * 512 KiB, and 1 MiB are probably the only reasonable values,
+ * except for kernel and initramfs images where a bigger
+ * dictionary can be fine and useful.
+ *
+ * Single-call mode (XZ_SINGLE): xz_dec_run() decodes the whole stream at
+ * once. The caller must provide enough output space or the decoding will
+ * fail. The output space is used as the dictionary buffer, which is why
+ * there is no need to allocate the dictionary as part of the decoder's
+ * internal state.
+ *
+ * Because the output buffer is used as the workspace, streams encoded using
+ * a big dictionary are not a problem in single-call mode. It is enough that
+ * the output buffer is big enough to hold the actual uncompressed data; it
+ * can be smaller than the dictionary size stored in the stream headers.
+ *
+ * Multi-call mode with preallocated dictionary (XZ_PREALLOC): dict_max bytes
+ * of memory is preallocated for the LZMA2 dictionary. This way there is no
+ * risk that xz_dec_run() could run out of memory, since xz_dec_run() will
+ * never allocate any memory. Instead, if the preallocated dictionary is too
+ * small for decoding the given input stream, xz_dec_run() will return
+ * XZ_MEMLIMIT_ERROR. Thus, it is important to know what kind of data will be
+ * decoded to avoid allocating excessive amount of memory for the dictionary.
+ *
+ * Multi-call mode with dynamically allocated dictionary (XZ_DYNALLOC):
+ * dict_max specifies the maximum allowed dictionary size that xz_dec_run()
+ * may allocate once it has parsed the dictionary size from the stream
+ * headers. This way excessive allocations can be avoided while still
+ * limiting the maximum memory usage to a sane value to prevent running the
+ * system out of memory when decompressing streams from untrusted sources.
+ *
+ * On success, xz_dec_init() returns a pointer to struct xz_dec, which is
+ * ready to be used with xz_dec_run(). If memory allocation fails,
+ * xz_dec_init() returns NULL.
+ */
+XZ_EXTERN struct xz_dec *xz_dec_init(enum xz_mode mode, uint32_t dict_max);
+
+/**
+ * xz_dec_run() - Run the XZ decoder
+ * @s: Decoder state allocated using xz_dec_init()
+ * @b: Input and output buffers
+ *
+ * The possible return values depend on build options and operation mode.
+ * See enum xz_ret for details.
+ *
+ * Note that if an error occurs in single-call mode (return value is not
+ * XZ_STREAM_END), b->in_pos and b->out_pos are not modified and the
+ * contents of the output buffer from b->out[b->out_pos] onward are
+ * undefined. This is true even after XZ_BUF_ERROR, because with some filter
+ * chains, there may be a second pass over the output buffer, and this pass
+ * cannot be properly done if the output buffer is truncated. Thus, you
+ * cannot give the single-call decoder a too small buffer and then expect to
+ * get that amount valid data from the beginning of the stream. You must use
+ * the multi-call decoder if you don't want to uncompress the whole stream.
+ */
+XZ_EXTERN enum xz_ret xz_dec_run(struct xz_dec *s, struct xz_buf *b);
+
+/**
+ * xz_dec_reset() - Reset an already allocated decoder state
+ * @s: Decoder state allocated using xz_dec_init()
+ *
+ * This function can be used to reset the multi-call decoder state without
+ * freeing and reallocating memory with xz_dec_end() and xz_dec_init().
+ *
+ * In single-call mode, xz_dec_reset() is always called in the beginning of
+ * xz_dec_run(). Thus, explicit call to xz_dec_reset() is useful only in
+ * multi-call mode.
+ */
+XZ_EXTERN void xz_dec_reset(struct xz_dec *s);
+
+/**
+ * xz_dec_end() - Free the memory allocated for the decoder state
+ * @s: Decoder state allocated using xz_dec_init(). If s is NULL,
+ * this function does nothing.
+ */
+XZ_EXTERN void xz_dec_end(struct xz_dec *s);
+
+/*
+ * Standalone build (userspace build or in-kernel build for boot time use)
+ * needs a CRC32 implementation. For normal in-kernel use, kernel's own
+ * CRC32 module is used instead, and users of this module don't need to
+ * care about the functions below.
+ */
+#ifndef XZ_INTERNAL_CRC32
+# ifdef __KERNEL__
+# define XZ_INTERNAL_CRC32 0
+# else
+# define XZ_INTERNAL_CRC32 1
+# endif
+#endif
+
+/*
+ * If CRC64 support has been enabled with XZ_USE_CRC64, a CRC64
+ * implementation is needed too.
+ */
+#ifndef XZ_USE_CRC64
+# undef XZ_INTERNAL_CRC64
+# define XZ_INTERNAL_CRC64 0
+#endif
+#ifndef XZ_INTERNAL_CRC64
+# ifdef __KERNEL__
+# error Using CRC64 in the kernel has not been implemented.
+# else
+# define XZ_INTERNAL_CRC64 1
+# endif
+#endif
+
+#if XZ_INTERNAL_CRC32
+/*
+ * This must be called before any other xz_* function to initialize
+ * the CRC32 lookup table.
+ */
+XZ_EXTERN void xz_crc32_init(void);
+
+/*
+ * Update CRC32 value using the polynomial from IEEE-802.3. To start a new
+ * calculation, the third argument must be zero. To continue the calculation,
+ * the previously returned value is passed as the third argument.
+ */
+XZ_EXTERN uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc);
+#endif
+
+#if XZ_INTERNAL_CRC64
+/*
+ * This must be called before any other xz_* function (except xz_crc32_init())
+ * to initialize the CRC64 lookup table.
+ */
+XZ_EXTERN void xz_crc64_init(void);
+
+/*
+ * Update CRC64 value using the polynomial from ECMA-182. To start a new
+ * calculation, the third argument must be zero. To continue the calculation,
+ * the previously returned value is passed as the third argument.
+ */
+XZ_EXTERN uint64_t xz_crc64(const uint8_t *buf, size_t size, uint64_t crc);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/lzma/xz-embedded/xz_config.h b/lzma/xz-embedded/xz_config.h
new file mode 100644
index 0000000..8b88c52
--- /dev/null
+++ b/lzma/xz-embedded/xz_config.h
@@ -0,0 +1,124 @@
+/*
+ * Private includes and definitions for userspace use of XZ Embedded
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+#ifndef XZ_CONFIG_H
+#define XZ_CONFIG_H
+
+/* Uncomment to enable CRC64 support. */
+/* #define XZ_USE_CRC64 */
+
+/* Uncomment as needed to enable BCJ filter decoders. */
+#define XZ_DEC_X86
+/* #define XZ_DEC_POWERPC */
+/* #define XZ_DEC_IA64 */
+#define XZ_DEC_ARM
+#define XZ_DEC_ARMTHUMB
+/* #define XZ_DEC_SPARC */
+
+/*
+ * MSVC doesn't support modern C but XZ Embedded is mostly C89
+ * so these are enough.
+ */
+#ifdef _MSC_VER
+typedef unsigned char bool;
+# define true 1
+# define false 0
+# define inline __inline
+#else
+# include <stdbool.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "xz.h"
+
+#define kmalloc(size, flags) malloc(size)
+#define kfree(ptr) free(ptr)
+#define vmalloc(size) malloc(size)
+#define vfree(ptr) free(ptr)
+
+#define memeq(a, b, size) (memcmp(a, b, size) == 0)
+#define memzero(buf, size) memset(buf, 0, size)
+
+#ifndef min
+# define min(x, y) ((x) < (y) ? (x) : (y))
+#endif
+#define min_t(type, x, y) min(x, y)
+
+/*
+ * Some functions have been marked with __always_inline to keep the
+ * performance reasonable even when the compiler is optimizing for
+ * small code size. You may be able to save a few bytes by #defining
+ * __always_inline to plain inline, but don't complain if the code
+ * becomes slow.
+ *
+ * NOTE: System headers on GNU/Linux may #define this macro already,
+ * so if you want to change it, you need to #undef it first.
+ */
+#ifndef __always_inline
+# ifdef __GNUC__
+# define __always_inline \
+ inline __attribute__((__always_inline__))
+# else
+# define __always_inline inline
+# endif
+#endif
+
+/* Inline functions to access unaligned unsigned 32-bit integers */
+#ifndef get_unaligned_le32
+static inline uint32_t get_unaligned_le32(const uint8_t *buf)
+{
+ return (uint32_t)buf[0]
+ | ((uint32_t)buf[1] << 8)
+ | ((uint32_t)buf[2] << 16)
+ | ((uint32_t)buf[3] << 24);
+}
+#endif
+
+#ifndef get_unaligned_be32
+static inline uint32_t get_unaligned_be32(const uint8_t *buf)
+{
+ return (uint32_t)(buf[0] << 24)
+ | ((uint32_t)buf[1] << 16)
+ | ((uint32_t)buf[2] << 8)
+ | (uint32_t)buf[3];
+}
+#endif
+
+#ifndef put_unaligned_le32
+static inline void put_unaligned_le32(uint32_t val, uint8_t *buf)
+{
+ buf[0] = (uint8_t)val;
+ buf[1] = (uint8_t)(val >> 8);
+ buf[2] = (uint8_t)(val >> 16);
+ buf[3] = (uint8_t)(val >> 24);
+}
+#endif
+
+#ifndef put_unaligned_be32
+static inline void put_unaligned_be32(uint32_t val, uint8_t *buf)
+{
+ buf[0] = (uint8_t)(val >> 24);
+ buf[1] = (uint8_t)(val >> 16);
+ buf[2] = (uint8_t)(val >> 8);
+ buf[3] = (uint8_t)val;
+}
+#endif
+
+/*
+ * Use get_unaligned_le32() also for aligned access for simplicity. On
+ * little endian systems, #define get_le32(ptr) (*(const uint32_t *)(ptr))
+ * could save a few bytes in code size.
+ */
+#ifndef get_le32
+# define get_le32 get_unaligned_le32
+#endif
+
+#endif
diff --git a/lzma/xz-embedded/xz_crc32.c b/lzma/xz-embedded/xz_crc32.c
new file mode 100644
index 0000000..34532d1
--- /dev/null
+++ b/lzma/xz-embedded/xz_crc32.c
@@ -0,0 +1,59 @@
+/*
+ * CRC32 using the polynomial from IEEE-802.3
+ *
+ * Authors: Lasse Collin <lasse.collin@tukaani.org>
+ * Igor Pavlov <http://7-zip.org/>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+/*
+ * This is not the fastest implementation, but it is pretty compact.
+ * The fastest versions of xz_crc32() on modern CPUs without hardware
+ * accelerated CRC instruction are 3-5 times as fast as this version,
+ * but they are bigger and use more memory for the lookup table.
+ */
+
+#include "xz_private.h"
+
+/*
+ * STATIC_RW_DATA is used in the pre-boot environment on some architectures.
+ * See <linux/decompress/mm.h> for details.
+ */
+#ifndef STATIC_RW_DATA
+# define STATIC_RW_DATA static
+#endif
+
+STATIC_RW_DATA uint32_t xz_crc32_table[256];
+
+XZ_EXTERN void xz_crc32_init(void)
+{
+ const uint32_t poly = 0xEDB88320;
+
+ uint32_t i;
+ uint32_t j;
+ uint32_t r;
+
+ for (i = 0; i < 256; ++i) {
+ r = i;
+ for (j = 0; j < 8; ++j)
+ r = (r >> 1) ^ (poly & ~((r & 1) - 1));
+
+ xz_crc32_table[i] = r;
+ }
+
+ return;
+}
+
+XZ_EXTERN uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc)
+{
+ crc = ~crc;
+
+ while (size != 0) {
+ crc = xz_crc32_table[*buf++ ^ (crc & 0xFF)] ^ (crc >> 8);
+ --size;
+ }
+
+ return ~crc;
+}
diff --git a/lzma/xz-embedded/xz_crc64.c b/lzma/xz-embedded/xz_crc64.c
new file mode 100644
index 0000000..ca1caee
--- /dev/null
+++ b/lzma/xz-embedded/xz_crc64.c
@@ -0,0 +1,50 @@
+/*
+ * CRC64 using the polynomial from ECMA-182
+ *
+ * This file is similar to xz_crc32.c. See the comments there.
+ *
+ * Authors: Lasse Collin <lasse.collin@tukaani.org>
+ * Igor Pavlov <http://7-zip.org/>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+#include "xz_private.h"
+
+#ifndef STATIC_RW_DATA
+# define STATIC_RW_DATA static
+#endif
+
+STATIC_RW_DATA uint64_t xz_crc64_table[256];
+
+XZ_EXTERN void xz_crc64_init(void)
+{
+ const uint64_t poly = 0xC96C5795D7870F42;
+
+ uint32_t i;
+ uint32_t j;
+ uint64_t r;
+
+ for (i = 0; i < 256; ++i) {
+ r = i;
+ for (j = 0; j < 8; ++j)
+ r = (r >> 1) ^ (poly & ~((r & 1) - 1));
+
+ xz_crc64_table[i] = r;
+ }
+
+ return;
+}
+
+XZ_EXTERN uint64_t xz_crc64(const uint8_t *buf, size_t size, uint64_t crc)
+{
+ crc = ~crc;
+
+ while (size != 0) {
+ crc = xz_crc64_table[*buf++ ^ (crc & 0xFF)] ^ (crc >> 8);
+ --size;
+ }
+
+ return ~crc;
+}
diff --git a/lzma/xz-embedded/xz_dec_bcj.c b/lzma/xz-embedded/xz_dec_bcj.c
new file mode 100644
index 0000000..a768e6d
--- /dev/null
+++ b/lzma/xz-embedded/xz_dec_bcj.c
@@ -0,0 +1,574 @@
+/*
+ * Branch/Call/Jump (BCJ) filter decoders
+ *
+ * Authors: Lasse Collin <lasse.collin@tukaani.org>
+ * Igor Pavlov <http://7-zip.org/>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+#include "xz_private.h"
+
+/*
+ * The rest of the file is inside this ifdef. It makes things a little more
+ * convenient when building without support for any BCJ filters.
+ */
+#ifdef XZ_DEC_BCJ
+
+struct xz_dec_bcj {
+ /* Type of the BCJ filter being used */
+ enum {
+ BCJ_X86 = 4, /* x86 or x86-64 */
+ BCJ_POWERPC = 5, /* Big endian only */
+ BCJ_IA64 = 6, /* Big or little endian */
+ BCJ_ARM = 7, /* Little endian only */
+ BCJ_ARMTHUMB = 8, /* Little endian only */
+ BCJ_SPARC = 9 /* Big or little endian */
+ } type;
+
+ /*
+ * Return value of the next filter in the chain. We need to preserve
+ * this information across calls, because we must not call the next
+ * filter anymore once it has returned XZ_STREAM_END.
+ */
+ enum xz_ret ret;
+
+ /* True if we are operating in single-call mode. */
+ bool single_call;
+
+ /*
+ * Absolute position relative to the beginning of the uncompressed
+ * data (in a single .xz Block). We care only about the lowest 32
+ * bits so this doesn't need to be uint64_t even with big files.
+ */
+ uint32_t pos;
+
+ /* x86 filter state */
+ uint32_t x86_prev_mask;
+
+ /* Temporary space to hold the variables from struct xz_buf */
+ uint8_t *out;
+ size_t out_pos;
+ size_t out_size;
+
+ struct {
+ /* Amount of already filtered data in the beginning of buf */
+ size_t filtered;
+
+ /* Total amount of data currently stored in buf */
+ size_t size;
+
+ /*
+ * Buffer to hold a mix of filtered and unfiltered data. This
+ * needs to be big enough to hold Alignment + 2 * Look-ahead:
+ *
+ * Type Alignment Look-ahead
+ * x86 1 4
+ * PowerPC 4 0
+ * IA-64 16 0
+ * ARM 4 0
+ * ARM-Thumb 2 2
+ * SPARC 4 0
+ */
+ uint8_t buf[16];
+ } temp;
+};
+
+#ifdef XZ_DEC_X86
+/*
+ * This is used to test the most significant byte of a memory address
+ * in an x86 instruction.
+ */
+static inline int bcj_x86_test_msbyte(uint8_t b)
+{
+ return b == 0x00 || b == 0xFF;
+}
+
+static size_t bcj_x86(struct xz_dec_bcj *s, uint8_t *buf, size_t size)
+{
+ static const bool mask_to_allowed_status[8]
+ = { true, true, true, false, true, false, false, false };
+
+ static const uint8_t mask_to_bit_num[8] = { 0, 1, 2, 2, 3, 3, 3, 3 };
+
+ size_t i;
+ size_t prev_pos = (size_t)-1;
+ uint32_t prev_mask = s->x86_prev_mask;
+ uint32_t src;
+ uint32_t dest;
+ uint32_t j;
+ uint8_t b;
+
+ if (size <= 4)
+ return 0;
+
+ size -= 4;
+ for (i = 0; i < size; ++i) {
+ if ((buf[i] & 0xFE) != 0xE8)
+ continue;
+
+ prev_pos = i - prev_pos;
+ if (prev_pos > 3) {
+ prev_mask = 0;
+ } else {
+ prev_mask = (prev_mask << (prev_pos - 1)) & 7;
+ if (prev_mask != 0) {
+ b = buf[i + 4 - mask_to_bit_num[prev_mask]];
+ if (!mask_to_allowed_status[prev_mask]
+ || bcj_x86_test_msbyte(b)) {
+ prev_pos = i;
+ prev_mask = (prev_mask << 1) | 1;
+ continue;
+ }
+ }
+ }
+
+ prev_pos = i;
+
+ if (bcj_x86_test_msbyte(buf[i + 4])) {
+ src = get_unaligned_le32(buf + i + 1);
+ while (true) {
+ dest = src - (s->pos + (uint32_t)i + 5);
+ if (prev_mask == 0)
+ break;
+
+ j = mask_to_bit_num[prev_mask] * 8;
+ b = (uint8_t)(dest >> (24 - j));
+ if (!bcj_x86_test_msbyte(b))
+ break;
+
+ src = dest ^ (((uint32_t)1 << (32 - j)) - 1);
+ }
+
+ dest &= 0x01FFFFFF;
+ dest |= (uint32_t)0 - (dest & 0x01000000);
+ put_unaligned_le32(dest, buf + i + 1);
+ i += 4;
+ } else {
+ prev_mask = (prev_mask << 1) | 1;
+ }
+ }
+
+ prev_pos = i - prev_pos;
+ s->x86_prev_mask = prev_pos > 3 ? 0 : prev_mask << (prev_pos - 1);
+ return i;
+}
+#endif
+
+#ifdef XZ_DEC_POWERPC
+static size_t bcj_powerpc(struct xz_dec_bcj *s, uint8_t *buf, size_t size)
+{
+ size_t i;
+ uint32_t instr;
+
+ for (i = 0; i + 4 <= size; i += 4) {
+ instr = get_unaligned_be32(buf + i);
+ if ((instr & 0xFC000003) == 0x48000001) {
+ instr &= 0x03FFFFFC;
+ instr -= s->pos + (uint32_t)i;
+ instr &= 0x03FFFFFC;
+ instr |= 0x48000001;
+ put_unaligned_be32(instr, buf + i);
+ }
+ }
+
+ return i;
+}
+#endif
+
+#ifdef XZ_DEC_IA64
+static size_t bcj_ia64(struct xz_dec_bcj *s, uint8_t *buf, size_t size)
+{
+ static const uint8_t branch_table[32] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 4, 4, 6, 6, 0, 0, 7, 7,
+ 4, 4, 0, 0, 4, 4, 0, 0
+ };
+
+ /*
+ * The local variables take a little bit stack space, but it's less
+ * than what LZMA2 decoder takes, so it doesn't make sense to reduce
+ * stack usage here without doing that for the LZMA2 decoder too.
+ */
+
+ /* Loop counters */
+ size_t i;
+ size_t j;
+
+ /* Instruction slot (0, 1, or 2) in the 128-bit instruction word */
+ uint32_t slot;
+
+ /* Bitwise offset of the instruction indicated by slot */
+ uint32_t bit_pos;
+
+ /* bit_pos split into byte and bit parts */
+ uint32_t byte_pos;
+ uint32_t bit_res;
+
+ /* Address part of an instruction */
+ uint32_t addr;
+
+ /* Mask used to detect which instructions to convert */
+ uint32_t mask;
+
+ /* 41-bit instruction stored somewhere in the lowest 48 bits */
+ uint64_t instr;
+
+ /* Instruction normalized with bit_res for easier manipulation */
+ uint64_t norm;
+
+ for (i = 0; i + 16 <= size; i += 16) {
+ mask = branch_table[buf[i] & 0x1F];
+ for (slot = 0, bit_pos = 5; slot < 3; ++slot, bit_pos += 41) {
+ if (((mask >> slot) & 1) == 0)
+ continue;
+
+ byte_pos = bit_pos >> 3;
+ bit_res = bit_pos & 7;
+ instr = 0;
+ for (j = 0; j < 6; ++j)
+ instr |= (uint64_t)(buf[i + j + byte_pos])
+ << (8 * j);
+
+ norm = instr >> bit_res;
+
+ if (((norm >> 37) & 0x0F) == 0x05
+ && ((norm >> 9) & 0x07) == 0) {
+ addr = (norm >> 13) & 0x0FFFFF;
+ addr |= ((uint32_t)(norm >> 36) & 1) << 20;
+ addr <<= 4;
+ addr -= s->pos + (uint32_t)i;
+ addr >>= 4;
+
+ norm &= ~((uint64_t)0x8FFFFF << 13);
+ norm |= (uint64_t)(addr & 0x0FFFFF) << 13;
+ norm |= (uint64_t)(addr & 0x100000)
+ << (36 - 20);
+
+ instr &= (1 << bit_res) - 1;
+ instr |= norm << bit_res;
+
+ for (j = 0; j < 6; j++)
+ buf[i + j + byte_pos]
+ = (uint8_t)(instr >> (8 * j));
+ }
+ }
+ }
+
+ return i;
+}
+#endif
+
+#ifdef XZ_DEC_ARM
+static size_t bcj_arm(struct xz_dec_bcj *s, uint8_t *buf, size_t size)
+{
+ size_t i;
+ uint32_t addr;
+
+ for (i = 0; i + 4 <= size; i += 4) {
+ if (buf[i + 3] == 0xEB) {
+ addr = (uint32_t)buf[i] | ((uint32_t)buf[i + 1] << 8)
+ | ((uint32_t)buf[i + 2] << 16);
+ addr <<= 2;
+ addr -= s->pos + (uint32_t)i + 8;
+ addr >>= 2;
+ buf[i] = (uint8_t)addr;
+ buf[i + 1] = (uint8_t)(addr >> 8);
+ buf[i + 2] = (uint8_t)(addr >> 16);
+ }
+ }
+
+ return i;
+}
+#endif
+
+#ifdef XZ_DEC_ARMTHUMB
+static size_t bcj_armthumb(struct xz_dec_bcj *s, uint8_t *buf, size_t size)
+{
+ size_t i;
+ uint32_t addr;
+
+ for (i = 0; i + 4 <= size; i += 2) {
+ if ((buf[i + 1] & 0xF8) == 0xF0
+ && (buf[i + 3] & 0xF8) == 0xF8) {
+ addr = (((uint32_t)buf[i + 1] & 0x07) << 19)
+ | ((uint32_t)buf[i] << 11)
+ | (((uint32_t)buf[i + 3] & 0x07) << 8)
+ | (uint32_t)buf[i + 2];
+ addr <<= 1;
+ addr -= s->pos + (uint32_t)i + 4;
+ addr >>= 1;
+ buf[i + 1] = (uint8_t)(0xF0 | ((addr >> 19) & 0x07));
+ buf[i] = (uint8_t)(addr >> 11);
+ buf[i + 3] = (uint8_t)(0xF8 | ((addr >> 8) & 0x07));
+ buf[i + 2] = (uint8_t)addr;
+ i += 2;
+ }
+ }
+
+ return i;
+}
+#endif
+
+#ifdef XZ_DEC_SPARC
+static size_t bcj_sparc(struct xz_dec_bcj *s, uint8_t *buf, size_t size)
+{
+ size_t i;
+ uint32_t instr;
+
+ for (i = 0; i + 4 <= size; i += 4) {
+ instr = get_unaligned_be32(buf + i);
+ if ((instr >> 22) == 0x100 || (instr >> 22) == 0x1FF) {
+ instr <<= 2;
+ instr -= s->pos + (uint32_t)i;
+ instr >>= 2;
+ instr = ((uint32_t)0x40000000 - (instr & 0x400000))
+ | 0x40000000 | (instr & 0x3FFFFF);
+ put_unaligned_be32(instr, buf + i);
+ }
+ }
+
+ return i;
+}
+#endif
+
+/*
+ * Apply the selected BCJ filter. Update *pos and s->pos to match the amount
+ * of data that got filtered.
+ *
+ * NOTE: This is implemented as a switch statement to avoid using function
+ * pointers, which could be problematic in the kernel boot code, which must
+ * avoid pointers to static data (at least on x86).
+ */
+static void bcj_apply(struct xz_dec_bcj *s,
+ uint8_t *buf, size_t *pos, size_t size)
+{
+ size_t filtered;
+
+ buf += *pos;
+ size -= *pos;
+
+ switch (s->type) {
+#ifdef XZ_DEC_X86
+ case BCJ_X86:
+ filtered = bcj_x86(s, buf, size);
+ break;
+#endif
+#ifdef XZ_DEC_POWERPC
+ case BCJ_POWERPC:
+ filtered = bcj_powerpc(s, buf, size);
+ break;
+#endif
+#ifdef XZ_DEC_IA64
+ case BCJ_IA64:
+ filtered = bcj_ia64(s, buf, size);
+ break;
+#endif
+#ifdef XZ_DEC_ARM
+ case BCJ_ARM:
+ filtered = bcj_arm(s, buf, size);
+ break;
+#endif
+#ifdef XZ_DEC_ARMTHUMB
+ case BCJ_ARMTHUMB:
+ filtered = bcj_armthumb(s, buf, size);
+ break;
+#endif
+#ifdef XZ_DEC_SPARC
+ case BCJ_SPARC:
+ filtered = bcj_sparc(s, buf, size);
+ break;
+#endif
+ default:
+ /* Never reached but silence compiler warnings. */
+ filtered = 0;
+ break;
+ }
+
+ *pos += filtered;
+ s->pos += filtered;
+}
+
+/*
+ * Flush pending filtered data from temp to the output buffer.
+ * Move the remaining mixture of possibly filtered and unfiltered
+ * data to the beginning of temp.
+ */
+static void bcj_flush(struct xz_dec_bcj *s, struct xz_buf *b)
+{
+ size_t copy_size;
+
+ copy_size = min_t(size_t, s->temp.filtered, b->out_size - b->out_pos);
+ memcpy(b->out + b->out_pos, s->temp.buf, copy_size);
+ b->out_pos += copy_size;
+
+ s->temp.filtered -= copy_size;
+ s->temp.size -= copy_size;
+ memmove(s->temp.buf, s->temp.buf + copy_size, s->temp.size);
+}
+
+/*
+ * The BCJ filter functions are primitive in sense that they process the
+ * data in chunks of 1-16 bytes. To hide this issue, this function does
+ * some buffering.
+ */
+XZ_EXTERN enum xz_ret xz_dec_bcj_run(struct xz_dec_bcj *s,
+ struct xz_dec_lzma2 *lzma2,
+ struct xz_buf *b)
+{
+ size_t out_start;
+
+ /*
+ * Flush pending already filtered data to the output buffer. Return
+ * immediatelly if we couldn't flush everything, or if the next
+ * filter in the chain had already returned XZ_STREAM_END.
+ */
+ if (s->temp.filtered > 0) {
+ bcj_flush(s, b);
+ if (s->temp.filtered > 0)
+ return XZ_OK;
+
+ if (s->ret == XZ_STREAM_END)
+ return XZ_STREAM_END;
+ }
+
+ /*
+ * If we have more output space than what is currently pending in
+ * temp, copy the unfiltered data from temp to the output buffer
+ * and try to fill the output buffer by decoding more data from the
+ * next filter in the chain. Apply the BCJ filter on the new data
+ * in the output buffer. If everything cannot be filtered, copy it
+ * to temp and rewind the output buffer position accordingly.
+ *
+ * This needs to be always run when temp.size == 0 to handle a special
+ * case where the output buffer is full and the next filter has no
+ * more output coming but hasn't returned XZ_STREAM_END yet.
+ */
+ if (s->temp.size < b->out_size - b->out_pos || s->temp.size == 0) {
+ out_start = b->out_pos;
+ memcpy(b->out + b->out_pos, s->temp.buf, s->temp.size);
+ b->out_pos += s->temp.size;
+
+ s->ret = xz_dec_lzma2_run(lzma2, b);
+ if (s->ret != XZ_STREAM_END
+ && (s->ret != XZ_OK || s->single_call))
+ return s->ret;
+
+ bcj_apply(s, b->out, &out_start, b->out_pos);
+
+ /*
+ * As an exception, if the next filter returned XZ_STREAM_END,
+ * we can do that too, since the last few bytes that remain
+ * unfiltered are meant to remain unfiltered.
+ */
+ if (s->ret == XZ_STREAM_END)
+ return XZ_STREAM_END;
+
+ s->temp.size = b->out_pos - out_start;
+ b->out_pos -= s->temp.size;
+ memcpy(s->temp.buf, b->out + b->out_pos, s->temp.size);
+
+ /*
+ * If there wasn't enough input to the next filter to fill
+ * the output buffer with unfiltered data, there's no point
+ * to try decoding more data to temp.
+ */
+ if (b->out_pos + s->temp.size < b->out_size)
+ return XZ_OK;
+ }
+
+ /*
+ * We have unfiltered data in temp. If the output buffer isn't full
+ * yet, try to fill the temp buffer by decoding more data from the
+ * next filter. Apply the BCJ filter on temp. Then we hopefully can
+ * fill the actual output buffer by copying filtered data from temp.
+ * A mix of filtered and unfiltered data may be left in temp; it will
+ * be taken care on the next call to this function.
+ */
+ if (b->out_pos < b->out_size) {
+ /* Make b->out{,_pos,_size} temporarily point to s->temp. */
+ s->out = b->out;
+ s->out_pos = b->out_pos;
+ s->out_size = b->out_size;
+ b->out = s->temp.buf;
+ b->out_pos = s->temp.size;
+ b->out_size = sizeof(s->temp.buf);
+
+ s->ret = xz_dec_lzma2_run(lzma2, b);
+
+ s->temp.size = b->out_pos;
+ b->out = s->out;
+ b->out_pos = s->out_pos;
+ b->out_size = s->out_size;
+
+ if (s->ret != XZ_OK && s->ret != XZ_STREAM_END)
+ return s->ret;
+
+ bcj_apply(s, s->temp.buf, &s->temp.filtered, s->temp.size);
+
+ /*
+ * If the next filter returned XZ_STREAM_END, we mark that
+ * everything is filtered, since the last unfiltered bytes
+ * of the stream are meant to be left as is.
+ */
+ if (s->ret == XZ_STREAM_END)
+ s->temp.filtered = s->temp.size;
+
+ bcj_flush(s, b);
+ if (s->temp.filtered > 0)
+ return XZ_OK;
+ }
+
+ return s->ret;
+}
+
+XZ_EXTERN struct xz_dec_bcj *xz_dec_bcj_create(bool single_call)
+{
+ struct xz_dec_bcj *s = kmalloc(sizeof(*s), GFP_KERNEL);
+ if (s != NULL)
+ s->single_call = single_call;
+
+ return s;
+}
+
+XZ_EXTERN enum xz_ret xz_dec_bcj_reset(struct xz_dec_bcj *s, uint8_t id)
+{
+ switch (id) {
+#ifdef XZ_DEC_X86
+ case BCJ_X86:
+#endif
+#ifdef XZ_DEC_POWERPC
+ case BCJ_POWERPC:
+#endif
+#ifdef XZ_DEC_IA64
+ case BCJ_IA64:
+#endif
+#ifdef XZ_DEC_ARM
+ case BCJ_ARM:
+#endif
+#ifdef XZ_DEC_ARMTHUMB
+ case BCJ_ARMTHUMB:
+#endif
+#ifdef XZ_DEC_SPARC
+ case BCJ_SPARC:
+#endif
+ break;
+
+ default:
+ /* Unsupported Filter ID */
+ return XZ_OPTIONS_ERROR;
+ }
+
+ s->type = id;
+ s->ret = XZ_OK;
+ s->pos = 0;
+ s->x86_prev_mask = 0;
+ s->temp.filtered = 0;
+ s->temp.size = 0;
+
+ return XZ_OK;
+}
+
+#endif
diff --git a/lzma/xz-embedded/xz_dec_lzma2.c b/lzma/xz-embedded/xz_dec_lzma2.c
new file mode 100644
index 0000000..a6cdc96
--- /dev/null
+++ b/lzma/xz-embedded/xz_dec_lzma2.c
@@ -0,0 +1,1171 @@
+/*
+ * LZMA2 decoder
+ *
+ * Authors: Lasse Collin <lasse.collin@tukaani.org>
+ * Igor Pavlov <http://7-zip.org/>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+#include "xz_private.h"
+#include "xz_lzma2.h"
+
+/*
+ * Range decoder initialization eats the first five bytes of each LZMA chunk.
+ */
+#define RC_INIT_BYTES 5
+
+/*
+ * Minimum number of usable input buffer to safely decode one LZMA symbol.
+ * The worst case is that we decode 22 bits using probabilities and 26
+ * direct bits. This may decode at maximum of 20 bytes of input. However,
+ * lzma_main() does an extra normalization before returning, thus we
+ * need to put 21 here.
+ */
+#define LZMA_IN_REQUIRED 21
+
+/*
+ * Dictionary (history buffer)
+ *
+ * These are always true:
+ * start <= pos <= full <= end
+ * pos <= limit <= end
+ *
+ * In multi-call mode, also these are true:
+ * end == size
+ * size <= size_max
+ * allocated <= size
+ *
+ * Most of these variables are size_t to support single-call mode,
+ * in which the dictionary variables address the actual output
+ * buffer directly.
+ */
+struct dictionary {
+ /* Beginning of the history buffer */
+ uint8_t *buf;
+
+ /* Old position in buf (before decoding more data) */
+ size_t start;
+
+ /* Position in buf */
+ size_t pos;
+
+ /*
+ * How full dictionary is. This is used to detect corrupt input that
+ * would read beyond the beginning of the uncompressed stream.
+ */
+ size_t full;
+
+ /* Write limit; we don't write to buf[limit] or later bytes. */
+ size_t limit;
+
+ /*
+ * End of the dictionary buffer. In multi-call mode, this is
+ * the same as the dictionary size. In single-call mode, this
+ * indicates the size of the output buffer.
+ */
+ size_t end;
+
+ /*
+ * Size of the dictionary as specified in Block Header. This is used
+ * together with "full" to detect corrupt input that would make us
+ * read beyond the beginning of the uncompressed stream.
+ */
+ uint32_t size;
+
+ /*
+ * Maximum allowed dictionary size in multi-call mode.
+ * This is ignored in single-call mode.
+ */
+ uint32_t size_max;
+
+ /*
+ * Amount of memory currently allocated for the dictionary.
+ * This is used only with XZ_DYNALLOC. (With XZ_PREALLOC,
+ * size_max is always the same as the allocated size.)
+ */
+ uint32_t allocated;
+
+ /* Operation mode */
+ enum xz_mode mode;
+};
+
+/* Range decoder */
+struct rc_dec {
+ uint32_t range;
+ uint32_t code;
+
+ /*
+ * Number of initializing bytes remaining to be read
+ * by rc_read_init().
+ */
+ uint32_t init_bytes_left;
+
+ /*
+ * Buffer from which we read our input. It can be either
+ * temp.buf or the caller-provided input buffer.
+ */
+ const uint8_t *in;
+ size_t in_pos;
+ size_t in_limit;
+};
+
+/* Probabilities for a length decoder. */
+struct lzma_len_dec {
+ /* Probability of match length being at least 10 */
+ uint16_t choice;
+
+ /* Probability of match length being at least 18 */
+ uint16_t choice2;
+
+ /* Probabilities for match lengths 2-9 */
+ uint16_t low[POS_STATES_MAX][LEN_LOW_SYMBOLS];
+
+ /* Probabilities for match lengths 10-17 */
+ uint16_t mid[POS_STATES_MAX][LEN_MID_SYMBOLS];
+
+ /* Probabilities for match lengths 18-273 */
+ uint16_t high[LEN_HIGH_SYMBOLS];
+};
+
+struct lzma_dec {
+ /* Distances of latest four matches */
+ uint32_t rep0;
+ uint32_t rep1;
+ uint32_t rep2;
+ uint32_t rep3;
+
+ /* Types of the most recently seen LZMA symbols */
+ enum lzma_state state;
+
+ /*
+ * Length of a match. This is updated so that dict_repeat can
+ * be called again to finish repeating the whole match.
+ */
+ uint32_t len;
+
+ /*
+ * LZMA properties or related bit masks (number of literal
+ * context bits, a mask dervied from the number of literal
+ * position bits, and a mask dervied from the number
+ * position bits)
+ */
+ uint32_t lc;
+ uint32_t literal_pos_mask; /* (1 << lp) - 1 */
+ uint32_t pos_mask; /* (1 << pb) - 1 */
+
+ /* If 1, it's a match. Otherwise it's a single 8-bit literal. */
+ uint16_t is_match[STATES][POS_STATES_MAX];
+
+ /* If 1, it's a repeated match. The distance is one of rep0 .. rep3. */
+ uint16_t is_rep[STATES];
+
+ /*
+ * If 0, distance of a repeated match is rep0.
+ * Otherwise check is_rep1.
+ */
+ uint16_t is_rep0[STATES];
+
+ /*
+ * If 0, distance of a repeated match is rep1.
+ * Otherwise check is_rep2.
+ */
+ uint16_t is_rep1[STATES];
+
+ /* If 0, distance of a repeated match is rep2. Otherwise it is rep3. */
+ uint16_t is_rep2[STATES];
+
+ /*
+ * If 1, the repeated match has length of one byte. Otherwise
+ * the length is decoded from rep_len_decoder.
+ */
+ uint16_t is_rep0_long[STATES][POS_STATES_MAX];
+
+ /*
+ * Probability tree for the highest two bits of the match
+ * distance. There is a separate probability tree for match
+ * lengths of 2 (i.e. MATCH_LEN_MIN), 3, 4, and [5, 273].
+ */
+ uint16_t dist_slot[DIST_STATES][DIST_SLOTS];
+
+ /*
+ * Probility trees for additional bits for match distance
+ * when the distance is in the range [4, 127].
+ */
+ uint16_t dist_special[FULL_DISTANCES - DIST_MODEL_END];
+
+ /*
+ * Probability tree for the lowest four bits of a match
+ * distance that is equal to or greater than 128.
+ */
+ uint16_t dist_align[ALIGN_SIZE];
+
+ /* Length of a normal match */
+ struct lzma_len_dec match_len_dec;
+
+ /* Length of a repeated match */
+ struct lzma_len_dec rep_len_dec;
+
+ /* Probabilities of literals */
+ uint16_t literal[LITERAL_CODERS_MAX][LITERAL_CODER_SIZE];
+};
+
+struct lzma2_dec {
+ /* Position in xz_dec_lzma2_run(). */
+ enum lzma2_seq {
+ SEQ_CONTROL,
+ SEQ_UNCOMPRESSED_1,
+ SEQ_UNCOMPRESSED_2,
+ SEQ_COMPRESSED_0,
+ SEQ_COMPRESSED_1,
+ SEQ_PROPERTIES,
+ SEQ_LZMA_PREPARE,
+ SEQ_LZMA_RUN,
+ SEQ_COPY
+ } sequence;
+
+ /* Next position after decoding the compressed size of the chunk. */
+ enum lzma2_seq next_sequence;
+
+ /* Uncompressed size of LZMA chunk (2 MiB at maximum) */
+ uint32_t uncompressed;
+
+ /*
+ * Compressed size of LZMA chunk or compressed/uncompressed
+ * size of uncompressed chunk (64 KiB at maximum)
+ */
+ uint32_t compressed;
+
+ /*
+ * True if dictionary reset is needed. This is false before
+ * the first chunk (LZMA or uncompressed).
+ */
+ bool need_dict_reset;
+
+ /*
+ * True if new LZMA properties are needed. This is false
+ * before the first LZMA chunk.
+ */
+ bool need_props;
+};
+
+struct xz_dec_lzma2 {
+ /*
+ * The order below is important on x86 to reduce code size and
+ * it shouldn't hurt on other platforms. Everything up to and
+ * including lzma.pos_mask are in the first 128 bytes on x86-32,
+ * which allows using smaller instructions to access those
+ * variables. On x86-64, fewer variables fit into the first 128
+ * bytes, but this is still the best order without sacrificing
+ * the readability by splitting the structures.
+ */
+ struct rc_dec rc;
+ struct dictionary dict;
+ struct lzma2_dec lzma2;
+ struct lzma_dec lzma;
+
+ /*
+ * Temporary buffer which holds small number of input bytes between
+ * decoder calls. See lzma2_lzma() for details.
+ */
+ struct {
+ uint32_t size;
+ uint8_t buf[3 * LZMA_IN_REQUIRED];
+ } temp;
+};
+
+/**************
+ * Dictionary *
+ **************/
+
+/*
+ * Reset the dictionary state. When in single-call mode, set up the beginning
+ * of the dictionary to point to the actual output buffer.
+ */
+static void dict_reset(struct dictionary *dict, struct xz_buf *b)
+{
+ if (DEC_IS_SINGLE(dict->mode)) {
+ dict->buf = b->out + b->out_pos;
+ dict->end = b->out_size - b->out_pos;
+ }
+
+ dict->start = 0;
+ dict->pos = 0;
+ dict->limit = 0;
+ dict->full = 0;
+}
+
+/* Set dictionary write limit */
+static void dict_limit(struct dictionary *dict, size_t out_max)
+{
+ if (dict->end - dict->pos <= out_max)
+ dict->limit = dict->end;
+ else
+ dict->limit = dict->pos + out_max;
+}
+
+/* Return true if at least one byte can be written into the dictionary. */
+static inline bool dict_has_space(const struct dictionary *dict)
+{
+ return dict->pos < dict->limit;
+}
+
+/*
+ * Get a byte from the dictionary at the given distance. The distance is
+ * assumed to valid, or as a special case, zero when the dictionary is
+ * still empty. This special case is needed for single-call decoding to
+ * avoid writing a '\0' to the end of the destination buffer.
+ */
+static inline uint32_t dict_get(const struct dictionary *dict, uint32_t dist)
+{
+ size_t offset = dict->pos - dist - 1;
+
+ if (dist >= dict->pos)
+ offset += dict->end;
+
+ return dict->full > 0 ? dict->buf[offset] : 0;
+}
+
+/*
+ * Put one byte into the dictionary. It is assumed that there is space for it.
+ */
+static inline void dict_put(struct dictionary *dict, uint8_t byte)
+{
+ dict->buf[dict->pos++] = byte;
+
+ if (dict->full < dict->pos)
+ dict->full = dict->pos;
+}
+
+/*
+ * Repeat given number of bytes from the given distance. If the distance is
+ * invalid, false is returned. On success, true is returned and *len is
+ * updated to indicate how many bytes were left to be repeated.
+ */
+static bool dict_repeat(struct dictionary *dict, uint32_t *len, uint32_t dist)
+{
+ size_t back;
+ uint32_t left;
+
+ if (dist >= dict->full || dist >= dict->size)
+ return false;
+
+ left = min_t(size_t, dict->limit - dict->pos, *len);
+ *len -= left;
+
+ back = dict->pos - dist - 1;
+ if (dist >= dict->pos)
+ back += dict->end;
+
+ do {
+ dict->buf[dict->pos++] = dict->buf[back++];
+ if (back == dict->end)
+ back = 0;
+ } while (--left > 0);
+
+ if (dict->full < dict->pos)
+ dict->full = dict->pos;
+
+ return true;
+}
+
+/* Copy uncompressed data as is from input to dictionary and output buffers. */
+static void dict_uncompressed(struct dictionary *dict, struct xz_buf *b,
+ uint32_t *left)
+{
+ size_t copy_size;
+
+ while (*left > 0 && b->in_pos < b->in_size
+ && b->out_pos < b->out_size) {
+ copy_size = min(b->in_size - b->in_pos,
+ b->out_size - b->out_pos);
+ if (copy_size > dict->end - dict->pos)
+ copy_size = dict->end - dict->pos;
+ if (copy_size > *left)
+ copy_size = *left;
+
+ *left -= copy_size;
+
+ memcpy(dict->buf + dict->pos, b->in + b->in_pos, copy_size);
+ dict->pos += copy_size;
+
+ if (dict->full < dict->pos)
+ dict->full = dict->pos;
+
+ if (DEC_IS_MULTI(dict->mode)) {
+ if (dict->pos == dict->end)
+ dict->pos = 0;
+
+ memcpy(b->out + b->out_pos, b->in + b->in_pos,
+ copy_size);
+ }
+
+ dict->start = dict->pos;
+
+ b->out_pos += copy_size;
+ b->in_pos += copy_size;
+ }
+}
+
+/*
+ * Flush pending data from dictionary to b->out. It is assumed that there is
+ * enough space in b->out. This is guaranteed because caller uses dict_limit()
+ * before decoding data into the dictionary.
+ */
+static uint32_t dict_flush(struct dictionary *dict, struct xz_buf *b)
+{
+ size_t copy_size = dict->pos - dict->start;
+
+ if (DEC_IS_MULTI(dict->mode)) {
+ if (dict->pos == dict->end)
+ dict->pos = 0;
+
+ memcpy(b->out + b->out_pos, dict->buf + dict->start,
+ copy_size);
+ }
+
+ dict->start = dict->pos;
+ b->out_pos += copy_size;
+ return copy_size;
+}
+
+/*****************
+ * Range decoder *
+ *****************/
+
+/* Reset the range decoder. */
+static void rc_reset(struct rc_dec *rc)
+{
+ rc->range = (uint32_t)-1;
+ rc->code = 0;
+ rc->init_bytes_left = RC_INIT_BYTES;
+}
+
+/*
+ * Read the first five initial bytes into rc->code if they haven't been
+ * read already. (Yes, the first byte gets completely ignored.)
+ */
+static bool rc_read_init(struct rc_dec *rc, struct xz_buf *b)
+{
+ while (rc->init_bytes_left > 0) {
+ if (b->in_pos == b->in_size)
+ return false;
+
+ rc->code = (rc->code << 8) + b->in[b->in_pos++];
+ --rc->init_bytes_left;
+ }
+
+ return true;
+}
+
+/* Return true if there may not be enough input for the next decoding loop. */
+static inline bool rc_limit_exceeded(const struct rc_dec *rc)
+{
+ return rc->in_pos > rc->in_limit;
+}
+
+/*
+ * Return true if it is possible (from point of view of range decoder) that
+ * we have reached the end of the LZMA chunk.
+ */
+static inline bool rc_is_finished(const struct rc_dec *rc)
+{
+ return rc->code == 0;
+}
+
+/* Read the next input byte if needed. */
+static __always_inline void rc_normalize(struct rc_dec *rc)
+{
+ if (rc->range < RC_TOP_VALUE) {
+ rc->range <<= RC_SHIFT_BITS;
+ rc->code = (rc->code << RC_SHIFT_BITS) + rc->in[rc->in_pos++];
+ }
+}
+
+/*
+ * Decode one bit. In some versions, this function has been splitted in three
+ * functions so that the compiler is supposed to be able to more easily avoid
+ * an extra branch. In this particular version of the LZMA decoder, this
+ * doesn't seem to be a good idea (tested with GCC 3.3.6, 3.4.6, and 4.3.3
+ * on x86). Using a non-splitted version results in nicer looking code too.
+ *
+ * NOTE: This must return an int. Do not make it return a bool or the speed
+ * of the code generated by GCC 3.x decreases 10-15 %. (GCC 4.3 doesn't care,
+ * and it generates 10-20 % faster code than GCC 3.x from this file anyway.)
+ */
+static __always_inline int rc_bit(struct rc_dec *rc, uint16_t *prob)
+{
+ uint32_t bound;
+ int bit;
+
+ rc_normalize(rc);
+ bound = (rc->range >> RC_BIT_MODEL_TOTAL_BITS) * *prob;
+ if (rc->code < bound) {
+ rc->range = bound;
+ *prob += (RC_BIT_MODEL_TOTAL - *prob) >> RC_MOVE_BITS;
+ bit = 0;
+ } else {
+ rc->range -= bound;
+ rc->code -= bound;
+ *prob -= *prob >> RC_MOVE_BITS;
+ bit = 1;
+ }
+
+ return bit;
+}
+
+/* Decode a bittree starting from the most significant bit. */
+static __always_inline uint32_t rc_bittree(struct rc_dec *rc,
+ uint16_t *probs, uint32_t limit)
+{
+ uint32_t symbol = 1;
+
+ do {
+ if (rc_bit(rc, &probs[symbol]))
+ symbol = (symbol << 1) + 1;
+ else
+ symbol <<= 1;
+ } while (symbol < limit);
+
+ return symbol;
+}
+
+/* Decode a bittree starting from the least significant bit. */
+static __always_inline void rc_bittree_reverse(struct rc_dec *rc,
+ uint16_t *probs,
+ uint32_t *dest, uint32_t limit)
+{
+ uint32_t symbol = 1;
+ uint32_t i = 0;
+
+ do {
+ if (rc_bit(rc, &probs[symbol])) {
+ symbol = (symbol << 1) + 1;
+ *dest += 1 << i;
+ } else {
+ symbol <<= 1;
+ }
+ } while (++i < limit);
+}
+
+/* Decode direct bits (fixed fifty-fifty probability) */
+static inline void rc_direct(struct rc_dec *rc, uint32_t *dest, uint32_t limit)
+{
+ uint32_t mask;
+
+ do {
+ rc_normalize(rc);
+ rc->range >>= 1;
+ rc->code -= rc->range;
+ mask = (uint32_t)0 - (rc->code >> 31);
+ rc->code += rc->range & mask;
+ *dest = (*dest << 1) + (mask + 1);
+ } while (--limit > 0);
+}
+
+/********
+ * LZMA *
+ ********/
+
+/* Get pointer to literal coder probability array. */
+static uint16_t *lzma_literal_probs(struct xz_dec_lzma2 *s)
+{
+ uint32_t prev_byte = dict_get(&s->dict, 0);
+ uint32_t low = prev_byte >> (8 - s->lzma.lc);
+ uint32_t high = (s->dict.pos & s->lzma.literal_pos_mask) << s->lzma.lc;
+ return s->lzma.literal[low + high];
+}
+
+/* Decode a literal (one 8-bit byte) */
+static void lzma_literal(struct xz_dec_lzma2 *s)
+{
+ uint16_t *probs;
+ uint32_t symbol;
+ uint32_t match_byte;
+ uint32_t match_bit;
+ uint32_t offset;
+ uint32_t i;
+
+ probs = lzma_literal_probs(s);
+
+ if (lzma_state_is_literal(s->lzma.state)) {
+ symbol = rc_bittree(&s->rc, probs, 0x100);
+ } else {
+ symbol = 1;
+ match_byte = dict_get(&s->dict, s->lzma.rep0) << 1;
+ offset = 0x100;
+
+ do {
+ match_bit = match_byte & offset;
+ match_byte <<= 1;
+ i = offset + match_bit + symbol;
+
+ if (rc_bit(&s->rc, &probs[i])) {
+ symbol = (symbol << 1) + 1;
+ offset &= match_bit;
+ } else {
+ symbol <<= 1;
+ offset &= ~match_bit;
+ }
+ } while (symbol < 0x100);
+ }
+
+ dict_put(&s->dict, (uint8_t)symbol);
+ lzma_state_literal(&s->lzma.state);
+}
+
+/* Decode the length of the match into s->lzma.len. */
+static void lzma_len(struct xz_dec_lzma2 *s, struct lzma_len_dec *l,
+ uint32_t pos_state)
+{
+ uint16_t *probs;
+ uint32_t limit;
+
+ if (!rc_bit(&s->rc, &l->choice)) {
+ probs = l->low[pos_state];
+ limit = LEN_LOW_SYMBOLS;
+ s->lzma.len = MATCH_LEN_MIN;
+ } else {
+ if (!rc_bit(&s->rc, &l->choice2)) {
+ probs = l->mid[pos_state];
+ limit = LEN_MID_SYMBOLS;
+ s->lzma.len = MATCH_LEN_MIN + LEN_LOW_SYMBOLS;
+ } else {
+ probs = l->high;
+ limit = LEN_HIGH_SYMBOLS;
+ s->lzma.len = MATCH_LEN_MIN + LEN_LOW_SYMBOLS
+ + LEN_MID_SYMBOLS;
+ }
+ }
+
+ s->lzma.len += rc_bittree(&s->rc, probs, limit) - limit;
+}
+
+/* Decode a match. The distance will be stored in s->lzma.rep0. */
+static void lzma_match(struct xz_dec_lzma2 *s, uint32_t pos_state)
+{
+ uint16_t *probs;
+ uint32_t dist_slot;
+ uint32_t limit;
+
+ lzma_state_match(&s->lzma.state);
+
+ s->lzma.rep3 = s->lzma.rep2;
+ s->lzma.rep2 = s->lzma.rep1;
+ s->lzma.rep1 = s->lzma.rep0;
+
+ lzma_len(s, &s->lzma.match_len_dec, pos_state);
+
+ probs = s->lzma.dist_slot[lzma_get_dist_state(s->lzma.len)];
+ dist_slot = rc_bittree(&s->rc, probs, DIST_SLOTS) - DIST_SLOTS;
+
+ if (dist_slot < DIST_MODEL_START) {
+ s->lzma.rep0 = dist_slot;
+ } else {
+ limit = (dist_slot >> 1) - 1;
+ s->lzma.rep0 = 2 + (dist_slot & 1);
+
+ if (dist_slot < DIST_MODEL_END) {
+ s->lzma.rep0 <<= limit;
+ probs = s->lzma.dist_special + s->lzma.rep0
+ - dist_slot - 1;
+ rc_bittree_reverse(&s->rc, probs,
+ &s->lzma.rep0, limit);
+ } else {
+ rc_direct(&s->rc, &s->lzma.rep0, limit - ALIGN_BITS);
+ s->lzma.rep0 <<= ALIGN_BITS;
+ rc_bittree_reverse(&s->rc, s->lzma.dist_align,
+ &s->lzma.rep0, ALIGN_BITS);
+ }
+ }
+}
+
+/*
+ * Decode a repeated match. The distance is one of the four most recently
+ * seen matches. The distance will be stored in s->lzma.rep0.
+ */
+static void lzma_rep_match(struct xz_dec_lzma2 *s, uint32_t pos_state)
+{
+ uint32_t tmp;
+
+ if (!rc_bit(&s->rc, &s->lzma.is_rep0[s->lzma.state])) {
+ if (!rc_bit(&s->rc, &s->lzma.is_rep0_long[
+ s->lzma.state][pos_state])) {
+ lzma_state_short_rep(&s->lzma.state);
+ s->lzma.len = 1;
+ return;
+ }
+ } else {
+ if (!rc_bit(&s->rc, &s->lzma.is_rep1[s->lzma.state])) {
+ tmp = s->lzma.rep1;
+ } else {
+ if (!rc_bit(&s->rc, &s->lzma.is_rep2[s->lzma.state])) {
+ tmp = s->lzma.rep2;
+ } else {
+ tmp = s->lzma.rep3;
+ s->lzma.rep3 = s->lzma.rep2;
+ }
+
+ s->lzma.rep2 = s->lzma.rep1;
+ }
+
+ s->lzma.rep1 = s->lzma.rep0;
+ s->lzma.rep0 = tmp;
+ }
+
+ lzma_state_long_rep(&s->lzma.state);
+ lzma_len(s, &s->lzma.rep_len_dec, pos_state);
+}
+
+/* LZMA decoder core */
+static bool lzma_main(struct xz_dec_lzma2 *s)
+{
+ uint32_t pos_state;
+
+ /*
+ * If the dictionary was reached during the previous call, try to
+ * finish the possibly pending repeat in the dictionary.
+ */
+ if (dict_has_space(&s->dict) && s->lzma.len > 0)
+ dict_repeat(&s->dict, &s->lzma.len, s->lzma.rep0);
+
+ /*
+ * Decode more LZMA symbols. One iteration may consume up to
+ * LZMA_IN_REQUIRED - 1 bytes.
+ */
+ while (dict_has_space(&s->dict) && !rc_limit_exceeded(&s->rc)) {
+ pos_state = s->dict.pos & s->lzma.pos_mask;
+
+ if (!rc_bit(&s->rc, &s->lzma.is_match[
+ s->lzma.state][pos_state])) {
+ lzma_literal(s);
+ } else {
+ if (rc_bit(&s->rc, &s->lzma.is_rep[s->lzma.state]))
+ lzma_rep_match(s, pos_state);
+ else
+ lzma_match(s, pos_state);
+
+ if (!dict_repeat(&s->dict, &s->lzma.len, s->lzma.rep0))
+ return false;
+ }
+ }
+
+ /*
+ * Having the range decoder always normalized when we are outside
+ * this function makes it easier to correctly handle end of the chunk.
+ */
+ rc_normalize(&s->rc);
+
+ return true;
+}
+
+/*
+ * Reset the LZMA decoder and range decoder state. Dictionary is nore reset
+ * here, because LZMA state may be reset without resetting the dictionary.
+ */
+static void lzma_reset(struct xz_dec_lzma2 *s)
+{
+ uint16_t *probs;
+ size_t i;
+
+ s->lzma.state = STATE_LIT_LIT;
+ s->lzma.rep0 = 0;
+ s->lzma.rep1 = 0;
+ s->lzma.rep2 = 0;
+ s->lzma.rep3 = 0;
+
+ /*
+ * All probabilities are initialized to the same value. This hack
+ * makes the code smaller by avoiding a separate loop for each
+ * probability array.
+ *
+ * This could be optimized so that only that part of literal
+ * probabilities that are actually required. In the common case
+ * we would write 12 KiB less.
+ */
+ probs = s->lzma.is_match[0];
+ for (i = 0; i < PROBS_TOTAL; ++i)
+ probs[i] = RC_BIT_MODEL_TOTAL / 2;
+
+ rc_reset(&s->rc);
+}
+
+/*
+ * Decode and validate LZMA properties (lc/lp/pb) and calculate the bit masks
+ * from the decoded lp and pb values. On success, the LZMA decoder state is
+ * reset and true is returned.
+ */
+static bool lzma_props(struct xz_dec_lzma2 *s, uint8_t props)
+{
+ if (props > (4 * 5 + 4) * 9 + 8)
+ return false;
+
+ s->lzma.pos_mask = 0;
+ while (props >= 9 * 5) {
+ props -= 9 * 5;
+ ++s->lzma.pos_mask;
+ }
+
+ s->lzma.pos_mask = (1 << s->lzma.pos_mask) - 1;
+
+ s->lzma.literal_pos_mask = 0;
+ while (props >= 9) {
+ props -= 9;
+ ++s->lzma.literal_pos_mask;
+ }
+
+ s->lzma.lc = props;
+
+ if (s->lzma.lc + s->lzma.literal_pos_mask > 4)
+ return false;
+
+ s->lzma.literal_pos_mask = (1 << s->lzma.literal_pos_mask) - 1;
+
+ lzma_reset(s);
+
+ return true;
+}
+
+/*********
+ * LZMA2 *
+ *********/
+
+/*
+ * The LZMA decoder assumes that if the input limit (s->rc.in_limit) hasn't
+ * been exceeded, it is safe to read up to LZMA_IN_REQUIRED bytes. This
+ * wrapper function takes care of making the LZMA decoder's assumption safe.
+ *
+ * As long as there is plenty of input left to be decoded in the current LZMA
+ * chunk, we decode directly from the caller-supplied input buffer until
+ * there's LZMA_IN_REQUIRED bytes left. Those remaining bytes are copied into
+ * s->temp.buf, which (hopefully) gets filled on the next call to this
+ * function. We decode a few bytes from the temporary buffer so that we can
+ * continue decoding from the caller-supplied input buffer again.
+ */
+static bool lzma2_lzma(struct xz_dec_lzma2 *s, struct xz_buf *b)
+{
+ size_t in_avail;
+ uint32_t tmp;
+
+ in_avail = b->in_size - b->in_pos;
+ if (s->temp.size > 0 || s->lzma2.compressed == 0) {
+ tmp = 2 * LZMA_IN_REQUIRED - s->temp.size;
+ if (tmp > s->lzma2.compressed - s->temp.size)
+ tmp = s->lzma2.compressed - s->temp.size;
+ if (tmp > in_avail)
+ tmp = in_avail;
+
+ memcpy(s->temp.buf + s->temp.size, b->in + b->in_pos, tmp);
+
+ if (s->temp.size + tmp == s->lzma2.compressed) {
+ memzero(s->temp.buf + s->temp.size + tmp,
+ sizeof(s->temp.buf)
+ - s->temp.size - tmp);
+ s->rc.in_limit = s->temp.size + tmp;
+ } else if (s->temp.size + tmp < LZMA_IN_REQUIRED) {
+ s->temp.size += tmp;
+ b->in_pos += tmp;
+ return true;
+ } else {
+ s->rc.in_limit = s->temp.size + tmp - LZMA_IN_REQUIRED;
+ }
+
+ s->rc.in = s->temp.buf;
+ s->rc.in_pos = 0;
+
+ if (!lzma_main(s) || s->rc.in_pos > s->temp.size + tmp)
+ return false;
+
+ s->lzma2.compressed -= s->rc.in_pos;
+
+ if (s->rc.in_pos < s->temp.size) {
+ s->temp.size -= s->rc.in_pos;
+ memmove(s->temp.buf, s->temp.buf + s->rc.in_pos,
+ s->temp.size);
+ return true;
+ }
+
+ b->in_pos += s->rc.in_pos - s->temp.size;
+ s->temp.size = 0;
+ }
+
+ in_avail = b->in_size - b->in_pos;
+ if (in_avail >= LZMA_IN_REQUIRED) {
+ s->rc.in = b->in;
+ s->rc.in_pos = b->in_pos;
+
+ if (in_avail >= s->lzma2.compressed + LZMA_IN_REQUIRED)
+ s->rc.in_limit = b->in_pos + s->lzma2.compressed;
+ else
+ s->rc.in_limit = b->in_size - LZMA_IN_REQUIRED;
+
+ if (!lzma_main(s))
+ return false;
+
+ in_avail = s->rc.in_pos - b->in_pos;
+ if (in_avail > s->lzma2.compressed)
+ return false;
+
+ s->lzma2.compressed -= in_avail;
+ b->in_pos = s->rc.in_pos;
+ }
+
+ in_avail = b->in_size - b->in_pos;
+ if (in_avail < LZMA_IN_REQUIRED) {
+ if (in_avail > s->lzma2.compressed)
+ in_avail = s->lzma2.compressed;
+
+ memcpy(s->temp.buf, b->in + b->in_pos, in_avail);
+ s->temp.size = in_avail;
+ b->in_pos += in_avail;
+ }
+
+ return true;
+}
+
+/*
+ * Take care of the LZMA2 control layer, and forward the job of actual LZMA
+ * decoding or copying of uncompressed chunks to other functions.
+ */
+XZ_EXTERN enum xz_ret xz_dec_lzma2_run(struct xz_dec_lzma2 *s,
+ struct xz_buf *b)
+{
+ uint32_t tmp;
+
+ while (b->in_pos < b->in_size || s->lzma2.sequence == SEQ_LZMA_RUN) {
+ switch (s->lzma2.sequence) {
+ case SEQ_CONTROL:
+ /*
+ * LZMA2 control byte
+ *
+ * Exact values:
+ * 0x00 End marker
+ * 0x01 Dictionary reset followed by
+ * an uncompressed chunk
+ * 0x02 Uncompressed chunk (no dictionary reset)
+ *
+ * Highest three bits (s->control & 0xE0):
+ * 0xE0 Dictionary reset, new properties and state
+ * reset, followed by LZMA compressed chunk
+ * 0xC0 New properties and state reset, followed
+ * by LZMA compressed chunk (no dictionary
+ * reset)
+ * 0xA0 State reset using old properties,
+ * followed by LZMA compressed chunk (no
+ * dictionary reset)
+ * 0x80 LZMA chunk (no dictionary or state reset)
+ *
+ * For LZMA compressed chunks, the lowest five bits
+ * (s->control & 1F) are the highest bits of the
+ * uncompressed size (bits 16-20).
+ *
+ * A new LZMA2 stream must begin with a dictionary
+ * reset. The first LZMA chunk must set new
+ * properties and reset the LZMA state.
+ *
+ * Values that don't match anything described above
+ * are invalid and we return XZ_DATA_ERROR.
+ */
+ tmp = b->in[b->in_pos++];
+
+ if (tmp == 0x00)
+ return XZ_STREAM_END;
+
+ if (tmp >= 0xE0 || tmp == 0x01) {
+ s->lzma2.need_props = true;
+ s->lzma2.need_dict_reset = false;
+ dict_reset(&s->dict, b);
+ } else if (s->lzma2.need_dict_reset) {
+ return XZ_DATA_ERROR;
+ }
+
+ if (tmp >= 0x80) {
+ s->lzma2.uncompressed = (tmp & 0x1F) << 16;
+ s->lzma2.sequence = SEQ_UNCOMPRESSED_1;
+
+ if (tmp >= 0xC0) {
+ /*
+ * When there are new properties,
+ * state reset is done at
+ * SEQ_PROPERTIES.
+ */
+ s->lzma2.need_props = false;
+ s->lzma2.next_sequence
+ = SEQ_PROPERTIES;
+
+ } else if (s->lzma2.need_props) {
+ return XZ_DATA_ERROR;
+
+ } else {
+ s->lzma2.next_sequence
+ = SEQ_LZMA_PREPARE;
+ if (tmp >= 0xA0)
+ lzma_reset(s);
+ }
+ } else {
+ if (tmp > 0x02)
+ return XZ_DATA_ERROR;
+
+ s->lzma2.sequence = SEQ_COMPRESSED_0;
+ s->lzma2.next_sequence = SEQ_COPY;
+ }
+
+ break;
+
+ case SEQ_UNCOMPRESSED_1:
+ s->lzma2.uncompressed
+ += (uint32_t)b->in[b->in_pos++] << 8;
+ s->lzma2.sequence = SEQ_UNCOMPRESSED_2;
+ break;
+
+ case SEQ_UNCOMPRESSED_2:
+ s->lzma2.uncompressed
+ += (uint32_t)b->in[b->in_pos++] + 1;
+ s->lzma2.sequence = SEQ_COMPRESSED_0;
+ break;
+
+ case SEQ_COMPRESSED_0:
+ s->lzma2.compressed
+ = (uint32_t)b->in[b->in_pos++] << 8;
+ s->lzma2.sequence = SEQ_COMPRESSED_1;
+ break;
+
+ case SEQ_COMPRESSED_1:
+ s->lzma2.compressed
+ += (uint32_t)b->in[b->in_pos++] + 1;
+ s->lzma2.sequence = s->lzma2.next_sequence;
+ break;
+
+ case SEQ_PROPERTIES:
+ if (!lzma_props(s, b->in[b->in_pos++]))
+ return XZ_DATA_ERROR;
+
+ s->lzma2.sequence = SEQ_LZMA_PREPARE;
+
+ case SEQ_LZMA_PREPARE:
+ if (s->lzma2.compressed < RC_INIT_BYTES)
+ return XZ_DATA_ERROR;
+
+ if (!rc_read_init(&s->rc, b))
+ return XZ_OK;
+
+ s->lzma2.compressed -= RC_INIT_BYTES;
+ s->lzma2.sequence = SEQ_LZMA_RUN;
+
+ case SEQ_LZMA_RUN:
+ /*
+ * Set dictionary limit to indicate how much we want
+ * to be encoded at maximum. Decode new data into the
+ * dictionary. Flush the new data from dictionary to
+ * b->out. Check if we finished decoding this chunk.
+ * In case the dictionary got full but we didn't fill
+ * the output buffer yet, we may run this loop
+ * multiple times without changing s->lzma2.sequence.
+ */
+ dict_limit(&s->dict, min_t(size_t,
+ b->out_size - b->out_pos,
+ s->lzma2.uncompressed));
+ if (!lzma2_lzma(s, b))
+ return XZ_DATA_ERROR;
+
+ s->lzma2.uncompressed -= dict_flush(&s->dict, b);
+
+ if (s->lzma2.uncompressed == 0) {
+ if (s->lzma2.compressed > 0 || s->lzma.len > 0
+ || !rc_is_finished(&s->rc))
+ return XZ_DATA_ERROR;
+
+ rc_reset(&s->rc);
+ s->lzma2.sequence = SEQ_CONTROL;
+
+ } else if (b->out_pos == b->out_size
+ || (b->in_pos == b->in_size
+ && s->temp.size
+ < s->lzma2.compressed)) {
+ return XZ_OK;
+ }
+
+ break;
+
+ case SEQ_COPY:
+ dict_uncompressed(&s->dict, b, &s->lzma2.compressed);
+ if (s->lzma2.compressed > 0)
+ return XZ_OK;
+
+ s->lzma2.sequence = SEQ_CONTROL;
+ break;
+ }
+ }
+
+ return XZ_OK;
+}
+
+XZ_EXTERN struct xz_dec_lzma2 *xz_dec_lzma2_create(enum xz_mode mode,
+ uint32_t dict_max)
+{
+ struct xz_dec_lzma2 *s = kmalloc(sizeof(*s), GFP_KERNEL);
+ if (s == NULL)
+ return NULL;
+
+ s->dict.mode = mode;
+ s->dict.size_max = dict_max;
+
+ if (DEC_IS_PREALLOC(mode)) {
+ s->dict.buf = vmalloc(dict_max);
+ if (s->dict.buf == NULL) {
+ kfree(s);
+ return NULL;
+ }
+ } else if (DEC_IS_DYNALLOC(mode)) {
+ s->dict.buf = NULL;
+ s->dict.allocated = 0;
+ }
+
+ return s;
+}
+
+XZ_EXTERN enum xz_ret xz_dec_lzma2_reset(struct xz_dec_lzma2 *s, uint8_t props)
+{
+ /* This limits dictionary size to 3 GiB to keep parsing simpler. */
+ if (props > 39)
+ return XZ_OPTIONS_ERROR;
+
+ s->dict.size = 2 + (props & 1);
+ s->dict.size <<= (props >> 1) + 11;
+
+ if (DEC_IS_MULTI(s->dict.mode)) {
+ if (s->dict.size > s->dict.size_max)
+ return XZ_MEMLIMIT_ERROR;
+
+ s->dict.end = s->dict.size;
+
+ if (DEC_IS_DYNALLOC(s->dict.mode)) {
+ if (s->dict.allocated < s->dict.size) {
+ vfree(s->dict.buf);
+ s->dict.buf = vmalloc(s->dict.size);
+ if (s->dict.buf == NULL) {
+ s->dict.allocated = 0;
+ return XZ_MEM_ERROR;
+ }
+ }
+ }
+ }
+
+ s->lzma.len = 0;
+
+ s->lzma2.sequence = SEQ_CONTROL;
+ s->lzma2.need_dict_reset = true;
+
+ s->temp.size = 0;
+
+ return XZ_OK;
+}
+
+XZ_EXTERN void xz_dec_lzma2_end(struct xz_dec_lzma2 *s)
+{
+ if (DEC_IS_MULTI(s->dict.mode))
+ vfree(s->dict.buf);
+
+ kfree(s);
+}
diff --git a/lzma/xz-embedded/xz_dec_stream.c b/lzma/xz-embedded/xz_dec_stream.c
new file mode 100644
index 0000000..d652550
--- /dev/null
+++ b/lzma/xz-embedded/xz_dec_stream.c
@@ -0,0 +1,847 @@
+/*
+ * .xz Stream decoder
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+#include "xz_private.h"
+#include "xz_stream.h"
+
+#ifdef XZ_USE_CRC64
+# define IS_CRC64(check_type) ((check_type) == XZ_CHECK_CRC64)
+#else
+# define IS_CRC64(check_type) false
+#endif
+
+/* Hash used to validate the Index field */
+struct xz_dec_hash {
+ vli_type unpadded;
+ vli_type uncompressed;
+ uint32_t crc32;
+};
+
+struct xz_dec {
+ /* Position in dec_main() */
+ enum {
+ SEQ_STREAM_HEADER,
+ SEQ_BLOCK_START,
+ SEQ_BLOCK_HEADER,
+ SEQ_BLOCK_UNCOMPRESS,
+ SEQ_BLOCK_PADDING,
+ SEQ_BLOCK_CHECK,
+ SEQ_INDEX,
+ SEQ_INDEX_PADDING,
+ SEQ_INDEX_CRC32,
+ SEQ_STREAM_FOOTER
+ } sequence;
+
+ /* Position in variable-length integers and Check fields */
+ uint32_t pos;
+
+ /* Variable-length integer decoded by dec_vli() */
+ vli_type vli;
+
+ /* Saved in_pos and out_pos */
+ size_t in_start;
+ size_t out_start;
+
+#ifdef XZ_USE_CRC64
+ /* CRC32 or CRC64 value in Block or CRC32 value in Index */
+ uint64_t crc;
+#else
+ /* CRC32 value in Block or Index */
+ uint32_t crc;
+#endif
+
+ /* Type of the integrity check calculated from uncompressed data */
+ enum xz_check check_type;
+
+ /* Operation mode */
+ enum xz_mode mode;
+
+ /*
+ * True if the next call to xz_dec_run() is allowed to return
+ * XZ_BUF_ERROR.
+ */
+ bool allow_buf_error;
+
+ /* Information stored in Block Header */
+ struct {
+ /*
+ * Value stored in the Compressed Size field, or
+ * VLI_UNKNOWN if Compressed Size is not present.
+ */
+ vli_type compressed;
+
+ /*
+ * Value stored in the Uncompressed Size field, or
+ * VLI_UNKNOWN if Uncompressed Size is not present.
+ */
+ vli_type uncompressed;
+
+ /* Size of the Block Header field */
+ uint32_t size;
+ } block_header;
+
+ /* Information collected when decoding Blocks */
+ struct {
+ /* Observed compressed size of the current Block */
+ vli_type compressed;
+
+ /* Observed uncompressed size of the current Block */
+ vli_type uncompressed;
+
+ /* Number of Blocks decoded so far */
+ vli_type count;
+
+ /*
+ * Hash calculated from the Block sizes. This is used to
+ * validate the Index field.
+ */
+ struct xz_dec_hash hash;
+ } block;
+
+ /* Variables needed when verifying the Index field */
+ struct {
+ /* Position in dec_index() */
+ enum {
+ SEQ_INDEX_COUNT,
+ SEQ_INDEX_UNPADDED,
+ SEQ_INDEX_UNCOMPRESSED
+ } sequence;
+
+ /* Size of the Index in bytes */
+ vli_type size;
+
+ /* Number of Records (matches block.count in valid files) */
+ vli_type count;
+
+ /*
+ * Hash calculated from the Records (matches block.hash in
+ * valid files).
+ */
+ struct xz_dec_hash hash;
+ } index;
+
+ /*
+ * Temporary buffer needed to hold Stream Header, Block Header,
+ * and Stream Footer. The Block Header is the biggest (1 KiB)
+ * so we reserve space according to that. buf[] has to be aligned
+ * to a multiple of four bytes; the size_t variables before it
+ * should guarantee this.
+ */
+ struct {
+ size_t pos;
+ size_t size;
+ uint8_t buf[1024];
+ } temp;
+
+ struct xz_dec_lzma2 *lzma2;
+
+#ifdef XZ_DEC_BCJ
+ struct xz_dec_bcj *bcj;
+ bool bcj_active;
+#endif
+};
+
+#ifdef XZ_DEC_ANY_CHECK
+/* Sizes of the Check field with different Check IDs */
+static const uint8_t check_sizes[16] = {
+ 0,
+ 4, 4, 4,
+ 8, 8, 8,
+ 16, 16, 16,
+ 32, 32, 32,
+ 64, 64, 64
+};
+#endif
+
+/*
+ * Fill s->temp by copying data starting from b->in[b->in_pos]. Caller
+ * must have set s->temp.pos to indicate how much data we are supposed
+ * to copy into s->temp.buf. Return true once s->temp.pos has reached
+ * s->temp.size.
+ */
+static bool fill_temp(struct xz_dec *s, struct xz_buf *b)
+{
+ size_t copy_size = min_t(size_t,
+ b->in_size - b->in_pos, s->temp.size - s->temp.pos);
+
+ memcpy(s->temp.buf + s->temp.pos, b->in + b->in_pos, copy_size);
+ b->in_pos += copy_size;
+ s->temp.pos += copy_size;
+
+ if (s->temp.pos == s->temp.size) {
+ s->temp.pos = 0;
+ return true;
+ }
+
+ return false;
+}
+
+/* Decode a variable-length integer (little-endian base-128 encoding) */
+static enum xz_ret dec_vli(struct xz_dec *s, const uint8_t *in,
+ size_t *in_pos, size_t in_size)
+{
+ uint8_t byte;
+
+ if (s->pos == 0)
+ s->vli = 0;
+
+ while (*in_pos < in_size) {
+ byte = in[*in_pos];
+ ++*in_pos;
+
+ s->vli |= (vli_type)(byte & 0x7F) << s->pos;
+
+ if ((byte & 0x80) == 0) {
+ /* Don't allow non-minimal encodings. */
+ if (byte == 0 && s->pos != 0)
+ return XZ_DATA_ERROR;
+
+ s->pos = 0;
+ return XZ_STREAM_END;
+ }
+
+ s->pos += 7;
+ if (s->pos == 7 * VLI_BYTES_MAX)
+ return XZ_DATA_ERROR;
+ }
+
+ return XZ_OK;
+}
+
+/*
+ * Decode the Compressed Data field from a Block. Update and validate
+ * the observed compressed and uncompressed sizes of the Block so that
+ * they don't exceed the values possibly stored in the Block Header
+ * (validation assumes that no integer overflow occurs, since vli_type
+ * is normally uint64_t). Update the CRC32 or CRC64 value if presence of
+ * the CRC32 or CRC64 field was indicated in Stream Header.
+ *
+ * Once the decoding is finished, validate that the observed sizes match
+ * the sizes possibly stored in the Block Header. Update the hash and
+ * Block count, which are later used to validate the Index field.
+ */
+static enum xz_ret dec_block(struct xz_dec *s, struct xz_buf *b)
+{
+ enum xz_ret ret;
+
+ s->in_start = b->in_pos;
+ s->out_start = b->out_pos;
+
+#ifdef XZ_DEC_BCJ
+ if (s->bcj_active)
+ ret = xz_dec_bcj_run(s->bcj, s->lzma2, b);
+ else
+#endif
+ ret = xz_dec_lzma2_run(s->lzma2, b);
+
+ s->block.compressed += b->in_pos - s->in_start;
+ s->block.uncompressed += b->out_pos - s->out_start;
+
+ /*
+ * There is no need to separately check for VLI_UNKNOWN, since
+ * the observed sizes are always smaller than VLI_UNKNOWN.
+ */
+ if (s->block.compressed > s->block_header.compressed
+ || s->block.uncompressed
+ > s->block_header.uncompressed)
+ return XZ_DATA_ERROR;
+
+ if (s->check_type == XZ_CHECK_CRC32)
+ s->crc = xz_crc32(b->out + s->out_start,
+ b->out_pos - s->out_start, s->crc);
+#ifdef XZ_USE_CRC64
+ else if (s->check_type == XZ_CHECK_CRC64)
+ s->crc = xz_crc64(b->out + s->out_start,
+ b->out_pos - s->out_start, s->crc);
+#endif
+
+ if (ret == XZ_STREAM_END) {
+ if (s->block_header.compressed != VLI_UNKNOWN
+ && s->block_header.compressed
+ != s->block.compressed)
+ return XZ_DATA_ERROR;
+
+ if (s->block_header.uncompressed != VLI_UNKNOWN
+ && s->block_header.uncompressed
+ != s->block.uncompressed)
+ return XZ_DATA_ERROR;
+
+ s->block.hash.unpadded += s->block_header.size
+ + s->block.compressed;
+
+#ifdef XZ_DEC_ANY_CHECK
+ s->block.hash.unpadded += check_sizes[s->check_type];
+#else
+ if (s->check_type == XZ_CHECK_CRC32)
+ s->block.hash.unpadded += 4;
+ else if (IS_CRC64(s->check_type))
+ s->block.hash.unpadded += 8;
+#endif
+
+ s->block.hash.uncompressed += s->block.uncompressed;
+ s->block.hash.crc32 = xz_crc32(
+ (const uint8_t *)&s->block.hash,
+ sizeof(s->block.hash), s->block.hash.crc32);
+
+ ++s->block.count;
+ }
+
+ return ret;
+}
+
+/* Update the Index size and the CRC32 value. */
+static void index_update(struct xz_dec *s, const struct xz_buf *b)
+{
+ size_t in_used = b->in_pos - s->in_start;
+ s->index.size += in_used;
+ s->crc = xz_crc32(b->in + s->in_start, in_used, s->crc);
+}
+
+/*
+ * Decode the Number of Records, Unpadded Size, and Uncompressed Size
+ * fields from the Index field. That is, Index Padding and CRC32 are not
+ * decoded by this function.
+ *
+ * This can return XZ_OK (more input needed), XZ_STREAM_END (everything
+ * successfully decoded), or XZ_DATA_ERROR (input is corrupt).
+ */
+static enum xz_ret dec_index(struct xz_dec *s, struct xz_buf *b)
+{
+ enum xz_ret ret;
+
+ do {
+ ret = dec_vli(s, b->in, &b->in_pos, b->in_size);
+ if (ret != XZ_STREAM_END) {
+ index_update(s, b);
+ return ret;
+ }
+
+ switch (s->index.sequence) {
+ case SEQ_INDEX_COUNT:
+ s->index.count = s->vli;
+
+ /*
+ * Validate that the Number of Records field
+ * indicates the same number of Records as
+ * there were Blocks in the Stream.
+ */
+ if (s->index.count != s->block.count)
+ return XZ_DATA_ERROR;
+
+ s->index.sequence = SEQ_INDEX_UNPADDED;
+ break;
+
+ case SEQ_INDEX_UNPADDED:
+ s->index.hash.unpadded += s->vli;
+ s->index.sequence = SEQ_INDEX_UNCOMPRESSED;
+ break;
+
+ case SEQ_INDEX_UNCOMPRESSED:
+ s->index.hash.uncompressed += s->vli;
+ s->index.hash.crc32 = xz_crc32(
+ (const uint8_t *)&s->index.hash,
+ sizeof(s->index.hash),
+ s->index.hash.crc32);
+ --s->index.count;
+ s->index.sequence = SEQ_INDEX_UNPADDED;
+ break;
+ }
+ } while (s->index.count > 0);
+
+ return XZ_STREAM_END;
+}
+
+/*
+ * Validate that the next four or eight input bytes match the value
+ * of s->crc. s->pos must be zero when starting to validate the first byte.
+ * The "bits" argument allows using the same code for both CRC32 and CRC64.
+ */
+static enum xz_ret crc_validate(struct xz_dec *s, struct xz_buf *b,
+ uint32_t bits)
+{
+ do {
+ if (b->in_pos == b->in_size)
+ return XZ_OK;
+
+ if (((s->crc >> s->pos) & 0xFF) != b->in[b->in_pos++])
+ return XZ_DATA_ERROR;
+
+ s->pos += 8;
+
+ } while (s->pos < bits);
+
+ s->crc = 0;
+ s->pos = 0;
+
+ return XZ_STREAM_END;
+}
+
+#ifdef XZ_DEC_ANY_CHECK
+/*
+ * Skip over the Check field when the Check ID is not supported.
+ * Returns true once the whole Check field has been skipped over.
+ */
+static bool check_skip(struct xz_dec *s, struct xz_buf *b)
+{
+ while (s->pos < check_sizes[s->check_type]) {
+ if (b->in_pos == b->in_size)
+ return false;
+
+ ++b->in_pos;
+ ++s->pos;
+ }
+
+ s->pos = 0;
+
+ return true;
+}
+#endif
+
+/* Decode the Stream Header field (the first 12 bytes of the .xz Stream). */
+static enum xz_ret dec_stream_header(struct xz_dec *s)
+{
+ if (!memeq(s->temp.buf, HEADER_MAGIC, HEADER_MAGIC_SIZE))
+ return XZ_FORMAT_ERROR;
+
+ if (xz_crc32(s->temp.buf + HEADER_MAGIC_SIZE, 2, 0)
+ != get_le32(s->temp.buf + HEADER_MAGIC_SIZE + 2))
+ return XZ_DATA_ERROR;
+
+ if (s->temp.buf[HEADER_MAGIC_SIZE] != 0)
+ return XZ_OPTIONS_ERROR;
+
+ /*
+ * Of integrity checks, we support none (Check ID = 0),
+ * CRC32 (Check ID = 1), and optionally CRC64 (Check ID = 4).
+ * However, if XZ_DEC_ANY_CHECK is defined, we will accept other
+ * check types too, but then the check won't be verified and
+ * a warning (XZ_UNSUPPORTED_CHECK) will be given.
+ */
+ s->check_type = s->temp.buf[HEADER_MAGIC_SIZE + 1];
+
+#ifdef XZ_DEC_ANY_CHECK
+ if (s->check_type > XZ_CHECK_MAX)
+ return XZ_OPTIONS_ERROR;
+
+ if (s->check_type > XZ_CHECK_CRC32 && !IS_CRC64(s->check_type))
+ return XZ_UNSUPPORTED_CHECK;
+#else
+ if (s->check_type > XZ_CHECK_CRC32 && !IS_CRC64(s->check_type))
+ return XZ_OPTIONS_ERROR;
+#endif
+
+ return XZ_OK;
+}
+
+/* Decode the Stream Footer field (the last 12 bytes of the .xz Stream) */
+static enum xz_ret dec_stream_footer(struct xz_dec *s)
+{
+ if (!memeq(s->temp.buf + 10, FOOTER_MAGIC, FOOTER_MAGIC_SIZE))
+ return XZ_DATA_ERROR;
+
+ if (xz_crc32(s->temp.buf + 4, 6, 0) != get_le32(s->temp.buf))
+ return XZ_DATA_ERROR;
+
+ /*
+ * Validate Backward Size. Note that we never added the size of the
+ * Index CRC32 field to s->index.size, thus we use s->index.size / 4
+ * instead of s->index.size / 4 - 1.
+ */
+ if ((s->index.size >> 2) != get_le32(s->temp.buf + 4))
+ return XZ_DATA_ERROR;
+
+ if (s->temp.buf[8] != 0 || s->temp.buf[9] != s->check_type)
+ return XZ_DATA_ERROR;
+
+ /*
+ * Use XZ_STREAM_END instead of XZ_OK to be more convenient
+ * for the caller.
+ */
+ return XZ_STREAM_END;
+}
+
+/* Decode the Block Header and initialize the filter chain. */
+static enum xz_ret dec_block_header(struct xz_dec *s)
+{
+ enum xz_ret ret;
+
+ /*
+ * Validate the CRC32. We know that the temp buffer is at least
+ * eight bytes so this is safe.
+ */
+ s->temp.size -= 4;
+ if (xz_crc32(s->temp.buf, s->temp.size, 0)
+ != get_le32(s->temp.buf + s->temp.size))
+ return XZ_DATA_ERROR;
+
+ s->temp.pos = 2;
+
+ /*
+ * Catch unsupported Block Flags. We support only one or two filters
+ * in the chain, so we catch that with the same test.
+ */
+#ifdef XZ_DEC_BCJ
+ if (s->temp.buf[1] & 0x3E)
+#else
+ if (s->temp.buf[1] & 0x3F)
+#endif
+ return XZ_OPTIONS_ERROR;
+
+ /* Compressed Size */
+ if (s->temp.buf[1] & 0x40) {
+ if (dec_vli(s, s->temp.buf, &s->temp.pos, s->temp.size)
+ != XZ_STREAM_END)
+ return XZ_DATA_ERROR;
+
+ s->block_header.compressed = s->vli;
+ } else {
+ s->block_header.compressed = VLI_UNKNOWN;
+ }
+
+ /* Uncompressed Size */
+ if (s->temp.buf[1] & 0x80) {
+ if (dec_vli(s, s->temp.buf, &s->temp.pos, s->temp.size)
+ != XZ_STREAM_END)
+ return XZ_DATA_ERROR;
+
+ s->block_header.uncompressed = s->vli;
+ } else {
+ s->block_header.uncompressed = VLI_UNKNOWN;
+ }
+
+#ifdef XZ_DEC_BCJ
+ /* If there are two filters, the first one must be a BCJ filter. */
+ s->bcj_active = s->temp.buf[1] & 0x01;
+ if (s->bcj_active) {
+ if (s->temp.size - s->temp.pos < 2)
+ return XZ_OPTIONS_ERROR;
+
+ ret = xz_dec_bcj_reset(s->bcj, s->temp.buf[s->temp.pos++]);
+ if (ret != XZ_OK)
+ return ret;
+
+ /*
+ * We don't support custom start offset,
+ * so Size of Properties must be zero.
+ */
+ if (s->temp.buf[s->temp.pos++] != 0x00)
+ return XZ_OPTIONS_ERROR;
+ }
+#endif
+
+ /* Valid Filter Flags always take at least two bytes. */
+ if (s->temp.size - s->temp.pos < 2)
+ return XZ_DATA_ERROR;
+
+ /* Filter ID = LZMA2 */
+ if (s->temp.buf[s->temp.pos++] != 0x21)
+ return XZ_OPTIONS_ERROR;
+
+ /* Size of Properties = 1-byte Filter Properties */
+ if (s->temp.buf[s->temp.pos++] != 0x01)
+ return XZ_OPTIONS_ERROR;
+
+ /* Filter Properties contains LZMA2 dictionary size. */
+ if (s->temp.size - s->temp.pos < 1)
+ return XZ_DATA_ERROR;
+
+ ret = xz_dec_lzma2_reset(s->lzma2, s->temp.buf[s->temp.pos++]);
+ if (ret != XZ_OK)
+ return ret;
+
+ /* The rest must be Header Padding. */
+ while (s->temp.pos < s->temp.size)
+ if (s->temp.buf[s->temp.pos++] != 0x00)
+ return XZ_OPTIONS_ERROR;
+
+ s->temp.pos = 0;
+ s->block.compressed = 0;
+ s->block.uncompressed = 0;
+
+ return XZ_OK;
+}
+
+static enum xz_ret dec_main(struct xz_dec *s, struct xz_buf *b)
+{
+ enum xz_ret ret;
+
+ /*
+ * Store the start position for the case when we are in the middle
+ * of the Index field.
+ */
+ s->in_start = b->in_pos;
+
+ while (true) {
+ switch (s->sequence) {
+ case SEQ_STREAM_HEADER:
+ /*
+ * Stream Header is copied to s->temp, and then
+ * decoded from there. This way if the caller
+ * gives us only little input at a time, we can
+ * still keep the Stream Header decoding code
+ * simple. Similar approach is used in many places
+ * in this file.
+ */
+ if (!fill_temp(s, b))
+ return XZ_OK;
+
+ /*
+ * If dec_stream_header() returns
+ * XZ_UNSUPPORTED_CHECK, it is still possible
+ * to continue decoding if working in multi-call
+ * mode. Thus, update s->sequence before calling
+ * dec_stream_header().
+ */
+ s->sequence = SEQ_BLOCK_START;
+
+ ret = dec_stream_header(s);
+ if (ret != XZ_OK)
+ return ret;
+
+ case SEQ_BLOCK_START:
+ /* We need one byte of input to continue. */
+ if (b->in_pos == b->in_size)
+ return XZ_OK;
+
+ /* See if this is the beginning of the Index field. */
+ if (b->in[b->in_pos] == 0) {
+ s->in_start = b->in_pos++;
+ s->sequence = SEQ_INDEX;
+ break;
+ }
+
+ /*
+ * Calculate the size of the Block Header and
+ * prepare to decode it.
+ */
+ s->block_header.size
+ = ((uint32_t)b->in[b->in_pos] + 1) * 4;
+
+ s->temp.size = s->block_header.size;
+ s->temp.pos = 0;
+ s->sequence = SEQ_BLOCK_HEADER;
+
+ case SEQ_BLOCK_HEADER:
+ if (!fill_temp(s, b))
+ return XZ_OK;
+
+ ret = dec_block_header(s);
+ if (ret != XZ_OK)
+ return ret;
+
+ s->sequence = SEQ_BLOCK_UNCOMPRESS;
+
+ case SEQ_BLOCK_UNCOMPRESS:
+ ret = dec_block(s, b);
+ if (ret != XZ_STREAM_END)
+ return ret;
+
+ s->sequence = SEQ_BLOCK_PADDING;
+
+ case SEQ_BLOCK_PADDING:
+ /*
+ * Size of Compressed Data + Block Padding
+ * must be a multiple of four. We don't need
+ * s->block.compressed for anything else
+ * anymore, so we use it here to test the size
+ * of the Block Padding field.
+ */
+ while (s->block.compressed & 3) {
+ if (b->in_pos == b->in_size)
+ return XZ_OK;
+
+ if (b->in[b->in_pos++] != 0)
+ return XZ_DATA_ERROR;
+
+ ++s->block.compressed;
+ }
+
+ s->sequence = SEQ_BLOCK_CHECK;
+
+ case SEQ_BLOCK_CHECK:
+ if (s->check_type == XZ_CHECK_CRC32) {
+ ret = crc_validate(s, b, 32);
+ if (ret != XZ_STREAM_END)
+ return ret;
+ }
+ else if (IS_CRC64(s->check_type)) {
+ ret = crc_validate(s, b, 64);
+ if (ret != XZ_STREAM_END)
+ return ret;
+ }
+#ifdef XZ_DEC_ANY_CHECK
+ else if (!check_skip(s, b)) {
+ return XZ_OK;
+ }
+#endif
+
+ s->sequence = SEQ_BLOCK_START;
+ break;
+
+ case SEQ_INDEX:
+ ret = dec_index(s, b);
+ if (ret != XZ_STREAM_END)
+ return ret;
+
+ s->sequence = SEQ_INDEX_PADDING;
+
+ case SEQ_INDEX_PADDING:
+ while ((s->index.size + (b->in_pos - s->in_start))
+ & 3) {
+ if (b->in_pos == b->in_size) {
+ index_update(s, b);
+ return XZ_OK;
+ }
+
+ if (b->in[b->in_pos++] != 0)
+ return XZ_DATA_ERROR;
+ }
+
+ /* Finish the CRC32 value and Index size. */
+ index_update(s, b);
+
+ /* Compare the hashes to validate the Index field. */
+ if (!memeq(&s->block.hash, &s->index.hash,
+ sizeof(s->block.hash)))
+ return XZ_DATA_ERROR;
+
+ s->sequence = SEQ_INDEX_CRC32;
+
+ case SEQ_INDEX_CRC32:
+ ret = crc_validate(s, b, 32);
+ if (ret != XZ_STREAM_END)
+ return ret;
+
+ s->temp.size = STREAM_HEADER_SIZE;
+ s->sequence = SEQ_STREAM_FOOTER;
+
+ case SEQ_STREAM_FOOTER:
+ if (!fill_temp(s, b))
+ return XZ_OK;
+
+ return dec_stream_footer(s);
+ }
+ }
+
+ /* Never reached */
+}
+
+/*
+ * xz_dec_run() is a wrapper for dec_main() to handle some special cases in
+ * multi-call and single-call decoding.
+ *
+ * In multi-call mode, we must return XZ_BUF_ERROR when it seems clear that we
+ * are not going to make any progress anymore. This is to prevent the caller
+ * from calling us infinitely when the input file is truncated or otherwise
+ * corrupt. Since zlib-style API allows that the caller fills the input buffer
+ * only when the decoder doesn't produce any new output, we have to be careful
+ * to avoid returning XZ_BUF_ERROR too easily: XZ_BUF_ERROR is returned only
+ * after the second consecutive call to xz_dec_run() that makes no progress.
+ *
+ * In single-call mode, if we couldn't decode everything and no error
+ * occurred, either the input is truncated or the output buffer is too small.
+ * Since we know that the last input byte never produces any output, we know
+ * that if all the input was consumed and decoding wasn't finished, the file
+ * must be corrupt. Otherwise the output buffer has to be too small or the
+ * file is corrupt in a way that decoding it produces too big output.
+ *
+ * If single-call decoding fails, we reset b->in_pos and b->out_pos back to
+ * their original values. This is because with some filter chains there won't
+ * be any valid uncompressed data in the output buffer unless the decoding
+ * actually succeeds (that's the price to pay of using the output buffer as
+ * the workspace).
+ */
+XZ_EXTERN enum xz_ret xz_dec_run(struct xz_dec *s, struct xz_buf *b)
+{
+ size_t in_start;
+ size_t out_start;
+ enum xz_ret ret;
+
+ if (DEC_IS_SINGLE(s->mode))
+ xz_dec_reset(s);
+
+ in_start = b->in_pos;
+ out_start = b->out_pos;
+ ret = dec_main(s, b);
+
+ if (DEC_IS_SINGLE(s->mode)) {
+ if (ret == XZ_OK)
+ ret = b->in_pos == b->in_size
+ ? XZ_DATA_ERROR : XZ_BUF_ERROR;
+
+ if (ret != XZ_STREAM_END) {
+ b->in_pos = in_start;
+ b->out_pos = out_start;
+ }
+
+ } else if (ret == XZ_OK && in_start == b->in_pos
+ && out_start == b->out_pos) {
+ if (s->allow_buf_error)
+ ret = XZ_BUF_ERROR;
+
+ s->allow_buf_error = true;
+ } else {
+ s->allow_buf_error = false;
+ }
+
+ return ret;
+}
+
+XZ_EXTERN struct xz_dec *xz_dec_init(enum xz_mode mode, uint32_t dict_max)
+{
+ struct xz_dec *s = kmalloc(sizeof(*s), GFP_KERNEL);
+ if (s == NULL)
+ return NULL;
+
+ s->mode = mode;
+
+#ifdef XZ_DEC_BCJ
+ s->bcj = xz_dec_bcj_create(DEC_IS_SINGLE(mode));
+ if (s->bcj == NULL)
+ goto error_bcj;
+#endif
+
+ s->lzma2 = xz_dec_lzma2_create(mode, dict_max);
+ if (s->lzma2 == NULL)
+ goto error_lzma2;
+
+ xz_dec_reset(s);
+ return s;
+
+error_lzma2:
+#ifdef XZ_DEC_BCJ
+ xz_dec_bcj_end(s->bcj);
+error_bcj:
+#endif
+ kfree(s);
+ return NULL;
+}
+
+XZ_EXTERN void xz_dec_reset(struct xz_dec *s)
+{
+ s->sequence = SEQ_STREAM_HEADER;
+ s->allow_buf_error = false;
+ s->pos = 0;
+ s->crc = 0;
+ memzero(&s->block, sizeof(s->block));
+ memzero(&s->index, sizeof(s->index));
+ s->temp.pos = 0;
+ s->temp.size = STREAM_HEADER_SIZE;
+}
+
+XZ_EXTERN void xz_dec_end(struct xz_dec *s)
+{
+ if (s != NULL) {
+ xz_dec_lzma2_end(s->lzma2);
+#ifdef XZ_DEC_BCJ
+ xz_dec_bcj_end(s->bcj);
+#endif
+ kfree(s);
+ }
+}
diff --git a/lzma/xz-embedded/xz_dec_syms.c b/lzma/xz-embedded/xz_dec_syms.c
new file mode 100644
index 0000000..32eb3c0
--- /dev/null
+++ b/lzma/xz-embedded/xz_dec_syms.c
@@ -0,0 +1,26 @@
+/*
+ * XZ decoder module information
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+#include <linux/module.h>
+#include <linux/xz.h>
+
+EXPORT_SYMBOL(xz_dec_init);
+EXPORT_SYMBOL(xz_dec_reset);
+EXPORT_SYMBOL(xz_dec_run);
+EXPORT_SYMBOL(xz_dec_end);
+
+MODULE_DESCRIPTION("XZ decompressor");
+MODULE_VERSION("1.0");
+MODULE_AUTHOR("Lasse Collin <lasse.collin@tukaani.org> and Igor Pavlov");
+
+/*
+ * This code is in the public domain, but in Linux it's simplest to just
+ * say it's GPL and consider the authors as the copyright holders.
+ */
+MODULE_LICENSE("GPL");
diff --git a/lzma/xz-embedded/xz_dec_test.c b/lzma/xz-embedded/xz_dec_test.c
new file mode 100644
index 0000000..da28a19
--- /dev/null
+++ b/lzma/xz-embedded/xz_dec_test.c
@@ -0,0 +1,220 @@
+/*
+ * XZ decoder tester
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/crc32.h>
+#include <linux/xz.h>
+
+/* Maximum supported dictionary size */
+#define DICT_MAX (1 << 20)
+
+/* Device name to pass to register_chrdev(). */
+#define DEVICE_NAME "xz_dec_test"
+
+/* Dynamically allocated device major number */
+static int device_major;
+
+/*
+ * We reuse the same decoder state, and thus can decode only one
+ * file at a time.
+ */
+static bool device_is_open;
+
+/* XZ decoder state */
+static struct xz_dec *state;
+
+/*
+ * Return value of xz_dec_run(). We need to avoid calling xz_dec_run() after
+ * it has returned XZ_STREAM_END, so we make this static.
+ */
+static enum xz_ret ret;
+
+/*
+ * Input and output buffers. The input buffer is used as a temporary safe
+ * place for the data coming from the userspace.
+ */
+static uint8_t buffer_in[1024];
+static uint8_t buffer_out[1024];
+
+/*
+ * Structure to pass the input and output buffers to the XZ decoder.
+ * A few of the fields are never modified so we initialize them here.
+ */
+static struct xz_buf buffers = {
+ .in = buffer_in,
+ .out = buffer_out,
+ .out_size = sizeof(buffer_out)
+};
+
+/*
+ * CRC32 of uncompressed data. This is used to give the user a simple way
+ * to check that the decoder produces correct output.
+ */
+static uint32_t crc;
+
+static int xz_dec_test_open(struct inode *i, struct file *f)
+{
+ if (device_is_open)
+ return -EBUSY;
+
+ device_is_open = true;
+
+ xz_dec_reset(state);
+ ret = XZ_OK;
+ crc = 0xFFFFFFFF;
+
+ buffers.in_pos = 0;
+ buffers.in_size = 0;
+ buffers.out_pos = 0;
+
+ printk(KERN_INFO DEVICE_NAME ": opened\n");
+ return 0;
+}
+
+static int xz_dec_test_release(struct inode *i, struct file *f)
+{
+ device_is_open = false;
+
+ if (ret == XZ_OK)
+ printk(KERN_INFO DEVICE_NAME ": input was truncated\n");
+
+ printk(KERN_INFO DEVICE_NAME ": closed\n");
+ return 0;
+}
+
+/*
+ * Decode the data given to us from the userspace. CRC32 of the uncompressed
+ * data is calculated and is printed at the end of successful decoding. The
+ * uncompressed data isn't stored anywhere for further use.
+ *
+ * The .xz file must have exactly one Stream and no Stream Padding. The data
+ * after the first Stream is considered to be garbage.
+ */
+static ssize_t xz_dec_test_write(struct file *file, const char __user *buf,
+ size_t size, loff_t *pos)
+{
+ size_t remaining;
+
+ if (ret != XZ_OK) {
+ if (size > 0)
+ printk(KERN_INFO DEVICE_NAME ": %zu bytes of "
+ "garbage at the end of the file\n",
+ size);
+
+ return -ENOSPC;
+ }
+
+ printk(KERN_INFO DEVICE_NAME ": decoding %zu bytes of input\n",
+ size);
+
+ remaining = size;
+ while ((remaining > 0 || buffers.out_pos == buffers.out_size)
+ && ret == XZ_OK) {
+ if (buffers.in_pos == buffers.in_size) {
+ buffers.in_pos = 0;
+ buffers.in_size = min(remaining, sizeof(buffer_in));
+ if (copy_from_user(buffer_in, buf, buffers.in_size))
+ return -EFAULT;
+
+ buf += buffers.in_size;
+ remaining -= buffers.in_size;
+ }
+
+ buffers.out_pos = 0;
+ ret = xz_dec_run(state, &buffers);
+ crc = crc32(crc, buffer_out, buffers.out_pos);
+ }
+
+ switch (ret) {
+ case XZ_OK:
+ printk(KERN_INFO DEVICE_NAME ": XZ_OK\n");
+ return size;
+
+ case XZ_STREAM_END:
+ printk(KERN_INFO DEVICE_NAME ": XZ_STREAM_END, "
+ "CRC32 = 0x%08X\n", ~crc);
+ return size - remaining - (buffers.in_size - buffers.in_pos);
+
+ case XZ_MEMLIMIT_ERROR:
+ printk(KERN_INFO DEVICE_NAME ": XZ_MEMLIMIT_ERROR\n");
+ break;
+
+ case XZ_FORMAT_ERROR:
+ printk(KERN_INFO DEVICE_NAME ": XZ_FORMAT_ERROR\n");
+ break;
+
+ case XZ_OPTIONS_ERROR:
+ printk(KERN_INFO DEVICE_NAME ": XZ_OPTIONS_ERROR\n");
+ break;
+
+ case XZ_DATA_ERROR:
+ printk(KERN_INFO DEVICE_NAME ": XZ_DATA_ERROR\n");
+ break;
+
+ case XZ_BUF_ERROR:
+ printk(KERN_INFO DEVICE_NAME ": XZ_BUF_ERROR\n");
+ break;
+
+ default:
+ printk(KERN_INFO DEVICE_NAME ": Bug detected!\n");
+ break;
+ }
+
+ return -EIO;
+}
+
+/* Allocate the XZ decoder state and register the character device. */
+static int __init xz_dec_test_init(void)
+{
+ static const struct file_operations fileops = {
+ .owner = THIS_MODULE,
+ .open = &xz_dec_test_open,
+ .release = &xz_dec_test_release,
+ .write = &xz_dec_test_write
+ };
+
+ state = xz_dec_init(XZ_PREALLOC, DICT_MAX);
+ if (state == NULL)
+ return -ENOMEM;
+
+ device_major = register_chrdev(0, DEVICE_NAME, &fileops);
+ if (device_major < 0) {
+ xz_dec_end(state);
+ return device_major;
+ }
+
+ printk(KERN_INFO DEVICE_NAME ": module loaded\n");
+ printk(KERN_INFO DEVICE_NAME ": Create a device node with "
+ "'mknod " DEVICE_NAME " c %d 0' and write .xz files "
+ "to it.\n", device_major);
+ return 0;
+}
+
+static void __exit xz_dec_test_exit(void)
+{
+ unregister_chrdev(device_major, DEVICE_NAME);
+ xz_dec_end(state);
+ printk(KERN_INFO DEVICE_NAME ": module unloaded\n");
+}
+
+module_init(xz_dec_test_init);
+module_exit(xz_dec_test_exit);
+
+MODULE_DESCRIPTION("XZ decompressor tester");
+MODULE_VERSION("1.0");
+MODULE_AUTHOR("Lasse Collin <lasse.collin@tukaani.org>");
+
+/*
+ * This code is in the public domain, but in Linux it's simplest to just
+ * say it's GPL and consider the authors as the copyright holders.
+ */
+MODULE_LICENSE("GPL");
diff --git a/lzma/xz-embedded/xz_lzma2.h b/lzma/xz-embedded/xz_lzma2.h
new file mode 100644
index 0000000..071d67b
--- /dev/null
+++ b/lzma/xz-embedded/xz_lzma2.h
@@ -0,0 +1,204 @@
+/*
+ * LZMA2 definitions
+ *
+ * Authors: Lasse Collin <lasse.collin@tukaani.org>
+ * Igor Pavlov <http://7-zip.org/>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+#ifndef XZ_LZMA2_H
+#define XZ_LZMA2_H
+
+/* Range coder constants */
+#define RC_SHIFT_BITS 8
+#define RC_TOP_BITS 24
+#define RC_TOP_VALUE (1 << RC_TOP_BITS)
+#define RC_BIT_MODEL_TOTAL_BITS 11
+#define RC_BIT_MODEL_TOTAL (1 << RC_BIT_MODEL_TOTAL_BITS)
+#define RC_MOVE_BITS 5
+
+/*
+ * Maximum number of position states. A position state is the lowest pb
+ * number of bits of the current uncompressed offset. In some places there
+ * are different sets of probabilities for different position states.
+ */
+#define POS_STATES_MAX (1 << 4)
+
+/*
+ * This enum is used to track which LZMA symbols have occurred most recently
+ * and in which order. This information is used to predict the next symbol.
+ *
+ * Symbols:
+ * - Literal: One 8-bit byte
+ * - Match: Repeat a chunk of data at some distance
+ * - Long repeat: Multi-byte match at a recently seen distance
+ * - Short repeat: One-byte repeat at a recently seen distance
+ *
+ * The symbol names are in from STATE_oldest_older_previous. REP means
+ * either short or long repeated match, and NONLIT means any non-literal.
+ */
+enum lzma_state {
+ STATE_LIT_LIT,
+ STATE_MATCH_LIT_LIT,
+ STATE_REP_LIT_LIT,
+ STATE_SHORTREP_LIT_LIT,
+ STATE_MATCH_LIT,
+ STATE_REP_LIT,
+ STATE_SHORTREP_LIT,
+ STATE_LIT_MATCH,
+ STATE_LIT_LONGREP,
+ STATE_LIT_SHORTREP,
+ STATE_NONLIT_MATCH,
+ STATE_NONLIT_REP
+};
+
+/* Total number of states */
+#define STATES 12
+
+/* The lowest 7 states indicate that the previous state was a literal. */
+#define LIT_STATES 7
+
+/* Indicate that the latest symbol was a literal. */
+static inline void lzma_state_literal(enum lzma_state *state)
+{
+ if (*state <= STATE_SHORTREP_LIT_LIT)
+ *state = STATE_LIT_LIT;
+ else if (*state <= STATE_LIT_SHORTREP)
+ *state -= 3;
+ else
+ *state -= 6;
+}
+
+/* Indicate that the latest symbol was a match. */
+static inline void lzma_state_match(enum lzma_state *state)
+{
+ *state = *state < LIT_STATES ? STATE_LIT_MATCH : STATE_NONLIT_MATCH;
+}
+
+/* Indicate that the latest state was a long repeated match. */
+static inline void lzma_state_long_rep(enum lzma_state *state)
+{
+ *state = *state < LIT_STATES ? STATE_LIT_LONGREP : STATE_NONLIT_REP;
+}
+
+/* Indicate that the latest symbol was a short match. */
+static inline void lzma_state_short_rep(enum lzma_state *state)
+{
+ *state = *state < LIT_STATES ? STATE_LIT_SHORTREP : STATE_NONLIT_REP;
+}
+
+/* Test if the previous symbol was a literal. */
+static inline bool lzma_state_is_literal(enum lzma_state state)
+{
+ return state < LIT_STATES;
+}
+
+/* Each literal coder is divided in three sections:
+ * - 0x001-0x0FF: Without match byte
+ * - 0x101-0x1FF: With match byte; match bit is 0
+ * - 0x201-0x2FF: With match byte; match bit is 1
+ *
+ * Match byte is used when the previous LZMA symbol was something else than
+ * a literal (that is, it was some kind of match).
+ */
+#define LITERAL_CODER_SIZE 0x300
+
+/* Maximum number of literal coders */
+#define LITERAL_CODERS_MAX (1 << 4)
+
+/* Minimum length of a match is two bytes. */
+#define MATCH_LEN_MIN 2
+
+/* Match length is encoded with 4, 5, or 10 bits.
+ *
+ * Length Bits
+ * 2-9 4 = Choice=0 + 3 bits
+ * 10-17 5 = Choice=1 + Choice2=0 + 3 bits
+ * 18-273 10 = Choice=1 + Choice2=1 + 8 bits
+ */
+#define LEN_LOW_BITS 3
+#define LEN_LOW_SYMBOLS (1 << LEN_LOW_BITS)
+#define LEN_MID_BITS 3
+#define LEN_MID_SYMBOLS (1 << LEN_MID_BITS)
+#define LEN_HIGH_BITS 8
+#define LEN_HIGH_SYMBOLS (1 << LEN_HIGH_BITS)
+#define LEN_SYMBOLS (LEN_LOW_SYMBOLS + LEN_MID_SYMBOLS + LEN_HIGH_SYMBOLS)
+
+/*
+ * Maximum length of a match is 273 which is a result of the encoding
+ * described above.
+ */
+#define MATCH_LEN_MAX (MATCH_LEN_MIN + LEN_SYMBOLS - 1)
+
+/*
+ * Different sets of probabilities are used for match distances that have
+ * very short match length: Lengths of 2, 3, and 4 bytes have a separate
+ * set of probabilities for each length. The matches with longer length
+ * use a shared set of probabilities.
+ */
+#define DIST_STATES 4
+
+/*
+ * Get the index of the appropriate probability array for decoding
+ * the distance slot.
+ */
+static inline uint32_t lzma_get_dist_state(uint32_t len)
+{
+ return len < DIST_STATES + MATCH_LEN_MIN
+ ? len - MATCH_LEN_MIN : DIST_STATES - 1;
+}
+
+/*
+ * The highest two bits of a 32-bit match distance are encoded using six bits.
+ * This six-bit value is called a distance slot. This way encoding a 32-bit
+ * value takes 6-36 bits, larger values taking more bits.
+ */
+#define DIST_SLOT_BITS 6
+#define DIST_SLOTS (1 << DIST_SLOT_BITS)
+
+/* Match distances up to 127 are fully encoded using probabilities. Since
+ * the highest two bits (distance slot) are always encoded using six bits,
+ * the distances 0-3 don't need any additional bits to encode, since the
+ * distance slot itself is the same as the actual distance. DIST_MODEL_START
+ * indicates the first distance slot where at least one additional bit is
+ * needed.
+ */
+#define DIST_MODEL_START 4
+
+/*
+ * Match distances greater than 127 are encoded in three pieces:
+ * - distance slot: the highest two bits
+ * - direct bits: 2-26 bits below the highest two bits
+ * - alignment bits: four lowest bits
+ *
+ * Direct bits don't use any probabilities.
+ *
+ * The distance slot value of 14 is for distances 128-191.
+ */
+#define DIST_MODEL_END 14
+
+/* Distance slots that indicate a distance <= 127. */
+#define FULL_DISTANCES_BITS (DIST_MODEL_END / 2)
+#define FULL_DISTANCES (1 << FULL_DISTANCES_BITS)
+
+/*
+ * For match distances greater than 127, only the highest two bits and the
+ * lowest four bits (alignment) is encoded using probabilities.
+ */
+#define ALIGN_BITS 4
+#define ALIGN_SIZE (1 << ALIGN_BITS)
+#define ALIGN_MASK (ALIGN_SIZE - 1)
+
+/* Total number of all probability variables */
+#define PROBS_TOTAL (1846 + LITERAL_CODERS_MAX * LITERAL_CODER_SIZE)
+
+/*
+ * LZMA remembers the four most recent match distances. Reusing these
+ * distances tends to take less space than re-encoding the actual
+ * distance value.
+ */
+#define REPS 4
+
+#endif
diff --git a/lzma/xz-embedded/xz_private.h b/lzma/xz-embedded/xz_private.h
new file mode 100644
index 0000000..482b90f
--- /dev/null
+++ b/lzma/xz-embedded/xz_private.h
@@ -0,0 +1,156 @@
+/*
+ * Private includes and definitions
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+#ifndef XZ_PRIVATE_H
+#define XZ_PRIVATE_H
+
+#ifdef __KERNEL__
+# include <linux/xz.h>
+# include <linux/kernel.h>
+# include <asm/unaligned.h>
+ /* XZ_PREBOOT may be defined only via decompress_unxz.c. */
+# ifndef XZ_PREBOOT
+# include <linux/slab.h>
+# include <linux/vmalloc.h>
+# include <linux/string.h>
+# ifdef CONFIG_XZ_DEC_X86
+# define XZ_DEC_X86
+# endif
+# ifdef CONFIG_XZ_DEC_POWERPC
+# define XZ_DEC_POWERPC
+# endif
+# ifdef CONFIG_XZ_DEC_IA64
+# define XZ_DEC_IA64
+# endif
+# ifdef CONFIG_XZ_DEC_ARM
+# define XZ_DEC_ARM
+# endif
+# ifdef CONFIG_XZ_DEC_ARMTHUMB
+# define XZ_DEC_ARMTHUMB
+# endif
+# ifdef CONFIG_XZ_DEC_SPARC
+# define XZ_DEC_SPARC
+# endif
+# define memeq(a, b, size) (memcmp(a, b, size) == 0)
+# define memzero(buf, size) memset(buf, 0, size)
+# endif
+# define get_le32(p) le32_to_cpup((const uint32_t *)(p))
+#else
+ /*
+ * For userspace builds, use a separate header to define the required
+ * macros and functions. This makes it easier to adapt the code into
+ * different environments and avoids clutter in the Linux kernel tree.
+ */
+# include "xz_config.h"
+#endif
+
+/* If no specific decoding mode is requested, enable support for all modes. */
+#if !defined(XZ_DEC_SINGLE) && !defined(XZ_DEC_PREALLOC) \
+ && !defined(XZ_DEC_DYNALLOC)
+# define XZ_DEC_SINGLE
+# define XZ_DEC_PREALLOC
+# define XZ_DEC_DYNALLOC
+#endif
+
+/*
+ * The DEC_IS_foo(mode) macros are used in "if" statements. If only some
+ * of the supported modes are enabled, these macros will evaluate to true or
+ * false at compile time and thus allow the compiler to omit unneeded code.
+ */
+#ifdef XZ_DEC_SINGLE
+# define DEC_IS_SINGLE(mode) ((mode) == XZ_SINGLE)
+#else
+# define DEC_IS_SINGLE(mode) (false)
+#endif
+
+#ifdef XZ_DEC_PREALLOC
+# define DEC_IS_PREALLOC(mode) ((mode) == XZ_PREALLOC)
+#else
+# define DEC_IS_PREALLOC(mode) (false)
+#endif
+
+#ifdef XZ_DEC_DYNALLOC
+# define DEC_IS_DYNALLOC(mode) ((mode) == XZ_DYNALLOC)
+#else
+# define DEC_IS_DYNALLOC(mode) (false)
+#endif
+
+#if !defined(XZ_DEC_SINGLE)
+# define DEC_IS_MULTI(mode) (true)
+#elif defined(XZ_DEC_PREALLOC) || defined(XZ_DEC_DYNALLOC)
+# define DEC_IS_MULTI(mode) ((mode) != XZ_SINGLE)
+#else
+# define DEC_IS_MULTI(mode) (false)
+#endif
+
+/*
+ * If any of the BCJ filter decoders are wanted, define XZ_DEC_BCJ.
+ * XZ_DEC_BCJ is used to enable generic support for BCJ decoders.
+ */
+#ifndef XZ_DEC_BCJ
+# if defined(XZ_DEC_X86) || defined(XZ_DEC_POWERPC) \
+ || defined(XZ_DEC_IA64) || defined(XZ_DEC_ARM) \
+ || defined(XZ_DEC_ARM) || defined(XZ_DEC_ARMTHUMB) \
+ || defined(XZ_DEC_SPARC)
+# define XZ_DEC_BCJ
+# endif
+#endif
+
+/*
+ * Allocate memory for LZMA2 decoder. xz_dec_lzma2_reset() must be used
+ * before calling xz_dec_lzma2_run().
+ */
+XZ_EXTERN struct xz_dec_lzma2 *xz_dec_lzma2_create(enum xz_mode mode,
+ uint32_t dict_max);
+
+/*
+ * Decode the LZMA2 properties (one byte) and reset the decoder. Return
+ * XZ_OK on success, XZ_MEMLIMIT_ERROR if the preallocated dictionary is not
+ * big enough, and XZ_OPTIONS_ERROR if props indicates something that this
+ * decoder doesn't support.
+ */
+XZ_EXTERN enum xz_ret xz_dec_lzma2_reset(struct xz_dec_lzma2 *s,
+ uint8_t props);
+
+/* Decode raw LZMA2 stream from b->in to b->out. */
+XZ_EXTERN enum xz_ret xz_dec_lzma2_run(struct xz_dec_lzma2 *s,
+ struct xz_buf *b);
+
+/* Free the memory allocated for the LZMA2 decoder. */
+XZ_EXTERN void xz_dec_lzma2_end(struct xz_dec_lzma2 *s);
+
+#ifdef XZ_DEC_BCJ
+/*
+ * Allocate memory for BCJ decoders. xz_dec_bcj_reset() must be used before
+ * calling xz_dec_bcj_run().
+ */
+XZ_EXTERN struct xz_dec_bcj *xz_dec_bcj_create(bool single_call);
+
+/*
+ * Decode the Filter ID of a BCJ filter. This implementation doesn't
+ * support custom start offsets, so no decoding of Filter Properties
+ * is needed. Returns XZ_OK if the given Filter ID is supported.
+ * Otherwise XZ_OPTIONS_ERROR is returned.
+ */
+XZ_EXTERN enum xz_ret xz_dec_bcj_reset(struct xz_dec_bcj *s, uint8_t id);
+
+/*
+ * Decode raw BCJ + LZMA2 stream. This must be used only if there actually is
+ * a BCJ filter in the chain. If the chain has only LZMA2, xz_dec_lzma2_run()
+ * must be called directly.
+ */
+XZ_EXTERN enum xz_ret xz_dec_bcj_run(struct xz_dec_bcj *s,
+ struct xz_dec_lzma2 *lzma2,
+ struct xz_buf *b);
+
+/* Free the memory allocated for the BCJ filters. */
+#define xz_dec_bcj_end(s) kfree(s)
+#endif
+
+#endif
diff --git a/lzma/xz-embedded/xz_stream.h b/lzma/xz-embedded/xz_stream.h
new file mode 100644
index 0000000..66cb5a7
--- /dev/null
+++ b/lzma/xz-embedded/xz_stream.h
@@ -0,0 +1,62 @@
+/*
+ * Definitions for handling the .xz file format
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+#ifndef XZ_STREAM_H
+#define XZ_STREAM_H
+
+#if defined(__KERNEL__) && !XZ_INTERNAL_CRC32
+# include <linux/crc32.h>
+# undef crc32
+# define xz_crc32(buf, size, crc) \
+ (~crc32_le(~(uint32_t)(crc), buf, size))
+#endif
+
+/*
+ * See the .xz file format specification at
+ * http://tukaani.org/xz/xz-file-format.txt
+ * to understand the container format.
+ */
+
+#define STREAM_HEADER_SIZE 12
+
+#define HEADER_MAGIC "\3757zXZ"
+#define HEADER_MAGIC_SIZE 6
+
+#define FOOTER_MAGIC "YZ"
+#define FOOTER_MAGIC_SIZE 2
+
+/*
+ * Variable-length integer can hold a 63-bit unsigned integer or a special
+ * value indicating that the value is unknown.
+ *
+ * Experimental: vli_type can be defined to uint32_t to save a few bytes
+ * in code size (no effect on speed). Doing so limits the uncompressed and
+ * compressed size of the file to less than 256 MiB and may also weaken
+ * error detection slightly.
+ */
+typedef uint64_t vli_type;
+
+#define VLI_MAX ((vli_type)-1 / 2)
+#define VLI_UNKNOWN ((vli_type)-1)
+
+/* Maximum encoded size of a VLI */
+#define VLI_BYTES_MAX (sizeof(vli_type) * 8 / 7)
+
+/* Integrity Check types */
+enum xz_check {
+ XZ_CHECK_NONE = 0,
+ XZ_CHECK_CRC32 = 1,
+ XZ_CHECK_CRC64 = 4,
+ XZ_CHECK_SHA256 = 10
+};
+
+/* Maximum possible Check ID */
+#define XZ_CHECK_MAX 15
+
+#endif