Compare commits
No commits in common. "pristine-tar" and "master" have entirely different histories.
pristine-t
...
master
100
Asm/x86/7zAsm.asm
Normal file
100
Asm/x86/7zAsm.asm
Normal file
@ -0,0 +1,100 @@
|
||||
; 7zAsm.asm -- ASM macros
|
||||
; 2009-12-12 : Igor Pavlov : Public domain
|
||||
; 2011-10-12 : P7ZIP : Public domain
|
||||
|
||||
%define NOT ~
|
||||
|
||||
%macro MY_ASM_START 0
|
||||
SECTION .text
|
||||
%endmacro
|
||||
|
||||
%macro MY_PROC 2 ; macro name:req, numParams:req
|
||||
align 16
|
||||
%define proc_numParams %2 ; numParams
|
||||
global %1
|
||||
global _%1
|
||||
%1:
|
||||
_%1:
|
||||
%endmacro
|
||||
|
||||
%macro MY_ENDP 0
|
||||
%ifdef x64
|
||||
ret
|
||||
; proc_name ENDP
|
||||
%else
|
||||
ret ; (proc_numParams - 2) * 4
|
||||
%endif
|
||||
%endmacro
|
||||
|
||||
%ifdef x64
|
||||
REG_SIZE equ 8
|
||||
%else
|
||||
REG_SIZE equ 4
|
||||
%endif
|
||||
|
||||
%define x0 EAX
|
||||
%define x1 ECX
|
||||
%define x2 EDX
|
||||
%define x3 EBX
|
||||
%define x4 ESP
|
||||
%define x5 EBP
|
||||
%define x6 ESI
|
||||
%define x7 EDI
|
||||
|
||||
%define x0_L AL
|
||||
%define x1_L CL
|
||||
%define x2_L DL
|
||||
%define x3_L BL
|
||||
|
||||
%define x0_H AH
|
||||
%define x1_H CH
|
||||
%define x2_H DH
|
||||
%define x3_H BH
|
||||
|
||||
%ifdef x64
|
||||
%define r0 RAX
|
||||
%define r1 RCX
|
||||
%define r2 RDX
|
||||
%define r3 RBX
|
||||
%define r4 RSP
|
||||
%define r5 RBP
|
||||
%define r6 RSI
|
||||
%define r7 RDI
|
||||
%else
|
||||
%define r0 x0
|
||||
%define r1 x1
|
||||
%define r2 x2
|
||||
%define r3 x3
|
||||
%define r4 x4
|
||||
%define r5 x5
|
||||
%define r6 x6
|
||||
%define r7 x7
|
||||
%endif
|
||||
|
||||
%macro MY_PUSH_4_REGS 0
|
||||
push r3
|
||||
push r5
|
||||
%ifdef x64
|
||||
%ifdef CYGWIN64
|
||||
push r6
|
||||
push r7
|
||||
%endif
|
||||
%else
|
||||
push r6
|
||||
push r7
|
||||
%endif
|
||||
%endmacro
|
||||
|
||||
%macro MY_POP_4_REGS 0
|
||||
%ifdef x64
|
||||
%ifdef CYGWIN64
|
||||
pop r7
|
||||
pop r6
|
||||
%endif
|
||||
%else
|
||||
pop r7
|
||||
pop r6
|
||||
%endif
|
||||
pop r5
|
||||
pop r3
|
||||
%endmacro
|
171
Asm/x86/7zCrcOpt_asm.asm
Normal file
171
Asm/x86/7zCrcOpt_asm.asm
Normal file
@ -0,0 +1,171 @@
|
||||
; 7zCrcOpt.asm -- CRC32 calculation : optimized version
|
||||
; 2009-12-12 : Igor Pavlov : Public domain
|
||||
|
||||
%include "7zAsm.asm"
|
||||
|
||||
MY_ASM_START
|
||||
|
||||
%define rD r2
|
||||
%define rN r7
|
||||
|
||||
%ifdef x64
|
||||
%define num_VAR r8
|
||||
%define table_VAR r9
|
||||
%else
|
||||
data_size equ (REG_SIZE * 7)
|
||||
crc_table equ (REG_SIZE + data_size)
|
||||
%define num_VAR [r4 + data_size]
|
||||
%define table_VAR [r4 + crc_table]
|
||||
%endif
|
||||
|
||||
%define SRCDAT rN + rD + 4 *
|
||||
|
||||
%macro CRC 4 ;CRC macro op:req, dest:req, src:req, t:req
|
||||
%1 %2, DWORD [r5 + %3 * 4 + 0400h * %4] ; op dest, DWORD [r5 + src * 4 + 0400h * t]
|
||||
%endmacro
|
||||
|
||||
%macro CRC_XOR 3 ; CRC_XOR macro dest:req, src:req, t:req
|
||||
CRC xor, %1, %2, %3
|
||||
%endmacro
|
||||
|
||||
%macro CRC_MOV 3 ; CRC_MOV macro dest:req, src:req, t:req
|
||||
CRC mov, %1, %2, %3 ; CRC mov, dest, src, t
|
||||
%endmacro
|
||||
|
||||
%macro CRC1b 0
|
||||
movzx x6, BYTE [rD]
|
||||
inc rD
|
||||
movzx x3, x0_L
|
||||
xor x6, x3
|
||||
shr x0, 8
|
||||
CRC xor, x0, r6, 0
|
||||
dec rN
|
||||
%endmacro
|
||||
|
||||
%macro MY_PROLOG 1 ; MY_PROLOG macro crc_end:req
|
||||
MY_PUSH_4_REGS
|
||||
|
||||
|
||||
%ifdef x64
|
||||
%ifdef CYGWIN64
|
||||
;ECX=CRC, RDX=buf, R8=size R9=table
|
||||
; already in R8 : mov num_VAR,R8 ; LEN
|
||||
; already in RDX : mov rD, RDX ; BUF
|
||||
; already in R9 : mov table_VAR,R9; table
|
||||
mov x0, ECX ; CRC
|
||||
%else
|
||||
;EDI=CRC, RSI=buf, RDX=size RCX=table
|
||||
mov num_VAR,RDX ; LEN
|
||||
mov rD, RSI ; BUF
|
||||
mov table_VAR,RCX; table
|
||||
mov x0, EDI ; CRC
|
||||
%endif
|
||||
%else
|
||||
mov x0, [r4 + 20] ; CRC
|
||||
mov rD, [r4 + 24] ; buf
|
||||
%endif
|
||||
mov rN, num_VAR
|
||||
mov r5, table_VAR
|
||||
test rN, rN
|
||||
jz near %1 ; crc_end
|
||||
%%sl:
|
||||
test rD, 7
|
||||
jz %%sl_end
|
||||
CRC1b
|
||||
jnz %%sl
|
||||
%%sl_end:
|
||||
cmp rN, 16
|
||||
jb near %1; crc_end
|
||||
add rN, rD
|
||||
mov num_VAR, rN
|
||||
sub rN, 8
|
||||
and rN, NOT 7
|
||||
sub rD, rN
|
||||
xor x0, [SRCDAT 0]
|
||||
%endmacro
|
||||
|
||||
%macro MY_EPILOG 1 ; MY_EPILOG macro crc_end:req
|
||||
xor x0, [SRCDAT 0]
|
||||
mov rD, rN
|
||||
mov rN, num_VAR
|
||||
sub rN, rD
|
||||
%1: ; crc_end:
|
||||
test rN, rN
|
||||
jz %%end ; @F
|
||||
CRC1b
|
||||
jmp %1 ; crc_end
|
||||
%%end:
|
||||
MY_POP_4_REGS
|
||||
%endmacro
|
||||
|
||||
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
|
||||
|
||||
%ifidn __OUTPUT_FORMAT__,elf
|
||||
section .note.GNU-stack noalloc noexec nowrite progbits
|
||||
%endif
|
||||
|
310
Asm/x86/AesOpt.asm
Normal file
310
Asm/x86/AesOpt.asm
Normal file
@ -0,0 +1,310 @@
|
||||
; AesOpt.asm -- Intel's AES.
|
||||
; 2009-12-12 : Igor Pavlov : Public domain
|
||||
|
||||
%include "7zAsm.asm"
|
||||
|
||||
MY_ASM_START
|
||||
|
||||
%ifndef x64
|
||||
; FIXME .xmm
|
||||
%endif
|
||||
|
||||
%define rD r2
|
||||
%define rN r0
|
||||
|
||||
%macro MY_PROLOG 1 ; MY_PROLOG macro reg:req
|
||||
%ifdef x64
|
||||
%ifdef CYGWIN64
|
||||
; ivAes : %rcx
|
||||
; data : %rdx
|
||||
; numBlocks : %r8
|
||||
%else
|
||||
mov RCX,RDI
|
||||
mov R8 ,RDX
|
||||
mov RDX,RSI
|
||||
%endif
|
||||
; movdqa [r4 + 8], xmm6
|
||||
; movdqa [r4 + 8 + 16], xmm7
|
||||
%endif
|
||||
|
||||
push r3
|
||||
push r5
|
||||
|
||||
%ifdef x64
|
||||
%ifdef CYGWIN64
|
||||
push r6
|
||||
%endif
|
||||
mov rN, r8
|
||||
%else
|
||||
push r6
|
||||
mov ecx, [r4 + REG_SIZE * 4]
|
||||
mov edx, [r4 + REG_SIZE * 5]
|
||||
mov rN, [r4 + REG_SIZE * 6]
|
||||
%endif
|
||||
|
||||
mov x6, [r1 + 16]
|
||||
shl x6, 5
|
||||
|
||||
movdqa %1, [r1] ; reg
|
||||
add r1, 32
|
||||
%endmacro
|
||||
|
||||
%macro MY_EPILOG 0
|
||||
%ifdef x64
|
||||
%ifdef CYGWIN64
|
||||
pop r6
|
||||
%endif
|
||||
%else
|
||||
pop r6
|
||||
%endif
|
||||
pop r5
|
||||
pop r3
|
||||
|
||||
%ifdef x64
|
||||
; movdqa xmm6, [r4 + 8]
|
||||
; movdqa xmm7, [r4 + 8 + 16]
|
||||
%endif
|
||||
|
||||
MY_ENDP
|
||||
%endmacro
|
||||
|
||||
ways equ 4
|
||||
ways16 equ (ways * 16)
|
||||
|
||||
%macro OP_W 2 ; op, op2
|
||||
|
||||
%define i 0
|
||||
%1 xmm0,%2
|
||||
%define i 1
|
||||
%1 xmm1,%2
|
||||
%define i 2
|
||||
%1 xmm2,%2
|
||||
%define i 3
|
||||
%1 xmm3,%2
|
||||
|
||||
%endmacro
|
||||
|
||||
%macro LOAD_OP 2 ; LOAD_OP macro op:req, offs:req
|
||||
%1 xmm0, [r1 + r3 %2]
|
||||
%endmacro
|
||||
|
||||
%macro LOAD_OP_W 2 ; LOAD_OP_W macro op:req, offs:req
|
||||
movdqa xmm7, [r1 + r3 %2]
|
||||
; OP_W %1, xmm7
|
||||
%1 xmm0,xmm7
|
||||
%1 xmm1,xmm7
|
||||
%1 xmm2,xmm7
|
||||
%1 xmm3,xmm7
|
||||
%endmacro
|
||||
|
||||
|
||||
; ---------- AES-CBC Decode ----------
|
||||
|
||||
%macro CBC_DEC_UPDATE 2 ; CBC_DEC_UPDATE macro reg, offs
|
||||
pxor %1, xmm6
|
||||
movdqa xmm6, [rD + %2]
|
||||
movdqa [rD + %2], %1
|
||||
%endmacro
|
||||
|
||||
%macro DECODE 1 ; macro op:req
|
||||
%1 aesdec, +16
|
||||
%%B:
|
||||
%1 aesdec, +0
|
||||
%1 aesdec, -16
|
||||
sub x3, 32
|
||||
jnz %%B
|
||||
%1 aesdeclast, +0
|
||||
%endmacro
|
||||
|
||||
; void AesCbc_Decode_Intel(UInt32 *ivAes, Byte *data, size_t numBlocks)
|
||||
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
|
||||
CBC_DEC_UPDATE xmm0, 0 * 16
|
||||
CBC_DEC_UPDATE xmm1, 1 * 16
|
||||
CBC_DEC_UPDATE xmm2, 2 * 16
|
||||
CBC_DEC_UPDATE xmm3, 3 * 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 ----------
|
||||
|
||||
%macro ENCODE 1 ; macro op:req
|
||||
%1 aesenc, -16
|
||||
%%B:
|
||||
%1 aesenc, +0
|
||||
%1 aesenc, +16
|
||||
add r3, 32
|
||||
jnz %%B
|
||||
%1 aesenclast, +0
|
||||
%endmacro
|
||||
|
||||
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 ----------
|
||||
|
||||
%macro XOR_UPD_1 2 ; reg, offs
|
||||
pxor %1, [rD + %2]
|
||||
%endmacro
|
||||
|
||||
%macro XOR_UPD_2 2 ; reg, offs
|
||||
movdqa [rD + %2], %1
|
||||
%endmacro
|
||||
|
||||
MY_PROC AesCtr_Code_Intel, 3
|
||||
MY_PROLOG xmm6
|
||||
|
||||
mov r5, r4
|
||||
shr r5, 4
|
||||
dec r5
|
||||
shl r5, 4
|
||||
|
||||
mov DWORD [r5], 1
|
||||
mov DWORD [r5 + 4], 0
|
||||
mov DWORD [r5 + 8], 0
|
||||
mov DWORD [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
|
||||
paddq xmm6, xmm7
|
||||
movdqa xmm0, xmm6
|
||||
|
||||
paddq xmm6, xmm7
|
||||
movdqa xmm1, xmm6
|
||||
|
||||
paddq xmm6, xmm7
|
||||
movdqa xmm2, xmm6
|
||||
|
||||
paddq xmm6, xmm7
|
||||
movdqa xmm3, xmm6
|
||||
|
||||
|
||||
|
||||
mov r3, r6
|
||||
LOAD_OP_W pxor, -32
|
||||
|
||||
ENCODE LOAD_OP_W
|
||||
|
||||
;OP_W XOR_UPD_1, i * 16
|
||||
XOR_UPD_1 xmm0, 0 * 16
|
||||
XOR_UPD_1 xmm1, 1 * 16
|
||||
XOR_UPD_1 xmm2, 2 * 16
|
||||
XOR_UPD_1 xmm3, 3 * 16
|
||||
|
||||
;OP_W XOR_UPD_2, i * 16
|
||||
XOR_UPD_2 xmm0, 0 * 16
|
||||
XOR_UPD_2 xmm1, 1 * 16
|
||||
XOR_UPD_2 xmm2, 2 * 16
|
||||
XOR_UPD_2 xmm3, 3 * 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
|
||||
|
||||
%ifidn __OUTPUT_FORMAT__,elf
|
||||
section .note.GNU-stack noalloc noexec nowrite progbits
|
||||
%endif
|
||||
|
35
C/7zBuf.h
Normal file
35
C/7zBuf.h
Normal file
@ -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
|
51
C/7zBuf2.c
Normal file
51
C/7zBuf2.c
Normal file
@ -0,0 +1,51 @@
|
||||
/* 7zBuf2.c -- Byte Buffer
|
||||
2014-08-22 : 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;
|
||||
}
|
||||
if (size != 0)
|
||||
{
|
||||
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;
|
||||
}
|
128
C/7zCrc.c
Normal file
128
C/7zCrc.c
Normal file
@ -0,0 +1,128 @@
|
||||
/* 7zCrc.c -- CRC32 init
|
||||
2015-03-10 : Igor Pavlov : Public domain */
|
||||
|
||||
#include "Precomp.h"
|
||||
|
||||
#include "7zCrc.h"
|
||||
#include "CpuArch.h"
|
||||
|
||||
#define kCrcPoly 0xEDB88320
|
||||
|
||||
#ifdef MY_CPU_LE
|
||||
#define CRC_NUM_TABLES 8
|
||||
#else
|
||||
#define CRC_NUM_TABLES 9
|
||||
|
||||
#define CRC_UINT32_SWAP(v) ((v >> 24) | ((v >> 8) & 0xFF00) | ((v << 8) & 0xFF0000) | (v << 24))
|
||||
|
||||
UInt32 MY_FAST_CALL CrcUpdateT1_BeT4(UInt32 v, const void *data, size_t size, const UInt32 *table);
|
||||
UInt32 MY_FAST_CALL CrcUpdateT1_BeT8(UInt32 v, const void *data, size_t size, const UInt32 *table);
|
||||
#endif
|
||||
|
||||
#ifndef MY_CPU_BE
|
||||
UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table);
|
||||
UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table);
|
||||
#endif
|
||||
|
||||
typedef UInt32 (MY_FAST_CALL *CRC_FUNC)(UInt32 v, const void *data, size_t size, const UInt32 *table);
|
||||
|
||||
CRC_FUNC g_CrcUpdateT4;
|
||||
CRC_FUNC g_CrcUpdateT8;
|
||||
CRC_FUNC g_CrcUpdate;
|
||||
|
||||
UInt32 g_CrcTable[256 * CRC_NUM_TABLES];
|
||||
|
||||
UInt32 MY_FAST_CALL CrcUpdate(UInt32 v, const void *data, size_t size)
|
||||
{
|
||||
return g_CrcUpdate(v, data, size, g_CrcTable);
|
||||
}
|
||||
|
||||
UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size)
|
||||
{
|
||||
return g_CrcUpdate(CRC_INIT_VAL, data, size, g_CrcTable) ^ CRC_INIT_VAL;
|
||||
}
|
||||
|
||||
#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
|
||||
|
||||
UInt32 MY_FAST_CALL CrcUpdateT1(UInt32 v, const void *data, size_t size, const UInt32 *table)
|
||||
{
|
||||
const Byte *p = (const Byte *)data;
|
||||
const Byte *pEnd = p + size;
|
||||
for (; p != pEnd; p++)
|
||||
v = CRC_UPDATE_BYTE_2(v, *p);
|
||||
return v;
|
||||
}
|
||||
|
||||
void MY_FAST_CALL CrcGenerateTable()
|
||||
{
|
||||
UInt32 i;
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
UInt32 r = i;
|
||||
unsigned j;
|
||||
for (j = 0; j < 8; j++)
|
||||
r = (r >> 1) ^ (kCrcPoly & ~((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);
|
||||
}
|
||||
|
||||
#if CRC_NUM_TABLES < 4
|
||||
|
||||
g_CrcUpdate = CrcUpdateT1;
|
||||
|
||||
#else
|
||||
|
||||
#ifdef MY_CPU_LE
|
||||
|
||||
g_CrcUpdateT4 = CrcUpdateT4;
|
||||
g_CrcUpdate = CrcUpdateT4;
|
||||
|
||||
#if CRC_NUM_TABLES >= 8
|
||||
g_CrcUpdateT8 = CrcUpdateT8;
|
||||
|
||||
#ifdef MY_CPU_X86_OR_AMD64
|
||||
if (!CPU_Is_InOrder())
|
||||
g_CrcUpdate = CrcUpdateT8;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#else
|
||||
{
|
||||
#ifndef MY_CPU_BE
|
||||
UInt32 k = 0x01020304;
|
||||
const Byte *p = (const Byte *)&k;
|
||||
if (p[0] == 4 && p[1] == 3)
|
||||
{
|
||||
g_CrcUpdateT4 = CrcUpdateT4;
|
||||
g_CrcUpdate = CrcUpdateT4;
|
||||
#if CRC_NUM_TABLES >= 8
|
||||
g_CrcUpdateT8 = CrcUpdateT8;
|
||||
// g_CrcUpdate = CrcUpdateT8;
|
||||
#endif
|
||||
}
|
||||
else if (p[0] != 1 || p[1] != 2)
|
||||
g_CrcUpdate = CrcUpdateT1;
|
||||
else
|
||||
#endif
|
||||
{
|
||||
for (i = 256 * CRC_NUM_TABLES - 1; i >= 256; i--)
|
||||
{
|
||||
UInt32 x = g_CrcTable[i - 256];
|
||||
g_CrcTable[i] = CRC_UINT32_SWAP(x);
|
||||
}
|
||||
g_CrcUpdateT4 = CrcUpdateT1_BeT4;
|
||||
g_CrcUpdate = CrcUpdateT1_BeT4;
|
||||
#if CRC_NUM_TABLES >= 8
|
||||
g_CrcUpdateT8 = CrcUpdateT1_BeT8;
|
||||
// g_CrcUpdate = CrcUpdateT1_BeT8;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
25
C/7zCrc.h
Normal file
25
C/7zCrc.h
Normal file
@ -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
|
115
C/7zCrcOpt.c
Normal file
115
C/7zCrcOpt.c
Normal file
@ -0,0 +1,115 @@
|
||||
/* 7zCrcOpt.c -- CRC32 calculation
|
||||
2015-03-01 : Igor Pavlov : Public domain */
|
||||
|
||||
#include "Precomp.h"
|
||||
|
||||
#include "CpuArch.h"
|
||||
|
||||
#ifndef MY_CPU_BE
|
||||
|
||||
#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
|
||||
|
||||
UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table)
|
||||
{
|
||||
const Byte *p = (const Byte *)data;
|
||||
for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++)
|
||||
v = CRC_UPDATE_BYTE_2(v, *p);
|
||||
for (; size >= 4; size -= 4, p += 4)
|
||||
{
|
||||
v ^= *(const UInt32 *)p;
|
||||
v =
|
||||
table[0x300 + ((v ) & 0xFF)]
|
||||
^ table[0x200 + ((v >> 8) & 0xFF)]
|
||||
^ table[0x100 + ((v >> 16) & 0xFF)]
|
||||
^ table[0x000 + ((v >> 24))];
|
||||
}
|
||||
for (; size > 0; size--, p++)
|
||||
v = CRC_UPDATE_BYTE_2(v, *p);
|
||||
return v;
|
||||
}
|
||||
|
||||
UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table)
|
||||
{
|
||||
const Byte *p = (const Byte *)data;
|
||||
for (; size > 0 && ((unsigned)(ptrdiff_t)p & 7) != 0; size--, p++)
|
||||
v = CRC_UPDATE_BYTE_2(v, *p);
|
||||
for (; size >= 8; size -= 8, p += 8)
|
||||
{
|
||||
UInt32 d;
|
||||
v ^= *(const UInt32 *)p;
|
||||
v =
|
||||
table[0x700 + ((v ) & 0xFF)]
|
||||
^ table[0x600 + ((v >> 8) & 0xFF)]
|
||||
^ table[0x500 + ((v >> 16) & 0xFF)]
|
||||
^ table[0x400 + ((v >> 24))];
|
||||
d = *((const UInt32 *)p + 1);
|
||||
v ^=
|
||||
table[0x300 + ((d ) & 0xFF)]
|
||||
^ table[0x200 + ((d >> 8) & 0xFF)]
|
||||
^ table[0x100 + ((d >> 16) & 0xFF)]
|
||||
^ table[0x000 + ((d >> 24))];
|
||||
}
|
||||
for (; size > 0; size--, p++)
|
||||
v = CRC_UPDATE_BYTE_2(v, *p);
|
||||
return v;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef MY_CPU_LE
|
||||
|
||||
#define CRC_UINT32_SWAP(v) ((v >> 24) | ((v >> 8) & 0xFF00) | ((v << 8) & 0xFF0000) | (v << 24))
|
||||
|
||||
#define CRC_UPDATE_BYTE_2_BE(crc, b) (table[(((crc) >> 24) ^ (b))] ^ ((crc) << 8))
|
||||
|
||||
UInt32 MY_FAST_CALL CrcUpdateT1_BeT4(UInt32 v, const void *data, size_t size, const UInt32 *table)
|
||||
{
|
||||
const Byte *p = (const Byte *)data;
|
||||
table += 0x100;
|
||||
v = CRC_UINT32_SWAP(v);
|
||||
for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++)
|
||||
v = CRC_UPDATE_BYTE_2_BE(v, *p);
|
||||
for (; size >= 4; size -= 4, p += 4)
|
||||
{
|
||||
v ^= *(const UInt32 *)p;
|
||||
v =
|
||||
table[0x000 + ((v ) & 0xFF)]
|
||||
^ table[0x100 + ((v >> 8) & 0xFF)]
|
||||
^ table[0x200 + ((v >> 16) & 0xFF)]
|
||||
^ table[0x300 + ((v >> 24))];
|
||||
}
|
||||
for (; size > 0; size--, p++)
|
||||
v = CRC_UPDATE_BYTE_2_BE(v, *p);
|
||||
return CRC_UINT32_SWAP(v);
|
||||
}
|
||||
|
||||
UInt32 MY_FAST_CALL CrcUpdateT1_BeT8(UInt32 v, const void *data, size_t size, const UInt32 *table)
|
||||
{
|
||||
const Byte *p = (const Byte *)data;
|
||||
table += 0x100;
|
||||
v = CRC_UINT32_SWAP(v);
|
||||
for (; size > 0 && ((unsigned)(ptrdiff_t)p & 7) != 0; size--, p++)
|
||||
v = CRC_UPDATE_BYTE_2_BE(v, *p);
|
||||
for (; size >= 8; size -= 8, p += 8)
|
||||
{
|
||||
UInt32 d;
|
||||
v ^= *(const UInt32 *)p;
|
||||
v =
|
||||
table[0x400 + ((v ) & 0xFF)]
|
||||
^ table[0x500 + ((v >> 8) & 0xFF)]
|
||||
^ table[0x600 + ((v >> 16) & 0xFF)]
|
||||
^ table[0x700 + ((v >> 24))];
|
||||
d = *((const UInt32 *)p + 1);
|
||||
v ^=
|
||||
table[0x000 + ((d ) & 0xFF)]
|
||||
^ table[0x100 + ((d >> 8) & 0xFF)]
|
||||
^ table[0x200 + ((d >> 16) & 0xFF)]
|
||||
^ table[0x300 + ((d >> 24))];
|
||||
}
|
||||
for (; size > 0; size--, p++)
|
||||
v = CRC_UPDATE_BYTE_2_BE(v, *p);
|
||||
return CRC_UINT32_SWAP(v);
|
||||
}
|
||||
|
||||
#endif
|
171
C/7zStream.c
Normal file
171
C/7zStream.c
Normal file
@ -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;
|
||||
}
|
256
C/7zTypes.h
Normal file
256
C/7zTypes.h
Normal file
@ -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
|
22
C/7zVersion.h
Normal file
22
C/7zVersion.h
Normal file
@ -0,0 +1,22 @@
|
||||
#define MY_VER_MAJOR 16
|
||||
#define MY_VER_MINOR 02
|
||||
#define MY_VER_BUILD 0
|
||||
#define MY_VERSION_NUMBERS "16.02"
|
||||
#define MY_VERSION "16.02"
|
||||
#define MY_DATE "2016-05-21"
|
||||
#undef MY_COPYRIGHT
|
||||
#undef MY_VERSION_COPYRIGHT_DATE
|
||||
#define MY_AUTHOR_NAME "Igor Pavlov"
|
||||
#define MY_COPYRIGHT_PD "Igor Pavlov : Public domain"
|
||||
#define MY_COPYRIGHT_CR "Copyright (c) 1999-2016 Igor Pavlov"
|
||||
|
||||
#ifdef USE_COPYRIGHT_CR
|
||||
#define MY_COPYRIGHT MY_COPYRIGHT_CR
|
||||
#else
|
||||
#define MY_COPYRIGHT MY_COPYRIGHT_PD
|
||||
#endif
|
||||
|
||||
#define MY_VERSION_COPYRIGHT_DATE MY_VERSION " : " MY_COPYRIGHT " : " MY_DATE
|
||||
|
||||
#define P7ZIP_VERSION "16.02"
|
||||
|
297
C/Aes.c
Normal file
297
C/Aes.c
Normal file
@ -0,0 +1,297 @@
|
||||
/* Aes.c -- AES encryption / decryption
|
||||
2016-05-21 : Igor Pavlov : Public domain */
|
||||
|
||||
#include "Precomp.h"
|
||||
|
||||
#include "Aes.h"
|
||||
#include "CpuArch.h"
|
||||
|
||||
static UInt32 T[256 * 4];
|
||||
static const Byte Sbox[256] = {
|
||||
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
|
||||
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
|
||||
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
|
||||
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
|
||||
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
|
||||
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
|
||||
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
|
||||
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
|
||||
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
|
||||
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
|
||||
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
|
||||
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
|
||||
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
|
||||
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
|
||||
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
|
||||
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16};
|
||||
|
||||
void MY_FAST_CALL AesCbc_Encode(UInt32 *ivAes, Byte *data, size_t numBlocks);
|
||||
void MY_FAST_CALL AesCbc_Decode(UInt32 *ivAes, Byte *data, size_t numBlocks);
|
||||
void MY_FAST_CALL AesCtr_Code(UInt32 *ivAes, Byte *data, size_t numBlocks);
|
||||
|
||||
void MY_FAST_CALL AesCbc_Encode_Intel(UInt32 *ivAes, Byte *data, size_t numBlocks);
|
||||
void MY_FAST_CALL AesCbc_Decode_Intel(UInt32 *ivAes, Byte *data, size_t numBlocks);
|
||||
void MY_FAST_CALL AesCtr_Code_Intel(UInt32 *ivAes, Byte *data, size_t numBlocks);
|
||||
|
||||
AES_CODE_FUNC g_AesCbc_Encode;
|
||||
AES_CODE_FUNC g_AesCbc_Decode;
|
||||
AES_CODE_FUNC g_AesCtr_Code;
|
||||
|
||||
static UInt32 D[256 * 4];
|
||||
static Byte InvS[256];
|
||||
|
||||
static const Byte Rcon[11] = { 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 };
|
||||
|
||||
#define xtime(x) ((((x) << 1) ^ (((x) & 0x80) != 0 ? 0x1B : 0)) & 0xFF)
|
||||
|
||||
#define Ui32(a0, a1, a2, a3) ((UInt32)(a0) | ((UInt32)(a1) << 8) | ((UInt32)(a2) << 16) | ((UInt32)(a3) << 24))
|
||||
|
||||
#define gb0(x) ( (x) & 0xFF)
|
||||
#define gb1(x) (((x) >> ( 8)) & 0xFF)
|
||||
#define gb2(x) (((x) >> (16)) & 0xFF)
|
||||
#define gb3(x) (((x) >> (24)) & 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
|
||||
#ifdef _7ZIP_ASM
|
||||
if (CPU_Is_Aes_Supported())
|
||||
{
|
||||
g_AesCbc_Encode = AesCbc_Encode_Intel;
|
||||
g_AesCbc_Decode = AesCbc_Decode_Intel;
|
||||
g_AesCtr_Code = AesCtr_Code_Intel;
|
||||
}
|
||||
#endif
|
||||
#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]
|
||||
|
||||
#define HT16(m, s, p) \
|
||||
HT4(m, 0, s, p); \
|
||||
HT4(m, 1, s, p); \
|
||||
HT4(m, 2, s, p); \
|
||||
HT4(m, 3, s, p); \
|
||||
|
||||
#define FT(i, x) Sbox[gb ## x(m[(i + x) & 3])]
|
||||
#define FT4(i) dest[i] = Ui32(FT(i, 0), FT(i, 1), FT(i, 2), FT(i, 3)) ^ w[i];
|
||||
|
||||
|
||||
#define HD(i, x, s) (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];
|
||||
|
||||
#define HD16(m, s, p) \
|
||||
HD4(m, 0, s, p); \
|
||||
HD4(m, 1, s, p); \
|
||||
HD4(m, 2, s, p); \
|
||||
HD4(m, 3, s, p); \
|
||||
|
||||
#define FD(i, x) InvS[gb ## x(m[(i - x) & 3])]
|
||||
#define FD4(i) dest[i] = Ui32(FD(i, 0), FD(i, 1), FD(i, 2), FD(i, 3)) ^ w[i];
|
||||
|
||||
void MY_FAST_CALL Aes_SetKey_Enc(UInt32 *w, const Byte *key, unsigned keySize)
|
||||
{
|
||||
unsigned i, wSize;
|
||||
wSize = keySize + 28;
|
||||
keySize /= 4;
|
||||
w[0] = ((UInt32)keySize / 2) + 3;
|
||||
w += 4;
|
||||
|
||||
for (i = 0; i < keySize; i++, key += 4)
|
||||
w[i] = GetUi32(key);
|
||||
|
||||
for (; i < wSize; i++)
|
||||
{
|
||||
UInt32 t = w[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[ (unsigned)Sbox[gb0(r)]] ^
|
||||
D[0x100 + (unsigned)Sbox[gb1(r)]] ^
|
||||
D[0x200 + (unsigned)Sbox[gb2(r)]] ^
|
||||
D[0x300 + (unsigned)Sbox[gb3(r)]];
|
||||
}
|
||||
}
|
||||
|
||||
/* Aes_Encode and Aes_Decode functions work with little-endian words.
|
||||
src and dest are pointers to 4 UInt32 words.
|
||||
src and dest can point to same block */
|
||||
|
||||
static void Aes_Encode(const UInt32 *w, UInt32 *dest, const UInt32 *src)
|
||||
{
|
||||
UInt32 s[4];
|
||||
UInt32 m[4];
|
||||
UInt32 numRounds2 = w[0];
|
||||
w += 4;
|
||||
s[0] = src[0] ^ w[0];
|
||||
s[1] = src[1] ^ w[1];
|
||||
s[2] = src[2] ^ w[2];
|
||||
s[3] = src[3] ^ w[3];
|
||||
w += 4;
|
||||
for (;;)
|
||||
{
|
||||
HT16(m, s, 0);
|
||||
if (--numRounds2 == 0)
|
||||
break;
|
||||
HT16(s, m, 4);
|
||||
w += 8;
|
||||
}
|
||||
w += 4;
|
||||
FT4(0); FT4(1); FT4(2); FT4(3);
|
||||
}
|
||||
|
||||
static void Aes_Decode(const UInt32 *w, UInt32 *dest, const UInt32 *src)
|
||||
{
|
||||
UInt32 s[4];
|
||||
UInt32 m[4];
|
||||
UInt32 numRounds2 = w[0];
|
||||
w += 4 + numRounds2 * 8;
|
||||
s[0] = src[0] ^ w[0];
|
||||
s[1] = src[1] ^ w[1];
|
||||
s[2] = src[2] ^ w[2];
|
||||
s[3] = src[3] ^ w[3];
|
||||
for (;;)
|
||||
{
|
||||
w -= 8;
|
||||
HD16(m, s, 4);
|
||||
if (--numRounds2 == 0)
|
||||
break;
|
||||
HD16(s, m, 0);
|
||||
}
|
||||
FD4(0); FD4(1); FD4(2); FD4(3);
|
||||
}
|
||||
|
||||
void AesCbc_Init(UInt32 *p, const Byte *iv)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < 4; i++)
|
||||
p[i] = GetUi32(iv + i * 4);
|
||||
}
|
||||
|
||||
void MY_FAST_CALL AesCbc_Encode(UInt32 *p, Byte *data, size_t numBlocks)
|
||||
{
|
||||
for (; numBlocks != 0; numBlocks--, data += AES_BLOCK_SIZE)
|
||||
{
|
||||
p[0] ^= GetUi32(data);
|
||||
p[1] ^= GetUi32(data + 4);
|
||||
p[2] ^= GetUi32(data + 8);
|
||||
p[3] ^= GetUi32(data + 12);
|
||||
|
||||
Aes_Encode(p + 4, p, p);
|
||||
|
||||
SetUi32(data, p[0]);
|
||||
SetUi32(data + 4, p[1]);
|
||||
SetUi32(data + 8, p[2]);
|
||||
SetUi32(data + 12, p[3]);
|
||||
}
|
||||
}
|
||||
|
||||
void MY_FAST_CALL AesCbc_Decode(UInt32 *p, Byte *data, size_t numBlocks)
|
||||
{
|
||||
UInt32 in[4], out[4];
|
||||
for (; numBlocks != 0; numBlocks--, data += AES_BLOCK_SIZE)
|
||||
{
|
||||
in[0] = GetUi32(data);
|
||||
in[1] = GetUi32(data + 4);
|
||||
in[2] = GetUi32(data + 8);
|
||||
in[3] = GetUi32(data + 12);
|
||||
|
||||
Aes_Decode(p + 4, out, in);
|
||||
|
||||
SetUi32(data, p[0] ^ out[0]);
|
||||
SetUi32(data + 4, p[1] ^ out[1]);
|
||||
SetUi32(data + 8, p[2] ^ out[2]);
|
||||
SetUi32(data + 12, p[3] ^ out[3]);
|
||||
|
||||
p[0] = in[0];
|
||||
p[1] = in[1];
|
||||
p[2] = in[2];
|
||||
p[3] = in[3];
|
||||
}
|
||||
}
|
||||
|
||||
void MY_FAST_CALL AesCtr_Code(UInt32 *p, Byte *data, size_t numBlocks)
|
||||
{
|
||||
for (; numBlocks != 0; numBlocks--)
|
||||
{
|
||||
UInt32 temp[4];
|
||||
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];
|
||||
}
|
||||
}
|
38
C/Aes.h
Normal file
38
C/Aes.h
Normal file
@ -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
|
328
C/Alloc.c
Normal file
328
C/Alloc.c
Normal file
@ -0,0 +1,328 @@
|
||||
/* Alloc.c -- Memory allocation functions
|
||||
2015-02-21 : Igor Pavlov : Public domain */
|
||||
|
||||
#include "Precomp.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef _7ZIP_LARGE_PAGES
|
||||
#ifdef __linux__
|
||||
#ifndef _7ZIP_ST
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <mntent.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#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
|
||||
|
||||
#ifdef _7ZIP_ASM
|
||||
// #include <emmintrin.h>
|
||||
extern int posix_memalign (void **, size_t, size_t);
|
||||
void *align_alloc(size_t size)
|
||||
{
|
||||
// return _mm_malloc(size,16);
|
||||
void * ptr = 0;
|
||||
|
||||
if (posix_memalign (&ptr, 16, size) == 0)
|
||||
return ptr;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void align_free(void * ptr)
|
||||
{
|
||||
// _mm_free(ptr);
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
void *align_alloc(size_t size)
|
||||
{
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void align_free(void * ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void *MyAlloc(size_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
return 0;
|
||||
#ifdef _SZ_ALLOC_DEBUG
|
||||
{
|
||||
void *p = align_alloc(size);
|
||||
fprintf(stderr, "\nAlloc %10d bytes, count = %10d, addr = %8X", size, g_allocCount++, (unsigned)p);
|
||||
return p;
|
||||
}
|
||||
#else
|
||||
return align_alloc(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
|
||||
align_free(address);
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#ifdef _7ZIP_LARGE_PAGES
|
||||
|
||||
#ifdef __linux__
|
||||
#define _7ZIP_MAX_HUGE_ALLOCS 64
|
||||
static void *g_HugePageAddr[_7ZIP_MAX_HUGE_ALLOCS] = { NULL };
|
||||
static size_t g_HugePageLen[_7ZIP_MAX_HUGE_ALLOCS];
|
||||
static char *g_HugetlbPath;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef _7ZIP_LARGE_PAGES
|
||||
static void *VirtualAlloc(size_t size, int memLargePages)
|
||||
{
|
||||
if (memLargePages)
|
||||
{
|
||||
#ifdef __linux__
|
||||
/* huge pages support for Linux; added by Joachim Henke */
|
||||
#ifndef _7ZIP_ST
|
||||
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
#endif
|
||||
int i;
|
||||
|
||||
void * address = NULL;
|
||||
#ifndef _7ZIP_ST
|
||||
pthread_mutex_lock(&mutex);
|
||||
#endif
|
||||
for (i = 0; i < _7ZIP_MAX_HUGE_ALLOCS; ++i)
|
||||
{
|
||||
if (g_HugePageAddr[i] == NULL)
|
||||
{
|
||||
int fd, pathlen = strlen(g_HugetlbPath);
|
||||
char tempname[pathlen+12];
|
||||
|
||||
memcpy(tempname, g_HugetlbPath, pathlen);
|
||||
memcpy(tempname + pathlen, "/7z-XXXXXX", 11);
|
||||
fd = mkstemp(tempname);
|
||||
unlink(tempname);
|
||||
if (fd < 0)
|
||||
{
|
||||
fprintf(stderr,"cant't open %s (%s)\n",tempname,strerror(errno));
|
||||
break;
|
||||
}
|
||||
address = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
close(fd);
|
||||
if (address == MAP_FAILED)
|
||||
{
|
||||
address = NULL;
|
||||
break;
|
||||
}
|
||||
g_HugePageLen[i] = size;
|
||||
g_HugePageAddr[i] = address;
|
||||
// fprintf(stderr,"HUGE[%d]=%ld %p\n",i,(long)size,address);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifndef _7ZIP_ST
|
||||
pthread_mutex_unlock(&mutex);
|
||||
#endif
|
||||
return address;
|
||||
#endif
|
||||
}
|
||||
return align_alloc(size);
|
||||
}
|
||||
#else
|
||||
static void *VirtualAlloc(size_t size, int memLargePages )
|
||||
{
|
||||
return align_alloc(size);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int VirtualFree(void *address)
|
||||
{
|
||||
#ifdef _7ZIP_LARGE_PAGES
|
||||
#ifdef __linux__
|
||||
int i;
|
||||
|
||||
for (i = 0; i < _7ZIP_MAX_HUGE_ALLOCS; ++i)
|
||||
{
|
||||
if (g_HugePageAddr[i] == address)
|
||||
{
|
||||
munmap(address, g_HugePageLen[i]);
|
||||
g_HugePageAddr[i] = NULL;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
align_free(address);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
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(size, 0);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
#ifdef _7ZIP_LARGE_PAGES
|
||||
size_t g_LargePageSize = 0;
|
||||
#ifdef _WIN32
|
||||
typedef SIZE_T (WINAPI *GetLargePageMinimumP)();
|
||||
#elif defined(__linux__)
|
||||
size_t largePageMinimum()
|
||||
{
|
||||
size_t size;
|
||||
|
||||
g_HugetlbPath = getenv("HUGETLB_PATH");
|
||||
|
||||
if (g_HugetlbPath == NULL)
|
||||
{
|
||||
// not defined => try to find out the directory
|
||||
static char dir_hugetlbfs[1024];
|
||||
const char * filename = "/etc/mtab"; // mounted filesystems
|
||||
FILE *fp;
|
||||
struct mntent * info;
|
||||
|
||||
dir_hugetlbfs[0]=0;
|
||||
|
||||
fp = setmntent(filename,"r");
|
||||
if (fp)
|
||||
{
|
||||
info = getmntent(fp);
|
||||
while(info)
|
||||
{
|
||||
/*
|
||||
printf("%s:\n",info->mnt_fsname);
|
||||
printf(" dir='%s'\n",info->mnt_dir);
|
||||
printf(" type='%s'\n",info->mnt_type);
|
||||
*/
|
||||
|
||||
if (strcmp(info->mnt_type,"hugetlbfs") == 0)
|
||||
{
|
||||
strcpy(dir_hugetlbfs,info->mnt_dir);
|
||||
break;
|
||||
}
|
||||
|
||||
info = getmntent(fp);
|
||||
}
|
||||
endmntent(fp);
|
||||
}
|
||||
|
||||
if (dir_hugetlbfs[0])
|
||||
{
|
||||
g_HugetlbPath = dir_hugetlbfs;
|
||||
// fprintf(stderr," Found hugetlbfs = '%s'\n",g_HugetlbPath);
|
||||
}
|
||||
}
|
||||
if (g_HugetlbPath == NULL || (size = pathconf(g_HugetlbPath, _PC_REC_MIN_XFER_SIZE)) <= getpagesize())
|
||||
return 0;
|
||||
return size;
|
||||
}
|
||||
#else
|
||||
#define largePageMinimum() 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void SetLargePageSize()
|
||||
{
|
||||
#ifdef _7ZIP_LARGE_PAGES
|
||||
size_t size;
|
||||
#ifdef _WIN32
|
||||
GetLargePageMinimumP largePageMinimum = (GetLargePageMinimumP)
|
||||
GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "GetLargePageMinimum");
|
||||
if (largePageMinimum == 0)
|
||||
return;
|
||||
#endif
|
||||
size = largePageMinimum();
|
||||
if (size == 0 || (size & (size - 1)) != 0)
|
||||
return;
|
||||
g_LargePageSize = size;
|
||||
// fprintf(stderr,"SetLargePageSize : %ld\n",(long)g_LargePageSize);
|
||||
#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( (size + g_LargePageSize - 1) & (~(g_LargePageSize - 1)), 1);
|
||||
if (res != 0)
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
return VirtualAlloc(size, 0);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static void *SzAlloc(void *p, size_t size) { UNUSED_VAR(p); return MyAlloc(size); }
|
||||
static void SzFree(void *p, void *address) { UNUSED_VAR(p); MyFree(address); }
|
||||
ISzAlloc g_Alloc = { SzAlloc, SzFree };
|
||||
|
||||
static void *SzBigAlloc(void *p, size_t size) { UNUSED_VAR(p); return BigAlloc(size); }
|
||||
static void SzBigFree(void *p, void *address) { UNUSED_VAR(p); BigFree(address); }
|
||||
ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree };
|
||||
|
26
C/Alloc.h
Normal file
26
C/Alloc.h
Normal file
@ -0,0 +1,26 @@
|
||||
/* Alloc.h -- Memory allocation functions
|
||||
2009-02-07 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __COMMON_ALLOC_H
|
||||
#define __COMMON_ALLOC_H
|
||||
|
||||
#include "7zTypes.h"
|
||||
|
||||
EXTERN_C_BEGIN
|
||||
|
||||
void *MyAlloc(size_t size);
|
||||
void MyFree(void *address);
|
||||
|
||||
void SetLargePageSize();
|
||||
|
||||
void *MidAlloc(size_t size);
|
||||
void MidFree(void *address);
|
||||
void *BigAlloc(size_t size);
|
||||
void BigFree(void *address);
|
||||
|
||||
extern ISzAlloc g_Alloc;
|
||||
extern ISzAlloc g_BigAlloc;
|
||||
|
||||
EXTERN_C_END
|
||||
|
||||
#endif
|
256
C/Bcj2.c
Normal file
256
C/Bcj2.c
Normal file
@ -0,0 +1,256 @@
|
||||
/* Bcj2.c -- BCJ2 Decoder (Converter for x86 code)
|
||||
2015-08-01 : Igor Pavlov : Public domain */
|
||||
|
||||
#include "Precomp.h"
|
||||
|
||||
#include "Bcj2.h"
|
||||
#include "CpuArch.h"
|
||||
|
||||
#define CProb UInt16
|
||||
|
||||
#define kTopValue ((UInt32)1 << 24)
|
||||
#define kNumModelBits 11
|
||||
#define kBitModelTotal (1 << kNumModelBits)
|
||||
#define kNumMoveBits 5
|
||||
|
||||
#define _IF_BIT_0 ttt = *prob; bound = (p->range >> kNumModelBits) * ttt; if (p->code < bound)
|
||||
#define _UPDATE_0 p->range = bound; *prob = (CProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits));
|
||||
#define _UPDATE_1 p->range -= bound; p->code -= bound; *prob = (CProb)(ttt - (ttt >> kNumMoveBits));
|
||||
|
||||
void Bcj2Dec_Init(CBcj2Dec *p)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
p->state = BCJ2_DEC_STATE_OK;
|
||||
p->ip = 0;
|
||||
p->temp[3] = 0;
|
||||
p->range = 0;
|
||||
p->code = 0;
|
||||
for (i = 0; i < sizeof(p->probs) / sizeof(p->probs[0]); i++)
|
||||
p->probs[i] = kBitModelTotal >> 1;
|
||||
}
|
||||
|
||||
SRes Bcj2Dec_Decode(CBcj2Dec *p)
|
||||
{
|
||||
if (p->range <= 5)
|
||||
{
|
||||
p->state = BCJ2_DEC_STATE_OK;
|
||||
for (; p->range != 5; p->range++)
|
||||
{
|
||||
if (p->range == 1 && p->code != 0)
|
||||
return SZ_ERROR_DATA;
|
||||
|
||||
if (p->bufs[BCJ2_STREAM_RC] == p->lims[BCJ2_STREAM_RC])
|
||||
{
|
||||
p->state = BCJ2_STREAM_RC;
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
p->code = (p->code << 8) | *(p->bufs[BCJ2_STREAM_RC])++;
|
||||
}
|
||||
|
||||
if (p->code == 0xFFFFFFFF)
|
||||
return SZ_ERROR_DATA;
|
||||
|
||||
p->range = 0xFFFFFFFF;
|
||||
}
|
||||
else if (p->state >= BCJ2_DEC_STATE_ORIG_0)
|
||||
{
|
||||
while (p->state <= BCJ2_DEC_STATE_ORIG_3)
|
||||
{
|
||||
Byte *dest = p->dest;
|
||||
if (dest == p->destLim)
|
||||
return SZ_OK;
|
||||
*dest = p->temp[p->state++ - BCJ2_DEC_STATE_ORIG_0];
|
||||
p->dest = dest + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
if (BCJ2_IS_32BIT_STREAM(p->state))
|
||||
{
|
||||
const Byte *cur = p->bufs[p->state];
|
||||
if (cur == p->lims[p->state])
|
||||
return SZ_OK;
|
||||
p->bufs[p->state] = cur + 4;
|
||||
|
||||
{
|
||||
UInt32 val;
|
||||
Byte *dest;
|
||||
SizeT rem;
|
||||
|
||||
p->ip += 4;
|
||||
val = GetBe32(cur) - p->ip;
|
||||
dest = p->dest;
|
||||
rem = p->destLim - dest;
|
||||
if (rem < 4)
|
||||
{
|
||||
SizeT i;
|
||||
SetUi32(p->temp, val);
|
||||
for (i = 0; i < rem; i++)
|
||||
dest[i] = p->temp[i];
|
||||
p->dest = dest + rem;
|
||||
p->state = BCJ2_DEC_STATE_ORIG_0 + (unsigned)rem;
|
||||
return SZ_OK;
|
||||
}
|
||||
SetUi32(dest, val);
|
||||
p->temp[3] = (Byte)(val >> 24);
|
||||
p->dest = dest + 4;
|
||||
p->state = BCJ2_DEC_STATE_OK;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (BCJ2_IS_32BIT_STREAM(p->state))
|
||||
p->state = BCJ2_DEC_STATE_OK;
|
||||
else
|
||||
{
|
||||
if (p->range < kTopValue)
|
||||
{
|
||||
if (p->bufs[BCJ2_STREAM_RC] == p->lims[BCJ2_STREAM_RC])
|
||||
{
|
||||
p->state = BCJ2_STREAM_RC;
|
||||
return SZ_OK;
|
||||
}
|
||||
p->range <<= 8;
|
||||
p->code = (p->code << 8) | *(p->bufs[BCJ2_STREAM_RC])++;
|
||||
}
|
||||
|
||||
{
|
||||
const Byte *src = p->bufs[BCJ2_STREAM_MAIN];
|
||||
const Byte *srcLim;
|
||||
Byte *dest;
|
||||
SizeT num = p->lims[BCJ2_STREAM_MAIN] - src;
|
||||
|
||||
if (num == 0)
|
||||
{
|
||||
p->state = BCJ2_STREAM_MAIN;
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
dest = p->dest;
|
||||
if (num > (SizeT)(p->destLim - dest))
|
||||
{
|
||||
num = p->destLim - dest;
|
||||
if (num == 0)
|
||||
{
|
||||
p->state = BCJ2_DEC_STATE_ORIG;
|
||||
return SZ_OK;
|
||||
}
|
||||
}
|
||||
|
||||
srcLim = src + num;
|
||||
|
||||
if (p->temp[3] == 0x0F && (src[0] & 0xF0) == 0x80)
|
||||
*dest = src[0];
|
||||
else for (;;)
|
||||
{
|
||||
Byte b = *src;
|
||||
*dest = b;
|
||||
if (b != 0x0F)
|
||||
{
|
||||
if ((b & 0xFE) == 0xE8)
|
||||
break;
|
||||
dest++;
|
||||
if (++src != srcLim)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
dest++;
|
||||
if (++src == srcLim)
|
||||
break;
|
||||
if ((*src & 0xF0) != 0x80)
|
||||
continue;
|
||||
*dest = *src;
|
||||
break;
|
||||
}
|
||||
|
||||
num = src - p->bufs[BCJ2_STREAM_MAIN];
|
||||
|
||||
if (src == srcLim)
|
||||
{
|
||||
p->temp[3] = src[-1];
|
||||
p->bufs[BCJ2_STREAM_MAIN] = src;
|
||||
p->ip += (UInt32)num;
|
||||
p->dest += num;
|
||||
p->state =
|
||||
p->bufs[BCJ2_STREAM_MAIN] ==
|
||||
p->lims[BCJ2_STREAM_MAIN] ?
|
||||
(unsigned)BCJ2_STREAM_MAIN :
|
||||
(unsigned)BCJ2_DEC_STATE_ORIG;
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
{
|
||||
UInt32 bound, ttt;
|
||||
CProb *prob;
|
||||
Byte b = src[0];
|
||||
Byte prev = (Byte)(num == 0 ? p->temp[3] : src[-1]);
|
||||
|
||||
p->temp[3] = b;
|
||||
p->bufs[BCJ2_STREAM_MAIN] = src + 1;
|
||||
num++;
|
||||
p->ip += (UInt32)num;
|
||||
p->dest += num;
|
||||
|
||||
prob = p->probs + (unsigned)(b == 0xE8 ? 2 + (unsigned)prev : (b == 0xE9 ? 1 : 0));
|
||||
|
||||
_IF_BIT_0
|
||||
{
|
||||
_UPDATE_0
|
||||
continue;
|
||||
}
|
||||
_UPDATE_1
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
UInt32 val;
|
||||
unsigned cj = (p->temp[3] == 0xE8) ? BCJ2_STREAM_CALL : BCJ2_STREAM_JUMP;
|
||||
const Byte *cur = p->bufs[cj];
|
||||
Byte *dest;
|
||||
SizeT rem;
|
||||
|
||||
if (cur == p->lims[cj])
|
||||
{
|
||||
p->state = cj;
|
||||
break;
|
||||
}
|
||||
|
||||
val = GetBe32(cur);
|
||||
p->bufs[cj] = cur + 4;
|
||||
|
||||
p->ip += 4;
|
||||
val -= p->ip;
|
||||
dest = p->dest;
|
||||
rem = p->destLim - dest;
|
||||
|
||||
if (rem < 4)
|
||||
{
|
||||
SizeT i;
|
||||
SetUi32(p->temp, val);
|
||||
for (i = 0; i < rem; i++)
|
||||
dest[i] = p->temp[i];
|
||||
p->dest = dest + rem;
|
||||
p->state = BCJ2_DEC_STATE_ORIG_0 + (unsigned)rem;
|
||||
break;
|
||||
}
|
||||
|
||||
SetUi32(dest, val);
|
||||
p->temp[3] = (Byte)(val >> 24);
|
||||
p->dest = dest + 4;
|
||||
}
|
||||
}
|
||||
|
||||
if (p->range < kTopValue && p->bufs[BCJ2_STREAM_RC] != p->lims[BCJ2_STREAM_RC])
|
||||
{
|
||||
p->range <<= 8;
|
||||
p->code = (p->code << 8) | *(p->bufs[BCJ2_STREAM_RC])++;
|
||||
}
|
||||
|
||||
return SZ_OK;
|
||||
}
|
146
C/Bcj2.h
Normal file
146
C/Bcj2.h
Normal file
@ -0,0 +1,146 @@
|
||||
/* Bcj2.h -- BCJ2 Converter for x86 code
|
||||
2014-11-10 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __BCJ2_H
|
||||
#define __BCJ2_H
|
||||
|
||||
#include "7zTypes.h"
|
||||
|
||||
EXTERN_C_BEGIN
|
||||
|
||||
#define BCJ2_NUM_STREAMS 4
|
||||
|
||||
enum
|
||||
{
|
||||
BCJ2_STREAM_MAIN,
|
||||
BCJ2_STREAM_CALL,
|
||||
BCJ2_STREAM_JUMP,
|
||||
BCJ2_STREAM_RC
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
BCJ2_DEC_STATE_ORIG_0 = BCJ2_NUM_STREAMS,
|
||||
BCJ2_DEC_STATE_ORIG_1,
|
||||
BCJ2_DEC_STATE_ORIG_2,
|
||||
BCJ2_DEC_STATE_ORIG_3,
|
||||
|
||||
BCJ2_DEC_STATE_ORIG,
|
||||
BCJ2_DEC_STATE_OK
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
BCJ2_ENC_STATE_ORIG = BCJ2_NUM_STREAMS,
|
||||
BCJ2_ENC_STATE_OK
|
||||
};
|
||||
|
||||
|
||||
#define BCJ2_IS_32BIT_STREAM(s) ((s) == BCJ2_STREAM_CALL || (s) == BCJ2_STREAM_JUMP)
|
||||
|
||||
/*
|
||||
CBcj2Dec / CBcj2Enc
|
||||
bufs sizes:
|
||||
BUF_SIZE(n) = lims[n] - bufs[n]
|
||||
bufs sizes for BCJ2_STREAM_CALL and BCJ2_STREAM_JUMP must be mutliply of 4:
|
||||
(BUF_SIZE(BCJ2_STREAM_CALL) & 3) == 0
|
||||
(BUF_SIZE(BCJ2_STREAM_JUMP) & 3) == 0
|
||||
*/
|
||||
|
||||
/*
|
||||
CBcj2Dec:
|
||||
dest is allowed to overlap with bufs[BCJ2_STREAM_MAIN], with the following conditions:
|
||||
bufs[BCJ2_STREAM_MAIN] >= dest &&
|
||||
bufs[BCJ2_STREAM_MAIN] - dest >= tempReserv +
|
||||
BUF_SIZE(BCJ2_STREAM_CALL) +
|
||||
BUF_SIZE(BCJ2_STREAM_JUMP)
|
||||
tempReserv = 0 : for first call of Bcj2Dec_Decode
|
||||
tempReserv = 4 : for any other calls of Bcj2Dec_Decode
|
||||
overlap with offset = 1 is not allowed
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const Byte *bufs[BCJ2_NUM_STREAMS];
|
||||
const Byte *lims[BCJ2_NUM_STREAMS];
|
||||
Byte *dest;
|
||||
const Byte *destLim;
|
||||
|
||||
unsigned state; /* BCJ2_STREAM_MAIN has more priority than BCJ2_STATE_ORIG */
|
||||
|
||||
UInt32 ip;
|
||||
Byte temp[4];
|
||||
UInt32 range;
|
||||
UInt32 code;
|
||||
UInt16 probs[2 + 256];
|
||||
} CBcj2Dec;
|
||||
|
||||
void Bcj2Dec_Init(CBcj2Dec *p);
|
||||
|
||||
/* Returns: SZ_OK or SZ_ERROR_DATA */
|
||||
SRes Bcj2Dec_Decode(CBcj2Dec *p);
|
||||
|
||||
#define Bcj2Dec_IsFinished(_p_) ((_p_)->code == 0)
|
||||
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
BCJ2_ENC_FINISH_MODE_CONTINUE,
|
||||
BCJ2_ENC_FINISH_MODE_END_BLOCK,
|
||||
BCJ2_ENC_FINISH_MODE_END_STREAM
|
||||
} EBcj2Enc_FinishMode;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Byte *bufs[BCJ2_NUM_STREAMS];
|
||||
const Byte *lims[BCJ2_NUM_STREAMS];
|
||||
const Byte *src;
|
||||
const Byte *srcLim;
|
||||
|
||||
unsigned state;
|
||||
EBcj2Enc_FinishMode finishMode;
|
||||
|
||||
Byte prevByte;
|
||||
|
||||
Byte cache;
|
||||
UInt32 range;
|
||||
UInt64 low;
|
||||
UInt64 cacheSize;
|
||||
|
||||
UInt32 ip;
|
||||
|
||||
/* 32-bit ralative offset in JUMP/CALL commands is
|
||||
- (mod 4 GB) in 32-bit mode
|
||||
- signed Int32 in 64-bit mode
|
||||
We use (mod 4 GB) check for fileSize.
|
||||
Use fileSize up to 2 GB, if you want to support 32-bit and 64-bit code conversion. */
|
||||
UInt32 fileIp;
|
||||
UInt32 fileSize; /* (fileSize <= ((UInt32)1 << 31)), 0 means no_limit */
|
||||
UInt32 relatLimit; /* (relatLimit <= ((UInt32)1 << 31)), 0 means desable_conversion */
|
||||
|
||||
UInt32 tempTarget;
|
||||
unsigned tempPos;
|
||||
Byte temp[4 * 2];
|
||||
|
||||
unsigned flushPos;
|
||||
|
||||
UInt16 probs[2 + 256];
|
||||
} CBcj2Enc;
|
||||
|
||||
void Bcj2Enc_Init(CBcj2Enc *p);
|
||||
void Bcj2Enc_Encode(CBcj2Enc *p);
|
||||
|
||||
#define Bcj2Enc_Get_InputData_Size(p) ((SizeT)((p)->srcLim - (p)->src) + (p)->tempPos)
|
||||
#define Bcj2Enc_IsFinished(p) ((p)->flushPos == 5)
|
||||
|
||||
|
||||
#define BCJ2_RELAT_LIMIT_NUM_BITS 26
|
||||
#define BCJ2_RELAT_LIMIT ((UInt32)1 << BCJ2_RELAT_LIMIT_NUM_BITS)
|
||||
|
||||
/* limit for CBcj2Enc::fileSize variable */
|
||||
#define BCJ2_FileSize_MAX ((UInt32)1 << 31)
|
||||
|
||||
EXTERN_C_END
|
||||
|
||||
#endif
|
312
C/Bcj2Enc.c
Normal file
312
C/Bcj2Enc.c
Normal file
@ -0,0 +1,312 @@
|
||||
/* Bcj2Enc.c -- BCJ2 Encoder (Converter for x86 code)
|
||||
2014-11-10 : Igor Pavlov : Public domain */
|
||||
|
||||
#include "Precomp.h"
|
||||
|
||||
/* #define SHOW_STAT */
|
||||
|
||||
#ifdef SHOW_STAT
|
||||
#include <stdio.h>
|
||||
#define PRF(x) x
|
||||
#else
|
||||
#define PRF(x)
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "Bcj2.h"
|
||||
#include "CpuArch.h"
|
||||
|
||||
#define CProb UInt16
|
||||
|
||||
#define kTopValue ((UInt32)1 << 24)
|
||||
#define kNumModelBits 11
|
||||
#define kBitModelTotal (1 << kNumModelBits)
|
||||
#define kNumMoveBits 5
|
||||
|
||||
void Bcj2Enc_Init(CBcj2Enc *p)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
p->state = BCJ2_ENC_STATE_OK;
|
||||
p->finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE;
|
||||
|
||||
p->prevByte = 0;
|
||||
|
||||
p->cache = 0;
|
||||
p->range = 0xFFFFFFFF;
|
||||
p->low = 0;
|
||||
p->cacheSize = 1;
|
||||
|
||||
p->ip = 0;
|
||||
|
||||
p->fileIp = 0;
|
||||
p->fileSize = 0;
|
||||
p->relatLimit = BCJ2_RELAT_LIMIT;
|
||||
|
||||
p->tempPos = 0;
|
||||
|
||||
p->flushPos = 0;
|
||||
|
||||
for (i = 0; i < sizeof(p->probs) / sizeof(p->probs[0]); i++)
|
||||
p->probs[i] = kBitModelTotal >> 1;
|
||||
}
|
||||
|
||||
static Bool MY_FAST_CALL RangeEnc_ShiftLow(CBcj2Enc *p)
|
||||
{
|
||||
if ((UInt32)p->low < (UInt32)0xFF000000 || (UInt32)(p->low >> 32) != 0)
|
||||
{
|
||||
Byte *buf = p->bufs[BCJ2_STREAM_RC];
|
||||
do
|
||||
{
|
||||
if (buf == p->lims[BCJ2_STREAM_RC])
|
||||
{
|
||||
p->state = BCJ2_STREAM_RC;
|
||||
p->bufs[BCJ2_STREAM_RC] = buf;
|
||||
return True;
|
||||
}
|
||||
*buf++ = (Byte)(p->cache + (Byte)(p->low >> 32));
|
||||
p->cache = 0xFF;
|
||||
}
|
||||
while (--p->cacheSize);
|
||||
p->bufs[BCJ2_STREAM_RC] = buf;
|
||||
p->cache = (Byte)((UInt32)p->low >> 24);
|
||||
}
|
||||
p->cacheSize++;
|
||||
p->low = (UInt32)p->low << 8;
|
||||
return False;
|
||||
}
|
||||
|
||||
static void Bcj2Enc_Encode_2(CBcj2Enc *p)
|
||||
{
|
||||
if (BCJ2_IS_32BIT_STREAM(p->state))
|
||||
{
|
||||
Byte *cur = p->bufs[p->state];
|
||||
if (cur == p->lims[p->state])
|
||||
return;
|
||||
SetBe32(cur, p->tempTarget);
|
||||
p->bufs[p->state] = cur + 4;
|
||||
}
|
||||
|
||||
p->state = BCJ2_ENC_STATE_ORIG;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (p->range < kTopValue)
|
||||
{
|
||||
if (RangeEnc_ShiftLow(p))
|
||||
return;
|
||||
p->range <<= 8;
|
||||
}
|
||||
|
||||
{
|
||||
{
|
||||
const Byte *src = p->src;
|
||||
const Byte *srcLim;
|
||||
Byte *dest;
|
||||
SizeT num = p->srcLim - src;
|
||||
|
||||
if (p->finishMode == BCJ2_ENC_FINISH_MODE_CONTINUE)
|
||||
{
|
||||
if (num <= 4)
|
||||
return;
|
||||
num -= 4;
|
||||
}
|
||||
else if (num == 0)
|
||||
break;
|
||||
|
||||
dest = p->bufs[BCJ2_STREAM_MAIN];
|
||||
if (num > (SizeT)(p->lims[BCJ2_STREAM_MAIN] - dest))
|
||||
{
|
||||
num = p->lims[BCJ2_STREAM_MAIN] - dest;
|
||||
if (num == 0)
|
||||
{
|
||||
p->state = BCJ2_STREAM_MAIN;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
srcLim = src + num;
|
||||
|
||||
if (p->prevByte == 0x0F && (src[0] & 0xF0) == 0x80)
|
||||
*dest = src[0];
|
||||
else for (;;)
|
||||
{
|
||||
Byte b = *src;
|
||||
*dest = b;
|
||||
if (b != 0x0F)
|
||||
{
|
||||
if ((b & 0xFE) == 0xE8)
|
||||
break;
|
||||
dest++;
|
||||
if (++src != srcLim)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
dest++;
|
||||
if (++src == srcLim)
|
||||
break;
|
||||
if ((*src & 0xF0) != 0x80)
|
||||
continue;
|
||||
*dest = *src;
|
||||
break;
|
||||
}
|
||||
|
||||
num = src - p->src;
|
||||
|
||||
if (src == srcLim)
|
||||
{
|
||||
p->prevByte = src[-1];
|
||||
p->bufs[BCJ2_STREAM_MAIN] = dest;
|
||||
p->src = src;
|
||||
p->ip += (UInt32)num;
|
||||
continue;
|
||||
}
|
||||
|
||||
{
|
||||
Byte context = (Byte)(num == 0 ? p->prevByte : src[-1]);
|
||||
Bool needConvert;
|
||||
|
||||
p->bufs[BCJ2_STREAM_MAIN] = dest + 1;
|
||||
p->ip += (UInt32)num + 1;
|
||||
src++;
|
||||
|
||||
needConvert = False;
|
||||
|
||||
if ((SizeT)(p->srcLim - src) >= 4)
|
||||
{
|
||||
UInt32 relatVal = GetUi32(src);
|
||||
if ((p->fileSize == 0 || (UInt32)(p->ip + 4 + relatVal - p->fileIp) < p->fileSize)
|
||||
&& ((relatVal + p->relatLimit) >> 1) < p->relatLimit)
|
||||
needConvert = True;
|
||||
}
|
||||
|
||||
{
|
||||
UInt32 bound;
|
||||
unsigned ttt;
|
||||
Byte b = src[-1];
|
||||
CProb *prob = p->probs + (unsigned)(b == 0xE8 ? 2 + (unsigned)context : (b == 0xE9 ? 1 : 0));
|
||||
|
||||
ttt = *prob;
|
||||
bound = (p->range >> kNumModelBits) * ttt;
|
||||
|
||||
if (!needConvert)
|
||||
{
|
||||
p->range = bound;
|
||||
*prob = (CProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits));
|
||||
p->src = src;
|
||||
p->prevByte = b;
|
||||
continue;
|
||||
}
|
||||
|
||||
p->low += bound;
|
||||
p->range -= bound;
|
||||
*prob = (CProb)(ttt - (ttt >> kNumMoveBits));
|
||||
|
||||
{
|
||||
UInt32 relatVal = GetUi32(src);
|
||||
UInt32 absVal;
|
||||
p->ip += 4;
|
||||
absVal = p->ip + relatVal;
|
||||
p->prevByte = src[3];
|
||||
src += 4;
|
||||
p->src = src;
|
||||
{
|
||||
unsigned cj = (b == 0xE8) ? BCJ2_STREAM_CALL : BCJ2_STREAM_JUMP;
|
||||
Byte *cur = p->bufs[cj];
|
||||
if (cur == p->lims[cj])
|
||||
{
|
||||
p->state = cj;
|
||||
p->tempTarget = absVal;
|
||||
return;
|
||||
}
|
||||
SetBe32(cur, absVal);
|
||||
p->bufs[cj] = cur + 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (p->finishMode != BCJ2_ENC_FINISH_MODE_END_STREAM)
|
||||
return;
|
||||
|
||||
for (; p->flushPos < 5; p->flushPos++)
|
||||
if (RangeEnc_ShiftLow(p))
|
||||
return;
|
||||
p->state = BCJ2_ENC_STATE_OK;
|
||||
}
|
||||
|
||||
|
||||
void Bcj2Enc_Encode(CBcj2Enc *p)
|
||||
{
|
||||
PRF(printf("\n"));
|
||||
PRF(printf("---- ip = %8d tempPos = %8d src = %8d\n", p->ip, p->tempPos, p->srcLim - p->src));
|
||||
|
||||
if (p->tempPos != 0)
|
||||
{
|
||||
unsigned extra = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
const Byte *src = p->src;
|
||||
const Byte *srcLim = p->srcLim;
|
||||
unsigned finishMode = p->finishMode;
|
||||
|
||||
p->src = p->temp;
|
||||
p->srcLim = p->temp + p->tempPos;
|
||||
if (src != srcLim)
|
||||
p->finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE;
|
||||
|
||||
PRF(printf(" ip = %8d tempPos = %8d src = %8d\n", p->ip, p->tempPos, p->srcLim - p->src));
|
||||
|
||||
Bcj2Enc_Encode_2(p);
|
||||
|
||||
{
|
||||
unsigned num = (unsigned)(p->src - p->temp);
|
||||
unsigned tempPos = p->tempPos - num;
|
||||
unsigned i;
|
||||
p->tempPos = tempPos;
|
||||
for (i = 0; i < tempPos; i++)
|
||||
p->temp[i] = p->temp[i + num];
|
||||
|
||||
p->src = src;
|
||||
p->srcLim = srcLim;
|
||||
p->finishMode = finishMode;
|
||||
|
||||
if (p->state != BCJ2_ENC_STATE_ORIG || src == srcLim)
|
||||
return;
|
||||
|
||||
if (extra >= tempPos)
|
||||
{
|
||||
p->src = src - tempPos;
|
||||
p->tempPos = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
p->temp[tempPos] = src[0];
|
||||
p->tempPos = tempPos + 1;
|
||||
p->src = src + 1;
|
||||
extra++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PRF(printf("++++ ip = %8d tempPos = %8d src = %8d\n", p->ip, p->tempPos, p->srcLim - p->src));
|
||||
|
||||
Bcj2Enc_Encode_2(p);
|
||||
|
||||
if (p->state == BCJ2_ENC_STATE_ORIG)
|
||||
{
|
||||
const Byte *src = p->src;
|
||||
unsigned rem = (unsigned)(p->srcLim - src);
|
||||
unsigned i;
|
||||
for (i = 0; i < rem; i++)
|
||||
p->temp[i] = src[i];
|
||||
p->tempPos = rem;
|
||||
p->src = src + rem;
|
||||
}
|
||||
}
|
48
C/Blake2.h
Normal file
48
C/Blake2.h
Normal file
@ -0,0 +1,48 @@
|
||||
/* Blake2.h -- BLAKE2 Hash
|
||||
2015-06-30 : Igor Pavlov : Public domain
|
||||
2015 : Samuel Neves : Public domain */
|
||||
|
||||
#ifndef __BLAKE2_H
|
||||
#define __BLAKE2_H
|
||||
|
||||
#include "7zTypes.h"
|
||||
|
||||
EXTERN_C_BEGIN
|
||||
|
||||
#define BLAKE2S_BLOCK_SIZE 64
|
||||
#define BLAKE2S_DIGEST_SIZE 32
|
||||
#define BLAKE2SP_PARALLEL_DEGREE 8
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UInt32 h[8];
|
||||
UInt32 t[2];
|
||||
UInt32 f[2];
|
||||
Byte buf[BLAKE2S_BLOCK_SIZE];
|
||||
UInt32 bufPos;
|
||||
UInt32 lastNode_f1;
|
||||
UInt32 dummy[2]; /* for sizeof(CBlake2s) alignment */
|
||||
} CBlake2s;
|
||||
|
||||
/* You need to xor CBlake2s::h[i] with input parameter block after Blake2s_Init0() */
|
||||
/*
|
||||
void Blake2s_Init0(CBlake2s *p);
|
||||
void Blake2s_Update(CBlake2s *p, const Byte *data, size_t size);
|
||||
void Blake2s_Final(CBlake2s *p, Byte *digest);
|
||||
*/
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CBlake2s S[BLAKE2SP_PARALLEL_DEGREE];
|
||||
unsigned bufPos;
|
||||
} CBlake2sp;
|
||||
|
||||
|
||||
void Blake2sp_Init(CBlake2sp *p);
|
||||
void Blake2sp_Update(CBlake2sp *p, const Byte *data, size_t size);
|
||||
void Blake2sp_Final(CBlake2sp *p, Byte *digest);
|
||||
|
||||
EXTERN_C_END
|
||||
|
||||
#endif
|
244
C/Blake2s.c
Normal file
244
C/Blake2s.c
Normal file
@ -0,0 +1,244 @@
|
||||
/* Blake2s.c -- BLAKE2s and BLAKE2sp Hash
|
||||
2015-06-30 : Igor Pavlov : Public domain
|
||||
2015 : Samuel Neves : Public domain */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "Blake2.h"
|
||||
#include "CpuArch.h"
|
||||
#include "RotateDefs.h"
|
||||
|
||||
#define rotr32 rotrFixed
|
||||
|
||||
#define BLAKE2S_NUM_ROUNDS 10
|
||||
#define BLAKE2S_FINAL_FLAG (~(UInt32)0)
|
||||
|
||||
static const UInt32 k_Blake2s_IV[8] =
|
||||
{
|
||||
0x6A09E667UL, 0xBB67AE85UL, 0x3C6EF372UL, 0xA54FF53AUL,
|
||||
0x510E527FUL, 0x9B05688CUL, 0x1F83D9ABUL, 0x5BE0CD19UL
|
||||
};
|
||||
|
||||
static const Byte k_Blake2s_Sigma[BLAKE2S_NUM_ROUNDS][16] =
|
||||
{
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } ,
|
||||
{ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } ,
|
||||
{ 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } ,
|
||||
{ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } ,
|
||||
{ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } ,
|
||||
{ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } ,
|
||||
{ 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } ,
|
||||
{ 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } ,
|
||||
{ 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } ,
|
||||
{ 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } ,
|
||||
};
|
||||
|
||||
|
||||
void Blake2s_Init0(CBlake2s *p)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < 8; i++)
|
||||
p->h[i] = k_Blake2s_IV[i];
|
||||
p->t[0] = 0;
|
||||
p->t[1] = 0;
|
||||
p->f[0] = 0;
|
||||
p->f[1] = 0;
|
||||
p->bufPos = 0;
|
||||
p->lastNode_f1 = 0;
|
||||
}
|
||||
|
||||
|
||||
static void Blake2s_Compress(CBlake2s *p)
|
||||
{
|
||||
UInt32 m[16];
|
||||
UInt32 v[16];
|
||||
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
m[i] = GetUi32(p->buf + i * sizeof(m[i]));
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
v[i] = p->h[i];
|
||||
}
|
||||
|
||||
v[ 8] = k_Blake2s_IV[0];
|
||||
v[ 9] = k_Blake2s_IV[1];
|
||||
v[10] = k_Blake2s_IV[2];
|
||||
v[11] = k_Blake2s_IV[3];
|
||||
|
||||
v[12] = p->t[0] ^ k_Blake2s_IV[4];
|
||||
v[13] = p->t[1] ^ k_Blake2s_IV[5];
|
||||
v[14] = p->f[0] ^ k_Blake2s_IV[6];
|
||||
v[15] = p->f[1] ^ k_Blake2s_IV[7];
|
||||
|
||||
#define G(r,i,a,b,c,d) \
|
||||
a += b + m[sigma[2*i+0]]; d ^= a; d = rotr32(d, 16); c += d; b ^= c; b = rotr32(b, 12); \
|
||||
a += b + m[sigma[2*i+1]]; d ^= a; d = rotr32(d, 8); c += d; b ^= c; b = rotr32(b, 7); \
|
||||
|
||||
#define R(r) \
|
||||
G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \
|
||||
G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \
|
||||
G(r,2,v[ 2],v[ 6],v[10],v[14]); \
|
||||
G(r,3,v[ 3],v[ 7],v[11],v[15]); \
|
||||
G(r,4,v[ 0],v[ 5],v[10],v[15]); \
|
||||
G(r,5,v[ 1],v[ 6],v[11],v[12]); \
|
||||
G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \
|
||||
G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \
|
||||
|
||||
{
|
||||
unsigned r;
|
||||
for (r = 0; r < BLAKE2S_NUM_ROUNDS; r++)
|
||||
{
|
||||
const Byte *sigma = k_Blake2s_Sigma[r];
|
||||
R(r);
|
||||
}
|
||||
/* R(0); R(1); R(2); R(3); R(4); R(5); R(6); R(7); R(8); R(9); */
|
||||
}
|
||||
|
||||
#undef G
|
||||
#undef R
|
||||
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < 8; i++)
|
||||
p->h[i] ^= v[i] ^ v[i + 8];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define Blake2s_Increment_Counter(S, inc) \
|
||||
{ p->t[0] += (inc); p->t[1] += (p->t[0] < (inc)); }
|
||||
|
||||
#define Blake2s_Set_LastBlock(p) \
|
||||
{ p->f[0] = BLAKE2S_FINAL_FLAG; p->f[1] = p->lastNode_f1; }
|
||||
|
||||
|
||||
static void Blake2s_Update(CBlake2s *p, const Byte *data, size_t size)
|
||||
{
|
||||
while (size != 0)
|
||||
{
|
||||
unsigned pos = (unsigned)p->bufPos;
|
||||
unsigned rem = BLAKE2S_BLOCK_SIZE - pos;
|
||||
|
||||
if (size <= rem)
|
||||
{
|
||||
memcpy(p->buf + pos, data, size);
|
||||
p->bufPos += (UInt32)size;
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(p->buf + pos, data, rem);
|
||||
Blake2s_Increment_Counter(S, BLAKE2S_BLOCK_SIZE);
|
||||
Blake2s_Compress(p);
|
||||
p->bufPos = 0;
|
||||
data += rem;
|
||||
size -= rem;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void Blake2s_Final(CBlake2s *p, Byte *digest)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
Blake2s_Increment_Counter(S, (UInt32)p->bufPos);
|
||||
Blake2s_Set_LastBlock(p);
|
||||
memset(p->buf + p->bufPos, 0, BLAKE2S_BLOCK_SIZE - p->bufPos);
|
||||
Blake2s_Compress(p);
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
SetUi32(digest + sizeof(p->h[i]) * i, p->h[i]);
|
||||
}
|
||||
|
||||
|
||||
/* ---------- BLAKE2s ---------- */
|
||||
|
||||
/* we need to xor CBlake2s::h[i] with input parameter block after Blake2s_Init0() */
|
||||
/*
|
||||
typedef struct
|
||||
{
|
||||
Byte digest_length;
|
||||
Byte key_length;
|
||||
Byte fanout;
|
||||
Byte depth;
|
||||
UInt32 leaf_length;
|
||||
Byte node_offset[6];
|
||||
Byte node_depth;
|
||||
Byte inner_length;
|
||||
Byte salt[BLAKE2S_SALTBYTES];
|
||||
Byte personal[BLAKE2S_PERSONALBYTES];
|
||||
} CBlake2sParam;
|
||||
*/
|
||||
|
||||
|
||||
static void Blake2sp_Init_Spec(CBlake2s *p, unsigned node_offset, unsigned node_depth)
|
||||
{
|
||||
Blake2s_Init0(p);
|
||||
|
||||
p->h[0] ^= (BLAKE2S_DIGEST_SIZE | ((UInt32)BLAKE2SP_PARALLEL_DEGREE << 16) | ((UInt32)2 << 24));
|
||||
p->h[2] ^= ((UInt32)node_offset);
|
||||
p->h[3] ^= ((UInt32)node_depth << 16) | ((UInt32)BLAKE2S_DIGEST_SIZE << 24);
|
||||
/*
|
||||
P->digest_length = BLAKE2S_DIGEST_SIZE;
|
||||
P->key_length = 0;
|
||||
P->fanout = BLAKE2SP_PARALLEL_DEGREE;
|
||||
P->depth = 2;
|
||||
P->leaf_length = 0;
|
||||
store48(P->node_offset, node_offset);
|
||||
P->node_depth = node_depth;
|
||||
P->inner_length = BLAKE2S_DIGEST_SIZE;
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
void Blake2sp_Init(CBlake2sp *p)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
p->bufPos = 0;
|
||||
|
||||
for (i = 0; i < BLAKE2SP_PARALLEL_DEGREE; i++)
|
||||
Blake2sp_Init_Spec(&p->S[i], i, 0);
|
||||
|
||||
p->S[BLAKE2SP_PARALLEL_DEGREE - 1].lastNode_f1 = BLAKE2S_FINAL_FLAG;
|
||||
}
|
||||
|
||||
|
||||
void Blake2sp_Update(CBlake2sp *p, const Byte *data, size_t size)
|
||||
{
|
||||
unsigned pos = p->bufPos;
|
||||
while (size != 0)
|
||||
{
|
||||
unsigned index = pos / BLAKE2S_BLOCK_SIZE;
|
||||
unsigned rem = BLAKE2S_BLOCK_SIZE - (pos & (BLAKE2S_BLOCK_SIZE - 1));
|
||||
if (rem > size)
|
||||
rem = (unsigned)size;
|
||||
Blake2s_Update(&p->S[index], data, rem);
|
||||
size -= rem;
|
||||
data += rem;
|
||||
pos += rem;
|
||||
pos &= (BLAKE2S_BLOCK_SIZE * BLAKE2SP_PARALLEL_DEGREE - 1);
|
||||
}
|
||||
p->bufPos = pos;
|
||||
}
|
||||
|
||||
|
||||
void Blake2sp_Final(CBlake2sp *p, Byte *digest)
|
||||
{
|
||||
CBlake2s R;
|
||||
unsigned i;
|
||||
|
||||
Blake2sp_Init_Spec(&R, 0, 1);
|
||||
R.lastNode_f1 = BLAKE2S_FINAL_FLAG;
|
||||
|
||||
for (i = 0; i < BLAKE2SP_PARALLEL_DEGREE; i++)
|
||||
{
|
||||
Byte hash[BLAKE2S_DIGEST_SIZE];
|
||||
Blake2s_Final(&p->S[i], hash);
|
||||
Blake2s_Update(&R, hash, BLAKE2S_DIGEST_SIZE);
|
||||
}
|
||||
|
||||
Blake2s_Final(&R, digest);
|
||||
}
|
135
C/Bra.c
Normal file
135
C/Bra.c
Normal file
@ -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;
|
||||
}
|
64
C/Bra.h
Normal file
64
C/Bra.h
Normal file
@ -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
|
82
C/Bra86.c
Normal file
82
C/Bra86.c
Normal file
@ -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++;
|
||||
}
|
||||
}
|
||||
}
|
69
C/BraIA64.c
Normal file
69
C/BraIA64.c
Normal file
@ -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;
|
||||
}
|
515
C/BwtSort.c
Normal file
515
C/BwtSort.c
Normal file
@ -0,0 +1,515 @@
|
||||
/* BwtSort.c -- BWT block sorting
|
||||
2013-11-12 : Igor Pavlov : Public domain */
|
||||
|
||||
#include "Precomp.h"
|
||||
|
||||
#include "BwtSort.h"
|
||||
#include "Sort.h"
|
||||
|
||||
/* #define BLOCK_SORT_USE_HEAP_SORT */
|
||||
|
||||
#define NO_INLINE MY_FAST_CALL
|
||||
|
||||
/* Don't change it !!! */
|
||||
#define kNumHashBytes 2
|
||||
#define kNumHashValues (1 << (kNumHashBytes * 8))
|
||||
|
||||
/* kNumRefBitsMax must be < (kNumHashBytes * 8) = 16 */
|
||||
#define kNumRefBitsMax 12
|
||||
|
||||
#define BS_TEMP_SIZE kNumHashValues
|
||||
|
||||
#ifdef BLOCK_SORT_EXTERNAL_FLAGS
|
||||
|
||||
/* 32 Flags in UInt32 word */
|
||||
#define kNumFlagsBits 5
|
||||
#define kNumFlagsInWord (1 << kNumFlagsBits)
|
||||
#define kFlagsMask (kNumFlagsInWord - 1)
|
||||
#define kAllFlags 0xFFFFFFFF
|
||||
|
||||
#else
|
||||
|
||||
#define kNumBitsMax 20
|
||||
#define kIndexMask ((1 << kNumBitsMax) - 1)
|
||||
#define kNumExtraBits (32 - kNumBitsMax)
|
||||
#define kNumExtra0Bits (kNumExtraBits - 2)
|
||||
#define kNumExtra0Mask ((1 << kNumExtra0Bits) - 1)
|
||||
|
||||
#define SetFinishedGroupSize(p, size) \
|
||||
{ *(p) |= ((((size) - 1) & kNumExtra0Mask) << kNumBitsMax); \
|
||||
if ((size) > (1 << kNumExtra0Bits)) { \
|
||||
*(p) |= 0x40000000; *((p) + 1) |= ((((size) - 1)>> kNumExtra0Bits) << kNumBitsMax); } } \
|
||||
|
||||
static void SetGroupSize(UInt32 *p, UInt32 size)
|
||||
{
|
||||
if (--size == 0)
|
||||
return;
|
||||
*p |= 0x80000000 | ((size & kNumExtra0Mask) << kNumBitsMax);
|
||||
if (size >= (1 << kNumExtra0Bits))
|
||||
{
|
||||
*p |= 0x40000000;
|
||||
p[1] |= ((size >> kNumExtra0Bits) << kNumBitsMax);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
SortGroup - is recursive Range-Sort function with HeapSort optimization for small blocks
|
||||
"range" is not real range. It's only for optimization.
|
||||
returns: 1 - if there are groups, 0 - no more groups
|
||||
*/
|
||||
|
||||
UInt32 NO_INLINE SortGroup(UInt32 BlockSize, UInt32 NumSortedBytes, UInt32 groupOffset, UInt32 groupSize, int NumRefBits, UInt32 *Indices
|
||||
#ifndef BLOCK_SORT_USE_HEAP_SORT
|
||||
, UInt32 left, UInt32 range
|
||||
#endif
|
||||
)
|
||||
{
|
||||
UInt32 *ind2 = Indices + groupOffset;
|
||||
UInt32 *Groups;
|
||||
if (groupSize <= 1)
|
||||
{
|
||||
/*
|
||||
#ifndef BLOCK_SORT_EXTERNAL_FLAGS
|
||||
SetFinishedGroupSize(ind2, 1);
|
||||
#endif
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
Groups = Indices + BlockSize + BS_TEMP_SIZE;
|
||||
if (groupSize <= ((UInt32)1 << NumRefBits)
|
||||
#ifndef BLOCK_SORT_USE_HEAP_SORT
|
||||
&& groupSize <= range
|
||||
#endif
|
||||
)
|
||||
{
|
||||
UInt32 *temp = Indices + BlockSize;
|
||||
UInt32 j;
|
||||
UInt32 mask, thereAreGroups, group, cg;
|
||||
{
|
||||
UInt32 gPrev;
|
||||
UInt32 gRes = 0;
|
||||
{
|
||||
UInt32 sp = ind2[0] + NumSortedBytes;
|
||||
if (sp >= BlockSize) sp -= BlockSize;
|
||||
gPrev = Groups[sp];
|
||||
temp[0] = (gPrev << NumRefBits);
|
||||
}
|
||||
|
||||
for (j = 1; j < groupSize; j++)
|
||||
{
|
||||
UInt32 sp = ind2[j] + NumSortedBytes;
|
||||
UInt32 g;
|
||||
if (sp >= BlockSize) sp -= BlockSize;
|
||||
g = Groups[sp];
|
||||
temp[j] = (g << NumRefBits) | j;
|
||||
gRes |= (gPrev ^ g);
|
||||
}
|
||||
if (gRes == 0)
|
||||
{
|
||||
#ifndef BLOCK_SORT_EXTERNAL_FLAGS
|
||||
SetGroupSize(ind2, groupSize);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
HeapSort(temp, groupSize);
|
||||
mask = ((1 << NumRefBits) - 1);
|
||||
thereAreGroups = 0;
|
||||
|
||||
group = groupOffset;
|
||||
cg = (temp[0] >> NumRefBits);
|
||||
temp[0] = ind2[temp[0] & mask];
|
||||
|
||||
{
|
||||
#ifdef BLOCK_SORT_EXTERNAL_FLAGS
|
||||
UInt32 *Flags = Groups + BlockSize;
|
||||
#else
|
||||
UInt32 prevGroupStart = 0;
|
||||
#endif
|
||||
|
||||
for (j = 1; j < groupSize; j++)
|
||||
{
|
||||
UInt32 val = temp[j];
|
||||
UInt32 cgCur = (val >> NumRefBits);
|
||||
|
||||
if (cgCur != cg)
|
||||
{
|
||||
cg = cgCur;
|
||||
group = groupOffset + j;
|
||||
|
||||
#ifdef BLOCK_SORT_EXTERNAL_FLAGS
|
||||
{
|
||||
UInt32 t = group - 1;
|
||||
Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask));
|
||||
}
|
||||
#else
|
||||
SetGroupSize(temp + prevGroupStart, j - prevGroupStart);
|
||||
prevGroupStart = j;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
thereAreGroups = 1;
|
||||
{
|
||||
UInt32 ind = ind2[val & mask];
|
||||
temp[j] = ind;
|
||||
Groups[ind] = group;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef BLOCK_SORT_EXTERNAL_FLAGS
|
||||
SetGroupSize(temp + prevGroupStart, j - prevGroupStart);
|
||||
#endif
|
||||
}
|
||||
|
||||
for (j = 0; j < groupSize; j++)
|
||||
ind2[j] = temp[j];
|
||||
return thereAreGroups;
|
||||
}
|
||||
|
||||
/* Check that all strings are in one group (cannot sort) */
|
||||
{
|
||||
UInt32 group, j;
|
||||
UInt32 sp = ind2[0] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize;
|
||||
group = Groups[sp];
|
||||
for (j = 1; j < groupSize; j++)
|
||||
{
|
||||
sp = ind2[j] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize;
|
||||
if (Groups[sp] != group)
|
||||
break;
|
||||
}
|
||||
if (j == groupSize)
|
||||
{
|
||||
#ifndef BLOCK_SORT_EXTERNAL_FLAGS
|
||||
SetGroupSize(ind2, groupSize);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef BLOCK_SORT_USE_HEAP_SORT
|
||||
{
|
||||
/* ---------- Range Sort ---------- */
|
||||
UInt32 i;
|
||||
UInt32 mid;
|
||||
for (;;)
|
||||
{
|
||||
UInt32 j;
|
||||
if (range <= 1)
|
||||
{
|
||||
#ifndef BLOCK_SORT_EXTERNAL_FLAGS
|
||||
SetGroupSize(ind2, groupSize);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
mid = left + ((range + 1) >> 1);
|
||||
j = groupSize;
|
||||
i = 0;
|
||||
do
|
||||
{
|
||||
UInt32 sp = ind2[i] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize;
|
||||
if (Groups[sp] >= mid)
|
||||
{
|
||||
for (j--; j > i; j--)
|
||||
{
|
||||
sp = ind2[j] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize;
|
||||
if (Groups[sp] < mid)
|
||||
{
|
||||
UInt32 temp = ind2[i]; ind2[i] = ind2[j]; ind2[j] = temp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i >= j)
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (++i < j);
|
||||
if (i == 0)
|
||||
{
|
||||
range = range - (mid - left);
|
||||
left = mid;
|
||||
}
|
||||
else if (i == groupSize)
|
||||
range = (mid - left);
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef BLOCK_SORT_EXTERNAL_FLAGS
|
||||
{
|
||||
UInt32 t = (groupOffset + i - 1);
|
||||
UInt32 *Flags = Groups + BlockSize;
|
||||
Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask));
|
||||
}
|
||||
#endif
|
||||
|
||||
{
|
||||
UInt32 j;
|
||||
for (j = i; j < groupSize; j++)
|
||||
Groups[ind2[j]] = groupOffset + i;
|
||||
}
|
||||
|
||||
{
|
||||
UInt32 res = SortGroup(BlockSize, NumSortedBytes, groupOffset, i, NumRefBits, Indices, left, mid - left);
|
||||
return res | SortGroup(BlockSize, NumSortedBytes, groupOffset + i, groupSize - i, NumRefBits, Indices, mid, range - (mid - left));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* ---------- Heap Sort ---------- */
|
||||
|
||||
{
|
||||
UInt32 j;
|
||||
for (j = 0; j < groupSize; j++)
|
||||
{
|
||||
UInt32 sp = ind2[j] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize;
|
||||
ind2[j] = sp;
|
||||
}
|
||||
|
||||
HeapSortRef(ind2, Groups, groupSize);
|
||||
|
||||
/* Write Flags */
|
||||
{
|
||||
UInt32 sp = ind2[0];
|
||||
UInt32 group = Groups[sp];
|
||||
|
||||
#ifdef BLOCK_SORT_EXTERNAL_FLAGS
|
||||
UInt32 *Flags = Groups + BlockSize;
|
||||
#else
|
||||
UInt32 prevGroupStart = 0;
|
||||
#endif
|
||||
|
||||
for (j = 1; j < groupSize; j++)
|
||||
{
|
||||
sp = ind2[j];
|
||||
if (Groups[sp] != group)
|
||||
{
|
||||
group = Groups[sp];
|
||||
#ifdef BLOCK_SORT_EXTERNAL_FLAGS
|
||||
{
|
||||
UInt32 t = groupOffset + j - 1;
|
||||
Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask));
|
||||
}
|
||||
#else
|
||||
SetGroupSize(ind2 + prevGroupStart, j - prevGroupStart);
|
||||
prevGroupStart = j;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef BLOCK_SORT_EXTERNAL_FLAGS
|
||||
SetGroupSize(ind2 + prevGroupStart, j - prevGroupStart);
|
||||
#endif
|
||||
}
|
||||
{
|
||||
/* Write new Groups values and Check that there are groups */
|
||||
UInt32 thereAreGroups = 0;
|
||||
for (j = 0; j < groupSize; j++)
|
||||
{
|
||||
UInt32 group = groupOffset + j;
|
||||
#ifndef BLOCK_SORT_EXTERNAL_FLAGS
|
||||
UInt32 subGroupSize = ((ind2[j] & ~0xC0000000) >> kNumBitsMax);
|
||||
if ((ind2[j] & 0x40000000) != 0)
|
||||
subGroupSize += ((ind2[j + 1] >> kNumBitsMax) << kNumExtra0Bits);
|
||||
subGroupSize++;
|
||||
for (;;)
|
||||
{
|
||||
UInt32 original = ind2[j];
|
||||
UInt32 sp = original & kIndexMask;
|
||||
if (sp < NumSortedBytes) sp += BlockSize; sp -= NumSortedBytes;
|
||||
ind2[j] = sp | (original & ~kIndexMask);
|
||||
Groups[sp] = group;
|
||||
if (--subGroupSize == 0)
|
||||
break;
|
||||
j++;
|
||||
thereAreGroups = 1;
|
||||
}
|
||||
#else
|
||||
UInt32 *Flags = Groups + BlockSize;
|
||||
for (;;)
|
||||
{
|
||||
UInt32 sp = ind2[j]; if (sp < NumSortedBytes) sp += BlockSize; sp -= NumSortedBytes;
|
||||
ind2[j] = sp;
|
||||
Groups[sp] = group;
|
||||
if ((Flags[(groupOffset + j) >> kNumFlagsBits] & (1 << ((groupOffset + j) & kFlagsMask))) == 0)
|
||||
break;
|
||||
j++;
|
||||
thereAreGroups = 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return thereAreGroups;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* conditions: blockSize > 0 */
|
||||
UInt32 BlockSort(UInt32 *Indices, const Byte *data, UInt32 blockSize)
|
||||
{
|
||||
UInt32 *counters = Indices + blockSize;
|
||||
UInt32 i;
|
||||
UInt32 *Groups;
|
||||
#ifdef BLOCK_SORT_EXTERNAL_FLAGS
|
||||
UInt32 *Flags;
|
||||
#endif
|
||||
|
||||
/* Radix-Sort for 2 bytes */
|
||||
for (i = 0; i < kNumHashValues; i++)
|
||||
counters[i] = 0;
|
||||
for (i = 0; i < blockSize - 1; i++)
|
||||
counters[((UInt32)data[i] << 8) | data[i + 1]]++;
|
||||
counters[((UInt32)data[i] << 8) | data[0]]++;
|
||||
|
||||
Groups = counters + BS_TEMP_SIZE;
|
||||
#ifdef BLOCK_SORT_EXTERNAL_FLAGS
|
||||
Flags = Groups + blockSize;
|
||||
{
|
||||
UInt32 numWords = (blockSize + kFlagsMask) >> kNumFlagsBits;
|
||||
for (i = 0; i < numWords; i++)
|
||||
Flags[i] = kAllFlags;
|
||||
}
|
||||
#endif
|
||||
|
||||
{
|
||||
UInt32 sum = 0;
|
||||
for (i = 0; i < kNumHashValues; i++)
|
||||
{
|
||||
UInt32 groupSize = counters[i];
|
||||
if (groupSize > 0)
|
||||
{
|
||||
#ifdef BLOCK_SORT_EXTERNAL_FLAGS
|
||||
UInt32 t = sum + groupSize - 1;
|
||||
Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask));
|
||||
#endif
|
||||
sum += groupSize;
|
||||
}
|
||||
counters[i] = sum - groupSize;
|
||||
}
|
||||
|
||||
for (i = 0; i < blockSize - 1; i++)
|
||||
Groups[i] = counters[((UInt32)data[i] << 8) | data[i + 1]];
|
||||
Groups[i] = counters[((UInt32)data[i] << 8) | data[0]];
|
||||
|
||||
for (i = 0; i < blockSize - 1; i++)
|
||||
Indices[counters[((UInt32)data[i] << 8) | data[i + 1]]++] = i;
|
||||
Indices[counters[((UInt32)data[i] << 8) | data[0]]++] = i;
|
||||
|
||||
#ifndef BLOCK_SORT_EXTERNAL_FLAGS
|
||||
{
|
||||
UInt32 prev = 0;
|
||||
for (i = 0; i < kNumHashValues; i++)
|
||||
{
|
||||
UInt32 prevGroupSize = counters[i] - prev;
|
||||
if (prevGroupSize == 0)
|
||||
continue;
|
||||
SetGroupSize(Indices + prev, prevGroupSize);
|
||||
prev = counters[i];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
{
|
||||
int NumRefBits;
|
||||
UInt32 NumSortedBytes;
|
||||
for (NumRefBits = 0; ((blockSize - 1) >> NumRefBits) != 0; NumRefBits++);
|
||||
NumRefBits = 32 - NumRefBits;
|
||||
if (NumRefBits > kNumRefBitsMax)
|
||||
NumRefBits = kNumRefBitsMax;
|
||||
|
||||
for (NumSortedBytes = kNumHashBytes; ; NumSortedBytes <<= 1)
|
||||
{
|
||||
#ifndef BLOCK_SORT_EXTERNAL_FLAGS
|
||||
UInt32 finishedGroupSize = 0;
|
||||
#endif
|
||||
UInt32 newLimit = 0;
|
||||
for (i = 0; i < blockSize;)
|
||||
{
|
||||
UInt32 groupSize;
|
||||
#ifdef BLOCK_SORT_EXTERNAL_FLAGS
|
||||
|
||||
if ((Flags[i >> kNumFlagsBits] & (1 << (i & kFlagsMask))) == 0)
|
||||
{
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
for (groupSize = 1;
|
||||
(Flags[(i + groupSize) >> kNumFlagsBits] & (1 << ((i + groupSize) & kFlagsMask))) != 0;
|
||||
groupSize++);
|
||||
|
||||
groupSize++;
|
||||
|
||||
#else
|
||||
|
||||
groupSize = ((Indices[i] & ~0xC0000000) >> kNumBitsMax);
|
||||
{
|
||||
Bool finishedGroup = ((Indices[i] & 0x80000000) == 0);
|
||||
if ((Indices[i] & 0x40000000) != 0)
|
||||
{
|
||||
groupSize += ((Indices[i + 1] >> kNumBitsMax) << kNumExtra0Bits);
|
||||
Indices[i + 1] &= kIndexMask;
|
||||
}
|
||||
Indices[i] &= kIndexMask;
|
||||
groupSize++;
|
||||
if (finishedGroup || groupSize == 1)
|
||||
{
|
||||
Indices[i - finishedGroupSize] &= kIndexMask;
|
||||
if (finishedGroupSize > 1)
|
||||
Indices[i - finishedGroupSize + 1] &= kIndexMask;
|
||||
{
|
||||
UInt32 newGroupSize = groupSize + finishedGroupSize;
|
||||
SetFinishedGroupSize(Indices + i - finishedGroupSize, newGroupSize);
|
||||
finishedGroupSize = newGroupSize;
|
||||
}
|
||||
i += groupSize;
|
||||
continue;
|
||||
}
|
||||
finishedGroupSize = 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if (NumSortedBytes >= blockSize)
|
||||
{
|
||||
UInt32 j;
|
||||
for (j = 0; j < groupSize; j++)
|
||||
{
|
||||
UInt32 t = (i + j);
|
||||
/* Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask)); */
|
||||
Groups[Indices[t]] = t;
|
||||
}
|
||||
}
|
||||
else
|
||||
if (SortGroup(blockSize, NumSortedBytes, i, groupSize, NumRefBits, Indices
|
||||
#ifndef BLOCK_SORT_USE_HEAP_SORT
|
||||
, 0, blockSize
|
||||
#endif
|
||||
) != 0)
|
||||
newLimit = i + groupSize;
|
||||
i += groupSize;
|
||||
}
|
||||
if (newLimit == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifndef BLOCK_SORT_EXTERNAL_FLAGS
|
||||
for (i = 0; i < blockSize;)
|
||||
{
|
||||
UInt32 groupSize = ((Indices[i] & ~0xC0000000) >> kNumBitsMax);
|
||||
if ((Indices[i] & 0x40000000) != 0)
|
||||
{
|
||||
groupSize += ((Indices[i + 1] >> kNumBitsMax) << kNumExtra0Bits);
|
||||
Indices[i + 1] &= kIndexMask;
|
||||
}
|
||||
Indices[i] &= kIndexMask;
|
||||
groupSize++;
|
||||
i += groupSize;
|
||||
}
|
||||
#endif
|
||||
return Groups[0];
|
||||
}
|
26
C/BwtSort.h
Normal file
26
C/BwtSort.h
Normal file
@ -0,0 +1,26 @@
|
||||
/* BwtSort.h -- BWT block sorting
|
||||
2013-01-18 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __BWT_SORT_H
|
||||
#define __BWT_SORT_H
|
||||
|
||||
#include "7zTypes.h"
|
||||
|
||||
EXTERN_C_BEGIN
|
||||
|
||||
/* use BLOCK_SORT_EXTERNAL_FLAGS if blockSize can be > 1M */
|
||||
/* #define BLOCK_SORT_EXTERNAL_FLAGS */
|
||||
|
||||
#ifdef BLOCK_SORT_EXTERNAL_FLAGS
|
||||
#define BLOCK_SORT_EXTERNAL_SIZE(blockSize) ((((blockSize) + 31) >> 5))
|
||||
#else
|
||||
#define BLOCK_SORT_EXTERNAL_SIZE(blockSize) 0
|
||||
#endif
|
||||
|
||||
#define BLOCK_SORT_BUF_SIZE(blockSize) ((blockSize) * 2 + BLOCK_SORT_EXTERNAL_SIZE(blockSize) + (1 << 16))
|
||||
|
||||
UInt32 BlockSort(UInt32 *indices, const Byte *data, UInt32 blockSize);
|
||||
|
||||
EXTERN_C_END
|
||||
|
||||
#endif
|
32
C/Compiler.h
Normal file
32
C/Compiler.h
Normal file
@ -0,0 +1,32 @@
|
||||
/* Compiler.h
|
||||
2015-08-02 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __7Z_COMPILER_H
|
||||
#define __7Z_COMPILER_H
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
#ifdef UNDER_CE
|
||||
#define RPC_NO_WINDOWS_H
|
||||
/* #pragma warning(disable : 4115) // '_RPC_ASYNC_STATE' : named type definition in parentheses */
|
||||
#pragma warning(disable : 4201) // nonstandard extension used : nameless struct/union
|
||||
#pragma warning(disable : 4214) // nonstandard extension used : bit field types other than int
|
||||
#endif
|
||||
|
||||
#if _MSC_VER >= 1300
|
||||
#pragma warning(disable : 4996) // This function or variable may be unsafe
|
||||
#else
|
||||
#pragma warning(disable : 4511) // copy constructor could not be generated
|
||||
#pragma warning(disable : 4512) // assignment operator could not be generated
|
||||
#pragma warning(disable : 4514) // unreferenced inline function has been removed
|
||||
#pragma warning(disable : 4702) // unreachable code
|
||||
#pragma warning(disable : 4710) // not inlined
|
||||
#pragma warning(disable : 4786) // identifier was truncated to '255' characters in the debug information
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#define UNUSED_VAR(x) (void)x;
|
||||
/* #define UNUSED_VAR(x) x=x; */
|
||||
|
||||
#endif
|
211
C/CpuArch.c
Normal file
211
C/CpuArch.c
Normal file
@ -0,0 +1,211 @@
|
||||
/* CpuArch.c -- CPU specific code
|
||||
2016-02-25: Igor Pavlov : Public domain */
|
||||
|
||||
#include "Precomp.h"
|
||||
|
||||
#include "CpuArch.h"
|
||||
|
||||
#ifdef _7ZIP_ASM
|
||||
#ifdef MY_CPU_X86_OR_AMD64
|
||||
|
||||
#if (defined(_MSC_VER) && !defined(MY_CPU_AMD64)) || defined(__GNUC__)
|
||||
#define USE_ASM
|
||||
#endif
|
||||
|
||||
#if !defined(USE_ASM) && _MSC_VER >= 1500
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
|
||||
#if defined(USE_ASM) && !defined(MY_CPU_AMD64)
|
||||
static UInt32 CheckFlag(UInt32 flag)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
__asm pushfd;
|
||||
__asm pop EAX;
|
||||
__asm mov EDX, EAX;
|
||||
__asm xor EAX, flag;
|
||||
__asm push EAX;
|
||||
__asm popfd;
|
||||
__asm pushfd;
|
||||
__asm pop EAX;
|
||||
__asm xor EAX, EDX;
|
||||
__asm push EDX;
|
||||
__asm popfd;
|
||||
__asm and flag, EAX;
|
||||
#else
|
||||
__asm__ __volatile__ (
|
||||
"pushf\n\t"
|
||||
"pop %%EAX\n\t"
|
||||
"movl %%EAX,%%EDX\n\t"
|
||||
"xorl %0,%%EAX\n\t"
|
||||
"push %%EAX\n\t"
|
||||
"popf\n\t"
|
||||
"pushf\n\t"
|
||||
"pop %%EAX\n\t"
|
||||
"xorl %%EDX,%%EAX\n\t"
|
||||
"push %%EDX\n\t"
|
||||
"popf\n\t"
|
||||
"andl %%EAX, %0\n\t":
|
||||
"=c" (flag) : "c" (flag) :
|
||||
"%eax", "%edx");
|
||||
#endif
|
||||
return flag;
|
||||
}
|
||||
#define CHECK_CPUID_IS_SUPPORTED if (CheckFlag(1 << 18) == 0 || CheckFlag(1 << 21) == 0) return False;
|
||||
#else
|
||||
#define CHECK_CPUID_IS_SUPPORTED
|
||||
#endif
|
||||
|
||||
void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d)
|
||||
{
|
||||
#ifdef USE_ASM
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
UInt32 a2, b2, c2, d2;
|
||||
__asm xor EBX, EBX;
|
||||
__asm xor ECX, ECX;
|
||||
__asm xor EDX, EDX;
|
||||
__asm mov EAX, function;
|
||||
__asm cpuid;
|
||||
__asm mov a2, EAX;
|
||||
__asm mov b2, EBX;
|
||||
__asm mov c2, ECX;
|
||||
__asm mov d2, EDX;
|
||||
|
||||
*a = a2;
|
||||
*b = b2;
|
||||
*c = c2;
|
||||
*d = d2;
|
||||
|
||||
#else
|
||||
|
||||
__asm__ __volatile__ (
|
||||
#if defined(MY_CPU_AMD64) && defined(__PIC__)
|
||||
"mov %%rbx, %%rdi;"
|
||||
"cpuid;"
|
||||
"xchg %%rbx, %%rdi;"
|
||||
: "=a" (*a) ,
|
||||
"=D" (*b) ,
|
||||
#elif defined(MY_CPU_X86) && defined(__PIC__)
|
||||
"mov %%ebx, %%edi;"
|
||||
"cpuid;"
|
||||
"xchgl %%ebx, %%edi;"
|
||||
: "=a" (*a) ,
|
||||
"=D" (*b) ,
|
||||
#else
|
||||
"cpuid"
|
||||
: "=a" (*a) ,
|
||||
"=b" (*b) ,
|
||||
#endif
|
||||
"=c" (*c) ,
|
||||
"=d" (*d)
|
||||
: "0" (function)) ;
|
||||
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
int CPUInfo[4];
|
||||
__cpuid(CPUInfo, function);
|
||||
*a = CPUInfo[0];
|
||||
*b = CPUInfo[1];
|
||||
*c = CPUInfo[2];
|
||||
*d = CPUInfo[3];
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
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 const UInt32 kVendors[][3] =
|
||||
{
|
||||
{ 0x756E6547, 0x49656E69, 0x6C65746E},
|
||||
{ 0x68747541, 0x69746E65, 0x444D4163},
|
||||
{ 0x746E6543, 0x48727561, 0x736C7561}
|
||||
};
|
||||
|
||||
int x86cpuid_GetFirm(const Cx86cpuid *p)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < sizeof(kVendors) / sizeof(kVendors[i]); i++)
|
||||
{
|
||||
const UInt32 *v = kVendors[i];
|
||||
if (v[0] == p->vendor[0] &&
|
||||
v[1] == p->vendor[1] &&
|
||||
v[2] == p->vendor[2])
|
||||
return (int)i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
Bool CPU_Is_InOrder()
|
||||
{
|
||||
Cx86cpuid p;
|
||||
int firm;
|
||||
UInt32 family, model;
|
||||
if (!x86cpuid_CheckAndRead(&p))
|
||||
return True;
|
||||
|
||||
family = x86cpuid_GetFamily(p.ver);
|
||||
model = x86cpuid_GetModel(p.ver);
|
||||
|
||||
firm = x86cpuid_GetFirm(&p);
|
||||
|
||||
switch (firm)
|
||||
{
|
||||
case CPU_FIRM_INTEL: return (family < 6 || (family == 6 && (
|
||||
/* In-Order Atom CPU */
|
||||
model == 0x1C /* 45 nm, N4xx, D4xx, N5xx, D5xx, 230, 330 */
|
||||
|| model == 0x26 /* 45 nm, Z6xx */
|
||||
|| model == 0x27 /* 32 nm, Z2460 */
|
||||
|| model == 0x35 /* 32 nm, Z2760 */
|
||||
|| model == 0x36 /* 32 nm, N2xxx, D2xxx */
|
||||
)));
|
||||
case CPU_FIRM_AMD: return (family < 5 || (family == 5 && (model < 6 || model == 0xA)));
|
||||
case CPU_FIRM_VIA: return (family < 6 || (family == 6 && model < 0xF));
|
||||
}
|
||||
return True;
|
||||
}
|
||||
|
||||
#if !defined(MY_CPU_AMD64) && defined(_WIN32)
|
||||
#include <windows.h>
|
||||
static 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
|
||||
|
||||
#else
|
||||
|
||||
Bool CPU_Is_InOrder()
|
||||
{
|
||||
return True;
|
||||
}
|
||||
|
||||
#endif // ifdef _7ZIP_ASM
|
||||
|
226
C/CpuArch.h
Normal file
226
C/CpuArch.h
Normal file
@ -0,0 +1,226 @@
|
||||
/* CpuArch.h -- CPU specific code
|
||||
2015-12-01: Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __CPU_ARCH_H
|
||||
#define __CPU_ARCH_H
|
||||
|
||||
#include "7zTypes.h"
|
||||
|
||||
EXTERN_C_BEGIN
|
||||
|
||||
/*
|
||||
MY_CPU_LE means that CPU is LITTLE ENDIAN.
|
||||
MY_CPU_BE means that CPU is BIG ENDIAN.
|
||||
If MY_CPU_LE and MY_CPU_BE are not defined, we don't know about ENDIANNESS of platform.
|
||||
|
||||
MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned memory accesses.
|
||||
*/
|
||||
|
||||
#if defined(_M_X64) \
|
||||
|| defined(_M_AMD64) \
|
||||
|| defined(__x86_64__) \
|
||||
|| defined(__AMD64__) \
|
||||
|| defined(__amd64__)
|
||||
#define MY_CPU_AMD64
|
||||
#endif
|
||||
|
||||
#if defined(MY_CPU_AMD64) \
|
||||
|| defined(_M_IA64) \
|
||||
|| defined(__AARCH64EL__) \
|
||||
|| defined(__AARCH64EB__)
|
||||
#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) \
|
||||
|| defined(__ARMEL__) \
|
||||
|| defined(__THUMBEL__) \
|
||||
|| defined(__ARMEB__) \
|
||||
|| defined(__THUMBEB__)
|
||||
#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) \
|
||||
|| defined(MY_CPU_ARM_LE) \
|
||||
|| defined(MY_CPU_IA64_LE) \
|
||||
|| defined(__LITTLE_ENDIAN__) \
|
||||
|| defined(__ARMEL__) \
|
||||
|| defined(__THUMBEL__) \
|
||||
|| defined(__AARCH64EL__) \
|
||||
|| defined(__MIPSEL__) \
|
||||
|| defined(__MIPSEL) \
|
||||
|| defined(_MIPSEL) \
|
||||
|| (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
|
||||
#define MY_CPU_LE
|
||||
#endif
|
||||
|
||||
#if defined(__BIG_ENDIAN__) \
|
||||
|| defined(__ARMEB__) \
|
||||
|| defined(__THUMBEB__) \
|
||||
|| defined(__AARCH64EB__) \
|
||||
|| defined(__MIPSEB__) \
|
||||
|| defined(__MIPSEB) \
|
||||
|| defined(_MIPSEB) \
|
||||
|| defined(__m68k__) \
|
||||
|| defined(__s390__) \
|
||||
|| defined(__s390x__) \
|
||||
|| defined(__zarch__) \
|
||||
|| defined(__sparc) \
|
||||
|| (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
|
||||
#define MY_CPU_BE
|
||||
#endif
|
||||
|
||||
#if defined(MY_CPU_LE) && defined(MY_CPU_BE)
|
||||
Stop_Compiling_Bad_Endian
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef MY_CPU_LE
|
||||
#if defined(MY_CPU_X86_OR_AMD64) \
|
||||
/* || defined(__AARCH64EL__) */
|
||||
#define MY_CPU_LE_UNALIGN
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef MY_CPU_LE_UNALIGN
|
||||
|
||||
#define GetUi16(p) (*(const UInt16 *)(const void *)(p))
|
||||
#define GetUi32(p) (*(const UInt32 *)(const void *)(p))
|
||||
#define GetUi64(p) (*(const UInt64 *)(const void *)(p))
|
||||
|
||||
#define SetUi16(p, v) { *(UInt16 *)(p) = (v); }
|
||||
#define SetUi32(p, v) { *(UInt32 *)(p) = (v); }
|
||||
#define SetUi64(p, v) { *(UInt64 *)(p) = (v); }
|
||||
|
||||
#else
|
||||
|
||||
#define GetUi16(p) ( (UInt16) ( \
|
||||
((const Byte *)(p))[0] | \
|
||||
((UInt16)((const Byte *)(p))[1] << 8) ))
|
||||
|
||||
#define GetUi32(p) ( \
|
||||
((const Byte *)(p))[0] | \
|
||||
((UInt32)((const Byte *)(p))[1] << 8) | \
|
||||
((UInt32)((const Byte *)(p))[2] << 16) | \
|
||||
((UInt32)((const Byte *)(p))[3] << 24))
|
||||
|
||||
#define GetUi64(p) (GetUi32(p) | ((UInt64)GetUi32(((const Byte *)(p)) + 4) << 32))
|
||||
|
||||
#define SetUi16(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \
|
||||
_ppp_[0] = (Byte)_vvv_; \
|
||||
_ppp_[1] = (Byte)(_vvv_ >> 8); }
|
||||
|
||||
#define SetUi32(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \
|
||||
_ppp_[0] = (Byte)_vvv_; \
|
||||
_ppp_[1] = (Byte)(_vvv_ >> 8); \
|
||||
_ppp_[2] = (Byte)(_vvv_ >> 16); \
|
||||
_ppp_[3] = (Byte)(_vvv_ >> 24); }
|
||||
|
||||
#define SetUi64(p, v) { Byte *_ppp2_ = (Byte *)(p); UInt64 _vvv2_ = (v); \
|
||||
SetUi32(_ppp2_ , (UInt32)_vvv2_); \
|
||||
SetUi32(_ppp2_ + 4, (UInt32)(_vvv2_ >> 32)); }
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(MY_CPU_LE_UNALIGN) && /* defined(_WIN64) && */ (_MSC_VER >= 1300)
|
||||
|
||||
/* Note: we use bswap instruction, that is unsupported in 386 cpu */
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#pragma intrinsic(_byteswap_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))
|
||||
|
||||
#define SetBe32(p, v) (*(UInt32 *)(void *)(p)) = _byteswap_ulong(v)
|
||||
|
||||
#elif defined(MY_CPU_LE_UNALIGN) && defined (__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
|
||||
|
||||
#define GetBe32(p) __builtin_bswap32(*(const UInt32 *)(const Byte *)(p))
|
||||
#define GetBe64(p) __builtin_bswap64(*(const UInt64 *)(const Byte *)(p))
|
||||
|
||||
#define SetBe32(p, v) (*(UInt32 *)(void *)(p)) = __builtin_bswap32(v)
|
||||
|
||||
#else
|
||||
|
||||
#define GetBe32(p) ( \
|
||||
((UInt32)((const Byte *)(p))[0] << 24) | \
|
||||
((UInt32)((const Byte *)(p))[1] << 16) | \
|
||||
((UInt32)((const Byte *)(p))[2] << 8) | \
|
||||
((const Byte *)(p))[3] )
|
||||
|
||||
#define GetBe64(p) (((UInt64)GetBe32(p) << 32) | GetBe32(((const Byte *)(p)) + 4))
|
||||
|
||||
#define SetBe32(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \
|
||||
_ppp_[0] = (Byte)(_vvv_ >> 24); \
|
||||
_ppp_[1] = (Byte)(_vvv_ >> 16); \
|
||||
_ppp_[2] = (Byte)(_vvv_ >> 8); \
|
||||
_ppp_[3] = (Byte)_vvv_; }
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#define GetBe16(p) ( (UInt16) ( \
|
||||
((UInt16)((const Byte *)(p))[0] << 8) | \
|
||||
((const Byte *)(p))[1] ))
|
||||
|
||||
|
||||
|
||||
#ifdef MY_CPU_X86_OR_AMD64
|
||||
#ifdef _7ZIP_ASM
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UInt32 maxFunc;
|
||||
UInt32 vendor[3];
|
||||
UInt32 ver;
|
||||
UInt32 b;
|
||||
UInt32 c;
|
||||
UInt32 d;
|
||||
} Cx86cpuid;
|
||||
|
||||
enum
|
||||
{
|
||||
CPU_FIRM_INTEL,
|
||||
CPU_FIRM_AMD,
|
||||
CPU_FIRM_VIA
|
||||
};
|
||||
|
||||
void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d);
|
||||
|
||||
Bool x86cpuid_CheckAndRead(Cx86cpuid *p);
|
||||
int x86cpuid_GetFirm(const Cx86cpuid *p);
|
||||
|
||||
#define x86cpuid_GetFamily(ver) (((ver >> 16) & 0xFF0) | ((ver >> 8) & 0xF))
|
||||
#define x86cpuid_GetModel(ver) (((ver >> 12) & 0xF0) | ((ver >> 4) & 0xF))
|
||||
#define x86cpuid_GetStepping(ver) (ver & 0xF)
|
||||
|
||||
#endif
|
||||
|
||||
Bool CPU_Is_InOrder();
|
||||
Bool CPU_Is_Aes_Supported();
|
||||
|
||||
#endif
|
||||
|
||||
EXTERN_C_END
|
||||
|
||||
#endif
|
64
C/Delta.c
Normal file
64
C/Delta.c
Normal file
@ -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);
|
||||
}
|
19
C/Delta.h
Normal file
19
C/Delta.h
Normal file
@ -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
|
148
C/HuffEnc.c
Normal file
148
C/HuffEnc.c
Normal file
@ -0,0 +1,148 @@
|
||||
/* HuffEnc.c -- functions for Huffman encoding
|
||||
2016-05-16 : Igor Pavlov : Public domain */
|
||||
|
||||
#include "Precomp.h"
|
||||
|
||||
#include "HuffEnc.h"
|
||||
#include "Sort.h"
|
||||
|
||||
#define kMaxLen 16
|
||||
#define NUM_BITS 10
|
||||
#define MASK ((1 << NUM_BITS) - 1)
|
||||
|
||||
#define NUM_COUNTERS 64
|
||||
|
||||
#define HUFFMAN_SPEED_OPT
|
||||
|
||||
void Huffman_Generate(const UInt32 *freqs, UInt32 *p, Byte *lens, UInt32 numSymbols, UInt32 maxLen)
|
||||
{
|
||||
UInt32 num = 0;
|
||||
/* if (maxLen > 10) maxLen = 10; */
|
||||
{
|
||||
UInt32 i;
|
||||
|
||||
#ifdef HUFFMAN_SPEED_OPT
|
||||
|
||||
UInt32 counters[NUM_COUNTERS];
|
||||
for (i = 0; i < NUM_COUNTERS; i++)
|
||||
counters[i] = 0;
|
||||
for (i = 0; i < numSymbols; i++)
|
||||
{
|
||||
UInt32 freq = freqs[i];
|
||||
counters[(freq < NUM_COUNTERS - 1) ? freq : NUM_COUNTERS - 1]++;
|
||||
}
|
||||
|
||||
for (i = 1; i < NUM_COUNTERS; i++)
|
||||
{
|
||||
UInt32 temp = counters[i];
|
||||
counters[i] = num;
|
||||
num += temp;
|
||||
}
|
||||
|
||||
for (i = 0; i < numSymbols; i++)
|
||||
{
|
||||
UInt32 freq = freqs[i];
|
||||
if (freq == 0)
|
||||
lens[i] = 0;
|
||||
else
|
||||
p[counters[((freq < NUM_COUNTERS - 1) ? freq : NUM_COUNTERS - 1)]++] = i | (freq << NUM_BITS);
|
||||
}
|
||||
counters[0] = 0;
|
||||
HeapSort(p + counters[NUM_COUNTERS - 2], counters[NUM_COUNTERS - 1] - counters[NUM_COUNTERS - 2]);
|
||||
|
||||
#else
|
||||
|
||||
for (i = 0; i < numSymbols; i++)
|
||||
{
|
||||
UInt32 freq = freqs[i];
|
||||
if (freq == 0)
|
||||
lens[i] = 0;
|
||||
else
|
||||
p[num++] = i | (freq << NUM_BITS);
|
||||
}
|
||||
HeapSort(p, num);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
if (num < 2)
|
||||
{
|
||||
unsigned minCode = 0;
|
||||
unsigned maxCode = 1;
|
||||
if (num == 1)
|
||||
{
|
||||
maxCode = (unsigned)p[0] & MASK;
|
||||
if (maxCode == 0)
|
||||
maxCode++;
|
||||
}
|
||||
p[minCode] = 0;
|
||||
p[maxCode] = 1;
|
||||
lens[minCode] = lens[maxCode] = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
UInt32 b, e, i;
|
||||
|
||||
i = b = e = 0;
|
||||
do
|
||||
{
|
||||
UInt32 n, m, freq;
|
||||
n = (i != num && (b == e || (p[i] >> NUM_BITS) <= (p[b] >> NUM_BITS))) ? i++ : b++;
|
||||
freq = (p[n] & ~MASK);
|
||||
p[n] = (p[n] & MASK) | (e << NUM_BITS);
|
||||
m = (i != num && (b == e || (p[i] >> NUM_BITS) <= (p[b] >> NUM_BITS))) ? i++ : b++;
|
||||
freq += (p[m] & ~MASK);
|
||||
p[m] = (p[m] & MASK) | (e << NUM_BITS);
|
||||
p[e] = (p[e] & MASK) | freq;
|
||||
e++;
|
||||
}
|
||||
while (num - e > 1);
|
||||
|
||||
{
|
||||
UInt32 lenCounters[kMaxLen + 1];
|
||||
for (i = 0; i <= kMaxLen; i++)
|
||||
lenCounters[i] = 0;
|
||||
|
||||
p[--e] &= MASK;
|
||||
lenCounters[1] = 2;
|
||||
while (e > 0)
|
||||
{
|
||||
UInt32 len = (p[p[--e] >> NUM_BITS] >> NUM_BITS) + 1;
|
||||
p[e] = (p[e] & MASK) | (len << NUM_BITS);
|
||||
if (len >= maxLen)
|
||||
for (len = maxLen - 1; lenCounters[len] == 0; len--);
|
||||
lenCounters[len]--;
|
||||
lenCounters[len + 1] += 2;
|
||||
}
|
||||
|
||||
{
|
||||
UInt32 len;
|
||||
i = 0;
|
||||
for (len = maxLen; len != 0; len--)
|
||||
{
|
||||
UInt32 k;
|
||||
for (k = lenCounters[len]; k != 0; k--)
|
||||
lens[p[i++] & MASK] = (Byte)len;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
UInt32 nextCodes[kMaxLen + 1];
|
||||
{
|
||||
UInt32 code = 0;
|
||||
UInt32 len;
|
||||
for (len = 1; len <= kMaxLen; len++)
|
||||
nextCodes[len] = code = (code + lenCounters[len - 1]) << 1;
|
||||
}
|
||||
/* if (code + lenCounters[kMaxLen] - 1 != (1 << kMaxLen) - 1) throw 1; */
|
||||
|
||||
{
|
||||
UInt32 k;
|
||||
for (k = 0; k < numSymbols; k++)
|
||||
p[k] = nextCodes[lens[k]]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
23
C/HuffEnc.h
Normal file
23
C/HuffEnc.h
Normal file
@ -0,0 +1,23 @@
|
||||
/* HuffEnc.h -- Huffman encoding
|
||||
2013-01-18 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __HUFF_ENC_H
|
||||
#define __HUFF_ENC_H
|
||||
|
||||
#include "7zTypes.h"
|
||||
|
||||
EXTERN_C_BEGIN
|
||||
|
||||
/*
|
||||
Conditions:
|
||||
num <= 1024 = 2 ^ NUM_BITS
|
||||
Sum(freqs) < 4M = 2 ^ (32 - NUM_BITS)
|
||||
maxLen <= 16 = kMaxLen
|
||||
Num_Items(p) >= HUFFMAN_TEMP_SIZE(num)
|
||||
*/
|
||||
|
||||
void Huffman_Generate(const UInt32 *freqs, UInt32 *p, Byte *lens, UInt32 num, UInt32 maxLen);
|
||||
|
||||
EXTERN_C_END
|
||||
|
||||
#endif
|
1044
C/LzFind.c
Normal file
1044
C/LzFind.c
Normal file
File diff suppressed because it is too large
Load Diff
117
C/LzFind.h
Normal file
117
C/LzFind.h
Normal file
@ -0,0 +1,117 @@
|
||||
/* LzFind.h -- Match finder for LZ algorithms
|
||||
2015-10-15 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __LZ_FIND_H
|
||||
#define __LZ_FIND_H
|
||||
|
||||
#include "7zTypes.h"
|
||||
|
||||
EXTERN_C_BEGIN
|
||||
|
||||
typedef UInt32 CLzRef;
|
||||
|
||||
typedef struct _CMatchFinder
|
||||
{
|
||||
Byte *buffer;
|
||||
UInt32 pos;
|
||||
UInt32 posLimit;
|
||||
UInt32 streamPos;
|
||||
UInt32 lenLimit;
|
||||
|
||||
UInt32 cyclicBufferPos;
|
||||
UInt32 cyclicBufferSize; /* it must be = (historySize + 1) */
|
||||
|
||||
Byte streamEndWasReached;
|
||||
Byte btMode;
|
||||
Byte bigHash;
|
||||
Byte directInput;
|
||||
|
||||
UInt32 matchMaxLen;
|
||||
CLzRef *hash;
|
||||
CLzRef *son;
|
||||
UInt32 hashMask;
|
||||
UInt32 cutValue;
|
||||
|
||||
Byte *bufferBase;
|
||||
ISeqInStream *stream;
|
||||
|
||||
UInt32 blockSize;
|
||||
UInt32 keepSizeBefore;
|
||||
UInt32 keepSizeAfter;
|
||||
|
||||
UInt32 numHashBytes;
|
||||
size_t directInputRem;
|
||||
UInt32 historySize;
|
||||
UInt32 fixedHashSize;
|
||||
UInt32 hashSizeSum;
|
||||
SRes result;
|
||||
UInt32 crc[256];
|
||||
size_t numRefs;
|
||||
} CMatchFinder;
|
||||
|
||||
#define Inline_MatchFinder_GetPointerToCurrentPos(p) ((p)->buffer)
|
||||
|
||||
#define Inline_MatchFinder_GetNumAvailableBytes(p) ((p)->streamPos - (p)->pos)
|
||||
|
||||
#define Inline_MatchFinder_IsFinishedOK(p) \
|
||||
((p)->streamEndWasReached \
|
||||
&& (p)->streamPos == (p)->pos \
|
||||
&& (!(p)->directInput || (p)->directInputRem == 0))
|
||||
|
||||
int MatchFinder_NeedMove(CMatchFinder *p);
|
||||
Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p);
|
||||
void MatchFinder_MoveBlock(CMatchFinder *p);
|
||||
void MatchFinder_ReadIfRequired(CMatchFinder *p);
|
||||
|
||||
void MatchFinder_Construct(CMatchFinder *p);
|
||||
|
||||
/* Conditions:
|
||||
historySize <= 3 GB
|
||||
keepAddBufferBefore + matchMaxLen + keepAddBufferAfter < 511MB
|
||||
*/
|
||||
int MatchFinder_Create(CMatchFinder *p, UInt32 historySize,
|
||||
UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
|
||||
ISzAlloc *alloc);
|
||||
void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc);
|
||||
void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, size_t numItems);
|
||||
void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue);
|
||||
|
||||
UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son,
|
||||
UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue,
|
||||
UInt32 *distances, UInt32 maxLen);
|
||||
|
||||
/*
|
||||
Conditions:
|
||||
Mf_GetNumAvailableBytes_Func must be called before each Mf_GetMatchLen_Func.
|
||||
Mf_GetPointerToCurrentPos_Func's result must be used only before any other function
|
||||
*/
|
||||
|
||||
typedef void (*Mf_Init_Func)(void *object);
|
||||
typedef UInt32 (*Mf_GetNumAvailableBytes_Func)(void *object);
|
||||
typedef const Byte * (*Mf_GetPointerToCurrentPos_Func)(void *object);
|
||||
typedef UInt32 (*Mf_GetMatches_Func)(void *object, UInt32 *distances);
|
||||
typedef void (*Mf_Skip_Func)(void *object, UInt32);
|
||||
|
||||
typedef struct _IMatchFinder
|
||||
{
|
||||
Mf_Init_Func Init;
|
||||
Mf_GetNumAvailableBytes_Func GetNumAvailableBytes;
|
||||
Mf_GetPointerToCurrentPos_Func GetPointerToCurrentPos;
|
||||
Mf_GetMatches_Func GetMatches;
|
||||
Mf_Skip_Func Skip;
|
||||
} IMatchFinder;
|
||||
|
||||
void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable);
|
||||
|
||||
void MatchFinder_Init_2(CMatchFinder *p, int readData);
|
||||
void MatchFinder_Init(CMatchFinder *p);
|
||||
|
||||
UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
|
||||
UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
|
||||
|
||||
void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
|
||||
void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
|
||||
|
||||
EXTERN_C_END
|
||||
|
||||
#endif
|
803
C/LzFindMt.c
Normal file
803
C/LzFindMt.c
Normal file
@ -0,0 +1,803 @@
|
||||
/* LzFindMt.c -- multithreaded Match finder for LZ algorithms
|
||||
2015-10-15 : Igor Pavlov : Public domain */
|
||||
|
||||
#include "Precomp.h"
|
||||
|
||||
#include "LzHash.h"
|
||||
|
||||
#include "LzFindMt.h"
|
||||
|
||||
static void MtSync_Construct(CMtSync *p)
|
||||
{
|
||||
p->wasCreated = False;
|
||||
p->csWasInitialized = False;
|
||||
p->csWasEntered = False;
|
||||
Thread_Construct(&p->thread);
|
||||
Event_Construct(&p->canStart);
|
||||
Event_Construct(&p->wasStarted);
|
||||
Event_Construct(&p->wasStopped);
|
||||
Semaphore_Construct(&p->freeSemaphore);
|
||||
Semaphore_Construct(&p->filledSemaphore);
|
||||
}
|
||||
|
||||
static void MtSync_GetNextBlock(CMtSync *p)
|
||||
{
|
||||
if (p->needStart)
|
||||
{
|
||||
p->numProcessedBlocks = 1;
|
||||
p->needStart = False;
|
||||
p->stopWriting = False;
|
||||
p->exit = False;
|
||||
Event_Reset(&p->wasStarted);
|
||||
Event_Reset(&p->wasStopped);
|
||||
|
||||
Event_Set(&p->canStart);
|
||||
Event_Wait(&p->wasStarted);
|
||||
}
|
||||
else
|
||||
{
|
||||
CriticalSection_Leave(&p->cs);
|
||||
p->csWasEntered = False;
|
||||
p->numProcessedBlocks++;
|
||||
Semaphore_Release1(&p->freeSemaphore);
|
||||
}
|
||||
Semaphore_Wait(&p->filledSemaphore);
|
||||
CriticalSection_Enter(&p->cs);
|
||||
p->csWasEntered = True;
|
||||
}
|
||||
|
||||
/* MtSync_StopWriting must be called if Writing was started */
|
||||
|
||||
static void MtSync_StopWriting(CMtSync *p)
|
||||
{
|
||||
UInt32 myNumBlocks = p->numProcessedBlocks;
|
||||
if (!Thread_WasCreated(&p->thread) || p->needStart)
|
||||
return;
|
||||
p->stopWriting = True;
|
||||
if (p->csWasEntered)
|
||||
{
|
||||
CriticalSection_Leave(&p->cs);
|
||||
p->csWasEntered = False;
|
||||
}
|
||||
Semaphore_Release1(&p->freeSemaphore);
|
||||
|
||||
Event_Wait(&p->wasStopped);
|
||||
|
||||
while (myNumBlocks++ != p->numProcessedBlocks)
|
||||
{
|
||||
Semaphore_Wait(&p->filledSemaphore);
|
||||
Semaphore_Release1(&p->freeSemaphore);
|
||||
}
|
||||
p->needStart = True;
|
||||
}
|
||||
|
||||
static void MtSync_Destruct(CMtSync *p)
|
||||
{
|
||||
if (Thread_WasCreated(&p->thread))
|
||||
{
|
||||
MtSync_StopWriting(p);
|
||||
p->exit = True;
|
||||
if (p->needStart)
|
||||
Event_Set(&p->canStart);
|
||||
Thread_Wait(&p->thread);
|
||||
Thread_Close(&p->thread);
|
||||
}
|
||||
if (p->csWasInitialized)
|
||||
{
|
||||
CriticalSection_Delete(&p->cs);
|
||||
p->csWasInitialized = False;
|
||||
}
|
||||
|
||||
Event_Close(&p->canStart);
|
||||
Event_Close(&p->wasStarted);
|
||||
Event_Close(&p->wasStopped);
|
||||
Semaphore_Close(&p->freeSemaphore);
|
||||
Semaphore_Close(&p->filledSemaphore);
|
||||
|
||||
p->wasCreated = False;
|
||||
}
|
||||
|
||||
#define RINOK_THREAD(x) { if ((x) != 0) return SZ_ERROR_THREAD; }
|
||||
|
||||
static SRes MtSync_Create2(CMtSync *p, THREAD_FUNC_TYPE startAddress, void *obj, UInt32 numBlocks)
|
||||
{
|
||||
if (p->wasCreated)
|
||||
return SZ_OK;
|
||||
|
||||
RINOK_THREAD(CriticalSection_Init(&p->cs));
|
||||
p->csWasInitialized = True;
|
||||
|
||||
RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->canStart));
|
||||
RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->wasStarted));
|
||||
RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->wasStopped));
|
||||
|
||||
RINOK_THREAD(Semaphore_Create(&p->freeSemaphore, numBlocks, numBlocks));
|
||||
RINOK_THREAD(Semaphore_Create(&p->filledSemaphore, 0, numBlocks));
|
||||
|
||||
p->needStart = True;
|
||||
|
||||
RINOK_THREAD(Thread_Create(&p->thread, startAddress, obj));
|
||||
p->wasCreated = True;
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
static SRes MtSync_Create(CMtSync *p, THREAD_FUNC_TYPE startAddress, void *obj, UInt32 numBlocks)
|
||||
{
|
||||
SRes res = MtSync_Create2(p, startAddress, obj, numBlocks);
|
||||
if (res != SZ_OK)
|
||||
MtSync_Destruct(p);
|
||||
return res;
|
||||
}
|
||||
|
||||
void MtSync_Init(CMtSync *p) { p->needStart = True; }
|
||||
|
||||
#define kMtMaxValForNormalize 0xFFFFFFFF
|
||||
|
||||
#define DEF_GetHeads2(name, v, action) \
|
||||
static void GetHeads ## name(const Byte *p, UInt32 pos, \
|
||||
UInt32 *hash, UInt32 hashMask, UInt32 *heads, UInt32 numHeads, const UInt32 *crc) \
|
||||
{ action; for (; numHeads != 0; numHeads--) { \
|
||||
const UInt32 value = (v); p++; *heads++ = pos - hash[value]; hash[value] = pos++; } }
|
||||
|
||||
#define DEF_GetHeads(name, v) DEF_GetHeads2(name, v, ;)
|
||||
|
||||
DEF_GetHeads2(2, (p[0] | ((UInt32)p[1] << 8)), UNUSED_VAR(hashMask); UNUSED_VAR(crc); )
|
||||
DEF_GetHeads(3, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8)) & hashMask)
|
||||
DEF_GetHeads(4, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ (crc[p[3]] << 5)) & hashMask)
|
||||
DEF_GetHeads(4b, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ ((UInt32)p[3] << 16)) & hashMask)
|
||||
/* DEF_GetHeads(5, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ (crc[p[3]] << 5) ^ (crc[p[4]] << 3)) & hashMask) */
|
||||
|
||||
static void HashThreadFunc(CMatchFinderMt *mt)
|
||||
{
|
||||
CMtSync *p = &mt->hashSync;
|
||||
for (;;)
|
||||
{
|
||||
UInt32 numProcessedBlocks = 0;
|
||||
Event_Wait(&p->canStart);
|
||||
Event_Set(&p->wasStarted);
|
||||
for (;;)
|
||||
{
|
||||
if (p->exit)
|
||||
return;
|
||||
if (p->stopWriting)
|
||||
{
|
||||
p->numProcessedBlocks = numProcessedBlocks;
|
||||
Event_Set(&p->wasStopped);
|
||||
break;
|
||||
}
|
||||
|
||||
{
|
||||
CMatchFinder *mf = mt->MatchFinder;
|
||||
if (MatchFinder_NeedMove(mf))
|
||||
{
|
||||
CriticalSection_Enter(&mt->btSync.cs);
|
||||
CriticalSection_Enter(&mt->hashSync.cs);
|
||||
{
|
||||
const Byte *beforePtr = Inline_MatchFinder_GetPointerToCurrentPos(mf);
|
||||
ptrdiff_t offset;
|
||||
MatchFinder_MoveBlock(mf);
|
||||
offset = beforePtr - Inline_MatchFinder_GetPointerToCurrentPos(mf);
|
||||
mt->pointerToCurPos -= offset;
|
||||
mt->buffer -= offset;
|
||||
}
|
||||
CriticalSection_Leave(&mt->btSync.cs);
|
||||
CriticalSection_Leave(&mt->hashSync.cs);
|
||||
continue;
|
||||
}
|
||||
|
||||
Semaphore_Wait(&p->freeSemaphore);
|
||||
|
||||
MatchFinder_ReadIfRequired(mf);
|
||||
if (mf->pos > (kMtMaxValForNormalize - kMtHashBlockSize))
|
||||
{
|
||||
UInt32 subValue = (mf->pos - mf->historySize - 1);
|
||||
MatchFinder_ReduceOffsets(mf, subValue);
|
||||
MatchFinder_Normalize3(subValue, mf->hash + mf->fixedHashSize, (size_t)mf->hashMask + 1);
|
||||
}
|
||||
{
|
||||
UInt32 *heads = mt->hashBuf + ((numProcessedBlocks++) & kMtHashNumBlocksMask) * kMtHashBlockSize;
|
||||
UInt32 num = mf->streamPos - mf->pos;
|
||||
heads[0] = 2;
|
||||
heads[1] = num;
|
||||
if (num >= mf->numHashBytes)
|
||||
{
|
||||
num = num - mf->numHashBytes + 1;
|
||||
if (num > kMtHashBlockSize - 2)
|
||||
num = kMtHashBlockSize - 2;
|
||||
mt->GetHeadsFunc(mf->buffer, mf->pos, mf->hash + mf->fixedHashSize, mf->hashMask, heads + 2, num, mf->crc);
|
||||
heads[0] += num;
|
||||
}
|
||||
mf->pos += num;
|
||||
mf->buffer += num;
|
||||
}
|
||||
}
|
||||
|
||||
Semaphore_Release1(&p->filledSemaphore);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void MatchFinderMt_GetNextBlock_Hash(CMatchFinderMt *p)
|
||||
{
|
||||
MtSync_GetNextBlock(&p->hashSync);
|
||||
p->hashBufPosLimit = p->hashBufPos = ((p->hashSync.numProcessedBlocks - 1) & kMtHashNumBlocksMask) * kMtHashBlockSize;
|
||||
p->hashBufPosLimit += p->hashBuf[p->hashBufPos++];
|
||||
p->hashNumAvail = p->hashBuf[p->hashBufPos++];
|
||||
}
|
||||
|
||||
#define kEmptyHashValue 0
|
||||
|
||||
/* #define MFMT_GM_INLINE */
|
||||
|
||||
#ifdef MFMT_GM_INLINE
|
||||
|
||||
#define NO_INLINE MY_FAST_CALL
|
||||
|
||||
static 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
|
||||
|
||||
static 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;
|
||||
distances[0] = curPos + p->hashNumAvail;
|
||||
distances += curPos;
|
||||
for (; p->hashNumAvail != 0; p->hashNumAvail--)
|
||||
*distances++ = 0;
|
||||
return;
|
||||
}
|
||||
{
|
||||
UInt32 size = p->hashBufPosLimit - p->hashBufPos;
|
||||
UInt32 lenLimit = p->matchMaxLen;
|
||||
UInt32 pos = p->pos;
|
||||
UInt32 cyclicBufferPos = p->cyclicBufferPos;
|
||||
if (lenLimit >= p->hashNumAvail)
|
||||
lenLimit = p->hashNumAvail;
|
||||
{
|
||||
UInt32 size2 = p->hashNumAvail - lenLimit + 1;
|
||||
if (size2 < size)
|
||||
size = size2;
|
||||
size2 = p->cyclicBufferSize - cyclicBufferPos;
|
||||
if (size2 < size)
|
||||
size = size2;
|
||||
}
|
||||
|
||||
#ifndef MFMT_GM_INLINE
|
||||
while (curPos < limit && size-- != 0)
|
||||
{
|
||||
UInt32 *startDistances = distances + curPos;
|
||||
UInt32 num = (UInt32)(GetMatchesSpec1(lenLimit, pos - p->hashBuf[p->hashBufPos++],
|
||||
pos, p->buffer, p->son, cyclicBufferPos, p->cyclicBufferSize, p->cutValue,
|
||||
startDistances + 1, p->numHashBytes - 1) - startDistances);
|
||||
*startDistances = num - 1;
|
||||
curPos += num;
|
||||
cyclicBufferPos++;
|
||||
pos++;
|
||||
p->buffer++;
|
||||
}
|
||||
#else
|
||||
{
|
||||
UInt32 posRes;
|
||||
curPos = 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;
|
||||
}
|
||||
|
||||
static void BtFillBlock(CMatchFinderMt *p, UInt32 globalBlockIndex)
|
||||
{
|
||||
CMtSync *sync = &p->hashSync;
|
||||
if (!sync->needStart)
|
||||
{
|
||||
CriticalSection_Enter(&sync->cs);
|
||||
sync->csWasEntered = True;
|
||||
}
|
||||
|
||||
BtGetMatches(p, p->btBuf + (globalBlockIndex & kMtBtNumBlocksMask) * kMtBtBlockSize);
|
||||
|
||||
if (p->pos > kMtMaxValForNormalize - kMtBtBlockSize)
|
||||
{
|
||||
UInt32 subValue = p->pos - p->cyclicBufferSize;
|
||||
MatchFinder_Normalize3(subValue, p->son, (size_t)p->cyclicBufferSize * 2);
|
||||
p->pos -= subValue;
|
||||
}
|
||||
|
||||
if (!sync->needStart)
|
||||
{
|
||||
CriticalSection_Leave(&sync->cs);
|
||||
sync->csWasEntered = False;
|
||||
}
|
||||
}
|
||||
|
||||
void BtThreadFunc(CMatchFinderMt *mt)
|
||||
{
|
||||
CMtSync *p = &mt->btSync;
|
||||
for (;;)
|
||||
{
|
||||
UInt32 blockIndex = 0;
|
||||
Event_Wait(&p->canStart);
|
||||
Event_Set(&p->wasStarted);
|
||||
for (;;)
|
||||
{
|
||||
if (p->exit)
|
||||
return;
|
||||
if (p->stopWriting)
|
||||
{
|
||||
p->numProcessedBlocks = blockIndex;
|
||||
MtSync_StopWriting(&mt->hashSync);
|
||||
Event_Set(&p->wasStopped);
|
||||
break;
|
||||
}
|
||||
Semaphore_Wait(&p->freeSemaphore);
|
||||
BtFillBlock(mt, blockIndex++);
|
||||
Semaphore_Release1(&p->filledSemaphore);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MatchFinderMt_Construct(CMatchFinderMt *p)
|
||||
{
|
||||
p->hashBuf = NULL;
|
||||
MtSync_Construct(&p->hashSync);
|
||||
MtSync_Construct(&p->btSync);
|
||||
}
|
||||
|
||||
static void MatchFinderMt_FreeMem(CMatchFinderMt *p, ISzAlloc *alloc)
|
||||
{
|
||||
alloc->Free(alloc, p->hashBuf);
|
||||
p->hashBuf = NULL;
|
||||
}
|
||||
|
||||
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];
|
||||
unsigned i = 0;
|
||||
for (i = 0; i < 16; i++)
|
||||
allocaDummy[i] = (Byte)0;
|
||||
if (allocaDummy[0] == 0)
|
||||
BtThreadFunc((CMatchFinderMt *)p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SRes MatchFinderMt_Create(CMatchFinderMt *p, UInt32 historySize, UInt32 keepAddBufferBefore,
|
||||
UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ISzAlloc *alloc)
|
||||
{
|
||||
CMatchFinder *mf = p->MatchFinder;
|
||||
p->historySize = historySize;
|
||||
if (kMtBtBlockSize <= matchMaxLen * 4)
|
||||
return SZ_ERROR_PARAM;
|
||||
if (!p->hashBuf)
|
||||
{
|
||||
p->hashBuf = (UInt32 *)alloc->Alloc(alloc, (kHashBufferSize + kBtBufferSize) * sizeof(UInt32));
|
||||
if (!p->hashBuf)
|
||||
return SZ_ERROR_MEM;
|
||||
p->btBuf = p->hashBuf + kHashBufferSize;
|
||||
}
|
||||
keepAddBufferBefore += (kHashBufferSize + kBtBufferSize);
|
||||
keepAddBufferAfter += kMtHashBlockSize;
|
||||
if (!MatchFinder_Create(mf, historySize, keepAddBufferBefore, matchMaxLen, keepAddBufferAfter, alloc))
|
||||
return SZ_ERROR_MEM;
|
||||
|
||||
RINOK(MtSync_Create(&p->hashSync, HashThreadFunc2, p, kMtHashNumBlocks));
|
||||
RINOK(MtSync_Create(&p->btSync, BtThreadFunc2, p, kMtBtNumBlocks));
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
/* Call it after ReleaseStream / SetStream */
|
||||
void MatchFinderMt_Init(CMatchFinderMt *p)
|
||||
{
|
||||
CMatchFinder *mf = p->MatchFinder;
|
||||
p->btBufPos = p->btBufPosLimit = 0;
|
||||
p->hashBufPos = p->hashBufPosLimit = 0;
|
||||
|
||||
/* Init without data reading. We don't want to read data in this thread */
|
||||
MatchFinder_Init_2(mf, False);
|
||||
|
||||
p->pointerToCurPos = Inline_MatchFinder_GetPointerToCurrentPos(mf);
|
||||
p->btNumAvailBytes = 0;
|
||||
p->lzPos = p->historySize + 1;
|
||||
|
||||
p->hash = mf->hash;
|
||||
p->fixedHashSize = mf->fixedHashSize;
|
||||
p->crc = mf->crc;
|
||||
|
||||
p->son = mf->son;
|
||||
p->matchMaxLen = mf->matchMaxLen;
|
||||
p->numHashBytes = mf->numHashBytes;
|
||||
p->pos = mf->pos;
|
||||
p->buffer = mf->buffer;
|
||||
p->cyclicBufferPos = mf->cyclicBufferPos;
|
||||
p->cyclicBufferSize = mf->cyclicBufferSize;
|
||||
p->cutValue = mf->cutValue;
|
||||
}
|
||||
|
||||
/* ReleaseStream is required to finish multithreading */
|
||||
void MatchFinderMt_ReleaseStream(CMatchFinderMt *p)
|
||||
{
|
||||
MtSync_StopWriting(&p->btSync);
|
||||
/* p->MatchFinder->ReleaseStream(); */
|
||||
}
|
||||
|
||||
static void MatchFinderMt_Normalize(CMatchFinderMt *p)
|
||||
{
|
||||
MatchFinder_Normalize3(p->lzPos - p->historySize - 1, p->hash, p->fixedHashSize);
|
||||
p->lzPos = p->historySize + 1;
|
||||
}
|
||||
|
||||
static void MatchFinderMt_GetNextBlock_Bt(CMatchFinderMt *p)
|
||||
{
|
||||
UInt32 blockIndex;
|
||||
MtSync_GetNextBlock(&p->btSync);
|
||||
blockIndex = ((p->btSync.numProcessedBlocks - 1) & kMtBtNumBlocksMask);
|
||||
p->btBufPosLimit = p->btBufPos = blockIndex * kMtBtBlockSize;
|
||||
p->btBufPosLimit += p->btBuf[p->btBufPos++];
|
||||
p->btNumAvailBytes = p->btBuf[p->btBufPos++];
|
||||
if (p->lzPos >= kMtMaxValForNormalize - kMtBtBlockSize)
|
||||
MatchFinderMt_Normalize(p);
|
||||
}
|
||||
|
||||
static const Byte * MatchFinderMt_GetPointerToCurrentPos(CMatchFinderMt *p)
|
||||
{
|
||||
return p->pointerToCurPos;
|
||||
}
|
||||
|
||||
#define GET_NEXT_BLOCK_IF_REQUIRED if (p->btBufPos == p->btBufPosLimit) MatchFinderMt_GetNextBlock_Bt(p);
|
||||
|
||||
static UInt32 MatchFinderMt_GetNumAvailableBytes(CMatchFinderMt *p)
|
||||
{
|
||||
GET_NEXT_BLOCK_IF_REQUIRED;
|
||||
return p->btNumAvailBytes;
|
||||
}
|
||||
|
||||
static UInt32 * MixMatches2(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances)
|
||||
{
|
||||
UInt32 h2, curMatch2;
|
||||
UInt32 *hash = p->hash;
|
||||
const Byte *cur = p->pointerToCurPos;
|
||||
UInt32 lzPos = p->lzPos;
|
||||
MT_HASH2_CALC
|
||||
|
||||
curMatch2 = hash[h2];
|
||||
hash[h2] = lzPos;
|
||||
|
||||
if (curMatch2 >= matchMinPos)
|
||||
if (cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0])
|
||||
{
|
||||
*distances++ = 2;
|
||||
*distances++ = lzPos - curMatch2 - 1;
|
||||
}
|
||||
|
||||
return distances;
|
||||
}
|
||||
|
||||
static UInt32 * MixMatches3(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances)
|
||||
{
|
||||
UInt32 h2, h3, curMatch2, curMatch3;
|
||||
UInt32 *hash = p->hash;
|
||||
const Byte *cur = p->pointerToCurPos;
|
||||
UInt32 lzPos = p->lzPos;
|
||||
MT_HASH3_CALC
|
||||
|
||||
curMatch2 = hash[ h2];
|
||||
curMatch3 = hash[kFix3HashSize + h3];
|
||||
|
||||
hash[ h2] = lzPos;
|
||||
hash[kFix3HashSize + h3] = lzPos;
|
||||
|
||||
if (curMatch2 >= matchMinPos && cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0])
|
||||
{
|
||||
distances[1] = lzPos - curMatch2 - 1;
|
||||
if (cur[(ptrdiff_t)curMatch2 - lzPos + 2] == cur[2])
|
||||
{
|
||||
distances[0] = 3;
|
||||
return distances + 2;
|
||||
}
|
||||
distances[0] = 2;
|
||||
distances += 2;
|
||||
}
|
||||
|
||||
if (curMatch3 >= matchMinPos && cur[(ptrdiff_t)curMatch3 - lzPos] == cur[0])
|
||||
{
|
||||
*distances++ = 3;
|
||||
*distances++ = lzPos - curMatch3 - 1;
|
||||
}
|
||||
|
||||
return distances;
|
||||
}
|
||||
|
||||
/*
|
||||
static UInt32 *MixMatches4(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances)
|
||||
{
|
||||
UInt32 h2, h3, h4, curMatch2, curMatch3, curMatch4;
|
||||
UInt32 *hash = p->hash;
|
||||
const Byte *cur = p->pointerToCurPos;
|
||||
UInt32 lzPos = p->lzPos;
|
||||
MT_HASH4_CALC
|
||||
|
||||
curMatch2 = hash[ h2];
|
||||
curMatch3 = hash[kFix3HashSize + h3];
|
||||
curMatch4 = hash[kFix4HashSize + h4];
|
||||
|
||||
hash[ h2] = lzPos;
|
||||
hash[kFix3HashSize + h3] = lzPos;
|
||||
hash[kFix4HashSize + h4] = lzPos;
|
||||
|
||||
if (curMatch2 >= matchMinPos && cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0])
|
||||
{
|
||||
distances[1] = lzPos - curMatch2 - 1;
|
||||
if (cur[(ptrdiff_t)curMatch2 - lzPos + 2] == cur[2])
|
||||
{
|
||||
distances[0] = (cur[(ptrdiff_t)curMatch2 - lzPos + 3] == cur[3]) ? 4 : 3;
|
||||
return distances + 2;
|
||||
}
|
||||
distances[0] = 2;
|
||||
distances += 2;
|
||||
}
|
||||
|
||||
if (curMatch3 >= matchMinPos && cur[(ptrdiff_t)curMatch3 - lzPos] == cur[0])
|
||||
{
|
||||
distances[1] = lzPos - curMatch3 - 1;
|
||||
if (cur[(ptrdiff_t)curMatch3 - lzPos + 3] == cur[3])
|
||||
{
|
||||
distances[0] = 4;
|
||||
return distances + 2;
|
||||
}
|
||||
distances[0] = 3;
|
||||
distances += 2;
|
||||
}
|
||||
|
||||
if (curMatch4 >= matchMinPos)
|
||||
if (
|
||||
cur[(ptrdiff_t)curMatch4 - lzPos] == cur[0] &&
|
||||
cur[(ptrdiff_t)curMatch4 - lzPos + 3] == cur[3]
|
||||
)
|
||||
{
|
||||
*distances++ = 4;
|
||||
*distances++ = lzPos - curMatch4 - 1;
|
||||
}
|
||||
|
||||
return distances;
|
||||
}
|
||||
*/
|
||||
|
||||
#define INCREASE_LZ_POS p->lzPos++; p->pointerToCurPos++;
|
||||
|
||||
static UInt32 MatchFinderMt2_GetMatches(CMatchFinderMt *p, UInt32 *distances)
|
||||
{
|
||||
const UInt32 *btBuf = p->btBuf + p->btBufPos;
|
||||
UInt32 len = *btBuf++;
|
||||
p->btBufPos += 1 + len;
|
||||
p->btNumAvailBytes--;
|
||||
{
|
||||
UInt32 i;
|
||||
for (i = 0; i < len; i += 2)
|
||||
{
|
||||
*distances++ = *btBuf++;
|
||||
*distances++ = *btBuf++;
|
||||
}
|
||||
}
|
||||
INCREASE_LZ_POS
|
||||
return len;
|
||||
}
|
||||
|
||||
static UInt32 MatchFinderMt_GetMatches(CMatchFinderMt *p, UInt32 *distances)
|
||||
{
|
||||
const UInt32 *btBuf = p->btBuf + p->btBufPos;
|
||||
UInt32 len = *btBuf++;
|
||||
p->btBufPos += 1 + len;
|
||||
|
||||
if (len == 0)
|
||||
{
|
||||
/* change for bt5 ! */
|
||||
if (p->btNumAvailBytes-- >= 4)
|
||||
len = (UInt32)(p->MixMatchesFunc(p, p->lzPos - p->historySize, distances) - (distances));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Condition: there are matches in btBuf with length < p->numHashBytes */
|
||||
UInt32 *distances2;
|
||||
p->btNumAvailBytes--;
|
||||
distances2 = p->MixMatchesFunc(p, p->lzPos - btBuf[1], distances);
|
||||
do
|
||||
{
|
||||
*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);
|
||||
|
||||
static void MatchFinderMt0_Skip(CMatchFinderMt *p, UInt32 num)
|
||||
{
|
||||
SKIP_HEADER2_MT { p->btNumAvailBytes--;
|
||||
SKIP_FOOTER_MT
|
||||
}
|
||||
|
||||
static void MatchFinderMt2_Skip(CMatchFinderMt *p, UInt32 num)
|
||||
{
|
||||
SKIP_HEADER_MT(2)
|
||||
UInt32 h2;
|
||||
MT_HASH2_CALC
|
||||
hash[h2] = p->lzPos;
|
||||
SKIP_FOOTER_MT
|
||||
}
|
||||
|
||||
static void MatchFinderMt3_Skip(CMatchFinderMt *p, UInt32 num)
|
||||
{
|
||||
SKIP_HEADER_MT(3)
|
||||
UInt32 h2, h3;
|
||||
MT_HASH3_CALC
|
||||
hash[kFix3HashSize + h3] =
|
||||
hash[ h2] =
|
||||
p->lzPos;
|
||||
SKIP_FOOTER_MT
|
||||
}
|
||||
|
||||
/*
|
||||
static void MatchFinderMt4_Skip(CMatchFinderMt *p, UInt32 num)
|
||||
{
|
||||
SKIP_HEADER_MT(4)
|
||||
UInt32 h2, h3, h4;
|
||||
MT_HASH4_CALC
|
||||
hash[kFix4HashSize + h4] =
|
||||
hash[kFix3HashSize + h3] =
|
||||
hash[ h2] =
|
||||
p->lzPos;
|
||||
SKIP_FOOTER_MT
|
||||
}
|
||||
*/
|
||||
|
||||
void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder *vTable)
|
||||
{
|
||||
vTable->Init = (Mf_Init_Func)MatchFinderMt_Init;
|
||||
vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinderMt_GetNumAvailableBytes;
|
||||
vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinderMt_GetPointerToCurrentPos;
|
||||
vTable->GetMatches = (Mf_GetMatches_Func)MatchFinderMt_GetMatches;
|
||||
|
||||
switch (p->MatchFinder->numHashBytes)
|
||||
{
|
||||
case 2:
|
||||
p->GetHeadsFunc = GetHeads2;
|
||||
p->MixMatchesFunc = (Mf_Mix_Matches)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->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;
|
||||
*/
|
||||
}
|
||||
}
|
101
C/LzFindMt.h
Normal file
101
C/LzFindMt.h
Normal file
@ -0,0 +1,101 @@
|
||||
/* LzFindMt.h -- multithreaded Match finder for LZ algorithms
|
||||
2015-05-03 : 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;
|
||||
const Byte *buffer;
|
||||
UInt32 cyclicBufferPos;
|
||||
UInt32 cyclicBufferSize; /* it must be historySize + 1 */
|
||||
UInt32 cutValue;
|
||||
|
||||
/* BT + Hash */
|
||||
CMtSync hashSync;
|
||||
/* Byte hashDummy[kMtCacheLineDummy]; */
|
||||
|
||||
/* Hash */
|
||||
Mf_GetHeads GetHeadsFunc;
|
||||
CMatchFinder *MatchFinder;
|
||||
} CMatchFinderMt;
|
||||
|
||||
void MatchFinderMt_Construct(CMatchFinderMt *p);
|
||||
void MatchFinderMt_Destruct(CMatchFinderMt *p, 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
|
57
C/LzHash.h
Normal file
57
C/LzHash.h
Normal file
@ -0,0 +1,57 @@
|
||||
/* LzHash.h -- HASH functions for LZ algorithms
|
||||
2015-04-12 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __LZ_HASH_H
|
||||
#define __LZ_HASH_H
|
||||
|
||||
#define kHash2Size (1 << 10)
|
||||
#define kHash3Size (1 << 16)
|
||||
#define kHash4Size (1 << 20)
|
||||
|
||||
#define kFix3HashSize (kHash2Size)
|
||||
#define kFix4HashSize (kHash2Size + kHash3Size)
|
||||
#define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size)
|
||||
|
||||
#define HASH2_CALC hv = cur[0] | ((UInt32)cur[1] << 8);
|
||||
|
||||
#define HASH3_CALC { \
|
||||
UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
|
||||
h2 = temp & (kHash2Size - 1); \
|
||||
hv = (temp ^ ((UInt32)cur[2] << 8)) & p->hashMask; }
|
||||
|
||||
#define HASH4_CALC { \
|
||||
UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
|
||||
h2 = temp & (kHash2Size - 1); \
|
||||
temp ^= ((UInt32)cur[2] << 8); \
|
||||
h3 = temp & (kHash3Size - 1); \
|
||||
hv = (temp ^ (p->crc[cur[3]] << 5)) & p->hashMask; }
|
||||
|
||||
#define HASH5_CALC { \
|
||||
UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
|
||||
h2 = temp & (kHash2Size - 1); \
|
||||
temp ^= ((UInt32)cur[2] << 8); \
|
||||
h3 = temp & (kHash3Size - 1); \
|
||||
temp ^= (p->crc[cur[3]] << 5); \
|
||||
h4 = temp & (kHash4Size - 1); \
|
||||
hv = (temp ^ (p->crc[cur[4]] << 3)) & p->hashMask; }
|
||||
|
||||
/* #define HASH_ZIP_CALC hv = ((cur[0] | ((UInt32)cur[1] << 8)) ^ p->crc[cur[2]]) & 0xFFFF; */
|
||||
#define HASH_ZIP_CALC hv = ((cur[2] | ((UInt32)cur[0] << 8)) ^ p->crc[cur[1]]) & 0xFFFF;
|
||||
|
||||
|
||||
#define MT_HASH2_CALC \
|
||||
h2 = (p->crc[cur[0]] ^ cur[1]) & (kHash2Size - 1);
|
||||
|
||||
#define MT_HASH3_CALC { \
|
||||
UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
|
||||
h2 = temp & (kHash2Size - 1); \
|
||||
h3 = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); }
|
||||
|
||||
#define MT_HASH4_CALC { \
|
||||
UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
|
||||
h2 = temp & (kHash2Size - 1); \
|
||||
temp ^= ((UInt32)cur[2] << 8); \
|
||||
h3 = temp & (kHash3Size - 1); \
|
||||
h4 = (temp ^ (p->crc[cur[3]] << 5)) & (kHash4Size - 1); }
|
||||
|
||||
#endif
|
378
C/Lzma2Dec.c
Normal file
378
C/Lzma2Dec.c
Normal file
@ -0,0 +1,378 @@
|
||||
/* Lzma2Dec.c -- LZMA2 Decoder
|
||||
2015-11-09 : 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 ", (unsigned)p->decoder.dicPos));
|
||||
PRF(printf(" %2X", (unsigned)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(" %8u", (unsigned)p->unpackSize));
|
||||
return (LZMA2_IS_UNCOMPRESSED_STATE(p)) ? LZMA2_STATE_DATA : LZMA2_STATE_PACK0;
|
||||
|
||||
case LZMA2_STATE_PACK0:
|
||||
p->packSize = (UInt32)b << 8;
|
||||
return LZMA2_STATE_PACK1;
|
||||
|
||||
case LZMA2_STATE_PACK1:
|
||||
p->packSize |= (UInt32)b;
|
||||
p->packSize++;
|
||||
PRF(printf(" %8u", (unsigned)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:
|
||||
{
|
||||
unsigned 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++);
|
||||
|
||||
if (dicPos == dicLimit && p->state != LZMA2_STATE_FINISHED)
|
||||
{
|
||||
p->state = LZMA2_STATE_ERROR;
|
||||
return SZ_ERROR_DATA;
|
||||
}
|
||||
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)
|
||||
{
|
||||
p->state = LZMA2_STATE_ERROR;
|
||||
return SZ_ERROR_DATA;
|
||||
}
|
||||
p->needInitDic = False;
|
||||
LzmaDec_InitDicAndState(&p->decoder, initDic, False);
|
||||
}
|
||||
|
||||
if (srcSizeCur > destSizeCur)
|
||||
srcSizeCur = destSizeCur;
|
||||
|
||||
if (srcSizeCur == 0)
|
||||
{
|
||||
p->state = LZMA2_STATE_ERROR;
|
||||
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)
|
||||
{
|
||||
unsigned mode = LZMA2_GET_LZMA_MODE(p);
|
||||
Bool initDic = (mode == 3);
|
||||
Bool initState = (mode != 0);
|
||||
if ((!initDic && p->needInitDic) || (!initState && p->needInitState))
|
||||
{
|
||||
p->state = LZMA2_STATE_ERROR;
|
||||
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)
|
||||
{
|
||||
p->state = LZMA2_STATE_ERROR;
|
||||
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;
|
||||
}
|
80
C/Lzma2Dec.h
Normal file
80
C/Lzma2Dec.h
Normal file
@ -0,0 +1,80 @@
|
||||
/* Lzma2Dec.h -- LZMA2 Decoder
|
||||
2015-05-13 : 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;
|
||||
unsigned 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
|
520
C/Lzma2Enc.c
Normal file
520
C/Lzma2Enc.c
Normal file
@ -0,0 +1,520 @@
|
||||
/* Lzma2Enc.c -- LZMA2 Encoder
|
||||
2015-10-04 : 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);
|
||||
|
||||
t1 = p->lzmaProps.numThreads;
|
||||
|
||||
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 && p->lzmaProps.reduceSize != (UInt64)(Int64)-1)
|
||||
{
|
||||
UInt64 temp = p->lzmaProps.reduceSize + p->blockSize - 1;
|
||||
if (temp > p->lzmaProps.reduceSize)
|
||||
{
|
||||
UInt64 numBlocks = temp / p->blockSize;
|
||||
if (numBlocks < (unsigned)t2)
|
||||
{
|
||||
t2 = (unsigned)numBlocks;
|
||||
if (t2 == 0)
|
||||
t2 = 1;
|
||||
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)
|
||||
{
|
||||
mainEncoder->outBuf = (Byte *)IAlloc_Alloc(mainEncoder->alloc, LZMA2_CHUNK_SIZE_COMPRESSED_MAX);
|
||||
if (!mainEncoder->outBuf)
|
||||
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)
|
||||
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[(unsigned)i];
|
||||
if (!t->enc)
|
||||
{
|
||||
t->enc = LzmaEnc_Create(p->alloc);
|
||||
if (!t->enc)
|
||||
return SZ_ERROR_MEM;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef _7ZIP_ST
|
||||
if (p->props.numBlockThreads > 1)
|
||||
{
|
||||
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;
|
||||
if (p->mtCoder.destBlockSize < p->props.blockSize)
|
||||
{
|
||||
p->mtCoder.destBlockSize = (size_t)0 - 1;
|
||||
if (p->mtCoder.destBlockSize < p->props.blockSize)
|
||||
return SZ_ERROR_FAIL;
|
||||
}
|
||||
p->mtCoder.numThreads = p->props.numBlockThreads;
|
||||
|
||||
return MtCoder_Code(&p->mtCoder);
|
||||
}
|
||||
#endif
|
||||
|
||||
return Lzma2Enc_EncodeMt1(&p->coders[0], p, outStream, inStream, progress);
|
||||
}
|
62
C/Lzma2Enc.h
Normal file
62
C/Lzma2Enc.h
Normal file
@ -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
|
111
C/Lzma86.h
Normal file
111
C/Lzma86.h
Normal file
@ -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
|
54
C/Lzma86Dec.c
Normal file
54
C/Lzma86Dec.c
Normal file
@ -0,0 +1,54 @@
|
||||
/* Lzma86Dec.c -- LZMA + x86 (BCJ) Filter Decoder
|
||||
2016-05-16 : Igor Pavlov : Public domain */
|
||||
|
||||
#include "Precomp.h"
|
||||
|
||||
#include "Lzma86.h"
|
||||
|
||||
#include "Alloc.h"
|
||||
#include "Bra.h"
|
||||
#include "LzmaDec.h"
|
||||
|
||||
SRes Lzma86_GetUnpackSize(const Byte *src, SizeT srcLen, UInt64 *unpackSize)
|
||||
{
|
||||
unsigned i;
|
||||
if (srcLen < LZMA86_HEADER_SIZE)
|
||||
return SZ_ERROR_INPUT_EOF;
|
||||
*unpackSize = 0;
|
||||
for (i = 0; i < sizeof(UInt64); i++)
|
||||
*unpackSize += ((UInt64)src[LZMA86_SIZE_OFFSET + i]) << (8 * i);
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
SRes Lzma86_Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen)
|
||||
{
|
||||
SRes res;
|
||||
int useFilter;
|
||||
SizeT inSizePure;
|
||||
ELzmaStatus status;
|
||||
|
||||
if (*srcLen < LZMA86_HEADER_SIZE)
|
||||
return SZ_ERROR_INPUT_EOF;
|
||||
|
||||
useFilter = src[0];
|
||||
|
||||
if (useFilter > 1)
|
||||
{
|
||||
*destLen = 0;
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
inSizePure = *srcLen - LZMA86_HEADER_SIZE;
|
||||
res = LzmaDecode(dest, destLen, src + LZMA86_HEADER_SIZE, &inSizePure,
|
||||
src + 1, LZMA_PROPS_SIZE, LZMA_FINISH_ANY, &status, &g_Alloc);
|
||||
*srcLen = inSizePure + LZMA86_HEADER_SIZE;
|
||||
if (res != SZ_OK)
|
||||
return res;
|
||||
if (useFilter == 1)
|
||||
{
|
||||
UInt32 x86State;
|
||||
x86_Convert_Init(x86State);
|
||||
x86_Convert(dest, *destLen, 0, &x86State, 0);
|
||||
}
|
||||
return SZ_OK;
|
||||
}
|
106
C/Lzma86Enc.c
Normal file
106
C/Lzma86Enc.c
Normal file
@ -0,0 +1,106 @@
|
||||
/* Lzma86Enc.c -- LZMA + x86 (BCJ) Filter Encoder
|
||||
2016-05-16 : Igor Pavlov : Public domain */
|
||||
|
||||
#include "Precomp.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "Lzma86.h"
|
||||
|
||||
#include "Alloc.h"
|
||||
#include "Bra.h"
|
||||
#include "LzmaEnc.h"
|
||||
|
||||
#define SZE_OUT_OVERFLOW SZE_DATA_ERROR
|
||||
|
||||
int Lzma86_Encode(Byte *dest, size_t *destLen, const Byte *src, size_t srcLen,
|
||||
int level, UInt32 dictSize, int filterMode)
|
||||
{
|
||||
size_t outSize2 = *destLen;
|
||||
Byte *filteredStream;
|
||||
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;
|
||||
}
|
1100
C/LzmaDec.c
Normal file
1100
C/LzmaDec.c
Normal file
File diff suppressed because it is too large
Load Diff
227
C/LzmaDec.h
Normal file
227
C/LzmaDec.h
Normal file
@ -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
|
2351
C/LzmaEnc.c
Normal file
2351
C/LzmaEnc.c
Normal file
File diff suppressed because it is too large
Load Diff
78
C/LzmaEnc.h
Normal file
78
C/LzmaEnc.h
Normal file
@ -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
|
327
C/MtCoder.c
Normal file
327
C/MtCoder.c
Normal file
@ -0,0 +1,327 @@
|
||||
/* MtCoder.c -- Multi-thread Coder
|
||||
2015-10-13 : Igor Pavlov : Public domain */
|
||||
|
||||
#include "Precomp.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;
|
||||
}
|
98
C/MtCoder.h
Normal file
98
C/MtCoder.h
Normal file
@ -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
|
85
C/Ppmd.h
Normal file
85
C/Ppmd.h
Normal file
@ -0,0 +1,85 @@
|
||||
/* Ppmd.h -- PPMD codec common code
|
||||
2016-05-16 : 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 z; for (z = 0; z < 256 / sizeof(p[0]); z += 8) { \
|
||||
p[z+7] = p[z+6] = p[z+5] = p[z+4] = p[z+3] = p[z+2] = p[z+1] = p[z+0] = ~(size_t)0; }}
|
||||
|
||||
EXTERN_C_END
|
||||
|
||||
#endif
|
710
C/Ppmd7.c
Normal file
710
C/Ppmd7.c
Normal file
@ -0,0 +1,710 @@
|
||||
/* Ppmd7.c -- PPMdH codec
|
||||
2016-05-21 : Igor Pavlov : Public domain
|
||||
This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */
|
||||
|
||||
#include "Precomp.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "Ppmd7.h"
|
||||
|
||||
const Byte PPMD7_kExpEscape[16] = { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 };
|
||||
static const UInt16 kInitBinEsc[] = { 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051};
|
||||
|
||||
#define MAX_FREQ 124
|
||||
#define UNIT_SIZE 12
|
||||
|
||||
#define U2B(nu) ((UInt32)(nu) * UNIT_SIZE)
|
||||
#define U2I(nu) (p->Units2Indx[(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[(unsigned)p->NS2Indx[nonMasked - 1]] +
|
||||
(nonMasked < (unsigned)SUFFIX(p->MinContext)->NumStats - p->MinContext->NumStats) +
|
||||
2 * (unsigned)(p->MinContext->SummFreq < 11 * p->MinContext->NumStats) +
|
||||
4 * (unsigned)(numMasked > nonMasked) +
|
||||
p->HiBitsFlag;
|
||||
{
|
||||
unsigned r = (see->Summ >> see->Shift);
|
||||
see->Summ = (UInt16)(see->Summ - r);
|
||||
*escFreq = r + (r == 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
see = &p->DummySee;
|
||||
*escFreq = 1;
|
||||
}
|
||||
return see;
|
||||
}
|
||||
|
||||
static void NextContext(CPpmd7 *p)
|
||||
{
|
||||
CTX_PTR c = CTX(SUCCESSOR(p->FoundState));
|
||||
if (p->OrderFall == 0 && (Byte *)c > p->Text)
|
||||
p->MinContext = p->MaxContext = c;
|
||||
else
|
||||
UpdateModel(p);
|
||||
}
|
||||
|
||||
void Ppmd7_Update1(CPpmd7 *p)
|
||||
{
|
||||
CPpmd_State *s = p->FoundState;
|
||||
s->Freq += 4;
|
||||
p->MinContext->SummFreq += 4;
|
||||
if (s[0].Freq > s[-1].Freq)
|
||||
{
|
||||
SwapStates(&s[0], &s[-1]);
|
||||
p->FoundState = --s;
|
||||
if (s->Freq > MAX_FREQ)
|
||||
Rescale(p);
|
||||
}
|
||||
NextContext(p);
|
||||
}
|
||||
|
||||
void Ppmd7_Update1_0(CPpmd7 *p)
|
||||
{
|
||||
p->PrevSuccess = (2 * p->FoundState->Freq > p->MinContext->SummFreq);
|
||||
p->RunLength += p->PrevSuccess;
|
||||
p->MinContext->SummFreq += 4;
|
||||
if ((p->FoundState->Freq += 4) > MAX_FREQ)
|
||||
Rescale(p);
|
||||
NextContext(p);
|
||||
}
|
||||
|
||||
void Ppmd7_UpdateBin(CPpmd7 *p)
|
||||
{
|
||||
p->FoundState->Freq = (Byte)(p->FoundState->Freq + (p->FoundState->Freq < 128 ? 1: 0));
|
||||
p->PrevSuccess = 1;
|
||||
p->RunLength++;
|
||||
NextContext(p);
|
||||
}
|
||||
|
||||
void Ppmd7_Update2(CPpmd7 *p)
|
||||
{
|
||||
p->MinContext->SummFreq += 4;
|
||||
if ((p->FoundState->Freq += 4) > MAX_FREQ)
|
||||
Rescale(p);
|
||||
p->RunLength = p->InitRL;
|
||||
UpdateModel(p);
|
||||
}
|
140
C/Ppmd7.h
Normal file
140
C/Ppmd7.h
Normal file
@ -0,0 +1,140 @@
|
||||
/* Ppmd7.h -- PPMdH compression codec
|
||||
2016-05-21 : 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[(unsigned)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[(unsigned)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
|
189
C/Ppmd7Dec.c
Normal file
189
C/Ppmd7Dec.c
Normal file
@ -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);
|
||||
}
|
||||
}
|
187
C/Ppmd7Enc.c
Normal file
187
C/Ppmd7Enc.c
Normal file
@ -0,0 +1,187 @@
|
||||
/* Ppmd7Enc.c -- PPMdH Encoder
|
||||
2015-09-28 : 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);
|
||||
}
|
||||
}
|
137
C/Ppmd8.h
Normal file
137
C/Ppmd8.h
Normal file
@ -0,0 +1,137 @@
|
||||
/* Ppmd8.h -- PPMdI codec
|
||||
2011-01-27 : Igor Pavlov : Public domain
|
||||
This code is based on:
|
||||
PPMd var.I (2002): Dmitry Shkarin : Public domain
|
||||
Carryless rangecoder (1999): Dmitry Subbotin : Public domain */
|
||||
|
||||
#ifndef __PPMD8_H
|
||||
#define __PPMD8_H
|
||||
|
||||
#include "Ppmd.h"
|
||||
|
||||
EXTERN_C_BEGIN
|
||||
|
||||
#define PPMD8_MIN_ORDER 2
|
||||
#define PPMD8_MAX_ORDER 16
|
||||
|
||||
struct CPpmd8_Context_;
|
||||
|
||||
typedef
|
||||
#ifdef PPMD_32BIT
|
||||
struct CPpmd8_Context_ *
|
||||
#else
|
||||
UInt32
|
||||
#endif
|
||||
CPpmd8_Context_Ref;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
typedef struct CPpmd8_Context_
|
||||
{
|
||||
Byte NumStats;
|
||||
Byte Flags;
|
||||
UInt16 SummFreq;
|
||||
CPpmd_State_Ref Stats;
|
||||
CPpmd8_Context_Ref Suffix;
|
||||
} CPpmd8_Context;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#define Ppmd8Context_OneState(p) ((CPpmd_State *)&(p)->SummFreq)
|
||||
|
||||
/* The BUG in Shkarin's code for FREEZE mode was fixed, but that fixed
|
||||
code is not compatible with original code for some files compressed
|
||||
in FREEZE mode. So we disable FREEZE mode support. */
|
||||
|
||||
enum
|
||||
{
|
||||
PPMD8_RESTORE_METHOD_RESTART,
|
||||
PPMD8_RESTORE_METHOD_CUT_OFF
|
||||
#ifdef PPMD8_FREEZE_SUPPORT
|
||||
, PPMD8_RESTORE_METHOD_FREEZE
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CPpmd8_Context *MinContext, *MaxContext;
|
||||
CPpmd_State *FoundState;
|
||||
unsigned OrderFall, InitEsc, PrevSuccess, MaxOrder;
|
||||
Int32 RunLength, InitRL; /* must be 32-bit at least */
|
||||
|
||||
UInt32 Size;
|
||||
UInt32 GlueCount;
|
||||
Byte *Base, *LoUnit, *HiUnit, *Text, *UnitsStart;
|
||||
UInt32 AlignOffset;
|
||||
unsigned RestoreMethod;
|
||||
|
||||
/* Range Coder */
|
||||
UInt32 Range;
|
||||
UInt32 Code;
|
||||
UInt32 Low;
|
||||
union
|
||||
{
|
||||
IByteIn *In;
|
||||
IByteOut *Out;
|
||||
} Stream;
|
||||
|
||||
Byte Indx2Units[PPMD_NUM_INDEXES];
|
||||
Byte Units2Indx[128];
|
||||
CPpmd_Void_Ref FreeList[PPMD_NUM_INDEXES];
|
||||
UInt32 Stamps[PPMD_NUM_INDEXES];
|
||||
|
||||
Byte NS2BSIndx[256], NS2Indx[260];
|
||||
CPpmd_See DummySee, See[24][32];
|
||||
UInt16 BinSumm[25][64];
|
||||
} CPpmd8;
|
||||
|
||||
void Ppmd8_Construct(CPpmd8 *p);
|
||||
Bool Ppmd8_Alloc(CPpmd8 *p, UInt32 size, ISzAlloc *alloc);
|
||||
void Ppmd8_Free(CPpmd8 *p, ISzAlloc *alloc);
|
||||
void Ppmd8_Init(CPpmd8 *p, unsigned maxOrder, unsigned restoreMethod);
|
||||
#define Ppmd8_WasAllocated(p) ((p)->Base != NULL)
|
||||
|
||||
|
||||
/* ---------- Internal Functions ---------- */
|
||||
|
||||
extern const Byte PPMD8_kExpEscape[16];
|
||||
|
||||
#ifdef PPMD_32BIT
|
||||
#define Ppmd8_GetPtr(p, ptr) (ptr)
|
||||
#define Ppmd8_GetContext(p, ptr) (ptr)
|
||||
#define Ppmd8_GetStats(p, ctx) ((ctx)->Stats)
|
||||
#else
|
||||
#define Ppmd8_GetPtr(p, offs) ((void *)((p)->Base + (offs)))
|
||||
#define Ppmd8_GetContext(p, offs) ((CPpmd8_Context *)Ppmd8_GetPtr((p), (offs)))
|
||||
#define Ppmd8_GetStats(p, ctx) ((CPpmd_State *)Ppmd8_GetPtr((p), ((ctx)->Stats)))
|
||||
#endif
|
||||
|
||||
void Ppmd8_Update1(CPpmd8 *p);
|
||||
void Ppmd8_Update1_0(CPpmd8 *p);
|
||||
void Ppmd8_Update2(CPpmd8 *p);
|
||||
void Ppmd8_UpdateBin(CPpmd8 *p);
|
||||
|
||||
#define Ppmd8_GetBinSumm(p) \
|
||||
&p->BinSumm[p->NS2Indx[Ppmd8Context_OneState(p->MinContext)->Freq - 1]][ \
|
||||
p->NS2BSIndx[Ppmd8_GetContext(p, p->MinContext->Suffix)->NumStats] + \
|
||||
p->PrevSuccess + p->MinContext->Flags + ((p->RunLength >> 26) & 0x20)]
|
||||
|
||||
CPpmd_See *Ppmd8_MakeEscFreq(CPpmd8 *p, unsigned numMasked, UInt32 *scale);
|
||||
|
||||
|
||||
/* ---------- Decode ---------- */
|
||||
|
||||
Bool Ppmd8_RangeDec_Init(CPpmd8 *p);
|
||||
#define Ppmd8_RangeDec_IsFinishedOK(p) ((p)->Code == 0)
|
||||
int Ppmd8_DecodeSymbol(CPpmd8 *p); /* returns: -1 as EndMarker, -2 as DataError */
|
||||
|
||||
|
||||
/* ---------- Encode ---------- */
|
||||
|
||||
#define Ppmd8_RangeEnc_Init(p) { (p)->Low = 0; (p)->Range = 0xFFFFFFFF; }
|
||||
void Ppmd8_RangeEnc_FlushData(CPpmd8 *p);
|
||||
void Ppmd8_EncodeSymbol(CPpmd8 *p, int symbol); /* symbol = -1 means EndMarker */
|
||||
|
||||
EXTERN_C_END
|
||||
|
||||
#endif
|
157
C/Ppmd8Dec.c
Normal file
157
C/Ppmd8Dec.c
Normal file
@ -0,0 +1,157 @@
|
||||
/* Ppmd8Dec.c -- PPMdI Decoder
|
||||
2010-04-16 : Igor Pavlov : Public domain
|
||||
This code is based on:
|
||||
PPMd var.I (2002): Dmitry Shkarin : Public domain
|
||||
Carryless rangecoder (1999): Dmitry Subbotin : Public domain */
|
||||
|
||||
#include "Precomp.h"
|
||||
|
||||
#include "Ppmd8.h"
|
||||
|
||||
#define kTop (1 << 24)
|
||||
#define kBot (1 << 15)
|
||||
|
||||
Bool Ppmd8_RangeDec_Init(CPpmd8 *p)
|
||||
{
|
||||
unsigned i;
|
||||
p->Low = 0;
|
||||
p->Range = 0xFFFFFFFF;
|
||||
p->Code = 0;
|
||||
for (i = 0; i < 4; i++)
|
||||
p->Code = (p->Code << 8) | p->Stream.In->Read(p->Stream.In);
|
||||
return (p->Code < 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
static UInt32 RangeDec_GetThreshold(CPpmd8 *p, UInt32 total)
|
||||
{
|
||||
return p->Code / (p->Range /= total);
|
||||
}
|
||||
|
||||
static void RangeDec_Decode(CPpmd8 *p, UInt32 start, UInt32 size)
|
||||
{
|
||||
start *= p->Range;
|
||||
p->Low += start;
|
||||
p->Code -= start;
|
||||
p->Range *= size;
|
||||
|
||||
while ((p->Low ^ (p->Low + p->Range)) < kTop ||
|
||||
(p->Range < kBot && ((p->Range = (0 - p->Low) & (kBot - 1)), 1)))
|
||||
{
|
||||
p->Code = (p->Code << 8) | p->Stream.In->Read(p->Stream.In);
|
||||
p->Range <<= 8;
|
||||
p->Low <<= 8;
|
||||
}
|
||||
}
|
||||
|
||||
#define MASK(sym) ((signed char *)charMask)[sym]
|
||||
|
||||
int Ppmd8_DecodeSymbol(CPpmd8 *p)
|
||||
{
|
||||
size_t charMask[256 / sizeof(size_t)];
|
||||
if (p->MinContext->NumStats != 0)
|
||||
{
|
||||
CPpmd_State *s = Ppmd8_GetStats(p, p->MinContext);
|
||||
unsigned i;
|
||||
UInt32 count, hiCnt;
|
||||
if ((count = RangeDec_GetThreshold(p, p->MinContext->SummFreq)) < (hiCnt = s->Freq))
|
||||
{
|
||||
Byte symbol;
|
||||
RangeDec_Decode(p, 0, s->Freq);
|
||||
p->FoundState = s;
|
||||
symbol = s->Symbol;
|
||||
Ppmd8_Update1_0(p);
|
||||
return symbol;
|
||||
}
|
||||
p->PrevSuccess = 0;
|
||||
i = p->MinContext->NumStats;
|
||||
do
|
||||
{
|
||||
if ((hiCnt += (++s)->Freq) > count)
|
||||
{
|
||||
Byte symbol;
|
||||
RangeDec_Decode(p, hiCnt - s->Freq, s->Freq);
|
||||
p->FoundState = s;
|
||||
symbol = s->Symbol;
|
||||
Ppmd8_Update1(p);
|
||||
return symbol;
|
||||
}
|
||||
}
|
||||
while (--i);
|
||||
if (count >= p->MinContext->SummFreq)
|
||||
return -2;
|
||||
RangeDec_Decode(p, hiCnt, p->MinContext->SummFreq - hiCnt);
|
||||
PPMD_SetAllBitsIn256Bytes(charMask);
|
||||
MASK(s->Symbol) = 0;
|
||||
i = p->MinContext->NumStats;
|
||||
do { MASK((--s)->Symbol) = 0; } while (--i);
|
||||
}
|
||||
else
|
||||
{
|
||||
UInt16 *prob = Ppmd8_GetBinSumm(p);
|
||||
if (((p->Code / (p->Range >>= 14)) < *prob))
|
||||
{
|
||||
Byte symbol;
|
||||
RangeDec_Decode(p, 0, *prob);
|
||||
*prob = (UInt16)PPMD_UPDATE_PROB_0(*prob);
|
||||
symbol = (p->FoundState = Ppmd8Context_OneState(p->MinContext))->Symbol;
|
||||
Ppmd8_UpdateBin(p);
|
||||
return symbol;
|
||||
}
|
||||
RangeDec_Decode(p, *prob, (1 << 14) - *prob);
|
||||
*prob = (UInt16)PPMD_UPDATE_PROB_1(*prob);
|
||||
p->InitEsc = PPMD8_kExpEscape[*prob >> 10];
|
||||
PPMD_SetAllBitsIn256Bytes(charMask);
|
||||
MASK(Ppmd8Context_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 = Ppmd8_GetContext(p, p->MinContext->Suffix);
|
||||
}
|
||||
while (p->MinContext->NumStats == numMasked);
|
||||
hiCnt = 0;
|
||||
s = Ppmd8_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 = Ppmd8_MakeEscFreq(p, numMasked, &freqSum);
|
||||
freqSum += hiCnt;
|
||||
count = RangeDec_GetThreshold(p, freqSum);
|
||||
|
||||
if (count < hiCnt)
|
||||
{
|
||||
Byte symbol;
|
||||
CPpmd_State **pps = ps;
|
||||
for (hiCnt = 0; (hiCnt += (*pps)->Freq) <= count; pps++);
|
||||
s = *pps;
|
||||
RangeDec_Decode(p, hiCnt - s->Freq, s->Freq);
|
||||
Ppmd_See_Update(see);
|
||||
p->FoundState = s;
|
||||
symbol = s->Symbol;
|
||||
Ppmd8_Update2(p);
|
||||
return symbol;
|
||||
}
|
||||
if (count >= freqSum)
|
||||
return -2;
|
||||
RangeDec_Decode(p, hiCnt, freqSum - hiCnt);
|
||||
see->Summ = (UInt16)(see->Summ + freqSum);
|
||||
do { MASK(ps[--i]->Symbol) = 0; } while (i != 0);
|
||||
}
|
||||
}
|
163
C/Ppmd8Enc.c
Normal file
163
C/Ppmd8Enc.c
Normal file
@ -0,0 +1,163 @@
|
||||
/* Ppmd8Enc.c -- PPMdI Encoder
|
||||
2010-04-16 : Igor Pavlov : Public domain
|
||||
This code is based on:
|
||||
PPMd var.I (2002): Dmitry Shkarin : Public domain
|
||||
Carryless rangecoder (1999): Dmitry Subbotin : Public domain */
|
||||
|
||||
#include "Precomp.h"
|
||||
|
||||
#include "Ppmd8.h"
|
||||
|
||||
#define kTop (1 << 24)
|
||||
#define kBot (1 << 15)
|
||||
|
||||
void Ppmd8_RangeEnc_FlushData(CPpmd8 *p)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < 4; i++, p->Low <<= 8 )
|
||||
p->Stream.Out->Write(p->Stream.Out, (Byte)(p->Low >> 24));
|
||||
}
|
||||
|
||||
static void RangeEnc_Normalize(CPpmd8 *p)
|
||||
{
|
||||
while ((p->Low ^ (p->Low + p->Range)) < kTop ||
|
||||
(p->Range < kBot && ((p->Range = (0 - p->Low) & (kBot - 1)), 1)))
|
||||
{
|
||||
p->Stream.Out->Write(p->Stream.Out, (Byte)(p->Low >> 24));
|
||||
p->Range <<= 8;
|
||||
p->Low <<= 8;
|
||||
}
|
||||
}
|
||||
|
||||
static void RangeEnc_Encode(CPpmd8 *p, UInt32 start, UInt32 size, UInt32 total)
|
||||
{
|
||||
p->Low += start * (p->Range /= total);
|
||||
p->Range *= size;
|
||||
RangeEnc_Normalize(p);
|
||||
}
|
||||
|
||||
static void RangeEnc_EncodeBit_0(CPpmd8 *p, UInt32 size0)
|
||||
{
|
||||
p->Range >>= 14;
|
||||
p->Range *= size0;
|
||||
RangeEnc_Normalize(p);
|
||||
}
|
||||
|
||||
static void RangeEnc_EncodeBit_1(CPpmd8 *p, UInt32 size0)
|
||||
{
|
||||
p->Low += size0 * (p->Range >>= 14);
|
||||
p->Range *= ((1 << 14) - size0);
|
||||
RangeEnc_Normalize(p);
|
||||
}
|
||||
|
||||
|
||||
#define MASK(sym) ((signed char *)charMask)[sym]
|
||||
|
||||
void Ppmd8_EncodeSymbol(CPpmd8 *p, int symbol)
|
||||
{
|
||||
size_t charMask[256 / sizeof(size_t)];
|
||||
if (p->MinContext->NumStats != 0)
|
||||
{
|
||||
CPpmd_State *s = Ppmd8_GetStats(p, p->MinContext);
|
||||
UInt32 sum;
|
||||
unsigned i;
|
||||
if (s->Symbol == symbol)
|
||||
{
|
||||
RangeEnc_Encode(p, 0, s->Freq, p->MinContext->SummFreq);
|
||||
p->FoundState = s;
|
||||
Ppmd8_Update1_0(p);
|
||||
return;
|
||||
}
|
||||
p->PrevSuccess = 0;
|
||||
sum = s->Freq;
|
||||
i = p->MinContext->NumStats;
|
||||
do
|
||||
{
|
||||
if ((++s)->Symbol == symbol)
|
||||
{
|
||||
RangeEnc_Encode(p, sum, s->Freq, p->MinContext->SummFreq);
|
||||
p->FoundState = s;
|
||||
Ppmd8_Update1(p);
|
||||
return;
|
||||
}
|
||||
sum += s->Freq;
|
||||
}
|
||||
while (--i);
|
||||
|
||||
PPMD_SetAllBitsIn256Bytes(charMask);
|
||||
MASK(s->Symbol) = 0;
|
||||
i = p->MinContext->NumStats;
|
||||
do { MASK((--s)->Symbol) = 0; } while (--i);
|
||||
RangeEnc_Encode(p, sum, p->MinContext->SummFreq - sum, p->MinContext->SummFreq);
|
||||
}
|
||||
else
|
||||
{
|
||||
UInt16 *prob = Ppmd8_GetBinSumm(p);
|
||||
CPpmd_State *s = Ppmd8Context_OneState(p->MinContext);
|
||||
if (s->Symbol == symbol)
|
||||
{
|
||||
RangeEnc_EncodeBit_0(p, *prob);
|
||||
*prob = (UInt16)PPMD_UPDATE_PROB_0(*prob);
|
||||
p->FoundState = s;
|
||||
Ppmd8_UpdateBin(p);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
RangeEnc_EncodeBit_1(p, *prob);
|
||||
*prob = (UInt16)PPMD_UPDATE_PROB_1(*prob);
|
||||
p->InitEsc = PPMD8_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 = Ppmd8_GetContext(p, p->MinContext->Suffix);
|
||||
}
|
||||
while (p->MinContext->NumStats == numMasked);
|
||||
|
||||
see = Ppmd8_MakeEscFreq(p, numMasked, &escFreq);
|
||||
s = Ppmd8_GetStats(p, p->MinContext);
|
||||
sum = 0;
|
||||
i = p->MinContext->NumStats + 1;
|
||||
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(p, low, s1->Freq, sum + escFreq);
|
||||
Ppmd_See_Update(see);
|
||||
p->FoundState = s1;
|
||||
Ppmd8_Update2(p);
|
||||
return;
|
||||
}
|
||||
sum += (s->Freq & (int)(MASK(cur)));
|
||||
MASK(cur) = 0;
|
||||
s++;
|
||||
}
|
||||
while (--i);
|
||||
|
||||
RangeEnc_Encode(p, sum, escFreq, sum + escFreq);
|
||||
see->Summ = (UInt16)(see->Summ + sum + escFreq);
|
||||
}
|
||||
}
|
10
C/Precomp.h
Normal file
10
C/Precomp.h
Normal file
@ -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
|
30
C/RotateDefs.h
Normal file
30
C/RotateDefs.h
Normal file
@ -0,0 +1,30 @@
|
||||
/* RotateDefs.h -- Rotate functions
|
||||
2015-03-25 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __ROTATE_DEFS_H
|
||||
#define __ROTATE_DEFS_H
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* don't use _rotl with MINGW. It can insert slow call to function. */
|
||||
|
||||
/* #if (_MSC_VER >= 1200) */
|
||||
#pragma intrinsic(_rotl)
|
||||
#pragma intrinsic(_rotr)
|
||||
/* #endif */
|
||||
|
||||
#define rotlFixed(x, n) _rotl((x), (n))
|
||||
#define rotrFixed(x, n) _rotr((x), (n))
|
||||
|
||||
#else
|
||||
|
||||
/* new compilers can translate these macros to fast commands. */
|
||||
|
||||
#define rotlFixed(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
|
||||
#define rotrFixed(x, n) (((x) >> (n)) | ((x) << (32 - (n))))
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
340
C/Sha1.c
Normal file
340
C/Sha1.c
Normal file
@ -0,0 +1,340 @@
|
||||
/* Sha1.c -- SHA-1 Hash
|
||||
2016-05-20 : Igor Pavlov : Public domain
|
||||
This code is based on public domain code of Steve Reid from Wei Dai's Crypto++ library. */
|
||||
|
||||
#include "Precomp.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "CpuArch.h"
|
||||
#include "RotateDefs.h"
|
||||
#include "Sha1.h"
|
||||
|
||||
// define it for speed optimization
|
||||
// #define _SHA1_UNROLL
|
||||
|
||||
#ifdef _SHA1_UNROLL
|
||||
#define kNumW 16
|
||||
#define WW(i) W[(i)&15]
|
||||
#else
|
||||
#define kNumW 80
|
||||
#define WW(i) W[i]
|
||||
#endif
|
||||
|
||||
#define w0(i) (W[i] = data[i])
|
||||
|
||||
#define w1(i) (WW(i) = rotlFixed(WW((i)-3) ^ WW((i)-8) ^ WW((i)-14) ^ WW((i)-16), 1))
|
||||
|
||||
#define f1(x,y,z) (z^(x&(y^z)))
|
||||
#define f2(x,y,z) (x^y^z)
|
||||
#define f3(x,y,z) ((x&y)|(z&(x|y)))
|
||||
#define f4(x,y,z) (x^y^z)
|
||||
|
||||
#define RK(a,b,c,d,e, fx, w, k) e += fx(b,c,d) + w + k + rotlFixed(a,5); b = rotlFixed(b,30);
|
||||
|
||||
#define R0(a,b,c,d,e, i) RK(a,b,c,d,e, f1, w0(i), 0x5A827999)
|
||||
#define R1(a,b,c,d,e, i) RK(a,b,c,d,e, f1, w1(i), 0x5A827999)
|
||||
#define R2(a,b,c,d,e, i) RK(a,b,c,d,e, f2, w1(i), 0x6ED9EBA1)
|
||||
#define R3(a,b,c,d,e, i) RK(a,b,c,d,e, f3, w1(i), 0x8F1BBCDC)
|
||||
#define R4(a,b,c,d,e, i) RK(a,b,c,d,e, f4, w1(i), 0xCA62C1D6)
|
||||
|
||||
#define RX_1_4(rx1, rx4, i) \
|
||||
rx1(a,b,c,d,e, i); \
|
||||
rx4(e,a,b,c,d, i+1); \
|
||||
rx4(d,e,a,b,c, i+2); \
|
||||
rx4(c,d,e,a,b, i+3); \
|
||||
rx4(b,c,d,e,a, i+4); \
|
||||
|
||||
#define RX_5(rx, i) RX_1_4(rx, rx, i);
|
||||
|
||||
#ifdef _SHA1_UNROLL
|
||||
|
||||
#define RX_15 \
|
||||
RX_5(R0, 0); \
|
||||
RX_5(R0, 5); \
|
||||
RX_5(R0, 10);
|
||||
|
||||
#define RX_20(rx, i) \
|
||||
RX_5(rx, i); \
|
||||
RX_5(rx, i + 5); \
|
||||
RX_5(rx, i + 10); \
|
||||
RX_5(rx, i + 15);
|
||||
|
||||
#else
|
||||
|
||||
#define RX_15 { unsigned i; for (i = 0; i < 15; i += 5) { RX_5(R0, i); } }
|
||||
#define RX_20(rx, ii) { unsigned i; i = ii; for (; i < ii + 20; i += 5) { RX_5(rx, i); } }
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
void Sha1_Init(CSha1 *p)
|
||||
{
|
||||
p->state[0] = 0x67452301;
|
||||
p->state[1] = 0xEFCDAB89;
|
||||
p->state[2] = 0x98BADCFE;
|
||||
p->state[3] = 0x10325476;
|
||||
p->state[4] = 0xC3D2E1F0;
|
||||
p->count = 0;
|
||||
}
|
||||
|
||||
void Sha1_GetBlockDigest(CSha1 *p, const UInt32 *data, UInt32 *destDigest)
|
||||
{
|
||||
UInt32 a, b, c, d, e;
|
||||
UInt32 W[kNumW];
|
||||
|
||||
a = p->state[0];
|
||||
b = p->state[1];
|
||||
c = p->state[2];
|
||||
d = p->state[3];
|
||||
e = p->state[4];
|
||||
|
||||
RX_15
|
||||
|
||||
RX_1_4(R0, R1, 15);
|
||||
|
||||
RX_20(R2, 20);
|
||||
RX_20(R3, 40);
|
||||
RX_20(R4, 60);
|
||||
|
||||
destDigest[0] = p->state[0] + a;
|
||||
destDigest[1] = p->state[1] + b;
|
||||
destDigest[2] = p->state[2] + c;
|
||||
destDigest[3] = p->state[3] + d;
|
||||
destDigest[4] = p->state[4] + e;
|
||||
}
|
||||
|
||||
void Sha1_UpdateBlock_Rar(CSha1 *p, UInt32 *data, int returnRes)
|
||||
{
|
||||
UInt32 a, b, c, d, e;
|
||||
UInt32 W[kNumW];
|
||||
|
||||
a = p->state[0];
|
||||
b = p->state[1];
|
||||
c = p->state[2];
|
||||
d = p->state[3];
|
||||
e = p->state[4];
|
||||
|
||||
RX_15
|
||||
|
||||
RX_1_4(R0, R1, 15);
|
||||
|
||||
RX_20(R2, 20);
|
||||
RX_20(R3, 40);
|
||||
RX_20(R4, 60);
|
||||
|
||||
p->state[0] += a;
|
||||
p->state[1] += b;
|
||||
p->state[2] += c;
|
||||
p->state[3] += d;
|
||||
p->state[4] += e;
|
||||
|
||||
if (returnRes)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0 ; i < SHA1_NUM_BLOCK_WORDS; i++)
|
||||
data[i] = W[kNumW - SHA1_NUM_BLOCK_WORDS + i];
|
||||
}
|
||||
}
|
||||
|
||||
#define Sha1_UpdateBlock(p) Sha1_GetBlockDigest(p, p->buffer, p->state)
|
||||
|
||||
void Sha1_Update(CSha1 *p, const Byte *data, size_t size)
|
||||
{
|
||||
unsigned pos, pos2;
|
||||
if (size == 0)
|
||||
return;
|
||||
pos = (unsigned)p->count & 0x3F;
|
||||
p->count += size;
|
||||
pos2 = pos & 3;
|
||||
pos >>= 2;
|
||||
|
||||
if (pos2 != 0)
|
||||
{
|
||||
UInt32 w;
|
||||
pos2 = (3 - pos2) * 8;
|
||||
w = ((UInt32)*data++) << pos2;
|
||||
if (--size && pos2)
|
||||
{
|
||||
pos2 -= 8;
|
||||
w |= ((UInt32)*data++) << pos2;
|
||||
if (--size && pos2)
|
||||
{
|
||||
pos2 -= 8;
|
||||
w |= ((UInt32)*data++) << pos2;
|
||||
size--;
|
||||
}
|
||||
}
|
||||
p->buffer[pos] |= w;
|
||||
if (pos2 == 0)
|
||||
pos++;
|
||||
}
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (pos == SHA1_NUM_BLOCK_WORDS)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
unsigned i;
|
||||
Sha1_UpdateBlock(p);
|
||||
if (size < SHA1_BLOCK_SIZE)
|
||||
break;
|
||||
size -= SHA1_BLOCK_SIZE;
|
||||
for (i = 0; i < SHA1_NUM_BLOCK_WORDS; i += 2)
|
||||
{
|
||||
p->buffer[i ] = GetBe32(data);
|
||||
p->buffer[i + 1] = GetBe32(data + 4);
|
||||
data += 8;
|
||||
}
|
||||
}
|
||||
pos = 0;
|
||||
}
|
||||
if (size < 4)
|
||||
break;
|
||||
|
||||
p->buffer[pos] = GetBe32(data);
|
||||
data += 4;
|
||||
size -= 4;
|
||||
pos++;
|
||||
}
|
||||
|
||||
if (size != 0)
|
||||
{
|
||||
UInt32 w = ((UInt32)data[0]) << 24;
|
||||
if (size > 1)
|
||||
{
|
||||
w |= ((UInt32)data[1]) << 16;
|
||||
if (size > 2)
|
||||
w |= ((UInt32)data[2]) << 8;
|
||||
}
|
||||
p->buffer[pos] = w;
|
||||
}
|
||||
}
|
||||
|
||||
void Sha1_Update_Rar(CSha1 *p, Byte *data, size_t size /* , int rar350Mode */)
|
||||
{
|
||||
int returnRes = False;
|
||||
|
||||
unsigned pos = (unsigned)p->count & 0x3F;
|
||||
p->count += size;
|
||||
|
||||
while (size--)
|
||||
{
|
||||
unsigned pos2 = (pos & 3);
|
||||
UInt32 v = ((UInt32)*data++) << (8 * (3 - pos2));
|
||||
UInt32 *ref = &(p->buffer[pos >> 2]);
|
||||
pos++;
|
||||
if (pos2 == 0)
|
||||
{
|
||||
*ref = v;
|
||||
continue;
|
||||
}
|
||||
*ref |= v;
|
||||
|
||||
if (pos == SHA1_BLOCK_SIZE)
|
||||
{
|
||||
pos = 0;
|
||||
Sha1_UpdateBlock_Rar(p, p->buffer, returnRes);
|
||||
if (returnRes)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < SHA1_NUM_BLOCK_WORDS; i++)
|
||||
{
|
||||
UInt32 d = p->buffer[i];
|
||||
Byte *prev = data + i * 4 - SHA1_BLOCK_SIZE;
|
||||
SetUi32(prev, d);
|
||||
}
|
||||
}
|
||||
// returnRes = rar350Mode;
|
||||
returnRes = True;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Sha1_Final(CSha1 *p, Byte *digest)
|
||||
{
|
||||
unsigned pos = (unsigned)p->count & 0x3F;
|
||||
unsigned pos2 = (pos & 3);
|
||||
UInt64 numBits;
|
||||
UInt32 w;
|
||||
unsigned i;
|
||||
|
||||
pos >>= 2;
|
||||
|
||||
w = 0;
|
||||
if (pos2 != 0)
|
||||
w = p->buffer[pos];
|
||||
p->buffer[pos++] = w | (((UInt32)0x80000000) >> (8 * pos2));
|
||||
|
||||
while (pos != (SHA1_NUM_BLOCK_WORDS - 2))
|
||||
{
|
||||
pos &= 0xF;
|
||||
if (pos == 0)
|
||||
Sha1_UpdateBlock(p);
|
||||
p->buffer[pos++] = 0;
|
||||
}
|
||||
|
||||
numBits = (p->count << 3);
|
||||
p->buffer[SHA1_NUM_BLOCK_WORDS - 2] = (UInt32)(numBits >> 32);
|
||||
p->buffer[SHA1_NUM_BLOCK_WORDS - 1] = (UInt32)(numBits);
|
||||
Sha1_UpdateBlock(p);
|
||||
|
||||
for (i = 0; i < SHA1_NUM_DIGEST_WORDS; i++)
|
||||
{
|
||||
UInt32 v = p->state[i];
|
||||
SetBe32(digest, v);
|
||||
digest += 4;
|
||||
}
|
||||
|
||||
Sha1_Init(p);
|
||||
}
|
||||
|
||||
|
||||
void Sha1_32_PrepareBlock(const CSha1 *p, UInt32 *block, unsigned size)
|
||||
{
|
||||
const UInt64 numBits = (p->count + size) << 5;
|
||||
block[SHA1_NUM_BLOCK_WORDS - 2] = (UInt32)(numBits >> 32);
|
||||
block[SHA1_NUM_BLOCK_WORDS - 1] = (UInt32)(numBits);
|
||||
block[size++] = 0x80000000;
|
||||
while (size != (SHA1_NUM_BLOCK_WORDS - 2))
|
||||
block[size++] = 0;
|
||||
}
|
||||
|
||||
void Sha1_32_Update(CSha1 *p, const UInt32 *data, size_t size)
|
||||
{
|
||||
unsigned pos = (unsigned)p->count & 0xF;
|
||||
p->count += size;
|
||||
while (size--)
|
||||
{
|
||||
p->buffer[pos++] = *data++;
|
||||
if (pos == SHA1_NUM_BLOCK_WORDS)
|
||||
{
|
||||
pos = 0;
|
||||
Sha1_UpdateBlock(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Sha1_32_Final(CSha1 *p, UInt32 *digest)
|
||||
{
|
||||
UInt64 numBits;
|
||||
unsigned pos = (unsigned)p->count & 0xF;
|
||||
p->buffer[pos++] = 0x80000000;
|
||||
|
||||
while (pos != (SHA1_NUM_BLOCK_WORDS - 2))
|
||||
{
|
||||
pos &= 0xF;
|
||||
if (pos == 0)
|
||||
Sha1_UpdateBlock(p);
|
||||
p->buffer[pos++] = 0;
|
||||
}
|
||||
|
||||
numBits = (p->count << 5);
|
||||
p->buffer[SHA1_NUM_BLOCK_WORDS - 2] = (UInt32)(numBits >> 32);
|
||||
p->buffer[SHA1_NUM_BLOCK_WORDS - 1] = (UInt32)(numBits);
|
||||
|
||||
Sha1_GetBlockDigest(p, p->buffer, digest);
|
||||
|
||||
Sha1_Init(p);
|
||||
}
|
38
C/Sha1.h
Normal file
38
C/Sha1.h
Normal file
@ -0,0 +1,38 @@
|
||||
/* Sha1.h -- SHA-1 Hash
|
||||
2016-05-20 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __7Z_SHA1_H
|
||||
#define __7Z_SHA1_H
|
||||
|
||||
#include "7zTypes.h"
|
||||
|
||||
EXTERN_C_BEGIN
|
||||
|
||||
#define SHA1_NUM_BLOCK_WORDS 16
|
||||
#define SHA1_NUM_DIGEST_WORDS 5
|
||||
|
||||
#define SHA1_BLOCK_SIZE (SHA1_NUM_BLOCK_WORDS * 4)
|
||||
#define SHA1_DIGEST_SIZE (SHA1_NUM_DIGEST_WORDS * 4)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UInt32 state[SHA1_NUM_DIGEST_WORDS];
|
||||
UInt64 count;
|
||||
UInt32 buffer[SHA1_NUM_BLOCK_WORDS];
|
||||
} CSha1;
|
||||
|
||||
void Sha1_Init(CSha1 *p);
|
||||
|
||||
void Sha1_GetBlockDigest(CSha1 *p, const UInt32 *data, UInt32 *destDigest);
|
||||
void Sha1_Update(CSha1 *p, const Byte *data, size_t size);
|
||||
void Sha1_Final(CSha1 *p, Byte *digest);
|
||||
|
||||
void Sha1_Update_Rar(CSha1 *p, Byte *data, size_t size /* , int rar350Mode */);
|
||||
|
||||
void Sha1_32_PrepareBlock(const CSha1 *p, UInt32 *block, unsigned size);
|
||||
void Sha1_32_Update(CSha1 *p, const UInt32 *data, size_t size);
|
||||
void Sha1_32_Final(CSha1 *p, UInt32 *digest);
|
||||
|
||||
EXTERN_C_END
|
||||
|
||||
#endif
|
248
C/Sha256.c
Normal file
248
C/Sha256.c
Normal file
@ -0,0 +1,248 @@
|
||||
/* Crypto/Sha256.c -- SHA-256 Hash
|
||||
2015-11-14 : Igor Pavlov : Public domain
|
||||
This code is based on public domain code from Wei Dai's Crypto++ library. */
|
||||
|
||||
#include "Precomp.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "CpuArch.h"
|
||||
#include "RotateDefs.h"
|
||||
#include "Sha256.h"
|
||||
|
||||
/* define it for speed optimization */
|
||||
#ifndef _SFX
|
||||
#define _SHA256_UNROLL
|
||||
#define _SHA256_UNROLL2
|
||||
#endif
|
||||
|
||||
/* #define _SHA256_UNROLL2 */
|
||||
|
||||
void Sha256_Init(CSha256 *p)
|
||||
{
|
||||
p->state[0] = 0x6a09e667;
|
||||
p->state[1] = 0xbb67ae85;
|
||||
p->state[2] = 0x3c6ef372;
|
||||
p->state[3] = 0xa54ff53a;
|
||||
p->state[4] = 0x510e527f;
|
||||
p->state[5] = 0x9b05688c;
|
||||
p->state[6] = 0x1f83d9ab;
|
||||
p->state[7] = 0x5be0cd19;
|
||||
p->count = 0;
|
||||
}
|
||||
|
||||
#define S0(x) (rotrFixed(x, 2) ^ rotrFixed(x,13) ^ rotrFixed(x, 22))
|
||||
#define S1(x) (rotrFixed(x, 6) ^ rotrFixed(x,11) ^ rotrFixed(x, 25))
|
||||
#define s0(x) (rotrFixed(x, 7) ^ rotrFixed(x,18) ^ (x >> 3))
|
||||
#define s1(x) (rotrFixed(x,17) ^ rotrFixed(x,19) ^ (x >> 10))
|
||||
|
||||
#define blk0(i) (W[i])
|
||||
#define blk2(i) (W[i] += s1(W[((i)-2)&15]) + W[((i)-7)&15] + s0(W[((i)-15)&15]))
|
||||
|
||||
#define Ch(x,y,z) (z^(x&(y^z)))
|
||||
#define Maj(x,y,z) ((x&y)|(z&(x|y)))
|
||||
|
||||
#ifdef _SHA256_UNROLL2
|
||||
|
||||
#define R(a,b,c,d,e,f,g,h, i) \
|
||||
h += S1(e) + Ch(e,f,g) + K[(i)+(j)] + (j ? blk2(i) : blk0(i)); \
|
||||
d += h; \
|
||||
h += S0(a) + Maj(a, b, c)
|
||||
|
||||
#define RX_8(i) \
|
||||
R(a,b,c,d,e,f,g,h, i); \
|
||||
R(h,a,b,c,d,e,f,g, i+1); \
|
||||
R(g,h,a,b,c,d,e,f, i+2); \
|
||||
R(f,g,h,a,b,c,d,e, i+3); \
|
||||
R(e,f,g,h,a,b,c,d, i+4); \
|
||||
R(d,e,f,g,h,a,b,c, i+5); \
|
||||
R(c,d,e,f,g,h,a,b, i+6); \
|
||||
R(b,c,d,e,f,g,h,a, i+7)
|
||||
|
||||
#define RX_16 RX_8(0); RX_8(8);
|
||||
|
||||
#else
|
||||
|
||||
#define a(i) T[(0-(i))&7]
|
||||
#define b(i) T[(1-(i))&7]
|
||||
#define c(i) T[(2-(i))&7]
|
||||
#define d(i) T[(3-(i))&7]
|
||||
#define e(i) T[(4-(i))&7]
|
||||
#define f(i) T[(5-(i))&7]
|
||||
#define g(i) T[(6-(i))&7]
|
||||
#define h(i) T[(7-(i))&7]
|
||||
|
||||
#define R(i) \
|
||||
h(i) += S1(e(i)) + Ch(e(i),f(i),g(i)) + K[(i)+(j)] + (j ? blk2(i) : blk0(i)); \
|
||||
d(i) += h(i); \
|
||||
h(i) += S0(a(i)) + Maj(a(i), b(i), c(i)) \
|
||||
|
||||
#ifdef _SHA256_UNROLL
|
||||
|
||||
#define RX_8(i) R(i+0); R(i+1); R(i+2); R(i+3); R(i+4); R(i+5); R(i+6); R(i+7);
|
||||
#define RX_16 RX_8(0); RX_8(8);
|
||||
|
||||
#else
|
||||
|
||||
#define RX_16 unsigned i; for (i = 0; i < 16; i++) { R(i); }
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
static const UInt32 K[64] = {
|
||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
|
||||
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
||||
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
|
||||
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
||||
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
|
||||
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
||||
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
|
||||
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
||||
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
|
||||
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
||||
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
|
||||
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
||||
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
|
||||
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
||||
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
|
||||
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
|
||||
};
|
||||
|
||||
static void Sha256_WriteByteBlock(CSha256 *p)
|
||||
{
|
||||
UInt32 W[16];
|
||||
unsigned j;
|
||||
UInt32 *state;
|
||||
|
||||
#ifdef _SHA256_UNROLL2
|
||||
UInt32 a,b,c,d,e,f,g,h;
|
||||
#else
|
||||
UInt32 T[8];
|
||||
#endif
|
||||
|
||||
for (j = 0; j < 16; j += 4)
|
||||
{
|
||||
const Byte *ccc = p->buffer + j * 4;
|
||||
W[j ] = GetBe32(ccc);
|
||||
W[j + 1] = GetBe32(ccc + 4);
|
||||
W[j + 2] = GetBe32(ccc + 8);
|
||||
W[j + 3] = GetBe32(ccc + 12);
|
||||
}
|
||||
|
||||
state = p->state;
|
||||
|
||||
#ifdef _SHA256_UNROLL2
|
||||
a = state[0];
|
||||
b = state[1];
|
||||
c = state[2];
|
||||
d = state[3];
|
||||
e = state[4];
|
||||
f = state[5];
|
||||
g = state[6];
|
||||
h = state[7];
|
||||
#else
|
||||
for (j = 0; j < 8; j++)
|
||||
T[j] = state[j];
|
||||
#endif
|
||||
|
||||
for (j = 0; j < 64; j += 16)
|
||||
{
|
||||
RX_16
|
||||
}
|
||||
|
||||
#ifdef _SHA256_UNROLL2
|
||||
state[0] += a;
|
||||
state[1] += b;
|
||||
state[2] += c;
|
||||
state[3] += d;
|
||||
state[4] += e;
|
||||
state[5] += f;
|
||||
state[6] += g;
|
||||
state[7] += h;
|
||||
#else
|
||||
for (j = 0; j < 8; j++)
|
||||
state[j] += T[j];
|
||||
#endif
|
||||
|
||||
/* Wipe variables */
|
||||
/* memset(W, 0, sizeof(W)); */
|
||||
/* memset(T, 0, sizeof(T)); */
|
||||
}
|
||||
|
||||
#undef S0
|
||||
#undef S1
|
||||
#undef s0
|
||||
#undef s1
|
||||
|
||||
void Sha256_Update(CSha256 *p, const Byte *data, size_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
return;
|
||||
|
||||
{
|
||||
unsigned pos = (unsigned)p->count & 0x3F;
|
||||
unsigned num;
|
||||
|
||||
p->count += size;
|
||||
|
||||
num = 64 - pos;
|
||||
if (num > size)
|
||||
{
|
||||
memcpy(p->buffer + pos, data, size);
|
||||
return;
|
||||
}
|
||||
|
||||
size -= num;
|
||||
memcpy(p->buffer + pos, data, num);
|
||||
data += num;
|
||||
}
|
||||
|
||||
for (;;)
|
||||
{
|
||||
Sha256_WriteByteBlock(p);
|
||||
if (size < 64)
|
||||
break;
|
||||
size -= 64;
|
||||
memcpy(p->buffer, data, 64);
|
||||
data += 64;
|
||||
}
|
||||
|
||||
if (size != 0)
|
||||
memcpy(p->buffer, data, size);
|
||||
}
|
||||
|
||||
void Sha256_Final(CSha256 *p, Byte *digest)
|
||||
{
|
||||
unsigned pos = (unsigned)p->count & 0x3F;
|
||||
unsigned i;
|
||||
|
||||
p->buffer[pos++] = 0x80;
|
||||
|
||||
while (pos != (64 - 8))
|
||||
{
|
||||
pos &= 0x3F;
|
||||
if (pos == 0)
|
||||
Sha256_WriteByteBlock(p);
|
||||
p->buffer[pos++] = 0;
|
||||
}
|
||||
|
||||
{
|
||||
UInt64 numBits = (p->count << 3);
|
||||
SetBe32(p->buffer + 64 - 8, (UInt32)(numBits >> 32));
|
||||
SetBe32(p->buffer + 64 - 4, (UInt32)(numBits));
|
||||
}
|
||||
|
||||
Sha256_WriteByteBlock(p);
|
||||
|
||||
for (i = 0; i < 8; i += 2)
|
||||
{
|
||||
UInt32 v0 = p->state[i];
|
||||
UInt32 v1 = p->state[i + 1];
|
||||
SetBe32(digest , v0);
|
||||
SetBe32(digest + 4, v1);
|
||||
digest += 8;
|
||||
}
|
||||
|
||||
Sha256_Init(p);
|
||||
}
|
26
C/Sha256.h
Normal file
26
C/Sha256.h
Normal file
@ -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
|
141
C/Sort.c
Normal file
141
C/Sort.c
Normal file
@ -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);
|
||||
}
|
||||
*/
|
18
C/Sort.h
Normal file
18
C/Sort.h
Normal file
@ -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
|
582
C/Threads.c
Normal file
582
C/Threads.c
Normal file
@ -0,0 +1,582 @@
|
||||
/* Threads.c */
|
||||
|
||||
#include "Threads.h"
|
||||
|
||||
#ifdef ENV_BEOS
|
||||
#include <kernel/OS.h>
|
||||
#else
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#if defined(__linux__)
|
||||
#define PTHREAD_MUTEX_ERRORCHECK PTHREAD_MUTEX_ERRORCHECK_NP
|
||||
#endif
|
||||
|
||||
#ifdef ENV_BEOS
|
||||
|
||||
/* TODO : optimize the code and verify the returned values */
|
||||
|
||||
WRes Thread_Create(CThread *thread, THREAD_FUNC_RET_TYPE (THREAD_FUNC_CALL_TYPE *startAddress)(void *), LPVOID parameter)
|
||||
{
|
||||
thread->_tid = spawn_thread((int32 (*)(void *))startAddress, "CThread", B_LOW_PRIORITY, parameter);
|
||||
if (thread->_tid >= B_OK) {
|
||||
resume_thread(thread->_tid);
|
||||
} else {
|
||||
thread->_tid = B_BAD_THREAD_ID;
|
||||
}
|
||||
thread->_created = 1;
|
||||
return 0; // SZ_OK;
|
||||
}
|
||||
|
||||
WRes Thread_Wait(CThread *thread)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (thread->_created == 0)
|
||||
return EINVAL;
|
||||
|
||||
if (thread->_tid >= B_OK)
|
||||
{
|
||||
status_t exit_value;
|
||||
wait_for_thread(thread->_tid, &exit_value);
|
||||
thread->_tid = B_BAD_THREAD_ID;
|
||||
} else {
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
thread->_created = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
WRes Thread_Close(CThread *thread)
|
||||
{
|
||||
if (!thread->_created) return SZ_OK;
|
||||
|
||||
thread->_tid = B_BAD_THREAD_ID;
|
||||
thread->_created = 0;
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
|
||||
WRes Event_Create(CEvent *p, BOOL manualReset, int initialSignaled)
|
||||
{
|
||||
p->_index_waiting = 0;
|
||||
p->_manual_reset = manualReset;
|
||||
p->_state = (initialSignaled ? TRUE : FALSE);
|
||||
p->_created = 1;
|
||||
p->_sem = create_sem(1,"event");
|
||||
return 0;
|
||||
}
|
||||
|
||||
WRes Event_Set(CEvent *p) {
|
||||
int index;
|
||||
acquire_sem(p->_sem);
|
||||
p->_state = TRUE;
|
||||
for(index = 0 ; index < p->_index_waiting ; index++)
|
||||
{
|
||||
send_data(p->_waiting[index], '7zCN', NULL, 0);
|
||||
}
|
||||
p->_index_waiting = 0;
|
||||
release_sem(p->_sem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
WRes Event_Reset(CEvent *p) {
|
||||
acquire_sem(p->_sem);
|
||||
p->_state = FALSE;
|
||||
release_sem(p->_sem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
WRes Event_Wait(CEvent *p) {
|
||||
acquire_sem(p->_sem);
|
||||
while (p->_state == FALSE)
|
||||
{
|
||||
thread_id sender;
|
||||
p->_waiting[p->_index_waiting++] = find_thread(NULL);
|
||||
release_sem(p->_sem);
|
||||
/* int msg = */ receive_data(&sender, NULL, 0);
|
||||
acquire_sem(p->_sem);
|
||||
}
|
||||
if (p->_manual_reset == FALSE)
|
||||
{
|
||||
p->_state = FALSE;
|
||||
}
|
||||
release_sem(p->_sem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
WRes Event_Close(CEvent *p) {
|
||||
if (p->_created)
|
||||
{
|
||||
p->_created = 0;
|
||||
delete_sem(p->_sem);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
WRes Semaphore_Create(CSemaphore *p, UInt32 initiallyCount, UInt32 maxCount)
|
||||
{
|
||||
p->_index_waiting = 0;
|
||||
p->_count = initiallyCount;
|
||||
p->_maxCount = maxCount;
|
||||
p->_created = 1;
|
||||
p->_sem = create_sem(1,"sem");
|
||||
return 0;
|
||||
}
|
||||
|
||||
WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 releaseCount)
|
||||
{
|
||||
UInt32 newCount;
|
||||
int index;
|
||||
|
||||
if (releaseCount < 1) return EINVAL;
|
||||
|
||||
acquire_sem(p->_sem);
|
||||
newCount = p->_count + releaseCount;
|
||||
if (newCount > p->_maxCount)
|
||||
{
|
||||
release_sem(p->_sem);
|
||||
return EINVAL;
|
||||
}
|
||||
p->_count = newCount;
|
||||
for(index = 0 ; index < p->_index_waiting ; index++)
|
||||
{
|
||||
send_data(p->_waiting[index], '7zCN', NULL, 0);
|
||||
}
|
||||
p->_index_waiting = 0;
|
||||
release_sem(p->_sem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
WRes Semaphore_Wait(CSemaphore *p) {
|
||||
acquire_sem(p->_sem);
|
||||
while (p->_count < 1)
|
||||
{
|
||||
thread_id sender;
|
||||
p->_waiting[p->_index_waiting++] = find_thread(NULL);
|
||||
release_sem(p->_sem);
|
||||
/* int msg = */ receive_data(&sender, NULL, 0);
|
||||
acquire_sem(p->_sem);
|
||||
}
|
||||
p->_count--;
|
||||
release_sem(p->_sem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
WRes Semaphore_Close(CSemaphore *p) {
|
||||
if (p->_created)
|
||||
{
|
||||
p->_created = 0;
|
||||
delete_sem(p->_sem);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
WRes CriticalSection_Init(CCriticalSection * lpCriticalSection)
|
||||
{
|
||||
lpCriticalSection->_sem = create_sem(1,"cc");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else /* !ENV_BEOS */
|
||||
|
||||
WRes Thread_Create(CThread *thread, THREAD_FUNC_RET_TYPE (THREAD_FUNC_CALL_TYPE *startAddress)(void *), LPVOID parameter)
|
||||
{
|
||||
pthread_attr_t attr;
|
||||
int ret;
|
||||
|
||||
thread->_created = 0;
|
||||
|
||||
ret = pthread_attr_init(&attr);
|
||||
if (ret) return ret;
|
||||
|
||||
ret = pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_JOINABLE);
|
||||
if (ret) return ret;
|
||||
|
||||
ret = pthread_create(&thread->_tid, &attr, (void * (*)(void *))startAddress, parameter);
|
||||
|
||||
/* ret2 = */ pthread_attr_destroy(&attr);
|
||||
|
||||
if (ret) return ret;
|
||||
|
||||
thread->_created = 1;
|
||||
|
||||
return 0; // SZ_OK;
|
||||
}
|
||||
|
||||
WRes Thread_Wait(CThread *thread)
|
||||
{
|
||||
void *thread_return;
|
||||
int ret;
|
||||
|
||||
if (thread->_created == 0)
|
||||
return EINVAL;
|
||||
|
||||
ret = pthread_join(thread->_tid,&thread_return);
|
||||
thread->_created = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
WRes Thread_Close(CThread *thread)
|
||||
{
|
||||
if (!thread->_created) return SZ_OK;
|
||||
|
||||
pthread_detach(thread->_tid);
|
||||
thread->_tid = 0;
|
||||
thread->_created = 0;
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_SYNCHRO
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
static void dump_error(int ligne,int ret,const char *text,void *param)
|
||||
{
|
||||
printf("\n##T%d#ERROR2 (l=%d) %s : param=%p ret = %d (%s)##\n",(int)pthread_self(),ligne,text,param,ret,strerror(ret));
|
||||
// abort();
|
||||
}
|
||||
|
||||
WRes Event_Create(CEvent *p, BOOL manualReset, int initialSignaled)
|
||||
{
|
||||
int ret;
|
||||
pthread_mutexattr_t mutexattr;
|
||||
memset(&mutexattr,0,sizeof(mutexattr));
|
||||
ret = pthread_mutexattr_init(&mutexattr);
|
||||
if (ret != 0) dump_error(__LINE__,ret,"Event_Create::pthread_mutexattr_init",&mutexattr);
|
||||
ret = pthread_mutexattr_settype(&mutexattr,PTHREAD_MUTEX_ERRORCHECK);
|
||||
if (ret != 0) dump_error(__LINE__,ret,"Event_Create::pthread_mutexattr_settype",&mutexattr);
|
||||
ret = pthread_mutex_init(&p->_mutex,&mutexattr);
|
||||
if (ret != 0) dump_error(__LINE__,ret,"Event_Create::pthread_mutexattr_init",&p->_mutex);
|
||||
if (ret == 0)
|
||||
{
|
||||
ret = pthread_cond_init(&p->_cond,0);
|
||||
if (ret != 0) dump_error(__LINE__,ret,"Event_Create::pthread_cond_init",&p->_cond);
|
||||
p->_manual_reset = manualReset;
|
||||
p->_state = (initialSignaled ? TRUE : FALSE);
|
||||
p->_created = 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
WRes Event_Set(CEvent *p) {
|
||||
int ret = pthread_mutex_lock(&p->_mutex);
|
||||
if (ret != 0) dump_error(__LINE__,ret,"ES::pthread_mutex_lock",&p->_mutex);
|
||||
if (ret == 0)
|
||||
{
|
||||
p->_state = TRUE;
|
||||
ret = pthread_cond_broadcast(&p->_cond);
|
||||
if (ret != 0) dump_error(__LINE__,ret,"ES::pthread_cond_broadcast",&p->_cond);
|
||||
if (ret == 0)
|
||||
{
|
||||
ret = pthread_mutex_unlock(&p->_mutex);
|
||||
if (ret != 0) dump_error(__LINE__,ret,"ES::pthread_mutex_unlock",&p->_mutex);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
WRes Event_Reset(CEvent *p) {
|
||||
int ret = pthread_mutex_lock(&p->_mutex);
|
||||
if (ret != 0) dump_error(__LINE__,ret,"ER::pthread_mutex_lock",&p->_mutex);
|
||||
if (ret == 0)
|
||||
{
|
||||
p->_state = FALSE;
|
||||
ret = pthread_mutex_unlock(&p->_mutex);
|
||||
if (ret != 0) dump_error(__LINE__,ret,"ER::pthread_mutex_unlock",&p->_mutex);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
WRes Event_Wait(CEvent *p) {
|
||||
int ret = pthread_mutex_lock(&p->_mutex);
|
||||
if (ret != 0) dump_error(__LINE__,ret,"EW::pthread_mutex_lock",&p->_mutex);
|
||||
if (ret == 0)
|
||||
{
|
||||
while ((p->_state == FALSE) && (ret == 0))
|
||||
{
|
||||
ret = pthread_cond_wait(&p->_cond, &p->_mutex);
|
||||
if (ret != 0) dump_error(__LINE__,ret,"EW::pthread_cond_wait",&p->_mutex);
|
||||
}
|
||||
if (ret == 0)
|
||||
{
|
||||
if (p->_manual_reset == FALSE)
|
||||
{
|
||||
p->_state = FALSE;
|
||||
}
|
||||
ret = pthread_mutex_unlock(&p->_mutex);
|
||||
if (ret != 0) dump_error(__LINE__,ret,"EW::pthread_mutex_unlock",&p->_mutex);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
WRes Event_Close(CEvent *p) {
|
||||
if (p->_created)
|
||||
{
|
||||
int ret;
|
||||
p->_created = 0;
|
||||
ret = pthread_mutex_destroy(&p->_mutex);
|
||||
if (ret != 0) dump_error(__LINE__,ret,"EC::pthread_mutex_destroy",&p->_mutex);
|
||||
ret = pthread_cond_destroy(&p->_cond);
|
||||
if (ret != 0) dump_error(__LINE__,ret,"EC::pthread_cond_destroy",&p->_cond);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
WRes Semaphore_Create(CSemaphore *p, UInt32 initiallyCount, UInt32 maxCount)
|
||||
{
|
||||
int ret;
|
||||
pthread_mutexattr_t mutexattr;
|
||||
memset(&mutexattr,0,sizeof(mutexattr));
|
||||
ret = pthread_mutexattr_init(&mutexattr);
|
||||
if (ret != 0) dump_error(__LINE__,ret,"SemC::pthread_mutexattr_init",&mutexattr);
|
||||
ret = pthread_mutexattr_settype(&mutexattr,PTHREAD_MUTEX_ERRORCHECK);
|
||||
if (ret != 0) dump_error(__LINE__,ret,"SemC::pthread_mutexattr_settype",&mutexattr);
|
||||
ret = pthread_mutex_init(&p->_mutex,&mutexattr);
|
||||
if (ret != 0) dump_error(__LINE__,ret,"SemC::pthread_mutexattr_init",&p->_mutex);
|
||||
if (ret == 0)
|
||||
{
|
||||
ret = pthread_cond_init(&p->_cond,0);
|
||||
if (ret != 0) dump_error(__LINE__,ret,"SemC::pthread_cond_init",&p->_mutex);
|
||||
p->_count = initiallyCount;
|
||||
p->_maxCount = maxCount;
|
||||
p->_created = 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 releaseCount)
|
||||
{
|
||||
int ret;
|
||||
if (releaseCount < 1) return EINVAL;
|
||||
|
||||
ret = pthread_mutex_lock(&p->_mutex);
|
||||
if (ret != 0) dump_error(__LINE__,ret,"SemR::pthread_mutex_lock",&p->_mutex);
|
||||
if (ret == 0)
|
||||
{
|
||||
UInt32 newCount = p->_count + releaseCount;
|
||||
if (newCount > p->_maxCount)
|
||||
{
|
||||
ret = pthread_mutex_unlock(&p->_mutex);
|
||||
if (ret != 0) dump_error(__LINE__,ret,"SemR::pthread_mutex_unlock",&p->_mutex);
|
||||
return EINVAL;
|
||||
}
|
||||
p->_count = newCount;
|
||||
ret = pthread_cond_broadcast(&p->_cond);
|
||||
if (ret != 0) dump_error(__LINE__,ret,"SemR::pthread_cond_broadcast",&p->_cond);
|
||||
if (ret == 0)
|
||||
{
|
||||
ret = pthread_mutex_unlock(&p->_mutex);
|
||||
if (ret != 0) dump_error(__LINE__,ret,"SemR::pthread_mutex_unlock",&p->_mutex);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
WRes Semaphore_Wait(CSemaphore *p) {
|
||||
int ret = pthread_mutex_lock(&p->_mutex);
|
||||
if (ret != 0) dump_error(__LINE__,ret,"SemW::pthread_mutex_lock",&p->_mutex);
|
||||
if (ret == 0)
|
||||
{
|
||||
while ((p->_count < 1) && (ret == 0))
|
||||
{
|
||||
ret = pthread_cond_wait(&p->_cond, &p->_mutex);
|
||||
if (ret != 0) dump_error(__LINE__,ret,"SemW::pthread_cond_wait",&p->_mutex);
|
||||
}
|
||||
if (ret == 0)
|
||||
{
|
||||
p->_count--;
|
||||
ret = pthread_mutex_unlock(&p->_mutex);
|
||||
if (ret != 0) dump_error(__LINE__,ret,"SemW::pthread_mutex_unlock",&p->_mutex);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
WRes Semaphore_Close(CSemaphore *p) {
|
||||
if (p->_created)
|
||||
{
|
||||
int ret;
|
||||
p->_created = 0;
|
||||
ret = pthread_mutex_destroy(&p->_mutex);
|
||||
if (ret != 0) dump_error(__LINE__,ret,"Semc::pthread_mutex_destroy",&p->_mutex);
|
||||
ret = pthread_cond_destroy(&p->_cond);
|
||||
if (ret != 0) dump_error(__LINE__,ret,"Semc::pthread_cond_destroy",&p->_cond);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
WRes CriticalSection_Init(CCriticalSection * lpCriticalSection)
|
||||
{
|
||||
if (lpCriticalSection)
|
||||
{
|
||||
int ret;
|
||||
pthread_mutexattr_t mutexattr;
|
||||
memset(&mutexattr,0,sizeof(mutexattr));
|
||||
ret = pthread_mutexattr_init(&mutexattr);
|
||||
if (ret != 0) dump_error(__LINE__,ret,"CS I::pthread_mutexattr_init",&mutexattr);
|
||||
ret = pthread_mutexattr_settype(&mutexattr,PTHREAD_MUTEX_ERRORCHECK);
|
||||
if (ret != 0) dump_error(__LINE__,ret,"CS I::pthread_mutexattr_settype",&mutexattr);
|
||||
ret = pthread_mutex_init(&lpCriticalSection->_mutex,&mutexattr);
|
||||
if (ret != 0) dump_error(__LINE__,ret,"CS I::pthread_mutexattr_init",&lpCriticalSection->_mutex);
|
||||
return ret;
|
||||
}
|
||||
return EINTR;
|
||||
}
|
||||
|
||||
void CriticalSection_Enter(CCriticalSection * lpCriticalSection)
|
||||
{
|
||||
if (lpCriticalSection)
|
||||
{
|
||||
int ret = pthread_mutex_lock(&(lpCriticalSection->_mutex));
|
||||
if (ret != 0) dump_error(__LINE__,ret,"CS::pthread_mutex_lock",&(lpCriticalSection->_mutex));
|
||||
}
|
||||
}
|
||||
|
||||
void CriticalSection_Leave(CCriticalSection * lpCriticalSection)
|
||||
{
|
||||
if (lpCriticalSection)
|
||||
{
|
||||
int ret = pthread_mutex_unlock(&(lpCriticalSection->_mutex));
|
||||
if (ret != 0) dump_error(__LINE__,ret,"CS::pthread_mutex_unlock",&(lpCriticalSection->_mutex));
|
||||
}
|
||||
}
|
||||
|
||||
void CriticalSection_Delete(CCriticalSection * lpCriticalSection)
|
||||
{
|
||||
if (lpCriticalSection)
|
||||
{
|
||||
int ret = pthread_mutex_destroy(&(lpCriticalSection->_mutex));
|
||||
if (ret != 0) dump_error(__LINE__,ret,"CS::pthread_mutex_destroy",&(lpCriticalSection->_mutex));
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
WRes Event_Create(CEvent *p, BOOL manualReset, int initialSignaled)
|
||||
{
|
||||
pthread_mutex_init(&p->_mutex,0);
|
||||
pthread_cond_init(&p->_cond,0);
|
||||
p->_manual_reset = manualReset;
|
||||
p->_state = (initialSignaled ? TRUE : FALSE);
|
||||
p->_created = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
WRes Event_Set(CEvent *p) {
|
||||
pthread_mutex_lock(&p->_mutex);
|
||||
p->_state = TRUE;
|
||||
pthread_cond_broadcast(&p->_cond);
|
||||
pthread_mutex_unlock(&p->_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
WRes Event_Reset(CEvent *p) {
|
||||
pthread_mutex_lock(&p->_mutex);
|
||||
p->_state = FALSE;
|
||||
pthread_mutex_unlock(&p->_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
WRes Event_Wait(CEvent *p) {
|
||||
pthread_mutex_lock(&p->_mutex);
|
||||
while (p->_state == FALSE)
|
||||
{
|
||||
pthread_cond_wait(&p->_cond, &p->_mutex);
|
||||
}
|
||||
if (p->_manual_reset == FALSE)
|
||||
{
|
||||
p->_state = FALSE;
|
||||
}
|
||||
pthread_mutex_unlock(&p->_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
WRes Event_Close(CEvent *p) {
|
||||
if (p->_created)
|
||||
{
|
||||
p->_created = 0;
|
||||
pthread_mutex_destroy(&p->_mutex);
|
||||
pthread_cond_destroy(&p->_cond);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
WRes Semaphore_Create(CSemaphore *p, UInt32 initiallyCount, UInt32 maxCount)
|
||||
{
|
||||
pthread_mutex_init(&p->_mutex,0);
|
||||
pthread_cond_init(&p->_cond,0);
|
||||
p->_count = initiallyCount;
|
||||
p->_maxCount = maxCount;
|
||||
p->_created = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 releaseCount)
|
||||
{
|
||||
UInt32 newCount;
|
||||
|
||||
if (releaseCount < 1) return EINVAL;
|
||||
|
||||
pthread_mutex_lock(&p->_mutex);
|
||||
|
||||
newCount = p->_count + releaseCount;
|
||||
if (newCount > p->_maxCount)
|
||||
{
|
||||
pthread_mutex_unlock(&p->_mutex);
|
||||
return EINVAL;
|
||||
}
|
||||
p->_count = newCount;
|
||||
pthread_cond_broadcast(&p->_cond);
|
||||
pthread_mutex_unlock(&p->_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
WRes Semaphore_Wait(CSemaphore *p) {
|
||||
pthread_mutex_lock(&p->_mutex);
|
||||
while (p->_count < 1)
|
||||
{
|
||||
pthread_cond_wait(&p->_cond, &p->_mutex);
|
||||
}
|
||||
p->_count--;
|
||||
pthread_mutex_unlock(&p->_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
WRes Semaphore_Close(CSemaphore *p) {
|
||||
if (p->_created)
|
||||
{
|
||||
p->_created = 0;
|
||||
pthread_mutex_destroy(&p->_mutex);
|
||||
pthread_cond_destroy(&p->_cond);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
WRes CriticalSection_Init(CCriticalSection * lpCriticalSection)
|
||||
{
|
||||
return pthread_mutex_init(&(lpCriticalSection->_mutex),0);
|
||||
}
|
||||
|
||||
#endif /* DEBUG_SYNCHRO */
|
||||
|
||||
#endif /* ENV_BEOS */
|
||||
|
||||
WRes ManualResetEvent_Create(CManualResetEvent *p, int initialSignaled)
|
||||
{ return Event_Create(p, TRUE, initialSignaled); }
|
||||
|
||||
WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p)
|
||||
{ return ManualResetEvent_Create(p, 0); }
|
||||
|
||||
WRes AutoResetEvent_Create(CAutoResetEvent *p, int initialSignaled)
|
||||
{ return Event_Create(p, FALSE, initialSignaled); }
|
||||
WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p)
|
||||
{ return AutoResetEvent_Create(p, 0); }
|
||||
|
123
C/Threads.h
Normal file
123
C/Threads.h
Normal file
@ -0,0 +1,123 @@
|
||||
/* Threads.h -- multithreading library
|
||||
2008-11-22 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __7Z_THRESDS_H
|
||||
#define __7Z_THRESDS_H
|
||||
|
||||
#include "7zTypes.h"
|
||||
#include "windows.h"
|
||||
|
||||
#ifdef ENV_BEOS
|
||||
#include <kernel/OS.h>
|
||||
#define MAX_THREAD 256
|
||||
#else
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
/* #define DEBUG_SYNCHRO 1 */
|
||||
|
||||
typedef struct _CThread
|
||||
{
|
||||
#ifdef ENV_BEOS
|
||||
thread_id _tid;
|
||||
#else
|
||||
pthread_t _tid;
|
||||
#endif
|
||||
int _created;
|
||||
|
||||
} CThread;
|
||||
|
||||
#define Thread_Construct(thread) (thread)->_created = 0
|
||||
#define Thread_WasCreated(thread) ((thread)->_created != 0)
|
||||
|
||||
typedef unsigned 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 *thread, THREAD_FUNC_TYPE startAddress, LPVOID parameter);
|
||||
WRes Thread_Wait(CThread *thread);
|
||||
WRes Thread_Close(CThread *thread);
|
||||
|
||||
typedef struct _CEvent
|
||||
{
|
||||
int _created;
|
||||
int _manual_reset;
|
||||
int _state;
|
||||
#ifdef ENV_BEOS
|
||||
thread_id _waiting[MAX_THREAD];
|
||||
int _index_waiting;
|
||||
sem_id _sem;
|
||||
#else
|
||||
pthread_mutex_t _mutex;
|
||||
pthread_cond_t _cond;
|
||||
#endif
|
||||
} CEvent;
|
||||
|
||||
typedef CEvent CAutoResetEvent;
|
||||
typedef CEvent CManualResetEvent;
|
||||
|
||||
#define Event_Construct(event) (event)->_created = 0
|
||||
#define Event_IsCreated(event) ((event)->_created)
|
||||
|
||||
WRes ManualResetEvent_Create(CManualResetEvent *event, int initialSignaled);
|
||||
WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *event);
|
||||
WRes AutoResetEvent_Create(CAutoResetEvent *event, int initialSignaled);
|
||||
WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *event);
|
||||
WRes Event_Set(CEvent *event);
|
||||
WRes Event_Reset(CEvent *event);
|
||||
WRes Event_Wait(CEvent *event);
|
||||
WRes Event_Close(CEvent *event);
|
||||
|
||||
|
||||
typedef struct _CSemaphore
|
||||
{
|
||||
int _created;
|
||||
UInt32 _count;
|
||||
UInt32 _maxCount;
|
||||
#ifdef ENV_BEOS
|
||||
thread_id _waiting[MAX_THREAD];
|
||||
int _index_waiting;
|
||||
sem_id _sem;
|
||||
#else
|
||||
pthread_mutex_t _mutex;
|
||||
pthread_cond_t _cond;
|
||||
#endif
|
||||
} CSemaphore;
|
||||
|
||||
#define Semaphore_Construct(p) (p)->_created = 0
|
||||
|
||||
WRes Semaphore_Create(CSemaphore *p, UInt32 initiallyCount, UInt32 maxCount);
|
||||
WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 num);
|
||||
#define Semaphore_Release1(p) Semaphore_ReleaseN(p, 1)
|
||||
WRes Semaphore_Wait(CSemaphore *p);
|
||||
WRes Semaphore_Close(CSemaphore *p);
|
||||
|
||||
typedef struct {
|
||||
#ifdef ENV_BEOS
|
||||
sem_id _sem;
|
||||
#else
|
||||
pthread_mutex_t _mutex;
|
||||
#endif
|
||||
} CCriticalSection;
|
||||
|
||||
WRes CriticalSection_Init(CCriticalSection *p);
|
||||
#ifdef ENV_BEOS
|
||||
#define CriticalSection_Delete(p) delete_sem((p)->_sem)
|
||||
#define CriticalSection_Enter(p) acquire_sem((p)->_sem)
|
||||
#define CriticalSection_Leave(p) release_sem((p)->_sem)
|
||||
#else
|
||||
#ifdef DEBUG_SYNCHRO
|
||||
void CriticalSection_Delete(CCriticalSection *);
|
||||
void CriticalSection_Enter(CCriticalSection *);
|
||||
void CriticalSection_Leave(CCriticalSection *);
|
||||
#else
|
||||
#define CriticalSection_Delete(p) pthread_mutex_destroy(&((p)->_mutex))
|
||||
#define CriticalSection_Enter(p) pthread_mutex_lock(&((p)->_mutex))
|
||||
#define CriticalSection_Leave(p) pthread_mutex_unlock(&((p)->_mutex))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
90
C/Xz.c
Normal file
90
C/Xz.c
Normal file
@ -0,0 +1,90 @@
|
||||
/* Xz.c - Xz
|
||||
2015-05-01 : Igor Pavlov : Public domain */
|
||||
|
||||
#include "Precomp.h"
|
||||
|
||||
#include "7zCrc.h"
|
||||
#include "CpuArch.h"
|
||||
#include "Xz.h"
|
||||
#include "XzCrc64.h"
|
||||
|
||||
const Byte XZ_SIG[XZ_SIG_SIZE] = { 0xFD, '7', 'z', 'X', 'Z', 0 };
|
||||
const Byte XZ_FOOTER_SIG[XZ_FOOTER_SIG_SIZE] = { 'Y', 'Z' };
|
||||
|
||||
unsigned Xz_WriteVarInt(Byte *buf, UInt64 v)
|
||||
{
|
||||
unsigned i = 0;
|
||||
do
|
||||
{
|
||||
buf[i++] = (Byte)((v & 0x7F) | 0x80);
|
||||
v >>= 7;
|
||||
}
|
||||
while (v != 0);
|
||||
buf[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)
|
||||
{
|
||||
unsigned t = XzFlags_GetCheckType(f);
|
||||
return (t == 0) ? 0 : (4 << ((t - 1) / 3));
|
||||
}
|
||||
|
||||
void XzCheck_Init(CXzCheck *p, unsigned mode)
|
||||
{
|
||||
p->mode = mode;
|
||||
switch (mode)
|
||||
{
|
||||
case XZ_CHECK_CRC32: p->crc = CRC_INIT_VAL; break;
|
||||
case XZ_CHECK_CRC64: p->crc64 = CRC64_INIT_VAL; break;
|
||||
case XZ_CHECK_SHA256: Sha256_Init(&p->sha); break;
|
||||
}
|
||||
}
|
||||
|
||||
void XzCheck_Update(CXzCheck *p, const void *data, size_t size)
|
||||
{
|
||||
switch (p->mode)
|
||||
{
|
||||
case XZ_CHECK_CRC32: p->crc = CrcUpdate(p->crc, data, size); break;
|
||||
case XZ_CHECK_CRC64: p->crc64 = Crc64Update(p->crc64, data, size); break;
|
||||
case XZ_CHECK_SHA256: Sha256_Update(&p->sha, (const Byte *)data, size); break;
|
||||
}
|
||||
}
|
||||
|
||||
int XzCheck_Final(CXzCheck *p, Byte *digest)
|
||||
{
|
||||
switch (p->mode)
|
||||
{
|
||||
case XZ_CHECK_CRC32:
|
||||
SetUi32(digest, CRC_GET_DIGEST(p->crc));
|
||||
break;
|
||||
case XZ_CHECK_CRC64:
|
||||
{
|
||||
int i;
|
||||
UInt64 v = CRC64_GET_DIGEST(p->crc64);
|
||||
for (i = 0; i < 8; i++, v >>= 8)
|
||||
digest[i] = (Byte)(v & 0xFF);
|
||||
break;
|
||||
}
|
||||
case XZ_CHECK_SHA256:
|
||||
Sha256_Final(&p->sha, digest);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
275
C/Xz.h
Normal file
275
C/Xz.h
Normal file
@ -0,0 +1,275 @@
|
||||
/* Xz.h - Xz interface
|
||||
2015-05-01 : 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 const Byte XZ_SIG[XZ_SIG_SIZE];
|
||||
extern const 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
|
||||
{
|
||||
unsigned mode;
|
||||
UInt32 crc;
|
||||
UInt64 crc64;
|
||||
CSha256 sha;
|
||||
} CXzCheck;
|
||||
|
||||
void XzCheck_Init(CXzCheck *p, unsigned mode);
|
||||
void XzCheck_Update(CXzCheck *p, const void *data, size_t size);
|
||||
int XzCheck_Final(CXzCheck *p, Byte *digest);
|
||||
|
||||
typedef UInt16 CXzStreamFlags;
|
||||
|
||||
#define XzFlags_IsSupported(f) ((f) <= XZ_CHECK_MASK)
|
||||
#define XzFlags_GetCheckType(f) ((f) & XZ_CHECK_MASK)
|
||||
#define XzFlags_HasDataCrc32(f) (Xz_GetCheckType(f) == XZ_CHECK_CRC32)
|
||||
unsigned XzFlags_GetCheckSize(CXzStreamFlags f);
|
||||
|
||||
SRes Xz_ParseHeader(CXzStreamFlags *p, const Byte *buf);
|
||||
SRes Xz_ReadHeader(CXzStreamFlags *p, ISeqInStream *inStream);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UInt64 unpackSize;
|
||||
UInt64 totalSize;
|
||||
} CXzBlockSizes;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CXzStreamFlags flags;
|
||||
size_t numBlocks;
|
||||
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;
|
||||
unsigned 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, unsigned 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
|
86
C/XzCrc64.c
Normal file
86
C/XzCrc64.c
Normal file
@ -0,0 +1,86 @@
|
||||
/* XzCrc64.c -- CRC64 calculation
|
||||
2015-03-01 : 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
|
||||
}
|
26
C/XzCrc64.h
Normal file
26
C/XzCrc64.h
Normal file
@ -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
|
69
C/XzCrc64Opt.c
Normal file
69
C/XzCrc64Opt.c
Normal file
@ -0,0 +1,69 @@
|
||||
/* XzCrc64Opt.c -- CRC64 calculation
|
||||
2015-03-01 : Igor Pavlov : Public domain */
|
||||
|
||||
#include "Precomp.h"
|
||||
|
||||
#include "CpuArch.h"
|
||||
|
||||
#ifndef MY_CPU_BE
|
||||
|
||||
#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
|
||||
|
||||
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)))
|
||||
|
||||
#define CRC_UPDATE_BYTE_2_BE(crc, b) (table[(Byte)((crc) >> 56) ^ (b)] ^ ((crc) << 8))
|
||||
|
||||
UInt64 MY_FAST_CALL XzCrc64UpdateT1_BeT4(UInt64 v, const void *data, size_t size, const UInt64 *table)
|
||||
{
|
||||
const Byte *p = (const Byte *)data;
|
||||
table += 0x100;
|
||||
v = CRC_UINT64_SWAP(v);
|
||||
for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++)
|
||||
v = CRC_UPDATE_BYTE_2_BE(v, *p);
|
||||
for (; size >= 4; size -= 4, p += 4)
|
||||
{
|
||||
UInt32 d = (UInt32)(v >> 32) ^ *(const UInt32 *)p;
|
||||
v = (v << 32)
|
||||
^ table[0x000 + ((d ) & 0xFF)]
|
||||
^ table[0x100 + ((d >> 8) & 0xFF)]
|
||||
^ table[0x200 + ((d >> 16) & 0xFF)]
|
||||
^ table[0x300 + ((d >> 24))];
|
||||
}
|
||||
for (; size > 0; size--, p++)
|
||||
v = CRC_UPDATE_BYTE_2_BE(v, *p);
|
||||
return CRC_UINT64_SWAP(v);
|
||||
}
|
||||
|
||||
#endif
|
913
C/XzDec.c
Normal file
913
C/XzDec.c
Normal file
@ -0,0 +1,913 @@
|
||||
/* XzDec.c -- Xz Decode
|
||||
2015-11-09 : 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)
|
||||
{
|
||||
unsigned i, limit;
|
||||
*value = 0;
|
||||
limit = (maxSize > 9) ? 9 : (unsigned)maxSize;
|
||||
|
||||
for (i = 0; i < limit;)
|
||||
{
|
||||
Byte b = p[i];
|
||||
*value |= (UInt64)(b & 0x7F) << (7 * i++);
|
||||
if ((b & 0x80) == 0)
|
||||
return (b == 0 && i != 1) ? 0 : i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ---------- BraState ---------- */
|
||||
|
||||
#define BRA_BUF_SIZE (1 << 14)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
size_t bufPos;
|
||||
size_t bufConv;
|
||||
size_t bufTotal;
|
||||
|
||||
UInt32 methodId;
|
||||
int encodeMode;
|
||||
UInt32 delta;
|
||||
UInt32 ip;
|
||||
UInt32 x86State;
|
||||
Byte deltaState[DELTA_STATE_SIZE];
|
||||
|
||||
Byte buf[BRA_BUF_SIZE];
|
||||
} CBraState;
|
||||
|
||||
static void BraState_Free(void *pp, ISzAlloc *alloc)
|
||||
{
|
||||
alloc->Free(alloc, pp);
|
||||
}
|
||||
|
||||
static SRes BraState_SetProps(void *pp, const Byte *props, size_t propSize, ISzAlloc *alloc)
|
||||
{
|
||||
CBraState *p = ((CBraState *)pp);
|
||||
UNUSED_VAR(alloc);
|
||||
p->ip = 0;
|
||||
if (p->methodId == XZ_ID_Delta)
|
||||
{
|
||||
if (propSize != 1)
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
p->delta = (unsigned)props[0] + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (propSize == 4)
|
||||
{
|
||||
UInt32 v = GetUi32(props);
|
||||
switch (p->methodId)
|
||||
{
|
||||
case XZ_ID_PPC:
|
||||
case XZ_ID_ARM:
|
||||
case XZ_ID_SPARC:
|
||||
if ((v & 3) != 0)
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
break;
|
||||
case XZ_ID_ARMT:
|
||||
if ((v & 1) != 0)
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
break;
|
||||
case XZ_ID_IA64:
|
||||
if ((v & 0xF) != 0)
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
break;
|
||||
}
|
||||
p->ip = v;
|
||||
}
|
||||
else if (propSize != 0)
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
}
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
static void BraState_Init(void *pp)
|
||||
{
|
||||
CBraState *p = ((CBraState *)pp);
|
||||
p->bufPos = p->bufConv = p->bufTotal = 0;
|
||||
x86_Convert_Init(p->x86State);
|
||||
if (p->methodId == XZ_ID_Delta)
|
||||
Delta_Init(p->deltaState);
|
||||
}
|
||||
|
||||
#define CASE_BRA_CONV(isa) case XZ_ID_ ## isa: 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;
|
||||
UNUSED_VAR(finishMode);
|
||||
*destLen = 0;
|
||||
*srcLen = 0;
|
||||
*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)
|
||||
{
|
||||
UNUSED_VAR(pp);
|
||||
UNUSED_VAR(props);
|
||||
UNUSED_VAR(alloc);
|
||||
return (propSize == 0) ? SZ_OK : SZ_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
static void SbState_Init(void *pp)
|
||||
{
|
||||
SbDec_Init((CSbDec *)pp);
|
||||
}
|
||||
|
||||
static SRes SbState_Code(void *pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
|
||||
int srcWasFinished, ECoderFinishMode finishMode, int *wasFinished)
|
||||
{
|
||||
CSbDec *p = (CSbDec *)pp;
|
||||
SRes res;
|
||||
UNUSED_VAR(srcWasFinished);
|
||||
p->dest = dest;
|
||||
p->destLen = *destLen;
|
||||
p->src = src;
|
||||
p->srcLen = *srcLen;
|
||||
p->finish = finishMode; /* change it */
|
||||
res = SbDec_Decode((CSbDec *)pp);
|
||||
*destLen -= p->destLen;
|
||||
*srcLen -= p->srcLen;
|
||||
*wasFinished = (*destLen == 0 && *srcLen == 0); /* change it */
|
||||
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);
|
||||
UNUSED_VAR(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)
|
||||
{
|
||||
unsigned i;
|
||||
p->alloc = alloc;
|
||||
p->buf = NULL;
|
||||
p->numCoders = 0;
|
||||
for (i = 0; i < MIXCODER_NUM_FILTERS_MAX; i++)
|
||||
p->coders[i].p = NULL;
|
||||
}
|
||||
|
||||
void MixCoder_Free(CMixCoder *p)
|
||||
{
|
||||
unsigned 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 = NULL; /* 9.31: the BUG was fixed */
|
||||
}
|
||||
}
|
||||
|
||||
void MixCoder_Init(CMixCoder *p)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < MIXCODER_NUM_FILTERS_MAX - 1; i++)
|
||||
{
|
||||
p->size[i] = 0;
|
||||
p->pos[i] = 0;
|
||||
p->finished[i] = 0;
|
||||
}
|
||||
for (i = 0; i < p->numCoders; i++)
|
||||
{
|
||||
IStateCoder *coder = &p->coders[i];
|
||||
coder->Init(coder->p);
|
||||
}
|
||||
}
|
||||
|
||||
SRes MixCoder_SetFromMethod(CMixCoder *p, unsigned 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)
|
||||
{
|
||||
p->buf = (Byte *)p->alloc->Alloc(p->alloc, CODER_BUF_SIZE * (MIXCODER_NUM_FILTERS_MAX - 1));
|
||||
if (!p->buf)
|
||||
return SZ_ERROR_MEM;
|
||||
}
|
||||
|
||||
if (p->numCoders != 1)
|
||||
finishMode = CODER_FINISH_ANY;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
Bool processed = False;
|
||||
unsigned 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;
|
||||
unsigned numFilters, i;
|
||||
unsigned headerSize = (unsigned)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[%u] = %2X: ", i, (unsigned)filter->id);
|
||||
{
|
||||
unsigned 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)
|
||||
{
|
||||
unsigned i;
|
||||
Bool needReInit = True;
|
||||
unsigned 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;
|
||||
}
|
538
C/XzEnc.c
Normal file
538
C/XzEnc.c
Normal file
@ -0,0 +1,538 @@
|
||||
/* XzEnc.c -- Xz Encode
|
||||
2015-09-16 : 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"
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
static SRes Xz_WriteHeader(CXzStreamFlags f, ISeqOutStream *s)
|
||||
{
|
||||
UInt32 crc;
|
||||
Byte header[XZ_STREAM_HEADER_SIZE];
|
||||
memcpy(header, XZ_SIG, XZ_SIG_SIZE);
|
||||
header[XZ_SIG_SIZE] = (Byte)(f >> 8);
|
||||
header[XZ_SIG_SIZE + 1] = (Byte)(f & 0xFF);
|
||||
crc = CrcCalc(header + XZ_SIG_SIZE, XZ_STREAM_FLAGS_SIZE);
|
||||
SetUi32(header + XZ_SIG_SIZE + XZ_STREAM_FLAGS_SIZE, crc);
|
||||
return WriteBytes(s, header, XZ_STREAM_HEADER_SIZE);
|
||||
}
|
||||
|
||||
|
||||
static SRes XzBlock_WriteHeader(const CXzBlock *p, ISeqOutStream *s)
|
||||
{
|
||||
Byte header[XZ_BLOCK_HEADER_SIZE_MAX];
|
||||
|
||||
unsigned pos = 1;
|
||||
unsigned numFilters, i;
|
||||
header[pos++] = p->flags;
|
||||
|
||||
if (XzBlock_HasPackSize(p)) pos += Xz_WriteVarInt(header + pos, p->packSize);
|
||||
if (XzBlock_HasUnpackSize(p)) pos += Xz_WriteVarInt(header + pos, p->unpackSize);
|
||||
numFilters = XzBlock_GetNumFilters(p);
|
||||
|
||||
for (i = 0; i < numFilters; i++)
|
||||
{
|
||||
const CXzFilter *f = &p->filters[i];
|
||||
pos += Xz_WriteVarInt(header + pos, f->id);
|
||||
pos += Xz_WriteVarInt(header + pos, f->propsSize);
|
||||
memcpy(header + pos, f->props, f->propsSize);
|
||||
pos += f->propsSize;
|
||||
}
|
||||
|
||||
while ((pos & 3) != 0)
|
||||
header[pos++] = 0;
|
||||
|
||||
header[0] = (Byte)(pos >> 2);
|
||||
SetUi32(header + pos, CrcCalc(header, pos));
|
||||
return WriteBytes(s, header, pos + 4);
|
||||
}
|
||||
|
||||
|
||||
static 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static SRes Xz_AddIndexRecord(CXzStream *p, UInt64 unpackSize, UInt64 totalSize, ISzAlloc *alloc)
|
||||
{
|
||||
if (!p->blocks || p->numBlocksAllocated == p->numBlocks)
|
||||
{
|
||||
size_t num = p->numBlocks * 2 + 1;
|
||||
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)
|
||||
return SZ_ERROR_MEM;
|
||||
if (p->numBlocks != 0)
|
||||
{
|
||||
memcpy(blocks, p->blocks, p->numBlocks * sizeof(CXzBlockSizes));
|
||||
alloc->Free(alloc, p->blocks);
|
||||
}
|
||||
p->blocks = blocks;
|
||||
p->numBlocksAllocated = num;
|
||||
}
|
||||
{
|
||||
CXzBlockSizes *block = &p->blocks[p->numBlocks++];
|
||||
block->unpackSize = unpackSize;
|
||||
block->totalSize = totalSize;
|
||||
}
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
|
||||
/* ---------- CSeqCheckInStream ---------- */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ISeqInStream p;
|
||||
ISeqInStream *realStream;
|
||||
UInt64 processed;
|
||||
CXzCheck check;
|
||||
} CSeqCheckInStream;
|
||||
|
||||
static void SeqCheckInStream_Init(CSeqCheckInStream *p, unsigned mode)
|
||||
{
|
||||
p->processed = 0;
|
||||
XzCheck_Init(&p->check, mode);
|
||||
}
|
||||
|
||||
static 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)
|
||||
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 = NULL;
|
||||
p->filterProps = NULL;
|
||||
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;
|
||||
unsigned 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;
|
||||
}
|
39
C/XzEnc.h
Normal file
39
C/XzEnc.h
Normal file
@ -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
|
313
C/XzIn.c
Normal file
313
C/XzIn.c
Normal file
@ -0,0 +1,313 @@
|
||||
/* XzIn.c - Xz input
|
||||
2015-11-08 : 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 numBlocks, pos = 1;
|
||||
UInt32 crc;
|
||||
|
||||
if (size < 5 || buf[0] != 0)
|
||||
return SZ_ERROR_ARCHIVE;
|
||||
|
||||
size -= 4;
|
||||
crc = CrcCalc(buf, size);
|
||||
if (crc != GetUi32(buf + size))
|
||||
return SZ_ERROR_ARCHIVE;
|
||||
|
||||
{
|
||||
UInt64 numBlocks64;
|
||||
READ_VARINT_AND_CHECK(buf, pos, size, &numBlocks64);
|
||||
numBlocks = (size_t)numBlocks64;
|
||||
if (numBlocks != numBlocks64 || numBlocks * 2 > size)
|
||||
return SZ_ERROR_ARCHIVE;
|
||||
}
|
||||
|
||||
Xz_Free(p, alloc);
|
||||
if (numBlocks != 0)
|
||||
{
|
||||
size_t i;
|
||||
p->numBlocks = numBlocks;
|
||||
p->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 LookInStream_SeekRead_ForArc(ILookInStream *stream, UInt64 offset, void *buf, size_t size)
|
||||
{
|
||||
RINOK(LookInStream_SeekTo(stream, offset));
|
||||
return LookInStream_Read(stream, buf, size);
|
||||
/* return LookInStream_Read2(stream, buf, size, SZ_ERROR_NO_ARCHIVE); */
|
||||
}
|
||||
|
||||
static SRes Xz_ReadBackward(CXzStream *p, ILookInStream *stream, Int64 *startOffset, ISzAlloc *alloc)
|
||||
{
|
||||
UInt64 indexSize;
|
||||
Byte buf[XZ_STREAM_FOOTER_SIZE];
|
||||
UInt64 pos = *startOffset;
|
||||
|
||||
if ((pos & 3) != 0 || pos < XZ_STREAM_FOOTER_SIZE)
|
||||
return SZ_ERROR_NO_ARCHIVE;
|
||||
|
||||
pos -= XZ_STREAM_FOOTER_SIZE;
|
||||
RINOK(LookInStream_SeekRead_ForArc(stream, pos, buf, XZ_STREAM_FOOTER_SIZE));
|
||||
|
||||
if (memcmp(buf + 10, XZ_FOOTER_SIG, XZ_FOOTER_SIG_SIZE) != 0)
|
||||
{
|
||||
UInt32 total = 0;
|
||||
pos += XZ_STREAM_FOOTER_SIZE;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
size_t i;
|
||||
#define TEMP_BUF_SIZE (1 << 10)
|
||||
Byte temp[TEMP_BUF_SIZE];
|
||||
|
||||
i = (pos > TEMP_BUF_SIZE) ? TEMP_BUF_SIZE : (size_t)pos;
|
||||
pos -= i;
|
||||
RINOK(LookInStream_SeekRead_ForArc(stream, pos, temp, i));
|
||||
total += (UInt32)i;
|
||||
for (; i != 0; i--)
|
||||
if (temp[i - 1] != 0)
|
||||
break;
|
||||
if (i != 0)
|
||||
{
|
||||
if ((i & 3) != 0)
|
||||
return SZ_ERROR_NO_ARCHIVE;
|
||||
pos += i;
|
||||
break;
|
||||
}
|
||||
if (pos < XZ_STREAM_FOOTER_SIZE || total > (1 << 16))
|
||||
return SZ_ERROR_NO_ARCHIVE;
|
||||
}
|
||||
|
||||
if (pos < XZ_STREAM_FOOTER_SIZE)
|
||||
return SZ_ERROR_NO_ARCHIVE;
|
||||
pos -= XZ_STREAM_FOOTER_SIZE;
|
||||
RINOK(LookInStream_SeekRead_ForArc(stream, pos, buf, XZ_STREAM_FOOTER_SIZE));
|
||||
if (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;
|
||||
|
||||
if (pos < indexSize)
|
||||
return SZ_ERROR_ARCHIVE;
|
||||
|
||||
pos -= indexSize;
|
||||
RINOK(LookInStream_SeekTo(stream, pos));
|
||||
RINOK(Xz_ReadIndex(p, stream, indexSize, alloc));
|
||||
|
||||
{
|
||||
UInt64 totalSize = Xz_GetPackSize(p);
|
||||
if (totalSize == XZ_SIZE_OVERFLOW
|
||||
|| totalSize >= ((UInt64)1 << 63)
|
||||
|| pos < totalSize + XZ_STREAM_HEADER_SIZE)
|
||||
return SZ_ERROR_ARCHIVE;
|
||||
pos -= (totalSize + XZ_STREAM_HEADER_SIZE);
|
||||
RINOK(LookInStream_SeekTo(stream, pos));
|
||||
*startOffset = pos;
|
||||
}
|
||||
{
|
||||
CXzStreamFlags headerFlags;
|
||||
CSecToRead secToRead;
|
||||
SecToRead_CreateVTable(&secToRead);
|
||||
secToRead.realStream = stream;
|
||||
|
||||
RINOK(Xz_ReadHeader(&headerFlags, &secToRead.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(LookInStream_SeekTo(stream, *startOffset));
|
||||
if (progress && progress->Progress(progress, endOffset - *startOffset, (UInt64)(Int64)-1) != SZ_OK)
|
||||
return SZ_ERROR_PROGRESS;
|
||||
}
|
||||
return SZ_OK;
|
||||
}
|
3
CPP/7zip/Archive/7z/7zCompressionMode.cpp
Normal file
3
CPP/7zip/Archive/7z/7zCompressionMode.cpp
Normal file
@ -0,0 +1,3 @@
|
||||
// CompressionMethod.cpp
|
||||
|
||||
#include "StdAfx.h"
|
74
CPP/7zip/Archive/7z/7zCompressionMode.h
Normal file
74
CPP/7zip/Archive/7z/7zCompressionMode.h
Normal file
@ -0,0 +1,74 @@
|
||||
// 7zCompressionMode.h
|
||||
|
||||
#ifndef __7Z_COMPRESSION_MODE_H
|
||||
#define __7Z_COMPRESSION_MODE_H
|
||||
|
||||
#include "../../Common/MethodId.h"
|
||||
#include "../../Common/MethodProps.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace N7z {
|
||||
|
||||
struct CMethodFull: public CMethodProps
|
||||
{
|
||||
CMethodId Id;
|
||||
UInt32 NumStreams;
|
||||
|
||||
bool IsSimpleCoder() const { return NumStreams == 1; }
|
||||
};
|
||||
|
||||
struct CBond2
|
||||
{
|
||||
UInt32 OutCoder;
|
||||
UInt32 OutStream;
|
||||
UInt32 InCoder;
|
||||
};
|
||||
|
||||
struct CCompressionMethodMode
|
||||
{
|
||||
/*
|
||||
if (Bonds.Empty()), then default bonds must be created
|
||||
if (Filter_was_Inserted)
|
||||
{
|
||||
Methods[0] is filter method
|
||||
Bonds don't contain bonds for filter (these bonds must be created)
|
||||
}
|
||||
*/
|
||||
|
||||
CObjectVector<CMethodFull> Methods;
|
||||
CRecordVector<CBond2> Bonds;
|
||||
|
||||
bool IsThereBond_to_Coder(unsigned coderIndex) const
|
||||
{
|
||||
FOR_VECTOR(i, Bonds)
|
||||
if (Bonds[i].InCoder == coderIndex)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DefaultMethod_was_Inserted;
|
||||
bool Filter_was_Inserted;
|
||||
|
||||
#ifndef _7ZIP_ST
|
||||
UInt32 NumThreads;
|
||||
bool MultiThreadMixer;
|
||||
#endif
|
||||
|
||||
bool PasswordIsDefined;
|
||||
UString Password;
|
||||
|
||||
bool IsEmpty() const { return (Methods.IsEmpty() && !PasswordIsDefined); }
|
||||
CCompressionMethodMode():
|
||||
DefaultMethod_was_Inserted(false),
|
||||
Filter_was_Inserted(false),
|
||||
PasswordIsDefined(false)
|
||||
#ifndef _7ZIP_ST
|
||||
, NumThreads(1)
|
||||
, MultiThreadMixer(true)
|
||||
#endif
|
||||
{}
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
543
CPP/7zip/Archive/7z/7zDecode.cpp
Normal file
543
CPP/7zip/Archive/7z/7zDecode.cpp
Normal file
@ -0,0 +1,543 @@
|
||||
// 7zDecode.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../Common/LimitedStreams.h"
|
||||
#include "../../Common/ProgressUtils.h"
|
||||
#include "../../Common/StreamObjects.h"
|
||||
|
||||
#include "7zDecode.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace N7z {
|
||||
|
||||
class CDecProgress:
|
||||
public ICompressProgressInfo,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CMyComPtr<ICompressProgressInfo> _progress;
|
||||
public:
|
||||
CDecProgress(ICompressProgressInfo *progress): _progress(progress) {}
|
||||
|
||||
MY_UNKNOWN_IMP1(ICompressProgressInfo)
|
||||
STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
|
||||
};
|
||||
|
||||
STDMETHODIMP CDecProgress::SetRatioInfo(const UInt64 * /* inSize */, const UInt64 *outSize)
|
||||
{
|
||||
return _progress->SetRatioInfo(NULL, outSize);
|
||||
}
|
||||
|
||||
static void Convert_FolderInfo_to_BindInfo(const CFolderEx &folder, CBindInfoEx &bi)
|
||||
{
|
||||
bi.Clear();
|
||||
|
||||
bi.Bonds.ClearAndSetSize(folder.Bonds.Size());
|
||||
unsigned i;
|
||||
for (i = 0; i < folder.Bonds.Size(); i++)
|
||||
{
|
||||
NCoderMixer2::CBond &bond = bi.Bonds[i];
|
||||
const N7z::CBond &folderBond = folder.Bonds[i];
|
||||
bond.PackIndex = folderBond.PackIndex;
|
||||
bond.UnpackIndex = folderBond.UnpackIndex;
|
||||
}
|
||||
|
||||
bi.Coders.ClearAndSetSize(folder.Coders.Size());
|
||||
bi.CoderMethodIDs.ClearAndSetSize(folder.Coders.Size());
|
||||
for (i = 0; i < folder.Coders.Size(); i++)
|
||||
{
|
||||
const CCoderInfo &coderInfo = folder.Coders[i];
|
||||
bi.Coders[i].NumStreams = coderInfo.NumStreams;
|
||||
bi.CoderMethodIDs[i] = coderInfo.MethodID;
|
||||
}
|
||||
|
||||
/*
|
||||
if (!bi.SetUnpackCoder())
|
||||
throw 1112;
|
||||
*/
|
||||
bi.UnpackCoder = folder.UnpackCoder;
|
||||
bi.PackStreams.ClearAndSetSize(folder.PackStreams.Size());
|
||||
for (i = 0; i < folder.PackStreams.Size(); i++)
|
||||
bi.PackStreams[i] = folder.PackStreams[i];
|
||||
}
|
||||
|
||||
static inline bool AreCodersEqual(
|
||||
const NCoderMixer2::CCoderStreamsInfo &a1,
|
||||
const NCoderMixer2::CCoderStreamsInfo &a2)
|
||||
{
|
||||
return (a1.NumStreams == a2.NumStreams);
|
||||
}
|
||||
|
||||
static inline bool AreBondsEqual(
|
||||
const NCoderMixer2::CBond &a1,
|
||||
const NCoderMixer2::CBond &a2)
|
||||
{
|
||||
return
|
||||
(a1.PackIndex == a2.PackIndex) &&
|
||||
(a1.UnpackIndex == a2.UnpackIndex);
|
||||
}
|
||||
|
||||
static bool AreBindInfoExEqual(const CBindInfoEx &a1, const CBindInfoEx &a2)
|
||||
{
|
||||
if (a1.Coders.Size() != a2.Coders.Size())
|
||||
return false;
|
||||
unsigned i;
|
||||
for (i = 0; i < a1.Coders.Size(); i++)
|
||||
if (!AreCodersEqual(a1.Coders[i], a2.Coders[i]))
|
||||
return false;
|
||||
|
||||
if (a1.Bonds.Size() != a2.Bonds.Size())
|
||||
return false;
|
||||
for (i = 0; i < a1.Bonds.Size(); i++)
|
||||
if (!AreBondsEqual(a1.Bonds[i], a2.Bonds[i]))
|
||||
return false;
|
||||
|
||||
for (i = 0; i < a1.CoderMethodIDs.Size(); i++)
|
||||
if (a1.CoderMethodIDs[i] != a2.CoderMethodIDs[i])
|
||||
return false;
|
||||
|
||||
if (a1.PackStreams.Size() != a2.PackStreams.Size())
|
||||
return false;
|
||||
for (i = 0; i < a1.PackStreams.Size(); i++)
|
||||
if (a1.PackStreams[i] != a2.PackStreams[i])
|
||||
return false;
|
||||
|
||||
/*
|
||||
if (a1.UnpackCoder != a2.UnpackCoder)
|
||||
return false;
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
CDecoder::CDecoder(bool useMixerMT):
|
||||
_bindInfoPrev_Defined(false),
|
||||
_useMixerMT(useMixerMT)
|
||||
{}
|
||||
|
||||
|
||||
struct CLockedInStream:
|
||||
public IUnknown,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CMyComPtr<IInStream> Stream;
|
||||
UInt64 Pos;
|
||||
|
||||
MY_UNKNOWN_IMP
|
||||
|
||||
#ifdef USE_MIXER_MT
|
||||
NWindows::NSynchronization::CCriticalSection CriticalSection;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
#ifdef USE_MIXER_MT
|
||||
|
||||
class CLockedSequentialInStreamMT:
|
||||
public ISequentialInStream,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CLockedInStream *_glob;
|
||||
UInt64 _pos;
|
||||
CMyComPtr<IUnknown> _globRef;
|
||||
public:
|
||||
void Init(CLockedInStream *lockedInStream, UInt64 startPos)
|
||||
{
|
||||
_globRef = lockedInStream;
|
||||
_glob = lockedInStream;
|
||||
_pos = startPos;
|
||||
}
|
||||
|
||||
MY_UNKNOWN_IMP1(ISequentialInStream)
|
||||
|
||||
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
|
||||
};
|
||||
|
||||
STDMETHODIMP CLockedSequentialInStreamMT::Read(void *data, UInt32 size, UInt32 *processedSize)
|
||||
{
|
||||
NWindows::NSynchronization::CCriticalSectionLock lock(_glob->CriticalSection);
|
||||
|
||||
if (_pos != _glob->Pos)
|
||||
{
|
||||
RINOK(_glob->Stream->Seek(_pos, STREAM_SEEK_SET, NULL));
|
||||
_glob->Pos = _pos;
|
||||
}
|
||||
|
||||
UInt32 realProcessedSize = 0;
|
||||
HRESULT res = _glob->Stream->Read(data, size, &realProcessedSize);
|
||||
_pos += realProcessedSize;
|
||||
_glob->Pos = _pos;
|
||||
if (processedSize)
|
||||
*processedSize = realProcessedSize;
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef USE_MIXER_ST
|
||||
|
||||
class CLockedSequentialInStreamST:
|
||||
public ISequentialInStream,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CLockedInStream *_glob;
|
||||
UInt64 _pos;
|
||||
CMyComPtr<IUnknown> _globRef;
|
||||
public:
|
||||
void Init(CLockedInStream *lockedInStream, UInt64 startPos)
|
||||
{
|
||||
_globRef = lockedInStream;
|
||||
_glob = lockedInStream;
|
||||
_pos = startPos;
|
||||
}
|
||||
|
||||
MY_UNKNOWN_IMP1(ISequentialInStream)
|
||||
|
||||
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
|
||||
};
|
||||
|
||||
STDMETHODIMP CLockedSequentialInStreamST::Read(void *data, UInt32 size, UInt32 *processedSize)
|
||||
{
|
||||
if (_pos != _glob->Pos)
|
||||
{
|
||||
RINOK(_glob->Stream->Seek(_pos, STREAM_SEEK_SET, NULL));
|
||||
_glob->Pos = _pos;
|
||||
}
|
||||
|
||||
UInt32 realProcessedSize = 0;
|
||||
HRESULT res = _glob->Stream->Read(data, size, &realProcessedSize);
|
||||
_pos += realProcessedSize;
|
||||
_glob->Pos = _pos;
|
||||
if (processedSize)
|
||||
*processedSize = realProcessedSize;
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
HRESULT CDecoder::Decode(
|
||||
DECL_EXTERNAL_CODECS_LOC_VARS
|
||||
IInStream *inStream,
|
||||
UInt64 startPos,
|
||||
const CFolders &folders, unsigned folderIndex,
|
||||
const UInt64 *unpackSize
|
||||
|
||||
, ISequentialOutStream *outStream
|
||||
, ICompressProgressInfo *compressProgress
|
||||
, ISequentialInStream **
|
||||
|
||||
#ifdef USE_MIXER_ST
|
||||
inStreamMainRes
|
||||
#endif
|
||||
|
||||
_7Z_DECODER_CRYPRO_VARS_DECL
|
||||
|
||||
#if !defined(_7ZIP_ST) && !defined(_SFX)
|
||||
, bool mtMode, UInt32 numThreads
|
||||
#endif
|
||||
)
|
||||
{
|
||||
const UInt64 *packPositions = &folders.PackPositions[folders.FoStartPackStreamIndex[folderIndex]];
|
||||
CFolderEx folderInfo;
|
||||
folders.ParseFolderEx(folderIndex, folderInfo);
|
||||
|
||||
if (!folderInfo.IsDecodingSupported())
|
||||
return E_NOTIMPL;
|
||||
|
||||
CBindInfoEx bindInfo;
|
||||
Convert_FolderInfo_to_BindInfo(folderInfo, bindInfo);
|
||||
if (!bindInfo.CalcMapsAndCheck())
|
||||
return E_NOTIMPL;
|
||||
|
||||
UInt64 folderUnpackSize = folders.GetFolderUnpackSize(folderIndex);
|
||||
bool fullUnpack = true;
|
||||
if (unpackSize)
|
||||
{
|
||||
if (*unpackSize > folderUnpackSize)
|
||||
return E_FAIL;
|
||||
fullUnpack = (*unpackSize == folderUnpackSize);
|
||||
}
|
||||
|
||||
/*
|
||||
We don't need to init isEncrypted and passwordIsDefined
|
||||
We must upgrade them only
|
||||
|
||||
#ifndef _NO_CRYPTO
|
||||
isEncrypted = false;
|
||||
passwordIsDefined = false;
|
||||
#endif
|
||||
*/
|
||||
|
||||
if (!_bindInfoPrev_Defined || !AreBindInfoExEqual(bindInfo, _bindInfoPrev))
|
||||
{
|
||||
_mixerRef.Release();
|
||||
|
||||
#ifdef USE_MIXER_MT
|
||||
#ifdef USE_MIXER_ST
|
||||
if (_useMixerMT)
|
||||
#endif
|
||||
{
|
||||
_mixerMT = new NCoderMixer2::CMixerMT(false);
|
||||
_mixerRef = _mixerMT;
|
||||
_mixer = _mixerMT;
|
||||
}
|
||||
#ifdef USE_MIXER_ST
|
||||
else
|
||||
#endif
|
||||
#endif
|
||||
{
|
||||
#ifdef USE_MIXER_ST
|
||||
_mixerST = new NCoderMixer2::CMixerST(false);
|
||||
_mixerRef = _mixerST;
|
||||
_mixer = _mixerST;
|
||||
#endif
|
||||
}
|
||||
|
||||
RINOK(_mixer->SetBindInfo(bindInfo));
|
||||
|
||||
FOR_VECTOR(i, folderInfo.Coders)
|
||||
{
|
||||
const CCoderInfo &coderInfo = folderInfo.Coders[i];
|
||||
|
||||
#ifndef _SFX
|
||||
// we don't support RAR codecs here
|
||||
if ((coderInfo.MethodID >> 8) == 0x403)
|
||||
return E_NOTIMPL;
|
||||
#endif
|
||||
|
||||
CCreatedCoder cod;
|
||||
RINOK(CreateCoder(
|
||||
EXTERNAL_CODECS_LOC_VARS
|
||||
coderInfo.MethodID, false, cod));
|
||||
|
||||
if (coderInfo.IsSimpleCoder())
|
||||
{
|
||||
if (!cod.Coder)
|
||||
return E_NOTIMPL;
|
||||
// CMethodId m = coderInfo.MethodID;
|
||||
// isFilter = (IsFilterMethod(m) || m == k_AES);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!cod.Coder2 || cod.NumStreams != coderInfo.NumStreams)
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
_mixer->AddCoder(cod);
|
||||
|
||||
// now there is no codec that uses another external codec
|
||||
/*
|
||||
#ifdef EXTERNAL_CODECS
|
||||
CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo;
|
||||
decoderUnknown.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo);
|
||||
if (setCompressCodecsInfo)
|
||||
{
|
||||
// we must use g_ExternalCodecs also
|
||||
RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(__externalCodecs->GetCodecs));
|
||||
}
|
||||
#endif
|
||||
*/
|
||||
}
|
||||
|
||||
_bindInfoPrev = bindInfo;
|
||||
_bindInfoPrev_Defined = true;
|
||||
}
|
||||
|
||||
_mixer->ReInit();
|
||||
|
||||
UInt32 packStreamIndex = 0;
|
||||
UInt32 unpackStreamIndexStart = folders.FoToCoderUnpackSizes[folderIndex];
|
||||
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < folderInfo.Coders.Size(); i++)
|
||||
{
|
||||
const CCoderInfo &coderInfo = folderInfo.Coders[i];
|
||||
IUnknown *decoder = _mixer->GetCoder(i).GetUnknown();
|
||||
|
||||
{
|
||||
CMyComPtr<ICompressSetDecoderProperties2> setDecoderProperties;
|
||||
decoder->QueryInterface(IID_ICompressSetDecoderProperties2, (void **)&setDecoderProperties);
|
||||
if (setDecoderProperties)
|
||||
{
|
||||
const CByteBuffer &props = coderInfo.Props;
|
||||
size_t size = props.Size();
|
||||
if (size > 0xFFFFFFFF)
|
||||
return E_NOTIMPL;
|
||||
HRESULT res = setDecoderProperties->SetDecoderProperties2((const Byte *)props, (UInt32)size);
|
||||
if (res == E_INVALIDARG)
|
||||
res = E_NOTIMPL;
|
||||
RINOK(res);
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(_7ZIP_ST) && !defined(_SFX)
|
||||
if (mtMode)
|
||||
{
|
||||
CMyComPtr<ICompressSetCoderMt> setCoderMt;
|
||||
decoder->QueryInterface(IID_ICompressSetCoderMt, (void **)&setCoderMt);
|
||||
if (setCoderMt)
|
||||
{
|
||||
RINOK(setCoderMt->SetNumberOfThreads(numThreads));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef _NO_CRYPTO
|
||||
{
|
||||
CMyComPtr<ICryptoSetPassword> cryptoSetPassword;
|
||||
decoder->QueryInterface(IID_ICryptoSetPassword, (void **)&cryptoSetPassword);
|
||||
if (cryptoSetPassword)
|
||||
{
|
||||
isEncrypted = true;
|
||||
if (!getTextPassword)
|
||||
return E_NOTIMPL;
|
||||
CMyComBSTR passwordBSTR;
|
||||
RINOK(getTextPassword->CryptoGetTextPassword(&passwordBSTR));
|
||||
passwordIsDefined = true;
|
||||
password.Empty();
|
||||
size_t len = 0;
|
||||
if (passwordBSTR)
|
||||
{
|
||||
password = passwordBSTR;
|
||||
len = password.Len();
|
||||
}
|
||||
CByteBuffer buffer(len * 2);
|
||||
for (size_t k = 0; k < len; k++)
|
||||
{
|
||||
wchar_t c = passwordBSTR[k];
|
||||
((Byte *)buffer)[k * 2] = (Byte)c;
|
||||
((Byte *)buffer)[k * 2 + 1] = (Byte)(c >> 8);
|
||||
}
|
||||
RINOK(cryptoSetPassword->CryptoSetPassword((const Byte *)buffer, (UInt32)buffer.Size()));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
{
|
||||
CMyComPtr<ICompressSetFinishMode> setFinishMode;
|
||||
decoder->QueryInterface(IID_ICompressSetFinishMode, (void **)&setFinishMode);
|
||||
if (setFinishMode)
|
||||
{
|
||||
RINOK(setFinishMode->SetFinishMode(BoolToInt(fullUnpack)));
|
||||
}
|
||||
}
|
||||
|
||||
UInt32 numStreams = (UInt32)coderInfo.NumStreams;
|
||||
|
||||
CObjArray<UInt64> packSizes(numStreams);
|
||||
CObjArray<const UInt64 *> packSizesPointers(numStreams);
|
||||
|
||||
for (UInt32 j = 0; j < numStreams; j++, packStreamIndex++)
|
||||
{
|
||||
int bond = folderInfo.FindBond_for_PackStream(packStreamIndex);
|
||||
|
||||
if (bond >= 0)
|
||||
packSizesPointers[j] = &folders.CoderUnpackSizes[unpackStreamIndexStart + folderInfo.Bonds[(unsigned)bond].UnpackIndex];
|
||||
else
|
||||
{
|
||||
int index = folderInfo.Find_in_PackStreams(packStreamIndex);
|
||||
if (index < 0)
|
||||
return E_NOTIMPL;
|
||||
packSizes[j] = packPositions[(unsigned)index + 1] - packPositions[(unsigned)index];
|
||||
packSizesPointers[j] = &packSizes[j];
|
||||
}
|
||||
}
|
||||
|
||||
const UInt64 *unpackSizesPointer =
|
||||
(unpackSize && i == bindInfo.UnpackCoder) ?
|
||||
unpackSize :
|
||||
&folders.CoderUnpackSizes[unpackStreamIndexStart + i];
|
||||
|
||||
_mixer->SetCoderInfo(i, unpackSizesPointer, packSizesPointers);
|
||||
}
|
||||
|
||||
if (outStream)
|
||||
{
|
||||
_mixer->SelectMainCoder(!fullUnpack);
|
||||
}
|
||||
|
||||
CObjectVector< CMyComPtr<ISequentialInStream> > inStreams;
|
||||
|
||||
CLockedInStream *lockedInStreamSpec = new CLockedInStream;
|
||||
CMyComPtr<IUnknown> lockedInStream = lockedInStreamSpec;
|
||||
|
||||
bool needMtLock = false;
|
||||
|
||||
if (folderInfo.PackStreams.Size() > 1)
|
||||
{
|
||||
// lockedInStream.Pos = (UInt64)(Int64)-1;
|
||||
// RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &lockedInStream.Pos));
|
||||
RINOK(inStream->Seek(startPos + packPositions[0], STREAM_SEEK_SET, &lockedInStreamSpec->Pos));
|
||||
lockedInStreamSpec->Stream = inStream;
|
||||
|
||||
#ifdef USE_MIXER_ST
|
||||
if (_mixer->IsThere_ExternalCoder_in_PackTree(_mixer->MainCoderIndex))
|
||||
#endif
|
||||
needMtLock = true;
|
||||
}
|
||||
|
||||
for (unsigned j = 0; j < folderInfo.PackStreams.Size(); j++)
|
||||
{
|
||||
CMyComPtr<ISequentialInStream> packStream;
|
||||
UInt64 packPos = startPos + packPositions[j];
|
||||
|
||||
if (folderInfo.PackStreams.Size() == 1)
|
||||
{
|
||||
RINOK(inStream->Seek(packPos, STREAM_SEEK_SET, NULL));
|
||||
packStream = inStream;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef USE_MIXER_MT
|
||||
#ifdef USE_MIXER_ST
|
||||
if (_useMixerMT || needMtLock)
|
||||
#endif
|
||||
{
|
||||
CLockedSequentialInStreamMT *lockedStreamImpSpec = new CLockedSequentialInStreamMT;
|
||||
packStream = lockedStreamImpSpec;
|
||||
lockedStreamImpSpec->Init(lockedInStreamSpec, packPos);
|
||||
}
|
||||
#ifdef USE_MIXER_ST
|
||||
else
|
||||
#endif
|
||||
#endif
|
||||
{
|
||||
#ifdef USE_MIXER_ST
|
||||
CLockedSequentialInStreamST *lockedStreamImpSpec = new CLockedSequentialInStreamST;
|
||||
packStream = lockedStreamImpSpec;
|
||||
lockedStreamImpSpec->Init(lockedInStreamSpec, packPos);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
|
||||
inStreams.AddNew() = streamSpec;
|
||||
streamSpec->SetStream(packStream);
|
||||
streamSpec->Init(packPositions[j + 1] - packPositions[j]);
|
||||
}
|
||||
|
||||
unsigned num = inStreams.Size();
|
||||
CObjArray<ISequentialInStream *> inStreamPointers(num);
|
||||
for (i = 0; i < num; i++)
|
||||
inStreamPointers[i] = inStreams[i];
|
||||
|
||||
if (outStream)
|
||||
{
|
||||
CMyComPtr<ICompressProgressInfo> progress2;
|
||||
if (compressProgress && !_mixer->Is_PackSize_Correct_for_Coder(_mixer->MainCoderIndex))
|
||||
progress2 = new CDecProgress(compressProgress);
|
||||
|
||||
ISequentialOutStream *outStreamPointer = outStream;
|
||||
return _mixer->Code(inStreamPointers, &outStreamPointer, progress2 ? (ICompressProgressInfo *)progress2 : compressProgress);
|
||||
}
|
||||
|
||||
#ifdef USE_MIXER_ST
|
||||
return _mixerST->GetMainUnpackStream(inStreamPointers, inStreamMainRes);
|
||||
#else
|
||||
return E_FAIL;
|
||||
#endif
|
||||
}
|
||||
|
||||
}}
|
68
CPP/7zip/Archive/7z/7zDecode.h
Normal file
68
CPP/7zip/Archive/7z/7zDecode.h
Normal file
@ -0,0 +1,68 @@
|
||||
// 7zDecode.h
|
||||
|
||||
#ifndef __7Z_DECODE_H
|
||||
#define __7Z_DECODE_H
|
||||
|
||||
#include "../Common/CoderMixer2.h"
|
||||
|
||||
#include "7zIn.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace N7z {
|
||||
|
||||
struct CBindInfoEx: public NCoderMixer2::CBindInfo
|
||||
{
|
||||
CRecordVector<CMethodId> CoderMethodIDs;
|
||||
|
||||
void Clear()
|
||||
{
|
||||
CBindInfo::Clear();
|
||||
CoderMethodIDs.Clear();
|
||||
}
|
||||
};
|
||||
|
||||
class CDecoder
|
||||
{
|
||||
bool _bindInfoPrev_Defined;
|
||||
CBindInfoEx _bindInfoPrev;
|
||||
|
||||
bool _useMixerMT;
|
||||
|
||||
#ifdef USE_MIXER_ST
|
||||
NCoderMixer2::CMixerST *_mixerST;
|
||||
#endif
|
||||
|
||||
#ifdef USE_MIXER_MT
|
||||
NCoderMixer2::CMixerMT *_mixerMT;
|
||||
#endif
|
||||
|
||||
NCoderMixer2::CMixer *_mixer;
|
||||
CMyComPtr<IUnknown> _mixerRef;
|
||||
|
||||
public:
|
||||
|
||||
CDecoder(bool useMixerMT);
|
||||
|
||||
HRESULT Decode(
|
||||
DECL_EXTERNAL_CODECS_LOC_VARS
|
||||
IInStream *inStream,
|
||||
UInt64 startPos,
|
||||
const CFolders &folders, unsigned folderIndex,
|
||||
const UInt64 *unpackSize // if (!unpackSize), then full folder is required
|
||||
// if (unpackSize), then only *unpackSize bytes from folder are required
|
||||
|
||||
, ISequentialOutStream *outStream
|
||||
, ICompressProgressInfo *compressProgress
|
||||
, ISequentialInStream **inStreamMainRes
|
||||
|
||||
_7Z_DECODER_CRYPRO_VARS_DECL
|
||||
|
||||
#if !defined(_7ZIP_ST) && !defined(_SFX)
|
||||
, bool mtMode, UInt32 numThreads
|
||||
#endif
|
||||
);
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
656
CPP/7zip/Archive/7z/7zEncode.cpp
Normal file
656
CPP/7zip/Archive/7z/7zEncode.cpp
Normal file
@ -0,0 +1,656 @@
|
||||
// 7zEncode.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../Common/CreateCoder.h"
|
||||
#include "../../Common/FilterCoder.h"
|
||||
#include "../../Common/LimitedStreams.h"
|
||||
#include "../../Common/InOutTempBuffer.h"
|
||||
#include "../../Common/ProgressUtils.h"
|
||||
#include "../../Common/StreamObjects.h"
|
||||
|
||||
#include "7zEncode.h"
|
||||
#include "7zSpecStream.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace N7z {
|
||||
|
||||
void CEncoder::InitBindConv()
|
||||
{
|
||||
unsigned numIn = _bindInfo.Coders.Size();
|
||||
|
||||
_SrcIn_to_DestOut.ClearAndSetSize(numIn);
|
||||
_DestOut_to_SrcIn.ClearAndSetSize(numIn);
|
||||
|
||||
unsigned numOut = _bindInfo.GetNum_Bonds_and_PackStreams();
|
||||
_SrcOut_to_DestIn.ClearAndSetSize(numOut);
|
||||
// _DestIn_to_SrcOut.ClearAndSetSize(numOut);
|
||||
|
||||
UInt32 destIn = 0;
|
||||
UInt32 destOut = 0;
|
||||
|
||||
for (unsigned i = _bindInfo.Coders.Size(); i != 0;)
|
||||
{
|
||||
i--;
|
||||
|
||||
const NCoderMixer2::CCoderStreamsInfo &coder = _bindInfo.Coders[i];
|
||||
|
||||
numIn--;
|
||||
numOut -= coder.NumStreams;
|
||||
|
||||
_SrcIn_to_DestOut[numIn] = destOut;
|
||||
_DestOut_to_SrcIn[destOut] = numIn;
|
||||
|
||||
destOut++;
|
||||
|
||||
for (UInt32 j = 0; j < coder.NumStreams; j++, destIn++)
|
||||
{
|
||||
UInt32 index = numOut + j;
|
||||
_SrcOut_to_DestIn[index] = destIn;
|
||||
// _DestIn_to_SrcOut[destIn] = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CEncoder::SetFolder(CFolder &folder)
|
||||
{
|
||||
folder.Bonds.SetSize(_bindInfo.Bonds.Size());
|
||||
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < _bindInfo.Bonds.Size(); i++)
|
||||
{
|
||||
CBond &fb = folder.Bonds[i];
|
||||
const NCoderMixer2::CBond &mixerBond = _bindInfo.Bonds[_bindInfo.Bonds.Size() - 1 - i];
|
||||
fb.PackIndex = _SrcOut_to_DestIn[mixerBond.PackIndex];
|
||||
fb.UnpackIndex = _SrcIn_to_DestOut[mixerBond.UnpackIndex];
|
||||
}
|
||||
|
||||
folder.Coders.SetSize(_bindInfo.Coders.Size());
|
||||
|
||||
for (i = 0; i < _bindInfo.Coders.Size(); i++)
|
||||
{
|
||||
CCoderInfo &coderInfo = folder.Coders[i];
|
||||
const NCoderMixer2::CCoderStreamsInfo &coderStreamsInfo = _bindInfo.Coders[_bindInfo.Coders.Size() - 1 - i];
|
||||
|
||||
coderInfo.NumStreams = coderStreamsInfo.NumStreams;
|
||||
coderInfo.MethodID = _decompressionMethods[i];
|
||||
// we don't free coderInfo.Props here. So coderInfo.Props can be non-empty.
|
||||
}
|
||||
|
||||
folder.PackStreams.SetSize(_bindInfo.PackStreams.Size());
|
||||
|
||||
for (i = 0; i < _bindInfo.PackStreams.Size(); i++)
|
||||
folder.PackStreams[i] = _SrcOut_to_DestIn[_bindInfo.PackStreams[i]];
|
||||
}
|
||||
|
||||
|
||||
|
||||
static HRESULT SetCoderProps2(const CProps &props, const UInt64 *dataSizeReduce, IUnknown *coder)
|
||||
{
|
||||
CMyComPtr<ICompressSetCoderProperties> setCoderProperties;
|
||||
coder->QueryInterface(IID_ICompressSetCoderProperties, (void **)&setCoderProperties);
|
||||
if (setCoderProperties)
|
||||
return props.SetCoderProps(setCoderProperties, dataSizeReduce);
|
||||
return props.AreThereNonOptionalProps() ? E_INVALIDARG : S_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CMtEncMultiProgress::Init(ICompressProgressInfo *progress)
|
||||
{
|
||||
_progress = progress;
|
||||
OutSize = 0;
|
||||
}
|
||||
|
||||
STDMETHODIMP CMtEncMultiProgress::SetRatioInfo(const UInt64 *inSize, const UInt64 * /* outSize */)
|
||||
{
|
||||
UInt64 outSize2;
|
||||
{
|
||||
#ifndef _7ZIP_ST
|
||||
NWindows::NSynchronization::CCriticalSectionLock lock(CriticalSection);
|
||||
#endif
|
||||
outSize2 = OutSize;
|
||||
}
|
||||
|
||||
if (_progress)
|
||||
return _progress->SetRatioInfo(inSize, &outSize2);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
HRESULT CEncoder::CreateMixerCoder(
|
||||
DECL_EXTERNAL_CODECS_LOC_VARS
|
||||
const UInt64 *inSizeForReduce)
|
||||
{
|
||||
#ifdef USE_MIXER_MT
|
||||
#ifdef USE_MIXER_ST
|
||||
if (_options.MultiThreadMixer)
|
||||
#endif
|
||||
{
|
||||
_mixerMT = new NCoderMixer2::CMixerMT(true);
|
||||
_mixerRef = _mixerMT;
|
||||
_mixer = _mixerMT;
|
||||
}
|
||||
#ifdef USE_MIXER_ST
|
||||
else
|
||||
#endif
|
||||
#endif
|
||||
{
|
||||
#ifdef USE_MIXER_ST
|
||||
_mixerST = new NCoderMixer2::CMixerST(true);
|
||||
_mixerRef = _mixerST;
|
||||
_mixer = _mixerST;
|
||||
#endif
|
||||
}
|
||||
|
||||
RINOK(_mixer->SetBindInfo(_bindInfo));
|
||||
|
||||
FOR_VECTOR (m, _options.Methods)
|
||||
{
|
||||
const CMethodFull &methodFull = _options.Methods[m];
|
||||
|
||||
CCreatedCoder cod;
|
||||
|
||||
RINOK(CreateCoder(
|
||||
EXTERNAL_CODECS_LOC_VARS
|
||||
methodFull.Id, true, cod));
|
||||
|
||||
if (cod.NumStreams != methodFull.NumStreams)
|
||||
return E_FAIL;
|
||||
if (!cod.Coder && !cod.Coder2)
|
||||
return E_FAIL;
|
||||
|
||||
CMyComPtr<IUnknown> encoderCommon = cod.Coder ? (IUnknown *)cod.Coder : (IUnknown *)cod.Coder2;
|
||||
|
||||
#ifndef _7ZIP_ST
|
||||
{
|
||||
CMyComPtr<ICompressSetCoderMt> setCoderMt;
|
||||
encoderCommon.QueryInterface(IID_ICompressSetCoderMt, &setCoderMt);
|
||||
if (setCoderMt)
|
||||
{
|
||||
RINOK(setCoderMt->SetNumberOfThreads(_options.NumThreads));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
RINOK(SetCoderProps2(methodFull, inSizeForReduce, encoderCommon));
|
||||
|
||||
/*
|
||||
CMyComPtr<ICryptoResetSalt> resetSalt;
|
||||
encoderCommon.QueryInterface(IID_ICryptoResetSalt, (void **)&resetSalt);
|
||||
if (resetSalt)
|
||||
{
|
||||
resetSalt->ResetSalt();
|
||||
}
|
||||
*/
|
||||
|
||||
// now there is no codec that uses another external codec
|
||||
/*
|
||||
#ifdef EXTERNAL_CODECS
|
||||
CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo;
|
||||
encoderCommon.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo);
|
||||
if (setCompressCodecsInfo)
|
||||
{
|
||||
// we must use g_ExternalCodecs also
|
||||
RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(__externalCodecs->GetCodecs));
|
||||
}
|
||||
#endif
|
||||
*/
|
||||
|
||||
CMyComPtr<ICryptoSetPassword> cryptoSetPassword;
|
||||
encoderCommon.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword);
|
||||
|
||||
if (cryptoSetPassword)
|
||||
{
|
||||
const unsigned sizeInBytes = _options.Password.Len() * 2;
|
||||
CByteBuffer buffer(sizeInBytes);
|
||||
for (unsigned i = 0; i < _options.Password.Len(); i++)
|
||||
{
|
||||
wchar_t c = _options.Password[i];
|
||||
((Byte *)buffer)[i * 2] = (Byte)c;
|
||||
((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8);
|
||||
}
|
||||
RINOK(cryptoSetPassword->CryptoSetPassword((const Byte *)buffer, (UInt32)sizeInBytes));
|
||||
}
|
||||
|
||||
_mixer->AddCoder(cod);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
class CSequentialOutTempBufferImp2:
|
||||
public ISequentialOutStream,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CInOutTempBuffer *_buf;
|
||||
public:
|
||||
CMtEncMultiProgress *_mtProgresSpec;
|
||||
|
||||
CSequentialOutTempBufferImp2(): _buf(0), _mtProgresSpec(NULL) {}
|
||||
void Init(CInOutTempBuffer *buffer) { _buf = buffer; }
|
||||
MY_UNKNOWN_IMP1(ISequentialOutStream)
|
||||
|
||||
STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
|
||||
};
|
||||
|
||||
STDMETHODIMP CSequentialOutTempBufferImp2::Write(const void *data, UInt32 size, UInt32 *processed)
|
||||
{
|
||||
if (!_buf->Write(data, size))
|
||||
{
|
||||
if (processed)
|
||||
*processed = 0;
|
||||
return E_FAIL;
|
||||
}
|
||||
if (processed)
|
||||
*processed = size;
|
||||
if (_mtProgresSpec)
|
||||
_mtProgresSpec->AddOutSize(size);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
class CSequentialOutMtNotify:
|
||||
public ISequentialOutStream,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
public:
|
||||
CMyComPtr<ISequentialOutStream> _stream;
|
||||
CMtEncMultiProgress *_mtProgresSpec;
|
||||
|
||||
CSequentialOutMtNotify(): _mtProgresSpec(NULL) {}
|
||||
MY_UNKNOWN_IMP1(ISequentialOutStream)
|
||||
|
||||
STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
|
||||
};
|
||||
|
||||
STDMETHODIMP CSequentialOutMtNotify::Write(const void *data, UInt32 size, UInt32 *processed)
|
||||
{
|
||||
UInt32 realProcessed = 0;
|
||||
HRESULT res = _stream->Write(data, size, &realProcessed);
|
||||
if (processed)
|
||||
*processed = realProcessed;
|
||||
if (_mtProgresSpec)
|
||||
_mtProgresSpec->AddOutSize(size);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
HRESULT CEncoder::Encode(
|
||||
DECL_EXTERNAL_CODECS_LOC_VARS
|
||||
ISequentialInStream *inStream,
|
||||
// const UInt64 *inStreamSize,
|
||||
const UInt64 *inSizeForReduce,
|
||||
CFolder &folderItem,
|
||||
CRecordVector<UInt64> &coderUnpackSizes,
|
||||
UInt64 &unpackSize,
|
||||
ISequentialOutStream *outStream,
|
||||
CRecordVector<UInt64> &packSizes,
|
||||
ICompressProgressInfo *compressProgress)
|
||||
{
|
||||
RINOK(EncoderConstr());
|
||||
|
||||
if (!_mixerRef)
|
||||
{
|
||||
RINOK(CreateMixerCoder(EXTERNAL_CODECS_LOC_VARS inSizeForReduce));
|
||||
}
|
||||
|
||||
_mixer->ReInit();
|
||||
|
||||
CMtEncMultiProgress *mtProgressSpec = NULL;
|
||||
CMyComPtr<ICompressProgressInfo> mtProgress;
|
||||
|
||||
CSequentialOutMtNotify *mtOutStreamNotifySpec = NULL;
|
||||
CMyComPtr<ISequentialOutStream> mtOutStreamNotify;
|
||||
|
||||
CObjectVector<CInOutTempBuffer> inOutTempBuffers;
|
||||
CObjectVector<CSequentialOutTempBufferImp2 *> tempBufferSpecs;
|
||||
CObjectVector<CMyComPtr<ISequentialOutStream> > tempBuffers;
|
||||
|
||||
unsigned numMethods = _bindInfo.Coders.Size();
|
||||
|
||||
unsigned i;
|
||||
|
||||
for (i = 1; i < _bindInfo.PackStreams.Size(); i++)
|
||||
{
|
||||
CInOutTempBuffer &iotb = inOutTempBuffers.AddNew();
|
||||
iotb.Create();
|
||||
iotb.InitWriting();
|
||||
}
|
||||
|
||||
for (i = 1; i < _bindInfo.PackStreams.Size(); i++)
|
||||
{
|
||||
CSequentialOutTempBufferImp2 *tempBufferSpec = new CSequentialOutTempBufferImp2;
|
||||
CMyComPtr<ISequentialOutStream> tempBuffer = tempBufferSpec;
|
||||
tempBufferSpec->Init(&inOutTempBuffers[i - 1]);
|
||||
tempBuffers.Add(tempBuffer);
|
||||
tempBufferSpecs.Add(tempBufferSpec);
|
||||
}
|
||||
|
||||
for (i = 0; i < numMethods; i++)
|
||||
_mixer->SetCoderInfo(i, NULL, NULL);
|
||||
|
||||
|
||||
/* inStreamSize can be used by BCJ2 to set optimal range of conversion.
|
||||
But current BCJ2 encoder uses also another way to check exact size of current file.
|
||||
So inStreamSize is not required. */
|
||||
|
||||
/*
|
||||
if (inStreamSize)
|
||||
_mixer->SetCoderInfo(_bindInfo.UnpackCoder, inStreamSize, NULL);
|
||||
*/
|
||||
|
||||
|
||||
CSequentialInStreamSizeCount2 *inStreamSizeCountSpec = new CSequentialInStreamSizeCount2;
|
||||
CMyComPtr<ISequentialInStream> inStreamSizeCount = inStreamSizeCountSpec;
|
||||
|
||||
CSequentialOutStreamSizeCount *outStreamSizeCountSpec = NULL;
|
||||
CMyComPtr<ISequentialOutStream> outStreamSizeCount;
|
||||
|
||||
inStreamSizeCountSpec->Init(inStream);
|
||||
|
||||
ISequentialInStream *inStreamPointer = inStreamSizeCount;
|
||||
CRecordVector<ISequentialOutStream *> outStreamPointers;
|
||||
|
||||
SetFolder(folderItem);
|
||||
|
||||
for (i = 0; i < numMethods; i++)
|
||||
{
|
||||
IUnknown *coder = _mixer->GetCoder(i).GetUnknown();
|
||||
|
||||
CMyComPtr<ICryptoResetInitVector> resetInitVector;
|
||||
coder->QueryInterface(IID_ICryptoResetInitVector, (void **)&resetInitVector);
|
||||
if (resetInitVector)
|
||||
{
|
||||
resetInitVector->ResetInitVector();
|
||||
}
|
||||
|
||||
CMyComPtr<ICompressWriteCoderProperties> writeCoderProperties;
|
||||
coder->QueryInterface(IID_ICompressWriteCoderProperties, (void **)&writeCoderProperties);
|
||||
|
||||
CByteBuffer &props = folderItem.Coders[numMethods - 1 - i].Props;
|
||||
|
||||
if (writeCoderProperties)
|
||||
{
|
||||
CDynBufSeqOutStream *outStreamSpec = new CDynBufSeqOutStream;
|
||||
CMyComPtr<ISequentialOutStream> dynOutStream(outStreamSpec);
|
||||
outStreamSpec->Init();
|
||||
writeCoderProperties->WriteCoderProperties(dynOutStream);
|
||||
outStreamSpec->CopyToBuffer(props);
|
||||
}
|
||||
else
|
||||
props.Free();
|
||||
}
|
||||
|
||||
_mixer->SelectMainCoder(false);
|
||||
UInt32 mainCoder = _mixer->MainCoderIndex;
|
||||
|
||||
bool useMtProgress = false;
|
||||
if (!_mixer->Is_PackSize_Correct_for_Coder(mainCoder))
|
||||
{
|
||||
#ifdef _7ZIP_ST
|
||||
if (!_mixer->IsThere_ExternalCoder_in_PackTree(mainCoder))
|
||||
#endif
|
||||
useMtProgress = true;
|
||||
}
|
||||
|
||||
if (useMtProgress)
|
||||
{
|
||||
mtProgressSpec = new CMtEncMultiProgress;
|
||||
mtProgress = mtProgressSpec;
|
||||
mtProgressSpec->Init(compressProgress);
|
||||
|
||||
mtOutStreamNotifySpec = new CSequentialOutMtNotify;
|
||||
mtOutStreamNotify = mtOutStreamNotifySpec;
|
||||
mtOutStreamNotifySpec->_stream = outStream;
|
||||
mtOutStreamNotifySpec->_mtProgresSpec = mtProgressSpec;
|
||||
|
||||
FOR_VECTOR(t, tempBufferSpecs)
|
||||
{
|
||||
tempBufferSpecs[t]->_mtProgresSpec = mtProgressSpec;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (_bindInfo.PackStreams.Size() != 0)
|
||||
{
|
||||
outStreamSizeCountSpec = new CSequentialOutStreamSizeCount;
|
||||
outStreamSizeCount = outStreamSizeCountSpec;
|
||||
outStreamSizeCountSpec->SetStream(mtOutStreamNotify ? (ISequentialOutStream *)mtOutStreamNotify : outStream);
|
||||
outStreamSizeCountSpec->Init();
|
||||
outStreamPointers.Add(outStreamSizeCount);
|
||||
}
|
||||
|
||||
for (i = 1; i < _bindInfo.PackStreams.Size(); i++)
|
||||
outStreamPointers.Add(tempBuffers[i - 1]);
|
||||
|
||||
RINOK(_mixer->Code(
|
||||
&inStreamPointer,
|
||||
&outStreamPointers.Front(),
|
||||
mtProgress ? (ICompressProgressInfo *)mtProgress : compressProgress));
|
||||
|
||||
if (_bindInfo.PackStreams.Size() != 0)
|
||||
packSizes.Add(outStreamSizeCountSpec->GetSize());
|
||||
|
||||
for (i = 1; i < _bindInfo.PackStreams.Size(); i++)
|
||||
{
|
||||
CInOutTempBuffer &inOutTempBuffer = inOutTempBuffers[i - 1];
|
||||
RINOK(inOutTempBuffer.WriteToStream(outStream));
|
||||
packSizes.Add(inOutTempBuffer.GetDataSize());
|
||||
}
|
||||
|
||||
unpackSize = 0;
|
||||
|
||||
for (i = 0; i < _bindInfo.Coders.Size(); i++)
|
||||
{
|
||||
int bond = _bindInfo.FindBond_for_UnpackStream(_DestOut_to_SrcIn[i]);
|
||||
UInt64 streamSize;
|
||||
if (bond < 0)
|
||||
{
|
||||
streamSize = inStreamSizeCountSpec->GetSize();
|
||||
unpackSize = streamSize;
|
||||
}
|
||||
else
|
||||
streamSize = _mixer->GetBondStreamSize(bond);
|
||||
coderUnpackSizes.Add(streamSize);
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
CEncoder::CEncoder(const CCompressionMethodMode &options):
|
||||
_constructed(false)
|
||||
{
|
||||
if (options.IsEmpty())
|
||||
throw 1;
|
||||
|
||||
_options = options;
|
||||
|
||||
#ifdef USE_MIXER_ST
|
||||
_mixerST = NULL;
|
||||
#endif
|
||||
|
||||
#ifdef USE_MIXER_MT
|
||||
_mixerMT = NULL;
|
||||
#endif
|
||||
|
||||
_mixer = NULL;
|
||||
}
|
||||
|
||||
|
||||
HRESULT CEncoder::EncoderConstr()
|
||||
{
|
||||
if (_constructed)
|
||||
return S_OK;
|
||||
if (_options.Methods.IsEmpty())
|
||||
{
|
||||
// it has only password method;
|
||||
if (!_options.PasswordIsDefined)
|
||||
throw 1;
|
||||
if (!_options.Bonds.IsEmpty())
|
||||
throw 1;
|
||||
|
||||
CMethodFull method;
|
||||
method.Id = k_AES;
|
||||
method.NumStreams = 1;
|
||||
_options.Methods.Add(method);
|
||||
|
||||
NCoderMixer2::CCoderStreamsInfo coderStreamsInfo;
|
||||
coderStreamsInfo.NumStreams = 1;
|
||||
_bindInfo.Coders.Add(coderStreamsInfo);
|
||||
|
||||
_bindInfo.PackStreams.Add(0);
|
||||
_bindInfo.UnpackCoder = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
UInt32 numOutStreams = 0;
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < _options.Methods.Size(); i++)
|
||||
{
|
||||
const CMethodFull &methodFull = _options.Methods[i];
|
||||
NCoderMixer2::CCoderStreamsInfo cod;
|
||||
|
||||
cod.NumStreams = methodFull.NumStreams;
|
||||
|
||||
if (_options.Bonds.IsEmpty())
|
||||
{
|
||||
// if there are no bonds in options, we create bonds via first streams of coders
|
||||
if (i != _options.Methods.Size() - 1)
|
||||
{
|
||||
NCoderMixer2::CBond bond;
|
||||
bond.PackIndex = numOutStreams;
|
||||
bond.UnpackIndex = i + 1; // it's next coder
|
||||
_bindInfo.Bonds.Add(bond);
|
||||
}
|
||||
else if (cod.NumStreams != 0)
|
||||
_bindInfo.PackStreams.Insert(0, numOutStreams);
|
||||
|
||||
for (UInt32 j = 1; j < cod.NumStreams; j++)
|
||||
_bindInfo.PackStreams.Add(numOutStreams + j);
|
||||
}
|
||||
|
||||
numOutStreams += cod.NumStreams;
|
||||
|
||||
_bindInfo.Coders.Add(cod);
|
||||
}
|
||||
|
||||
if (!_options.Bonds.IsEmpty())
|
||||
{
|
||||
for (i = 0; i < _options.Bonds.Size(); i++)
|
||||
{
|
||||
NCoderMixer2::CBond mixerBond;
|
||||
const CBond2 &bond = _options.Bonds[i];
|
||||
if (bond.InCoder >= _bindInfo.Coders.Size()
|
||||
|| bond.OutCoder >= _bindInfo.Coders.Size()
|
||||
|| bond.OutStream >= _bindInfo.Coders[bond.OutCoder].NumStreams)
|
||||
return E_INVALIDARG;
|
||||
mixerBond.PackIndex = _bindInfo.GetStream_for_Coder(bond.OutCoder) + bond.OutStream;
|
||||
mixerBond.UnpackIndex = bond.InCoder;
|
||||
_bindInfo.Bonds.Add(mixerBond);
|
||||
}
|
||||
|
||||
for (i = 0; i < numOutStreams; i++)
|
||||
if (_bindInfo.FindBond_for_PackStream(i) == -1)
|
||||
_bindInfo.PackStreams.Add(i);
|
||||
}
|
||||
|
||||
if (!_bindInfo.SetUnpackCoder())
|
||||
return E_INVALIDARG;
|
||||
|
||||
if (!_bindInfo.CalcMapsAndCheck())
|
||||
return E_INVALIDARG;
|
||||
|
||||
if (_bindInfo.PackStreams.Size() != 1)
|
||||
{
|
||||
/* main_PackStream is pack stream of main path of coders tree.
|
||||
We find main_PackStream, and place to start of list of out streams.
|
||||
It allows to use more optimal memory usage for temp buffers,
|
||||
if main_PackStream is largest stream. */
|
||||
|
||||
UInt32 ci = _bindInfo.UnpackCoder;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (_bindInfo.Coders[ci].NumStreams == 0)
|
||||
break;
|
||||
|
||||
UInt32 outIndex = _bindInfo.Coder_to_Stream[ci];
|
||||
int bond = _bindInfo.FindBond_for_PackStream(outIndex);
|
||||
if (bond >= 0)
|
||||
{
|
||||
ci = _bindInfo.Bonds[bond].UnpackIndex;
|
||||
continue;
|
||||
}
|
||||
|
||||
int si = _bindInfo.FindStream_in_PackStreams(outIndex);
|
||||
if (si >= 0)
|
||||
_bindInfo.PackStreams.MoveToFront(si);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (_options.PasswordIsDefined)
|
||||
{
|
||||
unsigned numCryptoStreams = _bindInfo.PackStreams.Size();
|
||||
|
||||
unsigned numInStreams = _bindInfo.Coders.Size();
|
||||
|
||||
for (i = 0; i < numCryptoStreams; i++)
|
||||
{
|
||||
NCoderMixer2::CBond bond;
|
||||
bond.UnpackIndex = numInStreams + i;
|
||||
bond.PackIndex = _bindInfo.PackStreams[i];
|
||||
_bindInfo.Bonds.Add(bond);
|
||||
}
|
||||
_bindInfo.PackStreams.Clear();
|
||||
|
||||
/*
|
||||
if (numCryptoStreams == 0)
|
||||
numCryptoStreams = 1;
|
||||
*/
|
||||
|
||||
for (i = 0; i < numCryptoStreams; i++)
|
||||
{
|
||||
CMethodFull method;
|
||||
method.NumStreams = 1;
|
||||
method.Id = k_AES;
|
||||
_options.Methods.Add(method);
|
||||
|
||||
NCoderMixer2::CCoderStreamsInfo cod;
|
||||
cod.NumStreams = 1;
|
||||
_bindInfo.Coders.Add(cod);
|
||||
|
||||
_bindInfo.PackStreams.Add(numOutStreams++);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (unsigned i = _options.Methods.Size(); i != 0;)
|
||||
_decompressionMethods.Add(_options.Methods[--i].Id);
|
||||
|
||||
if (_bindInfo.Coders.Size() > 16)
|
||||
return E_INVALIDARG;
|
||||
if (_bindInfo.GetNum_Bonds_and_PackStreams() > 16)
|
||||
return E_INVALIDARG;
|
||||
|
||||
if (!_bindInfo.CalcMapsAndCheck())
|
||||
return E_INVALIDARG;
|
||||
|
||||
InitBindConv();
|
||||
_constructed = true;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
CEncoder::~CEncoder() {}
|
||||
|
||||
}}
|
92
CPP/7zip/Archive/7z/7zEncode.h
Normal file
92
CPP/7zip/Archive/7z/7zEncode.h
Normal file
@ -0,0 +1,92 @@
|
||||
// 7zEncode.h
|
||||
|
||||
#ifndef __7Z_ENCODE_H
|
||||
#define __7Z_ENCODE_H
|
||||
|
||||
#include "7zCompressionMode.h"
|
||||
|
||||
#include "../Common/CoderMixer2.h"
|
||||
|
||||
#include "7zItem.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace N7z {
|
||||
|
||||
class CMtEncMultiProgress:
|
||||
public ICompressProgressInfo,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CMyComPtr<ICompressProgressInfo> _progress;
|
||||
#ifndef _7ZIP_ST
|
||||
NWindows::NSynchronization::CCriticalSection CriticalSection;
|
||||
#endif
|
||||
|
||||
public:
|
||||
UInt64 OutSize;
|
||||
|
||||
CMtEncMultiProgress(): OutSize(0) {}
|
||||
|
||||
void Init(ICompressProgressInfo *progress);
|
||||
|
||||
void AddOutSize(UInt64 addOutSize)
|
||||
{
|
||||
#ifndef _7ZIP_ST
|
||||
NWindows::NSynchronization::CCriticalSectionLock lock(CriticalSection);
|
||||
#endif
|
||||
OutSize += addOutSize;
|
||||
}
|
||||
|
||||
MY_UNKNOWN_IMP1(ICompressProgressInfo)
|
||||
|
||||
STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
|
||||
};
|
||||
|
||||
class CEncoder
|
||||
{
|
||||
#ifdef USE_MIXER_ST
|
||||
NCoderMixer2::CMixerST *_mixerST;
|
||||
#endif
|
||||
#ifdef USE_MIXER_MT
|
||||
NCoderMixer2::CMixerMT *_mixerMT;
|
||||
#endif
|
||||
|
||||
NCoderMixer2::CMixer *_mixer;
|
||||
CMyComPtr<IUnknown> _mixerRef;
|
||||
|
||||
CCompressionMethodMode _options;
|
||||
NCoderMixer2::CBindInfo _bindInfo;
|
||||
CRecordVector<CMethodId> _decompressionMethods;
|
||||
|
||||
CRecordVector<UInt32> _SrcIn_to_DestOut;
|
||||
CRecordVector<UInt32> _SrcOut_to_DestIn;
|
||||
// CRecordVector<UInt32> _DestIn_to_SrcOut;
|
||||
CRecordVector<UInt32> _DestOut_to_SrcIn;
|
||||
|
||||
void InitBindConv();
|
||||
void SetFolder(CFolder &folder);
|
||||
|
||||
HRESULT CreateMixerCoder(DECL_EXTERNAL_CODECS_LOC_VARS
|
||||
const UInt64 *inSizeForReduce);
|
||||
|
||||
bool _constructed;
|
||||
public:
|
||||
|
||||
CEncoder(const CCompressionMethodMode &options);
|
||||
~CEncoder();
|
||||
HRESULT EncoderConstr();
|
||||
HRESULT Encode(
|
||||
DECL_EXTERNAL_CODECS_LOC_VARS
|
||||
ISequentialInStream *inStream,
|
||||
// const UInt64 *inStreamSize,
|
||||
const UInt64 *inSizeForReduce,
|
||||
CFolder &folderItem,
|
||||
CRecordVector<UInt64> &coderUnpackSizes,
|
||||
UInt64 &unpackSize,
|
||||
ISequentialOutStream *outStream,
|
||||
CRecordVector<UInt64> &packSizes,
|
||||
ICompressProgressInfo *compressProgress);
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
408
CPP/7zip/Archive/7z/7zExtract.cpp
Normal file
408
CPP/7zip/Archive/7z/7zExtract.cpp
Normal file
@ -0,0 +1,408 @@
|
||||
// 7zExtract.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../../C/7zCrc.h"
|
||||
|
||||
#include "../../../Common/ComTry.h"
|
||||
|
||||
#include "../../Common/ProgressUtils.h"
|
||||
|
||||
#include "7zDecode.h"
|
||||
#include "7zHandler.h"
|
||||
|
||||
// EXTERN_g_ExternalCodecs
|
||||
|
||||
namespace NArchive {
|
||||
namespace N7z {
|
||||
|
||||
class CFolderOutStream:
|
||||
public ISequentialOutStream,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CMyComPtr<ISequentialOutStream> _stream;
|
||||
public:
|
||||
bool TestMode;
|
||||
bool CheckCrc;
|
||||
private:
|
||||
bool _fileIsOpen;
|
||||
bool _calcCrc;
|
||||
UInt32 _crc;
|
||||
UInt64 _rem;
|
||||
|
||||
const UInt32 *_indexes;
|
||||
unsigned _numFiles;
|
||||
unsigned _fileIndex;
|
||||
|
||||
HRESULT OpenFile(bool isCorrupted = false);
|
||||
HRESULT CloseFile_and_SetResult(Int32 res);
|
||||
HRESULT CloseFile();
|
||||
HRESULT ProcessEmptyFiles();
|
||||
|
||||
public:
|
||||
MY_UNKNOWN_IMP1(ISequentialOutStream)
|
||||
|
||||
const CDbEx *_db;
|
||||
CMyComPtr<IArchiveExtractCallback> ExtractCallback;
|
||||
|
||||
bool ExtraWriteWasCut;
|
||||
|
||||
CFolderOutStream():
|
||||
TestMode(false),
|
||||
CheckCrc(true)
|
||||
{}
|
||||
|
||||
STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
|
||||
|
||||
HRESULT Init(unsigned startIndex, const UInt32 *indexes, unsigned numFiles);
|
||||
HRESULT FlushCorrupted(Int32 callbackOperationResult);
|
||||
|
||||
bool WasWritingFinished() const { return _numFiles == 0; }
|
||||
};
|
||||
|
||||
|
||||
HRESULT CFolderOutStream::Init(unsigned startIndex, const UInt32 *indexes, unsigned numFiles)
|
||||
{
|
||||
_fileIndex = startIndex;
|
||||
_indexes = indexes;
|
||||
_numFiles = numFiles;
|
||||
|
||||
_fileIsOpen = false;
|
||||
ExtraWriteWasCut = false;
|
||||
|
||||
return ProcessEmptyFiles();
|
||||
}
|
||||
|
||||
HRESULT CFolderOutStream::OpenFile(bool isCorrupted)
|
||||
{
|
||||
const CFileItem &fi = _db->Files[_fileIndex];
|
||||
UInt32 nextFileIndex = (_indexes ? *_indexes : _fileIndex);
|
||||
Int32 askMode = (_fileIndex == nextFileIndex) ?
|
||||
(TestMode ?
|
||||
NExtract::NAskMode::kTest :
|
||||
NExtract::NAskMode::kExtract) :
|
||||
NExtract::NAskMode::kSkip;
|
||||
|
||||
if (isCorrupted
|
||||
&& askMode == NExtract::NAskMode::kExtract
|
||||
&& !_db->IsItemAnti(_fileIndex)
|
||||
&& !fi.IsDir)
|
||||
askMode = NExtract::NAskMode::kTest;
|
||||
|
||||
CMyComPtr<ISequentialOutStream> realOutStream;
|
||||
RINOK(ExtractCallback->GetStream(_fileIndex, &realOutStream, askMode));
|
||||
|
||||
_stream = realOutStream;
|
||||
_crc = CRC_INIT_VAL;
|
||||
_calcCrc = (CheckCrc && fi.CrcDefined && !fi.IsDir);
|
||||
|
||||
_fileIsOpen = true;
|
||||
_rem = fi.Size;
|
||||
|
||||
if (askMode == NExtract::NAskMode::kExtract
|
||||
&& !realOutStream
|
||||
&& !_db->IsItemAnti(_fileIndex)
|
||||
&& !fi.IsDir)
|
||||
askMode = NExtract::NAskMode::kSkip;
|
||||
return ExtractCallback->PrepareOperation(askMode);
|
||||
}
|
||||
|
||||
HRESULT CFolderOutStream::CloseFile_and_SetResult(Int32 res)
|
||||
{
|
||||
_stream.Release();
|
||||
_fileIsOpen = false;
|
||||
|
||||
if (!_indexes)
|
||||
_numFiles--;
|
||||
else if (*_indexes == _fileIndex)
|
||||
{
|
||||
_indexes++;
|
||||
_numFiles--;
|
||||
}
|
||||
|
||||
_fileIndex++;
|
||||
return ExtractCallback->SetOperationResult(res);
|
||||
}
|
||||
|
||||
HRESULT CFolderOutStream::CloseFile()
|
||||
{
|
||||
const CFileItem &fi = _db->Files[_fileIndex];
|
||||
return CloseFile_and_SetResult((!_calcCrc || fi.Crc == CRC_GET_DIGEST(_crc)) ?
|
||||
NExtract::NOperationResult::kOK :
|
||||
NExtract::NOperationResult::kCRCError);
|
||||
}
|
||||
|
||||
HRESULT CFolderOutStream::ProcessEmptyFiles()
|
||||
{
|
||||
while (_numFiles != 0 && _db->Files[_fileIndex].Size == 0)
|
||||
{
|
||||
RINOK(OpenFile());
|
||||
RINOK(CloseFile());
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CFolderOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
|
||||
{
|
||||
if (processedSize)
|
||||
*processedSize = 0;
|
||||
|
||||
while (size != 0)
|
||||
{
|
||||
if (_fileIsOpen)
|
||||
{
|
||||
UInt32 cur = (size < _rem ? size : (UInt32)_rem);
|
||||
HRESULT result = S_OK;
|
||||
if (_stream)
|
||||
result = _stream->Write(data, cur, &cur);
|
||||
if (_calcCrc)
|
||||
_crc = CrcUpdate(_crc, data, cur);
|
||||
if (processedSize)
|
||||
*processedSize += cur;
|
||||
data = (const Byte *)data + cur;
|
||||
size -= cur;
|
||||
_rem -= cur;
|
||||
if (_rem == 0)
|
||||
{
|
||||
RINOK(CloseFile());
|
||||
RINOK(ProcessEmptyFiles());
|
||||
}
|
||||
RINOK(result);
|
||||
if (cur == 0)
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
|
||||
RINOK(ProcessEmptyFiles());
|
||||
if (_numFiles == 0)
|
||||
{
|
||||
// we support partial extracting
|
||||
/*
|
||||
if (processedSize)
|
||||
*processedSize += size;
|
||||
break;
|
||||
*/
|
||||
ExtraWriteWasCut = true;
|
||||
// return S_FALSE;
|
||||
return k_My_HRESULT_WritingWasCut;
|
||||
}
|
||||
RINOK(OpenFile());
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CFolderOutStream::FlushCorrupted(Int32 callbackOperationResult)
|
||||
{
|
||||
while (_numFiles != 0)
|
||||
{
|
||||
if (_fileIsOpen)
|
||||
{
|
||||
RINOK(CloseFile_and_SetResult(callbackOperationResult));
|
||||
}
|
||||
else
|
||||
{
|
||||
RINOK(OpenFile(true));
|
||||
}
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
||||
Int32 testModeSpec, IArchiveExtractCallback *extractCallbackSpec)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
|
||||
CMyComPtr<IArchiveExtractCallback> extractCallback = extractCallbackSpec;
|
||||
|
||||
UInt64 importantTotalUnpacked = 0;
|
||||
|
||||
// numItems = (UInt32)(Int32)-1;
|
||||
|
||||
bool allFilesMode = (numItems == (UInt32)(Int32)-1);
|
||||
if (allFilesMode)
|
||||
numItems = _db.Files.Size();
|
||||
|
||||
if (numItems == 0)
|
||||
return S_OK;
|
||||
|
||||
{
|
||||
CNum prevFolder = kNumNoIndex;
|
||||
UInt32 nextFile = 0;
|
||||
|
||||
UInt32 i;
|
||||
|
||||
for (i = 0; i < numItems; i++)
|
||||
{
|
||||
UInt32 fileIndex = allFilesMode ? i : indices[i];
|
||||
CNum folderIndex = _db.FileIndexToFolderIndexMap[fileIndex];
|
||||
if (folderIndex == kNumNoIndex)
|
||||
continue;
|
||||
if (folderIndex != prevFolder || fileIndex < nextFile)
|
||||
nextFile = _db.FolderStartFileIndex[folderIndex];
|
||||
for (CNum index = nextFile; index <= fileIndex; index++)
|
||||
importantTotalUnpacked += _db.Files[index].Size;
|
||||
nextFile = fileIndex + 1;
|
||||
prevFolder = folderIndex;
|
||||
}
|
||||
}
|
||||
|
||||
RINOK(extractCallback->SetTotal(importantTotalUnpacked));
|
||||
|
||||
CLocalProgress *lps = new CLocalProgress;
|
||||
CMyComPtr<ICompressProgressInfo> progress = lps;
|
||||
lps->Init(extractCallback, false);
|
||||
|
||||
CDecoder decoder(
|
||||
#if !defined(USE_MIXER_MT)
|
||||
false
|
||||
#elif !defined(USE_MIXER_ST)
|
||||
true
|
||||
#elif !defined(__7Z_SET_PROPERTIES)
|
||||
#ifdef _7ZIP_ST
|
||||
false
|
||||
#else
|
||||
true
|
||||
#endif
|
||||
#else
|
||||
_useMultiThreadMixer
|
||||
#endif
|
||||
);
|
||||
|
||||
UInt64 curPacked, curUnpacked;
|
||||
|
||||
CMyComPtr<IArchiveExtractCallbackMessage> callbackMessage;
|
||||
extractCallback.QueryInterface(IID_IArchiveExtractCallbackMessage, &callbackMessage);
|
||||
|
||||
CFolderOutStream *folderOutStream = new CFolderOutStream;
|
||||
CMyComPtr<ISequentialOutStream> outStream(folderOutStream);
|
||||
|
||||
folderOutStream->_db = &_db;
|
||||
folderOutStream->ExtractCallback = extractCallback;
|
||||
folderOutStream->TestMode = (testModeSpec != 0);
|
||||
folderOutStream->CheckCrc = (_crcSize != 0);
|
||||
|
||||
for (UInt32 i = 0;; lps->OutSize += curUnpacked, lps->InSize += curPacked)
|
||||
{
|
||||
RINOK(lps->SetCur());
|
||||
|
||||
if (i >= numItems)
|
||||
break;
|
||||
|
||||
curUnpacked = 0;
|
||||
curPacked = 0;
|
||||
|
||||
UInt32 fileIndex = allFilesMode ? i : indices[i];
|
||||
CNum folderIndex = _db.FileIndexToFolderIndexMap[fileIndex];
|
||||
|
||||
UInt32 numSolidFiles = 1;
|
||||
|
||||
if (folderIndex != kNumNoIndex)
|
||||
{
|
||||
curPacked = _db.GetFolderFullPackSize(folderIndex);
|
||||
UInt32 nextFile = fileIndex + 1;
|
||||
fileIndex = _db.FolderStartFileIndex[folderIndex];
|
||||
UInt32 k;
|
||||
|
||||
for (k = i + 1; k < numItems; k++)
|
||||
{
|
||||
UInt32 fileIndex2 = allFilesMode ? k : indices[k];
|
||||
if (_db.FileIndexToFolderIndexMap[fileIndex2] != folderIndex
|
||||
|| fileIndex2 < nextFile)
|
||||
break;
|
||||
nextFile = fileIndex2 + 1;
|
||||
}
|
||||
|
||||
numSolidFiles = k - i;
|
||||
|
||||
for (k = fileIndex; k < nextFile; k++)
|
||||
curUnpacked += _db.Files[k].Size;
|
||||
}
|
||||
|
||||
{
|
||||
HRESULT result = folderOutStream->Init(fileIndex,
|
||||
allFilesMode ? NULL : indices + i,
|
||||
numSolidFiles);
|
||||
|
||||
i += numSolidFiles;
|
||||
|
||||
RINOK(result);
|
||||
}
|
||||
|
||||
// to test solid block with zero unpacked size we disable that code
|
||||
if (folderOutStream->WasWritingFinished())
|
||||
continue;
|
||||
|
||||
#ifndef _NO_CRYPTO
|
||||
CMyComPtr<ICryptoGetTextPassword> getTextPassword;
|
||||
if (extractCallback)
|
||||
extractCallback.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword);
|
||||
#endif
|
||||
|
||||
try
|
||||
{
|
||||
#ifndef _NO_CRYPTO
|
||||
bool isEncrypted = false;
|
||||
bool passwordIsDefined = false;
|
||||
UString password;
|
||||
#endif
|
||||
|
||||
|
||||
HRESULT result = decoder.Decode(
|
||||
EXTERNAL_CODECS_VARS
|
||||
_inStream,
|
||||
_db.ArcInfo.DataStartPosition,
|
||||
_db, folderIndex,
|
||||
&curUnpacked,
|
||||
|
||||
outStream,
|
||||
progress,
|
||||
NULL // *inStreamMainRes
|
||||
|
||||
_7Z_DECODER_CRYPRO_VARS
|
||||
#if !defined(_7ZIP_ST) && !defined(_SFX)
|
||||
, true, _numThreads
|
||||
#endif
|
||||
);
|
||||
|
||||
if (result == S_FALSE || result == E_NOTIMPL)
|
||||
{
|
||||
bool wasFinished = folderOutStream->WasWritingFinished();
|
||||
|
||||
int resOp = (result == S_FALSE ?
|
||||
NExtract::NOperationResult::kDataError :
|
||||
NExtract::NOperationResult::kUnsupportedMethod);
|
||||
|
||||
RINOK(folderOutStream->FlushCorrupted(resOp));
|
||||
|
||||
if (wasFinished)
|
||||
{
|
||||
// we don't show error, if it's after required files
|
||||
if (/* !folderOutStream->ExtraWriteWasCut && */ callbackMessage)
|
||||
{
|
||||
RINOK(callbackMessage->ReportExtractResult(NEventIndexType::kBlockIndex, folderIndex, resOp));
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (result != S_OK)
|
||||
return result;
|
||||
|
||||
RINOK(folderOutStream->FlushCorrupted(NExtract::NOperationResult::kDataError));
|
||||
continue;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
RINOK(folderOutStream->FlushCorrupted(NExtract::NOperationResult::kDataError));
|
||||
// continue;
|
||||
return E_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
}}
|
136
CPP/7zip/Archive/7z/7zFolderInStream.cpp
Normal file
136
CPP/7zip/Archive/7z/7zFolderInStream.cpp
Normal file
@ -0,0 +1,136 @@
|
||||
// 7zFolderInStream.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "7zFolderInStream.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace N7z {
|
||||
|
||||
void CFolderInStream::Init(IArchiveUpdateCallback *updateCallback,
|
||||
const UInt32 *indexes, unsigned numFiles)
|
||||
{
|
||||
_updateCallback = updateCallback;
|
||||
_indexes = indexes;
|
||||
_numFiles = numFiles;
|
||||
_index = 0;
|
||||
|
||||
Processed.ClearAndReserve(numFiles);
|
||||
CRCs.ClearAndReserve(numFiles);
|
||||
Sizes.ClearAndReserve(numFiles);
|
||||
|
||||
_pos = 0;
|
||||
_crc = CRC_INIT_VAL;
|
||||
_size_Defined = false;
|
||||
_size = 0;
|
||||
|
||||
_stream.Release();
|
||||
}
|
||||
|
||||
HRESULT CFolderInStream::OpenStream()
|
||||
{
|
||||
_pos = 0;
|
||||
_crc = CRC_INIT_VAL;
|
||||
_size_Defined = false;
|
||||
_size = 0;
|
||||
|
||||
while (_index < _numFiles)
|
||||
{
|
||||
CMyComPtr<ISequentialInStream> stream;
|
||||
HRESULT result = _updateCallback->GetStream(_indexes[_index], &stream);
|
||||
if (result != S_OK)
|
||||
{
|
||||
if (result != S_FALSE)
|
||||
return result;
|
||||
}
|
||||
|
||||
_stream = stream;
|
||||
|
||||
if (stream)
|
||||
{
|
||||
CMyComPtr<IStreamGetSize> streamGetSize;
|
||||
stream.QueryInterface(IID_IStreamGetSize, &streamGetSize);
|
||||
if (streamGetSize)
|
||||
{
|
||||
if (streamGetSize->GetSize(&_size) == S_OK)
|
||||
_size_Defined = true;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
_index++;
|
||||
RINOK(_updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
|
||||
AddFileInfo(result == S_OK);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void CFolderInStream::AddFileInfo(bool isProcessed)
|
||||
{
|
||||
Processed.Add(isProcessed);
|
||||
Sizes.Add(_pos);
|
||||
CRCs.Add(CRC_GET_DIGEST(_crc));
|
||||
}
|
||||
|
||||
STDMETHODIMP CFolderInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
|
||||
{
|
||||
if (processedSize)
|
||||
*processedSize = 0;
|
||||
while (size != 0)
|
||||
{
|
||||
if (_stream)
|
||||
{
|
||||
UInt32 processed2;
|
||||
RINOK(_stream->Read(data, size, &processed2));
|
||||
if (processed2 != 0)
|
||||
{
|
||||
_crc = CrcUpdate(_crc, data, processed2);
|
||||
_pos += processed2;
|
||||
if (processedSize)
|
||||
*processedSize = processed2;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
_stream.Release();
|
||||
_index++;
|
||||
AddFileInfo(true);
|
||||
|
||||
_pos = 0;
|
||||
_crc = CRC_INIT_VAL;
|
||||
_size_Defined = false;
|
||||
_size = 0;
|
||||
|
||||
RINOK(_updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
|
||||
}
|
||||
|
||||
if (_index >= _numFiles)
|
||||
break;
|
||||
RINOK(OpenStream());
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CFolderInStream::GetSubStreamSize(UInt64 subStream, UInt64 *value)
|
||||
{
|
||||
*value = 0;
|
||||
if (subStream > Sizes.Size())
|
||||
return S_FALSE; // E_FAIL;
|
||||
|
||||
unsigned index = (unsigned)subStream;
|
||||
if (index < Sizes.Size())
|
||||
{
|
||||
*value = Sizes[index];
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
if (!_size_Defined)
|
||||
{
|
||||
*value = _pos;
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
*value = (_pos > _size ? _pos : _size);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
}}
|
61
CPP/7zip/Archive/7z/7zFolderInStream.h
Normal file
61
CPP/7zip/Archive/7z/7zFolderInStream.h
Normal file
@ -0,0 +1,61 @@
|
||||
// 7zFolderInStream.h
|
||||
|
||||
#ifndef __7Z_FOLDER_IN_STREAM_H
|
||||
#define __7Z_FOLDER_IN_STREAM_H
|
||||
|
||||
#include "../../../../C/7zCrc.h"
|
||||
|
||||
#include "../../../Common/MyCom.h"
|
||||
#include "../../../Common/MyVector.h"
|
||||
|
||||
#include "../../ICoder.h"
|
||||
#include "../IArchive.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace N7z {
|
||||
|
||||
class CFolderInStream:
|
||||
public ISequentialInStream,
|
||||
public ICompressGetSubStreamSize,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CMyComPtr<ISequentialInStream> _stream;
|
||||
UInt64 _pos;
|
||||
UInt32 _crc;
|
||||
bool _size_Defined;
|
||||
UInt64 _size;
|
||||
|
||||
const UInt32 *_indexes;
|
||||
unsigned _numFiles;
|
||||
unsigned _index;
|
||||
|
||||
CMyComPtr<IArchiveUpdateCallback> _updateCallback;
|
||||
|
||||
HRESULT OpenStream();
|
||||
void AddFileInfo(bool isProcessed);
|
||||
|
||||
public:
|
||||
CRecordVector<bool> Processed;
|
||||
CRecordVector<UInt32> CRCs;
|
||||
CRecordVector<UInt64> Sizes;
|
||||
|
||||
MY_UNKNOWN_IMP2(ISequentialInStream, ICompressGetSubStreamSize)
|
||||
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
|
||||
STDMETHOD(GetSubStreamSize)(UInt64 subStream, UInt64 *value);
|
||||
|
||||
void Init(IArchiveUpdateCallback *updateCallback, const UInt32 *indexes, unsigned numFiles);
|
||||
|
||||
bool WasFinished() const { return _index == _numFiles; }
|
||||
|
||||
UInt64 GetFullSize() const
|
||||
{
|
||||
UInt64 size = 0;
|
||||
FOR_VECTOR (i, Sizes)
|
||||
size += Sizes[i];
|
||||
return size;
|
||||
}
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
755
CPP/7zip/Archive/7z/7zHandler.cpp
Normal file
755
CPP/7zip/Archive/7z/7zHandler.cpp
Normal file
@ -0,0 +1,755 @@
|
||||
// 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();
|
||||
_useMultiThreadMixer = true;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
|
||||
{
|
||||
*numItems = _db.Files.Size();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
#ifdef _SFX
|
||||
|
||||
IMP_IInArchive_ArcProps_NO_Table
|
||||
|
||||
STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProps)
|
||||
{
|
||||
*numProps = 0;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetPropertyInfo(UInt32 /* index */,
|
||||
BSTR * /* name */, PROPID * /* propID */, VARTYPE * /* varType */)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static const Byte kArcProps[] =
|
||||
{
|
||||
kpidHeadersSize,
|
||||
kpidMethod,
|
||||
kpidSolid,
|
||||
kpidNumBlocks
|
||||
// , kpidIsTree
|
||||
};
|
||||
|
||||
IMP_IInArchive_ArcProps
|
||||
|
||||
static inline char GetHex(unsigned value)
|
||||
{
|
||||
return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10)));
|
||||
}
|
||||
|
||||
static unsigned ConvertMethodIdToString_Back(char *s, UInt64 id)
|
||||
{
|
||||
int len = 0;
|
||||
do
|
||||
{
|
||||
s[--len] = GetHex((unsigned)id & 0xF); id >>= 4;
|
||||
s[--len] = GetHex((unsigned)id & 0xF); id >>= 4;
|
||||
}
|
||||
while (id != 0);
|
||||
return (unsigned)-len;
|
||||
}
|
||||
|
||||
static void ConvertMethodIdToString(AString &res, UInt64 id)
|
||||
{
|
||||
const unsigned kLen = 32;
|
||||
char s[kLen];
|
||||
unsigned len = kLen - 1;
|
||||
s[len] = 0;
|
||||
res += s + len - ConvertMethodIdToString_Back(s + len, id);
|
||||
}
|
||||
|
||||
static unsigned GetStringForSizeValue(char *s, UInt32 val)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i <= 31; i++)
|
||||
if (((UInt32)1 << i) == val)
|
||||
{
|
||||
if (i < 10)
|
||||
{
|
||||
s[0] = (char)('0' + i);
|
||||
s[1] = 0;
|
||||
return 1;
|
||||
}
|
||||
if (i < 20) { s[0] = '1'; s[1] = (char)('0' + i - 10); }
|
||||
else if (i < 30) { s[0] = '2'; s[1] = (char)('0' + i - 20); }
|
||||
else { s[0] = '3'; s[1] = (char)('0' + i - 30); }
|
||||
s[2] = 0;
|
||||
return 2;
|
||||
}
|
||||
char c = 'b';
|
||||
if ((val & ((1 << 20) - 1)) == 0) { val >>= 20; c = 'm'; }
|
||||
else if ((val & ((1 << 10) - 1)) == 0) { val >>= 10; c = 'k'; }
|
||||
::ConvertUInt32ToString(val, s);
|
||||
unsigned pos = MyStringLen(s);
|
||||
s[pos++] = c;
|
||||
s[pos] = 0;
|
||||
return pos;
|
||||
}
|
||||
|
||||
/*
|
||||
static inline void AddHexToString(UString &res, Byte value)
|
||||
{
|
||||
res += GetHex((Byte)(value >> 4));
|
||||
res += GetHex((Byte)(value & 0xF));
|
||||
}
|
||||
*/
|
||||
|
||||
static char *AddProp32(char *s, const char *name, UInt32 v)
|
||||
{
|
||||
*s++ = ':';
|
||||
s = MyStpCpy(s, name);
|
||||
::ConvertUInt32ToString(v, s);
|
||||
return s + MyStringLen(s);
|
||||
}
|
||||
|
||||
void CHandler::AddMethodName(AString &s, UInt64 id)
|
||||
{
|
||||
AString name;
|
||||
FindMethod(EXTERNAL_CODECS_VARS id, name);
|
||||
if (name.IsEmpty())
|
||||
ConvertMethodIdToString(s, id);
|
||||
else
|
||||
s += name;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
|
||||
{
|
||||
#ifndef _SFX
|
||||
COM_TRY_BEGIN
|
||||
#endif
|
||||
NCOM::CPropVariant prop;
|
||||
switch (propID)
|
||||
{
|
||||
#ifndef _SFX
|
||||
case kpidMethod:
|
||||
{
|
||||
AString s;
|
||||
const CParsedMethods &pm = _db.ParsedMethods;
|
||||
FOR_VECTOR (i, pm.IDs)
|
||||
{
|
||||
UInt64 id = pm.IDs[i];
|
||||
s.Add_Space_if_NotEmpty();
|
||||
char temp[16];
|
||||
if (id == k_LZMA2)
|
||||
{
|
||||
s += "LZMA2:";
|
||||
if ((pm.Lzma2Prop & 1) == 0)
|
||||
ConvertUInt32ToString((pm.Lzma2Prop >> 1) + 12, temp);
|
||||
else
|
||||
GetStringForSizeValue(temp, 3 << ((pm.Lzma2Prop >> 1) + 11));
|
||||
s += temp;
|
||||
}
|
||||
else if (id == k_LZMA)
|
||||
{
|
||||
s += "LZMA:";
|
||||
GetStringForSizeValue(temp, pm.LzmaDic);
|
||||
s += temp;
|
||||
}
|
||||
else
|
||||
AddMethodName(s, id);
|
||||
}
|
||||
prop = s;
|
||||
break;
|
||||
}
|
||||
case kpidSolid: prop = _db.IsSolid(); break;
|
||||
case kpidNumBlocks: prop = (UInt32)_db.NumFolders; break;
|
||||
case kpidHeadersSize: prop = _db.HeadersSize; break;
|
||||
case kpidPhySize: prop = _db.PhySize; break;
|
||||
case kpidOffset: if (_db.ArcInfo.StartPosition != 0) prop = _db.ArcInfo.StartPosition; break;
|
||||
/*
|
||||
case kpidIsTree: if (_db.IsTree) prop = true; break;
|
||||
case kpidIsAltStream: if (_db.ThereAreAltStreams) prop = true; break;
|
||||
case kpidIsAux: if (_db.IsTree) prop = true; break;
|
||||
*/
|
||||
// case kpidError: if (_db.ThereIsHeaderError) prop = "Header error"; break;
|
||||
#endif
|
||||
|
||||
case kpidWarningFlags:
|
||||
{
|
||||
UInt32 v = 0;
|
||||
if (_db.StartHeaderWasRecovered) v |= kpv_ErrorFlags_HeadersError;
|
||||
if (_db.UnsupportedFeatureWarning) v |= kpv_ErrorFlags_UnsupportedFeature;
|
||||
if (v != 0)
|
||||
prop = v;
|
||||
break;
|
||||
}
|
||||
|
||||
case kpidErrorFlags:
|
||||
{
|
||||
UInt32 v = 0;
|
||||
if (!_db.IsArc) v |= kpv_ErrorFlags_IsNotArc;
|
||||
if (_db.ThereIsHeaderError) v |= kpv_ErrorFlags_HeadersError;
|
||||
if (_db.UnexpectedEnd) v |= kpv_ErrorFlags_UnexpectedEnd;
|
||||
// if (_db.UnsupportedVersion) v |= kpv_ErrorFlags_Unsupported;
|
||||
if (_db.UnsupportedFeatureError) v |= kpv_ErrorFlags_UnsupportedFeature;
|
||||
prop = v;
|
||||
break;
|
||||
}
|
||||
}
|
||||
prop.Detach(value);
|
||||
return S_OK;
|
||||
#ifndef _SFX
|
||||
COM_TRY_END
|
||||
#endif
|
||||
}
|
||||
|
||||
static void SetFileTimeProp_From_UInt64Def(PROPVARIANT *prop, const CUInt64DefVector &v, int index)
|
||||
{
|
||||
UInt64 value;
|
||||
if (v.GetItem(index, value))
|
||||
PropVarEm_Set_FileTime64(prop, value);
|
||||
}
|
||||
|
||||
bool CHandler::IsFolderEncrypted(CNum folderIndex) const
|
||||
{
|
||||
if (folderIndex == kNumNoIndex)
|
||||
return false;
|
||||
size_t startPos = _db.FoCodersDataOffset[folderIndex];
|
||||
const Byte *p = _db.CodersData + startPos;
|
||||
size_t size = _db.FoCodersDataOffset[folderIndex + 1] - startPos;
|
||||
CInByte2 inByte;
|
||||
inByte.Init(p, size);
|
||||
|
||||
CNum numCoders = inByte.ReadNum();
|
||||
for (; numCoders != 0; numCoders--)
|
||||
{
|
||||
Byte mainByte = inByte.ReadByte();
|
||||
unsigned idSize = (mainByte & 0xF);
|
||||
const Byte *longID = inByte.GetPtr();
|
||||
UInt64 id64 = 0;
|
||||
for (unsigned j = 0; j < idSize; j++)
|
||||
id64 = ((id64 << 8) | longID[j]);
|
||||
inByte.SkipDataNoCheck(idSize);
|
||||
if (id64 == k_AES)
|
||||
return true;
|
||||
if ((mainByte & 0x20) != 0)
|
||||
inByte.SkipDataNoCheck(inByte.ReadNum());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetNumRawProps(UInt32 *numProps)
|
||||
{
|
||||
*numProps = 0;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetRawPropInfo(UInt32 /* index */, BSTR *name, PROPID *propID)
|
||||
{
|
||||
*name = NULL;
|
||||
*propID = kpidNtSecure;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetParent(UInt32 /* index */, UInt32 *parent, UInt32 *parentType)
|
||||
{
|
||||
/*
|
||||
const CFileItem &file = _db.Files[index];
|
||||
*parentType = (file.IsAltStream ? NParentType::kAltStream : NParentType::kDir);
|
||||
*parent = (UInt32)(Int32)file.Parent;
|
||||
*/
|
||||
*parentType = NParentType::kDir;
|
||||
*parent = (UInt32)(Int32)-1;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType)
|
||||
{
|
||||
*data = NULL;
|
||||
*dataSize = 0;
|
||||
*propType = 0;
|
||||
|
||||
if (/* _db.IsTree && propID == kpidName ||
|
||||
!_db.IsTree && */ propID == kpidPath)
|
||||
{
|
||||
if (_db.NameOffsets && _db.NamesBuf)
|
||||
{
|
||||
size_t offset = _db.NameOffsets[index];
|
||||
size_t size = (_db.NameOffsets[index + 1] - offset) * 2;
|
||||
if (size < ((UInt32)1 << 31))
|
||||
{
|
||||
*data = (const void *)(_db.NamesBuf + offset * 2);
|
||||
*dataSize = (UInt32)size;
|
||||
*propType = NPropDataType::kUtf16z;
|
||||
}
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
/*
|
||||
if (propID == kpidNtSecure)
|
||||
{
|
||||
if (index < (UInt32)_db.SecureIDs.Size())
|
||||
{
|
||||
int id = _db.SecureIDs[index];
|
||||
size_t offs = _db.SecureOffsets[id];
|
||||
size_t size = _db.SecureOffsets[id + 1] - offs;
|
||||
if (size >= 0)
|
||||
{
|
||||
*data = _db.SecureBuf + offs;
|
||||
*dataSize = (UInt32)size;
|
||||
*propType = NPropDataType::kRaw;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
#ifndef _SFX
|
||||
|
||||
HRESULT CHandler::SetMethodToProp(CNum folderIndex, PROPVARIANT *prop) const
|
||||
{
|
||||
PropVariant_Clear(prop);
|
||||
if (folderIndex == kNumNoIndex)
|
||||
return S_OK;
|
||||
// for (int ttt = 0; ttt < 1; ttt++) {
|
||||
const unsigned kTempSize = 256;
|
||||
char temp[kTempSize];
|
||||
unsigned pos = kTempSize;
|
||||
temp[--pos] = 0;
|
||||
|
||||
size_t startPos = _db.FoCodersDataOffset[folderIndex];
|
||||
const Byte *p = _db.CodersData + startPos;
|
||||
size_t size = _db.FoCodersDataOffset[folderIndex + 1] - startPos;
|
||||
CInByte2 inByte;
|
||||
inByte.Init(p, size);
|
||||
|
||||
// numCoders == 0 ???
|
||||
CNum numCoders = inByte.ReadNum();
|
||||
bool needSpace = false;
|
||||
|
||||
for (; numCoders != 0; numCoders--, needSpace = true)
|
||||
{
|
||||
if (pos < 32) // max size of property
|
||||
break;
|
||||
Byte mainByte = inByte.ReadByte();
|
||||
unsigned idSize = (mainByte & 0xF);
|
||||
const Byte *longID = inByte.GetPtr();
|
||||
UInt64 id64 = 0;
|
||||
for (unsigned j = 0; j < idSize; j++)
|
||||
id64 = ((id64 << 8) | longID[j]);
|
||||
inByte.SkipDataNoCheck(idSize);
|
||||
|
||||
if ((mainByte & 0x10) != 0)
|
||||
{
|
||||
inByte.ReadNum(); // NumInStreams
|
||||
inByte.ReadNum(); // NumOutStreams
|
||||
}
|
||||
|
||||
CNum propsSize = 0;
|
||||
const Byte *props = NULL;
|
||||
if ((mainByte & 0x20) != 0)
|
||||
{
|
||||
propsSize = inByte.ReadNum();
|
||||
props = inByte.GetPtr();
|
||||
inByte.SkipDataNoCheck(propsSize);
|
||||
}
|
||||
|
||||
const char *name = NULL;
|
||||
char s[32];
|
||||
s[0] = 0;
|
||||
|
||||
if (id64 <= (UInt32)0xFFFFFFFF)
|
||||
{
|
||||
UInt32 id = (UInt32)id64;
|
||||
if (id == k_LZMA)
|
||||
{
|
||||
name = "LZMA";
|
||||
if (propsSize == 5)
|
||||
{
|
||||
UInt32 dicSize = GetUi32((const Byte *)props + 1);
|
||||
char *dest = s + GetStringForSizeValue(s, dicSize);
|
||||
UInt32 d = props[0];
|
||||
if (d != 0x5D)
|
||||
{
|
||||
UInt32 lc = d % 9;
|
||||
d /= 9;
|
||||
UInt32 pb = d / 5;
|
||||
UInt32 lp = d % 5;
|
||||
if (lc != 3) dest = AddProp32(dest, "lc", lc);
|
||||
if (lp != 0) dest = AddProp32(dest, "lp", lp);
|
||||
if (pb != 2) dest = AddProp32(dest, "pb", pb);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (id == k_LZMA2)
|
||||
{
|
||||
name = "LZMA2";
|
||||
if (propsSize == 1)
|
||||
{
|
||||
Byte d = props[0];
|
||||
if ((d & 1) == 0)
|
||||
ConvertUInt32ToString((UInt32)((d >> 1) + 12), s);
|
||||
else
|
||||
GetStringForSizeValue(s, 3 << ((d >> 1) + 11));
|
||||
}
|
||||
}
|
||||
else if (id == k_PPMD)
|
||||
{
|
||||
name = "PPMD";
|
||||
if (propsSize == 5)
|
||||
{
|
||||
Byte order = *props;
|
||||
char *dest = s;
|
||||
*dest++ = 'o';
|
||||
ConvertUInt32ToString(order, dest);
|
||||
dest += MyStringLen(dest);
|
||||
dest = MyStpCpy(dest, ":mem");
|
||||
GetStringForSizeValue(dest, GetUi32(props + 1));
|
||||
}
|
||||
}
|
||||
else if (id == k_Delta)
|
||||
{
|
||||
name = "Delta";
|
||||
if (propsSize == 1)
|
||||
ConvertUInt32ToString((UInt32)props[0] + 1, s);
|
||||
}
|
||||
else if (id == k_BCJ2) name = "BCJ2";
|
||||
else if (id == k_BCJ) name = "BCJ";
|
||||
else if (id == k_AES)
|
||||
{
|
||||
name = "7zAES";
|
||||
if (propsSize >= 1)
|
||||
{
|
||||
Byte firstByte = props[0];
|
||||
UInt32 numCyclesPower = firstByte & 0x3F;
|
||||
ConvertUInt32ToString(numCyclesPower, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (name)
|
||||
{
|
||||
unsigned nameLen = MyStringLen(name);
|
||||
unsigned propsLen = MyStringLen(s);
|
||||
unsigned totalLen = nameLen + propsLen;
|
||||
if (propsLen != 0)
|
||||
totalLen++;
|
||||
if (needSpace)
|
||||
totalLen++;
|
||||
if (totalLen + 5 >= pos)
|
||||
break;
|
||||
pos -= totalLen;
|
||||
MyStringCopy(temp + pos, name);
|
||||
if (propsLen != 0)
|
||||
{
|
||||
char *dest = temp + pos + nameLen;
|
||||
*dest++ = ':';
|
||||
MyStringCopy(dest, s);
|
||||
}
|
||||
if (needSpace)
|
||||
temp[pos + totalLen - 1] = ' ';
|
||||
}
|
||||
else
|
||||
{
|
||||
AString methodName;
|
||||
FindMethod(EXTERNAL_CODECS_VARS id64, methodName);
|
||||
if (needSpace)
|
||||
temp[--pos] = ' ';
|
||||
if (methodName.IsEmpty())
|
||||
pos -= ConvertMethodIdToString_Back(temp + pos, id64);
|
||||
else
|
||||
{
|
||||
unsigned len = methodName.Len();
|
||||
if (len + 5 > pos)
|
||||
break;
|
||||
pos -= len;
|
||||
for (unsigned i = 0; i < len; i++)
|
||||
temp[pos + i] = methodName[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (numCoders != 0 && pos >= 4)
|
||||
{
|
||||
temp[--pos] = ' ';
|
||||
temp[--pos] = '.';
|
||||
temp[--pos] = '.';
|
||||
temp[--pos] = '.';
|
||||
}
|
||||
|
||||
return PropVarEm_Set_Str(prop, temp + pos);
|
||||
// }
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
|
||||
{
|
||||
PropVariant_Clear(value);
|
||||
// COM_TRY_BEGIN
|
||||
// NCOM::CPropVariant prop;
|
||||
|
||||
/*
|
||||
const CRef2 &ref2 = _refs[index];
|
||||
if (ref2.Refs.IsEmpty())
|
||||
return E_FAIL;
|
||||
const CRef &ref = ref2.Refs.Front();
|
||||
*/
|
||||
|
||||
const CFileItem &item = _db.Files[index];
|
||||
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)
|
||||
{
|
||||
if (_db.FolderStartFileIndex[folderIndex] == (CNum)index2 &&
|
||||
_db.FoStartPackStreamIndex[folderIndex + 1] -
|
||||
_db.FoStartPackStreamIndex[folderIndex] > (propID - kpidPackedSize0))
|
||||
{
|
||||
PropVarEm_Set_UInt64(value, _db.GetFolderPackStreamSize(folderIndex, propID - kpidPackedSize0));
|
||||
}
|
||||
}
|
||||
else
|
||||
PropVarEm_Set_UInt64(value, 0);
|
||||
}
|
||||
break;
|
||||
*/
|
||||
|
||||
#endif
|
||||
}
|
||||
// prop.Detach(value);
|
||||
return S_OK;
|
||||
// COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Open(IInStream *stream,
|
||||
const UInt64 *maxCheckStartPosition,
|
||||
IArchiveOpenCallback *openArchiveCallback)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
Close();
|
||||
#ifndef _SFX
|
||||
_fileInfoPopIDs.Clear();
|
||||
#endif
|
||||
|
||||
try
|
||||
{
|
||||
CMyComPtr<IArchiveOpenCallback> openArchiveCallbackTemp = openArchiveCallback;
|
||||
|
||||
#ifndef _NO_CRYPTO
|
||||
CMyComPtr<ICryptoGetTextPassword> getTextPassword;
|
||||
if (openArchiveCallback)
|
||||
openArchiveCallbackTemp.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword);
|
||||
#endif
|
||||
|
||||
CInArchive archive(
|
||||
#ifdef __7Z_SET_PROPERTIES
|
||||
_useMultiThreadMixer
|
||||
#else
|
||||
true
|
||||
#endif
|
||||
);
|
||||
_db.IsArc = false;
|
||||
RINOK(archive.Open(stream, maxCheckStartPosition));
|
||||
_db.IsArc = true;
|
||||
|
||||
HRESULT result = archive.ReadDatabase(
|
||||
EXTERNAL_CODECS_VARS
|
||||
_db
|
||||
#ifndef _NO_CRYPTO
|
||||
, getTextPassword, _isEncrypted, _passwordIsDefined, _password
|
||||
#endif
|
||||
);
|
||||
RINOK(result);
|
||||
|
||||
_inStream = stream;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
Close();
|
||||
// return E_INVALIDARG;
|
||||
// return S_FALSE;
|
||||
// we must return out_of_memory here
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
// _inStream = stream;
|
||||
#ifndef _SFX
|
||||
FillPopIDs();
|
||||
#endif
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Close()
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
_inStream.Release();
|
||||
_db.Clear();
|
||||
#ifndef _NO_CRYPTO
|
||||
_isEncrypted = false;
|
||||
_passwordIsDefined = false;
|
||||
_password.Empty();
|
||||
#endif
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
#ifdef __7Z_SET_PROPERTIES
|
||||
#ifdef EXTRACT_ONLY
|
||||
|
||||
STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
const UInt32 numProcessors = NSystem::GetNumberOfProcessors();
|
||||
_numThreads = numProcessors;
|
||||
_useMultiThreadMixer = true;
|
||||
|
||||
for (UInt32 i = 0; i < numProps; i++)
|
||||
{
|
||||
UString name = names[i];
|
||||
name.MakeLower_Ascii();
|
||||
if (name.IsEmpty())
|
||||
return E_INVALIDARG;
|
||||
const PROPVARIANT &value = values[i];
|
||||
UInt32 number;
|
||||
unsigned index = ParseStringToUInt32(name, number);
|
||||
if (index == 0)
|
||||
{
|
||||
if (name.IsEqualTo("mtf"))
|
||||
{
|
||||
RINOK(PROPVARIANT_to_bool(value, _useMultiThreadMixer));
|
||||
continue;
|
||||
}
|
||||
if (name.IsPrefixedBy_Ascii_NoCase("mt"))
|
||||
{
|
||||
RINOK(ParseMtProp(name.Ptr(2), value, numProcessors, _numThreads));
|
||||
continue;
|
||||
}
|
||||
else
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
}
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
IMPL_ISetCompressCodecsInfo
|
||||
|
||||
}}
|
173
CPP/7zip/Archive/7z/7zHandler.h
Normal file
173
CPP/7zip/Archive/7z/7zHandler.h
Normal file
@ -0,0 +1,173 @@
|
||||
// 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 {
|
||||
|
||||
#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 _useTypeSorting;
|
||||
|
||||
bool _compressHeaders;
|
||||
bool _encryptHeadersSpecified;
|
||||
bool _encryptHeaders;
|
||||
// bool _useParents; 9.26
|
||||
|
||||
CBoolPair Write_CTime;
|
||||
CBoolPair Write_ATime;
|
||||
CBoolPair Write_MTime;
|
||||
|
||||
bool _useMultiThreadMixer;
|
||||
|
||||
// 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 * const *names, const PROPVARIANT *values, UInt32 numProps);
|
||||
#endif
|
||||
|
||||
#ifndef EXTRACT_ONLY
|
||||
INTERFACE_IOutArchive(;)
|
||||
#endif
|
||||
|
||||
DECL_ISetCompressCodecsInfo
|
||||
|
||||
CHandler();
|
||||
|
||||
private:
|
||||
CMyComPtr<IInStream> _inStream;
|
||||
NArchive::N7z::CDbEx _db;
|
||||
|
||||
#ifndef _NO_CRYPTO
|
||||
bool _isEncrypted;
|
||||
bool _passwordIsDefined;
|
||||
UString _password;
|
||||
#endif
|
||||
|
||||
#ifdef EXTRACT_ONLY
|
||||
|
||||
#ifdef __7Z_SET_PROPERTIES
|
||||
UInt32 _numThreads;
|
||||
bool _useMultiThreadMixer;
|
||||
#endif
|
||||
|
||||
UInt32 _crcSize;
|
||||
|
||||
#else
|
||||
|
||||
CRecordVector<CBond2> _bonds;
|
||||
|
||||
HRESULT PropsMethod_To_FullMethod(CMethodFull &dest, const COneMethodInfo &m);
|
||||
HRESULT SetHeaderMethod(CCompressionMethodMode &headerMethod);
|
||||
HRESULT SetMainMethod(CCompressionMethodMode &method
|
||||
#ifndef _7ZIP_ST
|
||||
, UInt32 numThreads
|
||||
#endif
|
||||
);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
bool IsFolderEncrypted(CNum folderIndex) const;
|
||||
#ifndef _SFX
|
||||
|
||||
CRecordVector<UInt64> _fileInfoPopIDs;
|
||||
void FillPopIDs();
|
||||
void AddMethodName(AString &s, UInt64 id);
|
||||
HRESULT SetMethodToProp(CNum folderIndex, PROPVARIANT *prop) const;
|
||||
|
||||
#endif
|
||||
|
||||
DECL_EXTERNAL_CODECS_VARS
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
913
CPP/7zip/Archive/7z/7zHandlerOut.cpp
Normal file
913
CPP/7zip/Archive/7z/7zHandlerOut.cpp
Normal file
@ -0,0 +1,913 @@
|
||||
// 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 char *k_LZMA_Name = "LZMA";
|
||||
static const char *kDefaultMethodName = "LZMA2";
|
||||
static const char *k_Copy_Name = "Copy";
|
||||
|
||||
static const char *k_MatchFinder_ForHeaders = "BT2";
|
||||
static const UInt32 k_NumFastBytes_ForHeaders = 273;
|
||||
static const UInt32 k_Level_ForHeaders = 5;
|
||||
static const UInt32 k_Dictionary_ForHeaders =
|
||||
#ifdef UNDER_CE
|
||||
1 << 18;
|
||||
#else
|
||||
1 << 20;
|
||||
#endif
|
||||
|
||||
STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type)
|
||||
{
|
||||
*type = NFileTimeType::kWindows;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CHandler::PropsMethod_To_FullMethod(CMethodFull &dest, const COneMethodInfo &m)
|
||||
{
|
||||
if (!FindMethod(
|
||||
EXTERNAL_CODECS_VARS
|
||||
m.MethodName, dest.Id, dest.NumStreams))
|
||||
return E_INVALIDARG;
|
||||
(CProps &)dest = (CProps &)m;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CHandler::SetHeaderMethod(CCompressionMethodMode &headerMethod)
|
||||
{
|
||||
if (!_compressHeaders)
|
||||
return S_OK;
|
||||
COneMethodInfo m;
|
||||
m.MethodName = k_LZMA_Name;
|
||||
m.AddProp_Ascii(NCoderPropID::kMatchFinder, k_MatchFinder_ForHeaders);
|
||||
m.AddProp_Level(k_Level_ForHeaders);
|
||||
m.AddProp32(NCoderPropID::kNumFastBytes, k_NumFastBytes_ForHeaders);
|
||||
m.AddProp32(NCoderPropID::kDictionarySize, k_Dictionary_ForHeaders);
|
||||
m.AddProp_NumThreads(1);
|
||||
|
||||
CMethodFull &methodFull = headerMethod.Methods.AddNew();
|
||||
return PropsMethod_To_FullMethod(methodFull, m);
|
||||
}
|
||||
|
||||
HRESULT CHandler::SetMainMethod(
|
||||
CCompressionMethodMode &methodMode
|
||||
#ifndef _7ZIP_ST
|
||||
, UInt32 numThreads
|
||||
#endif
|
||||
)
|
||||
{
|
||||
methodMode.Bonds = _bonds;
|
||||
|
||||
CObjectVector<COneMethodInfo> methods = _methods;
|
||||
|
||||
{
|
||||
FOR_VECTOR (i, methods)
|
||||
{
|
||||
AString &methodName = methods[i].MethodName;
|
||||
if (methodName.IsEmpty())
|
||||
methodName = kDefaultMethodName;
|
||||
}
|
||||
if (methods.IsEmpty())
|
||||
{
|
||||
COneMethodInfo &m = methods.AddNew();
|
||||
m.MethodName = (GetLevel() == 0 ? k_Copy_Name : kDefaultMethodName);
|
||||
methodMode.DefaultMethod_was_Inserted = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!_filterMethod.MethodName.IsEmpty())
|
||||
{
|
||||
// if (methodMode.Bonds.IsEmpty())
|
||||
{
|
||||
FOR_VECTOR (k, methodMode.Bonds)
|
||||
{
|
||||
CBond2 &bond = methodMode.Bonds[k];
|
||||
bond.InCoder++;
|
||||
bond.OutCoder++;
|
||||
}
|
||||
methods.Insert(0, _filterMethod);
|
||||
methodMode.Filter_was_Inserted = true;
|
||||
}
|
||||
}
|
||||
|
||||
const UInt64 kSolidBytes_Min = (1 << 24);
|
||||
const UInt64 kSolidBytes_Max = ((UInt64)1 << 32) - 1;
|
||||
|
||||
bool needSolid = false;
|
||||
|
||||
FOR_VECTOR (i, methods)
|
||||
{
|
||||
COneMethodInfo &oneMethodInfo = methods[i];
|
||||
SetGlobalLevelAndThreads(oneMethodInfo
|
||||
#ifndef _7ZIP_ST
|
||||
, numThreads
|
||||
#endif
|
||||
);
|
||||
|
||||
CMethodFull &methodFull = methodMode.Methods.AddNew();
|
||||
RINOK(PropsMethod_To_FullMethod(methodFull, oneMethodInfo));
|
||||
|
||||
if (methodFull.Id != k_Copy)
|
||||
needSolid = true;
|
||||
|
||||
if (_numSolidBytesDefined)
|
||||
continue;
|
||||
|
||||
UInt32 dicSize;
|
||||
switch (methodFull.Id)
|
||||
{
|
||||
case k_LZMA:
|
||||
case k_LZMA2: dicSize = oneMethodInfo.Get_Lzma_DicSize(); break;
|
||||
case k_PPMD: dicSize = oneMethodInfo.Get_Ppmd_MemSize(); break;
|
||||
case k_Deflate: dicSize = (UInt32)1 << 15; break;
|
||||
case k_BZip2: dicSize = oneMethodInfo.Get_BZip2_BlockSize(); break;
|
||||
default: continue;
|
||||
}
|
||||
|
||||
_numSolidBytes = (UInt64)dicSize << 7;
|
||||
if (_numSolidBytes < kSolidBytes_Min) _numSolidBytes = kSolidBytes_Min;
|
||||
if (_numSolidBytes > kSolidBytes_Max) _numSolidBytes = kSolidBytes_Max;
|
||||
_numSolidBytesDefined = true;
|
||||
}
|
||||
|
||||
if (!_numSolidBytesDefined)
|
||||
if (needSolid)
|
||||
_numSolidBytes = kSolidBytes_Max;
|
||||
else
|
||||
_numSolidBytes = 0;
|
||||
_numSolidBytesDefined = true;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT GetTime(IArchiveUpdateCallback *updateCallback, int index, PROPID propID, UInt64 &ft, bool &ftDefined)
|
||||
{
|
||||
// ft = 0;
|
||||
// ftDefined = false;
|
||||
NCOM::CPropVariant prop;
|
||||
RINOK(updateCallback->GetProperty(index, propID, &prop));
|
||||
if (prop.vt == VT_FILETIME)
|
||||
{
|
||||
ft = prop.filetime.dwLowDateTime | ((UInt64)prop.filetime.dwHighDateTime << 32);
|
||||
ftDefined = true;
|
||||
}
|
||||
else if (prop.vt != VT_EMPTY)
|
||||
return E_INVALIDARG;
|
||||
else
|
||||
{
|
||||
ft = 0;
|
||||
ftDefined = false;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
#ifdef _WIN32
|
||||
static const wchar_t kDirDelimiter1 = L'\\';
|
||||
#endif
|
||||
static const wchar_t kDirDelimiter2 = L'/';
|
||||
|
||||
static inline bool IsCharDirLimiter(wchar_t c)
|
||||
{
|
||||
return (
|
||||
#ifdef _WIN32
|
||||
c == kDirDelimiter1 ||
|
||||
#endif
|
||||
c == kDirDelimiter2);
|
||||
}
|
||||
|
||||
static int FillSortIndex(CObjectVector<CTreeFolder> &treeFolders, int cur, int curSortIndex)
|
||||
{
|
||||
CTreeFolder &tf = treeFolders[cur];
|
||||
tf.SortIndex = curSortIndex++;
|
||||
for (int i = 0; i < tf.SubFolders.Size(); i++)
|
||||
curSortIndex = FillSortIndex(treeFolders, tf.SubFolders[i], curSortIndex);
|
||||
tf.SortIndexEnd = curSortIndex;
|
||||
return curSortIndex;
|
||||
}
|
||||
|
||||
static int FindSubFolder(const CObjectVector<CTreeFolder> &treeFolders, int cur, const UString &name, int &insertPos)
|
||||
{
|
||||
const CIntVector &subFolders = treeFolders[cur].SubFolders;
|
||||
int left = 0, right = subFolders.Size();
|
||||
insertPos = -1;
|
||||
for (;;)
|
||||
{
|
||||
if (left == right)
|
||||
{
|
||||
insertPos = left;
|
||||
return -1;
|
||||
}
|
||||
int mid = (left + right) / 2;
|
||||
int midFolder = subFolders[mid];
|
||||
int compare = CompareFileNames(name, treeFolders[midFolder].Name);
|
||||
if (compare == 0)
|
||||
return midFolder;
|
||||
if (compare < 0)
|
||||
right = mid;
|
||||
else
|
||||
left = mid + 1;
|
||||
}
|
||||
}
|
||||
|
||||
static int AddFolder(CObjectVector<CTreeFolder> &treeFolders, int cur, const UString &name)
|
||||
{
|
||||
int insertPos;
|
||||
int folderIndex = FindSubFolder(treeFolders, cur, name, insertPos);
|
||||
if (folderIndex < 0)
|
||||
{
|
||||
folderIndex = treeFolders.Size();
|
||||
CTreeFolder &newFolder = treeFolders.AddNew();
|
||||
newFolder.Parent = cur;
|
||||
newFolder.Name = name;
|
||||
treeFolders[cur].SubFolders.Insert(insertPos, folderIndex);
|
||||
}
|
||||
// else if (treeFolders[folderIndex].IsAltStreamFolder != isAltStreamFolder) throw 1123234234;
|
||||
return folderIndex;
|
||||
}
|
||||
*/
|
||||
|
||||
STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
|
||||
IArchiveUpdateCallback *updateCallback)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
|
||||
const CDbEx *db = 0;
|
||||
#ifdef _7Z_VOL
|
||||
if (_volumes.Size() > 1)
|
||||
return E_FAIL;
|
||||
const CVolume *volume = 0;
|
||||
if (_volumes.Size() == 1)
|
||||
{
|
||||
volume = &_volumes.Front();
|
||||
db = &volume->Database;
|
||||
}
|
||||
#else
|
||||
if (_inStream != 0)
|
||||
db = &_db;
|
||||
#endif
|
||||
|
||||
/*
|
||||
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 && !db->Files.IsEmpty())
|
||||
{
|
||||
if (!Write_CTime.Def) need_CTime = !db->CTime.Defs.IsEmpty();
|
||||
if (!Write_ATime.Def) need_ATime = !db->ATime.Defs.IsEmpty();
|
||||
if (!Write_MTime.Def) need_MTime = !db->MTime.Defs.IsEmpty();
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
ui.Size = 0;
|
||||
if (!ui.IsDir)
|
||||
{
|
||||
NCOM::CPropVariant prop;
|
||||
RINOK(updateCallback->GetProperty(i, kpidSize, &prop));
|
||||
if (prop.vt != VT_UI8)
|
||||
return E_INVALIDARG;
|
||||
ui.Size = (UInt64)prop.uhVal.QuadPart;
|
||||
if (ui.Size != 0 && ui.IsAnti)
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
}
|
||||
|
||||
updateItems.Add(ui);
|
||||
}
|
||||
|
||||
/*
|
||||
FillSortIndex(treeFolders, 0, 0);
|
||||
for (i = 0; i < (UInt32)updateItems.Size(); i++)
|
||||
{
|
||||
CUpdateItem &ui = updateItems[i];
|
||||
ui.ParentSortIndex = treeFolders[ui.ParentFolderIndex].SortIndex;
|
||||
ui.ParentSortIndexEnd = treeFolders[ui.ParentFolderIndex].SortIndexEnd;
|
||||
}
|
||||
*/
|
||||
|
||||
CCompressionMethodMode methodMode, headerMethod;
|
||||
|
||||
HRESULT res = SetMainMethod(methodMode
|
||||
#ifndef _7ZIP_ST
|
||||
, _numThreads
|
||||
#endif
|
||||
);
|
||||
RINOK(res);
|
||||
|
||||
RINOK(SetHeaderMethod(headerMethod));
|
||||
|
||||
#ifndef _7ZIP_ST
|
||||
methodMode.NumThreads = _numThreads;
|
||||
methodMode.MultiThreadMixer = _useMultiThreadMixer;
|
||||
headerMethod.NumThreads = 1;
|
||||
headerMethod.MultiThreadMixer = _useMultiThreadMixer;
|
||||
#endif
|
||||
|
||||
CMyComPtr<ICryptoGetTextPassword2> getPassword2;
|
||||
updateCallback->QueryInterface(IID_ICryptoGetTextPassword2, (void **)&getPassword2);
|
||||
|
||||
methodMode.PasswordIsDefined = false;
|
||||
methodMode.Password.Empty();
|
||||
if (getPassword2)
|
||||
{
|
||||
CMyComBSTR password;
|
||||
Int32 passwordIsDefined;
|
||||
RINOK(getPassword2->CryptoGetTextPassword2(&passwordIsDefined, &password));
|
||||
methodMode.PasswordIsDefined = IntToBool(passwordIsDefined);
|
||||
if (methodMode.PasswordIsDefined && password)
|
||||
methodMode.Password = password;
|
||||
}
|
||||
|
||||
bool compressMainHeader = _compressHeaders; // check it
|
||||
|
||||
bool encryptHeaders = false;
|
||||
|
||||
#ifndef _NO_CRYPTO
|
||||
if (!methodMode.PasswordIsDefined && _passwordIsDefined)
|
||||
{
|
||||
// if header is compressed, we use that password for updated archive
|
||||
methodMode.PasswordIsDefined = true;
|
||||
methodMode.Password = _password;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (methodMode.PasswordIsDefined)
|
||||
{
|
||||
if (_encryptHeadersSpecified)
|
||||
encryptHeaders = _encryptHeaders;
|
||||
#ifndef _NO_CRYPTO
|
||||
else
|
||||
encryptHeaders = _passwordIsDefined;
|
||||
#endif
|
||||
compressMainHeader = true;
|
||||
if (encryptHeaders)
|
||||
{
|
||||
headerMethod.PasswordIsDefined = methodMode.PasswordIsDefined;
|
||||
headerMethod.Password = methodMode.Password;
|
||||
}
|
||||
}
|
||||
|
||||
if (numItems < 2)
|
||||
compressMainHeader = false;
|
||||
|
||||
int level = GetLevel();
|
||||
|
||||
CUpdateOptions options;
|
||||
options.Method = &methodMode;
|
||||
options.HeaderMethod = (_compressHeaders || encryptHeaders) ? &headerMethod : NULL;
|
||||
options.UseFilters = (level != 0 && _autoFilter && !methodMode.Filter_was_Inserted);
|
||||
options.MaxFilter = (level >= 8);
|
||||
options.AnalysisLevel = GetAnalysisLevel();
|
||||
|
||||
options.HeaderOptions.CompressMainHeader = compressMainHeader;
|
||||
/*
|
||||
options.HeaderOptions.WriteCTime = Write_CTime;
|
||||
options.HeaderOptions.WriteATime = Write_ATime;
|
||||
options.HeaderOptions.WriteMTime = Write_MTime;
|
||||
*/
|
||||
|
||||
options.NumSolidFiles = _numSolidFiles;
|
||||
options.NumSolidBytes = _numSolidBytes;
|
||||
options.SolidExtension = _solidExtension;
|
||||
options.UseTypeSorting = _useTypeSorting;
|
||||
|
||||
options.RemoveSfxBlock = _removeSfxBlock;
|
||||
// options.VolumeMode = _volumeMode;
|
||||
|
||||
options.MultiThreadMixer = _useMultiThreadMixer;
|
||||
|
||||
COutArchive archive;
|
||||
CArchiveDatabaseOut newDatabase;
|
||||
|
||||
CMyComPtr<ICryptoGetTextPassword> getPassword;
|
||||
updateCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&getPassword);
|
||||
|
||||
/*
|
||||
if (secureBlocks.Sorted.Size() > 1)
|
||||
{
|
||||
secureBlocks.GetReverseMap();
|
||||
for (int i = 0; i < updateItems.Size(); i++)
|
||||
{
|
||||
int &secureIndex = updateItems[i].SecureIndex;
|
||||
secureIndex = secureBlocks.BufIndexToSortedIndex[secureIndex];
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
res = Update(
|
||||
EXTERNAL_CODECS_VARS
|
||||
#ifdef _7Z_VOL
|
||||
volume ? volume->Stream: 0,
|
||||
volume ? db : 0,
|
||||
#else
|
||||
_inStream,
|
||||
db,
|
||||
#endif
|
||||
updateItems,
|
||||
// treeFolders,
|
||||
// secureBlocks,
|
||||
archive, newDatabase, outStream, updateCallback, options
|
||||
#ifndef _NO_CRYPTO
|
||||
, getPassword
|
||||
#endif
|
||||
);
|
||||
|
||||
RINOK(res);
|
||||
|
||||
updateItems.ClearAndFree();
|
||||
|
||||
return archive.WriteDatabase(EXTERNAL_CODECS_VARS
|
||||
newDatabase, options.HeaderMethod, options.HeaderOptions);
|
||||
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
static HRESULT ParseBond(UString &srcString, UInt32 &coder, UInt32 &stream)
|
||||
{
|
||||
stream = 0;
|
||||
{
|
||||
unsigned index = ParseStringToUInt32(srcString, coder);
|
||||
if (index == 0)
|
||||
return E_INVALIDARG;
|
||||
srcString.DeleteFrontal(index);
|
||||
}
|
||||
if (srcString[0] == 's')
|
||||
{
|
||||
srcString.Delete(0);
|
||||
unsigned index = ParseStringToUInt32(srcString, stream);
|
||||
if (index == 0)
|
||||
return E_INVALIDARG;
|
||||
srcString.DeleteFrontal(index);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void COutHandler::InitProps()
|
||||
{
|
||||
CMultiMethodProps::Init();
|
||||
|
||||
_removeSfxBlock = false;
|
||||
_compressHeaders = true;
|
||||
_encryptHeadersSpecified = false;
|
||||
_encryptHeaders = false;
|
||||
// _useParents = false;
|
||||
|
||||
Write_CTime.Init();
|
||||
Write_ATime.Init();
|
||||
Write_MTime.Init();
|
||||
|
||||
_useMultiThreadMixer = true;
|
||||
|
||||
// _volumeMode = false;
|
||||
|
||||
InitSolid();
|
||||
_useTypeSorting = false;
|
||||
}
|
||||
|
||||
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("mtf")) return PROPVARIANT_to_bool(value, _useMultiThreadMixer);
|
||||
|
||||
if (name.IsEqualTo("qs")) return PROPVARIANT_to_bool(value, _useTypeSorting);
|
||||
|
||||
// if (name.IsEqualTo("v")) return PROPVARIANT_to_bool(value, _volumeMode);
|
||||
}
|
||||
return CMultiMethodProps::SetProperty(name, value);
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
_bonds.Clear();
|
||||
InitProps();
|
||||
|
||||
for (UInt32 i = 0; i < numProps; i++)
|
||||
{
|
||||
UString name = names[i];
|
||||
name.MakeLower_Ascii();
|
||||
if (name.IsEmpty())
|
||||
return E_INVALIDARG;
|
||||
|
||||
const PROPVARIANT &value = values[i];
|
||||
|
||||
if (name[0] == 'b')
|
||||
{
|
||||
if (value.vt != VT_EMPTY)
|
||||
return E_INVALIDARG;
|
||||
name.Delete(0);
|
||||
|
||||
CBond2 bond;
|
||||
RINOK(ParseBond(name, bond.OutCoder, bond.OutStream));
|
||||
if (name[0] != ':')
|
||||
return E_INVALIDARG;
|
||||
name.Delete(0);
|
||||
UInt32 inStream = 0;
|
||||
RINOK(ParseBond(name, bond.InCoder, inStream));
|
||||
if (inStream != 0)
|
||||
return E_INVALIDARG;
|
||||
if (!name.IsEmpty())
|
||||
return E_INVALIDARG;
|
||||
_bonds.Add(bond);
|
||||
continue;
|
||||
}
|
||||
|
||||
RINOK(SetProperty(name, value));
|
||||
}
|
||||
|
||||
unsigned numEmptyMethods = GetNumEmptyMethods();
|
||||
if (numEmptyMethods > 0)
|
||||
{
|
||||
unsigned k;
|
||||
for (k = 0; k < _bonds.Size(); k++)
|
||||
{
|
||||
const CBond2 &bond = _bonds[k];
|
||||
if (bond.InCoder < (UInt32)numEmptyMethods ||
|
||||
bond.OutCoder < (UInt32)numEmptyMethods)
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
for (k = 0; k < _bonds.Size(); k++)
|
||||
{
|
||||
CBond2 &bond = _bonds[k];
|
||||
bond.InCoder -= (UInt32)numEmptyMethods;
|
||||
bond.OutCoder -= (UInt32)numEmptyMethods;
|
||||
}
|
||||
_methods.DeleteFrontal(numEmptyMethods);
|
||||
}
|
||||
|
||||
FOR_VECTOR (k, _bonds)
|
||||
{
|
||||
const CBond2 &bond = _bonds[k];
|
||||
if (bond.InCoder >= (UInt32)_methods.Size() ||
|
||||
bond.OutCoder >= (UInt32)_methods.Size())
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
}}
|
19
CPP/7zip/Archive/7z/7zHeader.cpp
Normal file
19
CPP/7zip/Archive/7z/7zHeader.cpp
Normal file
@ -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;
|
||||
|
||||
}}
|
148
CPP/7zip/Archive/7z/7zHeader.h
Normal file
148
CPP/7zip/Archive/7z/7zHeader.h
Normal file
@ -0,0 +1,148 @@
|
||||
// 7z/7zHeader.h
|
||||
|
||||
#ifndef __7Z_HEADER_H
|
||||
#define __7Z_HEADER_H
|
||||
|
||||
#include "../../../Common/MyTypes.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace N7z {
|
||||
|
||||
const unsigned kSignatureSize = 6;
|
||||
extern Byte kSignature[kSignatureSize];
|
||||
|
||||
// #define _7Z_VOL
|
||||
// 7z-MultiVolume is not finished yet.
|
||||
// It can work already, but I still do not like some
|
||||
// things of that new multivolume format.
|
||||
// So please keep it commented.
|
||||
|
||||
#ifdef _7Z_VOL
|
||||
extern Byte kFinishSignature[kSignatureSize];
|
||||
#endif
|
||||
|
||||
struct CArchiveVersion
|
||||
{
|
||||
Byte Major;
|
||||
Byte Minor;
|
||||
};
|
||||
|
||||
const Byte kMajorVersion = 0;
|
||||
|
||||
struct CStartHeader
|
||||
{
|
||||
UInt64 NextHeaderOffset;
|
||||
UInt64 NextHeaderSize;
|
||||
UInt32 NextHeaderCRC;
|
||||
};
|
||||
|
||||
const UInt32 kStartHeaderSize = 20;
|
||||
|
||||
#ifdef _7Z_VOL
|
||||
struct CFinishHeader: public CStartHeader
|
||||
{
|
||||
UInt64 ArchiveStartOffset; // data offset from end if that struct
|
||||
UInt64 AdditionalStartBlockSize; // start signature & start header size
|
||||
};
|
||||
|
||||
const UInt32 kFinishHeaderSize = kStartHeaderSize + 16;
|
||||
#endif
|
||||
|
||||
namespace NID
|
||||
{
|
||||
enum EEnum
|
||||
{
|
||||
kEnd,
|
||||
|
||||
kHeader,
|
||||
|
||||
kArchiveProperties,
|
||||
|
||||
kAdditionalStreamsInfo,
|
||||
kMainStreamsInfo,
|
||||
kFilesInfo,
|
||||
|
||||
kPackInfo,
|
||||
kUnpackInfo,
|
||||
kSubStreamsInfo,
|
||||
|
||||
kSize,
|
||||
kCRC,
|
||||
|
||||
kFolder,
|
||||
|
||||
kCodersUnpackSize,
|
||||
kNumUnpackStream,
|
||||
|
||||
kEmptyStream,
|
||||
kEmptyFile,
|
||||
kAnti,
|
||||
|
||||
kName,
|
||||
kCTime,
|
||||
kATime,
|
||||
kMTime,
|
||||
kWinAttrib,
|
||||
kComment,
|
||||
|
||||
kEncodedHeader,
|
||||
|
||||
kStartPos,
|
||||
kDummy
|
||||
|
||||
// kNtSecure,
|
||||
// kParent,
|
||||
// kIsAux
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
const UInt32 k_Copy = 0;
|
||||
const UInt32 k_Delta = 3;
|
||||
|
||||
const UInt32 k_LZMA2 = 0x21;
|
||||
|
||||
const UInt32 k_SWAP2 = 0x20302;
|
||||
const UInt32 k_SWAP4 = 0x20304;
|
||||
|
||||
const UInt32 k_LZMA = 0x30101;
|
||||
const UInt32 k_PPMD = 0x30401;
|
||||
|
||||
const UInt32 k_Deflate = 0x40108;
|
||||
const UInt32 k_BZip2 = 0x40202;
|
||||
|
||||
const UInt32 k_BCJ = 0x3030103;
|
||||
const UInt32 k_BCJ2 = 0x303011B;
|
||||
const UInt32 k_PPC = 0x3030205;
|
||||
const UInt32 k_IA64 = 0x3030401;
|
||||
const UInt32 k_ARM = 0x3030501;
|
||||
const UInt32 k_ARMT = 0x3030701;
|
||||
const UInt32 k_SPARC = 0x3030805;
|
||||
|
||||
const UInt32 k_AES = 0x6F10701;
|
||||
|
||||
|
||||
static inline bool IsFilterMethod(UInt64 m)
|
||||
{
|
||||
if (m > (UInt64)0xFFFFFFFF)
|
||||
return false;
|
||||
switch ((UInt32)m)
|
||||
{
|
||||
case k_Delta:
|
||||
case k_BCJ:
|
||||
case k_BCJ2:
|
||||
case k_PPC:
|
||||
case k_IA64:
|
||||
case k_ARM:
|
||||
case k_ARMT:
|
||||
case k_SPARC:
|
||||
case k_SWAP2:
|
||||
case k_SWAP4:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
1640
CPP/7zip/Archive/7z/7zIn.cpp
Normal file
1640
CPP/7zip/Archive/7z/7zIn.cpp
Normal file
File diff suppressed because it is too large
Load Diff
431
CPP/7zip/Archive/7z/7zIn.h
Normal file
431
CPP/7zip/Archive/7z/7zIn.h
Normal file
@ -0,0 +1,431 @@
|
||||
// 7zIn.h
|
||||
|
||||
#ifndef __7Z_IN_H
|
||||
#define __7Z_IN_H
|
||||
|
||||
#include "../../../Common/MyCom.h"
|
||||
|
||||
#include "../../../Windows/PropVariant.h"
|
||||
|
||||
#include "../../IPassword.h"
|
||||
#include "../../IStream.h"
|
||||
|
||||
#include "../../Common/CreateCoder.h"
|
||||
#include "../../Common/InBuffer.h"
|
||||
|
||||
#include "7zItem.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace N7z {
|
||||
|
||||
/*
|
||||
We don't need to init isEncrypted and passwordIsDefined
|
||||
We must upgrade them only */
|
||||
|
||||
#ifdef _NO_CRYPTO
|
||||
#define _7Z_DECODER_CRYPRO_VARS_DECL
|
||||
#define _7Z_DECODER_CRYPRO_VARS
|
||||
#else
|
||||
#define _7Z_DECODER_CRYPRO_VARS_DECL , ICryptoGetTextPassword *getTextPassword, bool &isEncrypted, bool &passwordIsDefined, UString &password
|
||||
#define _7Z_DECODER_CRYPRO_VARS , getTextPassword, isEncrypted, passwordIsDefined, password
|
||||
#endif
|
||||
|
||||
struct CParsedMethods
|
||||
{
|
||||
Byte Lzma2Prop;
|
||||
UInt32 LzmaDic;
|
||||
CRecordVector<UInt64> IDs;
|
||||
|
||||
CParsedMethods(): Lzma2Prop(0), LzmaDic(0) {}
|
||||
};
|
||||
|
||||
struct CFolderEx: public CFolder
|
||||
{
|
||||
unsigned UnpackCoder;
|
||||
};
|
||||
|
||||
struct CFolders
|
||||
{
|
||||
CNum NumPackStreams;
|
||||
CNum NumFolders;
|
||||
|
||||
CObjArray<UInt64> PackPositions; // NumPackStreams + 1
|
||||
// CUInt32DefVector PackCRCs; // we don't use PackCRCs now
|
||||
|
||||
CUInt32DefVector FolderCRCs; // NumFolders
|
||||
CObjArray<CNum> NumUnpackStreamsVector; // NumFolders
|
||||
|
||||
CObjArray<UInt64> CoderUnpackSizes; // including unpack sizes of bond coders
|
||||
CObjArray<CNum> FoToCoderUnpackSizes; // NumFolders + 1
|
||||
CObjArray<CNum> FoStartPackStreamIndex; // NumFolders + 1
|
||||
CObjArray<Byte> FoToMainUnpackSizeIndex; // NumFolders
|
||||
|
||||
CObjArray<size_t> FoCodersDataOffset; // NumFolders + 1
|
||||
CByteBuffer CodersData;
|
||||
|
||||
CParsedMethods ParsedMethods;
|
||||
|
||||
void ParseFolderInfo(unsigned folderIndex, CFolder &folder) const;
|
||||
void ParseFolderEx(unsigned folderIndex, CFolderEx &folder) const
|
||||
{
|
||||
ParseFolderInfo(folderIndex, folder);
|
||||
folder.UnpackCoder = FoToMainUnpackSizeIndex[folderIndex];
|
||||
}
|
||||
|
||||
unsigned GetNumFolderUnpackSizes(unsigned folderIndex) const
|
||||
{
|
||||
return (unsigned)(FoToCoderUnpackSizes[folderIndex + 1] - FoToCoderUnpackSizes[folderIndex]);
|
||||
}
|
||||
|
||||
UInt64 GetFolderUnpackSize(unsigned folderIndex) const
|
||||
{
|
||||
return CoderUnpackSizes[FoToCoderUnpackSizes[folderIndex] + FoToMainUnpackSizeIndex[folderIndex]];
|
||||
}
|
||||
|
||||
UInt64 GetStreamPackSize(unsigned index) const
|
||||
{
|
||||
return PackPositions[index + 1] - PackPositions[index];
|
||||
}
|
||||
|
||||
CFolders(): NumPackStreams(0), NumFolders(0) {}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
NumPackStreams = 0;
|
||||
PackPositions.Free();
|
||||
// PackCRCs.Clear();
|
||||
|
||||
NumFolders = 0;
|
||||
FolderCRCs.Clear();
|
||||
NumUnpackStreamsVector.Free();
|
||||
CoderUnpackSizes.Free();
|
||||
FoToCoderUnpackSizes.Free();
|
||||
FoStartPackStreamIndex.Free();
|
||||
FoToMainUnpackSizeIndex.Free();
|
||||
FoCodersDataOffset.Free();
|
||||
CodersData.Free();
|
||||
}
|
||||
};
|
||||
|
||||
struct CDatabase: public CFolders
|
||||
{
|
||||
CRecordVector<CFileItem> Files;
|
||||
|
||||
CUInt64DefVector CTime;
|
||||
CUInt64DefVector ATime;
|
||||
CUInt64DefVector MTime;
|
||||
CUInt64DefVector StartPos;
|
||||
CBoolVector IsAnti;
|
||||
/*
|
||||
CBoolVector IsAux;
|
||||
CByteBuffer SecureBuf;
|
||||
CRecordVector<UInt32> SecureIDs;
|
||||
*/
|
||||
|
||||
CByteBuffer NamesBuf;
|
||||
CObjArray<size_t> NameOffsets; // numFiles + 1, offsets of utf-16 symbols
|
||||
|
||||
/*
|
||||
void ClearSecure()
|
||||
{
|
||||
SecureBuf.Free();
|
||||
SecureIDs.Clear();
|
||||
}
|
||||
*/
|
||||
|
||||
void Clear()
|
||||
{
|
||||
CFolders::Clear();
|
||||
// ClearSecure();
|
||||
|
||||
NamesBuf.Free();
|
||||
NameOffsets.Free();
|
||||
|
||||
Files.Clear();
|
||||
CTime.Clear();
|
||||
ATime.Clear();
|
||||
MTime.Clear();
|
||||
StartPos.Clear();
|
||||
IsAnti.Clear();
|
||||
// IsAux.Clear();
|
||||
}
|
||||
|
||||
bool IsSolid() const
|
||||
{
|
||||
for (CNum i = 0; i < NumFolders; i++)
|
||||
if (NumUnpackStreamsVector[i] > 1)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
bool IsItemAnti(unsigned index) const { return (index < IsAnti.Size() && IsAnti[index]); }
|
||||
// bool IsItemAux(unsigned index) const { return (index < IsAux.Size() && IsAux[index]); }
|
||||
|
||||
/*
|
||||
const void* GetName(unsigned index) const
|
||||
{
|
||||
if (!NameOffsets || !NamesBuf)
|
||||
return NULL;
|
||||
return (void *)((const Byte *)NamesBuf + NameOffsets[index] * 2);
|
||||
};
|
||||
*/
|
||||
void GetPath(unsigned index, UString &path) const;
|
||||
HRESULT GetPath_Prop(unsigned index, PROPVARIANT *path) const throw();
|
||||
};
|
||||
|
||||
struct CInArchiveInfo
|
||||
{
|
||||
CArchiveVersion Version;
|
||||
UInt64 StartPosition;
|
||||
UInt64 StartPositionAfterHeader;
|
||||
UInt64 DataStartPosition;
|
||||
UInt64 DataStartPosition2;
|
||||
CRecordVector<UInt64> FileInfoPopIDs;
|
||||
|
||||
void Clear()
|
||||
{
|
||||
StartPosition = 0;
|
||||
StartPositionAfterHeader = 0;
|
||||
DataStartPosition = 0;
|
||||
DataStartPosition2 = 0;
|
||||
FileInfoPopIDs.Clear();
|
||||
}
|
||||
};
|
||||
|
||||
struct CDbEx: public CDatabase
|
||||
{
|
||||
CInArchiveInfo ArcInfo;
|
||||
|
||||
CObjArray<CNum> FolderStartFileIndex;
|
||||
CObjArray<CNum> FileIndexToFolderIndexMap;
|
||||
|
||||
UInt64 HeadersSize;
|
||||
UInt64 PhySize;
|
||||
|
||||
/*
|
||||
CRecordVector<size_t> SecureOffsets;
|
||||
bool IsTree;
|
||||
bool ThereAreAltStreams;
|
||||
*/
|
||||
|
||||
bool IsArc;
|
||||
bool PhySizeWasConfirmed;
|
||||
|
||||
bool ThereIsHeaderError;
|
||||
bool UnexpectedEnd;
|
||||
// bool UnsupportedVersion;
|
||||
|
||||
bool StartHeaderWasRecovered;
|
||||
bool UnsupportedFeatureWarning;
|
||||
bool UnsupportedFeatureError;
|
||||
|
||||
/*
|
||||
void ClearSecureEx()
|
||||
{
|
||||
ClearSecure();
|
||||
SecureOffsets.Clear();
|
||||
}
|
||||
*/
|
||||
|
||||
void Clear()
|
||||
{
|
||||
IsArc = false;
|
||||
PhySizeWasConfirmed = false;
|
||||
|
||||
ThereIsHeaderError = false;
|
||||
UnexpectedEnd = false;
|
||||
// UnsupportedVersion = false;
|
||||
|
||||
StartHeaderWasRecovered = false;
|
||||
UnsupportedFeatureError = false;
|
||||
UnsupportedFeatureWarning = false;
|
||||
|
||||
/*
|
||||
IsTree = false;
|
||||
ThereAreAltStreams = false;
|
||||
*/
|
||||
|
||||
CDatabase::Clear();
|
||||
|
||||
// SecureOffsets.Clear();
|
||||
ArcInfo.Clear();
|
||||
FolderStartFileIndex.Free();
|
||||
FileIndexToFolderIndexMap.Free();
|
||||
|
||||
HeadersSize = 0;
|
||||
PhySize = 0;
|
||||
}
|
||||
|
||||
void FillLinks();
|
||||
|
||||
UInt64 GetFolderStreamPos(CNum folderIndex, unsigned indexInFolder) const
|
||||
{
|
||||
return ArcInfo.DataStartPosition +
|
||||
PackPositions[FoStartPackStreamIndex[folderIndex] + indexInFolder];
|
||||
}
|
||||
|
||||
UInt64 GetFolderFullPackSize(CNum folderIndex) const
|
||||
{
|
||||
return
|
||||
PackPositions[FoStartPackStreamIndex[folderIndex + 1]] -
|
||||
PackPositions[FoStartPackStreamIndex[folderIndex]];
|
||||
}
|
||||
|
||||
UInt64 GetFolderPackStreamSize(CNum folderIndex, unsigned streamIndex) const
|
||||
{
|
||||
size_t i = FoStartPackStreamIndex[folderIndex] + streamIndex;
|
||||
return PackPositions[i + 1] - PackPositions[i];
|
||||
}
|
||||
|
||||
UInt64 GetFilePackSize(CNum fileIndex) const
|
||||
{
|
||||
CNum folderIndex = FileIndexToFolderIndexMap[fileIndex];
|
||||
if (folderIndex != kNumNoIndex)
|
||||
if (FolderStartFileIndex[folderIndex] == fileIndex)
|
||||
return GetFolderFullPackSize(folderIndex);
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
const unsigned kNumBufLevelsMax = 4;
|
||||
|
||||
struct CInByte2
|
||||
{
|
||||
const Byte *_buffer;
|
||||
public:
|
||||
size_t _size;
|
||||
size_t _pos;
|
||||
|
||||
size_t GetRem() const { return _size - _pos; }
|
||||
const Byte *GetPtr() const { return _buffer + _pos; }
|
||||
void Init(const Byte *buffer, size_t size)
|
||||
{
|
||||
_buffer = buffer;
|
||||
_size = size;
|
||||
_pos = 0;
|
||||
}
|
||||
Byte ReadByte();
|
||||
void ReadBytes(Byte *data, size_t size);
|
||||
void SkipDataNoCheck(UInt64 size) { _pos += (size_t)size; }
|
||||
void SkipData(UInt64 size);
|
||||
|
||||
void SkipData();
|
||||
void SkipRem() { _pos = _size; }
|
||||
UInt64 ReadNumber();
|
||||
CNum ReadNum();
|
||||
UInt32 ReadUInt32();
|
||||
UInt64 ReadUInt64();
|
||||
|
||||
void ParseFolder(CFolder &folder);
|
||||
};
|
||||
|
||||
class CStreamSwitch;
|
||||
|
||||
const UInt32 kHeaderSize = 32;
|
||||
|
||||
class CInArchive
|
||||
{
|
||||
friend class CStreamSwitch;
|
||||
|
||||
CMyComPtr<IInStream> _stream;
|
||||
|
||||
unsigned _numInByteBufs;
|
||||
CInByte2 _inByteVector[kNumBufLevelsMax];
|
||||
|
||||
CInByte2 *_inByteBack;
|
||||
bool ThereIsHeaderError;
|
||||
|
||||
UInt64 _arhiveBeginStreamPosition;
|
||||
UInt64 _fileEndPosition;
|
||||
|
||||
Byte _header[kHeaderSize];
|
||||
|
||||
UInt64 HeadersSize;
|
||||
|
||||
bool _useMixerMT;
|
||||
|
||||
void AddByteStream(const Byte *buffer, size_t size);
|
||||
|
||||
void DeleteByteStream(bool needUpdatePos)
|
||||
{
|
||||
_numInByteBufs--;
|
||||
if (_numInByteBufs > 0)
|
||||
{
|
||||
_inByteBack = &_inByteVector[_numInByteBufs - 1];
|
||||
if (needUpdatePos)
|
||||
_inByteBack->_pos += _inByteVector[_numInByteBufs]._pos;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT FindAndReadSignature(IInStream *stream, const UInt64 *searchHeaderSizeLimit);
|
||||
|
||||
void ReadBytes(Byte *data, size_t size) { _inByteBack->ReadBytes(data, size); }
|
||||
Byte ReadByte() { return _inByteBack->ReadByte(); }
|
||||
UInt64 ReadNumber() { return _inByteBack->ReadNumber(); }
|
||||
CNum ReadNum() { return _inByteBack->ReadNum(); }
|
||||
UInt64 ReadID() { return _inByteBack->ReadNumber(); }
|
||||
UInt32 ReadUInt32() { return _inByteBack->ReadUInt32(); }
|
||||
UInt64 ReadUInt64() { return _inByteBack->ReadUInt64(); }
|
||||
void SkipData(UInt64 size) { _inByteBack->SkipData(size); }
|
||||
void SkipData() { _inByteBack->SkipData(); }
|
||||
void WaitId(UInt64 id);
|
||||
|
||||
void ReadArchiveProperties(CInArchiveInfo &archiveInfo);
|
||||
void ReadHashDigests(unsigned numItems, CUInt32DefVector &crcs);
|
||||
|
||||
void ReadPackInfo(CFolders &f);
|
||||
|
||||
void ReadUnpackInfo(
|
||||
const CObjectVector<CByteBuffer> *dataVector,
|
||||
CFolders &folders);
|
||||
|
||||
void ReadSubStreamsInfo(
|
||||
CFolders &folders,
|
||||
CRecordVector<UInt64> &unpackSizes,
|
||||
CUInt32DefVector &digests);
|
||||
|
||||
void ReadStreamsInfo(
|
||||
const CObjectVector<CByteBuffer> *dataVector,
|
||||
UInt64 &dataOffset,
|
||||
CFolders &folders,
|
||||
CRecordVector<UInt64> &unpackSizes,
|
||||
CUInt32DefVector &digests);
|
||||
|
||||
void ReadBoolVector(unsigned numItems, CBoolVector &v);
|
||||
void ReadBoolVector2(unsigned numItems, CBoolVector &v);
|
||||
void ReadUInt64DefVector(const CObjectVector<CByteBuffer> &dataVector,
|
||||
CUInt64DefVector &v, unsigned numItems);
|
||||
HRESULT ReadAndDecodePackedStreams(
|
||||
DECL_EXTERNAL_CODECS_LOC_VARS
|
||||
UInt64 baseOffset, UInt64 &dataOffset,
|
||||
CObjectVector<CByteBuffer> &dataVector
|
||||
_7Z_DECODER_CRYPRO_VARS_DECL
|
||||
);
|
||||
HRESULT ReadHeader(
|
||||
DECL_EXTERNAL_CODECS_LOC_VARS
|
||||
CDbEx &db
|
||||
_7Z_DECODER_CRYPRO_VARS_DECL
|
||||
);
|
||||
HRESULT ReadDatabase2(
|
||||
DECL_EXTERNAL_CODECS_LOC_VARS
|
||||
CDbEx &db
|
||||
_7Z_DECODER_CRYPRO_VARS_DECL
|
||||
);
|
||||
public:
|
||||
CInArchive(bool useMixerMT):
|
||||
_numInByteBufs(0),
|
||||
_useMixerMT(useMixerMT)
|
||||
{}
|
||||
|
||||
HRESULT Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit); // S_FALSE means is not archive
|
||||
void Close();
|
||||
|
||||
HRESULT ReadDatabase(
|
||||
DECL_EXTERNAL_CODECS_LOC_VARS
|
||||
CDbEx &db
|
||||
_7Z_DECODER_CRYPRO_VARS_DECL
|
||||
);
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
183
CPP/7zip/Archive/7z/7zItem.h
Normal file
183
CPP/7zip/Archive/7z/7zItem.h
Normal file
@ -0,0 +1,183 @@
|
||||
// 7zItem.h
|
||||
|
||||
#ifndef __7Z_ITEM_H
|
||||
#define __7Z_ITEM_H
|
||||
|
||||
#include "../../../Common/MyBuffer.h"
|
||||
#include "../../../Common/MyString.h"
|
||||
|
||||
#include "../../Common/MethodId.h"
|
||||
|
||||
#include "7zHeader.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace N7z {
|
||||
|
||||
typedef UInt32 CNum;
|
||||
const CNum kNumMax = 0x7FFFFFFF;
|
||||
const CNum kNumNoIndex = 0xFFFFFFFF;
|
||||
|
||||
struct CCoderInfo
|
||||
{
|
||||
CMethodId MethodID;
|
||||
CByteBuffer Props;
|
||||
UInt32 NumStreams;
|
||||
|
||||
bool IsSimpleCoder() const { return NumStreams == 1; }
|
||||
};
|
||||
|
||||
struct CBond
|
||||
{
|
||||
UInt32 PackIndex;
|
||||
UInt32 UnpackIndex;
|
||||
};
|
||||
|
||||
struct CFolder
|
||||
{
|
||||
CLASS_NO_COPY(CFolder)
|
||||
public:
|
||||
CObjArray2<CCoderInfo> Coders;
|
||||
CObjArray2<CBond> Bonds;
|
||||
CObjArray2<UInt32> PackStreams;
|
||||
|
||||
CFolder() {}
|
||||
|
||||
bool IsDecodingSupported() const { return Coders.Size() <= 32; }
|
||||
|
||||
int Find_in_PackStreams(UInt32 packStream) const
|
||||
{
|
||||
FOR_VECTOR(i, PackStreams)
|
||||
if (PackStreams[i] == packStream)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int FindBond_for_PackStream(UInt32 packStream) const
|
||||
{
|
||||
FOR_VECTOR(i, Bonds)
|
||||
if (Bonds[i].PackIndex == packStream)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
int FindBond_for_UnpackStream(UInt32 unpackStream) const
|
||||
{
|
||||
FOR_VECTOR(i, Bonds)
|
||||
if (Bonds[i].UnpackIndex == unpackStream)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int FindOutCoder() const
|
||||
{
|
||||
for (int i = (int)Coders.Size() - 1; i >= 0; i--)
|
||||
if (FindBond_for_UnpackStream(i) < 0)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
*/
|
||||
|
||||
bool IsEncrypted() const
|
||||
{
|
||||
FOR_VECTOR(i, Coders)
|
||||
if (Coders[i].MethodID == k_AES)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
struct CUInt32DefVector
|
||||
{
|
||||
CBoolVector Defs;
|
||||
CRecordVector<UInt32> Vals;
|
||||
|
||||
void ClearAndSetSize(unsigned newSize)
|
||||
{
|
||||
Defs.ClearAndSetSize(newSize);
|
||||
Vals.ClearAndSetSize(newSize);
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
Defs.Clear();
|
||||
Vals.Clear();
|
||||
}
|
||||
|
||||
void ReserveDown()
|
||||
{
|
||||
Defs.ReserveDown();
|
||||
Vals.ReserveDown();
|
||||
}
|
||||
|
||||
bool 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
|
916
CPP/7zip/Archive/7z/7zOut.cpp
Normal file
916
CPP/7zip/Archive/7z/7zOut.cpp
Normal file
@ -0,0 +1,916 @@
|
||||
// 7zOut.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../../C/7zCrc.h"
|
||||
|
||||
#include "../../../Common/AutoPtr.h"
|
||||
|
||||
#include "../../Common/StreamObjects.h"
|
||||
|
||||
#include "7zOut.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace N7z {
|
||||
|
||||
HRESULT COutArchive::WriteSignature()
|
||||
{
|
||||
Byte buf[8];
|
||||
memcpy(buf, kSignature, kSignatureSize);
|
||||
buf[kSignatureSize] = kMajorVersion;
|
||||
buf[kSignatureSize + 1] = 4;
|
||||
return WriteDirect(buf, 8);
|
||||
}
|
||||
|
||||
#ifdef _7Z_VOL
|
||||
HRESULT COutArchive::WriteFinishSignature()
|
||||
{
|
||||
RINOK(WriteDirect(kFinishSignature, kSignatureSize));
|
||||
CArchiveVersion av;
|
||||
av.Major = kMajorVersion;
|
||||
av.Minor = 2;
|
||||
RINOK(WriteDirectByte(av.Major));
|
||||
return WriteDirectByte(av.Minor);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void SetUInt32(Byte *p, UInt32 d)
|
||||
{
|
||||
for (int i = 0; i < 4; i++, d >>= 8)
|
||||
p[i] = (Byte)d;
|
||||
}
|
||||
|
||||
static void SetUInt64(Byte *p, UInt64 d)
|
||||
{
|
||||
for (int i = 0; i < 8; i++, d >>= 8)
|
||||
p[i] = (Byte)d;
|
||||
}
|
||||
|
||||
HRESULT COutArchive::WriteStartHeader(const CStartHeader &h)
|
||||
{
|
||||
Byte buf[24];
|
||||
SetUInt64(buf + 4, h.NextHeaderOffset);
|
||||
SetUInt64(buf + 12, h.NextHeaderSize);
|
||||
SetUInt32(buf + 20, h.NextHeaderCRC);
|
||||
SetUInt32(buf, CrcCalc(buf + 4, 20));
|
||||
return WriteDirect(buf, 24);
|
||||
}
|
||||
|
||||
#ifdef _7Z_VOL
|
||||
HRESULT COutArchive::WriteFinishHeader(const CFinishHeader &h)
|
||||
{
|
||||
CCRC crc;
|
||||
crc.UpdateUInt64(h.NextHeaderOffset);
|
||||
crc.UpdateUInt64(h.NextHeaderSize);
|
||||
crc.UpdateUInt32(h.NextHeaderCRC);
|
||||
crc.UpdateUInt64(h.ArchiveStartOffset);
|
||||
crc.UpdateUInt64(h.AdditionalStartBlockSize);
|
||||
RINOK(WriteDirectUInt32(crc.GetDigest()));
|
||||
RINOK(WriteDirectUInt64(h.NextHeaderOffset));
|
||||
RINOK(WriteDirectUInt64(h.NextHeaderSize));
|
||||
RINOK(WriteDirectUInt32(h.NextHeaderCRC));
|
||||
RINOK(WriteDirectUInt64(h.ArchiveStartOffset));
|
||||
return WriteDirectUInt64(h.AdditionalStartBlockSize);
|
||||
}
|
||||
#endif
|
||||
|
||||
HRESULT COutArchive::Create(ISequentialOutStream *stream, bool endMarker)
|
||||
{
|
||||
Close();
|
||||
#ifdef _7Z_VOL
|
||||
// endMarker = false;
|
||||
_endMarker = endMarker;
|
||||
#endif
|
||||
SeqStream = stream;
|
||||
if (!endMarker)
|
||||
{
|
||||
SeqStream.QueryInterface(IID_IOutStream, &Stream);
|
||||
if (!Stream)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
// endMarker = true;
|
||||
}
|
||||
}
|
||||
#ifdef _7Z_VOL
|
||||
if (endMarker)
|
||||
{
|
||||
/*
|
||||
CStartHeader sh;
|
||||
sh.NextHeaderOffset = (UInt32)(Int32)-1;
|
||||
sh.NextHeaderSize = (UInt32)(Int32)-1;
|
||||
sh.NextHeaderCRC = 0;
|
||||
WriteStartHeader(sh);
|
||||
*/
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if (!Stream)
|
||||
return E_FAIL;
|
||||
RINOK(WriteSignature());
|
||||
RINOK(Stream->Seek(0, STREAM_SEEK_CUR, &_prefixHeaderPos));
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void COutArchive::Close()
|
||||
{
|
||||
SeqStream.Release();
|
||||
Stream.Release();
|
||||
}
|
||||
|
||||
HRESULT COutArchive::SkipPrefixArchiveHeader()
|
||||
{
|
||||
#ifdef _7Z_VOL
|
||||
if (_endMarker)
|
||||
return S_OK;
|
||||
#endif
|
||||
Byte buf[24];
|
||||
memset(buf, 0, 24);
|
||||
return WriteDirect(buf, 24);
|
||||
}
|
||||
|
||||
UInt64 COutArchive::GetPos() const
|
||||
{
|
||||
if (_countMode)
|
||||
return _countSize;
|
||||
if (_writeToStream)
|
||||
return _outByte.GetProcessedSize();
|
||||
return _outByte2.GetPos();
|
||||
}
|
||||
|
||||
void COutArchive::WriteBytes(const void *data, size_t size)
|
||||
{
|
||||
if (_countMode)
|
||||
_countSize += size;
|
||||
else if (_writeToStream)
|
||||
{
|
||||
_outByte.WriteBytes(data, size);
|
||||
_crc = CrcUpdate(_crc, data, size);
|
||||
}
|
||||
else
|
||||
_outByte2.WriteBytes(data, size);
|
||||
}
|
||||
|
||||
void COutArchive::WriteByte(Byte b)
|
||||
{
|
||||
if (_countMode)
|
||||
_countSize++;
|
||||
else if (_writeToStream)
|
||||
{
|
||||
_outByte.WriteByte(b);
|
||||
_crc = CRC_UPDATE_BYTE(_crc, b);
|
||||
}
|
||||
else
|
||||
_outByte2.WriteByte(b);
|
||||
}
|
||||
|
||||
void COutArchive::WriteUInt32(UInt32 value)
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
WriteByte((Byte)value);
|
||||
value >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
void COutArchive::WriteUInt64(UInt64 value)
|
||||
{
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
WriteByte((Byte)value);
|
||||
value >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
void COutArchive::WriteNumber(UInt64 value)
|
||||
{
|
||||
Byte firstByte = 0;
|
||||
Byte mask = 0x80;
|
||||
int i;
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
if (value < ((UInt64(1) << ( 7 * (i + 1)))))
|
||||
{
|
||||
firstByte |= Byte(value >> (8 * i));
|
||||
break;
|
||||
}
|
||||
firstByte |= mask;
|
||||
mask >>= 1;
|
||||
}
|
||||
WriteByte(firstByte);
|
||||
for (; i > 0; i--)
|
||||
{
|
||||
WriteByte((Byte)value);
|
||||
value >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
static UInt32 GetBigNumberSize(UInt64 value)
|
||||
{
|
||||
int i;
|
||||
for (i = 1; i < 9; i++)
|
||||
if (value < (((UInt64)1 << (i * 7))))
|
||||
break;
|
||||
return i;
|
||||
}
|
||||
|
||||
#ifdef _7Z_VOL
|
||||
UInt32 COutArchive::GetVolHeadersSize(UInt64 dataSize, int nameLength, bool props)
|
||||
{
|
||||
UInt32 result = GetBigNumberSize(dataSize) * 2 + 41;
|
||||
if (nameLength != 0)
|
||||
{
|
||||
nameLength = (nameLength + 1) * 2;
|
||||
result += nameLength + GetBigNumberSize(nameLength) + 2;
|
||||
}
|
||||
if (props)
|
||||
{
|
||||
result += 20;
|
||||
}
|
||||
if (result >= 128)
|
||||
result++;
|
||||
result += kSignatureSize + 2 + kFinishHeaderSize;
|
||||
return result;
|
||||
}
|
||||
|
||||
UInt64 COutArchive::GetVolPureSize(UInt64 volSize, int nameLength, bool props)
|
||||
{
|
||||
UInt32 headersSizeBase = COutArchive::GetVolHeadersSize(1, nameLength, props);
|
||||
int testSize;
|
||||
if (volSize > headersSizeBase)
|
||||
testSize = volSize - headersSizeBase;
|
||||
else
|
||||
testSize = 1;
|
||||
UInt32 headersSize = COutArchive::GetVolHeadersSize(testSize, nameLength, props);
|
||||
UInt64 pureSize = 1;
|
||||
if (volSize > headersSize)
|
||||
pureSize = volSize - headersSize;
|
||||
return pureSize;
|
||||
}
|
||||
#endif
|
||||
|
||||
void COutArchive::WriteFolder(const CFolder &folder)
|
||||
{
|
||||
WriteNumber(folder.Coders.Size());
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < folder.Coders.Size(); i++)
|
||||
{
|
||||
const CCoderInfo &coder = folder.Coders[i];
|
||||
{
|
||||
UInt64 id = coder.MethodID;
|
||||
unsigned idSize;
|
||||
for (idSize = 1; idSize < sizeof(id); idSize++)
|
||||
if ((id >> (8 * idSize)) == 0)
|
||||
break;
|
||||
idSize &= 0xF;
|
||||
Byte temp[16];
|
||||
for (unsigned t = idSize; t != 0; t--, id >>= 8)
|
||||
temp[t] = (Byte)(id & 0xFF);
|
||||
|
||||
Byte b = (Byte)(idSize);
|
||||
bool isComplex = !coder.IsSimpleCoder();
|
||||
b |= (isComplex ? 0x10 : 0);
|
||||
|
||||
size_t propsSize = coder.Props.Size();
|
||||
b |= ((propsSize != 0) ? 0x20 : 0);
|
||||
temp[0] = b;
|
||||
WriteBytes(temp, idSize + 1);
|
||||
if (isComplex)
|
||||
{
|
||||
WriteNumber(coder.NumStreams);
|
||||
WriteNumber(1); // NumOutStreams;
|
||||
}
|
||||
if (propsSize == 0)
|
||||
continue;
|
||||
WriteNumber(propsSize);
|
||||
WriteBytes(coder.Props, propsSize);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < folder.Bonds.Size(); i++)
|
||||
{
|
||||
const CBond &bond = folder.Bonds[i];
|
||||
WriteNumber(bond.PackIndex);
|
||||
WriteNumber(bond.UnpackIndex);
|
||||
}
|
||||
|
||||
if (folder.PackStreams.Size() > 1)
|
||||
for (i = 0; i < folder.PackStreams.Size(); i++)
|
||||
WriteNumber(folder.PackStreams[i]);
|
||||
}
|
||||
|
||||
void COutArchive::WriteBoolVector(const CBoolVector &boolVector)
|
||||
{
|
||||
Byte b = 0;
|
||||
Byte mask = 0x80;
|
||||
FOR_VECTOR (i, boolVector)
|
||||
{
|
||||
if (boolVector[i])
|
||||
b |= mask;
|
||||
mask >>= 1;
|
||||
if (mask == 0)
|
||||
{
|
||||
WriteByte(b);
|
||||
mask = 0x80;
|
||||
b = 0;
|
||||
}
|
||||
}
|
||||
if (mask != 0x80)
|
||||
WriteByte(b);
|
||||
}
|
||||
|
||||
static inline unsigned Bv_GetSizeInBytes(const CBoolVector &v) { return ((unsigned)v.Size() + 7) / 8; }
|
||||
|
||||
void COutArchive::WritePropBoolVector(Byte id, const CBoolVector &boolVector)
|
||||
{
|
||||
WriteByte(id);
|
||||
WriteNumber(Bv_GetSizeInBytes(boolVector));
|
||||
WriteBoolVector(boolVector);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
{
|
||||
UInt64 packSize = 0;
|
||||
FOR_VECTOR (i, db.PackSizes)
|
||||
packSize += db.PackSizes[i];
|
||||
headerOffset = packSize;
|
||||
}
|
||||
|
||||
|
||||
WriteByte(NID::kHeader);
|
||||
|
||||
// Archive Properties
|
||||
|
||||
if (db.Folders.Size() > 0)
|
||||
{
|
||||
WriteByte(NID::kMainStreamsInfo);
|
||||
WritePackInfo(0, db.PackSizes, db.PackCRCs);
|
||||
WriteUnpackInfo(db.Folders, (const COutFolders &)db);
|
||||
|
||||
CRecordVector<UInt64> unpackSizes;
|
||||
CUInt32DefVector digests;
|
||||
FOR_VECTOR (i, db.Files)
|
||||
{
|
||||
const CFileItem &file = db.Files[i];
|
||||
if (!file.HasStream)
|
||||
continue;
|
||||
unpackSizes.Add(file.Size);
|
||||
digests.Defs.Add(file.CrcDefined);
|
||||
digests.Vals.Add(file.Crc);
|
||||
}
|
||||
|
||||
WriteSubStreamsInfo(db.Folders, (const COutFolders &)db, unpackSizes, digests);
|
||||
WriteByte(NID::kEnd);
|
||||
}
|
||||
|
||||
if (db.Files.IsEmpty())
|
||||
{
|
||||
WriteByte(NID::kEnd);
|
||||
return;
|
||||
}
|
||||
|
||||
WriteByte(NID::kFilesInfo);
|
||||
WriteNumber(db.Files.Size());
|
||||
|
||||
{
|
||||
/* ---------- Empty Streams ---------- */
|
||||
CBoolVector emptyStreamVector;
|
||||
emptyStreamVector.ClearAndSetSize(db.Files.Size());
|
||||
unsigned numEmptyStreams = 0;
|
||||
{
|
||||
FOR_VECTOR (i, db.Files)
|
||||
if (db.Files[i].HasStream)
|
||||
emptyStreamVector[i] = false;
|
||||
else
|
||||
{
|
||||
emptyStreamVector[i] = true;
|
||||
numEmptyStreams++;
|
||||
}
|
||||
}
|
||||
|
||||
if (numEmptyStreams != 0)
|
||||
{
|
||||
WritePropBoolVector(NID::kEmptyStream, emptyStreamVector);
|
||||
|
||||
CBoolVector emptyFileVector, antiVector;
|
||||
emptyFileVector.ClearAndSetSize(numEmptyStreams);
|
||||
antiVector.ClearAndSetSize(numEmptyStreams);
|
||||
bool thereAreEmptyFiles = false, thereAreAntiItems = false;
|
||||
unsigned cur = 0;
|
||||
|
||||
FOR_VECTOR (i, db.Files)
|
||||
{
|
||||
const CFileItem &file = db.Files[i];
|
||||
if (file.HasStream)
|
||||
continue;
|
||||
emptyFileVector[cur] = !file.IsDir;
|
||||
if (!file.IsDir)
|
||||
thereAreEmptyFiles = true;
|
||||
bool isAnti = db.IsItemAnti(i);
|
||||
antiVector[cur] = isAnti;
|
||||
if (isAnti)
|
||||
thereAreAntiItems = true;
|
||||
cur++;
|
||||
}
|
||||
|
||||
if (thereAreEmptyFiles)
|
||||
WritePropBoolVector(NID::kEmptyFile, emptyFileVector);
|
||||
if (thereAreAntiItems)
|
||||
WritePropBoolVector(NID::kAnti, antiVector);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
/* ---------- Names ---------- */
|
||||
|
||||
unsigned numDefined = 0;
|
||||
size_t namesDataSize = 0;
|
||||
FOR_VECTOR (i, db.Files)
|
||||
{
|
||||
const UString &name = db.Names[i];
|
||||
if (!name.IsEmpty())
|
||||
numDefined++;
|
||||
namesDataSize += (name.Len() + 1) * 2;
|
||||
}
|
||||
|
||||
if (numDefined > 0)
|
||||
{
|
||||
namesDataSize++;
|
||||
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_VECTOR (i, db.Files)
|
||||
{
|
||||
bool defined = db.Files[i].AttribDefined;
|
||||
boolVector[i] = defined;
|
||||
if (defined)
|
||||
numDefined++;
|
||||
}
|
||||
}
|
||||
|
||||
if (numDefined != 0)
|
||||
{
|
||||
WriteAlignedBoolHeader(boolVector, numDefined, NID::kWinAttrib, 4);
|
||||
FOR_VECTOR (i, db.Files)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
}}
|
321
CPP/7zip/Archive/7z/7zOut.h
Normal file
321
CPP/7zip/Archive/7z/7zOut.h
Normal file
@ -0,0 +1,321 @@
|
||||
// 7zOut.h
|
||||
|
||||
#ifndef __7Z_OUT_H
|
||||
#define __7Z_OUT_H
|
||||
|
||||
#include "7zCompressionMode.h"
|
||||
#include "7zEncode.h"
|
||||
#include "7zHeader.h"
|
||||
#include "7zItem.h"
|
||||
|
||||
#include "../../Common/OutBuffer.h"
|
||||
#include "../../Common/StreamUtils.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace N7z {
|
||||
|
||||
class CWriteBufferLoc
|
||||
{
|
||||
Byte *_data;
|
||||
size_t _size;
|
||||
size_t _pos;
|
||||
public:
|
||||
CWriteBufferLoc(): _size(0), _pos(0) {}
|
||||
void Init(Byte *data, size_t size)
|
||||
{
|
||||
_data = data;
|
||||
_size = size;
|
||||
_pos = 0;
|
||||
}
|
||||
void WriteBytes(const void *data, size_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
return;
|
||||
if (size > _size - _pos)
|
||||
throw 1;
|
||||
memcpy(_data + _pos, data, size);
|
||||
_pos += size;
|
||||
}
|
||||
void WriteByte(Byte b)
|
||||
{
|
||||
if (_size == _pos)
|
||||
throw 1;
|
||||
_data[_pos++] = b;
|
||||
}
|
||||
size_t GetPos() const { return _pos; }
|
||||
};
|
||||
|
||||
struct CHeaderOptions
|
||||
{
|
||||
bool CompressMainHeader;
|
||||
/*
|
||||
bool WriteCTime;
|
||||
bool WriteATime;
|
||||
bool WriteMTime;
|
||||
*/
|
||||
|
||||
CHeaderOptions():
|
||||
CompressMainHeader(true)
|
||||
/*
|
||||
, WriteCTime(false)
|
||||
, WriteATime(false)
|
||||
, WriteMTime(true)
|
||||
*/
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
struct CFileItem2
|
||||
{
|
||||
UInt64 CTime;
|
||||
UInt64 ATime;
|
||||
UInt64 MTime;
|
||||
UInt64 StartPos;
|
||||
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 bond coders
|
||||
|
||||
void OutFoldersClear()
|
||||
{
|
||||
FolderUnpackCRCs.Clear();
|
||||
NumUnpackStreamsVector.Clear();
|
||||
CoderUnpackSizes.Clear();
|
||||
}
|
||||
|
||||
void OutFoldersReserveDown()
|
||||
{
|
||||
FolderUnpackCRCs.ReserveDown();
|
||||
NumUnpackStreamsVector.ReserveDown();
|
||||
CoderUnpackSizes.ReserveDown();
|
||||
}
|
||||
};
|
||||
|
||||
struct CArchiveDatabaseOut: public COutFolders
|
||||
{
|
||||
CRecordVector<UInt64> PackSizes;
|
||||
CUInt32DefVector PackCRCs;
|
||||
CObjectVector<CFolder> Folders;
|
||||
|
||||
CRecordVector<CFileItem> Files;
|
||||
UStringVector Names;
|
||||
CUInt64DefVector CTime;
|
||||
CUInt64DefVector ATime;
|
||||
CUInt64DefVector MTime;
|
||||
CUInt64DefVector StartPos;
|
||||
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
|
174
CPP/7zip/Archive/7z/7zProperties.cpp
Normal file
174
CPP/7zip/Archive/7z/7zProperties.cpp
Normal file
@ -0,0 +1,174 @@
|
||||
// 7zProperties.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "7zProperties.h"
|
||||
#include "7zHeader.h"
|
||||
#include "7zHandler.h"
|
||||
|
||||
// #define _MULTI_PACK
|
||||
|
||||
namespace NArchive {
|
||||
namespace N7z {
|
||||
|
||||
struct CPropMap
|
||||
{
|
||||
UInt32 FilePropID;
|
||||
CStatProp StatProp;
|
||||
};
|
||||
|
||||
static const CPropMap kPropMap[] =
|
||||
{
|
||||
{ NID::kName, { NULL, kpidPath, VT_BSTR } },
|
||||
{ NID::kSize, { NULL, kpidSize, VT_UI8 } },
|
||||
{ NID::kPackInfo, { NULL, kpidPackSize, VT_UI8 } },
|
||||
|
||||
#ifdef _MULTI_PACK
|
||||
{ 100, { "Pack0", kpidPackedSize0, VT_UI8 } },
|
||||
{ 101, { "Pack1", kpidPackedSize1, VT_UI8 } },
|
||||
{ 102, { "Pack2", kpidPackedSize2, VT_UI8 } },
|
||||
{ 103, { "Pack3", kpidPackedSize3, VT_UI8 } },
|
||||
{ 104, { "Pack4", kpidPackedSize4, VT_UI8 } },
|
||||
#endif
|
||||
|
||||
{ NID::kCTime, { NULL, kpidCTime, VT_FILETIME } },
|
||||
{ NID::kMTime, { NULL, kpidMTime, VT_FILETIME } },
|
||||
{ NID::kATime, { NULL, kpidATime, VT_FILETIME } },
|
||||
{ NID::kWinAttrib, { NULL, kpidAttrib, VT_UI4 } },
|
||||
{ NID::kStartPos, { NULL, kpidPosition, VT_UI8 } },
|
||||
|
||||
{ NID::kCRC, { NULL, kpidCRC, VT_UI4 } },
|
||||
|
||||
// { NID::kIsAux, { NULL, kpidIsAux, VT_BOOL } },
|
||||
{ NID::kAnti, { NULL, kpidIsAnti, VT_BOOL } }
|
||||
|
||||
#ifndef _SFX
|
||||
,
|
||||
{ 97, { NULL, kpidEncrypted, VT_BOOL } },
|
||||
{ 98, { NULL, kpidMethod, VT_BSTR } },
|
||||
{ 99, { NULL, kpidBlock, VT_UI4 } }
|
||||
#endif
|
||||
};
|
||||
|
||||
static void CopyOneItem(CRecordVector<UInt64> &src,
|
||||
CRecordVector<UInt64> &dest, UInt32 item)
|
||||
{
|
||||
FOR_VECTOR (i, src)
|
||||
if (src[i] == item)
|
||||
{
|
||||
dest.Add(item);
|
||||
src.Delete(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void RemoveOneItem(CRecordVector<UInt64> &src, UInt32 item)
|
||||
{
|
||||
FOR_VECTOR (i, src)
|
||||
if (src[i] == item)
|
||||
{
|
||||
src.Delete(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void InsertToHead(CRecordVector<UInt64> &dest, UInt32 item)
|
||||
{
|
||||
FOR_VECTOR (i, dest)
|
||||
if (dest[i] == item)
|
||||
{
|
||||
dest.Delete(i);
|
||||
break;
|
||||
}
|
||||
dest.Insert(0, item);
|
||||
}
|
||||
|
||||
#define COPY_ONE_ITEM(id) CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::id);
|
||||
|
||||
void CHandler::FillPopIDs()
|
||||
{
|
||||
_fileInfoPopIDs.Clear();
|
||||
|
||||
#ifdef _7Z_VOL
|
||||
if (_volumes.Size() < 1)
|
||||
return;
|
||||
const CVolume &volume = _volumes.Front();
|
||||
const CArchiveDatabaseEx &_db = volume.Database;
|
||||
#endif
|
||||
|
||||
CRecordVector<UInt64> fileInfoPopIDs = _db.ArcInfo.FileInfoPopIDs;
|
||||
|
||||
RemoveOneItem(fileInfoPopIDs, NID::kEmptyStream);
|
||||
RemoveOneItem(fileInfoPopIDs, NID::kEmptyFile);
|
||||
/*
|
||||
RemoveOneItem(fileInfoPopIDs, NID::kParent);
|
||||
RemoveOneItem(fileInfoPopIDs, NID::kNtSecure);
|
||||
*/
|
||||
|
||||
COPY_ONE_ITEM(kName);
|
||||
COPY_ONE_ITEM(kAnti);
|
||||
COPY_ONE_ITEM(kSize);
|
||||
COPY_ONE_ITEM(kPackInfo);
|
||||
COPY_ONE_ITEM(kCTime);
|
||||
COPY_ONE_ITEM(kMTime);
|
||||
COPY_ONE_ITEM(kATime);
|
||||
COPY_ONE_ITEM(kWinAttrib);
|
||||
COPY_ONE_ITEM(kCRC);
|
||||
COPY_ONE_ITEM(kComment);
|
||||
|
||||
_fileInfoPopIDs += fileInfoPopIDs;
|
||||
|
||||
#ifndef _SFX
|
||||
_fileInfoPopIDs.Add(97);
|
||||
_fileInfoPopIDs.Add(98);
|
||||
_fileInfoPopIDs.Add(99);
|
||||
#endif
|
||||
|
||||
#ifdef _MULTI_PACK
|
||||
_fileInfoPopIDs.Add(100);
|
||||
_fileInfoPopIDs.Add(101);
|
||||
_fileInfoPopIDs.Add(102);
|
||||
_fileInfoPopIDs.Add(103);
|
||||
_fileInfoPopIDs.Add(104);
|
||||
#endif
|
||||
|
||||
#ifndef _SFX
|
||||
InsertToHead(_fileInfoPopIDs, NID::kMTime);
|
||||
InsertToHead(_fileInfoPopIDs, NID::kPackInfo);
|
||||
InsertToHead(_fileInfoPopIDs, NID::kSize);
|
||||
InsertToHead(_fileInfoPopIDs, NID::kName);
|
||||
#endif
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProps)
|
||||
{
|
||||
*numProps = _fileInfoPopIDs.Size();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetPropertyInfo(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)
|
||||
{
|
||||
if (index >= _fileInfoPopIDs.Size())
|
||||
return E_INVALIDARG;
|
||||
UInt64 id = _fileInfoPopIDs[index];
|
||||
for (unsigned i = 0; i < ARRAY_SIZE(kPropMap); i++)
|
||||
{
|
||||
const CPropMap &pr = kPropMap[i];
|
||||
if (pr.FilePropID == id)
|
||||
{
|
||||
const CStatProp &st = pr.StatProp;
|
||||
*propID = st.PropID;
|
||||
*varType = st.vt;
|
||||
/*
|
||||
if (st.lpwstrName)
|
||||
*name = ::SysAllocString(st.lpwstrName);
|
||||
else
|
||||
*/
|
||||
*name = NULL;
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
}}
|
22
CPP/7zip/Archive/7z/7zProperties.h
Normal file
22
CPP/7zip/Archive/7z/7zProperties.h
Normal file
@ -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
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user