Compare commits

...

151 Commits

Author SHA1 Message Date
Adam Hathcock
3fa7e854d3 Merge pull request #948 from adamhathcock/adam/update-0410
update to 0.41.0 and change symbols type
2025-10-13 12:32:54 +01:00
Adam Hathcock
0f5c080be6 update to 0.41.0 and change symbols type 2025-10-13 12:29:02 +01:00
Adam Hathcock
871009ef8d Merge pull request #947 from adamhathcock/adam/update-deps
Update dependencies and csharpier
2025-10-13 12:13:51 +01:00
Adam Hathcock
89a565c6c4 format 2025-10-13 12:10:42 +01:00
Adam Hathcock
6ed60e4d5f adjust Microsoft.NETFramework.ReferenceAssemblies 2025-10-13 12:08:39 +01:00
Adam Hathcock
4dab1df3ae adjust usage of sourcelink 2025-10-13 12:06:34 +01:00
Adam Hathcock
7b7aa2cdf0 Merge remote-tracking branch 'origin/master' into adam/update-deps 2025-10-13 11:56:50 +01:00
Adam Hathcock
d1e1a65f32 add agents file 2025-10-13 11:55:41 +01:00
Adam Hathcock
9d332b4ac5 add agents file 2025-10-13 11:52:18 +01:00
Adam Hathcock
fc2462e281 Update dependencies and csharpier 2025-10-13 10:40:43 +01:00
Adam Hathcock
fb2cddabf0 Merge pull request #945 from mitchcapper/archive_extension_hinting_pr
Extension hinting for ReaderFactory for better first try factory success
2025-09-29 09:02:11 +01:00
Mitch Capper
33481a9465 Extension hinting for ReaderFactory for better first try factory success
Also used by TarFactory to hint what compressiontype to attempt first
2025-09-24 00:04:07 -07:00
Adam Hathcock
45de87cb97 Merge pull request #943 from mitchcapper/zstandard_reading_pr
ZStandard tar support
2025-09-23 13:34:26 +01:00
Mitch Capper
553c533ada ZStandard tar support 2025-09-23 03:26:33 -07:00
Adam Hathcock
634e562b93 Merge pull request #935 from Nanook/bugfix/StreamBufferFix
Rewind buffer fix for directory extract.
2025-08-22 14:08:39 +01:00
Adam Hathcock
c789ead590 Merge branch 'master' into bugfix/StreamBufferFix 2025-08-22 14:05:35 +01:00
Adam Hathcock
d23560a441 Merge pull request #939 from Morilli/fix-winaescryptostream-dispose
Fix WinzipAesCryptoStream potentially not getting disposed
2025-08-22 14:03:06 +01:00
Morilli
9f306966db Adjust logic in CreateDecompressionStream to not wrap the returned stream
a ReadOnlySubStream never disposes its passes in stream which is problematic when that stream needs to be disposed. It's hard to tell who exactly has ownership over which stream here, but I'll just assume that whatever stream is passed in here should be disposed.
2025-08-21 20:08:57 +02:00
Morilli
8eea2cef97 add failing test 2025-08-21 20:08:34 +02:00
Nanook
3abbb89c2e Comment typo edit. 2025-08-01 21:50:36 +01:00
Nanook
76de7d54c7 Rewind buffer fix for directory extract. 2025-08-01 21:47:09 +01:00
Adam Hathcock
35aee6e066 Merge pull request #934 from Nanook/feature/zstd_zip_writing
Zip ZStandard Writing with tests. Level support.
2025-07-24 08:24:32 +01:00
Nanook
8a0152fe7c Fixed up test issue after copilot "fixes" :S. 2025-07-24 01:33:18 +01:00
Nanook
7769435fc8 CSharpier fixes after copilot tweaks. 2025-07-24 01:31:30 +01:00
Nanook
ae311ea66e Update tests/SharpCompress.Test/Zip/TestPseudoTextStream.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-24 01:28:56 +01:00
Nanook
d15816f162 Update tests/SharpCompress.Test/Zip/TestPseudoTextStream.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-24 01:28:40 +01:00
Nanook
5cbb31c559 Update tests/SharpCompress.Test/Zip/TestPseudoTextStream.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-24 01:28:23 +01:00
Nanook
b7f5b36f2b Update src/SharpCompress/Writers/Zip/ZipWriter.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-24 01:28:11 +01:00
Nanook
e9dd413de6 CSharpier formatting. 2025-07-24 00:46:09 +01:00
Nanook
c5de3d8cc1 Zip ZStandard Writing with tests. Level support. 2025-07-24 00:23:55 +01:00
Adam Hathcock
624c385e27 Merge pull request #930 from Nanook/feature/StreamStack
Added IStreamStack for debugging and configurable buffer management. …
2025-07-23 08:48:58 +01:00
Adam Hathcock
893890c985 Merge branch 'master' into feature/StreamStack 2025-07-23 08:46:16 +01:00
Adam Hathcock
e12efc8b52 Merge pull request #933 from Morilli/zipentry-attribute
Implement `Attrib` for `ZipEntry`
2025-07-23 08:45:04 +01:00
Morilli
015dfa41b1 implement Attrib for ZipEntrys 2025-07-22 20:12:22 +02:00
Morilli
5e72ce5fbe add failing test 2025-07-22 20:11:13 +02:00
Adam Hathcock
236e653176 Merge branch 'master' into feature/StreamStack 2025-07-22 11:55:57 +01:00
Adam Hathcock
3946c3ba03 Merge pull request #931 from SimonCahill/feat/add-throw-on-unseekable-stream
Added ArgumentException to Archive.Open implementations
2025-07-22 11:54:23 +01:00
Adam Hathcock
5bdd39e6eb Merge branch 'master' into feat/add-throw-on-unseekable-stream 2025-07-22 11:50:04 +01:00
Adam Hathcock
46267c0531 Merge pull request #929 from Morilli/fix-zipentry-comment
Fix zipentry comment implementation
2025-07-22 11:49:12 +01:00
Adam Hathcock
7b96eb7704 Merge pull request #928 from Morilli/fix-dotsettings
fix DotSettings options to conform to current code style and editorconfig
2025-07-22 11:47:36 +01:00
Nanook
60d5955101 Final tidy. 2025-07-22 00:12:30 +01:00
Nanook
587675e488 Fixed some missing features caused by merging an earlier branch than required. 2025-07-21 23:45:57 +01:00
Simon Cahill
c0ae319c63 Reverted debug change 2025-07-21 15:41:33 +02:00
Simon Cahill
d810f8d8db Reverted back; I don't know how this file changed 2025-07-21 15:38:14 +02:00
Simon Cahill
a88390a546 Added ArgumentException which is thrown when a non-seekable Stream instance is passed 2025-07-21 15:34:03 +02:00
Nanook
8575e5615d Formatting fix. 2025-07-20 19:18:31 +01:00
Nanook
5fe9516c09 Various copilot suggestions. Tests still passing. 2025-07-20 19:16:11 +01:00
Nanook
938775789d Formated with Sharpier. 2025-07-20 18:11:37 +01:00
Nanook
f37bebe51f Merge branch 'master' into feature/StreamStack 2025-07-20 17:46:28 +01:00
Nanook
21f14cd3f2 Added IStreamStack for debugging and configurable buffer management. Added SharpCompressStream to consolodate streams to help simplify debugging. All unit tests passing. 2025-07-20 17:35:22 +01:00
Morilli
4e7baeb2c9 fix zipentry comment being lost after reading local entry header 2025-07-19 19:56:41 +02:00
Morilli
d78a682dd8 add failing test 2025-07-19 19:56:38 +02:00
Morilli
44021b7abc fix DotSettings options to conform to current code style and editorconfig 2025-07-19 19:30:52 +02:00
Adam Hathcock
7f9e543213 Merge pull request #924 from Morilli/7zip-1block-solid-archive
Fix 7-zip solid archive detection
2025-07-14 09:12:43 +01:00
Morilli
c489e5a59b fix SevenZipArchive solid detection 2025-07-13 15:09:59 +02:00
Morilli
8de30db7f9 add failing test 2025-07-13 15:08:45 +02:00
Adam Hathcock
415f0c6774 Merge pull request #921 from Morilli/fix-volume-filename
Fix volume FileName property potentially missing
2025-07-07 09:22:45 +01:00
Morilli
aa9cf195a5 Fix volume FileName property potentially missing 2025-07-06 21:56:54 +02:00
Adam Hathcock
6412fc8135 Mark for 0.40 2025-06-03 08:48:34 +01:00
Adam Hathcock
8b1ba9a00c Merge pull request #914 from adamhathcock/update-deps
Update dependencies and csharpier
2025-06-03 08:33:18 +01:00
Adam Hathcock
b02584ef9e Update deps again 2025-06-03 08:30:28 +01:00
Adam Hathcock
88cd6bfd1a Merge remote-tracking branch 'origin/master' into update-deps 2025-06-03 08:13:41 +01:00
Adam Hathcock
89a3da14c9 Merge pull request #918 from Morilli/fix-bzip2-selector-oob
[bzip2] fix possible out of bounds access due to unsanitized nSelectors usage
2025-06-03 08:11:55 +01:00
Morilli
619d987492 fix possible out of bounds access due to unsanitized nSelectors usage 2025-06-02 21:24:38 +02:00
Adam Hathcock
744e410a1a Merge pull request #916 from Morilli/rar-multipart-reader
Implement multipart rar handling for ExtractAllEntries
2025-05-14 11:33:12 +01:00
Morilli
6e51967993 format 2025-05-14 11:42:52 +02:00
Morilli
7989ab2e28 modify now-broken test
This test tested that skipping over entries using the reader interface for an encrypted multi-volume rar archive worked.
However reading those entries doesn't work and the skipping was also not working properly so I believe it's fine to "break" this functionality.
2025-05-14 11:18:41 +02:00
Morilli
a3570a568d fix AbstractReader.Skip for multipart files 2025-05-14 10:27:58 +02:00
Morilli
c0cd998836 add failing test 2025-05-14 10:27:30 +02:00
Morilli
1a452acd1c implement ExtractAllEntries for multipart rar files 2025-05-14 10:27:18 +02:00
Adam Hathcock
6c54083b08 Merge remote-tracking branch 'origin/master' into update-deps 2025-04-28 16:30:40 +01:00
Adam Hathcock
76105ebdaf fix bullseye 2025-04-28 16:30:28 +01:00
Adam Hathcock
2c452201fa Merge pull request #854 from zgabi/patch-1
return Stream.Null when 7z entry has no stream
2025-04-28 16:26:58 +01:00
Adam Hathcock
9fc7fc73f9 Merge branch 'master' into patch-1 2025-04-28 16:21:20 +01:00
Adam Hathcock
e7417e35ba Update dependencies and csharpier 2025-04-28 16:18:01 +01:00
Adam Hathcock
19eb4c7cba Merge pull request #834 from adamhathcock/exception-normalization
Add SharpCompressException and use it or children in most places
2025-04-28 16:12:25 +01:00
Adam Hathcock
1f39a0c9da Merge remote-tracking branch 'origin/master' into exception-normalization
# Conflicts:
#	src/SharpCompress/Readers/ReaderFactory.cs
2025-04-28 16:08:08 +01:00
Adam Hathcock
a480a8893c format 2025-04-28 16:06:00 +01:00
Adam Hathcock
d3a9e341a5 Merge fixes 2025-04-28 16:05:31 +01:00
Adam Hathcock
95caffe607 Merge remote-tracking branch 'origin/master' into exception-normalization
# Conflicts:
#	src/SharpCompress/Common/Rar/RarVolume.cs
#	src/SharpCompress/Common/SevenZip/SevenZipFilePart.cs
#	src/SharpCompress/Compressors/LZMA/LZipStream.cs
2025-04-28 15:59:34 +01:00
Adam Hathcock
fdeca61284 Merge pull request #913 from jdpurcell/pr-bss-fix
Fix regression with BufferedSubStream calculation
2025-03-26 09:00:38 +00:00
J.D. Purcell
45dc653191 Fix regression with size calculation 2025-03-25 20:43:14 -04:00
Adam Hathcock
6e48302b7b Merge pull request #912 from jdpurcell/pr-bss-optim
Optimize BufferedSubStream.ReadByte
2025-03-25 08:04:38 +00:00
J.D. Purcell
a7918d7b11 Optimize BufferedSubStream.ReadByte 2025-03-24 21:28:08 -04:00
Adam Hathcock
ec21253af9 Merge pull request #909 from Morilli/update-usage
Update USAGE.md to remove problematic extraction example
2025-03-24 08:20:17 +00:00
Adam Hathcock
97cdda8663 Merge branch 'master' into update-usage 2025-03-24 08:18:16 +00:00
Adam Hathcock
35ac2b9d71 Merge pull request #910 from jdpurcell/pr-rangedecoderoptim
Optimize LZMA range decoder
2025-03-24 08:17:28 +00:00
J.D. Purcell
14affd8ffa Optimize LZMA range decoder 2025-03-22 17:14:38 -04:00
Morilli
c48409c903 Update USAGE.md
added an explanatory comment to the ExtractAllEntries usage and removed the problematic previous code.

