diff options
| author | Igor Pavlov <87184205+ip7z@users.noreply.github.com> | 2025-07-05 00:00:00 +0000 |
|---|---|---|
| committer | Igor Pavlov <87184205+ip7z@users.noreply.github.com> | 2025-07-05 19:27:33 +0500 |
| commit | 395149956d696e6e3099d8b76d797437f94a6942 (patch) | |
| tree | 6ed5013a637078ae2dfdc4acf1ad93bf29cea356 | |
| parent | e5431fa6f5505e385c6f9367260717e9c47dc2ee (diff) | |
| download | 7zip-25.00.tar.gz 7zip-25.00.tar.bz2 7zip-25.00.zip | |
25.0025.00
130 files changed, 5501 insertions, 2286 deletions
diff --git a/Asm/x86/Sort.asm b/Asm/x86/Sort.asm new file mode 100644 index 0000000..517c615 --- /dev/null +++ b/Asm/x86/Sort.asm | |||
| @@ -0,0 +1,860 @@ | |||
| 1 | ; SortTest.asm -- ASM version of HeapSort() function | ||
| 2 | ; Igor Pavlov : Public domain | ||
| 3 | |||
| 4 | include ../../../../Asm/x86/7zAsm.asm | ||
| 5 | |||
| 6 | MY_ASM_START | ||
| 7 | |||
| 8 | ifndef Z7_SORT_ASM_USE_SEGMENT | ||
| 9 | if (IS_LINUX gt 0) | ||
| 10 | ; Z7_SORT_ASM_USE_SEGMENT equ 1 | ||
| 11 | else | ||
| 12 | ; Z7_SORT_ASM_USE_SEGMENT equ 1 | ||
| 13 | endif | ||
| 14 | endif | ||
| 15 | |||
| 16 | ifdef Z7_SORT_ASM_USE_SEGMENT | ||
| 17 | _TEXT$Z7_SORT SEGMENT ALIGN(64) 'CODE' | ||
| 18 | MY_ALIGN macro num:req | ||
| 19 | align num | ||
| 20 | endm | ||
| 21 | else | ||
| 22 | MY_ALIGN macro num:req | ||
| 23 | ; We expect that ".text" is aligned for 16-bytes. | ||
| 24 | ; So we don't need large alignment inside our function. | ||
| 25 | align 16 | ||
| 26 | endm | ||
| 27 | endif | ||
| 28 | |||
| 29 | |||
| 30 | MY_ALIGN_16 macro | ||
| 31 | MY_ALIGN 16 | ||
| 32 | endm | ||
| 33 | |||
| 34 | MY_ALIGN_32 macro | ||
| 35 | MY_ALIGN 32 | ||
| 36 | endm | ||
| 37 | |||
| 38 | MY_ALIGN_64 macro | ||
| 39 | MY_ALIGN 64 | ||
| 40 | endm | ||
| 41 | |||
| 42 | ifdef x64 | ||
| 43 | |||
| 44 | NUM_PREFETCH_LEVELS equ 3 ; to prefetch 1x 64-bytes line (is good for most cases) | ||
| 45 | ; NUM_PREFETCH_LEVELS equ 4 ; to prefetch 2x 64-bytes lines (better for big arrays) | ||
| 46 | |||
| 47 | acc equ x0 | ||
| 48 | k equ r0 | ||
| 49 | k_x equ x0 | ||
| 50 | |||
| 51 | p equ r1 | ||
| 52 | |||
| 53 | s equ r2 | ||
| 54 | s_x equ x2 | ||
| 55 | |||
| 56 | a0 equ x3 | ||
| 57 | t0 equ a0 | ||
| 58 | |||
| 59 | a3 equ x5 | ||
| 60 | qq equ a3 | ||
| 61 | |||
| 62 | a1 equ x6 | ||
| 63 | t1 equ a1 | ||
| 64 | t1_r equ r6 | ||
| 65 | |||
| 66 | a2 equ x7 | ||
| 67 | t2 equ a2 | ||
| 68 | |||
| 69 | i equ r8 | ||
| 70 | e0 equ x8 | ||
| 71 | |||
| 72 | e1 equ x9 | ||
| 73 | |||
| 74 | num_last equ r10 | ||
| 75 | num_last_x equ x10 | ||
| 76 | |||
| 77 | next4_lim equ r11 | ||
| 78 | pref_lim equ r12 | ||
| 79 | |||
| 80 | |||
| 81 | |||
| 82 | SORT_2_WITH_TEMP_REG macro b0, b1, temp_reg | ||
| 83 | mov temp_reg, b0 | ||
| 84 | cmp b0, b1 | ||
| 85 | cmovae b0, b1 ; min | ||
| 86 | cmovae b1, temp_reg ; max | ||
| 87 | endm | ||
| 88 | |||
| 89 | SORT macro b0, b1 | ||
| 90 | SORT_2_WITH_TEMP_REG b0, b1, acc | ||
| 91 | endm | ||
| 92 | |||
| 93 | LOAD macro dest:req, index:req | ||
| 94 | mov dest, [p + 4 * index] | ||
| 95 | endm | ||
| 96 | |||
| 97 | STORE macro reg:req, index:req | ||
| 98 | mov [p + 4 * index], reg | ||
| 99 | endm | ||
| 100 | |||
| 101 | |||
| 102 | if (NUM_PREFETCH_LEVELS gt 3) | ||
| 103 | num_prefetches equ (1 SHL (NUM_PREFETCH_LEVELS - 3)) | ||
| 104 | else | ||
| 105 | num_prefetches equ 1 | ||
| 106 | endif | ||
| 107 | |||
| 108 | PREFETCH_OP macro offs | ||
| 109 | cur_offset = 7 * 4 ; it's average offset in 64-bytes cache line. | ||
| 110 | ; cur_offset = 0 ; we can use zero offset, if we are sure that array is aligned for 64-bytes. | ||
| 111 | rept num_prefetches | ||
| 112 | if 1 | ||
| 113 | prefetcht0 byte ptr [p + offs + cur_offset] | ||
| 114 | else | ||
| 115 | mov pref_x, dword ptr [p + offs + cur_offset] | ||
| 116 | endif | ||
| 117 | cur_offset = cur_offset + 64 | ||
| 118 | endm | ||
| 119 | endm | ||
| 120 | |||
| 121 | PREFETCH_MY macro | ||
| 122 | if 1 | ||
| 123 | if 1 | ||
| 124 | shl k, NUM_PREFETCH_LEVELS + 3 | ||
| 125 | else | ||
| 126 | ; we delay prefetch instruction to improve main loads | ||
| 127 | shl k, NUM_PREFETCH_LEVELS | ||
| 128 | shl k, 3 | ||
| 129 | ; shl k, 0 | ||
| 130 | endif | ||
| 131 | PREFETCH_OP k | ||
| 132 | elseif 1 | ||
| 133 | shl k, 3 | ||
| 134 | PREFETCH_OP k * (1 SHL NUM_PREFETCH_LEVELS) ; change it | ||
| 135 | endif | ||
| 136 | endm | ||
| 137 | |||
| 138 | |||
| 139 | STEP_1 macro exit_label, prefetch_macro | ||
| 140 | use_cmov_1 equ 1 ; set 1 for cmov, but it's slower in some cases | ||
| 141 | ; set 0 for LOAD after adc s, 0 | ||
| 142 | cmp t0, t1 | ||
| 143 | if use_cmov_1 | ||
| 144 | cmovb t0, t1 | ||
| 145 | ; STORE t0, k | ||
| 146 | endif | ||
| 147 | adc s, 0 | ||
| 148 | if use_cmov_1 eq 0 | ||
| 149 | LOAD t0, s | ||
| 150 | endif | ||
| 151 | cmp qq, t0 | ||
| 152 | jae exit_label | ||
| 153 | if 1 ; use_cmov_1 eq 0 | ||
| 154 | STORE t0, k | ||
| 155 | endif | ||
| 156 | prefetch_macro | ||
| 157 | mov t0, [p + s * 8] | ||
| 158 | mov t1, [p + s * 8 + 4] | ||
| 159 | mov k, s | ||
| 160 | add s, s ; slower for some cpus | ||
| 161 | ; lea s, dword ptr [s + s] ; slower for some cpus | ||
| 162 | ; shl s, 1 ; faster for some cpus | ||
| 163 | ; lea s, dword ptr [s * 2] ; faster for some cpus | ||
| 164 | rept 0 ; 1000 for debug : 0 for normal | ||
| 165 | ; number of calls in generate_stage : ~0.6 of number of items | ||
| 166 | shl k, 0 | ||
| 167 | endm | ||
| 168 | endm | ||
| 169 | |||
| 170 | |||
| 171 | STEP_2 macro exit_label, prefetch_macro | ||
| 172 | use_cmov_2 equ 0 ; set 1 for cmov, but it's slower in some cases | ||
| 173 | ; set 0 for LOAD after adc s, 0 | ||
| 174 | cmp t0, t1 | ||
| 175 | if use_cmov_2 | ||
| 176 | mov t2, t0 | ||
| 177 | cmovb t2, t1 | ||
| 178 | ; STORE t2, k | ||
| 179 | endif | ||
| 180 | mov t0, [p + s * 8] | ||
| 181 | mov t1, [p + s * 8 + 4] | ||
| 182 | cmovb t0, [p + s * 8 + 8] | ||
| 183 | cmovb t1, [p + s * 8 + 12] | ||
| 184 | adc s, 0 | ||
| 185 | if use_cmov_2 eq 0 | ||
| 186 | LOAD t2, s | ||
| 187 | endif | ||
| 188 | cmp qq, t2 | ||
| 189 | jae exit_label | ||
| 190 | if 1 ; use_cmov_2 eq 0 | ||
| 191 | STORE t2, k | ||
| 192 | endif | ||
| 193 | prefetch_macro | ||
| 194 | mov k, s | ||
| 195 | ; add s, s | ||
| 196 | ; lea s, [s + s] | ||
| 197 | shl s, 1 | ||
| 198 | ; lea s, [s * 2] | ||
| 199 | endm | ||
| 200 | |||
| 201 | |||
| 202 | MOVE_SMALLEST_UP macro STEP, use_prefetch, num_unrolls | ||
| 203 | LOCAL exit_1, exit_2, leaves, opt_loop, last_nodes | ||
| 204 | |||
| 205 | ; s == k * 2 | ||
| 206 | ; t0 == (p)[s] | ||
| 207 | ; t1 == (p)[s + 1] | ||
| 208 | cmp k, next4_lim | ||
| 209 | jae leaves | ||
| 210 | |||
| 211 | rept num_unrolls | ||
| 212 | STEP exit_2 | ||
| 213 | cmp k, next4_lim | ||
| 214 | jae leaves | ||
| 215 | endm | ||
| 216 | |||
| 217 | if use_prefetch | ||
| 218 | prefetch_macro equ PREFETCH_MY | ||
| 219 | pref_lim_2 equ pref_lim | ||
| 220 | ; lea pref_lim, dword ptr [num_last + 1] | ||
| 221 | ; shr pref_lim, NUM_PREFETCH_LEVELS + 1 | ||
| 222 | cmp k, pref_lim_2 | ||
| 223 | jae last_nodes | ||
| 224 | else | ||
| 225 | prefetch_macro equ | ||
| 226 | pref_lim_2 equ next4_lim | ||
| 227 | endif | ||
| 228 | |||
| 229 | MY_ALIGN_16 | ||
| 230 | opt_loop: | ||
| 231 | STEP exit_2, prefetch_macro | ||
| 232 | cmp k, pref_lim_2 | ||
| 233 | jb opt_loop | ||
| 234 | |||
| 235 | last_nodes: | ||
| 236 | ; k >= pref_lim_2 | ||
| 237 | ; 2 cases are possible: | ||
| 238 | ; case-1: num_after_prefetch_levels == 0 && next4_lim = pref_lim_2 | ||
| 239 | ; case-2: num_after_prefetch_levels == NUM_PREFETCH_LEVELS - 1 && | ||
| 240 | ; next4_lim = pref_lim_2 / (NUM_PREFETCH_LEVELS - 1) | ||
| 241 | if use_prefetch | ||
| 242 | yyy = NUM_PREFETCH_LEVELS - 1 | ||
| 243 | while yyy | ||
| 244 | yyy = yyy - 1 | ||
| 245 | STEP exit_2 | ||
| 246 | if yyy | ||
| 247 | cmp k, next4_lim | ||
| 248 | jae leaves | ||
| 249 | endif | ||
| 250 | endm | ||
| 251 | endif | ||
| 252 | |||
| 253 | leaves: | ||
| 254 | ; k >= next4_lim == (num_last + 1) / 4 must be provided by previous code. | ||
| 255 | ; we have 2 nodes in (s) level : always | ||
| 256 | ; we can have some nodes in (s * 2) level : low probability case | ||
| 257 | ; we have no nodes in (s * 4) level | ||
| 258 | ; s == k * 2 | ||
| 259 | ; t0 == (p)[s] | ||
| 260 | ; t1 == (p)[s + 1] | ||
| 261 | cmp t0, t1 | ||
| 262 | cmovb t0, t1 | ||
| 263 | adc s, 0 | ||
| 264 | STORE t0, k | ||
| 265 | |||
| 266 | ; t0 == (p)[s] | ||
| 267 | ; s / 2 == k : (s) is index of max item from (p)[k * 2], (p)[k * 2 + 1] | ||
| 268 | ; we have 3 possible cases here: | ||
| 269 | ; s * 2 > num_last : (s) node has no childs | ||
| 270 | ; s * 2 == num_last : (s) node has 1 leaf child that is last item of array | ||
| 271 | ; s * 2 < num_last : (s) node has 2 leaf childs. We provide (s * 4 > num_last) | ||
| 272 | ; we check for (s * 2 > num_last) before "cmp qq, t0" check, because | ||
| 273 | ; we will replace conditional jump with cmov instruction later. | ||
| 274 | lea t1_r, dword ptr [s + s] | ||
| 275 | cmp t1_r, num_last | ||
| 276 | ja exit_1 ; if (s * 2 > num_last), we have no childs : it's high probability branch | ||
| 277 | |||
| 278 | ; it's low probability branch | ||
| 279 | ; s * 2 <= num_last | ||
| 280 | cmp qq, t0 | ||
| 281 | jae exit_2 | ||
| 282 | |||
| 283 | ; qq < t0, so we go to next level | ||
| 284 | ; we check 1 or 2 childs in next level | ||
| 285 | mov t0, [p + s * 8] | ||
| 286 | mov k, s | ||
| 287 | mov s, t1_r | ||
| 288 | cmp t1_r, num_last | ||
| 289 | je @F ; (s == num_last) means that we have single child in tree | ||
| 290 | |||
| 291 | ; (s < num_last) : so we must read both childs and select max of them. | ||
| 292 | mov t1, [p + k * 8 + 4] | ||
| 293 | cmp t0, t1 | ||
| 294 | cmovb t0, t1 | ||
| 295 | adc s, 0 | ||
| 296 | @@: | ||
| 297 | STORE t0, k | ||
| 298 | exit_1: | ||
| 299 | ; t0 == (p)[s], s / 2 == k : (s) is index of max item from (p)[k * 2], (p)[k * 2 + 1] | ||
| 300 | cmp qq, t0 | ||
| 301 | cmovb k, s | ||
| 302 | exit_2: | ||
| 303 | STORE qq, k | ||
| 304 | endm | ||
| 305 | |||
| 306 | |||
| 307 | |||
| 308 | |||
| 309 | ifdef Z7_SORT_ASM_USE_SEGMENT | ||
| 310 | ; MY_ALIGN_64 | ||
| 311 | else | ||
| 312 | MY_ALIGN_16 | ||
| 313 | endif | ||
| 314 | |||
| 315 | MY_PROC HeapSort, 2 | ||
| 316 | |||
| 317 | if (IS_LINUX gt 0) | ||
| 318 | mov p, REG_ABI_PARAM_0 ; r1 <- r7 : linux | ||
| 319 | endif | ||
| 320 | mov num_last, REG_ABI_PARAM_1 ; r10 <- r6 : linux | ||
| 321 | ; r10 <- r2 : win64 | ||
| 322 | cmp num_last, 2 | ||
| 323 | jb end_1 | ||
| 324 | |||
| 325 | ; MY_PUSH_PRESERVED_ABI_REGS | ||
| 326 | MY_PUSH_PRESERVED_ABI_REGS_UP_TO_INCLUDING_R11 | ||
| 327 | push r12 | ||
| 328 | |||
| 329 | cmp num_last, 4 | ||
| 330 | ja sort_5 | ||
| 331 | |||
| 332 | LOAD a0, 0 | ||
| 333 | LOAD a1, 1 | ||
| 334 | SORT a0, a1 | ||
| 335 | cmp num_last, 3 | ||
| 336 | jb end_2 | ||
| 337 | |||
| 338 | LOAD a2, 2 | ||
| 339 | je sort_3 | ||
| 340 | |||
| 341 | LOAD a3, 3 | ||
| 342 | SORT a2, a3 | ||
| 343 | SORT a1, a3 | ||
| 344 | STORE a3, 3 | ||
| 345 | sort_3: | ||
| 346 | SORT a0, a2 | ||
| 347 | SORT a1, a2 | ||
| 348 | STORE a2, 2 | ||
| 349 | jmp end_2 | ||
| 350 | |||
| 351 | sort_5: | ||
| 352 | ; (num_last > 4) is required here | ||
| 353 | ; if (num_last >= 6) : we will use optimized loop for leaf nodes loop_down_1 | ||
| 354 | mov next4_lim, num_last | ||
| 355 | shr next4_lim, 2 | ||
| 356 | |||
| 357 | dec num_last | ||
| 358 | mov k, num_last | ||
| 359 | shr k, 1 | ||
| 360 | mov i, num_last | ||
| 361 | shr i, 2 | ||
| 362 | test num_last, 1 | ||
| 363 | jnz size_even | ||
| 364 | |||
| 365 | ; ODD number of items. So we compare parent with single child | ||
| 366 | LOAD t1, num_last | ||
| 367 | LOAD t0, k | ||
| 368 | SORT_2_WITH_TEMP_REG t1, t0, t2 | ||
| 369 | STORE t1, num_last | ||
| 370 | STORE t0, k | ||
| 371 | dec k | ||
| 372 | |||
| 373 | size_even: | ||
| 374 | cmp k, i | ||
| 375 | jbe loop_down ; jump for num_last == 4 case | ||
| 376 | |||
| 377 | if 0 ; 1 for debug | ||
| 378 | mov r15, k | ||
| 379 | mov r14d, 1 ; 100 | ||
| 380 | loop_benchmark: | ||
| 381 | endif | ||
| 382 | ; optimized loop for leaf nodes: | ||
| 383 | mov t0, [p + k * 8] | ||
| 384 | mov t1, [p + k * 8 + 4] | ||
| 385 | |||
| 386 | MY_ALIGN_16 | ||
| 387 | loop_down_1: | ||
| 388 | ; we compare parent with max of childs: | ||
| 389 | ; lea s, dword ptr [2 * k] | ||
| 390 | mov s, k | ||
| 391 | cmp t0, t1 | ||
| 392 | cmovb t0, t1 | ||
| 393 | adc s, s | ||
| 394 | LOAD t2, k | ||
| 395 | STORE t0, k | ||
| 396 | cmp t2, t0 | ||
| 397 | cmovae s, k | ||
| 398 | dec k | ||
| 399 | ; we preload next items before STORE operation for calculated address | ||
| 400 | mov t0, [p + k * 8] | ||
| 401 | mov t1, [p + k * 8 + 4] | ||
| 402 | STORE t2, s | ||
| 403 | cmp k, i | ||
| 404 | jne loop_down_1 | ||
| 405 | |||
| 406 | if 0 ; 1 for debug | ||
| 407 | mov k, r15 | ||
| 408 | dec r14d | ||
| 409 | jnz loop_benchmark | ||
| 410 | ; jmp end_debug | ||
| 411 | endif | ||
| 412 | |||
| 413 | MY_ALIGN_16 | ||
| 414 | loop_down: | ||
| 415 | mov t0, [p + i * 8] | ||
| 416 | mov t1, [p + i * 8 + 4] | ||
| 417 | LOAD qq, i | ||
| 418 | mov k, i | ||
| 419 | lea s, dword ptr [i + i] | ||
| 420 | ; jmp end_debug | ||
| 421 | DOWN_use_prefetch equ 0 | ||
| 422 | DOWN_num_unrolls equ 0 | ||
| 423 | MOVE_SMALLEST_UP STEP_1, DOWN_use_prefetch, DOWN_num_unrolls | ||
| 424 | sub i, 1 | ||
| 425 | jnb loop_down | ||
| 426 | |||
| 427 | ; jmp end_debug | ||
| 428 | LOAD e0, 0 | ||
| 429 | LOAD e1, 1 | ||
| 430 | |||
| 431 | LEVEL_3_LIMIT equ 8 ; 8 is default, but 7 also can work | ||
| 432 | |||
| 433 | cmp num_last, LEVEL_3_LIMIT + 1 | ||
| 434 | jb main_loop_sort_5 | ||
| 435 | |||
| 436 | MY_ALIGN_16 | ||
| 437 | main_loop_sort: | ||
| 438 | ; num_last > LEVEL_3_LIMIT | ||
| 439 | ; p[size--] = p[0]; | ||
| 440 | LOAD qq, num_last | ||
| 441 | STORE e0, num_last | ||
| 442 | mov e0, e1 | ||
| 443 | |||
| 444 | mov next4_lim, num_last | ||
| 445 | shr next4_lim, 2 | ||
| 446 | mov pref_lim, num_last | ||
| 447 | shr pref_lim, NUM_PREFETCH_LEVELS + 1 | ||
| 448 | |||
| 449 | dec num_last | ||
| 450 | if 0 ; 1 for debug | ||
| 451 | ; that optional optimization can improve the performance, if there are identical items in array | ||
| 452 | ; 3 times improvement : if all items in array are identical | ||
| 453 | ; 20% improvement : if items are different for 1 bit only | ||
| 454 | ; 1-10% improvement : if items are different for (2+) bits | ||
| 455 | ; no gain : if items are different | ||
| 456 | cmp qq, e1 | ||
| 457 | jae next_iter_main | ||
| 458 | endif | ||
| 459 | LOAD e1, 2 | ||
| 460 | LOAD t0, 3 | ||
| 461 | mov k_x, 2 | ||
| 462 | cmp e1, t0 | ||
| 463 | cmovb e1, t0 | ||
| 464 | mov t0, [p + 4 * (4 + 0)] | ||
| 465 | mov t1, [p + 4 * (4 + 1)] | ||
| 466 | cmovb t0, [p + 4 * (4 + 2)] | ||
| 467 | cmovb t1, [p + 4 * (4 + 3)] | ||
| 468 | adc k_x, 0 | ||
| 469 | ; (qq <= e1), because the tree is correctly sorted | ||
| 470 | ; also here we could check (qq >= e1) or (qq == e1) for faster exit | ||
| 471 | lea s, dword ptr [k + k] | ||
| 472 | MAIN_use_prefetch equ 1 | ||
| 473 | MAIN_num_unrolls equ 0 | ||
| 474 | MOVE_SMALLEST_UP STEP_2, MAIN_use_prefetch, MAIN_num_unrolls | ||
| 475 | |||
| 476 | next_iter_main: | ||
| 477 | cmp num_last, LEVEL_3_LIMIT | ||
| 478 | jne main_loop_sort | ||
| 479 | |||
| 480 | ; num_last == LEVEL_3_LIMIT | ||
| 481 | main_loop_sort_5: | ||
| 482 | ; 4 <= num_last <= LEVEL_3_LIMIT | ||
| 483 | ; p[size--] = p[0]; | ||
| 484 | LOAD qq, num_last | ||
| 485 | STORE e0, num_last | ||
| 486 | mov e0, e1 | ||
| 487 | dec num_last_x | ||
| 488 | |||
| 489 | LOAD e1, 2 | ||
| 490 | LOAD t0, 3 | ||
| 491 | mov k_x, 2 | ||
| 492 | cmp e1, t0 | ||
| 493 | cmovb e1, t0 | ||
| 494 | adc k_x, 0 | ||
| 495 | |||
| 496 | lea s_x, dword ptr [k * 2] | ||
| 497 | cmp s_x, num_last_x | ||
| 498 | ja exit_2 | ||
| 499 | |||
| 500 | mov t0, [p + k * 8] | ||
| 501 | je exit_1 | ||
| 502 | |||
| 503 | ; s < num_last | ||
| 504 | mov t1, [p + k * 8 + 4] | ||
| 505 | cmp t0, t1 | ||
| 506 | cmovb t0, t1 | ||
| 507 | adc s_x, 0 | ||
| 508 | exit_1: | ||
| 509 | STORE t0, k | ||
| 510 | cmp qq, t0 | ||
| 511 | cmovb k_x, s_x | ||
| 512 | exit_2: | ||
| 513 | STORE qq, k | ||
| 514 | cmp num_last_x, 3 | ||
| 515 | jne main_loop_sort_5 | ||
| 516 | |||
| 517 | ; num_last == 3 (real_size == 4) | ||
| 518 | LOAD a0, 2 | ||
| 519 | LOAD a1, 3 | ||
| 520 | STORE e1, 2 | ||
| 521 | STORE e0, 3 | ||
| 522 | SORT a0, a1 | ||
| 523 | end_2: | ||
| 524 | STORE a0, 0 | ||
| 525 | STORE a1, 1 | ||
| 526 | ; end_debug: | ||
| 527 | ; MY_POP_PRESERVED_ABI_REGS | ||
| 528 | pop r12 | ||
| 529 | MY_POP_PRESERVED_ABI_REGS_UP_TO_INCLUDING_R11 | ||
| 530 | end_1: | ||
| 531 | MY_ENDP | ||
| 532 | |||
| 533 | |||
| 534 | |||
| 535 | else | ||
| 536 | ; ------------ x86 32-bit ------------ | ||
| 537 | |||
| 538 | ifdef x64 | ||
| 539 | IS_CDECL = 0 | ||
| 540 | endif | ||
| 541 | |||
| 542 | acc equ x0 | ||
| 543 | k equ r0 | ||
| 544 | k_x equ acc | ||
| 545 | |||
| 546 | p equ r1 | ||
| 547 | |||
| 548 | num_last equ r2 | ||
| 549 | num_last_x equ x2 | ||
| 550 | |||
| 551 | a0 equ x3 | ||
| 552 | t0 equ a0 | ||
| 553 | |||
| 554 | a3 equ x5 | ||
| 555 | i equ r5 | ||
| 556 | e0 equ a3 | ||
| 557 | |||
| 558 | a1 equ x6 | ||
| 559 | qq equ a1 | ||
| 560 | |||
| 561 | a2 equ x7 | ||
| 562 | s equ r7 | ||
| 563 | s_x equ a2 | ||
| 564 | |||
| 565 | |||
| 566 | SORT macro b0, b1 | ||
| 567 | cmp b1, b0 | ||
| 568 | jae @F | ||
| 569 | if 1 | ||
| 570 | xchg b0, b1 | ||
| 571 | else | ||
| 572 | mov acc, b0 | ||
| 573 | mov b0, b1 ; min | ||
| 574 | mov b1, acc ; max | ||
| 575 | endif | ||
| 576 | @@: | ||
| 577 | endm | ||
| 578 | |||
| 579 | LOAD macro dest:req, index:req | ||
| 580 | mov dest, [p + 4 * index] | ||
| 581 | endm | ||
| 582 | |||
| 583 | STORE macro reg:req, index:req | ||
| 584 | mov [p + 4 * index], reg | ||
| 585 | endm | ||
| 586 | |||
| 587 | |||
| 588 | STEP_1 macro exit_label | ||
| 589 | mov t0, [p + k * 8] | ||
| 590 | cmp t0, [p + k * 8 + 4] | ||
| 591 | adc s, 0 | ||
| 592 | LOAD t0, s | ||
| 593 | STORE t0, k ; we lookahed stooring for most expected branch | ||
| 594 | cmp qq, t0 | ||
| 595 | jae exit_label | ||
| 596 | ; STORE t0, k ; use if | ||
| 597 | mov k, s | ||
| 598 | add s, s | ||
| 599 | ; lea s, dword ptr [s + s] | ||
| 600 | ; shl s, 1 | ||
| 601 | ; lea s, dword ptr [s * 2] | ||
| 602 | endm | ||
| 603 | |||
| 604 | STEP_BRANCH macro exit_label | ||
| 605 | mov t0, [p + k * 8] | ||
| 606 | cmp t0, [p + k * 8 + 4] | ||
| 607 | jae @F | ||
| 608 | inc s | ||
| 609 | mov t0, [p + k * 8 + 4] | ||
| 610 | @@: | ||
| 611 | cmp qq, t0 | ||
| 612 | jae exit_label | ||
| 613 | STORE t0, k | ||
| 614 | mov k, s | ||
| 615 | add s, s | ||
| 616 | endm | ||
| 617 | |||
| 618 | |||
| 619 | |||
| 620 | MOVE_SMALLEST_UP macro STEP, num_unrolls, exit_2 | ||
| 621 | LOCAL leaves, opt_loop, single | ||
| 622 | |||
| 623 | ; s == k * 2 | ||
| 624 | rept num_unrolls | ||
| 625 | cmp s, num_last | ||
| 626 | jae leaves | ||
| 627 | STEP_1 exit_2 | ||
| 628 | endm | ||
| 629 | cmp s, num_last | ||
| 630 | jb opt_loop | ||
| 631 | |||
| 632 | leaves: | ||
| 633 | ; (s >= num_last) | ||
| 634 | jne exit_2 | ||
| 635 | single: | ||
| 636 | ; (s == num_last) | ||
| 637 | mov t0, [p + k * 8] | ||
| 638 | cmp qq, t0 | ||
| 639 | jae exit_2 | ||
| 640 | STORE t0, k | ||
| 641 | mov k, s | ||
| 642 | jmp exit_2 | ||
| 643 | |||
| 644 | MY_ALIGN_16 | ||
| 645 | opt_loop: | ||
| 646 | STEP exit_2 | ||
| 647 | cmp s, num_last | ||
| 648 | jb opt_loop | ||
| 649 | je single | ||
| 650 | exit_2: | ||
| 651 | STORE qq, k | ||
| 652 | endm | ||
| 653 | |||
| 654 | |||
| 655 | |||
| 656 | |||
| 657 | ifdef Z7_SORT_ASM_USE_SEGMENT | ||
| 658 | ; MY_ALIGN_64 | ||
| 659 | else | ||
| 660 | MY_ALIGN_16 | ||
| 661 | endif | ||
| 662 | |||
| 663 | MY_PROC HeapSort, 2 | ||
| 664 | ifdef x64 | ||
| 665 | if (IS_LINUX gt 0) | ||
| 666 | mov num_last, REG_ABI_PARAM_1 ; r2 <- r6 : linux | ||
| 667 | mov p, REG_ABI_PARAM_0 ; r1 <- r7 : linux | ||
| 668 | endif | ||
| 669 | elseif (IS_CDECL gt 0) | ||
| 670 | mov num_last, [r4 + REG_SIZE * 2] | ||
| 671 | mov p, [r4 + REG_SIZE * 1] | ||
| 672 | endif | ||
| 673 | cmp num_last, 2 | ||
| 674 | jb end_1 | ||
| 675 | MY_PUSH_PRESERVED_ABI_REGS_UP_TO_INCLUDING_R11 | ||
| 676 | |||
| 677 | cmp num_last, 4 | ||
| 678 | ja sort_5 | ||
| 679 | |||
| 680 | LOAD a0, 0 | ||
| 681 | LOAD a1, 1 | ||
| 682 | SORT a0, a1 | ||
| 683 | cmp num_last, 3 | ||
| 684 | jb end_2 | ||
| 685 | |||
| 686 | LOAD a2, 2 | ||
| 687 | je sort_3 | ||
| 688 | |||
| 689 | LOAD a3, 3 | ||
| 690 | SORT a2, a3 | ||
| 691 | SORT a1, a3 | ||
| 692 | STORE a3, 3 | ||
| 693 | sort_3: | ||
| 694 | SORT a0, a2 | ||
| 695 | SORT a1, a2 | ||
| 696 | STORE a2, 2 | ||
| 697 | jmp end_2 | ||
| 698 | |||
| 699 | sort_5: | ||
| 700 | ; num_last > 4 | ||
| 701 | lea i, dword ptr [num_last - 2] | ||
| 702 | dec num_last | ||
| 703 | test i, 1 | ||
| 704 | jz loop_down | ||
| 705 | |||
| 706 | ; single child | ||
| 707 | mov t0, [p + num_last * 4] | ||
| 708 | mov qq, [p + num_last * 2] | ||
| 709 | dec i | ||
| 710 | cmp qq, t0 | ||
| 711 | jae loop_down | ||
| 712 | |||
| 713 | mov [p + num_last * 2], t0 | ||
| 714 | mov [p + num_last * 4], qq | ||
| 715 | |||
| 716 | MY_ALIGN_16 | ||
| 717 | loop_down: | ||
| 718 | mov t0, [p + i * 4] | ||
| 719 | cmp t0, [p + i * 4 + 4] | ||
| 720 | mov k, i | ||
| 721 | mov qq, [p + i * 2] | ||
| 722 | adc k, 0 | ||
| 723 | LOAD t0, k | ||
| 724 | cmp qq, t0 | ||
| 725 | jae down_next | ||
| 726 | mov [p + i * 2], t0 | ||
| 727 | lea s, dword ptr [k + k] | ||
| 728 | |||
| 729 | DOWN_num_unrolls equ 0 | ||
| 730 | MOVE_SMALLEST_UP STEP_1, DOWN_num_unrolls, down_exit_label | ||
| 731 | down_next: | ||
| 732 | sub i, 2 | ||
| 733 | jnb loop_down | ||
| 734 | ; jmp end_debug | ||
| 735 | |||
| 736 | LOAD e0, 0 | ||
| 737 | |||
| 738 | MY_ALIGN_16 | ||
| 739 | main_loop_sort: | ||
| 740 | ; num_last > 3 | ||
| 741 | mov t0, [p + 2 * 4] | ||
| 742 | cmp t0, [p + 3 * 4] | ||
| 743 | LOAD qq, num_last | ||
| 744 | STORE e0, num_last | ||
| 745 | LOAD e0, 1 | ||
| 746 | mov s_x, 2 | ||
| 747 | mov k_x, 1 | ||
| 748 | adc s, 0 | ||
| 749 | LOAD t0, s | ||
| 750 | dec num_last | ||
| 751 | cmp qq, t0 | ||
| 752 | jae main_exit_label | ||
| 753 | STORE t0, 1 | ||
| 754 | mov k, s | ||
| 755 | add s, s | ||
| 756 | if 1 | ||
| 757 | ; for branch data prefetch mode : | ||
| 758 | ; it's faster for large arrays : larger than (1 << 13) items. | ||
| 759 | MAIN_num_unrolls equ 10 | ||
| 760 | STEP_LOOP equ STEP_BRANCH | ||
| 761 | else | ||
| 762 | MAIN_num_unrolls equ 0 | ||
| 763 | STEP_LOOP equ STEP_1 | ||
| 764 | endif | ||
| 765 | |||
| 766 | MOVE_SMALLEST_UP STEP_LOOP, MAIN_num_unrolls, main_exit_label | ||
| 767 | |||
| 768 | ; jmp end_debug | ||
| 769 | cmp num_last, 3 | ||
| 770 | jne main_loop_sort | ||
| 771 | |||
| 772 | ; num_last == 3 (real_size == 4) | ||
| 773 | LOAD a0, 2 | ||
| 774 | LOAD a1, 3 | ||
| 775 | LOAD a2, 1 | ||
| 776 | STORE e0, 3 ; e0 is alias for a3 | ||
| 777 | STORE a2, 2 | ||
| 778 | SORT a0, a1 | ||
| 779 | end_2: | ||
| 780 | STORE a0, 0 | ||
| 781 | STORE a1, 1 | ||
| 782 | ; end_debug: | ||
| 783 | MY_POP_PRESERVED_ABI_REGS_UP_TO_INCLUDING_R11 | ||
| 784 | end_1: | ||
| 785 | MY_ENDP | ||
| 786 | |||
| 787 | endif | ||
| 788 | |||
| 789 | ifdef Z7_SORT_ASM_USE_SEGMENT | ||
| 790 | _TEXT$Z7_SORT ENDS | ||
| 791 | endif | ||
| 792 | |||
| 793 | if 0 | ||
| 794 | LEA_IS_D8 (R64) [R2 * 4 + 16] | ||
| 795 | Lat : TP | ||
| 796 | 2 : 1 : adl-e | ||
| 797 | 2 : 3 p056 adl-p | ||
| 798 | 1 : 2 : p15 hsw-rocket | ||
| 799 | 1 : 2 : p01 snb-ivb | ||
| 800 | 1 : 1 : p1 conroe-wsm | ||
| 801 | 1 : 4 : zen3,zen4 | ||
| 802 | 2 : 4 : zen1,zen2 | ||
| 803 | |||
| 804 | LEA_B_IS (R64) [R2 + R3 * 4] | ||
| 805 | Lat : TP | ||
| 806 | 1 : 1 : adl-e | ||
| 807 | 2 : 3 p056 adl-p | ||
| 808 | 1 : 2 : p15 hsw-rocket | ||
| 809 | 1 : 2 : p01 snb-ivb | ||
| 810 | 1 : 1 : p1 nhm-wsm | ||
| 811 | 1 : 1 : p0 conroe-wsm | ||
| 812 | 1 : 4 : zen3,zen4 | ||
| 813 | 2 :2,4 : zen1,zen2 | ||
| 814 | |||
| 815 | LEA_B_IS_D8 (R64) [R2 + R3 * 4 + 16] | ||
| 816 | Lat : TP | ||
| 817 | 2 : 1 : adl-e | ||
| 818 | 2 : 3 p056 adl-p | ||
| 819 | 1 : 2 : p15 ice-rocket | ||
| 820 | 3 : 1 : p1/p15 hsw-rocket | ||
| 821 | 3 : 1 : p01 snb-ivb | ||
| 822 | 1 : 1 : p1 nhm-wsm | ||
| 823 | 1 : 1 : p0 conroe-wsm | ||
| 824 | 2,1 : 2 : zen3,zen4 | ||
| 825 | 2 : 2 : zen1,zen2 | ||
| 826 | |||
| 827 | CMOVB (R64, R64) | ||
| 828 | Lat : TP | ||
| 829 | 1,2 : 2 : adl-e | ||
| 830 | 1 : 2 p06 adl-p | ||
| 831 | 1 : 2 : p06 bwd-rocket | ||
| 832 | 1,2 : 2 : p0156+p06 hsw | ||
| 833 | 1,2 :1.5 : p015+p05 snb-ivb | ||
| 834 | 1,2 : 1 : p015+p05 nhm | ||
| 835 | 1 : 1 : 2*p015 conroe | ||
| 836 | 1 : 2 : zen3,zen4 | ||
| 837 | 1 : 4 : zen1,zen2 | ||
| 838 | |||
| 839 | ADC (R64, 0) | ||
| 840 | Lat : TP | ||
| 841 | 1,2 : 2 : adl-e | ||
| 842 | 1 : 2 p06 adl-p | ||
| 843 | 1 : 2 : p06 bwd-rocket | ||
| 844 | 1 :1.5 : p0156+p06 hsw | ||
| 845 | 1 :1.5 : p015+p05 snb-ivb | ||
| 846 | 2 : 1 : 2*p015 conroe-wstm | ||
| 847 | 1 : 2 : zen1,zen2,zen3,zen4 | ||
| 848 | |||
| 849 | PREFETCHNTA : fetch data into non-temporal cache close to the processor, minimizing cache pollution. | ||
| 850 | L1 : Pentium3 | ||
| 851 | L2 : NetBurst | ||
| 852 | L1, not L2: Core duo, Core 2, Atom processors | ||
| 853 | L1, not L2, may fetch into L3 with fast replacement: Nehalem, Westmere, Sandy Bridge, ... | ||
| 854 | NEHALEM: Fills L1/L3, L1 LRU is not updated | ||
| 855 | L3 with fast replacement: Xeon Processors based on Nehalem, Westmere, Sandy Bridge, ... | ||
| 856 | PREFETCHT0 : fetch data into all cache levels. | ||
| 857 | PREFETCHT1 : fetch data into L2 and L3 | ||
| 858 | endif | ||
| 859 | |||
| 860 | end | ||
diff --git a/C/7zVersion.h b/C/7zVersion.h index e82ba0b..72733f7 100644 --- a/C/7zVersion.h +++ b/C/7zVersion.h | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | #define MY_VER_MAJOR 24 | 1 | #define MY_VER_MAJOR 25 |
| 2 | #define MY_VER_MINOR 9 | 2 | #define MY_VER_MINOR 0 |
| 3 | #define MY_VER_BUILD 0 | 3 | #define MY_VER_BUILD 0 |
| 4 | #define MY_VERSION_NUMBERS "24.09" | 4 | #define MY_VERSION_NUMBERS "25.00" |
| 5 | #define MY_VERSION MY_VERSION_NUMBERS | 5 | #define MY_VERSION MY_VERSION_NUMBERS |
| 6 | 6 | ||
| 7 | #ifdef MY_CPU_NAME | 7 | #ifdef MY_CPU_NAME |
| @@ -10,12 +10,12 @@ | |||
| 10 | #define MY_VERSION_CPU MY_VERSION | 10 | #define MY_VERSION_CPU MY_VERSION |
| 11 | #endif | 11 | #endif |
| 12 | 12 | ||
| 13 | #define MY_DATE "2024-11-29" | 13 | #define MY_DATE "2025-07-05" |
| 14 | #undef MY_COPYRIGHT | 14 | #undef MY_COPYRIGHT |
| 15 | #undef MY_VERSION_COPYRIGHT_DATE | 15 | #undef MY_VERSION_COPYRIGHT_DATE |
| 16 | #define MY_AUTHOR_NAME "Igor Pavlov" | 16 | #define MY_AUTHOR_NAME "Igor Pavlov" |
| 17 | #define MY_COPYRIGHT_PD "Igor Pavlov : Public domain" | 17 | #define MY_COPYRIGHT_PD "Igor Pavlov : Public domain" |
| 18 | #define MY_COPYRIGHT_CR "Copyright (c) 1999-2024 Igor Pavlov" | 18 | #define MY_COPYRIGHT_CR "Copyright (c) 1999-2025 Igor Pavlov" |
| 19 | 19 | ||
| 20 | #ifdef USE_COPYRIGHT_CR | 20 | #ifdef USE_COPYRIGHT_CR |
| 21 | #define MY_COPYRIGHT MY_COPYRIGHT_CR | 21 | #define MY_COPYRIGHT MY_COPYRIGHT_CR |
diff --git a/C/BwtSort.c b/C/BwtSort.c index 05ad6de..8f64f9d 100644 --- a/C/BwtSort.c +++ b/C/BwtSort.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* BwtSort.c -- BWT block sorting | 1 | /* BwtSort.c -- BWT block sorting |
| 2 | 2023-04-02 : Igor Pavlov : Public domain */ | 2 | : Igor Pavlov : Public domain */ |
| 3 | 3 | ||
| 4 | #include "Precomp.h" | 4 | #include "Precomp.h" |
| 5 | 5 | ||
| @@ -7,6 +7,44 @@ | |||
| 7 | #include "Sort.h" | 7 | #include "Sort.h" |
| 8 | 8 | ||
| 9 | /* #define BLOCK_SORT_USE_HEAP_SORT */ | 9 | /* #define BLOCK_SORT_USE_HEAP_SORT */ |
| 10 | // #define BLOCK_SORT_USE_HEAP_SORT | ||
| 11 | |||
| 12 | #ifdef BLOCK_SORT_USE_HEAP_SORT | ||
| 13 | |||
| 14 | #define HeapSortRefDown(p, vals, n, size, temp) \ | ||
| 15 | { size_t k = n; UInt32 val = vals[temp]; for (;;) { \ | ||
| 16 | size_t s = k << 1; \ | ||
| 17 | if (s > size) break; \ | ||
| 18 | if (s < size && vals[p[s + 1]] > vals[p[s]]) s++; \ | ||
| 19 | if (val >= vals[p[s]]) break; \ | ||
| 20 | p[k] = p[s]; k = s; \ | ||
| 21 | } p[k] = temp; } | ||
| 22 | |||
| 23 | void HeapSortRef(UInt32 *p, UInt32 *vals, size_t size) | ||
| 24 | { | ||
| 25 | if (size <= 1) | ||
| 26 | return; | ||
| 27 | p--; | ||
| 28 | { | ||
| 29 | size_t i = size / 2; | ||
| 30 | do | ||
| 31 | { | ||
| 32 | UInt32 temp = p[i]; | ||
| 33 | HeapSortRefDown(p, vals, i, size, temp); | ||
| 34 | } | ||
| 35 | while (--i != 0); | ||
| 36 | } | ||
| 37 | do | ||
| 38 | { | ||
| 39 | UInt32 temp = p[size]; | ||
| 40 | p[size--] = p[1]; | ||
| 41 | HeapSortRefDown(p, vals, 1, size, temp); | ||
| 42 | } | ||
| 43 | while (size > 1); | ||
| 44 | } | ||
| 45 | |||
| 46 | #endif // BLOCK_SORT_USE_HEAP_SORT | ||
| 47 | |||
| 10 | 48 | ||
| 11 | /* Don't change it !!! */ | 49 | /* Don't change it !!! */ |
| 12 | #define kNumHashBytes 2 | 50 | #define kNumHashBytes 2 |
| @@ -27,26 +65,27 @@ | |||
| 27 | 65 | ||
| 28 | #else | 66 | #else |
| 29 | 67 | ||
| 30 | #define kNumBitsMax 20 | 68 | #define kNumBitsMax 20 |
| 31 | #define kIndexMask ((1 << kNumBitsMax) - 1) | 69 | #define kIndexMask (((UInt32)1 << kNumBitsMax) - 1) |
| 32 | #define kNumExtraBits (32 - kNumBitsMax) | 70 | #define kNumExtraBits (32 - kNumBitsMax) |
| 33 | #define kNumExtra0Bits (kNumExtraBits - 2) | 71 | #define kNumExtra0Bits (kNumExtraBits - 2) |
| 34 | #define kNumExtra0Mask ((1 << kNumExtra0Bits) - 1) | 72 | #define kNumExtra0Mask ((1 << kNumExtra0Bits) - 1) |
| 35 | 73 | ||
| 36 | #define SetFinishedGroupSize(p, size) \ | 74 | #define SetFinishedGroupSize(p, size) \ |
| 37 | { *(p) |= ((((size) - 1) & kNumExtra0Mask) << kNumBitsMax); \ | 75 | { *(p) |= ((((UInt32)(size) - 1) & kNumExtra0Mask) << kNumBitsMax); \ |
| 38 | if ((size) > (1 << kNumExtra0Bits)) { \ | 76 | if ((size) > (1 << kNumExtra0Bits)) { \ |
| 39 | *(p) |= 0x40000000; *((p) + 1) |= ((((size) - 1)>> kNumExtra0Bits) << kNumBitsMax); } } \ | 77 | *(p) |= 0x40000000; \ |
| 78 | *((p) + 1) |= (((UInt32)(size) - 1) >> kNumExtra0Bits) << kNumBitsMax; } } \ | ||
| 40 | 79 | ||
| 41 | static void SetGroupSize(UInt32 *p, UInt32 size) | 80 | static void SetGroupSize(UInt32 *p, size_t size) |
| 42 | { | 81 | { |
| 43 | if (--size == 0) | 82 | if (--size == 0) |
| 44 | return; | 83 | return; |
| 45 | *p |= 0x80000000 | ((size & kNumExtra0Mask) << kNumBitsMax); | 84 | *p |= 0x80000000 | (((UInt32)size & kNumExtra0Mask) << kNumBitsMax); |
| 46 | if (size >= (1 << kNumExtra0Bits)) | 85 | if (size >= (1 << kNumExtra0Bits)) |
| 47 | { | 86 | { |
| 48 | *p |= 0x40000000; | 87 | *p |= 0x40000000; |
| 49 | p[1] |= ((size >> kNumExtra0Bits) << kNumBitsMax); | 88 | p[1] |= (((UInt32)size >> kNumExtra0Bits) << kNumBitsMax); |
| 50 | } | 89 | } |
| 51 | } | 90 | } |
| 52 | 91 | ||
| @@ -59,12 +98,14 @@ returns: 1 - if there are groups, 0 - no more groups | |||
| 59 | */ | 98 | */ |
| 60 | 99 | ||
| 61 | static | 100 | static |
| 62 | UInt32 | 101 | unsigned |
| 63 | Z7_FASTCALL | 102 | Z7_FASTCALL |
| 64 | SortGroup(UInt32 BlockSize, UInt32 NumSortedBytes, UInt32 groupOffset, UInt32 groupSize, int NumRefBits, UInt32 *Indices | 103 | SortGroup(size_t BlockSize, size_t NumSortedBytes, |
| 65 | #ifndef BLOCK_SORT_USE_HEAP_SORT | 104 | size_t groupOffset, size_t groupSize, |
| 66 | , UInt32 left, UInt32 range | 105 | unsigned NumRefBits, UInt32 *Indices |
| 67 | #endif | 106 | #ifndef BLOCK_SORT_USE_HEAP_SORT |
| 107 | , size_t left, size_t range | ||
| 108 | #endif | ||
| 68 | ) | 109 | ) |
| 69 | { | 110 | { |
| 70 | UInt32 *ind2 = Indices + groupOffset; | 111 | UInt32 *ind2 = Indices + groupOffset; |
| @@ -79,90 +120,93 @@ SortGroup(UInt32 BlockSize, UInt32 NumSortedBytes, UInt32 groupOffset, UInt32 gr | |||
| 79 | return 0; | 120 | return 0; |
| 80 | } | 121 | } |
| 81 | Groups = Indices + BlockSize + BS_TEMP_SIZE; | 122 | Groups = Indices + BlockSize + BS_TEMP_SIZE; |
| 82 | if (groupSize <= ((UInt32)1 << NumRefBits) | 123 | if (groupSize <= ((size_t)1 << NumRefBits) |
| 83 | #ifndef BLOCK_SORT_USE_HEAP_SORT | 124 | #ifndef BLOCK_SORT_USE_HEAP_SORT |
| 84 | && groupSize <= range | 125 | && groupSize <= range |
| 85 | #endif | 126 | #endif |
| 86 | ) | 127 | ) |
| 87 | { | 128 | { |
| 88 | UInt32 *temp = Indices + BlockSize; | 129 | UInt32 *temp = Indices + BlockSize; |
| 89 | UInt32 j; | 130 | size_t j, group; |
| 90 | UInt32 mask, thereAreGroups, group, cg; | 131 | UInt32 mask, cg; |
| 132 | unsigned thereAreGroups; | ||
| 91 | { | 133 | { |
| 92 | UInt32 gPrev; | 134 | UInt32 gPrev; |
| 93 | UInt32 gRes = 0; | 135 | UInt32 gRes = 0; |
| 94 | { | 136 | { |
| 95 | UInt32 sp = ind2[0] + NumSortedBytes; | 137 | size_t sp = ind2[0] + NumSortedBytes; |
| 96 | if (sp >= BlockSize) sp -= BlockSize; | 138 | if (sp >= BlockSize) |
| 139 | sp -= BlockSize; | ||
| 97 | gPrev = Groups[sp]; | 140 | gPrev = Groups[sp]; |
| 98 | temp[0] = (gPrev << NumRefBits); | 141 | temp[0] = gPrev << NumRefBits; |
| 99 | } | 142 | } |
| 100 | 143 | ||
| 101 | for (j = 1; j < groupSize; j++) | 144 | for (j = 1; j < groupSize; j++) |
| 102 | { | 145 | { |
| 103 | UInt32 sp = ind2[j] + NumSortedBytes; | 146 | size_t sp = ind2[j] + NumSortedBytes; |
| 104 | UInt32 g; | 147 | UInt32 g; |
| 105 | if (sp >= BlockSize) sp -= BlockSize; | 148 | if (sp >= BlockSize) |
| 149 | sp -= BlockSize; | ||
| 106 | g = Groups[sp]; | 150 | g = Groups[sp]; |
| 107 | temp[j] = (g << NumRefBits) | j; | 151 | temp[j] = (g << NumRefBits) | (UInt32)j; |
| 108 | gRes |= (gPrev ^ g); | 152 | gRes |= (gPrev ^ g); |
| 109 | } | 153 | } |
| 110 | if (gRes == 0) | 154 | if (gRes == 0) |
| 111 | { | 155 | { |
| 112 | #ifndef BLOCK_SORT_EXTERNAL_FLAGS | 156 | #ifndef BLOCK_SORT_EXTERNAL_FLAGS |
| 113 | SetGroupSize(ind2, groupSize); | 157 | SetGroupSize(ind2, groupSize); |
| 114 | #endif | 158 | #endif |
| 115 | return 1; | 159 | return 1; |
| 116 | } | 160 | } |
| 117 | } | 161 | } |
| 118 | 162 | ||
| 119 | HeapSort(temp, groupSize); | 163 | HeapSort(temp, groupSize); |
| 120 | mask = (((UInt32)1 << NumRefBits) - 1); | 164 | mask = ((UInt32)1 << NumRefBits) - 1; |
| 121 | thereAreGroups = 0; | 165 | thereAreGroups = 0; |
| 122 | 166 | ||
| 123 | group = groupOffset; | 167 | group = groupOffset; |
| 124 | cg = (temp[0] >> NumRefBits); | 168 | cg = temp[0] >> NumRefBits; |
| 125 | temp[0] = ind2[temp[0] & mask]; | 169 | temp[0] = ind2[temp[0] & mask]; |
| 126 | 170 | ||
| 127 | { | 171 | { |
| 128 | #ifdef BLOCK_SORT_EXTERNAL_FLAGS | 172 | #ifdef BLOCK_SORT_EXTERNAL_FLAGS |
| 129 | UInt32 *Flags = Groups + BlockSize; | 173 | UInt32 *Flags = Groups + BlockSize; |
| 130 | #else | 174 | #else |
| 131 | UInt32 prevGroupStart = 0; | 175 | size_t prevGroupStart = 0; |
| 132 | #endif | 176 | #endif |
| 133 | 177 | ||
| 134 | for (j = 1; j < groupSize; j++) | 178 | for (j = 1; j < groupSize; j++) |
| 135 | { | 179 | { |
| 136 | UInt32 val = temp[j]; | 180 | const UInt32 val = temp[j]; |
| 137 | UInt32 cgCur = (val >> NumRefBits); | 181 | const UInt32 cgCur = val >> NumRefBits; |
| 138 | 182 | ||
| 139 | if (cgCur != cg) | 183 | if (cgCur != cg) |
| 140 | { | 184 | { |
| 141 | cg = cgCur; | 185 | cg = cgCur; |
| 142 | group = groupOffset + j; | 186 | group = groupOffset + j; |
| 143 | 187 | ||
| 144 | #ifdef BLOCK_SORT_EXTERNAL_FLAGS | 188 | #ifdef BLOCK_SORT_EXTERNAL_FLAGS |
| 145 | { | 189 | { |
| 146 | UInt32 t = group - 1; | 190 | const size_t t = group - 1; |
| 147 | Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask)); | 191 | Flags[t >> kNumFlagsBits] &= ~((UInt32)1 << (t & kFlagsMask)); |
| 148 | } | 192 | } |
| 149 | #else | 193 | #else |
| 150 | SetGroupSize(temp + prevGroupStart, j - prevGroupStart); | 194 | SetGroupSize(temp + prevGroupStart, j - prevGroupStart); |
| 151 | prevGroupStart = j; | 195 | prevGroupStart = j; |
| 152 | #endif | 196 | #endif |
| 153 | } | 197 | } |
| 154 | else | 198 | else |
| 155 | thereAreGroups = 1; | 199 | thereAreGroups = 1; |
| 156 | { | 200 | { |
| 157 | UInt32 ind = ind2[val & mask]; | 201 | const UInt32 ind = ind2[val & mask]; |
| 158 | temp[j] = ind; | 202 | temp[j] = ind; |
| 159 | Groups[ind] = group; | 203 | Groups[ind] = (UInt32)group; |
| 160 | } | 204 | } |
| 161 | } | 205 | } |
| 162 | 206 | ||
| 163 | #ifndef BLOCK_SORT_EXTERNAL_FLAGS | 207 | #ifndef BLOCK_SORT_EXTERNAL_FLAGS |
| 164 | SetGroupSize(temp + prevGroupStart, j - prevGroupStart); | 208 | SetGroupSize(temp + prevGroupStart, j - prevGroupStart); |
| 165 | #endif | 209 | #endif |
| 166 | } | 210 | } |
| 167 | 211 | ||
| 168 | for (j = 0; j < groupSize; j++) | 212 | for (j = 0; j < groupSize; j++) |
| @@ -172,37 +216,42 @@ SortGroup(UInt32 BlockSize, UInt32 NumSortedBytes, UInt32 groupOffset, UInt32 gr | |||
| 172 | 216 | ||
| 173 | /* Check that all strings are in one group (cannot sort) */ | 217 | /* Check that all strings are in one group (cannot sort) */ |
| 174 | { | 218 | { |
| 175 | UInt32 group, j; | 219 | UInt32 group; |
| 176 | UInt32 sp = ind2[0] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize; | 220 | size_t j; |
| 221 | size_t sp = ind2[0] + NumSortedBytes; | ||
| 222 | if (sp >= BlockSize) | ||
| 223 | sp -= BlockSize; | ||
| 177 | group = Groups[sp]; | 224 | group = Groups[sp]; |
| 178 | for (j = 1; j < groupSize; j++) | 225 | for (j = 1; j < groupSize; j++) |
| 179 | { | 226 | { |
| 180 | sp = ind2[j] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize; | 227 | sp = ind2[j] + NumSortedBytes; |
| 228 | if (sp >= BlockSize) | ||
| 229 | sp -= BlockSize; | ||
| 181 | if (Groups[sp] != group) | 230 | if (Groups[sp] != group) |
| 182 | break; | 231 | break; |
| 183 | } | 232 | } |
| 184 | if (j == groupSize) | 233 | if (j == groupSize) |
| 185 | { | 234 | { |
| 186 | #ifndef BLOCK_SORT_EXTERNAL_FLAGS | 235 | #ifndef BLOCK_SORT_EXTERNAL_FLAGS |
| 187 | SetGroupSize(ind2, groupSize); | 236 | SetGroupSize(ind2, groupSize); |
| 188 | #endif | 237 | #endif |
| 189 | return 1; | 238 | return 1; |
| 190 | } | 239 | } |
| 191 | } | 240 | } |
| 192 | 241 | ||
| 193 | #ifndef BLOCK_SORT_USE_HEAP_SORT | 242 | #ifndef BLOCK_SORT_USE_HEAP_SORT |
| 194 | { | 243 | { |
| 195 | /* ---------- Range Sort ---------- */ | 244 | /* ---------- Range Sort ---------- */ |
| 196 | UInt32 i; | 245 | size_t i; |
| 197 | UInt32 mid; | 246 | size_t mid; |
| 198 | for (;;) | 247 | for (;;) |
| 199 | { | 248 | { |
| 200 | UInt32 j; | 249 | size_t j; |
| 201 | if (range <= 1) | 250 | if (range <= 1) |
| 202 | { | 251 | { |
| 203 | #ifndef BLOCK_SORT_EXTERNAL_FLAGS | 252 | #ifndef BLOCK_SORT_EXTERNAL_FLAGS |
| 204 | SetGroupSize(ind2, groupSize); | 253 | SetGroupSize(ind2, groupSize); |
| 205 | #endif | 254 | #endif |
| 206 | return 1; | 255 | return 1; |
| 207 | } | 256 | } |
| 208 | mid = left + ((range + 1) >> 1); | 257 | mid = left + ((range + 1) >> 1); |
| @@ -210,7 +259,7 @@ SortGroup(UInt32 BlockSize, UInt32 NumSortedBytes, UInt32 groupOffset, UInt32 gr | |||
| 210 | i = 0; | 259 | i = 0; |
| 211 | do | 260 | do |
| 212 | { | 261 | { |
| 213 | UInt32 sp = ind2[i] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize; | 262 | size_t sp = ind2[i] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize; |
| 214 | if (Groups[sp] >= mid) | 263 | if (Groups[sp] >= mid) |
| 215 | { | 264 | { |
| 216 | for (j--; j > i; j--) | 265 | for (j--; j > i; j--) |
| @@ -238,51 +287,53 @@ SortGroup(UInt32 BlockSize, UInt32 NumSortedBytes, UInt32 groupOffset, UInt32 gr | |||
| 238 | break; | 287 | break; |
| 239 | } | 288 | } |
| 240 | 289 | ||
| 241 | #ifdef BLOCK_SORT_EXTERNAL_FLAGS | 290 | #ifdef BLOCK_SORT_EXTERNAL_FLAGS |
| 242 | { | 291 | { |
| 243 | UInt32 t = (groupOffset + i - 1); | 292 | const size_t t = groupOffset + i - 1; |
| 244 | UInt32 *Flags = Groups + BlockSize; | 293 | UInt32 *Flags = Groups + BlockSize; |
| 245 | Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask)); | 294 | Flags[t >> kNumFlagsBits] &= ~((UInt32)1 << (t & kFlagsMask)); |
| 246 | } | 295 | } |
| 247 | #endif | 296 | #endif |
| 248 | 297 | ||
| 249 | { | 298 | { |
| 250 | UInt32 j; | 299 | size_t j; |
| 251 | for (j = i; j < groupSize; j++) | 300 | for (j = i; j < groupSize; j++) |
| 252 | Groups[ind2[j]] = groupOffset + i; | 301 | Groups[ind2[j]] = (UInt32)(groupOffset + i); |
| 253 | } | 302 | } |
| 254 | 303 | ||
| 255 | { | 304 | { |
| 256 | UInt32 res = SortGroup(BlockSize, NumSortedBytes, groupOffset, i, NumRefBits, Indices, left, mid - left); | 305 | unsigned res = SortGroup(BlockSize, NumSortedBytes, groupOffset, i, NumRefBits, Indices, left, mid - left); |
| 257 | return res | SortGroup(BlockSize, NumSortedBytes, groupOffset + i, groupSize - i, NumRefBits, Indices, mid, range - (mid - left)); | 306 | return res | SortGroup(BlockSize, NumSortedBytes, groupOffset + i, groupSize - i, NumRefBits, Indices, mid, range - (mid - left)); |
| 258 | } | 307 | } |
| 259 | 308 | ||
| 260 | } | 309 | } |
| 261 | 310 | ||
| 262 | #else | 311 | #else // BLOCK_SORT_USE_HEAP_SORT |
| 263 | 312 | ||
| 264 | /* ---------- Heap Sort ---------- */ | 313 | /* ---------- Heap Sort ---------- */ |
| 265 | 314 | ||
| 266 | { | 315 | { |
| 267 | UInt32 j; | 316 | size_t j; |
| 268 | for (j = 0; j < groupSize; j++) | 317 | for (j = 0; j < groupSize; j++) |
| 269 | { | 318 | { |
| 270 | UInt32 sp = ind2[j] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize; | 319 | size_t sp = ind2[j] + NumSortedBytes; |
| 271 | ind2[j] = sp; | 320 | if (sp >= BlockSize) |
| 321 | sp -= BlockSize; | ||
| 322 | ind2[j] = (UInt32)sp; | ||
| 272 | } | 323 | } |
| 273 | 324 | ||
| 274 | HeapSortRef(ind2, Groups, groupSize); | 325 | HeapSortRef(ind2, Groups, groupSize); |
| 275 | 326 | ||
| 276 | /* Write Flags */ | 327 | /* Write Flags */ |
| 277 | { | 328 | { |
| 278 | UInt32 sp = ind2[0]; | 329 | size_t sp = ind2[0]; |
| 279 | UInt32 group = Groups[sp]; | 330 | UInt32 group = Groups[sp]; |
| 280 | 331 | ||
| 281 | #ifdef BLOCK_SORT_EXTERNAL_FLAGS | 332 | #ifdef BLOCK_SORT_EXTERNAL_FLAGS |
| 282 | UInt32 *Flags = Groups + BlockSize; | 333 | UInt32 *Flags = Groups + BlockSize; |
| 283 | #else | 334 | #else |
| 284 | UInt32 prevGroupStart = 0; | 335 | size_t prevGroupStart = 0; |
| 285 | #endif | 336 | #endif |
| 286 | 337 | ||
| 287 | for (j = 1; j < groupSize; j++) | 338 | for (j = 1; j < groupSize; j++) |
| 288 | { | 339 | { |
| @@ -290,149 +341,210 @@ SortGroup(UInt32 BlockSize, UInt32 NumSortedBytes, UInt32 groupOffset, UInt32 gr | |||
| 290 | if (Groups[sp] != group) | 341 | if (Groups[sp] != group) |
| 291 | { | 342 | { |
| 292 | group = Groups[sp]; | 343 | group = Groups[sp]; |
| 293 | #ifdef BLOCK_SORT_EXTERNAL_FLAGS | 344 | #ifdef BLOCK_SORT_EXTERNAL_FLAGS |
| 294 | { | 345 | { |
| 295 | UInt32 t = groupOffset + j - 1; | 346 | const size_t t = groupOffset + j - 1; |
| 296 | Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask)); | 347 | Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask)); |
| 297 | } | 348 | } |
| 298 | #else | 349 | #else |
| 299 | SetGroupSize(ind2 + prevGroupStart, j - prevGroupStart); | 350 | SetGroupSize(ind2 + prevGroupStart, j - prevGroupStart); |
| 300 | prevGroupStart = j; | 351 | prevGroupStart = j; |
| 301 | #endif | 352 | #endif |
| 302 | } | 353 | } |
| 303 | } | 354 | } |
| 304 | 355 | ||
| 305 | #ifndef BLOCK_SORT_EXTERNAL_FLAGS | 356 | #ifndef BLOCK_SORT_EXTERNAL_FLAGS |
| 306 | SetGroupSize(ind2 + prevGroupStart, j - prevGroupStart); | 357 | SetGroupSize(ind2 + prevGroupStart, j - prevGroupStart); |
| 307 | #endif | 358 | #endif |
| 308 | } | 359 | } |
| 309 | { | 360 | { |
| 310 | /* Write new Groups values and Check that there are groups */ | 361 | /* Write new Groups values and Check that there are groups */ |
| 311 | UInt32 thereAreGroups = 0; | 362 | unsigned thereAreGroups = 0; |
| 312 | for (j = 0; j < groupSize; j++) | 363 | for (j = 0; j < groupSize; j++) |
| 313 | { | 364 | { |
| 314 | UInt32 group = groupOffset + j; | 365 | size_t group = groupOffset + j; |
| 315 | #ifndef BLOCK_SORT_EXTERNAL_FLAGS | 366 | #ifndef BLOCK_SORT_EXTERNAL_FLAGS |
| 316 | UInt32 subGroupSize = ((ind2[j] & ~0xC0000000) >> kNumBitsMax); | 367 | UInt32 subGroupSize = ((ind2[j] & ~0xC0000000) >> kNumBitsMax); |
| 317 | if ((ind2[j] & 0x40000000) != 0) | 368 | if (ind2[j] & 0x40000000) |
| 318 | subGroupSize += ((ind2[(size_t)j + 1] >> kNumBitsMax) << kNumExtra0Bits); | 369 | subGroupSize += ((ind2[(size_t)j + 1] >> kNumBitsMax) << kNumExtra0Bits); |
| 319 | subGroupSize++; | 370 | subGroupSize++; |
| 320 | for (;;) | 371 | for (;;) |
| 321 | { | 372 | { |
| 322 | UInt32 original = ind2[j]; | 373 | const UInt32 original = ind2[j]; |
| 323 | UInt32 sp = original & kIndexMask; | 374 | size_t sp = original & kIndexMask; |
| 324 | if (sp < NumSortedBytes) sp += BlockSize; sp -= NumSortedBytes; | 375 | if (sp < NumSortedBytes) |
| 325 | ind2[j] = sp | (original & ~kIndexMask); | 376 | sp += BlockSize; |
| 326 | Groups[sp] = group; | 377 | sp -= NumSortedBytes; |
| 378 | ind2[j] = (UInt32)sp | (original & ~kIndexMask); | ||
| 379 | Groups[sp] = (UInt32)group; | ||
| 327 | if (--subGroupSize == 0) | 380 | if (--subGroupSize == 0) |
| 328 | break; | 381 | break; |
| 329 | j++; | 382 | j++; |
| 330 | thereAreGroups = 1; | 383 | thereAreGroups = 1; |
| 331 | } | 384 | } |
| 332 | #else | 385 | #else |
| 333 | UInt32 *Flags = Groups + BlockSize; | 386 | UInt32 *Flags = Groups + BlockSize; |
| 334 | for (;;) | 387 | for (;;) |
| 335 | { | 388 | { |
| 336 | UInt32 sp = ind2[j]; if (sp < NumSortedBytes) sp += BlockSize; sp -= NumSortedBytes; | 389 | size_t sp = ind2[j]; |
| 337 | ind2[j] = sp; | 390 | if (sp < NumSortedBytes) |
| 338 | Groups[sp] = group; | 391 | sp += BlockSize; |
| 392 | sp -= NumSortedBytes; | ||
| 393 | ind2[j] = (UInt32)sp; | ||
| 394 | Groups[sp] = (UInt32)group; | ||
| 339 | if ((Flags[(groupOffset + j) >> kNumFlagsBits] & (1 << ((groupOffset + j) & kFlagsMask))) == 0) | 395 | if ((Flags[(groupOffset + j) >> kNumFlagsBits] & (1 << ((groupOffset + j) & kFlagsMask))) == 0) |
| 340 | break; | 396 | break; |
| 341 | j++; | 397 | j++; |
| 342 | thereAreGroups = 1; | 398 | thereAreGroups = 1; |
| 343 | } | 399 | } |
| 344 | #endif | 400 | #endif |
| 345 | } | 401 | } |
| 346 | return thereAreGroups; | 402 | return thereAreGroups; |
| 347 | } | 403 | } |
| 348 | } | 404 | } |
| 349 | #endif | 405 | #endif // BLOCK_SORT_USE_HEAP_SORT |
| 350 | } | 406 | } |
| 351 | 407 | ||
| 408 | |||
| 352 | /* conditions: blockSize > 0 */ | 409 | /* conditions: blockSize > 0 */ |
| 353 | UInt32 BlockSort(UInt32 *Indices, const Byte *data, UInt32 blockSize) | 410 | UInt32 BlockSort(UInt32 *Indices, const Byte *data, size_t blockSize) |
| 354 | { | 411 | { |
| 355 | UInt32 *counters = Indices + blockSize; | 412 | UInt32 *counters = Indices + blockSize; |
| 356 | UInt32 i; | 413 | size_t i; |
| 357 | UInt32 *Groups; | 414 | UInt32 *Groups; |
| 358 | #ifdef BLOCK_SORT_EXTERNAL_FLAGS | 415 | #ifdef BLOCK_SORT_EXTERNAL_FLAGS |
| 359 | UInt32 *Flags; | 416 | UInt32 *Flags; |
| 360 | #endif | 417 | #endif |
| 361 | 418 | ||
| 362 | /* Radix-Sort for 2 bytes */ | 419 | /* Radix-Sort for 2 bytes */ |
| 420 | // { UInt32 yyy; for (yyy = 0; yyy < 100; yyy++) { | ||
| 363 | for (i = 0; i < kNumHashValues; i++) | 421 | for (i = 0; i < kNumHashValues; i++) |
| 364 | counters[i] = 0; | 422 | counters[i] = 0; |
| 365 | for (i = 0; i < blockSize - 1; i++) | 423 | { |
| 366 | counters[((UInt32)data[i] << 8) | data[(size_t)i + 1]]++; | 424 | const Byte *data2 = data; |
| 367 | counters[((UInt32)data[i] << 8) | data[0]]++; | 425 | size_t a = data[(size_t)blockSize - 1]; |
| 426 | const Byte *data_lim = data + blockSize; | ||
| 427 | if (blockSize >= 4) | ||
| 428 | { | ||
| 429 | data_lim -= 3; | ||
| 430 | do | ||
| 431 | { | ||
| 432 | size_t b; | ||
| 433 | b = data2[0]; counters[(a << 8) | b]++; | ||
| 434 | a = data2[1]; counters[(b << 8) | a]++; | ||
| 435 | b = data2[2]; counters[(a << 8) | b]++; | ||
| 436 | a = data2[3]; counters[(b << 8) | a]++; | ||
| 437 | data2 += 4; | ||
| 438 | } | ||
| 439 | while (data2 < data_lim); | ||
| 440 | data_lim += 3; | ||
| 441 | } | ||
| 442 | while (data2 != data_lim) | ||
| 443 | { | ||
| 444 | size_t b = *data2++; | ||
| 445 | counters[(a << 8) | b]++; | ||
| 446 | a = b; | ||
| 447 | } | ||
| 448 | } | ||
| 449 | // }} | ||
| 368 | 450 | ||
| 369 | Groups = counters + BS_TEMP_SIZE; | 451 | Groups = counters + BS_TEMP_SIZE; |
| 370 | #ifdef BLOCK_SORT_EXTERNAL_FLAGS | 452 | #ifdef BLOCK_SORT_EXTERNAL_FLAGS |
| 371 | Flags = Groups + blockSize; | 453 | Flags = Groups + blockSize; |
| 372 | { | 454 | { |
| 373 | UInt32 numWords = (blockSize + kFlagsMask) >> kNumFlagsBits; | 455 | const size_t numWords = (blockSize + kFlagsMask) >> kNumFlagsBits; |
| 374 | for (i = 0; i < numWords; i++) | 456 | for (i = 0; i < numWords; i++) |
| 375 | Flags[i] = kAllFlags; | 457 | Flags[i] = kAllFlags; |
| 376 | } | 458 | } |
| 377 | #endif | 459 | #endif |
| 378 | 460 | ||
| 379 | { | 461 | { |
| 380 | UInt32 sum = 0; | 462 | UInt32 sum = 0; |
| 381 | for (i = 0; i < kNumHashValues; i++) | 463 | for (i = 0; i < kNumHashValues; i++) |
| 382 | { | 464 | { |
| 383 | UInt32 groupSize = counters[i]; | 465 | const UInt32 groupSize = counters[i]; |
| 384 | if (groupSize > 0) | 466 | counters[i] = sum; |
| 467 | sum += groupSize; | ||
| 468 | #ifdef BLOCK_SORT_EXTERNAL_FLAGS | ||
| 469 | if (groupSize) | ||
| 385 | { | 470 | { |
| 386 | #ifdef BLOCK_SORT_EXTERNAL_FLAGS | 471 | const UInt32 t = sum - 1; |
| 387 | UInt32 t = sum + groupSize - 1; | 472 | Flags[t >> kNumFlagsBits] &= ~((UInt32)1 << (t & kFlagsMask)); |
| 388 | Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask)); | ||
| 389 | #endif | ||
| 390 | sum += groupSize; | ||
| 391 | } | 473 | } |
| 392 | counters[i] = sum - groupSize; | 474 | #endif |
| 393 | } | 475 | } |
| 476 | } | ||
| 394 | 477 | ||
| 395 | for (i = 0; i < blockSize - 1; i++) | 478 | for (i = 0; i < blockSize - 1; i++) |
| 396 | Groups[i] = counters[((UInt32)data[i] << 8) | data[(size_t)i + 1]]; | 479 | Groups[i] = counters[((unsigned)data[i] << 8) | data[(size_t)i + 1]]; |
| 397 | Groups[i] = counters[((UInt32)data[i] << 8) | data[0]]; | 480 | Groups[i] = counters[((unsigned)data[i] << 8) | data[0]]; |
| 481 | |||
| 482 | { | ||
| 483 | #define SET_Indices(a, b, i) \ | ||
| 484 | { UInt32 c; \ | ||
| 485 | a = (a << 8) | (b); \ | ||
| 486 | c = counters[a]; \ | ||
| 487 | Indices[c] = (UInt32)i++; \ | ||
| 488 | counters[a] = c + 1; \ | ||
| 489 | } | ||
| 398 | 490 | ||
| 399 | for (i = 0; i < blockSize - 1; i++) | 491 | size_t a = data[0]; |
| 400 | Indices[counters[((UInt32)data[i] << 8) | data[(size_t)i + 1]]++] = i; | 492 | const Byte *data_ptr = data + 1; |
| 401 | Indices[counters[((UInt32)data[i] << 8) | data[0]]++] = i; | 493 | i = 0; |
| 402 | 494 | if (blockSize >= 3) | |
| 403 | #ifndef BLOCK_SORT_EXTERNAL_FLAGS | 495 | { |
| 496 | blockSize -= 2; | ||
| 497 | do | ||
| 498 | { | ||
| 499 | size_t b; | ||
| 500 | b = data_ptr[0]; SET_Indices(a, b, i) | ||
| 501 | a = data_ptr[1]; SET_Indices(b, a, i) | ||
| 502 | data_ptr += 2; | ||
| 503 | } | ||
| 504 | while (i < blockSize); | ||
| 505 | blockSize += 2; | ||
| 506 | } | ||
| 507 | if (i < blockSize - 1) | ||
| 404 | { | 508 | { |
| 509 | SET_Indices(a, data[(size_t)i + 1], i) | ||
| 510 | a = (Byte)a; | ||
| 511 | } | ||
| 512 | SET_Indices(a, data[0], i) | ||
| 513 | } | ||
| 514 | |||
| 515 | #ifndef BLOCK_SORT_EXTERNAL_FLAGS | ||
| 516 | { | ||
| 405 | UInt32 prev = 0; | 517 | UInt32 prev = 0; |
| 406 | for (i = 0; i < kNumHashValues; i++) | 518 | for (i = 0; i < kNumHashValues; i++) |
| 407 | { | 519 | { |
| 408 | UInt32 prevGroupSize = counters[i] - prev; | 520 | const UInt32 prevGroupSize = counters[i] - prev; |
| 409 | if (prevGroupSize == 0) | 521 | if (prevGroupSize == 0) |
| 410 | continue; | 522 | continue; |
| 411 | SetGroupSize(Indices + prev, prevGroupSize); | 523 | SetGroupSize(Indices + prev, prevGroupSize); |
| 412 | prev = counters[i]; | 524 | prev = counters[i]; |
| 413 | } | 525 | } |
| 414 | } | ||
| 415 | #endif | ||
| 416 | } | 526 | } |
| 527 | #endif | ||
| 417 | 528 | ||
| 418 | { | 529 | { |
| 419 | int NumRefBits; | 530 | unsigned NumRefBits; |
| 420 | UInt32 NumSortedBytes; | 531 | size_t NumSortedBytes; |
| 421 | for (NumRefBits = 0; ((blockSize - 1) >> NumRefBits) != 0; NumRefBits++); | 532 | for (NumRefBits = 0; ((blockSize - 1) >> NumRefBits) != 0; NumRefBits++) |
| 533 | {} | ||
| 422 | NumRefBits = 32 - NumRefBits; | 534 | NumRefBits = 32 - NumRefBits; |
| 423 | if (NumRefBits > kNumRefBitsMax) | 535 | if (NumRefBits > kNumRefBitsMax) |
| 424 | NumRefBits = kNumRefBitsMax; | 536 | NumRefBits = kNumRefBitsMax; |
| 425 | 537 | ||
| 426 | for (NumSortedBytes = kNumHashBytes; ; NumSortedBytes <<= 1) | 538 | for (NumSortedBytes = kNumHashBytes; ; NumSortedBytes <<= 1) |
| 427 | { | 539 | { |
| 428 | #ifndef BLOCK_SORT_EXTERNAL_FLAGS | 540 | #ifndef BLOCK_SORT_EXTERNAL_FLAGS |
| 429 | UInt32 finishedGroupSize = 0; | 541 | size_t finishedGroupSize = 0; |
| 430 | #endif | 542 | #endif |
| 431 | UInt32 newLimit = 0; | 543 | size_t newLimit = 0; |
| 432 | for (i = 0; i < blockSize;) | 544 | for (i = 0; i < blockSize;) |
| 433 | { | 545 | { |
| 434 | UInt32 groupSize; | 546 | size_t groupSize; |
| 435 | #ifdef BLOCK_SORT_EXTERNAL_FLAGS | 547 | #ifdef BLOCK_SORT_EXTERNAL_FLAGS |
| 436 | 548 | ||
| 437 | if ((Flags[i >> kNumFlagsBits] & (1 << (i & kFlagsMask))) == 0) | 549 | if ((Flags[i >> kNumFlagsBits] & (1 << (i & kFlagsMask))) == 0) |
| 438 | { | 550 | { |
| @@ -441,56 +553,56 @@ UInt32 BlockSort(UInt32 *Indices, const Byte *data, UInt32 blockSize) | |||
| 441 | } | 553 | } |
| 442 | for (groupSize = 1; | 554 | for (groupSize = 1; |
| 443 | (Flags[(i + groupSize) >> kNumFlagsBits] & (1 << ((i + groupSize) & kFlagsMask))) != 0; | 555 | (Flags[(i + groupSize) >> kNumFlagsBits] & (1 << ((i + groupSize) & kFlagsMask))) != 0; |
| 444 | groupSize++); | 556 | groupSize++) |
| 445 | 557 | {} | |
| 446 | groupSize++; | 558 | groupSize++; |
| 447 | 559 | ||
| 448 | #else | 560 | #else |
| 449 | 561 | ||
| 450 | groupSize = ((Indices[i] & ~0xC0000000) >> kNumBitsMax); | 562 | groupSize = (Indices[i] & ~0xC0000000) >> kNumBitsMax; |
| 451 | { | 563 | { |
| 452 | BoolInt finishedGroup = ((Indices[i] & 0x80000000) == 0); | 564 | const BoolInt finishedGroup = ((Indices[i] & 0x80000000) == 0); |
| 453 | if ((Indices[i] & 0x40000000) != 0) | 565 | if (Indices[i] & 0x40000000) |
| 454 | { | ||
| 455 | groupSize += ((Indices[(size_t)i + 1] >> kNumBitsMax) << kNumExtra0Bits); | ||
| 456 | Indices[(size_t)i + 1] &= kIndexMask; | ||
| 457 | } | ||
| 458 | Indices[i] &= kIndexMask; | ||
| 459 | groupSize++; | ||
| 460 | if (finishedGroup || groupSize == 1) | ||
| 461 | { | ||
| 462 | Indices[i - finishedGroupSize] &= kIndexMask; | ||
| 463 | if (finishedGroupSize > 1) | ||
| 464 | Indices[(size_t)(i - finishedGroupSize) + 1] &= kIndexMask; | ||
| 465 | { | 566 | { |
| 466 | UInt32 newGroupSize = groupSize + finishedGroupSize; | 567 | groupSize += ((Indices[(size_t)i + 1] >> kNumBitsMax) << kNumExtra0Bits); |
| 467 | SetFinishedGroupSize(Indices + i - finishedGroupSize, newGroupSize) | 568 | Indices[(size_t)i + 1] &= kIndexMask; |
| 468 | finishedGroupSize = newGroupSize; | ||
| 469 | } | 569 | } |
| 470 | i += groupSize; | 570 | Indices[i] &= kIndexMask; |
| 471 | continue; | 571 | groupSize++; |
| 472 | } | 572 | if (finishedGroup || groupSize == 1) |
| 473 | finishedGroupSize = 0; | 573 | { |
| 574 | Indices[i - finishedGroupSize] &= kIndexMask; | ||
| 575 | if (finishedGroupSize > 1) | ||
| 576 | Indices[(size_t)(i - finishedGroupSize) + 1] &= kIndexMask; | ||
| 577 | { | ||
| 578 | const size_t newGroupSize = groupSize + finishedGroupSize; | ||
| 579 | SetFinishedGroupSize(Indices + i - finishedGroupSize, newGroupSize) | ||
| 580 | finishedGroupSize = newGroupSize; | ||
| 581 | } | ||
| 582 | i += groupSize; | ||
| 583 | continue; | ||
| 584 | } | ||
| 585 | finishedGroupSize = 0; | ||
| 474 | } | 586 | } |
| 475 | 587 | ||
| 476 | #endif | 588 | #endif |
| 477 | 589 | ||
| 478 | if (NumSortedBytes >= blockSize) | 590 | if (NumSortedBytes >= blockSize) |
| 479 | { | 591 | { |
| 480 | UInt32 j; | 592 | size_t j; |
| 481 | for (j = 0; j < groupSize; j++) | 593 | for (j = 0; j < groupSize; j++) |
| 482 | { | 594 | { |
| 483 | UInt32 t = (i + j); | 595 | size_t t = i + j; |
| 484 | /* Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask)); */ | 596 | /* Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask)); */ |
| 485 | Groups[Indices[t]] = t; | 597 | Groups[Indices[t]] = (UInt32)t; |
| 486 | } | 598 | } |
| 487 | } | 599 | } |
| 488 | else | 600 | else |
| 489 | if (SortGroup(blockSize, NumSortedBytes, i, groupSize, NumRefBits, Indices | 601 | if (SortGroup(blockSize, NumSortedBytes, i, groupSize, NumRefBits, Indices |
| 490 | #ifndef BLOCK_SORT_USE_HEAP_SORT | 602 | #ifndef BLOCK_SORT_USE_HEAP_SORT |
| 491 | , 0, blockSize | 603 | , 0, blockSize |
| 492 | #endif | 604 | #endif |
| 493 | ) != 0) | 605 | )) |
| 494 | newLimit = i + groupSize; | 606 | newLimit = i + groupSize; |
| 495 | i += groupSize; | 607 | i += groupSize; |
| 496 | } | 608 | } |
| @@ -498,19 +610,19 @@ UInt32 BlockSort(UInt32 *Indices, const Byte *data, UInt32 blockSize) | |||
| 498 | break; | 610 | break; |
| 499 | } | 611 | } |
| 500 | } | 612 | } |
| 501 | #ifndef BLOCK_SORT_EXTERNAL_FLAGS | 613 | #ifndef BLOCK_SORT_EXTERNAL_FLAGS |
| 502 | for (i = 0; i < blockSize;) | 614 | for (i = 0; i < blockSize;) |
| 503 | { | 615 | { |
| 504 | UInt32 groupSize = ((Indices[i] & ~0xC0000000) >> kNumBitsMax); | 616 | size_t groupSize = (Indices[i] & ~0xC0000000) >> kNumBitsMax; |
| 505 | if ((Indices[i] & 0x40000000) != 0) | 617 | if (Indices[i] & 0x40000000) |
| 506 | { | 618 | { |
| 507 | groupSize += ((Indices[(size_t)i + 1] >> kNumBitsMax) << kNumExtra0Bits); | 619 | groupSize += (Indices[(size_t)i + 1] >> kNumBitsMax) << kNumExtra0Bits; |
| 508 | Indices[(size_t)i + 1] &= kIndexMask; | 620 | Indices[(size_t)i + 1] &= kIndexMask; |
| 509 | } | 621 | } |
| 510 | Indices[i] &= kIndexMask; | 622 | Indices[i] &= kIndexMask; |
| 511 | groupSize++; | 623 | groupSize++; |
| 512 | i += groupSize; | 624 | i += groupSize; |
| 513 | } | 625 | } |
| 514 | #endif | 626 | #endif |
| 515 | return Groups[0]; | 627 | return Groups[0]; |
| 516 | } | 628 | } |
diff --git a/C/BwtSort.h b/C/BwtSort.h index a34b243..1bd2316 100644 --- a/C/BwtSort.h +++ b/C/BwtSort.h | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* BwtSort.h -- BWT block sorting | 1 | /* BwtSort.h -- BWT block sorting |
| 2 | 2023-03-03 : Igor Pavlov : Public domain */ | 2 | : Igor Pavlov : Public domain */ |
| 3 | 3 | ||
| 4 | #ifndef ZIP7_INC_BWT_SORT_H | 4 | #ifndef ZIP7_INC_BWT_SORT_H |
| 5 | #define ZIP7_INC_BWT_SORT_H | 5 | #define ZIP7_INC_BWT_SORT_H |
| @@ -10,16 +10,17 @@ EXTERN_C_BEGIN | |||
| 10 | 10 | ||
| 11 | /* use BLOCK_SORT_EXTERNAL_FLAGS if blockSize can be > 1M */ | 11 | /* use BLOCK_SORT_EXTERNAL_FLAGS if blockSize can be > 1M */ |
| 12 | /* #define BLOCK_SORT_EXTERNAL_FLAGS */ | 12 | /* #define BLOCK_SORT_EXTERNAL_FLAGS */ |
| 13 | // #define BLOCK_SORT_EXTERNAL_FLAGS | ||
| 13 | 14 | ||
| 14 | #ifdef BLOCK_SORT_EXTERNAL_FLAGS | 15 | #ifdef BLOCK_SORT_EXTERNAL_FLAGS |
| 15 | #define BLOCK_SORT_EXTERNAL_SIZE(blockSize) ((((blockSize) + 31) >> 5)) | 16 | #define BLOCK_SORT_EXTERNAL_SIZE(blockSize) (((blockSize) + 31) >> 5) |
| 16 | #else | 17 | #else |
| 17 | #define BLOCK_SORT_EXTERNAL_SIZE(blockSize) 0 | 18 | #define BLOCK_SORT_EXTERNAL_SIZE(blockSize) 0 |
| 18 | #endif | 19 | #endif |
| 19 | 20 | ||
| 20 | #define BLOCK_SORT_BUF_SIZE(blockSize) ((blockSize) * 2 + BLOCK_SORT_EXTERNAL_SIZE(blockSize) + (1 << 16)) | 21 | #define BLOCK_SORT_BUF_SIZE(blockSize) ((blockSize) * 2 + BLOCK_SORT_EXTERNAL_SIZE(blockSize) + (1 << 16)) |
| 21 | 22 | ||
| 22 | UInt32 BlockSort(UInt32 *indices, const Byte *data, UInt32 blockSize); | 23 | UInt32 BlockSort(UInt32 *indices, const Byte *data, size_t blockSize); |
| 23 | 24 | ||
| 24 | EXTERN_C_END | 25 | EXTERN_C_END |
| 25 | 26 | ||
diff --git a/C/Compiler.h b/C/Compiler.h index 2a9c2b7..b266b27 100644 --- a/C/Compiler.h +++ b/C/Compiler.h | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* Compiler.h : Compiler specific defines and pragmas | 1 | /* Compiler.h : Compiler specific defines and pragmas |
| 2 | 2024-01-22 : Igor Pavlov : Public domain */ | 2 | : Igor Pavlov : Public domain */ |
| 3 | 3 | ||
| 4 | #ifndef ZIP7_INC_COMPILER_H | 4 | #ifndef ZIP7_INC_COMPILER_H |
| 5 | #define ZIP7_INC_COMPILER_H | 5 | #define ZIP7_INC_COMPILER_H |
| @@ -183,6 +183,16 @@ typedef void (*Z7_void_Function)(void); | |||
| 183 | #define Z7_ATTRIB_NO_VECTORIZE | 183 | #define Z7_ATTRIB_NO_VECTORIZE |
| 184 | #endif | 184 | #endif |
| 185 | 185 | ||
| 186 | #if defined(Z7_MSC_VER_ORIGINAL) && (Z7_MSC_VER_ORIGINAL >= 1920) | ||
| 187 | #define Z7_PRAGMA_OPTIMIZE_FOR_CODE_SIZE _Pragma("optimize ( \"s\", on )") | ||
| 188 | #define Z7_PRAGMA_OPTIMIZE_DEFAULT _Pragma("optimize ( \"\", on )") | ||
| 189 | #else | ||
| 190 | #define Z7_PRAGMA_OPTIMIZE_FOR_CODE_SIZE | ||
| 191 | #define Z7_PRAGMA_OPTIMIZE_DEFAULT | ||
| 192 | #endif | ||
| 193 | |||
| 194 | |||
| 195 | |||
| 186 | #if defined(MY_CPU_X86_OR_AMD64) && ( \ | 196 | #if defined(MY_CPU_X86_OR_AMD64) && ( \ |
| 187 | defined(__clang__) && (__clang_major__ >= 4) \ | 197 | defined(__clang__) && (__clang_major__ >= 4) \ |
| 188 | || defined(__GNUC__) && (__GNUC__ >= 5)) | 198 | || defined(__GNUC__) && (__GNUC__ >= 5)) |
diff --git a/C/CpuArch.h b/C/CpuArch.h index a6297ea..1690a5b 100644 --- a/C/CpuArch.h +++ b/C/CpuArch.h | |||
| @@ -47,6 +47,12 @@ MY_CPU_64BIT means that processor can work with 64-bit registers. | |||
| 47 | #define MY_CPU_SIZEOF_POINTER 4 | 47 | #define MY_CPU_SIZEOF_POINTER 4 |
| 48 | #endif | 48 | #endif |
| 49 | 49 | ||
| 50 | #if defined(__SSE2__) \ | ||
| 51 | || defined(MY_CPU_AMD64) \ | ||
| 52 | || defined(_M_IX86_FP) && (_M_IX86_FP >= 2) | ||
| 53 | #define MY_CPU_SSE2 | ||
| 54 | #endif | ||
| 55 | |||
| 50 | 56 | ||
| 51 | #if defined(_M_ARM64) \ | 57 | #if defined(_M_ARM64) \ |
| 52 | || defined(_M_ARM64EC) \ | 58 | || defined(_M_ARM64EC) \ |
| @@ -571,10 +577,12 @@ problem-4 : performace: | |||
| 571 | #define Z7_CONV_BE_TO_NATIVE_CONST32(v) (v) | 577 | #define Z7_CONV_BE_TO_NATIVE_CONST32(v) (v) |
| 572 | #define Z7_CONV_LE_TO_NATIVE_CONST32(v) Z7_BSWAP32_CONST(v) | 578 | #define Z7_CONV_LE_TO_NATIVE_CONST32(v) Z7_BSWAP32_CONST(v) |
| 573 | #define Z7_CONV_NATIVE_TO_BE_32(v) (v) | 579 | #define Z7_CONV_NATIVE_TO_BE_32(v) (v) |
| 580 | // #define Z7_GET_NATIVE16_FROM_2_BYTES(b0, b1) ((b1) | ((b0) << 8)) | ||
| 574 | #elif defined(MY_CPU_LE) | 581 | #elif defined(MY_CPU_LE) |
| 575 | #define Z7_CONV_BE_TO_NATIVE_CONST32(v) Z7_BSWAP32_CONST(v) | 582 | #define Z7_CONV_BE_TO_NATIVE_CONST32(v) Z7_BSWAP32_CONST(v) |
| 576 | #define Z7_CONV_LE_TO_NATIVE_CONST32(v) (v) | 583 | #define Z7_CONV_LE_TO_NATIVE_CONST32(v) (v) |
| 577 | #define Z7_CONV_NATIVE_TO_BE_32(v) Z7_BSWAP32(v) | 584 | #define Z7_CONV_NATIVE_TO_BE_32(v) Z7_BSWAP32(v) |
| 585 | // #define Z7_GET_NATIVE16_FROM_2_BYTES(b0, b1) ((b0) | ((b1) << 8)) | ||
| 578 | #else | 586 | #else |
| 579 | #error Stop_Compiling_Unknown_Endian_CONV | 587 | #error Stop_Compiling_Unknown_Endian_CONV |
| 580 | #endif | 588 | #endif |
diff --git a/C/HuffEnc.c b/C/HuffEnc.c index 996da30..cbf8c22 100644 --- a/C/HuffEnc.c +++ b/C/HuffEnc.c | |||
| @@ -1,60 +1,125 @@ | |||
| 1 | /* HuffEnc.c -- functions for Huffman encoding | 1 | /* HuffEnc.c -- functions for Huffman encoding |
| 2 | 2023-09-07 : Igor Pavlov : Public domain */ | 2 | Igor Pavlov : Public domain */ |
| 3 | 3 | ||
| 4 | #include "Precomp.h" | 4 | #include "Precomp.h" |
| 5 | 5 | ||
| 6 | #include <string.h> | ||
| 7 | |||
| 6 | #include "HuffEnc.h" | 8 | #include "HuffEnc.h" |
| 7 | #include "Sort.h" | 9 | #include "Sort.h" |
| 10 | #include "CpuArch.h" | ||
| 8 | 11 | ||
| 9 | #define kMaxLen 16 | 12 | #define kMaxLen Z7_HUFFMAN_LEN_MAX |
| 10 | #define NUM_BITS 10 | 13 | #define NUM_BITS 10 |
| 11 | #define MASK ((1u << NUM_BITS) - 1) | 14 | #define MASK ((1u << NUM_BITS) - 1) |
| 12 | 15 | #define FREQ_MASK (~(UInt32)MASK) | |
| 13 | #define NUM_COUNTERS 64 | 16 | #define NUM_COUNTERS (48 * 2) |
| 14 | 17 | ||
| 15 | #define HUFFMAN_SPEED_OPT | 18 | #if 1 && (defined(MY_CPU_LE) || defined(MY_CPU_BE)) |
| 19 | #if defined(MY_CPU_LE) | ||
| 20 | #define HI_HALF_OFFSET 1 | ||
| 21 | #else | ||
| 22 | #define HI_HALF_OFFSET 0 | ||
| 23 | #endif | ||
| 24 | #define LOAD_PARENT(p) ((unsigned)*((const UInt16 *)(p) + HI_HALF_OFFSET)) | ||
| 25 | #define STORE_PARENT(p, fb, val) *((UInt16 *)(p) + HI_HALF_OFFSET) = (UInt16)(val); | ||
| 26 | #define STORE_PARENT_DIRECT(p, fb, hi) STORE_PARENT(p, fb, hi) | ||
| 27 | #define UPDATE_E(eHi) eHi++; | ||
| 28 | #else | ||
| 29 | #define LOAD_PARENT(p) ((unsigned)(*(p) >> NUM_BITS)) | ||
| 30 | #define STORE_PARENT_DIRECT(p, fb, hi) *(p) = ((fb) & MASK) | (hi); // set parent field | ||
| 31 | #define STORE_PARENT(p, fb, val) STORE_PARENT_DIRECT(p, fb, ((UInt32)(val) << NUM_BITS)) | ||
| 32 | #define UPDATE_E(eHi) eHi += 1 << NUM_BITS; | ||
| 33 | #endif | ||
| 16 | 34 | ||
| 17 | void Huffman_Generate(const UInt32 *freqs, UInt32 *p, Byte *lens, UInt32 numSymbols, UInt32 maxLen) | 35 | void Huffman_Generate(const UInt32 *freqs, UInt32 *p, Byte *lens, unsigned numSymbols, unsigned maxLen) |
| 18 | { | 36 | { |
| 19 | UInt32 num = 0; | 37 | #if NUM_COUNTERS > 2 |
| 20 | /* if (maxLen > 10) maxLen = 10; */ | 38 | unsigned counters[NUM_COUNTERS]; |
| 39 | #endif | ||
| 40 | #if 1 && NUM_COUNTERS > (kMaxLen + 4) * 2 | ||
| 41 | #define lenCounters (counters) | ||
| 42 | #define codes (counters + kMaxLen + 4) | ||
| 43 | #else | ||
| 44 | unsigned lenCounters[kMaxLen + 1]; | ||
| 45 | UInt32 codes[kMaxLen + 1]; | ||
| 46 | #endif | ||
| 47 | |||
| 48 | unsigned num; | ||
| 21 | { | 49 | { |
| 22 | UInt32 i; | 50 | unsigned i; |
| 23 | 51 | // UInt32 sum = 0; | |
| 24 | #ifdef HUFFMAN_SPEED_OPT | 52 | |
| 53 | #if NUM_COUNTERS > 2 | ||
| 25 | 54 | ||
| 26 | UInt32 counters[NUM_COUNTERS]; | 55 | #define CTR_ITEM_FOR_FREQ(freq) \ |
| 56 | counters[(freq) >= NUM_COUNTERS - 1 ? NUM_COUNTERS - 1 : (unsigned)(freq)] | ||
| 57 | |||
| 27 | for (i = 0; i < NUM_COUNTERS; i++) | 58 | for (i = 0; i < NUM_COUNTERS; i++) |
| 28 | counters[i] = 0; | 59 | counters[i] = 0; |
| 29 | for (i = 0; i < numSymbols; i++) | 60 | memset(lens, 0, numSymbols); |
| 30 | { | 61 | { |
| 31 | UInt32 freq = freqs[i]; | 62 | const UInt32 *fp = freqs + numSymbols; |
| 32 | counters[(freq < NUM_COUNTERS - 1) ? freq : NUM_COUNTERS - 1]++; | 63 | #define NUM_UNROLLS 1 |
| 64 | #if NUM_UNROLLS > 1 // use 1 if odd (numSymbols) is possisble | ||
| 65 | if (numSymbols & 1) | ||
| 66 | { | ||
| 67 | UInt32 f; | ||
| 68 | f = *--fp; CTR_ITEM_FOR_FREQ(f)++; | ||
| 69 | // sum += f; | ||
| 70 | } | ||
| 71 | #endif | ||
| 72 | do | ||
| 73 | { | ||
| 74 | UInt32 f; | ||
| 75 | fp -= NUM_UNROLLS; | ||
| 76 | f = fp[0]; CTR_ITEM_FOR_FREQ(f)++; | ||
| 77 | // sum += f; | ||
| 78 | #if NUM_UNROLLS > 1 | ||
| 79 | f = fp[1]; CTR_ITEM_FOR_FREQ(f)++; | ||
| 80 | // sum += f; | ||
| 81 | #endif | ||
| 82 | } | ||
| 83 | while (fp != freqs); | ||
| 33 | } | 84 | } |
| 34 | 85 | #if 0 | |
| 35 | for (i = 1; i < NUM_COUNTERS; i++) | 86 | printf("\nsum=%8u numSymbols =%3u ctrs:", sum, numSymbols); |
| 36 | { | 87 | { |
| 37 | UInt32 temp = counters[i]; | 88 | unsigned k = 0; |
| 38 | counters[i] = num; | 89 | for (k = 0; k < NUM_COUNTERS; k++) |
| 39 | num += temp; | 90 | printf(" %u", counters[k]); |
| 40 | } | 91 | } |
| 41 | 92 | #endif | |
| 42 | for (i = 0; i < numSymbols; i++) | 93 | |
| 94 | num = counters[1]; | ||
| 95 | counters[1] = 0; | ||
| 96 | for (i = 2; i != NUM_COUNTERS; i += 2) | ||
| 43 | { | 97 | { |
| 44 | UInt32 freq = freqs[i]; | 98 | unsigned c; |
| 45 | if (freq == 0) | 99 | c = (counters )[i]; (counters )[i] = num; num += c; |
| 46 | lens[i] = 0; | 100 | c = (counters + 1)[i]; (counters + 1)[i] = num; num += c; |
| 47 | else | 101 | } |
| 48 | p[counters[((freq < NUM_COUNTERS - 1) ? freq : NUM_COUNTERS - 1)]++] = i | (freq << NUM_BITS); | 102 | counters[0] = num; // we want to write (freq==0) symbols to the end of (p) array |
| 103 | { | ||
| 104 | i = 0; | ||
| 105 | do | ||
| 106 | { | ||
| 107 | const UInt32 f = freqs[i]; | ||
| 108 | #if 0 | ||
| 109 | if (f == 0) lens[i] = 0; else | ||
| 110 | #endif | ||
| 111 | p[CTR_ITEM_FOR_FREQ(f)++] = i | (f << NUM_BITS); | ||
| 112 | } | ||
| 113 | while (++i != numSymbols); | ||
| 49 | } | 114 | } |
| 50 | counters[0] = 0; | ||
| 51 | HeapSort(p + counters[NUM_COUNTERS - 2], counters[NUM_COUNTERS - 1] - counters[NUM_COUNTERS - 2]); | 115 | HeapSort(p + counters[NUM_COUNTERS - 2], counters[NUM_COUNTERS - 1] - counters[NUM_COUNTERS - 2]); |
| 52 | 116 | ||
| 53 | #else | 117 | #else // NUM_COUNTERS <= 2 |
| 54 | 118 | ||
| 119 | num = 0; | ||
| 55 | for (i = 0; i < numSymbols; i++) | 120 | for (i = 0; i < numSymbols; i++) |
| 56 | { | 121 | { |
| 57 | UInt32 freq = freqs[i]; | 122 | const UInt32 freq = freqs[i]; |
| 58 | if (freq == 0) | 123 | if (freq == 0) |
| 59 | lens[i] = 0; | 124 | lens[i] = 0; |
| 60 | else | 125 | else |
| @@ -62,17 +127,27 @@ void Huffman_Generate(const UInt32 *freqs, UInt32 *p, Byte *lens, UInt32 numSymb | |||
| 62 | } | 127 | } |
| 63 | HeapSort(p, num); | 128 | HeapSort(p, num); |
| 64 | 129 | ||
| 65 | #endif | 130 | #endif |
| 66 | } | 131 | } |
| 67 | 132 | ||
| 68 | if (num < 2) | 133 | if (num <= 2) |
| 69 | { | 134 | { |
| 70 | unsigned minCode = 0; | 135 | unsigned minCode = 0; |
| 71 | unsigned maxCode = 1; | 136 | unsigned maxCode = 1; |
| 72 | if (num == 1) | 137 | if (num) |
| 73 | { | 138 | { |
| 74 | maxCode = (unsigned)p[0] & MASK; | 139 | maxCode = (unsigned)p[(size_t)num - 1] & MASK; |
| 75 | if (maxCode == 0) | 140 | if (num == 2) |
| 141 | { | ||
| 142 | minCode = (unsigned)p[0] & MASK; | ||
| 143 | if (minCode > maxCode) | ||
| 144 | { | ||
| 145 | const unsigned temp = minCode; | ||
| 146 | minCode = maxCode; | ||
| 147 | maxCode = temp; | ||
| 148 | } | ||
| 149 | } | ||
| 150 | else if (maxCode == 0) | ||
| 76 | maxCode++; | 151 | maxCode++; |
| 77 | } | 152 | } |
| 78 | p[minCode] = 0; | 153 | p[minCode] = 0; |
| @@ -80,69 +155,191 @@ void Huffman_Generate(const UInt32 *freqs, UInt32 *p, Byte *lens, UInt32 numSymb | |||
| 80 | lens[minCode] = lens[maxCode] = 1; | 155 | lens[minCode] = lens[maxCode] = 1; |
| 81 | return; | 156 | return; |
| 82 | } | 157 | } |
| 83 | |||
| 84 | { | 158 | { |
| 85 | UInt32 b, e, i; | 159 | unsigned i; |
| 86 | 160 | for (i = 0; i <= kMaxLen; i++) | |
| 87 | i = b = e = 0; | 161 | lenCounters[i] = 0; |
| 88 | do | 162 | lenCounters[1] = 2; // by default root node has 2 child leaves at level 1. |
| 163 | } | ||
| 164 | // if (num != 2) | ||
| 165 | { | ||
| 166 | // num > 2 | ||
| 167 | // the binary tree will contain (num - 1) internal nodes. | ||
| 168 | // p[num - 2] will be root node of binary tree. | ||
| 169 | UInt32 *b; | ||
| 170 | UInt32 *n; | ||
| 171 | // first node will have two leaf childs: p[0] and p[1]: | ||
| 172 | // p[0] += p[1] & FREQ_MASK; // set frequency sum of child leafs | ||
| 173 | // if (pi == n) exit(0); | ||
| 174 | // if (pi != n) | ||
| 89 | { | 175 | { |
| 90 | UInt32 n, m, freq; | 176 | UInt32 fb = (p[1] & FREQ_MASK) + p[0]; |
| 91 | n = (i != num && (b == e || (p[i] >> NUM_BITS) <= (p[b] >> NUM_BITS))) ? i++ : b++; | 177 | UInt32 f = p[2] & FREQ_MASK; |
| 92 | freq = (p[n] & ~MASK); | 178 | const UInt32 *pi = p + 2; |
| 93 | p[n] = (p[n] & MASK) | (e << NUM_BITS); | 179 | UInt32 *e = p; |
| 94 | m = (i != num && (b == e || (p[i] >> NUM_BITS) <= (p[b] >> NUM_BITS))) ? i++ : b++; | 180 | UInt32 eHi = 0; |
| 95 | freq += (p[m] & ~MASK); | 181 | n = p + num; |
| 96 | p[m] = (p[m] & MASK) | (e << NUM_BITS); | 182 | b = p; |
| 97 | p[e] = (p[e] & MASK) | freq; | 183 | // p[0] = fb; |
| 98 | e++; | 184 | for (;;) |
| 185 | { | ||
| 186 | // (b <= e) | ||
| 187 | UInt32 sum; | ||
| 188 | e++; | ||
| 189 | UPDATE_E(eHi) | ||
| 190 | |||
| 191 | // (b < e) | ||
| 192 | |||
| 193 | // p range : high bits | ||
| 194 | // [0, b) : parent : processed nodes that have parent and childs | ||
| 195 | // [b, e) : FREQ : non-processed nodes that have no parent but have childs | ||
| 196 | // [e, pi) : FREQ : processed leaves for which parent node was created | ||
| 197 | // [pi, n) : FREQ : non-processed leaves for which parent node was not created | ||
| 198 | |||
| 199 | // first child | ||
| 200 | // note : (*b < f) is same result as ((*b & FREQ_MASK) < f) | ||
| 201 | if (fb < f) | ||
| 202 | { | ||
| 203 | // node freq is smaller | ||
| 204 | sum = fb & FREQ_MASK; | ||
| 205 | STORE_PARENT_DIRECT (b, fb, eHi) | ||
| 206 | b++; | ||
| 207 | fb = *b; | ||
| 208 | if (b == e) | ||
| 209 | { | ||
| 210 | if (++pi == n) | ||
| 211 | break; | ||
| 212 | sum += f; | ||
| 213 | fb &= MASK; | ||
| 214 | fb |= sum; | ||
| 215 | *e = fb; | ||
| 216 | f = *pi & FREQ_MASK; | ||
| 217 | continue; | ||
| 218 | } | ||
| 219 | } | ||
| 220 | else if (++pi == n) | ||
| 221 | { | ||
| 222 | STORE_PARENT_DIRECT (b, fb, eHi) | ||
| 223 | b++; | ||
| 224 | break; | ||
| 225 | } | ||
| 226 | else | ||
| 227 | { | ||
| 228 | sum = f; | ||
| 229 | f = *pi & FREQ_MASK; | ||
| 230 | } | ||
| 231 | |||
| 232 | // (b < e) | ||
| 233 | |||
| 234 | // second child | ||
| 235 | if (fb < f) | ||
| 236 | { | ||
| 237 | sum += fb; | ||
| 238 | sum &= FREQ_MASK; | ||
| 239 | STORE_PARENT_DIRECT (b, fb, eHi) | ||
| 240 | b++; | ||
| 241 | *e = (*e & MASK) | sum; // set frequency sum | ||
| 242 | // (b <= e) is possible here | ||
| 243 | fb = *b; | ||
| 244 | } | ||
| 245 | else if (++pi == n) | ||
| 246 | break; | ||
| 247 | else | ||
| 248 | { | ||
| 249 | sum += f; | ||
| 250 | f = *pi & FREQ_MASK; | ||
| 251 | *e = (*e & MASK) | sum; // set frequency sum | ||
| 252 | } | ||
| 253 | } | ||
| 99 | } | 254 | } |
| 100 | while (num - e > 1); | ||
| 101 | 255 | ||
| 256 | // printf("\nnum-e=%3u, numSymbols=%3u, num=%3u, b=%3u", n - e, numSymbols, n - p, b - p); | ||
| 102 | { | 257 | { |
| 103 | UInt32 lenCounters[kMaxLen + 1]; | 258 | n -= 2; |
| 104 | for (i = 0; i <= kMaxLen; i++) | 259 | *n &= MASK; // root node : we clear high bits (zero bits mean level == 0) |
| 105 | lenCounters[i] = 0; | 260 | if (n != b) |
| 106 | |||
| 107 | p[--e] &= MASK; | ||
| 108 | lenCounters[1] = 2; | ||
| 109 | while (e != 0) | ||
| 110 | { | ||
| 111 | UInt32 len = (p[p[--e] >> NUM_BITS] >> NUM_BITS) + 1; | ||
| 112 | p[e] = (p[e] & MASK) | (len << NUM_BITS); | ||
| 113 | if (len >= maxLen) | ||
| 114 | for (len = maxLen - 1; lenCounters[len] == 0; len--); | ||
| 115 | lenCounters[len]--; | ||
| 116 | lenCounters[(size_t)len + 1] += 2; | ||
| 117 | } | ||
| 118 | |||
| 119 | { | 261 | { |
| 120 | UInt32 len; | 262 | // We go here, if we have some number of non-created nodes up to root. |
| 121 | i = 0; | 263 | // We process them in simplified code: |
| 122 | for (len = maxLen; len != 0; len--) | 264 | // position of parent for each pair of nodes is known. |
| 265 | // n[-2], n[-1] : current pair of child nodes | ||
| 266 | // (p1) : parent node for current pair. | ||
| 267 | UInt32 *p1 = n; | ||
| 268 | do | ||
| 123 | { | 269 | { |
| 124 | UInt32 k; | 270 | const unsigned len = LOAD_PARENT(p1) + 1; |
| 125 | for (k = lenCounters[len]; k != 0; k--) | 271 | p1--; |
| 126 | lens[p[i++] & MASK] = (Byte)len; | 272 | (lenCounters )[len] -= 2; // we remove 2 leaves from level (len) |
| 273 | (lenCounters + 1)[len] += 2 * 2; // we add 4 leaves at level (len + 1) | ||
| 274 | n -= 2; | ||
| 275 | STORE_PARENT (n , n[0], len) | ||
| 276 | STORE_PARENT (n + 1, n[1], len) | ||
| 127 | } | 277 | } |
| 278 | while (n != b); | ||
| 128 | } | 279 | } |
| 129 | 280 | } | |
| 281 | |||
| 282 | if (b != p) | ||
| 283 | { | ||
| 284 | // we detect level of each node (realtive to root), | ||
| 285 | // and update lenCounters[]. | ||
| 286 | // We process only intermediate nodes and we don't process leaves. | ||
| 287 | do | ||
| 130 | { | 288 | { |
| 131 | UInt32 nextCodes[kMaxLen + 1]; | 289 | // if (ii < b) : parent_bits_of (p[ii]) == index of parent node : ii < (p[ii]) |
| 132 | { | 290 | // if (ii >= b) : parent_bits_of (p[ii]) == level of this (ii) node in tree |
| 133 | UInt32 code = 0; | 291 | unsigned len; |
| 134 | UInt32 len; | 292 | b--; |
| 135 | for (len = 1; len <= kMaxLen; len++) | 293 | len = (unsigned)LOAD_PARENT(p + LOAD_PARENT(b)) + 1; |
| 136 | nextCodes[len] = code = (code + lenCounters[(size_t)len - 1]) << 1; | 294 | STORE_PARENT (b, *b, len) |
| 137 | } | 295 | if (len >= maxLen) |
| 138 | /* if (code + lenCounters[kMaxLen] - 1 != (1 << kMaxLen) - 1) throw 1; */ | ||
| 139 | |||
| 140 | { | 296 | { |
| 141 | UInt32 k; | 297 | // We are not allowed to create node at level (maxLen) and higher, |
| 142 | for (k = 0; k < numSymbols; k++) | 298 | // because all leaves must be placed to level (maxLen) or lower. |
| 143 | p[k] = nextCodes[lens[k]]++; | 299 | // We find nearest allowed leaf and place current node to level of that leaf: |
| 300 | for (len = maxLen - 1; lenCounters[len] == 0; len--) {} | ||
| 144 | } | 301 | } |
| 302 | lenCounters[len]--; // we remove 1 leaf from level (len) | ||
| 303 | (lenCounters + 1)[len] += 2; // we add 2 leaves at level (len + 1) | ||
| 304 | } | ||
| 305 | while (b != p); | ||
| 306 | } | ||
| 307 | } | ||
| 308 | { | ||
| 309 | { | ||
| 310 | unsigned len = maxLen; | ||
| 311 | const UInt32 *p2 = p; | ||
| 312 | do | ||
| 313 | { | ||
| 314 | unsigned k = lenCounters[len]; | ||
| 315 | if (k) | ||
| 316 | do | ||
| 317 | lens[(unsigned)*p2++ & MASK] = (Byte)len; | ||
| 318 | while (--k); | ||
| 319 | } | ||
| 320 | while (--len); | ||
| 321 | } | ||
| 322 | codes[0] = 0; // we don't want garbage values to be written to p[] array. | ||
| 323 | // codes[1] = 0; | ||
| 324 | { | ||
| 325 | UInt32 code = 0; | ||
| 326 | unsigned len; | ||
| 327 | for (len = 0; len < kMaxLen; len++) | ||
| 328 | (codes + 1)[len] = code = (code + lenCounters[len]) << 1; | ||
| 329 | } | ||
| 330 | /* if (code + lenCounters[kMaxLen] - 1 != (1 << kMaxLen) - 1) throw 1; */ | ||
| 331 | { | ||
| 332 | const Byte * const limit = lens + numSymbols; | ||
| 333 | do | ||
| 334 | { | ||
| 335 | unsigned len; | ||
| 336 | UInt32 c; | ||
| 337 | len = lens[0]; c = codes[len]; p[0] = c; codes[len] = c + 1; | ||
| 338 | // len = lens[1]; c = codes[len]; p[1] = c; codes[len] = c + 1; | ||
| 339 | p += 1; | ||
| 340 | lens += 1; | ||
| 145 | } | 341 | } |
| 342 | while (lens != limit); | ||
| 146 | } | 343 | } |
| 147 | } | 344 | } |
| 148 | } | 345 | } |
| @@ -150,5 +347,14 @@ void Huffman_Generate(const UInt32 *freqs, UInt32 *p, Byte *lens, UInt32 numSymb | |||
| 150 | #undef kMaxLen | 347 | #undef kMaxLen |
| 151 | #undef NUM_BITS | 348 | #undef NUM_BITS |
| 152 | #undef MASK | 349 | #undef MASK |
| 350 | #undef FREQ_MASK | ||
| 153 | #undef NUM_COUNTERS | 351 | #undef NUM_COUNTERS |
| 154 | #undef HUFFMAN_SPEED_OPT | 352 | #undef CTR_ITEM_FOR_FREQ |
| 353 | #undef LOAD_PARENT | ||
| 354 | #undef STORE_PARENT | ||
| 355 | #undef STORE_PARENT_DIRECT | ||
| 356 | #undef UPDATE_E | ||
| 357 | #undef HI_HALF_OFFSET | ||
| 358 | #undef NUM_UNROLLS | ||
| 359 | #undef lenCounters | ||
| 360 | #undef codes | ||
diff --git a/C/HuffEnc.h b/C/HuffEnc.h index cbc5d11..2217f55 100644 --- a/C/HuffEnc.h +++ b/C/HuffEnc.h | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* HuffEnc.h -- Huffman encoding | 1 | /* HuffEnc.h -- Huffman encoding |
| 2 | 2023-03-05 : Igor Pavlov : Public domain */ | 2 | Igor Pavlov : Public domain */ |
| 3 | 3 | ||
| 4 | #ifndef ZIP7_INC_HUFF_ENC_H | 4 | #ifndef ZIP7_INC_HUFF_ENC_H |
| 5 | #define ZIP7_INC_HUFF_ENC_H | 5 | #define ZIP7_INC_HUFF_ENC_H |
| @@ -8,14 +8,14 @@ | |||
| 8 | 8 | ||
| 9 | EXTERN_C_BEGIN | 9 | EXTERN_C_BEGIN |
| 10 | 10 | ||
| 11 | #define Z7_HUFFMAN_LEN_MAX 16 | ||
| 11 | /* | 12 | /* |
| 12 | Conditions: | 13 | Conditions: |
| 13 | num <= 1024 = 2 ^ NUM_BITS | 14 | 2 <= num <= 1024 = 2 ^ NUM_BITS |
| 14 | Sum(freqs) < 4M = 2 ^ (32 - NUM_BITS) | 15 | Sum(freqs) < 4M = 2 ^ (32 - NUM_BITS) |
| 15 | maxLen <= 16 = kMaxLen | 16 | 1 <= maxLen <= 16 = Z7_HUFFMAN_LEN_MAX |
| 16 | Num_Items(p) >= HUFFMAN_TEMP_SIZE(num) | 17 | Num_Items(p) >= HUFFMAN_TEMP_SIZE(num) |
| 17 | */ | 18 | */ |
| 18 | |||
| 19 | void Huffman_Generate(const UInt32 *freqs, UInt32 *p, Byte *lens, UInt32 num, UInt32 maxLen); | 19 | void Huffman_Generate(const UInt32 *freqs, UInt32 *p, Byte *lens, UInt32 num, UInt32 maxLen); |
| 20 | 20 | ||
| 21 | EXTERN_C_END | 21 | EXTERN_C_END |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* LzFind.c -- Match finder for LZ algorithms | 1 | /* LzFind.c -- Match finder for LZ algorithms |
| 2 | 2024-03-01 : Igor Pavlov : Public domain */ | 2 | : Igor Pavlov : Public domain */ |
| 3 | 3 | ||
| 4 | #include "Precomp.h" | 4 | #include "Precomp.h" |
| 5 | 5 | ||
| @@ -404,7 +404,7 @@ int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, | |||
| 404 | const unsigned nbMax = | 404 | const unsigned nbMax = |
| 405 | (p->numHashBytes == 2 ? 16 : | 405 | (p->numHashBytes == 2 ? 16 : |
| 406 | (p->numHashBytes == 3 ? 24 : 32)); | 406 | (p->numHashBytes == 3 ? 24 : 32)); |
| 407 | if (numBits > nbMax) | 407 | if (numBits >= nbMax) |
| 408 | numBits = nbMax; | 408 | numBits = nbMax; |
| 409 | if (numBits >= 32) | 409 | if (numBits >= 32) |
| 410 | hs = (UInt32)0 - 1; | 410 | hs = (UInt32)0 - 1; |
| @@ -416,14 +416,14 @@ int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, | |||
| 416 | hs |= (256 << kLzHash_CrcShift_2) - 1; | 416 | hs |= (256 << kLzHash_CrcShift_2) - 1; |
| 417 | { | 417 | { |
| 418 | const UInt32 hs2 = MatchFinder_GetHashMask2(p, historySize); | 418 | const UInt32 hs2 = MatchFinder_GetHashMask2(p, historySize); |
| 419 | if (hs > hs2) | 419 | if (hs >= hs2) |
| 420 | hs = hs2; | 420 | hs = hs2; |
| 421 | } | 421 | } |
| 422 | hsCur = hs; | 422 | hsCur = hs; |
| 423 | if (p->expectedDataSize < historySize) | 423 | if (p->expectedDataSize < historySize) |
| 424 | { | 424 | { |
| 425 | const UInt32 hs2 = MatchFinder_GetHashMask2(p, (UInt32)p->expectedDataSize); | 425 | const UInt32 hs2 = MatchFinder_GetHashMask2(p, (UInt32)p->expectedDataSize); |
| 426 | if (hsCur > hs2) | 426 | if (hsCur >= hs2) |
| 427 | hsCur = hs2; | 427 | hsCur = hs2; |
| 428 | } | 428 | } |
| 429 | } | 429 | } |
| @@ -434,7 +434,7 @@ int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, | |||
| 434 | if (p->expectedDataSize < historySize) | 434 | if (p->expectedDataSize < historySize) |
| 435 | { | 435 | { |
| 436 | hsCur = MatchFinder_GetHashMask(p, (UInt32)p->expectedDataSize); | 436 | hsCur = MatchFinder_GetHashMask(p, (UInt32)p->expectedDataSize); |
| 437 | if (hsCur > hs) // is it possible? | 437 | if (hsCur >= hs) // is it possible? |
| 438 | hsCur = hs; | 438 | hsCur = hs; |
| 439 | } | 439 | } |
| 440 | } | 440 | } |
| @@ -890,7 +890,7 @@ static UInt32 * Hc_GetMatchesSpec(size_t lenLimit, UInt32 curMatch, UInt32 pos, | |||
| 890 | return d; | 890 | return d; |
| 891 | { | 891 | { |
| 892 | const Byte *pb = cur - delta; | 892 | const Byte *pb = cur - delta; |
| 893 | curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)]; | 893 | curMatch = son[_cyclicBufferPos - delta + (_cyclicBufferPos < delta ? _cyclicBufferSize : 0)]; |
| 894 | if (pb[maxLen] == cur[maxLen] && *pb == *cur) | 894 | if (pb[maxLen] == cur[maxLen] && *pb == *cur) |
| 895 | { | 895 | { |
| 896 | UInt32 len = 0; | 896 | UInt32 len = 0; |
| @@ -925,7 +925,7 @@ static UInt32 * Hc_GetMatchesSpec(size_t lenLimit, UInt32 curMatch, UInt32 pos, | |||
| 925 | break; | 925 | break; |
| 926 | { | 926 | { |
| 927 | ptrdiff_t diff; | 927 | ptrdiff_t diff; |
| 928 | curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)]; | 928 | curMatch = son[_cyclicBufferPos - delta + (_cyclicBufferPos < delta ? _cyclicBufferSize : 0)]; |
| 929 | diff = (ptrdiff_t)0 - (ptrdiff_t)delta; | 929 | diff = (ptrdiff_t)0 - (ptrdiff_t)delta; |
| 930 | if (cur[maxLen] == cur[(ptrdiff_t)maxLen + diff]) | 930 | if (cur[maxLen] == cur[(ptrdiff_t)maxLen + diff]) |
| 931 | { | 931 | { |
| @@ -972,7 +972,7 @@ UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byt | |||
| 972 | // if (curMatch >= pos) { *ptr0 = *ptr1 = kEmptyHashValue; return NULL; } | 972 | // if (curMatch >= pos) { *ptr0 = *ptr1 = kEmptyHashValue; return NULL; } |
| 973 | 973 | ||
| 974 | cmCheck = (UInt32)(pos - _cyclicBufferSize); | 974 | cmCheck = (UInt32)(pos - _cyclicBufferSize); |
| 975 | if ((UInt32)pos <= _cyclicBufferSize) | 975 | if ((UInt32)pos < _cyclicBufferSize) |
| 976 | cmCheck = 0; | 976 | cmCheck = 0; |
| 977 | 977 | ||
| 978 | if (cmCheck < curMatch) | 978 | if (cmCheck < curMatch) |
| @@ -980,7 +980,7 @@ UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byt | |||
| 980 | { | 980 | { |
| 981 | const UInt32 delta = pos - curMatch; | 981 | const UInt32 delta = pos - curMatch; |
| 982 | { | 982 | { |
| 983 | CLzRef *pair = son + ((size_t)(_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1); | 983 | CLzRef *pair = son + ((size_t)(_cyclicBufferPos - delta + (_cyclicBufferPos < delta ? _cyclicBufferSize : 0)) << 1); |
| 984 | const Byte *pb = cur - delta; | 984 | const Byte *pb = cur - delta; |
| 985 | unsigned len = (len0 < len1 ? len0 : len1); | 985 | unsigned len = (len0 < len1 ? len0 : len1); |
| 986 | const UInt32 pair0 = pair[0]; | 986 | const UInt32 pair0 = pair[0]; |
| @@ -1039,7 +1039,7 @@ static void SkipMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const | |||
| 1039 | UInt32 cmCheck; | 1039 | UInt32 cmCheck; |
| 1040 | 1040 | ||
| 1041 | cmCheck = (UInt32)(pos - _cyclicBufferSize); | 1041 | cmCheck = (UInt32)(pos - _cyclicBufferSize); |
| 1042 | if ((UInt32)pos <= _cyclicBufferSize) | 1042 | if ((UInt32)pos < _cyclicBufferSize) |
| 1043 | cmCheck = 0; | 1043 | cmCheck = 0; |
| 1044 | 1044 | ||
| 1045 | if (// curMatch >= pos || // failure | 1045 | if (// curMatch >= pos || // failure |
| @@ -1048,7 +1048,7 @@ static void SkipMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const | |||
| 1048 | { | 1048 | { |
| 1049 | const UInt32 delta = pos - curMatch; | 1049 | const UInt32 delta = pos - curMatch; |
| 1050 | { | 1050 | { |
| 1051 | CLzRef *pair = son + ((size_t)(_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1); | 1051 | CLzRef *pair = son + ((size_t)(_cyclicBufferPos - delta + (_cyclicBufferPos < delta ? _cyclicBufferSize : 0)) << 1); |
| 1052 | const Byte *pb = cur - delta; | 1052 | const Byte *pb = cur - delta; |
| 1053 | unsigned len = (len0 < len1 ? len0 : len1); | 1053 | unsigned len = (len0 < len1 ? len0 : len1); |
| 1054 | if (pb[len] == cur[len]) | 1054 | if (pb[len] == cur[len]) |
| @@ -1595,7 +1595,7 @@ static void Bt5_MatchFinder_Skip(void *_p, UInt32 num) | |||
| 1595 | UInt32 pos = p->pos; \ | 1595 | UInt32 pos = p->pos; \ |
| 1596 | UInt32 num2 = num; \ | 1596 | UInt32 num2 = num; \ |
| 1597 | /* (p->pos == p->posLimit) is not allowed here !!! */ \ | 1597 | /* (p->pos == p->posLimit) is not allowed here !!! */ \ |
| 1598 | { const UInt32 rem = p->posLimit - pos; if (num2 > rem) num2 = rem; } \ | 1598 | { const UInt32 rem = p->posLimit - pos; if (num2 >= rem) num2 = rem; } \ |
| 1599 | num -= num2; \ | 1599 | num -= num2; \ |
| 1600 | { const UInt32 cycPos = p->cyclicBufferPos; \ | 1600 | { const UInt32 cycPos = p->cyclicBufferPos; \ |
| 1601 | son = p->son + cycPos; \ | 1601 | son = p->son + cycPos; \ |
diff --git a/C/LzFindMt.c b/C/LzFindMt.c index ac9d59d..25fcc46 100644 --- a/C/LzFindMt.c +++ b/C/LzFindMt.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* LzFindMt.c -- multithreaded Match finder for LZ algorithms | 1 | /* LzFindMt.c -- multithreaded Match finder for LZ algorithms |
| 2 | 2024-01-22 : Igor Pavlov : Public domain */ | 2 | : Igor Pavlov : Public domain */ |
| 3 | 3 | ||
| 4 | #include "Precomp.h" | 4 | #include "Precomp.h" |
| 5 | 5 | ||
| @@ -82,6 +82,8 @@ extern UInt64 g_NumIters_Bytes; | |||
| 82 | Z7_NO_INLINE | 82 | Z7_NO_INLINE |
| 83 | static void MtSync_Construct(CMtSync *p) | 83 | static void MtSync_Construct(CMtSync *p) |
| 84 | { | 84 | { |
| 85 | p->affinityGroup = -1; | ||
| 86 | p->affinityInGroup = 0; | ||
| 85 | p->affinity = 0; | 87 | p->affinity = 0; |
| 86 | p->wasCreated = False; | 88 | p->wasCreated = False; |
| 87 | p->csWasInitialized = False; | 89 | p->csWasInitialized = False; |
| @@ -259,6 +261,12 @@ static WRes MtSync_Create_WRes(CMtSync *p, THREAD_FUNC_TYPE startAddress, void * | |||
| 259 | // return ERROR_TOO_MANY_POSTS; // for debug | 261 | // return ERROR_TOO_MANY_POSTS; // for debug |
| 260 | // return EINVAL; // for debug | 262 | // return EINVAL; // for debug |
| 261 | 263 | ||
| 264 | #ifdef _WIN32 | ||
| 265 | if (p->affinityGroup >= 0) | ||
| 266 | wres = Thread_Create_With_Group(&p->thread, startAddress, obj, | ||
| 267 | (unsigned)(UInt32)p->affinityGroup, (CAffinityMask)p->affinityInGroup); | ||
| 268 | else | ||
| 269 | #endif | ||
| 262 | if (p->affinity != 0) | 270 | if (p->affinity != 0) |
| 263 | wres = Thread_Create_With_Affinity(&p->thread, startAddress, obj, (CAffinityMask)p->affinity); | 271 | wres = Thread_Create_With_Affinity(&p->thread, startAddress, obj, (CAffinityMask)p->affinity); |
| 264 | else | 272 | else |
diff --git a/C/LzFindMt.h b/C/LzFindMt.h index fcb479d..89984f5 100644 --- a/C/LzFindMt.h +++ b/C/LzFindMt.h | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* LzFindMt.h -- multithreaded Match finder for LZ algorithms | 1 | /* LzFindMt.h -- multithreaded Match finder for LZ algorithms |
| 2 | 2024-01-22 : Igor Pavlov : Public domain */ | 2 | : Igor Pavlov : Public domain */ |
| 3 | 3 | ||
| 4 | #ifndef ZIP7_INC_LZ_FIND_MT_H | 4 | #ifndef ZIP7_INC_LZ_FIND_MT_H |
| 5 | #define ZIP7_INC_LZ_FIND_MT_H | 5 | #define ZIP7_INC_LZ_FIND_MT_H |
| @@ -12,8 +12,10 @@ EXTERN_C_BEGIN | |||
| 12 | typedef struct | 12 | typedef struct |
| 13 | { | 13 | { |
| 14 | UInt32 numProcessedBlocks; | 14 | UInt32 numProcessedBlocks; |
| 15 | CThread thread; | 15 | Int32 affinityGroup; |
| 16 | UInt64 affinityInGroup; | ||
| 16 | UInt64 affinity; | 17 | UInt64 affinity; |
| 18 | CThread thread; | ||
| 17 | 19 | ||
| 18 | BoolInt wasCreated; | 20 | BoolInt wasCreated; |
| 19 | BoolInt needStart; | 21 | BoolInt needStart; |
diff --git a/C/Lzma2Enc.c b/C/Lzma2Enc.c index 703e146..72aec69 100644 --- a/C/Lzma2Enc.c +++ b/C/Lzma2Enc.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* Lzma2Enc.c -- LZMA2 Encoder | 1 | /* Lzma2Enc.c -- LZMA2 Encoder |
| 2 | 2023-04-13 : Igor Pavlov : Public domain */ | 2 | : Igor Pavlov : Public domain */ |
| 3 | 3 | ||
| 4 | #include "Precomp.h" | 4 | #include "Precomp.h" |
| 5 | 5 | ||
| @@ -235,6 +235,7 @@ void Lzma2EncProps_Init(CLzma2EncProps *p) | |||
| 235 | p->numBlockThreads_Reduced = -1; | 235 | p->numBlockThreads_Reduced = -1; |
| 236 | p->numBlockThreads_Max = -1; | 236 | p->numBlockThreads_Max = -1; |
| 237 | p->numTotalThreads = -1; | 237 | p->numTotalThreads = -1; |
| 238 | p->numThreadGroups = 0; | ||
| 238 | } | 239 | } |
| 239 | 240 | ||
| 240 | void Lzma2EncProps_Normalize(CLzma2EncProps *p) | 241 | void Lzma2EncProps_Normalize(CLzma2EncProps *p) |
| @@ -781,6 +782,7 @@ SRes Lzma2Enc_Encode2(CLzma2EncHandle p, | |||
| 781 | } | 782 | } |
| 782 | 783 | ||
| 783 | p->mtCoder.numThreadsMax = (unsigned)p->props.numBlockThreads_Max; | 784 | p->mtCoder.numThreadsMax = (unsigned)p->props.numBlockThreads_Max; |
| 785 | p->mtCoder.numThreadGroups = p->props.numThreadGroups; | ||
| 784 | p->mtCoder.expectedDataSize = p->expectedDataSize; | 786 | p->mtCoder.expectedDataSize = p->expectedDataSize; |
| 785 | 787 | ||
| 786 | { | 788 | { |
diff --git a/C/Lzma2Enc.h b/C/Lzma2Enc.h index cb25275..1e6b50c 100644 --- a/C/Lzma2Enc.h +++ b/C/Lzma2Enc.h | |||
| @@ -18,6 +18,7 @@ typedef struct | |||
| 18 | int numBlockThreads_Reduced; | 18 | int numBlockThreads_Reduced; |
| 19 | int numBlockThreads_Max; | 19 | int numBlockThreads_Max; |
| 20 | int numTotalThreads; | 20 | int numTotalThreads; |
| 21 | unsigned numThreadGroups; // 0 : no groups | ||
| 21 | } CLzma2EncProps; | 22 | } CLzma2EncProps; |
| 22 | 23 | ||
| 23 | void Lzma2EncProps_Init(CLzma2EncProps *p); | 24 | void Lzma2EncProps_Init(CLzma2EncProps *p); |
diff --git a/C/LzmaEnc.c b/C/LzmaEnc.c index 088b78f..84a29a5 100644 --- a/C/LzmaEnc.c +++ b/C/LzmaEnc.c | |||
| @@ -62,7 +62,9 @@ void LzmaEncProps_Init(CLzmaEncProps *p) | |||
| 62 | p->lc = p->lp = p->pb = p->algo = p->fb = p->btMode = p->numHashBytes = p->numThreads = -1; | 62 | p->lc = p->lp = p->pb = p->algo = p->fb = p->btMode = p->numHashBytes = p->numThreads = -1; |
| 63 | p->numHashOutBits = 0; | 63 | p->numHashOutBits = 0; |
| 64 | p->writeEndMark = 0; | 64 | p->writeEndMark = 0; |
| 65 | p->affinityGroup = -1; | ||
| 65 | p->affinity = 0; | 66 | p->affinity = 0; |
| 67 | p->affinityInGroup = 0; | ||
| 66 | } | 68 | } |
| 67 | 69 | ||
| 68 | void LzmaEncProps_Normalize(CLzmaEncProps *p) | 70 | void LzmaEncProps_Normalize(CLzmaEncProps *p) |
| @@ -598,6 +600,10 @@ SRes LzmaEnc_SetProps(CLzmaEncHandle p, const CLzmaEncProps *props2) | |||
| 598 | p->multiThread = (props.numThreads > 1); | 600 | p->multiThread = (props.numThreads > 1); |
| 599 | p->matchFinderMt.btSync.affinity = | 601 | p->matchFinderMt.btSync.affinity = |
| 600 | p->matchFinderMt.hashSync.affinity = props.affinity; | 602 | p->matchFinderMt.hashSync.affinity = props.affinity; |
| 603 | p->matchFinderMt.btSync.affinityGroup = | ||
| 604 | p->matchFinderMt.hashSync.affinityGroup = props.affinityGroup; | ||
| 605 | p->matchFinderMt.btSync.affinityInGroup = | ||
| 606 | p->matchFinderMt.hashSync.affinityInGroup = props.affinityInGroup; | ||
| 601 | #endif | 607 | #endif |
| 602 | 608 | ||
| 603 | return SZ_OK; | 609 | return SZ_OK; |
diff --git a/C/LzmaEnc.h b/C/LzmaEnc.h index 9f8039a..3feb5b4 100644 --- a/C/LzmaEnc.h +++ b/C/LzmaEnc.h | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* LzmaEnc.h -- LZMA Encoder | 1 | /* LzmaEnc.h -- LZMA Encoder |
| 2 | 2023-04-13 : Igor Pavlov : Public domain */ | 2 | : Igor Pavlov : Public domain */ |
| 3 | 3 | ||
| 4 | #ifndef ZIP7_INC_LZMA_ENC_H | 4 | #ifndef ZIP7_INC_LZMA_ENC_H |
| 5 | #define ZIP7_INC_LZMA_ENC_H | 5 | #define ZIP7_INC_LZMA_ENC_H |
| @@ -29,11 +29,13 @@ typedef struct | |||
| 29 | int numThreads; /* 1 or 2, default = 2 */ | 29 | int numThreads; /* 1 or 2, default = 2 */ |
| 30 | 30 | ||
| 31 | // int _pad; | 31 | // int _pad; |
| 32 | Int32 affinityGroup; | ||
| 32 | 33 | ||
| 33 | UInt64 reduceSize; /* estimated size of data that will be compressed. default = (UInt64)(Int64)-1. | 34 | UInt64 reduceSize; /* estimated size of data that will be compressed. default = (UInt64)(Int64)-1. |
| 34 | Encoder uses this value to reduce dictionary size */ | 35 | Encoder uses this value to reduce dictionary size */ |
| 35 | 36 | ||
| 36 | UInt64 affinity; | 37 | UInt64 affinity; |
| 38 | UInt64 affinityInGroup; | ||
| 37 | } CLzmaEncProps; | 39 | } CLzmaEncProps; |
| 38 | 40 | ||
| 39 | void LzmaEncProps_Init(CLzmaEncProps *p); | 41 | void LzmaEncProps_Init(CLzmaEncProps *p); |
diff --git a/C/MtCoder.c b/C/MtCoder.c index 03959b6..923b19a 100644 --- a/C/MtCoder.c +++ b/C/MtCoder.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* MtCoder.c -- Multi-thread Coder | 1 | /* MtCoder.c -- Multi-thread Coder |
| 2 | 2023-09-07 : Igor Pavlov : Public domain */ | 2 | : Igor Pavlov : Public domain */ |
| 3 | 3 | ||
| 4 | #include "Precomp.h" | 4 | #include "Precomp.h" |
| 5 | 5 | ||
| @@ -39,14 +39,28 @@ void MtProgressThunk_CreateVTable(CMtProgressThunk *p) | |||
| 39 | static THREAD_FUNC_DECL ThreadFunc(void *pp); | 39 | static THREAD_FUNC_DECL ThreadFunc(void *pp); |
| 40 | 40 | ||
| 41 | 41 | ||
| 42 | static SRes MtCoderThread_CreateAndStart(CMtCoderThread *t) | 42 | static SRes MtCoderThread_CreateAndStart(CMtCoderThread *t |
| 43 | #ifdef _WIN32 | ||
| 44 | , CMtCoder * const mtc | ||
| 45 | #endif | ||
| 46 | ) | ||
| 43 | { | 47 | { |
| 44 | WRes wres = AutoResetEvent_OptCreate_And_Reset(&t->startEvent); | 48 | WRes wres = AutoResetEvent_OptCreate_And_Reset(&t->startEvent); |
| 49 | // printf("\n====== MtCoderThread_CreateAndStart : \n"); | ||
| 45 | if (wres == 0) | 50 | if (wres == 0) |
| 46 | { | 51 | { |
| 47 | t->stop = False; | 52 | t->stop = False; |
| 48 | if (!Thread_WasCreated(&t->thread)) | 53 | if (!Thread_WasCreated(&t->thread)) |
| 49 | wres = Thread_Create(&t->thread, ThreadFunc, t); | 54 | { |
| 55 | #ifdef _WIN32 | ||
| 56 | if (mtc->numThreadGroups) | ||
| 57 | wres = Thread_Create_With_Group(&t->thread, ThreadFunc, t, | ||
| 58 | ThreadNextGroup_GetNext(&mtc->nextGroup), // group | ||
| 59 | 0); // affinityMask | ||
| 60 | else | ||
| 61 | #endif | ||
| 62 | wres = Thread_Create(&t->thread, ThreadFunc, t); | ||
| 63 | } | ||
| 50 | if (wres == 0) | 64 | if (wres == 0) |
| 51 | wres = Event_Set(&t->startEvent); | 65 | wres = Event_Set(&t->startEvent); |
| 52 | } | 66 | } |
| @@ -56,6 +70,7 @@ static SRes MtCoderThread_CreateAndStart(CMtCoderThread *t) | |||
| 56 | } | 70 | } |
| 57 | 71 | ||
| 58 | 72 | ||
| 73 | Z7_FORCE_INLINE | ||
| 59 | static void MtCoderThread_Destruct(CMtCoderThread *t) | 74 | static void MtCoderThread_Destruct(CMtCoderThread *t) |
| 60 | { | 75 | { |
| 61 | if (Thread_WasCreated(&t->thread)) | 76 | if (Thread_WasCreated(&t->thread)) |
| @@ -85,7 +100,7 @@ static void MtCoderThread_Destruct(CMtCoderThread *t) | |||
| 85 | 100 | ||
| 86 | static SRes ThreadFunc2(CMtCoderThread *t) | 101 | static SRes ThreadFunc2(CMtCoderThread *t) |
| 87 | { | 102 | { |
| 88 | CMtCoder *mtc = t->mtCoder; | 103 | CMtCoder * const mtc = t->mtCoder; |
| 89 | 104 | ||
| 90 | for (;;) | 105 | for (;;) |
| 91 | { | 106 | { |
| @@ -185,7 +200,11 @@ static SRes ThreadFunc2(CMtCoderThread *t) | |||
| 185 | if (mtc->numStartedThreads < mtc->numStartedThreadsLimit | 200 | if (mtc->numStartedThreads < mtc->numStartedThreadsLimit |
| 186 | && mtc->expectedDataSize != readProcessed) | 201 | && mtc->expectedDataSize != readProcessed) |
| 187 | { | 202 | { |
| 188 | res = MtCoderThread_CreateAndStart(&mtc->threads[mtc->numStartedThreads]); | 203 | res = MtCoderThread_CreateAndStart(&mtc->threads[mtc->numStartedThreads] |
| 204 | #ifdef _WIN32 | ||
| 205 | , mtc | ||
| 206 | #endif | ||
| 207 | ); | ||
| 189 | if (res == SZ_OK) | 208 | if (res == SZ_OK) |
| 190 | mtc->numStartedThreads++; | 209 | mtc->numStartedThreads++; |
| 191 | else | 210 | else |
| @@ -221,7 +240,7 @@ static SRes ThreadFunc2(CMtCoderThread *t) | |||
| 221 | } | 240 | } |
| 222 | 241 | ||
| 223 | { | 242 | { |
| 224 | CMtCoderBlock *block = &mtc->blocks[bi]; | 243 | CMtCoderBlock * const block = &mtc->blocks[bi]; |
| 225 | block->res = res; | 244 | block->res = res; |
| 226 | block->bufIndex = bufIndex; | 245 | block->bufIndex = bufIndex; |
| 227 | block->finished = finished; | 246 | block->finished = finished; |
| @@ -311,7 +330,7 @@ static SRes ThreadFunc2(CMtCoderThread *t) | |||
| 311 | 330 | ||
| 312 | static THREAD_FUNC_DECL ThreadFunc(void *pp) | 331 | static THREAD_FUNC_DECL ThreadFunc(void *pp) |
| 313 | { | 332 | { |
| 314 | CMtCoderThread *t = (CMtCoderThread *)pp; | 333 | CMtCoderThread * const t = (CMtCoderThread *)pp; |
| 315 | for (;;) | 334 | for (;;) |
| 316 | { | 335 | { |
| 317 | if (Event_Wait(&t->startEvent) != 0) | 336 | if (Event_Wait(&t->startEvent) != 0) |
| @@ -319,7 +338,7 @@ static THREAD_FUNC_DECL ThreadFunc(void *pp) | |||
| 319 | if (t->stop) | 338 | if (t->stop) |
| 320 | return 0; | 339 | return 0; |
| 321 | { | 340 | { |
| 322 | SRes res = ThreadFunc2(t); | 341 | const SRes res = ThreadFunc2(t); |
| 323 | CMtCoder *mtc = t->mtCoder; | 342 | CMtCoder *mtc = t->mtCoder; |
| 324 | if (res != SZ_OK) | 343 | if (res != SZ_OK) |
| 325 | { | 344 | { |
| @@ -328,7 +347,7 @@ static THREAD_FUNC_DECL ThreadFunc(void *pp) | |||
| 328 | 347 | ||
| 329 | #ifndef MTCODER_USE_WRITE_THREAD | 348 | #ifndef MTCODER_USE_WRITE_THREAD |
| 330 | { | 349 | { |
| 331 | unsigned numFinished = (unsigned)InterlockedIncrement(&mtc->numFinishedThreads); | 350 | const unsigned numFinished = (unsigned)InterlockedIncrement(&mtc->numFinishedThreads); |
| 332 | if (numFinished == mtc->numStartedThreads) | 351 | if (numFinished == mtc->numStartedThreads) |
| 333 | if (Event_Set(&mtc->finishedEvent) != 0) | 352 | if (Event_Set(&mtc->finishedEvent) != 0) |
| 334 | return (THREAD_FUNC_RET_TYPE)SZ_ERROR_THREAD; | 353 | return (THREAD_FUNC_RET_TYPE)SZ_ERROR_THREAD; |
| @@ -346,6 +365,7 @@ void MtCoder_Construct(CMtCoder *p) | |||
| 346 | 365 | ||
| 347 | p->blockSize = 0; | 366 | p->blockSize = 0; |
| 348 | p->numThreadsMax = 0; | 367 | p->numThreadsMax = 0; |
| 368 | p->numThreadGroups = 0; | ||
| 349 | p->expectedDataSize = (UInt64)(Int64)-1; | 369 | p->expectedDataSize = (UInt64)(Int64)-1; |
| 350 | 370 | ||
| 351 | p->inStream = NULL; | 371 | p->inStream = NULL; |
| @@ -429,6 +449,8 @@ SRes MtCoder_Code(CMtCoder *p) | |||
| 429 | unsigned i; | 449 | unsigned i; |
| 430 | SRes res = SZ_OK; | 450 | SRes res = SZ_OK; |
| 431 | 451 | ||
| 452 | // printf("\n====== MtCoder_Code : \n"); | ||
| 453 | |||
| 432 | if (numThreads > MTCODER_THREADS_MAX) | 454 | if (numThreads > MTCODER_THREADS_MAX) |
| 433 | numThreads = MTCODER_THREADS_MAX; | 455 | numThreads = MTCODER_THREADS_MAX; |
| 434 | numBlocksMax = MTCODER_GET_NUM_BLOCKS_FROM_THREADS(numThreads); | 456 | numBlocksMax = MTCODER_GET_NUM_BLOCKS_FROM_THREADS(numThreads); |
| @@ -492,11 +514,22 @@ SRes MtCoder_Code(CMtCoder *p) | |||
| 492 | 514 | ||
| 493 | p->numStartedThreadsLimit = numThreads; | 515 | p->numStartedThreadsLimit = numThreads; |
| 494 | p->numStartedThreads = 0; | 516 | p->numStartedThreads = 0; |
| 517 | ThreadNextGroup_Init(&p->nextGroup, p->numThreadGroups, 0); // startGroup | ||
| 495 | 518 | ||
| 496 | // for (i = 0; i < numThreads; i++) | 519 | // for (i = 0; i < numThreads; i++) |
| 497 | { | 520 | { |
| 521 | // here we create new thread for first block. | ||
| 522 | // And each new thread will create another new thread after block reading | ||
| 523 | // until numStartedThreadsLimit is reached. | ||
| 498 | CMtCoderThread *nextThread = &p->threads[p->numStartedThreads++]; | 524 | CMtCoderThread *nextThread = &p->threads[p->numStartedThreads++]; |
| 499 | RINOK(MtCoderThread_CreateAndStart(nextThread)) | 525 | { |
| 526 | const SRes res2 = MtCoderThread_CreateAndStart(nextThread | ||
| 527 | #ifdef _WIN32 | ||
| 528 | , p | ||
| 529 | #endif | ||
| 530 | ); | ||
| 531 | RINOK(res2) | ||
| 532 | } | ||
| 500 | } | 533 | } |
| 501 | 534 | ||
| 502 | RINOK_THREAD(Event_Set(&p->readEvent)) | 535 | RINOK_THREAD(Event_Set(&p->readEvent)) |
| @@ -513,9 +546,9 @@ SRes MtCoder_Code(CMtCoder *p) | |||
| 513 | RINOK_THREAD(Event_Wait(&p->writeEvents[bi])) | 546 | RINOK_THREAD(Event_Wait(&p->writeEvents[bi])) |
| 514 | 547 | ||
| 515 | { | 548 | { |
| 516 | const CMtCoderBlock *block = &p->blocks[bi]; | 549 | const CMtCoderBlock * const block = &p->blocks[bi]; |
| 517 | unsigned bufIndex = block->bufIndex; | 550 | const unsigned bufIndex = block->bufIndex; |
| 518 | BoolInt finished = block->finished; | 551 | const BoolInt finished = block->finished; |
| 519 | if (res == SZ_OK && block->res != SZ_OK) | 552 | if (res == SZ_OK && block->res != SZ_OK) |
| 520 | res = block->res; | 553 | res = block->res; |
| 521 | 554 | ||
| @@ -545,7 +578,7 @@ SRes MtCoder_Code(CMtCoder *p) | |||
| 545 | } | 578 | } |
| 546 | #else | 579 | #else |
| 547 | { | 580 | { |
| 548 | WRes wres = Event_Wait(&p->finishedEvent); | 581 | const WRes wres = Event_Wait(&p->finishedEvent); |
| 549 | res = MY_SRes_HRESULT_FROM_WRes(wres); | 582 | res = MY_SRes_HRESULT_FROM_WRes(wres); |
| 550 | } | 583 | } |
| 551 | #endif | 584 | #endif |
diff --git a/C/MtCoder.h b/C/MtCoder.h index 1231d3c..8166cca 100644 --- a/C/MtCoder.h +++ b/C/MtCoder.h | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* MtCoder.h -- Multi-thread Coder | 1 | /* MtCoder.h -- Multi-thread Coder |
| 2 | 2023-04-13 : Igor Pavlov : Public domain */ | 2 | : Igor Pavlov : Public domain */ |
| 3 | 3 | ||
| 4 | #ifndef ZIP7_INC_MT_CODER_H | 4 | #ifndef ZIP7_INC_MT_CODER_H |
| 5 | #define ZIP7_INC_MT_CODER_H | 5 | #define ZIP7_INC_MT_CODER_H |
| @@ -16,7 +16,7 @@ EXTERN_C_BEGIN | |||
| 16 | 16 | ||
| 17 | #ifndef Z7_ST | 17 | #ifndef Z7_ST |
| 18 | #define MTCODER_GET_NUM_BLOCKS_FROM_THREADS(numThreads) ((numThreads) + (numThreads) / 8 + 1) | 18 | #define MTCODER_GET_NUM_BLOCKS_FROM_THREADS(numThreads) ((numThreads) + (numThreads) / 8 + 1) |
| 19 | #define MTCODER_THREADS_MAX 64 | 19 | #define MTCODER_THREADS_MAX 256 |
| 20 | #define MTCODER_BLOCKS_MAX (MTCODER_GET_NUM_BLOCKS_FROM_THREADS(MTCODER_THREADS_MAX) + 3) | 20 | #define MTCODER_BLOCKS_MAX (MTCODER_GET_NUM_BLOCKS_FROM_THREADS(MTCODER_THREADS_MAX) + 3) |
| 21 | #else | 21 | #else |
| 22 | #define MTCODER_THREADS_MAX 1 | 22 | #define MTCODER_THREADS_MAX 1 |
| @@ -77,6 +77,7 @@ typedef struct CMtCoder_ | |||
| 77 | 77 | ||
| 78 | size_t blockSize; /* size of input block */ | 78 | size_t blockSize; /* size of input block */ |
| 79 | unsigned numThreadsMax; | 79 | unsigned numThreadsMax; |
| 80 | unsigned numThreadGroups; | ||
| 80 | UInt64 expectedDataSize; | 81 | UInt64 expectedDataSize; |
| 81 | 82 | ||
| 82 | ISeqInStreamPtr inStream; | 83 | ISeqInStreamPtr inStream; |
| @@ -125,6 +126,8 @@ typedef struct CMtCoder_ | |||
| 125 | CMtProgress mtProgress; | 126 | CMtProgress mtProgress; |
| 126 | CMtCoderBlock blocks[MTCODER_BLOCKS_MAX]; | 127 | CMtCoderBlock blocks[MTCODER_BLOCKS_MAX]; |
| 127 | CMtCoderThread threads[MTCODER_THREADS_MAX]; | 128 | CMtCoderThread threads[MTCODER_THREADS_MAX]; |
| 129 | |||
| 130 | CThreadNextGroup nextGroup; | ||
| 128 | } CMtCoder; | 131 | } CMtCoder; |
| 129 | 132 | ||
| 130 | 133 | ||
| @@ -439,26 +439,78 @@ void Sha512_Final(CSha512 *p, Byte *digest, unsigned digestSize) | |||
| 439 | 439 | ||
| 440 | 440 | ||
| 441 | 441 | ||
| 442 | // #define Z7_SHA512_PROBE_DEBUG // for debug | ||
| 442 | 443 | ||
| 443 | #if defined(_WIN32) && defined(Z7_COMPILER_SHA512_SUPPORTED) \ | 444 | #if defined(Z7_SHA512_PROBE_DEBUG) || defined(Z7_COMPILER_SHA512_SUPPORTED) |
| 444 | && defined(MY_CPU_ARM64) // we can disable this check to debug in x64 | ||
| 445 | 445 | ||
| 446 | #if 1 // 0 for debug | 446 | #if defined(Z7_SHA512_PROBE_DEBUG) \ |
| 447 | || defined(_WIN32) && defined(MY_CPU_ARM64) | ||
| 448 | #ifndef Z7_SHA512_USE_PROBE | ||
| 449 | #define Z7_SHA512_USE_PROBE | ||
| 450 | #endif | ||
| 451 | #endif | ||
| 447 | 452 | ||
| 448 | #include "7zWindows.h" | 453 | #ifdef Z7_SHA512_USE_PROBE |
| 449 | // #include <stdio.h> | 454 | |
| 450 | #if 0 && defined(MY_CPU_X86_OR_AMD64) | 455 | #ifdef Z7_SHA512_PROBE_DEBUG |
| 451 | #include <intrin.h> // for debug : for __ud2() | 456 | #include <stdio.h> |
| 457 | #define PRF(x) x | ||
| 458 | #else | ||
| 459 | #define PRF(x) | ||
| 452 | #endif | 460 | #endif |
| 453 | 461 | ||
| 454 | BoolInt CPU_IsSupported_SHA512(void) | 462 | #if 0 || !defined(_MSC_VER) // 1 || : for debug LONGJMP mode |
| 463 | // MINGW doesn't support __try. So we use signal() / longjmp(). | ||
| 464 | // Note: signal() / longjmp() probably is not thread-safe. | ||
| 465 | // So we must call Sha512Prepare() from main thread at program start. | ||
| 466 | #ifndef Z7_SHA512_USE_LONGJMP | ||
| 467 | #define Z7_SHA512_USE_LONGJMP | ||
| 468 | #endif | ||
| 469 | #endif | ||
| 470 | |||
| 471 | #ifdef Z7_SHA512_USE_LONGJMP | ||
| 472 | #include <signal.h> | ||
| 473 | #include <setjmp.h> | ||
| 474 | static jmp_buf g_Sha512_jmp_buf; | ||
| 475 | // static int g_Sha512_Unsupported; | ||
| 476 | |||
| 477 | #if defined(__GNUC__) && (__GNUC__ >= 8) \ | ||
| 478 | || defined(__clang__) && (__clang_major__ >= 3) | ||
| 479 | __attribute__((noreturn)) | ||
| 480 | #endif | ||
| 481 | static void Z7_CDECL Sha512_signal_Handler(int v) | ||
| 455 | { | 482 | { |
| 483 | PRF(printf("======== Sha512_signal_Handler = %x\n", (unsigned)v);) | ||
| 484 | // g_Sha512_Unsupported = 1; | ||
| 485 | longjmp(g_Sha512_jmp_buf, 1); | ||
| 486 | } | ||
| 487 | #endif // Z7_SHA512_USE_LONGJMP | ||
| 488 | |||
| 489 | |||
| 490 | #if defined(_WIN32) | ||
| 491 | #include "7zWindows.h" | ||
| 492 | #endif | ||
| 493 | |||
| 456 | #if defined(MY_CPU_ARM64) | 494 | #if defined(MY_CPU_ARM64) |
| 495 | // #define Z7_SHA512_USE_SIMPLIFIED_PROBE // for debug | ||
| 496 | #endif | ||
| 497 | |||
| 498 | #ifdef Z7_SHA512_USE_SIMPLIFIED_PROBE | ||
| 499 | #include <arm_neon.h> | ||
| 500 | #if defined(__clang__) | ||
| 501 | __attribute__((__target__("sha3"))) | ||
| 502 | #elif !defined(_MSC_VER) | ||
| 503 | __attribute__((__target__("arch=armv8.2-a+sha3"))) | ||
| 504 | #endif | ||
| 505 | #endif | ||
| 506 | static BoolInt CPU_IsSupported_SHA512_Probe(void) | ||
| 507 | { | ||
| 508 | PRF(printf("\n== CPU_IsSupported_SHA512_Probe\n");) | ||
| 509 | #if defined(_WIN32) && defined(MY_CPU_ARM64) | ||
| 457 | // we have no SHA512 flag for IsProcessorFeaturePresent() still. | 510 | // we have no SHA512 flag for IsProcessorFeaturePresent() still. |
| 458 | if (!CPU_IsSupported_CRYPTO()) | 511 | if (!CPU_IsSupported_CRYPTO()) |
| 459 | return False; | 512 | return False; |
| 460 | #endif | 513 | PRF(printf("==== Registry check\n");) |
| 461 | // printf("\nCPU_IsSupported_SHA512\n"); | ||
| 462 | { | 514 | { |
| 463 | // we can't read ID_AA64ISAR0_EL1 register from application. | 515 | // we can't read ID_AA64ISAR0_EL1 register from application. |
| 464 | // but ID_AA64ISAR0_EL1 register is mapped to "CP 4030" registry value. | 516 | // but ID_AA64ISAR0_EL1 register is mapped to "CP 4030" registry value. |
| @@ -486,6 +538,7 @@ BoolInt CPU_IsSupported_SHA512(void) | |||
| 486 | // 2 : SHA256 and SHA512 implemented | 538 | // 2 : SHA256 and SHA512 implemented |
| 487 | } | 539 | } |
| 488 | } | 540 | } |
| 541 | #endif // defined(_WIN32) && defined(MY_CPU_ARM64) | ||
| 489 | 542 | ||
| 490 | 543 | ||
| 491 | #if 1 // 0 for debug to disable SHA512 PROBE code | 544 | #if 1 // 0 for debug to disable SHA512 PROBE code |
| @@ -509,59 +562,97 @@ Does this PROBE code work in native Windows-arm64 (with/without sha512 hw instru | |||
| 509 | Are there any ways to fix the problems with arm64-wine and x64-SDE cases? | 562 | Are there any ways to fix the problems with arm64-wine and x64-SDE cases? |
| 510 | */ | 563 | */ |
| 511 | 564 | ||
| 512 | // printf("\n========== CPU_IsSupported_SHA512 PROBE ========\n"); | 565 | PRF(printf("==== CPU_IsSupported_SHA512 PROBE\n");) |
| 513 | { | 566 | { |
| 567 | BoolInt isSupported = False; | ||
| 568 | #ifdef Z7_SHA512_USE_LONGJMP | ||
| 569 | void (Z7_CDECL *signal_prev)(int); | ||
| 570 | /* | ||
| 571 | if (g_Sha512_Unsupported) | ||
| 572 | { | ||
| 573 | PRF(printf("==== g_Sha512_Unsupported\n");) | ||
| 574 | return False; | ||
| 575 | } | ||
| 576 | */ | ||
| 577 | printf("====== signal(SIGILL)\n"); | ||
| 578 | signal_prev = signal(SIGILL, Sha512_signal_Handler); | ||
| 579 | if (signal_prev == SIG_ERR) | ||
| 580 | { | ||
| 581 | PRF(printf("====== signal fail\n");) | ||
| 582 | return False; | ||
| 583 | } | ||
| 584 | // PRF(printf("==== signal_prev = %p\n", (void *)signal_prev);) | ||
| 585 | // docs: Before the specified function is executed, | ||
| 586 | // the value of func is set to SIG_DFL. | ||
| 587 | // So we can exit if (setjmp(g_Sha512_jmp_buf) != 0). | ||
| 588 | PRF(printf("====== setjmp\n");) | ||
| 589 | if (!setjmp(g_Sha512_jmp_buf)) | ||
| 590 | #else // Z7_SHA512_USE_LONGJMP | ||
| 591 | |||
| 592 | #ifdef _MSC_VER | ||
| 514 | #ifdef __clang_major__ | 593 | #ifdef __clang_major__ |
| 515 | #pragma GCC diagnostic ignored "-Wlanguage-extension-token" | 594 | #pragma GCC diagnostic ignored "-Wlanguage-extension-token" |
| 516 | #endif | 595 | #endif |
| 517 | __try | 596 | __try |
| 597 | #endif | ||
| 598 | #endif // Z7_SHA512_USE_LONGJMP | ||
| 599 | |||
| 518 | { | 600 | { |
| 519 | #if 0 // 1 : for debug (reduced version to detect sha512) | 601 | #if defined(Z7_COMPILER_SHA512_SUPPORTED) |
| 602 | #ifdef Z7_SHA512_USE_SIMPLIFIED_PROBE | ||
| 603 | // simplified sha512 check for arm64: | ||
| 520 | const uint64x2_t a = vdupq_n_u64(1); | 604 | const uint64x2_t a = vdupq_n_u64(1); |
| 521 | const uint64x2_t b = vsha512hq_u64(a, a, a); | 605 | const uint64x2_t b = vsha512hq_u64(a, a, a); |
| 606 | PRF(printf("======== vsha512hq_u64 probe\n");) | ||
| 522 | if ((UInt32)vgetq_lane_u64(b, 0) == 0x11800002) | 607 | if ((UInt32)vgetq_lane_u64(b, 0) == 0x11800002) |
| 523 | return True; | ||
| 524 | #else | 608 | #else |
| 525 | MY_ALIGN(16) | 609 | MY_ALIGN(16) |
| 526 | UInt64 temp[SHA512_NUM_DIGEST_WORDS + SHA512_NUM_BLOCK_WORDS]; | 610 | UInt64 temp[SHA512_NUM_DIGEST_WORDS + SHA512_NUM_BLOCK_WORDS]; |
| 527 | memset(temp, 0x5a, sizeof(temp)); | 611 | memset(temp, 0x5a, sizeof(temp)); |
| 528 | #if 0 && defined(MY_CPU_X86_OR_AMD64) | 612 | PRF(printf("======== Sha512_UpdateBlocks_HW\n");) |
| 529 | __ud2(); // for debug : that exception is not problem for SDE | ||
| 530 | #endif | ||
| 531 | #if 1 | ||
| 532 | Sha512_UpdateBlocks_HW(temp, | 613 | Sha512_UpdateBlocks_HW(temp, |
| 533 | (const Byte *)(const void *)(temp + SHA512_NUM_DIGEST_WORDS), 1); | 614 | (const Byte *)(const void *)(temp + SHA512_NUM_DIGEST_WORDS), 1); |
| 534 | // printf("\n==== t = %x\n", (UInt32)temp[0]); | 615 | // PRF(printf("======== t = %x\n", (UInt32)temp[0]);) |
| 535 | if ((UInt32)temp[0] == 0xa33cfdf7) | 616 | if ((UInt32)temp[0] == 0xa33cfdf7) |
| 617 | #endif | ||
| 536 | { | 618 | { |
| 537 | // printf("\n=== PROBE SHA512: SHA512 supported\n"); | 619 | PRF(printf("======== PROBE SHA512: SHA512 is supported\n");) |
| 538 | return True; | 620 | isSupported = True; |
| 539 | } | 621 | } |
| 622 | #else // Z7_COMPILER_SHA512_SUPPORTED | ||
| 623 | // for debug : we generate bad instrction or raise exception. | ||
| 624 | // __except() doesn't catch raise() calls. | ||
| 625 | #ifdef Z7_SHA512_USE_LONGJMP | ||
| 626 | PRF(printf("====== raise(SIGILL)\n");) | ||
| 627 | raise(SIGILL); | ||
| 628 | #else | ||
| 629 | #if defined(_MSC_VER) && defined(MY_CPU_X86) | ||
| 630 | __asm ud2 | ||
| 540 | #endif | 631 | #endif |
| 541 | #endif | 632 | #endif // Z7_SHA512_USE_LONGJMP |
| 633 | #endif // Z7_COMPILER_SHA512_SUPPORTED | ||
| 542 | } | 634 | } |
| 635 | |||
| 636 | #ifdef Z7_SHA512_USE_LONGJMP | ||
| 637 | PRF(printf("====== restore signal SIGILL\n");) | ||
| 638 | signal(SIGILL, signal_prev); | ||
| 639 | #elif _MSC_VER | ||
| 543 | __except (EXCEPTION_EXECUTE_HANDLER) | 640 | __except (EXCEPTION_EXECUTE_HANDLER) |
| 544 | { | 641 | { |
| 545 | // printf("\n==== CPU_IsSupported_SHA512 EXCEPTION_EXECUTE_HANDLER\n"); | 642 | PRF(printf("==== CPU_IsSupported_SHA512 __except(EXCEPTION_EXECUTE_HANDLER)\n");) |
| 546 | } | 643 | } |
| 644 | #endif | ||
| 645 | PRF(printf("== return (sha512 supported) = %d\n", isSupported);) | ||
| 646 | return isSupported; | ||
| 547 | } | 647 | } |
| 548 | return False; | ||
| 549 | #else | 648 | #else |
| 550 | // without SHA512 PROBE code | 649 | // without SHA512 PROBE code |
| 551 | return True; | 650 | return True; |
| 552 | #endif | 651 | #endif |
| 553 | |||
| 554 | } | 652 | } |
| 555 | 653 | ||
| 556 | #else | 654 | #endif // Z7_SHA512_USE_PROBE |
| 557 | 655 | #endif // defined(Z7_SHA512_PROBE_DEBUG) || defined(Z7_COMPILER_SHA512_SUPPORTED) | |
| 558 | BoolInt CPU_IsSupported_SHA512(void) | ||
| 559 | { | ||
| 560 | return False; | ||
| 561 | } | ||
| 562 | |||
| 563 | #endif | ||
| 564 | #endif // WIN32 arm64 | ||
| 565 | 656 | ||
| 566 | 657 | ||
| 567 | void Sha512Prepare(void) | 658 | void Sha512Prepare(void) |
| @@ -570,10 +661,10 @@ void Sha512Prepare(void) | |||
| 570 | SHA512_FUNC_UPDATE_BLOCKS f, f_hw; | 661 | SHA512_FUNC_UPDATE_BLOCKS f, f_hw; |
| 571 | f = Sha512_UpdateBlocks; | 662 | f = Sha512_UpdateBlocks; |
| 572 | f_hw = NULL; | 663 | f_hw = NULL; |
| 573 | #ifdef MY_CPU_X86_OR_AMD64 | 664 | #ifdef Z7_SHA512_USE_PROBE |
| 574 | if (CPU_IsSupported_SHA512() | 665 | if (CPU_IsSupported_SHA512_Probe()) |
| 575 | && CPU_IsSupported_AVX2() | 666 | #elif defined(MY_CPU_X86_OR_AMD64) |
| 576 | ) | 667 | if (CPU_IsSupported_SHA512() && CPU_IsSupported_AVX2()) |
| 577 | #else | 668 | #else |
| 578 | if (CPU_IsSupported_SHA512()) | 669 | if (CPU_IsSupported_SHA512()) |
| 579 | #endif | 670 | #endif |
| @@ -583,6 +674,8 @@ void Sha512Prepare(void) | |||
| 583 | } | 674 | } |
| 584 | g_SHA512_FUNC_UPDATE_BLOCKS = f; | 675 | g_SHA512_FUNC_UPDATE_BLOCKS = f; |
| 585 | g_SHA512_FUNC_UPDATE_BLOCKS_HW = f_hw; | 676 | g_SHA512_FUNC_UPDATE_BLOCKS_HW = f_hw; |
| 677 | #elif defined(Z7_SHA512_PROBE_DEBUG) | ||
| 678 | CPU_IsSupported_SHA512_Probe(); // for debug | ||
| 586 | #endif | 679 | #endif |
| 587 | } | 680 | } |
| 588 | 681 | ||
| @@ -1,141 +1,268 @@ | |||
| 1 | /* Sort.c -- Sort functions | 1 | /* Sort.c -- Sort functions |
| 2 | 2014-04-05 : Igor Pavlov : Public domain */ | 2 | : Igor Pavlov : Public domain */ |
| 3 | 3 | ||
| 4 | #include "Precomp.h" | 4 | #include "Precomp.h" |
| 5 | 5 | ||
| 6 | #include "Sort.h" | 6 | #include "Sort.h" |
| 7 | #include "CpuArch.h" | ||
| 7 | 8 | ||
| 8 | #define HeapSortDown(p, k, size, temp) \ | 9 | #if ( (defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))) \ |
| 9 | { for (;;) { \ | 10 | || (defined(__clang__) && Z7_has_builtin(__builtin_prefetch)) \ |
| 10 | size_t s = (k << 1); \ | 11 | ) |
| 11 | if (s > size) break; \ | 12 | // the code with prefetch is slow for small arrays on x86. |
| 12 | if (s < size && p[s + 1] > p[s]) s++; \ | 13 | // So we disable prefetch for x86. |
| 13 | if (temp >= p[s]) break; \ | 14 | #ifndef MY_CPU_X86 |
| 14 | p[k] = p[s]; k = s; \ | 15 | // #pragma message("Z7_PREFETCH : __builtin_prefetch") |
| 15 | } p[k] = temp; } | 16 | #define Z7_PREFETCH(a) __builtin_prefetch((a)) |
| 17 | #endif | ||
| 16 | 18 | ||
| 17 | void HeapSort(UInt32 *p, size_t size) | 19 | #elif defined(_WIN32) // || defined(_MSC_VER) && (_MSC_VER >= 1200) |
| 18 | { | 20 | |
| 19 | if (size <= 1) | 21 | #include "7zWindows.h" |
| 20 | return; | 22 | |
| 21 | p--; | 23 | // NOTE: CLANG/GCC/MSVC can define different values for _MM_HINT_T0 / PF_TEMPORAL_LEVEL_1. |
| 22 | { | 24 | // For example, clang-cl can generate "prefetcht2" instruction for |
| 23 | size_t i = size / 2; | 25 | // PreFetchCacheLine(PF_TEMPORAL_LEVEL_1) call. |
| 24 | do | 26 | // But we want to generate "prefetcht0" instruction. |
| 25 | { | 27 | // So for CLANG/GCC we must use __builtin_prefetch() in code branch above |
| 26 | UInt32 temp = p[i]; | 28 | // instead of PreFetchCacheLine() / _mm_prefetch(). |
| 27 | size_t k = i; | 29 | |
| 28 | HeapSortDown(p, k, size, temp) | 30 | // New msvc-x86 compiler generates "prefetcht0" instruction for PreFetchCacheLine() call. |
| 29 | } | 31 | // But old x86 cpus don't support "prefetcht0". |
| 30 | while (--i != 0); | 32 | // So we will use PreFetchCacheLine(), only if we are sure that |
| 31 | } | 33 | // generated instruction is supported by all cpus of that isa. |
| 32 | /* | 34 | #if defined(MY_CPU_AMD64) \ |
| 33 | do | 35 | || defined(MY_CPU_ARM64) \ |
| 34 | { | 36 | || defined(MY_CPU_IA64) |
| 35 | size_t k = 1; | 37 | // we need to use additional braces for (a) in PreFetchCacheLine call, because |
| 36 | UInt32 temp = p[size]; | 38 | // PreFetchCacheLine macro doesn't use braces: |
| 37 | p[size--] = p[1]; | 39 | // #define PreFetchCacheLine(l, a) _mm_prefetch((CHAR CONST *) a, l) |
| 38 | HeapSortDown(p, k, size, temp) | 40 | // #pragma message("Z7_PREFETCH : PreFetchCacheLine") |
| 39 | } | 41 | #define Z7_PREFETCH(a) PreFetchCacheLine(PF_TEMPORAL_LEVEL_1, (a)) |
| 40 | while (size > 1); | 42 | #endif |
| 41 | */ | 43 | |
| 42 | while (size > 3) | 44 | #endif // _WIN32 |
| 43 | { | 45 | |
| 44 | UInt32 temp = p[size]; | 46 | |
| 45 | size_t k = (p[3] > p[2]) ? 3 : 2; | 47 | #define PREFETCH_NO(p,k,s,size) |
| 46 | p[size--] = p[1]; | 48 | |
| 47 | p[1] = p[k]; | 49 | #ifndef Z7_PREFETCH |
| 48 | HeapSortDown(p, k, size, temp) | 50 | #define SORT_PREFETCH(p,k,s,size) |
| 49 | } | 51 | #else |
| 50 | { | 52 | |
| 51 | UInt32 temp = p[size]; | 53 | // #define PREFETCH_LEVEL 2 // use it if cache line is 32-bytes |
| 52 | p[size] = p[1]; | 54 | #define PREFETCH_LEVEL 3 // it is fast for most cases (64-bytes cache line prefetch) |
| 53 | if (size > 2 && p[2] < temp) | 55 | // #define PREFETCH_LEVEL 4 // it can be faster for big array (128-bytes prefetch) |
| 54 | { | 56 | |
| 55 | p[1] = p[2]; | 57 | #if PREFETCH_LEVEL == 0 |
| 56 | p[2] = temp; | 58 | |
| 57 | } | 59 | #define SORT_PREFETCH(p,k,s,size) |
| 58 | else | 60 | |
| 59 | p[1] = temp; | 61 | #else // PREFETCH_LEVEL != 0 |
| 60 | } | 62 | |
| 63 | /* | ||
| 64 | if defined(USE_PREFETCH_FOR_ALIGNED_ARRAY) | ||
| 65 | we prefetch one value per cache line. | ||
| 66 | Use it if array is aligned for cache line size (64 bytes) | ||
| 67 | or if array is small (less than L1 cache size). | ||
| 68 | |||
| 69 | if !defined(USE_PREFETCH_FOR_ALIGNED_ARRAY) | ||
| 70 | we perfetch all cache lines that can be required. | ||
| 71 | it can be faster for big unaligned arrays. | ||
| 72 | */ | ||
| 73 | #define USE_PREFETCH_FOR_ALIGNED_ARRAY | ||
| 74 | |||
| 75 | // s == k * 2 | ||
| 76 | #if 0 && PREFETCH_LEVEL <= 3 && defined(MY_CPU_X86_OR_AMD64) | ||
| 77 | // x86 supports (lea r1*8+offset) | ||
| 78 | #define PREFETCH_OFFSET(k,s) ((s) << PREFETCH_LEVEL) | ||
| 79 | #else | ||
| 80 | #define PREFETCH_OFFSET(k,s) ((k) << (PREFETCH_LEVEL + 1)) | ||
| 81 | #endif | ||
| 82 | |||
| 83 | #if 1 && PREFETCH_LEVEL <= 3 && defined(USE_PREFETCH_FOR_ALIGNED_ARRAY) | ||
| 84 | #define PREFETCH_ADD_OFFSET 0 | ||
| 85 | #else | ||
| 86 | // last offset that can be reqiured in PREFETCH_LEVEL step: | ||
| 87 | #define PREFETCH_RANGE ((2 << PREFETCH_LEVEL) - 1) | ||
| 88 | #define PREFETCH_ADD_OFFSET PREFETCH_RANGE / 2 | ||
| 89 | #endif | ||
| 90 | |||
| 91 | #if PREFETCH_LEVEL <= 3 | ||
| 92 | |||
| 93 | #ifdef USE_PREFETCH_FOR_ALIGNED_ARRAY | ||
| 94 | #define SORT_PREFETCH(p,k,s,size) \ | ||
| 95 | { const size_t s2 = PREFETCH_OFFSET(k,s) + PREFETCH_ADD_OFFSET; \ | ||
| 96 | if (s2 <= size) { \ | ||
| 97 | Z7_PREFETCH((p + s2)); \ | ||
| 98 | }} | ||
| 99 | #else /* for unaligned array */ | ||
| 100 | #define SORT_PREFETCH(p,k,s,size) \ | ||
| 101 | { const size_t s2 = PREFETCH_OFFSET(k,s) + PREFETCH_RANGE; \ | ||
| 102 | if (s2 <= size) { \ | ||
| 103 | Z7_PREFETCH((p + s2 - PREFETCH_RANGE)); \ | ||
| 104 | Z7_PREFETCH((p + s2)); \ | ||
| 105 | }} | ||
| 106 | #endif | ||
| 107 | |||
| 108 | #else // PREFETCH_LEVEL > 3 | ||
| 109 | |||
| 110 | #ifdef USE_PREFETCH_FOR_ALIGNED_ARRAY | ||
| 111 | #define SORT_PREFETCH(p,k,s,size) \ | ||
| 112 | { const size_t s2 = PREFETCH_OFFSET(k,s) + PREFETCH_RANGE - 16 / 2; \ | ||
| 113 | if (s2 <= size) { \ | ||
| 114 | Z7_PREFETCH((p + s2 - 16)); \ | ||
| 115 | Z7_PREFETCH((p + s2)); \ | ||
| 116 | }} | ||
| 117 | #else /* for unaligned array */ | ||
| 118 | #define SORT_PREFETCH(p,k,s,size) \ | ||
| 119 | { const size_t s2 = PREFETCH_OFFSET(k,s) + PREFETCH_RANGE; \ | ||
| 120 | if (s2 <= size) { \ | ||
| 121 | Z7_PREFETCH((p + s2 - PREFETCH_RANGE)); \ | ||
| 122 | Z7_PREFETCH((p + s2 - PREFETCH_RANGE / 2)); \ | ||
| 123 | Z7_PREFETCH((p + s2)); \ | ||
| 124 | }} | ||
| 125 | #endif | ||
| 126 | |||
| 127 | #endif // PREFETCH_LEVEL > 3 | ||
| 128 | #endif // PREFETCH_LEVEL != 0 | ||
| 129 | #endif // Z7_PREFETCH | ||
| 130 | |||
| 131 | |||
| 132 | #if defined(MY_CPU_ARM64) \ | ||
| 133 | /* || defined(MY_CPU_AMD64) */ \ | ||
| 134 | /* || defined(MY_CPU_ARM) && !defined(_MSC_VER) */ | ||
| 135 | // we want to use cmov, if cmov is very fast: | ||
| 136 | // - this cmov version is slower for clang-x64. | ||
| 137 | // - this cmov version is faster for gcc-arm64 for some fast arm64 cpus. | ||
| 138 | #define Z7_FAST_CMOV_SUPPORTED | ||
| 139 | #endif | ||
| 140 | |||
| 141 | #ifdef Z7_FAST_CMOV_SUPPORTED | ||
| 142 | // we want to use cmov here, if cmov is fast: new arm64 cpus. | ||
| 143 | // we want the compiler to use conditional move for this branch | ||
| 144 | #define GET_MAX_VAL(n0, n1, max_val_slow) if (n0 < n1) n0 = n1; | ||
| 145 | #else | ||
| 146 | // use this branch, if cpu doesn't support fast conditional move. | ||
| 147 | // it uses slow array access reading: | ||
| 148 | #define GET_MAX_VAL(n0, n1, max_val_slow) n0 = max_val_slow; | ||
| 149 | #endif | ||
| 150 | |||
| 151 | #define HeapSortDown(p, k, size, temp, macro_prefetch) \ | ||
| 152 | { \ | ||
| 153 | for (;;) { \ | ||
| 154 | UInt32 n0, n1; \ | ||
| 155 | size_t s = k * 2; \ | ||
| 156 | if (s >= size) { \ | ||
| 157 | if (s == size) { \ | ||
| 158 | n0 = p[s]; \ | ||
| 159 | p[k] = n0; \ | ||
| 160 | if (temp < n0) k = s; \ | ||
| 161 | } \ | ||
| 162 | break; \ | ||
| 163 | } \ | ||
| 164 | n0 = p[k * 2]; \ | ||
| 165 | n1 = p[k * 2 + 1]; \ | ||
| 166 | s += n0 < n1; \ | ||
| 167 | GET_MAX_VAL(n0, n1, p[s]) \ | ||
| 168 | if (temp >= n0) break; \ | ||
| 169 | macro_prefetch(p, k, s, size) \ | ||
| 170 | p[k] = n0; \ | ||
| 171 | k = s; \ | ||
| 172 | } \ | ||
| 173 | p[k] = temp; \ | ||
| 61 | } | 174 | } |
| 62 | 175 | ||
| 63 | void HeapSort64(UInt64 *p, size_t size) | 176 | |
| 177 | /* | ||
| 178 | stage-1 : O(n) : | ||
| 179 | we generate intermediate partially sorted binary tree: | ||
| 180 | p[0] : it's additional item for better alignment of tree structure in memory. | ||
| 181 | p[1] | ||
| 182 | p[2] p[3] | ||
| 183 | p[4] p[5] p[6] p[7] | ||
| 184 | ... | ||
| 185 | p[x] >= p[x * 2] | ||
| 186 | p[x] >= p[x * 2 + 1] | ||
| 187 | |||
| 188 | stage-2 : O(n)*log2(N): | ||
| 189 | we move largest item p[0] from head of tree to the end of array | ||
| 190 | and insert last item to sorted binary tree. | ||
| 191 | */ | ||
| 192 | |||
| 193 | // (p) must be aligned for cache line size (64-bytes) for best performance | ||
| 194 | |||
| 195 | void Z7_FASTCALL HeapSort(UInt32 *p, size_t size) | ||
| 64 | { | 196 | { |
| 65 | if (size <= 1) | 197 | if (size < 2) |
| 66 | return; | 198 | return; |
| 67 | p--; | 199 | if (size == 2) |
| 68 | { | ||
| 69 | size_t i = size / 2; | ||
| 70 | do | ||
| 71 | { | ||
| 72 | UInt64 temp = p[i]; | ||
| 73 | size_t k = i; | ||
| 74 | HeapSortDown(p, k, size, temp) | ||
| 75 | } | ||
| 76 | while (--i != 0); | ||
| 77 | } | ||
| 78 | /* | ||
| 79 | do | ||
| 80 | { | 200 | { |
| 81 | size_t k = 1; | 201 | const UInt32 a0 = p[0]; |
| 82 | UInt64 temp = p[size]; | 202 | const UInt32 a1 = p[1]; |
| 83 | p[size--] = p[1]; | 203 | const unsigned k = a1 < a0; |
| 84 | HeapSortDown(p, k, size, temp) | 204 | p[k] = a0; |
| 85 | } | 205 | p[k ^ 1] = a1; |
| 86 | while (size > 1); | 206 | return; |
| 87 | */ | ||
| 88 | while (size > 3) | ||
| 89 | { | ||
| 90 | UInt64 temp = p[size]; | ||
| 91 | size_t k = (p[3] > p[2]) ? 3 : 2; | ||
| 92 | p[size--] = p[1]; | ||
| 93 | p[1] = p[k]; | ||
| 94 | HeapSortDown(p, k, size, temp) | ||
| 95 | } | 207 | } |
| 96 | { | 208 | { |
| 97 | UInt64 temp = p[size]; | 209 | // stage-1 : O(n) |
| 98 | p[size] = p[1]; | 210 | // we transform array to partially sorted binary tree. |
| 99 | if (size > 2 && p[2] < temp) | 211 | size_t i = --size / 2; |
| 212 | // (size) now is the index of the last item in tree, | ||
| 213 | // if (i) | ||
| 100 | { | 214 | { |
| 101 | p[1] = p[2]; | 215 | do |
| 102 | p[2] = temp; | 216 | { |
| 217 | const UInt32 temp = p[i]; | ||
| 218 | size_t k = i; | ||
| 219 | HeapSortDown(p, k, size, temp, PREFETCH_NO) | ||
| 220 | } | ||
| 221 | while (--i); | ||
| 222 | } | ||
| 223 | { | ||
| 224 | const UInt32 temp = p[0]; | ||
| 225 | const UInt32 a1 = p[1]; | ||
| 226 | if (temp < a1) | ||
| 227 | { | ||
| 228 | size_t k = 1; | ||
| 229 | p[0] = a1; | ||
| 230 | HeapSortDown(p, k, size, temp, PREFETCH_NO) | ||
| 231 | } | ||
| 103 | } | 232 | } |
| 104 | else | ||
| 105 | p[1] = temp; | ||
| 106 | } | 233 | } |
| 107 | } | ||
| 108 | 234 | ||
| 109 | /* | 235 | if (size < 3) |
| 110 | #define HeapSortRefDown(p, vals, n, size, temp) \ | 236 | { |
| 111 | { size_t k = n; UInt32 val = vals[temp]; for (;;) { \ | 237 | // size == 2 |
| 112 | size_t s = (k << 1); \ | 238 | const UInt32 a0 = p[0]; |
| 113 | if (s > size) break; \ | 239 | p[0] = p[2]; |
| 114 | if (s < size && vals[p[s + 1]] > vals[p[s]]) s++; \ | 240 | p[2] = a0; |
| 115 | if (val >= vals[p[s]]) break; \ | ||
| 116 | p[k] = p[s]; k = s; \ | ||
| 117 | } p[k] = temp; } | ||
| 118 | |||
| 119 | void HeapSortRef(UInt32 *p, UInt32 *vals, size_t size) | ||
| 120 | { | ||
| 121 | if (size <= 1) | ||
| 122 | return; | 241 | return; |
| 123 | p--; | 242 | } |
| 243 | if (size != 3) | ||
| 124 | { | 244 | { |
| 125 | size_t i = size / 2; | 245 | // stage-2 : O(size) * log2(size): |
| 246 | // we move largest item p[0] from head to the end of array, | ||
| 247 | // and insert last item to sorted binary tree. | ||
| 126 | do | 248 | do |
| 127 | { | 249 | { |
| 128 | UInt32 temp = p[i]; | 250 | const UInt32 temp = p[size]; |
| 129 | HeapSortRefDown(p, vals, i, size, temp); | 251 | size_t k = p[2] < p[3] ? 3 : 2; |
| 252 | p[size--] = p[0]; | ||
| 253 | p[0] = p[1]; | ||
| 254 | p[1] = p[k]; | ||
| 255 | HeapSortDown(p, k, size, temp, SORT_PREFETCH) // PREFETCH_NO | ||
| 130 | } | 256 | } |
| 131 | while (--i != 0); | 257 | while (size != 3); |
| 132 | } | 258 | } |
| 133 | do | ||
| 134 | { | 259 | { |
| 135 | UInt32 temp = p[size]; | 260 | const UInt32 a2 = p[2]; |
| 136 | p[size--] = p[1]; | 261 | const UInt32 a3 = p[3]; |
| 137 | HeapSortRefDown(p, vals, 1, size, temp); | 262 | const size_t k = a2 < a3; |
| 263 | p[2] = p[1]; | ||
| 264 | p[3] = p[0]; | ||
| 265 | p[k] = a3; | ||
| 266 | p[k ^ 1] = a2; | ||
| 138 | } | 267 | } |
| 139 | while (size > 1); | ||
| 140 | } | 268 | } |
| 141 | */ | ||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* Sort.h -- Sort functions | 1 | /* Sort.h -- Sort functions |
| 2 | 2023-03-05 : Igor Pavlov : Public domain */ | 2 | : Igor Pavlov : Public domain */ |
| 3 | 3 | ||
| 4 | #ifndef ZIP7_INC_SORT_H | 4 | #ifndef ZIP7_INC_SORT_H |
| 5 | #define ZIP7_INC_SORT_H | 5 | #define ZIP7_INC_SORT_H |
| @@ -8,10 +8,7 @@ | |||
| 8 | 8 | ||
| 9 | EXTERN_C_BEGIN | 9 | EXTERN_C_BEGIN |
| 10 | 10 | ||
| 11 | void HeapSort(UInt32 *p, size_t size); | 11 | void Z7_FASTCALL HeapSort(UInt32 *p, size_t size); |
| 12 | void HeapSort64(UInt64 *p, size_t size); | ||
| 13 | |||
| 14 | /* void HeapSortRef(UInt32 *p, UInt32 *vals, size_t size); */ | ||
| 15 | 12 | ||
| 16 | EXTERN_C_END | 13 | EXTERN_C_END |
| 17 | 14 | ||
diff --git a/C/Threads.c b/C/Threads.c index 464efec..177d1d9 100644 --- a/C/Threads.c +++ b/C/Threads.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* Threads.c -- multithreading library | 1 | /* Threads.c -- multithreading library |
| 2 | 2024-03-28 : Igor Pavlov : Public domain */ | 2 | : Igor Pavlov : Public domain */ |
| 3 | 3 | ||
| 4 | #include "Precomp.h" | 4 | #include "Precomp.h" |
| 5 | 5 | ||
| @@ -59,6 +59,100 @@ WRes Thread_Wait_Close(CThread *p) | |||
| 59 | return (res != 0 ? res : res2); | 59 | return (res != 0 ? res : res2); |
| 60 | } | 60 | } |
| 61 | 61 | ||
| 62 | typedef struct MY_PROCESSOR_NUMBER { | ||
| 63 | WORD Group; | ||
| 64 | BYTE Number; | ||
| 65 | BYTE Reserved; | ||
| 66 | } MY_PROCESSOR_NUMBER, *MY_PPROCESSOR_NUMBER; | ||
| 67 | |||
| 68 | typedef struct MY_GROUP_AFFINITY { | ||
| 69 | #if defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION < 100000) | ||
| 70 | // KAFFINITY is not defined in old mingw | ||
| 71 | ULONG_PTR | ||
| 72 | #else | ||
| 73 | KAFFINITY | ||
| 74 | #endif | ||
| 75 | Mask; | ||
| 76 | WORD Group; | ||
| 77 | WORD Reserved[3]; | ||
| 78 | } MY_GROUP_AFFINITY, *MY_PGROUP_AFFINITY; | ||
| 79 | |||
| 80 | typedef BOOL (WINAPI *Func_SetThreadGroupAffinity)( | ||
| 81 | HANDLE hThread, | ||
| 82 | CONST MY_GROUP_AFFINITY *GroupAffinity, | ||
| 83 | MY_PGROUP_AFFINITY PreviousGroupAffinity); | ||
| 84 | |||
| 85 | typedef BOOL (WINAPI *Func_GetThreadGroupAffinity)( | ||
| 86 | HANDLE hThread, | ||
| 87 | MY_PGROUP_AFFINITY GroupAffinity); | ||
| 88 | |||
| 89 | typedef BOOL (WINAPI *Func_GetProcessGroupAffinity)( | ||
| 90 | HANDLE hProcess, | ||
| 91 | PUSHORT GroupCount, | ||
| 92 | PUSHORT GroupArray); | ||
| 93 | |||
| 94 | Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION | ||
| 95 | |||
| 96 | #if 0 | ||
| 97 | #include <stdio.h> | ||
| 98 | #define PRF(x) x | ||
| 99 | /* | ||
| 100 | -- | ||
| 101 | before call of SetThreadGroupAffinity() | ||
| 102 | GetProcessGroupAffinity return one group. | ||
| 103 | after call of SetThreadGroupAffinity(): | ||
| 104 | GetProcessGroupAffinity return more than group, | ||
| 105 | if SetThreadGroupAffinity() was to another group. | ||
| 106 | -- | ||
| 107 | GetProcessAffinityMask MS DOCs: | ||
| 108 | { | ||
| 109 | If the calling process contains threads in multiple groups, | ||
| 110 | the function returns zero for both affinity masks. | ||
| 111 | } | ||
| 112 | but tests in win10 with 2 groups (less than 64 cores total): | ||
| 113 | GetProcessAffinityMask() still returns non-zero affinity masks | ||
| 114 | even after SetThreadGroupAffinity() calls. | ||
| 115 | */ | ||
| 116 | static void PrintProcess_Info() | ||
| 117 | { | ||
| 118 | { | ||
| 119 | const | ||
| 120 | Func_GetProcessGroupAffinity fn_GetProcessGroupAffinity = | ||
| 121 | (Func_GetProcessGroupAffinity) Z7_CAST_FUNC_C GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), | ||
| 122 | "GetProcessGroupAffinity"); | ||
| 123 | if (fn_GetProcessGroupAffinity) | ||
| 124 | { | ||
| 125 | unsigned i; | ||
| 126 | USHORT GroupCounts[64]; | ||
| 127 | USHORT GroupCount = Z7_ARRAY_SIZE(GroupCounts); | ||
| 128 | BOOL boolRes = fn_GetProcessGroupAffinity(GetCurrentProcess(), | ||
| 129 | &GroupCount, GroupCounts); | ||
| 130 | printf("\n====== GetProcessGroupAffinity : " | ||
| 131 | "boolRes=%u GroupCounts = %u :", | ||
| 132 | boolRes, (unsigned)GroupCount); | ||
| 133 | for (i = 0; i < GroupCount; i++) | ||
| 134 | printf(" %u", GroupCounts[i]); | ||
| 135 | printf("\n"); | ||
| 136 | } | ||
| 137 | } | ||
| 138 | { | ||
| 139 | DWORD_PTR processAffinityMask, systemAffinityMask; | ||
| 140 | if (GetProcessAffinityMask(GetCurrentProcess(), &processAffinityMask, &systemAffinityMask)) | ||
| 141 | { | ||
| 142 | PRF(printf("\n====== GetProcessAffinityMask : " | ||
| 143 | ": processAffinityMask=%x, systemAffinityMask=%x\n", | ||
| 144 | (UInt32)processAffinityMask, (UInt32)systemAffinityMask);) | ||
| 145 | } | ||
| 146 | else | ||
| 147 | printf("\n==GetProcessAffinityMask FAIL"); | ||
| 148 | } | ||
| 149 | } | ||
| 150 | #else | ||
| 151 | #ifndef USE_THREADS_CreateThread | ||
| 152 | // #define PRF(x) | ||
| 153 | #endif | ||
| 154 | #endif | ||
| 155 | |||
| 62 | WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param) | 156 | WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param) |
| 63 | { | 157 | { |
| 64 | /* Windows Me/98/95: threadId parameter may not be NULL in _beginthreadex/CreateThread functions */ | 158 | /* Windows Me/98/95: threadId parameter may not be NULL in _beginthreadex/CreateThread functions */ |
| @@ -72,7 +166,43 @@ WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param) | |||
| 72 | 166 | ||
| 73 | unsigned threadId; | 167 | unsigned threadId; |
| 74 | *p = (HANDLE)(_beginthreadex(NULL, 0, func, param, 0, &threadId)); | 168 | *p = (HANDLE)(_beginthreadex(NULL, 0, func, param, 0, &threadId)); |
| 75 | 169 | ||
| 170 | #if 0 // 1 : for debug | ||
| 171 | { | ||
| 172 | DWORD_PTR prevMask; | ||
| 173 | DWORD_PTR affinity = 1 << 0; | ||
| 174 | prevMask = SetThreadAffinityMask(*p, (DWORD_PTR)affinity); | ||
| 175 | prevMask = prevMask; | ||
| 176 | } | ||
| 177 | #endif | ||
| 178 | #if 0 // 1 : for debug | ||
| 179 | { | ||
| 180 | /* win10: new thread will be created in same group that is assigned to parent thread | ||
| 181 | but affinity mask will contain all allowed threads of that group, | ||
| 182 | even if affinity mask of parent group is not full | ||
| 183 | win11: what group it will be created, if we have set | ||
| 184 | affinity of parent thread with ThreadGroupAffinity? | ||
| 185 | */ | ||
| 186 | const | ||
| 187 | Func_GetThreadGroupAffinity fn = | ||
| 188 | (Func_GetThreadGroupAffinity) Z7_CAST_FUNC_C GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), | ||
| 189 | "GetThreadGroupAffinity"); | ||
| 190 | if (fn) | ||
| 191 | { | ||
| 192 | // BOOL wres2; | ||
| 193 | MY_GROUP_AFFINITY groupAffinity; | ||
| 194 | memset(&groupAffinity, 0, sizeof(groupAffinity)); | ||
| 195 | /* wres2 = */ fn(*p, &groupAffinity); | ||
| 196 | PRF(printf("\n==Thread_Create cur = %6u GetThreadGroupAffinity(): " | ||
| 197 | "wres2_BOOL = %u, group=%u mask=%x\n", | ||
| 198 | GetCurrentThreadId(), | ||
| 199 | wres2, | ||
| 200 | groupAffinity.Group, | ||
| 201 | (UInt32)groupAffinity.Mask);) | ||
| 202 | } | ||
| 203 | } | ||
| 204 | #endif | ||
| 205 | |||
| 76 | #endif | 206 | #endif |
| 77 | 207 | ||
| 78 | /* maybe we must use errno here, but probably GetLastError() is also OK. */ | 208 | /* maybe we must use errno here, but probably GetLastError() is also OK. */ |
| @@ -110,7 +240,84 @@ WRes Thread_Create_With_Affinity(CThread *p, THREAD_FUNC_TYPE func, LPVOID param | |||
| 110 | */ | 240 | */ |
| 111 | } | 241 | } |
| 112 | { | 242 | { |
| 113 | DWORD prevSuspendCount = ResumeThread(h); | 243 | const DWORD prevSuspendCount = ResumeThread(h); |
| 244 | /* ResumeThread() returns: | ||
| 245 | 0 : was_not_suspended | ||
| 246 | 1 : was_resumed | ||
| 247 | -1 : error | ||
| 248 | */ | ||
| 249 | if (prevSuspendCount == (DWORD)-1) | ||
| 250 | wres = GetError(); | ||
| 251 | } | ||
| 252 | } | ||
| 253 | |||
| 254 | /* maybe we must use errno here, but probably GetLastError() is also OK. */ | ||
| 255 | return wres; | ||
| 256 | |||
| 257 | #endif | ||
| 258 | } | ||
| 259 | |||
| 260 | |||
| 261 | WRes Thread_Create_With_Group(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, unsigned group, CAffinityMask affinityMask) | ||
| 262 | { | ||
| 263 | #ifdef USE_THREADS_CreateThread | ||
| 264 | |||
| 265 | UNUSED_VAR(group) | ||
| 266 | UNUSED_VAR(affinityMask) | ||
| 267 | return Thread_Create(p, func, param); | ||
| 268 | |||
| 269 | #else | ||
| 270 | |||
| 271 | /* Windows Me/98/95: threadId parameter may not be NULL in _beginthreadex/CreateThread functions */ | ||
| 272 | HANDLE h; | ||
| 273 | WRes wres; | ||
| 274 | unsigned threadId; | ||
| 275 | h = (HANDLE)(_beginthreadex(NULL, 0, func, param, CREATE_SUSPENDED, &threadId)); | ||
| 276 | *p = h; | ||
| 277 | wres = HandleToWRes(h); | ||
| 278 | if (h) | ||
| 279 | { | ||
| 280 | // PrintProcess_Info(); | ||
| 281 | { | ||
| 282 | const | ||
| 283 | Func_SetThreadGroupAffinity fn = | ||
| 284 | (Func_SetThreadGroupAffinity) Z7_CAST_FUNC_C GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), | ||
| 285 | "SetThreadGroupAffinity"); | ||
| 286 | if (fn) | ||
| 287 | { | ||
| 288 | // WRes wres2; | ||
| 289 | MY_GROUP_AFFINITY groupAffinity, prev_groupAffinity; | ||
| 290 | memset(&groupAffinity, 0, sizeof(groupAffinity)); | ||
| 291 | // groupAffinity.Mask must use only bits that supported by current group | ||
| 292 | // (groupAffinity.Mask = 0) means all allowed bits | ||
| 293 | groupAffinity.Mask = affinityMask; | ||
| 294 | groupAffinity.Group = (WORD)group; | ||
| 295 | // wres2 = | ||
| 296 | fn(h, &groupAffinity, &prev_groupAffinity); | ||
| 297 | /* | ||
| 298 | if (groupAffinity.Group == prev_groupAffinity.Group) | ||
| 299 | wres2 = wres2; | ||
| 300 | else | ||
| 301 | wres2 = wres2; | ||
| 302 | if (wres2 == 0) | ||
| 303 | { | ||
| 304 | wres2 = GetError(); | ||
| 305 | PRF(printf("\n==SetThreadGroupAffinity error: %u\n", wres2);) | ||
| 306 | } | ||
| 307 | else | ||
| 308 | { | ||
| 309 | PRF(printf("\n==Thread_Create_With_Group::SetThreadGroupAffinity()" | ||
| 310 | " threadId = %6u" | ||
| 311 | " group=%u mask=%x\n", | ||
| 312 | threadId, | ||
| 313 | prev_groupAffinity.Group, | ||
| 314 | (UInt32)prev_groupAffinity.Mask);) | ||
| 315 | } | ||
| 316 | */ | ||
| 317 | } | ||
| 318 | } | ||
| 319 | { | ||
| 320 | const DWORD prevSuspendCount = ResumeThread(h); | ||
| 114 | /* ResumeThread() returns: | 321 | /* ResumeThread() returns: |
| 115 | 0 : was_not_suspended | 322 | 0 : was_not_suspended |
| 116 | 1 : was_resumed | 323 | 1 : was_resumed |
| @@ -297,6 +504,13 @@ WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param) | |||
| 297 | return Thread_Create_With_CpuSet(p, func, param, NULL); | 504 | return Thread_Create_With_CpuSet(p, func, param, NULL); |
| 298 | } | 505 | } |
| 299 | 506 | ||
| 507 | /* | ||
| 508 | WRes Thread_Create_With_Group(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, unsigned group, CAffinityMask affinity) | ||
| 509 | { | ||
| 510 | UNUSED_VAR(group) | ||
| 511 | return Thread_Create_With_Affinity(p, func, param, affinity); | ||
| 512 | } | ||
| 513 | */ | ||
| 300 | 514 | ||
| 301 | WRes Thread_Create_With_Affinity(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, CAffinityMask affinity) | 515 | WRes Thread_Create_With_Affinity(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, CAffinityMask affinity) |
| 302 | { | 516 | { |
| @@ -577,5 +791,22 @@ WRes AutoResetEvent_OptCreate_And_Reset(CAutoResetEvent *p) | |||
| 577 | return AutoResetEvent_CreateNotSignaled(p); | 791 | return AutoResetEvent_CreateNotSignaled(p); |
| 578 | } | 792 | } |
| 579 | 793 | ||
| 794 | void ThreadNextGroup_Init(CThreadNextGroup *p, UInt32 numGroups, UInt32 startGroup) | ||
| 795 | { | ||
| 796 | // printf("\n====== ThreadNextGroup_Init numGroups = %x: startGroup=%x\n", numGroups, startGroup); | ||
| 797 | if (numGroups == 0) | ||
| 798 | numGroups = 1; | ||
| 799 | p->NumGroups = numGroups; | ||
| 800 | p->NextGroup = startGroup % numGroups; | ||
| 801 | } | ||
| 802 | |||
| 803 | |||
| 804 | UInt32 ThreadNextGroup_GetNext(CThreadNextGroup *p) | ||
| 805 | { | ||
| 806 | const UInt32 next = p->NextGroup; | ||
| 807 | p->NextGroup = (next + 1) % p->NumGroups; | ||
| 808 | return next; | ||
| 809 | } | ||
| 810 | |||
| 580 | #undef PRF | 811 | #undef PRF |
| 581 | #undef Print | 812 | #undef Print |
diff --git a/C/Threads.h b/C/Threads.h index c1484a2..be12e6e 100644 --- a/C/Threads.h +++ b/C/Threads.h | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* Threads.h -- multithreading library | 1 | /* Threads.h -- multithreading library |
| 2 | 2024-03-28 : Igor Pavlov : Public domain */ | 2 | : Igor Pavlov : Public domain */ |
| 3 | 3 | ||
| 4 | #ifndef ZIP7_INC_THREADS_H | 4 | #ifndef ZIP7_INC_THREADS_H |
| 5 | #define ZIP7_INC_THREADS_H | 5 | #define ZIP7_INC_THREADS_H |
| @@ -140,12 +140,22 @@ WRes Thread_Create_With_Affinity(CThread *p, THREAD_FUNC_TYPE func, LPVOID param | |||
| 140 | WRes Thread_Wait_Close(CThread *p); | 140 | WRes Thread_Wait_Close(CThread *p); |
| 141 | 141 | ||
| 142 | #ifdef _WIN32 | 142 | #ifdef _WIN32 |
| 143 | WRes Thread_Create_With_Group(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, unsigned group, CAffinityMask affinityMask); | ||
| 143 | #define Thread_Create_With_CpuSet(p, func, param, cs) \ | 144 | #define Thread_Create_With_CpuSet(p, func, param, cs) \ |
| 144 | Thread_Create_With_Affinity(p, func, param, *cs) | 145 | Thread_Create_With_Affinity(p, func, param, *cs) |
| 145 | #else | 146 | #else |
| 146 | WRes Thread_Create_With_CpuSet(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, const CCpuSet *cpuSet); | 147 | WRes Thread_Create_With_CpuSet(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, const CCpuSet *cpuSet); |
| 147 | #endif | 148 | #endif |
| 148 | 149 | ||
| 150 | typedef struct | ||
| 151 | { | ||
| 152 | unsigned NumGroups; | ||
| 153 | unsigned NextGroup; | ||
| 154 | } CThreadNextGroup; | ||
| 155 | |||
| 156 | void ThreadNextGroup_Init(CThreadNextGroup *p, unsigned numGroups, unsigned startGroup); | ||
| 157 | unsigned ThreadNextGroup_GetNext(CThreadNextGroup *p); | ||
| 158 | |||
| 149 | 159 | ||
| 150 | #ifdef _WIN32 | 160 | #ifdef _WIN32 |
| 151 | 161 | ||
diff --git a/C/Util/Lzma/LzmaUtil.dsp b/C/Util/Lzma/LzmaUtil.dsp index e2e7d42..71de950 100644 --- a/C/Util/Lzma/LzmaUtil.dsp +++ b/C/Util/Lzma/LzmaUtil.dsp | |||
| @@ -122,6 +122,10 @@ SOURCE=..\..\Compiler.h | |||
| 122 | # End Source File | 122 | # End Source File |
| 123 | # Begin Source File | 123 | # Begin Source File |
| 124 | 124 | ||
| 125 | SOURCE=..\..\CpuArch.c | ||
| 126 | # End Source File | ||
| 127 | # Begin Source File | ||
| 128 | |||
| 125 | SOURCE=..\..\CpuArch.h | 129 | SOURCE=..\..\CpuArch.h |
| 126 | # End Source File | 130 | # End Source File |
| 127 | # Begin Source File | 131 | # Begin Source File |
diff --git a/C/Util/LzmaLib/LzmaLib.dsp b/C/Util/LzmaLib/LzmaLib.dsp index bacd967..f413137 100644 --- a/C/Util/LzmaLib/LzmaLib.dsp +++ b/C/Util/LzmaLib/LzmaLib.dsp | |||
| @@ -43,7 +43,7 @@ RSC=rc.exe | |||
| 43 | # PROP Ignore_Export_Lib 0 | 43 | # PROP Ignore_Export_Lib 0 |
| 44 | # PROP Target_Dir "" | 44 | # PROP Target_Dir "" |
| 45 | # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LZMALIB_EXPORTS" /YX /FD /c | 45 | # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LZMALIB_EXPORTS" /YX /FD /c |
| 46 | # ADD CPP /nologo /Gr /MT /W3 /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LZMALIB_EXPORTS" /FD /c | 46 | # ADD CPP /nologo /Gr /MT /W4 /WX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LZMALIB_EXPORTS" /FD /c |
| 47 | # SUBTRACT CPP /YX | 47 | # SUBTRACT CPP /YX |
| 48 | # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 | 48 | # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 |
| 49 | # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 | 49 | # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 |
| @@ -71,7 +71,7 @@ LINK32=link.exe | |||
| 71 | # PROP Ignore_Export_Lib 0 | 71 | # PROP Ignore_Export_Lib 0 |
| 72 | # PROP Target_Dir "" | 72 | # PROP Target_Dir "" |
| 73 | # 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 | 73 | # 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 |
| 74 | # 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 | 74 | # 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 |
| 75 | # SUBTRACT CPP /YX | 75 | # SUBTRACT CPP /YX |
| 76 | # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 | 76 | # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 |
| 77 | # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 | 77 | # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 |
| @@ -128,6 +128,10 @@ SOURCE=..\..\Compiler.h | |||
| 128 | # End Source File | 128 | # End Source File |
| 129 | # Begin Source File | 129 | # Begin Source File |
| 130 | 130 | ||
| 131 | SOURCE=..\..\CpuArch.c | ||
| 132 | # End Source File | ||
| 133 | # Begin Source File | ||
| 134 | |||
| 131 | SOURCE=..\..\CpuArch.h | 135 | SOURCE=..\..\CpuArch.h |
| 132 | # End Source File | 136 | # End Source File |
| 133 | # Begin Source File | 137 | # Begin Source File |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* Xz.h - Xz interface | 1 | /* Xz.h - Xz interface |
| 2 | 2024-01-26 : Igor Pavlov : Public domain */ | 2 | Igor Pavlov : Public domain */ |
| 3 | 3 | ||
| 4 | #ifndef ZIP7_INC_XZ_H | 4 | #ifndef ZIP7_INC_XZ_H |
| 5 | #define ZIP7_INC_XZ_H | 5 | #define ZIP7_INC_XZ_H |
| @@ -121,6 +121,7 @@ typedef struct | |||
| 121 | UInt64 startOffset; | 121 | UInt64 startOffset; |
| 122 | } CXzStream; | 122 | } CXzStream; |
| 123 | 123 | ||
| 124 | #define Xz_CONSTRUCT(p) { (p)->numBlocks = 0; (p)->blocks = NULL; (p)->flags = 0; } | ||
| 124 | void Xz_Construct(CXzStream *p); | 125 | void Xz_Construct(CXzStream *p); |
| 125 | void Xz_Free(CXzStream *p, ISzAllocPtr alloc); | 126 | void Xz_Free(CXzStream *p, ISzAllocPtr alloc); |
| 126 | 127 | ||
| @@ -136,8 +137,13 @@ typedef struct | |||
| 136 | CXzStream *streams; | 137 | CXzStream *streams; |
| 137 | } CXzs; | 138 | } CXzs; |
| 138 | 139 | ||
| 140 | #define Xzs_CONSTRUCT(p) { (p)->num = 0; (p)->numAllocated = 0; (p)->streams = NULL; } | ||
| 139 | void Xzs_Construct(CXzs *p); | 141 | void Xzs_Construct(CXzs *p); |
| 140 | void Xzs_Free(CXzs *p, ISzAllocPtr alloc); | 142 | void Xzs_Free(CXzs *p, ISzAllocPtr alloc); |
| 143 | /* | ||
| 144 | Xzs_ReadBackward() must be called for empty CXzs object. | ||
| 145 | Xzs_ReadBackward() can return non empty object with (p->num != 0) even in case of error. | ||
| 146 | */ | ||
| 141 | SRes Xzs_ReadBackward(CXzs *p, ILookInStreamPtr inStream, Int64 *startOffset, ICompressProgressPtr progress, ISzAllocPtr alloc); | 147 | SRes Xzs_ReadBackward(CXzs *p, ILookInStreamPtr inStream, Int64 *startOffset, ICompressProgressPtr progress, ISzAllocPtr alloc); |
| 142 | 148 | ||
| 143 | UInt64 Xzs_GetNumBlocks(const CXzs *p); | 149 | UInt64 Xzs_GetNumBlocks(const CXzs *p); |
| @@ -268,8 +274,8 @@ typedef struct | |||
| 268 | size_t outBufSize; | 274 | size_t outBufSize; |
| 269 | size_t outDataWritten; // the size of data in (outBuf) that were fully unpacked | 275 | size_t outDataWritten; // the size of data in (outBuf) that were fully unpacked |
| 270 | 276 | ||
| 271 | Byte shaDigest[SHA256_DIGEST_SIZE]; | 277 | UInt32 shaDigest32[SHA256_DIGEST_SIZE / 4]; |
| 272 | Byte buf[XZ_BLOCK_HEADER_SIZE_MAX]; | 278 | Byte buf[XZ_BLOCK_HEADER_SIZE_MAX]; // it must be aligned for 4-bytes |
| 273 | } CXzUnpacker; | 279 | } CXzUnpacker; |
| 274 | 280 | ||
| 275 | /* alloc : aligned for cache line allocation is better */ | 281 | /* alloc : aligned for cache line allocation is better */ |
diff --git a/C/XzCrc64Opt.c b/C/XzCrc64Opt.c index 0c1fc2f..6eea4a3 100644 --- a/C/XzCrc64Opt.c +++ b/C/XzCrc64Opt.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* XzCrc64Opt.c -- CRC64 calculation (optimized functions) | 1 | /* XzCrc64Opt.c -- CRC64 calculation (optimized functions) |
| 2 | 2023-12-08 : Igor Pavlov : Public domain */ | 2 | : Igor Pavlov : Public domain */ |
| 3 | 3 | ||
| 4 | #include "Precomp.h" | 4 | #include "Precomp.h" |
| 5 | 5 | ||
| @@ -235,7 +235,7 @@ CRC64_FUNC_PRE_BE(Z7_CRC64_NUM_TABLES_USE) | |||
| 235 | v = Q32BE(1, w1) ^ Q32BE(0, w0); | 235 | v = Q32BE(1, w1) ^ Q32BE(0, w0); |
| 236 | v ^= Q32BE(3, d1) ^ Q32BE(2, d0); | 236 | v ^= Q32BE(3, d1) ^ Q32BE(2, d0); |
| 237 | #endif | 237 | #endif |
| 238 | #elif | 238 | #else |
| 239 | #error Stop_Compiling_Bad_CRC64_NUM_TABLES | 239 | #error Stop_Compiling_Bad_CRC64_NUM_TABLES |
| 240 | #endif | 240 | #endif |
| 241 | p += Z7_CRC64_NUM_TABLES_USE; | 241 | p += Z7_CRC64_NUM_TABLES_USE; |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* XzDec.c -- Xz Decode | 1 | /* XzDec.c -- Xz Decode |
| 2 | 2024-03-01 : Igor Pavlov : Public domain */ | 2 | : Igor Pavlov : Public domain */ |
| 3 | 3 | ||
| 4 | #include "Precomp.h" | 4 | #include "Precomp.h" |
| 5 | 5 | ||
| @@ -59,7 +59,7 @@ unsigned Xz_ReadVarInt(const Byte *p, size_t maxSize, UInt64 *value) | |||
| 59 | 59 | ||
| 60 | for (i = 0; i < limit;) | 60 | for (i = 0; i < limit;) |
| 61 | { | 61 | { |
| 62 | Byte b = p[i]; | 62 | const unsigned b = p[i]; |
| 63 | *value |= (UInt64)(b & 0x7F) << (7 * i++); | 63 | *value |= (UInt64)(b & 0x7F) << (7 * i++); |
| 64 | if ((b & 0x80) == 0) | 64 | if ((b & 0x80) == 0) |
| 65 | return (b == 0 && i != 1) ? 0 : i; | 65 | return (b == 0 && i != 1) ? 0 : i; |
| @@ -796,11 +796,10 @@ SRes Xz_ParseHeader(CXzStreamFlags *p, const Byte *buf) | |||
| 796 | 796 | ||
| 797 | static BoolInt Xz_CheckFooter(CXzStreamFlags flags, UInt64 indexSize, const Byte *buf) | 797 | static BoolInt Xz_CheckFooter(CXzStreamFlags flags, UInt64 indexSize, const Byte *buf) |
| 798 | { | 798 | { |
| 799 | return indexSize == (((UInt64)GetUi32(buf + 4) + 1) << 2) | 799 | return indexSize == (((UInt64)GetUi32a(buf + 4) + 1) << 2) |
| 800 | && GetUi32(buf) == CrcCalc(buf + 4, 6) | 800 | && GetUi32a(buf) == CrcCalc(buf + 4, 6) |
| 801 | && flags == GetBe16(buf + 8) | 801 | && flags == GetBe16a(buf + 8) |
| 802 | && buf[10] == XZ_FOOTER_SIG_0 | 802 | && GetUi16a(buf + 10) == (XZ_FOOTER_SIG_0 | (XZ_FOOTER_SIG_1 << 8)); |
| 803 | && buf[11] == XZ_FOOTER_SIG_1; | ||
| 804 | } | 803 | } |
| 805 | 804 | ||
| 806 | #define READ_VARINT_AND_CHECK(buf, pos, size, res) \ | 805 | #define READ_VARINT_AND_CHECK(buf, pos, size, res) \ |
| @@ -1166,7 +1165,7 @@ SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen, | |||
| 1166 | p->indexPreSize = 1 + Xz_WriteVarInt(p->buf + 1, p->numBlocks); | 1165 | p->indexPreSize = 1 + Xz_WriteVarInt(p->buf + 1, p->numBlocks); |
| 1167 | p->indexPos = p->indexPreSize; | 1166 | p->indexPos = p->indexPreSize; |
| 1168 | p->indexSize += p->indexPreSize; | 1167 | p->indexSize += p->indexPreSize; |
| 1169 | Sha256_Final(&p->sha, p->shaDigest); | 1168 | Sha256_Final(&p->sha, (Byte *)(void *)p->shaDigest32); |
| 1170 | Sha256_Init(&p->sha); | 1169 | Sha256_Init(&p->sha); |
| 1171 | p->crc = CrcUpdate(CRC_INIT_VAL, p->buf, p->indexPreSize); | 1170 | p->crc = CrcUpdate(CRC_INIT_VAL, p->buf, p->indexPreSize); |
| 1172 | p->state = XZ_STATE_STREAM_INDEX; | 1171 | p->state = XZ_STATE_STREAM_INDEX; |
| @@ -1241,10 +1240,10 @@ SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen, | |||
| 1241 | break; | 1240 | break; |
| 1242 | } | 1241 | } |
| 1243 | { | 1242 | { |
| 1244 | Byte digest[XZ_CHECK_SIZE_MAX]; | 1243 | UInt32 digest32[XZ_CHECK_SIZE_MAX / 4]; |
| 1245 | p->state = XZ_STATE_BLOCK_HEADER; | 1244 | p->state = XZ_STATE_BLOCK_HEADER; |
| 1246 | p->pos = 0; | 1245 | p->pos = 0; |
| 1247 | if (XzCheck_Final(&p->check, digest) && memcmp(digest, p->buf, checkSize) != 0) | 1246 | if (XzCheck_Final(&p->check, (void *)digest32) && memcmp(digest32, p->buf, checkSize) != 0) |
| 1248 | return SZ_ERROR_CRC; | 1247 | return SZ_ERROR_CRC; |
| 1249 | if (p->decodeOnlyOneBlock) | 1248 | if (p->decodeOnlyOneBlock) |
| 1250 | { | 1249 | { |
| @@ -1289,12 +1288,12 @@ SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen, | |||
| 1289 | } | 1288 | } |
| 1290 | else | 1289 | else |
| 1291 | { | 1290 | { |
| 1292 | Byte digest[SHA256_DIGEST_SIZE]; | 1291 | UInt32 digest32[SHA256_DIGEST_SIZE / 4]; |
| 1293 | p->state = XZ_STATE_STREAM_INDEX_CRC; | 1292 | p->state = XZ_STATE_STREAM_INDEX_CRC; |
| 1294 | p->indexSize += 4; | 1293 | p->indexSize += 4; |
| 1295 | p->pos = 0; | 1294 | p->pos = 0; |
| 1296 | Sha256_Final(&p->sha, digest); | 1295 | Sha256_Final(&p->sha, (void *)digest32); |
| 1297 | if (memcmp(digest, p->shaDigest, SHA256_DIGEST_SIZE) != 0) | 1296 | if (memcmp(digest32, p->shaDigest32, SHA256_DIGEST_SIZE) != 0) |
| 1298 | return SZ_ERROR_CRC; | 1297 | return SZ_ERROR_CRC; |
| 1299 | } | 1298 | } |
| 1300 | } | 1299 | } |
| @@ -1313,7 +1312,7 @@ SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen, | |||
| 1313 | const Byte *ptr = p->buf; | 1312 | const Byte *ptr = p->buf; |
| 1314 | p->state = XZ_STATE_STREAM_FOOTER; | 1313 | p->state = XZ_STATE_STREAM_FOOTER; |
| 1315 | p->pos = 0; | 1314 | p->pos = 0; |
| 1316 | if (CRC_GET_DIGEST(p->crc) != GetUi32(ptr)) | 1315 | if (CRC_GET_DIGEST(p->crc) != GetUi32a(ptr)) |
| 1317 | return SZ_ERROR_CRC; | 1316 | return SZ_ERROR_CRC; |
| 1318 | } | 1317 | } |
| 1319 | break; | 1318 | break; |
| @@ -1343,7 +1342,7 @@ SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen, | |||
| 1343 | { | 1342 | { |
| 1344 | if (*src != 0) | 1343 | if (*src != 0) |
| 1345 | { | 1344 | { |
| 1346 | if (((UInt32)p->padSize & 3) != 0) | 1345 | if ((unsigned)p->padSize & 3) |
| 1347 | return SZ_ERROR_NO_ARCHIVE; | 1346 | return SZ_ERROR_NO_ARCHIVE; |
| 1348 | p->pos = 0; | 1347 | p->pos = 0; |
| 1349 | p->state = XZ_STATE_STREAM_HEADER; | 1348 | p->state = XZ_STATE_STREAM_HEADER; |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* XzEnc.c -- Xz Encode | 1 | /* XzEnc.c -- Xz Encode |
| 2 | 2024-03-01 : Igor Pavlov : Public domain */ | 2 | : Igor Pavlov : Public domain */ |
| 3 | 3 | ||
| 4 | #include "Precomp.h" | 4 | #include "Precomp.h" |
| 5 | 5 | ||
| @@ -411,6 +411,7 @@ static SRes SeqInFilter_Read(ISeqInStreamPtr pp, void *data, size_t *size) | |||
| 411 | } | 411 | } |
| 412 | } | 412 | } |
| 413 | 413 | ||
| 414 | Z7_FORCE_INLINE | ||
| 414 | static void SeqInFilter_Construct(CSeqInFilter *p) | 415 | static void SeqInFilter_Construct(CSeqInFilter *p) |
| 415 | { | 416 | { |
| 416 | p->buf = NULL; | 417 | p->buf = NULL; |
| @@ -418,6 +419,7 @@ static void SeqInFilter_Construct(CSeqInFilter *p) | |||
| 418 | p->vt.Read = SeqInFilter_Read; | 419 | p->vt.Read = SeqInFilter_Read; |
| 419 | } | 420 | } |
| 420 | 421 | ||
| 422 | Z7_FORCE_INLINE | ||
| 421 | static void SeqInFilter_Free(CSeqInFilter *p, ISzAllocPtr alloc) | 423 | static void SeqInFilter_Free(CSeqInFilter *p, ISzAllocPtr alloc) |
| 422 | { | 424 | { |
| 423 | if (p->StateCoder.p) | 425 | if (p->StateCoder.p) |
| @@ -507,6 +509,7 @@ void XzFilterProps_Init(CXzFilterProps *p) | |||
| 507 | void XzProps_Init(CXzProps *p) | 509 | void XzProps_Init(CXzProps *p) |
| 508 | { | 510 | { |
| 509 | p->checkId = XZ_CHECK_CRC32; | 511 | p->checkId = XZ_CHECK_CRC32; |
| 512 | p->numThreadGroups = 0; | ||
| 510 | p->blockSize = XZ_PROPS_BLOCK_SIZE_AUTO; | 513 | p->blockSize = XZ_PROPS_BLOCK_SIZE_AUTO; |
| 511 | p->numBlockThreads_Reduced = -1; | 514 | p->numBlockThreads_Reduced = -1; |
| 512 | p->numBlockThreads_Max = -1; | 515 | p->numBlockThreads_Max = -1; |
| @@ -689,6 +692,7 @@ typedef struct | |||
| 689 | } CLzma2WithFilters; | 692 | } CLzma2WithFilters; |
| 690 | 693 | ||
| 691 | 694 | ||
| 695 | Z7_FORCE_INLINE | ||
| 692 | static void Lzma2WithFilters_Construct(CLzma2WithFilters *p) | 696 | static void Lzma2WithFilters_Construct(CLzma2WithFilters *p) |
| 693 | { | 697 | { |
| 694 | p->lzma2 = NULL; | 698 | p->lzma2 = NULL; |
| @@ -712,6 +716,7 @@ static SRes Lzma2WithFilters_Create(CLzma2WithFilters *p, ISzAllocPtr alloc, ISz | |||
| 712 | } | 716 | } |
| 713 | 717 | ||
| 714 | 718 | ||
| 719 | Z7_FORCE_INLINE | ||
| 715 | static void Lzma2WithFilters_Free(CLzma2WithFilters *p, ISzAllocPtr alloc) | 720 | static void Lzma2WithFilters_Free(CLzma2WithFilters *p, ISzAllocPtr alloc) |
| 716 | { | 721 | { |
| 717 | #ifdef USE_SUBBLOCK | 722 | #ifdef USE_SUBBLOCK |
| @@ -1236,6 +1241,7 @@ SRes XzEnc_Encode(CXzEncHandle p, ISeqOutStreamPtr outStream, ISeqInStreamPtr in | |||
| 1236 | } | 1241 | } |
| 1237 | 1242 | ||
| 1238 | p->mtCoder.numThreadsMax = (unsigned)props->numBlockThreads_Max; | 1243 | p->mtCoder.numThreadsMax = (unsigned)props->numBlockThreads_Max; |
| 1244 | p->mtCoder.numThreadGroups = props->numThreadGroups; | ||
| 1239 | p->mtCoder.expectedDataSize = p->expectedDataSize; | 1245 | p->mtCoder.expectedDataSize = p->expectedDataSize; |
| 1240 | 1246 | ||
| 1241 | RINOK(MtCoder_Code(&p->mtCoder)) | 1247 | RINOK(MtCoder_Code(&p->mtCoder)) |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* XzEnc.h -- Xz Encode | 1 | /* XzEnc.h -- Xz Encode |
| 2 | 2023-04-13 : Igor Pavlov : Public domain */ | 2 | : Igor Pavlov : Public domain */ |
| 3 | 3 | ||
| 4 | #ifndef ZIP7_INC_XZ_ENC_H | 4 | #ifndef ZIP7_INC_XZ_ENC_H |
| 5 | #define ZIP7_INC_XZ_ENC_H | 5 | #define ZIP7_INC_XZ_ENC_H |
| @@ -31,6 +31,7 @@ typedef struct | |||
| 31 | CLzma2EncProps lzma2Props; | 31 | CLzma2EncProps lzma2Props; |
| 32 | CXzFilterProps filterProps; | 32 | CXzFilterProps filterProps; |
| 33 | unsigned checkId; | 33 | unsigned checkId; |
| 34 | unsigned numThreadGroups; // 0 : no groups | ||
| 34 | UInt64 blockSize; | 35 | UInt64 blockSize; |
| 35 | int numBlockThreads_Reduced; | 36 | int numBlockThreads_Reduced; |
| 36 | int numBlockThreads_Max; | 37 | int numBlockThreads_Max; |
| @@ -1,38 +1,39 @@ | |||
| 1 | /* XzIn.c - Xz input | 1 | /* XzIn.c - Xz input |
| 2 | 2023-09-07 : Igor Pavlov : Public domain */ | 2 | : Igor Pavlov : Public domain */ |
| 3 | 3 | ||
| 4 | #include "Precomp.h" | 4 | #include "Precomp.h" |
| 5 | 5 | ||
| 6 | #include <string.h> | 6 | #include <string.h> |
| 7 | 7 | ||
| 8 | #include "7zCrc.h" | 8 | #include "7zCrc.h" |
| 9 | #include "CpuArch.h" | ||
| 10 | #include "Xz.h" | 9 | #include "Xz.h" |
| 10 | #include "CpuArch.h" | ||
| 11 | 11 | ||
| 12 | /* | 12 | #define XZ_FOOTER_12B_ALIGNED16_SIG_CHECK(p) \ |
| 13 | #define XZ_FOOTER_SIG_CHECK(p) (memcmp((p), XZ_FOOTER_SIG, XZ_FOOTER_SIG_SIZE) == 0) | 13 | (GetUi16a((const Byte *)(const void *)(p) + 10) == \ |
| 14 | */ | 14 | (XZ_FOOTER_SIG_0 | (XZ_FOOTER_SIG_1 << 8))) |
| 15 | #define XZ_FOOTER_SIG_CHECK(p) ((p)[0] == XZ_FOOTER_SIG_0 && (p)[1] == XZ_FOOTER_SIG_1) | ||
| 16 | |||
| 17 | 15 | ||
| 18 | SRes Xz_ReadHeader(CXzStreamFlags *p, ISeqInStreamPtr inStream) | 16 | SRes Xz_ReadHeader(CXzStreamFlags *p, ISeqInStreamPtr inStream) |
| 19 | { | 17 | { |
| 20 | Byte sig[XZ_STREAM_HEADER_SIZE]; | 18 | UInt32 data32[XZ_STREAM_HEADER_SIZE / 4]; |
| 21 | size_t processedSize = XZ_STREAM_HEADER_SIZE; | 19 | size_t processedSize = XZ_STREAM_HEADER_SIZE; |
| 22 | RINOK(SeqInStream_ReadMax(inStream, sig, &processedSize)) | 20 | RINOK(SeqInStream_ReadMax(inStream, data32, &processedSize)) |
| 23 | if (processedSize != XZ_STREAM_HEADER_SIZE | 21 | if (processedSize != XZ_STREAM_HEADER_SIZE |
| 24 | || memcmp(sig, XZ_SIG, XZ_SIG_SIZE) != 0) | 22 | || memcmp(data32, XZ_SIG, XZ_SIG_SIZE) != 0) |
| 25 | return SZ_ERROR_NO_ARCHIVE; | 23 | return SZ_ERROR_NO_ARCHIVE; |
| 26 | return Xz_ParseHeader(p, sig); | 24 | return Xz_ParseHeader(p, (const Byte *)(const void *)data32); |
| 27 | } | 25 | } |
| 28 | 26 | ||
| 29 | #define READ_VARINT_AND_CHECK(buf, pos, size, res) \ | 27 | #define READ_VARINT_AND_CHECK(buf, size, res) \ |
| 30 | { const unsigned s = Xz_ReadVarInt(buf + pos, size - pos, res); \ | 28 | { const unsigned s = Xz_ReadVarInt(buf, size, res); \ |
| 31 | if (s == 0) return SZ_ERROR_ARCHIVE; \ | 29 | if (s == 0) return SZ_ERROR_ARCHIVE; \ |
| 32 | pos += s; } | 30 | size -= s; \ |
| 31 | buf += s; \ | ||
| 32 | } | ||
| 33 | 33 | ||
| 34 | SRes XzBlock_ReadHeader(CXzBlock *p, ISeqInStreamPtr inStream, BoolInt *isIndex, UInt32 *headerSizeRes) | 34 | SRes XzBlock_ReadHeader(CXzBlock *p, ISeqInStreamPtr inStream, BoolInt *isIndex, UInt32 *headerSizeRes) |
| 35 | { | 35 | { |
| 36 | MY_ALIGN(4) | ||
| 36 | Byte header[XZ_BLOCK_HEADER_SIZE_MAX]; | 37 | Byte header[XZ_BLOCK_HEADER_SIZE_MAX]; |
| 37 | unsigned headerSize; | 38 | unsigned headerSize; |
| 38 | *headerSizeRes = 0; | 39 | *headerSizeRes = 0; |
| @@ -57,8 +58,12 @@ SRes XzBlock_ReadHeader(CXzBlock *p, ISeqInStreamPtr inStream, BoolInt *isIndex, | |||
| 57 | return XzBlock_Parse(p, header); | 58 | return XzBlock_Parse(p, header); |
| 58 | } | 59 | } |
| 59 | 60 | ||
| 61 | |||
| 60 | #define ADD_SIZE_CHECK(size, val) \ | 62 | #define ADD_SIZE_CHECK(size, val) \ |
| 61 | { const UInt64 newSize = size + (val); if (newSize < size) return XZ_SIZE_OVERFLOW; size = newSize; } | 63 | { const UInt64 newSize = size + (val); \ |
| 64 | if (newSize < size) return XZ_SIZE_OVERFLOW; \ | ||
| 65 | size = newSize; \ | ||
| 66 | } | ||
| 62 | 67 | ||
| 63 | UInt64 Xz_GetUnpackSize(const CXzStream *p) | 68 | UInt64 Xz_GetUnpackSize(const CXzStream *p) |
| 64 | { | 69 | { |
| @@ -82,76 +87,85 @@ UInt64 Xz_GetPackSize(const CXzStream *p) | |||
| 82 | return size; | 87 | return size; |
| 83 | } | 88 | } |
| 84 | 89 | ||
| 85 | /* | ||
| 86 | SRes XzBlock_ReadFooter(CXzBlock *p, CXzStreamFlags f, ISeqInStreamPtr inStream) | ||
| 87 | { | ||
| 88 | return SeqInStream_Read(inStream, p->check, XzFlags_GetCheckSize(f)); | ||
| 89 | } | ||
| 90 | */ | ||
| 91 | 90 | ||
| 92 | static SRes Xz_ReadIndex2(CXzStream *p, const Byte *buf, size_t size, ISzAllocPtr alloc) | 91 | // input; |
| 92 | // CXzStream (p) is empty object. | ||
| 93 | // size != 0 | ||
| 94 | // (size & 3) == 0 | ||
| 95 | // (buf) is aligned for at least 4 bytes. | ||
| 96 | // output: | ||
| 97 | // p->numBlocks is number of allocated items in p->blocks | ||
| 98 | // p->blocks[*] values must be ignored, if function returns error. | ||
| 99 | static SRes Xz_ParseIndex(CXzStream *p, const Byte *buf, size_t size, ISzAllocPtr alloc) | ||
| 93 | { | 100 | { |
| 94 | size_t numBlocks, pos = 1; | 101 | size_t numBlocks; |
| 95 | UInt32 crc; | ||
| 96 | |||
| 97 | if (size < 5 || buf[0] != 0) | 102 | if (size < 5 || buf[0] != 0) |
| 98 | return SZ_ERROR_ARCHIVE; | 103 | return SZ_ERROR_ARCHIVE; |
| 99 | |||
| 100 | size -= 4; | 104 | size -= 4; |
| 101 | crc = CrcCalc(buf, size); | 105 | { |
| 102 | if (crc != GetUi32(buf + size)) | 106 | const UInt32 crc = CrcCalc(buf, size); |
| 103 | return SZ_ERROR_ARCHIVE; | 107 | if (crc != GetUi32a(buf + size)) |
| 104 | 108 | return SZ_ERROR_ARCHIVE; | |
| 109 | } | ||
| 110 | buf++; | ||
| 111 | size--; | ||
| 105 | { | 112 | { |
| 106 | UInt64 numBlocks64; | 113 | UInt64 numBlocks64; |
| 107 | READ_VARINT_AND_CHECK(buf, pos, size, &numBlocks64) | 114 | READ_VARINT_AND_CHECK(buf, size, &numBlocks64) |
| 108 | numBlocks = (size_t)numBlocks64; | 115 | // (numBlocks64) is 63-bit value, so we can calculate (numBlocks64 * 2): |
| 109 | if (numBlocks != numBlocks64 || numBlocks * 2 > size) | 116 | if (numBlocks64 * 2 > size) |
| 110 | return SZ_ERROR_ARCHIVE; | 117 | return SZ_ERROR_ARCHIVE; |
| 118 | if (numBlocks64 >= ((size_t)1 << (sizeof(size_t) * 8 - 1)) / sizeof(CXzBlockSizes)) | ||
| 119 | return SZ_ERROR_MEM; // SZ_ERROR_ARCHIVE | ||
| 120 | numBlocks = (size_t)numBlocks64; | ||
| 111 | } | 121 | } |
| 112 | 122 | // Xz_Free(p, alloc); // it's optional, because (p) is empty already | |
| 113 | Xz_Free(p, alloc); | 123 | if (numBlocks) |
| 114 | if (numBlocks != 0) | ||
| 115 | { | 124 | { |
| 116 | size_t i; | 125 | CXzBlockSizes *blocks = (CXzBlockSizes *)ISzAlloc_Alloc(alloc, sizeof(CXzBlockSizes) * numBlocks); |
| 117 | p->numBlocks = numBlocks; | 126 | if (!blocks) |
| 118 | p->blocks = (CXzBlockSizes *)ISzAlloc_Alloc(alloc, sizeof(CXzBlockSizes) * numBlocks); | ||
| 119 | if (!p->blocks) | ||
| 120 | return SZ_ERROR_MEM; | 127 | return SZ_ERROR_MEM; |
| 121 | for (i = 0; i < numBlocks; i++) | 128 | p->blocks = blocks; |
| 129 | p->numBlocks = numBlocks; | ||
| 130 | // the caller will call Xz_Free() in case of error | ||
| 131 | do | ||
| 122 | { | 132 | { |
| 123 | CXzBlockSizes *block = &p->blocks[i]; | 133 | READ_VARINT_AND_CHECK(buf, size, &blocks->totalSize) |
| 124 | READ_VARINT_AND_CHECK(buf, pos, size, &block->totalSize) | 134 | READ_VARINT_AND_CHECK(buf, size, &blocks->unpackSize) |
| 125 | READ_VARINT_AND_CHECK(buf, pos, size, &block->unpackSize) | 135 | if (blocks->totalSize == 0) |
| 126 | if (block->totalSize == 0) | ||
| 127 | return SZ_ERROR_ARCHIVE; | 136 | return SZ_ERROR_ARCHIVE; |
| 137 | blocks++; | ||
| 128 | } | 138 | } |
| 139 | while (--numBlocks); | ||
| 129 | } | 140 | } |
| 130 | while ((pos & 3) != 0) | 141 | if (size >= 4) |
| 131 | if (buf[pos++] != 0) | 142 | return SZ_ERROR_ARCHIVE; |
| 143 | while (size) | ||
| 144 | if (buf[--size]) | ||
| 132 | return SZ_ERROR_ARCHIVE; | 145 | return SZ_ERROR_ARCHIVE; |
| 133 | return (pos == size) ? SZ_OK : SZ_ERROR_ARCHIVE; | 146 | return SZ_OK; |
| 134 | } | 147 | } |
| 135 | 148 | ||
| 149 | |||
| 150 | /* | ||
| 136 | static SRes Xz_ReadIndex(CXzStream *p, ILookInStreamPtr stream, UInt64 indexSize, ISzAllocPtr alloc) | 151 | static SRes Xz_ReadIndex(CXzStream *p, ILookInStreamPtr stream, UInt64 indexSize, ISzAllocPtr alloc) |
| 137 | { | 152 | { |
| 138 | SRes res; | 153 | SRes res; |
| 139 | size_t size; | 154 | size_t size; |
| 140 | Byte *buf; | 155 | Byte *buf; |
| 141 | if (indexSize > ((UInt32)1 << 31)) | 156 | if (indexSize >= ((size_t)1 << (sizeof(size_t) * 8 - 1))) |
| 142 | return SZ_ERROR_UNSUPPORTED; | 157 | return SZ_ERROR_MEM; // SZ_ERROR_ARCHIVE |
| 143 | size = (size_t)indexSize; | 158 | size = (size_t)indexSize; |
| 144 | if (size != indexSize) | ||
| 145 | return SZ_ERROR_UNSUPPORTED; | ||
| 146 | buf = (Byte *)ISzAlloc_Alloc(alloc, size); | 159 | buf = (Byte *)ISzAlloc_Alloc(alloc, size); |
| 147 | if (!buf) | 160 | if (!buf) |
| 148 | return SZ_ERROR_MEM; | 161 | return SZ_ERROR_MEM; |
| 149 | res = LookInStream_Read2(stream, buf, size, SZ_ERROR_UNSUPPORTED); | 162 | res = LookInStream_Read2(stream, buf, size, SZ_ERROR_UNSUPPORTED); |
| 150 | if (res == SZ_OK) | 163 | if (res == SZ_OK) |
| 151 | res = Xz_ReadIndex2(p, buf, size, alloc); | 164 | res = Xz_ParseIndex(p, buf, size, alloc); |
| 152 | ISzAlloc_Free(alloc, buf); | 165 | ISzAlloc_Free(alloc, buf); |
| 153 | return res; | 166 | return res; |
| 154 | } | 167 | } |
| 168 | */ | ||
| 155 | 169 | ||
| 156 | static SRes LookInStream_SeekRead_ForArc(ILookInStreamPtr stream, UInt64 offset, void *buf, size_t size) | 170 | static SRes LookInStream_SeekRead_ForArc(ILookInStreamPtr stream, UInt64 offset, void *buf, size_t size) |
| 157 | { | 171 | { |
| @@ -160,84 +174,102 @@ static SRes LookInStream_SeekRead_ForArc(ILookInStreamPtr stream, UInt64 offset, | |||
| 160 | /* return LookInStream_Read2(stream, buf, size, SZ_ERROR_NO_ARCHIVE); */ | 174 | /* return LookInStream_Read2(stream, buf, size, SZ_ERROR_NO_ARCHIVE); */ |
| 161 | } | 175 | } |
| 162 | 176 | ||
| 177 | |||
| 178 | /* | ||
| 179 | in: | ||
| 180 | (*startOffset) is position in (stream) where xz_stream must be finished. | ||
| 181 | out: | ||
| 182 | if returns SZ_OK, then (*startOffset) is position in stream that shows start of xz_stream. | ||
| 183 | */ | ||
| 163 | static SRes Xz_ReadBackward(CXzStream *p, ILookInStreamPtr stream, Int64 *startOffset, ISzAllocPtr alloc) | 184 | static SRes Xz_ReadBackward(CXzStream *p, ILookInStreamPtr stream, Int64 *startOffset, ISzAllocPtr alloc) |
| 164 | { | 185 | { |
| 165 | UInt64 indexSize; | 186 | #define TEMP_BUF_SIZE (1 << 10) |
| 166 | Byte buf[XZ_STREAM_FOOTER_SIZE]; | 187 | UInt32 buf32[TEMP_BUF_SIZE / 4]; |
| 167 | UInt64 pos = (UInt64)*startOffset; | 188 | UInt64 pos = (UInt64)*startOffset; |
| 168 | 189 | ||
| 169 | if ((pos & 3) != 0 || pos < XZ_STREAM_FOOTER_SIZE) | 190 | if ((pos & 3) || pos < XZ_STREAM_FOOTER_SIZE) |
| 170 | return SZ_ERROR_NO_ARCHIVE; | 191 | return SZ_ERROR_NO_ARCHIVE; |
| 171 | |||
| 172 | pos -= XZ_STREAM_FOOTER_SIZE; | 192 | pos -= XZ_STREAM_FOOTER_SIZE; |
| 173 | RINOK(LookInStream_SeekRead_ForArc(stream, pos, buf, XZ_STREAM_FOOTER_SIZE)) | 193 | RINOK(LookInStream_SeekRead_ForArc(stream, pos, buf32, XZ_STREAM_FOOTER_SIZE)) |
| 174 | 194 | ||
| 175 | if (!XZ_FOOTER_SIG_CHECK(buf + 10)) | 195 | if (!XZ_FOOTER_12B_ALIGNED16_SIG_CHECK(buf32)) |
| 176 | { | 196 | { |
| 177 | UInt32 total = 0; | ||
| 178 | pos += XZ_STREAM_FOOTER_SIZE; | 197 | pos += XZ_STREAM_FOOTER_SIZE; |
| 179 | |||
| 180 | for (;;) | 198 | for (;;) |
| 181 | { | 199 | { |
| 182 | size_t i; | 200 | // pos != 0 |
| 183 | #define TEMP_BUF_SIZE (1 << 10) | 201 | // (pos & 3) == 0 |
| 184 | Byte temp[TEMP_BUF_SIZE]; | 202 | size_t i = pos >= TEMP_BUF_SIZE ? TEMP_BUF_SIZE : (size_t)pos; |
| 185 | |||
| 186 | i = (pos > TEMP_BUF_SIZE) ? TEMP_BUF_SIZE : (size_t)pos; | ||
| 187 | pos -= i; | 203 | pos -= i; |
| 188 | RINOK(LookInStream_SeekRead_ForArc(stream, pos, temp, i)) | 204 | RINOK(LookInStream_SeekRead_ForArc(stream, pos, buf32, i)) |
| 189 | total += (UInt32)i; | 205 | i /= 4; |
| 190 | for (; i != 0; i--) | 206 | do |
| 191 | if (temp[i - 1] != 0) | 207 | if (buf32[i - 1] != 0) |
| 192 | break; | 208 | break; |
| 193 | if (i != 0) | 209 | while (--i); |
| 194 | { | 210 | |
| 195 | if ((i & 3) != 0) | 211 | pos += i * 4; |
| 196 | return SZ_ERROR_NO_ARCHIVE; | 212 | #define XZ_STREAM_BACKWARD_READING_PAD_MAX (1 << 16) |
| 197 | pos += i; | 213 | // here we don't support rare case with big padding for xz stream. |
| 198 | break; | 214 | // so we have padding limit for backward reading. |
| 199 | } | 215 | if ((UInt64)*startOffset - pos > XZ_STREAM_BACKWARD_READING_PAD_MAX) |
| 200 | if (pos < XZ_STREAM_FOOTER_SIZE || total > (1 << 16)) | ||
| 201 | return SZ_ERROR_NO_ARCHIVE; | 216 | return SZ_ERROR_NO_ARCHIVE; |
| 217 | if (i) | ||
| 218 | break; | ||
| 202 | } | 219 | } |
| 203 | 220 | // we try to open xz stream after skipping zero padding. | |
| 221 | // ((UInt64)*startOffset == pos) is possible here! | ||
| 204 | if (pos < XZ_STREAM_FOOTER_SIZE) | 222 | if (pos < XZ_STREAM_FOOTER_SIZE) |
| 205 | return SZ_ERROR_NO_ARCHIVE; | 223 | return SZ_ERROR_NO_ARCHIVE; |
| 206 | pos -= XZ_STREAM_FOOTER_SIZE; | 224 | pos -= XZ_STREAM_FOOTER_SIZE; |
| 207 | RINOK(LookInStream_SeekRead_ForArc(stream, pos, buf, XZ_STREAM_FOOTER_SIZE)) | 225 | RINOK(LookInStream_SeekRead_ForArc(stream, pos, buf32, XZ_STREAM_FOOTER_SIZE)) |
| 208 | if (!XZ_FOOTER_SIG_CHECK(buf + 10)) | 226 | if (!XZ_FOOTER_12B_ALIGNED16_SIG_CHECK(buf32)) |
| 209 | return SZ_ERROR_NO_ARCHIVE; | 227 | return SZ_ERROR_NO_ARCHIVE; |
| 210 | } | 228 | } |
| 211 | 229 | ||
| 212 | p->flags = (CXzStreamFlags)GetBe16(buf + 8); | 230 | p->flags = (CXzStreamFlags)GetBe16a(buf32 + 2); |
| 213 | |||
| 214 | if (!XzFlags_IsSupported(p->flags)) | 231 | if (!XzFlags_IsSupported(p->flags)) |
| 215 | return SZ_ERROR_UNSUPPORTED; | 232 | return SZ_ERROR_UNSUPPORTED; |
| 216 | |||
| 217 | { | 233 | { |
| 218 | /* to eliminate GCC 6.3 warning: | 234 | /* to eliminate GCC 6.3 warning: |
| 219 | dereferencing type-punned pointer will break strict-aliasing rules */ | 235 | dereferencing type-punned pointer will break strict-aliasing rules */ |
| 220 | const Byte *buf_ptr = buf; | 236 | const UInt32 *buf_ptr = buf32; |
| 221 | if (GetUi32(buf_ptr) != CrcCalc(buf + 4, 6)) | 237 | if (GetUi32a(buf_ptr) != CrcCalc(buf32 + 1, 6)) |
| 222 | return SZ_ERROR_ARCHIVE; | 238 | return SZ_ERROR_ARCHIVE; |
| 223 | } | 239 | } |
| 224 | |||
| 225 | indexSize = ((UInt64)GetUi32(buf + 4) + 1) << 2; | ||
| 226 | |||
| 227 | if (pos < indexSize) | ||
| 228 | return SZ_ERROR_ARCHIVE; | ||
| 229 | |||
| 230 | pos -= indexSize; | ||
| 231 | RINOK(LookInStream_SeekTo(stream, pos)) | ||
| 232 | RINOK(Xz_ReadIndex(p, stream, indexSize, alloc)) | ||
| 233 | |||
| 234 | { | 240 | { |
| 235 | UInt64 totalSize = Xz_GetPackSize(p); | 241 | const UInt64 indexSize = ((UInt64)GetUi32a(buf32 + 1) + 1) << 2; |
| 236 | if (totalSize == XZ_SIZE_OVERFLOW | 242 | if (pos < indexSize) |
| 237 | || totalSize >= ((UInt64)1 << 63) | ||
| 238 | || pos < totalSize + XZ_STREAM_HEADER_SIZE) | ||
| 239 | return SZ_ERROR_ARCHIVE; | 243 | return SZ_ERROR_ARCHIVE; |
| 240 | pos -= (totalSize + XZ_STREAM_HEADER_SIZE); | 244 | pos -= indexSize; |
| 245 | // v25.00: relaxed indexSize check. We allow big index table. | ||
| 246 | // if (indexSize > ((UInt32)1 << 31)) | ||
| 247 | if (indexSize >= ((size_t)1 << (sizeof(size_t) * 8 - 1))) | ||
| 248 | return SZ_ERROR_MEM; // SZ_ERROR_ARCHIVE | ||
| 249 | RINOK(LookInStream_SeekTo(stream, pos)) | ||
| 250 | // RINOK(Xz_ReadIndex(p, stream, indexSize, alloc)) | ||
| 251 | { | ||
| 252 | SRes res; | ||
| 253 | const size_t size = (size_t)indexSize; | ||
| 254 | // if (size != indexSize) return SZ_ERROR_UNSUPPORTED; | ||
| 255 | Byte *buf = (Byte *)ISzAlloc_Alloc(alloc, size); | ||
| 256 | if (!buf) | ||
| 257 | return SZ_ERROR_MEM; | ||
| 258 | res = LookInStream_Read2(stream, buf, size, SZ_ERROR_UNSUPPORTED); | ||
| 259 | if (res == SZ_OK) | ||
| 260 | res = Xz_ParseIndex(p, buf, size, alloc); | ||
| 261 | ISzAlloc_Free(alloc, buf); | ||
| 262 | RINOK(res) | ||
| 263 | } | ||
| 264 | } | ||
| 265 | { | ||
| 266 | UInt64 total = Xz_GetPackSize(p); | ||
| 267 | if (total == XZ_SIZE_OVERFLOW || total >= ((UInt64)1 << 63)) | ||
| 268 | return SZ_ERROR_ARCHIVE; | ||
| 269 | total += XZ_STREAM_HEADER_SIZE; | ||
| 270 | if (pos < total) | ||
| 271 | return SZ_ERROR_ARCHIVE; | ||
| 272 | pos -= total; | ||
| 241 | RINOK(LookInStream_SeekTo(stream, pos)) | 273 | RINOK(LookInStream_SeekTo(stream, pos)) |
| 242 | *startOffset = (Int64)pos; | 274 | *startOffset = (Int64)pos; |
| 243 | } | 275 | } |
| @@ -246,7 +278,6 @@ static SRes Xz_ReadBackward(CXzStream *p, ILookInStreamPtr stream, Int64 *startO | |||
| 246 | CSecToRead secToRead; | 278 | CSecToRead secToRead; |
| 247 | SecToRead_CreateVTable(&secToRead); | 279 | SecToRead_CreateVTable(&secToRead); |
| 248 | secToRead.realStream = stream; | 280 | secToRead.realStream = stream; |
| 249 | |||
| 250 | RINOK(Xz_ReadHeader(&headerFlags, &secToRead.vt)) | 281 | RINOK(Xz_ReadHeader(&headerFlags, &secToRead.vt)) |
| 251 | return (p->flags == headerFlags) ? SZ_OK : SZ_ERROR_ARCHIVE; | 282 | return (p->flags == headerFlags) ? SZ_OK : SZ_ERROR_ARCHIVE; |
| 252 | } | 283 | } |
| @@ -257,8 +288,7 @@ static SRes Xz_ReadBackward(CXzStream *p, ILookInStreamPtr stream, Int64 *startO | |||
| 257 | 288 | ||
| 258 | void Xzs_Construct(CXzs *p) | 289 | void Xzs_Construct(CXzs *p) |
| 259 | { | 290 | { |
| 260 | p->num = p->numAllocated = 0; | 291 | Xzs_CONSTRUCT(p) |
| 261 | p->streams = 0; | ||
| 262 | } | 292 | } |
| 263 | 293 | ||
| 264 | void Xzs_Free(CXzs *p, ISzAllocPtr alloc) | 294 | void Xzs_Free(CXzs *p, ISzAllocPtr alloc) |
| @@ -268,7 +298,7 @@ void Xzs_Free(CXzs *p, ISzAllocPtr alloc) | |||
| 268 | Xz_Free(&p->streams[i], alloc); | 298 | Xz_Free(&p->streams[i], alloc); |
| 269 | ISzAlloc_Free(alloc, p->streams); | 299 | ISzAlloc_Free(alloc, p->streams); |
| 270 | p->num = p->numAllocated = 0; | 300 | p->num = p->numAllocated = 0; |
| 271 | p->streams = 0; | 301 | p->streams = NULL; |
| 272 | } | 302 | } |
| 273 | 303 | ||
| 274 | UInt64 Xzs_GetNumBlocks(const CXzs *p) | 304 | UInt64 Xzs_GetNumBlocks(const CXzs *p) |
| @@ -307,34 +337,49 @@ UInt64 Xzs_GetPackSize(const CXzs *p) | |||
| 307 | SRes Xzs_ReadBackward(CXzs *p, ILookInStreamPtr stream, Int64 *startOffset, ICompressProgressPtr progress, ISzAllocPtr alloc) | 337 | SRes Xzs_ReadBackward(CXzs *p, ILookInStreamPtr stream, Int64 *startOffset, ICompressProgressPtr progress, ISzAllocPtr alloc) |
| 308 | { | 338 | { |
| 309 | Int64 endOffset = 0; | 339 | Int64 endOffset = 0; |
| 340 | // it's supposed that CXzs object is empty here. | ||
| 341 | // if CXzs object is not empty, it will add new streams to that non-empty object. | ||
| 342 | // Xzs_Free(p, alloc); // it's optional call to empty CXzs object. | ||
| 310 | RINOK(ILookInStream_Seek(stream, &endOffset, SZ_SEEK_END)) | 343 | RINOK(ILookInStream_Seek(stream, &endOffset, SZ_SEEK_END)) |
| 311 | *startOffset = endOffset; | 344 | *startOffset = endOffset; |
| 312 | for (;;) | 345 | for (;;) |
| 313 | { | 346 | { |
| 314 | CXzStream st; | 347 | CXzStream st; |
| 315 | SRes res; | 348 | SRes res; |
| 316 | Xz_Construct(&st); | 349 | Xz_CONSTRUCT(&st) |
| 317 | res = Xz_ReadBackward(&st, stream, startOffset, alloc); | 350 | res = Xz_ReadBackward(&st, stream, startOffset, alloc); |
| 351 | // if (res == SZ_OK), then (*startOffset) is start offset of new stream if | ||
| 352 | // if (res != SZ_OK), then (*startOffset) is unchend or it's expected start offset of stream with error | ||
| 318 | st.startOffset = (UInt64)*startOffset; | 353 | st.startOffset = (UInt64)*startOffset; |
| 319 | RINOK(res) | 354 | // we must store (st) object to array, or we must free (st) local object. |
| 355 | if (res != SZ_OK) | ||
| 356 | { | ||
| 357 | Xz_Free(&st, alloc); | ||
| 358 | return res; | ||
| 359 | } | ||
| 320 | if (p->num == p->numAllocated) | 360 | if (p->num == p->numAllocated) |
| 321 | { | 361 | { |
| 322 | const size_t newNum = p->num + p->num / 4 + 1; | 362 | const size_t newNum = p->num + p->num / 4 + 1; |
| 323 | void *data = ISzAlloc_Alloc(alloc, newNum * sizeof(CXzStream)); | 363 | void *data = ISzAlloc_Alloc(alloc, newNum * sizeof(CXzStream)); |
| 324 | if (!data) | 364 | if (!data) |
| 365 | { | ||
| 366 | Xz_Free(&st, alloc); | ||
| 325 | return SZ_ERROR_MEM; | 367 | return SZ_ERROR_MEM; |
| 368 | } | ||
| 326 | p->numAllocated = newNum; | 369 | p->numAllocated = newNum; |
| 327 | if (p->num != 0) | 370 | if (p->num != 0) |
| 328 | memcpy(data, p->streams, p->num * sizeof(CXzStream)); | 371 | memcpy(data, p->streams, p->num * sizeof(CXzStream)); |
| 329 | ISzAlloc_Free(alloc, p->streams); | 372 | ISzAlloc_Free(alloc, p->streams); |
| 330 | p->streams = (CXzStream *)data; | 373 | p->streams = (CXzStream *)data; |
| 331 | } | 374 | } |
| 375 | // we use direct copying of raw data from local variable (st) to object in array. | ||
| 376 | // so we don't need to call Xz_Free(&st, alloc) after copying and after p->num++ | ||
| 332 | p->streams[p->num++] = st; | 377 | p->streams[p->num++] = st; |
| 333 | if (*startOffset == 0) | 378 | if (*startOffset == 0) |
| 334 | break; | 379 | return SZ_OK; |
| 335 | RINOK(LookInStream_SeekTo(stream, (UInt64)*startOffset)) | 380 | // seek operation is optional: |
| 381 | // RINOK(LookInStream_SeekTo(stream, (UInt64)*startOffset)) | ||
| 336 | if (progress && ICompressProgress_Progress(progress, (UInt64)(endOffset - *startOffset), (UInt64)(Int64)-1) != SZ_OK) | 382 | if (progress && ICompressProgress_Progress(progress, (UInt64)(endOffset - *startOffset), (UInt64)(Int64)-1) != SZ_OK) |
| 337 | return SZ_ERROR_PROGRESS; | 383 | return SZ_ERROR_PROGRESS; |
| 338 | } | 384 | } |
| 339 | return SZ_OK; | ||
| 340 | } | 385 | } |
diff --git a/CPP/7zip/7zip_gcc.mak b/CPP/7zip/7zip_gcc.mak index bcb06a0..12f1ef2 100644 --- a/CPP/7zip/7zip_gcc.mak +++ b/CPP/7zip/7zip_gcc.mak | |||
| @@ -1245,8 +1245,6 @@ $O/Sha512.o: ../../../../C/Sha512.c | |||
| 1245 | $(CC) $(CFLAGS) $< | 1245 | $(CC) $(CFLAGS) $< |
| 1246 | $O/Sha512Opt.o: ../../../../C/Sha512Opt.c | 1246 | $O/Sha512Opt.o: ../../../../C/Sha512Opt.c |
| 1247 | $(CC) $(CFLAGS) $< | 1247 | $(CC) $(CFLAGS) $< |
| 1248 | $O/Sort.o: ../../../../C/Sort.c | ||
| 1249 | $(CC) $(CFLAGS) $< | ||
| 1250 | $O/SwapBytes.o: ../../../../C/SwapBytes.c | 1248 | $O/SwapBytes.o: ../../../../C/SwapBytes.c |
| 1251 | $(CC) $(CFLAGS) $< | 1249 | $(CC) $(CFLAGS) $< |
| 1252 | $O/Xxh64.o: ../../../../C/Xxh64.c | 1250 | $O/Xxh64.o: ../../../../C/Xxh64.c |
| @@ -1285,6 +1283,8 @@ $O/Sha1Opt.o: ../../../../Asm/x86/Sha1Opt.asm | |||
| 1285 | $(MY_ASM) $(AFLAGS) $< | 1283 | $(MY_ASM) $(AFLAGS) $< |
| 1286 | $O/Sha256Opt.o: ../../../../Asm/x86/Sha256Opt.asm | 1284 | $O/Sha256Opt.o: ../../../../Asm/x86/Sha256Opt.asm |
| 1287 | $(MY_ASM) $(AFLAGS) $< | 1285 | $(MY_ASM) $(AFLAGS) $< |
| 1286 | $O/Sort.o: ../../../../Asm/x86/Sort.asm | ||
| 1287 | $(MY_ASM) $(AFLAGS) $< | ||
| 1288 | 1288 | ||
| 1289 | ifndef USE_JWASM | 1289 | ifndef USE_JWASM |
| 1290 | USE_X86_ASM_AES=1 | 1290 | USE_X86_ASM_AES=1 |
| @@ -1299,6 +1299,8 @@ $O/Sha1Opt.o: ../../../../C/Sha1Opt.c | |||
| 1299 | $(CC) $(CFLAGS) $< | 1299 | $(CC) $(CFLAGS) $< |
| 1300 | $O/Sha256Opt.o: ../../../../C/Sha256Opt.c | 1300 | $O/Sha256Opt.o: ../../../../C/Sha256Opt.c |
| 1301 | $(CC) $(CFLAGS) $< | 1301 | $(CC) $(CFLAGS) $< |
| 1302 | $O/Sort.o: ../../../../C/Sort.c | ||
| 1303 | $(CC) $(CFLAGS) $< | ||
| 1302 | endif | 1304 | endif |
| 1303 | 1305 | ||
| 1304 | 1306 | ||
diff --git a/CPP/7zip/Archive/7z/7zCompressionMode.h b/CPP/7zip/Archive/7z/7zCompressionMode.h index 737722d..ecfee7c 100644 --- a/CPP/7zip/Archive/7z/7zCompressionMode.h +++ b/CPP/7zip/Archive/7z/7zCompressionMode.h | |||
| @@ -59,6 +59,7 @@ struct CCompressionMethodMode | |||
| 59 | bool NumThreads_WasForced; | 59 | bool NumThreads_WasForced; |
| 60 | bool MultiThreadMixer; | 60 | bool MultiThreadMixer; |
| 61 | UInt32 NumThreads; | 61 | UInt32 NumThreads; |
| 62 | UInt32 NumThreadGroups; | ||
| 62 | #endif | 63 | #endif |
| 63 | 64 | ||
| 64 | UString Password; // _Wipe | 65 | UString Password; // _Wipe |
| @@ -74,6 +75,7 @@ struct CCompressionMethodMode | |||
| 74 | , NumThreads_WasForced(false) | 75 | , NumThreads_WasForced(false) |
| 75 | , MultiThreadMixer(true) | 76 | , MultiThreadMixer(true) |
| 76 | , NumThreads(1) | 77 | , NumThreads(1) |
| 78 | , NumThreadGroups(0) | ||
| 77 | #endif | 79 | #endif |
| 78 | , MemoryUsageLimit((UInt64)1 << 30) | 80 | , MemoryUsageLimit((UInt64)1 << 30) |
| 79 | {} | 81 | {} |
diff --git a/CPP/7zip/Archive/7z/7zHandlerOut.cpp b/CPP/7zip/Archive/7z/7zHandlerOut.cpp index ea5ea0f..c1c2b63 100644 --- a/CPP/7zip/Archive/7z/7zHandlerOut.cpp +++ b/CPP/7zip/Archive/7z/7zHandlerOut.cpp | |||
| @@ -111,8 +111,8 @@ HRESULT CHandler::SetMainMethod(CCompressionMethodMode &methodMode) | |||
| 111 | } | 111 | } |
| 112 | } | 112 | } |
| 113 | 113 | ||
| 114 | const UInt64 kSolidBytes_Min = (1 << 24); | 114 | const UInt64 kSolidBytes_Min = 1 << 24; |
| 115 | const UInt64 kSolidBytes_Max = ((UInt64)1 << 32); | 115 | const UInt64 kSolidBytes_Max = (UInt64)1 << 32; // for non-LZMA2 methods |
| 116 | 116 | ||
| 117 | bool needSolid = false; | 117 | bool needSolid = false; |
| 118 | 118 | ||
| @@ -122,22 +122,24 @@ HRESULT CHandler::SetMainMethod(CCompressionMethodMode &methodMode) | |||
| 122 | 122 | ||
| 123 | SetGlobalLevelTo(oneMethodInfo); | 123 | SetGlobalLevelTo(oneMethodInfo); |
| 124 | 124 | ||
| 125 | #ifndef Z7_ST | 125 | #ifndef Z7_ST |
| 126 | const bool numThreads_WasSpecifiedInMethod = (oneMethodInfo.Get_NumThreads() >= 0); | 126 | const bool numThreads_WasSpecifiedInMethod = (oneMethodInfo.Get_NumThreads() >= 0); |
| 127 | if (!numThreads_WasSpecifiedInMethod) | 127 | if (!numThreads_WasSpecifiedInMethod) |
| 128 | { | 128 | { |
| 129 | // here we set the (NCoderPropID::kNumThreads) property in each method, only if there is no such property already | 129 | // here we set the (NCoderPropID::kNumThreads) property in each method, only if there is no such property already |
| 130 | CMultiMethodProps::SetMethodThreadsTo_IfNotFinded(oneMethodInfo, methodMode.NumThreads); | 130 | CMultiMethodProps::SetMethodThreadsTo_IfNotFinded(oneMethodInfo, methodMode.NumThreads); |
| 131 | } | 131 | } |
| 132 | #endif | 132 | if (methodMode.NumThreadGroups > 1) |
| 133 | CMultiMethodProps::Set_Method_NumThreadGroups_IfNotFinded(oneMethodInfo, methodMode.NumThreadGroups); | ||
| 134 | #endif | ||
| 133 | 135 | ||
| 134 | CMethodFull &methodFull = methodMode.Methods.AddNew(); | 136 | CMethodFull &methodFull = methodMode.Methods.AddNew(); |
| 135 | RINOK(PropsMethod_To_FullMethod(methodFull, oneMethodInfo)) | 137 | RINOK(PropsMethod_To_FullMethod(methodFull, oneMethodInfo)) |
| 136 | 138 | ||
| 137 | #ifndef Z7_ST | 139 | #ifndef Z7_ST |
| 138 | methodFull.Set_NumThreads = true; | 140 | methodFull.Set_NumThreads = true; |
| 139 | methodFull.NumThreads = methodMode.NumThreads; | 141 | methodFull.NumThreads = methodMode.NumThreads; |
| 140 | #endif | 142 | #endif |
| 141 | 143 | ||
| 142 | if (methodFull.Id != k_Copy) | 144 | if (methodFull.Id != k_Copy) |
| 143 | needSolid = true; | 145 | needSolid = true; |
| @@ -217,19 +219,18 @@ HRESULT CHandler::SetMainMethod(CCompressionMethodMode &methodMode) | |||
| 217 | // here we get real chunkSize | 219 | // here we get real chunkSize |
| 218 | cs = oneMethodInfo.Get_Xz_BlockSize(); | 220 | cs = oneMethodInfo.Get_Xz_BlockSize(); |
| 219 | if (dicSize > cs) | 221 | if (dicSize > cs) |
| 220 | dicSize = cs; | 222 | dicSize = cs; |
| 221 | 223 | ||
| 222 | const UInt64 kSolidBytes_Lzma2_Max = ((UInt64)1 << 34); | 224 | const UInt64 kSolidBytes_Lzma2_Max = (UInt64)1 << 34; |
| 223 | if (numSolidBytes > kSolidBytes_Lzma2_Max) | 225 | if (numSolidBytes > kSolidBytes_Lzma2_Max) |
| 224 | numSolidBytes = kSolidBytes_Lzma2_Max; | 226 | numSolidBytes = kSolidBytes_Lzma2_Max; |
| 225 | 227 | ||
| 226 | methodFull.Set_NumThreads = false; // we don't use ICompressSetCoderMt::SetNumberOfThreads() for LZMA2 encoder | 228 | methodFull.Set_NumThreads = false; // we don't use ICompressSetCoderMt::SetNumberOfThreads() for LZMA2 encoder |
| 227 | 229 | ||
| 228 | #ifndef Z7_ST | 230 | #ifndef Z7_ST |
| 229 | if (!numThreads_WasSpecifiedInMethod | 231 | if (!numThreads_WasSpecifiedInMethod |
| 230 | && !methodMode.NumThreads_WasForced | 232 | && !methodMode.NumThreads_WasForced |
| 231 | && methodMode.MemoryUsageLimit_WasSet | 233 | && methodMode.MemoryUsageLimit_WasSet) |
| 232 | ) | ||
| 233 | { | 234 | { |
| 234 | const UInt32 lzmaThreads = oneMethodInfo.Get_Lzma_NumThreads(); | 235 | const UInt32 lzmaThreads = oneMethodInfo.Get_Lzma_NumThreads(); |
| 235 | const UInt32 numBlockThreads_Original = methodMode.NumThreads / lzmaThreads; | 236 | const UInt32 numBlockThreads_Original = methodMode.NumThreads / lzmaThreads; |
| @@ -273,14 +274,14 @@ HRESULT CHandler::SetMainMethod(CCompressionMethodMode &methodMode) | |||
| 273 | { | 274 | { |
| 274 | numSolidBytes = (UInt64)dicSize << 7; | 275 | numSolidBytes = (UInt64)dicSize << 7; |
| 275 | if (numSolidBytes > kSolidBytes_Max) | 276 | if (numSolidBytes > kSolidBytes_Max) |
| 276 | numSolidBytes = kSolidBytes_Max; | 277 | numSolidBytes = kSolidBytes_Max; |
| 277 | } | 278 | } |
| 278 | 279 | ||
| 279 | if (_numSolidBytesDefined) | 280 | if (_numSolidBytesDefined) |
| 280 | continue; | 281 | continue; |
| 281 | 282 | ||
| 282 | if (numSolidBytes < kSolidBytes_Min) | 283 | if (numSolidBytes < kSolidBytes_Min) |
| 283 | numSolidBytes = kSolidBytes_Min; | 284 | numSolidBytes = kSolidBytes_Min; |
| 284 | _numSolidBytes = numSolidBytes; | 285 | _numSolidBytes = numSolidBytes; |
| 285 | _numSolidBytesDefined = true; | 286 | _numSolidBytesDefined = true; |
| 286 | } | 287 | } |
| @@ -704,6 +705,9 @@ Z7_COM7F_IMF(CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt | |||
| 704 | methodMode.NumThreads = numThreads; | 705 | methodMode.NumThreads = numThreads; |
| 705 | methodMode.NumThreads_WasForced = _numThreads_WasForced; | 706 | methodMode.NumThreads_WasForced = _numThreads_WasForced; |
| 706 | methodMode.MultiThreadMixer = _useMultiThreadMixer; | 707 | methodMode.MultiThreadMixer = _useMultiThreadMixer; |
| 708 | #ifdef _WIN32 | ||
| 709 | methodMode.NumThreadGroups = _numThreadGroups; // _change it | ||
| 710 | #endif | ||
| 707 | // headerMethod.NumThreads = 1; | 711 | // headerMethod.NumThreads = 1; |
| 708 | headerMethod.MultiThreadMixer = _useMultiThreadMixer; | 712 | headerMethod.MultiThreadMixer = _useMultiThreadMixer; |
| 709 | } | 713 | } |
diff --git a/CPP/7zip/Archive/ArHandler.cpp b/CPP/7zip/Archive/ArHandler.cpp index 95e4719..944eec4 100644 --- a/CPP/7zip/Archive/ArHandler.cpp +++ b/CPP/7zip/Archive/ArHandler.cpp | |||
| @@ -325,7 +325,7 @@ HRESULT CHandler::ParseLongNames(IInStream *stream) | |||
| 325 | { | 325 | { |
| 326 | unsigned i; | 326 | unsigned i; |
| 327 | for (i = 0; i < _items.Size(); i++) | 327 | for (i = 0; i < _items.Size(); i++) |
| 328 | if (_items[i].Name == "//") | 328 | if (_items[i].Name.IsEqualTo("//")) |
| 329 | break; | 329 | break; |
| 330 | if (i == _items.Size()) | 330 | if (i == _items.Size()) |
| 331 | return S_OK; | 331 | return S_OK; |
| @@ -378,7 +378,7 @@ void CHandler::ChangeDuplicateNames() | |||
| 378 | if (item.Name[0] == '/') | 378 | if (item.Name[0] == '/') |
| 379 | continue; | 379 | continue; |
| 380 | CItem &prev = _items[i - 1]; | 380 | CItem &prev = _items[i - 1]; |
| 381 | if (item.Name == prev.Name) | 381 | if (item.Name.IsEqualTo(prev.Name)) |
| 382 | { | 382 | { |
| 383 | if (prev.SameNameIndex < 0) | 383 | if (prev.SameNameIndex < 0) |
| 384 | prev.SameNameIndex = 0; | 384 | prev.SameNameIndex = 0; |
| @@ -448,9 +448,9 @@ static UInt32 Get32(const Byte *p, unsigned be) { if (be) return GetBe32(p); ret | |||
| 448 | HRESULT CHandler::ParseLibSymbols(IInStream *stream, unsigned fileIndex) | 448 | HRESULT CHandler::ParseLibSymbols(IInStream *stream, unsigned fileIndex) |
| 449 | { | 449 | { |
| 450 | CItem &item = _items[fileIndex]; | 450 | CItem &item = _items[fileIndex]; |
| 451 | if (item.Name != "/" && | 451 | if (!item.Name.IsEqualTo("/") && |
| 452 | item.Name != "__.SYMDEF" && | 452 | !item.Name.IsEqualTo("__.SYMDEF") && |
| 453 | item.Name != "__.SYMDEF SORTED") | 453 | !item.Name.IsEqualTo("__.SYMDEF SORTED")) |
| 454 | return S_OK; | 454 | return S_OK; |
| 455 | if (item.Size > ((UInt32)1 << 30) || | 455 | if (item.Size > ((UInt32)1 << 30) || |
| 456 | item.Size < 4) | 456 | item.Size < 4) |
| @@ -462,7 +462,7 @@ HRESULT CHandler::ParseLibSymbols(IInStream *stream, unsigned fileIndex) | |||
| 462 | 462 | ||
| 463 | size_t pos = 0; | 463 | size_t pos = 0; |
| 464 | 464 | ||
| 465 | if (item.Name != "/") | 465 | if (!item.Name.IsEqualTo("/")) |
| 466 | { | 466 | { |
| 467 | // "__.SYMDEF" parsing (BSD) | 467 | // "__.SYMDEF" parsing (BSD) |
| 468 | unsigned be; | 468 | unsigned be; |
| @@ -603,7 +603,7 @@ Z7_COM7F_IMF(CHandler::Open(IInStream *stream, | |||
| 603 | if (_longNames_FileIndex >= 0) | 603 | if (_longNames_FileIndex >= 0) |
| 604 | _items.Delete((unsigned)_longNames_FileIndex); | 604 | _items.Delete((unsigned)_longNames_FileIndex); |
| 605 | 605 | ||
| 606 | if (!_items.IsEmpty() && _items[0].Name == "debian-binary") | 606 | if (!_items.IsEmpty() && _items[0].Name.IsEqualTo("debian-binary")) |
| 607 | { | 607 | { |
| 608 | _type = kType_Deb; | 608 | _type = kType_Deb; |
| 609 | _items.DeleteFrontal(1); | 609 | _items.DeleteFrontal(1); |
diff --git a/CPP/7zip/Archive/Bz2Handler.cpp b/CPP/7zip/Archive/Bz2Handler.cpp index ffd7ad0..02eeee6 100644 --- a/CPP/7zip/Archive/Bz2Handler.cpp +++ b/CPP/7zip/Archive/Bz2Handler.cpp | |||
| @@ -427,9 +427,13 @@ Z7_COM7F_IMF(CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt | |||
| 427 | } | 427 | } |
| 428 | 428 | ||
| 429 | CMethodProps props2 = _props; | 429 | CMethodProps props2 = _props; |
| 430 | #ifndef Z7_ST | 430 | #ifndef Z7_ST |
| 431 | props2.AddProp_NumThreads(_props._numThreads); | 431 | props2.AddProp_NumThreads(_props._numThreads); |
| 432 | #endif | 432 | #ifdef _WIN32 |
| 433 | if (_props._numThreadGroups > 1) | ||
| 434 | props2.AddProp32(NCoderPropID::kNumThreadGroups, _props._numThreadGroups); | ||
| 435 | #endif | ||
| 436 | #endif | ||
| 433 | 437 | ||
| 434 | return UpdateArchive(size, outStream, props2, updateCallback); | 438 | return UpdateArchive(size, outStream, props2, updateCallback); |
| 435 | } | 439 | } |
diff --git a/CPP/7zip/Archive/ComHandler.cpp b/CPP/7zip/Archive/ComHandler.cpp index 82d939d..144369e 100644 --- a/CPP/7zip/Archive/ComHandler.cpp +++ b/CPP/7zip/Archive/ComHandler.cpp | |||
| @@ -68,7 +68,7 @@ namespace NItemType | |||
| 68 | static const Byte kRootStorage = 5; | 68 | static const Byte kRootStorage = 5; |
| 69 | } | 69 | } |
| 70 | 70 | ||
| 71 | static const UInt32 kNameSizeMax = 64; | 71 | static const unsigned kNameSizeMax = 64; |
| 72 | 72 | ||
| 73 | struct CItem | 73 | struct CItem |
| 74 | { | 74 | { |
| @@ -98,30 +98,30 @@ struct CRef | |||
| 98 | 98 | ||
| 99 | class CDatabase | 99 | class CDatabase |
| 100 | { | 100 | { |
| 101 | UInt32 NumSectorsInMiniStream; | ||
| 102 | CObjArray<UInt32> MiniSids; | 101 | CObjArray<UInt32> MiniSids; |
| 103 | 102 | ||
| 104 | HRESULT AddNode(int parent, UInt32 did); | 103 | HRESULT AddNode(int parent, UInt32 did); |
| 105 | public: | ||
| 106 | 104 | ||
| 105 | public: | ||
| 107 | CObjArray<UInt32> Fat; | 106 | CObjArray<UInt32> Fat; |
| 108 | UInt32 FatSize; | ||
| 109 | |||
| 110 | CObjArray<UInt32> Mat; | 107 | CObjArray<UInt32> Mat; |
| 111 | UInt32 MatSize; | ||
| 112 | |||
| 113 | CObjectVector<CItem> Items; | 108 | CObjectVector<CItem> Items; |
| 114 | CRecordVector<CRef> Refs; | 109 | CRecordVector<CRef> Refs; |
| 110 | private: | ||
| 111 | UInt32 NumSectorsInMiniStream; | ||
| 112 | public: | ||
| 113 | UInt32 MatSize; | ||
| 114 | UInt32 FatSize; | ||
| 115 | 115 | ||
| 116 | UInt32 LongStreamMinSize; | 116 | UInt32 LongStreamMinSize; |
| 117 | unsigned SectorSizeBits; | 117 | unsigned SectorSizeBits; |
| 118 | unsigned MiniSectorSizeBits; | 118 | unsigned MiniSectorSizeBits; |
| 119 | 119 | ||
| 120 | Int32 MainSubfile; | 120 | Int32 MainSubfile; |
| 121 | EType Type; | ||
| 121 | 122 | ||
| 122 | UInt64 PhySize; | 123 | UInt64 PhySize; |
| 123 | UInt64 PhySize_Aligned; | 124 | UInt64 PhySize_Aligned; |
| 124 | EType Type; | ||
| 125 | 125 | ||
| 126 | bool IsNotArcType() const | 126 | bool IsNotArcType() const |
| 127 | { | 127 | { |
| @@ -148,14 +148,14 @@ public: | |||
| 148 | 148 | ||
| 149 | UInt64 GetItemPackSize(UInt64 size) const | 149 | UInt64 GetItemPackSize(UInt64 size) const |
| 150 | { | 150 | { |
| 151 | UInt64 mask = ((UInt64)1 << (IsLargeStream(size) ? SectorSizeBits : MiniSectorSizeBits)) - 1; | 151 | const UInt64 mask = ((UInt32)1 << (IsLargeStream(size) ? SectorSizeBits : MiniSectorSizeBits)) - 1; |
| 152 | return (size + mask) & ~mask; | 152 | return (size + mask) & ~mask; |
| 153 | } | 153 | } |
| 154 | 154 | ||
| 155 | bool GetMiniCluster(UInt32 sid, UInt64 &res) const | 155 | bool GetMiniCluster(UInt32 sid, UInt64 &res) const |
| 156 | { | 156 | { |
| 157 | unsigned subBits = SectorSizeBits - MiniSectorSizeBits; | 157 | const unsigned subBits = SectorSizeBits - MiniSectorSizeBits; |
| 158 | UInt32 fid = sid >> subBits; | 158 | const UInt32 fid = sid >> subBits; |
| 159 | if (fid >= NumSectorsInMiniStream) | 159 | if (fid >= NumSectorsInMiniStream) |
| 160 | return false; | 160 | return false; |
| 161 | res = (((UInt64)MiniSids[fid] + 1) << subBits) + (sid & ((1 << subBits) - 1)); | 161 | res = (((UInt64)MiniSids[fid] + 1) << subBits) + (sid & ((1 << subBits) - 1)); |
| @@ -177,7 +177,7 @@ HRESULT CDatabase::ReadSector(IInStream *inStream, Byte *buf, unsigned sectorSiz | |||
| 177 | HRESULT CDatabase::ReadIDs(IInStream *inStream, Byte *buf, unsigned sectorSizeBits, UInt32 sid, UInt32 *dest) | 177 | HRESULT CDatabase::ReadIDs(IInStream *inStream, Byte *buf, unsigned sectorSizeBits, UInt32 sid, UInt32 *dest) |
| 178 | { | 178 | { |
| 179 | RINOK(ReadSector(inStream, buf, sectorSizeBits, sid)) | 179 | RINOK(ReadSector(inStream, buf, sectorSizeBits, sid)) |
| 180 | UInt32 sectorSize = (UInt32)1 << sectorSizeBits; | 180 | const UInt32 sectorSize = (UInt32)1 << sectorSizeBits; |
| 181 | for (UInt32 t = 0; t < sectorSize; t += 4) | 181 | for (UInt32 t = 0; t < sectorSize; t += 4) |
| 182 | *dest++ = Get32(buf + t); | 182 | *dest++ = Get32(buf + t); |
| 183 | return S_OK; | 183 | return S_OK; |
| @@ -373,7 +373,7 @@ UString CDatabase::GetItemPath(UInt32 index) const | |||
| 373 | HRESULT CDatabase::Update_PhySize_WithItem(unsigned index) | 373 | HRESULT CDatabase::Update_PhySize_WithItem(unsigned index) |
| 374 | { | 374 | { |
| 375 | const CItem &item = Items[index]; | 375 | const CItem &item = Items[index]; |
| 376 | bool isLargeStream = (index == 0 || IsLargeStream(item.Size)); | 376 | const bool isLargeStream = (index == 0 || IsLargeStream(item.Size)); |
| 377 | if (!isLargeStream) | 377 | if (!isLargeStream) |
| 378 | return S_OK; | 378 | return S_OK; |
| 379 | const unsigned bsLog = isLargeStream ? SectorSizeBits : MiniSectorSizeBits; | 379 | const unsigned bsLog = isLargeStream ? SectorSizeBits : MiniSectorSizeBits; |
| @@ -527,6 +527,10 @@ HRESULT CDatabase::Open(IInStream *inStream) | |||
| 527 | { | 527 | { |
| 528 | CItem item; | 528 | CItem item; |
| 529 | item.Parse(sect + i, mode64bit); | 529 | item.Parse(sect + i, mode64bit); |
| 530 | // we use (item.Size) check here. | ||
| 531 | // so we don't need additional overflow checks for (item.Size +) in another code | ||
| 532 | if (item.Size >= ((UInt64)1 << 63)) | ||
| 533 | return S_FALSE; | ||
| 530 | Items.Add(item); | 534 | Items.Add(item); |
| 531 | } | 535 | } |
| 532 | sid = Fat[sid]; | 536 | sid = Fat[sid]; |
| @@ -767,11 +771,8 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, | |||
| 767 | UInt64 totalPackSize; | 771 | UInt64 totalPackSize; |
| 768 | totalSize = totalPackSize = 0; | 772 | totalSize = totalPackSize = 0; |
| 769 | 773 | ||
| 770 | NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); | 774 | CMyComPtr2_Create<ICompressCoder, NCompress::CCopyCoder> copyCoder; |
| 771 | CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec; | 775 | CMyComPtr2_Create<ICompressProgressInfo, CLocalProgress> lps; |
| 772 | |||
| 773 | CLocalProgress *lps = new CLocalProgress; | ||
| 774 | CMyComPtr<ICompressProgressInfo> progress = lps; | ||
| 775 | lps->Init(extractCallback, false); | 776 | lps->Init(extractCallback, false); |
| 776 | 777 | ||
| 777 | for (i = 0; i < numItems; i++) | 778 | for (i = 0; i < numItems; i++) |
| @@ -781,7 +782,8 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, | |||
| 781 | RINOK(lps->SetCur()) | 782 | RINOK(lps->SetCur()) |
| 782 | const UInt32 index = allFilesMode ? i : indices[i]; | 783 | const UInt32 index = allFilesMode ? i : indices[i]; |
| 783 | const CItem &item = _db.Items[_db.Refs[index].Did]; | 784 | const CItem &item = _db.Items[_db.Refs[index].Did]; |
| 784 | 785 | Int32 res; | |
| 786 | { | ||
| 785 | CMyComPtr<ISequentialOutStream> outStream; | 787 | CMyComPtr<ISequentialOutStream> outStream; |
| 786 | const Int32 askMode = testMode ? | 788 | const Int32 askMode = testMode ? |
| 787 | NExtract::NAskMode::kTest : | 789 | NExtract::NAskMode::kTest : |
| @@ -801,7 +803,7 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, | |||
| 801 | if (!testMode && !outStream) | 803 | if (!testMode && !outStream) |
| 802 | continue; | 804 | continue; |
| 803 | RINOK(extractCallback->PrepareOperation(askMode)) | 805 | RINOK(extractCallback->PrepareOperation(askMode)) |
| 804 | Int32 res = NExtract::NOperationResult::kDataError; | 806 | res = NExtract::NOperationResult::kDataError; |
| 805 | CMyComPtr<ISequentialInStream> inStream; | 807 | CMyComPtr<ISequentialInStream> inStream; |
| 806 | HRESULT hres = GetStream(index, &inStream); | 808 | HRESULT hres = GetStream(index, &inStream); |
| 807 | if (hres == S_FALSE) | 809 | if (hres == S_FALSE) |
| @@ -813,12 +815,12 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, | |||
| 813 | RINOK(hres) | 815 | RINOK(hres) |
| 814 | if (inStream) | 816 | if (inStream) |
| 815 | { | 817 | { |
| 816 | RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)) | 818 | RINOK(copyCoder.Interface()->Code(inStream, outStream, NULL, NULL, lps)) |
| 817 | if (copyCoderSpec->TotalSize == item.Size) | 819 | if (copyCoder->TotalSize == item.Size) |
| 818 | res = NExtract::NOperationResult::kOK; | 820 | res = NExtract::NOperationResult::kOK; |
| 819 | } | 821 | } |
| 820 | } | 822 | } |
| 821 | outStream.Release(); | 823 | } |
| 822 | RINOK(extractCallback->SetOperationResult(res)) | 824 | RINOK(extractCallback->SetOperationResult(res)) |
| 823 | } | 825 | } |
| 824 | return S_OK; | 826 | return S_OK; |
diff --git a/CPP/7zip/Archive/Common/HandlerOut.cpp b/CPP/7zip/Archive/Common/HandlerOut.cpp index 17fed67..5a11e30 100644 --- a/CPP/7zip/Archive/Common/HandlerOut.cpp +++ b/CPP/7zip/Archive/Common/HandlerOut.cpp | |||
| @@ -4,8 +4,6 @@ | |||
| 4 | 4 | ||
| 5 | #include "../../../Common/StringToInt.h" | 5 | #include "../../../Common/StringToInt.h" |
| 6 | 6 | ||
| 7 | #include "../Common/ParseProperties.h" | ||
| 8 | |||
| 9 | #include "HandlerOut.h" | 7 | #include "HandlerOut.h" |
| 10 | 8 | ||
| 11 | namespace NArchive { | 9 | namespace NArchive { |
| @@ -82,6 +80,7 @@ bool ParseSizeString(const wchar_t *s, const PROPVARIANT &prop, UInt64 percentsB | |||
| 82 | return true; | 80 | return true; |
| 83 | } | 81 | } |
| 84 | 82 | ||
| 83 | |||
| 85 | bool CCommonMethodProps::SetCommonProperty(const UString &name, const PROPVARIANT &value, HRESULT &hres) | 84 | bool CCommonMethodProps::SetCommonProperty(const UString &name, const PROPVARIANT &value, HRESULT &hres) |
| 86 | { | 85 | { |
| 87 | hres = S_OK; | 86 | hres = S_OK; |
| @@ -151,6 +150,11 @@ void CMultiMethodProps::SetMethodThreadsTo_Replace(CMethodProps &oneMethodInfo, | |||
| 151 | SetMethodProp32_Replace(oneMethodInfo, NCoderPropID::kNumThreads, numThreads); | 150 | SetMethodProp32_Replace(oneMethodInfo, NCoderPropID::kNumThreads, numThreads); |
| 152 | } | 151 | } |
| 153 | 152 | ||
| 153 | void CMultiMethodProps::Set_Method_NumThreadGroups_IfNotFinded(CMethodProps &oneMethodInfo, UInt32 numThreadGroups) | ||
| 154 | { | ||
| 155 | SetMethodProp32(oneMethodInfo, NCoderPropID::kNumThreadGroups, numThreadGroups); | ||
| 156 | } | ||
| 157 | |||
| 154 | #endif // Z7_ST | 158 | #endif // Z7_ST |
| 155 | 159 | ||
| 156 | 160 | ||
diff --git a/CPP/7zip/Archive/Common/HandlerOut.h b/CPP/7zip/Archive/Common/HandlerOut.h index 9340e1b..3122b05 100644 --- a/CPP/7zip/Archive/Common/HandlerOut.h +++ b/CPP/7zip/Archive/Common/HandlerOut.h | |||
| @@ -17,11 +17,21 @@ protected: | |||
| 17 | void InitCommon() | 17 | void InitCommon() |
| 18 | { | 18 | { |
| 19 | // _Write_MTime = true; | 19 | // _Write_MTime = true; |
| 20 | #ifndef Z7_ST | 20 | { |
| 21 | _numProcessors = _numThreads = NWindows::NSystem::GetNumberOfProcessors(); | 21 | #ifndef Z7_ST |
| 22 | _numThreads_WasForced = false; | 22 | _numThreads_WasForced = false; |
| 23 | #endif | 23 | UInt32 numThreads; |
| 24 | 24 | #ifdef _WIN32 | |
| 25 | NWindows::NSystem::CProcessAffinity aff; | ||
| 26 | numThreads = aff.Load_and_GetNumberOfThreads(); | ||
| 27 | _numThreadGroups = aff.IsGroupMode ? aff.Groups.GroupSizes.Size() : 0; | ||
| 28 | #else | ||
| 29 | numThreads = NWindows::NSystem::GetNumberOfProcessors(); | ||
| 30 | #endif // _WIN32 | ||
| 31 | _numProcessors = _numThreads = numThreads; | ||
| 32 | #endif // Z7_ST | ||
| 33 | } | ||
| 34 | |||
| 25 | size_t memAvail = (size_t)sizeof(size_t) << 28; | 35 | size_t memAvail = (size_t)sizeof(size_t) << 28; |
| 26 | _memAvail = memAvail; | 36 | _memAvail = memAvail; |
| 27 | _memUsage_Compress = memAvail; | 37 | _memUsage_Compress = memAvail; |
| @@ -46,11 +56,14 @@ protected: | |||
| 46 | } | 56 | } |
| 47 | 57 | ||
| 48 | public: | 58 | public: |
| 49 | #ifndef Z7_ST | 59 | #ifndef Z7_ST |
| 50 | UInt32 _numThreads; | 60 | UInt32 _numThreads; |
| 51 | UInt32 _numProcessors; | 61 | UInt32 _numProcessors; |
| 62 | #ifdef _WIN32 | ||
| 63 | UInt32 _numThreadGroups; | ||
| 64 | #endif | ||
| 52 | bool _numThreads_WasForced; | 65 | bool _numThreads_WasForced; |
| 53 | #endif | 66 | #endif |
| 54 | 67 | ||
| 55 | bool _memUsage_WasSet; | 68 | bool _memUsage_WasSet; |
| 56 | UInt64 _memUsage_Compress; | 69 | UInt64 _memUsage_Compress; |
| @@ -80,10 +93,12 @@ public: | |||
| 80 | 93 | ||
| 81 | void SetGlobalLevelTo(COneMethodInfo &oneMethodInfo) const; | 94 | void SetGlobalLevelTo(COneMethodInfo &oneMethodInfo) const; |
| 82 | 95 | ||
| 83 | #ifndef Z7_ST | 96 | #ifndef Z7_ST |
| 84 | static void SetMethodThreadsTo_IfNotFinded(CMethodProps &props, UInt32 numThreads); | 97 | static void SetMethodThreadsTo_IfNotFinded(CMethodProps &props, UInt32 numThreads); |
| 85 | static void SetMethodThreadsTo_Replace(CMethodProps &props, UInt32 numThreads); | 98 | static void SetMethodThreadsTo_Replace(CMethodProps &props, UInt32 numThreads); |
| 86 | #endif | 99 | |
| 100 | static void Set_Method_NumThreadGroups_IfNotFinded(CMethodProps &props, UInt32 numThreadGroups); | ||
| 101 | #endif | ||
| 87 | 102 | ||
| 88 | 103 | ||
| 89 | unsigned GetNumEmptyMethods() const | 104 | unsigned GetNumEmptyMethods() const |
diff --git a/CPP/7zip/Archive/Common/ItemNameUtils.cpp b/CPP/7zip/Archive/Common/ItemNameUtils.cpp index 8caf1d1..150efc9 100644 --- a/CPP/7zip/Archive/Common/ItemNameUtils.cpp +++ b/CPP/7zip/Archive/Common/ItemNameUtils.cpp | |||
| @@ -47,6 +47,25 @@ UString GetOsPath_Remove_TailSlash(const UString &name) | |||
| 47 | } | 47 | } |
| 48 | 48 | ||
| 49 | 49 | ||
| 50 | #if WCHAR_PATH_SEPARATOR != L'/' | ||
| 51 | void ReplaceToWinSlashes(UString &name, bool useBackslashReplacement) | ||
| 52 | { | ||
| 53 | // name.Replace(kUnixPathSepar, kOsPathSepar); | ||
| 54 | const unsigned len = name.Len(); | ||
| 55 | for (unsigned i = 0; i < len; i++) | ||
| 56 | { | ||
| 57 | wchar_t c = name[i]; | ||
| 58 | if (c == L'/') | ||
| 59 | c = WCHAR_PATH_SEPARATOR; | ||
| 60 | else if (useBackslashReplacement && c == L'\\') | ||
| 61 | c = WCHAR_IN_FILE_NAME_BACKSLASH_REPLACEMENT; // WSL scheme | ||
| 62 | else | ||
| 63 | continue; | ||
| 64 | name.ReplaceOneCharAtPos(i, c); | ||
| 65 | } | ||
| 66 | } | ||
| 67 | #endif | ||
| 68 | |||
| 50 | void ReplaceToOsSlashes_Remove_TailSlash(UString &name, bool | 69 | void ReplaceToOsSlashes_Remove_TailSlash(UString &name, bool |
| 51 | #if WCHAR_PATH_SEPARATOR != L'/' | 70 | #if WCHAR_PATH_SEPARATOR != L'/' |
| 52 | useBackslashReplacement | 71 | useBackslashReplacement |
| @@ -57,21 +76,7 @@ void ReplaceToOsSlashes_Remove_TailSlash(UString &name, bool | |||
| 57 | return; | 76 | return; |
| 58 | 77 | ||
| 59 | #if WCHAR_PATH_SEPARATOR != L'/' | 78 | #if WCHAR_PATH_SEPARATOR != L'/' |
| 60 | { | 79 | ReplaceToWinSlashes(name, useBackslashReplacement); |
| 61 | // name.Replace(kUnixPathSepar, kOsPathSepar); | ||
| 62 | const unsigned len = name.Len(); | ||
| 63 | for (unsigned i = 0; i < len; i++) | ||
| 64 | { | ||
| 65 | wchar_t c = name[i]; | ||
| 66 | if (c == L'/') | ||
| 67 | c = WCHAR_PATH_SEPARATOR; | ||
| 68 | else if (useBackslashReplacement && c == L'\\') | ||
| 69 | c = WCHAR_IN_FILE_NAME_BACKSLASH_REPLACEMENT; // WSL scheme | ||
| 70 | else | ||
| 71 | continue; | ||
| 72 | name.ReplaceOneCharAtPos(i, c); | ||
| 73 | } | ||
| 74 | } | ||
| 75 | #endif | 80 | #endif |
| 76 | 81 | ||
| 77 | if (name.Back() == kOsPathSepar) | 82 | if (name.Back() == kOsPathSepar) |
diff --git a/CPP/7zip/Archive/Common/ItemNameUtils.h b/CPP/7zip/Archive/Common/ItemNameUtils.h index 8ab9b61..cea8dcc 100644 --- a/CPP/7zip/Archive/Common/ItemNameUtils.h +++ b/CPP/7zip/Archive/Common/ItemNameUtils.h | |||
| @@ -13,6 +13,9 @@ void ReplaceSlashes_OsToUnix(UString &name); | |||
| 13 | UString GetOsPath(const UString &name); | 13 | UString GetOsPath(const UString &name); |
| 14 | UString GetOsPath_Remove_TailSlash(const UString &name); | 14 | UString GetOsPath_Remove_TailSlash(const UString &name); |
| 15 | 15 | ||
| 16 | #if WCHAR_PATH_SEPARATOR != L'/' | ||
| 17 | void ReplaceToWinSlashes(UString &name, bool useBackslashReplacement); | ||
| 18 | #endif | ||
| 16 | void ReplaceToOsSlashes_Remove_TailSlash(UString &name, bool useBackslashReplacement = false); | 19 | void ReplaceToOsSlashes_Remove_TailSlash(UString &name, bool useBackslashReplacement = false); |
| 17 | void NormalizeSlashes_in_FileName_for_OsPath(wchar_t *s, unsigned len); | 20 | void NormalizeSlashes_in_FileName_for_OsPath(wchar_t *s, unsigned len); |
| 18 | void NormalizeSlashes_in_FileName_for_OsPath(UString &name); | 21 | void NormalizeSlashes_in_FileName_for_OsPath(UString &name); |
diff --git a/CPP/7zip/Archive/CpioHandler.cpp b/CPP/7zip/Archive/CpioHandler.cpp index 2228040..62184f0 100644 --- a/CPP/7zip/Archive/CpioHandler.cpp +++ b/CPP/7zip/Archive/CpioHandler.cpp | |||
| @@ -437,7 +437,14 @@ HRESULT CInArchive::GetNextItem() | |||
| 437 | return S_OK; | 437 | return S_OK; |
| 438 | 438 | ||
| 439 | /* v23.02: we have disabled rDevMinor check because real file | 439 | /* v23.02: we have disabled rDevMinor check because real file |
| 440 | from Apple contains rDevMinor==255 by some unknown reason */ | 440 | from Apple contains rDevMinor==255 by some unknown reason |
| 441 | cpio 2.13 and older versions: it copies stat::st_rdev to archive. | ||
| 442 | and stat::st_rdev can be non-zero for some old linux/filesystems cases for regular files. | ||
| 443 | cpio 2.14 (2023) copies st_rdev to archive only if (S_ISBLK (st->st_mode) || S_ISCHR (st->st_mode)) | ||
| 444 | v25.00: we have disabled RDevMajor check here to support some rare case created by cpio 2.13- with old linux. | ||
| 445 | But we still keep full check in IsArc_Cpio() to reduce false cpio detection cases. | ||
| 446 | */ | ||
| 447 | #if 0 // 0 : to disable check to support some old linux cpio archives. | ||
| 441 | if (item.RDevMajor != 0 | 448 | if (item.RDevMajor != 0 |
| 442 | // || item.RDevMinor != 0 | 449 | // || item.RDevMinor != 0 |
| 443 | ) | 450 | ) |
| @@ -446,6 +453,7 @@ HRESULT CInArchive::GetNextItem() | |||
| 446 | !MY_LIN_S_ISBLK(item.Mode)) | 453 | !MY_LIN_S_ISBLK(item.Mode)) |
| 447 | return S_OK; | 454 | return S_OK; |
| 448 | } | 455 | } |
| 456 | #endif | ||
| 449 | 457 | ||
| 450 | // Size must be 0 for FIFOs and directories | 458 | // Size must be 0 for FIFOs and directories |
| 451 | if (item.IsDir() || MY_LIN_S_ISFIFO(item.Mode)) | 459 | if (item.IsDir() || MY_LIN_S_ISFIFO(item.Mode)) |
| @@ -873,17 +881,13 @@ Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val | |||
| 873 | { | 881 | { |
| 874 | case kpidPath: | 882 | case kpidPath: |
| 875 | { | 883 | { |
| 876 | UString res; | 884 | #ifdef _WIN32 |
| 877 | bool needConvert = true; | 885 | UString u; |
| 878 | #ifdef _WIN32 | 886 | ConvertUTF8ToUnicode(item.Name, u); |
| 879 | // if ( | 887 | #else |
| 880 | ConvertUTF8ToUnicode(item.Name, res); | 888 | const UString u = MultiByteToUnicodeString(item.Name, CP_OEMCP); |
| 881 | // ) | 889 | #endif |
| 882 | needConvert = false; | 890 | prop = NItemName::GetOsPath(u); |
| 883 | #endif | ||
| 884 | if (needConvert) | ||
| 885 | res = MultiByteToUnicodeString(item.Name, CP_OEMCP); | ||
| 886 | prop = NItemName::GetOsPath(res); | ||
| 887 | break; | 891 | break; |
| 888 | } | 892 | } |
| 889 | case kpidIsDir: prop = item.IsDir(); break; | 893 | case kpidIsDir: prop = item.IsDir(); break; |
| @@ -921,16 +925,12 @@ Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val | |||
| 921 | s.SetFrom_CalcLen((const char *)(const void *)(const Byte *)item.Data, (unsigned)item.Data.Size()); | 925 | s.SetFrom_CalcLen((const char *)(const void *)(const Byte *)item.Data, (unsigned)item.Data.Size()); |
| 922 | if (s.Len() == item.Data.Size()) | 926 | if (s.Len() == item.Data.Size()) |
| 923 | { | 927 | { |
| 928 | #ifdef _WIN32 | ||
| 924 | UString u; | 929 | UString u; |
| 925 | bool needConvert = true; | 930 | ConvertUTF8ToUnicode(item.Name, u); |
| 926 | #ifdef _WIN32 | 931 | #else |
| 927 | // if ( | 932 | const UString u = MultiByteToUnicodeString(s, CP_OEMCP); |
| 928 | ConvertUTF8ToUnicode(item.Name, u); | 933 | #endif |
| 929 | // ) | ||
| 930 | needConvert = false; | ||
| 931 | #endif | ||
| 932 | if (needConvert) | ||
| 933 | u = MultiByteToUnicodeString(s, CP_OEMCP); | ||
| 934 | prop = u; | 934 | prop = u; |
| 935 | } | 935 | } |
| 936 | } | 936 | } |
diff --git a/CPP/7zip/Archive/DmgHandler.cpp b/CPP/7zip/Archive/DmgHandler.cpp index 3901192..9079dc7 100644 --- a/CPP/7zip/Archive/DmgHandler.cpp +++ b/CPP/7zip/Archive/DmgHandler.cpp | |||
| @@ -444,7 +444,7 @@ const char *Find_Apple_FS_Ext(const AString &name) | |||
| 444 | { | 444 | { |
| 445 | const CAppleName &a = k_Names[i]; | 445 | const CAppleName &a = k_Names[i]; |
| 446 | if (a.Ext) | 446 | if (a.Ext) |
| 447 | if (name == a.AppleName) | 447 | if (name.IsEqualTo(a.AppleName)) |
| 448 | return a.Ext; | 448 | return a.Ext; |
| 449 | } | 449 | } |
| 450 | return NULL; | 450 | return NULL; |
| @@ -784,7 +784,7 @@ static const CXmlItem *FindKeyPair(const CXmlItem &item, const char *key, const | |||
| 784 | for (unsigned i = 0; i + 1 < item.SubItems.Size(); i++) | 784 | for (unsigned i = 0; i + 1 < item.SubItems.Size(); i++) |
| 785 | { | 785 | { |
| 786 | const CXmlItem &si = item.SubItems[i]; | 786 | const CXmlItem &si = item.SubItems[i]; |
| 787 | if (si.IsTagged("key") && si.GetSubString() == key) | 787 | if (si.IsTagged("key") && si.GetSubString().IsEqualTo(key)) |
| 788 | { | 788 | { |
| 789 | const CXmlItem *si_1 = &item.SubItems[i + 1]; | 789 | const CXmlItem *si_1 = &item.SubItems[i + 1]; |
| 790 | if (si_1->IsTagged(nextTag)) | 790 | if (si_1->IsTagged(nextTag)) |
| @@ -1251,7 +1251,7 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *openArchiveCall | |||
| 1251 | #endif | 1251 | #endif |
| 1252 | } | 1252 | } |
| 1253 | 1253 | ||
| 1254 | if (xml.Root.Name != "plist") | 1254 | if (!xml.Root.Name.IsEqualTo("plist")) |
| 1255 | return S_FALSE; | 1255 | return S_FALSE; |
| 1256 | 1256 | ||
| 1257 | const CXmlItem *dictItem = xml.Root.FindSubTag_GetPtr("dict"); | 1257 | const CXmlItem *dictItem = xml.Root.FindSubTag_GetPtr("dict"); |
diff --git a/CPP/7zip/Archive/FatHandler.cpp b/CPP/7zip/Archive/FatHandler.cpp index b31ee4f..18fce91 100644 --- a/CPP/7zip/Archive/FatHandler.cpp +++ b/CPP/7zip/Archive/FatHandler.cpp | |||
| @@ -2,13 +2,12 @@ | |||
| 2 | 2 | ||
| 3 | #include "StdAfx.h" | 3 | #include "StdAfx.h" |
| 4 | 4 | ||
| 5 | // #include <stdio.h> | ||
| 6 | |||
| 7 | #include "../../../C/CpuArch.h" | 5 | #include "../../../C/CpuArch.h" |
| 8 | 6 | ||
| 9 | #include "../../Common/ComTry.h" | 7 | #include "../../Common/ComTry.h" |
| 10 | #include "../../Common/IntToString.h" | 8 | #include "../../Common/IntToString.h" |
| 11 | #include "../../Common/MyBuffer.h" | 9 | #include "../../Common/MyBuffer.h" |
| 10 | #include "../../Common/MyBuffer2.h" | ||
| 12 | #include "../../Common/MyCom.h" | 11 | #include "../../Common/MyCom.h" |
| 13 | #include "../../Common/StringConvert.h" | 12 | #include "../../Common/StringConvert.h" |
| 14 | 13 | ||
| @@ -22,14 +21,19 @@ | |||
| 22 | 21 | ||
| 23 | #include "../Compress/CopyCoder.h" | 22 | #include "../Compress/CopyCoder.h" |
| 24 | 23 | ||
| 25 | #include "Common/DummyOutStream.h" | 24 | #include "Common/ItemNameUtils.h" |
| 26 | 25 | ||
| 27 | #define Get16(p) GetUi16(p) | 26 | #define Get16(p) GetUi16(p) |
| 28 | #define Get32(p) GetUi32(p) | 27 | #define Get32(p) GetUi32(p) |
| 29 | #define Get16a(p) GetUi16a(p) | 28 | #define Get16a(p) GetUi16a(p) |
| 30 | #define Get32a(p) GetUi32a(p) | 29 | #define Get32a(p) GetUi32a(p) |
| 31 | 30 | ||
| 32 | #define PRF(x) /* x */ | 31 | #if 0 |
| 32 | #include <stdio.h> | ||
| 33 | #define PRF(x) x | ||
| 34 | #else | ||
| 35 | #define PRF(x) | ||
| 36 | #endif | ||
| 33 | 37 | ||
| 34 | namespace NArchive { | 38 | namespace NArchive { |
| 35 | namespace NFat { | 39 | namespace NFat { |
| @@ -38,35 +42,34 @@ static const UInt32 kFatItemUsedByDirMask = (UInt32)1 << 31; | |||
| 38 | 42 | ||
| 39 | struct CHeader | 43 | struct CHeader |
| 40 | { | 44 | { |
| 41 | UInt32 NumSectors; | 45 | Byte NumFatBits; |
| 42 | UInt16 NumReservedSectors; | 46 | Byte SectorSizeLog; |
| 47 | Byte SectorsPerClusterLog; | ||
| 48 | Byte ClusterSizeLog; | ||
| 43 | Byte NumFats; | 49 | Byte NumFats; |
| 50 | Byte MediaType; | ||
| 51 | |||
| 52 | bool VolFieldsDefined; | ||
| 53 | bool HeadersWarning; | ||
| 54 | |||
| 55 | UInt32 FatSize; | ||
| 56 | UInt32 BadCluster; | ||
| 57 | |||
| 58 | UInt16 NumReservedSectors; | ||
| 59 | UInt32 NumSectors; | ||
| 44 | UInt32 NumFatSectors; | 60 | UInt32 NumFatSectors; |
| 45 | UInt32 RootDirSector; | 61 | UInt32 RootDirSector; |
| 46 | UInt32 NumRootDirSectors; | 62 | UInt32 NumRootDirSectors; |
| 47 | UInt32 DataSector; | 63 | UInt32 DataSector; |
| 48 | 64 | ||
| 49 | UInt32 FatSize; | ||
| 50 | UInt32 BadCluster; | ||
| 51 | |||
| 52 | Byte NumFatBits; | ||
| 53 | Byte SectorSizeLog; | ||
| 54 | Byte SectorsPerClusterLog; | ||
| 55 | Byte ClusterSizeLog; | ||
| 56 | |||
| 57 | UInt16 SectorsPerTrack; | 65 | UInt16 SectorsPerTrack; |
| 58 | UInt16 NumHeads; | 66 | UInt16 NumHeads; |
| 59 | UInt32 NumHiddenSectors; | 67 | UInt32 NumHiddenSectors; |
| 60 | |||
| 61 | bool VolFieldsDefined; | ||
| 62 | bool HeadersWarning; | ||
| 63 | 68 | ||
| 64 | UInt32 VolId; | 69 | UInt32 VolId; |
| 65 | // Byte VolName[11]; | 70 | // Byte VolName[11]; |
| 66 | // Byte FileSys[8]; | 71 | // Byte FileSys[8]; |
| 67 | |||
| 68 | // Byte OemName[5]; | 72 | // Byte OemName[5]; |
| 69 | Byte MediaType; | ||
| 70 | 73 | ||
| 71 | // 32-bit FAT | 74 | // 32-bit FAT |
| 72 | UInt16 Flags; | 75 | UInt16 Flags; |
| @@ -104,15 +107,8 @@ struct CHeader | |||
| 104 | bool Parse(const Byte *p); | 107 | bool Parse(const Byte *p); |
| 105 | }; | 108 | }; |
| 106 | 109 | ||
| 107 | static int GetLog(UInt32 num) | ||
| 108 | { | ||
| 109 | for (int i = 0; i < 31; i++) | ||
| 110 | if (((UInt32)1 << i) == num) | ||
| 111 | return i; | ||
| 112 | return -1; | ||
| 113 | } | ||
| 114 | 110 | ||
| 115 | static const UInt32 kHeaderSize = 512; | 111 | static const unsigned kHeaderSize = 512; |
| 116 | 112 | ||
| 117 | API_FUNC_IsArc IsArc_Fat(const Byte *p, size_t size); | 113 | API_FUNC_IsArc IsArc_Fat(const Byte *p, size_t size); |
| 118 | API_FUNC_IsArc IsArc_Fat(const Byte *p, size_t size) | 114 | API_FUNC_IsArc IsArc_Fat(const Byte *p, size_t size) |
| @@ -125,7 +121,7 @@ API_FUNC_IsArc IsArc_Fat(const Byte *p, size_t size) | |||
| 125 | 121 | ||
| 126 | bool CHeader::Parse(const Byte *p) | 122 | bool CHeader::Parse(const Byte *p) |
| 127 | { | 123 | { |
| 128 | if (p[0x1FE] != 0x55 || p[0x1FF] != 0xAA) | 124 | if (Get16(p + 0x1FE) != 0xAA55) |
| 129 | return false; | 125 | return false; |
| 130 | 126 | ||
| 131 | HeadersWarning = false; | 127 | HeadersWarning = false; |
| @@ -139,22 +135,40 @@ bool CHeader::Parse(const Byte *p) | |||
| 139 | } | 135 | } |
| 140 | { | 136 | { |
| 141 | { | 137 | { |
| 142 | const UInt32 val32 = Get16(p + 11); | 138 | const unsigned num = Get16(p + 11); |
| 143 | const int s = GetLog(val32); | 139 | unsigned i = 9; |
| 144 | if (s < 9 || s > 12) | 140 | unsigned m = 1 << i; |
| 145 | return false; | 141 | for (;;) |
| 146 | SectorSizeLog = (Byte)s; | 142 | { |
| 143 | if (m == num) | ||
| 144 | break; | ||
| 145 | m <<= 1; | ||
| 146 | if (++i > 12) | ||
| 147 | return false; | ||
| 148 | } | ||
| 149 | SectorSizeLog = (Byte)i; | ||
| 147 | } | 150 | } |
| 148 | { | 151 | { |
| 149 | const UInt32 val32 = p[13]; | 152 | const unsigned num = p[13]; |
| 150 | const int s = GetLog(val32); | 153 | unsigned i = 0; |
| 151 | if (s < 0) | 154 | unsigned m = 1 << i; |
| 155 | for (;;) | ||
| 156 | { | ||
| 157 | if (m == num) | ||
| 158 | break; | ||
| 159 | m <<= 1; | ||
| 160 | if (++i > 7) | ||
| 161 | return false; | ||
| 162 | } | ||
| 163 | SectorsPerClusterLog = (Byte)i; | ||
| 164 | i += SectorSizeLog; | ||
| 165 | ClusterSizeLog = (Byte)i; | ||
| 166 | // (2^15 = 32 KB is safe cluster size that is suported by all system. | ||
| 167 | // (2^16 = 64 KB is supported by some systems | ||
| 168 | // (128 KB / 256 KB) can be created by some tools, but it is not supported by many tools. | ||
| 169 | if (i > 18) // 256 KB | ||
| 152 | return false; | 170 | return false; |
| 153 | SectorsPerClusterLog = (Byte)s; | ||
| 154 | } | 171 | } |
| 155 | ClusterSizeLog = (Byte)(SectorSizeLog + SectorsPerClusterLog); | ||
| 156 | if (ClusterSizeLog > 24) | ||
| 157 | return false; | ||
| 158 | } | 172 | } |
| 159 | 173 | ||
| 160 | NumReservedSectors = Get16(p + 14); | 174 | NumReservedSectors = Get16(p + 14); |
| @@ -169,7 +183,7 @@ bool CHeader::Parse(const Byte *p) | |||
| 169 | const bool isOkOffset = (codeOffset == 0) | 183 | const bool isOkOffset = (codeOffset == 0) |
| 170 | || (codeOffset == (p[0] == 0xEB ? 2 : 3)); | 184 | || (codeOffset == (p[0] == 0xEB ? 2 : 3)); |
| 171 | 185 | ||
| 172 | const UInt16 numRootDirEntries = Get16(p + 17); | 186 | const unsigned numRootDirEntries = Get16(p + 17); |
| 173 | if (numRootDirEntries == 0) | 187 | if (numRootDirEntries == 0) |
| 174 | { | 188 | { |
| 175 | if (codeOffset < 90 && !isOkOffset) | 189 | if (codeOffset < 90 && !isOkOffset) |
| @@ -183,10 +197,10 @@ bool CHeader::Parse(const Byte *p) | |||
| 183 | if (codeOffset < 62 - 24 && !isOkOffset) | 197 | if (codeOffset < 62 - 24 && !isOkOffset) |
| 184 | return false; | 198 | return false; |
| 185 | NumFatBits = 0; | 199 | NumFatBits = 0; |
| 186 | const UInt32 mask = (1 << (SectorSizeLog - 5)) - 1; | 200 | const unsigned mask = (1u << (SectorSizeLog - 5)) - 1; |
| 187 | if ((numRootDirEntries & mask) != 0) | 201 | if (numRootDirEntries & mask) |
| 188 | return false; | 202 | return false; |
| 189 | NumRootDirSectors = (numRootDirEntries + mask) >> (SectorSizeLog - 5); | 203 | NumRootDirSectors = (numRootDirEntries /* + mask */) >> (SectorSizeLog - 5); |
| 190 | } | 204 | } |
| 191 | 205 | ||
| 192 | NumSectors = Get16(p + 19); | 206 | NumSectors = Get16(p + 19); |
| @@ -198,7 +212,6 @@ bool CHeader::Parse(const Byte *p) | |||
| 198 | else if (IsFat32()) | 212 | else if (IsFat32()) |
| 199 | return false; | 213 | return false; |
| 200 | */ | 214 | */ |
| 201 | |||
| 202 | MediaType = p[21]; | 215 | MediaType = p[21]; |
| 203 | NumFatSectors = Get16(p + 22); | 216 | NumFatSectors = Get16(p + 22); |
| 204 | SectorsPerTrack = Get16(p + 24); | 217 | SectorsPerTrack = Get16(p + 24); |
| @@ -222,7 +235,7 @@ bool CHeader::Parse(const Byte *p) | |||
| 222 | return false; | 235 | return false; |
| 223 | RootCluster = Get32(p + 8); | 236 | RootCluster = Get32(p + 8); |
| 224 | FsInfoSector = Get16(p + 12); | 237 | FsInfoSector = Get16(p + 12); |
| 225 | for (int i = 16; i < 28; i++) | 238 | for (unsigned i = 16; i < 28; i++) |
| 226 | if (p[i] != 0) | 239 | if (p[i] != 0) |
| 227 | return false; | 240 | return false; |
| 228 | p += 28; | 241 | p += 28; |
| @@ -260,7 +273,7 @@ bool CHeader::Parse(const Byte *p) | |||
| 260 | if (numClusters >= 0xFFF5) | 273 | if (numClusters >= 0xFFF5) |
| 261 | return false; | 274 | return false; |
| 262 | NumFatBits = (Byte)(numClusters < 0xFF5 ? 12 : 16); | 275 | NumFatBits = (Byte)(numClusters < 0xFF5 ? 12 : 16); |
| 263 | BadCluster &= ((1 << NumFatBits) - 1); | 276 | BadCluster &= (((UInt32)1 << NumFatBits) - 1); |
| 264 | } | 277 | } |
| 265 | 278 | ||
| 266 | FatSize = numClusters + 2; | 279 | FatSize = numClusters + 2; |
| @@ -283,103 +296,157 @@ bool CHeader::Parse(const Byte *p) | |||
| 283 | return true; | 296 | return true; |
| 284 | } | 297 | } |
| 285 | 298 | ||
| 286 | struct CItem | 299 | |
| 300 | |||
| 301 | class CItem | ||
| 287 | { | 302 | { |
| 288 | UString UName; | 303 | Z7_CLASS_NO_COPY(CItem) |
| 289 | char DosName[11]; | 304 | public: |
| 305 | UInt32 Size; | ||
| 306 | Byte Attrib; | ||
| 290 | Byte CTime2; | 307 | Byte CTime2; |
| 291 | UInt32 CTime; | ||
| 292 | UInt32 MTime; | ||
| 293 | UInt16 ADate; | 308 | UInt16 ADate; |
| 294 | Byte Attrib; | 309 | CByteBuffer LongName; // if LongName.Size() == 0 : no long name |
| 310 | // if LongName.Size() != 0 : it's NULL terminated UTF16-LE string. | ||
| 311 | char DosName[11]; | ||
| 295 | Byte Flags; | 312 | Byte Flags; |
| 296 | UInt32 Size; | 313 | UInt32 MTime; |
| 314 | UInt32 CTime; | ||
| 297 | UInt32 Cluster; | 315 | UInt32 Cluster; |
| 298 | Int32 Parent; | 316 | Int32 Parent; |
| 299 | 317 | ||
| 318 | CItem() {} | ||
| 319 | |||
| 300 | // NT uses Flags to store Low Case status | 320 | // NT uses Flags to store Low Case status |
| 301 | bool NameIsLow() const { return (Flags & 0x8) != 0; } | 321 | bool NameIsLow() const { return (Flags & 0x8) != 0; } |
| 302 | bool ExtIsLow() const { return (Flags & 0x10) != 0; } | 322 | bool ExtIsLow() const { return (Flags & 0x10) != 0; } |
| 303 | bool IsDir() const { return (Attrib & 0x10) != 0; } | 323 | bool IsDir() const { return (Attrib & 0x10) != 0; } |
| 304 | UString GetShortName() const; | 324 | void GetShortName(UString &dest) const; |
| 305 | UString GetName() const; | 325 | void GetName(UString &name) const; |
| 306 | UString GetVolName() const; | ||
| 307 | }; | 326 | }; |
| 308 | 327 | ||
| 309 | static unsigned CopyAndTrim(char *dest, const char *src, unsigned size, bool toLower) | 328 | |
| 329 | static char *CopyAndTrim(char *dest, const char *src, | ||
| 330 | unsigned size, unsigned toLower) | ||
| 310 | { | 331 | { |
| 311 | memcpy(dest, src, size); | 332 | do |
| 312 | if (toLower) | ||
| 313 | { | 333 | { |
| 314 | for (unsigned i = 0; i < size; i++) | 334 | if (src[(size_t)size - 1] != ' ') |
| 315 | { | 335 | { |
| 316 | char c = dest[i]; | 336 | const unsigned range = toLower ? 'Z' - 'A' + 1 : 0; |
| 317 | if (c >= 'A' && c <= 'Z') | 337 | do |
| 318 | dest[i] = (char)(c + 0x20); | 338 | { |
| 339 | unsigned c = (Byte)*src++; | ||
| 340 | if ((unsigned)(c - 'A') < range) | ||
| 341 | c += 0x20; | ||
| 342 | *dest++ = (char)c; | ||
| 343 | } | ||
| 344 | while (--size); | ||
| 345 | break; | ||
| 319 | } | 346 | } |
| 320 | } | 347 | } |
| 321 | 348 | while (--size); | |
| 322 | for (unsigned i = size;;) | 349 | *dest = 0; |
| 323 | { | 350 | return dest; |
| 324 | if (i == 0) | ||
| 325 | return 0; | ||
| 326 | if (dest[i - 1] != ' ') | ||
| 327 | return i; | ||
| 328 | i--; | ||
| 329 | } | ||
| 330 | } | 351 | } |
| 331 | 352 | ||
| 332 | static UString FatStringToUnicode(const char *s) | 353 | |
| 354 | static void FatStringToUnicode(UString &dest, const char *s) | ||
| 333 | { | 355 | { |
| 334 | return MultiByteToUnicodeString(s, CP_OEMCP); | 356 | MultiByteToUnicodeString2(dest, AString(s), CP_OEMCP); |
| 335 | } | 357 | } |
| 336 | 358 | ||
| 337 | UString CItem::GetShortName() const | 359 | void CItem::GetShortName(UString &shortName) const |
| 338 | { | 360 | { |
| 339 | char s[16]; | 361 | char s[16]; |
| 340 | unsigned i = CopyAndTrim(s, DosName, 8, NameIsLow()); | 362 | char *dest = CopyAndTrim(s, DosName, 8, NameIsLow()); |
| 341 | s[i++] = '.'; | 363 | *dest++ = '.'; |
| 342 | unsigned j = CopyAndTrim(s + i, DosName + 8, 3, ExtIsLow()); | 364 | char *dest2 = CopyAndTrim(dest, DosName + 8, 3, ExtIsLow()); |
| 343 | if (j == 0) | 365 | if (dest == dest2) |
| 344 | i--; | 366 | dest[-1] = 0; |
| 345 | s[i + j] = 0; | 367 | FatStringToUnicode(shortName, s); |
| 346 | return FatStringToUnicode(s); | ||
| 347 | } | 368 | } |
| 348 | 369 | ||
| 349 | UString CItem::GetName() const | 370 | |
| 371 | |||
| 372 | // numWords != 0 | ||
| 373 | static unsigned ParseLongName(UInt16 *buf, unsigned numWords) | ||
| 350 | { | 374 | { |
| 351 | if (!UName.IsEmpty()) | 375 | unsigned i; |
| 352 | return UName; | 376 | for (i = 0; i < numWords; i++) |
| 353 | return GetShortName(); | 377 | { |
| 378 | const unsigned c = buf[i]; | ||
| 379 | if (c == 0) | ||
| 380 | break; | ||
| 381 | if (c == 0xFFFF) | ||
| 382 | return 0; | ||
| 383 | } | ||
| 384 | if (i == 0) | ||
| 385 | return 0; | ||
| 386 | buf[i] = 0; | ||
| 387 | numWords -= i; | ||
| 388 | i++; | ||
| 389 | if (numWords > 1) | ||
| 390 | { | ||
| 391 | numWords--; | ||
| 392 | buf += i; | ||
| 393 | do | ||
| 394 | if (*buf++ != 0xFFFF) | ||
| 395 | return 0; | ||
| 396 | while (--numWords); | ||
| 397 | } | ||
| 398 | return i; // it includes NULL terminator | ||
| 399 | } | ||
| 400 | |||
| 401 | |||
| 402 | void CItem::GetName(UString &name) const | ||
| 403 | { | ||
| 404 | if (LongName.Size() >= 2) | ||
| 405 | { | ||
| 406 | const Byte * const p = LongName; | ||
| 407 | const unsigned numWords = ((unsigned)LongName.Size() - 2) / 2; | ||
| 408 | wchar_t *dest = name.GetBuf(numWords); | ||
| 409 | for (unsigned i = 0; i < numWords; i++) | ||
| 410 | dest[i] = (wchar_t)Get16(p + (size_t)i * 2); | ||
| 411 | name.ReleaseBuf_SetEnd(numWords); | ||
| 412 | } | ||
| 413 | else | ||
| 414 | GetShortName(name); | ||
| 415 | if (name.IsEmpty()) // it's unexpected | ||
| 416 | name = '_'; | ||
| 417 | NItemName::NormalizeSlashes_in_FileName_for_OsPath(name); | ||
| 354 | } | 418 | } |
| 355 | 419 | ||
| 356 | UString CItem::GetVolName() const | 420 | |
| 421 | static void GetVolName(const char dosName[11], NWindows::NCOM::CPropVariant &prop) | ||
| 357 | { | 422 | { |
| 358 | if (!UName.IsEmpty()) | ||
| 359 | return UName; | ||
| 360 | char s[12]; | 423 | char s[12]; |
| 361 | unsigned i = CopyAndTrim(s, DosName, 11, false); | 424 | CopyAndTrim(s, dosName, 11, false); |
| 362 | s[i] = 0; | 425 | UString u; |
| 363 | return FatStringToUnicode(s); | 426 | FatStringToUnicode(u, AString(s)); |
| 427 | prop = u; | ||
| 364 | } | 428 | } |
| 365 | 429 | ||
| 430 | |||
| 366 | struct CDatabase | 431 | struct CDatabase |
| 367 | { | 432 | { |
| 368 | CHeader Header; | ||
| 369 | CObjectVector<CItem> Items; | 433 | CObjectVector<CItem> Items; |
| 370 | UInt32 *Fat; | 434 | UInt32 *Fat; |
| 435 | CHeader Header; | ||
| 371 | CMyComPtr<IInStream> InStream; | 436 | CMyComPtr<IInStream> InStream; |
| 372 | IArchiveOpenCallback *OpenCallback; | 437 | IArchiveOpenCallback *OpenCallback; |
| 438 | CAlignedBuffer ByteBuf; | ||
| 439 | CByteBuffer LfnBuf; | ||
| 373 | 440 | ||
| 374 | UInt32 NumFreeClusters; | 441 | UInt32 NumFreeClusters; |
| 375 | bool VolItemDefined; | ||
| 376 | CItem VolItem; | ||
| 377 | UInt32 NumDirClusters; | 442 | UInt32 NumDirClusters; |
| 378 | CByteBuffer ByteBuf; | ||
| 379 | UInt64 NumCurUsedBytes; | 443 | UInt64 NumCurUsedBytes; |
| 380 | |||
| 381 | UInt64 PhySize; | 444 | UInt64 PhySize; |
| 382 | 445 | ||
| 446 | UInt32 Vol_MTime; | ||
| 447 | char VolLabel[11]; | ||
| 448 | bool VolItem_Defined; | ||
| 449 | |||
| 383 | CDatabase(): Fat(NULL) {} | 450 | CDatabase(): Fat(NULL) {} |
| 384 | ~CDatabase() { ClearAndClose(); } | 451 | ~CDatabase() { ClearAndClose(); } |
| 385 | 452 | ||
| @@ -388,7 +455,7 @@ struct CDatabase | |||
| 388 | HRESULT OpenProgressFat(bool changeTotal = true); | 455 | HRESULT OpenProgressFat(bool changeTotal = true); |
| 389 | HRESULT OpenProgress(); | 456 | HRESULT OpenProgress(); |
| 390 | 457 | ||
| 391 | UString GetItemPath(UInt32 index) const; | 458 | void GetItemPath(UInt32 index, UString &s) const; |
| 392 | HRESULT Open(); | 459 | HRESULT Open(); |
| 393 | HRESULT ReadDir(Int32 parent, UInt32 cluster, unsigned level); | 460 | HRESULT ReadDir(Int32 parent, UInt32 cluster, unsigned level); |
| 394 | 461 | ||
| @@ -400,6 +467,7 @@ struct CDatabase | |||
| 400 | HRESULT SeekToCluster(UInt32 cluster) { return SeekToSector(Header.ClusterToSector(cluster)); } | 467 | HRESULT SeekToCluster(UInt32 cluster) { return SeekToSector(Header.ClusterToSector(cluster)); } |
| 401 | }; | 468 | }; |
| 402 | 469 | ||
| 470 | |||
| 403 | HRESULT CDatabase::SeekToSector(UInt32 sector) | 471 | HRESULT CDatabase::SeekToSector(UInt32 sector) |
| 404 | { | 472 | { |
| 405 | return InStream_SeekSet(InStream, (UInt64)sector << Header.SectorSizeLog); | 473 | return InStream_SeekSet(InStream, (UInt64)sector << Header.SectorSizeLog); |
| @@ -408,7 +476,7 @@ HRESULT CDatabase::SeekToSector(UInt32 sector) | |||
| 408 | void CDatabase::Clear() | 476 | void CDatabase::Clear() |
| 409 | { | 477 | { |
| 410 | PhySize = 0; | 478 | PhySize = 0; |
| 411 | VolItemDefined = false; | 479 | VolItem_Defined = false; |
| 412 | NumDirClusters = 0; | 480 | NumDirClusters = 0; |
| 413 | NumCurUsedBytes = 0; | 481 | NumCurUsedBytes = 0; |
| 414 | 482 | ||
| @@ -440,49 +508,35 @@ HRESULT CDatabase::OpenProgress() | |||
| 440 | { | 508 | { |
| 441 | if (!OpenCallback) | 509 | if (!OpenCallback) |
| 442 | return S_OK; | 510 | return S_OK; |
| 443 | UInt64 numItems = Items.Size(); | 511 | const UInt64 numItems = Items.Size(); |
| 444 | return OpenCallback->SetCompleted(&numItems, &NumCurUsedBytes); | 512 | return OpenCallback->SetCompleted(&numItems, &NumCurUsedBytes); |
| 445 | } | 513 | } |
| 446 | 514 | ||
| 447 | UString CDatabase::GetItemPath(UInt32 index) const | 515 | void CDatabase::GetItemPath(UInt32 index, UString &s) const |
| 448 | { | 516 | { |
| 449 | const CItem *item = &Items[index]; | 517 | UString name; |
| 450 | UString name = item->GetName(); | ||
| 451 | for (;;) | 518 | for (;;) |
| 452 | { | 519 | { |
| 453 | index = (UInt32)item->Parent; | 520 | const CItem &item = Items[index]; |
| 454 | if (item->Parent < 0) | 521 | item.GetName(name); |
| 455 | return name; | 522 | if (item.Parent >= 0) |
| 456 | item = &Items[index]; | 523 | name.InsertAtFront(WCHAR_PATH_SEPARATOR); |
| 457 | name.InsertAtFront(WCHAR_PATH_SEPARATOR); | 524 | s.Insert(0, name); |
| 458 | if (item->UName.IsEmpty()) | 525 | index = (UInt32)item.Parent; |
| 459 | name.Insert(0, item->GetShortName()); | 526 | if (item.Parent < 0) |
| 460 | else | 527 | break; |
| 461 | name.Insert(0, item->UName); | ||
| 462 | } | 528 | } |
| 463 | } | 529 | } |
| 464 | 530 | ||
| 465 | static wchar_t *AddSubStringToName(wchar_t *dest, const Byte *p, unsigned numChars) | ||
| 466 | { | ||
| 467 | for (unsigned i = 0; i < numChars; i++) | ||
| 468 | { | ||
| 469 | wchar_t c = Get16(p + i * 2); | ||
| 470 | if (c != 0 && c != 0xFFFF) | ||
| 471 | *dest++ = c; | ||
| 472 | } | ||
| 473 | *dest = 0; | ||
| 474 | return dest; | ||
| 475 | } | ||
| 476 | 531 | ||
| 477 | HRESULT CDatabase::ReadDir(Int32 parent, UInt32 cluster, unsigned level) | 532 | HRESULT CDatabase::ReadDir(Int32 parent, UInt32 cluster, unsigned level) |
| 478 | { | 533 | { |
| 479 | unsigned startIndex = Items.Size(); | 534 | const unsigned startIndex = Items.Size(); |
| 480 | if (startIndex >= (1 << 30) || level > 256) | 535 | if (startIndex >= (1 << 30) || level > 256) |
| 481 | return S_FALSE; | 536 | return S_FALSE; |
| 482 | 537 | ||
| 483 | UInt32 sectorIndex = 0; | ||
| 484 | UInt32 blockSize = Header.ClusterSize(); | 538 | UInt32 blockSize = Header.ClusterSize(); |
| 485 | bool clusterMode = (Header.IsFat32() || parent >= 0); | 539 | const bool clusterMode = (Header.IsFat32() || parent >= 0); |
| 486 | if (!clusterMode) | 540 | if (!clusterMode) |
| 487 | { | 541 | { |
| 488 | blockSize = Header.SectorSize(); | 542 | blockSize = Header.SectorSize(); |
| @@ -490,21 +544,26 @@ HRESULT CDatabase::ReadDir(Int32 parent, UInt32 cluster, unsigned level) | |||
| 490 | } | 544 | } |
| 491 | 545 | ||
| 492 | ByteBuf.Alloc(blockSize); | 546 | ByteBuf.Alloc(blockSize); |
| 493 | UString curName; | 547 | |
| 494 | int checkSum = -1; | 548 | const unsigned k_NumLfnRecords_MAX = 20; // 260 symbols limit (strict limit) |
| 495 | int numLongRecords = -1; | 549 | // const unsigned k_NumLfnRecords_MAX = 0x40 - 1; // 1260 symbols limit (relaxed limit) |
| 550 | const unsigned k_NumLfnBytes_in_Record = 13 * 2; | ||
| 551 | // we reserve 2 additional bytes for NULL terminator | ||
| 552 | LfnBuf.Alloc(k_NumLfnRecords_MAX * k_NumLfnBytes_in_Record + 2 * 1); | ||
| 496 | 553 | ||
| 554 | UInt32 curDirBytes_read = 0; | ||
| 555 | UInt32 sectorIndex = 0; | ||
| 556 | unsigned num_lfn_records = 0; | ||
| 557 | unsigned lfn_RecordIndex = 0; | ||
| 558 | int checkSum = -1; | ||
| 559 | bool is_record_error = false; | ||
| 560 | |||
| 497 | for (UInt32 pos = blockSize;; pos += 32) | 561 | for (UInt32 pos = blockSize;; pos += 32) |
| 498 | { | 562 | { |
| 499 | if (pos == blockSize) | 563 | if (pos == blockSize) |
| 500 | { | 564 | { |
| 501 | pos = 0; | 565 | pos = 0; |
| 502 | 566 | ||
| 503 | if ((NumDirClusters & 0xFF) == 0) | ||
| 504 | { | ||
| 505 | RINOK(OpenProgress()) | ||
| 506 | } | ||
| 507 | |||
| 508 | if (clusterMode) | 567 | if (clusterMode) |
| 509 | { | 568 | { |
| 510 | if (Header.IsEoc(cluster)) | 569 | if (Header.IsEoc(cluster)) |
| @@ -514,21 +573,37 @@ HRESULT CDatabase::ReadDir(Int32 parent, UInt32 cluster, unsigned level) | |||
| 514 | PRF(printf("\nCluster = %4X", cluster)); | 573 | PRF(printf("\nCluster = %4X", cluster)); |
| 515 | RINOK(SeekToCluster(cluster)) | 574 | RINOK(SeekToCluster(cluster)) |
| 516 | const UInt32 newCluster = Fat[cluster]; | 575 | const UInt32 newCluster = Fat[cluster]; |
| 517 | if ((newCluster & kFatItemUsedByDirMask) != 0) | 576 | if (newCluster & kFatItemUsedByDirMask) |
| 518 | return S_FALSE; | 577 | return S_FALSE; |
| 519 | Fat[cluster] |= kFatItemUsedByDirMask; | 578 | Fat[cluster] |= kFatItemUsedByDirMask; |
| 520 | cluster = newCluster; | 579 | cluster = newCluster; |
| 521 | NumDirClusters++; | 580 | NumDirClusters++; |
| 581 | if ((NumDirClusters & 0xFF) == 0) | ||
| 582 | { | ||
| 583 | RINOK(OpenProgress()) | ||
| 584 | } | ||
| 522 | NumCurUsedBytes += Header.ClusterSize(); | 585 | NumCurUsedBytes += Header.ClusterSize(); |
| 523 | } | 586 | } |
| 524 | else if (sectorIndex++ >= Header.NumRootDirSectors) | 587 | else if (sectorIndex++ >= Header.NumRootDirSectors) |
| 525 | break; | 588 | break; |
| 526 | 589 | ||
| 590 | // if (curDirBytes_read > (1u << 28)) // do we need some relaxed limit for non-MS FATs? | ||
| 591 | if (curDirBytes_read >= (1u << 21)) // 2MB limit from FAT specification. | ||
| 592 | return S_FALSE; | ||
| 527 | RINOK(ReadStream_FALSE(InStream, ByteBuf, blockSize)) | 593 | RINOK(ReadStream_FALSE(InStream, ByteBuf, blockSize)) |
| 594 | curDirBytes_read += blockSize; | ||
| 528 | } | 595 | } |
| 529 | 596 | ||
| 530 | const Byte *p = ByteBuf + pos; | 597 | if (is_record_error) |
| 531 | 598 | { | |
| 599 | Header.HeadersWarning = true; | ||
| 600 | num_lfn_records = 0; | ||
| 601 | lfn_RecordIndex = 0; | ||
| 602 | checkSum = -1; | ||
| 603 | } | ||
| 604 | |||
| 605 | const Byte * const p = ByteBuf + pos; | ||
| 606 | |||
| 532 | if (p[0] == 0) | 607 | if (p[0] == 0) |
| 533 | { | 608 | { |
| 534 | /* | 609 | /* |
| @@ -538,125 +613,191 @@ HRESULT CDatabase::ReadDir(Int32 parent, UInt32 cluster, unsigned level) | |||
| 538 | */ | 613 | */ |
| 539 | break; | 614 | break; |
| 540 | } | 615 | } |
| 541 | 616 | ||
| 617 | is_record_error = true; | ||
| 618 | |||
| 542 | if (p[0] == 0xE5) | 619 | if (p[0] == 0xE5) |
| 543 | { | 620 | { |
| 544 | if (numLongRecords > 0) | 621 | // deleted entry |
| 545 | return S_FALSE; | 622 | if (num_lfn_records == 0) |
| 623 | is_record_error = false; | ||
| 546 | continue; | 624 | continue; |
| 547 | } | 625 | } |
| 548 | 626 | // else | |
| 549 | Byte attrib = p[11]; | ||
| 550 | if ((attrib & 0x3F) == 0xF) | ||
| 551 | { | 627 | { |
| 552 | if (p[0] > 0x7F || Get16(p + 26) != 0) | 628 | const Byte attrib = p[11]; |
| 553 | return S_FALSE; | 629 | // maybe we can use more strick check : (attrib == 0xF) ? |
| 554 | int longIndex = p[0] & 0x3F; | 630 | if ((attrib & 0x3F) == 0xF) |
| 555 | if (longIndex == 0) | ||
| 556 | return S_FALSE; | ||
| 557 | bool isLast = (p[0] & 0x40) != 0; | ||
| 558 | if (numLongRecords < 0) | ||
| 559 | { | 631 | { |
| 560 | if (!isLast) | 632 | // long file name (LFN) entry |
| 633 | const unsigned longIndex = p[0] & 0x3F; | ||
| 634 | if (longIndex == 0 | ||
| 635 | || longIndex > k_NumLfnRecords_MAX | ||
| 636 | || p[0] > 0x7F | ||
| 637 | || Get16a(p + 26) != 0 // LDIR_FstClusLO | ||
| 638 | ) | ||
| 639 | { | ||
| 561 | return S_FALSE; | 640 | return S_FALSE; |
| 562 | numLongRecords = longIndex; | 641 | // break; |
| 642 | } | ||
| 643 | const bool isLast = (p[0] & 0x40) != 0; | ||
| 644 | if (num_lfn_records == 0) | ||
| 645 | { | ||
| 646 | if (!isLast) | ||
| 647 | continue; // orphan | ||
| 648 | num_lfn_records = longIndex; | ||
| 649 | } | ||
| 650 | else if (isLast || longIndex != lfn_RecordIndex) | ||
| 651 | { | ||
| 652 | return S_FALSE; | ||
| 653 | // break; | ||
| 654 | } | ||
| 655 | |||
| 656 | lfn_RecordIndex = longIndex - 1; | ||
| 657 | |||
| 658 | if (p[12] == 0) | ||
| 659 | { | ||
| 660 | Byte * const dest = LfnBuf + k_NumLfnBytes_in_Record * lfn_RecordIndex; | ||
| 661 | memcpy(dest, p + 1, 5 * 2); | ||
| 662 | memcpy(dest + 5 * 2, p + 14, 6 * 2); | ||
| 663 | memcpy(dest + 11 * 2, p + 28, 2 * 2); | ||
| 664 | if (isLast) | ||
| 665 | checkSum = p[13]; | ||
| 666 | if (checkSum == p[13]) | ||
| 667 | is_record_error = false; | ||
| 668 | // else return S_FALSE; | ||
| 669 | continue; | ||
| 670 | } | ||
| 671 | // else | ||
| 672 | checkSum = -1; // we will ignore LfnBuf in this case | ||
| 673 | continue; | ||
| 563 | } | 674 | } |
| 564 | else if (isLast || numLongRecords != longIndex) | ||
| 565 | return S_FALSE; | ||
| 566 | |||
| 567 | numLongRecords--; | ||
| 568 | 675 | ||
| 569 | if (p[12] == 0) | 676 | if (lfn_RecordIndex) |
| 570 | { | 677 | { |
| 571 | wchar_t nameBuf[14]; | 678 | Header.HeadersWarning = true; |
| 572 | wchar_t *dest; | 679 | // return S_FALSE; |
| 573 | |||
| 574 | dest = AddSubStringToName(nameBuf, p + 1, 5); | ||
| 575 | dest = AddSubStringToName(dest, p + 14, 6); | ||
| 576 | AddSubStringToName(dest, p + 28, 2); | ||
| 577 | curName = nameBuf + curName; | ||
| 578 | if (isLast) | ||
| 579 | checkSum = p[13]; | ||
| 580 | if (checkSum != p[13]) | ||
| 581 | return S_FALSE; | ||
| 582 | } | 680 | } |
| 583 | } | 681 | // lfn_RecordIndex = 0; |
| 584 | else | ||
| 585 | { | ||
| 586 | if (numLongRecords > 0) | ||
| 587 | return S_FALSE; | ||
| 588 | CItem item; | ||
| 589 | memcpy(item.DosName, p, 11); | ||
| 590 | 682 | ||
| 591 | if (checkSum >= 0) | 683 | const unsigned type_in_attrib = attrib & 0x18; |
| 684 | if (type_in_attrib == 0x18) | ||
| 592 | { | 685 | { |
| 593 | Byte sum = 0; | 686 | // invalid directory record (both flags are set: dir_flag and volume_flag) |
| 594 | for (unsigned i = 0; i < 11; i++) | 687 | return S_FALSE; |
| 595 | sum = (Byte)(((sum & 1) ? 0x80 : 0) + (sum >> 1) + (Byte)item.DosName[i]); | 688 | // break; |
| 596 | if (sum == checkSum) | 689 | // continue; |
| 597 | item.UName = curName; | ||
| 598 | } | 690 | } |
| 599 | 691 | if (type_in_attrib == 8) // volume_flag | |
| 600 | if (item.DosName[0] == 5) | ||
| 601 | item.DosName[0] = (char)(Byte)0xE5; | ||
| 602 | item.Attrib = attrib; | ||
| 603 | item.Flags = p[12]; | ||
| 604 | item.Size = Get32(p + 28); | ||
| 605 | item.Cluster = Get16(p + 26); | ||
| 606 | if (Header.NumFatBits > 16) | ||
| 607 | item.Cluster |= ((UInt32)Get16(p + 20) << 16); | ||
| 608 | else | ||
| 609 | { | 692 | { |
| 610 | // OS/2 and WinNT probably can store EA (extended atributes) in that field. | 693 | if (!VolItem_Defined && level == 0) |
| 694 | { | ||
| 695 | VolItem_Defined = true; | ||
| 696 | memcpy(VolLabel, p, 11); | ||
| 697 | Vol_MTime = Get32(p + 22); | ||
| 698 | is_record_error = false; | ||
| 699 | } | ||
| 611 | } | 700 | } |
| 612 | 701 | else if (memcmp(p, ". ", 11) == 0 | |
| 613 | item.CTime = Get32(p + 14); | 702 | || memcmp(p, ".. ", 11) == 0) |
| 614 | item.CTime2 = p[13]; | ||
| 615 | item.ADate = Get16(p + 18); | ||
| 616 | item.MTime = Get32(p + 22); | ||
| 617 | item.Parent = parent; | ||
| 618 | |||
| 619 | if (attrib == 8) | ||
| 620 | { | 703 | { |
| 621 | VolItem = item; | 704 | if (num_lfn_records == 0 && type_in_attrib == 0x10) // dir_flag |
| 622 | VolItemDefined = true; | 705 | is_record_error = false; |
| 623 | } | 706 | } |
| 624 | else | 707 | else |
| 625 | if (memcmp(item.DosName, ". ", 11) != 0 && | ||
| 626 | memcmp(item.DosName, ".. ", 11) != 0) | ||
| 627 | { | 708 | { |
| 628 | if (!item.IsDir()) | 709 | CItem &item = Items.AddNew(); |
| 629 | NumCurUsedBytes += Header.GetFilePackSize(item.Size); | 710 | memcpy(item.DosName, p, 11); |
| 630 | Items.Add(item); | 711 | if (item.DosName[0] == 5) |
| 631 | PRF(printf("\n%7d: %S", Items.Size(), GetItemPath(Items.Size() - 1))); | 712 | item.DosName[0] = (char)(Byte)0xE5; // 0xE5 is valid KANJI lead byte value. |
| 713 | item.Attrib = attrib; | ||
| 714 | item.Flags = p[12]; | ||
| 715 | item.Size = Get32a(p + 28); | ||
| 716 | item.Cluster = Get16a(p + 26); | ||
| 717 | if (Header.NumFatBits > 16) | ||
| 718 | item.Cluster |= ((UInt32)Get16a(p + 20) << 16); | ||
| 719 | else | ||
| 720 | { | ||
| 721 | // OS/2 and WinNT probably can store EA (extended atributes) in that field. | ||
| 722 | } | ||
| 723 | item.CTime = Get32(p + 14); | ||
| 724 | item.CTime2 = p[13]; | ||
| 725 | item.ADate = Get16a(p + 18); | ||
| 726 | item.MTime = Get32(p + 22); | ||
| 727 | item.Parent = parent; | ||
| 728 | { | ||
| 729 | if (!item.IsDir()) | ||
| 730 | NumCurUsedBytes += Header.GetFilePackSize(item.Size); | ||
| 731 | // PRF(printf("\n%7d: %S", Items.Size(), GetItemPath(Items.Size() - 1))); | ||
| 732 | PRF(printf("\n%7d" /* ": %S" */, Items.Size() /* , item.GetShortName() */ );) | ||
| 733 | } | ||
| 734 | if (num_lfn_records == 0) | ||
| 735 | is_record_error = false; | ||
| 736 | else if (checkSum >= 0 && lfn_RecordIndex == 0) | ||
| 737 | { | ||
| 738 | Byte sum = 0; | ||
| 739 | for (unsigned i = 0; i < 11; i++) | ||
| 740 | sum = (Byte)((sum << 7) + (sum >> 1) + (Byte)item.DosName[i]); | ||
| 741 | if (sum == checkSum) | ||
| 742 | { | ||
| 743 | const unsigned numWords = ParseLongName((UInt16 *)(void *)(Byte *)LfnBuf, | ||
| 744 | num_lfn_records * k_NumLfnBytes_in_Record / 2); | ||
| 745 | if (numWords > 1) | ||
| 746 | { | ||
| 747 | // numWords includes NULL terminator | ||
| 748 | item.LongName.CopyFrom(LfnBuf, numWords * 2); | ||
| 749 | is_record_error = false; | ||
| 750 | } | ||
| 751 | } | ||
| 752 | } | ||
| 753 | |||
| 754 | if ( | ||
| 755 | // item.LongName.Size() < 20 || // for debug | ||
| 756 | item.LongName.Size() <= 2 * 1 | ||
| 757 | && memcmp(p, " ", 11) == 0) | ||
| 758 | { | ||
| 759 | char s[16 + 16]; | ||
| 760 | const size_t numChars = (size_t)(ConvertUInt32ToString( | ||
| 761 | Items.Size() - 1 - startIndex, | ||
| 762 | MyStpCpy(s, "[NONAME]-")) - s) + 1; | ||
| 763 | item.LongName.Alloc(numChars * 2); | ||
| 764 | for (size_t i = 0; i < numChars; i++) | ||
| 765 | { | ||
| 766 | SetUi16a(item.LongName + i * 2, (Byte)s[i]) | ||
| 767 | } | ||
| 768 | Header.HeadersWarning = true; | ||
| 769 | } | ||
| 632 | } | 770 | } |
| 633 | numLongRecords = -1; | 771 | num_lfn_records = 0; |
| 634 | curName.Empty(); | ||
| 635 | checkSum = -1; | ||
| 636 | } | 772 | } |
| 637 | } | 773 | } |
| 638 | 774 | ||
| 639 | unsigned finishIndex = Items.Size(); | 775 | if (is_record_error) |
| 776 | Header.HeadersWarning = true; | ||
| 777 | |||
| 778 | const unsigned finishIndex = Items.Size(); | ||
| 640 | for (unsigned i = startIndex; i < finishIndex; i++) | 779 | for (unsigned i = startIndex; i < finishIndex; i++) |
| 641 | { | 780 | { |
| 642 | const CItem &item = Items[i]; | 781 | const CItem &item = Items[i]; |
| 643 | if (item.IsDir()) | 782 | if (item.IsDir()) |
| 644 | { | 783 | { |
| 645 | PRF(printf("\n%S", GetItemPath(i))); | 784 | PRF(printf("\n---- %c%c%c%c%c", item.DosName[0], item.DosName[1], item.DosName[2], item.DosName[3], item.DosName[4])); |
| 646 | RINOK(CDatabase::ReadDir((int)i, item.Cluster, level + 1)) | 785 | RINOK(ReadDir((int)i, item.Cluster, level + 1)) |
| 647 | } | 786 | } |
| 648 | } | 787 | } |
| 649 | return S_OK; | 788 | return S_OK; |
| 650 | } | 789 | } |
| 651 | 790 | ||
| 791 | |||
| 792 | |||
| 652 | HRESULT CDatabase::Open() | 793 | HRESULT CDatabase::Open() |
| 653 | { | 794 | { |
| 654 | Clear(); | 795 | Clear(); |
| 655 | bool numFreeClustersDefined = false; | 796 | bool numFreeClusters_Defined = false; |
| 656 | { | 797 | { |
| 657 | Byte buf[kHeaderSize]; | 798 | UInt32 buf32[kHeaderSize / 4]; |
| 658 | RINOK(ReadStream_FALSE(InStream, buf, kHeaderSize)) | 799 | RINOK(ReadStream_FALSE(InStream, buf32, kHeaderSize)) |
| 659 | if (!Header.Parse(buf)) | 800 | if (!Header.Parse((Byte *)(void *)buf32)) |
| 660 | return S_FALSE; | 801 | return S_FALSE; |
| 661 | UInt64 fileSize; | 802 | UInt64 fileSize; |
| 662 | RINOK(InStream_GetSize_SeekToEnd(InStream, fileSize)) | 803 | RINOK(InStream_GetSize_SeekToEnd(InStream, fileSize)) |
| @@ -671,21 +812,21 @@ HRESULT CDatabase::Open() | |||
| 671 | { | 812 | { |
| 672 | if (((UInt32)Header.FsInfoSector << Header.SectorSizeLog) + kHeaderSize <= fileSize | 813 | if (((UInt32)Header.FsInfoSector << Header.SectorSizeLog) + kHeaderSize <= fileSize |
| 673 | && SeekToSector(Header.FsInfoSector) == S_OK | 814 | && SeekToSector(Header.FsInfoSector) == S_OK |
| 674 | && ReadStream_FALSE(InStream, buf, kHeaderSize) == S_OK | 815 | && ReadStream_FALSE(InStream, buf32, kHeaderSize) == S_OK |
| 675 | && 0xaa550000 == Get32(buf + 508) | 816 | && 0xaa550000 == Get32a(buf32 + 508 / 4) |
| 676 | && 0x41615252 == Get32(buf) | 817 | && 0x41615252 == Get32a(buf32) |
| 677 | && 0x61417272 == Get32(buf + 484)) | 818 | && 0x61417272 == Get32a(buf32 + 484 / 4)) |
| 678 | { | 819 | { |
| 679 | NumFreeClusters = Get32(buf + 488); | 820 | NumFreeClusters = Get32a(buf32 + 488 / 4); |
| 680 | numFreeClustersDefined = (NumFreeClusters <= Header.FatSize); | 821 | numFreeClusters_Defined = (NumFreeClusters <= Header.FatSize); |
| 681 | } | 822 | } |
| 682 | else | 823 | else |
| 683 | Header.HeadersWarning = true; | 824 | Header.HeadersWarning = true; |
| 684 | } | 825 | } |
| 685 | } | 826 | } |
| 686 | 827 | ||
| 687 | // numFreeClustersDefined = false; // to recalculate NumFreeClusters | 828 | // numFreeClusters_Defined = false; // to recalculate NumFreeClusters |
| 688 | if (!numFreeClustersDefined) | 829 | if (!numFreeClusters_Defined) |
| 689 | NumFreeClusters = 0; | 830 | NumFreeClusters = 0; |
| 690 | 831 | ||
| 691 | CByteBuffer byteBuf; | 832 | CByteBuffer byteBuf; |
| @@ -695,7 +836,7 @@ HRESULT CDatabase::Open() | |||
| 695 | RINOK(SeekToSector(Header.GetFatSector())) | 836 | RINOK(SeekToSector(Header.GetFatSector())) |
| 696 | if (Header.NumFatBits == 32) | 837 | if (Header.NumFatBits == 32) |
| 697 | { | 838 | { |
| 698 | const UInt32 kBufSize = (1 << 15); | 839 | const UInt32 kBufSize = 1 << 15; |
| 699 | byteBuf.Alloc(kBufSize); | 840 | byteBuf.Alloc(kBufSize); |
| 700 | for (UInt32 i = 0;;) | 841 | for (UInt32 i = 0;;) |
| 701 | { | 842 | { |
| @@ -712,7 +853,7 @@ HRESULT CDatabase::Open() | |||
| 712 | const UInt32 *src = (const UInt32 *)(const void *)(const Byte *)byteBuf; | 853 | const UInt32 *src = (const UInt32 *)(const void *)(const Byte *)byteBuf; |
| 713 | UInt32 *dest = Fat + i; | 854 | UInt32 *dest = Fat + i; |
| 714 | const UInt32 *srcLim = src + size; | 855 | const UInt32 *srcLim = src + size; |
| 715 | if (numFreeClustersDefined) | 856 | if (numFreeClusters_Defined) |
| 716 | do | 857 | do |
| 717 | *dest++ = Get32a(src) & 0x0FFFFFFF; | 858 | *dest++ = Get32a(src) & 0x0FFFFFFF; |
| 718 | while (++src != srcLim); | 859 | while (++src != srcLim); |
| @@ -731,7 +872,7 @@ HRESULT CDatabase::Open() | |||
| 731 | i += size; | 872 | i += size; |
| 732 | if ((i & 0xFFFFF) == 0) | 873 | if ((i & 0xFFFFF) == 0) |
| 733 | { | 874 | { |
| 734 | RINOK(OpenProgressFat(!numFreeClustersDefined)) | 875 | RINOK(OpenProgressFat(!numFreeClusters_Defined)) |
| 735 | } | 876 | } |
| 736 | } | 877 | } |
| 737 | } | 878 | } |
| @@ -751,7 +892,7 @@ HRESULT CDatabase::Open() | |||
| 751 | for (UInt32 j = 0; j < fatSize; j++) | 892 | for (UInt32 j = 0; j < fatSize; j++) |
| 752 | fat[j] = (Get16(p + j * 3 / 2) >> ((j & 1) << 2)) & 0xFFF; | 893 | fat[j] = (Get16(p + j * 3 / 2) >> ((j & 1) << 2)) & 0xFFF; |
| 753 | 894 | ||
| 754 | if (!numFreeClustersDefined) | 895 | if (!numFreeClusters_Defined) |
| 755 | { | 896 | { |
| 756 | UInt32 numFreeClusters = 0; | 897 | UInt32 numFreeClusters = 0; |
| 757 | for (UInt32 i = 0; i < fatSize; i++) | 898 | for (UInt32 i = 0; i < fatSize; i++) |
| @@ -781,11 +922,12 @@ HRESULT CDatabase::Open() | |||
| 781 | 922 | ||
| 782 | Z7_class_CHandler_final: | 923 | Z7_class_CHandler_final: |
| 783 | public IInArchive, | 924 | public IInArchive, |
| 925 | public IArchiveGetRawProps, | ||
| 784 | public IInArchiveGetStream, | 926 | public IInArchiveGetStream, |
| 785 | public CMyUnknownImp, | 927 | public CMyUnknownImp, |
| 786 | CDatabase | 928 | CDatabase |
| 787 | { | 929 | { |
| 788 | Z7_IFACES_IMP_UNK_2(IInArchive, IInArchiveGetStream) | 930 | Z7_IFACES_IMP_UNK_3(IInArchive, IArchiveGetRawProps, IInArchiveGetStream) |
| 789 | }; | 931 | }; |
| 790 | 932 | ||
| 791 | Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream)) | 933 | Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream)) |
| @@ -831,6 +973,8 @@ Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream)) | |||
| 831 | COM_TRY_END | 973 | COM_TRY_END |
| 832 | } | 974 | } |
| 833 | 975 | ||
| 976 | |||
| 977 | |||
| 834 | static const Byte kProps[] = | 978 | static const Byte kProps[] = |
| 835 | { | 979 | { |
| 836 | kpidPath, | 980 | kpidPath, |
| @@ -842,6 +986,7 @@ static const Byte kProps[] = | |||
| 842 | kpidATime, | 986 | kpidATime, |
| 843 | kpidAttrib, | 987 | kpidAttrib, |
| 844 | kpidShortName | 988 | kpidShortName |
| 989 | // , kpidCharacts | ||
| 845 | }; | 990 | }; |
| 846 | 991 | ||
| 847 | enum | 992 | enum |
| @@ -922,15 +1067,16 @@ Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) | |||
| 922 | case kpidPhySize: prop = PhySize; break; | 1067 | case kpidPhySize: prop = PhySize; break; |
| 923 | case kpidFreeSpace: prop = (UInt64)NumFreeClusters << Header.ClusterSizeLog; break; | 1068 | case kpidFreeSpace: prop = (UInt64)NumFreeClusters << Header.ClusterSizeLog; break; |
| 924 | case kpidHeadersSize: prop = GetHeadersSize(); break; | 1069 | case kpidHeadersSize: prop = GetHeadersSize(); break; |
| 925 | case kpidMTime: if (VolItemDefined) PropVariant_SetFrom_DosTime(prop, VolItem.MTime); break; | 1070 | case kpidMTime: if (VolItem_Defined) PropVariant_SetFrom_DosTime(prop, Vol_MTime); break; |
| 926 | case kpidShortComment: | 1071 | case kpidShortComment: |
| 927 | case kpidVolumeName: if (VolItemDefined) prop = VolItem.GetVolName(); break; | 1072 | case kpidVolumeName: if (VolItem_Defined) GetVolName(VolLabel, prop); break; |
| 928 | case kpidNumFats: if (Header.NumFats != 2) prop = Header.NumFats; break; | 1073 | case kpidNumFats: if (Header.NumFats != 2) prop = Header.NumFats; break; |
| 929 | case kpidSectorSize: prop = (UInt32)1 << Header.SectorSizeLog; break; | 1074 | case kpidSectorSize: prop = (UInt32)1 << Header.SectorSizeLog; break; |
| 930 | // case kpidSectorsPerTrack: prop = Header.SectorsPerTrack; break; | 1075 | // case kpidSectorsPerTrack: prop = Header.SectorsPerTrack; break; |
| 931 | // case kpidNumHeads: prop = Header.NumHeads; break; | 1076 | // case kpidNumHeads: prop = Header.NumHeads; break; |
| 932 | // case kpidOemName: STRING_TO_PROP(Header.OemName, prop); break; | 1077 | // case kpidOemName: STRING_TO_PROP(Header.OemName, prop); break; |
| 933 | case kpidId: if (Header.VolFieldsDefined) prop = Header.VolId; break; | 1078 | case kpidId: if (Header.VolFieldsDefined) prop = Header.VolId; break; |
| 1079 | case kpidIsTree: prop = true; break; | ||
| 934 | // case kpidVolName: if (Header.VolFieldsDefined) STRING_TO_PROP(Header.VolName, prop); break; | 1080 | // case kpidVolName: if (Header.VolFieldsDefined) STRING_TO_PROP(Header.VolName, prop); break; |
| 935 | // case kpidFileSysType: if (Header.VolFieldsDefined) STRING_TO_PROP(Header.FileSys, prop); break; | 1081 | // case kpidFileSysType: if (Header.VolFieldsDefined) STRING_TO_PROP(Header.FileSys, prop); break; |
| 936 | // case kpidHiddenSectors: prop = Header.NumHiddenSectors; break; | 1082 | // case kpidHiddenSectors: prop = Header.NumHiddenSectors; break; |
| @@ -948,6 +1094,52 @@ Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) | |||
| 948 | COM_TRY_END | 1094 | COM_TRY_END |
| 949 | } | 1095 | } |
| 950 | 1096 | ||
| 1097 | |||
| 1098 | Z7_COM7F_IMF(CHandler::GetNumRawProps(UInt32 *numProps)) | ||
| 1099 | { | ||
| 1100 | *numProps = 0; | ||
| 1101 | return S_OK; | ||
| 1102 | } | ||
| 1103 | |||
| 1104 | Z7_COM7F_IMF(CHandler::GetRawPropInfo(UInt32 /* index */ , BSTR *name, PROPID *propID)) | ||
| 1105 | { | ||
| 1106 | *name = NULL; | ||
| 1107 | *propID = 0; | ||
| 1108 | return S_OK; | ||
| 1109 | } | ||
| 1110 | |||
| 1111 | Z7_COM7F_IMF(CHandler::GetParent(UInt32 index, UInt32 *parent, UInt32 *parentType)) | ||
| 1112 | { | ||
| 1113 | *parentType = NParentType::kDir; | ||
| 1114 | int par = -1; | ||
| 1115 | if (index < Items.Size()) | ||
| 1116 | par = Items[index].Parent; | ||
| 1117 | *parent = (UInt32)(Int32)par; | ||
| 1118 | return S_OK; | ||
| 1119 | } | ||
| 1120 | |||
| 1121 | Z7_COM7F_IMF(CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType)) | ||
| 1122 | { | ||
| 1123 | *data = NULL; | ||
| 1124 | *dataSize = 0; | ||
| 1125 | *propType = 0; | ||
| 1126 | |||
| 1127 | if (index < Items.Size() | ||
| 1128 | && propID == kpidName) | ||
| 1129 | { | ||
| 1130 | CByteBuffer &buf = Items[index].LongName; | ||
| 1131 | const UInt32 size = (UInt32)buf.Size(); | ||
| 1132 | if (size != 0) | ||
| 1133 | { | ||
| 1134 | *dataSize = size; | ||
| 1135 | *propType = NPropDataType::kUtf16z; | ||
| 1136 | *data = (const void *)(const Byte *)buf; | ||
| 1137 | } | ||
| 1138 | } | ||
| 1139 | return S_OK; | ||
| 1140 | } | ||
| 1141 | |||
| 1142 | |||
| 951 | Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) | 1143 | Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) |
| 952 | { | 1144 | { |
| 953 | COM_TRY_BEGIN | 1145 | COM_TRY_BEGIN |
| @@ -955,8 +1147,28 @@ Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val | |||
| 955 | const CItem &item = Items[index]; | 1147 | const CItem &item = Items[index]; |
| 956 | switch (propID) | 1148 | switch (propID) |
| 957 | { | 1149 | { |
| 958 | case kpidPath: prop = GetItemPath(index); break; | 1150 | case kpidPath: |
| 959 | case kpidShortName: prop = item.GetShortName(); break; | 1151 | case kpidName: |
| 1152 | case kpidShortName: | ||
| 1153 | { | ||
| 1154 | UString s; | ||
| 1155 | if (propID == kpidPath) | ||
| 1156 | GetItemPath(index, s); | ||
| 1157 | else if (propID == kpidName) | ||
| 1158 | item.GetName(s); | ||
| 1159 | else | ||
| 1160 | item.GetShortName(s); | ||
| 1161 | prop = s; | ||
| 1162 | break; | ||
| 1163 | } | ||
| 1164 | /* | ||
| 1165 | case kpidCharacts: | ||
| 1166 | { | ||
| 1167 | if (item.LongName.Size()) | ||
| 1168 | prop = "LFN"; | ||
| 1169 | break; | ||
| 1170 | } | ||
| 1171 | */ | ||
| 960 | case kpidIsDir: prop = item.IsDir(); break; | 1172 | case kpidIsDir: prop = item.IsDir(); break; |
| 961 | case kpidMTime: PropVariant_SetFrom_DosTime(prop, item.MTime); break; | 1173 | case kpidMTime: PropVariant_SetFrom_DosTime(prop, item.MTime); break; |
| 962 | case kpidCTime: FatTimeToProp(item.CTime, item.CTime2, prop); break; | 1174 | case kpidCTime: FatTimeToProp(item.CTime, item.CTime2, prop); break; |
| @@ -1004,34 +1216,44 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, | |||
| 1004 | Int32 testMode, IArchiveExtractCallback *extractCallback)) | 1216 | Int32 testMode, IArchiveExtractCallback *extractCallback)) |
| 1005 | { | 1217 | { |
| 1006 | COM_TRY_BEGIN | 1218 | COM_TRY_BEGIN |
| 1007 | const bool allFilesMode = (numItems == (UInt32)(Int32)-1); | 1219 | if (numItems == (UInt32)(Int32)-1) |
| 1008 | if (allFilesMode) | 1220 | { |
| 1221 | indices = NULL; | ||
| 1009 | numItems = Items.Size(); | 1222 | numItems = Items.Size(); |
| 1010 | if (numItems == 0) | 1223 | if (numItems == 0) |
| 1011 | return S_OK; | 1224 | return S_OK; |
| 1012 | UInt32 i; | 1225 | } |
| 1226 | else | ||
| 1227 | { | ||
| 1228 | if (numItems == 0) | ||
| 1229 | return S_OK; | ||
| 1230 | if (!indices) | ||
| 1231 | return E_INVALIDARG; | ||
| 1232 | } | ||
| 1013 | UInt64 totalSize = 0; | 1233 | UInt64 totalSize = 0; |
| 1014 | for (i = 0; i < numItems; i++) | ||
| 1015 | { | 1234 | { |
| 1016 | const CItem &item = Items[allFilesMode ? i : indices[i]]; | 1235 | UInt32 i = 0; |
| 1017 | if (!item.IsDir()) | 1236 | do |
| 1018 | totalSize += item.Size; | 1237 | { |
| 1238 | UInt32 index = i; | ||
| 1239 | if (indices) | ||
| 1240 | index = indices[i]; | ||
| 1241 | const CItem &item = Items[index]; | ||
| 1242 | if (!item.IsDir()) | ||
| 1243 | totalSize += item.Size; | ||
| 1244 | } | ||
| 1245 | while (++i != numItems); | ||
| 1019 | } | 1246 | } |
| 1020 | RINOK(extractCallback->SetTotal(totalSize)) | 1247 | RINOK(extractCallback->SetTotal(totalSize)) |
| 1021 | 1248 | ||
| 1022 | UInt64 totalPackSize; | 1249 | CMyComPtr2_Create<ICompressProgressInfo, CLocalProgress> lps; |
| 1023 | totalSize = totalPackSize = 0; | ||
| 1024 | |||
| 1025 | NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); | ||
| 1026 | CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec; | ||
| 1027 | |||
| 1028 | CLocalProgress *lps = new CLocalProgress; | ||
| 1029 | CMyComPtr<ICompressProgressInfo> progress = lps; | ||
| 1030 | lps->Init(extractCallback, false); | 1250 | lps->Init(extractCallback, false); |
| 1251 | CMyComPtr2_Create<ICompressCoder, NCompress::CCopyCoder> copyCoder; | ||
| 1031 | 1252 | ||
| 1032 | CDummyOutStream *outStreamSpec = new CDummyOutStream; | 1253 | UInt64 totalPackSize; |
| 1033 | CMyComPtr<ISequentialOutStream> outStream(outStreamSpec); | 1254 | totalSize = totalPackSize = 0; |
| 1034 | 1255 | ||
| 1256 | UInt32 i; | ||
| 1035 | for (i = 0;; i++) | 1257 | for (i = 0;; i++) |
| 1036 | { | 1258 | { |
| 1037 | lps->InSize = totalPackSize; | 1259 | lps->InSize = totalPackSize; |
| @@ -1039,46 +1261,45 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, | |||
| 1039 | RINOK(lps->SetCur()) | 1261 | RINOK(lps->SetCur()) |
| 1040 | if (i == numItems) | 1262 | if (i == numItems) |
| 1041 | break; | 1263 | break; |
| 1042 | CMyComPtr<ISequentialOutStream> realOutStream; | 1264 | int res; |
| 1043 | const Int32 askMode = testMode ? | ||
| 1044 | NExtract::NAskMode::kTest : | ||
| 1045 | NExtract::NAskMode::kExtract; | ||
| 1046 | const UInt32 index = allFilesMode ? i : indices[i]; | ||
| 1047 | const CItem &item = Items[index]; | ||
| 1048 | RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) | ||
| 1049 | |||
| 1050 | if (item.IsDir()) | ||
| 1051 | { | 1265 | { |
| 1266 | CMyComPtr<ISequentialOutStream> realOutStream; | ||
| 1267 | const Int32 askMode = testMode ? | ||
| 1268 | NExtract::NAskMode::kTest : | ||
| 1269 | NExtract::NAskMode::kExtract; | ||
| 1270 | UInt32 index = i; | ||
| 1271 | if (indices) | ||
| 1272 | index = indices[i]; | ||
| 1273 | const CItem &item = Items[index]; | ||
| 1274 | RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) | ||
| 1275 | |||
| 1276 | if (item.IsDir()) | ||
| 1277 | { | ||
| 1278 | RINOK(extractCallback->PrepareOperation(askMode)) | ||
| 1279 | RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) | ||
| 1280 | continue; | ||
| 1281 | } | ||
| 1282 | |||
| 1283 | totalPackSize += Header.GetFilePackSize(item.Size); | ||
| 1284 | totalSize += item.Size; | ||
| 1285 | |||
| 1286 | if (!testMode && !realOutStream) | ||
| 1287 | continue; | ||
| 1052 | RINOK(extractCallback->PrepareOperation(askMode)) | 1288 | RINOK(extractCallback->PrepareOperation(askMode)) |
| 1053 | RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) | 1289 | res = NExtract::NOperationResult::kDataError; |
| 1054 | continue; | 1290 | CMyComPtr<ISequentialInStream> inStream; |
| 1055 | } | 1291 | const HRESULT hres = GetStream(index, &inStream); |
| 1056 | 1292 | if (hres != S_FALSE) | |
| 1057 | totalPackSize += Header.GetFilePackSize(item.Size); | ||
| 1058 | totalSize += item.Size; | ||
| 1059 | |||
| 1060 | if (!testMode && !realOutStream) | ||
| 1061 | continue; | ||
| 1062 | RINOK(extractCallback->PrepareOperation(askMode)) | ||
| 1063 | |||
| 1064 | outStreamSpec->SetStream(realOutStream); | ||
| 1065 | realOutStream.Release(); | ||
| 1066 | outStreamSpec->Init(); | ||
| 1067 | |||
| 1068 | int res = NExtract::NOperationResult::kDataError; | ||
| 1069 | CMyComPtr<ISequentialInStream> inStream; | ||
| 1070 | HRESULT hres = GetStream(index, &inStream); | ||
| 1071 | if (hres != S_FALSE) | ||
| 1072 | { | ||
| 1073 | RINOK(hres) | ||
| 1074 | if (inStream) | ||
| 1075 | { | 1293 | { |
| 1076 | RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)) | 1294 | RINOK(hres) |
| 1077 | if (copyCoderSpec->TotalSize == item.Size) | 1295 | if (inStream) |
| 1078 | res = NExtract::NOperationResult::kOK; | 1296 | { |
| 1297 | RINOK(copyCoder.Interface()->Code(inStream, realOutStream, NULL, NULL, lps)) | ||
| 1298 | if (copyCoder->TotalSize == item.Size) | ||
| 1299 | res = NExtract::NOperationResult::kOK; | ||
| 1300 | } | ||
| 1079 | } | 1301 | } |
| 1080 | } | 1302 | } |
| 1081 | outStreamSpec->ReleaseStream(); | ||
| 1082 | RINOK(extractCallback->SetOperationResult(res)) | 1303 | RINOK(extractCallback->SetOperationResult(res)) |
| 1083 | } | 1304 | } |
| 1084 | return S_OK; | 1305 | return S_OK; |
diff --git a/CPP/7zip/Archive/Nsis/NsisIn.cpp b/CPP/7zip/Archive/Nsis/NsisIn.cpp index c9e2c01..194e5bf 100644 --- a/CPP/7zip/Archive/Nsis/NsisIn.cpp +++ b/CPP/7zip/Archive/Nsis/NsisIn.cpp | |||
| @@ -4005,7 +4005,7 @@ HRESULT CInArchive::ReadEntries(const CBlockHeader &bh) | |||
| 4005 | AddParam_Var(params[0]); | 4005 | AddParam_Var(params[0]); |
| 4006 | AString temp; | 4006 | AString temp; |
| 4007 | ReadString2(temp, params[1]); | 4007 | ReadString2(temp, params[1]); |
| 4008 | if (temp != "$TEMP") | 4008 | if (!temp.IsEqualTo("$TEMP")) |
| 4009 | SpaceQuStr(temp); | 4009 | SpaceQuStr(temp); |
| 4010 | break; | 4010 | break; |
| 4011 | } | 4011 | } |
| @@ -4410,7 +4410,7 @@ HRESULT CInArchive::ReadEntries(const CBlockHeader &bh) | |||
| 4410 | } | 4410 | } |
| 4411 | else | 4411 | else |
| 4412 | { | 4412 | { |
| 4413 | if (func == "DllUnregisterServer") | 4413 | if (func.IsEqualTo("DllUnregisterServer")) |
| 4414 | { | 4414 | { |
| 4415 | s += "UnRegDLL"; | 4415 | s += "UnRegDLL"; |
| 4416 | printFunc = false; | 4416 | printFunc = false; |
| @@ -4418,7 +4418,7 @@ HRESULT CInArchive::ReadEntries(const CBlockHeader &bh) | |||
| 4418 | else | 4418 | else |
| 4419 | { | 4419 | { |
| 4420 | s += "RegDLL"; | 4420 | s += "RegDLL"; |
| 4421 | if (func == "DllRegisterServer") | 4421 | if (func.IsEqualTo("DllRegisterServer")) |
| 4422 | printFunc = false; | 4422 | printFunc = false; |
| 4423 | } | 4423 | } |
| 4424 | AddParam(params[0]); | 4424 | AddParam(params[0]); |
| @@ -4886,7 +4886,7 @@ HRESULT CInArchive::ReadEntries(const CBlockHeader &bh) | |||
| 4886 | AddParam_Var(params[1]); | 4886 | AddParam_Var(params[1]); |
| 4887 | AddParam(params[2]); | 4887 | AddParam(params[2]); |
| 4888 | AddParam(params[4]); | 4888 | AddParam(params[4]); |
| 4889 | // if (params[2] == "0") AddCommentAndString("GetWinVer"); | 4889 | // if (params[2].IsEqualTo("0")) AddCommentAndString("GetWinVer"); |
| 4890 | } | 4890 | } |
| 4891 | else | 4891 | else |
| 4892 | s += "GetOsInfo"; | 4892 | s += "GetOsInfo"; |
diff --git a/CPP/7zip/Archive/NtfsHandler.cpp b/CPP/7zip/Archive/NtfsHandler.cpp index d55521d..05c177f 100644 --- a/CPP/7zip/Archive/NtfsHandler.cpp +++ b/CPP/7zip/Archive/NtfsHandler.cpp | |||
| @@ -1907,7 +1907,7 @@ HRESULT CDatabase::Open() | |||
| 1907 | for (i = 0; i < SecurityAttrs.Size(); i++) | 1907 | for (i = 0; i < SecurityAttrs.Size(); i++) |
| 1908 | { | 1908 | { |
| 1909 | const CAttr &attr = SecurityAttrs[i]; | 1909 | const CAttr &attr = SecurityAttrs[i]; |
| 1910 | if (attr.Name == L"$SII") | 1910 | if (attr.Name.IsEqualTo("$SII")) |
| 1911 | { | 1911 | { |
| 1912 | if (attr.Type == ATTR_TYPE_INDEX_ROOT) | 1912 | if (attr.Type == ATTR_TYPE_INDEX_ROOT) |
| 1913 | { | 1913 | { |
diff --git a/CPP/7zip/Archive/PeHandler.cpp b/CPP/7zip/Archive/PeHandler.cpp index 8a0ff05..79f89ef 100644 --- a/CPP/7zip/Archive/PeHandler.cpp +++ b/CPP/7zip/Archive/PeHandler.cpp | |||
| @@ -2638,7 +2638,7 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) | |||
| 2638 | { | 2638 | { |
| 2639 | const CSection § = _sections[i]; | 2639 | const CSection § = _sections[i]; |
| 2640 | if (IsOpt()) | 2640 | if (IsOpt()) |
| 2641 | if (_parseResources && sect.Name == ".rsrc") | 2641 | if (_parseResources && sect.Name.IsEqualTo(".rsrc")) |
| 2642 | { | 2642 | { |
| 2643 | // 20.01: we try to parse only first copy of .rsrc section. | 2643 | // 20.01: we try to parse only first copy of .rsrc section. |
| 2644 | _parseResources = false; | 2644 | _parseResources = false; |
| @@ -2727,7 +2727,7 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) | |||
| 2727 | for (i = 0; i < _mixItems.Size(); i++) | 2727 | for (i = 0; i < _mixItems.Size(); i++) |
| 2728 | { | 2728 | { |
| 2729 | const CMixItem &mixItem = _mixItems[i]; | 2729 | const CMixItem &mixItem = _mixItems[i]; |
| 2730 | if (mixItem.StringIndex < 0 && mixItem.ResourceIndex < 0 && _sections[mixItem.SectionIndex].Name == "_winzip_") | 2730 | if (mixItem.StringIndex < 0 && mixItem.ResourceIndex < 0 && _sections[mixItem.SectionIndex].Name.IsEqualTo("_winzip_")) |
| 2731 | { | 2731 | { |
| 2732 | _mainSubfile = (Int32)(int)i; | 2732 | _mainSubfile = (Int32)(int)i; |
| 2733 | break; | 2733 | break; |
diff --git a/CPP/7zip/Archive/Rar/Rar5Handler.cpp b/CPP/7zip/Archive/Rar/Rar5Handler.cpp index 7d75aae..a639d8b 100644 --- a/CPP/7zip/Archive/Rar/Rar5Handler.cpp +++ b/CPP/7zip/Archive/Rar/Rar5Handler.cpp | |||
| @@ -393,6 +393,7 @@ void CItem::Link_to_Prop(unsigned linkType, NWindows::NCOM::CPropVariant &prop) | |||
| 393 | if (!FindExtra_Link(link)) | 393 | if (!FindExtra_Link(link)) |
| 394 | return; | 394 | return; |
| 395 | 395 | ||
| 396 | bool isWindows = (HostOS == kHost_Windows); | ||
| 396 | if (link.Type != linkType) | 397 | if (link.Type != linkType) |
| 397 | { | 398 | { |
| 398 | if (linkType != NLinkType::kUnixSymLink) | 399 | if (linkType != NLinkType::kUnixSymLink) |
| @@ -400,8 +401,11 @@ void CItem::Link_to_Prop(unsigned linkType, NWindows::NCOM::CPropVariant &prop) | |||
| 400 | switch ((unsigned)link.Type) | 401 | switch ((unsigned)link.Type) |
| 401 | { | 402 | { |
| 402 | case NLinkType::kUnixSymLink: | 403 | case NLinkType::kUnixSymLink: |
| 404 | isWindows = false; | ||
| 405 | break; | ||
| 403 | case NLinkType::kWinSymLink: | 406 | case NLinkType::kWinSymLink: |
| 404 | case NLinkType::kWinJunction: | 407 | case NLinkType::kWinJunction: |
| 408 | isWindows = true; | ||
| 405 | break; | 409 | break; |
| 406 | default: return; | 410 | default: return; |
| 407 | } | 411 | } |
| @@ -409,10 +413,15 @@ void CItem::Link_to_Prop(unsigned linkType, NWindows::NCOM::CPropVariant &prop) | |||
| 409 | 413 | ||
| 410 | AString s; | 414 | AString s; |
| 411 | s.SetFrom_CalcLen((const char *)(Extra + link.NameOffset), link.NameLen); | 415 | s.SetFrom_CalcLen((const char *)(Extra + link.NameOffset), link.NameLen); |
| 412 | |||
| 413 | UString unicode; | 416 | UString unicode; |
| 414 | ConvertUTF8ToUnicode(s, unicode); | 417 | ConvertUTF8ToUnicode(s, unicode); |
| 415 | prop = NItemName::GetOsPath(unicode); | 418 | // rar5.0 used '\\' separator for windows symlinks and \??\ prefix for abs paths. |
| 419 | // rar5.1+ uses '/' separator for windows symlinks and /??/ prefix for abs paths. | ||
| 420 | // v25.00: we convert Windows slashes to Linux slashes: | ||
| 421 | if (isWindows) | ||
| 422 | unicode.Replace(L'\\', L'/'); | ||
| 423 | prop = unicode; | ||
| 424 | // prop = NItemName::GetOsPath(unicode); | ||
| 416 | } | 425 | } |
| 417 | 426 | ||
| 418 | bool CItem::GetAltStreamName(AString &name) const | 427 | bool CItem::GetAltStreamName(AString &name) const |
diff --git a/CPP/7zip/Archive/Rar/Rar5Handler.h b/CPP/7zip/Archive/Rar/Rar5Handler.h index 8f6581a..913ba85 100644 --- a/CPP/7zip/Archive/Rar/Rar5Handler.h +++ b/CPP/7zip/Archive/Rar/Rar5Handler.h | |||
| @@ -286,10 +286,10 @@ struct CItem | |||
| 286 | 286 | ||
| 287 | bool IsService() const { return RecordType == NHeaderType::kService; } | 287 | bool IsService() const { return RecordType == NHeaderType::kService; } |
| 288 | 288 | ||
| 289 | bool Is_STM() const { return IsService() && Name == "STM"; } | 289 | bool Is_STM() const { return IsService() && Name.IsEqualTo("STM"); } |
| 290 | bool Is_CMT() const { return IsService() && Name == "CMT"; } | 290 | bool Is_CMT() const { return IsService() && Name.IsEqualTo("CMT"); } |
| 291 | bool Is_ACL() const { return IsService() && Name == "ACL"; } | 291 | bool Is_ACL() const { return IsService() && Name.IsEqualTo("ACL"); } |
| 292 | // bool Is_QO() const { return IsService() && Name == "QO"; } | 292 | // bool Is_QO() const { return IsService() && Name.IsEqualTo("QO"); } |
| 293 | 293 | ||
| 294 | int FindExtra(unsigned extraID, unsigned &recordDataSize) const; | 294 | int FindExtra(unsigned extraID, unsigned &recordDataSize) const; |
| 295 | void PrintInfo(AString &s) const; | 295 | void PrintInfo(AString &s) const; |
diff --git a/CPP/7zip/Archive/Rar/RarHandler.cpp b/CPP/7zip/Archive/Rar/RarHandler.cpp index 9157acc..dfbad33 100644 --- a/CPP/7zip/Archive/Rar/RarHandler.cpp +++ b/CPP/7zip/Archive/Rar/RarHandler.cpp | |||
| @@ -435,13 +435,13 @@ bool CInArchive::ReadHeaderReal(const Byte *p, unsigned size, CItem &item) | |||
| 435 | size -= sizeof(item.Salt); | 435 | size -= sizeof(item.Salt); |
| 436 | p += sizeof(item.Salt); | 436 | p += sizeof(item.Salt); |
| 437 | } | 437 | } |
| 438 | if (item.Name == "ACL" && size == 0) | 438 | if (item.Name.IsEqualTo("ACL") && size == 0) |
| 439 | { | 439 | { |
| 440 | item.IsAltStream = true; | 440 | item.IsAltStream = true; |
| 441 | item.Name.Empty(); | 441 | item.Name.Empty(); |
| 442 | item.UnicodeName.SetFromAscii(".ACL"); | 442 | item.UnicodeName.SetFromAscii(".ACL"); |
| 443 | } | 443 | } |
| 444 | else if (item.Name == "STM" && size != 0 && (size & 1) == 0) | 444 | else if (item.Name.IsEqualTo("STM") && size != 0 && (size & 1) == 0) |
| 445 | { | 445 | { |
| 446 | item.IsAltStream = true; | 446 | item.IsAltStream = true; |
| 447 | item.Name.Empty(); | 447 | item.Name.Empty(); |
diff --git a/CPP/7zip/Archive/RpmHandler.cpp b/CPP/7zip/Archive/RpmHandler.cpp index da2b6ee..4f8aaaa 100644 --- a/CPP/7zip/Archive/RpmHandler.cpp +++ b/CPP/7zip/Archive/RpmHandler.cpp | |||
| @@ -330,11 +330,11 @@ void CHandler::AddSubFileExtension(AString &res) const | |||
| 330 | if (!_compressor.IsEmpty()) | 330 | if (!_compressor.IsEmpty()) |
| 331 | { | 331 | { |
| 332 | s = _compressor; | 332 | s = _compressor; |
| 333 | if (_compressor == "bzip2") | 333 | if (_compressor.IsEqualTo("bzip2")) |
| 334 | s = "bz2"; | 334 | s = "bz2"; |
| 335 | else if (_compressor == "gzip") | 335 | else if (_compressor.IsEqualTo("gzip")) |
| 336 | s = "gz"; | 336 | s = "gz"; |
| 337 | else if (_compressor == "zstd") | 337 | else if (_compressor.IsEqualTo("zstd")) |
| 338 | s = "zst"; | 338 | s = "zst"; |
| 339 | } | 339 | } |
| 340 | else | 340 | else |
diff --git a/CPP/7zip/Archive/VmdkHandler.cpp b/CPP/7zip/Archive/VmdkHandler.cpp index 9c293a3..221af21 100644 --- a/CPP/7zip/Archive/VmdkHandler.cpp +++ b/CPP/7zip/Archive/VmdkHandler.cpp | |||
| @@ -202,9 +202,12 @@ struct CExtentInfo | |||
| 202 | // PartitionUUID | 202 | // PartitionUUID |
| 203 | // DeviceIdentifier | 203 | // DeviceIdentifier |
| 204 | 204 | ||
| 205 | bool IsType_ZERO() const { return Type == "ZERO"; } | 205 | bool IsType_ZERO() const { return Type.IsEqualTo("ZERO"); } |
| 206 | // bool IsType_FLAT() const { return Type == "FLAT"; } | 206 | // bool IsType_FLAT() const { return Type.IsEqualTo("FLAT"); } |
| 207 | bool IsType_Flat() const { return Type == "FLAT" || Type == "VMFS" || Type == "VMFSRAW"; } | 207 | bool IsType_Flat() const |
| 208 | { return Type.IsEqualTo("FLAT") | ||
| 209 | || Type.IsEqualTo("VMFS") | ||
| 210 | || Type.IsEqualTo("VMFSRAW"); } | ||
| 208 | 211 | ||
| 209 | bool Parse(const char *s); | 212 | bool Parse(const char *s); |
| 210 | }; | 213 | }; |
diff --git a/CPP/7zip/Archive/Wim/WimIn.cpp b/CPP/7zip/Archive/Wim/WimIn.cpp index 614755a..a748e99 100644 --- a/CPP/7zip/Archive/Wim/WimIn.cpp +++ b/CPP/7zip/Archive/Wim/WimIn.cpp | |||
| @@ -1814,7 +1814,7 @@ bool CWimXml::Parse() | |||
| 1814 | 1814 | ||
| 1815 | if (!Xml.Parse(utf)) | 1815 | if (!Xml.Parse(utf)) |
| 1816 | return false; | 1816 | return false; |
| 1817 | if (Xml.Root.Name != "WIM") | 1817 | if (!Xml.Root.Name.IsEqualTo("WIM")) |
| 1818 | return false; | 1818 | return false; |
| 1819 | 1819 | ||
| 1820 | FOR_VECTOR (i, Xml.Root.SubItems) | 1820 | FOR_VECTOR (i, Xml.Root.SubItems) |
diff --git a/CPP/7zip/Archive/XarHandler.cpp b/CPP/7zip/Archive/XarHandler.cpp index 6ef8941..cba546e 100644 --- a/CPP/7zip/Archive/XarHandler.cpp +++ b/CPP/7zip/Archive/XarHandler.cpp | |||
| @@ -266,7 +266,7 @@ struct CFile | |||
| 266 | 266 | ||
| 267 | bool IsCopyMethod() const | 267 | bool IsCopyMethod() const |
| 268 | { | 268 | { |
| 269 | return Method.IsEmpty() || Method == "octet-stream"; | 269 | return Method.IsEmpty() || Method.IsEqualTo("octet-stream"); |
| 270 | } | 270 | } |
| 271 | 271 | ||
| 272 | void UpdateTotalPackSize(UInt64 &totalSize) const | 272 | void UpdateTotalPackSize(UInt64 &totalSize) const |
| @@ -416,7 +416,7 @@ static bool AddItem(const CXmlItem &item, CObjectVector<CFile> &files, int paren | |||
| 416 | return true; | 416 | return true; |
| 417 | if (level >= 1024) | 417 | if (level >= 1024) |
| 418 | return false; | 418 | return false; |
| 419 | if (item.Name == "file") | 419 | if (item.Name.IsEqualTo("file")) |
| 420 | { | 420 | { |
| 421 | CFile file(parent); | 421 | CFile file(parent); |
| 422 | parent = (int)files.Size(); | 422 | parent = (int)files.Size(); |
| @@ -435,19 +435,19 @@ static bool AddItem(const CXmlItem &item, CObjectVector<CFile> &files, int paren | |||
| 435 | { | 435 | { |
| 436 | file.Type = typeItem->GetSubString(); | 436 | file.Type = typeItem->GetSubString(); |
| 437 | // file.LinkFrom = typeItem->GetPropVal("link"); | 437 | // file.LinkFrom = typeItem->GetPropVal("link"); |
| 438 | if (file.Type == "directory") | 438 | if (file.Type.IsEqualTo("directory")) |
| 439 | file.IsDir = true; | 439 | file.IsDir = true; |
| 440 | else | 440 | else |
| 441 | { | 441 | { |
| 442 | // file.IsDir = false; | 442 | // file.IsDir = false; |
| 443 | /* | 443 | /* |
| 444 | else if (file.Type == "file") | 444 | else if (file.Type.IsEqualTo("file")) |
| 445 | {} | 445 | {} |
| 446 | else if (file.Type == "hardlink") | 446 | else if (file.Type.IsEqualTo("hardlink")) |
| 447 | {} | 447 | {} |
| 448 | else | 448 | else |
| 449 | */ | 449 | */ |
| 450 | if (file.Type == "symlink") | 450 | if (file.Type.IsEqualTo("symlink")) |
| 451 | file.Is_SymLink = true; | 451 | file.Is_SymLink = true; |
| 452 | // file.IsDir = false; | 452 | // file.IsDir = false; |
| 453 | } | 453 | } |
| @@ -489,7 +489,7 @@ static bool AddItem(const CXmlItem &item, CObjectVector<CFile> &files, int paren | |||
| 489 | if (s.IsPrefixedBy(xx)) | 489 | if (s.IsPrefixedBy(xx)) |
| 490 | { | 490 | { |
| 491 | s.DeleteFrontal(xx.Len()); | 491 | s.DeleteFrontal(xx.Len()); |
| 492 | if (s == "gzip") | 492 | if (s.IsEqualTo("gzip")) |
| 493 | s = METHOD_NAME_ZLIB; | 493 | s = METHOD_NAME_ZLIB; |
| 494 | } | 494 | } |
| 495 | } | 495 | } |
| @@ -692,12 +692,13 @@ HRESULT CHandler::Open2(IInStream *stream) | |||
| 692 | file.UpdateTotalPackSize(totalPackSize); | 692 | file.UpdateTotalPackSize(totalPackSize); |
| 693 | if (file.Parent == -1) | 693 | if (file.Parent == -1) |
| 694 | { | 694 | { |
| 695 | if (file.Name == "Payload" || file.Name == "Content") | 695 | if (file.Name.IsEqualTo("Payload") || |
| 696 | file.Name.IsEqualTo("Content")) | ||
| 696 | { | 697 | { |
| 697 | _mainSubfile = (Int32)(int)i; | 698 | _mainSubfile = (Int32)(int)i; |
| 698 | numMainFiles++; | 699 | numMainFiles++; |
| 699 | } | 700 | } |
| 700 | else if (file.Name == "PackageInfo") | 701 | else if (file.Name.IsEqualTo("PackageInfo")) |
| 701 | _is_pkg = true; | 702 | _is_pkg = true; |
| 702 | } | 703 | } |
| 703 | } | 704 | } |
| @@ -1210,9 +1211,9 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, | |||
| 1210 | else | 1211 | else |
| 1211 | opRes = NExtract::NOperationResult::kUnsupportedMethod; | 1212 | opRes = NExtract::NOperationResult::kUnsupportedMethod; |
| 1212 | } | 1213 | } |
| 1213 | else if (item.Method == METHOD_NAME_ZLIB) | 1214 | else if (item.Method.IsEqualTo(METHOD_NAME_ZLIB)) |
| 1214 | coder = zlibCoder; | 1215 | coder = zlibCoder; |
| 1215 | else if (item.Method == "bzip2") | 1216 | else if (item.Method.IsEqualTo("bzip2")) |
| 1216 | coder = bzip2Coder; | 1217 | coder = bzip2Coder; |
| 1217 | else | 1218 | else |
| 1218 | opRes = NExtract::NOperationResult::kUnsupportedMethod; | 1219 | opRes = NExtract::NOperationResult::kUnsupportedMethod; |
diff --git a/CPP/7zip/Archive/XzHandler.cpp b/CPP/7zip/Archive/XzHandler.cpp index 907376c..5aaa405 100644 --- a/CPP/7zip/Archive/XzHandler.cpp +++ b/CPP/7zip/Archive/XzHandler.cpp | |||
| @@ -446,7 +446,7 @@ void COpenCallbackWrap::Init(IArchiveOpenCallback *callback) | |||
| 446 | struct CXzsCPP | 446 | struct CXzsCPP |
| 447 | { | 447 | { |
| 448 | CXzs p; | 448 | CXzs p; |
| 449 | CXzsCPP() { Xzs_Construct(&p); } | 449 | CXzsCPP() { Xzs_CONSTRUCT(&p) } |
| 450 | ~CXzsCPP() { Xzs_Free(&p, &g_Alloc); } | 450 | ~CXzsCPP() { Xzs_Free(&p, &g_Alloc); } |
| 451 | }; | 451 | }; |
| 452 | 452 | ||
| @@ -536,6 +536,9 @@ HRESULT CHandler::Open2(IInStream *inStream, /* UInt32 flags, */ IArchiveOpenCal | |||
| 536 | 536 | ||
| 537 | if (res2 == SZ_ERROR_ARCHIVE) | 537 | if (res2 == SZ_ERROR_ARCHIVE) |
| 538 | return S_FALSE; | 538 | return S_FALSE; |
| 539 | // what codes are possible here ? | ||
| 540 | // ?? res2 == SZ_ERROR_MEM : is possible here | ||
| 541 | // ?? res2 == SZ_ERROR_UNSUPPORTED : is possible here | ||
| 539 | } | 542 | } |
| 540 | else if (!isIndex) | 543 | else if (!isIndex) |
| 541 | { | 544 | { |
| @@ -1159,6 +1162,13 @@ Z7_COM7F_IMF(CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt | |||
| 1159 | */ | 1162 | */ |
| 1160 | 1163 | ||
| 1161 | #ifndef Z7_ST | 1164 | #ifndef Z7_ST |
| 1165 | |||
| 1166 | #ifdef _WIN32 | ||
| 1167 | // we don't use chunk multithreading inside lzma2 stream. | ||
| 1168 | // so we don't set xzProps.lzma2Props.numThreadGroups. | ||
| 1169 | if (_numThreadGroups > 1) | ||
| 1170 | xzProps.numThreadGroups = _numThreadGroups; | ||
| 1171 | #endif | ||
| 1162 | 1172 | ||
| 1163 | UInt32 numThreads = _numThreads; | 1173 | UInt32 numThreads = _numThreads; |
| 1164 | 1174 | ||
| @@ -1183,6 +1193,8 @@ Z7_COM7F_IMF(CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt | |||
| 1183 | CMultiMethodProps::SetMethodThreadsTo_IfNotFinded(oneMethodInfo, numThreads); | 1193 | CMultiMethodProps::SetMethodThreadsTo_IfNotFinded(oneMethodInfo, numThreads); |
| 1184 | } | 1194 | } |
| 1185 | 1195 | ||
| 1196 | // printf("\n====== GetProcessGroupAffinity : \n"); | ||
| 1197 | |||
| 1186 | UInt64 cs = _numSolidBytes; | 1198 | UInt64 cs = _numSolidBytes; |
| 1187 | if (cs != XZ_PROPS_BLOCK_SIZE_AUTO) | 1199 | if (cs != XZ_PROPS_BLOCK_SIZE_AUTO) |
| 1188 | oneMethodInfo.AddProp_BlockSize2(cs); | 1200 | oneMethodInfo.AddProp_BlockSize2(cs); |
diff --git a/CPP/7zip/Archive/Zip/ZipUpdate.cpp b/CPP/7zip/Archive/Zip/ZipUpdate.cpp index bc047b7..b2684dc 100644 --- a/CPP/7zip/Archive/Zip/ZipUpdate.cpp +++ b/CPP/7zip/Archive/Zip/ZipUpdate.cpp | |||
| @@ -250,13 +250,26 @@ struct CThreadInfo | |||
| 250 | 250 | ||
| 251 | HRESULT CreateEvents() | 251 | HRESULT CreateEvents() |
| 252 | { | 252 | { |
| 253 | WRes wres = CompressEvent.CreateIfNotCreated_Reset(); | 253 | const WRes wres = CompressEvent.CreateIfNotCreated_Reset(); |
| 254 | return HRESULT_FROM_WIN32(wres); | 254 | return HRESULT_FROM_WIN32(wres); |
| 255 | } | 255 | } |
| 256 | 256 | ||
| 257 | HRESULT CreateThread() | 257 | // (group < 0) means no_group. |
| 258 | HRESULT CreateThread_with_group( | ||
| 259 | #ifdef _WIN32 | ||
| 260 | int group | ||
| 261 | #endif | ||
| 262 | ) | ||
| 258 | { | 263 | { |
| 259 | WRes wres = Thread.Create(CoderThread, this); | 264 | // tested in win10: If thread is created by another thread, |
| 265 | // child thread probably uses same group as parent thread. | ||
| 266 | // So we don't need to send (group) to encoder in created thread. | ||
| 267 | const WRes wres = | ||
| 268 | #ifdef _WIN32 | ||
| 269 | group >= 0 ? | ||
| 270 | Thread.Create_With_Group(CoderThread, this, (unsigned)group) : | ||
| 271 | #endif | ||
| 272 | Thread.Create(CoderThread, this); | ||
| 260 | return HRESULT_FROM_WIN32(wres); | 273 | return HRESULT_FROM_WIN32(wres); |
| 261 | } | 274 | } |
| 262 | 275 | ||
| @@ -450,8 +463,12 @@ static HRESULT UpdateItemOldData( | |||
| 450 | if (ui.NewProps) | 463 | if (ui.NewProps) |
| 451 | { | 464 | { |
| 452 | if (item.HasDescriptor()) | 465 | if (item.HasDescriptor()) |
| 453 | return E_NOTIMPL; | 466 | { |
| 454 | 467 | // we know compressed / uncompressed sizes and crc. | |
| 468 | // so we remove descriptor here | ||
| 469 | item.Flags = (UInt16)(item.Flags & ~NFileHeader::NFlags::kDescriptorUsedMask); | ||
| 470 | // return E_NOTIMPL; | ||
| 471 | } | ||
| 455 | // we keep ExternalAttrib and some another properties from old archive | 472 | // we keep ExternalAttrib and some another properties from old archive |
| 456 | // item.ExternalAttrib = ui.Attrib; | 473 | // item.ExternalAttrib = ui.Attrib; |
| 457 | // if we don't change Comment, we keep Comment from OldProperties | 474 | // if we don't change Comment, we keep Comment from OldProperties |
| @@ -1000,6 +1017,9 @@ static HRESULT Update2( | |||
| 1000 | #ifndef Z7_ST | 1017 | #ifndef Z7_ST |
| 1001 | 1018 | ||
| 1002 | UInt32 numThreads = options._numThreads; | 1019 | UInt32 numThreads = options._numThreads; |
| 1020 | #ifdef _WIN32 | ||
| 1021 | const UInt32 numThreadGroups = options._numThreadGroups; | ||
| 1022 | #endif | ||
| 1003 | 1023 | ||
| 1004 | UInt32 numZipThreads_limit = numThreads; | 1024 | UInt32 numZipThreads_limit = numThreads; |
| 1005 | if (numZipThreads_limit > numFilesToCompress) | 1025 | if (numZipThreads_limit > numFilesToCompress) |
| @@ -1014,12 +1034,10 @@ static HRESULT Update2( | |||
| 1014 | } | 1034 | } |
| 1015 | 1035 | ||
| 1016 | { | 1036 | { |
| 1037 | // we reduce number of threads for 32-bit to reduce memory usege to 256 MB | ||
| 1017 | const UInt32 kNumMaxThreads = | 1038 | const UInt32 kNumMaxThreads = |
| 1018 | #ifdef _WIN32 | 1039 | // _WIN32 (64-bit) supports only 64 threads in one group. |
| 1019 | 64; // _WIN32 supports only 64 threads in one group. So no need for more threads here | 1040 | 8 << (sizeof(size_t) / 2); // 32 threads for 32-bit : 128 threads for 64-bit |
| 1020 | #else | ||
| 1021 | 128; | ||
| 1022 | #endif | ||
| 1023 | if (numThreads > kNumMaxThreads) | 1041 | if (numThreads > kNumMaxThreads) |
| 1024 | numThreads = kNumMaxThreads; | 1042 | numThreads = kNumMaxThreads; |
| 1025 | } | 1043 | } |
| @@ -1264,7 +1282,14 @@ static HRESULT Update2( | |||
| 1264 | threadInfo.Progress = threadInfo.ProgressSpec; | 1282 | threadInfo.Progress = threadInfo.ProgressSpec; |
| 1265 | threadInfo.ProgressSpec->Init(&mtCompressProgressMixer, i); | 1283 | threadInfo.ProgressSpec->Init(&mtCompressProgressMixer, i); |
| 1266 | threadInfo.MtSem = &mtSem; | 1284 | threadInfo.MtSem = &mtSem; |
| 1267 | RINOK(threadInfo.CreateThread()) | 1285 | const HRESULT hres = |
| 1286 | threadInfo.CreateThread_with_group( | ||
| 1287 | #ifdef _WIN32 | ||
| 1288 | (numThreadGroups > 1 && numThreads > 1) ? | ||
| 1289 | (int)(i % numThreadGroups) : -1 | ||
| 1290 | #endif | ||
| 1291 | ); | ||
| 1292 | RINOK(hres) | ||
| 1268 | } | 1293 | } |
| 1269 | } | 1294 | } |
| 1270 | 1295 | ||
diff --git a/CPP/7zip/Bundles/Alone/makefile b/CPP/7zip/Bundles/Alone/makefile index 7547590..9f81f9e 100644 --- a/CPP/7zip/Bundles/Alone/makefile +++ b/CPP/7zip/Bundles/Alone/makefile | |||
| @@ -5,6 +5,7 @@ CFLAGS = $(CFLAGS) -DZ7_ZIP_LZFSE_DISABLE | |||
| 5 | # CONSOLE_VARIANT_FLAGS=-DZ7_PROG_VARIANT_A | 5 | # CONSOLE_VARIANT_FLAGS=-DZ7_PROG_VARIANT_A |
| 6 | # ZIP_FLAGS=-DZ7_ZIP_LZFSE_DISABLE | 6 | # ZIP_FLAGS=-DZ7_ZIP_LZFSE_DISABLE |
| 7 | 7 | ||
| 8 | # USE_C_SORT=1 | ||
| 8 | # USE_C_AES = 1 | 9 | # USE_C_AES = 1 |
| 9 | # USE_C_SHA = 1 | 10 | # USE_C_SHA = 1 |
| 10 | # USE_C_LZFINDOPT = 1 | 11 | # USE_C_LZFINDOPT = 1 |
| @@ -221,7 +222,6 @@ C_OBJS = \ | |||
| 221 | $O\Ppmd8.obj \ | 222 | $O\Ppmd8.obj \ |
| 222 | $O\Ppmd8Dec.obj \ | 223 | $O\Ppmd8Dec.obj \ |
| 223 | $O\Ppmd8Enc.obj \ | 224 | $O\Ppmd8Enc.obj \ |
| 224 | $O\Sort.obj \ | ||
| 225 | $O\SwapBytes.obj \ | 225 | $O\SwapBytes.obj \ |
| 226 | $O\Threads.obj \ | 226 | $O\Threads.obj \ |
| 227 | $O\Xxh64.obj \ | 227 | $O\Xxh64.obj \ |
| @@ -240,5 +240,6 @@ C_OBJS = \ | |||
| 240 | !include "../../LzmaDec.mak" | 240 | !include "../../LzmaDec.mak" |
| 241 | !include "../../Sha1.mak" | 241 | !include "../../Sha1.mak" |
| 242 | !include "../../Sha256.mak" | 242 | !include "../../Sha256.mak" |
| 243 | !include "../../Sort.mak" | ||
| 243 | 244 | ||
| 244 | !include "../../7zip.mak" | 245 | !include "../../7zip.mak" |
diff --git a/CPP/7zip/Bundles/Alone7z/makefile b/CPP/7zip/Bundles/Alone7z/makefile index 89584e1..f0a813a 100644 --- a/CPP/7zip/Bundles/Alone7z/makefile +++ b/CPP/7zip/Bundles/Alone7z/makefile | |||
| @@ -148,7 +148,6 @@ C_OBJS = \ | |||
| 148 | $O\LzmaEnc.obj \ | 148 | $O\LzmaEnc.obj \ |
| 149 | $O\MtCoder.obj \ | 149 | $O\MtCoder.obj \ |
| 150 | $O\MtDec.obj \ | 150 | $O\MtDec.obj \ |
| 151 | $O\Sort.obj \ | ||
| 152 | $O\SwapBytes.obj \ | 151 | $O\SwapBytes.obj \ |
| 153 | $O\Threads.obj \ | 152 | $O\Threads.obj \ |
| 154 | $O\Xz.obj \ | 153 | $O\Xz.obj \ |
| @@ -164,5 +163,6 @@ C_OBJS = \ | |||
| 164 | !include "../../LzFindOpt.mak" | 163 | !include "../../LzFindOpt.mak" |
| 165 | !include "../../LzmaDec.mak" | 164 | !include "../../LzmaDec.mak" |
| 166 | !include "../../Sha256.mak" | 165 | !include "../../Sha256.mak" |
| 166 | !include "../../Sort.mak" | ||
| 167 | 167 | ||
| 168 | !include "../../7zip.mak" | 168 | !include "../../7zip.mak" |
diff --git a/CPP/7zip/Bundles/Format7z/makefile b/CPP/7zip/Bundles/Format7z/makefile index fe6f94d..3d4754c 100644 --- a/CPP/7zip/Bundles/Format7z/makefile +++ b/CPP/7zip/Bundles/Format7z/makefile | |||
| @@ -135,7 +135,6 @@ C_OBJS = \ | |||
| 135 | $O\Ppmd7.obj \ | 135 | $O\Ppmd7.obj \ |
| 136 | $O\Ppmd7Dec.obj \ | 136 | $O\Ppmd7Dec.obj \ |
| 137 | $O\Ppmd7Enc.obj \ | 137 | $O\Ppmd7Enc.obj \ |
| 138 | $O\Sort.obj \ | ||
| 139 | $O\SwapBytes.obj \ | 138 | $O\SwapBytes.obj \ |
| 140 | $O\Threads.obj \ | 139 | $O\Threads.obj \ |
| 141 | 140 | ||
| @@ -144,5 +143,6 @@ C_OBJS = \ | |||
| 144 | !include "../../LzFindOpt.mak" | 143 | !include "../../LzFindOpt.mak" |
| 145 | !include "../../LzmaDec.mak" | 144 | !include "../../LzmaDec.mak" |
| 146 | !include "../../Sha256.mak" | 145 | !include "../../Sha256.mak" |
| 146 | !include "../../Sort.mak" | ||
| 147 | 147 | ||
| 148 | !include "../../7zip.mak" | 148 | !include "../../7zip.mak" |
diff --git a/CPP/7zip/Bundles/Format7zF/Arc.mak b/CPP/7zip/Bundles/Format7zF/Arc.mak index 7166ab3..b1c6fe2 100644 --- a/CPP/7zip/Bundles/Format7zF/Arc.mak +++ b/CPP/7zip/Bundles/Format7zF/Arc.mak | |||
| @@ -291,7 +291,6 @@ C_OBJS = \ | |||
| 291 | $O\Sha3.obj \ | 291 | $O\Sha3.obj \ |
| 292 | $O\Sha512.obj \ | 292 | $O\Sha512.obj \ |
| 293 | $O\Sha512Opt.obj \ | 293 | $O\Sha512Opt.obj \ |
| 294 | $O\Sort.obj \ | ||
| 295 | $O\SwapBytes.obj \ | 294 | $O\SwapBytes.obj \ |
| 296 | $O\Threads.obj \ | 295 | $O\Threads.obj \ |
| 297 | $O\Xxh64.obj \ | 296 | $O\Xxh64.obj \ |
| @@ -308,3 +307,4 @@ C_OBJS = \ | |||
| 308 | !include "../../LzmaDec.mak" | 307 | !include "../../LzmaDec.mak" |
| 309 | !include "../../Sha1.mak" | 308 | !include "../../Sha1.mak" |
| 310 | !include "../../Sha256.mak" | 309 | !include "../../Sha256.mak" |
| 310 | !include "../../Sort.mak" | ||
diff --git a/CPP/7zip/Bundles/SFXSetup/SfxSetup.cpp b/CPP/7zip/Bundles/SFXSetup/SfxSetup.cpp index eb28f5d..0c09807 100644 --- a/CPP/7zip/Bundles/SFXSetup/SfxSetup.cpp +++ b/CPP/7zip/Bundles/SFXSetup/SfxSetup.cpp | |||
| @@ -229,7 +229,7 @@ int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE /* hPrevInstance */, | |||
| 229 | } | 229 | } |
| 230 | 230 | ||
| 231 | const FString tempDirPath = tempDir.GetPath(); | 231 | const FString tempDirPath = tempDir.GetPath(); |
| 232 | // tempDirPath = L"M:\\1\\"; // to test low disk space | 232 | // tempDirPath = "M:\\1\\"; // to test low disk space |
| 233 | { | 233 | { |
| 234 | bool isCorrupt = false; | 234 | bool isCorrupt = false; |
| 235 | UString errorMessage; | 235 | UString errorMessage; |
| @@ -308,7 +308,7 @@ int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE /* hPrevInstance */, | |||
| 308 | { | 308 | { |
| 309 | if (appLaunched.IsEmpty()) | 309 | if (appLaunched.IsEmpty()) |
| 310 | { | 310 | { |
| 311 | appLaunched = L"setup.exe"; | 311 | appLaunched = "setup.exe"; |
| 312 | if (!NFind::DoesFileExist_FollowLink(us2fs(appLaunched))) | 312 | if (!NFind::DoesFileExist_FollowLink(us2fs(appLaunched))) |
| 313 | { | 313 | { |
| 314 | if (!assumeYes) | 314 | if (!assumeYes) |
diff --git a/CPP/7zip/Common/InBuffer.h b/CPP/7zip/Common/InBuffer.h index a8ccb40..13ec088 100644 --- a/CPP/7zip/Common/InBuffer.h +++ b/CPP/7zip/Common/InBuffer.h | |||
| @@ -97,6 +97,16 @@ public: | |||
| 97 | 97 | ||
| 98 | size_t ReadBytesPart(Byte *buf, size_t size); | 98 | size_t ReadBytesPart(Byte *buf, size_t size); |
| 99 | size_t ReadBytes(Byte *buf, size_t size); | 99 | size_t ReadBytes(Byte *buf, size_t size); |
| 100 | const Byte *Lookahead(size_t &rem) | ||
| 101 | { | ||
| 102 | rem = (size_t)(_bufLim - _buf); | ||
| 103 | if (!rem) | ||
| 104 | { | ||
| 105 | ReadBlock(); | ||
| 106 | rem = (size_t)(_bufLim - _buf); | ||
| 107 | } | ||
| 108 | return _buf; | ||
| 109 | } | ||
| 100 | size_t Skip(size_t size); | 110 | size_t Skip(size_t size); |
| 101 | }; | 111 | }; |
| 102 | 112 | ||
diff --git a/CPP/7zip/Common/MethodProps.cpp b/CPP/7zip/Common/MethodProps.cpp index d87884c..a5d90cf 100644 --- a/CPP/7zip/Common/MethodProps.cpp +++ b/CPP/7zip/Common/MethodProps.cpp | |||
| @@ -324,15 +324,22 @@ void CCoderProps::AddProp(const CProp &prop) | |||
| 324 | 324 | ||
| 325 | HRESULT CProps::SetCoderProps(ICompressSetCoderProperties *scp, const UInt64 *dataSizeReduce) const | 325 | HRESULT CProps::SetCoderProps(ICompressSetCoderProperties *scp, const UInt64 *dataSizeReduce) const |
| 326 | { | 326 | { |
| 327 | return SetCoderProps_DSReduce_Aff(scp, dataSizeReduce, NULL); | 327 | return SetCoderProps_DSReduce_Aff(scp, dataSizeReduce, NULL, NULL, NULL); |
| 328 | } | 328 | } |
| 329 | 329 | ||
| 330 | HRESULT CProps::SetCoderProps_DSReduce_Aff( | 330 | HRESULT CProps::SetCoderProps_DSReduce_Aff( |
| 331 | ICompressSetCoderProperties *scp, | 331 | ICompressSetCoderProperties *scp, |
| 332 | const UInt64 *dataSizeReduce, | 332 | const UInt64 *dataSizeReduce, |
| 333 | const UInt64 *affinity) const | 333 | const UInt64 *affinity, |
| 334 | { | 334 | const UInt32 *affinityGroup, |
| 335 | CCoderProps coderProps(Props.Size() + (dataSizeReduce ? 1 : 0) + (affinity ? 1 : 0) ); | 335 | const UInt64 *affinityInGroup) const |
| 336 | { | ||
| 337 | CCoderProps coderProps(Props.Size() | ||
| 338 | + (dataSizeReduce ? 1 : 0) | ||
| 339 | + (affinity ? 1 : 0) | ||
| 340 | + (affinityGroup ? 1 : 0) | ||
| 341 | + (affinityInGroup ? 1 : 0) | ||
| 342 | ); | ||
| 336 | FOR_VECTOR (i, Props) | 343 | FOR_VECTOR (i, Props) |
| 337 | coderProps.AddProp(Props[i]); | 344 | coderProps.AddProp(Props[i]); |
| 338 | if (dataSizeReduce) | 345 | if (dataSizeReduce) |
| @@ -349,6 +356,20 @@ HRESULT CProps::SetCoderProps_DSReduce_Aff( | |||
| 349 | prop.Value = *affinity; | 356 | prop.Value = *affinity; |
| 350 | coderProps.AddProp(prop); | 357 | coderProps.AddProp(prop); |
| 351 | } | 358 | } |
| 359 | if (affinityGroup) | ||
| 360 | { | ||
| 361 | CProp prop; | ||
| 362 | prop.Id = NCoderPropID::kThreadGroup; | ||
| 363 | prop.Value = *affinityGroup; | ||
| 364 | coderProps.AddProp(prop); | ||
| 365 | } | ||
| 366 | if (affinityInGroup) | ||
| 367 | { | ||
| 368 | CProp prop; | ||
| 369 | prop.Id = NCoderPropID::kAffinityInGroup; | ||
| 370 | prop.Value = *affinityInGroup; | ||
| 371 | coderProps.AddProp(prop); | ||
| 372 | } | ||
| 352 | return coderProps.SetProps(scp); | 373 | return coderProps.SetProps(scp); |
| 353 | } | 374 | } |
| 354 | 375 | ||
| @@ -409,6 +430,11 @@ static const CNameToPropID g_NameToPropID[] = | |||
| 409 | { VT_UI4, "offset" }, | 430 | { VT_UI4, "offset" }, |
| 410 | { VT_UI4, "zhb" } | 431 | { VT_UI4, "zhb" } |
| 411 | /* | 432 | /* |
| 433 | , { VT_UI4, "tgn" }, // kNumThreadGroups | ||
| 434 | , { VT_UI4, "tgi" }, // kThreadGroup | ||
| 435 | , { VT_UI8, "tga" }, // kAffinityInGroup | ||
| 436 | */ | ||
| 437 | /* | ||
| 412 | , | 438 | , |
| 413 | // { VT_UI4, "zhc" }, | 439 | // { VT_UI4, "zhc" }, |
| 414 | // { VT_UI4, "zhd" }, | 440 | // { VT_UI4, "zhd" }, |
diff --git a/CPP/7zip/Common/MethodProps.h b/CPP/7zip/Common/MethodProps.h index a52f4bc..be108fa 100644 --- a/CPP/7zip/Common/MethodProps.h +++ b/CPP/7zip/Common/MethodProps.h | |||
| @@ -80,7 +80,11 @@ struct CProps | |||
| 80 | } | 80 | } |
| 81 | 81 | ||
| 82 | HRESULT SetCoderProps(ICompressSetCoderProperties *scp, const UInt64 *dataSizeReduce = NULL) const; | 82 | HRESULT SetCoderProps(ICompressSetCoderProperties *scp, const UInt64 *dataSizeReduce = NULL) const; |
| 83 | HRESULT SetCoderProps_DSReduce_Aff(ICompressSetCoderProperties *scp, const UInt64 *dataSizeReduce, const UInt64 *affinity) const; | 83 | HRESULT SetCoderProps_DSReduce_Aff(ICompressSetCoderProperties *scp, |
| 84 | const UInt64 *dataSizeReduce, | ||
| 85 | const UInt64 *affinity, | ||
| 86 | const UInt32 *affinityGroup, | ||
| 87 | const UInt64 *affinityInGroup) const; | ||
| 84 | }; | 88 | }; |
| 85 | 89 | ||
| 86 | class CMethodProps: public CProps | 90 | class CMethodProps: public CProps |
diff --git a/CPP/7zip/Common/OutBuffer.h b/CPP/7zip/Common/OutBuffer.h index 88f5787..af78c4f 100644 --- a/CPP/7zip/Common/OutBuffer.h +++ b/CPP/7zip/Common/OutBuffer.h | |||
| @@ -45,6 +45,7 @@ public: | |||
| 45 | HRESULT Flush() throw(); | 45 | HRESULT Flush() throw(); |
| 46 | void FlushWithCheck(); | 46 | void FlushWithCheck(); |
| 47 | 47 | ||
| 48 | Z7_FORCE_INLINE | ||
| 48 | void WriteByte(Byte b) | 49 | void WriteByte(Byte b) |
| 49 | { | 50 | { |
| 50 | UInt32 pos = _pos; | 51 | UInt32 pos = _pos; |
| @@ -54,10 +55,34 @@ public: | |||
| 54 | if (pos == _limitPos) | 55 | if (pos == _limitPos) |
| 55 | FlushWithCheck(); | 56 | FlushWithCheck(); |
| 56 | } | 57 | } |
| 58 | |||
| 57 | void WriteBytes(const void *data, size_t size) | 59 | void WriteBytes(const void *data, size_t size) |
| 58 | { | 60 | { |
| 59 | for (size_t i = 0; i < size; i++) | 61 | while (size) |
| 60 | WriteByte(((const Byte *)data)[i]); | 62 | { |
| 63 | UInt32 pos = _pos; | ||
| 64 | size_t cur = (size_t)(_limitPos - pos); | ||
| 65 | if (cur >= size) | ||
| 66 | cur = size; | ||
| 67 | size -= cur; | ||
| 68 | Byte *dest = _buf + pos; | ||
| 69 | pos += (UInt32)cur; | ||
| 70 | _pos = pos; | ||
| 71 | #if 0 | ||
| 72 | memcpy(dest, data, cur); | ||
| 73 | data = (const void *)((const Byte *)data + cur); | ||
| 74 | #else | ||
| 75 | const Byte * const lim = (const Byte *)data + cur; | ||
| 76 | do | ||
| 77 | { | ||
| 78 | *dest++ = *(const Byte *)data; | ||
| 79 | data = (const void *)((const Byte *)data + 1); | ||
| 80 | } | ||
| 81 | while (data != lim); | ||
| 82 | #endif | ||
| 83 | if (pos == _limitPos) | ||
| 84 | FlushWithCheck(); | ||
| 85 | } | ||
| 61 | } | 86 | } |
| 62 | 87 | ||
| 63 | Byte *GetOutBuffer(size_t &avail) | 88 | Byte *GetOutBuffer(size_t &avail) |
diff --git a/CPP/7zip/Compress/BZip2Const.h b/CPP/7zip/Compress/BZip2Const.h index 0dfcfe5..3380aaf 100644 --- a/CPP/7zip/Compress/BZip2Const.h +++ b/CPP/7zip/Compress/BZip2Const.h | |||
| @@ -46,7 +46,7 @@ const UInt32 kBlockSizeStep = 100000; | |||
| 46 | const UInt32 kBlockSizeMax = kBlockSizeMultMax * kBlockSizeStep; | 46 | const UInt32 kBlockSizeMax = kBlockSizeMultMax * kBlockSizeStep; |
| 47 | 47 | ||
| 48 | const unsigned kNumSelectorsBits = 15; | 48 | const unsigned kNumSelectorsBits = 15; |
| 49 | const UInt32 kNumSelectorsMax = (2 + (kBlockSizeMax / kGroupSize)); | 49 | const unsigned kNumSelectorsMax = 2 + kBlockSizeMax / kGroupSize; |
| 50 | 50 | ||
| 51 | const unsigned kRleModeRepSize = 4; | 51 | const unsigned kRleModeRepSize = 4; |
| 52 | 52 | ||
diff --git a/CPP/7zip/Compress/BZip2Encoder.cpp b/CPP/7zip/Compress/BZip2Encoder.cpp index ef2555a..f8ee0c9 100644 --- a/CPP/7zip/Compress/BZip2Encoder.cpp +++ b/CPP/7zip/Compress/BZip2Encoder.cpp | |||
| @@ -6,18 +6,20 @@ | |||
| 6 | #include "../../../C/BwtSort.h" | 6 | #include "../../../C/BwtSort.h" |
| 7 | #include "../../../C/HuffEnc.h" | 7 | #include "../../../C/HuffEnc.h" |
| 8 | 8 | ||
| 9 | #include "BZip2Crc.h" | ||
| 10 | #include "BZip2Encoder.h" | 9 | #include "BZip2Encoder.h" |
| 11 | #include "Mtf8.h" | ||
| 12 | 10 | ||
| 13 | namespace NCompress { | 11 | namespace NCompress { |
| 14 | namespace NBZip2 { | 12 | namespace NBZip2 { |
| 15 | 13 | ||
| 16 | const unsigned kMaxHuffmanLenForEncoding = 16; // it must be < kMaxHuffmanLen = 20 | 14 | #define HUFFMAN_LEN 16 |
| 17 | 15 | #if HUFFMAN_LEN > Z7_HUFFMAN_LEN_MAX | |
| 18 | static const UInt32 kBufferSize = (1 << 17); | 16 | #error Stop_Compiling_Bad_HUFFMAN_LEN_BZip2Encoder |
| 17 | #endif | ||
| 18 | |||
| 19 | static const size_t kBufferSize = 1 << 17; | ||
| 19 | static const unsigned kNumHuffPasses = 4; | 20 | static const unsigned kNumHuffPasses = 4; |
| 20 | 21 | ||
| 22 | |||
| 21 | bool CThreadInfo::Alloc() | 23 | bool CThreadInfo::Alloc() |
| 22 | { | 24 | { |
| 23 | if (!m_BlockSorterIndex) | 25 | if (!m_BlockSorterIndex) |
| @@ -27,11 +29,15 @@ bool CThreadInfo::Alloc() | |||
| 27 | return false; | 29 | return false; |
| 28 | } | 30 | } |
| 29 | 31 | ||
| 30 | if (!m_Block) | 32 | if (!m_Block_Base) |
| 31 | { | 33 | { |
| 32 | m_Block = (Byte *)::MidAlloc(kBlockSizeMax * 5 + kBlockSizeMax / 10 + (20 << 10)); | 34 | const unsigned kPadSize = 1 << 7; // we need at least 1 byte backward padding, becuase we use (m_Block - 1) pointer; |
| 33 | if (!m_Block) | 35 | m_Block_Base = (Byte *)::MidAlloc(kBlockSizeMax * 5 |
| 36 | + kBlockSizeMax / 10 + (20 << 10) | ||
| 37 | + kPadSize); | ||
| 38 | if (!m_Block_Base) | ||
| 34 | return false; | 39 | return false; |
| 40 | m_Block = m_Block_Base + kPadSize; | ||
| 35 | m_MtfArray = m_Block + kBlockSizeMax; | 41 | m_MtfArray = m_Block + kBlockSizeMax; |
| 36 | m_TempArray = m_MtfArray + kBlockSizeMax * 2 + 2; | 42 | m_TempArray = m_MtfArray + kBlockSizeMax * 2 + 2; |
| 37 | } | 43 | } |
| @@ -42,8 +48,8 @@ void CThreadInfo::Free() | |||
| 42 | { | 48 | { |
| 43 | ::BigFree(m_BlockSorterIndex); | 49 | ::BigFree(m_BlockSorterIndex); |
| 44 | m_BlockSorterIndex = NULL; | 50 | m_BlockSorterIndex = NULL; |
| 45 | ::MidFree(m_Block); | 51 | ::MidFree(m_Block_Base); |
| 46 | m_Block = NULL; | 52 | m_Block_Base = NULL; |
| 47 | } | 53 | } |
| 48 | 54 | ||
| 49 | #ifndef Z7_ST | 55 | #ifndef Z7_ST |
| @@ -60,6 +66,14 @@ HRESULT CThreadInfo::Create() | |||
| 60 | if (wres == 0) { wres = CanWriteEvent.Create(); | 66 | if (wres == 0) { wres = CanWriteEvent.Create(); |
| 61 | if (wres == 0) | 67 | if (wres == 0) |
| 62 | { | 68 | { |
| 69 | #ifdef _WIN32 | ||
| 70 | if (Encoder->_props.NumThreadGroups != 0) | ||
| 71 | { | ||
| 72 | const UInt32 group = ThreadNextGroup_GetNext(&Encoder->ThreadNextGroup); | ||
| 73 | wres = Thread.Create_With_Group(MFThread, this, group, 0); // affinity | ||
| 74 | } | ||
| 75 | else | ||
| 76 | #endif | ||
| 63 | if (Encoder->_props.Affinity != 0) | 77 | if (Encoder->_props.Affinity != 0) |
| 64 | wres = Thread.Create_With_Affinity(MFThread, this, (CAffinityMask)Encoder->_props.Affinity); | 78 | wres = Thread.Create_With_Affinity(MFThread, this, (CAffinityMask)Encoder->_props.Affinity); |
| 65 | else | 79 | else |
| @@ -216,94 +230,251 @@ void CEncoder::Free() | |||
| 216 | } | 230 | } |
| 217 | #endif | 231 | #endif |
| 218 | 232 | ||
| 233 | struct CRleEncoder | ||
| 234 | { | ||
| 235 | const Byte *_src; | ||
| 236 | const Byte *_srcLim; | ||
| 237 | Byte *_dest; | ||
| 238 | const Byte *_destLim; | ||
| 239 | Byte _prevByte; | ||
| 240 | unsigned _numReps; | ||
| 241 | |||
| 242 | void Encode(); | ||
| 243 | }; | ||
| 244 | |||
| 245 | Z7_NO_INLINE | ||
| 246 | void CRleEncoder::Encode() | ||
| 247 | { | ||
| 248 | const Byte *src = _src; | ||
| 249 | const Byte * const srcLim = _srcLim; | ||
| 250 | Byte *dest = _dest; | ||
| 251 | const Byte * const destLim = _destLim; | ||
| 252 | Byte prev = _prevByte; | ||
| 253 | unsigned numReps = _numReps; | ||
| 254 | // (dest < destLim) | ||
| 255 | // src = srcLim; // for debug | ||
| 256 | while (dest < destLim) | ||
| 257 | { | ||
| 258 | if (src == srcLim) | ||
| 259 | break; | ||
| 260 | const Byte b = *src++; | ||
| 261 | if (b != prev) | ||
| 262 | { | ||
| 263 | if (numReps >= kRleModeRepSize) | ||
| 264 | *dest++ = (Byte)(numReps - kRleModeRepSize); | ||
| 265 | *dest++ = b; | ||
| 266 | numReps = 1; | ||
| 267 | prev = b; | ||
| 268 | /* | ||
| 269 | { // speed optimization code: | ||
| 270 | if (dest >= destLim || src == srcLim) | ||
| 271 | break; | ||
| 272 | const Byte b2 = *src++; | ||
| 273 | *dest++ = b2; | ||
| 274 | numReps += (prev == b2); | ||
| 275 | prev = b2; | ||
| 276 | } | ||
| 277 | */ | ||
| 278 | continue; | ||
| 279 | } | ||
| 280 | numReps++; | ||
| 281 | if (numReps <= kRleModeRepSize) | ||
| 282 | *dest++ = b; | ||
| 283 | else if (numReps == kRleModeRepSize + 255) | ||
| 284 | { | ||
| 285 | *dest++ = (Byte)(numReps - kRleModeRepSize); | ||
| 286 | numReps = 0; | ||
| 287 | } | ||
| 288 | } | ||
| 289 | _src = src; | ||
| 290 | _dest = dest; | ||
| 291 | _prevByte = prev; | ||
| 292 | _numReps = numReps; | ||
| 293 | // (dest <= destLim + 1) | ||
| 294 | } | ||
| 295 | |||
| 296 | |||
| 297 | // out: return value is blockSize: size of data filled in buffer[]: | ||
| 298 | // (returned_blockSize <= _props.BlockSizeMult * kBlockSizeStep) | ||
| 219 | UInt32 CEncoder::ReadRleBlock(Byte *buffer) | 299 | UInt32 CEncoder::ReadRleBlock(Byte *buffer) |
| 220 | { | 300 | { |
| 301 | CRleEncoder rle; | ||
| 221 | UInt32 i = 0; | 302 | UInt32 i = 0; |
| 222 | Byte prevByte; | 303 | if (m_InStream.ReadByte(rle._prevByte)) |
| 223 | if (m_InStream.ReadByte(prevByte)) | ||
| 224 | { | 304 | { |
| 225 | NumBlocks++; | 305 | NumBlocks++; |
| 226 | const UInt32 blockSize = _props.BlockSizeMult * kBlockSizeStep - 1; | 306 | const UInt32 blockSize = _props.BlockSizeMult * kBlockSizeStep - 1; // -1 for RLE |
| 227 | unsigned numReps = 1; | 307 | rle._destLim = buffer + blockSize; |
| 228 | buffer[i++] = prevByte; | 308 | rle._numReps = 1; |
| 229 | while (i < blockSize) // "- 1" to support RLE | 309 | buffer[i++] = rle._prevByte; |
| 310 | while (i < blockSize) | ||
| 230 | { | 311 | { |
| 231 | Byte b; | 312 | rle._dest = buffer + i; |
| 232 | if (!m_InStream.ReadByte(b)) | 313 | size_t rem; |
| 314 | const Byte * const ptr = m_InStream.Lookahead(rem); | ||
| 315 | if (rem == 0) | ||
| 233 | break; | 316 | break; |
| 234 | if (b != prevByte) | 317 | rle._src = ptr; |
| 235 | { | 318 | rle._srcLim = ptr + rem; |
| 236 | if (numReps >= kRleModeRepSize) | 319 | rle.Encode(); |
| 237 | buffer[i++] = (Byte)(numReps - kRleModeRepSize); | 320 | m_InStream.Skip((size_t)(rle._src - ptr)); |
| 238 | buffer[i++] = b; | 321 | i = (UInt32)(size_t)(rle._dest - buffer); |
| 239 | numReps = 1; | 322 | // (i <= blockSize + 1) |
| 240 | prevByte = b; | ||
| 241 | continue; | ||
| 242 | } | ||
| 243 | numReps++; | ||
| 244 | if (numReps <= kRleModeRepSize) | ||
| 245 | buffer[i++] = b; | ||
| 246 | else if (numReps == kRleModeRepSize + 255) | ||
| 247 | { | ||
| 248 | buffer[i++] = (Byte)(numReps - kRleModeRepSize); | ||
| 249 | numReps = 0; | ||
| 250 | } | ||
| 251 | } | 323 | } |
| 252 | // it's to support original BZip2 decoder | 324 | const int n = (int)rle._numReps - (int)kRleModeRepSize; |
| 253 | if (numReps >= kRleModeRepSize) | 325 | if (n >= 0) |
| 254 | buffer[i++] = (Byte)(numReps - kRleModeRepSize); | 326 | buffer[i++] = (Byte)n; |
| 255 | } | 327 | } |
| 256 | return i; | 328 | return i; |
| 257 | } | 329 | } |
| 258 | 330 | ||
| 259 | void CThreadInfo::WriteBits2(UInt32 value, unsigned numBits) { m_OutStreamCurrent->WriteBits(value, numBits); } | 331 | |
| 260 | void CThreadInfo::WriteByte2(Byte b) { WriteBits2(b, 8); } | 332 | |
| 261 | void CThreadInfo::WriteBit2(Byte v) { WriteBits2(v, 1); } | 333 | Z7_NO_INLINE |
| 262 | void CThreadInfo::WriteCrc2(UInt32 v) | 334 | void CThreadInfo::WriteBits2(UInt32 value, unsigned numBits) |
| 263 | { | 335 | { m_OutStreamCurrent.WriteBits(value, numBits); } |
| 264 | for (unsigned i = 0; i < 4; i++) | 336 | /* |
| 265 | WriteByte2(((Byte)(v >> (24 - i * 8)))); | 337 | Z7_NO_INLINE |
| 338 | void CThreadInfo::WriteByte2(unsigned b) | ||
| 339 | { m_OutStreamCurrent.WriteByte(b); } | ||
| 340 | */ | ||
| 341 | // void CEncoder::WriteBits(UInt32 value, unsigned numBits) { m_OutStream.WriteBits(value, numBits); } | ||
| 342 | Z7_NO_INLINE | ||
| 343 | void CEncoder::WriteByte(Byte b) { m_OutStream.WriteByte(b); } | ||
| 344 | |||
| 345 | |||
| 346 | #define WRITE_BITS_UPDATE(value, numBits) \ | ||
| 347 | { \ | ||
| 348 | numBits -= _bitPos; \ | ||
| 349 | const UInt32 hi = value >> numBits; \ | ||
| 350 | *_buf++ = (Byte)(_curByte | hi); \ | ||
| 351 | value -= hi << numBits; \ | ||
| 352 | _bitPos = 8; \ | ||
| 353 | _curByte = 0; \ | ||
| 266 | } | 354 | } |
| 267 | 355 | ||
| 268 | void CEncoder::WriteBits(UInt32 value, unsigned numBits) { m_OutStream.WriteBits(value, numBits); } | 356 | #if HUFFMAN_LEN > 16 |
| 269 | void CEncoder::WriteByte(Byte b) { WriteBits(b, 8); } | 357 | |
| 270 | // void CEncoder::WriteBit(Byte v) { WriteBits(v, 1); } | 358 | #define WRITE_BITS_HUFF(value2, numBits2) \ |
| 271 | void CEncoder::WriteCrc(UInt32 v) | 359 | { \ |
| 272 | { | 360 | UInt32 value = value2; \ |
| 273 | for (unsigned i = 0; i < 4; i++) | 361 | unsigned numBits = numBits2; \ |
| 274 | WriteByte(((Byte)(v >> (24 - i * 8)))); | 362 | while (numBits >= _bitPos) { \ |
| 363 | WRITE_BITS_UPDATE(value, numBits) \ | ||
| 364 | } \ | ||
| 365 | _bitPos -= numBits; \ | ||
| 366 | _curByte |= (value << _bitPos); \ | ||
| 367 | } | ||
| 368 | |||
| 369 | #else // HUFFMAN_LEN <= 16 | ||
| 370 | |||
| 371 | // numBits2 <= 16 is supported | ||
| 372 | #define WRITE_BITS_HUFF(value2, numBits2) \ | ||
| 373 | { \ | ||
| 374 | UInt32 value = value2; \ | ||
| 375 | unsigned numBits = numBits2; \ | ||
| 376 | if (numBits >= _bitPos) \ | ||
| 377 | { \ | ||
| 378 | WRITE_BITS_UPDATE(value, numBits) \ | ||
| 379 | if (numBits >= _bitPos) \ | ||
| 380 | { \ | ||
| 381 | numBits -= _bitPos; \ | ||
| 382 | const UInt32 hi = value >> numBits; \ | ||
| 383 | *_buf++ = (Byte)hi; \ | ||
| 384 | value -= hi << numBits; \ | ||
| 385 | } \ | ||
| 386 | } \ | ||
| 387 | _bitPos -= numBits; \ | ||
| 388 | _curByte |= (value << _bitPos); \ | ||
| 389 | } | ||
| 390 | |||
| 391 | #endif | ||
| 392 | |||
| 393 | #define WRITE_BITS_8(value2, numBits2) \ | ||
| 394 | { \ | ||
| 395 | UInt32 value = value2; \ | ||
| 396 | unsigned numBits = numBits2; \ | ||
| 397 | if (numBits >= _bitPos) \ | ||
| 398 | { \ | ||
| 399 | WRITE_BITS_UPDATE(value, numBits) \ | ||
| 400 | } \ | ||
| 401 | _bitPos -= numBits; \ | ||
| 402 | _curByte |= (value << _bitPos); \ | ||
| 403 | } | ||
| 404 | |||
| 405 | #define WRITE_BIT_PRE \ | ||
| 406 | { _bitPos--; } | ||
| 407 | |||
| 408 | #define WRITE_BIT_POST \ | ||
| 409 | { \ | ||
| 410 | if (_bitPos == 0) \ | ||
| 411 | { \ | ||
| 412 | *_buf++ = (Byte)_curByte; \ | ||
| 413 | _curByte = 0; \ | ||
| 414 | _bitPos = 8; \ | ||
| 415 | } \ | ||
| 416 | } | ||
| 417 | |||
| 418 | #define WRITE_BIT_0 \ | ||
| 419 | { \ | ||
| 420 | WRITE_BIT_PRE \ | ||
| 421 | WRITE_BIT_POST \ | ||
| 422 | } | ||
| 423 | |||
| 424 | #define WRITE_BIT_1 \ | ||
| 425 | { \ | ||
| 426 | WRITE_BIT_PRE \ | ||
| 427 | _curByte |= 1u << _bitPos; \ | ||
| 428 | WRITE_BIT_POST \ | ||
| 275 | } | 429 | } |
| 276 | 430 | ||
| 277 | 431 | ||
| 278 | // blockSize > 0 | 432 | // blockSize > 0 |
| 279 | void CThreadInfo::EncodeBlock(const Byte *block, UInt32 blockSize) | 433 | void CThreadInfo::EncodeBlock(const Byte *block, UInt32 blockSize) |
| 280 | { | 434 | { |
| 281 | WriteBit2(0); // Randomised = false | 435 | // WriteBit2(0); // Randomised = false |
| 282 | |||
| 283 | { | 436 | { |
| 284 | UInt32 origPtr = BlockSort(m_BlockSorterIndex, block, blockSize); | 437 | const UInt32 origPtr = BlockSort(m_BlockSorterIndex, block, blockSize); |
| 285 | // if (m_BlockSorterIndex[origPtr] != 0) throw 1; | 438 | // if (m_BlockSorterIndex[origPtr] != 0) throw 1; |
| 286 | m_BlockSorterIndex[origPtr] = blockSize; | 439 | m_BlockSorterIndex[origPtr] = blockSize; |
| 287 | WriteBits2(origPtr, kNumOrigBits); | 440 | WriteBits2(origPtr, kNumOrigBits + 1); // + 1 for additional high bit flag (Randomised = false) |
| 288 | } | 441 | } |
| 289 | 442 | Byte mtfBuf[256]; | |
| 290 | CMtf8Encoder mtf; | 443 | // memset(mtfBuf, 0, sizeof(mtfBuf)); // to disable MSVC warning |
| 291 | unsigned numInUse = 0; | 444 | unsigned numInUse; |
| 292 | { | 445 | { |
| 293 | Byte inUse[256]; | 446 | Byte inUse[256]; |
| 294 | Byte inUse16[16]; | 447 | Byte inUse16[16]; |
| 295 | UInt32 i; | 448 | unsigned i; |
| 296 | for (i = 0; i < 256; i++) | 449 | for (i = 0; i < 256; i++) |
| 297 | inUse[i] = 0; | 450 | inUse[i] = 0; |
| 298 | for (i = 0; i < 16; i++) | 451 | for (i = 0; i < 16; i++) |
| 299 | inUse16[i] = 0; | 452 | inUse16[i] = 0; |
| 300 | for (i = 0; i < blockSize; i++) | 453 | { |
| 301 | inUse[block[i]] = 1; | 454 | const Byte * cur = block; |
| 455 | block = block + (size_t)blockSize - 1; | ||
| 456 | if (cur != block) | ||
| 457 | { | ||
| 458 | do | ||
| 459 | { | ||
| 460 | const unsigned b0 = cur[0]; | ||
| 461 | const unsigned b1 = cur[1]; | ||
| 462 | cur += 2; | ||
| 463 | inUse[b0] = 1; | ||
| 464 | inUse[b1] = 1; | ||
| 465 | } | ||
| 466 | while (cur < block); | ||
| 467 | } | ||
| 468 | if (cur == block) | ||
| 469 | inUse[cur[0]] = 1; | ||
| 470 | block -= blockSize; // block pointer is (original_block - 1) | ||
| 471 | } | ||
| 472 | numInUse = 0; | ||
| 302 | for (i = 0; i < 256; i++) | 473 | for (i = 0; i < 256; i++) |
| 303 | if (inUse[i]) | 474 | if (inUse[i]) |
| 304 | { | 475 | { |
| 305 | inUse16[i >> 4] = 1; | 476 | inUse16[i >> 4] = 1; |
| 306 | mtf.Buf[numInUse++] = (Byte)i; | 477 | mtfBuf[numInUse++] = (Byte)i; |
| 307 | } | 478 | } |
| 308 | for (i = 0; i < 16; i++) | 479 | for (i = 0; i < 16; i++) |
| 309 | WriteBit2(inUse16[i]); | 480 | WriteBit2(inUse16[i]); |
| @@ -311,65 +482,88 @@ void CThreadInfo::EncodeBlock(const Byte *block, UInt32 blockSize) | |||
| 311 | if (inUse16[i >> 4]) | 482 | if (inUse16[i >> 4]) |
| 312 | WriteBit2(inUse[i]); | 483 | WriteBit2(inUse[i]); |
| 313 | } | 484 | } |
| 314 | unsigned alphaSize = numInUse + 2; | 485 | const unsigned alphaSize = numInUse + 2; |
| 315 | 486 | ||
| 316 | Byte *mtfs = m_MtfArray; | ||
| 317 | UInt32 mtfArraySize = 0; | ||
| 318 | UInt32 symbolCounts[kMaxAlphaSize]; | 487 | UInt32 symbolCounts[kMaxAlphaSize]; |
| 319 | { | 488 | { |
| 320 | for (unsigned i = 0; i < kMaxAlphaSize; i++) | 489 | for (unsigned i = 0; i < kMaxAlphaSize; i++) |
| 321 | symbolCounts[i] = 0; | 490 | symbolCounts[i] = 0; |
| 491 | symbolCounts[(size_t)alphaSize - 1] = 1; | ||
| 322 | } | 492 | } |
| 323 | 493 | ||
| 494 | Byte *mtfs = m_MtfArray; | ||
| 324 | { | 495 | { |
| 325 | UInt32 rleSize = 0; | ||
| 326 | UInt32 i = 0; | ||
| 327 | const UInt32 *bsIndex = m_BlockSorterIndex; | 496 | const UInt32 *bsIndex = m_BlockSorterIndex; |
| 328 | block--; | 497 | const UInt32 *bsIndex_rle = bsIndex; |
| 498 | const UInt32 * const bsIndex_end = bsIndex + blockSize; | ||
| 499 | // block--; // backward fix | ||
| 500 | // block pointer is (original_block - 1) | ||
| 329 | do | 501 | do |
| 330 | { | 502 | { |
| 331 | unsigned pos = mtf.FindAndMove(block[bsIndex[i]]); | 503 | const Byte v = block[*bsIndex++]; |
| 332 | if (pos == 0) | 504 | Byte a = mtfBuf[0]; |
| 333 | rleSize++; | 505 | if (v != a) |
| 334 | else | ||
| 335 | { | 506 | { |
| 336 | while (rleSize != 0) | 507 | mtfBuf[0] = v; |
| 337 | { | 508 | { |
| 338 | rleSize--; | 509 | UInt32 rleSize = (UInt32)(size_t)(bsIndex - bsIndex_rle) - 1; |
| 339 | mtfs[mtfArraySize++] = (Byte)(rleSize & 1); | 510 | bsIndex_rle = bsIndex; |
| 340 | symbolCounts[rleSize & 1]++; | 511 | while (rleSize) |
| 341 | rleSize >>= 1; | 512 | { |
| 513 | const unsigned sym = (unsigned)(--rleSize & 1); | ||
| 514 | *mtfs++ = (Byte)sym; | ||
| 515 | symbolCounts[sym]++; | ||
| 516 | rleSize >>= 1; | ||
| 517 | } | ||
| 342 | } | 518 | } |
| 343 | if (pos >= 0xFE) | 519 | unsigned pos1 = 2; // = real_pos + 1 |
| 520 | Byte b; | ||
| 521 | b = mtfBuf[1]; mtfBuf[1] = a; if (v != b) | ||
| 522 | { a = mtfBuf[2]; mtfBuf[2] = b; if (v == a) pos1 = 3; | ||
| 523 | else { b = mtfBuf[3]; mtfBuf[3] = a; if (v == b) pos1 = 4; | ||
| 524 | else | ||
| 525 | { | ||
| 526 | Byte *m = mtfBuf + 7; | ||
| 527 | for (;;) | ||
| 528 | { | ||
| 529 | a = m[-3]; m[-3] = b; if (v == a) { pos1 = (unsigned)(size_t)(m - (mtfBuf + 2)); break; } | ||
| 530 | b = m[-2]; m[-2] = a; if (v == b) { pos1 = (unsigned)(size_t)(m - (mtfBuf + 1)); break; } | ||
| 531 | a = m[-1]; m[-1] = b; if (v == a) { pos1 = (unsigned)(size_t)(m - (mtfBuf )); break; } | ||
| 532 | b = m[ 0]; m[ 0] = a; m += 4; if (v == b) { pos1 = (unsigned)(size_t)(m - (mtfBuf + 3)); break; } | ||
| 533 | } | ||
| 534 | }}} | ||
| 535 | symbolCounts[pos1]++; | ||
| 536 | if (pos1 >= 0xff) | ||
| 344 | { | 537 | { |
| 345 | mtfs[mtfArraySize++] = 0xFF; | 538 | *mtfs++ = 0xff; |
| 346 | mtfs[mtfArraySize++] = (Byte)(pos - 0xFE); | 539 | // pos1 -= 0xff; |
| 540 | pos1++; // we need only low byte | ||
| 347 | } | 541 | } |
| 348 | else | 542 | *mtfs++ = (Byte)pos1; |
| 349 | mtfs[mtfArraySize++] = (Byte)(pos + 1); | ||
| 350 | symbolCounts[(size_t)pos + 1]++; | ||
| 351 | } | 543 | } |
| 352 | } | 544 | } |
| 353 | while (++i < blockSize); | 545 | while (bsIndex < bsIndex_end); |
| 354 | 546 | ||
| 355 | while (rleSize != 0) | 547 | UInt32 rleSize = (UInt32)(size_t)(bsIndex - bsIndex_rle); |
| 548 | while (rleSize) | ||
| 356 | { | 549 | { |
| 357 | rleSize--; | 550 | const unsigned sym = (unsigned)(--rleSize & 1); |
| 358 | mtfs[mtfArraySize++] = (Byte)(rleSize & 1); | 551 | *mtfs++ = (Byte)sym; |
| 359 | symbolCounts[rleSize & 1]++; | 552 | symbolCounts[sym]++; |
| 360 | rleSize >>= 1; | 553 | rleSize >>= 1; |
| 361 | } | 554 | } |
| 362 | 555 | ||
| 363 | if (alphaSize < 256) | 556 | unsigned d = alphaSize - 1; |
| 364 | mtfs[mtfArraySize++] = (Byte)(alphaSize - 1); | 557 | if (alphaSize >= 256) |
| 365 | else | ||
| 366 | { | 558 | { |
| 367 | mtfs[mtfArraySize++] = 0xFF; | 559 | *mtfs++ = 0xff; |
| 368 | mtfs[mtfArraySize++] = (Byte)(alphaSize - 256); | 560 | d = alphaSize; // (-256) |
| 369 | } | 561 | } |
| 370 | symbolCounts[(size_t)alphaSize - 1]++; | 562 | *mtfs++ = (Byte)d; |
| 371 | } | 563 | } |
| 372 | 564 | ||
| 565 | const Byte * const mtf_lim = mtfs; | ||
| 566 | |||
| 373 | UInt32 numSymbols = 0; | 567 | UInt32 numSymbols = 0; |
| 374 | { | 568 | { |
| 375 | for (unsigned i = 0; i < kMaxAlphaSize; i++) | 569 | for (unsigned i = 0; i < kMaxAlphaSize; i++) |
| @@ -378,34 +572,30 @@ void CThreadInfo::EncodeBlock(const Byte *block, UInt32 blockSize) | |||
| 378 | 572 | ||
| 379 | unsigned bestNumTables = kNumTablesMin; | 573 | unsigned bestNumTables = kNumTablesMin; |
| 380 | UInt32 bestPrice = 0xFFFFFFFF; | 574 | UInt32 bestPrice = 0xFFFFFFFF; |
| 381 | UInt32 startPos = m_OutStreamCurrent->GetPos(); | 575 | const UInt32 startPos = m_OutStreamCurrent.GetPos(); |
| 382 | Byte startCurByte = m_OutStreamCurrent->GetCurByte(); | 576 | const unsigned startCurByte = m_OutStreamCurrent.GetCurByte(); |
| 383 | for (unsigned nt = kNumTablesMin; nt <= kNumTablesMax + 1; nt++) | 577 | for (unsigned nt = kNumTablesMin; nt <= kNumTablesMax + 1; nt++) |
| 384 | { | 578 | { |
| 385 | unsigned numTables; | 579 | unsigned numTables; |
| 386 | 580 | ||
| 387 | if (m_OptimizeNumTables) | 581 | if (m_OptimizeNumTables) |
| 388 | { | 582 | { |
| 389 | m_OutStreamCurrent->SetPos(startPos); | 583 | m_OutStreamCurrent.SetPos(startPos); |
| 390 | m_OutStreamCurrent->SetCurState((startPos & 7), startCurByte); | 584 | m_OutStreamCurrent.SetCurState(startPos & 7, startCurByte); |
| 391 | if (nt <= kNumTablesMax) | 585 | numTables = (nt <= kNumTablesMax ? nt : bestNumTables); |
| 392 | numTables = nt; | ||
| 393 | else | ||
| 394 | numTables = bestNumTables; | ||
| 395 | } | 586 | } |
| 396 | else | 587 | else |
| 397 | { | 588 | { |
| 398 | if (numSymbols < 200) numTables = 2; | 589 | if (numSymbols < 200) numTables = 2; |
| 399 | else if (numSymbols < 600) numTables = 3; | 590 | else if (numSymbols < 600) numTables = 3; |
| 400 | else if (numSymbols < 1200) numTables = 4; | 591 | else if (numSymbols < 1200) numTables = 4; |
| 401 | else if (numSymbols < 2400) numTables = 5; | 592 | else if (numSymbols < 2400) numTables = 5; |
| 402 | else numTables = 6; | 593 | else numTables = 6; |
| 403 | } | 594 | } |
| 404 | 595 | ||
| 405 | WriteBits2(numTables, kNumTablesBits); | 596 | WriteBits2(numTables, kNumTablesBits); |
| 406 | 597 | const unsigned numSelectors = (numSymbols + kGroupSize - 1) / kGroupSize; | |
| 407 | UInt32 numSelectors = (numSymbols + kGroupSize - 1) / kGroupSize; | 598 | WriteBits2((UInt32)numSelectors, kNumSelectorsBits); |
| 408 | WriteBits2(numSelectors, kNumSelectorsBits); | ||
| 409 | 599 | ||
| 410 | { | 600 | { |
| 411 | UInt32 remFreq = numSymbols; | 601 | UInt32 remFreq = numSymbols; |
| @@ -436,28 +626,23 @@ void CThreadInfo::EncodeBlock(const Byte *block, UInt32 blockSize) | |||
| 436 | 626 | ||
| 437 | for (unsigned pass = 0; pass < kNumHuffPasses; pass++) | 627 | for (unsigned pass = 0; pass < kNumHuffPasses; pass++) |
| 438 | { | 628 | { |
| 629 | memset(Freqs, 0, sizeof(Freqs[0]) * numTables); | ||
| 630 | // memset(Freqs, 0, sizeof(Freqs)); | ||
| 439 | { | 631 | { |
| 440 | unsigned t = 0; | 632 | mtfs = m_MtfArray; |
| 441 | do | ||
| 442 | memset(Freqs[t], 0, sizeof(Freqs[t])); | ||
| 443 | while (++t < numTables); | ||
| 444 | } | ||
| 445 | |||
| 446 | { | ||
| 447 | UInt32 mtfPos = 0; | ||
| 448 | UInt32 g = 0; | 633 | UInt32 g = 0; |
| 449 | do | 634 | do |
| 450 | { | 635 | { |
| 451 | UInt32 symbols[kGroupSize]; | 636 | unsigned symbols[kGroupSize]; |
| 452 | unsigned i = 0; | 637 | unsigned i = 0; |
| 453 | do | 638 | do |
| 454 | { | 639 | { |
| 455 | UInt32 symbol = mtfs[mtfPos++]; | 640 | UInt32 symbol = *mtfs++; |
| 456 | if (symbol >= 0xFF) | 641 | if (symbol >= 0xFF) |
| 457 | symbol += mtfs[mtfPos++]; | 642 | symbol += *mtfs++; |
| 458 | symbols[i] = symbol; | 643 | symbols[i] = symbol; |
| 459 | } | 644 | } |
| 460 | while (++i < kGroupSize && mtfPos < mtfArraySize); | 645 | while (++i < kGroupSize && mtfs < mtf_lim); |
| 461 | 646 | ||
| 462 | UInt32 bestPrice2 = 0xFFFFFFFF; | 647 | UInt32 bestPrice2 = 0xFFFFFFFF; |
| 463 | unsigned t = 0; | 648 | unsigned t = 0; |
| @@ -482,7 +667,7 @@ void CThreadInfo::EncodeBlock(const Byte *block, UInt32 blockSize) | |||
| 482 | freqs[symbols[j]]++; | 667 | freqs[symbols[j]]++; |
| 483 | while (++j < i); | 668 | while (++j < i); |
| 484 | } | 669 | } |
| 485 | while (mtfPos < mtfArraySize); | 670 | while (mtfs < mtf_lim); |
| 486 | } | 671 | } |
| 487 | 672 | ||
| 488 | unsigned t = 0; | 673 | unsigned t = 0; |
| @@ -494,11 +679,15 @@ void CThreadInfo::EncodeBlock(const Byte *block, UInt32 blockSize) | |||
| 494 | if (freqs[i] == 0) | 679 | if (freqs[i] == 0) |
| 495 | freqs[i] = 1; | 680 | freqs[i] = 1; |
| 496 | while (++i < alphaSize); | 681 | while (++i < alphaSize); |
| 497 | Huffman_Generate(freqs, Codes[t], Lens[t], kMaxAlphaSize, kMaxHuffmanLenForEncoding); | 682 | Huffman_Generate(freqs, Codes[t], Lens[t], kMaxAlphaSize, HUFFMAN_LEN); |
| 498 | } | 683 | } |
| 499 | while (++t < numTables); | 684 | while (++t < numTables); |
| 500 | } | 685 | } |
| 501 | 686 | ||
| 687 | unsigned _bitPos; // 0 < _bitPos <= 8 : number of non-filled low bits in _curByte | ||
| 688 | unsigned _curByte; // low (_bitPos) bits are zeros | ||
| 689 | // high (8 - _bitPos) bits are filled | ||
| 690 | Byte *_buf; | ||
| 502 | { | 691 | { |
| 503 | Byte mtfSel[kNumTablesMax]; | 692 | Byte mtfSel[kNumTablesMax]; |
| 504 | { | 693 | { |
| @@ -507,81 +696,97 @@ void CThreadInfo::EncodeBlock(const Byte *block, UInt32 blockSize) | |||
| 507 | mtfSel[t] = (Byte)t; | 696 | mtfSel[t] = (Byte)t; |
| 508 | while (++t < numTables); | 697 | while (++t < numTables); |
| 509 | } | 698 | } |
| 699 | |||
| 700 | _bitPos = m_OutStreamCurrent._bitPos; | ||
| 701 | _curByte = m_OutStreamCurrent._curByte; | ||
| 702 | _buf = m_OutStreamCurrent._buf; | ||
| 703 | // stream.Init_from_Global(m_OutStreamCurrent); | ||
| 510 | 704 | ||
| 511 | UInt32 i = 0; | 705 | const Byte *selectors = m_Selectors; |
| 706 | const Byte * const selectors_lim = selectors + numSelectors; | ||
| 707 | Byte prev = 0; // mtfSel[0]; | ||
| 512 | do | 708 | do |
| 513 | { | 709 | { |
| 514 | Byte sel = m_Selectors[i]; | 710 | const Byte sel = *selectors++; |
| 515 | unsigned pos; | 711 | if (prev != sel) |
| 516 | for (pos = 0; mtfSel[pos] != sel; pos++) | 712 | { |
| 517 | WriteBit2(1); | 713 | Byte *mtfSel_cur = &mtfSel[1]; |
| 518 | WriteBit2(0); | 714 | for (;;) |
| 519 | for (; pos > 0; pos--) | 715 | { |
| 520 | mtfSel[pos] = mtfSel[(size_t)pos - 1]; | 716 | WRITE_BIT_1 |
| 521 | mtfSel[0] = sel; | 717 | const Byte next = *mtfSel_cur; |
| 718 | *mtfSel_cur++ = prev; | ||
| 719 | prev = next; | ||
| 720 | if (next == sel) | ||
| 721 | break; | ||
| 722 | } | ||
| 723 | // mtfSel[0] = sel; | ||
| 724 | } | ||
| 725 | WRITE_BIT_0 | ||
| 522 | } | 726 | } |
| 523 | while (++i < numSelectors); | 727 | while (selectors != selectors_lim); |
| 524 | } | 728 | } |
| 525 | |||
| 526 | { | 729 | { |
| 527 | unsigned t = 0; | 730 | unsigned t = 0; |
| 528 | do | 731 | do |
| 529 | { | 732 | { |
| 530 | const Byte *lens = Lens[t]; | 733 | const Byte *lens = Lens[t]; |
| 531 | UInt32 len = lens[0]; | 734 | unsigned len = lens[0]; |
| 532 | WriteBits2(len, kNumLevelsBits); | 735 | WRITE_BITS_8(len, kNumLevelsBits) |
| 533 | unsigned i = 0; | 736 | unsigned i = 0; |
| 534 | do | 737 | do |
| 535 | { | 738 | { |
| 536 | UInt32 level = lens[i]; | 739 | const unsigned level = lens[i]; |
| 537 | while (len != level) | 740 | while (len != level) |
| 538 | { | 741 | { |
| 539 | WriteBit2(1); | 742 | WRITE_BIT_1 |
| 540 | if (len < level) | 743 | if (len < level) |
| 541 | { | 744 | { |
| 542 | WriteBit2(0); | ||
| 543 | len++; | 745 | len++; |
| 746 | WRITE_BIT_0 | ||
| 544 | } | 747 | } |
| 545 | else | 748 | else |
| 546 | { | 749 | { |
| 547 | WriteBit2(1); | ||
| 548 | len--; | 750 | len--; |
| 751 | WRITE_BIT_1 | ||
| 549 | } | 752 | } |
| 550 | } | 753 | } |
| 551 | WriteBit2(0); | 754 | WRITE_BIT_0 |
| 552 | } | 755 | } |
| 553 | while (++i < alphaSize); | 756 | while (++i < alphaSize); |
| 554 | } | 757 | } |
| 555 | while (++t < numTables); | 758 | while (++t < numTables); |
| 556 | } | 759 | } |
| 557 | |||
| 558 | { | 760 | { |
| 559 | UInt32 groupSize = 0; | 761 | UInt32 groupSize = 1; |
| 560 | UInt32 groupIndex = 0; | 762 | const Byte *selectors = m_Selectors; |
| 561 | const Byte *lens = NULL; | 763 | const Byte *lens = NULL; |
| 562 | const UInt32 *codes = NULL; | 764 | const UInt32 *codes = NULL; |
| 563 | UInt32 mtfPos = 0; | 765 | mtfs = m_MtfArray; |
| 564 | do | 766 | do |
| 565 | { | 767 | { |
| 566 | UInt32 symbol = mtfs[mtfPos++]; | 768 | unsigned symbol = *mtfs++; |
| 567 | if (symbol >= 0xFF) | 769 | if (symbol >= 0xFF) |
| 568 | symbol += mtfs[mtfPos++]; | 770 | symbol += *mtfs++; |
| 569 | if (groupSize == 0) | 771 | if (--groupSize == 0) |
| 570 | { | 772 | { |
| 571 | groupSize = kGroupSize; | 773 | groupSize = kGroupSize; |
| 572 | unsigned t = m_Selectors[groupIndex++]; | 774 | const unsigned t = *selectors++; |
| 573 | lens = Lens[t]; | 775 | lens = Lens[t]; |
| 574 | codes = Codes[t]; | 776 | codes = Codes[t]; |
| 575 | } | 777 | } |
| 576 | groupSize--; | 778 | WRITE_BITS_HUFF(codes[symbol], lens[symbol]) |
| 577 | m_OutStreamCurrent->WriteBits(codes[symbol], lens[symbol]); | ||
| 578 | } | 779 | } |
| 579 | while (mtfPos < mtfArraySize); | 780 | while (mtfs < mtf_lim); |
| 580 | } | 781 | } |
| 782 | // Restore_from_Local: | ||
| 783 | m_OutStreamCurrent._bitPos = _bitPos; | ||
| 784 | m_OutStreamCurrent._curByte = _curByte; | ||
| 785 | m_OutStreamCurrent._buf = _buf; | ||
| 581 | 786 | ||
| 582 | if (!m_OptimizeNumTables) | 787 | if (!m_OptimizeNumTables) |
| 583 | break; | 788 | break; |
| 584 | UInt32 price = m_OutStreamCurrent->GetPos() - startPos; | 789 | const UInt32 price = m_OutStreamCurrent.GetPos() - startPos; |
| 585 | if (price <= bestPrice) | 790 | if (price <= bestPrice) |
| 586 | { | 791 | { |
| 587 | if (nt == kNumTablesMax) | 792 | if (nt == kNumTablesMax) |
| @@ -592,6 +797,7 @@ void CThreadInfo::EncodeBlock(const Byte *block, UInt32 blockSize) | |||
| 592 | } | 797 | } |
| 593 | } | 798 | } |
| 594 | 799 | ||
| 800 | |||
| 595 | // blockSize > 0 | 801 | // blockSize > 0 |
| 596 | UInt32 CThreadInfo::EncodeBlockWithHeaders(const Byte *block, UInt32 blockSize) | 802 | UInt32 CThreadInfo::EncodeBlockWithHeaders(const Byte *block, UInt32 blockSize) |
| 597 | { | 803 | { |
| @@ -603,148 +809,134 @@ UInt32 CThreadInfo::EncodeBlockWithHeaders(const Byte *block, UInt32 blockSize) | |||
| 603 | WriteByte2(kBlockSig5); | 809 | WriteByte2(kBlockSig5); |
| 604 | 810 | ||
| 605 | CBZip2Crc crc; | 811 | CBZip2Crc crc; |
| 606 | unsigned numReps = 0; | 812 | const Byte * const lim = block + blockSize; |
| 607 | Byte prevByte = block[0]; | 813 | unsigned b = *block++; |
| 608 | UInt32 i = 0; | 814 | crc.UpdateByte(b); |
| 609 | do | 815 | for (;;) |
| 610 | { | 816 | { |
| 611 | Byte b = block[i]; | 817 | const unsigned prev = b; |
| 612 | if (numReps == kRleModeRepSize) | 818 | if (block >= lim) { break; } b = *block++; crc.UpdateByte(b); if (prev != b) continue; |
| 613 | { | 819 | if (block >= lim) { break; } b = *block++; crc.UpdateByte(b); if (prev != b) continue; |
| 614 | for (; b > 0; b--) | 820 | if (block >= lim) { break; } b = *block++; crc.UpdateByte(b); if (prev != b) continue; |
| 615 | crc.UpdateByte(prevByte); | 821 | if (block >= lim) { break; } b = *block++; if (b) do crc.UpdateByte(prev); while (--b); |
| 616 | numReps = 0; | 822 | if (block >= lim) { break; } b = *block++; crc.UpdateByte(b); |
| 617 | continue; | ||
| 618 | } | ||
| 619 | if (prevByte == b) | ||
| 620 | numReps++; | ||
| 621 | else | ||
| 622 | { | ||
| 623 | numReps = 1; | ||
| 624 | prevByte = b; | ||
| 625 | } | ||
| 626 | crc.UpdateByte(b); | ||
| 627 | } | 823 | } |
| 628 | while (++i < blockSize); | 824 | const UInt32 crcRes = crc.GetDigest(); |
| 629 | UInt32 crcRes = crc.GetDigest(); | 825 | for (int i = 24; i >= 0; i -= 8) |
| 630 | WriteCrc2(crcRes); | 826 | WriteByte2((Byte)(crcRes >> i)); |
| 631 | EncodeBlock(block, blockSize); | 827 | EncodeBlock(lim - blockSize, blockSize); |
| 632 | return crcRes; | 828 | return crcRes; |
| 633 | } | 829 | } |
| 634 | 830 | ||
| 831 | |||
| 635 | void CThreadInfo::EncodeBlock2(const Byte *block, UInt32 blockSize, UInt32 numPasses) | 832 | void CThreadInfo::EncodeBlock2(const Byte *block, UInt32 blockSize, UInt32 numPasses) |
| 636 | { | 833 | { |
| 637 | UInt32 numCrcs = m_NumCrcs; | 834 | const UInt32 numCrcs = m_NumCrcs; |
| 638 | bool needCompare = false; | 835 | |
| 639 | 836 | const UInt32 startBytePos = m_OutStreamCurrent.GetBytePos(); | |
| 640 | UInt32 startBytePos = m_OutStreamCurrent->GetBytePos(); | 837 | const UInt32 startPos = m_OutStreamCurrent.GetPos(); |
| 641 | UInt32 startPos = m_OutStreamCurrent->GetPos(); | 838 | const unsigned startCurByte = m_OutStreamCurrent.GetCurByte(); |
| 642 | Byte startCurByte = m_OutStreamCurrent->GetCurByte(); | 839 | unsigned endCurByte = 0; |
| 643 | Byte endCurByte = 0; | 840 | UInt32 endPos = 0; // 0 means no no additional passes |
| 644 | UInt32 endPos = 0; | ||
| 645 | if (numPasses > 1 && blockSize >= (1 << 10)) | 841 | if (numPasses > 1 && blockSize >= (1 << 10)) |
| 646 | { | 842 | { |
| 647 | UInt32 blockSize0 = blockSize / 2; // ???? | 843 | UInt32 bs0 = blockSize / 2; |
| 648 | 844 | for (; bs0 < blockSize && | |
| 649 | for (; (block[blockSize0] == block[(size_t)blockSize0 - 1] | 845 | (block[ bs0 ] == |
| 650 | || block[(size_t)blockSize0 - 1] == block[(size_t)blockSize0 - 2]) | 846 | block[(size_t)bs0 - 1] || |
| 651 | && blockSize0 < blockSize; | 847 | block[(size_t)bs0 - 1] == |
| 652 | blockSize0++); | 848 | block[(size_t)bs0 - 2]); |
| 849 | bs0++) | ||
| 850 | {} | ||
| 653 | 851 | ||
| 654 | if (blockSize0 < blockSize) | 852 | if (bs0 < blockSize) |
| 655 | { | 853 | { |
| 656 | EncodeBlock2(block, blockSize0, numPasses - 1); | 854 | EncodeBlock2(block, bs0, numPasses - 1); |
| 657 | EncodeBlock2(block + blockSize0, blockSize - blockSize0, numPasses - 1); | 855 | EncodeBlock2(block + bs0, blockSize - bs0, numPasses - 1); |
| 658 | endPos = m_OutStreamCurrent->GetPos(); | 856 | endPos = m_OutStreamCurrent.GetPos(); |
| 659 | endCurByte = m_OutStreamCurrent->GetCurByte(); | 857 | endCurByte = m_OutStreamCurrent.GetCurByte(); |
| 660 | if ((endPos & 7) > 0) | 858 | // we prepare next byte as identical byte to starting byte for main encoding attempt: |
| 859 | if (endPos & 7) | ||
| 661 | WriteBits2(0, 8 - (endPos & 7)); | 860 | WriteBits2(0, 8 - (endPos & 7)); |
| 662 | m_OutStreamCurrent->SetCurState((startPos & 7), startCurByte); | 861 | m_OutStreamCurrent.SetCurState((startPos & 7), startCurByte); |
| 663 | needCompare = true; | ||
| 664 | } | 862 | } |
| 665 | } | 863 | } |
| 666 | 864 | ||
| 667 | UInt32 startBytePos2 = m_OutStreamCurrent->GetBytePos(); | 865 | const UInt32 startBytePos2 = m_OutStreamCurrent.GetBytePos(); |
| 668 | UInt32 startPos2 = m_OutStreamCurrent->GetPos(); | 866 | const UInt32 startPos2 = m_OutStreamCurrent.GetPos(); |
| 669 | UInt32 crcVal = EncodeBlockWithHeaders(block, blockSize); | 867 | const UInt32 crcVal = EncodeBlockWithHeaders(block, blockSize); |
| 670 | UInt32 endPos2 = m_OutStreamCurrent->GetPos(); | ||
| 671 | 868 | ||
| 672 | if (needCompare) | 869 | if (endPos) |
| 673 | { | 870 | { |
| 674 | UInt32 size2 = endPos2 - startPos2; | 871 | const UInt32 size2 = m_OutStreamCurrent.GetPos() - startPos2; |
| 675 | if (size2 < endPos - startPos) | 872 | if (size2 >= endPos - startPos) |
| 676 | { | ||
| 677 | UInt32 numBytes = m_OutStreamCurrent->GetBytePos() - startBytePos2; | ||
| 678 | Byte *buffer = m_OutStreamCurrent->GetStream(); | ||
| 679 | for (UInt32 i = 0; i < numBytes; i++) | ||
| 680 | buffer[startBytePos + i] = buffer[startBytePos2 + i]; | ||
| 681 | m_OutStreamCurrent->SetPos(startPos + endPos2 - startPos2); | ||
| 682 | m_NumCrcs = numCrcs; | ||
| 683 | m_CRCs[m_NumCrcs++] = crcVal; | ||
| 684 | } | ||
| 685 | else | ||
| 686 | { | 873 | { |
| 687 | m_OutStreamCurrent->SetPos(endPos); | 874 | m_OutStreamCurrent.SetPos(endPos); |
| 688 | m_OutStreamCurrent->SetCurState((endPos & 7), endCurByte); | 875 | m_OutStreamCurrent.SetCurState((endPos & 7), endCurByte); |
| 876 | return; | ||
| 689 | } | 877 | } |
| 878 | const UInt32 numBytes = m_OutStreamCurrent.GetBytePos() - startBytePos2; | ||
| 879 | Byte * const buffer = m_OutStreamCurrent.GetStream(); | ||
| 880 | memmove(buffer + startBytePos, buffer + startBytePos2, numBytes); | ||
| 881 | m_OutStreamCurrent.SetPos(startPos + size2); | ||
| 882 | // we don't call m_OutStreamCurrent.SetCurState() here because | ||
| 883 | // m_OutStreamCurrent._curByte is correct already | ||
| 690 | } | 884 | } |
| 691 | else | 885 | m_CRCs[numCrcs] = crcVal; |
| 692 | { | 886 | m_NumCrcs = numCrcs + 1; |
| 693 | m_NumCrcs = numCrcs; | ||
| 694 | m_CRCs[m_NumCrcs++] = crcVal; | ||
| 695 | } | ||
| 696 | } | 887 | } |
| 697 | 888 | ||
| 889 | |||
| 698 | HRESULT CThreadInfo::EncodeBlock3(UInt32 blockSize) | 890 | HRESULT CThreadInfo::EncodeBlock3(UInt32 blockSize) |
| 699 | { | 891 | { |
| 700 | CMsbfEncoderTemp outStreamTemp; | 892 | CMsbfEncoderTemp &outStreamTemp = m_OutStreamCurrent; |
| 701 | outStreamTemp.SetStream(m_TempArray); | 893 | outStreamTemp.SetStream(m_TempArray); |
| 702 | outStreamTemp.Init(); | 894 | outStreamTemp.Init(); |
| 703 | m_OutStreamCurrent = &outStreamTemp; | ||
| 704 | |||
| 705 | m_NumCrcs = 0; | 895 | m_NumCrcs = 0; |
| 706 | 896 | ||
| 707 | EncodeBlock2(m_Block, blockSize, Encoder->_props.NumPasses); | 897 | EncodeBlock2(m_Block, blockSize, Encoder->_props.NumPasses); |
| 708 | 898 | ||
| 709 | #ifndef Z7_ST | 899 | #ifndef Z7_ST |
| 710 | if (Encoder->MtMode) | 900 | if (Encoder->MtMode) |
| 711 | Encoder->ThreadsInfo[m_BlockIndex].CanWriteEvent.Lock(); | 901 | Encoder->ThreadsInfo[m_BlockIndex].CanWriteEvent.Lock(); |
| 712 | #endif | 902 | #endif |
| 903 | |||
| 713 | for (UInt32 i = 0; i < m_NumCrcs; i++) | 904 | for (UInt32 i = 0; i < m_NumCrcs; i++) |
| 714 | Encoder->CombinedCrc.Update(m_CRCs[i]); | 905 | Encoder->CombinedCrc.Update(m_CRCs[i]); |
| 715 | Encoder->WriteBytes(m_TempArray, outStreamTemp.GetPos(), outStreamTemp.GetCurByte()); | 906 | Encoder->WriteBytes(m_TempArray, outStreamTemp.GetPos(), outStreamTemp.GetNonFlushedByteBits()); |
| 716 | HRESULT res = S_OK; | 907 | HRESULT res = S_OK; |
| 717 | #ifndef Z7_ST | 908 | |
| 909 | #ifndef Z7_ST | ||
| 718 | if (Encoder->MtMode) | 910 | if (Encoder->MtMode) |
| 719 | { | 911 | { |
| 720 | UInt32 blockIndex = m_BlockIndex + 1; | 912 | UInt32 blockIndex = m_BlockIndex + 1; |
| 721 | if (blockIndex == Encoder->NumThreads) | 913 | if (blockIndex == Encoder->NumThreads) |
| 722 | blockIndex = 0; | 914 | blockIndex = 0; |
| 723 | |||
| 724 | if (Encoder->Progress) | 915 | if (Encoder->Progress) |
| 725 | { | 916 | { |
| 726 | const UInt64 packSize = Encoder->m_OutStream.GetProcessedSize(); | 917 | const UInt64 packSize = Encoder->m_OutStream.GetProcessedSize(); |
| 727 | res = Encoder->Progress->SetRatioInfo(&m_UnpackSize, &packSize); | 918 | res = Encoder->Progress->SetRatioInfo(&m_UnpackSize, &packSize); |
| 728 | } | 919 | } |
| 729 | |||
| 730 | Encoder->ThreadsInfo[blockIndex].CanWriteEvent.Set(); | 920 | Encoder->ThreadsInfo[blockIndex].CanWriteEvent.Set(); |
| 731 | } | 921 | } |
| 732 | #endif | 922 | #endif |
| 733 | return res; | 923 | return res; |
| 734 | } | 924 | } |
| 735 | 925 | ||
| 736 | void CEncoder::WriteBytes(const Byte *data, UInt32 sizeInBits, Byte lastByte) | 926 | void CEncoder::WriteBytes(const Byte *data, UInt32 sizeInBits, unsigned lastByteBits) |
| 737 | { | 927 | { |
| 738 | UInt32 bytesSize = (sizeInBits >> 3); | 928 | m_OutStream.WriteBytes(data, sizeInBits >> 3); |
| 739 | for (UInt32 i = 0; i < bytesSize; i++) | 929 | sizeInBits &= 7; |
| 740 | m_OutStream.WriteBits(data[i], 8); | 930 | if (sizeInBits) |
| 741 | WriteBits(lastByte, (sizeInBits & 7)); | 931 | m_OutStream.WriteBits(lastByteBits, sizeInBits); |
| 742 | } | 932 | } |
| 743 | 933 | ||
| 744 | 934 | ||
| 745 | HRESULT CEncoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, | 935 | HRESULT CEncoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, |
| 746 | const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress) | 936 | const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress) |
| 747 | { | 937 | { |
| 938 | ThreadNextGroup_Init(&ThreadNextGroup, _props.NumThreadGroups, 0); // startGroup | ||
| 939 | |||
| 748 | NumBlocks = 0; | 940 | NumBlocks = 0; |
| 749 | #ifndef Z7_ST | 941 | #ifndef Z7_ST |
| 750 | Progress = progress; | 942 | Progress = progress; |
| @@ -823,11 +1015,11 @@ HRESULT CEncoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream * | |||
| 823 | { | 1015 | { |
| 824 | CThreadInfo &ti = | 1016 | CThreadInfo &ti = |
| 825 | #ifndef Z7_ST | 1017 | #ifndef Z7_ST |
| 826 | ThreadsInfo[0]; | 1018 | ThreadsInfo[0]; |
| 827 | #else | 1019 | #else |
| 828 | ThreadsInfo; | 1020 | ThreadsInfo; |
| 829 | #endif | 1021 | #endif |
| 830 | UInt32 blockSize = ReadRleBlock(ti.m_Block); | 1022 | const UInt32 blockSize = ReadRleBlock(ti.m_Block); |
| 831 | if (blockSize == 0) | 1023 | if (blockSize == 0) |
| 832 | break; | 1024 | break; |
| 833 | RINOK(ti.EncodeBlock3(blockSize)) | 1025 | RINOK(ti.EncodeBlock3(blockSize)) |
| @@ -845,8 +1037,11 @@ HRESULT CEncoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream * | |||
| 845 | WriteByte(kFinSig3); | 1037 | WriteByte(kFinSig3); |
| 846 | WriteByte(kFinSig4); | 1038 | WriteByte(kFinSig4); |
| 847 | WriteByte(kFinSig5); | 1039 | WriteByte(kFinSig5); |
| 848 | 1040 | { | |
| 849 | WriteCrc(CombinedCrc.GetDigest()); | 1041 | const UInt32 v = CombinedCrc.GetDigest(); |
| 1042 | for (int i = 24; i >= 0; i -= 8) | ||
| 1043 | WriteByte((Byte)(v >> i)); | ||
| 1044 | } | ||
| 850 | RINOK(Flush()) | 1045 | RINOK(Flush()) |
| 851 | if (!m_InStream.WasFinished()) | 1046 | if (!m_InStream.WasFinished()) |
| 852 | return E_FAIL; | 1047 | return E_FAIL; |
| @@ -869,14 +1064,21 @@ Z7_COM7F_IMF(CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIA | |||
| 869 | for (UInt32 i = 0; i < numProps; i++) | 1064 | for (UInt32 i = 0; i < numProps; i++) |
| 870 | { | 1065 | { |
| 871 | const PROPVARIANT &prop = coderProps[i]; | 1066 | const PROPVARIANT &prop = coderProps[i]; |
| 872 | PROPID propID = propIDs[i]; | 1067 | const PROPID propID = propIDs[i]; |
| 873 | 1068 | ||
| 874 | if (propID == NCoderPropID::kAffinity) | 1069 | if (propID == NCoderPropID::kAffinity) |
| 875 | { | 1070 | { |
| 876 | if (prop.vt == VT_UI8) | 1071 | if (prop.vt != VT_UI8) |
| 877 | props.Affinity = prop.uhVal.QuadPart; | 1072 | return E_INVALIDARG; |
| 878 | else | 1073 | props.Affinity = prop.uhVal.QuadPart; |
| 1074 | continue; | ||
| 1075 | } | ||
| 1076 | |||
| 1077 | if (propID == NCoderPropID::kNumThreadGroups) | ||
| 1078 | { | ||
| 1079 | if (prop.vt != VT_UI4) | ||
| 879 | return E_INVALIDARG; | 1080 | return E_INVALIDARG; |
| 1081 | props.NumThreadGroups = (UInt32)prop.ulVal; | ||
| 880 | continue; | 1082 | continue; |
| 881 | } | 1083 | } |
| 882 | 1084 | ||
| @@ -884,7 +1086,7 @@ Z7_COM7F_IMF(CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIA | |||
| 884 | continue; | 1086 | continue; |
| 885 | if (prop.vt != VT_UI4) | 1087 | if (prop.vt != VT_UI4) |
| 886 | return E_INVALIDARG; | 1088 | return E_INVALIDARG; |
| 887 | UInt32 v = (UInt32)prop.ulVal; | 1089 | const UInt32 v = (UInt32)prop.ulVal; |
| 888 | switch (propID) | 1090 | switch (propID) |
| 889 | { | 1091 | { |
| 890 | case NCoderPropID::kNumPasses: props.NumPasses = v; break; | 1092 | case NCoderPropID::kNumPasses: props.NumPasses = v; break; |
diff --git a/CPP/7zip/Compress/BZip2Encoder.h b/CPP/7zip/Compress/BZip2Encoder.h index 4a04fbd..bcb4025 100644 --- a/CPP/7zip/Compress/BZip2Encoder.h +++ b/CPP/7zip/Compress/BZip2Encoder.h | |||
| @@ -3,7 +3,6 @@ | |||
| 3 | #ifndef ZIP7_INC_COMPRESS_BZIP2_ENCODER_H | 3 | #ifndef ZIP7_INC_COMPRESS_BZIP2_ENCODER_H |
| 4 | #define ZIP7_INC_COMPRESS_BZIP2_ENCODER_H | 4 | #define ZIP7_INC_COMPRESS_BZIP2_ENCODER_H |
| 5 | 5 | ||
| 6 | #include "../../Common/Defs.h" | ||
| 7 | #include "../../Common/MyCom.h" | 6 | #include "../../Common/MyCom.h" |
| 8 | 7 | ||
| 9 | #ifndef Z7_ST | 8 | #ifndef Z7_ST |
| @@ -23,80 +22,114 @@ | |||
| 23 | namespace NCompress { | 22 | namespace NCompress { |
| 24 | namespace NBZip2 { | 23 | namespace NBZip2 { |
| 25 | 24 | ||
| 26 | class CMsbfEncoderTemp | 25 | const unsigned kNumPassesMax = 10; |
| 26 | |||
| 27 | struct CMsbfEncoderTemp | ||
| 27 | { | 28 | { |
| 28 | UInt32 _pos; | 29 | unsigned _bitPos; // 0 < _bitPos <= 8 : number of non-filled low bits in _curByte |
| 29 | unsigned _bitPos; | 30 | unsigned _curByte; // low (_bitPos) bits are zeros |
| 30 | Byte _curByte; | 31 | // high (8 - _bitPos) bits are filled |
| 31 | Byte *_buf; | 32 | Byte *_buf; |
| 32 | public: | 33 | Byte *_buf_base; |
| 33 | void SetStream(Byte *buf) { _buf = buf; } | 34 | void SetStream(Byte *buf) { _buf_base = _buf = buf; } |
| 34 | Byte *GetStream() const { return _buf; } | 35 | Byte *GetStream() const { return _buf_base; } |
| 35 | 36 | ||
| 36 | void Init() | 37 | void Init() |
| 37 | { | 38 | { |
| 38 | _pos = 0; | ||
| 39 | _bitPos = 8; | 39 | _bitPos = 8; |
| 40 | _curByte = 0; | 40 | _curByte = 0; |
| 41 | _buf = _buf_base; | ||
| 41 | } | 42 | } |
| 42 | 43 | ||
| 43 | void Flush() | 44 | // required condition: (value >> numBits) == 0 |
| 44 | { | 45 | // numBits == 0 is allowed |
| 45 | if (_bitPos < 8) | ||
| 46 | WriteBits(0, _bitPos); | ||
| 47 | } | ||
| 48 | |||
| 49 | void WriteBits(UInt32 value, unsigned numBits) | 46 | void WriteBits(UInt32 value, unsigned numBits) |
| 50 | { | 47 | { |
| 51 | while (numBits > 0) | 48 | do |
| 52 | { | 49 | { |
| 53 | unsigned numNewBits = MyMin(numBits, _bitPos); | 50 | unsigned bp = _bitPos; |
| 54 | numBits -= numNewBits; | 51 | unsigned curByte = _curByte; |
| 55 | 52 | if (numBits < bp) | |
| 56 | _curByte = (Byte)(_curByte << numNewBits); | ||
| 57 | UInt32 newBits = value >> numBits; | ||
| 58 | _curByte |= Byte(newBits); | ||
| 59 | value -= (newBits << numBits); | ||
| 60 | |||
| 61 | _bitPos -= numNewBits; | ||
| 62 | |||
| 63 | if (_bitPos == 0) | ||
| 64 | { | 53 | { |
| 65 | _buf[_pos++] = _curByte; | 54 | bp -= numBits; |
| 66 | _bitPos = 8; | 55 | _curByte = curByte | (value << bp); |
| 56 | _bitPos = bp; | ||
| 57 | return; | ||
| 67 | } | 58 | } |
| 59 | numBits -= bp; | ||
| 60 | const UInt32 hi = value >> numBits; | ||
| 61 | value -= (hi << numBits); | ||
| 62 | Byte *buf = _buf; | ||
| 63 | _bitPos = 8; | ||
| 64 | _curByte = 0; | ||
| 65 | *buf++ = (Byte)(curByte | hi); | ||
| 66 | _buf = buf; | ||
| 68 | } | 67 | } |
| 68 | while (numBits); | ||
| 69 | } | 69 | } |
| 70 | 70 | ||
| 71 | UInt32 GetBytePos() const { return _pos ; } | 71 | void WriteBit(unsigned value) |
| 72 | UInt32 GetPos() const { return _pos * 8 + (8 - _bitPos); } | 72 | { |
| 73 | Byte GetCurByte() const { return _curByte; } | 73 | const unsigned bp = _bitPos - 1; |
| 74 | const unsigned curByte = _curByte | (value << bp); | ||
| 75 | _curByte = curByte; | ||
| 76 | _bitPos = bp; | ||
| 77 | if (bp == 0) | ||
| 78 | { | ||
| 79 | *_buf++ = (Byte)curByte; | ||
| 80 | _curByte = 0; | ||
| 81 | _bitPos = 8; | ||
| 82 | } | ||
| 83 | } | ||
| 84 | |||
| 85 | void WriteByte(unsigned b) | ||
| 86 | { | ||
| 87 | const unsigned bp = _bitPos; | ||
| 88 | const unsigned a = _curByte | (b >> (8 - bp)); | ||
| 89 | _curByte = b << bp; | ||
| 90 | Byte *buf = _buf; | ||
| 91 | *buf++ = (Byte)a; | ||
| 92 | _buf = buf; | ||
| 93 | } | ||
| 94 | |||
| 95 | UInt32 GetBytePos() const { return (UInt32)(size_t)(_buf - _buf_base); } | ||
| 96 | UInt32 GetPos() const { return GetBytePos() * 8 + 8 - _bitPos; } | ||
| 97 | unsigned GetCurByte() const { return _curByte; } | ||
| 98 | unsigned GetNonFlushedByteBits() const { return _curByte >> _bitPos; } | ||
| 74 | void SetPos(UInt32 bitPos) | 99 | void SetPos(UInt32 bitPos) |
| 75 | { | 100 | { |
| 76 | _pos = bitPos >> 3; | 101 | _buf = _buf_base + (bitPos >> 3); |
| 77 | _bitPos = 8 - ((unsigned)bitPos & 7); | 102 | _bitPos = 8 - ((unsigned)bitPos & 7); |
| 78 | } | 103 | } |
| 79 | void SetCurState(unsigned bitPos, Byte curByte) | 104 | void SetCurState(unsigned bitPos, unsigned curByte) |
| 80 | { | 105 | { |
| 81 | _bitPos = 8 - bitPos; | 106 | _bitPos = 8 - bitPos; |
| 82 | _curByte = curByte; | 107 | _curByte = curByte; |
| 83 | } | 108 | } |
| 84 | }; | 109 | }; |
| 85 | 110 | ||
| 86 | class CEncoder; | ||
| 87 | 111 | ||
| 88 | const unsigned kNumPassesMax = 10; | 112 | class CEncoder; |
| 89 | 113 | ||
| 90 | class CThreadInfo | 114 | class CThreadInfo |
| 91 | { | 115 | { |
| 116 | private: | ||
| 117 | CMsbfEncoderTemp m_OutStreamCurrent; | ||
| 92 | public: | 118 | public: |
| 119 | CEncoder *Encoder; | ||
| 93 | Byte *m_Block; | 120 | Byte *m_Block; |
| 94 | private: | 121 | private: |
| 95 | Byte *m_MtfArray; | 122 | Byte *m_MtfArray; |
| 96 | Byte *m_TempArray; | 123 | Byte *m_TempArray; |
| 97 | UInt32 *m_BlockSorterIndex; | 124 | UInt32 *m_BlockSorterIndex; |
| 98 | 125 | ||
| 99 | CMsbfEncoderTemp *m_OutStreamCurrent; | 126 | public: |
| 127 | bool m_OptimizeNumTables; | ||
| 128 | UInt32 m_NumCrcs; | ||
| 129 | UInt32 m_BlockIndex; | ||
| 130 | UInt64 m_UnpackSize; | ||
| 131 | |||
| 132 | Byte *m_Block_Base; | ||
| 100 | 133 | ||
| 101 | Byte Lens[kNumTablesMax][kMaxAlphaSize]; | 134 | Byte Lens[kNumTablesMax][kMaxAlphaSize]; |
| 102 | UInt32 Freqs[kNumTablesMax][kMaxAlphaSize]; | 135 | UInt32 Freqs[kNumTablesMax][kMaxAlphaSize]; |
| @@ -105,20 +138,16 @@ private: | |||
| 105 | Byte m_Selectors[kNumSelectorsMax]; | 138 | Byte m_Selectors[kNumSelectorsMax]; |
| 106 | 139 | ||
| 107 | UInt32 m_CRCs[1 << kNumPassesMax]; | 140 | UInt32 m_CRCs[1 << kNumPassesMax]; |
| 108 | UInt32 m_NumCrcs; | ||
| 109 | 141 | ||
| 110 | void WriteBits2(UInt32 value, unsigned numBits); | 142 | void WriteBits2(UInt32 value, unsigned numBits); |
| 111 | void WriteByte2(Byte b); | 143 | void WriteByte2(unsigned b) { WriteBits2(b, 8); } |
| 112 | void WriteBit2(Byte v); | 144 | void WriteBit2(unsigned v) { m_OutStreamCurrent.WriteBit(v); } |
| 113 | void WriteCrc2(UInt32 v); | ||
| 114 | 145 | ||
| 115 | void EncodeBlock(const Byte *block, UInt32 blockSize); | 146 | void EncodeBlock(const Byte *block, UInt32 blockSize); |
| 116 | UInt32 EncodeBlockWithHeaders(const Byte *block, UInt32 blockSize); | 147 | UInt32 EncodeBlockWithHeaders(const Byte *block, UInt32 blockSize); |
| 117 | void EncodeBlock2(const Byte *block, UInt32 blockSize, UInt32 numPasses); | 148 | void EncodeBlock2(const Byte *block, UInt32 blockSize, UInt32 numPasses); |
| 118 | public: | 149 | public: |
| 119 | bool m_OptimizeNumTables; | 150 | #ifndef Z7_ST |
| 120 | CEncoder *Encoder; | ||
| 121 | #ifndef Z7_ST | ||
| 122 | NWindows::CThread Thread; | 151 | NWindows::CThread Thread; |
| 123 | 152 | ||
| 124 | NWindows::NSynchronization::CAutoResetEvent StreamWasFinishedEvent; | 153 | NWindows::NSynchronization::CAutoResetEvent StreamWasFinishedEvent; |
| @@ -127,17 +156,14 @@ public: | |||
| 127 | // it's not member of this thread. We just need one event per thread | 156 | // it's not member of this thread. We just need one event per thread |
| 128 | NWindows::NSynchronization::CAutoResetEvent CanWriteEvent; | 157 | NWindows::NSynchronization::CAutoResetEvent CanWriteEvent; |
| 129 | 158 | ||
| 130 | private: | ||
| 131 | UInt32 m_BlockIndex; | ||
| 132 | UInt64 m_UnpackSize; | ||
| 133 | public: | 159 | public: |
| 134 | Byte MtPad[1 << 8]; // It's pad for Multi-Threading. Must be >= Cache_Line_Size. | 160 | Byte MtPad[1 << 8]; // It's pad for Multi-Threading. Must be >= Cache_Line_Size. |
| 135 | HRESULT Create(); | 161 | HRESULT Create(); |
| 136 | void FinishStream(bool needLeave); | 162 | void FinishStream(bool needLeave); |
| 137 | THREAD_FUNC_RET_TYPE ThreadFunc(); | 163 | THREAD_FUNC_RET_TYPE ThreadFunc(); |
| 138 | #endif | 164 | #endif |
| 139 | 165 | ||
| 140 | CThreadInfo(): m_Block(NULL), m_BlockSorterIndex(NULL) {} | 166 | CThreadInfo(): m_BlockSorterIndex(NULL), m_Block_Base(NULL) {} |
| 141 | ~CThreadInfo() { Free(); } | 167 | ~CThreadInfo() { Free(); } |
| 142 | bool Alloc(); | 168 | bool Alloc(); |
| 143 | void Free(); | 169 | void Free(); |
| @@ -145,16 +171,19 @@ public: | |||
| 145 | HRESULT EncodeBlock3(UInt32 blockSize); | 171 | HRESULT EncodeBlock3(UInt32 blockSize); |
| 146 | }; | 172 | }; |
| 147 | 173 | ||
| 174 | |||
| 148 | struct CEncProps | 175 | struct CEncProps |
| 149 | { | 176 | { |
| 150 | UInt32 BlockSizeMult; | 177 | UInt32 BlockSizeMult; |
| 151 | UInt32 NumPasses; | 178 | UInt32 NumPasses; |
| 179 | UInt32 NumThreadGroups; | ||
| 152 | UInt64 Affinity; | 180 | UInt64 Affinity; |
| 153 | 181 | ||
| 154 | CEncProps() | 182 | CEncProps() |
| 155 | { | 183 | { |
| 156 | BlockSizeMult = (UInt32)(Int32)-1; | 184 | BlockSizeMult = (UInt32)(Int32)-1; |
| 157 | NumPasses = (UInt32)(Int32)-1; | 185 | NumPasses = (UInt32)(Int32)-1; |
| 186 | NumThreadGroups = 0; | ||
| 158 | Affinity = 0; | 187 | Affinity = 0; |
| 159 | } | 188 | } |
| 160 | void Normalize(int level); | 189 | void Normalize(int level); |
| @@ -206,6 +235,7 @@ public: | |||
| 206 | bool CloseThreads; | 235 | bool CloseThreads; |
| 207 | bool StreamWasFinished; | 236 | bool StreamWasFinished; |
| 208 | NWindows::NSynchronization::CManualResetEvent CanStartWaitingEvent; | 237 | NWindows::NSynchronization::CManualResetEvent CanStartWaitingEvent; |
| 238 | CThreadNextGroup ThreadNextGroup; | ||
| 209 | 239 | ||
| 210 | HRESULT Result; | 240 | HRESULT Result; |
| 211 | ICompressProgressInfo *Progress; | 241 | ICompressProgressInfo *Progress; |
| @@ -218,12 +248,8 @@ public: | |||
| 218 | UInt64 GetInProcessedSize() const { return m_InStream.GetProcessedSize(); } | 248 | UInt64 GetInProcessedSize() const { return m_InStream.GetProcessedSize(); } |
| 219 | 249 | ||
| 220 | UInt32 ReadRleBlock(Byte *buf); | 250 | UInt32 ReadRleBlock(Byte *buf); |
| 221 | void WriteBytes(const Byte *data, UInt32 sizeInBits, Byte lastByte); | 251 | void WriteBytes(const Byte *data, UInt32 sizeInBits, unsigned lastByteBits); |
| 222 | |||
| 223 | void WriteBits(UInt32 value, unsigned numBits); | ||
| 224 | void WriteByte(Byte b); | 252 | void WriteByte(Byte b); |
| 225 | // void WriteBit(Byte v); | ||
| 226 | void WriteCrc(UInt32 v); | ||
| 227 | 253 | ||
| 228 | #ifndef Z7_ST | 254 | #ifndef Z7_ST |
| 229 | HRESULT Create(); | 255 | HRESULT Create(); |
diff --git a/CPP/7zip/Compress/BitlEncoder.h b/CPP/7zip/Compress/BitlEncoder.h index 67b1428..364f84d 100644 --- a/CPP/7zip/Compress/BitlEncoder.h +++ b/CPP/7zip/Compress/BitlEncoder.h | |||
| @@ -33,6 +33,7 @@ public: | |||
| 33 | _bitPos = 8; | 33 | _bitPos = 8; |
| 34 | _curByte = 0; | 34 | _curByte = 0; |
| 35 | } | 35 | } |
| 36 | Z7_FORCE_INLINE | ||
| 36 | void WriteBits(UInt32 value, unsigned numBits) | 37 | void WriteBits(UInt32 value, unsigned numBits) |
| 37 | { | 38 | { |
| 38 | while (numBits > 0) | 39 | while (numBits > 0) |
diff --git a/CPP/7zip/Compress/BitmEncoder.h b/CPP/7zip/Compress/BitmEncoder.h index 978ee1c..f7448cd 100644 --- a/CPP/7zip/Compress/BitmEncoder.h +++ b/CPP/7zip/Compress/BitmEncoder.h | |||
| @@ -8,8 +8,9 @@ | |||
| 8 | template<class TOutByte> | 8 | template<class TOutByte> |
| 9 | class CBitmEncoder | 9 | class CBitmEncoder |
| 10 | { | 10 | { |
| 11 | unsigned _bitPos; | 11 | unsigned _bitPos; // 0 < _bitPos <= 8 : number of non-filled low bits in _curByte |
| 12 | Byte _curByte; | 12 | unsigned _curByte; // low (_bitPos) bits are zeros |
| 13 | // high (8 - _bitPos) bits are filled | ||
| 13 | TOutByte _stream; | 14 | TOutByte _stream; |
| 14 | public: | 15 | public: |
| 15 | bool Create(UInt32 bufferSize) { return _stream.Create(bufferSize); } | 16 | bool Create(UInt32 bufferSize) { return _stream.Create(bufferSize); } |
| @@ -24,25 +25,65 @@ public: | |||
| 24 | HRESULT Flush() | 25 | HRESULT Flush() |
| 25 | { | 26 | { |
| 26 | if (_bitPos < 8) | 27 | if (_bitPos < 8) |
| 27 | WriteBits(0, _bitPos); | 28 | { |
| 29 | _stream.WriteByte((Byte)_curByte); | ||
| 30 | _bitPos = 8; | ||
| 31 | _curByte = 0; | ||
| 32 | } | ||
| 28 | return _stream.Flush(); | 33 | return _stream.Flush(); |
| 29 | } | 34 | } |
| 35 | |||
| 36 | // required condition: (value >> numBits) == 0 | ||
| 37 | // numBits == 0 is allowed | ||
| 30 | void WriteBits(UInt32 value, unsigned numBits) | 38 | void WriteBits(UInt32 value, unsigned numBits) |
| 31 | { | 39 | { |
| 32 | while (numBits > 0) | 40 | do |
| 33 | { | 41 | { |
| 34 | if (numBits < _bitPos) | 42 | unsigned bp = _bitPos; |
| 43 | unsigned curByte = _curByte; | ||
| 44 | if (numBits < bp) | ||
| 35 | { | 45 | { |
| 36 | _curByte = (Byte)(_curByte | (value << (_bitPos -= numBits))); | 46 | bp -= numBits; |
| 47 | _curByte = curByte | (value << bp); | ||
| 48 | _bitPos = bp; | ||
| 37 | return; | 49 | return; |
| 38 | } | 50 | } |
| 39 | numBits -= _bitPos; | 51 | numBits -= bp; |
| 40 | UInt32 newBits = (value >> numBits); | 52 | const UInt32 hi = (value >> numBits); |
| 41 | value -= (newBits << numBits); | 53 | value -= (hi << numBits); |
| 42 | _stream.WriteByte((Byte)(_curByte | newBits)); | 54 | _stream.WriteByte((Byte)(curByte | hi)); |
| 43 | _bitPos = 8; | 55 | _bitPos = 8; |
| 44 | _curByte = 0; | 56 | _curByte = 0; |
| 45 | } | 57 | } |
| 58 | while (numBits); | ||
| 59 | } | ||
| 60 | void WriteByte(unsigned b) | ||
| 61 | { | ||
| 62 | const unsigned bp = _bitPos; | ||
| 63 | const unsigned a = _curByte | (b >> (8 - bp)); | ||
| 64 | _curByte = b << bp; | ||
| 65 | _stream.WriteByte((Byte)a); | ||
| 66 | } | ||
| 67 | |||
| 68 | void WriteBytes(const Byte *data, size_t num) | ||
| 69 | { | ||
| 70 | const unsigned bp = _bitPos; | ||
| 71 | #if 1 // 1 for optional speed-optimized code branch | ||
| 72 | if (bp == 8) | ||
| 73 | { | ||
| 74 | _stream.WriteBytes(data, num); | ||
| 75 | return; | ||
| 76 | } | ||
| 77 | #endif | ||
| 78 | unsigned c = _curByte; | ||
| 79 | const unsigned bp_rev = 8 - bp; | ||
| 80 | for (size_t i = 0; i < num; i++) | ||
| 81 | { | ||
| 82 | const unsigned b = data[i]; | ||
| 83 | _stream.WriteByte((Byte)(c | (b >> bp_rev))); | ||
| 84 | c = b << bp; | ||
| 85 | } | ||
| 86 | _curByte = c; | ||
| 46 | } | 87 | } |
| 47 | }; | 88 | }; |
| 48 | 89 | ||
diff --git a/CPP/7zip/Compress/DeflateDecoder.cpp b/CPP/7zip/Compress/DeflateDecoder.cpp index 73895fe..7993176 100644 --- a/CPP/7zip/Compress/DeflateDecoder.cpp +++ b/CPP/7zip/Compress/DeflateDecoder.cpp | |||
| @@ -117,15 +117,13 @@ bool CCoder::ReadTables(void) | |||
| 117 | if (_numDistLevels > kDistTableSize32) | 117 | if (_numDistLevels > kDistTableSize32) |
| 118 | return false; | 118 | return false; |
| 119 | 119 | ||
| 120 | Byte levelLevels[kLevelTableSize]; | 120 | const unsigned kLevelTableSize_aligned4 = kLevelTableSize + 1; |
| 121 | for (unsigned i = 0; i < kLevelTableSize; i++) | 121 | Byte levelLevels[kLevelTableSize_aligned4]; |
| 122 | { | 122 | memset (levelLevels, 0, sizeof(levelLevels)); |
| 123 | const unsigned position = kCodeLengthAlphabetOrder[i]; | 123 | unsigned i = 0; |
| 124 | if (i < numLevelCodes) | 124 | do |
| 125 | levelLevels[position] = (Byte)ReadBits(kLevelFieldSize); | 125 | levelLevels[kCodeLengthAlphabetOrder[i++]] = (Byte)ReadBits(kLevelFieldSize); |
| 126 | else | 126 | while (i != numLevelCodes); |
| 127 | levelLevels[position] = 0; | ||
| 128 | } | ||
| 129 | 127 | ||
| 130 | if (m_InBitStream.ExtraBitsWereRead()) | 128 | if (m_InBitStream.ExtraBitsWereRead()) |
| 131 | return false; | 129 | return false; |
diff --git a/CPP/7zip/Compress/DeflateEncoder.cpp b/CPP/7zip/Compress/DeflateEncoder.cpp index 87b4f83..afc5f12 100644 --- a/CPP/7zip/Compress/DeflateEncoder.cpp +++ b/CPP/7zip/Compress/DeflateEncoder.cpp | |||
| @@ -19,12 +19,16 @@ | |||
| 19 | #define NO_INLINE | 19 | #define NO_INLINE |
| 20 | #endif | 20 | #endif |
| 21 | 21 | ||
| 22 | #define MAX_HUF_LEN_12 12 | ||
| 23 | |||
| 22 | namespace NCompress { | 24 | namespace NCompress { |
| 23 | namespace NDeflate { | 25 | namespace NDeflate { |
| 24 | namespace NEncoder { | 26 | namespace NEncoder { |
| 25 | 27 | ||
| 28 | static const unsigned k_CodeValue_Len_Is_Literal_Flag = 1u << 15; | ||
| 29 | |||
| 26 | static const unsigned kNumDivPassesMax = 10; // [0, 16); ratio/speed/ram tradeoff; use big value for better compression ratio. | 30 | static const unsigned kNumDivPassesMax = 10; // [0, 16); ratio/speed/ram tradeoff; use big value for better compression ratio. |
| 27 | static const UInt32 kNumTables = (1 << kNumDivPassesMax); | 31 | static const unsigned kNumTables = 1u << kNumDivPassesMax; |
| 28 | 32 | ||
| 29 | static const UInt32 kFixedHuffmanCodeBlockSizeMax = (1 << 8); // [0, (1 << 32)); ratio/speed tradeoff; use big value for better compression ratio. | 33 | static const UInt32 kFixedHuffmanCodeBlockSizeMax = (1 << 8); // [0, (1 << 32)); ratio/speed tradeoff; use big value for better compression ratio. |
| 30 | static const UInt32 kDivideCodeBlockSizeMin = (1 << 7); // [1, (1 << 32)); ratio/speed tradeoff; use small value for better compression ratio. | 34 | static const UInt32 kDivideCodeBlockSizeMin = (1 << 7); // [1, (1 << 32)); ratio/speed tradeoff; use small value for better compression ratio. |
| @@ -77,7 +81,7 @@ public: | |||
| 77 | 81 | ||
| 78 | static CFastPosInit g_FastPosInit; | 82 | static CFastPosInit g_FastPosInit; |
| 79 | 83 | ||
| 80 | inline UInt32 GetPosSlot(UInt32 pos) | 84 | inline unsigned GetPosSlot(UInt32 pos) |
| 81 | { | 85 | { |
| 82 | /* | 86 | /* |
| 83 | if (pos < 0x200) | 87 | if (pos < 0x200) |
| @@ -162,13 +166,13 @@ HRESULT CCoder::Create() | |||
| 162 | // COM_TRY_BEGIN | 166 | // COM_TRY_BEGIN |
| 163 | if (!m_Values) | 167 | if (!m_Values) |
| 164 | { | 168 | { |
| 165 | m_Values = (CCodeValue *)MyAlloc((kMaxUncompressedBlockSize) * sizeof(CCodeValue)); | 169 | m_Values = (CCodeValue *)MyAlloc(kMaxUncompressedBlockSize * sizeof(CCodeValue)); |
| 166 | if (!m_Values) | 170 | if (!m_Values) |
| 167 | return E_OUTOFMEMORY; | 171 | return E_OUTOFMEMORY; |
| 168 | } | 172 | } |
| 169 | if (!m_Tables) | 173 | if (!m_Tables) |
| 170 | { | 174 | { |
| 171 | m_Tables = (CTables *)MyAlloc((kNumTables) * sizeof(CTables)); | 175 | m_Tables = (CTables *)MyAlloc(kNumTables * sizeof(CTables)); |
| 172 | if (!m_Tables) | 176 | if (!m_Tables) |
| 173 | return E_OUTOFMEMORY; | 177 | return E_OUTOFMEMORY; |
| 174 | } | 178 | } |
| @@ -268,19 +272,21 @@ NO_INLINE void CCoder::GetMatches() | |||
| 268 | 272 | ||
| 269 | UInt32 distanceTmp[kMatchMaxLen * 2 + 3]; | 273 | UInt32 distanceTmp[kMatchMaxLen * 2 + 3]; |
| 270 | 274 | ||
| 271 | const UInt32 numPairs = (UInt32)((_btMode ? | 275 | const size_t numPairs = (size_t)((_btMode ? |
| 272 | Bt3Zip_MatchFinder_GetMatches(&_lzInWindow, distanceTmp): | 276 | Bt3Zip_MatchFinder_GetMatches(&_lzInWindow, distanceTmp): |
| 273 | Hc3Zip_MatchFinder_GetMatches(&_lzInWindow, distanceTmp)) - distanceTmp); | 277 | Hc3Zip_MatchFinder_GetMatches(&_lzInWindow, distanceTmp)) - distanceTmp); |
| 274 | 278 | ||
| 275 | *m_MatchDistances = (UInt16)numPairs; | 279 | UInt16 *matchDistances = m_MatchDistances; |
| 280 | *matchDistances++ = (UInt16)numPairs; | ||
| 276 | 281 | ||
| 277 | if (numPairs != 0) | 282 | if (numPairs != 0) |
| 278 | { | 283 | { |
| 279 | UInt32 i; | 284 | size_t i; |
| 280 | for (i = 0; i < numPairs; i += 2) | 285 | for (i = 0; i < numPairs; i += 2) |
| 281 | { | 286 | { |
| 282 | m_MatchDistances[(size_t)i + 1] = (UInt16)distanceTmp[i]; | 287 | matchDistances[0] = (UInt16)distanceTmp[i]; |
| 283 | m_MatchDistances[(size_t)i + 2] = (UInt16)distanceTmp[(size_t)i + 1]; | 288 | matchDistances[1] = (UInt16)distanceTmp[(size_t)i + 1]; |
| 289 | matchDistances += 2; | ||
| 284 | } | 290 | } |
| 285 | UInt32 len = distanceTmp[(size_t)numPairs - 2]; | 291 | UInt32 len = distanceTmp[(size_t)numPairs - 2]; |
| 286 | if (len == m_NumFastBytes && m_NumFastBytes != m_MatchMaxLen) | 292 | if (len == m_NumFastBytes && m_NumFastBytes != m_MatchMaxLen) |
| @@ -291,11 +297,11 @@ NO_INLINE void CCoder::GetMatches() | |||
| 291 | if (numAvail > m_MatchMaxLen) | 297 | if (numAvail > m_MatchMaxLen) |
| 292 | numAvail = m_MatchMaxLen; | 298 | numAvail = m_MatchMaxLen; |
| 293 | for (; len < numAvail && pby[len] == pby2[len]; len++); | 299 | for (; len < numAvail && pby[len] == pby2[len]; len++); |
| 294 | m_MatchDistances[(size_t)i - 1] = (UInt16)len; | 300 | matchDistances[-2] = (UInt16)len; |
| 295 | } | 301 | } |
| 296 | } | 302 | } |
| 297 | if (m_IsMultiPass) | 303 | if (m_IsMultiPass) |
| 298 | m_Pos += numPairs + 1; | 304 | m_Pos += (UInt32)numPairs + 1; |
| 299 | if (!m_SecondPass) | 305 | if (!m_SecondPass) |
| 300 | m_AdditionalOffset++; | 306 | m_AdditionalOffset++; |
| 301 | } | 307 | } |
| @@ -535,6 +541,7 @@ NO_INLINE void CCoder::WriteBits(UInt32 value, unsigned numBits) | |||
| 535 | } | 541 | } |
| 536 | 542 | ||
| 537 | #define WRITE_HF2(codes, lens, i) m_OutStream.WriteBits(codes[i], lens[i]) | 543 | #define WRITE_HF2(codes, lens, i) m_OutStream.WriteBits(codes[i], lens[i]) |
| 544 | #define WRITE_HF2_NO_INLINE(codes, lens, i) WriteBits(codes[i], lens[i]) | ||
| 538 | #define WRITE_HF(i) WriteBits(codes[i], lens[i]) | 545 | #define WRITE_HF(i) WriteBits(codes[i], lens[i]) |
| 539 | 546 | ||
| 540 | NO_INLINE void CCoder::LevelTableCode(const Byte *levels, unsigned numLevels, const Byte *lens, const UInt32 *codes) | 547 | NO_INLINE void CCoder::LevelTableCode(const Byte *levels, unsigned numLevels, const Byte *lens, const UInt32 *codes) |
| @@ -619,17 +626,22 @@ static NO_INLINE UInt32 Huffman_GetPrice(const UInt32 *freqs, const Byte *lens, | |||
| 619 | return price; | 626 | return price; |
| 620 | } | 627 | } |
| 621 | 628 | ||
| 622 | static NO_INLINE UInt32 Huffman_GetPrice_Spec(const UInt32 *freqs, const Byte *lens, UInt32 num, const Byte *extraBits, UInt32 extraBase) | 629 | static NO_INLINE UInt32 Huffman_GetPrice_Spec( |
| 630 | const UInt32 *freqs, const Byte *lens, UInt32 num, | ||
| 631 | const Byte *extraBits, UInt32 extraBase) | ||
| 623 | { | 632 | { |
| 624 | return Huffman_GetPrice(freqs, lens, num) + | 633 | return |
| 634 | Huffman_GetPrice(freqs, lens, num) + | ||
| 625 | Huffman_GetPrice(freqs + extraBase, extraBits, num - extraBase); | 635 | Huffman_GetPrice(freqs + extraBase, extraBits, num - extraBase); |
| 626 | } | 636 | } |
| 627 | 637 | ||
| 628 | NO_INLINE UInt32 CCoder::GetLzBlockPrice() const | 638 | NO_INLINE UInt32 CCoder::GetLzBlockPrice() const |
| 629 | { | 639 | { |
| 630 | return | 640 | return |
| 631 | Huffman_GetPrice_Spec(mainFreqs, m_NewLevels.litLenLevels, kFixedMainTableSize, m_LenDirectBits, kSymbolMatch) + | 641 | Huffman_GetPrice_Spec(mainFreqs, m_NewLevels.litLenLevels, |
| 632 | Huffman_GetPrice_Spec(distFreqs, m_NewLevels.distLevels, kDistTableSize64, kDistDirectBits, 0); | 642 | kFixedMainTableSize, m_LenDirectBits, kSymbolMatch) + |
| 643 | Huffman_GetPrice_Spec(distFreqs, m_NewLevels.distLevels, | ||
| 644 | kDistTableSize64, kDistDirectBits, 0); | ||
| 633 | } | 645 | } |
| 634 | 646 | ||
| 635 | NO_INLINE void CCoder::TryBlock() | 647 | NO_INLINE void CCoder::TryBlock() |
| @@ -658,7 +670,7 @@ NO_INLINE void CCoder::TryBlock() | |||
| 658 | CCodeValue &codeValue = m_Values[m_ValueIndex++]; | 670 | CCodeValue &codeValue = m_Values[m_ValueIndex++]; |
| 659 | if (len >= kMatchMinLen) | 671 | if (len >= kMatchMinLen) |
| 660 | { | 672 | { |
| 661 | UInt32 newLen = len - kMatchMinLen; | 673 | const UInt32 newLen = len - kMatchMinLen; |
| 662 | codeValue.Len = (UInt16)newLen; | 674 | codeValue.Len = (UInt16)newLen; |
| 663 | mainFreqs[kSymbolMatch + (size_t)g_LenSlots[newLen]]++; | 675 | mainFreqs[kSymbolMatch + (size_t)g_LenSlots[newLen]]++; |
| 664 | codeValue.Pos = (UInt16)pos; | 676 | codeValue.Pos = (UInt16)pos; |
| @@ -666,10 +678,10 @@ NO_INLINE void CCoder::TryBlock() | |||
| 666 | } | 678 | } |
| 667 | else | 679 | else |
| 668 | { | 680 | { |
| 669 | Byte b = *(Inline_MatchFinder_GetPointerToCurrentPos(&_lzInWindow) - m_AdditionalOffset); | 681 | const unsigned b = *(Inline_MatchFinder_GetPointerToCurrentPos(&_lzInWindow) - m_AdditionalOffset); |
| 670 | mainFreqs[b]++; | 682 | mainFreqs[b]++; |
| 671 | codeValue.SetAsLiteral(); | 683 | codeValue.Len = k_CodeValue_Len_Is_Literal_Flag; |
| 672 | codeValue.Pos = b; | 684 | codeValue.Pos = (UInt16)b; |
| 673 | } | 685 | } |
| 674 | m_AdditionalOffset -= len; | 686 | m_AdditionalOffset -= len; |
| 675 | BlockSizeRes += len; | 687 | BlockSizeRes += len; |
| @@ -704,16 +716,24 @@ NO_INLINE void CCoder::SetPrices(const CLevels &levels) | |||
| 704 | } | 716 | } |
| 705 | } | 717 | } |
| 706 | 718 | ||
| 719 | #if MAX_HUF_LEN_12 > 12 | ||
| 720 | // Huffman_ReverseBits() now supports 12-bits values only. | ||
| 721 | #error Stop_Compiling_Bad_MAX_HUF_LEN_12 | ||
| 722 | #endif | ||
| 707 | static NO_INLINE void Huffman_ReverseBits(UInt32 *codes, const Byte *lens, UInt32 num) | 723 | static NO_INLINE void Huffman_ReverseBits(UInt32 *codes, const Byte *lens, UInt32 num) |
| 708 | { | 724 | { |
| 709 | for (UInt32 i = 0; i < num; i++) | 725 | const Byte * const lens_lim = lens + num; |
| 726 | do | ||
| 710 | { | 727 | { |
| 711 | UInt32 x = codes[i]; | 728 | // we should change constants, if lens[*] can be larger than 12. |
| 712 | x = ((x & 0x5555) << 1) | ((x & 0xAAAA) >> 1); | 729 | UInt32 x = *codes; |
| 713 | x = ((x & 0x3333) << 2) | ((x & 0xCCCC) >> 2); | 730 | x = ((x & (0x555 )) << 2) + (x & (0xAAA )); |
| 714 | x = ((x & 0x0F0F) << 4) | ((x & 0xF0F0) >> 4); | 731 | x = ((x & (0x333 << 1)) << 4) | (x & (0xCCC << 1)); |
| 715 | codes[i] = (((x & 0x00FF) << 8) | ((x & 0xFF00) >> 8)) >> (16 - lens[i]); | 732 | x = ((x & (0xF0F << 3)) << 8) | (x & (0x0F0 << 3)); |
| 733 | // we can use (x) instead of (x & (0xFF << 7)), if we support garabage data after (*lens) bits. | ||
| 734 | *codes++ = (((x & (0xFF << 7)) << 16) | x) >> (*lens ^ 31); | ||
| 716 | } | 735 | } |
| 736 | while (++lens != lens_lim); | ||
| 717 | } | 737 | } |
| 718 | 738 | ||
| 719 | NO_INLINE void CCoder::WriteBlock() | 739 | NO_INLINE void CCoder::WriteBlock() |
| @@ -721,24 +741,28 @@ NO_INLINE void CCoder::WriteBlock() | |||
| 721 | Huffman_ReverseBits(mainCodes, m_NewLevels.litLenLevels, kFixedMainTableSize); | 741 | Huffman_ReverseBits(mainCodes, m_NewLevels.litLenLevels, kFixedMainTableSize); |
| 722 | Huffman_ReverseBits(distCodes, m_NewLevels.distLevels, kDistTableSize64); | 742 | Huffman_ReverseBits(distCodes, m_NewLevels.distLevels, kDistTableSize64); |
| 723 | 743 | ||
| 724 | for (UInt32 i = 0; i < m_ValueIndex; i++) | 744 | CCodeValue *values = m_Values; |
| 745 | const CCodeValue * const values_lim = values + m_ValueIndex; | ||
| 746 | |||
| 747 | if (values != values_lim) | ||
| 748 | do | ||
| 725 | { | 749 | { |
| 726 | const CCodeValue &codeValue = m_Values[i]; | 750 | const UInt32 len = values->Len; |
| 727 | if (codeValue.IsLiteral()) | 751 | const UInt32 dist = values->Pos; |
| 728 | WRITE_HF2(mainCodes, m_NewLevels.litLenLevels, codeValue.Pos); | 752 | if (len == k_CodeValue_Len_Is_Literal_Flag) |
| 753 | WRITE_HF2(mainCodes, m_NewLevels.litLenLevels, dist); | ||
| 729 | else | 754 | else |
| 730 | { | 755 | { |
| 731 | UInt32 len = codeValue.Len; | 756 | const unsigned lenSlot = g_LenSlots[len]; |
| 732 | UInt32 lenSlot = g_LenSlots[len]; | ||
| 733 | WRITE_HF2(mainCodes, m_NewLevels.litLenLevels, kSymbolMatch + lenSlot); | 757 | WRITE_HF2(mainCodes, m_NewLevels.litLenLevels, kSymbolMatch + lenSlot); |
| 734 | m_OutStream.WriteBits(len - m_LenStart[lenSlot], m_LenDirectBits[lenSlot]); | 758 | m_OutStream.WriteBits(len - m_LenStart[lenSlot], m_LenDirectBits[lenSlot]); |
| 735 | UInt32 dist = codeValue.Pos; | 759 | const unsigned posSlot = GetPosSlot(dist); |
| 736 | UInt32 posSlot = GetPosSlot(dist); | ||
| 737 | WRITE_HF2(distCodes, m_NewLevels.distLevels, posSlot); | 760 | WRITE_HF2(distCodes, m_NewLevels.distLevels, posSlot); |
| 738 | m_OutStream.WriteBits(dist - kDistStart[posSlot], kDistDirectBits[posSlot]); | 761 | m_OutStream.WriteBits(dist - kDistStart[posSlot], kDistDirectBits[posSlot]); |
| 739 | } | 762 | } |
| 740 | } | 763 | } |
| 741 | WRITE_HF2(mainCodes, m_NewLevels.litLenLevels, kSymbolEndOfBlock); | 764 | while (++values != values_lim); |
| 765 | WRITE_HF2_NO_INLINE(mainCodes, m_NewLevels.litLenLevels, kSymbolEndOfBlock); | ||
| 742 | } | 766 | } |
| 743 | 767 | ||
| 744 | static UInt32 GetStorePrice(UInt32 blockSize, unsigned bitPosition) | 768 | static UInt32 GetStorePrice(UInt32 blockSize, unsigned bitPosition) |
| @@ -787,10 +811,10 @@ NO_INLINE UInt32 CCoder::TryDynBlock(unsigned tableIndex, UInt32 numPasses) | |||
| 787 | { | 811 | { |
| 788 | m_Pos = posTemp; | 812 | m_Pos = posTemp; |
| 789 | TryBlock(); | 813 | TryBlock(); |
| 790 | unsigned numHuffBits = | 814 | const unsigned numHuffBits = |
| 791 | (m_ValueIndex > 18000 ? 12 : | 815 | m_ValueIndex > 18000 ? MAX_HUF_LEN_12 : |
| 792 | (m_ValueIndex > 7000 ? 11 : | 816 | m_ValueIndex > 7000 ? 11 : |
| 793 | (m_ValueIndex > 2000 ? 10 : 9))); | 817 | m_ValueIndex > 2000 ? 10 : 9; |
| 794 | MakeTables(numHuffBits); | 818 | MakeTables(numHuffBits); |
| 795 | SetPrices(m_NewLevels); | 819 | SetPrices(m_NewLevels); |
| 796 | } | 820 | } |
diff --git a/CPP/7zip/Compress/Lzma2Encoder.cpp b/CPP/7zip/Compress/Lzma2Encoder.cpp index 0dc7e23..ffe1152 100644 --- a/CPP/7zip/Compress/Lzma2Encoder.cpp +++ b/CPP/7zip/Compress/Lzma2Encoder.cpp | |||
| @@ -52,7 +52,15 @@ HRESULT SetLzma2Prop(PROPID propID, const PROPVARIANT &prop, CLzma2EncProps &lzm | |||
| 52 | case NCoderPropID::kNumThreads: | 52 | case NCoderPropID::kNumThreads: |
| 53 | if (prop.vt != VT_UI4) | 53 | if (prop.vt != VT_UI4) |
| 54 | return E_INVALIDARG; | 54 | return E_INVALIDARG; |
| 55 | lzma2Props.numTotalThreads = (int)(prop.ulVal); | 55 | lzma2Props.numTotalThreads = (int)prop.ulVal; |
| 56 | break; | ||
| 57 | case NCoderPropID::kNumThreadGroups: | ||
| 58 | if (prop.vt != VT_UI4) | ||
| 59 | return E_INVALIDARG; | ||
| 60 | // 16-bit value supported by Windows | ||
| 61 | if (prop.ulVal >= (1u << 16)) | ||
| 62 | return E_INVALIDARG; | ||
| 63 | lzma2Props.numThreadGroups = (unsigned)prop.ulVal; | ||
| 56 | break; | 64 | break; |
| 57 | default: | 65 | default: |
| 58 | RINOK(NLzma::SetLzmaProp(propID, prop, lzma2Props.lzmaProps)) | 66 | RINOK(NLzma::SetLzmaProp(propID, prop, lzma2Props.lzmaProps)) |
diff --git a/CPP/7zip/Compress/LzmaEncoder.cpp b/CPP/7zip/Compress/LzmaEncoder.cpp index 08e3ba5..bca2eee 100644 --- a/CPP/7zip/Compress/LzmaEncoder.cpp +++ b/CPP/7zip/Compress/LzmaEncoder.cpp | |||
| @@ -101,6 +101,24 @@ HRESULT SetLzmaProp(PROPID propID, const PROPVARIANT &prop, CLzmaEncProps &ep) | |||
| 101 | return S_OK; | 101 | return S_OK; |
| 102 | } | 102 | } |
| 103 | 103 | ||
| 104 | if (propID == NCoderPropID::kAffinityInGroup) | ||
| 105 | { | ||
| 106 | if (prop.vt == VT_UI8) | ||
| 107 | ep.affinityInGroup = prop.uhVal.QuadPart; | ||
| 108 | else | ||
| 109 | return E_INVALIDARG; | ||
| 110 | return S_OK; | ||
| 111 | } | ||
| 112 | |||
| 113 | if (propID == NCoderPropID::kThreadGroup) | ||
| 114 | { | ||
| 115 | if (prop.vt == VT_UI4) | ||
| 116 | ep.affinityGroup = (Int32)(UInt32)prop.ulVal; | ||
| 117 | else | ||
| 118 | return E_INVALIDARG; | ||
| 119 | return S_OK; | ||
| 120 | } | ||
| 121 | |||
| 104 | if (propID == NCoderPropID::kHashBits) | 122 | if (propID == NCoderPropID::kHashBits) |
| 105 | { | 123 | { |
| 106 | if (prop.vt == VT_UI4) | 124 | if (prop.vt == VT_UI4) |
diff --git a/CPP/7zip/Compress/Mtf8.h b/CPP/7zip/Compress/Mtf8.h index 1b44d00..5fce30e 100644 --- a/CPP/7zip/Compress/Mtf8.h +++ b/CPP/7zip/Compress/Mtf8.h | |||
| @@ -13,6 +13,18 @@ struct CMtf8Encoder | |||
| 13 | 13 | ||
| 14 | unsigned FindAndMove(Byte v) throw() | 14 | unsigned FindAndMove(Byte v) throw() |
| 15 | { | 15 | { |
| 16 | #if 1 | ||
| 17 | Byte b = Buf[0]; | ||
| 18 | if (v == b) | ||
| 19 | return 0; | ||
| 20 | Buf[0] = v; | ||
| 21 | for (unsigned pos = 0;;) | ||
| 22 | { | ||
| 23 | Byte a; | ||
| 24 | a = Buf[++pos]; Buf[pos] = b; if (v == a) return pos; | ||
| 25 | b = Buf[++pos]; Buf[pos] = a; if (v == b) return pos; | ||
| 26 | } | ||
| 27 | #else | ||
| 16 | size_t pos; | 28 | size_t pos; |
| 17 | for (pos = 0; Buf[pos] != v; pos++); | 29 | for (pos = 0; Buf[pos] != v; pos++); |
| 18 | const unsigned resPos = (unsigned)pos; | 30 | const unsigned resPos = (unsigned)pos; |
| @@ -31,6 +43,7 @@ struct CMtf8Encoder | |||
| 31 | Buf[pos] = Buf[pos - 1]; | 43 | Buf[pos] = Buf[pos - 1]; |
| 32 | Buf[0] = v; | 44 | Buf[0] = v; |
| 33 | return resPos; | 45 | return resPos; |
| 46 | #endif | ||
| 34 | } | 47 | } |
| 35 | }; | 48 | }; |
| 36 | 49 | ||
diff --git a/CPP/7zip/Compress/Rar5Decoder.cpp b/CPP/7zip/Compress/Rar5Decoder.cpp index 8be24e2..7279b5a 100644 --- a/CPP/7zip/Compress/Rar5Decoder.cpp +++ b/CPP/7zip/Compress/Rar5Decoder.cpp | |||
| @@ -936,31 +936,30 @@ HRESULT CDecoder::ExecuteFilter(const CFilter &f) | |||
| 936 | HRESULT CDecoder::WriteBuf() | 936 | HRESULT CDecoder::WriteBuf() |
| 937 | { | 937 | { |
| 938 | DeleteUnusedFilters(); | 938 | DeleteUnusedFilters(); |
| 939 | |||
| 940 | const UInt64 lzSize = _lzSize + _winPos; | 939 | const UInt64 lzSize = _lzSize + _winPos; |
| 941 | 940 | ||
| 942 | for (unsigned i = 0; i < _numFilters;) | 941 | for (unsigned i = 0; i < _numFilters;) |
| 943 | { | 942 | { |
| 944 | const CFilter &f = _filters[i]; | ||
| 945 | const UInt64 blockStart = f.Start; | ||
| 946 | const size_t lzAvail = (size_t)(lzSize - _lzWritten); | 943 | const size_t lzAvail = (size_t)(lzSize - _lzWritten); |
| 947 | if (lzAvail == 0) | 944 | if (lzAvail == 0) |
| 948 | break; | 945 | break; |
| 949 | 946 | // (lzAvail != 0) | |
| 947 | const CFilter &f = _filters[i]; | ||
| 948 | const UInt64 blockStart = f.Start; | ||
| 950 | if (blockStart > _lzWritten) | 949 | if (blockStart > _lzWritten) |
| 951 | { | 950 | { |
| 952 | const UInt64 rem = blockStart - _lzWritten; | 951 | const UInt64 rem = blockStart - _lzWritten; |
| 952 | // (rem != 0) | ||
| 953 | size_t size = lzAvail; | 953 | size_t size = lzAvail; |
| 954 | if (size > rem) | 954 | if (size > rem) |
| 955 | size = (size_t)rem; | 955 | size = (size_t)rem; |
| 956 | if (size != 0) // is it true always ? | 956 | // (size != 0) |
| 957 | { | 957 | RINOK(WriteData(_window + _winPos - lzAvail, size)) |
| 958 | RINOK(WriteData(_window + _winPos - lzAvail, size)) | 958 | _lzWritten += size; |
| 959 | _lzWritten += size; | ||
| 960 | } | ||
| 961 | continue; | 959 | continue; |
| 962 | } | 960 | } |
| 963 | 961 | ||
| 962 | // (blockStart <= _lzWritten) | ||
| 964 | const UInt32 blockSize = f.Size; | 963 | const UInt32 blockSize = f.Size; |
| 965 | size_t offset = (size_t)(_lzWritten - blockStart); | 964 | size_t offset = (size_t)(_lzWritten - blockStart); |
| 966 | if (offset == 0) | 965 | if (offset == 0) |
| @@ -987,10 +986,8 @@ HRESULT CDecoder::WriteBuf() | |||
| 987 | } | 986 | } |
| 988 | 987 | ||
| 989 | DeleteUnusedFilters(); | 988 | DeleteUnusedFilters(); |
| 990 | |||
| 991 | if (_numFilters) | 989 | if (_numFilters) |
| 992 | return S_OK; | 990 | return S_OK; |
| 993 | |||
| 994 | const size_t lzAvail = (size_t)(lzSize - _lzWritten); | 991 | const size_t lzAvail = (size_t)(lzSize - _lzWritten); |
| 995 | RINOK(WriteData(_window + _winPos - lzAvail, lzAvail)) | 992 | RINOK(WriteData(_window + _winPos - lzAvail, lzAvail)) |
| 996 | _lzWritten += lzAvail; | 993 | _lzWritten += lzAvail; |
| @@ -1367,6 +1364,12 @@ enum enum_exit_type | |||
| 1367 | Z7_HUFF_DECODE_CHECK(sym, huf, kNumHufBits, kNumTableBits, bitStream, { LZ_LOOP_BREAK_ERROR }) | 1364 | Z7_HUFF_DECODE_CHECK(sym, huf, kNumHufBits, kNumTableBits, bitStream, { LZ_LOOP_BREAK_ERROR }) |
| 1368 | 1365 | ||
| 1369 | 1366 | ||
| 1367 | /* | ||
| 1368 | DecodeLZ2() will stop decoding if it reaches limit when (_winPos >= _limit) | ||
| 1369 | at return: | ||
| 1370 | (_winPos < _limit + kMaxMatchLen) | ||
| 1371 | also it can write up to (COPY_CHUNK_SIZE - 1) additional junk bytes after (_winPos). | ||
| 1372 | */ | ||
| 1370 | HRESULT CDecoder::DecodeLZ2(const CBitDecoder &bitStream) throw() | 1373 | HRESULT CDecoder::DecodeLZ2(const CBitDecoder &bitStream) throw() |
| 1371 | { | 1374 | { |
| 1372 | #if 0 | 1375 | #if 0 |
| @@ -1656,6 +1659,13 @@ decode_error: | |||
| 1656 | 1659 | ||
| 1657 | 1660 | ||
| 1658 | 1661 | ||
| 1662 | /* | ||
| 1663 | input conditions: | ||
| 1664 | _winPos < _winSize | ||
| 1665 | return: | ||
| 1666 | _winPos < _winSize is expected, if (return_res == S_OK) | ||
| 1667 | _winPos >= _winSize is possible in (return_res != S_OK) | ||
| 1668 | */ | ||
| 1659 | HRESULT CDecoder::DecodeLZ() | 1669 | HRESULT CDecoder::DecodeLZ() |
| 1660 | { | 1670 | { |
| 1661 | CBitDecoder _bitStream; | 1671 | CBitDecoder _bitStream; |
| @@ -1679,6 +1689,8 @@ HRESULT CDecoder::DecodeLZ() | |||
| 1679 | if (winPos >= limit) | 1689 | if (winPos >= limit) |
| 1680 | { | 1690 | { |
| 1681 | _winPos = winPos < _winSize ? winPos : _winSize; | 1691 | _winPos = winPos < _winSize ? winPos : _winSize; |
| 1692 | // _winPos == min(winPos, _winSize) | ||
| 1693 | // we will not write data after _winSize | ||
| 1682 | RINOK(WriteBuf()) | 1694 | RINOK(WriteBuf()) |
| 1683 | if (_unpackSize_Defined && _writtenFileSize > _unpackSize) | 1695 | if (_unpackSize_Defined && _writtenFileSize > _unpackSize) |
| 1684 | break; // return S_FALSE; | 1696 | break; // return S_FALSE; |
| @@ -1854,7 +1866,15 @@ Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream | |||
| 1854 | { | 1866 | { |
| 1855 | // if (_winPos > 100) _winPos -= 100; // for debug: corruption | 1867 | // if (_winPos > 100) _winPos -= 100; // for debug: corruption |
| 1856 | const UInt64 lzSize = _lzSize + _winPos; | 1868 | const UInt64 lzSize = _lzSize + _winPos; |
| 1857 | if (!_isSolid || !_wasInit | 1869 | /* |
| 1870 | if previous file was decoded with error or for some another cases, then | ||
| 1871 | (lzSize > _lzEnd) is possible | ||
| 1872 | (_winPos > _winSize) is possible | ||
| 1873 | (_winPos < _winSize + kMaxMatchLen) | ||
| 1874 | */ | ||
| 1875 | if (!_window | ||
| 1876 | || !_isSolid | ||
| 1877 | || !_wasInit | ||
| 1858 | || (lzSize < _lzEnd | 1878 | || (lzSize < _lzEnd |
| 1859 | #if Z7_RAR_RECOVER_SOLID_LIMIT != 0 | 1879 | #if Z7_RAR_RECOVER_SOLID_LIMIT != 0 |
| 1860 | && lzSize + Z7_RAR_RECOVER_SOLID_LIMIT < _lzEnd | 1880 | && lzSize + Z7_RAR_RECOVER_SOLID_LIMIT < _lzEnd |
| @@ -1863,9 +1883,9 @@ Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream | |||
| 1863 | { | 1883 | { |
| 1864 | if (_isSolid) | 1884 | if (_isSolid) |
| 1865 | _lzError = LZ_ERROR_TYPE_HEADER; | 1885 | _lzError = LZ_ERROR_TYPE_HEADER; |
| 1866 | _lzEnd = 0; | ||
| 1867 | _lzSize = 0; | 1886 | _lzSize = 0; |
| 1868 | _lzWritten = 0; | 1887 | // _lzEnd = 0; // it will be set later |
| 1888 | // _lzWritten = 0; // it will be set later | ||
| 1869 | _winPos = 0; | 1889 | _winPos = 0; |
| 1870 | for (unsigned i = 0; i < kNumReps; i++) | 1890 | for (unsigned i = 0; i < kNumReps; i++) |
| 1871 | _reps[i] = (size_t)0 - 1; | 1891 | _reps[i] = (size_t)0 - 1; |
| @@ -1873,51 +1893,67 @@ Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream | |||
| 1873 | _tableWasFilled = false; | 1893 | _tableWasFilled = false; |
| 1874 | _wasInit = true; | 1894 | _wasInit = true; |
| 1875 | } | 1895 | } |
| 1876 | #if Z7_RAR_RECOVER_SOLID_LIMIT != 0 | 1896 | else |
| 1877 | else if (lzSize < _lzEnd) | ||
| 1878 | { | 1897 | { |
| 1898 | const size_t ws = _winSize; | ||
| 1899 | if (_winPos >= ws) | ||
| 1900 | { | ||
| 1901 | // we must normalize (_winPos) and data in _window, | ||
| 1902 | _winPos -= ws; | ||
| 1903 | _lzSize += ws; | ||
| 1904 | // (_winPos < kMaxMatchLen < _winSize) | ||
| 1905 | // if (_window) | ||
| 1906 | memcpy(_window, _window + ws, _winPos); // memmove is not required here | ||
| 1907 | } | ||
| 1908 | |||
| 1909 | #if Z7_RAR_RECOVER_SOLID_LIMIT != 0 | ||
| 1910 | if (lzSize < _lzEnd) | ||
| 1911 | { | ||
| 1879 | #if 0 | 1912 | #if 0 |
| 1880 | return S_FALSE; | 1913 | return S_FALSE; |
| 1881 | #else | 1914 | #else |
| 1882 | // we can report that recovering was made: | 1915 | // we can report that recovering was made: |
| 1883 | // _lzError = LZ_ERROR_TYPE_HEADER; | 1916 | // _lzError = LZ_ERROR_TYPE_HEADER; |
| 1884 | // We write zeros to area after corruption: | 1917 | // We write zeros to area after corruption: |
| 1885 | if (_window) | 1918 | // if (_window) |
| 1886 | { | ||
| 1887 | UInt64 rem = _lzEnd - lzSize; | ||
| 1888 | const size_t ws = _winSize; | ||
| 1889 | if (rem >= ws) | ||
| 1890 | { | 1919 | { |
| 1891 | My_ZeroMemory(_window, ws); | 1920 | UInt64 rem = _lzEnd - lzSize; |
| 1892 | _lzSize = ws; | 1921 | if (rem >= ws) |
| 1893 | _winPos = 0; | ||
| 1894 | } | ||
| 1895 | else | ||
| 1896 | { | ||
| 1897 | const size_t cur = ws - _winPos; | ||
| 1898 | if (cur <= rem) | ||
| 1899 | { | 1922 | { |
| 1900 | rem -= cur; | 1923 | My_ZeroMemory(_window, ws); |
| 1901 | My_ZeroMemory(_window + _winPos, cur); | 1924 | _lzSize = ws; |
| 1902 | _lzSize += _winPos; | ||
| 1903 | _winPos = 0; | 1925 | _winPos = 0; |
| 1904 | } | 1926 | } |
| 1905 | My_ZeroMemory(_window + _winPos, (size_t)rem); | 1927 | else |
| 1906 | _winPos += (size_t)rem; | 1928 | { |
| 1929 | // rem < _winSize | ||
| 1930 | // _winPos <= ws | ||
| 1931 | const size_t cur = ws - _winPos; | ||
| 1932 | if (cur <= rem) | ||
| 1933 | { | ||
| 1934 | rem -= cur; | ||
| 1935 | My_ZeroMemory(_window + _winPos, cur); | ||
| 1936 | _lzSize = ws; | ||
| 1937 | _winPos = 0; | ||
| 1938 | } | ||
| 1939 | My_ZeroMemory(_window + _winPos, (size_t)rem); | ||
| 1940 | _winPos += (size_t)rem; | ||
| 1941 | } | ||
| 1907 | } | 1942 | } |
| 1908 | } | 1943 | // else return S_FALSE; |
| 1909 | // else return S_FALSE; | ||
| 1910 | #endif | 1944 | #endif |
| 1945 | } | ||
| 1911 | } | 1946 | } |
| 1912 | #endif | 1947 | #endif |
| 1913 | } | 1948 | } |
| 1914 | 1949 | ||
| 1950 | // _winPos < _winSize | ||
| 1915 | // we don't want _lzSize overflow | 1951 | // we don't want _lzSize overflow |
| 1916 | if (_lzSize >= DICT_SIZE_MAX) | 1952 | if (_lzSize >= DICT_SIZE_MAX) |
| 1917 | _lzSize = DICT_SIZE_MAX; | 1953 | _lzSize = DICT_SIZE_MAX; |
| 1918 | _lzEnd = _lzSize + _winPos; | 1954 | _lzEnd = _lzSize + _winPos; |
| 1919 | // _lzSize <= DICT_SIZE_MAX | 1955 | // _lzSize <= DICT_SIZE_MAX |
| 1920 | // _lzEnd <= DICT_SIZE_MAX * 2 | 1956 | // _lzEnd < DICT_SIZE_MAX + _winSize |
| 1921 | 1957 | ||
| 1922 | size_t newSize = _dictSize; | 1958 | size_t newSize = _dictSize; |
| 1923 | if (newSize < kWinSize_Min) | 1959 | if (newSize < kWinSize_Min) |
| @@ -1941,10 +1977,11 @@ Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream | |||
| 1941 | // If dictionary was increased in solid, we don't want grow. | 1977 | // If dictionary was increased in solid, we don't want grow. |
| 1942 | return S_FALSE; // E_OUTOFMEMORY | 1978 | return S_FALSE; // E_OUTOFMEMORY |
| 1943 | } | 1979 | } |
| 1944 | // (newSize <= _winSize) | 1980 | // (newSize <= _dictSize_forCheck) |
| 1945 | } | 1981 | } |
| 1946 | else | 1982 | else |
| 1947 | { | 1983 | { |
| 1984 | // !_isSolid || !_window | ||
| 1948 | _dictSize_forCheck = newSize; | 1985 | _dictSize_forCheck = newSize; |
| 1949 | { | 1986 | { |
| 1950 | size_t newSize_small = newSize; | 1987 | size_t newSize_small = newSize; |
| @@ -1964,7 +2001,7 @@ Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream | |||
| 1964 | if (!_window || allocSize > _winSize_Allocated) | 2001 | if (!_window || allocSize > _winSize_Allocated) |
| 1965 | { | 2002 | { |
| 1966 | Z7_RAR_FREE_WINDOW | 2003 | Z7_RAR_FREE_WINDOW |
| 1967 | _window = NULL; | 2004 | _window = NULL; |
| 1968 | _winSize_Allocated = 0; | 2005 | _winSize_Allocated = 0; |
| 1969 | Byte *win = (Byte *)::BigAlloc(allocSize); | 2006 | Byte *win = (Byte *)::BigAlloc(allocSize); |
| 1970 | if (!win) | 2007 | if (!win) |
diff --git a/CPP/7zip/Crypto/MyAes.cpp b/CPP/7zip/Crypto/MyAes.cpp index f84bca8..0ae0e16 100644 --- a/CPP/7zip/Crypto/MyAes.cpp +++ b/CPP/7zip/Crypto/MyAes.cpp | |||
| @@ -153,7 +153,26 @@ Z7_COM7F_IMF2(UInt32, CAesCtrCoder::Filter(Byte *data, UInt32 size)) | |||
| 153 | #ifndef Z7_EXTRACT_ONLY | 153 | #ifndef Z7_EXTRACT_ONLY |
| 154 | 154 | ||
| 155 | #ifdef MY_CPU_X86_OR_AMD64 | 155 | #ifdef MY_CPU_X86_OR_AMD64 |
| 156 | #define USE_HW_AES | 156 | |
| 157 | #if defined(__INTEL_COMPILER) | ||
| 158 | #if (__INTEL_COMPILER >= 1110) | ||
| 159 | #define USE_HW_AES | ||
| 160 | #if (__INTEL_COMPILER >= 1900) | ||
| 161 | #define USE_HW_VAES | ||
| 162 | #endif | ||
| 163 | #endif | ||
| 164 | #elif defined(Z7_CLANG_VERSION) && (Z7_CLANG_VERSION >= 30800) \ | ||
| 165 | || defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40400) | ||
| 166 | #define USE_HW_AES | ||
| 167 | #if defined(__clang__) && (__clang_major__ >= 8) \ | ||
| 168 | || defined(__GNUC__) && (__GNUC__ >= 8) | ||
| 169 | #define USE_HW_VAES | ||
| 170 | #endif | ||
| 171 | #elif defined(_MSC_VER) | ||
| 172 | #define USE_HW_AES | ||
| 173 | #define USE_HW_VAES | ||
| 174 | #endif | ||
| 175 | |||
| 157 | #elif defined(MY_CPU_ARM_OR_ARM64) && defined(MY_CPU_LE) | 176 | #elif defined(MY_CPU_ARM_OR_ARM64) && defined(MY_CPU_LE) |
| 158 | 177 | ||
| 159 | #if defined(__ARM_FEATURE_AES) \ | 178 | #if defined(__ARM_FEATURE_AES) \ |
| @@ -186,15 +205,15 @@ Z7_COM7F_IMF2(UInt32, CAesCtrCoder::Filter(Byte *data, UInt32 size)) | |||
| 186 | #define SET_AES_FUNC_2(f2) \ | 205 | #define SET_AES_FUNC_2(f2) \ |
| 187 | if (algo == 2) if (g_Aes_SupportedFunctions_Flags & k_Aes_SupportedFunctions_HW) \ | 206 | if (algo == 2) if (g_Aes_SupportedFunctions_Flags & k_Aes_SupportedFunctions_HW) \ |
| 188 | { f = f2; } | 207 | { f = f2; } |
| 189 | #ifdef MY_CPU_X86_OR_AMD64 | 208 | #ifdef USE_HW_VAES |
| 190 | #define SET_AES_FUNC_23(f2, f3) \ | 209 | #define SET_AES_FUNC_23(f2, f3) \ |
| 191 | SET_AES_FUNC_2(f2) \ | 210 | SET_AES_FUNC_2(f2) \ |
| 192 | if (algo == 3) if (g_Aes_SupportedFunctions_Flags & k_Aes_SupportedFunctions_HW_256) \ | 211 | if (algo == 3) if (g_Aes_SupportedFunctions_Flags & k_Aes_SupportedFunctions_HW_256) \ |
| 193 | { f = f3; } | 212 | { f = f3; } |
| 194 | #else // MY_CPU_X86_OR_AMD64 | 213 | #else // USE_HW_VAES |
| 195 | #define SET_AES_FUNC_23(f2, f3) \ | 214 | #define SET_AES_FUNC_23(f2, f3) \ |
| 196 | SET_AES_FUNC_2(f2) | 215 | SET_AES_FUNC_2(f2) |
| 197 | #endif // MY_CPU_X86_OR_AMD64 | 216 | #endif // USE_HW_VAES |
| 198 | #else // USE_HW_AES | 217 | #else // USE_HW_AES |
| 199 | #define SET_AES_FUNC_23(f2, f3) | 218 | #define SET_AES_FUNC_23(f2, f3) |
| 200 | #endif // USE_HW_AES | 219 | #endif // USE_HW_AES |
diff --git a/CPP/7zip/ICoder.h b/CPP/7zip/ICoder.h index aec2834..20d0ff7 100644 --- a/CPP/7zip/ICoder.h +++ b/CPP/7zip/ICoder.h | |||
| @@ -136,6 +136,9 @@ namespace NCoderPropID | |||
| 136 | kAffinity, // VT_UI8 | 136 | kAffinity, // VT_UI8 |
| 137 | kBranchOffset, // VT_UI4 | 137 | kBranchOffset, // VT_UI4 |
| 138 | kHashBits, // VT_UI4 | 138 | kHashBits, // VT_UI4 |
| 139 | kNumThreadGroups, // VT_UI4 | ||
| 140 | kThreadGroup, // VT_UI4 | ||
| 141 | kAffinityInGroup, // VT_UI8 | ||
| 139 | /* | 142 | /* |
| 140 | // kHash3Bits, // VT_UI4 | 143 | // kHash3Bits, // VT_UI4 |
| 141 | // kHash2Bits, // VT_UI4 | 144 | // kHash2Bits, // VT_UI4 |
diff --git a/CPP/7zip/Sort.mak b/CPP/7zip/Sort.mak new file mode 100644 index 0000000..ca0ff59 --- /dev/null +++ b/CPP/7zip/Sort.mak | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | !IF defined(USE_NO_ASM) || defined(USE_C_SORT) || "$(PLATFORM)" == "ia64" || "$(PLATFORM)" == "mips" || "$(PLATFORM)" == "arm" || "$(PLATFORM)" == "arm64" | ||
| 2 | C_OBJS = $(C_OBJS) \ | ||
| 3 | !ELSE | ||
| 4 | ASM_OBJS = $(ASM_OBJS) \ | ||
| 5 | !ENDIF | ||
| 6 | $O\Sort.obj | ||
diff --git a/CPP/7zip/UI/Common/ArchiveCommandLine.cpp b/CPP/7zip/UI/Common/ArchiveCommandLine.cpp index 556b25a..de9f43e 100644 --- a/CPP/7zip/UI/Common/ArchiveCommandLine.cpp +++ b/CPP/7zip/UI/Common/ArchiveCommandLine.cpp | |||
| @@ -63,17 +63,46 @@ EXTERN_C_END | |||
| 63 | 63 | ||
| 64 | #else | 64 | #else |
| 65 | 65 | ||
| 66 | // #define MY_isatty_fileno(x) (isatty(fileno(x))) | 66 | static bool MY_IS_TERMINAL(FILE *x) |
| 67 | // #define MY_IS_TERMINAL(x) (MY_isatty_fileno(x) != 0); | ||
| 68 | static inline bool MY_IS_TERMINAL(FILE *x) | ||
| 69 | { | 67 | { |
| 70 | return ( | 68 | #ifdef _WIN32 |
| 71 | #if defined(_MSC_VER) && (_MSC_VER >= 1400) | 69 | /* |
| 72 | _isatty(_fileno(x)) | 70 | crt/stdio.h: |
| 73 | #else | 71 | typedef struct _iobuf FILE; |
| 74 | isatty(fileno(x)) | 72 | #define stdin (&_iob[0]) |
| 75 | #endif | 73 | #define stdout (&_iob[1]) |
| 76 | != 0); | 74 | #define stderr (&_iob[2]) |
| 75 | */ | ||
| 76 | // fprintf(stderr, "\nMY_IS_TERMINAL = %p", x); | ||
| 77 | const int fd = _fileno(x); | ||
| 78 | /* (fd) is 0, 1 or 2 in console program. | ||
| 79 | docs: If stdout or stderr is not associated with | ||
| 80 | an output stream (for example, in a Windows application | ||
| 81 | without a console window), the file descriptor returned is -2. | ||
| 82 | In previous versions, the file descriptor returned was -1. | ||
| 83 | */ | ||
| 84 | if (fd < 0) // is not associated with an output stream application (without a console window) | ||
| 85 | return false; | ||
| 86 | // fprintf(stderr, "\n\nstderr _fileno(%p) = %d", x, fd); | ||
| 87 | if (!_isatty(fd)) | ||
| 88 | return false; | ||
| 89 | // fprintf(stderr, "\nisatty_val = true"); | ||
| 90 | const HANDLE h = (HANDLE)_get_osfhandle(fd); | ||
| 91 | /* _get_osfhandle() returns intptr_t in new SDK, or long in MSVC6. | ||
| 92 | Also it can return (INVALID_HANDLE_VALUE). | ||
| 93 | docs: _get_osfhandle also returns the special value -2 when | ||
| 94 | the file descriptor is not associated with a stream | ||
| 95 | in old msvcrt.dll: it returns (-1) for incorrect value | ||
| 96 | */ | ||
| 97 | // fprintf(stderr, "\n_get_osfhandle() = %p", (void *)h); | ||
| 98 | if (h == NULL || h == INVALID_HANDLE_VALUE) | ||
| 99 | return false; | ||
| 100 | DWORD st; | ||
| 101 | // fprintf(stderr, "\nGetConsoleMode() = %u", (unsigned)GetConsoleMode(h, &st)); | ||
| 102 | return GetConsoleMode(h, &st) != 0; | ||
| 103 | #else | ||
| 104 | return isatty(fileno(x)) != 0; | ||
| 105 | #endif | ||
| 77 | } | 106 | } |
| 78 | 107 | ||
| 79 | #endif | 108 | #endif |
| @@ -1088,7 +1117,7 @@ void CArcCmdLineParser::Parse1(const UStringVector &commandStrings, | |||
| 1088 | const UString &s = parser[NKey::kLargePages].PostStrings[0]; | 1117 | const UString &s = parser[NKey::kLargePages].PostStrings[0]; |
| 1089 | if (s.IsEmpty()) | 1118 | if (s.IsEmpty()) |
| 1090 | slp = 1; | 1119 | slp = 1; |
| 1091 | else if (s != L"-") | 1120 | else if (!s.IsEqualTo("-")) |
| 1092 | { | 1121 | { |
| 1093 | if (!StringToUInt32(s, slp)) | 1122 | if (!StringToUInt32(s, slp)) |
| 1094 | throw CArcCmdLineException("Unsupported switch postfix for -slp", s); | 1123 | throw CArcCmdLineException("Unsupported switch postfix for -slp", s); |
| @@ -1338,7 +1367,7 @@ void CArcCmdLineParser::Parse2(CArcCmdLineOptions &options) | |||
| 1338 | const UString &s = parser[NKey::kFullPathMode].PostStrings[0]; | 1367 | const UString &s = parser[NKey::kFullPathMode].PostStrings[0]; |
| 1339 | if (!s.IsEmpty()) | 1368 | if (!s.IsEmpty()) |
| 1340 | { | 1369 | { |
| 1341 | if (s == L"2") | 1370 | if (s.IsEqualTo("2")) |
| 1342 | censorPathMode = NWildcard::k_FullPath; | 1371 | censorPathMode = NWildcard::k_FullPath; |
| 1343 | else | 1372 | else |
| 1344 | throw CArcCmdLineException("Unsupported -spf:", s); | 1373 | throw CArcCmdLineException("Unsupported -spf:", s); |
| @@ -1400,6 +1429,7 @@ void CArcCmdLineParser::Parse2(CArcCmdLineOptions &options) | |||
| 1400 | const bool isExtractGroupCommand = options.Command.IsFromExtractGroup(); | 1429 | const bool isExtractGroupCommand = options.Command.IsFromExtractGroup(); |
| 1401 | const bool isExtractOrList = isExtractGroupCommand || options.Command.CommandType == NCommandType::kList; | 1430 | const bool isExtractOrList = isExtractGroupCommand || options.Command.CommandType == NCommandType::kList; |
| 1402 | const bool isRename = options.Command.CommandType == NCommandType::kRename; | 1431 | const bool isRename = options.Command.CommandType == NCommandType::kRename; |
| 1432 | options.UpdateOptions.RenameMode = isRename; | ||
| 1403 | 1433 | ||
| 1404 | if ((isExtractOrList || isRename) && options.StdInMode) | 1434 | if ((isExtractOrList || isRename) && options.StdInMode) |
| 1405 | thereIsArchiveName = false; | 1435 | thereIsArchiveName = false; |
| @@ -1516,9 +1546,9 @@ void CArcCmdLineParser::Parse2(CArcCmdLineOptions &options) | |||
| 1516 | const UString &s = parser[NKey::kZoneFile].PostStrings[0]; | 1546 | const UString &s = parser[NKey::kZoneFile].PostStrings[0]; |
| 1517 | if (!s.IsEmpty()) | 1547 | if (!s.IsEmpty()) |
| 1518 | { | 1548 | { |
| 1519 | if (s == L"0") eo.ZoneMode = NExtract::NZoneIdMode::kNone; | 1549 | if (s.IsEqualTo("0")) eo.ZoneMode = NExtract::NZoneIdMode::kNone; |
| 1520 | else if (s == L"1") eo.ZoneMode = NExtract::NZoneIdMode::kAll; | 1550 | else if (s.IsEqualTo("1")) eo.ZoneMode = NExtract::NZoneIdMode::kAll; |
| 1521 | else if (s == L"2") eo.ZoneMode = NExtract::NZoneIdMode::kOffice; | 1551 | else if (s.IsEqualTo("2")) eo.ZoneMode = NExtract::NZoneIdMode::kOffice; |
| 1522 | else | 1552 | else |
| 1523 | throw CArcCmdLineException("Unsupported -snz:", s); | 1553 | throw CArcCmdLineException("Unsupported -snz:", s); |
| 1524 | } | 1554 | } |
diff --git a/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp b/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp index 67ea29c..3abcd2d 100644 --- a/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp +++ b/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp | |||
| @@ -6,12 +6,10 @@ | |||
| 6 | #undef printf | 6 | #undef printf |
| 7 | 7 | ||
| 8 | // #include <stdio.h> | 8 | // #include <stdio.h> |
| 9 | // #include "../../../../C/CpuTicks.h" | ||
| 10 | 9 | ||
| 11 | #include "../../../../C/Alloc.h" | 10 | #include "../../../../C/Alloc.h" |
| 12 | #include "../../../../C/CpuArch.h" | 11 | #include "../../../../C/CpuArch.h" |
| 13 | 12 | ||
| 14 | |||
| 15 | #include "../../../Common/ComTry.h" | 13 | #include "../../../Common/ComTry.h" |
| 16 | #include "../../../Common/IntToString.h" | 14 | #include "../../../Common/IntToString.h" |
| 17 | #include "../../../Common/StringConvert.h" | 15 | #include "../../../Common/StringConvert.h" |
| @@ -33,6 +31,8 @@ | |||
| 33 | #include "../../Common/FilePathAutoRename.h" | 31 | #include "../../Common/FilePathAutoRename.h" |
| 34 | #include "../../Common/StreamUtils.h" | 32 | #include "../../Common/StreamUtils.h" |
| 35 | 33 | ||
| 34 | #include "../../Archive/Common/ItemNameUtils.h" | ||
| 35 | |||
| 36 | #include "../Common/ExtractingFilePath.h" | 36 | #include "../Common/ExtractingFilePath.h" |
| 37 | #include "../Common/PropIDUtils.h" | 37 | #include "../Common/PropIDUtils.h" |
| 38 | 38 | ||
| @@ -56,6 +56,19 @@ static const char * const kCantCreateHardLink = "Cannot create hard link"; | |||
| 56 | static const char * const kCantCreateSymLink = "Cannot create symbolic link"; | 56 | static const char * const kCantCreateSymLink = "Cannot create symbolic link"; |
| 57 | #endif | 57 | #endif |
| 58 | 58 | ||
| 59 | static const unsigned k_LinkDataSize_LIMIT = 1 << 12; | ||
| 60 | |||
| 61 | #if WCHAR_PATH_SEPARATOR != L'/' | ||
| 62 | // we convert linux slashes to windows slashes for further processing. | ||
| 63 | // also we convert linux backslashes to BackslashReplacement character. | ||
| 64 | #define REPLACE_SLASHES_from_Linux_to_Sys(s) \ | ||
| 65 | { NArchive::NItemName::ReplaceToWinSlashes(s, true); } // useBackslashReplacement | ||
| 66 | // { s.Replace(L'/', WCHAR_PATH_SEPARATOR); } | ||
| 67 | #else | ||
| 68 | #define REPLACE_SLASHES_from_Linux_to_Sys(s) | ||
| 69 | #endif | ||
| 70 | |||
| 71 | |||
| 59 | #ifndef Z7_SFX | 72 | #ifndef Z7_SFX |
| 60 | 73 | ||
| 61 | Z7_COM7F_IMF(COutStreamWithHash::Write(const void *data, UInt32 size, UInt32 *processedSize)) | 74 | Z7_COM7F_IMF(COutStreamWithHash::Write(const void *data, UInt32 size, UInt32 *processedSize)) |
| @@ -217,7 +230,7 @@ HRESULT CArchiveExtractCallback::PrepareHardLinks(const CRecordVector<UInt32> *r | |||
| 217 | if (!_arc->Ask_INode) | 230 | if (!_arc->Ask_INode) |
| 218 | return S_OK; | 231 | return S_OK; |
| 219 | 232 | ||
| 220 | IInArchive *archive = _arc->Archive; | 233 | IInArchive * const archive = _arc->Archive; |
| 221 | CRecordVector<CHardLinkNode> &hardIDs = _hardLinks.IDs; | 234 | CRecordVector<CHardLinkNode> &hardIDs = _hardLinks.IDs; |
| 222 | 235 | ||
| 223 | { | 236 | { |
| @@ -574,6 +587,13 @@ HRESULT CArchiveExtractCallback::SendMessageError2(HRESULT errorCode, const char | |||
| 574 | return _extractCallback2->MessageError(s); | 587 | return _extractCallback2->MessageError(s); |
| 575 | } | 588 | } |
| 576 | 589 | ||
| 590 | HRESULT CArchiveExtractCallback::SendMessageError2_with_LastError( | ||
| 591 | const char *message, const FString &path1, const FString &path2) | ||
| 592 | { | ||
| 593 | const HRESULT errorCode = GetLastError_noZero_HRESULT(); | ||
| 594 | return SendMessageError2(errorCode, message, path1, path2); | ||
| 595 | } | ||
| 596 | |||
| 577 | #ifndef Z7_SFX | 597 | #ifndef Z7_SFX |
| 578 | 598 | ||
| 579 | Z7_CLASS_IMP_COM_1( | 599 | Z7_CLASS_IMP_COM_1( |
| @@ -604,36 +624,20 @@ Z7_COM7F_IMF(CGetProp::GetProp(PROPID propID, PROPVARIANT *value)) | |||
| 604 | #endif // Z7_SFX | 624 | #endif // Z7_SFX |
| 605 | 625 | ||
| 606 | 626 | ||
| 607 | #ifdef SUPPORT_LINKS | ||
| 608 | |||
| 609 | static UString GetDirPrefixOf(const UString &src) | ||
| 610 | { | ||
| 611 | UString s (src); | ||
| 612 | if (!s.IsEmpty()) | ||
| 613 | { | ||
| 614 | if (IsPathSepar(s.Back())) | ||
| 615 | s.DeleteBack(); | ||
| 616 | int pos = s.ReverseFind_PathSepar(); | ||
| 617 | s.DeleteFrom((unsigned)(pos + 1)); | ||
| 618 | } | ||
| 619 | return s; | ||
| 620 | } | ||
| 621 | |||
| 622 | #endif // SUPPORT_LINKS | ||
| 623 | |||
| 624 | struct CLinkLevelsInfo | 627 | struct CLinkLevelsInfo |
| 625 | { | 628 | { |
| 626 | bool IsAbsolute; | 629 | bool IsAbsolute; |
| 627 | int LowLevel; | 630 | int LowLevel; |
| 628 | int FinalLevel; | 631 | int FinalLevel; |
| 629 | 632 | ||
| 630 | void Parse(const UString &path); | 633 | void Parse(const UString &path, bool isWSL); |
| 631 | }; | 634 | }; |
| 632 | 635 | ||
| 633 | void CLinkLevelsInfo::Parse(const UString &path) | 636 | void CLinkLevelsInfo::Parse(const UString &path, bool isWSL) |
| 634 | { | 637 | { |
| 635 | IsAbsolute = NName::IsAbsolutePath(path); | 638 | IsAbsolute = isWSL ? |
| 636 | 639 | IS_PATH_SEPAR(path[0]) : | |
| 640 | NName::IsAbsolutePath(path); | ||
| 637 | LowLevel = 0; | 641 | LowLevel = 0; |
| 638 | FinalLevel = 0; | 642 | FinalLevel = 0; |
| 639 | 643 | ||
| @@ -650,9 +654,9 @@ void CLinkLevelsInfo::Parse(const UString &path) | |||
| 650 | IsAbsolute = true; | 654 | IsAbsolute = true; |
| 651 | continue; | 655 | continue; |
| 652 | } | 656 | } |
| 653 | if (s == L".") | 657 | if (s.IsEqualTo(".")) |
| 654 | continue; | 658 | continue; |
| 655 | if (s == L"..") | 659 | if (s.IsEqualTo("..")) |
| 656 | { | 660 | { |
| 657 | level--; | 661 | level--; |
| 658 | if (LowLevel > level) | 662 | if (LowLevel > level) |
| @@ -666,16 +670,20 @@ void CLinkLevelsInfo::Parse(const UString &path) | |||
| 666 | } | 670 | } |
| 667 | 671 | ||
| 668 | 672 | ||
| 669 | bool IsSafePath(const UString &path); | 673 | static bool IsSafePath(const UString &path, bool isWSL) |
| 670 | bool IsSafePath(const UString &path) | ||
| 671 | { | 674 | { |
| 672 | CLinkLevelsInfo levelsInfo; | 675 | CLinkLevelsInfo levelsInfo; |
| 673 | levelsInfo.Parse(path); | 676 | levelsInfo.Parse(path, isWSL); |
| 674 | return !levelsInfo.IsAbsolute | 677 | return !levelsInfo.IsAbsolute |
| 675 | && levelsInfo.LowLevel >= 0 | 678 | && levelsInfo.LowLevel >= 0 |
| 676 | && levelsInfo.FinalLevel > 0; | 679 | && levelsInfo.FinalLevel > 0; |
| 677 | } | 680 | } |
| 678 | 681 | ||
| 682 | bool IsSafePath(const UString &path); | ||
| 683 | bool IsSafePath(const UString &path) | ||
| 684 | { | ||
| 685 | return IsSafePath(path, false); // isWSL | ||
| 686 | } | ||
| 679 | 687 | ||
| 680 | bool CensorNode_CheckPath2(const NWildcard::CCensorNode &node, const CReadArcItem &item, bool &include); | 688 | bool CensorNode_CheckPath2(const NWildcard::CCensorNode &node, const CReadArcItem &item, bool &include); |
| 681 | bool CensorNode_CheckPath2(const NWildcard::CCensorNode &node, const CReadArcItem &item, bool &include) | 689 | bool CensorNode_CheckPath2(const NWildcard::CCensorNode &node, const CReadArcItem &item, bool &include) |
| @@ -791,159 +799,113 @@ HRESULT CArchiveExtractCallback::MyCopyFile(ISequentialOutStream *outStream) | |||
| 791 | 799 | ||
| 792 | HRESULT CArchiveExtractCallback::ReadLink() | 800 | HRESULT CArchiveExtractCallback::ReadLink() |
| 793 | { | 801 | { |
| 794 | IInArchive *archive = _arc->Archive; | 802 | IInArchive * const archive = _arc->Archive; |
| 795 | const UInt32 index = _index; | 803 | const UInt32 index = _index; |
| 796 | _link.Clear(); | 804 | // _link.Clear(); // _link.Clear() was called already. |
| 797 | |||
| 798 | { | 805 | { |
| 799 | NCOM::CPropVariant prop; | 806 | NCOM::CPropVariant prop; |
| 800 | RINOK(archive->GetProperty(index, kpidHardLink, &prop)) | 807 | RINOK(archive->GetProperty(index, kpidHardLink, &prop)) |
| 801 | if (prop.vt == VT_BSTR) | 808 | if (prop.vt == VT_BSTR) |
| 802 | { | 809 | { |
| 803 | _link.isHardLink = true; | 810 | _link.LinkType = k_LinkType_HardLink; |
| 804 | // _link.isCopyLink = false; | ||
| 805 | _link.isRelative = false; // RAR5, TAR: hard links are from root folder of archive | 811 | _link.isRelative = false; // RAR5, TAR: hard links are from root folder of archive |
| 806 | _link.linkPath.SetFromBstr(prop.bstrVal); | 812 | _link.LinkPath.SetFromBstr(prop.bstrVal); |
| 813 | // 7-Zip 24-: tar handler returned original path (with linux slash in most case) | ||
| 814 | // 7-Zip 24-: rar5 handler returned path with system slash. | ||
| 815 | // 7-Zip 25+: tar/rar5 handlers return linux path in most cases. | ||
| 807 | } | 816 | } |
| 808 | else if (prop.vt != VT_EMPTY) | 817 | else if (prop.vt != VT_EMPTY) |
| 809 | return E_FAIL; | 818 | return E_FAIL; |
| 810 | } | 819 | } |
| 811 | |||
| 812 | /* | 820 | /* |
| 813 | { | 821 | { |
| 814 | NCOM::CPropVariant prop; | 822 | NCOM::CPropVariant prop; |
| 815 | RINOK(archive->GetProperty(index, kpidCopyLink, &prop)); | 823 | RINOK(archive->GetProperty(index, kpidCopyLink, &prop)); |
| 816 | if (prop.vt == VT_BSTR) | 824 | if (prop.vt == VT_BSTR) |
| 817 | { | 825 | { |
| 818 | _link.isHardLink = false; | 826 | _link.LinkType = k_LinkType_CopyLink; |
| 819 | _link.isCopyLink = true; | ||
| 820 | _link.isRelative = false; // RAR5: copy links are from root folder of archive | 827 | _link.isRelative = false; // RAR5: copy links are from root folder of archive |
| 821 | _link.linkPath.SetFromBstr(prop.bstrVal); | 828 | _link.LinkPath.SetFromBstr(prop.bstrVal); |
| 822 | } | 829 | } |
| 823 | else if (prop.vt != VT_EMPTY) | 830 | else if (prop.vt != VT_EMPTY) |
| 824 | return E_FAIL; | 831 | return E_FAIL; |
| 825 | } | 832 | } |
| 826 | */ | 833 | */ |
| 827 | |||
| 828 | { | 834 | { |
| 829 | NCOM::CPropVariant prop; | 835 | NCOM::CPropVariant prop; |
| 830 | RINOK(archive->GetProperty(index, kpidSymLink, &prop)) | 836 | RINOK(archive->GetProperty(index, kpidSymLink, &prop)) |
| 831 | if (prop.vt == VT_BSTR) | 837 | if (prop.vt == VT_BSTR) |
| 832 | { | 838 | { |
| 833 | _link.isHardLink = false; | 839 | _link.LinkType = k_LinkType_PureSymLink; |
| 834 | // _link.isCopyLink = false; | 840 | _link.isRelative = true; // RAR5, TAR: symbolic links are relative by default |
| 835 | _link.isRelative = true; // RAR5, TAR: symbolic links can be relative | 841 | _link.LinkPath.SetFromBstr(prop.bstrVal); |
| 836 | _link.linkPath.SetFromBstr(prop.bstrVal); | 842 | // 7-Zip 24-: (tar, cpio, xar, ext, iso) handlers returned returned original path (with linux slash in most case) |
| 843 | // 7-Zip 24-: rar5 handler returned path with system slash. | ||
| 844 | // 7-Zip 25+: all handlers return linux path in most cases. | ||
| 837 | } | 845 | } |
| 838 | else if (prop.vt != VT_EMPTY) | 846 | else if (prop.vt != VT_EMPTY) |
| 839 | return E_FAIL; | 847 | return E_FAIL; |
| 840 | } | 848 | } |
| 841 | 849 | ||
| 842 | NtReparse_Data = NULL; | 850 | // linux path separator in (_link.LinkPath) is expected for most cases, |
| 843 | NtReparse_Size = 0; | 851 | // if new handler code is used, and if data in archive is correct. |
| 844 | 852 | // NtReparse_Data = NULL; | |
| 845 | if (_link.linkPath.IsEmpty() && _arc->GetRawProps) | 853 | // NtReparse_Size = 0; |
| 854 | if (!_link.LinkPath.IsEmpty()) | ||
| 855 | { | ||
| 856 | REPLACE_SLASHES_from_Linux_to_Sys(_link.LinkPath) | ||
| 857 | } | ||
| 858 | else if (_arc->GetRawProps) | ||
| 846 | { | 859 | { |
| 847 | const void *data; | 860 | const void *data; |
| 848 | UInt32 dataSize; | 861 | UInt32 dataSize, propType; |
| 849 | UInt32 propType; | 862 | if (_arc->GetRawProps->GetRawProp(_index, kpidNtReparse, &data, &dataSize, &propType) == S_OK |
| 850 | 863 | // && dataSize == 1234567 // for debug: unpacking without reparse | |
| 851 | _arc->GetRawProps->GetRawProp(_index, kpidNtReparse, &data, &dataSize, &propType); | 864 | && dataSize) |
| 852 | |||
| 853 | // if (dataSize == 1234567) // for debug: unpacking without reparse | ||
| 854 | if (dataSize != 0) | ||
| 855 | { | 865 | { |
| 856 | if (propType != NPropDataType::kRaw) | 866 | if (propType != NPropDataType::kRaw) |
| 857 | return E_FAIL; | 867 | return E_FAIL; |
| 858 | |||
| 859 | // 21.06: we need kpidNtReparse in linux for wim archives created in Windows | 868 | // 21.06: we need kpidNtReparse in linux for wim archives created in Windows |
| 860 | // #ifdef _WIN32 | 869 | // NtReparse_Data = data; |
| 861 | 870 | // NtReparse_Size = dataSize; | |
| 862 | NtReparse_Data = data; | 871 | // we ignore error code here, if there is failure of parsing: |
| 863 | NtReparse_Size = dataSize; | 872 | _link.Parse_from_WindowsReparseData((const Byte *)data, dataSize); |
| 864 | |||
| 865 | CReparseAttr reparse; | ||
| 866 | bool isOkReparse = reparse.Parse((const Byte *)data, dataSize); | ||
| 867 | if (isOkReparse) | ||
| 868 | { | ||
| 869 | _link.isHardLink = false; | ||
| 870 | // _link.isCopyLink = false; | ||
| 871 | _link.linkPath = reparse.GetPath(); | ||
| 872 | _link.isJunction = reparse.IsMountPoint(); | ||
| 873 | |||
| 874 | if (reparse.IsSymLink_WSL()) | ||
| 875 | { | ||
| 876 | _link.isWSL = true; | ||
| 877 | _link.isRelative = reparse.IsRelative_WSL(); | ||
| 878 | } | ||
| 879 | else | ||
| 880 | _link.isRelative = reparse.IsRelative_Win(); | ||
| 881 | |||
| 882 | // const AString s = GetAnsiString(_link.linkPath); | ||
| 883 | // printf("\n_link.linkPath: %s\n", s.Ptr()); | ||
| 884 | |||
| 885 | #ifndef _WIN32 | ||
| 886 | _link.linkPath.Replace(L'\\', WCHAR_PATH_SEPARATOR); | ||
| 887 | #endif | ||
| 888 | } | ||
| 889 | // #endif | ||
| 890 | } | 873 | } |
| 891 | } | 874 | } |
| 892 | 875 | ||
| 893 | if (_link.linkPath.IsEmpty()) | 876 | if (_link.LinkPath.IsEmpty()) |
| 894 | return S_OK; | 877 | return S_OK; |
| 895 | 878 | // (_link.LinkPath) uses system path separator. | |
| 879 | // windows: (_link.LinkPath) doesn't contain linux separator (slash). | ||
| 896 | { | 880 | { |
| 897 | #ifdef _WIN32 | 881 | // _link.LinkPath = "\\??\\r:\\1\\2"; // for debug |
| 898 | _link.linkPath.Replace(L'/', WCHAR_PATH_SEPARATOR); | 882 | // rar5+ returns kpidSymLink absolute link path with "\??\" prefix. |
| 899 | #endif | 883 | // we normalize such prefix: |
| 900 | 884 | if (_link.LinkPath.IsPrefixedBy(STRING_PATH_SEPARATOR "??" STRING_PATH_SEPARATOR)) | |
| 901 | // rar5 uses "\??\" prefix for absolute links | ||
| 902 | if (_link.linkPath.IsPrefixedBy(WSTRING_PATH_SEPARATOR L"??" WSTRING_PATH_SEPARATOR)) | ||
| 903 | { | 885 | { |
| 904 | _link.isRelative = false; | 886 | _link.isRelative = false; |
| 905 | _link.linkPath.DeleteFrontal(4); | 887 | // we normalize prefix from "\??\" to "\\?\": |
| 906 | } | 888 | _link.LinkPath.ReplaceOneCharAtPos(1, WCHAR_PATH_SEPARATOR); |
| 907 | 889 | _link.isWindowsPath = true; | |
| 908 | for (;;) | 890 | if (_link.LinkPath.IsPrefixedBy_Ascii_NoCase( |
| 909 | // while (NName::IsAbsolutePath(linkPath)) | 891 | STRING_PATH_SEPARATOR |
| 910 | { | 892 | STRING_PATH_SEPARATOR "?" |
| 911 | unsigned n = NName::GetRootPrefixSize(_link.linkPath); | 893 | STRING_PATH_SEPARATOR "UNC" |
| 912 | if (n == 0) | 894 | STRING_PATH_SEPARATOR)) |
| 913 | break; | ||
| 914 | _link.isRelative = false; | ||
| 915 | _link.linkPath.DeleteFrontal(n); | ||
| 916 | } | ||
| 917 | } | ||
| 918 | |||
| 919 | if (_link.linkPath.IsEmpty()) | ||
| 920 | return S_OK; | ||
| 921 | |||
| 922 | if (!_link.isRelative && _removePathParts.Size() != 0) | ||
| 923 | { | ||
| 924 | UStringVector pathParts; | ||
| 925 | SplitPathToParts(_link.linkPath, pathParts); | ||
| 926 | bool badPrefix = false; | ||
| 927 | FOR_VECTOR (i, _removePathParts) | ||
| 928 | { | ||
| 929 | if (CompareFileNames(_removePathParts[i], pathParts[i]) != 0) | ||
| 930 | { | 895 | { |
| 931 | badPrefix = true; | 896 | // we normalize prefix from "\\?\UNC\path" to "\\path": |
| 932 | break; | 897 | _link.LinkPath.DeleteFrontal(6); |
| 898 | _link.LinkPath.ReplaceOneCharAtPos(0, WCHAR_PATH_SEPARATOR); | ||
| 899 | } | ||
| 900 | else | ||
| 901 | { | ||
| 902 | const unsigned k_prefix_Size = 4; | ||
| 903 | if (NName::IsDrivePath(_link.LinkPath.Ptr(k_prefix_Size))) | ||
| 904 | _link.LinkPath.DeleteFrontal(k_prefix_Size); | ||
| 933 | } | 905 | } |
| 934 | } | 906 | } |
| 935 | if (!badPrefix) | ||
| 936 | pathParts.DeleteFrontal(_removePathParts.Size()); | ||
| 937 | _link.linkPath = MakePathFromParts(pathParts); | ||
| 938 | } | 907 | } |
| 939 | 908 | _link.Normalize_to_RelativeSafe(_removePathParts); | |
| 940 | /* | ||
| 941 | if (!_link.linkPath.IsEmpty()) | ||
| 942 | { | ||
| 943 | printf("\n_link %s to -> %s\n", GetOemString(_item.Path).Ptr(), GetOemString(_link.linkPath).Ptr()); | ||
| 944 | } | ||
| 945 | */ | ||
| 946 | |||
| 947 | return S_OK; | 909 | return S_OK; |
| 948 | } | 910 | } |
| 949 | 911 | ||
| @@ -961,7 +923,7 @@ static HRESULT GetOwner(IInArchive *archive, | |||
| 961 | if (prop.vt == VT_UI4) | 923 | if (prop.vt == VT_UI4) |
| 962 | { | 924 | { |
| 963 | res.Id_Defined = true; | 925 | res.Id_Defined = true; |
| 964 | res.Id = prop.ulVal; // for debug | 926 | res.Id = prop.ulVal; |
| 965 | // res.Id++; // for debug | 927 | // res.Id++; // for debug |
| 966 | // if (pidId == kpidGroupId) res.Id += 7; // for debug | 928 | // if (pidId == kpidGroupId) res.Id += 7; // for debug |
| 967 | // res.Id = 0; // for debug | 929 | // res.Id = 0; // for debug |
| @@ -993,7 +955,7 @@ static HRESULT GetOwner(IInArchive *archive, | |||
| 993 | 955 | ||
| 994 | HRESULT CArchiveExtractCallback::Read_fi_Props() | 956 | HRESULT CArchiveExtractCallback::Read_fi_Props() |
| 995 | { | 957 | { |
| 996 | IInArchive *archive = _arc->Archive; | 958 | IInArchive * const archive = _arc->Archive; |
| 997 | const UInt32 index = _index; | 959 | const UInt32 index = _index; |
| 998 | 960 | ||
| 999 | _fi.Attrib_Defined = false; | 961 | _fi.Attrib_Defined = false; |
| @@ -1134,7 +1096,7 @@ void CArchiveExtractCallback::CreateFolders() | |||
| 1134 | if (!_item.IsDir | 1096 | if (!_item.IsDir |
| 1135 | #ifdef SUPPORT_LINKS | 1097 | #ifdef SUPPORT_LINKS |
| 1136 | #ifndef WIN32 | 1098 | #ifndef WIN32 |
| 1137 | || !_link.linkPath.IsEmpty() | 1099 | || !_link.LinkPath.IsEmpty() |
| 1138 | #endif | 1100 | #endif |
| 1139 | #endif | 1101 | #endif |
| 1140 | ) | 1102 | ) |
| @@ -1273,8 +1235,7 @@ HRESULT CArchiveExtractCallback::CheckExistFile(FString &fullProcessedPath, bool | |||
| 1273 | // MyMoveFile can rename folders. So it's OK to use it for folders too | 1235 | // MyMoveFile can rename folders. So it's OK to use it for folders too |
| 1274 | if (!MyMoveFile(fullProcessedPath, existPath)) | 1236 | if (!MyMoveFile(fullProcessedPath, existPath)) |
| 1275 | { | 1237 | { |
| 1276 | HRESULT errorCode = GetLastError_noZero_HRESULT(); | 1238 | RINOK(SendMessageError2_with_LastError(kCantRenameFile, existPath, fullProcessedPath)) |
| 1277 | RINOK(SendMessageError2(errorCode, kCantRenameFile, existPath, fullProcessedPath)) | ||
| 1278 | return E_FAIL; | 1239 | return E_FAIL; |
| 1279 | } | 1240 | } |
| 1280 | } | 1241 | } |
| @@ -1341,7 +1302,7 @@ HRESULT CArchiveExtractCallback::GetExtractStream(CMyComPtr<ISequentialOutStream | |||
| 1341 | RINOK(Read_fi_Props()) | 1302 | RINOK(Read_fi_Props()) |
| 1342 | 1303 | ||
| 1343 | #ifdef SUPPORT_LINKS | 1304 | #ifdef SUPPORT_LINKS |
| 1344 | IInArchive *archive = _arc->Archive; | 1305 | IInArchive * const archive = _arc->Archive; |
| 1345 | #endif | 1306 | #endif |
| 1346 | 1307 | ||
| 1347 | const UInt32 index = _index; | 1308 | const UInt32 index = _index; |
| @@ -1387,7 +1348,7 @@ HRESULT CArchiveExtractCallback::GetExtractStream(CMyComPtr<ISequentialOutStream | |||
| 1387 | if (isAnti) | 1348 | if (isAnti) |
| 1388 | RemoveDir(_diskFilePath); | 1349 | RemoveDir(_diskFilePath); |
| 1389 | #ifdef SUPPORT_LINKS | 1350 | #ifdef SUPPORT_LINKS |
| 1390 | if (_link.linkPath.IsEmpty()) | 1351 | if (_link.LinkPath.IsEmpty()) |
| 1391 | #endif | 1352 | #endif |
| 1392 | { | 1353 | { |
| 1393 | if (!isAnti) | 1354 | if (!isAnti) |
| @@ -1416,15 +1377,15 @@ HRESULT CArchiveExtractCallback::GetExtractStream(CMyComPtr<ISequentialOutStream | |||
| 1416 | 1377 | ||
| 1417 | #ifdef SUPPORT_LINKS | 1378 | #ifdef SUPPORT_LINKS |
| 1418 | 1379 | ||
| 1419 | if (!_link.linkPath.IsEmpty()) | 1380 | if (!_link.LinkPath.IsEmpty()) |
| 1420 | { | 1381 | { |
| 1421 | #ifndef UNDER_CE | 1382 | #ifndef UNDER_CE |
| 1422 | { | 1383 | { |
| 1423 | bool linkWasSet = false; | 1384 | bool linkWasSet = false; |
| 1424 | RINOK(SetFromLinkPath(fullProcessedPath, _link, linkWasSet)) | 1385 | RINOK(SetLink(fullProcessedPath, _link, linkWasSet)) |
| 1425 | if (linkWasSet) | 1386 | if (linkWasSet) |
| 1426 | { | 1387 | { |
| 1427 | _isSymLinkCreated = _link.IsSymLink(); | 1388 | _isSymLinkCreated = _link.Is_AnySymLink(); |
| 1428 | SetAttrib(); | 1389 | SetAttrib(); |
| 1429 | // printf("\nlinkWasSet %s\n", GetAnsiString(_diskFilePath)); | 1390 | // printf("\nlinkWasSet %s\n", GetAnsiString(_diskFilePath)); |
| 1430 | } | 1391 | } |
| @@ -1454,12 +1415,7 @@ HRESULT CArchiveExtractCallback::GetExtractStream(CMyComPtr<ISequentialOutStream | |||
| 1454 | else | 1415 | else |
| 1455 | { | 1416 | { |
| 1456 | if (!MyCreateHardLink(fullProcessedPath, hl)) | 1417 | if (!MyCreateHardLink(fullProcessedPath, hl)) |
| 1457 | { | 1418 | return SendMessageError2_with_LastError(kCantCreateHardLink, fullProcessedPath, hl); |
| 1458 | const HRESULT errorCode = GetLastError_noZero_HRESULT(); | ||
| 1459 | RINOK(SendMessageError2(errorCode, kCantCreateHardLink, fullProcessedPath, hl)) | ||
| 1460 | return S_OK; | ||
| 1461 | } | ||
| 1462 | |||
| 1463 | // printf("\nHard linkWasSet Archive_Get_HardLinkNode %s\n", GetAnsiString(_diskFilePath)); | 1419 | // printf("\nHard linkWasSet Archive_Get_HardLinkNode %s\n", GetAnsiString(_diskFilePath)); |
| 1464 | // _needSetAttrib = true; // do we need to set attribute ? | 1420 | // _needSetAttrib = true; // do we need to set attribute ? |
| 1465 | SetAttrib(); | 1421 | SetAttrib(); |
| @@ -1491,7 +1447,7 @@ HRESULT CArchiveExtractCallback::GetExtractStream(CMyComPtr<ISequentialOutStream | |||
| 1491 | 1447 | ||
| 1492 | bool is_SymLink_in_Data = false; | 1448 | bool is_SymLink_in_Data = false; |
| 1493 | 1449 | ||
| 1494 | if (_curSize_Defined && _curSize > 0 && _curSize < (1 << 12)) | 1450 | if (_curSize_Defined && _curSize && _curSize < k_LinkDataSize_LIMIT) |
| 1495 | { | 1451 | { |
| 1496 | if (_fi.IsLinuxSymLink()) | 1452 | if (_fi.IsLinuxSymLink()) |
| 1497 | { | 1453 | { |
| @@ -1513,7 +1469,7 @@ HRESULT CArchiveExtractCallback::GetExtractStream(CMyComPtr<ISequentialOutStream | |||
| 1513 | _bufPtrSeqOutStream_Spec->Init(_outMemBuf, _outMemBuf.Size()); | 1469 | _bufPtrSeqOutStream_Spec->Init(_outMemBuf, _outMemBuf.Size()); |
| 1514 | outStreamLoc = _bufPtrSeqOutStream; | 1470 | outStreamLoc = _bufPtrSeqOutStream; |
| 1515 | } | 1471 | } |
| 1516 | else // not reprase | 1472 | else // not reparse |
| 1517 | { | 1473 | { |
| 1518 | if (_ntOptions.PreAllocateOutFile && !_isSplit && _curSize_Defined && _curSize > (1 << 12)) | 1474 | if (_ntOptions.PreAllocateOutFile && !_isSplit && _curSize_Defined && _curSize > (1 << 12)) |
| 1519 | { | 1475 | { |
| @@ -1568,7 +1524,7 @@ HRESULT CArchiveExtractCallback::GetExtractStream(CMyComPtr<ISequentialOutStream | |||
| 1568 | RINOK(outFileStream_Loc->Seek((Int64)_position, STREAM_SEEK_SET, NULL)) | 1524 | RINOK(outFileStream_Loc->Seek((Int64)_position, STREAM_SEEK_SET, NULL)) |
| 1569 | } | 1525 | } |
| 1570 | outStreamLoc = outFileStream_Loc; | 1526 | outStreamLoc = outFileStream_Loc; |
| 1571 | } // if not reprase | 1527 | } // if not reparse |
| 1572 | 1528 | ||
| 1573 | _outFileStream = outFileStream_Loc; | 1529 | _outFileStream = outFileStream_Loc; |
| 1574 | 1530 | ||
| @@ -1620,8 +1576,7 @@ Z7_COM7F_IMF(CArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStre | |||
| 1620 | _fileLength_WasSet = false; | 1576 | _fileLength_WasSet = false; |
| 1621 | _isRenamed = false; | 1577 | _isRenamed = false; |
| 1622 | // _fi.Clear(); | 1578 | // _fi.Clear(); |
| 1623 | _extractMode = false; | 1579 | _extractMode = false; |
| 1624 | // _is_SymLink_in_Data = false; | ||
| 1625 | _is_SymLink_in_Data_Linux = false; | 1580 | _is_SymLink_in_Data_Linux = false; |
| 1626 | _needSetAttrib = false; | 1581 | _needSetAttrib = false; |
| 1627 | _isSymLinkCreated = false; | 1582 | _isSymLinkCreated = false; |
| @@ -1661,7 +1616,7 @@ Z7_COM7F_IMF(CArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStre | |||
| 1661 | } | 1616 | } |
| 1662 | 1617 | ||
| 1663 | 1618 | ||
| 1664 | IInArchive *archive = _arc->Archive; | 1619 | IInArchive * const archive = _arc->Archive; |
| 1665 | 1620 | ||
| 1666 | RINOK(GetItem(index)) | 1621 | RINOK(GetItem(index)) |
| 1667 | 1622 | ||
| @@ -1677,10 +1632,9 @@ Z7_COM7F_IMF(CArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStre | |||
| 1677 | } | 1632 | } |
| 1678 | } | 1633 | } |
| 1679 | 1634 | ||
| 1680 | #ifdef SUPPORT_LINKS | 1635 | #ifdef SUPPORT_LINKS |
| 1681 | RINOK(ReadLink()) | 1636 | RINOK(ReadLink()) |
| 1682 | #endif // SUPPORT_LINKS | 1637 | #endif |
| 1683 | |||
| 1684 | 1638 | ||
| 1685 | RINOK(Archive_GetItemBoolProp(archive, index, kpidEncrypted, _encrypted)) | 1639 | RINOK(Archive_GetItemBoolProp(archive, index, kpidEncrypted, _encrypted)) |
| 1686 | 1640 | ||
| @@ -2016,63 +1970,80 @@ HRESULT CArchiveExtractCallback::CloseFile() | |||
| 2016 | 1970 | ||
| 2017 | #ifdef SUPPORT_LINKS | 1971 | #ifdef SUPPORT_LINKS |
| 2018 | 1972 | ||
| 1973 | /* | ||
| 1974 | in: | ||
| 1975 | link.LinkPath : must be relative (non-absolute) path in any case !!! | ||
| 1976 | link.isRelative / target path that must stored as created link: | ||
| 1977 | == false / _dirPathPrefix_Full + link.LinkPath | ||
| 1978 | == true / link.LinkPath | ||
| 1979 | */ | ||
| 2019 | 1980 | ||
| 2020 | HRESULT CArchiveExtractCallback::SetFromLinkPath( | 1981 | HRESULT CArchiveExtractCallback::SetLink( |
| 2021 | const FString &fullProcessedPath, | 1982 | const FString &fullProcessedPath_from, |
| 2022 | const CLinkInfo &linkInfo, | 1983 | const CLinkInfo &link, |
| 2023 | bool &linkWasSet) | 1984 | bool &linkWasSet) |
| 2024 | { | 1985 | { |
| 2025 | linkWasSet = false; | 1986 | linkWasSet = false; |
| 2026 | if (!_ntOptions.SymLinks.Val && !linkInfo.isHardLink) | 1987 | if (link.LinkPath.IsEmpty()) |
| 1988 | return S_OK; | ||
| 1989 | if (!_ntOptions.SymLinks.Val && link.Is_AnySymLink()) | ||
| 2027 | return S_OK; | 1990 | return S_OK; |
| 2028 | |||
| 2029 | UString relatPath; | ||
| 2030 | |||
| 2031 | /* if (linkInfo.isRelative) | ||
| 2032 | linkInfo.linkPath is final link path that must be stored to file link field | ||
| 2033 | else | ||
| 2034 | linkInfo.linkPath is path from root of archive. So we must add _dirPathPrefix_Full before linkPath. | ||
| 2035 | */ | ||
| 2036 | |||
| 2037 | if (linkInfo.isRelative) | ||
| 2038 | relatPath = GetDirPrefixOf(_item.Path); | ||
| 2039 | relatPath += linkInfo.linkPath; | ||
| 2040 | |||
| 2041 | if (!IsSafePath(relatPath)) | ||
| 2042 | { | 1991 | { |
| 2043 | return SendMessageError2( | 1992 | UString path; |
| 2044 | 0, // errorCode | 1993 | if (link.isRelative) |
| 1994 | { | ||
| 1995 | // _item.PathParts : parts that will be created in output folder. | ||
| 1996 | // we want to get directory prefix of link item. | ||
| 1997 | // so we remove file name (last non-empty part) from PathParts: | ||
| 1998 | UStringVector v = _item.PathParts; | ||
| 1999 | while (!v.IsEmpty()) | ||
| 2000 | { | ||
| 2001 | const unsigned len = v.Back().Len(); | ||
| 2002 | v.DeleteBack(); | ||
| 2003 | if (len) | ||
| 2004 | break; | ||
| 2005 | } | ||
| 2006 | path = MakePathFromParts(v); | ||
| 2007 | NName::NormalizeDirPathPrefix(path); | ||
| 2008 | } | ||
| 2009 | path += link.LinkPath; | ||
| 2010 | /* | ||
| 2011 | path is calculated virtual target path of link | ||
| 2012 | path is relative to root folder of extracted items | ||
| 2013 | if (!link.isRelative), then (path == link.LinkPath) | ||
| 2014 | */ | ||
| 2015 | if (!IsSafePath(path, link.Is_WSL())) | ||
| 2016 | return SendMessageError2(0, // errorCode | ||
| 2045 | "Dangerous link path was ignored", | 2017 | "Dangerous link path was ignored", |
| 2046 | us2fs(_item.Path), | 2018 | us2fs(_item.Path), us2fs(link.LinkPath)); |
| 2047 | us2fs(linkInfo.linkPath)); // us2fs(relatPath) | ||
| 2048 | } | 2019 | } |
| 2049 | 2020 | ||
| 2050 | FString existPath; | 2021 | FString target; // target path that will be stored to link field |
| 2051 | if (linkInfo.isHardLink /* || linkInfo.IsCopyLink */ || !linkInfo.isRelative) | 2022 | if (link.Is_HardLink() /* || link.IsCopyLink */ || !link.isRelative) |
| 2052 | { | 2023 | { |
| 2053 | if (!NName::GetFullPath(_dirPathPrefix_Full, us2fs(relatPath), existPath)) | 2024 | // isRelative == false |
| 2054 | { | 2025 | // all hard links and absolute symbolic links |
| 2055 | RINOK(SendMessageError("Incorrect path", us2fs(relatPath))) | 2026 | // relatPath == link.LinkPath |
| 2056 | } | 2027 | // we get absolute link path for target: |
| 2028 | if (!NName::GetFullPath(_dirPathPrefix_Full, us2fs(link.LinkPath), target)) | ||
| 2029 | return SendMessageError("Incorrect link path", us2fs(link.LinkPath)); | ||
| 2030 | // (target) is (_dirPathPrefix_Full + relatPath) | ||
| 2057 | } | 2031 | } |
| 2058 | else | 2032 | else |
| 2059 | { | 2033 | { |
| 2060 | existPath = us2fs(linkInfo.linkPath); | 2034 | // link.isRelative == true |
| 2061 | // printf("\nlinkPath = : %s\n", GetOemString(linkInfo.linkPath).Ptr()); | 2035 | // relative symbolic links only |
| 2036 | target = us2fs(link.LinkPath); | ||
| 2062 | } | 2037 | } |
| 2063 | 2038 | if (target.IsEmpty()) | |
| 2064 | if (existPath.IsEmpty()) | 2039 | return SendMessageError("Empty link", fullProcessedPath_from); |
| 2065 | return SendMessageError("Empty link", fullProcessedPath); | ||
| 2066 | 2040 | ||
| 2067 | if (linkInfo.isHardLink /* || linkInfo.IsCopyLink */) | 2041 | if (link.Is_HardLink() /* || link.IsCopyLink */) |
| 2068 | { | 2042 | { |
| 2069 | // if (linkInfo.isHardLink) | 2043 | // if (link.isHardLink) |
| 2070 | { | 2044 | { |
| 2071 | if (!MyCreateHardLink(fullProcessedPath, existPath)) | 2045 | if (!MyCreateHardLink(fullProcessedPath_from, target)) |
| 2072 | { | 2046 | return SendMessageError2_with_LastError(kCantCreateHardLink, fullProcessedPath_from, target); |
| 2073 | const HRESULT errorCode = GetLastError_noZero_HRESULT(); | ||
| 2074 | RINOK(SendMessageError2(errorCode, kCantCreateHardLink, fullProcessedPath, existPath)) | ||
| 2075 | } | ||
| 2076 | /* | 2047 | /* |
| 2077 | RINOK(PrepareOperation(NArchive::NExtract::NAskMode::kExtract)) | 2048 | RINOK(PrepareOperation(NArchive::NExtract::NAskMode::kExtract)) |
| 2078 | _op_WasReported = true; | 2049 | _op_WasReported = true; |
| @@ -2085,19 +2056,19 @@ HRESULT CArchiveExtractCallback::SetFromLinkPath( | |||
| 2085 | // IsCopyLink | 2056 | // IsCopyLink |
| 2086 | { | 2057 | { |
| 2087 | NFind::CFileInfo fi; | 2058 | NFind::CFileInfo fi; |
| 2088 | if (!fi.Find(existPath)) | 2059 | if (!fi.Find(target)) |
| 2089 | { | 2060 | { |
| 2090 | RINOK(SendMessageError2("Cannot find the file for copying", existPath, fullProcessedPath)); | 2061 | RINOK(SendMessageError2("Cannot find the file for copying", target, fullProcessedPath)); |
| 2091 | } | 2062 | } |
| 2092 | else | 2063 | else |
| 2093 | { | 2064 | { |
| 2094 | if (_curSize_Defined && _curSize == fi.Size) | 2065 | if (_curSize_Defined && _curSize == fi.Size) |
| 2095 | _copyFile_Path = existPath; | 2066 | _copyFile_Path = target; |
| 2096 | else | 2067 | else |
| 2097 | { | 2068 | { |
| 2098 | RINOK(SendMessageError2("File size collision for file copying", existPath, fullProcessedPath)); | 2069 | RINOK(SendMessageError2("File size collision for file copying", target, fullProcessedPath)); |
| 2099 | } | 2070 | } |
| 2100 | // RINOK(MyCopyFile(existPath, fullProcessedPath)); | 2071 | // RINOK(MyCopyFile(target, fullProcessedPath)); |
| 2101 | } | 2072 | } |
| 2102 | } | 2073 | } |
| 2103 | */ | 2074 | */ |
| @@ -2111,127 +2082,249 @@ HRESULT CArchiveExtractCallback::SetFromLinkPath( | |||
| 2111 | // Windows before Vista doesn't support symbolic links. | 2082 | // Windows before Vista doesn't support symbolic links. |
| 2112 | // we could convert such symbolic links to Junction Points | 2083 | // we could convert such symbolic links to Junction Points |
| 2113 | // isJunction = true; | 2084 | // isJunction = true; |
| 2114 | // convertToAbs = true; | ||
| 2115 | } | 2085 | } |
| 2116 | */ | 2086 | */ |
| 2117 | 2087 | ||
| 2118 | if (!_ntOptions.SymLinks_AllowDangerous.Val) | 2088 | #ifdef _WIN32 |
| 2089 | const bool isDir = (_item.IsDir || link.LinkType == k_LinkType_Junction); | ||
| 2090 | #endif | ||
| 2091 | |||
| 2092 | if (!_ntOptions.SymLinks_AllowDangerous.Val && link.isRelative) | ||
| 2119 | { | 2093 | { |
| 2120 | #ifdef _WIN32 | 2094 | /* |
| 2121 | if (_item.IsDir) | 2095 | We want to use additional check for links that can link to directory. |
| 2122 | #endif | 2096 | - linux: all symbolic links are files. |
| 2123 | if (linkInfo.isRelative) | 2097 | - windows: we can have file/directory symbolic link, |
| 2124 | { | 2098 | but file symbolic link works like directory link in windows. |
| 2125 | CLinkLevelsInfo levelsInfo; | 2099 | So we use additional check for all relative links. |
| 2126 | levelsInfo.Parse(linkInfo.linkPath); | 2100 | |
| 2127 | if (levelsInfo.FinalLevel < 1 || levelsInfo.IsAbsolute) | 2101 | We don't allow decreasing of final level of link. |
| 2128 | { | 2102 | So if some another extracted file will use this link, |
| 2129 | return SendMessageError2( | 2103 | then number of real path parts (after link redirection) cannot be |
| 2130 | 0, // errorCode | 2104 | smaller than number of requested path parts from archive records. |
| 2131 | "Dangerous symbolic link path was ignored", | 2105 | |
| 2132 | us2fs(_item.Path), | 2106 | Now we check only (link.LinkPath) without (_item.PathParts). |
| 2133 | us2fs(linkInfo.linkPath)); | 2107 | */ |
| 2134 | } | 2108 | CLinkLevelsInfo levelsInfo; |
| 2135 | } | 2109 | levelsInfo.Parse(link.LinkPath, link.Is_WSL()); |
| 2110 | if (levelsInfo.FinalLevel < 1 | ||
| 2111 | // || levelsInfo.LowLevel < 0 // we allow negative temporary levels | ||
| 2112 | || levelsInfo.IsAbsolute) | ||
| 2113 | return SendMessageError2(0, // errorCode | ||
| 2114 | "Dangerous symbolic link path was ignored", | ||
| 2115 | us2fs(_item.Path), us2fs(link.LinkPath)); | ||
| 2136 | } | 2116 | } |
| 2137 | 2117 | ||
| 2138 | 2118 | ||
| 2139 | #ifdef _WIN32 | 2119 | #ifdef _WIN32 |
| 2140 | |||
| 2141 | CByteBuffer data; | 2120 | CByteBuffer data; |
| 2142 | // printf("\nFillLinkData(): %s\n", GetOemString(existPath).Ptr()); | 2121 | // printf("\nFillLinkData(): %s\n", GetOemString(target).Ptr()); |
| 2143 | if (!FillLinkData(data, fs2us(existPath), !linkInfo.isJunction, linkInfo.isWSL)) | 2122 | if (link.Is_WSL()) |
| 2123 | { | ||
| 2124 | Convert_WinPath_to_WslLinuxPath(target, !link.isRelative); | ||
| 2125 | FillLinkData_WslLink(data, fs2us(target)); | ||
| 2126 | } | ||
| 2127 | else | ||
| 2128 | FillLinkData_WinLink(data, fs2us(target), link.LinkType != k_LinkType_Junction); | ||
| 2129 | if (data.Size() == 0) | ||
| 2144 | return SendMessageError("Cannot fill link data", us2fs(_item.Path)); | 2130 | return SendMessageError("Cannot fill link data", us2fs(_item.Path)); |
| 2145 | |||
| 2146 | /* | 2131 | /* |
| 2147 | if (NtReparse_Size != data.Size() || memcmp(NtReparse_Data, data, data.Size()) != 0) | 2132 | if (NtReparse_Size != data.Size() || memcmp(NtReparse_Data, data, data.Size()) != 0) |
| 2148 | { | 2133 | SendMessageError("reconstructed Reparse is different", fs2us(target)); |
| 2149 | SendMessageError("reconstructed Reparse is different", fs2us(existPath)); | ||
| 2150 | } | ||
| 2151 | */ | 2134 | */ |
| 2152 | |||
| 2153 | CReparseAttr attr; | ||
| 2154 | if (!attr.Parse(data, data.Size())) | ||
| 2155 | { | 2135 | { |
| 2156 | RINOK(SendMessageError("Internal error for symbolic link file", us2fs(_item.Path))) | 2136 | // we check that reparse data is correct, but we ignore attr.MinorError. |
| 2157 | return S_OK; | 2137 | CReparseAttr attr; |
| 2138 | if (!attr.Parse(data, data.Size())) | ||
| 2139 | return SendMessageError("Internal error for symbolic link file", us2fs(_item.Path)); | ||
| 2158 | } | 2140 | } |
| 2159 | if (!NFile::NIO::SetReparseData(fullProcessedPath, _item.IsDir, data, (DWORD)data.Size())) | 2141 | if (!NFile::NIO::SetReparseData(fullProcessedPath_from, isDir, data, (DWORD)data.Size())) |
| 2142 | #else // ! _WIN32 | ||
| 2143 | if (!NFile::NIO::SetSymLink(fullProcessedPath_from, target)) | ||
| 2144 | #endif // ! _WIN32 | ||
| 2160 | { | 2145 | { |
| 2161 | RINOK(SendMessageError_with_LastError(kCantCreateSymLink, fullProcessedPath)) | 2146 | return SendMessageError_with_LastError(kCantCreateSymLink, fullProcessedPath_from); |
| 2162 | return S_OK; | ||
| 2163 | } | 2147 | } |
| 2164 | linkWasSet = true; | 2148 | linkWasSet = true; |
| 2165 | |||
| 2166 | return S_OK; | 2149 | return S_OK; |
| 2167 | 2150 | } | |
| 2168 | 2151 | ||
| 2169 | #else // ! _WIN32 | 2152 | |
| 2170 | 2153 | ||
| 2171 | if (!NFile::NIO::SetSymLink(fullProcessedPath, existPath)) | 2154 | bool CLinkInfo::Parse_from_WindowsReparseData(const Byte *data, size_t dataSize) |
| 2155 | { | ||
| 2156 | CReparseAttr reparse; | ||
| 2157 | if (!reparse.Parse(data, dataSize)) | ||
| 2158 | return false; | ||
| 2159 | // const AString s = GetAnsiString(LinkPath); | ||
| 2160 | // printf("\nlinkPath: %s\n", s.Ptr()); | ||
| 2161 | LinkPath = reparse.GetPath(); | ||
| 2162 | if (reparse.IsSymLink_WSL()) | ||
| 2172 | { | 2163 | { |
| 2173 | RINOK(SendMessageError_with_LastError(kCantCreateSymLink, fullProcessedPath)) | 2164 | LinkType = k_LinkType_WSL; |
| 2174 | return S_OK; | 2165 | isRelative = reparse.IsRelative_WSL(); // detected from LinkPath[0] |
| 2166 | // LinkPath is original raw name converted to UString from AString | ||
| 2167 | // Linux separator '/' is expected here. | ||
| 2168 | REPLACE_SLASHES_from_Linux_to_Sys(LinkPath) | ||
| 2175 | } | 2169 | } |
| 2176 | linkWasSet = true; | 2170 | else |
| 2171 | { | ||
| 2172 | LinkType = reparse.IsMountPoint() ? k_LinkType_Junction : k_LinkType_PureSymLink; | ||
| 2173 | isRelative = reparse.IsRelative_Win(); // detected by (Flags == Z7_WIN_SYMLINK_FLAG_RELATIVE) | ||
| 2174 | isWindowsPath = true; | ||
| 2175 | // LinkPath is original windows link path from raparse data with \??\ prefix removed. | ||
| 2176 | // windows '\\' separator is expected here. | ||
| 2177 | // linux '/' separator is not expected here. | ||
| 2178 | // we translate both types of separators to system separator. | ||
| 2179 | LinkPath.Replace( | ||
| 2180 | #if WCHAR_PATH_SEPARATOR == L'\\' | ||
| 2181 | L'/' | ||
| 2182 | #else | ||
| 2183 | L'\\' | ||
| 2184 | #endif | ||
| 2185 | , WCHAR_PATH_SEPARATOR); | ||
| 2186 | } | ||
| 2187 | // (LinkPath) uses system path separator. | ||
| 2188 | // windows: (LinkPath) doesn't contain linux separator (slash). | ||
| 2189 | return true; | ||
| 2190 | } | ||
| 2177 | 2191 | ||
| 2178 | return S_OK; | ||
| 2179 | 2192 | ||
| 2180 | #endif // ! _WIN32 | 2193 | bool CLinkInfo::Parse_from_LinuxData(const Byte *data, size_t dataSize) |
| 2194 | { | ||
| 2195 | // Clear(); // *this object was cleared by constructor already. | ||
| 2196 | LinkType = k_LinkType_PureSymLink; | ||
| 2197 | AString utf; | ||
| 2198 | if (dataSize >= k_LinkDataSize_LIMIT) | ||
| 2199 | return false; | ||
| 2200 | utf.SetFrom_CalcLen((const char *)data, (unsigned)dataSize); | ||
| 2201 | UString u; | ||
| 2202 | if (!ConvertUTF8ToUnicode(utf, u)) | ||
| 2203 | return false; | ||
| 2204 | if (u.IsEmpty()) | ||
| 2205 | return false; | ||
| 2206 | const wchar_t c = u[0]; | ||
| 2207 | isRelative = (c != L'/'); | ||
| 2208 | // linux path separator is expected | ||
| 2209 | REPLACE_SLASHES_from_Linux_to_Sys(u) | ||
| 2210 | LinkPath = u; | ||
| 2211 | // (LinkPath) uses system path separator. | ||
| 2212 | // windows: (LinkPath) doesn't contain linux separator (slash). | ||
| 2213 | return true; | ||
| 2214 | } | ||
| 2215 | |||
| 2216 | |||
| 2217 | // in/out: (LinkPath) uses system path separator | ||
| 2218 | // in/out: windows: (LinkPath) doesn't contain linux separator (slash). | ||
| 2219 | // out: (LinkPath) is relative path, and LinkPath[0] is not path separator | ||
| 2220 | // out: isRelative changed to false, if any prefix was removed. | ||
| 2221 | // note: absolute windows links "c:\" to root will be reduced to empty string: | ||
| 2222 | void CLinkInfo::Remove_AbsPathPrefixes() | ||
| 2223 | { | ||
| 2224 | while (!LinkPath.IsEmpty()) | ||
| 2225 | { | ||
| 2226 | unsigned n = 0; | ||
| 2227 | if (!Is_WSL()) | ||
| 2228 | { | ||
| 2229 | n = | ||
| 2230 | #ifndef _WIN32 | ||
| 2231 | isWindowsPath ? | ||
| 2232 | NName::GetRootPrefixSize_WINDOWS(LinkPath) : | ||
| 2233 | #endif | ||
| 2234 | NName::GetRootPrefixSize(LinkPath); | ||
| 2235 | /* | ||
| 2236 | // "c:path" will be ignored later as "Dangerous absolute path" | ||
| 2237 | // so check is not required | ||
| 2238 | if (n == 0 | ||
| 2239 | #ifndef _WIN32 | ||
| 2240 | && isWindowsPath | ||
| 2241 | #endif | ||
| 2242 | && NName::IsDrivePath2(LinkPath)) | ||
| 2243 | n = 2; | ||
| 2244 | */ | ||
| 2245 | } | ||
| 2246 | if (n == 0) | ||
| 2247 | { | ||
| 2248 | if (!IS_PATH_SEPAR(LinkPath[0])) | ||
| 2249 | break; | ||
| 2250 | n = 1; | ||
| 2251 | } | ||
| 2252 | isRelative = false; // (LinkPath) will be treated as relative to root folder of archive | ||
| 2253 | LinkPath.DeleteFrontal(n); | ||
| 2254 | } | ||
| 2181 | } | 2255 | } |
| 2182 | 2256 | ||
| 2183 | 2257 | ||
| 2184 | bool CLinkInfo::Parse(const Byte *data, size_t dataSize, bool isLinuxData) | 2258 | /* |
| 2259 | it removes redundant separators, if there are double separators, | ||
| 2260 | but it keeps double separators at start of string //name/. | ||
| 2261 | in/out: system path separator is used | ||
| 2262 | windows: slash character (linux separator) is not treated as separator | ||
| 2263 | windows: (path) doesn't contain linux separator (slash). | ||
| 2264 | */ | ||
| 2265 | static void RemoveRedundantPathSeparators(UString &path) | ||
| 2185 | { | 2266 | { |
| 2186 | Clear(); | 2267 | wchar_t *dest = path.GetBuf(); |
| 2187 | // this->isLinux = isLinuxData; | 2268 | const wchar_t * const start = dest; |
| 2188 | 2269 | const wchar_t *src = dest; | |
| 2189 | if (isLinuxData) | 2270 | for (;;) |
| 2190 | { | 2271 | { |
| 2191 | isJunction = false; | 2272 | wchar_t c = *src++; |
| 2192 | isHardLink = false; | 2273 | if (c == 0) |
| 2193 | AString utf; | 2274 | break; |
| 2194 | if (dataSize >= (1 << 12)) | 2275 | // if (IS_PATH_SEPAR(c)) // for Windows: we can change (/) to (\). |
| 2195 | return false; | 2276 | if (c == WCHAR_PATH_SEPARATOR) |
| 2196 | utf.SetFrom_CalcLen((const char *)data, (unsigned)dataSize); | 2277 | { |
| 2197 | UString u; | 2278 | if (dest - start >= 2 && dest[-1] == WCHAR_PATH_SEPARATOR) |
| 2198 | if (!ConvertUTF8ToUnicode(utf, u)) | 2279 | continue; |
| 2199 | return false; | 2280 | // c = WCHAR_PATH_SEPARATOR; // for Windows: we can change (/) to (\). |
| 2200 | linkPath = u; | 2281 | } |
| 2201 | 2282 | *dest++ = c; | |
| 2202 | // in linux symbolic data: we expect that linux separator '/' is used | ||
| 2203 | // if windows link was created, then we also must use linux separator | ||
| 2204 | if (u.IsEmpty()) | ||
| 2205 | return false; | ||
| 2206 | const wchar_t c = u[0]; | ||
| 2207 | isRelative = !IS_PATH_SEPAR(c); | ||
| 2208 | return true; | ||
| 2209 | } | 2283 | } |
| 2284 | *dest = 0; | ||
| 2285 | path.ReleaseBuf_SetLen((unsigned)(dest - path.Ptr())); | ||
| 2286 | } | ||
| 2210 | 2287 | ||
| 2211 | CReparseAttr reparse; | 2288 | |
| 2212 | if (!reparse.Parse(data, dataSize)) | 2289 | // in/out: (LinkPath) uses system path separator |
| 2213 | return false; | 2290 | // in/out: windows: (LinkPath) doesn't contain linux separator (slash). |
| 2214 | isHardLink = false; | 2291 | // out: (LinkPath) is relative path, and LinkPath[0] is not path separator |
| 2215 | // isCopyLink = false; | 2292 | void CLinkInfo::Normalize_to_RelativeSafe(UStringVector &removePathParts) |
| 2216 | linkPath = reparse.GetPath(); | 2293 | { |
| 2217 | isJunction = reparse.IsMountPoint(); | 2294 | // We WILL NOT WRITE original absolute link path from archive to filesystem. |
| 2218 | 2295 | // So here we remove all root prefixes from (LinkPath). | |
| 2219 | if (reparse.IsSymLink_WSL()) | 2296 | // If we see any absolute root prefix, then we suppose that this prefix is virtual prefix |
| 2297 | // that shows that link is relative to root folder of archive | ||
| 2298 | RemoveRedundantPathSeparators(LinkPath); | ||
| 2299 | // LinkPath = "\\\\?\\r:test\\test2"; // for debug | ||
| 2300 | Remove_AbsPathPrefixes(); | ||
| 2301 | // (LinkPath) now is relative: | ||
| 2302 | // if (isRelative == false), then (LinkPath) is relative to root folder of archive | ||
| 2303 | // if (isRelative == true ), then (LinkPath) is relative to current item | ||
| 2304 | if (LinkPath.IsEmpty() || isRelative || removePathParts.Size() == 0) | ||
| 2305 | return; | ||
| 2306 | |||
| 2307 | // if LinkPath is prefixed by _removePathParts, we remove these paths | ||
| 2308 | UStringVector pathParts; | ||
| 2309 | SplitPathToParts(LinkPath, pathParts); | ||
| 2310 | bool badPrefix = false; | ||
| 2220 | { | 2311 | { |
| 2221 | isWSL = true; | 2312 | FOR_VECTOR (i, removePathParts) |
| 2222 | isRelative = reparse.IsRelative_WSL(); | 2313 | { |
| 2314 | if (i >= pathParts.Size() | ||
| 2315 | || CompareFileNames(removePathParts[i], pathParts[i]) != 0) | ||
| 2316 | { | ||
| 2317 | badPrefix = true; | ||
| 2318 | break; | ||
| 2319 | } | ||
| 2320 | } | ||
| 2223 | } | 2321 | } |
| 2224 | else | 2322 | if (!badPrefix) |
| 2225 | isRelative = reparse.IsRelative_Win(); | 2323 | pathParts.DeleteFrontal(removePathParts.Size()); |
| 2226 | 2324 | LinkPath = MakePathFromParts(pathParts); | |
| 2227 | // FIXME !!! | 2325 | Remove_AbsPathPrefixes(); |
| 2228 | #ifndef _WIN32 | ||
| 2229 | linkPath.Replace(L'\\', WCHAR_PATH_SEPARATOR); | ||
| 2230 | #endif | ||
| 2231 | |||
| 2232 | return true; | ||
| 2233 | } | 2326 | } |
| 2234 | 2327 | ||
| 2235 | #endif // SUPPORT_LINKS | 2328 | #endif // SUPPORT_LINKS |
| 2236 | 2329 | ||
| 2237 | 2330 | ||
| @@ -2239,12 +2332,12 @@ HRESULT CArchiveExtractCallback::CloseReparseAndFile() | |||
| 2239 | { | 2332 | { |
| 2240 | HRESULT res = S_OK; | 2333 | HRESULT res = S_OK; |
| 2241 | 2334 | ||
| 2242 | #ifdef SUPPORT_LINKS | 2335 | #ifdef SUPPORT_LINKS |
| 2243 | 2336 | ||
| 2244 | size_t reparseSize = 0; | 2337 | size_t reparseSize = 0; |
| 2245 | bool repraseMode = false; | 2338 | bool repraseMode = false; |
| 2246 | bool needSetReparse = false; | 2339 | bool needSetReparse = false; |
| 2247 | CLinkInfo linkInfo; | 2340 | CLinkInfo link; |
| 2248 | 2341 | ||
| 2249 | if (_bufPtrSeqOutStream) | 2342 | if (_bufPtrSeqOutStream) |
| 2250 | { | 2343 | { |
| @@ -2258,15 +2351,19 @@ HRESULT CArchiveExtractCallback::CloseReparseAndFile() | |||
| 2258 | needSetReparse = reparse.Parse(_outMemBuf, reparseSize, errorCode); | 2351 | needSetReparse = reparse.Parse(_outMemBuf, reparseSize, errorCode); |
| 2259 | if (needSetReparse) | 2352 | if (needSetReparse) |
| 2260 | { | 2353 | { |
| 2261 | UString linkPath = reparse.GetPath(); | 2354 | UString LinkPath = reparse.GetPath(); |
| 2262 | #ifndef _WIN32 | 2355 | #ifndef _WIN32 |
| 2263 | linkPath.Replace(L'\\', WCHAR_PATH_SEPARATOR); | 2356 | LinkPath.Replace(L'\\', WCHAR_PATH_SEPARATOR); |
| 2264 | #endif | 2357 | #endif |
| 2265 | } | 2358 | } |
| 2266 | */ | 2359 | */ |
| 2267 | needSetReparse = linkInfo.Parse(_outMemBuf, reparseSize, _is_SymLink_in_Data_Linux); | 2360 | needSetReparse = _is_SymLink_in_Data_Linux ? |
| 2361 | link.Parse_from_LinuxData(_outMemBuf, reparseSize) : | ||
| 2362 | link.Parse_from_WindowsReparseData(_outMemBuf, reparseSize); | ||
| 2268 | if (!needSetReparse) | 2363 | if (!needSetReparse) |
| 2269 | res = SendMessageError_with_LastError("Incorrect reparse stream", us2fs(_item.Path)); | 2364 | res = SendMessageError_with_LastError("Incorrect reparse stream", us2fs(_item.Path)); |
| 2365 | // (link.LinkPath) uses system path separator. | ||
| 2366 | // windows: (link.LinkPath) doesn't contain linux separator (slash). | ||
| 2270 | } | 2367 | } |
| 2271 | else | 2368 | else |
| 2272 | { | 2369 | { |
| @@ -2281,23 +2378,18 @@ HRESULT CArchiveExtractCallback::CloseReparseAndFile() | |||
| 2281 | _bufPtrSeqOutStream.Release(); | 2378 | _bufPtrSeqOutStream.Release(); |
| 2282 | } | 2379 | } |
| 2283 | 2380 | ||
| 2284 | #endif // SUPPORT_LINKS | 2381 | #endif // SUPPORT_LINKS |
| 2285 | |||
| 2286 | 2382 | ||
| 2287 | const HRESULT res2 = CloseFile(); | 2383 | const HRESULT res2 = CloseFile(); |
| 2288 | |||
| 2289 | if (res == S_OK) | 2384 | if (res == S_OK) |
| 2290 | res = res2; | 2385 | res = res2; |
| 2291 | |||
| 2292 | RINOK(res) | 2386 | RINOK(res) |
| 2293 | 2387 | ||
| 2294 | #ifdef SUPPORT_LINKS | 2388 | #ifdef SUPPORT_LINKS |
| 2295 | if (repraseMode) | 2389 | if (repraseMode) |
| 2296 | { | 2390 | { |
| 2297 | _curSize = reparseSize; | 2391 | _curSize = reparseSize; |
| 2298 | _curSize_Defined = true; | 2392 | _curSize_Defined = true; |
| 2299 | |||
| 2300 | #ifdef SUPPORT_LINKS | ||
| 2301 | if (needSetReparse) | 2393 | if (needSetReparse) |
| 2302 | { | 2394 | { |
| 2303 | // in Linux : we must delete empty file before symbolic link creation | 2395 | // in Linux : we must delete empty file before symbolic link creation |
| @@ -2307,31 +2399,19 @@ HRESULT CArchiveExtractCallback::CloseReparseAndFile() | |||
| 2307 | RINOK(SendMessageError_with_LastError("can't delete file", _diskFilePath)) | 2399 | RINOK(SendMessageError_with_LastError("can't delete file", _diskFilePath)) |
| 2308 | } | 2400 | } |
| 2309 | { | 2401 | { |
| 2310 | /* | ||
| 2311 | // for DEBUG ONLY: we can extract sym links as WSL links | ||
| 2312 | // to eliminate (non-admin) errors for sym links. | ||
| 2313 | #ifdef _WIN32 | ||
| 2314 | if (!linkInfo.isHardLink && !linkInfo.isJunction) | ||
| 2315 | linkInfo.isWSL = true; | ||
| 2316 | #endif | ||
| 2317 | */ | ||
| 2318 | bool linkWasSet = false; | 2402 | bool linkWasSet = false; |
| 2319 | RINOK(SetFromLinkPath(_diskFilePath, linkInfo, linkWasSet)) | 2403 | // link.LinkPath = "r:\\1\\2"; // for debug |
| 2404 | // link.isJunction = true; // for debug | ||
| 2405 | link.Normalize_to_RelativeSafe(_removePathParts); | ||
| 2406 | RINOK(SetLink(_diskFilePath, link, linkWasSet)) | ||
| 2320 | if (linkWasSet) | 2407 | if (linkWasSet) |
| 2321 | _isSymLinkCreated = linkInfo.IsSymLink(); | 2408 | _isSymLinkCreated = true; // link.IsSymLink(); |
| 2322 | else | 2409 | else |
| 2323 | _needSetAttrib = false; | 2410 | _needSetAttrib = false; |
| 2324 | } | 2411 | } |
| 2325 | /* | ||
| 2326 | if (!NFile::NIO::SetReparseData(_diskFilePath, _item.IsDir, )) | ||
| 2327 | { | ||
| 2328 | res = SendMessageError_with_LastError(kCantCreateSymLink, _diskFilePath); | ||
| 2329 | } | ||
| 2330 | */ | ||
| 2331 | } | 2412 | } |
| 2332 | #endif | ||
| 2333 | } | 2413 | } |
| 2334 | #endif | 2414 | #endif // SUPPORT_LINKS |
| 2335 | return res; | 2415 | return res; |
| 2336 | } | 2416 | } |
| 2337 | 2417 | ||
diff --git a/CPP/7zip/UI/Common/ArchiveExtractCallback.h b/CPP/7zip/UI/Common/ArchiveExtractCallback.h index f3ee01c..71fa3ef 100644 --- a/CPP/7zip/UI/Common/ArchiveExtractCallback.h +++ b/CPP/7zip/UI/Common/ArchiveExtractCallback.h | |||
| @@ -178,36 +178,50 @@ struct CDirPathTime: public CFiTimesCAM | |||
| 178 | 178 | ||
| 179 | #ifdef SUPPORT_LINKS | 179 | #ifdef SUPPORT_LINKS |
| 180 | 180 | ||
| 181 | |||
| 182 | enum ELinkType | ||
| 183 | { | ||
| 184 | k_LinkType_HardLink, | ||
| 185 | k_LinkType_PureSymLink, | ||
| 186 | k_LinkType_Junction, | ||
| 187 | k_LinkType_WSL | ||
| 188 | // , k_LinkType_CopyLink; | ||
| 189 | }; | ||
| 190 | |||
| 191 | |||
| 181 | struct CLinkInfo | 192 | struct CLinkInfo |
| 182 | { | 193 | { |
| 183 | // bool isCopyLink; | 194 | ELinkType LinkType; |
| 184 | bool isHardLink; | ||
| 185 | bool isJunction; | ||
| 186 | bool isRelative; | 195 | bool isRelative; |
| 187 | bool isWSL; | 196 | // if (isRelative == false), then (LinkPath) is relative to root folder of archive |
| 188 | UString linkPath; | 197 | // if (isRelative == true ), then (LinkPath) is relative to current item |
| 198 | bool isWindowsPath; | ||
| 199 | UString LinkPath; | ||
| 200 | |||
| 201 | bool Is_HardLink() const { return LinkType == k_LinkType_HardLink; } | ||
| 202 | bool Is_AnySymLink() const { return LinkType != k_LinkType_HardLink; } | ||
| 189 | 203 | ||
| 190 | bool IsSymLink() const { return !isHardLink; } | 204 | bool Is_WSL() const { return LinkType == k_LinkType_WSL; } |
| 191 | 205 | ||
| 192 | CLinkInfo(): | 206 | CLinkInfo(): |
| 193 | // IsCopyLink(false), | 207 | LinkType(k_LinkType_PureSymLink), |
| 194 | isHardLink(false), | ||
| 195 | isJunction(false), | ||
| 196 | isRelative(false), | 208 | isRelative(false), |
| 197 | isWSL(false) | 209 | isWindowsPath(false) |
| 198 | {} | 210 | {} |
| 199 | 211 | ||
| 200 | void Clear() | 212 | void Clear() |
| 201 | { | 213 | { |
| 202 | // IsCopyLink = false; | 214 | LinkType = k_LinkType_PureSymLink; |
| 203 | isHardLink = false; | ||
| 204 | isJunction = false; | ||
| 205 | isRelative = false; | 215 | isRelative = false; |
| 206 | isWSL = false; | 216 | isWindowsPath = false; |
| 207 | linkPath.Empty(); | 217 | LinkPath.Empty(); |
| 208 | } | 218 | } |
| 209 | 219 | ||
| 210 | bool Parse(const Byte *data, size_t dataSize, bool isLinuxData); | 220 | bool Parse_from_WindowsReparseData(const Byte *data, size_t dataSize); |
| 221 | bool Parse_from_LinuxData(const Byte *data, size_t dataSize); | ||
| 222 | void Normalize_to_RelativeSafe(UStringVector &removePathParts); | ||
| 223 | private: | ||
| 224 | void Remove_AbsPathPrefixes(); | ||
| 211 | }; | 225 | }; |
| 212 | 226 | ||
| 213 | #endif // SUPPORT_LINKS | 227 | #endif // SUPPORT_LINKS |
| @@ -287,8 +301,8 @@ private: | |||
| 287 | 301 | ||
| 288 | bool _isRenamed; | 302 | bool _isRenamed; |
| 289 | bool _extractMode; | 303 | bool _extractMode; |
| 290 | // bool _is_SymLink_in_Data; | 304 | bool _is_SymLink_in_Data_Linux; // false = WIN32, true = LINUX. |
| 291 | bool _is_SymLink_in_Data_Linux; // false = WIN32, true = LINUX | 305 | // _is_SymLink_in_Data_Linux is detected from Windows/Linux part of attributes of file. |
| 292 | bool _needSetAttrib; | 306 | bool _needSetAttrib; |
| 293 | bool _isSymLinkCreated; | 307 | bool _isSymLinkCreated; |
| 294 | bool _itemFailure; | 308 | bool _itemFailure; |
| @@ -420,6 +434,7 @@ public: | |||
| 420 | HRESULT SendMessageError_with_Error(HRESULT errorCode, const char *message, const FString &path); | 434 | HRESULT SendMessageError_with_Error(HRESULT errorCode, const char *message, const FString &path); |
| 421 | HRESULT SendMessageError_with_LastError(const char *message, const FString &path); | 435 | HRESULT SendMessageError_with_LastError(const char *message, const FString &path); |
| 422 | HRESULT SendMessageError2(HRESULT errorCode, const char *message, const FString &path1, const FString &path2); | 436 | HRESULT SendMessageError2(HRESULT errorCode, const char *message, const FString &path1, const FString &path2); |
| 437 | HRESULT SendMessageError2_with_LastError(const char *message, const FString &path1, const FString &path2); | ||
| 423 | 438 | ||
| 424 | #if defined(_WIN32) && !defined(UNDER_CE) && !defined(Z7_SFX) | 439 | #if defined(_WIN32) && !defined(UNDER_CE) && !defined(Z7_SFX) |
| 425 | NExtract::NZoneIdMode::EEnum ZoneMode; | 440 | NExtract::NZoneIdMode::EEnum ZoneMode; |
| @@ -487,11 +502,16 @@ public: | |||
| 487 | private: | 502 | private: |
| 488 | CHardLinks _hardLinks; | 503 | CHardLinks _hardLinks; |
| 489 | CLinkInfo _link; | 504 | CLinkInfo _link; |
| 505 | // const void *NtReparse_Data; | ||
| 506 | // UInt32 NtReparse_Size; | ||
| 490 | 507 | ||
| 491 | // FString _copyFile_Path; | 508 | // FString _copyFile_Path; |
| 492 | // HRESULT MyCopyFile(ISequentialOutStream *outStream); | 509 | // HRESULT MyCopyFile(ISequentialOutStream *outStream); |
| 493 | HRESULT Link(const FString &fullProcessedPath); | ||
| 494 | HRESULT ReadLink(); | 510 | HRESULT ReadLink(); |
| 511 | HRESULT SetLink( | ||
| 512 | const FString &fullProcessedPath_from, | ||
| 513 | const CLinkInfo &linkInfo, | ||
| 514 | bool &linkWasSet); | ||
| 495 | 515 | ||
| 496 | public: | 516 | public: |
| 497 | // call PrepareHardLinks() after Init() | 517 | // call PrepareHardLinks() after Init() |
| @@ -538,16 +558,6 @@ private: | |||
| 538 | HRESULT CloseReparseAndFile(); | 558 | HRESULT CloseReparseAndFile(); |
| 539 | HRESULT CloseReparseAndFile2(); | 559 | HRESULT CloseReparseAndFile2(); |
| 540 | HRESULT SetDirsTimes(); | 560 | HRESULT SetDirsTimes(); |
| 541 | |||
| 542 | const void *NtReparse_Data; | ||
| 543 | UInt32 NtReparse_Size; | ||
| 544 | |||
| 545 | #ifdef SUPPORT_LINKS | ||
| 546 | HRESULT SetFromLinkPath( | ||
| 547 | const FString &fullProcessedPath, | ||
| 548 | const CLinkInfo &linkInfo, | ||
| 549 | bool &linkWasSet); | ||
| 550 | #endif | ||
| 551 | }; | 561 | }; |
| 552 | 562 | ||
| 553 | 563 | ||
diff --git a/CPP/7zip/UI/Common/Bench.cpp b/CPP/7zip/UI/Common/Bench.cpp index 05d66aa..eb24e7f 100644 --- a/CPP/7zip/UI/Common/Bench.cpp +++ b/CPP/7zip/UI/Common/Bench.cpp | |||
| @@ -871,14 +871,27 @@ struct CAffinityMode | |||
| 871 | unsigned NumCoreThreads; | 871 | unsigned NumCoreThreads; |
| 872 | unsigned NumCores; | 872 | unsigned NumCores; |
| 873 | // unsigned DivideNum; | 873 | // unsigned DivideNum; |
| 874 | |||
| 875 | #ifdef _WIN32 | ||
| 876 | unsigned NumGroups; | ||
| 877 | #endif | ||
| 878 | |||
| 874 | UInt32 Sizes[NUM_CPU_LEVELS_MAX]; | 879 | UInt32 Sizes[NUM_CPU_LEVELS_MAX]; |
| 875 | 880 | ||
| 876 | void SetLevels(unsigned numCores, unsigned numCoreThreads); | 881 | void SetLevels(unsigned numCores, unsigned numCoreThreads); |
| 877 | DWORD_PTR GetAffinityMask(UInt32 bundleIndex, CCpuSet *cpuSet) const; | 882 | DWORD_PTR GetAffinityMask(UInt32 bundleIndex, CCpuSet *cpuSet) const; |
| 878 | bool NeedAffinity() const { return NumBundleThreads != 0; } | 883 | bool NeedAffinity() const { return NumBundleThreads != 0; } |
| 879 | 884 | ||
| 885 | #ifdef _WIN32 | ||
| 886 | bool NeedGroupsMode() const { return NumGroups > 1; } | ||
| 887 | #endif | ||
| 888 | |||
| 880 | WRes CreateThread_WithAffinity(NWindows::CThread &thread, THREAD_FUNC_TYPE startAddress, LPVOID parameter, UInt32 bundleIndex) const | 889 | WRes CreateThread_WithAffinity(NWindows::CThread &thread, THREAD_FUNC_TYPE startAddress, LPVOID parameter, UInt32 bundleIndex) const |
| 881 | { | 890 | { |
| 891 | #ifdef _WIN32 | ||
| 892 | if (NeedGroupsMode()) // we need fix for bundleIndex usage | ||
| 893 | return thread.Create_With_Group(startAddress, parameter, bundleIndex % NumGroups); | ||
| 894 | #endif | ||
| 882 | if (NeedAffinity()) | 895 | if (NeedAffinity()) |
| 883 | { | 896 | { |
| 884 | CCpuSet cpuSet; | 897 | CCpuSet cpuSet; |
| @@ -892,6 +905,9 @@ struct CAffinityMode | |||
| 892 | NumBundleThreads(0), | 905 | NumBundleThreads(0), |
| 893 | NumLevels(0), | 906 | NumLevels(0), |
| 894 | NumCoreThreads(1) | 907 | NumCoreThreads(1) |
| 908 | #ifdef _WIN32 | ||
| 909 | , NumGroups(0) | ||
| 910 | #endif | ||
| 895 | // DivideNum(1) | 911 | // DivideNum(1) |
| 896 | {} | 912 | {} |
| 897 | }; | 913 | }; |
| @@ -1288,22 +1304,28 @@ HRESULT CEncoderInfo::Generate() | |||
| 1288 | if (scp) | 1304 | if (scp) |
| 1289 | { | 1305 | { |
| 1290 | const UInt64 reduceSize = kBufferSize; | 1306 | const UInt64 reduceSize = kBufferSize; |
| 1291 | 1307 | /* in posix : new thread uses same affinity as parent thread, | |
| 1292 | /* in posix new thread uses same affinity as parent thread, | ||
| 1293 | so we don't need to send affinity to coder in posix */ | 1308 | so we don't need to send affinity to coder in posix */ |
| 1294 | UInt64 affMask; | 1309 | UInt64 affMask = 0; |
| 1295 | #if !defined(Z7_ST) && defined(_WIN32) | 1310 | UInt32 affinityGroup = (UInt32)(Int32)-1; |
| 1311 | // UInt64 affinityInGroup = 0; | ||
| 1312 | #if !defined(Z7_ST) && defined(_WIN32) | ||
| 1296 | { | 1313 | { |
| 1297 | CCpuSet cpuSet; | 1314 | CCpuSet cpuSet; |
| 1298 | affMask = AffinityMode.GetAffinityMask(EncoderIndex, &cpuSet); | 1315 | if (AffinityMode.NeedGroupsMode()) // we need fix for affinityInGroup also |
| 1316 | affinityGroup = EncoderIndex % AffinityMode.NumGroups; | ||
| 1317 | else | ||
| 1318 | affMask = AffinityMode.GetAffinityMask(EncoderIndex, &cpuSet); | ||
| 1299 | } | 1319 | } |
| 1300 | #else | 1320 | #endif |
| 1301 | affMask = 0; | 1321 | // affMask <<= 3; // debug line: to test no affinity in coder |
| 1302 | #endif | 1322 | // affMask = 0; // for debug |
| 1303 | // affMask <<= 3; // debug line: to test no affinity in coder; | 1323 | // affinityGroup = 0; // for debug |
| 1304 | // affMask = 0; | 1324 | // affinityInGroup = 1; // for debug |
| 1305 | 1325 | RINOK(method.SetCoderProps_DSReduce_Aff(scp, &reduceSize, | |
| 1306 | RINOK(method.SetCoderProps_DSReduce_Aff(scp, &reduceSize, (affMask != 0 ? &affMask : NULL))) | 1326 | affMask != 0 ? &affMask : NULL, |
| 1327 | affinityGroup != (UInt32)(Int32)-1 ? &affinityGroup : NULL, | ||
| 1328 | /* affinityInGroup != 0 ? &affinityInGroup : */ NULL)) | ||
| 1307 | } | 1329 | } |
| 1308 | else | 1330 | else |
| 1309 | { | 1331 | { |
| @@ -2962,7 +2984,7 @@ AString GetProcessThreadsInfo(const NSystem::CProcessAffinity &ti) | |||
| 2962 | { | 2984 | { |
| 2963 | AString s; | 2985 | AString s; |
| 2964 | // s.Add_UInt32(ti.numProcessThreads); | 2986 | // s.Add_UInt32(ti.numProcessThreads); |
| 2965 | unsigned numSysThreads = ti.GetNumSystemThreads(); | 2987 | const unsigned numSysThreads = ti.GetNumSystemThreads(); |
| 2966 | if (ti.GetNumProcessThreads() != numSysThreads) | 2988 | if (ti.GetNumProcessThreads() != numSysThreads) |
| 2967 | { | 2989 | { |
| 2968 | // if (ti.numProcessThreads != ti.numSysThreads) | 2990 | // if (ti.numProcessThreads != ti.numSysThreads) |
| @@ -2992,6 +3014,35 @@ AString GetProcessThreadsInfo(const NSystem::CProcessAffinity &ti) | |||
| 2992 | } | 3014 | } |
| 2993 | #endif | 3015 | #endif |
| 2994 | } | 3016 | } |
| 3017 | #ifdef _WIN32 | ||
| 3018 | if (ti.Groups.GroupSizes.Size() > 1 || | ||
| 3019 | (ti.Groups.GroupSizes.Size() == 1 | ||
| 3020 | && ti.Groups.NumThreadsTotal != numSysThreads)) | ||
| 3021 | { | ||
| 3022 | s += " : "; | ||
| 3023 | s.Add_UInt32(ti.Groups.GroupSizes.Size()); | ||
| 3024 | s += " groups : "; | ||
| 3025 | if (ti.Groups.NumThreadsTotal == numSysThreads) | ||
| 3026 | { | ||
| 3027 | s.Add_UInt32(ti.Groups.NumThreadsTotal); | ||
| 3028 | s += " c : "; | ||
| 3029 | } | ||
| 3030 | UInt32 minSize, maxSize; | ||
| 3031 | ti.Groups.Get_GroupSize_Min_Max(minSize, maxSize); | ||
| 3032 | if (minSize == maxSize) | ||
| 3033 | { | ||
| 3034 | s.Add_UInt32(ti.Groups.GroupSizes[0]); | ||
| 3035 | s += " c/g"; | ||
| 3036 | } | ||
| 3037 | else | ||
| 3038 | FOR_VECTOR (i, ti.Groups.GroupSizes) | ||
| 3039 | { | ||
| 3040 | if (i != 0) | ||
| 3041 | s.Add_Char(' '); | ||
| 3042 | s.Add_UInt32(ti.Groups.GroupSizes[i]); | ||
| 3043 | } | ||
| 3044 | } | ||
| 3045 | #endif | ||
| 2995 | return s; | 3046 | return s; |
| 2996 | } | 3047 | } |
| 2997 | 3048 | ||
| @@ -3753,9 +3804,13 @@ HRESULT Bench( | |||
| 3753 | UInt64 complexInCommands = kComplexInCommands; | 3804 | UInt64 complexInCommands = kComplexInCommands; |
| 3754 | UInt32 numThreads_Start = 1; | 3805 | UInt32 numThreads_Start = 1; |
| 3755 | 3806 | ||
| 3756 | #ifndef Z7_ST | 3807 | #ifndef Z7_ST |
| 3757 | CAffinityMode affinityMode; | 3808 | CAffinityMode affinityMode; |
| 3758 | #endif | 3809 | #ifdef _WIN32 |
| 3810 | if (threadsInfo.IsGroupMode && threadsInfo.Groups.GroupSizes.Size() > 1) | ||
| 3811 | affinityMode.NumGroups = threadsInfo.Groups.GroupSizes.Size(); | ||
| 3812 | #endif | ||
| 3813 | #endif | ||
| 3759 | 3814 | ||
| 3760 | 3815 | ||
| 3761 | COneMethodInfo method; | 3816 | COneMethodInfo method; |
| @@ -4861,7 +4916,7 @@ HRESULT Bench( | |||
| 4861 | if (AreSameMethodNames(benchMethod, methodName)) | 4916 | if (AreSameMethodNames(benchMethod, methodName)) |
| 4862 | { | 4917 | { |
| 4863 | if (benchProps.IsEmpty() | 4918 | if (benchProps.IsEmpty() |
| 4864 | || (benchProps == "x5" && method.PropsString.IsEmpty()) | 4919 | || (benchProps.IsEqualTo("x5") && method.PropsString.IsEmpty()) |
| 4865 | || method.PropsString.IsPrefixedBy_Ascii_NoCase(benchProps)) | 4920 | || method.PropsString.IsPrefixedBy_Ascii_NoCase(benchProps)) |
| 4866 | { | 4921 | { |
| 4867 | callback.BenchProps.EncComplex = h.EncComplex; | 4922 | callback.BenchProps.EncComplex = h.EncComplex; |
diff --git a/CPP/7zip/UI/Common/EnumDirItems.cpp b/CPP/7zip/UI/Common/EnumDirItems.cpp index 11643ae..cada2e6 100644 --- a/CPP/7zip/UI/Common/EnumDirItems.cpp +++ b/CPP/7zip/UI/Common/EnumDirItems.cpp | |||
| @@ -1213,11 +1213,13 @@ HRESULT CDirItems::FillFixedReparse() | |||
| 1213 | // continue; // for debug | 1213 | // continue; // for debug |
| 1214 | if (!item.Has_Attrib_ReparsePoint()) | 1214 | if (!item.Has_Attrib_ReparsePoint()) |
| 1215 | continue; | 1215 | continue; |
| 1216 | 1216 | /* | |
| 1217 | We want to get properties of target file instead of properies of symbolic link. | ||
| 1218 | Probably this code is unused, because | ||
| 1219 | CFileInfo::Find(with followLink = true) called Fill_From_ByHandleFileInfo() already. | ||
| 1220 | */ | ||
| 1217 | // if (item.IsDir()) continue; | 1221 | // if (item.IsDir()) continue; |
| 1218 | |||
| 1219 | const FString phyPath = GetPhyPath(i); | 1222 | const FString phyPath = GetPhyPath(i); |
| 1220 | |||
| 1221 | NFind::CFileInfo fi; | 1223 | NFind::CFileInfo fi; |
| 1222 | if (fi.Fill_From_ByHandleFileInfo(phyPath)) // item.IsDir() | 1224 | if (fi.Fill_From_ByHandleFileInfo(phyPath)) // item.IsDir() |
| 1223 | { | 1225 | { |
| @@ -1228,38 +1230,13 @@ HRESULT CDirItems::FillFixedReparse() | |||
| 1228 | item.Attrib = fi.Attrib; | 1230 | item.Attrib = fi.Attrib; |
| 1229 | continue; | 1231 | continue; |
| 1230 | } | 1232 | } |
| 1231 | |||
| 1232 | /* | ||
| 1233 | // we request properties of target file instead of properies of symbolic link | ||
| 1234 | // here we also can manually parse unsupported links (like WSL links) | ||
| 1235 | NIO::CInFile inFile; | ||
| 1236 | if (inFile.Open(phyPath)) | ||
| 1237 | { | ||
| 1238 | BY_HANDLE_FILE_INFORMATION info; | ||
| 1239 | if (inFile.GetFileInformation(&info)) | ||
| 1240 | { | ||
| 1241 | // Stat.FilesSize doesn't contain item.Size already | ||
| 1242 | // Stat.FilesSize -= item.Size; | ||
| 1243 | item.Size = (((UInt64)info.nFileSizeHigh) << 32) + info.nFileSizeLow; | ||
| 1244 | Stat.FilesSize += item.Size; | ||
| 1245 | item.CTime = info.ftCreationTime; | ||
| 1246 | item.ATime = info.ftLastAccessTime; | ||
| 1247 | item.MTime = info.ftLastWriteTime; | ||
| 1248 | item.Attrib = info.dwFileAttributes; | ||
| 1249 | continue; | ||
| 1250 | } | ||
| 1251 | } | ||
| 1252 | */ | ||
| 1253 | |||
| 1254 | RINOK(AddError(phyPath)) | 1233 | RINOK(AddError(phyPath)) |
| 1255 | continue; | 1234 | continue; |
| 1256 | } | 1235 | } |
| 1257 | 1236 | ||
| 1258 | // (SymLinks == true) here | 1237 | // (SymLinks == true) |
| 1259 | |||
| 1260 | if (item.ReparseData.Size() == 0) | 1238 | if (item.ReparseData.Size() == 0) |
| 1261 | continue; | 1239 | continue; |
| 1262 | |||
| 1263 | // if (item.Size == 0) | 1240 | // if (item.Size == 0) |
| 1264 | { | 1241 | { |
| 1265 | // 20.03: we use Reparse Data instead of real data | 1242 | // 20.03: we use Reparse Data instead of real data |
| @@ -1277,7 +1254,7 @@ HRESULT CDirItems::FillFixedReparse() | |||
| 1277 | /* imagex/WIM reduces absolute paths in links (raparse data), | 1254 | /* imagex/WIM reduces absolute paths in links (raparse data), |
| 1278 | if we archive non root folder. We do same thing here */ | 1255 | if we archive non root folder. We do same thing here */ |
| 1279 | 1256 | ||
| 1280 | bool isWSL = false; | 1257 | // bool isWSL = false; |
| 1281 | if (attr.IsSymLink_WSL()) | 1258 | if (attr.IsSymLink_WSL()) |
| 1282 | { | 1259 | { |
| 1283 | // isWSL = true; | 1260 | // isWSL = true; |
| @@ -1314,21 +1291,27 @@ HRESULT CDirItems::FillFixedReparse() | |||
| 1314 | continue; | 1291 | continue; |
| 1315 | if (rootPrefixSize == prefix.Len()) | 1292 | if (rootPrefixSize == prefix.Len()) |
| 1316 | continue; // simple case: paths are from root | 1293 | continue; // simple case: paths are from root |
| 1317 | |||
| 1318 | if (link.Len() <= prefix.Len()) | 1294 | if (link.Len() <= prefix.Len()) |
| 1319 | continue; | 1295 | continue; |
| 1320 | |||
| 1321 | if (CompareFileNames(link.Left(prefix.Len()), prefix) != 0) | 1296 | if (CompareFileNames(link.Left(prefix.Len()), prefix) != 0) |
| 1322 | continue; | 1297 | continue; |
| 1323 | 1298 | ||
| 1324 | UString newLink = prefix.Left(rootPrefixSize); | 1299 | UString newLink = prefix.Left(rootPrefixSize); |
| 1325 | newLink += link.Ptr(prefix.Len()); | 1300 | newLink += link.Ptr(prefix.Len()); |
| 1326 | 1301 | ||
| 1327 | CByteBuffer data; | 1302 | CByteBuffer &data = item.ReparseData2; |
| 1328 | bool isSymLink = !attr.IsMountPoint(); | 1303 | /* |
| 1329 | if (!FillLinkData(data, newLink, isSymLink, isWSL)) | 1304 | if (isWSL) |
| 1305 | { | ||
| 1306 | Convert_WinPath_to_WslLinuxPath(newLink, true); // is absolute : change it | ||
| 1307 | FillLinkData_WslLink(data, newLink); | ||
| 1308 | } | ||
| 1309 | else | ||
| 1310 | */ | ||
| 1311 | FillLinkData_WinLink(data, newLink, !attr.IsMountPoint()); | ||
| 1312 | if (data.Size() == 0) | ||
| 1330 | continue; | 1313 | continue; |
| 1331 | item.ReparseData2 = data; | 1314 | // item.ReparseData2 = data; |
| 1332 | } | 1315 | } |
| 1333 | return S_OK; | 1316 | return S_OK; |
| 1334 | } | 1317 | } |
diff --git a/CPP/7zip/UI/Common/Extract.cpp b/CPP/7zip/UI/Common/Extract.cpp index 010b01c..0301976 100644 --- a/CPP/7zip/UI/Common/Extract.cpp +++ b/CPP/7zip/UI/Common/Extract.cpp | |||
| @@ -389,7 +389,7 @@ HRESULT Extract( | |||
| 389 | { | 389 | { |
| 390 | UString s = arcPath.Ptr(pos + 1); | 390 | UString s = arcPath.Ptr(pos + 1); |
| 391 | int index = codecs->FindFormatForExtension(s); | 391 | int index = codecs->FindFormatForExtension(s); |
| 392 | if (index >= 0 && s == L"001") | 392 | if (index >= 0 && s.IsEqualTo("001")) |
| 393 | { | 393 | { |
| 394 | s = arcPath.Left(pos); | 394 | s = arcPath.Left(pos); |
| 395 | pos = s.ReverseFind(L'.'); | 395 | pos = s.ReverseFind(L'.'); |
diff --git a/CPP/7zip/UI/Common/ExtractingFilePath.cpp b/CPP/7zip/UI/Common/ExtractingFilePath.cpp index 88da4ad..5ca5e66 100644 --- a/CPP/7zip/UI/Common/ExtractingFilePath.cpp +++ b/CPP/7zip/UI/Common/ExtractingFilePath.cpp | |||
| @@ -208,7 +208,7 @@ void Correct_FsPath(bool absIsAllowed, bool keepAndReplaceEmptyPrefixes, UString | |||
| 208 | if (parts.Size() > 1 && parts[1].IsEmpty()) | 208 | if (parts.Size() > 1 && parts[1].IsEmpty()) |
| 209 | { | 209 | { |
| 210 | i = 2; | 210 | i = 2; |
| 211 | if (parts.Size() > 2 && parts[2] == L"?") | 211 | if (parts.Size() > 2 && parts[2].IsEqualTo("?")) |
| 212 | { | 212 | { |
| 213 | i = 3; | 213 | i = 3; |
| 214 | if (parts.Size() > 3 && NWindows::NFile::NName::IsDrivePath2(parts[3])) | 214 | if (parts.Size() > 3 && NWindows::NFile::NName::IsDrivePath2(parts[3])) |
diff --git a/CPP/7zip/UI/Common/HashCalc.cpp b/CPP/7zip/UI/Common/HashCalc.cpp index 9caac36..f026f80 100644 --- a/CPP/7zip/UI/Common/HashCalc.cpp +++ b/CPP/7zip/UI/Common/HashCalc.cpp | |||
| @@ -62,7 +62,7 @@ HRESULT CHashBundle::SetMethods(DECL_EXTERNAL_CODECS_LOC_VARS const UStringVecto | |||
| 62 | if (m.MethodName.IsEmpty()) | 62 | if (m.MethodName.IsEmpty()) |
| 63 | m.MethodName = k_DefaultHashMethod; | 63 | m.MethodName = k_DefaultHashMethod; |
| 64 | 64 | ||
| 65 | if (m.MethodName == "*") | 65 | if (m.MethodName.IsEqualTo("*")) |
| 66 | { | 66 | { |
| 67 | CRecordVector<CMethodId> tempMethods; | 67 | CRecordVector<CMethodId> tempMethods; |
| 68 | GetHashMethods(EXTERNAL_CODECS_LOC_VARS tempMethods); | 68 | GetHashMethods(EXTERNAL_CODECS_LOC_VARS tempMethods); |
| @@ -431,6 +431,19 @@ static void WriteLine(CDynLimBuf &hashFileString, | |||
| 431 | } | 431 | } |
| 432 | 432 | ||
| 433 | 433 | ||
| 434 | static void Convert_TagName_to_MethodName(AString &method) | ||
| 435 | { | ||
| 436 | // we need to convert at least SHA512/256 to SHA512-256, and SHA512/224 to SHA512-224 | ||
| 437 | // but we convert any '/' to '-'. | ||
| 438 | method.Replace('/', '-'); | ||
| 439 | } | ||
| 440 | |||
| 441 | static void Convert_MethodName_to_TagName(AString &method) | ||
| 442 | { | ||
| 443 | if (method.IsPrefixedBy_Ascii_NoCase("SHA512-2")) | ||
| 444 | method.ReplaceOneCharAtPos(6, '/'); | ||
| 445 | } | ||
| 446 | |||
| 434 | 447 | ||
| 435 | static void WriteLine(CDynLimBuf &hashFileString, | 448 | static void WriteLine(CDynLimBuf &hashFileString, |
| 436 | const CHashOptionsLocal &options, | 449 | const CHashOptionsLocal &options, |
| @@ -440,8 +453,10 @@ static void WriteLine(CDynLimBuf &hashFileString, | |||
| 440 | { | 453 | { |
| 441 | AString methodName; | 454 | AString methodName; |
| 442 | if (!hb.Hashers.IsEmpty()) | 455 | if (!hb.Hashers.IsEmpty()) |
| 456 | { | ||
| 443 | methodName = hb.Hashers[0].Name; | 457 | methodName = hb.Hashers[0].Name; |
| 444 | 458 | Convert_MethodName_to_TagName(methodName); | |
| 459 | } | ||
| 445 | AString hashesString; | 460 | AString hashesString; |
| 446 | AddHashResultLine(hashesString, hb.Hashers); | 461 | AddHashResultLine(hashesString, hb.Hashers); |
| 447 | WriteLine(hashFileString, options, path, isDir, methodName, hashesString); | 462 | WriteLine(hashFileString, options, path, isDir, methodName, hashesString); |
| @@ -752,7 +767,7 @@ bool CHashPair::ParseCksum(const char *s) | |||
| 752 | Name = end; | 767 | Name = end; |
| 753 | 768 | ||
| 754 | Hash.Alloc(4); | 769 | Hash.Alloc(4); |
| 755 | SetBe32(Hash, crc) | 770 | SetBe32a(Hash, crc) |
| 756 | 771 | ||
| 757 | Size_from_Arc = size; | 772 | Size_from_Arc = size; |
| 758 | Size_from_Arc_Defined = true; | 773 | Size_from_Arc_Defined = true; |
| @@ -773,56 +788,87 @@ static const char * const k_CsumMethodNames[] = | |||
| 773 | { | 788 | { |
| 774 | "sha256" | 789 | "sha256" |
| 775 | , "sha224" | 790 | , "sha224" |
| 776 | // , "sha512-224" | 791 | , "sha512-224" |
| 777 | // , "sha512-256" | 792 | , "sha512-256" |
| 778 | , "sha384" | 793 | , "sha384" |
| 779 | , "sha512" | 794 | , "sha512" |
| 780 | // , "sha3-224" | 795 | , "sha3-224" |
| 781 | , "sha3-256" | 796 | , "sha3-256" |
| 782 | // , "sha3-384" | 797 | , "sha3-384" |
| 783 | // , "sha3-512" | 798 | , "sha3-512" |
| 784 | // , "shake128" | 799 | // , "shake128" |
| 785 | // , "shake256" | 800 | // , "shake256" |
| 786 | , "sha1" | 801 | , "sha1" |
| 802 | , "sha2" | ||
| 803 | , "sha3" | ||
| 804 | , "sha" | ||
| 787 | , "md5" | 805 | , "md5" |
| 788 | , "blake2sp" | 806 | , "blake2s" |
| 789 | , "blake2b" | 807 | , "blake2b" |
| 808 | , "blake2sp" | ||
| 790 | , "xxh64" | 809 | , "xxh64" |
| 791 | , "crc64" | ||
| 792 | , "crc32" | 810 | , "crc32" |
| 811 | , "crc64" | ||
| 793 | , "cksum" | 812 | , "cksum" |
| 794 | }; | 813 | }; |
| 795 | 814 | ||
| 796 | static UString GetMethod_from_FileName(const UString &name) | 815 | |
| 816 | // returns true, if (method) is known hash method or hash method group name. | ||
| 817 | static bool GetMethod_from_FileName(const UString &name, AString &method) | ||
| 797 | { | 818 | { |
| 819 | method.Empty(); | ||
| 798 | AString s; | 820 | AString s; |
| 799 | ConvertUnicodeToUTF8(name, s); | 821 | ConvertUnicodeToUTF8(name, s); |
| 800 | const int dotPos = s.ReverseFind_Dot(); | 822 | const int dotPos = s.ReverseFind_Dot(); |
| 801 | const char *src = s.Ptr(); | ||
| 802 | bool isExtension = false; | ||
| 803 | if (dotPos >= 0) | 823 | if (dotPos >= 0) |
| 804 | { | 824 | { |
| 805 | isExtension = true; | 825 | method = s.Ptr(dotPos + 1); |
| 806 | src = s.Ptr(dotPos + 1); | 826 | if (method.IsEqualTo_Ascii_NoCase("txt") || |
| 827 | method.IsEqualTo_Ascii_NoCase("asc")) | ||
| 828 | { | ||
| 829 | method.Empty(); | ||
| 830 | const int dotPos2 = s.Find('.'); | ||
| 831 | if (dotPos2 >= 0) | ||
| 832 | s.DeleteFrom(dotPos2); | ||
| 833 | } | ||
| 807 | } | 834 | } |
| 808 | const char *m = ""; | 835 | if (method.IsEmpty()) |
| 836 | { | ||
| 837 | // we support file names with "sum" and "sums" postfixes: "sha256sum", "sha256sums" | ||
| 838 | unsigned size; | ||
| 839 | if (s.Len() > 4 && StringsAreEqualNoCase_Ascii(s.RightPtr(4), "sums")) | ||
| 840 | size = 4; | ||
| 841 | else if (s.Len() > 3 && StringsAreEqualNoCase_Ascii(s.RightPtr(3), "sum")) | ||
| 842 | size = 3; | ||
| 843 | else | ||
| 844 | return false; | ||
| 845 | method = s; | ||
| 846 | method.DeleteFrom(s.Len() - size); | ||
| 847 | } | ||
| 848 | |||
| 809 | unsigned i; | 849 | unsigned i; |
| 810 | for (i = 0; i < Z7_ARRAY_SIZE(k_CsumMethodNames); i++) | 850 | for (i = 0; i < Z7_ARRAY_SIZE(k_CsumMethodNames); i++) |
| 811 | { | 851 | { |
| 812 | m = k_CsumMethodNames[i]; | 852 | const char *m = k_CsumMethodNames[i]; |
| 813 | if (isExtension) | 853 | if (method.IsEqualTo_Ascii_NoCase(m)) |
| 814 | { | 854 | { |
| 815 | if (StringsAreEqual_Ascii(src, m)) | 855 | // method = m; // we can get lowcase |
| 816 | break; | 856 | return true; |
| 817 | } | 857 | } |
| 818 | else if (IsString1PrefixedByString2_NoCase_Ascii(src, m)) | ||
| 819 | if (StringsAreEqual_Ascii(src + strlen(m), "sums")) | ||
| 820 | break; | ||
| 821 | } | 858 | } |
| 822 | UString res; | 859 | |
| 823 | if (i != Z7_ARRAY_SIZE(k_CsumMethodNames)) | 860 | /* |
| 824 | res = m; | 861 | for (i = 0; i < Z7_ARRAY_SIZE(k_CsumMethodNames); i++) |
| 825 | return res; | 862 | { |
| 863 | const char *m = k_CsumMethodNames[i]; | ||
| 864 | if (method.IsPrefixedBy_Ascii_NoCase(m)) | ||
| 865 | { | ||
| 866 | method = m; // we get lowcase | ||
| 867 | return true; | ||
| 868 | } | ||
| 869 | } | ||
| 870 | */ | ||
| 871 | return false; | ||
| 826 | } | 872 | } |
| 827 | 873 | ||
| 828 | 874 | ||
| @@ -1047,7 +1093,7 @@ Z7_COM7F_IMF(CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data | |||
| 1047 | if (propID == kpidChecksum) | 1093 | if (propID == kpidChecksum) |
| 1048 | { | 1094 | { |
| 1049 | const CHashPair &hp = HashPairs[index]; | 1095 | const CHashPair &hp = HashPairs[index]; |
| 1050 | if (hp.Hash.Size() > 0) | 1096 | if (hp.Hash.Size() != 0) |
| 1051 | { | 1097 | { |
| 1052 | *data = hp.Hash; | 1098 | *data = hp.Hash; |
| 1053 | *dataSize = (UInt32)hp.Hash.Size(); | 1099 | *dataSize = (UInt32)hp.Hash.Size(); |
| @@ -1100,11 +1146,6 @@ Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) | |||
| 1100 | s.Add_UInt32(_hashSize * 8); | 1146 | s.Add_UInt32(_hashSize * 8); |
| 1101 | s += "-bit"; | 1147 | s += "-bit"; |
| 1102 | } | 1148 | } |
| 1103 | if (!_nameExtenstion.IsEmpty()) | ||
| 1104 | { | ||
| 1105 | s.Add_Space_if_NotEmpty(); | ||
| 1106 | s += _nameExtenstion; | ||
| 1107 | } | ||
| 1108 | if (_is_PgpMethod) | 1149 | if (_is_PgpMethod) |
| 1109 | { | 1150 | { |
| 1110 | Add_OptSpace_String(s, "PGP"); | 1151 | Add_OptSpace_String(s, "PGP"); |
| @@ -1120,6 +1161,18 @@ Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) | |||
| 1120 | Add_OptSpace_String(s, "TAG"); | 1161 | Add_OptSpace_String(s, "TAG"); |
| 1121 | if (_are_there_Dirs) | 1162 | if (_are_there_Dirs) |
| 1122 | Add_OptSpace_String(s, "DIRS"); | 1163 | Add_OptSpace_String(s, "DIRS"); |
| 1164 | if (!_method_from_FileName.IsEmpty()) | ||
| 1165 | { | ||
| 1166 | Add_OptSpace_String(s, "filename_method:"); | ||
| 1167 | s += _method_from_FileName; | ||
| 1168 | if (!_is_KnownMethod_in_FileName) | ||
| 1169 | s += ":UNKNOWN"; | ||
| 1170 | } | ||
| 1171 | if (!_methods.IsEmpty()) | ||
| 1172 | { | ||
| 1173 | Add_OptSpace_String(s, "cmd_method:"); | ||
| 1174 | s += _methods[0]; | ||
| 1175 | } | ||
| 1123 | prop = s; | 1176 | prop = s; |
| 1124 | break; | 1177 | break; |
| 1125 | } | 1178 | } |
| @@ -1228,6 +1281,15 @@ static HRESULT ReadStream_to_Buf(IInStream *stream, CByteBuffer &buf, IArchiveOp | |||
| 1228 | } | 1281 | } |
| 1229 | 1282 | ||
| 1230 | 1283 | ||
| 1284 | static bool isThere_Zero_Byte(const Byte *data, size_t size) | ||
| 1285 | { | ||
| 1286 | for (size_t i = 0; i < size; i++) | ||
| 1287 | if (data[i] == 0) | ||
| 1288 | return true; | ||
| 1289 | return false; | ||
| 1290 | } | ||
| 1291 | |||
| 1292 | |||
| 1231 | Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *openCallback)) | 1293 | Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *openCallback)) |
| 1232 | { | 1294 | { |
| 1233 | COM_TRY_BEGIN | 1295 | COM_TRY_BEGIN |
| @@ -1239,17 +1301,9 @@ Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallb | |||
| 1239 | 1301 | ||
| 1240 | CObjectVector<CHashPair> &pairs = HashPairs; | 1302 | CObjectVector<CHashPair> &pairs = HashPairs; |
| 1241 | 1303 | ||
| 1242 | bool zeroMode = false; | 1304 | const bool zeroMode = isThere_Zero_Byte(buf, buf.Size()); |
| 1243 | bool cr_lf_Mode = false; | ||
| 1244 | { | ||
| 1245 | for (size_t i = 0; i < buf.Size(); i++) | ||
| 1246 | if (buf.ConstData()[i] == 0) | ||
| 1247 | { | ||
| 1248 | zeroMode = true; | ||
| 1249 | break; | ||
| 1250 | } | ||
| 1251 | } | ||
| 1252 | _is_ZeroMode = zeroMode; | 1305 | _is_ZeroMode = zeroMode; |
| 1306 | bool cr_lf_Mode = false; | ||
| 1253 | if (!zeroMode) | 1307 | if (!zeroMode) |
| 1254 | cr_lf_Mode = Is_CR_LF_Data(buf, buf.Size()); | 1308 | cr_lf_Mode = Is_CR_LF_Data(buf, buf.Size()); |
| 1255 | 1309 | ||
| @@ -1263,13 +1317,21 @@ Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallb | |||
| 1263 | NCOM::CPropVariant prop; | 1317 | NCOM::CPropVariant prop; |
| 1264 | RINOK(openVolumeCallback->GetProperty(kpidName, &prop)) | 1318 | RINOK(openVolumeCallback->GetProperty(kpidName, &prop)) |
| 1265 | if (prop.vt == VT_BSTR) | 1319 | if (prop.vt == VT_BSTR) |
| 1266 | _nameExtenstion = GetMethod_from_FileName(prop.bstrVal); | 1320 | _is_KnownMethod_in_FileName = GetMethod_from_FileName(prop.bstrVal, _method_from_FileName); |
| 1267 | } | 1321 | } |
| 1268 | } | 1322 | } |
| 1269 | 1323 | ||
| 1270 | bool cksumMode = false; | 1324 | if (!_methods.IsEmpty()) |
| 1271 | if (_nameExtenstion.IsEqualTo_Ascii_NoCase("cksum")) | 1325 | { |
| 1272 | cksumMode = true; | 1326 | ConvertUnicodeToUTF8(_methods[0], _method_for_Extraction); |
| 1327 | } | ||
| 1328 | if (_method_for_Extraction.IsEmpty()) | ||
| 1329 | { | ||
| 1330 | // if (_is_KnownMethod_in_FileName) | ||
| 1331 | _method_for_Extraction = _method_from_FileName; | ||
| 1332 | } | ||
| 1333 | |||
| 1334 | const bool cksumMode = _method_for_Extraction.IsEqualTo_Ascii_NoCase("cksum"); | ||
| 1273 | _is_CksumMode = cksumMode; | 1335 | _is_CksumMode = cksumMode; |
| 1274 | 1336 | ||
| 1275 | size_t pos = 0; | 1337 | size_t pos = 0; |
| @@ -1366,6 +1428,7 @@ void CHandler::ClearVars() | |||
| 1366 | _is_ZeroMode = false; | 1428 | _is_ZeroMode = false; |
| 1367 | _are_there_Tags = false; | 1429 | _are_there_Tags = false; |
| 1368 | _are_there_Dirs = false; | 1430 | _are_there_Dirs = false; |
| 1431 | _is_KnownMethod_in_FileName = false; | ||
| 1369 | _hashSize_Defined = false; | 1432 | _hashSize_Defined = false; |
| 1370 | _hashSize = 0; | 1433 | _hashSize = 0; |
| 1371 | } | 1434 | } |
| @@ -1374,7 +1437,8 @@ void CHandler::ClearVars() | |||
| 1374 | Z7_COM7F_IMF(CHandler::Close()) | 1437 | Z7_COM7F_IMF(CHandler::Close()) |
| 1375 | { | 1438 | { |
| 1376 | ClearVars(); | 1439 | ClearVars(); |
| 1377 | _nameExtenstion.Empty(); | 1440 | _method_from_FileName.Empty(); |
| 1441 | _method_for_Extraction.Empty(); | ||
| 1378 | _pgpMethod.Empty(); | 1442 | _pgpMethod.Empty(); |
| 1379 | HashPairs.Clear(); | 1443 | HashPairs.Clear(); |
| 1380 | return S_OK; | 1444 | return S_OK; |
| @@ -1401,19 +1465,73 @@ static bool CheckDigests(const Byte *a, const Byte *b, size_t size) | |||
| 1401 | } | 1465 | } |
| 1402 | 1466 | ||
| 1403 | 1467 | ||
| 1404 | static void AddDefaultMethod(UStringVector &methods, unsigned size) | 1468 | static void AddDefaultMethod(UStringVector &methods, |
| 1469 | const char *name, unsigned size) | ||
| 1405 | { | 1470 | { |
| 1471 | int shaVersion = -1; | ||
| 1472 | if (name) | ||
| 1473 | { | ||
| 1474 | if (StringsAreEqualNoCase_Ascii(name, "sha")) | ||
| 1475 | { | ||
| 1476 | shaVersion = 0; | ||
| 1477 | if (size == 0) | ||
| 1478 | size = 32; | ||
| 1479 | } | ||
| 1480 | else if (StringsAreEqualNoCase_Ascii(name, "sha1")) | ||
| 1481 | { | ||
| 1482 | shaVersion = 1; | ||
| 1483 | if (size == 0) | ||
| 1484 | size = 20; | ||
| 1485 | } | ||
| 1486 | else if (StringsAreEqualNoCase_Ascii(name, "sha2")) | ||
| 1487 | { | ||
| 1488 | shaVersion = 2; | ||
| 1489 | if (size == 0) | ||
| 1490 | size = 32; | ||
| 1491 | } | ||
| 1492 | else if (StringsAreEqualNoCase_Ascii(name, "sha3")) | ||
| 1493 | { | ||
| 1494 | if (size == 0 || | ||
| 1495 | size == 32) name = "sha3-256"; | ||
| 1496 | else if (size == 28) name = "sha3-224"; | ||
| 1497 | else if (size == 48) name = "sha3-384"; | ||
| 1498 | else if (size == 64) name = "sha3-512"; | ||
| 1499 | } | ||
| 1500 | else if (StringsAreEqualNoCase_Ascii(name, "sha512")) | ||
| 1501 | { | ||
| 1502 | // we allow any sha512 derived hash inside .sha512 file: | ||
| 1503 | if (size == 48) name = "sha384"; | ||
| 1504 | else if (size == 32) name = "sha512-256"; | ||
| 1505 | else if (size == 28) name = "sha512-224"; | ||
| 1506 | } | ||
| 1507 | if (shaVersion >= 0) | ||
| 1508 | name = NULL; | ||
| 1509 | } | ||
| 1510 | |||
| 1406 | const char *m = NULL; | 1511 | const char *m = NULL; |
| 1407 | if (size == 32) m = "sha256"; | 1512 | if (name) |
| 1408 | else if (size == 20) m = "sha1"; | 1513 | m = name; |
| 1409 | else if (size == 16) m = "md5"; | ||
| 1410 | else if (size == 8) m = "crc64"; | ||
| 1411 | else if (size == 4) m = "crc32"; | ||
| 1412 | else | 1514 | else |
| 1515 | { | ||
| 1516 | if (size == 64) m = "sha512"; | ||
| 1517 | else if (size == 48) m = "sha384"; | ||
| 1518 | else if (size == 32) m = "sha256"; | ||
| 1519 | else if (size == 28) m = "sha224"; | ||
| 1520 | else if (size == 20) m = "sha1"; | ||
| 1521 | else if (shaVersion < 0) | ||
| 1522 | { | ||
| 1523 | if (size == 16) m = "md5"; | ||
| 1524 | else if (size == 8) m = "crc64"; | ||
| 1525 | else if (size == 4) m = "crc32"; | ||
| 1526 | } | ||
| 1527 | } | ||
| 1528 | |||
| 1529 | if (!m) | ||
| 1413 | return; | 1530 | return; |
| 1414 | #ifdef Z7_EXTERNAL_CODECS | 1531 | |
| 1532 | #ifdef Z7_EXTERNAL_CODECS | ||
| 1415 | const CExternalCodecs *_externalCodecs = g_ExternalCodecs_Ptr; | 1533 | const CExternalCodecs *_externalCodecs = g_ExternalCodecs_Ptr; |
| 1416 | #endif | 1534 | #endif |
| 1417 | CMethodId id; | 1535 | CMethodId id; |
| 1418 | if (FindHashMethod(EXTERNAL_CODECS_LOC_VARS | 1536 | if (FindHashMethod(EXTERNAL_CODECS_LOC_VARS |
| 1419 | AString(m), id)) | 1537 | AString(m), id)) |
| @@ -1444,15 +1562,15 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, | |||
| 1444 | CHashBundle hb_Glob; | 1562 | CHashBundle hb_Glob; |
| 1445 | // UStringVector methods = options.Methods; | 1563 | // UStringVector methods = options.Methods; |
| 1446 | UStringVector methods; | 1564 | UStringVector methods; |
| 1447 | 1565 | ||
| 1448 | if (methods.IsEmpty() && !_nameExtenstion.IsEmpty()) | 1566 | /* |
| 1567 | if (methods.IsEmpty() && !utf_nameExtenstion.IsEmpty() && !_hashSize_Defined) | ||
| 1449 | { | 1568 | { |
| 1450 | AString utf; | ||
| 1451 | ConvertUnicodeToUTF8(_nameExtenstion, utf); | ||
| 1452 | CMethodId id; | 1569 | CMethodId id; |
| 1453 | if (FindHashMethod(EXTERNAL_CODECS_LOC_VARS utf, id)) | 1570 | if (FindHashMethod(EXTERNAL_CODECS_LOC_VARS utf_nameExtenstion, id)) |
| 1454 | methods.Add(_nameExtenstion); | 1571 | methods.Add(_nameExtenstion); |
| 1455 | } | 1572 | } |
| 1573 | */ | ||
| 1456 | 1574 | ||
| 1457 | if (methods.IsEmpty() && !_pgpMethod.IsEmpty()) | 1575 | if (methods.IsEmpty() && !_pgpMethod.IsEmpty()) |
| 1458 | { | 1576 | { |
| @@ -1461,12 +1579,21 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, | |||
| 1461 | methods.Add(UString(_pgpMethod)); | 1579 | methods.Add(UString(_pgpMethod)); |
| 1462 | } | 1580 | } |
| 1463 | 1581 | ||
| 1582 | /* | ||
| 1464 | if (methods.IsEmpty() && _pgpMethod.IsEmpty() && _hashSize_Defined) | 1583 | if (methods.IsEmpty() && _pgpMethod.IsEmpty() && _hashSize_Defined) |
| 1465 | AddDefaultMethod(methods, _hashSize); | 1584 | { |
| 1585 | AddDefaultMethod(methods, | ||
| 1586 | utf_nameExtenstion.IsEmpty() ? NULL : utf_nameExtenstion.Ptr(), | ||
| 1587 | _hashSize); | ||
| 1588 | } | ||
| 1589 | */ | ||
| 1466 | 1590 | ||
| 1467 | RINOK(hb_Glob.SetMethods( | 1591 | if (!methods.IsEmpty()) |
| 1592 | { | ||
| 1593 | RINOK(hb_Glob.SetMethods( | ||
| 1468 | EXTERNAL_CODECS_LOC_VARS | 1594 | EXTERNAL_CODECS_LOC_VARS |
| 1469 | methods)) | 1595 | methods)) |
| 1596 | } | ||
| 1470 | 1597 | ||
| 1471 | Z7_DECL_CMyComPtr_QI_FROM( | 1598 | Z7_DECL_CMyComPtr_QI_FROM( |
| 1472 | IArchiveUpdateCallbackFile, | 1599 | IArchiveUpdateCallbackFile, |
| @@ -1561,9 +1688,11 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, | |||
| 1561 | { | 1688 | { |
| 1562 | hb_Use = &hb_Loc; | 1689 | hb_Use = &hb_Loc; |
| 1563 | CMethodId id; | 1690 | CMethodId id; |
| 1564 | if (FindHashMethod(EXTERNAL_CODECS_LOC_VARS hp.Method, id)) | 1691 | AString methodName = hp.Method; |
| 1692 | Convert_TagName_to_MethodName(methodName); | ||
| 1693 | if (FindHashMethod(EXTERNAL_CODECS_LOC_VARS methodName, id)) | ||
| 1565 | { | 1694 | { |
| 1566 | methods_loc.Add(UString(hp.Method)); | 1695 | methods_loc.Add(UString(methodName)); |
| 1567 | RINOK(hb_Loc.SetMethods( | 1696 | RINOK(hb_Loc.SetMethods( |
| 1568 | EXTERNAL_CODECS_LOC_VARS | 1697 | EXTERNAL_CODECS_LOC_VARS |
| 1569 | methods_loc)) | 1698 | methods_loc)) |
| @@ -1573,7 +1702,10 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, | |||
| 1573 | } | 1702 | } |
| 1574 | else if (methods.IsEmpty()) | 1703 | else if (methods.IsEmpty()) |
| 1575 | { | 1704 | { |
| 1576 | AddDefaultMethod(methods_loc, (unsigned)hp.Hash.Size()); | 1705 | AddDefaultMethod(methods_loc, |
| 1706 | _method_for_Extraction.IsEmpty() ? NULL : | ||
| 1707 | _method_for_Extraction.Ptr(), | ||
| 1708 | (unsigned)hp.Hash.Size()); | ||
| 1577 | if (!methods_loc.IsEmpty()) | 1709 | if (!methods_loc.IsEmpty()) |
| 1578 | { | 1710 | { |
| 1579 | hb_Use = &hb_Loc; | 1711 | hb_Use = &hb_Loc; |
| @@ -1621,7 +1753,7 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, | |||
| 1621 | Int32 opRes = NArchive::NExtract::NOperationResult::kUnsupportedMethod; | 1753 | Int32 opRes = NArchive::NExtract::NOperationResult::kUnsupportedMethod; |
| 1622 | if (isSupportedMode | 1754 | if (isSupportedMode |
| 1623 | && res_SetMethods != E_NOTIMPL | 1755 | && res_SetMethods != E_NOTIMPL |
| 1624 | && hb_Use->Hashers.Size() > 0 | 1756 | && !hb_Use->Hashers.IsEmpty() |
| 1625 | ) | 1757 | ) |
| 1626 | { | 1758 | { |
| 1627 | const CHasherState &hs = hb_Use->Hashers[0]; | 1759 | const CHasherState &hs = hb_Use->Hashers[0]; |
| @@ -1774,10 +1906,6 @@ Z7_COM7F_IMF(CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt | |||
| 1774 | methods.Add(_methods[k]); | 1906 | methods.Add(_methods[k]); |
| 1775 | } | 1907 | } |
| 1776 | } | 1908 | } |
| 1777 | else if (_crcSize_WasSet) | ||
| 1778 | { | ||
| 1779 | AddDefaultMethod(methods, _crcSize); | ||
| 1780 | } | ||
| 1781 | else | 1909 | else |
| 1782 | { | 1910 | { |
| 1783 | Z7_DECL_CMyComPtr_QI_FROM( | 1911 | Z7_DECL_CMyComPtr_QI_FROM( |
| @@ -1789,12 +1917,23 @@ Z7_COM7F_IMF(CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt | |||
| 1789 | RINOK(getRootProps->GetRootProp(kpidArcFileName, &prop)) | 1917 | RINOK(getRootProps->GetRootProp(kpidArcFileName, &prop)) |
| 1790 | if (prop.vt == VT_BSTR) | 1918 | if (prop.vt == VT_BSTR) |
| 1791 | { | 1919 | { |
| 1792 | const UString method = GetMethod_from_FileName(prop.bstrVal); | 1920 | AString method; |
| 1921 | /* const bool isKnownMethod = */ GetMethod_from_FileName(prop.bstrVal, method); | ||
| 1793 | if (!method.IsEmpty()) | 1922 | if (!method.IsEmpty()) |
| 1794 | methods.Add(method); | 1923 | { |
| 1924 | AddDefaultMethod(methods, method, _crcSize_WasSet ? _crcSize : 0); | ||
| 1925 | if (methods.IsEmpty()) | ||
| 1926 | return E_NOTIMPL; | ||
| 1927 | } | ||
| 1795 | } | 1928 | } |
| 1796 | } | 1929 | } |
| 1797 | } | 1930 | } |
| 1931 | if (methods.IsEmpty() && _crcSize_WasSet) | ||
| 1932 | { | ||
| 1933 | AddDefaultMethod(methods, | ||
| 1934 | NULL, // name | ||
| 1935 | _crcSize); | ||
| 1936 | } | ||
| 1798 | 1937 | ||
| 1799 | RINOK(hb.SetMethods(EXTERNAL_CODECS_LOC_VARS methods)) | 1938 | RINOK(hb.SetMethods(EXTERNAL_CODECS_LOC_VARS methods)) |
| 1800 | 1939 | ||
| @@ -2038,6 +2177,15 @@ HRESULT CHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value) | |||
| 2038 | } | 2177 | } |
| 2039 | 2178 | ||
| 2040 | 2179 | ||
| 2180 | void CHandler::InitProps() | ||
| 2181 | { | ||
| 2182 | _supportWindowsBackslash = true; | ||
| 2183 | _crcSize_WasSet = false; | ||
| 2184 | _crcSize = 4; | ||
| 2185 | _methods.Clear(); | ||
| 2186 | _options.Init_HashOptionsLocal(); | ||
| 2187 | } | ||
| 2188 | |||
| 2041 | Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)) | 2189 | Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)) |
| 2042 | { | 2190 | { |
| 2043 | COM_TRY_BEGIN | 2191 | COM_TRY_BEGIN |
| @@ -2088,22 +2236,27 @@ void Codecs_AddHashArcHandler(CCodecs *codecs) | |||
| 2088 | " sha512" | 2236 | " sha512" |
| 2089 | " sha384" | 2237 | " sha384" |
| 2090 | " sha224" | 2238 | " sha224" |
| 2091 | // " sha512-224" | 2239 | " sha512-224" |
| 2092 | // " sha512-256" | 2240 | " sha512-256" |
| 2093 | // " sha3-224" | 2241 | " sha3-224" |
| 2094 | " sha3-256" | 2242 | " sha3-256" |
| 2095 | // " sha3-384" | 2243 | " sha3-384" |
| 2096 | // " sha3-512" | 2244 | " sha3-512" |
| 2097 | // " shake128" | 2245 | // " shake128" |
| 2098 | // " shake256" | 2246 | // " shake256" |
| 2099 | " sha1" | 2247 | " sha1" |
| 2248 | " sha2" | ||
| 2249 | " sha3" | ||
| 2100 | " sha" | 2250 | " sha" |
| 2101 | " md5" | 2251 | " md5" |
| 2252 | " blake2s" | ||
| 2253 | " blake2b" | ||
| 2102 | " blake2sp" | 2254 | " blake2sp" |
| 2103 | " xxh64" | 2255 | " xxh64" |
| 2104 | " crc32 crc64" | 2256 | " crc32" |
| 2105 | " asc" | 2257 | " crc64" |
| 2106 | " cksum" | 2258 | " cksum" |
| 2259 | " asc" | ||
| 2107 | // " b2sum" | 2260 | // " b2sum" |
| 2108 | ), | 2261 | ), |
| 2109 | UString()); | 2262 | UString()); |
diff --git a/CPP/7zip/UI/Common/HashCalc.h b/CPP/7zip/UI/Common/HashCalc.h index 1e9dbf4..b8f867f 100644 --- a/CPP/7zip/UI/Common/HashCalc.h +++ b/CPP/7zip/UI/Common/HashCalc.h | |||
| @@ -279,32 +279,25 @@ Z7_CLASS_IMP_CHandler_IInArchive_3( | |||
| 279 | bool _isArc; | 279 | bool _isArc; |
| 280 | bool _supportWindowsBackslash; | 280 | bool _supportWindowsBackslash; |
| 281 | bool _crcSize_WasSet; | 281 | bool _crcSize_WasSet; |
| 282 | UInt64 _phySize; | ||
| 283 | CObjectVector<CHashPair> HashPairs; | ||
| 284 | UString _nameExtenstion; | ||
| 285 | // UString _method_fromName; | ||
| 286 | AString _pgpMethod; | ||
| 287 | bool _is_CksumMode; | 282 | bool _is_CksumMode; |
| 288 | bool _is_PgpMethod; | 283 | bool _is_PgpMethod; |
| 289 | bool _is_ZeroMode; | 284 | bool _is_ZeroMode; |
| 290 | bool _are_there_Tags; | 285 | bool _are_there_Tags; |
| 291 | bool _are_there_Dirs; | 286 | bool _are_there_Dirs; |
| 287 | bool _is_KnownMethod_in_FileName; | ||
| 292 | bool _hashSize_Defined; | 288 | bool _hashSize_Defined; |
| 293 | unsigned _hashSize; | 289 | unsigned _hashSize; |
| 294 | UInt32 _crcSize; | 290 | UInt32 _crcSize; |
| 291 | UInt64 _phySize; | ||
| 292 | CObjectVector<CHashPair> HashPairs; | ||
| 295 | UStringVector _methods; | 293 | UStringVector _methods; |
| 294 | AString _method_from_FileName; | ||
| 295 | AString _pgpMethod; | ||
| 296 | AString _method_for_Extraction; | ||
| 296 | CHashOptionsLocal _options; | 297 | CHashOptionsLocal _options; |
| 297 | 298 | ||
| 298 | void ClearVars(); | 299 | void ClearVars(); |
| 299 | 300 | void InitProps(); | |
| 300 | void InitProps() | ||
| 301 | { | ||
| 302 | _supportWindowsBackslash = true; | ||
| 303 | _crcSize_WasSet = false; | ||
| 304 | _crcSize = 4; | ||
| 305 | _methods.Clear(); | ||
| 306 | _options.Init_HashOptionsLocal(); | ||
| 307 | } | ||
| 308 | 301 | ||
| 309 | bool CanUpdate() const | 302 | bool CanUpdate() const |
| 310 | { | 303 | { |
diff --git a/CPP/7zip/UI/Common/LoadCodecs.cpp b/CPP/7zip/UI/Common/LoadCodecs.cpp index 6bf53ea..943435a 100644 --- a/CPP/7zip/UI/Common/LoadCodecs.cpp +++ b/CPP/7zip/UI/Common/LoadCodecs.cpp | |||
| @@ -170,7 +170,7 @@ void CArcInfoEx::AddExts(const UString &ext, const UString &addExt) | |||
| 170 | if (i < addExts.Size()) | 170 | if (i < addExts.Size()) |
| 171 | { | 171 | { |
| 172 | extInfo.AddExt = addExts[i]; | 172 | extInfo.AddExt = addExts[i]; |
| 173 | if (extInfo.AddExt == L"*") | 173 | if (extInfo.AddExt.IsEqualTo("*")) |
| 174 | extInfo.AddExt.Empty(); | 174 | extInfo.AddExt.Empty(); |
| 175 | } | 175 | } |
| 176 | Exts.Add(extInfo); | 176 | Exts.Add(extInfo); |
| @@ -931,8 +931,8 @@ bool CCodecs::FindFormatForArchiveType(const UString &arcType, CIntVector &forma | |||
| 931 | const UString name = arcType.Mid(pos, (unsigned)pos2 - pos); | 931 | const UString name = arcType.Mid(pos, (unsigned)pos2 - pos); |
| 932 | if (name.IsEmpty()) | 932 | if (name.IsEmpty()) |
| 933 | return false; | 933 | return false; |
| 934 | int index = FindFormatForArchiveType(name); | 934 | const int index = FindFormatForArchiveType(name); |
| 935 | if (index < 0 && name != L"*") | 935 | if (index < 0 && !name.IsEqualTo("*")) |
| 936 | { | 936 | { |
| 937 | formatIndices.Clear(); | 937 | formatIndices.Clear(); |
| 938 | return false; | 938 | return false; |
diff --git a/CPP/7zip/UI/Common/Update.cpp b/CPP/7zip/UI/Common/Update.cpp index b959a3c..1c2754e 100644 --- a/CPP/7zip/UI/Common/Update.cpp +++ b/CPP/7zip/UI/Common/Update.cpp | |||
| @@ -474,7 +474,7 @@ static HRESULT Compress( | |||
| 474 | 474 | ||
| 475 | CArcToDoStat stat2; | 475 | CArcToDoStat stat2; |
| 476 | 476 | ||
| 477 | if (options.RenamePairs.Size() != 0) | 477 | if (options.RenameMode || options.RenamePairs.Size() != 0) |
| 478 | { | 478 | { |
| 479 | FOR_VECTOR (i, arcItems) | 479 | FOR_VECTOR (i, arcItems) |
| 480 | { | 480 | { |
| @@ -1920,7 +1920,7 @@ Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION | |||
| 1920 | if (NFind::DoesDirExist(phyPath)) | 1920 | if (NFind::DoesDirExist(phyPath)) |
| 1921 | { | 1921 | { |
| 1922 | RINOK(callback->DeletingAfterArchiving(phyPath, true)) | 1922 | RINOK(callback->DeletingAfterArchiving(phyPath, true)) |
| 1923 | RemoveDir(phyPath); | 1923 | RemoveDirAlways_if_Empty(phyPath); |
| 1924 | } | 1924 | } |
| 1925 | } | 1925 | } |
| 1926 | 1926 | ||
diff --git a/CPP/7zip/UI/Common/Update.h b/CPP/7zip/UI/Common/Update.h index 216339a..ae141e5 100644 --- a/CPP/7zip/UI/Common/Update.h +++ b/CPP/7zip/UI/Common/Update.h | |||
| @@ -94,6 +94,7 @@ struct CUpdateOptions | |||
| 94 | 94 | ||
| 95 | bool DeleteAfterCompressing; | 95 | bool DeleteAfterCompressing; |
| 96 | bool SetArcMTime; | 96 | bool SetArcMTime; |
| 97 | bool RenameMode; | ||
| 97 | 98 | ||
| 98 | CBoolPair NtSecurity; | 99 | CBoolPair NtSecurity; |
| 99 | CBoolPair AltStreams; | 100 | CBoolPair AltStreams; |
| @@ -139,6 +140,7 @@ struct CUpdateOptions | |||
| 139 | 140 | ||
| 140 | DeleteAfterCompressing(false), | 141 | DeleteAfterCompressing(false), |
| 141 | SetArcMTime(false), | 142 | SetArcMTime(false), |
| 143 | RenameMode(false), | ||
| 142 | 144 | ||
| 143 | ArcNameMode(k_ArcNameMode_Smart), | 145 | ArcNameMode(k_ArcNameMode_Smart), |
| 144 | PathMode(NWildcard::k_RelatPath) | 146 | PathMode(NWildcard::k_RelatPath) |
diff --git a/CPP/7zip/UI/Common/UpdateCallback.cpp b/CPP/7zip/UI/Common/UpdateCallback.cpp index d3ee639..e2f1866 100644 --- a/CPP/7zip/UI/Common/UpdateCallback.cpp +++ b/CPP/7zip/UI/Common/UpdateCallback.cpp | |||
| @@ -32,6 +32,7 @@ | |||
| 32 | #include "../../../Windows/PropVariant.h" | 32 | #include "../../../Windows/PropVariant.h" |
| 33 | 33 | ||
| 34 | #include "../../Common/StreamObjects.h" | 34 | #include "../../Common/StreamObjects.h" |
| 35 | #include "../../Archive/Common/ItemNameUtils.h" | ||
| 35 | 36 | ||
| 36 | #include "UpdateCallback.h" | 37 | #include "UpdateCallback.h" |
| 37 | 38 | ||
| @@ -306,7 +307,7 @@ Z7_COM7F_IMF(CArchiveUpdateCallback::GetRawProp(UInt32 index, PROPID propID, con | |||
| 306 | 307 | ||
| 307 | #if defined(_WIN32) && !defined(UNDER_CE) | 308 | #if defined(_WIN32) && !defined(UNDER_CE) |
| 308 | 309 | ||
| 309 | static UString GetRelativePath(const UString &to, const UString &from) | 310 | static UString GetRelativePath(const UString &to, const UString &from, bool isWSL) |
| 310 | { | 311 | { |
| 311 | UStringVector partsTo, partsFrom; | 312 | UStringVector partsTo, partsFrom; |
| 312 | SplitPathToParts(to, partsTo); | 313 | SplitPathToParts(to, partsTo); |
| @@ -324,11 +325,12 @@ static UString GetRelativePath(const UString &to, const UString &from) | |||
| 324 | 325 | ||
| 325 | if (i == 0) | 326 | if (i == 0) |
| 326 | { | 327 | { |
| 327 | #ifdef _WIN32 | 328 | #ifdef _WIN32 |
| 328 | if (NName::IsDrivePath(to) || | 329 | if (isWSL || |
| 329 | NName::IsDrivePath(from)) | 330 | (NName::IsDrivePath(to) || |
| 331 | NName::IsDrivePath(from))) | ||
| 330 | return to; | 332 | return to; |
| 331 | #endif | 333 | #endif |
| 332 | } | 334 | } |
| 333 | 335 | ||
| 334 | UString s; | 336 | UString s; |
| @@ -373,54 +375,87 @@ Z7_COM7F_IMF(CArchiveUpdateCallback::GetProperty(UInt32 index, PROPID propID, PR | |||
| 373 | return S_OK; | 375 | return S_OK; |
| 374 | } | 376 | } |
| 375 | 377 | ||
| 376 | #if !defined(UNDER_CE) | 378 | #if !defined(UNDER_CE) |
| 377 | |||
| 378 | if (up.DirIndex >= 0) | 379 | if (up.DirIndex >= 0) |
| 379 | { | 380 | { |
| 380 | const CDirItem &di = DirItems->Items[(unsigned)up.DirIndex]; | 381 | const CDirItem &di = DirItems->Items[(unsigned)up.DirIndex]; |
| 381 | 382 | if (di.ReparseData.Size()) | |
| 382 | #ifdef _WIN32 | ||
| 383 | // if (di.IsDir()) | ||
| 384 | { | 383 | { |
| 384 | #ifdef _WIN32 | ||
| 385 | CReparseAttr attr; | 385 | CReparseAttr attr; |
| 386 | if (attr.Parse(di.ReparseData, di.ReparseData.Size())) | 386 | if (attr.Parse(di.ReparseData, di.ReparseData.Size())) |
| 387 | { | 387 | { |
| 388 | const UString simpleName = attr.GetPath(); | 388 | UString path = attr.GetPath(); |
| 389 | if (!attr.IsSymLink_WSL() && attr.IsRelative_Win()) | 389 | if (!path.IsEmpty()) |
| 390 | prop = simpleName; | ||
| 391 | else | ||
| 392 | { | 390 | { |
| 393 | const FString phyPath = DirItems->GetPhyPath((unsigned)up.DirIndex); | 391 | bool isWSL = attr.IsSymLink_WSL(); |
| 394 | FString fullPath; | 392 | if (isWSL) |
| 395 | if (NDir::MyGetFullPathName(phyPath, fullPath)) | 393 | NArchive::NItemName::ReplaceToWinSlashes(path, true); // useBackslashReplacement |
| 394 | // it's expected that (path) now uses windows slashes. | ||
| 395 | // CReparseAttr::IsRelative_Win() returns true if FLAG_RELATIVE is set | ||
| 396 | // CReparseAttr::IsRelative_Win() returns true for "\dir1\path" | ||
| 397 | // but we want to store real relative paths without "\" root prefix. | ||
| 398 | // so we parse path instead of IsRelative_Win() calling. | ||
| 399 | if (// attr.IsRelative_Win() || | ||
| 400 | (isWSL ? | ||
| 401 | IS_PATH_SEPAR(path[0]) : | ||
| 402 | NName::IsAbsolutePath(path))) | ||
| 396 | { | 403 | { |
| 397 | prop = GetRelativePath(simpleName, fs2us(fullPath)); | 404 | // (path) is abolute path or relative to root: "\path" |
| 405 | // we try to convert (path) to relative path for writing to archive. | ||
| 406 | const FString phyPath = DirItems->GetPhyPath((unsigned)up.DirIndex); | ||
| 407 | FString fullPath; | ||
| 408 | if (NDir::MyGetFullPathName(phyPath, fullPath)) | ||
| 409 | { | ||
| 410 | if (IS_PATH_SEPAR(path[0]) && | ||
| 411 | !IS_PATH_SEPAR(path[1])) | ||
| 412 | { | ||
| 413 | // path is relative to root of (fullPath): "\path" | ||
| 414 | const unsigned prefixSize = NName::GetRootPrefixSize(fullPath); | ||
| 415 | if (prefixSize) | ||
| 416 | { | ||
| 417 | path.DeleteFrontal(1); | ||
| 418 | path.Insert(0, fs2us(fullPath.Left(prefixSize))); | ||
| 419 | // we have changed "\" prefix to drive prefix "c:\" in (path). | ||
| 420 | // (path) is Windows path now. | ||
| 421 | isWSL = false; | ||
| 422 | } | ||
| 423 | } | ||
| 424 | } | ||
| 425 | path = GetRelativePath(path, fs2us(fullPath), isWSL); | ||
| 398 | } | 426 | } |
| 427 | #if WCHAR_PATH_SEPARATOR != L'/' | ||
| 428 | // 7-Zip's TAR handler in Windows replaces windows slashes to linux slashes. | ||
| 429 | // so we can return any slashes to TAR handler. | ||
| 430 | // or we can convert to linux slashes here, | ||
| 431 | // because input IInArchive handler uses linux slashes for kpidSymLink. | ||
| 432 | // path.Replace(WCHAR_PATH_SEPARATOR, L'/'); | ||
| 433 | #endif | ||
| 434 | if (!path.IsEmpty()) | ||
| 435 | prop = path; | ||
| 399 | } | 436 | } |
| 400 | prop.Detach(value); | ||
| 401 | return S_OK; | ||
| 402 | } | 437 | } |
| 403 | } | 438 | #else // ! _WIN32 |
| 404 | |||
| 405 | #else // _WIN32 | ||
| 406 | |||
| 407 | if (di.ReparseData.Size() != 0) | ||
| 408 | { | ||
| 409 | AString utf; | 439 | AString utf; |
| 410 | utf.SetFrom_CalcLen((const char *)(const Byte *)di.ReparseData, (unsigned)di.ReparseData.Size()); | 440 | utf.SetFrom_CalcLen((const char *)(const Byte *)di.ReparseData, (unsigned)di.ReparseData.Size()); |
| 411 | 441 | #if 0 // 0 - for debug | |
| 442 | // it's expected that link data uses system codepage. | ||
| 443 | // fs2us() ignores conversion errors. But we want correct path | ||
| 444 | UString us (fs2us(utf)); | ||
| 445 | #else | ||
| 412 | UString us; | 446 | UString us; |
| 413 | if (ConvertUTF8ToUnicode(utf, us)) | 447 | if (ConvertUTF8ToUnicode(utf, us)) |
| 448 | #endif | ||
| 414 | { | 449 | { |
| 415 | prop = us; | 450 | if (!us.IsEmpty()) |
| 416 | prop.Detach(value); | 451 | prop = us; |
| 417 | return S_OK; | ||
| 418 | } | 452 | } |
| 453 | #endif // ! _WIN32 | ||
| 419 | } | 454 | } |
| 420 | 455 | prop.Detach(value); | |
| 421 | #endif // _WIN32 | 456 | return S_OK; |
| 422 | } | 457 | } |
| 423 | #endif // !defined(UNDER_CE) | 458 | #endif // !defined(UNDER_CE) |
| 424 | } | 459 | } |
| 425 | else if (propID == kpidHardLink) | 460 | else if (propID == kpidHardLink) |
| 426 | { | 461 | { |
| @@ -428,7 +463,12 @@ Z7_COM7F_IMF(CArchiveUpdateCallback::GetProperty(UInt32 index, PROPID propID, PR | |||
| 428 | { | 463 | { |
| 429 | const CKeyKeyValPair &pair = _map[_hardIndex_To]; | 464 | const CKeyKeyValPair &pair = _map[_hardIndex_To]; |
| 430 | const CUpdatePair2 &up2 = (*UpdatePairs)[pair.Value]; | 465 | const CUpdatePair2 &up2 = (*UpdatePairs)[pair.Value]; |
| 431 | prop = DirItems->GetLogPath((unsigned)up2.DirIndex); | 466 | const UString path = DirItems->GetLogPath((unsigned)up2.DirIndex); |
| 467 | #if WCHAR_PATH_SEPARATOR != L'/' | ||
| 468 | // 7-Zip's TAR handler in Windows replaces windows slashes to linux slashes. | ||
| 469 | // path.Replace(WCHAR_PATH_SEPARATOR, L'/'); | ||
| 470 | #endif | ||
| 471 | prop = path; | ||
| 432 | prop.Detach(value); | 472 | prop.Detach(value); |
| 433 | return S_OK; | 473 | return S_OK; |
| 434 | } | 474 | } |
| @@ -438,7 +478,7 @@ Z7_COM7F_IMF(CArchiveUpdateCallback::GetProperty(UInt32 index, PROPID propID, PR | |||
| 438 | return S_OK; | 478 | return S_OK; |
| 439 | } | 479 | } |
| 440 | } | 480 | } |
| 441 | } | 481 | } // if (up.NewData) |
| 442 | 482 | ||
| 443 | if (up.IsAnti | 483 | if (up.IsAnti |
| 444 | && propID != kpidIsDir | 484 | && propID != kpidIsDir |
diff --git a/CPP/7zip/UI/Console/Main.cpp b/CPP/7zip/UI/Console/Main.cpp index dabd696..90e00a4 100644 --- a/CPP/7zip/UI/Console/Main.cpp +++ b/CPP/7zip/UI/Console/Main.cpp | |||
| @@ -908,9 +908,12 @@ int Main2( | |||
| 908 | 908 | ||
| 909 | if (options.EnableHeaders) | 909 | if (options.EnableHeaders) |
| 910 | { | 910 | { |
| 911 | ShowCopyrightAndHelp(g_StdStream, false); | 911 | if (g_StdStream) |
| 912 | if (!parser.Parse1Log.IsEmpty()) | 912 | { |
| 913 | *g_StdStream << parser.Parse1Log; | 913 | ShowCopyrightAndHelp(g_StdStream, false); |
| 914 | if (!parser.Parse1Log.IsEmpty()) | ||
| 915 | *g_StdStream << parser.Parse1Log; | ||
| 916 | } | ||
| 914 | } | 917 | } |
| 915 | 918 | ||
| 916 | parser.Parse2(options); | 919 | parser.Parse2(options); |
diff --git a/CPP/7zip/UI/Console/makefile b/CPP/7zip/UI/Console/makefile index a20b0cc..d449b38 100644 --- a/CPP/7zip/UI/Console/makefile +++ b/CPP/7zip/UI/Console/makefile | |||
| @@ -59,10 +59,10 @@ COMPRESS_OBJS = \ | |||
| 59 | C_OBJS = $(C_OBJS) \ | 59 | C_OBJS = $(C_OBJS) \ |
| 60 | $O\Alloc.obj \ | 60 | $O\Alloc.obj \ |
| 61 | $O\CpuArch.obj \ | 61 | $O\CpuArch.obj \ |
| 62 | $O\Sort.obj \ | ||
| 63 | $O\Threads.obj \ | 62 | $O\Threads.obj \ |
| 64 | 63 | ||
| 65 | !include "../../Crc.mak" | 64 | !include "../../Crc.mak" |
| 65 | !include "../../Sort.mak" | ||
| 66 | !include "Console.mak" | 66 | !include "Console.mak" |
| 67 | 67 | ||
| 68 | !include "../../7zip.mak" | 68 | !include "../../7zip.mak" |
diff --git a/CPP/7zip/UI/Explorer/makefile b/CPP/7zip/UI/Explorer/makefile index 3901d6b..311d70e 100644 --- a/CPP/7zip/UI/Explorer/makefile +++ b/CPP/7zip/UI/Explorer/makefile | |||
| @@ -72,7 +72,7 @@ FM_OBJS = \ | |||
| 72 | 72 | ||
| 73 | C_OBJS = \ | 73 | C_OBJS = \ |
| 74 | $O\CpuArch.obj \ | 74 | $O\CpuArch.obj \ |
| 75 | $O\Sort.obj \ | ||
| 76 | $O\Threads.obj \ | 75 | $O\Threads.obj \ |
| 77 | 76 | ||
| 77 | !include "../../Sort.mak" | ||
| 78 | !include "../../7zip.mak" | 78 | !include "../../7zip.mak" |
diff --git a/CPP/7zip/UI/Far/Plugin.cpp b/CPP/7zip/UI/Far/Plugin.cpp index 2d31b8a..b7f91d6 100644 --- a/CPP/7zip/UI/Far/Plugin.cpp +++ b/CPP/7zip/UI/Far/Plugin.cpp | |||
| @@ -61,7 +61,6 @@ static void MyGetFileTime(IFolderFolder *folder, UInt32 itemIndex, | |||
| 61 | } | 61 | } |
| 62 | 62 | ||
| 63 | #define kDotsReplaceString "[[..]]" | 63 | #define kDotsReplaceString "[[..]]" |
| 64 | #define kDotsReplaceStringU L"[[..]]" | ||
| 65 | 64 | ||
| 66 | static void CopyStrLimited(char *dest, const AString &src, unsigned len) | 65 | static void CopyStrLimited(char *dest, const AString &src, unsigned len) |
| 67 | { | 66 | { |
| @@ -84,7 +83,7 @@ void CPlugin::ReadPluginPanelItem(PluginPanelItem &panelItem, UInt32 itemIndex) | |||
| 84 | throw 272340; | 83 | throw 272340; |
| 85 | 84 | ||
| 86 | AString oemString (UnicodeStringToMultiByte(prop.bstrVal, CP_OEMCP)); | 85 | AString oemString (UnicodeStringToMultiByte(prop.bstrVal, CP_OEMCP)); |
| 87 | if (oemString == "..") | 86 | if (oemString.IsEqualTo("..")) |
| 88 | oemString = kDotsReplaceString; | 87 | oemString = kDotsReplaceString; |
| 89 | 88 | ||
| 90 | COPY_STR_LIMITED(panelItem.FindData.cFileName, oemString); | 89 | COPY_STR_LIMITED(panelItem.FindData.cFileName, oemString); |
| @@ -193,7 +192,7 @@ void CPlugin::EnterToDirectory(const UString &dirName) | |||
| 193 | { | 192 | { |
| 194 | CMyComPtr<IFolderFolder> newFolder; | 193 | CMyComPtr<IFolderFolder> newFolder; |
| 195 | UString s = dirName; | 194 | UString s = dirName; |
| 196 | if (dirName == kDotsReplaceStringU) | 195 | if (dirName.IsEqualTo(kDotsReplaceString)) |
| 197 | s = ".."; | 196 | s = ".."; |
| 198 | _folder->BindToFolder(s, &newFolder); | 197 | _folder->BindToFolder(s, &newFolder); |
| 199 | if (!newFolder) | 198 | if (!newFolder) |
| @@ -209,12 +208,12 @@ void CPlugin::EnterToDirectory(const UString &dirName) | |||
| 209 | int CPlugin::SetDirectory(const char *aszDir, int /* opMode */) | 208 | int CPlugin::SetDirectory(const char *aszDir, int /* opMode */) |
| 210 | { | 209 | { |
| 211 | UString path = MultiByteToUnicodeString(aszDir, CP_OEMCP); | 210 | UString path = MultiByteToUnicodeString(aszDir, CP_OEMCP); |
| 212 | if (path == WSTRING_PATH_SEPARATOR) | 211 | if (path.IsEqualTo(STRING_PATH_SEPARATOR)) |
| 213 | { | 212 | { |
| 214 | _folder.Release(); | 213 | _folder.Release(); |
| 215 | m_ArchiveHandler->BindToRootFolder(&_folder); | 214 | m_ArchiveHandler->BindToRootFolder(&_folder); |
| 216 | } | 215 | } |
| 217 | else if (path == L"..") | 216 | else if (path.IsEqualTo("..")) |
| 218 | { | 217 | { |
| 219 | CMyComPtr<IFolderFolder> newFolder; | 218 | CMyComPtr<IFolderFolder> newFolder; |
| 220 | _folder->BindToParentFolder(&newFolder); | 219 | _folder->BindToParentFolder(&newFolder); |
diff --git a/CPP/7zip/UI/Far/makefile b/CPP/7zip/UI/Far/makefile index a66f9d7..7bc166b 100644 --- a/CPP/7zip/UI/Far/makefile +++ b/CPP/7zip/UI/Far/makefile | |||
| @@ -99,9 +99,9 @@ COMPRESS_OBJS = \ | |||
| 99 | C_OBJS = \ | 99 | C_OBJS = \ |
| 100 | $O\Alloc.obj \ | 100 | $O\Alloc.obj \ |
| 101 | $O\CpuArch.obj \ | 101 | $O\CpuArch.obj \ |
| 102 | $O\Sort.obj \ | ||
| 103 | $O\Threads.obj \ | 102 | $O\Threads.obj \ |
| 104 | 103 | ||
| 105 | !include "../../Crc.mak" | 104 | !include "../../Crc.mak" |
| 105 | !include "../../Sort.mak" | ||
| 106 | 106 | ||
| 107 | !include "../../7zip.mak" | 107 | !include "../../7zip.mak" |
diff --git a/CPP/7zip/UI/FileManager/FM.cpp b/CPP/7zip/UI/FileManager/FM.cpp index 7310802..b2f4c2b 100644 --- a/CPP/7zip/UI/FileManager/FM.cpp +++ b/CPP/7zip/UI/FileManager/FM.cpp | |||
| @@ -651,7 +651,7 @@ static int WINAPI WinMain2(int nCmdShow) | |||
| 651 | SplitStringToTwoStrings(commandsString, paramString, tailString); | 651 | SplitStringToTwoStrings(commandsString, paramString, tailString); |
| 652 | paramString.Trim(); | 652 | paramString.Trim(); |
| 653 | tailString.Trim(); | 653 | tailString.Trim(); |
| 654 | if (tailString.IsPrefixedBy(L"-t")) | 654 | if (tailString.IsPrefixedBy("-t")) |
| 655 | g_ArcFormat = tailString.Ptr(2); | 655 | g_ArcFormat = tailString.Ptr(2); |
| 656 | 656 | ||
| 657 | /* | 657 | /* |
diff --git a/CPP/7zip/UI/FileManager/LangUtils.cpp b/CPP/7zip/UI/FileManager/LangUtils.cpp index 8fcb507..4712192 100644 --- a/CPP/7zip/UI/FileManager/LangUtils.cpp +++ b/CPP/7zip/UI/FileManager/LangUtils.cpp | |||
| @@ -309,15 +309,13 @@ void ReloadLang() | |||
| 309 | { | 309 | { |
| 310 | g_Lang.Clear(); | 310 | g_Lang.Clear(); |
| 311 | ReadRegLang(g_LangID); | 311 | ReadRegLang(g_LangID); |
| 312 | #ifndef _UNICODE | 312 | if (g_LangID.IsEmpty()) |
| 313 | if (g_IsNT) | ||
| 314 | #endif | ||
| 315 | { | 313 | { |
| 316 | if (g_LangID.IsEmpty()) | 314 | #ifndef _UNICODE |
| 317 | { | 315 | if (g_IsNT) |
| 316 | #endif | ||
| 318 | OpenDefaultLang(); | 317 | OpenDefaultLang(); |
| 319 | return; | 318 | return; |
| 320 | } | ||
| 321 | } | 319 | } |
| 322 | if (g_LangID.Len() > 1 || g_LangID[0] != L'-') | 320 | if (g_LangID.Len() > 1 || g_LangID[0] != L'-') |
| 323 | { | 321 | { |
diff --git a/CPP/7zip/UI/FileManager/LinkDialog.cpp b/CPP/7zip/UI/FileManager/LinkDialog.cpp index 0f24761..a92ee4d 100644 --- a/CPP/7zip/UI/FileManager/LinkDialog.cpp +++ b/CPP/7zip/UI/FileManager/LinkDialog.cpp | |||
| @@ -45,28 +45,24 @@ static bool GetSymLink(CFSTR path, CReparseAttr &attr, UString &errorMessage) | |||
| 45 | CByteBuffer buf; | 45 | CByteBuffer buf; |
| 46 | if (!NIO::GetReparseData(path, buf, NULL)) | 46 | if (!NIO::GetReparseData(path, buf, NULL)) |
| 47 | return false; | 47 | return false; |
| 48 | |||
| 49 | if (!attr.Parse(buf, buf.Size())) | 48 | if (!attr.Parse(buf, buf.Size())) |
| 50 | { | 49 | { |
| 51 | SetLastError(attr.ErrorCode); | 50 | SetLastError(attr.ErrorCode); |
| 52 | return false; | 51 | return false; |
| 53 | } | 52 | } |
| 54 | |||
| 55 | CByteBuffer data2; | 53 | CByteBuffer data2; |
| 56 | if (!FillLinkData(data2, attr.GetPath(), | 54 | FillLinkData(data2, attr.GetPath(), |
| 57 | !attr.IsMountPoint(), attr.IsSymLink_WSL())) | 55 | !attr.IsMountPoint(), attr.IsSymLink_WSL()); |
| 56 | if (data2.Size() == 0) | ||
| 58 | { | 57 | { |
| 59 | errorMessage = "Cannot reproduce reparse point"; | 58 | errorMessage = "Cannot reproduce reparse point"; |
| 60 | return false; | 59 | return false; |
| 61 | } | 60 | } |
| 62 | 61 | if (data2 != buf) | |
| 63 | if (data2.Size() != buf.Size() || | ||
| 64 | memcmp(data2, buf, buf.Size()) != 0) | ||
| 65 | { | 62 | { |
| 66 | errorMessage = "mismatch for reproduced reparse point"; | 63 | errorMessage = "mismatch for reproduced reparse point"; |
| 67 | return false; | 64 | return false; |
| 68 | } | 65 | } |
| 69 | |||
| 70 | return true; | 66 | return true; |
| 71 | } | 67 | } |
| 72 | 68 | ||
| @@ -113,8 +109,8 @@ bool CLinkDialog::OnInit() | |||
| 113 | const bool res = GetSymLink(us2fs(FilePath), attr, error); | 109 | const bool res = GetSymLink(us2fs(FilePath), attr, error); |
| 114 | if (!res && error.IsEmpty()) | 110 | if (!res && error.IsEmpty()) |
| 115 | { | 111 | { |
| 116 | DWORD lastError = GetLastError(); | 112 | const DWORD lastError = GetLastError(); |
| 117 | if (lastError != 0) | 113 | if (lastError) |
| 118 | error = NError::MyFormatMessage(lastError); | 114 | error = NError::MyFormatMessage(lastError); |
| 119 | } | 115 | } |
| 120 | 116 | ||
| @@ -319,10 +315,10 @@ void CLinkDialog::OnButton_Link() | |||
| 319 | return; | 315 | return; |
| 320 | } | 316 | } |
| 321 | 317 | ||
| 322 | const bool isSymLink = (idb != IDR_LINK_TYPE_JUNCTION); | ||
| 323 | |||
| 324 | CByteBuffer data; | 318 | CByteBuffer data; |
| 325 | if (!FillLinkData(data, to, isSymLink, isWSL)) | 319 | const bool isSymLink = (idb != IDR_LINK_TYPE_JUNCTION); |
| 320 | FillLinkData(data, to, isSymLink, isWSL); | ||
| 321 | if (data.Size() == 0) | ||
| 326 | { | 322 | { |
| 327 | ShowError(L"Incorrect link"); | 323 | ShowError(L"Incorrect link"); |
| 328 | return; | 324 | return; |
| @@ -386,6 +382,9 @@ void CApp::Link() | |||
| 386 | path = destPanel.GetFsPath(); | 382 | path = destPanel.GetFsPath(); |
| 387 | } | 383 | } |
| 388 | 384 | ||
| 385 | CSelectedState srcSelState; | ||
| 386 | srcPanel.SaveSelectedState(srcSelState); | ||
| 387 | |||
| 389 | CLinkDialog dlg; | 388 | CLinkDialog dlg; |
| 390 | dlg.CurDirPrefix = fsPrefix; | 389 | dlg.CurDirPrefix = fsPrefix; |
| 391 | dlg.FilePath = srcPath + itemName; | 390 | dlg.FilePath = srcPath + itemName; |
| @@ -394,7 +393,10 @@ void CApp::Link() | |||
| 394 | if (dlg.Create(srcPanel.GetParent()) != IDOK) | 393 | if (dlg.Create(srcPanel.GetParent()) != IDOK) |
| 395 | return; | 394 | return; |
| 396 | 395 | ||
| 397 | // fix it: we should refresh panel with changed link | 396 | // we refresh srcPanel to show changes in "Link" (kpidNtReparse) column. |
| 397 | // maybe we should refresh another panel also? | ||
| 398 | if (srcPanel._visibleColumns.FindItem_for_PropID(kpidNtReparse) >= 0) | ||
| 399 | srcPanel.RefreshListCtrl(srcSelState); | ||
| 398 | 400 | ||
| 399 | RefreshTitleAlways(); | 401 | RefreshTitleAlways(); |
| 400 | } | 402 | } |
diff --git a/CPP/7zip/UI/FileManager/Panel.h b/CPP/7zip/UI/FileManager/Panel.h index 9c53048..9ef0926 100644 --- a/CPP/7zip/UI/FileManager/Panel.h +++ b/CPP/7zip/UI/FileManager/Panel.h | |||
| @@ -711,8 +711,8 @@ public: | |||
| 711 | } | 711 | } |
| 712 | 712 | ||
| 713 | // bool IsFsOrDrivesFolder() const { return IsFSFolder() || IsFSDrivesFolder(); } | 713 | // bool IsFsOrDrivesFolder() const { return IsFSFolder() || IsFSDrivesFolder(); } |
| 714 | bool IsDeviceDrivesPrefix() const { return _currentFolderPrefix == L"\\\\.\\"; } | 714 | bool IsDeviceDrivesPrefix() const { return _currentFolderPrefix.IsEqualTo("\\\\.\\"); } |
| 715 | bool IsSuperDrivesPrefix() const { return _currentFolderPrefix == L"\\\\?\\"; } | 715 | bool IsSuperDrivesPrefix() const { return _currentFolderPrefix.IsEqualTo("\\\\?\\"); } |
| 716 | 716 | ||
| 717 | /* | 717 | /* |
| 718 | c:\Dir | 718 | c:\Dir |
diff --git a/CPP/7zip/UI/FileManager/PanelCopy.cpp b/CPP/7zip/UI/FileManager/PanelCopy.cpp index d4f1db7..f070be9 100644 --- a/CPP/7zip/UI/FileManager/PanelCopy.cpp +++ b/CPP/7zip/UI/FileManager/PanelCopy.cpp | |||
| @@ -284,7 +284,7 @@ HRESULT CPanel::CopyTo(CCopyToOptions &options, | |||
| 284 | if (options.hashMethods.Size() == 1) | 284 | if (options.hashMethods.Size() == 1) |
| 285 | { | 285 | { |
| 286 | const UString &s = options.hashMethods[0]; | 286 | const UString &s = options.hashMethods[0]; |
| 287 | if (s != L"*") | 287 | if (!s.IsEqualTo("*")) |
| 288 | title = s; | 288 | title = s; |
| 289 | } | 289 | } |
| 290 | } | 290 | } |
diff --git a/CPP/7zip/UI/FileManager/PanelFolderChange.cpp b/CPP/7zip/UI/FileManager/PanelFolderChange.cpp index c34cb74..b0fb53e 100644 --- a/CPP/7zip/UI/FileManager/PanelFolderChange.cpp +++ b/CPP/7zip/UI/FileManager/PanelFolderChange.cpp | |||
| @@ -428,7 +428,7 @@ void CPanel::LoadFullPathAndShow() | |||
| 428 | UString name_Computer = RootFolder_GetName_Computer(iconIndex); | 428 | UString name_Computer = RootFolder_GetName_Computer(iconIndex); |
| 429 | name_Computer.Add_PathSepar(); | 429 | name_Computer.Add_PathSepar(); |
| 430 | if (path == name_Computer | 430 | if (path == name_Computer |
| 431 | || path == L"\\\\?\\") | 431 | || path.IsEqualTo("\\\\?\\")) |
| 432 | item.iImage = iconIndex; | 432 | item.iImage = iconIndex; |
| 433 | else | 433 | else |
| 434 | { | 434 | { |
| @@ -639,7 +639,7 @@ bool CPanel::OnComboBoxCommand(UINT code, LPARAM /* param */, LRESULT &result) | |||
| 639 | unsigned indent = 0; | 639 | unsigned indent = 0; |
| 640 | { | 640 | { |
| 641 | UString path = _currentFolderPrefix; | 641 | UString path = _currentFolderPrefix; |
| 642 | // path = L"\\\\.\\y:\\"; // for debug | 642 | // path = "\\\\.\\y:\\"; // for debug |
| 643 | UString prefix0; | 643 | UString prefix0; |
| 644 | if (path.IsPrefixedBy_Ascii_NoCase("\\\\")) | 644 | if (path.IsPrefixedBy_Ascii_NoCase("\\\\")) |
| 645 | { | 645 | { |
| @@ -702,7 +702,7 @@ bool CPanel::OnComboBoxCommand(UINT code, LPARAM /* param */, LRESULT &result) | |||
| 702 | int iconIndex_Computer; | 702 | int iconIndex_Computer; |
| 703 | const UString name_Computer = RootFolder_GetName_Computer(iconIndex_Computer); | 703 | const UString name_Computer = RootFolder_GetName_Computer(iconIndex_Computer); |
| 704 | 704 | ||
| 705 | // const bool is_devicePrefix = (sumPath == L"\\\\.\\"); | 705 | // const bool is_devicePrefix = (sumPath.IsEqualTo("\\\\.\\")); |
| 706 | 706 | ||
| 707 | if (pathParts.Size() > 1) | 707 | if (pathParts.Size() > 1) |
| 708 | if (!sumPath.IsEmpty() | 708 | if (!sumPath.IsEmpty() |
| @@ -901,8 +901,8 @@ UString CPanel::GetParentDirPrefix() const | |||
| 901 | { | 901 | { |
| 902 | s = _currentFolderPrefix; | 902 | s = _currentFolderPrefix; |
| 903 | s.DeleteBack(); | 903 | s.DeleteBack(); |
| 904 | if (s != L"\\\\." && | 904 | if (!s.IsEqualTo("\\\\.") && |
| 905 | s != L"\\\\?") | 905 | !s.IsEqualTo("\\\\?")) |
| 906 | { | 906 | { |
| 907 | int pos = s.ReverseFind_PathSepar(); | 907 | int pos = s.ReverseFind_PathSepar(); |
| 908 | if (pos >= 0) | 908 | if (pos >= 0) |
| @@ -935,8 +935,8 @@ void CPanel::OpenParentFolder() | |||
| 935 | } | 935 | } |
| 936 | else | 936 | else |
| 937 | */ | 937 | */ |
| 938 | if (focusedName != L"\\\\." && | 938 | if (!focusedName.IsEqualTo("\\\\.") && |
| 939 | focusedName != L"\\\\?") | 939 | !focusedName.IsEqualTo("\\\\?")) |
| 940 | { | 940 | { |
| 941 | const int pos = focusedName.ReverseFind_PathSepar(); | 941 | const int pos = focusedName.ReverseFind_PathSepar(); |
| 942 | if (pos >= 0) | 942 | if (pos >= 0) |
diff --git a/CPP/7zip/UI/FileManager/PanelOperations.cpp b/CPP/7zip/UI/FileManager/PanelOperations.cpp index 8b16224..427464b 100644 --- a/CPP/7zip/UI/FileManager/PanelOperations.cpp +++ b/CPP/7zip/UI/FileManager/PanelOperations.cpp | |||
| @@ -275,8 +275,8 @@ static bool IsCorrectFsName(const UString &name) | |||
| 275 | { | 275 | { |
| 276 | const UString lastPart = name.Ptr((unsigned)(name.ReverseFind_PathSepar() + 1)); | 276 | const UString lastPart = name.Ptr((unsigned)(name.ReverseFind_PathSepar() + 1)); |
| 277 | return | 277 | return |
| 278 | lastPart != L"." && | 278 | !lastPart.IsEqualTo(".") && |
| 279 | lastPart != L".."; | 279 | !lastPart.IsEqualTo(".."); |
| 280 | } | 280 | } |
| 281 | 281 | ||
| 282 | bool CorrectFsPath(const UString &relBase, const UString &path, UString &result); | 282 | bool CorrectFsPath(const UString &relBase, const UString &path, UString &result); |
diff --git a/CPP/7zip/UI/FileManager/RootFolder.cpp b/CPP/7zip/UI/FileManager/RootFolder.cpp index 192f660..b512f3b 100644 --- a/CPP/7zip/UI/FileManager/RootFolder.cpp +++ b/CPP/7zip/UI/FileManager/RootFolder.cpp | |||
| @@ -249,7 +249,7 @@ Z7_COM7F_IMF(CRootFolder::BindToFolder(const wchar_t *name, IFolderFolder **resu | |||
| 249 | AreEqualNames(name2, L"Documents")) | 249 | AreEqualNames(name2, L"Documents")) |
| 250 | return BindToFolder((UInt32)ROOT_INDEX_DOCUMENTS, resultFolder); | 250 | return BindToFolder((UInt32)ROOT_INDEX_DOCUMENTS, resultFolder); |
| 251 | #else | 251 | #else |
| 252 | if (name2 == WSTRING_PATH_SEPARATOR) | 252 | if (name2.IsEqualTo(STRING_PATH_SEPARATOR)) |
| 253 | return BindToFolder((UInt32)ROOT_INDEX_COMPUTER, resultFolder); | 253 | return BindToFolder((UInt32)ROOT_INDEX_COMPUTER, resultFolder); |
| 254 | #endif | 254 | #endif |
| 255 | 255 | ||
| @@ -257,7 +257,7 @@ Z7_COM7F_IMF(CRootFolder::BindToFolder(const wchar_t *name, IFolderFolder **resu | |||
| 257 | AreEqualNames(name2, L"Computer")) | 257 | AreEqualNames(name2, L"Computer")) |
| 258 | return BindToFolder((UInt32)ROOT_INDEX_COMPUTER, resultFolder); | 258 | return BindToFolder((UInt32)ROOT_INDEX_COMPUTER, resultFolder); |
| 259 | 259 | ||
| 260 | if (name2 == WSTRING_PATH_SEPARATOR) | 260 | if (name2.IsEqualTo(STRING_PATH_SEPARATOR)) |
| 261 | { | 261 | { |
| 262 | CMyComPtr<IFolderFolder> subFolder = this; | 262 | CMyComPtr<IFolderFolder> subFolder = this; |
| 263 | *resultFolder = subFolder.Detach(); | 263 | *resultFolder = subFolder.Detach(); |
diff --git a/CPP/7zip/UI/FileManager/makefile b/CPP/7zip/UI/FileManager/makefile index 0ca5caa..24dc4ca 100644 --- a/CPP/7zip/UI/FileManager/makefile +++ b/CPP/7zip/UI/FileManager/makefile | |||
| @@ -104,7 +104,7 @@ AR_COMMON_OBJS = \ | |||
| 104 | C_OBJS = $(C_OBJS) \ | 104 | C_OBJS = $(C_OBJS) \ |
| 105 | $O\Alloc.obj \ | 105 | $O\Alloc.obj \ |
| 106 | $O\CpuArch.obj \ | 106 | $O\CpuArch.obj \ |
| 107 | $O\Sort.obj \ | ||
| 108 | $O\Threads.obj \ | 107 | $O\Threads.obj \ |
| 109 | 108 | ||
| 109 | !include "../../Sort.mak" | ||
| 110 | !include "../../7zip.mak" | 110 | !include "../../7zip.mak" |
diff --git a/CPP/7zip/UI/GUI/BenchmarkDialog.cpp b/CPP/7zip/UI/GUI/BenchmarkDialog.cpp index ce5473a..1686c69 100644 --- a/CPP/7zip/UI/GUI/BenchmarkDialog.cpp +++ b/CPP/7zip/UI/GUI/BenchmarkDialog.cpp | |||
| @@ -1856,7 +1856,7 @@ HRESULT Benchmark( | |||
| 1856 | const CProperty &prop = props[i]; | 1856 | const CProperty &prop = props[i]; |
| 1857 | UString name = prop.Name; | 1857 | UString name = prop.Name; |
| 1858 | name.MakeLower_Ascii(); | 1858 | name.MakeLower_Ascii(); |
| 1859 | if (name.IsEqualTo_Ascii_NoCase("m") && prop.Value == L"*") | 1859 | if (name.IsEqualTo_Ascii_NoCase("m") && prop.Value.IsEqualTo("*")) |
| 1860 | { | 1860 | { |
| 1861 | bd.TotalMode = true; | 1861 | bd.TotalMode = true; |
| 1862 | continue; | 1862 | continue; |
| @@ -1865,7 +1865,7 @@ HRESULT Benchmark( | |||
| 1865 | NCOM::CPropVariant propVariant; | 1865 | NCOM::CPropVariant propVariant; |
| 1866 | if (!prop.Value.IsEmpty()) | 1866 | if (!prop.Value.IsEmpty()) |
| 1867 | ParseNumberString(prop.Value, propVariant); | 1867 | ParseNumberString(prop.Value, propVariant); |
| 1868 | if (name.IsPrefixedBy(L"mt")) | 1868 | if (name.IsPrefixedBy("mt")) |
| 1869 | { | 1869 | { |
| 1870 | #ifndef Z7_ST | 1870 | #ifndef Z7_ST |
| 1871 | RINOK(ParseMtProp(name.Ptr(2), propVariant, numCPUs, numThreads)) | 1871 | RINOK(ParseMtProp(name.Ptr(2), propVariant, numCPUs, numThreads)) |
diff --git a/CPP/7zip/UI/GUI/BenchmarkDialog.rc b/CPP/7zip/UI/GUI/BenchmarkDialog.rc index 3e73e46..5df7ff2 100644 --- a/CPP/7zip/UI/GUI/BenchmarkDialog.rc +++ b/CPP/7zip/UI/GUI/BenchmarkDialog.rc | |||
| @@ -81,7 +81,7 @@ BEGIN | |||
| 81 | 81 | ||
| 82 | LTEXT "&Number of CPU threads:", IDT_BENCH_NUM_THREADS, m, 30, g0xs, 8 | 82 | LTEXT "&Number of CPU threads:", IDT_BENCH_NUM_THREADS, m, 30, g0xs, 8 |
| 83 | COMBOBOX IDC_BENCH_NUM_THREADS, g1x, 29, g1xs, 140, MY_COMBO | 83 | COMBOBOX IDC_BENCH_NUM_THREADS, g1x, 29, g1xs, 140, MY_COMBO |
| 84 | LTEXT "", IDT_BENCH_HARDWARE_THREADS, gc2x, 30, g7xs, MY_TEXT_NOPREFIX | 84 | LTEXT "", IDT_BENCH_HARDWARE_THREADS, gc2x, 30, g7xs, 24, SS_NOPREFIX |
| 85 | 85 | ||
| 86 | RTEXT "Size", IDT_BENCH_SIZE, xSize, 54, sSize, MY_TEXT_NOPREFIX | 86 | RTEXT "Size", IDT_BENCH_SIZE, xSize, 54, sSize, MY_TEXT_NOPREFIX |
| 87 | RTEXT "CPU Usage", IDT_BENCH_USAGE_LABEL, xUsage, 54, sUsage, MY_TEXT_NOPREFIX | 87 | RTEXT "CPU Usage", IDT_BENCH_USAGE_LABEL, xUsage, 54, sUsage, MY_TEXT_NOPREFIX |
diff --git a/CPP/7zip/UI/GUI/CompressDialog.cpp b/CPP/7zip/UI/GUI/CompressDialog.cpp index 58f863e..85d7186 100644 --- a/CPP/7zip/UI/GUI/CompressDialog.cpp +++ b/CPP/7zip/UI/GUI/CompressDialog.cpp | |||
| @@ -2600,11 +2600,17 @@ void CCompressDialog::SetNumThreads2() | |||
| 2600 | UInt32 numAlgoThreadsMax = numHardwareThreads * 2; | 2600 | UInt32 numAlgoThreadsMax = numHardwareThreads * 2; |
| 2601 | const int methodID = GetMethodID(); | 2601 | const int methodID = GetMethodID(); |
| 2602 | 2602 | ||
| 2603 | switch (methodID) | 2603 | const bool isZip = IsZipFormat(); |
| 2604 | if (isZip) | ||
| 2605 | numAlgoThreadsMax = | ||
| 2606 | 8 << (sizeof(size_t) / 2); // 32 threads for 32-bit : 128 threads for 64-bit | ||
| 2607 | else if (IsXzFormat()) | ||
| 2608 | numAlgoThreadsMax = 256 * 2; | ||
| 2609 | else switch (methodID) | ||
| 2604 | { | 2610 | { |
| 2605 | case kLZMA: numAlgoThreadsMax = 2; break; | 2611 | case kLZMA: numAlgoThreadsMax = 2; break; |
| 2606 | case kLZMA2: numAlgoThreadsMax = 256; break; | 2612 | case kLZMA2: numAlgoThreadsMax = 256; break; |
| 2607 | case kBZip2: numAlgoThreadsMax = 32; break; | 2613 | case kBZip2: numAlgoThreadsMax = 64; break; |
| 2608 | // case kZSTD: numAlgoThreadsMax = num_ZSTD_threads_MAX; break; | 2614 | // case kZSTD: numAlgoThreadsMax = num_ZSTD_threads_MAX; break; |
| 2609 | case kCopy: | 2615 | case kCopy: |
| 2610 | case kPPMd: | 2616 | case kPPMd: |
| @@ -2613,17 +2619,6 @@ void CCompressDialog::SetNumThreads2() | |||
| 2613 | case kPPMdZip: | 2619 | case kPPMdZip: |
| 2614 | numAlgoThreadsMax = 1; | 2620 | numAlgoThreadsMax = 1; |
| 2615 | } | 2621 | } |
| 2616 | const bool isZip = IsZipFormat(); | ||
| 2617 | if (isZip) | ||
| 2618 | { | ||
| 2619 | numAlgoThreadsMax = | ||
| 2620 | #ifdef _WIN32 | ||
| 2621 | 64; // _WIN32 supports only 64 threads in one group. So no need for more threads here | ||
| 2622 | #else | ||
| 2623 | 128; | ||
| 2624 | #endif | ||
| 2625 | } | ||
| 2626 | |||
| 2627 | UInt32 autoThreads = numHardwareThreads; | 2622 | UInt32 autoThreads = numHardwareThreads; |
| 2628 | if (autoThreads > numAlgoThreadsMax) | 2623 | if (autoThreads > numAlgoThreadsMax) |
| 2629 | autoThreads = numAlgoThreadsMax; | 2624 | autoThreads = numAlgoThreadsMax; |
| @@ -3008,7 +3003,7 @@ UInt64 CCompressDialog::GetMemoryUsage_Threads_Dict_DecompMem(UInt32 numThreads, | |||
| 3008 | else | 3003 | else |
| 3009 | { | 3004 | { |
| 3010 | size += numBlockThreads * (size1 + chunkSize); | 3005 | size += numBlockThreads * (size1 + chunkSize); |
| 3011 | UInt32 numPackChunks = numBlockThreads + (numBlockThreads / 8) + 1; | 3006 | const UInt32 numPackChunks = numBlockThreads + (numBlockThreads / 8) + 1; |
| 3012 | if (chunkSize < ((UInt32)1 << 26)) numBlockThreads++; | 3007 | if (chunkSize < ((UInt32)1 << 26)) numBlockThreads++; |
| 3013 | if (chunkSize < ((UInt32)1 << 24)) numBlockThreads++; | 3008 | if (chunkSize < ((UInt32)1 << 24)) numBlockThreads++; |
| 3014 | if (chunkSize < ((UInt32)1 << 22)) numBlockThreads++; | 3009 | if (chunkSize < ((UInt32)1 << 22)) numBlockThreads++; |
diff --git a/CPP/7zip/UI/GUI/makefile b/CPP/7zip/UI/GUI/makefile index 22ae095..b879a5d 100644 --- a/CPP/7zip/UI/GUI/makefile +++ b/CPP/7zip/UI/GUI/makefile | |||
| @@ -141,10 +141,9 @@ C_OBJS = \ | |||
| 141 | $O\Alloc.obj \ | 141 | $O\Alloc.obj \ |
| 142 | $O\CpuArch.obj \ | 142 | $O\CpuArch.obj \ |
| 143 | $O\DllSecur.obj \ | 143 | $O\DllSecur.obj \ |
| 144 | $O\Sort.obj \ | ||
| 145 | $O\Threads.obj \ | 144 | $O\Threads.obj \ |
| 146 | 145 | ||
| 147 | !include "../../Crc.mak" | 146 | !include "../../Crc.mak" |
| 148 | 147 | !include "../../Sort.mak" | |
| 149 | 148 | ||
| 150 | !include "../../7zip.mak" | 149 | !include "../../7zip.mak" |
diff --git a/CPP/Build.mak b/CPP/Build.mak index afb7ae8..86cc2af 100644 --- a/CPP/Build.mak +++ b/CPP/Build.mak | |||
| @@ -111,7 +111,13 @@ CFLAGS = $(CFLAGS) -Zc:forScope | |||
| 111 | 111 | ||
| 112 | !IFNDEF UNDER_CE | 112 | !IFNDEF UNDER_CE |
| 113 | !IF "$(CC)" != "clang-cl" | 113 | !IF "$(CC)" != "clang-cl" |
| 114 | CFLAGS = $(CFLAGS) -MP4 | 114 | MP_NPROC = 16 |
| 115 | !IFDEF NUMBER_OF_PROCESSORS | ||
| 116 | !IF $(NUMBER_OF_PROCESSORS) < $(MP_NPROC) | ||
| 117 | MP_NPROC = $(NUMBER_OF_PROCESSORS) | ||
| 118 | !ENDIF | ||
| 119 | !ENDIF | ||
| 120 | CFLAGS = $(CFLAGS) -MP$(MP_NPROC) | ||
| 115 | !ENDIF | 121 | !ENDIF |
| 116 | !IFNDEF PLATFORM | 122 | !IFNDEF PLATFORM |
| 117 | # CFLAGS = $(CFLAGS) -arch:IA32 | 123 | # CFLAGS = $(CFLAGS) -arch:IA32 |
diff --git a/CPP/Common/MyString.cpp b/CPP/Common/MyString.cpp index b5f7e52..10e2331 100644 --- a/CPP/Common/MyString.cpp +++ b/CPP/Common/MyString.cpp | |||
| @@ -208,35 +208,6 @@ bool StringsAreEqualNoCase(const wchar_t *s1, const wchar_t *s2) throw() | |||
| 208 | 208 | ||
| 209 | // ---------- ASCII ---------- | 209 | // ---------- ASCII ---------- |
| 210 | 210 | ||
| 211 | bool AString::IsPrefixedBy_Ascii_NoCase(const char *s) const throw() | ||
| 212 | { | ||
| 213 | const char *s1 = _chars; | ||
| 214 | for (;;) | ||
| 215 | { | ||
| 216 | const char c2 = *s++; | ||
| 217 | if (c2 == 0) | ||
| 218 | return true; | ||
| 219 | const char c1 = *s1++; | ||
| 220 | if (MyCharLower_Ascii(c1) != | ||
| 221 | MyCharLower_Ascii(c2)) | ||
| 222 | return false; | ||
| 223 | } | ||
| 224 | } | ||
| 225 | |||
| 226 | bool UString::IsPrefixedBy_Ascii_NoCase(const char *s) const throw() | ||
| 227 | { | ||
| 228 | const wchar_t *s1 = _chars; | ||
| 229 | for (;;) | ||
| 230 | { | ||
| 231 | const char c2 = *s++; | ||
| 232 | if (c2 == 0) | ||
| 233 | return true; | ||
| 234 | const wchar_t c1 = *s1++; | ||
| 235 | if (MyCharLower_Ascii(c1) != (unsigned char)MyCharLower_Ascii(c2)) | ||
| 236 | return false; | ||
| 237 | } | ||
| 238 | } | ||
| 239 | |||
| 240 | bool StringsAreEqual_Ascii(const char *u, const char *a) throw() | 211 | bool StringsAreEqual_Ascii(const char *u, const char *a) throw() |
| 241 | { | 212 | { |
| 242 | for (;;) | 213 | for (;;) |
diff --git a/CPP/Common/MyString.h b/CPP/Common/MyString.h index ba9914e..639b874 100644 --- a/CPP/Common/MyString.h +++ b/CPP/Common/MyString.h | |||
| @@ -429,11 +429,11 @@ public: | |||
| 429 | // int CompareNoCase(const char *s) const { return MyStringCompareNoCase(_chars, s); } | 429 | // int CompareNoCase(const char *s) const { return MyStringCompareNoCase(_chars, s); } |
| 430 | // int CompareNoCase(const AString &s) const { return MyStringCompareNoCase(_chars, s._chars); } | 430 | // int CompareNoCase(const AString &s) const { return MyStringCompareNoCase(_chars, s._chars); } |
| 431 | bool IsPrefixedBy(const char *s) const { return IsString1PrefixedByString2(_chars, s); } | 431 | bool IsPrefixedBy(const char *s) const { return IsString1PrefixedByString2(_chars, s); } |
| 432 | bool IsPrefixedBy_Ascii_NoCase(const char *s) const throw(); | 432 | bool IsPrefixedBy_Ascii_NoCase(const char *s) const { return IsString1PrefixedByString2_NoCase_Ascii(_chars, s); } |
| 433 | 433 | ||
| 434 | bool IsAscii() const | 434 | bool IsAscii() const |
| 435 | { | 435 | { |
| 436 | unsigned len = Len(); | 436 | const unsigned len = Len(); |
| 437 | const char *s = _chars; | 437 | const char *s = _chars; |
| 438 | for (unsigned i = 0; i < len; i++) | 438 | for (unsigned i = 0; i < len; i++) |
| 439 | if ((unsigned char)s[i] >= 0x80) | 439 | if ((unsigned char)s[i] >= 0x80) |
| @@ -727,22 +727,23 @@ public: | |||
| 727 | // int CompareNoCase(const wchar_t *s) const { return MyStringCompareNoCase(_chars, s); } | 727 | // int CompareNoCase(const wchar_t *s) const { return MyStringCompareNoCase(_chars, s); } |
| 728 | // int CompareNoCase(const UString &s) const { return MyStringCompareNoCase(_chars, s._chars); } | 728 | // int CompareNoCase(const UString &s) const { return MyStringCompareNoCase(_chars, s._chars); } |
| 729 | bool IsPrefixedBy(const wchar_t *s) const { return IsString1PrefixedByString2(_chars, s); } | 729 | bool IsPrefixedBy(const wchar_t *s) const { return IsString1PrefixedByString2(_chars, s); } |
| 730 | bool IsPrefixedBy(const char *s) const { return IsString1PrefixedByString2(_chars, s); } | ||
| 730 | bool IsPrefixedBy_NoCase(const wchar_t *s) const { return IsString1PrefixedByString2_NoCase(_chars, s); } | 731 | bool IsPrefixedBy_NoCase(const wchar_t *s) const { return IsString1PrefixedByString2_NoCase(_chars, s); } |
| 731 | bool IsPrefixedBy_Ascii_NoCase(const char *s) const throw(); | 732 | bool IsPrefixedBy_Ascii_NoCase(const char *s) const { return IsString1PrefixedByString2_NoCase_Ascii(_chars, s); } |
| 732 | 733 | ||
| 733 | bool IsAscii() const | 734 | bool IsAscii() const |
| 734 | { | 735 | { |
| 735 | unsigned len = Len(); | 736 | const unsigned len = Len(); |
| 736 | const wchar_t *s = _chars; | 737 | const wchar_t *s = _chars; |
| 737 | for (unsigned i = 0; i < len; i++) | 738 | for (unsigned i = 0; i < len; i++) |
| 738 | if (s[i] >= 0x80) | 739 | if ((unsigned)(int)s[i] >= 0x80) |
| 739 | return false; | 740 | return false; |
| 740 | return true; | 741 | return true; |
| 741 | } | 742 | } |
| 742 | int Find(wchar_t c) const { return FindCharPosInString(_chars, c); } | 743 | int Find(wchar_t c) const { return FindCharPosInString(_chars, c); } |
| 743 | int Find(wchar_t c, unsigned startIndex) const | 744 | int Find(wchar_t c, unsigned startIndex) const |
| 744 | { | 745 | { |
| 745 | int pos = FindCharPosInString(_chars + startIndex, c); | 746 | const int pos = FindCharPosInString(_chars + startIndex, c); |
| 746 | return pos < 0 ? -1 : (int)startIndex + pos; | 747 | return pos < 0 ? -1 : (int)startIndex + pos; |
| 747 | } | 748 | } |
| 748 | 749 | ||
diff --git a/CPP/Common/MyXml.cpp b/CPP/Common/MyXml.cpp index cc891fc..8364aae 100644 --- a/CPP/Common/MyXml.cpp +++ b/CPP/Common/MyXml.cpp | |||
| @@ -24,7 +24,7 @@ static bool IsSpaceChar(char c) | |||
| 24 | int CXmlItem::FindProp(const char *propName) const throw() | 24 | int CXmlItem::FindProp(const char *propName) const throw() |
| 25 | { | 25 | { |
| 26 | FOR_VECTOR (i, Props) | 26 | FOR_VECTOR (i, Props) |
| 27 | if (Props[i].Name == propName) | 27 | if (Props[i].Name.IsEqualTo(propName)) |
| 28 | return (int)i; | 28 | return (int)i; |
| 29 | return -1; | 29 | return -1; |
| 30 | } | 30 | } |
| @@ -39,7 +39,7 @@ AString CXmlItem::GetPropVal(const char *propName) const | |||
| 39 | 39 | ||
| 40 | bool CXmlItem::IsTagged(const char *tag) const throw() | 40 | bool CXmlItem::IsTagged(const char *tag) const throw() |
| 41 | { | 41 | { |
| 42 | return (IsTag && Name == tag); | 42 | return (IsTag && Name.IsEqualTo(tag)); |
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | int CXmlItem::FindSubTag(const char *tag) const throw() | 45 | int CXmlItem::FindSubTag(const char *tag) const throw() |
diff --git a/CPP/Common/Sha3Reg.cpp b/CPP/Common/Sha3Reg.cpp index 95db25e..cd2e288 100644 --- a/CPP/Common/Sha3Reg.cpp +++ b/CPP/Common/Sha3Reg.cpp | |||
| @@ -58,7 +58,7 @@ Z7_COM7F_IMF2(UInt32, CSha3Hasher::GetDigestSize()) | |||
| 58 | static IHasher *CreateHasherSpec() \ | 58 | static IHasher *CreateHasherSpec() \ |
| 59 | { return new CSha3Hasher(digestSize / 8, isShake, \ | 59 | { return new CSha3Hasher(digestSize / 8, isShake, \ |
| 60 | SHA3_BLOCK_SIZE_FROM_DIGEST_SIZE(digestSize_for_blockSize / 8)); } \ | 60 | SHA3_BLOCK_SIZE_FROM_DIGEST_SIZE(digestSize_for_blockSize / 8)); } \ |
| 61 | static const CHasherInfo g_HasherInfo = { CreateHasherSpec, id, name, digestSize }; \ | 61 | static const CHasherInfo g_HasherInfo = { CreateHasherSpec, id, name, digestSize / 8 }; \ |
| 62 | struct REGISTER_HASHER_NAME(cls) { REGISTER_HASHER_NAME(cls)() { RegisterHasher(&g_HasherInfo); }}; \ | 62 | struct REGISTER_HASHER_NAME(cls) { REGISTER_HASHER_NAME(cls)() { RegisterHasher(&g_HasherInfo); }}; \ |
| 63 | static REGISTER_HASHER_NAME(cls) g_RegisterHasher; } | 63 | static REGISTER_HASHER_NAME(cls) g_RegisterHasher; } |
| 64 | 64 | ||
diff --git a/CPP/Common/Wildcard.cpp b/CPP/Common/Wildcard.cpp index 798cbd9..b561a89 100644 --- a/CPP/Common/Wildcard.cpp +++ b/CPP/Common/Wildcard.cpp | |||
| @@ -255,7 +255,8 @@ ForDir nonrec [0, M) same as ForBoth-File | |||
| 255 | 255 | ||
| 256 | bool CItem::AreAllAllowed() const | 256 | bool CItem::AreAllAllowed() const |
| 257 | { | 257 | { |
| 258 | return ForFile && ForDir && WildcardMatching && PathParts.Size() == 1 && PathParts.Front() == L"*"; | 258 | return ForFile && ForDir && WildcardMatching |
| 259 | && PathParts.Size() == 1 && PathParts.Front().IsEqualTo("*"); | ||
| 259 | } | 260 | } |
| 260 | 261 | ||
| 261 | bool CItem::CheckPath(const UStringVector &pathParts, bool isFile) const | 262 | bool CItem::CheckPath(const UStringVector &pathParts, bool isFile) const |
| @@ -542,7 +543,7 @@ unsigned GetNumPrefixParts_if_DrivePath(UStringVector &pathParts) | |||
| 542 | { | 543 | { |
| 543 | if (pathParts.Size() < 4 | 544 | if (pathParts.Size() < 4 |
| 544 | || !pathParts[1].IsEmpty() | 545 | || !pathParts[1].IsEmpty() |
| 545 | || pathParts[2] != L"?") | 546 | || !pathParts[2].IsEqualTo("?")) |
| 546 | return 0; | 547 | return 0; |
| 547 | testIndex = 3; | 548 | testIndex = 3; |
| 548 | } | 549 | } |
| @@ -574,11 +575,11 @@ static unsigned GetNumPrefixParts(const UStringVector &pathParts) | |||
| 574 | return 1; | 575 | return 1; |
| 575 | if (pathParts.Size() == 2) | 576 | if (pathParts.Size() == 2) |
| 576 | return 2; | 577 | return 2; |
| 577 | if (pathParts[2] == L".") | 578 | if (pathParts[2].IsEqualTo(".")) |
| 578 | return 3; | 579 | return 3; |
| 579 | 580 | ||
| 580 | unsigned networkParts = 2; | 581 | unsigned networkParts = 2; |
| 581 | if (pathParts[2] == L"?") | 582 | if (pathParts[2].IsEqualTo("?")) |
| 582 | { | 583 | { |
| 583 | if (pathParts.Size() == 3) | 584 | if (pathParts.Size() == 3) |
| 584 | return 3; | 585 | return 3; |
| @@ -642,7 +643,7 @@ void CCensor::AddItem(ECensorPathMode pathMode, bool include, const UString &pat | |||
| 642 | if (pathParts.Size() >= 3 | 643 | if (pathParts.Size() >= 3 |
| 643 | && pathParts[0].IsEmpty() | 644 | && pathParts[0].IsEmpty() |
| 644 | && pathParts[1].IsEmpty() | 645 | && pathParts[1].IsEmpty() |
| 645 | && pathParts[2] == L"?") | 646 | && pathParts[2].IsEqualTo("?")) |
| 646 | ignoreWildcardIndex = 2; | 647 | ignoreWildcardIndex = 2; |
| 647 | // #endif | 648 | // #endif |
| 648 | 649 | ||
| @@ -665,7 +666,7 @@ void CCensor::AddItem(ECensorPathMode pathMode, bool include, const UString &pat | |||
| 665 | for (unsigned i = numPrefixParts; i < pathParts.Size(); i++) | 666 | for (unsigned i = numPrefixParts; i < pathParts.Size(); i++) |
| 666 | { | 667 | { |
| 667 | const UString &part = pathParts[i]; | 668 | const UString &part = pathParts[i]; |
| 668 | if (part == L".." || part == L".") | 669 | if (part.IsEqualTo("..") || part.IsEqualTo(".")) |
| 669 | dotsIndex = (int)i; | 670 | dotsIndex = (int)i; |
| 670 | } | 671 | } |
| 671 | 672 | ||
diff --git a/CPP/Windows/FileDir.cpp b/CPP/Windows/FileDir.cpp index 2cb83b2..10c4e98 100644 --- a/CPP/Windows/FileDir.cpp +++ b/CPP/Windows/FileDir.cpp | |||
| @@ -651,6 +651,35 @@ bool RemoveDirWithSubItems(const FString &path) | |||
| 651 | return RemoveDir(path); | 651 | return RemoveDir(path); |
| 652 | } | 652 | } |
| 653 | 653 | ||
| 654 | bool RemoveDirAlways_if_Empty(const FString &path) | ||
| 655 | { | ||
| 656 | const DWORD attrib = NFind::GetFileAttrib(path); | ||
| 657 | if (attrib != INVALID_FILE_ATTRIBUTES | ||
| 658 | && (attrib & FILE_ATTRIBUTE_READONLY)) | ||
| 659 | { | ||
| 660 | bool need_ClearAttrib = true; | ||
| 661 | if ((attrib & FILE_ATTRIBUTE_REPARSE_POINT) == 0) | ||
| 662 | { | ||
| 663 | FString s (path); | ||
| 664 | s.Add_PathSepar(); | ||
| 665 | NFind::CEnumerator enumerator; | ||
| 666 | enumerator.SetDirPrefix(s); | ||
| 667 | NFind::CDirEntry fi; | ||
| 668 | if (enumerator.Next(fi)) | ||
| 669 | { | ||
| 670 | // we don't want to change attributes, if there are files | ||
| 671 | // in directory, because RemoveDir(path) will fail. | ||
| 672 | need_ClearAttrib = false; | ||
| 673 | // SetLastError(ERROR_DIR_NOT_EMPTY); | ||
| 674 | // return false; | ||
| 675 | } | ||
| 676 | } | ||
| 677 | if (need_ClearAttrib) | ||
| 678 | SetFileAttrib(path, 0); // we clear read-only attrib to remove read-only dir | ||
| 679 | } | ||
| 680 | return RemoveDir(path); | ||
| 681 | } | ||
| 682 | |||
| 654 | #endif // _WIN32 | 683 | #endif // _WIN32 |
| 655 | 684 | ||
| 656 | #ifdef UNDER_CE | 685 | #ifdef UNDER_CE |
diff --git a/CPP/Windows/FileDir.h b/CPP/Windows/FileDir.h index 74675ee..65e6368 100644 --- a/CPP/Windows/FileDir.h +++ b/CPP/Windows/FileDir.h | |||
| @@ -78,6 +78,11 @@ bool CreateComplexDir(CFSTR path); | |||
| 78 | 78 | ||
| 79 | bool DeleteFileAlways(CFSTR name); | 79 | bool DeleteFileAlways(CFSTR name); |
| 80 | bool RemoveDirWithSubItems(const FString &path); | 80 | bool RemoveDirWithSubItems(const FString &path); |
| 81 | #ifdef _WIN32 | ||
| 82 | bool RemoveDirAlways_if_Empty(const FString &path); | ||
| 83 | #else | ||
| 84 | #define RemoveDirAlways_if_Empty RemoveDir | ||
| 85 | #endif | ||
| 81 | 86 | ||
| 82 | bool MyGetFullPathName(CFSTR path, FString &resFullPath); | 87 | bool MyGetFullPathName(CFSTR path, FString &resFullPath); |
| 83 | bool GetFullPathAndSplit(CFSTR path, FString &resDirPrefix, FString &resFileName); | 88 | bool GetFullPathAndSplit(CFSTR path, FString &resDirPrefix, FString &resFileName); |
diff --git a/CPP/Windows/FileFind.cpp b/CPP/Windows/FileFind.cpp index ca387f6..64075ab 100644 --- a/CPP/Windows/FileFind.cpp +++ b/CPP/Windows/FileFind.cpp | |||
| @@ -731,7 +731,7 @@ bool CFileInfo::Find(CFSTR path, bool followLink) | |||
| 731 | bool isOK = false; | 731 | bool isOK = false; |
| 732 | if (finder.FindFirst(s, *this)) | 732 | if (finder.FindFirst(s, *this)) |
| 733 | { | 733 | { |
| 734 | if (Name == FTEXT(".")) | 734 | if (Name.IsEqualTo(".")) |
| 735 | { | 735 | { |
| 736 | Name = path + prefixSize; | 736 | Name = path + prefixSize; |
| 737 | return true; | 737 | return true; |
| @@ -769,6 +769,13 @@ bool CFileInfo::Find(CFSTR path, bool followLink) | |||
| 769 | 769 | ||
| 770 | // return FollowReparse(path, IsDir()); | 770 | // return FollowReparse(path, IsDir()); |
| 771 | return Fill_From_ByHandleFileInfo(path); | 771 | return Fill_From_ByHandleFileInfo(path); |
| 772 | /* | ||
| 773 | // Fill_From_ByHandleFileInfo returns false (with Access Denied error), | ||
| 774 | // if there is reparse link file (not directory reparse item). | ||
| 775 | if (Fill_From_ByHandleFileInfo(path)) | ||
| 776 | return true; | ||
| 777 | return HasReparsePoint(); | ||
| 778 | */ | ||
| 772 | } | 779 | } |
| 773 | 780 | ||
| 774 | bool CFileInfoBase::Fill_From_ByHandleFileInfo(CFSTR path) | 781 | bool CFileInfoBase::Fill_From_ByHandleFileInfo(CFSTR path) |
diff --git a/CPP/Windows/FileIO.h b/CPP/Windows/FileIO.h index 6ba40eb..26edef4 100644 --- a/CPP/Windows/FileIO.h +++ b/CPP/Windows/FileIO.h | |||
| @@ -11,8 +11,7 @@ | |||
| 11 | 11 | ||
| 12 | #define Z7_WIN_SYMLINK_FLAG_RELATIVE 1 | 12 | #define Z7_WIN_SYMLINK_FLAG_RELATIVE 1 |
| 13 | 13 | ||
| 14 | // what the meaning of that FLAG or field (2)? | 14 | #define Z7_WIN_LX_SYMLINK_VERSION_2 2 |
| 15 | #define Z7_WIN_LX_SYMLINK_FLAG 2 | ||
| 16 | 15 | ||
| 17 | #ifdef _WIN32 | 16 | #ifdef _WIN32 |
| 18 | 17 | ||
| @@ -44,7 +43,33 @@ namespace NWindows { | |||
| 44 | namespace NFile { | 43 | namespace NFile { |
| 45 | 44 | ||
| 46 | #if defined(_WIN32) && !defined(UNDER_CE) | 45 | #if defined(_WIN32) && !defined(UNDER_CE) |
| 47 | bool FillLinkData(CByteBuffer &dest, const wchar_t *path, bool isSymLink, bool isWSL); | 46 | /* |
| 47 | in: (CByteBuffer &dest) is empty | ||
| 48 | in: (path) uses Windows path separator (\). | ||
| 49 | out: (path) uses Linux path separator (/). | ||
| 50 | if (isAbsPath == true), then "c:\\" prefix is replaced to "/mnt/c/" prefix | ||
| 51 | */ | ||
| 52 | void Convert_WinPath_to_WslLinuxPath(FString &path, bool convertDrivePath); | ||
| 53 | // (path) must use Linux path separator (/). | ||
| 54 | void FillLinkData_WslLink(CByteBuffer &dest, const wchar_t *path); | ||
| 55 | |||
| 56 | /* | ||
| 57 | in: (CByteBuffer &dest) is empty | ||
| 58 | if (isSymLink == false) : MOUNT_POINT : (path) must be absolute. | ||
| 59 | if (isSymLink == true) : SYMLINK : Windows | ||
| 60 | (path) must use Windows path separator (\). | ||
| 61 | (path) must be without link "\\??\\" prefix. | ||
| 62 | link "\\??\\" prefix will be added inside FillLinkData(), if path is absolute. | ||
| 63 | */ | ||
| 64 | void FillLinkData_WinLink(CByteBuffer &dest, const wchar_t *path, bool isSymLink); | ||
| 65 | // in: (CByteBuffer &dest) is empty | ||
| 66 | inline void FillLinkData(CByteBuffer &dest, const wchar_t *path, bool isSymLink, bool isWSL) | ||
| 67 | { | ||
| 68 | if (isWSL) | ||
| 69 | FillLinkData_WslLink(dest, path); | ||
| 70 | else | ||
| 71 | FillLinkData_WinLink(dest, path, isSymLink); | ||
| 72 | } | ||
| 48 | #endif | 73 | #endif |
| 49 | 74 | ||
| 50 | struct CReparseShortInfo | 75 | struct CReparseShortInfo |
| @@ -61,7 +86,6 @@ struct CReparseAttr | |||
| 61 | UInt32 Flags; | 86 | UInt32 Flags; |
| 62 | UString SubsName; | 87 | UString SubsName; |
| 63 | UString PrintName; | 88 | UString PrintName; |
| 64 | |||
| 65 | AString WslName; | 89 | AString WslName; |
| 66 | 90 | ||
| 67 | bool HeaderError; | 91 | bool HeaderError; |
| @@ -71,8 +95,7 @@ struct CReparseAttr | |||
| 71 | 95 | ||
| 72 | CReparseAttr(): Tag(0), Flags(0) {} | 96 | CReparseAttr(): Tag(0), Flags(0) {} |
| 73 | 97 | ||
| 74 | // Parse() | 98 | // returns (true) and (ErrorCode = 0), if (it's correct known link) |
| 75 | // returns (true) and (ErrorCode = 0), if (it'a correct known link) | ||
| 76 | // returns (false) and (ErrorCode = ERROR_REPARSE_TAG_INVALID), if unknown tag | 99 | // returns (false) and (ErrorCode = ERROR_REPARSE_TAG_INVALID), if unknown tag |
| 77 | bool Parse(const Byte *p, size_t size); | 100 | bool Parse(const Byte *p, size_t size); |
| 78 | 101 | ||
| @@ -80,18 +103,14 @@ struct CReparseAttr | |||
| 80 | bool IsSymLink_Win() const { return Tag == Z7_WIN_IO_REPARSE_TAG_SYMLINK; } | 103 | bool IsSymLink_Win() const { return Tag == Z7_WIN_IO_REPARSE_TAG_SYMLINK; } |
| 81 | bool IsSymLink_WSL() const { return Tag == Z7_WIN_IO_REPARSE_TAG_LX_SYMLINK; } | 104 | bool IsSymLink_WSL() const { return Tag == Z7_WIN_IO_REPARSE_TAG_LX_SYMLINK; } |
| 82 | 105 | ||
| 106 | // note: "/dir1/path" is marked as relative. | ||
| 83 | bool IsRelative_Win() const { return Flags == Z7_WIN_SYMLINK_FLAG_RELATIVE; } | 107 | bool IsRelative_Win() const { return Flags == Z7_WIN_SYMLINK_FLAG_RELATIVE; } |
| 84 | 108 | ||
| 85 | bool IsRelative_WSL() const | 109 | bool IsRelative_WSL() const |
| 86 | { | 110 | { |
| 87 | if (WslName.IsEmpty()) | 111 | return WslName[0] != '/'; // WSL uses unix path separator |
| 88 | return true; | ||
| 89 | char c = WslName[0]; | ||
| 90 | return !IS_PATH_SEPAR(c); | ||
| 91 | } | 112 | } |
| 92 | 113 | ||
| 93 | // bool IsVolume() const; | ||
| 94 | |||
| 95 | bool IsOkNamePair() const; | 114 | bool IsOkNamePair() const; |
| 96 | UString GetPath() const; | 115 | UString GetPath() const; |
| 97 | }; | 116 | }; |
diff --git a/CPP/Windows/FileLink.cpp b/CPP/Windows/FileLink.cpp index bb380ec..2883c82 100644 --- a/CPP/Windows/FileLink.cpp +++ b/CPP/Windows/FileLink.cpp | |||
| @@ -39,12 +39,24 @@ namespace NFile { | |||
| 39 | using namespace NName; | 39 | using namespace NName; |
| 40 | 40 | ||
| 41 | /* | 41 | /* |
| 42 | Win10 Junctions/SymLinks: | ||
| 43 | - (/) slash doesn't work as path separator | ||
| 44 | - Win10 preinstalled junctions don't use tail backslash, but tail backslashes also work. | ||
| 45 | - double backslash works only after drive prefix "c:\\dir1\dir2\", | ||
| 46 | and doesn't work in another places. | ||
| 47 | - absolute path without \??\ prefix doesn't work | ||
| 48 | - absolute path "c:" doesn't work | ||
| 49 | */ | ||
| 50 | |||
| 51 | /* | ||
| 42 | Reparse Points (Junctions and Symbolic Links): | 52 | Reparse Points (Junctions and Symbolic Links): |
| 43 | struct | 53 | struct |
| 44 | { | 54 | { |
| 45 | UInt32 Tag; | 55 | UInt32 Tag; |
| 46 | UInt16 Size; // not including starting 8 bytes | 56 | UInt16 Size; // not including starting 8 bytes |
| 47 | UInt16 Reserved; // = 0 | 57 | UInt16 Reserved; // = 0, DOCs: // Length, in bytes, of the unparsed portion of |
| 58 | // the file name pointed to by the FileName member of the associated file object. | ||
| 59 | // This member is only valid for create operations when the I/O fails with STATUS_REPARSE. | ||
| 48 | 60 | ||
| 49 | UInt16 SubstituteOffset; // offset in bytes from start of namesChars | 61 | UInt16 SubstituteOffset; // offset in bytes from start of namesChars |
| 50 | UInt16 SubstituteLen; // size in bytes, it doesn't include tailed NUL | 62 | UInt16 SubstituteLen; // size in bytes, it doesn't include tailed NUL |
| @@ -68,6 +80,16 @@ using namespace NName; | |||
| 68 | 2) Default Order in table: | 80 | 2) Default Order in table: |
| 69 | Print Path | 81 | Print Path |
| 70 | Substitute Path | 82 | Substitute Path |
| 83 | |||
| 84 | DOCS: | ||
| 85 | The print name SHOULD be an informative pathname, suitable for display | ||
| 86 | to a user, that also identifies the target of the mount point. | ||
| 87 | Neither of these pathnames can contain dot directory names. | ||
| 88 | |||
| 89 | reparse tags, with the exception of IO_REPARSE_TAG_SYMLINK, | ||
| 90 | are processed on the server and are not processed by a client | ||
| 91 | after transmission over the wire. | ||
| 92 | Clients SHOULD treat associated reparse data as opaque data. | ||
| 71 | */ | 93 | */ |
| 72 | 94 | ||
| 73 | /* | 95 | /* |
| @@ -93,7 +115,8 @@ static const UInt32 kReparseFlags_Microsoft = ((UInt32)1 << 31); | |||
| 93 | #define Get16(p) GetUi16(p) | 115 | #define Get16(p) GetUi16(p) |
| 94 | #define Get32(p) GetUi32(p) | 116 | #define Get32(p) GetUi32(p) |
| 95 | 117 | ||
| 96 | static const wchar_t * const k_LinkPrefix = L"\\??\\"; | 118 | static const char * const k_LinkPrefix = "\\??\\"; |
| 119 | static const char * const k_LinkPrefix_UNC = "\\??\\UNC\\"; | ||
| 97 | static const unsigned k_LinkPrefix_Size = 4; | 120 | static const unsigned k_LinkPrefix_Size = 4; |
| 98 | 121 | ||
| 99 | static bool IsLinkPrefix(const wchar_t *s) | 122 | static bool IsLinkPrefix(const wchar_t *s) |
| @@ -102,7 +125,7 @@ static bool IsLinkPrefix(const wchar_t *s) | |||
| 102 | } | 125 | } |
| 103 | 126 | ||
| 104 | /* | 127 | /* |
| 105 | static const wchar_t * const k_VolumePrefix = L"Volume{"; | 128 | static const char * const k_VolumePrefix = "Volume{"; |
| 106 | static const bool IsVolumeName(const wchar_t *s) | 129 | static const bool IsVolumeName(const wchar_t *s) |
| 107 | { | 130 | { |
| 108 | return IsString1PrefixedByString2(s, k_VolumePrefix); | 131 | return IsString1PrefixedByString2(s, k_VolumePrefix); |
| @@ -118,7 +141,7 @@ static void WriteString(Byte *dest, const wchar_t *path) | |||
| 118 | { | 141 | { |
| 119 | for (;;) | 142 | for (;;) |
| 120 | { | 143 | { |
| 121 | wchar_t c = *path++; | 144 | const wchar_t c = *path++; |
| 122 | if (c == 0) | 145 | if (c == 0) |
| 123 | return; | 146 | return; |
| 124 | Set16(dest, (UInt16)c) | 147 | Set16(dest, (UInt16)c) |
| @@ -126,62 +149,103 @@ static void WriteString(Byte *dest, const wchar_t *path) | |||
| 126 | } | 149 | } |
| 127 | } | 150 | } |
| 128 | 151 | ||
| 129 | bool FillLinkData(CByteBuffer &dest, const wchar_t *path, bool isSymLink, bool isWSL) | 152 | #ifdef _WIN32 |
| 153 | void Convert_WinPath_to_WslLinuxPath(FString &s, bool convertDrivePath) | ||
| 130 | { | 154 | { |
| 131 | bool isAbs = IsAbsolutePath(path); | 155 | if (convertDrivePath && IsDrivePath(s)) |
| 132 | if (!isAbs && !isSymLink) | ||
| 133 | return false; | ||
| 134 | |||
| 135 | if (isWSL) | ||
| 136 | { | 156 | { |
| 137 | // unsupported characters probably use Replacement Character UTF-16 0xFFFD | 157 | FChar c = s[0]; |
| 138 | AString utf; | 158 | c = MyCharLower_Ascii(c); |
| 139 | ConvertUnicodeToUTF8(path, utf); | 159 | s.DeleteFrontal(2); |
| 140 | const size_t size = 4 + utf.Len(); | 160 | s.InsertAtFront(c); |
| 141 | if (size != (UInt16)size) | 161 | s.Insert(0, FTEXT("/mnt/")); |
| 142 | return false; | ||
| 143 | dest.Alloc(8 + size); | ||
| 144 | Byte *p = dest; | ||
| 145 | Set32(p, Z7_WIN_IO_REPARSE_TAG_LX_SYMLINK) | ||
| 146 | Set16(p + 4, (UInt16)(size)) | ||
| 147 | Set16(p + 6, 0) | ||
| 148 | Set32(p + 8, Z7_WIN_LX_SYMLINK_FLAG) | ||
| 149 | memcpy(p + 12, utf.Ptr(), utf.Len()); | ||
| 150 | return true; | ||
| 151 | } | 162 | } |
| 163 | s.Replace(FCHAR_PATH_SEPARATOR, FTEXT('/')); | ||
| 164 | } | ||
| 165 | #endif | ||
| 152 | 166 | ||
| 153 | // usual symbolic LINK (NOT WSL) | ||
| 154 | 167 | ||
| 155 | bool needPrintName = true; | 168 | static const unsigned k_Link_Size_Limit = 1u << 16; // 16-bit field is used for size. |
| 169 | |||
| 170 | void FillLinkData_WslLink(CByteBuffer &dest, const wchar_t *path) | ||
| 171 | { | ||
| 172 | // dest.Free(); // it's empty already | ||
| 173 | // WSL probably uses Replacement Character UTF-16 0xFFFD for unsupported characters? | ||
| 174 | AString utf; | ||
| 175 | ConvertUnicodeToUTF8(path, utf); | ||
| 176 | const unsigned size = 4 + utf.Len(); | ||
| 177 | if (size >= k_Link_Size_Limit) | ||
| 178 | return; | ||
| 179 | dest.Alloc(8 + size); | ||
| 180 | Byte *p = dest; | ||
| 181 | Set32(p, Z7_WIN_IO_REPARSE_TAG_LX_SYMLINK) | ||
| 182 | // Set32(p + 4, (UInt32)size) | ||
| 183 | Set16(p + 4, (UInt16)size) | ||
| 184 | Set16(p + 6, 0) | ||
| 185 | Set32(p + 8, Z7_WIN_LX_SYMLINK_VERSION_2) | ||
| 186 | memcpy(p + 12, utf.Ptr(), utf.Len()); | ||
| 187 | } | ||
| 188 | |||
| 156 | 189 | ||
| 157 | if (IsSuperPath(path)) | 190 | void FillLinkData_WinLink(CByteBuffer &dest, const wchar_t *path, bool isSymLink) |
| 191 | { | ||
| 192 | // dest.Free(); // it's empty already | ||
| 193 | bool isAbs = false; | ||
| 194 | if (IS_PATH_SEPAR(path[0])) | ||
| 158 | { | 195 | { |
| 159 | path += kSuperPathPrefixSize; | 196 | // root paths "\dir1\path" are marked as relative |
| 160 | if (!IsDrivePath(path)) | 197 | if (IS_PATH_SEPAR(path[1])) |
| 161 | needPrintName = false; | 198 | isAbs = true; |
| 199 | } | ||
| 200 | else | ||
| 201 | isAbs = IsAbsolutePath(path); | ||
| 202 | if (!isAbs && !isSymLink) | ||
| 203 | { | ||
| 204 | // Win10 allows us to create relative MOUNT_POINT. | ||
| 205 | // But relative MOUNT_POINT will not work when accessing it. | ||
| 206 | // So we prevent useless creation of a relative MOUNT_POINT. | ||
| 207 | return; | ||
| 162 | } | 208 | } |
| 163 | 209 | ||
| 164 | const unsigned add_Prefix_Len = isAbs ? k_LinkPrefix_Size : 0; | 210 | bool needPrintName = true; |
| 165 | 211 | UString subs (path); | |
| 212 | if (isAbs) | ||
| 213 | { | ||
| 214 | const bool isSuperPath = IsSuperPath(path); | ||
| 215 | if (!isSuperPath && NName::IsNetworkPath(us2fs(path))) | ||
| 216 | { | ||
| 217 | subs = k_LinkPrefix_UNC; | ||
| 218 | subs += (path + 2); | ||
| 219 | } | ||
| 220 | else | ||
| 221 | { | ||
| 222 | if (isSuperPath) | ||
| 223 | { | ||
| 224 | // we remove super prefix: | ||
| 225 | path += kSuperPathPrefixSize; | ||
| 226 | // we want to get correct abolute path in PrintName still. | ||
| 227 | if (!IsDrivePath(path)) | ||
| 228 | needPrintName = false; // we need "\\server\path" for print name. | ||
| 229 | } | ||
| 230 | subs = k_LinkPrefix; | ||
| 231 | subs += path; | ||
| 232 | } | ||
| 233 | } | ||
| 234 | const size_t len1 = subs.Len() * 2; | ||
| 166 | size_t len2 = (size_t)MyStringLen(path) * 2; | 235 | size_t len2 = (size_t)MyStringLen(path) * 2; |
| 167 | const size_t len1 = len2 + add_Prefix_Len * 2; | ||
| 168 | if (!needPrintName) | 236 | if (!needPrintName) |
| 169 | len2 = 0; | 237 | len2 = 0; |
| 170 | 238 | size_t totalNamesSize = len1 + len2; | |
| 171 | size_t totalNamesSize = (len1 + len2); | ||
| 172 | |||
| 173 | /* some WIM imagex software uses old scheme for symbolic links. | 239 | /* some WIM imagex software uses old scheme for symbolic links. |
| 174 | so we can old scheme for byte to byte compatibility */ | 240 | so we can use old scheme for byte to byte compatibility */ |
| 175 | 241 | const bool newOrderScheme = isSymLink; | |
| 176 | bool newOrderScheme = isSymLink; | ||
| 177 | // newOrderScheme = false; | 242 | // newOrderScheme = false; |
| 178 | |||
| 179 | if (!newOrderScheme) | 243 | if (!newOrderScheme) |
| 180 | totalNamesSize += 2 * 2; | 244 | totalNamesSize += 2 * 2; // we use NULL terminators in old scheme. |
| 181 | 245 | ||
| 182 | const size_t size = 8 + 8 + (isSymLink ? 4 : 0) + totalNamesSize; | 246 | const size_t size = 8 + 8 + (isSymLink ? 4 : 0) + totalNamesSize; |
| 183 | if (size != (UInt16)size) | 247 | if (size >= k_Link_Size_Limit) |
| 184 | return false; | 248 | return; |
| 185 | dest.Alloc(size); | 249 | dest.Alloc(size); |
| 186 | memset(dest, 0, size); | 250 | memset(dest, 0, size); |
| 187 | const UInt32 tag = isSymLink ? | 251 | const UInt32 tag = isSymLink ? |
| @@ -189,6 +253,7 @@ bool FillLinkData(CByteBuffer &dest, const wchar_t *path, bool isSymLink, bool i | |||
| 189 | Z7_WIN_IO_REPARSE_TAG_MOUNT_POINT; | 253 | Z7_WIN_IO_REPARSE_TAG_MOUNT_POINT; |
| 190 | Byte *p = dest; | 254 | Byte *p = dest; |
| 191 | Set32(p, tag) | 255 | Set32(p, tag) |
| 256 | // Set32(p + 4, (UInt32)(size - 8)) | ||
| 192 | Set16(p + 4, (UInt16)(size - 8)) | 257 | Set16(p + 4, (UInt16)(size - 8)) |
| 193 | Set16(p + 6, 0) | 258 | Set16(p + 6, 0) |
| 194 | p += 8; | 259 | p += 8; |
| @@ -204,21 +269,16 @@ bool FillLinkData(CByteBuffer &dest, const wchar_t *path, bool isSymLink, bool i | |||
| 204 | Set16(p + 2, (UInt16)len1) | 269 | Set16(p + 2, (UInt16)len1) |
| 205 | Set16(p + 4, (UInt16)printOffs) | 270 | Set16(p + 4, (UInt16)printOffs) |
| 206 | Set16(p + 6, (UInt16)len2) | 271 | Set16(p + 6, (UInt16)len2) |
| 207 | |||
| 208 | p += 8; | 272 | p += 8; |
| 209 | if (isSymLink) | 273 | if (isSymLink) |
| 210 | { | 274 | { |
| 211 | UInt32 flags = isAbs ? 0 : Z7_WIN_SYMLINK_FLAG_RELATIVE; | 275 | const UInt32 flags = isAbs ? 0 : Z7_WIN_SYMLINK_FLAG_RELATIVE; |
| 212 | Set32(p, flags) | 276 | Set32(p, flags) |
| 213 | p += 4; | 277 | p += 4; |
| 214 | } | 278 | } |
| 215 | 279 | WriteString(p + subOffs, subs); | |
| 216 | if (add_Prefix_Len != 0) | ||
| 217 | WriteString(p + subOffs, k_LinkPrefix); | ||
| 218 | WriteString(p + subOffs + add_Prefix_Len * 2, path); | ||
| 219 | if (needPrintName) | 280 | if (needPrintName) |
| 220 | WriteString(p + printOffs, path); | 281 | WriteString(p + printOffs, path); |
| 221 | return true; | ||
| 222 | } | 282 | } |
| 223 | 283 | ||
| 224 | #endif // defined(_WIN32) && !defined(UNDER_CE) | 284 | #endif // defined(_WIN32) && !defined(UNDER_CE) |
| @@ -230,7 +290,7 @@ static void GetString(const Byte *p, unsigned len, UString &res) | |||
| 230 | unsigned i; | 290 | unsigned i; |
| 231 | for (i = 0; i < len; i++) | 291 | for (i = 0; i < len; i++) |
| 232 | { | 292 | { |
| 233 | wchar_t c = Get16(p + i * 2); | 293 | const wchar_t c = Get16(p + (size_t)i * 2); |
| 234 | if (c == 0) | 294 | if (c == 0) |
| 235 | break; | 295 | break; |
| 236 | s[i] = c; | 296 | s[i] = c; |
| @@ -239,6 +299,7 @@ static void GetString(const Byte *p, unsigned len, UString &res) | |||
| 239 | res.ReleaseBuf_SetLen(i); | 299 | res.ReleaseBuf_SetLen(i); |
| 240 | } | 300 | } |
| 241 | 301 | ||
| 302 | |||
| 242 | bool CReparseAttr::Parse(const Byte *p, size_t size) | 303 | bool CReparseAttr::Parse(const Byte *p, size_t size) |
| 243 | { | 304 | { |
| 244 | ErrorCode = (DWORD)ERROR_INVALID_REPARSE_DATA; | 305 | ErrorCode = (DWORD)ERROR_INVALID_REPARSE_DATA; |
| @@ -250,7 +311,12 @@ bool CReparseAttr::Parse(const Byte *p, size_t size) | |||
| 250 | return false; | 311 | return false; |
| 251 | Tag = Get32(p); | 312 | Tag = Get32(p); |
| 252 | if (Get16(p + 6) != 0) // padding | 313 | if (Get16(p + 6) != 0) // padding |
| 253 | return false; | 314 | { |
| 315 | // DOCs: Reserved : the field SHOULD be set to 0 | ||
| 316 | // and MUST be ignored (by parser). | ||
| 317 | // Win10 ignores it. | ||
| 318 | MinorError = true; // optional | ||
| 319 | } | ||
| 254 | unsigned len = Get16(p + 4); | 320 | unsigned len = Get16(p + 4); |
| 255 | p += 8; | 321 | p += 8; |
| 256 | size -= 8; | 322 | size -= 8; |
| @@ -262,8 +328,6 @@ bool CReparseAttr::Parse(const Byte *p, size_t size) | |||
| 262 | (type & kReparseFlags_Microsoft) == 0 || | 328 | (type & kReparseFlags_Microsoft) == 0 || |
| 263 | (type & 0xFFFF) != 3) | 329 | (type & 0xFFFF) != 3) |
| 264 | */ | 330 | */ |
| 265 | |||
| 266 | |||
| 267 | HeaderError = false; | 331 | HeaderError = false; |
| 268 | 332 | ||
| 269 | if ( Tag != Z7_WIN_IO_REPARSE_TAG_MOUNT_POINT | 333 | if ( Tag != Z7_WIN_IO_REPARSE_TAG_MOUNT_POINT |
| @@ -282,8 +346,7 @@ bool CReparseAttr::Parse(const Byte *p, size_t size) | |||
| 282 | { | 346 | { |
| 283 | if (len < 4) | 347 | if (len < 4) |
| 284 | return false; | 348 | return false; |
| 285 | Flags = Get32(p); // maybe it's not Flags | 349 | if (Get32(p) != Z7_WIN_LX_SYMLINK_VERSION_2) |
| 286 | if (Flags != Z7_WIN_LX_SYMLINK_FLAG) | ||
| 287 | return false; | 350 | return false; |
| 288 | len -= 4; | 351 | len -= 4; |
| 289 | p += 4; | 352 | p += 4; |
| @@ -291,12 +354,13 @@ bool CReparseAttr::Parse(const Byte *p, size_t size) | |||
| 291 | unsigned i; | 354 | unsigned i; |
| 292 | for (i = 0; i < len; i++) | 355 | for (i = 0; i < len; i++) |
| 293 | { | 356 | { |
| 294 | char c = (char)p[i]; | 357 | const char c = (char)p[i]; |
| 295 | s[i] = c; | 358 | s[i] = c; |
| 296 | if (c == 0) | 359 | if (c == 0) |
| 297 | break; | 360 | break; |
| 298 | } | 361 | } |
| 299 | WslName.ReleaseBuf_SetEnd(i); | 362 | s[i] = 0; |
| 363 | WslName.ReleaseBuf_SetLen(i); | ||
| 300 | MinorError = (i != len); | 364 | MinorError = (i != len); |
| 301 | ErrorCode = 0; | 365 | ErrorCode = 0; |
| 302 | return true; | 366 | return true; |
| @@ -304,10 +368,10 @@ bool CReparseAttr::Parse(const Byte *p, size_t size) | |||
| 304 | 368 | ||
| 305 | if (len < 8) | 369 | if (len < 8) |
| 306 | return false; | 370 | return false; |
| 307 | unsigned subOffs = Get16(p); | 371 | const unsigned subOffs = Get16(p); |
| 308 | unsigned subLen = Get16(p + 2); | 372 | const unsigned subLen = Get16(p + 2); |
| 309 | unsigned printOffs = Get16(p + 4); | 373 | const unsigned printOffs = Get16(p + 4); |
| 310 | unsigned printLen = Get16(p + 6); | 374 | const unsigned printLen = Get16(p + 6); |
| 311 | len -= 8; | 375 | len -= 8; |
| 312 | p += 8; | 376 | p += 8; |
| 313 | 377 | ||
| @@ -335,15 +399,17 @@ bool CReparseAttr::Parse(const Byte *p, size_t size) | |||
| 335 | 399 | ||
| 336 | bool CReparseShortInfo::Parse(const Byte *p, size_t size) | 400 | bool CReparseShortInfo::Parse(const Byte *p, size_t size) |
| 337 | { | 401 | { |
| 338 | const Byte *start = p; | 402 | const Byte * const start = p; |
| 339 | Offset= 0; | 403 | Offset = 0; |
| 340 | Size = 0; | 404 | Size = 0; |
| 341 | if (size < 8) | 405 | if (size < 8) |
| 342 | return false; | 406 | return false; |
| 343 | UInt32 Tag = Get32(p); | 407 | const UInt32 Tag = Get32(p); |
| 344 | UInt32 len = Get16(p + 4); | 408 | UInt32 len = Get16(p + 4); |
| 409 | /* | ||
| 345 | if (len + 8 > size) | 410 | if (len + 8 > size) |
| 346 | return false; | 411 | return false; |
| 412 | */ | ||
| 347 | /* | 413 | /* |
| 348 | if ((type & kReparseFlags_Alias) == 0 || | 414 | if ((type & kReparseFlags_Alias) == 0 || |
| 349 | (type & kReparseFlags_Microsoft) == 0 || | 415 | (type & kReparseFlags_Microsoft) == 0 || |
| @@ -353,16 +419,14 @@ bool CReparseShortInfo::Parse(const Byte *p, size_t size) | |||
| 353 | Tag != Z7_WIN_IO_REPARSE_TAG_SYMLINK) | 419 | Tag != Z7_WIN_IO_REPARSE_TAG_SYMLINK) |
| 354 | // return true; | 420 | // return true; |
| 355 | return false; | 421 | return false; |
| 356 | 422 | /* | |
| 357 | if (Get16(p + 6) != 0) // padding | 423 | if (Get16(p + 6) != 0) // padding |
| 358 | return false; | 424 | return false; |
| 359 | 425 | */ | |
| 360 | p += 8; | 426 | p += 8; |
| 361 | size -= 8; | 427 | size -= 8; |
| 362 | |||
| 363 | if (len != size) // do we need that check? | 428 | if (len != size) // do we need that check? |
| 364 | return false; | 429 | return false; |
| 365 | |||
| 366 | if (len < 8) | 430 | if (len < 8) |
| 367 | return false; | 431 | return false; |
| 368 | unsigned subOffs = Get16(p); | 432 | unsigned subOffs = Get16(p); |
| @@ -396,10 +460,14 @@ bool CReparseAttr::IsOkNamePair() const | |||
| 396 | { | 460 | { |
| 397 | if (IsLinkPrefix(SubsName)) | 461 | if (IsLinkPrefix(SubsName)) |
| 398 | { | 462 | { |
| 463 | if (PrintName == GetPath()) | ||
| 464 | return true; | ||
| 465 | /* | ||
| 399 | if (!IsDrivePath(SubsName.Ptr(k_LinkPrefix_Size))) | 466 | if (!IsDrivePath(SubsName.Ptr(k_LinkPrefix_Size))) |
| 400 | return PrintName.IsEmpty(); | 467 | return PrintName.IsEmpty(); |
| 401 | if (wcscmp(SubsName.Ptr(k_LinkPrefix_Size), PrintName) == 0) | 468 | if (wcscmp(SubsName.Ptr(k_LinkPrefix_Size), PrintName) == 0) |
| 402 | return true; | 469 | return true; |
| 470 | */ | ||
| 403 | } | 471 | } |
| 404 | return wcscmp(SubsName, PrintName) == 0; | 472 | return wcscmp(SubsName, PrintName) == 0; |
| 405 | } | 473 | } |
| @@ -415,21 +483,26 @@ bool CReparseAttr::IsVolume() const | |||
| 415 | 483 | ||
| 416 | UString CReparseAttr::GetPath() const | 484 | UString CReparseAttr::GetPath() const |
| 417 | { | 485 | { |
| 486 | UString s (SubsName); | ||
| 418 | if (IsSymLink_WSL()) | 487 | if (IsSymLink_WSL()) |
| 419 | { | 488 | { |
| 420 | UString u; | ||
| 421 | // if (CheckUTF8(attr.WslName) | 489 | // if (CheckUTF8(attr.WslName) |
| 422 | if (!ConvertUTF8ToUnicode(WslName, u)) | 490 | if (!ConvertUTF8ToUnicode(WslName, s)) |
| 423 | MultiByteToUnicodeString2(u, WslName); | 491 | MultiByteToUnicodeString2(s, WslName); |
| 424 | return u; | ||
| 425 | } | 492 | } |
| 426 | 493 | else if (IsLinkPrefix(s)) | |
| 427 | UString s (SubsName); | ||
| 428 | if (IsLinkPrefix(s)) | ||
| 429 | { | 494 | { |
| 430 | s.ReplaceOneCharAtPos(1, '\\'); // we normalize prefix from "\??\" to "\\?\" | 495 | if (IsString1PrefixedByString2_NoCase_Ascii(s.Ptr(), k_LinkPrefix_UNC)) |
| 431 | if (IsDrivePath(s.Ptr(k_LinkPrefix_Size))) | 496 | { |
| 432 | s.DeleteFrontal(k_LinkPrefix_Size); | 497 | s.DeleteFrontal(6); |
| 498 | s.ReplaceOneCharAtPos(0, '\\'); | ||
| 499 | } | ||
| 500 | else | ||
| 501 | { | ||
| 502 | s.ReplaceOneCharAtPos(1, '\\'); // we normalize prefix from "\??\" to "\\?\" | ||
| 503 | if (IsDrivePath(s.Ptr(k_LinkPrefix_Size))) | ||
| 504 | s.DeleteFrontal(k_LinkPrefix_Size); | ||
| 505 | } | ||
| 433 | } | 506 | } |
| 434 | return s; | 507 | return s; |
| 435 | } | 508 | } |
| @@ -468,7 +541,7 @@ bool GetReparseData(CFSTR path, CByteBuffer &reparseData, BY_HANDLE_FILE_INFORMA | |||
| 468 | static bool CreatePrefixDirOfFile(CFSTR path) | 541 | static bool CreatePrefixDirOfFile(CFSTR path) |
| 469 | { | 542 | { |
| 470 | FString path2 (path); | 543 | FString path2 (path); |
| 471 | int pos = path2.ReverseFind_PathSepar(); | 544 | const int pos = path2.ReverseFind_PathSepar(); |
| 472 | if (pos < 0) | 545 | if (pos < 0) |
| 473 | return true; | 546 | return true; |
| 474 | #ifdef _WIN32 | 547 | #ifdef _WIN32 |
| @@ -494,6 +567,8 @@ static bool OutIoReparseData(DWORD controlCode, CFSTR path, void *data, DWORD si | |||
| 494 | } | 567 | } |
| 495 | 568 | ||
| 496 | 569 | ||
| 570 | // MOUNT_POINT (Junction Point) and LX_SYMLINK (WSL) can be written without administrator rights. | ||
| 571 | // SYMLINK requires administrator rights. | ||
| 497 | // If there is Reparse data already, it still writes new Reparse data | 572 | // If there is Reparse data already, it still writes new Reparse data |
| 498 | bool SetReparseData(CFSTR path, bool isDir, const void *data, DWORD size) | 573 | bool SetReparseData(CFSTR path, bool isDir, const void *data, DWORD size) |
| 499 | { | 574 | { |
| @@ -540,10 +615,11 @@ bool DeleteReparseData(CFSTR path) | |||
| 540 | SetLastError(ERROR_INVALID_REPARSE_DATA); | 615 | SetLastError(ERROR_INVALID_REPARSE_DATA); |
| 541 | return false; | 616 | return false; |
| 542 | } | 617 | } |
| 543 | BYTE buf[my_REPARSE_DATA_BUFFER_HEADER_SIZE]; | 618 | // BYTE buf[my_REPARSE_DATA_BUFFER_HEADER_SIZE]; |
| 544 | memset(buf, 0, sizeof(buf)); | 619 | // memset(buf, 0, sizeof(buf)); |
| 545 | memcpy(buf, reparseData, 4); // tag | 620 | // memcpy(buf, reparseData, 4); // tag |
| 546 | return OutIoReparseData(my_FSCTL_DELETE_REPARSE_POINT, path, buf, sizeof(buf)); | 621 | memset(reparseData + 4, 0, my_REPARSE_DATA_BUFFER_HEADER_SIZE - 4); |
| 622 | return OutIoReparseData(my_FSCTL_DELETE_REPARSE_POINT, path, reparseData, my_REPARSE_DATA_BUFFER_HEADER_SIZE); | ||
| 547 | } | 623 | } |
| 548 | 624 | ||
| 549 | } | 625 | } |
diff --git a/CPP/Windows/FileName.cpp b/CPP/Windows/FileName.cpp index 1f4a6da..eb62567 100644 --- a/CPP/Windows/FileName.cpp +++ b/CPP/Windows/FileName.cpp | |||
| @@ -65,8 +65,15 @@ void NormalizeDirPathPrefix(UString &dirPath) | |||
| 65 | dirPath.Add_PathSepar(); | 65 | dirPath.Add_PathSepar(); |
| 66 | } | 66 | } |
| 67 | 67 | ||
| 68 | |||
| 69 | #define IS_LETTER_CHAR(c) ((((unsigned)(int)(c) | 0x20) - (unsigned)'a' <= (unsigned)('z' - 'a'))) | ||
| 70 | bool IsDrivePath (const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && IS_SEPAR(s[2]); } | ||
| 71 | // bool IsDriveName2(const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && s[2] == 0; } | ||
| 72 | |||
| 68 | #ifdef _WIN32 | 73 | #ifdef _WIN32 |
| 69 | 74 | ||
| 75 | bool IsDrivePath2(const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':'; } | ||
| 76 | |||
| 70 | #ifndef USE_UNICODE_FSTRING | 77 | #ifndef USE_UNICODE_FSTRING |
| 71 | #ifdef Z7_LONG_PATH | 78 | #ifdef Z7_LONG_PATH |
| 72 | static void NormalizeDirSeparators(UString &s) | 79 | static void NormalizeDirSeparators(UString &s) |
| @@ -87,13 +94,6 @@ void NormalizeDirSeparators(FString &s) | |||
| 87 | s.ReplaceOneCharAtPos(i, FCHAR_PATH_SEPARATOR); | 94 | s.ReplaceOneCharAtPos(i, FCHAR_PATH_SEPARATOR); |
| 88 | } | 95 | } |
| 89 | 96 | ||
| 90 | #endif | ||
| 91 | |||
| 92 | |||
| 93 | #define IS_LETTER_CHAR(c) ((((unsigned)(int)(c) | 0x20) - (unsigned)'a' <= (unsigned)('z' - 'a'))) | ||
| 94 | |||
| 95 | bool IsDrivePath(const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && IS_SEPAR(s[2]); } | ||
| 96 | |||
| 97 | bool IsAltPathPrefix(CFSTR s) throw() | 97 | bool IsAltPathPrefix(CFSTR s) throw() |
| 98 | { | 98 | { |
| 99 | unsigned len = MyStringLen(s); | 99 | unsigned len = MyStringLen(s); |
| @@ -117,16 +117,23 @@ bool IsAltPathPrefix(CFSTR s) throw() | |||
| 117 | return true; | 117 | return true; |
| 118 | } | 118 | } |
| 119 | 119 | ||
| 120 | #if defined(_WIN32) && !defined(UNDER_CE) | 120 | #endif // _WIN32 |
| 121 | |||
| 121 | 122 | ||
| 122 | const char * const kSuperPathPrefix = "\\\\?\\"; | 123 | const char * const kSuperPathPrefix = |
| 124 | STRING_PATH_SEPARATOR | ||
| 125 | STRING_PATH_SEPARATOR "?" | ||
| 126 | STRING_PATH_SEPARATOR; | ||
| 123 | #ifdef Z7_LONG_PATH | 127 | #ifdef Z7_LONG_PATH |
| 124 | static const char * const kSuperUncPrefix = "\\\\?\\UNC\\"; | 128 | static const char * const kSuperUncPrefix = |
| 129 | STRING_PATH_SEPARATOR | ||
| 130 | STRING_PATH_SEPARATOR "?" | ||
| 131 | STRING_PATH_SEPARATOR "UNC" | ||
| 132 | STRING_PATH_SEPARATOR; | ||
| 125 | #endif | 133 | #endif |
| 126 | 134 | ||
| 127 | #define IS_DEVICE_PATH(s) (IS_SEPAR((s)[0]) && IS_SEPAR((s)[1]) && (s)[2] == '.' && IS_SEPAR((s)[3])) | 135 | #define IS_DEVICE_PATH(s) (IS_SEPAR((s)[0]) && IS_SEPAR((s)[1]) && (s)[2] == '.' && IS_SEPAR((s)[3])) |
| 128 | #define IS_SUPER_PREFIX(s) (IS_SEPAR((s)[0]) && IS_SEPAR((s)[1]) && (s)[2] == '?' && IS_SEPAR((s)[3])) | 136 | #define IS_SUPER_PREFIX(s) (IS_SEPAR((s)[0]) && IS_SEPAR((s)[1]) && (s)[2] == '?' && IS_SEPAR((s)[3])) |
| 129 | #define IS_SUPER_OR_DEVICE_PATH(s) (IS_SEPAR((s)[0]) && IS_SEPAR((s)[1]) && ((s)[2] == '?' || (s)[2] == '.') && IS_SEPAR((s)[3])) | ||
| 130 | 137 | ||
| 131 | #define IS_UNC_WITH_SLASH(s) ( \ | 138 | #define IS_UNC_WITH_SLASH(s) ( \ |
| 132 | ((s)[0] == 'U' || (s)[0] == 'u') \ | 139 | ((s)[0] == 'U' || (s)[0] == 'u') \ |
| @@ -134,6 +141,16 @@ static const char * const kSuperUncPrefix = "\\\\?\\UNC\\"; | |||
| 134 | && ((s)[2] == 'C' || (s)[2] == 'c') \ | 141 | && ((s)[2] == 'C' || (s)[2] == 'c') \ |
| 135 | && IS_SEPAR((s)[3])) | 142 | && IS_SEPAR((s)[3])) |
| 136 | 143 | ||
| 144 | static const unsigned kDrivePrefixSize = 3; /* c:\ */ | ||
| 145 | |||
| 146 | bool IsSuperPath(const wchar_t *s) throw(); | ||
| 147 | bool IsSuperPath(const wchar_t *s) throw() { return IS_SUPER_PREFIX(s); } | ||
| 148 | // bool IsSuperUncPath(const wchar_t *s) throw() { return (IS_SUPER_PREFIX(s) && IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize)); } | ||
| 149 | |||
| 150 | #if defined(_WIN32) && !defined(UNDER_CE) | ||
| 151 | |||
| 152 | #define IS_SUPER_OR_DEVICE_PATH(s) (IS_SEPAR((s)[0]) && IS_SEPAR((s)[1]) && ((s)[2] == '?' || (s)[2] == '.') && IS_SEPAR((s)[3])) | ||
| 153 | bool IsSuperOrDevicePath(const wchar_t *s) throw() { return IS_SUPER_OR_DEVICE_PATH(s); } | ||
| 137 | bool IsDevicePath(CFSTR s) throw() | 154 | bool IsDevicePath(CFSTR s) throw() |
| 138 | { | 155 | { |
| 139 | #ifdef UNDER_CE | 156 | #ifdef UNDER_CE |
| @@ -154,7 +171,7 @@ bool IsDevicePath(CFSTR s) throw() | |||
| 154 | 171 | ||
| 155 | if (!IS_DEVICE_PATH(s)) | 172 | if (!IS_DEVICE_PATH(s)) |
| 156 | return false; | 173 | return false; |
| 157 | unsigned len = MyStringLen(s); | 174 | const unsigned len = MyStringLen(s); |
| 158 | if (len == 6 && s[5] == ':') | 175 | if (len == 6 && s[5] == ':') |
| 159 | return true; | 176 | return true; |
| 160 | if (len < 18 || len > 22 || !IsString1PrefixedByString2(s + kDevicePathPrefixSize, "PhysicalDrive")) | 177 | if (len < 18 || len > 22 || !IsString1PrefixedByString2(s + kDevicePathPrefixSize, "PhysicalDrive")) |
| @@ -174,7 +191,7 @@ bool IsNetworkPath(CFSTR s) throw() | |||
| 174 | return false; | 191 | return false; |
| 175 | if (IsSuperUncPath(s)) | 192 | if (IsSuperUncPath(s)) |
| 176 | return true; | 193 | return true; |
| 177 | FChar c = s[2]; | 194 | const FChar c = s[2]; |
| 178 | return (c != '.' && c != '?'); | 195 | return (c != '.' && c != '?'); |
| 179 | } | 196 | } |
| 180 | 197 | ||
| @@ -187,7 +204,7 @@ unsigned GetNetworkServerPrefixSize(CFSTR s) throw() | |||
| 187 | prefixSize = kSuperUncPathPrefixSize; | 204 | prefixSize = kSuperUncPathPrefixSize; |
| 188 | else | 205 | else |
| 189 | { | 206 | { |
| 190 | FChar c = s[2]; | 207 | const FChar c = s[2]; |
| 191 | if (c == '.' || c == '?') | 208 | if (c == '.' || c == '?') |
| 192 | return 0; | 209 | return 0; |
| 193 | } | 210 | } |
| @@ -209,14 +226,6 @@ bool IsNetworkShareRootPath(CFSTR s) throw() | |||
| 209 | return s[(unsigned)pos + 1] == 0; | 226 | return s[(unsigned)pos + 1] == 0; |
| 210 | } | 227 | } |
| 211 | 228 | ||
| 212 | static const unsigned kDrivePrefixSize = 3; /* c:\ */ | ||
| 213 | |||
| 214 | bool IsDrivePath2(const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':'; } | ||
| 215 | // bool IsDriveName2(const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && s[2] == 0; } | ||
| 216 | bool IsSuperPath(const wchar_t *s) throw() { return IS_SUPER_PREFIX(s); } | ||
| 217 | bool IsSuperOrDevicePath(const wchar_t *s) throw() { return IS_SUPER_OR_DEVICE_PATH(s); } | ||
| 218 | // bool IsSuperUncPath(const wchar_t *s) throw() { return (IS_SUPER_PREFIX(s) && IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize)); } | ||
| 219 | |||
| 220 | bool IsAltStreamPrefixWithColon(const UString &s) throw() | 229 | bool IsAltStreamPrefixWithColon(const UString &s) throw() |
| 221 | { | 230 | { |
| 222 | if (s.IsEmpty()) | 231 | if (s.IsEmpty()) |
| @@ -349,14 +358,16 @@ unsigned GetRootPrefixSize(CFSTR s) throw() | |||
| 349 | } | 358 | } |
| 350 | 359 | ||
| 351 | #endif // USE_UNICODE_FSTRING | 360 | #endif // USE_UNICODE_FSTRING |
| 361 | #endif // _WIN32 | ||
| 362 | |||
| 352 | 363 | ||
| 353 | static unsigned GetRootPrefixSize_Of_NetworkPath(const wchar_t *s) throw() | 364 | static unsigned GetRootPrefixSize_Of_NetworkPath(const wchar_t *s) throw() |
| 354 | { | 365 | { |
| 355 | // Network path: we look "server\path\" as root prefix | 366 | // Network path: we look "server\path\" as root prefix |
| 356 | int pos = FindSepar(s); | 367 | const int pos = FindSepar(s); |
| 357 | if (pos < 0) | 368 | if (pos < 0) |
| 358 | return 0; | 369 | return 0; |
| 359 | int pos2 = FindSepar(s + (unsigned)pos + 1); | 370 | const int pos2 = FindSepar(s + (unsigned)pos + 1); |
| 360 | if (pos2 < 0) | 371 | if (pos2 < 0) |
| 361 | return 0; | 372 | return 0; |
| 362 | return (unsigned)(pos + pos2 + 2); | 373 | return (unsigned)(pos + pos2 + 2); |
| @@ -370,7 +381,7 @@ static unsigned GetRootPrefixSize_Of_SimplePath(const wchar_t *s) throw() | |||
| 370 | return 0; | 381 | return 0; |
| 371 | if (s[1] == 0 || !IS_SEPAR(s[1])) | 382 | if (s[1] == 0 || !IS_SEPAR(s[1])) |
| 372 | return 1; | 383 | return 1; |
| 373 | unsigned size = GetRootPrefixSize_Of_NetworkPath(s + 2); | 384 | const unsigned size = GetRootPrefixSize_Of_NetworkPath(s + 2); |
| 374 | return (size == 0) ? 0 : 2 + size; | 385 | return (size == 0) ? 0 : 2 + size; |
| 375 | } | 386 | } |
| 376 | 387 | ||
| @@ -378,17 +389,21 @@ static unsigned GetRootPrefixSize_Of_SuperPath(const wchar_t *s) throw() | |||
| 378 | { | 389 | { |
| 379 | if (IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize)) | 390 | if (IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize)) |
| 380 | { | 391 | { |
| 381 | unsigned size = GetRootPrefixSize_Of_NetworkPath(s + kSuperUncPathPrefixSize); | 392 | const unsigned size = GetRootPrefixSize_Of_NetworkPath(s + kSuperUncPathPrefixSize); |
| 382 | return (size == 0) ? 0 : kSuperUncPathPrefixSize + size; | 393 | return (size == 0) ? 0 : kSuperUncPathPrefixSize + size; |
| 383 | } | 394 | } |
| 384 | // we support \\?\c:\ paths and volume GUID paths \\?\Volume{GUID}\" | 395 | // we support \\?\c:\ paths and volume GUID paths \\?\Volume{GUID}\" |
| 385 | int pos = FindSepar(s + kSuperPathPrefixSize); | 396 | const int pos = FindSepar(s + kSuperPathPrefixSize); |
| 386 | if (pos < 0) | 397 | if (pos < 0) |
| 387 | return 0; | 398 | return 0; |
| 388 | return kSuperPathPrefixSize + (unsigned)(pos + 1); | 399 | return kSuperPathPrefixSize + (unsigned)(pos + 1); |
| 389 | } | 400 | } |
| 390 | 401 | ||
| 402 | #ifdef _WIN32 | ||
| 391 | unsigned GetRootPrefixSize(const wchar_t *s) throw() | 403 | unsigned GetRootPrefixSize(const wchar_t *s) throw() |
| 404 | #else | ||
| 405 | unsigned GetRootPrefixSize_WINDOWS(const wchar_t *s) throw() | ||
| 406 | #endif | ||
| 392 | { | 407 | { |
| 393 | if (IS_DEVICE_PATH(s)) | 408 | if (IS_DEVICE_PATH(s)) |
| 394 | return kDevicePathPrefixSize; | 409 | return kDevicePathPrefixSize; |
| @@ -397,7 +412,7 @@ unsigned GetRootPrefixSize(const wchar_t *s) throw() | |||
| 397 | return GetRootPrefixSize_Of_SimplePath(s); | 412 | return GetRootPrefixSize_Of_SimplePath(s); |
| 398 | } | 413 | } |
| 399 | 414 | ||
| 400 | #else // _WIN32 | 415 | #ifndef _WIN32 |
| 401 | 416 | ||
| 402 | bool IsAbsolutePath(const wchar_t *s) throw() { return IS_SEPAR(s[0]); } | 417 | bool IsAbsolutePath(const wchar_t *s) throw() { return IS_SEPAR(s[0]); } |
| 403 | 418 | ||
diff --git a/CPP/Windows/FileName.h b/CPP/Windows/FileName.h index 219b656..ce26e78 100644 --- a/CPP/Windows/FileName.h +++ b/CPP/Windows/FileName.h | |||
| @@ -25,13 +25,13 @@ bool IsDrivePath(const wchar_t *s) throw(); // first 3 chars are drive chars li | |||
| 25 | 25 | ||
| 26 | bool IsAltPathPrefix(CFSTR s) throw(); /* name: */ | 26 | bool IsAltPathPrefix(CFSTR s) throw(); /* name: */ |
| 27 | 27 | ||
| 28 | #if defined(_WIN32) && !defined(UNDER_CE) | ||
| 29 | |||
| 30 | extern const char * const kSuperPathPrefix; /* \\?\ */ | 28 | extern const char * const kSuperPathPrefix; /* \\?\ */ |
| 31 | const unsigned kDevicePathPrefixSize = 4; | 29 | const unsigned kDevicePathPrefixSize = 4; |
| 32 | const unsigned kSuperPathPrefixSize = 4; | 30 | const unsigned kSuperPathPrefixSize = 4; |
| 33 | const unsigned kSuperUncPathPrefixSize = kSuperPathPrefixSize + 4; | 31 | const unsigned kSuperUncPathPrefixSize = kSuperPathPrefixSize + 4; |
| 34 | 32 | ||
| 33 | #if defined(_WIN32) && !defined(UNDER_CE) | ||
| 34 | |||
| 35 | bool IsDevicePath(CFSTR s) throw(); /* \\.\ */ | 35 | bool IsDevicePath(CFSTR s) throw(); /* \\.\ */ |
| 36 | bool IsSuperUncPath(CFSTR s) throw(); /* \\?\UNC\ */ | 36 | bool IsSuperUncPath(CFSTR s) throw(); /* \\?\UNC\ */ |
| 37 | bool IsNetworkPath(CFSTR s) throw(); /* \\?\UNC\ or \\SERVER */ | 37 | bool IsNetworkPath(CFSTR s) throw(); /* \\?\UNC\ or \\SERVER */ |
| @@ -86,6 +86,15 @@ int FindAltStreamColon(CFSTR path) throw(); | |||
| 86 | bool IsAbsolutePath(const wchar_t *s) throw(); | 86 | bool IsAbsolutePath(const wchar_t *s) throw(); |
| 87 | unsigned GetRootPrefixSize(const wchar_t *s) throw(); | 87 | unsigned GetRootPrefixSize(const wchar_t *s) throw(); |
| 88 | 88 | ||
| 89 | #ifndef _WIN32 | ||
| 90 | /* GetRootPrefixSize_WINDOWS() is called in linux, but it parses path by windows rules. | ||
| 91 | It supports only paths system (linux) slash separators (STRING_PATH_SEPARATOR), | ||
| 92 | It doesn't parses paths with backslash (windows) separators. | ||
| 93 | "c:/dir/file" is supported. | ||
| 94 | */ | ||
| 95 | unsigned GetRootPrefixSize_WINDOWS(const wchar_t *s) throw(); | ||
| 96 | #endif | ||
| 97 | |||
| 89 | #ifdef Z7_LONG_PATH | 98 | #ifdef Z7_LONG_PATH |
| 90 | 99 | ||
| 91 | const int kSuperPathType_UseOnlyMain = 0; | 100 | const int kSuperPathType_UseOnlyMain = 0; |
diff --git a/CPP/Windows/System.cpp b/CPP/Windows/System.cpp index 5fa87f3..4745785 100644 --- a/CPP/Windows/System.cpp +++ b/CPP/Windows/System.cpp | |||
| @@ -25,6 +25,69 @@ namespace NSystem { | |||
| 25 | 25 | ||
| 26 | #ifdef _WIN32 | 26 | #ifdef _WIN32 |
| 27 | 27 | ||
| 28 | /* | ||
| 29 | note: returned value in 32-bit version can be limited by value 32. | ||
| 30 | while 64-bit version returns full value. | ||
| 31 | GetMaximumProcessorCount(groupNumber) can return higher value than | ||
| 32 | GetActiveProcessorCount(groupNumber) in some cases, because CPUs can be added. | ||
| 33 | */ | ||
| 34 | // typedef DWORD (WINAPI *Func_GetMaximumProcessorCount)(WORD GroupNumber); | ||
| 35 | typedef DWORD (WINAPI *Func_GetActiveProcessorCount)(WORD GroupNumber); | ||
| 36 | typedef WORD (WINAPI *Func_GetActiveProcessorGroupCount)(VOID); | ||
| 37 | /* | ||
| 38 | #if 0 && defined(ALL_PROCESSOR_GROUPS) | ||
| 39 | #define MY_ALL_PROCESSOR_GROUPS ALL_PROCESSOR_GROUPS | ||
| 40 | #else | ||
| 41 | #define MY_ALL_PROCESSOR_GROUPS 0xffff | ||
| 42 | #endif | ||
| 43 | */ | ||
| 44 | |||
| 45 | Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION | ||
| 46 | |||
| 47 | bool CCpuGroups::Load() | ||
| 48 | { | ||
| 49 | NumThreadsTotal = 0; | ||
| 50 | GroupSizes.Clear(); | ||
| 51 | const HMODULE hmodule = ::GetModuleHandleA("kernel32.dll"); | ||
| 52 | // Is_Win11_Groups = GetProcAddress(hmodule, "SetThreadSelectedCpuSetMasks") != NULL; | ||
| 53 | const | ||
| 54 | Func_GetActiveProcessorGroupCount | ||
| 55 | fn_GetActiveProcessorGroupCount = Z7_GET_PROC_ADDRESS( | ||
| 56 | Func_GetActiveProcessorGroupCount, hmodule, | ||
| 57 | "GetActiveProcessorGroupCount"); | ||
| 58 | const | ||
| 59 | Func_GetActiveProcessorCount | ||
| 60 | fn_GetActiveProcessorCount = Z7_GET_PROC_ADDRESS( | ||
| 61 | Func_GetActiveProcessorCount, hmodule, | ||
| 62 | "GetActiveProcessorCount"); | ||
| 63 | if (!fn_GetActiveProcessorGroupCount || | ||
| 64 | !fn_GetActiveProcessorCount) | ||
| 65 | return false; | ||
| 66 | |||
| 67 | const unsigned numGroups = fn_GetActiveProcessorGroupCount(); | ||
| 68 | if (numGroups == 0) | ||
| 69 | return false; | ||
| 70 | UInt32 sum = 0; | ||
| 71 | for (unsigned i = 0; i < numGroups; i++) | ||
| 72 | { | ||
| 73 | const UInt32 num = fn_GetActiveProcessorCount((WORD)i); | ||
| 74 | /* | ||
| 75 | if (num == 0) | ||
| 76 | { | ||
| 77 | // it means error | ||
| 78 | // but is it possible that some group is empty by some reason? | ||
| 79 | // GroupSizes.Clear(); | ||
| 80 | // return false; | ||
| 81 | } | ||
| 82 | */ | ||
| 83 | sum += num; | ||
| 84 | GroupSizes.Add(num); | ||
| 85 | } | ||
| 86 | NumThreadsTotal = sum; | ||
| 87 | // NumThreadsTotal = fn_GetActiveProcessorCount(MY_ALL_PROCESSOR_GROUPS); | ||
| 88 | return true; | ||
| 89 | } | ||
| 90 | |||
| 28 | UInt32 CountAffinity(DWORD_PTR mask) | 91 | UInt32 CountAffinity(DWORD_PTR mask) |
| 29 | { | 92 | { |
| 30 | UInt32 num = 0; | 93 | UInt32 num = 0; |
| @@ -38,31 +101,62 @@ UInt32 CountAffinity(DWORD_PTR mask) | |||
| 38 | 101 | ||
| 39 | BOOL CProcessAffinity::Get() | 102 | BOOL CProcessAffinity::Get() |
| 40 | { | 103 | { |
| 41 | #ifndef UNDER_CE | 104 | IsGroupMode = false; |
| 42 | return GetProcessAffinityMask(GetCurrentProcess(), &processAffinityMask, &systemAffinityMask); | 105 | Groups.Load(); |
| 43 | #else | 106 | // SetThreadAffinityMask(GetCurrentThread(), 1); |
| 44 | return FALSE; | 107 | // SetProcessAffinityMask(GetCurrentProcess(), 1); |
| 45 | #endif | 108 | BOOL res = GetProcessAffinityMask(GetCurrentProcess(), |
| 109 | &processAffinityMask, &systemAffinityMask); | ||
| 110 | /* DOCs: On a system with more than 64 processors, if the threads | ||
| 111 | of the calling process are in a single processor group, the | ||
| 112 | function sets the variables pointed to by lpProcessAffinityMask | ||
| 113 | and lpSystemAffinityMask to the process affinity mask and the | ||
| 114 | processor mask of active logical processors for that group. | ||
| 115 | If the calling process contains threads in multiple groups, | ||
| 116 | the function returns zero for both affinity masks | ||
| 117 | |||
| 118 | note: tested in Win10: GetProcessAffinityMask() doesn't return 0 | ||
| 119 | in (processAffinityMask) and (systemAffinityMask) masks. | ||
| 120 | We need to test it in Win11: how to get mask==0 from GetProcessAffinityMask()? | ||
| 121 | */ | ||
| 122 | if (!res) | ||
| 123 | { | ||
| 124 | processAffinityMask = 0; | ||
| 125 | systemAffinityMask = 0; | ||
| 126 | } | ||
| 127 | if (Groups.GroupSizes.Size() > 1 && Groups.NumThreadsTotal) | ||
| 128 | if (// !res || | ||
| 129 | processAffinityMask == 0 || // to support case described in DOCs and for (!res) case | ||
| 130 | processAffinityMask == systemAffinityMask) // for default nonchanged affinity | ||
| 131 | { | ||
| 132 | // we set IsGroupMode only if processAffinity is default (not changed). | ||
| 133 | res = TRUE; | ||
| 134 | IsGroupMode = true; | ||
| 135 | } | ||
| 136 | return res; | ||
| 46 | } | 137 | } |
| 47 | 138 | ||
| 48 | 139 | ||
| 140 | UInt32 CProcessAffinity::Load_and_GetNumberOfThreads() | ||
| 141 | { | ||
| 142 | if (Get()) | ||
| 143 | { | ||
| 144 | const UInt32 numProcessors = GetNumProcessThreads(); | ||
| 145 | if (numProcessors) | ||
| 146 | return numProcessors; | ||
| 147 | } | ||
| 148 | SYSTEM_INFO systemInfo; | ||
| 149 | GetSystemInfo(&systemInfo); | ||
| 150 | // the number of logical processors in the current group | ||
| 151 | return systemInfo.dwNumberOfProcessors; | ||
| 152 | } | ||
| 153 | |||
| 49 | UInt32 GetNumberOfProcessors() | 154 | UInt32 GetNumberOfProcessors() |
| 50 | { | 155 | { |
| 51 | // We need to know how many threads we can use. | 156 | // We need to know how many threads we can use. |
| 52 | // By default the process is assigned to one group. | 157 | // By default the process is assigned to one group. |
| 53 | // So we get the number of logical processors (threads) | ||
| 54 | // assigned to current process in the current group. | ||
| 55 | // Group size can be smaller than total number logical processors, for exammple, 2x36 | ||
| 56 | |||
| 57 | CProcessAffinity pa; | 158 | CProcessAffinity pa; |
| 58 | 159 | return pa.Load_and_GetNumberOfThreads(); | |
| 59 | if (pa.Get() && pa.processAffinityMask != 0) | ||
| 60 | return pa.GetNumProcessThreads(); | ||
| 61 | |||
| 62 | SYSTEM_INFO systemInfo; | ||
| 63 | GetSystemInfo(&systemInfo); | ||
| 64 | // the number of logical processors in the current group | ||
| 65 | return (UInt32)systemInfo.dwNumberOfProcessors; | ||
| 66 | } | 160 | } |
| 67 | 161 | ||
| 68 | #else | 162 | #else |
diff --git a/CPP/Windows/System.h b/CPP/Windows/System.h index 9951b8b..0c80373 100644 --- a/CPP/Windows/System.h +++ b/CPP/Windows/System.h | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #endif | 9 | #endif |
| 10 | 10 | ||
| 11 | #include "../Common/MyTypes.h" | 11 | #include "../Common/MyTypes.h" |
| 12 | #include "../Common/MyVector.h" | ||
| 12 | #include "../Common/MyWindows.h" | 13 | #include "../Common/MyWindows.h" |
| 13 | 14 | ||
| 14 | namespace NWindows { | 15 | namespace NWindows { |
| @@ -16,6 +17,34 @@ namespace NSystem { | |||
| 16 | 17 | ||
| 17 | #ifdef _WIN32 | 18 | #ifdef _WIN32 |
| 18 | 19 | ||
| 20 | struct CCpuGroups | ||
| 21 | { | ||
| 22 | CRecordVector<UInt32> GroupSizes; | ||
| 23 | UInt32 NumThreadsTotal; // sum of threads in all groups | ||
| 24 | // bool Is_Win11_Groups; // useless | ||
| 25 | |||
| 26 | void Get_GroupSize_Min_Max(UInt32 &minSize, UInt32 &maxSize) const | ||
| 27 | { | ||
| 28 | unsigned num = GroupSizes.Size(); | ||
| 29 | UInt32 minSize2 = 0, maxSize2 = 0; | ||
| 30 | if (num) | ||
| 31 | { | ||
| 32 | minSize2 = (UInt32)0 - 1; | ||
| 33 | do | ||
| 34 | { | ||
| 35 | const UInt32 v = GroupSizes[--num]; | ||
| 36 | if (minSize2 > v) minSize2 = v; | ||
| 37 | if (maxSize2 < v) maxSize2 = v; | ||
| 38 | } | ||
| 39 | while (num); | ||
| 40 | } | ||
| 41 | minSize = minSize2; | ||
| 42 | maxSize = maxSize2; | ||
| 43 | } | ||
| 44 | bool Load(); | ||
| 45 | CCpuGroups(): NumThreadsTotal(0) {} | ||
| 46 | }; | ||
| 47 | |||
| 19 | UInt32 CountAffinity(DWORD_PTR mask); | 48 | UInt32 CountAffinity(DWORD_PTR mask); |
| 20 | 49 | ||
| 21 | struct CProcessAffinity | 50 | struct CProcessAffinity |
| @@ -25,14 +54,28 @@ struct CProcessAffinity | |||
| 25 | DWORD_PTR processAffinityMask; | 54 | DWORD_PTR processAffinityMask; |
| 26 | DWORD_PTR systemAffinityMask; | 55 | DWORD_PTR systemAffinityMask; |
| 27 | 56 | ||
| 57 | CCpuGroups Groups; | ||
| 58 | bool IsGroupMode; | ||
| 59 | /* | ||
| 60 | IsGroupMode == true, if | ||
| 61 | Groups.GroupSizes.Size() > 1) && { dafalt affinity was not changed } | ||
| 62 | IsGroupMode == false, if single group or affinity was changed | ||
| 63 | */ | ||
| 64 | |||
| 65 | UInt32 Load_and_GetNumberOfThreads(); | ||
| 66 | |||
| 28 | void InitST() | 67 | void InitST() |
| 29 | { | 68 | { |
| 30 | // numProcessThreads = 1; | 69 | // numProcessThreads = 1; |
| 31 | // numSysThreads = 1; | 70 | // numSysThreads = 1; |
| 32 | processAffinityMask = 1; | 71 | processAffinityMask = 1; |
| 33 | systemAffinityMask = 1; | 72 | systemAffinityMask = 1; |
| 73 | IsGroupMode = false; | ||
| 74 | // Groups.NumThreadsTotal = 0; | ||
| 75 | // Groups.Is_Win11_Groups = false; | ||
| 34 | } | 76 | } |
| 35 | 77 | ||
| 78 | /* | ||
| 36 | void CpuZero() | 79 | void CpuZero() |
| 37 | { | 80 | { |
| 38 | processAffinityMask = 0; | 81 | processAffinityMask = 0; |
| @@ -42,9 +85,23 @@ struct CProcessAffinity | |||
| 42 | { | 85 | { |
| 43 | processAffinityMask |= ((DWORD_PTR)1 << cpuIndex); | 86 | processAffinityMask |= ((DWORD_PTR)1 << cpuIndex); |
| 44 | } | 87 | } |
| 88 | */ | ||
| 45 | 89 | ||
| 46 | UInt32 GetNumProcessThreads() const { return CountAffinity(processAffinityMask); } | 90 | UInt32 GetNumProcessThreads() const |
| 47 | UInt32 GetNumSystemThreads() const { return CountAffinity(systemAffinityMask); } | 91 | { |
| 92 | if (IsGroupMode) | ||
| 93 | return Groups.NumThreadsTotal; | ||
| 94 | // IsGroupMode == false | ||
| 95 | // so we don't want to use groups | ||
| 96 | // we return number of threads in default primary group: | ||
| 97 | return CountAffinity(processAffinityMask); | ||
| 98 | } | ||
| 99 | UInt32 GetNumSystemThreads() const | ||
| 100 | { | ||
| 101 | if (Groups.GroupSizes.Size() > 1 && Groups.NumThreadsTotal) | ||
| 102 | return Groups.NumThreadsTotal; | ||
| 103 | return CountAffinity(systemAffinityMask); | ||
| 104 | } | ||
| 48 | 105 | ||
| 49 | BOOL Get(); | 106 | BOOL Get(); |
| 50 | 107 | ||
diff --git a/CPP/Windows/Thread.h b/CPP/Windows/Thread.h index d72f64c..75c1616 100644 --- a/CPP/Windows/Thread.h +++ b/CPP/Windows/Thread.h | |||
| @@ -26,8 +26,10 @@ public: | |||
| 26 | { return Thread_Create_With_Affinity(&thread, startAddress, param, affinity); } | 26 | { return Thread_Create_With_Affinity(&thread, startAddress, param, affinity); } |
| 27 | WRes Create_With_CpuSet(THREAD_FUNC_TYPE startAddress, LPVOID param, const CCpuSet *cpuSet) | 27 | WRes Create_With_CpuSet(THREAD_FUNC_TYPE startAddress, LPVOID param, const CCpuSet *cpuSet) |
| 28 | { return Thread_Create_With_CpuSet(&thread, startAddress, param, cpuSet); } | 28 | { return Thread_Create_With_CpuSet(&thread, startAddress, param, cpuSet); } |
| 29 | 29 | ||
| 30 | #ifdef _WIN32 | 30 | #ifdef _WIN32 |
| 31 | WRes Create_With_Group(THREAD_FUNC_TYPE startAddress, LPVOID param, unsigned group, CAffinityMask affinity = 0) | ||
| 32 | { return Thread_Create_With_Group(&thread, startAddress, param, group, affinity); } | ||
| 31 | operator HANDLE() { return thread; } | 33 | operator HANDLE() { return thread; } |
| 32 | void Attach(HANDLE handle) { thread = handle; } | 34 | void Attach(HANDLE handle) { thread = handle; } |
| 33 | HANDLE Detach() { HANDLE h = thread; thread = NULL; return h; } | 35 | HANDLE Detach() { HANDLE h = thread; thread = NULL; return h; } |
| @@ -36,7 +38,7 @@ public: | |||
| 36 | bool Terminate(DWORD exitCode) { return BOOLToBool(::TerminateThread(thread, exitCode)); } | 38 | bool Terminate(DWORD exitCode) { return BOOLToBool(::TerminateThread(thread, exitCode)); } |
| 37 | int GetPriority() { return ::GetThreadPriority(thread); } | 39 | int GetPriority() { return ::GetThreadPriority(thread); } |
| 38 | bool SetPriority(int priority) { return BOOLToBool(::SetThreadPriority(thread, priority)); } | 40 | bool SetPriority(int priority) { return BOOLToBool(::SetThreadPriority(thread, priority)); } |
| 39 | #endif | 41 | #endif |
| 40 | }; | 42 | }; |
| 41 | 43 | ||
| 42 | } | 44 | } |
diff --git a/CPP/Windows/TimeUtils.cpp b/CPP/Windows/TimeUtils.cpp index bbd79ba..4e3bc59 100644 --- a/CPP/Windows/TimeUtils.cpp +++ b/CPP/Windows/TimeUtils.cpp | |||
| @@ -258,8 +258,9 @@ bool GetSecondsSince1601(unsigned year, unsigned month, unsigned day, | |||
| 258 | FreeBSD 11.0, NetBSD 7.1, OpenBSD 6.0, | 258 | FreeBSD 11.0, NetBSD 7.1, OpenBSD 6.0, |
| 259 | Minix 3.1.8, AIX 7.1, HP-UX 11.31, IRIX 6.5, Solaris 11.3, | 259 | Minix 3.1.8, AIX 7.1, HP-UX 11.31, IRIX 6.5, Solaris 11.3, |
| 260 | Cygwin 2.9, mingw, MSVC 14, Android 9.0. | 260 | Cygwin 2.9, mingw, MSVC 14, Android 9.0. |
| 261 | Android NDK defines TIME_UTC but doesn't have the timespec_get(). | ||
| 261 | */ | 262 | */ |
| 262 | #if defined(TIME_UTC) | 263 | #if defined(TIME_UTC) && !defined(__ANDROID__) |
| 263 | #define ZIP7_USE_timespec_get | 264 | #define ZIP7_USE_timespec_get |
| 264 | // #pragma message("ZIP7_USE_timespec_get") | 265 | // #pragma message("ZIP7_USE_timespec_get") |
| 265 | #elif defined(CLOCK_REALTIME) | 266 | #elif defined(CLOCK_REALTIME) |
diff --git a/DOC/7zip.wxs b/DOC/7zip.wxs index 867e3d1..d369074 100644 --- a/DOC/7zip.wxs +++ b/DOC/7zip.wxs | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | <?xml version="1.0"?> | 1 | <?xml version="1.0"?> |
| 2 | 2 | ||
| 3 | <?define VerMajor = "24" ?> | 3 | <?define VerMajor = "25" ?> |
| 4 | <?define VerMinor = "09" ?> | 4 | <?define VerMinor = "00" ?> |
| 5 | <?define VerBuild = "00" ?> | 5 | <?define VerBuild = "00" ?> |
| 6 | <?define MmVer = "$(var.VerMajor).$(var.VerMinor)" ?> | 6 | <?define MmVer = "$(var.VerMajor).$(var.VerMinor)" ?> |
| 7 | <?define MmHex = "$(var.VerMajor)$(var.VerMinor)" ?> | 7 | <?define MmHex = "$(var.VerMajor)$(var.VerMinor)" ?> |
diff --git a/DOC/License.txt b/DOC/License.txt index 8917dfc..bbb56a3 100644 --- a/DOC/License.txt +++ b/DOC/License.txt | |||
| @@ -3,7 +3,7 @@ | |||
| 3 | License for use and distribution | 3 | License for use and distribution |
| 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 5 | 5 | ||
| 6 | 7-Zip Copyright (C) 1999-2024 Igor Pavlov. | 6 | 7-Zip Copyright (C) 1999-2025 Igor Pavlov. |
| 7 | 7 | ||
| 8 | The licenses for files are: | 8 | The licenses for files are: |
| 9 | 9 | ||
| @@ -58,7 +58,7 @@ BSD 3-clause License in 7-Zip code | |||
| 58 | 58 | ||
| 59 | Copyright (c) 2015-2016, Apple Inc. All rights reserved. | 59 | Copyright (c) 2015-2016, Apple Inc. All rights reserved. |
| 60 | Copyright (c) Facebook, Inc. All rights reserved. | 60 | Copyright (c) Facebook, Inc. All rights reserved. |
| 61 | Copyright (c) 2023-2024 Igor Pavlov. | 61 | Copyright (c) 2023-2025 Igor Pavlov. |
| 62 | 62 | ||
| 63 | Text of the "BSD 3-clause License" | 63 | Text of the "BSD 3-clause License" |
| 64 | ---------------------------------- | 64 | ---------------------------------- |
| @@ -102,7 +102,7 @@ BSD 2-clause License in 7-Zip code | |||
| 102 | XXH64 code in 7-Zip was derived from the original XXH64 code developed by Yann Collet. | 102 | XXH64 code in 7-Zip was derived from the original XXH64 code developed by Yann Collet. |
| 103 | 103 | ||
| 104 | Copyright (c) 2012-2021 Yann Collet. | 104 | Copyright (c) 2012-2021 Yann Collet. |
| 105 | Copyright (c) 2023-2024 Igor Pavlov. | 105 | Copyright (c) 2023-2025 Igor Pavlov. |
| 106 | 106 | ||
| 107 | Text of the "BSD 2-clause License" | 107 | Text of the "BSD 2-clause License" |
| 108 | ---------------------------------- | 108 | ---------------------------------- |
diff --git a/DOC/readme.txt b/DOC/readme.txt index ad1d842..7fbbdc8 100644 --- a/DOC/readme.txt +++ b/DOC/readme.txt | |||
| @@ -1,9 +1,9 @@ | |||
| 1 | 7-Zip 24.09 Sources | 1 | 7-Zip 25.00 Sources |
| 2 | ------------------- | 2 | ------------------- |
| 3 | 3 | ||
| 4 | 7-Zip is a file archiver for Windows. | 4 | 7-Zip is a file archiver for Windows. |
| 5 | 5 | ||
| 6 | 7-Zip Copyright (C) 1999-2024 Igor Pavlov. | 6 | 7-Zip Copyright (C) 1999-2025 Igor Pavlov. |
| 7 | 7 | ||
| 8 | 8 | ||
| 9 | License Info | 9 | License Info |
| @@ -73,8 +73,8 @@ All final 7-Zip binaries are compiled via makefiles, that provide best | |||
| 73 | optimization options. | 73 | optimization options. |
| 74 | 74 | ||
| 75 | 75 | ||
| 76 | How to compile with makefile | 76 | How to compile with makefile in Windows |
| 77 | ---------------------------- | 77 | --------------------------------------- |
| 78 | 78 | ||
| 79 | Some macronames can be defined for compiling with makefile: | 79 | Some macronames can be defined for compiling with makefile: |
| 80 | 80 | ||
| @@ -88,6 +88,23 @@ MY_DYNAMIC_LINK | |||
| 88 | for dynamic linking to the run-time library (msvcrt.dll). | 88 | for dynamic linking to the run-time library (msvcrt.dll). |
| 89 | The default makefile option is static linking to the run-time library. | 89 | The default makefile option is static linking to the run-time library. |
| 90 | 90 | ||
| 91 | To compile all 7-Zip files for x64 with Visual Studio 2022, | ||
| 92 | use the following command sequence: | ||
| 93 | |||
| 94 | cd SRC\CPP\7zip | ||
| 95 | %comspec% /k "C:\Program Files\VS2022\VC\Auxiliary\Build\vcvars64.bat" | ||
| 96 | nmake | ||
| 97 | |||
| 98 | You can use another "vcvars*.bat" files from "VS2022\VC\Auxiliary\Build" directory | ||
| 99 | to compile for other platforms: | ||
| 100 | vcvars64.bat | ||
| 101 | vcvarsamd64_arm64.bat | ||
| 102 | vcvarsamd64_x86.bat | ||
| 103 | |||
| 104 | Also you can compile single binary from directory with related project. | ||
| 105 | For example, to compile 7za.exe, use the following command sequence: | ||
| 106 | cd SRC\CPP\7zip\Bundles\Alone\ | ||
| 107 | nmake | ||
| 91 | 108 | ||
| 92 | 109 | ||
| 93 | Compiling 7-Zip for Unix/Linux | 110 | Compiling 7-Zip for Unix/Linux |
diff --git a/DOC/src-history.txt b/DOC/src-history.txt index 6b57694..70b11b5 100644 --- a/DOC/src-history.txt +++ b/DOC/src-history.txt | |||
| @@ -1,6 +1,18 @@ | |||
| 1 | HISTORY of the 7-Zip source code | 1 | HISTORY of the 7-Zip source code |
| 2 | -------------------------------- | 2 | -------------------------------- |
| 3 | 3 | ||
| 4 | 25.00 2025-07-05 | ||
| 5 | ------------------------- | ||
| 6 | - 7-Zip for Windows can now use more than 64 CPU threads for compression | ||
| 7 | to zip/7z/xz archives and for the 7-Zip benchmark. | ||
| 8 | If there are more than one processor group in Windows (on systems with more than | ||
| 9 | 64 cpu threads), 7-Zip distributes running CPU threads across different processor groups. | ||
| 10 | - bzip2 compression speed was increased by 15-40%. | ||
| 11 | - deflate (zip/gz) compression speed was increased by 1-3%. | ||
| 12 | - improved support for zip, cpio and fat archives. | ||
| 13 | - fixed some bugs and vulnerabilities. | ||
| 14 | |||
| 15 | |||
| 4 | 24.09 2024-11-29 | 16 | 24.09 2024-11-29 |
| 5 | ------------------------- | 17 | ------------------------- |
| 6 | - The default dictionary size values for LZMA/LZMA2 compression methods were increased: | 18 | - The default dictionary size values for LZMA/LZMA2 compression methods were increased: |
