Compare commits

..

194 Commits
0.12.4 ... pax

Author SHA1 Message Date
Adam Hathcock
1f8bd6d7e3 Try Tar PAX reading 2018-02-06 15:21:04 +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
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
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
Adam Hathcock
0f511c4b2a Mark for 0.18.1 2017-08-17 11:43:34 +01:00
twirpx
42d9dfd117 Fixed bug: Passing default ReaderOptions when creating ZipReader for solid extraction (#287) 2017-08-16 08:19:23 +01:00
Adam Hathcock
3983db08ff Use nameof 2017-07-27 11:05:33 -05:00
Adam Hathcock
72114bceea Add release link 2017-07-17 10:22:58 -05:00
Adam Hathcock
c303f96682 mark for 0.18 2017-07-17 10:11:27 -05:00
Adam Hathcock
0e785968c4 Rework usage of WriterOptions for writers since it was inconsistently used. (#271) 2017-07-17 11:05:42 -04:00
Adam Hathcock
15110e18e2 Don't skip ZipReader data twice. (#272)
* Don't skip ZipReader data twice.

* Add archive for a new test
2017-07-17 11:05:21 -04:00
Adam Hathcock
5465af041b Use Skip and ReadFully extension methods where possible. (#276) 2017-07-17 10:55:22 -04:00
Adam Hathcock
310d56fc16 Made ArchiveEncoding a non-static class that is used with options. (#274)
* Made ArchiveEncoding a non-static class that is used with options.

* Revert some formatting.

* Optional string decoder delegate (#278)
2017-07-17 10:53:20 -04:00
eklann
231258ef69 Force encoding (#266)
* Fixing build

* Fixing build

* Fixing build

* Fixed build (seems working now)

* Added support to force specific encoding when reading or writing an archive

* Minor fixed related to force encoding

* Removed obsolete project file not present in master
2017-07-05 10:15:49 -05:00
Sam Bott
16b7e3ffc8 Add XZ tests (#258)
* tests added and converted to xunit

* reordered two assertions
2017-06-11 13:44:00 +01:00
Adam Hathcock
513e59f830 Mark for 0.17.1 2017-06-09 08:28:35 +01:00
Adam Hathcock
b10a1cf2bd Bug on Windows on .NET Core fix (#257)
* Bug on Windows on .NET Core fix: https://github.com/dotnet/corefx/issues/20676

* Add comment
2017-06-09 08:22:47 +01:00
Adam Hathcock
1656edaa29 Add some more details to nuget package 2017-06-01 12:36:01 +01:00
Adam Hathcock
cff49aacba Added explicit tar skip check. Caught skip issue. 2017-06-01 11:25:32 +01:00
Adam Hathcock
19c32aff6c README fixes 2017-06-01 10:56:11 +01:00
Adam Hathcock
db3ec8337f Mark for 0.17 2017-06-01 10:54:50 +01:00
Adam Hathcock
e7bfc40461 Fix Skipping when compressed size is unknown (fallback to decompressing) 2017-06-01 09:26:08 +01:00
Adam Hathcock
3d3ca254ba Zip64 introduced seekable behavior into ZipWriter. The position may … (#252)
* Zip64 introduced seekable behavior into ZipWriter.  The position may not be zero.

* Remove some dead code

* Update formats for zip64

* Make version created by and version needed to extract the same

* Running tests is faster than skipping
2017-05-31 16:55:49 +01:00
Adam Hathcock
b45bc859a4 XZ Format (#247)
* Started integrated XZ format from https://github.com/sambott/XZ.NET

* Add readme line as it was copy/pasted

* Tar used with XZ

* update formats
2017-05-31 16:55:26 +01:00
Adam Hathcock
912d7a8775 Lzip (#245)
* First pass.  Writing isn't implemented on stream.  Tests are busted.

* LZipReader works...no file name :(

* LZipWriter works

* Writing tests are actually correct now.  LZipStream correctly writes trailer now.  lzip command line tool likes it.

* Add recommendation blurb

* Update notes for formats

* LZip isn't an archive format

* Attempting to fix and implement crc32

* LZip writing test passes

* Had to invert crc to check uncompressed data.
2017-05-31 16:51:24 +01:00
Adam Hathcock
16885da1b5 Mark for 0.16.2 2017-05-31 14:47:51 +01:00
Adam Hathcock
26714052eb Merge pull request #249 from adamhathcock/zip_entry_compression_fix
Per entry compression was being written out incorrectly on the centra…
2017-05-31 12:55:37 +01:00
Adam Hathcock
3df763a783 Merge branch 'master' into zip_entry_compression_fix 2017-05-31 11:15:30 +01:00
Adam Hathcock
925842bc4b Merge pull request #251 from dbaumber/Issue-250
Fix for Issue #250: remove extra build flags for .NET 3.5
2017-05-31 10:54:52 +01:00
Dan Baumberger
cead62704e Fix for Issue #250: remove extra build flags for .NET 3.5 as to
enable WinZipAes for .NET 3.5.
2017-05-30 13:43:48 -07:00
Adam Hathcock
3f24a744c0 Merge branch 'master' into zip_entry_compression_fix 2017-05-30 16:10:41 +01:00
Adam Hathcock
cce97548a2 Merge pull request #212 from kenkendk/remove_unused_code
Removed the unused code to write entries in Zip Headers
2017-05-30 16:09:04 +01:00
Adam Hathcock
9270d7cabf Add cache for dotnet packages 2017-05-30 16:04:55 +01:00
Adam Hathcock
264aa6d366 Merge branch 'master' into remove_unused_code 2017-05-30 15:58:44 +01:00
Adam Hathcock
69fc74e376 Per entry compression was being written out incorrectly on the central directory. Fix for that. 2017-05-30 15:37:41 +01:00
Adam Hathcock
a361d41e68 Fix test namespaces 2017-05-30 15:14:02 +01:00
Adam Hathcock
38766dac99 Wrong logic for skipping tests 2017-05-30 12:50:03 +01:00
Adam Hathcock
c30bc65281 Don't run tests on travis either 2017-05-30 12:46:34 +01:00
Adam Hathcock
296ebd942a Shrink script a bit 2017-05-30 12:37:16 +01:00
Adam Hathcock
afa19f7ad8 Add xplat cake and travis build 2017-05-30 12:35:12 +01:00
Adam Hathcock
a193b2d3b1 Add xplat build 2017-05-29 10:35:55 +01:00
Adam Hathcock
be4a65e572 update readme 2017-05-24 08:52:12 +01:00
Adam Hathcock
6832918e71 Mark for 0.16.1 2017-05-23 16:21:07 +01:00
Adam Hathcock
fd9a3ffbcc Merge commit '18641d4f9b849daea7b6fbb7edad51369534ffa3'
* commit '18641d4f9b849daea7b6fbb7edad51369534ffa3':
  Normalize Rar keys
2017-05-23 16:15:58 +01:00
Adam Hathcock
41added690 Private setter clean up 2017-05-23 16:15:47 +01:00
Adam Hathcock
18641d4f9b Merge pull request #238 from adamhathcock/issue_201
Normalize Rar keys
2017-05-23 16:14:55 +01:00
Adam Hathcock
4d0c5099d4 Merge branch 'master' into issue_201 2017-05-23 16:13:09 +01:00
Adam Hathcock
9d9d491245 Slightly better fix for https://github.com/adamhathcock/sharpcompress/pull/235 2017-05-23 16:10:15 +01:00
Adam Hathcock
7b81d18071 Merge pull request #235 from dbaumber/Issue-230
Issue #230: preserve the compression method when getting a compressed…
2017-05-23 15:50:32 +01:00
Dan Baumberger
7d0acbc988 Merge branch 'Issue-230' of https://github.com/dbaumber/sharpcompress into Issue-230 2017-05-23 07:46:48 -07:00
Dan Baumberger
313c044c41 Added a unit test for the WinZipAes multiple OpenEntryStream() bug. 2017-05-23 07:44:45 -07:00
Dan Baumberger
f6f8adf97e Merge branch 'master' into Issue-230 2017-05-23 07:43:02 -07:00
Adam Hathcock
bc97d325ca Normalize Rar keys 2017-05-22 10:55:15 +01:00
Adam Hathcock
0f2d325f20 oh yeah, appveyor doesn't like the tests 2017-05-22 09:08:16 +01:00
Adam Hathcock
63d5503e12 forgot to actually add tests to script 2017-05-22 09:06:33 +01:00
Adam Hathcock
e53f2cac4a Mark for 0.16.0 2017-05-22 08:58:52 +01:00
Adam Hathcock
3b73464233 Merge pull request #236 from damieng/zip-min-version-of-20
Default zip ver to 20 (deflate/encyption), fixes #164
2017-05-22 08:38:18 +01:00
Damien Guard
575f10f766 Default zip ver to 20 (deflate/encyption), fixes #164 2017-05-19 16:37:20 -07:00
Dan Baumberger
8d3fc3533b Issue #230: preserve the compression method when getting a compressed stream for encrypted ZIP archives. 2017-05-19 08:36:11 -07:00
Adam Hathcock
60370b8539 don't run appveyor tests 2017-05-19 15:51:06 +01:00
Adam Hathcock
f6db114865 Remove console writelines 2017-05-19 15:47:53 +01:00
Adam Hathcock
1c6c344b6b Tests don't run on appveyor 2017-05-19 15:45:29 +01:00
Adam Hathcock
d0302898e0 Add back net45,net35 and cake 2017-05-19 13:33:12 +01:00
Adam Hathcock
057ac9b001 Enable test 2017-05-19 11:03:31 +01:00
Adam Hathcock
8be931bbcb Doing some resharper clean up 2017-05-19 10:52:49 +01:00
Adam Hathcock
3197ef289c Forgot to hit save 2017-05-19 10:15:19 +01:00
Adam Hathcock
631578c175 Update to next version. Stop Zip64 tests from running all the time and some clean up 2017-05-19 10:10:23 +01:00
Adam Hathcock
f1809163c7 correct gitignore 2017-05-19 09:44:45 +01:00
Adam Hathcock
60e1fe86f2 Fix test running 2017-05-19 09:40:37 +01:00
Adam Hathcock
59d7de5bfc Try again appveyor 2017-05-19 09:36:05 +01:00
Adam Hathcock
6e95c1d84a Drop net35 support as dot net tooling doesn’t support it currently 2017-05-19 09:34:02 +01:00
Adam Hathcock
ee64670755 Move test folder to be tests 2017-05-19 09:19:37 +01:00
Adam Hathcock
3f7d0f5b68 Update test project 2017-05-19 09:14:43 +01:00
Adam Hathcock
e3514c5c4b Don’t attempt to autodeploy 2017-05-19 09:06:18 +01:00
Adam Hathcock
cc3a9cff88 Merge pull request #231 from adamhathcock/VS2017
Vs2017
2017-05-19 09:02:12 +01:00
Adam Hathcock
15e821aa39 Remove unused events 2017-05-19 08:49:44 +01:00
Adam Hathcock
8dd1dbab5f Remove Cake as it’s unnecessary for basic build/test/publish 2017-05-19 08:47:17 +01:00
Adam Hathcock
65ce91ddf6 Update. Only use net35, net standard 1.0 and net standard 1.3 2017-05-19 08:46:27 +01:00
Adam Hathcock
bf55595d6f Merge pull request #226 from gardebring/master
Add new event handler to allow tracking of progress of extraction progress for individual entry
2017-04-25 13:07:44 +01:00
Anders Gardebring
2aa123ccd7 Remove begin and end events since this can now be tracked via progress instead 2017-04-25 13:21:04 +02:00
Anders Gardebring
0990b06cc9 Create new TransferTo method and pass Entry and IReaderExtractionListener instead of passing an action lambda. 2017-04-25 12:48:56 +02:00
Anders Gardebring
e05f9843ba Use strongly typed ReaderProgress instead of object[] 2017-04-25 12:36:32 +02:00
Anders Gardebring
683d2714d0 Add new event to be able to track progress of extraction of individual entry when extracting an archive. This allows for showing or logging progress of the extraction process, especially useful for large files that might take a long time to extract. 2017-04-24 13:50:45 +02:00
Anders Gardebring
b8ef1ecafc Revert "Add new feature to allow injection of an action into the extraction process. This allows for showing or logging progress of the extraction process, especially useful for large files that might take a long time to extract."
This reverts commit 467fc2d03d.
2017-04-24 10:22:49 +02:00
Anders Gardebring
467fc2d03d Add new feature to allow injection of an action into the extraction process. This allows for showing or logging progress of the extraction process, especially useful for large files that might take a long time to extract. 2017-04-20 11:45:53 +02:00
Adam Hathcock
58b4fe4f28 Merge pull request #220 from coderb/master
verify RAR crc on header and file data
2017-04-07 11:56:06 +01:00
Brien Oberstein
97d5e0aac4 verify rar CRC on header and file data 2017-04-04 12:20:06 -04:00
Adam Hathcock
356c977cff Merge pull request #215 from mnadareski/master
Removed restriction on 7zip file entries
2017-03-17 09:20:59 +00:00
Matt Nadareski
99d6062376 Removed restriction on 7zip file entries 2017-03-16 15:55:20 -07:00
Adam Hathcock
f8538403e4 Merge pull request #211 from kenkendk/add_zip64
Add zip64
2017-03-13 10:23:26 +00:00
Kenneth Skovhede
ba12019bc7 Removed the unused code to write entries in Zip Headers 2017-03-11 08:05:49 +01:00
Kenneth Skovhede
726b9c80f6 Fixed compiling the unittest 2017-03-11 01:05:58 +01:00
Kenneth Skovhede
2894711c51 Added a test suite to verify zip64 write support is working, and can be read in both Archive and Stream mode 2017-03-11 00:54:06 +01:00
Kenneth Skovhede
85280f6f4f Changed the logic to throw exceptions when sizes exceed the zip archive limits, and zip64 is not enabled.
This changes the logic, such that archives larger than 4GiB are still automatically written correct (only the central header is special).
Archives with individual streams larger than 4 GiB must set the zip64 flag, either on the archive or the individual streams.
2017-03-11 00:53:42 +01:00
Kenneth Skovhede
d7f4c0ee32 Fixed an error in the zip64 central end of header: the signature + length (12 bytes) are not included in the reported length. 2017-03-10 23:10:06 +01:00
Kenneth Skovhede
1263c0d976 Added support for writing zip64 headers 2017-03-09 23:56:42 +01:00
Kenneth Skovhede
cd3cbd2b32 Support for writing zip64 headers in the unused code 2017-03-09 23:18:57 +01:00
Adam Hathcock
b3a4fed8be Mark for 0.15.2 2017-03-09 11:02:44 +00:00
Adam Hathcock
d0b4af6666 Merge pull request #210 from kenkendk/fix_invalid_headers
Fix invalid headers
2017-03-09 10:41:18 +00:00
Kenneth Skovhede
81ab5c189d Fixed writing correct headers in zip archives 2017-03-09 11:34:24 +01:00
Kenneth Skovhede
6ef3be4b5c Fixed writing correct headers in zip archives 2017-03-09 11:32:20 +01:00
Adam Hathcock
9f90a1d651 Mark for 0.15.1 2017-01-25 09:31:01 +00:00
Adam Hathcock
ce9a3fd1ef Add file ordering fix for OS X 2017-01-25 09:29:13 +00:00
Adam Hathcock
7c6f05058e Merge pull request #206 from markryd/zip64-extraction
Zip64 extending information and ZipReader
2017-01-25 09:03:43 +00:00
Mark Rydstrom
a8c3a7439e Add support for zip64 to ZipReader 2017-01-25 17:05:48 +10:00
Mark Rydstrom
839b3ab0cf Add support for zip64 extended information field 2017-01-25 16:51:15 +10:00
Adam Hathcock
44d54db80e Fix some path issues on OS X when running tests. 2017-01-24 17:36:51 +00:00
Adam Hathcock
a67d7bc429 Mark for 0.15 2017-01-24 17:25:19 +00:00
Adam Hathcock
079a818c6c Merge pull request #205 from markryd/zip64-extraction
Add zip64 support for ZipArchive extraction
2017-01-24 16:56:42 +00:00
Mark Rydstrom
6be6ef0b5c Add zip64 support for ZipArchive extraction 2017-01-24 13:04:03 +10:00
Adam Hathcock
8e51d9d646 0.14.1 2016-11-30 14:26:18 +00:00
Adam Hathcock
ea206f4f02 Merge pull request #199 from adamhathcock/Issue-198
Gzip entry can't be read multiple times
2016-11-25 09:33:56 +00:00
Adam Hathcock
f175a2a252 Merge branch 'master' into Issue-198 2016-11-25 09:21:44 +00:00
Adam Hathcock
3f7e559b86 Merge pull request #200 from ITnent/bug/Issue-197
Open branch, to fix multiple crashes on repeated zip archives reading…
2016-11-25 09:21:34 +00:00
Vladimir Demidov
2959b4d701 Modified check integrity condition for the encrypted file. 2016-11-24 20:41:08 +03:00
Vladimir Demidov
031286c5eb Fixed defects after review. 2016-11-24 18:01:49 +03:00
Vladimir Demidov
e181fa8c4a Restored original tabs. 2016-11-24 17:11:43 +03:00
Vladimir Demidov
7b035bec5d Fixed some issues after review. 2016-11-24 16:21:02 +03:00
Vladimir Demidov
f39d2bf53a Open branch, to fix multiple crashes on repeated zip archives reading. Added fix. 2016-11-24 15:14:29 +03:00
Adam Hathcock
7c8e407182 Merge branch 'master' into Issue-198 2016-11-21 12:21:29 +00:00
Adam Hathcock
a09136d46b Merge pull request #195 from jskeet/strong-naming
Strong-name both the main and test projects
2016-11-21 12:06:13 +00:00
Adam Hathcock
5fe1363ee1 Gzip entry can't be read multiple times https://github.com/adamhathcock/sharpcompress/issues/198 2016-11-21 12:04:35 +00:00
Jon Skeet
b41823fc10 Strong-name both the main and test projects
It's not clear whether SharpCompress.Test.Portable (as referenced
in AssemblyInfo.cs) still exists, but build.ps1 certainly works.
2016-11-15 18:42:56 +00:00
Adam Hathcock
0a64fe28b0 Oops, removed too much from project.json 2016-10-14 09:03:15 +01:00
Adam Hathcock
e320ccfa9a 0.14.0 2016-10-14 08:59:19 +01:00
Adam Hathcock
9628ff9456 Merge pull request #191 from jskeet/lzip
Initial read-only support for LZip
2016-10-14 08:50:32 +01:00
Jon Skeet
d540f78cfc Initial read-only support for LZip
LZip has no notion of flienames, so an LzipReader wouldn't make very much sense;
I've just implemented the stream, and hooked it into tar support.
2016-10-12 15:08:56 +01:00
Adam Hathcock
66420cd299 Merge pull request #189 from ziaa/master
Remove unbalanced parentheses in code samples
2016-10-08 18:25:30 +01:00
Seyed Zia Azimi
dd0594471f Remove unbalanced parentheses in samples 2016-10-07 19:33:41 +03:30
Adam Hathcock
844ba228ee Make 0.13.1 2016-10-03 13:44:19 +01:00
Adam Hathcock
7efc701b32 Merge pull request #188 from adamhathcock/fix_nulls
Fix null password on ReaderFactory.  Fix null options on SevenZipArchive
2016-10-03 13:41:55 +01:00
Adam Hathcock
d7e29f7c4d Fix occasionally failing test 2016-10-03 13:37:04 +01:00
Adam Hathcock
f26ba91386 Fix null password on ReaderFactory. Fix null options on SevenZipArchive 2016-10-03 13:32:53 +01:00
Adam Hathcock
c73ac2039c Merge pull request #185 from adamhathcock/ppmd_allocation_zipwriter
Make PpmdProperties lazy to avoid unnecessary allocations.
2016-10-03 13:04:14 +01:00
Adam Hathcock
671f9cd0cb Empty commit to kick build 2016-10-03 12:58:23 +01:00
Adam Hathcock
131b5b9714 Can't use Lazy on .NET 3.5 :( 2016-10-03 11:20:29 +01:00
Adam Hathcock
74af0889b9 Make PpmdProperties lazy to avoid unnecessary allocations. 2016-10-03 10:16:26 +01:00
Adam Hathcock
e5ee399045 Merge pull request #181 from claunia/patch-1
Update FORMATS.md
2016-09-30 07:08:52 +01:00
deeb7a0f64 Update FORMATS.md
Add ADC to formats list.
2016-09-29 22:53:51 +01:00
Adam Hathcock
5af3bab1dc Merge pull request #180 from adamhathcock/documenting
Add Markdown files to document things.
2016-09-29 11:58:19 +01:00
Adam Hathcock
28be84d315 For all branches 2016-09-29 11:35:54 +01:00
Adam Hathcock
a0528c737d Trying just to build once 2016-09-29 11:34:50 +01:00
Adam Hathcock
b506e488e8 Add build badge 2016-09-29 11:32:31 +01:00
Adam Hathcock
58eb0e08d6 Don't save artifacts for PRs 2016-09-29 11:22:26 +01:00
Adam Hathcock
562701894f Save nupkgs 2016-09-29 11:13:05 +01:00
Adam Hathcock
54a562273b Incomplete refactoring 2016-09-29 11:10:11 +01:00
Adam Hathcock
3f8c9c4cb0 Update for 0.13.0 2016-09-29 11:03:11 +01:00
Adam Hathcock
3e7d28b043 Can I fix tables? 2016-09-29 10:57:49 +01:00
Adam Hathcock
40b10d4a26 Add Markdown files to document things. 2016-09-29 10:55:04 +01:00
Adam Hathcock
f367630a2a Merge pull request #179 from adamhathcock/tar_fix
Allow empty tar header to be read to know there are no more tar heade…
2016-09-28 13:57:09 +01:00
Adam Hathcock
b9e4f00862 Merge branch 'master' into tar_fix 2016-09-28 13:50:45 +01:00
Adam Hathcock
d6e74d6163 Merge pull request #178 from adamhathcock/7zip_deflate
Allow deflate decoder for 7zip
2016-09-28 13:50:35 +01:00
Adam Hathcock
4a4522b842 Merge branch 'master' into 7zip_deflate 2016-09-28 13:44:46 +01:00
Adam Hathcock
710ba4423d Merge branch 'master' into tar_fix 2016-09-28 13:43:21 +01:00
Adam Hathcock
2a5494a804 Merge pull request #174 from adamhathcock/redo_options
Redo options
2016-09-28 13:40:54 +01:00
Adam Hathcock
568909800c Allow empty tar header to be read to know there are no more tar headers to read 2016-09-28 12:00:48 +01:00
Adam Hathcock
7513a608b1 Allow deflate decoder 2016-09-28 11:59:31 +01:00
Adam Hathcock
911e9878bd Merge branch 'master' into redo_options 2016-09-27 13:09:07 +01:00
Adam Hathcock
899d7d6e61 Appveyor (#175)
* First pass of Cake build

* Update Cake but still need cake itself to run on full CLR

* Test out appveyor

* 3.5 build fix

* Build master and PRs differently.  Still scared to auto publish to nuget.
2016-09-27 13:08:42 +01:00
Adam Hathcock
260c0ee776 Add SaveTo overload for zip archives 2016-09-27 11:19:52 +01:00
Adam Hathcock
d71520808d Helps if I rename everything 2016-09-27 11:08:54 +01:00
Adam Hathcock
177fc2a12c Flags were a better idea when I was younger. It's not clear though. 2016-09-27 10:50:36 +01:00
Adam Hathcock
5dafcb02d4 Redo options classes 2016-09-27 10:23:35 +01:00
Adam Hathcock
c4fde80c5e Create proper options objects to remove flags from API 2016-09-27 10:14:08 +01:00
Adam Hathcock
06e3486ec4 Bump version 2016-09-26 11:53:35 +01:00
Adam Hathcock
bd7c783aaf Test fixes 2016-09-26 11:51:35 +01:00
Adam Hathcock
d732e3cfa4 Renamespace for proper pluralization 2016-09-26 11:49:49 +01:00
Adam Hathcock
c24cdc66ed Clean up from clean up 2016-09-26 11:03:15 +01:00
Adam Hathcock
efa6f7a82e Huge Resharper clean up. Fixed up test project.json 2016-09-26 10:55:52 +01:00
ddbbc3b847 Adds support for Apple Data Compression. (#168) 2016-09-12 17:41:31 +01:00
Adam Hathcock
7037161c07 Update README 2016-08-12 12:15:45 +01:00
433 changed files with 14883 additions and 9317 deletions

11
.circleci/config.yml Normal file
View File

@@ -0,0 +1,11 @@
version: 2
jobs:
build:
docker:
- image: adamhathcock/cake-build:latest
steps:
- checkout
- run:
name: Build
command: ./build.sh

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

31
.gitignore vendored
View File

@@ -1,14 +1,17 @@
**/bin/*
**/obj/*
_ReSharper.SharpCompress/
bin/
*.suo
*.user
TestArchives/Scratch/
TestArchives/Scratch2/
TestResults/
*.nupkg
packages/*/
project.lock.json
test/TestArchives/Scratch
.vs
**/bin/*
**/obj/*
_ReSharper.SharpCompress/
bin/
*.suo
*.user
TestArchives/Scratch/
TestArchives/Scratch2/
TestResults/
*.nupkg
packages/*/
project.lock.json
tests/TestArchives/Scratch
.vs
tools
.vscode
.idea/

60
FORMATS.md Normal file
View File

@@ -0,0 +1,60 @@
# Formats
## 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.
## 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 |
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.
## 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.
| Compressor | Compress/Decompress |
| --- | --- |
| BZip2Stream | Both |
| GZipStream | Both |
| DeflateStream | Both |
| LZMAStream | Both |
| PPMdStream | Both |
| ADCStream | Decompress |
| LZipStream | Both |
| XZStream | Decompress |
## Archive Formats vs Compression
Sometimes the terminology gets mixed.
### Compression
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)
### 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.

105
README.md
View File

@@ -1,13 +1,29 @@
# SharpCompress
SharpCompress is a compression library for .NET/Mono/Silverlight/WP7 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 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.
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)
Circle CI Build -
[![CircleCI](https://circleci.com/gh/adamhathcock/sharpcompress.svg?style=svg)](https://circleci.com/gh/adamhathcock/sharpcompress)
## Need Help?
Post Issues on Github!
Check the [Supported Formats](https://github.com/adamhathcock/sharpcompress/wiki/Supported-Formats) and [basic samples.](https://github.com/adamhathcock/sharpcompress/wiki/API-Examples)
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`)
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
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
@@ -23,28 +39,97 @@ I'm always looking for help or ideas. Please submit code or email with ideas. Un
* RAR 5 support
* 7Zip writing
* Zip64
* Zip64 (Need writing and extend Reading)
* Multi-volume Zip support.
## In-Progress
* RAR5 support
* DNX/NET Core support
* xproj targeting
## Version Log
### Version 0.18
* [Now on Github releases](https://github.com/adamhathcock/sharpcompress/releases/tag/0.18)
### Version 0.17.1
* Fix - [Bug Fix for .NET Core on Windows](https://github.com/adamhathcock/sharpcompress/pull/257)
### 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)
* Fix - [Zip files with post-data descriptors can be properly skipped via decompression](https://github.com/adamhathcock/sharpcompress/issues/162)
### Version 0.16.2
* Fix [.NET 3.5 should support files and cryptography (was a regression from 0.16.0)](https://github.com/adamhathcock/sharpcompress/pull/251)
* Fix [Zip per entry compression customization wrote the wrong method into the zip archive](https://github.com/adamhathcock/sharpcompress/pull/249)
### Version 0.16.1
* Fix [Preserve compression method when getting a compressed stream](https://github.com/adamhathcock/sharpcompress/pull/235)
* Fix [RAR entry key normalization fix](https://github.com/adamhathcock/sharpcompress/issues/201)
### Version 0.16.0
* Breaking - [Progress Event Tracking rethink](https://github.com/adamhathcock/sharpcompress/pull/226)
* Update to VS2017 - [VS2017](https://github.com/adamhathcock/sharpcompress/pull/231) - Framework targets have been changed.
* New - [Add Zip64 writing](https://github.com/adamhathcock/sharpcompress/pull/211)
* [Fix invalid/mismatching Zip version flags.](https://github.com/adamhathcock/sharpcompress/issues/164) - This allows nuget/System.IO.Packaging to read zip files generated by SharpCompress
* [Fix 7Zip directory hiding](https://github.com/adamhathcock/sharpcompress/pull/215/files)
* [Verify RAR CRC headers](https://github.com/adamhathcock/sharpcompress/pull/220)
### Version 0.15.2
* [Fix invalid headers](https://github.com/adamhathcock/sharpcompress/pull/210) - fixes an issue creating large-ish zip archives that was introduced with zip64 reading.
### Version 0.15.1
* [Zip64 extending information and ZipReader](https://github.com/adamhathcock/sharpcompress/pull/206)
### Version 0.15.0
* [Add zip64 support for ZipArchive extraction](https://github.com/adamhathcock/sharpcompress/pull/205)
### Version 0.14.1
* [.NET Assemblies aren't strong named](https://github.com/adamhathcock/sharpcompress/issues/158)
* [Pkware encryption for Zip files didn't allow for multiple reads of an entry](https://github.com/adamhathcock/sharpcompress/issues/197)
* [GZip Entry couldn't be read multiple times](https://github.com/adamhathcock/sharpcompress/issues/198)
### Version 0.14.0
* [Support for LZip reading in for Tars](https://github.com/adamhathcock/sharpcompress/pull/191)
### Version 0.13.1
* [Fix null password on ReaderFactory. Fix null options on SevenZipArchive](https://github.com/adamhathcock/sharpcompress/pull/188)
* [Make PpmdProperties lazy to avoid unnecessary allocations.](https://github.com/adamhathcock/sharpcompress/pull/185)
### Version 0.13.0
* Breaking change: Big refactor of Options on API.
* 7Zip supports Deflate
### Version 0.12.4
* Forward only zip issue fix https://github.com/adamhathcock/sharpcompress/issues/160
* Try to fix frameworks again by copying targets from JSON.NET
### Version 0.12.3
* 7Zip fixes https://github.com/adamhathcock/sharpcompress/issues/73
* Maybe all profiles will work with project.json now
### Version 0.12.2
* Support Profile 259 again
### Version 0.12.1
* Support Silverlight 5
### Version 0.12.0
* .NET Core RTM!
* Bug fix for Tar long paths
@@ -97,7 +182,7 @@ I'm always looking for help or ideas. Please submit code or email with ideas. Un
* Embedded some BouncyCastle crypto classes to allow RAR Decryption and Winzip AES Decryption in Portable and Windows Store DLLs
* Built in Release (I think)
Some Help/Discussion: https://sharpcompress.codeplex.com/discussions
XZ implementation based on: https://github.com/sambott/XZ.NET by @sambott
7Zip implementation based on: https://code.google.com/p/managed-lzma/

View File

@@ -1,44 +1,38 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.24720.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{F18F1765-4A02-42FD-9BEF-F0E2FCBD9D17}"
ProjectSection(SolutionItems) = preProject
global.json = global.json
EndProjectSection
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "SharpCompress", "src\SharpCompress\SharpCompress.xproj", "{FD19DDD8-72B2-4024-8665-0D1F7A2AA998}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{3C5BE746-03E5-4895-9988-0B57F162F86C}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{0F0901FF-E8D9-426A-B5A2-17C7F47C1529}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "SharpCompress.Test", "test\SharpCompress.Test\SharpCompress.Test.xproj", "{3B80E585-A2F3-4666-8F69-C7FFDA0DD7E5}"
ProjectSection(ProjectDependencies) = postProject
{FD19DDD8-72B2-4024-8665-0D1F7A2AA998} = {FD19DDD8-72B2-4024-8665-0D1F7A2AA998}
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{FD19DDD8-72B2-4024-8665-0D1F7A2AA998}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FD19DDD8-72B2-4024-8665-0D1F7A2AA998}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FD19DDD8-72B2-4024-8665-0D1F7A2AA998}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FD19DDD8-72B2-4024-8665-0D1F7A2AA998}.Release|Any CPU.Build.0 = Release|Any CPU
{3B80E585-A2F3-4666-8F69-C7FFDA0DD7E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3B80E585-A2F3-4666-8F69-C7FFDA0DD7E5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3B80E585-A2F3-4666-8F69-C7FFDA0DD7E5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3B80E585-A2F3-4666-8F69-C7FFDA0DD7E5}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{FD19DDD8-72B2-4024-8665-0D1F7A2AA998} = {3C5BE746-03E5-4895-9988-0B57F162F86C}
{3B80E585-A2F3-4666-8F69-C7FFDA0DD7E5} = {0F0901FF-E8D9-426A-B5A2-17C7F47C1529}
EndGlobalSection
EndGlobal
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26430.6
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{F18F1765-4A02-42FD-9BEF-F0E2FCBD9D17}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{3C5BE746-03E5-4895-9988-0B57F162F86C}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{0F0901FF-E8D9-426A-B5A2-17C7F47C1529}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SharpCompress", "src\SharpCompress\SharpCompress.csproj", "{FD19DDD8-72B2-4024-8665-0D1F7A2AA998}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SharpCompress.Test", "tests\SharpCompress.Test\SharpCompress.Test.csproj", "{F2B1A1EB-0FA6-40D0-8908-E13247C7226F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{FD19DDD8-72B2-4024-8665-0D1F7A2AA998}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FD19DDD8-72B2-4024-8665-0D1F7A2AA998}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FD19DDD8-72B2-4024-8665-0D1F7A2AA998}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FD19DDD8-72B2-4024-8665-0D1F7A2AA998}.Release|Any CPU.Build.0 = Release|Any CPU
{F2B1A1EB-0FA6-40D0-8908-E13247C7226F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{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
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{FD19DDD8-72B2-4024-8665-0D1F7A2AA998} = {3C5BE746-03E5-4895-9988-0B57F162F86C}
{F2B1A1EB-0FA6-40D0-8908-E13247C7226F} = {0F0901FF-E8D9-426A-B5A2-17C7F47C1529}
EndGlobalSection
EndGlobal

View File

@@ -1,6 +1,120 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/Environment/InjectedLayers/FileInjectedLayer/=181069325DAB1C4287CD564D6CDDEDB3/AbsolutePath/@EntryValue">D:\Git\sharpcompress\SharpCompress\sharpcompress.DotSettings</s:String>
<s:String x:Key="/Default/Environment/InjectedLayers/FileInjectedLayer/=181069325DAB1C4287CD564D6CDDEDB3/RelativePath/@EntryValue">..\SharpCompress\sharpcompress.DotSettings</s:String>
<s:Boolean x:Key="/Default/Environment/InjectedLayers/FileInjectedLayer/=181069325DAB1C4287CD564D6CDDEDB3/@KeyIndexDefined">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/InjectedLayers/InjectedLayerCustomization/=File181069325DAB1C4287CD564D6CDDEDB3/@KeyIndexDefined">True</s:Boolean>
<s:Double x:Key="/Default/Environment/InjectedLayers/InjectedLayerCustomization/=File181069325DAB1C4287CD564D6CDDEDB3/RelativePriority/@EntryValue">1</s:Double></wpf:ResourceDictionary>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArgumentsStyleNamedExpression/@EntryIndexedValue">DO_NOT_SHOW</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeBraces_005Fdowhile/@EntryIndexedValue">ERROR</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeBraces_005Ffixed/@EntryIndexedValue">ERROR</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeBraces_005Ffor/@EntryIndexedValue">ERROR</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeBraces_005Fforeach/@EntryIndexedValue">ERROR</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeBraces_005Fifelse/@EntryIndexedValue">ERROR</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeBraces_005Flock/@EntryIndexedValue">ERROR</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeBraces_005Fusing/@EntryIndexedValue">ERROR</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeBraces_005Fwhile/@EntryIndexedValue">ERROR</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=MethodSupportsCancellation/@EntryIndexedValue">ERROR</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=RedundantExplicitParamsArrayCreation/@EntryIndexedValue">DO_NOT_SHOW</s:String>
<s:String x:Key="/Default/CodeStyle/CodeCleanup/Profiles/=Basic_0020Clean/@EntryIndexedValue">&lt;?xml version="1.0" encoding="utf-16"?&gt;&lt;Profile name="Basic Clean"&gt;&lt;CSOptimizeUsings&gt;&lt;OptimizeUsings&gt;True&lt;/OptimizeUsings&gt;&lt;EmbraceInRegion&gt;False&lt;/EmbraceInRegion&gt;&lt;RegionName&gt;&lt;/RegionName&gt;&lt;/CSOptimizeUsings&gt;&lt;CSShortenReferences&gt;True&lt;/CSShortenReferences&gt;&lt;CSRemoveCodeRedundancies&gt;True&lt;/CSRemoveCodeRedundancies&gt;&lt;CSMakeFieldReadonly&gt;True&lt;/CSMakeFieldReadonly&gt;&lt;CSCodeStyleAttributes ArrangeTypeAccessModifier="False" ArrangeTypeMemberAccessModifier="False" SortModifiers="False" RemoveRedundantParentheses="False" AddMissingParentheses="False" ArrangeBraces="True" ArrangeAttributes="False" ArrangeArgumentsStyle="False" /&gt;&lt;RemoveCodeRedundancies&gt;True&lt;/RemoveCodeRedundancies&gt;&lt;CSUseAutoProperty&gt;True&lt;/CSUseAutoProperty&gt;&lt;CSMakeAutoPropertyGetOnly&gt;True&lt;/CSMakeAutoPropertyGetOnly&gt;&lt;CSReformatCode&gt;True&lt;/CSReformatCode&gt;&lt;/Profile&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/CodeCleanup/SilentCleanupProfile/@EntryValue">Basic Clean</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/APPLY_ON_COMPLETION/@EntryValue">True</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/ARGUMENTS_NAMED/@EntryValue">Named</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_FOR/@EntryValue">Required</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_FOREACH/@EntryValue">Required</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_IFELSE/@EntryValue">Required</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_WHILE/@EntryValue">Required</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_FIRST_ARG_BY_PAREN/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_LINQ_QUERY/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTILINE_ARGUMENT/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTILINE_ARRAY_AND_OBJECT_INITIALIZER/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTILINE_CALLS_CHAIN/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTILINE_EXPRESSION/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTILINE_EXTENDS_LIST/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTILINE_FOR_STMT/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTILINE_PARAMETER/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTIPLE_DECLARATION/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTLINE_TYPE_PARAMETER_CONSTRAINS/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTLINE_TYPE_PARAMETER_LIST/@EntryValue">True</s:Boolean>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/BLANK_LINES_AFTER_START_COMMENT/@EntryValue">0</s:Int64>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/BLANK_LINES_BEFORE_SINGLE_LINE_COMMENT/@EntryValue">1</s:Int64>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/FORCE_ATTRIBUTE_STYLE/@EntryValue">SEPARATE</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/FORCE_FIXED_BRACES_STYLE/@EntryValue">ALWAYS_ADD</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/FORCE_FOR_BRACES_STYLE/@EntryValue">ALWAYS_ADD</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/FORCE_FOREACH_BRACES_STYLE/@EntryValue">ALWAYS_ADD</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/FORCE_IFELSE_BRACES_STYLE/@EntryValue">ALWAYS_ADD</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/FORCE_USING_BRACES_STYLE/@EntryValue">ALWAYS_ADD</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/FORCE_WHILE_BRACES_STYLE/@EntryValue">ALWAYS_ADD</s:String>
<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: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: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: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>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SIMPLE_EMBEDDED_STATEMENT_STYLE/@EntryValue">LINE_BREAK</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_AFTER_TYPECAST_PARENTHESES/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_AROUND_ARROW_OP/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_AROUND_MULTIPLICATIVE_OP/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_BEFORE_SIZEOF_PARENTHESES/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_BEFORE_TYPEOF_PARENTHESES/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/STICK_COMMENT/@EntryValue">False</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_ARGUMENTS_STYLE/@EntryValue">CHOP_IF_LONG</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_ARRAY_INITIALIZER_STYLE/@EntryValue">CHOP_IF_LONG</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_EXTENDS_LIST_STYLE/@EntryValue">CHOP_IF_LONG</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_LINES/@EntryValue">False</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_PARAMETERS_STYLE/@EntryValue">CHOP_IF_LONG</s:String>
<s:String x:Key="/Default/CodeStyle/CSharpVarKeywordUsage/ForBuiltInTypes/@EntryValue">UseVarWhenEvident</s:String>
<s:String x:Key="/Default/CodeStyle/CSharpVarKeywordUsage/ForOtherTypes/@EntryValue">UseVarWhenEvident</s:String>
<s:String x:Key="/Default/CodeStyle/CSharpVarKeywordUsage/ForSimpleTypes/@EntryValue">UseVarWhenEvident</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateInstanceFields/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticFields/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticReadonly/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=StaticReadonly/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FBLOCK_005FSCOPE_005FCONSTANT/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FBLOCK_005FSCOPE_005FFUNCTION/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FBLOCK_005FSCOPE_005FVARIABLE/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FCLASS/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FCONSTRUCTOR/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FFUNCTION/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FGLOBAL_005FVARIABLE/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FLABEL/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FLOCAL_005FCONSTRUCTOR/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FLOCAL_005FVARIABLE/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FOBJECT_005FPROPERTY_005FOF_005FFUNCTION/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FPARAMETER/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FCLASS/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FENUM/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FENUM_005FMEMBER/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FINTERFACE/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="I" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FMODULE/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FMODULE_005FEXPORTED/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FMODULE_005FLOCAL/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPRIVATE_005FMEMBER_005FACCESSOR/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPRIVATE_005FSTATIC_005FTYPE_005FFIELD/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPRIVATE_005FTYPE_005FFIELD/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPRIVATE_005FTYPE_005FMETHOD/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPROTECTED_005FMEMBER_005FACCESSOR/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPROTECTED_005FSTATIC_005FTYPE_005FFIELD/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPROTECTED_005FTYPE_005FFIELD/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPROTECTED_005FTYPE_005FMETHOD/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPUBLIC_005FMEMBER_005FACCESSOR/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPUBLIC_005FSTATIC_005FTYPE_005FFIELD/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPUBLIC_005FTYPE_005FFIELD/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPUBLIC_005FTYPE_005FMETHOD/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FTYPE_005FPARAMETER/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="T" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/WebNaming/UserRules/=ASP_005FFIELD/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/WebNaming/UserRules/=ASP_005FHTML_005FCONTROL/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/WebNaming/UserRules/=ASP_005FTAG_005FNAME/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/WebNaming/UserRules/=ASP_005FTAG_005FPREFIX/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<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_002ESettingsUpgrade_002EAddAccessorOwnerDeclarationBracesMigration/@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>

BIN
SharpCompress.snk Normal file

Binary file not shown.

131
USAGE.md Normal file
View File

@@ -0,0 +1,131 @@
# 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.
However, the .NET Framework often has classes that will dispose streams by default to make things "easy" like the following:
```C#
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:
```C#
using (var fileStream = File.Open("foo"))
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 be explicit though, consider always using the overloads that use `ReaderOptions` or `WriterOptions` and explicitly set `LeaveStreamOpen` the way you want.
## Samples
Also, look over the tests for more thorough [examples](https://github.com/adamhathcock/sharpcompress/tree/master/test/SharpCompress.Test)
### Create Zip Archive from all files in a directory to a file
```C#
using (var archive = ZipArchive.Create())
{
archive.AddAllFromDirectory("D:\\temp");
archive.SaveTo("C:\\temp.zip", CompressionType.Deflate);
}
```
### Create Zip Archive from all files in a directory and save in memory
```C#
var memoryStream = new MemoryStream();
using (var archive = ZipArchive.Create())
{
archive.AddAllFromDirectory("D:\\temp");
archive.SaveTo(memoryStream, new WriterOptions(CompressionType.Deflate)
{
LeaveStreamOpen = true
});
}
//reset memoryStream to be usable now
memoryStream.Position = 0;
```
### Extract all files from a Rar file to a directory using RarArchive
```C#
using (var archive = RarArchive.Open("Test.rar"))
{
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
{
entry.WriteToDirectory("D:\\temp", new ExtractionOptions()
{
ExtractFullPath = true,
Overwrite = true
});
}
}
```
### Use ReaderFactory to autodetect archive type and Open the entry stream
```C#
using (Stream stream = File.OpenRead("Tar.tar.bz2"))
using (var reader = ReaderFactory.Open(stream))
{
while (reader.MoveToNextEntry())
{
if (!reader.Entry.IsDirectory)
{
Console.WriteLine(reader.Entry.Key);
reader.WriteEntryToDirectory(@"C:\temp", new ExtractionOptions()
{
ExtractFullPath = true,
Overwrite = true
});
}
}
}
```
### Use ReaderFactory to autodetect archive type and Open the entry stream
```C#
using (Stream stream = File.OpenRead("Tar.tar.bz2"))
using (var reader = ReaderFactory.Open(stream))
{
while (reader.MoveToNextEntry())
{
if (!reader.Entry.IsDirectory)
{
using (var entryStream = reader.OpenEntryStream())
{
entryStream.CopyTo(...);
}
}
}
}
```
### Use WriterFactory to write all files from a directory in a streaming manner.
```C#
using (Stream stream = File.OpenWrite("C:\\temp.tgz"))
using (var writer = WriterFactory.Open(stream, ArchiveType.Tar, new WriterOptions(CompressionType.GZip)
{
LeaveOpenStream = true
}))
{
writer.WriteAll("D:\\temp", "*", SearchOption.AllDirectories);
}
```

20
appveyor.yml Normal file
View File

@@ -0,0 +1,20 @@
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

98
build.cake Normal file
View File

@@ -0,0 +1,98 @@
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 = "netstandard1.3";
DotNetCoreBuild("./src/SharpCompress/SharpCompress.csproj", settings);
settings.Framework = "netstandard2.0";
DotNetCoreBuild("./src/SharpCompress/SharpCompress.csproj", settings);
}
});
Task("Test")
.IsDependentOn("Build")
.Does(() =>
{
var files = GetFiles("tests/**/*.csproj");
foreach(var file in files)
{
var settings = new DotNetCoreTestSettings
{
Configuration = "Release",
Framework = "netcoreapp2.0"
};
DotNetCoreTest(file.ToString(), settings);
settings = new DotNetCoreTestSettings
{
Configuration = "Release",
Framework = "netcoreapp1.1"
};
DotNetCoreTest(file.ToString(), settings);
}
});
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 Normal file
View File

@@ -0,0 +1,228 @@
##########################################################################
# 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

42
build.sh Executable file
View File

@@ -0,0 +1,42 @@
#!/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.23.0
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" "$@"

View File

@@ -1,3 +0,0 @@
{
"projects": ["src","test"]
}

View File

@@ -1,111 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using SharpCompress.Common;
using SharpCompress.IO;
namespace SharpCompress.Archive.GZip
{
internal class GZipWritableArchiveEntry : GZipArchiveEntry, IWritableArchiveEntry
{
private readonly string path;
private readonly long size;
private readonly DateTime? lastModified;
private readonly bool closeStream;
private readonly Stream stream;
internal GZipWritableArchiveEntry(GZipArchive archive, Stream stream,
string path, long size, DateTime? lastModified, bool closeStream)
: base(archive, null)
{
this.stream = stream;
this.path = path;
this.size = size;
this.lastModified = lastModified;
this.closeStream = closeStream;
}
public override long Crc
{
get { return 0; }
}
public override string Key
{
get { return path; }
}
public override long CompressedSize
{
get { return 0; }
}
public override long Size
{
get { return size; }
}
public override DateTime? LastModifiedTime
{
get { return lastModified; }
}
public override DateTime? CreatedTime
{
get { return null; }
}
public override DateTime? LastAccessedTime
{
get { return null; }
}
public override DateTime? ArchivedTime
{
get { return null; }
}
public override bool IsEncrypted
{
get { return false; }
}
public override bool IsDirectory
{
get { return false; }
}
public override bool IsSplit
{
get { return false; }
}
internal override IEnumerable<FilePart> Parts
{
get { throw new NotImplementedException(); }
}
Stream IWritableArchiveEntry.Stream
{
get
{
return stream;
}
}
public override Stream OpenEntryStream()
{
//ensure new stream is at the start, this could be reset
stream.Seek(0, SeekOrigin.Begin);
return new NonDisposingStream(stream);
}
internal override void Close()
{
if (closeStream)
{
stream.Dispose();
}
}
}
}

View File

@@ -1,231 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using SharpCompress.Common;
using SharpCompress.Common.Tar;
using SharpCompress.Common.Tar.Headers;
using SharpCompress.IO;
using SharpCompress.Reader;
using SharpCompress.Reader.Tar;
using SharpCompress.Writer.Tar;
namespace SharpCompress.Archive.Tar
{
public class TarArchive : AbstractWritableArchive<TarArchiveEntry, TarVolume>
{
#if !NO_FILE
/// <summary>
/// Constructor expects a filepath to an existing file.
/// </summary>
/// <param name="filePath"></param>
public static TarArchive Open(string filePath)
{
return Open(filePath, Options.None);
}
/// <summary>
/// Constructor with a FileInfo object to an existing file.
/// </summary>
/// <param name="fileInfo"></param>
public static TarArchive Open(FileInfo fileInfo)
{
return Open(fileInfo, Options.None);
}
/// <summary>
/// Constructor expects a filepath to an existing file.
/// </summary>
/// <param name="filePath"></param>
/// <param name="options"></param>
public static TarArchive Open(string filePath, Options options)
{
filePath.CheckNotNullOrEmpty("filePath");
return Open(new FileInfo(filePath), options);
}
/// <summary>
/// Constructor with a FileInfo object to an existing file.
/// </summary>
/// <param name="fileInfo"></param>
/// <param name="options"></param>
public static TarArchive Open(FileInfo fileInfo, Options options)
{
fileInfo.CheckNotNull("fileInfo");
return new TarArchive(fileInfo, options);
}
#endif
/// <summary>
/// Takes a seekable Stream as a source
/// </summary>
/// <param name="stream"></param>
public static TarArchive Open(Stream stream)
{
stream.CheckNotNull("stream");
return Open(stream, Options.None);
}
/// <summary>
/// Takes a seekable Stream as a source
/// </summary>
/// <param name="stream"></param>
/// <param name="options"></param>
public static TarArchive Open(Stream stream, Options options)
{
stream.CheckNotNull("stream");
return new TarArchive(stream, options);
}
#if !NO_FILE
public static bool IsTarFile(string filePath)
{
return IsTarFile(new FileInfo(filePath));
}
public static bool IsTarFile(FileInfo fileInfo)
{
if (!fileInfo.Exists)
{
return false;
}
using (Stream stream = fileInfo.OpenRead())
{
return IsTarFile(stream);
}
}
#endif
public static bool IsTarFile(Stream stream)
{
try
{
TarHeader tar = new TarHeader();
tar.Read(new BinaryReader(stream));
return tar.Name.Length > 0 && Enum.IsDefined(typeof (EntryType), tar.EntryType);
}
catch
{
}
return false;
}
#if !NO_FILE
/// <summary>
/// Constructor with a FileInfo object to an existing file.
/// </summary>
/// <param name="fileInfo"></param>
/// <param name="options"></param>
internal TarArchive(FileInfo fileInfo, Options options)
: base(ArchiveType.Tar, fileInfo, options)
{
}
protected override IEnumerable<TarVolume> LoadVolumes(FileInfo file, Options options)
{
if (FlagUtility.HasFlag(options, Options.KeepStreamsOpen))
{
options = (Options)FlagUtility.SetFlag(options, Options.KeepStreamsOpen, false);
}
return new TarVolume(file.OpenRead(), options).AsEnumerable();
}
#endif
/// <summary>
/// Takes multiple seekable Streams for a multi-part archive
/// </summary>
/// <param name="stream"></param>
/// <param name="options"></param>
internal TarArchive(Stream stream, Options options)
: base(ArchiveType.Tar, stream, options)
{
}
internal TarArchive()
: base(ArchiveType.Tar)
{
}
protected override IEnumerable<TarVolume> LoadVolumes(IEnumerable<Stream> streams, Options options)
{
return new TarVolume(streams.First(), options).AsEnumerable();
}
protected override IEnumerable<TarArchiveEntry> LoadEntries(IEnumerable<TarVolume> volumes)
{
Stream stream = volumes.Single().Stream;
TarHeader previousHeader = null;
foreach (TarHeader header in TarHeaderFactory.ReadHeader(StreamingMode.Seekable, stream))
{
if (header != null)
{
if (header.EntryType == EntryType.LongName)
{
previousHeader = header;
}
else
{
if (previousHeader != null)
{
var entry = new TarArchiveEntry(this, new TarFilePart(previousHeader, stream),
CompressionType.None);
var oldStreamPos = stream.Position;
using(var entryStream = entry.OpenEntryStream())
using(var memoryStream = new MemoryStream())
{
entryStream.TransferTo(memoryStream);
memoryStream.Position = 0;
var bytes = memoryStream.ToArray();
header.Name = ArchiveEncoding.Default.GetString(bytes, 0, bytes.Length).TrimNulls();
}
stream.Position = oldStreamPos;
previousHeader = null;
}
yield return new TarArchiveEntry(this, new TarFilePart(header, stream), CompressionType.None);
}
}
}
}
public static TarArchive Create()
{
return new TarArchive();
}
protected override TarArchiveEntry CreateEntryInternal(string filePath, Stream source,
long size, DateTime? modified, bool closeStream)
{
return new TarWritableArchiveEntry(this, source, CompressionType.Unknown, filePath, size, modified,
closeStream);
}
protected override void SaveTo(Stream stream, CompressionInfo compressionInfo,
IEnumerable<TarArchiveEntry> oldEntries,
IEnumerable<TarArchiveEntry> newEntries)
{
using (var writer = new TarWriter(stream, compressionInfo))
{
foreach (var entry in oldEntries.Concat(newEntries)
.Where(x => !x.IsDirectory))
{
using (var entryStream = entry.OpenEntryStream())
{
writer.Write(entry.Key, entryStream, entry.LastModifiedTime, entry.Size);
}
}
}
}
protected override IReader CreateReaderForSolidExtraction()
{
var stream = Volumes.Single().Stream;
stream.Position = 0;
return TarReader.Open(stream);
}
}
}

View File

@@ -1,110 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using SharpCompress.Common;
using SharpCompress.IO;
namespace SharpCompress.Archive.Tar
{
internal class TarWritableArchiveEntry : TarArchiveEntry, IWritableArchiveEntry
{
private readonly string path;
private readonly long size;
private readonly DateTime? lastModified;
private readonly bool closeStream;
private readonly Stream stream;
internal TarWritableArchiveEntry(TarArchive archive, Stream stream, CompressionType compressionType,
string path, long size, DateTime? lastModified, bool closeStream)
: base(archive, null, compressionType)
{
this.stream = stream;
this.path = path;
this.size = size;
this.lastModified = lastModified;
this.closeStream = closeStream;
}
public override long Crc
{
get { return 0; }
}
public override string Key
{
get { return path; }
}
public override long CompressedSize
{
get { return 0; }
}
public override long Size
{
get { return size; }
}
public override DateTime? LastModifiedTime
{
get { return lastModified; }
}
public override DateTime? CreatedTime
{
get { return null; }
}
public override DateTime? LastAccessedTime
{
get { return null; }
}
public override DateTime? ArchivedTime
{
get { return null; }
}
public override bool IsEncrypted
{
get { return false; }
}
public override bool IsDirectory
{
get { return false; }
}
public override bool IsSplit
{
get { return false; }
}
internal override IEnumerable<FilePart> Parts
{
get { throw new NotImplementedException(); }
}
Stream IWritableArchiveEntry.Stream
{
get
{
return stream;
}
}
public override Stream OpenEntryStream()
{
//ensure new stream is at the start, this could be reset
stream.Seek(0, SeekOrigin.Begin);
return new NonDisposingStream(stream);
}
internal override void Close()
{
if (closeStream)
{
stream.Dispose();
}
}
}
}

View File

@@ -1,113 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using SharpCompress.Common;
using SharpCompress.IO;
namespace SharpCompress.Archive.Zip
{
internal class ZipWritableArchiveEntry : ZipArchiveEntry, IWritableArchiveEntry
{
private readonly string path;
private readonly long size;
private readonly DateTime? lastModified;
private readonly bool closeStream;
private readonly Stream stream;
private bool isDisposed;
internal ZipWritableArchiveEntry(ZipArchive archive, Stream stream, string path, long size,
DateTime? lastModified, bool closeStream)
: base(archive, null)
{
this.stream = stream;
this.path = path;
this.size = size;
this.lastModified = lastModified;
this.closeStream = closeStream;
}
public override long Crc
{
get { return 0; }
}
public override string Key
{
get { return path; }
}
public override long CompressedSize
{
get { return 0; }
}
public override long Size
{
get { return size; }
}
public override DateTime? LastModifiedTime
{
get { return lastModified; }
}
public override DateTime? CreatedTime
{
get { return null; }
}
public override DateTime? LastAccessedTime
{
get { return null; }
}
public override DateTime? ArchivedTime
{
get { return null; }
}
public override bool IsEncrypted
{
get { return false; }
}
public override bool IsDirectory
{
get { return false; }
}
public override bool IsSplit
{
get { return false; }
}
internal override IEnumerable<FilePart> Parts
{
get { throw new NotImplementedException(); }
}
Stream IWritableArchiveEntry.Stream
{
get
{
return stream;
}
}
public override Stream OpenEntryStream()
{
//ensure new stream is at the start, this could be reset
stream.Seek(0, SeekOrigin.Begin);
return new NonDisposingStream(stream);
}
internal override void Close()
{
if (closeStream && !isDisposed)
{
stream.Dispose();
isDisposed = true;
}
}
}
}

View File

@@ -3,9 +3,9 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using SharpCompress.Common;
using SharpCompress.Reader;
using SharpCompress.Readers;
namespace SharpCompress.Archive
namespace SharpCompress.Archives
{
public abstract class AbstractArchive<TEntry, TVolume> : IArchive, IArchiveExtractionListener
where TEntry : IArchiveEntry
@@ -20,31 +20,33 @@ namespace SharpCompress.Archive
public event EventHandler<CompressedBytesReadEventArgs> CompressedBytesRead;
public event EventHandler<FilePartExtractionBeginEventArgs> FilePartExtractionBegin;
protected string Password { get; private set; }
protected ReaderOptions ReaderOptions { get; }
private bool disposed;
#if !NO_FILE
internal AbstractArchive(ArchiveType type, FileInfo fileInfo, Options options, string password)
internal AbstractArchive(ArchiveType type, FileInfo fileInfo, ReaderOptions readerOptions)
{
Type = type;
Password = password;
if (!fileInfo.Exists)
{
throw new ArgumentException("File does not exist: " + fileInfo.FullName);
}
options = (Options) FlagUtility.SetFlag(options, Options.KeepStreamsOpen, false);
lazyVolumes = new LazyReadOnlyCollection<TVolume>(LoadVolumes(fileInfo, options));
ReaderOptions = readerOptions;
readerOptions.LeaveStreamOpen = false;
lazyVolumes = new LazyReadOnlyCollection<TVolume>(LoadVolumes(fileInfo));
lazyEntries = new LazyReadOnlyCollection<TEntry>(LoadEntries(Volumes));
}
protected abstract IEnumerable<TVolume> LoadVolumes(FileInfo file, Options options);
protected abstract IEnumerable<TVolume> LoadVolumes(FileInfo file);
#endif
internal AbstractArchive(ArchiveType type, IEnumerable<Stream> streams, Options options, string password)
internal AbstractArchive(ArchiveType type, IEnumerable<Stream> streams, ReaderOptions readerOptions)
{
Type = type;
Password = password;
lazyVolumes = new LazyReadOnlyCollection<TVolume>(LoadVolumes(streams.Select(CheckStreams), options));
ReaderOptions = readerOptions;
lazyVolumes = new LazyReadOnlyCollection<TVolume>(LoadVolumes(streams.Select(CheckStreams)));
lazyEntries = new LazyReadOnlyCollection<TEntry>(LoadEntries(Volumes));
}
@@ -54,22 +56,17 @@ namespace SharpCompress.Archive
lazyVolumes = new LazyReadOnlyCollection<TVolume>(Enumerable.Empty<TVolume>());
lazyEntries = new LazyReadOnlyCollection<TEntry>(Enumerable.Empty<TEntry>());
}
public ArchiveType Type { get; private set; }
public ArchiveType Type { get; }
void IArchiveExtractionListener.FireEntryExtractionBegin(IArchiveEntry entry)
{
if (EntryExtractionBegin != null)
{
EntryExtractionBegin(this, new ArchiveExtractionEventArgs<IArchiveEntry>(entry));
}
EntryExtractionBegin?.Invoke(this, new ArchiveExtractionEventArgs<IArchiveEntry>(entry));
}
void IArchiveExtractionListener.FireEntryExtractionEnd(IArchiveEntry entry)
{
if (EntryExtractionEnd != null)
{
EntryExtractionEnd(this, new ArchiveExtractionEventArgs<IArchiveEntry>(entry));
}
EntryExtractionEnd?.Invoke(this, new ArchiveExtractionEventArgs<IArchiveEntry>(entry));
}
private static Stream CheckStreams(Stream stream)
@@ -84,49 +81,29 @@ namespace SharpCompress.Archive
/// <summary>
/// Returns an ReadOnlyCollection of all the RarArchiveEntries across the one or many parts of the RarArchive.
/// </summary>
public virtual ICollection<TEntry> Entries
{
get { return lazyEntries; }
}
public virtual ICollection<TEntry> Entries { get { return lazyEntries; } }
/// <summary>
/// Returns an ReadOnlyCollection of all the RarArchiveVolumes across the one or many parts of the RarArchive.
/// </summary>
public ICollection<TVolume> Volumes
{
get { return lazyVolumes; }
}
public ICollection<TVolume> Volumes { get { return lazyVolumes; } }
/// <summary>
/// The total size of the files compressed in the archive.
/// </summary>
public virtual long TotalSize
{
get { return Entries.Aggregate(0L, (total, cf) => total + cf.CompressedSize); }
}
public virtual long TotalSize { get { return Entries.Aggregate(0L, (total, cf) => total + cf.CompressedSize); } }
/// <summary>
/// The total size of the files as uncompressed in the archive.
/// </summary>
public virtual long TotalUncompressSize
{
get { return Entries.Aggregate(0L, (total, cf) => total + cf.Size); }
}
public virtual long TotalUncompressSize { get { return Entries.Aggregate(0L, (total, cf) => total + cf.Size); } }
protected abstract IEnumerable<TVolume> LoadVolumes(IEnumerable<Stream> streams, Options options);
protected abstract IEnumerable<TVolume> LoadVolumes(IEnumerable<Stream> streams);
protected abstract IEnumerable<TEntry> LoadEntries(IEnumerable<TVolume> volumes);
IEnumerable<IArchiveEntry> IArchive.Entries
{
get { return Entries.Cast<IArchiveEntry>(); }
}
IEnumerable<IArchiveEntry> IArchive.Entries { get { return Entries.Cast<IArchiveEntry>(); } }
IEnumerable<IVolume> IArchive.Volumes
{
get { return lazyVolumes.Cast<IVolume>(); }
}
private bool disposed;
IEnumerable<IVolume> IArchive.Volumes { get { return lazyVolumes.Cast<IVolume>(); } }
public virtual void Dispose()
{
@@ -146,27 +123,21 @@ namespace SharpCompress.Archive
void IExtractionListener.FireCompressedBytesRead(long currentPartCompressedBytes, long compressedReadBytes)
{
if (CompressedBytesRead != null)
CompressedBytesRead?.Invoke(this, new CompressedBytesReadEventArgs
{
CompressedBytesRead(this, new CompressedBytesReadEventArgs()
{
CurrentFilePartCompressedBytesRead = currentPartCompressedBytes,
CompressedBytesRead = compressedReadBytes
});
}
CurrentFilePartCompressedBytesRead = currentPartCompressedBytes,
CompressedBytesRead = compressedReadBytes
});
}
void IExtractionListener.FireFilePartExtractionBegin(string name, long size, long compressedSize)
{
if (FilePartExtractionBegin != null)
FilePartExtractionBegin?.Invoke(this, new FilePartExtractionBeginEventArgs
{
FilePartExtractionBegin(this, new FilePartExtractionBeginEventArgs()
{
CompressedSize = compressedSize,
Size = size,
Name = name,
});
}
CompressedSize = compressedSize,
Size = size,
Name = name
});
}
/// <summary>
@@ -191,11 +162,7 @@ namespace SharpCompress.Archive
/// <summary>
/// Archive is SOLID (this means the Archive saved bytes by reusing information which helps for archives containing many small files).
/// </summary>
public virtual bool IsSolid
{
get { return false; }
}
public virtual bool IsSolid { get { return false; } }
/// <summary>
/// The archive can find all the parts of the archive needed to fully extract the archive. This forces the parsing of the entire archive.

View File

@@ -3,8 +3,10 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using SharpCompress.Common;
using SharpCompress.Readers;
using SharpCompress.Writers;
namespace SharpCompress.Archive
namespace SharpCompress.Archives
{
public abstract class AbstractWritableArchive<TEntry, TVolume> : AbstractArchive<TEntry, TVolume>, IWritableArchive
where TEntry : IArchiveEntry
@@ -21,14 +23,14 @@ namespace SharpCompress.Archive
{
}
internal AbstractWritableArchive(ArchiveType type, Stream stream, Options options)
: base(type, stream.AsEnumerable(), options, null)
internal AbstractWritableArchive(ArchiveType type, Stream stream, ReaderOptions readerFactoryOptions)
: base(type, stream.AsEnumerable(), readerFactoryOptions)
{
}
#if !NO_FILE
internal AbstractWritableArchive(ArchiveType type, FileInfo fileInfo, Options options)
: base(type, fileInfo, options, null)
internal AbstractWritableArchive(ArchiveType type, FileInfo fileInfo, ReaderOptions readerFactoryOptions)
: base(type, fileInfo, readerFactoryOptions)
{
}
#endif
@@ -53,10 +55,7 @@ namespace SharpCompress.Archive
modifiedEntries.AddRange(OldEntries.Concat(newEntries));
}
private IEnumerable<TEntry> OldEntries
{
get { return base.Entries.Where(x => !removedEntries.Contains(x)); }
}
private IEnumerable<TEntry> OldEntries { get { return base.Entries.Where(x => !removedEntries.Contains(x)); } }
public void RemoveEntry(TEntry entry)
{
@@ -66,25 +65,25 @@ namespace SharpCompress.Archive
RebuildModifiedCollection();
}
}
void IWritableArchive.RemoveEntry(IArchiveEntry entry)
{
RemoveEntry((TEntry)entry);
}
public TEntry AddEntry(string key, Stream source,
long size = 0, DateTime? modified = null)
long size = 0, DateTime? modified = null)
{
return AddEntry(key, source, false, size, modified);
}
IArchiveEntry IWritableArchive.AddEntry(string key, Stream source, bool closeStream, long size, DateTime? modified)
{
return AddEntry(key, source, closeStream, size, modified);
}
public TEntry AddEntry(string key, Stream source, bool closeStream,
long size = 0, DateTime? modified = null)
long size = 0, DateTime? modified = null)
{
if (key.StartsWith("/")
|| key.StartsWith("\\"))
@@ -105,7 +104,7 @@ namespace SharpCompress.Archive
{
foreach (var path in Entries.Select(x => x.Key))
{
var p = path.Replace('/','\\');
var p = path.Replace('/', '\\');
if (p.StartsWith("\\"))
{
p = p.Substring(1);
@@ -115,15 +114,15 @@ namespace SharpCompress.Archive
return false;
}
public void SaveTo(Stream stream, CompressionInfo compressionType)
public void SaveTo(Stream stream, WriterOptions options)
{
//reset streams of new entries
newEntries.Cast<IWritableArchiveEntry>().ForEach(x => x.Stream.Seek(0, SeekOrigin.Begin));
SaveTo(stream, compressionType, OldEntries, newEntries);
SaveTo(stream, options, OldEntries, newEntries);
}
protected TEntry CreateEntry(string key, Stream source, long size, DateTime? modified,
bool closeStream)
bool closeStream)
{
if (!source.CanRead || !source.CanSeek)
{
@@ -133,10 +132,9 @@ namespace SharpCompress.Archive
}
protected abstract TEntry CreateEntryInternal(string key, Stream source, long size, DateTime? modified,
bool closeStream);
bool closeStream);
protected abstract void SaveTo(Stream stream, CompressionInfo compressionType,
IEnumerable<TEntry> oldEntries, IEnumerable<TEntry> newEntries);
protected abstract void SaveTo(Stream stream, WriterOptions options, IEnumerable<TEntry> oldEntries, IEnumerable<TEntry> newEntries);
public override void Dispose()
{

View File

@@ -1,13 +1,15 @@
using System;
using System.IO;
using SharpCompress.Archive.GZip;
using SharpCompress.Archive.Rar;
using SharpCompress.Archive.SevenZip;
using SharpCompress.Archive.Tar;
using SharpCompress.Archive.Zip;
using SharpCompress.Archives.GZip;
using SharpCompress.Archives.Rar;
using SharpCompress.Archives.SevenZip;
using SharpCompress.Archives.Tar;
using SharpCompress.Archives.Zip;
using SharpCompress.Common;
using SharpCompress.Compressors.LZMA;
using SharpCompress.Readers;
namespace SharpCompress.Archive
namespace SharpCompress.Archives
{
public class ArchiveFactory
{
@@ -15,46 +17,46 @@ namespace SharpCompress.Archive
/// Opens an Archive for random access
/// </summary>
/// <param name="stream"></param>
/// <param name="options"></param>
/// <param name="readerOptions"></param>
/// <returns></returns>
public static IArchive Open(Stream stream, Options options = Options.KeepStreamsOpen)
public static IArchive Open(Stream stream, ReaderOptions readerOptions = null)
{
stream.CheckNotNull("stream");
if (!stream.CanRead || !stream.CanSeek)
{
throw new ArgumentException("Stream should be readable and seekable");
}
readerOptions = readerOptions ?? new ReaderOptions();
if (ZipArchive.IsZipFile(stream, null))
{
stream.Seek(0, SeekOrigin.Begin);
return ZipArchive.Open(stream, options, null);
return ZipArchive.Open(stream, readerOptions);
}
stream.Seek(0, SeekOrigin.Begin);
if (SevenZipArchive.IsSevenZipFile(stream))
{
stream.Seek(0, SeekOrigin.Begin);
return SevenZipArchive.Open(stream, options);
return SevenZipArchive.Open(stream, readerOptions);
}
stream.Seek(0, SeekOrigin.Begin);
if (GZipArchive.IsGZipFile(stream))
{
stream.Seek(0, SeekOrigin.Begin);
return GZipArchive.Open(stream, options);
return GZipArchive.Open(stream, readerOptions);
}
stream.Seek(0, SeekOrigin.Begin);
if (RarArchive.IsRarFile(stream, options))
if (RarArchive.IsRarFile(stream, readerOptions))
{
stream.Seek(0, SeekOrigin.Begin);
return RarArchive.Open(stream, options);
stream.Seek(0, SeekOrigin.Begin);
return RarArchive.Open(stream, readerOptions);
}
stream.Seek(0, SeekOrigin.Begin);
if (TarArchive.IsTarFile(stream))
{
stream.Seek(0, SeekOrigin.Begin);
return TarArchive.Open(stream, options);
return TarArchive.Open(stream, readerOptions);
}
throw new InvalidOperationException("Cannot determine compressed stream type. Supported Archive Formats: Zip, GZip, Tar, Rar, 7Zip");
throw new InvalidOperationException("Cannot determine compressed stream type. Supported Archive Formats: Zip, GZip, Tar, Rar, 7Zip, LZip");
}
public static IWritableArchive Create(ArchiveType type)
@@ -62,52 +64,35 @@ namespace SharpCompress.Archive
switch (type)
{
case ArchiveType.Zip:
{
return ZipArchive.Create();
}
{
return ZipArchive.Create();
}
case ArchiveType.Tar:
{
return TarArchive.Create();
}
{
return TarArchive.Create();
}
case ArchiveType.GZip:
{
return GZipArchive.Create();
}
{
return GZipArchive.Create();
}
default:
{
throw new NotSupportedException("Cannot create Archives of type: " + type);
}
{
throw new NotSupportedException("Cannot create Archives of type: " + type);
}
}
}
#if !NO_FILE
/// <summary>
/// Constructor expects a filepath to an existing file.
/// </summary>
/// <param name="filePath"></param>
public static IArchive Open(string filePath)
{
return Open(filePath, Options.None);
}
/// <summary>
/// Constructor with a FileInfo object to an existing file.
/// </summary>
/// <param name="fileInfo"></param>
public static IArchive Open(FileInfo fileInfo)
{
return Open(fileInfo, Options.None);
}
/// <summary>
/// Constructor expects a filepath to an existing file.
/// </summary>
/// <param name="filePath"></param>
/// <param name="options"></param>
public static IArchive Open(string filePath, Options options)
public static IArchive Open(string filePath, ReaderOptions options = null)
{
filePath.CheckNotNullOrEmpty("filePath");
return Open(new FileInfo(filePath), options);
return Open(new FileInfo(filePath), options ?? new ReaderOptions());
}
/// <summary>
@@ -115,15 +100,16 @@ namespace SharpCompress.Archive
/// </summary>
/// <param name="fileInfo"></param>
/// <param name="options"></param>
public static IArchive Open(FileInfo fileInfo, Options options)
public static IArchive Open(FileInfo fileInfo, ReaderOptions options = null)
{
fileInfo.CheckNotNull("fileInfo");
options = options ?? new ReaderOptions();
using (var stream = fileInfo.OpenRead())
{
if (ZipArchive.IsZipFile(stream, null))
{
stream.Dispose();
return ZipArchive.Open(fileInfo, options, null);
return ZipArchive.Open(fileInfo, options);
}
stream.Seek(0, SeekOrigin.Begin);
if (SevenZipArchive.IsSevenZipFile(stream))
@@ -157,7 +143,7 @@ namespace SharpCompress.Archive
/// Extract to specific directory, retaining filename
/// </summary>
public static void WriteToDirectory(string sourceArchive, string destinationDirectory,
ExtractOptions options = ExtractOptions.Overwrite)
ExtractionOptions options = null)
{
using (IArchive archive = Open(sourceArchive))
{

View File

@@ -4,53 +4,37 @@ using System.IO;
using System.Linq;
using SharpCompress.Common;
using SharpCompress.Common.GZip;
using SharpCompress.Reader;
using SharpCompress.Reader.GZip;
using SharpCompress.Writer.GZip;
using SharpCompress.Readers;
using SharpCompress.Readers.GZip;
using SharpCompress.Writers;
using SharpCompress.Writers.GZip;
namespace SharpCompress.Archive.GZip
namespace SharpCompress.Archives.GZip
{
public class GZipArchive : AbstractWritableArchive<GZipArchiveEntry, GZipVolume>
{
#if !NO_FILE
/// <summary>
/// Constructor expects a filepath to an existing file.
/// </summary>
/// <param name="filePath"></param>
public static GZipArchive Open(string filePath)
{
return Open(filePath, Options.None);
}
/// <summary>
/// Constructor with a FileInfo object to an existing file.
/// </summary>
/// <param name="fileInfo"></param>
public static GZipArchive Open(FileInfo fileInfo)
{
return Open(fileInfo, Options.None);
}
/// <summary>
/// Constructor expects a filepath to an existing file.
/// </summary>
/// <param name="filePath"></param>
/// <param name="options"></param>
public static GZipArchive Open(string filePath, Options options)
/// <param name="readerOptions"></param>
public static GZipArchive Open(string filePath, ReaderOptions readerOptions = null)
{
filePath.CheckNotNullOrEmpty("filePath");
return Open(new FileInfo(filePath), options);
return Open(new FileInfo(filePath), readerOptions ?? new ReaderOptions());
}
/// <summary>
/// Constructor with a FileInfo object to an existing file.
/// </summary>
/// <param name="fileInfo"></param>
/// <param name="options"></param>
public static GZipArchive Open(FileInfo fileInfo, Options options)
/// <param name="readerOptions"></param>
public static GZipArchive Open(FileInfo fileInfo, ReaderOptions readerOptions = null)
{
fileInfo.CheckNotNull("fileInfo");
return new GZipArchive(fileInfo, options);
return new GZipArchive(fileInfo, readerOptions ?? new ReaderOptions());
}
#endif
@@ -58,21 +42,11 @@ namespace SharpCompress.Archive.GZip
/// Takes a seekable Stream as a source
/// </summary>
/// <param name="stream"></param>
public static GZipArchive Open(Stream stream)
/// <param name="readerOptions"></param>
public static GZipArchive Open(Stream stream, ReaderOptions readerOptions = null)
{
stream.CheckNotNull("stream");
return Open(stream, Options.None);
}
/// <summary>
/// Takes a seekable Stream as a source
/// </summary>
/// <param name="stream"></param>
/// <param name="options"></param>
public static GZipArchive Open(Stream stream, Options options)
{
stream.CheckNotNull("stream");
return new GZipArchive(stream, options);
return new GZipArchive(stream, readerOptions ?? new ReaderOptions());
}
public static GZipArchive Create()
@@ -81,19 +55,20 @@ namespace SharpCompress.Archive.GZip
}
#if !NO_FILE
/// <summary>
/// Constructor with a FileInfo object to an existing file.
/// </summary>
/// <param name="fileInfo"></param>
/// <param name="options"></param>
internal GZipArchive(FileInfo fileInfo, Options options)
internal GZipArchive(FileInfo fileInfo, ReaderOptions options)
: base(ArchiveType.GZip, fileInfo, options)
{
}
protected override IEnumerable<GZipVolume> LoadVolumes(FileInfo file, Options options)
protected override IEnumerable<GZipVolume> LoadVolumes(FileInfo file)
{
return new GZipVolume(file, options).AsEnumerable();
return new GZipVolume(file, ReaderOptions).AsEnumerable();
}
public static bool IsGZipFile(string filePath)
@@ -122,7 +97,7 @@ namespace SharpCompress.Archive.GZip
{
using (var stream = fileInfo.Open(FileMode.Create, FileAccess.Write))
{
SaveTo(stream);
SaveTo(stream, new WriterOptions(CompressionType.GZip));
}
}
#endif
@@ -131,17 +106,17 @@ namespace SharpCompress.Archive.GZip
{
// read the header on the first read
byte[] header = new byte[10];
int n = stream.Read(header, 0, header.Length);
// workitem 8501: handle edge case (decompress empty stream)
if (n == 0)
return false;
if (n != 10)
if (!stream.ReadFully(header))
{
return false;
}
if (header[0] != 0x1F || header[1] != 0x8B || header[2] != 8)
{
return false;
}
return true;
}
@@ -151,7 +126,7 @@ namespace SharpCompress.Archive.GZip
/// </summary>
/// <param name="stream"></param>
/// <param name="options"></param>
internal GZipArchive(Stream stream, Options options)
internal GZipArchive(Stream stream, ReaderOptions options)
: base(ArchiveType.GZip, stream, options)
{
}
@@ -161,13 +136,8 @@ namespace SharpCompress.Archive.GZip
{
}
public void SaveTo(Stream stream)
{
SaveTo(stream, CompressionType.GZip);
}
protected override GZipArchiveEntry CreateEntryInternal(string filePath, Stream source, long size, DateTime? modified,
bool closeStream)
bool closeStream)
{
if (Entries.Any())
{
@@ -176,7 +146,7 @@ namespace SharpCompress.Archive.GZip
return new GZipWritableArchiveEntry(this, source, filePath, size, modified, closeStream);
}
protected override void SaveTo(Stream stream, CompressionInfo compressionInfo,
protected override void SaveTo(Stream stream, WriterOptions options,
IEnumerable<GZipArchiveEntry> oldEntries,
IEnumerable<GZipArchiveEntry> newEntries)
{
@@ -184,7 +154,7 @@ namespace SharpCompress.Archive.GZip
{
throw new InvalidOperationException("Only one entry is allowed in a GZip Archive");
}
using (var writer = new GZipWriter(stream))
using (var writer = new GZipWriter(stream, new GZipWriterOptions(options)))
{
foreach (var entry in oldEntries.Concat(newEntries)
.Where(x => !x.IsDirectory))
@@ -197,15 +167,15 @@ namespace SharpCompress.Archive.GZip
}
}
protected override IEnumerable<GZipVolume> LoadVolumes(IEnumerable<Stream> streams, Options options)
protected override IEnumerable<GZipVolume> LoadVolumes(IEnumerable<Stream> streams)
{
return new GZipVolume(streams.First(), options).AsEnumerable();
return new GZipVolume(streams.First(), ReaderOptions).AsEnumerable();
}
protected override IEnumerable<GZipArchiveEntry> LoadEntries(IEnumerable<GZipVolume> volumes)
{
Stream stream = volumes.Single().Stream;
yield return new GZipArchiveEntry(this, new GZipFilePart(stream));
yield return new GZipArchiveEntry(this, new GZipFilePart(stream, ReaderOptions.ArchiveEncoding));
}
protected override IReader CreateReaderForSolidExtraction()

View File

@@ -2,11 +2,10 @@
using System.Linq;
using SharpCompress.Common.GZip;
namespace SharpCompress.Archive.GZip
namespace SharpCompress.Archives.GZip
{
public class GZipArchiveEntry : GZipEntry, IArchiveEntry
{
internal GZipArchiveEntry(GZipArchive archive, GZipFilePart part)
: base(part)
{
@@ -15,16 +14,20 @@ namespace SharpCompress.Archive.GZip
public virtual Stream OpenEntryStream()
{
//this is to reset the stream to be read multiple times
var part = Parts.Single() as GZipFilePart;
if (part.GetRawStream().Position != part.EntryStartPosition)
{
part.GetRawStream().Position = part.EntryStartPosition;
}
return Parts.Single().GetCompressedStream();
}
#region IArchiveEntry Members
public IArchive Archive { get; private set; }
public bool IsComplete
{
get { return true; }
}
public IArchive Archive { get; }
public bool IsComplete => true;
#endregion
}

View File

@@ -0,0 +1,66 @@
using System;
using System.Collections.Generic;
using System.IO;
using SharpCompress.Common;
using SharpCompress.IO;
namespace SharpCompress.Archives.GZip
{
internal class GZipWritableArchiveEntry : GZipArchiveEntry, IWritableArchiveEntry
{
private readonly bool closeStream;
private readonly Stream stream;
internal GZipWritableArchiveEntry(GZipArchive archive, Stream stream,
string path, long size, DateTime? lastModified, bool closeStream)
: base(archive, null)
{
this.stream = stream;
Key = path;
Size = size;
LastModifiedTime = lastModified;
this.closeStream = closeStream;
}
public override long Crc => 0;
public override string Key { get; }
public override long CompressedSize => 0;
public override long Size { get; }
public override DateTime? LastModifiedTime { get; }
public override DateTime? CreatedTime => null;
public override DateTime? LastAccessedTime => null;
public override DateTime? ArchivedTime => null;
public override bool IsEncrypted => false;
public override bool IsDirectory => false;
public override bool IsSplit => false;
internal override IEnumerable<FilePart> Parts => throw new NotImplementedException();
Stream IWritableArchiveEntry.Stream => stream;
public override Stream OpenEntryStream()
{
//ensure new stream is at the start, this could be reset
stream.Seek(0, SeekOrigin.Begin);
return new NonDisposingStream(stream);
}
internal override void Close()
{
if (closeStream)
{
stream.Dispose();
}
}
}
}

View File

@@ -1,9 +1,9 @@
using System;
using System.Collections.Generic;
using SharpCompress.Common;
using SharpCompress.Reader;
using SharpCompress.Readers;
namespace SharpCompress.Archive
namespace SharpCompress.Archives
{
public interface IArchive : IDisposable
{

View File

@@ -1,7 +1,7 @@
using System.IO;
using SharpCompress.Common;
namespace SharpCompress.Archive
namespace SharpCompress.Archives
{
public interface IArchiveEntry : IEntry
{

View File

@@ -1,8 +1,9 @@
using System.IO;
using SharpCompress.Common;
using SharpCompress.IO;
using SharpCompress.Readers;
namespace SharpCompress.Archive
namespace SharpCompress.Archives
{
public static class IArchiveEntryExtensions
{
@@ -28,25 +29,33 @@ namespace SharpCompress.Archive
return;
}
using (entryStream)
using (Stream s = new ListeningStream(streamListener, entryStream))
{
s.TransferTo(streamToWriteTo);
using (Stream s = new ListeningStream(streamListener, entryStream))
{
s.TransferTo(streamToWriteTo);
}
}
streamListener.FireEntryExtractionEnd(archiveEntry);
}
#if !NO_FILE
/// <summary>
/// Extract to specific directory, retaining filename
/// </summary>
/// <summary>
/// Extract to specific directory, retaining filename
/// </summary>
public static void WriteToDirectory(this IArchiveEntry entry, string destinationDirectory,
ExtractOptions options = ExtractOptions.Overwrite)
ExtractionOptions options = null)
{
string destinationFileName;
string file = Path.GetFileName(entry.Key);
options = options ?? new ExtractionOptions()
{
Overwrite = true
};
if (options.HasFlag(ExtractOptions.ExtractFullPath))
if (options.ExtractFullPath)
{
string folder = Path.GetDirectoryName(entry.Key);
string destdir = Path.Combine(destinationDirectory, folder);
@@ -70,11 +79,16 @@ namespace SharpCompress.Archive
/// Extract to specific file
/// </summary>
public static void WriteToFile(this IArchiveEntry entry, string destinationFileName,
ExtractOptions options = ExtractOptions.Overwrite)
ExtractionOptions options = null)
{
FileMode fm = FileMode.Create;
options = options ?? new ExtractionOptions()
{
Overwrite = true
};
if (!options.HasFlag(ExtractOptions.Overwrite))
if (!options.Overwrite)
{
fm = FileMode.CreateNew;
}

View File

@@ -1,16 +1,20 @@
using System.Linq;
using SharpCompress.Common;
#if !NO_FILE
using System.Linq;
using SharpCompress.Readers;
namespace SharpCompress.Archive
#endif
namespace SharpCompress.Archives
{
public static class IArchiveExtensions
{
#if !NO_FILE
/// <summary>
/// Extract to specific directory, retaining filename
/// </summary>
/// <summary>
/// Extract to specific directory, retaining filename
/// </summary>
public static void WriteToDirectory(this IArchive archive, string destinationDirectory,
ExtractOptions options = ExtractOptions.Overwrite)
ExtractionOptions options = null)
{
foreach (IArchiveEntry entry in archive.Entries.Where(x => !x.IsDirectory))
{

View File

@@ -1,6 +1,6 @@
using SharpCompress.Common;
namespace SharpCompress.Archive
namespace SharpCompress.Archives
{
internal interface IArchiveExtractionListener : IExtractionListener
{

View File

@@ -1,8 +1,8 @@
using System;
using System.IO;
using SharpCompress.Common;
using SharpCompress.Writers;
namespace SharpCompress.Archive
namespace SharpCompress.Archives
{
public interface IWritableArchive : IArchive
{
@@ -10,6 +10,6 @@ namespace SharpCompress.Archive
IArchiveEntry AddEntry(string key, Stream source, bool closeStream, long size = 0, DateTime? modified = null);
void SaveTo(Stream stream, CompressionInfo compressionType);
void SaveTo(Stream stream, WriterOptions options);
}
}

View File

@@ -1,6 +1,6 @@
using System.IO;
namespace SharpCompress.Archive
namespace SharpCompress.Archives
{
internal interface IWritableArchiveEntry
{

View File

@@ -1,17 +1,13 @@
using System;
#if !NO_FILE
using System;
#endif
using System.IO;
using SharpCompress.Common;
using SharpCompress.Writers;
namespace SharpCompress.Archive
namespace SharpCompress.Archives
{
public static class IWritableArchiveExtensions
{
public static void SaveTo(this IWritableArchive writableArchive,
Stream stream, CompressionType compressionType)
{
writableArchive.SaveTo(stream, new CompressionInfo {Type = compressionType});
}
#if !NO_FILE
public static void AddEntry(this IWritableArchive writableArchive,
@@ -26,33 +22,16 @@ namespace SharpCompress.Archive
fileInfo.LastWriteTime);
}
public static void SaveTo(this IWritableArchive writableArchive,
string filePath, CompressionType compressionType)
public static void SaveTo(this IWritableArchive writableArchive, string filePath, WriterOptions options)
{
writableArchive.SaveTo(new FileInfo(filePath), new CompressionInfo {Type = compressionType});
writableArchive.SaveTo(new FileInfo(filePath), options);
}
public static void SaveTo(this IWritableArchive writableArchive,
FileInfo fileInfo, CompressionType compressionType)
public static void SaveTo(this IWritableArchive writableArchive, FileInfo fileInfo, WriterOptions options)
{
using (var stream = fileInfo.Open(FileMode.Create, FileAccess.Write))
{
writableArchive.SaveTo(stream, new CompressionInfo {Type = compressionType});
}
}
public static void SaveTo(this IWritableArchive writableArchive,
string filePath, CompressionInfo compressionInfo)
{
writableArchive.SaveTo(new FileInfo(filePath), compressionInfo);
}
public static void SaveTo(this IWritableArchive writableArchive,
FileInfo fileInfo, CompressionInfo compressionInfo)
{
using (var stream = fileInfo.Open(FileMode.Create, FileAccess.Write))
{
writableArchive.SaveTo(stream, compressionInfo);
writableArchive.SaveTo(stream, options);
}
}

View File

@@ -1,42 +1,40 @@
#if !NO_FILE

#if !NO_FILE
using System.Collections.Generic;
using System.IO;
using SharpCompress.Common;
using SharpCompress.Common.Rar;
using SharpCompress.Common.Rar.Headers;
using SharpCompress.IO;
using SharpCompress.Readers;
namespace SharpCompress.Archive.Rar
namespace SharpCompress.Archives.Rar
{
/// <summary>
/// A rar part based on a FileInfo object
/// </summary>
internal class FileInfoRarArchiveVolume : RarVolume
{
internal FileInfoRarArchiveVolume(FileInfo fileInfo, string password, Options options)
: base(StreamingMode.Seekable, fileInfo.OpenRead(), password, FixOptions(options))
internal FileInfoRarArchiveVolume(FileInfo fileInfo, ReaderOptions options)
: base(StreamingMode.Seekable, fileInfo.OpenRead(), FixOptions(options))
{
FileInfo = fileInfo;
FileParts = base.GetVolumeFileParts().ToReadOnly();
FileParts = GetVolumeFileParts().ToReadOnly();
}
private static Options FixOptions(Options options)
private static ReaderOptions FixOptions(ReaderOptions options)
{
//make sure we're closing streams with fileinfo
if (options.HasFlag(Options.KeepStreamsOpen))
{
options = (Options) FlagUtility.SetFlag(options, Options.KeepStreamsOpen, false);
}
options.LeaveStreamOpen = false;
return options;
}
internal ReadOnlyCollection<RarFilePart> FileParts { get; private set; }
internal ReadOnlyCollection<RarFilePart> FileParts { get; }
internal FileInfo FileInfo { get; private set; }
internal FileInfo FileInfo { get; }
internal override RarFilePart CreateFilePart(FileHeader fileHeader, MarkHeader markHeader)
{
return new FileInfoRarFilePart(this, markHeader, fileHeader, FileInfo);
return new FileInfoRarFilePart(this, ReaderOptions.Password, markHeader, fileHeader, FileInfo);
}
internal override IEnumerable<RarFilePart> ReadFileParts()

View File

@@ -1,19 +1,19 @@
#if !NO_FILE

#if !NO_FILE
using System.IO;
using SharpCompress.Common.Rar;
using SharpCompress.Common.Rar.Headers;
namespace SharpCompress.Archive.Rar
namespace SharpCompress.Archives.Rar
{
internal class FileInfoRarFilePart : SeekableFilePart
{
internal FileInfoRarFilePart(FileInfoRarArchiveVolume volume, MarkHeader mh, FileHeader fh, FileInfo fi)
: base(mh, fh, volume.Stream, volume.Password)
internal FileInfoRarFilePart(FileInfoRarArchiveVolume volume, string password, MarkHeader mh, FileHeader fh, FileInfo fi)
: base(mh, fh, volume.Stream, password)
{
FileInfo = fi;
}
internal FileInfo FileInfo { get; private set; }
internal FileInfo FileInfo { get; }
internal override string FilePartName
{

View File

@@ -1,6 +1,6 @@
using System.Linq;
namespace SharpCompress.Archive.Rar
namespace SharpCompress.Archives.Rar
{
public static class RarArchiveExtensions
{

View File

@@ -1,41 +1,35 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using SharpCompress.Common;
using SharpCompress.Common.Rar;
using SharpCompress.Common.Rar.Headers;
using SharpCompress.Compressor.Rar;
using SharpCompress.Compressors.Rar;
using SharpCompress.IO;
using SharpCompress.Reader;
using SharpCompress.Reader.Rar;
using SharpCompress.Readers;
using SharpCompress.Readers.Rar;
namespace SharpCompress.Archive.Rar
namespace SharpCompress.Archives.Rar
{
public class RarArchive : AbstractArchive<RarArchiveEntry, RarVolume>
{
private readonly Unpack unpack = new Unpack();
internal Unpack Unpack
{
get { return unpack; }
}
internal Unpack Unpack { get; } = new Unpack();
#if !NO_FILE
/// <summary>
/// Constructor with a FileInfo object to an existing file.
/// </summary>
/// <param name="fileInfo"></param>
/// <param name="options"></param>
/// <param name="password"></param>
internal RarArchive(FileInfo fileInfo, Options options, string password)
: base(ArchiveType.Rar, fileInfo, options, password)
internal RarArchive(FileInfo fileInfo, ReaderOptions options)
: base(ArchiveType.Rar, fileInfo, options)
{
}
protected override IEnumerable<RarVolume> LoadVolumes(FileInfo file, Options options)
protected override IEnumerable<RarVolume> LoadVolumes(FileInfo file)
{
return RarArchiveVolumeFactory.GetParts(file, Password, options);
return RarArchiveVolumeFactory.GetParts(file, ReaderOptions);
}
#endif
@@ -44,9 +38,8 @@ namespace SharpCompress.Archive.Rar
/// </summary>
/// <param name="streams"></param>
/// <param name="options"></param>
/// <param name="password"></param>
internal RarArchive(IEnumerable<Stream> streams, Options options, string password)
: base(ArchiveType.Rar, streams, options, password)
internal RarArchive(IEnumerable<Stream> streams, ReaderOptions options)
: base(ArchiveType.Rar, streams, options)
{
}
@@ -55,36 +48,33 @@ namespace SharpCompress.Archive.Rar
return RarArchiveEntryFactory.GetEntries(this, volumes);
}
protected override IEnumerable<RarVolume> LoadVolumes(IEnumerable<Stream> streams, Options options)
protected override IEnumerable<RarVolume> LoadVolumes(IEnumerable<Stream> streams)
{
return RarArchiveVolumeFactory.GetParts(streams, Password, options);
return RarArchiveVolumeFactory.GetParts(streams, ReaderOptions);
}
protected override IReader CreateReaderForSolidExtraction()
{
var stream = Volumes.First().Stream;
stream.Position = 0;
return RarReader.Open(stream, Password);
return RarReader.Open(stream, ReaderOptions);
}
public override bool IsSolid
{
get { return Volumes.First().IsSolidArchive; }
}
public override bool IsSolid => Volumes.First().IsSolidArchive;
#region Creation
#if !NO_FILE
/// <summary>
/// Constructor expects a filepath to an existing file.
/// Constructor with a FileInfo object to an existing file.
/// </summary>
/// <param name="filePath"></param>
/// <param name="options"></param>
/// <param name="password"></param>
public static RarArchive Open(string filePath, Options options = Options.None, string password = null)
public static RarArchive Open(string filePath, ReaderOptions options = null)
{
filePath.CheckNotNullOrEmpty("filePath");
return Open(new FileInfo(filePath), options, password);
return new RarArchive(new FileInfo(filePath), options ?? new ReaderOptions());
}
/// <summary>
@@ -92,23 +82,22 @@ namespace SharpCompress.Archive.Rar
/// </summary>
/// <param name="fileInfo"></param>
/// <param name="options"></param>
/// <param name="password"></param>
public static RarArchive Open(FileInfo fileInfo, Options options = Options.None, string password = null)
public static RarArchive Open(FileInfo fileInfo, ReaderOptions options = null)
{
fileInfo.CheckNotNull("fileInfo");
return new RarArchive(fileInfo, options, password);
return new RarArchive(fileInfo, options ?? new ReaderOptions());
}
#endif
/// <summary>
/// Takes a seekable Stream as a source
/// </summary>
/// <param name="stream"></param>
/// <param name="options"></param>
/// <param name="password"></param>
public static RarArchive Open(Stream stream, Options options = Options.KeepStreamsOpen, string password = null)
public static RarArchive Open(Stream stream, ReaderOptions options = null)
{
stream.CheckNotNull("stream");
return Open(stream.AsEnumerable(), options, password);
return Open(stream.AsEnumerable(), options ?? new ReaderOptions());
}
/// <summary>
@@ -116,11 +105,10 @@ namespace SharpCompress.Archive.Rar
/// </summary>
/// <param name="streams"></param>
/// <param name="options"></param>
/// <param name="password"></param>
public static RarArchive Open(IEnumerable<Stream> streams, Options options = Options.KeepStreamsOpen, string password = null)
public static RarArchive Open(IEnumerable<Stream> streams, ReaderOptions options = null)
{
streams.CheckNotNull("streams");
return new RarArchive(streams, options, password);
return new RarArchive(streams, options ?? new ReaderOptions());
}
#if !NO_FILE
@@ -141,17 +129,12 @@ namespace SharpCompress.Archive.Rar
}
}
#endif
public static bool IsRarFile(Stream stream)
{
return IsRarFile(stream, Options.None);
}
public static bool IsRarFile(Stream stream, Options options)
public static bool IsRarFile(Stream stream, ReaderOptions options = null)
{
try
{
var headerFactory = new RarHeaderFactory(StreamingMode.Seekable, options);
var headerFactory = new RarHeaderFactory(StreamingMode.Seekable, options ?? new ReaderOptions());
var markHeader = headerFactory.ReadHeaders(stream).FirstOrDefault() as MarkHeader;
return markHeader != null && markHeader.IsValid();
}

View File

@@ -5,9 +5,9 @@ using System.Linq;
using SharpCompress.Common;
using SharpCompress.Common.Rar;
using SharpCompress.Common.Rar.Headers;
using SharpCompress.Compressor.Rar;
using SharpCompress.Compressors.Rar;
namespace SharpCompress.Archive.Rar
namespace SharpCompress.Archives.Rar
{
public class RarArchiveEntry : RarEntry, IArchiveEntry
{
@@ -20,28 +20,13 @@ namespace SharpCompress.Archive.Rar
this.archive = archive;
}
public override CompressionType CompressionType
{
get { return CompressionType.Rar; }
}
public override CompressionType CompressionType => CompressionType.Rar;
public IArchive Archive
{
get
{
return archive;
}
}
public IArchive Archive => archive;
internal override IEnumerable<FilePart> Parts
{
get { return parts.Cast<FilePart>(); }
}
internal override IEnumerable<FilePart> Parts => parts.Cast<FilePart>();
internal override FileHeader FileHeader
{
get { return parts.First().FileHeader; }
}
internal override FileHeader FileHeader => parts.First().FileHeader;
public override long Crc
{
@@ -49,11 +34,10 @@ namespace SharpCompress.Archive.Rar
{
CheckIncomplete();
return parts.Select(fp => fp.FileHeader)
.Single(fh => !fh.FileFlags.HasFlag(FileFlags.SPLIT_AFTER)).FileCRC;
.Single(fh => !fh.FileFlags.HasFlag(FileFlags.SPLIT_AFTER)).FileCRC;
}
}
public override long Size
{
get
@@ -81,10 +65,7 @@ namespace SharpCompress.Archive.Rar
return new RarStream(archive.Unpack, FileHeader, new MultiVolumeReadOnlyStream(Parts.Cast<RarFilePart>(), archive));
}
public bool IsComplete
{
get { return parts.Select(fp => fp.FileHeader).Any(fh => !fh.FileFlags.HasFlag(FileFlags.SPLIT_AFTER)); }
}
public bool IsComplete { get { return parts.Select(fp => fp.FileHeader).Any(fh => !fh.FileFlags.HasFlag(FileFlags.SPLIT_AFTER)); } }
private void CheckIncomplete()
{

View File

@@ -3,7 +3,7 @@ using SharpCompress.Common;
using SharpCompress.Common.Rar;
using SharpCompress.Common.Rar.Headers;
namespace SharpCompress.Archive.Rar
namespace SharpCompress.Archives.Rar
{
internal static class RarArchiveEntryFactory
{
@@ -25,7 +25,7 @@ namespace SharpCompress.Archive.Rar
{
groupedParts.Add(fp);
if (!FlagUtility.HasFlag((long) fp.FileHeader.FileFlags, (long) FileFlags.SPLIT_AFTER))
if (!FlagUtility.HasFlag((long)fp.FileHeader.FileFlags, (long)FileFlags.SPLIT_AFTER))
{
yield return groupedParts;
groupedParts = new List<RarFilePart>();

View File

@@ -1,17 +1,20 @@
using System;
using System.Collections.Generic;
using System.IO;
using SharpCompress.Common;
using SharpCompress.Common.Rar;
using SharpCompress.Readers;
#if !NO_FILE
using System.Linq;
using System.Text;
using SharpCompress.Common.Rar.Headers;
using SharpCompress.Common;
using SharpCompress.Common.Rar;
#endif
namespace SharpCompress.Archive.Rar
namespace SharpCompress.Archives.Rar
{
internal static class RarArchiveVolumeFactory
{
internal static IEnumerable<RarVolume> GetParts(IEnumerable<Stream> streams, string password, Options options)
internal static IEnumerable<RarVolume> GetParts(IEnumerable<Stream> streams, ReaderOptions options)
{
foreach (Stream s in streams)
{
@@ -19,15 +22,15 @@ namespace SharpCompress.Archive.Rar
{
throw new ArgumentException("Stream is not readable and seekable");
}
StreamRarArchiveVolume part = new StreamRarArchiveVolume(s, password, options);
StreamRarArchiveVolume part = new StreamRarArchiveVolume(s, options);
yield return part;
}
}
#if !NO_FILE
internal static IEnumerable<RarVolume> GetParts(FileInfo fileInfo, string password, Options options)
internal static IEnumerable<RarVolume> GetParts(FileInfo fileInfo, ReaderOptions options)
{
FileInfoRarArchiveVolume part = new FileInfoRarArchiveVolume(fileInfo, password, options);
FileInfoRarArchiveVolume part = new FileInfoRarArchiveVolume(fileInfo, options);
yield return part;
if (!part.ArchiveHeader.ArchiveHeaderFlags.HasFlag(ArchiveFlags.VOLUME))
@@ -39,7 +42,7 @@ namespace SharpCompress.Archive.Rar
//we use fileinfo because rar is dumb and looks at file names rather than archive info for another volume
while (fileInfo != null && fileInfo.Exists)
{
part = new FileInfoRarArchiveVolume(fileInfo, password, options);
part = new FileInfoRarArchiveVolume(fileInfo, options);
fileInfo = GetNextFileInfo(ah, part.FileParts.FirstOrDefault() as FileInfoRarFilePart);
yield return part;

View File

@@ -1,9 +1,8 @@
using System;
using System.IO;
using System.IO;
using SharpCompress.Common.Rar;
using SharpCompress.Common.Rar.Headers;
namespace SharpCompress.Archive.Rar
namespace SharpCompress.Archives.Rar
{
internal class SeekableFilePart : RarFilePart
{
@@ -29,9 +28,6 @@ namespace SharpCompress.Archive.Rar
return stream;
}
internal override string FilePartName
{
get { return "Unknown Stream - File Entry: " + FileHeader.FileName; }
}
internal override string FilePartName => "Unknown Stream - File Entry: " + FileHeader.FileName;
}
}

View File

@@ -1,16 +1,16 @@
using System.Collections.Generic;
using System.IO;
using SharpCompress.Common;
using SharpCompress.Common.Rar;
using SharpCompress.Common.Rar.Headers;
using SharpCompress.IO;
using SharpCompress.Readers;
namespace SharpCompress.Archive.Rar
namespace SharpCompress.Archives.Rar
{
internal class StreamRarArchiveVolume : RarVolume
{
internal StreamRarArchiveVolume(Stream stream, string password, Options options)
: base(StreamingMode.Seekable, stream, password, options)
internal StreamRarArchiveVolume(Stream stream, ReaderOptions options)
: base(StreamingMode.Seekable, stream, options)
{
}
@@ -21,7 +21,7 @@ namespace SharpCompress.Archive.Rar
internal override RarFilePart CreateFilePart(FileHeader fileHeader, MarkHeader markHeader)
{
return new SeekableFilePart(markHeader, fileHeader, Stream, Password);
return new SeekableFilePart(markHeader, fileHeader, Stream, ReaderOptions.Password);
}
}
}

View File

@@ -4,90 +4,59 @@ using System.IO;
using System.Linq;
using SharpCompress.Common;
using SharpCompress.Common.SevenZip;
using SharpCompress.Compressors.LZMA.Utilites;
using SharpCompress.IO;
using SharpCompress.Reader;
using SharpCompress.Readers;
namespace SharpCompress.Archive.SevenZip
namespace SharpCompress.Archives.SevenZip
{
public class SevenZipArchive : AbstractArchive<SevenZipArchiveEntry, SevenZipVolume>
{
private ArchiveDatabase database;
#if !NO_FILE
/// <summary>
/// Constructor expects a filepath to an existing file.
/// </summary>
/// <param name="filePath"></param>
public static SevenZipArchive Open(string filePath)
{
return Open(filePath, Options.None);
}
/// <summary>
/// Constructor with a FileInfo object to an existing file.
/// </summary>
/// <param name="fileInfo"></param>
public static SevenZipArchive Open(FileInfo fileInfo)
{
return Open(fileInfo, Options.None);
}
/// <summary>
/// Constructor expects a filepath to an existing file.
/// </summary>
/// <param name="filePath"></param>
/// <param name="options"></param>
public static SevenZipArchive Open(string filePath, Options options)
/// <param name="readerOptions"></param>
public static SevenZipArchive Open(string filePath, ReaderOptions readerOptions = null)
{
filePath.CheckNotNullOrEmpty("filePath");
return Open(new FileInfo(filePath), options);
return Open(new FileInfo(filePath), readerOptions ?? new ReaderOptions());
}
/// <summary>
/// Constructor with a FileInfo object to an existing file.
/// </summary>
/// <param name="fileInfo"></param>
/// <param name="options"></param>
public static SevenZipArchive Open(FileInfo fileInfo, Options options)
/// <param name="readerOptions"></param>
public static SevenZipArchive Open(FileInfo fileInfo, ReaderOptions readerOptions = null)
{
fileInfo.CheckNotNull("fileInfo");
return new SevenZipArchive(fileInfo, options);
return new SevenZipArchive(fileInfo, readerOptions ?? new ReaderOptions());
}
#endif
/// <summary>
/// Takes a seekable Stream as a source
/// </summary>
/// <param name="stream"></param>
public static SevenZipArchive Open(Stream stream)
/// <param name="readerOptions"></param>
public static SevenZipArchive Open(Stream stream, ReaderOptions readerOptions = null)
{
stream.CheckNotNull("stream");
return Open(stream, Options.None);
}
/// <summary>
/// Takes a seekable Stream as a source
/// </summary>
/// <param name="stream"></param>
/// <param name="options"></param>
public static SevenZipArchive Open(Stream stream, Options options)
{
stream.CheckNotNull("stream");
return new SevenZipArchive(stream, options);
return new SevenZipArchive(stream, readerOptions ?? new ReaderOptions());
}
#if !NO_FILE
internal SevenZipArchive(FileInfo fileInfo, Options options)
: base(ArchiveType.SevenZip, fileInfo, options, null)
internal SevenZipArchive(FileInfo fileInfo, ReaderOptions readerOptions)
: base(ArchiveType.SevenZip, fileInfo, readerOptions)
{
}
protected override IEnumerable<SevenZipVolume> LoadVolumes(FileInfo file, Options options)
protected override IEnumerable<SevenZipVolume> LoadVolumes(FileInfo file)
{
if (FlagUtility.HasFlag(options, Options.KeepStreamsOpen))
{
options = (Options)FlagUtility.SetFlag(options, Options.KeepStreamsOpen, false);
}
return new SevenZipVolume(file.OpenRead(), options).AsEnumerable();
return new SevenZipVolume(file.OpenRead(), ReaderOptions).AsEnumerable();
}
public static bool IsSevenZipFile(string filePath)
@@ -108,8 +77,8 @@ namespace SharpCompress.Archive.SevenZip
}
#endif
internal SevenZipArchive(Stream stream, Options options)
: base(ArchiveType.SevenZip, stream.AsEnumerable(), options, null)
internal SevenZipArchive(Stream stream, ReaderOptions readerOptions)
: base(ArchiveType.SevenZip, stream.AsEnumerable(), readerOptions)
{
}
@@ -118,7 +87,7 @@ namespace SharpCompress.Archive.SevenZip
{
}
protected override IEnumerable<SevenZipVolume> LoadVolumes(IEnumerable<Stream> streams, Options options)
protected override IEnumerable<SevenZipVolume> LoadVolumes(IEnumerable<Stream> streams)
{
foreach (Stream s in streams)
{
@@ -126,7 +95,7 @@ namespace SharpCompress.Archive.SevenZip
{
throw new ArgumentException("Stream is not readable and seekable");
}
SevenZipVolume volume = new SevenZipVolume(s, options);
SevenZipVolume volume = new SevenZipVolume(s, ReaderOptions);
yield return volume;
}
}
@@ -138,10 +107,7 @@ namespace SharpCompress.Archive.SevenZip
for (int i = 0; i < database.Files.Count; i++)
{
var file = database.Files[i];
if (!file.IsDir)
{
yield return new SevenZipArchiveEntry(this, new SevenZipFilePart(stream, database, i, file));
}
yield return new SevenZipArchiveEntry(this, new SevenZipFilePart(stream, database, i, file, ReaderOptions.ArchiveEncoding));
}
}
@@ -152,11 +118,10 @@ namespace SharpCompress.Archive.SevenZip
stream.Position = 0;
var reader = new ArchiveReader();
reader.Open(stream);
database = reader.ReadDatabase(null);
database = reader.ReadDatabase(new PasswordProvider(ReaderOptions.Password));
}
}
public static bool IsSevenZipFile(Stream stream)
{
try
@@ -169,7 +134,7 @@ namespace SharpCompress.Archive.SevenZip
}
}
private static readonly byte[] SIGNATURE = new byte[] {(byte) '7', (byte) 'z', 0xBC, 0xAF, 0x27, 0x1C};
private static readonly byte[] SIGNATURE = {(byte)'7', (byte)'z', 0xBC, 0xAF, 0x27, 0x1C};
private static bool SignatureMatch(Stream stream)
{
@@ -180,13 +145,10 @@ namespace SharpCompress.Archive.SevenZip
protected override IReader CreateReaderForSolidExtraction()
{
return new SevenZipReader(this);
return new SevenZipReader(ReaderOptions, this);
}
public override bool IsSolid
{
get { return Entries.Where(x => !x.IsDirectory).GroupBy(x => x.FilePart.Folder).Count() > 1; }
}
public override bool IsSolid { get { return Entries.Where(x => !x.IsDirectory).GroupBy(x => x.FilePart.Folder).Count() > 1; } }
public override long TotalSize
{
@@ -204,17 +166,13 @@ namespace SharpCompress.Archive.SevenZip
private Stream currentStream;
private CFileItem currentItem;
internal SevenZipReader(SevenZipArchive archive)
: base(Options.KeepStreamsOpen, ArchiveType.SevenZip)
internal SevenZipReader(ReaderOptions readerOptions, SevenZipArchive archive)
: base(readerOptions, ArchiveType.SevenZip)
{
this.archive = archive;
}
public override SevenZipVolume Volume
{
get { return archive.Volumes.Single(); }
}
public override SevenZipVolume Volume => archive.Volumes.Single();
internal override IEnumerable<SevenZipEntry> GetEntries(Stream stream)
{
@@ -233,7 +191,7 @@ namespace SharpCompress.Archive.SevenZip
}
else
{
currentStream = archive.database.GetFolderStream(stream, currentFolder, null);
currentStream = archive.database.GetFolderStream(stream, currentFolder, new PasswordProvider(Options.Password));
}
foreach (var entry in group)
{
@@ -248,5 +206,21 @@ namespace SharpCompress.Archive.SevenZip
return CreateEntryStream(new ReadOnlySubStream(currentStream, currentItem.Size));
}
}
private class PasswordProvider : IPasswordProvider
{
private readonly string _password;
public PasswordProvider(string password)
{
_password = password;
}
public string CryptoGetTextPassword()
{
return _password;
}
}
}
}
}

View File

@@ -1,8 +1,7 @@
using System;
using System.IO;
using System.IO;
using SharpCompress.Common.SevenZip;
namespace SharpCompress.Archive.SevenZip
namespace SharpCompress.Archives.SevenZip
{
public class SevenZipArchiveEntry : SevenZipEntry, IArchiveEntry
{
@@ -16,19 +15,14 @@ namespace SharpCompress.Archive.SevenZip
{
return FilePart.GetCompressedStream();
}
public IArchive Archive { get; private set; }
public bool IsComplete
{
get { return true; }
}
public IArchive Archive { get; }
public bool IsComplete => true;
/// <summary>
/// This is a 7Zip Anti item
/// </summary>
public bool IsAnti
{
get { return FilePart.Header.IsAnti; }
}
public bool IsAnti => FilePart.Header.IsAnti;
}
}

View File

@@ -0,0 +1,445 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using SharpCompress.Common;
using SharpCompress.Common.Tar;
using SharpCompress.IO;
using SharpCompress.Readers;
using SharpCompress.Readers.Tar;
using SharpCompress.Writers;
using SharpCompress.Writers.Tar;
namespace SharpCompress.Archives.Tar
{
public static class PaxHeaders
{
public const string paxGNUSparseNumBlocks = "GNU.sparse.numblocks";
public const string paxGNUSparseOffset = "GNU.sparse.offset";
public const string paxGNUSparseNumBytes = "GNU.sparse.numbytes";
public const string paxGNUSparseMap = "GNU.sparse.map";
public const string paxGNUSparseName = "GNU.sparse.name";
public const string paxGNUSparseMajor = "GNU.sparse.major";
public const string paxGNUSparseMinor = "GNU.sparse.minor";
public const string paxGNUSparseSize = "GNU.sparse.size";
public const string paxGNUSparseRealSize = "GNU.sparse.realsize";
}
// Keywords for the PAX Extended Header
public static class PaxKeywords
{
public const string paxAtime = "atime";
public const string paxCharset = "charset";
public const string paxComment = "comment";
public const string paxCtime = "ctime";// please note that ctime is not a valid pax header.
public const string paxGid = "gid";
public const string paxGname = "gname";
public const string paxLinkpath = "linkpath";
public const string paxMtime = "mtime";
public const string paxPath = "path";
public const string paxSize = "size";
public const string paxUid = "uid";
public const string paxUname = "uname";
public const string paxXattr = "SCHILY.xattr.";
public const string paxNone = "";
}
public class TarArchive : AbstractWritableArchive<TarArchiveEntry, TarVolume>
{
#if !NO_FILE
/// <summary>
/// Constructor expects a filepath to an existing file.
/// </summary>
/// <param name="filePath"></param>
/// <param name="readerOptions"></param>
public static TarArchive Open(string filePath, ReaderOptions readerOptions = null)
{
filePath.CheckNotNullOrEmpty("filePath");
return Open(new FileInfo(filePath), readerOptions ?? new ReaderOptions());
}
/// <summary>
/// Constructor with a FileInfo object to an existing file.
/// </summary>
/// <param name="fileInfo"></param>
/// <param name="readerOptions"></param>
public static TarArchive Open(FileInfo fileInfo, ReaderOptions readerOptions = null)
{
fileInfo.CheckNotNull("fileInfo");
return new TarArchive(fileInfo, readerOptions ?? new ReaderOptions());
}
#endif
/// <summary>
/// Takes a seekable Stream as a source
/// </summary>
/// <param name="stream"></param>
/// <param name="readerOptions"></param>
public static TarArchive Open(Stream stream, ReaderOptions readerOptions = null)
{
stream.CheckNotNull("stream");
return new TarArchive(stream, readerOptions ?? new ReaderOptions());
}
#if !NO_FILE
public static bool IsTarFile(string filePath)
{
return IsTarFile(new FileInfo(filePath));
}
public static bool IsTarFile(FileInfo fileInfo)
{
if (!fileInfo.Exists)
{
return false;
}
using (Stream stream = fileInfo.OpenRead())
{
return IsTarFile(stream);
}
}
#endif
public static bool IsTarFile(Stream stream)
{
try
{
TarHeader tar = new TarHeader(new ArchiveEncoding());
tar.Read(new BinaryReader(stream));
return tar.Name.Length > 0 && Enum.IsDefined(typeof(EntryType), tar.EntryType);
}
catch
{
}
return false;
}
#if !NO_FILE
/// <summary>
/// Constructor with a FileInfo object to an existing file.
/// </summary>
/// <param name="fileInfo"></param>
/// <param name="readerOptions"></param>
internal TarArchive(FileInfo fileInfo, ReaderOptions readerOptions)
: base(ArchiveType.Tar, fileInfo, readerOptions)
{
}
protected override IEnumerable<TarVolume> LoadVolumes(FileInfo file)
{
return new TarVolume(file.OpenRead(), ReaderOptions).AsEnumerable();
}
#endif
/// <summary>
/// Takes multiple seekable Streams for a multi-part archive
/// </summary>
/// <param name="stream"></param>
/// <param name="readerOptions"></param>
internal TarArchive(Stream stream, ReaderOptions readerOptions)
: base(ArchiveType.Tar, stream, readerOptions)
{
}
internal TarArchive()
: base(ArchiveType.Tar)
{
}
protected override IEnumerable<TarVolume> LoadVolumes(IEnumerable<Stream> streams)
{
return new TarVolume(streams.First(), ReaderOptions).AsEnumerable();
}
protected override IEnumerable<TarArchiveEntry> LoadEntries(IEnumerable<TarVolume> volumes)
{
Stream stream = volumes.Single().Stream;
TarHeader previousHeader = null;
byte[] previousBytes = null;
foreach (TarHeader header in TarHeaderFactory.ReadHeader(StreamingMode.Seekable, stream, ReaderOptions.ArchiveEncoding))
{
if (header != null)
{
switch (header.EntryType)
{
case EntryType.GlobalExtendedHeader:
case EntryType.PosixExtendedHeader:
case EntryType.LongName:
{
previousHeader = header;
var entry = new TarArchiveEntry(this,
new TarFilePart(previousHeader, stream),
CompressionType.None);
using (var entryStream = entry.OpenEntryStream())
{
using (var memoryStream = new MemoryStream())
{
entryStream.TransferTo(memoryStream);
memoryStream.Position = 0;
previousBytes = memoryStream.ToArray();
}
}
continue;
}
}
if (previousHeader != null && previousHeader.EntryType == EntryType.LongName)
{
header.Name = ReaderOptions.ArchiveEncoding.Decode(previousBytes).TrimNulls();
previousHeader = null;
previousBytes = null;
}
if (previousHeader != null && previousHeader.EntryType == EntryType.PosixExtendedHeader)
{
mergePAX(header, parsePAX(previousBytes));
previousHeader = null;
previousBytes = null;
}
yield return new TarArchiveEntry(this, new TarFilePart(header, stream), CompressionType.None);
}
}
}
// parsePAX parses PAX headers.
// If an extended header (type 'x') is invalid, ErrHeader is returned
private Dictionary<string, string> parsePAX(byte[] previousBytes)
{
byte[] s = previousBytes;
// For GNU PAX sparse format 0.0 support.
// This function transforms the sparse format 0.0 headers into format 0.1
// headers since 0.0 headers were not PAX compliant.
var sparseMap = new List<string>();
var extHdrs = new Dictionary<string, string>();
while (s.Length > 0)
{
var t = parsePAXRecord(s);
string key = ReaderOptions.ArchiveEncoding.Decode(t.Item1);
string value = ReaderOptions.ArchiveEncoding.Decode(t.Item2);
byte[] residual = t.Item3;
string x = ReaderOptions.ArchiveEncoding.Decode(t.Item3);
Console.WriteLine(x);
s = residual;
switch (key) {
case PaxHeaders.paxGNUSparseOffset:
case PaxHeaders.paxGNUSparseNumBytes:
// Validate sparse header order and value.
if ((sparseMap.Count%2 == 0 && key != PaxHeaders.paxGNUSparseOffset) ||
(sparseMap.Count%2 == 1 && key != PaxHeaders.paxGNUSparseNumBytes) ||
value.Contains(","))
{
extHdrs.Clear();
return extHdrs;
}
sparseMap.Add(value);
break;
default:
// According to PAX specification, a value is stored only if it is
// non-empty. Otherwise, the key is deleted.
if (value.Length > 0)
{
extHdrs[key] = value;
} else
{
extHdrs.Remove(key);
}
break;
}
}
if (sparseMap.Count> 0)
{
extHdrs[PaxHeaders.paxGNUSparseMap] = string.Join(",", sparseMap);
}
return extHdrs;
}
// parsePAXRecord parses the input PAX record string into a key-value pair.
// If parsing is successful, it will slice off the currently read record and
// return the remainder as r.
//
// A PAX record is of the following form:
// "%d %s=%s\n" % (size, key, value)
private Tuple<byte[], byte[], byte[]> parsePAXRecord(byte[] s) {
// The size field ends at the first space.
var sp = Array.IndexOf(s, (byte)' ');
if (sp == -1)
{
return Tuple.Create(Array.Empty<byte>(), Array.Empty<byte>(), s);
}
// Parse the first token as a decimal integer.
var x = s.Take(sp).ToArray();
var n = Convert.ToInt64(ReaderOptions.ArchiveEncoding.Decode(x), 10); // Intentionally parse as native int
if (n < 5 || s.Length < n) {
return Tuple.Create(Array.Empty<byte>(), Array.Empty<byte>(), s);
}
// Extract everything between the space and the final newline.
var rec = s.Skip(sp + 1).Take((int)n -sp - 2).ToArray();
var nl = s.Skip((int)n-1).Take(1).Single();
var rem = s.Skip((int)n).ToArray();
if (nl != '\n') {
return Tuple.Create(Array.Empty<byte>(), Array.Empty<byte>(), s);
}
// The first equals separates the key from the value.
var eq = Array.IndexOf(rec, (byte)'=');
if (eq == -1) {
return Tuple.Create(Array.Empty<byte>(), Array.Empty<byte>(), s);
}
return Tuple.Create( rec.Take(eq).ToArray(), rec.Skip(eq+1).ToArray(), rem);
}
// mergePAX merges well known headers according to PAX standard.
// In general headers with the same name as those found
// in the header struct overwrite those found in the header
// struct with higher precision or longer values. Esp. useful
// for name and linkname fields.
private void mergePAX(TarHeader hdr, Dictionary<string, string> headers)
{
foreach (var kv in headers)
{
switch (kv.Key)
{
case PaxKeywords.paxPath:
hdr.Name = kv.Value;
break;
//case PaxKeywords.paxLinkpath:
//hdr.Linkname = v
//case PaxKeywords.paxUname:
//hdr.Uname = v
//case PaxKeywords.paxGname:
//hdr.Gname = v
//case PaxKeywords.paxUid:
//id64, err = strconv.ParseInt(v, 10, 64)
//hdr.Uid = int(id64) // Integer overflow possible
//case PaxKeywords.paxGid:
//id64, err = strconv.ParseInt(v, 10, 64)
//hdr.Gid = int(id64) // Integer overflow possible
//case PaxKeywords.paxAtime:
//hdr.AccessTime, err = parsePAXTime(v)
case PaxKeywords.paxMtime:
hdr.LastModifiedTime = parsePAXTime(kv.Value).DateTime;
break;
//case PaxKeywords.paxCtime:
//hdr.ChangeTime, err = parsePAXTime(v)
case PaxKeywords.paxSize:
hdr.Size = long.Parse(kv.Value);
break;
/*default:
if (kv.Key.StartsWith(PaxKeywords.paxXattr)) {
if hdr.Xattrs == nil {
hdr.Xattrs = make(map[string]string)
}
hdr.Xattrs[k[len(paxXattr):]] = v
}*/
}
}
}
// parsePAXTime takes a string of the form %d.%d as described in the PAX
// specification. Note that this implementation allows for negative timestamps,
// which is allowed for by the PAX specification, but not always portable.
private static DateTimeOffset parsePAXTime(string s)
{
//const int maxNanoSecondDigits = 9;
// Split string into seconds and sub-seconds parts.
var ss = s;
var sn = "";
var pos = s.IndexOf('.');
if (pos >= 0)
{
ss = s.Substring(0, pos);
sn = s.Substring(pos + 1);
}
// Parse the seconds.
var secs = long.Parse(ss);
// if (sn.Length == 0)
//{
return DateTimeOffset.FromUnixTimeSeconds(secs);
/*}
// Parse the nanoseconds.
if (sn.Trim("0123456789".ToCharArray()) != "") {
return DateTimeOffset.MinValue;
}
while (sn.Length < maxNanoSecondDigits)
{
sn += "0"; // Right pad
}
if (sn.Length > maxNanoSecondDigits) {
sn = sn.Substring(0, maxNanoSecondDigits); // Right truncate
}
var nsecs = long.Parse(sn); // Must succeed
if (ss.Length > 0 && ss[0] == '-')
{
return DateTimeOffset.FromUnixTimeSeconds(secs); // Negative correction
}
return time.Unix(secs, int64(nsecs)), nil*/
}
public static TarArchive Create()
{
return new TarArchive();
}
protected override TarArchiveEntry CreateEntryInternal(string filePath,
Stream source,
long size,
DateTime? modified,
bool closeStream)
{
return new TarWritableArchiveEntry(this,
source,
CompressionType.Unknown,
filePath,
size,
modified,
closeStream);
}
protected override void SaveTo(Stream stream,
WriterOptions options,
IEnumerable<TarArchiveEntry> oldEntries,
IEnumerable<TarArchiveEntry> newEntries)
{
using (var writer = new TarWriter(stream, new TarWriterOptions(options)))
{
foreach (var entry in oldEntries.Concat(newEntries)
.Where(x => !x.IsDirectory))
{
using (var entryStream = entry.OpenEntryStream())
{
writer.Write(entry.Key, entryStream, entry.LastModifiedTime, entry.Size);
}
}
}
}
protected override IReader CreateReaderForSolidExtraction()
{
var stream = Volumes.Single().Stream;
stream.Position = 0;
return TarReader.Open(stream);
}
}
}

View File

@@ -3,7 +3,7 @@ using System.Linq;
using SharpCompress.Common;
using SharpCompress.Common.Tar;
namespace SharpCompress.Archive.Tar
namespace SharpCompress.Archives.Tar
{
public class TarArchiveEntry : TarEntry, IArchiveEntry
{
@@ -19,12 +19,10 @@ namespace SharpCompress.Archive.Tar
}
#region IArchiveEntry Members
public IArchive Archive { get; private set; }
public bool IsComplete
{
get { return true; }
}
public IArchive Archive { get; }
public bool IsComplete => true;
#endregion
}

View File

@@ -0,0 +1,65 @@
using System;
using System.Collections.Generic;
using System.IO;
using SharpCompress.Common;
using SharpCompress.IO;
namespace SharpCompress.Archives.Tar
{
internal class TarWritableArchiveEntry : TarArchiveEntry, IWritableArchiveEntry
{
private readonly bool closeStream;
private readonly Stream stream;
internal TarWritableArchiveEntry(TarArchive archive, Stream stream, CompressionType compressionType,
string path, long size, DateTime? lastModified, bool closeStream)
: base(archive, null, compressionType)
{
this.stream = stream;
Key = path;
Size = size;
LastModifiedTime = lastModified;
this.closeStream = closeStream;
}
public override long Crc => 0;
public override string Key { get; }
public override long CompressedSize => 0;
public override long Size { get; }
public override DateTime? LastModifiedTime { get; }
public override DateTime? CreatedTime => null;
public override DateTime? LastAccessedTime => null;
public override DateTime? ArchivedTime => null;
public override bool IsEncrypted => false;
public override bool IsDirectory => false;
public override bool IsSplit => false;
internal override IEnumerable<FilePart> Parts => throw new NotImplementedException();
Stream IWritableArchiveEntry.Stream => stream;
public override Stream OpenEntryStream()
{
//ensure new stream is at the start, this could be reset
stream.Seek(0, SeekOrigin.Begin);
return new NonDisposingStream(stream);
}
internal override void Close()
{
if (closeStream)
{
stream.Dispose();
}
}
}
}

View File

@@ -5,12 +5,13 @@ using System.Linq;
using SharpCompress.Common;
using SharpCompress.Common.Zip;
using SharpCompress.Common.Zip.Headers;
using SharpCompress.Compressor.Deflate;
using SharpCompress.Reader;
using SharpCompress.Reader.Zip;
using SharpCompress.Writer.Zip;
using SharpCompress.Compressors.Deflate;
using SharpCompress.Readers;
using SharpCompress.Readers.Zip;
using SharpCompress.Writers;
using SharpCompress.Writers.Zip;
namespace SharpCompress.Archive.Zip
namespace SharpCompress.Archives.Zip
{
public class ZipArchive : AbstractWritableArchive<ZipArchiveEntry, ZipVolume>
{
@@ -23,48 +24,27 @@ namespace SharpCompress.Archive.Zip
public CompressionLevel DeflateCompressionLevel { get; set; }
#if !NO_FILE
/// <summary>
/// Constructor expects a filepath to an existing file.
/// </summary>
/// <param name="filePath"></param>
/// <param name="password"></param>
public static ZipArchive Open(string filePath, string password = null)
{
return Open(filePath, Options.None, password);
}
/// <summary>
/// Constructor with a FileInfo object to an existing file.
/// </summary>
/// <param name="fileInfo"></param>
/// <param name="password"></param>
public static ZipArchive Open(FileInfo fileInfo, string password = null)
{
return Open(fileInfo, Options.None, password);
}
/// <summary>
/// Constructor expects a filepath to an existing file.
/// </summary>
/// <param name="filePath"></param>
/// <param name="options"></param>
/// <param name="password"></param>
public static ZipArchive Open(string filePath, Options options, string password = null)
/// <param name="readerOptions"></param>
public static ZipArchive Open(string filePath, ReaderOptions readerOptions = null)
{
filePath.CheckNotNullOrEmpty("filePath");
return Open(new FileInfo(filePath), options, password);
return Open(new FileInfo(filePath), readerOptions ?? new ReaderOptions());
}
/// <summary>
/// Constructor with a FileInfo object to an existing file.
/// </summary>
/// <param name="fileInfo"></param>
/// <param name="options"></param>
/// <param name="password"></param>
public static ZipArchive Open(FileInfo fileInfo, Options options, string password = null)
/// <param name="readerOptions"></param>
public static ZipArchive Open(FileInfo fileInfo, ReaderOptions readerOptions = null)
{
fileInfo.CheckNotNull("fileInfo");
return new ZipArchive(fileInfo, options, password);
return new ZipArchive(fileInfo, readerOptions ?? new ReaderOptions());
}
#endif
@@ -72,26 +52,15 @@ namespace SharpCompress.Archive.Zip
/// Takes a seekable Stream as a source
/// </summary>
/// <param name="stream"></param>
/// <param name="password"></param>
public static ZipArchive Open(Stream stream, string password = null)
/// <param name="readerOptions"></param>
public static ZipArchive Open(Stream stream, ReaderOptions readerOptions = null)
{
stream.CheckNotNull("stream");
return Open(stream, Options.None, password);
}
/// <summary>
/// Takes a seekable Stream as a source
/// </summary>
/// <param name="stream"></param>
/// <param name="options"></param>
/// <param name="password"></param>
public static ZipArchive Open(Stream stream, Options options, string password = null)
{
stream.CheckNotNull("stream");
return new ZipArchive(stream, options, password);
return new ZipArchive(stream, readerOptions ?? new ReaderOptions());
}
#if !NO_FILE
public static bool IsZipFile(string filePath, string password = null)
{
return IsZipFile(new FileInfo(filePath), password);
@@ -112,7 +81,7 @@ namespace SharpCompress.Archive.Zip
public static bool IsZipFile(Stream stream, string password = null)
{
StreamingZipHeaderFactory headerFactory = new StreamingZipHeaderFactory(password);
StreamingZipHeaderFactory headerFactory = new StreamingZipHeaderFactory(password, new ArchiveEncoding());
try
{
ZipHeader header =
@@ -121,7 +90,7 @@ namespace SharpCompress.Archive.Zip
{
return false;
}
return Enum.IsDefined(typeof (ZipHeaderType), header.ZipHeaderType);
return Enum.IsDefined(typeof(ZipHeaderType), header.ZipHeaderType);
}
catch (CryptographicException)
{
@@ -134,25 +103,21 @@ namespace SharpCompress.Archive.Zip
}
#if !NO_FILE
/// <summary>
/// Constructor with a FileInfo object to an existing file.
/// </summary>
/// <param name="fileInfo"></param>
/// <param name="options"></param>
/// <param name="password"></param>
internal ZipArchive(FileInfo fileInfo, Options options, string password = null)
: base(ArchiveType.Zip, fileInfo, options)
/// <param name="readerOptions"></param>
internal ZipArchive(FileInfo fileInfo, ReaderOptions readerOptions)
: base(ArchiveType.Zip, fileInfo, readerOptions)
{
headerFactory = new SeekableZipHeaderFactory(password);
headerFactory = new SeekableZipHeaderFactory(readerOptions.Password, readerOptions.ArchiveEncoding);
}
protected override IEnumerable<ZipVolume> LoadVolumes(FileInfo file, Options options)
protected override IEnumerable<ZipVolume> LoadVolumes(FileInfo file)
{
if (FlagUtility.HasFlag(options, Options.KeepStreamsOpen))
{
options = (Options)FlagUtility.SetFlag(options, Options.KeepStreamsOpen, false);
}
return new ZipVolume(file.OpenRead(), options).AsEnumerable();
return new ZipVolume(file.OpenRead(), ReaderOptions).AsEnumerable();
}
#endif
@@ -165,17 +130,16 @@ namespace SharpCompress.Archive.Zip
/// Takes multiple seekable Streams for a multi-part archive
/// </summary>
/// <param name="stream"></param>
/// <param name="options"></param>
/// <param name="password"></param>
internal ZipArchive(Stream stream, Options options, string password = null)
: base(ArchiveType.Zip, stream, options)
/// <param name="readerOptions"></param>
internal ZipArchive(Stream stream, ReaderOptions readerOptions)
: base(ArchiveType.Zip, stream, readerOptions)
{
headerFactory = new SeekableZipHeaderFactory(password);
headerFactory = new SeekableZipHeaderFactory(readerOptions.Password, readerOptions.ArchiveEncoding);
}
protected override IEnumerable<ZipVolume> LoadVolumes(IEnumerable<Stream> streams, Options options)
protected override IEnumerable<ZipVolume> LoadVolumes(IEnumerable<Stream> streams)
{
return new ZipVolume(streams.First(), options).AsEnumerable();
return new ZipVolume(streams.First(), ReaderOptions).AsEnumerable();
}
protected override IEnumerable<ZipArchiveEntry> LoadEntries(IEnumerable<ZipVolume> volumes)
@@ -199,7 +163,7 @@ namespace SharpCompress.Archive.Zip
case ZipHeaderType.DirectoryEnd:
{
byte[] bytes = (h as DirectoryEndHeader).Comment;
volume.Comment = ArchiveEncoding.Default.GetString(bytes, 0, bytes.Length);
volume.Comment = ReaderOptions.ArchiveEncoding.Decode(bytes);
yield break;
}
}
@@ -207,25 +171,30 @@ namespace SharpCompress.Archive.Zip
}
}
protected override void SaveTo(Stream stream, CompressionInfo compressionInfo,
public void SaveTo(Stream stream)
{
SaveTo(stream, new WriterOptions(CompressionType.Deflate));
}
protected override void SaveTo(Stream stream, WriterOptions options,
IEnumerable<ZipArchiveEntry> oldEntries,
IEnumerable<ZipArchiveEntry> newEntries)
{
using (var writer = new ZipWriter(stream, compressionInfo, string.Empty))
using (var writer = new ZipWriter(stream, new ZipWriterOptions(options)))
{
foreach (var entry in oldEntries.Concat(newEntries)
.Where(x => !x.IsDirectory))
{
using (var entryStream = entry.OpenEntryStream())
{
writer.Write(entry.Key, entryStream, entry.LastModifiedTime, string.Empty);
writer.Write(entry.Key, entryStream, entry.LastModifiedTime);
}
}
}
}
protected override ZipArchiveEntry CreateEntryInternal(string filePath, Stream source, long size, DateTime? modified,
bool closeStream)
bool closeStream)
{
return new ZipWritableArchiveEntry(this, source, filePath, size, modified, closeStream);
}
@@ -239,7 +208,7 @@ namespace SharpCompress.Archive.Zip
{
var stream = Volumes.Single().Stream;
stream.Position = 0;
return ZipReader.Open(stream);
return ZipReader.Open(stream, ReaderOptions);
}
}
}

View File

@@ -2,7 +2,7 @@
using System.Linq;
using SharpCompress.Common.Zip;
namespace SharpCompress.Archive.Zip
namespace SharpCompress.Archives.Zip
{
public class ZipArchiveEntry : ZipEntry, IArchiveEntry
{
@@ -19,18 +19,12 @@ namespace SharpCompress.Archive.Zip
#region IArchiveEntry Members
public IArchive Archive { get; private set; }
public IArchive Archive { get; }
public bool IsComplete
{
get { return true; }
}
public bool IsComplete => true;
#endregion
public string Comment
{
get { return (Parts.Single() as SeekableZipFilePart).Comment; }
}
public string Comment => (Parts.Single() as SeekableZipFilePart).Comment;
}
}

View File

@@ -0,0 +1,68 @@
using System;
using System.Collections.Generic;
using System.IO;
using SharpCompress.Common;
using SharpCompress.IO;
namespace SharpCompress.Archives.Zip
{
internal class ZipWritableArchiveEntry : ZipArchiveEntry, IWritableArchiveEntry
{
private readonly bool closeStream;
private readonly Stream stream;
private bool isDisposed;
internal ZipWritableArchiveEntry(ZipArchive archive, Stream stream, string path, long size,
DateTime? lastModified, bool closeStream)
: base(archive, null)
{
this.stream = stream;
Key = path;
Size = size;
LastModifiedTime = lastModified;
this.closeStream = closeStream;
}
public override long Crc => 0;
public override string Key { get; }
public override long CompressedSize => 0;
public override long Size { get; }
public override DateTime? LastModifiedTime { get; }
public override DateTime? CreatedTime => null;
public override DateTime? LastAccessedTime => null;
public override DateTime? ArchivedTime => null;
public override bool IsEncrypted => false;
public override bool IsDirectory => false;
public override bool IsSplit => false;
internal override IEnumerable<FilePart> Parts => throw new NotImplementedException();
Stream IWritableArchiveEntry.Stream => stream;
public override Stream OpenEntryStream()
{
//ensure new stream is at the start, this could be reset
stream.Seek(0, SeekOrigin.Begin);
return new NonDisposingStream(stream);
}
internal override void Close()
{
if (closeStream && !isDisposed)
{
stream.Dispose();
isDisposed = true;
}
}
}
}

View File

@@ -2,12 +2,24 @@
using System.Reflection;
using System.Runtime.CompilerServices;
[assembly: AssemblyTitle("SharpCompress")]
[assembly: AssemblyProduct("SharpCompress")]
[assembly: InternalsVisibleTo("SharpCompress.Test")]
[assembly: InternalsVisibleTo("SharpCompress.Test.Portable")]
[assembly: InternalsVisibleTo("SharpCompress.Test" + SharpCompress.AssemblyInfo.PublicKeySuffix)]
[assembly: InternalsVisibleTo("SharpCompress.Test.Portable" + SharpCompress.AssemblyInfo.PublicKeySuffix)]
[assembly: CLSCompliant(true)]
namespace SharpCompress
{
/// <summary>
/// Just a static class to house the public key, to avoid repetition.
/// </summary>
internal static class AssemblyInfo
{
internal const string PublicKeySuffix =
",PublicKey=002400000480000094000000060200000024000052534131000400000100010059acfa17d26c44" +
"7a4d03f16eaa72c9187c04f16e6569dd168b080e39a6f5c9fd00f28c768cd8e9a089d5a0e1b34c" +
"cd971488e7afe030ce5ce8df2053cf12ec89f6d38065c434c09ee6af3ee284c5dc08f44774b679" +
"bf39298e57efe30d4b00aecf9e4f6f8448b2cb0146d8956dfcab606cc64a0ac38c60a7d78b0d65" +
"d3b98dc0";
}
}

View File

@@ -0,0 +1,119 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#if NETCORE
using System.Runtime.CompilerServices;
using System.Threading;
namespace SharpCompress.Buffers
{
/// <summary>
/// Provides a resource pool that enables reusing instances of type <see cref="T:T[]"/>.
/// </summary>
/// <remarks>
/// <para>
/// Renting and returning buffers with an <see cref="ArrayPool{T}"/> can increase performance
/// in situations where arrays are created and destroyed frequently, resulting in significant
/// memory pressure on the garbage collector.
/// </para>
/// <para>
/// This class is thread-safe. All members may be used by multiple threads concurrently.
/// </para>
/// </remarks>
internal abstract class ArrayPool<T>
{
/// <summary>The lazily-initialized shared pool instance.</summary>
private static ArrayPool<T> s_sharedInstance = null;
/// <summary>
/// Retrieves a shared <see cref="ArrayPool{T}"/> instance.
/// </summary>
/// <remarks>
/// The shared pool provides a default implementation of <see cref="ArrayPool{T}"/>
/// that's intended for general applicability. It maintains arrays of multiple sizes, and
/// may hand back a larger array than was actually requested, but will never hand back a smaller
/// array than was requested. Renting a buffer from it with <see cref="Rent"/> will result in an
/// existing buffer being taken from the pool if an appropriate buffer is available or in a new
/// buffer being allocated if one is not available.
/// </remarks>
public static ArrayPool<T> Shared
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return Volatile.Read(ref s_sharedInstance) ?? EnsureSharedCreated(); }
}
/// <summary>Ensures that <see cref="s_sharedInstance"/> has been initialized to a pool and returns it.</summary>
[MethodImpl(MethodImplOptions.NoInlining)]
private static ArrayPool<T> EnsureSharedCreated()
{
Interlocked.CompareExchange(ref s_sharedInstance, Create(), null);
return s_sharedInstance;
}
/// <summary>
/// Creates a new <see cref="ArrayPool{T}"/> instance using default configuration options.
/// </summary>
/// <returns>A new <see cref="ArrayPool{T}"/> instance.</returns>
public static ArrayPool<T> Create()
{
return new DefaultArrayPool<T>();
}
/// <summary>
/// Creates a new <see cref="ArrayPool{T}"/> instance using custom configuration options.
/// </summary>
/// <param name="maxArrayLength">The maximum length of array instances that may be stored in the pool.</param>
/// <param name="maxArraysPerBucket">
/// The maximum number of array instances that may be stored in each bucket in the pool. The pool
/// groups arrays of similar lengths into buckets for faster access.
/// </param>
/// <returns>A new <see cref="ArrayPool{T}"/> instance with the specified configuration options.</returns>
/// <remarks>
/// The created pool will group arrays into buckets, with no more than <paramref name="maxArraysPerBucket"/>
/// in each bucket and with those arrays not exceeding <paramref name="maxArrayLength"/> in length.
/// </remarks>
public static ArrayPool<T> Create(int maxArrayLength, int maxArraysPerBucket)
{
return new DefaultArrayPool<T>(maxArrayLength, maxArraysPerBucket);
}
/// <summary>
/// Retrieves a buffer that is at least the requested length.
/// </summary>
/// <param name="minimumLength">The minimum length of the array needed.</param>
/// <returns>
/// An <see cref="T:T[]"/> that is at least <paramref name="minimumLength"/> in length.
/// </returns>
/// <remarks>
/// This buffer is loaned to the caller and should be returned to the same pool via
/// <see cref="Return"/> so that it may be reused in subsequent usage of <see cref="Rent"/>.
/// It is not a fatal error to not return a rented buffer, but failure to do so may lead to
/// decreased application performance, as the pool may need to create a new buffer to replace
/// the one lost.
/// </remarks>
public abstract T[] Rent(int minimumLength);
/// <summary>
/// Returns to the pool an array that was previously obtained via <see cref="Rent"/> on the same
/// <see cref="ArrayPool{T}"/> instance.
/// </summary>
/// <param name="array">
/// The buffer previously obtained from <see cref="Rent"/> to return to the pool.
/// </param>
/// <param name="clearArray">
/// If <c>true</c> and if the pool will store the buffer to enable subsequent reuse, <see cref="Return"/>
/// will clear <paramref name="array"/> of its contents so that a subsequent consumer via <see cref="Rent"/>
/// will not see the previous consumer's content. If <c>false</c> or if the pool will release the buffer,
/// the array's contents are left unchanged.
/// </param>
/// <remarks>
/// Once a buffer has been returned to the pool, the caller gives up all ownership of the buffer
/// and must not use it. The reference returned from a given call to <see cref="Rent"/> must only be
/// returned via <see cref="Return"/> once. The default <see cref="ArrayPool{T}"/>
/// may hold onto the returned buffer in order to rent it again, or it may release the returned buffer
/// if it's determined that the pool already has enough buffers stored.
/// </remarks>
public abstract void Return(T[] array, bool clearArray = false);
}
}
#endif

View File

@@ -0,0 +1,144 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#if NETCORE
using System;
namespace SharpCompress.Buffers
{
internal sealed partial class DefaultArrayPool<T> : ArrayPool<T>
{
/// <summary>The default maximum length of each array in the pool (2^20).</summary>
private const int DefaultMaxArrayLength = 1024 * 1024;
/// <summary>The default maximum number of arrays per bucket that are available for rent.</summary>
private const int DefaultMaxNumberOfArraysPerBucket = 50;
/// <summary>Lazily-allocated empty array used when arrays of length 0 are requested.</summary>
private static T[] s_emptyArray; // we support contracts earlier than those with Array.Empty<T>()
private readonly Bucket[] _buckets;
internal DefaultArrayPool() : this(DefaultMaxArrayLength, DefaultMaxNumberOfArraysPerBucket)
{
}
internal DefaultArrayPool(int maxArrayLength, int maxArraysPerBucket)
{
if (maxArrayLength <= 0)
{
throw new ArgumentOutOfRangeException(nameof(maxArrayLength));
}
if (maxArraysPerBucket <= 0)
{
throw new ArgumentOutOfRangeException(nameof(maxArraysPerBucket));
}
// Our bucketing algorithm has a min length of 2^4 and a max length of 2^30.
// Constrain the actual max used to those values.
const int MinimumArrayLength = 0x10, MaximumArrayLength = 0x40000000;
if (maxArrayLength > MaximumArrayLength)
{
maxArrayLength = MaximumArrayLength;
}
else if (maxArrayLength < MinimumArrayLength)
{
maxArrayLength = MinimumArrayLength;
}
// Create the buckets.
int poolId = Id;
int maxBuckets = Utilities.SelectBucketIndex(maxArrayLength);
var buckets = new Bucket[maxBuckets + 1];
for (int i = 0; i < buckets.Length; i++)
{
buckets[i] = new Bucket(Utilities.GetMaxSizeForBucket(i), maxArraysPerBucket, poolId);
}
_buckets = buckets;
}
/// <summary>Gets an ID for the pool to use with events.</summary>
private int Id => GetHashCode();
public override T[] Rent(int minimumLength)
{
// Arrays can't be smaller than zero. We allow requesting zero-length arrays (even though
// pooling such an array isn't valuable) as it's a valid length array, and we want the pool
// to be usable in general instead of using `new`, even for computed lengths.
if (minimumLength < 0)
{
throw new ArgumentOutOfRangeException(nameof(minimumLength));
}
else if (minimumLength == 0)
{
// No need for events with the empty array. Our pool is effectively infinite
// and we'll never allocate for rents and never store for returns.
return s_emptyArray ?? (s_emptyArray = new T[0]);
}
T[] buffer = null;
int index = Utilities.SelectBucketIndex(minimumLength);
if (index < _buckets.Length)
{
// Search for an array starting at the 'index' bucket. If the bucket is empty, bump up to the
// next higher bucket and try that one, but only try at most a few buckets.
const int MaxBucketsToTry = 2;
int i = index;
do
{
// Attempt to rent from the bucket. If we get a buffer from it, return it.
buffer = _buckets[i].Rent();
if (buffer != null)
{
return buffer;
}
}
while (++i < _buckets.Length && i != index + MaxBucketsToTry);
// The pool was exhausted for this buffer size. Allocate a new buffer with a size corresponding
// to the appropriate bucket.
buffer = new T[_buckets[index]._bufferLength];
}
else
{
// The request was for a size too large for the pool. Allocate an array of exactly the requested length.
// When it's returned to the pool, we'll simply throw it away.
buffer = new T[minimumLength];
}
return buffer;
}
public override void Return(T[] array, bool clearArray = false)
{
if (array == null)
{
throw new ArgumentNullException(nameof(array));
}
else if (array.Length == 0)
{
// Ignore empty arrays. When a zero-length array is rented, we return a singleton
// rather than actually taking a buffer out of the lowest bucket.
return;
}
// Determine with what bucket this array length is associated
int bucket = Utilities.SelectBucketIndex(array.Length);
// If we can tell that the buffer was allocated, drop it. Otherwise, check if we have space in the pool
if (bucket < _buckets.Length)
{
// Clear the array if the user requests
if (clearArray)
{
Array.Clear(array, 0, array.Length);
}
// Return the buffer to its bucket. In the future, we might consider having Return return false
// instead of dropping a bucket, in which case we could try to return to a lower-sized bucket,
// just as how in Rent we allow renting from a higher-sized bucket.
_buckets[bucket].Return(array);
}
}
}
}
#endif

View File

@@ -0,0 +1,111 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#if NETCORE
using System;
using System.Diagnostics;
using System.Threading;
namespace SharpCompress.Buffers
{
internal sealed partial class DefaultArrayPool<T> : ArrayPool<T>
{
/// <summary>Provides a thread-safe bucket containing buffers that can be Rent'd and Return'd.</summary>
private sealed class Bucket
{
internal readonly int _bufferLength;
private readonly T[][] _buffers;
private readonly int _poolId;
private SpinLock _lock; // do not make this readonly; it's a mutable struct
private int _index;
/// <summary>
/// Creates the pool with numberOfBuffers arrays where each buffer is of bufferLength length.
/// </summary>
internal Bucket(int bufferLength, int numberOfBuffers, int poolId)
{
_lock = new SpinLock(Debugger.IsAttached); // only enable thread tracking if debugger is attached; it adds non-trivial overheads to Enter/Exit
_buffers = new T[numberOfBuffers][];
_bufferLength = bufferLength;
_poolId = poolId;
}
/// <summary>Gets an ID for the bucket to use with events.</summary>
internal int Id => GetHashCode();
/// <summary>Takes an array from the bucket. If the bucket is empty, returns null.</summary>
internal T[] Rent()
{
T[][] buffers = _buffers;
T[] buffer = null;
// While holding the lock, grab whatever is at the next available index and
// update the index. We do as little work as possible while holding the spin
// lock to minimize contention with other threads. The try/finally is
// necessary to properly handle thread aborts on platforms which have them.
bool lockTaken = false, allocateBuffer = false;
try
{
_lock.Enter(ref lockTaken);
if (_index < buffers.Length)
{
buffer = buffers[_index];
buffers[_index++] = null;
allocateBuffer = buffer == null;
}
}
finally
{
if (lockTaken) _lock.Exit(false);
}
// While we were holding the lock, we grabbed whatever was at the next available index, if
// there was one. If we tried and if we got back null, that means we hadn't yet allocated
// for that slot, in which case we should do so now.
if (allocateBuffer)
{
buffer = new T[_bufferLength];
}
return buffer;
}
/// <summary>
/// Attempts to return the buffer to the bucket. If successful, the buffer will be stored
/// in the bucket and true will be returned; otherwise, the buffer won't be stored, and false
/// will be returned.
/// </summary>
internal void Return(T[] array)
{
// Check to see if the buffer is the correct size for this bucket
if (array.Length != _bufferLength)
{
throw new ArgumentException("Buffer not from pool", nameof(array));
}
// While holding the spin lock, if there's room available in the bucket,
// put the buffer into the next available slot. Otherwise, we just drop it.
// The try/finally is necessary to properly handle thread aborts on platforms
// which have them.
bool lockTaken = false;
try
{
_lock.Enter(ref lockTaken);
if (_index != 0)
{
_buffers[--_index] = array;
}
}
finally
{
if (lockTaken) _lock.Exit(false);
}
}
}
}
}
#endif

View File

@@ -0,0 +1,38 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#if NETCORE
using System.Diagnostics;
using System.Runtime.CompilerServices;
namespace SharpCompress.Buffers
{
internal static class Utilities
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static int SelectBucketIndex(int bufferSize)
{
Debug.Assert(bufferSize > 0);
uint bitsRemaining = ((uint)bufferSize - 1) >> 4;
int poolIndex = 0;
if (bitsRemaining > 0xFFFF) { bitsRemaining >>= 16; poolIndex = 16; }
if (bitsRemaining > 0xFF) { bitsRemaining >>= 8; poolIndex += 8; }
if (bitsRemaining > 0xF) { bitsRemaining >>= 4; poolIndex += 4; }
if (bitsRemaining > 0x3) { bitsRemaining >>= 2; poolIndex += 2; }
if (bitsRemaining > 0x1) { bitsRemaining >>= 1; poolIndex += 1; }
return poolIndex + (int)bitsRemaining;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static int GetMaxSizeForBucket(int binIndex)
{
int maxSize = 16 << binIndex;
Debug.Assert(maxSize >= 0);
return maxSize;
}
}
}
#endif

View File

@@ -1,23 +1,60 @@
using System.Text;
using System;
using System.Text;
namespace SharpCompress.Common
{
public static class ArchiveEncoding
public class ArchiveEncoding
{
/// <summary>
/// Default encoding to use when archive format doesn't specify one.
/// </summary>
public static Encoding Default { get; set; }
public Encoding Default { get; set; }
/// <summary>
/// Encoding used by encryption schemes which don't comply with RFC 2898.
/// ArchiveEncoding used by encryption schemes which don't comply with RFC 2898.
/// </summary>
public static Encoding Password { get; set; }
public Encoding Password { get; set; }
static ArchiveEncoding()
/// <summary>
/// Set this encoding when you want to force it for all encoding operations.
/// </summary>
public Encoding Forced { get; set; }
/// <summary>
/// Set this when you want to use a custom method for all decoding operations.
/// </summary>
/// <returns>string Func(bytes, index, length)</returns>
public Func<byte[], int, int, string> CustomDecoder { get; set; }
public ArchiveEncoding()
{
Default = Encoding.UTF8;
Password = Encoding.UTF8;
}
public string Decode(byte[] bytes)
{
return Decode(bytes, 0, bytes.Length);
}
public string Decode(byte[] bytes, int start, int length)
{
return GetDecoder().Invoke(bytes, start, length);
}
public byte[] Encode(string str)
{
return GetEncoding().GetBytes(str);
}
public Encoding GetEncoding()
{
return Forced ?? Default ?? Encoding.UTF8;
}
public Func<byte[], int, int, string> GetDecoder()
{
return CustomDecoder ?? ((bytes, index, count) => (Default ?? Encoding.UTF8).GetString(bytes, index, count));
}
}
}

View File

@@ -9,6 +9,6 @@ namespace SharpCompress.Common
Item = entry;
}
public T Item { get; private set; }
public T Item { get; }
}
}

View File

@@ -6,6 +6,6 @@
Zip,
Tar,
SevenZip,
GZip,
GZip
}
}

View File

@@ -1,30 +0,0 @@
using SharpCompress.Compressor.Deflate;
namespace SharpCompress.Common
{
/// <summary>
/// Detailed compression properties when saving.
/// </summary>
public class CompressionInfo
{
public CompressionInfo()
{
DeflateCompressionLevel = CompressionLevel.Default;
}
/// <summary>
/// The algorthm to use. Must be valid for the format type.
/// </summary>
public CompressionType Type { get; set; }
/// <summary>
/// When CompressionType.Deflate is used, this property is referenced. Defaults to CompressionLevel.Default.
/// </summary>
public CompressionLevel DeflateCompressionLevel { get; set; }
public static implicit operator CompressionInfo(CompressionType compressionType)
{
return new CompressionInfo() {Type = compressionType};
}
}
}

View File

@@ -11,6 +11,8 @@
LZMA,
BCJ,
BCJ2,
Unknown,
LZip,
Xz,
Unknown
}
}

View File

@@ -70,16 +70,11 @@ namespace SharpCompress.Common
internal virtual void Close()
{
}
/// <summary>
/// Entry file attribute.
/// </summary>
public virtual int? Attrib
{
get { throw new NotImplementedException(); }
}
public virtual int? Attrib => throw new NotImplementedException();
}
}

View File

@@ -1,19 +1,19 @@
using System;
using System.IO;
using SharpCompress.Reader;
using SharpCompress.Readers;
namespace SharpCompress.Common
{
public class EntryStream : Stream
{
public IReader Reader { get; private set; }
private Stream stream;
public IReader Reader { get; }
private readonly Stream stream;
private bool completed;
private bool isDisposed;
internal EntryStream(IReader reader, Stream stream)
{
this.Reader = reader;
Reader = reader;
this.stream = stream;
}
@@ -44,36 +44,20 @@ namespace SharpCompress.Common
stream.Dispose();
}
public override bool CanRead
{
get { return true; }
}
public override bool CanRead => true;
public override bool CanSeek
{
get { return false; }
}
public override bool CanSeek => false;
public override bool CanWrite
{
get { return false; }
}
public override bool CanWrite => false;
public override void Flush()
{
throw new NotSupportedException();
}
public override long Length
{
get { throw new NotSupportedException(); }
}
public override long Length => throw new NotSupportedException();
public override long Position
{
get { throw new NotSupportedException(); }
set { throw new NotSupportedException(); }
}
public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); }
public override int Read(byte[] buffer, int offset, int count)
{

View File

@@ -4,9 +4,17 @@ namespace SharpCompress.Common
{
public abstract class FilePart
{
protected FilePart(ArchiveEncoding archiveEncoding)
{
ArchiveEncoding = archiveEncoding;
}
internal ArchiveEncoding ArchiveEncoding { get; }
internal abstract string FilePartName { get; }
internal abstract Stream GetCompressedStream();
internal abstract Stream GetRawStream();
internal bool Skipped { get; set; }
}
}

View File

@@ -48,7 +48,7 @@ namespace SharpCompress.Common
{
return ((bitField & flag) == flag);
}
/// <summary>
/// Returns true if the flag is set on the specified bit field.
/// Currently only works with 32-bit bitfields.
@@ -75,7 +75,6 @@ namespace SharpCompress.Common
return ((bitField & flag) == flag);
}
/// <summary>
/// Sets a bit-field to either on or off for the specified flag.
/// </summary>
@@ -83,9 +82,9 @@ namespace SharpCompress.Common
/// <param name="flag">Flag to change</param>
/// <param name="on">bool</param>
/// <returns>The flagged variable with the flag changed</returns>
public static long SetFlag(long bitField, long flag, bool @on)
public static long SetFlag(long bitField, long flag, bool on)
{
if (@on)
if (on)
{
return bitField | flag;
}
@@ -100,10 +99,10 @@ namespace SharpCompress.Common
/// <param name="flag">Flag to change</param>
/// <param name="on">bool</param>
/// <returns>The flagged variable with the flag changed</returns>
public static long SetFlag<T>(T bitField, T flag, bool @on)
public static long SetFlag<T>(T bitField, T flag, bool on)
where T : struct
{
return SetFlag(Convert.ToInt64(bitField), Convert.ToInt64(flag), @on);
return SetFlag(Convert.ToInt64(bitField), Convert.ToInt64(flag), on);
}
}
}

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace SharpCompress.Common.GZip
{
@@ -13,74 +14,35 @@ namespace SharpCompress.Common.GZip
this.filePart = filePart;
}
public override CompressionType CompressionType
{
get { return CompressionType.GZip; }
}
public override CompressionType CompressionType => CompressionType.GZip;
public override long Crc
{
get { return 0; }
}
public override long Crc => 0;
public override string Key
{
get { return filePart.FilePartName; }
}
public override string Key => filePart.FilePartName;
public override long CompressedSize
{
get { return 0; }
}
public override long CompressedSize => 0;
public override long Size
{
get { return 0; }
}
public override long Size => 0;
public override DateTime? LastModifiedTime
{
get { return filePart.DateModified; }
}
public override DateTime? LastModifiedTime => filePart.DateModified;
public override DateTime? CreatedTime
{
get { return null; }
}
public override DateTime? CreatedTime => null;
public override DateTime? LastAccessedTime
{
get { return null; }
}
public override DateTime? LastAccessedTime => null;
public override DateTime? ArchivedTime
{
get { return null; }
}
public override DateTime? ArchivedTime => null;
public override bool IsEncrypted
{
get { return false; }
}
public override bool IsEncrypted => false;
public override bool IsDirectory
{
get { return false; }
}
public override bool IsDirectory => false;
public override bool IsSplit
{
get { return false; }
}
public override bool IsSplit => false;
internal override IEnumerable<FilePart> Parts
{
get { return filePart.AsEnumerable<FilePart>(); }
}
internal override IEnumerable<FilePart> Parts => filePart.AsEnumerable<FilePart>();
internal static IEnumerable<GZipEntry> GetEntries(Stream stream)
internal static IEnumerable<GZipEntry> GetEntries(Stream stream, OptionsBase options)
{
yield return new GZipEntry(new GZipFilePart(stream));
yield return new GZipEntry(new GZipFilePart(stream, options.ArchiveEncoding));
}
}
}

View File

@@ -1,38 +1,41 @@
using System;
using System.Collections.Generic;
using System.IO;
using SharpCompress.Common.Tar.Headers;
using SharpCompress.Compressor;
using SharpCompress.Compressor.Deflate;
using SharpCompress.Converter;
using SharpCompress.Compressors;
using SharpCompress.Compressors.Deflate;
using SharpCompress.Converters;
using System.Text;
using SharpCompress.Common.Tar;
namespace SharpCompress.Common.GZip
{
internal class GZipFilePart : FilePart
{
private string name;
private readonly Stream stream;
private string _name;
private readonly Stream _stream;
internal GZipFilePart(Stream stream)
internal GZipFilePart(Stream stream, ArchiveEncoding archiveEncoding)
: base(archiveEncoding)
{
ReadAndValidateGzipHeader(stream);
this.stream = stream;
EntryStartPosition = stream.Position;
this._stream = stream;
}
internal long EntryStartPosition { get; }
internal DateTime? DateModified { get; private set; }
internal override string FilePartName
{
get { return name; }
}
internal override string FilePartName => _name;
internal override Stream GetCompressedStream()
{
return new DeflateStream(stream, CompressionMode.Decompress, CompressionLevel.Default, false);
return new DeflateStream(_stream, CompressionMode.Decompress, CompressionLevel.Default, false);
}
internal override Stream GetRawStream()
{
return stream;
return _stream;
}
private void ReadAndValidateGzipHeader(Stream stream)
@@ -43,13 +46,19 @@ namespace SharpCompress.Common.GZip
// workitem 8501: handle edge case (decompress empty stream)
if (n == 0)
{
return;
}
if (n != 10)
{
throw new ZlibException("Not a valid GZIP stream.");
}
if (header[0] != 0x1F || header[1] != 0x8B || header[2] != 8)
{
throw new ZlibException("Bad GZIP header.");
}
Int32 timet = DataConverter.LittleEndian.GetInt32(header, 4);
DateModified = TarHeader.Epoch.AddSeconds(timet);
@@ -58,27 +67,33 @@ namespace SharpCompress.Common.GZip
// read and discard extra field
n = stream.Read(header, 0, 2); // 2-byte length field
Int16 extraLength = (Int16) (header[0] + header[1]*256);
Int16 extraLength = (Int16)(header[0] + header[1] * 256);
byte[] extra = new byte[extraLength];
n = stream.Read(extra, 0, extra.Length);
if (n != extraLength)
if (!stream.ReadFully(extra))
{
throw new ZlibException("Unexpected end-of-file reading GZIP header.");
}
n = extraLength;
}
if ((header[3] & 0x08) == 0x08)
name = ReadZeroTerminatedString(stream);
{
_name = ReadZeroTerminatedString(stream);
}
if ((header[3] & 0x10) == 0x010)
{
ReadZeroTerminatedString(stream);
}
if ((header[3] & 0x02) == 0x02)
{
stream.ReadByte(); // CRC16, ignore
}
}
private static string ReadZeroTerminatedString(Stream stream)
private string ReadZeroTerminatedString(Stream stream)
{
byte[] buf1 = new byte[1];
var list = new System.Collections.Generic.List<byte>();
var list = new List<byte>();
bool done = false;
do
{
@@ -96,9 +111,10 @@ namespace SharpCompress.Common.GZip
{
list.Add(buf1[0]);
}
} while (!done);
byte[] a = list.ToArray();
return ArchiveEncoding.Default.GetString(a, 0, a.Length);
}
while (!done);
byte[] buffer = list.ToArray();
return ArchiveEncoding.Decode(buffer);
}
}
}

View File

@@ -1,29 +1,25 @@
using System.IO;
using SharpCompress.Readers;
namespace SharpCompress.Common.GZip
{
public class GZipVolume : Volume
{
public GZipVolume(Stream stream, Options options)
public GZipVolume(Stream stream, ReaderOptions options)
: base(stream, options)
{
}
#if !NO_FILE
public GZipVolume(FileInfo fileInfo, Options options)
public GZipVolume(FileInfo fileInfo, ReaderOptions options)
: base(fileInfo.OpenRead(), options)
{
options.LeaveStreamOpen = false;
}
#endif
public override bool IsFirstVolume
{
get { return true; }
}
public override bool IsFirstVolume => true;
public override bool IsMultiVolume
{
get { return true; }
}
public override bool IsMultiVolume => true;
}
}

View File

@@ -1,14 +1,16 @@
#if !NO_FILE
#if !NO_FILE
using System.IO;
using SharpCompress.Readers;
namespace SharpCompress.Common
{
internal static class IEntryExtensions
{
internal static void PreserveExtractionOptions(this IEntry entry, string destinationFileName,
ExtractOptions options)
ExtractionOptions options)
{
if (options.HasFlag(ExtractOptions.PreserveFileTime) || options.HasFlag(ExtractOptions.PreserveAttributes))
if (options.PreserveFileTime || options.PreserveAttributes)
{
FileInfo nf = new FileInfo(destinationFileName);
if (!nf.Exists)
@@ -17,7 +19,7 @@ namespace SharpCompress.Common
}
// update file time to original packed time
if (options.HasFlag(ExtractOptions.PreserveFileTime))
if (options.PreserveFileTime)
{
if (entry.CreatedTime.HasValue)
{
@@ -35,7 +37,7 @@ namespace SharpCompress.Common
}
}
if (options.HasFlag(ExtractOptions.PreserveAttributes))
if (options.PreserveAttributes)
{
if (entry.Attrib.HasValue)
{
@@ -46,4 +48,4 @@ namespace SharpCompress.Common
}
}
}
#endif
#endif

View File

@@ -1,4 +1,5 @@
using System;
#if !NO_FILE
using System.IO;
#endif

View File

@@ -1,23 +0,0 @@
using System;
namespace SharpCompress.Common
{
[Flags]
public enum Options
{
/// <summary>
/// No options specified
/// </summary>
None = 0,
/// <summary>
/// SharpCompress will keep the supplied streams open
/// </summary>
KeepStreamsOpen = 1,
/// <summary>
/// Look for RarArchive (Check for self-extracting archives or cases where RarArchive isn't at the start of the file)
/// </summary>
LookForHeader = 2,
}
}

View File

@@ -0,0 +1,13 @@
namespace SharpCompress.Common
{
public class OptionsBase
{
/// <summary>
/// SharpCompress will keep the supplied streams open. Default is true.
/// </summary>
public bool LeaveStreamOpen { get; set; } = true;
public ArchiveEncoding ArchiveEncoding { get; set; } = new ArchiveEncoding();
}
}

View File

@@ -17,10 +17,7 @@ namespace SharpCompress.Common.Rar.Headers
}
}
internal ArchiveFlags ArchiveHeaderFlags
{
get { return (ArchiveFlags) base.Flags; }
}
internal ArchiveFlags ArchiveHeaderFlags => (ArchiveFlags)Flags;
internal short HighPosAv { get; private set; }
@@ -28,9 +25,6 @@ namespace SharpCompress.Common.Rar.Headers
internal byte EncryptionVersion { get; private set; }
public bool HasPassword
{
get { return ArchiveHeaderFlags.HasFlag(ArchiveFlags.PASSWORD); }
}
public bool HasPassword => ArchiveHeaderFlags.HasFlag(ArchiveFlags.PASSWORD);
}
}

View File

@@ -16,10 +16,7 @@ namespace SharpCompress.Common.Rar.Headers
}
}
internal EndArchiveFlags EndArchiveFlags
{
get { return (EndArchiveFlags) base.Flags; }
}
internal EndArchiveFlags EndArchiveFlags => (EndArchiveFlags)Flags;
internal int? ArchiveCRC { get; private set; }

View File

@@ -1,6 +1,6 @@
using SharpCompress.IO;
using System;
using System.IO;
using SharpCompress.IO;
namespace SharpCompress.Common.Rar.Headers
{
@@ -68,12 +68,12 @@ namespace SharpCompress.Common.Rar.Headers
}
else
{
FileName = DecodeDefault(fileNameBytes);
FileName = ArchiveEncoding.Decode(fileNameBytes);
}
}
else
{
FileName = DecodeDefault(fileNameBytes);
FileName = ArchiveEncoding.Decode(fileNameBytes);
}
FileName = ConvertPath(FileName, HostOS);
}
@@ -118,12 +118,6 @@ namespace SharpCompress.Common.Rar.Headers
}
}
//only the full .net framework will do other code pages than unicode/utf8
private string DecodeDefault(byte[] bytes)
{
return ArchiveEncoding.Default.GetString(bytes, 0, bytes.Length);
}
private long UInt32To64(uint x, uint y)
{
long l = x;
@@ -155,6 +149,7 @@ namespace SharpCompress.Common.Rar.Headers
byte b = reader.ReadByte();
nanosecondHundreds |= (((uint)b) << ((j + 3 - count) * 8));
}
//10^-7 to 10^-3
return time.Value.AddMilliseconds(nanosecondHundreds * Math.Pow(10, -4));
}
@@ -164,31 +159,20 @@ namespace SharpCompress.Common.Rar.Headers
#if NO_FILE
return path.Replace('\\', '/');
#else
switch (os)
if (Path.DirectorySeparatorChar == '/')
{
case HostOS.MacOS:
case HostOS.Unix:
{
if (Path.DirectorySeparatorChar == '\\')
{
return path.Replace('/', '\\');
}
}
break;
default:
{
if (Path.DirectorySeparatorChar == '/')
{
return path.Replace('\\', '/');
}
}
break;
return path.Replace('\\', '/');
}
else if (Path.DirectorySeparatorChar == '\\')
{
return path.Replace('/', '\\');
}
return path;
#endif
}
internal long DataStartPosition { get; set; }
internal HostOS HostOS { get; private set; }
internal uint FileCRC { get; private set; }
@@ -207,12 +191,10 @@ namespace SharpCompress.Common.Rar.Headers
internal int FileAttributes { get; private set; }
internal FileFlags FileFlags
{
get { return (FileFlags)base.Flags; }
}
internal FileFlags FileFlags => (FileFlags)Flags;
internal long CompressedSize { get; private set; }
internal long UncompressedSize { get; private set; }
internal string FileName { get; private set; }

View File

@@ -32,19 +32,19 @@ namespace SharpCompress.Common.Rar.Headers
switch (flags >> 6)
{
case 0:
buf.Append((char) (GetChar(name, encPos++)));
buf.Append((char)(GetChar(name, encPos++)));
++decPos;
break;
case 1:
buf.Append((char) (GetChar(name, encPos++) + (highByte << 8)));
buf.Append((char)(GetChar(name, encPos++) + (highByte << 8)));
++decPos;
break;
case 2:
low = GetChar(name, encPos);
high = GetChar(name, encPos + 1);
buf.Append((char) ((high << 8) + low));
buf.Append((char)((high << 8) + low));
++decPos;
encPos += 2;
break;
@@ -57,14 +57,14 @@ namespace SharpCompress.Common.Rar.Headers
for (length = (length & 0x7f) + 2; length > 0 && decPos < name.Length; length--, decPos++)
{
low = (GetChar(name, decPos) + correction) & 0xff;
buf.Append((char) ((highByte << 8) + low));
buf.Append((char)((highByte << 8) + low));
}
}
else
{
for (length += 2; length > 0 && decPos < name.Length; length--, decPos++)
{
buf.Append((char) (GetChar(name, decPos)));
buf.Append((char)(GetChar(name, decPos)));
}
}
break;

View File

@@ -13,12 +13,12 @@ namespace SharpCompress.Common.Rar.Headers
ProtectHeader = 0x78,
SignHeader = 0x79,
NewSubHeader = 0x7a,
EndArchiveHeader = 0x7b,
EndArchiveHeader = 0x7b
}
internal enum HeaderFlags : short
{
LONG_BLOCK = -0x8000,
LONG_BLOCK = -0x8000
}
[Flags]
@@ -33,7 +33,7 @@ namespace SharpCompress.Common.Rar.Headers
PROTECT = 0x0040,
PASSWORD = 0x0080,
FIRSTVOLUME = 0x0100,
ENCRYPTVER = 0x0200,
ENCRYPTVER = 0x0200
}
internal enum HostOS
@@ -70,16 +70,15 @@ namespace SharpCompress.Common.Rar.Headers
SALT = 0x0400,
VERSION = 0x0800,
EXTTIME = 0x1000,
EXTFLAGS = 0x2000,
EXTFLAGS = 0x2000
}
[Flags]
internal enum EndArchiveFlags
{
EARC_NEXT_VOLUME = 0x0001,
EARC_DATACRC = 0x0002,
EARC_REVSPACE = 0x0004,
EARC_VOLNUMBER = 0x0008,
EARC_VOLNUMBER = 0x0008
}
}

View File

@@ -18,9 +18,9 @@ namespace SharpCompress.Common.Rar.Headers
Flags == 0x1A21 &&
HeaderSize == 0x07;
// Rar5 signature: 52 61 72 21 1A 07 10 00 (not supported yet)
// Rar5 signature: 52 61 72 21 1A 07 01 00 (not supported yet)
}
internal bool OldFormat { get; private set; }
}
}
}

View File

@@ -20,14 +20,14 @@ namespace SharpCompress.Common.Rar.Headers
//internal static final NewSubHeaderType SUBHEAD_TYPE_BEOSEA = new NewSubHeaderType(new byte[]{'E','A','B','E'});
private byte[] bytes;
private readonly byte[] bytes;
private NewSubHeaderType(params char[] chars)
{
bytes = new byte[chars.Length];
for (int i = 0; i < chars.Length; ++i)
{
bytes[i] = (byte) chars[i];
bytes[i] = (byte)chars[i];
}
}

View File

@@ -13,10 +13,10 @@ namespace SharpCompress.Common.Rar.Headers
Mark = reader.ReadBytes(8);
}
internal uint DataSize { get { return AdditionalSize; } }
internal uint DataSize => AdditionalSize;
internal byte Version { get; private set; }
internal ushort RecSectors { get; private set; }
internal uint TotalBlocks { get; private set; }
internal byte[] Mark { get; private set; }
}
}
}

View File

@@ -1,5 +1,7 @@
using System.IO;
using System;
using System.IO;
using SharpCompress.IO;
using System.Text;
namespace SharpCompress.Common.Rar.Headers
{
@@ -16,16 +18,18 @@ namespace SharpCompress.Common.Rar.Headers
HeaderSize = baseHeader.HeaderSize;
AdditionalSize = baseHeader.AdditionalSize;
ReadBytes = baseHeader.ReadBytes;
ArchiveEncoding = baseHeader.ArchiveEncoding;
}
internal static RarHeader Create(MarkingBinaryReader reader)
internal static RarHeader Create(RarCrcBinaryReader reader, ArchiveEncoding archiveEncoding)
{
try
{
RarHeader header = new RarHeader();
header.ArchiveEncoding = archiveEncoding;
reader.Mark();
header.ReadFromReader(reader);
header.ReadStartFromReader(reader);
header.ReadBytes += reader.CurrentReadByteCount;
return header;
@@ -35,9 +39,11 @@ namespace SharpCompress.Common.Rar.Headers
return null;
}
}
protected virtual void ReadFromReader(MarkingBinaryReader reader)
private void ReadStartFromReader(RarCrcBinaryReader reader)
{
HeadCRC = reader.ReadInt16();
HeadCRC = reader.ReadUInt16();
reader.ResetCrc();
HeaderType = (HeaderType)(reader.ReadByte() & 0xff);
Flags = reader.ReadInt16();
HeaderSize = reader.ReadInt16();
@@ -47,7 +53,12 @@ namespace SharpCompress.Common.Rar.Headers
}
}
internal T PromoteHeader<T>(MarkingBinaryReader reader)
protected virtual void ReadFromReader(MarkingBinaryReader reader)
{
throw new NotImplementedException();
}
internal T PromoteHeader<T>(RarCrcBinaryReader reader)
where T : RarHeader, new()
{
T header = new T();
@@ -64,9 +75,22 @@ namespace SharpCompress.Common.Rar.Headers
reader.ReadBytes(headerSizeDiff);
}
VerifyHeaderCrc(reader.GetCrc());
return header;
}
private void VerifyHeaderCrc(ushort crc)
{
if (HeaderType != HeaderType.MarkHeader)
{
if (crc != HeadCRC)
{
throw new InvalidFormatException("rar header crc mismatch");
}
}
}
protected virtual void PostReadingBytes(MarkingBinaryReader reader)
{
}
@@ -76,7 +100,7 @@ namespace SharpCompress.Common.Rar.Headers
/// </summary>
protected long ReadBytes { get; private set; }
protected short HeadCRC { get; private set; }
protected ushort HeadCRC { get; private set; }
internal HeaderType HeaderType { get; private set; }
@@ -87,6 +111,8 @@ namespace SharpCompress.Common.Rar.Headers
protected short HeaderSize { get; private set; }
internal ArchiveEncoding ArchiveEncoding { get; private set; }
/// <summary>
/// This additional size of the header could be file data
/// </summary>

View File

@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using SharpCompress.IO;
using SharpCompress.Readers;
namespace SharpCompress.Common.Rar.Headers
{
@@ -9,21 +10,19 @@ namespace SharpCompress.Common.Rar.Headers
{
private const int MAX_SFX_SIZE = 0x80000 - 16; //archive.cpp line 136
internal RarHeaderFactory(StreamingMode mode, Options options, string password = null)
internal RarHeaderFactory(StreamingMode mode, ReaderOptions options)
{
StreamingMode = mode;
Options = options;
Password = password;
}
private Options Options { get; set; }
public string Password { get; private set; }
internal StreamingMode StreamingMode { get; private set; }
private ReaderOptions Options { get; }
internal StreamingMode StreamingMode { get; }
internal bool IsEncrypted { get; private set; }
internal IEnumerable<RarHeader> ReadHeaders(Stream stream)
{
if (Options.HasFlag(Options.LookForHeader))
if (Options.LookForHeader)
{
stream = CheckSFX(stream);
}
@@ -91,7 +90,7 @@ namespace SharpCompress.Common.Rar.Headers
}
catch (Exception e)
{
if (!Options.HasFlag(Options.KeepStreamsOpen))
if (!Options.LeaveStreamOpen)
{
#if NET35
reader.Close();
@@ -114,15 +113,14 @@ namespace SharpCompress.Common.Rar.Headers
return rewindableStream;
}
private RarHeader ReadNextHeader(Stream stream)
{
#if !NO_CRYPTO
var reader = new RarCryptoBinaryReader(stream, Password);
var reader = new RarCryptoBinaryReader(stream, Options.Password);
if (IsEncrypted)
{
if (Password == null)
if (Options.Password == null)
{
throw new CryptographicException("Encrypted Rar archive has no password specified.");
}
@@ -131,11 +129,11 @@ namespace SharpCompress.Common.Rar.Headers
reader.InitializeAes(salt);
}
#else
var reader = new MarkingBinaryReader(stream);
var reader = new RarCrcBinaryReader(stream);
#endif
RarHeader header = RarHeader.Create(reader);
RarHeader header = RarHeader.Create(reader, Options.ArchiveEncoding);
if (header == null)
{
return null;
@@ -156,7 +154,7 @@ namespace SharpCompress.Common.Rar.Headers
case HeaderType.ProtectHeader:
{
ProtectHeader ph = header.PromoteHeader<ProtectHeader>(reader);
// skip the recovery record data, we do not use it.
switch (StreamingMode)
{
@@ -224,9 +222,9 @@ namespace SharpCompress.Common.Rar.Headers
else
{
#if !NO_CRYPTO
fh.PackedStream = new RarCryptoWrapper(ms, Password, fh.Salt);
fh.PackedStream = new RarCryptoWrapper(ms, Options.Password, fh.Salt);
#else
throw new NotSupportedException("RarCrypto not supported");
throw new NotSupportedException("RarCrypto not supported");
#endif
}
}
@@ -244,7 +242,7 @@ namespace SharpCompress.Common.Rar.Headers
}
default:
{
throw new InvalidFormatException("Invalid Rar Header: " + header.HeaderType.ToString());
throw new InvalidFormatException("Invalid Rar Header: " + header.HeaderType);
}
}
}

View File

@@ -0,0 +1,40 @@
using System.IO;
using SharpCompress.Compressors.Rar;
using SharpCompress.IO;
namespace SharpCompress.Common.Rar {
internal class RarCrcBinaryReader : MarkingBinaryReader {
private uint currentCrc;
public RarCrcBinaryReader(Stream stream) : base(stream)
{
}
public ushort GetCrc()
{
return (ushort)~currentCrc;
}
public void ResetCrc()
{
currentCrc = 0xffffffff;
}
protected void UpdateCrc(byte b)
{
currentCrc = RarCRC.CheckCrc(currentCrc, b);
}
protected byte[] ReadBytesNoCrc(int count)
{
return base.ReadBytes(count);
}
public override byte[] ReadBytes(int count)
{
var result = base.ReadBytes(count);
currentCrc = RarCRC.CheckCrc(currentCrc, result, 0, result.Length);
return result;
}
}
}

View File

@@ -1,16 +1,18 @@
#if !NO_CRYPTO
#if !NO_CRYPTO
using System.Collections.Generic;
using System.IO;
using SharpCompress.IO;
namespace SharpCompress.Common.Rar
{
internal class RarCryptoBinaryReader : MarkingBinaryReader
internal class RarCryptoBinaryReader : RarCrcBinaryReader
{
private RarRijndael rijndael;
private byte[] salt;
private readonly string password;
private readonly Queue<byte> data = new Queue<byte>();
private long readCount;
public RarCryptoBinaryReader(Stream stream, string password )
: base(stream)
@@ -18,6 +20,22 @@ namespace SharpCompress.Common.Rar
this.password = password;
}
// track read count ourselves rather than using the underlying stream since we buffer
public override long CurrentReadByteCount {
get
{
return this.readCount;
}
protected set
{
// ignore
}
}
public override void Mark() {
this.readCount = 0;
}
protected bool UseEncryption
{
get { return salt != null; }
@@ -35,6 +53,7 @@ namespace SharpCompress.Common.Rar
{
return ReadAndDecryptBytes(count);
}
this.readCount += count;
return base.ReadBytes(count);
}
@@ -49,7 +68,7 @@ namespace SharpCompress.Common.Rar
for (int i = 0; i < alignedSize / 16; i++)
{
//long ax = System.currentTimeMillis();
byte[] cipherText = base.ReadBytes(16);
byte[] cipherText = base.ReadBytesNoCrc(16);
var readBytes = rijndael.ProcessBlock(cipherText);
foreach (var readByte in readBytes)
data.Enqueue(readByte);
@@ -62,8 +81,11 @@ namespace SharpCompress.Common.Rar
for (int i = 0; i < count; i++)
{
decryptedBytes[i] = data.Dequeue();
var b = data.Dequeue();
decryptedBytes[i] = b;
UpdateCrc(b);
}
this.readCount += count;
return decryptedBytes;
}

View File

@@ -1,3 +1,4 @@
#if !NO_CRYPTO
using System;
using System.Collections.Generic;

View File

@@ -10,71 +10,44 @@ namespace SharpCompress.Common.Rar
/// <summary>
/// The File's 32 bit CRC Hash
/// </summary>
public override long Crc
{
get { return FileHeader.FileCRC; }
}
public override long Crc => FileHeader.FileCRC;
/// <summary>
/// The path of the file internal to the Rar Archive.
/// </summary>
public override string Key
{
get { return FileHeader.FileName; }
}
public override string Key => FileHeader.FileName;
/// <summary>
/// The entry last modified time in the archive, if recorded
/// </summary>
public override DateTime? LastModifiedTime
{
get { return FileHeader.FileLastModifiedTime; }
}
public override DateTime? LastModifiedTime => FileHeader.FileLastModifiedTime;
/// <summary>
/// The entry create time in the archive, if recorded
/// </summary>
public override DateTime? CreatedTime
{
get { return FileHeader.FileCreatedTime; }
}
public override DateTime? CreatedTime => FileHeader.FileCreatedTime;
/// <summary>
/// The entry last accessed time in the archive, if recorded
/// </summary>
public override DateTime? LastAccessedTime
{
get { return FileHeader.FileLastAccessedTime; }
}
public override DateTime? LastAccessedTime => FileHeader.FileLastAccessedTime;
/// <summary>
/// The entry time whend archived, if recorded
/// </summary>
public override DateTime? ArchivedTime
{
get { return FileHeader.FileArchivedTime; }
}
public override DateTime? ArchivedTime => FileHeader.FileArchivedTime;
/// <summary>
/// Entry is password protected and encrypted and cannot be extracted.
/// </summary>
public override bool IsEncrypted
{
get { return FileHeader.FileFlags.HasFlag(FileFlags.PASSWORD); }
}
public override bool IsEncrypted => FileHeader.FileFlags.HasFlag(FileFlags.PASSWORD);
/// <summary>
/// Entry is password protected and encrypted and cannot be extracted.
/// </summary>
public override bool IsDirectory
{
get { return FileHeader.FileFlags.HasFlag(FileFlags.DIRECTORY); }
}
public override bool IsDirectory => FileHeader.FileFlags.HasFlag(FileFlags.DIRECTORY);
public override bool IsSplit
{
get { return FileHeader.FileFlags.HasFlag(FileFlags.SPLIT_AFTER); }
}
public override bool IsSplit => FileHeader.FileFlags.HasFlag(FileFlags.SPLIT_AFTER);
public override string ToString()
{

View File

@@ -9,14 +9,15 @@ namespace SharpCompress.Common.Rar
internal abstract class RarFilePart : FilePart
{
internal RarFilePart(MarkHeader mh, FileHeader fh)
: base(fh.ArchiveEncoding)
{
MarkHeader = mh;
FileHeader = fh;
}
internal MarkHeader MarkHeader { get; private set; }
internal MarkHeader MarkHeader { get; }
internal FileHeader FileHeader { get; private set; }
internal FileHeader FileHeader { get; }
internal override Stream GetRawStream()
{

View File

@@ -74,13 +74,16 @@ namespace SharpCompress.Common.Rar
byte[] aesKey = new byte[CRYPTO_BLOCK_SIZE];
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
aesKey[i*4 + j] = (byte)
(((digest[i*4]*0x1000000) & 0xff000000 |
(uint) ((digest[i*4 + 1]*0x10000) & 0xff0000) |
(uint) ((digest[i*4 + 2]*0x100) & 0xff00) |
(uint) (digest[i*4 + 3] & 0xff)) >> (j*8));
}
}
rijndael.Init(false, new KeyParameter(aesKey));
@@ -100,10 +103,14 @@ namespace SharpCompress.Common.Rar
rijndael.ProcessBlock(cipherText, 0, plainText, 0);
for (int j = 0; j < plainText.Length; j++)
{
decryptedBytes.Add((byte) (plainText[j] ^ aesInitializationVector[j%16])); //32:114, 33:101
}
for (int j = 0; j < aesInitializationVector.Length; j++)
{
aesInitializationVector[j] = cipherText[j];
}
return decryptedBytes.ToArray();
}

View File

@@ -4,6 +4,7 @@ using System.IO;
using System.Linq;
using SharpCompress.Common.Rar.Headers;
using SharpCompress.IO;
using SharpCompress.Readers;
namespace SharpCompress.Common.Rar
{
@@ -13,20 +14,14 @@ namespace SharpCompress.Common.Rar
public abstract class RarVolume : Volume
{
private readonly RarHeaderFactory headerFactory;
internal RarVolume(StreamingMode mode, Stream stream, string password, Options options)
internal RarVolume(StreamingMode mode, Stream stream, ReaderOptions options)
: base(stream, options)
{
headerFactory = new RarHeaderFactory(mode, options, password);
Password = password;
headerFactory = new RarHeaderFactory(mode, options);
}
internal string Password { get; private set; }
internal StreamingMode Mode
{
get { return headerFactory.StreamingMode; }
}
internal StreamingMode Mode => headerFactory.StreamingMode;
internal abstract IEnumerable<RarFilePart> ReadFileParts();
@@ -35,26 +30,26 @@ namespace SharpCompress.Common.Rar
internal IEnumerable<RarFilePart> GetVolumeFileParts()
{
MarkHeader previousMarkHeader = null;
foreach (RarHeader header in headerFactory.ReadHeaders(this.Stream))
foreach (RarHeader header in headerFactory.ReadHeaders(Stream))
{
switch (header.HeaderType)
{
case HeaderType.ArchiveHeader:
{
ArchiveHeader = header as ArchiveHeader;
}
{
ArchiveHeader = header as ArchiveHeader;
}
break;
case HeaderType.MarkHeader:
{
previousMarkHeader = header as MarkHeader;
}
{
previousMarkHeader = header as MarkHeader;
}
break;
case HeaderType.FileHeader:
{
FileHeader fh = header as FileHeader;
RarFilePart fp = CreateFilePart(fh, previousMarkHeader);
yield return fp;
}
{
FileHeader fh = header as FileHeader;
RarFilePart fp = CreateFilePart(fh, previousMarkHeader);
yield return fp;
}
break;
}
}
@@ -70,6 +65,7 @@ namespace SharpCompress.Common.Rar
{
throw new InvalidOperationException("ArchiveHeader should never been null in a streaming read.");
}
//we only want to load the archive header to avoid overhead but have to do the nasty thing and reset the stream
GetVolumeFileParts().First();
Stream.Position = 0;

View File

@@ -1,13 +1,17 @@
using System;
using SharpCompress.Readers;
namespace SharpCompress.Common
{
public class ReaderExtractionEventArgs<T> : EventArgs
{
internal ReaderExtractionEventArgs(T entry)
internal ReaderExtractionEventArgs(T entry, ReaderProgress readerProgress = null)
{
Item = entry;
ReaderProgress = readerProgress;
}
public T Item { get; private set; }
public T Item { get; }
public ReaderProgress ReaderProgress { get; }
}
}
}

View File

@@ -1,8 +1,8 @@
using System;
using System.Collections.Generic;
using System.IO;
using SharpCompress.Compressor.LZMA;
using SharpCompress.Compressor.LZMA.Utilites;
using SharpCompress.Compressors.LZMA;
using SharpCompress.Compressors.LZMA.Utilites;
namespace SharpCompress.Common.SevenZip
{
@@ -22,6 +22,13 @@ namespace SharpCompress.Common.SevenZip
internal List<long> PackStreamStartPositions = new List<long>();
internal List<int> FolderStartFileIndex = new List<int>();
internal List<int> FileIndexToFolderIndexMap = new List<int>();
internal IPasswordProvider PasswordProvider { get; }
public ArchiveDatabase(IPasswordProvider passwordProvider)
{
PasswordProvider = passwordProvider;
}
internal void Clear()
{
@@ -80,15 +87,19 @@ namespace SharpCompress.Common.SevenZip
{
// v3.13 incorrectly worked with empty folders
// v4.07: Loop for skipping empty folders
for (; ; )
for (;;)
{
if (folderIndex >= Folders.Count)
{
throw new InvalidOperationException();
}
FolderStartFileIndex.Add(i); // check it
if (NumUnpackStreamsVector[folderIndex] != 0)
{
break;
}
folderIndex++;
}
@@ -97,7 +108,9 @@ namespace SharpCompress.Common.SevenZip
FileIndexToFolderIndexMap.Add(folderIndex);
if (emptyStream)
{
continue;
}
indexInFolder++;
@@ -128,7 +141,9 @@ namespace SharpCompress.Common.SevenZip
long size = 0;
for (int i = 0; i < folder.PackStreams.Count; i++)
{
size += PackSizes[packStreamIndex + i];
}
return size;
}
@@ -139,7 +154,9 @@ namespace SharpCompress.Common.SevenZip
long folderStartPackPos = GetFolderStreamPos(folder, 0);
List<long> packSizes = new List<long>();
for (int j = 0; j < folder.PackStreams.Count; j++)
{
packSizes.Add(PackSizes[packStreamIndex + j]);
}
return DecoderStreamHelper.CreateDecoderStream(stream, folderStartPackPos, packSizes.ToArray(), folder, pw);
}
@@ -153,8 +170,12 @@ namespace SharpCompress.Common.SevenZip
{
int folderIndex = FileIndexToFolderIndexMap[fileIndex];
if (folderIndex != -1)
{
if (FolderStartFileIndex[folderIndex] == fileIndex)
{
return GetFolderFullPackSize(folderIndex);
}
}
return 0;
}
}

View File

@@ -1,9 +1,10 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using SharpCompress.Compressor.LZMA;
using SharpCompress.Compressor.LZMA.Utilites;
using SharpCompress.Compressors.LZMA;
using SharpCompress.Compressors.LZMA.Utilites;
using SharpCompress.IO;
namespace SharpCompress.Common.SevenZip
@@ -17,7 +18,7 @@ namespace SharpCompress.Common.SevenZip
internal long _streamEnding;
internal byte[] _header;
private Dictionary<int, Stream> _cachedStreams = new Dictionary<int, Stream>();
private readonly Dictionary<int, Stream> _cachedStreams = new Dictionary<int, Stream>();
internal void AddByteStream(byte[] buffer, int offset, int length)
{
@@ -66,7 +67,9 @@ namespace SharpCompress.Common.SevenZip
{
ulong id = _currentReader.ReadNumber();
if (id > 25)
{
return null;
}
#if DEBUG
Log.WriteLine("ReadId: {0}", (BlockType)id);
#endif
@@ -85,13 +88,17 @@ namespace SharpCompress.Common.SevenZip
private void WaitAttribute(BlockType attribute)
{
for (; ; )
for (;;)
{
BlockType? type = ReadId();
if (type == attribute)
{
return;
}
if (type == BlockType.End)
{
throw new InvalidOperationException();
}
SkipData();
}
}
@@ -99,7 +106,9 @@ namespace SharpCompress.Common.SevenZip
private void ReadArchiveProperties()
{
while (ReadId() != BlockType.End)
{
SkipData();
}
}
#endregion
@@ -122,7 +131,9 @@ namespace SharpCompress.Common.SevenZip
}
if ((data & mask) != 0)
{
bits.SetBit(i);
}
mask >>= 1;
}
@@ -134,7 +145,9 @@ namespace SharpCompress.Common.SevenZip
{
byte allTrue = ReadByte();
if (allTrue != 0)
{
return new BitVector(length, true);
}
return ReadBitVector(length);
}
@@ -150,9 +163,13 @@ namespace SharpCompress.Common.SevenZip
for (int i = 0; i < numFiles; i++)
{
if (defined[i])
{
action(i, checked((long)ReadUInt64()));
}
else
{
action(i, null);
}
}
}
}
@@ -165,10 +182,11 @@ namespace SharpCompress.Common.SevenZip
private DateTime? TranslateTime(long? time)
{
if (time.HasValue)
if (time.HasValue && time.Value >= 0 && time.Value <= 2650467743999999999) //maximum Windows file time 31.12.9999
{
return TranslateTime(time.Value);
else
return null;
}
return null;
}
private void ReadDateTimeVector(List<byte[]> dataVector, int numFiles, Action<int, DateTime?> action)
@@ -185,9 +203,13 @@ namespace SharpCompress.Common.SevenZip
for (int i = 0; i < numFiles; i++)
{
if (boolVector[i])
{
action(i, ReadUInt32());
}
else
{
action(i, null);
}
}
}
}
@@ -230,10 +252,14 @@ namespace SharpCompress.Common.SevenZip
Log.WriteLine("MethodId: " + String.Join("", Enumerable.Range(0, idSize).Select(x => longID[x].ToString("x2")).ToArray()));
#endif
if (idSize > 8)
{
throw new NotSupportedException();
}
ulong id = 0;
for (int j = 0; j < idSize; j++)
{
id |= (ulong)longID[idSize - 1 - j] << (8 * j);
}
coder.MethodId = new CMethodId(id);
if ((mainByte & 0x10) != 0)
@@ -264,7 +290,9 @@ namespace SharpCompress.Common.SevenZip
}
if ((mainByte & 0x80) != 0)
{
throw new NotSupportedException();
}
numInStreams += coder.NumInStreams;
numOutStreams += coder.NumOutStreams;
@@ -298,9 +326,12 @@ namespace SharpCompress.Common.SevenZip
#endif
if (numInStreams < numBindPairs)
{
throw new NotSupportedException();
}
int numPackStreams = numInStreams - numBindPairs;
//folder.PackStreams.Reserve(numPackStreams);
if (numPackStreams == 1)
{
@@ -317,7 +348,9 @@ namespace SharpCompress.Common.SevenZip
}
if (folder.PackStreams.Count != 1)
{
throw new NotSupportedException();
}
}
else
{
@@ -417,11 +450,13 @@ namespace SharpCompress.Common.SevenZip
#endif
BlockType? type;
for (; ; )
for (;;)
{
type = ReadId();
if (type == BlockType.End)
{
break;
}
if (type == BlockType.CRC)
{
packCRCs = ReadHashDigests(numPackStreams);
@@ -434,7 +469,9 @@ namespace SharpCompress.Common.SevenZip
{
packCRCs = new List<uint?>(numPackStreams);
for (int i = 0; i < numPackStreams; i++)
{
packCRCs.Add(null);
}
}
}
finally
@@ -462,13 +499,14 @@ namespace SharpCompress.Common.SevenZip
using (CStreamSwitch streamSwitch = new CStreamSwitch())
{
streamSwitch.Set(this, dataVector);
//folders.Clear();
//folders.Reserve(numFolders);
folders = new List<CFolder>(numFolders);
int index = 0;
for (int i = 0; i < numFolders; i++)
{
var f = new CFolder { FirstPackStreamId = index };
var f = new CFolder {FirstPackStreamId = index};
folders.Add(f);
GetNextFolderItem(f);
index += f.PackStreams.Count;
@@ -499,17 +537,21 @@ namespace SharpCompress.Common.SevenZip
#endif
}
for (; ; )
for (;;)
{
BlockType? type = ReadId();
if (type == BlockType.End)
{
return;
}
if (type == BlockType.CRC)
{
List<uint?> crcs = ReadHashDigests(numFolders);
for (int i = 0; i < numFolders; i++)
{
folders[i].UnpackCRC = crcs[i];
}
continue;
}
@@ -536,7 +578,7 @@ namespace SharpCompress.Common.SevenZip
numUnpackStreamsInFolders = null;
BlockType? type;
for (; ; )
for (;;)
{
type = ReadId();
if (type == BlockType.NumUnpackStream)
@@ -559,9 +601,13 @@ namespace SharpCompress.Common.SevenZip
continue;
}
if (type == BlockType.CRC || type == BlockType.Size)
{
break;
}
if (type == BlockType.End)
{
break;
}
SkipData();
}
@@ -569,7 +615,9 @@ namespace SharpCompress.Common.SevenZip
{
numUnpackStreamsInFolders = new List<int>(folders.Count);
for (int i = 0; i < folders.Count; i++)
{
numUnpackStreamsInFolders.Add(1);
}
}
unpackSizes = new List<long>(folders.Count);
@@ -579,7 +627,9 @@ namespace SharpCompress.Common.SevenZip
// v4.07: we check that folder is empty
int numSubstreams = numUnpackStreamsInFolders[i];
if (numSubstreams == 0)
{
continue;
}
#if DEBUG
Log.Write("#{0} StreamSizes:", i);
#endif
@@ -602,7 +652,9 @@ namespace SharpCompress.Common.SevenZip
#endif
}
if (type == BlockType.Size)
{
type = ReadId();
}
int numDigests = 0;
int numDigestsTotal = 0;
@@ -610,13 +662,15 @@ namespace SharpCompress.Common.SevenZip
{
int numSubstreams = numUnpackStreamsInFolders[i];
if (numSubstreams != 1 || !folders[i].UnpackCRCDefined)
{
numDigests += numSubstreams;
}
numDigestsTotal += numSubstreams;
}
digests = null;
for (; ; )
for (;;)
{
if (type == BlockType.CRC)
{
@@ -636,12 +690,16 @@ namespace SharpCompress.Common.SevenZip
else
{
for (int j = 0; j < numSubstreams; j++, digestIndex++)
{
digests.Add(digests2[digestIndex]);
}
}
}
if (digestIndex != numDigests || numDigestsTotal != digests.Count)
System.Diagnostics.Debugger.Break();
{
Debugger.Break();
}
}
else if (type == BlockType.End)
{
@@ -649,7 +707,9 @@ namespace SharpCompress.Common.SevenZip
{
digests = new List<uint?>(numDigestsTotal);
for (int i = 0; i < numDigestsTotal; i++)
{
digests.Add(null);
}
}
return;
}
@@ -693,7 +753,7 @@ namespace SharpCompress.Common.SevenZip
unpackSizes = null;
digests = null;
for (; ; )
for (;;)
{
switch (ReadId())
{
@@ -768,12 +828,18 @@ namespace SharpCompress.Common.SevenZip
byte[] data = new byte[unpackSize];
outStream.ReadExact(data, 0, data.Length);
if (outStream.ReadByte() >= 0)
{
throw new InvalidOperationException("Decoded stream is longer than expected.");
}
dataVector.Add(data);
if (folder.UnpackCRCDefined)
{
if (CRC.Finish(CRC.Update(CRC.kInitCRC, data, 0, unpackSize)) != folder.UnpackCRC)
{
throw new InvalidOperationException("Decoded stream does not match expected CRC.");
}
}
}
return dataVector;
}
@@ -842,10 +908,14 @@ namespace SharpCompress.Common.SevenZip
db.Files.Clear();
if (type == BlockType.End)
{
return;
}
if (type != BlockType.FilesInfo)
{
throw new InvalidOperationException();
}
int numFiles = ReadNum();
#if DEBUG
@@ -853,18 +923,22 @@ namespace SharpCompress.Common.SevenZip
#endif
db.Files = new List<CFileItem>(numFiles);
for (int i = 0; i < numFiles; i++)
{
db.Files.Add(new CFileItem());
}
BitVector emptyStreamVector = new BitVector(numFiles);
BitVector emptyFileVector = null;
BitVector antiFileVector = null;
int numEmptyStreams = 0;
for (; ; )
for (;;)
{
type = ReadId();
if (type == BlockType.End)
{
break;
}
long size = checked((long)ReadNumber()); // TODO: throw invalid data on negative
int oldPos = _currentReader.Offset;
@@ -894,32 +968,34 @@ namespace SharpCompress.Common.SevenZip
Log.Write("WinAttributes:");
#endif
ReadAttributeVector(dataVector, numFiles, delegate(int i, uint? attr)
{
// Some third party implementations established an unofficial extension
// of the 7z archive format by placing posix file attributes in the high
// bits of the windows file attributes. This makes use of the fact that
// the official implementation does not perform checks on this value.
//
// Newer versions of the official 7z GUI client will try to parse this
// extension, thus acknowledging the unofficial use of these bits.
//
// For us it is safe to just discard the upper bits if they are set and
// keep the windows attributes from the lower bits (which should be set
// properly even if posix file attributes are present, in order to be
// compatible with older 7z archive readers)
//
// Note that the 15th bit is used by some implementations to indicate
// presence of the extension, but not all implementations do that so
// we can't trust that bit and must ignore it.
//
if (attr.HasValue && (attr.Value >> 16) != 0)
{
// Some third party implementations established an unofficial extension
// of the 7z archive format by placing posix file attributes in the high
// bits of the windows file attributes. This makes use of the fact that
// the official implementation does not perform checks on this value.
//
// Newer versions of the official 7z GUI client will try to parse this
// extension, thus acknowledging the unofficial use of these bits.
//
// For us it is safe to just discard the upper bits if they are set and
// keep the windows attributes from the lower bits (which should be set
// properly even if posix file attributes are present, in order to be
// compatible with older 7z archive readers)
//
// Note that the 15th bit is used by some implementations to indicate
// presence of the extension, but not all implementations do that so
// we can't trust that bit and must ignore it.
//
if (attr.HasValue && (attr.Value >> 16) != 0)
attr = attr.Value & 0x7FFFu;
attr = attr.Value & 0x7FFFu;
}
db.Files[i].Attrib = attr;
db.Files[i].Attrib = attr;
#if DEBUG
Log.Write(" " + (attr.HasValue ? attr.Value.ToString("x8") : "n/a"));
Log.Write(" " + (attr.HasValue ? attr.Value.ToString("x8") : "n/a"));
#endif
});
});
#if DEBUG
Log.WriteLine();
#endif
@@ -958,7 +1034,9 @@ namespace SharpCompress.Common.SevenZip
#if DEBUG
Log.Write("EmptyFile: ");
for (int i = 0; i < numEmptyStreams; i++)
{
Log.Write(emptyFileVector[i] ? "x" : ".");
}
Log.WriteLine();
#endif
break;
@@ -967,7 +1045,9 @@ namespace SharpCompress.Common.SevenZip
#if DEBUG
Log.Write("Anti: ");
for (int i = 0; i < numEmptyStreams; i++)
{
Log.Write(antiFileVector[i] ? "x" : ".");
}
Log.WriteLine();
#endif
break;
@@ -976,12 +1056,12 @@ namespace SharpCompress.Common.SevenZip
Log.Write("StartPos:");
#endif
ReadNumberVector(dataVector, numFiles, delegate(int i, long? startPos)
{
db.Files[i].StartPos = startPos;
{
db.Files[i].StartPos = startPos;
#if DEBUG
Log.Write(" " + (startPos.HasValue ? startPos.Value.ToString() : "n/a"));
Log.Write(" " + (startPos.HasValue ? startPos.Value.ToString() : "n/a"));
#endif
});
});
#if DEBUG
Log.WriteLine();
#endif
@@ -991,12 +1071,12 @@ namespace SharpCompress.Common.SevenZip
Log.Write("CTime:");
#endif
ReadDateTimeVector(dataVector, numFiles, delegate(int i, DateTime? time)
{
db.Files[i].CTime = time;
{
db.Files[i].CTime = time;
#if DEBUG
Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a"));
Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a"));
#endif
});
});
#if DEBUG
Log.WriteLine();
#endif
@@ -1006,12 +1086,12 @@ namespace SharpCompress.Common.SevenZip
Log.Write("ATime:");
#endif
ReadDateTimeVector(dataVector, numFiles, delegate(int i, DateTime? time)
{
db.Files[i].ATime = time;
{
db.Files[i].ATime = time;
#if DEBUG
Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a"));
Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a"));
#endif
});
});
#if DEBUG
Log.WriteLine();
#endif
@@ -1021,12 +1101,12 @@ namespace SharpCompress.Common.SevenZip
Log.Write("MTime:");
#endif
ReadDateTimeVector(dataVector, numFiles, delegate(int i, DateTime? time)
{
db.Files[i].MTime = time;
{
db.Files[i].MTime = time;
#if DEBUG
Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a"));
Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a"));
#endif
});
});
#if DEBUG
Log.WriteLine();
#endif
@@ -1036,8 +1116,12 @@ namespace SharpCompress.Common.SevenZip
Log.Write("Dummy: " + size);
#endif
for (long j = 0; j < size; j++)
{
if (ReadByte() != 0)
{
throw new InvalidOperationException();
}
}
break;
default:
SkipData(size);
@@ -1047,7 +1131,9 @@ namespace SharpCompress.Common.SevenZip
// since 0.3 record sizes must be correct
bool checkRecordsSize = (db.MajorVersion > 0 || db.MinorVersion > 2);
if (checkRecordsSize && _currentReader.Offset - oldPos != size)
{
throw new InvalidOperationException();
}
}
int emptyFileIndex = 0;
@@ -1095,11 +1181,13 @@ namespace SharpCompress.Common.SevenZip
// TODO: Check Signature!
_header = new byte[0x20];
for (int offset = 0; offset < 0x20; )
for (int offset = 0; offset < 0x20;)
{
int delta = stream.Read(_header, offset, 0x20 - offset);
if (delta == 0)
{
throw new EndOfStreamException();
}
offset += delta;
}
@@ -1109,24 +1197,30 @@ namespace SharpCompress.Common.SevenZip
public void Close()
{
if (_stream != null)
{
_stream.Dispose();
}
foreach (var stream in _cachedStreams.Values)
{
stream.Dispose();
}
_cachedStreams.Clear();
}
public ArchiveDatabase ReadDatabase(IPasswordProvider pass)
{
var db = new ArchiveDatabase();
var db = new ArchiveDatabase(pass);
db.Clear();
db.MajorVersion = _header[6];
db.MinorVersion = _header[7];
if (db.MajorVersion != 0)
{
throw new InvalidOperationException();
}
uint crcFromArchive = DataReader.Get32(_header, 8);
long nextHeaderOffset = (long)DataReader.Get64(_header, 0xC);
@@ -1140,7 +1234,9 @@ namespace SharpCompress.Common.SevenZip
crc = CRC.Finish(crc);
if (crc != crcFromArchive)
{
throw new InvalidOperationException();
}
db.StartPositionAfterHeader = _streamOrigin + 0x20;
@@ -1151,12 +1247,15 @@ namespace SharpCompress.Common.SevenZip
return db;
}
if (nextHeaderOffset < 0 || nextHeaderSize < 0 || nextHeaderSize > Int32.MaxValue)
{
throw new InvalidOperationException();
}
if (nextHeaderOffset > _streamEnding - db.StartPositionAfterHeader)
{
throw new IndexOutOfRangeException();
}
_stream.Seek(nextHeaderOffset, SeekOrigin.Current);
@@ -1164,7 +1263,9 @@ namespace SharpCompress.Common.SevenZip
_stream.ReadExact(header, 0, header.Length);
if (CRC.Finish(CRC.Update(CRC.kInitCRC, header, 0, header.Length)) != nextHeaderCrc)
{
throw new InvalidOperationException();
}
using (CStreamSwitch streamSwitch = new CStreamSwitch())
{
@@ -1174,9 +1275,11 @@ namespace SharpCompress.Common.SevenZip
if (type != BlockType.Header)
{
if (type != BlockType.EncodedHeader)
{
throw new InvalidOperationException();
}
var dataVector = ReadAndDecodePackedStreams(db.StartPositionAfterHeader, pass);
var dataVector = ReadAndDecodePackedStreams(db.StartPositionAfterHeader, db.PasswordProvider);
// compressed header without content is odd but ok
if (dataVector.Count == 0)
@@ -1186,15 +1289,19 @@ namespace SharpCompress.Common.SevenZip
}
if (dataVector.Count != 1)
{
throw new InvalidOperationException();
}
streamSwitch.Set(this, dataVector[0]);
if (ReadId() != BlockType.Header)
{
throw new InvalidOperationException();
}
}
ReadHeader(db, pass);
ReadHeader(db, db.PasswordProvider);
}
db.Fill();
return db;
@@ -1211,55 +1318,41 @@ namespace SharpCompress.Common.SevenZip
FileIndex = fileIndex;
FolderIndex = folderIndex;
if (fileIndex != -1)
{
ExtractStatuses.Add(true);
}
}
}
private class FolderUnpackStream : Stream
{
private ArchiveDatabase _db;
private int _startIndex;
private List<bool> _extractStatuses;
private readonly ArchiveDatabase _db;
private readonly int _startIndex;
private readonly List<bool> _extractStatuses;
public FolderUnpackStream(ArchiveDatabase db, int p, int startIndex, List<bool> list)
{
this._db = db;
this._startIndex = startIndex;
this._extractStatuses = list;
_db = db;
_startIndex = startIndex;
_extractStatuses = list;
}
#region Stream
public override bool CanRead
{
get { return true; }
}
public override bool CanRead => true;
public override bool CanSeek
{
get { return false; }
}
public override bool CanSeek => false;
public override bool CanWrite
{
get { return false; }
}
public override bool CanWrite => false;
public override void Flush()
{
throw new NotSupportedException();
}
public override long Length
{
get { throw new NotSupportedException(); }
}
public override long Length => throw new NotSupportedException();
public override long Position
{
get { throw new NotSupportedException(); }
set { throw new NotSupportedException(); }
}
public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); }
public override int Read(byte[] buffer, int offset, int count)
{
@@ -1298,9 +1391,13 @@ namespace SharpCompress.Common.SevenZip
Log.WriteLine(_db.Files[index].Name);
#endif
if (_db.Files[index].CrcDefined)
{
_stream = new CrcCheckStream(_db.Files[index].Crc.Value);
}
else
{
_stream = new MemoryStream();
}
_rem = _db.Files[index].Size;
}
@@ -1312,7 +1409,9 @@ namespace SharpCompress.Common.SevenZip
{
int write = count;
if (write > _rem)
{
write = (int)_rem;
}
_stream.Write(buffer, offset, write);
count -= write;
_rem -= write;
@@ -1331,7 +1430,7 @@ namespace SharpCompress.Common.SevenZip
if (_currentIndex == _extractStatuses.Count)
{
// we support partial extracting
System.Diagnostics.Debugger.Break();
Debugger.Break();
throw new NotSupportedException();
}
OpenFile();
@@ -1342,7 +1441,7 @@ namespace SharpCompress.Common.SevenZip
#endregion
}
private Stream GetCachedDecoderStream(ArchiveDatabase _db, int folderIndex, IPasswordProvider pw)
private Stream GetCachedDecoderStream(ArchiveDatabase _db, int folderIndex)
{
Stream s;
if (!_cachedStreams.TryGetValue(folderIndex, out s))
@@ -1352,44 +1451,56 @@ namespace SharpCompress.Common.SevenZip
long folderStartPackPos = _db.GetFolderStreamPos(folderInfo, 0);
List<long> packSizes = new List<long>();
for (int j = 0; j < folderInfo.PackStreams.Count; j++)
{
packSizes.Add(_db.PackSizes[packStreamIndex + j]);
}
s = DecoderStreamHelper.CreateDecoderStream(_stream, folderStartPackPos, packSizes.ToArray(), folderInfo,
pw);
_db.PasswordProvider);
_cachedStreams.Add(folderIndex, s);
}
return s;
}
public Stream OpenStream(ArchiveDatabase _db, int fileIndex, IPasswordProvider pw)
public Stream OpenStream(ArchiveDatabase _db, int fileIndex)
{
int folderIndex = _db.FileIndexToFolderIndexMap[fileIndex];
int numFilesInFolder = _db.NumUnpackStreamsVector[folderIndex];
int firstFileIndex = _db.FolderStartFileIndex[folderIndex];
if (firstFileIndex > fileIndex || fileIndex - firstFileIndex >= numFilesInFolder)
{
throw new InvalidOperationException();
}
int skipCount = fileIndex - firstFileIndex;
long skipSize = 0;
for (int i = 0; i < skipCount; i++)
{
skipSize += _db.Files[firstFileIndex + i].Size;
}
Stream s = GetCachedDecoderStream(_db, folderIndex, pw);
Stream s = GetCachedDecoderStream(_db, folderIndex);
s.Position = skipSize;
return new ReadOnlySubStream(s, _db.Files[fileIndex].Size);
}
public void Extract(ArchiveDatabase _db, int[] indices, IPasswordProvider pw)
public void Extract(ArchiveDatabase _db, int[] indices)
{
int numItems;
bool allFilesMode = (indices == null);
if (allFilesMode)
{
numItems = _db.Files.Count;
}
else
{
numItems = indices.Length;
}
if (numItems == 0)
{
return;
}
List<CExtractFolderInfo> extractFolderInfoVector = new List<CExtractFolderInfo>();
for (int i = 0; i < numItems; i++)
@@ -1404,27 +1515,37 @@ namespace SharpCompress.Common.SevenZip
}
if (extractFolderInfoVector.Count == 0 || folderIndex != extractFolderInfoVector.Last().FolderIndex)
{
extractFolderInfoVector.Add(new CExtractFolderInfo(-1, folderIndex));
}
CExtractFolderInfo efi = extractFolderInfoVector.Last();
int startIndex = _db.FolderStartFileIndex[folderIndex];
for (int index = efi.ExtractStatuses.Count; index <= fileIndex - startIndex; index++)
{
efi.ExtractStatuses.Add(index == fileIndex - startIndex);
}
}
foreach (CExtractFolderInfo efi in extractFolderInfoVector)
{
int startIndex;
if (efi.FileIndex != -1)
{
startIndex = efi.FileIndex;
}
else
{
startIndex = _db.FolderStartFileIndex[efi.FolderIndex];
}
var outStream = new FolderUnpackStream(_db, 0, startIndex, efi.ExtractStatuses);
if (efi.FileIndex != -1)
{
continue;
}
int folderIndex = efi.FolderIndex;
CFolder folderInfo = _db.Folders[folderIndex];
@@ -1434,18 +1555,22 @@ namespace SharpCompress.Common.SevenZip
List<long> packSizes = new List<long>();
for (int j = 0; j < folderInfo.PackStreams.Count; j++)
{
packSizes.Add(_db.PackSizes[packStreamIndex + j]);
}
// TODO: If the decoding fails the last file may be extracted incompletely. Delete it?
Stream s = DecoderStreamHelper.CreateDecoderStream(_stream, folderStartPackPos, packSizes.ToArray(),
folderInfo, pw);
folderInfo, _db.PasswordProvider);
byte[] buffer = new byte[4 << 10];
for (; ; )
for (;;)
{
int processed = s.Read(buffer, 0, buffer.Length);
if (processed == 0)
{
break;
}
outStream.Write(buffer, 0, processed);
}
}
@@ -1463,4 +1588,4 @@ namespace SharpCompress.Common.SevenZip
#endregion
}
}
}

View File

@@ -12,19 +12,13 @@ namespace SharpCompress.Common.SevenZip
public bool HasStream { get; internal set; }
public bool IsDir { get; internal set; }
public bool CrcDefined
{
get { return Crc != null; }
}
public bool CrcDefined => Crc != null;
public bool AttribDefined
{
get { return Attrib != null; }
}
public bool AttribDefined => Attrib != null;
public void SetAttrib(uint attrib)
{
this.Attrib = attrib;
Attrib = attrib;
}
public DateTime? CTime { get; internal set; }

View File

@@ -1,6 +1,6 @@
using System;
using System.Collections.Generic;
using SharpCompress.Compressor.LZMA;
using SharpCompress.Compressors.LZMA;
namespace SharpCompress.Common.SevenZip
{
@@ -13,19 +13,22 @@ namespace SharpCompress.Common.SevenZip
internal List<long> UnpackSizes = new List<long>();
internal uint? UnpackCRC;
internal bool UnpackCRCDefined
{
get { return UnpackCRC != null; }
}
internal bool UnpackCRCDefined => UnpackCRC != null;
public long GetUnpackSize()
{
if (UnpackSizes.Count == 0)
{
return 0;
}
for (int i = UnpackSizes.Count - 1; i >= 0; i--)
{
if (FindBindPairForOutStream(i) < 0)
{
return UnpackSizes[i];
}
}
throw new Exception();
}
@@ -34,7 +37,9 @@ namespace SharpCompress.Common.SevenZip
{
int count = 0;
for (int i = 0; i < Coders.Count; i++)
{
count += Coders[i].NumOutStreams;
}
return count;
}
@@ -42,8 +47,12 @@ namespace SharpCompress.Common.SevenZip
public int FindBindPairForInStream(int inStreamIndex)
{
for (int i = 0; i < BindPairs.Count; i++)
{
if (BindPairs[i].InIndex == inStreamIndex)
{
return i;
}
}
return -1;
}
@@ -51,8 +60,12 @@ namespace SharpCompress.Common.SevenZip
public int FindBindPairForOutStream(int outStreamIndex)
{
for (int i = 0; i < BindPairs.Count; i++)
{
if (BindPairs[i].OutIndex == outStreamIndex)
{
return i;
}
}
return -1;
}
@@ -60,8 +73,12 @@ namespace SharpCompress.Common.SevenZip
public int FindPackStreamArrayIndex(int inStreamIndex)
{
for (int i = 0; i < PackStreams.Count; i++)
{
if (PackStreams[i] == inStreamIndex)
{
return i;
}
}
return -1;
}
@@ -69,8 +86,12 @@ namespace SharpCompress.Common.SevenZip
public bool IsEncrypted()
{
for (int i = Coders.Count - 1; i >= 0; i--)
{
if (Coders[i].MethodId == CMethodId.kAES)
{
return true;
}
}
return false;
}
@@ -82,25 +103,39 @@ namespace SharpCompress.Common.SevenZip
const int kNumBindsMax = 32;
if (Coders.Count > kNumCodersMax || BindPairs.Count > kNumBindsMax)
{
return false;
}
{
var v = new BitVector(BindPairs.Count + PackStreams.Count);
for (int i = 0; i < BindPairs.Count; i++)
{
if (v.GetAndSet(BindPairs[i].InIndex))
{
return false;
}
}
for (int i = 0; i < PackStreams.Count; i++)
{
if (v.GetAndSet(PackStreams[i]))
{
return false;
}
}
}
{
var v = new BitVector(UnpackSizes.Count);
for (int i = 0; i < BindPairs.Count; i++)
{
if (v.GetAndSet(BindPairs[i].OutIndex))
{
return false;
}
}
}
uint[] mask = new uint[kMaskSize];
@@ -112,9 +147,13 @@ namespace SharpCompress.Common.SevenZip
{
CCoderInfo coder = Coders[i];
for (int j = 0; j < coder.NumInStreams; j++)
{
inStreamToCoder.Add(i);
}
for (int j = 0; j < coder.NumOutStreams; j++)
{
outStreamToCoder.Add(i);
}
}
for (int i = 0; i < BindPairs.Count; i++)
@@ -125,13 +164,23 @@ namespace SharpCompress.Common.SevenZip
}
for (int i = 0; i < kMaskSize; i++)
{
for (int j = 0; j < kMaskSize; j++)
{
if (((1u << j) & mask[i]) != 0)
{
mask[i] |= mask[j];
}
}
}
for (int i = 0; i < kMaskSize; i++)
{
if (((1u << i) & mask[i]) != 0)
{
return false;
}
}
return true;
}

View File

@@ -16,7 +16,7 @@
public CMethodId(ulong id)
{
this.Id = id;
Id = id;
}
public override int GetHashCode()
@@ -26,7 +26,7 @@
public override bool Equals(object obj)
{
return obj is CMethodId && (CMethodId) obj == this;
return obj is CMethodId && (CMethodId)obj == this;
}
public bool Equals(CMethodId other)
@@ -48,7 +48,9 @@
{
int bytes = 0;
for (ulong value = Id; value != 0; value >>= 8)
{
bytes++;
}
return bytes;
}
}

View File

@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
using SharpCompress.Compressor.LZMA;
using SharpCompress.Compressors.LZMA;
namespace SharpCompress.Common.SevenZip
{
@@ -47,7 +46,9 @@ namespace SharpCompress.Common.SevenZip
{
int dataIndex = archive.ReadNum();
if (dataIndex < 0 || dataIndex >= dataVector.Count)
{
throw new InvalidOperationException();
}
#if DEBUG
Log.WriteLine("[switch to stream {0}]", dataIndex);

View File

@@ -1,7 +1,7 @@
using System;
using System.IO;
using System.Text;
using SharpCompress.Compressor.LZMA;
using SharpCompress.Compressors.LZMA;
namespace SharpCompress.Common.SevenZip
{
@@ -11,31 +11,30 @@ namespace SharpCompress.Common.SevenZip
public static uint Get32(byte[] buffer, int offset)
{
return (uint) buffer[offset]
+ ((uint) buffer[offset + 1] << 8)
+ ((uint) buffer[offset + 2] << 16)
+ ((uint) buffer[offset + 3] << 24);
return buffer[offset]
+ ((uint)buffer[offset + 1] << 8)
+ ((uint)buffer[offset + 2] << 16)
+ ((uint)buffer[offset + 3] << 24);
}
public static ulong Get64(byte[] buffer, int offset)
{
return (ulong) buffer[offset]
+ ((ulong) buffer[offset + 1] << 8)
+ ((ulong) buffer[offset + 2] << 16)
+ ((ulong) buffer[offset + 3] << 24)
+ ((ulong) buffer[offset + 4] << 32)
+ ((ulong) buffer[offset + 5] << 40)
+ ((ulong) buffer[offset + 6] << 48)
+ ((ulong) buffer[offset + 7] << 56);
return buffer[offset]
+ ((ulong)buffer[offset + 1] << 8)
+ ((ulong)buffer[offset + 2] << 16)
+ ((ulong)buffer[offset + 3] << 24)
+ ((ulong)buffer[offset + 4] << 32)
+ ((ulong)buffer[offset + 5] << 40)
+ ((ulong)buffer[offset + 6] << 48)
+ ((ulong)buffer[offset + 7] << 56);
}
#endregion
#region Variables
private byte[] _buffer;
private int _offset;
private int _ending;
private readonly byte[] _buffer;
private readonly int _ending;
#endregion
@@ -44,38 +43,43 @@ namespace SharpCompress.Common.SevenZip
public DataReader(byte[] buffer, int offset, int length)
{
_buffer = buffer;
_offset = offset;
Offset = offset;
_ending = offset + length;
}
public int Offset
{
get { return _offset; }
}
public int Offset { get; private set; }
public Byte ReadByte()
{
if (_offset >= _ending)
if (Offset >= _ending)
{
throw new EndOfStreamException();
}
return _buffer[_offset++];
return _buffer[Offset++];
}
public void ReadBytes(byte[] buffer, int offset, int length)
{
if (length > _ending - _offset)
if (length > _ending - Offset)
{
throw new EndOfStreamException();
}
while (length-- > 0)
buffer[offset++] = _buffer[_offset++];
{
buffer[offset++] = _buffer[Offset++];
}
}
public void SkipData(long size)
{
if (size > _ending - _offset)
if (size > _ending - Offset)
{
throw new EndOfStreamException();
}
_offset += (int) size;
Offset += (int)size;
#if DEBUG
Log.WriteLine("SkipData {0}", size);
#endif
@@ -83,15 +87,17 @@ namespace SharpCompress.Common.SevenZip
public void SkipData()
{
SkipData(checked((long) ReadNumber()));
SkipData(checked((long)ReadNumber()));
}
public ulong ReadNumber()
{
if (_offset >= _ending)
if (Offset >= _ending)
{
throw new EndOfStreamException();
}
byte firstByte = _buffer[_offset++];
byte firstByte = _buffer[Offset++];
byte mask = 0x80;
ulong value = 0;
@@ -100,14 +106,16 @@ namespace SharpCompress.Common.SevenZip
if ((firstByte & mask) == 0)
{
ulong highPart = firstByte & (mask - 1u);
value += highPart << (i*8);
value += highPart << (i * 8);
return value;
}
if (_offset >= _ending)
if (Offset >= _ending)
{
throw new EndOfStreamException();
}
value |= (ulong) _buffer[_offset++] << (8*i);
value |= (ulong)_buffer[Offset++] << (8 * i);
mask >>= 1;
}
@@ -118,48 +126,58 @@ namespace SharpCompress.Common.SevenZip
{
ulong value = ReadNumber();
if (value > Int32.MaxValue)
{
throw new NotSupportedException();
}
return (int) value;
return (int)value;
}
public uint ReadUInt32()
{
if (_offset + 4 > _ending)
if (Offset + 4 > _ending)
{
throw new EndOfStreamException();
}
uint res = Get32(_buffer, _offset);
_offset += 4;
uint res = Get32(_buffer, Offset);
Offset += 4;
return res;
}
public ulong ReadUInt64()
{
if (_offset + 8 > _ending)
if (Offset + 8 > _ending)
{
throw new EndOfStreamException();
}
ulong res = Get64(_buffer, _offset);
_offset += 8;
ulong res = Get64(_buffer, Offset);
Offset += 8;
return res;
}
public string ReadString()
{
int ending = _offset;
int ending = Offset;
for (;;)
{
if (ending + 2 > _ending)
{
throw new EndOfStreamException();
}
if (_buffer[ending] == 0 && _buffer[ending + 1] == 0)
{
break;
}
ending += 2;
}
string str = Encoding.Unicode.GetString(_buffer, _offset, ending - _offset);
_offset = ending + 2;
string str = Encoding.Unicode.GetString(_buffer, Offset, ending - Offset);
Offset = ending + 2;
return str;
}

View File

@@ -7,79 +7,37 @@ namespace SharpCompress.Common.SevenZip
{
internal SevenZipEntry(SevenZipFilePart filePart)
{
this.FilePart = filePart;
FilePart = filePart;
}
internal SevenZipFilePart FilePart { get; private set; }
internal SevenZipFilePart FilePart { get; }
public override CompressionType CompressionType
{
get { return FilePart.CompressionType; }
}
public override CompressionType CompressionType => FilePart.CompressionType;
public override long Crc
{
get { return FilePart.Header.Crc ?? 0; }
}
public override long Crc => FilePart.Header.Crc ?? 0;
public override string Key
{
get { return FilePart.Header.Name; }
}
public override string Key => FilePart.Header.Name;
public override long CompressedSize
{
get { return 0; }
}
public override long CompressedSize => 0;
public override long Size
{
get { return (long) FilePart.Header.Size; }
}
public override long Size => FilePart.Header.Size;
public override DateTime? LastModifiedTime
{
get { return FilePart.Header.MTime; }
}
public override DateTime? LastModifiedTime => FilePart.Header.MTime;
public override DateTime? CreatedTime
{
get { return null; }
}
public override DateTime? CreatedTime => null;
public override DateTime? LastAccessedTime
{
get { return null; }
}
public override DateTime? LastAccessedTime => null;
public override DateTime? ArchivedTime
{
get { return null; }
}
public override DateTime? ArchivedTime => null;
public override bool IsEncrypted
{
get { return false; }
}
public override bool IsEncrypted => false;
public override bool IsDirectory
{
get { return FilePart.Header.IsDir; }
}
public override bool IsDirectory => FilePart.Header.IsDir;
public override bool IsSplit
{
get { return false; }
}
public override bool IsSplit => false;
public override int? Attrib
{
get { return (int) FilePart.Header.Attrib; }
}
public override int? Attrib => (int)FilePart.Header.Attrib;
internal override IEnumerable<FilePart> Parts
{
get { return FilePart.AsEnumerable<FilePart>(); }
}
internal override IEnumerable<FilePart> Parts => FilePart.AsEnumerable<FilePart>();
}
}

View File

@@ -7,14 +7,15 @@ namespace SharpCompress.Common.SevenZip
{
internal class SevenZipFilePart : FilePart
{
private CompressionType? type;
private Stream stream;
private ArchiveDatabase database;
private CompressionType? _type;
private readonly Stream _stream;
private readonly ArchiveDatabase _database;
internal SevenZipFilePart(Stream stream, ArchiveDatabase database, int index, CFileItem fileEntry)
internal SevenZipFilePart(Stream stream, ArchiveDatabase database, int index, CFileItem fileEntry, ArchiveEncoding archiveEncoding)
: base(archiveEncoding)
{
this.stream = stream;
this.database = database;
this._stream = stream;
this._database = database;
Index = index;
Header = fileEntry;
if (Header.HasStream)
@@ -24,14 +25,11 @@ namespace SharpCompress.Common.SevenZip
}
internal Stream BaseStream { get; private set; }
internal CFileItem Header { get; private set; }
internal CFolder Folder { get; private set; }
internal int Index { get; private set; }
internal CFileItem Header { get; }
internal CFolder Folder { get; }
internal int Index { get; }
internal override string FilePartName
{
get { return Header.Name; }
}
internal override string FilePartName => Header.Name;
internal override Stream GetRawStream()
{
@@ -44,14 +42,14 @@ namespace SharpCompress.Common.SevenZip
{
return null;
}
var folderStream = database.GetFolderStream(stream, Folder, null);
var folderStream = _database.GetFolderStream(_stream, Folder, _database.PasswordProvider);
int firstFileIndex = database.FolderStartFileIndex[database.Folders.IndexOf(Folder)];
int firstFileIndex = _database.FolderStartFileIndex[_database.Folders.IndexOf(Folder)];
int skipCount = Index - firstFileIndex;
long skipSize = 0;
for (int i = 0; i < skipCount; i++)
{
skipSize += database.Files[firstFileIndex + i].Size;
skipSize += _database.Files[firstFileIndex + i].Size;
}
if (skipSize > 0)
{
@@ -64,11 +62,11 @@ namespace SharpCompress.Common.SevenZip
{
get
{
if (type == null)
if (_type == null)
{
type = GetCompression();
_type = GetCompression();
}
return type.Value;
return _type.Value;
}
}
@@ -87,20 +85,20 @@ namespace SharpCompress.Common.SevenZip
{
var coder = Folder.Coders.First();
switch (coder.MethodId.Id)
{
{
case k_LZMA:
case k_LZMA2:
{
return CompressionType.LZMA;
}
{
return CompressionType.LZMA;
}
case k_PPMD:
{
return CompressionType.PPMd;
}
{
return CompressionType.PPMd;
}
case k_BZip2:
{
return CompressionType.BZip2;
}
{
return CompressionType.BZip2;
}
default:
throw new NotImplementedException();
}

View File

@@ -1,11 +1,13 @@
using System.IO;
using SharpCompress.Archives;
using SharpCompress.Readers;
namespace SharpCompress.Common.SevenZip
{
public class SevenZipVolume : Volume
{
public SevenZipVolume(Stream stream, Options options)
: base(stream, options)
public SevenZipVolume(Stream stream, ReaderOptions readerFactoryOptions)
: base(stream, readerFactoryOptions)
{
}
}

View File

@@ -0,0 +1,20 @@
namespace SharpCompress.Common.Tar
{
internal enum EntryType : byte
{
File = 0,
OldFile = (byte)'0',
HardLink = (byte)'1',
SymLink = (byte)'2',
CharDevice = (byte)'3',
BlockDevice = (byte)'4',
Directory = (byte)'5',
Fifo = (byte)'6',
LongLink = (byte)'K',
LongName = (byte)'L',
SparseFile = (byte)'S',
VolumeHeader = (byte)'V',
GlobalExtendedHeader = (byte)'g',
PosixExtendedHeader = (byte)'x'
}
}

View File

@@ -1,19 +0,0 @@
namespace SharpCompress.Common.Tar.Headers
{
internal enum EntryType : byte
{
File = 0,
OldFile = (byte) '0',
HardLink = (byte) '1',
SymLink = (byte) '2',
CharDevice = (byte) '3',
BlockDevice = (byte) '4',
Directory = (byte) '5',
Fifo = (byte) '6',
LongLink = (byte) 'K',
LongName = (byte) 'L',
SparseFile = (byte) 'S',
VolumeHeader = (byte) 'V',
GlobalExtendedHeader = (byte) 'g',
}
}

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