I've added a new example for iterating over entries that doesn't extract them.
2025-03-22 16:50:15 +01:00
Adam Hathcock
227f66f299 Merge pull request #907 from jdpurcell/pr-copyblockoptim
Optimize LZ OutWindow.CopyBlock
2025-03-20 08:24:39 +00:00
J.D. Purcell
c2d9bf94d1 Optimize LZ OutWindow.CopyBlock 2025-03-19 22:29:38 -04:00
Adam Hathcock
8f03841161 Merge pull request #906 from TwanVanDongen/master
Added ARC's crunched methods 5, 6, 7 & 8
2025-03-17 08:30:12 +00:00
Twan van Dongen
344a1ed912 Merge branch 'master' of https://github.com/TwanVanDongen/sharpcompress 2025-03-14 19:09:56 +01:00
Twan van Dongen
ff71993b31 Trying to overcome differences in charpier versions... 2025-03-14 19:09:52 +01:00
Twan van Dongen
18bb773b2c Merge branch 'master' of https://github.com/TwanVanDongen/sharpcompress 2025-03-14 19:06:14 +01:00
Twan van Dongen
7f905c7940 More csharpier stuff 2025-03-14 19:06:10 +01:00
Twan van Dongen
8a4ba6fc56 Removed empty lineRemoved failing test 2025-03-14 19:03:54 +01:00
Twan van Dongen
e0b275c01c Removed empty line for CSharpier 2025-03-14 19:01:07 +01:00
Twan van Dongen
5926db85df Added ARC's crunched methods 5, 6, 7 & 8 2025-03-14 18:58:34 +01:00
Adam Hathcock
a4715a10e7 Merge pull request #905 from TwanVanDongen/master
ARC decompression methods 3 and 4 added
2025-03-12 08:21:57 +00:00
Twan van Dongen
de0f5c0fcb Merge branch 'master' of https://github.com/TwanVanDongen/sharpcompress 2025-03-11 20:20:45 +01:00
Twan van Dongen
88d85ce6ac Extra line removed for csharpier 2025-03-11 20:20:41 +01:00
Twan van Dongen
131c171d3e Merge branch 'master' of https://github.com/TwanVanDongen/sharpcompress 2025-03-11 20:16:24 +01:00
Twan van Dongen
c5ddef6ef7 An exception occurred in ReadOnlySubStream when attempting to set the position to the same value. 2025-03-11 20:15:53 +01:00
Twan van Dongen
f36486d006 Merge branch 'master' of https://github.com/TwanVanDongen/sharpcompress 2025-03-11 18:57:52 +01:00
Twan van Dongen
eaf466c5c3 Implementation of squeezed and packed compression algorithms for .ARC archive format 2025-03-11 18:15:53 +01:00
Adam Hathcock
b41bcc349e Merge pull request #903 from TwanVanDongen/master
Base Reader implementation of .ARC format
2025-03-10 08:55:43 +00:00
Adam Hathcock
825c61bdcd Merge branch 'master' into master 2025-03-10 08:51:58 +00:00
Adam Hathcock
f13f49bd71 Merge pull request #904 from jdpurcell/pr-7zattr
Provide access to extended attributes for 7-zip
2025-03-10 08:49:33 +00:00
J.D. Purcell
88f5d4544b Add SevenZipEntry ExtendedAttrib property 2025-03-09 17:16:55 -04:00
J.D. Purcell
b7432a20f0 Remove some unused internal members 2025-03-09 17:16:55 -04:00
Twan van Dongen
ab57c85e66 Missing comma added for csharpier 2025-03-09 18:45:27 +01:00
Twan van Dongen
c7c41bc0d8 Missing comma added for csharpier checksBase Reader implementation of .ARC format 2025-03-09 18:40:43 +01:00
Twan van Dongen
c66f9b06a4 Base Reader implementation of .ARC format 2025-03-09 18:22:52 +01:00
Adam Hathcock
a3ac7e7ca7 Merge pull request #901 from ms264556/feature/sha256-quick-fix
Handle XZ CheckType SHA-256
2025-03-07 10:52:24 +00:00
ms264556
187b762f8a Corrected XZ BlockCheckSize formula 2025-03-07 19:53:49 +13:00
ms264556
3a7fbdfa52 Handle XZ CheckType SHA-256 2025-03-07 14:46:07 +13:00
Adam Hathcock
bbeb46b37f Merge pull request #900 from Morilli/WriteToDirectory-reader
make WriteToDirectory functions use ExtractAllEntries
2025-03-03 08:32:00 +00:00
Morilli
5450b9a700 make WriteToDirectory functions use ExtractAllEntries
for extracting files from solid archives this can be required to get acceptable extraction performance and should therefore always be called.
2025-02-28 21:46:04 +01:00
Adam Hathcock
353b28647c Merge pull request #897 from Morilli/bufferedsubstream-readbyte
Implement ReadByte for BufferedSubStream
2025-02-17 08:07:14 +00:00
Adam Hathcock
2411f4f870 Merge branch 'master' into bufferedsubstream-readbyte 2025-02-17 08:05:02 +00:00
Adam Hathcock
34cd059423 Merge pull request #898 from Morilli/lz-readbyte
Implement ReadByte for LzmaStream and LzOutWindow
2025-02-17 08:04:34 +00:00
Morilli
4b4ec12c87 Implement ReadByte for LzmaStream and LzOutWindow 2025-02-16 18:37:56 +01:00
Morilli
441147c0dc Implement ReadByte for BufferedSubStream 2025-02-16 13:41:46 +01:00
Adam Hathcock
08ceac9f46 Merge pull request #896 from adamhathcock/rar_unpack20_audio_fix
Rar2 v20,v26 Multimedia (Audio) decoder fix
2025-02-12 08:25:38 +00:00
Nanook
6bc690b50b Seriously? 2025-02-11 23:10:03 +00:00
Nanook
c41888b338 Rar2 v20,v26 Multimedia (Audio) decoder fix 2025-02-11 22:30:59 +00:00
Adam Hathcock
6d3c980b39 Merge pull request #894 from Morilli/fix-rare-solid-rar-failure
Fix condition in rar v3 code
2025-02-11 11:39:17 +00:00
Morilli
eb5db176fa revert change to rar5 code
... yeah... apparently the thing that fixes rar3 code breaks rar5 code
2025-02-11 11:21:51 +01:00
Morilli
a77c03fcaf add comment and change the same code in new Unpack50 2025-02-11 11:03:56 +01:00
Adam Hathcock
04b25011e9 Merge branch 'master' into fix-rare-solid-rar-failure 2025-02-11 08:31:49 +00:00
Adam Hathcock
96b34aec10 Merge pull request #895 from Morilli/fix-test-concurrency
use File.OpenRead instead of File.Open in tests to allow concurrent access
2025-02-11 08:30:12 +00:00
Morilli
d560b46c85 use File.OpenRead instead of File.Open to allow concurrent access 2025-02-11 03:31:49 +01:00
Morilli
94789ce455 Fix condition in rar v3 code 2025-02-11 03:04:18 +01:00
Adam Hathcock
55797e5873 Merge pull request #893 from adamhathcock/rar_unpack20
Fix for Rar4 v20 compression.
2025-02-10 09:27:27 +00:00
Nanook
675cab3074 Fix for Rar4 v20 compression. 2025-02-07 22:39:33 +00:00
Adam Hathcock
8d63ab646e Merge pull request #891 from Morilli/fix-zip-datadescriptor-header
Fix zip entry handling for entries with data descriptors
2025-01-28 08:12:40 +00:00
Adam Hathcock
37a2fa1cdc Merge branch 'master' into fix-zip-datadescriptor-header 2025-01-28 08:08:55 +00:00
Adam Hathcock
79ed9650b3 Merge pull request #892 from adamhathcock/fix-tests
don't run net48 on non-windows
2025-01-28 08:08:41 +00:00
Adam Hathcock
b6dc58164e don't run net48 on non-windows 2025-01-28 08:04:59 +00:00
Morilli
f9a974c1fe fix formatting 2025-01-28 02:24:42 +01:00
Morilli
91e672befb remove old hack trying to fix a similar thing
Introduced in af264cdc58c9d076bf83477cbdbfe7a5dad282b7; the test included in that commit passes still.
2025-01-28 02:12:16 +01:00
Morilli
c14d18b9df set local header data from directory header when flag is set
As described in section 4.4.7-4.4.9 of the zip specification when this flag is set the correct values will be in the data descriptor record and in the directory header.
2025-01-28 01:56:14 +01:00
Morilli
d2cfc1844c add failing test 2025-01-28 01:49:49 +01:00
Adam Hathcock
2fb3243a1a Tests also on net48 2025-01-16 08:38:11 +00:00
Zavarkó Gábor
471a3f63fe return Stream.Null when 7z entry has no stream 2024-07-07 00:14:00 +02:00
Adam Hathcock
5d9c99508d fmt 2024-04-23 15:08:50 +01:00
Adam Hathcock
e4d5b56951 fix more nulls and tests 2024-04-23 15:08:32 +01:00
Adam Hathcock
e31238d121 fmt 2024-04-23 14:48:50 +01:00
Adam Hathcock
a283d99e1b compiles 2024-04-23 14:48:33 +01:00
Adam Hathcock
8cb621ebed Add SharpCompressException and use it or children in most places 2024-04-23 14:47:40 +01:00
219 changed files with 7884 additions and 3974 deletions

View File

