Compare commits

...

185 Commits

Author SHA1 Message Date
Adam Hathcock
bec2662d23 Update version 2015-12-28 18:40:35 +00:00
Adam Hathcock
dd35052de9 Merge pull request #105 from benshoof/fix-tests-release-build
Fix Release build of Tests
2015-12-17 08:54:31 +00:00
Adam Hathcock
2a630e04b2 Merge pull request #107 from benshoof/fix-nonzip-perf-regression
Fixed serious performance regression (revert 0f12a073af)
2015-12-15 16:33:06 +00:00
benshoof
231b78e096 Revert 0f12a073af
Revert commit that caused all non-zip files to be read entirely upon
opening.
IsZipArchive() would read and process the entire file looking for a zip
header.
2015-12-15 07:28:50 -09:00
Adam Hathcock
ce6e1d26f4 Merge pull request #104 from benshoof/fix-vs2013-build
Fix VS2013 compiler warnings (errors)
2015-12-15 09:10:49 +00:00
benshoof
69a25cd142 Fix Release build of Tests
Fixes release builds of SharpCompress.Test and
SharpCompress.Test.Portable. The UNSIGNED symbol was missing from the
Release configurations of SharpCompress.Unsigned and
SharpCompress.PortableTest
2015-12-14 15:32:49 -09:00
benshoof
cc2ad7d8d5 Fix VS2013 compiler warnings (errors)
Fixes broken build in VS2013 introduced by
18bd810228. That commit attempted to fix a
compiler warning from VS2015, but this turns out to be a compiler bug:
https://github.com/dotnet/roslyn/issues/4027 . That commit added code
which VS2013 correctly treats as a compiler warning, breaking the VS2013
build.
I have reverted this unnecessary change to the deflate code, fixing the
VS2013 build, and disabled warning CS0675 on send_bits() which will
satisfy VS2015.
2015-12-14 15:24:33 -09:00
Adam Hathcock
1aa0498e5d update nuspec 2015-11-30 19:40:24 +00:00
Adam Hathcock
1ce5e15fd2 Minor cleanup 2015-11-30 19:40:16 +00:00
Adam Hathcock
b40131736a Merge pull request #103 from pappe82/android-compatibility
Zip entry header version for Deflate compression set to 20
2015-11-30 19:37:38 +00:00
pappe82
c2b15b9c09 Zip entry header version for Deflate compression set to 20
The java runtime on Android cannot process file entries with the fixed
version 63 - it can only process entries up to version 20, which should
be fine if the entry was compressed using deflate.
2015-11-30 14:43:28 +01:00
Adam Hathcock
27a4f78712 version 0.11.2 2015-11-20 18:59:43 +00:00
Adam Hathcock
2b5ee6e8cb resharper update 2015-11-20 18:59:29 +00:00
Adam Hathcock
cd8ea28576 last write time shouldn't equal...right? 2015-11-20 18:59:15 +00:00
Adam Hathcock
b2b6934499 Merge pull request #101 from twirpx/master
Non-compilable statements + zip archive handling
2015-11-19 16:46:26 +00:00
twirpx
0f12a073af Eliminated "throw - catch all" logic in ZipArchive 2015-11-19 21:08:55 +05:00
twirpx
18bd810228 Fixed non-compilable statements 2015-11-19 21:07:52 +05:00
twirpx
13bbb202c7 Changed MAX_ITERATIONS_FOR_DIRECTORY_HEADER to deal with archives that have larger comments 2015-11-19 21:06:56 +05:00
Adam Hathcock
9a638e7aa5 Merge pull request #97 from Icenium/natanasova/add-explicit-compressioninfo
Add explicit compressioninfo when writing file to zip
2015-10-01 09:33:26 -07:00
Adam Hathcock
7a11dc4385 Merge pull request #96 from Icenium/natanasova/fix-extract-options-as-flag
Use enum as flag correctly
2015-10-01 09:30:46 -07:00
Nadya Atanasova
66816ce390 Add explicit compressioninfo when writing file to zip 2015-10-01 17:15:37 +03:00
Nadya Atanasova
5d8bd7b69b Use enum as flag correctly
Check PreserveFileTime when file times are initialized.
2015-10-01 17:02:58 +03:00
Adam Hathcock
0132c85ec7 Merge pull request #83 from haykpetros/issue_80
Added additional check to make sure that data is properly copied to a…
2015-08-30 09:46:38 +01:00
haykpetros
9bf5df72a6 Added additional check to make sure that data is properly copied to array regardless fo computer/CPU platform (little-endian or big-endian). In case of big-endian platform intermediate array will be reversed prior to copying to destination array. 2015-08-05 05:27:30 -07:00
Adam Hathcock
91fc241358 Merge pull request #82 from haykpetros/issue_79
Issue 79
2015-08-04 15:05:37 +01:00
haykpetros
35a8b444b8 I feel there is no need to use unsafe version, so conditional compilation has been removed and only safe version kept. 2015-08-04 03:47:09 -07:00
haykpetros
2e928e86fd Removed unused method. 2015-08-04 03:24:59 -07:00
Adam Hathcock
6648f33c4e Merge pull request #81 from haykpetros/issue_78
Move closing parentheses to where they should be, so build does not b…
2015-08-04 10:05:17 +01:00
haykpetros
2a70ec8100 Move closing parentheses to where they should be, so build does not break for non-DEBUG configurations. 2015-08-03 13:11:13 -07:00
Adam Hathcock
05e0d591a5 Merge pull request #72 from hodm/master
Extract Options And Total Sizes
2015-07-27 10:07:22 +01:00
Adam Hathcock
1d30a1b51d Update README 2015-07-27 10:03:39 +01:00
Adam Hathcock
315c138c05 Removing .NET 2.0 support and LinqBridge dies a firey death 2015-07-27 09:48:36 +01:00
hodm
b0c514d87c Extract Options And Total Sizes
Fixed TotalSize For 7z
added TotalUncompressSize Tested for 7z
this enables to show progress for the entire archive
Added 2 Extract Options: PreserveFileTime And PreserveAttributes.
Put All the Log Command under DEBUG Condition.
2015-07-26 23:36:28 +03:00
Adam Hathcock
8e5cb77af2 Merge pull request #69 from pnewman8/master
Skip entry stream on dispose
2015-07-20 16:27:55 +01:00
Paul Newman
8faebc78d0 Cancel moved from EntryStream to Reader
Relates to previous commit. Following discussion with Adam, moved the Cancel() to the reader.

Example:

while (reader.MoveToNextEntry())
{
  using (var data = new StreamReader(reader.OpenEntryStream()))
  {
    try
    {
      DoSomething(data.ReadLine());
    }
    catch
    {
      reader.Cancel();
      throw;
    }
  }
}
2015-07-15 18:13:46 +01:00
Paul Newman
afff386622 Skip entry stream on dispose
Until now the caller had to completely consume each entry stream, or call SkipEntry(), before disposing the stream. If not, exception was thrown: "EntryStream has not been fully consumed". Hugely inconvenient; a user-thrown exception inside a "using (EntryStream)" block would be discarded.

Now automatically skips the entry on dispose.

Added method EntryStream.Cancel(). Call this if entry stream is unfinished, and no further entries are required. Helps with efficiency, as it avoids reading data that is not needed.
2015-07-15 13:44:20 +01:00
Adam Hathcock
9eb43156e8 Update license URL 2015-06-12 12:06:21 +01:00
Adam Hathcock
5dd9994d34 Update for 0.11 2015-06-12 12:03:03 +01:00
Adam Hathcock
f18771904e Made unsigned csproj for testing. Sign the main DLL again. 2015-06-12 11:59:31 +01:00
Adam Hathcock
ff1cdbfff2 Fix portable tests 2015-06-12 11:53:37 +01:00
Adam Hathcock
332d71d40d UTF8 is the default encoding for all platforms 2015-06-12 11:37:42 +01:00
Adam Hathcock
d9c31dace8 Fixing lingering build issues 2015-06-12 11:31:04 +01:00
Adam Hathcock
33c83e3893 Merge pull request #63 from mrgleba/master
ZipWriter: use ArchiveEncoding.Default
2015-06-11 09:30:05 +01:00
mrgleba
c7fc5f8819 ZipWriter: use ArchiveEncoding.Default
ShaprCompress is used internally in Mono to implement
System.IO.Compression, which allows the user to specify path encoding.
The change allows for specifying the encoding via
ArchiveEncoding.Default.
2015-06-11 08:36:33 +02:00
Adam Hathcock
8df6243807 Merge pull request #59 from KOLANICH/ZipFileEntry-LoadExtra-ArrayOverflowFix
Zip file entry load extra array overflow fix
2015-05-22 08:52:04 +01:00
Adam Hathcock
8bf5c99386 Merge pull request #56 from KOLANICH/test-path-fix
Improved testability
2015-05-22 08:51:44 +01:00
KOLANICH
83eae05e0c Fixed oveflow Zip/Headers/ZipFileEntry.cs 2015-05-22 00:07:32 +03:00
KOLANICH
7c70a7aafd Improved testability
1) disabled requirement of signature
2) added runtime discovery of folder with archives
3) disabled signing of test assembly
2015-05-22 00:00:59 +03:00
Adam Hathcock
dae13c782f Merge pull request #55 from benshoof/rar_protect_header
Added read support for RARs with Protect Headers
2015-05-08 13:58:05 +01:00
benshoof
ae1e37cde6 Added read support for RARs with Protect Headers
Some RARs with recovery records contain Protect Headers, I've added
support for parsing them so that RARs containing them can be read,
instead of an invalid-header exception being thrown. Parsing logic taken
from unrar reference source.
2015-05-07 18:20:05 -08:00
Adam Hathcock
94f4d35663 Merge pull request #53 from benshoof/master
Fixed .NET2 Release build
2015-05-05 09:19:51 +01:00
benshoof
5144104fef Fixed .NET2 Release build
The .NET2 project only built in Debug configuration due to not including
the compilation symbol NET2 in the Release configuration.
2015-05-02 20:40:34 -08:00
Adam Hathcock
f87e6672f2 Merge pull request #51 from sander2/fix-tar.bz2-compression
Fixed bug where tar.bz2 compression did not work
2015-04-09 13:39:38 +01:00
Adam Hathcock
312b53398c Merge pull request #52 from sander2/tar-long-name-support
Tar long name support
2015-04-09 13:39:21 +01:00
Sander Bosma
26ddc09c6a add unit test for writing tar archives containing long filenames 2015-04-07 21:43:45 +02:00
Sander Bosma
3113500229 don't write trailing zero in WriteOctalBytes
this fixes a bug where the trailing zero of the CRC overwrote the entrytype
2015-04-07 21:43:45 +02:00
Sander Bosma
ef72829f1c Fixed bug where tar.bz2 compression did not work 2015-04-06 17:09:55 +02:00
Sander Bosma
088644240a Tar: Support for writing long filenames (>100 chars) using longlink 2015-04-06 14:38:57 +02:00
Adam Hathcock
065ed29600 Merge pull request #47 from norvegec/master
fixed: .NET2 project is not compiling
2015-03-16 11:02:46 +00:00
Adam Hathcock
ee8c1f7904 Merge pull request #45 from catester/master
Made the assembly CLSCompliant.
2015-03-16 10:55:21 +00:00
catester
5d6a83578c Made the assembly CLSCompliant.
Added attribute [assembly: CLSCompliant(true)] and changed type of
public Crc properties from uint to long to satisfy CLS compliance.
2015-03-16 12:29:21 +02:00
Adam Hathcock
37d8d34601 Merge pull request #44 from catester/master
Added IWritableArchive interface
2015-03-16 09:43:28 +00:00
Norvegec
492f64053b fixed: .NET2 project is not compiling 2015-03-15 02:10:06 +03:00
catester
988fe5eac0 Replaced NotImplementedException for streams
This commit is more correct, it covers all stream types now.
2015-03-14 14:45:04 +02:00
catester
c48a47c9b2 Revert "Revert "Replaced NotImplementedException for streams""
This reverts commit abed9eb2c9.
2015-03-14 14:22:55 +02:00
catester
abed9eb2c9 Revert "Replaced NotImplementedException for streams"
This reverts commit 391663ac67.
2015-03-14 13:31:02 +02:00
catester
391663ac67 Replaced NotImplementedException for streams
Especially for streams, it is more appropriate to throw
NotSupportedException instead of NotImplementedException. Usually
consumers of streams expect NotSupportedException to handle errors.
There are other places that also use NotImplementedException but I
didn't examine them for now. I only modified stream classes in
SharpCompress.IO. For reference about this best practise, please see
these articles:
http://blogs.msdn.com/b/brada/archive/2004/07/29/201354.aspx

http://blogs.msdn.com/b/jaredpar/archive/2008/12/12/notimplementedexception-vs-notsupportedexception.aspx
2015-03-14 12:46:34 +02:00
catester
a8c055b990 Added IWritableArchive interface
So that when working with ArchiveFactory, you can cast the opened
archive to IWritableArchive for accessing AddEntry, RemoveEntry and
SaveTo methods without having to know what type of archive is opened
underhood. Also moved extension methods from AbstractWritableArchive to
this new interface. Also added GZipArchive to ArchiveFactory.Create as
it is one of the 3 writable archive types (zip, tar, gzip), not sure why
it was omitted.
2015-03-13 22:38:33 +02:00
Adam Hathcock
7ee885e7d5 Merge pull request #41 from mattbab/patch-1
Fixed simple typo
2015-01-21 08:02:48 +00:00
M.Babcock
ed05bd721f Fixed simple typo 2015-01-20 20:24:22 -06:00
Adam Hathcock
e52c183f1a Merge pull request #40 from Strachu/master
Inconsistent time format
2015-01-14 14:25:57 +00:00
Adam Hathcock
ed6ad6ac6d Merge pull request #39 from hrasyid/master
Fix typo
2015-01-14 14:24:51 +00:00
Strachu
62f198b532 All archive types now consistently return times as local time. 2015-01-14 14:23:59 +01:00
Hamdanil Rasyid
9770cfec9b Fix typo 2015-01-11 17:06:02 -08:00
Adam Hathcock
e05f30308c Merge pull request #30 from larvata/fix-zip-ansi-filename
Fix ansi filename decoded as gibberish in zip file
2014-12-24 17:10:30 +00:00
Adam Hathcock
6958347849 Merge pull request #32 from larvata/fix-extractAllEntires
Add EntryExtractionEvent for stream reader
2014-12-24 17:10:08 +00:00
Adam Hathcock
8e6ced6138 Merge pull request #31 from larvata/implement-central-directory-header
implement info-zip unicode path extra field
2014-12-24 17:09:20 +00:00
larvata
0c36ff6082 Fix ansi filename decoded as gibberish in zip file 2014-12-24 13:58:29 +08:00
larvata
f78e839365 implement info-zip unicode path extra field
Winrar won't set 'general purpose bit flag' for unicode filename storage
but use 'extra field:Info-ZIP Unicode Path Extra Field' instead.
2014-12-24 13:51:31 +08:00
larvata
7e3f04e669 add entryExtractionEvent for stream 2014-12-22 16:34:47 +08:00
Adam Hathcock
2d237bfbca Merge pull request #29 from arition/password_fix
Fix error when password is not in English
2014-12-18 23:41:35 +00:00
Adam Hathcock
e6e88dbde0 Merge pull request #28 from Strachu/tar_fix
Fixed bugs related to handling of .tar archives with long names
2014-12-16 14:37:09 +00:00
arition
e558a78354 Fix error when password is not in English 2014-12-16 19:47:13 +08:00
Adam Hathcock
c2df06a746 Merge pull request #27 from Strachu/rar_reorder
Changed the order of detecting whether the archive is in .rar format.
2014-12-16 10:51:47 +00:00
Adam Hathcock
41da844250 Merge pull request #26 from Strachu/7z_mtime
Exposed modification time for .7z archives
2014-12-16 10:47:26 +00:00
Strachu
8fcb0cb7a2 Fixed bug causing entries of non-ustar archive being after one with very long name to be discarded 2014-12-16 11:11:02 +01:00
Strachu
2e533f9fb5 Fixed handling of ustar tar files with long names. 2014-12-15 21:13:57 +01:00
Strachu
ca2778b658 Changed the order of detecting whether the archive is in .rar format.
Its very slow with big archives and shouldn't be done when we got archive in format which can be detected fast.
2014-12-15 20:57:54 +01:00
Strachu
3147ee0f14 Exposed modification time for .7z archives 2014-12-15 20:26:26 +01:00
Adam Hathcock
f72558de9e Merge pull request #23 from pivotal-cf-experimental/master
Adds MIT license.
2014-11-11 17:33:45 +00:00
mavenraven.org
6d69791db1 Adds MIT license. 2014-11-11 08:48:32 -08:00
Adam Hathcock
6e05a20136 Support file sizes larger than int.MaxValue 2014-10-24 09:39:59 +01:00
Adam Hathcock
d36ae445e2 Don't dispose! 2014-07-01 19:33:59 +01:00
Adam Hathcock
022f7ed26b Fix change from previous pull request 2014-04-30 11:27:49 +01:00
Adam Hathcock
d1a64021e1 Check for entry stream null. 2014-04-30 11:26:54 +01:00
Adam Hathcock
9225531f1e Merge pull request #15 from bastianeicher/master
.NET 2.0 version in NuGet package with limited dependency on LinqBridge
2014-04-24 10:16:00 +01:00
Bastian Eicher
650dc6f8bb .NET 2.0 version in NuGet package with limited dependency on LinqBridge 2014-04-16 17:07:41 +02:00
Adam Hathcock
49d6f1f633 Enumerate FILES not DIRECTORIES 2014-04-15 09:41:16 +01:00
Adam Hathcock
505f435f5d Renamed LinqBridge to .NET 2.0 target.
Cleaned up some cross-versioning code.
2014-04-15 09:36:05 +01:00
Adam Hathcock
d9d63fba96 Merge pull request #12 from bastianeicher/master
Added .NET 2.0 version (with LinqBridge)
2014-04-15 09:26:36 +01:00
Bastian Eicher
8c3d260d7c Added .NET 2.0 version (with LinqBridge) 2014-03-18 14:45:48 +01:00
Adam Hathcock
0fd00efada Fixed other projects 2014-02-01 10:36:22 +00:00
Adam Hathcock
71e86cd7e4 Added explicit checks for multi-volume encrypted archives to throw an error 2014-02-01 10:29:01 +00:00
Adam Hathcock
c64a96398d RarArchives now have password support 2014-02-01 09:01:15 +00:00
Adam Hathcock
efa9805fe4 Fixing Windows Store project to be Windows 8.1 with newest files 2014-02-01 07:57:50 +00:00
Adam Hathcock
2100d49cef Little more clean up 2013-12-23 12:29:41 +00:00
Adam Hathcock
66ffc82d41 Entries don't have FilePaths, they have keys 2013-12-23 12:20:06 +00:00
Adam Hathcock
e58ec599f0 Cleaning up some FileInfo non-usage and fixing tests. 2013-12-23 12:15:57 +00:00
Adam Hathcock
4eda2043df Moved ExtractTo to common logic 2013-12-23 11:42:08 +00:00
Adam Hathcock
afd65a7505 Removed unimplemented Close 2013-12-23 11:12:07 +00:00
Adam Hathcock
25148a9bf8 No expected exception 2013-12-22 09:37:35 +00:00
Adam Hathcock
97bc1865dc When using writable entries, reset stream on entry stream access. 2013-12-21 17:37:54 +00:00
Adam Hathcock
865afbfbf0 Throw exception when adding duplicate entry 2013-12-21 17:29:36 +00:00
Adam Hathcock
c59e6a8c99 AddEntry should return the added entry. 2013-12-21 17:14:41 +00:00
Adam Hathcock
be9111630e Fix for some type management problems 2013-12-21 09:34:40 +00:00
Adam Hathcock
d46de85ca2 Allow multiple saves of an archive. New entry streams must be seekable and resetable. 2013-12-20 15:50:29 +00:00
Adam Hathcock
c1562c5829 new entry streams must be readable and seekable 2013-12-20 15:33:20 +00:00
Adam Hathcock
f862cc6947 Remove redundant test from previous change 2013-12-20 15:32:57 +00:00
Adam Hathcock
cc3848aea5 Remove write check as I never actually write to any of the read streams 2013-12-20 15:00:17 +00:00
Adam Hathcock
46fc663e90 Fixed issue where adding a new entry then removing it wouldn't actually remove it. 2013-12-20 12:28:17 +00:00
Adam Hathcock
84ed6bc7f0 More Can* implemented 2013-12-19 11:05:39 +00:00
Adam Hathcock
fe5895d373 Implement Can* 2013-12-19 10:35:15 +00:00
Adam Hathcock
770e2d6e75 Resharper 8.1 2013-12-19 10:34:59 +00:00
Adam Hathcock
84704e5ce2 Release packaging for 0.10.3 2013-12-15 11:42:54 +00:00
Adam Hathcock
059fe1f545 Test for previous change 2013-12-15 11:16:59 +00:00
Adam Hathcock
fe8c6aec5f Ensure adding always disposes 2013-12-15 11:16:48 +00:00
Adam Hathcock
3ab38fbfc2 If the requested amount of bytes was not read, assume end of stream 2013-11-24 09:40:38 +00:00
Adam Hathcock
b4bfde77d2 Version 0.10.2 2013-11-23 13:08:54 +00:00
Adam Hathcock
c4b005b3d4 Strong name Windows Store assembly 2013-11-23 11:13:01 +00:00
Adam Hathcock
c9d1f7b528 Updating with VS 2013 2013-11-23 11:10:22 +00:00
Adam Hathcock
21aa57945d Fix for byte counting 2013-11-23 11:10:07 +00:00
Adam Hathcock
1d0c7b6445 Added work around for invalid extended time format
https://sharpcompress.codeplex.com/workitem/42
2013-10-19 13:28:33 +01:00
Adam Hathcock
f33d8f9a5e Fixed deletion test 2013-10-19 13:21:37 +01:00
Adam Hathcock
ee2d6216b7 Remove unused class 2013-08-14 16:36:09 +01:00
Adam Hathcock
a42414bdaa Version 0.10.1.3 - hopefully cleaned up building problem for different platforms 2013-08-14 16:26:41 +01:00
Adam Hathcock
3e201053c6 Version 0.10.1.2 2013-08-14 08:06:07 +01:00
Adam Hathcock
46c03ce027 Release for 0.10.1 as 0.10.1.1 for nuspec changes 2013-08-13 20:35:40 +01:00
Adam Hathcock
718dac1a31 Merge pull request #4 from sawilde/master
Ensure the assemblies have the same name in the nuget package #2
2013-08-13 12:28:37 -07:00
Shaun Wilde
137f2655a5 Merge branch 'master' of https://github.com/adamhathcock/sharpcompress
Conflicts:
	NuGet/sharpcompress.nuspec
2013-08-14 05:21:45 +10:00
Adam Hathcock
8109ae003d 0.10.1 packing 2013-08-11 09:51:05 +01:00
Adam Hathcock
8325b919ce Version 0.10.1 2013-08-11 09:47:00 +01:00
Adam Hathcock
61c97faf6c Remove needless sync stream. 2013-08-11 09:45:46 +01:00
Shaun Wilde
2dc297394f Ensure the assemblies have the same name in the nuget package #2 2013-08-08 19:40:11 +10:00
Adam Hathcock
7aa5d310f2 Packaging for 0.10 2013-07-27 12:43:02 +01:00
Adam Hathcock
e3fb32aa3c Marking 0.10 2013-07-27 12:36:40 +01:00
Adam Hathcock
65090b0fb0 Force tests to run single threaded 2013-07-27 12:20:32 +01:00
Adam Hathcock
3bbb407bdb Fixed line endings 2013-07-27 12:20:17 +01:00
Adam Hathcock
404fa8c62d AES zip decryption works 2013-07-27 12:06:54 +01:00
Adam Hathcock
9cf8c1a747 Moved classes into own files 2013-07-27 08:30:20 +01:00
Adam Hathcock
0937c63a9e Added extra encryption test. 2013-07-27 08:27:31 +01:00
Adam Hathcock
f367f489eb Adding bouncy castle crypto for portable (and metro) 2013-07-20 11:46:37 +01:00
Adam Hathcock
d78677186b Refactor crypto out of MarkingBinaryReader into RarCrypto specific class. Remove functionality from portable build to make it work. 2013-07-16 16:53:00 +01:00
Adam Hathcock
9447c1ed71 Add resharper shared config 2013-07-16 16:52:01 +01:00
Adam Hathcock
a16219763b Merge pull request #1 from hrasyid/master
Added support for decryption of RAR files
2013-07-16 07:27:31 -07:00
Hamdanil Rasyid
430263b672 More style adjustment 2013-07-16 22:19:41 +08:00
Hamdanil Rasyid
cc902bcb2d Style issue and access modifiers 2013-07-16 22:17:15 +08:00
Hamdanil Rasyid
a29f7d4500 Revert "Remove requirement for signature"
This reverts commit 1d10ea29da.
2013-07-16 22:00:13 +08:00
Hamdanil Rasyid
f9194b645d Merge branch 'master' of https://github.com/hrasyid/sharpcompress 2013-07-16 00:18:36 +08:00
Hamdanil Rasyid
c7f6b506b5 Use faster implementation of SHA1 2013-07-16 00:17:24 +08:00
Hamdanil Rasyid
1ab89ba59c Cleanup 2013-07-16 00:04:54 +08:00
Hamdanil Rasyid
3370fadbd1 Refactor all cryptography codes to RarRijndael 2013-07-15 23:43:26 +08:00
Hamdanil Rasyid
a73c831647 Refactor initialization codes into one class 2013-07-15 23:29:24 +08:00
hrasyid
203a7beef7 Merge pull request #1 from hrasyid/dev_rardecryption
Dev rardecryption
2013-07-14 09:56:39 -07:00
Hamdanil Rasyid
6c2b447530 Fix filename 2013-07-15 00:44:07 +08:00
Hamdanil Rasyid
1e7d6dc4f5 Test both Rar with header+ file encrypted and only file encrypted 2013-07-15 00:42:48 +08:00
Hamdanil Rasyid
37c4665630 Make password a parameter 2013-07-15 00:35:35 +08:00
Hamdanil Rasyid
d15c8785ac Use more meaningful error message 2013-07-14 23:22:08 +08:00
Hamdanil Rasyid
ab19dedf1f Fix bug when ignoring offset 2013-07-14 23:20:43 +08:00
Hamdanil Rasyid
34190f6576 Code tidyness 2013-07-14 19:09:33 +08:00
Hamdanil Rasyid
78cecda03a Update to reflect folder structure 2013-07-14 19:08:54 +08:00
Hamdanil Rasyid
13de04ddd2 Fix bug when no rijndael is used 2013-07-14 19:08:20 +08:00
Hamdanil Rasyid
e1511bf3ba Decrypt stream (in addition to header) 2013-07-14 19:04:22 +08:00
Hamdanil Rasyid
e78ead7bc3 Temporarily do not treat warning as error 2013-07-13 21:49:35 +08:00
Hamdanil Rasyid
bb2dcce57a Remove comments from reference code 2013-07-13 21:49:04 +08:00
Hamdanil Rasyid
c0b630c795 Decrypt rar - first attempt, test still fails 2013-07-13 20:12:35 +08:00
Hamdanil Rasyid
22d181e637 recognize encrypted flag in archive header 2013-07-13 10:45:25 +08:00
Hamdanil Rasyid
af8e4f9da8 Add test case for encrypted Rar 2013-07-12 23:26:30 +08:00
Hamdanil Rasyid
ad421936dc Modify test base to follow my folder structure 2013-07-12 23:23:56 +08:00
Hamdanil Rasyid
1d10ea29da Remove requirement for signature 2013-07-12 21:43:38 +08:00
Adam Hathcock
31f8c18bc5 Added codeplex discussion link 2013-05-28 19:40:13 +01:00
Adam Hathcock
692bebf658 Better message for supported types
Changed exception message in Reader/Archive Factory to list the
supported types.
2013-05-28 19:34:41 +01:00
Adam Hathcock
0ab103e1b1 Made streams Dispose resilient
Made streams resilient to dispose being called multiple times.  Removed
unused stream.
2013-05-28 19:29:54 +01:00
Adam Hathcock
483f2e564a Fixing ArchiveFactory.Open IsRarFile: https://sharpcompress.codeplex.com/workitem/35 2013-05-07 14:31:30 +01:00
Adam Hathcock
ea6661ee8e Changing some nuget metadata 2013-05-04 17:15:46 +01:00
Adam Hathcock
9ff2369744 Version 0.9 2013-05-04 17:05:09 +01:00
176 changed files with 9685 additions and 2667 deletions

