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