@@ -3,9 +3,9 @@
"isRoot": true,
"tools": {
"csharpier": {
"version": "0.30.6",
"version": "1.1.2",
"commands": [
"dotnet-csharpier"
"csharpier"
],
"rollForward": false
}

64
AGENTS.md Normal file
View File

@@ -0,0 +1,64 @@
---
description: 'Guidelines for building C# applications'
applyTo: '**/*.cs'
---
# C# Development
## C# Instructions
- Always use the latest version C#, currently C# 13 features.
- Write clear and concise comments for each function.
## General Instructions
- Make only high confidence suggestions when reviewing code changes.
- Write code with good maintainability practices, including comments on why certain design decisions were made.
- Handle edge cases and write clear exception handling.
- For libraries or external dependencies, mention their usage and purpose in comments.
## Naming Conventions
- Follow PascalCase for component names, method names, and public members.
- Use camelCase for private fields and local variables.
- Prefix interface names with "I" (e.g., IUserService).
## Code Formatting
- Use CSharpier for all code formatting to ensure consistent style across the project.
- Install CSharpier globally: `dotnet tool install -g csharpier`
- Format files with: `dotnet csharpier format .`
- Configure your IDE to format on save using CSharpier.
- CSharpier configuration can be customized via `.csharpierrc` file in the project root.
- Trust CSharpier's opinionated formatting decisions to maintain consistency.
## Project Setup and Structure
- Guide users through creating a new .NET project with the appropriate templates.
- Explain the purpose of each generated file and folder to build understanding of the project structure.
- Demonstrate how to organize code using feature folders or domain-driven design principles.
- Show proper separation of concerns with models, services, and data access layers.
- Explain the Program.cs and configuration system in ASP.NET Core 9 including environment-specific settings.
## Nullable Reference Types
- Declare variables non-nullable, and check for `null` at entry points.
- Always use `is null` or `is not null` instead of `== null` or `!= null`.
- Trust the C# null annotations and don't add null checks when the type system says a value cannot be null.
## Testing
- Always include test cases for critical paths of the application.
- Guide users through creating unit tests.
- Do not emit "Act", "Arrange" or "Assert" comments.
- Copy existing style in nearby files for test method names and capitalization.
- Explain integration testing approaches for API endpoints.
- Demonstrate how to mock dependencies for effective testing.
- Show how to test authentication and authorization logic.
- Explain test-driven development principles as applied to API development.
## Performance Optimization
- Guide users on implementing caching strategies (in-memory, distributed, response caching).
- Explain asynchronous programming patterns and why they matter for API performance.
- Demonstrate pagination, filtering, and sorting for large data sets.
- Show how to implement compression and other performance optimizations.
- Explain how to measure and benchmark API performance.

View File

@@ -1,19 +1,20 @@
<Project>
<ItemGroup>
<PackageVersion Include="Bullseye" Version="5.0.0" />
<PackageVersion Include="FluentAssertions" Version="7.0.0" />
<PackageVersion Include="Bullseye" Version="6.0.0" />
<PackageVersion Include="AwesomeAssertions" Version="9.2.0" />
<PackageVersion Include="Glob" Version="1.1.9" />
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="8.0.0" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.13.0" />
<PackageVersion Include="Mono.Posix.NETStandard" Version="1.0.0" />
<PackageVersion Include="SimpleExec" Version="12.0.0" />
<PackageVersion Include="System.Buffers" Version="4.6.0" />
<PackageVersion Include="System.Memory" Version="4.6.0" />
<PackageVersion Include="System.Text.Encoding.CodePages" Version="8.0.0" />
<PackageVersion Include="xunit" Version="2.9.3" />
<PackageVersion Include="xunit.runner.visualstudio" Version="3.0.1" />
<PackageVersion Include="xunit.runner.visualstudio" Version="3.1.5" />
<PackageVersion Include="xunit.SkippableFact" Version="1.5.23" />
<PackageVersion Include="ZstdSharp.Port" Version="0.8.4" />
<GlobalPackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" />
<PackageVersion Include="ZstdSharp.Port" Version="0.8.6" />
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="8.0.0" />
<PackageVersion Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.3" />
</ItemGroup>
</Project>

View File

@@ -15,6 +15,7 @@
| Tar | None | Both | TarArchive | TarReader | TarWriter (3) |
| Tar.GZip | DEFLATE | Both | TarArchive | TarReader | TarWriter (3) |
| Tar.BZip2 | BZip2 | Both | TarArchive | TarReader | TarWriter (3) |
| Tar.Zstandard | ZStandard | Decompress | TarArchive | TarReader | N/A |
| Tar.LZip | LZMA | Both | TarArchive | TarReader | TarWriter (3) |
| Tar.XZ | LZMA2 | Decompress | TarArchive | TarReader | TarWriter (3) |
| GZip (single file) | DEFLATE | Both | GZipArchive | GZipReader | GZipWriter |
@@ -41,6 +42,7 @@ For those who want to directly compress/decompress bits. The single file formats
| ADCStream | Decompress |
| LZipStream | Both |
| XZStream | Decompress |
| ZStandardStream | Decompress |
## Archive Formats vs Compression

View File

@@ -1,6 +1,6 @@
# SharpCompress
SharpCompress is a compression library in pure C# for .NET Framework 4.62, .NET Standard 2.1, .NET 6.0 and NET 8.0 that can unrar, un7zip, unzip, untar unbzip2, ungzip, unlzip with forward-only reading and file random access APIs. Write support for zip/tar/bzip2/gzip/lzip are implemented.
SharpCompress is a compression library in pure C# for .NET Framework 4.62, .NET Standard 2.1, .NET 6.0 and NET 8.0 that can unrar, un7zip, unzip, untar unbzip2, ungzip, unlzip, unzstd with forward-only reading and file random access APIs. Write support for zip/tar/bzip2/gzip/lzip are implemented.
The major feature is support for non-seekable streams so large files can be processed on the fly (i.e. download stream).
@@ -20,10 +20,12 @@ In general, I recommend GZip (Deflate)/BZip2 (BZip)/LZip (LZMA) as the simplicit
Zip is okay, but it's a very hap-hazard format and the variation in headers and implementations makes it hard to get correct. Uses Deflate by default but supports a lot of compression methods.
RAR is not recommended as it's a propriatory format and the compression is closed source. Use Tar/LZip for LZMA
RAR is not recommended as it's a proprietary 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.
ZStandard is an efficient format that works well for streaming with a flexible compression level to tweak the speed/performance trade off you are looking for. We currently only implement decompression for ZStandard but as we leverage the [ZstdSharp](https://github.com/oleg-st/ZstdSharp) library one could likely add compression support without much trouble (PRs are welcome!).
## A Simple Request
Hi everyone. I hope you're using SharpCompress and finding it useful. Please give me feedback on what you'd like to see changed especially as far as usability goes. New feature suggestions are always welcome as well. I would also like to know what projects SharpCompress is being used in. I like seeing how it is used to give me ideas for future versions. Thanks!
@@ -40,6 +42,7 @@ I'm always looking for help or ideas. Please submit code or email with ideas. Un
* 7Zip writing
* Zip64 (Need writing and extend Reading)
* Multi-volume Zip support.
* ZStandard writing
## Version Log

View File

@@ -20,6 +20,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Config", "Config", "{CDB425
.editorconfig = .editorconfig
Directory.Packages.props = Directory.Packages.props
NuGet.config = NuGet.config
.github\workflows\dotnetcore.yml = .github\workflows\dotnetcore.yml
EndProjectSection
EndProject
Global

View File

@@ -15,17 +15,17 @@
<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/ARGUMENTS_NAMED/@EntryValue">Positional</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_FIRST_ARG_BY_PAREN/@EntryValue">False</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_ARRAY_AND_OBJECT_INITIALIZER/@EntryValue">False</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_EXPRESSION/@EntryValue">False</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>
@@ -42,7 +42,7 @@
<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:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/INDENT_ANONYMOUS_METHOD_BLOCK/@EntryValue">False</s:Boolean>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/KEEP_BLANK_LINES_IN_CODE/@EntryValue">1</s:Int64>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/KEEP_BLANK_LINES_IN_DECLARATIONS/@EntryValue">1</s:Int64>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_ACCESSOR_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String>
@@ -50,12 +50,12 @@
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_CONSTRUCTOR_INITIALIZER_ON_SAME_LINE/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_FIELD_ATTRIBUTE_ON_SAME_LINE/@EntryValue">False</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_FIELD_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_ACCESSORHOLDER_ON_SINGLE_LINE/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_ACCESSORHOLDER_ON_SINGLE_LINE/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_ACCESSOR_ATTRIBUTE_ON_SAME_LINE/@EntryValue">False</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_EMBEDDED_STATEMENT_ON_SAME_LINE/@EntryValue">NEVER</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_INITIALIZER_ON_SINGLE_LINE/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_INITIALIZER_ON_SINGLE_LINE/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_WHILE_ON_NEW_LINE/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_WHILE_ON_NEW_LINE/@EntryValue">False</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>
@@ -67,13 +67,13 @@
<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_ARRAY_INITIALIZER_STYLE/@EntryValue">CHOP_ALWAYS</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/CSharpVarKeywordUsage/ForBuiltInTypes/@EntryValue">UseVar</s:String>
<s:String x:Key="/Default/CodeStyle/CSharpVarKeywordUsage/ForOtherTypes/@EntryValue">UseVar</s:String>
<s:String x:Key="/Default/CodeStyle/CSharpVarKeywordUsage/ForSimpleTypes/@EntryValue">UseVar</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>
@@ -122,6 +122,7 @@
<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:String x:Key="/Default/CustomTools/CustomToolsData/@EntryValue"></s:String>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpAttributeForSingleLineMethodUpgrade/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>

View File

@@ -71,18 +71,34 @@ using (var archive = ZipArchive.Create())
memoryStream.Position = 0;
```
### Extract all files from a Rar file to a directory using RarArchive
### Extract all files from a rar file to a directory using RarArchive
Note: Extracting a solid rar or 7z file needs to be done in sequential order to get acceptable decompression speed.
It is explicitly recommended to use `ExtractAllEntries` when extracting an entire `IArchive` instead of iterating over all its `Entries`.
Alternatively, use `IArchive.WriteToDirectory`.
```C#
using (var archive = RarArchive.Open("Test.rar"))
{
using (var reader = archive.ExtractAllEntries())
{
reader.WriteAllToDirectory(@"D:\temp", new ExtractionOptions()
{
ExtractFullPath = true,
Overwrite = true
});
}
}
```
### Iterate over all files from a Rar file 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
});
Console.WriteLine($"{entry.Key}: {entry.Size} bytes");
}
}
```

View File

@@ -15,7 +15,7 @@ const string Publish = "publish";
Target(
Clean,
ForEach("**/bin", "**/obj"),
["**/bin", "**/obj"],
dir =>
{
IEnumerable<string> GetDirectories(string d)
@@ -44,14 +44,14 @@ Target(
() =>
{
Run("dotnet", "tool restore");
Run("dotnet", "csharpier --check .");
Run("dotnet", "csharpier check .");
}
);
Target(Restore, DependsOn(Format), () => Run("dotnet", "restore"));
Target(Restore, [Format], () => Run("dotnet", "restore"));
Target(
Build,
DependsOn(Restore),
[Restore],
() =>
{
Run("dotnet", "build src/SharpCompress/SharpCompress.csproj -c Release --no-restore");
@@ -60,8 +60,8 @@ Target(
Target(
Test,
DependsOn(Build),
ForEach("net8.0", "net462"),
[Build],
["net8.0", "net48"],
framework =>
{
IEnumerable<string> GetFiles(string d)
@@ -69,7 +69,7 @@ Target(
return Glob.Files(".", d);
}
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && framework == "net462")
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && framework == "net48")
{
return;
}
@@ -83,13 +83,13 @@ Target(
Target(
Publish,
DependsOn(Test),
[Test],
() =>
{
Run("dotnet", "pack src/SharpCompress/SharpCompress.csproj -c Release -o artifacts/");
}
);
Target("default", DependsOn(Publish), () => Console.WriteLine("Done!"));
Target("default", [Publish], () => Console.WriteLine("Done!"));
await RunTargetsAndExitAsync(args);

View File

@@ -1,14 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Bullseye" />
<PackageReference Include="Glob" />
<PackageReference Include="SimpleExec" />
<PackageReference Include="SimpleExec" />
</ItemGroup>
</Project>

View File

@@ -4,9 +4,9 @@
"net8.0": {
"Bullseye": {
"type": "Direct",
"requested": "[5.0.0, )",
"resolved": "5.0.0",
"contentHash": "bqyt+m17ym+5aN45C5oZRAjuLDt8jKiCm/ys1XfymIXSkrTFwvI/QsbY3ucPSHDz7SF7uON7B57kXFv5H2k1ew=="
"requested": "[6.0.0, )",
"resolved": "6.0.0",
"contentHash": "vgwwXfzs7jJrskWH7saHRMgPzziq/e86QZNWY1MnMxd7e+De7E7EX4K3C7yrvaK9y02SJoLxNxcLG/q5qUAghw=="
},
"Glob": {
"type": "Direct",
@@ -14,31 +14,11 @@
"resolved": "1.1.9",
"contentHash": "AfK5+ECWYTP7G3AAdnU8IfVj+QpGjrh9GC2mpdcJzCvtQ4pnerAGwHsxJ9D4/RnhDUz2DSzd951O/lQjQby2Sw=="
},
"Microsoft.SourceLink.GitHub": {
"type": "Direct",
"requested": "[8.0.0, )",
"resolved": "8.0.0",
"contentHash": "G5q7OqtwIyGTkeIOAc3u2ZuV/kicQaec5EaRnc0pIeSnh9LUjj+PYQrJYBURvDt7twGl2PKA7nSN0kz1Zw5bnQ==",
"dependencies": {
"Microsoft.Build.Tasks.Git": "8.0.0",
"Microsoft.SourceLink.Common": "8.0.0"
}
},
"SimpleExec": {
"type": "Direct",
"requested": "[12.0.0, )",
"resolved": "12.0.0",
"contentHash": "ptxlWtxC8vM6Y6e3h9ZTxBBkOWnWrm/Sa1HT+2i1xcXY3Hx2hmKDZP5RShPf8Xr9D+ivlrXNy57ktzyH8kyt+Q=="
},
"Microsoft.Build.Tasks.Git": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "bZKfSIKJRXLTuSzLudMFte/8CempWjVamNUR5eHJizsy+iuOuO/k2gnh7W0dHJmYY0tBf+gUErfluCv5mySAOQ=="
},
"Microsoft.SourceLink.Common": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw=="
}
}
}

View File

@@ -53,7 +53,7 @@ public abstract class AbstractArchive<TEntry, TVolume> : IArchive, IArchiveExtra
{
if (!stream.CanSeek || !stream.CanRead)
{
throw new ArgumentException("Archive streams must be Readable and Seekable");
throw new ArchiveException("Archive streams must be Readable and Seekable");
}
return stream;
}

View File

@@ -151,7 +151,7 @@ public abstract class AbstractWritableArchive<TEntry, TVolume>
{
if (!source.CanRead || !source.CanSeek)
{
throw new ArgumentException(
throw new ArchiveException(
"Streams must be readable and seekable to use the Writing Archive API"
);
}

View File

@@ -4,6 +4,7 @@ using System.IO;
using System.Linq;
using SharpCompress.Common;
using SharpCompress.Factories;
using SharpCompress.IO;
using SharpCompress.Readers;
namespace SharpCompress.Archives;
@@ -19,7 +20,7 @@ public static class ArchiveFactory
public static IArchive Open(Stream stream, ReaderOptions? readerOptions = null)
{
readerOptions ??= new ReaderOptions();
stream = new SharpCompressStream(stream, bufferSize: readerOptions.BufferSize);
return FindFactory<IArchiveFactory>(stream).Open(stream, readerOptions);
}
@@ -122,10 +123,7 @@ public static class ArchiveFactory
)
{
using var archive = Open(sourceArchive);
foreach (var entry in archive.Entries)
{
entry.WriteToDirectory(destinationDirectory, options);
}
archive.WriteToDirectory(destinationDirectory, options);
}
private static T FindFactory<T>(FileInfo finfo)
@@ -168,14 +166,22 @@ public static class ArchiveFactory
);
}
public static bool IsArchive(string filePath, out ArchiveType? type)
public static bool IsArchive(
string filePath,
out ArchiveType? type,
int bufferSize = ReaderOptions.DefaultBufferSize
)
{
filePath.CheckNotNullOrEmpty(nameof(filePath));
using Stream s = File.OpenRead(filePath);
return IsArchive(s, out type);
return IsArchive(s, out type, bufferSize);
}
public static bool IsArchive(Stream stream, out ArchiveType? type)
public static bool IsArchive(
Stream stream,
out ArchiveType? type,
int bufferSize = ReaderOptions.DefaultBufferSize
)
{
type = null;
stream.CheckNotNull(nameof(stream));

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.IO;
using SharpCompress.Common;
@@ -14,8 +14,11 @@ class AutoArchiveFactory : IArchiveFactory
public IEnumerable<string> GetSupportedExtensions() => throw new NotSupportedException();
public bool IsArchive(Stream stream, string? password = null) =>
throw new NotSupportedException();
public bool IsArchive(
Stream stream,
string? password = null,
int bufferSize = ReaderOptions.DefaultBufferSize
) => throw new NotSupportedException();
public FileInfo? GetFilePart(int index, FileInfo part1) => throw new NotSupportedException();

View File

@@ -89,6 +89,12 @@ public class GZipArchive : AbstractWritableArchive<GZipArchiveEntry, GZipVolume>
public static GZipArchive Open(Stream stream, ReaderOptions? readerOptions = null)
{
stream.CheckNotNull(nameof(stream));
if (stream is not { CanSeek: true })
{
throw new ArgumentException("Stream must be seekable", nameof(stream));
}
return new GZipArchive(
new SourceStream(stream, _ => null, readerOptions ?? new ReaderOptions())
);
@@ -162,7 +168,7 @@ public class GZipArchive : AbstractWritableArchive<GZipArchiveEntry, GZipVolume>
{
if (Entries.Any())
{
throw new InvalidOperationException("Only one entry is allowed in a GZip Archive");
throw new InvalidFormatException("Only one entry is allowed in a GZip Archive");
}
return new GZipWritableArchiveEntry(this, source, filePath, size, modified, closeStream);
}
@@ -176,7 +182,7 @@ public class GZipArchive : AbstractWritableArchive<GZipArchiveEntry, GZipVolume>
{
if (Entries.Count > 1)
{
throw new InvalidOperationException("Only one entry is allowed in a GZip Archive");
throw new InvalidFormatException("Only one entry is allowed in a GZip Archive");
}
using var writer = new GZipWriter(stream, new GZipWriterOptions(options));
foreach (var entry in oldEntries.Concat(newEntries).Where(x => !x.IsDirectory))

View File

@@ -17,7 +17,7 @@ public class GZipArchiveEntry : GZipEntry, IArchiveEntry
{
part.GetRawStream().Position = part.EntryStartPosition;
}
return Parts.Single().GetCompressedStream();
return Parts.Single().GetCompressedStream().NotNull();
}
#region IArchiveEntry Members

View File

@@ -58,7 +58,7 @@ internal sealed class GZipWritableArchiveEntry : GZipArchiveEntry, IWritableArch
{
//ensure new stream is at the start, this could be reset
stream.Seek(0, SeekOrigin.Begin);
return NonDisposingStream.Create(stream);
return SharpCompressStream.Create(stream, leaveOpen: true);
}
internal override void Close()

View File

@@ -4,6 +4,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using SharpCompress.Common;
using SharpCompress.Readers;
namespace SharpCompress.Archives;
@@ -18,10 +19,8 @@ public static class IArchiveExtensions
ExtractionOptions? options = null
)
{
foreach (var entry in archive.Entries.Where(x => !x.IsDirectory))
{
entry.WriteToDirectory(destinationDirectory, options);
}
using var reader = archive.ExtractAllEntries();
reader.WriteAllToDirectory(destinationDirectory, options);
}
/// <summary>

View File

@@ -67,6 +67,16 @@ public class RarArchive : AbstractArchive<RarArchiveEntry, RarVolume>
protected override IReader CreateReaderForSolidExtraction()
{
if (this.IsMultipartVolume())
{
var streams = Volumes.Select(volume =>
{
volume.Stream.Position = 0;
return volume.Stream;
});
return RarReader.Open(streams, ReaderOptions);
}
var stream = Volumes.First().Stream;
stream.Position = 0;
return RarReader.Open(stream, ReaderOptions);
@@ -121,6 +131,12 @@ public class RarArchive : AbstractArchive<RarArchiveEntry, RarVolume>
public static RarArchive Open(Stream stream, ReaderOptions? options = null)
{
stream.CheckNotNull(nameof(stream));
if (stream is not { CanSeek: true })
{
throw new ArgumentException("Stream must be seekable", nameof(stream));
}
return new RarArchive(new SourceStream(stream, _ => null, options ?? new ReaderOptions()));
}

View File

@@ -42,7 +42,7 @@ public class RarArchiveEntry : RarEntry, IArchiveEntry
{
CheckIncomplete();
return BitConverter.ToUInt32(
parts.Select(fp => fp.FileHeader).Single(fh => !fh.IsSplitAfter).FileCrc,
parts.Select(fp => fp.FileHeader).Single(fh => !fh.IsSplitAfter).FileCrc.NotNull(),
0
);
}

View File

@@ -92,6 +92,12 @@ public class SevenZipArchive : AbstractArchive<SevenZipArchiveEntry, SevenZipVol
public static SevenZipArchive Open(Stream stream, ReaderOptions? readerOptions = null)
{
stream.CheckNotNull("stream");
if (stream is not { CanSeek: true })
{
throw new ArgumentException("Stream must be seekable", nameof(stream));
}
return new SevenZipArchive(
new SourceStream(stream, _ => null, readerOptions ?? new ReaderOptions())
);
@@ -194,7 +200,10 @@ public class SevenZipArchive : AbstractArchive<SevenZipArchiveEntry, SevenZipVol
new SevenZipReader(ReaderOptions, this);
public override bool IsSolid =>
Entries.Where(x => !x.IsDirectory).GroupBy(x => x.FilePart.Folder).Count() > 1;
Entries
.Where(x => !x.IsDirectory)
.GroupBy(x => x.FilePart.Folder)
.Any(folder => folder.Count() > 1);
public override long TotalSize =>
_database?._packSizes.Aggregate(0L, (total, packSize) => total + packSize) ?? 0;

View File

@@ -90,6 +90,12 @@ public class TarArchive : AbstractWritableArchive<TarArchiveEntry, TarVolume>
public static TarArchive Open(Stream stream, ReaderOptions? readerOptions = null)
{
stream.CheckNotNull(nameof(stream));
if (stream is not { CanSeek: true })
{
throw new ArgumentException("Stream must be seekable", nameof(stream));
}
return new TarArchive(
new SourceStream(stream, i => null, readerOptions ?? new ReaderOptions())
);

View File

@@ -10,7 +10,7 @@ public class TarArchiveEntry : TarEntry, IArchiveEntry
internal TarArchiveEntry(TarArchive archive, TarFilePart? part, CompressionType compressionType)
: base(part, compressionType) => Archive = archive;
public virtual Stream OpenEntryStream() => Parts.Single().GetCompressedStream();
public virtual Stream OpenEntryStream() => Parts.Single().GetCompressedStream().NotNull();
#region IArchiveEntry Members

View File

@@ -58,7 +58,7 @@ internal sealed class TarWritableArchiveEntry : TarArchiveEntry, IWritableArchiv
{
//ensure new stream is at the start, this could be reset
stream.Seek(0, SeekOrigin.Begin);
return NonDisposingStream.Create(stream);
return SharpCompressStream.Create(stream, leaveOpen: true);
}
internal override void Close()

View File

@@ -111,29 +111,51 @@ public class ZipArchive : AbstractWritableArchive<ZipArchiveEntry, ZipVolume>
public static ZipArchive Open(Stream stream, ReaderOptions? readerOptions = null)
{
stream.CheckNotNull(nameof(stream));
if (stream is not { CanSeek: true })
{
throw new ArgumentException("Stream must be seekable", nameof(stream));
}
return new ZipArchive(
new SourceStream(stream, i => null, readerOptions ?? new ReaderOptions())
);
}
public static bool IsZipFile(string filePath, string? password = null) =>
IsZipFile(new FileInfo(filePath), password);
public static bool IsZipFile(
string filePath,
string? password = null,
int bufferSize = ReaderOptions.DefaultBufferSize
) => IsZipFile(new FileInfo(filePath), password, bufferSize);
public static bool IsZipFile(FileInfo fileInfo, string? password = null)
public static bool IsZipFile(
FileInfo fileInfo,
string? password = null,
int bufferSize = ReaderOptions.DefaultBufferSize
)
{
if (!fileInfo.Exists)
{
return false;
}
using Stream stream = fileInfo.OpenRead();
return IsZipFile(stream, password);
return IsZipFile(stream, password, bufferSize);
}
public static bool IsZipFile(Stream stream, string? password = null)
public static bool IsZipFile(
Stream stream,
string? password = null,
int bufferSize = ReaderOptions.DefaultBufferSize
)
{
var headerFactory = new StreamingZipHeaderFactory(password, new ArchiveEncoding(), null);
try
{
if (stream is not SharpCompressStream)
{
stream = new SharpCompressStream(stream, bufferSize: bufferSize);
}
var header = headerFactory
.ReadStreamHeader(stream)
.FirstOrDefault(x => x.ZipHeaderType != ZipHeaderType.Split);
@@ -153,11 +175,20 @@ public class ZipArchive : AbstractWritableArchive<ZipArchiveEntry, ZipVolume>
}
}
public static bool IsZipMulti(Stream stream, string? password = null)
public static bool IsZipMulti(
Stream stream,
string? password = null,
int bufferSize = ReaderOptions.DefaultBufferSize
)
{
var headerFactory = new StreamingZipHeaderFactory(password, new ArchiveEncoding(), null);
try
{
if (stream is not SharpCompressStream)
{
stream = new SharpCompressStream(stream, bufferSize: bufferSize);
}
var header = headerFactory
.ReadStreamHeader(stream)
.FirstOrDefault(x => x.ZipHeaderType != ZipHeaderType.Split);
@@ -196,7 +227,7 @@ public class ZipArchive : AbstractWritableArchive<ZipArchiveEntry, ZipVolume>
if (streams.Count() > 1) //test part 2 - true = multipart not split
{
streams[1].Position += 4; //skip the POST_DATA_DESCRIPTOR to prevent an exception
var isZip = IsZipFile(streams[1], ReaderOptions.Password);
var isZip = IsZipFile(streams[1], ReaderOptions.Password, ReaderOptions.BufferSize);
streams[1].Position -= 4;
if (isZip)
{
@@ -299,7 +330,7 @@ public class ZipArchive : AbstractWritableArchive<ZipArchiveEntry, ZipVolume>
protected override IReader CreateReaderForSolidExtraction()
{
var stream = Volumes.Single().Stream;
stream.Position = 0;
((IStreamStack)stream).StackSeek(0);
return ZipReader.Open(stream, ReaderOptions, Entries);
}
}

View File

@@ -9,7 +9,7 @@ public class ZipArchiveEntry : ZipEntry, IArchiveEntry
internal ZipArchiveEntry(ZipArchive archive, SeekableZipFilePart? part)
: base(part) => Archive = archive;
public virtual Stream OpenEntryStream() => Parts.Single().GetCompressedStream();
public virtual Stream OpenEntryStream() => Parts.Single().GetCompressedStream().NotNull();
#region IArchiveEntry Members
@@ -18,6 +18,4 @@ public class ZipArchiveEntry : ZipEntry, IArchiveEntry
public bool IsComplete => true;
#endregion
public string? Comment => ((SeekableZipFilePart)Parts.Single()).Comment;
}

View File

@@ -59,7 +59,7 @@ internal class ZipWritableArchiveEntry : ZipArchiveEntry, IWritableArchiveEntry
{
//ensure new stream is at the start, this could be reset
stream.Seek(0, SeekOrigin.Begin);
return NonDisposingStream.Create(stream);
return SharpCompressStream.Create(stream, leaveOpen: true);
}
internal override void Close()

View File

@@ -0,0 +1,60 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SharpCompress.Common.GZip;
using SharpCompress.Common.Tar;
namespace SharpCompress.Common.Arc
{
public class ArcEntry : Entry
{
private readonly ArcFilePart? _filePart;
internal ArcEntry(ArcFilePart? filePart)
{
_filePart = filePart;
}
public override long Crc
{
get
{
if (_filePart == null)
{
return 0;
}
return _filePart.Header.Crc16;
}
}
public override string? Key => _filePart?.Header.Name;
public override string? LinkTarget => null;
public override long CompressedSize => _filePart?.Header.CompressedSize ?? 0;
public override CompressionType CompressionType =>
_filePart?.Header.CompressionMethod ?? CompressionType.Unknown;
public override long Size => throw new NotImplementedException();
public override DateTime? LastModifiedTime => null;
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 IsSplitAfter => false;
internal override IEnumerable<FilePart> Parts => _filePart.Empty();
}
}

View File

@@ -0,0 +1,76 @@
using System;
using System.IO;
using System.Linq;
using System.Text;
namespace SharpCompress.Common.Arc
{
public class ArcEntryHeader
{
public ArchiveEncoding ArchiveEncoding { get; }
public CompressionType CompressionMethod { get; private set; }
public string? Name { get; private set; }
public long CompressedSize { get; private set; }
public DateTime DateTime { get; private set; }
public int Crc16 { get; private set; }
public long OriginalSize { get; private set; }
public long DataStartPosition { get; private set; }
public ArcEntryHeader(ArchiveEncoding archiveEncoding)
{
this.ArchiveEncoding = archiveEncoding;
}
public ArcEntryHeader? ReadHeader(Stream stream)
{
byte[] headerBytes = new byte[29];
if (stream.Read(headerBytes, 0, headerBytes.Length) != headerBytes.Length)
{
return null;
}
DataStartPosition = stream.Position;
return LoadFrom(headerBytes);
}
public ArcEntryHeader LoadFrom(byte[] headerBytes)
{
CompressionMethod = GetCompressionType(headerBytes[1]);
// Read name
int nameEnd = Array.IndexOf(headerBytes, (byte)0, 1); // Find null terminator
Name = Encoding.UTF8.GetString(headerBytes, 2, nameEnd > 0 ? nameEnd - 2 : 12);
int offset = 15;
CompressedSize = BitConverter.ToUInt32(headerBytes, offset);
offset += 4;
uint rawDateTime = BitConverter.ToUInt32(headerBytes, offset);
DateTime = ConvertToDateTime(rawDateTime);
offset += 4;
Crc16 = BitConverter.ToUInt16(headerBytes, offset);
offset += 2;
OriginalSize = BitConverter.ToUInt32(headerBytes, offset);
return this;
}
private CompressionType GetCompressionType(byte value)
{
return value switch
{
1 or 2 => CompressionType.None,
3 => CompressionType.RLE90,
4 => CompressionType.Squeezed,
5 or 6 or 7 or 8 => CompressionType.Crunched,
9 => CompressionType.Squashed,
10 => CompressionType.Crushed,
11 => CompressionType.Distilled,
_ => CompressionType.Unknown,
};
}
public static DateTime ConvertToDateTime(long rawDateTime)
{
// Convert Unix timestamp to DateTime (UTC)
return DateTimeOffset.FromUnixTimeSeconds(rawDateTime).UtcDateTime;
}
}
}

View File

@@ -0,0 +1,75 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SharpCompress.Common.GZip;
using SharpCompress.Common.Tar;
using SharpCompress.Common.Tar.Headers;
using SharpCompress.Common.Zip.Headers;
using SharpCompress.Compressors.Lzw;
using SharpCompress.Compressors.RLE90;
using SharpCompress.Compressors.Squeezed;
using SharpCompress.IO;
namespace SharpCompress.Common.Arc
{
public class ArcFilePart : FilePart
{
private readonly Stream? _stream;
internal ArcFilePart(ArcEntryHeader localArcHeader, Stream? seekableStream)
: base(localArcHeader.ArchiveEncoding)
{
_stream = seekableStream;
Header = localArcHeader;
}
internal ArcEntryHeader Header { get; set; }
internal override string? FilePartName => Header.Name;
internal override Stream GetCompressedStream()
{
if (_stream != null)
{
Stream compressedStream;
switch (Header.CompressionMethod)
{
case CompressionType.None:
compressedStream = new ReadOnlySubStream(
_stream,
Header.DataStartPosition,
Header.CompressedSize
);
break;
case CompressionType.RLE90:
compressedStream = new RunLength90Stream(
_stream,
(int)Header.CompressedSize
);
break;
case CompressionType.Squeezed:
compressedStream = new SqueezeStream(_stream, (int)Header.CompressedSize);
break;
case CompressionType.Crunched:
compressedStream = new ArcLzwStream(
_stream,
(int)Header.CompressedSize,
true
);
break;
default:
throw new NotSupportedException(
"CompressionMethod: " + Header.CompressionMethod
);
}
return compressedStream;
}
return _stream.NotNull();
}
internal override Stream? GetRawStream() => _stream;
}
}

View File

@@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SharpCompress.Readers;
namespace SharpCompress.Common.Arc
{
public class ArcVolume : Volume
{
public ArcVolume(Stream stream, ReaderOptions readerOptions, int index = 0)
: base(stream, readerOptions, index) { }
}
}

View File

@@ -1,9 +0,0 @@
using System;
namespace SharpCompress.Common;
public class ArchiveException : Exception
{
public ArchiveException(string message)
: base(message) { }
}

View File

@@ -7,4 +7,5 @@ public enum ArchiveType
Tar,
SevenZip,
GZip,
Arc,
}

View File

@@ -22,4 +22,11 @@ public enum CompressionType
Reduce3,
Reduce4,
Explode,
Squeezed,
RLE90,
Crunched,
Squashed,
Crushed,
Distilled,
ZStandard,
}

View File

@@ -1,9 +0,0 @@
using System;
namespace SharpCompress.Common;
public class CryptographicException : Exception
{
public CryptographicException(string message)
: base(message) { }
}

View File

@@ -1,11 +1,33 @@
using System;
using System.IO;
using System.IO.Compression;
using SharpCompress.IO;
using SharpCompress.Readers;
namespace SharpCompress.Common;
public class EntryStream : Stream
public class EntryStream : Stream, IStreamStack
{
#if DEBUG_STREAMS
long IStreamStack.InstanceId { get; set; }
#endif
int IStreamStack.DefaultBufferSize { get; set; }
Stream IStreamStack.BaseStream() => _stream;
int IStreamStack.BufferSize
{
get => 0;
set { }
}
int IStreamStack.BufferPosition
{
get => 0;
set { }
}
void IStreamStack.SetPosition(long position) { }
private readonly IReader _reader;
private readonly Stream _stream;
private bool _completed;
@@ -15,6 +37,9 @@ public class EntryStream : Stream
{
_reader = reader;
_stream = stream;
#if DEBUG_STREAMS
this.DebugConstruct(typeof(EntryStream));
#endif
}
/// <summary>
@@ -32,11 +57,28 @@ public class EntryStream : Stream
{
SkipEntry();
}
//Need a safe standard approach to this - it's okay for compression to overreads. Handling needs to be standardised
if (_stream is IStreamStack ss)
{
if (ss.BaseStream() is SharpCompress.Compressors.Deflate.DeflateStream deflateStream)
{
deflateStream.Flush(); //Deflate over reads. Knock it back
}
else if (ss.BaseStream() is SharpCompress.Compressors.LZMA.LzmaStream lzmaStream)
{
lzmaStream.Flush(); //Lzma over reads. Knock it back
}
}
if (_isDisposed)
{
return;
}
_isDisposed = true;
#if DEBUG_STREAMS
this.DebugDispose(typeof(EntryStream));
#endif
base.Dispose(disposing);
_stream.Dispose();
}
@@ -53,7 +95,7 @@ public class EntryStream : Stream
public override long Position
{
get => throw new NotSupportedException();
get => _stream.Position; //throw new NotSupportedException();
set => throw new NotSupportedException();
}

View File

@@ -1,12 +0,0 @@
using System;
namespace SharpCompress.Common;
public class ExtractionException : Exception
{
public ExtractionException(string message)
: base(message) { }
public ExtractionException(string message, Exception inner)
: base(message, inner) { }
}

View File

@@ -11,7 +11,7 @@ public abstract class FilePart
internal abstract string? FilePartName { get; }
public int Index { get; set; }
internal abstract Stream GetCompressedStream();
internal abstract Stream? GetCompressedStream();
internal abstract Stream? GetRawStream();
internal bool Skipped { get; set; }
}

View File

@@ -1,7 +0,0 @@
namespace SharpCompress.Common;
public class IncompleteArchiveException : ArchiveException
{
public IncompleteArchiveException(string message)
: base(message) { }
}

View File

@@ -1,12 +0,0 @@
using System;
namespace SharpCompress.Common;
public class InvalidFormatException : ExtractionException
{
public InvalidFormatException(string message)
: base(message) { }
public InvalidFormatException(string message, Exception inner)
: base(message, inner) { }
}

View File

@@ -1,12 +0,0 @@
using System;
namespace SharpCompress.Common;
public class MultiVolumeExtractionException : ExtractionException
{
public MultiVolumeExtractionException(string message)
: base(message) { }
public MultiVolumeExtractionException(string message, Exception inner)
: base(message, inner) { }
}

View File

@@ -1,7 +0,0 @@
namespace SharpCompress.Common;
public class MultipartStreamRequiredException : ExtractionException
{
public MultipartStreamRequiredException(string message)
: base(message) { }
}

View File

@@ -17,7 +17,7 @@ internal class CryptKey5 : ICryptKey
private byte[] _pswCheck = { };
private byte[] _hashKey = { };
public CryptKey5(string password, Rar5CryptoInfo rar5CryptoInfo)
public CryptKey5(string? password, Rar5CryptoInfo rar5CryptoInfo)
{
_password = password ?? "";
_cryptoInfo = rar5CryptoInfo;

View File

@@ -1,8 +1,5 @@
#nullable disable
using System;
using System.Security.Cryptography;
using SharpCompress.Common.Rar.Headers;
using SharpCompress.IO;
namespace SharpCompress.Common.Rar.Headers;

View File

@@ -1,9 +1,6 @@
#nullable disable
using System;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using SharpCompress.IO;
#if !Rar2017_64bit
@@ -18,7 +15,7 @@ namespace SharpCompress.Common.Rar.Headers;
internal class FileHeader : RarHeader
{
private byte[] _hash;
private byte[]? _hash;
public FileHeader(RarHeader header, RarCrcBinaryReader reader, HeaderType headerType)
: base(header, reader, headerType) { }
@@ -319,6 +316,10 @@ internal class FileHeader : RarHeader
if (NewSubHeaderType.SUBHEAD_TYPE_RR.Equals(fileNameBytes))
{
if (SubData is null)
{
throw new InvalidFormatException();
}
RecoverySectors =
SubData[8]
+ (SubData[9] << 8)
@@ -340,12 +341,16 @@ internal class FileHeader : RarHeader
if (RemainingHeaderBytes(reader) >= 2)
{
var extendedFlags = reader.ReadUInt16();
FileLastModifiedTime = ProcessExtendedTimeV4(
extendedFlags,
FileLastModifiedTime,
reader,
0
);
if (FileLastModifiedTime is not null)
{
FileLastModifiedTime = ProcessExtendedTimeV4(
extendedFlags,
FileLastModifiedTime,
reader,
0
);
}
FileCreatedTime = ProcessExtendedTimeV4(extendedFlags, null, reader, 1);
FileLastAccessedTime = ProcessExtendedTimeV4(extendedFlags, null, reader, 2);
FileArchivedTime = ProcessExtendedTimeV4(extendedFlags, null, reader, 3);
@@ -377,7 +382,7 @@ internal class FileHeader : RarHeader
var dosTime = reader.ReadUInt32();
time = Utility.DosDateToDateTime(dosTime);
}
if ((rmode & 4) == 0)
if ((rmode & 4) == 0 && time is not null)
{
time = time.Value.AddSeconds(1);
}
@@ -390,7 +395,11 @@ internal class FileHeader : RarHeader
}
//10^-7 to 10^-3
return time.Value.AddMilliseconds(nanosecondHundreds * Math.Pow(10, -4));
if (time is not null)
{
return time.Value.AddMilliseconds(nanosecondHundreds * Math.Pow(10, -4));
}
return null;
}
private static string ConvertPathV4(string path)
@@ -406,13 +415,13 @@ internal class FileHeader : RarHeader
return path;
}
public override string ToString() => FileName;
public override string ToString() => FileName ?? "FileHeader";
private ushort Flags { get; set; }
private bool HasFlag(ushort flag) => (Flags & flag) == flag;
internal byte[] FileCrc
internal byte[]? FileCrc
{
get => _hash;
private set => _hash = value;
@@ -441,22 +450,22 @@ internal class FileHeader : RarHeader
public bool IsRedir => RedirType != 0;
public byte RedirFlags { get; private set; }
public bool IsRedirDirectory => (RedirFlags & RedirFlagV5.DIRECTORY) != 0;
public string RedirTargetName { get; private set; }
public string? RedirTargetName { get; private set; }
// unused for UnpackV1 implementation (limitation)
internal size_t WindowSize { get; private set; }
internal byte[] R4Salt { get; private set; }
internal Rar5CryptoInfo Rar5CryptoInfo { get; private set; }
internal byte[]? R4Salt { get; private set; }
internal Rar5CryptoInfo? Rar5CryptoInfo { get; private set; }
private byte HostOs { get; set; }
internal uint FileAttributes { get; private set; }
internal long CompressedSize { get; private set; }
internal long UncompressedSize { get; private set; }
internal string FileName { get; private set; }
internal byte[] SubData { get; private set; }
internal string? FileName { get; private set; }
internal byte[]? SubData { get; private set; }
internal int RecoverySectors { get; private set; }
internal long DataStartPosition { get; set; }
public Stream PackedStream { get; set; }
public Stream? PackedStream { get; set; }
public bool IsSplitBefore =>
IsRar5 ? HasHeaderFlag(HeaderFlagsV5.SPLIT_BEFORE) : HasFlag(FileFlagsV4.SPLIT_BEFORE);

View File

@@ -1,5 +1,4 @@
using System;
using System.IO;
using SharpCompress.IO;
namespace SharpCompress.Common.Rar.Headers;
@@ -21,7 +20,7 @@ internal class RarHeader : IRarHeader
{
return new RarHeader(reader, isRar5, archiveEncoding);
}
catch (EndOfStreamException)
catch (InvalidFormatException)
{
return null;
}

View File

@@ -1,7 +1,5 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using SharpCompress.Common.Rar;
using SharpCompress.IO;
using SharpCompress.Readers;
@@ -160,10 +158,15 @@ public class RarHeaderFactory
{
fh.PackedStream = new RarCryptoWrapper(
ms,
fh.R4Salt is null ? fh.Rar5CryptoInfo.Salt : fh.R4Salt,
fh.R4Salt is null
? new CryptKey5(Options.Password!, fh.Rar5CryptoInfo)
: new CryptKey3(Options.Password!)
? fh.Rar5CryptoInfo.NotNull().Salt
: fh.R4Salt,
fh.R4Salt is null
? new CryptKey5(
Options.Password,
fh.Rar5CryptoInfo.NotNull()
)
: new CryptKey3(Options.Password)
);
}
}

View File

@@ -20,7 +20,7 @@ public abstract class RarEntry : Entry
/// <summary>
/// The File's 32 bit CRC Hash
/// </summary>
public override long Crc => BitConverter.ToUInt32(FileHeader.FileCrc, 0);
public override long Crc => BitConverter.ToUInt32(FileHeader.FileCrc.NotNull(), 0);
/// <summary>
/// The path of the file internal to the Rar Archive.
@@ -68,7 +68,7 @@ public abstract class RarEntry : Entry
public bool IsRedir => FileHeader.IsRedir;
public string RedirTargetName => FileHeader.RedirTargetName;
public string? RedirTargetName => FileHeader.RedirTargetName;
public override string ToString() =>
string.Format(

View File

@@ -62,7 +62,7 @@ public abstract class RarVolume : Volume
if (fh.FileName == "CMT")
{
var buffer = new byte[fh.CompressedSize];
fh.PackedStream.Read(buffer, 0, buffer.Length);
fh.PackedStream.NotNull().ReadFully(buffer);
Comment = Encoding.UTF8.GetString(buffer, 0, buffer.Length - 1);
}
}

View File

@@ -1,12 +0,0 @@
using System;
namespace SharpCompress.Common;
public class ReaderCancelledException : Exception
{
public ReaderCancelledException(string message)
: base(message) { }
public ReaderCancelledException(string message, Exception inner)
: base(message, inner) { }
}

View File

@@ -784,7 +784,7 @@ internal class ArchiveReader
);
break;
default:
throw new InvalidOperationException();
throw new InvalidFormatException();
}
}
}
@@ -843,7 +843,7 @@ internal class ArchiveReader
outStream.ReadExact(data, 0, data.Length);
if (outStream.ReadByte() >= 0)
{
throw new InvalidOperationException("Decoded stream is longer than expected.");
throw new InvalidFormatException("Decoded stream is longer than expected.");
}
dataVector.Add(data);
@@ -854,7 +854,7 @@ internal class ArchiveReader
!= folder._unpackCrc
)
{
throw new InvalidOperationException(
throw new InvalidFormatException(
"Decoded stream does not match expected CRC."
);
}
@@ -996,6 +996,11 @@ internal class ArchiveReader
numFiles,
delegate(int i, uint? attr)
{
// Keep the original attribute value because it could potentially get
// modified in the logic that follows. Some callers of the library may
// find the original value useful.
db._files[i].ExtendedAttrib = 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
@@ -1458,7 +1463,7 @@ internal class ArchiveReader
#if DEBUG
Log.WriteLine(_db._files[index].Name);
#endif
if (_db._files[index].CrcDefined)
if (_db._files[index].Crc.HasValue)
{
_stream = new CrcCheckStream(_db._files[index].Crc.Value);
}

View File

@@ -8,18 +8,13 @@ internal class CFileItem
{
public long Size { get; internal set; }
public uint? Attrib { get; internal set; }
public uint? ExtendedAttrib { get; internal set; }
public uint? Crc { get; internal set; }
public string Name { get; internal set; }
public bool HasStream { get; internal set; }
public bool IsDir { get; internal set; }
public bool CrcDefined => Crc != null;
public bool AttribDefined => Attrib != null;
public void SetAttrib(uint attrib) => Attrib = attrib;
public DateTime? CTime { get; internal set; }
public DateTime? ATime { get; internal set; }
public DateTime? MTime { get; internal set; }

View File

@@ -38,5 +38,8 @@ public class SevenZipEntry : Entry
public override int? Attrib =>
FilePart.Header.Attrib.HasValue ? (int?)FilePart.Header.Attrib.Value : null;
public int? ExtendedAttrib =>
FilePart.Header.ExtendedAttrib.HasValue ? (int?)FilePart.Header.ExtendedAttrib.Value : null;
internal override IEnumerable<FilePart> Parts => FilePart.AsEnumerable<FilePart>();
}

View File

@@ -1,4 +1,3 @@
using System;
using System.IO;
using System.Linq;
using SharpCompress.IO;
@@ -41,7 +40,7 @@ internal class SevenZipFilePart : FilePart
{
if (!Header.HasStream)
{
throw new InvalidOperationException("File does not have a stream.");
return Stream.Null;
}
var folderStream = _database.GetFolderStream(_stream, Folder!, _database.PasswordProvider);
@@ -86,7 +85,7 @@ internal class SevenZipFilePart : FilePart
K_LZMA or K_LZMA2 => CompressionType.LZMA,
K_PPMD => CompressionType.PPMd,
K_B_ZIP2 => CompressionType.BZip2,
_ => throw new NotImplementedException(),
_ => throw new InvalidFormatException(),
};
}

View File

@@ -0,0 +1,48 @@
using System;
namespace SharpCompress.Common;
public class SharpCompressException : Exception
{
public SharpCompressException() { }
public SharpCompressException(string message)
: base(message) { }
public SharpCompressException(string message, Exception inner)
: base(message, inner) { }
}
public class ArchiveException(string message) : SharpCompressException(message);
public class IncompleteArchiveException(string message) : ArchiveException(message);
public class CryptographicException(string message) : SharpCompressException(message);
public class ReaderCancelledException(string message) : SharpCompressException(message);
public class ExtractionException : SharpCompressException
{
public ExtractionException() { }
public ExtractionException(string message)
: base(message) { }
public ExtractionException(string message, Exception inner)
: base(message, inner) { }
}
public class MultipartStreamRequiredException(string message) : ExtractionException(message);
public class MultiVolumeExtractionException(string message) : ExtractionException(message);
public class InvalidFormatException : ExtractionException
{
public InvalidFormatException() { }
public InvalidFormatException(string message)
: base(message) { }
public InvalidFormatException(string message, Exception inner)
: base(message, inner) { }
}

View File

@@ -216,7 +216,7 @@ internal sealed class TarHeader
if (buffer.Length != 0 && buffer.Length < BLOCK_SIZE)
{
throw new InvalidOperationException("Buffer is invalid size");
throw new InvalidFormatException("Buffer is invalid size");
}
return buffer;
}

View File

@@ -4,13 +4,38 @@ using SharpCompress.IO;
namespace SharpCompress.Common.Tar;
internal class TarReadOnlySubStream : NonDisposingStream
internal class TarReadOnlySubStream : SharpCompressStream, IStreamStack
{
#if DEBUG_STREAMS
long IStreamStack.InstanceId { get; set; }
#endif
Stream IStreamStack.BaseStream() => base.Stream;
int IStreamStack.BufferSize
{
get => 0;
set { }
}
int IStreamStack.BufferPosition
{
get => 0;
set { }
}
void IStreamStack.SetPosition(long position) { }
private bool _isDisposed;
private long _amountRead;
public TarReadOnlySubStream(Stream stream, long bytesToRead)
: base(stream, throwOnDispose: false) => BytesLeftToRead = bytesToRead;
: base(stream, leaveOpen: true, throwOnDispose: false)
{
BytesLeftToRead = bytesToRead;
#if DEBUG_STREAMS
this.DebugConstruct(typeof(TarReadOnlySubStream));
#endif
}
protected override void Dispose(bool disposing)
{
@@ -20,7 +45,9 @@ internal class TarReadOnlySubStream : NonDisposingStream
}
_isDisposed = true;
#if DEBUG_STREAMS
this.DebugDispose(typeof(TarReadOnlySubStream));
#endif
if (disposing)
{
// Ensure we read all remaining blocks for this entry.

View File

@@ -7,16 +7,22 @@ namespace SharpCompress.Common;
public abstract class Volume : IVolume
{
private readonly Stream _baseStream;
private readonly Stream _actualStream;
internal Volume(Stream stream, ReaderOptions? readerOptions, int index = 0)
{
Index = index;
ReaderOptions = readerOptions ?? new ReaderOptions();
_baseStream = stream;
if (ReaderOptions.LeaveStreamOpen)
{
stream = NonDisposingStream.Create(stream);
stream = SharpCompressStream.Create(stream, leaveOpen: true);
}
if (stream is IStreamStack ss)
ss.SetBuffer(ReaderOptions.BufferSize, true);
_actualStream = stream;
}
@@ -32,7 +38,7 @@ public abstract class Volume : IVolume
public virtual int Index { get; internal set; }
public string? FileName => (_actualStream as FileStream)?.Name;
public string? FileName => (_baseStream as FileStream)?.Name;
/// <summary>
/// RarArchive is part of a multi-part archive.

View File

@@ -123,11 +123,7 @@ internal class DirectoryEntryHeader : ZipFileEntry
public long RelativeOffsetOfEntryHeader { get; set; }
public uint ExternalFileAttributes { get; set; }
public ushort InternalFileAttributes { get; set; }
public ushort DiskNumberStart { get; set; }
public string? Comment { get; private set; }
}

View File

@@ -120,4 +120,8 @@ internal abstract class ZipFileEntry : ZipHeader
internal ZipFilePart? Part { get; set; }
internal bool IsZip64 => CompressedSize >= uint.MaxValue;
internal uint ExternalFileAttributes { get; set; }
internal string? Comment { get; set; }
}

View File

@@ -1,5 +1,6 @@
using System;
using System.IO;
using SharpCompress.IO;
namespace SharpCompress.Common.Zip;
@@ -9,8 +10,28 @@ internal enum CryptoMode
Decrypt,
}
internal class PkwareTraditionalCryptoStream : Stream
internal class PkwareTraditionalCryptoStream : Stream, IStreamStack
{
#if DEBUG_STREAMS
long IStreamStack.InstanceId { get; set; }
#endif
int IStreamStack.DefaultBufferSize { get; set; }
Stream IStreamStack.BaseStream() => _stream;
int IStreamStack.BufferSize
{
get => 0;
set { return; }
}
int IStreamStack.BufferPosition
{
get => 0;
set { return; }
}
void IStreamStack.SetPosition(long position) { }
private readonly PkwareTraditionalEncryptionData _encryptor;
private readonly CryptoMode _mode;
private readonly Stream _stream;
@@ -25,6 +46,10 @@ internal class PkwareTraditionalCryptoStream : Stream
_encryptor = encryptor;
_stream = stream;
_mode = mode;
#if DEBUG_STREAMS
this.DebugConstruct(typeof(PkwareTraditionalCryptoStream));
#endif
}
public override bool CanRead => (_mode == CryptoMode.Decrypt);
@@ -100,6 +125,9 @@ internal class PkwareTraditionalCryptoStream : Stream
return;
}
_isDisposed = true;
#if DEBUG_STREAMS
this.DebugDispose(typeof(PkwareTraditionalCryptoStream));
#endif
base.Dispose(disposing);
_stream.Dispose();
}

View File

@@ -1,6 +1,5 @@
using System.IO;
using SharpCompress.Common.Zip.Headers;
using SharpCompress.IO;
namespace SharpCompress.Common.Zip;
@@ -8,18 +7,13 @@ internal class SeekableZipFilePart : ZipFilePart
{
private bool _isLocalHeaderLoaded;
private readonly SeekableZipHeaderFactory _headerFactory;
private readonly DirectoryEntryHeader _directoryEntryHeader;
internal SeekableZipFilePart(
SeekableZipHeaderFactory headerFactory,
DirectoryEntryHeader header,
Stream stream
)
: base(header, stream)
{
_headerFactory = headerFactory;
_directoryEntryHeader = header;
}
: base(header, stream) => _headerFactory = headerFactory;
internal override Stream GetCompressedStream()
{
@@ -31,29 +25,13 @@ internal class SeekableZipFilePart : ZipFilePart
return base.GetCompressedStream();
}
internal string? Comment => ((DirectoryEntryHeader)Header).Comment;
private void LoadLocalHeader()
{
var hasData = Header.HasData;
Header = _headerFactory.GetLocalHeader(BaseStream, ((DirectoryEntryHeader)Header));
Header.HasData = hasData;
}
private void LoadLocalHeader() =>
Header = _headerFactory.GetLocalHeader(BaseStream, (DirectoryEntryHeader)Header);
protected override Stream CreateBaseStream()
{
BaseStream.Position = Header.DataStartPosition.NotNull();
if (
(Header.CompressedSize == 0)
&& FlagUtility.HasFlag(Header.Flags, HeaderFlags.UsePostDataDescriptor)
&& _directoryEntryHeader.HasData
&& (_directoryEntryHeader.CompressedSize != 0)
)
{
return new ReadOnlySubStream(BaseStream, _directoryEntryHeader.CompressedSize);
}
return BaseStream;
}
}

View File

@@ -149,6 +149,18 @@ internal sealed class SeekableZipHeaderFactory : ZipHeaderFactory
{
throw new InvalidOperationException();
}
// populate fields only known from the DirectoryEntryHeader
localEntryHeader.HasData = directoryEntryHeader.HasData;
localEntryHeader.ExternalFileAttributes = directoryEntryHeader.ExternalFileAttributes;
localEntryHeader.Comment = directoryEntryHeader.Comment;
if (FlagUtility.HasFlag(localEntryHeader.Flags, HeaderFlags.UsePostDataDescriptor))
{
localEntryHeader.Crc = directoryEntryHeader.Crc;
localEntryHeader.CompressedSize = directoryEntryHeader.CompressedSize;
localEntryHeader.UncompressedSize = directoryEntryHeader.UncompressedSize;
}
return localEntryHeader;
}
}