3
.gitignore vendored
View File

@@ -6,3 +6,6 @@ bin/
*.user
TestArchives/Scratch/
TestArchives/Scratch2/
TestResults/
*.nupkg
packages/*/

21
LICENSE.txt Normal file
View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2014 Adam Hathcock
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -1,23 +1,24 @@
<?xml version="1.0"?>
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<version>0.8.2</version>
<authors>Adam Hathcock</authors>
<owners>Adam Hathcock</owners>
<licenseUrl>http://sharpcompress.codeplex.com/license</licenseUrl>
<projectUrl>http://sharpcompress.codeplex.com/</projectUrl>
<id>sharpcompress</id>
<title>SharpCompress - Pure C# Decompression/Compression</title>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>SharpCompress is a compression library for .NET/Mono/Silverlight/WP7 that can unrar, decompress 7zip, zip/unzip, tar/untar bzip2/unbzip2 and gzip/ungzip with forward-only reading and file random access APIs. Write support for zip/tar/bzip2/gzip is implemented.</description>
<releaseNotes />
<language>en-US</language>
<tags>rar unrar zip unzip bzip2 gzip tar 7zip .net40 .net35 sl4</tags>
</metadata>
<files>
<file src="..\bin\SharpCompress.3.5.dll" target="lib\net35\SharpCompress.3.5.dll" />
<file src="..\bin\SharpCompress.dll" target="lib\net40\SharpCompress.dll" />
<file src="..\bin\SharpCompress.WP7.dll" target="lib\sl3-wp\SharpCompress.WP7.dll" />
<file src="..\bin\SharpCompress.Silverlight.dll" target="lib\sl50\SharpCompress.Silverlight.dll" />
</files>
<metadata>
<id>sharpcompress</id>
<version>0.11.3</version>
<title>SharpCompress - Pure C# Decompression/Compression</title>
<authors>Adam Hathcock</authors>
<owners>Adam Hathcock</owners>
<licenseUrl>https://github.com/adamhathcock/sharpcompress/blob/master/LICENSE.txt</licenseUrl>
<projectUrl>https://github.com/adamhathcock/sharpcompress</projectUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>SharpCompress is a compression library for .NET/Mono/Silverlight/WP7/WindowsStore that can unrar, decompress 7zip, zip/unzip, tar/untar bzip2/unbzip2 and gzip/ungzip with forward-only reading and file random access APIs. Write support for zip/tar/bzip2/gzip is implemented.</description>
<releaseNotes />
<language>en-US</language>
<tags>rar unrar zip unzip bzip2 gzip tar 7zip</tags>
<dependencies>
</dependencies>
</metadata>
<files>
<file src="..\bin\Full\SharpCompress.dll" target="lib\net40\SharpCompress.dll" />
<file src="..\bin\WindowsStore\SharpCompress.dll" target="lib\netcore45\SharpCompress.dll" />
<file src="..\bin\Portable\SharpCompress.dll" target="lib\portable-net4+sl5+wp8+win8\SharpCompress.dll" />
</files>
</package>

View File

@@ -3,7 +3,7 @@ SharpCompress
Github mirror of http://sharpcompress.codeplex.com
SharpCompress is a compression library for .NET/Mono/Silverlight/WP7 that can unrar, un7zip, unzip, untar unbzip2 and ungzip with forward-only reading and file random access APIs. Write support for zip/tar/bzip2/gzip is implemented.
SharpCompress is a compression library for .NET/Mono/Silverlight/WP7 that can unrar, un7zip, unzip, untar unbzip2 and ungzip with forward-only reading and file random access APIs. Write support for zip/tar/bzip2/gzip are implemented.
The major feature is support for non-seekable streams so large files can be processed on the fly (i.e. download stream).
@@ -16,9 +16,55 @@ Want to contribute?
I'm always looking for help or ideas. Please submit code or email with ideas. Unfortunately, just letting me know you'd like to help is not enough because I really have no overall plan of what needs to be done. I'll definitely accept code submissions and add you as a member of the project!
TODOs (always lots):
* RAR 5 support
* 7Zip writing
* RAR Decryption
* Zip64
* Multi-volume Zip support.
7Zip implementation based on: https://code.google.com/p/managed-lzma/
Version 0.11.1:
==============
- Added Cancel on IReader
- Removed .NET 2.0 support and LinqBridge dependency
Version 0.11:
==============
- Been over a year, contains mainly fixes from contributors!
- Possible breaking change: ArchiveEncoding is UTF8 by default now.
- TAR supports writing long names using longlink
- RAR Protect Header added
Version 0.10.3:
==============
- Finally fixed Disposal issue when creating a new archive with the Archive API
Version 0.10.2:
==============
- Fixed Rar Header reading for invalid extended time headers.
- Windows Store assembly is now strong named
- Known issues with Long Tar names being worked on
- Updated to VS2013
- Portable targets SL5 and Windows Phone 8 (up from SL4 and WP7)
Version 0.10.1:
==============
- Fixed 7Zip extraction performance problem
Version 0.10:
==============
- Added support for RAR Decryption (thanks to https://github.com/hrasyid)
- Embedded some BouncyCastle crypto classes to allow RAR Decryption and Winzip AES Decryption in Portable and Windows Store DLLs
- Built in Release (I think)
Some Help/Discussion:
https://sharpcompress.codeplex.com/discussions
7Zip implementation based on: https://code.google.com/p/managed-lzma/
LICENSE
Copyright (c) 2000 - 2011 The Legion Of The Bouncy Castle (http://www.bouncycastle.org)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -120,11 +120,60 @@ namespace SharpCompress.Test
void archive_EntryExtractionBegin(object sender, ArchiveExtractionEventArgs<IArchiveEntry> e)
{
this.entryTotal = e.Item.Size;
Console.WriteLine("Initializing File Entry Extraction: " + e.Item.FilePath);
Console.WriteLine("Initializing File Entry Extraction: " + e.Item.Key);
}
private long? entryTotal;
private long partTotal;
private long totalSize;
protected void ArchiveFileReadEx(string testArchive)
{
testArchive = Path.Combine(TEST_ARCHIVES_PATH, testArchive);
ArchiveFileReadEx(testArchive.AsEnumerable());
}
/// <summary>
/// Demonstrate the TotalUncompressSize property, and the ExtractOptions.PreserveFileTime and ExtractOptions.PreserveAttributes extract options
/// </summary>
protected void ArchiveFileReadEx(IEnumerable<string> testArchives)
{
foreach (var path in testArchives)
{
ResetScratch();
using (var archive = ArchiveFactory.Open(path))
{
this.totalSize = archive.TotalUncompressSize;
archive.EntryExtractionBegin += Archive_EntryExtractionBeginEx;
archive.EntryExtractionEnd += Archive_EntryExtractionEndEx;
archive.CompressedBytesRead += Archive_CompressedBytesReadEx;
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
{
entry.WriteToDirectory(SCRATCH_FILES_PATH,
ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite | ExtractOptions.PreserveFileTime | ExtractOptions.PreserveAttributes);
}
}
VerifyFilesEx();
}
}
private void Archive_EntryExtractionEndEx(object sender, ArchiveExtractionEventArgs<IArchiveEntry> e)
{
this.partTotal += e.Item.Size;
}
private void Archive_CompressedBytesReadEx(object sender, CompressedBytesReadEventArgs e)
{
string percentage = this.entryTotal.HasValue ? this.CreatePercentage(e.CompressedBytesRead, this.entryTotal.Value).ToString() : "-";
string tortalPercentage = this.CreatePercentage(this.partTotal + e.CompressedBytesRead, this.totalSize).ToString();
Console.WriteLine(@"Read Compressed File Progress: {0}% Total Progress {1}%", percentage, tortalPercentage);
}
private void Archive_EntryExtractionBeginEx(object sender, ArchiveExtractionEventArgs<IArchiveEntry> e)
{
this.entryTotal = e.Item.Size;
}
private int CreatePercentage(long n, long d)
{

View File

@@ -23,7 +23,7 @@ namespace SharpCompress.Test
using (var archive = ArchiveFactory.Open(stream))
{
var entry = archive.Entries.First();
entry.WriteToFile(Path.Combine(SCRATCH_FILES_PATH, entry.FilePath));
entry.WriteToFile(Path.Combine(SCRATCH_FILES_PATH, entry.Key));
}
CompareArchivesByPath(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar"),
Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar"));
@@ -37,7 +37,7 @@ namespace SharpCompress.Test
using (var archive = GZipArchive.Open(stream))
{
var entry = archive.Entries.First();
entry.WriteToFile(Path.Combine(SCRATCH_FILES_PATH, entry.FilePath));
entry.WriteToFile(Path.Combine(SCRATCH_FILES_PATH, entry.Key));
}
CompareArchivesByPath(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar"),
Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar"));

View File

@@ -10,17 +10,93 @@ namespace SharpCompress.Test
[TestClass]
public class RarArchiveTests : ArchiveTests
{
[TestMethod]
public void Rar_EncryptedFileAndHeader_Archive()
{
ReadRarPassword("Rar.encrypted_filesAndHeader.rar", "test");
}
[TestMethod]
public void Rar_EncryptedFileOnly_Archive()
{
ReadRarPassword("Rar.encrypted_filesOnly.rar", "test");
}
[TestMethod]
public void Rar_Encrypted_Archive()
{
ReadRarPassword("Encrypted.rar", "test");
}
private void ReadRarPassword(string testArchive, string password)
{
ResetScratch();
using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, testArchive)))
using (var archive = RarArchive.Open(stream, Options.KeepStreamsOpen, password))
{
foreach (var entry in archive.Entries)
{
if (!entry.IsDirectory)
{
Assert.AreEqual(entry.CompressionType, CompressionType.Rar);
entry.WriteToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite);
}
}
}
VerifyFiles();
}
[TestMethod]
[ExpectedException(typeof(InvalidFormatException))]
public void Rar_Multi_Archive_Encrypted()
{
ArchiveFileReadPassword("EncryptedParts.part01.rar", "test");
}
protected void ArchiveFileReadPassword(string archiveName, string password)
{
ResetScratch();
using (var archive = RarArchive.Open(Path.Combine(TEST_ARCHIVES_PATH, archiveName), Options.None, password))
{
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
{
entry.WriteToDirectory(SCRATCH_FILES_PATH,
ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite);
}
}
VerifyFiles();
}
[TestMethod]
public void Rar_None_ArchiveStreamRead()
{
ArchiveStreamRead("Rar.none.rar");
}
[TestMethod]
public void Rar_ArchiveStreamRead()
{
ArchiveStreamRead("Rar.rar");
}
[TestMethod]
public void Rar_test_invalid_exttime_ArchiveStreamRead()
{
ResetScratch();
using (var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "test_invalid_exttime.rar")))
{
using (var archive = ArchiveFactory.Open(stream))
{
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
{
entry.WriteToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite);
}
}
}
}
[TestMethod]
public void Rar_Jpg_ArchiveStreamRead()
{
@@ -47,7 +123,7 @@ namespace SharpCompress.Test
{
using (var archive = RarArchive.Open(stream))
{
Assert.IsFalse(archive.IsSolidArchive());
Assert.IsFalse(archive.IsSolid);
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
{
entry.WriteToDirectory(SCRATCH_FILES_PATH,
@@ -114,7 +190,7 @@ namespace SharpCompress.Test
{
using (var archive = RarArchive.Open(stream))
{
Assert.IsFalse(archive.IsSolidArchive());
Assert.IsFalse(archive.IsSolid);
Assert.IsTrue(archive.Entries.Any(entry => entry.IsDirectory));
}
}

View File

@@ -0,0 +1,60 @@
using System.IO;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SharpCompress.Common;
using SharpCompress.Common.Rar.Headers;
using SharpCompress.IO;
namespace SharpCompress.Test.Rar
{
/// <summary>
/// Summary description for RarFactoryReaderTest
/// </summary>
[TestClass]
public class RarHeaderFactoryTest : TestBase
{
private RarHeaderFactory rarHeaderFactory;
[TestInitialize]
public void Initialize()
{
ResetScratch();
rarHeaderFactory = new RarHeaderFactory(StreamingMode.Seekable, Options.KeepStreamsOpen);
}
[TestMethod]
public void ReadHeaders_RecognizeEncryptedFlag()
{
ReadEncryptedFlag("Rar.Encrypted_filesAndHeader.rar", true);
}
private void ReadEncryptedFlag(string testArchive, bool isEncrypted)
{
using (var stream = GetReaderStream(testArchive))
foreach (var header in rarHeaderFactory.ReadHeaders(stream))
{
if (header.HeaderType == HeaderType.ArchiveHeader)
{
Assert.AreEqual(isEncrypted, rarHeaderFactory.IsEncrypted);
break;
}
}
}
[TestMethod]
public void ReadHeaders_RecognizeNoEncryptedFlag()
{
ReadEncryptedFlag("Rar.rar", false);
}
private FileStream GetReaderStream(string testArchive)
{
return new FileStream(Path.Combine(TEST_ARCHIVES_PATH, testArchive),
FileMode.Open);
}
}
}

View File

@@ -33,10 +33,33 @@ namespace SharpCompress.Test
VerifyFiles();
}
//[TestMethod]
public void Rar_Multi_Reader_Encrypted()
{
var testArchives = new string[] { "EncryptedParts.part01.rar",
"EncryptedParts.part02.rar",
"EncryptedParts.part03.rar",
"EncryptedParts.part04.rar",
"EncryptedParts.part05.rar",
"EncryptedParts.part06.rar"};
ResetScratch();
using (var reader = RarReader.Open(testArchives.Select(s => Path.Combine(TEST_ARCHIVES_PATH, s))
.Select(p => File.OpenRead(p))))
{
while (reader.MoveToNextEntry())
{
reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite);
}
}
VerifyFiles();
}
[TestMethod]
public void Rar_Multi_Reader_Delete_Files()
{
var testArchives = new string[] { "Rar.multi.part01.rar",
var testArchives = new string[] { "Rar.multi.part01.rar",
"Rar.multi.part02.rar",
"Rar.multi.part03.rar",
"Rar.multi.part04.rar",
@@ -44,27 +67,30 @@ namespace SharpCompress.Test
"Rar.multi.part06.rar"};
ResetScratch();
ResetScratch();
foreach (var file in testArchives)
{
File.Copy(Path.Combine(TEST_ARCHIVES_PATH, file), Path.Combine(SCRATCH2_FILES_PATH, file));
}
foreach (var file in testArchives)
{
File.Copy(Path.Combine(TEST_ARCHIVES_PATH, file), Path.Combine(SCRATCH2_FILES_PATH, file));
}
var streams = testArchives.Select(s => Path.Combine(SCRATCH2_FILES_PATH, s)).Select(File.OpenRead).ToList();
using (var reader = RarReader.Open(streams))
{
while (reader.MoveToNextEntry())
{
reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite);
}
}
foreach (var stream in streams)
{
stream.Dispose();
}
VerifyFiles();
using (var reader = RarReader.Open(testArchives.Select(s => Path.Combine(SCRATCH2_FILES_PATH, s))
.Select(p => File.OpenRead(p)), Options.None))
{
while (reader.MoveToNextEntry())
{
reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite);
}
}
VerifyFiles();
foreach (var file in testArchives.Select(s => Path.Combine(SCRATCH2_FILES_PATH, s)))
{
File.Delete(file);
}
foreach (var file in testArchives.Select(s => Path.Combine(SCRATCH2_FILES_PATH, s)))
{
File.Delete(file);
}
}
[TestMethod]
@@ -79,6 +105,44 @@ namespace SharpCompress.Test
Read("Rar.rar", CompressionType.Rar);
}
[TestMethod]
public void Rar_EncryptedFileAndHeader_Reader()
{
ReadRar("Rar.encrypted_filesAndHeader.rar", "test");
}
[TestMethod]
public void Rar_EncryptedFileOnly_Reader()
{
ReadRar("Rar.encrypted_filesOnly.rar", "test");
}
[TestMethod]
public void Rar_Encrypted_Reader()
{
ReadRar("Encrypted.rar", "test");
}
private void ReadRar(string testArchive, string password)
{
ResetScratch();
using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, testArchive)))
using (var reader = RarReader.Open(stream, password))
{
while (reader.MoveToNextEntry())
{
if (!reader.Entry.IsDirectory)
{
Assert.AreEqual(reader.Entry.CompressionType, CompressionType.Rar);
reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite);
}
}
}
VerifyFiles();
}
[TestMethod]
public void Rar_Entry_Stream()
{
@@ -93,8 +157,8 @@ namespace SharpCompress.Test
Assert.AreEqual(reader.Entry.CompressionType, CompressionType.Rar);
using (var entryStream = reader.OpenEntryStream())
{
string file = Path.GetFileName(reader.Entry.FilePath);
string folder = Path.GetDirectoryName(reader.Entry.FilePath);
string file = Path.GetFileName(reader.Entry.Key);
string folder = Path.GetDirectoryName(reader.Entry.Key);
string destdir = Path.Combine(SCRATCH_FILES_PATH, folder);
if (!Directory.Exists(destdir))
{
@@ -161,7 +225,7 @@ namespace SharpCompress.Test
{
while (reader.MoveToNextEntry())
{
if (reader.Entry.FilePath.Contains("jpg"))
if (reader.Entry.Key.Contains("jpg"))
{
Assert.AreEqual(reader.Entry.CompressionType, CompressionType.Rar);
reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite);
@@ -179,7 +243,7 @@ namespace SharpCompress.Test
{
while (reader.MoveToNextEntry())
{
if (reader.Entry.FilePath.Contains("jpg"))
if (reader.Entry.Key.Contains("jpg"))
{
Assert.AreEqual(reader.Entry.CompressionType, CompressionType.Rar);
reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite);

View File

@@ -61,6 +61,11 @@ namespace SharpCompress.Test
ArchiveFileRead("7Zip.BZip2.7z");
}
[TestMethod]
public void SevenZipArchive_LZMA_Time_Attributes_PathRead()
{
ArchiveFileReadEx("7Zip.LZMA.7z");
}
[TestMethod]
[ExpectedException(typeof(IndexOutOfRangeException))]

View File

@@ -0,0 +1,113 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{E9C3C94B-FB27-4B4F-B225-57513C254D37}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>SharpCompress.Test</RootNamespace>
<AssemblyName>SharpCompress.Test.Portable</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkProfile>
</TargetFrameworkProfile>
<FileAlignment>512</FileAlignment>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\sharpcompress\</SolutionDir>
<RestorePackages>true</RestorePackages>
<ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\DebugPortable\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<StartupObject>
</StartupObject>
</PropertyGroup>
<PropertyGroup>
<SignAssembly>false</SignAssembly>
</PropertyGroup>
<PropertyGroup>
<AssemblyOriginatorKeyFile>..\SharpCompress\SharpCompress.pfx</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
<Reference Include="System" />
<Reference Include="System.Core" />
</ItemGroup>
<ItemGroup>
<Compile Include="ArchiveTests.cs" />
<Compile Include="GZip\GZipWriterTests.cs" />
<Compile Include="GZip\GZipArchiveTests.cs" />
<Compile Include="Rar\RarHeaderFactoryTest.cs" />
<Compile Include="SevenZip\SevenZipArchiveTests.cs" />
<Compile Include="Streams\StreamTests.cs" />
<Compile Include="Tar\TarWriterTests.cs" />
<Compile Include="Tar\TarReaderTests.cs" />
<Compile Include="Zip\ZipWriterTests.cs" />
<Compile Include="WriterTests.cs" />
<Compile Include="Rar\RarReaderTests.cs" />
<Compile Include="ReaderTests.cs" />
<Compile Include="Tar\TarArchiveTests.cs" />
<Compile Include="Zip\ZipArchiveTests.cs" />
<Compile Include="Rar\RarArchiveTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="RewindableStreamTest.cs" />
<Compile Include="TestBase.cs" />
<Compile Include="TestStream.cs" />
<Compile Include="Zip\ZipReaderTests.cs" />
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
<DesignTime>True</DesignTime>
</Compile>
<None Include="..\SharpCompress\SharpCompress.pfx">
<Link>SharpCompress.pfx</Link>
</None>
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\SharpCompress\SharpCompress.PortableTest.csproj">
<Project>{efdcaf57-fd4d-4e5d-a3d5-f26b875817ed}</Project>
<Name>SharpCompress.PortableTest</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@@ -42,7 +42,7 @@
</StartupObject>
</PropertyGroup>
<PropertyGroup>
<SignAssembly>true</SignAssembly>
<SignAssembly>false</SignAssembly>
</PropertyGroup>
<PropertyGroup>
<AssemblyOriginatorKeyFile>..\SharpCompress\SharpCompress.pfx</AssemblyOriginatorKeyFile>
@@ -56,6 +56,7 @@
<Compile Include="ArchiveTests.cs" />
<Compile Include="GZip\GZipWriterTests.cs" />
<Compile Include="GZip\GZipArchiveTests.cs" />
<Compile Include="Rar\RarHeaderFactoryTest.cs" />
<Compile Include="SevenZip\SevenZipArchiveTests.cs" />
<Compile Include="Streams\StreamTests.cs" />
<Compile Include="Tar\TarWriterTests.cs" />
@@ -96,9 +97,9 @@
</Compile>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\SharpCompress\SharpCompress.csproj">
<Project>{10A689CF-76A2-4A4F-96E4-553C33398438}</Project>
<Name>SharpCompress</Name>
<ProjectReference Include="..\SharpCompress\SharpCompress.Unsigned.csproj">
<Project>{27d535cb-2fd3-4621-8c9a-46161fc77a5d}</Project>
<Name>SharpCompress.Unsigned</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

View File

@@ -30,13 +30,71 @@ namespace SharpCompress.Test
[TestMethod]
public void TarArchivePathReadLongName()
public void Tar_NonUstarArchiveWithLongNameDoesNotSkipEntriesAfterTheLongOne()
{
string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "very long filename.tar");
using (var archive = TarArchive.Open(unmodified))
{
Assert.AreEqual(2, archive.Entries.Count);
Assert.AreEqual(archive.Entries.Last().FilePath, @"very long filename/very long filename very long filename very long filename very long filename very long filename very long filename very long filename very long filename very long filename very long filename.jpg");
Assert.AreEqual(5, archive.Entries.Count);
Assert.IsTrue(archive.Entries.Any(entry => entry.Key == "very long filename/"));
Assert.IsTrue(archive.Entries.Any(entry => entry.Key == "very long filename/very long filename very long filename very long filename very long filename very long filename very long filename very long filename very long filename very long filename very long filename.jpg"));
Assert.IsTrue(archive.Entries.Any(entry => entry.Key == "z_file 1.txt"));
Assert.IsTrue(archive.Entries.Any(entry => entry.Key == "z_file 2.txt"));
Assert.IsTrue(archive.Entries.Any(entry => entry.Key == "z_file 3.txt"));
}
}
[TestMethod]
public void Tar_VeryLongFilepathReadback()
{
string archive = "Tar_VeryLongFilepathReadback.tar";
ResetScratch();
// create a very long filename
string longFilename = "";
for (int i = 0; i < 600; i = longFilename.Length)
longFilename += i.ToString("D10") + "-";
longFilename += ".txt";
// Step 1: create a tar file containing a file with a long name
using (Stream stream = File.OpenWrite(Path.Combine(SCRATCH2_FILES_PATH, archive)))
using (var writer = SharpCompress.Writer.WriterFactory.Open(stream, ArchiveType.Tar, CompressionType.None))
using (Stream inputStream = new MemoryStream())
{
StreamWriter sw = new StreamWriter(inputStream);
sw.Write("dummy filecontent");
sw.Flush();
inputStream.Position = 0;
writer.Write(longFilename, inputStream, null);
}
// Step 2: check if the written tar file can be read correctly
string unmodified = Path.Combine(SCRATCH2_FILES_PATH, archive);
using (var archive2 = TarArchive.Open(unmodified))
{
Assert.AreEqual(1, archive2.Entries.Count);
Assert.IsTrue(archive2.Entries.Any(entry => entry.Key == longFilename));
foreach (var entry in archive2.Entries)
Assert.AreEqual("dummy filecontent", new StreamReader(entry.OpenEntryStream()).ReadLine());
}
}
[TestMethod]
public void Tar_UstarArchivePathReadLongName()
{
string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "ustar with long names.tar");
using(var archive = TarArchive.Open(unmodified))
{
Assert.AreEqual(6, archive.Entries.Count);
Assert.IsTrue(archive.Entries.Any(entry => entry.Key == "Directory/"));
Assert.IsTrue(archive.Entries.Any(entry => entry.Key == "Directory/Some file with veeeeeeeeeery loooooooooong name"));
Assert.IsTrue(archive.Entries.Any(entry => entry.Key == "Directory/Directory with veeeeeeeeeery loooooooooong name/"));
Assert.IsTrue(archive.Entries.Any(entry => entry.Key == "Directory/Directory with veeeeeeeeeery loooooooooong name/Some file with veeeeeeeeeery loooooooooong name"));
Assert.IsTrue(archive.Entries.Any(entry => entry.Key == "Directory/Directory with veeeeeeeeeery loooooooooong name/Directory with veeeeeeeeeery loooooooooong name/"));
Assert.IsTrue(archive.Entries.Any(entry => entry.Key == "Directory/Directory with veeeeeeeeeery loooooooooong name/Directory with veeeeeeeeeery loooooooooong name/Some file with veeeeeeeeeery loooooooooong name"));
}
}
@@ -81,7 +139,7 @@ namespace SharpCompress.Test
base.ResetScratch();
using (var archive = TarArchive.Open(unmodified))
{
var entry = archive.Entries.Where(x => x.FilePath.EndsWith("jpg")).Single();
var entry = archive.Entries.Where(x => x.Key.EndsWith("jpg")).Single();
archive.RemoveEntry(entry);
archive.SaveTo(scratchPath, CompressionType.None);
}

View File

@@ -46,8 +46,8 @@ namespace SharpCompress.Test
Assert.AreEqual(reader.Entry.CompressionType, CompressionType.BZip2);
using (var entryStream = reader.OpenEntryStream())
{
string file = Path.GetFileName(reader.Entry.FilePath);
string folder = Path.GetDirectoryName(reader.Entry.FilePath);
string file = Path.GetFileName(reader.Entry.Key);
string folder = Path.GetDirectoryName(reader.Entry.Key);
string destdir = Path.Combine(SCRATCH_FILES_PATH, folder);
if (!Directory.Exists(destdir))
{
@@ -81,7 +81,7 @@ namespace SharpCompress.Test
using (var entryStream = reader.OpenEntryStream())
{
entryStream.SkipEntry();
names.Add(reader.Entry.FilePath);
names.Add(reader.Entry.Key);
}
}
}

View File

@@ -1,21 +1,23 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SharpCompress.Common;
using SharpCompress.Reader;
namespace SharpCompress.Test
{
[TestClass]
public class TestBase
{
protected const string TEST_BASE_PATH = @"C:\Git\sharpcompress";
protected static readonly string TEST_ARCHIVES_PATH = Path.Combine(TEST_BASE_PATH, "TestArchives", "Archives");
protected static readonly string ORIGINAL_FILES_PATH = Path.Combine(TEST_BASE_PATH, "TestArchives", "Original");
protected static readonly string MISC_TEST_FILES_PATH = Path.Combine(TEST_BASE_PATH, "TestArchives", "MiscTest");
protected static readonly string SCRATCH_FILES_PATH = Path.Combine(TEST_BASE_PATH, "TestArchives", "Scratch");
protected static readonly string SCRATCH2_FILES_PATH = Path.Combine(TEST_BASE_PATH, "TestArchives", "Scratch2");
protected static string SOLUTION_BASE_PATH=null;
protected static string TEST_ARCHIVES_PATH;
protected static string ORIGINAL_FILES_PATH;
protected static string MISC_TEST_FILES_PATH;
protected static string SCRATCH_FILES_PATH;
protected static string SCRATCH2_FILES_PATH;
protected static IEnumerable<string> GetRarArchives()
{
yield return Path.Combine(TEST_ARCHIVES_PATH, "Rar.none.rar");
@@ -76,6 +78,21 @@ namespace SharpCompress.Test
}
}
/// <summary>
/// Verifies the files also check modified time and attributes.
/// </summary>
public void VerifyFilesEx()
{
if (UseExtensionInsteadOfNameToVerify)
{
VerifyFilesByExtensionEx();
}
else
{
VerifyFilesByNameEx();
}
}
protected void VerifyFilesByName()
{
var extracted =
@@ -95,6 +112,52 @@ namespace SharpCompress.Test
}
}
/// <summary>
/// Verifies the files by name also check modified time and attributes.
/// </summary>
protected void VerifyFilesByNameEx()
{
var extracted =
Directory.EnumerateFiles(SCRATCH_FILES_PATH, "*.*", SearchOption.AllDirectories)
.ToLookup(path => path.Substring(SCRATCH_FILES_PATH.Length));
var original =
Directory.EnumerateFiles(ORIGINAL_FILES_PATH, "*.*", SearchOption.AllDirectories)
.ToLookup(path => path.Substring(ORIGINAL_FILES_PATH.Length));
Assert.AreEqual(extracted.Count, original.Count);
foreach (var orig in original)
{
Assert.IsTrue(extracted.Contains(orig.Key));
CompareFilesByPath(orig.Single(), extracted[orig.Key].Single());
CompareFilesByTimeAndAttribut(orig.Single(), extracted[orig.Key].Single());
}
}
/// <summary>
/// Verifies the files by extension also check modified time and attributes.
/// </summary>
protected void VerifyFilesByExtensionEx()
{
var extracted =
Directory.EnumerateFiles(SCRATCH_FILES_PATH, "*.*", SearchOption.AllDirectories)
.ToLookup(path => Path.GetExtension(path));
var original =
Directory.EnumerateFiles(ORIGINAL_FILES_PATH, "*.*", SearchOption.AllDirectories)
.ToLookup(path => Path.GetExtension(path));
Assert.AreEqual(extracted.Count, original.Count);
foreach (var orig in original)
{
Assert.IsTrue(extracted.Contains(orig.Key));
CompareFilesByPath(orig.Single(), extracted[orig.Key].Single());
CompareFilesByTimeAndAttribut(orig.Single(), extracted[orig.Key].Single());
}
}
protected bool UseExtensionInsteadOfNameToVerify { get; set; }
protected void VerifyFilesByExtension()
@@ -122,18 +185,27 @@ namespace SharpCompress.Test
using (var file2Stream = File.OpenRead(file2))
{
Assert.AreEqual(file1Stream.Length, file2Stream.Length);
int byte1 = 0;
int byte2 = 0;
while (byte1 != -1)
for (int counter = 0; byte1 != -1; counter++)
{
byte1 = file1Stream.ReadByte();
byte2 = file2Stream.ReadByte();
Assert.AreEqual(byte1, byte2);
if (byte1 != byte2)
Assert.AreEqual(byte1, byte2, string.Format("Byte {0} differ between {1} and {2}",
counter, file1, file2));
}
}
}
protected void CompareFilesByTimeAndAttribut(string file1, string file2)
{
FileInfo fi1 = new FileInfo(file1);
FileInfo fi2 = new FileInfo(file2);
Assert.AreNotEqual(fi1.LastWriteTime, fi2.LastWriteTime);
Assert.AreEqual(fi1.Attributes, fi2.Attributes);
}
protected void CompareArchivesByPath(string file1, string file2)
{
using (var archive1 = ReaderFactory.Open(File.OpenRead(file1), Options.None))
@@ -142,10 +214,23 @@ namespace SharpCompress.Test
while (archive1.MoveToNextEntry())
{
Assert.IsTrue(archive2.MoveToNextEntry());
Assert.AreEqual(archive1.Entry.FilePath, archive2.Entry.FilePath);
Assert.AreEqual(archive1.Entry.Key, archive2.Entry.Key);
}
Assert.IsFalse(archive2.MoveToNextEntry());
}
}
private static readonly object testLock = new object();
[AssemblyInitialize]
public static void InitializePaths(TestContext ctx)
{
SOLUTION_BASE_PATH = Path.GetDirectoryName(Path.GetDirectoryName(ctx.TestDir));
TEST_ARCHIVES_PATH = Path.Combine(SOLUTION_BASE_PATH, "TestArchives", "Archives");
ORIGINAL_FILES_PATH = Path.Combine(SOLUTION_BASE_PATH, "TestArchives", "Original");
MISC_TEST_FILES_PATH = Path.Combine(SOLUTION_BASE_PATH, "TestArchives", "MiscTest");
SCRATCH_FILES_PATH = Path.Combine(SOLUTION_BASE_PATH, "TestArchives", "Scratch");
SCRATCH2_FILES_PATH = Path.Combine(SOLUTION_BASE_PATH, "TestArchives", "Scratch2");
}
}
}

View File

@@ -1,6 +1,8 @@
using System;
using System.IO;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SharpCompress.Archive;
using SharpCompress.Archive.Zip;
@@ -138,26 +140,7 @@ namespace SharpCompress.Test
base.ResetScratch();
using (var archive = ZipArchive.Open(unmodified))
{
var entry = archive.Entries.Where(x => x.FilePath.EndsWith("jpg")).Single();
archive.RemoveEntry(entry);
archive.SaveTo(scratchPath, CompressionType.Deflate);
}
CompareArchivesByPath(modified, scratchPath);
}
[TestMethod]
[ExpectedException(typeof(ArchiveException))]
public void Zip_Random_Write_Remove_Fail()
{
string scratchPath = Path.Combine(SCRATCH_FILES_PATH, "Zip.deflate.mod.zip");
string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.noEmptyDirs.zip");
string modified = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.mod.zip");
base.ResetScratch();
using (var stream = File.OpenRead(unmodified))
using (var archive = ZipArchive.Open(stream))
{
var entry = archive.Entries.Where(x => x.FilePath.EndsWith("jpg")).Single();
var entry = archive.Entries.Single(x => x.Key.EndsWith("jpg"));
archive.RemoveEntry(entry);
archive.SaveTo(scratchPath, CompressionType.Deflate);
}
@@ -181,19 +164,133 @@ namespace SharpCompress.Test
CompareArchivesByPath(modified, scratchPath);
}
[TestMethod]
public void Zip_Save_Twice()
{
string scratchPath1 = Path.Combine(SCRATCH_FILES_PATH, "a.zip");
string scratchPath2 = Path.Combine(SCRATCH_FILES_PATH, "b.zip");
ResetScratch();
using (var arc = ZipArchive.Create())
{
string str = "test.txt";
var source = new MemoryStream(Encoding.UTF8.GetBytes(str));
arc.AddEntry("test.txt", source, true, source.Length);
arc.SaveTo(scratchPath1, CompressionType.Deflate);
arc.SaveTo(scratchPath2, CompressionType.Deflate);
}
Assert.AreEqual(new FileInfo(scratchPath1).Length, new FileInfo(scratchPath2).Length);
}
[TestMethod]
public void Zip_Removal_Poly()
{
ResetScratch();
string scratchPath = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.noEmptyDirs.zip");
using (ZipArchive vfs = (ZipArchive)ArchiveFactory.Open(scratchPath))
{
var e = vfs.Entries.First(v => v.Key.EndsWith("jpg"));
vfs.RemoveEntry(e);
Assert.IsNull(vfs.Entries.FirstOrDefault(v => v.Key.EndsWith("jpg")));
Assert.IsNull(((IArchive)vfs).Entries.FirstOrDefault(v => v.Key.EndsWith("jpg")));
}
}
[TestMethod]
[ExpectedException(typeof(ArchiveException))]
public void Zip_Create_NoDups()
{
using (var arc = ZipArchive.Create())
{
arc.AddEntry("1.txt", new MemoryStream());
arc.AddEntry("\\1.txt", new MemoryStream());
}
}
[TestMethod]
public void Zip_Create_Same_Stream()
{
string scratchPath1 = Path.Combine(SCRATCH_FILES_PATH, "a.zip");
string scratchPath2 = Path.Combine(SCRATCH_FILES_PATH, "b.zip");
using (var arc = ZipArchive.Create())
{
using (var stream = new MemoryStream(Encoding.UTF8.GetBytes("qwert")))
{
arc.AddEntry("1.txt", stream, false, stream.Length);
arc.AddEntry("2.txt", stream, false, stream.Length);
arc.SaveTo(scratchPath1, CompressionType.Deflate);
arc.SaveTo(scratchPath2, CompressionType.Deflate);
}
}
Assert.AreEqual(new FileInfo(scratchPath1).Length, new FileInfo(scratchPath2).Length);
}
[TestMethod]
public void Zip_Create_New()
{
string scratchPath = Path.Combine(SCRATCH_FILES_PATH, "Zip.deflate.noEmptyDirs.zip");
base.ResetScratch();
foreach (var file in Directory.EnumerateFiles(ORIGINAL_FILES_PATH, "*.*", SearchOption.AllDirectories))
{
var newFileName = file.Substring(ORIGINAL_FILES_PATH.Length);
if (newFileName.StartsWith(Path.DirectorySeparatorChar.ToString()))
{
newFileName = newFileName.Substring(1);
}
newFileName = Path.Combine(SCRATCH_FILES_PATH, newFileName);
var newDir = Path.GetDirectoryName(newFileName);
if (!Directory.Exists(newDir))
{
Directory.CreateDirectory(newDir);
}
File.Copy(file, newFileName);
}
string scratchPath = Path.Combine(SCRATCH2_FILES_PATH, "Zip.deflate.noEmptyDirs.zip");
string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.noEmptyDirs.zip");
base.ResetScratch();
using (var archive = ZipArchive.Create())
{
archive.AddAllFromDirectory(ORIGINAL_FILES_PATH);
archive.AddAllFromDirectory(SCRATCH_FILES_PATH);
archive.SaveTo(scratchPath, CompressionType.Deflate);
}
CompareArchivesByPath(unmodified, scratchPath);
Directory.Delete(SCRATCH_FILES_PATH, true);
}
[TestMethod]
public void Zip_Create_New_Add_Remove()
{
base.ResetScratch();
foreach (var file in Directory.EnumerateFiles(ORIGINAL_FILES_PATH, "*.*", SearchOption.AllDirectories))
{
var newFileName = file.Substring(ORIGINAL_FILES_PATH.Length);
if (newFileName.StartsWith(Path.DirectorySeparatorChar.ToString()))
{
newFileName = newFileName.Substring(1);
}
newFileName = Path.Combine(SCRATCH_FILES_PATH, newFileName);
var newDir = Path.GetDirectoryName(newFileName);
if (!Directory.Exists(newDir))
{
Directory.CreateDirectory(newDir);
}
File.Copy(file, newFileName);
}
string scratchPath = Path.Combine(SCRATCH2_FILES_PATH, "Zip.deflate.noEmptyDirs.zip");
using (var archive = ZipArchive.Create())
{
archive.AddAllFromDirectory(SCRATCH_FILES_PATH);
archive.RemoveEntry(archive.Entries.Single(x => x.Key.EndsWith("jpg", StringComparison.OrdinalIgnoreCase)));
Assert.IsFalse(archive.Entries.Any(x => x.Key.EndsWith("jpg")));
}
Directory.Delete(SCRATCH_FILES_PATH, true);
}
[TestMethod]
@@ -292,7 +389,7 @@ namespace SharpCompress.Test
using (var zipArchive = ZipArchive.Open(stream))
{
foreach(var entry in zipArchive.Entries)
foreach (var entry in zipArchive.Entries)
{
using (var entryStream = entry.OpenEntryStream())
{

View File

@@ -1,6 +1,15 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2012
# Visual Studio 2013
VisualStudioVersion = 12.0.31101.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Testing", "Testing", "{932BBFCC-76E3-45FF-90CA-6BE4FBF4A097}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{F18F1765-4A02-42FD-9BEF-F0E2FCBD9D17}"
ProjectSection(SolutionItems) = preProject
NuGet\sharpcompress.nuspec = NuGet\sharpcompress.nuspec
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpCompress", "SharpCompress\SharpCompress.csproj", "{10A689CF-76A2-4A4F-96E4-553C33398438}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpCompress.Test", "SharpCompress.Test\SharpCompress.Test.csproj", "{15679D7A-F22C-4943-87FF-BF5C76C4A6FD}"
@@ -9,6 +18,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpCompress.Portable", "S
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpCompress.WindowsStore", "SharpCompress\SharpCompress.WindowsStore.csproj", "{1DF6D83C-31FF-47B6-82FE-C4603BE916B5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpCompress.PortableTest", "SharpCompress\SharpCompress.PortableTest.csproj", "{EFDCAF57-FD4D-4E5D-A3D5-F26B875817ED}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpCompress.Test.Portable", "SharpCompress.Test\SharpCompress.Test.Portable.csproj", "{E9C3C94B-FB27-4B4F-B225-57513C254D37}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpCompress.Unsigned", "SharpCompress\SharpCompress.Unsigned.csproj", "{27D535CB-2FD3-4621-8C9A-46161FC77A5D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -31,8 +46,26 @@ Global
{1DF6D83C-31FF-47B6-82FE-C4603BE916B5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1DF6D83C-31FF-47B6-82FE-C4603BE916B5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1DF6D83C-31FF-47B6-82FE-C4603BE916B5}.Release|Any CPU.Build.0 = Release|Any CPU
{EFDCAF57-FD4D-4E5D-A3D5-F26B875817ED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EFDCAF57-FD4D-4E5D-A3D5-F26B875817ED}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EFDCAF57-FD4D-4E5D-A3D5-F26B875817ED}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EFDCAF57-FD4D-4E5D-A3D5-F26B875817ED}.Release|Any CPU.Build.0 = Release|Any CPU
{E9C3C94B-FB27-4B4F-B225-57513C254D37}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E9C3C94B-FB27-4B4F-B225-57513C254D37}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E9C3C94B-FB27-4B4F-B225-57513C254D37}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E9C3C94B-FB27-4B4F-B225-57513C254D37}.Release|Any CPU.Build.0 = Release|Any CPU
{27D535CB-2FD3-4621-8C9A-46161FC77A5D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{27D535CB-2FD3-4621-8C9A-46161FC77A5D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{27D535CB-2FD3-4621-8C9A-46161FC77A5D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{27D535CB-2FD3-4621-8C9A-46161FC77A5D}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{15679D7A-F22C-4943-87FF-BF5C76C4A6FD} = {932BBFCC-76E3-45FF-90CA-6BE4FBF4A097}
{EFDCAF57-FD4D-4E5D-A3D5-F26B875817ED} = {932BBFCC-76E3-45FF-90CA-6BE4FBF4A097}
{E9C3C94B-FB27-4B4F-B225-57513C254D37} = {932BBFCC-76E3-45FF-90CA-6BE4FBF4A097}
{27D535CB-2FD3-4621-8C9A-46161FC77A5D} = {932BBFCC-76E3-45FF-90CA-6BE4FBF4A097}
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,6 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/Environment/InjectedLayers/FileInjectedLayer/=181069325DAB1C4287CD564D6CDDEDB3/AbsolutePath/@EntryValue">D:\Git\sharpcompress\SharpCompress\sharpcompress.DotSettings</s:String>
<s:String x:Key="/Default/Environment/InjectedLayers/FileInjectedLayer/=181069325DAB1C4287CD564D6CDDEDB3/RelativePath/@EntryValue">..\SharpCompress\sharpcompress.DotSettings</s:String>
<s:Boolean x:Key="/Default/Environment/InjectedLayers/FileInjectedLayer/=181069325DAB1C4287CD564D6CDDEDB3/@KeyIndexDefined">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/InjectedLayers/InjectedLayerCustomization/=File181069325DAB1C4287CD564D6CDDEDB3/@KeyIndexDefined">True</s:Boolean>
<s:Double x:Key="/Default/Environment/InjectedLayers/InjectedLayerCustomization/=File181069325DAB1C4287CD564D6CDDEDB3/RelativePriority/@EntryValue">1</s:Double></wpf:ResourceDictionary>

View File

@@ -7,7 +7,7 @@ using SharpCompress.Reader;
namespace SharpCompress.Archive
{
public abstract class AbstractArchive<TEntry, TVolume> : IArchive, IStreamListener
public abstract class AbstractArchive<TEntry, TVolume> : IArchive, IArchiveExtractionListener
where TEntry : IArchiveEntry
where TVolume : IVolume
{
@@ -20,10 +20,13 @@ namespace SharpCompress.Archive
public event EventHandler<CompressedBytesReadEventArgs> CompressedBytesRead;
public event EventHandler<FilePartExtractionBeginEventArgs> FilePartExtractionBegin;
protected string Password { get; private set; }
#if !PORTABLE && !NETFX_CORE
internal AbstractArchive(ArchiveType type, FileInfo fileInfo, Options options)
internal AbstractArchive(ArchiveType type, FileInfo fileInfo, Options options, string password)
{
this.Type = type;
Type = type;
Password = password;
if (!fileInfo.Exists)
{
throw new ArgumentException("File does not exist: " + fileInfo.FullName);
@@ -37,22 +40,23 @@ namespace SharpCompress.Archive
protected abstract IEnumerable<TVolume> LoadVolumes(FileInfo file, Options options);
#endif
internal AbstractArchive(ArchiveType type, IEnumerable<Stream> streams, Options options)
internal AbstractArchive(ArchiveType type, IEnumerable<Stream> streams, Options options, string password)
{
this.Type = type;
lazyVolumes =
new LazyReadOnlyCollection<TVolume>(LoadVolumes(streams.Select<Stream, Stream>(CheckStreams), options));
Type = type;
Password = password;
lazyVolumes = new LazyReadOnlyCollection<TVolume>(LoadVolumes(streams.Select(CheckStreams), options));
lazyEntries = new LazyReadOnlyCollection<TEntry>(LoadEntries(Volumes));
}
internal AbstractArchive(ArchiveType type)
{
this.Type = type;
Type = type;
lazyVolumes = new LazyReadOnlyCollection<TVolume>(Enumerable.Empty<TVolume>());
lazyEntries = new LazyReadOnlyCollection<TEntry>(Enumerable.Empty<TEntry>());
}
public ArchiveType Type { get; private set; }
internal void FireEntryExtractionBegin(IArchiveEntry entry)
void IArchiveExtractionListener.FireEntryExtractionBegin(IArchiveEntry entry)
{
if (EntryExtractionBegin != null)
{
@@ -60,7 +64,7 @@ namespace SharpCompress.Archive
}
}
internal void FireEntryExtractionEnd(IArchiveEntry entry)
void IArchiveExtractionListener.FireEntryExtractionEnd(IArchiveEntry entry)
{
if (EntryExtractionEnd != null)
{
@@ -80,7 +84,6 @@ namespace SharpCompress.Archive
/// <summary>
/// Returns an ReadOnlyCollection of all the RarArchiveEntries across the one or many parts of the RarArchive.
/// </summary>
/// <returns></returns>
public virtual ICollection<TEntry> Entries
{
get { return lazyEntries; }
@@ -89,7 +92,6 @@ namespace SharpCompress.Archive
/// <summary>
/// Returns an ReadOnlyCollection of all the RarArchiveVolumes across the one or many parts of the RarArchive.
/// </summary>
/// <returns></returns>
public ICollection<TVolume> Volumes
{
get { return lazyVolumes; }
@@ -98,17 +100,25 @@ namespace SharpCompress.Archive
/// <summary>
/// The total size of the files compressed in the archive.
/// </summary>
public long TotalSize
public virtual long TotalSize
{
get { return Entries.Aggregate(0L, (total, cf) => total + cf.CompressedSize); }
}
/// <summary>
/// The total size of the files as uncompressed in the archive.
/// </summary>
public virtual long TotalUncompressSize
{
get { return Entries.Aggregate(0L, (total, cf) => total + cf.Size); }
}
protected abstract IEnumerable<TVolume> LoadVolumes(IEnumerable<Stream> streams, Options options);
protected abstract IEnumerable<TEntry> LoadEntries(IEnumerable<TVolume> volumes);
IEnumerable<IArchiveEntry> IArchive.Entries
{
get { return lazyEntries.Cast<IArchiveEntry>(); }
get { return Entries.Cast<IArchiveEntry>(); }
}
IEnumerable<IVolume> IArchive.Volumes
@@ -118,7 +128,7 @@ namespace SharpCompress.Archive
private bool disposed;
public void Dispose()
public virtual void Dispose()
{
if (!disposed)
{
@@ -128,16 +138,13 @@ namespace SharpCompress.Archive
}
}
internal void EnsureEntriesLoaded()
void IArchiveExtractionListener.EnsureEntriesLoaded()
{
lazyEntries.EnsureFullyLoaded();
lazyVolumes.EnsureFullyLoaded();
}
public ArchiveType Type { get; private set; }
void IStreamListener.FireCompressedBytesRead(long currentPartCompressedBytes, long compressedReadBytes)
void IExtractionListener.FireCompressedBytesRead(long currentPartCompressedBytes, long compressedReadBytes)
{
if (CompressedBytesRead != null)
{
@@ -149,7 +156,7 @@ namespace SharpCompress.Archive
}
}
void IStreamListener.FireFilePartExtractionBegin(string name, long size, long compressedSize)
void IExtractionListener.FireFilePartExtractionBegin(string name, long size, long compressedSize)
{
if (FilePartExtractionBegin != null)
{
@@ -175,7 +182,7 @@ namespace SharpCompress.Archive
/// <returns></returns>
public IReader ExtractAllEntries()
{
EnsureEntriesLoaded();
((IArchiveExtractionListener)this).EnsureEntriesLoaded();
return CreateReaderForSolidExtraction();
}
@@ -197,7 +204,7 @@ namespace SharpCompress.Archive
{
get
{
EnsureEntriesLoaded();
((IArchiveExtractionListener)this).EnsureEntriesLoaded();
return Entries.All(x => x.IsComplete);
}
}

View File

@@ -6,7 +6,7 @@ using SharpCompress.Common;
namespace SharpCompress.Archive
{
public abstract class AbstractWritableArchive<TEntry, TVolume> : AbstractArchive<TEntry, TVolume>
public abstract class AbstractWritableArchive<TEntry, TVolume> : AbstractArchive<TEntry, TVolume>, IWritableArchive
where TEntry : IArchiveEntry
where TVolume : IVolume
{
@@ -15,37 +15,24 @@ namespace SharpCompress.Archive
private readonly List<TEntry> modifiedEntries = new List<TEntry>();
private bool hasModifications;
private readonly bool anyNotWritable;
internal AbstractWritableArchive(ArchiveType type)
: base(type)
{
}
internal AbstractWritableArchive(ArchiveType type, IEnumerable<Stream> streams, Options options)
: base(type, streams, options)
internal AbstractWritableArchive(ArchiveType type, Stream stream, Options options)
: base(type, stream.AsEnumerable(), options, null)
{
if (streams.Any(x => !x.CanWrite))
{
anyNotWritable = true;
}
}
#if !PORTABLE && !NETFX_CORE
internal AbstractWritableArchive(ArchiveType type, FileInfo fileInfo, Options options)
: base(type, fileInfo, options)
: base(type, fileInfo, options, null)
{
}
#endif
private void CheckWritable()
{
if (anyNotWritable)
{
throw new ArchiveException("All Archive streams must be Writable to use Archive writing functionality.");
}
}
public override ICollection<TEntry> Entries
{
get
@@ -61,6 +48,7 @@ namespace SharpCompress.Archive
private void RebuildModifiedCollection()
{
hasModifications = true;
newEntries.RemoveAll(v => removedEntries.Contains(v));
modifiedEntries.Clear();
modifiedEntries.AddRange(OldEntries.Concat(newEntries));
}
@@ -72,50 +60,90 @@ namespace SharpCompress.Archive
public void RemoveEntry(TEntry entry)
{
CheckWritable();
if (!removedEntries.Contains(entry))
{
removedEntries.Add(entry);
RebuildModifiedCollection();
}
}
public void AddEntry(string filePath, Stream source,
long size = 0, DateTime? modified = null)
void IWritableArchive.RemoveEntry(IArchiveEntry entry)
{
CheckWritable();
newEntries.Add(CreateEntry(filePath, source, size, modified, false));
RebuildModifiedCollection();
RemoveEntry((TEntry)entry);
}
public void AddEntry(string filePath, Stream source, bool closeStream,
public TEntry AddEntry(string key, Stream source,
long size = 0, DateTime? modified = null)
{
CheckWritable();
newEntries.Add(CreateEntry(filePath, source, size, modified, closeStream));
RebuildModifiedCollection();
return AddEntry(key, source, false, size, modified);
}
#if !PORTABLE && !NETFX_CORE
public void AddEntry(string filePath, FileInfo fileInfo)
IArchiveEntry IWritableArchive.AddEntry(string key, Stream source, bool closeStream, long size, DateTime? modified)
{
if (!fileInfo.Exists)
return AddEntry(key, source, closeStream, size, modified);
}
public TEntry AddEntry(string key, Stream source, bool closeStream,
long size = 0, DateTime? modified = null)
{
if (key.StartsWith("/")
|| key.StartsWith("\\"))
{
throw new ArgumentException("FileInfo does not exist.");
key = key.Substring(1);
}
AddEntry(filePath, fileInfo.OpenRead(), true, fileInfo.Length, fileInfo.LastWriteTime);
if (DoesKeyMatchExisting(key))
{
throw new ArchiveException("Cannot add entry with duplicate key: " + key);
}
var entry = CreateEntry(key, source, size, modified, closeStream);
newEntries.Add(entry);
RebuildModifiedCollection();
return entry;
}
private bool DoesKeyMatchExisting(string key)
{
foreach (var path in Entries.Select(x => x.Key))
{
var p = path.Replace('/','\\');
if (p.StartsWith("\\"))
{
p = p.Substring(1);
}
return string.Equals(p, key, StringComparison.OrdinalIgnoreCase);
}
return false;
}
#endif
public void SaveTo(Stream stream, CompressionInfo compressionType)
{
//reset streams of new entries
newEntries.Cast<IWritableArchiveEntry>().ForEach(x => x.Stream.Seek(0, SeekOrigin.Begin));
SaveTo(stream, compressionType, OldEntries, newEntries);
}
protected abstract TEntry CreateEntry(string filePath, Stream source, long size, DateTime? modified,
protected TEntry CreateEntry(string key, Stream source, long size, DateTime? modified,
bool closeStream)
{
if (!source.CanRead || !source.CanSeek)
{
throw new ArgumentException("Streams must be readable and seekable to use the Writing Archive API");
}
return CreateEntryInternal(key, source, size, modified, closeStream);
}
protected abstract TEntry CreateEntryInternal(string key, Stream source, long size, DateTime? modified,
bool closeStream);
protected abstract void SaveTo(Stream stream, CompressionInfo compressionType,
IEnumerable<TEntry> oldEntries, IEnumerable<TEntry> newEntries);
public override void Dispose()
{
base.Dispose();
newEntries.Cast<Entry>().ForEach(x => x.Close());
removedEntries.Cast<Entry>().ForEach(x => x.Close());
modifiedEntries.Cast<Entry>().ForEach(x => x.Close());
}
}
}

View File

@@ -31,12 +31,6 @@ namespace SharpCompress.Archive
return ZipArchive.Open(stream, options, null);
}
stream.Seek(0, SeekOrigin.Begin);
if (RarArchive.IsRarFile(stream))
{
stream.Seek(0, SeekOrigin.Begin);
return RarArchive.Open(stream, options);
}
stream.Seek(0, SeekOrigin.Begin);
if (TarArchive.IsTarFile(stream))
{
stream.Seek(0, SeekOrigin.Begin);
@@ -54,10 +48,16 @@ namespace SharpCompress.Archive
stream.Seek(0, SeekOrigin.Begin);
return GZipArchive.Open(stream, options);
}
throw new InvalidOperationException("Cannot determine compressed stream type.");
stream.Seek(0, SeekOrigin.Begin);
if(RarArchive.IsRarFile(stream, Options.LookForHeader | Options.KeepStreamsOpen))
{
stream.Seek(0, SeekOrigin.Begin);
return RarArchive.Open(stream, options);
}
throw new InvalidOperationException("Cannot determine compressed stream type. Supported Archive Formats: Zip, GZip, Tar, Rar, 7Zip");
}
public static IArchive Create(ArchiveType type)
public static IWritableArchive Create(ArchiveType type)
{
switch (type)
{
@@ -69,6 +69,10 @@ namespace SharpCompress.Archive
{
return TarArchive.Create();
}
case ArchiveType.GZip:
{
return GZipArchive.Create();
}
default:
{
throw new NotSupportedException("Cannot create Archives of type: " + type);
@@ -122,12 +126,6 @@ namespace SharpCompress.Archive
return ZipArchive.Open(fileInfo, options, null);
}
stream.Seek(0, SeekOrigin.Begin);
if (RarArchive.IsRarFile(stream, Options.LookForHeader | Options.KeepStreamsOpen))
{
stream.Dispose();
return RarArchive.Open(fileInfo, options);
}
stream.Seek(0, SeekOrigin.Begin);
if (TarArchive.IsTarFile(stream))
{
stream.Dispose();
@@ -145,7 +143,13 @@ namespace SharpCompress.Archive
stream.Dispose();
return GZipArchive.Open(fileInfo, options);
}
throw new InvalidOperationException("Cannot determine compressed stream type.");
stream.Seek(0, SeekOrigin.Begin);
if(RarArchive.IsRarFile(stream, Options.LookForHeader | Options.KeepStreamsOpen))
{
stream.Dispose();
return RarArchive.Open(fileInfo, options);
}
throw new InvalidOperationException("Cannot determine compressed stream type. Supported Archive Formats: Zip, GZip, Tar, Rar, 7Zip");
}
}

View File

@@ -75,6 +75,11 @@ namespace SharpCompress.Archive.GZip
return new GZipArchive(stream, options);
}
public static GZipArchive Create()
{
return new GZipArchive();
}
#if !PORTABLE && !NETFX_CORE
/// <summary>
/// Constructor with a FileInfo object to an existing file.
@@ -147,7 +152,7 @@ namespace SharpCompress.Archive.GZip
/// <param name="stream"></param>
/// <param name="options"></param>
internal GZipArchive(Stream stream, Options options)
: base(ArchiveType.GZip, stream.AsEnumerable(), options)
: base(ArchiveType.GZip, stream, options)
{
}
@@ -158,10 +163,10 @@ namespace SharpCompress.Archive.GZip
public void SaveTo(Stream stream)
{
this.SaveTo(stream, CompressionType.GZip);
SaveTo(stream, CompressionType.GZip);
}
protected override GZipArchiveEntry CreateEntry(string filePath, Stream source, long size, DateTime? modified,
protected override GZipArchiveEntry CreateEntryInternal(string filePath, Stream source, long size, DateTime? modified,
bool closeStream)
{
if (Entries.Any())
@@ -186,7 +191,7 @@ namespace SharpCompress.Archive.GZip
{
using (var entryStream = entry.OpenEntryStream())
{
writer.Write(entry.FilePath, entryStream, entry.LastModifiedTime);
writer.Write(entry.Key, entryStream, entry.LastModifiedTime);
}
}
}

View File

@@ -1,18 +1,16 @@
using System.IO;
using System.Linq;
using SharpCompress.Common;
using SharpCompress.Common.GZip;
namespace SharpCompress.Archive.GZip
{
public class GZipArchiveEntry : GZipEntry, IArchiveEntry
{
private GZipArchive archive;
internal GZipArchiveEntry(GZipArchive archive, GZipFilePart part)
: base(part)
{
this.archive = archive;
Archive = archive;
}
public virtual Stream OpenEntryStream()
@@ -21,15 +19,7 @@ namespace SharpCompress.Archive.GZip
}
#region IArchiveEntry Members
public void WriteTo(Stream streamToWriteTo)
{
if (IsEncrypted)
{
throw new PasswordProtectedException("Entry is password protected and cannot be extracted.");
}
this.Extract(archive, streamToWriteTo);
}
public IArchive Archive { get; private set; }
public bool IsComplete
{

View File

@@ -6,30 +6,31 @@ using SharpCompress.IO;
namespace SharpCompress.Archive.GZip
{
internal class GZipWritableArchiveEntry : GZipArchiveEntry
internal class GZipWritableArchiveEntry : GZipArchiveEntry, IWritableArchiveEntry
{
private string path;
private long size;
private DateTime? lastModified;
private bool closeStream;
private readonly string path;
private readonly long size;
private readonly DateTime? lastModified;
private readonly bool closeStream;
private readonly Stream stream;
internal GZipWritableArchiveEntry(GZipArchive archive, Stream stream,
string path, long size, DateTime? lastModified, bool closeStream)
: base(archive, null)
{
this.Stream = stream;
this.stream = stream;
this.path = path;
this.size = size;
this.lastModified = lastModified;
this.closeStream = closeStream;
}
public override uint Crc
public override long Crc
{
get { return 0; }
}
public override string FilePath
public override string Key
{
get { return path; }
}
@@ -84,18 +85,26 @@ namespace SharpCompress.Archive.GZip
get { throw new NotImplementedException(); }
}
internal Stream Stream { get; private set; }
Stream IWritableArchiveEntry.Stream
{
get
{
return stream;
}
}
public override Stream OpenEntryStream()
{
return new NonDisposingStream(Stream);
//ensure new stream is at the start, this could be reset
stream.Seek(0, SeekOrigin.Begin);
return new NonDisposingStream(stream);
}
internal override void Close()
{
if (closeStream)
{
Stream.Dispose();
stream.Dispose();
}
}
}

View File

@@ -14,7 +14,6 @@ namespace SharpCompress.Archive
event EventHandler<FilePartExtractionBeginEventArgs> FilePartExtractionBegin;
IEnumerable<IArchiveEntry> Entries { get; }
long TotalSize { get; }
IEnumerable<IVolume> Volumes { get; }
ArchiveType Type { get; }
@@ -24,7 +23,6 @@ namespace SharpCompress.Archive
/// This is primarily for SOLID Rar Archives or 7Zip Archives as they need to be
/// extracted sequentially for the best performance.
/// </summary>
/// <returns></returns>
IReader ExtractAllEntries();
/// <summary>
@@ -37,5 +35,15 @@ namespace SharpCompress.Archive
/// This checks to see if all the known entries have IsComplete = true
/// </summary>
bool IsComplete { get; }
/// <summary>
/// The total size of the files compressed in the archive.
/// </summary>
long TotalSize { get; }
/// <summary>
/// The total size of the files as uncompressed in the archive.
/// </summary>
long TotalUncompressSize { get; }
}
}

View File

@@ -1,10 +1,40 @@
using System.IO;
using SharpCompress.Common;
using SharpCompress.IO;
namespace SharpCompress.Archive
{
public static class IArchiveEntryExtensions
{
public static void WriteTo(this IArchiveEntry archiveEntry, Stream streamToWriteTo)
{
if (archiveEntry.Archive.Type == ArchiveType.Rar && archiveEntry.Archive.IsSolid)
{
throw new InvalidFormatException("Cannot use Archive random access on SOLID Rar files.");
}
if (archiveEntry.IsDirectory)
{
throw new ExtractionException("Entry is a file directory and cannot be extracted.");
}
var streamListener = archiveEntry.Archive as IArchiveExtractionListener;
streamListener.EnsureEntriesLoaded();
streamListener.FireEntryExtractionBegin(archiveEntry);
streamListener.FireFilePartExtractionBegin(archiveEntry.Key, archiveEntry.Size, archiveEntry.CompressedSize);
var entryStream = archiveEntry.OpenEntryStream();
if (entryStream == null)
{
return;
}
using(entryStream)
using (Stream s = new ListeningStream(streamListener, entryStream))
{
s.TransferTo(streamToWriteTo);
}
streamListener.FireEntryExtractionEnd(archiveEntry);
}
#if !PORTABLE && !NETFX_CORE
/// <summary>
/// Extract to specific directory, retaining filename
@@ -12,13 +42,13 @@ namespace SharpCompress.Archive
public static void WriteToDirectory(this IArchiveEntry entry, string destinationDirectory,
ExtractOptions options = ExtractOptions.Overwrite)
{
string destinationFileName = string.Empty;
string file = Path.GetFileName(entry.FilePath);
string destinationFileName;
string file = Path.GetFileName(entry.Key);
if (options.HasFlag(ExtractOptions.ExtractFullPath))
{
string folder = Path.GetDirectoryName(entry.FilePath);
string folder = Path.GetDirectoryName(entry.Key);
string destdir = Path.Combine(destinationDirectory, folder);
if (!Directory.Exists(destdir))
{
@@ -50,11 +80,43 @@ namespace SharpCompress.Archive
fm = FileMode.CreateNew;
}
using (FileStream fs = File.Open(destinationFileName, fm))
// using (Stream entryStream = entry.OpenEntryStream())
{
//entryStream.TransferTo(fs);
entry.WriteTo(fs);
}
if (options.HasFlag(ExtractOptions.PreserveFileTime) || options.HasFlag(ExtractOptions.PreserveAttributes))
{
// update file time to original packed time
FileInfo nf = new FileInfo(destinationFileName);
if (nf.Exists)
{
if (options.HasFlag(ExtractOptions.PreserveFileTime))
{
if (entry.CreatedTime.HasValue)
{
nf.CreationTime = entry.CreatedTime.Value;
}
if (entry.LastModifiedTime.HasValue)
{
nf.LastWriteTime = entry.LastModifiedTime.Value;
}
if (entry.LastAccessedTime.HasValue)
{
nf.LastAccessTime = entry.CreatedTime.Value;
}
}
if (options.HasFlag(ExtractOptions.PreserveAttributes))
{
if (entry.Attrib.HasValue)
{
nf.Attributes = (FileAttributes)System.Enum.ToObject(typeof(FileAttributes), entry.Attrib.Value);
}
}
}
}
}
#endif
}

View File

@@ -11,11 +11,14 @@ namespace SharpCompress.Archive
/// </summary>
Stream OpenEntryStream();
void WriteTo(Stream stream);
/// <summary>
/// The archive can find all the parts of the archive needed to extract this entry.
/// </summary>
bool IsComplete { get; }
/// <summary>
/// The archive instance this entry belongs to
/// </summary>
IArchive Archive { get; }
}
}

View File

@@ -0,0 +1,11 @@
using SharpCompress.Common;
namespace SharpCompress.Archive
{
internal interface IArchiveExtractionListener : IExtractionListener
{
void EnsureEntriesLoaded();
void FireEntryExtractionBegin(IArchiveEntry entry);
void FireEntryExtractionEnd(IArchiveEntry entry);
}
}

View File

@@ -1,85 +1,84 @@
using System.IO;
using SharpCompress.Common;
namespace SharpCompress.Archive
{
public static class AbstractWritableArchiveExtensions
{
public static void SaveTo<TEntry, TVolume>(this AbstractWritableArchive<TEntry, TVolume> writableArchive,
Stream stream, CompressionType compressionType)
where TEntry : IArchiveEntry
where TVolume : IVolume
{
writableArchive.SaveTo(stream, new CompressionInfo {Type = compressionType});
}
#if !PORTABLE && !NETFX_CORE
public static void AddEntry<TEntry, TVolume>(this AbstractWritableArchive<TEntry, TVolume> writableArchive,
string entryPath, string filePath)
where TEntry : IArchiveEntry
where TVolume : IVolume
{
var fileInfo = new FileInfo(filePath);
if (!fileInfo.Exists)
{
throw new FileNotFoundException("Could not AddEntry: " + filePath);
}
writableArchive.AddEntry(entryPath, new FileInfo(filePath).OpenRead(), true, fileInfo.Length,
fileInfo.LastWriteTime);
}
public static void SaveTo<TEntry, TVolume>(this AbstractWritableArchive<TEntry, TVolume> writableArchive,
string filePath, CompressionType compressionType)
where TEntry : IArchiveEntry
where TVolume : IVolume
{
writableArchive.SaveTo(new FileInfo(filePath), new CompressionInfo {Type = compressionType});
}
public static void SaveTo<TEntry, TVolume>(this AbstractWritableArchive<TEntry, TVolume> writableArchive,
FileInfo fileInfo, CompressionType compressionType)
where TEntry : IArchiveEntry
where TVolume : IVolume
{
using (var stream = fileInfo.Open(FileMode.Create, FileAccess.Write))
{
writableArchive.SaveTo(stream, new CompressionInfo {Type = compressionType});
}
}
public static void SaveTo<TEntry, TVolume>(this AbstractWritableArchive<TEntry, TVolume> writableArchive,
string filePath, CompressionInfo compressionInfo)
where TEntry : IArchiveEntry
where TVolume : IVolume
{
writableArchive.SaveTo(new FileInfo(filePath), compressionInfo);
}
public static void SaveTo<TEntry, TVolume>(this AbstractWritableArchive<TEntry, TVolume> writableArchive,
FileInfo fileInfo, CompressionInfo compressionInfo)
where TEntry : IArchiveEntry
where TVolume : IVolume
{
using (var stream = fileInfo.Open(FileMode.Create, FileAccess.Write))
{
writableArchive.SaveTo(stream, compressionInfo);
}
}
public static void AddAllFromDirectory<TEntry, TVolume>(
this AbstractWritableArchive<TEntry, TVolume> writableArchive,
string filePath, string searchPattern = "*.*", SearchOption searchOption = SearchOption.AllDirectories)
where TEntry : IArchiveEntry
where TVolume : IVolume
{
foreach (var path in Directory.EnumerateFiles(filePath, searchPattern, searchOption))
{
var fileInfo = new FileInfo(path);
writableArchive.AddEntry(path.Substring(filePath.Length), fileInfo.OpenRead(), true, fileInfo.Length,
fileInfo.LastWriteTime);
}
}
#endif
}
using System;
using System.IO;
using SharpCompress.Common;
namespace SharpCompress.Archive
{
public static class IWritableArchiveExtensions
{
public static void SaveTo(this IWritableArchive writableArchive,
Stream stream, CompressionType compressionType)
{
writableArchive.SaveTo(stream, new CompressionInfo {Type = compressionType});
}
#if !PORTABLE && !NETFX_CORE
public static void AddEntry(this IWritableArchive writableArchive,
string entryPath, string filePath)
{
var fileInfo = new FileInfo(filePath);
if (!fileInfo.Exists)
{
throw new FileNotFoundException("Could not AddEntry: " + filePath);
}
writableArchive.AddEntry(entryPath, new FileInfo(filePath).OpenRead(), true, fileInfo.Length,
fileInfo.LastWriteTime);
}
public static void SaveTo(this IWritableArchive writableArchive,
string filePath, CompressionType compressionType)
{
writableArchive.SaveTo(new FileInfo(filePath), new CompressionInfo {Type = compressionType});
}
public static void SaveTo(this IWritableArchive writableArchive,
FileInfo fileInfo, CompressionType compressionType)
{
using (var stream = fileInfo.Open(FileMode.Create, FileAccess.Write))
{
writableArchive.SaveTo(stream, new CompressionInfo {Type = compressionType});
}
}
public static void SaveTo(this IWritableArchive writableArchive,
string filePath, CompressionInfo compressionInfo)
{
writableArchive.SaveTo(new FileInfo(filePath), compressionInfo);
}
public static void SaveTo(this IWritableArchive writableArchive,
FileInfo fileInfo, CompressionInfo compressionInfo)
{
using (var stream = fileInfo.Open(FileMode.Create, FileAccess.Write))
{
writableArchive.SaveTo(stream, compressionInfo);
}
}
public static void AddAllFromDirectory(
this IWritableArchive writableArchive,
string filePath, string searchPattern = "*.*", SearchOption searchOption = SearchOption.AllDirectories)
{
#if NET2
foreach (var path in Directory.GetFiles(filePath, searchPattern, searchOption))
#else
foreach (var path in Directory.EnumerateFiles(filePath, searchPattern, searchOption))
#endif
{
var fileInfo = new FileInfo(path);
writableArchive.AddEntry(path.Substring(filePath.Length), fileInfo.OpenRead(), true, fileInfo.Length,
fileInfo.LastWriteTime);
}
}
public static IArchiveEntry AddEntry(this IWritableArchive writableArchive, string key, FileInfo fileInfo)
{
if (!fileInfo.Exists)
{
throw new ArgumentException("FileInfo does not exist.");
}
return writableArchive.AddEntry(key, fileInfo.OpenRead(), true, fileInfo.Length, fileInfo.LastWriteTime);
}
#endif
}
}

View File

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

View File

@@ -0,0 +1,9 @@
using System.IO;
namespace SharpCompress.Archive
{
internal interface IWritableArchiveEntry
{
Stream Stream { get; }
}
}

View File

@@ -12,8 +12,8 @@ namespace SharpCompress.Archive.Rar
/// </summary>
internal class FileInfoRarArchiveVolume : RarVolume
{
internal FileInfoRarArchiveVolume(FileInfo fileInfo, Options options)
: base(StreamingMode.Seekable, fileInfo.OpenRead(), FixOptions(options))
internal FileInfoRarArchiveVolume(FileInfo fileInfo, string password, Options options)
: base(StreamingMode.Seekable, fileInfo.OpenRead(), password, FixOptions(options))
{
FileInfo = fileInfo;
FileParts = base.GetVolumeFileParts().ToReadOnly();
@@ -42,10 +42,5 @@ namespace SharpCompress.Archive.Rar
{
return FileParts;
}
public override FileInfo VolumeFile
{
get { return FileInfo; }
}
}
}

View File

@@ -4,12 +4,12 @@ using SharpCompress.Common.Rar.Headers;
namespace SharpCompress.Archive.Rar
{
internal class FileInfoRarFilePart : RarFilePart
internal class FileInfoRarFilePart : SeekableFilePart
{
private FileInfoRarArchiveVolume volume;
private readonly FileInfoRarArchiveVolume volume;
internal FileInfoRarFilePart(FileInfoRarArchiveVolume volume, MarkHeader mh, FileHeader fh, FileInfo fi)
: base(mh, fh)
: base(mh, fh, volume.Stream, volume.Password)
{
this.volume = volume;
FileInfo = fi;
@@ -17,13 +17,6 @@ namespace SharpCompress.Archive.Rar
internal FileInfo FileInfo { get; private set; }
internal override Stream GetCompressedStream()
{
var stream = volume.Stream;
stream.Position = FileHeader.DataStartPosition;
return stream;
}
internal override string FilePartName
{
get

View File

@@ -19,13 +19,5 @@ namespace SharpCompress.Archive.Rar
{
return archive.Volumes.First().IsMultiVolume;
}
/// <summary>
/// RarArchive is SOLID (this means the Archive saved bytes by reusing information which helps for archives containing many small files).
/// </summary>
public static bool IsSolidArchive(this RarArchive archive)
{
return archive.IsSolid;
}
}
}

View File

@@ -27,14 +27,15 @@ namespace SharpCompress.Archive.Rar
/// </summary>
/// <param name="fileInfo"></param>
/// <param name="options"></param>
internal RarArchive(FileInfo fileInfo, Options options)
: base(ArchiveType.Rar, fileInfo, options)
/// <param name="password"></param>
internal RarArchive(FileInfo fileInfo, Options options, string password)
: base(ArchiveType.Rar, fileInfo, options, password)
{
}
protected override IEnumerable<RarVolume> LoadVolumes(FileInfo file, Options options)
{
return RarArchiveVolumeFactory.GetParts(file, options);
return RarArchiveVolumeFactory.GetParts(file, Password, options);
}
#endif
@@ -43,8 +44,9 @@ namespace SharpCompress.Archive.Rar
/// </summary>
/// <param name="streams"></param>
/// <param name="options"></param>
internal RarArchive(IEnumerable<Stream> streams, Options options)
: base(ArchiveType.Rar, streams, options)
/// <param name="password"></param>
internal RarArchive(IEnumerable<Stream> streams, Options options, string password)
: base(ArchiveType.Rar, streams, options, password)
{
}
@@ -55,7 +57,7 @@ namespace SharpCompress.Archive.Rar
protected override IEnumerable<RarVolume> LoadVolumes(IEnumerable<Stream> streams, Options options)
{
return RarArchiveVolumeFactory.GetParts(streams, options);
return RarArchiveVolumeFactory.GetParts(streams, Password, options);
}
protected override IReader CreateReaderForSolidExtraction()
@@ -73,33 +75,16 @@ namespace SharpCompress.Archive.Rar
#region Creation
#if !PORTABLE && !NETFX_CORE
/// <summary>
/// Constructor expects a filepath to an existing file.
/// </summary>
/// <param name="filePath"></param>
public static RarArchive Open(string filePath)
{
return Open(filePath, Options.None);
}
/// <summary>
/// Constructor with a FileInfo object to an existing file.
/// </summary>
/// <param name="fileInfo"></param>
public static RarArchive Open(FileInfo fileInfo)
{
return Open(fileInfo, Options.None);
}
/// <summary>
/// Constructor expects a filepath to an existing file.
/// </summary>
/// <param name="filePath"></param>
/// <param name="options"></param>
public static RarArchive Open(string filePath, Options options)
/// <param name="password"></param>
public static RarArchive Open(string filePath, Options options = Options.None, string password = null)
{
filePath.CheckNotNullOrEmpty("filePath");
return Open(new FileInfo(filePath), options);
return Open(new FileInfo(filePath), options, password);
}
/// <summary>
@@ -107,42 +92,23 @@ namespace SharpCompress.Archive.Rar
/// </summary>
/// <param name="fileInfo"></param>
/// <param name="options"></param>
public static RarArchive Open(FileInfo fileInfo, Options options)
/// <param name="password"></param>
public static RarArchive Open(FileInfo fileInfo, Options options = Options.None, string password = null)
{
fileInfo.CheckNotNull("fileInfo");
return new RarArchive(fileInfo, options);
return new RarArchive(fileInfo, options, password);
}
#endif
/// <summary>
/// Takes a seekable Stream as a source
/// </summary>
/// <param name="stream"></param>
public static RarArchive Open(Stream stream)
{
stream.CheckNotNull("stream");
return Open(stream.AsEnumerable());
}
/// <summary>
/// Takes a seekable Stream as a source
/// </summary>
/// <param name="stream"></param>
/// <param name="options"></param>
public static RarArchive Open(Stream stream, Options options)
/// <param name="password"></param>
public static RarArchive Open(Stream stream, Options options = Options.KeepStreamsOpen, string password = null)
{
stream.CheckNotNull("stream");
return Open(stream.AsEnumerable(), options);
}
/// <summary>
/// Takes multiple seekable Streams for a multi-part archive
/// </summary>
/// <param name="streams"></param>
public static RarArchive Open(IEnumerable<Stream> streams)
{
streams.CheckNotNull("streams");
return new RarArchive(streams, Options.KeepStreamsOpen);
return Open(stream.AsEnumerable(), options, password);
}
/// <summary>
@@ -150,10 +116,11 @@ namespace SharpCompress.Archive.Rar
/// </summary>
/// <param name="streams"></param>
/// <param name="options"></param>
public static RarArchive Open(IEnumerable<Stream> streams, Options options)
/// <param name="password"></param>
public static RarArchive Open(IEnumerable<Stream> streams, Options options = Options.KeepStreamsOpen, string password = null)
{
streams.CheckNotNull("streams");
return new RarArchive(streams, options);
return new RarArchive(streams, options, password);
}
#if !PORTABLE && !NETFX_CORE

View File

@@ -11,11 +11,12 @@ namespace SharpCompress.Archive.Rar
public class RarArchiveEntry : RarEntry, IArchiveEntry
{
private readonly ICollection<RarFilePart> parts;
private readonly RarArchive archive;
internal RarArchiveEntry(RarArchive archive, IEnumerable<RarFilePart> parts)
{
this.parts = parts.ToList();
Archive = archive;
this.archive = archive;
}
public override CompressionType CompressionType
@@ -23,7 +24,13 @@ namespace SharpCompress.Archive.Rar
get { return CompressionType.Rar; }
}
private RarArchive Archive { get; set; }
public IArchive Archive
{
get
{
return archive;
}
}
internal override IEnumerable<FilePart> Parts
{
@@ -35,14 +42,13 @@ namespace SharpCompress.Archive.Rar
get { return parts.First().FileHeader; }
}
public override uint Crc
public override long Crc
{
get
{
CheckIncomplete();
return parts.Select(fp => fp.FileHeader)
.Where(fh => !fh.FileFlags.HasFlag(FileFlags.SPLIT_AFTER))
.Single().FileCRC;
.Single(fh => !fh.FileFlags.HasFlag(FileFlags.SPLIT_AFTER)).FileCRC;
}
}
@@ -67,22 +73,8 @@ namespace SharpCompress.Archive.Rar
public Stream OpenEntryStream()
{
return new RarStream(Archive.Unpack, FileHeader,
new MultiVolumeReadOnlyStream(Parts.Cast<RarFilePart>(), Archive));
}
public void WriteTo(Stream streamToWriteTo)
{
CheckIncomplete();
if (Archive.IsSolidArchive())
{
throw new InvalidFormatException("Cannot use Archive random access on SOLID Rar files.");
}
if (IsEncrypted)
{
throw new PasswordProtectedException("Entry is password protected and cannot be extracted.");
}
this.Extract(Archive, streamToWriteTo);
return new RarStream(archive.Unpack, FileHeader,
new MultiVolumeReadOnlyStream(Parts.Cast<RarFilePart>(), archive));
}
public bool IsComplete
@@ -97,9 +89,5 @@ namespace SharpCompress.Archive.Rar
throw new IncompleteArchiveException("ArchiveEntry is incomplete and cannot perform this operation.");
}
}
internal override void Close()
{
}
}
}

View File

@@ -13,7 +13,7 @@ namespace SharpCompress.Archive.Rar
{
internal static class RarArchiveVolumeFactory
{
internal static IEnumerable<RarVolume> GetParts(IEnumerable<Stream> streams, Options options)
internal static IEnumerable<RarVolume> GetParts(IEnumerable<Stream> streams, string password, Options options)
{
foreach (Stream s in streams)
{
@@ -21,15 +21,15 @@ namespace SharpCompress.Archive.Rar
{
throw new ArgumentException("Stream is not readable and seekable");
}
StreamRarArchiveVolume part = new StreamRarArchiveVolume(s, options);
StreamRarArchiveVolume part = new StreamRarArchiveVolume(s, password, options);
yield return part;
}
}
#if !PORTABLE && !NETFX_CORE
internal static IEnumerable<RarVolume> GetParts(FileInfo fileInfo, Options options)
internal static IEnumerable<RarVolume> GetParts(FileInfo fileInfo, string password, Options options)
{
FileInfoRarArchiveVolume part = new FileInfoRarArchiveVolume(fileInfo, options);
FileInfoRarArchiveVolume part = new FileInfoRarArchiveVolume(fileInfo, password, options);
yield return part;
if (!part.ArchiveHeader.ArchiveHeaderFlags.HasFlag(ArchiveFlags.VOLUME))
@@ -41,7 +41,7 @@ namespace SharpCompress.Archive.Rar
//we use fileinfo because rar is dumb and looks at file names rather than archive info for another volume
while (fileInfo != null && fileInfo.Exists)
{
part = new FileInfoRarArchiveVolume(fileInfo, options);
part = new FileInfoRarArchiveVolume(fileInfo, password, options);
fileInfo = GetNextFileInfo(ah, part.FileParts.FirstOrDefault() as FileInfoRarFilePart);
yield return part;

View File

@@ -0,0 +1,39 @@
using System;
using System.IO;
using SharpCompress.Common.Rar;
using SharpCompress.Common.Rar.Headers;
namespace SharpCompress.Archive.Rar
{
internal class SeekableFilePart : RarFilePart
{
private readonly Stream stream;
private readonly string password;
internal SeekableFilePart(MarkHeader mh, FileHeader fh, Stream stream, string password)
: base(mh, fh)
{
this.stream = stream;
this.password = password;
}
internal override Stream GetCompressedStream()
{
stream.Position = FileHeader.DataStartPosition;
if (FileHeader.Salt != null)
{
#if PORTABLE
throw new NotSupportedException("Encrypted Rar files aren't supported in portable distro.");
#else
return new RarCryptoWrapper(stream, password, FileHeader.Salt);
#endif
}
return stream;
}
internal override string FilePartName
{
get { return "Unknown Stream - File Entry: " + FileHeader.FileName; }
}
}
}

View File

@@ -1,28 +0,0 @@
using System.IO;
using SharpCompress.Common.Rar;
using SharpCompress.Common.Rar.Headers;
namespace SharpCompress.Archive.Rar
{
internal class SeekableStreamFilePart : RarFilePart
{
internal SeekableStreamFilePart(MarkHeader mh, FileHeader fh, Stream stream)
: base(mh, fh)
{
Stream = stream;
}
internal Stream Stream { get; private set; }
internal override Stream GetCompressedStream()
{
Stream.Position = FileHeader.DataStartPosition;
return Stream;
}
internal override string FilePartName
{
get { return "Unknown Stream - File Entry: " + base.FileHeader.FileName; }
}
}
}

View File

@@ -9,18 +9,11 @@ namespace SharpCompress.Archive.Rar
{
internal class StreamRarArchiveVolume : RarVolume
{
internal StreamRarArchiveVolume(Stream stream, Options options)
: base(StreamingMode.Seekable, stream, options)
internal StreamRarArchiveVolume(Stream stream, string password, Options options)
: base(StreamingMode.Seekable, stream, password, options)
{
}
#if !PORTABLE && !NETFX_CORE
public override FileInfo VolumeFile
{
get { return null; }
}
#endif
internal override IEnumerable<RarFilePart> ReadFileParts()
{
return GetVolumeFileParts();
@@ -28,7 +21,7 @@ namespace SharpCompress.Archive.Rar
internal override RarFilePart CreateFilePart(FileHeader fileHeader, MarkHeader markHeader)
{
return new SeekableStreamFilePart(markHeader, fileHeader, Stream);
return new SeekableFilePart(markHeader, fileHeader, Stream, Password);
}
}
}

View File

@@ -77,13 +77,17 @@ namespace SharpCompress.Archive.SevenZip
#if !PORTABLE && !NETFX_CORE
internal SevenZipArchive(FileInfo fileInfo, Options options)
: base(ArchiveType.SevenZip, fileInfo, options)
: base(ArchiveType.SevenZip, fileInfo, options, null)
{
}
protected override IEnumerable<SevenZipVolume> LoadVolumes(FileInfo file, Options options)
{
return new SevenZipVolume(file, options).AsEnumerable();
if (FlagUtility.HasFlag(options, Options.KeepStreamsOpen))
{
options = (Options)FlagUtility.SetFlag(options, Options.KeepStreamsOpen, false);
}
return new SevenZipVolume(file.OpenRead(), options).AsEnumerable();
}
public static bool IsSevenZipFile(string filePath)
@@ -105,7 +109,7 @@ namespace SharpCompress.Archive.SevenZip
#endif
internal SevenZipArchive(Stream stream, Options options)
: base(ArchiveType.SevenZip, stream.AsEnumerable(), options)
: base(ArchiveType.SevenZip, stream.AsEnumerable(), options, null)
{
}
@@ -184,6 +188,15 @@ namespace SharpCompress.Archive.SevenZip
get { return Entries.Where(x => !x.IsDirectory).GroupBy(x => x.FilePart.Folder).Count() > 1; }
}
public override long TotalSize
{
get
{
int i = Entries.Count;
return database.PackSizes.Aggregate(0L, (total, packSize) => total + packSize);
}
}
private class SevenZipReader : AbstractReader<SevenZipEntry, SevenZipVolume>
{
private readonly SevenZipArchive archive;
@@ -232,7 +245,7 @@ namespace SharpCompress.Archive.SevenZip
protected override EntryStream GetEntryStream()
{
return new EntryStream(new ReadOnlySubStream(currentStream, currentItem.Size));
return CreateEntryStream(new ReadOnlySubStream(currentStream, currentItem.Size));
}
}
}

View File

@@ -1,32 +1,21 @@
using System.IO;
using SharpCompress.Common;
using SharpCompress.Common.SevenZip;
namespace SharpCompress.Archive.SevenZip
{
public class SevenZipArchiveEntry : SevenZipEntry, IArchiveEntry
{
private SevenZipArchive archive;
internal SevenZipArchiveEntry(SevenZipArchive archive, SevenZipFilePart part)
: base(part)
{
this.archive = archive;
Archive = archive;
}
public Stream OpenEntryStream()
{
return FilePart.GetCompressedStream();
}
public void WriteTo(Stream stream)
{
if (IsEncrypted)
{
throw new PasswordProtectedException("Entry is password protected and cannot be extracted.");
}
this.Extract(archive, stream);
}
public IArchive Archive { get; private set; }
public bool IsComplete
{

View File

@@ -123,7 +123,11 @@ namespace SharpCompress.Archive.Tar
protected override IEnumerable<TarVolume> LoadVolumes(FileInfo file, Options options)
{
return new TarVolume(file, options).AsEnumerable();
if (FlagUtility.HasFlag(options, Options.KeepStreamsOpen))
{
options = (Options)FlagUtility.SetFlag(options, Options.KeepStreamsOpen, false);
}
return new TarVolume(file.OpenRead(), options).AsEnumerable();
}
#endif
@@ -133,7 +137,7 @@ namespace SharpCompress.Archive.Tar
/// <param name="stream"></param>
/// <param name="options"></param>
internal TarArchive(Stream stream, Options options)
: base(ArchiveType.Tar, stream.AsEnumerable(), options)
: base(ArchiveType.Tar, stream, options)
{
}
@@ -165,11 +169,21 @@ namespace SharpCompress.Archive.Tar
{
var entry = new TarArchiveEntry(this, new TarFilePart(previousHeader, stream),
CompressionType.None);
var memoryStream = new MemoryStream();
entry.WriteTo(memoryStream);
memoryStream.Position = 0;
var bytes = memoryStream.ToArray();
header.Name = ArchiveEncoding.Default.GetString(bytes, 0, bytes.Length).TrimNulls();
var oldStreamPos = stream.Position;
using(var entryStream = entry.OpenEntryStream())
using(var memoryStream = new MemoryStream())
{
entryStream.TransferTo(memoryStream);
memoryStream.Position = 0;
var bytes = memoryStream.ToArray();
header.Name = ArchiveEncoding.Default.GetString(bytes, 0, bytes.Length).TrimNulls();
}
stream.Position = oldStreamPos;
previousHeader = null;
}
yield return new TarArchiveEntry(this, new TarFilePart(header, stream), CompressionType.None);
@@ -183,7 +197,7 @@ namespace SharpCompress.Archive.Tar
return new TarArchive();
}
protected override TarArchiveEntry CreateEntry(string filePath, Stream source,
protected override TarArchiveEntry CreateEntryInternal(string filePath, Stream source,
long size, DateTime? modified, bool closeStream)
{
return new TarWritableArchiveEntry(this, source, CompressionType.Unknown, filePath, size, modified,
@@ -201,7 +215,7 @@ namespace SharpCompress.Archive.Tar
{
using (var entryStream = entry.OpenEntryStream())
{
writer.Write(entry.FilePath, entryStream, entry.LastModifiedTime, entry.Size);
writer.Write(entry.Key, entryStream, entry.LastModifiedTime, entry.Size);
}
}
}

View File

@@ -7,12 +7,10 @@ namespace SharpCompress.Archive.Tar
{
public class TarArchiveEntry : TarEntry, IArchiveEntry
{
private TarArchive archive;
internal TarArchiveEntry(TarArchive archive, TarFilePart part, CompressionType compressionType)
: base(part, compressionType)
{
this.archive = archive;
Archive = archive;
}
public virtual Stream OpenEntryStream()
@@ -21,15 +19,7 @@ namespace SharpCompress.Archive.Tar
}
#region IArchiveEntry Members
public void WriteTo(Stream streamToWriteTo)
{
if (IsEncrypted)
{
throw new PasswordProtectedException("Entry is password protected and cannot be extracted.");
}
this.Extract(archive, streamToWriteTo);
}
public IArchive Archive { get; private set; }
public bool IsComplete
{

View File

@@ -6,30 +6,31 @@ using SharpCompress.IO;
namespace SharpCompress.Archive.Tar
{
internal class TarWritableArchiveEntry : TarArchiveEntry
internal class TarWritableArchiveEntry : TarArchiveEntry, IWritableArchiveEntry
{
private string path;
private long size;
private DateTime? lastModified;
private bool closeStream;
private readonly string path;
private readonly long size;
private readonly DateTime? lastModified;
private readonly bool closeStream;
private readonly Stream stream;
internal TarWritableArchiveEntry(TarArchive archive, Stream stream, CompressionType compressionType,
string path, long size, DateTime? lastModified, bool closeStream)
: base(archive, null, compressionType)
{
this.Stream = stream;
this.stream = stream;
this.path = path;
this.size = size;
this.lastModified = lastModified;
this.closeStream = closeStream;
}
public override uint Crc
public override long Crc
{
get { return 0; }
}
public override string FilePath
public override string Key
{
get { return path; }
}
@@ -83,19 +84,26 @@ namespace SharpCompress.Archive.Tar
{
get { throw new NotImplementedException(); }
}
internal Stream Stream { get; private set; }
Stream IWritableArchiveEntry.Stream
{
get
{
return stream;
}
}
public override Stream OpenEntryStream()
{
return new NonDisposingStream(Stream);
//ensure new stream is at the start, this could be reset
stream.Seek(0, SeekOrigin.Begin);
return new NonDisposingStream(stream);
}
internal override void Close()
{
if (closeStream)
{
Stream.Dispose();
stream.Dispose();
}
}
}

View File

@@ -14,7 +14,7 @@ namespace SharpCompress.Archive.Zip
{
public class ZipArchive : AbstractWritableArchive<ZipArchiveEntry, ZipVolume>
{
private SeekableZipHeaderFactory headerFactory;
private readonly SeekableZipHeaderFactory headerFactory;
/// <summary>
/// Gets or sets the compression level applied to files added to the archive,
@@ -148,7 +148,11 @@ namespace SharpCompress.Archive.Zip
protected override IEnumerable<ZipVolume> LoadVolumes(FileInfo file, Options options)
{
return new ZipVolume(file, options).AsEnumerable();
if (FlagUtility.HasFlag(options, Options.KeepStreamsOpen))
{
options = (Options)FlagUtility.SetFlag(options, Options.KeepStreamsOpen, false);
}
return new ZipVolume(file.OpenRead(), options).AsEnumerable();
}
#endif
@@ -164,7 +168,7 @@ namespace SharpCompress.Archive.Zip
/// <param name="options"></param>
/// <param name="password"></param>
internal ZipArchive(Stream stream, Options options, string password = null)
: base(ArchiveType.Zip, stream.AsEnumerable(), options)
: base(ArchiveType.Zip, stream, options)
{
headerFactory = new SeekableZipHeaderFactory(password);
}
@@ -177,7 +181,7 @@ namespace SharpCompress.Archive.Zip
protected override IEnumerable<ZipArchiveEntry> LoadEntries(IEnumerable<ZipVolume> volumes)
{
var volume = volumes.Single();
Stream stream = volumes.Single().Stream;
Stream stream = volume.Stream;
foreach (ZipHeader h in headerFactory.ReadSeekableHeader(stream))
{
if (h != null)
@@ -214,13 +218,13 @@ namespace SharpCompress.Archive.Zip
{
using (var entryStream = entry.OpenEntryStream())
{
writer.Write(entry.FilePath, entryStream, entry.LastModifiedTime, string.Empty);
writer.Write(entry.Key, entryStream, entry.LastModifiedTime, string.Empty);
}
}
}
}
protected override ZipArchiveEntry CreateEntry(string filePath, Stream source, long size, DateTime? modified,
protected override ZipArchiveEntry CreateEntryInternal(string filePath, Stream source, long size, DateTime? modified,
bool closeStream)
{
return new ZipWritableArchiveEntry(this, source, filePath, size, modified, closeStream);

View File

@@ -6,12 +6,10 @@ namespace SharpCompress.Archive.Zip
{
public class ZipArchiveEntry : ZipEntry, IArchiveEntry
{
private ZipArchive archive;
internal ZipArchiveEntry(ZipArchive archive, SeekableZipFilePart part)
: base(part)
{
this.archive = archive;
Archive = archive;
}
public virtual Stream OpenEntryStream()
@@ -21,10 +19,7 @@ namespace SharpCompress.Archive.Zip
#region IArchiveEntry Members
public void WriteTo(Stream streamToWriteTo)
{
this.Extract(archive, streamToWriteTo);
}
public IArchive Archive { get; private set; }
public bool IsComplete
{

View File

@@ -6,30 +6,32 @@ using SharpCompress.IO;
namespace SharpCompress.Archive.Zip
{
internal class ZipWritableArchiveEntry : ZipArchiveEntry
internal class ZipWritableArchiveEntry : ZipArchiveEntry, IWritableArchiveEntry
{
private string path;
private long size;
private DateTime? lastModified;
private bool closeStream;
private readonly string path;
private readonly long size;
private readonly DateTime? lastModified;
private readonly bool closeStream;
private readonly Stream stream;
private bool isDisposed;
internal ZipWritableArchiveEntry(ZipArchive archive, Stream stream, string path, long size,
DateTime? lastModified, bool closeStream)
: base(archive, null)
{
this.Stream = stream;
this.stream = stream;
this.path = path;
this.size = size;
this.lastModified = lastModified;
this.closeStream = closeStream;
}
public override uint Crc
public override long Crc
{
get { return 0; }
}
public override string FilePath
public override string Key
{
get { return path; }
}
@@ -84,18 +86,27 @@ namespace SharpCompress.Archive.Zip
get { throw new NotImplementedException(); }
}
internal Stream Stream { get; private set; }
Stream IWritableArchiveEntry.Stream
{
get
{
return stream;
}
}
public override Stream OpenEntryStream()
{
return new NonDisposingStream(Stream);
//ensure new stream is at the start, this could be reset
stream.Seek(0, SeekOrigin.Begin);
return new NonDisposingStream(stream);
}
internal override void Close()
{
if (closeStream)
if (closeStream && !isDisposed)
{
Stream.Dispose();
stream.Dispose();
isDisposed = true;
}
}
}

View File

@@ -1,20 +1,20 @@
using System.Reflection;
using System;
using System.Reflection;
using System.Runtime.CompilerServices;
#if SILVERLIGHT
[assembly: AssemblyTitle("SharpCompress.Silverlight")]
[assembly: AssemblyProduct("SharpCompress.Silverlight")]
#else
#if PORTABLE
[assembly: AssemblyTitle("SharpCompress.Silverlight")]
[assembly: AssemblyProduct("SharpCompress.Silverlight")]
[assembly: AssemblyTitle("SharpCompress.Portable")]
[assembly: AssemblyProduct("SharpCompress.Portable")]
#else
[assembly: AssemblyTitle("SharpCompress")]
[assembly: AssemblyProduct("SharpCompress")]
[assembly:
InternalsVisibleTo(
"SharpCompress.Test, PublicKey=002400000480000094000000060200000024000052534131000400000100010005d6ae1b0f6875393da83c920a5b9408f5191aaf4e8b3c2c476ad2a11f5041ecae84ce9298bc4c203637e2fd3a80ad5378a9fa8da1363e98cea45c73969198a4b64510927c910001491cebbadf597b22448ad103b0a4007e339faf8fe8665dcdb70d65b27ac05b1977c0655fad06b372b820ecbdccf10a0f214fee0986dfeded"
)]
#endif
#endif
#if UNSIGNED
[assembly: InternalsVisibleTo("SharpCompress.Test")]
[assembly: InternalsVisibleTo("SharpCompress.Test.Portable")]
#endif
[assembly: CLSCompliant(true)]

View File

@@ -1,29 +1,23 @@
using System.Globalization;
using System.Text;
using System.Text;
namespace SharpCompress.Common
{
public class ArchiveEncoding
public static class ArchiveEncoding
{
/// <summary>
/// Default encoding to use when archive format doesn't specify one.
/// </summary>
public static Encoding Default;
public static Encoding Default { get; set; }
/// <summary>
/// Encoding used by encryption schemes which don't comply with RFC 2898.
/// </summary>
public static Encoding Password;
public static Encoding Password { get; set; }
static ArchiveEncoding()
{
#if PORTABLE || NETFX_CORE
Default = Encoding.UTF8;
Password = Encoding.UTF8;
#else
Default = Encoding.GetEncoding(CultureInfo.CurrentCulture.TextInfo.OEMCodePage);
Password = Encoding.Default;
#endif
}
}
}

View File

@@ -3,19 +3,17 @@ using System.Collections.Generic;
namespace SharpCompress.Common
{
public abstract class Entry : SharpCompress.Common.IEntry
public abstract class Entry : IEntry
{
internal bool IsSolid { get; set; }
/// <summary>
/// The File's 32 bit CRC Hash
/// </summary>
public abstract uint Crc { get; }
public abstract long Crc { get; }
/// <summary>
/// The path of the file internal to the Rar Archive.
/// The string key of the file internal to the Archive.
/// </summary>
public abstract string FilePath { get; }
public abstract string Key { get; }
/// <summary>
/// The compressed file size
@@ -48,7 +46,7 @@ namespace SharpCompress.Common
public abstract DateTime? LastAccessedTime { get; }
/// <summary>
/// The entry time whend archived, if recorded
/// The entry time when archived, if recorded
/// </summary>
public abstract DateTime? ArchivedTime { get; }
@@ -62,10 +60,26 @@ namespace SharpCompress.Common
/// </summary>
public abstract bool IsDirectory { get; }
/// <summary>
/// Entry is split among multiple volumes
/// </summary>
public abstract bool IsSplit { get; }
internal abstract IEnumerable<FilePart> Parts { get; }
internal bool IsSolid { get; set; }
internal virtual void Close()
{
}
/// <summary>
/// Entry file attribute.
/// </summary>
public virtual int? Attrib
{
get { throw new NotImplementedException(); }
}
internal abstract void Close();
}
}

View File

@@ -1,15 +1,19 @@
using System;
using System.IO;
using SharpCompress.Reader;
namespace SharpCompress.Common
{
public class EntryStream : Stream
{
public IReader Reader { get; private set; }
private Stream stream;
private bool completed;
private bool isDisposed;
internal EntryStream(Stream stream)
internal EntryStream(IReader reader, Stream stream)
{
this.Reader = reader;
this.stream = stream;
}
@@ -27,11 +31,15 @@ namespace SharpCompress.Common
protected override void Dispose(bool disposing)
{
if (!completed)
if (!(completed || Reader.Cancelled))
{
throw new InvalidOperationException(
"EntryStream has not been fully consumed. Read the entire stream or use SkipEntry.");
SkipEntry();
}
if (isDisposed)
{
return;
}
isDisposed = true;
base.Dispose(disposing);
stream.Dispose();
}
@@ -53,18 +61,18 @@ namespace SharpCompress.Common
public override void Flush()
{
throw new System.NotImplementedException();
throw new NotSupportedException();
}
public override long Length
{
get { throw new System.NotImplementedException(); }
get { throw new NotSupportedException(); }
}
public override long Position
{
get { throw new System.NotImplementedException(); }
set { throw new System.NotImplementedException(); }
get { throw new NotSupportedException(); }
set { throw new NotSupportedException(); }
}
public override int Read(byte[] buffer, int offset, int count)
@@ -79,17 +87,17 @@ namespace SharpCompress.Common
public override long Seek(long offset, SeekOrigin origin)
{
throw new System.NotImplementedException();
throw new NotSupportedException();
}
public override void SetLength(long value)
{
throw new System.NotImplementedException();
throw new NotSupportedException();
}
public override void Write(byte[] buffer, int offset, int count)
{
throw new System.NotImplementedException();
throw new NotSupportedException();
}
}
}

View File

@@ -5,16 +5,26 @@ namespace SharpCompress.Common
[Flags]
public enum ExtractOptions
{
None,
None = 0,
/// <summary>
/// overwrite target if it exists
/// </summary>
Overwrite,
Overwrite = 1 << 0,
/// <summary>
/// extract with internal directory structure
/// </summary>
ExtractFullPath,
ExtractFullPath = 1 << 1,
/// <summary>
/// preserve file time
/// </summary>
PreserveFileTime = 1 << 2,
/// <summary>
/// preserve windows file attributes
/// </summary>
PreserveAttributes = 1 << 3,
}
}

View File

@@ -18,12 +18,12 @@ namespace SharpCompress.Common.GZip
get { return CompressionType.GZip; }
}
public override uint Crc
public override long Crc
{
get { return 0; }
}
public override string FilePath
public override string Key
{
get { return filePart.FilePartName; }
}
@@ -82,9 +82,5 @@ namespace SharpCompress.Common.GZip
{
yield return new GZipEntry(new GZipFilePart(stream));
}
internal override void Close()
{
}
}
}

View File

@@ -21,16 +21,6 @@ namespace SharpCompress.Common.GZip
}
#endif
#if !PORTABLE && !NETFX_CORE
/// <summary>
/// File that backs this volume, if it not stream based
/// </summary>
public override FileInfo VolumeFile
{
get { return fileInfo; }
}
#endif
public override bool IsFirstVolume
{
get { return true; }

View File

@@ -1,44 +0,0 @@
using System.IO;
namespace SharpCompress.Common
{
public class GenericVolume : Volume
{
#if !PORTABLE && !NETFX_CORE
private FileInfo fileInfo;
#endif
public GenericVolume(Stream stream, Options options)
: base(stream, options)
{
}
#if !PORTABLE && !NETFX_CORE
public GenericVolume(FileInfo fileInfo, Options options)
: base(fileInfo.OpenRead(), options)
{
this.fileInfo = fileInfo;
}
#endif
#if !PORTABLE && !NETFX_CORE
/// <summary>
/// File that backs this volume, if it not stream based
/// </summary>
public override FileInfo VolumeFile
{
get { return fileInfo; }
}
#endif
public override bool IsFirstVolume
{
get { return true; }
}
public override bool IsMultiVolume
{
get { return true; }
}
}
}

View File

@@ -7,14 +7,15 @@ namespace SharpCompress.Common
CompressionType CompressionType { get; }
DateTime? ArchivedTime { get; }
long CompressedSize { get; }
uint Crc { get; }
long Crc { get; }
DateTime? CreatedTime { get; }
string FilePath { get; }
string Key { get; }
bool IsDirectory { get; }
bool IsEncrypted { get; }
bool IsSplit { get; }
DateTime? LastAccessedTime { get; }
DateTime? LastModifiedTime { get; }
long Size { get; }
int? Attrib { get; }
}
}

View File

@@ -1,6 +1,6 @@
namespace SharpCompress.Common
{
internal interface IStreamListener
internal interface IExtractionListener
{
void FireFilePartExtractionBegin(string name, long size, long compressedSize);
void FireCompressedBytesRead(long currentPartCompressedBytes, long compressedReadBytes);

View File

@@ -7,11 +7,5 @@ namespace SharpCompress.Common
{
public interface IVolume : IDisposable
{
#if !PORTABLE && !NETFX_CORE
/// <summary>
/// File that backs this volume, if it not stream based
/// </summary>
FileInfo VolumeFile { get; }
#endif
}
}

View File

@@ -27,5 +27,10 @@ namespace SharpCompress.Common.Rar.Headers
internal int PosAv { get; private set; }
internal byte EncryptionVersion { get; private set; }
public bool HasPassword
{
get { return ArchiveHeaderFlags.HasFlag(ArchiveFlags.PASSWORD); }
}
}
}

View File

@@ -1,6 +1,5 @@
using System;
using System.IO;
using System.Text;
using SharpCompress.IO;
namespace SharpCompress.Common.Rar.Headers
@@ -15,7 +14,7 @@ namespace SharpCompress.Common.Rar.Headers
{
uint lowUncompressedSize = reader.ReadUInt32();
HostOS = (HostOS) (int) reader.ReadByte();
HostOS = (HostOS)reader.ReadByte();
FileCRC = reader.ReadUInt32();
@@ -46,7 +45,7 @@ namespace SharpCompress.Common.Rar.Headers
CompressedSize = UInt32To64(highCompressedSize, AdditionalSize);
UncompressedSize = UInt32To64(highUncompressedkSize, lowUncompressedSize);
nameSize = nameSize > 4*1024 ? (short) (4*1024) : nameSize;
nameSize = nameSize > 4 * 1024 ? (short)(4 * 1024) : nameSize;
byte[] fileNameBytes = reader.ReadBytes(nameSize);
@@ -106,11 +105,16 @@ namespace SharpCompress.Common.Rar.Headers
}
if (FileFlags.HasFlag(FileFlags.EXTTIME))
{
ushort extendedFlags = reader.ReadUInt16();
FileLastModifiedTime = ProcessExtendedTime(extendedFlags, FileLastModifiedTime, reader, 0);
FileCreatedTime = ProcessExtendedTime(extendedFlags, null, reader, 1);
FileLastAccessedTime = ProcessExtendedTime(extendedFlags, null, reader, 2);
FileArchivedTime = ProcessExtendedTime(extendedFlags, null, reader, 3);
// verify that the end of the header hasn't been reached before reading the Extended Time.
// some tools incorrectly omit Extended Time despite specifying FileFlags.EXTTIME, which most parsers tolerate.
if (ReadBytes + reader.CurrentReadByteCount <= HeaderSize - 2)
{
ushort extendedFlags = reader.ReadUInt16();
FileLastModifiedTime = ProcessExtendedTime(extendedFlags, FileLastModifiedTime, reader, 0);
FileCreatedTime = ProcessExtendedTime(extendedFlags, null, reader, 1);
FileLastAccessedTime = ProcessExtendedTime(extendedFlags, null, reader, 2);
FileArchivedTime = ProcessExtendedTime(extendedFlags, null, reader, 3);
}
}
}
@@ -130,7 +134,7 @@ namespace SharpCompress.Common.Rar.Headers
private static DateTime? ProcessExtendedTime(ushort extendedFlags, DateTime? time, MarkingBinaryReader reader,
int i)
{
uint rmode = (uint) extendedFlags >> (3 - i)*4;
uint rmode = (uint)extendedFlags >> (3 - i) * 4;
if ((rmode & 8) == 0)
{
return null;
@@ -145,14 +149,14 @@ namespace SharpCompress.Common.Rar.Headers
time = time.Value.AddSeconds(1);
}
uint nanosecondHundreds = 0;
int count = (int) rmode & 3;
int count = (int)rmode & 3;
for (int j = 0; j < count; j++)
{
byte b = reader.ReadByte();
nanosecondHundreds |= (((uint) b) << ((j + 3 - count)*8));
nanosecondHundreds |= (((uint)b) << ((j + 3 - count) * 8));
}
//10^-7 to 10^-3
return time.Value.AddMilliseconds(nanosecondHundreds*Math.Pow(10, -4));
return time.Value.AddMilliseconds(nanosecondHundreds * Math.Pow(10, -4));
}
private static string ConvertPath(string path, HostOS os)
@@ -205,7 +209,7 @@ namespace SharpCompress.Common.Rar.Headers
internal FileFlags FileFlags
{
get { return (FileFlags) base.Flags; }
get { return (FileFlags)base.Flags; }
}
internal long CompressedSize { get; private set; }

View File

@@ -0,0 +1,22 @@
using SharpCompress.IO;
namespace SharpCompress.Common.Rar.Headers
{
// ProtectHeader is part of the Recovery Record feature
internal class ProtectHeader : RarHeader
{
protected override void ReadFromReader(MarkingBinaryReader reader)
{
Version = reader.ReadByte();
RecSectors = reader.ReadUInt16();
TotalBlocks = reader.ReadUInt32();
Mark = reader.ReadBytes(8);
}
internal uint DataSize { get { return AdditionalSize; } }
internal byte Version { get; private set; }
internal ushort RecSectors { get; private set; }
internal uint TotalBlocks { get; private set; }
internal byte[] Mark { get; private set; }
}
}

View File

@@ -35,11 +35,10 @@ namespace SharpCompress.Common.Rar.Headers
return null;
}
}
protected virtual void ReadFromReader(MarkingBinaryReader reader)
{
HeadCRC = reader.ReadInt16();
HeaderType = (HeaderType) (int) (reader.ReadByte() & 0xff);
HeaderType = (HeaderType)(reader.ReadByte() & 0xff);
Flags = reader.ReadInt16();
HeaderSize = reader.ReadInt16();
if (FlagUtility.HasFlag(Flags, LONG_BLOCK))
@@ -58,7 +57,7 @@ namespace SharpCompress.Common.Rar.Headers
header.ReadFromReader(reader);
header.ReadBytes += reader.CurrentReadByteCount;
int headerSizeDiff = header.HeaderSize - (int) header.ReadBytes;
int headerSizeDiff = header.HeaderSize - (int)header.ReadBytes;
if (headerSizeDiff > 0)
{

View File

@@ -7,24 +7,27 @@ namespace SharpCompress.Common.Rar.Headers
{
internal class RarHeaderFactory
{
private int MAX_SFX_SIZE = 0x80000 - 16; //archive.cpp line 136
private const int MAX_SFX_SIZE = 0x80000 - 16; //archive.cpp line 136
internal RarHeaderFactory(StreamingMode mode, Options options)
internal RarHeaderFactory(StreamingMode mode, Options options, string password = null)
{
StreamingMode = mode;
Options = options;
Password = password;
}
private Options Options { get; set; }
public string Password { get; private set; }
internal StreamingMode StreamingMode { get; private set; }
internal bool IsEncrypted { get; private set; }
internal IEnumerable<RarHeader> ReadHeaders(Stream stream)
{
if (Options.HasFlag(Options.LookForHeader))
{
stream = CheckSFX(stream);
}
RarHeader header;
while ((header = ReadNextHeader(stream)) != null)
{
@@ -90,7 +93,11 @@ namespace SharpCompress.Common.Rar.Headers
{
if (!Options.HasFlag(Options.KeepStreamsOpen))
{
#if NET2
reader.Close();
#else
reader.Dispose();
#endif
}
throw new InvalidFormatException("Error trying to read rar signature.", e);
}
@@ -107,9 +114,26 @@ namespace SharpCompress.Common.Rar.Headers
return rewindableStream;
}
private RarHeader ReadNextHeader(Stream stream)
{
MarkingBinaryReader reader = new MarkingBinaryReader(stream);
#if PORTABLE
var reader = new MarkingBinaryReader(stream);
#else
var reader = new RarCryptoBinaryReader(stream, Password);
if (IsEncrypted)
{
if (Password == null)
{
throw new CryptographicException("Encrypted Rar archive has no password specified.");
}
reader.SkipQueue();
byte[] salt = reader.ReadBytes(8);
reader.InitializeAes(salt);
}
#endif
RarHeader header = RarHeader.Create(reader);
if (header == null)
{
@@ -119,12 +143,41 @@ namespace SharpCompress.Common.Rar.Headers
{
case HeaderType.ArchiveHeader:
{
return header.PromoteHeader<ArchiveHeader>(reader);
var ah = header.PromoteHeader<ArchiveHeader>(reader);
IsEncrypted = ah.HasPassword;
return ah;
}
case HeaderType.MarkHeader:
{
return header.PromoteHeader<MarkHeader>(reader);
}
case HeaderType.ProtectHeader:
{
ProtectHeader ph = header.PromoteHeader<ProtectHeader>(reader);
// skip the recovery record data, we do not use it.
switch (StreamingMode)
{
case StreamingMode.Seekable:
{
reader.BaseStream.Position += ph.DataSize;
}
break;
case StreamingMode.Streaming:
{
reader.BaseStream.Skip(ph.DataSize);
}
break;
default:
{
throw new InvalidFormatException("Invalid StreamingMode");
}
}
return ph;
}
case HeaderType.NewSubHeader:
{
FileHeader fh = header.PromoteHeader<FileHeader>(reader);
@@ -162,9 +215,19 @@ namespace SharpCompress.Common.Rar.Headers
break;
case StreamingMode.Streaming:
{
ReadOnlySubStream ms
= new ReadOnlySubStream(reader.BaseStream, fh.CompressedSize);
fh.PackedStream = ms;
var ms = new ReadOnlySubStream(reader.BaseStream, fh.CompressedSize);
if (fh.Salt == null)
{
fh.PackedStream = ms;
}
else
{
#if PORTABLE
throw new NotSupportedException("Encrypted Rar files aren't supported in portable distro.");
#else
fh.PackedStream = new RarCryptoWrapper(ms, Password, fh.Salt);
#endif
}
}
break;
default:

View File

@@ -0,0 +1,81 @@
using System.Collections.Generic;
using System.IO;
using SharpCompress.IO;
namespace SharpCompress.Common.Rar
{
internal class RarCryptoBinaryReader : MarkingBinaryReader
{
private RarRijndael rijndael;
private byte[] salt;
private readonly string password;
private readonly Queue<byte> data = new Queue<byte>();
public RarCryptoBinaryReader(Stream stream, string password )
: base(stream)
{
this.password = password;
}
protected bool UseEncryption
{
get { return salt != null; }
}
internal void InitializeAes(byte[] salt)
{
this.salt = salt;
rijndael = RarRijndael.InitializeFrom(password, salt);
}
public override byte[] ReadBytes(int count)
{
if (UseEncryption)
{
return ReadAndDecryptBytes(count);
}
return base.ReadBytes(count);
}
private byte[] ReadAndDecryptBytes(int count)
{
int queueSize = data.Count;
int sizeToRead = count - queueSize;
if (sizeToRead > 0)
{
int alignedSize = sizeToRead + ((~sizeToRead + 1) & 0xf);
for (int i = 0; i < alignedSize / 16; i++)
{
//long ax = System.currentTimeMillis();
byte[] cipherText = base.ReadBytes(16);
var readBytes = rijndael.ProcessBlock(cipherText);
foreach (var readByte in readBytes)
data.Enqueue(readByte);
}
}
var decryptedBytes = new byte[count];
for (int i = 0; i < count; i++)
{
decryptedBytes[i] = data.Dequeue();
}
return decryptedBytes;
}
public void ClearQueue()
{
data.Clear();
}
public void SkipQueue()
{
var position = BaseStream.Position;
BaseStream.Position = position + data.Count;
ClearQueue();
}
}
}

View File

@@ -0,0 +1,108 @@
using System;
using System.Collections.Generic;
using System.IO;
namespace SharpCompress.Common.Rar
{
internal class RarCryptoWrapper : Stream
{
private readonly Stream actualStream;
private readonly byte[] salt;
private RarRijndael rijndael;
private readonly Queue<byte> data = new Queue<byte>();
public RarCryptoWrapper(Stream actualStream, string password, byte[] salt)
{
this.actualStream = actualStream;
this.salt = salt;
rijndael = RarRijndael.InitializeFrom(password, salt);
}
public override void Flush()
{
throw new NotSupportedException();
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException();
}
public override void SetLength(long value)
{
throw new NotSupportedException();
}
public override int Read(byte[] buffer, int offset, int count)
{
if (salt == null)
{
return actualStream.Read(buffer, offset, count);
}
return ReadAndDecrypt(buffer, offset, count);
}
public int ReadAndDecrypt(byte[] buffer, int offset, int count)
{
int queueSize = data.Count;
int sizeToRead = count - queueSize;
if (sizeToRead > 0)
{
int alignedSize = sizeToRead + ((~sizeToRead + 1) & 0xf);
for (int i = 0; i < alignedSize / 16; i++)
{
//long ax = System.currentTimeMillis();
byte[] cipherText = new byte[RarRijndael.CRYPTO_BLOCK_SIZE];
actualStream.Read(cipherText, 0, RarRijndael.CRYPTO_BLOCK_SIZE);
var readBytes = rijndael.ProcessBlock(cipherText);
foreach (var readByte in readBytes)
data.Enqueue(readByte);
}
for (int i = 0; i < count; i++)
buffer[offset + i] = data.Dequeue();
}
return count;
}
public override void Write(byte[] buffer, int offset, int count)
{
throw new NotSupportedException();
}
public override bool CanRead
{
get { return true; }
}
public override bool CanSeek
{
get { return false; }
}
public override bool CanWrite
{
get { return false; }
}
public override long Length
{
get { throw new NotSupportedException(); }
}
public override long Position { get; set; }
protected override void Dispose(bool disposing)
{
if (rijndael != null)
{
rijndael.Dispose();
rijndael = null;
}
base.Dispose(disposing);
}
}
}

View File

@@ -10,7 +10,7 @@ namespace SharpCompress.Common.Rar
/// <summary>
/// The File's 32 bit CRC Hash
/// </summary>
public override uint Crc
public override long Crc
{
get { return FileHeader.FileCRC; }
}
@@ -18,7 +18,7 @@ namespace SharpCompress.Common.Rar
/// <summary>
/// The path of the file internal to the Rar Archive.
/// </summary>
public override string FilePath
public override string Key
{
get { return FileHeader.FileName; }
}
@@ -79,7 +79,7 @@ namespace SharpCompress.Common.Rar
public override string ToString()
{
return string.Format("Entry Path: {0} Compressed Size: {1} Uncompressed Size: {2} CRC: {3}",
FilePath, CompressedSize, Size, Crc);
Key, CompressedSize, Size, Crc);
}
}
}

View File

@@ -0,0 +1,113 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Parameters;
namespace SharpCompress.Common.Rar
{
internal class RarRijndael : IDisposable
{
internal const int CRYPTO_BLOCK_SIZE = 16;
private readonly string password;
private readonly byte[] salt;
private byte[] aesInitializationVector;
private RijndaelEngine rijndael;
private RarRijndael(string password, byte[] salt)
{
this.password = password;
this.salt = salt;
}
private byte[] ComputeHash(byte[] input)
{
var sha = new Sha1Digest();
sha.BlockUpdate(input, 0, input.Length);
byte[] result = new byte[sha.GetDigestSize()];
sha.DoFinal(result, 0);
return result;
}
private void Initialize()
{
rijndael = new RijndaelEngine();
aesInitializationVector = new byte[CRYPTO_BLOCK_SIZE];
int rawLength = 2 * password.Length;
byte[] rawPassword = new byte[rawLength + 8];
byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
for (int i = 0; i < password.Length; i++)
{
rawPassword[i * 2] = passwordBytes[i];
rawPassword[i * 2 + 1] = 0;
}
for (int i = 0; i < salt.Length; i++)
{
rawPassword[i + rawLength] = salt[i];
}
const int noOfRounds = (1 << 18);
IList<byte> bytes = new List<byte>();
byte[] digest;
//TODO slow code below, find ways to optimize
for (int i = 0; i < noOfRounds; i++)
{
bytes.AddRange(rawPassword);
bytes.AddRange(new[] { (byte)i, (byte)(i >> 8), (byte)(i >> CRYPTO_BLOCK_SIZE) });
if (i % (noOfRounds / CRYPTO_BLOCK_SIZE) == 0)
{
digest = ComputeHash(bytes.ToArray());
aesInitializationVector[i / (noOfRounds / CRYPTO_BLOCK_SIZE)] = digest[19];
}
}
digest = ComputeHash(bytes.ToArray());
//slow code ends
byte[] aesKey = new byte[CRYPTO_BLOCK_SIZE];
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)
aesKey[i * 4 + j] = (byte)
(((digest[i * 4] * 0x1000000) & 0xff000000 |
(uint)((digest[i * 4 + 1] * 0x10000) & 0xff0000) |
(uint)((digest[i * 4 + 2] * 0x100) & 0xff00) |
(uint)(digest[i * 4 + 3] & 0xff)) >> (j * 8));
rijndael.Init(false, new KeyParameter(aesKey));
}
public static RarRijndael InitializeFrom(string password, byte[] salt)
{
var rijndael = new RarRijndael(password, salt);
rijndael.Initialize();
return rijndael;
}
public byte[] ProcessBlock(byte[] cipherText)
{
var plainText = new byte[CRYPTO_BLOCK_SIZE];
var decryptedBytes = new List<byte>();
rijndael.ProcessBlock(cipherText, 0, plainText, 0);
for (int j = 0; j < plainText.Length; j++)
decryptedBytes.Add((byte)(plainText[j] ^ aesInitializationVector[j % 16])); //32:114, 33:101
for (int j = 0; j < aesInitializationVector.Length; j++)
aesInitializationVector[j] = cipherText[j];
return decryptedBytes.ToArray();
}
public void Dispose()
{
}
}
}

View File

@@ -0,0 +1,111 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
namespace SharpCompress.Common.Rar
{
internal class RarRijndael : IDisposable
{
internal const int CRYPTO_BLOCK_SIZE = 16;
private readonly string password;
private readonly byte[] salt;
private byte[] aesInitializationVector;
private Rijndael rijndael;
private RarRijndael(string password, byte[] salt)
{
this.password = password;
this.salt = salt;
}
private void Initialize()
{
rijndael = new RijndaelManaged() { Padding = PaddingMode.None };
aesInitializationVector = new byte[CRYPTO_BLOCK_SIZE];
int rawLength = 2 * password.Length;
byte[] rawPassword = new byte[rawLength + 8];
byte[] passwordBytes = Encoding.Unicode.GetBytes(password);
for (int i = 0; i < rawLength; i++)
{
rawPassword[i] = passwordBytes[i];
}
for (int i = 0; i < salt.Length; i++)
{
rawPassword[i + rawLength] = salt[i];
}
SHA1 sha = new SHA1CryptoServiceProvider();
const int noOfRounds = (1 << 18);
IList<byte> bytes = new List<byte>();
byte[] digest;
//TODO slow code below, find ways to optimize
for (int i = 0; i < noOfRounds; i++)
{
bytes.AddRange(rawPassword);
bytes.AddRange(new[] { (byte)i, (byte)(i >> 8), (byte)(i >> CRYPTO_BLOCK_SIZE) });
if (i % (noOfRounds / CRYPTO_BLOCK_SIZE) == 0)
{
digest = sha.ComputeHash(bytes.ToArray());
aesInitializationVector[i / (noOfRounds / CRYPTO_BLOCK_SIZE)] = digest[19];
}
}
digest = sha.ComputeHash(bytes.ToArray());
//slow code ends
byte[] aesKey = new byte[CRYPTO_BLOCK_SIZE];
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)
aesKey[i * 4 + j] = (byte)
(((digest[i * 4] * 0x1000000) & 0xff000000 |
(uint)((digest[i * 4 + 1] * 0x10000) & 0xff0000) |
(uint)((digest[i * 4 + 2] * 0x100) & 0xff00) |
(uint)(digest[i * 4 + 3] & 0xff)) >> (j * 8));
rijndael.IV = new byte[CRYPTO_BLOCK_SIZE];
rijndael.Key = aesKey;
rijndael.BlockSize = CRYPTO_BLOCK_SIZE * 8;
}
public static RarRijndael InitializeFrom(string password, byte[] salt)
{
var rijndael = new RarRijndael(password, salt);
rijndael.Initialize();
return rijndael;
}
public byte[] ProcessBlock(byte[] cipherText)
{
var plainText = new byte[CRYPTO_BLOCK_SIZE];
var decryptedBytes = new List<byte>();
var decryptor = rijndael.CreateDecryptor();
using (var msDecrypt = new MemoryStream(cipherText))
{
using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
csDecrypt.ReadFully(plainText);
}
}
for (int j = 0; j < plainText.Length; j++)
decryptedBytes.Add((byte)(plainText[j] ^ aesInitializationVector[j % 16])); //32:114, 33:101
for (int j = 0; j < aesInitializationVector.Length; j++)
aesInitializationVector[j] = cipherText[j];
return decryptedBytes.ToArray();
}
public void Dispose()
{
((IDisposable)rijndael).Dispose();
}
}
}

View File

@@ -13,13 +13,16 @@ namespace SharpCompress.Common.Rar
public abstract class RarVolume : Volume
{
private readonly RarHeaderFactory headerFactory;
internal RarVolume(StreamingMode mode, Stream stream, Options options)
internal RarVolume(StreamingMode mode, Stream stream, string password, Options options)
: base(stream, options)
{
headerFactory = new RarHeaderFactory(mode, options);
headerFactory = new RarHeaderFactory(mode, options, password);
Password = password;
}
internal string Password { get; private set; }
internal StreamingMode Mode
{
get { return headerFactory.StreamingMode; }

View File

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

View File

@@ -67,8 +67,9 @@ namespace SharpCompress.Common.SevenZip
ulong id = _currentReader.ReadNumber();
if (id > 25)
return null;
#if DEBUG
Log.WriteLine("ReadId: {0}", (BlockType)id);
#endif
return (BlockType)id;
}
@@ -159,7 +160,7 @@ namespace SharpCompress.Common.SevenZip
private DateTime TranslateTime(long time)
{
// FILETIME = 100-nanosecond intervals since January 1, 1601 (UTC)
return DateTime.FromFileTimeUtc(time);
return DateTime.FromFileTimeUtc(time).ToLocalTime();
}
private DateTime? TranslateTime(long? time)
@@ -197,20 +198,25 @@ namespace SharpCompress.Common.SevenZip
private void GetNextFolderItem(CFolder folder)
{
#if DEBUG
Log.WriteLine("-- GetNextFolderItem --");
Log.PushIndent();
#endif
try
{
int numCoders = ReadNum();
#if DEBUG
Log.WriteLine("NumCoders: " + numCoders);
#endif
folder.Coders = new List<CCoderInfo>(numCoders);
int numInStreams = 0;
int numOutStreams = 0;
for (int i = 0; i < numCoders; i++)
{
#if DEBUG
Log.WriteLine("-- Coder --");
Log.PushIndent();
#endif
try
{
CCoderInfo coder = new CCoderInfo();
@@ -220,11 +226,9 @@ namespace SharpCompress.Common.SevenZip
int idSize = (mainByte & 0xF);
byte[] longID = new byte[idSize];
ReadBytes(longID, 0, idSize);
Log.WriteLine("MethodId: " +
String.Join("",
Enumerable.Range(0, idSize)
.Select(x => longID[x].ToString("x2"))
.ToArray()));
#if DEBUG
Log.WriteLine("MethodId: " + String.Join("", Enumerable.Range(0, idSize).Select(x => longID[x].ToString("x2")).ToArray()));
#endif
if (idSize > 8)
throw new NotSupportedException();
ulong id = 0;
@@ -236,12 +240,15 @@ namespace SharpCompress.Common.SevenZip
{
coder.NumInStreams = ReadNum();
coder.NumOutStreams = ReadNum();
Log.WriteLine("Complex Stream (In: " + coder.NumInStreams + " - Out: " + coder.NumOutStreams +
")");
#if DEBUG
Log.WriteLine("Complex Stream (In: " + coder.NumInStreams + " - Out: " + coder.NumOutStreams + ")");
#endif
}
else
{
#if DEBUG
Log.WriteLine("Simple Stream (In: 1 - Out: 1)");
#endif
coder.NumInStreams = 1;
coder.NumOutStreams = 1;
}
@@ -251,8 +258,9 @@ namespace SharpCompress.Common.SevenZip
int propsSize = ReadNum();
coder.Props = new byte[propsSize];
ReadBytes(coder.Props, 0, propsSize);
Log.WriteLine("Settings: " +
String.Join("", coder.Props.Select(bt => bt.ToString("x2")).ToArray()));
#if DEBUG
Log.WriteLine("Settings: " + String.Join("", coder.Props.Select(bt => bt.ToString("x2")).ToArray()));
#endif
}
if ((mainByte & 0x80) != 0)
@@ -263,23 +271,31 @@ namespace SharpCompress.Common.SevenZip
}
finally
{
#if DEBUG
Log.PopIndent();
#endif
}
}
int numBindPairs = numOutStreams - 1;
folder.BindPairs = new List<CBindPair>(numBindPairs);
#if DEBUG
Log.WriteLine("BindPairs: " + numBindPairs);
Log.PushIndent();
#endif
for (int i = 0; i < numBindPairs; i++)
{
CBindPair bp = new CBindPair();
bp.InIndex = ReadNum();
bp.OutIndex = ReadNum();
folder.BindPairs.Add(bp);
#if DEBUG
Log.WriteLine("#" + i + " - In: " + bp.InIndex + " - Out: " + bp.OutIndex);
#endif
}
#if DEBUG
Log.PopIndent();
#endif
if (numInStreams < numBindPairs)
throw new NotSupportedException();
@@ -292,7 +308,9 @@ namespace SharpCompress.Common.SevenZip
{
if (folder.FindBindPairForInStream(i) < 0)
{
#if DEBUG
Log.WriteLine("Single PackStream: #" + i);
#endif
folder.PackStreams.Add(i);
break;
}
@@ -303,26 +321,36 @@ namespace SharpCompress.Common.SevenZip
}
else
{
#if DEBUG
Log.WriteLine("Multiple PackStreams ...");
Log.PushIndent();
#endif
for (int i = 0; i < numPackStreams; i++)
{
var num = ReadNum();
#if DEBUG
Log.WriteLine("#" + i + " - " + num);
#endif
folder.PackStreams.Add(num);
}
#if DEBUG
Log.PopIndent();
#endif
}
}
finally
{
#if DEBUG
Log.PopIndent();
#endif
}
}
private List<uint?> ReadHashDigests(int count)
{
#if DEBUG
Log.Write("ReadHashDigests:");
#endif
var defined = ReadOptionalBitVector(count);
var digests = new List<uint?>(count);
@@ -331,44 +359,62 @@ namespace SharpCompress.Common.SevenZip
if (defined[i])
{
uint crc = ReadUInt32();
#if DEBUG
Log.Write(" " + crc.ToString("x8"));
#endif
digests.Add(crc);
}
else
{
#if DEBUG
Log.Write(" ########");
#endif
digests.Add(null);
}
}
#if DEBUG
Log.WriteLine();
#endif
return digests;
}
private void ReadPackInfo(out long dataOffset, out List<long> packSizes, out List<uint?> packCRCs)
{
#if DEBUG
Log.WriteLine("-- ReadPackInfo --");
Log.PushIndent();
#endif
try
{
packCRCs = null;
dataOffset = checked((long)ReadNumber());
#if DEBUG
Log.WriteLine("DataOffset: " + dataOffset);
#endif
int numPackStreams = ReadNum();
#if DEBUG
Log.WriteLine("NumPackStreams: " + numPackStreams);
#endif
WaitAttribute(BlockType.Size);
packSizes = new List<long>(numPackStreams);
#if DEBUG
Log.Write("Sizes:");
#endif
for (int i = 0; i < numPackStreams; i++)
{
var size = checked((long)ReadNumber());
#if DEBUG
Log.Write(" " + size);
#endif
packSizes.Add(size);
}
#if DEBUG
Log.WriteLine();
#endif
BlockType? type;
for (; ; )
@@ -393,19 +439,25 @@ namespace SharpCompress.Common.SevenZip
}
finally
{
#if DEBUG
Log.PopIndent();
#endif
}
}
private void ReadUnpackInfo(List<byte[]> dataVector, out List<CFolder> folders)
{
#if DEBUG
Log.WriteLine("-- ReadUnpackInfo --");
Log.PushIndent();
#endif
try
{
WaitAttribute(BlockType.Folder);
int numFolders = ReadNum();
#if DEBUG
Log.WriteLine("NumFolders: {0}", numFolders);
#endif
using (CStreamSwitch streamSwitch = new CStreamSwitch())
{
@@ -424,20 +476,27 @@ namespace SharpCompress.Common.SevenZip
}
WaitAttribute(BlockType.CodersUnpackSize);
#if DEBUG
Log.WriteLine("UnpackSizes:");
#endif
for (int i = 0; i < numFolders; i++)
{
CFolder folder = folders[i];
#if DEBUG
Log.Write(" #" + i + ":");
#endif
int numOutStreams = folder.GetNumOutStreams();
for (int j = 0; j < numOutStreams; j++)
{
long size = checked((long)ReadNumber());
#if DEBUG
Log.Write(" " + size);
#endif
folder.UnpackSizes.Add(size);
}
#if DEBUG
Log.WriteLine();
#endif
}
for (; ; )
@@ -459,15 +518,19 @@ namespace SharpCompress.Common.SevenZip
}
finally
{
#if DEBUG
Log.PopIndent();
#endif
}
}
private void ReadSubStreamsInfo(List<CFolder> folders, out List<int> numUnpackStreamsInFolders,
out List<long> unpackSizes, out List<uint?> digests)
{
#if DEBUG
Log.WriteLine("-- ReadSubStreamsInfo --");
Log.PushIndent();
#endif
try
{
numUnpackStreamsInFolders = null;
@@ -479,14 +542,20 @@ namespace SharpCompress.Common.SevenZip
if (type == BlockType.NumUnpackStream)
{
numUnpackStreamsInFolders = new List<int>(folders.Count);
#if DEBUG
Log.Write("NumUnpackStreams:");
#endif
for (int i = 0; i < folders.Count; i++)
{
var num = ReadNum();
#if DEBUG
Log.Write(" " + num);
#endif
numUnpackStreamsInFolders.Add(num);
}
#if DEBUG
Log.WriteLine();
#endif
continue;
}
if (type == BlockType.CRC || type == BlockType.Size)
@@ -511,21 +580,26 @@ namespace SharpCompress.Common.SevenZip
int numSubstreams = numUnpackStreamsInFolders[i];
if (numSubstreams == 0)
continue;
#if DEBUG
Log.Write("#{0} StreamSizes:", i);
#endif
long sum = 0;
for (int j = 1; j < numSubstreams; j++)
{
if (type == BlockType.Size)
{
long size = checked((long)ReadNumber());
#if DEBUG
Log.Write(" " + size);
#endif
unpackSizes.Add(size);
sum += size;
}
}
unpackSizes.Add(folders[i].GetUnpackSize() - sum);
#if DEBUG
Log.WriteLine(" - rest: " + unpackSizes.Last());
#endif
}
if (type == BlockType.Size)
type = ReadId();
@@ -589,7 +663,9 @@ namespace SharpCompress.Common.SevenZip
}
finally
{
#if DEBUG
Log.PopIndent();
#endif
}
}
@@ -603,8 +679,10 @@ namespace SharpCompress.Common.SevenZip
out List<long> unpackSizes,
out List<uint?> digests)
{
#if DEBUG
Log.WriteLine("-- ReadStreamsInfo --");
Log.PushIndent();
#endif
try
{
dataOffset = long.MinValue;
@@ -637,14 +715,18 @@ namespace SharpCompress.Common.SevenZip
}
finally
{
#if DEBUG
Log.PopIndent();
#endif
}
}
private List<byte[]> ReadAndDecodePackedStreams(long baseOffset, IPasswordProvider pass)
{
#if DEBUG
Log.WriteLine("-- ReadAndDecodePackedStreams --");
Log.PushIndent();
#endif
try
{
long dataStartPos;
@@ -697,14 +779,18 @@ namespace SharpCompress.Common.SevenZip
}
finally
{
#if DEBUG
Log.PopIndent();
#endif
}
}
private void ReadHeader(ArchiveDatabase db, IPasswordProvider getTextPassword)
{
#if DEBUG
Log.WriteLine("-- ReadHeader --");
Log.PushIndent();
#endif
try
{
BlockType? type = ReadId();
@@ -762,7 +848,9 @@ namespace SharpCompress.Common.SevenZip
throw new InvalidOperationException();
int numFiles = ReadNum();
#if DEBUG
Log.WriteLine("NumFiles: " + numFiles);
#endif
db.Files = new List<CFileItem>(numFiles);
for (int i = 0; i < numFiles; i++)
db.Files.Add(new CFileItem());
@@ -786,112 +874,147 @@ namespace SharpCompress.Common.SevenZip
using (var streamSwitch = new CStreamSwitch())
{
streamSwitch.Set(this, dataVector);
#if DEBUG
Log.Write("FileNames:");
#endif
for (int i = 0; i < db.Files.Count; i++)
{
db.Files[i].Name = _currentReader.ReadString();
#if DEBUG
Log.Write(" " + db.Files[i].Name);
#endif
}
#if DEBUG
Log.WriteLine();
#endif
}
break;
case BlockType.WinAttributes:
#if DEBUG
Log.Write("WinAttributes:");
#endif
ReadAttributeVector(dataVector, numFiles, delegate(int i, uint? attr)
{
db.Files[i].Attrib = attr;
Log.Write(" " +
(attr.HasValue
? attr.Value.ToString("x8")
: "n/a"));
#if DEBUG
Log.Write(" " + (attr.HasValue ? attr.Value.ToString("x8") : "n/a"));
#endif
});
#if DEBUG
Log.WriteLine();
#endif
break;
case BlockType.EmptyStream:
emptyStreamVector = ReadBitVector(numFiles);
#if DEBUG
Log.Write("EmptyStream: ");
#endif
for (int i = 0; i < emptyStreamVector.Length; i++)
{
if (emptyStreamVector[i])
{
#if DEBUG
Log.Write("x");
#endif
numEmptyStreams++;
}
else
{
#if DEBUG
Log.Write(".");
#endif
}
}
#if DEBUG
Log.WriteLine();
#endif
emptyFileVector = new BitVector(numEmptyStreams);
antiFileVector = new BitVector(numEmptyStreams);
break;
case BlockType.EmptyFile:
emptyFileVector = ReadBitVector(numEmptyStreams);
#if DEBUG
Log.Write("EmptyFile: ");
for (int i = 0; i < numEmptyStreams; i++)
Log.Write(emptyFileVector[i] ? "x" : ".");
Log.WriteLine();
#endif
break;
case BlockType.Anti:
antiFileVector = ReadBitVector(numEmptyStreams);
#if DEBUG
Log.Write("Anti: ");
for (int i = 0; i < numEmptyStreams; i++)
Log.Write(antiFileVector[i] ? "x" : ".");
Log.WriteLine();
#endif
break;
case BlockType.StartPos:
#if DEBUG
Log.Write("StartPos:");
#endif
ReadNumberVector(dataVector, numFiles, delegate(int i, long? startPos)
{
db.Files[i].StartPos = startPos;
Log.Write(" " +
(startPos.HasValue
? startPos.Value.ToString()
: "n/a"));
#if DEBUG
Log.Write(" " + (startPos.HasValue ? startPos.Value.ToString() : "n/a"));
#endif
});
#if DEBUG
Log.WriteLine();
#endif
break;
case BlockType.CTime:
#if DEBUG
Log.Write("CTime:");
#endif
ReadDateTimeVector(dataVector, numFiles, delegate(int i, DateTime? time)
{
db.Files[i].CTime = time;
Log.Write(" " +
(time.HasValue
? time.Value.ToString()
: "n/a"));
#if DEBUG
Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a"));
#endif
});
#if DEBUG
Log.WriteLine();
#endif
break;
case BlockType.ATime:
#if DEBUG
Log.Write("ATime:");
#endif
ReadDateTimeVector(dataVector, numFiles, delegate(int i, DateTime? time)
{
db.Files[i].ATime = time;
Log.Write(" " +
(time.HasValue
? time.Value.ToString()
: "n/a"));
#if DEBUG
Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a"));
#endif
});
#if DEBUG
Log.WriteLine();
#endif
break;
case BlockType.MTime:
#if DEBUG
Log.Write("MTime:");
#endif
ReadDateTimeVector(dataVector, numFiles, delegate(int i, DateTime? time)
{
db.Files[i].MTime = time;
Log.Write(" " +
(time.HasValue
? time.Value.ToString()
: "n/a"));
#if DEBUG
Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a"));
#endif
});
#if DEBUG
Log.WriteLine();
#endif
break;
case BlockType.Dummy:
#if DEBUG
Log.Write("Dummy: " + size);
#endif
for (long j = 0; j < size; j++)
if (ReadByte() != 0)
throw new InvalidOperationException();
@@ -933,7 +1056,9 @@ namespace SharpCompress.Common.SevenZip
}
finally
{
#if DEBUG
Log.PopIndent();
#endif
}
}
@@ -1089,48 +1214,48 @@ namespace SharpCompress.Common.SevenZip
public override bool CanRead
{
get { throw new NotImplementedException(); }
get { return true; }
}
public override bool CanSeek
{
get { throw new NotImplementedException(); }
get { return false; }
}
public override bool CanWrite
{
get { throw new NotImplementedException(); }
get { return false; }
}
public override void Flush()
{
throw new NotImplementedException();
throw new NotSupportedException();
}
public override long Length
{
get { throw new NotImplementedException(); }
get { throw new NotSupportedException(); }
}
public override long Position
{
get { throw new NotImplementedException(); }
set { throw new NotImplementedException(); }
get { throw new NotSupportedException(); }
set { throw new NotSupportedException(); }
}
public override int Read(byte[] buffer, int offset, int count)
{
throw new NotImplementedException();
throw new NotSupportedException();
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotImplementedException();
throw new NotSupportedException();
}
public override void SetLength(long value)
{
throw new NotImplementedException();
throw new NotSupportedException();
}
private Stream _stream;
@@ -1156,7 +1281,9 @@ namespace SharpCompress.Common.SevenZip
//string filename = @"D:\_testdump\" + _db.Files[index].Name;
//Directory.CreateDirectory(Path.GetDirectoryName(filename));
//_stream = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.Delete);
#if DEBUG
Log.WriteLine(_db.Files[index].Name);
#endif
if (_db.Files[index].CrcDefined)
_stream = new CrcCheckStream(_db.Files[index].Crc.Value);
else
@@ -1192,7 +1319,7 @@ namespace SharpCompress.Common.SevenZip
{
// we support partial extracting
System.Diagnostics.Debugger.Break();
throw new NotImplementedException();
throw new NotSupportedException();
}
OpenFile();
}

View File

@@ -16,7 +16,9 @@ namespace SharpCompress.Common.SevenZip
if (_active)
{
_active = false;
#if DEBUG
Log.WriteLine("[end of switch]");
#endif
}
if (_needRemove)
@@ -47,7 +49,9 @@ namespace SharpCompress.Common.SevenZip
if (dataIndex < 0 || dataIndex >= dataVector.Count)
throw new InvalidOperationException();
#if DEBUG
Log.WriteLine("[switch to stream {0}]", dataIndex);
#endif
_archive = archive;
_archive.AddByteStream(dataVector[dataIndex], 0, dataVector[dataIndex].Length);
_needRemove = true;
@@ -55,7 +59,9 @@ namespace SharpCompress.Common.SevenZip
}
else
{
#if DEBUG
Log.WriteLine("[inline data]");
#endif
}
}
}

View File

@@ -78,7 +78,9 @@ namespace SharpCompress.Common.SevenZip
throw new EndOfStreamException();
_offset += (int) size;
#if DEBUG
Log.WriteLine("SkipData {0}", size);
#endif
}
public void SkipData()

View File

@@ -17,12 +17,12 @@ namespace SharpCompress.Common.SevenZip
get { return FilePart.CompressionType; }
}
public override uint Crc
public override long Crc
{
get { return FilePart.Header.Crc ?? 0; }
}
public override string FilePath
public override string Key
{
get { return FilePart.Header.Name; }
}
@@ -39,22 +39,22 @@ namespace SharpCompress.Common.SevenZip
public override DateTime? LastModifiedTime
{
get { throw new NotImplementedException(); }
get { return FilePart.Header.MTime; }
}
public override DateTime? CreatedTime
{
get { throw new NotImplementedException(); }
get { return null; }
}
public override DateTime? LastAccessedTime
{
get { throw new NotImplementedException(); }
get { return null; }
}
public override DateTime? ArchivedTime
{
get { throw new NotImplementedException(); }
get { return null; }
}
public override bool IsEncrypted
@@ -72,13 +72,14 @@ namespace SharpCompress.Common.SevenZip
get { return false; }
}
public override int? Attrib
{
get { return (int) FilePart.Header.Attrib; }
}
internal override IEnumerable<FilePart> Parts
{
get { return FilePart.AsEnumerable<FilePart>(); }
}
internal override void Close()
{
}
}
}

View File

@@ -2,18 +2,11 @@
namespace SharpCompress.Common.SevenZip
{
public class SevenZipVolume : GenericVolume
public class SevenZipVolume : Volume
{
public SevenZipVolume(Stream stream, Options options)
: base(stream, options)
{
}
#if !PORTABLE && !NETFX_CORE
public SevenZipVolume(FileInfo fileInfo, Options options)
: base(fileInfo, options)
{
}
#endif
}
}

View File

@@ -25,7 +25,7 @@ namespace SharpCompress.Common.Tar.Headers
internal class TarHeader
{
internal static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0);
internal static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
internal string Name { get; set; }
//internal int Mode { get; set; }
@@ -40,48 +40,64 @@ namespace SharpCompress.Common.Tar.Headers
internal void Write(Stream output)
{
if (Name.Length > 255)
{
throw new InvalidFormatException("UsTar fileName can not be longer thatn 255 chars");
}
byte[] buffer = new byte[512];
string name = Name;
if (name.Length > 100)
{
name = Name.Substring(0, 100);
}
WriteStringBytes(name, buffer, 0, 100);
WriteOctalBytes(511, buffer, 100, 8);
WriteOctalBytes(0, buffer, 108, 8);
WriteOctalBytes(0, buffer, 116, 8);
WriteOctalBytes(Size, buffer, 124, 12);
var time = (long) (LastModifiedTime - Epoch).TotalSeconds;
WriteOctalBytes(time, buffer, 136, 12);
buffer[156] = (byte) EntryType;
WriteOctalBytes(511, buffer, 100, 8); // file mode
WriteOctalBytes(0, buffer, 108, 8); // owner ID
WriteOctalBytes(0, buffer, 116, 8); // group ID
//Encoding.UTF8.GetBytes("magic").CopyTo(buffer, 257);
if (Name.Length > 100)
{
name = Name.Substring(101, Name.Length);
ArchiveEncoding.Default.GetBytes(name).CopyTo(buffer, 345);
// Set mock filename and filetype to indicate the next block is the actual name of the file
WriteStringBytes("././@LongLink", buffer, 0, 100);
buffer[156] = (byte)EntryType.LongName;
WriteOctalBytes(Name.Length + 1, buffer, 124, 12);
}
if (Size >= 0x1FFFFFFFF)
else
{
WriteStringBytes(Name, buffer, 0, 100);
WriteOctalBytes(Size, buffer, 124, 12);
var time = (long)(LastModifiedTime.ToUniversalTime() - Epoch).TotalSeconds;
WriteOctalBytes(time, buffer, 136, 12);
buffer[156] = (byte)EntryType;
if (Size >= 0x1FFFFFFFF)
{
#if PORTABLE || NETFX_CORE
byte[] bytes = BitConverter.GetBytes(Utility.HostToNetworkOrder(Size));
#else
byte[] bytes = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(Size));
byte[] bytes = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(Size));
#endif
var bytes12 = new byte[12];
bytes.CopyTo(bytes12, 12 - bytes.Length);
bytes12[0] |= 0x80;
bytes12.CopyTo(buffer, 124);
var bytes12 = new byte[12];
bytes.CopyTo(bytes12, 12 - bytes.Length);
bytes12[0] |= 0x80;
bytes12.CopyTo(buffer, 124);
}
}
int crc = RecalculateChecksum(buffer);
WriteOctalBytes(crc, buffer, 148, 8);
output.Write(buffer, 0, buffer.Length);
if (Name.Length > 100)
{
WriteLongFilenameHeader(output);
Name = Name.Substring(0, 100);
Write(output);
}
}
private void WriteLongFilenameHeader(Stream output)
{
byte[] nameBytes = ArchiveEncoding.Default.GetBytes(Name);
output.Write(nameBytes, 0, nameBytes.Length);
// pad to multiple of 512 bytes, and make sure a terminating null is added
int numPaddingBytes = 512 - (nameBytes.Length % 512);
if (numPaddingBytes == 0)
numPaddingBytes = 512;
output.Write(new byte[numPaddingBytes], 0, numPaddingBytes);
}
internal bool Read(BinaryReader reader)
@@ -115,12 +131,12 @@ namespace SharpCompress.Common.Tar.Headers
Size = ReadASCIIInt64Base8(buffer, 124, 11);
}
long unixTimeStamp = ReadASCIIInt64Base8(buffer, 136, 11);
LastModifiedTime = Epoch.AddSeconds(unixTimeStamp);
LastModifiedTime = Epoch.AddSeconds(unixTimeStamp).ToLocalTime();
Magic = ArchiveEncoding.Default.GetString(buffer, 257, 6).TrimNulls();
if (!string.IsNullOrEmpty(Magic) && "ustar ".Equals(Magic))
if (!string.IsNullOrEmpty(Magic) && "ustar".Equals(Magic))
{
string namePrefix = ArchiveEncoding.Default.GetString(buffer, 345, 157);
namePrefix = namePrefix.TrimNulls();
@@ -163,7 +179,6 @@ namespace SharpCompress.Common.Tar.Headers
{
buffer[offset + i + shift] = (byte) val[i];
}
buffer[offset + length] = 0;
}
private static int ReadASCIIInt32Base8(byte[] buffer, int offset, int count)

View File

@@ -22,12 +22,12 @@ namespace SharpCompress.Common.Tar
get { return type; }
}
public override uint Crc
public override long Crc
{
get { return 0; }
}
public override string FilePath
public override string Key
{
get { return filePart.Header.Name; }
}
@@ -100,9 +100,5 @@ namespace SharpCompress.Common.Tar
}
}
}
internal override void Close()
{
}
}
}

View File

@@ -6,12 +6,12 @@ namespace SharpCompress.Common.Tar
{
internal class TarFilePart : FilePart
{
private Stream seekableStream;
private readonly Stream seekableStream;
internal TarFilePart(TarHeader header, Stream seekableStream)
{
this.seekableStream = seekableStream;
this.Header = header;
Header = header;
}
internal TarHeader Header { get; private set; }

View File

@@ -4,19 +4,25 @@ namespace SharpCompress.Common.Tar
{
internal class TarReadOnlySubStream : Stream
{
private int amountRead;
private bool isDisposed;
private long amountRead;
public TarReadOnlySubStream(Stream stream, long bytesToRead)
{
this.Stream = stream;
this.BytesLeftToRead = bytesToRead;
Stream = stream;
BytesLeftToRead = bytesToRead;
}
protected override void Dispose(bool disposing)
{
if (isDisposed)
{
return;
}
isDisposed = true;
if (disposing)
{
int skipBytes = this.amountRead%512;
long skipBytes = amountRead % 512;
if (skipBytes == 0)
{
return;
@@ -27,7 +33,7 @@ namespace SharpCompress.Common.Tar
return;
}
var buffer = new byte[skipBytes];
this.Stream.ReadFully(buffer);
Stream.ReadFully(buffer);
}
}
@@ -52,48 +58,48 @@ namespace SharpCompress.Common.Tar
public override void Flush()
{
throw new System.NotImplementedException();
throw new System.NotSupportedException();
}
public override long Length
{
get { throw new System.NotImplementedException(); }
get { throw new System.NotSupportedException(); }
}
public override long Position
{
get { throw new System.NotImplementedException(); }
set { throw new System.NotImplementedException(); }
get { throw new System.NotSupportedException(); }
set { throw new System.NotSupportedException(); }
}
public override int Read(byte[] buffer, int offset, int count)
{
if (this.BytesLeftToRead < count)
if (BytesLeftToRead < count)
{
count = (int) this.BytesLeftToRead;
count = (int)BytesLeftToRead;
}
int read = this.Stream.Read(buffer, offset, count);
int read = Stream.Read(buffer, offset, count);
if (read > 0)
{
this.BytesLeftToRead -= read;
this.amountRead += read;
BytesLeftToRead -= read;
amountRead += read;
}
return read;
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new System.NotImplementedException();
throw new System.NotSupportedException();
}
public override void SetLength(long value)
{
throw new System.NotImplementedException();
throw new System.NotSupportedException();
}
public override void Write(byte[] buffer, int offset, int count)
{
throw new System.NotImplementedException();
throw new System.NotSupportedException();
}
}
}

View File

@@ -2,18 +2,11 @@
namespace SharpCompress.Common.Tar
{
public class TarVolume : GenericVolume
public class TarVolume : Volume
{
public TarVolume(Stream stream, Options options)
: base(stream, options)
{
}
#if !PORTABLE && !NETFX_CORE
public TarVolume(FileInfo fileInfo, Options options)
: base(fileInfo, options)
{
}
#endif
}
}

View File

@@ -24,16 +24,18 @@ namespace SharpCompress.Common
/// RarArchive is the first volume of a multi-part archive.
/// Only Rar 3.0 format and higher
/// </summary>
public abstract bool IsFirstVolume { get; }
public virtual bool IsFirstVolume
{
get { return true; }
}
/// <summary>
/// RarArchive is part of a multi-part archive.
/// </summary>
public abstract bool IsMultiVolume { get; }
#if !PORTABLE && !NETFX_CORE
public abstract FileInfo VolumeFile { get; }
#endif
public virtual bool IsMultiVolume
{
get { return true; }
}
private bool disposed;

View File

@@ -1,4 +1,5 @@
using System.IO;
using System.Linq;
namespace SharpCompress.Common.Zip.Headers
{
@@ -34,6 +35,12 @@ namespace SharpCompress.Common.Zip.Headers
byte[] comment = reader.ReadBytes(commentLength);
Comment = DecodeString(comment);
LoadExtra(extra);
var unicodePathExtra = Extra.FirstOrDefault(u => u.Type == ExtraDataType.UnicodePathExtraField);
if (unicodePathExtra != null)
{
Name = ((ExtraUnicodePathExtraField)unicodePathExtra).UnicodeName;
}
}
internal override void Write(BinaryWriter writer)

View File

@@ -1,19 +1,8 @@
using System.IO;
using System.Linq;
namespace SharpCompress.Common.Zip.Headers
{
internal enum ExtraDataType : ushort
{
WinZipAes = 0x9901,
}
internal class ExtraData
{
internal ExtraDataType Type { get; set; }
internal ushort Length { get; set; }
internal byte[] DataBytes { get; set; }
}
internal class LocalEntryHeader : ZipFileEntry
{
public LocalEntryHeader()
@@ -37,6 +26,12 @@ namespace SharpCompress.Common.Zip.Headers
byte[] extra = reader.ReadBytes(extraLength);
Name = DecodeString(name);
LoadExtra(extra);
var unicodePathExtra = Extra.FirstOrDefault(u => u.Type == ExtraDataType.UnicodePathExtraField);
if (unicodePathExtra!=null)
{
Name = ((ExtraUnicodePathExtraField) unicodePathExtra).UnicodeName;
}
}
internal override void Write(BinaryWriter writer)

View File

@@ -0,0 +1,75 @@
using System;
using System.Text;
namespace SharpCompress.Common.Zip.Headers
{
internal enum ExtraDataType : ushort
{
WinZipAes = 0x9901,
NotImplementedExtraData = 0xFFFF,
// Third Party Mappings
// -Info-ZIP Unicode Path Extra Field
UnicodePathExtraField = 0x7075
}
internal class ExtraData
{
internal ExtraDataType Type { get; set; }
internal ushort Length { get; set; }
internal byte[] DataBytes { get; set; }
}
internal class ExtraUnicodePathExtraField : ExtraData
{
internal byte Version
{
get { return this.DataBytes[0]; }
}
internal byte[] NameCRC32
{
get
{
var crc = new byte[4];
Buffer.BlockCopy(this.DataBytes, 1, crc, 0, 4);
return crc;
}
}
internal string UnicodeName
{
get
{
// PathNamelength = dataLength - Version(1 byte) - NameCRC32(4 bytes)
var length = this.Length - 5;
var nameStr = Encoding.UTF8.GetString(this.DataBytes, 5, length);
return nameStr;
}
}
}
internal static class LocalEntryHeaderExtraFactory
{
internal static ExtraData Create(ExtraDataType type,ushort length, byte[] extraData)
{
switch (type)
{
case ExtraDataType.UnicodePathExtraField:
return new ExtraUnicodePathExtraField()
{
Type = type,
Length = length,
DataBytes = extraData
};
default:
return new ExtraData
{
Type = type,
Length = length,
DataBytes = extraData
};
}
}
}
}

View File

@@ -13,7 +13,6 @@ namespace SharpCompress.Common.Zip.Headers
Extra = new List<ExtraData>();
}
internal bool IsDirectory
{
get { return Name.EndsWith("/"); }
@@ -25,6 +24,7 @@ namespace SharpCompress.Common.Zip.Headers
{
return Encoding.UTF8.GetString(str, 0, str.Length);
}
return ArchiveEncoding.Default.GetString(str, 0, str.Length);
}
@@ -66,22 +66,19 @@ namespace SharpCompress.Common.Zip.Headers
protected void LoadExtra(byte[] extra)
{
for (int i = 0; i < extra.Length;)
for (int i = 0; i < extra.Length-4;)
{
ExtraDataType type = (ExtraDataType) BitConverter.ToUInt16(extra, i);
if (!Enum.IsDefined(typeof (ExtraDataType), type))
{
return;
type = ExtraDataType.NotImplementedExtraData;
}
ushort length = BitConverter.ToUInt16(extra, i + 2);
byte[] data = new byte[length];
Buffer.BlockCopy(extra, i + 4, data, 0, length);
Extra.Add(new ExtraData
{
Type = type,
Length = length,
DataBytes = data
});
Extra.Add(LocalEntryHeaderExtraFactory.Create(type,length,data));
i += length + 4;
}
}

View File

@@ -15,6 +15,7 @@ namespace SharpCompress.Common.Zip
private readonly PkwareTraditionalEncryptionData encryptor;
private readonly CryptoMode mode;
private readonly Stream stream;
private bool isDisposed;
public PkwareTraditionalCryptoStream(Stream stream, PkwareTraditionalEncryptionData encryptor, CryptoMode mode)
{
@@ -104,5 +105,16 @@ namespace SharpCompress.Common.Zip
{
throw new NotSupportedException();
}
protected override void Dispose(bool disposing)
{
if (isDisposed)
{
return;
}
isDisposed = true;
base.Dispose(disposing);
stream.Dispose();
}
}
}

View File

@@ -8,7 +8,7 @@ namespace SharpCompress.Common.Zip
{
internal class SeekableZipHeaderFactory : ZipHeaderFactory
{
private const int MAX_ITERATIONS_FOR_DIRECTORY_HEADER = 1000;
private const int MAX_ITERATIONS_FOR_DIRECTORY_HEADER = 4096;
internal SeekableZipHeaderFactory(string password)
: base(StreamingMode.Seekable, password)

View File

@@ -0,0 +1,170 @@
using System;
using System.IO;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Parameters;
namespace SharpCompress.Common.Zip
{
internal class WinzipAesCryptoStream : Stream
{
private const int BLOCK_SIZE_IN_BYTES = 16;
private readonly IBufferedCipher rijndael;
private readonly byte[] counter = new byte[BLOCK_SIZE_IN_BYTES];
private readonly Stream stream;
private int nonce = 1;
private byte[] counterOut = new byte[BLOCK_SIZE_IN_BYTES];
private bool isFinalBlock;
private long totalBytesLeftToRead;
private bool isDisposed;
internal WinzipAesCryptoStream(Stream stream, WinzipAesEncryptionData winzipAesEncryptionData, long length)
{
this.stream = stream;
totalBytesLeftToRead = length;
rijndael = CreateRijndael(winzipAesEncryptionData);
}
private IBufferedCipher CreateRijndael(WinzipAesEncryptionData winzipAesEncryptionData)
{
var blockCipher = new BufferedBlockCipher(new RijndaelEngine());
var param = new KeyParameter(winzipAesEncryptionData.KeyBytes);
blockCipher.Init(true, param);
return blockCipher;
}
public override bool CanRead
{
get { return true; }
}
public override bool CanSeek
{
get { return false; }
}
public override bool CanWrite
{
get { return false; }
}
public override long Length
{
get { throw new NotImplementedException(); }
}
public override long Position
{
get { throw new NotImplementedException(); }
set { throw new NotImplementedException(); }
}
protected override void Dispose(bool disposing)
{
if (isDisposed)
{
return;
}
isDisposed = true;
if (disposing)
{
//read out last 10 auth bytes
var ten = new byte[10];
stream.Read(ten, 0, 10);
stream.Dispose();
}
}
public override void Flush()
{
throw new NotImplementedException();
}
public override int Read(byte[] buffer, int offset, int count)
{
if (totalBytesLeftToRead == 0)
{
return 0;
}
int bytesToRead = count;
if (count > totalBytesLeftToRead)
{
bytesToRead = (int)totalBytesLeftToRead;
}
int read = stream.Read(buffer, offset, bytesToRead);
totalBytesLeftToRead -= read;
ReadTransformBlocks(buffer, offset, read);
return read;
}
private int ReadTransformOneBlock(byte[] buffer, int offset, int last)
{
if (isFinalBlock)
{
throw new InvalidOperationException();
}
int bytesRemaining = last - offset;
int bytesToRead = (bytesRemaining > BLOCK_SIZE_IN_BYTES)
? BLOCK_SIZE_IN_BYTES
: bytesRemaining;
// update the counter
Array.Copy(BitConverter.GetBytes(nonce++), 0, counter, 0, 4);
// Determine if this is the final block
if ((bytesToRead == bytesRemaining) && (totalBytesLeftToRead == 0))
{
counterOut = rijndael.DoFinal(counter, 0, BLOCK_SIZE_IN_BYTES);
isFinalBlock = true;
}
else
{
rijndael.ProcessBytes(counter, 0, BLOCK_SIZE_IN_BYTES, counterOut, 0);
}
XorInPlace(buffer, offset, bytesToRead);
return bytesToRead;
}
private void XorInPlace(byte[] buffer, int offset, int count)
{
for (int i = 0; i < count; i++)
{
buffer[offset + i] = (byte)(counterOut[i] ^ buffer[offset + i]);
}
}
private void ReadTransformBlocks(byte[] buffer, int offset, int count)
{
int posn = offset;
int last = count + offset;
while (posn < buffer.Length && posn < last)
{
int n = ReadTransformOneBlock(buffer, posn, last);
posn += n;
}
}
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();
}
}
}

View File

@@ -9,48 +9,33 @@ namespace SharpCompress.Common.Zip
private const int BLOCK_SIZE_IN_BYTES = 16;
private readonly SymmetricAlgorithm cipher;
private readonly byte[] counter = new byte[BLOCK_SIZE_IN_BYTES];
private readonly HMACSHA1 hmac;
private readonly Stream stream;
private readonly ICryptoTransform transform;
private int _nonce = 1;
private int nonce = 1;
private byte[] counterOut = new byte[BLOCK_SIZE_IN_BYTES];
private bool isFinalBlock;
private CryptoMode mode;
private long totalBytesLeftToRead;
private bool isDisposed;
internal WinzipAesCryptoStream(Stream stream, WinzipAesEncryptionData winzipAesEncryptionData, long length,
CryptoMode mode)
internal WinzipAesCryptoStream(Stream stream, WinzipAesEncryptionData winzipAesEncryptionData, long length)
{
this.mode = mode;
this.stream = stream;
totalBytesLeftToRead = length;
hmac = new HMACSHA1(winzipAesEncryptionData.IvBytes);
cipher = CreateCipher(winzipAesEncryptionData);
var iv = new byte[BLOCK_SIZE_IN_BYTES];
transform = cipher.CreateEncryptor(winzipAesEncryptionData.KeyBytes, iv);
//if (_mode == CryptoMode.Encrypt)
//{
// _iobuf = new byte[2048];
// _PendingWriteBlock = new byte[BLOCK_SIZE_IN_BYTES];
//}
}
private SymmetricAlgorithm CreateCipher(WinzipAesEncryptionData winzipAesEncryptionData)
{
#if !PORTABLE
RijndaelManaged cipher = new RijndaelManaged();
cipher.BlockSize = BLOCK_SIZE_IN_BYTES*8;
cipher.KeySize = winzipAesEncryptionData.KeyBytes.Length*8;
cipher.BlockSize = BLOCK_SIZE_IN_BYTES * 8;
cipher.KeySize = winzipAesEncryptionData.KeyBytes.Length * 8;
cipher.Mode = CipherMode.ECB;
cipher.Padding = PaddingMode.None;
return cipher;
#else
throw new NotSupportedException("Cannot decrypt Winzip AES with Silverlight or WP7.");
#endif
}
public override bool CanRead
@@ -70,17 +55,22 @@ namespace SharpCompress.Common.Zip
public override long Length
{
get { throw new NotImplementedException(); }
get { throw new NotSupportedException(); }
}
public override long Position
{
get { throw new NotImplementedException(); }
set { throw new NotImplementedException(); }
get { throw new NotSupportedException(); }
set { throw new NotSupportedException(); }
}
protected override void Dispose(bool disposing)
{
if (isDisposed)
{
return;
}
isDisposed = true;
if (disposing)
{
//read out last 10 auth bytes
@@ -92,7 +82,7 @@ namespace SharpCompress.Common.Zip
public override void Flush()
{
throw new NotImplementedException();
throw new NotSupportedException();
}
public override int Read(byte[] buffer, int offset, int count)
@@ -104,7 +94,7 @@ namespace SharpCompress.Common.Zip
int bytesToRead = count;
if (count > totalBytesLeftToRead)
{
bytesToRead = (int) totalBytesLeftToRead;
bytesToRead = (int)totalBytesLeftToRead;
}
int read = stream.Read(buffer, offset, bytesToRead);
totalBytesLeftToRead -= read;
@@ -127,12 +117,11 @@ namespace SharpCompress.Common.Zip
: bytesRemaining;
// update the counter
Array.Copy(BitConverter.GetBytes(_nonce++), 0, counter, 0, 4);
Array.Copy(BitConverter.GetBytes(nonce++), 0, counter, 0, 4);
// Determine if this is the final block
if ((bytesToRead == bytesRemaining) && (totalBytesLeftToRead == 0))
{
hmac.TransformFinalBlock(buffer, offset, bytesToRead);
counterOut = transform.TransformFinalBlock(counter,
0,
BLOCK_SIZE_IN_BYTES);
@@ -140,7 +129,6 @@ namespace SharpCompress.Common.Zip
}
else
{
hmac.TransformBlock(buffer, offset, bytesToRead, null, 0);
transform.TransformBlock(counter,
0, // offset
BLOCK_SIZE_IN_BYTES,
@@ -157,7 +145,7 @@ namespace SharpCompress.Common.Zip
{
for (int i = 0; i < count; i++)
{
buffer[offset + i] = (byte) (counterOut[i] ^ buffer[offset + i]);
buffer[offset + i] = (byte)(counterOut[i] ^ buffer[offset + i]);
}
}
@@ -176,17 +164,17 @@ namespace SharpCompress.Common.Zip
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotImplementedException();
throw new NotSupportedException();
}
public override void SetLength(long value)
{
throw new NotImplementedException();
throw new NotSupportedException();
}
public override void Write(byte[] buffer, int offset, int count)
{
throw new NotImplementedException();
throw new NotSupportedException();
}
}
}

View File

@@ -0,0 +1,68 @@
using System;
using System.Text;
using SharpCompress.Crypto;
namespace SharpCompress.Common.Zip
{
internal class WinzipAesEncryptionData
{
private const int RFC2898_ITERATIONS = 1000;
private byte[] salt;
private WinzipAesKeySize keySize;
private byte[] passwordVerifyValue;
private string password;
private byte[] generatedVerifyValue;
internal WinzipAesEncryptionData(WinzipAesKeySize keySize, byte[] salt, byte[] passwordVerifyValue,
string password)
{
this.keySize = keySize;
this.salt = salt;
this.passwordVerifyValue = passwordVerifyValue;
this.password = password;
Initialize();
}
internal byte[] IvBytes { get; set; }
internal byte[] KeyBytes { get; set; }
private int KeySizeInBytes
{
get { return KeyLengthInBytes(keySize); }
}
internal static int KeyLengthInBytes(WinzipAesKeySize keySize)
{
switch (keySize)
{
case WinzipAesKeySize.KeySize128:
return 16;
case WinzipAesKeySize.KeySize192:
return 24;
case WinzipAesKeySize.KeySize256:
return 32;
}
throw new InvalidOperationException();
}
private void Initialize()
{
var utf8 = new UTF8Encoding(false);
var paramz = new PBKDF2(utf8.GetBytes(password), salt, RFC2898_ITERATIONS);
KeyBytes = paramz.GetBytes(KeySizeInBytes);
IvBytes = paramz.GetBytes(KeySizeInBytes);
generatedVerifyValue = paramz.GetBytes(2);
short verify = BitConverter.ToInt16(passwordVerifyValue, 0);
if (password != null)
{
short generated = BitConverter.ToInt16(generatedVerifyValue, 0);
if (verify != generated)
throw new InvalidFormatException("bad password");
}
}
}
}

View File

@@ -53,12 +53,12 @@ namespace SharpCompress.Common.Zip
}
}
public override uint Crc
public override long Crc
{
get { return filePart.Header.Crc; }
}
public override string FilePath
public override string Key
{
get { return filePart.Header.Name; }
}
@@ -112,9 +112,5 @@ namespace SharpCompress.Common.Zip
{
get { return filePart.AsEnumerable<FilePart>(); }
}
internal override void Close()
{
}
}
}

View File

@@ -89,7 +89,7 @@ namespace SharpCompress.Common.Zip
Header.CompressedSize > 0 ? Header.CompressedSize - 4 - props.Length : -1,
FlagUtility.HasFlag(Header.Flags, HeaderFlags.Bit1)
? -1
: (long) Header.UncompressedSize);
: (long)Header.UncompressedSize);
}
case ZipCompressionMethod.PPMd:
{
@@ -120,7 +120,7 @@ namespace SharpCompress.Common.Zip
{
throw new InvalidFormatException("Unexpected vendor ID for WinZip AES metadata");
}
Header.CompressionMethod = (ZipCompressionMethod) BitConverter.ToUInt16(data.DataBytes, 5);
Header.CompressionMethod = (ZipCompressionMethod)BitConverter.ToUInt16(data.DataBytes, 5);
return CreateDecompressionStream(stream);
}
default:
@@ -134,7 +134,7 @@ namespace SharpCompress.Common.Zip
{
if ((Header.CompressedSize == 0)
#if !PORTABLE && !NETFX_CORE
&& ((Header.PkwareTraditionalEncryptionData != null)
&& ((Header.PkwareTraditionalEncryptionData != null)
|| (Header.WinzipAesEncryptionData != null)))
#else
&& (Header.PkwareTraditionalEncryptionData != null))
@@ -160,8 +160,7 @@ namespace SharpCompress.Common.Zip
if (Header.WinzipAesEncryptionData != null)
{
//only read 10 less because the last ten are auth bytes
return new WinzipAesCryptoStream(plainStream, Header.WinzipAesEncryptionData,
Header.CompressedSize - 10, CryptoMode.Decrypt);
return new WinzipAesCryptoStream(plainStream, Header.WinzipAesEncryptionData, Header.CompressedSize - 10);
}
#endif
return plainStream;

View File

@@ -2,20 +2,13 @@
namespace SharpCompress.Common.Zip
{
public class ZipVolume : GenericVolume
public class ZipVolume : Volume
{
public ZipVolume(Stream stream, Options options)
: base(stream, options)
{
}
#if !PORTABLE && !NETFX_CORE
public ZipVolume(FileInfo fileInfo, Options options)
: base(fileInfo, options)
{
}
#endif
public string Comment { get; internal set; }
}
}

View File

@@ -5,6 +5,7 @@ namespace SharpCompress.Compressor.BZip2
public class BZip2Stream : Stream
{
private readonly Stream stream;
private bool isDisposed;
/// <summary>
/// Create a BZip2Stream
@@ -29,6 +30,11 @@ namespace SharpCompress.Compressor.BZip2
protected override void Dispose(bool disposing)
{
if (isDisposed)
{
return;
}
isDisposed = true;
if (disposing)
{
stream.Dispose();

View File

@@ -65,8 +65,8 @@ namespace SharpCompress.Compressor.BZip2
{
if (inUse[i])
{
seqToUnseq[nInUse] = (char) i;
unseqToSeq[i] = (char) nInUse;
seqToUnseq[nInUse] = (char)i;
unseqToSeq[i] = (char)nInUse;
nInUse++;
}
}
@@ -145,6 +145,7 @@ namespace SharpCompress.Compressor.BZip2
private int rTPos = 0;
private int j2;
private char z;
private bool isDisposed;
public CBZip2InputStream(Stream zStream, bool decompressConcatenated, bool leaveOpen)
{
@@ -157,6 +158,20 @@ namespace SharpCompress.Compressor.BZip2
SetupBlock();
}
protected override void Dispose(bool disposing)
{
if (isDisposed)
{
return;
}
isDisposed = true;
base.Dispose(disposing);
if (bsStream != null)
{
bsStream.Dispose();
}
}
internal static int[][] InitIntArray(int n1, int n2)
{
int[][] a = new int[n1][];
@@ -299,7 +314,7 @@ namespace SharpCompress.Compressor.BZip2
}
computedCombinedCRC = (computedCombinedCRC << 1)
| (int) (((uint) computedCombinedCRC) >> 31);
| (int)(((uint)computedCombinedCRC) >> 31);
computedCombinedCRC ^= computedBlockCRC;
}
@@ -372,7 +387,7 @@ namespace SharpCompress.Compressor.BZip2
int thech = '\0';
try
{
thech = (char) bsStream.ReadByte();
thech = (char)bsStream.ReadByte();
}
catch (IOException)
{
@@ -394,7 +409,7 @@ namespace SharpCompress.Compressor.BZip2
private char BsGetUChar()
{
return (char) BsR(8);
return (char)BsR(8);
}
private int BsGetint()
@@ -409,12 +424,12 @@ namespace SharpCompress.Compressor.BZip2
private int BsGetIntVS(int numBits)
{
return (int) BsR(numBits);
return (int)BsR(numBits);
}
private int BsGetInt32()
{
return (int) BsGetint();
return (int)BsGetint();
}
private void HbCreateDecodeTables(int[] limit, int[] basev,
@@ -501,7 +516,7 @@ namespace SharpCompress.Compressor.BZip2
{
if (BsR(1) == 1)
{
inUse[i*16 + j] = true;
inUse[i * 16 + j] = true;
}
}
}
@@ -520,7 +535,7 @@ namespace SharpCompress.Compressor.BZip2
{
j++;
}
selectorMtf[i] = (char) j;
selectorMtf[i] = (char)j;
}
/* Undo the MTF values for the selectors. */
@@ -563,7 +578,7 @@ namespace SharpCompress.Compressor.BZip2
curr--;
}
}
len[t][i] = (char) curr;
len[t][i] = (char)curr;
}
}
@@ -595,7 +610,7 @@ namespace SharpCompress.Compressor.BZip2
int i, j, nextSym, limitLast;
int EOB, groupNo, groupPos;
limitLast = BZip2Constants.baseBlockSize*blockSize100k;
limitLast = BZip2Constants.baseBlockSize * blockSize100k;
origPtr = BsGetIntVS(24);
RecvDecodingTables();
@@ -616,7 +631,7 @@ namespace SharpCompress.Compressor.BZip2
for (i = 0; i <= 255; i++)
{
yy[i] = (char) i;
yy[i] = (char)i;
}
last = -1;
@@ -643,7 +658,7 @@ namespace SharpCompress.Compressor.BZip2
char thech = '\0';
try
{
thech = (char) bsStream.ReadByte();
thech = (char)bsStream.ReadByte();
}
catch (IOException)
{
@@ -682,13 +697,13 @@ namespace SharpCompress.Compressor.BZip2
{
if (nextSym == BZip2Constants.RUNA)
{
s = s + (0 + 1)*N;
s = s + (0 + 1) * N;
}
else if (nextSym == BZip2Constants.RUNB)
{
s = s + (1 + 1)*N;
s = s + (1 + 1) * N;
}
N = N*2;
N = N * 2;
{
int zt, zn, zvec, zj;
if (groupPos == 0)
@@ -711,7 +726,7 @@ namespace SharpCompress.Compressor.BZip2
char thech = '\0';
try
{
thech = (char) bsStream.ReadByte();
thech = (char)bsStream.ReadByte();
}
catch (IOException)
{
@@ -808,7 +823,7 @@ namespace SharpCompress.Compressor.BZip2
char thech = '\0';
try
{
thech = (char) bsStream.ReadByte();
thech = (char)bsStream.ReadByte();
}
catch (IOException)
{
@@ -848,7 +863,7 @@ namespace SharpCompress.Compressor.BZip2
for (i = 0; i <= last; i++)
{
ch = (char) ll8[i];
ch = (char)ll8[i];
tt[cftab[ch]] = i;
cftab[ch]++;
}
@@ -889,7 +904,7 @@ namespace SharpCompress.Compressor.BZip2
}
}
rNToGo--;
ch2 ^= (int) ((rNToGo == 1) ? 1 : 0);
ch2 ^= (int)((rNToGo == 1) ? 1 : 0);
i2++;
currentChar = ch2;
@@ -950,7 +965,7 @@ namespace SharpCompress.Compressor.BZip2
}
}
rNToGo--;
z ^= (char) ((rNToGo == 1) ? 1 : 0);
z ^= (char)((rNToGo == 1) ? 1 : 0);
j2 = 0;
currentState = RAND_PART_C_STATE;
SetupRandPartC();
@@ -965,7 +980,7 @@ namespace SharpCompress.Compressor.BZip2
private void SetupRandPartC()
{
if (j2 < (int) z)
if (j2 < (int)z)
{
currentChar = ch2;
mCrc.UpdateCRC(ch2);
@@ -1009,7 +1024,7 @@ namespace SharpCompress.Compressor.BZip2
private void SetupNoRandPartC()
{
if (j2 < (int) z)
if (j2 < (int)z)
{
currentChar = ch2;
mCrc.UpdateCRC(ch2);
@@ -1039,7 +1054,7 @@ namespace SharpCompress.Compressor.BZip2
return;
}
int n = BZip2Constants.baseBlockSize*newSize100k;
int n = BZip2Constants.baseBlockSize * newSize100k;
ll8 = new char[n];
tt = new int[n];
}
@@ -1057,7 +1072,7 @@ namespace SharpCompress.Compressor.BZip2
c = ReadByte();
if (c == -1)
break;
buffer[k + offset] = (byte) c;
buffer[k + offset] = (byte)c;
}
return k;
}

View File

@@ -670,6 +670,7 @@ namespace SharpCompress.Compressor.Deflate
send_bits((tree[c2] & 0xffff), (tree[c2 + 1] & 0xffff));
}
#pragma warning disable 675 // workaround for Visual Studio 2015 compiler bug: https://github.com/dotnet/roslyn/issues/4027
internal void send_bits(int value, int length)
{
int len = length;
@@ -680,7 +681,7 @@ namespace SharpCompress.Compressor.Deflate
//int val = value;
// bi_buf |= (val << bi_valid);
bi_buf |= (short) ((value << bi_valid) & 0xffff);
bi_buf |= (short)((value << bi_valid) & 0xffff);
//put_short(bi_buf);
pending[pendingCount++] = (byte) bi_buf;
pending[pendingCount++] = (byte) (bi_buf >> 8);
@@ -692,11 +693,12 @@ namespace SharpCompress.Compressor.Deflate
else
{
// bi_buf |= (value) << bi_valid;
bi_buf |= (short) ((value << bi_valid) & 0xffff);
bi_buf |= (short)((value << bi_valid) & 0xffff);
bi_valid += len;
}
}
}
#pragma warning restore 675
// Send one empty static block to give enough lookahead for inflate.
// This takes 10 bits, of which 7 may remain in the bit buffer.

