Compare commits

...

382 Commits
0.18.1 ... 0.27

Author SHA1 Message Date
Adam Hathcock
a28d686eb9 Fix relavant package references 2021-01-11 12:01:17 +00:00
Adam Hathcock
ac525a8ec2 Merge branch 'master' of github.com:adamhathcock/sharpcompress 2021-01-11 10:01:49 +00:00
Adam Hathcock
52c44befa2 Merge pull request #560 from adamhathcock/gzip-fixes
Expose Last Modified time on GZipStream.  Add CRC and Size to GZipEntries on Archive
2021-01-11 08:57:19 +00:00
Adam Hathcock
c64251c341 Mark for 0.27 2021-01-09 14:04:44 +00:00
Adam Hathcock
bdc57d3c33 Merge pull request #559 from adamhathcock/net5
Use Net5, NetCoreApp3.1, NetStandard2.1, NetStandard2.0 only
2021-01-09 13:43:37 +00:00
Adam Hathcock
7edc437df2 formatting 2021-01-09 13:40:57 +00:00
Adam Hathcock
57e4395e7d Merge branch 'master' into net5
# Conflicts:
#	build/Program.cs
#	src/SharpCompress/Common/Zip/ZipFilePart.cs
2021-01-09 13:40:09 +00:00
Adam Hathcock
ee17dca9e5 Fix formatting 2021-01-09 13:36:30 +00:00
Adam Hathcock
e9f3add5b9 Merge branch 'master' into gzip-fixes 2021-01-09 13:35:52 +00:00
Adam Hathcock
faf1a9f7e4 Merge pull request #561 from adamhathcock/format
Use dotnet format to ensure some kind of code style
2021-01-09 13:35:26 +00:00
Adam Hathcock
5357bd07c7 Let dotnet format do it’s thing 2021-01-09 13:33:34 +00:00
Adam Hathcock
8c0e2cbd25 Use dotnet format 2021-01-09 13:32:14 +00:00
Adam Hathcock
674f3b4f28 Merge branch 'master' into gzip-fixes 2021-01-09 13:25:55 +00:00
Adam Hathcock
6e42e00974 Merge pull request #485 from adamhathcock/issue-256
Create and using PauseEntryRebuilding for adding large numbers of ent…
2021-01-09 13:23:52 +00:00
Adam Hathcock
8598885258 Read trailer for GZip for CRC and uncompressed size 2021-01-09 13:22:06 +00:00
Adam Hathcock
669e40d53c Merge branch 'master' into issue-256 2021-01-09 13:01:16 +00:00
Adam Hathcock
1adcce6c62 Expose Last Modified time on GZipStream 2021-01-09 12:53:13 +00:00
Adam Hathcock
147be6e6e1 Use Net5, NetCoreApp3.1, NetStandard2.1, NetStandard2.0 only 2021-01-09 10:34:49 +00:00
Adam Hathcock
5879999094 Merge pull request #551 from carbon/alder32
Use hardware accelerated Alder32 impl
2020-11-19 08:21:31 +00:00
Jason Nelson
477a30cf5b Use hardware accelerated Alder32 impl 2020-11-18 11:21:29 -08:00
Adam Hathcock
2fec03e1ac Merge pull request #550 from carbon/cq
Improve Code Quality 3
2020-11-18 18:32:53 +00:00
Jason Nelson
9a17449a02 Format NewSubHeaderType 2020-11-18 09:44:13 -08:00
Jason Nelson
087a6aad8c Cross target .NETCOREAPP3.1 and react to new nullablity annotations 2020-11-18 09:43:08 -08:00
Jason Nelson
e243a8e88f Format AbstractArchive 2020-11-18 09:31:39 -08:00
Jason Nelson
b57df8026a Use pattern matching 2020-11-18 09:29:38 -08:00
Jason Nelson
a1d45b44cd Format ArchiveFactory 2020-11-18 09:28:24 -08:00
Jason Nelson
e47e1d220a Format AesDecoderStream 2020-11-18 09:25:38 -08:00
Jason Nelson
0129a933df Remove NETSTANDARD1_3 symbol 2020-11-18 09:23:50 -08:00
Jason Nelson
fa241bb0d7 Inline variable declarations 2020-11-18 09:21:45 -08:00
Jason Nelson
d8804ae108 Improve conditional logic to prepare to add .NETCOREAPP target 2020-11-18 09:19:21 -08:00
Jason Nelson
8090d269e7 Add polyfills for string.EndWith(char) && string.Contains(char) 2020-11-18 09:16:53 -08:00
Jason Nelson
b0101f20c5 Eliminate culture specific StartsWith comparisions 2020-11-18 09:12:01 -08:00
Jason Nelson
dd48e4299a Simplify .NET framework code exclusions, bump min .NET framework version to 4.6.1 2020-11-18 09:07:30 -08:00
Jason Nelson
c61ee0c24f Update deps 2020-11-18 09:02:11 -08:00
Jason Nelson
9576867c34 Enable C# 9 2020-11-18 09:01:35 -08:00
Adam Hathcock
4426a24298 Merge pull request #549 from adamhathcock/update-deps
Update dependencies
2020-11-03 08:47:58 +00:00
Adam Hathcock
3b43c1e413 Update dependencies 2020-11-03 08:45:10 +00:00
Adam Hathcock
aa6575c8f9 Merge pull request #541 from avao/master
UT and Fix for: Index out of range exception from gzip #532
2020-10-19 12:33:31 +01:00
avao
0268713960 UT and Fix for: Index out of range exception from gzip #532 2020-10-13 19:58:11 +01:00
Adam Hathcock
f36167d425 Merge pull request #531 from carbon/master
Improve CQ3
2020-08-01 06:25:09 +01:00
Jason Nelson
33ffcb9308 Use Array.Empty<byte> 2020-07-31 17:00:46 -07:00
Jason Nelson
a649c25a91 Eliminate two allocations in HuffmanTree 2020-07-31 16:58:21 -07:00
Jason Nelson
fa1e773960 Eliminate two allocations in Crc32 2020-07-31 16:55:07 -07:00
Jason Nelson
62f7238796 Make CMethodId readonly 2020-07-31 16:49:34 -07:00
Jason Nelson
d4ccf73340 Embed FAST_ENCODER_TREE_STRUCTURE_DATA 2020-07-31 16:47:05 -07:00
Jason Nelson
5ddb0f96bc Use switch expressions 2020-07-31 16:37:56 -07:00
Jason Nelson
75a6db8f4c Eliminate three allocations in HbMakeCodeLengths 2020-07-31 16:33:00 -07:00
Jason Nelson
ae5635319b Eliminate header bytes allocation 2020-07-31 16:30:26 -07:00
Jason Nelson
98ed3080d0 Eliminate three allocations 2020-07-31 16:30:09 -07:00
Jason Nelson
c618eacad4 Optimize RijndaelEngine 2020-07-31 16:22:44 -07:00
Jason Nelson
3b11e6ef97 Eliminate two allocations 2020-07-31 16:10:59 -07:00
Jason Nelson
40af9359db Pollyfill and use Stream.Read(Span<byte> buffer) 2020-07-31 16:08:38 -07:00
Jason Nelson
d6bf9dae42 Eliminate allocation 2020-07-31 16:01:09 -07:00
Adam Hathcock
13917941ff Merge pull request #530 from carbon/master
Enable test coverage for net461 and fix regression
2020-07-31 18:39:40 +01:00
Jason Nelson
28f04329ae Merge branch 'master' of https://github.com/carbon/sharpcompress 2020-07-31 10:12:37 -07:00
Jason Nelson
404a6b231d Fix .NET 461 failures 2020-07-31 10:12:34 -07:00
Jason Nelson
184596da3c Merge branch 'master' into master 2020-07-31 11:37:45 -05:00
Jason Nelson
f00f393687 Disable failing net461 tests 2020-07-31 09:30:20 -07:00
Jason Nelson
cbbfb89619 Add failure notes 2020-07-31 09:29:06 -07:00
Jason Nelson
6a5cf11dd0 Fix net461 bug 2020-07-31 09:27:41 -07:00
Jason Nelson
fc1d0a0464 Run tests against net461 2020-07-31 09:27:32 -07:00
Adam Hathcock
74af1759eb Merge pull request #529 from carbon/master
Improve code quality v2
2020-07-31 06:55:35 +01:00
Jason Nelson
ee3162ad71 Fix return 2020-07-30 17:49:29 -07:00
Jason Nelson
4357165163 Add Read/Write overrides to NonDisposingStream 2020-07-30 17:36:03 -07:00
Jason Nelson
6973436b94 Add and use Stream.Write(ReadOnlySpan<byte> buffer) polyfill 2020-07-30 17:29:33 -07:00
Jason Nelson
7750ed7106 Finish spanification of RijndaelEngine 2020-07-30 17:01:13 -07:00
Jason Nelson
773158e9d8 Seal LZipStream 2020-07-30 16:57:30 -07:00
Jason Nelson
4db615597d Refactor ExtraData and enable nullable 2020-07-30 16:48:22 -07:00
Jason Nelson
6bdf2365fc Inline variable declarations 2020-07-30 16:45:38 -07:00
Adam Hathcock
a7944f28c5 Fix CI again 2020-07-26 14:45:32 +01:00
Adam Hathcock
426d459284 Fix CI build 2020-07-26 14:39:13 +01:00
Adam Hathcock
b00b461ada Update documented targets 2020-07-26 14:38:19 +01:00
Adam Hathcock
84834b6348 ignore snukpkg 2020-07-26 14:36:42 +01:00
Adam Hathcock
f521fd35ff Fix tests, update to 0.26 2020-07-26 14:36:07 +01:00
Adam Hathcock
2979fceecf Merge pull request #522 from JTOne123/master
[PR] The proj files have been updated to enable SourceLink
2020-07-26 12:07:13 +01:00
Adam Hathcock
b12e8e793f Merge branch 'master' into master 2020-07-26 12:07:05 +01:00
Adam Hathcock
c77ec59a28 Merge pull request #527 from adamhathcock/default-encoding
Don’t use 437 Encoding by default anymore.
2020-07-26 12:06:30 +01:00
Adam Hathcock
42ba8cf828 Merge branch 'master' into default-encoding 2020-07-26 12:06:22 +01:00
Adam Hathcock
c7618fc895 Merge pull request #528 from DannyBoyk/issue_524_tararchive_fails_read_all_entries
Ensure TarArchive enumerates all entries
2020-07-26 12:05:58 +01:00
Daniel Nash
d055b34efe Ensure TarArchive enumerates all entries
While enumerating the entries of a tar file and writing their contents
to disk using TarArchive, it was discovered TarArchive was not properly
discarding padding bytes in the last block of each entry. TarArchive was
sometimes able to recover depending on the number of padding bytes due
to the logic it uses to find the next entry header, but not always.

TarArchive was changed to use TarReadOnlySubStream when opening entries
and TarReadOnlySubstream was changed to ensure all an entry's blocks are
read when it is being disposed.

Fixes adamhathcock/sharpcompress#524
2020-07-20 12:57:39 -04:00
Adam Hathcock
b7f635f540 Update readme 2020-07-16 15:35:27 +01:00
Adam Hathcock
5e95a54260 Merge branch 'master' into default-encoding 2020-07-16 14:32:51 +01:00
Adam Hathcock
4354e82bb5 Don’t use 437 Encoding by default anymore. 2020-07-16 14:28:37 +01:00
Adam Hathcock
ab7bdc24dc Merge pull request #523 from kdaadk/master
Decompress multipart solid RAR4.x archive
2020-07-01 12:56:58 +01:00
Dmitriy
81997fe1ba rename test 2020-07-01 15:10:21 +05:00
Dmitriy
de6759a83f - remove check of solid archive
- change tests
- add test on multi solid archive
2020-07-01 15:06:54 +05:00
Adam Hathcock
233dc33130 Fix running tests on build 2020-06-25 09:22:15 +01:00
Adam Hathcock
39b07f45f1 Update github action and minor SDK bump 2020-06-25 09:16:15 +01:00
Pavlo Datsiuk
802662a165 [COMMIT] The proj files have been updated to enable SourceLink [SharpCompress.csproj] 2020-06-25 10:58:21 +03:00
Adam Hathcock
2859848fc4 Give the artifacts names 2020-05-24 10:41:06 +01:00
Adam Hathcock
b734d00062 Remove README for appveyor and fix artifacts again 2020-05-24 10:35:39 +01:00
Adam Hathcock
02a17d22f6 Adjust artifacts and remove appveyor 2020-05-24 10:32:50 +01:00
Adam Hathcock
7bfff472c6 Fix yaml 2020-05-24 10:26:51 +01:00
Adam Hathcock
5aa146be17 Remove matrix var 2020-05-24 10:25:40 +01:00
Adam Hathcock
a0bfc22a29 Try upload artifact 2020-05-24 10:23:01 +01:00
Adam Hathcock
6ed46b5fcc Fix CI paths 2020-05-24 09:04:10 +01:00
Adam Hathcock
904e40ef57 Switch to bullseye for building 2020-05-24 09:00:27 +01:00
Adam Hathcock
00ff119ec4 Minor Rider issues resolved. Still two outstanding. 2020-05-24 08:42:36 +01:00
Adam Hathcock
60d2511e80 Remove .NET Standard 1.3 which is no longer in support 2020-05-24 08:42:06 +01:00
Adam Hathcock
ed56a4aa4a Merge pull request #515 from carbon/master
Enable nullable
2020-05-24 08:20:37 +01:00
Jason Nelson
5b6a1c97e3 Enable nullable 2020-05-23 16:27:55 -07:00
Adam Hathcock
8bfc9ef4de Update for 0.25.1 2020-05-22 13:46:36 +01:00
Adam Hathcock
fa949e089e Merge pull request #512 from adamhathcock/fix-codepages
Attempt Windows reference fix
2020-05-22 13:44:10 +01:00
Adam Hathcock
c296ca7660 Merge pull request #513 from RealOrko/symbolic-link-default-write
Added default implementation with warning for symbolic links
2020-05-22 13:43:56 +01:00
RealOrko
538b38869f Added a warning for the writing of symbolic links with a link to the original GitHub issue for the DOTNET runtime 2020-05-21 13:00:25 +01:00
Adam Hathcock
ce328ed90b Merge branch 'master' into fix-codepages 2020-05-15 08:28:25 +01:00
Adam Hathcock
632bae725d Add braces for clarity 2020-05-14 13:47:21 +01:00
Adam Hathcock
4f824b1d9a Add build flags for Core targets 2020-05-14 13:16:00 +01:00
Adam Hathcock
120aee8039 See if windows reference is fixed 2020-05-14 13:09:17 +01:00
Adam Hathcock
3b2b341c4d Merge pull request #508 from turbedi/minor_optimizations
Minor optimizations
2020-04-11 09:08:07 +01:00
Berkan Diler
4cad40f637 Minor string optimizations 2020-04-10 12:33:40 +02:00
Berkan Diler
2c64380019 Use 3 argument Array.Copy when possible 2020-04-10 12:06:38 +02:00
Berkan Diler
ccb9593de2 Replace Span<T>.Fill(0) with Span<T>.Clear() 2020-04-10 12:03:32 +02:00
Berkan Diler
921a99fc32 Replace static readonly byte[] fields with static ReadOnlySpan<byte> properties 2020-04-10 11:54:58 +02:00
Adam Hathcock
400d2c1774 Fix usings and add braces for better merging 2020-04-03 08:47:30 +01:00
Adam Hathcock
762497b1c1 Tag for 0.25.0 and update packages 2020-04-03 08:25:43 +01:00
Adam Hathcock
be9edc7512 Merge pull request #500 from Erior/Issue_86
ZipReader/StreamingZipReaderFactory fails for archive entries which are uncompressed files in ZIP format #86
2020-01-17 09:38:19 +00:00
Lars Vahlenberg
9bf9d34d94 Issue86 Proposal 2020-01-16 22:08:48 +01:00
Adam Hathcock
df8405006c Fix workflow name 2020-01-03 09:24:08 +00:00
Adam Hathcock
d135fdce58 Give github actions build a name and use badge 2020-01-03 09:22:51 +00:00
Adam Hathcock
ba570b93bb Merge pull request #496 from Bond-009/allocations
Reduce the amount of allocations
2020-01-03 09:18:17 +00:00
Adam Hathcock
6dfe0c7a96 Merge branch 'master' into allocations 2020-01-03 09:16:46 +00:00
Adam Hathcock
73d4430a65 Merge pull request #498 from adamhathcock/build-netcore3
Build netcore3
2020-01-03 09:15:14 +00:00
Adam Hathcock
ce6fd9b976 JUst one target 2020-01-03 09:12:10 +00:00
Adam Hathcock
ae7e8c03f2 Put wrong SDK 2020-01-03 09:07:34 +00:00
Adam Hathcock
22e2526f4c Update cake and dependencies 2020-01-03 09:06:13 +00:00
Adam Hathcock
50283d9411 Add new build targets for netcore3 2020-01-03 09:02:04 +00:00
Bond-009
d2c2b58f3b Fix language version and add netstandard2.1 2020-01-02 17:43:58 +01:00
Bond_009
50d4b39ca0 Fix test 2019-12-30 22:17:45 +01:00
Bond_009
1ed675e960 Minor improvement 2019-12-30 19:19:05 +01:00
Bond_009
80b0671844 Reduce the amount of allocations
* Directly fill an array instead of filling a List and copying that to
an array
* Use own buffer when writing bytes to a stream
* Remove DataConverter class, replaced by BinaryPrimitives
2019-12-30 18:58:25 +01:00
Bond-009
6f387336c0 Use functions from System.Memory instead of selfmade ones (#495)
* Use functions from System.Memory instead of selfmade ones

* Update SharpCompress.Test.csproj
2019-12-30 15:19:46 +00:00
Adam Hathcock
3b2e273832 Merge branch 'master' into issue-256 2019-10-10 09:27:46 +01:00
Adam Hathcock
9540b01bcc NET Standard 1.3 and 2.0 only (#482)
* Remove NET35, NET45 and NET Standard 1.0

* Update README and memset

* Remove NETCORE build flag

* NET 46 too?

* Update packages and usage
2019-10-10 09:24:41 +01:00
Adam Hathcock
43c839eb89 Create and using PauseEntryRebuilding for adding large numbers of entries 2019-10-09 09:55:16 +01:00
Adam Hathcock
446d6914c1 Merge pull request #483 from Bond-009/nameof
Use nameof for param names
2019-09-17 14:21:04 +01:00
Bond_009
637223aa53 Use nameof for param names 2019-09-17 13:28:44 +02:00
Adam Hathcock
17d5565120 Merge pull request #478 from Bond-009/buffers
Use System.Buffers Nuget package
2019-09-17 10:05:29 +01:00
Bond_009
4b54187b4c Fix build 2019-09-11 21:33:57 +02:00
Bond_009
cfb1421367 Use System.Buffers Nuget package 2019-09-11 20:06:50 +02:00
Adam Hathcock
5072a0f6f5 Merge pull request #471 from adamhathcock/release-024
Bump version and dependencies
2019-08-20 20:36:38 +01:00
Adam Hathcock
357dff1403 Bump version and dependencies 2019-08-20 14:29:47 -05:00
Adam Hathcock
a2bd66ded8 Merge pull request #460 from itn3000/tar-fix-garbled2
fix filename garbling in tar(#414)
2019-06-27 12:16:53 +01:00
itn3000
6bfa3c25a4 add more comments 2019-06-27 20:01:40 +09:00
itn3000
1ea9ab72c1 add comment for subtracting 2019-06-27 19:59:16 +09:00
itn3000
07c42b8725 replace magic number 2019-06-27 10:59:21 +09:00
itn3000
70392c32e2 use Buffer.BlockCopy for performance 2019-06-27 09:47:26 +09:00
itn3000
9b4b2a9f7c considering encoding in processing filename(#414)
modify test tar archive because it was not expected one.
(expected "тест.txt" in encoding 866, but actual is omitted upper byte)
2019-06-26 17:34:12 +09:00
Adam Hathcock
d3dd708b58 Merge pull request #457 from DannyBoyk/issue_456_zip_bounded_substreams_data_descriptors
Return a bounded substream when data descriptors are used in seekable zips
2019-06-04 13:42:24 +01:00
Daniel Nash
af264cdc58 Return a bounded substream when data descriptors are used in seekable zips 2019-06-04 08:31:42 -04:00
Adam Hathcock
cfd6df976f Merge pull request #455 from DannyBoyk/issue_454_zip_bad_extra_field
Handle a bad extra field in a local file header in zip files
2019-06-04 09:24:55 +01:00
Daniel Nash
b2bd20b47e Handle a bad extra field in a local file header in zip files 2019-06-03 13:02:28 -04:00
Adam Hathcock
ffea093e95 Merge pull request #453 from Lssikkes/master
Fix for clients failing on just having a 64 bit offset in ZIP64
2019-05-24 19:33:59 +01:00
Leroy Sikkes
78eb8fcf92 Fix for clients that don't support ZIP64 standard correctly in case headers are only pointed to in ZIP64 directory structure 2019-05-24 18:27:49 +02:00
Adam Hathcock
a052956881 Merge pull request #452 from Lssikkes/master
Various fixes for ZIP64 writer (zero byte entries, 32 bit where supported)
2019-05-24 16:17:48 +01:00
Lssikkes
9319ea6992 Updated ZIP64 writer to write 32 bit values to directory entries for better compatibility.
Support for zero byte files without corruption errors from WinRAR/7-zip
2019-05-24 16:14:30 +02:00
Adam Hathcock
4e5b70dbfa Merge pull request #444 from eugeny-trunin/mem-opt
Memory and speed optimization
2019-03-20 15:13:00 +00:00
evgeny
c68eaa8397 Memory and speed optimization 2019-03-20 17:46:57 +03:00
Adam Hathcock
bbb7c85ba7 Merge pull request #442 from turbolocust/master
Fix: ArchiveEncoding was ignored in TarWriterOptions
2019-03-19 08:31:31 +00:00
Matthias Fussenegger
8174359228 Fix: ArchiveEncoding was ignored in TarWriterOptions 2019-03-18 18:25:00 +01:00
Adam Hathcock
acf66c5195 Merge pull request #440 from adamhathcock/release-023
Bump release for 0.23 and update dependencies
2019-02-27 12:57:30 +00:00
Adam Hathcock
880c9fa97a Bump release and update dependencies 2019-02-27 12:55:16 +00:00
Adam Hathcock
e5c111f2be Merge pull request #436 from Numpsy/populate_zip_volume_comment
Changes to populate ZipArchive.ZipVolumne.Comment
2019-01-14 08:14:03 +00:00
Richard Webb
4e9cd064dd Unit test to show reading of a Zip volume/archive comment 2019-01-13 21:05:55 +00:00
Richard Webb
12a6d3977e Return the DirectoryEndHeader from SeekableZipHeaderFactory.ReadSeekable so that it can be used by ZipArchive 2018-12-14 22:44:44 +00:00
Adam Hathcock
a95bbaf820 Merge pull request #423 from markfinal/tarsymlink
Tar symlink support
2018-11-05 08:31:48 +00:00
Mark Final
70bafa653b Tar symlink extraction
Extended SharpCompress.Common.ExtractionOptions with a delegate to write symbolic links. If not is null, and a symbolic link is encountered, an exception is thrown.
Removed Mono.Posix.NETStandard from the library, but added to the .NET Core 2.1 test application.
Extended the test to implement the delegate.
2018-11-03 09:45:12 +00:00
Mark Final
3f4338489c Removed unnecessary code 2018-11-01 21:57:49 +00:00
Mark Final
d91e58f2cc Refs #248. Refs #132. Added a test case of a tar containing symlinks
This is a source archive of the MoltenVK project from github, which is my use-case for SharpCompress.
I added a test case in the project, which should extract the tar, and validate any symlink targets with what the tar thinks it ought to be.
2018-11-01 21:51:14 +00:00
Mark Final
192b9c1e8b Ref #248. Ref #132. Tar reader support for symlinks for .NET standard 2 and Posix platforms
Extracts linkname from the tar header, and exposes this on IEntry as the LinkTarget (string) property. If an entry is not a symlink, then that property is null.

Uses Mono.Posix.NETStandard nuget to create a symlink. However, this is only applicable to .NET standard 2.0+. So far, unable to find a nuget that works for older versions.

Also, not sure what to do on Windows.
2018-11-01 21:48:51 +00:00
Adam Hathcock
0941239454 Merge pull request #417 from KyotoFox/fix-entrystream-flush
Allow Flush on EntryStream
2018-10-04 12:48:08 +01:00
Knut Ørland
53ad00cdc4 Use soft tabs 2018-10-04 13:13:14 +02:00
Knut Ørland
6dd5da48f7 Added test that calls EntryStream.Flush() 2018-10-04 13:08:53 +02:00
Knut Ørland
efae8328a9 Don't throw an exception when flushing an EntryStream
From Microsoft docs: “In a class derived from Stream that doesn't
support writing, Flush is typically implemented as an empty method to
ensure full compatibility with other Stream types since it's valid to
flush a read-only stream.”
2018-10-04 13:05:36 +02:00
Adam Hathcock
f1facc51de Merge pull request #409 from G-Research/RecogniseEmptyTarArchives
Recognise empty tar archives.
2018-09-25 13:20:59 +01:00
Adam Hathcock
a471ca6a76 Use Cake tool on circle. Update test packages 2018-08-31 09:27:04 +01:00
Elliot Prior
83f6690576 Recognise empty tar archives.
Currently, when ArchiveFactory.Open is called on an empty tar archive, it throws due to being unable to determine the stream type. This fix allows it to recognise empty tar files by checking for whether the filename is empty, the size is empty and the entry type is defined. Add a test to try opening an empty archive.
2018-08-16 10:25:47 +01:00
Adam Hathcock
1850ea67f6 Merge pull request #408 from majoreffort/master
Test and fix for #407
2018-07-24 09:42:03 +01:00
majoreffort
2fd6178aa9 Fixed length in TarHeader#WriteStringBytes 2018-07-23 19:58:37 +02:00
majoreffort
ec044e6f42 Added Tar test for 100 char filename issue. 2018-07-23 19:48:01 +02:00
Adam Hathcock
bd96279649 Merge pull request #404 from MattKotsenas/bugfix/idisposable
Enable parallel test execution
2018-07-12 19:53:50 +01:00
Matt Kotsenas
f7ad595945 Enable test parallelization and remove garbage collection workaround
Now that the sources of file locking are fixed, enable test parallelization
and the forced garbage collection workaround.

Lastly, remove the `IsLocked` check because it doesn't work in a
parallel test running world - the file may be locked due to another test
running.
2018-07-12 10:33:19 -07:00
Matt Kotsenas
93c0b91de9 Refactor TestSharpCompressWithEmptyStream
Refactor `TestSharpCompressWithEmptyStream` so it asserts that the files
and bytes are the same.
2018-07-12 10:32:08 -07:00
Matt Kotsenas
138038b08f Move RarReaderTests over to user ReaderFactory
- Refactor `RarReaderTests` to use `ReaderFactory`
- Update `ReaderTests.Read` to support Rar tests
2018-07-12 10:32:08 -07:00
Matt Kotsenas
e9a6fed607 FIXUP decouple UseReader from VerifyFiles 2018-07-11 16:53:34 -07:00
Matt Kotsenas
87a1440382 Decouple UseReader from VerifyFiles 2018-07-11 16:49:49 -07:00
Matt Kotsenas
3c2f4ebe9b Combine ForwardOnlyStream and NonSeekableStream
Delete `NonSeekableStream` used in Zip64 tests in favor
of `ForwardOnlyStream` used in Mocks.

Additionally, delete the `ForwardOnlyStream.ReadByte` implementation
as the implementation on the base Stream is sufficient.
2018-07-11 16:42:03 -07:00
Matt Kotsenas
933ffe7828 Remove unused code from ArchiveTests 2018-07-11 16:33:46 -07:00
Matt Kotsenas
7d20ba5243 Simplify RarHeaderTests 2018-07-11 16:21:19 -07:00
Matt Kotsenas
44dc36af48 Update ReaderTests base class to validate Dispose
Update the `ReaderTests` base class to validate that `Dispose` is
called appropriately in both the close and the leave open cases.
2018-07-11 16:21:19 -07:00
Matt Kotsenas
98558c5ba9 Refactor TestStream constructor
Refactor the `TestStream` constructor so by default it defers to
the underlying Stream
2018-07-11 16:21:19 -07:00
Matt Kotsenas
6c25322465 Follow best-practices for Dispose in Volume and ForwardOnlyStream
Update `Volume` and `ForwardOnlyStream` to follow the project's
general pattern and best-practices for `Dispose`
2018-07-11 16:21:19 -07:00
Matt Kotsenas
6d1d62fd32 Delete AppendingStream
`AppendingStream` is unused, so rather than refactor it, just delete it.
2018-07-11 16:21:19 -07:00
Matt Kotsenas
ee4ae661d7 Refactor ListeningStream
Refactor `ListeningStream`:

- Override of `WriteByte` was redundant and removed
- Make `Dispose` delegate to base class
2018-07-11 16:21:19 -07:00
Matt Kotsenas
0473ec1626 Open test archives as read
Update `RarHeaderFactoryTests` and `GZipArchiveTests` to open the test
readers as `FileAccess.Read` and `FileShare.Read` to prevent issues with
multiple test from trying to open exclusive access to files.
2018-07-11 16:21:19 -07:00
Matt Kotsenas
c6cf0d40ee Simplify ReaderTests
The `IEnumerable<string>` version of `ReaderTests` is unused, so delete
it to simplify the code.
2018-07-11 16:21:19 -07:00
Matt Kotsenas
4cd80e96f3 Simplify GZip bad compression test 2018-07-11 16:21:19 -07:00
Matt Kotsenas
16524717ba Fix Stream leak in ArchiveFactory
`ArchiveFactory.Open` has two overloads that take `string` or
`FileInfo` (string delegates to FileInfo). Both of these implementations
open a `Stream` with the default `ReaderOptions`, which leaves the
stream open, resulting in a leak.

The fix is to set `LeaveOpen` to `false` if no options were provided.
Note that if a user was provding options and `LeaveOpen` was set to
`true`, the code did and will still leak.
2018-07-11 16:21:19 -07:00
Matt Kotsenas
cab1ce3d0c Update sub-streams to uniformly inherit from NonDisposingStream
Update the sub-stream classes to all inherit from `NonDisposingStream`.
This allows them to correctly implement the `Dispose` pattern, and delegate
the actual disposal to `NonDisposingStream`.

In doing so, we need to remove some redundant overrides from
`NonDisposingStream`, otherwise `BufferedSubStream` would use the
overrides inherited from `NonDisposingStream` instead of the ones
inherited from `Stream` (i.e. delegate `ReadByte` to `Read`).
2018-07-11 16:17:49 -07:00
Matt Kotsenas
6c2e5e1164 Cleanup NonDisposingStream for reuse
- Remove the duplicate `GC.SuppressFinalization` call
(called in `System.IO.Stream)
- Improve the `ThrowOnDispose` error message
2018-07-11 12:19:34 -07:00
Matt Kotsenas
c2bf540057 Close verification streams in TestBase.CompareArchivesByPath 2018-07-11 12:12:30 -07:00
Matt Kotsenas
a35c66e166 Move RewindableStreamTest.cs to the Streams/ folder 2018-07-10 12:07:33 -07:00
Matt Kotsenas
084c5e2686 Rename StreamTests.cs --> LzmaStreamTests.cs 2018-07-10 12:07:32 -07:00
Matt Kotsenas
6ae715b153 Move the TestStream and ForwardOnlyStream to Mocks folder
Move the `TestStream` and `ForwardOnlyStream` to Mocks/ to separate them
from the test classes.
2018-07-10 12:07:32 -07:00
Adam Hathcock
9c8692806a Merge pull request #403 from MattKotsenas/bugfix/parallel-tests
Fix and re-enable tests
2018-07-10 20:01:20 +01:00
Matt Kotsenas
2d87351d2a Add tests back to AppVeyor 2018-07-10 11:52:00 -07:00
Matt Kotsenas
3114afde0e Add workaround for in-use files
The `TestBase` is not always able to delete the scratch folder in
`Dispose()` because sometimes the files are still in use.

This problem appears to be leaked file handles (likely due to incorrect
handling of `IDisposable`). To avoid the problem for now, force a
garbage collection prior to deleting the scratch folder.
2018-07-10 11:49:38 -07:00
Matt Kotsenas
7b338511cc Create unique scratch path per test
Tests fail in Visual Studio because they try to reuse the same scratch
working space, and each test is responsible for resetting the space. To
simplify the test code:

1. Make `TestBase` `IDisposable` and have it create the scratch space
2. Remove `ResetScratch()` as it is now handled by the base class
3. Add a unique ID to each scrach space folder to prevent collisions
2018-07-10 11:46:44 -07:00
Adam Hathcock
09c27681e1 Merge pull request #402 from a764578566/master
file search support linq Pattern
2018-07-10 13:21:09 +01:00
zhoujr
4ebc1f82b7 file search support linq Pattern 2018-07-10 19:58:59 +08:00
Adam Hathcock
4640ca497a Merge pull request #400 from MattKotsenas/feature/avoid-exception-in-readerfactory
Avoid throwing NotSupportedException in ReaderFactory hot path
2018-07-10 08:47:13 +01:00
Matt Kotsenas
bebccaae28 Avoid throwing NotSupportedException in ReaderFactory hot path
`ReaderFactory.Open()` calls `ZipArchive.IsZipFile()` to determine if
the `Stream` is a zip archive, which calls into
`ZipHeaderFactory.ReadHeader()`, which throws a `NotSupportedException`
when the `Stream` is not a zip archive.

To be clear, this exception is caught and `IsZipFile()` returns `false`,
but when called in a hot-path, these exceptions can become expensive.

To address this issue, `ReadHeader` now returns `null` in the default
cause instead of throwing. All callsites were already checking for and
handling `null`, so no behavior changes.
2018-07-09 18:44:46 -07:00
Adam Hathcock
7ee53373c6 Remove tests as AppVeyor can’t handle them at the moment 2018-07-09 09:05:10 +01:00
Adam Hathcock
d577fe1ac6 Merge pull request #385 from twirpx/master
Fixed EFS flag handling
2018-07-09 08:48:34 +01:00
Adam Hathcock
9f976aaf78 Merge branch 'master' into master 2018-07-09 08:48:26 +01:00
Adam Hathcock
8a7d7e366f Merge pull request #396 from andreas-eriksson/Rar5IsEncrypted
Correctly set IsEncrypted for entries in Rar5.
2018-07-09 08:48:12 +01:00
Adam Hathcock
540ab1c6fa Merge branch 'master' into master 2018-07-09 08:47:32 +01:00
Adam Hathcock
6792afbdb1 Merge branch 'master' into Rar5IsEncrypted 2018-07-09 08:44:32 +01:00
Adam Hathcock
e5a7185671 Mark for 0.22 2018-07-09 08:42:45 +01:00
Adam Hathcock
cdaf453b2d Update dependencies and tests to .NET Core 2.1 2018-07-09 08:39:37 +01:00
Andreas Eriksson
f9cc80e1de Correctly set IsEncrypted for entries in Rar5. 2018-06-29 15:51:40 +02:00
Adam Hathcock
7beff9e83c Merge pull request #395 from adamhathcock/zip-slip-readers
Zip slip for Readers
2018-06-28 11:56:44 +01:00
Adam Hathcock
8f49f1b6f8 Merge remote-tracking branch 'origin/master' into zip-slip-readers 2018-06-28 11:52:43 +01:00
Adam Hathcock
7e336a0247 Slip in new SDK 2018-06-28 11:51:17 +01:00
Adam Hathcock
e37e8bdadc Move path handling for extraction to be common
Reader and Archive now share more extraction logic
2018-06-28 11:46:51 +01:00
Adam Hathcock
40bd61b16b Merge pull request #389 from frankyjuang/patch-1
Fix comment
2018-06-08 08:59:52 +01:00
Juang, Yi-Lin
87fbb45099 Fix comment 2018-06-08 11:27:43 +08:00
twirpx
e822f9a95c Tests fixed to use explicit use of 866 encoding because of usage file named in Russian in several tests 2018-05-30 22:17:27 +05:00
twirpx
8a5a9159e1 Fixed DirectoryEntryHeader Name/Comment decoding in case of EFS flags set 2018-05-30 21:47:31 +05:00
twirpx
73b3c6b419 Merge branch 'master' of https://github.com/adamhathcock/sharpcompress 2018-05-30 20:28:15 +05:00
Adam Hathcock
f9bd7ebdb0 Merge pull request #384 from MrJul/perf-readbyte
Implemented ReadByte/WriteByte on streams to improve performance
2018-05-28 09:21:28 +01:00
Julien Lebosquain
540618c062 Implemented ReadByte/WriteByte on streams to improve performance 2018-05-27 16:31:44 +02:00
Adam Hathcock
9e96dec8c9 Merge pull request #383 from itn3000/add-filename-encoding-example
add example for custom file encoding
2018-05-23 09:14:46 +01:00
itn3000
7b7af612ba add example for custom file encoding 2018-05-23 09:46:36 +09:00
Adam Hathcock
3a747ba87e Update USAGE with new stream handling 2018-05-16 08:51:33 +01:00
Adam Hathcock
87e57e3a9a Mark for 0.21.1 2018-05-15 09:14:56 +01:00
Adam Hathcock
785d0dcebf Merge pull request #381 from adamhathcock/issue-380
Allow forced encoding to override default encoding
2018-05-15 09:13:16 +01:00
Adam Hathcock
2314776f55 Also check for CustomDecoder 2018-05-15 08:28:11 +01:00
Adam Hathcock
473f5d8189 Make GetDecoder use GetEncoding for forced 2018-05-14 16:20:57 +01:00
Adam Hathcock
be971cb6f7 Allow forced encoding to override default encoding 2018-05-14 16:08:31 +01:00
Adam Hathcock
3f94c1a50d Remove lingering uses of non disposing stream 2018-05-08 14:10:49 +01:00
Adam Hathcock
2919ec293a mark for 0.21 2018-05-06 09:39:36 +01:00
Adam Hathcock
19d25152e5 Merge pull request #378 from adamhathcock/fix_crypto_namespace
Fix namespaces to not interfere with bouncy castle users
2018-05-06 09:20:17 +01:00
Adam Hathcock
747180203c Rider isn’t quite good enough in refactoring 2018-05-06 09:12:18 +01:00
Adam Hathcock
9f89a0844d Fix namespaces to not interfere with bouncy castle users 2018-05-06 09:09:45 +01:00
Adam Hathcock
c64282e915 more naming 2018-05-06 09:07:06 +01:00
Adam Hathcock
c44a80bab2 Merge remote-tracking branch 'origin/master' 2018-05-06 08:59:23 +01:00
Adam Hathcock
8dfc4a2ffb more variable naming 2018-05-06 08:59:00 +01:00
Adam Hathcock
c341c626a5 variable naming clean up 2018-05-06 08:49:32 +01:00
Adam Hathcock
173a0fe659 Some naming clean up 2018-05-05 19:35:58 +01:00
Adam Hathcock
5fdae1cf82 Make readonly and fix visibility 2018-05-05 19:23:34 +01:00
Adam Hathcock
9e892ab397 Merge pull request #376 from leezer3/master
Fix broken link in usage.md
2018-05-05 16:18:17 +01:00
Christopher Lees
e95559b4fc Fix broken link in usage.md 2018-05-05 15:08:56 +01:00
Adam Hathcock
18475cc86d Use proper xunit single threading 2018-05-05 09:38:56 +01:00
Adam Hathcock
88b59600cd Merge pull request #369 from adamhathcock/leaveOpen
Rework LeaveOpen to be consistent
2018-05-05 09:27:32 +01:00
Adam Hathcock
9a9d64bcbe Merge branch 'master' into leaveOpen
# Conflicts:
#	src/SharpCompress/Compressors/LZMA/LZipStream.cs
2018-05-05 09:25:26 +01:00
Adam Hathcock
4f3408ec25 Merge pull request #375 from adamhathcock/issue_360
Fixes lzip stream disposal
2018-05-05 09:20:35 +01:00
Adam Hathcock
e9d0fb85ac Merge branch 'master' into leaveOpen 2018-05-05 09:19:38 +01:00
Adam Hathcock
1ce37ef7a8 Fixes lzip stream disposal 2018-05-05 09:18:01 +01:00
Adam Hathcock
ecad356e30 Merge pull request #363 from sridhar6668/sridhar6668/support_extended_ascii
ZipArchive Reader: Uses IBM PC character encoding to decode filename …
2018-05-05 09:12:22 +01:00
Adam Hathcock
fafd8da91d Merge branch 'master' into leaveOpen 2018-05-05 09:10:19 +01:00
Adam Hathcock
2fb31d4b84 Merge branch 'master' into sridhar6668/support_extended_ascii 2018-05-05 09:09:09 +01:00
Adam Hathcock
8b478451ac Evil zip is a windows only test because of paths 2018-05-05 09:05:32 +01:00
Adam Hathcock
42b1205fb4 Merge pull request #374 from odinn1984/feat/fail_on_outside_target_files
fix: prevent extracting archived files outside of target path
2018-05-02 22:51:02 +01:00
odinn1986
80ceb1c375 fix: prevent extracting archived files outside of target path
This PR is meant to fix an arbitrary file write vulnerability, that can be
achieved using a specially crafted zip archive, that holds path traversal
filenames. When the filename gets concatenated to the target extraction
directory, the final path ends up outside of the target folder.

A sample malicious zip file named Zip.Evil.zip was used,
and when running the code below, resulted in the creation of C:/Temp/evil.txt
outside of the intended target directory.

There are various possible ways to avoid this issue, some include checking
for .. (dot dot) characters in the filename, but the best solution in our
opinion is to check if the final target filename, starts with the target
folder (after both are resolved to their absolute path).

Stay secure,
Snyk Team
2018-05-02 23:12:33 +03:00
Adam Hathcock
501407c3fe Change flag name to be closer to spec 2018-04-29 16:33:15 +01:00
Adam Hathcock
abddabf18e Proper fixes for all platforms 2018-04-29 16:27:26 +01:00
Adam Hathcock
91d753cbdb Merge branch 'master' into sridhar6668/support_extended_ascii 2018-04-29 15:12:02 +01:00
Adam Hathcock
259acd0694 misc additions 2018-04-29 15:09:26 +01:00
Adam Hathcock
33f7258ea2 Merge branch 'master' into leaveOpen
# Conflicts:
#	src/SharpCompress/Common/Rar/Headers/RarHeaderFactory.cs
#	src/SharpCompress/Readers/Rar/RarReader.cs
2018-04-29 14:47:08 +01:00
Adam Hathcock
1ea7bb57e5 Merge branch 'master' into sridhar6668/support_extended_ascii 2018-04-29 11:39:09 +01:00
Adam Hathcock
3e60e796fb Merge pull request #340 from adamhathcock/rar5
Rar5 Feature
2018-04-29 11:36:49 +01:00
Adam Hathcock
d9c178cbee Fix all platform support 2018-04-29 11:33:49 +01:00
Adam Hathcock
031b3c55f6 FIx solid support. I did it wrong 2018-04-29 11:12:28 +01:00
Adam Hathcock
b43d2c3d95 Disabled decryption tests 2018-04-29 10:55:51 +01:00
Adam Hathcock
d865120480 ArchiveCryptHeader renamed 2018-04-29 10:13:46 +01:00
Adam Hathcock
15534f466a Add basic rar5 crypt header 2018-04-28 18:20:40 +01:00
Adam Hathcock
9d63dcb8d6 Uncommit some tests 2018-04-28 18:14:47 +01:00
Adam Hathcock
6efe30bd6e Merge branch 'master' into rar5
# Conflicts:
#	.gitignore
2018-04-28 18:09:10 +01:00
Adam Hathcock
52dd9f0609 Merge pull request #371 from adamhathcock/Issue-370
Expose stream length.  Clean up entry stream
2018-04-26 11:33:23 +01:00
Adam Hathcock
bee7f43880 Expose stream length. Clean up entry stream 2018-04-26 09:46:01 +01:00
Adam Hathcock
d38276e8cf Fix solid and some other tests 2018-04-23 10:29:46 +01:00
Adam Hathcock
f3daaeb200 Try to use both for Rarv5 support 2018-04-23 09:39:50 +01:00
Adam Hathcock
9b152a40a9 Merge branch 'master' into rar5 2018-04-22 11:35:33 +01:00
Adam Hathcock
89ae8ca526 Rejigger read only substream 2018-04-22 11:32:47 +01:00
Adam Hathcock
68a5e474a6 More testing of file handling 2018-04-22 11:19:11 +01:00
Adam Hathcock
bf58742ddf rework of leave stream open for readers 2018-04-22 11:09:03 +01:00
Adam Hathcock
f18e5b75bb Archives set up correctly 2018-04-22 10:06:30 +01:00
Adam Hathcock
e919c99b14 First pass of removing explicit leaveOpen on streams. 2018-04-22 10:02:18 +01:00
Adam Hathcock
b960f2e5ba Minor build updates 2018-04-22 09:17:03 +01:00
srperias@microsoft.com
5d8728d592 Decode without setting the default Encoding type 2018-03-28 13:12:54 -07:00
srperias@microsoft.com
04ba6c2d73 ZipArchive Reader: Uses IBM PC character encoding to decode filename and comment if the general purpose bit 11 is not set in the header 2018-03-27 13:54:16 -07:00
Adam Hathcock
0cab9bd4b4 Mark for 0.20.0 2018-03-24 07:42:20 +00:00
Adam Hathcock
279d305013 Merge pull request #359 from prettierci-commits/prettierci-master-1521104105
PrettierCI master Sync
2018-03-15 08:56:49 +00:00
PrettierCI
750c1fb069 Sync with Prettier 2018-03-15 08:55:06 +00:00
Adam Hathcock
359a6042cd Merge pull request #352 from adamhathcock/cake-026
Cake 0.26
2018-03-01 15:40:30 +00:00
Adam Hathcock
e27d2ec660 Remove netcoreapp1.x testing 2018-03-01 15:35:55 +00:00
Adam Hathcock
da56bfc01f Merge pull request #354 from frabar666/deflate64-decompress
Support Deflate64 decompression
2018-03-01 09:14:06 +00:00
frabar666
6e2c7d2857 support Deflate64 decompression 2018-02-27 23:31:11 +01:00
Adam Hathcock
5481609554 Build with new cake 2018-02-27 08:52:55 +00:00
Frederik Carlier
a62f4df0b1 Implement entry.ToString(), let it return entry.Key (#351) 2018-02-16 13:43:23 +00:00
Adam Hathcock
f893c1272c Merge pull request #337 from 4ybaka/issue-323-tar-archive-finalization
Added ability to leave tar archive open after stream is closed
2018-01-14 19:52:08 +00:00
Dmitry
e701f5277e Merge branch 'master' into issue-323-tar-archive-finalization 2018-01-13 00:47:04 +01:00
Dmitry Nesterov
f85fd1f6a4 Added ability to leave tar archive open after stream is closed 2018-01-13 00:44:42 +01:00
Dmitry Nesterov
8f7ea420b3 Revert "Added ability to leave tar archive open after stream is closed"
This reverts commit 9092ecf331.
2018-01-13 00:41:35 +01:00
Adam Hathcock
b39f389a67 Merge branch 'master' into rar5 2018-01-10 14:58:40 +00:00
Adam Hathcock
d8c8dabb52 Merge pull request #336 from diontools/ImproveStreamSkipping
Utility.Skip uses seek
2018-01-10 11:23:24 +00:00
Dmitry Nesterov
9092ecf331 Added ability to leave tar archive open after stream is closed 2018-01-04 22:57:32 +01:00
diontools
2fd9fe96ad Utility.Skip uses seek 2018-01-03 00:23:34 +09:00
coderb
554153e6a0 rar5: port old algos 2017-12-20 19:10:06 -05:00
coderb
3c29122dfe rar5: porting old algos 2017-12-20 19:04:41 -05:00
coderb
c42dc646ae rar5: reporting older algos 2017-12-20 18:51:48 -05:00
coderb
edd6206a03 rar5: fix checkin 2017-12-20 18:32:36 -05:00
coderb
a1e7f55b95 rar5: unpack working!!! 2017-12-20 18:32:12 -05:00
coderb
218823e9b2 rar5: unpack bugfix 2017-12-20 18:13:04 -05:00
coderb
3e8f52689e unrar5: unpack wip 2017-12-20 16:01:55 -05:00
coderb
0219fc3ea9 unrar5: unpack wip 2017-12-20 14:58:49 -05:00
coderb
66cb2ab662 unrar5: unpack wip 2017-12-20 14:28:22 -05:00
coderb
91c85f0aa6 unrar5: unpack wip 2017-12-20 14:22:47 -05:00
coderb
fd9790cc36 unrar5: unpack wip 2017-12-20 14:15:20 -05:00
coderb
0d40883176 unrar5: unpack wip 2017-12-20 11:19:30 -05:00
coderb
2d0319f779 rar5: unpack wip 2017-12-20 02:11:45 -05:00
coderb
aaeaa44c0b rar5: unpack wip 2017-12-20 01:55:54 -05:00
coderb
9fc77db073 rar5: unpack wip 2017-12-20 01:39:13 -05:00
coderb
bdaa060003 rar5: unpack wip 2017-12-20 01:21:53 -05:00
coderb
b5cb9901b1 rar5: wip 2017-12-20 00:29:07 -05:00
coderb
fb4d503c9a rar5: wip 2017-12-20 00:17:47 -05:00
coderb
c3c2fcf4d0 rar5: unpack wip 2017-12-19 21:41:36 -05:00
coderb
f2d2d94d1b rar5: unpack wip 2017-12-19 14:03:53 -05:00
coderb
11c1b45335 rar5: unpack wip 2017-12-19 13:52:57 -05:00
coderb
b8a308012f rar5: unpack work 2017-12-18 11:01:37 -05:00
coderb
122a732206 unrar5: pull in fast memset code 2017-12-18 10:18:17 -05:00
coderb
59e4383209 rar5: unpack wip 2017-12-18 10:02:34 -05:00
coderb
22b008f723 rar5: unpack wip 2017-12-18 09:51:24 -05:00
coderb
c770094425 rar5: fileheader fixes 2017-12-18 09:46:18 -05:00
coderb
093a5fdf31 rar5: oops 2017-12-18 09:25:55 -05:00
coderb
f811835f02 rar5: rename Entry.IsSplit -> IsSplitAfter, misc wip 2017-12-18 09:20:20 -05:00
coderb
5dda13b800 rar5: reorg code for side by side implementations 2017-12-18 08:23:18 -05:00
coderb
a20306afe0 rar5: port wip 2017-12-17 21:23:32 -05:00
coderb
476b1df323 rar5: clean port unrarsrc 5.5.8 wip 2017-12-17 20:59:34 -05:00
coderb
aec5a913da rar5: checkin missing file 2017-12-17 20:54:54 -05:00
coderb
e13795651d rar: import unrarsrc-5.5.8 for reference
this will allow us to diff against newer version of unrarsrc if we wish to update our port
2017-12-17 17:52:00 -05:00
coderb
cc175da0d8 rar5: unpack wip 2017-12-17 17:08:53 -05:00
coderb
a2369fb531 rar5: uppercase method names 2017-12-17 12:08:09 -05:00
coderb
c5b8a444f2 rar5: unpack tighten up access modifiers 2017-12-17 12:03:41 -05:00
coderb
f450608073 rar5: unpack use partial class instead of inheritance 2017-12-17 11:46:17 -05:00
coderb
0e57537167 rar5: unpack wip 2017-12-17 11:36:33 -05:00
coderb
1445b0a48b rar5: refactor unpack classes 2017-12-17 11:33:31 -05:00
coderb
d268cc7685 rar5: wip unpack50() 2017-12-17 11:16:42 -05:00
coderb
7969bbaac4 rar5: working on decompression 2017-12-17 11:04:13 -05:00
coderb
b9e89ca64b rar5: wip 2017-12-17 10:40:41 -05:00
coderb
f802b41665 rar5: wip 2017-12-17 10:08:21 -05:00
coderb
f0eac57bb9 rar5: more cleanup 2017-12-17 09:14:08 -05:00
coderb
c9d3563f31 rar5: some cleanup 2017-12-17 09:00:11 -05:00
coderb
8563179592 rar5: wip 2017-12-17 08:35:41 -05:00
coderb
1c49ff63e2 rar5: replicate rar test cases 2017-12-17 08:09:41 -05:00
coderb
5f121c5da4 rar5 wip 2017-12-17 07:39:02 -05:00
coderb
72f52359e6 rar5: wip 2017-12-17 01:58:40 -05:00
coderb
9f549b98da rar5: support ArchiveHeader, additional rar5 header implementation 2017-12-16 20:39:53 -05:00
coderb
c346a4ca94 rar5: change rar MarkHeader detection logic to support rar5 2017-12-16 17:35:07 -05:00
coderb
d334b54846 rar5: add test archives 2017-12-16 12:54:32 -05:00
Adam Hathcock
02f68b793c Mark for 0.19.2 2017-12-16 09:08:17 +00:00
Adam Hathcock
57b9133a0f Change namespace and visibility to avoid collisions (#333) 2017-12-16 09:05:21 +00:00
Adam Hathcock
815f5e09e8 Mark for 0.19.1 2017-12-15 14:46:14 +00:00
Adam Hathcock
5bdf01ee59 Absorb arraypool from CoreFX (#331) 2017-12-15 14:45:02 +00:00
Adam Hathcock
bd9417e74c Mark for 0.19 2017-12-12 11:17:57 +00:00
Adam Hathcock
694e869162 Use arraypool for transfer/skip (#326)
* Use arraypool for transfer/skip

* Merge fixes

* Remove redundant constant
2017-12-08 13:58:38 +00:00
Adam Hathcock
45845f8963 Add Circle CI build 2017-12-08 12:03:28 +00:00
Adam Hathcock
a8b6def76a Netcore2 (#302)
* Add netstandard 2.0 target and netcoreapp2.0 tests

* Update xunit

* set tests explicitly to netcore2

* update travis

* Don't say build as netcoreapp1.0

* try adding dotnet 1 too

* Remove .NET Core 1 support

* switch to circle

* update cake

* fix circle build

* try fix file ending test again

* Fix casing on files

* Another casing fix

* Add back netstandard1.0

* Finish adding netstandard 1.0 back

* Add netstandard1.3 back
2017-12-08 12:00:29 +00:00
Sors
a4ebd5fb3d Rar 5 format (#310)
Fix rar 5 format comment
2017-12-04 18:59:49 +00:00
Adam Hathcock
3da3b212fa create new memorystream to allow proper resizing as memorystream could be a user provided buffer. Update xunit (#307) 2017-12-04 18:48:38 +00:00
Martijn Kant
c2528cf93e Mk/add support for extracting password protected LZMA(2) 7z archives (#324)
* Added possibility to decompress a password protected 7z LZMA archive

* Fix tests
2017-12-04 10:55:30 +00:00
coderb
550fecd4d3 bugfix: eliminate spurious rar crc exception when Read() is called with count = 0 (#313) 2017-10-23 11:58:02 +01:00
Adam Hathcock
50b01428b4 Mark for 0.18.2 2017-09-22 09:16:42 +01:00
Thritton
bb59f28b22 Update ArchiveReader.cs (#303)
#227
Added check if argument is in range in method TranslateTime(long? time)
2017-09-19 15:25:10 +01:00
François
7064cda6de Zlib: fix Adler32 implementation (#301) 2017-09-17 22:21:09 +01:00
Adam Hathcock
525c1873e8 Fix merge 2017-09-17 22:16:57 +01:00
François
3d91b4eb5e XZ: fix padding issues (#300)
* XZ: fix variable-length integers decoding

* XZ: fix block and index padding issues

* cleanup in XZStreamTests
2017-09-17 22:14:23 +01:00
François
f20c03180e XZ: fix variable-length integers decoding (#299) 2017-09-17 22:05:20 +01:00
Vladimir Kozlov
08fee76b4e Fixes Double Dispose() of ZipWritingStream #294 https://github.com/adamhathcock/sharpcompress/issues/294 (#295) 2017-09-08 13:25:53 +01:00
twirpx
149f5e4fb5 Minor fixes 2017-08-22 11:46:32 +05:00
twirpx
1793fc949d Fixed bug: Passing default ReaderOptions when creating ZipReader for solid extraction 2017-08-16 08:57:36 +05:00
526 changed files with 52130 additions and 9636 deletions

12
.config/dotnet-tools.json Normal file
View File

@@ -0,0 +1,12 @@
{
"version": 1,
"isRoot": true,
"tools": {
"dotnet-format": {
"version": "4.1.131201",
"commands": [
"dotnet-format"
]
}
}
}

2
.gitattributes vendored
View File

@@ -2,4 +2,4 @@
* text=auto
# need original files to be windows
test/TestArchives/Original/*.txt eol=crlf
*.txt text eol=crlf

24
.github/workflows/dotnetcore.yml vendored Normal file
View File

@@ -0,0 +1,24 @@
name: SharpCompress
on: [push, pull_request]
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [windows-latest, ubuntu-latest]
steps:
- uses: actions/checkout@v1
- uses: actions/setup-dotnet@v1
with:
dotnet-version: 5.0.101
- run: dotnet run -p build/build.csproj
- uses: actions/upload-artifact@v2
with:
name: ${{ matrix.os }}-sharpcompress.nupkg
path: artifacts/*
- uses: actions/upload-artifact@v2
with:
name: ${{ matrix.os }}-sharpcompress.snupkg
path: artifacts/*

4
.gitignore vendored
View File

@@ -14,3 +14,7 @@ tests/TestArchives/Scratch
.vs
tools
.vscode
.idea/
.DS_Store
*.snupkg

View File

@@ -1,13 +0,0 @@
dist: trusty
language: csharp
cache:
directories:
- $HOME/.dotnet
solution: SharpCompress.sln
matrix:
include:
- dotnet: 1.0.4
mono: none
env: DOTNETCORE=1
script:
- ./build.sh

View File

@@ -2,47 +2,48 @@
## Accessing Archives
- Archive classes allow random access to a seekable stream.
- Reader classes allow forward-only reading on a stream.
- Writer classes allow forward-only Writing on a stream.
* Archive classes allow random access to a seekable stream.
* Reader classes allow forward-only reading on a stream.
* Writer classes allow forward-only Writing on a stream.
## Supported Format Table
| Archive Format | Compression Format(s) | Compress/Decompress | Archive API | Reader API | Writer API |
| --- | --- | --- | --- | --- | --- |
| Rar | Rar | Decompress (1) | RarArchive | RarReader | N/A |
| Zip (2) | None, DEFLATE, BZip2, LZMA/LZMA2, PPMd | Both | ZipArchive | ZipReader | ZipWriter |
| Tar | None | Both | TarArchive | TarReader | TarWriter (3) |
| Tar.GZip | DEFLATE | Both | TarArchive | TarReader | TarWriter (3) |
| Tar.BZip2 | BZip2 | Both | TarArchive | TarReader | TarWriter (3) |
| Tar.LZip | LZMA | Both | TarArchive | TarReader | TarWriter (3) |
| Tar.XZ | LZMA2 | Decompress | TarArchive | TarReader | TarWriter (3) |
| GZip (single file) | DEFLATE | Both | GZipArchive | GZipReader | GZipWriter |
| 7Zip (4) | LZMA, LZMA2, BZip2, PPMd, BCJ, BCJ2, Deflate | Decompress | SevenZipArchive | N/A | N/A |
| LZip (single file) (5) | LZip (LZMA) | Both | LZipArchive | LZipReader | LZipWriter |
| Archive Format | Compression Format(s) | Compress/Decompress | Archive API | Reader API | Writer API |
| ---------------------- | ------------------------------------------------- | ------------------- | --------------- | ---------- | ------------- |
| Rar | Rar | Decompress (1) | RarArchive | RarReader | N/A |
| Zip (2) | None, DEFLATE, Deflate64, BZip2, LZMA/LZMA2, PPMd | Both | ZipArchive | ZipReader | ZipWriter |
| Tar | None | Both | TarArchive | TarReader | TarWriter (3) |
| Tar.GZip | DEFLATE | Both | TarArchive | TarReader | TarWriter (3) |
| Tar.BZip2 | BZip2 | Both | TarArchive | TarReader | TarWriter (3) |
| Tar.LZip | LZMA | Both | TarArchive | TarReader | TarWriter (3) |
| Tar.XZ | LZMA2 | Decompress | TarArchive | TarReader | TarWriter (3) |
| GZip (single file) | DEFLATE | Both | GZipArchive | GZipReader | GZipWriter |
| 7Zip (4) | LZMA, LZMA2, BZip2, PPMd, BCJ, BCJ2, Deflate | Decompress | SevenZipArchive | N/A | N/A |
| LZip (single file) (5) | LZip (LZMA) | Both | LZipArchive | LZipReader | LZipWriter |
1. SOLID Rars are only supported in the RarReader API.
2. Zip format supports pkware and WinzipAES encryption. However, encrypted LZMA is not supported. Zip64 reading/writing is supported but only with seekable streams as the Zip spec doesn't support Zip64 data in post data descriptors.
3. The Tar format requires a file size in the header. If no size is specified to the TarWriter and the stream is not seekable, then an exception will be thrown.
4. The 7Zip format doesn't allow for reading as a forward-only stream so 7Zip is only supported through the Archive API
5. LZip has no support for extra data like the file name or timestamp. There is a default filename used when looking at the entry Key on the archive.
1. SOLID Rars are only supported in the RarReader API.
2. Zip format supports pkware and WinzipAES encryption. However, encrypted LZMA is not supported. Zip64 reading/writing is supported but only with seekable streams as the Zip spec doesn't support Zip64 data in post data descriptors. Deflate64 is only supported for reading.
3. The Tar format requires a file size in the header. If no size is specified to the TarWriter and the stream is not seekable, then an exception will be thrown.
4. The 7Zip format doesn't allow for reading as a forward-only stream so 7Zip is only supported through the Archive API
5. LZip has no support for extra data like the file name or timestamp. There is a default filename used when looking at the entry Key on the archive.
## Compression Streams
For those who want to directly compress/decompress bits. The single file formats are represented here as well. However, BZip2, LZip and XZ have no metadata (GZip has a little) so using them without something like a Tar file makes little sense.
For those who want to directly compress/decompress bits. The single file formats are represented here as well. However, BZip2, LZip and XZ have no metadata (GZip has a little) so using them without something like a Tar file makes little sense.
| Compressor | Compress/Decompress |
| --- | --- |
| BZip2Stream | Both |
| GZipStream | Both |
| DeflateStream | Both |
| LZMAStream | Both |
| PPMdStream | Both |
| ADCStream | Decompress |
| LZipStream | Both |
| XZStream | Decompress |
| Compressor | Compress/Decompress |
| --------------- | ------------------- |
| BZip2Stream | Both |
| GZipStream | Both |
| DeflateStream | Both |
| Deflate64Stream | Decompress |
| LZMAStream | Both |
| PPMdStream | Both |
| ADCStream | Decompress |
| LZipStream | Both |
| XZStream | Decompress |
## Archive Formats vs Compression
## Archive Formats vs Compression
Sometimes the terminology gets mixed.
@@ -52,9 +53,8 @@ DEFLATE, LZMA are pure compression algorithms
### Formats
Formats like Zip, 7Zip, Rar are archive formats only. They use other compression methods (e.g. DEFLATE, LZMA, etc.) or propriatory (e.g RAR)
Formats like Zip, 7Zip, Rar are archive formats only. They use other compression methods (e.g. DEFLATE, LZMA, etc.) or propriatory (e.g RAR)
### Overlap
GZip, BZip2 and LZip are single file archival formats. The overlap in the API happens because Tar uses the single file formats as "compression" methods and the API tries to hide this a bit.
GZip, BZip2 and LZip are single file archival formats. The overlap in the API happens because Tar uses the single file formats as "compression" methods and the API tries to hide this a bit.

View File

@@ -1,35 +1,33 @@
# SharpCompress
SharpCompress is a compression library in pure C# for .NET 3.5, 4.5, .NET Standard 1.0, 1.3 that can unrar, un7zip, unzip, untar unbzip2 and ungzip with forward-only reading and file random access APIs. Write support for zip/tar/bzip2/gzip are implemented.
SharpCompress is a compression library in pure C# for .NET Standard 2.0, 2.1, .NET Core 3.1 and .NET 5.0 that can unrar, un7zip, unzip, untar unbzip2, ungzip, unlzip with forward-only reading and file random access APIs. Write support for zip/tar/bzip2/gzip/lzip are implemented.
The major feature is support for non-seekable streams so large files can be processed on the fly (i.e. download stream).
The major feature is support for non-seekable streams so large files can be processed on the fly (i.e. download stream).
AppVeyor Build -
[![Build status](https://ci.appveyor.com/api/projects/status/voxg971oemmvxh1e/branch/master?svg=true)](https://ci.appveyor.com/project/adamhathcock/sharpcompress/branch/master)
Travis CI Build -
[![Build Status](https://travis-ci.org/adamhathcock/sharpcompress.svg?branch=master)](https://travis-ci.org/adamhathcock/sharpcompress)
GitHub Actions Build -
[![GitHubActions](https://github.com/adamhathcock/sharpcompress/workflows/SharpCompress/badge.svg)](https://circleci.com/gh/adamhathcock/sharpcompress)
## Need Help?
Post Issues on Github!
Check the [Supported Formats](FORMATS.md) and [Basic Usage.](USAGE.md)
## Recommended Formats
In general, I recommend GZip (Deflate)/BZip2 (BZip)/LZip (LZMA) as the simplicity of the formats lend to better long term archival as well as the streamability. Tar is often used in conjunction for multiple files in a single archive (e.g. `.tar.gz`)
In general, I recommend GZip (Deflate)/BZip2 (BZip)/LZip (LZMA) as the simplicity of the formats lend to better long term archival as well as the streamability. Tar is often used in conjunction for multiple files in a single archive (e.g. `.tar.gz`)
Zip is okay, but it's a very hap-hazard format and the variation in headers and implementations makes it hard to get correct. Uses Deflate by default but supports a lot of compression methods.
Zip is okay, but it's a very hap-hazard format and the variation in headers and implementations makes it hard to get correct. Uses Deflate by default but supports a lot of compression methods.
RAR is not recommended as it's a propriatory format and the compression is closed source. Use Tar/LZip for LZMA
RAR is not recommended as it's a propriatory format and the compression is closed source. Use Tar/LZip for LZMA
7Zip and XZ both are overly complicated. 7Zip does not support streamable formats. XZ has known holes explained here: (http://www.nongnu.org/lzip/xz_inadequate.html) Use Tar/LZip for LZMA compression instead.
7Zip and XZ both are overly complicated. 7Zip does not support streamable formats. XZ has known holes explained here: (http://www.nongnu.org/lzip/xz_inadequate.html) Use Tar/LZip for LZMA compression instead.
## A Simple Request
Hi everyone. I hope you're using SharpCompress and finding it useful. Please give me feedback on what you'd like to see changed especially as far as usability goes. New feature suggestions are always welcome as well. I would also like to know what projects SharpCompress is being used in. I like seeing how it is used to give me ideas for future versions. Thanks!
Please do not email me directly to ask for help. If you think there is a real issue, please report it here.
Please do not email me directly to ask for help. If you think there is a real issue, please report it here.
## Want to contribute?
@@ -37,7 +35,7 @@ I'm always looking for help or ideas. Please submit code or email with ideas. Un
## TODOs (always lots)
* RAR 5 support
* RAR 5 decryption support
* 7Zip writing
* Zip64 (Need writing and extend Reading)
* Multi-volume Zip support.
@@ -54,9 +52,9 @@ I'm always looking for help or ideas. Please submit code or email with ideas. Un
### Version 0.17.0
* New - Full LZip support! Can read and write LZip files and Tars inside LZip files. [Make LZip a first class citizen. #241](https://github.com/adamhathcock/sharpcompress/issues/241)
* New - XZ read support! Can read XZ files and Tars inside XZ files. [XZ in SharpCompress #91](https://github.com/adamhathcock/sharpcompress/issues/94)
* Fix - [Regression - zip file writing on seekable streams always assumed stream start was 0. Introduced with Zip64 writing.](https://github.com/adamhathcock/sharpcompress/issues/244)
* New - Full LZip support! Can read and write LZip files and Tars inside LZip files. [Make LZip a first class citizen. #241](https://github.com/adamhathcock/sharpcompress/issues/241)
* New - XZ read support! Can read XZ files and Tars inside XZ files. [XZ in SharpCompress #91](https://github.com/adamhathcock/sharpcompress/issues/94)
* Fix - [Regression - zip file writing on seekable streams always assumed stream start was 0. Introduced with Zip64 writing.](https://github.com/adamhathcock/sharpcompress/issues/244)
* Fix - [Zip files with post-data descriptors can be properly skipped via decompression](https://github.com/adamhathcock/sharpcompress/issues/162)
### Version 0.16.2
@@ -136,7 +134,7 @@ I'm always looking for help or ideas. Please submit code or email with ideas. Un
### Version 0.11.6
* Bug fix for global header in Tar
* Writers now have a leaveOpen `bool` overload. They won't close streams if not-requested to.
* Writers now have a leaveOpen `bool` overload. They won't close streams if not-requested to.
### Version 0.11.5
@@ -155,7 +153,7 @@ I'm always looking for help or ideas. Please submit code or email with ideas. Un
### Version 0.11
* Been over a year, contains mainly fixes from contributors!
* Been over a year, contains mainly fixes from contributors!
* Possible breaking change: ArchiveEncoding is UTF8 by default now.
* TAR supports writing long names using longlink
* RAR Protect Header added

View File

@@ -13,6 +13,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SharpCompress", "src\SharpC
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SharpCompress.Test", "tests\SharpCompress.Test\SharpCompress.Test.csproj", "{F2B1A1EB-0FA6-40D0-8908-E13247C7226F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "build", "build\build.csproj", "{D4D613CB-5E94-47FB-85BE-B8423D20C545}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -27,6 +29,10 @@ Global
{F2B1A1EB-0FA6-40D0-8908-E13247C7226F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F2B1A1EB-0FA6-40D0-8908-E13247C7226F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F2B1A1EB-0FA6-40D0-8908-E13247C7226F}.Release|Any CPU.Build.0 = Release|Any CPU
{D4D613CB-5E94-47FB-85BE-B8423D20C545}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D4D613CB-5E94-47FB-85BE-B8423D20C545}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D4D613CB-5E94-47FB-85BE-B8423D20C545}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D4D613CB-5E94-47FB-85BE-B8423D20C545}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@@ -45,10 +45,14 @@
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/INDENT_ANONYMOUS_METHOD_BLOCK/@EntryValue">True</s:Boolean>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/KEEP_BLANK_LINES_IN_CODE/@EntryValue">1</s:Int64>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/KEEP_BLANK_LINES_IN_DECLARATIONS/@EntryValue">1</s:Int64>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_ACCESSOR_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_ACCESSORHOLDER_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_CONSTRUCTOR_INITIALIZER_ON_SAME_LINE/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_FIELD_ATTRIBUTE_ON_SAME_LINE/@EntryValue">False</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_FIELD_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_ACCESSORHOLDER_ON_SINGLE_LINE/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_ACCESSOR_ATTRIBUTE_ON_SAME_LINE/@EntryValue">False</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_EMBEDDED_STATEMENT_ON_SAME_LINE/@EntryValue">NEVER</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_INITIALIZER_ON_SINGLE_LINE/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_WHILE_ON_NEW_LINE/@EntryValue">True</s:Boolean>
@@ -114,6 +118,15 @@
<s:String x:Key="/Default/CodeStyle/Naming/XamlNaming/UserRules/=NAMESPACE_005FALIAS/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/XamlNaming/UserRules/=XAML_005FFIELD/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/XamlNaming/UserRules/=XAML_005FRESOURCE/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpAttributeForSingleLineMethodUpgrade/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpRenamePlacementToArrangementMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EAddAccessorOwnerDeclarationBracesMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002ECSharpPlaceAttributeOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateThisQualifierSettings/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateThisQualifierSettings/@EntryIndexedValue">True</s:Boolean>
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=6af8f80e_002D9fdd_002D4223_002D8e02_002D473db916f9b2/@EntryIndexedValue">&lt;SessionState ContinuousTestingIsOn="False" ContinuousTestingMode="0" FrameworkVersion="{x:Null}" IsLocked="False" Name="All tests from Solution" PlatformMonoPreference="{x:Null}" PlatformType="{x:Null}" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"&gt;
&lt;Solution /&gt;
&lt;/SessionState&gt;</s:String></wpf:ResourceDictionary>

View File

@@ -1,7 +1,8 @@
# SharpCompress Usage
## Stream Rules
When dealing with Streams, the rule should be that you don't close a stream you didn't create. This, in effect, should mean you should always put a Stream in a using block to dispose it.
## Stream Rules (changed with 0.21)
When dealing with Streams, the rule should be that you don't close a stream you didn't create. This, in effect, should mean you should always put a Stream in a using block to dispose it.
However, the .NET Framework often has classes that will dispose streams by default to make things "easy" like the following:
@@ -12,7 +13,7 @@ using (var reader = new StreamReader(File.Open("foo")))
}
```
In this example, reader should get disposed. However, stream rules should say the the `FileStream` created by `File.Open` should remain open. However, the .NET Framework closes it for you by default unless you override the constructor. In general, you should be writing Stream code like this:
In this example, reader should get disposed. However, stream rules should say the the `FileStream` created by `File.Open` should remain open. However, the .NET Framework closes it for you by default unless you override the constructor. In general, you should be writing Stream code like this:
```C#
using (var fileStream = File.Open("foo"))
@@ -22,16 +23,15 @@ using (var reader = new StreamReader(fileStream))
}
```
To deal with the "correct" rules as well as the expectations of users, I've decided on this:
* When writing, leave streams open.
* When reading, close streams
To deal with the "correct" rules as well as the expectations of users, I've decided to always close wrapped streams as of 0.21.
To be explicit though, consider always using the overloads that use `ReaderOptions` or `WriterOptions` and explicitly set `LeaveStreamOpen` the way you want.
If using Compression Stream classes directly and you don't want the wrapped stream to be closed. Use the `NonDisposingStream` as a wrapped to prevent the stream being disposed. The change in 0.21 simplified a lot even though the usage is a bit more convoluted.
## Samples
Also, look over the tests for more thorough [examples](https://github.com/adamhathcock/sharpcompress/tree/master/test/SharpCompress.Test)
Also, look over the tests for more thorough [examples](https://github.com/adamhathcock/sharpcompress/tree/master/tests/SharpCompress.Test)
### Create Zip Archive from all files in a directory to a file
@@ -43,11 +43,9 @@ using (var archive = ZipArchive.Create())
}
```
### Create Zip Archive from all files in a directory and save in memory
```C#
var memoryStream = new MemoryStream();
using (var archive = ZipArchive.Create())
{
@@ -129,3 +127,20 @@ using (var writer = WriterFactory.Open(stream, ArchiveType.Tar, new WriterOption
writer.WriteAll("D:\\temp", "*", SearchOption.AllDirectories);
}
```
### Extract zip which has non-utf8 encoded filename(cp932)
```C#
var opts = new SharpCompress.Readers.ReaderOptions();
var encoding = Encoding.GetEncoding(932);
opts.ArchiveEncoding = new SharpCompress.Common.ArchiveEncoding();
opts.ArchiveEncoding.CustomDecoder = (data, x, y) =>
{
return encoding.GetString(data);
};
var tr = SharpCompress.Archives.Zip.ZipArchive.Open("test.zip", opts);
foreach(var entry in tr.Entries)
{
Console.WriteLine($"{entry.Key}");
}
```

View File

@@ -1,20 +0,0 @@
version: '{build}'
image: Visual Studio 2017
pull_requests:
do_not_increment_build_number: true
branches:
only:
- master
nuget:
disable_publish_on_pr: true
build_script:
- ps: .\build.ps1
test: off
artifacts:
- path: src\SharpCompress\bin\Release\*.nupkg

View File

@@ -1,93 +0,0 @@
var target = Argument("target", "Default");
var tag = Argument("tag", "cake");
Task("Restore")
.Does(() =>
{
DotNetCoreRestore(".");
});
Task("Build")
.IsDependentOn("Restore")
.Does(() =>
{
if (IsRunningOnWindows())
{
MSBuild("./sharpcompress.sln", c =>
{
c.SetConfiguration("Release")
.SetVerbosity(Verbosity.Minimal)
.UseToolVersion(MSBuildToolVersion.VS2017);
});
}
else
{
var settings = new DotNetCoreBuildSettings
{
Framework = "netstandard1.0",
Configuration = "Release"
};
DotNetCoreBuild("./src/SharpCompress/SharpCompress.csproj", settings);
settings.Framework = "netcoreapp1.1";
DotNetCoreBuild("./tests/SharpCompress.Test/SharpCompress.Test.csproj", settings);
}
});
Task("Test")
.IsDependentOn("Build")
.Does(() =>
{
if (!bool.Parse(EnvironmentVariable("APPVEYOR") ?? "false")
&& !bool.Parse(EnvironmentVariable("TRAVIS") ?? "false"))
{
var files = GetFiles("tests/**/*.csproj");
foreach(var file in files)
{
var settings = new DotNetCoreTestSettings
{
Configuration = "Release"
};
DotNetCoreTest(file.ToString(), settings);
}
}
else
{
Information("Skipping tests as this is AppVeyor or Travis CI");
}
});
Task("Pack")
.IsDependentOn("Build")
.Does(() =>
{
if (IsRunningOnWindows())
{
MSBuild("src/SharpCompress/SharpCompress.csproj", c => c
.SetConfiguration("Release")
.SetVerbosity(Verbosity.Minimal)
.UseToolVersion(MSBuildToolVersion.VS2017)
.WithProperty("NoBuild", "true")
.WithTarget("Pack"));
}
else
{
Information("Skipping Pack as this is not Windows");
}
});
Task("Default")
.IsDependentOn("Restore")
.IsDependentOn("Build")
.IsDependentOn("Test")
.IsDependentOn("Pack");
Task("RunTests")
.IsDependentOn("Restore")
.IsDependentOn("Build")
.IsDependentOn("Test");
RunTarget(target);

228
build.ps1
View File

@@ -1,228 +0,0 @@
##########################################################################
# This is the Cake bootstrapper script for PowerShell.
# This file was downloaded from https://github.com/cake-build/resources
# Feel free to change this file to fit your needs.
##########################################################################
<#
.SYNOPSIS
This is a Powershell script to bootstrap a Cake build.
.DESCRIPTION
This Powershell script will download NuGet if missing, restore NuGet tools (including Cake)
and execute your Cake build script with the parameters you provide.
.PARAMETER Script
The build script to execute.
.PARAMETER Target
The build script target to run.
.PARAMETER Configuration
The build configuration to use.
.PARAMETER Verbosity
Specifies the amount of information to be displayed.
.PARAMETER Experimental
Tells Cake to use the latest Roslyn release.
.PARAMETER WhatIf
Performs a dry run of the build script.
No tasks will be executed.
.PARAMETER Mono
Tells Cake to use the Mono scripting engine.
.PARAMETER SkipToolPackageRestore
Skips restoring of packages.
.PARAMETER ScriptArgs
Remaining arguments are added here.
.LINK
http://cakebuild.net
#>
[CmdletBinding()]
Param(
[string]$Script = "build.cake",
[string]$Target = "Default",
[ValidateSet("Release", "Debug")]
[string]$Configuration = "Release",
[ValidateSet("Quiet", "Minimal", "Normal", "Verbose", "Diagnostic")]
[string]$Verbosity = "Verbose",
[switch]$Experimental,
[Alias("DryRun","Noop")]
[switch]$WhatIf,
[switch]$Mono,
[switch]$SkipToolPackageRestore,
[Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)]
[string[]]$ScriptArgs
)
[Reflection.Assembly]::LoadWithPartialName("System.Security") | Out-Null
function MD5HashFile([string] $filePath)
{
if ([string]::IsNullOrEmpty($filePath) -or !(Test-Path $filePath -PathType Leaf))
{
return $null
}
[System.IO.Stream] $file = $null;
[System.Security.Cryptography.MD5] $md5 = $null;
try
{
$md5 = [System.Security.Cryptography.MD5]::Create()
$file = [System.IO.File]::OpenRead($filePath)
return [System.BitConverter]::ToString($md5.ComputeHash($file))
}
finally
{
if ($file -ne $null)
{
$file.Dispose()
}
}
}
Write-Host "Preparing to run build script..."
if(!$PSScriptRoot){
$PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent
}
$TOOLS_DIR = Join-Path $PSScriptRoot "tools"
$ADDINS_DIR = Join-Path $TOOLS_DIR "addins"
$MODULES_DIR = Join-Path $TOOLS_DIR "modules"
$NUGET_EXE = Join-Path $TOOLS_DIR "nuget.exe"
$CAKE_EXE = Join-Path $TOOLS_DIR "Cake/Cake.exe"
$NUGET_URL = "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe"
$PACKAGES_CONFIG = Join-Path $TOOLS_DIR "packages.config"
$PACKAGES_CONFIG_MD5 = Join-Path $TOOLS_DIR "packages.config.md5sum"
$ADDINS_PACKAGES_CONFIG = Join-Path $ADDINS_DIR "packages.config"
$MODULES_PACKAGES_CONFIG = Join-Path $MODULES_DIR "packages.config"
# Should we use mono?
$UseMono = "";
if($Mono.IsPresent) {
Write-Verbose -Message "Using the Mono based scripting engine."
$UseMono = "-mono"
}
# Should we use the new Roslyn?
$UseExperimental = "";
if($Experimental.IsPresent -and !($Mono.IsPresent)) {
Write-Verbose -Message "Using experimental version of Roslyn."
$UseExperimental = "-experimental"
}
# Is this a dry run?
$UseDryRun = "";
if($WhatIf.IsPresent) {
$UseDryRun = "-dryrun"
}
# Make sure tools folder exists
if ((Test-Path $PSScriptRoot) -and !(Test-Path $TOOLS_DIR)) {
Write-Verbose -Message "Creating tools directory..."
New-Item -Path $TOOLS_DIR -Type directory | out-null
}
# Make sure that packages.config exist.
if (!(Test-Path $PACKAGES_CONFIG)) {
Write-Verbose -Message "Downloading packages.config..."
try { (New-Object System.Net.WebClient).DownloadFile("http://cakebuild.net/download/bootstrapper/packages", $PACKAGES_CONFIG) } catch {
Throw "Could not download packages.config."
}
}
# Try find NuGet.exe in path if not exists
if (!(Test-Path $NUGET_EXE)) {
Write-Verbose -Message "Trying to find nuget.exe in PATH..."
$existingPaths = $Env:Path -Split ';' | Where-Object { (![string]::IsNullOrEmpty($_)) -and (Test-Path $_ -PathType Container) }
$NUGET_EXE_IN_PATH = Get-ChildItem -Path $existingPaths -Filter "nuget.exe" | Select -First 1
if ($NUGET_EXE_IN_PATH -ne $null -and (Test-Path $NUGET_EXE_IN_PATH.FullName)) {
Write-Verbose -Message "Found in PATH at $($NUGET_EXE_IN_PATH.FullName)."
$NUGET_EXE = $NUGET_EXE_IN_PATH.FullName
}
}
# Try download NuGet.exe if not exists
if (!(Test-Path $NUGET_EXE)) {
Write-Verbose -Message "Downloading NuGet.exe..."
try {
(New-Object System.Net.WebClient).DownloadFile($NUGET_URL, $NUGET_EXE)
} catch {
Throw "Could not download NuGet.exe."
}
}
# Save nuget.exe path to environment to be available to child processed
$ENV:NUGET_EXE = $NUGET_EXE
# Restore tools from NuGet?
if(-Not $SkipToolPackageRestore.IsPresent) {
Push-Location
Set-Location $TOOLS_DIR
# Check for changes in packages.config and remove installed tools if true.
[string] $md5Hash = MD5HashFile($PACKAGES_CONFIG)
if((!(Test-Path $PACKAGES_CONFIG_MD5)) -Or
($md5Hash -ne (Get-Content $PACKAGES_CONFIG_MD5 ))) {
Write-Verbose -Message "Missing or changed package.config hash..."
Remove-Item * -Recurse -Exclude packages.config,nuget.exe
}
Write-Verbose -Message "Restoring tools from NuGet..."
$NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$TOOLS_DIR`""
if ($LASTEXITCODE -ne 0) {
Throw "An error occured while restoring NuGet tools."
}
else
{
$md5Hash | Out-File $PACKAGES_CONFIG_MD5 -Encoding "ASCII"
}
Write-Verbose -Message ($NuGetOutput | out-string)
Pop-Location
}
# Restore addins from NuGet
if (Test-Path $ADDINS_PACKAGES_CONFIG) {
Push-Location
Set-Location $ADDINS_DIR
Write-Verbose -Message "Restoring addins from NuGet..."
$NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$ADDINS_DIR`""
if ($LASTEXITCODE -ne 0) {
Throw "An error occured while restoring NuGet addins."
}
Write-Verbose -Message ($NuGetOutput | out-string)
Pop-Location
}
# Restore modules from NuGet
if (Test-Path $MODULES_PACKAGES_CONFIG) {
Push-Location
Set-Location $MODULES_DIR
Write-Verbose -Message "Restoring modules from NuGet..."
$NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$MODULES_DIR`""
if ($LASTEXITCODE -ne 0) {
Throw "An error occured while restoring NuGet modules."
}
Write-Verbose -Message ($NuGetOutput | out-string)
Pop-Location
}
# Make sure that Cake has been installed.
if (!(Test-Path $CAKE_EXE)) {
Throw "Could not find Cake.exe at $CAKE_EXE"
}
# Start Cake
Write-Host "Running build script..."
Invoke-Expression "& `"$CAKE_EXE`" `"$Script`" -target=`"$Target`" -configuration=`"$Configuration`" -verbosity=`"$Verbosity`" $UseMono $UseDryRun $UseExperimental $ScriptArgs"
exit $LASTEXITCODE

View File

@@ -1,42 +0,0 @@
#!/usr/bin/env bash
##########################################################################
# This is the Cake bootstrapper script for Linux and OS X.
# This file was downloaded from https://github.com/cake-build/resources
# Feel free to change this file to fit your needs.
##########################################################################
# Define directories.
SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
TOOLS_DIR=$SCRIPT_DIR/tools
CAKE_VERSION=0.19.1
CAKE_DLL=$TOOLS_DIR/Cake.CoreCLR.$CAKE_VERSION/Cake.dll
# Make sure the tools folder exist.
if [ ! -d "$TOOLS_DIR" ]; then
mkdir "$TOOLS_DIR"
fi
###########################################################################
# INSTALL CAKE
###########################################################################
if [ ! -f "$CAKE_DLL" ]; then
curl -Lsfo Cake.CoreCLR.zip "https://www.nuget.org/api/v2/package/Cake.CoreCLR/$CAKE_VERSION" && unzip -q Cake.CoreCLR.zip -d "$TOOLS_DIR/Cake.CoreCLR.$CAKE_VERSION" && rm -f Cake.CoreCLR.zip
if [ $? -ne 0 ]; then
echo "An error occured while installing Cake."
exit 1
fi
fi
# Make sure that Cake has been installed.
if [ ! -f "$CAKE_DLL" ]; then
echo "Could not find Cake.exe at '$CAKE_DLL'."
exit 1
fi
###########################################################################
# RUN BUILD SCRIPT
###########################################################################
# Start Cake
exec dotnet "$CAKE_DLL" "$@"

83
build/Program.cs Normal file
View File

@@ -0,0 +1,83 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using GlobExpressions;
using static Bullseye.Targets;
using static SimpleExec.Command;
class Program
{
private const string Clean = "clean";
private const string Format = "format";
private const string Build = "build";
private const string Test = "test";
private const string Publish = "publish";
static void Main(string[] args)
{
Target(Clean,
ForEach("**/bin", "**/obj"),
dir =>
{
IEnumerable<string> GetDirectories(string d)
{
return Glob.Directories(".", d);
}
void RemoveDirectory(string d)
{
if (Directory.Exists(d))
{
Console.WriteLine(d);
Directory.Delete(d, true);
}
}
foreach (var d in GetDirectories(dir))
{
RemoveDirectory(d);
}
});
Target(Format, () =>
{
Run("dotnet", "tool restore");
Run("dotnet", "format --check");
});
Target(Build, DependsOn(Format),
framework =>
{
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && framework == "net46")
{
return;
}
Run("dotnet", "build src/SharpCompress/SharpCompress.csproj -c Release");
});
Target(Test, DependsOn(Build), ForEach("net5.0"),
framework =>
{
IEnumerable<string> GetFiles(string d)
{
return Glob.Files(".", d);
}
foreach (var file in GetFiles("**/*.Test.csproj"))
{
Run("dotnet", $"test {file} -c Release -f {framework}");
}
});
Target(Publish, DependsOn(Test),
() =>
{
Run("dotnet", "pack src/SharpCompress/SharpCompress.csproj -c Release -o artifacts/");
});
Target("default", DependsOn(Publish), () => Console.WriteLine("Done!"));
RunTargetsAndExit(args);
}
}

14
build/build.csproj Normal file
View File

@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Bullseye" Version="3.6.0" />
<PackageReference Include="Glob" Version="1.1.8" />
<PackageReference Include="SimpleExec" Version="6.4.0" />
</ItemGroup>
</Project>

5
global.json Normal file
View File

@@ -0,0 +1,5 @@
{
"sdk": {
"version": "5.0.101"
}
}

3497
reference/APPNOTE.TXT Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,279 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{95CC809B-03FC-4EDB-BB20-FD07A698C05F}</ProjectGuid>
<RootNamespace>UnRAR</RootNamespace>
<Keyword>Win32Proj</Keyword>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v140_xp</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
<WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v140_xp</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v140_xp</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
<WholeProgramOptimization>false</WholeProgramOptimization>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v140_xp</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>14.0.24720.0</_ProjectFileVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<OutDir>build\unrar32\$(Configuration)\</OutDir>
<IntDir>build\unrar32\$(Configuration)\obj\</IntDir>
<LinkIncremental>true</LinkIncremental>
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<OutDir>build\unrar64\$(Configuration)\</OutDir>
<IntDir>build\unrar64\$(Configuration)\obj\</IntDir>
<LinkIncremental>true</LinkIncremental>
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>build\unrar32\$(Configuration)\</OutDir>
<IntDir>build\unrar32\$(Configuration)\obj\</IntDir>
<LinkIncremental>false</LinkIncremental>
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<OutDir>build\unrar64\$(Configuration)\</OutDir>
<IntDir>build\unrar64\$(Configuration)\obj\</IntDir>
<LinkIncremental>false</LinkIncremental>
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>UNRAR;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CallingConvention>StdCall</CallingConvention>
<DisableSpecificWarnings>4007;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<TargetMachine>MachineX86</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>UNRAR;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CallingConvention>StdCall</CallingConvention>
<DisableSpecificWarnings>4007;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<TargetMachine>MachineX64</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions>
<Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
<FavorSizeOrSpeed>Neither</FavorSizeOrSpeed>
<OmitFramePointers>true</OmitFramePointers>
<WholeProgramOptimization>false</WholeProgramOptimization>
<PreprocessorDefinitions>UNRAR;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<StructMemberAlignment>Default</StructMemberAlignment>
<BufferSecurityCheck>true</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
<EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
<FloatingPointModel>Precise</FloatingPointModel>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CallingConvention>StdCall</CallingConvention>
<DisableSpecificWarnings>4007;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<LinkTimeCodeGeneration />
<TargetMachine>MachineX86</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions>
<Optimization>MinSpace</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
<FavorSizeOrSpeed>Neither</FavorSizeOrSpeed>
<OmitFramePointers>true</OmitFramePointers>
<WholeProgramOptimization>false</WholeProgramOptimization>
<PreprocessorDefinitions>UNRAR;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>false</StringPooling>
<MinimalRebuild>false</MinimalRebuild>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<BufferSecurityCheck>true</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CallingConvention>StdCall</CallingConvention>
<DisableSpecificWarnings>4007;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<LinkTimeCodeGeneration />
<TargetMachine>MachineX64</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="archive.cpp" />
<ClCompile Include="arcread.cpp" />
<ClCompile Include="blake2s.cpp" />
<ClCompile Include="cmddata.cpp" />
<ClCompile Include="consio.cpp" />
<ClCompile Include="crc.cpp" />
<ClCompile Include="crypt.cpp" />
<ClCompile Include="encname.cpp" />
<ClCompile Include="errhnd.cpp" />
<ClCompile Include="extinfo.cpp" />
<ClCompile Include="extract.cpp" />
<ClCompile Include="filcreat.cpp" />
<ClCompile Include="file.cpp" />
<ClCompile Include="filefn.cpp" />
<ClCompile Include="filestr.cpp" />
<ClCompile Include="find.cpp" />
<ClCompile Include="getbits.cpp" />
<ClCompile Include="global.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
</PrecompiledHeader>
</ClCompile>
<ClCompile Include="hash.cpp" />
<ClCompile Include="headers.cpp" />
<ClCompile Include="isnt.cpp" />
<ClCompile Include="list.cpp" />
<ClCompile Include="match.cpp" />
<ClCompile Include="options.cpp" />
<ClCompile Include="pathfn.cpp" />
<ClCompile Include="qopen.cpp" />
<ClCompile Include="rar.cpp" />
<ClCompile Include="rarpch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="rarvm.cpp" />
<ClCompile Include="rawread.cpp" />
<ClCompile Include="rdwrfn.cpp" />
<ClCompile Include="recvol.cpp" />
<ClCompile Include="resource.cpp" />
<ClCompile Include="rijndael.cpp" />
<ClCompile Include="rs.cpp" />
<ClCompile Include="rs16.cpp" />
<ClCompile Include="scantree.cpp" />
<ClCompile Include="secpassword.cpp" />
<ClCompile Include="sha1.cpp" />
<ClCompile Include="sha256.cpp" />
<ClCompile Include="smallfn.cpp" />
<ClCompile Include="strfn.cpp" />
<ClCompile Include="strlist.cpp" />
<ClCompile Include="system.cpp" />
<ClCompile Include="threadpool.cpp" />
<ClCompile Include="timefn.cpp" />
<ClCompile Include="ui.cpp" />
<ClCompile Include="unicode.cpp" />
<ClCompile Include="unpack.cpp" />
<ClCompile Include="volume.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@@ -0,0 +1,420 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="release_nocrypt|Win32">
<Configuration>release_nocrypt</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="release_nocrypt|x64">
<Configuration>release_nocrypt</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectName>UnRAR</ProjectName>
<ProjectGuid>{E815C46C-36C4-499F-BBC2-E772C6B17971}</ProjectGuid>
<RootNamespace>UnRAR</RootNamespace>
<Keyword>Win32Proj</Keyword>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='release_nocrypt|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v140_xp</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
<WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v140_xp</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
<WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v140_xp</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='release_nocrypt|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v140_xp</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
<WholeProgramOptimization>false</WholeProgramOptimization>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v140_xp</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
<WholeProgramOptimization>false</WholeProgramOptimization>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v140_xp</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='release_nocrypt|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='release_nocrypt|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>14.0.24720.0</_ProjectFileVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<OutDir>build\unrardll32\$(Configuration)\</OutDir>
<IntDir>build\unrardll32\$(Configuration)\obj\</IntDir>
<LinkIncremental>true</LinkIncremental>
<GenerateManifest>true</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<OutDir>build\unrardll64\$(Configuration)\</OutDir>
<IntDir>build\unrardll64\$(Configuration)\obj\</IntDir>
<LinkIncremental>true</LinkIncremental>
<GenerateManifest>true</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>build\unrardll32\$(Configuration)\</OutDir>
<IntDir>build\unrardll32\$(Configuration)\obj\</IntDir>
<LinkIncremental>false</LinkIncremental>
<GenerateManifest>true</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<OutDir>build\unrardll64\$(Configuration)\</OutDir>
<IntDir>build\unrardll64\$(Configuration)\obj\</IntDir>
<LinkIncremental>false</LinkIncremental>
<GenerateManifest>true</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='release_nocrypt|Win32'">
<OutDir>build\unrardll32\$(Configuration)\</OutDir>
<IntDir>build\unrardll32\$(Configuration)\obj\</IntDir>
<LinkIncremental>false</LinkIncremental>
<GenerateManifest>true</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='release_nocrypt|x64'">
<OutDir>build\unrardll64\$(Configuration)\</OutDir>
<IntDir>build\unrardll64\$(Configuration)\obj\</IntDir>
<LinkIncremental>false</LinkIncremental>
<GenerateManifest>true</GenerateManifest>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>RARDLL;UNRAR;SILENT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild>
<ExceptionHandling>Sync</ExceptionHandling>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<StructMemberAlignment>4Bytes</StructMemberAlignment>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CallingConvention>Cdecl</CallingConvention>
<DisableSpecificWarnings>4007;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
</ClCompile>
<Link>
<OutputFile>$(OutDir)unrar.dll</OutputFile>
<ModuleDefinitionFile>dll.def</ModuleDefinitionFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<TargetMachine>MachineX86</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>RARDLL;UNRAR;SILENT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild>
<ExceptionHandling>Sync</ExceptionHandling>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<StructMemberAlignment>4Bytes</StructMemberAlignment>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CallingConvention>Cdecl</CallingConvention>
<DisableSpecificWarnings>4007;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet>
</ClCompile>
<Link>
<OutputFile>$(OutDir)unrar.dll</OutputFile>
<ModuleDefinitionFile>dll.def</ModuleDefinitionFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<TargetMachine>MachineX64</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions>
<Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
<FavorSizeOrSpeed>Neither</FavorSizeOrSpeed>
<OmitFramePointers>true</OmitFramePointers>
<WholeProgramOptimization>false</WholeProgramOptimization>
<PreprocessorDefinitions>RARDLL;UNRAR;SILENT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild>
<ExceptionHandling>Sync</ExceptionHandling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<StructMemberAlignment>4Bytes</StructMemberAlignment>
<BufferSecurityCheck>true</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
<EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
<FloatingPointModel>Precise</FloatingPointModel>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CallingConvention>Cdecl</CallingConvention>
<DisableSpecificWarnings>4007;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
</ClCompile>
<Link>
<AdditionalOptions>/SAFESEH %(AdditionalOptions)</AdditionalOptions>
<OutputFile>$(OutDir)unrar.dll</OutputFile>
<ModuleDefinitionFile>dll.def</ModuleDefinitionFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<LinkTimeCodeGeneration />
<TargetMachine>MachineX86</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions>
<Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
<FavorSizeOrSpeed>Neither</FavorSizeOrSpeed>
<OmitFramePointers>true</OmitFramePointers>
<WholeProgramOptimization>false</WholeProgramOptimization>
<PreprocessorDefinitions>RARDLL;UNRAR;SILENT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>false</StringPooling>
<MinimalRebuild>false</MinimalRebuild>
<ExceptionHandling>Sync</ExceptionHandling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<StructMemberAlignment>4Bytes</StructMemberAlignment>
<BufferSecurityCheck>true</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CallingConvention>Cdecl</CallingConvention>
<DisableSpecificWarnings>4007;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet>
</ClCompile>
<Link>
<OutputFile>$(OutDir)unrar.dll</OutputFile>
<ModuleDefinitionFile>dll.def</ModuleDefinitionFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<LinkTimeCodeGeneration />
<TargetMachine>MachineX64</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='release_nocrypt|Win32'">
<ClCompile>
<AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions>
<Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
<FavorSizeOrSpeed>Neither</FavorSizeOrSpeed>
<OmitFramePointers>true</OmitFramePointers>
<WholeProgramOptimization>false</WholeProgramOptimization>
<PreprocessorDefinitions>RARDLL;UNRAR;SILENT;RAR_NOCRYPT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild>
<ExceptionHandling>Sync</ExceptionHandling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<StructMemberAlignment>4Bytes</StructMemberAlignment>
<BufferSecurityCheck>true</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
<EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
<FloatingPointModel>Precise</FloatingPointModel>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CallingConvention>Cdecl</CallingConvention>
<DisableSpecificWarnings>4007;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
</ClCompile>
<Link>
<AdditionalOptions>/SAFESEH %(AdditionalOptions)</AdditionalOptions>
<OutputFile>$(OutDir)unrar.dll</OutputFile>
<ModuleDefinitionFile>dll_nocrypt.def</ModuleDefinitionFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<LinkTimeCodeGeneration />
<TargetMachine>MachineX86</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='release_nocrypt|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions>
<Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
<FavorSizeOrSpeed>Neither</FavorSizeOrSpeed>
<OmitFramePointers>true</OmitFramePointers>
<WholeProgramOptimization>false</WholeProgramOptimization>
<PreprocessorDefinitions>RARDLL;UNRAR;SILENT;RAR_NOCRYPT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>false</StringPooling>
<MinimalRebuild>false</MinimalRebuild>
<ExceptionHandling>Sync</ExceptionHandling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<StructMemberAlignment>4Bytes</StructMemberAlignment>
<BufferSecurityCheck>true</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CallingConvention>StdCall</CallingConvention>
<DisableSpecificWarnings>4007;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet>
</ClCompile>
<Link>
<OutputFile>$(OutDir)unrar.dll</OutputFile>
<ModuleDefinitionFile>dll_nocrypt.def</ModuleDefinitionFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<LinkTimeCodeGeneration />
<TargetMachine>MachineX64</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="archive.cpp" />
<ClCompile Include="arcread.cpp" />
<ClCompile Include="blake2s.cpp" />
<ClCompile Include="cmddata.cpp" />
<ClCompile Include="consio.cpp" />
<ClCompile Include="crc.cpp" />
<ClCompile Include="crypt.cpp" />
<ClCompile Include="dll.cpp" />
<ClCompile Include="encname.cpp" />
<ClCompile Include="errhnd.cpp" />
<ClCompile Include="extinfo.cpp" />
<ClCompile Include="extract.cpp" />
<ClCompile Include="filcreat.cpp" />
<ClCompile Include="file.cpp" />
<ClCompile Include="filefn.cpp" />
<ClCompile Include="filestr.cpp" />
<ClCompile Include="find.cpp" />
<ClCompile Include="getbits.cpp" />
<ClCompile Include="global.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='release_nocrypt|Win32'">
</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='release_nocrypt|x64'">
</PrecompiledHeader>
</ClCompile>
<ClCompile Include="hash.cpp" />
<ClCompile Include="headers.cpp" />
<ClCompile Include="isnt.cpp" />
<ClCompile Include="match.cpp" />
<ClCompile Include="options.cpp" />
<ClCompile Include="pathfn.cpp" />
<ClCompile Include="qopen.cpp" />
<ClCompile Include="rar.cpp" />
<ClCompile Include="rarpch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='release_nocrypt|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='release_nocrypt|x64'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="rarvm.cpp" />
<ClCompile Include="rawread.cpp" />
<ClCompile Include="rdwrfn.cpp" />
<ClCompile Include="rijndael.cpp" />
<ClCompile Include="rs.cpp" />
<ClCompile Include="rs16.cpp" />
<ClCompile Include="scantree.cpp" />
<ClCompile Include="secpassword.cpp" />
<ClCompile Include="sha1.cpp" />
<ClCompile Include="sha256.cpp" />
<ClCompile Include="smallfn.cpp" />
<ClCompile Include="strfn.cpp" />
<ClCompile Include="strlist.cpp" />
<ClCompile Include="system.cpp" />
<ClCompile Include="threadpool.cpp" />
<ClCompile Include="timefn.cpp" />
<ClCompile Include="ui.cpp" />
<ClCompile Include="unicode.cpp" />
<ClCompile Include="unpack.cpp" />
<ClCompile Include="volume.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="rar.hpp" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="dll.rc" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@@ -0,0 +1,92 @@
ACKNOWLEDGMENTS
* We used "Screaming Fast Galois Field Arithmetic Using Intel
SIMD Instructions" paper by James S. Plank, Kevin M. Greenan
and Ethan L. Miller to improve Reed-Solomon coding performance.
Also we are grateful to Artem Drobanov and Bulat Ziganshin
for samples and ideas allowed to make Reed-Solomon coding
more efficient.
* RAR text compression algorithm is based on Dmitry Shkarin PPMII
and Dmitry Subbotin carryless rangecoder public domain source code.
You may find it in ftp.elf.stuba.sk/pub/pc/pack.
* RAR encryption includes parts of code from Szymon Stefanek
and Brian Gladman AES implementations also as Steve Reid SHA-1 source.
---------------------------------------------------------------------------
Copyright (c) 2002, Dr Brian Gladman < >, Worcester, UK.
All rights reserved.
LICENSE TERMS
The free distribution and use of this software in both source and binary
form is allowed (with or without changes) provided that:
1. distributions of this source code include the above copyright
notice, this list of conditions and the following disclaimer;
2. distributions in binary form include the above copyright
notice, this list of conditions and the following disclaimer
in the documentation and/or other associated materials;
3. the copyright holder's name is not used to endorse products
built using this software without specific written permission.
ALTERNATIVELY, provided that this notice is retained in full, this product
may be distributed under the terms of the GNU General Public License (GPL),
in which case the provisions of the GPL apply INSTEAD OF those given above.
DISCLAIMER
This software is provided 'as is' with no explicit or implied warranties
in respect of its properties, including, but not limited to, correctness
and/or fitness for purpose.
---------------------------------------------------------------------------
Source code of this package also as other cryptographic technology
and computing project related links are available on Brian Gladman's
web site: http://www.gladman.me.uk
* RAR uses CRC32 function based on Intel Slicing-by-8 algorithm.
Original Intel Slicing-by-8 code is available here:
http://sourceforge.net/projects/slicing-by-8/
Original Intel Slicing-by-8 code is licensed under BSD License
available at http://www.opensource.org/licenses/bsd-license.html
Copyright (c) 2004-2006 Intel Corporation.
All Rights Reserved
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with
the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
* RAR archives may optionally include BLAKE2sp hash ( https://blake2.net ),
designed by Jean-Philippe Aumasson, Samuel Neves, Zooko Wilcox-O'Hearn
and Christian Winnerlein.
* Useful hints provided by Alexander Khoroshev and Bulat Ziganshin allowed
to significantly improve RAR compression and speed.

166
reference/unrar/arccmt.cpp Normal file
View File

@@ -0,0 +1,166 @@
static bool IsAnsiEscComment(const wchar *Data,size_t Size);
bool Archive::GetComment(Array<wchar> *CmtData)
{
if (!MainComment)
return false;
SaveFilePos SavePos(*this);
#ifndef SFX_MODULE
uint CmtLength;
if (Format==RARFMT14)
{
Seek(SFXSize+SIZEOF_MAINHEAD14,SEEK_SET);
CmtLength=GetByte();
CmtLength+=(GetByte()<<8);
}
else
#endif
{
if (MainHead.CommentInHeader)
{
// Old style (RAR 2.9) archive comment embedded into the main
// archive header.
Seek(SFXSize+SIZEOF_MARKHEAD3+SIZEOF_MAINHEAD3,SEEK_SET);
ReadHeader();
}
else
{
// Current (RAR 3.0+) version of archive comment.
Seek(GetStartPos(),SEEK_SET);
return SearchSubBlock(SUBHEAD_TYPE_CMT)!=0 && ReadCommentData(CmtData);
}
#ifndef SFX_MODULE
// Old style (RAR 2.9) comment header embedded into the main
// archive header.
if (BrokenHeader)
{
uiMsg(UIERROR_CMTBROKEN,FileName);
return false;
}
CmtLength=CommHead.HeadSize-SIZEOF_COMMHEAD;
#endif
}
#ifndef SFX_MODULE
if (Format==RARFMT14 && MainHead.PackComment || Format!=RARFMT14 && CommHead.Method!=0x30)
{
if (Format!=RARFMT14 && (CommHead.UnpVer < 15 || CommHead.UnpVer > VER_UNPACK || CommHead.Method > 0x35))
return false;
ComprDataIO DataIO;
DataIO.SetTestMode(true);
uint UnpCmtLength;
if (Format==RARFMT14)
{
#ifdef RAR_NOCRYPT
return false;
#else
UnpCmtLength=GetByte();
UnpCmtLength+=(GetByte()<<8);
CmtLength-=2;
DataIO.SetCmt13Encryption();
CommHead.UnpVer=15;
#endif
}
else
UnpCmtLength=CommHead.UnpSize;
DataIO.SetFiles(this,NULL);
DataIO.EnableShowProgress(false);
DataIO.SetPackedSizeToRead(CmtLength);
DataIO.UnpHash.Init(HASH_CRC32,1);
Unpack CmtUnpack(&DataIO);
CmtUnpack.Init(0x10000,false);
CmtUnpack.SetDestSize(UnpCmtLength);
CmtUnpack.DoUnpack(CommHead.UnpVer,false);
if (Format!=RARFMT14 && (DataIO.UnpHash.GetCRC32()&0xffff)!=CommHead.CommCRC)
{
uiMsg(UIERROR_CMTBROKEN,FileName);
return false;
}
else
{
byte *UnpData;
size_t UnpDataSize;
DataIO.GetUnpackedData(&UnpData,&UnpDataSize);
#ifdef _WIN_ALL
// If we ever decide to extend it to Android, we'll need to alloc
// 4x memory for OEM to UTF-8 output here.
OemToCharBuffA((char *)UnpData,(char *)UnpData,(DWORD)UnpDataSize);
#endif
CmtData->Alloc(UnpDataSize+1);
memset(CmtData->Addr(0),0,CmtData->Size()*sizeof(wchar));
CharToWide((char *)UnpData,CmtData->Addr(0),CmtData->Size());
CmtData->Alloc(wcslen(CmtData->Addr(0)));
}
}
else
{
if (CmtLength==0)
return false;
Array<byte> CmtRaw(CmtLength);
Read(&CmtRaw[0],CmtLength);
if (Format!=RARFMT14 && CommHead.CommCRC!=(~CRC32(0xffffffff,&CmtRaw[0],CmtLength)&0xffff))
{
uiMsg(UIERROR_CMTBROKEN,FileName);
return false;
}
CmtData->Alloc(CmtLength+1);
CmtRaw.Push(0);
#ifdef _WIN_ALL
// If we ever decide to extend it to Android, we'll need to alloc
// 4x memory for OEM to UTF-8 output here.
OemToCharA((char *)&CmtRaw[0],(char *)&CmtRaw[0]);
#endif
CharToWide((char *)&CmtRaw[0],CmtData->Addr(0),CmtLength);
CmtData->Alloc(wcslen(CmtData->Addr(0)));
}
#endif
return CmtData->Size() > 0;
}
bool Archive::ReadCommentData(Array<wchar> *CmtData)
{
Array<byte> CmtRaw;
if (!ReadSubData(&CmtRaw,NULL))
return false;
size_t CmtSize=CmtRaw.Size();
CmtRaw.Push(0);
CmtData->Alloc(CmtSize+1);
if (Format==RARFMT50)
UtfToWide((char *)&CmtRaw[0],CmtData->Addr(0),CmtData->Size());
else
if ((SubHead.SubFlags & SUBHEAD_FLAGS_CMT_UNICODE)!=0)
{
RawToWide(&CmtRaw[0],CmtData->Addr(0),CmtSize/2);
(*CmtData)[CmtSize/2]=0;
}
else
{
CharToWide((char *)&CmtRaw[0],CmtData->Addr(0),CmtData->Size());
}
CmtData->Alloc(wcslen(CmtData->Addr(0))); // Set buffer size to actual comment length.
return true;
}
void Archive::ViewComment()
{
if (Cmd->DisableComment)
return;
Array<wchar> CmtBuf;
if (GetComment(&CmtBuf)) // In GUI too, so "Test" command detects broken comments.
{
size_t CmtSize=CmtBuf.Size();
wchar *ChPtr=wcschr(&CmtBuf[0],0x1A);
if (ChPtr!=NULL)
CmtSize=ChPtr-&CmtBuf[0];
mprintf(L"\n");
OutComment(&CmtBuf[0],CmtSize);
}
}

332
reference/unrar/archive.cpp Normal file
View File

@@ -0,0 +1,332 @@
#include "rar.hpp"
#include "arccmt.cpp"
Archive::Archive(RAROptions *InitCmd)
{
Cmd=NULL; // Just in case we'll have an exception in 'new' below.
DummyCmd=(InitCmd==NULL);
Cmd=DummyCmd ? (new RAROptions):InitCmd;
OpenShared=Cmd->OpenShared;
Format=RARFMT15;
Solid=false;
Volume=false;
MainComment=false;
Locked=false;
Signed=false;
FirstVolume=false;
NewNumbering=false;
SFXSize=0;
LatestTime.Reset();
Protected=false;
Encrypted=false;
FailedHeaderDecryption=false;
BrokenHeader=false;
LastReadBlock=0;
CurBlockPos=0;
NextBlockPos=0;
RecoverySize=-1;
RecoveryPercent=-1;
memset(&MainHead,0,sizeof(MainHead));
memset(&CryptHead,0,sizeof(CryptHead));
memset(&EndArcHead,0,sizeof(EndArcHead));
VolNumber=0;
VolWrite=0;
AddingFilesSize=0;
AddingHeadersSize=0;
*FirstVolumeName=0;
Splitting=false;
NewArchive=false;
SilentOpen=false;
}
Archive::~Archive()
{
if (DummyCmd)
delete Cmd;
}
void Archive::CheckArc(bool EnableBroken)
{
if (!IsArchive(EnableBroken))
{
// If FailedHeaderDecryption is set, we already reported that archive
// password is incorrect.
if (!FailedHeaderDecryption)
uiMsg(UIERROR_BADARCHIVE,FileName);
ErrHandler.Exit(RARX_FATAL);
}
}
#if !defined(SFX_MODULE)
void Archive::CheckOpen(const wchar *Name)
{
TOpen(Name);
CheckArc(false);
}
#endif
bool Archive::WCheckOpen(const wchar *Name)
{
if (!WOpen(Name))
return false;
if (!IsArchive(false))
{
uiMsg(UIERROR_BADARCHIVE,FileName);
Close();
return false;
}
return true;
}
RARFORMAT Archive::IsSignature(const byte *D,size_t Size)
{
RARFORMAT Type=RARFMT_NONE;
if (Size>=1 && D[0]==0x52)
#ifndef SFX_MODULE
if (Size>=4 && D[1]==0x45 && D[2]==0x7e && D[3]==0x5e)
Type=RARFMT14;
else
#endif
if (Size>=7 && D[1]==0x61 && D[2]==0x72 && D[3]==0x21 && D[4]==0x1a && D[5]==0x07)
{
// We check the last signature byte, so we can return a sensible
// warning in case we'll want to change the archive format
// sometimes in the future.
if (D[6]==0)
Type=RARFMT15;
else
if (D[6]==1)
Type=RARFMT50;
else
if (D[6]==2)
Type=RARFMT_FUTURE;
}
return Type;
}
bool Archive::IsArchive(bool EnableBroken)
{
Encrypted=false;
BrokenHeader=false; // Might be left from previous volume.
#ifndef SFX_MODULE
if (IsDevice())
{
uiMsg(UIERROR_INVALIDNAME,FileName,FileName);
return false;
}
#endif
if (Read(MarkHead.Mark,SIZEOF_MARKHEAD3)!=SIZEOF_MARKHEAD3)
return false;
SFXSize=0;
RARFORMAT Type;
if ((Type=IsSignature(MarkHead.Mark,SIZEOF_MARKHEAD3))!=RARFMT_NONE)
{
Format=Type;
if (Format==RARFMT14)
Seek(Tell()-SIZEOF_MARKHEAD3,SEEK_SET);
}
else
{
Array<char> Buffer(MAXSFXSIZE);
long CurPos=(long)Tell();
int ReadSize=Read(&Buffer[0],Buffer.Size()-16);
for (int I=0;I<ReadSize;I++)
if (Buffer[I]==0x52 && (Type=IsSignature((byte *)&Buffer[I],ReadSize-I))!=RARFMT_NONE)
{
Format=Type;
if (Format==RARFMT14 && I>0 && CurPos<28 && ReadSize>31)
{
char *D=&Buffer[28-CurPos];
if (D[0]!=0x52 || D[1]!=0x53 || D[2]!=0x46 || D[3]!=0x58)
continue;
}
SFXSize=CurPos+I;
Seek(SFXSize,SEEK_SET);
if (Format==RARFMT15 || Format==RARFMT50)
Read(MarkHead.Mark,SIZEOF_MARKHEAD3);
break;
}
if (SFXSize==0)
return false;
}
if (Format==RARFMT_FUTURE)
{
uiMsg(UIERROR_NEWRARFORMAT,FileName);
return false;
}
if (Format==RARFMT50) // RAR 5.0 signature is by one byte longer.
{
Read(MarkHead.Mark+SIZEOF_MARKHEAD3,1);
if (MarkHead.Mark[SIZEOF_MARKHEAD3]!=0)
return false;
MarkHead.HeadSize=SIZEOF_MARKHEAD5;
}
else
MarkHead.HeadSize=SIZEOF_MARKHEAD3;
#ifdef RARDLL
// If callback function is not set, we cannot get the password,
// so we skip the initial header processing for encrypted header archive.
// It leads to skipped archive comment, but the rest of archive data
// is processed correctly.
if (Cmd->Callback==NULL)
SilentOpen=true;
#endif
// Skip the archive encryption header if any and read the main header.
while (ReadHeader()!=0)
{
HEADER_TYPE Type=GetHeaderType();
// In RAR 5.0 we need to quit after reading HEAD_CRYPT if we wish to
// avoid the password prompt.
if (Type==HEAD_MAIN || SilentOpen && Type==HEAD_CRYPT)
break;
SeekToNext();
}
// This check allows to make RS based recovery even if password is incorrect.
// But we should not do it for EnableBroken or we'll get 'not RAR archive'
// messages when extracting encrypted archives with wrong password.
if (FailedHeaderDecryption && !EnableBroken)
return false;
SeekToNext();
if (BrokenHeader) // Main archive header is corrupt.
{
uiMsg(UIERROR_MHEADERBROKEN,FileName);
if (!EnableBroken)
return false;
}
MainComment=MainHead.CommentInHeader;
// If we process non-encrypted archive or can request a password,
// we set 'first volume' flag based on file attributes below.
// It is necessary for RAR 2.x archives, which did not have 'first volume'
// flag in main header. Also for all RAR formats we need to scan until
// first file header to set "comment" flag when reading service header.
// Unless we are in silent mode, we need to know about presence of comment
// immediately after IsArchive call.
if (!SilentOpen || !Encrypted)
{
SaveFilePos SavePos(*this);
int64 SaveCurBlockPos=CurBlockPos,SaveNextBlockPos=NextBlockPos;
HEADER_TYPE SaveCurHeaderType=CurHeaderType;
while (ReadHeader()!=0)
{
HEADER_TYPE HeaderType=GetHeaderType();
if (HeaderType==HEAD_SERVICE)
{
// If we have a split service headers, it surely indicates non-first
// volume. But not split service header does not guarantee the first
// volume, because we can have split file after non-split archive
// comment. So we do not quit from loop here.
FirstVolume=Volume && !SubHead.SplitBefore;
}
else
if (HeaderType==HEAD_FILE)
{
FirstVolume=Volume && !FileHead.SplitBefore;
break;
}
else
if (HeaderType==HEAD_ENDARC) // Might happen if archive contains only a split service header.
break;
SeekToNext();
}
CurBlockPos=SaveCurBlockPos;
NextBlockPos=SaveNextBlockPos;
CurHeaderType=SaveCurHeaderType;
}
if (!Volume || FirstVolume)
wcscpy(FirstVolumeName,FileName);
return true;
}
void Archive::SeekToNext()
{
Seek(NextBlockPos,SEEK_SET);
}
// Calculate the block size including encryption fields and padding if any.
uint Archive::FullHeaderSize(size_t Size)
{
if (Encrypted)
{
Size = ALIGN_VALUE(Size, CRYPT_BLOCK_SIZE); // Align to encryption block size.
if (Format == RARFMT50)
Size += SIZE_INITV;
else
Size += SIZE_SALT30;
}
return uint(Size);
}
#ifdef USE_QOPEN
bool Archive::Open(const wchar *Name,uint Mode)
{
// Important if we reuse Archive object and it has virtual QOpen
// file position not matching real. For example, for 'l -v volname'.
QOpen.Unload();
return File::Open(Name,Mode);
}
int Archive::Read(void *Data,size_t Size)
{
size_t Result;
if (QOpen.Read(Data,Size,Result))
return (int)Result;
return File::Read(Data,Size);
}
void Archive::Seek(int64 Offset,int Method)
{
if (!QOpen.Seek(Offset,Method))
File::Seek(Offset,Method);
}
int64 Archive::Tell()
{
int64 QPos;
if (QOpen.Tell(&QPos))
return QPos;
return File::Tell();
}
#endif

151
reference/unrar/archive.hpp Normal file
View File

@@ -0,0 +1,151 @@
#ifndef _RAR_ARCHIVE_
#define _RAR_ARCHIVE_
class PPack;
class RawRead;
class RawWrite;
enum NOMODIFY_FLAGS
{
NMDF_ALLOWLOCK=1,NMDF_ALLOWANYVOLUME=2,NMDF_ALLOWFIRSTVOLUME=4
};
enum RARFORMAT {RARFMT_NONE,RARFMT14,RARFMT15,RARFMT50,RARFMT_FUTURE};
enum ADDSUBDATA_FLAGS
{
ASDF_SPLIT = 1, // Allow to split archive just before header if necessary.
ASDF_COMPRESS = 2, // Allow to compress data following subheader.
ASDF_CRYPT = 4, // Encrypt data after subheader if password is set.
ASDF_CRYPTIFHEADERS = 8 // Encrypt data after subheader only in -hp mode.
};
class Archive:public File
{
private:
void UpdateLatestTime(FileHeader *CurBlock);
void ConvertNameCase(wchar *Name);
void ConvertFileHeader(FileHeader *hd);
void WriteBlock50(HEADER_TYPE HeaderType,BaseBlock *wb,bool OnlySetSize,bool NonFinalWrite);
size_t ReadHeader14();
size_t ReadHeader15();
size_t ReadHeader50();
void ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb);
void RequestArcPassword();
void UnexpEndArcMsg();
void BrokenHeaderMsg();
void UnkEncVerMsg(const wchar *Name);
void UnkEncVerMsg();
bool ReadCommentData(Array<wchar> *CmtData);
#if !defined(RAR_NOCRYPT)
CryptData HeadersCrypt;
#endif
ComprDataIO SubDataIO;
bool DummyCmd;
RAROptions *Cmd;
int64 RecoverySize;
int RecoveryPercent;
RarTime LatestTime;
int LastReadBlock;
HEADER_TYPE CurHeaderType;
bool SilentOpen;
#ifdef USE_QOPEN
QuickOpen QOpen;
#endif
public:
Archive(RAROptions *InitCmd=NULL);
~Archive();
static RARFORMAT IsSignature(const byte *D,size_t Size);
bool IsArchive(bool EnableBroken);
size_t SearchBlock(HEADER_TYPE HeaderType);
size_t SearchSubBlock(const wchar *Type);
size_t SearchRR();
void WriteBlock(HEADER_TYPE HeaderType,BaseBlock *wb=NULL,bool OnlySetSize=false,bool NonFinalWrite=false);
void SetBlockSize(HEADER_TYPE HeaderType,BaseBlock *wb=NULL) {WriteBlock(HeaderType,wb,true);}
size_t ReadHeader();
void CheckArc(bool EnableBroken);
void CheckOpen(const wchar *Name);
bool WCheckOpen(const wchar *Name);
bool GetComment(Array<wchar> *CmtData);
void ViewComment();
void SetLatestTime(RarTime *NewTime);
void SeekToNext();
bool CheckAccess();
bool IsArcDir();
void ConvertAttributes();
void VolSubtractHeaderSize(size_t SubSize);
uint FullHeaderSize(size_t Size);
int64 GetStartPos();
void AddSubData(byte *SrcData,uint64 DataSize,File *SrcFile,
const wchar *Name,uint Flags);
bool ReadSubData(Array<byte> *UnpData,File *DestFile);
HEADER_TYPE GetHeaderType() {return CurHeaderType;};
RAROptions* GetRAROptions() {return Cmd;}
void SetSilentOpen(bool Mode) {SilentOpen=Mode;}
#if 0
void GetRecoveryInfo(bool Required,int64 *Size,int *Percent);
#endif
#ifdef USE_QOPEN
bool Open(const wchar *Name,uint Mode=FMF_READ);
int Read(void *Data,size_t Size);
void Seek(int64 Offset,int Method);
int64 Tell();
void QOpenUnload() {QOpen.Unload();}
#endif
BaseBlock ShortBlock;
MarkHeader MarkHead;
MainHeader MainHead;
CryptHeader CryptHead;
FileHeader FileHead;
EndArcHeader EndArcHead;
SubBlockHeader SubBlockHead;
FileHeader SubHead;
CommentHeader CommHead;
ProtectHeader ProtectHead;
AVHeader AVHead;
SignHeader SignHead;
UnixOwnersHeader UOHead;
MacFInfoHeader MACHead;
EAHeader EAHead;
StreamHeader StreamHead;
int64 CurBlockPos;
int64 NextBlockPos;
RARFORMAT Format;
bool Solid;
bool Volume;
bool MainComment;
bool Locked;
bool Signed;
bool FirstVolume;
bool NewNumbering;
bool Protected;
bool Encrypted;
size_t SFXSize;
bool BrokenHeader;
bool FailedHeaderDecryption;
#if !defined(RAR_NOCRYPT)
byte ArcSalt[SIZE_SALT50];
#endif
bool Splitting;
uint VolNumber;
int64 VolWrite;
uint64 AddingFilesSize;
uint64 AddingHeadersSize;
bool NewArchive;
wchar FirstVolumeName[NM];
};
#endif

1437
reference/unrar/arcread.cpp Normal file

File diff suppressed because it is too large Load Diff

191
reference/unrar/array.hpp Normal file
View File

@@ -0,0 +1,191 @@
#ifndef _RAR_ARRAY_
#define _RAR_ARRAY_
extern ErrorHandler ErrHandler;
template <class T> class Array
{
private:
T *Buffer;
size_t BufSize;
size_t AllocSize;
size_t MaxSize;
bool Secure; // Clean memory if true.
public:
Array();
Array(size_t Size);
Array(const Array &Src); // Copy constructor.
~Array();
inline void CleanData();
inline T& operator [](size_t Item) const;
inline T* operator + (size_t Pos);
inline size_t Size(); // Returns the size in items, not in bytes.
void Add(size_t Items);
void Alloc(size_t Items);
void Reset();
void SoftReset();
void operator = (Array<T> &Src);
void Push(T Item);
void Append(T *Item,size_t Count);
T* Addr(size_t Item) {return Buffer+Item;}
void SetMaxSize(size_t Size) {MaxSize=Size;}
T* Begin() {return Buffer;}
T* End() {return Buffer==NULL ? NULL:Buffer+BufSize;}
void SetSecure() {Secure=true;}
};
template <class T> void Array<T>::CleanData()
{
Buffer=NULL;
BufSize=0;
AllocSize=0;
MaxSize=0;
Secure=false;
}
template <class T> Array<T>::Array()
{
CleanData();
}
template <class T> Array<T>::Array(size_t Size)
{
CleanData();
Add(Size);
}
// Copy constructor in case we need to pass an object as value.
template <class T> Array<T>::Array(const Array &Src)
{
CleanData();
Alloc(Src.BufSize);
if (Src.BufSize!=0)
memcpy((void *)Buffer,(void *)Src.Buffer,Src.BufSize*sizeof(T));
}
template <class T> Array<T>::~Array()
{
if (Buffer!=NULL)
{
if (Secure)
cleandata(Buffer,AllocSize*sizeof(T));
free(Buffer);
}
}
template <class T> inline T& Array<T>::operator [](size_t Item) const
{
return Buffer[Item];
}
template <class T> inline T* Array<T>::operator +(size_t Pos)
{
return Buffer+Pos;
}
template <class T> inline size_t Array<T>::Size()
{
return BufSize;
}
template <class T> void Array<T>::Add(size_t Items)
{
BufSize+=Items;
if (BufSize>AllocSize)
{
if (MaxSize!=0 && BufSize>MaxSize)
{
ErrHandler.GeneralErrMsg(L"Maximum allowed array size (%u) is exceeded",MaxSize);
ErrHandler.MemoryError();
}
size_t Suggested=AllocSize+AllocSize/4+32;
size_t NewSize=Max(BufSize,Suggested);
T *NewBuffer;
if (Secure)
{
NewBuffer=(T *)malloc(NewSize*sizeof(T));
if (NewBuffer==NULL)
ErrHandler.MemoryError();
if (Buffer!=NULL)
{
memcpy(NewBuffer,Buffer,AllocSize*sizeof(T));
cleandata(Buffer,AllocSize*sizeof(T));
free(Buffer);
}
}
else
{
NewBuffer=(T *)realloc(Buffer,NewSize*sizeof(T));
if (NewBuffer==NULL)
ErrHandler.MemoryError();
}
Buffer=NewBuffer;
AllocSize=NewSize;
}
}
template <class T> void Array<T>::Alloc(size_t Items)
{
if (Items>AllocSize)
Add(Items-BufSize);
else
BufSize=Items;
}
template <class T> void Array<T>::Reset()
{
if (Buffer!=NULL)
{
free(Buffer);
Buffer=NULL;
}
BufSize=0;
AllocSize=0;
}
// Reset buffer size, but preserve already allocated memory if any,
// so we can reuse it without wasting time to allocation.
template <class T> void Array<T>::SoftReset()
{
BufSize=0;
}
template <class T> void Array<T>::operator =(Array<T> &Src)
{
Reset();
Alloc(Src.BufSize);
if (Src.BufSize!=0)
memcpy((void *)Buffer,(void *)Src.Buffer,Src.BufSize*sizeof(T));
}
template <class T> void Array<T>::Push(T Item)
{
Add(1);
(*this)[Size()-1]=Item;
}
template <class T> void Array<T>::Append(T *Items,size_t Count)
{
size_t CurSize=Size();
Add(Count);
memcpy(Buffer+CurSize,Items,Count*sizeof(T));
}
#endif

183
reference/unrar/blake2s.cpp Normal file
View File

@@ -0,0 +1,183 @@
// Based on public domain code written in 2012 by Samuel Neves
#include "rar.hpp"
#ifdef USE_SSE
#include "blake2s_sse.cpp"
#endif
static void blake2s_init_param( blake2s_state *S, uint32 node_offset, uint32 node_depth);
static void blake2s_update( blake2s_state *S, const byte *in, size_t inlen );
static void blake2s_final( blake2s_state *S, byte *digest );
#include "blake2sp.cpp"
static const uint32 blake2s_IV[8] =
{
0x6A09E667UL, 0xBB67AE85UL, 0x3C6EF372UL, 0xA54FF53AUL,
0x510E527FUL, 0x9B05688CUL, 0x1F83D9ABUL, 0x5BE0CD19UL
};
static const byte blake2s_sigma[10][16] =
{
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } ,
{ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } ,
{ 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } ,
{ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } ,
{ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } ,
{ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } ,
{ 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } ,
{ 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } ,
{ 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } ,
{ 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } ,
};
static inline void blake2s_set_lastnode( blake2s_state *S )
{
S->f[1] = ~0U;
}
/* Some helper functions, not necessarily useful */
static inline void blake2s_set_lastblock( blake2s_state *S )
{
if( S->last_node ) blake2s_set_lastnode( S );
S->f[0] = ~0U;
}
static inline void blake2s_increment_counter( blake2s_state *S, const uint32 inc )
{
S->t[0] += inc;
S->t[1] += ( S->t[0] < inc );
}
/* init2 xors IV with input parameter block */
void blake2s_init_param( blake2s_state *S, uint32 node_offset, uint32 node_depth)
{
#ifdef USE_SSE
if (_SSE_Version>=SSE_SSE2)
blake2s_init_sse();
#endif
S->init(); // Clean data.
for( int i = 0; i < 8; ++i )
S->h[i] = blake2s_IV[i];
S->h[0] ^= 0x02080020; // We use BLAKE2sp parameters block.
S->h[2] ^= node_offset;
S->h[3] ^= (node_depth<<16)|0x20000000;
}
#define G(r,i,m,a,b,c,d) \
a = a + b + m[blake2s_sigma[r][2*i+0]]; \
d = rotr32(d ^ a, 16); \
c = c + d; \
b = rotr32(b ^ c, 12); \
a = a + b + m[blake2s_sigma[r][2*i+1]]; \
d = rotr32(d ^ a, 8); \
c = c + d; \
b = rotr32(b ^ c, 7);
static void blake2s_compress( blake2s_state *S, const byte block[BLAKE2S_BLOCKBYTES] )
{
uint32 m[16];
uint32 v[16];
for( size_t i = 0; i < 16; ++i )
m[i] = RawGet4( block + i * 4 );
for( size_t i = 0; i < 8; ++i )
v[i] = S->h[i];
v[ 8] = blake2s_IV[0];
v[ 9] = blake2s_IV[1];
v[10] = blake2s_IV[2];
v[11] = blake2s_IV[3];
v[12] = S->t[0] ^ blake2s_IV[4];
v[13] = S->t[1] ^ blake2s_IV[5];
v[14] = S->f[0] ^ blake2s_IV[6];
v[15] = S->f[1] ^ blake2s_IV[7];
for ( uint r = 0; r <= 9; ++r ) // No gain on i7 if unrolled, but exe size grows.
{
G(r,0,m,v[ 0],v[ 4],v[ 8],v[12]);
G(r,1,m,v[ 1],v[ 5],v[ 9],v[13]);
G(r,2,m,v[ 2],v[ 6],v[10],v[14]);
G(r,3,m,v[ 3],v[ 7],v[11],v[15]);
G(r,4,m,v[ 0],v[ 5],v[10],v[15]);
G(r,5,m,v[ 1],v[ 6],v[11],v[12]);
G(r,6,m,v[ 2],v[ 7],v[ 8],v[13]);
G(r,7,m,v[ 3],v[ 4],v[ 9],v[14]);
}
for( size_t i = 0; i < 8; ++i )
S->h[i] = S->h[i] ^ v[i] ^ v[i + 8];
}
void blake2s_update( blake2s_state *S, const byte *in, size_t inlen )
{
while( inlen > 0 )
{
size_t left = S->buflen;
size_t fill = 2 * BLAKE2S_BLOCKBYTES - left;
if( inlen > fill )
{
memcpy( S->buf + left, in, fill ); // Fill buffer
S->buflen += fill;
blake2s_increment_counter( S, BLAKE2S_BLOCKBYTES );
#ifdef USE_SSE
#ifdef _WIN_32 // We use SSSE3 _mm_shuffle_epi8 only in x64 mode.
if (_SSE_Version>=SSE_SSE2)
#else
if (_SSE_Version>=SSE_SSSE3)
#endif
blake2s_compress_sse( S, S->buf );
else
blake2s_compress( S, S->buf ); // Compress
#else
blake2s_compress( S, S->buf ); // Compress
#endif
memcpy( S->buf, S->buf + BLAKE2S_BLOCKBYTES, BLAKE2S_BLOCKBYTES ); // Shift buffer left
S->buflen -= BLAKE2S_BLOCKBYTES;
in += fill;
inlen -= fill;
}
else // inlen <= fill
{
memcpy( S->buf + left, in, (size_t)inlen );
S->buflen += (size_t)inlen; // Be lazy, do not compress
in += inlen;
inlen = 0;
}
}
}
void blake2s_final( blake2s_state *S, byte *digest )
{
if( S->buflen > BLAKE2S_BLOCKBYTES )
{
blake2s_increment_counter( S, BLAKE2S_BLOCKBYTES );
blake2s_compress( S, S->buf );
S->buflen -= BLAKE2S_BLOCKBYTES;
memcpy( S->buf, S->buf + BLAKE2S_BLOCKBYTES, S->buflen );
}
blake2s_increment_counter( S, ( uint32 )S->buflen );
blake2s_set_lastblock( S );
memset( S->buf + S->buflen, 0, 2 * BLAKE2S_BLOCKBYTES - S->buflen ); /* Padding */
blake2s_compress( S, S->buf );
for( int i = 0; i < 8; ++i ) /* Output full hash */
RawPut4( S->h[i], digest + 4 * i );
}

101
reference/unrar/blake2s.hpp Normal file
View File

@@ -0,0 +1,101 @@
// Based on public domain code written in 2012 by Samuel Neves
#ifndef _RAR_BLAKE2_
#define _RAR_BLAKE2_
#define BLAKE2_DIGEST_SIZE 32
enum blake2s_constant
{
BLAKE2S_BLOCKBYTES = 64,
BLAKE2S_OUTBYTES = 32
};
// Alignment to 64 improves performance of both SSE and non-SSE versions.
// Alignment to n*16 is required for SSE version, so we selected 64.
// We use the custom alignment scheme instead of __declspec(align(x)),
// because it is less compiler dependent. Also the compiler directive
// does not help if structure is a member of class allocated through
// 'new' operator.
struct blake2s_state
{
enum { BLAKE_ALIGNMENT = 64 };
// buffer and uint32 h[8], t[2], f[2];
enum { BLAKE_DATA_SIZE = 48 + 2 * BLAKE2S_BLOCKBYTES };
byte ubuf[BLAKE_DATA_SIZE + BLAKE_ALIGNMENT];
byte *buf; // byte buf[2 * BLAKE2S_BLOCKBYTES].
uint32 *h, *t, *f; // uint32 h[8], t[2], f[2].
size_t buflen;
byte last_node;
blake2s_state()
{
set_pointers();
}
// Required when we declare and assign in the same command.
blake2s_state(blake2s_state &st)
{
set_pointers();
*this=st;
}
void set_pointers()
{
// Set aligned pointers. Must be done in constructor, not in Init(),
// so assignments like 'blake2sp_state res=blake2ctx' work correctly
// even if blake2sp_init is not called for 'res'.
buf = (byte *) ALIGN_VALUE(ubuf, BLAKE_ALIGNMENT);
h = (uint32 *) (buf + 2 * BLAKE2S_BLOCKBYTES);
t = h + 8;
f = t + 2;
}
void init()
{
memset( ubuf, 0, sizeof( ubuf ) );
buflen = 0;
last_node = 0;
}
// Since we use pointers, the default = would work incorrectly.
blake2s_state& operator = (blake2s_state &st)
{
if (this != &st)
{
memcpy(buf, st.buf, BLAKE_DATA_SIZE);
buflen = st.buflen;
last_node = st.last_node;
}
return *this;
}
};
#ifdef RAR_SMP
class ThreadPool;
#endif
struct blake2sp_state
{
blake2s_state S[8];
blake2s_state R;
byte buf[8 * BLAKE2S_BLOCKBYTES];
size_t buflen;
#ifdef RAR_SMP
ThreadPool *ThPool;
uint MaxThreads;
#endif
};
void blake2sp_init( blake2sp_state *S );
void blake2sp_update( blake2sp_state *S, const byte *in, size_t inlen );
void blake2sp_final( blake2sp_state *S, byte *digest );
#endif

View File

@@ -0,0 +1,129 @@
// Based on public domain code written in 2012 by Samuel Neves
extern const byte blake2s_sigma[10][16];
// Initialization vector.
static __m128i blake2s_IV_0_3, blake2s_IV_4_7;
#ifdef _WIN_64
// Constants for cyclic rotation. Used in 64-bit mode in mm_rotr_epi32 macro.
static __m128i crotr8, crotr16;
#endif
static void blake2s_init_sse()
{
// We cannot initialize these 128 bit variables in place when declaring
// them globally, because global scope initialization is performed before
// our SSE check and it would make code incompatible with older non-SSE2
// CPUs. Also we cannot initialize them as static inside of function
// using these variables, because SSE static initialization is not thread
// safe: first thread starts initialization and sets "init done" flag even
// if it is not done yet, second thread can attempt to access half-init
// SSE data. So we moved init code here.
blake2s_IV_0_3 = _mm_setr_epi32( 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A );
blake2s_IV_4_7 = _mm_setr_epi32( 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19 );
#ifdef _WIN_64
crotr8 = _mm_set_epi8( 12, 15, 14, 13, 8, 11, 10, 9, 4, 7, 6, 5, 0, 3, 2, 1 );
crotr16 = _mm_set_epi8( 13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2 );
#endif
}
#define LOAD(p) _mm_load_si128( (__m128i *)(p) )
#define STORE(p,r) _mm_store_si128((__m128i *)(p), r)
#ifdef _WIN_32
// 32-bit mode has less SSE2 registers and in MSVC2008 it is more efficient
// to not use _mm_shuffle_epi8 here.
#define mm_rotr_epi32(r, c) ( \
_mm_xor_si128(_mm_srli_epi32( (r), c ),_mm_slli_epi32( (r), 32-c )) )
#else
#define mm_rotr_epi32(r, c) ( \
c==8 ? _mm_shuffle_epi8(r,crotr8) \
: c==16 ? _mm_shuffle_epi8(r,crotr16) \
: _mm_xor_si128(_mm_srli_epi32( (r), c ),_mm_slli_epi32( (r), 32-c )) )
#endif
#define G1(row1,row2,row3,row4,buf) \
row1 = _mm_add_epi32( _mm_add_epi32( row1, buf), row2 ); \
row4 = _mm_xor_si128( row4, row1 ); \
row4 = mm_rotr_epi32(row4, 16); \
row3 = _mm_add_epi32( row3, row4 ); \
row2 = _mm_xor_si128( row2, row3 ); \
row2 = mm_rotr_epi32(row2, 12);
#define G2(row1,row2,row3,row4,buf) \
row1 = _mm_add_epi32( _mm_add_epi32( row1, buf), row2 ); \
row4 = _mm_xor_si128( row4, row1 ); \
row4 = mm_rotr_epi32(row4, 8); \
row3 = _mm_add_epi32( row3, row4 ); \
row2 = _mm_xor_si128( row2, row3 ); \
row2 = mm_rotr_epi32(row2, 7);
#define DIAGONALIZE(row1,row2,row3,row4) \
row4 = _mm_shuffle_epi32( row4, _MM_SHUFFLE(2,1,0,3) ); \
row3 = _mm_shuffle_epi32( row3, _MM_SHUFFLE(1,0,3,2) ); \
row2 = _mm_shuffle_epi32( row2, _MM_SHUFFLE(0,3,2,1) );
#define UNDIAGONALIZE(row1,row2,row3,row4) \
row4 = _mm_shuffle_epi32( row4, _MM_SHUFFLE(0,3,2,1) ); \
row3 = _mm_shuffle_epi32( row3, _MM_SHUFFLE(1,0,3,2) ); \
row2 = _mm_shuffle_epi32( row2, _MM_SHUFFLE(2,1,0,3) );
#ifdef _WIN_64
// MSVC 2008 in x64 mode expands _mm_set_epi32 to store to stack and load
// from stack operations, which are slower than this code.
#define _mm_set_epi32(i3,i2,i1,i0) \
_mm_unpacklo_epi32(_mm_unpacklo_epi32(_mm_cvtsi32_si128(i0),_mm_cvtsi32_si128(i2)), \
_mm_unpacklo_epi32(_mm_cvtsi32_si128(i1),_mm_cvtsi32_si128(i3)))
#endif
// Original BLAKE2 SSE4.1 message loading code was a little slower in x86 mode
// and about the same in x64 mode in our test. Perhaps depends on compiler.
// We also tried _mm_i32gather_epi32 and _mm256_i32gather_epi32 AVX2 gather
// instructions here, but they did not show any speed gain on i7-6700K.
#define SSE_ROUND(m,row,r) \
{ \
__m128i buf; \
buf=_mm_set_epi32(m[blake2s_sigma[r][6]],m[blake2s_sigma[r][4]],m[blake2s_sigma[r][2]],m[blake2s_sigma[r][0]]); \
G1(row[0],row[1],row[2],row[3],buf); \
buf=_mm_set_epi32(m[blake2s_sigma[r][7]],m[blake2s_sigma[r][5]],m[blake2s_sigma[r][3]],m[blake2s_sigma[r][1]]); \
G2(row[0],row[1],row[2],row[3],buf); \
DIAGONALIZE(row[0],row[1],row[2],row[3]); \
buf=_mm_set_epi32(m[blake2s_sigma[r][14]],m[blake2s_sigma[r][12]],m[blake2s_sigma[r][10]],m[blake2s_sigma[r][8]]); \
G1(row[0],row[1],row[2],row[3],buf); \
buf=_mm_set_epi32(m[blake2s_sigma[r][15]],m[blake2s_sigma[r][13]],m[blake2s_sigma[r][11]],m[blake2s_sigma[r][9]]); \
G2(row[0],row[1],row[2],row[3],buf); \
UNDIAGONALIZE(row[0],row[1],row[2],row[3]); \
}
static int blake2s_compress_sse( blake2s_state *S, const byte block[BLAKE2S_BLOCKBYTES] )
{
__m128i row[4];
__m128i ff0, ff1;
const uint32 *m = ( uint32 * )block;
row[0] = ff0 = LOAD( &S->h[0] );
row[1] = ff1 = LOAD( &S->h[4] );
row[2] = blake2s_IV_0_3;
row[3] = _mm_xor_si128( blake2s_IV_4_7, LOAD( &S->t[0] ) );
SSE_ROUND( m, row, 0 );
SSE_ROUND( m, row, 1 );
SSE_ROUND( m, row, 2 );
SSE_ROUND( m, row, 3 );
SSE_ROUND( m, row, 4 );
SSE_ROUND( m, row, 5 );
SSE_ROUND( m, row, 6 );
SSE_ROUND( m, row, 7 );
SSE_ROUND( m, row, 8 );
SSE_ROUND( m, row, 9 );
STORE( &S->h[0], _mm_xor_si128( ff0, _mm_xor_si128( row[0], row[2] ) ) );
STORE( &S->h[4], _mm_xor_si128( ff1, _mm_xor_si128( row[1], row[3] ) ) );
return 0;
}

View File

@@ -0,0 +1,153 @@
/*
BLAKE2 reference source code package - reference C implementations
Written in 2012 by Samuel Neves <sneves@dei.uc.pt>
To the extent possible under law, the author(s) have dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
You should have received a copy of the CC0 Public Domain Dedication along with
this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#define PARALLELISM_DEGREE 8
void blake2sp_init( blake2sp_state *S )
{
memset( S->buf, 0, sizeof( S->buf ) );
S->buflen = 0;
blake2s_init_param( &S->R, 0, 1 ); // Init root.
for( uint i = 0; i < PARALLELISM_DEGREE; ++i )
blake2s_init_param( &S->S[i], i, 0 ); // Init leaf.
S->R.last_node = 1;
S->S[PARALLELISM_DEGREE - 1].last_node = 1;
}
struct Blake2ThreadData
{
void Update();
blake2s_state *S;
const byte *in;
size_t inlen;
};
void Blake2ThreadData::Update()
{
size_t inlen__ = inlen;
const byte *in__ = ( const byte * )in;
while( inlen__ >= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES )
{
#ifdef USE_SSE
// We gain 5% in i7 SSE mode by prefetching next data block.
if (_SSE_Version>=SSE_SSE && inlen__ >= 2 * PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES)
_mm_prefetch((char*)(in__ + PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES), _MM_HINT_T0);
#endif
blake2s_update( S, in__, BLAKE2S_BLOCKBYTES );
in__ += PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;
inlen__ -= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;
}
}
#ifdef RAR_SMP
THREAD_PROC(Blake2Thread)
{
Blake2ThreadData *td=(Blake2ThreadData *)Data;
td->Update();
}
#endif
void blake2sp_update( blake2sp_state *S, const byte *in, size_t inlen )
{
size_t left = S->buflen;
size_t fill = sizeof( S->buf ) - left;
if( left && inlen >= fill )
{
memcpy( S->buf + left, in, fill );
for( size_t i = 0; i < PARALLELISM_DEGREE; ++i )
blake2s_update( &S->S[i], S->buf + i * BLAKE2S_BLOCKBYTES, BLAKE2S_BLOCKBYTES );
in += fill;
inlen -= fill;
left = 0;
}
Blake2ThreadData btd_array[PARALLELISM_DEGREE];
#ifdef RAR_SMP
uint ThreadNumber = inlen < 0x1000 ? 1 : S->MaxThreads;
if (ThreadNumber==6 || ThreadNumber==7) // 6 and 7 threads work slower than 4 here.
ThreadNumber=4;
#else
uint ThreadNumber=1;
#endif
for (size_t id__=0;id__<PARALLELISM_DEGREE;)
{
for (uint Thread=0;Thread<ThreadNumber && id__<PARALLELISM_DEGREE;Thread++)
{
Blake2ThreadData *btd=btd_array+Thread;
btd->inlen = inlen;
btd->in = in + id__ * BLAKE2S_BLOCKBYTES;
btd->S = &S->S[id__];
#ifdef RAR_SMP
if (ThreadNumber>1)
S->ThPool->AddTask(Blake2Thread,(void*)btd);
else
btd->Update();
#else
btd->Update();
#endif
id__++;
}
#ifdef RAR_SMP
if (S->ThPool!=NULL) // Can be NULL in -mt1 mode.
S->ThPool->WaitDone();
#endif // RAR_SMP
}
in += inlen - inlen % ( PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES );
inlen %= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;
if( inlen > 0 )
memcpy( S->buf + left, in, (size_t)inlen );
S->buflen = left + (size_t)inlen;
}
void blake2sp_final( blake2sp_state *S, byte *digest )
{
byte hash[PARALLELISM_DEGREE][BLAKE2S_OUTBYTES];
for( size_t i = 0; i < PARALLELISM_DEGREE; ++i )
{
if( S->buflen > i * BLAKE2S_BLOCKBYTES )
{
size_t left = S->buflen - i * BLAKE2S_BLOCKBYTES;
if( left > BLAKE2S_BLOCKBYTES ) left = BLAKE2S_BLOCKBYTES;
blake2s_update( &S->S[i], S->buf + i * BLAKE2S_BLOCKBYTES, left );
}
blake2s_final( &S->S[i], hash[i] );
}
for( size_t i = 0; i < PARALLELISM_DEGREE; ++i )
blake2s_update( &S->R, hash[i], BLAKE2S_OUTBYTES );
blake2s_final( &S->R, digest );
}

1400
reference/unrar/cmddata.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,64 @@
#ifndef _RAR_CMDDATA_
#define _RAR_CMDDATA_
#define DefaultStoreList L"7z;ace;arj;bz2;cab;gz;jpeg;jpg;lha;lz;lzh;mp3;rar;taz;tgz;xz;z;zip;zipx"
enum RAR_CMD_LIST_MODE {RCLM_AUTO,RCLM_REJECT_LISTS,RCLM_ACCEPT_LISTS};
class CommandData:public RAROptions
{
private:
void ProcessSwitchesString(const wchar *Str);
void ProcessSwitch(const wchar *Switch);
void BadSwitch(const wchar *Switch);
uint GetExclAttr(const wchar *Str);
bool FileLists;
bool NoMoreSwitches;
RAR_CMD_LIST_MODE ListMode;
bool BareOutput;
public:
CommandData();
void Init();
void ParseCommandLine(bool Preprocess,int argc, char *argv[]);
void ParseArg(wchar *ArgW);
void ParseDone();
void ParseEnvVar();
void ReadConfig();
void PreprocessArg(const wchar *Arg);
void OutTitle();
void OutHelp(RAR_EXIT ExitCode);
bool IsSwitch(int Ch);
bool ExclCheck(const wchar *CheckName,bool Dir,bool CheckFullPath,bool CheckInclList);
static bool CheckArgs(StringList *Args,bool Dir,const wchar *CheckName,bool CheckFullPath,int MatchMode);
bool ExclDirByAttr(uint FileAttr);
bool TimeCheck(RarTime &ft);
bool SizeCheck(int64 Size);
bool AnyFiltersActive();
int IsProcessFile(FileHeader &FileHead,bool *ExactMatch=NULL,int MatchType=MATCH_WILDSUBPATH,
wchar *MatchedArg=NULL,uint MatchedArgSize=0);
void ProcessCommand();
void AddArcName(const wchar *Name);
bool GetArcName(wchar *Name,int MaxSize);
bool CheckWinSize();
int GetRecoverySize(const wchar *Str,int DefSize);
#ifndef SFX_MODULE
void ReportWrongSwitches(RARFORMAT Format);
#endif
wchar Command[NM+16];
wchar ArcName[NM];
StringList FileArgs;
StringList ExclArgs;
StringList InclArgs;
StringList ArcNames;
StringList StoreArgs;
};
#endif

48
reference/unrar/coder.cpp Normal file
View File

@@ -0,0 +1,48 @@
inline unsigned int RangeCoder::GetChar()
{
return(UnpackRead->GetChar());
}
void RangeCoder::InitDecoder(Unpack *UnpackRead)
{
RangeCoder::UnpackRead=UnpackRead;
low=code=0;
range=uint(-1);
for (int i=0;i < 4;i++)
code=(code << 8) | GetChar();
}
// (int) cast before "low" added only to suppress compiler warnings.
#define ARI_DEC_NORMALIZE(code,low,range,read) \
{ \
while ((low^(low+range))<TOP || range<BOT && ((range=-(int)low&(BOT-1)),1)) \
{ \
code=(code << 8) | read->GetChar(); \
range <<= 8; \
low <<= 8; \
} \
}
inline int RangeCoder::GetCurrentCount()
{
return (code-low)/(range /= SubRange.scale);
}
inline uint RangeCoder::GetCurrentShiftCount(uint SHIFT)
{
return (code-low)/(range >>= SHIFT);
}
inline void RangeCoder::Decode()
{
low += range*SubRange.LowCount;
range *= SubRange.HighCount-SubRange.LowCount;
}

23
reference/unrar/coder.hpp Normal file
View File

@@ -0,0 +1,23 @@
/****************************************************************************
* Contents: 'Carryless rangecoder' by Dmitry Subbotin *
****************************************************************************/
class RangeCoder
{
public:
void InitDecoder(Unpack *UnpackRead);
inline int GetCurrentCount();
inline uint GetCurrentShiftCount(uint SHIFT);
inline void Decode();
inline void PutChar(unsigned int c);
inline unsigned int GetChar();
uint low, code, range;
struct SUBRANGE
{
uint LowCount, HighCount, scale;
} SubRange;
Unpack *UnpackRead;
};

View File

@@ -0,0 +1,50 @@
#ifndef _RAR_COMPRESS_
#define _RAR_COMPRESS_
// Combine pack and unpack constants to class to avoid polluting global
// namespace with numerous short names.
class PackDef
{
public:
static const uint MAX_LZ_MATCH = 0x1001;
static const uint MAX3_LZ_MATCH = 0x101; // Maximum match length for RAR v3.
static const uint LOW_DIST_REP_COUNT = 16;
static const uint NC = 306; /* alphabet = {0, 1, 2, ..., NC - 1} */
static const uint DC = 64;
static const uint LDC = 16;
static const uint RC = 44;
static const uint HUFF_TABLE_SIZE = NC + DC + RC + LDC;
static const uint BC = 20;
static const uint NC30 = 299; /* alphabet = {0, 1, 2, ..., NC - 1} */
static const uint DC30 = 60;
static const uint LDC30 = 17;
static const uint RC30 = 28;
static const uint BC30 = 20;
static const uint HUFF_TABLE_SIZE30 = NC30 + DC30 + RC30 + LDC30;
static const uint NC20 = 298; /* alphabet = {0, 1, 2, ..., NC - 1} */
static const uint DC20 = 48;
static const uint RC20 = 28;
static const uint BC20 = 19;
static const uint MC20 = 257;
// Largest alphabet size among all values listed above.
static const uint LARGEST_TABLE_SIZE = 306;
enum {
CODE_HUFFMAN, CODE_LZ, CODE_REPEATLZ, CODE_CACHELZ, CODE_STARTFILE,
CODE_ENDFILE, CODE_FILTER, CODE_FILTERDATA
};
};
enum FilterType {
// These values must not be changed, because we use them directly
// in RAR5 compression and decompression code.
FILTER_DELTA=0, FILTER_E8, FILTER_E8E9, FILTER_ARM,
FILTER_AUDIO, FILTER_RGB, FILTER_ITANIUM, FILTER_PPM, FILTER_NONE
};
#endif

352
reference/unrar/consio.cpp Normal file
View File

@@ -0,0 +1,352 @@
#include "rar.hpp"
#include "log.cpp"
static MESSAGE_TYPE MsgStream=MSG_STDOUT;
static RAR_CHARSET RedirectCharset=RCH_DEFAULT;
const int MaxMsgSize=2*NM+2048;
static bool StdoutRedirected=false,StderrRedirected=false,StdinRedirected=false;
#ifdef _WIN_ALL
static bool IsRedirected(DWORD nStdHandle)
{
HANDLE hStd=GetStdHandle(nStdHandle);
DWORD Mode;
return GetFileType(hStd)!=FILE_TYPE_CHAR || GetConsoleMode(hStd,&Mode)==0;
}
#endif
void InitConsole()
{
#ifdef _WIN_ALL
// We want messages like file names or progress percent to be printed
// immediately. Use only in Windows, in Unix they can cause wprintf %ls
// to fail with non-English strings.
setbuf(stdout,NULL);
setbuf(stderr,NULL);
// Detect if output is redirected and set output mode properly.
// We do not want to send Unicode output to files and especially to pipes
// like '|more', which cannot handle them correctly in Windows.
// In Unix console output is UTF-8 and it is handled correctly
// when redirecting, so no need to perform any adjustments.
StdoutRedirected=IsRedirected(STD_OUTPUT_HANDLE);
StderrRedirected=IsRedirected(STD_ERROR_HANDLE);
StdinRedirected=IsRedirected(STD_INPUT_HANDLE);
#ifdef _MSC_VER
if (!StdoutRedirected)
_setmode(_fileno(stdout), _O_U16TEXT);
if (!StderrRedirected)
_setmode(_fileno(stderr), _O_U16TEXT);
#endif
#elif defined(_UNIX)
StdoutRedirected=!isatty(fileno(stdout));
StderrRedirected=!isatty(fileno(stderr));
StdinRedirected=!isatty(fileno(stdin));
#endif
}
void InitConsoleOptions(MESSAGE_TYPE MsgStream,RAR_CHARSET RedirectCharset)
{
::MsgStream=MsgStream;
::RedirectCharset=RedirectCharset;
}
#ifndef SILENT
static void cvt_wprintf(FILE *dest,const wchar *fmt,va_list arglist)
{
// This buffer is for format string only, not for entire output,
// so it can be short enough.
wchar fmtw[1024];
PrintfPrepareFmt(fmt,fmtw,ASIZE(fmtw));
#ifdef _WIN_ALL
safebuf wchar Msg[MaxMsgSize];
if (dest==stdout && StdoutRedirected || dest==stderr && StderrRedirected)
{
HANDLE hOut=GetStdHandle(dest==stdout ? STD_OUTPUT_HANDLE:STD_ERROR_HANDLE);
vswprintf(Msg,ASIZE(Msg),fmtw,arglist);
DWORD Written;
if (RedirectCharset==RCH_UNICODE)
WriteFile(hOut,Msg,(DWORD)wcslen(Msg)*sizeof(*Msg),&Written,NULL);
else
{
// Avoid Unicode for redirect in Windows, it does not work with pipes.
safebuf char MsgA[MaxMsgSize];
if (RedirectCharset==RCH_UTF8)
WideToUtf(Msg,MsgA,ASIZE(MsgA));
else
WideToChar(Msg,MsgA,ASIZE(MsgA));
if (RedirectCharset==RCH_DEFAULT || RedirectCharset==RCH_OEM)
CharToOemA(MsgA,MsgA); // Console tools like 'more' expect OEM encoding.
// We already converted \n to \r\n above, so we use WriteFile instead
// of C library to avoid unnecessary additional conversion.
WriteFile(hOut,MsgA,(DWORD)strlen(MsgA),&Written,NULL);
}
return;
}
// MSVC2008 vfwprintf writes every character to console separately
// and it is too slow. We use direct WriteConsole call instead.
vswprintf(Msg,ASIZE(Msg),fmtw,arglist);
HANDLE hOut=GetStdHandle(dest==stderr ? STD_ERROR_HANDLE:STD_OUTPUT_HANDLE);
DWORD Written;
WriteConsole(hOut,Msg,(DWORD)wcslen(Msg),&Written,NULL);
#else
vfwprintf(dest,fmtw,arglist);
// We do not use setbuf(NULL) in Unix (see comments in InitConsole).
fflush(dest);
#endif
}
void mprintf(const wchar *fmt,...)
{
if (MsgStream==MSG_NULL || MsgStream==MSG_ERRONLY)
return;
fflush(stderr); // Ensure proper message order.
va_list arglist;
va_start(arglist,fmt);
FILE *dest=MsgStream==MSG_STDERR ? stderr:stdout;
cvt_wprintf(dest,fmt,arglist);
va_end(arglist);
}
#endif
#ifndef SILENT
void eprintf(const wchar *fmt,...)
{
if (MsgStream==MSG_NULL)
return;
fflush(stdout); // Ensure proper message order.
va_list arglist;
va_start(arglist,fmt);
cvt_wprintf(stderr,fmt,arglist);
va_end(arglist);
}
#endif
#ifndef SILENT
static void GetPasswordText(wchar *Str,uint MaxLength)
{
if (MaxLength==0)
return;
if (StdinRedirected)
getwstr(Str,MaxLength); // Read from pipe or redirected file.
else
{
#ifdef _WIN_ALL
HANDLE hConIn=GetStdHandle(STD_INPUT_HANDLE);
HANDLE hConOut=GetStdHandle(STD_OUTPUT_HANDLE);
DWORD ConInMode,ConOutMode;
DWORD Read=0;
GetConsoleMode(hConIn,&ConInMode);
GetConsoleMode(hConOut,&ConOutMode);
SetConsoleMode(hConIn,ENABLE_LINE_INPUT);
SetConsoleMode(hConOut,ENABLE_PROCESSED_OUTPUT|ENABLE_WRAP_AT_EOL_OUTPUT);
ReadConsole(hConIn,Str,MaxLength-1,&Read,NULL);
Str[Read]=0;
SetConsoleMode(hConIn,ConInMode);
SetConsoleMode(hConOut,ConOutMode);
#else
char StrA[MAXPASSWORD];
#if defined(_EMX) || defined (__VMS)
fgets(StrA,ASIZE(StrA)-1,stdin);
#elif defined(__sun)
strncpyz(StrA,getpassphrase(""),ASIZE(StrA));
#else
strncpyz(StrA,getpass(""),ASIZE(StrA));
#endif
CharToWide(StrA,Str,MaxLength);
cleandata(StrA,sizeof(StrA));
#endif
}
Str[MaxLength-1]=0;
RemoveLF(Str);
}
#endif
#ifndef SILENT
bool GetConsolePassword(UIPASSWORD_TYPE Type,const wchar *FileName,SecPassword *Password)
{
if (!StdinRedirected)
uiAlarm(UIALARM_QUESTION);
while (true)
{
if (!StdinRedirected)
if (Type==UIPASSWORD_GLOBAL)
eprintf(L"\n%s: ",St(MAskPsw));
else
eprintf(St(MAskPswFor),FileName);
wchar PlainPsw[MAXPASSWORD];
GetPasswordText(PlainPsw,ASIZE(PlainPsw));
if (*PlainPsw==0 && Type==UIPASSWORD_GLOBAL)
return false;
if (!StdinRedirected && Type==UIPASSWORD_GLOBAL)
{
eprintf(St(MReAskPsw));
wchar CmpStr[MAXPASSWORD];
GetPasswordText(CmpStr,ASIZE(CmpStr));
if (*CmpStr==0 || wcscmp(PlainPsw,CmpStr)!=0)
{
eprintf(St(MNotMatchPsw));
cleandata(PlainPsw,sizeof(PlainPsw));
cleandata(CmpStr,sizeof(CmpStr));
continue;
}
cleandata(CmpStr,sizeof(CmpStr));
}
Password->Set(PlainPsw);
cleandata(PlainPsw,sizeof(PlainPsw));
break;
}
return true;
}
#endif
#ifndef SILENT
bool getwstr(wchar *str,size_t n)
{
// Print buffered prompt title function before waiting for input.
fflush(stderr);
*str=0;
#if defined(_WIN_ALL)
// fgetws does not work well with non-English text in Windows,
// so we do not use it.
if (StdinRedirected) // ReadConsole does not work if redirected.
{
// fgets does not work well with pipes in Windows in our test.
// Let's use files.
Array<char> StrA(n*4); // Up to 4 UTF-8 characters per wchar_t.
File SrcFile;
SrcFile.SetHandleType(FILE_HANDLESTD);
int ReadSize=SrcFile.Read(&StrA[0],StrA.Size()-1);
if (ReadSize<=0)
{
// Looks like stdin is a null device. We can enter to infinite loop
// calling Ask(), so let's better exit.
ErrHandler.Exit(RARX_USERBREAK);
}
StrA[ReadSize]=0;
CharToWide(&StrA[0],str,n);
cleandata(&StrA[0],StrA.Size()); // We can use this function to enter passwords.
}
else
{
DWORD ReadSize=0;
if (ReadConsole(GetStdHandle(STD_INPUT_HANDLE),str,DWORD(n-1),&ReadSize,NULL)==0)
return false;
str[ReadSize]=0;
}
#else
if (fgetws(str,n,stdin)==NULL)
ErrHandler.Exit(RARX_USERBREAK); // Avoid infinite Ask() loop.
#endif
RemoveLF(str);
return true;
}
#endif
#ifndef SILENT
// We allow this function to return 0 in case of invalid input,
// because it might be convenient to press Enter to some not dangerous
// prompts like "insert disk with next volume". We should call this function
// again in case of 0 in dangerous prompt such as overwriting file.
int Ask(const wchar *AskStr)
{
uiAlarm(UIALARM_QUESTION);
const int MaxItems=10;
wchar Item[MaxItems][40];
int ItemKeyPos[MaxItems],NumItems=0;
for (const wchar *NextItem=AskStr;NextItem!=NULL;NextItem=wcschr(NextItem+1,'_'))
{
wchar *CurItem=Item[NumItems];
wcsncpyz(CurItem,NextItem+1,ASIZE(Item[0]));
wchar *EndItem=wcschr(CurItem,'_');
if (EndItem!=NULL)
*EndItem=0;
int KeyPos=0,CurKey;
while ((CurKey=CurItem[KeyPos])!=0)
{
bool Found=false;
for (int I=0;I<NumItems && !Found;I++)
if (toupperw(Item[I][ItemKeyPos[I]])==toupperw(CurKey))
Found=true;
if (!Found && CurKey!=' ')
break;
KeyPos++;
}
ItemKeyPos[NumItems]=KeyPos;
NumItems++;
}
for (int I=0;I<NumItems;I++)
{
eprintf(I==0 ? (NumItems>4 ? L"\n":L" "):L", ");
int KeyPos=ItemKeyPos[I];
for (int J=0;J<KeyPos;J++)
eprintf(L"%c",Item[I][J]);
eprintf(L"[%c]%ls",Item[I][KeyPos],&Item[I][KeyPos+1]);
}
eprintf(L" ");
wchar Str[50];
getwstr(Str,ASIZE(Str));
wchar Ch=toupperw(Str[0]);
for (int I=0;I<NumItems;I++)
if (Ch==Item[I][ItemKeyPos[I]])
return I+1;
return 0;
}
#endif
static bool IsCommentUnsafe(const wchar *Data,size_t Size)
{
for (size_t I=0;I<Size;I++)
if (Data[I]==27 && Data[I+1]=='[')
for (size_t J=I+2;J<Size;J++)
{
// Return true for <ESC>[{key};"{string}"p used to redefine
// a keyboard key on some terminals.
if (Data[J]=='\"')
return true;
if (!IsDigit(Data[J]) && Data[J]!=';')
break;
}
return false;
}
void OutComment(const wchar *Comment,size_t Size)
{
if (IsCommentUnsafe(Comment,Size))
return;
const size_t MaxOutSize=0x400;
for (size_t I=0;I<Size;I+=MaxOutSize)
{
wchar Msg[MaxOutSize+1];
size_t CopySize=Min(MaxOutSize,Size-I);
wcsncpy(Msg,Comment+I,CopySize);
Msg[CopySize]=0;
mprintf(L"%s",Msg);
}
mprintf(L"\n");
}

View File

@@ -0,0 +1,26 @@
#ifndef _RAR_CONSIO_
#define _RAR_CONSIO_
void InitConsole();
void InitConsoleOptions(MESSAGE_TYPE MsgStream,RAR_CHARSET RedirectCharset);
void OutComment(const wchar *Comment,size_t Size);
#ifndef SILENT
bool GetConsolePassword(UIPASSWORD_TYPE Type,const wchar *FileName,SecPassword *Password);
#endif
#ifdef SILENT
inline void mprintf(const wchar *fmt,...) {}
inline void eprintf(const wchar *fmt,...) {}
inline void Alarm() {}
inline int Ask(const wchar *AskStr) {return 0;}
inline bool getwstr(wchar *str,size_t n) {return false;}
#else
void mprintf(const wchar *fmt,...);
void eprintf(const wchar *fmt,...);
void Alarm();
int Ask(const wchar *AskStr);
bool getwstr(wchar *str,size_t n);
#endif
#endif

102
reference/unrar/crc.cpp Normal file
View File

@@ -0,0 +1,102 @@
// This CRC function is based on Intel Slicing-by-8 algorithm.
//
// Original Intel Slicing-by-8 code is available here:
//
// http://sourceforge.net/projects/slicing-by-8/
//
// Original Intel Slicing-by-8 code is licensed as:
//
// Copyright (c) 2004-2006 Intel Corporation - All Rights Reserved
//
// This software program is licensed subject to the BSD License,
// available at http://www.opensource.org/licenses/bsd-license.html
#include "rar.hpp"
static uint crc_tables[8][256]; // Tables for Slicing-by-8.
// Build the classic CRC32 lookup table.
// We also provide this function to legacy RAR and ZIP decryption code.
void InitCRC32(uint *CRCTab)
{
if (CRCTab[1]!=0)
return;
for (uint I=0;I<256;I++)
{
uint C=I;
for (uint J=0;J<8;J++)
C=(C & 1) ? (C>>1)^0xEDB88320 : (C>>1);
CRCTab[I]=C;
}
}
static void InitTables()
{
InitCRC32(crc_tables[0]);
for (uint I=0;I<256;I++) // Build additional lookup tables.
{
uint C=crc_tables[0][I];
for (uint J=1;J<8;J++)
{
C=crc_tables[0][(byte)C]^(C>>8);
crc_tables[J][I]=C;
}
}
}
struct CallInitCRC {CallInitCRC() {InitTables();}} static CallInit32;
uint CRC32(uint StartCRC,const void *Addr,size_t Size)
{
byte *Data=(byte *)Addr;
// Align Data to 8 for better performance.
for (;Size>0 && ((size_t)Data & 7);Size--,Data++)
StartCRC=crc_tables[0][(byte)(StartCRC^Data[0])]^(StartCRC>>8);
for (;Size>=8;Size-=8,Data+=8)
{
#ifdef BIG_ENDIAN
StartCRC ^= Data[0]|(Data[1] << 8)|(Data[2] << 16)|(Data[3] << 24);
uint NextData = Data[4]|(Data[5] << 8)|(Data[6] << 16)|(Data[7] << 24);
#else
StartCRC ^= *(uint32 *) Data;
uint NextData = *(uint32 *) (Data +4);
#endif
StartCRC = crc_tables[7][(byte) StartCRC ] ^
crc_tables[6][(byte)(StartCRC >> 8) ] ^
crc_tables[5][(byte)(StartCRC >> 16)] ^
crc_tables[4][(byte)(StartCRC >> 24)] ^
crc_tables[3][(byte) NextData ] ^
crc_tables[2][(byte)(NextData >>8 ) ] ^
crc_tables[1][(byte)(NextData >> 16)] ^
crc_tables[0][(byte)(NextData >> 24)];
}
for (;Size>0;Size--,Data++) // Process left data.
StartCRC=crc_tables[0][(byte)(StartCRC^Data[0])]^(StartCRC>>8);
return StartCRC;
}
#ifndef SFX_MODULE
// For RAR 1.4 archives in case somebody still has them.
ushort Checksum14(ushort StartCRC,const void *Addr,size_t Size)
{
byte *Data=(byte *)Addr;
for (size_t I=0;I<Size;I++)
{
StartCRC=(StartCRC+Data[I])&0xffff;
StartCRC=((StartCRC<<1)|(StartCRC>>15))&0xffff;
}
return StartCRC;
}
#endif

15
reference/unrar/crc.hpp Normal file
View File

@@ -0,0 +1,15 @@
#ifndef _RAR_CRC_
#define _RAR_CRC_
// This function is only to intialize external CRC tables. We do not need to
// call it before calculating CRC32.
void InitCRC32(uint *CRCTab);
uint CRC32(uint StartCRC,const void *Addr,size_t Size);
#ifndef SFX_MODULE
ushort Checksum14(ushort StartCRC,const void *Addr,size_t Size);
#endif
#endif

134
reference/unrar/crypt.cpp Normal file
View File

@@ -0,0 +1,134 @@
#include "rar.hpp"
#ifndef SFX_MODULE
#include "crypt1.cpp"
#include "crypt2.cpp"
#endif
#include "crypt3.cpp"
#include "crypt5.cpp"
CryptData::CryptData()
{
Method=CRYPT_NONE;
memset(KDF3Cache,0,sizeof(KDF3Cache));
memset(KDF5Cache,0,sizeof(KDF5Cache));
KDF3CachePos=0;
KDF5CachePos=0;
memset(CRCTab,0,sizeof(CRCTab));
}
CryptData::~CryptData()
{
cleandata(KDF3Cache,sizeof(KDF3Cache));
cleandata(KDF5Cache,sizeof(KDF5Cache));
}
void CryptData::DecryptBlock(byte *Buf,size_t Size)
{
switch(Method)
{
#ifndef SFX_MODULE
case CRYPT_RAR13:
Decrypt13(Buf,Size);
break;
case CRYPT_RAR15:
Crypt15(Buf,Size);
break;
case CRYPT_RAR20:
for (size_t I=0;I<Size;I+=CRYPT_BLOCK_SIZE)
DecryptBlock20(Buf+I);
break;
#endif
case CRYPT_RAR30:
case CRYPT_RAR50:
rin.blockDecrypt(Buf,Size,Buf);
break;
}
}
bool CryptData::SetCryptKeys(bool Encrypt,CRYPT_METHOD Method,
SecPassword *Password,const byte *Salt,
const byte *InitV,uint Lg2Cnt,byte *HashKey,byte *PswCheck)
{
if (!Password->IsSet() || Method==CRYPT_NONE)
return false;
CryptData::Method=Method;
wchar PwdW[MAXPASSWORD];
Password->Get(PwdW,ASIZE(PwdW));
char PwdA[MAXPASSWORD];
WideToChar(PwdW,PwdA,ASIZE(PwdA));
switch(Method)
{
#ifndef SFX_MODULE
case CRYPT_RAR13:
SetKey13(PwdA);
break;
case CRYPT_RAR15:
SetKey15(PwdA);
break;
case CRYPT_RAR20:
SetKey20(PwdA);
break;
#endif
case CRYPT_RAR30:
SetKey30(Encrypt,Password,PwdW,Salt);
break;
case CRYPT_RAR50:
SetKey50(Encrypt,Password,PwdW,Salt,InitV,Lg2Cnt,HashKey,PswCheck);
break;
}
cleandata(PwdA,sizeof(PwdA));
cleandata(PwdW,sizeof(PwdW));
return true;
}
// Use the current system time to additionally randomize data.
static void TimeRandomize(byte *RndBuf,size_t BufSize)
{
static uint Count=0;
RarTime CurTime;
CurTime.SetCurrentTime();
uint64 Random=CurTime.GetWin()+clock();
for (size_t I=0;I<BufSize;I++)
{
byte RndByte = byte (Random >> ( (I & 7) * 8 ));
RndBuf[I]=byte( (RndByte ^ I) + Count++);
}
}
// Fill buffer with random data.
void GetRnd(byte *RndBuf,size_t BufSize)
{
bool Success=false;
#if defined(_WIN_ALL)
HCRYPTPROV hProvider = 0;
if (CryptAcquireContext(&hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
{
Success=CryptGenRandom(hProvider, (DWORD)BufSize, RndBuf) == TRUE;
CryptReleaseContext(hProvider, 0);
}
#elif defined(_UNIX)
FILE *rndf = fopen("/dev/urandom", "r");
if (rndf!=NULL)
{
Success=fread(RndBuf, BufSize, 1, rndf) == BufSize;
fclose(rndf);
}
#endif
// We use this code only as the last resort if code above failed.
if (!Success)
TimeRandomize(RndBuf,BufSize);
}

101
reference/unrar/crypt.hpp Normal file
View File

@@ -0,0 +1,101 @@
#ifndef _RAR_CRYPT_
#define _RAR_CRYPT_
enum CRYPT_METHOD {
CRYPT_NONE,CRYPT_RAR13,CRYPT_RAR15,CRYPT_RAR20,CRYPT_RAR30,CRYPT_RAR50
};
#define SIZE_SALT50 16
#define SIZE_SALT30 8
#define SIZE_INITV 16
#define SIZE_PSWCHECK 8
#define SIZE_PSWCHECK_CSUM 4
#define CRYPT_BLOCK_SIZE 16
#define CRYPT_BLOCK_MASK (CRYPT_BLOCK_SIZE-1) // 0xf
#define CRYPT5_KDF_LG2_COUNT 15 // LOG2 of PDKDF2 iteration count.
#define CRYPT5_KDF_LG2_COUNT_MAX 24 // LOG2 of maximum accepted iteration count.
#define CRYPT_VERSION 0 // Supported encryption version.
class CryptData
{
struct KDF5CacheItem
{
SecPassword Pwd;
byte Salt[SIZE_SALT50];
byte Key[32];
uint Lg2Count; // Log2 of PBKDF2 repetition count.
byte PswCheckValue[SHA256_DIGEST_SIZE];
byte HashKeyValue[SHA256_DIGEST_SIZE];
};
struct KDF3CacheItem
{
SecPassword Pwd;
byte Salt[SIZE_SALT30];
byte Key[16];
byte Init[16];
bool SaltPresent;
};
private:
void SetKey13(const char *Password);
void Decrypt13(byte *Data,size_t Count);
void SetKey15(const char *Password);
void Crypt15(byte *Data,size_t Count);
void SetKey20(const char *Password);
void Swap20(byte *Ch1,byte *Ch2);
void UpdKeys20(byte *Buf);
void EncryptBlock20(byte *Buf);
void DecryptBlock20(byte *Buf);
void SetKey30(bool Encrypt,SecPassword *Password,const wchar *PwdW,const byte *Salt);
void SetKey50(bool Encrypt,SecPassword *Password,const wchar *PwdW,const byte *Salt,const byte *InitV,uint Lg2Cnt,byte *HashKey,byte *PswCheck);
KDF3CacheItem KDF3Cache[4];
uint KDF3CachePos;
KDF5CacheItem KDF5Cache[4];
uint KDF5CachePos;
CRYPT_METHOD Method;
Rijndael rin;
uint CRCTab[256]; // For RAR 1.5 and RAR 2.0 encryption.
byte SubstTable20[256];
uint Key20[4];
byte Key13[3];
ushort Key15[4];
public:
CryptData();
~CryptData();
bool SetCryptKeys(bool Encrypt,CRYPT_METHOD Method,SecPassword *Password,
const byte *Salt,const byte *InitV,uint Lg2Cnt,
byte *HashKey,byte *PswCheck);
void SetAV15Encryption();
void SetCmt13Encryption();
void EncryptBlock(byte *Buf,size_t Size);
void DecryptBlock(byte *Buf,size_t Size);
static void SetSalt(byte *Salt,size_t SaltSize);
};
void GetRnd(byte *RndBuf,size_t BufSize);
void hmac_sha256(const byte *Key,size_t KeyLength,const byte *Data,
size_t DataLength,byte *ResDigest);
void pbkdf2(const byte *pass, size_t pass_len, const byte *salt,
size_t salt_len,byte *key, byte *Value1, byte *Value2,
uint rounds);
void ConvertHashToMAC(HashValue *Value,byte *Key);
#endif

View File

@@ -0,0 +1,79 @@
extern uint CRCTab[256];
void CryptData::SetKey13(const char *Password)
{
Key13[0]=Key13[1]=Key13[2]=0;
for (size_t I=0;Password[I]!=0;I++)
{
byte P=Password[I];
Key13[0]+=P;
Key13[1]^=P;
Key13[2]+=P;
Key13[2]=(byte)rotls(Key13[2],1,8);
}
}
void CryptData::SetKey15(const char *Password)
{
InitCRC32(CRCTab);
uint PswCRC=CRC32(0xffffffff,Password,strlen(Password));
Key15[0]=PswCRC&0xffff;
Key15[1]=(PswCRC>>16)&0xffff;
Key15[2]=Key15[3]=0;
for (size_t I=0;Password[I]!=0;I++)
{
byte P=Password[I];
Key15[2]^=P^CRCTab[P];
Key15[3]+=P+(CRCTab[P]>>16);
}
}
void CryptData::SetAV15Encryption()
{
InitCRC32(CRCTab);
Method=CRYPT_RAR15;
Key15[0]=0x4765;
Key15[1]=0x9021;
Key15[2]=0x7382;
Key15[3]=0x5215;
}
void CryptData::SetCmt13Encryption()
{
Method=CRYPT_RAR13;
Key13[0]=0;
Key13[1]=7;
Key13[2]=77;
}
void CryptData::Decrypt13(byte *Data,size_t Count)
{
while (Count--)
{
Key13[1]+=Key13[2];
Key13[0]+=Key13[1];
*Data-=Key13[0];
Data++;
}
}
void CryptData::Crypt15(byte *Data,size_t Count)
{
while (Count--)
{
Key15[0]+=0x1234;
Key15[1]^=CRCTab[(Key15[0] & 0x1fe)>>1];
Key15[2]-=CRCTab[(Key15[0] & 0x1fe)>>1]>>16;
Key15[0]^=Key15[2];
Key15[3]=rotrs(Key15[3]&0xffff,1,16)^Key15[1];
Key15[3]=rotrs(Key15[3]&0xffff,1,16);
Key15[0]^=Key15[3];
*Data^=(byte)(Key15[0]>>8);
Data++;
}
}

133
reference/unrar/crypt2.cpp Normal file
View File

@@ -0,0 +1,133 @@
#define NROUNDS 32
#define substLong(t) ( (uint)SubstTable20[(uint)t&255] | \
((uint)SubstTable20[(int)(t>> 8)&255]<< 8) | \
((uint)SubstTable20[(int)(t>>16)&255]<<16) | \
((uint)SubstTable20[(int)(t>>24)&255]<<24) )
static byte InitSubstTable20[256]={
215, 19,149, 35, 73,197,192,205,249, 28, 16,119, 48,221, 2, 42,
232, 1,177,233, 14, 88,219, 25,223,195,244, 90, 87,239,153,137,
255,199,147, 70, 92, 66,246, 13,216, 40, 62, 29,217,230, 86, 6,
71, 24,171,196,101,113,218,123, 93, 91,163,178,202, 67, 44,235,
107,250, 75,234, 49,167,125,211, 83,114,157,144, 32,193,143, 36,
158,124,247,187, 89,214,141, 47,121,228, 61,130,213,194,174,251,
97,110, 54,229,115, 57,152, 94,105,243,212, 55,209,245, 63, 11,
164,200, 31,156, 81,176,227, 21, 76, 99,139,188,127, 17,248, 51,
207,120,189,210, 8,226, 41, 72,183,203,135,165,166, 60, 98, 7,
122, 38,155,170, 69,172,252,238, 39,134, 59,128,236, 27,240, 80,
131, 3, 85,206,145, 79,154,142,159,220,201,133, 74, 64, 20,129,
224,185,138,103,173,182, 43, 34,254, 82,198,151,231,180, 58, 10,
118, 26,102, 12, 50,132, 22,191,136,111,162,179, 45, 4,148,108,
161, 56, 78,126,242,222, 15,175,146, 23, 33,241,181,190, 77,225,
0, 46,169,186, 68, 95,237, 65, 53,208,253,168, 9, 18,100, 52,
116,184,160, 96,109, 37, 30,106,140,104,150, 5,204,117,112, 84
};
void CryptData::SetKey20(const char *Password)
{
InitCRC32(CRCTab);
char Psw[MAXPASSWORD];
strncpyz(Psw,Password,ASIZE(Psw)); // We'll need to modify it below.
size_t PswLength=strlen(Psw);
Key20[0]=0xD3A3B879L;
Key20[1]=0x3F6D12F7L;
Key20[2]=0x7515A235L;
Key20[3]=0xA4E7F123L;
memcpy(SubstTable20,InitSubstTable20,sizeof(SubstTable20));
for (uint J=0;J<256;J++)
for (size_t I=0;I<PswLength;I+=2)
{
uint N1=(byte)CRCTab [ (byte(Password[I]) - J) &0xff];
uint N2=(byte)CRCTab [ (byte(Password[I+1]) + J) &0xff];
for (int K=1;N1!=N2;N1=(N1+1)&0xff,K++)
Swap20(&SubstTable20[N1],&SubstTable20[(N1+I+K)&0xff]);
}
// Incomplete last block of password must be zero padded.
if ((PswLength & CRYPT_BLOCK_MASK)!=0)
for (size_t I=PswLength;I<=(PswLength|CRYPT_BLOCK_MASK);I++)
Psw[I]=0;
for (size_t I=0;I<PswLength;I+=CRYPT_BLOCK_SIZE)
EncryptBlock20((byte *)Psw+I);
}
void CryptData::EncryptBlock20(byte *Buf)
{
uint A,B,C,D,T,TA,TB;
A=RawGet4(Buf+0)^Key20[0];
B=RawGet4(Buf+4)^Key20[1];
C=RawGet4(Buf+8)^Key20[2];
D=RawGet4(Buf+12)^Key20[3];
for(int I=0;I<NROUNDS;I++)
{
T=((C+rotls(D,11,32))^Key20[I&3]);
TA=A^substLong(T);
T=((D^rotls(C,17,32))+Key20[I&3]);
TB=B^substLong(T);
A=C;
B=D;
C=TA;
D=TB;
}
RawPut4(C^Key20[0],Buf+0);
RawPut4(D^Key20[1],Buf+4);
RawPut4(A^Key20[2],Buf+8);
RawPut4(B^Key20[3],Buf+12);
UpdKeys20(Buf);
}
void CryptData::DecryptBlock20(byte *Buf)
{
byte InBuf[16];
uint A,B,C,D,T,TA,TB;
A=RawGet4(Buf+0)^Key20[0];
B=RawGet4(Buf+4)^Key20[1];
C=RawGet4(Buf+8)^Key20[2];
D=RawGet4(Buf+12)^Key20[3];
memcpy(InBuf,Buf,sizeof(InBuf));
for(int I=NROUNDS-1;I>=0;I--)
{
T=((C+rotls(D,11,32))^Key20[I&3]);
TA=A^substLong(T);
T=((D^rotls(C,17,32))+Key20[I&3]);
TB=B^substLong(T);
A=C;
B=D;
C=TA;
D=TB;
}
RawPut4(C^Key20[0],Buf+0);
RawPut4(D^Key20[1],Buf+4);
RawPut4(A^Key20[2],Buf+8);
RawPut4(B^Key20[3],Buf+12);
UpdKeys20(InBuf);
}
void CryptData::UpdKeys20(byte *Buf)
{
for (int I=0;I<16;I+=4)
{
Key20[0]^=CRCTab[Buf[I]];
Key20[1]^=CRCTab[Buf[I+1]];
Key20[2]^=CRCTab[Buf[I+2]];
Key20[3]^=CRCTab[Buf[I+3]];
}
}
void CryptData::Swap20(byte *Ch1,byte *Ch2)
{
byte Ch=*Ch1;
*Ch1=*Ch2;
*Ch2=Ch;
}

View File

@@ -0,0 +1,68 @@
void CryptData::SetKey30(bool Encrypt,SecPassword *Password,const wchar *PwdW,const byte *Salt)
{
byte AESKey[16],AESInit[16];
bool Cached=false;
for (uint I=0;I<ASIZE(KDF3Cache);I++)
if (KDF3Cache[I].Pwd==*Password &&
(Salt==NULL && !KDF3Cache[I].SaltPresent || Salt!=NULL &&
KDF3Cache[I].SaltPresent && memcmp(KDF3Cache[I].Salt,Salt,SIZE_SALT30)==0))
{
memcpy(AESKey,KDF3Cache[I].Key,sizeof(AESKey));
SecHideData(AESKey,sizeof(AESKey),false,false);
memcpy(AESInit,KDF3Cache[I].Init,sizeof(AESInit));
Cached=true;
break;
}
if (!Cached)
{
byte RawPsw[2*MAXPASSWORD+SIZE_SALT30];
WideToRaw(PwdW,RawPsw,ASIZE(RawPsw));
size_t RawLength=2*wcslen(PwdW);
if (Salt!=NULL)
{
memcpy(RawPsw+RawLength,Salt,SIZE_SALT30);
RawLength+=SIZE_SALT30;
}
sha1_context c;
sha1_init(&c);
const int HashRounds=0x40000;
for (int I=0;I<HashRounds;I++)
{
sha1_process_rar29( &c, RawPsw, RawLength );
byte PswNum[3];
PswNum[0]=(byte)I;
PswNum[1]=(byte)(I>>8);
PswNum[2]=(byte)(I>>16);
sha1_process(&c, PswNum, 3);
if (I%(HashRounds/16)==0)
{
sha1_context tempc=c;
uint32 digest[5];
sha1_done( &tempc, digest );
AESInit[I/(HashRounds/16)]=(byte)digest[4];
}
}
uint32 digest[5];
sha1_done( &c, digest );
for (int I=0;I<4;I++)
for (int J=0;J<4;J++)
AESKey[I*4+J]=(byte)(digest[I]>>(J*8));
KDF3Cache[KDF3CachePos].Pwd=*Password;
if ((KDF3Cache[KDF3CachePos].SaltPresent=(Salt!=NULL))==true)
memcpy(KDF3Cache[KDF3CachePos].Salt,Salt,SIZE_SALT30);
memcpy(KDF3Cache[KDF3CachePos].Key,AESKey,sizeof(AESKey));
SecHideData(KDF3Cache[KDF3CachePos].Key,sizeof(KDF3Cache[KDF3CachePos].Key),true,false);
memcpy(KDF3Cache[KDF3CachePos].Init,AESInit,sizeof(AESInit));
KDF3CachePos=(KDF3CachePos+1)%ASIZE(KDF3Cache);
cleandata(RawPsw,sizeof(RawPsw));
}
rin.Init(Encrypt, AESKey, 128, AESInit);
cleandata(AESKey,sizeof(AESKey));
cleandata(AESInit,sizeof(AESInit));
}

233
reference/unrar/crypt5.cpp Normal file
View File

@@ -0,0 +1,233 @@
static void hmac_sha256(const byte *Key,size_t KeyLength,const byte *Data,
size_t DataLength,byte *ResDigest,
sha256_context *ICtxOpt,bool *SetIOpt,
sha256_context *RCtxOpt,bool *SetROpt)
{
const size_t Sha256BlockSize=64; // As defined in RFC 4868.
byte KeyHash[SHA256_DIGEST_SIZE];
if (KeyLength > Sha256BlockSize) // Convert longer keys to key hash.
{
sha256_context KCtx;
sha256_init(&KCtx);
sha256_process(&KCtx, Key, KeyLength);
sha256_done(&KCtx, KeyHash);
Key = KeyHash;
KeyLength = SHA256_DIGEST_SIZE;
}
byte KeyBuf[Sha256BlockSize]; // Store the padded key here.
sha256_context ICtx;
if (ICtxOpt!=NULL && *SetIOpt)
ICtx=*ICtxOpt; // Use already calculated first block context.
else
{
// This calculation is the same for all iterations with same password.
// So for PBKDF2 we can calculate it only for first block and then reuse
// to improve performance.
for (size_t I = 0; I < KeyLength; I++) // Use 0x36 padding for inner digest.
KeyBuf[I] = Key[I] ^ 0x36;
for (size_t I = KeyLength; I < Sha256BlockSize; I++)
KeyBuf[I] = 0x36;
sha256_init(&ICtx);
sha256_process(&ICtx, KeyBuf, Sha256BlockSize); // Hash padded key.
}
if (ICtxOpt!=NULL && !*SetIOpt) // Store constant context for further reuse.
{
*ICtxOpt=ICtx;
*SetIOpt=true;
}
sha256_process(&ICtx, Data, DataLength); // Hash data.
byte IDig[SHA256_DIGEST_SIZE]; // Internal digest for padded key and data.
sha256_done(&ICtx, IDig);
sha256_context RCtx;
if (RCtxOpt!=NULL && *SetROpt)
RCtx=*RCtxOpt; // Use already calculated first block context.
else
{
// This calculation is the same for all iterations with same password.
// So for PBKDF2 we can calculate it only for first block and then reuse
// to improve performance.
for (size_t I = 0; I < KeyLength; I++) // Use 0x5c for outer key padding.
KeyBuf[I] = Key[I] ^ 0x5c;
for (size_t I = KeyLength; I < Sha256BlockSize; I++)
KeyBuf[I] = 0x5c;
sha256_init(&RCtx);
sha256_process(&RCtx, KeyBuf, Sha256BlockSize); // Hash padded key.
}
if (RCtxOpt!=NULL && !*SetROpt) // Store constant context for further reuse.
{
*RCtxOpt=RCtx;
*SetROpt=true;
}
sha256_process(&RCtx, IDig, SHA256_DIGEST_SIZE); // Hash internal digest.
sha256_done(&RCtx, ResDigest);
}
// PBKDF2 for 32 byte key length. We generate the key for specified number
// of iteration count also as two supplementary values (key for checksums
// and password verification) for iterations+16 and iterations+32.
void pbkdf2(const byte *Pwd, size_t PwdLength,
const byte *Salt, size_t SaltLength,
byte *Key, byte *V1, byte *V2, uint Count)
{
const size_t MaxSalt=64;
byte SaltData[MaxSalt+4];
memcpy(SaltData, Salt, Min(SaltLength,MaxSalt));
SaltData[SaltLength + 0] = 0; // Salt concatenated to 1.
SaltData[SaltLength + 1] = 0;
SaltData[SaltLength + 2] = 0;
SaltData[SaltLength + 3] = 1;
// First iteration: HMAC of password, salt and block index (1).
byte U1[SHA256_DIGEST_SIZE];
hmac_sha256(Pwd, PwdLength, SaltData, SaltLength + 4, U1, NULL, NULL, NULL, NULL);
byte Fn[SHA256_DIGEST_SIZE]; // Current function value.
memcpy(Fn, U1, sizeof(Fn)); // Function at first iteration.
uint CurCount[] = { Count-1, 16, 16 };
byte *CurValue[] = { Key , V1, V2 };
sha256_context ICtxOpt,RCtxOpt;
bool SetIOpt=false,SetROpt=false;
byte U2[SHA256_DIGEST_SIZE];
for (uint I = 0; I < 3; I++) // For output key and 2 supplementary values.
{
for (uint J = 0; J < CurCount[I]; J++)
{
// U2 = PRF (P, U1).
hmac_sha256(Pwd, PwdLength, U1, sizeof(U1), U2, &ICtxOpt, &SetIOpt, &RCtxOpt, &SetROpt);
memcpy(U1, U2, sizeof(U1));
for (uint K = 0; K < sizeof(Fn); K++) // Function ^= U.
Fn[K] ^= U1[K];
}
memcpy(CurValue[I], Fn, SHA256_DIGEST_SIZE);
}
cleandata(SaltData, sizeof(SaltData));
cleandata(Fn, sizeof(Fn));
cleandata(U1, sizeof(U1));
cleandata(U2, sizeof(U2));
}
void CryptData::SetKey50(bool Encrypt,SecPassword *Password,const wchar *PwdW,
const byte *Salt,const byte *InitV,uint Lg2Cnt,byte *HashKey,
byte *PswCheck)
{
if (Lg2Cnt>CRYPT5_KDF_LG2_COUNT_MAX)
return;
byte Key[32],PswCheckValue[SHA256_DIGEST_SIZE],HashKeyValue[SHA256_DIGEST_SIZE];
bool Found=false;
for (uint I=0;I<ASIZE(KDF5Cache);I++)
{
KDF5CacheItem *Item=KDF5Cache+I;
if (Item->Lg2Count==Lg2Cnt && Item->Pwd==*Password &&
memcmp(Item->Salt,Salt,SIZE_SALT50)==0)
{
memcpy(Key,Item->Key,sizeof(Key));
SecHideData(Key,sizeof(Key),false,false);
memcpy(PswCheckValue,Item->PswCheckValue,sizeof(PswCheckValue));
memcpy(HashKeyValue,Item->HashKeyValue,sizeof(HashKeyValue));
Found=true;
break;
}
}
if (!Found)
{
char PwdUtf[MAXPASSWORD*4];
WideToUtf(PwdW,PwdUtf,ASIZE(PwdUtf));
pbkdf2((byte *)PwdUtf,strlen(PwdUtf),Salt,SIZE_SALT50,Key,HashKeyValue,PswCheckValue,(1<<Lg2Cnt));
cleandata(PwdUtf,sizeof(PwdUtf));
KDF5CacheItem *Item=KDF5Cache+(KDF5CachePos++ % ASIZE(KDF5Cache));
Item->Lg2Count=Lg2Cnt;
Item->Pwd=*Password;
memcpy(Item->Salt,Salt,SIZE_SALT50);
memcpy(Item->Key,Key,sizeof(Item->Key));
memcpy(Item->PswCheckValue,PswCheckValue,sizeof(PswCheckValue));
memcpy(Item->HashKeyValue,HashKeyValue,sizeof(HashKeyValue));
SecHideData(Item->Key,sizeof(Item->Key),true,false);
}
if (HashKey!=NULL)
memcpy(HashKey,HashKeyValue,SHA256_DIGEST_SIZE);
if (PswCheck!=NULL)
{
memset(PswCheck,0,SIZE_PSWCHECK);
for (uint I=0;I<SHA256_DIGEST_SIZE;I++)
PswCheck[I%SIZE_PSWCHECK]^=PswCheckValue[I];
cleandata(PswCheckValue,sizeof(PswCheckValue));
}
// NULL initialization vector is possible if we only need the password
// check value for archive encryption header.
if (InitV!=NULL)
rin.Init(Encrypt, Key, 256, InitV);
cleandata(Key,sizeof(Key));
}
void ConvertHashToMAC(HashValue *Value,byte *Key)
{
if (Value->Type==HASH_CRC32)
{
byte RawCRC[4];
RawPut4(Value->CRC32,RawCRC);
byte Digest[SHA256_DIGEST_SIZE];
hmac_sha256(Key,SHA256_DIGEST_SIZE,RawCRC,sizeof(RawCRC),Digest,NULL,NULL,NULL,NULL);
Value->CRC32=0;
for (uint I=0;I<ASIZE(Digest);I++)
Value->CRC32^=Digest[I] << ((I & 3) * 8);
}
if (Value->Type==HASH_BLAKE2)
{
byte Digest[BLAKE2_DIGEST_SIZE];
hmac_sha256(Key,BLAKE2_DIGEST_SIZE,Value->Digest,sizeof(Value->Digest),Digest,NULL,NULL,NULL,NULL);
memcpy(Value->Digest,Digest,sizeof(Value->Digest));
}
}
#if 0
static void TestPBKDF2();
struct TestKDF {TestKDF() {TestPBKDF2();exit(0);}} GlobalTestKDF;
void TestPBKDF2() // Test PBKDF2 HMAC-SHA256
{
byte Key[32],V1[32],V2[32];
pbkdf2((byte *)"password", 8, (byte *)"salt", 4, Key, V1, V2, 1);
byte Res1[32]={0x12, 0x0f, 0xb6, 0xcf, 0xfc, 0xf8, 0xb3, 0x2c, 0x43, 0xe7, 0x22, 0x52, 0x56, 0xc4, 0xf8, 0x37, 0xa8, 0x65, 0x48, 0xc9, 0x2c, 0xcc, 0x35, 0x48, 0x08, 0x05, 0x98, 0x7c, 0xb7, 0x0b, 0xe1, 0x7b };
mprintf(L"\nPBKDF2 test1: %s", memcmp(Key,Res1,32)==0 ? L"OK":L"Failed");
pbkdf2((byte *)"password", 8, (byte *)"salt", 4, Key, V1, V2, 4096);
byte Res2[32]={0xc5, 0xe4, 0x78, 0xd5, 0x92, 0x88, 0xc8, 0x41, 0xaa, 0x53, 0x0d, 0xb6, 0x84, 0x5c, 0x4c, 0x8d, 0x96, 0x28, 0x93, 0xa0, 0x01, 0xce, 0x4e, 0x11, 0xa4, 0x96, 0x38, 0x73, 0xaa, 0x98, 0x13, 0x4a };
mprintf(L"\nPBKDF2 test2: %s", memcmp(Key,Res2,32)==0 ? L"OK":L"Failed");
pbkdf2((byte *)"just some long string pretending to be a password", 49, (byte *)"salt, salt, salt, a lot of salt", 31, Key, V1, V2, 65536);
byte Res3[32]={0x08, 0x0f, 0xa3, 0x1d, 0x42, 0x2d, 0xb0, 0x47, 0x83, 0x9b, 0xce, 0x3a, 0x3b, 0xce, 0x49, 0x51, 0xe2, 0x62, 0xb9, 0xff, 0x76, 0x2f, 0x57, 0xe9, 0xc4, 0x71, 0x96, 0xce, 0x4b, 0x6b, 0x6e, 0xbf};
mprintf(L"\nPBKDF2 test3: %s", memcmp(Key,Res3,32)==0 ? L"OK":L"Failed");
}
#endif

474
reference/unrar/dll.cpp Normal file
View File

@@ -0,0 +1,474 @@
#include "rar.hpp"
static int RarErrorToDll(RAR_EXIT ErrCode);
struct DataSet
{
CommandData Cmd;
Archive Arc;
CmdExtract Extract;
int OpenMode;
int HeaderSize;
DataSet():Arc(&Cmd),Extract(&Cmd) {};
};
HANDLE PASCAL RAROpenArchive(struct RAROpenArchiveData *r)
{
RAROpenArchiveDataEx rx;
memset(&rx,0,sizeof(rx));
rx.ArcName=r->ArcName;
rx.OpenMode=r->OpenMode;
rx.CmtBuf=r->CmtBuf;
rx.CmtBufSize=r->CmtBufSize;
HANDLE hArc=RAROpenArchiveEx(&rx);
r->OpenResult=rx.OpenResult;
r->CmtSize=rx.CmtSize;
r->CmtState=rx.CmtState;
return hArc;
}
HANDLE PASCAL RAROpenArchiveEx(struct RAROpenArchiveDataEx *r)
{
DataSet *Data=NULL;
try
{
r->OpenResult=0;
Data=new DataSet;
Data->Cmd.DllError=0;
Data->OpenMode=r->OpenMode;
Data->Cmd.FileArgs.AddString(L"*");
char AnsiArcName[NM];
*AnsiArcName=0;
if (r->ArcName!=NULL)
{
strncpyz(AnsiArcName,r->ArcName,ASIZE(AnsiArcName));
#ifdef _WIN_ALL
if (!AreFileApisANSI())
{
OemToCharBuffA(r->ArcName,AnsiArcName,ASIZE(AnsiArcName));
AnsiArcName[ASIZE(AnsiArcName)-1]=0;
}
#endif
}
wchar ArcName[NM];
GetWideName(AnsiArcName,r->ArcNameW,ArcName,ASIZE(ArcName));
Data->Cmd.AddArcName(ArcName);
Data->Cmd.Overwrite=OVERWRITE_ALL;
Data->Cmd.VersionControl=1;
Data->Cmd.Callback=r->Callback;
Data->Cmd.UserData=r->UserData;
// Open shared mode is added by request of dll users, who need to
// browse and unpack archives while downloading.
Data->Cmd.OpenShared = true;
if (!Data->Arc.Open(ArcName,FMF_OPENSHARED))
{
r->OpenResult=ERAR_EOPEN;
delete Data;
return NULL;
}
if (!Data->Arc.IsArchive(true))
{
if (Data->Cmd.DllError!=0)
r->OpenResult=Data->Cmd.DllError;
else
{
RAR_EXIT ErrCode=ErrHandler.GetErrorCode();
if (ErrCode!=RARX_SUCCESS && ErrCode!=RARX_WARNING)
r->OpenResult=RarErrorToDll(ErrCode);
else
r->OpenResult=ERAR_BAD_ARCHIVE;
}
delete Data;
return NULL;
}
r->Flags=0;
if (Data->Arc.Volume)
r->Flags|=0x01;
if (Data->Arc.Locked)
r->Flags|=0x04;
if (Data->Arc.Solid)
r->Flags|=0x08;
if (Data->Arc.NewNumbering)
r->Flags|=0x10;
if (Data->Arc.Signed)
r->Flags|=0x20;
if (Data->Arc.Protected)
r->Flags|=0x40;
if (Data->Arc.Encrypted)
r->Flags|=0x80;
if (Data->Arc.FirstVolume)
r->Flags|=0x100;
Array<wchar> CmtDataW;
if (r->CmtBufSize!=0 && Data->Arc.GetComment(&CmtDataW))
{
Array<char> CmtData(CmtDataW.Size()*4+1);
memset(&CmtData[0],0,CmtData.Size());
WideToChar(&CmtDataW[0],&CmtData[0],CmtData.Size()-1);
size_t Size=strlen(&CmtData[0])+1;
r->Flags|=2;
r->CmtState=Size>r->CmtBufSize ? ERAR_SMALL_BUF:1;
r->CmtSize=(uint)Min(Size,r->CmtBufSize);
memcpy(r->CmtBuf,&CmtData[0],r->CmtSize-1);
if (Size<=r->CmtBufSize)
r->CmtBuf[r->CmtSize-1]=0;
}
else
r->CmtState=r->CmtSize=0;
Data->Extract.ExtractArchiveInit(Data->Arc);
return (HANDLE)Data;
}
catch (RAR_EXIT ErrCode)
{
if (Data!=NULL && Data->Cmd.DllError!=0)
r->OpenResult=Data->Cmd.DllError;
else
r->OpenResult=RarErrorToDll(ErrCode);
if (Data != NULL)
delete Data;
return NULL;
}
catch (std::bad_alloc&) // Catch 'new' exception.
{
r->OpenResult=ERAR_NO_MEMORY;
if (Data != NULL)
delete Data;
}
return NULL; // To make compilers happy.
}
int PASCAL RARCloseArchive(HANDLE hArcData)
{
DataSet *Data=(DataSet *)hArcData;
bool Success=Data==NULL ? false:Data->Arc.Close();
delete Data;
return Success ? ERAR_SUCCESS : ERAR_ECLOSE;
}
int PASCAL RARReadHeader(HANDLE hArcData,struct RARHeaderData *D)
{
struct RARHeaderDataEx X;
memset(&X,0,sizeof(X));
int Code=RARReadHeaderEx(hArcData,&X);
strncpyz(D->ArcName,X.ArcName,ASIZE(D->ArcName));
strncpyz(D->FileName,X.FileName,ASIZE(D->FileName));
D->Flags=X.Flags;
D->PackSize=X.PackSize;
D->UnpSize=X.UnpSize;
D->HostOS=X.HostOS;
D->FileCRC=X.FileCRC;
D->FileTime=X.FileTime;
D->UnpVer=X.UnpVer;
D->Method=X.Method;
D->FileAttr=X.FileAttr;
D->CmtSize=0;
D->CmtState=0;
return Code;
}
int PASCAL RARReadHeaderEx(HANDLE hArcData,struct RARHeaderDataEx *D)
{
DataSet *Data=(DataSet *)hArcData;
try
{
if ((Data->HeaderSize=(int)Data->Arc.SearchBlock(HEAD_FILE))<=0)
{
if (Data->Arc.Volume && Data->Arc.GetHeaderType()==HEAD_ENDARC &&
Data->Arc.EndArcHead.NextVolume)
if (MergeArchive(Data->Arc,NULL,false,'L'))
{
Data->Arc.Seek(Data->Arc.CurBlockPos,SEEK_SET);
return RARReadHeaderEx(hArcData,D);
}
else
return ERAR_EOPEN;
if (Data->Arc.BrokenHeader)
return ERAR_BAD_DATA;
// Might be necessary if RARSetPassword is still called instead of
// open callback for RAR5 archives and if password is invalid.
if (Data->Arc.FailedHeaderDecryption)
return ERAR_BAD_PASSWORD;
return ERAR_END_ARCHIVE;
}
FileHeader *hd=&Data->Arc.FileHead;
if (Data->OpenMode==RAR_OM_LIST && hd->SplitBefore)
{
int Code=RARProcessFile(hArcData,RAR_SKIP,NULL,NULL);
if (Code==0)
return RARReadHeaderEx(hArcData,D);
else
return Code;
}
wcsncpy(D->ArcNameW,Data->Arc.FileName,ASIZE(D->ArcNameW));
WideToChar(D->ArcNameW,D->ArcName,ASIZE(D->ArcName));
wcsncpy(D->FileNameW,hd->FileName,ASIZE(D->FileNameW));
WideToChar(D->FileNameW,D->FileName,ASIZE(D->FileName));
#ifdef _WIN_ALL
CharToOemA(D->FileName,D->FileName);
#endif
D->Flags=0;
if (hd->SplitBefore)
D->Flags|=RHDF_SPLITBEFORE;
if (hd->SplitAfter)
D->Flags|=RHDF_SPLITAFTER;
if (hd->Encrypted)
D->Flags|=RHDF_ENCRYPTED;
if (hd->Solid)
D->Flags|=RHDF_SOLID;
if (hd->Dir)
D->Flags|=RHDF_DIRECTORY;
D->PackSize=uint(hd->PackSize & 0xffffffff);
D->PackSizeHigh=uint(hd->PackSize>>32);
D->UnpSize=uint(hd->UnpSize & 0xffffffff);
D->UnpSizeHigh=uint(hd->UnpSize>>32);
D->HostOS=hd->HSType==HSYS_WINDOWS ? HOST_WIN32:HOST_UNIX;
if (Data->Arc.Format==RARFMT50)
D->UnpVer=Data->Arc.FileHead.UnpVer==0 ? 50 : 200; // If it is not 0, just set it to something big.
else
D->UnpVer=Data->Arc.FileHead.UnpVer;
D->FileCRC=hd->FileHash.CRC32;
D->FileTime=hd->mtime.GetDos();
uint64 MRaw=hd->mtime.GetWin();
D->MtimeLow=(uint)MRaw;
D->MtimeHigh=(uint)(MRaw>>32);
uint64 CRaw=hd->ctime.GetWin();
D->CtimeLow=(uint)CRaw;
D->CtimeHigh=(uint)(CRaw>>32);
uint64 ARaw=hd->atime.GetWin();
D->AtimeLow=(uint)ARaw;
D->AtimeHigh=(uint)(ARaw>>32);
D->Method=hd->Method+0x30;
D->FileAttr=hd->FileAttr;
D->CmtSize=0;
D->CmtState=0;
D->DictSize=uint(hd->WinSize/1024);
switch (hd->FileHash.Type)
{
case HASH_RAR14:
case HASH_CRC32:
D->HashType=RAR_HASH_CRC32;
break;
case HASH_BLAKE2:
D->HashType=RAR_HASH_BLAKE2;
memcpy(D->Hash,hd->FileHash.Digest,BLAKE2_DIGEST_SIZE);
break;
default:
D->HashType=RAR_HASH_NONE;
break;
}
D->RedirType=hd->RedirType;
// RedirNameSize sanity check is useful in case some developer
// did not initialize Reserved area with 0 as required in docs.
// We have taken 'Redir*' fields from Reserved area. We may remove
// this RedirNameSize check sometimes later.
if (hd->RedirType!=FSREDIR_NONE && D->RedirName!=NULL &&
D->RedirNameSize>0 && D->RedirNameSize<100000)
wcsncpyz(D->RedirName,hd->RedirName,D->RedirNameSize);
D->DirTarget=hd->DirTarget;
}
catch (RAR_EXIT ErrCode)
{
return Data->Cmd.DllError!=0 ? Data->Cmd.DllError : RarErrorToDll(ErrCode);
}
return ERAR_SUCCESS;
}
int PASCAL ProcessFile(HANDLE hArcData,int Operation,char *DestPath,char *DestName,wchar *DestPathW,wchar *DestNameW)
{
DataSet *Data=(DataSet *)hArcData;
try
{
Data->Cmd.DllError=0;
if (Data->OpenMode==RAR_OM_LIST || Data->OpenMode==RAR_OM_LIST_INCSPLIT ||
Operation==RAR_SKIP && !Data->Arc.Solid)
{
if (Data->Arc.Volume && Data->Arc.GetHeaderType()==HEAD_FILE &&
Data->Arc.FileHead.SplitAfter)
if (MergeArchive(Data->Arc,NULL,false,'L'))
{
Data->Arc.Seek(Data->Arc.CurBlockPos,SEEK_SET);
return ERAR_SUCCESS;
}
else
return ERAR_EOPEN;
Data->Arc.SeekToNext();
}
else
{
Data->Cmd.DllOpMode=Operation;
*Data->Cmd.ExtrPath=0;
*Data->Cmd.DllDestName=0;
if (DestPath!=NULL)
{
char ExtrPathA[NM];
strncpyz(ExtrPathA,DestPath,ASIZE(ExtrPathA)-2);
#ifdef _WIN_ALL
// We must not apply OemToCharBuffA directly to DestPath,
// because we do not know DestPath length and OemToCharBuffA
// does not stop at 0.
OemToCharA(ExtrPathA,ExtrPathA);
#endif
CharToWide(ExtrPathA,Data->Cmd.ExtrPath,ASIZE(Data->Cmd.ExtrPath));
AddEndSlash(Data->Cmd.ExtrPath,ASIZE(Data->Cmd.ExtrPath));
}
if (DestName!=NULL)
{
char DestNameA[NM];
strncpyz(DestNameA,DestName,ASIZE(DestNameA)-2);
#ifdef _WIN_ALL
// We must not apply OemToCharBuffA directly to DestName,
// because we do not know DestName length and OemToCharBuffA
// does not stop at 0.
OemToCharA(DestNameA,DestNameA);
#endif
CharToWide(DestNameA,Data->Cmd.DllDestName,ASIZE(Data->Cmd.DllDestName));
}
if (DestPathW!=NULL)
{
wcsncpy(Data->Cmd.ExtrPath,DestPathW,ASIZE(Data->Cmd.ExtrPath));
AddEndSlash(Data->Cmd.ExtrPath,ASIZE(Data->Cmd.ExtrPath));
}
if (DestNameW!=NULL)
wcsncpyz(Data->Cmd.DllDestName,DestNameW,ASIZE(Data->Cmd.DllDestName));
wcscpy(Data->Cmd.Command,Operation==RAR_EXTRACT ? L"X":L"T");
Data->Cmd.Test=Operation!=RAR_EXTRACT;
bool Repeat=false;
Data->Extract.ExtractCurrentFile(Data->Arc,Data->HeaderSize,Repeat);
// Now we process extra file information if any.
//
// Archive can be closed if we process volumes, next volume is missing
// and current one is already removed or deleted. So we need to check
// if archive is still open to avoid calling file operations on
// the invalid file handle. Some of our file operations like Seek()
// process such invalid handle correctly, some not.
while (Data->Arc.IsOpened() && Data->Arc.ReadHeader()!=0 &&
Data->Arc.GetHeaderType()==HEAD_SERVICE)
{
Data->Extract.ExtractCurrentFile(Data->Arc,Data->HeaderSize,Repeat);
Data->Arc.SeekToNext();
}
Data->Arc.Seek(Data->Arc.CurBlockPos,SEEK_SET);
}
}
catch (std::bad_alloc&)
{
return ERAR_NO_MEMORY;
}
catch (RAR_EXIT ErrCode)
{
return Data->Cmd.DllError!=0 ? Data->Cmd.DllError : RarErrorToDll(ErrCode);
}
return Data->Cmd.DllError;
}
int PASCAL RARProcessFile(HANDLE hArcData,int Operation,char *DestPath,char *DestName)
{
return(ProcessFile(hArcData,Operation,DestPath,DestName,NULL,NULL));
}
int PASCAL RARProcessFileW(HANDLE hArcData,int Operation,wchar *DestPath,wchar *DestName)
{
return(ProcessFile(hArcData,Operation,NULL,NULL,DestPath,DestName));
}
void PASCAL RARSetChangeVolProc(HANDLE hArcData,CHANGEVOLPROC ChangeVolProc)
{
DataSet *Data=(DataSet *)hArcData;
Data->Cmd.ChangeVolProc=ChangeVolProc;
}
void PASCAL RARSetCallback(HANDLE hArcData,UNRARCALLBACK Callback,LPARAM UserData)
{
DataSet *Data=(DataSet *)hArcData;
Data->Cmd.Callback=Callback;
Data->Cmd.UserData=UserData;
}
void PASCAL RARSetProcessDataProc(HANDLE hArcData,PROCESSDATAPROC ProcessDataProc)
{
DataSet *Data=(DataSet *)hArcData;
Data->Cmd.ProcessDataProc=ProcessDataProc;
}
#ifndef RAR_NOCRYPT
void PASCAL RARSetPassword(HANDLE hArcData,char *Password)
{
DataSet *Data=(DataSet *)hArcData;
wchar PasswordW[MAXPASSWORD];
GetWideName(Password,NULL,PasswordW,ASIZE(PasswordW));
Data->Cmd.Password.Set(PasswordW);
cleandata(PasswordW,sizeof(PasswordW));
}
#endif
int PASCAL RARGetDllVersion()
{
return RAR_DLL_VERSION;
}
static int RarErrorToDll(RAR_EXIT ErrCode)
{
switch(ErrCode)
{
case RARX_FATAL:
return ERAR_EREAD;
case RARX_CRC:
return ERAR_BAD_DATA;
case RARX_WRITE:
return ERAR_EWRITE;
case RARX_OPEN:
return ERAR_EOPEN;
case RARX_CREATE:
return ERAR_ECREATE;
case RARX_MEMORY:
return ERAR_NO_MEMORY;
case RARX_BADPWD:
return ERAR_BAD_PASSWORD;
case RARX_SUCCESS:
return ERAR_SUCCESS; // 0.
default:
return ERAR_UNKNOWN;
}
}

12
reference/unrar/dll.def Normal file
View File

@@ -0,0 +1,12 @@
EXPORTS
RAROpenArchive
RAROpenArchiveEx
RARCloseArchive
RARReadHeader
RARReadHeaderEx
RARProcessFile
RARSetCallback
RARSetChangeVolProc
RARSetProcessDataProc
RARSetPassword
RARGetDllVersion

185
reference/unrar/dll.hpp Normal file
View File

@@ -0,0 +1,185 @@
#ifndef _UNRAR_DLL_
#define _UNRAR_DLL_
#pragma pack(1)
#define ERAR_SUCCESS 0
#define ERAR_END_ARCHIVE 10
#define ERAR_NO_MEMORY 11
#define ERAR_BAD_DATA 12
#define ERAR_BAD_ARCHIVE 13
#define ERAR_UNKNOWN_FORMAT 14
#define ERAR_EOPEN 15
#define ERAR_ECREATE 16
#define ERAR_ECLOSE 17
#define ERAR_EREAD 18
#define ERAR_EWRITE 19
#define ERAR_SMALL_BUF 20
#define ERAR_UNKNOWN 21
#define ERAR_MISSING_PASSWORD 22
#define ERAR_EREFERENCE 23
#define ERAR_BAD_PASSWORD 24
#define RAR_OM_LIST 0
#define RAR_OM_EXTRACT 1
#define RAR_OM_LIST_INCSPLIT 2
#define RAR_SKIP 0
#define RAR_TEST 1
#define RAR_EXTRACT 2
#define RAR_VOL_ASK 0
#define RAR_VOL_NOTIFY 1
#define RAR_DLL_VERSION 8
#define RAR_HASH_NONE 0
#define RAR_HASH_CRC32 1
#define RAR_HASH_BLAKE2 2
#ifdef _UNIX
#define CALLBACK
#define PASCAL
#define LONG long
#define HANDLE void *
#define LPARAM long
#define UINT unsigned int
#endif
#define RHDF_SPLITBEFORE 0x01
#define RHDF_SPLITAFTER 0x02
#define RHDF_ENCRYPTED 0x04
#define RHDF_SOLID 0x10
#define RHDF_DIRECTORY 0x20
struct RARHeaderData
{
char ArcName[260];
char FileName[260];
unsigned int Flags;
unsigned int PackSize;
unsigned int UnpSize;
unsigned int HostOS;
unsigned int FileCRC;
unsigned int FileTime;
unsigned int UnpVer;
unsigned int Method;
unsigned int FileAttr;
char *CmtBuf;
unsigned int CmtBufSize;
unsigned int CmtSize;
unsigned int CmtState;
};
struct RARHeaderDataEx
{
char ArcName[1024];
wchar_t ArcNameW[1024];
char FileName[1024];
wchar_t FileNameW[1024];
unsigned int Flags;
unsigned int PackSize;
unsigned int PackSizeHigh;
unsigned int UnpSize;
unsigned int UnpSizeHigh;
unsigned int HostOS;
unsigned int FileCRC;
unsigned int FileTime;
unsigned int UnpVer;
unsigned int Method;
unsigned int FileAttr;
char *CmtBuf;
unsigned int CmtBufSize;
unsigned int CmtSize;
unsigned int CmtState;
unsigned int DictSize;
unsigned int HashType;
char Hash[32];
unsigned int RedirType;
wchar_t *RedirName;
unsigned int RedirNameSize;
unsigned int DirTarget;
unsigned int MtimeLow;
unsigned int MtimeHigh;
unsigned int CtimeLow;
unsigned int CtimeHigh;
unsigned int AtimeLow;
unsigned int AtimeHigh;
unsigned int Reserved[988];
};
struct RAROpenArchiveData
{
char *ArcName;
unsigned int OpenMode;
unsigned int OpenResult;
char *CmtBuf;
unsigned int CmtBufSize;
unsigned int CmtSize;
unsigned int CmtState;
};
typedef int (CALLBACK *UNRARCALLBACK)(UINT msg,LPARAM UserData,LPARAM P1,LPARAM P2);
#define ROADF_VOLUME 0x0001
#define ROADF_COMMENT 0x0002
#define ROADF_LOCK 0x0004
#define ROADF_SOLID 0x0008
#define ROADF_NEWNUMBERING 0x0010
#define ROADF_SIGNED 0x0020
#define ROADF_RECOVERY 0x0040
#define ROADF_ENCHEADERS 0x0080
#define ROADF_FIRSTVOLUME 0x0100
struct RAROpenArchiveDataEx
{
char *ArcName;
wchar_t *ArcNameW;
unsigned int OpenMode;
unsigned int OpenResult;
char *CmtBuf;
unsigned int CmtBufSize;
unsigned int CmtSize;
unsigned int CmtState;
unsigned int Flags;
UNRARCALLBACK Callback;
LPARAM UserData;
unsigned int Reserved[28];
};
enum UNRARCALLBACK_MESSAGES {
UCM_CHANGEVOLUME,UCM_PROCESSDATA,UCM_NEEDPASSWORD,UCM_CHANGEVOLUMEW,
UCM_NEEDPASSWORDW
};
typedef int (PASCAL *CHANGEVOLPROC)(char *ArcName,int Mode);
typedef int (PASCAL *PROCESSDATAPROC)(unsigned char *Addr,int Size);
#ifdef __cplusplus
extern "C" {
#endif
HANDLE PASCAL RAROpenArchive(struct RAROpenArchiveData *ArchiveData);
HANDLE PASCAL RAROpenArchiveEx(struct RAROpenArchiveDataEx *ArchiveData);
int PASCAL RARCloseArchive(HANDLE hArcData);
int PASCAL RARReadHeader(HANDLE hArcData,struct RARHeaderData *HeaderData);
int PASCAL RARReadHeaderEx(HANDLE hArcData,struct RARHeaderDataEx *HeaderData);
int PASCAL RARProcessFile(HANDLE hArcData,int Operation,char *DestPath,char *DestName);
int PASCAL RARProcessFileW(HANDLE hArcData,int Operation,wchar_t *DestPath,wchar_t *DestName);
void PASCAL RARSetCallback(HANDLE hArcData,UNRARCALLBACK Callback,LPARAM UserData);
void PASCAL RARSetChangeVolProc(HANDLE hArcData,CHANGEVOLPROC ChangeVolProc);
void PASCAL RARSetProcessDataProc(HANDLE hArcData,PROCESSDATAPROC ProcessDataProc);
void PASCAL RARSetPassword(HANDLE hArcData,char *Password);
int PASCAL RARGetDllVersion();
#ifdef __cplusplus
}
#endif
#pragma pack()
#endif

28
reference/unrar/dll.rc Normal file
View File

@@ -0,0 +1,28 @@
#include <windows.h>
#include <commctrl.h>
VS_VERSION_INFO VERSIONINFO
FILEVERSION 5, 50, 100, 2418
PRODUCTVERSION 5, 50, 100, 2418
FILEOS VOS__WINDOWS32
FILETYPE VFT_APP
{
BLOCK "StringFileInfo"
{
BLOCK "040904E4"
{
VALUE "CompanyName", "Alexander Roshal\0"
VALUE "ProductName", "RAR decompression library\0"
VALUE "FileDescription", "RAR decompression library\0"
VALUE "FileVersion", "5.50.0\0"
VALUE "ProductVersion", "5.50.0\0"
VALUE "LegalCopyright", "Copyright © Alexander Roshal 1993-2017\0"
VALUE "OriginalFilename", "Unrar.dll\0"
}
}
BLOCK "VarFileInfo"
{
VALUE "Translation", 0x0409, 0x04E4
}
}

View File

@@ -0,0 +1,69 @@
#include "rar.hpp"
EncodeFileName::EncodeFileName()
{
Flags=0;
FlagBits=0;
FlagsPos=0;
DestSize=0;
}
void EncodeFileName::Decode(char *Name,byte *EncName,size_t EncSize,wchar *NameW,
size_t MaxDecSize)
{
size_t EncPos=0,DecPos=0;
byte HighByte=EncPos<EncSize ? EncName[EncPos++] : 0;
while (EncPos<EncSize && DecPos<MaxDecSize)
{
if (FlagBits==0)
{
if (EncPos>=EncSize)
break;
Flags=EncName[EncPos++];
FlagBits=8;
}
switch(Flags>>6)
{
case 0:
if (EncPos>=EncSize)
break;
NameW[DecPos++]=EncName[EncPos++];
break;
case 1:
if (EncPos>=EncSize)
break;
NameW[DecPos++]=EncName[EncPos++]+(HighByte<<8);
break;
case 2:
if (EncPos+1>=EncSize)
break;
NameW[DecPos++]=EncName[EncPos]+(EncName[EncPos+1]<<8);
EncPos+=2;
break;
case 3:
{
if (EncPos>=EncSize)
break;
int Length=EncName[EncPos++];
if ((Length & 0x80)!=0)
{
if (EncPos>=EncSize)
break;
byte Correction=EncName[EncPos++];
for (Length=(Length&0x7f)+2;Length>0 && DecPos<MaxDecSize;Length--,DecPos++)
NameW[DecPos]=((Name[DecPos]+Correction)&0xff)+(HighByte<<8);
}
else
for (Length+=2;Length>0 && DecPos<MaxDecSize;Length--,DecPos++)
NameW[DecPos]=Name[DecPos];
}
break;
}
Flags<<=2;
FlagBits-=2;
}
NameW[DecPos<MaxDecSize ? DecPos:MaxDecSize-1]=0;
}

View File

@@ -0,0 +1,20 @@
#ifndef _RAR_ENCNAME_
#define _RAR_ENCNAME_
class EncodeFileName
{
private:
void AddFlags(int Value);
byte *EncName;
byte Flags;
uint FlagBits;
size_t FlagsPos;
size_t DestSize;
public:
EncodeFileName();
size_t Encode(char *Name,wchar *NameW,byte *EncName);
void Decode(char *Name,byte *EncName,size_t EncSize,wchar *NameW,size_t MaxDecSize);
};
#endif

391
reference/unrar/errhnd.cpp Normal file
View File

@@ -0,0 +1,391 @@
#include "rar.hpp"
ErrorHandler::ErrorHandler()
{
Clean();
}
void ErrorHandler::Clean()
{
ExitCode=RARX_SUCCESS;
ErrCount=0;
EnableBreak=true;
Silent=false;
UserBreak=false;
MainExit=false;
DisableShutdown=false;
}
void ErrorHandler::MemoryError()
{
MemoryErrorMsg();
Exit(RARX_MEMORY);
}
void ErrorHandler::OpenError(const wchar *FileName)
{
#ifndef SILENT
OpenErrorMsg(FileName);
Exit(RARX_OPEN);
#endif
}
void ErrorHandler::CloseError(const wchar *FileName)
{
if (!UserBreak)
{
uiMsg(UIERROR_FILECLOSE,FileName);
SysErrMsg();
}
#if !defined(SILENT) || defined(RARDLL)
Exit(RARX_FATAL);
#endif
}
void ErrorHandler::ReadError(const wchar *FileName)
{
#ifndef SILENT
ReadErrorMsg(FileName);
#endif
#if !defined(SILENT) || defined(RARDLL)
Exit(RARX_FATAL);
#endif
}
bool ErrorHandler::AskRepeatRead(const wchar *FileName)
{
#if !defined(SILENT) && !defined(SFX_MODULE)
if (!Silent)
{
SysErrMsg();
bool Repeat=uiAskRepeatRead(FileName);
if (!Repeat) // Disable shutdown if user pressed Cancel in error dialog.
DisableShutdown=true;
return Repeat;
}
#endif
return false;
}
void ErrorHandler::WriteError(const wchar *ArcName,const wchar *FileName)
{
#ifndef SILENT
WriteErrorMsg(ArcName,FileName);
#endif
#if !defined(SILENT) || defined(RARDLL)
Exit(RARX_WRITE);
#endif
}
#ifdef _WIN_ALL
void ErrorHandler::WriteErrorFAT(const wchar *FileName)
{
SysErrMsg();
uiMsg(UIERROR_NTFSREQUIRED,FileName);
#if !defined(SILENT) && !defined(SFX_MODULE) || defined(RARDLL)
Exit(RARX_WRITE);
#endif
}
#endif
bool ErrorHandler::AskRepeatWrite(const wchar *FileName,bool DiskFull)
{
#ifndef SILENT
if (!Silent)
{
// We do not display "repeat write" prompt in Android, so we do not
// need the matching system error message.
SysErrMsg();
bool Repeat=uiAskRepeatWrite(FileName,DiskFull);
if (!Repeat) // Disable shutdown if user pressed Cancel in error dialog.
DisableShutdown=true;
return Repeat;
}
#endif
return false;
}
void ErrorHandler::SeekError(const wchar *FileName)
{
if (!UserBreak)
{
uiMsg(UIERROR_FILESEEK,FileName);
SysErrMsg();
}
#if !defined(SILENT) || defined(RARDLL)
Exit(RARX_FATAL);
#endif
}
void ErrorHandler::GeneralErrMsg(const wchar *fmt,...)
{
va_list arglist;
va_start(arglist,fmt);
wchar Msg[1024];
vswprintf(Msg,ASIZE(Msg),fmt,arglist);
uiMsg(UIERROR_GENERALERRMSG,Msg);
SysErrMsg();
va_end(arglist);
}
void ErrorHandler::MemoryErrorMsg()
{
uiMsg(UIERROR_MEMORY);
SetErrorCode(RARX_MEMORY);
}
void ErrorHandler::OpenErrorMsg(const wchar *FileName)
{
OpenErrorMsg(NULL,FileName);
}
void ErrorHandler::OpenErrorMsg(const wchar *ArcName,const wchar *FileName)
{
uiMsg(UIERROR_FILEOPEN,ArcName,FileName);
SysErrMsg();
SetErrorCode(RARX_OPEN);
}
void ErrorHandler::CreateErrorMsg(const wchar *FileName)
{
CreateErrorMsg(NULL,FileName);
}
void ErrorHandler::CreateErrorMsg(const wchar *ArcName,const wchar *FileName)
{
uiMsg(UIERROR_FILECREATE,ArcName,FileName);
SysErrMsg();
SetErrorCode(RARX_CREATE);
}
void ErrorHandler::ReadErrorMsg(const wchar *FileName)
{
ReadErrorMsg(NULL,FileName);
}
void ErrorHandler::ReadErrorMsg(const wchar *ArcName,const wchar *FileName)
{
uiMsg(UIERROR_FILEREAD,ArcName,FileName);
SysErrMsg();
SetErrorCode(RARX_FATAL);
}
void ErrorHandler::WriteErrorMsg(const wchar *ArcName,const wchar *FileName)
{
uiMsg(UIERROR_FILEWRITE,ArcName,FileName);
SysErrMsg();
SetErrorCode(RARX_WRITE);
}
void ErrorHandler::ArcBrokenMsg(const wchar *ArcName)
{
uiMsg(UIERROR_ARCBROKEN,ArcName);
SetErrorCode(RARX_CRC);
}
void ErrorHandler::ChecksumFailedMsg(const wchar *ArcName,const wchar *FileName)
{
uiMsg(UIERROR_CHECKSUM,ArcName,FileName);
SetErrorCode(RARX_CRC);
}
void ErrorHandler::UnknownMethodMsg(const wchar *ArcName,const wchar *FileName)
{
uiMsg(UIERROR_UNKNOWNMETHOD,ArcName,FileName);
ErrHandler.SetErrorCode(RARX_FATAL);
}
void ErrorHandler::Exit(RAR_EXIT ExitCode)
{
uiAlarm(UIALARM_ERROR);
Throw(ExitCode);
}
void ErrorHandler::SetErrorCode(RAR_EXIT Code)
{
switch(Code)
{
case RARX_WARNING:
case RARX_USERBREAK:
if (ExitCode==RARX_SUCCESS)
ExitCode=Code;
break;
case RARX_CRC:
if (ExitCode!=RARX_BADPWD)
ExitCode=Code;
break;
case RARX_FATAL:
if (ExitCode==RARX_SUCCESS || ExitCode==RARX_WARNING)
ExitCode=RARX_FATAL;
break;
default:
ExitCode=Code;
break;
}
ErrCount++;
}
#ifdef _WIN_ALL
BOOL __stdcall ProcessSignal(DWORD SigType)
#else
#if defined(__sun)
extern "C"
#endif
void _stdfunction ProcessSignal(int SigType)
#endif
{
#ifdef _WIN_ALL
// When a console application is run as a service, this allows the service
// to continue running after the user logs off.
if (SigType==CTRL_LOGOFF_EVENT)
return TRUE;
#endif
ErrHandler.UserBreak=true;
mprintf(St(MBreak));
#ifdef _WIN_ALL
// Let the main thread to handle 'throw' and destroy file objects.
for (uint I=0;!ErrHandler.MainExit && I<50;I++)
Sleep(100);
#if defined(USE_RC) && !defined(SFX_MODULE) && !defined(RARDLL)
ExtRes.UnloadDLL();
#endif
exit(RARX_USERBREAK);
#endif
#ifdef _UNIX
static uint BreakCount=0;
// User continues to press Ctrl+C, exit immediately without cleanup.
if (++BreakCount>1)
exit(RARX_USERBREAK);
// Otherwise return from signal handler and let Wait() function to close
// files and quit. We cannot use the same approach as in Windows,
// because Unix signal handler can block execution of our main code.
#endif
#if defined(_WIN_ALL) && !defined(_MSC_VER)
// never reached, just to avoid a compiler warning
return TRUE;
#endif
}
void ErrorHandler::SetSignalHandlers(bool Enable)
{
EnableBreak=Enable;
#ifdef _WIN_ALL
SetConsoleCtrlHandler(Enable ? ProcessSignal:NULL,TRUE);
#else
signal(SIGINT,Enable ? ProcessSignal:SIG_IGN);
signal(SIGTERM,Enable ? ProcessSignal:SIG_IGN);
#endif
}
void ErrorHandler::Throw(RAR_EXIT Code)
{
if (Code==RARX_USERBREAK && !EnableBreak)
return;
#if !defined(SILENT)
// Do not write "aborted" when just displaying online help.
if (Code!=RARX_SUCCESS && Code!=RARX_USERERROR)
mprintf(L"\n%s\n",St(MProgAborted));
#endif
SetErrorCode(Code);
throw Code;
}
void ErrorHandler::SysErrMsg()
{
#if !defined(SFX_MODULE) && !defined(SILENT)
#ifdef _WIN_ALL
wchar *lpMsgBuf=NULL;
int ErrType=GetLastError();
if (ErrType!=0 && FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
NULL,ErrType,MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&lpMsgBuf,0,NULL))
{
wchar *CurMsg=lpMsgBuf;
while (CurMsg!=NULL)
{
while (*CurMsg=='\r' || *CurMsg=='\n')
CurMsg++;
if (*CurMsg==0)
break;
wchar *EndMsg=wcschr(CurMsg,'\r');
if (EndMsg==NULL)
EndMsg=wcschr(CurMsg,'\n');
if (EndMsg!=NULL)
{
*EndMsg=0;
EndMsg++;
}
uiMsg(UIERROR_SYSERRMSG,CurMsg);
CurMsg=EndMsg;
}
}
LocalFree( lpMsgBuf );
#endif
#if defined(_UNIX) || defined(_EMX)
if (errno!=0)
{
char *err=strerror(errno);
if (err!=NULL)
{
wchar Msg[1024];
CharToWide(err,Msg,ASIZE(Msg));
uiMsg(UIERROR_SYSERRMSG,Msg);
}
}
#endif
#endif
}
int ErrorHandler::GetSystemErrorCode()
{
#ifdef _WIN_ALL
return GetLastError();
#else
return errno;
#endif
}
void ErrorHandler::SetSystemErrorCode(int Code)
{
#ifdef _WIN_ALL
SetLastError(Code);
#else
errno=Code;
#endif
}

View File

@@ -0,0 +1,70 @@
#ifndef _RAR_ERRHANDLER_
#define _RAR_ERRHANDLER_
enum RAR_EXIT // RAR exit code.
{
RARX_SUCCESS = 0,
RARX_WARNING = 1,
RARX_FATAL = 2,
RARX_CRC = 3,
RARX_LOCK = 4,
RARX_WRITE = 5,
RARX_OPEN = 6,
RARX_USERERROR = 7,
RARX_MEMORY = 8,
RARX_CREATE = 9,
RARX_NOFILES = 10,
RARX_BADPWD = 11,
RARX_USERBREAK = 255
};
class ErrorHandler
{
private:
RAR_EXIT ExitCode;
uint ErrCount;
bool EnableBreak;
bool Silent;
bool DisableShutdown; // Shutdown is not suitable after last error.
public:
ErrorHandler();
void Clean();
void MemoryError();
void OpenError(const wchar *FileName);
void CloseError(const wchar *FileName);
void ReadError(const wchar *FileName);
bool AskRepeatRead(const wchar *FileName);
void WriteError(const wchar *ArcName,const wchar *FileName);
void WriteErrorFAT(const wchar *FileName);
bool AskRepeatWrite(const wchar *FileName,bool DiskFull);
void SeekError(const wchar *FileName);
void GeneralErrMsg(const wchar *fmt,...);
void MemoryErrorMsg();
void OpenErrorMsg(const wchar *FileName);
void OpenErrorMsg(const wchar *ArcName,const wchar *FileName);
void CreateErrorMsg(const wchar *FileName);
void CreateErrorMsg(const wchar *ArcName,const wchar *FileName);
void ReadErrorMsg(const wchar *FileName);
void ReadErrorMsg(const wchar *ArcName,const wchar *FileName);
void WriteErrorMsg(const wchar *ArcName,const wchar *FileName);
void ArcBrokenMsg(const wchar *ArcName);
void ChecksumFailedMsg(const wchar *ArcName,const wchar *FileName);
void UnknownMethodMsg(const wchar *ArcName,const wchar *FileName);
void Exit(RAR_EXIT ExitCode);
void SetErrorCode(RAR_EXIT Code);
RAR_EXIT GetErrorCode() {return ExitCode;}
uint GetErrorCount() {return ErrCount;}
void SetSignalHandlers(bool Enable);
void Throw(RAR_EXIT Code);
void SetSilent(bool Mode) {Silent=Mode;};
void SysErrMsg();
int GetSystemErrorCode();
void SetSystemErrorCode(int Code);
bool IsShutdownEnabled() {return !DisableShutdown;}
bool UserBreak; // Ctrl+Break is pressed.
bool MainExit; // main() is completed.
};
#endif

178
reference/unrar/extinfo.cpp Normal file
View File

@@ -0,0 +1,178 @@
#include "rar.hpp"
#include "hardlinks.cpp"
#include "win32stm.cpp"
#ifdef _WIN_ALL
#include "win32acl.cpp"
#include "win32lnk.cpp"
#endif
#ifdef _UNIX
#include "uowners.cpp"
#ifdef SAVE_LINKS
#include "ulinks.cpp"
#endif
#endif
// RAR2 service header extra records.
#ifndef SFX_MODULE
void SetExtraInfo20(CommandData *Cmd,Archive &Arc,wchar *Name)
{
if (Cmd->Test)
return;
switch(Arc.SubBlockHead.SubType)
{
#ifdef _UNIX
case UO_HEAD:
if (Cmd->ProcessOwners)
ExtractUnixOwner20(Arc,Name);
break;
#endif
#ifdef _WIN_ALL
case NTACL_HEAD:
if (Cmd->ProcessOwners)
ExtractACL20(Arc,Name);
break;
case STREAM_HEAD:
ExtractStreams20(Arc,Name);
break;
#endif
}
}
#endif
// RAR3 and RAR5 service header extra records.
void SetExtraInfo(CommandData *Cmd,Archive &Arc,wchar *Name)
{
#ifdef _UNIX
if (!Cmd->Test && Cmd->ProcessOwners && Arc.Format==RARFMT15 &&
Arc.SubHead.CmpName(SUBHEAD_TYPE_UOWNER))
ExtractUnixOwner30(Arc,Name);
#endif
#ifdef _WIN_ALL
if (!Cmd->Test && Cmd->ProcessOwners && Arc.SubHead.CmpName(SUBHEAD_TYPE_ACL))
ExtractACL(Arc,Name);
if (Arc.SubHead.CmpName(SUBHEAD_TYPE_STREAM))
ExtractStreams(Arc,Name,Cmd->Test);
#endif
}
// Extra data stored directly in file header.
void SetFileHeaderExtra(CommandData *Cmd,Archive &Arc,wchar *Name)
{
#ifdef _UNIX
if (Cmd->ProcessOwners && Arc.Format==RARFMT50 && Arc.FileHead.UnixOwnerSet)
SetUnixOwner(Arc,Name);
#endif
}
// Calculate a number of path components except \. and \..
static int CalcAllowedDepth(const wchar *Name)
{
int AllowedDepth=0;
while (*Name!=0)
{
if (IsPathDiv(Name[0]) && Name[1]!=0 && !IsPathDiv(Name[1]))
{
bool Dot=Name[1]=='.' && (IsPathDiv(Name[2]) || Name[2]==0);
bool Dot2=Name[1]=='.' && Name[2]=='.' && (IsPathDiv(Name[3]) || Name[3]==0);
if (!Dot && !Dot2)
AllowedDepth++;
}
Name++;
}
return AllowedDepth;
}
// Check if all existing path components are directories and not links.
static bool LinkInPath(const wchar *Name)
{
wchar Path[NM];
if (wcslen(Name)>=ASIZE(Path))
return true; // It should not be that long, skip.
wcsncpyz(Path,Name,ASIZE(Path));
for (wchar *s=Path+wcslen(Path)-1;s>Path;s--)
if (IsPathDiv(*s))
{
*s=0;
FindData FD;
if (FindFile::FastFind(Path,&FD,true) && (FD.IsLink || !FD.IsDir))
return true;
}
return false;
}
bool IsRelativeSymlinkSafe(CommandData *Cmd,const wchar *SrcName,const wchar *PrepSrcName,const wchar *TargetName)
{
// Catch root dir based /path/file paths also as stuff like \\?\.
// Do not check PrepSrcName here, it can be root based if destination path
// is a root based.
if (IsFullRootPath(SrcName) || IsFullRootPath(TargetName))
return false;
// Number of ".." in link target.
int UpLevels=0;
for (int Pos=0;*TargetName!=0;Pos++)
{
bool Dot2=TargetName[0]=='.' && TargetName[1]=='.' &&
(IsPathDiv(TargetName[2]) || TargetName[2]==0) &&
(Pos==0 || IsPathDiv(*(TargetName-1)));
if (Dot2)
UpLevels++;
TargetName++;
}
// If link target includes "..", it must not have another links
// in the path, because they can bypass our safety check. For example,
// suppose we extracted "lnk1" -> "." first and "lnk1/lnk2" -> ".." next
// or "dir/lnk1" -> ".." first and "dir/lnk1/lnk2" -> ".." next.
if (UpLevels>0 && LinkInPath(PrepSrcName))
return false;
// We could check just prepared src name, but for extra safety
// we check both original (as from archive header) and prepared
// (after applying the destination path and -ep switches) names.
int AllowedDepth=CalcAllowedDepth(SrcName); // Original name depth.
// Remove the destination path from prepared name if any. We should not
// count the destination path depth, because the link target must point
// inside of this path, not outside of it.
size_t ExtrPathLength=wcslen(Cmd->ExtrPath);
if (ExtrPathLength>0 && wcsncmp(PrepSrcName,Cmd->ExtrPath,ExtrPathLength)==0)
{
PrepSrcName+=ExtrPathLength;
while (IsPathDiv(*PrepSrcName))
PrepSrcName++;
}
int PrepAllowedDepth=CalcAllowedDepth(PrepSrcName);
return AllowedDepth>=UpLevels && PrepAllowedDepth>=UpLevels;
}
bool ExtractSymlink(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc,const wchar *LinkName)
{
#if defined(SAVE_LINKS) && defined(_UNIX)
// For RAR 3.x archives we process links even in test mode to skip link data.
if (Arc.Format==RARFMT15)
return ExtractUnixLink30(Cmd,DataIO,Arc,LinkName);
if (Arc.Format==RARFMT50)
return ExtractUnixLink50(Cmd,LinkName,&Arc.FileHead);
#elif defined _WIN_ALL
// RAR 5.0 archives store link information in file header, so there is
// no need to additionally test it if we do not create a file.
if (Arc.Format==RARFMT50)
return CreateReparsePoint(Cmd,LinkName,&Arc.FileHead);
#endif
return false;
}

View File

@@ -0,0 +1,23 @@
#ifndef _RAR_EXTINFO_
#define _RAR_EXTINFO_
bool IsRelativeSymlinkSafe(CommandData *Cmd,const wchar *SrcName,const wchar *PrepSrcName,const wchar *TargetName);
bool ExtractSymlink(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc,const wchar *LinkName);
#ifdef _UNIX
void SetUnixOwner(Archive &Arc,const wchar *FileName);
#endif
bool ExtractHardlink(wchar *NameNew,wchar *NameExisting,size_t NameExistingSize);
void GetStreamNameNTFS(Archive &Arc,wchar *StreamName,size_t MaxSize);
#ifdef _WIN_ALL
bool SetPrivilege(LPCTSTR PrivName);
#endif
void SetExtraInfo20(CommandData *Cmd,Archive &Arc,wchar *Name);
void SetExtraInfo(CommandData *Cmd,Archive &Arc,wchar *Name);
void SetFileHeaderExtra(CommandData *Cmd,Archive &Arc,wchar *Name);
#endif

1167
reference/unrar/extract.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,62 @@
#ifndef _RAR_EXTRACT_
#define _RAR_EXTRACT_
enum EXTRACT_ARC_CODE {EXTRACT_ARC_NEXT,EXTRACT_ARC_REPEAT};
class CmdExtract
{
private:
EXTRACT_ARC_CODE ExtractArchive();
bool ExtractFileCopy(File &New,wchar *ArcName,wchar *NameNew,wchar *NameExisting,size_t NameExistingSize);
void ExtrPrepareName(Archive &Arc,const wchar *ArcFileName,wchar *DestName,size_t DestSize);
#ifdef RARDLL
bool ExtrDllGetPassword();
#else
bool ExtrGetPassword(Archive &Arc,const wchar *ArcFileName);
#endif
#if defined(_WIN_ALL) && !defined(SFX_MODULE)
void ConvertDosPassword(Archive &Arc,SecPassword &DestPwd);
#endif
void ExtrCreateDir(Archive &Arc,const wchar *ArcFileName);
bool ExtrCreateFile(Archive &Arc,File &CurFile);
bool CheckUnpVer(Archive &Arc,const wchar *ArcFileName);
RarTime StartTime; // time when extraction started
CommandData *Cmd;
ComprDataIO DataIO;
Unpack *Unp;
unsigned long TotalFileCount;
unsigned long FileCount;
unsigned long MatchedArgs;
bool FirstFile;
bool AllMatchesExact;
bool ReconstructDone;
// If any non-zero solid file was successfully unpacked before current.
// If true and if current encrypted file is broken, obviously
// the password is correct and we can report broken CRC without
// any wrong password hints.
bool AnySolidDataUnpackedWell;
wchar ArcName[NM];
bool PasswordAll;
bool PrevProcessed; // If previous file was successfully extracted or tested.
wchar DestFileName[NM];
bool PasswordCancelled;
#if defined(_WIN_ALL) && !defined(SFX_MODULE) && !defined(SILENT)
bool Fat32,NotFat32;
#endif
public:
CmdExtract(CommandData *Cmd);
~CmdExtract();
void DoExtract();
void ExtractArchiveInit(Archive &Arc);
bool ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat);
static void UnstoreFile(ComprDataIO &DataIO,int64 DestUnpSize);
};
#endif

View File

@@ -0,0 +1,163 @@
#include "rar.hpp"
// If NewFile==NULL, we delete created file after user confirmation.
// It is useful we we need to overwrite an existing folder or file,
// but need user confirmation for that.
bool FileCreate(RAROptions *Cmd,File *NewFile,wchar *Name,size_t MaxNameSize,
bool *UserReject,int64 FileSize,RarTime *FileTime,bool WriteOnly)
{
if (UserReject!=NULL)
*UserReject=false;
#ifdef _WIN_ALL
bool ShortNameChanged=false;
#endif
while (FileExist(Name))
{
#if defined(_WIN_ALL)
if (!ShortNameChanged)
{
// Avoid the infinite loop if UpdateExistingShortName returns
// the same name.
ShortNameChanged=true;
// Maybe our long name matches the short name of existing file.
// Let's check if we can change the short name.
if (UpdateExistingShortName(Name))
continue;
}
// Allow short name check again. It is necessary, because rename and
// autorename below can change the name, so we need to check it again.
ShortNameChanged=false;
#endif
UIASKREP_RESULT Choice=uiAskReplaceEx(Cmd,Name,MaxNameSize,FileSize,FileTime,(NewFile==NULL ? UIASKREP_F_NORENAME:0));
if (Choice==UIASKREP_R_REPLACE)
break;
if (Choice==UIASKREP_R_SKIP)
{
if (UserReject!=NULL)
*UserReject=true;
return false;
}
if (Choice==UIASKREP_R_CANCEL)
ErrHandler.Exit(RARX_USERBREAK);
}
// Try to truncate the existing file first instead of delete,
// so we preserve existing file permissions such as NTFS permissions.
uint FileMode=WriteOnly ? FMF_WRITE|FMF_SHAREREAD:FMF_UPDATE|FMF_SHAREREAD;
if (NewFile!=NULL && NewFile->Create(Name,FileMode))
return true;
CreatePath(Name,true);
return NewFile!=NULL ? NewFile->Create(Name,FileMode):DelFile(Name);
}
bool GetAutoRenamedName(wchar *Name,size_t MaxNameSize)
{
wchar NewName[NM];
size_t NameLength=wcslen(Name);
wchar *Ext=GetExt(Name);
if (Ext==NULL)
Ext=Name+NameLength;
for (uint FileVer=1;;FileVer++)
{
swprintf(NewName,ASIZE(NewName),L"%.*ls(%u)%ls",uint(Ext-Name),Name,FileVer,Ext);
if (!FileExist(NewName))
{
wcsncpyz(Name,NewName,MaxNameSize);
break;
}
if (FileVer>=1000000)
return false;
}
return true;
}
#if defined(_WIN_ALL)
// If we find a file, which short name is equal to 'Name', we try to change
// its short name, while preserving the long name. It helps when unpacking
// an archived file, which long name is equal to short name of already
// existing file. Otherwise we would overwrite the already existing file,
// even though its long name does not match the name of unpacking file.
bool UpdateExistingShortName(const wchar *Name)
{
wchar LongPathName[NM];
DWORD Res=GetLongPathName(Name,LongPathName,ASIZE(LongPathName));
if (Res==0 || Res>=ASIZE(LongPathName))
return false;
wchar ShortPathName[NM];
Res=GetShortPathName(Name,ShortPathName,ASIZE(ShortPathName));
if (Res==0 || Res>=ASIZE(ShortPathName))
return false;
wchar *LongName=PointToName(LongPathName);
wchar *ShortName=PointToName(ShortPathName);
// We continue only if file has a short name, which does not match its
// long name, and this short name is equal to name of file which we need
// to create.
if (*ShortName==0 || wcsicomp(LongName,ShortName)==0 ||
wcsicomp(PointToName(Name),ShortName)!=0)
return false;
// Generate the temporary new name for existing file.
wchar NewName[NM];
*NewName=0;
for (int I=0;I<10000 && *NewName==0;I+=123)
{
// Here we copy the path part of file to create. We'll make the temporary
// file in the same folder.
wcsncpyz(NewName,Name,ASIZE(NewName));
// Here we set the random name part.
swprintf(PointToName(NewName),ASIZE(NewName),L"rtmp%d",I);
// If such file is already exist, try next random name.
if (FileExist(NewName))
*NewName=0;
}
// If we could not generate the name not used by any other file, we return.
if (*NewName==0)
return false;
// FastFind returns the name without path, but we need the fully qualified
// name for renaming, so we use the path from file to create and long name
// from existing file.
wchar FullName[NM];
wcsncpyz(FullName,Name,ASIZE(FullName));
SetName(FullName,LongName,ASIZE(FullName));
// Rename the existing file to randomly generated name. Normally it changes
// the short name too.
if (!MoveFile(FullName,NewName))
return false;
// Now we need to create the temporary empty file with same name as
// short name of our already existing file. We do it to occupy its previous
// short name and not allow to use it again when renaming the file back to
// its original long name.
File KeepShortFile;
bool Created=false;
if (!FileExist(Name))
Created=KeepShortFile.Create(Name,FMF_WRITE|FMF_SHAREREAD);
// Now we rename the existing file from temporary name to original long name.
// Since its previous short name is occupied by another file, it should
// get another short name.
MoveFile(NewName,FullName);
if (Created)
{
// Delete the temporary zero length file occupying the short name,
KeepShortFile.Close();
KeepShortFile.Delete();
}
// We successfully changed the short name. Maybe sometimes we'll simplify
// this function by use of SetFileShortName Windows API call.
// But SetFileShortName is not available in older Windows.
return true;
}
#endif

View File

@@ -0,0 +1,14 @@
#ifndef _RAR_FILECREATE_
#define _RAR_FILECREATE_
bool FileCreate(RAROptions *Cmd,File *NewFile,wchar *Name,size_t MaxNameSize,
bool *UserReject,int64 FileSize=INT64NDF,
RarTime *FileTime=NULL,bool WriteOnly=false);
bool GetAutoRenamedName(wchar *Name,size_t MaxNameSize);
#if defined(_WIN_ALL)
bool UpdateExistingShortName(const wchar *Name);
#endif
#endif

729
reference/unrar/file.cpp Normal file
View File

@@ -0,0 +1,729 @@
#include "rar.hpp"
File::File()
{
hFile=FILE_BAD_HANDLE;
*FileName=0;
NewFile=false;
LastWrite=false;
HandleType=FILE_HANDLENORMAL;
SkipClose=false;
IgnoreReadErrors=false;
ErrorType=FILE_SUCCESS;
OpenShared=false;
AllowDelete=true;
AllowExceptions=true;
#ifdef _WIN_ALL
NoSequentialRead=false;
CreateMode=FMF_UNDEFINED;
#endif
}
File::~File()
{
if (hFile!=FILE_BAD_HANDLE && !SkipClose)
if (NewFile)
Delete();
else
Close();
}
void File::operator = (File &SrcFile)
{
hFile=SrcFile.hFile;
NewFile=SrcFile.NewFile;
LastWrite=SrcFile.LastWrite;
HandleType=SrcFile.HandleType;
wcsncpyz(FileName,SrcFile.FileName,ASIZE(FileName));
SrcFile.SkipClose=true;
}
bool File::Open(const wchar *Name,uint Mode)
{
ErrorType=FILE_SUCCESS;
FileHandle hNewFile;
bool OpenShared=File::OpenShared || (Mode & FMF_OPENSHARED)!=0;
bool UpdateMode=(Mode & FMF_UPDATE)!=0;
bool WriteMode=(Mode & FMF_WRITE)!=0;
#ifdef _WIN_ALL
uint Access=WriteMode ? GENERIC_WRITE:GENERIC_READ;
if (UpdateMode)
Access|=GENERIC_WRITE;
uint ShareMode=(Mode & FMF_OPENEXCLUSIVE) ? 0 : FILE_SHARE_READ;
if (OpenShared)
ShareMode|=FILE_SHARE_WRITE;
uint Flags=NoSequentialRead ? 0:FILE_FLAG_SEQUENTIAL_SCAN;
hNewFile=CreateFile(Name,Access,ShareMode,NULL,OPEN_EXISTING,Flags,NULL);
DWORD LastError;
if (hNewFile==FILE_BAD_HANDLE)
{
LastError=GetLastError();
wchar LongName[NM];
if (GetWinLongPath(Name,LongName,ASIZE(LongName)))
{
hNewFile=CreateFile(LongName,Access,ShareMode,NULL,OPEN_EXISTING,Flags,NULL);
// For archive names longer than 260 characters first CreateFile
// (without \\?\) fails and sets LastError to 3 (access denied).
// We need the correct "file not found" error code to decide
// if we create a new archive or quit with "cannot create" error.
// So we need to check the error code after \\?\ CreateFile again,
// otherwise we'll fail to create new archives with long names.
// But we cannot simply assign the new code to LastError,
// because it would break "..\arcname.rar" relative names processing.
// First CreateFile returns the correct "file not found" code for such
// names, but "\\?\" CreateFile returns ERROR_INVALID_NAME treating
// dots as a directory name. So we check only for "file not found"
// error here and for other errors use the first CreateFile result.
if (GetLastError()==ERROR_FILE_NOT_FOUND)
LastError=ERROR_FILE_NOT_FOUND;
}
}
if (hNewFile==FILE_BAD_HANDLE && LastError==ERROR_FILE_NOT_FOUND)
ErrorType=FILE_NOTFOUND;
#else
int flags=UpdateMode ? O_RDWR:(WriteMode ? O_WRONLY:O_RDONLY);
#ifdef O_BINARY
flags|=O_BINARY;
#if defined(_AIX) && defined(_LARGE_FILE_API)
flags|=O_LARGEFILE;
#endif
#endif
char NameA[NM];
WideToChar(Name,NameA,ASIZE(NameA));
int handle=open(NameA,flags);
#ifdef LOCK_EX
#ifdef _OSF_SOURCE
extern "C" int flock(int, int);
#endif
if (!OpenShared && UpdateMode && handle>=0 && flock(handle,LOCK_EX|LOCK_NB)==-1)
{
close(handle);
return false;
}
#endif
if (handle==-1)
hNewFile=FILE_BAD_HANDLE;
else
{
#ifdef FILE_USE_OPEN
hNewFile=handle;
#else
hNewFile=fdopen(handle,UpdateMode ? UPDATEBINARY:READBINARY);
#endif
}
if (hNewFile==FILE_BAD_HANDLE && errno==ENOENT)
ErrorType=FILE_NOTFOUND;
#endif
NewFile=false;
HandleType=FILE_HANDLENORMAL;
SkipClose=false;
bool Success=hNewFile!=FILE_BAD_HANDLE;
if (Success)
{
hFile=hNewFile;
wcsncpyz(FileName,Name,ASIZE(FileName));
}
return Success;
}
#if !defined(SFX_MODULE)
void File::TOpen(const wchar *Name)
{
if (!WOpen(Name))
ErrHandler.Exit(RARX_OPEN);
}
#endif
bool File::WOpen(const wchar *Name)
{
if (Open(Name))
return true;
ErrHandler.OpenErrorMsg(Name);
return false;
}
bool File::Create(const wchar *Name,uint Mode)
{
// OpenIndiana based NAS and CIFS shares fail to set the file time if file
// was created in read+write mode and some data was written and not flushed
// before SetFileTime call. So we should use the write only mode if we plan
// SetFileTime call and do not need to read from file.
bool WriteMode=(Mode & FMF_WRITE)!=0;
bool ShareRead=(Mode & FMF_SHAREREAD)!=0 || File::OpenShared;
#ifdef _WIN_ALL
CreateMode=Mode;
uint Access=WriteMode ? GENERIC_WRITE:GENERIC_READ|GENERIC_WRITE;
DWORD ShareMode=ShareRead ? FILE_SHARE_READ:0;
// Windows automatically removes dots and spaces in the end of file name,
// So we detect such names and process them with \\?\ prefix.
wchar *LastChar=PointToLastChar(Name);
bool Special=*LastChar=='.' || *LastChar==' ';
if (Special && (Mode & FMF_STANDARDNAMES)==0)
hFile=FILE_BAD_HANDLE;
else
hFile=CreateFile(Name,Access,ShareMode,NULL,CREATE_ALWAYS,0,NULL);
if (hFile==FILE_BAD_HANDLE)
{
wchar LongName[NM];
if (GetWinLongPath(Name,LongName,ASIZE(LongName)))
hFile=CreateFile(LongName,Access,ShareMode,NULL,CREATE_ALWAYS,0,NULL);
}
#else
char NameA[NM];
WideToChar(Name,NameA,ASIZE(NameA));
#ifdef FILE_USE_OPEN
hFile=open(NameA,(O_CREAT|O_TRUNC) | (WriteMode ? O_WRONLY : O_RDWR),0666);
#else
hFile=fopen(NameA,WriteMode ? WRITEBINARY:CREATEBINARY);
#endif
#endif
NewFile=true;
HandleType=FILE_HANDLENORMAL;
SkipClose=false;
wcsncpyz(FileName,Name,ASIZE(FileName));
return hFile!=FILE_BAD_HANDLE;
}
#if !defined(SFX_MODULE)
void File::TCreate(const wchar *Name,uint Mode)
{
if (!WCreate(Name,Mode))
ErrHandler.Exit(RARX_FATAL);
}
#endif
bool File::WCreate(const wchar *Name,uint Mode)
{
if (Create(Name,Mode))
return true;
ErrHandler.CreateErrorMsg(Name);
return false;
}
bool File::Close()
{
bool Success=true;
if (hFile!=FILE_BAD_HANDLE)
{
if (!SkipClose)
{
#ifdef _WIN_ALL
// We use the standard system handle for stdout in Windows
// and it must not be closed here.
if (HandleType==FILE_HANDLENORMAL)
Success=CloseHandle(hFile)==TRUE;
#else
#ifdef FILE_USE_OPEN
Success=close(hFile)!=-1;
#else
Success=fclose(hFile)!=EOF;
#endif
#endif
}
hFile=FILE_BAD_HANDLE;
}
HandleType=FILE_HANDLENORMAL;
if (!Success && AllowExceptions)
ErrHandler.CloseError(FileName);
return Success;
}
bool File::Delete()
{
if (HandleType!=FILE_HANDLENORMAL)
return false;
if (hFile!=FILE_BAD_HANDLE)
Close();
if (!AllowDelete)
return false;
return DelFile(FileName);
}
bool File::Rename(const wchar *NewName)
{
// No need to rename if names are already same.
bool Success=wcscmp(FileName,NewName)==0;
if (!Success)
Success=RenameFile(FileName,NewName);
if (Success)
wcscpy(FileName,NewName);
return Success;
}
bool File::Write(const void *Data,size_t Size)
{
if (Size==0)
return true;
if (HandleType==FILE_HANDLESTD)
{
#ifdef _WIN_ALL
hFile=GetStdHandle(STD_OUTPUT_HANDLE);
#else
// Cannot use the standard stdout here, because it already has wide orientation.
if (hFile==FILE_BAD_HANDLE)
{
#ifdef FILE_USE_OPEN
hFile=dup(STDOUT_FILENO); // Open new stdout stream.
#else
hFile=fdopen(dup(STDOUT_FILENO),"w"); // Open new stdout stream.
#endif
}
#endif
}
bool Success;
while (1)
{
Success=false;
#ifdef _WIN_ALL
DWORD Written=0;
if (HandleType!=FILE_HANDLENORMAL)
{
// writing to stdout can fail in old Windows if data block is too large
const size_t MaxSize=0x4000;
for (size_t I=0;I<Size;I+=MaxSize)
{
Success=WriteFile(hFile,(byte *)Data+I,(DWORD)Min(Size-I,MaxSize),&Written,NULL)==TRUE;
if (!Success)
break;
}
}
else
Success=WriteFile(hFile,Data,(DWORD)Size,&Written,NULL)==TRUE;
#else
#ifdef FILE_USE_OPEN
ssize_t Written=write(hFile,Data,Size);
Success=Written==Size;
#else
int Written=fwrite(Data,1,Size,hFile);
Success=Written==Size && !ferror(hFile);
#endif
#endif
if (!Success && AllowExceptions && HandleType==FILE_HANDLENORMAL)
{
#if defined(_WIN_ALL) && !defined(SFX_MODULE) && !defined(RARDLL)
int ErrCode=GetLastError();
int64 FilePos=Tell();
uint64 FreeSize=GetFreeDisk(FileName);
SetLastError(ErrCode);
if (FreeSize>Size && FilePos-Size<=0xffffffff && FilePos+Size>0xffffffff)
ErrHandler.WriteErrorFAT(FileName);
#endif
if (ErrHandler.AskRepeatWrite(FileName,false))
{
#if !defined(_WIN_ALL) && !defined(FILE_USE_OPEN)
clearerr(hFile);
#endif
if (Written<Size && Written>0)
Seek(Tell()-Written,SEEK_SET);
continue;
}
ErrHandler.WriteError(NULL,FileName);
}
break;
}
LastWrite=true;
return Success; // It can return false only if AllowExceptions is disabled.
}
int File::Read(void *Data,size_t Size)
{
int64 FilePos=0; // Initialized only to suppress some compilers warning.
if (IgnoreReadErrors)
FilePos=Tell();
int ReadSize;
while (true)
{
ReadSize=DirectRead(Data,Size);
if (ReadSize==-1)
{
ErrorType=FILE_READERROR;
if (AllowExceptions)
if (IgnoreReadErrors)
{
ReadSize=0;
for (size_t I=0;I<Size;I+=512)
{
Seek(FilePos+I,SEEK_SET);
size_t SizeToRead=Min(Size-I,512);
int ReadCode=DirectRead(Data,SizeToRead);
ReadSize+=(ReadCode==-1) ? 512:ReadCode;
}
}
else
{
if (HandleType==FILE_HANDLENORMAL && ErrHandler.AskRepeatRead(FileName))
continue;
ErrHandler.ReadError(FileName);
}
}
break;
}
return ReadSize;
}
// Returns -1 in case of error.
int File::DirectRead(void *Data,size_t Size)
{
#ifdef _WIN_ALL
const size_t MaxDeviceRead=20000;
const size_t MaxLockedRead=32768;
#endif
if (HandleType==FILE_HANDLESTD)
{
#ifdef _WIN_ALL
// if (Size>MaxDeviceRead)
// Size=MaxDeviceRead;
hFile=GetStdHandle(STD_INPUT_HANDLE);
#else
#ifdef FILE_USE_OPEN
hFile=STDIN_FILENO;
#else
hFile=stdin;
#endif
#endif
}
#ifdef _WIN_ALL
// For pipes like 'type file.txt | rar -si arcname' ReadFile may return
// data in small ~4KB blocks. It may slightly reduce the compression ratio.
DWORD Read;
if (!ReadFile(hFile,Data,(DWORD)Size,&Read,NULL))
{
if (IsDevice() && Size>MaxDeviceRead)
return DirectRead(Data,MaxDeviceRead);
if (HandleType==FILE_HANDLESTD && GetLastError()==ERROR_BROKEN_PIPE)
return 0;
// We had a bug report about failure to archive 1C database lock file
// 1Cv8tmp.1CL, which is a zero length file with a region above 200 KB
// permanently locked. If our first read request uses too large buffer
// and if we are in -dh mode, so we were able to open the file,
// we'll fail with "Read error". So now we use try a smaller buffer size
// in case of lock error.
if (HandleType==FILE_HANDLENORMAL && Size>MaxLockedRead &&
GetLastError()==ERROR_LOCK_VIOLATION)
return DirectRead(Data,MaxLockedRead);
return -1;
}
return Read;
#else
#ifdef FILE_USE_OPEN
ssize_t ReadSize=read(hFile,Data,Size);
if (ReadSize==-1)
return -1;
return (int)ReadSize;
#else
if (LastWrite)
{
fflush(hFile);
LastWrite=false;
}
clearerr(hFile);
size_t ReadSize=fread(Data,1,Size,hFile);
if (ferror(hFile))
return -1;
return (int)ReadSize;
#endif
#endif
}
void File::Seek(int64 Offset,int Method)
{
if (!RawSeek(Offset,Method) && AllowExceptions)
ErrHandler.SeekError(FileName);
}
bool File::RawSeek(int64 Offset,int Method)
{
if (hFile==FILE_BAD_HANDLE)
return true;
if (Offset<0 && Method!=SEEK_SET)
{
Offset=(Method==SEEK_CUR ? Tell():FileLength())+Offset;
Method=SEEK_SET;
}
#ifdef _WIN_ALL
LONG HighDist=(LONG)(Offset>>32);
if (SetFilePointer(hFile,(LONG)Offset,&HighDist,Method)==0xffffffff &&
GetLastError()!=NO_ERROR)
return false;
#else
LastWrite=false;
#ifdef FILE_USE_OPEN
if (lseek(hFile,(off_t)Offset,Method)==-1)
return false;
#elif defined(_LARGEFILE_SOURCE) && !defined(_OSF_SOURCE) && !defined(__VMS)
if (fseeko(hFile,Offset,Method)!=0)
return false;
#else
if (fseek(hFile,(long)Offset,Method)!=0)
return false;
#endif
#endif
return true;
}
int64 File::Tell()
{
if (hFile==FILE_BAD_HANDLE)
if (AllowExceptions)
ErrHandler.SeekError(FileName);
else
return -1;
#ifdef _WIN_ALL
LONG HighDist=0;
uint LowDist=SetFilePointer(hFile,0,&HighDist,FILE_CURRENT);
if (LowDist==0xffffffff && GetLastError()!=NO_ERROR)
if (AllowExceptions)
ErrHandler.SeekError(FileName);
else
return -1;
return INT32TO64(HighDist,LowDist);
#else
#ifdef FILE_USE_OPEN
return lseek(hFile,0,SEEK_CUR);
#elif defined(_LARGEFILE_SOURCE) && !defined(_OSF_SOURCE)
return ftello(hFile);
#else
return ftell(hFile);
#endif
#endif
}
void File::Prealloc(int64 Size)
{
#ifdef _WIN_ALL
if (RawSeek(Size,SEEK_SET))
{
Truncate();
Seek(0,SEEK_SET);
}
#endif
#if defined(_UNIX) && defined(USE_FALLOCATE)
// fallocate is rather new call. Only latest kernels support it.
// So we are not using it by default yet.
int fd = GetFD();
if (fd >= 0)
fallocate(fd, 0, 0, Size);
#endif
}
byte File::GetByte()
{
byte Byte=0;
Read(&Byte,1);
return Byte;
}
void File::PutByte(byte Byte)
{
Write(&Byte,1);
}
bool File::Truncate()
{
#ifdef _WIN_ALL
return SetEndOfFile(hFile)==TRUE;
#else
return ftruncate(GetFD(),(off_t)Tell())==0;
#endif
}
void File::Flush()
{
#ifdef _WIN_ALL
FlushFileBuffers(hFile);
#else
#ifndef FILE_USE_OPEN
fflush(hFile);
#endif
fsync(GetFD());
#endif
}
void File::SetOpenFileTime(RarTime *ftm,RarTime *ftc,RarTime *fta)
{
#ifdef _WIN_ALL
// Workaround for OpenIndiana NAS time bug. If we cannot create a file
// in write only mode, we need to flush the write buffer before calling
// SetFileTime or file time will not be changed.
if (CreateMode!=FMF_UNDEFINED && (CreateMode & FMF_WRITE)==0)
FlushFileBuffers(hFile);
bool sm=ftm!=NULL && ftm->IsSet();
bool sc=ftc!=NULL && ftc->IsSet();
bool sa=fta!=NULL && fta->IsSet();
FILETIME fm,fc,fa;
if (sm)
ftm->GetWinFT(&fm);
if (sc)
ftc->GetWinFT(&fc);
if (sa)
fta->GetWinFT(&fa);
SetFileTime(hFile,sc ? &fc:NULL,sa ? &fa:NULL,sm ? &fm:NULL);
#endif
}
void File::SetCloseFileTime(RarTime *ftm,RarTime *fta)
{
// Android APP_PLATFORM := android-14 does not support futimens and futimes.
// Newer platforms support futimens, but fail on Android 4.2.
// We have to use utime for Android.
// Also we noticed futimens fail to set timestamps on NTFS partition
// mounted to virtual Linux x86 machine, but utimensat worked correctly.
// So we set timestamps for already closed files in Unix.
#ifdef _UNIX
SetCloseFileTimeByName(FileName,ftm,fta);
#endif
}
void File::SetCloseFileTimeByName(const wchar *Name,RarTime *ftm,RarTime *fta)
{
#ifdef _UNIX
bool setm=ftm!=NULL && ftm->IsSet();
bool seta=fta!=NULL && fta->IsSet();
if (setm || seta)
{
char NameA[NM];
WideToChar(Name,NameA,ASIZE(NameA));
#ifdef UNIX_TIME_NS
timespec times[2];
times[0].tv_sec=seta ? fta->GetUnix() : 0;
times[0].tv_nsec=seta ? long(fta->GetUnixNS()%1000000000) : UTIME_NOW;
times[1].tv_sec=setm ? ftm->GetUnix() : 0;
times[1].tv_nsec=setm ? long(ftm->GetUnixNS()%1000000000) : UTIME_NOW;
utimensat(AT_FDCWD,NameA,times,0);
#else
utimbuf ut;
if (setm)
ut.modtime=ftm->GetUnix();
else
ut.modtime=fta->GetUnix(); // Need to set something, cannot left it 0.
if (seta)
ut.actime=fta->GetUnix();
else
ut.actime=ut.modtime; // Need to set something, cannot left it 0.
utime(NameA,&ut);
#endif
}
#endif
}
void File::GetOpenFileTime(RarTime *ft)
{
#ifdef _WIN_ALL
FILETIME FileTime;
GetFileTime(hFile,NULL,NULL,&FileTime);
ft->SetWinFT(&FileTime);
#endif
#if defined(_UNIX) || defined(_EMX)
struct stat st;
fstat(GetFD(),&st);
ft->SetUnix(st.st_mtime);
#endif
}
int64 File::FileLength()
{
SaveFilePos SavePos(*this);
Seek(0,SEEK_END);
return Tell();
}
bool File::IsDevice()
{
if (hFile==FILE_BAD_HANDLE)
return false;
#ifdef _WIN_ALL
uint Type=GetFileType(hFile);
return Type==FILE_TYPE_CHAR || Type==FILE_TYPE_PIPE;
#else
return isatty(GetFD());
#endif
}
#ifndef SFX_MODULE
int64 File::Copy(File &Dest,int64 Length)
{
Array<char> Buffer(0x40000);
int64 CopySize=0;
bool CopyAll=(Length==INT64NDF);
while (CopyAll || Length>0)
{
Wait();
size_t SizeToRead=(!CopyAll && Length<(int64)Buffer.Size()) ? (size_t)Length:Buffer.Size();
char *Buf=&Buffer[0];
int ReadSize=Read(Buf,SizeToRead);
if (ReadSize==0)
break;
size_t WriteSize=ReadSize;
#ifdef _WIN_ALL
// For FAT32 USB flash drives in Windows if first write is 4 KB or more,
// write caching is disabled and "write through" is enabled, resulting
// in bad performance, especially for many small files. It happens when
// we create SFX archive on USB drive, because SFX module is written first.
// So we split the first write to small 1 KB followed by rest of data.
if (CopySize==0 && WriteSize>=4096)
{
const size_t FirstWrite=1024;
Dest.Write(Buf,FirstWrite);
Buf+=FirstWrite;
WriteSize-=FirstWrite;
}
#endif
Dest.Write(Buf,WriteSize);
CopySize+=ReadSize;
if (!CopyAll)
Length-=ReadSize;
}
return CopySize;
}
#endif

126
reference/unrar/file.hpp Normal file
View File

@@ -0,0 +1,126 @@
#ifndef _RAR_FILE_
#define _RAR_FILE_
#define FILE_USE_OPEN
#ifdef _WIN_ALL
typedef HANDLE FileHandle;
#define FILE_BAD_HANDLE INVALID_HANDLE_VALUE
#elif defined(FILE_USE_OPEN)
typedef off_t FileHandle;
#define FILE_BAD_HANDLE -1
#else
typedef FILE* FileHandle;
#define FILE_BAD_HANDLE NULL
#endif
class RAROptions;
enum FILE_HANDLETYPE {FILE_HANDLENORMAL,FILE_HANDLESTD};
enum FILE_ERRORTYPE {FILE_SUCCESS,FILE_NOTFOUND,FILE_READERROR};
enum FILE_MODE_FLAGS {
// Request read only access to file. Default for Open.
FMF_READ=0,
// Request both read and write access to file. Default for Create.
FMF_UPDATE=1,
// Request write only access to file.
FMF_WRITE=2,
// Open files which are already opened for write by other programs.
FMF_OPENSHARED=4,
// Open files only if no other program is opened it even in shared mode.
FMF_OPENEXCLUSIVE=8,
// Provide read access to created file for other programs.
FMF_SHAREREAD=16,
// Use standard NTFS names without trailing dots and spaces.
FMF_STANDARDNAMES=32,
// Mode flags are not defined yet.
FMF_UNDEFINED=256
};
class File
{
private:
FileHandle hFile;
bool LastWrite;
FILE_HANDLETYPE HandleType;
bool SkipClose;
bool IgnoreReadErrors;
bool NewFile;
bool AllowDelete;
bool AllowExceptions;
#ifdef _WIN_ALL
bool NoSequentialRead;
uint CreateMode;
#endif
protected:
bool OpenShared; // Set by 'Archive' class.
public:
wchar FileName[NM];
FILE_ERRORTYPE ErrorType;
public:
File();
virtual ~File();
void operator = (File &SrcFile);
virtual bool Open(const wchar *Name,uint Mode=FMF_READ);
void TOpen(const wchar *Name);
bool WOpen(const wchar *Name);
bool Create(const wchar *Name,uint Mode=FMF_UPDATE|FMF_SHAREREAD);
void TCreate(const wchar *Name,uint Mode=FMF_UPDATE|FMF_SHAREREAD);
bool WCreate(const wchar *Name,uint Mode=FMF_UPDATE|FMF_SHAREREAD);
bool Close();
bool Delete();
bool Rename(const wchar *NewName);
bool Write(const void *Data,size_t Size);
virtual int Read(void *Data,size_t Size);
int DirectRead(void *Data,size_t Size);
virtual void Seek(int64 Offset,int Method);
bool RawSeek(int64 Offset,int Method);
virtual int64 Tell();
void Prealloc(int64 Size);
byte GetByte();
void PutByte(byte Byte);
bool Truncate();
void Flush();
void SetOpenFileTime(RarTime *ftm,RarTime *ftc=NULL,RarTime *fta=NULL);
void SetCloseFileTime(RarTime *ftm,RarTime *fta=NULL);
static void SetCloseFileTimeByName(const wchar *Name,RarTime *ftm,RarTime *fta);
void GetOpenFileTime(RarTime *ft);
bool IsOpened() {return hFile!=FILE_BAD_HANDLE;};
int64 FileLength();
void SetHandleType(FILE_HANDLETYPE Type) {HandleType=Type;}
FILE_HANDLETYPE GetHandleType() {return HandleType;}
bool IsDevice();
static bool RemoveCreated();
FileHandle GetHandle() {return hFile;}
void SetHandle(FileHandle Handle) {Close();hFile=Handle;}
void SetIgnoreReadErrors(bool Mode) {IgnoreReadErrors=Mode;}
int64 Copy(File &Dest,int64 Length=INT64NDF);
void SetAllowDelete(bool Allow) {AllowDelete=Allow;}
void SetExceptions(bool Allow) {AllowExceptions=Allow;}
#ifdef _WIN_ALL
void RemoveSequentialFlag() {NoSequentialRead=true;}
#endif
#ifdef _UNIX
int GetFD()
{
#ifdef FILE_USE_OPEN
return hFile;
#else
return fileno(hFile);
#endif
}
#endif
};
#endif

510
reference/unrar/filefn.cpp Normal file
View File

@@ -0,0 +1,510 @@
#include "rar.hpp"
MKDIR_CODE MakeDir(const wchar *Name,bool SetAttr,uint Attr)
{
#ifdef _WIN_ALL
// Windows automatically removes dots and spaces in the end of directory
// name. So we detect such names and process them with \\?\ prefix.
wchar *LastChar=PointToLastChar(Name);
bool Special=*LastChar=='.' || *LastChar==' ';
BOOL RetCode=Special ? FALSE : CreateDirectory(Name,NULL);
if (RetCode==0 && !FileExist(Name))
{
wchar LongName[NM];
if (GetWinLongPath(Name,LongName,ASIZE(LongName)))
RetCode=CreateDirectory(LongName,NULL);
}
if (RetCode!=0) // Non-zero return code means success for CreateDirectory.
{
if (SetAttr)
SetFileAttr(Name,Attr);
return MKDIR_SUCCESS;
}
int ErrCode=GetLastError();
if (ErrCode==ERROR_FILE_NOT_FOUND || ErrCode==ERROR_PATH_NOT_FOUND)
return MKDIR_BADPATH;
return MKDIR_ERROR;
#elif defined(_UNIX)
char NameA[NM];
WideToChar(Name,NameA,ASIZE(NameA));
mode_t uattr=SetAttr ? (mode_t)Attr:0777;
int ErrCode=mkdir(NameA,uattr);
if (ErrCode==-1)
return errno==ENOENT ? MKDIR_BADPATH:MKDIR_ERROR;
return MKDIR_SUCCESS;
#else
return MKDIR_ERROR;
#endif
}
bool CreatePath(const wchar *Path,bool SkipLastName)
{
if (Path==NULL || *Path==0)
return false;
#if defined(_WIN_ALL) || defined(_EMX)
uint DirAttr=0;
#else
uint DirAttr=0777;
#endif
bool Success=true;
for (const wchar *s=Path;*s!=0;s++)
{
wchar DirName[NM];
if (s-Path>=ASIZE(DirName))
break;
// Process all kinds of path separators, so user can enter Unix style
// path in Windows or Windows in Unix. s>Path check avoids attempting
// creating an empty directory for paths starting from path separator.
if (IsPathDiv(*s) && s>Path)
{
#ifdef _WIN_ALL
// We must not attempt to create "D:" directory, because first
// CreateDirectory will fail, so we'll use \\?\D:, which forces Wine
// to create "D:" directory.
if (s==Path+2 && Path[1]==':')
continue;
#endif
wcsncpy(DirName,Path,s-Path);
DirName[s-Path]=0;
Success=MakeDir(DirName,true,DirAttr)==MKDIR_SUCCESS;
if (Success)
{
mprintf(St(MCreatDir),DirName);
mprintf(L" %s",St(MOk));
}
}
}
if (!SkipLastName && !IsPathDiv(*PointToLastChar(Path)))
Success=MakeDir(Path,true,DirAttr)==MKDIR_SUCCESS;
return Success;
}
void SetDirTime(const wchar *Name,RarTime *ftm,RarTime *ftc,RarTime *fta)
{
#if defined(_WIN_ALL)
bool sm=ftm!=NULL && ftm->IsSet();
bool sc=ftc!=NULL && ftc->IsSet();
bool sa=fta!=NULL && fta->IsSet();
uint DirAttr=GetFileAttr(Name);
bool ResetAttr=(DirAttr!=0xffffffff && (DirAttr & FILE_ATTRIBUTE_READONLY)!=0);
if (ResetAttr)
SetFileAttr(Name,0);
HANDLE hFile=CreateFile(Name,GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS,NULL);
if (hFile==INVALID_HANDLE_VALUE)
{
wchar LongName[NM];
if (GetWinLongPath(Name,LongName,ASIZE(LongName)))
hFile=CreateFile(LongName,GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS,NULL);
}
if (hFile==INVALID_HANDLE_VALUE)
return;
FILETIME fm,fc,fa;
if (sm)
ftm->GetWinFT(&fm);
if (sc)
ftc->GetWinFT(&fc);
if (sa)
fta->GetWinFT(&fa);
SetFileTime(hFile,sc ? &fc:NULL,sa ? &fa:NULL,sm ? &fm:NULL);
CloseHandle(hFile);
if (ResetAttr)
SetFileAttr(Name,DirAttr);
#endif
#if defined(_UNIX) || defined(_EMX)
File::SetCloseFileTimeByName(Name,ftm,fta);
#endif
}
bool IsRemovable(const wchar *Name)
{
#if defined(_WIN_ALL)
wchar Root[NM];
GetPathRoot(Name,Root,ASIZE(Root));
int Type=GetDriveType(*Root!=0 ? Root:NULL);
return Type==DRIVE_REMOVABLE || Type==DRIVE_CDROM;
#else
return false;
#endif
}
#ifndef SFX_MODULE
int64 GetFreeDisk(const wchar *Name)
{
#ifdef _WIN_ALL
wchar Root[NM];
GetFilePath(Name,Root,ASIZE(Root));
ULARGE_INTEGER uiTotalSize,uiTotalFree,uiUserFree;
uiUserFree.u.LowPart=uiUserFree.u.HighPart=0;
if (GetDiskFreeSpaceEx(*Root!=0 ? Root:NULL,&uiUserFree,&uiTotalSize,&uiTotalFree) &&
uiUserFree.u.HighPart<=uiTotalFree.u.HighPart)
return INT32TO64(uiUserFree.u.HighPart,uiUserFree.u.LowPart);
return 0;
#elif defined(_UNIX)
wchar Root[NM];
GetFilePath(Name,Root,ASIZE(Root));
char RootA[NM];
WideToChar(Root,RootA,ASIZE(RootA));
struct statvfs sfs;
if (statvfs(*RootA!=0 ? RootA:".",&sfs)!=0)
return 0;
int64 FreeSize=sfs.f_bsize;
FreeSize=FreeSize*sfs.f_bavail;
return FreeSize;
#else
return 0;
#endif
}
#endif
#if defined(_WIN_ALL) && !defined(SFX_MODULE) && !defined(SILENT)
// Return 'true' for FAT and FAT32, so we can adjust the maximum supported
// file size to 4 GB for these file systems.
bool IsFAT(const wchar *Name)
{
wchar Root[NM];
GetPathRoot(Name,Root,ASIZE(Root));
wchar FileSystem[MAX_PATH+1];
if (GetVolumeInformation(Root,NULL,0,NULL,NULL,NULL,FileSystem,ASIZE(FileSystem)))
return wcscmp(FileSystem,L"FAT")==0 || wcscmp(FileSystem,L"FAT32")==0;
return false;
}
#endif
bool FileExist(const wchar *Name)
{
#ifdef _WIN_ALL
return GetFileAttr(Name)!=0xffffffff;
#elif defined(ENABLE_ACCESS)
char NameA[NM];
WideToChar(Name,NameA,ASIZE(NameA));
return access(NameA,0)==0;
#else
FindData FD;
return FindFile::FastFind(Name,&FD);
#endif
}
bool WildFileExist(const wchar *Name)
{
if (IsWildcard(Name))
{
FindFile Find;
Find.SetMask(Name);
FindData fd;
return Find.Next(&fd);
}
return FileExist(Name);
}
bool IsDir(uint Attr)
{
#ifdef _WIN_ALL
return Attr!=0xffffffff && (Attr & FILE_ATTRIBUTE_DIRECTORY)!=0;
#endif
#if defined(_UNIX)
return (Attr & 0xF000)==0x4000;
#endif
}
bool IsUnreadable(uint Attr)
{
#if defined(_UNIX) && defined(S_ISFIFO) && defined(S_ISSOCK) && defined(S_ISCHR)
return S_ISFIFO(Attr) || S_ISSOCK(Attr) || S_ISCHR(Attr);
#endif
return false;
}
bool IsLink(uint Attr)
{
#ifdef _UNIX
return (Attr & 0xF000)==0xA000;
#elif defined(_WIN_ALL)
return (Attr & FILE_ATTRIBUTE_REPARSE_POINT)!=0;
#else
return false;
#endif
}
bool IsDeleteAllowed(uint FileAttr)
{
#ifdef _WIN_ALL
return (FileAttr & (FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_HIDDEN))==0;
#else
return (FileAttr & (S_IRUSR|S_IWUSR))==(S_IRUSR|S_IWUSR);
#endif
}
void PrepareToDelete(const wchar *Name)
{
#if defined(_WIN_ALL) || defined(_EMX)
SetFileAttr(Name,0);
#endif
#ifdef _UNIX
if (Name!=NULL)
{
char NameA[NM];
WideToChar(Name,NameA,ASIZE(NameA));
chmod(NameA,S_IRUSR|S_IWUSR|S_IXUSR);
}
#endif
}
uint GetFileAttr(const wchar *Name)
{
#ifdef _WIN_ALL
DWORD Attr=GetFileAttributes(Name);
if (Attr==0xffffffff)
{
wchar LongName[NM];
if (GetWinLongPath(Name,LongName,ASIZE(LongName)))
Attr=GetFileAttributes(LongName);
}
return Attr;
#else
char NameA[NM];
WideToChar(Name,NameA,ASIZE(NameA));
struct stat st;
if (stat(NameA,&st)!=0)
return 0;
return st.st_mode;
#endif
}
bool SetFileAttr(const wchar *Name,uint Attr)
{
#ifdef _WIN_ALL
bool Success=SetFileAttributes(Name,Attr)!=0;
if (!Success)
{
wchar LongName[NM];
if (GetWinLongPath(Name,LongName,ASIZE(LongName)))
Success=SetFileAttributes(LongName,Attr)!=0;
}
return Success;
#elif defined(_UNIX)
char NameA[NM];
WideToChar(Name,NameA,ASIZE(NameA));
return chmod(NameA,(mode_t)Attr)==0;
#else
return false;
#endif
}
#if 0
wchar *MkTemp(wchar *Name,size_t MaxSize)
{
size_t Length=wcslen(Name);
RarTime CurTime;
CurTime.SetCurrentTime();
// We cannot use CurTime.GetWin() as is, because its lowest bits can
// have low informational value, like being a zero or few fixed numbers.
uint Random=(uint)(CurTime.GetWin()/100000);
// Using PID we guarantee that different RAR copies use different temp names
// even if started in exactly the same time.
uint PID=0;
#ifdef _WIN_ALL
PID=(uint)GetCurrentProcessId();
#elif defined(_UNIX)
PID=(uint)getpid();
#endif
for (uint Attempt=0;;Attempt++)
{
uint Ext=Random%50000+Attempt;
wchar RndText[50];
swprintf(RndText,ASIZE(RndText),L"%u.%03u",PID,Ext);
if (Length+wcslen(RndText)>=MaxSize || Attempt==1000)
return NULL;
wcscpy(Name+Length,RndText);
if (!FileExist(Name))
break;
}
return Name;
}
#endif
#if !defined(SFX_MODULE)
void CalcFileSum(File *SrcFile,uint *CRC32,byte *Blake2,uint Threads,int64 Size,uint Flags)
{
SaveFilePos SavePos(*SrcFile);
#ifndef SILENT
int64 FileLength=Size==INT64NDF ? SrcFile->FileLength() : Size;
#endif
if ((Flags & (CALCFSUM_SHOWTEXT|CALCFSUM_SHOWPERCENT))!=0)
uiMsg(UIEVENT_FILESUMSTART);
if ((Flags & CALCFSUM_CURPOS)==0)
SrcFile->Seek(0,SEEK_SET);
const size_t BufSize=0x100000;
Array<byte> Data(BufSize);
DataHash HashCRC,HashBlake2;
HashCRC.Init(HASH_CRC32,Threads);
HashBlake2.Init(HASH_BLAKE2,Threads);
int64 BlockCount=0;
int64 TotalRead=0;
while (true)
{
size_t SizeToRead;
if (Size==INT64NDF) // If we process the entire file.
SizeToRead=BufSize; // Then always attempt to read the entire buffer.
else
SizeToRead=(size_t)Min((int64)BufSize,Size);
int ReadSize=SrcFile->Read(&Data[0],SizeToRead);
if (ReadSize==0)
break;
TotalRead+=ReadSize;
if ((++BlockCount & 0xf)==0)
{
#ifndef SILENT
if ((Flags & CALCFSUM_SHOWPROGRESS)!=0)
uiExtractProgress(TotalRead,FileLength,TotalRead,FileLength);
else
{
if ((Flags & CALCFSUM_SHOWPERCENT)!=0)
uiMsg(UIEVENT_FILESUMPROGRESS,ToPercent(TotalRead,FileLength));
}
#endif
Wait();
}
if (CRC32!=NULL)
HashCRC.Update(&Data[0],ReadSize);
if (Blake2!=NULL)
HashBlake2.Update(&Data[0],ReadSize);
if (Size!=INT64NDF)
Size-=ReadSize;
}
if ((Flags & CALCFSUM_SHOWPERCENT)!=0)
uiMsg(UIEVENT_FILESUMEND);
if (CRC32!=NULL)
*CRC32=HashCRC.GetCRC32();
if (Blake2!=NULL)
{
HashValue Result;
HashBlake2.Result(&Result);
memcpy(Blake2,Result.Digest,sizeof(Result.Digest));
}
}
#endif
bool RenameFile(const wchar *SrcName,const wchar *DestName)
{
#ifdef _WIN_ALL
bool Success=MoveFile(SrcName,DestName)!=0;
if (!Success)
{
wchar LongName1[NM],LongName2[NM];
if (GetWinLongPath(SrcName,LongName1,ASIZE(LongName1)) &&
GetWinLongPath(DestName,LongName2,ASIZE(LongName2)))
Success=MoveFile(LongName1,LongName2)!=0;
}
return Success;
#else
char SrcNameA[NM],DestNameA[NM];
WideToChar(SrcName,SrcNameA,ASIZE(SrcNameA));
WideToChar(DestName,DestNameA,ASIZE(DestNameA));
bool Success=rename(SrcNameA,DestNameA)==0;
return Success;
#endif
}
bool DelFile(const wchar *Name)
{
#ifdef _WIN_ALL
bool Success=DeleteFile(Name)!=0;
if (!Success)
{
wchar LongName[NM];
if (GetWinLongPath(Name,LongName,ASIZE(LongName)))
Success=DeleteFile(LongName)!=0;
}
return Success;
#else
char NameA[NM];
WideToChar(Name,NameA,ASIZE(NameA));
bool Success=remove(NameA)==0;
return Success;
#endif
}
#if defined(_WIN_ALL) && !defined(SFX_MODULE)
bool SetFileCompression(const wchar *Name,bool State)
{
HANDLE hFile=CreateFile(Name,FILE_READ_DATA|FILE_WRITE_DATA,
FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_SEQUENTIAL_SCAN,NULL);
if (hFile==INVALID_HANDLE_VALUE)
{
wchar LongName[NM];
if (GetWinLongPath(Name,LongName,ASIZE(LongName)))
hFile=CreateFile(LongName,FILE_READ_DATA|FILE_WRITE_DATA,
FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_SEQUENTIAL_SCAN,NULL);
}
if (hFile==INVALID_HANDLE_VALUE)
return false;
SHORT NewState=State ? COMPRESSION_FORMAT_DEFAULT:COMPRESSION_FORMAT_NONE;
DWORD Result;
int RetCode=DeviceIoControl(hFile,FSCTL_SET_COMPRESSION,&NewState,
sizeof(NewState),NULL,0,&Result,NULL);
CloseHandle(hFile);
return RetCode!=0;
}
#endif

View File

@@ -0,0 +1,50 @@
#ifndef _RAR_FILEFN_
#define _RAR_FILEFN_
enum MKDIR_CODE {MKDIR_SUCCESS,MKDIR_ERROR,MKDIR_BADPATH};
MKDIR_CODE MakeDir(const wchar *Name,bool SetAttr,uint Attr);
bool CreatePath(const wchar *Path,bool SkipLastName);
void SetDirTime(const wchar *Name,RarTime *ftm,RarTime *ftc,RarTime *fta);
bool IsRemovable(const wchar *Name);
#ifndef SFX_MODULE
int64 GetFreeDisk(const wchar *Name);
#endif
#if defined(_WIN_ALL) && !defined(SFX_MODULE) && !defined(SILENT)
bool IsFAT(const wchar *Root);
#endif
bool FileExist(const wchar *Name);
bool WildFileExist(const wchar *Name);
bool IsDir(uint Attr);
bool IsUnreadable(uint Attr);
bool IsLink(uint Attr);
void SetSFXMode(const wchar *FileName);
void EraseDiskContents(const wchar *FileName);
bool IsDeleteAllowed(uint FileAttr);
void PrepareToDelete(const wchar *Name);
uint GetFileAttr(const wchar *Name);
bool SetFileAttr(const wchar *Name,uint Attr);
#if 0
wchar* MkTemp(wchar *Name,size_t MaxSize);
#endif
enum CALCFSUM_FLAGS {CALCFSUM_SHOWTEXT=1,CALCFSUM_SHOWPERCENT=2,CALCFSUM_SHOWPROGRESS=4,CALCFSUM_CURPOS=8};
void CalcFileSum(File *SrcFile,uint *CRC32,byte *Blake2,uint Threads,int64 Size=INT64NDF,uint Flags=0);
bool RenameFile(const wchar *SrcName,const wchar *DestName);
bool DelFile(const wchar *Name);
bool DelDir(const wchar *Name);
#if defined(_WIN_ALL) && !defined(SFX_MODULE)
bool SetFileCompression(const wchar *Name,bool State);
#endif
#endif

162
reference/unrar/filestr.cpp Normal file
View File

@@ -0,0 +1,162 @@
#include "rar.hpp"
bool ReadTextFile(
const wchar *Name,
StringList *List,
bool Config,
bool AbortOnError,
RAR_CHARSET SrcCharset,
bool Unquote,
bool SkipComments,
bool ExpandEnvStr)
{
wchar FileName[NM];
*FileName=0;
if (Name!=NULL)
if (Config)
GetConfigName(Name,FileName,ASIZE(FileName),true,false);
else
wcsncpyz(FileName,Name,ASIZE(FileName));
File SrcFile;
if (*FileName!=0)
{
bool OpenCode=AbortOnError ? SrcFile.WOpen(FileName):SrcFile.Open(FileName,0);
if (!OpenCode)
{
if (AbortOnError)
ErrHandler.Exit(RARX_OPEN);
return false;
}
}
else
SrcFile.SetHandleType(FILE_HANDLESTD);
uint DataSize=0,ReadSize;
const int ReadBlock=4096;
Array<byte> Data(ReadBlock);
while ((ReadSize=SrcFile.Read(&Data[DataSize],ReadBlock))!=0)
{
DataSize+=ReadSize;
Data.Add(ReadSize); // Always have ReadBlock available for next data.
}
// Set to really read size, so we can zero terminate it correctly.
Data.Alloc(DataSize);
int LowEndian=DataSize>=2 && Data[0]==255 && Data[1]==254 ? 1:0;
int BigEndian=DataSize>=2 && Data[0]==254 && Data[1]==255 ? 1:0;
bool Utf8=DataSize>=3 && Data[0]==0xef && Data[1]==0xbb && Data[2]==0xbf;
if (SrcCharset==RCH_DEFAULT)
{
if (LowEndian || BigEndian)
for (size_t I=2;I<DataSize;I++)
if (Data[I]<32 && Data[I]!='\r' && Data[I]!='\n')
{
SrcCharset=RCH_UNICODE; // High byte in UTF-16 char is found.
break;
}
if (Utf8)
{
Data.Push(0); // Need a zero terminated string for UtfToWide.
if (IsTextUtf8((const char *)(Data+3)))
SrcCharset=RCH_UTF8;
}
}
Array<wchar> DataW;
if (SrcCharset==RCH_DEFAULT || SrcCharset==RCH_OEM || SrcCharset==RCH_ANSI)
{
Data.Push(0); // Zero terminate.
#if defined(_WIN_ALL)
if (SrcCharset==RCH_OEM)
OemToCharA((char *)&Data[0],(char *)&Data[0]);
#endif
DataW.Alloc(Data.Size());
CharToWide((char *)&Data[0],&DataW[0],DataW.Size());
}
if (SrcCharset==RCH_UNICODE)
{
size_t Start=2; // Skip byte order mark.
if (!LowEndian && !BigEndian) // No byte order mask.
{
Start=0;
LowEndian=1;
}
DataW.Alloc(Data.Size()/2+1);
size_t End=Data.Size() & ~1; // We need even bytes number for UTF-16.
for (size_t I=Start;I<End;I+=2)
DataW[(I-Start)/2]=Data[I+BigEndian]+Data[I+LowEndian]*256;
DataW[(End-Start)/2]=0;
}
if (SrcCharset==RCH_UTF8)
{
Data.Push(0); // Zero terminate data.
DataW.Alloc(Data.Size());
UtfToWide((const char *)(Data+(Utf8 ? 3:0)),&DataW[0],DataW.Size());
}
wchar *CurStr=&DataW[0];
while (*CurStr!=0)
{
wchar *NextStr=CurStr,*CmtPtr=NULL;
while (*NextStr!='\r' && *NextStr!='\n' && *NextStr!=0)
{
if (SkipComments && NextStr[0]=='/' && NextStr[1]=='/')
{
*NextStr=0;
CmtPtr=NextStr;
}
NextStr++;
}
bool Done=*NextStr==0;
*NextStr=0;
for (wchar *SpacePtr=(CmtPtr!=NULL ? CmtPtr:NextStr)-1;SpacePtr>=CurStr;SpacePtr--)
{
if (*SpacePtr!=' ' && *SpacePtr!='\t')
break;
*SpacePtr=0;
}
if (Unquote && *CurStr=='\"')
{
size_t Length=wcslen(CurStr);
if (CurStr[Length-1]=='\"')
{
CurStr[Length-1]=0;
CurStr++;
}
}
bool Expanded=false;
#if defined(_WIN_ALL)
if (ExpandEnvStr && *CurStr=='%') // Expand environment variables in Windows.
{
wchar ExpName[NM];
*ExpName=0;
DWORD Result=ExpandEnvironmentStrings(CurStr,ExpName,ASIZE(ExpName));
Expanded=Result!=0 && Result<ASIZE(ExpName);
if (Expanded && *ExpName!=0)
List->AddString(ExpName);
}
#endif
if (!Expanded && *CurStr!=0)
List->AddString(CurStr);
if (Done)
break;
CurStr=NextStr+1;
while (*CurStr=='\r' || *CurStr=='\n')
CurStr++;
}
return true;
}

View File

@@ -0,0 +1,15 @@
#ifndef _RAR_FILESTR_
#define _RAR_FILESTR_
bool ReadTextFile(
const wchar *Name,
StringList *List,
bool Config,
bool AbortOnError=false,
RAR_CHARSET SrcCharset=RCH_DEFAULT,
bool Unquote=false,
bool SkipComments=false,
bool ExpandEnvStr=false
);
#endif

218
reference/unrar/find.cpp Normal file
View File

@@ -0,0 +1,218 @@
#include "rar.hpp"
FindFile::FindFile()
{
*FindMask=0;
FirstCall=true;
#ifdef _WIN_ALL
hFind=INVALID_HANDLE_VALUE;
#else
dirp=NULL;
#endif
}
FindFile::~FindFile()
{
#ifdef _WIN_ALL
if (hFind!=INVALID_HANDLE_VALUE)
FindClose(hFind);
#else
if (dirp!=NULL)
closedir(dirp);
#endif
}
void FindFile::SetMask(const wchar *Mask)
{
wcscpy(FindMask,Mask);
FirstCall=true;
}
bool FindFile::Next(FindData *fd,bool GetSymLink)
{
fd->Error=false;
if (*FindMask==0)
return false;
#ifdef _WIN_ALL
if (FirstCall)
{
if ((hFind=Win32Find(INVALID_HANDLE_VALUE,FindMask,fd))==INVALID_HANDLE_VALUE)
return false;
}
else
if (Win32Find(hFind,FindMask,fd)==INVALID_HANDLE_VALUE)
return false;
#else
if (FirstCall)
{
wchar DirName[NM];
wcsncpyz(DirName,FindMask,ASIZE(DirName));
RemoveNameFromPath(DirName);
if (*DirName==0)
wcscpy(DirName,L".");
char DirNameA[NM];
WideToChar(DirName,DirNameA,ASIZE(DirNameA));
if ((dirp=opendir(DirNameA))==NULL)
{
fd->Error=(errno!=ENOENT);
return false;
}
}
while (1)
{
struct dirent *ent=readdir(dirp);
if (ent==NULL)
return false;
if (strcmp(ent->d_name,".")==0 || strcmp(ent->d_name,"..")==0)
continue;
wchar Name[NM];
if (!CharToWide(ent->d_name,Name,ASIZE(Name)))
uiMsg(UIERROR_INVALIDNAME,UINULL,Name);
if (CmpName(FindMask,Name,MATCH_NAMES))
{
wchar FullName[NM];
wcscpy(FullName,FindMask);
*PointToName(FullName)=0;
if (wcslen(FullName)+wcslen(Name)>=ASIZE(FullName)-1)
{
uiMsg(UIERROR_PATHTOOLONG,FullName,L"",Name);
return false;
}
wcscat(FullName,Name);
if (!FastFind(FullName,fd,GetSymLink))
{
ErrHandler.OpenErrorMsg(FullName);
continue;
}
wcscpy(fd->Name,FullName);
break;
}
}
#endif
fd->Flags=0;
fd->IsDir=IsDir(fd->FileAttr);
fd->IsLink=IsLink(fd->FileAttr);
FirstCall=false;
wchar *NameOnly=PointToName(fd->Name);
if (wcscmp(NameOnly,L".")==0 || wcscmp(NameOnly,L"..")==0)
return Next(fd);
return true;
}
bool FindFile::FastFind(const wchar *FindMask,FindData *fd,bool GetSymLink)
{
fd->Error=false;
#ifndef _UNIX
if (IsWildcard(FindMask))
return false;
#endif
#ifdef _WIN_ALL
HANDLE hFind=Win32Find(INVALID_HANDLE_VALUE,FindMask,fd);
if (hFind==INVALID_HANDLE_VALUE)
return false;
FindClose(hFind);
#else
char FindMaskA[NM];
WideToChar(FindMask,FindMaskA,ASIZE(FindMaskA));
struct stat st;
if (GetSymLink)
{
#ifdef SAVE_LINKS
if (lstat(FindMaskA,&st)!=0)
#else
if (stat(FindMaskA,&st)!=0)
#endif
{
fd->Error=(errno!=ENOENT);
return false;
}
}
else
if (stat(FindMaskA,&st)!=0)
{
fd->Error=(errno!=ENOENT);
return false;
}
fd->FileAttr=st.st_mode;
fd->Size=st.st_size;
#ifdef UNIX_TIME_NS
fd->mtime.SetUnixNS(st.st_mtim.tv_sec*(uint64)1000000000+st.st_mtim.tv_nsec);
fd->atime.SetUnixNS(st.st_atim.tv_sec*(uint64)1000000000+st.st_atim.tv_nsec);
fd->ctime.SetUnixNS(st.st_ctim.tv_sec*(uint64)1000000000+st.st_ctim.tv_nsec);
#else
fd->mtime.SetUnix(st.st_mtime);
fd->atime.SetUnix(st.st_atime);
fd->ctime.SetUnix(st.st_ctime);
#endif
wcsncpyz(fd->Name,FindMask,ASIZE(fd->Name));
#endif
fd->Flags=0;
fd->IsDir=IsDir(fd->FileAttr);
fd->IsLink=IsLink(fd->FileAttr);
return true;
}
#ifdef _WIN_ALL
HANDLE FindFile::Win32Find(HANDLE hFind,const wchar *Mask,FindData *fd)
{
WIN32_FIND_DATA FindData;
if (hFind==INVALID_HANDLE_VALUE)
{
hFind=FindFirstFile(Mask,&FindData);
if (hFind==INVALID_HANDLE_VALUE)
{
wchar LongMask[NM];
if (GetWinLongPath(Mask,LongMask,ASIZE(LongMask)))
hFind=FindFirstFile(LongMask,&FindData);
}
if (hFind==INVALID_HANDLE_VALUE)
{
int SysErr=GetLastError();
// We must not issue an error for "file not found" and "path not found",
// because it is normal to not find anything for wildcard mask when
// archiving. Also searching for non-existent file is normal in some
// other modules, like WinRAR scanning for winrar_theme_description.txt
// to check if any themes are available.
fd->Error=SysErr!=ERROR_FILE_NOT_FOUND &&
SysErr!=ERROR_PATH_NOT_FOUND &&
SysErr!=ERROR_NO_MORE_FILES;
}
}
else
if (!FindNextFile(hFind,&FindData))
{
hFind=INVALID_HANDLE_VALUE;
fd->Error=GetLastError()!=ERROR_NO_MORE_FILES;
}
if (hFind!=INVALID_HANDLE_VALUE)
{
wcsncpyz(fd->Name,Mask,ASIZE(fd->Name));
SetName(fd->Name,FindData.cFileName,ASIZE(fd->Name));
fd->Size=INT32TO64(FindData.nFileSizeHigh,FindData.nFileSizeLow);
fd->FileAttr=FindData.dwFileAttributes;
fd->ftCreationTime=FindData.ftCreationTime;
fd->ftLastAccessTime=FindData.ftLastAccessTime;
fd->ftLastWriteTime=FindData.ftLastWriteTime;
fd->mtime.SetWinFT(&FindData.ftLastWriteTime);
fd->ctime.SetWinFT(&FindData.ftCreationTime);
fd->atime.SetWinFT(&FindData.ftLastAccessTime);
}
fd->Flags=0;
return hFind;
}
#endif

49
reference/unrar/find.hpp Normal file
View File

@@ -0,0 +1,49 @@
#ifndef _RAR_FINDDATA_
#define _RAR_FINDDATA_
enum FINDDATA_FLAGS {
FDDF_SECONDDIR=1 // Second encounter of same directory in SCAN_GETDIRSTWICE ScanTree mode.
};
struct FindData
{
wchar Name[NM];
uint64 Size;
uint FileAttr;
bool IsDir;
bool IsLink;
RarTime mtime;
RarTime ctime;
RarTime atime;
#ifdef _WIN_ALL
FILETIME ftCreationTime;
FILETIME ftLastAccessTime;
FILETIME ftLastWriteTime;
#endif
uint Flags;
bool Error;
};
class FindFile
{
private:
#ifdef _WIN_ALL
static HANDLE Win32Find(HANDLE hFind,const wchar *Mask,FindData *fd);
#endif
wchar FindMask[NM];
bool FirstCall;
#ifdef _WIN_ALL
HANDLE hFind;
#else
DIR *dirp;
#endif
public:
FindFile();
~FindFile();
void SetMask(const wchar *Mask);
bool Next(FindData *fd,bool GetSymLink=false);
static bool FastFind(const wchar *FindMask,FindData *fd,bool GetSymLink=false);
};
#endif

View File

@@ -0,0 +1,52 @@
#include "rar.hpp"
BitInput::BitInput(bool AllocBuffer)
{
ExternalBuffer=false;
if (AllocBuffer)
{
// getbits32 attempts to read data from InAddr, ... InAddr+3 positions.
// So let's allocate 3 additional bytes for situation, when we need to
// read only 1 byte from the last position of buffer and avoid a crash
// from access to next 3 bytes, which contents we do not need.
size_t BufSize=MAX_SIZE+3;
InBuf=new byte[BufSize];
// Ensure that we get predictable results when accessing bytes in area
// not filled with read data.
memset(InBuf,0,BufSize);
}
else
InBuf=NULL;
}
BitInput::~BitInput()
{
if (!ExternalBuffer)
delete[] InBuf;
}
void BitInput::faddbits(uint Bits)
{
// Function wrapped version of inline addbits to save code size.
addbits(Bits);
}
uint BitInput::fgetbits()
{
// Function wrapped version of inline getbits to save code size.
return getbits();
}
void BitInput::SetExternalBuffer(byte *Buf)
{
if (InBuf!=NULL && !ExternalBuffer)
delete[] InBuf;
InBuf=Buf;
ExternalBuffer=true;
}

View File

@@ -0,0 +1,68 @@
#ifndef _RAR_GETBITS_
#define _RAR_GETBITS_
class BitInput
{
public:
enum BufferSize {MAX_SIZE=0x8000}; // Size of input buffer.
int InAddr; // Curent byte position in the buffer.
int InBit; // Current bit position in the current byte.
bool ExternalBuffer;
public:
BitInput(bool AllocBuffer);
~BitInput();
byte *InBuf; // Dynamically allocated input buffer.
void InitBitInput()
{
InAddr=InBit=0;
}
// Move forward by 'Bits' bits.
void addbits(uint Bits)
{
Bits+=InBit;
InAddr+=Bits>>3;
InBit=Bits&7;
}
// Return 16 bits from current position in the buffer.
// Bit at (InAddr,InBit) has the highest position in returning data.
uint getbits()
{
uint BitField=(uint)InBuf[InAddr] << 16;
BitField|=(uint)InBuf[InAddr+1] << 8;
BitField|=(uint)InBuf[InAddr+2];
BitField >>= (8-InBit);
return BitField & 0xffff;
}
// Return 32 bits from current position in the buffer.
// Bit at (InAddr,InBit) has the highest position in returning data.
uint getbits32()
{
uint BitField=(uint)InBuf[InAddr] << 24;
BitField|=(uint)InBuf[InAddr+1] << 16;
BitField|=(uint)InBuf[InAddr+2] << 8;
BitField|=(uint)InBuf[InAddr+3];
BitField <<= InBit;
BitField|=(uint)InBuf[InAddr+4] >> (8-InBit);
return BitField & 0xffffffff;
}
void faddbits(uint Bits);
uint fgetbits();
// Check if buffer has enough space for IncPtr bytes. Returns 'true'
// if buffer will be overflown.
bool Overflow(uint IncPtr)
{
return InAddr+IncPtr>=MAX_SIZE;
}
void SetExternalBuffer(byte *Buf);
};
#endif

View File

@@ -0,0 +1,7 @@
#define INCLUDEGLOBAL
#if defined(__BORLANDC__) || defined(_MSC_VER)
#pragma hdrstop
#endif
#include "rar.hpp"

View File

@@ -0,0 +1,14 @@
#ifndef _RAR_GLOBAL_
#define _RAR_GLOBAL_
#ifdef INCLUDEGLOBAL
#define EXTVAR
#else
#define EXTVAR extern
#endif
EXTVAR ErrorHandler ErrHandler;
#endif

View File

@@ -0,0 +1,34 @@
bool ExtractHardlink(wchar *NameNew,wchar *NameExisting,size_t NameExistingSize)
{
SlashToNative(NameExisting,NameExisting,NameExistingSize); // Not needed for RAR 5.1+ archives.
if (!FileExist(NameExisting))
return false;
CreatePath(NameNew,true);
#ifdef _WIN_ALL
bool Success=CreateHardLink(NameNew,NameExisting,NULL)!=0;
if (!Success)
{
uiMsg(UIERROR_HLINKCREATE,NameNew);
ErrHandler.SysErrMsg();
ErrHandler.SetErrorCode(RARX_CREATE);
}
return Success;
#elif defined(_UNIX)
char NameExistingA[NM],NameNewA[NM];
WideToChar(NameExisting,NameExistingA,ASIZE(NameExistingA));
WideToChar(NameNew,NameNewA,ASIZE(NameNewA));
bool Success=link(NameExistingA,NameNewA)==0;
if (!Success)
{
uiMsg(UIERROR_HLINKCREATE,NameNew);
ErrHandler.SysErrMsg();
ErrHandler.SetErrorCode(RARX_CREATE);
}
return Success;
#else
return false;
#endif
}

135
reference/unrar/hash.cpp Normal file
View File

@@ -0,0 +1,135 @@
#include "rar.hpp"
void HashValue::Init(HASH_TYPE Type)
{
HashValue::Type=Type;
// Zero length data CRC32 is 0. It is important to set it when creating
// headers with no following data like directories or symlinks.
if (Type==HASH_RAR14 || Type==HASH_CRC32)
CRC32=0;
if (Type==HASH_BLAKE2)
{
// dd0e891776933f43c7d032b08a917e25741f8aa9a12c12e1cac8801500f2ca4f
// is BLAKE2sp hash of empty data. We init the structure to this value,
// so if we create a file or service header with no following data like
// "file copy" or "symlink", we set the checksum to proper value avoiding
// additional header type or size checks when extracting.
static byte EmptyHash[32]={
0xdd, 0x0e, 0x89, 0x17, 0x76, 0x93, 0x3f, 0x43,
0xc7, 0xd0, 0x32, 0xb0, 0x8a, 0x91, 0x7e, 0x25,
0x74, 0x1f, 0x8a, 0xa9, 0xa1, 0x2c, 0x12, 0xe1,
0xca, 0xc8, 0x80, 0x15, 0x00, 0xf2, 0xca, 0x4f
};
memcpy(Digest,EmptyHash,sizeof(Digest));
}
}
bool HashValue::operator == (const HashValue &cmp)
{
if (Type==HASH_NONE || cmp.Type==HASH_NONE)
return true;
if (Type==HASH_RAR14 && cmp.Type==HASH_RAR14 ||
Type==HASH_CRC32 && cmp.Type==HASH_CRC32)
return CRC32==cmp.CRC32;
if (Type==HASH_BLAKE2 && cmp.Type==HASH_BLAKE2)
return memcmp(Digest,cmp.Digest,sizeof(Digest))==0;
return false;
}
DataHash::DataHash()
{
blake2ctx=NULL;
HashType=HASH_NONE;
#ifdef RAR_SMP
ThPool=NULL;
MaxThreads=0;
#endif
}
DataHash::~DataHash()
{
#ifdef RAR_SMP
DestroyThreadPool(ThPool);
#endif
cleandata(&CurCRC32, sizeof(CurCRC32));
if (blake2ctx!=NULL)
{
cleandata(blake2ctx, sizeof(blake2sp_state));
delete blake2ctx;
}
}
void DataHash::Init(HASH_TYPE Type,uint MaxThreads)
{
if (blake2ctx==NULL)
blake2ctx=new blake2sp_state;
HashType=Type;
if (Type==HASH_RAR14)
CurCRC32=0;
if (Type==HASH_CRC32)
CurCRC32=0xffffffff; // Initial CRC32 value.
if (Type==HASH_BLAKE2)
blake2sp_init(blake2ctx);
#ifdef RAR_SMP
DataHash::MaxThreads=Min(MaxThreads,MaxHashThreads);
#endif
}
void DataHash::Update(const void *Data,size_t DataSize)
{
#ifndef SFX_MODULE
if (HashType==HASH_RAR14)
CurCRC32=Checksum14((ushort)CurCRC32,Data,DataSize);
#endif
if (HashType==HASH_CRC32)
CurCRC32=CRC32(CurCRC32,Data,DataSize);
if (HashType==HASH_BLAKE2)
{
#ifdef RAR_SMP
if (MaxThreads>1 && ThPool==NULL)
ThPool=CreateThreadPool();
blake2ctx->ThPool=ThPool;
blake2ctx->MaxThreads=MaxThreads;
#endif
blake2sp_update( blake2ctx, (byte *)Data, DataSize);
}
}
void DataHash::Result(HashValue *Result)
{
Result->Type=HashType;
if (HashType==HASH_RAR14)
Result->CRC32=CurCRC32;
if (HashType==HASH_CRC32)
Result->CRC32=CurCRC32^0xffffffff;
if (HashType==HASH_BLAKE2)
{
// Preserve the original context, so we can continue hashing if necessary.
blake2sp_state res=*blake2ctx;
blake2sp_final(&res,Result->Digest);
}
}
uint DataHash::GetCRC32()
{
return HashType==HASH_CRC32 ? CurCRC32^0xffffffff : 0;
}
bool DataHash::Cmp(HashValue *CmpValue,byte *Key)
{
HashValue Final;
Result(&Final);
if (Key!=NULL)
ConvertHashToMAC(&Final,Key);
return Final==*CmpValue;
}

52
reference/unrar/hash.hpp Normal file
View File

@@ -0,0 +1,52 @@
#ifndef _RAR_DATAHASH_
#define _RAR_DATAHASH_
enum HASH_TYPE {HASH_NONE,HASH_RAR14,HASH_CRC32,HASH_BLAKE2};
struct HashValue
{
void Init(HASH_TYPE Type);
bool operator == (const HashValue &cmp);
bool operator != (const HashValue &cmp) {return !(*this==cmp);}
HASH_TYPE Type;
union
{
uint CRC32;
byte Digest[SHA256_DIGEST_SIZE];
};
};
#ifdef RAR_SMP
class ThreadPool;
class DataHash;
#endif
class DataHash
{
private:
HASH_TYPE HashType;
uint CurCRC32;
blake2sp_state *blake2ctx;
#ifdef RAR_SMP
ThreadPool *ThPool;
uint MaxThreads;
// Upper limit for maximum threads to prevent wasting threads in pool.
static const uint MaxHashThreads=8;
#endif
public:
DataHash();
~DataHash();
void Init(HASH_TYPE Type,uint MaxThreads);
void Update(const void *Data,size_t DataSize);
void Result(HashValue *Result);
uint GetCRC32();
bool Cmp(HashValue *CmpValue,byte *Key);
HASH_TYPE Type() {return HashType;}
};
#endif

View File

@@ -0,0 +1,61 @@
#include "rar.hpp"
void FileHeader::Reset(size_t SubDataSize)
{
SubData.Alloc(SubDataSize);
BaseBlock::Reset();
FileHash.Init(HASH_NONE);
mtime.Reset();
atime.Reset();
ctime.Reset();
SplitBefore=false;
SplitAfter=false;
UnknownUnpSize=0;
SubFlags=0; // Important for RAR 3.0 subhead.
CryptMethod=CRYPT_NONE;
Encrypted=false;
SaltSet=false;
UsePswCheck=false;
UseHashKey=false;
Lg2Count=0;
Solid=false;
Dir=false;
WinSize=0;
Inherited=false;
SubBlock=false;
CommentInHeader=false;
Version=false;
LargeFile=false;
RedirType=FSREDIR_NONE;
DirTarget=false;
UnixOwnerSet=false;
}
FileHeader& FileHeader::operator = (FileHeader &hd)
{
SubData.Reset();
memcpy(this,&hd,sizeof(*this));
SubData.CleanData();
SubData=hd.SubData;
return *this;
}
void MainHeader::Reset()
{
HighPosAV=0;
PosAV=0;
CommentInHeader=false;
PackComment=false;
Locator=false;
QOpenOffset=0;
QOpenMaxSize=0;
RROffset=0;
RRMaxSize=0;
}

380
reference/unrar/headers.hpp Normal file
View File

@@ -0,0 +1,380 @@
#ifndef _RAR_HEADERS_
#define _RAR_HEADERS_
#define SIZEOF_MARKHEAD3 7 // Size of RAR 4.x archive mark header.
#define SIZEOF_MAINHEAD14 7 // Size of RAR 1.4 main archive header.
#define SIZEOF_MAINHEAD3 13 // Size of RAR 4.x main archive header.
#define SIZEOF_FILEHEAD14 21 // Size of RAR 1.4 file header.
#define SIZEOF_FILEHEAD3 32 // Size of RAR 3.0 file header.
#define SIZEOF_SHORTBLOCKHEAD 7
#define SIZEOF_LONGBLOCKHEAD 11
#define SIZEOF_SUBBLOCKHEAD 14
#define SIZEOF_COMMHEAD 13
#define SIZEOF_PROTECTHEAD 26
#define SIZEOF_AVHEAD 14
#define SIZEOF_SIGNHEAD 15
#define SIZEOF_UOHEAD 18
#define SIZEOF_MACHEAD 22
#define SIZEOF_EAHEAD 24
#define SIZEOF_BEEAHEAD 24
#define SIZEOF_STREAMHEAD 26
#define VER_PACK 29
#define VER_PACK5 50 // It is stored as 0, but we subtract 50 when saving an archive.
#define VER_UNPACK 29
#define VER_UNPACK5 50 // It is stored as 0, but we add 50 when reading an archive.
#define MHD_VOLUME 0x0001U
// Old style main archive comment embed into main archive header. Must not
// be used in new archives anymore.
#define MHD_COMMENT 0x0002U
#define MHD_LOCK 0x0004U
#define MHD_SOLID 0x0008U
#define MHD_PACK_COMMENT 0x0010U
#define MHD_NEWNUMBERING 0x0010U
#define MHD_AV 0x0020U
#define MHD_PROTECT 0x0040U
#define MHD_PASSWORD 0x0080U
#define MHD_FIRSTVOLUME 0x0100U
#define LHD_SPLIT_BEFORE 0x0001U
#define LHD_SPLIT_AFTER 0x0002U
#define LHD_PASSWORD 0x0004U
// Old style file comment embed into file header. Must not be used
// in new archives anymore.
#define LHD_COMMENT 0x0008U
// For non-file subheaders it denotes 'subblock having a parent file' flag.
#define LHD_SOLID 0x0010U
#define LHD_WINDOWMASK 0x00e0U
#define LHD_WINDOW64 0x0000U
#define LHD_WINDOW128 0x0020U
#define LHD_WINDOW256 0x0040U
#define LHD_WINDOW512 0x0060U
#define LHD_WINDOW1024 0x0080U
#define LHD_WINDOW2048 0x00a0U
#define LHD_WINDOW4096 0x00c0U
#define LHD_DIRECTORY 0x00e0U
#define LHD_LARGE 0x0100U
#define LHD_UNICODE 0x0200U
#define LHD_SALT 0x0400U
#define LHD_VERSION 0x0800U
#define LHD_EXTTIME 0x1000U
#define SKIP_IF_UNKNOWN 0x4000U
#define LONG_BLOCK 0x8000U
#define EARC_NEXT_VOLUME 0x0001U // Not last volume.
#define EARC_DATACRC 0x0002U // Store CRC32 of RAR archive (now is used only in volumes).
#define EARC_REVSPACE 0x0004U // Reserve space for end of REV file 7 byte record.
#define EARC_VOLNUMBER 0x0008U // Store a number of current volume.
enum HEADER_TYPE {
// RAR 5.0 header types.
HEAD_MARK=0x00, HEAD_MAIN=0x01, HEAD_FILE=0x02, HEAD_SERVICE=0x03,
HEAD_CRYPT=0x04, HEAD_ENDARC=0x05, HEAD_UNKNOWN=0xff,
// RAR 1.5 - 4.x header types.
HEAD3_MARK=0x72,HEAD3_MAIN=0x73,HEAD3_FILE=0x74,HEAD3_CMT=0x75,
HEAD3_AV=0x76,HEAD3_OLDSERVICE=0x77,HEAD3_PROTECT=0x78,HEAD3_SIGN=0x79,
HEAD3_SERVICE=0x7a,HEAD3_ENDARC=0x7b
};
enum { EA_HEAD=0x100,UO_HEAD=0x101,MAC_HEAD=0x102,BEEA_HEAD=0x103,
NTACL_HEAD=0x104,STREAM_HEAD=0x105 };
// Internal implementation, depends on archive format version.
enum HOST_SYSTEM {
// RAR 5.0 host OS
HOST5_WINDOWS=0,HOST5_UNIX=1,
// RAR 3.0 host OS.
HOST_MSDOS=0,HOST_OS2=1,HOST_WIN32=2,HOST_UNIX=3,HOST_MACOS=4,
HOST_BEOS=5,HOST_MAX
};
// Unified archive format independent implementation.
enum HOST_SYSTEM_TYPE {
HSYS_WINDOWS, HSYS_UNIX, HSYS_UNKNOWN
};
// We also use these values in extra field, so do not modify them.
enum FILE_SYSTEM_REDIRECT {
FSREDIR_NONE=0, FSREDIR_UNIXSYMLINK, FSREDIR_WINSYMLINK, FSREDIR_JUNCTION,
FSREDIR_HARDLINK, FSREDIR_FILECOPY
};
#define SUBHEAD_TYPE_CMT L"CMT"
#define SUBHEAD_TYPE_QOPEN L"QO"
#define SUBHEAD_TYPE_ACL L"ACL"
#define SUBHEAD_TYPE_STREAM L"STM"
#define SUBHEAD_TYPE_UOWNER L"UOW"
#define SUBHEAD_TYPE_AV L"AV"
#define SUBHEAD_TYPE_RR L"RR"
#define SUBHEAD_TYPE_OS2EA L"EA2"
/* new file inherits a subblock when updating a host file */
#define SUBHEAD_FLAGS_INHERITED 0x80000000
#define SUBHEAD_FLAGS_CMT_UNICODE 0x00000001
struct MarkHeader
{
byte Mark[8];
// Following fields are virtual and not present in real blocks.
uint HeadSize;
};
struct BaseBlock
{
uint HeadCRC; // 'ushort' for RAR 1.5.
HEADER_TYPE HeaderType; // 1 byte for RAR 1.5.
uint Flags; // 'ushort' for RAR 1.5.
uint HeadSize; // 'ushort' for RAR 1.5, up to 2 MB for RAR 5.0.
bool SkipIfUnknown;
void Reset()
{
SkipIfUnknown=false;
}
};
struct BlockHeader:BaseBlock
{
uint DataSize;
};
struct MainHeader:BaseBlock
{
ushort HighPosAV;
uint PosAV;
bool CommentInHeader;
bool PackComment; // For RAR 1.4 archive format only.
bool Locator;
uint64 QOpenOffset; // Offset of quick list record.
uint64 QOpenMaxSize; // Maximum size of QOpen offset in locator extra field.
uint64 RROffset; // Offset of recovery record.
uint64 RRMaxSize; // Maximum size of RR offset in locator extra field.
void Reset();
};
struct FileHeader:BlockHeader
{
byte HostOS;
byte UnpVer;
byte Method;
union {
uint FileAttr;
uint SubFlags;
};
wchar FileName[NM];
Array<byte> SubData;
RarTime mtime;
RarTime ctime;
RarTime atime;
int64 PackSize;
int64 UnpSize;
int64 MaxSize; // Reserve size bytes for vint of this size.
HashValue FileHash;
uint FileFlags;
bool SplitBefore;
bool SplitAfter;
bool UnknownUnpSize;
bool Encrypted;
CRYPT_METHOD CryptMethod;
bool SaltSet;
byte Salt[SIZE_SALT50];
byte InitV[SIZE_INITV];
bool UsePswCheck;
byte PswCheck[SIZE_PSWCHECK];
// Use HMAC calculated from HashKey and checksum instead of plain checksum.
bool UseHashKey;
// Key to convert checksum to HMAC. Derived from password with PBKDF2
// using additional iterations.
byte HashKey[SHA256_DIGEST_SIZE];
uint Lg2Count; // Log2 of PBKDF2 repetition count.
bool Solid;
bool Dir;
bool CommentInHeader; // RAR 2.0 file comment.
bool Version; // name.ext;ver file name containing the version number.
size_t WinSize;
bool Inherited; // New file inherits a subblock when updating a host file (for subblocks only).
// 'true' if file sizes use 8 bytes instead of 4. Not used in RAR 5.0.
bool LargeFile;
// 'true' for HEAD_SERVICE block, which is a child of preceding file block.
// RAR 4.x uses 'solid' flag to indicate child subheader blocks in archives.
bool SubBlock;
HOST_SYSTEM_TYPE HSType;
FILE_SYSTEM_REDIRECT RedirType;
wchar RedirName[NM];
bool DirTarget;
bool UnixOwnerSet,UnixOwnerNumeric,UnixGroupNumeric;
char UnixOwnerName[256],UnixGroupName[256];
#ifdef _UNIX
uid_t UnixOwnerID;
gid_t UnixGroupID;
#else // Need these Unix fields in Windows too for 'list' command.
uint UnixOwnerID;
uint UnixGroupID;
#endif
void Reset(size_t SubDataSize=0);
bool CmpName(const wchar *Name)
{
return(wcscmp(FileName,Name)==0);
}
FileHeader& operator = (FileHeader &hd);
};
struct EndArcHeader:BaseBlock
{
// Optional CRC32 of entire archive up to start of EndArcHeader block.
// Present in RAR 4.x archives if EARC_DATACRC flag is set.
uint ArcDataCRC;
uint VolNumber; // Optional number of current volume.
// 7 additional zero bytes can be stored here if EARC_REVSPACE is set.
bool NextVolume; // Not last volume.
bool DataCRC;
bool RevSpace;
bool StoreVolNumber;
void Reset()
{
BaseBlock::Reset();
NextVolume=false;
DataCRC=false;
RevSpace=false;
StoreVolNumber=false;
}
};
struct CryptHeader:BaseBlock
{
bool UsePswCheck;
uint Lg2Count; // Log2 of PBKDF2 repetition count.
byte Salt[SIZE_SALT50];
byte PswCheck[SIZE_PSWCHECK];
};
// SubBlockHeader and its successors were used in RAR 2.x format.
// RAR 4.x uses FileHeader with HEAD_SERVICE HeaderType for subblocks.
struct SubBlockHeader:BlockHeader
{
ushort SubType;
byte Level;
};
struct CommentHeader:BaseBlock
{
ushort UnpSize;
byte UnpVer;
byte Method;
ushort CommCRC;
};
struct ProtectHeader:BlockHeader
{
byte Version;
ushort RecSectors;
uint TotalBlocks;
byte Mark[8];
};
struct AVHeader:BaseBlock
{
byte UnpVer;
byte Method;
byte AVVer;
uint AVInfoCRC;
};
struct SignHeader:BaseBlock
{
uint CreationTime;
ushort ArcNameSize;
ushort UserNameSize;
};
struct UnixOwnersHeader:SubBlockHeader
{
ushort OwnerNameSize;
ushort GroupNameSize;
/* dummy */
char OwnerName[256];
char GroupName[256];
};
struct EAHeader:SubBlockHeader
{
uint UnpSize;
byte UnpVer;
byte Method;
uint EACRC;
};
struct StreamHeader:SubBlockHeader
{
uint UnpSize;
byte UnpVer;
byte Method;
uint StreamCRC;
ushort StreamNameSize;
char StreamName[260];
};
struct MacFInfoHeader:SubBlockHeader
{
uint fileType;
uint fileCreator;
};
#endif

View File

@@ -0,0 +1,100 @@
#ifndef _RAR_HEADERS5_
#define _RAR_HEADERS5_
#define SIZEOF_MARKHEAD5 8 // RAR 5.0 signature length.
#define SIZEOF_SHORTBLOCKHEAD5 7 // Smallest RAR 5.0 block size.
// RAR 5.0 block flags common for all blocks.
// Additional extra area is present in the end of block header.
#define HFL_EXTRA 0x0001
// Additional data area is present in the end of block header.
#define HFL_DATA 0x0002
// Unknown blocks with this flag must be skipped when updating an archive.
#define HFL_SKIPIFUNKNOWN 0x0004
// Data area of this block is continuing from previous volume.
#define HFL_SPLITBEFORE 0x0008
// Data area of this block is continuing in next volume.
#define HFL_SPLITAFTER 0x0010
// Block depends on preceding file block.
#define HFL_CHILD 0x0020
// Preserve a child block if host is modified.
#define HFL_INHERITED 0x0040
// RAR 5.0 main archive header specific flags.
#define MHFL_VOLUME 0x0001 // Volume.
#define MHFL_VOLNUMBER 0x0002 // Volume number field is present. True for all volumes except first.
#define MHFL_SOLID 0x0004 // Solid archive.
#define MHFL_PROTECT 0x0008 // Recovery record is present.
#define MHFL_LOCK 0x0010 // Locked archive.
// RAR 5.0 file header specific flags.
#define FHFL_DIRECTORY 0x0001 // Directory.
#define FHFL_UTIME 0x0002 // Time field in Unix format is present.
#define FHFL_CRC32 0x0004 // CRC32 field is present.
#define FHFL_UNPUNKNOWN 0x0008 // Unknown unpacked size.
// RAR 5.0 end of archive header specific flags.
#define EHFL_NEXTVOLUME 0x0001 // Not last volume.
// RAR 5.0 archive encryption header specific flags.
#define CHFL_CRYPT_PSWCHECK 0x0001 // Password check data is present.
// RAR 5.0 file compression flags.
#define FCI_ALGO_BIT0 0x0001 // Version of compression algorithm.
#define FCI_ALGO_BIT1 0x0002 // 0 .. 63.
#define FCI_ALGO_BIT2 0x0004
#define FCI_ALGO_BIT3 0x0008
#define FCI_ALGO_BIT4 0x0010
#define FCI_ALGO_BIT5 0x0020
#define FCI_SOLID 0x0040 // Solid flag.
#define FCI_METHOD_BIT0 0x0080 // Compression method.
#define FCI_METHOD_BIT1 0x0100 // 0 .. 5 (6 and 7 are not used).
#define FCI_METHOD_BIT2 0x0200
#define FCI_DICT_BIT0 0x0400 // Dictionary size.
#define FCI_DICT_BIT1 0x0800 // 128 KB .. 4 GB.
#define FCI_DICT_BIT2 0x1000
#define FCI_DICT_BIT3 0x2000
// Main header extra field values.
#define MHEXTRA_LOCATOR 0x01 // Position of quick list and other blocks.
// Flags for MHEXTRA_LOCATOR.
#define MHEXTRA_LOCATOR_QLIST 0x01 // Quick open offset is present.
#define MHEXTRA_LOCATOR_RR 0x02 // Recovery record offset is present.
// File and service header extra field values.
#define FHEXTRA_CRYPT 0x01 // Encryption parameters.
#define FHEXTRA_HASH 0x02 // File hash.
#define FHEXTRA_HTIME 0x03 // High precision file time.
#define FHEXTRA_VERSION 0x04 // File version information.
#define FHEXTRA_REDIR 0x05 // File system redirection (links, etc.).
#define FHEXTRA_UOWNER 0x06 // Unix owner and group information.
#define FHEXTRA_SUBDATA 0x07 // Service header subdata array.
// Hash type values for FHEXTRA_HASH.
#define FHEXTRA_HASH_BLAKE2 0x00
// Flags for FHEXTRA_HTIME.
#define FHEXTRA_HTIME_UNIXTIME 0x01 // Use Unix time_t format.
#define FHEXTRA_HTIME_MTIME 0x02 // mtime is present.
#define FHEXTRA_HTIME_CTIME 0x04 // ctime is present.
#define FHEXTRA_HTIME_ATIME 0x08 // atime is present.
#define FHEXTRA_HTIME_UNIX_NS 0x10 // Unix format with nanosecond precision.
// Flags for FHEXTRA_CRYPT.
#define FHEXTRA_CRYPT_PSWCHECK 0x01 // Store password check data.
#define FHEXTRA_CRYPT_HASHMAC 0x02 // Use MAC for unpacked data checksums.
// Flags for FHEXTRA_REDIR.
#define FHEXTRA_REDIR_DIR 0x01 // Link target is directory.
// Flags for FHEXTRA_UOWNER.
#define FHEXTRA_UOWNER_UNAME 0x01 // User name string is present.
#define FHEXTRA_UOWNER_GNAME 0x02 // Group name string is present.
#define FHEXTRA_UOWNER_NUMUID 0x04 // Numeric user ID is present.
#define FHEXTRA_UOWNER_NUMGID 0x08 // Numeric group ID is present.
#endif

24
reference/unrar/isnt.cpp Normal file
View File

@@ -0,0 +1,24 @@
#include "rar.hpp"
#ifdef _WIN_ALL
DWORD WinNT()
{
static int dwPlatformId=-1;
static DWORD dwMajorVersion,dwMinorVersion;
if (dwPlatformId==-1)
{
OSVERSIONINFO WinVer;
WinVer.dwOSVersionInfoSize=sizeof(WinVer);
GetVersionEx(&WinVer);
dwPlatformId=WinVer.dwPlatformId;
dwMajorVersion=WinVer.dwMajorVersion;
dwMinorVersion=WinVer.dwMinorVersion;
}
DWORD Result=0;
if (dwPlatformId==VER_PLATFORM_WIN32_NT)
Result=dwMajorVersion*0x100+dwMinorVersion;
return Result;
}
#endif

13
reference/unrar/isnt.hpp Normal file
View File

@@ -0,0 +1,13 @@
#ifndef _RAR_ISNT_
#define _RAR_ISNT_
enum WINNT_VERSION {
WNT_NONE=0,WNT_NT351=0x0333,WNT_NT4=0x0400,WNT_W2000=0x0500,
WNT_WXP=0x0501,WNT_W2003=0x0502,WNT_VISTA=0x0600,WNT_W7=0x0601,
WNT_W8=0x0602,WNT_W81=0x0603,WNT_W10=0x0a00
};
DWORD WinNT();
#endif

View File

@@ -0,0 +1,42 @@
****** ***** ****** UnRAR - free utility for RAR archives
** ** ** ** ** ** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
****** ******* ****** License for use and distribution of
** ** ** ** ** ** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
** ** ** ** ** ** FREE portable version
~~~~~~~~~~~~~~~~~~~~~
The source code of UnRAR utility is freeware. This means:
1. All copyrights to RAR and the utility UnRAR are exclusively
owned by the author - Alexander Roshal.
2. UnRAR source code may be used in any software to handle
RAR archives without limitations free of charge, but cannot be
used to develop RAR (WinRAR) compatible archiver and to
re-create RAR compression algorithm, which is proprietary.
Distribution of modified UnRAR source code in separate form
or as a part of other software is permitted, provided that
full text of this paragraph, starting from "UnRAR source code"
words, is included in license, or in documentation if license
is not available, and in source code comments of resulting package.
3. The UnRAR utility may be freely distributed. It is allowed
to distribute UnRAR inside of other software packages.
4. THE RAR ARCHIVER AND THE UnRAR UTILITY ARE DISTRIBUTED "AS IS".
NO WARRANTY OF ANY KIND IS EXPRESSED OR IMPLIED. YOU USE AT
YOUR OWN RISK. THE AUTHOR WILL NOT BE LIABLE FOR DATA LOSS,
DAMAGES, LOSS OF PROFITS OR ANY OTHER KIND OF LOSS WHILE USING
OR MISUSING THIS SOFTWARE.
5. Installing and using the UnRAR utility signifies acceptance of
these terms and conditions of the license.
6. If you don't agree with terms of the license you must remove
UnRAR files from your storage devices and cease to use the
utility.
Thank you for your interest in RAR and UnRAR.
Alexander L. Roshal

472
reference/unrar/list.cpp Normal file
View File

@@ -0,0 +1,472 @@
#include "rar.hpp"
static void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bool Technical,bool Bare);
static void ListSymLink(Archive &Arc);
static void ListFileAttr(uint A,HOST_SYSTEM_TYPE HostType,wchar *AttrStr,size_t AttrSize);
static void ListOldSubHeader(Archive &Arc);
static void ListNewSubHeader(CommandData *Cmd,Archive &Arc);
void ListArchive(CommandData *Cmd)
{
int64 SumPackSize=0,SumUnpSize=0;
uint ArcCount=0,SumFileCount=0;
bool Technical=(Cmd->Command[1]=='T');
bool ShowService=Technical && Cmd->Command[2]=='A';
bool Bare=(Cmd->Command[1]=='B');
bool Verbose=(Cmd->Command[0]=='V');
wchar ArcName[NM];
while (Cmd->GetArcName(ArcName,ASIZE(ArcName)))
{
if (Cmd->ManualPassword)
Cmd->Password.Clean(); // Clean user entered password before processing next archive.
Archive Arc(Cmd);
#ifdef _WIN_ALL
Arc.RemoveSequentialFlag();
#endif
if (!Arc.WOpen(ArcName))
continue;
bool FileMatched=true;
while (1)
{
int64 TotalPackSize=0,TotalUnpSize=0;
uint FileCount=0;
if (Arc.IsArchive(true))
{
bool TitleShown=false;
if (!Bare)
{
Arc.ViewComment();
mprintf(L"\n%s: %s",St(MListArchive),Arc.FileName);
mprintf(L"\n%s: ",St(MListDetails));
uint SetCount=0;
const wchar *Fmt=Arc.Format==RARFMT14 ? L"RAR 1.4":(Arc.Format==RARFMT15 ? L"RAR 4":L"RAR 5");
mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", Fmt);
if (Arc.Solid)
mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListSolid));
if (Arc.SFXSize>0)
mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListSFX));
if (Arc.Volume)
if (Arc.Format==RARFMT50)
{
// RAR 5.0 archives store the volume number in main header,
// so it is already available now.
if (SetCount++ > 0)
mprintf(L", ");
mprintf(St(MVolumeNumber),Arc.VolNumber+1);
}
else
mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListVolume));
if (Arc.Protected)
mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListRR));
if (Arc.Locked)
mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListLock));
if (Arc.Encrypted)
mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListEncHead));
mprintf(L"\n");
}
wchar VolNumText[50];
*VolNumText=0;
while(Arc.ReadHeader()>0)
{
HEADER_TYPE HeaderType=Arc.GetHeaderType();
if (HeaderType==HEAD_ENDARC)
{
#ifndef SFX_MODULE
// Only RAR 1.5 archives store the volume number in end record.
if (Arc.EndArcHead.StoreVolNumber && Arc.Format==RARFMT15)
swprintf(VolNumText,ASIZE(VolNumText),L"%.10ls %u",St(MListVolume),Arc.VolNumber+1);
#endif
if (Technical && ShowService)
{
mprintf(L"\n%12ls: %ls",St(MListService),L"EOF");
if (*VolNumText!=0)
mprintf(L"\n%12ls: %ls",St(MListFlags),VolNumText);
mprintf(L"\n");
}
break;
}
switch(HeaderType)
{
case HEAD_FILE:
FileMatched=Cmd->IsProcessFile(Arc.FileHead)!=0;
if (FileMatched)
{
ListFileHeader(Arc,Arc.FileHead,TitleShown,Verbose,Technical,Bare);
if (!Arc.FileHead.SplitBefore)
{
TotalUnpSize+=Arc.FileHead.UnpSize;
FileCount++;
}
TotalPackSize+=Arc.FileHead.PackSize;
}
break;
case HEAD_SERVICE:
if (FileMatched && !Bare)
{
if (Technical && ShowService)
ListFileHeader(Arc,Arc.SubHead,TitleShown,Verbose,true,false);
}
break;
}
Arc.SeekToNext();
}
if (!Bare && !Technical)
if (TitleShown)
{
wchar UnpSizeText[20];
itoa(TotalUnpSize,UnpSizeText,ASIZE(UnpSizeText));
wchar PackSizeText[20];
itoa(TotalPackSize,PackSizeText,ASIZE(PackSizeText));
if (Verbose)
{
mprintf(L"\n----------- --------- -------- ----- ---------- ----- -------- ----");
mprintf(L"\n%21ls %9ls %3d%% %-27ls %u",UnpSizeText,
PackSizeText,ToPercentUnlim(TotalPackSize,TotalUnpSize),
VolNumText,FileCount);
}
else
{
mprintf(L"\n----------- --------- ---------- ----- ----");
mprintf(L"\n%21ls %-16ls %u",UnpSizeText,VolNumText,FileCount);
}
SumFileCount+=FileCount;
SumUnpSize+=TotalUnpSize;
SumPackSize+=TotalPackSize;
mprintf(L"\n");
}
else
mprintf(St(MListNoFiles));
ArcCount++;
#ifndef NOVOLUME
if (Cmd->VolSize!=0 && (Arc.FileHead.SplitAfter ||
Arc.GetHeaderType()==HEAD_ENDARC && Arc.EndArcHead.NextVolume) &&
MergeArchive(Arc,NULL,false,Cmd->Command[0]))
Arc.Seek(0,SEEK_SET);
else
#endif
break;
}
else
{
if (Cmd->ArcNames.ItemsCount()<2 && !Bare)
mprintf(St(MNotRAR),Arc.FileName);
break;
}
}
}
// Clean user entered password. Not really required, just for extra safety.
if (Cmd->ManualPassword)
Cmd->Password.Clean();
if (ArcCount>1 && !Bare && !Technical)
{
wchar UnpSizeText[20],PackSizeText[20];
itoa(SumUnpSize,UnpSizeText,ASIZE(UnpSizeText));
itoa(SumPackSize,PackSizeText,ASIZE(PackSizeText));
if (Verbose)
mprintf(L"%21ls %9ls %3d%% %28ls %u",UnpSizeText,PackSizeText,
ToPercentUnlim(SumPackSize,SumUnpSize),L"",SumFileCount);
else
mprintf(L"%21ls %18s %lu",UnpSizeText,L"",SumFileCount);
}
}
enum LISTCOL_TYPE {
LCOL_NAME,LCOL_ATTR,LCOL_SIZE,LCOL_PACKED,LCOL_RATIO,LCOL_CSUM,LCOL_ENCR
};
void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bool Technical,bool Bare)
{
wchar *Name=hd.FileName;
RARFORMAT Format=Arc.Format;
if (Bare)
{
mprintf(L"%s\n",Name);
return;
}
if (!TitleShown && !Technical)
{
if (Verbose)
{
mprintf(L"\n%ls",St(MListTitleV));
mprintf(L"\n----------- --------- -------- ----- ---------- ----- -------- ----");
}
else
{
mprintf(L"\n%ls",St(MListTitleL));
mprintf(L"\n----------- --------- ---------- ----- ----");
}
TitleShown=true;
}
wchar UnpSizeText[30],PackSizeText[30];
if (hd.UnpSize==INT64NDF)
wcscpy(UnpSizeText,L"?");
else
itoa(hd.UnpSize,UnpSizeText,ASIZE(UnpSizeText));
itoa(hd.PackSize,PackSizeText,ASIZE(PackSizeText));
wchar AttrStr[30];
if (hd.HeaderType==HEAD_SERVICE)
swprintf(AttrStr,ASIZE(AttrStr),L"%cB",hd.Inherited ? 'I' : '.');
else
ListFileAttr(hd.FileAttr,hd.HSType,AttrStr,ASIZE(AttrStr));
wchar RatioStr[10];
if (hd.SplitBefore && hd.SplitAfter)
wcscpy(RatioStr,L"<->");
else
if (hd.SplitBefore)
wcscpy(RatioStr,L"<--");
else
if (hd.SplitAfter)
wcscpy(RatioStr,L"-->");
else
swprintf(RatioStr,ASIZE(RatioStr),L"%d%%",ToPercentUnlim(hd.PackSize,hd.UnpSize));
wchar DateStr[50];
hd.mtime.GetText(DateStr,ASIZE(DateStr),Technical);
if (Technical)
{
mprintf(L"\n%12s: %s",St(MListName),Name);
bool FileBlock=hd.HeaderType==HEAD_FILE;
if (!FileBlock && Arc.SubHead.CmpName(SUBHEAD_TYPE_STREAM))
{
mprintf(L"\n%12ls: %ls",St(MListType),St(MListStream));
wchar StreamName[NM];
GetStreamNameNTFS(Arc,StreamName,ASIZE(StreamName));
mprintf(L"\n%12ls: %ls",St(MListTarget),StreamName);
}
else
{
const wchar *Type=St(FileBlock ? (hd.Dir ? MListDir:MListFile):MListService);
if (hd.RedirType!=FSREDIR_NONE)
switch(hd.RedirType)
{
case FSREDIR_UNIXSYMLINK:
Type=St(MListUSymlink); break;
case FSREDIR_WINSYMLINK:
Type=St(MListWSymlink); break;
case FSREDIR_JUNCTION:
Type=St(MListJunction); break;
case FSREDIR_HARDLINK:
Type=St(MListHardlink); break;
case FSREDIR_FILECOPY:
Type=St(MListCopy); break;
}
mprintf(L"\n%12ls: %ls",St(MListType),Type);
if (hd.RedirType!=FSREDIR_NONE)
if (Format==RARFMT15)
{
char LinkTargetA[NM];
if (Arc.FileHead.Encrypted)
{
// Link data are encrypted. We would need to ask for password
// and initialize decryption routine to display the link target.
strncpyz(LinkTargetA,"*<-?->",ASIZE(LinkTargetA));
}
else
{
int DataSize=(int)Min(hd.PackSize,ASIZE(LinkTargetA)-1);
Arc.Read(LinkTargetA,DataSize);
LinkTargetA[DataSize > 0 ? DataSize : 0] = 0;
}
wchar LinkTarget[NM];
CharToWide(LinkTargetA,LinkTarget,ASIZE(LinkTarget));
mprintf(L"\n%12ls: %ls",St(MListTarget),LinkTarget);
}
else
mprintf(L"\n%12ls: %ls",St(MListTarget),hd.RedirName);
}
if (!hd.Dir)
{
mprintf(L"\n%12ls: %ls",St(MListSize),UnpSizeText);
mprintf(L"\n%12ls: %ls",St(MListPacked),PackSizeText);
mprintf(L"\n%12ls: %ls",St(MListRatio),RatioStr);
}
if (hd.mtime.IsSet())
mprintf(L"\n%12ls: %ls",St(MListMtime),DateStr);
if (hd.ctime.IsSet())
{
hd.ctime.GetText(DateStr,ASIZE(DateStr),true);
mprintf(L"\n%12ls: %ls",St(MListCtime),DateStr);
}
if (hd.atime.IsSet())
{
hd.atime.GetText(DateStr,ASIZE(DateStr),true);
mprintf(L"\n%12ls: %ls",St(MListAtime),DateStr);
}
mprintf(L"\n%12ls: %ls",St(MListAttr),AttrStr);
if (hd.FileHash.Type==HASH_CRC32)
mprintf(L"\n%12ls: %8.8X",
hd.UseHashKey ? L"CRC32 MAC":hd.SplitAfter ? L"Pack-CRC32":L"CRC32",
hd.FileHash.CRC32);
if (hd.FileHash.Type==HASH_BLAKE2)
{
wchar BlakeStr[BLAKE2_DIGEST_SIZE*2+1];
BinToHex(hd.FileHash.Digest,BLAKE2_DIGEST_SIZE,NULL,BlakeStr,ASIZE(BlakeStr));
mprintf(L"\n%12ls: %ls",
hd.UseHashKey ? L"BLAKE2 MAC":hd.SplitAfter ? L"Pack-BLAKE2":L"BLAKE2",
BlakeStr);
}
const wchar *HostOS=L"";
if (Format==RARFMT50 && hd.HSType!=HSYS_UNKNOWN)
HostOS=hd.HSType==HSYS_WINDOWS ? L"Windows":L"Unix";
if (Format==RARFMT15)
{
static const wchar *RarOS[]={
L"DOS",L"OS/2",L"Windows",L"Unix",L"Mac OS",L"BeOS",L"WinCE",L"",L"",L""
};
if (hd.HostOS<ASIZE(RarOS))
HostOS=RarOS[hd.HostOS];
}
if (*HostOS!=0)
mprintf(L"\n%12ls: %ls",St(MListHostOS),HostOS);
mprintf(L"\n%12ls: RAR %ls(v%d) -m%d -md=%d%s",St(MListCompInfo),
Format==RARFMT15 ? L"3.0":L"5.0",hd.UnpVer,hd.Method,
hd.WinSize>=0x100000 ? hd.WinSize/0x100000:hd.WinSize/0x400,
hd.WinSize>=0x100000 ? L"M":L"K");
if (hd.Solid || hd.Encrypted)
{
mprintf(L"\n%12ls: ",St(MListFlags));
if (hd.Solid)
mprintf(L"%ls ",St(MListSolid));
if (hd.Encrypted)
mprintf(L"%ls ",St(MListEnc));
}
if (hd.Version)
{
uint Version=ParseVersionFileName(Name,false);
if (Version!=0)
mprintf(L"\n%12ls: %u",St(MListFileVer),Version);
}
if (hd.UnixOwnerSet)
{
mprintf(L"\n%12ls: ",L"Unix owner");
if (*hd.UnixOwnerName!=0)
mprintf(L"%ls:",GetWide(hd.UnixOwnerName));
if (*hd.UnixGroupName!=0)
mprintf(L"%ls",GetWide(hd.UnixGroupName));
if ((*hd.UnixOwnerName!=0 || *hd.UnixGroupName!=0) && (hd.UnixOwnerNumeric || hd.UnixGroupNumeric))
mprintf(L" ");
if (hd.UnixOwnerNumeric)
mprintf(L"#%d:",hd.UnixOwnerID);
if (hd.UnixGroupNumeric)
mprintf(L"#%d:",hd.UnixGroupID);
}
mprintf(L"\n");
return;
}
mprintf(L"\n%c%10ls %9ls ",hd.Encrypted ? '*' : ' ',AttrStr,UnpSizeText);
if (Verbose)
mprintf(L"%9ls %4ls ",PackSizeText,RatioStr);
mprintf(L" %ls ",DateStr);
if (Verbose)
{
if (hd.FileHash.Type==HASH_CRC32)
mprintf(L"%8.8X ",hd.FileHash.CRC32);
else
if (hd.FileHash.Type==HASH_BLAKE2)
{
byte *S=hd.FileHash.Digest;
mprintf(L"%02x%02x..%02x ",S[0],S[1],S[31]);
}
else
mprintf(L"???????? ");
}
mprintf(L"%ls",Name);
}
/*
void ListSymLink(Archive &Arc)
{
if (Arc.FileHead.HSType==HSYS_UNIX && (Arc.FileHead.FileAttr & 0xF000)==0xA000)
if (Arc.FileHead.Encrypted)
{
// Link data are encrypted. We would need to ask for password
// and initialize decryption routine to display the link target.
mprintf(L"\n%22ls %ls",L"-->",L"*<-?->");
}
else
{
char FileName[NM];
uint DataSize=(uint)Min(Arc.FileHead.PackSize,sizeof(FileName)-1);
Arc.Read(FileName,DataSize);
FileName[DataSize]=0;
mprintf(L"\n%22ls %ls",L"-->",GetWide(FileName));
}
}
*/
void ListFileAttr(uint A,HOST_SYSTEM_TYPE HostType,wchar *AttrStr,size_t AttrSize)
{
switch(HostType)
{
case HSYS_WINDOWS:
swprintf(AttrStr,AttrSize,L"%c%c%c%c%c%c%c",
(A & 0x2000)!=0 ? 'I' : '.', // Not content indexed.
(A & 0x0800)!=0 ? 'C' : '.', // Compressed.
(A & 0x0020)!=0 ? 'A' : '.', // Archive.
(A & 0x0010)!=0 ? 'D' : '.', // Directory.
(A & 0x0004)!=0 ? 'S' : '.', // System.
(A & 0x0002)!=0 ? 'H' : '.', // Hidden.
(A & 0x0001)!=0 ? 'R' : '.'); // Read-only.
break;
case HSYS_UNIX:
switch (A & 0xF000)
{
case 0x4000:
AttrStr[0]='d';
break;
case 0xA000:
AttrStr[0]='l';
break;
default:
AttrStr[0]='-';
break;
}
swprintf(AttrStr+1,AttrSize-1,L"%c%c%c%c%c%c%c%c%c",
(A & 0x0100) ? 'r' : '-',
(A & 0x0080) ? 'w' : '-',
(A & 0x0040) ? ((A & 0x0800)!=0 ? 's':'x'):((A & 0x0800)!=0 ? 'S':'-'),
(A & 0x0020) ? 'r' : '-',
(A & 0x0010) ? 'w' : '-',
(A & 0x0008) ? ((A & 0x0400)!=0 ? 's':'x'):((A & 0x0400)!=0 ? 'S':'-'),
(A & 0x0004) ? 'r' : '-',
(A & 0x0002) ? 'w' : '-',
(A & 0x0001) ? ((A & 0x200)!=0 ? 't' : 'x') : '-');
break;
case HSYS_UNKNOWN:
wcscpy(AttrStr,L"?");
break;
}
}

6
reference/unrar/list.hpp Normal file
View File

@@ -0,0 +1,6 @@
#ifndef _RAR_LIST_
#define _RAR_LIST_
void ListArchive(CommandData *Cmd);
#endif

381
reference/unrar/loclang.hpp Normal file
View File

@@ -0,0 +1,381 @@
#define MYesNo L"_Yes_No"
#define MYesNoAll L"_Yes_No_All"
#define MYesNoAllQ L"_Yes_No_All_nEver_Quit"
#define MYesNoAllRenQ L"_Yes_No_All_nEver_Rename_Quit"
#define MContinueQuit L"_Continue_Quit"
#define MRetryAbort L"_Retry_Abort"
#define MCopyright L"\nRAR %s Copyright (c) 1993-%d Alexander Roshal %d %s %d"
#define MRegTo L"\nRegistered to %s\n"
#define MShare L"\nTrial version Type 'rar -?' for help\n"
#define MRegKeyWarning L"\nAvailable license key is valid only for %s\n"
#define MUCopyright L"\nUNRAR %s freeware Copyright (c) 1993-%d Alexander Roshal\n"
#define MBeta L"beta"
#define Mx86 L"x86"
#define Mx64 L"x64"
#define MMonthJan L"Jan"
#define MMonthFeb L"Feb"
#define MMonthMar L"Mar"
#define MMonthApr L"Apr"
#define MMonthMay L"May"
#define MMonthJun L"Jun"
#define MMonthJul L"Jul"
#define MMonthAug L"Aug"
#define MMonthSep L"Sep"
#define MMonthOct L"Oct"
#define MMonthNov L"Nov"
#define MMonthDec L"Dec"
#define MRARTitle1 L"\nUsage: rar <command> -<switch 1> -<switch N> <archive> <files...>"
#define MUNRARTitle1 L"\nUsage: unrar <command> -<switch 1> -<switch N> <archive> <files...>"
#define MRARTitle2 L"\n <@listfiles...> <path_to_extract\\>"
#define MCHelpCmd L"\n\n<Commands>"
#define MCHelpCmdA L"\n a Add files to archive"
#define MCHelpCmdC L"\n c Add archive comment"
#define MCHelpCmdCH L"\n ch Change archive parameters"
#define MCHelpCmdCW L"\n cw Write archive comment to file"
#define MCHelpCmdD L"\n d Delete files from archive"
#define MCHelpCmdE L"\n e Extract files without archived paths"
#define MCHelpCmdF L"\n f Freshen files in archive"
#define MCHelpCmdI L"\n i[par]=<str> Find string in archives"
#define MCHelpCmdK L"\n k Lock archive"
#define MCHelpCmdL L"\n l[t[a],b] List archive contents [technical[all], bare]"
#define MCHelpCmdM L"\n m[f] Move to archive [files only]"
#define MCHelpCmdP L"\n p Print file to stdout"
#define MCHelpCmdR L"\n r Repair archive"
#define MCHelpCmdRC L"\n rc Reconstruct missing volumes"
#define MCHelpCmdRN L"\n rn Rename archived files"
#define MCHelpCmdRR L"\n rr[N] Add data recovery record"
#define MCHelpCmdRV L"\n rv[N] Create recovery volumes"
#define MCHelpCmdS L"\n s[name|-] Convert archive to or from SFX"
#define MCHelpCmdT L"\n t Test archive files"
#define MCHelpCmdU L"\n u Update files in archive"
#define MCHelpCmdV L"\n v[t[a],b] Verbosely list archive contents [technical[all],bare]"
#define MCHelpCmdX L"\n x Extract files with full path"
#define MCHelpSw L"\n\n<Switches>"
#define MCHelpSwm L"\n - Stop switches scanning"
#define MCHelpSwAT L"\n @[+] Disable [enable] file lists"
#define MCHelpSwAC L"\n ac Clear Archive attribute after compression or extraction"
#define MCHelpSwAD L"\n ad Append archive name to destination path"
#define MCHelpSwAG L"\n ag[format] Generate archive name using the current date"
#define MCHelpSwAI L"\n ai Ignore file attributes"
#define MCHelpSwAO L"\n ao Add files with Archive attribute set"
#define MCHelpSwAP L"\n ap<path> Set path inside archive"
#define MCHelpSwAS L"\n as Synchronize archive contents"
#define MCHelpSwCm L"\n c- Disable comments show"
#define MCHelpSwCFGm L"\n cfg- Disable read configuration"
#define MCHelpSwCL L"\n cl Convert names to lower case"
#define MCHelpSwCU L"\n cu Convert names to upper case"
#define MCHelpSwDF L"\n df Delete files after archiving"
#define MCHelpSwDH L"\n dh Open shared files"
#define MCHelpSwDR L"\n dr Delete files to Recycle Bin"
#define MCHelpSwDS L"\n ds Disable name sort for solid archive"
#define MCHelpSwDW L"\n dw Wipe files after archiving"
#define MCHelpSwEa L"\n e[+]<attr> Set file exclude and include attributes"
#define MCHelpSwED L"\n ed Do not add empty directories"
#define MCHelpSwEN L"\n en Do not put 'end of archive' block"
#define MCHelpSwEP L"\n ep Exclude paths from names"
#define MCHelpSwEP1 L"\n ep1 Exclude base directory from names"
#define MCHelpSwEP2 L"\n ep2 Expand paths to full"
#define MCHelpSwEP3 L"\n ep3 Expand paths to full including the drive letter"
#define MCHelpSwF L"\n f Freshen files"
#define MCHelpSwHP L"\n hp[password] Encrypt both file data and headers"
#define MCHelpSwHT L"\n ht[b|c] Select hash type [BLAKE2,CRC32] for file checksum"
#define MCHelpSwIDP L"\n id[c,d,p,q] Disable messages"
#define MCHelpSwIEML L"\n ieml[addr] Send archive by email"
#define MCHelpSwIERR L"\n ierr Send all messages to stderr"
#define MCHelpSwILOG L"\n ilog[name] Log errors to file (registered versions only)"
#define MCHelpSwINUL L"\n inul Disable all messages"
#define MCHelpSwIOFF L"\n ioff Turn PC off after completing an operation"
#define MCHelpSwISND L"\n isnd Enable sound"
#define MCHelpSwIVER L"\n iver Display the version number"
#define MCHelpSwK L"\n k Lock archive"
#define MCHelpSwKB L"\n kb Keep broken extracted files"
#define MCHelpSwLog L"\n log[f][=name] Write names to log file"
#define MCHelpSwMn L"\n m<0..5> Set compression level (0-store...3-default...5-maximal)"
#define MCHelpSwMA L"\n ma[4|5] Specify a version of archiving format"
#define MCHelpSwMC L"\n mc<par> Set advanced compression parameters"
#define MCHelpSwMD L"\n md<n>[k,m,g] Dictionary size in KB, MB or GB"
#define MCHelpSwMS L"\n ms[ext;ext] Specify file types to store"
#define MCHelpSwMT L"\n mt<threads> Set the number of threads"
#define MCHelpSwN L"\n n<file> Additionally filter included files"
#define MCHelpSwNa L"\n n@ Read additional filter masks from stdin"
#define MCHelpSwNal L"\n n@<list> Read additional filter masks from list file"
#define MCHelpSwO L"\n o[+|-] Set the overwrite mode"
#define MCHelpSwOC L"\n oc Set NTFS Compressed attribute"
#define MCHelpSwOH L"\n oh Save hard links as the link instead of the file"
#define MCHelpSwOI L"\n oi[0-4][:min] Save identical files as references"
#define MCHelpSwOL L"\n ol[a] Process symbolic links as the link [absolute paths]"
#define MCHelpSwONI L"\n oni Allow potentially incompatible names"
#define MCHelpSwOR L"\n or Rename files automatically"
#define MCHelpSwOS L"\n os Save NTFS streams"
#define MCHelpSwOW L"\n ow Save or restore file owner and group"
#define MCHelpSwP L"\n p[password] Set password"
#define MCHelpSwPm L"\n p- Do not query password"
#define MCHelpSwQO L"\n qo[-|+] Add quick open information [none|force]"
#define MCHelpSwR L"\n r Recurse subdirectories"
#define MCHelpSwRm L"\n r- Disable recursion"
#define MCHelpSwR0 L"\n r0 Recurse subdirectories for wildcard names only"
#define MCHelpSwRI L"\n ri<P>[:<S>] Set priority (0-default,1-min..15-max) and sleep time in ms"
#define MCHelpSwRR L"\n rr[N] Add data recovery record"
#define MCHelpSwRV L"\n rv[N] Create recovery volumes"
#define MCHelpSwS L"\n s[<N>,v[-],e] Create solid archive"
#define MCHelpSwSm L"\n s- Disable solid archiving"
#define MCHelpSwSC L"\n sc<chr>[obj] Specify the character set"
#define MCHelpSwSFX L"\n sfx[name] Create SFX archive"
#define MCHelpSwSI L"\n si[name] Read data from standard input (stdin)"
#define MCHelpSwSL L"\n sl<size> Process files with size less than specified"
#define MCHelpSwSM L"\n sm<size> Process files with size more than specified"
#define MCHelpSwT L"\n t Test files after archiving"
#define MCHelpSwTK L"\n tk Keep original archive time"
#define MCHelpSwTL L"\n tl Set archive time to latest file"
#define MCHelpSwTN L"\n tn<time> Process files newer than <time>"
#define MCHelpSwTO L"\n to<time> Process files older than <time>"
#define MCHelpSwTA L"\n ta<date> Process files modified after <date> in YYYYMMDDHHMMSS format"
#define MCHelpSwTB L"\n tb<date> Process files modified before <date> in YYYYMMDDHHMMSS format"
#define MCHelpSwTS L"\n ts[m|c|a] Save or restore file time (modification, creation, access)"
#define MCHelpSwU L"\n u Update files"
#define MCHelpSwV L"\n v Create volumes with size autodetection or list all volumes"
#define MCHelpSwVUnr L"\n v List all volumes"
#define MCHelpSwVn L"\n v<size>[k,b] Create volumes with size=<size>*1000 [*1024, *1]"
#define MCHelpSwVD L"\n vd Erase disk contents before creating volume"
#define MCHelpSwVER L"\n ver[n] File version control"
#define MCHelpSwVN L"\n vn Use the old style volume naming scheme"
#define MCHelpSwVP L"\n vp Pause before each volume"
#define MCHelpSwW L"\n w<path> Assign work directory"
#define MCHelpSwX L"\n x<file> Exclude specified file"
#define MCHelpSwXa L"\n x@ Read file names to exclude from stdin"
#define MCHelpSwXal L"\n x@<list> Exclude files listed in specified list file"
#define MCHelpSwY L"\n y Assume Yes on all queries"
#define MCHelpSwZ L"\n z[file] Read archive comment from file"
#define MBadArc L"\nERROR: Bad archive %s\n"
#define MAskPsw L"Enter password (will not be echoed)"
#define MAskPswFor L"\nEnter password (will not be echoed) for %s: "
#define MReAskPsw L"\nReenter password: "
#define MNotMatchPsw L"\nERROR: Passwords do not match\n"
#define MErrWrite L"Write error in the file %s"
#define MErrRead L"Read error in the file %s"
#define MErrSeek L"Seek error in the file %s"
#define MErrFClose L"Cannot close the file %s"
#define MErrOutMem L"Not enough memory"
#define MErrBrokenArc L"Corrupt archive - use 'Repair' command"
#define MProgAborted L"Program aborted"
#define MErrRename L"\nCannot rename %s to %s"
#define MAbsNextVol L"\nCannot find volume %s"
#define MBreak L"\nUser break\n"
#define MAskCreatVol L"\nCreate next volume ?"
#define MAskNextDisk L"\nDisk full. Insert next"
#define MCreatVol L"\n\nCreating %sarchive %s\n"
#define MAskNextVol L"\nInsert disk with %s"
#define MTestVol L"\n\nTesting archive %s\n"
#define MExtrVol L"\n\nExtracting from %s\n"
#define MConverting L"\nConverting %s"
#define MCvtToSFX L"\nConvert archives to SFX"
#define MCvtFromSFX L"\nRemoving SFX module"
#define MNotSFX L"\n%s is not SFX archive"
#define MNotRAR L"\n%s is not RAR archive"
#define MNotFirstVol L"\n%s is not the first volume"
#define MCvtOldFormat L"\n%s - cannot convert to SFX archive with old format"
#define MCannotCreate L"\nCannot create %s"
#define MCannotOpen L"\nCannot open %s"
#define MUnknownMeth L"\nUnknown method in %s"
#define MNewRarFormat L"\nUnsupported archive format. Please update RAR to a newer version."
#define MOk L" OK"
#define MDone L"\nDone"
#define MLockingArc L"\nLocking archive"
#define MNotMdfOld L"\n\nERROR: Cannot modify old format archive"
#define MNotMdfLock L"\n\nERROR: Locked archive"
#define MNotMdfVol L"\n\nERROR: Cannot modify volume"
#define MPackAskReg L"\nEvaluation copy. Please register.\n"
#define MCreateArchive L"\nCreating %sarchive %s\n"
#define MUpdateArchive L"\nUpdating %sarchive %s\n"
#define MAddSolid L"solid "
#define MAddFile L"\nAdding %-58s "
#define MUpdFile L"\nUpdating %-58s "
#define MAddPoints L"\n... %-58s "
#define MMoveDelFiles L"\n\nDeleting files %s..."
#define MMoveDelDirs L"and directories"
#define MMoveDelFile L"\nDeleting %-30s"
#define MMoveDeleted L" deleted"
#define MMoveNotDeleted L" NOT DELETED"
#define MClearAttrib L"\n\nClearing attributes..."
#define MMoveDelDir L"\nDeleting directory %-30s"
#define MWarErrFOpen L"\nWARNING: Cannot open %d %s"
#define MErrOpenFiles L"files"
#define MErrOpenFile L"file"
#define MAddNoFiles L"\nWARNING: No files"
#define MMdfEncrSol L"\n%s: encrypted"
#define MCannotMdfEncrSol L"\nCannot modify solid archive containing encrypted files"
#define MAddAnalyze L"\nAnalyzing archived files: "
#define MRepacking L"\nRepacking archived files: "
#define MCRCFailed L"\n%-20s - checksum error"
#define MExtrTest L"\n\nTesting archive %s\n"
#define MExtracting L"\n\nExtracting from %s\n"
#define MUseCurPsw L"\n%s - use current password ?"
#define MCreatDir L"\nCreating %-56s"
#define MExtrSkipFile L"\nSkipping %-56s"
#define MExtrTestFile L"\nTesting %-56s"
#define MExtrFile L"\nExtracting %-56s"
#define MExtrPoints L"\n... %-56s"
#define MExtrErrMkDir L"\nCannot create directory %s"
#define MExtrPrinting L"\n------ Printing %s\n\n"
#define MEncrBadCRC L"\nChecksum error in the encrypted file %s. Corrupt file or wrong password."
#define MExtrNoFiles L"\nNo files to extract"
#define MExtrAllOk L"\nAll OK"
#define MExtrTotalErr L"\nTotal errors: %ld"
#define MAskReplace L"\n\nWould you like to replace the existing file %s\n%6s bytes, modified on %s\nwith a new one\n%6s bytes, modified on %s\n"
#define MAskOverwrite L"\nOverwrite %s ?"
#define MAskNewName L"\nEnter new name: "
#define MHeaderBroken L"\nCorrupt header is found"
#define MMainHeaderBroken L"\nMain archive header is corrupt"
#define MLogFileHead L"\n%s - the file header is corrupt"
#define MLogProtectHead L"The data recovery header is corrupt"
#define MReadStdinCmt L"\nReading comment from stdin\n"
#define MReadCommFrom L"\nReading comment from %s"
#define MDelComment L"\nDeleting comment from %s"
#define MAddComment L"\nAdding comment to %s"
#define MFCommAdd L"\nAdding file comments"
#define MAskFComm L"\n\nReading comment for %s : %s from stdin\n"
#define MLogCommBrk L"\nThe archive comment is corrupt"
#define MCommAskCont L"\nPress 'Enter' to continue or 'Q' to quit:"
#define MWriteCommTo L"\nWrite comment to %s"
#define MCommNotPres L"\nComment is not present"
#define MDelFrom L"\nDeleting from %s"
#define MDeleting L"\nDeleting %s"
#define MEraseArc L"\nErasing empty archive %s"
#define MNoDelFiles L"\nNo files to delete"
#define MLogTitle L"-------- %2d %s %d, archive %s"
#define MPathTooLong L"\nERROR: Path too long\n"
#define MListArchive L"Archive"
#define MListDetails L"Details"
#define MListSolid L"solid"
#define MListSFX L"SFX"
#define MListVolume L"volume"
#define MListRR L"recovery record"
#define MListLock L"lock"
#define MListEnc L"encrypted"
#define MListEncHead L"encrypted headers"
#define MListTitleL L" Attributes Size Date Time Name"
#define MListTitleV L" Attributes Size Packed Ratio Date Time Checksum Name"
#define MListName L"Name"
#define MListType L"Type"
#define MListFile L"File"
#define MListDir L"Directory"
#define MListUSymlink L"Unix symbolic link"
#define MListWSymlink L"Windows symbolic link"
#define MListJunction L"NTFS junction point"
#define MListHardlink L"Hard link"
#define MListCopy L"File reference"
#define MListStream L"NTFS alternate data stream"
#define MListTarget L"Target"
#define MListSize L"Size"
#define MListPacked L"Packed size"
#define MListRatio L"Ratio"
#define MListMtime L"mtime"
#define MListCtime L"ctime"
#define MListAtime L"atime"
#define MListAttr L"Attributes"
#define MListFlags L"Flags"
#define MListCompInfo L"Compression"
#define MListHostOS L"Host OS"
#define MListFileVer L"File version"
#define MListService L"Service"
#define MListUOHead L"\n Unix Owner/Group data: %-14s %-14s"
#define MListNTACLHead L"\n NTFS security data"
#define MListStrmHead L"\n NTFS stream: %s"
#define MListUnkHead L"\n Unknown subheader type: 0x%04x"
#define MFileComment L"\nComment: "
#define MYes L"Yes"
#define MNo L"No"
#define MListNoFiles L" 0 files\n"
#define MRprReconstr L"\nReconstructing %s"
#define MRprBuild L"\nBuilding %s"
#define MRprOldFormat L"\nCannot repair archive with old format"
#define MRprFind L"\nFound %s"
#define MRprAskIsSol L"\nThe archive header is corrupt. Mark archive as solid ?"
#define MRprNoFiles L"\nNo files found"
#define MLogUnexpEOF L"\nUnexpected end of archive"
#define MRepAskReconst L"\nReconstruct archive structure ?"
#define MRecScanning L"\nScanning..."
#define MRecRNotFound L"\nData recovery record not found"
#define MRecRFound L"\nData recovery record found"
#define MRecSecDamage L"\nSector %ld (offsets %lX...%lX) damaged"
#define MRecCorrected L" - data recovered"
#define MRecFailed L" - cannot recover data"
#define MAddRecRec L"\nAdding data recovery record"
#define MEraseForVolume L"\n\nErasing contents of drive %c:\n"
#define MGetOwnersError L"\nWARNING: Cannot get %s owner and group\n"
#define MErrGetOwnerID L"\nWARNING: Cannot get owner %s ID\n"
#define MErrGetGroupID L"\nWARNING: Cannot get group %s ID\n"
#define MOwnersBroken L"\nERROR: %s group and owner data are corrupt\n"
#define MSetOwnersError L"\nWARNING: Cannot set %s owner and group\n"
#define MErrLnkRead L"\nWARNING: Cannot read symbolic link %s"
#define MSymLinkExists L"\nWARNING: Symbolic link %s already exists"
#define MAskRetryCreate L"\nCannot create %s. Retry ?"
#define MListMACHead1 L"\n Mac OS file type: %c%c%c%c ; "
#define MListMACHead2 L"file creator: %c%c%c%c\n"
#define MDataBadCRC L"\n%-20s : packed data checksum error in volume %s"
#define MFileRO L"\n%s is read-only"
#define MACLGetError L"\nWARNING: Cannot get %s security data\n"
#define MACLSetError L"\nWARNING: Cannot set %s security data\n"
#define MACLBroken L"\nERROR: %s security data are corrupt\n"
#define MACLUnknown L"\nWARNING: Unknown format of %s security data\n"
#define MStreamBroken L"\nERROR: %s stream data are corrupt\n"
#define MStreamUnknown L"\nWARNING: Unknown format of %s stream data\n"
#define MInvalidName L"\nERROR: Invalid file name %s"
#define MProcessArc L"\n\nProcessing archive %s"
#define MCorrectingName L"\nWARNING: Attempting to correct the invalid file name"
#define MUnpCannotMerge L"\nWARNING: You need to start extraction from a previous volume to unpack %s"
#define MUnknownOption L"\nERROR: Unknown option: %s"
#define MSubHeadCorrupt L"\nERROR: Corrupt data header found, ignored"
#define MSubHeadUnknown L"\nWARNING: Unknown data header format, ignored"
#define MSubHeadDataCRC L"\nERROR: Corrupt %s data block"
#define MSubHeadType L"\nData header type: %s"
#define MScanError L"\nCannot read contents of %s"
#define MNotVolume L"\n%s is not volume"
#define MRecVolDiffSets L"\nERROR: %s and %s belong to different sets"
#define MRecVolMissing L"\n%d volumes missing"
#define MRecVolFound L"\n%d recovery volumes found"
#define MRecVolAllExist L"\nNothing to reconstruct"
#define MRecVolCannotFix L"\nReconstruction impossible"
#define MReconstructing L"\nReconstructing..."
#define MCreating L"\nCreating %s"
#define MRenaming L"\nRenaming %s to %s"
#define MNTFSRequired L"\nWrite error: only NTFS file system supports files larger than 4 GB"
#define MFAT32Size L"\nWARNING: FAT32 file system does not support 4 GB or larger files"
#define MErrChangeAttr L"\nWARNING: Cannot change attributes of %s"
#define MWrongSFXVer L"\nERROR: default SFX module does not support RAR %d.%d archives"
#define MCannotEncName L"\nCannot encrypt archive already containing encrypted files"
#define MCannotEmail L"\nCannot email the file %s"
#define MCopyrightS L"\nRAR SFX archive"
#define MSHelpCmd L"\n\n<Commands>"
#define MSHelpCmdE L"\n -x Extract from archive (default)"
#define MSHelpCmdT L"\n -t Test archive files"
#define MSHelpCmdV L"\n -v Verbosely list contents of archive"
#define MRecVolLimit L"\nTotal number of usual and recovery volumes must not exceed %d"
#define MVolumeNumber L"volume %d"
#define MCannotDelete L"\nCannot delete %s"
#define MCalcCRC L"\nCalculating the checksum"
#define MTooLargeSFXArc L"\nWARNING: Too large SFX archive. Windows cannot run the executable file exceeding 4 GB."
#define MCalcCRCAllVol L"\nCalculating checksums of all volumes."
#define MNotEnoughDisk L"\nERROR: Not enough disk space for %s."
#define MNewerRAR L"\nYou may need a newer version of RAR."
#define MUnkEncMethod L"\nUnknown encryption method in %s"
#define MWrongPassword L"\nThe specified password is incorrect."
#define MRepairing L"\nRepairing"
#define MAreaDamaged L"\nCorrupt %d bytes at %08x %08x"
#define MBlocksRecovered L"\n%d blocks recovered."
#define MRRDamaged L"\nRecovery record is corrupt."
#define MTestingRR L"\nTesting the recovery record"
#define MFailed L"Failed"
#define MIncompatSwitch L"\n%s switch is not supported for RAR %d.x archive format."
#define MSearchDupFiles L"\nSearching for identical files"
#define MNumFound L"%d found."
#define MUnknownExtra L"\nUnknown extra field in %s."
#define MCorruptExtra L"\nCorrupt %s extra field in %s."
#define MCopyError L"\nCannot copy %s to %s."
#define MCopyErrorHint L"\nYou need to unpack the entire archive to create file reference entries."
#define MCopyingData L"\nCopying data"
#define MErrCreateLnkS L"\nCannot create symbolic link %s"
#define MErrCreateLnkH L"\nCannot create hard link %s"
#define MNeedAdmin L"\nYou may need to run RAR as administrator"
#define MDictOutMem L"\nNot enough memory for %d MB compression dictionary, changed to %d MB."
#define MUseSmalllerDict L"\nPlease use a smaller compression dictionary."

37
reference/unrar/log.cpp Normal file
View File

@@ -0,0 +1,37 @@
#include "rar.hpp"
static wchar LogName[NM];
static RAR_CHARSET LogCharset=RCH_DEFAULT;
void InitLogOptions(const wchar *LogFileName,RAR_CHARSET CSet)
{
wcsncpyz(LogName,LogFileName,ASIZE(LogName));
LogCharset=CSet;
}
#ifndef SILENT
void Log(const wchar *ArcName,const wchar *fmt,...)
{
// Preserve the error code for possible following system error message.
int Code=ErrHandler.GetSystemErrorCode();
uiAlarm(UIALARM_ERROR);
// This buffer is for format string only, not for entire output,
// so it can be short enough.
wchar fmtw[1024];
PrintfPrepareFmt(fmt,fmtw,ASIZE(fmtw));
safebuf wchar Msg[2*NM+1024];
va_list arglist;
va_start(arglist,fmt);
vswprintf(Msg,ASIZE(Msg),fmtw,arglist);
va_end(arglist);
eprintf(L"%ls",Msg);
ErrHandler.SetSystemErrorCode(Code);
}
#endif

12
reference/unrar/log.hpp Normal file
View File

@@ -0,0 +1,12 @@
#ifndef _RAR_LOG_
#define _RAR_LOG_
void InitLogOptions(const wchar *LogFileName,RAR_CHARSET CSet);
#ifdef SILENT
inline void Log(const wchar *ArcName,const wchar *fmt,...) {}
#else
void Log(const wchar *ArcName,const wchar *fmt,...);
#endif
#endif

173
reference/unrar/makefile Normal file
View File

@@ -0,0 +1,173 @@
#
# Makefile for UNIX - unrar
# Linux using GCC
CXX=c++
CXXFLAGS=-O2
LIBFLAGS=-fPIC
DEFINES=-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -DRAR_SMP
STRIP=strip
AR=ar
LDFLAGS=-pthread
DESTDIR=/usr
# Linux using LCC
#CXX=lcc
#CXXFLAGS=-O2
#DEFINES=-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
#STRIP=strip
#AR=ar
#DESTDIR=/usr
# CYGWIN using GCC
#CXX=c++
#CXXFLAGS=-O2
#LIBFLAGS=
#DEFINES=-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -DRAR_SMP
#STRIP=strip
#AR=ar
#LDFLAGS=-pthread
#DESTDIR=/usr
# HP UX using aCC
#CXX=aCC
#CXXFLAGS=-AA +O2 +Onolimit
#DEFINES=-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
#STRIP=strip
#AR=ar
#DESTDIR=/usr
# IRIX using GCC
#CXX=g++
#CXXFLAGS=-O2
#DEFINES=-DBIG_ENDIAN -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_BSD_COMPAT -D_XOPEN_SOURCE -D_XOPEN_SOURCE_EXTENDED=1
#STRIP=strip
#AR=ar
#DESTDIR=/usr
# IRIX using MIPSPro (experimental)
#CXX=CC
#CXXFLAGS=-O2 -mips3 -woff 1234,1156,3284 -LANG:std
#DEFINES=-DBIG_ENDIAN -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_BSD_COMPAT -Dint64=int64_t
#STRIP=strip
#AR=ar
#DESTDIR=/usr
# AIX using xlC (IBM VisualAge C++ 5.0)
#CXX=xlC
#CXXFLAGS=-O -qinline -qro -qroconst -qmaxmem=16384 -qcpluscmt
#DEFINES=-D_LARGE_FILES -D_LARGE_FILE_API
#LIBS=-lbsd
#STRIP=strip
#AR=ar
#DESTDIR=/usr
# Solaris using CC
#CXX=CC
#CXXFLAGS=-fast -erroff=wvarhidemem
#DEFINES=-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
#STRIP=strip
#AR=ar
#DESTDIR=/usr
# Solaris using GCC (optimized for UltraSPARC 1 CPU)
#CXX=g++
#CXXFLAGS=-O3 -mcpu=v9 -mtune=ultrasparc -m32
#DEFINES=-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
#STRIP=/usr/ccs/bin/strip
#AR=/usr/ccs/bin/ar
#DESTDIR=/usr
# Tru64 5.1B using GCC3
#CXX=g++
#CXXFLAGS=-O2 -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_XOPEN_SOURCE=500
#STRIP=strip
#AR=ar
#LDFLAGS=-rpath /usr/local/gcc/lib
#DESTDIR=/usr
# Tru64 5.1B using DEC C++
#CXX=cxx
#CXXFLAGS=-O4 -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -Dint64=long
#STRIP=strip
#AR=ar
#LDFLAGS=
#DESTDIR=/usr
# QNX 6.x using GCC
#CXX=g++
#CXXFLAGS=-O2 -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -fexceptions
#STRIP=strip
#AR=ar
#LDFLAGS=-fexceptions
#DESTDIR=/usr
# Cross-compile
# Linux using arm-linux-g++
#CXX=arm-linux-g++
#CXXFLAGS=-O2
#DEFINES=-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
#STRIP=arm-linux-strip
#AR=arm-linux-ar
#LDFLAGS=-static
#DESTDIR=/usr
##########################
COMPILE=$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(DEFINES)
LINK=$(CXX)
WHAT=UNRAR
UNRAR_OBJ=filestr.o recvol.o rs.o scantree.o qopen.o
LIB_OBJ=filestr.o scantree.o dll.o qopen.o
OBJECTS=rar.o strlist.o strfn.o pathfn.o smallfn.o global.o file.o filefn.o filcreat.o \
archive.o arcread.o unicode.o system.o isnt.o crypt.o crc.o rawread.o encname.o \
resource.o match.o timefn.o rdwrfn.o consio.o options.o errhnd.o rarvm.o secpassword.o \
rijndael.o getbits.o sha1.o sha256.o blake2s.o hash.o extinfo.o extract.o volume.o \
list.o find.o unpack.o headers.o threadpool.o rs16.o cmddata.o ui.o
.cpp.o:
$(COMPILE) -D$(WHAT) -c $<
all: unrar
install: install-unrar
uninstall: uninstall-unrar
clean:
@rm -f *.o *.bak *~
unrar: clean $(OBJECTS) $(UNRAR_OBJ)
@rm -f unrar
$(LINK) -o unrar $(LDFLAGS) $(OBJECTS) $(UNRAR_OBJ) $(LIBS)
$(STRIP) unrar
sfx: WHAT=SFX_MODULE
sfx: clean $(OBJECTS)
@rm -f default.sfx
$(LINK) -o default.sfx $(LDFLAGS) $(OBJECTS)
$(STRIP) default.sfx
lib: WHAT=RARDLL
lib: CXXFLAGS+=$(LIBFLAGS)
lib: clean $(OBJECTS) $(LIB_OBJ)
@rm -f libunrar.so
@rm -f libunrar.a
$(LINK) -shared -o libunrar.so $(LDFLAGS) $(OBJECTS) $(LIB_OBJ)
$(AR) rcs libunrar.a $(OBJECTS) $(LIB_OBJ)
install-unrar:
install -D unrar $(DESTDIR)/bin/unrar
uninstall-unrar:
rm -f $(DESTDIR)/bin/unrar
install-lib:
install libunrar.so $(DESTDIR)/lib
install libunrar.a $(DESTDIR)/lib
uninstall-lib:
rm -f $(DESTDIR)/lib/libunrar.so

145
reference/unrar/match.cpp Normal file
View File

@@ -0,0 +1,145 @@
#include "rar.hpp"
static bool match(const wchar *pattern,const wchar *string,bool ForceCase);
static int mwcsicompc(const wchar *Str1,const wchar *Str2,bool ForceCase);
static int mwcsnicompc(const wchar *Str1,const wchar *Str2,size_t N,bool ForceCase);
inline uint touppercw(uint ch,bool ForceCase)
{
if (ForceCase)
return ch;
#if defined(_UNIX)
return ch;
#else
return toupperw(ch);
#endif
}
bool CmpName(const wchar *Wildcard,const wchar *Name,int CmpMode)
{
bool ForceCase=(CmpMode&MATCH_FORCECASESENSITIVE)!=0;
CmpMode&=MATCH_MODEMASK;
if (CmpMode!=MATCH_NAMES)
{
size_t WildLength=wcslen(Wildcard);
if (CmpMode!=MATCH_EXACT && CmpMode!=MATCH_EXACTPATH &&
mwcsnicompc(Wildcard,Name,WildLength,ForceCase)==0)
{
// For all modes except MATCH_NAMES, MATCH_EXACT and MATCH_EXACTPATH
// "path1" mask must match "path1\path2\filename.ext" and "path1" names.
wchar NextCh=Name[WildLength];
if (NextCh==L'\\' || NextCh==L'/' || NextCh==0)
return(true);
}
// Nothing more to compare for MATCH_SUBPATHONLY.
if (CmpMode==MATCH_SUBPATHONLY)
return(false);
wchar Path1[NM],Path2[NM];
GetFilePath(Wildcard,Path1,ASIZE(Path1));
GetFilePath(Name,Path2,ASIZE(Path2));
if ((CmpMode==MATCH_EXACT || CmpMode==MATCH_EXACTPATH) &&
mwcsicompc(Path1,Path2,ForceCase)!=0)
return(false);
if (CmpMode==MATCH_SUBPATH || CmpMode==MATCH_WILDSUBPATH)
if (IsWildcard(Path1))
return(match(Wildcard,Name,ForceCase));
else
if (CmpMode==MATCH_SUBPATH || IsWildcard(Wildcard))
{
if (*Path1 && mwcsnicompc(Path1,Path2,wcslen(Path1),ForceCase)!=0)
return(false);
}
else
if (mwcsicompc(Path1,Path2,ForceCase)!=0)
return(false);
}
wchar *Name1=PointToName(Wildcard);
wchar *Name2=PointToName(Name);
// Always return false for RAR temporary files to exclude them
// from archiving operations.
if (mwcsnicompc(L"__rar_",Name2,6,false)==0)
return(false);
if (CmpMode==MATCH_EXACT)
return(mwcsicompc(Name1,Name2,ForceCase)==0);
return(match(Name1,Name2,ForceCase));
}
bool match(const wchar *pattern,const wchar *string,bool ForceCase)
{
for (;; ++string)
{
wchar stringc=touppercw(*string,ForceCase);
wchar patternc=touppercw(*pattern++,ForceCase);
switch (patternc)
{
case 0:
return(stringc==0);
case '?':
if (stringc == 0)
return(false);
break;
case '*':
if (*pattern==0)
return(true);
if (*pattern=='.')
{
if (pattern[1]=='*' && pattern[2]==0)
return(true);
const wchar *dot=wcschr(string,'.');
if (pattern[1]==0)
return (dot==NULL || dot[1]==0);
if (dot!=NULL)
{
string=dot;
if (wcspbrk(pattern,L"*?")==NULL && wcschr(string+1,'.')==NULL)
return(mwcsicompc(pattern+1,string+1,ForceCase)==0);
}
}
while (*string)
if (match(pattern,string++,ForceCase))
return(true);
return(false);
default:
if (patternc != stringc)
{
// Allow "name." mask match "name" and "name.\" match "name\".
if (patternc=='.' && (stringc==0 || stringc=='\\' || stringc=='.'))
return(match(pattern,string,ForceCase));
else
return(false);
}
break;
}
}
}
int mwcsicompc(const wchar *Str1,const wchar *Str2,bool ForceCase)
{
if (ForceCase)
return wcscmp(Str1,Str2);
return wcsicompc(Str1,Str2);
}
int mwcsnicompc(const wchar *Str1,const wchar *Str2,size_t N,bool ForceCase)
{
if (ForceCase)
return wcsncmp(Str1,Str2,N);
#if defined(_UNIX)
return wcsncmp(Str1,Str2,N);
#else
return wcsnicomp(Str1,Str2,N);
#endif
}

34
reference/unrar/match.hpp Normal file
View File

@@ -0,0 +1,34 @@
#ifndef _RAR_MATCH_
#define _RAR_MATCH_
enum {
MATCH_NAMES, // Paths are ignored.
// Compares names only using wildcards.
MATCH_SUBPATHONLY, // Paths must match either exactly or path in wildcard
// must be present in the beginning of file path.
// For example, "c:\path1\*" or "c:\path1" will match
// "c:\path1\path2\file".
// Names are not compared.
MATCH_EXACT, // Paths must match exactly.
// Names must match exactly.
MATCH_EXACTPATH, // Paths must match exactly.
// Names are compared using wildcards.
MATCH_SUBPATH, // Names must be the same, but path in mask is allowed
// to be only a part of name path. In other words,
// we match all files matching the file mask
// in current folder and subfolders.
MATCH_WILDSUBPATH // Works as MATCH_SUBPATH if file mask contains
// wildcards and as MATCH_EXACTPATH otherwise.
};
#define MATCH_MODEMASK 0x0000ffff
#define MATCH_FORCECASESENSITIVE 0x80000000
bool CmpName(const wchar *Wildcard,const wchar *Name,int CmpMode);
#endif

617
reference/unrar/model.cpp Normal file
View File

@@ -0,0 +1,617 @@
/****************************************************************************
* This file is part of PPMd project *
* Written and distributed to public domain by Dmitry Shkarin 1997, *
* 1999-2000 *
* Contents: model description and encoding/decoding routines *
****************************************************************************/
static const int MAX_O=64; /* maximum allowed model order */
const uint TOP=1 << 24, BOT=1 << 15;
template <class T>
inline void _PPMD_SWAP(T& t1,T& t2) { T tmp=t1; t1=t2; t2=tmp; }
inline RARPPM_CONTEXT* RARPPM_CONTEXT::createChild(ModelPPM *Model,RARPPM_STATE* pStats,
RARPPM_STATE& FirstState)
{
RARPPM_CONTEXT* pc = (RARPPM_CONTEXT*) Model->SubAlloc.AllocContext();
if ( pc )
{
pc->NumStats=1;
pc->OneState=FirstState;
pc->Suffix=this;
pStats->Successor=pc;
}
return pc;
}
ModelPPM::ModelPPM()
{
MinContext=NULL;
MaxContext=NULL;
MedContext=NULL;
}
void ModelPPM::RestartModelRare()
{
int i, k, m;
memset(CharMask,0,sizeof(CharMask));
SubAlloc.InitSubAllocator();
InitRL=-(MaxOrder < 12 ? MaxOrder:12)-1;
MinContext = MaxContext = (RARPPM_CONTEXT*) SubAlloc.AllocContext();
MinContext->Suffix=NULL;
OrderFall=MaxOrder;
MinContext->U.SummFreq=(MinContext->NumStats=256)+1;
FoundState=MinContext->U.Stats=(RARPPM_STATE*)SubAlloc.AllocUnits(256/2);
for (RunLength=InitRL, PrevSuccess=i=0;i < 256;i++)
{
MinContext->U.Stats[i].Symbol=i;
MinContext->U.Stats[i].Freq=1;
MinContext->U.Stats[i].Successor=NULL;
}
static const ushort InitBinEsc[]={
0x3CDD,0x1F3F,0x59BF,0x48F3,0x64A1,0x5ABC,0x6632,0x6051
};
for (i=0;i < 128;i++)
for (k=0;k < 8;k++)
for (m=0;m < 64;m += 8)
BinSumm[i][k+m]=BIN_SCALE-InitBinEsc[k]/(i+2);
for (i=0;i < 25;i++)
for (k=0;k < 16;k++)
SEE2Cont[i][k].init(5*i+10);
}
void ModelPPM::StartModelRare(int MaxOrder)
{
int i, k, m ,Step;
EscCount=1;
/*
if (MaxOrder < 2)
{
memset(CharMask,0,sizeof(CharMask));
OrderFall=ModelPPM::MaxOrder;
MinContext=MaxContext;
while (MinContext->Suffix != NULL)
{
MinContext=MinContext->Suffix;
OrderFall--;
}
FoundState=MinContext->U.Stats;
MinContext=MaxContext;
}
else
*/
{
ModelPPM::MaxOrder=MaxOrder;
RestartModelRare();
NS2BSIndx[0]=2*0;
NS2BSIndx[1]=2*1;
memset(NS2BSIndx+2,2*2,9);
memset(NS2BSIndx+11,2*3,256-11);
for (i=0;i < 3;i++)
NS2Indx[i]=i;
for (m=i, k=Step=1;i < 256;i++)
{
NS2Indx[i]=m;
if ( !--k )
{
k = ++Step;
m++;
}
}
memset(HB2Flag,0,0x40);
memset(HB2Flag+0x40,0x08,0x100-0x40);
DummySEE2Cont.Shift=PERIOD_BITS;
}
}
void RARPPM_CONTEXT::rescale(ModelPPM *Model)
{
int OldNS=NumStats, i=NumStats-1, Adder, EscFreq;
RARPPM_STATE* p1, * p;
for (p=Model->FoundState;p != U.Stats;p--)
_PPMD_SWAP(p[0],p[-1]);
U.Stats->Freq += 4;
U.SummFreq += 4;
EscFreq=U.SummFreq-p->Freq;
Adder=(Model->OrderFall != 0);
U.SummFreq = (p->Freq=(p->Freq+Adder) >> 1);
do
{
EscFreq -= (++p)->Freq;
U.SummFreq += (p->Freq=(p->Freq+Adder) >> 1);
if (p[0].Freq > p[-1].Freq)
{
RARPPM_STATE tmp=*(p1=p);
do
{
p1[0]=p1[-1];
} while (--p1 != U.Stats && tmp.Freq > p1[-1].Freq);
*p1=tmp;
}
} while ( --i );
if (p->Freq == 0)
{
do
{
i++;
} while ((--p)->Freq == 0);
EscFreq += i;
if ((NumStats -= i) == 1)
{
RARPPM_STATE tmp=*U.Stats;
do
{
tmp.Freq-=(tmp.Freq >> 1);
EscFreq>>=1;
} while (EscFreq > 1);
Model->SubAlloc.FreeUnits(U.Stats,(OldNS+1) >> 1);
*(Model->FoundState=&OneState)=tmp; return;
}
}
U.SummFreq += (EscFreq -= (EscFreq >> 1));
int n0=(OldNS+1) >> 1, n1=(NumStats+1) >> 1;
if (n0 != n1)
U.Stats = (RARPPM_STATE*) Model->SubAlloc.ShrinkUnits(U.Stats,n0,n1);
Model->FoundState=U.Stats;
}
inline RARPPM_CONTEXT* ModelPPM::CreateSuccessors(bool Skip,RARPPM_STATE* p1)
{
#ifdef __ICL
static
#endif
RARPPM_STATE UpState;
RARPPM_CONTEXT* pc=MinContext, * UpBranch=FoundState->Successor;
RARPPM_STATE * p, * ps[MAX_O], ** pps=ps;
if ( !Skip )
{
*pps++ = FoundState;
if ( !pc->Suffix )
goto NO_LOOP;
}
if ( p1 )
{
p=p1;
pc=pc->Suffix;
goto LOOP_ENTRY;
}
do
{
pc=pc->Suffix;
if (pc->NumStats != 1)
{
if ((p=pc->U.Stats)->Symbol != FoundState->Symbol)
do
{
p++;
} while (p->Symbol != FoundState->Symbol);
}
else
p=&(pc->OneState);
LOOP_ENTRY:
if (p->Successor != UpBranch)
{
pc=p->Successor;
break;
}
*pps++ = p;
} while ( pc->Suffix );
NO_LOOP:
if (pps == ps)
return pc;
UpState.Symbol=*(byte*) UpBranch;
UpState.Successor=(RARPPM_CONTEXT*) (((byte*) UpBranch)+1);
if (pc->NumStats != 1)
{
if ((byte*) pc <= SubAlloc.pText)
return(NULL);
if ((p=pc->U.Stats)->Symbol != UpState.Symbol)
do
{
p++;
} while (p->Symbol != UpState.Symbol);
uint cf=p->Freq-1;
uint s0=pc->U.SummFreq-pc->NumStats-cf;
UpState.Freq=1+((2*cf <= s0)?(5*cf > s0):((2*cf+3*s0-1)/(2*s0)));
}
else
UpState.Freq=pc->OneState.Freq;
do
{
pc = pc->createChild(this,*--pps,UpState);
if ( !pc )
return NULL;
} while (pps != ps);
return pc;
}
inline void ModelPPM::UpdateModel()
{
RARPPM_STATE fs = *FoundState, *p = NULL;
RARPPM_CONTEXT *pc, *Successor;
uint ns1, ns, cf, sf, s0;
if (fs.Freq < MAX_FREQ/4 && (pc=MinContext->Suffix) != NULL)
{
if (pc->NumStats != 1)
{
if ((p=pc->U.Stats)->Symbol != fs.Symbol)
{
do
{
p++;
} while (p->Symbol != fs.Symbol);
if (p[0].Freq >= p[-1].Freq)
{
_PPMD_SWAP(p[0],p[-1]);
p--;
}
}
if (p->Freq < MAX_FREQ-9)
{
p->Freq += 2;
pc->U.SummFreq += 2;
}
}
else
{
p=&(pc->OneState);
p->Freq += (p->Freq < 32);
}
}
if ( !OrderFall )
{
MinContext=MaxContext=FoundState->Successor=CreateSuccessors(TRUE,p);
if ( !MinContext )
goto RESTART_MODEL;
return;
}
*SubAlloc.pText++ = fs.Symbol;
Successor = (RARPPM_CONTEXT*) SubAlloc.pText;
if (SubAlloc.pText >= SubAlloc.FakeUnitsStart)
goto RESTART_MODEL;
if ( fs.Successor )
{
if ((byte*) fs.Successor <= SubAlloc.pText &&
(fs.Successor=CreateSuccessors(FALSE,p)) == NULL)
goto RESTART_MODEL;
if ( !--OrderFall )
{
Successor=fs.Successor;
SubAlloc.pText -= (MaxContext != MinContext);
}
}
else
{
FoundState->Successor=Successor;
fs.Successor=MinContext;
}
s0=MinContext->U.SummFreq-(ns=MinContext->NumStats)-(fs.Freq-1);
for (pc=MaxContext;pc != MinContext;pc=pc->Suffix)
{
if ((ns1=pc->NumStats) != 1)
{
if ((ns1 & 1) == 0)
{
pc->U.Stats=(RARPPM_STATE*) SubAlloc.ExpandUnits(pc->U.Stats,ns1 >> 1);
if ( !pc->U.Stats )
goto RESTART_MODEL;
}
pc->U.SummFreq += (2*ns1 < ns)+2*((4*ns1 <= ns) & (pc->U.SummFreq <= 8*ns1));
}
else
{
p=(RARPPM_STATE*) SubAlloc.AllocUnits(1);
if ( !p )
goto RESTART_MODEL;
*p=pc->OneState;
pc->U.Stats=p;
if (p->Freq < MAX_FREQ/4-1)
p->Freq += p->Freq;
else
p->Freq = MAX_FREQ-4;
pc->U.SummFreq=p->Freq+InitEsc+(ns > 3);
}
cf=2*fs.Freq*(pc->U.SummFreq+6);
sf=s0+pc->U.SummFreq;
if (cf < 6*sf)
{
cf=1+(cf > sf)+(cf >= 4*sf);
pc->U.SummFreq += 3;
}
else
{
cf=4+(cf >= 9*sf)+(cf >= 12*sf)+(cf >= 15*sf);
pc->U.SummFreq += cf;
}
p=pc->U.Stats+ns1;
p->Successor=Successor;
p->Symbol = fs.Symbol;
p->Freq = cf;
pc->NumStats=++ns1;
}
MaxContext=MinContext=fs.Successor;
return;
RESTART_MODEL:
RestartModelRare();
EscCount=0;
}
// Tabulated escapes for exponential symbol distribution
static const byte ExpEscape[16]={ 25,14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 };
#define GET_MEAN(SUMM,SHIFT,ROUND) ((SUMM+(1 << (SHIFT-ROUND))) >> (SHIFT))
inline void RARPPM_CONTEXT::decodeBinSymbol(ModelPPM *Model)
{
RARPPM_STATE& rs=OneState;
Model->HiBitsFlag=Model->HB2Flag[Model->FoundState->Symbol];
ushort& bs=Model->BinSumm[rs.Freq-1][Model->PrevSuccess+
Model->NS2BSIndx[Suffix->NumStats-1]+
Model->HiBitsFlag+2*Model->HB2Flag[rs.Symbol]+
((Model->RunLength >> 26) & 0x20)];
if (Model->Coder.GetCurrentShiftCount(TOT_BITS) < bs)
{
Model->FoundState=&rs;
rs.Freq += (rs.Freq < 128);
Model->Coder.SubRange.LowCount=0;
Model->Coder.SubRange.HighCount=bs;
bs = GET_SHORT16(bs+INTERVAL-GET_MEAN(bs,PERIOD_BITS,2));
Model->PrevSuccess=1;
Model->RunLength++;
}
else
{
Model->Coder.SubRange.LowCount=bs;
bs = GET_SHORT16(bs-GET_MEAN(bs,PERIOD_BITS,2));
Model->Coder.SubRange.HighCount=BIN_SCALE;
Model->InitEsc=ExpEscape[bs >> 10];
Model->NumMasked=1;
Model->CharMask[rs.Symbol]=Model->EscCount;
Model->PrevSuccess=0;
Model->FoundState=NULL;
}
}
inline void RARPPM_CONTEXT::update1(ModelPPM *Model,RARPPM_STATE* p)
{
(Model->FoundState=p)->Freq += 4;
U.SummFreq += 4;
if (p[0].Freq > p[-1].Freq)
{
_PPMD_SWAP(p[0],p[-1]);
Model->FoundState=--p;
if (p->Freq > MAX_FREQ)
rescale(Model);
}
}
inline bool RARPPM_CONTEXT::decodeSymbol1(ModelPPM *Model)
{
Model->Coder.SubRange.scale=U.SummFreq;
RARPPM_STATE* p=U.Stats;
int i, HiCnt;
int count=Model->Coder.GetCurrentCount();
if (count>=(int)Model->Coder.SubRange.scale)
return(false);
if (count < (HiCnt=p->Freq))
{
Model->PrevSuccess=(2*(Model->Coder.SubRange.HighCount=HiCnt) > Model->Coder.SubRange.scale);
Model->RunLength += Model->PrevSuccess;
(Model->FoundState=p)->Freq=(HiCnt += 4);
U.SummFreq += 4;
if (HiCnt > MAX_FREQ)
rescale(Model);
Model->Coder.SubRange.LowCount=0;
return(true);
}
else
if (Model->FoundState==NULL)
return(false);
Model->PrevSuccess=0;
i=NumStats-1;
while ((HiCnt += (++p)->Freq) <= count)
if (--i == 0)
{
Model->HiBitsFlag=Model->HB2Flag[Model->FoundState->Symbol];
Model->Coder.SubRange.LowCount=HiCnt;
Model->CharMask[p->Symbol]=Model->EscCount;
i=(Model->NumMasked=NumStats)-1;
Model->FoundState=NULL;
do
{
Model->CharMask[(--p)->Symbol]=Model->EscCount;
} while ( --i );
Model->Coder.SubRange.HighCount=Model->Coder.SubRange.scale;
return(true);
}
Model->Coder.SubRange.LowCount=(Model->Coder.SubRange.HighCount=HiCnt)-p->Freq;
update1(Model,p);
return(true);
}
inline void RARPPM_CONTEXT::update2(ModelPPM *Model,RARPPM_STATE* p)
{
(Model->FoundState=p)->Freq += 4;
U.SummFreq += 4;
if (p->Freq > MAX_FREQ)
rescale(Model);
Model->EscCount++;
Model->RunLength=Model->InitRL;
}
inline RARPPM_SEE2_CONTEXT* RARPPM_CONTEXT::makeEscFreq2(ModelPPM *Model,int Diff)
{
RARPPM_SEE2_CONTEXT* psee2c;
if (NumStats != 256)
{
psee2c=Model->SEE2Cont[Model->NS2Indx[Diff-1]]+
(Diff < Suffix->NumStats-NumStats)+
2*(U.SummFreq < 11*NumStats)+4*(Model->NumMasked > Diff)+
Model->HiBitsFlag;
Model->Coder.SubRange.scale=psee2c->getMean();
}
else
{
psee2c=&Model->DummySEE2Cont;
Model->Coder.SubRange.scale=1;
}
return psee2c;
}
inline bool RARPPM_CONTEXT::decodeSymbol2(ModelPPM *Model)
{
int count, HiCnt, i=NumStats-Model->NumMasked;
RARPPM_SEE2_CONTEXT* psee2c=makeEscFreq2(Model,i);
RARPPM_STATE* ps[256], ** pps=ps, * p=U.Stats-1;
HiCnt=0;
do
{
do
{
p++;
} while (Model->CharMask[p->Symbol] == Model->EscCount);
HiCnt += p->Freq;
*pps++ = p;
} while ( --i );
Model->Coder.SubRange.scale += HiCnt;
count=Model->Coder.GetCurrentCount();
if (count>=(int)Model->Coder.SubRange.scale)
return(false);
p=*(pps=ps);
if (count < HiCnt)
{
HiCnt=0;
while ((HiCnt += p->Freq) <= count)
p=*++pps;
Model->Coder.SubRange.LowCount = (Model->Coder.SubRange.HighCount=HiCnt)-p->Freq;
psee2c->update();
update2(Model,p);
}
else
{
Model->Coder.SubRange.LowCount=HiCnt;
Model->Coder.SubRange.HighCount=Model->Coder.SubRange.scale;
i=NumStats-Model->NumMasked;
pps--;
do
{
Model->CharMask[(*++pps)->Symbol]=Model->EscCount;
} while ( --i );
psee2c->Summ += Model->Coder.SubRange.scale;
Model->NumMasked = NumStats;
}
return(true);
}
inline void ModelPPM::ClearMask()
{
EscCount=1;
memset(CharMask,0,sizeof(CharMask));
}
// reset PPM variables after data error allowing safe resuming
// of further data processing
void ModelPPM::CleanUp()
{
SubAlloc.StopSubAllocator();
SubAlloc.StartSubAllocator(1);
StartModelRare(2);
}
bool ModelPPM::DecodeInit(Unpack *UnpackRead,int &EscChar)
{
int MaxOrder=UnpackRead->GetChar();
bool Reset=(MaxOrder & 0x20)!=0;
int MaxMB;
if (Reset)
MaxMB=UnpackRead->GetChar();
else
if (SubAlloc.GetAllocatedMemory()==0)
return(false);
if (MaxOrder & 0x40)
EscChar=UnpackRead->GetChar();
Coder.InitDecoder(UnpackRead);
if (Reset)
{
MaxOrder=(MaxOrder & 0x1f)+1;
if (MaxOrder>16)
MaxOrder=16+(MaxOrder-16)*3;
if (MaxOrder==1)
{
SubAlloc.StopSubAllocator();
return(false);
}
SubAlloc.StartSubAllocator(MaxMB+1);
StartModelRare(MaxOrder);
}
return(MinContext!=NULL);
}
int ModelPPM::DecodeChar()
{
if ((byte*)MinContext <= SubAlloc.pText || (byte*)MinContext>SubAlloc.HeapEnd)
return(-1);
if (MinContext->NumStats != 1)
{
if ((byte*)MinContext->U.Stats <= SubAlloc.pText || (byte*)MinContext->U.Stats>SubAlloc.HeapEnd)
return(-1);
if (!MinContext->decodeSymbol1(this))
return(-1);
}
else
MinContext->decodeBinSymbol(this);
Coder.Decode();
while ( !FoundState )
{
ARI_DEC_NORMALIZE(Coder.code,Coder.low,Coder.range,Coder.UnpackRead);
do
{
OrderFall++;
MinContext=MinContext->Suffix;
if ((byte*)MinContext <= SubAlloc.pText || (byte*)MinContext>SubAlloc.HeapEnd)
return(-1);
} while (MinContext->NumStats == NumMasked);
if (!MinContext->decodeSymbol2(this))
return(-1);
Coder.Decode();
}
int Symbol=FoundState->Symbol;
if (!OrderFall && (byte*) FoundState->Successor > SubAlloc.pText)
MinContext=MaxContext=FoundState->Successor;
else
{
UpdateModel();
if (EscCount == 0)
ClearMask();
}
ARI_DEC_NORMALIZE(Coder.code,Coder.low,Coder.range,Coder.UnpackRead);
return(Symbol);
}

122
reference/unrar/model.hpp Normal file
View File

@@ -0,0 +1,122 @@
#ifndef _RAR_PPMMODEL_
#define _RAR_PPMMODEL_
#include "coder.hpp"
#include "suballoc.hpp"
#ifdef ALLOW_MISALIGNED
#pragma pack(1)
#endif
struct RARPPM_DEF
{
static const int INT_BITS=7, PERIOD_BITS=7, TOT_BITS=INT_BITS+PERIOD_BITS,
INTERVAL=1 << INT_BITS, BIN_SCALE=1 << TOT_BITS, MAX_FREQ=124;
};
struct RARPPM_SEE2_CONTEXT : RARPPM_DEF
{ // SEE-contexts for PPM-contexts with masked symbols
ushort Summ;
byte Shift, Count;
void init(int InitVal)
{
Summ=InitVal << (Shift=PERIOD_BITS-4);
Count=4;
}
uint getMean()
{
uint RetVal=GET_SHORT16(Summ) >> Shift;
Summ -= RetVal;
return RetVal+(RetVal == 0);
}
void update()
{
if (Shift < PERIOD_BITS && --Count == 0)
{
Summ += Summ;
Count=3 << Shift++;
}
}
};
class ModelPPM;
struct RARPPM_CONTEXT;
struct RARPPM_STATE
{
byte Symbol;
byte Freq;
RARPPM_CONTEXT* Successor;
};
struct RARPPM_CONTEXT : RARPPM_DEF
{
ushort NumStats;
struct FreqData
{
ushort SummFreq;
RARPPM_STATE RARPPM_PACK_ATTR * Stats;
};
union
{
FreqData U;
RARPPM_STATE OneState;
};
RARPPM_CONTEXT* Suffix;
inline void encodeBinSymbol(ModelPPM *Model,int symbol); // MaxOrder:
inline void encodeSymbol1(ModelPPM *Model,int symbol); // ABCD context
inline void encodeSymbol2(ModelPPM *Model,int symbol); // BCD suffix
inline void decodeBinSymbol(ModelPPM *Model); // BCDE successor
inline bool decodeSymbol1(ModelPPM *Model); // other orders:
inline bool decodeSymbol2(ModelPPM *Model); // BCD context
inline void update1(ModelPPM *Model,RARPPM_STATE* p); // CD suffix
inline void update2(ModelPPM *Model,RARPPM_STATE* p); // BCDE successor
void rescale(ModelPPM *Model);
inline RARPPM_CONTEXT* createChild(ModelPPM *Model,RARPPM_STATE* pStats,RARPPM_STATE& FirstState);
inline RARPPM_SEE2_CONTEXT* makeEscFreq2(ModelPPM *Model,int Diff);
};
#ifdef ALLOW_MISALIGNED
#ifdef _AIX
#pragma pack(pop)
#else
#pragma pack()
#endif
#endif
class ModelPPM : RARPPM_DEF
{
private:
friend struct RARPPM_CONTEXT;
RARPPM_SEE2_CONTEXT SEE2Cont[25][16], DummySEE2Cont;
struct RARPPM_CONTEXT *MinContext, *MedContext, *MaxContext;
RARPPM_STATE* FoundState; // found next state transition
int NumMasked, InitEsc, OrderFall, MaxOrder, RunLength, InitRL;
byte CharMask[256], NS2Indx[256], NS2BSIndx[256], HB2Flag[256];
byte EscCount, PrevSuccess, HiBitsFlag;
ushort BinSumm[128][64]; // binary SEE-contexts
RangeCoder Coder;
SubAllocator SubAlloc;
void RestartModelRare();
void StartModelRare(int MaxOrder);
inline RARPPM_CONTEXT* CreateSuccessors(bool Skip,RARPPM_STATE* p1);
inline void UpdateModel();
inline void ClearMask();
public:
ModelPPM();
void CleanUp(); // reset PPM variables after data error
bool DecodeInit(Unpack *UnpackRead,int &EscChar);
int DecodeChar();
};
#endif

View File

@@ -0,0 +1,35 @@
#include "rar.hpp"
RAROptions::RAROptions()
{
Init();
}
RAROptions::~RAROptions()
{
// It is important for security reasons, so we do not have the unnecessary
// password data left in memory.
memset(this,0,sizeof(RAROptions));
}
void RAROptions::Init()
{
memset(this,0,sizeof(RAROptions));
WinSize=0x2000000;
Overwrite=OVERWRITE_DEFAULT;
Method=3;
MsgStream=MSG_STDOUT;
ConvertNames=NAMES_ORIGINALCASE;
xmtime=EXTTIME_HIGH3;
FileSizeLess=INT64NDF;
FileSizeMore=INT64NDF;
HashType=HASH_CRC32;
#ifdef RAR_SMP
Threads=GetNumberOfThreads();
#endif
#ifdef USE_QOPEN
QOpenMode=QOPEN_AUTO;
#endif
}

191
reference/unrar/options.hpp Normal file
View File

@@ -0,0 +1,191 @@
#ifndef _RAR_OPTIONS_
#define _RAR_OPTIONS_
#define DEFAULT_RECOVERY -3
#define DEFAULT_RECVOLUMES -10
#define VOLSIZE_AUTO INT64NDF // Automatically detect the volume size.
enum PATH_EXCL_MODE {
EXCL_UNCHANGED=0, // Process paths as is (default).
EXCL_SKIPWHOLEPATH, // -ep (exclude the path completely)
EXCL_BASEPATH, // -ep1 (exclude the base part of path)
EXCL_SAVEFULLPATH, // -ep2 (the full path without the disk letter)
EXCL_ABSPATH, // -ep3 (the full path with the disk letter)
EXCL_SKIPABSPATH // Works as EXCL_BASEPATH for fully qualified paths
// and as EXCL_UNCHANGED for relative paths.
// Used by WinRAR GUI only.
};
enum {SOLID_NONE=0,SOLID_NORMAL=1,SOLID_COUNT=2,SOLID_FILEEXT=4,
SOLID_VOLUME_DEPENDENT=8,SOLID_VOLUME_INDEPENDENT=16};
enum {ARCTIME_NONE=0,ARCTIME_KEEP,ARCTIME_LATEST};
enum EXTTIME_MODE {
EXTTIME_NONE=0,EXTTIME_1S,EXTTIME_HIGH1,EXTTIME_HIGH2,EXTTIME_HIGH3
};
enum {NAMES_ORIGINALCASE=0,NAMES_UPPERCASE,NAMES_LOWERCASE};
enum MESSAGE_TYPE {MSG_STDOUT=0,MSG_STDERR,MSG_ERRONLY,MSG_NULL};
enum RECURSE_MODE
{
RECURSE_NONE=0, // no recurse switches
RECURSE_DISABLE, // switch -r-
RECURSE_ALWAYS, // switch -r
RECURSE_WILDCARDS, // switch -r0
};
enum OVERWRITE_MODE
{
OVERWRITE_DEFAULT=0, // Ask when extracting, silently overwrite when archiving.
OVERWRITE_ALL,
OVERWRITE_NONE,
OVERWRITE_AUTORENAME,
OVERWRITE_FORCE_ASK
};
enum QOPEN_MODE { QOPEN_NONE, QOPEN_AUTO, QOPEN_ALWAYS };
enum RAR_CHARSET { RCH_DEFAULT=0,RCH_ANSI,RCH_OEM,RCH_UNICODE,RCH_UTF8 };
#define MAX_FILTER_TYPES 16
enum FilterState {FILTER_DEFAULT=0,FILTER_AUTO,FILTER_FORCE,FILTER_DISABLE};
enum SAVECOPY_MODE {
SAVECOPY_NONE=0, SAVECOPY_SILENT, SAVECOPY_LIST, SAVECOPY_LISTEXIT,
SAVECOPY_DUPLISTEXIT
};
struct FilterMode
{
FilterState State;
int Param1;
int Param2;
};
#define MAX_GENERATE_MASK 128
class RAROptions
{
public:
RAROptions();
~RAROptions();
void Init();
uint ExclFileAttr;
uint InclFileAttr;
bool InclAttrSet;
size_t WinSize;
wchar TempPath[NM];
#ifdef USE_QOPEN
wchar SFXModule[NM];
QOPEN_MODE QOpenMode;
#endif
bool ConfigDisabled; // Switch -cfg-.
wchar ExtrPath[NM];
wchar CommentFile[NM];
RAR_CHARSET CommentCharset;
RAR_CHARSET FilelistCharset;
RAR_CHARSET ErrlogCharset;
RAR_CHARSET RedirectCharset;
wchar ArcPath[NM];
SecPassword Password;
bool EncryptHeaders;
bool ManualPassword; // Password entered manually during operation, might need to clean for next archive.
wchar LogName[NM];
MESSAGE_TYPE MsgStream;
bool Sound;
OVERWRITE_MODE Overwrite;
int Method;
HASH_TYPE HashType;
int Recovery;
int RecVolNumber;
bool DisablePercentage;
bool DisableCopyright;
bool DisableDone;
bool PrintVersion;
int Solid;
int SolidCount;
bool ClearArc;
bool AddArcOnly;
bool DisableComment;
bool FreshFiles;
bool UpdateFiles;
PATH_EXCL_MODE ExclPath;
RECURSE_MODE Recurse;
int64 VolSize;
Array<int64> NextVolSizes;
uint CurVolNum;
bool AllYes;
bool DisableSortSolid;
int ArcTime;
int ConvertNames;
bool ProcessOwners;
bool SaveSymLinks;
bool SaveHardLinks;
bool AbsoluteLinks;
int Priority;
int SleepTime;
bool KeepBroken;
bool OpenShared;
bool DeleteFiles;
#ifdef _WIN_ALL
bool AllowIncompatNames; // Allow names with trailing dots and spaces.
#endif
#ifndef SFX_MODULE
bool GenerateArcName;
wchar GenerateMask[MAX_GENERATE_MASK];
#endif
bool SyncFiles;
bool ProcessEA;
bool SaveStreams;
bool SetCompressedAttr;
bool IgnoreGeneralAttr;
RarTime FileTimeBefore;
RarTime FileTimeAfter;
int64 FileSizeLess;
int64 FileSizeMore;
bool Lock;
bool Test;
bool VolumePause;
FilterMode FilterModes[MAX_FILTER_TYPES];
wchar EmailTo[NM];
uint VersionControl;
bool AppendArcNameToPath;
bool Shutdown;
EXTTIME_MODE xmtime;
EXTTIME_MODE xctime;
EXTTIME_MODE xatime;
wchar CompressStdin[NM];
uint Threads; // We use it to init hash even if RAR_SMP is not defined.
#ifdef RARDLL
wchar DllDestName[NM];
int DllOpMode;
int DllError;
LPARAM UserData;
UNRARCALLBACK Callback;
CHANGEVOLPROC ChangeVolProc;
PROCESSDATAPROC ProcessDataProc;
#endif
};
#endif

253
reference/unrar/os.hpp Normal file
View File

@@ -0,0 +1,253 @@
#ifndef _RAR_OS_
#define _RAR_OS_
#define FALSE 0
#define TRUE 1
#ifdef __EMX__
#define INCL_BASE
#endif
#if defined(RARDLL) && !defined(SILENT)
#define SILENT
#endif
#include <new>
#if defined(_WIN_ALL) || defined(_EMX)
#define LITTLE_ENDIAN
#define NM 2048
#ifdef _WIN_ALL
#define STRICT
#define UNICODE
#undef WINVER
#undef _WIN32_WINNT
#define WINVER 0x0501
#define _WIN32_WINNT 0x0501
#if !defined(ZIPSFX)
#define RAR_SMP
#endif
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <prsht.h>
#include <shlwapi.h>
#pragma comment(lib, "Shlwapi.lib")
#include <shellapi.h>
#include <shlobj.h>
#include <winioctl.h>
#include <wincrypt.h>
#include <wchar.h>
#include <wctype.h>
#endif // _WIN_ALL
#include <sys/types.h>
#include <sys/stat.h>
#include <dos.h>
#if !defined(_EMX) && !defined(_MSC_VER)
#include <dir.h>
#endif
#ifdef _MSC_VER
#if _MSC_VER<1500
#define for if (0) ; else for
#endif
#include <direct.h>
#include <intrin.h>
#define USE_SSE
#define SSE_ALIGNMENT 16
#else
#include <dirent.h>
#endif // _MSC_VER
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#include <dos.h>
#include <io.h>
#include <time.h>
#include <signal.h>
#define SAVE_LINKS
#define ENABLE_ACCESS
#define DefConfigName L"rar.ini"
#define DefLogName L"rar.log"
#define SPATHDIVIDER L"\\"
#define CPATHDIVIDER '\\'
#define MASKALL L"*"
#define READBINARY "rb"
#define READTEXT "rt"
#define UPDATEBINARY "r+b"
#define CREATEBINARY "w+b"
#define WRITEBINARY "wb"
#define APPENDTEXT "at"
#if defined(_WIN_ALL)
#ifdef _MSC_VER
#define _stdfunction __cdecl
#define _forceinline __forceinline
#else
#define _stdfunction _USERENTRY
#define _forceinline inline
#endif
#else
#define _stdfunction
#define _forceinline inline
#endif
#endif // defined(_WIN_ALL) || defined(_EMX)
#ifdef _UNIX
#define NM 2048
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#if defined(__QNXNTO__)
#include <sys/param.h>
#endif
#if defined(RAR_SMP) && defined(__APPLE__)
#include <sys/sysctl.h>
#endif
#ifndef SFX_MODULE
#include <sys/statvfs.h>
#endif
#include <pwd.h>
#include <grp.h>
#include <wchar.h>
#include <wctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#include <errno.h>
#include <dirent.h>
#include <time.h>
#include <signal.h>
#include <utime.h>
#include <locale.h>
#ifdef S_IFLNK
#define SAVE_LINKS
#endif
#if defined(__linux) || defined(__FreeBSD__)
#include <sys/time.h>
#define USE_LUTIMES
#endif
#define ENABLE_ACCESS
#define DefConfigName L".rarrc"
#define DefLogName L".rarlog"
#define SPATHDIVIDER L"/"
#define CPATHDIVIDER '/'
#define MASKALL L"*"
#define READBINARY "r"
#define READTEXT "r"
#define UPDATEBINARY "r+"
#define CREATEBINARY "w+"
#define WRITEBINARY "w"
#define APPENDTEXT "a"
#define _stdfunction
#define _forceinline inline
#ifdef _APPLE
#if defined(__BIG_ENDIAN__) && !defined(BIG_ENDIAN)
#define BIG_ENDIAN
#undef LITTLE_ENDIAN
#endif
#if defined(__i386__) && !defined(LITTLE_ENDIAN)
#define LITTLE_ENDIAN
#undef BIG_ENDIAN
#endif
#endif
#if defined(__sparc) || defined(sparc) || defined(__hpux)
#ifndef BIG_ENDIAN
#define BIG_ENDIAN
#endif
#endif
#if _POSIX_C_SOURCE >= 200809L
#define UNIX_TIME_NS // Nanosecond time precision in Unix.
#endif
#endif // _UNIX
#if 0
#define MSGID_INT
typedef int MSGID;
#else
typedef const wchar* MSGID;
#endif
#ifndef SSE_ALIGNMENT // No SSE use and no special data alignment is required.
#define SSE_ALIGNMENT 1
#endif
#define safebuf static
// Solaris defines _LITTLE_ENDIAN or _BIG_ENDIAN.
#if defined(_LITTLE_ENDIAN) && !defined(LITTLE_ENDIAN)
#define LITTLE_ENDIAN
#endif
#if defined(_BIG_ENDIAN) && !defined(BIG_ENDIAN)
#define BIG_ENDIAN
#endif
#if !defined(LITTLE_ENDIAN) && !defined(BIG_ENDIAN)
#if defined(__i386) || defined(i386) || defined(__i386__) || defined(__x86_64)
#define LITTLE_ENDIAN
#elif defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN || defined(__LITTLE_ENDIAN__)
#define LITTLE_ENDIAN
#elif defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN || defined(__BIG_ENDIAN__)
#define BIG_ENDIAN
#else
#error "Neither LITTLE_ENDIAN nor BIG_ENDIAN are defined. Define one of them."
#endif
#endif
#if defined(LITTLE_ENDIAN) && defined(BIG_ENDIAN)
#if defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN
#undef LITTLE_ENDIAN
#elif defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN
#undef BIG_ENDIAN
#else
#error "Both LITTLE_ENDIAN and BIG_ENDIAN are defined. Undef one of them."
#endif
#endif
#if !defined(BIG_ENDIAN) && defined(_WIN_ALL) || defined(__i386__) || defined(__x86_64__)
// Allow not aligned integer access, increases speed in some operations.
#define ALLOW_MISALIGNED
#endif
#endif // _RAR_OS_

983
reference/unrar/pathfn.cpp Normal file
View File

@@ -0,0 +1,983 @@
#include "rar.hpp"
wchar* PointToName(const wchar *Path)
{
for (int I=(int)wcslen(Path)-1;I>=0;I--)
if (IsPathDiv(Path[I]))
return (wchar*)&Path[I+1];
return (wchar*)((*Path && IsDriveDiv(Path[1])) ? Path+2:Path);
}
wchar* PointToLastChar(const wchar *Path)
{
size_t Length=wcslen(Path);
return (wchar*)(Length>0 ? Path+Length-1:Path);
}
wchar* ConvertPath(const wchar *SrcPath,wchar *DestPath)
{
const wchar *DestPtr=SrcPath;
// Prevent \..\ in any part of path string.
for (const wchar *s=DestPtr;*s!=0;s++)
if (IsPathDiv(s[0]) && s[1]=='.' && s[2]=='.' && IsPathDiv(s[3]))
DestPtr=s+4;
// Remove <d>:\ and any sequence of . and \ in the beginning of path string.
while (*DestPtr!=0)
{
const wchar *s=DestPtr;
if (s[0]!=0 && IsDriveDiv(s[1]))
s+=2;
if (s[0]=='\\' && s[1]=='\\')
{
const wchar *Slash=wcschr(s+2,'\\');
if (Slash!=NULL && (Slash=wcschr(Slash+1,'\\'))!=NULL)
s=Slash+1;
}
for (const wchar *t=s;*t!=0;t++)
if (IsPathDiv(*t))
s=t+1;
else
if (*t!='.')
break;
if (s==DestPtr)
break;
DestPtr=s;
}
// Code above does not remove last "..", doing here.
if (DestPtr[0]=='.' && DestPtr[1]=='.' && DestPtr[2]==0)
DestPtr+=2;
if (DestPath!=NULL)
{
// SrcPath and DestPath can point to same memory area,
// so we use the temporary buffer for copying.
wchar TmpStr[NM];
wcsncpyz(TmpStr,DestPtr,ASIZE(TmpStr));
wcscpy(DestPath,TmpStr);
}
return (wchar *)DestPtr;
}
void SetName(wchar *FullName,const wchar *Name,size_t MaxSize)
{
wchar *NamePtr=PointToName(FullName);
wcsncpyz(NamePtr,Name,MaxSize-(NamePtr-FullName));
}
void SetExt(wchar *Name,const wchar *NewExt,size_t MaxSize)
{
if (Name==NULL || *Name==0)
return;
wchar *Dot=GetExt(Name);
if (Dot!=NULL)
*Dot=0;
if (NewExt!=NULL)
{
wcsncatz(Name,L".",MaxSize);
wcsncatz(Name,NewExt,MaxSize);
}
}
#ifndef SFX_MODULE
void SetSFXExt(wchar *SFXName,size_t MaxSize)
{
if (SFXName==NULL || *SFXName==0)
return;
#ifdef _UNIX
SetExt(SFXName,L"sfx",MaxSize);
#endif
#if defined(_WIN_ALL) || defined(_EMX)
SetExt(SFXName,L"exe",MaxSize);
#endif
}
#endif
// 'Ext' is an extension with the leading dot, like L".rar".
wchar *GetExt(const wchar *Name)
{
return Name==NULL ? NULL:wcsrchr(PointToName(Name),'.');
}
// 'Ext' is an extension without the leading dot, like L"rar".
bool CmpExt(const wchar *Name,const wchar *Ext)
{
wchar *NameExt=GetExt(Name);
return NameExt!=NULL && wcsicomp(NameExt+1,Ext)==0;
}
bool IsWildcard(const wchar *Str)
{
return Str==NULL ? false:wcspbrk(Str,L"*?")!=NULL;
}
bool IsPathDiv(int Ch)
{
#ifdef _WIN_ALL
return Ch=='\\' || Ch=='/';
#else
return Ch==CPATHDIVIDER;
#endif
}
bool IsDriveDiv(int Ch)
{
#ifdef _UNIX
return false;
#else
return Ch==':';
#endif
}
bool IsDriveLetter(const wchar *Path)
{
wchar Letter=etoupperw(Path[0]);
return Letter>='A' && Letter<='Z' && IsDriveDiv(Path[1]);
}
int GetPathDisk(const wchar *Path)
{
if (IsDriveLetter(Path))
return etoupperw(*Path)-'A';
else
return -1;
}
void AddEndSlash(wchar *Path,size_t MaxLength)
{
size_t Length=wcslen(Path);
if (Length>0 && Path[Length-1]!=CPATHDIVIDER && Length+1<MaxLength)
wcscat(Path,SPATHDIVIDER);
}
void MakeName(const wchar *Path,const wchar *Name,wchar *Pathname,size_t MaxSize)
{
// 'Name' and 'Pathname' can point to same memory area. This is why we use
// the temporary buffer instead of constructing the name in 'Pathname'.
wchar OutName[NM];
wcsncpyz(OutName,Path,ASIZE(OutName));
AddEndSlash(OutName,ASIZE(OutName));
wcsncatz(OutName,Name,ASIZE(OutName));
wcsncpyz(Pathname,OutName,MaxSize);
}
// Returns file path including the trailing path separator symbol.
void GetFilePath(const wchar *FullName,wchar *Path,size_t MaxLength)
{
if (MaxLength==0)
return;
size_t PathLength=Min(MaxLength-1,size_t(PointToName(FullName)-FullName));
wcsncpy(Path,FullName,PathLength);
Path[PathLength]=0;
}
// Removes name and returns file path without the trailing
// path separator symbol.
void RemoveNameFromPath(wchar *Path)
{
wchar *Name=PointToName(Path);
if (Name>=Path+2 && (!IsDriveDiv(Path[1]) || Name>=Path+4))
Name--;
*Name=0;
}
#if defined(_WIN_ALL) && !defined(SFX_MODULE)
bool GetAppDataPath(wchar *Path,size_t MaxSize,bool Create)
{
LPMALLOC g_pMalloc;
SHGetMalloc(&g_pMalloc);
LPITEMIDLIST ppidl;
*Path=0;
bool Success=false;
if (SHGetSpecialFolderLocation(NULL,CSIDL_APPDATA,&ppidl)==NOERROR &&
SHGetPathFromIDList(ppidl,Path) && *Path!=0)
{
AddEndSlash(Path,MaxSize);
wcsncatz(Path,L"WinRAR",MaxSize);
Success=FileExist(Path);
if (!Success && Create)
Success=MakeDir(Path,false,0)==MKDIR_SUCCESS;
}
g_pMalloc->Free(ppidl);
return Success;
}
#endif
#if defined(_WIN_ALL) && !defined(SFX_MODULE)
void GetRarDataPath(wchar *Path,size_t MaxSize,bool Create)
{
*Path=0;
HKEY hKey;
if (RegOpenKeyEx(HKEY_CURRENT_USER,L"Software\\WinRAR\\Paths",0,
KEY_QUERY_VALUE,&hKey)==ERROR_SUCCESS)
{
DWORD DataSize=(DWORD)MaxSize,Type;
RegQueryValueEx(hKey,L"AppData",0,&Type,(BYTE *)Path,&DataSize);
RegCloseKey(hKey);
}
if (*Path==0 || !FileExist(Path))
if (!GetAppDataPath(Path,MaxSize,Create))
{
GetModuleFileName(NULL,Path,(DWORD)MaxSize);
RemoveNameFromPath(Path);
}
}
#endif
#ifndef SFX_MODULE
bool EnumConfigPaths(uint Number,wchar *Path,size_t MaxSize,bool Create)
{
#ifdef _UNIX
static const wchar *ConfPath[]={
L"/etc", L"/etc/rar", L"/usr/lib", L"/usr/local/lib", L"/usr/local/etc"
};
if (Number==0)
{
char *EnvStr=getenv("HOME");
if (EnvStr!=NULL)
GetWideName(EnvStr,NULL,Path,MaxSize);
else
wcsncpyz(Path, ConfPath[0], MaxSize);
return true;
}
Number--;
if (Number>=ASIZE(ConfPath))
return false;
wcsncpyz(Path,ConfPath[Number], MaxSize);
return true;
#elif defined(_WIN_ALL)
if (Number>1)
return false;
if (Number==0)
GetRarDataPath(Path,MaxSize,Create);
else
{
GetModuleFileName(NULL,Path,(DWORD)MaxSize);
RemoveNameFromPath(Path);
}
return true;
#else
return false;
#endif
}
#endif
#ifndef SFX_MODULE
void GetConfigName(const wchar *Name,wchar *FullName,size_t MaxSize,bool CheckExist,bool Create)
{
*FullName=0;
for (uint I=0;EnumConfigPaths(I,FullName,MaxSize,Create);I++)
{
AddEndSlash(FullName,MaxSize);
wcsncatz(FullName,Name,MaxSize);
if (!CheckExist || WildFileExist(FullName))
break;
}
}
#endif
// Returns a pointer to rightmost digit of volume number.
wchar* GetVolNumPart(const wchar *ArcName)
{
// Pointing to last name character.
const wchar *ChPtr=ArcName+wcslen(ArcName)-1;
// Skipping the archive extension.
while (!IsDigit(*ChPtr) && ChPtr>ArcName)
ChPtr--;
// Skipping the numeric part of name.
const wchar *NumPtr=ChPtr;
while (IsDigit(*NumPtr) && NumPtr>ArcName)
NumPtr--;
// Searching for first numeric part in names like name.part##of##.rar.
// Stop search on the first dot.
while (NumPtr>ArcName && *NumPtr!='.')
{
if (IsDigit(*NumPtr))
{
// Validate the first numeric part only if it has a dot somewhere
// before it.
wchar *Dot=wcschr(PointToName(ArcName),'.');
if (Dot!=NULL && Dot<NumPtr)
ChPtr=NumPtr;
break;
}
NumPtr--;
}
return (wchar *)ChPtr;
}
void NextVolumeName(wchar *ArcName,uint MaxLength,bool OldNumbering)
{
wchar *ChPtr;
if ((ChPtr=GetExt(ArcName))==NULL)
{
wcsncatz(ArcName,L".rar",MaxLength);
ChPtr=GetExt(ArcName);
}
else
if (ChPtr[1]==0 && wcslen(ArcName)<MaxLength-3 || wcsicomp(ChPtr+1,L"exe")==0 || wcsicomp(ChPtr+1,L"sfx")==0)
wcscpy(ChPtr+1,L"rar");
if (!OldNumbering)
{
ChPtr=GetVolNumPart(ArcName);
while ((++(*ChPtr))=='9'+1)
{
*ChPtr='0';
ChPtr--;
if (ChPtr<ArcName || !IsDigit(*ChPtr))
{
for (wchar *EndPtr=ArcName+wcslen(ArcName);EndPtr!=ChPtr;EndPtr--)
*(EndPtr+1)=*EndPtr;
*(ChPtr+1)='1';
break;
}
}
}
else
if (!IsDigit(*(ChPtr+2)) || !IsDigit(*(ChPtr+3)))
wcscpy(ChPtr+2,L"00");
else
{
ChPtr+=3;
while ((++(*ChPtr))=='9'+1)
if (*(ChPtr-1)=='.')
{
*ChPtr='A';
break;
}
else
{
*ChPtr='0';
ChPtr--;
}
}
}
bool IsNameUsable(const wchar *Name)
{
#ifndef _UNIX
if (Name[0] && Name[1] && wcschr(Name+2,':')!=NULL)
return false;
for (const wchar *s=Name;*s!=0;s++)
{
if ((uint)*s<32)
return false;
if ((*s==' ' || *s=='.') && IsPathDiv(s[1]))
return false;
}
#endif
return *Name!=0 && wcspbrk(Name,L"?*<>|\"")==NULL;
}
void MakeNameUsable(char *Name,bool Extended)
{
#ifdef _WIN_ALL
// In Windows we also need to convert characters not defined in current
// code page. This double conversion changes them to '?', which is
// catched by code below.
size_t NameLength=strlen(Name);
wchar NameW[NM];
CharToWide(Name,NameW,ASIZE(NameW));
WideToChar(NameW,Name,NameLength+1);
Name[NameLength]=0;
#endif
for (char *s=Name;*s!=0;s=charnext(s))
{
if (strchr(Extended ? "?*<>|\"":"?*",*s)!=NULL || Extended && (byte)*s<32)
*s='_';
#ifdef _EMX
if (*s=='=')
*s='_';
#endif
#ifndef _UNIX
if (s-Name>1 && *s==':')
*s='_';
// Remove ' ' and '.' before path separator, but allow .\ and ..\.
if ((*s==' ' || *s=='.' && s>Name && !IsPathDiv(s[-1]) && s[-1]!='.') && IsPathDiv(s[1]))
*s='_';
#endif
}
}
void MakeNameUsable(wchar *Name,bool Extended)
{
for (wchar *s=Name;*s!=0;s++)
{
if (wcschr(Extended ? L"?*<>|\"":L"?*",*s)!=NULL || Extended && (uint)*s<32)
*s='_';
#ifndef _UNIX
if (s-Name>1 && *s==':')
*s='_';
#if 0 // We already can create such files.
// Remove ' ' and '.' before path separator, but allow .\ and ..\.
if (IsPathDiv(s[1]) && (*s==' ' || *s=='.' && s>Name &&
!IsPathDiv(s[-1]) && (s[-1]!='.' || s>Name+1 && !IsPathDiv(s[-2]))))
*s='_';
#endif
#endif
}
}
void UnixSlashToDos(const char *SrcName,char *DestName,size_t MaxLength)
{
size_t Copied=0;
for (;Copied<MaxLength-1 && SrcName[Copied]!=0;Copied++)
DestName[Copied]=SrcName[Copied]=='/' ? '\\':SrcName[Copied];
DestName[Copied]=0;
}
void DosSlashToUnix(const char *SrcName,char *DestName,size_t MaxLength)
{
size_t Copied=0;
for (;Copied<MaxLength-1 && SrcName[Copied]!=0;Copied++)
DestName[Copied]=SrcName[Copied]=='\\' ? '/':SrcName[Copied];
DestName[Copied]=0;
}
void UnixSlashToDos(const wchar *SrcName,wchar *DestName,size_t MaxLength)
{
size_t Copied=0;
for (;Copied<MaxLength-1 && SrcName[Copied]!=0;Copied++)
DestName[Copied]=SrcName[Copied]=='/' ? '\\':SrcName[Copied];
DestName[Copied]=0;
}
void DosSlashToUnix(const wchar *SrcName,wchar *DestName,size_t MaxLength)
{
size_t Copied=0;
for (;Copied<MaxLength-1 && SrcName[Copied]!=0;Copied++)
DestName[Copied]=SrcName[Copied]=='\\' ? '/':SrcName[Copied];
DestName[Copied]=0;
}
void ConvertNameToFull(const wchar *Src,wchar *Dest,size_t MaxSize)
{
if (Src==NULL || *Src==0)
{
if (MaxSize>0)
*Dest=0;
return;
}
#ifdef _WIN_ALL
{
wchar FullName[NM],*NamePtr;
DWORD Code=GetFullPathName(Src,ASIZE(FullName),FullName,&NamePtr);
if (Code==0 || Code>ASIZE(FullName))
{
wchar LongName[NM];
if (GetWinLongPath(Src,LongName,ASIZE(LongName)))
Code=GetFullPathName(LongName,ASIZE(FullName),FullName,&NamePtr);
}
if (Code!=0 && Code<ASIZE(FullName))
wcsncpyz(Dest,FullName,MaxSize);
else
if (Src!=Dest)
wcsncpyz(Dest,Src,MaxSize);
}
#elif defined(_UNIX)
if (IsFullPath(Src))
*Dest=0;
else
{
char CurDirA[NM];
if (getcwd(CurDirA,ASIZE(CurDirA))==NULL)
*CurDirA=0;
CharToWide(CurDirA,Dest,MaxSize);
AddEndSlash(Dest,MaxSize);
}
wcsncatz(Dest,Src,MaxSize);
#else
wcsncpyz(Dest,Src,MaxSize);
#endif
}
bool IsFullPath(const wchar *Path)
{
/*
wchar PathOnly[NM];
GetFilePath(Path,PathOnly,ASIZE(PathOnly));
if (IsWildcard(PathOnly))
return true;
*/
#if defined(_WIN_ALL) || defined(_EMX)
return Path[0]=='\\' && Path[1]=='\\' || IsDriveLetter(Path) && IsPathDiv(Path[2]);
#else
return IsPathDiv(Path[0]);
#endif
}
bool IsFullRootPath(const wchar *Path)
{
return IsFullPath(Path) || IsPathDiv(Path[0]);
}
void GetPathRoot(const wchar *Path,wchar *Root,size_t MaxSize)
{
*Root=0;
if (IsDriveLetter(Path))
swprintf(Root,MaxSize,L"%c:\\",*Path);
else
if (Path[0]=='\\' && Path[1]=='\\')
{
const wchar *Slash=wcschr(Path+2,'\\');
if (Slash!=NULL)
{
size_t Length;
if ((Slash=wcschr(Slash+1,'\\'))!=NULL)
Length=Slash-Path+1;
else
Length=wcslen(Path);
if (Length>=MaxSize)
Length=0;
wcsncpy(Root,Path,Length);
Root[Length]=0;
}
}
}
int ParseVersionFileName(wchar *Name,bool Truncate)
{
int Version=0;
wchar *VerText=wcsrchr(Name,';');
if (VerText!=NULL)
{
if (Version==0)
Version=atoiw(VerText+1);
if (Truncate)
*VerText=0;
}
return Version;
}
#if !defined(SFX_MODULE)
// Get the name of first volume. Return the leftmost digit of volume number.
wchar* VolNameToFirstName(const wchar *VolName,wchar *FirstName,size_t MaxSize,bool NewNumbering)
{
if (FirstName!=VolName)
wcsncpyz(FirstName,VolName,MaxSize);
wchar *VolNumStart=FirstName;
if (NewNumbering)
{
wchar N='1';
// From the rightmost digit of volume number to the left.
for (wchar *ChPtr=GetVolNumPart(FirstName);ChPtr>FirstName;ChPtr--)
if (IsDigit(*ChPtr))
{
*ChPtr=N; // Set the rightmost digit to '1' and others to '0'.
N='0';
}
else
if (N=='0')
{
VolNumStart=ChPtr+1; // Store the position of leftmost digit in volume number.
break;
}
}
else
{
// Old volume numbering scheme. Just set the extension to ".rar".
SetExt(FirstName,L"rar",MaxSize);
VolNumStart=GetExt(FirstName);
}
if (!FileExist(FirstName))
{
// If the first volume, which name we just generated, is not exist,
// check if volume with same name and any other extension is available.
// It can help in case of *.exe or *.sfx first volume.
wchar Mask[NM];
wcsncpyz(Mask,FirstName,ASIZE(Mask));
SetExt(Mask,L"*",ASIZE(Mask));
FindFile Find;
Find.SetMask(Mask);
FindData FD;
while (Find.Next(&FD))
{
Archive Arc;
if (Arc.Open(FD.Name,0) && Arc.IsArchive(true) && Arc.FirstVolume)
{
wcsncpyz(FirstName,FD.Name,MaxSize);
break;
}
}
}
return VolNumStart;
}
#endif
#ifndef SFX_MODULE
static void GenArcName(wchar *ArcName,const wchar *GenerateMask,uint ArcNumber,bool &ArcNumPresent)
{
bool Prefix=false;
if (*GenerateMask=='+')
{
Prefix=true; // Add the time string before the archive name.
GenerateMask++; // Skip '+' in the beginning of time mask.
}
wchar Mask[MAX_GENERATE_MASK];
wcsncpyz(Mask,*GenerateMask!=0 ? GenerateMask:L"yyyymmddhhmmss",ASIZE(Mask));
bool QuoteMode=false,Hours=false;
for (uint I=0;Mask[I]!=0;I++)
{
if (Mask[I]=='{' || Mask[I]=='}')
{
QuoteMode=(Mask[I]=='{');
continue;
}
if (QuoteMode)
continue;
int CurChar=toupperw(Mask[I]);
if (CurChar=='H')
Hours=true;
if (Hours && CurChar=='M')
{
// Replace minutes with 'I'. We use 'M' both for months and minutes,
// so we treat as minutes only those 'M' which are found after hours.
Mask[I]='I';
}
if (CurChar=='N')
{
uint Digits=GetDigits(ArcNumber);
uint NCount=0;
while (toupperw(Mask[I+NCount])=='N')
NCount++;
// Here we ensure that we have enough 'N' characters to fit all digits
// of archive number. We'll replace them by actual number later
// in this function.
if (NCount<Digits)
{
wmemmove(Mask+I+Digits,Mask+I+NCount,wcslen(Mask+I+NCount)+1);
wmemset(Mask+I,'N',Digits);
}
I+=Max(Digits,NCount)-1;
ArcNumPresent=true;
continue;
}
}
RarTime CurTime;
CurTime.SetCurrentTime();
RarLocalTime rlt;
CurTime.GetLocal(&rlt);
wchar Ext[NM],*Dot=GetExt(ArcName);
*Ext=0;
if (Dot==NULL)
wcscpy(Ext,*PointToName(ArcName)==0 ? L".rar":L"");
else
{
wcsncpyz(Ext,Dot,ASIZE(Ext));
*Dot=0;
}
int WeekDay=rlt.wDay==0 ? 6:rlt.wDay-1;
int StartWeekDay=rlt.yDay-WeekDay;
if (StartWeekDay<0)
if (StartWeekDay<=-4)
StartWeekDay+=IsLeapYear(rlt.Year-1) ? 366:365;
else
StartWeekDay=0;
int CurWeek=StartWeekDay/7+1;
if (StartWeekDay%7>=4)
CurWeek++;
char Field[10][6];
sprintf(Field[0],"%04u",rlt.Year);
sprintf(Field[1],"%02u",rlt.Month);
sprintf(Field[2],"%02u",rlt.Day);
sprintf(Field[3],"%02u",rlt.Hour);
sprintf(Field[4],"%02u",rlt.Minute);
sprintf(Field[5],"%02u",rlt.Second);
sprintf(Field[6],"%02u",(uint)CurWeek);
sprintf(Field[7],"%u",(uint)WeekDay+1);
sprintf(Field[8],"%03u",rlt.yDay+1);
sprintf(Field[9],"%05u",ArcNumber);
const wchar *MaskChars=L"YMDHISWAEN";
int CField[sizeof(Field)/sizeof(Field[0])];
memset(CField,0,sizeof(CField));
QuoteMode=false;
for (int I=0;Mask[I]!=0;I++)
{
if (Mask[I]=='{' || Mask[I]=='}')
{
QuoteMode=(Mask[I]=='{');
continue;
}
if (QuoteMode)
continue;
const wchar *ChPtr=wcschr(MaskChars,toupperw(Mask[I]));
if (ChPtr!=NULL)
CField[ChPtr-MaskChars]++;
}
wchar DateText[MAX_GENERATE_MASK];
*DateText=0;
QuoteMode=false;
for (size_t I=0,J=0;Mask[I]!=0 && J<ASIZE(DateText)-1;I++)
{
if (Mask[I]=='{' || Mask[I]=='}')
{
QuoteMode=(Mask[I]=='{');
continue;
}
const wchar *ChPtr=wcschr(MaskChars,toupperw(Mask[I]));
if (ChPtr==NULL || QuoteMode)
{
DateText[J]=Mask[I];
#ifdef _WIN_ALL
// We do not allow ':' in Windows because of NTFS streams.
// Users had problems after specifying hh:mm mask.
if (DateText[J]==':')
DateText[J]='_';
#endif
}
else
{
size_t FieldPos=ChPtr-MaskChars;
int CharPos=(int)strlen(Field[FieldPos])-CField[FieldPos]--;
if (FieldPos==1 && toupperw(Mask[I+1])=='M' && toupperw(Mask[I+2])=='M')
{
wcsncpyz(DateText+J,GetMonthName(rlt.Month-1),ASIZE(DateText)-J);
J=wcslen(DateText);
I+=2;
continue;
}
if (CharPos<0)
DateText[J]=Mask[I];
else
DateText[J]=Field[FieldPos][CharPos];
}
DateText[++J]=0;
}
if (Prefix)
{
wchar NewName[NM];
GetFilePath(ArcName,NewName,ASIZE(NewName));
AddEndSlash(NewName,ASIZE(NewName));
wcsncatz(NewName,DateText,ASIZE(NewName));
wcsncatz(NewName,PointToName(ArcName),ASIZE(NewName));
wcscpy(ArcName,NewName);
}
else
wcscat(ArcName,DateText);
wcscat(ArcName,Ext);
}
void GenerateArchiveName(wchar *ArcName,size_t MaxSize,const wchar *GenerateMask,bool Archiving)
{
// Must be enough space for archive name plus all stuff in mask plus
// extra overhead produced by mask 'N' (archive number) characters.
// One 'N' character can result in several numbers if we process more
// than 9 archives.
wchar NewName[NM+MAX_GENERATE_MASK+20];
uint ArcNumber=1;
while (true) // Loop for 'N' (archive number) processing.
{
wcsncpyz(NewName,ArcName,ASIZE(NewName));
bool ArcNumPresent=false;
GenArcName(NewName,GenerateMask,ArcNumber,ArcNumPresent);
if (!ArcNumPresent)
break;
if (!FileExist(NewName))
{
if (!Archiving && ArcNumber>1)
{
// If we perform non-archiving operation, we need to use the last
// existing archive before the first unused name. So we generate
// the name for (ArcNumber-1) below.
wcsncpyz(NewName,NullToEmpty(ArcName),ASIZE(NewName));
GenArcName(NewName,GenerateMask,ArcNumber-1,ArcNumPresent);
}
break;
}
ArcNumber++;
}
wcsncpyz(ArcName,NewName,MaxSize);
}
#endif
wchar* GetWideName(const char *Name,const wchar *NameW,wchar *DestW,size_t DestSize)
{
if (NameW!=NULL && *NameW!=0)
{
if (DestW!=NameW)
wcsncpy(DestW,NameW,DestSize);
}
else
if (Name!=NULL)
CharToWide(Name,DestW,DestSize);
else
*DestW=0;
// Ensure that we return a zero terminate string for security reasons.
if (DestSize>0)
DestW[DestSize-1]=0;
return DestW;
}
#ifdef _WIN_ALL
// We should return 'true' even if resulting path is shorter than MAX_PATH,
// because we can also use this function to open files with non-standard
// characters, even if their path length is normal.
bool GetWinLongPath(const wchar *Src,wchar *Dest,size_t MaxSize)
{
if (*Src==0)
return false;
const wchar *Prefix=L"\\\\?\\";
const size_t PrefixLength=4;
bool FullPath=IsDriveLetter(Src) && IsPathDiv(Src[2]);
size_t SrcLength=wcslen(Src);
if (IsFullPath(Src)) // Paths in d:\path\name format.
{
if (IsDriveLetter(Src))
{
if (MaxSize<=PrefixLength+SrcLength)
return false;
wcsncpy(Dest,Prefix,PrefixLength);
wcscpy(Dest+PrefixLength,Src);
return true;
}
else
if (Src[0]=='\\' && Src[1]=='\\')
{
if (MaxSize<=PrefixLength+SrcLength+2)
return false;
wcsncpy(Dest,Prefix,PrefixLength);
wcscpy(Dest+PrefixLength,L"UNC");
wcscpy(Dest+PrefixLength+3,Src+1);
return true;
}
// We may be here only if we modify IsFullPath in the future.
return false;
}
else
{
wchar CurDir[NM];
DWORD DirCode=GetCurrentDirectory(ASIZE(CurDir)-1,CurDir);
if (DirCode==0 || DirCode>ASIZE(CurDir)-1)
return false;
if (IsPathDiv(Src[0])) // Paths in \path\name format.
{
if (MaxSize<=PrefixLength+SrcLength+2)
return false;
wcsncpy(Dest,Prefix,PrefixLength);
wcsncpy(Dest+PrefixLength,CurDir,2); // Copy drive letter 'd:'.
wcscpy(Dest+PrefixLength+2,Src);
return true;
}
else // Paths in path\name format.
{
AddEndSlash(CurDir,ASIZE(CurDir));
if (MaxSize<=PrefixLength+wcslen(CurDir)+SrcLength)
return false;
wcsncpy(Dest,Prefix,PrefixLength);
wcscpy(Dest+PrefixLength,CurDir);
if (Src[0]=='.' && IsPathDiv(Src[1])) // Remove leading .\ in pathname.
Src+=2;
wcsncatz(Dest,Src,MaxSize);
return true;
}
}
return false;
}
// Convert Unix, OS X and Android decomposed chracters to Windows precomposed.
void ConvertToPrecomposed(wchar *Name,size_t NameSize)
{
wchar FileName[NM];
if (WinNT()>=WNT_VISTA && // MAP_PRECOMPOSED is not supported in XP.
FoldString(MAP_PRECOMPOSED,Name,-1,FileName,ASIZE(FileName))!=0)
{
FileName[ASIZE(FileName)-1]=0;
wcsncpyz(Name,FileName,NameSize);
}
}
// Remove trailing spaces and dots in file name and in dir names in path.
void MakeNameCompatible(wchar *Name)
{
int Src=0,Dest=0;
while (true)
{
if (IsPathDiv(Name[Src]) || Name[Src]==0)
for (int I=Dest-1;I>0 && (Name[I]==' ' || Name[I]=='.');I--)
{
if (IsPathDiv(Name[I-1])) // Permit path1/./path2 paths.
break;
Dest--;
}
Name[Dest]=Name[Src];
if (Name[Src]==0)
break;
Src++;
Dest++;
}
}
#endif

View File

@@ -0,0 +1,76 @@
#ifndef _RAR_PATHFN_
#define _RAR_PATHFN_
wchar* PointToName(const wchar *Path);
wchar* PointToLastChar(const wchar *Path);
wchar* ConvertPath(const wchar *SrcPath,wchar *DestPath);
void SetName(wchar *FullName,const wchar *Name,size_t MaxSize);
void SetExt(wchar *Name,const wchar *NewExt,size_t MaxSize);
void SetSFXExt(wchar *SFXName,size_t MaxSize);
wchar *GetExt(const wchar *Name);
bool CmpExt(const wchar *Name,const wchar *Ext);
bool IsWildcard(const wchar *Str);
bool IsPathDiv(int Ch);
bool IsDriveDiv(int Ch);
bool IsDriveLetter(const wchar *Path);
int GetPathDisk(const wchar *Path);
void AddEndSlash(wchar *Path,size_t MaxLength);
void MakeName(const wchar *Path,const wchar *Name,wchar *Pathname,size_t MaxSize);
void GetFilePath(const wchar *FullName,wchar *Path,size_t MaxLength);
void RemoveNameFromPath(wchar *Path);
#if defined(_WIN_ALL) && !defined(SFX_MODULE)
bool GetAppDataPath(wchar *Path,size_t MaxSize,bool Create);
void GetRarDataPath(wchar *Path,size_t MaxSize,bool Create);
#endif
#ifndef SFX_MODULE
bool EnumConfigPaths(uint Number,wchar *Path,size_t MaxSize,bool Create);
void GetConfigName(const wchar *Name,wchar *FullName,size_t MaxSize,bool CheckExist,bool Create);
#endif
wchar* GetVolNumPart(const wchar *ArcName);
void NextVolumeName(wchar *ArcName,uint MaxLength,bool OldNumbering);
bool IsNameUsable(const wchar *Name);
void MakeNameUsable(char *Name,bool Extended);
void MakeNameUsable(wchar *Name,bool Extended);
void UnixSlashToDos(const char *SrcName,char *DestName,size_t MaxLength);
void DosSlashToUnix(const char *SrcName,char *DestName,size_t MaxLength);
void UnixSlashToDos(const wchar *SrcName,wchar *DestName,size_t MaxLength);
void DosSlashToUnix(const wchar *SrcName,wchar *DestName,size_t MaxLength);
inline void SlashToNative(const char *SrcName,char *DestName,size_t MaxLength)
{
#ifdef _WIN_ALL
UnixSlashToDos(SrcName,DestName,MaxLength);
#else
DosSlashToUnix(SrcName,DestName,MaxLength);
#endif
}
inline void SlashToNative(const wchar *SrcName,wchar *DestName,size_t MaxLength)
{
#ifdef _WIN_ALL
UnixSlashToDos(SrcName,DestName,MaxLength);
#else
DosSlashToUnix(SrcName,DestName,MaxLength);
#endif
}
void ConvertNameToFull(const wchar *Src,wchar *Dest,size_t MaxSize);
bool IsFullPath(const wchar *Path);
bool IsFullRootPath(const wchar *Path);
void GetPathRoot(const wchar *Path,wchar *Root,size_t MaxSize);
int ParseVersionFileName(wchar *Name,bool Truncate);
wchar* VolNameToFirstName(const wchar *VolName,wchar *FirstName,size_t MaxSize,bool NewNumbering);
wchar* GetWideName(const char *Name,const wchar *NameW,wchar *DestW,size_t DestSize);
#ifndef SFX_MODULE
void GenerateArchiveName(wchar *ArcName,size_t MaxSize,const wchar *GenerateMask,bool Archiving);
#endif
#ifdef _WIN_ALL
bool GetWinLongPath(const wchar *Src,wchar *Dest,size_t MaxSize);
void ConvertToPrecomposed(wchar *Name,size_t NameSize);
void MakeNameCompatible(wchar *Name);
#endif
#endif

272
reference/unrar/qopen.cpp Normal file
View File

@@ -0,0 +1,272 @@
#include "rar.hpp"
QuickOpen::QuickOpen()
{
Buf=NULL;
Init(NULL,false);
}
QuickOpen::~QuickOpen()
{
Close();
delete[] Buf;
}
void QuickOpen::Init(Archive *Arc,bool WriteMode)
{
if (Arc!=NULL) // Unless called from constructor.
Close();
QuickOpen::Arc=Arc;
QuickOpen::WriteMode=WriteMode;
ListStart=NULL;
ListEnd=NULL;
if (Buf==NULL)
Buf=new byte[MaxBufSize];
CurBufSize=0; // Current size of buffered data in write mode.
Loaded=false;
}
void QuickOpen::Close()
{
QuickOpenItem *Item=ListStart;
while (Item!=NULL)
{
QuickOpenItem *Next=Item->Next;
delete[] Item->Header;
delete Item;
Item=Next;
}
}
void QuickOpen::Load(uint64 BlockPos)
{
if (!Loaded) // If loading the first time, perform additional intialization.
{
SeekPos=Arc->Tell();
UnsyncSeekPos=false;
SaveFilePos SavePos(*Arc);
Arc->Seek(BlockPos,SEEK_SET);
if (Arc->ReadHeader()==0 || Arc->GetHeaderType()!=HEAD_SERVICE ||
!Arc->SubHead.CmpName(SUBHEAD_TYPE_QOPEN))
return;
QLHeaderPos=Arc->CurBlockPos;
RawDataStart=Arc->Tell();
RawDataSize=Arc->SubHead.UnpSize;
Loaded=true; // Set only after all file processing calls like Tell, Seek, ReadHeader.
}
if (Arc->SubHead.Encrypted)
{
RAROptions *Cmd=Arc->GetRAROptions();
#ifndef RAR_NOCRYPT
if (Cmd->Password.IsSet())
Crypt.SetCryptKeys(false,CRYPT_RAR50,&Cmd->Password,Arc->SubHead.Salt,
Arc->SubHead.InitV,Arc->SubHead.Lg2Count,
Arc->SubHead.HashKey,Arc->SubHead.PswCheck);
else
#endif
return;
}
RawDataPos=0;
ReadBufSize=0;
ReadBufPos=0;
LastReadHeader.Reset();
LastReadHeaderPos=0;
ReadBuffer();
}
bool QuickOpen::Read(void *Data,size_t Size,size_t &Result)
{
if (!Loaded)
return false;
// Find next suitable cached block.
while (LastReadHeaderPos+LastReadHeader.Size()<=SeekPos)
if (!ReadNext())
break;
if (!Loaded)
{
// If something wrong happened, let's set the correct file pointer
// and stop further quick open processing.
if (UnsyncSeekPos)
Arc->File::Seek(SeekPos,SEEK_SET);
return false;
}
if (SeekPos>=LastReadHeaderPos && SeekPos+Size<=LastReadHeaderPos+LastReadHeader.Size())
{
memcpy(Data,LastReadHeader+size_t(SeekPos-LastReadHeaderPos),Size);
Result=Size;
SeekPos+=Size;
UnsyncSeekPos=true;
}
else
{
if (UnsyncSeekPos)
{
Arc->File::Seek(SeekPos,SEEK_SET);
UnsyncSeekPos=false;
}
int ReadSize=Arc->File::Read(Data,Size);
if (ReadSize<0)
{
Loaded=false;
return false;
}
Result=ReadSize;
SeekPos+=ReadSize;
}
return true;
}
bool QuickOpen::Seek(int64 Offset,int Method)
{
if (!Loaded)
return false;
// Normally we process an archive sequentially from beginning to end,
// so we read quick open data sequentially. But some operations like
// archive updating involve several passes. So if we detect that file
// pointer is moved back, we reload quick open data from beginning.
if (Method==SEEK_SET && (uint64)Offset<SeekPos && (uint64)Offset<LastReadHeaderPos)
Load(QLHeaderPos);
if (Method==SEEK_SET)
SeekPos=Offset;
if (Method==SEEK_CUR)
SeekPos+=Offset;
UnsyncSeekPos=true;
if (Method==SEEK_END)
{
Arc->File::Seek(Offset,SEEK_END);
SeekPos=Arc->File::Tell();
UnsyncSeekPos=false;
}
return true;
}
bool QuickOpen::Tell(int64 *Pos)
{
if (!Loaded)
return false;
*Pos=SeekPos;
return true;
}
uint QuickOpen::ReadBuffer()
{
SaveFilePos SavePos(*Arc);
Arc->File::Seek(RawDataStart+RawDataPos,SEEK_SET);
size_t SizeToRead=(size_t)Min(RawDataSize-RawDataPos,MaxBufSize-ReadBufSize);
if (Arc->SubHead.Encrypted)
SizeToRead &= ~CRYPT_BLOCK_MASK;
if (SizeToRead==0)
return 0;
int ReadSize=Arc->File::Read(Buf+ReadBufSize,SizeToRead);
if (ReadSize<=0)
return 0;
#ifndef RAR_NOCRYPT
if (Arc->SubHead.Encrypted)
Crypt.DecryptBlock(Buf+ReadBufSize,ReadSize & ~CRYPT_BLOCK_MASK);
#endif
RawDataPos+=ReadSize;
ReadBufSize+=ReadSize;
return ReadSize;
}
// Fill RawRead object from buffer.
bool QuickOpen::ReadRaw(RawRead &Raw)
{
if (MaxBufSize-ReadBufPos<0x100) // We are close to end of buffer.
{
// Ensure that we have enough data to read CRC and header size.
size_t DataLeft=ReadBufSize-ReadBufPos;
memcpy(Buf,Buf+ReadBufPos,DataLeft);
ReadBufPos=0;
ReadBufSize=DataLeft;
ReadBuffer();
}
const size_t FirstReadSize=7;
if (ReadBufPos+FirstReadSize>ReadBufSize)
return false;
Raw.Read(Buf+ReadBufPos,FirstReadSize);
ReadBufPos+=FirstReadSize;
uint SavedCRC=Raw.Get4();
uint SizeBytes=Raw.GetVSize(4);
uint64 BlockSize=Raw.GetV();
int SizeToRead=int(BlockSize);
SizeToRead-=FirstReadSize-SizeBytes-4; // Adjust overread size bytes if any.
if (SizeToRead<0 || SizeBytes==0 || BlockSize==0)
{
Loaded=false; // Invalid data.
return false;
}
// If rest of block data crosses buffer boundary, read it in loop.
size_t DataLeft=ReadBufSize-ReadBufPos;
while (SizeToRead>0)
{
size_t CurSizeToRead=Min(DataLeft,(size_t)SizeToRead);
Raw.Read(Buf+ReadBufPos,CurSizeToRead);
ReadBufPos+=CurSizeToRead;
SizeToRead-=int(CurSizeToRead);
if (SizeToRead>0) // We read the entire buffer and still need more data.
{
ReadBufPos=0;
ReadBufSize=0;
if (ReadBuffer()==0)
return false;
}
}
return SavedCRC==Raw.GetCRC50();
}
// Read next cached header.
bool QuickOpen::ReadNext()
{
RawRead Raw(NULL);
if (!ReadRaw(Raw)) // Read internal quick open header preceding stored block.
return false;
uint Flags=(uint)Raw.GetV();
uint64 Offset=Raw.GetV();
size_t HeaderSize=(size_t)Raw.GetV();
LastReadHeader.Alloc(HeaderSize);
Raw.GetB(&LastReadHeader[0],HeaderSize);
// Calculate the absolute position as offset from quick open service header.
LastReadHeaderPos=QLHeaderPos-Offset;
return true;
}

61
reference/unrar/qopen.hpp Normal file
View File

@@ -0,0 +1,61 @@
#ifndef _RAR_QOPEN_
#define _RAR_QOPEN_
struct QuickOpenItem
{
byte *Header;
size_t HeaderSize;
uint64 ArcPos;
QuickOpenItem *Next;
};
class Archive;
class RawRead;
class QuickOpen
{
private:
void Close();
uint ReadBuffer();
bool ReadRaw(RawRead &Raw);
bool ReadNext();
Archive *Arc;
bool WriteMode;
QuickOpenItem *ListStart;
QuickOpenItem *ListEnd;
byte *Buf;
static const size_t MaxBufSize=0x10000; // Must be multiple of CRYPT_BLOCK_SIZE.
size_t CurBufSize;
#ifndef RAR_NOCRYPT // For shell extension.
CryptData Crypt;
#endif
bool Loaded;
uint64 QLHeaderPos;
uint64 RawDataStart;
uint64 RawDataSize;
uint64 RawDataPos;
size_t ReadBufSize;
size_t ReadBufPos;
Array<byte> LastReadHeader;
uint64 LastReadHeaderPos;
uint64 SeekPos;
bool UnsyncSeekPos; // QOpen SeekPos does not match an actual file pointer.
public:
QuickOpen();
~QuickOpen();
void Init(Archive *Arc,bool WriteMode);
void Load(uint64 BlockPos);
void Unload() { Loaded=false; }
bool Read(void *Data,size_t Size,size_t &Result);
bool Seek(int64 Offset,int Method);
bool Tell(int64 *Pos);
};
#endif

105
reference/unrar/rar.cpp Normal file
View File

@@ -0,0 +1,105 @@
#include "rar.hpp"
#if !defined(RARDLL)
int main(int argc, char *argv[])
{
#ifdef _UNIX
setlocale(LC_ALL,"");
#endif
InitConsole();
ErrHandler.SetSignalHandlers(true);
#ifdef SFX_MODULE
wchar ModuleName[NM];
#ifdef _WIN_ALL
GetModuleFileName(NULL,ModuleName,ASIZE(ModuleName));
#else
CharToWide(argv[0],ModuleName,ASIZE(ModuleName));
#endif
#endif
#ifdef _WIN_ALL
SetErrorMode(SEM_NOALIGNMENTFAULTEXCEPT|SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
#endif
#if defined(_WIN_ALL) && !defined(SFX_MODULE)
// Must be initialized, normal initialization can be skipped in case of
// exception.
bool ShutdownOnClose=false;
#endif
try
{
CommandData *Cmd=new CommandData;
#ifdef SFX_MODULE
wcscpy(Cmd->Command,L"X");
char *Switch=argc>1 ? argv[1]:NULL;
if (Switch!=NULL && Cmd->IsSwitch(Switch[0]))
{
int UpperCmd=etoupper(Switch[1]);
switch(UpperCmd)
{
case 'T':
case 'V':
Cmd->Command[0]=UpperCmd;
break;
case '?':
Cmd->OutHelp(RARX_SUCCESS);
break;
}
}
Cmd->AddArcName(ModuleName);
Cmd->ParseDone();
Cmd->AbsoluteLinks=true; // If users runs SFX, he trusts an archive source.
#else // !SFX_MODULE
Cmd->ParseCommandLine(true,argc,argv);
if (!Cmd->ConfigDisabled)
{
Cmd->ReadConfig();
Cmd->ParseEnvVar();
}
Cmd->ParseCommandLine(false,argc,argv);
#endif
#if defined(_WIN_ALL) && !defined(SFX_MODULE)
ShutdownOnClose=Cmd->Shutdown;
#endif
uiInit(Cmd->Sound);
InitConsoleOptions(Cmd->MsgStream,Cmd->RedirectCharset);
InitLogOptions(Cmd->LogName,Cmd->ErrlogCharset);
ErrHandler.SetSilent(Cmd->AllYes || Cmd->MsgStream==MSG_NULL);
Cmd->OutTitle();
Cmd->ProcessCommand();
delete Cmd;
}
catch (RAR_EXIT ErrCode)
{
ErrHandler.SetErrorCode(ErrCode);
}
catch (std::bad_alloc&)
{
ErrHandler.MemoryErrorMsg();
ErrHandler.SetErrorCode(RARX_MEMORY);
}
catch (...)
{
ErrHandler.SetErrorCode(RARX_FATAL);
}
#if defined(_WIN_ALL) && !defined(SFX_MODULE)
if (ShutdownOnClose && ErrHandler.IsShutdownEnabled())
Shutdown();
#endif
ErrHandler.MainExit=true;
return ErrHandler.GetErrorCode();
}
#endif

94
reference/unrar/rar.hpp Normal file
View File

@@ -0,0 +1,94 @@
#ifndef _RAR_RARCOMMON_
#define _RAR_RARCOMMON_
#include "raros.hpp"
#include "rartypes.hpp"
#include "os.hpp"
#ifdef RARDLL
#include "dll.hpp"
#endif
#include "version.hpp"
#include "rardefs.hpp"
#include "rarlang.hpp"
#include "unicode.hpp"
#include "errhnd.hpp"
#include "secpassword.hpp"
#include "array.hpp"
#include "timefn.hpp"
#include "sha1.hpp"
#include "sha256.hpp"
#include "blake2s.hpp"
#include "hash.hpp"
#include "options.hpp"
#include "rijndael.hpp"
#include "crypt.hpp"
#include "headers5.hpp"
#include "headers.hpp"
#include "pathfn.hpp"
#include "strfn.hpp"
#include "strlist.hpp"
#include "file.hpp"
#include "crc.hpp"
#include "ui.hpp"
#include "filefn.hpp"
#include "filestr.hpp"
#include "find.hpp"
#include "scantree.hpp"
#include "savepos.hpp"
#include "getbits.hpp"
#include "rdwrfn.hpp"
#ifdef USE_QOPEN
#include "qopen.hpp"
#endif
#include "archive.hpp"
#include "match.hpp"
#include "cmddata.hpp"
#include "filcreat.hpp"
#include "consio.hpp"
#include "system.hpp"
#ifdef _WIN_ALL
#include "isnt.hpp"
#endif
#include "log.hpp"
#include "rawint.hpp"
#include "rawread.hpp"
#include "encname.hpp"
#include "resource.hpp"
#include "compress.hpp"
#include "rarvm.hpp"
#include "model.hpp"
#include "threadpool.hpp"
#include "unpack.hpp"
#include "extinfo.hpp"
#include "extract.hpp"
#include "list.hpp"
#include "rs.hpp"
#include "rs16.hpp"
#include "recvol.hpp"
#include "volume.hpp"
#include "smallfn.hpp"
#include "global.hpp"
#if 0
#include "benchmark.hpp"
#endif
#endif

Some files were not shown because too many files have changed in this diff Show More