View File

@@ -1,5 +1,4 @@
using System.IO;
using System.Net.Sockets;
using SharpCompress.Common.Zip.Headers;
using SharpCompress.Compressors.Deflate;
using SharpCompress.IO;
@@ -27,12 +26,12 @@ internal sealed class StreamingZipFilePart : ZipFilePart
);
if (LeaveStreamOpen)
{
return NonDisposingStream.Create(_decompressionStream);
return SharpCompressStream.Create(_decompressionStream, leaveOpen: true);
}
return _decompressionStream;
}
internal BinaryReader FixStreamedFileLocation(ref RewindableStream rewindableStream)
internal BinaryReader FixStreamedFileLocation(ref SharpCompressStream rewindableStream)
{
if (Header.IsDirectory)
{
@@ -50,7 +49,7 @@ internal sealed class StreamingZipFilePart : ZipFilePart
if (_decompressionStream is DeflateStream deflateStream)
{
rewindableStream.Rewind(deflateStream.InputBuffer);
((IStreamStack)rewindableStream).StackSeek(0);
}
Skipped = true;

View File

@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
@@ -19,16 +20,24 @@ internal class StreamingZipHeaderFactory : ZipHeaderFactory
internal IEnumerable<ZipHeader> ReadStreamHeader(Stream stream)
{
RewindableStream rewindableStream;
if (stream is not SharpCompressStream) //ensure the stream is already a SharpCompressStream. So the buffer/size will already be set
{
//the original code wrapped this with RewindableStream. Wrap with SharpCompressStream as we can get the buffer size
if (stream is SourceStream src)
{
stream = new SharpCompressStream(
stream,
src.ReaderOptions.LeaveStreamOpen,
bufferSize: src.ReaderOptions.BufferSize
);
}
else
{
throw new ArgumentException("Stream must be a SharpCompressStream", nameof(stream));
}
}
SharpCompressStream rewindableStream = (SharpCompressStream)stream;
if (stream is RewindableStream rs)
{
rewindableStream = rs;
}
else
{
rewindableStream = new RewindableStream(stream);
}
while (true)
{
ZipHeader? header;
@@ -43,9 +52,8 @@ internal class StreamingZipHeaderFactory : ZipHeaderFactory
{
continue;
}
reader = ((StreamingZipFilePart)_lastEntryHeader.Part).FixStreamedFileLocation(
ref rewindableStream
);
// removed requirement for FixStreamedFileLocation()
var pos = rewindableStream.CanSeek ? (long?)rewindableStream.Position : null;
@@ -56,26 +64,32 @@ internal class StreamingZipHeaderFactory : ZipHeaderFactory
}
_lastEntryHeader.Crc = crc;
// The DataDescriptor can be either 64bit or 32bit
var compressed_size = reader.ReadUInt32();
var uncompressed_size = reader.ReadUInt32();
// Check if we have header or 64bit DataDescriptor
//attempt 32bit read
ulong compSize = reader.ReadUInt32();
ulong uncompSize = reader.ReadUInt32();
headerBytes = reader.ReadUInt32();
var test_header = !(headerBytes == 0x04034b50 || headerBytes == 0x02014b50);
var test_64bit = ((long)uncompressed_size << 32) | compressed_size;
if (test_64bit == _lastEntryHeader.CompressedSize && test_header)
//check for zip64 sentinel or unexpected header
bool isSentinel = compSize == 0xFFFFFFFF || uncompSize == 0xFFFFFFFF;
bool isHeader = headerBytes == 0x04034b50 || headerBytes == 0x02014b50;
if (!isHeader && !isSentinel)
{
_lastEntryHeader.UncompressedSize =
((long)reader.ReadUInt32() << 32) | headerBytes;
//reshuffle into 64-bit values
compSize = (uncompSize << 32) | compSize;
uncompSize = ((ulong)headerBytes << 32) | reader.ReadUInt32();
headerBytes = reader.ReadUInt32();
}
else
else if (isSentinel)
{
_lastEntryHeader.UncompressedSize = uncompressed_size;
//standards-compliant zip64 descriptor
compSize = reader.ReadUInt64();
uncompSize = reader.ReadUInt64();
}
_lastEntryHeader.CompressedSize = (long)compSize;
_lastEntryHeader.UncompressedSize = (long)uncompSize;
if (pos.HasValue)
{
_lastEntryHeader.DataStartPosition = pos - _lastEntryHeader.CompressedSize;
@@ -86,9 +100,9 @@ internal class StreamingZipHeaderFactory : ZipHeaderFactory
if (_lastEntryHeader.Part is null)
continue;
reader = ((StreamingZipFilePart)_lastEntryHeader.Part).FixStreamedFileLocation(
ref rewindableStream
);
//reader = ((StreamingZipFilePart)_lastEntryHeader.Part).FixStreamedFileLocation(
// ref rewindableStream
//);
var pos = rewindableStream.CanSeek ? (long?)rewindableStream.Position : null;
@@ -173,16 +187,11 @@ internal class StreamingZipHeaderFactory : ZipHeaderFactory
} // Check if zip is streaming ( Length is 0 and is declared in PostDataDescriptor )
else if (local_header.Flags.HasFlag(HeaderFlags.UsePostDataDescriptor))
{
var isRecording = rewindableStream.IsRecording;
if (!isRecording)
{
rewindableStream.StartRecording();
}
var nextHeaderBytes = reader.ReadUInt32();
((IStreamStack)rewindableStream).Rewind(sizeof(uint));
// Check if next data is PostDataDescriptor, streamed file with 0 length
header.HasData = !IsHeader(nextHeaderBytes);
rewindableStream.Rewind(!isRecording);
}
else // We are not streaming and compressed size is 0, we have no data
{

View File

@@ -2,11 +2,32 @@ using System;
using System.Buffers.Binary;
using System.IO;
using System.Security.Cryptography;
using SharpCompress.IO;
namespace SharpCompress.Common.Zip;
internal class WinzipAesCryptoStream : Stream
internal class WinzipAesCryptoStream : Stream, IStreamStack
{
#if DEBUG_STREAMS
long IStreamStack.InstanceId { get; set; }
#endif
int IStreamStack.DefaultBufferSize { get; set; }
Stream IStreamStack.BaseStream() => _stream;
int IStreamStack.BufferSize
{
get => 0;
set { }
}
int IStreamStack.BufferPosition
{
get => 0;
set { }
}
void IStreamStack.SetPosition(long position) { }
private const int BLOCK_SIZE_IN_BYTES = 16;
private readonly SymmetricAlgorithm _cipher;
private readonly byte[] _counter = new byte[BLOCK_SIZE_IN_BYTES];
@@ -27,6 +48,10 @@ internal class WinzipAesCryptoStream : Stream
_stream = stream;
_totalBytesLeftToRead = length;
#if DEBUG_STREAMS
this.DebugConstruct(typeof(WinzipAesCryptoStream));
#endif
_cipher = CreateCipher(winzipAesEncryptionData);
var iv = new byte[BLOCK_SIZE_IN_BYTES];
@@ -64,6 +89,9 @@ internal class WinzipAesCryptoStream : Stream
return;
}
_isDisposed = true;
#if DEBUG_STREAMS
this.DebugDispose(typeof(WinzipAesCryptoStream));
#endif
if (disposing)
{
//read out last 10 auth bytes

View File

@@ -13,7 +13,7 @@ internal enum ZipCompressionMethod
Deflate64 = 9,
BZip2 = 12,
LZMA = 14,
ZStd = 93,
ZStandard = 93,
Xz = 95,
PPMd = 98,
WinzipAes = 0x63, //http://www.winzip.com/aes_info.htm

View File

@@ -46,6 +46,7 @@ public class ZipEntry : Entry
ZipCompressionMethod.Reduce3 => CompressionType.Reduce3,
ZipCompressionMethod.Reduce4 => CompressionType.Reduce4,
ZipCompressionMethod.Explode => CompressionType.Explode,
ZipCompressionMethod.ZStandard => CompressionType.ZStandard,
_ => CompressionType.Unknown,
};
@@ -83,4 +84,8 @@ public class ZipEntry : Entry
public override bool IsSplitAfter => false;
internal override IEnumerable<FilePart> Parts => _filePart.Empty();
public override int? Attrib => (int?)_filePart?.Header.ExternalFileAttributes;
public string? Comment => _filePart?.Header.Comment;
}

View File

@@ -45,7 +45,7 @@ internal abstract class ZipFilePart : FilePart
);
if (LeaveStreamOpen)
{
return NonDisposingStream.Create(decompressionStream);
return SharpCompressStream.Create(decompressionStream, leaveOpen: true);
}
return decompressionStream;
}
@@ -70,17 +70,12 @@ internal abstract class ZipFilePart : FilePart
{
case ZipCompressionMethod.None:
{
if (stream is ReadOnlySubStream)
if (Header.CompressedSize is 0)
{
return stream;
return new DataDescriptorStream(stream);
}
if (Header.CompressedSize > 0)
{
return new ReadOnlySubStream(stream, Header.CompressedSize);
}
return new DataDescriptorStream(stream);
return stream;
}
case ZipCompressionMethod.Shrink:
{
@@ -152,7 +147,7 @@ internal abstract class ZipFilePart : FilePart
{
return new XZStream(stream);
}
case ZipCompressionMethod.ZStd:
case ZipCompressionMethod.ZStandard:
{
return new DecompressionStream(stream);
}
@@ -218,7 +213,7 @@ internal abstract class ZipFilePart : FilePart
) || Header.IsZip64
)
{
plainStream = NonDisposingStream.Create(plainStream); //make sure AES doesn't close
plainStream = SharpCompressStream.Create(plainStream, leaveOpen: true); //make sure AES doesn't close
}
else
{

View File

@@ -1,4 +1,4 @@
//
//
// ADC.cs
//
// Author:
@@ -28,14 +28,35 @@
using System;
using System.IO;
using SharpCompress.IO;
namespace SharpCompress.Compressors.ADC;
/// <summary>
/// Provides a forward readable only stream that decompresses ADC data
/// </summary>
public sealed class ADCStream : Stream
public sealed class ADCStream : Stream, IStreamStack
{
#if DEBUG_STREAMS
long IStreamStack.InstanceId { get; set; }
#endif
int IStreamStack.DefaultBufferSize { get; set; }
Stream IStreamStack.BaseStream() => _stream;
int IStreamStack.BufferSize
{
get => 0;
set { }
}
int IStreamStack.BufferPosition
{
get => 0;
set { }
}
void IStreamStack.SetPosition(long position) { }
/// <summary>
/// This stream holds the compressed data
/// </summary>
@@ -74,6 +95,9 @@ public sealed class ADCStream : Stream
}
_stream = stream;
#if DEBUG_STREAMS
this.DebugConstruct(typeof(ADCStream));
#endif
}
public override bool CanRead => _stream.CanRead;
@@ -99,6 +123,9 @@ public sealed class ADCStream : Stream
return;
}
_isDisposed = true;
#if DEBUG_STREAMS
this.DebugDispose(typeof(ADCStream));
#endif
base.Dispose(disposing);
}