View File

@@ -174,7 +174,7 @@ namespace SharpCompress.Compressor.Deflate
/// </summary>
public override long Length
{
get { throw new NotImplementedException(); }
get { throw new NotSupportedException(); }
}
/// <summary>
@@ -198,7 +198,7 @@ namespace SharpCompress.Compressor.Deflate
return _baseStream._z.TotalBytesIn;
return 0;
}
set { throw new NotImplementedException(); }
set { throw new NotSupportedException(); }
}
/// <summary>
@@ -275,7 +275,7 @@ namespace SharpCompress.Compressor.Deflate
/// <returns>irrelevant!</returns>
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotImplementedException();
throw new NotSupportedException();
}
/// <summary>
@@ -284,7 +284,7 @@ namespace SharpCompress.Compressor.Deflate
/// <param name="value">this is irrelevant, since it will always throw!</param>
public override void SetLength(long value)
{
throw new NotImplementedException();
throw new NotSupportedException();
}
/// <summary>

View File

@@ -163,7 +163,7 @@ namespace SharpCompress.Compressor.Deflate
/// </summary>
public override long Length
{
get { throw new NotImplementedException(); }
get { throw new NotSupportedException(); }
}
/// <summary>
@@ -188,7 +188,7 @@ namespace SharpCompress.Compressor.Deflate
return 0;
}
set { throw new NotImplementedException(); }
set { throw new NotSupportedException(); }
}
/// <summary>
@@ -286,7 +286,7 @@ namespace SharpCompress.Compressor.Deflate
/// <returns>irrelevant!</returns>
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotImplementedException();
throw new NotSupportedException();
}
/// <summary>
@@ -295,7 +295,7 @@ namespace SharpCompress.Compressor.Deflate
/// <param name="value">irrelevant; this method will always throw!</param>
public override void SetLength(long value)
{
throw new NotImplementedException();
throw new NotSupportedException();
}
/// <summary>

File diff suppressed because it is too large Load Diff

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