--- Begin Message ---
- To: Debian Bug Tracking System <submit@bugs.debian.org>
- Subject: unblock: 7zip/25.00+dfsg-1
- From: Bastian Germann <bage@debian.org>
- Date: Wed, 23 Jul 2025 19:33:01 +0200
- Message-id: <175329198151.1069.3473974810772754658.reportbug@duagon-BXN3S64.localdomain>
Package: release.debian.org
Severity: normal
X-Debbugs-Cc: 7zip@packages.debian.org
Control: affects -1 + src:7zip
User: release.debian.org@packages.debian.org
Usertags: unblock
Please unblock package 7zip
[ Reason ]
7zip-rar 25.00 has migrated to trixie.
The 7zip-rar interface might not be compatible with 7zip in trixie.
[ Impact ]
7zip-rar might fail to be called for specific rar file operations.
[ Tests ]
I have tried to provoke a crash by extracting a rar file but have not
succeeded.
[ Risks ]
None. The risks are in not migrating.
[ Checklist ]
[x] all changes are documented in the d/changelog
[x] I reviewed all changes and I approve them
[x] attach debdiff against the package in testing
unblock 7zip/25.00+dfsg-1
diff -Nru 7zip-24.09+dfsg/Asm/x86/Sort.asm 7zip-25.00+dfsg/Asm/x86/Sort.asm
--- 7zip-24.09+dfsg/Asm/x86/Sort.asm 1970-01-01 01:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/Asm/x86/Sort.asm 2025-01-08 09:00:00.000000000 +0100
@@ -0,0 +1,860 @@
+; SortTest.asm -- ASM version of HeapSort() function
+; Igor Pavlov : Public domain
+
+include ../../../../Asm/x86/7zAsm.asm
+
+MY_ASM_START
+
+ifndef Z7_SORT_ASM_USE_SEGMENT
+if (IS_LINUX gt 0)
+ ; Z7_SORT_ASM_USE_SEGMENT equ 1
+else
+ ; Z7_SORT_ASM_USE_SEGMENT equ 1
+endif
+endif
+
+ifdef Z7_SORT_ASM_USE_SEGMENT
+_TEXT$Z7_SORT SEGMENT ALIGN(64) 'CODE'
+MY_ALIGN macro num:req
+ align num
+endm
+else
+MY_ALIGN macro num:req
+ ; We expect that ".text" is aligned for 16-bytes.
+ ; So we don't need large alignment inside our function.
+ align 16
+endm
+endif
+
+
+MY_ALIGN_16 macro
+ MY_ALIGN 16
+endm
+
+MY_ALIGN_32 macro
+ MY_ALIGN 32
+endm
+
+MY_ALIGN_64 macro
+ MY_ALIGN 64
+endm
+
+ifdef x64
+
+NUM_PREFETCH_LEVELS equ 3 ; to prefetch 1x 64-bytes line (is good for most cases)
+; NUM_PREFETCH_LEVELS equ 4 ; to prefetch 2x 64-bytes lines (better for big arrays)
+
+acc equ x0
+k equ r0
+k_x equ x0
+
+p equ r1
+
+s equ r2
+s_x equ x2
+
+a0 equ x3
+t0 equ a0
+
+a3 equ x5
+qq equ a3
+
+a1 equ x6
+t1 equ a1
+t1_r equ r6
+
+a2 equ x7
+t2 equ a2
+
+i equ r8
+e0 equ x8
+
+e1 equ x9
+
+num_last equ r10
+num_last_x equ x10
+
+next4_lim equ r11
+pref_lim equ r12
+
+
+
+SORT_2_WITH_TEMP_REG macro b0, b1, temp_reg
+ mov temp_reg, b0
+ cmp b0, b1
+ cmovae b0, b1 ; min
+ cmovae b1, temp_reg ; max
+endm
+
+SORT macro b0, b1
+ SORT_2_WITH_TEMP_REG b0, b1, acc
+endm
+
+LOAD macro dest:req, index:req
+ mov dest, [p + 4 * index]
+endm
+
+STORE macro reg:req, index:req
+ mov [p + 4 * index], reg
+endm
+
+
+if (NUM_PREFETCH_LEVELS gt 3)
+ num_prefetches equ (1 SHL (NUM_PREFETCH_LEVELS - 3))
+else
+ num_prefetches equ 1
+endif
+
+PREFETCH_OP macro offs
+ cur_offset = 7 * 4 ; it's average offset in 64-bytes cache line.
+ ; cur_offset = 0 ; we can use zero offset, if we are sure that array is aligned for 64-bytes.
+ rept num_prefetches
+ if 1
+ prefetcht0 byte ptr [p + offs + cur_offset]
+ else
+ mov pref_x, dword ptr [p + offs + cur_offset]
+ endif
+ cur_offset = cur_offset + 64
+ endm
+endm
+
+PREFETCH_MY macro
+if 1
+ if 1
+ shl k, NUM_PREFETCH_LEVELS + 3
+ else
+ ; we delay prefetch instruction to improve main loads
+ shl k, NUM_PREFETCH_LEVELS
+ shl k, 3
+ ; shl k, 0
+ endif
+ PREFETCH_OP k
+elseif 1
+ shl k, 3
+ PREFETCH_OP k * (1 SHL NUM_PREFETCH_LEVELS) ; change it
+endif
+endm
+
+
+STEP_1 macro exit_label, prefetch_macro
+use_cmov_1 equ 1 ; set 1 for cmov, but it's slower in some cases
+ ; set 0 for LOAD after adc s, 0
+ cmp t0, t1
+ if use_cmov_1
+ cmovb t0, t1
+ ; STORE t0, k
+ endif
+ adc s, 0
+ if use_cmov_1 eq 0
+ LOAD t0, s
+ endif
+ cmp qq, t0
+ jae exit_label
+ if 1 ; use_cmov_1 eq 0
+ STORE t0, k
+ endif
+ prefetch_macro
+ mov t0, [p + s * 8]
+ mov t1, [p + s * 8 + 4]
+ mov k, s
+ add s, s ; slower for some cpus
+ ; lea s, dword ptr [s + s] ; slower for some cpus
+ ; shl s, 1 ; faster for some cpus
+ ; lea s, dword ptr [s * 2] ; faster for some cpus
+ rept 0 ; 1000 for debug : 0 for normal
+ ; number of calls in generate_stage : ~0.6 of number of items
+ shl k, 0
+ endm
+endm
+
+
+STEP_2 macro exit_label, prefetch_macro
+use_cmov_2 equ 0 ; set 1 for cmov, but it's slower in some cases
+ ; set 0 for LOAD after adc s, 0
+ cmp t0, t1
+ if use_cmov_2
+ mov t2, t0
+ cmovb t2, t1
+ ; STORE t2, k
+ endif
+ mov t0, [p + s * 8]
+ mov t1, [p + s * 8 + 4]
+ cmovb t0, [p + s * 8 + 8]
+ cmovb t1, [p + s * 8 + 12]
+ adc s, 0
+ if use_cmov_2 eq 0
+ LOAD t2, s
+ endif
+ cmp qq, t2
+ jae exit_label
+ if 1 ; use_cmov_2 eq 0
+ STORE t2, k
+ endif
+ prefetch_macro
+ mov k, s
+ ; add s, s
+ ; lea s, [s + s]
+ shl s, 1
+ ; lea s, [s * 2]
+endm
+
+
+MOVE_SMALLEST_UP macro STEP, use_prefetch, num_unrolls
+ LOCAL exit_1, exit_2, leaves, opt_loop, last_nodes
+
+ ; s == k * 2
+ ; t0 == (p)[s]
+ ; t1 == (p)[s + 1]
+ cmp k, next4_lim
+ jae leaves
+
+ rept num_unrolls
+ STEP exit_2
+ cmp k, next4_lim
+ jae leaves
+ endm
+
+ if use_prefetch
+ prefetch_macro equ PREFETCH_MY
+ pref_lim_2 equ pref_lim
+ ; lea pref_lim, dword ptr [num_last + 1]
+ ; shr pref_lim, NUM_PREFETCH_LEVELS + 1
+ cmp k, pref_lim_2
+ jae last_nodes
+ else
+ prefetch_macro equ
+ pref_lim_2 equ next4_lim
+ endif
+
+MY_ALIGN_16
+opt_loop:
+ STEP exit_2, prefetch_macro
+ cmp k, pref_lim_2
+ jb opt_loop
+
+last_nodes:
+ ; k >= pref_lim_2
+ ; 2 cases are possible:
+ ; case-1: num_after_prefetch_levels == 0 && next4_lim = pref_lim_2
+ ; case-2: num_after_prefetch_levels == NUM_PREFETCH_LEVELS - 1 &&
+ ; next4_lim = pref_lim_2 / (NUM_PREFETCH_LEVELS - 1)
+ if use_prefetch
+ yyy = NUM_PREFETCH_LEVELS - 1
+ while yyy
+ yyy = yyy - 1
+ STEP exit_2
+ if yyy
+ cmp k, next4_lim
+ jae leaves
+ endif
+ endm
+ endif
+
+leaves:
+ ; k >= next4_lim == (num_last + 1) / 4 must be provided by previous code.
+ ; we have 2 nodes in (s) level : always
+ ; we can have some nodes in (s * 2) level : low probability case
+ ; we have no nodes in (s * 4) level
+ ; s == k * 2
+ ; t0 == (p)[s]
+ ; t1 == (p)[s + 1]
+ cmp t0, t1
+ cmovb t0, t1
+ adc s, 0
+ STORE t0, k
+
+ ; t0 == (p)[s]
+ ; s / 2 == k : (s) is index of max item from (p)[k * 2], (p)[k * 2 + 1]
+ ; we have 3 possible cases here:
+ ; s * 2 > num_last : (s) node has no childs
+ ; s * 2 == num_last : (s) node has 1 leaf child that is last item of array
+ ; s * 2 < num_last : (s) node has 2 leaf childs. We provide (s * 4 > num_last)
+ ; we check for (s * 2 > num_last) before "cmp qq, t0" check, because
+ ; we will replace conditional jump with cmov instruction later.
+ lea t1_r, dword ptr [s + s]
+ cmp t1_r, num_last
+ ja exit_1 ; if (s * 2 > num_last), we have no childs : it's high probability branch
+
+ ; it's low probability branch
+ ; s * 2 <= num_last
+ cmp qq, t0
+ jae exit_2
+
+ ; qq < t0, so we go to next level
+ ; we check 1 or 2 childs in next level
+ mov t0, [p + s * 8]
+ mov k, s
+ mov s, t1_r
+ cmp t1_r, num_last
+ je @F ; (s == num_last) means that we have single child in tree
+
+ ; (s < num_last) : so we must read both childs and select max of them.
+ mov t1, [p + k * 8 + 4]
+ cmp t0, t1
+ cmovb t0, t1
+ adc s, 0
+@@:
+ STORE t0, k
+exit_1:
+ ; t0 == (p)[s], s / 2 == k : (s) is index of max item from (p)[k * 2], (p)[k * 2 + 1]
+ cmp qq, t0
+ cmovb k, s
+exit_2:
+ STORE qq, k
+endm
+
+
+
+
+ifdef Z7_SORT_ASM_USE_SEGMENT
+; MY_ALIGN_64
+else
+ MY_ALIGN_16
+endif
+
+MY_PROC HeapSort, 2
+
+if (IS_LINUX gt 0)
+ mov p, REG_ABI_PARAM_0 ; r1 <- r7 : linux
+endif
+ mov num_last, REG_ABI_PARAM_1 ; r10 <- r6 : linux
+ ; r10 <- r2 : win64
+ cmp num_last, 2
+ jb end_1
+
+ ; MY_PUSH_PRESERVED_ABI_REGS
+ MY_PUSH_PRESERVED_ABI_REGS_UP_TO_INCLUDING_R11
+ push r12
+
+ cmp num_last, 4
+ ja sort_5
+
+ LOAD a0, 0
+ LOAD a1, 1
+ SORT a0, a1
+ cmp num_last, 3
+ jb end_2
+
+ LOAD a2, 2
+ je sort_3
+
+ LOAD a3, 3
+ SORT a2, a3
+ SORT a1, a3
+ STORE a3, 3
+sort_3:
+ SORT a0, a2
+ SORT a1, a2
+ STORE a2, 2
+ jmp end_2
+
+sort_5:
+ ; (num_last > 4) is required here
+ ; if (num_last >= 6) : we will use optimized loop for leaf nodes loop_down_1
+ mov next4_lim, num_last
+ shr next4_lim, 2
+
+ dec num_last
+ mov k, num_last
+ shr k, 1
+ mov i, num_last
+ shr i, 2
+ test num_last, 1
+ jnz size_even
+
+ ; ODD number of items. So we compare parent with single child
+ LOAD t1, num_last
+ LOAD t0, k
+ SORT_2_WITH_TEMP_REG t1, t0, t2
+ STORE t1, num_last
+ STORE t0, k
+ dec k
+
+size_even:
+ cmp k, i
+ jbe loop_down ; jump for num_last == 4 case
+
+if 0 ; 1 for debug
+ mov r15, k
+ mov r14d, 1 ; 100
+loop_benchmark:
+endif
+ ; optimized loop for leaf nodes:
+ mov t0, [p + k * 8]
+ mov t1, [p + k * 8 + 4]
+
+MY_ALIGN_16
+loop_down_1:
+ ; we compare parent with max of childs:
+ ; lea s, dword ptr [2 * k]
+ mov s, k
+ cmp t0, t1
+ cmovb t0, t1
+ adc s, s
+ LOAD t2, k
+ STORE t0, k
+ cmp t2, t0
+ cmovae s, k
+ dec k
+ ; we preload next items before STORE operation for calculated address
+ mov t0, [p + k * 8]
+ mov t1, [p + k * 8 + 4]
+ STORE t2, s
+ cmp k, i
+ jne loop_down_1
+
+if 0 ; 1 for debug
+ mov k, r15
+ dec r14d
+ jnz loop_benchmark
+ ; jmp end_debug
+endif
+
+MY_ALIGN_16
+loop_down:
+ mov t0, [p + i * 8]
+ mov t1, [p + i * 8 + 4]
+ LOAD qq, i
+ mov k, i
+ lea s, dword ptr [i + i]
+ ; jmp end_debug
+ DOWN_use_prefetch equ 0
+ DOWN_num_unrolls equ 0
+ MOVE_SMALLEST_UP STEP_1, DOWN_use_prefetch, DOWN_num_unrolls
+ sub i, 1
+ jnb loop_down
+
+ ; jmp end_debug
+ LOAD e0, 0
+ LOAD e1, 1
+
+ LEVEL_3_LIMIT equ 8 ; 8 is default, but 7 also can work
+
+ cmp num_last, LEVEL_3_LIMIT + 1
+ jb main_loop_sort_5
+
+MY_ALIGN_16
+main_loop_sort:
+ ; num_last > LEVEL_3_LIMIT
+ ; p[size--] = p[0];
+ LOAD qq, num_last
+ STORE e0, num_last
+ mov e0, e1
+
+ mov next4_lim, num_last
+ shr next4_lim, 2
+ mov pref_lim, num_last
+ shr pref_lim, NUM_PREFETCH_LEVELS + 1
+
+ dec num_last
+if 0 ; 1 for debug
+ ; that optional optimization can improve the performance, if there are identical items in array
+ ; 3 times improvement : if all items in array are identical
+ ; 20% improvement : if items are different for 1 bit only
+ ; 1-10% improvement : if items are different for (2+) bits
+ ; no gain : if items are different
+ cmp qq, e1
+ jae next_iter_main
+endif
+ LOAD e1, 2
+ LOAD t0, 3
+ mov k_x, 2
+ cmp e1, t0
+ cmovb e1, t0
+ mov t0, [p + 4 * (4 + 0)]
+ mov t1, [p + 4 * (4 + 1)]
+ cmovb t0, [p + 4 * (4 + 2)]
+ cmovb t1, [p + 4 * (4 + 3)]
+ adc k_x, 0
+ ; (qq <= e1), because the tree is correctly sorted
+ ; also here we could check (qq >= e1) or (qq == e1) for faster exit
+ lea s, dword ptr [k + k]
+ MAIN_use_prefetch equ 1
+ MAIN_num_unrolls equ 0
+ MOVE_SMALLEST_UP STEP_2, MAIN_use_prefetch, MAIN_num_unrolls
+
+next_iter_main:
+ cmp num_last, LEVEL_3_LIMIT
+ jne main_loop_sort
+
+ ; num_last == LEVEL_3_LIMIT
+main_loop_sort_5:
+ ; 4 <= num_last <= LEVEL_3_LIMIT
+ ; p[size--] = p[0];
+ LOAD qq, num_last
+ STORE e0, num_last
+ mov e0, e1
+ dec num_last_x
+
+ LOAD e1, 2
+ LOAD t0, 3
+ mov k_x, 2
+ cmp e1, t0
+ cmovb e1, t0
+ adc k_x, 0
+
+ lea s_x, dword ptr [k * 2]
+ cmp s_x, num_last_x
+ ja exit_2
+
+ mov t0, [p + k * 8]
+ je exit_1
+
+ ; s < num_last
+ mov t1, [p + k * 8 + 4]
+ cmp t0, t1
+ cmovb t0, t1
+ adc s_x, 0
+exit_1:
+ STORE t0, k
+ cmp qq, t0
+ cmovb k_x, s_x
+exit_2:
+ STORE qq, k
+ cmp num_last_x, 3
+ jne main_loop_sort_5
+
+ ; num_last == 3 (real_size == 4)
+ LOAD a0, 2
+ LOAD a1, 3
+ STORE e1, 2
+ STORE e0, 3
+ SORT a0, a1
+end_2:
+ STORE a0, 0
+ STORE a1, 1
+; end_debug:
+ ; MY_POP_PRESERVED_ABI_REGS
+ pop r12
+ MY_POP_PRESERVED_ABI_REGS_UP_TO_INCLUDING_R11
+end_1:
+MY_ENDP
+
+
+
+else
+; ------------ x86 32-bit ------------
+
+ifdef x64
+IS_CDECL = 0
+endif
+
+acc equ x0
+k equ r0
+k_x equ acc
+
+p equ r1
+
+num_last equ r2
+num_last_x equ x2
+
+a0 equ x3
+t0 equ a0
+
+a3 equ x5
+i equ r5
+e0 equ a3
+
+a1 equ x6
+qq equ a1
+
+a2 equ x7
+s equ r7
+s_x equ a2
+
+
+SORT macro b0, b1
+ cmp b1, b0
+ jae @F
+ if 1
+ xchg b0, b1
+ else
+ mov acc, b0
+ mov b0, b1 ; min
+ mov b1, acc ; max
+ endif
+@@:
+endm
+
+LOAD macro dest:req, index:req
+ mov dest, [p + 4 * index]
+endm
+
+STORE macro reg:req, index:req
+ mov [p + 4 * index], reg
+endm
+
+
+STEP_1 macro exit_label
+ mov t0, [p + k * 8]
+ cmp t0, [p + k * 8 + 4]
+ adc s, 0
+ LOAD t0, s
+ STORE t0, k ; we lookahed stooring for most expected branch
+ cmp qq, t0
+ jae exit_label
+ ; STORE t0, k ; use if
+ mov k, s
+ add s, s
+ ; lea s, dword ptr [s + s]
+ ; shl s, 1
+ ; lea s, dword ptr [s * 2]
+endm
+
+STEP_BRANCH macro exit_label
+ mov t0, [p + k * 8]
+ cmp t0, [p + k * 8 + 4]
+ jae @F
+ inc s
+ mov t0, [p + k * 8 + 4]
+@@:
+ cmp qq, t0
+ jae exit_label
+ STORE t0, k
+ mov k, s
+ add s, s
+endm
+
+
+
+MOVE_SMALLEST_UP macro STEP, num_unrolls, exit_2
+ LOCAL leaves, opt_loop, single
+
+ ; s == k * 2
+ rept num_unrolls
+ cmp s, num_last
+ jae leaves
+ STEP_1 exit_2
+ endm
+ cmp s, num_last
+ jb opt_loop
+
+leaves:
+ ; (s >= num_last)
+ jne exit_2
+single:
+ ; (s == num_last)
+ mov t0, [p + k * 8]
+ cmp qq, t0
+ jae exit_2
+ STORE t0, k
+ mov k, s
+ jmp exit_2
+
+MY_ALIGN_16
+opt_loop:
+ STEP exit_2
+ cmp s, num_last
+ jb opt_loop
+ je single
+exit_2:
+ STORE qq, k
+endm
+
+
+
+
+ifdef Z7_SORT_ASM_USE_SEGMENT
+; MY_ALIGN_64
+else
+ MY_ALIGN_16
+endif
+
+MY_PROC HeapSort, 2
+ ifdef x64
+ if (IS_LINUX gt 0)
+ mov num_last, REG_ABI_PARAM_1 ; r2 <- r6 : linux
+ mov p, REG_ABI_PARAM_0 ; r1 <- r7 : linux
+ endif
+ elseif (IS_CDECL gt 0)
+ mov num_last, [r4 + REG_SIZE * 2]
+ mov p, [r4 + REG_SIZE * 1]
+ endif
+ cmp num_last, 2
+ jb end_1
+ MY_PUSH_PRESERVED_ABI_REGS_UP_TO_INCLUDING_R11
+
+ cmp num_last, 4
+ ja sort_5
+
+ LOAD a0, 0
+ LOAD a1, 1
+ SORT a0, a1
+ cmp num_last, 3
+ jb end_2
+
+ LOAD a2, 2
+ je sort_3
+
+ LOAD a3, 3
+ SORT a2, a3
+ SORT a1, a3
+ STORE a3, 3
+sort_3:
+ SORT a0, a2
+ SORT a1, a2
+ STORE a2, 2
+ jmp end_2
+
+sort_5:
+ ; num_last > 4
+ lea i, dword ptr [num_last - 2]
+ dec num_last
+ test i, 1
+ jz loop_down
+
+ ; single child
+ mov t0, [p + num_last * 4]
+ mov qq, [p + num_last * 2]
+ dec i
+ cmp qq, t0
+ jae loop_down
+
+ mov [p + num_last * 2], t0
+ mov [p + num_last * 4], qq
+
+MY_ALIGN_16
+loop_down:
+ mov t0, [p + i * 4]
+ cmp t0, [p + i * 4 + 4]
+ mov k, i
+ mov qq, [p + i * 2]
+ adc k, 0
+ LOAD t0, k
+ cmp qq, t0
+ jae down_next
+ mov [p + i * 2], t0
+ lea s, dword ptr [k + k]
+
+ DOWN_num_unrolls equ 0
+ MOVE_SMALLEST_UP STEP_1, DOWN_num_unrolls, down_exit_label
+down_next:
+ sub i, 2
+ jnb loop_down
+ ; jmp end_debug
+
+ LOAD e0, 0
+
+MY_ALIGN_16
+main_loop_sort:
+ ; num_last > 3
+ mov t0, [p + 2 * 4]
+ cmp t0, [p + 3 * 4]
+ LOAD qq, num_last
+ STORE e0, num_last
+ LOAD e0, 1
+ mov s_x, 2
+ mov k_x, 1
+ adc s, 0
+ LOAD t0, s
+ dec num_last
+ cmp qq, t0
+ jae main_exit_label
+ STORE t0, 1
+ mov k, s
+ add s, s
+ if 1
+ ; for branch data prefetch mode :
+ ; it's faster for large arrays : larger than (1 << 13) items.
+ MAIN_num_unrolls equ 10
+ STEP_LOOP equ STEP_BRANCH
+ else
+ MAIN_num_unrolls equ 0
+ STEP_LOOP equ STEP_1
+ endif
+
+ MOVE_SMALLEST_UP STEP_LOOP, MAIN_num_unrolls, main_exit_label
+
+ ; jmp end_debug
+ cmp num_last, 3
+ jne main_loop_sort
+
+ ; num_last == 3 (real_size == 4)
+ LOAD a0, 2
+ LOAD a1, 3
+ LOAD a2, 1
+ STORE e0, 3 ; e0 is alias for a3
+ STORE a2, 2
+ SORT a0, a1
+end_2:
+ STORE a0, 0
+ STORE a1, 1
+; end_debug:
+ MY_POP_PRESERVED_ABI_REGS_UP_TO_INCLUDING_R11
+end_1:
+MY_ENDP
+
+endif
+
+ifdef Z7_SORT_ASM_USE_SEGMENT
+_TEXT$Z7_SORT ENDS
+endif
+
+if 0
+LEA_IS_D8 (R64) [R2 * 4 + 16]
+ Lat : TP
+ 2 : 1 : adl-e
+ 2 : 3 p056 adl-p
+ 1 : 2 : p15 hsw-rocket
+ 1 : 2 : p01 snb-ivb
+ 1 : 1 : p1 conroe-wsm
+ 1 : 4 : zen3,zen4
+ 2 : 4 : zen1,zen2
+
+LEA_B_IS (R64) [R2 + R3 * 4]
+ Lat : TP
+ 1 : 1 : adl-e
+ 2 : 3 p056 adl-p
+ 1 : 2 : p15 hsw-rocket
+ 1 : 2 : p01 snb-ivb
+ 1 : 1 : p1 nhm-wsm
+ 1 : 1 : p0 conroe-wsm
+ 1 : 4 : zen3,zen4
+ 2 :2,4 : zen1,zen2
+
+LEA_B_IS_D8 (R64) [R2 + R3 * 4 + 16]
+ Lat : TP
+ 2 : 1 : adl-e
+ 2 : 3 p056 adl-p
+ 1 : 2 : p15 ice-rocket
+ 3 : 1 : p1/p15 hsw-rocket
+ 3 : 1 : p01 snb-ivb
+ 1 : 1 : p1 nhm-wsm
+ 1 : 1 : p0 conroe-wsm
+ 2,1 : 2 : zen3,zen4
+ 2 : 2 : zen1,zen2
+
+CMOVB (R64, R64)
+ Lat : TP
+ 1,2 : 2 : adl-e
+ 1 : 2 p06 adl-p
+ 1 : 2 : p06 bwd-rocket
+ 1,2 : 2 : p0156+p06 hsw
+ 1,2 :1.5 : p015+p05 snb-ivb
+ 1,2 : 1 : p015+p05 nhm
+ 1 : 1 : 2*p015 conroe
+ 1 : 2 : zen3,zen4
+ 1 : 4 : zen1,zen2
+
+ADC (R64, 0)
+ Lat : TP
+ 1,2 : 2 : adl-e
+ 1 : 2 p06 adl-p
+ 1 : 2 : p06 bwd-rocket
+ 1 :1.5 : p0156+p06 hsw
+ 1 :1.5 : p015+p05 snb-ivb
+ 2 : 1 : 2*p015 conroe-wstm
+ 1 : 2 : zen1,zen2,zen3,zen4
+
+PREFETCHNTA : fetch data into non-temporal cache close to the processor, minimizing cache pollution.
+ L1 : Pentium3
+ L2 : NetBurst
+ L1, not L2: Core duo, Core 2, Atom processors
+ L1, not L2, may fetch into L3 with fast replacement: Nehalem, Westmere, Sandy Bridge, ...
+ NEHALEM: Fills L1/L3, L1 LRU is not updated
+ L3 with fast replacement: Xeon Processors based on Nehalem, Westmere, Sandy Bridge, ...
+PREFETCHT0 : fetch data into all cache levels.
+PREFETCHT1 : fetch data into L2 and L3
+endif
+
+end
diff -Nru 7zip-24.09+dfsg/C/7zVersion.h 7zip-25.00+dfsg/C/7zVersion.h
--- 7zip-24.09+dfsg/C/7zVersion.h 2024-11-29 12:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/C/7zVersion.h 2025-07-05 13:00:00.000000000 +0200
@@ -1,7 +1,7 @@
-#define MY_VER_MAJOR 24
-#define MY_VER_MINOR 9
+#define MY_VER_MAJOR 25
+#define MY_VER_MINOR 0
#define MY_VER_BUILD 0
-#define MY_VERSION_NUMBERS "24.09"
+#define MY_VERSION_NUMBERS "25.00"
#define MY_VERSION MY_VERSION_NUMBERS
#ifdef MY_CPU_NAME
@@ -10,12 +10,12 @@
#define MY_VERSION_CPU MY_VERSION
#endif
-#define MY_DATE "2024-11-29"
+#define MY_DATE "2025-07-05"
#undef MY_COPYRIGHT
#undef MY_VERSION_COPYRIGHT_DATE
#define MY_AUTHOR_NAME "Igor Pavlov"
#define MY_COPYRIGHT_PD "Igor Pavlov : Public domain"
-#define MY_COPYRIGHT_CR "Copyright (c) 1999-2024 Igor Pavlov"
+#define MY_COPYRIGHT_CR "Copyright (c) 1999-2025 Igor Pavlov"
#ifdef USE_COPYRIGHT_CR
#define MY_COPYRIGHT MY_COPYRIGHT_CR
diff -Nru 7zip-24.09+dfsg/C/BwtSort.c 7zip-25.00+dfsg/C/BwtSort.c
--- 7zip-24.09+dfsg/C/BwtSort.c 2023-04-02 13:00:00.000000000 +0200
+++ 7zip-25.00+dfsg/C/BwtSort.c 2025-01-13 14:00:00.000000000 +0100
@@ -1,5 +1,5 @@
/* BwtSort.c -- BWT block sorting
-2023-04-02 : Igor Pavlov : Public domain */
+: Igor Pavlov : Public domain */
#include "Precomp.h"
@@ -7,6 +7,44 @@
#include "Sort.h"
/* #define BLOCK_SORT_USE_HEAP_SORT */
+// #define BLOCK_SORT_USE_HEAP_SORT
+
+#ifdef BLOCK_SORT_USE_HEAP_SORT
+
+#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);
+}
+
+#endif // BLOCK_SORT_USE_HEAP_SORT
+
/* Don't change it !!! */
#define kNumHashBytes 2
@@ -27,26 +65,27 @@
#else
-#define kNumBitsMax 20
-#define kIndexMask ((1 << kNumBitsMax) - 1)
-#define kNumExtraBits (32 - kNumBitsMax)
-#define kNumExtra0Bits (kNumExtraBits - 2)
-#define kNumExtra0Mask ((1 << kNumExtra0Bits) - 1)
+#define kNumBitsMax 20
+#define kIndexMask (((UInt32)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); \
+ { *(p) |= ((((UInt32)(size) - 1) & kNumExtra0Mask) << kNumBitsMax); \
if ((size) > (1 << kNumExtra0Bits)) { \
- *(p) |= 0x40000000; *((p) + 1) |= ((((size) - 1)>> kNumExtra0Bits) << kNumBitsMax); } } \
+ *(p) |= 0x40000000; \
+ *((p) + 1) |= (((UInt32)(size) - 1) >> kNumExtra0Bits) << kNumBitsMax; } } \
-static void SetGroupSize(UInt32 *p, UInt32 size)
+static void SetGroupSize(UInt32 *p, size_t size)
{
if (--size == 0)
return;
- *p |= 0x80000000 | ((size & kNumExtra0Mask) << kNumBitsMax);
+ *p |= 0x80000000 | (((UInt32)size & kNumExtra0Mask) << kNumBitsMax);
if (size >= (1 << kNumExtra0Bits))
{
*p |= 0x40000000;
- p[1] |= ((size >> kNumExtra0Bits) << kNumBitsMax);
+ p[1] |= (((UInt32)size >> kNumExtra0Bits) << kNumBitsMax);
}
}
@@ -59,12 +98,14 @@
*/
static
-UInt32
+unsigned
Z7_FASTCALL
-SortGroup(UInt32 BlockSize, UInt32 NumSortedBytes, UInt32 groupOffset, UInt32 groupSize, int NumRefBits, UInt32 *Indices
- #ifndef BLOCK_SORT_USE_HEAP_SORT
- , UInt32 left, UInt32 range
- #endif
+SortGroup(size_t BlockSize, size_t NumSortedBytes,
+ size_t groupOffset, size_t groupSize,
+ unsigned NumRefBits, UInt32 *Indices
+#ifndef BLOCK_SORT_USE_HEAP_SORT
+ , size_t left, size_t range
+#endif
)
{
UInt32 *ind2 = Indices + groupOffset;
@@ -79,90 +120,93 @@
return 0;
}
Groups = Indices + BlockSize + BS_TEMP_SIZE;
- if (groupSize <= ((UInt32)1 << NumRefBits)
- #ifndef BLOCK_SORT_USE_HEAP_SORT
+ if (groupSize <= ((size_t)1 << NumRefBits)
+#ifndef BLOCK_SORT_USE_HEAP_SORT
&& groupSize <= range
- #endif
+#endif
)
{
UInt32 *temp = Indices + BlockSize;
- UInt32 j;
- UInt32 mask, thereAreGroups, group, cg;
+ size_t j, group;
+ UInt32 mask, cg;
+ unsigned thereAreGroups;
{
UInt32 gPrev;
UInt32 gRes = 0;
{
- UInt32 sp = ind2[0] + NumSortedBytes;
- if (sp >= BlockSize) sp -= BlockSize;
+ size_t sp = ind2[0] + NumSortedBytes;
+ if (sp >= BlockSize)
+ sp -= BlockSize;
gPrev = Groups[sp];
- temp[0] = (gPrev << NumRefBits);
+ temp[0] = gPrev << NumRefBits;
}
for (j = 1; j < groupSize; j++)
{
- UInt32 sp = ind2[j] + NumSortedBytes;
+ size_t sp = ind2[j] + NumSortedBytes;
UInt32 g;
- if (sp >= BlockSize) sp -= BlockSize;
+ if (sp >= BlockSize)
+ sp -= BlockSize;
g = Groups[sp];
- temp[j] = (g << NumRefBits) | j;
+ temp[j] = (g << NumRefBits) | (UInt32)j;
gRes |= (gPrev ^ g);
}
if (gRes == 0)
{
- #ifndef BLOCK_SORT_EXTERNAL_FLAGS
+#ifndef BLOCK_SORT_EXTERNAL_FLAGS
SetGroupSize(ind2, groupSize);
- #endif
+#endif
return 1;
}
}
HeapSort(temp, groupSize);
- mask = (((UInt32)1 << NumRefBits) - 1);
+ mask = ((UInt32)1 << NumRefBits) - 1;
thereAreGroups = 0;
group = groupOffset;
- cg = (temp[0] >> NumRefBits);
+ cg = temp[0] >> NumRefBits;
temp[0] = ind2[temp[0] & mask];
{
- #ifdef BLOCK_SORT_EXTERNAL_FLAGS
+#ifdef BLOCK_SORT_EXTERNAL_FLAGS
UInt32 *Flags = Groups + BlockSize;
- #else
- UInt32 prevGroupStart = 0;
- #endif
+#else
+ size_t prevGroupStart = 0;
+#endif
for (j = 1; j < groupSize; j++)
{
- UInt32 val = temp[j];
- UInt32 cgCur = (val >> NumRefBits);
+ const UInt32 val = temp[j];
+ const UInt32 cgCur = val >> NumRefBits;
if (cgCur != cg)
{
cg = cgCur;
group = groupOffset + j;
- #ifdef BLOCK_SORT_EXTERNAL_FLAGS
+#ifdef BLOCK_SORT_EXTERNAL_FLAGS
{
- UInt32 t = group - 1;
- Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask));
+ const size_t t = group - 1;
+ Flags[t >> kNumFlagsBits] &= ~((UInt32)1 << (t & kFlagsMask));
}
- #else
+#else
SetGroupSize(temp + prevGroupStart, j - prevGroupStart);
prevGroupStart = j;
- #endif
+#endif
}
else
thereAreGroups = 1;
{
- UInt32 ind = ind2[val & mask];
- temp[j] = ind;
- Groups[ind] = group;
+ const UInt32 ind = ind2[val & mask];
+ temp[j] = ind;
+ Groups[ind] = (UInt32)group;
}
}
- #ifndef BLOCK_SORT_EXTERNAL_FLAGS
+#ifndef BLOCK_SORT_EXTERNAL_FLAGS
SetGroupSize(temp + prevGroupStart, j - prevGroupStart);
- #endif
+#endif
}
for (j = 0; j < groupSize; j++)
@@ -172,37 +216,42 @@
/* Check that all strings are in one group (cannot sort) */
{
- UInt32 group, j;
- UInt32 sp = ind2[0] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize;
+ UInt32 group;
+ size_t j;
+ size_t 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;
+ sp = ind2[j] + NumSortedBytes;
+ if (sp >= BlockSize)
+ sp -= BlockSize;
if (Groups[sp] != group)
break;
}
if (j == groupSize)
{
- #ifndef BLOCK_SORT_EXTERNAL_FLAGS
+#ifndef BLOCK_SORT_EXTERNAL_FLAGS
SetGroupSize(ind2, groupSize);
- #endif
+#endif
return 1;
}
}
- #ifndef BLOCK_SORT_USE_HEAP_SORT
+#ifndef BLOCK_SORT_USE_HEAP_SORT
{
/* ---------- Range Sort ---------- */
- UInt32 i;
- UInt32 mid;
+ size_t i;
+ size_t mid;
for (;;)
{
- UInt32 j;
+ size_t j;
if (range <= 1)
{
- #ifndef BLOCK_SORT_EXTERNAL_FLAGS
+#ifndef BLOCK_SORT_EXTERNAL_FLAGS
SetGroupSize(ind2, groupSize);
- #endif
+#endif
return 1;
}
mid = left + ((range + 1) >> 1);
@@ -210,7 +259,7 @@
i = 0;
do
{
- UInt32 sp = ind2[i] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize;
+ size_t sp = ind2[i] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize;
if (Groups[sp] >= mid)
{
for (j--; j > i; j--)
@@ -238,51 +287,53 @@
break;
}
- #ifdef BLOCK_SORT_EXTERNAL_FLAGS
+#ifdef BLOCK_SORT_EXTERNAL_FLAGS
{
- UInt32 t = (groupOffset + i - 1);
+ const size_t t = groupOffset + i - 1;
UInt32 *Flags = Groups + BlockSize;
- Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask));
+ Flags[t >> kNumFlagsBits] &= ~((UInt32)1 << (t & kFlagsMask));
}
- #endif
+#endif
{
- UInt32 j;
+ size_t j;
for (j = i; j < groupSize; j++)
- Groups[ind2[j]] = groupOffset + i;
+ Groups[ind2[j]] = (UInt32)(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));
+ unsigned 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
+#else // BLOCK_SORT_USE_HEAP_SORT
/* ---------- Heap Sort ---------- */
{
- UInt32 j;
+ size_t j;
for (j = 0; j < groupSize; j++)
{
- UInt32 sp = ind2[j] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize;
- ind2[j] = sp;
+ size_t sp = ind2[j] + NumSortedBytes;
+ if (sp >= BlockSize)
+ sp -= BlockSize;
+ ind2[j] = (UInt32)sp;
}
HeapSortRef(ind2, Groups, groupSize);
/* Write Flags */
{
- UInt32 sp = ind2[0];
+ size_t sp = ind2[0];
UInt32 group = Groups[sp];
- #ifdef BLOCK_SORT_EXTERNAL_FLAGS
+#ifdef BLOCK_SORT_EXTERNAL_FLAGS
UInt32 *Flags = Groups + BlockSize;
- #else
- UInt32 prevGroupStart = 0;
- #endif
+#else
+ size_t prevGroupStart = 0;
+#endif
for (j = 1; j < groupSize; j++)
{
@@ -290,149 +341,210 @@
if (Groups[sp] != group)
{
group = Groups[sp];
- #ifdef BLOCK_SORT_EXTERNAL_FLAGS
+#ifdef BLOCK_SORT_EXTERNAL_FLAGS
{
- UInt32 t = groupOffset + j - 1;
+ const size_t t = groupOffset + j - 1;
Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask));
}
- #else
+#else
SetGroupSize(ind2 + prevGroupStart, j - prevGroupStart);
prevGroupStart = j;
- #endif
+#endif
}
}
- #ifndef BLOCK_SORT_EXTERNAL_FLAGS
+#ifndef BLOCK_SORT_EXTERNAL_FLAGS
SetGroupSize(ind2 + prevGroupStart, j - prevGroupStart);
- #endif
+#endif
}
{
/* Write new Groups values and Check that there are groups */
- UInt32 thereAreGroups = 0;
+ unsigned thereAreGroups = 0;
for (j = 0; j < groupSize; j++)
{
- UInt32 group = groupOffset + j;
- #ifndef BLOCK_SORT_EXTERNAL_FLAGS
+ size_t group = groupOffset + j;
+#ifndef BLOCK_SORT_EXTERNAL_FLAGS
UInt32 subGroupSize = ((ind2[j] & ~0xC0000000) >> kNumBitsMax);
- if ((ind2[j] & 0x40000000) != 0)
+ if (ind2[j] & 0x40000000)
subGroupSize += ((ind2[(size_t)j + 1] >> kNumBitsMax) << kNumExtra0Bits);
subGroupSize++;
for (;;)
{
- UInt32 original = ind2[j];
- UInt32 sp = original & kIndexMask;
- if (sp < NumSortedBytes) sp += BlockSize; sp -= NumSortedBytes;
- ind2[j] = sp | (original & ~kIndexMask);
- Groups[sp] = group;
+ const UInt32 original = ind2[j];
+ size_t sp = original & kIndexMask;
+ if (sp < NumSortedBytes)
+ sp += BlockSize;
+ sp -= NumSortedBytes;
+ ind2[j] = (UInt32)sp | (original & ~kIndexMask);
+ Groups[sp] = (UInt32)group;
if (--subGroupSize == 0)
break;
j++;
thereAreGroups = 1;
}
- #else
+#else
UInt32 *Flags = Groups + BlockSize;
for (;;)
{
- UInt32 sp = ind2[j]; if (sp < NumSortedBytes) sp += BlockSize; sp -= NumSortedBytes;
- ind2[j] = sp;
- Groups[sp] = group;
+ size_t sp = ind2[j];
+ if (sp < NumSortedBytes)
+ sp += BlockSize;
+ sp -= NumSortedBytes;
+ ind2[j] = (UInt32)sp;
+ Groups[sp] = (UInt32)group;
if ((Flags[(groupOffset + j) >> kNumFlagsBits] & (1 << ((groupOffset + j) & kFlagsMask))) == 0)
break;
j++;
thereAreGroups = 1;
}
- #endif
+#endif
}
return thereAreGroups;
}
}
- #endif
+#endif // BLOCK_SORT_USE_HEAP_SORT
}
+
/* conditions: blockSize > 0 */
-UInt32 BlockSort(UInt32 *Indices, const Byte *data, UInt32 blockSize)
+UInt32 BlockSort(UInt32 *Indices, const Byte *data, size_t blockSize)
{
UInt32 *counters = Indices + blockSize;
- UInt32 i;
+ size_t i;
UInt32 *Groups;
- #ifdef BLOCK_SORT_EXTERNAL_FLAGS
+#ifdef BLOCK_SORT_EXTERNAL_FLAGS
UInt32 *Flags;
- #endif
+#endif
- /* Radix-Sort for 2 bytes */
+/* Radix-Sort for 2 bytes */
+// { UInt32 yyy; for (yyy = 0; yyy < 100; yyy++) {
for (i = 0; i < kNumHashValues; i++)
counters[i] = 0;
- for (i = 0; i < blockSize - 1; i++)
- counters[((UInt32)data[i] << 8) | data[(size_t)i + 1]]++;
- counters[((UInt32)data[i] << 8) | data[0]]++;
+ {
+ const Byte *data2 = data;
+ size_t a = data[(size_t)blockSize - 1];
+ const Byte *data_lim = data + blockSize;
+ if (blockSize >= 4)
+ {
+ data_lim -= 3;
+ do
+ {
+ size_t b;
+ b = data2[0]; counters[(a << 8) | b]++;
+ a = data2[1]; counters[(b << 8) | a]++;
+ b = data2[2]; counters[(a << 8) | b]++;
+ a = data2[3]; counters[(b << 8) | a]++;
+ data2 += 4;
+ }
+ while (data2 < data_lim);
+ data_lim += 3;
+ }
+ while (data2 != data_lim)
+ {
+ size_t b = *data2++;
+ counters[(a << 8) | b]++;
+ a = b;
+ }
+ }
+// }}
Groups = counters + BS_TEMP_SIZE;
- #ifdef BLOCK_SORT_EXTERNAL_FLAGS
+#ifdef BLOCK_SORT_EXTERNAL_FLAGS
Flags = Groups + blockSize;
- {
- UInt32 numWords = (blockSize + kFlagsMask) >> kNumFlagsBits;
- for (i = 0; i < numWords; i++)
- Flags[i] = kAllFlags;
- }
- #endif
+ {
+ const size_t 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)
+ const UInt32 groupSize = counters[i];
+ counters[i] = sum;
+ sum += groupSize;
+#ifdef BLOCK_SORT_EXTERNAL_FLAGS
+ if (groupSize)
{
- #ifdef BLOCK_SORT_EXTERNAL_FLAGS
- UInt32 t = sum + groupSize - 1;
- Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask));
- #endif
- sum += groupSize;
+ const UInt32 t = sum - 1;
+ Flags[t >> kNumFlagsBits] &= ~((UInt32)1 << (t & kFlagsMask));
}
- counters[i] = sum - groupSize;
+#endif
}
+ }
- for (i = 0; i < blockSize - 1; i++)
- Groups[i] = counters[((UInt32)data[i] << 8) | data[(size_t)i + 1]];
- Groups[i] = counters[((UInt32)data[i] << 8) | data[0]];
+ for (i = 0; i < blockSize - 1; i++)
+ Groups[i] = counters[((unsigned)data[i] << 8) | data[(size_t)i + 1]];
+ Groups[i] = counters[((unsigned)data[i] << 8) | data[0]];
+
+ {
+#define SET_Indices(a, b, i) \
+ { UInt32 c; \
+ a = (a << 8) | (b); \
+ c = counters[a]; \
+ Indices[c] = (UInt32)i++; \
+ counters[a] = c + 1; \
+ }
- for (i = 0; i < blockSize - 1; i++)
- Indices[counters[((UInt32)data[i] << 8) | data[(size_t)i + 1]]++] = i;
- Indices[counters[((UInt32)data[i] << 8) | data[0]]++] = i;
-
- #ifndef BLOCK_SORT_EXTERNAL_FLAGS
+ size_t a = data[0];
+ const Byte *data_ptr = data + 1;
+ i = 0;
+ if (blockSize >= 3)
+ {
+ blockSize -= 2;
+ do
+ {
+ size_t b;
+ b = data_ptr[0]; SET_Indices(a, b, i)
+ a = data_ptr[1]; SET_Indices(b, a, i)
+ data_ptr += 2;
+ }
+ while (i < blockSize);
+ blockSize += 2;
+ }
+ if (i < blockSize - 1)
{
+ SET_Indices(a, data[(size_t)i + 1], i)
+ a = (Byte)a;
+ }
+ SET_Indices(a, data[0], i)
+ }
+
+#ifndef BLOCK_SORT_EXTERNAL_FLAGS
+ {
UInt32 prev = 0;
for (i = 0; i < kNumHashValues; i++)
{
- UInt32 prevGroupSize = counters[i] - prev;
+ const UInt32 prevGroupSize = counters[i] - prev;
if (prevGroupSize == 0)
continue;
SetGroupSize(Indices + prev, prevGroupSize);
prev = counters[i];
}
- }
- #endif
}
+#endif
{
- int NumRefBits;
- UInt32 NumSortedBytes;
- for (NumRefBits = 0; ((blockSize - 1) >> NumRefBits) != 0; NumRefBits++);
+ unsigned NumRefBits;
+ size_t NumSortedBytes;
+ for (NumRefBits = 0; ((blockSize - 1) >> NumRefBits) != 0; NumRefBits++)
+ {}
NumRefBits = 32 - NumRefBits;
if (NumRefBits > kNumRefBitsMax)
- NumRefBits = kNumRefBitsMax;
+ NumRefBits = kNumRefBitsMax;
for (NumSortedBytes = kNumHashBytes; ; NumSortedBytes <<= 1)
{
- #ifndef BLOCK_SORT_EXTERNAL_FLAGS
- UInt32 finishedGroupSize = 0;
- #endif
- UInt32 newLimit = 0;
+#ifndef BLOCK_SORT_EXTERNAL_FLAGS
+ size_t finishedGroupSize = 0;
+#endif
+ size_t newLimit = 0;
for (i = 0; i < blockSize;)
{
- UInt32 groupSize;
- #ifdef BLOCK_SORT_EXTERNAL_FLAGS
+ size_t groupSize;
+#ifdef BLOCK_SORT_EXTERNAL_FLAGS
if ((Flags[i >> kNumFlagsBits] & (1 << (i & kFlagsMask))) == 0)
{
@@ -441,56 +553,56 @@
}
for (groupSize = 1;
(Flags[(i + groupSize) >> kNumFlagsBits] & (1 << ((i + groupSize) & kFlagsMask))) != 0;
- groupSize++);
-
+ groupSize++)
+ {}
groupSize++;
- #else
+#else
- groupSize = ((Indices[i] & ~0xC0000000) >> kNumBitsMax);
+ groupSize = (Indices[i] & ~0xC0000000) >> kNumBitsMax;
{
- BoolInt finishedGroup = ((Indices[i] & 0x80000000) == 0);
- if ((Indices[i] & 0x40000000) != 0)
- {
- groupSize += ((Indices[(size_t)i + 1] >> kNumBitsMax) << kNumExtra0Bits);
- Indices[(size_t)i + 1] &= kIndexMask;
- }
- Indices[i] &= kIndexMask;
- groupSize++;
- if (finishedGroup || groupSize == 1)
- {
- Indices[i - finishedGroupSize] &= kIndexMask;
- if (finishedGroupSize > 1)
- Indices[(size_t)(i - finishedGroupSize) + 1] &= kIndexMask;
+ const BoolInt finishedGroup = ((Indices[i] & 0x80000000) == 0);
+ if (Indices[i] & 0x40000000)
{
- UInt32 newGroupSize = groupSize + finishedGroupSize;
- SetFinishedGroupSize(Indices + i - finishedGroupSize, newGroupSize)
- finishedGroupSize = newGroupSize;
+ groupSize += ((Indices[(size_t)i + 1] >> kNumBitsMax) << kNumExtra0Bits);
+ Indices[(size_t)i + 1] &= kIndexMask;
}
- i += groupSize;
- continue;
- }
- finishedGroupSize = 0;
+ Indices[i] &= kIndexMask;
+ groupSize++;
+ if (finishedGroup || groupSize == 1)
+ {
+ Indices[i - finishedGroupSize] &= kIndexMask;
+ if (finishedGroupSize > 1)
+ Indices[(size_t)(i - finishedGroupSize) + 1] &= kIndexMask;
+ {
+ const size_t newGroupSize = groupSize + finishedGroupSize;
+ SetFinishedGroupSize(Indices + i - finishedGroupSize, newGroupSize)
+ finishedGroupSize = newGroupSize;
+ }
+ i += groupSize;
+ continue;
+ }
+ finishedGroupSize = 0;
}
- #endif
+#endif
if (NumSortedBytes >= blockSize)
{
- UInt32 j;
+ size_t j;
for (j = 0; j < groupSize; j++)
{
- UInt32 t = (i + j);
+ size_t t = i + j;
/* Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask)); */
- Groups[Indices[t]] = t;
+ Groups[Indices[t]] = (UInt32)t;
}
}
else
if (SortGroup(blockSize, NumSortedBytes, i, groupSize, NumRefBits, Indices
- #ifndef BLOCK_SORT_USE_HEAP_SORT
- , 0, blockSize
- #endif
- ) != 0)
+ #ifndef BLOCK_SORT_USE_HEAP_SORT
+ , 0, blockSize
+ #endif
+ ))
newLimit = i + groupSize;
i += groupSize;
}
@@ -498,19 +610,19 @@
break;
}
}
- #ifndef BLOCK_SORT_EXTERNAL_FLAGS
+#ifndef BLOCK_SORT_EXTERNAL_FLAGS
for (i = 0; i < blockSize;)
{
- UInt32 groupSize = ((Indices[i] & ~0xC0000000) >> kNumBitsMax);
- if ((Indices[i] & 0x40000000) != 0)
+ size_t groupSize = (Indices[i] & ~0xC0000000) >> kNumBitsMax;
+ if (Indices[i] & 0x40000000)
{
- groupSize += ((Indices[(size_t)i + 1] >> kNumBitsMax) << kNumExtra0Bits);
+ groupSize += (Indices[(size_t)i + 1] >> kNumBitsMax) << kNumExtra0Bits;
Indices[(size_t)i + 1] &= kIndexMask;
}
Indices[i] &= kIndexMask;
groupSize++;
i += groupSize;
}
- #endif
+#endif
return Groups[0];
}
diff -Nru 7zip-24.09+dfsg/C/BwtSort.h 7zip-25.00+dfsg/C/BwtSort.h
--- 7zip-24.09+dfsg/C/BwtSort.h 2023-03-03 11:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/C/BwtSort.h 2024-12-18 19:00:00.000000000 +0100
@@ -1,5 +1,5 @@
/* BwtSort.h -- BWT block sorting
-2023-03-03 : Igor Pavlov : Public domain */
+: Igor Pavlov : Public domain */
#ifndef ZIP7_INC_BWT_SORT_H
#define ZIP7_INC_BWT_SORT_H
@@ -10,16 +10,17 @@
/* use BLOCK_SORT_EXTERNAL_FLAGS if blockSize can be > 1M */
/* #define BLOCK_SORT_EXTERNAL_FLAGS */
+// #define BLOCK_SORT_EXTERNAL_FLAGS
#ifdef BLOCK_SORT_EXTERNAL_FLAGS
-#define BLOCK_SORT_EXTERNAL_SIZE(blockSize) ((((blockSize) + 31) >> 5))
+#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);
+UInt32 BlockSort(UInt32 *indices, const Byte *data, size_t blockSize);
EXTERN_C_END
diff -Nru 7zip-24.09+dfsg/C/Compiler.h 7zip-25.00+dfsg/C/Compiler.h
--- 7zip-24.09+dfsg/C/Compiler.h 2024-03-01 16:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/C/Compiler.h 2025-06-30 19:00:00.000000000 +0200
@@ -1,5 +1,5 @@
/* Compiler.h : Compiler specific defines and pragmas
-2024-01-22 : Igor Pavlov : Public domain */
+: Igor Pavlov : Public domain */
#ifndef ZIP7_INC_COMPILER_H
#define ZIP7_INC_COMPILER_H
@@ -183,6 +183,16 @@
#define Z7_ATTRIB_NO_VECTORIZE
#endif
+#if defined(Z7_MSC_VER_ORIGINAL) && (Z7_MSC_VER_ORIGINAL >= 1920)
+ #define Z7_PRAGMA_OPTIMIZE_FOR_CODE_SIZE _Pragma("optimize ( \"s\", on )")
+ #define Z7_PRAGMA_OPTIMIZE_DEFAULT _Pragma("optimize ( \"\", on )")
+#else
+ #define Z7_PRAGMA_OPTIMIZE_FOR_CODE_SIZE
+ #define Z7_PRAGMA_OPTIMIZE_DEFAULT
+#endif
+
+
+
#if defined(MY_CPU_X86_OR_AMD64) && ( \
defined(__clang__) && (__clang_major__ >= 4) \
|| defined(__GNUC__) && (__GNUC__ >= 5))
diff -Nru 7zip-24.09+dfsg/C/CpuArch.h 7zip-25.00+dfsg/C/CpuArch.h
--- 7zip-24.09+dfsg/C/CpuArch.h 2024-11-13 09:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/C/CpuArch.h 2025-04-05 10:00:00.000000000 +0200
@@ -47,6 +47,12 @@
#define MY_CPU_SIZEOF_POINTER 4
#endif
+#if defined(__SSE2__) \
+ || defined(MY_CPU_AMD64) \
+ || defined(_M_IX86_FP) && (_M_IX86_FP >= 2)
+#define MY_CPU_SSE2
+#endif
+
#if defined(_M_ARM64) \
|| defined(_M_ARM64EC) \
@@ -571,10 +577,12 @@
#define Z7_CONV_BE_TO_NATIVE_CONST32(v) (v)
#define Z7_CONV_LE_TO_NATIVE_CONST32(v) Z7_BSWAP32_CONST(v)
#define Z7_CONV_NATIVE_TO_BE_32(v) (v)
+// #define Z7_GET_NATIVE16_FROM_2_BYTES(b0, b1) ((b1) | ((b0) << 8))
#elif defined(MY_CPU_LE)
#define Z7_CONV_BE_TO_NATIVE_CONST32(v) Z7_BSWAP32_CONST(v)
#define Z7_CONV_LE_TO_NATIVE_CONST32(v) (v)
#define Z7_CONV_NATIVE_TO_BE_32(v) Z7_BSWAP32(v)
+// #define Z7_GET_NATIVE16_FROM_2_BYTES(b0, b1) ((b0) | ((b1) << 8))
#else
#error Stop_Compiling_Unknown_Endian_CONV
#endif
diff -Nru 7zip-24.09+dfsg/C/HuffEnc.c 7zip-25.00+dfsg/C/HuffEnc.c
--- 7zip-24.09+dfsg/C/HuffEnc.c 2023-09-07 13:00:00.000000000 +0200
+++ 7zip-25.00+dfsg/C/HuffEnc.c 2025-03-20 15:00:00.000000000 +0100
@@ -1,60 +1,125 @@
/* HuffEnc.c -- functions for Huffman encoding
-2023-09-07 : Igor Pavlov : Public domain */
+Igor Pavlov : Public domain */
#include "Precomp.h"
+#include <string.h>
+
#include "HuffEnc.h"
#include "Sort.h"
+#include "CpuArch.h"
-#define kMaxLen 16
-#define NUM_BITS 10
-#define MASK ((1u << NUM_BITS) - 1)
-
-#define NUM_COUNTERS 64
-
-#define HUFFMAN_SPEED_OPT
+#define kMaxLen Z7_HUFFMAN_LEN_MAX
+#define NUM_BITS 10
+#define MASK ((1u << NUM_BITS) - 1)
+#define FREQ_MASK (~(UInt32)MASK)
+#define NUM_COUNTERS (48 * 2)
+
+#if 1 && (defined(MY_CPU_LE) || defined(MY_CPU_BE))
+#if defined(MY_CPU_LE)
+ #define HI_HALF_OFFSET 1
+#else
+ #define HI_HALF_OFFSET 0
+#endif
+#define LOAD_PARENT(p) ((unsigned)*((const UInt16 *)(p) + HI_HALF_OFFSET))
+#define STORE_PARENT(p, fb, val) *((UInt16 *)(p) + HI_HALF_OFFSET) = (UInt16)(val);
+#define STORE_PARENT_DIRECT(p, fb, hi) STORE_PARENT(p, fb, hi)
+#define UPDATE_E(eHi) eHi++;
+#else
+#define LOAD_PARENT(p) ((unsigned)(*(p) >> NUM_BITS))
+#define STORE_PARENT_DIRECT(p, fb, hi) *(p) = ((fb) & MASK) | (hi); // set parent field
+#define STORE_PARENT(p, fb, val) STORE_PARENT_DIRECT(p, fb, ((UInt32)(val) << NUM_BITS))
+#define UPDATE_E(eHi) eHi += 1 << NUM_BITS;
+#endif
-void Huffman_Generate(const UInt32 *freqs, UInt32 *p, Byte *lens, UInt32 numSymbols, UInt32 maxLen)
+void Huffman_Generate(const UInt32 *freqs, UInt32 *p, Byte *lens, unsigned numSymbols, unsigned maxLen)
{
- UInt32 num = 0;
- /* if (maxLen > 10) maxLen = 10; */
+#if NUM_COUNTERS > 2
+ unsigned counters[NUM_COUNTERS];
+#endif
+#if 1 && NUM_COUNTERS > (kMaxLen + 4) * 2
+ #define lenCounters (counters)
+ #define codes (counters + kMaxLen + 4)
+#else
+ unsigned lenCounters[kMaxLen + 1];
+ UInt32 codes[kMaxLen + 1];
+#endif
+
+ unsigned num;
{
- UInt32 i;
-
- #ifdef HUFFMAN_SPEED_OPT
+ unsigned i;
+ // UInt32 sum = 0;
+
+#if NUM_COUNTERS > 2
- UInt32 counters[NUM_COUNTERS];
+#define CTR_ITEM_FOR_FREQ(freq) \
+ counters[(freq) >= NUM_COUNTERS - 1 ? NUM_COUNTERS - 1 : (unsigned)(freq)]
+
for (i = 0; i < NUM_COUNTERS; i++)
counters[i] = 0;
- for (i = 0; i < numSymbols; i++)
+ memset(lens, 0, numSymbols);
{
- UInt32 freq = freqs[i];
- counters[(freq < NUM_COUNTERS - 1) ? freq : NUM_COUNTERS - 1]++;
+ const UInt32 *fp = freqs + numSymbols;
+#define NUM_UNROLLS 1
+#if NUM_UNROLLS > 1 // use 1 if odd (numSymbols) is possisble
+ if (numSymbols & 1)
+ {
+ UInt32 f;
+ f = *--fp; CTR_ITEM_FOR_FREQ(f)++;
+ // sum += f;
+ }
+#endif
+ do
+ {
+ UInt32 f;
+ fp -= NUM_UNROLLS;
+ f = fp[0]; CTR_ITEM_FOR_FREQ(f)++;
+ // sum += f;
+#if NUM_UNROLLS > 1
+ f = fp[1]; CTR_ITEM_FOR_FREQ(f)++;
+ // sum += f;
+#endif
+ }
+ while (fp != freqs);
}
-
- for (i = 1; i < NUM_COUNTERS; i++)
+#if 0
+ printf("\nsum=%8u numSymbols =%3u ctrs:", sum, numSymbols);
{
- UInt32 temp = counters[i];
- counters[i] = num;
- num += temp;
+ unsigned k = 0;
+ for (k = 0; k < NUM_COUNTERS; k++)
+ printf(" %u", counters[k]);
}
-
- for (i = 0; i < numSymbols; i++)
+#endif
+
+ num = counters[1];
+ counters[1] = 0;
+ for (i = 2; i != NUM_COUNTERS; i += 2)
{
- 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);
+ unsigned c;
+ c = (counters )[i]; (counters )[i] = num; num += c;
+ c = (counters + 1)[i]; (counters + 1)[i] = num; num += c;
+ }
+ counters[0] = num; // we want to write (freq==0) symbols to the end of (p) array
+ {
+ i = 0;
+ do
+ {
+ const UInt32 f = freqs[i];
+#if 0
+ if (f == 0) lens[i] = 0; else
+#endif
+ p[CTR_ITEM_FOR_FREQ(f)++] = i | (f << NUM_BITS);
+ }
+ while (++i != numSymbols);
}
- counters[0] = 0;
HeapSort(p + counters[NUM_COUNTERS - 2], counters[NUM_COUNTERS - 1] - counters[NUM_COUNTERS - 2]);
- #else
-
+#else // NUM_COUNTERS <= 2
+
+ num = 0;
for (i = 0; i < numSymbols; i++)
{
- UInt32 freq = freqs[i];
+ const UInt32 freq = freqs[i];
if (freq == 0)
lens[i] = 0;
else
@@ -62,17 +127,27 @@
}
HeapSort(p, num);
- #endif
+#endif
}
- if (num < 2)
+ if (num <= 2)
{
unsigned minCode = 0;
unsigned maxCode = 1;
- if (num == 1)
+ if (num)
{
- maxCode = (unsigned)p[0] & MASK;
- if (maxCode == 0)
+ maxCode = (unsigned)p[(size_t)num - 1] & MASK;
+ if (num == 2)
+ {
+ minCode = (unsigned)p[0] & MASK;
+ if (minCode > maxCode)
+ {
+ const unsigned temp = minCode;
+ minCode = maxCode;
+ maxCode = temp;
+ }
+ }
+ else if (maxCode == 0)
maxCode++;
}
p[minCode] = 0;
@@ -80,69 +155,191 @@
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);
-
+ unsigned i;
+ for (i = 0; i <= kMaxLen; i++)
+ lenCounters[i] = 0;
+ lenCounters[1] = 2; // by default root node has 2 child leaves at level 1.
+ }
+ // if (num != 2)
+ {
+ // num > 2
+ // the binary tree will contain (num - 1) internal nodes.
+ // p[num - 2] will be root node of binary tree.
+ UInt32 *b;
+ UInt32 *n;
+ // first node will have two leaf childs: p[0] and p[1]:
+ // p[0] += p[1] & FREQ_MASK; // set frequency sum of child leafs
+ // if (pi == n) exit(0);
+ // if (pi != n)
{
- UInt32 lenCounters[kMaxLen + 1];
- for (i = 0; i <= kMaxLen; i++)
- lenCounters[i] = 0;
-
- p[--e] &= MASK;
- lenCounters[1] = 2;
- while (e != 0)
- {
- UInt32 len = (p[p[--e] >> NUM_BITS] >> NUM_BITS) + 1;
- p[e] = (p[e] & MASK) | (len << NUM_BITS);
- if (len >= maxLen)
- for (len = maxLen - 1; lenCounters[len] == 0; len--);
- lenCounters[len]--;
- lenCounters[(size_t)len + 1] += 2;
- }
-
+ UInt32 fb = (p[1] & FREQ_MASK) + p[0];
+ UInt32 f = p[2] & FREQ_MASK;
+ const UInt32 *pi = p + 2;
+ UInt32 *e = p;
+ UInt32 eHi = 0;
+ n = p + num;
+ b = p;
+ // p[0] = fb;
+ for (;;)
{
- UInt32 len;
- i = 0;
- for (len = maxLen; len != 0; len--)
+ // (b <= e)
+ UInt32 sum;
+ e++;
+ UPDATE_E(eHi)
+
+ // (b < e)
+
+ // p range : high bits
+ // [0, b) : parent : processed nodes that have parent and childs
+ // [b, e) : FREQ : non-processed nodes that have no parent but have childs
+ // [e, pi) : FREQ : processed leaves for which parent node was created
+ // [pi, n) : FREQ : non-processed leaves for which parent node was not created
+
+ // first child
+ // note : (*b < f) is same result as ((*b & FREQ_MASK) < f)
+ if (fb < f)
+ {
+ // node freq is smaller
+ sum = fb & FREQ_MASK;
+ STORE_PARENT_DIRECT (b, fb, eHi)
+ b++;
+ fb = *b;
+ if (b == e)
+ {
+ if (++pi == n)
+ break;
+ sum += f;
+ fb &= MASK;
+ fb |= sum;
+ *e = fb;
+ f = *pi & FREQ_MASK;
+ continue;
+ }
+ }
+ else if (++pi == n)
+ {
+ STORE_PARENT_DIRECT (b, fb, eHi)
+ b++;
+ break;
+ }
+ else
+ {
+ sum = f;
+ f = *pi & FREQ_MASK;
+ }
+
+ // (b < e)
+
+ // second child
+ if (fb < f)
{
- UInt32 k;
- for (k = lenCounters[len]; k != 0; k--)
- lens[p[i++] & MASK] = (Byte)len;
+ sum += fb;
+ sum &= FREQ_MASK;
+ STORE_PARENT_DIRECT (b, fb, eHi)
+ b++;
+ *e = (*e & MASK) | sum; // set frequency sum
+ // (b <= e) is possible here
+ fb = *b;
+ }
+ else if (++pi == n)
+ break;
+ else
+ {
+ sum += f;
+ f = *pi & FREQ_MASK;
+ *e = (*e & MASK) | sum; // set frequency sum
}
}
-
+ }
+
+ // printf("\nnum-e=%3u, numSymbols=%3u, num=%3u, b=%3u", n - e, numSymbols, n - p, b - p);
+ {
+ n -= 2;
+ *n &= MASK; // root node : we clear high bits (zero bits mean level == 0)
+ if (n != b)
{
- UInt32 nextCodes[kMaxLen + 1];
+ // We go here, if we have some number of non-created nodes up to root.
+ // We process them in simplified code:
+ // position of parent for each pair of nodes is known.
+ // n[-2], n[-1] : current pair of child nodes
+ // (p1) : parent node for current pair.
+ UInt32 *p1 = n;
+ do
{
- UInt32 code = 0;
- UInt32 len;
- for (len = 1; len <= kMaxLen; len++)
- nextCodes[len] = code = (code + lenCounters[(size_t)len - 1]) << 1;
+ const unsigned len = LOAD_PARENT(p1) + 1;
+ p1--;
+ (lenCounters )[len] -= 2; // we remove 2 leaves from level (len)
+ (lenCounters + 1)[len] += 2 * 2; // we add 4 leaves at level (len + 1)
+ n -= 2;
+ STORE_PARENT (n , n[0], len)
+ STORE_PARENT (n + 1, n[1], len)
}
- /* if (code + lenCounters[kMaxLen] - 1 != (1 << kMaxLen) - 1) throw 1; */
-
+ while (n != b);
+ }
+ }
+
+ if (b != p)
+ {
+ // we detect level of each node (realtive to root),
+ // and update lenCounters[].
+ // We process only intermediate nodes and we don't process leaves.
+ do
+ {
+ // if (ii < b) : parent_bits_of (p[ii]) == index of parent node : ii < (p[ii])
+ // if (ii >= b) : parent_bits_of (p[ii]) == level of this (ii) node in tree
+ unsigned len;
+ b--;
+ len = (unsigned)LOAD_PARENT(p + LOAD_PARENT(b)) + 1;
+ STORE_PARENT (b, *b, len)
+ if (len >= maxLen)
{
- UInt32 k;
- for (k = 0; k < numSymbols; k++)
- p[k] = nextCodes[lens[k]]++;
+ // We are not allowed to create node at level (maxLen) and higher,
+ // because all leaves must be placed to level (maxLen) or lower.
+ // We find nearest allowed leaf and place current node to level of that leaf:
+ for (len = maxLen - 1; lenCounters[len] == 0; len--) {}
}
+ lenCounters[len]--; // we remove 1 leaf from level (len)
+ (lenCounters + 1)[len] += 2; // we add 2 leaves at level (len + 1)
+ }
+ while (b != p);
+ }
+ }
+ {
+ {
+ unsigned len = maxLen;
+ const UInt32 *p2 = p;
+ do
+ {
+ unsigned k = lenCounters[len];
+ if (k)
+ do
+ lens[(unsigned)*p2++ & MASK] = (Byte)len;
+ while (--k);
+ }
+ while (--len);
+ }
+ codes[0] = 0; // we don't want garbage values to be written to p[] array.
+ // codes[1] = 0;
+ {
+ UInt32 code = 0;
+ unsigned len;
+ for (len = 0; len < kMaxLen; len++)
+ (codes + 1)[len] = code = (code + lenCounters[len]) << 1;
+ }
+ /* if (code + lenCounters[kMaxLen] - 1 != (1 << kMaxLen) - 1) throw 1; */
+ {
+ const Byte * const limit = lens + numSymbols;
+ do
+ {
+ unsigned len;
+ UInt32 c;
+ len = lens[0]; c = codes[len]; p[0] = c; codes[len] = c + 1;
+ // len = lens[1]; c = codes[len]; p[1] = c; codes[len] = c + 1;
+ p += 1;
+ lens += 1;
}
+ while (lens != limit);
}
}
}
@@ -150,5 +347,14 @@
#undef kMaxLen
#undef NUM_BITS
#undef MASK
+#undef FREQ_MASK
#undef NUM_COUNTERS
-#undef HUFFMAN_SPEED_OPT
+#undef CTR_ITEM_FOR_FREQ
+#undef LOAD_PARENT
+#undef STORE_PARENT
+#undef STORE_PARENT_DIRECT
+#undef UPDATE_E
+#undef HI_HALF_OFFSET
+#undef NUM_UNROLLS
+#undef lenCounters
+#undef codes
diff -Nru 7zip-24.09+dfsg/C/HuffEnc.h 7zip-25.00+dfsg/C/HuffEnc.h
--- 7zip-24.09+dfsg/C/HuffEnc.h 2023-03-05 18:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/C/HuffEnc.h 2025-03-20 15:00:00.000000000 +0100
@@ -1,5 +1,5 @@
/* HuffEnc.h -- Huffman encoding
-2023-03-05 : Igor Pavlov : Public domain */
+Igor Pavlov : Public domain */
#ifndef ZIP7_INC_HUFF_ENC_H
#define ZIP7_INC_HUFF_ENC_H
@@ -8,14 +8,14 @@
EXTERN_C_BEGIN
+#define Z7_HUFFMAN_LEN_MAX 16
/*
Conditions:
- num <= 1024 = 2 ^ NUM_BITS
+ 2 <= num <= 1024 = 2 ^ NUM_BITS
Sum(freqs) < 4M = 2 ^ (32 - NUM_BITS)
- maxLen <= 16 = kMaxLen
+ 1 <= maxLen <= 16 = Z7_HUFFMAN_LEN_MAX
Num_Items(p) >= HUFFMAN_TEMP_SIZE(num)
*/
-
void Huffman_Generate(const UInt32 *freqs, UInt32 *p, Byte *lens, UInt32 num, UInt32 maxLen);
EXTERN_C_END
diff -Nru 7zip-24.09+dfsg/C/LzFind.c 7zip-25.00+dfsg/C/LzFind.c
--- 7zip-24.09+dfsg/C/LzFind.c 2024-03-01 08:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/C/LzFind.c 2025-05-19 08:00:00.000000000 +0200
@@ -1,5 +1,5 @@
/* LzFind.c -- Match finder for LZ algorithms
-2024-03-01 : Igor Pavlov : Public domain */
+: Igor Pavlov : Public domain */
#include "Precomp.h"
@@ -404,7 +404,7 @@
const unsigned nbMax =
(p->numHashBytes == 2 ? 16 :
(p->numHashBytes == 3 ? 24 : 32));
- if (numBits > nbMax)
+ if (numBits >= nbMax)
numBits = nbMax;
if (numBits >= 32)
hs = (UInt32)0 - 1;
@@ -416,14 +416,14 @@
hs |= (256 << kLzHash_CrcShift_2) - 1;
{
const UInt32 hs2 = MatchFinder_GetHashMask2(p, historySize);
- if (hs > hs2)
+ if (hs >= hs2)
hs = hs2;
}
hsCur = hs;
if (p->expectedDataSize < historySize)
{
const UInt32 hs2 = MatchFinder_GetHashMask2(p, (UInt32)p->expectedDataSize);
- if (hsCur > hs2)
+ if (hsCur >= hs2)
hsCur = hs2;
}
}
@@ -434,7 +434,7 @@
if (p->expectedDataSize < historySize)
{
hsCur = MatchFinder_GetHashMask(p, (UInt32)p->expectedDataSize);
- if (hsCur > hs) // is it possible?
+ if (hsCur >= hs) // is it possible?
hsCur = hs;
}
}
@@ -890,7 +890,7 @@
return d;
{
const Byte *pb = cur - delta;
- curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)];
+ curMatch = son[_cyclicBufferPos - delta + (_cyclicBufferPos < delta ? _cyclicBufferSize : 0)];
if (pb[maxLen] == cur[maxLen] && *pb == *cur)
{
UInt32 len = 0;
@@ -925,7 +925,7 @@
break;
{
ptrdiff_t diff;
- curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)];
+ curMatch = son[_cyclicBufferPos - delta + (_cyclicBufferPos < delta ? _cyclicBufferSize : 0)];
diff = (ptrdiff_t)0 - (ptrdiff_t)delta;
if (cur[maxLen] == cur[(ptrdiff_t)maxLen + diff])
{
@@ -972,7 +972,7 @@
// if (curMatch >= pos) { *ptr0 = *ptr1 = kEmptyHashValue; return NULL; }
cmCheck = (UInt32)(pos - _cyclicBufferSize);
- if ((UInt32)pos <= _cyclicBufferSize)
+ if ((UInt32)pos < _cyclicBufferSize)
cmCheck = 0;
if (cmCheck < curMatch)
@@ -980,7 +980,7 @@
{
const UInt32 delta = pos - curMatch;
{
- CLzRef *pair = son + ((size_t)(_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
+ CLzRef *pair = son + ((size_t)(_cyclicBufferPos - delta + (_cyclicBufferPos < delta ? _cyclicBufferSize : 0)) << 1);
const Byte *pb = cur - delta;
unsigned len = (len0 < len1 ? len0 : len1);
const UInt32 pair0 = pair[0];
@@ -1039,7 +1039,7 @@
UInt32 cmCheck;
cmCheck = (UInt32)(pos - _cyclicBufferSize);
- if ((UInt32)pos <= _cyclicBufferSize)
+ if ((UInt32)pos < _cyclicBufferSize)
cmCheck = 0;
if (// curMatch >= pos || // failure
@@ -1048,7 +1048,7 @@
{
const UInt32 delta = pos - curMatch;
{
- CLzRef *pair = son + ((size_t)(_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
+ CLzRef *pair = son + ((size_t)(_cyclicBufferPos - delta + (_cyclicBufferPos < delta ? _cyclicBufferSize : 0)) << 1);
const Byte *pb = cur - delta;
unsigned len = (len0 < len1 ? len0 : len1);
if (pb[len] == cur[len])
@@ -1595,7 +1595,7 @@
UInt32 pos = p->pos; \
UInt32 num2 = num; \
/* (p->pos == p->posLimit) is not allowed here !!! */ \
- { const UInt32 rem = p->posLimit - pos; if (num2 > rem) num2 = rem; } \
+ { const UInt32 rem = p->posLimit - pos; if (num2 >= rem) num2 = rem; } \
num -= num2; \
{ const UInt32 cycPos = p->cyclicBufferPos; \
son = p->son + cycPos; \
diff -Nru 7zip-24.09+dfsg/C/LzFindMt.c 7zip-25.00+dfsg/C/LzFindMt.c
--- 7zip-24.09+dfsg/C/LzFindMt.c 2024-01-22 15:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/C/LzFindMt.c 2025-06-30 18:00:00.000000000 +0200
@@ -1,5 +1,5 @@
/* LzFindMt.c -- multithreaded Match finder for LZ algorithms
-2024-01-22 : Igor Pavlov : Public domain */
+: Igor Pavlov : Public domain */
#include "Precomp.h"
@@ -82,6 +82,8 @@
Z7_NO_INLINE
static void MtSync_Construct(CMtSync *p)
{
+ p->affinityGroup = -1;
+ p->affinityInGroup = 0;
p->affinity = 0;
p->wasCreated = False;
p->csWasInitialized = False;
@@ -259,6 +261,12 @@
// return ERROR_TOO_MANY_POSTS; // for debug
// return EINVAL; // for debug
+#ifdef _WIN32
+ if (p->affinityGroup >= 0)
+ wres = Thread_Create_With_Group(&p->thread, startAddress, obj,
+ (unsigned)(UInt32)p->affinityGroup, (CAffinityMask)p->affinityInGroup);
+ else
+#endif
if (p->affinity != 0)
wres = Thread_Create_With_Affinity(&p->thread, startAddress, obj, (CAffinityMask)p->affinity);
else
diff -Nru 7zip-24.09+dfsg/C/LzFindMt.h 7zip-25.00+dfsg/C/LzFindMt.h
--- 7zip-24.09+dfsg/C/LzFindMt.h 2024-01-22 15:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/C/LzFindMt.h 2025-05-10 09:00:00.000000000 +0200
@@ -1,5 +1,5 @@
/* LzFindMt.h -- multithreaded Match finder for LZ algorithms
-2024-01-22 : Igor Pavlov : Public domain */
+: Igor Pavlov : Public domain */
#ifndef ZIP7_INC_LZ_FIND_MT_H
#define ZIP7_INC_LZ_FIND_MT_H
@@ -12,8 +12,10 @@
typedef struct
{
UInt32 numProcessedBlocks;
- CThread thread;
+ Int32 affinityGroup;
+ UInt64 affinityInGroup;
UInt64 affinity;
+ CThread thread;
BoolInt wasCreated;
BoolInt needStart;
diff -Nru 7zip-24.09+dfsg/C/Lzma2Enc.c 7zip-25.00+dfsg/C/Lzma2Enc.c
--- 7zip-24.09+dfsg/C/Lzma2Enc.c 2023-04-13 10:00:00.000000000 +0200
+++ 7zip-25.00+dfsg/C/Lzma2Enc.c 2025-06-30 19:00:00.000000000 +0200
@@ -1,5 +1,5 @@
/* Lzma2Enc.c -- LZMA2 Encoder
-2023-04-13 : Igor Pavlov : Public domain */
+: Igor Pavlov : Public domain */
#include "Precomp.h"
@@ -235,6 +235,7 @@
p->numBlockThreads_Reduced = -1;
p->numBlockThreads_Max = -1;
p->numTotalThreads = -1;
+ p->numThreadGroups = 0;
}
void Lzma2EncProps_Normalize(CLzma2EncProps *p)
@@ -781,6 +782,7 @@
}
p->mtCoder.numThreadsMax = (unsigned)p->props.numBlockThreads_Max;
+ p->mtCoder.numThreadGroups = p->props.numThreadGroups;
p->mtCoder.expectedDataSize = p->expectedDataSize;
{
diff -Nru 7zip-24.09+dfsg/C/Lzma2Enc.h 7zip-25.00+dfsg/C/Lzma2Enc.h
--- 7zip-24.09+dfsg/C/Lzma2Enc.h 2023-04-13 10:00:00.000000000 +0200
+++ 7zip-25.00+dfsg/C/Lzma2Enc.h 2025-06-28 14:00:00.000000000 +0200
@@ -18,6 +18,7 @@
int numBlockThreads_Reduced;
int numBlockThreads_Max;
int numTotalThreads;
+ unsigned numThreadGroups; // 0 : no groups
} CLzma2EncProps;
void Lzma2EncProps_Init(CLzma2EncProps *p);
diff -Nru 7zip-24.09+dfsg/C/LzmaEnc.c 7zip-25.00+dfsg/C/LzmaEnc.c
--- 7zip-24.09+dfsg/C/LzmaEnc.c 2024-11-12 08:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/C/LzmaEnc.c 2025-05-11 16:00:00.000000000 +0200
@@ -62,7 +62,9 @@
p->lc = p->lp = p->pb = p->algo = p->fb = p->btMode = p->numHashBytes = p->numThreads = -1;
p->numHashOutBits = 0;
p->writeEndMark = 0;
+ p->affinityGroup = -1;
p->affinity = 0;
+ p->affinityInGroup = 0;
}
void LzmaEncProps_Normalize(CLzmaEncProps *p)
@@ -598,6 +600,10 @@
p->multiThread = (props.numThreads > 1);
p->matchFinderMt.btSync.affinity =
p->matchFinderMt.hashSync.affinity = props.affinity;
+ p->matchFinderMt.btSync.affinityGroup =
+ p->matchFinderMt.hashSync.affinityGroup = props.affinityGroup;
+ p->matchFinderMt.btSync.affinityInGroup =
+ p->matchFinderMt.hashSync.affinityInGroup = props.affinityInGroup;
#endif
return SZ_OK;
diff -Nru 7zip-24.09+dfsg/C/LzmaEnc.h 7zip-25.00+dfsg/C/LzmaEnc.h
--- 7zip-24.09+dfsg/C/LzmaEnc.h 2023-04-13 10:00:00.000000000 +0200
+++ 7zip-25.00+dfsg/C/LzmaEnc.h 2025-05-10 09:00:00.000000000 +0200
@@ -1,5 +1,5 @@
/* LzmaEnc.h -- LZMA Encoder
-2023-04-13 : Igor Pavlov : Public domain */
+: Igor Pavlov : Public domain */
#ifndef ZIP7_INC_LZMA_ENC_H
#define ZIP7_INC_LZMA_ENC_H
@@ -29,11 +29,13 @@
int numThreads; /* 1 or 2, default = 2 */
// int _pad;
+ Int32 affinityGroup;
UInt64 reduceSize; /* estimated size of data that will be compressed. default = (UInt64)(Int64)-1.
Encoder uses this value to reduce dictionary size */
UInt64 affinity;
+ UInt64 affinityInGroup;
} CLzmaEncProps;
void LzmaEncProps_Init(CLzmaEncProps *p);
diff -Nru 7zip-24.09+dfsg/C/MtCoder.c 7zip-25.00+dfsg/C/MtCoder.c
--- 7zip-24.09+dfsg/C/MtCoder.c 2023-09-07 15:00:00.000000000 +0200
+++ 7zip-25.00+dfsg/C/MtCoder.c 2025-07-04 08:00:00.000000000 +0200
@@ -1,5 +1,5 @@
/* MtCoder.c -- Multi-thread Coder
-2023-09-07 : Igor Pavlov : Public domain */
+: Igor Pavlov : Public domain */
#include "Precomp.h"
@@ -39,14 +39,28 @@
static THREAD_FUNC_DECL ThreadFunc(void *pp);
-static SRes MtCoderThread_CreateAndStart(CMtCoderThread *t)
+static SRes MtCoderThread_CreateAndStart(CMtCoderThread *t
+#ifdef _WIN32
+ , CMtCoder * const mtc
+#endif
+ )
{
WRes wres = AutoResetEvent_OptCreate_And_Reset(&t->startEvent);
+ // printf("\n====== MtCoderThread_CreateAndStart : \n");
if (wres == 0)
{
t->stop = False;
if (!Thread_WasCreated(&t->thread))
- wres = Thread_Create(&t->thread, ThreadFunc, t);
+ {
+#ifdef _WIN32
+ if (mtc->numThreadGroups)
+ wres = Thread_Create_With_Group(&t->thread, ThreadFunc, t,
+ ThreadNextGroup_GetNext(&mtc->nextGroup), // group
+ 0); // affinityMask
+ else
+#endif
+ wres = Thread_Create(&t->thread, ThreadFunc, t);
+ }
if (wres == 0)
wres = Event_Set(&t->startEvent);
}
@@ -56,6 +70,7 @@
}
+Z7_FORCE_INLINE
static void MtCoderThread_Destruct(CMtCoderThread *t)
{
if (Thread_WasCreated(&t->thread))
@@ -85,7 +100,7 @@
static SRes ThreadFunc2(CMtCoderThread *t)
{
- CMtCoder *mtc = t->mtCoder;
+ CMtCoder * const mtc = t->mtCoder;
for (;;)
{
@@ -185,7 +200,11 @@
if (mtc->numStartedThreads < mtc->numStartedThreadsLimit
&& mtc->expectedDataSize != readProcessed)
{
- res = MtCoderThread_CreateAndStart(&mtc->threads[mtc->numStartedThreads]);
+ res = MtCoderThread_CreateAndStart(&mtc->threads[mtc->numStartedThreads]
+#ifdef _WIN32
+ , mtc
+#endif
+ );
if (res == SZ_OK)
mtc->numStartedThreads++;
else
@@ -221,7 +240,7 @@
}
{
- CMtCoderBlock *block = &mtc->blocks[bi];
+ CMtCoderBlock * const block = &mtc->blocks[bi];
block->res = res;
block->bufIndex = bufIndex;
block->finished = finished;
@@ -311,7 +330,7 @@
static THREAD_FUNC_DECL ThreadFunc(void *pp)
{
- CMtCoderThread *t = (CMtCoderThread *)pp;
+ CMtCoderThread * const t = (CMtCoderThread *)pp;
for (;;)
{
if (Event_Wait(&t->startEvent) != 0)
@@ -319,7 +338,7 @@
if (t->stop)
return 0;
{
- SRes res = ThreadFunc2(t);
+ const SRes res = ThreadFunc2(t);
CMtCoder *mtc = t->mtCoder;
if (res != SZ_OK)
{
@@ -328,7 +347,7 @@
#ifndef MTCODER_USE_WRITE_THREAD
{
- unsigned numFinished = (unsigned)InterlockedIncrement(&mtc->numFinishedThreads);
+ const unsigned numFinished = (unsigned)InterlockedIncrement(&mtc->numFinishedThreads);
if (numFinished == mtc->numStartedThreads)
if (Event_Set(&mtc->finishedEvent) != 0)
return (THREAD_FUNC_RET_TYPE)SZ_ERROR_THREAD;
@@ -346,6 +365,7 @@
p->blockSize = 0;
p->numThreadsMax = 0;
+ p->numThreadGroups = 0;
p->expectedDataSize = (UInt64)(Int64)-1;
p->inStream = NULL;
@@ -429,6 +449,8 @@
unsigned i;
SRes res = SZ_OK;
+ // printf("\n====== MtCoder_Code : \n");
+
if (numThreads > MTCODER_THREADS_MAX)
numThreads = MTCODER_THREADS_MAX;
numBlocksMax = MTCODER_GET_NUM_BLOCKS_FROM_THREADS(numThreads);
@@ -492,11 +514,22 @@
p->numStartedThreadsLimit = numThreads;
p->numStartedThreads = 0;
+ ThreadNextGroup_Init(&p->nextGroup, p->numThreadGroups, 0); // startGroup
// for (i = 0; i < numThreads; i++)
{
+ // here we create new thread for first block.
+ // And each new thread will create another new thread after block reading
+ // until numStartedThreadsLimit is reached.
CMtCoderThread *nextThread = &p->threads[p->numStartedThreads++];
- RINOK(MtCoderThread_CreateAndStart(nextThread))
+ {
+ const SRes res2 = MtCoderThread_CreateAndStart(nextThread
+#ifdef _WIN32
+ , p
+#endif
+ );
+ RINOK(res2)
+ }
}
RINOK_THREAD(Event_Set(&p->readEvent))
@@ -513,9 +546,9 @@
RINOK_THREAD(Event_Wait(&p->writeEvents[bi]))
{
- const CMtCoderBlock *block = &p->blocks[bi];
- unsigned bufIndex = block->bufIndex;
- BoolInt finished = block->finished;
+ const CMtCoderBlock * const block = &p->blocks[bi];
+ const unsigned bufIndex = block->bufIndex;
+ const BoolInt finished = block->finished;
if (res == SZ_OK && block->res != SZ_OK)
res = block->res;
@@ -545,7 +578,7 @@
}
#else
{
- WRes wres = Event_Wait(&p->finishedEvent);
+ const WRes wres = Event_Wait(&p->finishedEvent);
res = MY_SRes_HRESULT_FROM_WRes(wres);
}
#endif
diff -Nru 7zip-24.09+dfsg/C/MtCoder.h 7zip-25.00+dfsg/C/MtCoder.h
--- 7zip-24.09+dfsg/C/MtCoder.h 2023-04-13 10:00:00.000000000 +0200
+++ 7zip-25.00+dfsg/C/MtCoder.h 2025-05-15 08:00:00.000000000 +0200
@@ -1,5 +1,5 @@
/* MtCoder.h -- Multi-thread Coder
-2023-04-13 : Igor Pavlov : Public domain */
+: Igor Pavlov : Public domain */
#ifndef ZIP7_INC_MT_CODER_H
#define ZIP7_INC_MT_CODER_H
@@ -16,7 +16,7 @@
#ifndef Z7_ST
#define MTCODER_GET_NUM_BLOCKS_FROM_THREADS(numThreads) ((numThreads) + (numThreads) / 8 + 1)
- #define MTCODER_THREADS_MAX 64
+ #define MTCODER_THREADS_MAX 256
#define MTCODER_BLOCKS_MAX (MTCODER_GET_NUM_BLOCKS_FROM_THREADS(MTCODER_THREADS_MAX) + 3)
#else
#define MTCODER_THREADS_MAX 1
@@ -77,6 +77,7 @@
size_t blockSize; /* size of input block */
unsigned numThreadsMax;
+ unsigned numThreadGroups;
UInt64 expectedDataSize;
ISeqInStreamPtr inStream;
@@ -125,6 +126,8 @@
CMtProgress mtProgress;
CMtCoderBlock blocks[MTCODER_BLOCKS_MAX];
CMtCoderThread threads[MTCODER_THREADS_MAX];
+
+ CThreadNextGroup nextGroup;
} CMtCoder;
diff -Nru 7zip-24.09+dfsg/C/Sha512.c 7zip-25.00+dfsg/C/Sha512.c
--- 7zip-24.09+dfsg/C/Sha512.c 2024-11-09 11:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/C/Sha512.c 2024-12-03 12:00:00.000000000 +0100
@@ -439,26 +439,78 @@
+// #define Z7_SHA512_PROBE_DEBUG // for debug
-#if defined(_WIN32) && defined(Z7_COMPILER_SHA512_SUPPORTED) \
- && defined(MY_CPU_ARM64) // we can disable this check to debug in x64
+#if defined(Z7_SHA512_PROBE_DEBUG) || defined(Z7_COMPILER_SHA512_SUPPORTED)
-#if 1 // 0 for debug
+#if defined(Z7_SHA512_PROBE_DEBUG) \
+ || defined(_WIN32) && defined(MY_CPU_ARM64)
+#ifndef Z7_SHA512_USE_PROBE
+#define Z7_SHA512_USE_PROBE
+#endif
+#endif
-#include "7zWindows.h"
-// #include <stdio.h>
-#if 0 && defined(MY_CPU_X86_OR_AMD64)
-#include <intrin.h> // for debug : for __ud2()
+#ifdef Z7_SHA512_USE_PROBE
+
+#ifdef Z7_SHA512_PROBE_DEBUG
+#include <stdio.h>
+#define PRF(x) x
+#else
+#define PRF(x)
#endif
-BoolInt CPU_IsSupported_SHA512(void)
+#if 0 || !defined(_MSC_VER) // 1 || : for debug LONGJMP mode
+// MINGW doesn't support __try. So we use signal() / longjmp().
+// Note: signal() / longjmp() probably is not thread-safe.
+// So we must call Sha512Prepare() from main thread at program start.
+#ifndef Z7_SHA512_USE_LONGJMP
+#define Z7_SHA512_USE_LONGJMP
+#endif
+#endif
+
+#ifdef Z7_SHA512_USE_LONGJMP
+#include <signal.h>
+#include <setjmp.h>
+static jmp_buf g_Sha512_jmp_buf;
+// static int g_Sha512_Unsupported;
+
+#if defined(__GNUC__) && (__GNUC__ >= 8) \
+ || defined(__clang__) && (__clang_major__ >= 3)
+ __attribute__((noreturn))
+#endif
+static void Z7_CDECL Sha512_signal_Handler(int v)
{
+ PRF(printf("======== Sha512_signal_Handler = %x\n", (unsigned)v);)
+ // g_Sha512_Unsupported = 1;
+ longjmp(g_Sha512_jmp_buf, 1);
+}
+#endif // Z7_SHA512_USE_LONGJMP
+
+
+#if defined(_WIN32)
+#include "7zWindows.h"
+#endif
+
#if defined(MY_CPU_ARM64)
+// #define Z7_SHA512_USE_SIMPLIFIED_PROBE // for debug
+#endif
+
+#ifdef Z7_SHA512_USE_SIMPLIFIED_PROBE
+#include <arm_neon.h>
+#if defined(__clang__)
+ __attribute__((__target__("sha3")))
+#elif !defined(_MSC_VER)
+ __attribute__((__target__("arch=armv8.2-a+sha3")))
+#endif
+#endif
+static BoolInt CPU_IsSupported_SHA512_Probe(void)
+{
+ PRF(printf("\n== CPU_IsSupported_SHA512_Probe\n");)
+#if defined(_WIN32) && defined(MY_CPU_ARM64)
// we have no SHA512 flag for IsProcessorFeaturePresent() still.
if (!CPU_IsSupported_CRYPTO())
return False;
-#endif
- // printf("\nCPU_IsSupported_SHA512\n");
+ PRF(printf("==== Registry check\n");)
{
// we can't read ID_AA64ISAR0_EL1 register from application.
// but ID_AA64ISAR0_EL1 register is mapped to "CP 4030" registry value.
@@ -486,6 +538,7 @@
// 2 : SHA256 and SHA512 implemented
}
}
+#endif // defined(_WIN32) && defined(MY_CPU_ARM64)
#if 1 // 0 for debug to disable SHA512 PROBE code
@@ -509,59 +562,97 @@
Are there any ways to fix the problems with arm64-wine and x64-SDE cases?
*/
- // printf("\n========== CPU_IsSupported_SHA512 PROBE ========\n");
+ PRF(printf("==== CPU_IsSupported_SHA512 PROBE\n");)
{
+ BoolInt isSupported = False;
+#ifdef Z7_SHA512_USE_LONGJMP
+ void (Z7_CDECL *signal_prev)(int);
+ /*
+ if (g_Sha512_Unsupported)
+ {
+ PRF(printf("==== g_Sha512_Unsupported\n");)
+ return False;
+ }
+ */
+ printf("====== signal(SIGILL)\n");
+ signal_prev = signal(SIGILL, Sha512_signal_Handler);
+ if (signal_prev == SIG_ERR)
+ {
+ PRF(printf("====== signal fail\n");)
+ return False;
+ }
+ // PRF(printf("==== signal_prev = %p\n", (void *)signal_prev);)
+ // docs: Before the specified function is executed,
+ // the value of func is set to SIG_DFL.
+ // So we can exit if (setjmp(g_Sha512_jmp_buf) != 0).
+ PRF(printf("====== setjmp\n");)
+ if (!setjmp(g_Sha512_jmp_buf))
+#else // Z7_SHA512_USE_LONGJMP
+
+#ifdef _MSC_VER
#ifdef __clang_major__
#pragma GCC diagnostic ignored "-Wlanguage-extension-token"
#endif
__try
+#endif
+#endif // Z7_SHA512_USE_LONGJMP
+
{
-#if 0 // 1 : for debug (reduced version to detect sha512)
+#if defined(Z7_COMPILER_SHA512_SUPPORTED)
+#ifdef Z7_SHA512_USE_SIMPLIFIED_PROBE
+ // simplified sha512 check for arm64:
const uint64x2_t a = vdupq_n_u64(1);
const uint64x2_t b = vsha512hq_u64(a, a, a);
+ PRF(printf("======== vsha512hq_u64 probe\n");)
if ((UInt32)vgetq_lane_u64(b, 0) == 0x11800002)
- return True;
#else
MY_ALIGN(16)
UInt64 temp[SHA512_NUM_DIGEST_WORDS + SHA512_NUM_BLOCK_WORDS];
memset(temp, 0x5a, sizeof(temp));
-#if 0 && defined(MY_CPU_X86_OR_AMD64)
- __ud2(); // for debug : that exception is not problem for SDE
-#endif
-#if 1
+ PRF(printf("======== Sha512_UpdateBlocks_HW\n");)
Sha512_UpdateBlocks_HW(temp,
(const Byte *)(const void *)(temp + SHA512_NUM_DIGEST_WORDS), 1);
- // printf("\n==== t = %x\n", (UInt32)temp[0]);
+ // PRF(printf("======== t = %x\n", (UInt32)temp[0]);)
if ((UInt32)temp[0] == 0xa33cfdf7)
+#endif
{
- // printf("\n=== PROBE SHA512: SHA512 supported\n");
- return True;
+ PRF(printf("======== PROBE SHA512: SHA512 is supported\n");)
+ isSupported = True;
}
+#else // Z7_COMPILER_SHA512_SUPPORTED
+ // for debug : we generate bad instrction or raise exception.
+ // __except() doesn't catch raise() calls.
+#ifdef Z7_SHA512_USE_LONGJMP
+ PRF(printf("====== raise(SIGILL)\n");)
+ raise(SIGILL);
+#else
+#if defined(_MSC_VER) && defined(MY_CPU_X86)
+ __asm ud2
#endif
-#endif
+#endif // Z7_SHA512_USE_LONGJMP
+#endif // Z7_COMPILER_SHA512_SUPPORTED
}
+
+#ifdef Z7_SHA512_USE_LONGJMP
+ PRF(printf("====== restore signal SIGILL\n");)
+ signal(SIGILL, signal_prev);
+#elif _MSC_VER
__except (EXCEPTION_EXECUTE_HANDLER)
{
- // printf("\n==== CPU_IsSupported_SHA512 EXCEPTION_EXECUTE_HANDLER\n");
+ PRF(printf("==== CPU_IsSupported_SHA512 __except(EXCEPTION_EXECUTE_HANDLER)\n");)
}
+#endif
+ PRF(printf("== return (sha512 supported) = %d\n", isSupported);)
+ return isSupported;
}
- return False;
#else
// without SHA512 PROBE code
return True;
#endif
-
}
-#else
-
-BoolInt CPU_IsSupported_SHA512(void)
-{
- return False;
-}
-
-#endif
-#endif // WIN32 arm64
+#endif // Z7_SHA512_USE_PROBE
+#endif // defined(Z7_SHA512_PROBE_DEBUG) || defined(Z7_COMPILER_SHA512_SUPPORTED)
void Sha512Prepare(void)
@@ -570,10 +661,10 @@
SHA512_FUNC_UPDATE_BLOCKS f, f_hw;
f = Sha512_UpdateBlocks;
f_hw = NULL;
-#ifdef MY_CPU_X86_OR_AMD64
- if (CPU_IsSupported_SHA512()
- && CPU_IsSupported_AVX2()
- )
+#ifdef Z7_SHA512_USE_PROBE
+ if (CPU_IsSupported_SHA512_Probe())
+#elif defined(MY_CPU_X86_OR_AMD64)
+ if (CPU_IsSupported_SHA512() && CPU_IsSupported_AVX2())
#else
if (CPU_IsSupported_SHA512())
#endif
@@ -583,6 +674,8 @@
}
g_SHA512_FUNC_UPDATE_BLOCKS = f;
g_SHA512_FUNC_UPDATE_BLOCKS_HW = f_hw;
+#elif defined(Z7_SHA512_PROBE_DEBUG)
+ CPU_IsSupported_SHA512_Probe(); // for debug
#endif
}
diff -Nru 7zip-24.09+dfsg/C/Sort.c 7zip-25.00+dfsg/C/Sort.c
--- 7zip-24.09+dfsg/C/Sort.c 2014-04-05 14:00:00.000000000 +0200
+++ 7zip-25.00+dfsg/C/Sort.c 2025-01-08 10:00:00.000000000 +0100
@@ -1,141 +1,268 @@
/* Sort.c -- Sort functions
-2014-04-05 : Igor Pavlov : Public domain */
+: Igor Pavlov : Public domain */
#include "Precomp.h"
#include "Sort.h"
+#include "CpuArch.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; }
+#if ( (defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))) \
+ || (defined(__clang__) && Z7_has_builtin(__builtin_prefetch)) \
+ )
+// the code with prefetch is slow for small arrays on x86.
+// So we disable prefetch for x86.
+#ifndef MY_CPU_X86
+ // #pragma message("Z7_PREFETCH : __builtin_prefetch")
+ #define Z7_PREFETCH(a) __builtin_prefetch((a))
+#endif
-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;
- }
+#elif defined(_WIN32) // || defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "7zWindows.h"
+
+// NOTE: CLANG/GCC/MSVC can define different values for _MM_HINT_T0 / PF_TEMPORAL_LEVEL_1.
+// For example, clang-cl can generate "prefetcht2" instruction for
+// PreFetchCacheLine(PF_TEMPORAL_LEVEL_1) call.
+// But we want to generate "prefetcht0" instruction.
+// So for CLANG/GCC we must use __builtin_prefetch() in code branch above
+// instead of PreFetchCacheLine() / _mm_prefetch().
+
+// New msvc-x86 compiler generates "prefetcht0" instruction for PreFetchCacheLine() call.
+// But old x86 cpus don't support "prefetcht0".
+// So we will use PreFetchCacheLine(), only if we are sure that
+// generated instruction is supported by all cpus of that isa.
+#if defined(MY_CPU_AMD64) \
+ || defined(MY_CPU_ARM64) \
+ || defined(MY_CPU_IA64)
+// we need to use additional braces for (a) in PreFetchCacheLine call, because
+// PreFetchCacheLine macro doesn't use braces:
+// #define PreFetchCacheLine(l, a) _mm_prefetch((CHAR CONST *) a, l)
+ // #pragma message("Z7_PREFETCH : PreFetchCacheLine")
+ #define Z7_PREFETCH(a) PreFetchCacheLine(PF_TEMPORAL_LEVEL_1, (a))
+#endif
+
+#endif // _WIN32
+
+
+#define PREFETCH_NO(p,k,s,size)
+
+#ifndef Z7_PREFETCH
+ #define SORT_PREFETCH(p,k,s,size)
+#else
+
+// #define PREFETCH_LEVEL 2 // use it if cache line is 32-bytes
+#define PREFETCH_LEVEL 3 // it is fast for most cases (64-bytes cache line prefetch)
+// #define PREFETCH_LEVEL 4 // it can be faster for big array (128-bytes prefetch)
+
+#if PREFETCH_LEVEL == 0
+
+ #define SORT_PREFETCH(p,k,s,size)
+
+#else // PREFETCH_LEVEL != 0
+
+/*
+if defined(USE_PREFETCH_FOR_ALIGNED_ARRAY)
+ we prefetch one value per cache line.
+ Use it if array is aligned for cache line size (64 bytes)
+ or if array is small (less than L1 cache size).
+
+if !defined(USE_PREFETCH_FOR_ALIGNED_ARRAY)
+ we perfetch all cache lines that can be required.
+ it can be faster for big unaligned arrays.
+*/
+ #define USE_PREFETCH_FOR_ALIGNED_ARRAY
+
+// s == k * 2
+#if 0 && PREFETCH_LEVEL <= 3 && defined(MY_CPU_X86_OR_AMD64)
+ // x86 supports (lea r1*8+offset)
+ #define PREFETCH_OFFSET(k,s) ((s) << PREFETCH_LEVEL)
+#else
+ #define PREFETCH_OFFSET(k,s) ((k) << (PREFETCH_LEVEL + 1))
+#endif
+
+#if 1 && PREFETCH_LEVEL <= 3 && defined(USE_PREFETCH_FOR_ALIGNED_ARRAY)
+ #define PREFETCH_ADD_OFFSET 0
+#else
+ // last offset that can be reqiured in PREFETCH_LEVEL step:
+ #define PREFETCH_RANGE ((2 << PREFETCH_LEVEL) - 1)
+ #define PREFETCH_ADD_OFFSET PREFETCH_RANGE / 2
+#endif
+
+#if PREFETCH_LEVEL <= 3
+
+#ifdef USE_PREFETCH_FOR_ALIGNED_ARRAY
+ #define SORT_PREFETCH(p,k,s,size) \
+ { const size_t s2 = PREFETCH_OFFSET(k,s) + PREFETCH_ADD_OFFSET; \
+ if (s2 <= size) { \
+ Z7_PREFETCH((p + s2)); \
+ }}
+#else /* for unaligned array */
+ #define SORT_PREFETCH(p,k,s,size) \
+ { const size_t s2 = PREFETCH_OFFSET(k,s) + PREFETCH_RANGE; \
+ if (s2 <= size) { \
+ Z7_PREFETCH((p + s2 - PREFETCH_RANGE)); \
+ Z7_PREFETCH((p + s2)); \
+ }}
+#endif
+
+#else // PREFETCH_LEVEL > 3
+
+#ifdef USE_PREFETCH_FOR_ALIGNED_ARRAY
+ #define SORT_PREFETCH(p,k,s,size) \
+ { const size_t s2 = PREFETCH_OFFSET(k,s) + PREFETCH_RANGE - 16 / 2; \
+ if (s2 <= size) { \
+ Z7_PREFETCH((p + s2 - 16)); \
+ Z7_PREFETCH((p + s2)); \
+ }}
+#else /* for unaligned array */
+ #define SORT_PREFETCH(p,k,s,size) \
+ { const size_t s2 = PREFETCH_OFFSET(k,s) + PREFETCH_RANGE; \
+ if (s2 <= size) { \
+ Z7_PREFETCH((p + s2 - PREFETCH_RANGE)); \
+ Z7_PREFETCH((p + s2 - PREFETCH_RANGE / 2)); \
+ Z7_PREFETCH((p + s2)); \
+ }}
+#endif
+
+#endif // PREFETCH_LEVEL > 3
+#endif // PREFETCH_LEVEL != 0
+#endif // Z7_PREFETCH
+
+
+#if defined(MY_CPU_ARM64) \
+ /* || defined(MY_CPU_AMD64) */ \
+ /* || defined(MY_CPU_ARM) && !defined(_MSC_VER) */
+ // we want to use cmov, if cmov is very fast:
+ // - this cmov version is slower for clang-x64.
+ // - this cmov version is faster for gcc-arm64 for some fast arm64 cpus.
+ #define Z7_FAST_CMOV_SUPPORTED
+#endif
+
+#ifdef Z7_FAST_CMOV_SUPPORTED
+ // we want to use cmov here, if cmov is fast: new arm64 cpus.
+ // we want the compiler to use conditional move for this branch
+ #define GET_MAX_VAL(n0, n1, max_val_slow) if (n0 < n1) n0 = n1;
+#else
+ // use this branch, if cpu doesn't support fast conditional move.
+ // it uses slow array access reading:
+ #define GET_MAX_VAL(n0, n1, max_val_slow) n0 = max_val_slow;
+#endif
+
+#define HeapSortDown(p, k, size, temp, macro_prefetch) \
+{ \
+ for (;;) { \
+ UInt32 n0, n1; \
+ size_t s = k * 2; \
+ if (s >= size) { \
+ if (s == size) { \
+ n0 = p[s]; \
+ p[k] = n0; \
+ if (temp < n0) k = s; \
+ } \
+ break; \
+ } \
+ n0 = p[k * 2]; \
+ n1 = p[k * 2 + 1]; \
+ s += n0 < n1; \
+ GET_MAX_VAL(n0, n1, p[s]) \
+ if (temp >= n0) break; \
+ macro_prefetch(p, k, s, size) \
+ p[k] = n0; \
+ k = s; \
+ } \
+ p[k] = temp; \
}
-void HeapSort64(UInt64 *p, size_t size)
+
+/*
+stage-1 : O(n) :
+ we generate intermediate partially sorted binary tree:
+ p[0] : it's additional item for better alignment of tree structure in memory.
+ p[1]
+ p[2] p[3]
+ p[4] p[5] p[6] p[7]
+ ...
+ p[x] >= p[x * 2]
+ p[x] >= p[x * 2 + 1]
+
+stage-2 : O(n)*log2(N):
+ we move largest item p[0] from head of tree to the end of array
+ and insert last item to sorted binary tree.
+*/
+
+// (p) must be aligned for cache line size (64-bytes) for best performance
+
+void Z7_FASTCALL HeapSort(UInt32 *p, size_t size)
{
- if (size <= 1)
+ if (size < 2)
return;
- p--;
+ if (size == 2)
{
- 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)
+ const UInt32 a0 = p[0];
+ const UInt32 a1 = p[1];
+ const unsigned k = a1 < a0;
+ p[k] = a0;
+ p[k ^ 1] = a1;
+ return;
}
{
- UInt64 temp = p[size];
- p[size] = p[1];
- if (size > 2 && p[2] < temp)
+ // stage-1 : O(n)
+ // we transform array to partially sorted binary tree.
+ size_t i = --size / 2;
+ // (size) now is the index of the last item in tree,
+ // if (i)
+ {
+ do
+ {
+ const UInt32 temp = p[i];
+ size_t k = i;
+ HeapSortDown(p, k, size, temp, PREFETCH_NO)
+ }
+ while (--i);
+ }
{
- p[1] = p[2];
- p[2] = temp;
+ const UInt32 temp = p[0];
+ const UInt32 a1 = p[1];
+ if (temp < a1)
+ {
+ size_t k = 1;
+ p[0] = a1;
+ HeapSortDown(p, k, size, temp, PREFETCH_NO)
+ }
}
- 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)
+ if (size < 3)
+ {
+ // size == 2
+ const UInt32 a0 = p[0];
+ p[0] = p[2];
+ p[2] = a0;
return;
- p--;
+ }
+ if (size != 3)
{
- size_t i = size / 2;
+ // stage-2 : O(size) * log2(size):
+ // we move largest item p[0] from head to the end of array,
+ // and insert last item to sorted binary tree.
do
{
- UInt32 temp = p[i];
- HeapSortRefDown(p, vals, i, size, temp);
+ const UInt32 temp = p[size];
+ size_t k = p[2] < p[3] ? 3 : 2;
+ p[size--] = p[0];
+ p[0] = p[1];
+ p[1] = p[k];
+ HeapSortDown(p, k, size, temp, SORT_PREFETCH) // PREFETCH_NO
}
- while (--i != 0);
+ while (size != 3);
}
- do
{
- UInt32 temp = p[size];
- p[size--] = p[1];
- HeapSortRefDown(p, vals, 1, size, temp);
+ const UInt32 a2 = p[2];
+ const UInt32 a3 = p[3];
+ const size_t k = a2 < a3;
+ p[2] = p[1];
+ p[3] = p[0];
+ p[k] = a3;
+ p[k ^ 1] = a2;
}
- while (size > 1);
}
-*/
diff -Nru 7zip-24.09+dfsg/C/Sort.h 7zip-25.00+dfsg/C/Sort.h
--- 7zip-24.09+dfsg/C/Sort.h 2023-03-05 19:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/C/Sort.h 2025-01-06 10:00:00.000000000 +0100
@@ -1,5 +1,5 @@
/* Sort.h -- Sort functions
-2023-03-05 : Igor Pavlov : Public domain */
+: Igor Pavlov : Public domain */
#ifndef ZIP7_INC_SORT_H
#define ZIP7_INC_SORT_H
@@ -8,10 +8,7 @@
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); */
+void Z7_FASTCALL HeapSort(UInt32 *p, size_t size);
EXTERN_C_END
diff -Nru 7zip-24.09+dfsg/C/Threads.c 7zip-25.00+dfsg/C/Threads.c
--- 7zip-24.09+dfsg/C/Threads.c 2024-03-28 18:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/C/Threads.c 2025-07-05 11:00:00.000000000 +0200
@@ -1,5 +1,5 @@
/* Threads.c -- multithreading library
-2024-03-28 : Igor Pavlov : Public domain */
+: Igor Pavlov : Public domain */
#include "Precomp.h"
@@ -59,6 +59,100 @@
return (res != 0 ? res : res2);
}
+typedef struct MY_PROCESSOR_NUMBER {
+ WORD Group;
+ BYTE Number;
+ BYTE Reserved;
+} MY_PROCESSOR_NUMBER, *MY_PPROCESSOR_NUMBER;
+
+typedef struct MY_GROUP_AFFINITY {
+#if defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION < 100000)
+ // KAFFINITY is not defined in old mingw
+ ULONG_PTR
+#else
+ KAFFINITY
+#endif
+ Mask;
+ WORD Group;
+ WORD Reserved[3];
+} MY_GROUP_AFFINITY, *MY_PGROUP_AFFINITY;
+
+typedef BOOL (WINAPI *Func_SetThreadGroupAffinity)(
+ HANDLE hThread,
+ CONST MY_GROUP_AFFINITY *GroupAffinity,
+ MY_PGROUP_AFFINITY PreviousGroupAffinity);
+
+typedef BOOL (WINAPI *Func_GetThreadGroupAffinity)(
+ HANDLE hThread,
+ MY_PGROUP_AFFINITY GroupAffinity);
+
+typedef BOOL (WINAPI *Func_GetProcessGroupAffinity)(
+ HANDLE hProcess,
+ PUSHORT GroupCount,
+ PUSHORT GroupArray);
+
+Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION
+
+#if 0
+#include <stdio.h>
+#define PRF(x) x
+/*
+--
+ before call of SetThreadGroupAffinity()
+ GetProcessGroupAffinity return one group.
+ after call of SetThreadGroupAffinity():
+ GetProcessGroupAffinity return more than group,
+ if SetThreadGroupAffinity() was to another group.
+--
+ GetProcessAffinityMask MS DOCs:
+ {
+ If the calling process contains threads in multiple groups,
+ the function returns zero for both affinity masks.
+ }
+ but tests in win10 with 2 groups (less than 64 cores total):
+ GetProcessAffinityMask() still returns non-zero affinity masks
+ even after SetThreadGroupAffinity() calls.
+*/
+static void PrintProcess_Info()
+{
+ {
+ const
+ Func_GetProcessGroupAffinity fn_GetProcessGroupAffinity =
+ (Func_GetProcessGroupAffinity) Z7_CAST_FUNC_C GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")),
+ "GetProcessGroupAffinity");
+ if (fn_GetProcessGroupAffinity)
+ {
+ unsigned i;
+ USHORT GroupCounts[64];
+ USHORT GroupCount = Z7_ARRAY_SIZE(GroupCounts);
+ BOOL boolRes = fn_GetProcessGroupAffinity(GetCurrentProcess(),
+ &GroupCount, GroupCounts);
+ printf("\n====== GetProcessGroupAffinity : "
+ "boolRes=%u GroupCounts = %u :",
+ boolRes, (unsigned)GroupCount);
+ for (i = 0; i < GroupCount; i++)
+ printf(" %u", GroupCounts[i]);
+ printf("\n");
+ }
+ }
+ {
+ DWORD_PTR processAffinityMask, systemAffinityMask;
+ if (GetProcessAffinityMask(GetCurrentProcess(), &processAffinityMask, &systemAffinityMask))
+ {
+ PRF(printf("\n====== GetProcessAffinityMask : "
+ ": processAffinityMask=%x, systemAffinityMask=%x\n",
+ (UInt32)processAffinityMask, (UInt32)systemAffinityMask);)
+ }
+ else
+ printf("\n==GetProcessAffinityMask FAIL");
+ }
+}
+#else
+#ifndef USE_THREADS_CreateThread
+// #define PRF(x)
+#endif
+#endif
+
WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param)
{
/* Windows Me/98/95: threadId parameter may not be NULL in _beginthreadex/CreateThread functions */
@@ -72,7 +166,43 @@
unsigned threadId;
*p = (HANDLE)(_beginthreadex(NULL, 0, func, param, 0, &threadId));
-
+
+#if 0 // 1 : for debug
+ {
+ DWORD_PTR prevMask;
+ DWORD_PTR affinity = 1 << 0;
+ prevMask = SetThreadAffinityMask(*p, (DWORD_PTR)affinity);
+ prevMask = prevMask;
+ }
+#endif
+#if 0 // 1 : for debug
+ {
+ /* win10: new thread will be created in same group that is assigned to parent thread
+ but affinity mask will contain all allowed threads of that group,
+ even if affinity mask of parent group is not full
+ win11: what group it will be created, if we have set
+ affinity of parent thread with ThreadGroupAffinity?
+ */
+ const
+ Func_GetThreadGroupAffinity fn =
+ (Func_GetThreadGroupAffinity) Z7_CAST_FUNC_C GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")),
+ "GetThreadGroupAffinity");
+ if (fn)
+ {
+ // BOOL wres2;
+ MY_GROUP_AFFINITY groupAffinity;
+ memset(&groupAffinity, 0, sizeof(groupAffinity));
+ /* wres2 = */ fn(*p, &groupAffinity);
+ PRF(printf("\n==Thread_Create cur = %6u GetThreadGroupAffinity(): "
+ "wres2_BOOL = %u, group=%u mask=%x\n",
+ GetCurrentThreadId(),
+ wres2,
+ groupAffinity.Group,
+ (UInt32)groupAffinity.Mask);)
+ }
+ }
+#endif
+
#endif
/* maybe we must use errno here, but probably GetLastError() is also OK. */
@@ -110,7 +240,84 @@
*/
}
{
- DWORD prevSuspendCount = ResumeThread(h);
+ const DWORD prevSuspendCount = ResumeThread(h);
+ /* ResumeThread() returns:
+ 0 : was_not_suspended
+ 1 : was_resumed
+ -1 : error
+ */
+ if (prevSuspendCount == (DWORD)-1)
+ wres = GetError();
+ }
+ }
+
+ /* maybe we must use errno here, but probably GetLastError() is also OK. */
+ return wres;
+
+ #endif
+}
+
+
+WRes Thread_Create_With_Group(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, unsigned group, CAffinityMask affinityMask)
+{
+#ifdef USE_THREADS_CreateThread
+
+ UNUSED_VAR(group)
+ UNUSED_VAR(affinityMask)
+ return Thread_Create(p, func, param);
+
+#else
+
+ /* Windows Me/98/95: threadId parameter may not be NULL in _beginthreadex/CreateThread functions */
+ HANDLE h;
+ WRes wres;
+ unsigned threadId;
+ h = (HANDLE)(_beginthreadex(NULL, 0, func, param, CREATE_SUSPENDED, &threadId));
+ *p = h;
+ wres = HandleToWRes(h);
+ if (h)
+ {
+ // PrintProcess_Info();
+ {
+ const
+ Func_SetThreadGroupAffinity fn =
+ (Func_SetThreadGroupAffinity) Z7_CAST_FUNC_C GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")),
+ "SetThreadGroupAffinity");
+ if (fn)
+ {
+ // WRes wres2;
+ MY_GROUP_AFFINITY groupAffinity, prev_groupAffinity;
+ memset(&groupAffinity, 0, sizeof(groupAffinity));
+ // groupAffinity.Mask must use only bits that supported by current group
+ // (groupAffinity.Mask = 0) means all allowed bits
+ groupAffinity.Mask = affinityMask;
+ groupAffinity.Group = (WORD)group;
+ // wres2 =
+ fn(h, &groupAffinity, &prev_groupAffinity);
+ /*
+ if (groupAffinity.Group == prev_groupAffinity.Group)
+ wres2 = wres2;
+ else
+ wres2 = wres2;
+ if (wres2 == 0)
+ {
+ wres2 = GetError();
+ PRF(printf("\n==SetThreadGroupAffinity error: %u\n", wres2);)
+ }
+ else
+ {
+ PRF(printf("\n==Thread_Create_With_Group::SetThreadGroupAffinity()"
+ " threadId = %6u"
+ " group=%u mask=%x\n",
+ threadId,
+ prev_groupAffinity.Group,
+ (UInt32)prev_groupAffinity.Mask);)
+ }
+ */
+ }
+ }
+ {
+ const DWORD prevSuspendCount = ResumeThread(h);
/* ResumeThread() returns:
0 : was_not_suspended
1 : was_resumed
@@ -297,6 +504,13 @@
return Thread_Create_With_CpuSet(p, func, param, NULL);
}
+/*
+WRes Thread_Create_With_Group(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, unsigned group, CAffinityMask affinity)
+{
+ UNUSED_VAR(group)
+ return Thread_Create_With_Affinity(p, func, param, affinity);
+}
+*/
WRes Thread_Create_With_Affinity(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, CAffinityMask affinity)
{
@@ -577,5 +791,22 @@
return AutoResetEvent_CreateNotSignaled(p);
}
+void ThreadNextGroup_Init(CThreadNextGroup *p, UInt32 numGroups, UInt32 startGroup)
+{
+ // printf("\n====== ThreadNextGroup_Init numGroups = %x: startGroup=%x\n", numGroups, startGroup);
+ if (numGroups == 0)
+ numGroups = 1;
+ p->NumGroups = numGroups;
+ p->NextGroup = startGroup % numGroups;
+}
+
+
+UInt32 ThreadNextGroup_GetNext(CThreadNextGroup *p)
+{
+ const UInt32 next = p->NextGroup;
+ p->NextGroup = (next + 1) % p->NumGroups;
+ return next;
+}
+
#undef PRF
#undef Print
diff -Nru 7zip-24.09+dfsg/C/Threads.h 7zip-25.00+dfsg/C/Threads.h
--- 7zip-24.09+dfsg/C/Threads.h 2024-03-28 18:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/C/Threads.h 2025-06-30 16:00:00.000000000 +0200
@@ -1,5 +1,5 @@
/* Threads.h -- multithreading library
-2024-03-28 : Igor Pavlov : Public domain */
+: Igor Pavlov : Public domain */
#ifndef ZIP7_INC_THREADS_H
#define ZIP7_INC_THREADS_H
@@ -140,12 +140,22 @@
WRes Thread_Wait_Close(CThread *p);
#ifdef _WIN32
+WRes Thread_Create_With_Group(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, unsigned group, CAffinityMask affinityMask);
#define Thread_Create_With_CpuSet(p, func, param, cs) \
Thread_Create_With_Affinity(p, func, param, *cs)
#else
WRes Thread_Create_With_CpuSet(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, const CCpuSet *cpuSet);
#endif
+typedef struct
+{
+ unsigned NumGroups;
+ unsigned NextGroup;
+} CThreadNextGroup;
+
+void ThreadNextGroup_Init(CThreadNextGroup *p, unsigned numGroups, unsigned startGroup);
+unsigned ThreadNextGroup_GetNext(CThreadNextGroup *p);
+
#ifdef _WIN32
diff -Nru 7zip-24.09+dfsg/C/Util/Lzma/LzmaUtil.dsp 7zip-25.00+dfsg/C/Util/Lzma/LzmaUtil.dsp
--- 7zip-24.09+dfsg/C/Util/Lzma/LzmaUtil.dsp 2023-04-04 22:00:00.000000000 +0200
+++ 7zip-25.00+dfsg/C/Util/Lzma/LzmaUtil.dsp 2025-02-05 07:00:00.000000000 +0100
@@ -122,6 +122,10 @@
# End Source File
# Begin Source File
+SOURCE=..\..\CpuArch.c
+# End Source File
+# Begin Source File
+
SOURCE=..\..\CpuArch.h
# End Source File
# Begin Source File
diff -Nru 7zip-24.09+dfsg/C/Util/LzmaLib/LzmaLib.dsp 7zip-25.00+dfsg/C/Util/LzmaLib/LzmaLib.dsp
--- 7zip-24.09+dfsg/C/Util/LzmaLib/LzmaLib.dsp 2023-04-04 15:00:00.000000000 +0200
+++ 7zip-25.00+dfsg/C/Util/LzmaLib/LzmaLib.dsp 2025-02-05 07:00:00.000000000 +0100
@@ -43,7 +43,7 @@
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LZMALIB_EXPORTS" /YX /FD /c
-# ADD CPP /nologo /Gr /MT /W3 /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LZMALIB_EXPORTS" /FD /c
+# ADD CPP /nologo /Gr /MT /W4 /WX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LZMALIB_EXPORTS" /FD /c
# SUBTRACT CPP /YX
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
@@ -71,7 +71,7 @@
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LZMALIB_EXPORTS" /YX /FD /GZ /c
-# ADD CPP /nologo /MTd /W3 /Gm /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LZMALIB_EXPORTS" /D "COMPRESS_MF_MT" /FD /GZ /c
+# ADD CPP /nologo /MTd /W4 /WX /Gm /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LZMALIB_EXPORTS" /D "COMPRESS_MF_MT" /FD /GZ /c
# SUBTRACT CPP /YX
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
@@ -128,6 +128,10 @@
# End Source File
# Begin Source File
+SOURCE=..\..\CpuArch.c
+# End Source File
+# Begin Source File
+
SOURCE=..\..\CpuArch.h
# End Source File
# Begin Source File
diff -Nru 7zip-24.09+dfsg/C/XzCrc64Opt.c 7zip-25.00+dfsg/C/XzCrc64Opt.c
--- 7zip-24.09+dfsg/C/XzCrc64Opt.c 2023-12-08 09:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/C/XzCrc64Opt.c 2025-01-03 21:00:00.000000000 +0100
@@ -1,5 +1,5 @@
/* XzCrc64Opt.c -- CRC64 calculation (optimized functions)
-2023-12-08 : Igor Pavlov : Public domain */
+: Igor Pavlov : Public domain */
#include "Precomp.h"
@@ -235,7 +235,7 @@
v = Q32BE(1, w1) ^ Q32BE(0, w0);
v ^= Q32BE(3, d1) ^ Q32BE(2, d0);
#endif
-#elif
+#else
#error Stop_Compiling_Bad_CRC64_NUM_TABLES
#endif
p += Z7_CRC64_NUM_TABLES_USE;
diff -Nru 7zip-24.09+dfsg/C/XzDec.c 7zip-25.00+dfsg/C/XzDec.c
--- 7zip-24.09+dfsg/C/XzDec.c 2024-03-01 07:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/C/XzDec.c 2025-04-30 15:00:00.000000000 +0200
@@ -1,5 +1,5 @@
/* XzDec.c -- Xz Decode
-2024-03-01 : Igor Pavlov : Public domain */
+: Igor Pavlov : Public domain */
#include "Precomp.h"
@@ -59,7 +59,7 @@
for (i = 0; i < limit;)
{
- Byte b = p[i];
+ const unsigned b = p[i];
*value |= (UInt64)(b & 0x7F) << (7 * i++);
if ((b & 0x80) == 0)
return (b == 0 && i != 1) ? 0 : i;
@@ -796,11 +796,10 @@
static BoolInt Xz_CheckFooter(CXzStreamFlags flags, UInt64 indexSize, const Byte *buf)
{
- return indexSize == (((UInt64)GetUi32(buf + 4) + 1) << 2)
- && GetUi32(buf) == CrcCalc(buf + 4, 6)
- && flags == GetBe16(buf + 8)
- && buf[10] == XZ_FOOTER_SIG_0
- && buf[11] == XZ_FOOTER_SIG_1;
+ return indexSize == (((UInt64)GetUi32a(buf + 4) + 1) << 2)
+ && GetUi32a(buf) == CrcCalc(buf + 4, 6)
+ && flags == GetBe16a(buf + 8)
+ && GetUi16a(buf + 10) == (XZ_FOOTER_SIG_0 | (XZ_FOOTER_SIG_1 << 8));
}
#define READ_VARINT_AND_CHECK(buf, pos, size, res) \
@@ -1166,7 +1165,7 @@
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_Final(&p->sha, (Byte *)(void *)p->shaDigest32);
Sha256_Init(&p->sha);
p->crc = CrcUpdate(CRC_INIT_VAL, p->buf, p->indexPreSize);
p->state = XZ_STATE_STREAM_INDEX;
@@ -1241,10 +1240,10 @@
break;
}
{
- Byte digest[XZ_CHECK_SIZE_MAX];
+ UInt32 digest32[XZ_CHECK_SIZE_MAX / 4];
p->state = XZ_STATE_BLOCK_HEADER;
p->pos = 0;
- if (XzCheck_Final(&p->check, digest) && memcmp(digest, p->buf, checkSize) != 0)
+ if (XzCheck_Final(&p->check, (void *)digest32) && memcmp(digest32, p->buf, checkSize) != 0)
return SZ_ERROR_CRC;
if (p->decodeOnlyOneBlock)
{
@@ -1289,12 +1288,12 @@
}
else
{
- Byte digest[SHA256_DIGEST_SIZE];
+ UInt32 digest32[SHA256_DIGEST_SIZE / 4];
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)
+ Sha256_Final(&p->sha, (void *)digest32);
+ if (memcmp(digest32, p->shaDigest32, SHA256_DIGEST_SIZE) != 0)
return SZ_ERROR_CRC;
}
}
@@ -1313,7 +1312,7 @@
const Byte *ptr = p->buf;
p->state = XZ_STATE_STREAM_FOOTER;
p->pos = 0;
- if (CRC_GET_DIGEST(p->crc) != GetUi32(ptr))
+ if (CRC_GET_DIGEST(p->crc) != GetUi32a(ptr))
return SZ_ERROR_CRC;
}
break;
@@ -1343,7 +1342,7 @@
{
if (*src != 0)
{
- if (((UInt32)p->padSize & 3) != 0)
+ if ((unsigned)p->padSize & 3)
return SZ_ERROR_NO_ARCHIVE;
p->pos = 0;
p->state = XZ_STATE_STREAM_HEADER;
diff -Nru 7zip-24.09+dfsg/C/XzEnc.c 7zip-25.00+dfsg/C/XzEnc.c
--- 7zip-24.09+dfsg/C/XzEnc.c 2024-03-01 07:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/C/XzEnc.c 2025-07-04 08:00:00.000000000 +0200
@@ -1,5 +1,5 @@
/* XzEnc.c -- Xz Encode
-2024-03-01 : Igor Pavlov : Public domain */
+: Igor Pavlov : Public domain */
#include "Precomp.h"
@@ -411,6 +411,7 @@
}
}
+Z7_FORCE_INLINE
static void SeqInFilter_Construct(CSeqInFilter *p)
{
p->buf = NULL;
@@ -418,6 +419,7 @@
p->vt.Read = SeqInFilter_Read;
}
+Z7_FORCE_INLINE
static void SeqInFilter_Free(CSeqInFilter *p, ISzAllocPtr alloc)
{
if (p->StateCoder.p)
@@ -507,6 +509,7 @@
void XzProps_Init(CXzProps *p)
{
p->checkId = XZ_CHECK_CRC32;
+ p->numThreadGroups = 0;
p->blockSize = XZ_PROPS_BLOCK_SIZE_AUTO;
p->numBlockThreads_Reduced = -1;
p->numBlockThreads_Max = -1;
@@ -689,6 +692,7 @@
} CLzma2WithFilters;
+Z7_FORCE_INLINE
static void Lzma2WithFilters_Construct(CLzma2WithFilters *p)
{
p->lzma2 = NULL;
@@ -712,6 +716,7 @@
}
+Z7_FORCE_INLINE
static void Lzma2WithFilters_Free(CLzma2WithFilters *p, ISzAllocPtr alloc)
{
#ifdef USE_SUBBLOCK
@@ -1236,6 +1241,7 @@
}
p->mtCoder.numThreadsMax = (unsigned)props->numBlockThreads_Max;
+ p->mtCoder.numThreadGroups = props->numThreadGroups;
p->mtCoder.expectedDataSize = p->expectedDataSize;
RINOK(MtCoder_Code(&p->mtCoder))
diff -Nru 7zip-24.09+dfsg/C/XzEnc.h 7zip-25.00+dfsg/C/XzEnc.h
--- 7zip-24.09+dfsg/C/XzEnc.h 2023-04-13 10:00:00.000000000 +0200
+++ 7zip-25.00+dfsg/C/XzEnc.h 2025-07-02 14:00:00.000000000 +0200
@@ -1,5 +1,5 @@
/* XzEnc.h -- Xz Encode
-2023-04-13 : Igor Pavlov : Public domain */
+: Igor Pavlov : Public domain */
#ifndef ZIP7_INC_XZ_ENC_H
#define ZIP7_INC_XZ_ENC_H
@@ -31,6 +31,7 @@
CLzma2EncProps lzma2Props;
CXzFilterProps filterProps;
unsigned checkId;
+ unsigned numThreadGroups; // 0 : no groups
UInt64 blockSize;
int numBlockThreads_Reduced;
int numBlockThreads_Max;
diff -Nru 7zip-24.09+dfsg/C/Xz.h 7zip-25.00+dfsg/C/Xz.h
--- 7zip-24.09+dfsg/C/Xz.h 2024-01-26 15:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/C/Xz.h 2025-05-03 13:00:00.000000000 +0200
@@ -1,5 +1,5 @@
/* Xz.h - Xz interface
-2024-01-26 : Igor Pavlov : Public domain */
+Igor Pavlov : Public domain */
#ifndef ZIP7_INC_XZ_H
#define ZIP7_INC_XZ_H
@@ -121,6 +121,7 @@
UInt64 startOffset;
} CXzStream;
+#define Xz_CONSTRUCT(p) { (p)->numBlocks = 0; (p)->blocks = NULL; (p)->flags = 0; }
void Xz_Construct(CXzStream *p);
void Xz_Free(CXzStream *p, ISzAllocPtr alloc);
@@ -136,8 +137,13 @@
CXzStream *streams;
} CXzs;
+#define Xzs_CONSTRUCT(p) { (p)->num = 0; (p)->numAllocated = 0; (p)->streams = NULL; }
void Xzs_Construct(CXzs *p);
void Xzs_Free(CXzs *p, ISzAllocPtr alloc);
+/*
+Xzs_ReadBackward() must be called for empty CXzs object.
+Xzs_ReadBackward() can return non empty object with (p->num != 0) even in case of error.
+*/
SRes Xzs_ReadBackward(CXzs *p, ILookInStreamPtr inStream, Int64 *startOffset, ICompressProgressPtr progress, ISzAllocPtr alloc);
UInt64 Xzs_GetNumBlocks(const CXzs *p);
@@ -268,8 +274,8 @@
size_t outBufSize;
size_t outDataWritten; // the size of data in (outBuf) that were fully unpacked
- Byte shaDigest[SHA256_DIGEST_SIZE];
- Byte buf[XZ_BLOCK_HEADER_SIZE_MAX];
+ UInt32 shaDigest32[SHA256_DIGEST_SIZE / 4];
+ Byte buf[XZ_BLOCK_HEADER_SIZE_MAX]; // it must be aligned for 4-bytes
} CXzUnpacker;
/* alloc : aligned for cache line allocation is better */
diff -Nru 7zip-24.09+dfsg/C/XzIn.c 7zip-25.00+dfsg/C/XzIn.c
--- 7zip-24.09+dfsg/C/XzIn.c 2023-09-07 15:00:00.000000000 +0200
+++ 7zip-25.00+dfsg/C/XzIn.c 2025-05-04 12:00:00.000000000 +0200
@@ -1,38 +1,39 @@
/* XzIn.c - Xz input
-2023-09-07 : Igor Pavlov : Public domain */
+: Igor Pavlov : Public domain */
#include "Precomp.h"
#include <string.h>
#include "7zCrc.h"
-#include "CpuArch.h"
#include "Xz.h"
+#include "CpuArch.h"
-/*
-#define XZ_FOOTER_SIG_CHECK(p) (memcmp((p), XZ_FOOTER_SIG, XZ_FOOTER_SIG_SIZE) == 0)
-*/
-#define XZ_FOOTER_SIG_CHECK(p) ((p)[0] == XZ_FOOTER_SIG_0 && (p)[1] == XZ_FOOTER_SIG_1)
-
+#define XZ_FOOTER_12B_ALIGNED16_SIG_CHECK(p) \
+ (GetUi16a((const Byte *)(const void *)(p) + 10) == \
+ (XZ_FOOTER_SIG_0 | (XZ_FOOTER_SIG_1 << 8)))
SRes Xz_ReadHeader(CXzStreamFlags *p, ISeqInStreamPtr inStream)
{
- Byte sig[XZ_STREAM_HEADER_SIZE];
+ UInt32 data32[XZ_STREAM_HEADER_SIZE / 4];
size_t processedSize = XZ_STREAM_HEADER_SIZE;
- RINOK(SeqInStream_ReadMax(inStream, sig, &processedSize))
+ RINOK(SeqInStream_ReadMax(inStream, data32, &processedSize))
if (processedSize != XZ_STREAM_HEADER_SIZE
- || memcmp(sig, XZ_SIG, XZ_SIG_SIZE) != 0)
+ || memcmp(data32, XZ_SIG, XZ_SIG_SIZE) != 0)
return SZ_ERROR_NO_ARCHIVE;
- return Xz_ParseHeader(p, sig);
+ return Xz_ParseHeader(p, (const Byte *)(const void *)data32);
}
-#define READ_VARINT_AND_CHECK(buf, pos, size, res) \
- { const unsigned s = Xz_ReadVarInt(buf + pos, size - pos, res); \
+#define READ_VARINT_AND_CHECK(buf, size, res) \
+{ const unsigned s = Xz_ReadVarInt(buf, size, res); \
if (s == 0) return SZ_ERROR_ARCHIVE; \
- pos += s; }
+ size -= s; \
+ buf += s; \
+}
SRes XzBlock_ReadHeader(CXzBlock *p, ISeqInStreamPtr inStream, BoolInt *isIndex, UInt32 *headerSizeRes)
{
+ MY_ALIGN(4)
Byte header[XZ_BLOCK_HEADER_SIZE_MAX];
unsigned headerSize;
*headerSizeRes = 0;
@@ -57,8 +58,12 @@
return XzBlock_Parse(p, header);
}
+
#define ADD_SIZE_CHECK(size, val) \
- { const UInt64 newSize = size + (val); if (newSize < size) return XZ_SIZE_OVERFLOW; size = newSize; }
+{ const UInt64 newSize = size + (val); \
+ if (newSize < size) return XZ_SIZE_OVERFLOW; \
+ size = newSize; \
+}
UInt64 Xz_GetUnpackSize(const CXzStream *p)
{
@@ -82,76 +87,85 @@
return size;
}
-/*
-SRes XzBlock_ReadFooter(CXzBlock *p, CXzStreamFlags f, ISeqInStreamPtr inStream)
-{
- return SeqInStream_Read(inStream, p->check, XzFlags_GetCheckSize(f));
-}
-*/
-static SRes Xz_ReadIndex2(CXzStream *p, const Byte *buf, size_t size, ISzAllocPtr alloc)
+// input;
+// CXzStream (p) is empty object.
+// size != 0
+// (size & 3) == 0
+// (buf) is aligned for at least 4 bytes.
+// output:
+// p->numBlocks is number of allocated items in p->blocks
+// p->blocks[*] values must be ignored, if function returns error.
+static SRes Xz_ParseIndex(CXzStream *p, const Byte *buf, size_t size, ISzAllocPtr alloc)
{
- size_t numBlocks, pos = 1;
- UInt32 crc;
-
+ size_t numBlocks;
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;
-
+ {
+ const UInt32 crc = CrcCalc(buf, size);
+ if (crc != GetUi32a(buf + size))
+ return SZ_ERROR_ARCHIVE;
+ }
+ buf++;
+ size--;
{
UInt64 numBlocks64;
- READ_VARINT_AND_CHECK(buf, pos, size, &numBlocks64)
- numBlocks = (size_t)numBlocks64;
- if (numBlocks != numBlocks64 || numBlocks * 2 > size)
+ READ_VARINT_AND_CHECK(buf, size, &numBlocks64)
+ // (numBlocks64) is 63-bit value, so we can calculate (numBlocks64 * 2):
+ if (numBlocks64 * 2 > size)
return SZ_ERROR_ARCHIVE;
+ if (numBlocks64 >= ((size_t)1 << (sizeof(size_t) * 8 - 1)) / sizeof(CXzBlockSizes))
+ return SZ_ERROR_MEM; // SZ_ERROR_ARCHIVE
+ numBlocks = (size_t)numBlocks64;
}
-
- Xz_Free(p, alloc);
- if (numBlocks != 0)
+ // Xz_Free(p, alloc); // it's optional, because (p) is empty already
+ if (numBlocks)
{
- size_t i;
- p->numBlocks = numBlocks;
- p->blocks = (CXzBlockSizes *)ISzAlloc_Alloc(alloc, sizeof(CXzBlockSizes) * numBlocks);
- if (!p->blocks)
+ CXzBlockSizes *blocks = (CXzBlockSizes *)ISzAlloc_Alloc(alloc, sizeof(CXzBlockSizes) * numBlocks);
+ if (!blocks)
return SZ_ERROR_MEM;
- for (i = 0; i < numBlocks; i++)
+ p->blocks = blocks;
+ p->numBlocks = numBlocks;
+ // the caller will call Xz_Free() in case of error
+ do
{
- 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)
+ READ_VARINT_AND_CHECK(buf, size, &blocks->totalSize)
+ READ_VARINT_AND_CHECK(buf, size, &blocks->unpackSize)
+ if (blocks->totalSize == 0)
return SZ_ERROR_ARCHIVE;
+ blocks++;
}
+ while (--numBlocks);
}
- while ((pos & 3) != 0)
- if (buf[pos++] != 0)
+ if (size >= 4)
+ return SZ_ERROR_ARCHIVE;
+ while (size)
+ if (buf[--size])
return SZ_ERROR_ARCHIVE;
- return (pos == size) ? SZ_OK : SZ_ERROR_ARCHIVE;
+ return SZ_OK;
}
+
+/*
static SRes Xz_ReadIndex(CXzStream *p, ILookInStreamPtr stream, UInt64 indexSize, ISzAllocPtr alloc)
{
SRes res;
size_t size;
Byte *buf;
- if (indexSize > ((UInt32)1 << 31))
- return SZ_ERROR_UNSUPPORTED;
+ if (indexSize >= ((size_t)1 << (sizeof(size_t) * 8 - 1)))
+ return SZ_ERROR_MEM; // SZ_ERROR_ARCHIVE
size = (size_t)indexSize;
- if (size != indexSize)
- return SZ_ERROR_UNSUPPORTED;
buf = (Byte *)ISzAlloc_Alloc(alloc, size);
if (!buf)
return SZ_ERROR_MEM;
res = LookInStream_Read2(stream, buf, size, SZ_ERROR_UNSUPPORTED);
if (res == SZ_OK)
- res = Xz_ReadIndex2(p, buf, size, alloc);
+ res = Xz_ParseIndex(p, buf, size, alloc);
ISzAlloc_Free(alloc, buf);
return res;
}
+*/
static SRes LookInStream_SeekRead_ForArc(ILookInStreamPtr stream, UInt64 offset, void *buf, size_t size)
{
@@ -160,84 +174,102 @@
/* return LookInStream_Read2(stream, buf, size, SZ_ERROR_NO_ARCHIVE); */
}
+
+/*
+in:
+ (*startOffset) is position in (stream) where xz_stream must be finished.
+out:
+ if returns SZ_OK, then (*startOffset) is position in stream that shows start of xz_stream.
+*/
static SRes Xz_ReadBackward(CXzStream *p, ILookInStreamPtr stream, Int64 *startOffset, ISzAllocPtr alloc)
{
- UInt64 indexSize;
- Byte buf[XZ_STREAM_FOOTER_SIZE];
+ #define TEMP_BUF_SIZE (1 << 10)
+ UInt32 buf32[TEMP_BUF_SIZE / 4];
UInt64 pos = (UInt64)*startOffset;
- if ((pos & 3) != 0 || pos < XZ_STREAM_FOOTER_SIZE)
+ if ((pos & 3) || 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))
+ RINOK(LookInStream_SeekRead_ForArc(stream, pos, buf32, XZ_STREAM_FOOTER_SIZE))
- if (!XZ_FOOTER_SIG_CHECK(buf + 10))
+ if (!XZ_FOOTER_12B_ALIGNED16_SIG_CHECK(buf32))
{
- 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 != 0
+ // (pos & 3) == 0
+ size_t 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)
+ RINOK(LookInStream_SeekRead_ForArc(stream, pos, buf32, i))
+ i /= 4;
+ do
+ if (buf32[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))
+ while (--i);
+
+ pos += i * 4;
+ #define XZ_STREAM_BACKWARD_READING_PAD_MAX (1 << 16)
+ // here we don't support rare case with big padding for xz stream.
+ // so we have padding limit for backward reading.
+ if ((UInt64)*startOffset - pos > XZ_STREAM_BACKWARD_READING_PAD_MAX)
return SZ_ERROR_NO_ARCHIVE;
+ if (i)
+ break;
}
-
+ // we try to open xz stream after skipping zero padding.
+ // ((UInt64)*startOffset == pos) is possible here!
if (pos < XZ_STREAM_FOOTER_SIZE)
return SZ_ERROR_NO_ARCHIVE;
pos -= XZ_STREAM_FOOTER_SIZE;
- RINOK(LookInStream_SeekRead_ForArc(stream, pos, buf, XZ_STREAM_FOOTER_SIZE))
- if (!XZ_FOOTER_SIG_CHECK(buf + 10))
+ RINOK(LookInStream_SeekRead_ForArc(stream, pos, buf32, XZ_STREAM_FOOTER_SIZE))
+ if (!XZ_FOOTER_12B_ALIGNED16_SIG_CHECK(buf32))
return SZ_ERROR_NO_ARCHIVE;
}
- p->flags = (CXzStreamFlags)GetBe16(buf + 8);
-
+ p->flags = (CXzStreamFlags)GetBe16a(buf32 + 2);
if (!XzFlags_IsSupported(p->flags))
return SZ_ERROR_UNSUPPORTED;
-
{
/* to eliminate GCC 6.3 warning:
dereferencing type-punned pointer will break strict-aliasing rules */
- const Byte *buf_ptr = buf;
- if (GetUi32(buf_ptr) != CrcCalc(buf + 4, 6))
+ const UInt32 *buf_ptr = buf32;
+ if (GetUi32a(buf_ptr) != CrcCalc(buf32 + 1, 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)
+ const UInt64 indexSize = ((UInt64)GetUi32a(buf32 + 1) + 1) << 2;
+ if (pos < indexSize)
return SZ_ERROR_ARCHIVE;
- pos -= (totalSize + XZ_STREAM_HEADER_SIZE);
+ pos -= indexSize;
+ // v25.00: relaxed indexSize check. We allow big index table.
+ // if (indexSize > ((UInt32)1 << 31))
+ if (indexSize >= ((size_t)1 << (sizeof(size_t) * 8 - 1)))
+ return SZ_ERROR_MEM; // SZ_ERROR_ARCHIVE
+ RINOK(LookInStream_SeekTo(stream, pos))
+ // RINOK(Xz_ReadIndex(p, stream, indexSize, alloc))
+ {
+ SRes res;
+ const size_t size = (size_t)indexSize;
+ // if (size != indexSize) return SZ_ERROR_UNSUPPORTED;
+ Byte *buf = (Byte *)ISzAlloc_Alloc(alloc, size);
+ if (!buf)
+ return SZ_ERROR_MEM;
+ res = LookInStream_Read2(stream, buf, size, SZ_ERROR_UNSUPPORTED);
+ if (res == SZ_OK)
+ res = Xz_ParseIndex(p, buf, size, alloc);
+ ISzAlloc_Free(alloc, buf);
+ RINOK(res)
+ }
+ }
+ {
+ UInt64 total = Xz_GetPackSize(p);
+ if (total == XZ_SIZE_OVERFLOW || total >= ((UInt64)1 << 63))
+ return SZ_ERROR_ARCHIVE;
+ total += XZ_STREAM_HEADER_SIZE;
+ if (pos < total)
+ return SZ_ERROR_ARCHIVE;
+ pos -= total;
RINOK(LookInStream_SeekTo(stream, pos))
*startOffset = (Int64)pos;
}
@@ -246,7 +278,6 @@
CSecToRead secToRead;
SecToRead_CreateVTable(&secToRead);
secToRead.realStream = stream;
-
RINOK(Xz_ReadHeader(&headerFlags, &secToRead.vt))
return (p->flags == headerFlags) ? SZ_OK : SZ_ERROR_ARCHIVE;
}
@@ -257,8 +288,7 @@
void Xzs_Construct(CXzs *p)
{
- p->num = p->numAllocated = 0;
- p->streams = 0;
+ Xzs_CONSTRUCT(p)
}
void Xzs_Free(CXzs *p, ISzAllocPtr alloc)
@@ -268,7 +298,7 @@
Xz_Free(&p->streams[i], alloc);
ISzAlloc_Free(alloc, p->streams);
p->num = p->numAllocated = 0;
- p->streams = 0;
+ p->streams = NULL;
}
UInt64 Xzs_GetNumBlocks(const CXzs *p)
@@ -307,34 +337,49 @@
SRes Xzs_ReadBackward(CXzs *p, ILookInStreamPtr stream, Int64 *startOffset, ICompressProgressPtr progress, ISzAllocPtr alloc)
{
Int64 endOffset = 0;
+ // it's supposed that CXzs object is empty here.
+ // if CXzs object is not empty, it will add new streams to that non-empty object.
+ // Xzs_Free(p, alloc); // it's optional call to empty CXzs object.
RINOK(ILookInStream_Seek(stream, &endOffset, SZ_SEEK_END))
*startOffset = endOffset;
for (;;)
{
CXzStream st;
SRes res;
- Xz_Construct(&st);
+ Xz_CONSTRUCT(&st)
res = Xz_ReadBackward(&st, stream, startOffset, alloc);
+ // if (res == SZ_OK), then (*startOffset) is start offset of new stream if
+ // if (res != SZ_OK), then (*startOffset) is unchend or it's expected start offset of stream with error
st.startOffset = (UInt64)*startOffset;
- RINOK(res)
+ // we must store (st) object to array, or we must free (st) local object.
+ if (res != SZ_OK)
+ {
+ Xz_Free(&st, alloc);
+ return res;
+ }
if (p->num == p->numAllocated)
{
const size_t newNum = p->num + p->num / 4 + 1;
void *data = ISzAlloc_Alloc(alloc, newNum * sizeof(CXzStream));
if (!data)
+ {
+ Xz_Free(&st, alloc);
return SZ_ERROR_MEM;
+ }
p->numAllocated = newNum;
if (p->num != 0)
memcpy(data, p->streams, p->num * sizeof(CXzStream));
ISzAlloc_Free(alloc, p->streams);
p->streams = (CXzStream *)data;
}
+ // we use direct copying of raw data from local variable (st) to object in array.
+ // so we don't need to call Xz_Free(&st, alloc) after copying and after p->num++
p->streams[p->num++] = st;
if (*startOffset == 0)
- break;
- RINOK(LookInStream_SeekTo(stream, (UInt64)*startOffset))
+ return SZ_OK;
+ // seek operation is optional:
+ // RINOK(LookInStream_SeekTo(stream, (UInt64)*startOffset))
if (progress && ICompressProgress_Progress(progress, (UInt64)(endOffset - *startOffset), (UInt64)(Int64)-1) != SZ_OK)
return SZ_ERROR_PROGRESS;
}
- return SZ_OK;
}
diff -Nru 7zip-24.09+dfsg/CPP/7zip/7zip_gcc.mak 7zip-25.00+dfsg/CPP/7zip/7zip_gcc.mak
--- 7zip-24.09+dfsg/CPP/7zip/7zip_gcc.mak 2024-11-25 18:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/7zip/7zip_gcc.mak 2025-07-02 07:00:00.000000000 +0200
@@ -1245,8 +1245,6 @@
$(CC) $(CFLAGS) $<
$O/Sha512Opt.o: ../../../../C/Sha512Opt.c
$(CC) $(CFLAGS) $<
-$O/Sort.o: ../../../../C/Sort.c
- $(CC) $(CFLAGS) $<
$O/SwapBytes.o: ../../../../C/SwapBytes.c
$(CC) $(CFLAGS) $<
$O/Xxh64.o: ../../../../C/Xxh64.c
@@ -1285,6 +1283,8 @@
$(MY_ASM) $(AFLAGS) $<
$O/Sha256Opt.o: ../../../../Asm/x86/Sha256Opt.asm
$(MY_ASM) $(AFLAGS) $<
+$O/Sort.o: ../../../../Asm/x86/Sort.asm
+ $(MY_ASM) $(AFLAGS) $<
ifndef USE_JWASM
USE_X86_ASM_AES=1
@@ -1299,6 +1299,8 @@
$(CC) $(CFLAGS) $<
$O/Sha256Opt.o: ../../../../C/Sha256Opt.c
$(CC) $(CFLAGS) $<
+$O/Sort.o: ../../../../C/Sort.c
+ $(CC) $(CFLAGS) $<
endif
diff -Nru 7zip-24.09+dfsg/CPP/7zip/Archive/7z/7zCompressionMode.h 7zip-25.00+dfsg/CPP/7zip/Archive/7z/7zCompressionMode.h
--- 7zip-24.09+dfsg/CPP/7zip/Archive/7z/7zCompressionMode.h 2023-11-24 19:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/7zip/Archive/7z/7zCompressionMode.h 2024-12-14 10:00:00.000000000 +0100
@@ -59,6 +59,7 @@
bool NumThreads_WasForced;
bool MultiThreadMixer;
UInt32 NumThreads;
+ UInt32 NumThreadGroups;
#endif
UString Password; // _Wipe
@@ -74,6 +75,7 @@
, NumThreads_WasForced(false)
, MultiThreadMixer(true)
, NumThreads(1)
+ , NumThreadGroups(0)
#endif
, MemoryUsageLimit((UInt64)1 << 30)
{}
diff -Nru 7zip-24.09+dfsg/CPP/7zip/Archive/7z/7zHandlerOut.cpp 7zip-25.00+dfsg/CPP/7zip/Archive/7z/7zHandlerOut.cpp
--- 7zip-24.09+dfsg/CPP/7zip/Archive/7z/7zHandlerOut.cpp 2024-05-12 14:00:00.000000000 +0200
+++ 7zip-25.00+dfsg/CPP/7zip/Archive/7z/7zHandlerOut.cpp 2025-07-03 09:00:00.000000000 +0200
@@ -111,8 +111,8 @@
}
}
- const UInt64 kSolidBytes_Min = (1 << 24);
- const UInt64 kSolidBytes_Max = ((UInt64)1 << 32);
+ const UInt64 kSolidBytes_Min = 1 << 24;
+ const UInt64 kSolidBytes_Max = (UInt64)1 << 32; // for non-LZMA2 methods
bool needSolid = false;
@@ -122,22 +122,24 @@
SetGlobalLevelTo(oneMethodInfo);
- #ifndef Z7_ST
+#ifndef Z7_ST
const bool numThreads_WasSpecifiedInMethod = (oneMethodInfo.Get_NumThreads() >= 0);
if (!numThreads_WasSpecifiedInMethod)
{
// here we set the (NCoderPropID::kNumThreads) property in each method, only if there is no such property already
CMultiMethodProps::SetMethodThreadsTo_IfNotFinded(oneMethodInfo, methodMode.NumThreads);
}
- #endif
+ if (methodMode.NumThreadGroups > 1)
+ CMultiMethodProps::Set_Method_NumThreadGroups_IfNotFinded(oneMethodInfo, methodMode.NumThreadGroups);
+#endif
CMethodFull &methodFull = methodMode.Methods.AddNew();
RINOK(PropsMethod_To_FullMethod(methodFull, oneMethodInfo))
- #ifndef Z7_ST
+#ifndef Z7_ST
methodFull.Set_NumThreads = true;
methodFull.NumThreads = methodMode.NumThreads;
- #endif
+#endif
if (methodFull.Id != k_Copy)
needSolid = true;
@@ -217,19 +219,18 @@
// here we get real chunkSize
cs = oneMethodInfo.Get_Xz_BlockSize();
if (dicSize > cs)
- dicSize = cs;
+ dicSize = cs;
- const UInt64 kSolidBytes_Lzma2_Max = ((UInt64)1 << 34);
+ const UInt64 kSolidBytes_Lzma2_Max = (UInt64)1 << 34;
if (numSolidBytes > kSolidBytes_Lzma2_Max)
- numSolidBytes = kSolidBytes_Lzma2_Max;
+ numSolidBytes = kSolidBytes_Lzma2_Max;
methodFull.Set_NumThreads = false; // we don't use ICompressSetCoderMt::SetNumberOfThreads() for LZMA2 encoder
#ifndef Z7_ST
if (!numThreads_WasSpecifiedInMethod
&& !methodMode.NumThreads_WasForced
- && methodMode.MemoryUsageLimit_WasSet
- )
+ && methodMode.MemoryUsageLimit_WasSet)
{
const UInt32 lzmaThreads = oneMethodInfo.Get_Lzma_NumThreads();
const UInt32 numBlockThreads_Original = methodMode.NumThreads / lzmaThreads;
@@ -273,14 +274,14 @@
{
numSolidBytes = (UInt64)dicSize << 7;
if (numSolidBytes > kSolidBytes_Max)
- numSolidBytes = kSolidBytes_Max;
+ numSolidBytes = kSolidBytes_Max;
}
if (_numSolidBytesDefined)
continue;
if (numSolidBytes < kSolidBytes_Min)
- numSolidBytes = kSolidBytes_Min;
+ numSolidBytes = kSolidBytes_Min;
_numSolidBytes = numSolidBytes;
_numSolidBytesDefined = true;
}
@@ -704,6 +705,9 @@
methodMode.NumThreads = numThreads;
methodMode.NumThreads_WasForced = _numThreads_WasForced;
methodMode.MultiThreadMixer = _useMultiThreadMixer;
+#ifdef _WIN32
+ methodMode.NumThreadGroups = _numThreadGroups; // _change it
+#endif
// headerMethod.NumThreads = 1;
headerMethod.MultiThreadMixer = _useMultiThreadMixer;
}
diff -Nru 7zip-24.09+dfsg/CPP/7zip/Archive/ArHandler.cpp 7zip-25.00+dfsg/CPP/7zip/Archive/ArHandler.cpp
--- 7zip-24.09+dfsg/CPP/7zip/Archive/ArHandler.cpp 2024-02-25 20:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/7zip/Archive/ArHandler.cpp 2025-06-16 12:00:00.000000000 +0200
@@ -325,7 +325,7 @@
{
unsigned i;
for (i = 0; i < _items.Size(); i++)
- if (_items[i].Name == "//")
+ if (_items[i].Name.IsEqualTo("//"))
break;
if (i == _items.Size())
return S_OK;
@@ -378,7 +378,7 @@
if (item.Name[0] == '/')
continue;
CItem &prev = _items[i - 1];
- if (item.Name == prev.Name)
+ if (item.Name.IsEqualTo(prev.Name))
{
if (prev.SameNameIndex < 0)
prev.SameNameIndex = 0;
@@ -448,9 +448,9 @@
HRESULT CHandler::ParseLibSymbols(IInStream *stream, unsigned fileIndex)
{
CItem &item = _items[fileIndex];
- if (item.Name != "/" &&
- item.Name != "__.SYMDEF" &&
- item.Name != "__.SYMDEF SORTED")
+ if (!item.Name.IsEqualTo("/") &&
+ !item.Name.IsEqualTo("__.SYMDEF") &&
+ !item.Name.IsEqualTo("__.SYMDEF SORTED"))
return S_OK;
if (item.Size > ((UInt32)1 << 30) ||
item.Size < 4)
@@ -462,7 +462,7 @@
size_t pos = 0;
- if (item.Name != "/")
+ if (!item.Name.IsEqualTo("/"))
{
// "__.SYMDEF" parsing (BSD)
unsigned be;
@@ -603,7 +603,7 @@
if (_longNames_FileIndex >= 0)
_items.Delete((unsigned)_longNames_FileIndex);
- if (!_items.IsEmpty() && _items[0].Name == "debian-binary")
+ if (!_items.IsEmpty() && _items[0].Name.IsEqualTo("debian-binary"))
{
_type = kType_Deb;
_items.DeleteFrontal(1);
diff -Nru 7zip-24.09+dfsg/CPP/7zip/Archive/Bz2Handler.cpp 7zip-25.00+dfsg/CPP/7zip/Archive/Bz2Handler.cpp
--- 7zip-24.09+dfsg/CPP/7zip/Archive/Bz2Handler.cpp 2024-02-26 10:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/7zip/Archive/Bz2Handler.cpp 2025-07-02 14:00:00.000000000 +0200
@@ -427,9 +427,13 @@
}
CMethodProps props2 = _props;
- #ifndef Z7_ST
+#ifndef Z7_ST
props2.AddProp_NumThreads(_props._numThreads);
- #endif
+#ifdef _WIN32
+ if (_props._numThreadGroups > 1)
+ props2.AddProp32(NCoderPropID::kNumThreadGroups, _props._numThreadGroups);
+#endif
+#endif
return UpdateArchive(size, outStream, props2, updateCallback);
}
diff -Nru 7zip-24.09+dfsg/CPP/7zip/Archive/ComHandler.cpp 7zip-25.00+dfsg/CPP/7zip/Archive/ComHandler.cpp
--- 7zip-24.09+dfsg/CPP/7zip/Archive/ComHandler.cpp 2024-02-15 08:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/7zip/Archive/ComHandler.cpp 2025-04-26 13:18:00.000000000 +0200
@@ -68,7 +68,7 @@
static const Byte kRootStorage = 5;
}
-static const UInt32 kNameSizeMax = 64;
+static const unsigned kNameSizeMax = 64;
struct CItem
{
@@ -98,30 +98,30 @@
class CDatabase
{
- UInt32 NumSectorsInMiniStream;
CObjArray<UInt32> MiniSids;
HRESULT AddNode(int parent, UInt32 did);
-public:
+public:
CObjArray<UInt32> Fat;
- UInt32 FatSize;
-
CObjArray<UInt32> Mat;
- UInt32 MatSize;
-
CObjectVector<CItem> Items;
CRecordVector<CRef> Refs;
+private:
+ UInt32 NumSectorsInMiniStream;
+public:
+ UInt32 MatSize;
+ UInt32 FatSize;
UInt32 LongStreamMinSize;
unsigned SectorSizeBits;
unsigned MiniSectorSizeBits;
Int32 MainSubfile;
+ EType Type;
UInt64 PhySize;
UInt64 PhySize_Aligned;
- EType Type;
bool IsNotArcType() const
{
@@ -148,14 +148,14 @@
UInt64 GetItemPackSize(UInt64 size) const
{
- UInt64 mask = ((UInt64)1 << (IsLargeStream(size) ? SectorSizeBits : MiniSectorSizeBits)) - 1;
+ const UInt64 mask = ((UInt32)1 << (IsLargeStream(size) ? SectorSizeBits : MiniSectorSizeBits)) - 1;
return (size + mask) & ~mask;
}
bool GetMiniCluster(UInt32 sid, UInt64 &res) const
{
- unsigned subBits = SectorSizeBits - MiniSectorSizeBits;
- UInt32 fid = sid >> subBits;
+ const unsigned subBits = SectorSizeBits - MiniSectorSizeBits;
+ const UInt32 fid = sid >> subBits;
if (fid >= NumSectorsInMiniStream)
return false;
res = (((UInt64)MiniSids[fid] + 1) << subBits) + (sid & ((1 << subBits) - 1));
@@ -177,7 +177,7 @@
HRESULT CDatabase::ReadIDs(IInStream *inStream, Byte *buf, unsigned sectorSizeBits, UInt32 sid, UInt32 *dest)
{
RINOK(ReadSector(inStream, buf, sectorSizeBits, sid))
- UInt32 sectorSize = (UInt32)1 << sectorSizeBits;
+ const UInt32 sectorSize = (UInt32)1 << sectorSizeBits;
for (UInt32 t = 0; t < sectorSize; t += 4)
*dest++ = Get32(buf + t);
return S_OK;
@@ -373,7 +373,7 @@
HRESULT CDatabase::Update_PhySize_WithItem(unsigned index)
{
const CItem &item = Items[index];
- bool isLargeStream = (index == 0 || IsLargeStream(item.Size));
+ const bool isLargeStream = (index == 0 || IsLargeStream(item.Size));
if (!isLargeStream)
return S_OK;
const unsigned bsLog = isLargeStream ? SectorSizeBits : MiniSectorSizeBits;
@@ -527,6 +527,10 @@
{
CItem item;
item.Parse(sect + i, mode64bit);
+ // we use (item.Size) check here.
+ // so we don't need additional overflow checks for (item.Size +) in another code
+ if (item.Size >= ((UInt64)1 << 63))
+ return S_FALSE;
Items.Add(item);
}
sid = Fat[sid];
@@ -767,11 +771,8 @@
UInt64 totalPackSize;
totalSize = totalPackSize = 0;
- NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
- CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
-
- CLocalProgress *lps = new CLocalProgress;
- CMyComPtr<ICompressProgressInfo> progress = lps;
+ CMyComPtr2_Create<ICompressCoder, NCompress::CCopyCoder> copyCoder;
+ CMyComPtr2_Create<ICompressProgressInfo, CLocalProgress> lps;
lps->Init(extractCallback, false);
for (i = 0; i < numItems; i++)
@@ -781,7 +782,8 @@
RINOK(lps->SetCur())
const UInt32 index = allFilesMode ? i : indices[i];
const CItem &item = _db.Items[_db.Refs[index].Did];
-
+ Int32 res;
+ {
CMyComPtr<ISequentialOutStream> outStream;
const Int32 askMode = testMode ?
NExtract::NAskMode::kTest :
@@ -801,7 +803,7 @@
if (!testMode && !outStream)
continue;
RINOK(extractCallback->PrepareOperation(askMode))
- Int32 res = NExtract::NOperationResult::kDataError;
+ res = NExtract::NOperationResult::kDataError;
CMyComPtr<ISequentialInStream> inStream;
HRESULT hres = GetStream(index, &inStream);
if (hres == S_FALSE)
@@ -813,12 +815,12 @@
RINOK(hres)
if (inStream)
{
- RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress))
- if (copyCoderSpec->TotalSize == item.Size)
+ RINOK(copyCoder.Interface()->Code(inStream, outStream, NULL, NULL, lps))
+ if (copyCoder->TotalSize == item.Size)
res = NExtract::NOperationResult::kOK;
}
}
- outStream.Release();
+ }
RINOK(extractCallback->SetOperationResult(res))
}
return S_OK;
diff -Nru 7zip-24.09+dfsg/CPP/7zip/Archive/Common/HandlerOut.cpp 7zip-25.00+dfsg/CPP/7zip/Archive/Common/HandlerOut.cpp
--- 7zip-24.09+dfsg/CPP/7zip/Archive/Common/HandlerOut.cpp 2023-05-07 17:00:00.000000000 +0200
+++ 7zip-25.00+dfsg/CPP/7zip/Archive/Common/HandlerOut.cpp 2025-07-02 08:00:00.000000000 +0200
@@ -4,8 +4,6 @@
#include "../../../Common/StringToInt.h"
-#include "../Common/ParseProperties.h"
-
#include "HandlerOut.h"
namespace NArchive {
@@ -82,6 +80,7 @@
return true;
}
+
bool CCommonMethodProps::SetCommonProperty(const UString &name, const PROPVARIANT &value, HRESULT &hres)
{
hres = S_OK;
@@ -151,6 +150,11 @@
SetMethodProp32_Replace(oneMethodInfo, NCoderPropID::kNumThreads, numThreads);
}
+void CMultiMethodProps::Set_Method_NumThreadGroups_IfNotFinded(CMethodProps &oneMethodInfo, UInt32 numThreadGroups)
+{
+ SetMethodProp32(oneMethodInfo, NCoderPropID::kNumThreadGroups, numThreadGroups);
+}
+
#endif // Z7_ST
diff -Nru 7zip-24.09+dfsg/CPP/7zip/Archive/Common/HandlerOut.h 7zip-25.00+dfsg/CPP/7zip/Archive/Common/HandlerOut.h
--- 7zip-24.09+dfsg/CPP/7zip/Archive/Common/HandlerOut.h 2024-10-22 11:00:00.000000000 +0200
+++ 7zip-25.00+dfsg/CPP/7zip/Archive/Common/HandlerOut.h 2025-07-02 09:00:00.000000000 +0200
@@ -17,11 +17,21 @@
void InitCommon()
{
// _Write_MTime = true;
- #ifndef Z7_ST
- _numProcessors = _numThreads = NWindows::NSystem::GetNumberOfProcessors();
- _numThreads_WasForced = false;
- #endif
-
+ {
+#ifndef Z7_ST
+ _numThreads_WasForced = false;
+ UInt32 numThreads;
+#ifdef _WIN32
+ NWindows::NSystem::CProcessAffinity aff;
+ numThreads = aff.Load_and_GetNumberOfThreads();
+ _numThreadGroups = aff.IsGroupMode ? aff.Groups.GroupSizes.Size() : 0;
+#else
+ numThreads = NWindows::NSystem::GetNumberOfProcessors();
+#endif // _WIN32
+ _numProcessors = _numThreads = numThreads;
+#endif // Z7_ST
+ }
+
size_t memAvail = (size_t)sizeof(size_t) << 28;
_memAvail = memAvail;
_memUsage_Compress = memAvail;
@@ -46,11 +56,14 @@
}
public:
- #ifndef Z7_ST
+#ifndef Z7_ST
UInt32 _numThreads;
UInt32 _numProcessors;
+#ifdef _WIN32
+ UInt32 _numThreadGroups;
+#endif
bool _numThreads_WasForced;
- #endif
+#endif
bool _memUsage_WasSet;
UInt64 _memUsage_Compress;
@@ -80,10 +93,12 @@
void SetGlobalLevelTo(COneMethodInfo &oneMethodInfo) const;
- #ifndef Z7_ST
+#ifndef Z7_ST
static void SetMethodThreadsTo_IfNotFinded(CMethodProps &props, UInt32 numThreads);
static void SetMethodThreadsTo_Replace(CMethodProps &props, UInt32 numThreads);
- #endif
+
+ static void Set_Method_NumThreadGroups_IfNotFinded(CMethodProps &props, UInt32 numThreadGroups);
+#endif
unsigned GetNumEmptyMethods() const
diff -Nru 7zip-24.09+dfsg/CPP/7zip/Archive/Common/ItemNameUtils.cpp 7zip-25.00+dfsg/CPP/7zip/Archive/Common/ItemNameUtils.cpp
--- 7zip-24.09+dfsg/CPP/7zip/Archive/Common/ItemNameUtils.cpp 2022-01-09 19:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/7zip/Archive/Common/ItemNameUtils.cpp 2025-06-18 13:00:00.000000000 +0200
@@ -47,6 +47,25 @@
}
+#if WCHAR_PATH_SEPARATOR != L'/'
+void ReplaceToWinSlashes(UString &name, bool useBackslashReplacement)
+{
+ // name.Replace(kUnixPathSepar, kOsPathSepar);
+ const unsigned len = name.Len();
+ for (unsigned i = 0; i < len; i++)
+ {
+ wchar_t c = name[i];
+ if (c == L'/')
+ c = WCHAR_PATH_SEPARATOR;
+ else if (useBackslashReplacement && c == L'\\')
+ c = WCHAR_IN_FILE_NAME_BACKSLASH_REPLACEMENT; // WSL scheme
+ else
+ continue;
+ name.ReplaceOneCharAtPos(i, c);
+ }
+}
+#endif
+
void ReplaceToOsSlashes_Remove_TailSlash(UString &name, bool
#if WCHAR_PATH_SEPARATOR != L'/'
useBackslashReplacement
@@ -57,21 +76,7 @@
return;
#if WCHAR_PATH_SEPARATOR != L'/'
- {
- // name.Replace(kUnixPathSepar, kOsPathSepar);
- const unsigned len = name.Len();
- for (unsigned i = 0; i < len; i++)
- {
- wchar_t c = name[i];
- if (c == L'/')
- c = WCHAR_PATH_SEPARATOR;
- else if (useBackslashReplacement && c == L'\\')
- c = WCHAR_IN_FILE_NAME_BACKSLASH_REPLACEMENT; // WSL scheme
- else
- continue;
- name.ReplaceOneCharAtPos(i, c);
- }
- }
+ ReplaceToWinSlashes(name, useBackslashReplacement);
#endif
if (name.Back() == kOsPathSepar)
diff -Nru 7zip-24.09+dfsg/CPP/7zip/Archive/Common/ItemNameUtils.h 7zip-25.00+dfsg/CPP/7zip/Archive/Common/ItemNameUtils.h
--- 7zip-24.09+dfsg/CPP/7zip/Archive/Common/ItemNameUtils.h 2023-01-10 18:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/7zip/Archive/Common/ItemNameUtils.h 2025-06-16 14:00:00.000000000 +0200
@@ -13,6 +13,9 @@
UString GetOsPath(const UString &name);
UString GetOsPath_Remove_TailSlash(const UString &name);
+#if WCHAR_PATH_SEPARATOR != L'/'
+void ReplaceToWinSlashes(UString &name, bool useBackslashReplacement);
+#endif
void ReplaceToOsSlashes_Remove_TailSlash(UString &name, bool useBackslashReplacement = false);
void NormalizeSlashes_in_FileName_for_OsPath(wchar_t *s, unsigned len);
void NormalizeSlashes_in_FileName_for_OsPath(UString &name);
diff -Nru 7zip-24.09+dfsg/CPP/7zip/Archive/CpioHandler.cpp 7zip-25.00+dfsg/CPP/7zip/Archive/CpioHandler.cpp
--- 7zip-24.09+dfsg/CPP/7zip/Archive/CpioHandler.cpp 2023-10-02 12:00:00.000000000 +0200
+++ 7zip-25.00+dfsg/CPP/7zip/Archive/CpioHandler.cpp 2025-06-21 09:00:00.000000000 +0200
@@ -437,7 +437,14 @@
return S_OK;
/* v23.02: we have disabled rDevMinor check because real file
- from Apple contains rDevMinor==255 by some unknown reason */
+ from Apple contains rDevMinor==255 by some unknown reason
+ cpio 2.13 and older versions: it copies stat::st_rdev to archive.
+ and stat::st_rdev can be non-zero for some old linux/filesystems cases for regular files.
+ cpio 2.14 (2023) copies st_rdev to archive only if (S_ISBLK (st->st_mode) || S_ISCHR (st->st_mode))
+ v25.00: we have disabled RDevMajor check here to support some rare case created by cpio 2.13- with old linux.
+ But we still keep full check in IsArc_Cpio() to reduce false cpio detection cases.
+ */
+#if 0 // 0 : to disable check to support some old linux cpio archives.
if (item.RDevMajor != 0
// || item.RDevMinor != 0
)
@@ -446,6 +453,7 @@
!MY_LIN_S_ISBLK(item.Mode))
return S_OK;
}
+#endif
// Size must be 0 for FIFOs and directories
if (item.IsDir() || MY_LIN_S_ISFIFO(item.Mode))
@@ -873,17 +881,13 @@
{
case kpidPath:
{
- UString res;
- bool needConvert = true;
- #ifdef _WIN32
- // if (
- ConvertUTF8ToUnicode(item.Name, res);
- // )
- needConvert = false;
- #endif
- if (needConvert)
- res = MultiByteToUnicodeString(item.Name, CP_OEMCP);
- prop = NItemName::GetOsPath(res);
+#ifdef _WIN32
+ UString u;
+ ConvertUTF8ToUnicode(item.Name, u);
+#else
+ const UString u = MultiByteToUnicodeString(item.Name, CP_OEMCP);
+#endif
+ prop = NItemName::GetOsPath(u);
break;
}
case kpidIsDir: prop = item.IsDir(); break;
@@ -921,16 +925,12 @@
s.SetFrom_CalcLen((const char *)(const void *)(const Byte *)item.Data, (unsigned)item.Data.Size());
if (s.Len() == item.Data.Size())
{
+#ifdef _WIN32
UString u;
- bool needConvert = true;
- #ifdef _WIN32
- // if (
- ConvertUTF8ToUnicode(item.Name, u);
- // )
- needConvert = false;
- #endif
- if (needConvert)
- u = MultiByteToUnicodeString(s, CP_OEMCP);
+ ConvertUTF8ToUnicode(item.Name, u);
+#else
+ const UString u = MultiByteToUnicodeString(s, CP_OEMCP);
+#endif
prop = u;
}
}
diff -Nru 7zip-24.09+dfsg/CPP/7zip/Archive/DmgHandler.cpp 7zip-25.00+dfsg/CPP/7zip/Archive/DmgHandler.cpp
--- 7zip-24.09+dfsg/CPP/7zip/Archive/DmgHandler.cpp 2024-03-28 13:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/7zip/Archive/DmgHandler.cpp 2025-06-16 11:00:00.000000000 +0200
@@ -444,7 +444,7 @@
{
const CAppleName &a = k_Names[i];
if (a.Ext)
- if (name == a.AppleName)
+ if (name.IsEqualTo(a.AppleName))
return a.Ext;
}
return NULL;
@@ -784,7 +784,7 @@
for (unsigned i = 0; i + 1 < item.SubItems.Size(); i++)
{
const CXmlItem &si = item.SubItems[i];
- if (si.IsTagged("key") && si.GetSubString() == key)
+ if (si.IsTagged("key") && si.GetSubString().IsEqualTo(key))
{
const CXmlItem *si_1 = &item.SubItems[i + 1];
if (si_1->IsTagged(nextTag))
@@ -1251,7 +1251,7 @@
#endif
}
- if (xml.Root.Name != "plist")
+ if (!xml.Root.Name.IsEqualTo("plist"))
return S_FALSE;
const CXmlItem *dictItem = xml.Root.FindSubTag_GetPtr("dict");
diff -Nru 7zip-24.09+dfsg/CPP/7zip/Archive/FatHandler.cpp 7zip-25.00+dfsg/CPP/7zip/Archive/FatHandler.cpp
--- 7zip-24.09+dfsg/CPP/7zip/Archive/FatHandler.cpp 2023-06-26 19:00:00.000000000 +0200
+++ 7zip-25.00+dfsg/CPP/7zip/Archive/FatHandler.cpp 2025-02-09 10:00:00.000000000 +0100
@@ -2,13 +2,12 @@
#include "StdAfx.h"
-// #include <stdio.h>
-
#include "../../../C/CpuArch.h"
#include "../../Common/ComTry.h"
#include "../../Common/IntToString.h"
#include "../../Common/MyBuffer.h"
+#include "../../Common/MyBuffer2.h"
#include "../../Common/MyCom.h"
#include "../../Common/StringConvert.h"
@@ -22,14 +21,19 @@
#include "../Compress/CopyCoder.h"
-#include "Common/DummyOutStream.h"
+#include "Common/ItemNameUtils.h"
#define Get16(p) GetUi16(p)
#define Get32(p) GetUi32(p)
#define Get16a(p) GetUi16a(p)
#define Get32a(p) GetUi32a(p)
-#define PRF(x) /* x */
+#if 0
+#include <stdio.h>
+#define PRF(x) x
+#else
+#define PRF(x)
+#endif
namespace NArchive {
namespace NFat {
@@ -38,35 +42,34 @@
struct CHeader
{
- UInt32 NumSectors;
- UInt16 NumReservedSectors;
+ Byte NumFatBits;
+ Byte SectorSizeLog;
+ Byte SectorsPerClusterLog;
+ Byte ClusterSizeLog;
Byte NumFats;
+ Byte MediaType;
+
+ bool VolFieldsDefined;
+ bool HeadersWarning;
+
+ UInt32 FatSize;
+ UInt32 BadCluster;
+
+ UInt16 NumReservedSectors;
+ UInt32 NumSectors;
UInt32 NumFatSectors;
UInt32 RootDirSector;
UInt32 NumRootDirSectors;
UInt32 DataSector;
- UInt32 FatSize;
- UInt32 BadCluster;
-
- Byte NumFatBits;
- Byte SectorSizeLog;
- Byte SectorsPerClusterLog;
- Byte ClusterSizeLog;
-
UInt16 SectorsPerTrack;
UInt16 NumHeads;
UInt32 NumHiddenSectors;
-
- bool VolFieldsDefined;
- bool HeadersWarning;
UInt32 VolId;
// Byte VolName[11];
// Byte FileSys[8];
-
// Byte OemName[5];
- Byte MediaType;
// 32-bit FAT
UInt16 Flags;
@@ -104,15 +107,8 @@
bool Parse(const Byte *p);
};
-static int GetLog(UInt32 num)
-{
- for (int i = 0; i < 31; i++)
- if (((UInt32)1 << i) == num)
- return i;
- return -1;
-}
-static const UInt32 kHeaderSize = 512;
+static const unsigned kHeaderSize = 512;
API_FUNC_IsArc IsArc_Fat(const Byte *p, size_t size);
API_FUNC_IsArc IsArc_Fat(const Byte *p, size_t size)
@@ -125,7 +121,7 @@
bool CHeader::Parse(const Byte *p)
{
- if (p[0x1FE] != 0x55 || p[0x1FF] != 0xAA)
+ if (Get16(p + 0x1FE) != 0xAA55)
return false;
HeadersWarning = false;
@@ -139,22 +135,40 @@
}
{
{
- const UInt32 val32 = Get16(p + 11);
- const int s = GetLog(val32);
- if (s < 9 || s > 12)
- return false;
- SectorSizeLog = (Byte)s;
+ const unsigned num = Get16(p + 11);
+ unsigned i = 9;
+ unsigned m = 1 << i;
+ for (;;)
+ {
+ if (m == num)
+ break;
+ m <<= 1;
+ if (++i > 12)
+ return false;
+ }
+ SectorSizeLog = (Byte)i;
}
{
- const UInt32 val32 = p[13];
- const int s = GetLog(val32);
- if (s < 0)
+ const unsigned num = p[13];
+ unsigned i = 0;
+ unsigned m = 1 << i;
+ for (;;)
+ {
+ if (m == num)
+ break;
+ m <<= 1;
+ if (++i > 7)
+ return false;
+ }
+ SectorsPerClusterLog = (Byte)i;
+ i += SectorSizeLog;
+ ClusterSizeLog = (Byte)i;
+ // (2^15 = 32 KB is safe cluster size that is suported by all system.
+ // (2^16 = 64 KB is supported by some systems
+ // (128 KB / 256 KB) can be created by some tools, but it is not supported by many tools.
+ if (i > 18) // 256 KB
return false;
- SectorsPerClusterLog = (Byte)s;
}
- ClusterSizeLog = (Byte)(SectorSizeLog + SectorsPerClusterLog);
- if (ClusterSizeLog > 24)
- return false;
}
NumReservedSectors = Get16(p + 14);
@@ -169,7 +183,7 @@
const bool isOkOffset = (codeOffset == 0)
|| (codeOffset == (p[0] == 0xEB ? 2 : 3));
- const UInt16 numRootDirEntries = Get16(p + 17);
+ const unsigned numRootDirEntries = Get16(p + 17);
if (numRootDirEntries == 0)
{
if (codeOffset < 90 && !isOkOffset)
@@ -183,10 +197,10 @@
if (codeOffset < 62 - 24 && !isOkOffset)
return false;
NumFatBits = 0;
- const UInt32 mask = (1 << (SectorSizeLog - 5)) - 1;
- if ((numRootDirEntries & mask) != 0)
+ const unsigned mask = (1u << (SectorSizeLog - 5)) - 1;
+ if (numRootDirEntries & mask)
return false;
- NumRootDirSectors = (numRootDirEntries + mask) >> (SectorSizeLog - 5);
+ NumRootDirSectors = (numRootDirEntries /* + mask */) >> (SectorSizeLog - 5);
}
NumSectors = Get16(p + 19);
@@ -198,7 +212,6 @@
else if (IsFat32())
return false;
*/
-
MediaType = p[21];
NumFatSectors = Get16(p + 22);
SectorsPerTrack = Get16(p + 24);
@@ -222,7 +235,7 @@
return false;
RootCluster = Get32(p + 8);
FsInfoSector = Get16(p + 12);
- for (int i = 16; i < 28; i++)
+ for (unsigned i = 16; i < 28; i++)
if (p[i] != 0)
return false;
p += 28;
@@ -260,7 +273,7 @@
if (numClusters >= 0xFFF5)
return false;
NumFatBits = (Byte)(numClusters < 0xFF5 ? 12 : 16);
- BadCluster &= ((1 << NumFatBits) - 1);
+ BadCluster &= (((UInt32)1 << NumFatBits) - 1);
}
FatSize = numClusters + 2;
@@ -283,103 +296,157 @@
return true;
}
-struct CItem
+
+
+class CItem
{
- UString UName;
- char DosName[11];
+ Z7_CLASS_NO_COPY(CItem)
+public:
+ UInt32 Size;
+ Byte Attrib;
Byte CTime2;
- UInt32 CTime;
- UInt32 MTime;
UInt16 ADate;
- Byte Attrib;
+ CByteBuffer LongName; // if LongName.Size() == 0 : no long name
+ // if LongName.Size() != 0 : it's NULL terminated UTF16-LE string.
+ char DosName[11];
Byte Flags;
- UInt32 Size;
+ UInt32 MTime;
+ UInt32 CTime;
UInt32 Cluster;
Int32 Parent;
+ CItem() {}
+
// NT uses Flags to store Low Case status
bool NameIsLow() const { return (Flags & 0x8) != 0; }
bool ExtIsLow() const { return (Flags & 0x10) != 0; }
bool IsDir() const { return (Attrib & 0x10) != 0; }
- UString GetShortName() const;
- UString GetName() const;
- UString GetVolName() const;
+ void GetShortName(UString &dest) const;
+ void GetName(UString &name) const;
};
-static unsigned CopyAndTrim(char *dest, const char *src, unsigned size, bool toLower)
+
+static char *CopyAndTrim(char *dest, const char *src,
+ unsigned size, unsigned toLower)
{
- memcpy(dest, src, size);
- if (toLower)
+ do
{
- for (unsigned i = 0; i < size; i++)
+ if (src[(size_t)size - 1] != ' ')
{
- char c = dest[i];
- if (c >= 'A' && c <= 'Z')
- dest[i] = (char)(c + 0x20);
+ const unsigned range = toLower ? 'Z' - 'A' + 1 : 0;
+ do
+ {
+ unsigned c = (Byte)*src++;
+ if ((unsigned)(c - 'A') < range)
+ c += 0x20;
+ *dest++ = (char)c;
+ }
+ while (--size);
+ break;
}
}
-
- for (unsigned i = size;;)
- {
- if (i == 0)
- return 0;
- if (dest[i - 1] != ' ')
- return i;
- i--;
- }
+ while (--size);
+ *dest = 0;
+ return dest;
}
-static UString FatStringToUnicode(const char *s)
+
+static void FatStringToUnicode(UString &dest, const char *s)
{
- return MultiByteToUnicodeString(s, CP_OEMCP);
+ MultiByteToUnicodeString2(dest, AString(s), CP_OEMCP);
}
-UString CItem::GetShortName() const
+void CItem::GetShortName(UString &shortName) const
{
char s[16];
- unsigned i = CopyAndTrim(s, DosName, 8, NameIsLow());
- s[i++] = '.';
- unsigned j = CopyAndTrim(s + i, DosName + 8, 3, ExtIsLow());
- if (j == 0)
- i--;
- s[i + j] = 0;
- return FatStringToUnicode(s);
+ char *dest = CopyAndTrim(s, DosName, 8, NameIsLow());
+ *dest++ = '.';
+ char *dest2 = CopyAndTrim(dest, DosName + 8, 3, ExtIsLow());
+ if (dest == dest2)
+ dest[-1] = 0;
+ FatStringToUnicode(shortName, s);
}
-UString CItem::GetName() const
+
+
+// numWords != 0
+static unsigned ParseLongName(UInt16 *buf, unsigned numWords)
{
- if (!UName.IsEmpty())
- return UName;
- return GetShortName();
+ unsigned i;
+ for (i = 0; i < numWords; i++)
+ {
+ const unsigned c = buf[i];
+ if (c == 0)
+ break;
+ if (c == 0xFFFF)
+ return 0;
+ }
+ if (i == 0)
+ return 0;
+ buf[i] = 0;
+ numWords -= i;
+ i++;
+ if (numWords > 1)
+ {
+ numWords--;
+ buf += i;
+ do
+ if (*buf++ != 0xFFFF)
+ return 0;
+ while (--numWords);
+ }
+ return i; // it includes NULL terminator
+}
+
+
+void CItem::GetName(UString &name) const
+{
+ if (LongName.Size() >= 2)
+ {
+ const Byte * const p = LongName;
+ const unsigned numWords = ((unsigned)LongName.Size() - 2) / 2;
+ wchar_t *dest = name.GetBuf(numWords);
+ for (unsigned i = 0; i < numWords; i++)
+ dest[i] = (wchar_t)Get16(p + (size_t)i * 2);
+ name.ReleaseBuf_SetEnd(numWords);
+ }
+ else
+ GetShortName(name);
+ if (name.IsEmpty()) // it's unexpected
+ name = '_';
+ NItemName::NormalizeSlashes_in_FileName_for_OsPath(name);
}
-UString CItem::GetVolName() const
+
+static void GetVolName(const char dosName[11], NWindows::NCOM::CPropVariant &prop)
{
- if (!UName.IsEmpty())
- return UName;
char s[12];
- unsigned i = CopyAndTrim(s, DosName, 11, false);
- s[i] = 0;
- return FatStringToUnicode(s);
+ CopyAndTrim(s, dosName, 11, false);
+ UString u;
+ FatStringToUnicode(u, AString(s));
+ prop = u;
}
+
struct CDatabase
{
- CHeader Header;
CObjectVector<CItem> Items;
UInt32 *Fat;
+ CHeader Header;
CMyComPtr<IInStream> InStream;
IArchiveOpenCallback *OpenCallback;
+ CAlignedBuffer ByteBuf;
+ CByteBuffer LfnBuf;
UInt32 NumFreeClusters;
- bool VolItemDefined;
- CItem VolItem;
UInt32 NumDirClusters;
- CByteBuffer ByteBuf;
UInt64 NumCurUsedBytes;
-
UInt64 PhySize;
+ UInt32 Vol_MTime;
+ char VolLabel[11];
+ bool VolItem_Defined;
+
CDatabase(): Fat(NULL) {}
~CDatabase() { ClearAndClose(); }
@@ -388,7 +455,7 @@
HRESULT OpenProgressFat(bool changeTotal = true);
HRESULT OpenProgress();
- UString GetItemPath(UInt32 index) const;
+ void GetItemPath(UInt32 index, UString &s) const;
HRESULT Open();
HRESULT ReadDir(Int32 parent, UInt32 cluster, unsigned level);
@@ -400,6 +467,7 @@
HRESULT SeekToCluster(UInt32 cluster) { return SeekToSector(Header.ClusterToSector(cluster)); }
};
+
HRESULT CDatabase::SeekToSector(UInt32 sector)
{
return InStream_SeekSet(InStream, (UInt64)sector << Header.SectorSizeLog);
@@ -408,7 +476,7 @@
void CDatabase::Clear()
{
PhySize = 0;
- VolItemDefined = false;
+ VolItem_Defined = false;
NumDirClusters = 0;
NumCurUsedBytes = 0;
@@ -440,49 +508,35 @@
{
if (!OpenCallback)
return S_OK;
- UInt64 numItems = Items.Size();
+ const UInt64 numItems = Items.Size();
return OpenCallback->SetCompleted(&numItems, &NumCurUsedBytes);
}
-UString CDatabase::GetItemPath(UInt32 index) const
+void CDatabase::GetItemPath(UInt32 index, UString &s) const
{
- const CItem *item = &Items[index];
- UString name = item->GetName();
+ UString name;
for (;;)
{
- index = (UInt32)item->Parent;
- if (item->Parent < 0)
- return name;
- item = &Items[index];
- name.InsertAtFront(WCHAR_PATH_SEPARATOR);
- if (item->UName.IsEmpty())
- name.Insert(0, item->GetShortName());
- else
- name.Insert(0, item->UName);
+ const CItem &item = Items[index];
+ item.GetName(name);
+ if (item.Parent >= 0)
+ name.InsertAtFront(WCHAR_PATH_SEPARATOR);
+ s.Insert(0, name);
+ index = (UInt32)item.Parent;
+ if (item.Parent < 0)
+ break;
}
}
-static wchar_t *AddSubStringToName(wchar_t *dest, const Byte *p, unsigned numChars)
-{
- for (unsigned i = 0; i < numChars; i++)
- {
- wchar_t c = Get16(p + i * 2);
- if (c != 0 && c != 0xFFFF)
- *dest++ = c;
- }
- *dest = 0;
- return dest;
-}
HRESULT CDatabase::ReadDir(Int32 parent, UInt32 cluster, unsigned level)
{
- unsigned startIndex = Items.Size();
+ const unsigned startIndex = Items.Size();
if (startIndex >= (1 << 30) || level > 256)
return S_FALSE;
- UInt32 sectorIndex = 0;
UInt32 blockSize = Header.ClusterSize();
- bool clusterMode = (Header.IsFat32() || parent >= 0);
+ const bool clusterMode = (Header.IsFat32() || parent >= 0);
if (!clusterMode)
{
blockSize = Header.SectorSize();
@@ -490,21 +544,26 @@
}
ByteBuf.Alloc(blockSize);
- UString curName;
- int checkSum = -1;
- int numLongRecords = -1;
+
+ const unsigned k_NumLfnRecords_MAX = 20; // 260 symbols limit (strict limit)
+ // const unsigned k_NumLfnRecords_MAX = 0x40 - 1; // 1260 symbols limit (relaxed limit)
+ const unsigned k_NumLfnBytes_in_Record = 13 * 2;
+ // we reserve 2 additional bytes for NULL terminator
+ LfnBuf.Alloc(k_NumLfnRecords_MAX * k_NumLfnBytes_in_Record + 2 * 1);
+ UInt32 curDirBytes_read = 0;
+ UInt32 sectorIndex = 0;
+ unsigned num_lfn_records = 0;
+ unsigned lfn_RecordIndex = 0;
+ int checkSum = -1;
+ bool is_record_error = false;
+
for (UInt32 pos = blockSize;; pos += 32)
{
if (pos == blockSize)
{
pos = 0;
- if ((NumDirClusters & 0xFF) == 0)
- {
- RINOK(OpenProgress())
- }
-
if (clusterMode)
{
if (Header.IsEoc(cluster))
@@ -514,21 +573,37 @@
PRF(printf("\nCluster = %4X", cluster));
RINOK(SeekToCluster(cluster))
const UInt32 newCluster = Fat[cluster];
- if ((newCluster & kFatItemUsedByDirMask) != 0)
+ if (newCluster & kFatItemUsedByDirMask)
return S_FALSE;
Fat[cluster] |= kFatItemUsedByDirMask;
cluster = newCluster;
NumDirClusters++;
+ if ((NumDirClusters & 0xFF) == 0)
+ {
+ RINOK(OpenProgress())
+ }
NumCurUsedBytes += Header.ClusterSize();
}
else if (sectorIndex++ >= Header.NumRootDirSectors)
break;
+ // if (curDirBytes_read > (1u << 28)) // do we need some relaxed limit for non-MS FATs?
+ if (curDirBytes_read >= (1u << 21)) // 2MB limit from FAT specification.
+ return S_FALSE;
RINOK(ReadStream_FALSE(InStream, ByteBuf, blockSize))
+ curDirBytes_read += blockSize;
}
- const Byte *p = ByteBuf + pos;
-
+ if (is_record_error)
+ {
+ Header.HeadersWarning = true;
+ num_lfn_records = 0;
+ lfn_RecordIndex = 0;
+ checkSum = -1;
+ }
+
+ const Byte * const p = ByteBuf + pos;
+
if (p[0] == 0)
{
/*
@@ -538,125 +613,191 @@
*/
break;
}
-
+
+ is_record_error = true;
+
if (p[0] == 0xE5)
{
- if (numLongRecords > 0)
- return S_FALSE;
+ // deleted entry
+ if (num_lfn_records == 0)
+ is_record_error = false;
continue;
}
-
- Byte attrib = p[11];
- if ((attrib & 0x3F) == 0xF)
+ // else
{
- if (p[0] > 0x7F || Get16(p + 26) != 0)
- return S_FALSE;
- int longIndex = p[0] & 0x3F;
- if (longIndex == 0)
- return S_FALSE;
- bool isLast = (p[0] & 0x40) != 0;
- if (numLongRecords < 0)
+ const Byte attrib = p[11];
+ // maybe we can use more strick check : (attrib == 0xF) ?
+ if ((attrib & 0x3F) == 0xF)
{
- if (!isLast)
+ // long file name (LFN) entry
+ const unsigned longIndex = p[0] & 0x3F;
+ if (longIndex == 0
+ || longIndex > k_NumLfnRecords_MAX
+ || p[0] > 0x7F
+ || Get16a(p + 26) != 0 // LDIR_FstClusLO
+ )
+ {
+ return S_FALSE;
+ // break;
+ }
+ const bool isLast = (p[0] & 0x40) != 0;
+ if (num_lfn_records == 0)
+ {
+ if (!isLast)
+ continue; // orphan
+ num_lfn_records = longIndex;
+ }
+ else if (isLast || longIndex != lfn_RecordIndex)
+ {
return S_FALSE;
- numLongRecords = longIndex;
+ // break;
+ }
+
+ lfn_RecordIndex = longIndex - 1;
+
+ if (p[12] == 0)
+ {
+ Byte * const dest = LfnBuf + k_NumLfnBytes_in_Record * lfn_RecordIndex;
+ memcpy(dest, p + 1, 5 * 2);
+ memcpy(dest + 5 * 2, p + 14, 6 * 2);
+ memcpy(dest + 11 * 2, p + 28, 2 * 2);
+ if (isLast)
+ checkSum = p[13];
+ if (checkSum == p[13])
+ is_record_error = false;
+ // else return S_FALSE;
+ continue;
+ }
+ // else
+ checkSum = -1; // we will ignore LfnBuf in this case
+ continue;
}
- else if (isLast || numLongRecords != longIndex)
- return S_FALSE;
-
- numLongRecords--;
- if (p[12] == 0)
+ if (lfn_RecordIndex)
{
- wchar_t nameBuf[14];
- wchar_t *dest;
-
- dest = AddSubStringToName(nameBuf, p + 1, 5);
- dest = AddSubStringToName(dest, p + 14, 6);
- AddSubStringToName(dest, p + 28, 2);
- curName = nameBuf + curName;
- if (isLast)
- checkSum = p[13];
- if (checkSum != p[13])
- return S_FALSE;
+ Header.HeadersWarning = true;
+ // return S_FALSE;
}
- }
- else
- {
- if (numLongRecords > 0)
- return S_FALSE;
- CItem item;
- memcpy(item.DosName, p, 11);
+ // lfn_RecordIndex = 0;
- if (checkSum >= 0)
+ const unsigned type_in_attrib = attrib & 0x18;
+ if (type_in_attrib == 0x18)
{
- Byte sum = 0;
- for (unsigned i = 0; i < 11; i++)
- sum = (Byte)(((sum & 1) ? 0x80 : 0) + (sum >> 1) + (Byte)item.DosName[i]);
- if (sum == checkSum)
- item.UName = curName;
+ // invalid directory record (both flags are set: dir_flag and volume_flag)
+ return S_FALSE;
+ // break;
+ // continue;
}
-
- if (item.DosName[0] == 5)
- item.DosName[0] = (char)(Byte)0xE5;
- item.Attrib = attrib;
- item.Flags = p[12];
- item.Size = Get32(p + 28);
- item.Cluster = Get16(p + 26);
- if (Header.NumFatBits > 16)
- item.Cluster |= ((UInt32)Get16(p + 20) << 16);
- else
+ if (type_in_attrib == 8) // volume_flag
{
- // OS/2 and WinNT probably can store EA (extended atributes) in that field.
+ if (!VolItem_Defined && level == 0)
+ {
+ VolItem_Defined = true;
+ memcpy(VolLabel, p, 11);
+ Vol_MTime = Get32(p + 22);
+ is_record_error = false;
+ }
}
-
- item.CTime = Get32(p + 14);
- item.CTime2 = p[13];
- item.ADate = Get16(p + 18);
- item.MTime = Get32(p + 22);
- item.Parent = parent;
-
- if (attrib == 8)
+ else if (memcmp(p, ". ", 11) == 0
+ || memcmp(p, ".. ", 11) == 0)
{
- VolItem = item;
- VolItemDefined = true;
+ if (num_lfn_records == 0 && type_in_attrib == 0x10) // dir_flag
+ is_record_error = false;
}
else
- if (memcmp(item.DosName, ". ", 11) != 0 &&
- memcmp(item.DosName, ".. ", 11) != 0)
{
- if (!item.IsDir())
- NumCurUsedBytes += Header.GetFilePackSize(item.Size);
- Items.Add(item);
- PRF(printf("\n%7d: %S", Items.Size(), GetItemPath(Items.Size() - 1)));
+ CItem &item = Items.AddNew();
+ memcpy(item.DosName, p, 11);
+ if (item.DosName[0] == 5)
+ item.DosName[0] = (char)(Byte)0xE5; // 0xE5 is valid KANJI lead byte value.
+ item.Attrib = attrib;
+ item.Flags = p[12];
+ item.Size = Get32a(p + 28);
+ item.Cluster = Get16a(p + 26);
+ if (Header.NumFatBits > 16)
+ item.Cluster |= ((UInt32)Get16a(p + 20) << 16);
+ else
+ {
+ // OS/2 and WinNT probably can store EA (extended atributes) in that field.
+ }
+ item.CTime = Get32(p + 14);
+ item.CTime2 = p[13];
+ item.ADate = Get16a(p + 18);
+ item.MTime = Get32(p + 22);
+ item.Parent = parent;
+ {
+ if (!item.IsDir())
+ NumCurUsedBytes += Header.GetFilePackSize(item.Size);
+ // PRF(printf("\n%7d: %S", Items.Size(), GetItemPath(Items.Size() - 1)));
+ PRF(printf("\n%7d" /* ": %S" */, Items.Size() /* , item.GetShortName() */ );)
+ }
+ if (num_lfn_records == 0)
+ is_record_error = false;
+ else if (checkSum >= 0 && lfn_RecordIndex == 0)
+ {
+ Byte sum = 0;
+ for (unsigned i = 0; i < 11; i++)
+ sum = (Byte)((sum << 7) + (sum >> 1) + (Byte)item.DosName[i]);
+ if (sum == checkSum)
+ {
+ const unsigned numWords = ParseLongName((UInt16 *)(void *)(Byte *)LfnBuf,
+ num_lfn_records * k_NumLfnBytes_in_Record / 2);
+ if (numWords > 1)
+ {
+ // numWords includes NULL terminator
+ item.LongName.CopyFrom(LfnBuf, numWords * 2);
+ is_record_error = false;
+ }
+ }
+ }
+
+ if (
+ // item.LongName.Size() < 20 || // for debug
+ item.LongName.Size() <= 2 * 1
+ && memcmp(p, " ", 11) == 0)
+ {
+ char s[16 + 16];
+ const size_t numChars = (size_t)(ConvertUInt32ToString(
+ Items.Size() - 1 - startIndex,
+ MyStpCpy(s, "[NONAME]-")) - s) + 1;
+ item.LongName.Alloc(numChars * 2);
+ for (size_t i = 0; i < numChars; i++)
+ {
+ SetUi16a(item.LongName + i * 2, (Byte)s[i])
+ }
+ Header.HeadersWarning = true;
+ }
}
- numLongRecords = -1;
- curName.Empty();
- checkSum = -1;
+ num_lfn_records = 0;
}
}
- unsigned finishIndex = Items.Size();
+ if (is_record_error)
+ Header.HeadersWarning = true;
+
+ const unsigned finishIndex = Items.Size();
for (unsigned i = startIndex; i < finishIndex; i++)
{
const CItem &item = Items[i];
if (item.IsDir())
{
- PRF(printf("\n%S", GetItemPath(i)));
- RINOK(CDatabase::ReadDir((int)i, item.Cluster, level + 1))
+ PRF(printf("\n---- %c%c%c%c%c", item.DosName[0], item.DosName[1], item.DosName[2], item.DosName[3], item.DosName[4]));
+ RINOK(ReadDir((int)i, item.Cluster, level + 1))
}
}
return S_OK;
}
+
+
HRESULT CDatabase::Open()
{
Clear();
- bool numFreeClustersDefined = false;
+ bool numFreeClusters_Defined = false;
{
- Byte buf[kHeaderSize];
- RINOK(ReadStream_FALSE(InStream, buf, kHeaderSize))
- if (!Header.Parse(buf))
+ UInt32 buf32[kHeaderSize / 4];
+ RINOK(ReadStream_FALSE(InStream, buf32, kHeaderSize))
+ if (!Header.Parse((Byte *)(void *)buf32))
return S_FALSE;
UInt64 fileSize;
RINOK(InStream_GetSize_SeekToEnd(InStream, fileSize))
@@ -671,21 +812,21 @@
{
if (((UInt32)Header.FsInfoSector << Header.SectorSizeLog) + kHeaderSize <= fileSize
&& SeekToSector(Header.FsInfoSector) == S_OK
- && ReadStream_FALSE(InStream, buf, kHeaderSize) == S_OK
- && 0xaa550000 == Get32(buf + 508)
- && 0x41615252 == Get32(buf)
- && 0x61417272 == Get32(buf + 484))
+ && ReadStream_FALSE(InStream, buf32, kHeaderSize) == S_OK
+ && 0xaa550000 == Get32a(buf32 + 508 / 4)
+ && 0x41615252 == Get32a(buf32)
+ && 0x61417272 == Get32a(buf32 + 484 / 4))
{
- NumFreeClusters = Get32(buf + 488);
- numFreeClustersDefined = (NumFreeClusters <= Header.FatSize);
+ NumFreeClusters = Get32a(buf32 + 488 / 4);
+ numFreeClusters_Defined = (NumFreeClusters <= Header.FatSize);
}
else
Header.HeadersWarning = true;
}
}
- // numFreeClustersDefined = false; // to recalculate NumFreeClusters
- if (!numFreeClustersDefined)
+ // numFreeClusters_Defined = false; // to recalculate NumFreeClusters
+ if (!numFreeClusters_Defined)
NumFreeClusters = 0;
CByteBuffer byteBuf;
@@ -695,7 +836,7 @@
RINOK(SeekToSector(Header.GetFatSector()))
if (Header.NumFatBits == 32)
{
- const UInt32 kBufSize = (1 << 15);
+ const UInt32 kBufSize = 1 << 15;
byteBuf.Alloc(kBufSize);
for (UInt32 i = 0;;)
{
@@ -712,7 +853,7 @@
const UInt32 *src = (const UInt32 *)(const void *)(const Byte *)byteBuf;
UInt32 *dest = Fat + i;
const UInt32 *srcLim = src + size;
- if (numFreeClustersDefined)
+ if (numFreeClusters_Defined)
do
*dest++ = Get32a(src) & 0x0FFFFFFF;
while (++src != srcLim);
@@ -731,7 +872,7 @@
i += size;
if ((i & 0xFFFFF) == 0)
{
- RINOK(OpenProgressFat(!numFreeClustersDefined))
+ RINOK(OpenProgressFat(!numFreeClusters_Defined))
}
}
}
@@ -751,7 +892,7 @@
for (UInt32 j = 0; j < fatSize; j++)
fat[j] = (Get16(p + j * 3 / 2) >> ((j & 1) << 2)) & 0xFFF;
- if (!numFreeClustersDefined)
+ if (!numFreeClusters_Defined)
{
UInt32 numFreeClusters = 0;
for (UInt32 i = 0; i < fatSize; i++)
@@ -781,11 +922,12 @@
Z7_class_CHandler_final:
public IInArchive,
+ public IArchiveGetRawProps,
public IInArchiveGetStream,
public CMyUnknownImp,
CDatabase
{
- Z7_IFACES_IMP_UNK_2(IInArchive, IInArchiveGetStream)
+ Z7_IFACES_IMP_UNK_3(IInArchive, IArchiveGetRawProps, IInArchiveGetStream)
};
Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream))
@@ -831,6 +973,8 @@
COM_TRY_END
}
+
+
static const Byte kProps[] =
{
kpidPath,
@@ -842,6 +986,7 @@
kpidATime,
kpidAttrib,
kpidShortName
+ // , kpidCharacts
};
enum
@@ -922,15 +1067,16 @@
case kpidPhySize: prop = PhySize; break;
case kpidFreeSpace: prop = (UInt64)NumFreeClusters << Header.ClusterSizeLog; break;
case kpidHeadersSize: prop = GetHeadersSize(); break;
- case kpidMTime: if (VolItemDefined) PropVariant_SetFrom_DosTime(prop, VolItem.MTime); break;
+ case kpidMTime: if (VolItem_Defined) PropVariant_SetFrom_DosTime(prop, Vol_MTime); break;
case kpidShortComment:
- case kpidVolumeName: if (VolItemDefined) prop = VolItem.GetVolName(); break;
+ case kpidVolumeName: if (VolItem_Defined) GetVolName(VolLabel, prop); break;
case kpidNumFats: if (Header.NumFats != 2) prop = Header.NumFats; break;
case kpidSectorSize: prop = (UInt32)1 << Header.SectorSizeLog; break;
// case kpidSectorsPerTrack: prop = Header.SectorsPerTrack; break;
// case kpidNumHeads: prop = Header.NumHeads; break;
// case kpidOemName: STRING_TO_PROP(Header.OemName, prop); break;
case kpidId: if (Header.VolFieldsDefined) prop = Header.VolId; break;
+ case kpidIsTree: prop = true; break;
// case kpidVolName: if (Header.VolFieldsDefined) STRING_TO_PROP(Header.VolName, prop); break;
// case kpidFileSysType: if (Header.VolFieldsDefined) STRING_TO_PROP(Header.FileSys, prop); break;
// case kpidHiddenSectors: prop = Header.NumHiddenSectors; break;
@@ -948,6 +1094,52 @@
COM_TRY_END
}
+
+Z7_COM7F_IMF(CHandler::GetNumRawProps(UInt32 *numProps))
+{
+ *numProps = 0;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetRawPropInfo(UInt32 /* index */ , BSTR *name, PROPID *propID))
+{
+ *name = NULL;
+ *propID = 0;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetParent(UInt32 index, UInt32 *parent, UInt32 *parentType))
+{
+ *parentType = NParentType::kDir;
+ int par = -1;
+ if (index < Items.Size())
+ par = Items[index].Parent;
+ *parent = (UInt32)(Int32)par;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType))
+{
+ *data = NULL;
+ *dataSize = 0;
+ *propType = 0;
+
+ if (index < Items.Size()
+ && propID == kpidName)
+ {
+ CByteBuffer &buf = Items[index].LongName;
+ const UInt32 size = (UInt32)buf.Size();
+ if (size != 0)
+ {
+ *dataSize = size;
+ *propType = NPropDataType::kUtf16z;
+ *data = (const void *)(const Byte *)buf;
+ }
+ }
+ return S_OK;
+}
+
+
Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
{
COM_TRY_BEGIN
@@ -955,8 +1147,28 @@
const CItem &item = Items[index];
switch (propID)
{
- case kpidPath: prop = GetItemPath(index); break;
- case kpidShortName: prop = item.GetShortName(); break;
+ case kpidPath:
+ case kpidName:
+ case kpidShortName:
+ {
+ UString s;
+ if (propID == kpidPath)
+ GetItemPath(index, s);
+ else if (propID == kpidName)
+ item.GetName(s);
+ else
+ item.GetShortName(s);
+ prop = s;
+ break;
+ }
+/*
+ case kpidCharacts:
+ {
+ if (item.LongName.Size())
+ prop = "LFN";
+ break;
+ }
+*/
case kpidIsDir: prop = item.IsDir(); break;
case kpidMTime: PropVariant_SetFrom_DosTime(prop, item.MTime); break;
case kpidCTime: FatTimeToProp(item.CTime, item.CTime2, prop); break;
@@ -1004,34 +1216,44 @@
Int32 testMode, IArchiveExtractCallback *extractCallback))
{
COM_TRY_BEGIN
- const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
- if (allFilesMode)
+ if (numItems == (UInt32)(Int32)-1)
+ {
+ indices = NULL;
numItems = Items.Size();
- if (numItems == 0)
- return S_OK;
- UInt32 i;
+ if (numItems == 0)
+ return S_OK;
+ }
+ else
+ {
+ if (numItems == 0)
+ return S_OK;
+ if (!indices)
+ return E_INVALIDARG;
+ }
UInt64 totalSize = 0;
- for (i = 0; i < numItems; i++)
{
- const CItem &item = Items[allFilesMode ? i : indices[i]];
- if (!item.IsDir())
- totalSize += item.Size;
+ UInt32 i = 0;
+ do
+ {
+ UInt32 index = i;
+ if (indices)
+ index = indices[i];
+ const CItem &item = Items[index];
+ if (!item.IsDir())
+ totalSize += item.Size;
+ }
+ while (++i != numItems);
}
RINOK(extractCallback->SetTotal(totalSize))
- UInt64 totalPackSize;
- totalSize = totalPackSize = 0;
-
- NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
- CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
-
- CLocalProgress *lps = new CLocalProgress;
- CMyComPtr<ICompressProgressInfo> progress = lps;
+ CMyComPtr2_Create<ICompressProgressInfo, CLocalProgress> lps;
lps->Init(extractCallback, false);
+ CMyComPtr2_Create<ICompressCoder, NCompress::CCopyCoder> copyCoder;
- CDummyOutStream *outStreamSpec = new CDummyOutStream;
- CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+ UInt64 totalPackSize;
+ totalSize = totalPackSize = 0;
+ UInt32 i;
for (i = 0;; i++)
{
lps->InSize = totalPackSize;
@@ -1039,46 +1261,45 @@
RINOK(lps->SetCur())
if (i == numItems)
break;
- CMyComPtr<ISequentialOutStream> realOutStream;
- const Int32 askMode = testMode ?
- NExtract::NAskMode::kTest :
- NExtract::NAskMode::kExtract;
- const UInt32 index = allFilesMode ? i : indices[i];
- const CItem &item = Items[index];
- RINOK(extractCallback->GetStream(index, &realOutStream, askMode))
-
- if (item.IsDir())
+ int res;
{
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ const Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ UInt32 index = i;
+ if (indices)
+ index = indices[i];
+ const CItem &item = Items[index];
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode))
+
+ if (item.IsDir())
+ {
+ RINOK(extractCallback->PrepareOperation(askMode))
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
+ continue;
+ }
+
+ totalPackSize += Header.GetFilePackSize(item.Size);
+ totalSize += item.Size;
+
+ if (!testMode && !realOutStream)
+ continue;
RINOK(extractCallback->PrepareOperation(askMode))
- RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
- continue;
- }
-
- totalPackSize += Header.GetFilePackSize(item.Size);
- totalSize += item.Size;
-
- if (!testMode && !realOutStream)
- continue;
- RINOK(extractCallback->PrepareOperation(askMode))
-
- outStreamSpec->SetStream(realOutStream);
- realOutStream.Release();
- outStreamSpec->Init();
-
- int res = NExtract::NOperationResult::kDataError;
- CMyComPtr<ISequentialInStream> inStream;
- HRESULT hres = GetStream(index, &inStream);
- if (hres != S_FALSE)
- {
- RINOK(hres)
- if (inStream)
+ res = NExtract::NOperationResult::kDataError;
+ CMyComPtr<ISequentialInStream> inStream;
+ const HRESULT hres = GetStream(index, &inStream);
+ if (hres != S_FALSE)
{
- RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress))
- if (copyCoderSpec->TotalSize == item.Size)
- res = NExtract::NOperationResult::kOK;
+ RINOK(hres)
+ if (inStream)
+ {
+ RINOK(copyCoder.Interface()->Code(inStream, realOutStream, NULL, NULL, lps))
+ if (copyCoder->TotalSize == item.Size)
+ res = NExtract::NOperationResult::kOK;
+ }
}
}
- outStreamSpec->ReleaseStream();
RINOK(extractCallback->SetOperationResult(res))
}
return S_OK;
diff -Nru 7zip-24.09+dfsg/CPP/7zip/Archive/Nsis/NsisIn.cpp 7zip-25.00+dfsg/CPP/7zip/Archive/Nsis/NsisIn.cpp
--- 7zip-24.09+dfsg/CPP/7zip/Archive/Nsis/NsisIn.cpp 2023-12-11 12:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/7zip/Archive/Nsis/NsisIn.cpp 2025-06-16 10:00:00.000000000 +0200
@@ -4005,7 +4005,7 @@
AddParam_Var(params[0]);
AString temp;
ReadString2(temp, params[1]);
- if (temp != "$TEMP")
+ if (!temp.IsEqualTo("$TEMP"))
SpaceQuStr(temp);
break;
}
@@ -4410,7 +4410,7 @@
}
else
{
- if (func == "DllUnregisterServer")
+ if (func.IsEqualTo("DllUnregisterServer"))
{
s += "UnRegDLL";
printFunc = false;
@@ -4418,7 +4418,7 @@
else
{
s += "RegDLL";
- if (func == "DllRegisterServer")
+ if (func.IsEqualTo("DllRegisterServer"))
printFunc = false;
}
AddParam(params[0]);
@@ -4886,7 +4886,7 @@
AddParam_Var(params[1]);
AddParam(params[2]);
AddParam(params[4]);
- // if (params[2] == "0") AddCommentAndString("GetWinVer");
+ // if (params[2].IsEqualTo("0")) AddCommentAndString("GetWinVer");
}
else
s += "GetOsInfo";
diff -Nru 7zip-24.09+dfsg/CPP/7zip/Archive/NtfsHandler.cpp 7zip-25.00+dfsg/CPP/7zip/Archive/NtfsHandler.cpp
--- 7zip-24.09+dfsg/CPP/7zip/Archive/NtfsHandler.cpp 2024-03-28 19:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/7zip/Archive/NtfsHandler.cpp 2025-06-16 10:00:00.000000000 +0200
@@ -1907,7 +1907,7 @@
for (i = 0; i < SecurityAttrs.Size(); i++)
{
const CAttr &attr = SecurityAttrs[i];
- if (attr.Name == L"$SII")
+ if (attr.Name.IsEqualTo("$SII"))
{
if (attr.Type == ATTR_TYPE_INDEX_ROOT)
{
diff -Nru 7zip-24.09+dfsg/CPP/7zip/Archive/PeHandler.cpp 7zip-25.00+dfsg/CPP/7zip/Archive/PeHandler.cpp
--- 7zip-24.09+dfsg/CPP/7zip/Archive/PeHandler.cpp 2024-07-12 11:00:00.000000000 +0200
+++ 7zip-25.00+dfsg/CPP/7zip/Archive/PeHandler.cpp 2025-06-16 09:00:00.000000000 +0200
@@ -2638,7 +2638,7 @@
{
const CSection § = _sections[i];
if (IsOpt())
- if (_parseResources && sect.Name == ".rsrc")
+ if (_parseResources && sect.Name.IsEqualTo(".rsrc"))
{
// 20.01: we try to parse only first copy of .rsrc section.
_parseResources = false;
@@ -2727,7 +2727,7 @@
for (i = 0; i < _mixItems.Size(); i++)
{
const CMixItem &mixItem = _mixItems[i];
- if (mixItem.StringIndex < 0 && mixItem.ResourceIndex < 0 && _sections[mixItem.SectionIndex].Name == "_winzip_")
+ if (mixItem.StringIndex < 0 && mixItem.ResourceIndex < 0 && _sections[mixItem.SectionIndex].Name.IsEqualTo("_winzip_"))
{
_mainSubfile = (Int32)(int)i;
break;
diff -Nru 7zip-24.09+dfsg/CPP/7zip/Archive/Rar/Rar5Handler.cpp 7zip-25.00+dfsg/CPP/7zip/Archive/Rar/Rar5Handler.cpp
--- 7zip-24.09+dfsg/CPP/7zip/Archive/Rar/Rar5Handler.cpp 2024-11-26 12:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/7zip/Archive/Rar/Rar5Handler.cpp 2025-06-18 09:00:00.000000000 +0200
@@ -393,6 +393,7 @@
if (!FindExtra_Link(link))
return;
+ bool isWindows = (HostOS == kHost_Windows);
if (link.Type != linkType)
{
if (linkType != NLinkType::kUnixSymLink)
@@ -400,8 +401,11 @@
switch ((unsigned)link.Type)
{
case NLinkType::kUnixSymLink:
+ isWindows = false;
+ break;
case NLinkType::kWinSymLink:
case NLinkType::kWinJunction:
+ isWindows = true;
break;
default: return;
}
@@ -409,10 +413,15 @@
AString s;
s.SetFrom_CalcLen((const char *)(Extra + link.NameOffset), link.NameLen);
-
UString unicode;
ConvertUTF8ToUnicode(s, unicode);
- prop = NItemName::GetOsPath(unicode);
+ // rar5.0 used '\\' separator for windows symlinks and \??\ prefix for abs paths.
+ // rar5.1+ uses '/' separator for windows symlinks and /??/ prefix for abs paths.
+ // v25.00: we convert Windows slashes to Linux slashes:
+ if (isWindows)
+ unicode.Replace(L'\\', L'/');
+ prop = unicode;
+ // prop = NItemName::GetOsPath(unicode);
}
bool CItem::GetAltStreamName(AString &name) const
diff -Nru 7zip-24.09+dfsg/CPP/7zip/Archive/Rar/Rar5Handler.h 7zip-25.00+dfsg/CPP/7zip/Archive/Rar/Rar5Handler.h
--- 7zip-24.09+dfsg/CPP/7zip/Archive/Rar/Rar5Handler.h 2024-03-18 15:42:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/7zip/Archive/Rar/Rar5Handler.h 2025-06-16 12:00:00.000000000 +0200
@@ -286,10 +286,10 @@
bool IsService() const { return RecordType == NHeaderType::kService; }
- bool Is_STM() const { return IsService() && Name == "STM"; }
- bool Is_CMT() const { return IsService() && Name == "CMT"; }
- bool Is_ACL() const { return IsService() && Name == "ACL"; }
- // bool Is_QO() const { return IsService() && Name == "QO"; }
+ bool Is_STM() const { return IsService() && Name.IsEqualTo("STM"); }
+ bool Is_CMT() const { return IsService() && Name.IsEqualTo("CMT"); }
+ bool Is_ACL() const { return IsService() && Name.IsEqualTo("ACL"); }
+ // bool Is_QO() const { return IsService() && Name.IsEqualTo("QO"); }
int FindExtra(unsigned extraID, unsigned &recordDataSize) const;
void PrintInfo(AString &s) const;
diff -Nru 7zip-24.09+dfsg/CPP/7zip/Archive/Rar/RarHandler.cpp 7zip-25.00+dfsg/CPP/7zip/Archive/Rar/RarHandler.cpp
--- 7zip-24.09+dfsg/CPP/7zip/Archive/Rar/RarHandler.cpp 2023-03-06 17:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/7zip/Archive/Rar/RarHandler.cpp 2025-06-16 10:00:00.000000000 +0200
@@ -435,13 +435,13 @@
size -= sizeof(item.Salt);
p += sizeof(item.Salt);
}
- if (item.Name == "ACL" && size == 0)
+ if (item.Name.IsEqualTo("ACL") && size == 0)
{
item.IsAltStream = true;
item.Name.Empty();
item.UnicodeName.SetFromAscii(".ACL");
}
- else if (item.Name == "STM" && size != 0 && (size & 1) == 0)
+ else if (item.Name.IsEqualTo("STM") && size != 0 && (size & 1) == 0)
{
item.IsAltStream = true;
item.Name.Empty();
diff -Nru 7zip-24.09+dfsg/CPP/7zip/Archive/RpmHandler.cpp 7zip-25.00+dfsg/CPP/7zip/Archive/RpmHandler.cpp
--- 7zip-24.09+dfsg/CPP/7zip/Archive/RpmHandler.cpp 2023-12-18 18:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/7zip/Archive/RpmHandler.cpp 2025-06-16 09:00:00.000000000 +0200
@@ -330,11 +330,11 @@
if (!_compressor.IsEmpty())
{
s = _compressor;
- if (_compressor == "bzip2")
+ if (_compressor.IsEqualTo("bzip2"))
s = "bz2";
- else if (_compressor == "gzip")
+ else if (_compressor.IsEqualTo("gzip"))
s = "gz";
- else if (_compressor == "zstd")
+ else if (_compressor.IsEqualTo("zstd"))
s = "zst";
}
else
diff -Nru 7zip-24.09+dfsg/CPP/7zip/Archive/VmdkHandler.cpp 7zip-25.00+dfsg/CPP/7zip/Archive/VmdkHandler.cpp
--- 7zip-24.09+dfsg/CPP/7zip/Archive/VmdkHandler.cpp 2023-09-07 10:00:00.000000000 +0200
+++ 7zip-25.00+dfsg/CPP/7zip/Archive/VmdkHandler.cpp 2025-06-16 11:00:00.000000000 +0200
@@ -202,9 +202,12 @@
// PartitionUUID
// DeviceIdentifier
- bool IsType_ZERO() const { return Type == "ZERO"; }
- // bool IsType_FLAT() const { return Type == "FLAT"; }
- bool IsType_Flat() const { return Type == "FLAT" || Type == "VMFS" || Type == "VMFSRAW"; }
+ bool IsType_ZERO() const { return Type.IsEqualTo("ZERO"); }
+ // bool IsType_FLAT() const { return Type.IsEqualTo("FLAT"); }
+ bool IsType_Flat() const
+ { return Type.IsEqualTo("FLAT")
+ || Type.IsEqualTo("VMFS")
+ || Type.IsEqualTo("VMFSRAW"); }
bool Parse(const char *s);
};
diff -Nru 7zip-24.09+dfsg/CPP/7zip/Archive/Wim/WimIn.cpp 7zip-25.00+dfsg/CPP/7zip/Archive/Wim/WimIn.cpp
--- 7zip-24.09+dfsg/CPP/7zip/Archive/Wim/WimIn.cpp 2024-01-01 10:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/7zip/Archive/Wim/WimIn.cpp 2025-06-16 09:00:00.000000000 +0200
@@ -1814,7 +1814,7 @@
if (!Xml.Parse(utf))
return false;
- if (Xml.Root.Name != "WIM")
+ if (!Xml.Root.Name.IsEqualTo("WIM"))
return false;
FOR_VECTOR (i, Xml.Root.SubItems)
diff -Nru 7zip-24.09+dfsg/CPP/7zip/Archive/XarHandler.cpp 7zip-25.00+dfsg/CPP/7zip/Archive/XarHandler.cpp
--- 7zip-24.09+dfsg/CPP/7zip/Archive/XarHandler.cpp 2024-11-12 12:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/7zip/Archive/XarHandler.cpp 2025-06-16 09:00:00.000000000 +0200
@@ -266,7 +266,7 @@
bool IsCopyMethod() const
{
- return Method.IsEmpty() || Method == "octet-stream";
+ return Method.IsEmpty() || Method.IsEqualTo("octet-stream");
}
void UpdateTotalPackSize(UInt64 &totalSize) const
@@ -416,7 +416,7 @@
return true;
if (level >= 1024)
return false;
- if (item.Name == "file")
+ if (item.Name.IsEqualTo("file"))
{
CFile file(parent);
parent = (int)files.Size();
@@ -435,19 +435,19 @@
{
file.Type = typeItem->GetSubString();
// file.LinkFrom = typeItem->GetPropVal("link");
- if (file.Type == "directory")
+ if (file.Type.IsEqualTo("directory"))
file.IsDir = true;
else
{
// file.IsDir = false;
/*
- else if (file.Type == "file")
+ else if (file.Type.IsEqualTo("file"))
{}
- else if (file.Type == "hardlink")
+ else if (file.Type.IsEqualTo("hardlink"))
{}
else
*/
- if (file.Type == "symlink")
+ if (file.Type.IsEqualTo("symlink"))
file.Is_SymLink = true;
// file.IsDir = false;
}
@@ -489,7 +489,7 @@
if (s.IsPrefixedBy(xx))
{
s.DeleteFrontal(xx.Len());
- if (s == "gzip")
+ if (s.IsEqualTo("gzip"))
s = METHOD_NAME_ZLIB;
}
}
@@ -692,12 +692,13 @@
file.UpdateTotalPackSize(totalPackSize);
if (file.Parent == -1)
{
- if (file.Name == "Payload" || file.Name == "Content")
+ if (file.Name.IsEqualTo("Payload") ||
+ file.Name.IsEqualTo("Content"))
{
_mainSubfile = (Int32)(int)i;
numMainFiles++;
}
- else if (file.Name == "PackageInfo")
+ else if (file.Name.IsEqualTo("PackageInfo"))
_is_pkg = true;
}
}
@@ -1210,9 +1211,9 @@
else
opRes = NExtract::NOperationResult::kUnsupportedMethod;
}
- else if (item.Method == METHOD_NAME_ZLIB)
+ else if (item.Method.IsEqualTo(METHOD_NAME_ZLIB))
coder = zlibCoder;
- else if (item.Method == "bzip2")
+ else if (item.Method.IsEqualTo("bzip2"))
coder = bzip2Coder;
else
opRes = NExtract::NOperationResult::kUnsupportedMethod;
diff -Nru 7zip-24.09+dfsg/CPP/7zip/Archive/XzHandler.cpp 7zip-25.00+dfsg/CPP/7zip/Archive/XzHandler.cpp
--- 7zip-24.09+dfsg/CPP/7zip/Archive/XzHandler.cpp 2024-10-02 10:00:00.000000000 +0200
+++ 7zip-25.00+dfsg/CPP/7zip/Archive/XzHandler.cpp 2025-07-03 13:00:00.000000000 +0200
@@ -446,7 +446,7 @@
struct CXzsCPP
{
CXzs p;
- CXzsCPP() { Xzs_Construct(&p); }
+ CXzsCPP() { Xzs_CONSTRUCT(&p) }
~CXzsCPP() { Xzs_Free(&p, &g_Alloc); }
};
@@ -536,6 +536,9 @@
if (res2 == SZ_ERROR_ARCHIVE)
return S_FALSE;
+ // what codes are possible here ?
+ // ?? res2 == SZ_ERROR_MEM : is possible here
+ // ?? res2 == SZ_ERROR_UNSUPPORTED : is possible here
}
else if (!isIndex)
{
@@ -1159,6 +1162,13 @@
*/
#ifndef Z7_ST
+
+#ifdef _WIN32
+ // we don't use chunk multithreading inside lzma2 stream.
+ // so we don't set xzProps.lzma2Props.numThreadGroups.
+ if (_numThreadGroups > 1)
+ xzProps.numThreadGroups = _numThreadGroups;
+#endif
UInt32 numThreads = _numThreads;
@@ -1183,6 +1193,8 @@
CMultiMethodProps::SetMethodThreadsTo_IfNotFinded(oneMethodInfo, numThreads);
}
+ // printf("\n====== GetProcessGroupAffinity : \n");
+
UInt64 cs = _numSolidBytes;
if (cs != XZ_PROPS_BLOCK_SIZE_AUTO)
oneMethodInfo.AddProp_BlockSize2(cs);
diff -Nru 7zip-24.09+dfsg/CPP/7zip/Archive/Zip/ZipUpdate.cpp 7zip-25.00+dfsg/CPP/7zip/Archive/Zip/ZipUpdate.cpp
--- 7zip-24.09+dfsg/CPP/7zip/Archive/Zip/ZipUpdate.cpp 2024-08-09 12:00:00.000000000 +0200
+++ 7zip-25.00+dfsg/CPP/7zip/Archive/Zip/ZipUpdate.cpp 2025-07-03 11:00:00.000000000 +0200
@@ -250,13 +250,26 @@
HRESULT CreateEvents()
{
- WRes wres = CompressEvent.CreateIfNotCreated_Reset();
+ const WRes wres = CompressEvent.CreateIfNotCreated_Reset();
return HRESULT_FROM_WIN32(wres);
}
- HRESULT CreateThread()
+ // (group < 0) means no_group.
+ HRESULT CreateThread_with_group(
+#ifdef _WIN32
+ int group
+#endif
+ )
{
- WRes wres = Thread.Create(CoderThread, this);
+ // tested in win10: If thread is created by another thread,
+ // child thread probably uses same group as parent thread.
+ // So we don't need to send (group) to encoder in created thread.
+ const WRes wres =
+#ifdef _WIN32
+ group >= 0 ?
+ Thread.Create_With_Group(CoderThread, this, (unsigned)group) :
+#endif
+ Thread.Create(CoderThread, this);
return HRESULT_FROM_WIN32(wres);
}
@@ -450,8 +463,12 @@
if (ui.NewProps)
{
if (item.HasDescriptor())
- return E_NOTIMPL;
-
+ {
+ // we know compressed / uncompressed sizes and crc.
+ // so we remove descriptor here
+ item.Flags = (UInt16)(item.Flags & ~NFileHeader::NFlags::kDescriptorUsedMask);
+ // return E_NOTIMPL;
+ }
// we keep ExternalAttrib and some another properties from old archive
// item.ExternalAttrib = ui.Attrib;
// if we don't change Comment, we keep Comment from OldProperties
@@ -1000,6 +1017,9 @@
#ifndef Z7_ST
UInt32 numThreads = options._numThreads;
+#ifdef _WIN32
+ const UInt32 numThreadGroups = options._numThreadGroups;
+#endif
UInt32 numZipThreads_limit = numThreads;
if (numZipThreads_limit > numFilesToCompress)
@@ -1014,12 +1034,10 @@
}
{
+ // we reduce number of threads for 32-bit to reduce memory usege to 256 MB
const UInt32 kNumMaxThreads =
- #ifdef _WIN32
- 64; // _WIN32 supports only 64 threads in one group. So no need for more threads here
- #else
- 128;
- #endif
+ // _WIN32 (64-bit) supports only 64 threads in one group.
+ 8 << (sizeof(size_t) / 2); // 32 threads for 32-bit : 128 threads for 64-bit
if (numThreads > kNumMaxThreads)
numThreads = kNumMaxThreads;
}
@@ -1264,7 +1282,14 @@
threadInfo.Progress = threadInfo.ProgressSpec;
threadInfo.ProgressSpec->Init(&mtCompressProgressMixer, i);
threadInfo.MtSem = &mtSem;
- RINOK(threadInfo.CreateThread())
+ const HRESULT hres =
+ threadInfo.CreateThread_with_group(
+#ifdef _WIN32
+ (numThreadGroups > 1 && numThreads > 1) ?
+ (int)(i % numThreadGroups) : -1
+#endif
+ );
+ RINOK(hres)
}
}
diff -Nru 7zip-24.09+dfsg/CPP/7zip/Bundles/Alone/makefile 7zip-25.00+dfsg/CPP/7zip/Bundles/Alone/makefile
--- 7zip-24.09+dfsg/CPP/7zip/Bundles/Alone/makefile 2024-01-29 12:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/7zip/Bundles/Alone/makefile 2025-07-02 09:00:00.000000000 +0200
@@ -5,6 +5,7 @@
# CONSOLE_VARIANT_FLAGS=-DZ7_PROG_VARIANT_A
# ZIP_FLAGS=-DZ7_ZIP_LZFSE_DISABLE
+# USE_C_SORT=1
# USE_C_AES = 1
# USE_C_SHA = 1
# USE_C_LZFINDOPT = 1
@@ -221,7 +222,6 @@
$O\Ppmd8.obj \
$O\Ppmd8Dec.obj \
$O\Ppmd8Enc.obj \
- $O\Sort.obj \
$O\SwapBytes.obj \
$O\Threads.obj \
$O\Xxh64.obj \
@@ -240,5 +240,6 @@
!include "../../LzmaDec.mak"
!include "../../Sha1.mak"
!include "../../Sha256.mak"
+!include "../../Sort.mak"
!include "../../7zip.mak"
diff -Nru 7zip-24.09+dfsg/CPP/7zip/Bundles/Alone7z/makefile 7zip-25.00+dfsg/CPP/7zip/Bundles/Alone7z/makefile
--- 7zip-24.09+dfsg/CPP/7zip/Bundles/Alone7z/makefile 2024-02-29 09:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/7zip/Bundles/Alone7z/makefile 2025-07-01 17:00:00.000000000 +0200
@@ -148,7 +148,6 @@
$O\LzmaEnc.obj \
$O\MtCoder.obj \
$O\MtDec.obj \
- $O\Sort.obj \
$O\SwapBytes.obj \
$O\Threads.obj \
$O\Xz.obj \
@@ -164,5 +163,6 @@
!include "../../LzFindOpt.mak"
!include "../../LzmaDec.mak"
!include "../../Sha256.mak"
+!include "../../Sort.mak"
!include "../../7zip.mak"
diff -Nru 7zip-24.09+dfsg/CPP/7zip/Bundles/Format7z/makefile 7zip-25.00+dfsg/CPP/7zip/Bundles/Format7z/makefile
--- 7zip-24.09+dfsg/CPP/7zip/Bundles/Format7z/makefile 2024-03-20 08:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/7zip/Bundles/Format7z/makefile 2025-07-01 17:00:00.000000000 +0200
@@ -135,7 +135,6 @@
$O\Ppmd7.obj \
$O\Ppmd7Dec.obj \
$O\Ppmd7Enc.obj \
- $O\Sort.obj \
$O\SwapBytes.obj \
$O\Threads.obj \
@@ -144,5 +143,6 @@
!include "../../LzFindOpt.mak"
!include "../../LzmaDec.mak"
!include "../../Sha256.mak"
+!include "../../Sort.mak"
!include "../../7zip.mak"
diff -Nru 7zip-24.09+dfsg/CPP/7zip/Bundles/Format7zF/Arc.mak 7zip-25.00+dfsg/CPP/7zip/Bundles/Format7zF/Arc.mak
--- 7zip-24.09+dfsg/CPP/7zip/Bundles/Format7zF/Arc.mak 2024-11-25 18:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/7zip/Bundles/Format7zF/Arc.mak 2025-07-01 17:00:00.000000000 +0200
@@ -291,7 +291,6 @@
$O\Sha3.obj \
$O\Sha512.obj \
$O\Sha512Opt.obj \
- $O\Sort.obj \
$O\SwapBytes.obj \
$O\Threads.obj \
$O\Xxh64.obj \
@@ -308,3 +307,4 @@
!include "../../LzmaDec.mak"
!include "../../Sha1.mak"
!include "../../Sha256.mak"
+!include "../../Sort.mak"
diff -Nru 7zip-24.09+dfsg/CPP/7zip/Bundles/SFXSetup/SfxSetup.cpp 7zip-25.00+dfsg/CPP/7zip/Bundles/SFXSetup/SfxSetup.cpp
--- 7zip-24.09+dfsg/CPP/7zip/Bundles/SFXSetup/SfxSetup.cpp 2024-03-20 08:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/7zip/Bundles/SFXSetup/SfxSetup.cpp 2025-06-16 10:00:00.000000000 +0200
@@ -229,7 +229,7 @@
}
const FString tempDirPath = tempDir.GetPath();
- // tempDirPath = L"M:\\1\\"; // to test low disk space
+ // tempDirPath = "M:\\1\\"; // to test low disk space
{
bool isCorrupt = false;
UString errorMessage;
@@ -308,7 +308,7 @@
{
if (appLaunched.IsEmpty())
{
- appLaunched = L"setup.exe";
+ appLaunched = "setup.exe";
if (!NFind::DoesFileExist_FollowLink(us2fs(appLaunched)))
{
if (!assumeYes)
diff -Nru 7zip-24.09+dfsg/CPP/7zip/Common/InBuffer.h 7zip-25.00+dfsg/CPP/7zip/Common/InBuffer.h
--- 7zip-24.09+dfsg/CPP/7zip/Common/InBuffer.h 2023-12-24 14:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/7zip/Common/InBuffer.h 2025-02-20 09:00:00.000000000 +0100
@@ -97,6 +97,16 @@
size_t ReadBytesPart(Byte *buf, size_t size);
size_t ReadBytes(Byte *buf, size_t size);
+ const Byte *Lookahead(size_t &rem)
+ {
+ rem = (size_t)(_bufLim - _buf);
+ if (!rem)
+ {
+ ReadBlock();
+ rem = (size_t)(_bufLim - _buf);
+ }
+ return _buf;
+ }
size_t Skip(size_t size);
};
diff -Nru 7zip-24.09+dfsg/CPP/7zip/Common/MethodProps.cpp 7zip-25.00+dfsg/CPP/7zip/Common/MethodProps.cpp
--- 7zip-24.09+dfsg/CPP/7zip/Common/MethodProps.cpp 2024-02-26 09:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/7zip/Common/MethodProps.cpp 2025-06-28 11:00:00.000000000 +0200
@@ -324,15 +324,22 @@
HRESULT CProps::SetCoderProps(ICompressSetCoderProperties *scp, const UInt64 *dataSizeReduce) const
{
- return SetCoderProps_DSReduce_Aff(scp, dataSizeReduce, NULL);
+ return SetCoderProps_DSReduce_Aff(scp, dataSizeReduce, NULL, NULL, NULL);
}
HRESULT CProps::SetCoderProps_DSReduce_Aff(
ICompressSetCoderProperties *scp,
const UInt64 *dataSizeReduce,
- const UInt64 *affinity) const
-{
- CCoderProps coderProps(Props.Size() + (dataSizeReduce ? 1 : 0) + (affinity ? 1 : 0) );
+ const UInt64 *affinity,
+ const UInt32 *affinityGroup,
+ const UInt64 *affinityInGroup) const
+{
+ CCoderProps coderProps(Props.Size()
+ + (dataSizeReduce ? 1 : 0)
+ + (affinity ? 1 : 0)
+ + (affinityGroup ? 1 : 0)
+ + (affinityInGroup ? 1 : 0)
+ );
FOR_VECTOR (i, Props)
coderProps.AddProp(Props[i]);
if (dataSizeReduce)
@@ -349,6 +356,20 @@
prop.Value = *affinity;
coderProps.AddProp(prop);
}
+ if (affinityGroup)
+ {
+ CProp prop;
+ prop.Id = NCoderPropID::kThreadGroup;
+ prop.Value = *affinityGroup;
+ coderProps.AddProp(prop);
+ }
+ if (affinityInGroup)
+ {
+ CProp prop;
+ prop.Id = NCoderPropID::kAffinityInGroup;
+ prop.Value = *affinityInGroup;
+ coderProps.AddProp(prop);
+ }
return coderProps.SetProps(scp);
}
@@ -409,6 +430,11 @@
{ VT_UI4, "offset" },
{ VT_UI4, "zhb" }
/*
+ , { VT_UI4, "tgn" }, // kNumThreadGroups
+ , { VT_UI4, "tgi" }, // kThreadGroup
+ , { VT_UI8, "tga" }, // kAffinityInGroup
+ */
+ /*
,
// { VT_UI4, "zhc" },
// { VT_UI4, "zhd" },
diff -Nru 7zip-24.09+dfsg/CPP/7zip/Common/MethodProps.h 7zip-25.00+dfsg/CPP/7zip/Common/MethodProps.h
--- 7zip-24.09+dfsg/CPP/7zip/Common/MethodProps.h 2024-11-11 18:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/7zip/Common/MethodProps.h 2025-06-28 11:00:00.000000000 +0200
@@ -80,7 +80,11 @@
}
HRESULT SetCoderProps(ICompressSetCoderProperties *scp, const UInt64 *dataSizeReduce = NULL) const;
- HRESULT SetCoderProps_DSReduce_Aff(ICompressSetCoderProperties *scp, const UInt64 *dataSizeReduce, const UInt64 *affinity) const;
+ HRESULT SetCoderProps_DSReduce_Aff(ICompressSetCoderProperties *scp,
+ const UInt64 *dataSizeReduce,
+ const UInt64 *affinity,
+ const UInt32 *affinityGroup,
+ const UInt64 *affinityInGroup) const;
};
class CMethodProps: public CProps
diff -Nru 7zip-24.09+dfsg/CPP/7zip/Common/OutBuffer.h 7zip-25.00+dfsg/CPP/7zip/Common/OutBuffer.h
--- 7zip-24.09+dfsg/CPP/7zip/Common/OutBuffer.h 2023-12-24 14:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/7zip/Common/OutBuffer.h 2025-02-23 15:00:00.000000000 +0100
@@ -45,6 +45,7 @@
HRESULT Flush() throw();
void FlushWithCheck();
+ Z7_FORCE_INLINE
void WriteByte(Byte b)
{
UInt32 pos = _pos;
@@ -54,10 +55,34 @@
if (pos == _limitPos)
FlushWithCheck();
}
+
void WriteBytes(const void *data, size_t size)
{
- for (size_t i = 0; i < size; i++)
- WriteByte(((const Byte *)data)[i]);
+ while (size)
+ {
+ UInt32 pos = _pos;
+ size_t cur = (size_t)(_limitPos - pos);
+ if (cur >= size)
+ cur = size;
+ size -= cur;
+ Byte *dest = _buf + pos;
+ pos += (UInt32)cur;
+ _pos = pos;
+#if 0
+ memcpy(dest, data, cur);
+ data = (const void *)((const Byte *)data + cur);
+#else
+ const Byte * const lim = (const Byte *)data + cur;
+ do
+ {
+ *dest++ = *(const Byte *)data;
+ data = (const void *)((const Byte *)data + 1);
+ }
+ while (data != lim);
+#endif
+ if (pos == _limitPos)
+ FlushWithCheck();
+ }
}
Byte *GetOutBuffer(size_t &avail)
diff -Nru 7zip-24.09+dfsg/CPP/7zip/Compress/BitlEncoder.h 7zip-25.00+dfsg/CPP/7zip/Compress/BitlEncoder.h
--- 7zip-24.09+dfsg/CPP/7zip/Compress/BitlEncoder.h 2023-01-10 18:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/7zip/Compress/BitlEncoder.h 2025-03-13 14:00:00.000000000 +0100
@@ -33,6 +33,7 @@
_bitPos = 8;
_curByte = 0;
}
+ Z7_FORCE_INLINE
void WriteBits(UInt32 value, unsigned numBits)
{
while (numBits > 0)
diff -Nru 7zip-24.09+dfsg/CPP/7zip/Compress/BitmEncoder.h 7zip-25.00+dfsg/CPP/7zip/Compress/BitmEncoder.h
--- 7zip-24.09+dfsg/CPP/7zip/Compress/BitmEncoder.h 2023-01-10 18:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/7zip/Compress/BitmEncoder.h 2025-02-28 07:00:00.000000000 +0100
@@ -8,8 +8,9 @@
template<class TOutByte>
class CBitmEncoder
{
- unsigned _bitPos;
- Byte _curByte;
+ unsigned _bitPos; // 0 < _bitPos <= 8 : number of non-filled low bits in _curByte
+ unsigned _curByte; // low (_bitPos) bits are zeros
+ // high (8 - _bitPos) bits are filled
TOutByte _stream;
public:
bool Create(UInt32 bufferSize) { return _stream.Create(bufferSize); }
@@ -24,25 +25,65 @@
HRESULT Flush()
{
if (_bitPos < 8)
- WriteBits(0, _bitPos);
+ {
+ _stream.WriteByte((Byte)_curByte);
+ _bitPos = 8;
+ _curByte = 0;
+ }
return _stream.Flush();
}
+
+ // required condition: (value >> numBits) == 0
+ // numBits == 0 is allowed
void WriteBits(UInt32 value, unsigned numBits)
{
- while (numBits > 0)
+ do
{
- if (numBits < _bitPos)
+ unsigned bp = _bitPos;
+ unsigned curByte = _curByte;
+ if (numBits < bp)
{
- _curByte = (Byte)(_curByte | (value << (_bitPos -= numBits)));
+ bp -= numBits;
+ _curByte = curByte | (value << bp);
+ _bitPos = bp;
return;
}
- numBits -= _bitPos;
- UInt32 newBits = (value >> numBits);
- value -= (newBits << numBits);
- _stream.WriteByte((Byte)(_curByte | newBits));
+ numBits -= bp;
+ const UInt32 hi = (value >> numBits);
+ value -= (hi << numBits);
+ _stream.WriteByte((Byte)(curByte | hi));
_bitPos = 8;
_curByte = 0;
}
+ while (numBits);
+ }
+ void WriteByte(unsigned b)
+ {
+ const unsigned bp = _bitPos;
+ const unsigned a = _curByte | (b >> (8 - bp));
+ _curByte = b << bp;
+ _stream.WriteByte((Byte)a);
+ }
+
+ void WriteBytes(const Byte *data, size_t num)
+ {
+ const unsigned bp = _bitPos;
+#if 1 // 1 for optional speed-optimized code branch
+ if (bp == 8)
+ {
+ _stream.WriteBytes(data, num);
+ return;
+ }
+#endif
+ unsigned c = _curByte;
+ const unsigned bp_rev = 8 - bp;
+ for (size_t i = 0; i < num; i++)
+ {
+ const unsigned b = data[i];
+ _stream.WriteByte((Byte)(c | (b >> bp_rev)));
+ c = b << bp;
+ }
+ _curByte = c;
}
};
diff -Nru 7zip-24.09+dfsg/CPP/7zip/Compress/BZip2Const.h 7zip-25.00+dfsg/CPP/7zip/Compress/BZip2Const.h
--- 7zip-24.09+dfsg/CPP/7zip/Compress/BZip2Const.h 2023-01-10 18:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/7zip/Compress/BZip2Const.h 2024-12-17 12:00:00.000000000 +0100
@@ -46,7 +46,7 @@
const UInt32 kBlockSizeMax = kBlockSizeMultMax * kBlockSizeStep;
const unsigned kNumSelectorsBits = 15;
-const UInt32 kNumSelectorsMax = (2 + (kBlockSizeMax / kGroupSize));
+const unsigned kNumSelectorsMax = 2 + kBlockSizeMax / kGroupSize;
const unsigned kRleModeRepSize = 4;
diff -Nru 7zip-24.09+dfsg/CPP/7zip/Compress/BZip2Encoder.cpp 7zip-25.00+dfsg/CPP/7zip/Compress/BZip2Encoder.cpp
--- 7zip-24.09+dfsg/CPP/7zip/Compress/BZip2Encoder.cpp 2023-01-30 19:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/7zip/Compress/BZip2Encoder.cpp 2025-06-30 17:00:00.000000000 +0200
@@ -6,18 +6,20 @@
#include "../../../C/BwtSort.h"
#include "../../../C/HuffEnc.h"
-#include "BZip2Crc.h"
#include "BZip2Encoder.h"
-#include "Mtf8.h"
namespace NCompress {
namespace NBZip2 {
-const unsigned kMaxHuffmanLenForEncoding = 16; // it must be < kMaxHuffmanLen = 20
-
-static const UInt32 kBufferSize = (1 << 17);
+#define HUFFMAN_LEN 16
+#if HUFFMAN_LEN > Z7_HUFFMAN_LEN_MAX
+ #error Stop_Compiling_Bad_HUFFMAN_LEN_BZip2Encoder
+#endif
+
+static const size_t kBufferSize = 1 << 17;
static const unsigned kNumHuffPasses = 4;
+
bool CThreadInfo::Alloc()
{
if (!m_BlockSorterIndex)
@@ -27,11 +29,15 @@
return false;
}
- if (!m_Block)
+ if (!m_Block_Base)
{
- m_Block = (Byte *)::MidAlloc(kBlockSizeMax * 5 + kBlockSizeMax / 10 + (20 << 10));
- if (!m_Block)
+ const unsigned kPadSize = 1 << 7; // we need at least 1 byte backward padding, becuase we use (m_Block - 1) pointer;
+ m_Block_Base = (Byte *)::MidAlloc(kBlockSizeMax * 5
+ + kBlockSizeMax / 10 + (20 << 10)
+ + kPadSize);
+ if (!m_Block_Base)
return false;
+ m_Block = m_Block_Base + kPadSize;
m_MtfArray = m_Block + kBlockSizeMax;
m_TempArray = m_MtfArray + kBlockSizeMax * 2 + 2;
}
@@ -42,8 +48,8 @@
{
::BigFree(m_BlockSorterIndex);
m_BlockSorterIndex = NULL;
- ::MidFree(m_Block);
- m_Block = NULL;
+ ::MidFree(m_Block_Base);
+ m_Block_Base = NULL;
}
#ifndef Z7_ST
@@ -60,6 +66,14 @@
if (wres == 0) { wres = CanWriteEvent.Create();
if (wres == 0)
{
+#ifdef _WIN32
+ if (Encoder->_props.NumThreadGroups != 0)
+ {
+ const UInt32 group = ThreadNextGroup_GetNext(&Encoder->ThreadNextGroup);
+ wres = Thread.Create_With_Group(MFThread, this, group, 0); // affinity
+ }
+ else
+#endif
if (Encoder->_props.Affinity != 0)
wres = Thread.Create_With_Affinity(MFThread, this, (CAffinityMask)Encoder->_props.Affinity);
else
@@ -216,94 +230,251 @@
}
#endif
+struct CRleEncoder
+{
+ const Byte *_src;
+ const Byte *_srcLim;
+ Byte *_dest;
+ const Byte *_destLim;
+ Byte _prevByte;
+ unsigned _numReps;
+
+ void Encode();
+};
+
+Z7_NO_INLINE
+void CRleEncoder::Encode()
+{
+ const Byte *src = _src;
+ const Byte * const srcLim = _srcLim;
+ Byte *dest = _dest;
+ const Byte * const destLim = _destLim;
+ Byte prev = _prevByte;
+ unsigned numReps = _numReps;
+ // (dest < destLim)
+ // src = srcLim; // for debug
+ while (dest < destLim)
+ {
+ if (src == srcLim)
+ break;
+ const Byte b = *src++;
+ if (b != prev)
+ {
+ if (numReps >= kRleModeRepSize)
+ *dest++ = (Byte)(numReps - kRleModeRepSize);
+ *dest++ = b;
+ numReps = 1;
+ prev = b;
+ /*
+ { // speed optimization code:
+ if (dest >= destLim || src == srcLim)
+ break;
+ const Byte b2 = *src++;
+ *dest++ = b2;
+ numReps += (prev == b2);
+ prev = b2;
+ }
+ */
+ continue;
+ }
+ numReps++;
+ if (numReps <= kRleModeRepSize)
+ *dest++ = b;
+ else if (numReps == kRleModeRepSize + 255)
+ {
+ *dest++ = (Byte)(numReps - kRleModeRepSize);
+ numReps = 0;
+ }
+ }
+ _src = src;
+ _dest = dest;
+ _prevByte = prev;
+ _numReps = numReps;
+ // (dest <= destLim + 1)
+}
+
+
+// out: return value is blockSize: size of data filled in buffer[]:
+// (returned_blockSize <= _props.BlockSizeMult * kBlockSizeStep)
UInt32 CEncoder::ReadRleBlock(Byte *buffer)
{
+ CRleEncoder rle;
UInt32 i = 0;
- Byte prevByte;
- if (m_InStream.ReadByte(prevByte))
+ if (m_InStream.ReadByte(rle._prevByte))
{
NumBlocks++;
- const UInt32 blockSize = _props.BlockSizeMult * kBlockSizeStep - 1;
- unsigned numReps = 1;
- buffer[i++] = prevByte;
- while (i < blockSize) // "- 1" to support RLE
- {
- Byte b;
- if (!m_InStream.ReadByte(b))
+ const UInt32 blockSize = _props.BlockSizeMult * kBlockSizeStep - 1; // -1 for RLE
+ rle._destLim = buffer + blockSize;
+ rle._numReps = 1;
+ buffer[i++] = rle._prevByte;
+ while (i < blockSize)
+ {
+ rle._dest = buffer + i;
+ size_t rem;
+ const Byte * const ptr = m_InStream.Lookahead(rem);
+ if (rem == 0)
break;
- if (b != prevByte)
- {
- if (numReps >= kRleModeRepSize)
- buffer[i++] = (Byte)(numReps - kRleModeRepSize);
- buffer[i++] = b;
- numReps = 1;
- prevByte = b;
- continue;
- }
- numReps++;
- if (numReps <= kRleModeRepSize)
- buffer[i++] = b;
- else if (numReps == kRleModeRepSize + 255)
- {
- buffer[i++] = (Byte)(numReps - kRleModeRepSize);
- numReps = 0;
- }
- }
- // it's to support original BZip2 decoder
- if (numReps >= kRleModeRepSize)
- buffer[i++] = (Byte)(numReps - kRleModeRepSize);
+ rle._src = ptr;
+ rle._srcLim = ptr + rem;
+ rle.Encode();
+ m_InStream.Skip((size_t)(rle._src - ptr));
+ i = (UInt32)(size_t)(rle._dest - buffer);
+ // (i <= blockSize + 1)
+ }
+ const int n = (int)rle._numReps - (int)kRleModeRepSize;
+ if (n >= 0)
+ buffer[i++] = (Byte)n;
}
return i;
}
-void CThreadInfo::WriteBits2(UInt32 value, unsigned numBits) { m_OutStreamCurrent->WriteBits(value, numBits); }
-void CThreadInfo::WriteByte2(Byte b) { WriteBits2(b, 8); }
-void CThreadInfo::WriteBit2(Byte v) { WriteBits2(v, 1); }
-void CThreadInfo::WriteCrc2(UInt32 v)
-{
- for (unsigned i = 0; i < 4; i++)
- WriteByte2(((Byte)(v >> (24 - i * 8))));
-}
-
-void CEncoder::WriteBits(UInt32 value, unsigned numBits) { m_OutStream.WriteBits(value, numBits); }
-void CEncoder::WriteByte(Byte b) { WriteBits(b, 8); }
-// void CEncoder::WriteBit(Byte v) { WriteBits(v, 1); }
-void CEncoder::WriteCrc(UInt32 v)
-{
- for (unsigned i = 0; i < 4; i++)
- WriteByte(((Byte)(v >> (24 - i * 8))));
+
+
+Z7_NO_INLINE
+void CThreadInfo::WriteBits2(UInt32 value, unsigned numBits)
+ { m_OutStreamCurrent.WriteBits(value, numBits); }
+/*
+Z7_NO_INLINE
+void CThreadInfo::WriteByte2(unsigned b)
+ { m_OutStreamCurrent.WriteByte(b); }
+*/
+// void CEncoder::WriteBits(UInt32 value, unsigned numBits) { m_OutStream.WriteBits(value, numBits); }
+Z7_NO_INLINE
+void CEncoder::WriteByte(Byte b) { m_OutStream.WriteByte(b); }
+
+
+#define WRITE_BITS_UPDATE(value, numBits) \
+{ \
+ numBits -= _bitPos; \
+ const UInt32 hi = value >> numBits; \
+ *_buf++ = (Byte)(_curByte | hi); \
+ value -= hi << numBits; \
+ _bitPos = 8; \
+ _curByte = 0; \
+}
+
+#if HUFFMAN_LEN > 16
+
+#define WRITE_BITS_HUFF(value2, numBits2) \
+{ \
+ UInt32 value = value2; \
+ unsigned numBits = numBits2; \
+ while (numBits >= _bitPos) { \
+ WRITE_BITS_UPDATE(value, numBits) \
+ } \
+ _bitPos -= numBits; \
+ _curByte |= (value << _bitPos); \
+}
+
+#else // HUFFMAN_LEN <= 16
+
+// numBits2 <= 16 is supported
+#define WRITE_BITS_HUFF(value2, numBits2) \
+{ \
+ UInt32 value = value2; \
+ unsigned numBits = numBits2; \
+ if (numBits >= _bitPos) \
+ { \
+ WRITE_BITS_UPDATE(value, numBits) \
+ if (numBits >= _bitPos) \
+ { \
+ numBits -= _bitPos; \
+ const UInt32 hi = value >> numBits; \
+ *_buf++ = (Byte)hi; \
+ value -= hi << numBits; \
+ } \
+ } \
+ _bitPos -= numBits; \
+ _curByte |= (value << _bitPos); \
+}
+
+#endif
+
+#define WRITE_BITS_8(value2, numBits2) \
+{ \
+ UInt32 value = value2; \
+ unsigned numBits = numBits2; \
+ if (numBits >= _bitPos) \
+ { \
+ WRITE_BITS_UPDATE(value, numBits) \
+ } \
+ _bitPos -= numBits; \
+ _curByte |= (value << _bitPos); \
+}
+
+#define WRITE_BIT_PRE \
+ { _bitPos--; }
+
+#define WRITE_BIT_POST \
+{ \
+ if (_bitPos == 0) \
+ { \
+ *_buf++ = (Byte)_curByte; \
+ _curByte = 0; \
+ _bitPos = 8; \
+ } \
+}
+
+#define WRITE_BIT_0 \
+{ \
+ WRITE_BIT_PRE \
+ WRITE_BIT_POST \
+}
+
+#define WRITE_BIT_1 \
+{ \
+ WRITE_BIT_PRE \
+ _curByte |= 1u << _bitPos; \
+ WRITE_BIT_POST \
}
// blockSize > 0
void CThreadInfo::EncodeBlock(const Byte *block, UInt32 blockSize)
{
- WriteBit2(0); // Randomised = false
-
+ // WriteBit2(0); // Randomised = false
{
- UInt32 origPtr = BlockSort(m_BlockSorterIndex, block, blockSize);
+ const UInt32 origPtr = BlockSort(m_BlockSorterIndex, block, blockSize);
// if (m_BlockSorterIndex[origPtr] != 0) throw 1;
m_BlockSorterIndex[origPtr] = blockSize;
- WriteBits2(origPtr, kNumOrigBits);
+ WriteBits2(origPtr, kNumOrigBits + 1); // + 1 for additional high bit flag (Randomised = false)
}
-
- CMtf8Encoder mtf;
- unsigned numInUse = 0;
+ Byte mtfBuf[256];
+ // memset(mtfBuf, 0, sizeof(mtfBuf)); // to disable MSVC warning
+ unsigned numInUse;
{
Byte inUse[256];
Byte inUse16[16];
- UInt32 i;
+ unsigned i;
for (i = 0; i < 256; i++)
inUse[i] = 0;
for (i = 0; i < 16; i++)
inUse16[i] = 0;
- for (i = 0; i < blockSize; i++)
- inUse[block[i]] = 1;
+ {
+ const Byte * cur = block;
+ block = block + (size_t)blockSize - 1;
+ if (cur != block)
+ {
+ do
+ {
+ const unsigned b0 = cur[0];
+ const unsigned b1 = cur[1];
+ cur += 2;
+ inUse[b0] = 1;
+ inUse[b1] = 1;
+ }
+ while (cur < block);
+ }
+ if (cur == block)
+ inUse[cur[0]] = 1;
+ block -= blockSize; // block pointer is (original_block - 1)
+ }
+ numInUse = 0;
for (i = 0; i < 256; i++)
if (inUse[i])
{
inUse16[i >> 4] = 1;
- mtf.Buf[numInUse++] = (Byte)i;
+ mtfBuf[numInUse++] = (Byte)i;
}
for (i = 0; i < 16; i++)
WriteBit2(inUse16[i]);
@@ -311,65 +482,88 @@
if (inUse16[i >> 4])
WriteBit2(inUse[i]);
}
- unsigned alphaSize = numInUse + 2;
+ const unsigned alphaSize = numInUse + 2;
- Byte *mtfs = m_MtfArray;
- UInt32 mtfArraySize = 0;
UInt32 symbolCounts[kMaxAlphaSize];
{
for (unsigned i = 0; i < kMaxAlphaSize; i++)
symbolCounts[i] = 0;
+ symbolCounts[(size_t)alphaSize - 1] = 1;
}
+ Byte *mtfs = m_MtfArray;
{
- UInt32 rleSize = 0;
- UInt32 i = 0;
const UInt32 *bsIndex = m_BlockSorterIndex;
- block--;
+ const UInt32 *bsIndex_rle = bsIndex;
+ const UInt32 * const bsIndex_end = bsIndex + blockSize;
+ // block--; // backward fix
+ // block pointer is (original_block - 1)
do
{
- unsigned pos = mtf.FindAndMove(block[bsIndex[i]]);
- if (pos == 0)
- rleSize++;
- else
+ const Byte v = block[*bsIndex++];
+ Byte a = mtfBuf[0];
+ if (v != a)
{
- while (rleSize != 0)
+ mtfBuf[0] = v;
{
- rleSize--;
- mtfs[mtfArraySize++] = (Byte)(rleSize & 1);
- symbolCounts[rleSize & 1]++;
- rleSize >>= 1;
+ UInt32 rleSize = (UInt32)(size_t)(bsIndex - bsIndex_rle) - 1;
+ bsIndex_rle = bsIndex;
+ while (rleSize)
+ {
+ const unsigned sym = (unsigned)(--rleSize & 1);
+ *mtfs++ = (Byte)sym;
+ symbolCounts[sym]++;
+ rleSize >>= 1;
+ }
}
- if (pos >= 0xFE)
+ unsigned pos1 = 2; // = real_pos + 1
+ Byte b;
+ b = mtfBuf[1]; mtfBuf[1] = a; if (v != b)
+ { a = mtfBuf[2]; mtfBuf[2] = b; if (v == a) pos1 = 3;
+ else { b = mtfBuf[3]; mtfBuf[3] = a; if (v == b) pos1 = 4;
+ else
+ {
+ Byte *m = mtfBuf + 7;
+ for (;;)
+ {
+ a = m[-3]; m[-3] = b; if (v == a) { pos1 = (unsigned)(size_t)(m - (mtfBuf + 2)); break; }
+ b = m[-2]; m[-2] = a; if (v == b) { pos1 = (unsigned)(size_t)(m - (mtfBuf + 1)); break; }
+ a = m[-1]; m[-1] = b; if (v == a) { pos1 = (unsigned)(size_t)(m - (mtfBuf )); break; }
+ b = m[ 0]; m[ 0] = a; m += 4; if (v == b) { pos1 = (unsigned)(size_t)(m - (mtfBuf + 3)); break; }
+ }
+ }}}
+ symbolCounts[pos1]++;
+ if (pos1 >= 0xff)
{
- mtfs[mtfArraySize++] = 0xFF;
- mtfs[mtfArraySize++] = (Byte)(pos - 0xFE);
+ *mtfs++ = 0xff;
+ // pos1 -= 0xff;
+ pos1++; // we need only low byte
}
- else
- mtfs[mtfArraySize++] = (Byte)(pos + 1);
- symbolCounts[(size_t)pos + 1]++;
+ *mtfs++ = (Byte)pos1;
}
}
- while (++i < blockSize);
+ while (bsIndex < bsIndex_end);
- while (rleSize != 0)
+ UInt32 rleSize = (UInt32)(size_t)(bsIndex - bsIndex_rle);
+ while (rleSize)
{
- rleSize--;
- mtfs[mtfArraySize++] = (Byte)(rleSize & 1);
- symbolCounts[rleSize & 1]++;
+ const unsigned sym = (unsigned)(--rleSize & 1);
+ *mtfs++ = (Byte)sym;
+ symbolCounts[sym]++;
rleSize >>= 1;
}
-
- if (alphaSize < 256)
- mtfs[mtfArraySize++] = (Byte)(alphaSize - 1);
- else
+
+ unsigned d = alphaSize - 1;
+ if (alphaSize >= 256)
{
- mtfs[mtfArraySize++] = 0xFF;
- mtfs[mtfArraySize++] = (Byte)(alphaSize - 256);
+ *mtfs++ = 0xff;
+ d = alphaSize; // (-256)
}
- symbolCounts[(size_t)alphaSize - 1]++;
+ *mtfs++ = (Byte)d;
}
+ const Byte * const mtf_lim = mtfs;
+
UInt32 numSymbols = 0;
{
for (unsigned i = 0; i < kMaxAlphaSize; i++)
@@ -378,34 +572,30 @@
unsigned bestNumTables = kNumTablesMin;
UInt32 bestPrice = 0xFFFFFFFF;
- UInt32 startPos = m_OutStreamCurrent->GetPos();
- Byte startCurByte = m_OutStreamCurrent->GetCurByte();
+ const UInt32 startPos = m_OutStreamCurrent.GetPos();
+ const unsigned startCurByte = m_OutStreamCurrent.GetCurByte();
for (unsigned nt = kNumTablesMin; nt <= kNumTablesMax + 1; nt++)
{
unsigned numTables;
if (m_OptimizeNumTables)
{
- m_OutStreamCurrent->SetPos(startPos);
- m_OutStreamCurrent->SetCurState((startPos & 7), startCurByte);
- if (nt <= kNumTablesMax)
- numTables = nt;
- else
- numTables = bestNumTables;
+ m_OutStreamCurrent.SetPos(startPos);
+ m_OutStreamCurrent.SetCurState(startPos & 7, startCurByte);
+ numTables = (nt <= kNumTablesMax ? nt : bestNumTables);
}
else
{
- if (numSymbols < 200) numTables = 2;
- else if (numSymbols < 600) numTables = 3;
+ if (numSymbols < 200) numTables = 2;
+ else if (numSymbols < 600) numTables = 3;
else if (numSymbols < 1200) numTables = 4;
else if (numSymbols < 2400) numTables = 5;
- else numTables = 6;
+ else numTables = 6;
}
WriteBits2(numTables, kNumTablesBits);
-
- UInt32 numSelectors = (numSymbols + kGroupSize - 1) / kGroupSize;
- WriteBits2(numSelectors, kNumSelectorsBits);
+ const unsigned numSelectors = (numSymbols + kGroupSize - 1) / kGroupSize;
+ WriteBits2((UInt32)numSelectors, kNumSelectorsBits);
{
UInt32 remFreq = numSymbols;
@@ -436,28 +626,23 @@
for (unsigned pass = 0; pass < kNumHuffPasses; pass++)
{
+ memset(Freqs, 0, sizeof(Freqs[0]) * numTables);
+ // memset(Freqs, 0, sizeof(Freqs));
{
- unsigned t = 0;
- do
- memset(Freqs[t], 0, sizeof(Freqs[t]));
- while (++t < numTables);
- }
-
- {
- UInt32 mtfPos = 0;
+ mtfs = m_MtfArray;
UInt32 g = 0;
do
{
- UInt32 symbols[kGroupSize];
+ unsigned symbols[kGroupSize];
unsigned i = 0;
do
{
- UInt32 symbol = mtfs[mtfPos++];
+ UInt32 symbol = *mtfs++;
if (symbol >= 0xFF)
- symbol += mtfs[mtfPos++];
+ symbol += *mtfs++;
symbols[i] = symbol;
}
- while (++i < kGroupSize && mtfPos < mtfArraySize);
+ while (++i < kGroupSize && mtfs < mtf_lim);
UInt32 bestPrice2 = 0xFFFFFFFF;
unsigned t = 0;
@@ -482,7 +667,7 @@
freqs[symbols[j]]++;
while (++j < i);
}
- while (mtfPos < mtfArraySize);
+ while (mtfs < mtf_lim);
}
unsigned t = 0;
@@ -494,11 +679,15 @@
if (freqs[i] == 0)
freqs[i] = 1;
while (++i < alphaSize);
- Huffman_Generate(freqs, Codes[t], Lens[t], kMaxAlphaSize, kMaxHuffmanLenForEncoding);
+ Huffman_Generate(freqs, Codes[t], Lens[t], kMaxAlphaSize, HUFFMAN_LEN);
}
while (++t < numTables);
}
+ unsigned _bitPos; // 0 < _bitPos <= 8 : number of non-filled low bits in _curByte
+ unsigned _curByte; // low (_bitPos) bits are zeros
+ // high (8 - _bitPos) bits are filled
+ Byte *_buf;
{
Byte mtfSel[kNumTablesMax];
{
@@ -507,81 +696,97 @@
mtfSel[t] = (Byte)t;
while (++t < numTables);
}
+
+ _bitPos = m_OutStreamCurrent._bitPos;
+ _curByte = m_OutStreamCurrent._curByte;
+ _buf = m_OutStreamCurrent._buf;
+ // stream.Init_from_Global(m_OutStreamCurrent);
- UInt32 i = 0;
+ const Byte *selectors = m_Selectors;
+ const Byte * const selectors_lim = selectors + numSelectors;
+ Byte prev = 0; // mtfSel[0];
do
{
- Byte sel = m_Selectors[i];
- unsigned pos;
- for (pos = 0; mtfSel[pos] != sel; pos++)
- WriteBit2(1);
- WriteBit2(0);
- for (; pos > 0; pos--)
- mtfSel[pos] = mtfSel[(size_t)pos - 1];
- mtfSel[0] = sel;
+ const Byte sel = *selectors++;
+ if (prev != sel)
+ {
+ Byte *mtfSel_cur = &mtfSel[1];
+ for (;;)
+ {
+ WRITE_BIT_1
+ const Byte next = *mtfSel_cur;
+ *mtfSel_cur++ = prev;
+ prev = next;
+ if (next == sel)
+ break;
+ }
+ // mtfSel[0] = sel;
+ }
+ WRITE_BIT_0
}
- while (++i < numSelectors);
+ while (selectors != selectors_lim);
}
-
{
unsigned t = 0;
do
{
const Byte *lens = Lens[t];
- UInt32 len = lens[0];
- WriteBits2(len, kNumLevelsBits);
+ unsigned len = lens[0];
+ WRITE_BITS_8(len, kNumLevelsBits)
unsigned i = 0;
do
{
- UInt32 level = lens[i];
+ const unsigned level = lens[i];
while (len != level)
{
- WriteBit2(1);
+ WRITE_BIT_1
if (len < level)
{
- WriteBit2(0);
len++;
+ WRITE_BIT_0
}
else
{
- WriteBit2(1);
len--;
+ WRITE_BIT_1
}
}
- WriteBit2(0);
+ WRITE_BIT_0
}
while (++i < alphaSize);
}
while (++t < numTables);
}
-
{
- UInt32 groupSize = 0;
- UInt32 groupIndex = 0;
+ UInt32 groupSize = 1;
+ const Byte *selectors = m_Selectors;
const Byte *lens = NULL;
const UInt32 *codes = NULL;
- UInt32 mtfPos = 0;
+ mtfs = m_MtfArray;
do
{
- UInt32 symbol = mtfs[mtfPos++];
+ unsigned symbol = *mtfs++;
if (symbol >= 0xFF)
- symbol += mtfs[mtfPos++];
- if (groupSize == 0)
+ symbol += *mtfs++;
+ if (--groupSize == 0)
{
groupSize = kGroupSize;
- unsigned t = m_Selectors[groupIndex++];
+ const unsigned t = *selectors++;
lens = Lens[t];
codes = Codes[t];
}
- groupSize--;
- m_OutStreamCurrent->WriteBits(codes[symbol], lens[symbol]);
+ WRITE_BITS_HUFF(codes[symbol], lens[symbol])
}
- while (mtfPos < mtfArraySize);
+ while (mtfs < mtf_lim);
}
+ // Restore_from_Local:
+ m_OutStreamCurrent._bitPos = _bitPos;
+ m_OutStreamCurrent._curByte = _curByte;
+ m_OutStreamCurrent._buf = _buf;
if (!m_OptimizeNumTables)
break;
- UInt32 price = m_OutStreamCurrent->GetPos() - startPos;
+ const UInt32 price = m_OutStreamCurrent.GetPos() - startPos;
if (price <= bestPrice)
{
if (nt == kNumTablesMax)
@@ -592,6 +797,7 @@
}
}
+
// blockSize > 0
UInt32 CThreadInfo::EncodeBlockWithHeaders(const Byte *block, UInt32 blockSize)
{
@@ -603,148 +809,134 @@
WriteByte2(kBlockSig5);
CBZip2Crc crc;
- unsigned numReps = 0;
- Byte prevByte = block[0];
- UInt32 i = 0;
- do
+ const Byte * const lim = block + blockSize;
+ unsigned b = *block++;
+ crc.UpdateByte(b);
+ for (;;)
{
- Byte b = block[i];
- if (numReps == kRleModeRepSize)
- {
- for (; b > 0; b--)
- crc.UpdateByte(prevByte);
- numReps = 0;
- continue;
- }
- if (prevByte == b)
- numReps++;
- else
- {
- numReps = 1;
- prevByte = b;
- }
- crc.UpdateByte(b);
- }
- while (++i < blockSize);
- UInt32 crcRes = crc.GetDigest();
- WriteCrc2(crcRes);
- EncodeBlock(block, blockSize);
+ const unsigned prev = b;
+ if (block >= lim) { break; } b = *block++; crc.UpdateByte(b); if (prev != b) continue;
+ if (block >= lim) { break; } b = *block++; crc.UpdateByte(b); if (prev != b) continue;
+ if (block >= lim) { break; } b = *block++; crc.UpdateByte(b); if (prev != b) continue;
+ if (block >= lim) { break; } b = *block++; if (b) do crc.UpdateByte(prev); while (--b);
+ if (block >= lim) { break; } b = *block++; crc.UpdateByte(b);
+ }
+ const UInt32 crcRes = crc.GetDigest();
+ for (int i = 24; i >= 0; i -= 8)
+ WriteByte2((Byte)(crcRes >> i));
+ EncodeBlock(lim - blockSize, blockSize);
return crcRes;
}
+
void CThreadInfo::EncodeBlock2(const Byte *block, UInt32 blockSize, UInt32 numPasses)
{
- UInt32 numCrcs = m_NumCrcs;
- bool needCompare = false;
+ const UInt32 numCrcs = m_NumCrcs;
- UInt32 startBytePos = m_OutStreamCurrent->GetBytePos();
- UInt32 startPos = m_OutStreamCurrent->GetPos();
- Byte startCurByte = m_OutStreamCurrent->GetCurByte();
- Byte endCurByte = 0;
- UInt32 endPos = 0;
+ const UInt32 startBytePos = m_OutStreamCurrent.GetBytePos();
+ const UInt32 startPos = m_OutStreamCurrent.GetPos();
+ const unsigned startCurByte = m_OutStreamCurrent.GetCurByte();
+ unsigned endCurByte = 0;
+ UInt32 endPos = 0; // 0 means no no additional passes
if (numPasses > 1 && blockSize >= (1 << 10))
{
- UInt32 blockSize0 = blockSize / 2; // ????
-
- for (; (block[blockSize0] == block[(size_t)blockSize0 - 1]
- || block[(size_t)blockSize0 - 1] == block[(size_t)blockSize0 - 2])
- && blockSize0 < blockSize;
- blockSize0++);
+ UInt32 bs0 = blockSize / 2;
+ for (; bs0 < blockSize &&
+ (block[ bs0 ] ==
+ block[(size_t)bs0 - 1] ||
+ block[(size_t)bs0 - 1] ==
+ block[(size_t)bs0 - 2]);
+ bs0++)
+ {}
- if (blockSize0 < blockSize)
+ if (bs0 < blockSize)
{
- EncodeBlock2(block, blockSize0, numPasses - 1);
- EncodeBlock2(block + blockSize0, blockSize - blockSize0, numPasses - 1);
- endPos = m_OutStreamCurrent->GetPos();
- endCurByte = m_OutStreamCurrent->GetCurByte();
- if ((endPos & 7) > 0)
+ EncodeBlock2(block, bs0, numPasses - 1);
+ EncodeBlock2(block + bs0, blockSize - bs0, numPasses - 1);
+ endPos = m_OutStreamCurrent.GetPos();
+ endCurByte = m_OutStreamCurrent.GetCurByte();
+ // we prepare next byte as identical byte to starting byte for main encoding attempt:
+ if (endPos & 7)
WriteBits2(0, 8 - (endPos & 7));
- m_OutStreamCurrent->SetCurState((startPos & 7), startCurByte);
- needCompare = true;
+ m_OutStreamCurrent.SetCurState((startPos & 7), startCurByte);
}
}
- UInt32 startBytePos2 = m_OutStreamCurrent->GetBytePos();
- UInt32 startPos2 = m_OutStreamCurrent->GetPos();
- UInt32 crcVal = EncodeBlockWithHeaders(block, blockSize);
- UInt32 endPos2 = m_OutStreamCurrent->GetPos();
+ const UInt32 startBytePos2 = m_OutStreamCurrent.GetBytePos();
+ const UInt32 startPos2 = m_OutStreamCurrent.GetPos();
+ const UInt32 crcVal = EncodeBlockWithHeaders(block, blockSize);
- if (needCompare)
+ if (endPos)
{
- UInt32 size2 = endPos2 - startPos2;
- if (size2 < endPos - startPos)
+ const UInt32 size2 = m_OutStreamCurrent.GetPos() - startPos2;
+ if (size2 >= endPos - startPos)
{
- UInt32 numBytes = m_OutStreamCurrent->GetBytePos() - startBytePos2;
- Byte *buffer = m_OutStreamCurrent->GetStream();
- for (UInt32 i = 0; i < numBytes; i++)
- buffer[startBytePos + i] = buffer[startBytePos2 + i];
- m_OutStreamCurrent->SetPos(startPos + endPos2 - startPos2);
- m_NumCrcs = numCrcs;
- m_CRCs[m_NumCrcs++] = crcVal;
- }
- else
- {
- m_OutStreamCurrent->SetPos(endPos);
- m_OutStreamCurrent->SetCurState((endPos & 7), endCurByte);
+ m_OutStreamCurrent.SetPos(endPos);
+ m_OutStreamCurrent.SetCurState((endPos & 7), endCurByte);
+ return;
}
+ const UInt32 numBytes = m_OutStreamCurrent.GetBytePos() - startBytePos2;
+ Byte * const buffer = m_OutStreamCurrent.GetStream();
+ memmove(buffer + startBytePos, buffer + startBytePos2, numBytes);
+ m_OutStreamCurrent.SetPos(startPos + size2);
+ // we don't call m_OutStreamCurrent.SetCurState() here because
+ // m_OutStreamCurrent._curByte is correct already
}
- else
- {
- m_NumCrcs = numCrcs;
- m_CRCs[m_NumCrcs++] = crcVal;
- }
+ m_CRCs[numCrcs] = crcVal;
+ m_NumCrcs = numCrcs + 1;
}
+
HRESULT CThreadInfo::EncodeBlock3(UInt32 blockSize)
{
- CMsbfEncoderTemp outStreamTemp;
+ CMsbfEncoderTemp &outStreamTemp = m_OutStreamCurrent;
outStreamTemp.SetStream(m_TempArray);
outStreamTemp.Init();
- m_OutStreamCurrent = &outStreamTemp;
-
m_NumCrcs = 0;
EncodeBlock2(m_Block, blockSize, Encoder->_props.NumPasses);
- #ifndef Z7_ST
+#ifndef Z7_ST
if (Encoder->MtMode)
Encoder->ThreadsInfo[m_BlockIndex].CanWriteEvent.Lock();
- #endif
+#endif
+
for (UInt32 i = 0; i < m_NumCrcs; i++)
Encoder->CombinedCrc.Update(m_CRCs[i]);
- Encoder->WriteBytes(m_TempArray, outStreamTemp.GetPos(), outStreamTemp.GetCurByte());
+ Encoder->WriteBytes(m_TempArray, outStreamTemp.GetPos(), outStreamTemp.GetNonFlushedByteBits());
HRESULT res = S_OK;
- #ifndef Z7_ST
+
+#ifndef Z7_ST
if (Encoder->MtMode)
{
UInt32 blockIndex = m_BlockIndex + 1;
if (blockIndex == Encoder->NumThreads)
blockIndex = 0;
-
if (Encoder->Progress)
{
const UInt64 packSize = Encoder->m_OutStream.GetProcessedSize();
res = Encoder->Progress->SetRatioInfo(&m_UnpackSize, &packSize);
}
-
Encoder->ThreadsInfo[blockIndex].CanWriteEvent.Set();
}
- #endif
+#endif
return res;
}
-void CEncoder::WriteBytes(const Byte *data, UInt32 sizeInBits, Byte lastByte)
+void CEncoder::WriteBytes(const Byte *data, UInt32 sizeInBits, unsigned lastByteBits)
{
- UInt32 bytesSize = (sizeInBits >> 3);
- for (UInt32 i = 0; i < bytesSize; i++)
- m_OutStream.WriteBits(data[i], 8);
- WriteBits(lastByte, (sizeInBits & 7));
+ m_OutStream.WriteBytes(data, sizeInBits >> 3);
+ sizeInBits &= 7;
+ if (sizeInBits)
+ m_OutStream.WriteBits(lastByteBits, sizeInBits);
}
HRESULT CEncoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
{
+ ThreadNextGroup_Init(&ThreadNextGroup, _props.NumThreadGroups, 0); // startGroup
+
NumBlocks = 0;
#ifndef Z7_ST
Progress = progress;
@@ -823,11 +1015,11 @@
{
CThreadInfo &ti =
#ifndef Z7_ST
- ThreadsInfo[0];
+ ThreadsInfo[0];
#else
- ThreadsInfo;
+ ThreadsInfo;
#endif
- UInt32 blockSize = ReadRleBlock(ti.m_Block);
+ const UInt32 blockSize = ReadRleBlock(ti.m_Block);
if (blockSize == 0)
break;
RINOK(ti.EncodeBlock3(blockSize))
@@ -845,8 +1037,11 @@
WriteByte(kFinSig3);
WriteByte(kFinSig4);
WriteByte(kFinSig5);
-
- WriteCrc(CombinedCrc.GetDigest());
+ {
+ const UInt32 v = CombinedCrc.GetDigest();
+ for (int i = 24; i >= 0; i -= 8)
+ WriteByte((Byte)(v >> i));
+ }
RINOK(Flush())
if (!m_InStream.WasFinished())
return E_FAIL;
@@ -869,14 +1064,21 @@
for (UInt32 i = 0; i < numProps; i++)
{
const PROPVARIANT &prop = coderProps[i];
- PROPID propID = propIDs[i];
+ const PROPID propID = propIDs[i];
if (propID == NCoderPropID::kAffinity)
{
- if (prop.vt == VT_UI8)
- props.Affinity = prop.uhVal.QuadPart;
- else
+ if (prop.vt != VT_UI8)
+ return E_INVALIDARG;
+ props.Affinity = prop.uhVal.QuadPart;
+ continue;
+ }
+
+ if (propID == NCoderPropID::kNumThreadGroups)
+ {
+ if (prop.vt != VT_UI4)
return E_INVALIDARG;
+ props.NumThreadGroups = (UInt32)prop.ulVal;
continue;
}
@@ -884,7 +1086,7 @@
continue;
if (prop.vt != VT_UI4)
return E_INVALIDARG;
- UInt32 v = (UInt32)prop.ulVal;
+ const UInt32 v = (UInt32)prop.ulVal;
switch (propID)
{
case NCoderPropID::kNumPasses: props.NumPasses = v; break;
diff -Nru 7zip-24.09+dfsg/CPP/7zip/Compress/BZip2Encoder.h 7zip-25.00+dfsg/CPP/7zip/Compress/BZip2Encoder.h
--- 7zip-24.09+dfsg/CPP/7zip/Compress/BZip2Encoder.h 2023-03-28 12:00:00.000000000 +0200
+++ 7zip-25.00+dfsg/CPP/7zip/Compress/BZip2Encoder.h 2025-02-28 07:00:00.000000000 +0100
@@ -3,7 +3,6 @@
#ifndef ZIP7_INC_COMPRESS_BZIP2_ENCODER_H
#define ZIP7_INC_COMPRESS_BZIP2_ENCODER_H
-#include "../../Common/Defs.h"
#include "../../Common/MyCom.h"
#ifndef Z7_ST
@@ -23,80 +22,114 @@
namespace NCompress {
namespace NBZip2 {
-class CMsbfEncoderTemp
+const unsigned kNumPassesMax = 10;
+
+struct CMsbfEncoderTemp
{
- UInt32 _pos;
- unsigned _bitPos;
- Byte _curByte;
+ unsigned _bitPos; // 0 < _bitPos <= 8 : number of non-filled low bits in _curByte
+ unsigned _curByte; // low (_bitPos) bits are zeros
+ // high (8 - _bitPos) bits are filled
Byte *_buf;
-public:
- void SetStream(Byte *buf) { _buf = buf; }
- Byte *GetStream() const { return _buf; }
+ Byte *_buf_base;
+ void SetStream(Byte *buf) { _buf_base = _buf = buf; }
+ Byte *GetStream() const { return _buf_base; }
void Init()
{
- _pos = 0;
_bitPos = 8;
_curByte = 0;
+ _buf = _buf_base;
}
- void Flush()
- {
- if (_bitPos < 8)
- WriteBits(0, _bitPos);
- }
-
+ // required condition: (value >> numBits) == 0
+ // numBits == 0 is allowed
void WriteBits(UInt32 value, unsigned numBits)
{
- while (numBits > 0)
+ do
{
- unsigned numNewBits = MyMin(numBits, _bitPos);
- numBits -= numNewBits;
-
- _curByte = (Byte)(_curByte << numNewBits);
- UInt32 newBits = value >> numBits;
- _curByte |= Byte(newBits);
- value -= (newBits << numBits);
-
- _bitPos -= numNewBits;
-
- if (_bitPos == 0)
+ unsigned bp = _bitPos;
+ unsigned curByte = _curByte;
+ if (numBits < bp)
{
- _buf[_pos++] = _curByte;
- _bitPos = 8;
+ bp -= numBits;
+ _curByte = curByte | (value << bp);
+ _bitPos = bp;
+ return;
}
+ numBits -= bp;
+ const UInt32 hi = value >> numBits;
+ value -= (hi << numBits);
+ Byte *buf = _buf;
+ _bitPos = 8;
+ _curByte = 0;
+ *buf++ = (Byte)(curByte | hi);
+ _buf = buf;
}
+ while (numBits);
}
-
- UInt32 GetBytePos() const { return _pos ; }
- UInt32 GetPos() const { return _pos * 8 + (8 - _bitPos); }
- Byte GetCurByte() const { return _curByte; }
+
+ void WriteBit(unsigned value)
+ {
+ const unsigned bp = _bitPos - 1;
+ const unsigned curByte = _curByte | (value << bp);
+ _curByte = curByte;
+ _bitPos = bp;
+ if (bp == 0)
+ {
+ *_buf++ = (Byte)curByte;
+ _curByte = 0;
+ _bitPos = 8;
+ }
+ }
+
+ void WriteByte(unsigned b)
+ {
+ const unsigned bp = _bitPos;
+ const unsigned a = _curByte | (b >> (8 - bp));
+ _curByte = b << bp;
+ Byte *buf = _buf;
+ *buf++ = (Byte)a;
+ _buf = buf;
+ }
+
+ UInt32 GetBytePos() const { return (UInt32)(size_t)(_buf - _buf_base); }
+ UInt32 GetPos() const { return GetBytePos() * 8 + 8 - _bitPos; }
+ unsigned GetCurByte() const { return _curByte; }
+ unsigned GetNonFlushedByteBits() const { return _curByte >> _bitPos; }
void SetPos(UInt32 bitPos)
{
- _pos = bitPos >> 3;
+ _buf = _buf_base + (bitPos >> 3);
_bitPos = 8 - ((unsigned)bitPos & 7);
}
- void SetCurState(unsigned bitPos, Byte curByte)
+ void SetCurState(unsigned bitPos, unsigned curByte)
{
_bitPos = 8 - bitPos;
_curByte = curByte;
}
};
-class CEncoder;
-const unsigned kNumPassesMax = 10;
+class CEncoder;
class CThreadInfo
{
+private:
+ CMsbfEncoderTemp m_OutStreamCurrent;
public:
+ CEncoder *Encoder;
Byte *m_Block;
private:
Byte *m_MtfArray;
Byte *m_TempArray;
UInt32 *m_BlockSorterIndex;
- CMsbfEncoderTemp *m_OutStreamCurrent;
+public:
+ bool m_OptimizeNumTables;
+ UInt32 m_NumCrcs;
+ UInt32 m_BlockIndex;
+ UInt64 m_UnpackSize;
+
+ Byte *m_Block_Base;
Byte Lens[kNumTablesMax][kMaxAlphaSize];
UInt32 Freqs[kNumTablesMax][kMaxAlphaSize];
@@ -105,20 +138,16 @@
Byte m_Selectors[kNumSelectorsMax];
UInt32 m_CRCs[1 << kNumPassesMax];
- UInt32 m_NumCrcs;
void WriteBits2(UInt32 value, unsigned numBits);
- void WriteByte2(Byte b);
- void WriteBit2(Byte v);
- void WriteCrc2(UInt32 v);
+ void WriteByte2(unsigned b) { WriteBits2(b, 8); }
+ void WriteBit2(unsigned v) { m_OutStreamCurrent.WriteBit(v); }
void EncodeBlock(const Byte *block, UInt32 blockSize);
UInt32 EncodeBlockWithHeaders(const Byte *block, UInt32 blockSize);
void EncodeBlock2(const Byte *block, UInt32 blockSize, UInt32 numPasses);
public:
- bool m_OptimizeNumTables;
- CEncoder *Encoder;
- #ifndef Z7_ST
+#ifndef Z7_ST
NWindows::CThread Thread;
NWindows::NSynchronization::CAutoResetEvent StreamWasFinishedEvent;
@@ -127,17 +156,14 @@
// it's not member of this thread. We just need one event per thread
NWindows::NSynchronization::CAutoResetEvent CanWriteEvent;
-private:
- UInt32 m_BlockIndex;
- UInt64 m_UnpackSize;
public:
Byte MtPad[1 << 8]; // It's pad for Multi-Threading. Must be >= Cache_Line_Size.
HRESULT Create();
void FinishStream(bool needLeave);
THREAD_FUNC_RET_TYPE ThreadFunc();
- #endif
+#endif
- CThreadInfo(): m_Block(NULL), m_BlockSorterIndex(NULL) {}
+ CThreadInfo(): m_BlockSorterIndex(NULL), m_Block_Base(NULL) {}
~CThreadInfo() { Free(); }
bool Alloc();
void Free();
@@ -145,16 +171,19 @@
HRESULT EncodeBlock3(UInt32 blockSize);
};
+
struct CEncProps
{
UInt32 BlockSizeMult;
UInt32 NumPasses;
+ UInt32 NumThreadGroups;
UInt64 Affinity;
CEncProps()
{
BlockSizeMult = (UInt32)(Int32)-1;
NumPasses = (UInt32)(Int32)-1;
+ NumThreadGroups = 0;
Affinity = 0;
}
void Normalize(int level);
@@ -206,6 +235,7 @@
bool CloseThreads;
bool StreamWasFinished;
NWindows::NSynchronization::CManualResetEvent CanStartWaitingEvent;
+ CThreadNextGroup ThreadNextGroup;
HRESULT Result;
ICompressProgressInfo *Progress;
@@ -218,12 +248,8 @@
UInt64 GetInProcessedSize() const { return m_InStream.GetProcessedSize(); }
UInt32 ReadRleBlock(Byte *buf);
- void WriteBytes(const Byte *data, UInt32 sizeInBits, Byte lastByte);
-
- void WriteBits(UInt32 value, unsigned numBits);
+ void WriteBytes(const Byte *data, UInt32 sizeInBits, unsigned lastByteBits);
void WriteByte(Byte b);
- // void WriteBit(Byte v);
- void WriteCrc(UInt32 v);
#ifndef Z7_ST
HRESULT Create();
diff -Nru 7zip-24.09+dfsg/CPP/7zip/Compress/DeflateDecoder.cpp 7zip-25.00+dfsg/CPP/7zip/Compress/DeflateDecoder.cpp
--- 7zip-24.09+dfsg/CPP/7zip/Compress/DeflateDecoder.cpp 2024-01-01 19:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/7zip/Compress/DeflateDecoder.cpp 2025-03-04 13:00:00.000000000 +0100
@@ -117,15 +117,13 @@
if (_numDistLevels > kDistTableSize32)
return false;
- Byte levelLevels[kLevelTableSize];
- for (unsigned i = 0; i < kLevelTableSize; i++)
- {
- const unsigned position = kCodeLengthAlphabetOrder[i];
- if (i < numLevelCodes)
- levelLevels[position] = (Byte)ReadBits(kLevelFieldSize);
- else
- levelLevels[position] = 0;
- }
+ const unsigned kLevelTableSize_aligned4 = kLevelTableSize + 1;
+ Byte levelLevels[kLevelTableSize_aligned4];
+ memset (levelLevels, 0, sizeof(levelLevels));
+ unsigned i = 0;
+ do
+ levelLevels[kCodeLengthAlphabetOrder[i++]] = (Byte)ReadBits(kLevelFieldSize);
+ while (i != numLevelCodes);
if (m_InBitStream.ExtraBitsWereRead())
return false;
diff -Nru 7zip-24.09+dfsg/CPP/7zip/Compress/DeflateEncoder.cpp 7zip-25.00+dfsg/CPP/7zip/Compress/DeflateEncoder.cpp
--- 7zip-24.09+dfsg/CPP/7zip/Compress/DeflateEncoder.cpp 2024-01-01 19:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/7zip/Compress/DeflateEncoder.cpp 2025-01-13 14:00:00.000000000 +0100
@@ -19,12 +19,16 @@
#define NO_INLINE
#endif
+#define MAX_HUF_LEN_12 12
+
namespace NCompress {
namespace NDeflate {
namespace NEncoder {
+static const unsigned k_CodeValue_Len_Is_Literal_Flag = 1u << 15;
+
static const unsigned kNumDivPassesMax = 10; // [0, 16); ratio/speed/ram tradeoff; use big value for better compression ratio.
-static const UInt32 kNumTables = (1 << kNumDivPassesMax);
+static const unsigned kNumTables = 1u << kNumDivPassesMax;
static const UInt32 kFixedHuffmanCodeBlockSizeMax = (1 << 8); // [0, (1 << 32)); ratio/speed tradeoff; use big value for better compression ratio.
static const UInt32 kDivideCodeBlockSizeMin = (1 << 7); // [1, (1 << 32)); ratio/speed tradeoff; use small value for better compression ratio.
@@ -77,7 +81,7 @@
static CFastPosInit g_FastPosInit;
-inline UInt32 GetPosSlot(UInt32 pos)
+inline unsigned GetPosSlot(UInt32 pos)
{
/*
if (pos < 0x200)
@@ -162,13 +166,13 @@
// COM_TRY_BEGIN
if (!m_Values)
{
- m_Values = (CCodeValue *)MyAlloc((kMaxUncompressedBlockSize) * sizeof(CCodeValue));
+ m_Values = (CCodeValue *)MyAlloc(kMaxUncompressedBlockSize * sizeof(CCodeValue));
if (!m_Values)
return E_OUTOFMEMORY;
}
if (!m_Tables)
{
- m_Tables = (CTables *)MyAlloc((kNumTables) * sizeof(CTables));
+ m_Tables = (CTables *)MyAlloc(kNumTables * sizeof(CTables));
if (!m_Tables)
return E_OUTOFMEMORY;
}
@@ -268,19 +272,21 @@
UInt32 distanceTmp[kMatchMaxLen * 2 + 3];
- const UInt32 numPairs = (UInt32)((_btMode ?
+ const size_t numPairs = (size_t)((_btMode ?
Bt3Zip_MatchFinder_GetMatches(&_lzInWindow, distanceTmp):
Hc3Zip_MatchFinder_GetMatches(&_lzInWindow, distanceTmp)) - distanceTmp);
- *m_MatchDistances = (UInt16)numPairs;
+ UInt16 *matchDistances = m_MatchDistances;
+ *matchDistances++ = (UInt16)numPairs;
if (numPairs != 0)
{
- UInt32 i;
+ size_t i;
for (i = 0; i < numPairs; i += 2)
{
- m_MatchDistances[(size_t)i + 1] = (UInt16)distanceTmp[i];
- m_MatchDistances[(size_t)i + 2] = (UInt16)distanceTmp[(size_t)i + 1];
+ matchDistances[0] = (UInt16)distanceTmp[i];
+ matchDistances[1] = (UInt16)distanceTmp[(size_t)i + 1];
+ matchDistances += 2;
}
UInt32 len = distanceTmp[(size_t)numPairs - 2];
if (len == m_NumFastBytes && m_NumFastBytes != m_MatchMaxLen)
@@ -291,11 +297,11 @@
if (numAvail > m_MatchMaxLen)
numAvail = m_MatchMaxLen;
for (; len < numAvail && pby[len] == pby2[len]; len++);
- m_MatchDistances[(size_t)i - 1] = (UInt16)len;
+ matchDistances[-2] = (UInt16)len;
}
}
if (m_IsMultiPass)
- m_Pos += numPairs + 1;
+ m_Pos += (UInt32)numPairs + 1;
if (!m_SecondPass)
m_AdditionalOffset++;
}
@@ -535,6 +541,7 @@
}
#define WRITE_HF2(codes, lens, i) m_OutStream.WriteBits(codes[i], lens[i])
+#define WRITE_HF2_NO_INLINE(codes, lens, i) WriteBits(codes[i], lens[i])
#define WRITE_HF(i) WriteBits(codes[i], lens[i])
NO_INLINE void CCoder::LevelTableCode(const Byte *levels, unsigned numLevels, const Byte *lens, const UInt32 *codes)
@@ -619,17 +626,22 @@
return price;
}
-static NO_INLINE UInt32 Huffman_GetPrice_Spec(const UInt32 *freqs, const Byte *lens, UInt32 num, const Byte *extraBits, UInt32 extraBase)
+static NO_INLINE UInt32 Huffman_GetPrice_Spec(
+ const UInt32 *freqs, const Byte *lens, UInt32 num,
+ const Byte *extraBits, UInt32 extraBase)
{
- return Huffman_GetPrice(freqs, lens, num) +
+ return
+ Huffman_GetPrice(freqs, lens, num) +
Huffman_GetPrice(freqs + extraBase, extraBits, num - extraBase);
}
NO_INLINE UInt32 CCoder::GetLzBlockPrice() const
{
return
- Huffman_GetPrice_Spec(mainFreqs, m_NewLevels.litLenLevels, kFixedMainTableSize, m_LenDirectBits, kSymbolMatch) +
- Huffman_GetPrice_Spec(distFreqs, m_NewLevels.distLevels, kDistTableSize64, kDistDirectBits, 0);
+ Huffman_GetPrice_Spec(mainFreqs, m_NewLevels.litLenLevels,
+ kFixedMainTableSize, m_LenDirectBits, kSymbolMatch) +
+ Huffman_GetPrice_Spec(distFreqs, m_NewLevels.distLevels,
+ kDistTableSize64, kDistDirectBits, 0);
}
NO_INLINE void CCoder::TryBlock()
@@ -658,7 +670,7 @@
CCodeValue &codeValue = m_Values[m_ValueIndex++];
if (len >= kMatchMinLen)
{
- UInt32 newLen = len - kMatchMinLen;
+ const UInt32 newLen = len - kMatchMinLen;
codeValue.Len = (UInt16)newLen;
mainFreqs[kSymbolMatch + (size_t)g_LenSlots[newLen]]++;
codeValue.Pos = (UInt16)pos;
@@ -666,10 +678,10 @@
}
else
{
- Byte b = *(Inline_MatchFinder_GetPointerToCurrentPos(&_lzInWindow) - m_AdditionalOffset);
+ const unsigned b = *(Inline_MatchFinder_GetPointerToCurrentPos(&_lzInWindow) - m_AdditionalOffset);
mainFreqs[b]++;
- codeValue.SetAsLiteral();
- codeValue.Pos = b;
+ codeValue.Len = k_CodeValue_Len_Is_Literal_Flag;
+ codeValue.Pos = (UInt16)b;
}
m_AdditionalOffset -= len;
BlockSizeRes += len;
@@ -704,16 +716,24 @@
}
}
+#if MAX_HUF_LEN_12 > 12
+// Huffman_ReverseBits() now supports 12-bits values only.
+#error Stop_Compiling_Bad_MAX_HUF_LEN_12
+#endif
static NO_INLINE void Huffman_ReverseBits(UInt32 *codes, const Byte *lens, UInt32 num)
{
- for (UInt32 i = 0; i < num; i++)
+ const Byte * const lens_lim = lens + num;
+ do
{
- UInt32 x = codes[i];
- x = ((x & 0x5555) << 1) | ((x & 0xAAAA) >> 1);
- x = ((x & 0x3333) << 2) | ((x & 0xCCCC) >> 2);
- x = ((x & 0x0F0F) << 4) | ((x & 0xF0F0) >> 4);
- codes[i] = (((x & 0x00FF) << 8) | ((x & 0xFF00) >> 8)) >> (16 - lens[i]);
+ // we should change constants, if lens[*] can be larger than 12.
+ UInt32 x = *codes;
+ x = ((x & (0x555 )) << 2) + (x & (0xAAA ));
+ x = ((x & (0x333 << 1)) << 4) | (x & (0xCCC << 1));
+ x = ((x & (0xF0F << 3)) << 8) | (x & (0x0F0 << 3));
+ // we can use (x) instead of (x & (0xFF << 7)), if we support garabage data after (*lens) bits.
+ *codes++ = (((x & (0xFF << 7)) << 16) | x) >> (*lens ^ 31);
}
+ while (++lens != lens_lim);
}
NO_INLINE void CCoder::WriteBlock()
@@ -721,24 +741,28 @@
Huffman_ReverseBits(mainCodes, m_NewLevels.litLenLevels, kFixedMainTableSize);
Huffman_ReverseBits(distCodes, m_NewLevels.distLevels, kDistTableSize64);
- for (UInt32 i = 0; i < m_ValueIndex; i++)
+ CCodeValue *values = m_Values;
+ const CCodeValue * const values_lim = values + m_ValueIndex;
+
+ if (values != values_lim)
+ do
{
- const CCodeValue &codeValue = m_Values[i];
- if (codeValue.IsLiteral())
- WRITE_HF2(mainCodes, m_NewLevels.litLenLevels, codeValue.Pos);
+ const UInt32 len = values->Len;
+ const UInt32 dist = values->Pos;
+ if (len == k_CodeValue_Len_Is_Literal_Flag)
+ WRITE_HF2(mainCodes, m_NewLevels.litLenLevels, dist);
else
{
- UInt32 len = codeValue.Len;
- UInt32 lenSlot = g_LenSlots[len];
+ const unsigned lenSlot = g_LenSlots[len];
WRITE_HF2(mainCodes, m_NewLevels.litLenLevels, kSymbolMatch + lenSlot);
m_OutStream.WriteBits(len - m_LenStart[lenSlot], m_LenDirectBits[lenSlot]);
- UInt32 dist = codeValue.Pos;
- UInt32 posSlot = GetPosSlot(dist);
+ const unsigned posSlot = GetPosSlot(dist);
WRITE_HF2(distCodes, m_NewLevels.distLevels, posSlot);
m_OutStream.WriteBits(dist - kDistStart[posSlot], kDistDirectBits[posSlot]);
}
}
- WRITE_HF2(mainCodes, m_NewLevels.litLenLevels, kSymbolEndOfBlock);
+ while (++values != values_lim);
+ WRITE_HF2_NO_INLINE(mainCodes, m_NewLevels.litLenLevels, kSymbolEndOfBlock);
}
static UInt32 GetStorePrice(UInt32 blockSize, unsigned bitPosition)
@@ -787,10 +811,10 @@
{
m_Pos = posTemp;
TryBlock();
- unsigned numHuffBits =
- (m_ValueIndex > 18000 ? 12 :
- (m_ValueIndex > 7000 ? 11 :
- (m_ValueIndex > 2000 ? 10 : 9)));
+ const unsigned numHuffBits =
+ m_ValueIndex > 18000 ? MAX_HUF_LEN_12 :
+ m_ValueIndex > 7000 ? 11 :
+ m_ValueIndex > 2000 ? 10 : 9;
MakeTables(numHuffBits);
SetPrices(m_NewLevels);
}
diff -Nru 7zip-24.09+dfsg/CPP/7zip/Compress/Lzma2Encoder.cpp 7zip-25.00+dfsg/CPP/7zip/Compress/Lzma2Encoder.cpp
--- 7zip-24.09+dfsg/CPP/7zip/Compress/Lzma2Encoder.cpp 2023-03-28 13:00:00.000000000 +0200
+++ 7zip-25.00+dfsg/CPP/7zip/Compress/Lzma2Encoder.cpp 2025-06-28 14:00:00.000000000 +0200
@@ -52,7 +52,15 @@
case NCoderPropID::kNumThreads:
if (prop.vt != VT_UI4)
return E_INVALIDARG;
- lzma2Props.numTotalThreads = (int)(prop.ulVal);
+ lzma2Props.numTotalThreads = (int)prop.ulVal;
+ break;
+ case NCoderPropID::kNumThreadGroups:
+ if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ // 16-bit value supported by Windows
+ if (prop.ulVal >= (1u << 16))
+ return E_INVALIDARG;
+ lzma2Props.numThreadGroups = (unsigned)prop.ulVal;
break;
default:
RINOK(NLzma::SetLzmaProp(propID, prop, lzma2Props.lzmaProps))
diff -Nru 7zip-24.09+dfsg/CPP/7zip/Compress/LzmaEncoder.cpp 7zip-25.00+dfsg/CPP/7zip/Compress/LzmaEncoder.cpp
--- 7zip-24.09+dfsg/CPP/7zip/Compress/LzmaEncoder.cpp 2023-03-28 15:00:00.000000000 +0200
+++ 7zip-25.00+dfsg/CPP/7zip/Compress/LzmaEncoder.cpp 2024-12-19 09:00:00.000000000 +0100
@@ -101,6 +101,24 @@
return S_OK;
}
+ if (propID == NCoderPropID::kAffinityInGroup)
+ {
+ if (prop.vt == VT_UI8)
+ ep.affinityInGroup = prop.uhVal.QuadPart;
+ else
+ return E_INVALIDARG;
+ return S_OK;
+ }
+
+ if (propID == NCoderPropID::kThreadGroup)
+ {
+ if (prop.vt == VT_UI4)
+ ep.affinityGroup = (Int32)(UInt32)prop.ulVal;
+ else
+ return E_INVALIDARG;
+ return S_OK;
+ }
+
if (propID == NCoderPropID::kHashBits)
{
if (prop.vt == VT_UI4)
diff -Nru 7zip-24.09+dfsg/CPP/7zip/Compress/Mtf8.h 7zip-25.00+dfsg/CPP/7zip/Compress/Mtf8.h
--- 7zip-24.09+dfsg/CPP/7zip/Compress/Mtf8.h 2023-03-28 15:00:00.000000000 +0200
+++ 7zip-25.00+dfsg/CPP/7zip/Compress/Mtf8.h 2024-12-17 19:00:00.000000000 +0100
@@ -13,6 +13,18 @@
unsigned FindAndMove(Byte v) throw()
{
+#if 1
+ Byte b = Buf[0];
+ if (v == b)
+ return 0;
+ Buf[0] = v;
+ for (unsigned pos = 0;;)
+ {
+ Byte a;
+ a = Buf[++pos]; Buf[pos] = b; if (v == a) return pos;
+ b = Buf[++pos]; Buf[pos] = a; if (v == b) return pos;
+ }
+#else
size_t pos;
for (pos = 0; Buf[pos] != v; pos++);
const unsigned resPos = (unsigned)pos;
@@ -31,6 +43,7 @@
Buf[pos] = Buf[pos - 1];
Buf[0] = v;
return resPos;
+#endif
}
};
diff -Nru 7zip-24.09+dfsg/CPP/7zip/Crypto/MyAes.cpp 7zip-25.00+dfsg/CPP/7zip/Crypto/MyAes.cpp
--- 7zip-24.09+dfsg/CPP/7zip/Crypto/MyAes.cpp 2024-03-01 10:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/7zip/Crypto/MyAes.cpp 2024-12-10 09:00:00.000000000 +0100
@@ -153,7 +153,26 @@
#ifndef Z7_EXTRACT_ONLY
#ifdef MY_CPU_X86_OR_AMD64
- #define USE_HW_AES
+
+ #if defined(__INTEL_COMPILER)
+ #if (__INTEL_COMPILER >= 1110)
+ #define USE_HW_AES
+ #if (__INTEL_COMPILER >= 1900)
+ #define USE_HW_VAES
+ #endif
+ #endif
+ #elif defined(Z7_CLANG_VERSION) && (Z7_CLANG_VERSION >= 30800) \
+ || defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40400)
+ #define USE_HW_AES
+ #if defined(__clang__) && (__clang_major__ >= 8) \
+ || defined(__GNUC__) && (__GNUC__ >= 8)
+ #define USE_HW_VAES
+ #endif
+ #elif defined(_MSC_VER)
+ #define USE_HW_AES
+ #define USE_HW_VAES
+ #endif
+
#elif defined(MY_CPU_ARM_OR_ARM64) && defined(MY_CPU_LE)
#if defined(__ARM_FEATURE_AES) \
@@ -186,15 +205,15 @@
#define SET_AES_FUNC_2(f2) \
if (algo == 2) if (g_Aes_SupportedFunctions_Flags & k_Aes_SupportedFunctions_HW) \
{ f = f2; }
- #ifdef MY_CPU_X86_OR_AMD64
+ #ifdef USE_HW_VAES
#define SET_AES_FUNC_23(f2, f3) \
SET_AES_FUNC_2(f2) \
if (algo == 3) if (g_Aes_SupportedFunctions_Flags & k_Aes_SupportedFunctions_HW_256) \
{ f = f3; }
- #else // MY_CPU_X86_OR_AMD64
+ #else // USE_HW_VAES
#define SET_AES_FUNC_23(f2, f3) \
SET_AES_FUNC_2(f2)
- #endif // MY_CPU_X86_OR_AMD64
+ #endif // USE_HW_VAES
#else // USE_HW_AES
#define SET_AES_FUNC_23(f2, f3)
#endif // USE_HW_AES
diff -Nru 7zip-24.09+dfsg/CPP/7zip/ICoder.h 7zip-25.00+dfsg/CPP/7zip/ICoder.h
--- 7zip-24.09+dfsg/CPP/7zip/ICoder.h 2023-04-06 12:00:00.000000000 +0200
+++ 7zip-25.00+dfsg/CPP/7zip/ICoder.h 2024-12-14 20:00:00.000000000 +0100
@@ -136,6 +136,9 @@
kAffinity, // VT_UI8
kBranchOffset, // VT_UI4
kHashBits, // VT_UI4
+ kNumThreadGroups, // VT_UI4
+ kThreadGroup, // VT_UI4
+ kAffinityInGroup, // VT_UI8
/*
// kHash3Bits, // VT_UI4
// kHash2Bits, // VT_UI4
diff -Nru 7zip-24.09+dfsg/CPP/7zip/Sort.mak 7zip-25.00+dfsg/CPP/7zip/Sort.mak
--- 7zip-24.09+dfsg/CPP/7zip/Sort.mak 1970-01-01 01:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/7zip/Sort.mak 2025-07-02 10:00:00.000000000 +0200
@@ -0,0 +1,6 @@
+!IF defined(USE_NO_ASM) || defined(USE_C_SORT) || "$(PLATFORM)" == "ia64" || "$(PLATFORM)" == "mips" || "$(PLATFORM)" == "arm" || "$(PLATFORM)" == "arm64"
+C_OBJS = $(C_OBJS) \
+!ELSE
+ASM_OBJS = $(ASM_OBJS) \
+!ENDIF
+ $O\Sort.obj
diff -Nru 7zip-24.09+dfsg/CPP/7zip/UI/Common/ArchiveCommandLine.cpp 7zip-25.00+dfsg/CPP/7zip/UI/Common/ArchiveCommandLine.cpp
--- 7zip-24.09+dfsg/CPP/7zip/UI/Common/ArchiveCommandLine.cpp 2024-06-17 13:00:00.000000000 +0200
+++ 7zip-25.00+dfsg/CPP/7zip/UI/Common/ArchiveCommandLine.cpp 2025-07-03 13:00:00.000000000 +0200
@@ -63,17 +63,46 @@
#else
-// #define MY_isatty_fileno(x) (isatty(fileno(x)))
-// #define MY_IS_TERMINAL(x) (MY_isatty_fileno(x) != 0);
-static inline bool MY_IS_TERMINAL(FILE *x)
-{
- return (
- #if defined(_MSC_VER) && (_MSC_VER >= 1400)
- _isatty(_fileno(x))
- #else
- isatty(fileno(x))
- #endif
- != 0);
+static bool MY_IS_TERMINAL(FILE *x)
+{
+#ifdef _WIN32
+ /*
+crt/stdio.h:
+typedef struct _iobuf FILE;
+#define stdin (&_iob[0])
+#define stdout (&_iob[1])
+#define stderr (&_iob[2])
+*/
+ // fprintf(stderr, "\nMY_IS_TERMINAL = %p", x);
+ const int fd = _fileno(x);
+ /* (fd) is 0, 1 or 2 in console program.
+ docs: If stdout or stderr is not associated with
+ an output stream (for example, in a Windows application
+ without a console window), the file descriptor returned is -2.
+ In previous versions, the file descriptor returned was -1.
+ */
+ if (fd < 0) // is not associated with an output stream application (without a console window)
+ return false;
+ // fprintf(stderr, "\n\nstderr _fileno(%p) = %d", x, fd);
+ if (!_isatty(fd))
+ return false;
+ // fprintf(stderr, "\nisatty_val = true");
+ const HANDLE h = (HANDLE)_get_osfhandle(fd);
+ /* _get_osfhandle() returns intptr_t in new SDK, or long in MSVC6.
+ Also it can return (INVALID_HANDLE_VALUE).
+ docs: _get_osfhandle also returns the special value -2 when
+ the file descriptor is not associated with a stream
+ in old msvcrt.dll: it returns (-1) for incorrect value
+ */
+ // fprintf(stderr, "\n_get_osfhandle() = %p", (void *)h);
+ if (h == NULL || h == INVALID_HANDLE_VALUE)
+ return false;
+ DWORD st;
+ // fprintf(stderr, "\nGetConsoleMode() = %u", (unsigned)GetConsoleMode(h, &st));
+ return GetConsoleMode(h, &st) != 0;
+#else
+ return isatty(fileno(x)) != 0;
+#endif
}
#endif
@@ -1088,7 +1117,7 @@
const UString &s = parser[NKey::kLargePages].PostStrings[0];
if (s.IsEmpty())
slp = 1;
- else if (s != L"-")
+ else if (!s.IsEqualTo("-"))
{
if (!StringToUInt32(s, slp))
throw CArcCmdLineException("Unsupported switch postfix for -slp", s);
@@ -1338,7 +1367,7 @@
const UString &s = parser[NKey::kFullPathMode].PostStrings[0];
if (!s.IsEmpty())
{
- if (s == L"2")
+ if (s.IsEqualTo("2"))
censorPathMode = NWildcard::k_FullPath;
else
throw CArcCmdLineException("Unsupported -spf:", s);
@@ -1400,6 +1429,7 @@
const bool isExtractGroupCommand = options.Command.IsFromExtractGroup();
const bool isExtractOrList = isExtractGroupCommand || options.Command.CommandType == NCommandType::kList;
const bool isRename = options.Command.CommandType == NCommandType::kRename;
+ options.UpdateOptions.RenameMode = isRename;
if ((isExtractOrList || isRename) && options.StdInMode)
thereIsArchiveName = false;
@@ -1516,9 +1546,9 @@
const UString &s = parser[NKey::kZoneFile].PostStrings[0];
if (!s.IsEmpty())
{
- if (s == L"0") eo.ZoneMode = NExtract::NZoneIdMode::kNone;
- else if (s == L"1") eo.ZoneMode = NExtract::NZoneIdMode::kAll;
- else if (s == L"2") eo.ZoneMode = NExtract::NZoneIdMode::kOffice;
+ if (s.IsEqualTo("0")) eo.ZoneMode = NExtract::NZoneIdMode::kNone;
+ else if (s.IsEqualTo("1")) eo.ZoneMode = NExtract::NZoneIdMode::kAll;
+ else if (s.IsEqualTo("2")) eo.ZoneMode = NExtract::NZoneIdMode::kOffice;
else
throw CArcCmdLineException("Unsupported -snz:", s);
}
diff -Nru 7zip-24.09+dfsg/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp 7zip-25.00+dfsg/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp
--- 7zip-24.09+dfsg/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp 2024-10-11 18:00:00.000000000 +0200
+++ 7zip-25.00+dfsg/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp 2025-06-29 11:00:00.000000000 +0200
@@ -6,12 +6,10 @@
#undef printf
// #include <stdio.h>
-// #include "../../../../C/CpuTicks.h"
#include "../../../../C/Alloc.h"
#include "../../../../C/CpuArch.h"
-
#include "../../../Common/ComTry.h"
#include "../../../Common/IntToString.h"
#include "../../../Common/StringConvert.h"
@@ -33,6 +31,8 @@
#include "../../Common/FilePathAutoRename.h"
#include "../../Common/StreamUtils.h"
+#include "../../Archive/Common/ItemNameUtils.h"
+
#include "../Common/ExtractingFilePath.h"
#include "../Common/PropIDUtils.h"
@@ -56,6 +56,19 @@
static const char * const kCantCreateSymLink = "Cannot create symbolic link";
#endif
+static const unsigned k_LinkDataSize_LIMIT = 1 << 12;
+
+#if WCHAR_PATH_SEPARATOR != L'/'
+ // we convert linux slashes to windows slashes for further processing.
+ // also we convert linux backslashes to BackslashReplacement character.
+ #define REPLACE_SLASHES_from_Linux_to_Sys(s) \
+ { NArchive::NItemName::ReplaceToWinSlashes(s, true); } // useBackslashReplacement
+ // { s.Replace(L'/', WCHAR_PATH_SEPARATOR); }
+#else
+ #define REPLACE_SLASHES_from_Linux_to_Sys(s)
+#endif
+
+
#ifndef Z7_SFX
Z7_COM7F_IMF(COutStreamWithHash::Write(const void *data, UInt32 size, UInt32 *processedSize))
@@ -217,7 +230,7 @@
if (!_arc->Ask_INode)
return S_OK;
- IInArchive *archive = _arc->Archive;
+ IInArchive * const archive = _arc->Archive;
CRecordVector<CHardLinkNode> &hardIDs = _hardLinks.IDs;
{
@@ -574,6 +587,13 @@
return _extractCallback2->MessageError(s);
}
+HRESULT CArchiveExtractCallback::SendMessageError2_with_LastError(
+ const char *message, const FString &path1, const FString &path2)
+{
+ const HRESULT errorCode = GetLastError_noZero_HRESULT();
+ return SendMessageError2(errorCode, message, path1, path2);
+}
+
#ifndef Z7_SFX
Z7_CLASS_IMP_COM_1(
@@ -604,36 +624,20 @@
#endif // Z7_SFX
-#ifdef SUPPORT_LINKS
-
-static UString GetDirPrefixOf(const UString &src)
-{
- UString s (src);
- if (!s.IsEmpty())
- {
- if (IsPathSepar(s.Back()))
- s.DeleteBack();
- int pos = s.ReverseFind_PathSepar();
- s.DeleteFrom((unsigned)(pos + 1));
- }
- return s;
-}
-
-#endif // SUPPORT_LINKS
-
struct CLinkLevelsInfo
{
bool IsAbsolute;
int LowLevel;
int FinalLevel;
- void Parse(const UString &path);
+ void Parse(const UString &path, bool isWSL);
};
-void CLinkLevelsInfo::Parse(const UString &path)
+void CLinkLevelsInfo::Parse(const UString &path, bool isWSL)
{
- IsAbsolute = NName::IsAbsolutePath(path);
-
+ IsAbsolute = isWSL ?
+ IS_PATH_SEPAR(path[0]) :
+ NName::IsAbsolutePath(path);
LowLevel = 0;
FinalLevel = 0;
@@ -650,9 +654,9 @@
IsAbsolute = true;
continue;
}
- if (s == L".")
+ if (s.IsEqualTo("."))
continue;
- if (s == L"..")
+ if (s.IsEqualTo(".."))
{
level--;
if (LowLevel > level)
@@ -666,16 +670,20 @@
}
-bool IsSafePath(const UString &path);
-bool IsSafePath(const UString &path)
+static bool IsSafePath(const UString &path, bool isWSL)
{
CLinkLevelsInfo levelsInfo;
- levelsInfo.Parse(path);
+ levelsInfo.Parse(path, isWSL);
return !levelsInfo.IsAbsolute
&& levelsInfo.LowLevel >= 0
&& levelsInfo.FinalLevel > 0;
}
+bool IsSafePath(const UString &path);
+bool IsSafePath(const UString &path)
+{
+ return IsSafePath(path, false); // isWSL
+}
bool CensorNode_CheckPath2(const NWildcard::CCensorNode &node, const CReadArcItem &item, bool &include);
bool CensorNode_CheckPath2(const NWildcard::CCensorNode &node, const CReadArcItem &item, bool &include)
@@ -791,159 +799,113 @@
HRESULT CArchiveExtractCallback::ReadLink()
{
- IInArchive *archive = _arc->Archive;
+ IInArchive * const archive = _arc->Archive;
const UInt32 index = _index;
- _link.Clear();
-
+ // _link.Clear(); // _link.Clear() was called already.
{
NCOM::CPropVariant prop;
RINOK(archive->GetProperty(index, kpidHardLink, &prop))
if (prop.vt == VT_BSTR)
{
- _link.isHardLink = true;
- // _link.isCopyLink = false;
+ _link.LinkType = k_LinkType_HardLink;
_link.isRelative = false; // RAR5, TAR: hard links are from root folder of archive
- _link.linkPath.SetFromBstr(prop.bstrVal);
+ _link.LinkPath.SetFromBstr(prop.bstrVal);
+ // 7-Zip 24-: tar handler returned original path (with linux slash in most case)
+ // 7-Zip 24-: rar5 handler returned path with system slash.
+ // 7-Zip 25+: tar/rar5 handlers return linux path in most cases.
}
else if (prop.vt != VT_EMPTY)
return E_FAIL;
}
-
/*
{
NCOM::CPropVariant prop;
RINOK(archive->GetProperty(index, kpidCopyLink, &prop));
if (prop.vt == VT_BSTR)
{
- _link.isHardLink = false;
- _link.isCopyLink = true;
+ _link.LinkType = k_LinkType_CopyLink;
_link.isRelative = false; // RAR5: copy links are from root folder of archive
- _link.linkPath.SetFromBstr(prop.bstrVal);
+ _link.LinkPath.SetFromBstr(prop.bstrVal);
}
else if (prop.vt != VT_EMPTY)
return E_FAIL;
}
*/
-
{
NCOM::CPropVariant prop;
RINOK(archive->GetProperty(index, kpidSymLink, &prop))
if (prop.vt == VT_BSTR)
{
- _link.isHardLink = false;
- // _link.isCopyLink = false;
- _link.isRelative = true; // RAR5, TAR: symbolic links can be relative
- _link.linkPath.SetFromBstr(prop.bstrVal);
+ _link.LinkType = k_LinkType_PureSymLink;
+ _link.isRelative = true; // RAR5, TAR: symbolic links are relative by default
+ _link.LinkPath.SetFromBstr(prop.bstrVal);
+ // 7-Zip 24-: (tar, cpio, xar, ext, iso) handlers returned returned original path (with linux slash in most case)
+ // 7-Zip 24-: rar5 handler returned path with system slash.
+ // 7-Zip 25+: all handlers return linux path in most cases.
}
else if (prop.vt != VT_EMPTY)
return E_FAIL;
}
- NtReparse_Data = NULL;
- NtReparse_Size = 0;
-
- if (_link.linkPath.IsEmpty() && _arc->GetRawProps)
+ // linux path separator in (_link.LinkPath) is expected for most cases,
+ // if new handler code is used, and if data in archive is correct.
+ // NtReparse_Data = NULL;
+ // NtReparse_Size = 0;
+ if (!_link.LinkPath.IsEmpty())
+ {
+ REPLACE_SLASHES_from_Linux_to_Sys(_link.LinkPath)
+ }
+ else if (_arc->GetRawProps)
{
const void *data;
- UInt32 dataSize;
- UInt32 propType;
-
- _arc->GetRawProps->GetRawProp(_index, kpidNtReparse, &data, &dataSize, &propType);
-
- // if (dataSize == 1234567) // for debug: unpacking without reparse
- if (dataSize != 0)
+ UInt32 dataSize, propType;
+ if (_arc->GetRawProps->GetRawProp(_index, kpidNtReparse, &data, &dataSize, &propType) == S_OK
+ // && dataSize == 1234567 // for debug: unpacking without reparse
+ && dataSize)
{
if (propType != NPropDataType::kRaw)
return E_FAIL;
-
// 21.06: we need kpidNtReparse in linux for wim archives created in Windows
- // #ifdef _WIN32
-
- NtReparse_Data = data;
- NtReparse_Size = dataSize;
-
- CReparseAttr reparse;
- bool isOkReparse = reparse.Parse((const Byte *)data, dataSize);
- if (isOkReparse)
- {
- _link.isHardLink = false;
- // _link.isCopyLink = false;
- _link.linkPath = reparse.GetPath();
- _link.isJunction = reparse.IsMountPoint();
-
- if (reparse.IsSymLink_WSL())
- {
- _link.isWSL = true;
- _link.isRelative = reparse.IsRelative_WSL();
- }
- else
- _link.isRelative = reparse.IsRelative_Win();
-
- // const AString s = GetAnsiString(_link.linkPath);
- // printf("\n_link.linkPath: %s\n", s.Ptr());
-
- #ifndef _WIN32
- _link.linkPath.Replace(L'\\', WCHAR_PATH_SEPARATOR);
- #endif
- }
- // #endif
+ // NtReparse_Data = data;
+ // NtReparse_Size = dataSize;
+ // we ignore error code here, if there is failure of parsing:
+ _link.Parse_from_WindowsReparseData((const Byte *)data, dataSize);
}
}
- if (_link.linkPath.IsEmpty())
+ if (_link.LinkPath.IsEmpty())
return S_OK;
-
+ // (_link.LinkPath) uses system path separator.
+ // windows: (_link.LinkPath) doesn't contain linux separator (slash).
{
- #ifdef _WIN32
- _link.linkPath.Replace(L'/', WCHAR_PATH_SEPARATOR);
- #endif
-
- // rar5 uses "\??\" prefix for absolute links
- if (_link.linkPath.IsPrefixedBy(WSTRING_PATH_SEPARATOR L"??" WSTRING_PATH_SEPARATOR))
- {
- _link.isRelative = false;
- _link.linkPath.DeleteFrontal(4);
- }
-
- for (;;)
- // while (NName::IsAbsolutePath(linkPath))
+ // _link.LinkPath = "\\??\\r:\\1\\2"; // for debug
+ // rar5+ returns kpidSymLink absolute link path with "\??\" prefix.
+ // we normalize such prefix:
+ if (_link.LinkPath.IsPrefixedBy(STRING_PATH_SEPARATOR "??" STRING_PATH_SEPARATOR))
{
- unsigned n = NName::GetRootPrefixSize(_link.linkPath);
- if (n == 0)
- break;
_link.isRelative = false;
- _link.linkPath.DeleteFrontal(n);
- }
- }
-
- if (_link.linkPath.IsEmpty())
- return S_OK;
-
- if (!_link.isRelative && _removePathParts.Size() != 0)
- {
- UStringVector pathParts;
- SplitPathToParts(_link.linkPath, pathParts);
- bool badPrefix = false;
- FOR_VECTOR (i, _removePathParts)
- {
- if (CompareFileNames(_removePathParts[i], pathParts[i]) != 0)
+ // we normalize prefix from "\??\" to "\\?\":
+ _link.LinkPath.ReplaceOneCharAtPos(1, WCHAR_PATH_SEPARATOR);
+ _link.isWindowsPath = true;
+ if (_link.LinkPath.IsPrefixedBy_Ascii_NoCase(
+ STRING_PATH_SEPARATOR
+ STRING_PATH_SEPARATOR "?"
+ STRING_PATH_SEPARATOR "UNC"
+ STRING_PATH_SEPARATOR))
+ {
+ // we normalize prefix from "\\?\UNC\path" to "\\path":
+ _link.LinkPath.DeleteFrontal(6);
+ _link.LinkPath.ReplaceOneCharAtPos(0, WCHAR_PATH_SEPARATOR);
+ }
+ else
{
- badPrefix = true;
- break;
+ const unsigned k_prefix_Size = 4;
+ if (NName::IsDrivePath(_link.LinkPath.Ptr(k_prefix_Size)))
+ _link.LinkPath.DeleteFrontal(k_prefix_Size);
}
}
- if (!badPrefix)
- pathParts.DeleteFrontal(_removePathParts.Size());
- _link.linkPath = MakePathFromParts(pathParts);
}
-
- /*
- if (!_link.linkPath.IsEmpty())
- {
- printf("\n_link %s to -> %s\n", GetOemString(_item.Path).Ptr(), GetOemString(_link.linkPath).Ptr());
- }
- */
-
+ _link.Normalize_to_RelativeSafe(_removePathParts);
return S_OK;
}
@@ -961,7 +923,7 @@
if (prop.vt == VT_UI4)
{
res.Id_Defined = true;
- res.Id = prop.ulVal; // for debug
+ res.Id = prop.ulVal;
// res.Id++; // for debug
// if (pidId == kpidGroupId) res.Id += 7; // for debug
// res.Id = 0; // for debug
@@ -993,7 +955,7 @@
HRESULT CArchiveExtractCallback::Read_fi_Props()
{
- IInArchive *archive = _arc->Archive;
+ IInArchive * const archive = _arc->Archive;
const UInt32 index = _index;
_fi.Attrib_Defined = false;
@@ -1134,7 +1096,7 @@
if (!_item.IsDir
#ifdef SUPPORT_LINKS
#ifndef WIN32
- || !_link.linkPath.IsEmpty()
+ || !_link.LinkPath.IsEmpty()
#endif
#endif
)
@@ -1273,8 +1235,7 @@
// MyMoveFile can rename folders. So it's OK to use it for folders too
if (!MyMoveFile(fullProcessedPath, existPath))
{
- HRESULT errorCode = GetLastError_noZero_HRESULT();
- RINOK(SendMessageError2(errorCode, kCantRenameFile, existPath, fullProcessedPath))
+ RINOK(SendMessageError2_with_LastError(kCantRenameFile, existPath, fullProcessedPath))
return E_FAIL;
}
}
@@ -1341,7 +1302,7 @@
RINOK(Read_fi_Props())
#ifdef SUPPORT_LINKS
- IInArchive *archive = _arc->Archive;
+ IInArchive * const archive = _arc->Archive;
#endif
const UInt32 index = _index;
@@ -1387,7 +1348,7 @@
if (isAnti)
RemoveDir(_diskFilePath);
#ifdef SUPPORT_LINKS
- if (_link.linkPath.IsEmpty())
+ if (_link.LinkPath.IsEmpty())
#endif
{
if (!isAnti)
@@ -1416,15 +1377,15 @@
#ifdef SUPPORT_LINKS
- if (!_link.linkPath.IsEmpty())
+ if (!_link.LinkPath.IsEmpty())
{
#ifndef UNDER_CE
{
bool linkWasSet = false;
- RINOK(SetFromLinkPath(fullProcessedPath, _link, linkWasSet))
+ RINOK(SetLink(fullProcessedPath, _link, linkWasSet))
if (linkWasSet)
{
- _isSymLinkCreated = _link.IsSymLink();
+ _isSymLinkCreated = _link.Is_AnySymLink();
SetAttrib();
// printf("\nlinkWasSet %s\n", GetAnsiString(_diskFilePath));
}
@@ -1454,12 +1415,7 @@
else
{
if (!MyCreateHardLink(fullProcessedPath, hl))
- {
- const HRESULT errorCode = GetLastError_noZero_HRESULT();
- RINOK(SendMessageError2(errorCode, kCantCreateHardLink, fullProcessedPath, hl))
- return S_OK;
- }
-
+ return SendMessageError2_with_LastError(kCantCreateHardLink, fullProcessedPath, hl);
// printf("\nHard linkWasSet Archive_Get_HardLinkNode %s\n", GetAnsiString(_diskFilePath));
// _needSetAttrib = true; // do we need to set attribute ?
SetAttrib();
@@ -1491,7 +1447,7 @@
bool is_SymLink_in_Data = false;
- if (_curSize_Defined && _curSize > 0 && _curSize < (1 << 12))
+ if (_curSize_Defined && _curSize && _curSize < k_LinkDataSize_LIMIT)
{
if (_fi.IsLinuxSymLink())
{
@@ -1513,7 +1469,7 @@
_bufPtrSeqOutStream_Spec->Init(_outMemBuf, _outMemBuf.Size());
outStreamLoc = _bufPtrSeqOutStream;
}
- else // not reprase
+ else // not reparse
{
if (_ntOptions.PreAllocateOutFile && !_isSplit && _curSize_Defined && _curSize > (1 << 12))
{
@@ -1568,7 +1524,7 @@
RINOK(outFileStream_Loc->Seek((Int64)_position, STREAM_SEEK_SET, NULL))
}
outStreamLoc = outFileStream_Loc;
- } // if not reprase
+ } // if not reparse
_outFileStream = outFileStream_Loc;
@@ -1620,8 +1576,7 @@
_fileLength_WasSet = false;
_isRenamed = false;
// _fi.Clear();
- _extractMode = false;
- // _is_SymLink_in_Data = false;
+ _extractMode = false;
_is_SymLink_in_Data_Linux = false;
_needSetAttrib = false;
_isSymLinkCreated = false;
@@ -1661,7 +1616,7 @@
}
- IInArchive *archive = _arc->Archive;
+ IInArchive * const archive = _arc->Archive;
RINOK(GetItem(index))
@@ -1677,10 +1632,9 @@
}
}
- #ifdef SUPPORT_LINKS
+#ifdef SUPPORT_LINKS
RINOK(ReadLink())
- #endif // SUPPORT_LINKS
-
+#endif
RINOK(Archive_GetItemBoolProp(archive, index, kpidEncrypted, _encrypted))
@@ -2016,63 +1970,80 @@
#ifdef SUPPORT_LINKS
+/*
+in:
+ link.LinkPath : must be relative (non-absolute) path in any case !!!
+ link.isRelative / target path that must stored as created link:
+ == false / _dirPathPrefix_Full + link.LinkPath
+ == true / link.LinkPath
+*/
-HRESULT CArchiveExtractCallback::SetFromLinkPath(
- const FString &fullProcessedPath,
- const CLinkInfo &linkInfo,
+HRESULT CArchiveExtractCallback::SetLink(
+ const FString &fullProcessedPath_from,
+ const CLinkInfo &link,
bool &linkWasSet)
{
linkWasSet = false;
- if (!_ntOptions.SymLinks.Val && !linkInfo.isHardLink)
+ if (link.LinkPath.IsEmpty())
+ return S_OK;
+ if (!_ntOptions.SymLinks.Val && link.Is_AnySymLink())
return S_OK;
-
- UString relatPath;
-
- /* if (linkInfo.isRelative)
- linkInfo.linkPath is final link path that must be stored to file link field
- else
- linkInfo.linkPath is path from root of archive. So we must add _dirPathPrefix_Full before linkPath.
- */
-
- if (linkInfo.isRelative)
- relatPath = GetDirPrefixOf(_item.Path);
- relatPath += linkInfo.linkPath;
-
- if (!IsSafePath(relatPath))
{
- return SendMessageError2(
- 0, // errorCode
+ UString path;
+ if (link.isRelative)
+ {
+ // _item.PathParts : parts that will be created in output folder.
+ // we want to get directory prefix of link item.
+ // so we remove file name (last non-empty part) from PathParts:
+ UStringVector v = _item.PathParts;
+ while (!v.IsEmpty())
+ {
+ const unsigned len = v.Back().Len();
+ v.DeleteBack();
+ if (len)
+ break;
+ }
+ path = MakePathFromParts(v);
+ NName::NormalizeDirPathPrefix(path);
+ }
+ path += link.LinkPath;
+ /*
+ path is calculated virtual target path of link
+ path is relative to root folder of extracted items
+ if (!link.isRelative), then (path == link.LinkPath)
+ */
+ if (!IsSafePath(path, link.Is_WSL()))
+ return SendMessageError2(0, // errorCode
"Dangerous link path was ignored",
- us2fs(_item.Path),
- us2fs(linkInfo.linkPath)); // us2fs(relatPath)
+ us2fs(_item.Path), us2fs(link.LinkPath));
}
- FString existPath;
- if (linkInfo.isHardLink /* || linkInfo.IsCopyLink */ || !linkInfo.isRelative)
+ FString target; // target path that will be stored to link field
+ if (link.Is_HardLink() /* || link.IsCopyLink */ || !link.isRelative)
{
- if (!NName::GetFullPath(_dirPathPrefix_Full, us2fs(relatPath), existPath))
- {
- RINOK(SendMessageError("Incorrect path", us2fs(relatPath)))
- }
+ // isRelative == false
+ // all hard links and absolute symbolic links
+ // relatPath == link.LinkPath
+ // we get absolute link path for target:
+ if (!NName::GetFullPath(_dirPathPrefix_Full, us2fs(link.LinkPath), target))
+ return SendMessageError("Incorrect link path", us2fs(link.LinkPath));
+ // (target) is (_dirPathPrefix_Full + relatPath)
}
else
{
- existPath = us2fs(linkInfo.linkPath);
- // printf("\nlinkPath = : %s\n", GetOemString(linkInfo.linkPath).Ptr());
+ // link.isRelative == true
+ // relative symbolic links only
+ target = us2fs(link.LinkPath);
}
-
- if (existPath.IsEmpty())
- return SendMessageError("Empty link", fullProcessedPath);
+ if (target.IsEmpty())
+ return SendMessageError("Empty link", fullProcessedPath_from);
- if (linkInfo.isHardLink /* || linkInfo.IsCopyLink */)
+ if (link.Is_HardLink() /* || link.IsCopyLink */)
{
- // if (linkInfo.isHardLink)
+ // if (link.isHardLink)
{
- if (!MyCreateHardLink(fullProcessedPath, existPath))
- {
- const HRESULT errorCode = GetLastError_noZero_HRESULT();
- RINOK(SendMessageError2(errorCode, kCantCreateHardLink, fullProcessedPath, existPath))
- }
+ if (!MyCreateHardLink(fullProcessedPath_from, target))
+ return SendMessageError2_with_LastError(kCantCreateHardLink, fullProcessedPath_from, target);
/*
RINOK(PrepareOperation(NArchive::NExtract::NAskMode::kExtract))
_op_WasReported = true;
@@ -2085,19 +2056,19 @@
// IsCopyLink
{
NFind::CFileInfo fi;
- if (!fi.Find(existPath))
+ if (!fi.Find(target))
{
- RINOK(SendMessageError2("Cannot find the file for copying", existPath, fullProcessedPath));
+ RINOK(SendMessageError2("Cannot find the file for copying", target, fullProcessedPath));
}
else
{
if (_curSize_Defined && _curSize == fi.Size)
- _copyFile_Path = existPath;
+ _copyFile_Path = target;
else
{
- RINOK(SendMessageError2("File size collision for file copying", existPath, fullProcessedPath));
+ RINOK(SendMessageError2("File size collision for file copying", target, fullProcessedPath));
}
- // RINOK(MyCopyFile(existPath, fullProcessedPath));
+ // RINOK(MyCopyFile(target, fullProcessedPath));
}
}
*/
@@ -2111,127 +2082,249 @@
// Windows before Vista doesn't support symbolic links.
// we could convert such symbolic links to Junction Points
// isJunction = true;
- // convertToAbs = true;
}
*/
- if (!_ntOptions.SymLinks_AllowDangerous.Val)
+#ifdef _WIN32
+ const bool isDir = (_item.IsDir || link.LinkType == k_LinkType_Junction);
+#endif
+
+ if (!_ntOptions.SymLinks_AllowDangerous.Val && link.isRelative)
{
- #ifdef _WIN32
- if (_item.IsDir)
- #endif
- if (linkInfo.isRelative)
- {
- CLinkLevelsInfo levelsInfo;
- levelsInfo.Parse(linkInfo.linkPath);
- if (levelsInfo.FinalLevel < 1 || levelsInfo.IsAbsolute)
- {
- return SendMessageError2(
- 0, // errorCode
- "Dangerous symbolic link path was ignored",
- us2fs(_item.Path),
- us2fs(linkInfo.linkPath));
- }
- }
+ /*
+ We want to use additional check for links that can link to directory.
+ - linux: all symbolic links are files.
+ - windows: we can have file/directory symbolic link,
+ but file symbolic link works like directory link in windows.
+ So we use additional check for all relative links.
+
+ We don't allow decreasing of final level of link.
+ So if some another extracted file will use this link,
+ then number of real path parts (after link redirection) cannot be
+ smaller than number of requested path parts from archive records.
+
+ Now we check only (link.LinkPath) without (_item.PathParts).
+ */
+ CLinkLevelsInfo levelsInfo;
+ levelsInfo.Parse(link.LinkPath, link.Is_WSL());
+ if (levelsInfo.FinalLevel < 1
+ // || levelsInfo.LowLevel < 0 // we allow negative temporary levels
+ || levelsInfo.IsAbsolute)
+ return SendMessageError2(0, // errorCode
+ "Dangerous symbolic link path was ignored",
+ us2fs(_item.Path), us2fs(link.LinkPath));
}
- #ifdef _WIN32
-
+#ifdef _WIN32
CByteBuffer data;
- // printf("\nFillLinkData(): %s\n", GetOemString(existPath).Ptr());
- if (!FillLinkData(data, fs2us(existPath), !linkInfo.isJunction, linkInfo.isWSL))
+ // printf("\nFillLinkData(): %s\n", GetOemString(target).Ptr());
+ if (link.Is_WSL())
+ {
+ Convert_WinPath_to_WslLinuxPath(target, !link.isRelative);
+ FillLinkData_WslLink(data, fs2us(target));
+ }
+ else
+ FillLinkData_WinLink(data, fs2us(target), link.LinkType != k_LinkType_Junction);
+ if (data.Size() == 0)
return SendMessageError("Cannot fill link data", us2fs(_item.Path));
-
/*
if (NtReparse_Size != data.Size() || memcmp(NtReparse_Data, data, data.Size()) != 0)
- {
- SendMessageError("reconstructed Reparse is different", fs2us(existPath));
- }
+ SendMessageError("reconstructed Reparse is different", fs2us(target));
*/
-
- CReparseAttr attr;
- if (!attr.Parse(data, data.Size()))
{
- RINOK(SendMessageError("Internal error for symbolic link file", us2fs(_item.Path)))
- return S_OK;
- }
- if (!NFile::NIO::SetReparseData(fullProcessedPath, _item.IsDir, data, (DWORD)data.Size()))
+ // we check that reparse data is correct, but we ignore attr.MinorError.
+ CReparseAttr attr;
+ if (!attr.Parse(data, data.Size()))
+ return SendMessageError("Internal error for symbolic link file", us2fs(_item.Path));
+ }
+ if (!NFile::NIO::SetReparseData(fullProcessedPath_from, isDir, data, (DWORD)data.Size()))
+#else // ! _WIN32
+ if (!NFile::NIO::SetSymLink(fullProcessedPath_from, target))
+#endif // ! _WIN32
{
- RINOK(SendMessageError_with_LastError(kCantCreateSymLink, fullProcessedPath))
- return S_OK;
+ return SendMessageError_with_LastError(kCantCreateSymLink, fullProcessedPath_from);
}
linkWasSet = true;
-
return S_OK;
-
-
- #else // ! _WIN32
+}
+
+
- if (!NFile::NIO::SetSymLink(fullProcessedPath, existPath))
+bool CLinkInfo::Parse_from_WindowsReparseData(const Byte *data, size_t dataSize)
+{
+ CReparseAttr reparse;
+ if (!reparse.Parse(data, dataSize))
+ return false;
+ // const AString s = GetAnsiString(LinkPath);
+ // printf("\nlinkPath: %s\n", s.Ptr());
+ LinkPath = reparse.GetPath();
+ if (reparse.IsSymLink_WSL())
{
- RINOK(SendMessageError_with_LastError(kCantCreateSymLink, fullProcessedPath))
- return S_OK;
+ LinkType = k_LinkType_WSL;
+ isRelative = reparse.IsRelative_WSL(); // detected from LinkPath[0]
+ // LinkPath is original raw name converted to UString from AString
+ // Linux separator '/' is expected here.
+ REPLACE_SLASHES_from_Linux_to_Sys(LinkPath)
}
- linkWasSet = true;
+ else
+ {
+ LinkType = reparse.IsMountPoint() ? k_LinkType_Junction : k_LinkType_PureSymLink;
+ isRelative = reparse.IsRelative_Win(); // detected by (Flags == Z7_WIN_SYMLINK_FLAG_RELATIVE)
+ isWindowsPath = true;
+ // LinkPath is original windows link path from raparse data with \??\ prefix removed.
+ // windows '\\' separator is expected here.
+ // linux '/' separator is not expected here.
+ // we translate both types of separators to system separator.
+ LinkPath.Replace(
+#if WCHAR_PATH_SEPARATOR == L'\\'
+ L'/'
+#else
+ L'\\'
+#endif
+ , WCHAR_PATH_SEPARATOR);
+ }
+ // (LinkPath) uses system path separator.
+ // windows: (LinkPath) doesn't contain linux separator (slash).
+ return true;
+}
- return S_OK;
- #endif // ! _WIN32
+bool CLinkInfo::Parse_from_LinuxData(const Byte *data, size_t dataSize)
+{
+ // Clear(); // *this object was cleared by constructor already.
+ LinkType = k_LinkType_PureSymLink;
+ AString utf;
+ if (dataSize >= k_LinkDataSize_LIMIT)
+ return false;
+ utf.SetFrom_CalcLen((const char *)data, (unsigned)dataSize);
+ UString u;
+ if (!ConvertUTF8ToUnicode(utf, u))
+ return false;
+ if (u.IsEmpty())
+ return false;
+ const wchar_t c = u[0];
+ isRelative = (c != L'/');
+ // linux path separator is expected
+ REPLACE_SLASHES_from_Linux_to_Sys(u)
+ LinkPath = u;
+ // (LinkPath) uses system path separator.
+ // windows: (LinkPath) doesn't contain linux separator (slash).
+ return true;
}
+
+// in/out: (LinkPath) uses system path separator
+// in/out: windows: (LinkPath) doesn't contain linux separator (slash).
+// out: (LinkPath) is relative path, and LinkPath[0] is not path separator
+// out: isRelative changed to false, if any prefix was removed.
+// note: absolute windows links "c:\" to root will be reduced to empty string:
+void CLinkInfo::Remove_AbsPathPrefixes()
+{
+ while (!LinkPath.IsEmpty())
+ {
+ unsigned n = 0;
+ if (!Is_WSL())
+ {
+ n =
+#ifndef _WIN32
+ isWindowsPath ?
+ NName::GetRootPrefixSize_WINDOWS(LinkPath) :
+#endif
+ NName::GetRootPrefixSize(LinkPath);
+/*
+ // "c:path" will be ignored later as "Dangerous absolute path"
+ // so check is not required
+ if (n == 0
+#ifndef _WIN32
+ && isWindowsPath
+#endif
+ && NName::IsDrivePath2(LinkPath))
+ n = 2;
+*/
+ }
+ if (n == 0)
+ {
+ if (!IS_PATH_SEPAR(LinkPath[0]))
+ break;
+ n = 1;
+ }
+ isRelative = false; // (LinkPath) will be treated as relative to root folder of archive
+ LinkPath.DeleteFrontal(n);
+ }
+}
-bool CLinkInfo::Parse(const Byte *data, size_t dataSize, bool isLinuxData)
+
+/*
+ it removes redundant separators, if there are double separators,
+ but it keeps double separators at start of string //name/.
+ in/out: system path separator is used
+ windows: slash character (linux separator) is not treated as separator
+ windows: (path) doesn't contain linux separator (slash).
+*/
+static void RemoveRedundantPathSeparators(UString &path)
{
- Clear();
- // this->isLinux = isLinuxData;
-
- if (isLinuxData)
+ wchar_t *dest = path.GetBuf();
+ const wchar_t * const start = dest;
+ const wchar_t *src = dest;
+ for (;;)
{
- isJunction = false;
- isHardLink = false;
- AString utf;
- if (dataSize >= (1 << 12))
- return false;
- utf.SetFrom_CalcLen((const char *)data, (unsigned)dataSize);
- UString u;
- if (!ConvertUTF8ToUnicode(utf, u))
- return false;
- linkPath = u;
-
- // in linux symbolic data: we expect that linux separator '/' is used
- // if windows link was created, then we also must use linux separator
- if (u.IsEmpty())
- return false;
- const wchar_t c = u[0];
- isRelative = !IS_PATH_SEPAR(c);
- return true;
+ wchar_t c = *src++;
+ if (c == 0)
+ break;
+ // if (IS_PATH_SEPAR(c)) // for Windows: we can change (/) to (\).
+ if (c == WCHAR_PATH_SEPARATOR)
+ {
+ if (dest - start >= 2 && dest[-1] == WCHAR_PATH_SEPARATOR)
+ continue;
+ // c = WCHAR_PATH_SEPARATOR; // for Windows: we can change (/) to (\).
+ }
+ *dest++ = c;
}
+ *dest = 0;
+ path.ReleaseBuf_SetLen((unsigned)(dest - path.Ptr()));
+}
- CReparseAttr reparse;
- if (!reparse.Parse(data, dataSize))
- return false;
- isHardLink = false;
- // isCopyLink = false;
- linkPath = reparse.GetPath();
- isJunction = reparse.IsMountPoint();
-
- if (reparse.IsSymLink_WSL())
+
+// in/out: (LinkPath) uses system path separator
+// in/out: windows: (LinkPath) doesn't contain linux separator (slash).
+// out: (LinkPath) is relative path, and LinkPath[0] is not path separator
+void CLinkInfo::Normalize_to_RelativeSafe(UStringVector &removePathParts)
+{
+ // We WILL NOT WRITE original absolute link path from archive to filesystem.
+ // So here we remove all root prefixes from (LinkPath).
+ // If we see any absolute root prefix, then we suppose that this prefix is virtual prefix
+ // that shows that link is relative to root folder of archive
+ RemoveRedundantPathSeparators(LinkPath);
+ // LinkPath = "\\\\?\\r:test\\test2"; // for debug
+ Remove_AbsPathPrefixes();
+ // (LinkPath) now is relative:
+ // if (isRelative == false), then (LinkPath) is relative to root folder of archive
+ // if (isRelative == true ), then (LinkPath) is relative to current item
+ if (LinkPath.IsEmpty() || isRelative || removePathParts.Size() == 0)
+ return;
+
+ // if LinkPath is prefixed by _removePathParts, we remove these paths
+ UStringVector pathParts;
+ SplitPathToParts(LinkPath, pathParts);
+ bool badPrefix = false;
{
- isWSL = true;
- isRelative = reparse.IsRelative_WSL();
+ FOR_VECTOR (i, removePathParts)
+ {
+ if (i >= pathParts.Size()
+ || CompareFileNames(removePathParts[i], pathParts[i]) != 0)
+ {
+ badPrefix = true;
+ break;
+ }
+ }
}
- else
- isRelative = reparse.IsRelative_Win();
-
- // FIXME !!!
- #ifndef _WIN32
- linkPath.Replace(L'\\', WCHAR_PATH_SEPARATOR);
- #endif
-
- return true;
+ if (!badPrefix)
+ pathParts.DeleteFrontal(removePathParts.Size());
+ LinkPath = MakePathFromParts(pathParts);
+ Remove_AbsPathPrefixes();
}
-
+
#endif // SUPPORT_LINKS
@@ -2239,12 +2332,12 @@
{
HRESULT res = S_OK;
- #ifdef SUPPORT_LINKS
+#ifdef SUPPORT_LINKS
size_t reparseSize = 0;
bool repraseMode = false;
bool needSetReparse = false;
- CLinkInfo linkInfo;
+ CLinkInfo link;
if (_bufPtrSeqOutStream)
{
@@ -2258,15 +2351,19 @@
needSetReparse = reparse.Parse(_outMemBuf, reparseSize, errorCode);
if (needSetReparse)
{
- UString linkPath = reparse.GetPath();
+ UString LinkPath = reparse.GetPath();
#ifndef _WIN32
- linkPath.Replace(L'\\', WCHAR_PATH_SEPARATOR);
+ LinkPath.Replace(L'\\', WCHAR_PATH_SEPARATOR);
#endif
}
*/
- needSetReparse = linkInfo.Parse(_outMemBuf, reparseSize, _is_SymLink_in_Data_Linux);
+ needSetReparse = _is_SymLink_in_Data_Linux ?
+ link.Parse_from_LinuxData(_outMemBuf, reparseSize) :
+ link.Parse_from_WindowsReparseData(_outMemBuf, reparseSize);
if (!needSetReparse)
res = SendMessageError_with_LastError("Incorrect reparse stream", us2fs(_item.Path));
+ // (link.LinkPath) uses system path separator.
+ // windows: (link.LinkPath) doesn't contain linux separator (slash).
}
else
{
@@ -2281,23 +2378,18 @@
_bufPtrSeqOutStream.Release();
}
- #endif // SUPPORT_LINKS
-
+#endif // SUPPORT_LINKS
const HRESULT res2 = CloseFile();
-
if (res == S_OK)
res = res2;
-
RINOK(res)
- #ifdef SUPPORT_LINKS
+#ifdef SUPPORT_LINKS
if (repraseMode)
{
_curSize = reparseSize;
_curSize_Defined = true;
-
- #ifdef SUPPORT_LINKS
if (needSetReparse)
{
// in Linux : we must delete empty file before symbolic link creation
@@ -2307,31 +2399,19 @@
RINOK(SendMessageError_with_LastError("can't delete file", _diskFilePath))
}
{
- /*
- // for DEBUG ONLY: we can extract sym links as WSL links
- // to eliminate (non-admin) errors for sym links.
- #ifdef _WIN32
- if (!linkInfo.isHardLink && !linkInfo.isJunction)
- linkInfo.isWSL = true;
- #endif
- */
bool linkWasSet = false;
- RINOK(SetFromLinkPath(_diskFilePath, linkInfo, linkWasSet))
+ // link.LinkPath = "r:\\1\\2"; // for debug
+ // link.isJunction = true; // for debug
+ link.Normalize_to_RelativeSafe(_removePathParts);
+ RINOK(SetLink(_diskFilePath, link, linkWasSet))
if (linkWasSet)
- _isSymLinkCreated = linkInfo.IsSymLink();
+ _isSymLinkCreated = true; // link.IsSymLink();
else
_needSetAttrib = false;
}
- /*
- if (!NFile::NIO::SetReparseData(_diskFilePath, _item.IsDir, ))
- {
- res = SendMessageError_with_LastError(kCantCreateSymLink, _diskFilePath);
- }
- */
}
- #endif
}
- #endif
+#endif // SUPPORT_LINKS
return res;
}
diff -Nru 7zip-24.09+dfsg/CPP/7zip/UI/Common/ArchiveExtractCallback.h 7zip-25.00+dfsg/CPP/7zip/UI/Common/ArchiveExtractCallback.h
--- 7zip-24.09+dfsg/CPP/7zip/UI/Common/ArchiveExtractCallback.h 2024-10-11 17:00:00.000000000 +0200
+++ 7zip-25.00+dfsg/CPP/7zip/UI/Common/ArchiveExtractCallback.h 2025-06-16 13:00:00.000000000 +0200
@@ -178,36 +178,50 @@
#ifdef SUPPORT_LINKS
+
+enum ELinkType
+{
+ k_LinkType_HardLink,
+ k_LinkType_PureSymLink,
+ k_LinkType_Junction,
+ k_LinkType_WSL
+ // , k_LinkType_CopyLink;
+};
+
+
struct CLinkInfo
{
- // bool isCopyLink;
- bool isHardLink;
- bool isJunction;
+ ELinkType LinkType;
bool isRelative;
- bool isWSL;
- UString linkPath;
+ // if (isRelative == false), then (LinkPath) is relative to root folder of archive
+ // if (isRelative == true ), then (LinkPath) is relative to current item
+ bool isWindowsPath;
+ UString LinkPath;
+
+ bool Is_HardLink() const { return LinkType == k_LinkType_HardLink; }
+ bool Is_AnySymLink() const { return LinkType != k_LinkType_HardLink; }
- bool IsSymLink() const { return !isHardLink; }
+ bool Is_WSL() const { return LinkType == k_LinkType_WSL; }
CLinkInfo():
- // IsCopyLink(false),
- isHardLink(false),
- isJunction(false),
+ LinkType(k_LinkType_PureSymLink),
isRelative(false),
- isWSL(false)
+ isWindowsPath(false)
{}
void Clear()
{
- // IsCopyLink = false;
- isHardLink = false;
- isJunction = false;
+ LinkType = k_LinkType_PureSymLink;
isRelative = false;
- isWSL = false;
- linkPath.Empty();
+ isWindowsPath = false;
+ LinkPath.Empty();
}
- bool Parse(const Byte *data, size_t dataSize, bool isLinuxData);
+ bool Parse_from_WindowsReparseData(const Byte *data, size_t dataSize);
+ bool Parse_from_LinuxData(const Byte *data, size_t dataSize);
+ void Normalize_to_RelativeSafe(UStringVector &removePathParts);
+private:
+ void Remove_AbsPathPrefixes();
};
#endif // SUPPORT_LINKS
@@ -287,8 +301,8 @@
bool _isRenamed;
bool _extractMode;
- // bool _is_SymLink_in_Data;
- bool _is_SymLink_in_Data_Linux; // false = WIN32, true = LINUX
+ bool _is_SymLink_in_Data_Linux; // false = WIN32, true = LINUX.
+ // _is_SymLink_in_Data_Linux is detected from Windows/Linux part of attributes of file.
bool _needSetAttrib;
bool _isSymLinkCreated;
bool _itemFailure;
@@ -420,6 +434,7 @@
HRESULT SendMessageError_with_Error(HRESULT errorCode, const char *message, const FString &path);
HRESULT SendMessageError_with_LastError(const char *message, const FString &path);
HRESULT SendMessageError2(HRESULT errorCode, const char *message, const FString &path1, const FString &path2);
+ HRESULT SendMessageError2_with_LastError(const char *message, const FString &path1, const FString &path2);
#if defined(_WIN32) && !defined(UNDER_CE) && !defined(Z7_SFX)
NExtract::NZoneIdMode::EEnum ZoneMode;
@@ -487,11 +502,16 @@
private:
CHardLinks _hardLinks;
CLinkInfo _link;
+ // const void *NtReparse_Data;
+ // UInt32 NtReparse_Size;
// FString _copyFile_Path;
// HRESULT MyCopyFile(ISequentialOutStream *outStream);
- HRESULT Link(const FString &fullProcessedPath);
HRESULT ReadLink();
+ HRESULT SetLink(
+ const FString &fullProcessedPath_from,
+ const CLinkInfo &linkInfo,
+ bool &linkWasSet);
public:
// call PrepareHardLinks() after Init()
@@ -538,16 +558,6 @@
HRESULT CloseReparseAndFile();
HRESULT CloseReparseAndFile2();
HRESULT SetDirsTimes();
-
- const void *NtReparse_Data;
- UInt32 NtReparse_Size;
-
- #ifdef SUPPORT_LINKS
- HRESULT SetFromLinkPath(
- const FString &fullProcessedPath,
- const CLinkInfo &linkInfo,
- bool &linkWasSet);
- #endif
};
diff -Nru 7zip-24.09+dfsg/CPP/7zip/UI/Common/Bench.cpp 7zip-25.00+dfsg/CPP/7zip/UI/Common/Bench.cpp
--- 7zip-24.09+dfsg/CPP/7zip/UI/Common/Bench.cpp 2024-11-25 15:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/7zip/UI/Common/Bench.cpp 2025-06-30 18:00:00.000000000 +0200
@@ -871,14 +871,27 @@
unsigned NumCoreThreads;
unsigned NumCores;
// unsigned DivideNum;
+
+#ifdef _WIN32
+ unsigned NumGroups;
+#endif
+
UInt32 Sizes[NUM_CPU_LEVELS_MAX];
void SetLevels(unsigned numCores, unsigned numCoreThreads);
DWORD_PTR GetAffinityMask(UInt32 bundleIndex, CCpuSet *cpuSet) const;
bool NeedAffinity() const { return NumBundleThreads != 0; }
+#ifdef _WIN32
+ bool NeedGroupsMode() const { return NumGroups > 1; }
+#endif
+
WRes CreateThread_WithAffinity(NWindows::CThread &thread, THREAD_FUNC_TYPE startAddress, LPVOID parameter, UInt32 bundleIndex) const
{
+#ifdef _WIN32
+ if (NeedGroupsMode()) // we need fix for bundleIndex usage
+ return thread.Create_With_Group(startAddress, parameter, bundleIndex % NumGroups);
+#endif
if (NeedAffinity())
{
CCpuSet cpuSet;
@@ -892,6 +905,9 @@
NumBundleThreads(0),
NumLevels(0),
NumCoreThreads(1)
+#ifdef _WIN32
+ , NumGroups(0)
+#endif
// DivideNum(1)
{}
};
@@ -1288,22 +1304,28 @@
if (scp)
{
const UInt64 reduceSize = kBufferSize;
-
- /* in posix new thread uses same affinity as parent thread,
+ /* in posix : new thread uses same affinity as parent thread,
so we don't need to send affinity to coder in posix */
- UInt64 affMask;
- #if !defined(Z7_ST) && defined(_WIN32)
+ UInt64 affMask = 0;
+ UInt32 affinityGroup = (UInt32)(Int32)-1;
+ // UInt64 affinityInGroup = 0;
+#if !defined(Z7_ST) && defined(_WIN32)
{
CCpuSet cpuSet;
- affMask = AffinityMode.GetAffinityMask(EncoderIndex, &cpuSet);
+ if (AffinityMode.NeedGroupsMode()) // we need fix for affinityInGroup also
+ affinityGroup = EncoderIndex % AffinityMode.NumGroups;
+ else
+ affMask = AffinityMode.GetAffinityMask(EncoderIndex, &cpuSet);
}
- #else
- affMask = 0;
- #endif
- // affMask <<= 3; // debug line: to test no affinity in coder;
- // affMask = 0;
-
- RINOK(method.SetCoderProps_DSReduce_Aff(scp, &reduceSize, (affMask != 0 ? &affMask : NULL)))
+#endif
+ // affMask <<= 3; // debug line: to test no affinity in coder
+ // affMask = 0; // for debug
+ // affinityGroup = 0; // for debug
+ // affinityInGroup = 1; // for debug
+ RINOK(method.SetCoderProps_DSReduce_Aff(scp, &reduceSize,
+ affMask != 0 ? &affMask : NULL,
+ affinityGroup != (UInt32)(Int32)-1 ? &affinityGroup : NULL,
+ /* affinityInGroup != 0 ? &affinityInGroup : */ NULL))
}
else
{
@@ -2962,7 +2984,7 @@
{
AString s;
// s.Add_UInt32(ti.numProcessThreads);
- unsigned numSysThreads = ti.GetNumSystemThreads();
+ const unsigned numSysThreads = ti.GetNumSystemThreads();
if (ti.GetNumProcessThreads() != numSysThreads)
{
// if (ti.numProcessThreads != ti.numSysThreads)
@@ -2992,6 +3014,35 @@
}
#endif
}
+#ifdef _WIN32
+ if (ti.Groups.GroupSizes.Size() > 1 ||
+ (ti.Groups.GroupSizes.Size() == 1
+ && ti.Groups.NumThreadsTotal != numSysThreads))
+ {
+ s += " : ";
+ s.Add_UInt32(ti.Groups.GroupSizes.Size());
+ s += " groups : ";
+ if (ti.Groups.NumThreadsTotal == numSysThreads)
+ {
+ s.Add_UInt32(ti.Groups.NumThreadsTotal);
+ s += " c : ";
+ }
+ UInt32 minSize, maxSize;
+ ti.Groups.Get_GroupSize_Min_Max(minSize, maxSize);
+ if (minSize == maxSize)
+ {
+ s.Add_UInt32(ti.Groups.GroupSizes[0]);
+ s += " c/g";
+ }
+ else
+ FOR_VECTOR (i, ti.Groups.GroupSizes)
+ {
+ if (i != 0)
+ s.Add_Char(' ');
+ s.Add_UInt32(ti.Groups.GroupSizes[i]);
+ }
+ }
+#endif
return s;
}
@@ -3753,9 +3804,13 @@
UInt64 complexInCommands = kComplexInCommands;
UInt32 numThreads_Start = 1;
- #ifndef Z7_ST
+#ifndef Z7_ST
CAffinityMode affinityMode;
- #endif
+#ifdef _WIN32
+ if (threadsInfo.IsGroupMode && threadsInfo.Groups.GroupSizes.Size() > 1)
+ affinityMode.NumGroups = threadsInfo.Groups.GroupSizes.Size();
+#endif
+#endif
COneMethodInfo method;
@@ -4861,7 +4916,7 @@
if (AreSameMethodNames(benchMethod, methodName))
{
if (benchProps.IsEmpty()
- || (benchProps == "x5" && method.PropsString.IsEmpty())
+ || (benchProps.IsEqualTo("x5") && method.PropsString.IsEmpty())
|| method.PropsString.IsPrefixedBy_Ascii_NoCase(benchProps))
{
callback.BenchProps.EncComplex = h.EncComplex;
diff -Nru 7zip-24.09+dfsg/CPP/7zip/UI/Common/EnumDirItems.cpp 7zip-25.00+dfsg/CPP/7zip/UI/Common/EnumDirItems.cpp
--- 7zip-24.09+dfsg/CPP/7zip/UI/Common/EnumDirItems.cpp 2024-10-06 11:00:00.000000000 +0200
+++ 7zip-25.00+dfsg/CPP/7zip/UI/Common/EnumDirItems.cpp 2025-06-20 12:00:00.000000000 +0200
@@ -1213,11 +1213,13 @@
// continue; // for debug
if (!item.Has_Attrib_ReparsePoint())
continue;
-
+ /*
+ We want to get properties of target file instead of properies of symbolic link.
+ Probably this code is unused, because
+ CFileInfo::Find(with followLink = true) called Fill_From_ByHandleFileInfo() already.
+ */
// if (item.IsDir()) continue;
-
const FString phyPath = GetPhyPath(i);
-
NFind::CFileInfo fi;
if (fi.Fill_From_ByHandleFileInfo(phyPath)) // item.IsDir()
{
@@ -1228,38 +1230,13 @@
item.Attrib = fi.Attrib;
continue;
}
-
- /*
- // we request properties of target file instead of properies of symbolic link
- // here we also can manually parse unsupported links (like WSL links)
- NIO::CInFile inFile;
- if (inFile.Open(phyPath))
- {
- BY_HANDLE_FILE_INFORMATION info;
- if (inFile.GetFileInformation(&info))
- {
- // Stat.FilesSize doesn't contain item.Size already
- // Stat.FilesSize -= item.Size;
- item.Size = (((UInt64)info.nFileSizeHigh) << 32) + info.nFileSizeLow;
- Stat.FilesSize += item.Size;
- item.CTime = info.ftCreationTime;
- item.ATime = info.ftLastAccessTime;
- item.MTime = info.ftLastWriteTime;
- item.Attrib = info.dwFileAttributes;
- continue;
- }
- }
- */
-
RINOK(AddError(phyPath))
continue;
}
- // (SymLinks == true) here
-
+ // (SymLinks == true)
if (item.ReparseData.Size() == 0)
continue;
-
// if (item.Size == 0)
{
// 20.03: we use Reparse Data instead of real data
@@ -1277,7 +1254,7 @@
/* imagex/WIM reduces absolute paths in links (raparse data),
if we archive non root folder. We do same thing here */
- bool isWSL = false;
+ // bool isWSL = false;
if (attr.IsSymLink_WSL())
{
// isWSL = true;
@@ -1314,21 +1291,27 @@
continue;
if (rootPrefixSize == prefix.Len())
continue; // simple case: paths are from root
-
if (link.Len() <= prefix.Len())
continue;
-
if (CompareFileNames(link.Left(prefix.Len()), prefix) != 0)
continue;
UString newLink = prefix.Left(rootPrefixSize);
newLink += link.Ptr(prefix.Len());
- CByteBuffer data;
- bool isSymLink = !attr.IsMountPoint();
- if (!FillLinkData(data, newLink, isSymLink, isWSL))
+ CByteBuffer &data = item.ReparseData2;
+/*
+ if (isWSL)
+ {
+ Convert_WinPath_to_WslLinuxPath(newLink, true); // is absolute : change it
+ FillLinkData_WslLink(data, newLink);
+ }
+ else
+*/
+ FillLinkData_WinLink(data, newLink, !attr.IsMountPoint());
+ if (data.Size() == 0)
continue;
- item.ReparseData2 = data;
+ // item.ReparseData2 = data;
}
return S_OK;
}
diff -Nru 7zip-24.09+dfsg/CPP/7zip/UI/Common/Extract.cpp 7zip-25.00+dfsg/CPP/7zip/UI/Common/Extract.cpp
--- 7zip-24.09+dfsg/CPP/7zip/UI/Common/Extract.cpp 2024-02-10 10:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/7zip/UI/Common/Extract.cpp 2025-06-16 10:00:00.000000000 +0200
@@ -389,7 +389,7 @@
{
UString s = arcPath.Ptr(pos + 1);
int index = codecs->FindFormatForExtension(s);
- if (index >= 0 && s == L"001")
+ if (index >= 0 && s.IsEqualTo("001"))
{
s = arcPath.Left(pos);
pos = s.ReverseFind(L'.');
diff -Nru 7zip-24.09+dfsg/CPP/7zip/UI/Common/ExtractingFilePath.cpp 7zip-25.00+dfsg/CPP/7zip/UI/Common/ExtractingFilePath.cpp
--- 7zip-24.09+dfsg/CPP/7zip/UI/Common/ExtractingFilePath.cpp 2023-03-06 17:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/7zip/UI/Common/ExtractingFilePath.cpp 2025-06-16 08:00:00.000000000 +0200
@@ -208,7 +208,7 @@
if (parts.Size() > 1 && parts[1].IsEmpty())
{
i = 2;
- if (parts.Size() > 2 && parts[2] == L"?")
+ if (parts.Size() > 2 && parts[2].IsEqualTo("?"))
{
i = 3;
if (parts.Size() > 3 && NWindows::NFile::NName::IsDrivePath2(parts[3]))
diff -Nru 7zip-24.09+dfsg/CPP/7zip/UI/Common/HashCalc.cpp 7zip-25.00+dfsg/CPP/7zip/UI/Common/HashCalc.cpp
--- 7zip-24.09+dfsg/CPP/7zip/UI/Common/HashCalc.cpp 2024-11-12 12:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/7zip/UI/Common/HashCalc.cpp 2025-06-16 09:00:00.000000000 +0200
@@ -62,7 +62,7 @@
if (m.MethodName.IsEmpty())
m.MethodName = k_DefaultHashMethod;
- if (m.MethodName == "*")
+ if (m.MethodName.IsEqualTo("*"))
{
CRecordVector<CMethodId> tempMethods;
GetHashMethods(EXTERNAL_CODECS_LOC_VARS tempMethods);
@@ -431,6 +431,19 @@
}
+static void Convert_TagName_to_MethodName(AString &method)
+{
+ // we need to convert at least SHA512/256 to SHA512-256, and SHA512/224 to SHA512-224
+ // but we convert any '/' to '-'.
+ method.Replace('/', '-');
+}
+
+static void Convert_MethodName_to_TagName(AString &method)
+{
+ if (method.IsPrefixedBy_Ascii_NoCase("SHA512-2"))
+ method.ReplaceOneCharAtPos(6, '/');
+}
+
static void WriteLine(CDynLimBuf &hashFileString,
const CHashOptionsLocal &options,
@@ -440,8 +453,10 @@
{
AString methodName;
if (!hb.Hashers.IsEmpty())
+ {
methodName = hb.Hashers[0].Name;
-
+ Convert_MethodName_to_TagName(methodName);
+ }
AString hashesString;
AddHashResultLine(hashesString, hb.Hashers);
WriteLine(hashFileString, options, path, isDir, methodName, hashesString);
@@ -752,7 +767,7 @@
Name = end;
Hash.Alloc(4);
- SetBe32(Hash, crc)
+ SetBe32a(Hash, crc)
Size_from_Arc = size;
Size_from_Arc_Defined = true;
@@ -773,56 +788,87 @@
{
"sha256"
, "sha224"
-// , "sha512-224"
-// , "sha512-256"
+ , "sha512-224"
+ , "sha512-256"
, "sha384"
, "sha512"
-// , "sha3-224"
+ , "sha3-224"
, "sha3-256"
-// , "sha3-384"
-// , "sha3-512"
+ , "sha3-384"
+ , "sha3-512"
// , "shake128"
// , "shake256"
, "sha1"
+ , "sha2"
+ , "sha3"
+ , "sha"
, "md5"
- , "blake2sp"
+ , "blake2s"
, "blake2b"
+ , "blake2sp"
, "xxh64"
- , "crc64"
, "crc32"
+ , "crc64"
, "cksum"
};
-static UString GetMethod_from_FileName(const UString &name)
+
+// returns true, if (method) is known hash method or hash method group name.
+static bool GetMethod_from_FileName(const UString &name, AString &method)
{
+ method.Empty();
AString s;
ConvertUnicodeToUTF8(name, s);
const int dotPos = s.ReverseFind_Dot();
- const char *src = s.Ptr();
- bool isExtension = false;
if (dotPos >= 0)
{
- isExtension = true;
- src = s.Ptr(dotPos + 1);
+ method = s.Ptr(dotPos + 1);
+ if (method.IsEqualTo_Ascii_NoCase("txt") ||
+ method.IsEqualTo_Ascii_NoCase("asc"))
+ {
+ method.Empty();
+ const int dotPos2 = s.Find('.');
+ if (dotPos2 >= 0)
+ s.DeleteFrom(dotPos2);
+ }
+ }
+ if (method.IsEmpty())
+ {
+ // we support file names with "sum" and "sums" postfixes: "sha256sum", "sha256sums"
+ unsigned size;
+ if (s.Len() > 4 && StringsAreEqualNoCase_Ascii(s.RightPtr(4), "sums"))
+ size = 4;
+ else if (s.Len() > 3 && StringsAreEqualNoCase_Ascii(s.RightPtr(3), "sum"))
+ size = 3;
+ else
+ return false;
+ method = s;
+ method.DeleteFrom(s.Len() - size);
}
- const char *m = "";
+
unsigned i;
for (i = 0; i < Z7_ARRAY_SIZE(k_CsumMethodNames); i++)
{
- m = k_CsumMethodNames[i];
- if (isExtension)
+ const char *m = k_CsumMethodNames[i];
+ if (method.IsEqualTo_Ascii_NoCase(m))
{
- if (StringsAreEqual_Ascii(src, m))
- break;
+ // method = m; // we can get lowcase
+ return true;
+ }
+ }
+
+/*
+ for (i = 0; i < Z7_ARRAY_SIZE(k_CsumMethodNames); i++)
+ {
+ const char *m = k_CsumMethodNames[i];
+ if (method.IsPrefixedBy_Ascii_NoCase(m))
+ {
+ method = m; // we get lowcase
+ return true;
}
- else if (IsString1PrefixedByString2_NoCase_Ascii(src, m))
- if (StringsAreEqual_Ascii(src + strlen(m), "sums"))
- break;
}
- UString res;
- if (i != Z7_ARRAY_SIZE(k_CsumMethodNames))
- res = m;
- return res;
+*/
+ return false;
}
@@ -1047,7 +1093,7 @@
if (propID == kpidChecksum)
{
const CHashPair &hp = HashPairs[index];
- if (hp.Hash.Size() > 0)
+ if (hp.Hash.Size() != 0)
{
*data = hp.Hash;
*dataSize = (UInt32)hp.Hash.Size();
@@ -1100,11 +1146,6 @@
s.Add_UInt32(_hashSize * 8);
s += "-bit";
}
- if (!_nameExtenstion.IsEmpty())
- {
- s.Add_Space_if_NotEmpty();
- s += _nameExtenstion;
- }
if (_is_PgpMethod)
{
Add_OptSpace_String(s, "PGP");
@@ -1120,6 +1161,18 @@
Add_OptSpace_String(s, "TAG");
if (_are_there_Dirs)
Add_OptSpace_String(s, "DIRS");
+ if (!_method_from_FileName.IsEmpty())
+ {
+ Add_OptSpace_String(s, "filename_method:");
+ s += _method_from_FileName;
+ if (!_is_KnownMethod_in_FileName)
+ s += ":UNKNOWN";
+ }
+ if (!_methods.IsEmpty())
+ {
+ Add_OptSpace_String(s, "cmd_method:");
+ s += _methods[0];
+ }
prop = s;
break;
}
@@ -1228,6 +1281,15 @@
}
+static bool isThere_Zero_Byte(const Byte *data, size_t size)
+{
+ for (size_t i = 0; i < size; i++)
+ if (data[i] == 0)
+ return true;
+ return false;
+}
+
+
Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *openCallback))
{
COM_TRY_BEGIN
@@ -1239,17 +1301,9 @@
CObjectVector<CHashPair> &pairs = HashPairs;
- bool zeroMode = false;
- bool cr_lf_Mode = false;
- {
- for (size_t i = 0; i < buf.Size(); i++)
- if (buf.ConstData()[i] == 0)
- {
- zeroMode = true;
- break;
- }
- }
+ const bool zeroMode = isThere_Zero_Byte(buf, buf.Size());
_is_ZeroMode = zeroMode;
+ bool cr_lf_Mode = false;
if (!zeroMode)
cr_lf_Mode = Is_CR_LF_Data(buf, buf.Size());
@@ -1263,13 +1317,21 @@
NCOM::CPropVariant prop;
RINOK(openVolumeCallback->GetProperty(kpidName, &prop))
if (prop.vt == VT_BSTR)
- _nameExtenstion = GetMethod_from_FileName(prop.bstrVal);
+ _is_KnownMethod_in_FileName = GetMethod_from_FileName(prop.bstrVal, _method_from_FileName);
}
}
- bool cksumMode = false;
- if (_nameExtenstion.IsEqualTo_Ascii_NoCase("cksum"))
- cksumMode = true;
+ if (!_methods.IsEmpty())
+ {
+ ConvertUnicodeToUTF8(_methods[0], _method_for_Extraction);
+ }
+ if (_method_for_Extraction.IsEmpty())
+ {
+ // if (_is_KnownMethod_in_FileName)
+ _method_for_Extraction = _method_from_FileName;
+ }
+
+ const bool cksumMode = _method_for_Extraction.IsEqualTo_Ascii_NoCase("cksum");
_is_CksumMode = cksumMode;
size_t pos = 0;
@@ -1366,6 +1428,7 @@
_is_ZeroMode = false;
_are_there_Tags = false;
_are_there_Dirs = false;
+ _is_KnownMethod_in_FileName = false;
_hashSize_Defined = false;
_hashSize = 0;
}
@@ -1374,7 +1437,8 @@
Z7_COM7F_IMF(CHandler::Close())
{
ClearVars();
- _nameExtenstion.Empty();
+ _method_from_FileName.Empty();
+ _method_for_Extraction.Empty();
_pgpMethod.Empty();
HashPairs.Clear();
return S_OK;
@@ -1401,19 +1465,73 @@
}
-static void AddDefaultMethod(UStringVector &methods, unsigned size)
+static void AddDefaultMethod(UStringVector &methods,
+ const char *name, unsigned size)
{
+ int shaVersion = -1;
+ if (name)
+ {
+ if (StringsAreEqualNoCase_Ascii(name, "sha"))
+ {
+ shaVersion = 0;
+ if (size == 0)
+ size = 32;
+ }
+ else if (StringsAreEqualNoCase_Ascii(name, "sha1"))
+ {
+ shaVersion = 1;
+ if (size == 0)
+ size = 20;
+ }
+ else if (StringsAreEqualNoCase_Ascii(name, "sha2"))
+ {
+ shaVersion = 2;
+ if (size == 0)
+ size = 32;
+ }
+ else if (StringsAreEqualNoCase_Ascii(name, "sha3"))
+ {
+ if (size == 0 ||
+ size == 32) name = "sha3-256";
+ else if (size == 28) name = "sha3-224";
+ else if (size == 48) name = "sha3-384";
+ else if (size == 64) name = "sha3-512";
+ }
+ else if (StringsAreEqualNoCase_Ascii(name, "sha512"))
+ {
+ // we allow any sha512 derived hash inside .sha512 file:
+ if (size == 48) name = "sha384";
+ else if (size == 32) name = "sha512-256";
+ else if (size == 28) name = "sha512-224";
+ }
+ if (shaVersion >= 0)
+ name = NULL;
+ }
+
const char *m = NULL;
- if (size == 32) m = "sha256";
- else if (size == 20) m = "sha1";
- else if (size == 16) m = "md5";
- else if (size == 8) m = "crc64";
- else if (size == 4) m = "crc32";
+ if (name)
+ m = name;
else
+ {
+ if (size == 64) m = "sha512";
+ else if (size == 48) m = "sha384";
+ else if (size == 32) m = "sha256";
+ else if (size == 28) m = "sha224";
+ else if (size == 20) m = "sha1";
+ else if (shaVersion < 0)
+ {
+ if (size == 16) m = "md5";
+ else if (size == 8) m = "crc64";
+ else if (size == 4) m = "crc32";
+ }
+ }
+
+ if (!m)
return;
- #ifdef Z7_EXTERNAL_CODECS
+
+#ifdef Z7_EXTERNAL_CODECS
const CExternalCodecs *_externalCodecs = g_ExternalCodecs_Ptr;
- #endif
+#endif
CMethodId id;
if (FindHashMethod(EXTERNAL_CODECS_LOC_VARS
AString(m), id))
@@ -1444,15 +1562,15 @@
CHashBundle hb_Glob;
// UStringVector methods = options.Methods;
UStringVector methods;
-
- if (methods.IsEmpty() && !_nameExtenstion.IsEmpty())
+
+/*
+ if (methods.IsEmpty() && !utf_nameExtenstion.IsEmpty() && !_hashSize_Defined)
{
- AString utf;
- ConvertUnicodeToUTF8(_nameExtenstion, utf);
CMethodId id;
- if (FindHashMethod(EXTERNAL_CODECS_LOC_VARS utf, id))
+ if (FindHashMethod(EXTERNAL_CODECS_LOC_VARS utf_nameExtenstion, id))
methods.Add(_nameExtenstion);
}
+*/
if (methods.IsEmpty() && !_pgpMethod.IsEmpty())
{
@@ -1461,12 +1579,21 @@
methods.Add(UString(_pgpMethod));
}
+/*
if (methods.IsEmpty() && _pgpMethod.IsEmpty() && _hashSize_Defined)
- AddDefaultMethod(methods, _hashSize);
+ {
+ AddDefaultMethod(methods,
+ utf_nameExtenstion.IsEmpty() ? NULL : utf_nameExtenstion.Ptr(),
+ _hashSize);
+ }
+*/
- RINOK(hb_Glob.SetMethods(
+ if (!methods.IsEmpty())
+ {
+ RINOK(hb_Glob.SetMethods(
EXTERNAL_CODECS_LOC_VARS
methods))
+ }
Z7_DECL_CMyComPtr_QI_FROM(
IArchiveUpdateCallbackFile,
@@ -1561,9 +1688,11 @@
{
hb_Use = &hb_Loc;
CMethodId id;
- if (FindHashMethod(EXTERNAL_CODECS_LOC_VARS hp.Method, id))
+ AString methodName = hp.Method;
+ Convert_TagName_to_MethodName(methodName);
+ if (FindHashMethod(EXTERNAL_CODECS_LOC_VARS methodName, id))
{
- methods_loc.Add(UString(hp.Method));
+ methods_loc.Add(UString(methodName));
RINOK(hb_Loc.SetMethods(
EXTERNAL_CODECS_LOC_VARS
methods_loc))
@@ -1573,7 +1702,10 @@
}
else if (methods.IsEmpty())
{
- AddDefaultMethod(methods_loc, (unsigned)hp.Hash.Size());
+ AddDefaultMethod(methods_loc,
+ _method_for_Extraction.IsEmpty() ? NULL :
+ _method_for_Extraction.Ptr(),
+ (unsigned)hp.Hash.Size());
if (!methods_loc.IsEmpty())
{
hb_Use = &hb_Loc;
@@ -1621,7 +1753,7 @@
Int32 opRes = NArchive::NExtract::NOperationResult::kUnsupportedMethod;
if (isSupportedMode
&& res_SetMethods != E_NOTIMPL
- && hb_Use->Hashers.Size() > 0
+ && !hb_Use->Hashers.IsEmpty()
)
{
const CHasherState &hs = hb_Use->Hashers[0];
@@ -1774,10 +1906,6 @@
methods.Add(_methods[k]);
}
}
- else if (_crcSize_WasSet)
- {
- AddDefaultMethod(methods, _crcSize);
- }
else
{
Z7_DECL_CMyComPtr_QI_FROM(
@@ -1789,12 +1917,23 @@
RINOK(getRootProps->GetRootProp(kpidArcFileName, &prop))
if (prop.vt == VT_BSTR)
{
- const UString method = GetMethod_from_FileName(prop.bstrVal);
+ AString method;
+ /* const bool isKnownMethod = */ GetMethod_from_FileName(prop.bstrVal, method);
if (!method.IsEmpty())
- methods.Add(method);
+ {
+ AddDefaultMethod(methods, method, _crcSize_WasSet ? _crcSize : 0);
+ if (methods.IsEmpty())
+ return E_NOTIMPL;
+ }
}
}
}
+ if (methods.IsEmpty() && _crcSize_WasSet)
+ {
+ AddDefaultMethod(methods,
+ NULL, // name
+ _crcSize);
+ }
RINOK(hb.SetMethods(EXTERNAL_CODECS_LOC_VARS methods))
@@ -2038,6 +2177,15 @@
}
+void CHandler::InitProps()
+{
+ _supportWindowsBackslash = true;
+ _crcSize_WasSet = false;
+ _crcSize = 4;
+ _methods.Clear();
+ _options.Init_HashOptionsLocal();
+}
+
Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps))
{
COM_TRY_BEGIN
@@ -2088,22 +2236,27 @@
" sha512"
" sha384"
" sha224"
- // " sha512-224"
- // " sha512-256"
- // " sha3-224"
+ " sha512-224"
+ " sha512-256"
+ " sha3-224"
" sha3-256"
- // " sha3-384"
- // " sha3-512"
+ " sha3-384"
+ " sha3-512"
// " shake128"
// " shake256"
" sha1"
+ " sha2"
+ " sha3"
" sha"
" md5"
+ " blake2s"
+ " blake2b"
" blake2sp"
" xxh64"
- " crc32 crc64"
- " asc"
+ " crc32"
+ " crc64"
" cksum"
+ " asc"
// " b2sum"
),
UString());
diff -Nru 7zip-24.09+dfsg/CPP/7zip/UI/Common/HashCalc.h 7zip-25.00+dfsg/CPP/7zip/UI/Common/HashCalc.h
--- 7zip-24.09+dfsg/CPP/7zip/UI/Common/HashCalc.h 2024-02-09 19:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/7zip/UI/Common/HashCalc.h 2024-12-09 10:00:00.000000000 +0100
@@ -279,32 +279,25 @@
bool _isArc;
bool _supportWindowsBackslash;
bool _crcSize_WasSet;
- UInt64 _phySize;
- CObjectVector<CHashPair> HashPairs;
- UString _nameExtenstion;
- // UString _method_fromName;
- AString _pgpMethod;
bool _is_CksumMode;
bool _is_PgpMethod;
bool _is_ZeroMode;
bool _are_there_Tags;
bool _are_there_Dirs;
+ bool _is_KnownMethod_in_FileName;
bool _hashSize_Defined;
unsigned _hashSize;
UInt32 _crcSize;
+ UInt64 _phySize;
+ CObjectVector<CHashPair> HashPairs;
UStringVector _methods;
+ AString _method_from_FileName;
+ AString _pgpMethod;
+ AString _method_for_Extraction;
CHashOptionsLocal _options;
void ClearVars();
-
- void InitProps()
- {
- _supportWindowsBackslash = true;
- _crcSize_WasSet = false;
- _crcSize = 4;
- _methods.Clear();
- _options.Init_HashOptionsLocal();
- }
+ void InitProps();
bool CanUpdate() const
{
diff -Nru 7zip-24.09+dfsg/CPP/7zip/UI/Common/LoadCodecs.cpp 7zip-25.00+dfsg/CPP/7zip/UI/Common/LoadCodecs.cpp
--- 7zip-24.09+dfsg/CPP/7zip/UI/Common/LoadCodecs.cpp 2023-12-03 19:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/7zip/UI/Common/LoadCodecs.cpp 2025-06-16 08:00:00.000000000 +0200
@@ -170,7 +170,7 @@
if (i < addExts.Size())
{
extInfo.AddExt = addExts[i];
- if (extInfo.AddExt == L"*")
+ if (extInfo.AddExt.IsEqualTo("*"))
extInfo.AddExt.Empty();
}
Exts.Add(extInfo);
@@ -931,8 +931,8 @@
const UString name = arcType.Mid(pos, (unsigned)pos2 - pos);
if (name.IsEmpty())
return false;
- int index = FindFormatForArchiveType(name);
- if (index < 0 && name != L"*")
+ const int index = FindFormatForArchiveType(name);
+ if (index < 0 && !name.IsEqualTo("*"))
{
formatIndices.Clear();
return false;
diff -Nru 7zip-24.09+dfsg/CPP/7zip/UI/Common/UpdateCallback.cpp 7zip-25.00+dfsg/CPP/7zip/UI/Common/UpdateCallback.cpp
--- 7zip-24.09+dfsg/CPP/7zip/UI/Common/UpdateCallback.cpp 2024-03-03 17:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/7zip/UI/Common/UpdateCallback.cpp 2025-06-18 14:00:00.000000000 +0200
@@ -32,6 +32,7 @@
#include "../../../Windows/PropVariant.h"
#include "../../Common/StreamObjects.h"
+#include "../../Archive/Common/ItemNameUtils.h"
#include "UpdateCallback.h"
@@ -306,7 +307,7 @@
#if defined(_WIN32) && !defined(UNDER_CE)
-static UString GetRelativePath(const UString &to, const UString &from)
+static UString GetRelativePath(const UString &to, const UString &from, bool isWSL)
{
UStringVector partsTo, partsFrom;
SplitPathToParts(to, partsTo);
@@ -324,11 +325,12 @@
if (i == 0)
{
- #ifdef _WIN32
- if (NName::IsDrivePath(to) ||
- NName::IsDrivePath(from))
+#ifdef _WIN32
+ if (isWSL ||
+ (NName::IsDrivePath(to) ||
+ NName::IsDrivePath(from)))
return to;
- #endif
+#endif
}
UString s;
@@ -373,54 +375,87 @@
return S_OK;
}
- #if !defined(UNDER_CE)
-
+#if !defined(UNDER_CE)
if (up.DirIndex >= 0)
{
const CDirItem &di = DirItems->Items[(unsigned)up.DirIndex];
-
- #ifdef _WIN32
- // if (di.IsDir())
+ if (di.ReparseData.Size())
{
+#ifdef _WIN32
CReparseAttr attr;
if (attr.Parse(di.ReparseData, di.ReparseData.Size()))
{
- const UString simpleName = attr.GetPath();
- if (!attr.IsSymLink_WSL() && attr.IsRelative_Win())
- prop = simpleName;
- else
+ UString path = attr.GetPath();
+ if (!path.IsEmpty())
{
- const FString phyPath = DirItems->GetPhyPath((unsigned)up.DirIndex);
- FString fullPath;
- if (NDir::MyGetFullPathName(phyPath, fullPath))
+ bool isWSL = attr.IsSymLink_WSL();
+ if (isWSL)
+ NArchive::NItemName::ReplaceToWinSlashes(path, true); // useBackslashReplacement
+ // it's expected that (path) now uses windows slashes.
+ // CReparseAttr::IsRelative_Win() returns true if FLAG_RELATIVE is set
+ // CReparseAttr::IsRelative_Win() returns true for "\dir1\path"
+ // but we want to store real relative paths without "\" root prefix.
+ // so we parse path instead of IsRelative_Win() calling.
+ if (// attr.IsRelative_Win() ||
+ (isWSL ?
+ IS_PATH_SEPAR(path[0]) :
+ NName::IsAbsolutePath(path)))
{
- prop = GetRelativePath(simpleName, fs2us(fullPath));
+ // (path) is abolute path or relative to root: "\path"
+ // we try to convert (path) to relative path for writing to archive.
+ const FString phyPath = DirItems->GetPhyPath((unsigned)up.DirIndex);
+ FString fullPath;
+ if (NDir::MyGetFullPathName(phyPath, fullPath))
+ {
+ if (IS_PATH_SEPAR(path[0]) &&
+ !IS_PATH_SEPAR(path[1]))
+ {
+ // path is relative to root of (fullPath): "\path"
+ const unsigned prefixSize = NName::GetRootPrefixSize(fullPath);
+ if (prefixSize)
+ {
+ path.DeleteFrontal(1);
+ path.Insert(0, fs2us(fullPath.Left(prefixSize)));
+ // we have changed "\" prefix to drive prefix "c:\" in (path).
+ // (path) is Windows path now.
+ isWSL = false;
+ }
+ }
+ }
+ path = GetRelativePath(path, fs2us(fullPath), isWSL);
}
+#if WCHAR_PATH_SEPARATOR != L'/'
+ // 7-Zip's TAR handler in Windows replaces windows slashes to linux slashes.
+ // so we can return any slashes to TAR handler.
+ // or we can convert to linux slashes here,
+ // because input IInArchive handler uses linux slashes for kpidSymLink.
+ // path.Replace(WCHAR_PATH_SEPARATOR, L'/');
+#endif
+ if (!path.IsEmpty())
+ prop = path;
}
- prop.Detach(value);
- return S_OK;
}
- }
-
- #else // _WIN32
-
- if (di.ReparseData.Size() != 0)
- {
+#else // ! _WIN32
AString utf;
utf.SetFrom_CalcLen((const char *)(const Byte *)di.ReparseData, (unsigned)di.ReparseData.Size());
-
+ #if 0 // 0 - for debug
+ // it's expected that link data uses system codepage.
+ // fs2us() ignores conversion errors. But we want correct path
+ UString us (fs2us(utf));
+ #else
UString us;
if (ConvertUTF8ToUnicode(utf, us))
+ #endif
{
- prop = us;
- prop.Detach(value);
- return S_OK;
+ if (!us.IsEmpty())
+ prop = us;
}
+#endif // ! _WIN32
}
-
- #endif // _WIN32
+ prop.Detach(value);
+ return S_OK;
}
- #endif // !defined(UNDER_CE)
+#endif // !defined(UNDER_CE)
}
else if (propID == kpidHardLink)
{
@@ -428,7 +463,12 @@
{
const CKeyKeyValPair &pair = _map[_hardIndex_To];
const CUpdatePair2 &up2 = (*UpdatePairs)[pair.Value];
- prop = DirItems->GetLogPath((unsigned)up2.DirIndex);
+ const UString path = DirItems->GetLogPath((unsigned)up2.DirIndex);
+#if WCHAR_PATH_SEPARATOR != L'/'
+ // 7-Zip's TAR handler in Windows replaces windows slashes to linux slashes.
+ // path.Replace(WCHAR_PATH_SEPARATOR, L'/');
+#endif
+ prop = path;
prop.Detach(value);
return S_OK;
}
@@ -438,7 +478,7 @@
return S_OK;
}
}
- }
+ } // if (up.NewData)
if (up.IsAnti
&& propID != kpidIsDir
diff -Nru 7zip-24.09+dfsg/CPP/7zip/UI/Common/Update.cpp 7zip-25.00+dfsg/CPP/7zip/UI/Common/Update.cpp
--- 7zip-24.09+dfsg/CPP/7zip/UI/Common/Update.cpp 2024-10-22 11:00:00.000000000 +0200
+++ 7zip-25.00+dfsg/CPP/7zip/UI/Common/Update.cpp 2024-12-30 14:00:00.000000000 +0100
@@ -474,7 +474,7 @@
CArcToDoStat stat2;
- if (options.RenamePairs.Size() != 0)
+ if (options.RenameMode || options.RenamePairs.Size() != 0)
{
FOR_VECTOR (i, arcItems)
{
@@ -1920,7 +1920,7 @@
if (NFind::DoesDirExist(phyPath))
{
RINOK(callback->DeletingAfterArchiving(phyPath, true))
- RemoveDir(phyPath);
+ RemoveDirAlways_if_Empty(phyPath);
}
}
diff -Nru 7zip-24.09+dfsg/CPP/7zip/UI/Common/Update.h 7zip-25.00+dfsg/CPP/7zip/UI/Common/Update.h
--- 7zip-24.09+dfsg/CPP/7zip/UI/Common/Update.h 2024-10-22 11:00:00.000000000 +0200
+++ 7zip-25.00+dfsg/CPP/7zip/UI/Common/Update.h 2024-12-30 14:00:00.000000000 +0100
@@ -94,6 +94,7 @@
bool DeleteAfterCompressing;
bool SetArcMTime;
+ bool RenameMode;
CBoolPair NtSecurity;
CBoolPair AltStreams;
@@ -139,6 +140,7 @@
DeleteAfterCompressing(false),
SetArcMTime(false),
+ RenameMode(false),
ArcNameMode(k_ArcNameMode_Smart),
PathMode(NWildcard::k_RelatPath)
diff -Nru 7zip-24.09+dfsg/CPP/7zip/UI/Console/Main.cpp 7zip-25.00+dfsg/CPP/7zip/UI/Console/Main.cpp
--- 7zip-24.09+dfsg/CPP/7zip/UI/Console/Main.cpp 2024-06-17 13:00:00.000000000 +0200
+++ 7zip-25.00+dfsg/CPP/7zip/UI/Console/Main.cpp 2025-01-24 08:00:00.000000000 +0100
@@ -908,9 +908,12 @@
if (options.EnableHeaders)
{
- ShowCopyrightAndHelp(g_StdStream, false);
- if (!parser.Parse1Log.IsEmpty())
- *g_StdStream << parser.Parse1Log;
+ if (g_StdStream)
+ {
+ ShowCopyrightAndHelp(g_StdStream, false);
+ if (!parser.Parse1Log.IsEmpty())
+ *g_StdStream << parser.Parse1Log;
+ }
}
parser.Parse2(options);
diff -Nru 7zip-24.09+dfsg/CPP/7zip/UI/Console/makefile 7zip-25.00+dfsg/CPP/7zip/UI/Console/makefile
--- 7zip-24.09+dfsg/CPP/7zip/UI/Console/makefile 2023-01-29 18:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/7zip/UI/Console/makefile 2025-07-01 17:00:00.000000000 +0200
@@ -59,10 +59,10 @@
C_OBJS = $(C_OBJS) \
$O\Alloc.obj \
$O\CpuArch.obj \
- $O\Sort.obj \
$O\Threads.obj \
!include "../../Crc.mak"
+!include "../../Sort.mak"
!include "Console.mak"
!include "../../7zip.mak"
diff -Nru 7zip-24.09+dfsg/CPP/7zip/UI/Explorer/makefile 7zip-25.00+dfsg/CPP/7zip/UI/Explorer/makefile
--- 7zip-24.09+dfsg/CPP/7zip/UI/Explorer/makefile 2024-03-20 08:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/7zip/UI/Explorer/makefile 2025-07-01 17:00:00.000000000 +0200
@@ -72,7 +72,7 @@
C_OBJS = \
$O\CpuArch.obj \
- $O\Sort.obj \
$O\Threads.obj \
+!include "../../Sort.mak"
!include "../../7zip.mak"
diff -Nru 7zip-24.09+dfsg/CPP/7zip/UI/Far/makefile 7zip-25.00+dfsg/CPP/7zip/UI/Far/makefile
--- 7zip-24.09+dfsg/CPP/7zip/UI/Far/makefile 2024-01-27 11:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/7zip/UI/Far/makefile 2025-07-01 17:00:00.000000000 +0200
@@ -99,9 +99,9 @@
C_OBJS = \
$O\Alloc.obj \
$O\CpuArch.obj \
- $O\Sort.obj \
$O\Threads.obj \
!include "../../Crc.mak"
+!include "../../Sort.mak"
!include "../../7zip.mak"
diff -Nru 7zip-24.09+dfsg/CPP/7zip/UI/Far/Plugin.cpp 7zip-25.00+dfsg/CPP/7zip/UI/Far/Plugin.cpp
--- 7zip-24.09+dfsg/CPP/7zip/UI/Far/Plugin.cpp 2024-01-23 21:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/7zip/UI/Far/Plugin.cpp 2025-06-16 09:00:00.000000000 +0200
@@ -61,7 +61,6 @@
}
#define kDotsReplaceString "[[..]]"
-#define kDotsReplaceStringU L"[[..]]"
static void CopyStrLimited(char *dest, const AString &src, unsigned len)
{
@@ -84,7 +83,7 @@
throw 272340;
AString oemString (UnicodeStringToMultiByte(prop.bstrVal, CP_OEMCP));
- if (oemString == "..")
+ if (oemString.IsEqualTo(".."))
oemString = kDotsReplaceString;
COPY_STR_LIMITED(panelItem.FindData.cFileName, oemString);
@@ -193,7 +192,7 @@
{
CMyComPtr<IFolderFolder> newFolder;
UString s = dirName;
- if (dirName == kDotsReplaceStringU)
+ if (dirName.IsEqualTo(kDotsReplaceString))
s = "..";
_folder->BindToFolder(s, &newFolder);
if (!newFolder)
@@ -209,12 +208,12 @@
int CPlugin::SetDirectory(const char *aszDir, int /* opMode */)
{
UString path = MultiByteToUnicodeString(aszDir, CP_OEMCP);
- if (path == WSTRING_PATH_SEPARATOR)
+ if (path.IsEqualTo(STRING_PATH_SEPARATOR))
{
_folder.Release();
m_ArchiveHandler->BindToRootFolder(&_folder);
}
- else if (path == L"..")
+ else if (path.IsEqualTo(".."))
{
CMyComPtr<IFolderFolder> newFolder;
_folder->BindToParentFolder(&newFolder);
diff -Nru 7zip-24.09+dfsg/CPP/7zip/UI/FileManager/FM.cpp 7zip-25.00+dfsg/CPP/7zip/UI/FileManager/FM.cpp
--- 7zip-24.09+dfsg/CPP/7zip/UI/FileManager/FM.cpp 2024-10-21 09:00:00.000000000 +0200
+++ 7zip-25.00+dfsg/CPP/7zip/UI/FileManager/FM.cpp 2025-06-15 10:00:00.000000000 +0200
@@ -651,7 +651,7 @@
SplitStringToTwoStrings(commandsString, paramString, tailString);
paramString.Trim();
tailString.Trim();
- if (tailString.IsPrefixedBy(L"-t"))
+ if (tailString.IsPrefixedBy("-t"))
g_ArcFormat = tailString.Ptr(2);
/*
diff -Nru 7zip-24.09+dfsg/CPP/7zip/UI/FileManager/LangUtils.cpp 7zip-25.00+dfsg/CPP/7zip/UI/FileManager/LangUtils.cpp
--- 7zip-24.09+dfsg/CPP/7zip/UI/FileManager/LangUtils.cpp 2024-03-15 08:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/7zip/UI/FileManager/LangUtils.cpp 2025-01-07 21:00:00.000000000 +0100
@@ -309,15 +309,13 @@
{
g_Lang.Clear();
ReadRegLang(g_LangID);
- #ifndef _UNICODE
- if (g_IsNT)
- #endif
+ if (g_LangID.IsEmpty())
{
- if (g_LangID.IsEmpty())
- {
+#ifndef _UNICODE
+ if (g_IsNT)
+#endif
OpenDefaultLang();
- return;
- }
+ return;
}
if (g_LangID.Len() > 1 || g_LangID[0] != L'-')
{
diff -Nru 7zip-24.09+dfsg/CPP/7zip/UI/FileManager/LinkDialog.cpp 7zip-25.00+dfsg/CPP/7zip/UI/FileManager/LinkDialog.cpp
--- 7zip-24.09+dfsg/CPP/7zip/UI/FileManager/LinkDialog.cpp 2023-03-19 18:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/7zip/UI/FileManager/LinkDialog.cpp 2025-06-20 12:00:00.000000000 +0200
@@ -45,28 +45,24 @@
CByteBuffer buf;
if (!NIO::GetReparseData(path, buf, NULL))
return false;
-
if (!attr.Parse(buf, buf.Size()))
{
SetLastError(attr.ErrorCode);
return false;
}
-
CByteBuffer data2;
- if (!FillLinkData(data2, attr.GetPath(),
- !attr.IsMountPoint(), attr.IsSymLink_WSL()))
+ FillLinkData(data2, attr.GetPath(),
+ !attr.IsMountPoint(), attr.IsSymLink_WSL());
+ if (data2.Size() == 0)
{
errorMessage = "Cannot reproduce reparse point";
return false;
}
-
- if (data2.Size() != buf.Size() ||
- memcmp(data2, buf, buf.Size()) != 0)
+ if (data2 != buf)
{
errorMessage = "mismatch for reproduced reparse point";
return false;
}
-
return true;
}
@@ -113,8 +109,8 @@
const bool res = GetSymLink(us2fs(FilePath), attr, error);
if (!res && error.IsEmpty())
{
- DWORD lastError = GetLastError();
- if (lastError != 0)
+ const DWORD lastError = GetLastError();
+ if (lastError)
error = NError::MyFormatMessage(lastError);
}
@@ -319,10 +315,10 @@
return;
}
- const bool isSymLink = (idb != IDR_LINK_TYPE_JUNCTION);
-
CByteBuffer data;
- if (!FillLinkData(data, to, isSymLink, isWSL))
+ const bool isSymLink = (idb != IDR_LINK_TYPE_JUNCTION);
+ FillLinkData(data, to, isSymLink, isWSL);
+ if (data.Size() == 0)
{
ShowError(L"Incorrect link");
return;
@@ -386,6 +382,9 @@
path = destPanel.GetFsPath();
}
+ CSelectedState srcSelState;
+ srcPanel.SaveSelectedState(srcSelState);
+
CLinkDialog dlg;
dlg.CurDirPrefix = fsPrefix;
dlg.FilePath = srcPath + itemName;
@@ -394,7 +393,10 @@
if (dlg.Create(srcPanel.GetParent()) != IDOK)
return;
- // fix it: we should refresh panel with changed link
+ // we refresh srcPanel to show changes in "Link" (kpidNtReparse) column.
+ // maybe we should refresh another panel also?
+ if (srcPanel._visibleColumns.FindItem_for_PropID(kpidNtReparse) >= 0)
+ srcPanel.RefreshListCtrl(srcSelState);
RefreshTitleAlways();
}
diff -Nru 7zip-24.09+dfsg/CPP/7zip/UI/FileManager/makefile 7zip-25.00+dfsg/CPP/7zip/UI/FileManager/makefile
--- 7zip-24.09+dfsg/CPP/7zip/UI/FileManager/makefile 2024-01-27 10:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/7zip/UI/FileManager/makefile 2025-07-01 17:00:00.000000000 +0200
@@ -104,7 +104,7 @@
C_OBJS = $(C_OBJS) \
$O\Alloc.obj \
$O\CpuArch.obj \
- $O\Sort.obj \
$O\Threads.obj \
+!include "../../Sort.mak"
!include "../../7zip.mak"
diff -Nru 7zip-24.09+dfsg/CPP/7zip/UI/FileManager/PanelCopy.cpp 7zip-25.00+dfsg/CPP/7zip/UI/FileManager/PanelCopy.cpp
--- 7zip-24.09+dfsg/CPP/7zip/UI/FileManager/PanelCopy.cpp 2024-10-22 10:00:00.000000000 +0200
+++ 7zip-25.00+dfsg/CPP/7zip/UI/FileManager/PanelCopy.cpp 2025-06-16 08:00:00.000000000 +0200
@@ -284,7 +284,7 @@
if (options.hashMethods.Size() == 1)
{
const UString &s = options.hashMethods[0];
- if (s != L"*")
+ if (!s.IsEqualTo("*"))
title = s;
}
}
diff -Nru 7zip-24.09+dfsg/CPP/7zip/UI/FileManager/PanelFolderChange.cpp 7zip-25.00+dfsg/CPP/7zip/UI/FileManager/PanelFolderChange.cpp
--- 7zip-24.09+dfsg/CPP/7zip/UI/FileManager/PanelFolderChange.cpp 2024-07-09 13:00:00.000000000 +0200
+++ 7zip-25.00+dfsg/CPP/7zip/UI/FileManager/PanelFolderChange.cpp 2025-06-16 10:00:00.000000000 +0200
@@ -428,7 +428,7 @@
UString name_Computer = RootFolder_GetName_Computer(iconIndex);
name_Computer.Add_PathSepar();
if (path == name_Computer
- || path == L"\\\\?\\")
+ || path.IsEqualTo("\\\\?\\"))
item.iImage = iconIndex;
else
{
@@ -639,7 +639,7 @@
unsigned indent = 0;
{
UString path = _currentFolderPrefix;
- // path = L"\\\\.\\y:\\"; // for debug
+ // path = "\\\\.\\y:\\"; // for debug
UString prefix0;
if (path.IsPrefixedBy_Ascii_NoCase("\\\\"))
{
@@ -702,7 +702,7 @@
int iconIndex_Computer;
const UString name_Computer = RootFolder_GetName_Computer(iconIndex_Computer);
- // const bool is_devicePrefix = (sumPath == L"\\\\.\\");
+ // const bool is_devicePrefix = (sumPath.IsEqualTo("\\\\.\\"));
if (pathParts.Size() > 1)
if (!sumPath.IsEmpty()
@@ -901,8 +901,8 @@
{
s = _currentFolderPrefix;
s.DeleteBack();
- if (s != L"\\\\." &&
- s != L"\\\\?")
+ if (!s.IsEqualTo("\\\\.") &&
+ !s.IsEqualTo("\\\\?"))
{
int pos = s.ReverseFind_PathSepar();
if (pos >= 0)
@@ -935,8 +935,8 @@
}
else
*/
- if (focusedName != L"\\\\." &&
- focusedName != L"\\\\?")
+ if (!focusedName.IsEqualTo("\\\\.") &&
+ !focusedName.IsEqualTo("\\\\?"))
{
const int pos = focusedName.ReverseFind_PathSepar();
if (pos >= 0)
diff -Nru 7zip-24.09+dfsg/CPP/7zip/UI/FileManager/Panel.h 7zip-25.00+dfsg/CPP/7zip/UI/FileManager/Panel.h
--- 7zip-24.09+dfsg/CPP/7zip/UI/FileManager/Panel.h 2024-10-13 12:00:00.000000000 +0200
+++ 7zip-25.00+dfsg/CPP/7zip/UI/FileManager/Panel.h 2025-06-16 08:00:00.000000000 +0200
@@ -711,8 +711,8 @@
}
// bool IsFsOrDrivesFolder() const { return IsFSFolder() || IsFSDrivesFolder(); }
- bool IsDeviceDrivesPrefix() const { return _currentFolderPrefix == L"\\\\.\\"; }
- bool IsSuperDrivesPrefix() const { return _currentFolderPrefix == L"\\\\?\\"; }
+ bool IsDeviceDrivesPrefix() const { return _currentFolderPrefix.IsEqualTo("\\\\.\\"); }
+ bool IsSuperDrivesPrefix() const { return _currentFolderPrefix.IsEqualTo("\\\\?\\"); }
/*
c:\Dir
diff -Nru 7zip-24.09+dfsg/CPP/7zip/UI/FileManager/PanelOperations.cpp 7zip-25.00+dfsg/CPP/7zip/UI/FileManager/PanelOperations.cpp
--- 7zip-24.09+dfsg/CPP/7zip/UI/FileManager/PanelOperations.cpp 2024-10-04 19:00:00.000000000 +0200
+++ 7zip-25.00+dfsg/CPP/7zip/UI/FileManager/PanelOperations.cpp 2025-06-16 09:00:00.000000000 +0200
@@ -275,8 +275,8 @@
{
const UString lastPart = name.Ptr((unsigned)(name.ReverseFind_PathSepar() + 1));
return
- lastPart != L"." &&
- lastPart != L"..";
+ !lastPart.IsEqualTo(".") &&
+ !lastPart.IsEqualTo("..");
}
bool CorrectFsPath(const UString &relBase, const UString &path, UString &result);
diff -Nru 7zip-24.09+dfsg/CPP/7zip/UI/FileManager/RootFolder.cpp 7zip-25.00+dfsg/CPP/7zip/UI/FileManager/RootFolder.cpp
--- 7zip-24.09+dfsg/CPP/7zip/UI/FileManager/RootFolder.cpp 2024-07-09 13:00:00.000000000 +0200
+++ 7zip-25.00+dfsg/CPP/7zip/UI/FileManager/RootFolder.cpp 2025-06-16 08:00:00.000000000 +0200
@@ -249,7 +249,7 @@
AreEqualNames(name2, L"Documents"))
return BindToFolder((UInt32)ROOT_INDEX_DOCUMENTS, resultFolder);
#else
- if (name2 == WSTRING_PATH_SEPARATOR)
+ if (name2.IsEqualTo(STRING_PATH_SEPARATOR))
return BindToFolder((UInt32)ROOT_INDEX_COMPUTER, resultFolder);
#endif
@@ -257,7 +257,7 @@
AreEqualNames(name2, L"Computer"))
return BindToFolder((UInt32)ROOT_INDEX_COMPUTER, resultFolder);
- if (name2 == WSTRING_PATH_SEPARATOR)
+ if (name2.IsEqualTo(STRING_PATH_SEPARATOR))
{
CMyComPtr<IFolderFolder> subFolder = this;
*resultFolder = subFolder.Detach();
diff -Nru 7zip-24.09+dfsg/CPP/7zip/UI/GUI/BenchmarkDialog.cpp 7zip-25.00+dfsg/CPP/7zip/UI/GUI/BenchmarkDialog.cpp
--- 7zip-24.09+dfsg/CPP/7zip/UI/GUI/BenchmarkDialog.cpp 2024-11-08 18:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/7zip/UI/GUI/BenchmarkDialog.cpp 2025-06-16 09:00:00.000000000 +0200
@@ -1856,7 +1856,7 @@
const CProperty &prop = props[i];
UString name = prop.Name;
name.MakeLower_Ascii();
- if (name.IsEqualTo_Ascii_NoCase("m") && prop.Value == L"*")
+ if (name.IsEqualTo_Ascii_NoCase("m") && prop.Value.IsEqualTo("*"))
{
bd.TotalMode = true;
continue;
@@ -1865,7 +1865,7 @@
NCOM::CPropVariant propVariant;
if (!prop.Value.IsEmpty())
ParseNumberString(prop.Value, propVariant);
- if (name.IsPrefixedBy(L"mt"))
+ if (name.IsPrefixedBy("mt"))
{
#ifndef Z7_ST
RINOK(ParseMtProp(name.Ptr(2), propVariant, numCPUs, numThreads))
diff -Nru 7zip-24.09+dfsg/CPP/7zip/UI/GUI/BenchmarkDialog.rc 7zip-25.00+dfsg/CPP/7zip/UI/GUI/BenchmarkDialog.rc
--- 7zip-24.09+dfsg/CPP/7zip/UI/GUI/BenchmarkDialog.rc 2021-05-26 13:06:11.000000000 +0200
+++ 7zip-25.00+dfsg/CPP/7zip/UI/GUI/BenchmarkDialog.rc 2025-07-03 14:00:00.000000000 +0200
@@ -81,7 +81,7 @@
LTEXT "&Number of CPU threads:", IDT_BENCH_NUM_THREADS, m, 30, g0xs, 8
COMBOBOX IDC_BENCH_NUM_THREADS, g1x, 29, g1xs, 140, MY_COMBO
- LTEXT "", IDT_BENCH_HARDWARE_THREADS, gc2x, 30, g7xs, MY_TEXT_NOPREFIX
+ LTEXT "", IDT_BENCH_HARDWARE_THREADS, gc2x, 30, g7xs, 24, SS_NOPREFIX
RTEXT "Size", IDT_BENCH_SIZE, xSize, 54, sSize, MY_TEXT_NOPREFIX
RTEXT "CPU Usage", IDT_BENCH_USAGE_LABEL, xUsage, 54, sUsage, MY_TEXT_NOPREFIX
diff -Nru 7zip-24.09+dfsg/CPP/7zip/UI/GUI/CompressDialog.cpp 7zip-25.00+dfsg/CPP/7zip/UI/GUI/CompressDialog.cpp
--- 7zip-24.09+dfsg/CPP/7zip/UI/GUI/CompressDialog.cpp 2024-11-29 17:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/7zip/UI/GUI/CompressDialog.cpp 2025-07-04 11:00:00.000000000 +0200
@@ -2600,11 +2600,17 @@
UInt32 numAlgoThreadsMax = numHardwareThreads * 2;
const int methodID = GetMethodID();
- switch (methodID)
+ const bool isZip = IsZipFormat();
+ if (isZip)
+ numAlgoThreadsMax =
+ 8 << (sizeof(size_t) / 2); // 32 threads for 32-bit : 128 threads for 64-bit
+ else if (IsXzFormat())
+ numAlgoThreadsMax = 256 * 2;
+ else switch (methodID)
{
case kLZMA: numAlgoThreadsMax = 2; break;
case kLZMA2: numAlgoThreadsMax = 256; break;
- case kBZip2: numAlgoThreadsMax = 32; break;
+ case kBZip2: numAlgoThreadsMax = 64; break;
// case kZSTD: numAlgoThreadsMax = num_ZSTD_threads_MAX; break;
case kCopy:
case kPPMd:
@@ -2613,17 +2619,6 @@
case kPPMdZip:
numAlgoThreadsMax = 1;
}
- const bool isZip = IsZipFormat();
- if (isZip)
- {
- numAlgoThreadsMax =
- #ifdef _WIN32
- 64; // _WIN32 supports only 64 threads in one group. So no need for more threads here
- #else
- 128;
- #endif
- }
-
UInt32 autoThreads = numHardwareThreads;
if (autoThreads > numAlgoThreadsMax)
autoThreads = numAlgoThreadsMax;
@@ -3008,7 +3003,7 @@
else
{
size += numBlockThreads * (size1 + chunkSize);
- UInt32 numPackChunks = numBlockThreads + (numBlockThreads / 8) + 1;
+ const UInt32 numPackChunks = numBlockThreads + (numBlockThreads / 8) + 1;
if (chunkSize < ((UInt32)1 << 26)) numBlockThreads++;
if (chunkSize < ((UInt32)1 << 24)) numBlockThreads++;
if (chunkSize < ((UInt32)1 << 22)) numBlockThreads++;
diff -Nru 7zip-24.09+dfsg/CPP/7zip/UI/GUI/makefile 7zip-25.00+dfsg/CPP/7zip/UI/GUI/makefile
--- 7zip-24.09+dfsg/CPP/7zip/UI/GUI/makefile 2024-03-14 12:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/7zip/UI/GUI/makefile 2025-07-01 17:00:00.000000000 +0200
@@ -141,10 +141,9 @@
$O\Alloc.obj \
$O\CpuArch.obj \
$O\DllSecur.obj \
- $O\Sort.obj \
$O\Threads.obj \
!include "../../Crc.mak"
-
+!include "../../Sort.mak"
!include "../../7zip.mak"
diff -Nru 7zip-24.09+dfsg/CPP/Build.mak 7zip-25.00+dfsg/CPP/Build.mak
--- 7zip-24.09+dfsg/CPP/Build.mak 2024-05-02 14:00:00.000000000 +0200
+++ 7zip-25.00+dfsg/CPP/Build.mak 2025-07-02 07:00:00.000000000 +0200
@@ -111,7 +111,13 @@
!IFNDEF UNDER_CE
!IF "$(CC)" != "clang-cl"
-CFLAGS = $(CFLAGS) -MP4
+MP_NPROC = 16
+!IFDEF NUMBER_OF_PROCESSORS
+!IF $(NUMBER_OF_PROCESSORS) < $(MP_NPROC)
+MP_NPROC = $(NUMBER_OF_PROCESSORS)
+!ENDIF
+!ENDIF
+CFLAGS = $(CFLAGS) -MP$(MP_NPROC)
!ENDIF
!IFNDEF PLATFORM
# CFLAGS = $(CFLAGS) -arch:IA32
diff -Nru 7zip-24.09+dfsg/CPP/Common/MyString.cpp 7zip-25.00+dfsg/CPP/Common/MyString.cpp
--- 7zip-24.09+dfsg/CPP/Common/MyString.cpp 2024-02-19 10:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/Common/MyString.cpp 2025-06-15 10:00:00.000000000 +0200
@@ -208,35 +208,6 @@
// ---------- ASCII ----------
-bool AString::IsPrefixedBy_Ascii_NoCase(const char *s) const throw()
-{
- const char *s1 = _chars;
- for (;;)
- {
- const char c2 = *s++;
- if (c2 == 0)
- return true;
- const char c1 = *s1++;
- if (MyCharLower_Ascii(c1) !=
- MyCharLower_Ascii(c2))
- return false;
- }
-}
-
-bool UString::IsPrefixedBy_Ascii_NoCase(const char *s) const throw()
-{
- const wchar_t *s1 = _chars;
- for (;;)
- {
- const char c2 = *s++;
- if (c2 == 0)
- return true;
- const wchar_t c1 = *s1++;
- if (MyCharLower_Ascii(c1) != (unsigned char)MyCharLower_Ascii(c2))
- return false;
- }
-}
-
bool StringsAreEqual_Ascii(const char *u, const char *a) throw()
{
for (;;)
diff -Nru 7zip-24.09+dfsg/CPP/Common/MyString.h 7zip-25.00+dfsg/CPP/Common/MyString.h
--- 7zip-24.09+dfsg/CPP/Common/MyString.h 2024-01-22 10:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/Common/MyString.h 2025-07-01 12:00:00.000000000 +0200
@@ -429,11 +429,11 @@
// int CompareNoCase(const char *s) const { return MyStringCompareNoCase(_chars, s); }
// int CompareNoCase(const AString &s) const { return MyStringCompareNoCase(_chars, s._chars); }
bool IsPrefixedBy(const char *s) const { return IsString1PrefixedByString2(_chars, s); }
- bool IsPrefixedBy_Ascii_NoCase(const char *s) const throw();
+ bool IsPrefixedBy_Ascii_NoCase(const char *s) const { return IsString1PrefixedByString2_NoCase_Ascii(_chars, s); }
bool IsAscii() const
{
- unsigned len = Len();
+ const unsigned len = Len();
const char *s = _chars;
for (unsigned i = 0; i < len; i++)
if ((unsigned char)s[i] >= 0x80)
@@ -727,22 +727,23 @@
// int CompareNoCase(const wchar_t *s) const { return MyStringCompareNoCase(_chars, s); }
// int CompareNoCase(const UString &s) const { return MyStringCompareNoCase(_chars, s._chars); }
bool IsPrefixedBy(const wchar_t *s) const { return IsString1PrefixedByString2(_chars, s); }
+ bool IsPrefixedBy(const char *s) const { return IsString1PrefixedByString2(_chars, s); }
bool IsPrefixedBy_NoCase(const wchar_t *s) const { return IsString1PrefixedByString2_NoCase(_chars, s); }
- bool IsPrefixedBy_Ascii_NoCase(const char *s) const throw();
+ bool IsPrefixedBy_Ascii_NoCase(const char *s) const { return IsString1PrefixedByString2_NoCase_Ascii(_chars, s); }
bool IsAscii() const
{
- unsigned len = Len();
+ const unsigned len = Len();
const wchar_t *s = _chars;
for (unsigned i = 0; i < len; i++)
- if (s[i] >= 0x80)
+ if ((unsigned)(int)s[i] >= 0x80)
return false;
return true;
}
int Find(wchar_t c) const { return FindCharPosInString(_chars, c); }
int Find(wchar_t c, unsigned startIndex) const
{
- int pos = FindCharPosInString(_chars + startIndex, c);
+ const int pos = FindCharPosInString(_chars + startIndex, c);
return pos < 0 ? -1 : (int)startIndex + pos;
}
diff -Nru 7zip-24.09+dfsg/CPP/Common/MyXml.cpp 7zip-25.00+dfsg/CPP/Common/MyXml.cpp
--- 7zip-24.09+dfsg/CPP/Common/MyXml.cpp 2024-01-21 21:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/Common/MyXml.cpp 2025-06-16 11:00:00.000000000 +0200
@@ -24,7 +24,7 @@
int CXmlItem::FindProp(const char *propName) const throw()
{
FOR_VECTOR (i, Props)
- if (Props[i].Name == propName)
+ if (Props[i].Name.IsEqualTo(propName))
return (int)i;
return -1;
}
@@ -39,7 +39,7 @@
bool CXmlItem::IsTagged(const char *tag) const throw()
{
- return (IsTag && Name == tag);
+ return (IsTag && Name.IsEqualTo(tag));
}
int CXmlItem::FindSubTag(const char *tag) const throw()
diff -Nru 7zip-24.09+dfsg/CPP/Common/Sha3Reg.cpp 7zip-25.00+dfsg/CPP/Common/Sha3Reg.cpp
--- 7zip-24.09+dfsg/CPP/Common/Sha3Reg.cpp 2024-11-26 10:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/Common/Sha3Reg.cpp 2024-12-01 10:00:00.000000000 +0100
@@ -58,7 +58,7 @@
static IHasher *CreateHasherSpec() \
{ return new CSha3Hasher(digestSize / 8, isShake, \
SHA3_BLOCK_SIZE_FROM_DIGEST_SIZE(digestSize_for_blockSize / 8)); } \
- static const CHasherInfo g_HasherInfo = { CreateHasherSpec, id, name, digestSize }; \
+ static const CHasherInfo g_HasherInfo = { CreateHasherSpec, id, name, digestSize / 8 }; \
struct REGISTER_HASHER_NAME(cls) { REGISTER_HASHER_NAME(cls)() { RegisterHasher(&g_HasherInfo); }}; \
static REGISTER_HASHER_NAME(cls) g_RegisterHasher; }
diff -Nru 7zip-24.09+dfsg/CPP/Common/Wildcard.cpp 7zip-25.00+dfsg/CPP/Common/Wildcard.cpp
--- 7zip-24.09+dfsg/CPP/Common/Wildcard.cpp 2022-12-30 16:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/Common/Wildcard.cpp 2025-06-16 12:00:00.000000000 +0200
@@ -255,7 +255,8 @@
bool CItem::AreAllAllowed() const
{
- return ForFile && ForDir && WildcardMatching && PathParts.Size() == 1 && PathParts.Front() == L"*";
+ return ForFile && ForDir && WildcardMatching
+ && PathParts.Size() == 1 && PathParts.Front().IsEqualTo("*");
}
bool CItem::CheckPath(const UStringVector &pathParts, bool isFile) const
@@ -542,7 +543,7 @@
{
if (pathParts.Size() < 4
|| !pathParts[1].IsEmpty()
- || pathParts[2] != L"?")
+ || !pathParts[2].IsEqualTo("?"))
return 0;
testIndex = 3;
}
@@ -574,11 +575,11 @@
return 1;
if (pathParts.Size() == 2)
return 2;
- if (pathParts[2] == L".")
+ if (pathParts[2].IsEqualTo("."))
return 3;
unsigned networkParts = 2;
- if (pathParts[2] == L"?")
+ if (pathParts[2].IsEqualTo("?"))
{
if (pathParts.Size() == 3)
return 3;
@@ -642,7 +643,7 @@
if (pathParts.Size() >= 3
&& pathParts[0].IsEmpty()
&& pathParts[1].IsEmpty()
- && pathParts[2] == L"?")
+ && pathParts[2].IsEqualTo("?"))
ignoreWildcardIndex = 2;
// #endif
@@ -665,7 +666,7 @@
for (unsigned i = numPrefixParts; i < pathParts.Size(); i++)
{
const UString &part = pathParts[i];
- if (part == L".." || part == L".")
+ if (part.IsEqualTo("..") || part.IsEqualTo("."))
dotsIndex = (int)i;
}
diff -Nru 7zip-24.09+dfsg/CPP/Windows/FileDir.cpp 7zip-25.00+dfsg/CPP/Windows/FileDir.cpp
--- 7zip-24.09+dfsg/CPP/Windows/FileDir.cpp 2024-10-24 07:00:00.000000000 +0200
+++ 7zip-25.00+dfsg/CPP/Windows/FileDir.cpp 2025-06-20 13:00:00.000000000 +0200
@@ -651,6 +651,35 @@
return RemoveDir(path);
}
+bool RemoveDirAlways_if_Empty(const FString &path)
+{
+ const DWORD attrib = NFind::GetFileAttrib(path);
+ if (attrib != INVALID_FILE_ATTRIBUTES
+ && (attrib & FILE_ATTRIBUTE_READONLY))
+ {
+ bool need_ClearAttrib = true;
+ if ((attrib & FILE_ATTRIBUTE_REPARSE_POINT) == 0)
+ {
+ FString s (path);
+ s.Add_PathSepar();
+ NFind::CEnumerator enumerator;
+ enumerator.SetDirPrefix(s);
+ NFind::CDirEntry fi;
+ if (enumerator.Next(fi))
+ {
+ // we don't want to change attributes, if there are files
+ // in directory, because RemoveDir(path) will fail.
+ need_ClearAttrib = false;
+ // SetLastError(ERROR_DIR_NOT_EMPTY);
+ // return false;
+ }
+ }
+ if (need_ClearAttrib)
+ SetFileAttrib(path, 0); // we clear read-only attrib to remove read-only dir
+ }
+ return RemoveDir(path);
+}
+
#endif // _WIN32
#ifdef UNDER_CE
diff -Nru 7zip-24.09+dfsg/CPP/Windows/FileDir.h 7zip-25.00+dfsg/CPP/Windows/FileDir.h
--- 7zip-24.09+dfsg/CPP/Windows/FileDir.h 2024-10-17 09:00:00.000000000 +0200
+++ 7zip-25.00+dfsg/CPP/Windows/FileDir.h 2024-11-30 21:00:00.000000000 +0100
@@ -78,6 +78,11 @@
bool DeleteFileAlways(CFSTR name);
bool RemoveDirWithSubItems(const FString &path);
+#ifdef _WIN32
+bool RemoveDirAlways_if_Empty(const FString &path);
+#else
+#define RemoveDirAlways_if_Empty RemoveDir
+#endif
bool MyGetFullPathName(CFSTR path, FString &resFullPath);
bool GetFullPathAndSplit(CFSTR path, FString &resDirPrefix, FString &resFileName);
diff -Nru 7zip-24.09+dfsg/CPP/Windows/FileFind.cpp 7zip-25.00+dfsg/CPP/Windows/FileFind.cpp
--- 7zip-24.09+dfsg/CPP/Windows/FileFind.cpp 2024-02-12 11:47:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/Windows/FileFind.cpp 2025-06-20 13:00:00.000000000 +0200
@@ -731,7 +731,7 @@
bool isOK = false;
if (finder.FindFirst(s, *this))
{
- if (Name == FTEXT("."))
+ if (Name.IsEqualTo("."))
{
Name = path + prefixSize;
return true;
@@ -769,6 +769,13 @@
// return FollowReparse(path, IsDir());
return Fill_From_ByHandleFileInfo(path);
+/*
+ // Fill_From_ByHandleFileInfo returns false (with Access Denied error),
+ // if there is reparse link file (not directory reparse item).
+ if (Fill_From_ByHandleFileInfo(path))
+ return true;
+ return HasReparsePoint();
+*/
}
bool CFileInfoBase::Fill_From_ByHandleFileInfo(CFSTR path)
diff -Nru 7zip-24.09+dfsg/CPP/Windows/FileIO.h 7zip-25.00+dfsg/CPP/Windows/FileIO.h
--- 7zip-24.09+dfsg/CPP/Windows/FileIO.h 2024-02-10 17:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/Windows/FileIO.h 2025-06-20 13:15:00.000000000 +0200
@@ -11,8 +11,7 @@
#define Z7_WIN_SYMLINK_FLAG_RELATIVE 1
-// what the meaning of that FLAG or field (2)?
-#define Z7_WIN_LX_SYMLINK_FLAG 2
+#define Z7_WIN_LX_SYMLINK_VERSION_2 2
#ifdef _WIN32
@@ -44,7 +43,33 @@
namespace NFile {
#if defined(_WIN32) && !defined(UNDER_CE)
-bool FillLinkData(CByteBuffer &dest, const wchar_t *path, bool isSymLink, bool isWSL);
+/*
+ in: (CByteBuffer &dest) is empty
+ in: (path) uses Windows path separator (\).
+ out: (path) uses Linux path separator (/).
+ if (isAbsPath == true), then "c:\\" prefix is replaced to "/mnt/c/" prefix
+*/
+void Convert_WinPath_to_WslLinuxPath(FString &path, bool convertDrivePath);
+// (path) must use Linux path separator (/).
+void FillLinkData_WslLink(CByteBuffer &dest, const wchar_t *path);
+
+/*
+ in: (CByteBuffer &dest) is empty
+ if (isSymLink == false) : MOUNT_POINT : (path) must be absolute.
+ if (isSymLink == true) : SYMLINK : Windows
+ (path) must use Windows path separator (\).
+ (path) must be without link "\\??\\" prefix.
+ link "\\??\\" prefix will be added inside FillLinkData(), if path is absolute.
+*/
+void FillLinkData_WinLink(CByteBuffer &dest, const wchar_t *path, bool isSymLink);
+// in: (CByteBuffer &dest) is empty
+inline void FillLinkData(CByteBuffer &dest, const wchar_t *path, bool isSymLink, bool isWSL)
+{
+ if (isWSL)
+ FillLinkData_WslLink(dest, path);
+ else
+ FillLinkData_WinLink(dest, path, isSymLink);
+}
#endif
struct CReparseShortInfo
@@ -61,7 +86,6 @@
UInt32 Flags;
UString SubsName;
UString PrintName;
-
AString WslName;
bool HeaderError;
@@ -71,8 +95,7 @@
CReparseAttr(): Tag(0), Flags(0) {}
- // Parse()
- // returns (true) and (ErrorCode = 0), if (it'a correct known link)
+ // returns (true) and (ErrorCode = 0), if (it's correct known link)
// returns (false) and (ErrorCode = ERROR_REPARSE_TAG_INVALID), if unknown tag
bool Parse(const Byte *p, size_t size);
@@ -80,18 +103,14 @@
bool IsSymLink_Win() const { return Tag == Z7_WIN_IO_REPARSE_TAG_SYMLINK; }
bool IsSymLink_WSL() const { return Tag == Z7_WIN_IO_REPARSE_TAG_LX_SYMLINK; }
+ // note: "/dir1/path" is marked as relative.
bool IsRelative_Win() const { return Flags == Z7_WIN_SYMLINK_FLAG_RELATIVE; }
bool IsRelative_WSL() const
{
- if (WslName.IsEmpty())
- return true;
- char c = WslName[0];
- return !IS_PATH_SEPAR(c);
+ return WslName[0] != '/'; // WSL uses unix path separator
}
- // bool IsVolume() const;
-
bool IsOkNamePair() const;
UString GetPath() const;
};
diff -Nru 7zip-24.09+dfsg/CPP/Windows/FileLink.cpp 7zip-25.00+dfsg/CPP/Windows/FileLink.cpp
--- 7zip-24.09+dfsg/CPP/Windows/FileLink.cpp 2023-09-05 08:00:00.000000000 +0200
+++ 7zip-25.00+dfsg/CPP/Windows/FileLink.cpp 2025-06-20 13:00:00.000000000 +0200
@@ -39,12 +39,24 @@
using namespace NName;
/*
+Win10 Junctions/SymLinks:
+ - (/) slash doesn't work as path separator
+ - Win10 preinstalled junctions don't use tail backslash, but tail backslashes also work.
+ - double backslash works only after drive prefix "c:\\dir1\dir2\",
+ and doesn't work in another places.
+ - absolute path without \??\ prefix doesn't work
+ - absolute path "c:" doesn't work
+*/
+
+/*
Reparse Points (Junctions and Symbolic Links):
struct
{
UInt32 Tag;
UInt16 Size; // not including starting 8 bytes
- UInt16 Reserved; // = 0
+ UInt16 Reserved; // = 0, DOCs: // Length, in bytes, of the unparsed portion of
+ // the file name pointed to by the FileName member of the associated file object.
+ // This member is only valid for create operations when the I/O fails with STATUS_REPARSE.
UInt16 SubstituteOffset; // offset in bytes from start of namesChars
UInt16 SubstituteLen; // size in bytes, it doesn't include tailed NUL
@@ -68,6 +80,16 @@
2) Default Order in table:
Print Path
Substitute Path
+
+DOCS:
+ The print name SHOULD be an informative pathname, suitable for display
+ to a user, that also identifies the target of the mount point.
+ Neither of these pathnames can contain dot directory names.
+
+reparse tags, with the exception of IO_REPARSE_TAG_SYMLINK,
+are processed on the server and are not processed by a client
+after transmission over the wire.
+Clients SHOULD treat associated reparse data as opaque data.
*/
/*
@@ -93,7 +115,8 @@
#define Get16(p) GetUi16(p)
#define Get32(p) GetUi32(p)
-static const wchar_t * const k_LinkPrefix = L"\\??\\";
+static const char * const k_LinkPrefix = "\\??\\";
+static const char * const k_LinkPrefix_UNC = "\\??\\UNC\\";
static const unsigned k_LinkPrefix_Size = 4;
static bool IsLinkPrefix(const wchar_t *s)
@@ -102,7 +125,7 @@
}
/*
-static const wchar_t * const k_VolumePrefix = L"Volume{";
+static const char * const k_VolumePrefix = "Volume{";
static const bool IsVolumeName(const wchar_t *s)
{
return IsString1PrefixedByString2(s, k_VolumePrefix);
@@ -118,7 +141,7 @@
{
for (;;)
{
- wchar_t c = *path++;
+ const wchar_t c = *path++;
if (c == 0)
return;
Set16(dest, (UInt16)c)
@@ -126,62 +149,103 @@
}
}
-bool FillLinkData(CByteBuffer &dest, const wchar_t *path, bool isSymLink, bool isWSL)
+#ifdef _WIN32
+void Convert_WinPath_to_WslLinuxPath(FString &s, bool convertDrivePath)
{
- bool isAbs = IsAbsolutePath(path);
- if (!isAbs && !isSymLink)
- return false;
-
- if (isWSL)
+ if (convertDrivePath && IsDrivePath(s))
{
- // unsupported characters probably use Replacement Character UTF-16 0xFFFD
- AString utf;
- ConvertUnicodeToUTF8(path, utf);
- const size_t size = 4 + utf.Len();
- if (size != (UInt16)size)
- return false;
- dest.Alloc(8 + size);
- Byte *p = dest;
- Set32(p, Z7_WIN_IO_REPARSE_TAG_LX_SYMLINK)
- Set16(p + 4, (UInt16)(size))
- Set16(p + 6, 0)
- Set32(p + 8, Z7_WIN_LX_SYMLINK_FLAG)
- memcpy(p + 12, utf.Ptr(), utf.Len());
- return true;
+ FChar c = s[0];
+ c = MyCharLower_Ascii(c);
+ s.DeleteFrontal(2);
+ s.InsertAtFront(c);
+ s.Insert(0, FTEXT("/mnt/"));
}
+ s.Replace(FCHAR_PATH_SEPARATOR, FTEXT('/'));
+}
+#endif
- // usual symbolic LINK (NOT WSL)
- bool needPrintName = true;
+static const unsigned k_Link_Size_Limit = 1u << 16; // 16-bit field is used for size.
+
+void FillLinkData_WslLink(CByteBuffer &dest, const wchar_t *path)
+{
+ // dest.Free(); // it's empty already
+ // WSL probably uses Replacement Character UTF-16 0xFFFD for unsupported characters?
+ AString utf;
+ ConvertUnicodeToUTF8(path, utf);
+ const unsigned size = 4 + utf.Len();
+ if (size >= k_Link_Size_Limit)
+ return;
+ dest.Alloc(8 + size);
+ Byte *p = dest;
+ Set32(p, Z7_WIN_IO_REPARSE_TAG_LX_SYMLINK)
+ // Set32(p + 4, (UInt32)size)
+ Set16(p + 4, (UInt16)size)
+ Set16(p + 6, 0)
+ Set32(p + 8, Z7_WIN_LX_SYMLINK_VERSION_2)
+ memcpy(p + 12, utf.Ptr(), utf.Len());
+}
+
- if (IsSuperPath(path))
+void FillLinkData_WinLink(CByteBuffer &dest, const wchar_t *path, bool isSymLink)
+{
+ // dest.Free(); // it's empty already
+ bool isAbs = false;
+ if (IS_PATH_SEPAR(path[0]))
+ {
+ // root paths "\dir1\path" are marked as relative
+ if (IS_PATH_SEPAR(path[1]))
+ isAbs = true;
+ }
+ else
+ isAbs = IsAbsolutePath(path);
+ if (!isAbs && !isSymLink)
{
- path += kSuperPathPrefixSize;
- if (!IsDrivePath(path))
- needPrintName = false;
+ // Win10 allows us to create relative MOUNT_POINT.
+ // But relative MOUNT_POINT will not work when accessing it.
+ // So we prevent useless creation of a relative MOUNT_POINT.
+ return;
}
- const unsigned add_Prefix_Len = isAbs ? k_LinkPrefix_Size : 0;
-
+ bool needPrintName = true;
+ UString subs (path);
+ if (isAbs)
+ {
+ const bool isSuperPath = IsSuperPath(path);
+ if (!isSuperPath && NName::IsNetworkPath(us2fs(path)))
+ {
+ subs = k_LinkPrefix_UNC;
+ subs += (path + 2);
+ }
+ else
+ {
+ if (isSuperPath)
+ {
+ // we remove super prefix:
+ path += kSuperPathPrefixSize;
+ // we want to get correct abolute path in PrintName still.
+ if (!IsDrivePath(path))
+ needPrintName = false; // we need "\\server\path" for print name.
+ }
+ subs = k_LinkPrefix;
+ subs += path;
+ }
+ }
+ const size_t len1 = subs.Len() * 2;
size_t len2 = (size_t)MyStringLen(path) * 2;
- const size_t len1 = len2 + add_Prefix_Len * 2;
if (!needPrintName)
len2 = 0;
-
- size_t totalNamesSize = (len1 + len2);
-
+ size_t totalNamesSize = len1 + len2;
/* some WIM imagex software uses old scheme for symbolic links.
- so we can old scheme for byte to byte compatibility */
-
- bool newOrderScheme = isSymLink;
+ so we can use old scheme for byte to byte compatibility */
+ const bool newOrderScheme = isSymLink;
// newOrderScheme = false;
-
if (!newOrderScheme)
- totalNamesSize += 2 * 2;
+ totalNamesSize += 2 * 2; // we use NULL terminators in old scheme.
const size_t size = 8 + 8 + (isSymLink ? 4 : 0) + totalNamesSize;
- if (size != (UInt16)size)
- return false;
+ if (size >= k_Link_Size_Limit)
+ return;
dest.Alloc(size);
memset(dest, 0, size);
const UInt32 tag = isSymLink ?
@@ -189,6 +253,7 @@
Z7_WIN_IO_REPARSE_TAG_MOUNT_POINT;
Byte *p = dest;
Set32(p, tag)
+ // Set32(p + 4, (UInt32)(size - 8))
Set16(p + 4, (UInt16)(size - 8))
Set16(p + 6, 0)
p += 8;
@@ -204,21 +269,16 @@
Set16(p + 2, (UInt16)len1)
Set16(p + 4, (UInt16)printOffs)
Set16(p + 6, (UInt16)len2)
-
p += 8;
if (isSymLink)
{
- UInt32 flags = isAbs ? 0 : Z7_WIN_SYMLINK_FLAG_RELATIVE;
+ const UInt32 flags = isAbs ? 0 : Z7_WIN_SYMLINK_FLAG_RELATIVE;
Set32(p, flags)
p += 4;
}
-
- if (add_Prefix_Len != 0)
- WriteString(p + subOffs, k_LinkPrefix);
- WriteString(p + subOffs + add_Prefix_Len * 2, path);
+ WriteString(p + subOffs, subs);
if (needPrintName)
WriteString(p + printOffs, path);
- return true;
}
#endif // defined(_WIN32) && !defined(UNDER_CE)
@@ -230,7 +290,7 @@
unsigned i;
for (i = 0; i < len; i++)
{
- wchar_t c = Get16(p + i * 2);
+ const wchar_t c = Get16(p + (size_t)i * 2);
if (c == 0)
break;
s[i] = c;
@@ -239,6 +299,7 @@
res.ReleaseBuf_SetLen(i);
}
+
bool CReparseAttr::Parse(const Byte *p, size_t size)
{
ErrorCode = (DWORD)ERROR_INVALID_REPARSE_DATA;
@@ -250,7 +311,12 @@
return false;
Tag = Get32(p);
if (Get16(p + 6) != 0) // padding
- return false;
+ {
+ // DOCs: Reserved : the field SHOULD be set to 0
+ // and MUST be ignored (by parser).
+ // Win10 ignores it.
+ MinorError = true; // optional
+ }
unsigned len = Get16(p + 4);
p += 8;
size -= 8;
@@ -262,8 +328,6 @@
(type & kReparseFlags_Microsoft) == 0 ||
(type & 0xFFFF) != 3)
*/
-
-
HeaderError = false;
if ( Tag != Z7_WIN_IO_REPARSE_TAG_MOUNT_POINT
@@ -282,8 +346,7 @@
{
if (len < 4)
return false;
- Flags = Get32(p); // maybe it's not Flags
- if (Flags != Z7_WIN_LX_SYMLINK_FLAG)
+ if (Get32(p) != Z7_WIN_LX_SYMLINK_VERSION_2)
return false;
len -= 4;
p += 4;
@@ -291,12 +354,13 @@
unsigned i;
for (i = 0; i < len; i++)
{
- char c = (char)p[i];
+ const char c = (char)p[i];
s[i] = c;
if (c == 0)
break;
}
- WslName.ReleaseBuf_SetEnd(i);
+ s[i] = 0;
+ WslName.ReleaseBuf_SetLen(i);
MinorError = (i != len);
ErrorCode = 0;
return true;
@@ -304,10 +368,10 @@
if (len < 8)
return false;
- unsigned subOffs = Get16(p);
- unsigned subLen = Get16(p + 2);
- unsigned printOffs = Get16(p + 4);
- unsigned printLen = Get16(p + 6);
+ const unsigned subOffs = Get16(p);
+ const unsigned subLen = Get16(p + 2);
+ const unsigned printOffs = Get16(p + 4);
+ const unsigned printLen = Get16(p + 6);
len -= 8;
p += 8;
@@ -335,15 +399,17 @@
bool CReparseShortInfo::Parse(const Byte *p, size_t size)
{
- const Byte *start = p;
- Offset= 0;
+ const Byte * const start = p;
+ Offset = 0;
Size = 0;
if (size < 8)
return false;
- UInt32 Tag = Get32(p);
+ const UInt32 Tag = Get32(p);
UInt32 len = Get16(p + 4);
+ /*
if (len + 8 > size)
return false;
+ */
/*
if ((type & kReparseFlags_Alias) == 0 ||
(type & kReparseFlags_Microsoft) == 0 ||
@@ -353,16 +419,14 @@
Tag != Z7_WIN_IO_REPARSE_TAG_SYMLINK)
// return true;
return false;
-
+ /*
if (Get16(p + 6) != 0) // padding
return false;
-
+ */
p += 8;
size -= 8;
-
if (len != size) // do we need that check?
return false;
-
if (len < 8)
return false;
unsigned subOffs = Get16(p);
@@ -396,10 +460,14 @@
{
if (IsLinkPrefix(SubsName))
{
+ if (PrintName == GetPath())
+ return true;
+/*
if (!IsDrivePath(SubsName.Ptr(k_LinkPrefix_Size)))
return PrintName.IsEmpty();
if (wcscmp(SubsName.Ptr(k_LinkPrefix_Size), PrintName) == 0)
return true;
+*/
}
return wcscmp(SubsName, PrintName) == 0;
}
@@ -415,21 +483,26 @@
UString CReparseAttr::GetPath() const
{
+ UString s (SubsName);
if (IsSymLink_WSL())
{
- UString u;
// if (CheckUTF8(attr.WslName)
- if (!ConvertUTF8ToUnicode(WslName, u))
- MultiByteToUnicodeString2(u, WslName);
- return u;
+ if (!ConvertUTF8ToUnicode(WslName, s))
+ MultiByteToUnicodeString2(s, WslName);
}
-
- UString s (SubsName);
- if (IsLinkPrefix(s))
+ else if (IsLinkPrefix(s))
{
- s.ReplaceOneCharAtPos(1, '\\'); // we normalize prefix from "\??\" to "\\?\"
- if (IsDrivePath(s.Ptr(k_LinkPrefix_Size)))
- s.DeleteFrontal(k_LinkPrefix_Size);
+ if (IsString1PrefixedByString2_NoCase_Ascii(s.Ptr(), k_LinkPrefix_UNC))
+ {
+ s.DeleteFrontal(6);
+ s.ReplaceOneCharAtPos(0, '\\');
+ }
+ else
+ {
+ s.ReplaceOneCharAtPos(1, '\\'); // we normalize prefix from "\??\" to "\\?\"
+ if (IsDrivePath(s.Ptr(k_LinkPrefix_Size)))
+ s.DeleteFrontal(k_LinkPrefix_Size);
+ }
}
return s;
}
@@ -468,7 +541,7 @@
static bool CreatePrefixDirOfFile(CFSTR path)
{
FString path2 (path);
- int pos = path2.ReverseFind_PathSepar();
+ const int pos = path2.ReverseFind_PathSepar();
if (pos < 0)
return true;
#ifdef _WIN32
@@ -494,6 +567,8 @@
}
+// MOUNT_POINT (Junction Point) and LX_SYMLINK (WSL) can be written without administrator rights.
+// SYMLINK requires administrator rights.
// If there is Reparse data already, it still writes new Reparse data
bool SetReparseData(CFSTR path, bool isDir, const void *data, DWORD size)
{
@@ -540,10 +615,11 @@
SetLastError(ERROR_INVALID_REPARSE_DATA);
return false;
}
- BYTE buf[my_REPARSE_DATA_BUFFER_HEADER_SIZE];
- memset(buf, 0, sizeof(buf));
- memcpy(buf, reparseData, 4); // tag
- return OutIoReparseData(my_FSCTL_DELETE_REPARSE_POINT, path, buf, sizeof(buf));
+ // BYTE buf[my_REPARSE_DATA_BUFFER_HEADER_SIZE];
+ // memset(buf, 0, sizeof(buf));
+ // memcpy(buf, reparseData, 4); // tag
+ memset(reparseData + 4, 0, my_REPARSE_DATA_BUFFER_HEADER_SIZE - 4);
+ return OutIoReparseData(my_FSCTL_DELETE_REPARSE_POINT, path, reparseData, my_REPARSE_DATA_BUFFER_HEADER_SIZE);
}
}
diff -Nru 7zip-24.09+dfsg/CPP/Windows/FileName.cpp 7zip-25.00+dfsg/CPP/Windows/FileName.cpp
--- 7zip-24.09+dfsg/CPP/Windows/FileName.cpp 2024-10-06 12:00:00.000000000 +0200
+++ 7zip-25.00+dfsg/CPP/Windows/FileName.cpp 2025-06-14 15:39:00.000000000 +0200
@@ -65,8 +65,15 @@
dirPath.Add_PathSepar();
}
+
+#define IS_LETTER_CHAR(c) ((((unsigned)(int)(c) | 0x20) - (unsigned)'a' <= (unsigned)('z' - 'a')))
+bool IsDrivePath (const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && IS_SEPAR(s[2]); }
+// bool IsDriveName2(const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && s[2] == 0; }
+
#ifdef _WIN32
+bool IsDrivePath2(const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':'; }
+
#ifndef USE_UNICODE_FSTRING
#ifdef Z7_LONG_PATH
static void NormalizeDirSeparators(UString &s)
@@ -87,13 +94,6 @@
s.ReplaceOneCharAtPos(i, FCHAR_PATH_SEPARATOR);
}
-#endif
-
-
-#define IS_LETTER_CHAR(c) ((((unsigned)(int)(c) | 0x20) - (unsigned)'a' <= (unsigned)('z' - 'a')))
-
-bool IsDrivePath(const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && IS_SEPAR(s[2]); }
-
bool IsAltPathPrefix(CFSTR s) throw()
{
unsigned len = MyStringLen(s);
@@ -117,16 +117,23 @@
return true;
}
-#if defined(_WIN32) && !defined(UNDER_CE)
+#endif // _WIN32
+
-const char * const kSuperPathPrefix = "\\\\?\\";
+const char * const kSuperPathPrefix =
+ STRING_PATH_SEPARATOR
+ STRING_PATH_SEPARATOR "?"
+ STRING_PATH_SEPARATOR;
#ifdef Z7_LONG_PATH
-static const char * const kSuperUncPrefix = "\\\\?\\UNC\\";
+static const char * const kSuperUncPrefix =
+ STRING_PATH_SEPARATOR
+ STRING_PATH_SEPARATOR "?"
+ STRING_PATH_SEPARATOR "UNC"
+ STRING_PATH_SEPARATOR;
#endif
#define IS_DEVICE_PATH(s) (IS_SEPAR((s)[0]) && IS_SEPAR((s)[1]) && (s)[2] == '.' && IS_SEPAR((s)[3]))
#define IS_SUPER_PREFIX(s) (IS_SEPAR((s)[0]) && IS_SEPAR((s)[1]) && (s)[2] == '?' && IS_SEPAR((s)[3]))
-#define IS_SUPER_OR_DEVICE_PATH(s) (IS_SEPAR((s)[0]) && IS_SEPAR((s)[1]) && ((s)[2] == '?' || (s)[2] == '.') && IS_SEPAR((s)[3]))
#define IS_UNC_WITH_SLASH(s) ( \
((s)[0] == 'U' || (s)[0] == 'u') \
@@ -134,6 +141,16 @@
&& ((s)[2] == 'C' || (s)[2] == 'c') \
&& IS_SEPAR((s)[3]))
+static const unsigned kDrivePrefixSize = 3; /* c:\ */
+
+bool IsSuperPath(const wchar_t *s) throw();
+bool IsSuperPath(const wchar_t *s) throw() { return IS_SUPER_PREFIX(s); }
+// bool IsSuperUncPath(const wchar_t *s) throw() { return (IS_SUPER_PREFIX(s) && IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize)); }
+
+#if defined(_WIN32) && !defined(UNDER_CE)
+
+#define IS_SUPER_OR_DEVICE_PATH(s) (IS_SEPAR((s)[0]) && IS_SEPAR((s)[1]) && ((s)[2] == '?' || (s)[2] == '.') && IS_SEPAR((s)[3]))
+bool IsSuperOrDevicePath(const wchar_t *s) throw() { return IS_SUPER_OR_DEVICE_PATH(s); }
bool IsDevicePath(CFSTR s) throw()
{
#ifdef UNDER_CE
@@ -154,7 +171,7 @@
if (!IS_DEVICE_PATH(s))
return false;
- unsigned len = MyStringLen(s);
+ const unsigned len = MyStringLen(s);
if (len == 6 && s[5] == ':')
return true;
if (len < 18 || len > 22 || !IsString1PrefixedByString2(s + kDevicePathPrefixSize, "PhysicalDrive"))
@@ -174,7 +191,7 @@
return false;
if (IsSuperUncPath(s))
return true;
- FChar c = s[2];
+ const FChar c = s[2];
return (c != '.' && c != '?');
}
@@ -187,7 +204,7 @@
prefixSize = kSuperUncPathPrefixSize;
else
{
- FChar c = s[2];
+ const FChar c = s[2];
if (c == '.' || c == '?')
return 0;
}
@@ -209,14 +226,6 @@
return s[(unsigned)pos + 1] == 0;
}
-static const unsigned kDrivePrefixSize = 3; /* c:\ */
-
-bool IsDrivePath2(const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':'; }
-// bool IsDriveName2(const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && s[2] == 0; }
-bool IsSuperPath(const wchar_t *s) throw() { return IS_SUPER_PREFIX(s); }
-bool IsSuperOrDevicePath(const wchar_t *s) throw() { return IS_SUPER_OR_DEVICE_PATH(s); }
-// bool IsSuperUncPath(const wchar_t *s) throw() { return (IS_SUPER_PREFIX(s) && IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize)); }
-
bool IsAltStreamPrefixWithColon(const UString &s) throw()
{
if (s.IsEmpty())
@@ -349,14 +358,16 @@
}
#endif // USE_UNICODE_FSTRING
+#endif // _WIN32
+
static unsigned GetRootPrefixSize_Of_NetworkPath(const wchar_t *s) throw()
{
// Network path: we look "server\path\" as root prefix
- int pos = FindSepar(s);
+ const int pos = FindSepar(s);
if (pos < 0)
return 0;
- int pos2 = FindSepar(s + (unsigned)pos + 1);
+ const int pos2 = FindSepar(s + (unsigned)pos + 1);
if (pos2 < 0)
return 0;
return (unsigned)(pos + pos2 + 2);
@@ -370,7 +381,7 @@
return 0;
if (s[1] == 0 || !IS_SEPAR(s[1]))
return 1;
- unsigned size = GetRootPrefixSize_Of_NetworkPath(s + 2);
+ const unsigned size = GetRootPrefixSize_Of_NetworkPath(s + 2);
return (size == 0) ? 0 : 2 + size;
}
@@ -378,17 +389,21 @@
{
if (IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize))
{
- unsigned size = GetRootPrefixSize_Of_NetworkPath(s + kSuperUncPathPrefixSize);
+ const unsigned size = GetRootPrefixSize_Of_NetworkPath(s + kSuperUncPathPrefixSize);
return (size == 0) ? 0 : kSuperUncPathPrefixSize + size;
}
// we support \\?\c:\ paths and volume GUID paths \\?\Volume{GUID}\"
- int pos = FindSepar(s + kSuperPathPrefixSize);
+ const int pos = FindSepar(s + kSuperPathPrefixSize);
if (pos < 0)
return 0;
return kSuperPathPrefixSize + (unsigned)(pos + 1);
}
+#ifdef _WIN32
unsigned GetRootPrefixSize(const wchar_t *s) throw()
+#else
+unsigned GetRootPrefixSize_WINDOWS(const wchar_t *s) throw()
+#endif
{
if (IS_DEVICE_PATH(s))
return kDevicePathPrefixSize;
@@ -397,7 +412,7 @@
return GetRootPrefixSize_Of_SimplePath(s);
}
-#else // _WIN32
+#ifndef _WIN32
bool IsAbsolutePath(const wchar_t *s) throw() { return IS_SEPAR(s[0]); }
diff -Nru 7zip-24.09+dfsg/CPP/Windows/FileName.h 7zip-25.00+dfsg/CPP/Windows/FileName.h
--- 7zip-24.09+dfsg/CPP/Windows/FileName.h 2023-04-24 20:00:00.000000000 +0200
+++ 7zip-25.00+dfsg/CPP/Windows/FileName.h 2025-06-20 13:00:00.000000000 +0200
@@ -25,13 +25,13 @@
bool IsAltPathPrefix(CFSTR s) throw(); /* name: */
-#if defined(_WIN32) && !defined(UNDER_CE)
-
extern const char * const kSuperPathPrefix; /* \\?\ */
const unsigned kDevicePathPrefixSize = 4;
const unsigned kSuperPathPrefixSize = 4;
const unsigned kSuperUncPathPrefixSize = kSuperPathPrefixSize + 4;
+#if defined(_WIN32) && !defined(UNDER_CE)
+
bool IsDevicePath(CFSTR s) throw(); /* \\.\ */
bool IsSuperUncPath(CFSTR s) throw(); /* \\?\UNC\ */
bool IsNetworkPath(CFSTR s) throw(); /* \\?\UNC\ or \\SERVER */
@@ -86,6 +86,15 @@
bool IsAbsolutePath(const wchar_t *s) throw();
unsigned GetRootPrefixSize(const wchar_t *s) throw();
+#ifndef _WIN32
+/* GetRootPrefixSize_WINDOWS() is called in linux, but it parses path by windows rules.
+ It supports only paths system (linux) slash separators (STRING_PATH_SEPARATOR),
+ It doesn't parses paths with backslash (windows) separators.
+ "c:/dir/file" is supported.
+*/
+unsigned GetRootPrefixSize_WINDOWS(const wchar_t *s) throw();
+#endif
+
#ifdef Z7_LONG_PATH
const int kSuperPathType_UseOnlyMain = 0;
diff -Nru 7zip-24.09+dfsg/CPP/Windows/System.cpp 7zip-25.00+dfsg/CPP/Windows/System.cpp
--- 7zip-24.09+dfsg/CPP/Windows/System.cpp 2024-10-24 07:00:00.000000000 +0200
+++ 7zip-25.00+dfsg/CPP/Windows/System.cpp 2025-06-30 17:00:00.000000000 +0200
@@ -25,6 +25,69 @@
#ifdef _WIN32
+/*
+note: returned value in 32-bit version can be limited by value 32.
+ while 64-bit version returns full value.
+GetMaximumProcessorCount(groupNumber) can return higher value than
+GetActiveProcessorCount(groupNumber) in some cases, because CPUs can be added.
+*/
+// typedef DWORD (WINAPI *Func_GetMaximumProcessorCount)(WORD GroupNumber);
+typedef DWORD (WINAPI *Func_GetActiveProcessorCount)(WORD GroupNumber);
+typedef WORD (WINAPI *Func_GetActiveProcessorGroupCount)(VOID);
+/*
+#if 0 && defined(ALL_PROCESSOR_GROUPS)
+#define MY_ALL_PROCESSOR_GROUPS ALL_PROCESSOR_GROUPS
+#else
+#define MY_ALL_PROCESSOR_GROUPS 0xffff
+#endif
+*/
+
+Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION
+
+bool CCpuGroups::Load()
+{
+ NumThreadsTotal = 0;
+ GroupSizes.Clear();
+ const HMODULE hmodule = ::GetModuleHandleA("kernel32.dll");
+ // Is_Win11_Groups = GetProcAddress(hmodule, "SetThreadSelectedCpuSetMasks") != NULL;
+ const
+ Func_GetActiveProcessorGroupCount
+ fn_GetActiveProcessorGroupCount = Z7_GET_PROC_ADDRESS(
+ Func_GetActiveProcessorGroupCount, hmodule,
+ "GetActiveProcessorGroupCount");
+ const
+ Func_GetActiveProcessorCount
+ fn_GetActiveProcessorCount = Z7_GET_PROC_ADDRESS(
+ Func_GetActiveProcessorCount, hmodule,
+ "GetActiveProcessorCount");
+ if (!fn_GetActiveProcessorGroupCount ||
+ !fn_GetActiveProcessorCount)
+ return false;
+
+ const unsigned numGroups = fn_GetActiveProcessorGroupCount();
+ if (numGroups == 0)
+ return false;
+ UInt32 sum = 0;
+ for (unsigned i = 0; i < numGroups; i++)
+ {
+ const UInt32 num = fn_GetActiveProcessorCount((WORD)i);
+ /*
+ if (num == 0)
+ {
+ // it means error
+ // but is it possible that some group is empty by some reason?
+ // GroupSizes.Clear();
+ // return false;
+ }
+ */
+ sum += num;
+ GroupSizes.Add(num);
+ }
+ NumThreadsTotal = sum;
+ // NumThreadsTotal = fn_GetActiveProcessorCount(MY_ALL_PROCESSOR_GROUPS);
+ return true;
+}
+
UInt32 CountAffinity(DWORD_PTR mask)
{
UInt32 num = 0;
@@ -38,31 +101,62 @@
BOOL CProcessAffinity::Get()
{
- #ifndef UNDER_CE
- return GetProcessAffinityMask(GetCurrentProcess(), &processAffinityMask, &systemAffinityMask);
- #else
- return FALSE;
- #endif
+ IsGroupMode = false;
+ Groups.Load();
+ // SetThreadAffinityMask(GetCurrentThread(), 1);
+ // SetProcessAffinityMask(GetCurrentProcess(), 1);
+ BOOL res = GetProcessAffinityMask(GetCurrentProcess(),
+ &processAffinityMask, &systemAffinityMask);
+ /* DOCs: On a system with more than 64 processors, if the threads
+ of the calling process are in a single processor group, the
+ function sets the variables pointed to by lpProcessAffinityMask
+ and lpSystemAffinityMask to the process affinity mask and the
+ processor mask of active logical processors for that group.
+ If the calling process contains threads in multiple groups,
+ the function returns zero for both affinity masks
+
+ note: tested in Win10: GetProcessAffinityMask() doesn't return 0
+ in (processAffinityMask) and (systemAffinityMask) masks.
+ We need to test it in Win11: how to get mask==0 from GetProcessAffinityMask()?
+ */
+ if (!res)
+ {
+ processAffinityMask = 0;
+ systemAffinityMask = 0;
+ }
+ if (Groups.GroupSizes.Size() > 1 && Groups.NumThreadsTotal)
+ if (// !res ||
+ processAffinityMask == 0 || // to support case described in DOCs and for (!res) case
+ processAffinityMask == systemAffinityMask) // for default nonchanged affinity
+ {
+ // we set IsGroupMode only if processAffinity is default (not changed).
+ res = TRUE;
+ IsGroupMode = true;
+ }
+ return res;
}
+UInt32 CProcessAffinity::Load_and_GetNumberOfThreads()
+{
+ if (Get())
+ {
+ const UInt32 numProcessors = GetNumProcessThreads();
+ if (numProcessors)
+ return numProcessors;
+ }
+ SYSTEM_INFO systemInfo;
+ GetSystemInfo(&systemInfo);
+ // the number of logical processors in the current group
+ return systemInfo.dwNumberOfProcessors;
+}
+
UInt32 GetNumberOfProcessors()
{
// We need to know how many threads we can use.
// By default the process is assigned to one group.
- // So we get the number of logical processors (threads)
- // assigned to current process in the current group.
- // Group size can be smaller than total number logical processors, for exammple, 2x36
-
CProcessAffinity pa;
-
- if (pa.Get() && pa.processAffinityMask != 0)
- return pa.GetNumProcessThreads();
-
- SYSTEM_INFO systemInfo;
- GetSystemInfo(&systemInfo);
- // the number of logical processors in the current group
- return (UInt32)systemInfo.dwNumberOfProcessors;
+ return pa.Load_and_GetNumberOfThreads();
}
#else
diff -Nru 7zip-24.09+dfsg/CPP/Windows/System.h 7zip-25.00+dfsg/CPP/Windows/System.h
--- 7zip-24.09+dfsg/CPP/Windows/System.h 2024-10-02 10:00:00.000000000 +0200
+++ 7zip-25.00+dfsg/CPP/Windows/System.h 2025-06-30 12:00:00.000000000 +0200
@@ -9,6 +9,7 @@
#endif
#include "../Common/MyTypes.h"
+#include "../Common/MyVector.h"
#include "../Common/MyWindows.h"
namespace NWindows {
@@ -16,6 +17,34 @@
#ifdef _WIN32
+struct CCpuGroups
+{
+ CRecordVector<UInt32> GroupSizes;
+ UInt32 NumThreadsTotal; // sum of threads in all groups
+ // bool Is_Win11_Groups; // useless
+
+ void Get_GroupSize_Min_Max(UInt32 &minSize, UInt32 &maxSize) const
+ {
+ unsigned num = GroupSizes.Size();
+ UInt32 minSize2 = 0, maxSize2 = 0;
+ if (num)
+ {
+ minSize2 = (UInt32)0 - 1;
+ do
+ {
+ const UInt32 v = GroupSizes[--num];
+ if (minSize2 > v) minSize2 = v;
+ if (maxSize2 < v) maxSize2 = v;
+ }
+ while (num);
+ }
+ minSize = minSize2;
+ maxSize = maxSize2;
+ }
+ bool Load();
+ CCpuGroups(): NumThreadsTotal(0) {}
+};
+
UInt32 CountAffinity(DWORD_PTR mask);
struct CProcessAffinity
@@ -25,14 +54,28 @@
DWORD_PTR processAffinityMask;
DWORD_PTR systemAffinityMask;
+ CCpuGroups Groups;
+ bool IsGroupMode;
+ /*
+ IsGroupMode == true, if
+ Groups.GroupSizes.Size() > 1) && { dafalt affinity was not changed }
+ IsGroupMode == false, if single group or affinity was changed
+ */
+
+ UInt32 Load_and_GetNumberOfThreads();
+
void InitST()
{
// numProcessThreads = 1;
// numSysThreads = 1;
processAffinityMask = 1;
systemAffinityMask = 1;
+ IsGroupMode = false;
+ // Groups.NumThreadsTotal = 0;
+ // Groups.Is_Win11_Groups = false;
}
+/*
void CpuZero()
{
processAffinityMask = 0;
@@ -42,9 +85,23 @@
{
processAffinityMask |= ((DWORD_PTR)1 << cpuIndex);
}
+*/
- UInt32 GetNumProcessThreads() const { return CountAffinity(processAffinityMask); }
- UInt32 GetNumSystemThreads() const { return CountAffinity(systemAffinityMask); }
+ UInt32 GetNumProcessThreads() const
+ {
+ if (IsGroupMode)
+ return Groups.NumThreadsTotal;
+ // IsGroupMode == false
+ // so we don't want to use groups
+ // we return number of threads in default primary group:
+ return CountAffinity(processAffinityMask);
+ }
+ UInt32 GetNumSystemThreads() const
+ {
+ if (Groups.GroupSizes.Size() > 1 && Groups.NumThreadsTotal)
+ return Groups.NumThreadsTotal;
+ return CountAffinity(systemAffinityMask);
+ }
BOOL Get();
diff -Nru 7zip-24.09+dfsg/CPP/Windows/Thread.h 7zip-25.00+dfsg/CPP/Windows/Thread.h
--- 7zip-24.09+dfsg/CPP/Windows/Thread.h 2023-03-04 10:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/CPP/Windows/Thread.h 2025-06-30 17:00:00.000000000 +0200
@@ -26,8 +26,10 @@
{ return Thread_Create_With_Affinity(&thread, startAddress, param, affinity); }
WRes Create_With_CpuSet(THREAD_FUNC_TYPE startAddress, LPVOID param, const CCpuSet *cpuSet)
{ return Thread_Create_With_CpuSet(&thread, startAddress, param, cpuSet); }
-
- #ifdef _WIN32
+
+#ifdef _WIN32
+ WRes Create_With_Group(THREAD_FUNC_TYPE startAddress, LPVOID param, unsigned group, CAffinityMask affinity = 0)
+ { return Thread_Create_With_Group(&thread, startAddress, param, group, affinity); }
operator HANDLE() { return thread; }
void Attach(HANDLE handle) { thread = handle; }
HANDLE Detach() { HANDLE h = thread; thread = NULL; return h; }
@@ -36,7 +38,7 @@
bool Terminate(DWORD exitCode) { return BOOLToBool(::TerminateThread(thread, exitCode)); }
int GetPriority() { return ::GetThreadPriority(thread); }
bool SetPriority(int priority) { return BOOLToBool(::SetThreadPriority(thread, priority)); }
- #endif
+#endif
};
}
diff -Nru 7zip-24.09+dfsg/CPP/Windows/TimeUtils.cpp 7zip-25.00+dfsg/CPP/Windows/TimeUtils.cpp
--- 7zip-24.09+dfsg/CPP/Windows/TimeUtils.cpp 2024-04-13 11:00:00.000000000 +0200
+++ 7zip-25.00+dfsg/CPP/Windows/TimeUtils.cpp 2025-06-12 10:00:00.000000000 +0200
@@ -258,8 +258,9 @@
FreeBSD 11.0, NetBSD 7.1, OpenBSD 6.0,
Minix 3.1.8, AIX 7.1, HP-UX 11.31, IRIX 6.5, Solaris 11.3,
Cygwin 2.9, mingw, MSVC 14, Android 9.0.
+ Android NDK defines TIME_UTC but doesn't have the timespec_get().
*/
-#if defined(TIME_UTC)
+#if defined(TIME_UTC) && !defined(__ANDROID__)
#define ZIP7_USE_timespec_get
// #pragma message("ZIP7_USE_timespec_get")
#elif defined(CLOCK_REALTIME)
diff -Nru 7zip-24.09+dfsg/debian/changelog 7zip-25.00+dfsg/debian/changelog
--- 7zip-24.09+dfsg/debian/changelog 2025-05-08 12:46:16.000000000 +0200
+++ 7zip-25.00+dfsg/debian/changelog 2025-07-07 17:16:13.000000000 +0200
@@ -1,3 +1,13 @@
+7zip (25.00+dfsg-1) unstable; urgency=medium
+
+ * New upstream version 25.00+dfsg
+ * Rediff patches
+ * Drop unused macro while building SFX stub
+ * Disable CI for upstream codes branch
+ * Enable cross build test in CI
+
+ -- YOKOTA Hiroshi <yokota.hgml@gmail.com> Tue, 08 Jul 2025 00:16:13 +0900
+
7zip (24.09+dfsg-8) unstable; urgency=medium
[ Roger Shimizu ]
diff -Nru 7zip-24.09+dfsg/debian/patches/0001-Accept-Debian-build-flags.patch 7zip-25.00+dfsg/debian/patches/0001-Accept-Debian-build-flags.patch
--- 7zip-24.09+dfsg/debian/patches/0001-Accept-Debian-build-flags.patch 2025-02-26 06:57:23.000000000 +0100
+++ 7zip-25.00+dfsg/debian/patches/0001-Accept-Debian-build-flags.patch 2025-07-07 17:16:13.000000000 +0200
@@ -8,7 +8,7 @@
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/CPP/7zip/7zip_gcc.mak b/CPP/7zip/7zip_gcc.mak
-index fcb580a..51c73b5 100644
+index 8fbef14..2756ba4 100644
--- a/CPP/7zip/7zip_gcc.mak
+++ b/CPP/7zip/7zip_gcc.mak
@@ -45,7 +45,7 @@ CFLAGS_DEBUG = -g
diff -Nru 7zip-24.09+dfsg/debian/patches/0002-Use-getcwd-3-POSIX-extension-to-avoid-PATH_MAX-macro.patch 7zip-25.00+dfsg/debian/patches/0002-Use-getcwd-3-POSIX-extension-to-avoid-PATH_MAX-macro.patch
--- 7zip-24.09+dfsg/debian/patches/0002-Use-getcwd-3-POSIX-extension-to-avoid-PATH_MAX-macro.patch 2025-02-26 06:57:23.000000000 +0100
+++ 7zip-25.00+dfsg/debian/patches/0002-Use-getcwd-3-POSIX-extension-to-avoid-PATH_MAX-macro.patch 2025-07-07 17:16:13.000000000 +0200
@@ -10,10 +10,10 @@
1 file changed, 1 insertion(+), 12 deletions(-)
diff --git a/CPP/Windows/FileDir.cpp b/CPP/Windows/FileDir.cpp
-index 5063568..f1efd80 100644
+index 2e36cc2..1bd2443 100644
--- a/CPP/Windows/FileDir.cpp
+++ b/CPP/Windows/FileDir.cpp
-@@ -1103,22 +1103,11 @@ bool GetCurrentDir(FString &path)
+@@ -1132,22 +1132,11 @@ bool GetCurrentDir(FString &path)
{
path.Empty();
diff -Nru 7zip-24.09+dfsg/debian/patches/0005-Add-note-for-unexpected-recursive-operations-behavio.patch 7zip-25.00+dfsg/debian/patches/0005-Add-note-for-unexpected-recursive-operations-behavio.patch
--- 7zip-24.09+dfsg/debian/patches/0005-Add-note-for-unexpected-recursive-operations-behavio.patch 2025-03-31 17:09:57.000000000 +0200
+++ 7zip-25.00+dfsg/debian/patches/0005-Add-note-for-unexpected-recursive-operations-behavio.patch 2025-07-07 17:16:13.000000000 +0200
@@ -9,7 +9,7 @@
1 file changed, 4 insertions(+)
diff --git a/CPP/7zip/UI/Console/Main.cpp b/CPP/7zip/UI/Console/Main.cpp
-index 4fa5c35..86cffb3 100644
+index 5094452..7511322 100644
--- a/CPP/7zip/UI/Console/Main.cpp
+++ b/CPP/7zip/UI/Console/Main.cpp
@@ -133,6 +133,10 @@ static const char * const kHelpString =
diff -Nru 7zip-24.09+dfsg/debian/patches/0006-Use-c-flags-for-asmc.patch 7zip-25.00+dfsg/debian/patches/0006-Use-c-flags-for-asmc.patch
--- 7zip-24.09+dfsg/debian/patches/0006-Use-c-flags-for-asmc.patch 2025-03-31 17:09:57.000000000 +0200
+++ 7zip-25.00+dfsg/debian/patches/0006-Use-c-flags-for-asmc.patch 2025-07-07 17:16:13.000000000 +0200
@@ -2,13 +2,15 @@
Date: Thu, 26 Dec 2024 23:27:17 +0900
Subject: Use "-c" flags for asmc
+Bug: https://github.com/nidud/asmc/issues/15#issuecomment-2553310674
+
No needs to build executable files while in assembling.
---
CPP/7zip/7zip_gcc.mak | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/CPP/7zip/7zip_gcc.mak b/CPP/7zip/7zip_gcc.mak
-index 51c73b5..4b0cc27 100644
+index 2756ba4..5d05cf0 100644
--- a/CPP/7zip/7zip_gcc.mak
+++ b/CPP/7zip/7zip_gcc.mak
@@ -194,7 +194,7 @@ AFLAGS_ABI = -elf -DABI_LINUX -DABI_CDECL
diff -Nru 7zip-24.09+dfsg/debian/patches/0007-Add-fpic-for-Asmc-options.patch 7zip-25.00+dfsg/debian/patches/0007-Add-fpic-for-Asmc-options.patch
--- 7zip-24.09+dfsg/debian/patches/0007-Add-fpic-for-Asmc-options.patch 2025-03-31 17:09:57.000000000 +0200
+++ 7zip-25.00+dfsg/debian/patches/0007-Add-fpic-for-Asmc-options.patch 2025-07-07 17:16:13.000000000 +0200
@@ -2,14 +2,18 @@
Date: Fri, 27 Dec 2024 12:15:55 +0900
Subject: Add "-fpic" for Asmc options
+Bug: https://github.com/nidud/asmc/issues/15#issuecomment-2554348661
+Bug: https://github.com/nidud/asmc/issues/15#issuecomment-2554659070
+
Asmc author suggests this option:
* https://github.com/nidud/asmc/issues/15#issuecomment-2554348661
+* https://github.com/nidud/asmc/issues/15#issuecomment-2554659070
---
CPP/7zip/7zip_gcc.mak | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/CPP/7zip/7zip_gcc.mak b/CPP/7zip/7zip_gcc.mak
-index 4b0cc27..792ad13 100644
+index 5d05cf0..3fada36 100644
--- a/CPP/7zip/7zip_gcc.mak
+++ b/CPP/7zip/7zip_gcc.mak
@@ -194,7 +194,7 @@ AFLAGS_ABI = -elf -DABI_LINUX -DABI_CDECL
diff -Nru 7zip-24.09+dfsg/debian/patches/0008-Drop-unused-macro-while-building-SFX-stub.patch 7zip-25.00+dfsg/debian/patches/0008-Drop-unused-macro-while-building-SFX-stub.patch
--- 7zip-24.09+dfsg/debian/patches/0008-Drop-unused-macro-while-building-SFX-stub.patch 1970-01-01 01:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/debian/patches/0008-Drop-unused-macro-while-building-SFX-stub.patch 2025-07-07 17:16:13.000000000 +0200
@@ -0,0 +1,32 @@
+From: YOKOTA Hiroshi <yokota.hgml@gmail.com>
+Date: Mon, 7 Jul 2025 11:53:15 +0900
+Subject: Drop unused macro while building SFX stub
+
+> ../../UI/Common/ArchiveExtractCallback.cpp:68:11: error: macro "REPLACE_SLASHES_from_Linux_to_Sys" is not used [-Werror=unused-macros]
+> 68 | #define REPLACE_SLASHES_from_Linux_to_Sys(s)
+> | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+> cc1plus: all warnings being treated as errors
+---
+ CPP/7zip/UI/Common/ArchiveExtractCallback.cpp | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp b/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp
+index 88c3cf8..45ac1f5 100644
+--- a/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp
++++ b/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp
+@@ -58,6 +58,7 @@ static const char * const kCantCreateSymLink = "Cannot create symbolic link";
+
+ static const unsigned k_LinkDataSize_LIMIT = 1 << 12;
+
++#ifndef Z7_SFX
+ #if WCHAR_PATH_SEPARATOR != L'/'
+ // we convert linux slashes to windows slashes for further processing.
+ // also we convert linux backslashes to BackslashReplacement character.
+@@ -67,6 +68,7 @@ static const unsigned k_LinkDataSize_LIMIT = 1 << 12;
+ #else
+ #define REPLACE_SLASHES_from_Linux_to_Sys(s)
+ #endif
++#endif // Z7_SFX
+
+
+ #ifndef Z7_SFX
diff -Nru 7zip-24.09+dfsg/debian/patches/series 7zip-25.00+dfsg/debian/patches/series
--- 7zip-24.09+dfsg/debian/patches/series 2025-03-31 17:09:57.000000000 +0200
+++ 7zip-25.00+dfsg/debian/patches/series 2025-07-07 17:16:13.000000000 +0200
@@ -5,3 +5,4 @@
0005-Add-note-for-unexpected-recursive-operations-behavio.patch
0006-Use-c-flags-for-asmc.patch
0007-Add-fpic-for-Asmc-options.patch
+0008-Drop-unused-macro-while-building-SFX-stub.patch
diff -Nru 7zip-24.09+dfsg/debian/salsa-ci.yml 7zip-25.00+dfsg/debian/salsa-ci.yml
--- 7zip-24.09+dfsg/debian/salsa-ci.yml 1970-01-01 01:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/debian/salsa-ci.yml 2025-07-07 17:16:13.000000000 +0200
@@ -0,0 +1,7 @@
+---
+include:
+ - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/recipes/debian.yml
+
+variables:
+ SALSA_CI_IGNORED_BRANCHES: 'upstream|pristine-tar'
+ SALSA_CI_DISABLE_CROSSBUILD_ARM64: 0
diff -Nru 7zip-24.09+dfsg/DOC/7zip.wxs 7zip-25.00+dfsg/DOC/7zip.wxs
--- 7zip-24.09+dfsg/DOC/7zip.wxs 2024-11-28 16:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/DOC/7zip.wxs 2025-07-05 15:00:00.000000000 +0200
@@ -1,7 +1,7 @@
<?xml version="1.0"?>
-<?define VerMajor = "24" ?>
-<?define VerMinor = "09" ?>
+<?define VerMajor = "25" ?>
+<?define VerMinor = "00" ?>
<?define VerBuild = "00" ?>
<?define MmVer = "$(var.VerMajor).$(var.VerMinor)" ?>
<?define MmHex = "$(var.VerMajor)$(var.VerMinor)" ?>
diff -Nru 7zip-24.09+dfsg/DOC/License.txt 7zip-25.00+dfsg/DOC/License.txt
--- 7zip-24.09+dfsg/DOC/License.txt 2024-01-28 15:22:46.000000000 +0100
+++ 7zip-25.00+dfsg/DOC/License.txt 2025-07-05 15:56:54.000000000 +0200
@@ -3,7 +3,7 @@
License for use and distribution
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- 7-Zip Copyright (C) 1999-2024 Igor Pavlov.
+ 7-Zip Copyright (C) 1999-2025 Igor Pavlov.
The licenses for files are:
@@ -58,7 +58,7 @@
Copyright (c) 2015-2016, Apple Inc. All rights reserved.
Copyright (c) Facebook, Inc. All rights reserved.
- Copyright (c) 2023-2024 Igor Pavlov.
+ Copyright (c) 2023-2025 Igor Pavlov.
Text of the "BSD 3-clause License"
----------------------------------
@@ -102,7 +102,7 @@
XXH64 code in 7-Zip was derived from the original XXH64 code developed by Yann Collet.
Copyright (c) 2012-2021 Yann Collet.
- Copyright (c) 2023-2024 Igor Pavlov.
+ Copyright (c) 2023-2025 Igor Pavlov.
Text of the "BSD 2-clause License"
----------------------------------
diff -Nru 7zip-24.09+dfsg/DOC/readme.txt 7zip-25.00+dfsg/DOC/readme.txt
--- 7zip-24.09+dfsg/DOC/readme.txt 2024-11-29 17:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/DOC/readme.txt 2025-07-05 15:00:00.000000000 +0200
@@ -1,9 +1,9 @@
-7-Zip 24.09 Sources
+7-Zip 25.00 Sources
-------------------
7-Zip is a file archiver for Windows.
-7-Zip Copyright (C) 1999-2024 Igor Pavlov.
+7-Zip Copyright (C) 1999-2025 Igor Pavlov.
License Info
@@ -73,8 +73,8 @@
optimization options.
-How to compile with makefile
-----------------------------
+How to compile with makefile in Windows
+---------------------------------------
Some macronames can be defined for compiling with makefile:
@@ -88,6 +88,23 @@
for dynamic linking to the run-time library (msvcrt.dll).
The default makefile option is static linking to the run-time library.
+To compile all 7-Zip files for x64 with Visual Studio 2022,
+use the following command sequence:
+
+ cd SRC\CPP\7zip
+ %comspec% /k "C:\Program Files\VS2022\VC\Auxiliary\Build\vcvars64.bat"
+ nmake
+
+You can use another "vcvars*.bat" files from "VS2022\VC\Auxiliary\Build" directory
+to compile for other platforms:
+ vcvars64.bat
+ vcvarsamd64_arm64.bat
+ vcvarsamd64_x86.bat
+
+Also you can compile single binary from directory with related project.
+For example, to compile 7za.exe, use the following command sequence:
+ cd SRC\CPP\7zip\Bundles\Alone\
+ nmake
Compiling 7-Zip for Unix/Linux
diff -Nru 7zip-24.09+dfsg/DOC/src-history.txt 7zip-25.00+dfsg/DOC/src-history.txt
--- 7zip-24.09+dfsg/DOC/src-history.txt 2024-11-29 17:00:00.000000000 +0100
+++ 7zip-25.00+dfsg/DOC/src-history.txt 2025-07-05 16:00:00.000000000 +0200
@@ -1,6 +1,18 @@
HISTORY of the 7-Zip source code
--------------------------------
+25.00 2025-07-05
+-------------------------
+- 7-Zip for Windows can now use more than 64 CPU threads for compression
+ to zip/7z/xz archives and for the 7-Zip benchmark.
+ If there are more than one processor group in Windows (on systems with more than
+ 64 cpu threads), 7-Zip distributes running CPU threads across different processor groups.
+- bzip2 compression speed was increased by 15-40%.
+- deflate (zip/gz) compression speed was increased by 1-3%.
+- improved support for zip, cpio and fat archives.
+- fixed some bugs and vulnerabilities.
+
+
24.09 2024-11-29
-------------------------
- The default dictionary size values for LZMA/LZMA2 compression methods were increased:
--- End Message ---