View File

@@ -0,0 +1,231 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using SharpCompress.Compressors.RLE90;
using SharpCompress.Compressors.Squeezed;
using SharpCompress.IO;
public partial class ArcLzwStream : Stream, IStreamStack
{
#if DEBUG_STREAMS
long IStreamStack.InstanceId { get; set; }
#endif
int IStreamStack.DefaultBufferSize { get; set; }
Stream IStreamStack.BaseStream() => _stream;
int IStreamStack.BufferSize
{
get => 0;
set { }
}
int IStreamStack.BufferPosition
{
get => 0;
set { }
}
void IStreamStack.SetPosition(long position) { }
private Stream _stream;
private bool _processed;
private bool _useCrunched;
private int _compressedSize;
private const int BITS = 12;
private const int CRUNCH_BITS = 12;
private const int SQUASH_BITS = 13;
private const int INIT_BITS = 9;
private const ushort FIRST = 257;
private const ushort CLEAR = 256;
private ushort oldcode;
private byte finchar;
private int n_bits;
private ushort maxcode;
private ushort[] prefix = new ushort[8191];
private byte[] suffix = new byte[8191];
private bool clearFlag;
private Stack<byte> stack = new Stack<byte>();
private ushort freeEnt;
private ushort maxcodemax;
public ArcLzwStream(Stream stream, int compressedSize, bool useCrunched = true)
{
_stream = stream;
#if DEBUG_STREAMS
this.DebugConstruct(typeof(ArcLzwStream));
#endif
_useCrunched = useCrunched;
_compressedSize = compressedSize;
oldcode = 0;
finchar = 0;
n_bits = 0;
maxcode = 0;
clearFlag = false;
freeEnt = FIRST;
maxcodemax = 0;
}
private ushort? GetCode(BitReader reader)
{
if (clearFlag || freeEnt > maxcode)
{
if (freeEnt > maxcode)
{
n_bits++;
maxcode = (n_bits == BITS) ? maxcodemax : (ushort)((1 << n_bits) - 1);
}
if (clearFlag)
{
clearFlag = false;
n_bits = INIT_BITS;
maxcode = (ushort)((1 << n_bits) - 1);
}
}
return (ushort?)reader.ReadBits(n_bits);
}
public List<byte> Decompress(byte[] input, bool useCrunched)
{
var result = new List<byte>();
int bits = useCrunched ? CRUNCH_BITS : SQUASH_BITS;
if (useCrunched)
{
if (input[0] != BITS)
{
throw new InvalidDataException($"File packed with {input[0]}, expected {BITS}.");
}
input = input.Skip(1).ToArray();
}
maxcodemax = (ushort)(1 << bits);
clearFlag = false;
n_bits = INIT_BITS;
maxcode = (ushort)((1 << n_bits) - 1);
for (int i = 0; i < 256; i++)
{
suffix[i] = (byte)i;
}
var reader = new BitReader(input);
freeEnt = FIRST;
if (GetCode(reader) is ushort old)
{
oldcode = old;
finchar = (byte)oldcode;
result.Add(finchar);
}
while (GetCode(reader) is ushort code)
{
if (code == CLEAR)
{
Array.Clear(prefix, 0, prefix.Length);
clearFlag = true;
freeEnt = (ushort)(FIRST - 1);
if (GetCode(reader) is ushort c)
{
code = c;
}
else
{
break;
}
}
ushort incode = code;
if (code >= freeEnt)
{
stack.Push(finchar);
code = oldcode;
}
while (code >= 256)
{
stack.Push(suffix[code]);
code = prefix[code];
}
finchar = suffix[code];
stack.Push(finchar);
while (stack.Count > 0)
{
result.Add(stack.Pop());
}
code = freeEnt;
if (code < maxcodemax)
{
prefix[code] = oldcode;
suffix[code] = finchar;
freeEnt = (ushort)(code + 1);
}
oldcode = incode;
}
return result;
}
// Stream base class implementation
public override bool CanRead => true;
public override bool CanSeek => false;
public override bool CanWrite => false;
public override long Length => throw new NotImplementedException();
public override long Position
{
get => _stream.Position;
set => throw new NotImplementedException();
}
public override void Flush() => throw new NotImplementedException();
public override int Read(byte[] buffer, int offset, int count)
{
if (_processed)
{
return 0;
}
_processed = true;
var data = new byte[_compressedSize];
_stream.Read(data, 0, _compressedSize);
var decoded = Decompress(data, _useCrunched);
var result = decoded.Count();
if (_useCrunched)
{
var unpacked = RLE.UnpackRLE(decoded.ToArray());
unpacked.CopyTo(buffer, 0);
result = unpacked.Count;
}
else
{
decoded.CopyTo(buffer, 0);
}
return result;
}
public override long Seek(long offset, SeekOrigin origin) =>
throw new NotImplementedException();
public override void SetLength(long value) => throw new NotImplementedException();
public override void Write(byte[] buffer, int offset, int count) =>
throw new NotImplementedException();
protected override void Dispose(bool disposing)
{
#if DEBUG_STREAMS
this.DebugDispose(typeof(ArcLzwStream));
#endif
base.Dispose(disposing);
}
}

View File

@@ -0,0 +1,56 @@
using System;
public partial class ArcLzwStream
{
public class BitReader
{
private readonly byte[] data;
private int bitPosition;
private int bytePosition;
public BitReader(byte[] inputData)
{
data = inputData;
bitPosition = 0;
bytePosition = 0;
}
public int? ReadBits(int bitCount)
{
if (bitCount <= 0 || bitCount > 16)
throw new ArgumentOutOfRangeException(
nameof(bitCount),
"Bit count must be between 1 and 16"
);
if (bytePosition >= data.Length)
return null;
int result = 0;
int bitsRead = 0;
while (bitsRead < bitCount)
{
if (bytePosition >= data.Length)
return null;
int bitsAvailable = 8 - bitPosition;
int bitsToRead = Math.Min(bitCount - bitsRead, bitsAvailable);
int mask = (1 << bitsToRead) - 1;
result |= ((data[bytePosition] >> bitPosition) & mask) << bitsRead;
bitPosition += bitsToRead;
bitsRead += bitsToRead;
if (bitPosition >= 8)
{
bitPosition = 0;
bytePosition++;
}
}
return (ushort)result;
}
}
}

View File

@@ -1,10 +1,31 @@
using System;
using System;
using System.IO;
using SharpCompress.IO;
namespace SharpCompress.Compressors.BZip2;
public sealed class BZip2Stream : Stream
public sealed class BZip2Stream : Stream, IStreamStack
{
#if DEBUG_STREAMS
long IStreamStack.InstanceId { get; set; }
#endif
int IStreamStack.DefaultBufferSize { get; set; }
Stream IStreamStack.BaseStream() => stream;
int IStreamStack.BufferSize
{
get => 0;
set { }
}
int IStreamStack.BufferPosition
{
get => 0;
set { }
}
void IStreamStack.SetPosition(long position) { }
private readonly Stream stream;
private bool isDisposed;
@@ -16,6 +37,9 @@ public sealed class BZip2Stream : Stream
/// <param name="decompressConcatenated">Decompress Concatenated</param>
public BZip2Stream(Stream stream, CompressionMode compressionMode, bool decompressConcatenated)
{
#if DEBUG_STREAMS
this.DebugConstruct(typeof(BZip2Stream));
#endif
Mode = compressionMode;
if (Mode == CompressionMode.Compress)
{
@@ -36,6 +60,9 @@ public sealed class BZip2Stream : Stream
return;
}
isDisposed = true;
#if DEBUG_STREAMS
this.DebugDispose(typeof(BZip2Stream));
#endif
if (disposing)
{
stream.Dispose();

View File

@@ -2,6 +2,7 @@
using System;
using System.IO;
using SharpCompress.IO;
/*
* Copyright 2001,2004-2005 The Apache Software Foundation
@@ -37,8 +38,28 @@ namespace SharpCompress.Compressors.BZip2;
* start of the BZIP2 stream to make it compatible with other PGP programs.
*/
internal class CBZip2InputStream : Stream
internal class CBZip2InputStream : Stream, IStreamStack
{
#if DEBUG_STREAMS
long IStreamStack.InstanceId { get; set; }
#endif
int IStreamStack.DefaultBufferSize { get; set; }
Stream IStreamStack.BaseStream() => bsStream;
int IStreamStack.BufferSize
{
get => 0;
set { }
}
int IStreamStack.BufferPosition
{
get => 0;
set { }
}
void IStreamStack.SetPosition(long position) { }
private static void Cadvise()
{
//System.out.Println("CRC Error");
@@ -164,6 +185,10 @@ internal class CBZip2InputStream : Stream
ll8 = null;
tt = null;
BsSetStream(zStream);
#if DEBUG_STREAMS
this.DebugConstruct(typeof(CBZip2InputStream));
#endif
Initialize(true);
InitBlock();
SetupBlock();
@@ -176,6 +201,9 @@ internal class CBZip2InputStream : Stream
return;
}
isDisposed = true;
#if DEBUG_STREAMS
this.DebugDispose(typeof(CBZip2InputStream));
#endif
base.Dispose(disposing);
bsStream?.Dispose();
}
@@ -542,9 +570,14 @@ internal class CBZip2InputStream : Stream
{
j++;
}
selectorMtf[i] = (char)j;
if (i < BZip2Constants.MAX_SELECTORS)
{
selectorMtf[i] = (char)j;
}
}
nSelectors = Math.Min(nSelectors, BZip2Constants.MAX_SELECTORS);
/* Undo the MTF values for the selectors. */
{
var pos = new char[BZip2Constants.N_GROUPS];

View File

@@ -1,5 +1,6 @@
using System;
using System.IO;
using SharpCompress.IO;
/*
* Copyright 2001,2004-2005 The Apache Software Foundation
@@ -38,8 +39,28 @@ namespace SharpCompress.Compressors.BZip2;
* start of the BZIP2 stream to make it compatible with other PGP programs.
*/
internal sealed class CBZip2OutputStream : Stream
internal sealed class CBZip2OutputStream : Stream, IStreamStack
{
#if DEBUG_STREAMS
long IStreamStack.InstanceId { get; set; }
#endif
int IStreamStack.DefaultBufferSize { get; set; }
Stream IStreamStack.BaseStream() => bsStream;
int IStreamStack.BufferSize
{
get => 0;
set { }
}
int IStreamStack.BufferPosition
{
get => 0;
set { }
}
void IStreamStack.SetPosition(long position) { }
private const int SETMASK = (1 << 21);
private const int CLEARMASK = (~SETMASK);
private const int GREATER_ICOST = 15;
@@ -334,6 +355,10 @@ internal sealed class CBZip2OutputStream : Stream
BsSetStream(inStream);
#if DEBUG_STREAMS
this.DebugConstruct(typeof(CBZip2OutputStream));
#endif
workFactor = 50;
if (inBlockSize > 9)
{
@@ -450,6 +475,9 @@ internal sealed class CBZip2OutputStream : Stream
Finish();
disposed = true;
#if DEBUG_STREAMS
this.DebugDispose(typeof(CBZip2OutputStream));
#endif
Dispose();
bsStream?.Dispose();
bsStream = null;

View File

@@ -27,11 +27,33 @@
using System;
using System.IO;
using System.Text;
using System.Threading;
using SharpCompress.IO;
namespace SharpCompress.Compressors.Deflate;
public class DeflateStream : Stream
public class DeflateStream : Stream, IStreamStack
{
#if DEBUG_STREAMS
long IStreamStack.InstanceId { get; set; }
#endif
int IStreamStack.DefaultBufferSize { get; set; }
Stream IStreamStack.BaseStream() => _baseStream;
int IStreamStack.BufferSize
{
get => 0;
set { }
}
int IStreamStack.BufferPosition
{
get => 0;
set { }
}
void IStreamStack.SetPosition(long position) { }
private readonly ZlibBaseStream _baseStream;
private bool _disposed;
@@ -40,7 +62,8 @@ public class DeflateStream : Stream
CompressionMode mode,
CompressionLevel level = CompressionLevel.Default,
Encoding? forceEncoding = null
) =>
)
{
_baseStream = new ZlibBaseStream(
stream,
mode,
@@ -49,6 +72,11 @@ public class DeflateStream : Stream
forceEncoding
);
#if DEBUG_STREAMS
this.DebugConstruct(typeof(DeflateStream));
#endif
}
#region Zlib properties
/// <summary>
@@ -233,6 +261,9 @@ public class DeflateStream : Stream
{
if (!_disposed)
{
#if DEBUG_STREAMS
this.DebugDispose(typeof(DeflateStream));
#endif
if (disposing)
{
_baseStream?.Dispose();
@@ -290,6 +321,7 @@ public class DeflateStream : Stream
{
throw new ObjectDisposedException("DeflateStream");
}
return _baseStream.Read(buffer, offset, count);
}

View File

@@ -30,11 +30,32 @@ using System;
using System.Buffers.Binary;
using System.IO;
using System.Text;
using SharpCompress.IO;
namespace SharpCompress.Compressors.Deflate;
public class GZipStream : Stream
public class GZipStream : Stream, IStreamStack
{
#if DEBUG_STREAMS
long IStreamStack.InstanceId { get; set; }
#endif
int IStreamStack.DefaultBufferSize { get; set; }
Stream IStreamStack.BaseStream() => BaseStream;
int IStreamStack.BufferSize
{
get => 0;
set { }
}
int IStreamStack.BufferPosition
{
get => 0;
set { }
}
void IStreamStack.SetPosition(long position) { }
internal static readonly DateTime UNIX_EPOCH = new(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
private string? _comment;
@@ -62,6 +83,9 @@ public class GZipStream : Stream
)
{
BaseStream = new ZlibBaseStream(stream, mode, level, ZlibStreamFlavor.GZIP, encoding);
#if DEBUG_STREAMS
this.DebugConstruct(typeof(GZipStream));
#endif
_encoding = encoding;
}
@@ -210,6 +234,9 @@ public class GZipStream : Stream
Crc32 = BaseStream.Crc32;
}
_disposed = true;
#if DEBUG_STREAMS
this.DebugDispose(typeof(GZipStream));
#endif
}
}
finally

View File

@@ -62,8 +62,8 @@
//
// -----------------------------------------------------------------------
using System;
using System.IO;
using SharpCompress.Common;
namespace SharpCompress.Compressors.Deflate;
@@ -177,7 +177,7 @@ public enum CompressionStrategy
/// <summary>
/// A general purpose exception class for exceptions in the Zlib library.
/// </summary>
public class ZlibException : Exception
public class ZlibException : SharpCompressException
{
/// <summary>
/// The ZlibException class captures exception information generated

View File

@@ -32,6 +32,7 @@ using System.Collections.Generic;
using System.IO;
using System.Text;
using SharpCompress.Common.Tar.Headers;
using SharpCompress.IO;
namespace SharpCompress.Compressors.Deflate;
@@ -42,8 +43,28 @@ internal enum ZlibStreamFlavor
GZIP = 1952,
}
internal class ZlibBaseStream : Stream
internal class ZlibBaseStream : Stream, IStreamStack
{
#if DEBUG_STREAMS
long IStreamStack.InstanceId { get; set; }
#endif
int IStreamStack.DefaultBufferSize { get; set; }
Stream IStreamStack.BaseStream() => _stream;
int IStreamStack.BufferSize
{
get => 0;
set { }
}
int IStreamStack.BufferPosition
{
get => 0;
set { }
}
void IStreamStack.SetPosition(long position) { }
protected internal ZlibCodec _z; // deferred init... new ZlibCodec();
protected internal StreamMode _streamMode = StreamMode.Undefined;
@@ -87,6 +108,10 @@ internal class ZlibBaseStream : Stream
_encoding = encoding;
#if DEBUG_STREAMS
this.DebugConstruct(typeof(ZlibBaseStream));
#endif
// workitem 7159
if (flavor == ZlibStreamFlavor.GZIP)
{
@@ -334,6 +359,9 @@ internal class ZlibBaseStream : Stream
return;
}
isDisposed = true;
#if DEBUG_STREAMS
this.DebugDispose(typeof(ZlibBaseStream));
#endif
base.Dispose(disposing);
if (disposing)
{
@@ -354,7 +382,13 @@ internal class ZlibBaseStream : Stream
}
}
public override void Flush() => _stream.Flush();
public override void Flush()
{
_stream.Flush();
//rewind the buffer
((IStreamStack)this).Rewind(z.AvailableBytesIn); //unused
z.AvailableBytesIn = 0;
}
public override Int64 Seek(Int64 offset, SeekOrigin origin) =>
throw new NotSupportedException();
@@ -634,6 +668,13 @@ internal class ZlibBaseStream : Stream
crc.SlurpBlock(buffer, offset, rc);
}
if (rc == ZlibConstants.Z_STREAM_END && z.AvailableBytesIn != 0 && !_wantCompress)
{
//rewind the buffer
((IStreamStack)this).Rewind(z.AvailableBytesIn); //unused
z.AvailableBytesIn = 0;
}
return rc;
}

View File

@@ -60,7 +60,6 @@
//
// -----------------------------------------------------------------------
namespace SharpCompress.Compressors.Deflate;
/// <summary>

View File

@@ -28,11 +28,32 @@
using System;
using System.IO;
using System.Text;
using SharpCompress.IO;
namespace SharpCompress.Compressors.Deflate;
public class ZlibStream : Stream
public class ZlibStream : Stream, IStreamStack
{
#if DEBUG_STREAMS
long IStreamStack.InstanceId { get; set; }
#endif
int IStreamStack.DefaultBufferSize { get; set; }
Stream IStreamStack.BaseStream() => _baseStream;
int IStreamStack.BufferSize
{
get => 0;
set { }
}
int IStreamStack.BufferPosition
{
get => 0;
set { }
}
void IStreamStack.SetPosition(long position) { }
private readonly ZlibBaseStream _baseStream;
private bool _disposed;
@@ -47,7 +68,13 @@ public class ZlibStream : Stream
CompressionMode mode,
CompressionLevel level,
Encoding encoding
) => _baseStream = new ZlibBaseStream(stream, mode, level, ZlibStreamFlavor.ZLIB, encoding);
)
{
_baseStream = new ZlibBaseStream(stream, mode, level, ZlibStreamFlavor.ZLIB, encoding);
#if DEBUG_STREAMS
this.DebugConstruct(typeof(ZlibStream));
#endif
}
#region Zlib properties
@@ -216,6 +243,9 @@ public class ZlibStream : Stream
_baseStream?.Dispose();
}
_disposed = true;
#if DEBUG_STREAMS
this.DebugDispose(typeof(ZlibStream));
#endif
}
}
finally

View File

@@ -8,12 +8,34 @@ using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.CompilerServices;
using SharpCompress.Common;
using SharpCompress.Common.Zip;
using SharpCompress.IO;
namespace SharpCompress.Compressors.Deflate64;
public sealed class Deflate64Stream : Stream
public sealed class Deflate64Stream : Stream, IStreamStack
{
#if DEBUG_STREAMS
long IStreamStack.InstanceId { get; set; }
#endif
int IStreamStack.DefaultBufferSize { get; set; }
Stream IStreamStack.BaseStream() => _stream;
int IStreamStack.BufferSize
{
get => 0;
set { }
}
int IStreamStack.BufferPosition
{
get => 0;
set { }
}
void IStreamStack.SetPosition(long position) { }
private const int DEFAULT_BUFFER_SIZE = 8192;
private Stream _stream;
@@ -41,6 +63,9 @@ public sealed class Deflate64Stream : Stream
}
InitializeInflater(stream, ZipCompressionMethod.Deflate64);
#if DEBUG_STREAMS
this.DebugConstruct(typeof(Deflate64Stream));
#endif
}
/// <summary>
@@ -151,7 +176,7 @@ public sealed class Deflate64Stream : Stream
{
// The stream is either malicious or poorly implemented and returned a number of
// bytes larger than the buffer supplied to it.
throw new InvalidDataException("Deflate64: invalid data");
throw new InvalidFormatException("Deflate64: invalid data");
}
_inflater.SetInput(_buffer, 0, bytes);
@@ -251,6 +276,9 @@ public sealed class Deflate64Stream : Stream
// In this case, we still need to clean up internal resources, hence the inner finally blocks.
try
{
#if DEBUG_STREAMS
this.DebugDispose(typeof(Deflate64Stream));
#endif
if (disposing)
{
_stream?.Dispose();

View File

@@ -243,7 +243,6 @@ internal static class FastEncoderStatics
// cache locality, fewer memory operations.
//
// Encoding information for literal and Length.
// The least 5 significant bits are the length
// and the rest is the code bits.

View File

@@ -4,7 +4,7 @@
using System;
using System.Diagnostics;
using System.IO;
using SharpCompress.Common;
namespace SharpCompress.Compressors.Deflate64;
@@ -192,7 +192,7 @@ internal sealed class HuffmanTree
var increment = 1 << len;
if (start >= increment)
{
throw new InvalidDataException("Deflate64: invalid Huffman data");
throw new InvalidFormatException("Deflate64: invalid Huffman data");
}
// Note the bits in the table are reverted.
@@ -234,7 +234,7 @@ internal sealed class HuffmanTree
if (value > 0)
{
// prevent an IndexOutOfRangeException from array[index]
throw new InvalidDataException("Deflate64: invalid Huffman data");
throw new InvalidFormatException("Deflate64: invalid Huffman data");
}
Debug.Assert(
@@ -307,7 +307,7 @@ internal sealed class HuffmanTree
// huffman code lengths must be at least 1 bit long
if (codeLength <= 0)
{
throw new InvalidDataException("Deflate64: invalid Huffman data");
throw new InvalidFormatException("Deflate64: invalid Huffman data");
}
//

View File

@@ -30,7 +30,7 @@
using System;
using System.Diagnostics;
using System.IO;
using SharpCompress.Compressors.Deflate;
namespace SharpCompress.Compressors.Deflate64;
@@ -385,7 +385,7 @@ internal sealed class InflaterManaged
}
else
{
throw new InvalidDataException("Deflate64: unknown block type");
throw new ZlibException("Deflate64: unknown block type");
}
}
@@ -411,7 +411,7 @@ internal sealed class InflaterManaged
}
else
{
throw new InvalidDataException("Deflate64: unknown block type");
throw new ZlibException("Deflate64: unknown block type");
}
//
@@ -473,7 +473,7 @@ internal sealed class InflaterManaged
// make sure complement matches
if ((ushort)_blockLength != (ushort)(~blockLengthComplement))
{
throw new InvalidDataException("Deflate64: invalid block length");
throw new ZlibException("Deflate64: invalid block length");
}
}
@@ -507,7 +507,7 @@ internal sealed class InflaterManaged
default:
Debug. /*Fail*/
Assert(false, "check why we are here!");
throw new InvalidDataException("Deflate64: unknown state");
throw new ZlibException("Deflate64: unknown state");
}
}
}
@@ -569,7 +569,7 @@ internal sealed class InflaterManaged
{
if (symbol < 0 || symbol >= S_EXTRA_LENGTH_BITS.Length)
{
throw new InvalidDataException("Deflate64: invalid data");
throw new ZlibException("Deflate64: invalid data");
}
_extraBits = S_EXTRA_LENGTH_BITS[symbol];
Debug.Assert(_extraBits != 0, "We handle other cases separately!");
@@ -591,7 +591,7 @@ internal sealed class InflaterManaged
if (_length < 0 || _length >= S_LENGTH_BASE.Length)
{
throw new InvalidDataException("Deflate64: invalid data");
throw new ZlibException("Deflate64: invalid data");
}
_length = S_LENGTH_BASE[_length] + bits;
}
@@ -649,7 +649,7 @@ internal sealed class InflaterManaged
default:
Debug. /*Fail*/
Assert(false, "check why we are here!");
throw new InvalidDataException("Deflate64: unknown state");
throw new ZlibException("Deflate64: unknown state");
}
}
@@ -781,7 +781,7 @@ internal sealed class InflaterManaged
if (_loopCounter == 0)
{
// can't have "prev code" on first code
throw new InvalidDataException();
throw new ZlibException();
}
var previousCode = _codeList[_loopCounter - 1];
@@ -789,7 +789,7 @@ internal sealed class InflaterManaged
if (_loopCounter + repeatCount > _codeArraySize)
{
throw new InvalidDataException();
throw new ZlibException();
}
for (var j = 0; j < repeatCount; j++)
@@ -809,7 +809,7 @@ internal sealed class InflaterManaged
if (_loopCounter + repeatCount > _codeArraySize)
{
throw new InvalidDataException();
throw new ZlibException();
}
for (var j = 0; j < repeatCount; j++)
@@ -830,7 +830,7 @@ internal sealed class InflaterManaged
if (_loopCounter + repeatCount > _codeArraySize)
{
throw new InvalidDataException();
throw new ZlibException();
}
for (var j = 0; j < repeatCount; j++)
@@ -846,7 +846,7 @@ internal sealed class InflaterManaged
default:
Debug. /*Fail*/
Assert(false, "check why we are here!");
throw new InvalidDataException("Deflate64: unknown state");
throw new ZlibException("Deflate64: unknown state");
}
var literalTreeCodeLength = new byte[HuffmanTree.MAX_LITERAL_TREE_ELEMENTS];
@@ -865,7 +865,7 @@ internal sealed class InflaterManaged
// Make sure there is an end-of-block code, otherwise how could we ever end?
if (literalTreeCodeLength[HuffmanTree.END_OF_BLOCK_CODE] == 0)
{
throw new InvalidDataException();
throw new ZlibException();
}
_literalLengthTree = new HuffmanTree(literalTreeCodeLength);

View File

@@ -1,11 +1,32 @@
using System;
using System.IO;
using SharpCompress.Common.Zip.Headers;
using SharpCompress.IO;
namespace SharpCompress.Compressors.Explode;
public class ExplodeStream : Stream
public class ExplodeStream : Stream, IStreamStack
{
#if DEBUG_STREAMS
long IStreamStack.InstanceId { get; set; }
#endif
int IStreamStack.DefaultBufferSize { get; set; }
Stream IStreamStack.BaseStream() => inStream;
int IStreamStack.BufferSize
{
get => 0;
set { }
}
int IStreamStack.BufferPosition
{
get => 0;
set { }
}
void IStreamStack.SetPosition(long position) { }
private const int INVALID_CODE = 99;
private const int WSIZE = 64 * 1024;
@@ -45,6 +66,9 @@ public class ExplodeStream : Stream
)
{
inStream = inStr;
#if DEBUG_STREAMS
this.DebugConstruct(typeof(ExplodeStream));
#endif
this.compressedSize = (int)compressedSize;
unCompressedSize = (long)uncompressedSize;
this.generalPurposeBitFlag = generalPurposeBitFlag;
@@ -54,6 +78,14 @@ public class ExplodeStream : Stream
explode_var_init();
}
protected override void Dispose(bool disposing)
{
#if DEBUG_STREAMS
this.DebugDispose(typeof(ExplodeStream));
#endif
base.Dispose(disposing);
}
public override void Flush()
{
throw new NotImplementedException();

View File

@@ -5,8 +5,8 @@
*/
using System;
using System.IO;
using System.Runtime.CompilerServices;
using SharpCompress.Common;
namespace SharpCompress.Compressors.Filters;
@@ -244,7 +244,7 @@ public sealed class BranchExecFilter
long size = data.Length;
if (size < 16)
{
throw new InvalidDataException("Unexpected data size");
throw new InvalidFormatException("Unexpected data size");
}
size -= 16;

View File

@@ -1,4 +1,3 @@
using System;
using System.IO;
namespace SharpCompress.Compressors.Filters

View File

@@ -3,11 +3,32 @@ using System.IO;
using System.Security.Cryptography;
using System.Text;
using SharpCompress.Compressors.LZMA.Utilites;
using SharpCompress.IO;
namespace SharpCompress.Compressors.LZMA;
internal sealed class AesDecoderStream : DecoderStream2
internal sealed class AesDecoderStream : DecoderStream2, IStreamStack
{
#if DEBUG_STREAMS
long IStreamStack.InstanceId { get; set; }
#endif
int IStreamStack.DefaultBufferSize { get; set; }
Stream IStreamStack.BaseStream() => mStream;
int IStreamStack.BufferSize
{
get => 0;
set { }
}
int IStreamStack.BufferPosition
{
get => 0;
set { }
}
void IStreamStack.SetPosition(long position) { }
private readonly Stream mStream;
private readonly ICryptoTransform mDecoder;
private readonly byte[] mBuffer;
@@ -31,6 +52,10 @@ internal sealed class AesDecoderStream : DecoderStream2
mStream = input;
mLimit = limit;
#if DEBUG_STREAMS
this.DebugConstruct(typeof(AesDecoderStream));
#endif
if (((uint)input.Length & 15) != 0)
{
throw new NotSupportedException("AES decoder does not support padding.");
@@ -64,6 +89,9 @@ internal sealed class AesDecoderStream : DecoderStream2
return;
}
isDisposed = true;
#if DEBUG_STREAMS
this.DebugDispose(typeof(AesDecoderStream));
#endif
if (disposing)
{
mStream.Dispose();

View File

@@ -1,11 +1,32 @@
using System;
using System;
using System.Collections.Generic;
using System.IO;
using SharpCompress.IO;
namespace SharpCompress.Compressors.LZMA;
internal class Bcj2DecoderStream : DecoderStream2
internal class Bcj2DecoderStream : DecoderStream2, IStreamStack
{
#if DEBUG_STREAMS
long IStreamStack.InstanceId { get; set; }
#endif
int IStreamStack.DefaultBufferSize { get; set; }
Stream IStreamStack.BaseStream() => _mMainStream;
int IStreamStack.BufferSize
{
get => 0;
set { }
}
int IStreamStack.BufferPosition
{
get => 0;
set { }
}
void IStreamStack.SetPosition(long position) { }
private const int K_NUM_TOP_BITS = 24;
private const uint K_TOP_VALUE = (1 << K_NUM_TOP_BITS);
@@ -109,6 +130,10 @@ internal class Bcj2DecoderStream : DecoderStream2
_mStatusDecoder[i] = new StatusDecoder();
}
#if DEBUG_STREAMS
this.DebugConstruct(typeof(Bcj2DecoderStream));
#endif
_mIter = Run().GetEnumerator();
}
@@ -119,6 +144,9 @@ internal class Bcj2DecoderStream : DecoderStream2
return;
}
_isDisposed = true;
#if DEBUG_STREAMS
this.DebugDispose(typeof(Bcj2DecoderStream));
#endif
base.Dispose(disposing);
_mMainStream.Dispose();
_mCallStream.Dispose();

View File

@@ -1,5 +1,6 @@
using System;
using System.IO;
using SharpCompress.Common;
using SharpCompress.Common.SevenZip;
using SharpCompress.Compressors.LZMA.Utilites;
using SharpCompress.IO;
@@ -46,7 +47,7 @@ internal static class DecoderStreamHelper
}
}
throw new InvalidOperationException("Could not link output stream to coder.");
throw new InvalidFormatException("Could not link output stream to coder.");
}
private static void FindPrimaryOutStreamIndex(
@@ -75,7 +76,7 @@ internal static class DecoderStreamHelper
{
if (foundPrimaryOutStream)
{
throw new NotSupportedException("Multiple output streams.");
throw new InvalidFormatException("Multiple output streams.");
}
foundPrimaryOutStream = true;
@@ -87,7 +88,7 @@ internal static class DecoderStreamHelper
if (!foundPrimaryOutStream)
{
throw new NotSupportedException("No output stream.");
throw new InvalidFormatException("No output stream.");
}
}

View File

@@ -85,28 +85,56 @@ internal class OutWindow
_streamPos = _pos;
}
public void CopyBlock(int distance, int len)
public void CopyPending()
{
var size = len;
var pos = _pos - distance - 1;
if (pos < 0)
if (_pendingLen < 1)
{
pos += _windowSize;
return;
}
for (; size > 0 && _pos < _windowSize && _total < _limit; size--)
var rem = _pendingLen;
var pos = (_pendingDist < _pos ? _pos : _pos + _windowSize) - _pendingDist - 1;
while (rem > 0 && HasSpace)
{
if (pos >= _windowSize)
{
pos = 0;
}
_buffer[_pos++] = _buffer[pos++];
_total++;
PutByte(_buffer[pos++]);
rem--;
}
_pendingLen = rem;
}
public void CopyBlock(int distance, int len)
{
var rem = len;
var pos = (distance < _pos ? _pos : _pos + _windowSize) - distance - 1;
var targetSize = HasSpace ? (int)Math.Min(rem, _limit - _total) : 0;
var sizeUntilWindowEnd = Math.Min(_windowSize - _pos, _windowSize - pos);
var sizeUntilOverlap = Math.Abs(pos - _pos);
var fastSize = Math.Min(Math.Min(sizeUntilWindowEnd, sizeUntilOverlap), targetSize);
if (fastSize >= 2)
{
_buffer.AsSpan(pos, fastSize).CopyTo(_buffer.AsSpan(_pos, fastSize));
_pos += fastSize;
pos += fastSize;
_total += fastSize;
if (_pos >= _windowSize)
{
Flush();
}
rem -= fastSize;
}
_pendingLen = size;
while (rem > 0 && HasSpace)
{
if (pos >= _windowSize)
{
pos = 0;
}
PutByte(_buffer[pos++]);
rem--;
}
_pendingLen = rem;
_pendingDist = distance;
}
@@ -188,12 +216,23 @@ internal class OutWindow
return size;
}
public void CopyPending()
public int ReadByte()
{
if (_pendingLen > 0)
if (_streamPos >= _pos)
{
CopyBlock(_pendingDist, _pendingLen);
return -1;
}
int value = _buffer[_streamPos];
_streamPos++;
if (_streamPos >= _windowSize)
{
_pos = 0;
_streamPos = 0;
}
return value;
}
public int AvailableBytes => _pos - _streamPos;

View File

@@ -1,6 +1,7 @@
using System;
using System.Buffers.Binary;
using System.IO;
using SharpCompress.Common;
using SharpCompress.Crypto;
using SharpCompress.IO;
@@ -14,10 +15,30 @@ namespace SharpCompress.Compressors.LZMA;
/// <summary>
/// Stream supporting the LZIP format, as documented at http://www.nongnu.org/lzip/manual/lzip_manual.html
/// </summary>
public sealed class LZipStream : Stream
public sealed class LZipStream : Stream, IStreamStack
{
#if DEBUG_STREAMS
long IStreamStack.InstanceId { get; set; }
#endif
int IStreamStack.DefaultBufferSize { get; set; }
Stream IStreamStack.BaseStream() => _stream;
int IStreamStack.BufferSize
{
get => 0;
set { }
}
int IStreamStack.BufferPosition
{
get => 0;
set { }
}
void IStreamStack.SetPosition(long position) { }
private readonly Stream _stream;
private readonly CountingWritableSubStream? _countingWritableSubStream;
private readonly SharpCompressStream? _countingWritableSubStream;
private bool _disposed;
private bool _finished;
@@ -32,7 +53,7 @@ public sealed class LZipStream : Stream
var dSize = ValidateAndReadSize(stream);
if (dSize == 0)
{
throw new IOException("Not an LZip stream");
throw new InvalidFormatException("Not an LZip stream");
}
var properties = GetProperties(dSize);
_stream = new LzmaStream(properties, stream);
@@ -43,7 +64,7 @@ public sealed class LZipStream : Stream
var dSize = 104 * 1024;
WriteHeaderSize(stream);
_countingWritableSubStream = new CountingWritableSubStream(stream);
_countingWritableSubStream = new SharpCompressStream(stream, leaveOpen: true);
_stream = new Crc32Stream(
new LzmaStream(
new LzmaEncoderProperties(true, dSize),
@@ -51,6 +72,9 @@ public sealed class LZipStream : Stream
_countingWritableSubStream
)
);
#if DEBUG_STREAMS
this.DebugConstruct(typeof(LZipStream));
#endif
}
}
@@ -63,7 +87,7 @@ public sealed class LZipStream : Stream
var crc32Stream = (Crc32Stream)_stream;
crc32Stream.WrappedStream.Dispose();
crc32Stream.Dispose();
var compressedCount = _countingWritableSubStream.NotNull().Count;
var compressedCount = _countingWritableSubStream.NotNull().InternalPosition;
Span<byte> intBuf = stackalloc byte[8];
BinaryPrimitives.WriteUInt32LittleEndian(intBuf, crc32Stream.Crc);
@@ -73,7 +97,10 @@ public sealed class LZipStream : Stream
_countingWritableSubStream?.Write(intBuf);
//total with headers
BinaryPrimitives.WriteUInt64LittleEndian(intBuf, compressedCount + 6 + 20);
BinaryPrimitives.WriteUInt64LittleEndian(
intBuf,
(ulong)compressedCount + (ulong)(6 + 20)
);
_countingWritableSubStream?.Write(intBuf);
}
_finished = true;
@@ -89,6 +116,9 @@ public sealed class LZipStream : Stream
return;
}
_disposed = true;
#if DEBUG_STREAMS
this.DebugDispose(typeof(LZipStream));
#endif
if (disposing)
{
Finish();
@@ -167,11 +197,6 @@ public sealed class LZipStream : Stream
/// </summary>
public static int ValidateAndReadSize(Stream stream)
{
if (stream is null)
{
throw new ArgumentNullException(nameof(stream));
}
// Read the header
Span<byte> header = stackalloc byte[6];
var n = stream.Read(header);
@@ -198,33 +223,25 @@ public sealed class LZipStream : Stream
return (1 << basePower) - (subtractionNumerator * (1 << (basePower - 4)));
}
private static readonly byte[] headerBytes = new byte[6]
{
private static readonly byte[] headerBytes =
[
(byte)'L',
(byte)'Z',
(byte)'I',
(byte)'P',
1,
113,
};
public static void WriteHeaderSize(Stream stream)
{
if (stream is null)
{
throw new ArgumentNullException(nameof(stream));
}
];
public static void WriteHeaderSize(Stream stream) =>
// hard coding the dictionary size encoding
stream.Write(headerBytes, 0, 6);
}
/// <summary>
/// Creates a byte array to communicate the parameters and dictionary size to LzmaStream.
/// </summary>
private static byte[] GetProperties(int dictionarySize) =>
new byte[]
{
[
// Parameters as per http://www.nongnu.org/lzip/manual/lzip_manual.html#Stream-format
// but encoded as a single byte in the format LzmaStream expects.
// literal_context_bits = 3
@@ -236,5 +253,5 @@ public sealed class LZipStream : Stream
(byte)((dictionarySize >> 8) & 0xff),
(byte)((dictionarySize >> 16) & 0xff),
(byte)((dictionarySize >> 24) & 0xff),
};
];
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Diagnostics;
@@ -28,52 +28,68 @@ internal static class Log
if (NEEDS_INDENT)
{
NEEDS_INDENT = false;
#if DEBUG_LZMA
Debug.Write(INDENT.Peek());
#endif
}
}
public static void Write(object value)
{
EnsureIndent();
#if DEBUG_LZMA
Debug.Write(value);
#endif
}
public static void Write(string text)
{
EnsureIndent();
#if DEBUG_LZMA
Debug.Write(text);
#endif
}
public static void Write(string format, params object[] args)
{
EnsureIndent();
#if DEBUG_LZMA
Debug.Write(string.Format(format, args));
#endif
}
public static void WriteLine()
{
#if DEBUG_LZMA
Debug.WriteLine("");
#endif
NEEDS_INDENT = true;
}
public static void WriteLine(object value)
{
EnsureIndent();
#if DEBUG_LZMA
Debug.WriteLine(value);
#endif
NEEDS_INDENT = true;
}
public static void WriteLine(string text)
{
EnsureIndent();
#if DEBUG_LZMA
Debug.WriteLine(text);
#endif
NEEDS_INDENT = true;
}
public static void WriteLine(string format, params object[] args)
{
EnsureIndent();
#if DEBUG_LZMA
Debug.WriteLine(string.Format(format, args));
#endif
NEEDS_INDENT = true;
}
}

View File

@@ -2,6 +2,7 @@
using System;
using System.IO;
using SharpCompress.Common;
using SharpCompress.Compressors.LZMA.LZ;
using SharpCompress.Compressors.LZMA.RangeCoder;
@@ -1611,7 +1612,7 @@ internal class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties
{
if (_nowPos64 > 0)
{
throw new InvalidOperationException();
throw new InvalidFormatException();
}
_trainSize = (uint)trainStream.Length;
if (_trainSize > 0)

View File

@@ -4,11 +4,32 @@ using System;
using System.Buffers.Binary;
using System.IO;
using SharpCompress.Compressors.LZMA.LZ;
using SharpCompress.IO;
namespace SharpCompress.Compressors.LZMA;
public class LzmaStream : Stream
public class LzmaStream : Stream, IStreamStack
{
#if DEBUG_STREAMS
long IStreamStack.InstanceId { get; set; }
#endif
int IStreamStack.DefaultBufferSize { get; set; }
Stream IStreamStack.BaseStream() => _inputStream;
int IStreamStack.BufferSize
{
get => 0;
set { }
}
int IStreamStack.BufferPosition
{
get => 0;
set { }
}
void IStreamStack.SetPosition(long position) { }
private readonly Stream _inputStream;
private readonly long _inputSize;
private readonly long _outputSize;
@@ -56,6 +77,10 @@ public class LzmaStream : Stream
_outputSize = outputSize;
_isLzma2 = isLzma2;
#if DEBUG_STREAMS
this.DebugConstruct(typeof(LzmaStream));
#endif
if (!isLzma2)
{
_dictionarySize = BinaryPrimitives.ReadInt32LittleEndian(properties.AsSpan(1));
@@ -117,6 +142,11 @@ public class LzmaStream : Stream
Properties = prop;
_encoder.SetStreams(null, outputStream, -1, -1);
#if DEBUG_STREAMS
this.DebugConstruct(typeof(LzmaStream));
#endif
if (presetDictionary != null)
{
_encoder.Train(presetDictionary);
@@ -138,6 +168,9 @@ public class LzmaStream : Stream
return;
}
_isDisposed = true;
#if DEBUG_STREAMS
this.DebugDispose(typeof(LzmaStream));
#endif
if (disposing)
{
if (_encoder != null)
@@ -247,6 +280,82 @@ public class LzmaStream : Stream
return total;
}
public override int ReadByte()
{
if (_endReached)
{
return -1;
}
if (_availableBytes == 0)
{
if (_isLzma2)
{
DecodeChunkHeader();
}
else
{
_endReached = true;
}
}
if (_endReached)
{
if (_inputSize >= 0 && _inputPosition != _inputSize)
{
throw new DataErrorException();
}
if (_outputSize >= 0 && _position != _outputSize)
{
throw new DataErrorException();
}
return -1;
}
_outWindow.SetLimit(1);
if (_uncompressedChunk)
{
_inputPosition += _outWindow.CopyStream(_inputStream, 1);
}
else if (_decoder.Code(_dictionarySize, _outWindow, _rangeDecoder) && _outputSize < 0)
{
_availableBytes = _outWindow.AvailableBytes;
}
var value = _outWindow.ReadByte();
_position++;
_availableBytes--;
if (_availableBytes == 0 && !_uncompressedChunk)
{
// Check range corruption scenario
if (
!_rangeDecoder.IsFinished
|| (_rangeDecoderLimit >= 0 && _rangeDecoder._total != _rangeDecoderLimit)
)
{
// Stream might have End Of Stream marker
_outWindow.SetLimit(2);
if (!_decoder.Code(_dictionarySize, _outWindow, _rangeDecoder))
{
_rangeDecoder.ReleaseStream();
throw new DataErrorException();
}
}
_rangeDecoder.ReleaseStream();
_inputPosition += _rangeDecoder._total;
if (_outWindow.HasPending)
{
throw new DataErrorException();
}
}
return value;
}
private void DecodeChunkHeader()
{
var control = _inputStream.ReadByte();

View File

@@ -1,6 +1,7 @@
#nullable disable
using System.IO;
using System.Runtime.CompilerServices;
namespace SharpCompress.Compressors.LZMA.RangeCoder;
@@ -152,6 +153,7 @@ internal class Decoder
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Normalize2()
{
if (_range < K_TOP_VALUE)

View File

@@ -107,24 +107,13 @@ internal struct BitDecoder
{
rangeDecoder._range = newBound;
_prob += (K_BIT_MODEL_TOTAL - _prob) >> K_NUM_MOVE_BITS;
if (rangeDecoder._range < Decoder.K_TOP_VALUE)
{
rangeDecoder._code =
(rangeDecoder._code << 8) | (byte)rangeDecoder._stream.ReadByte();
rangeDecoder._range <<= 8;
rangeDecoder._total++;
}
rangeDecoder.Normalize2();
return 0;
}
rangeDecoder._range -= newBound;
rangeDecoder._code -= newBound;
_prob -= (_prob) >> K_NUM_MOVE_BITS;
if (rangeDecoder._range < Decoder.K_TOP_VALUE)
{
rangeDecoder._code = (rangeDecoder._code << 8) | (byte)rangeDecoder._stream.ReadByte();
rangeDecoder._range <<= 8;
rangeDecoder._total++;
}
rangeDecoder.Normalize2();
return 1;
}
}

View File

@@ -1,10 +1,31 @@
using System;
using System;
using System.IO;
using SharpCompress.IO;
namespace SharpCompress.Compressors.LZMA.Utilites;
internal class CrcBuilderStream : Stream
internal class CrcBuilderStream : Stream, IStreamStack
{
#if DEBUG_STREAMS
long IStreamStack.InstanceId { get; set; }
#endif
int IStreamStack.DefaultBufferSize { get; set; }
Stream IStreamStack.BaseStream() => _mTarget;
int IStreamStack.BufferSize
{
get => 0;
set { }
}
int IStreamStack.BufferPosition
{
get => 0;
set { }
}
void IStreamStack.SetPosition(long position) { }
private readonly Stream _mTarget;
private uint _mCrc;
private bool _mFinished;
@@ -13,6 +34,9 @@ internal class CrcBuilderStream : Stream
public CrcBuilderStream(Stream target)
{
_mTarget = target;
#if DEBUG_STREAMS
this.DebugConstruct(typeof(CrcBuilderStream));
#endif
_mCrc = Crc.INIT_CRC;
}
@@ -23,6 +47,9 @@ internal class CrcBuilderStream : Stream
return;
}
_isDisposed = true;
#if DEBUG_STREAMS
this.DebugDispose(typeof(CrcBuilderStream));
#endif
_mTarget.Dispose();
base.Dispose(disposing);
}

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