12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057 |
- /* This file is part of SevenZipSharp.
- SevenZipSharp is free software: you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- SevenZipSharp is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Lesser General Public License for more details.
- You should have received a copy of the GNU Lesser General Public License
- along with SevenZipSharp. If not, see <http://www.gnu.org/licenses/>.
- */
- using System;
- using System.Collections.Generic;
- using System.Globalization;
- using System.IO;
- #if DOTNET20
- using System.Threading;
- #else
- using System.Linq;
- #endif
- using System.Runtime.InteropServices;
- #if !WINCE
- using System.Security.Permissions;
- #endif
- using SevenZip.Sdk;
- using SevenZip.Sdk.Compression.Lzma;
- #if MONO
- using SevenZip.Mono.COM;
- #endif
- namespace SevenZip
- {
- #if COMPRESS
- /// <summary>
- /// Class for packing files into 7-zip archives
- /// </summary>
- public sealed partial class SevenZipCompressor
- #if UNMANAGED
- : SevenZipBase
- #endif
- {
- #if UNMANAGED
- #region Fields
- private bool _compressingFilesOnDisk;
- /// <summary>
- /// Gets or sets the archiving compression level.
- /// </summary>
- public CompressionLevel CompressionLevel { get; set; }
- private OutArchiveFormat _archiveFormat = OutArchiveFormat.SevenZip;
- private CompressionMethod _compressionMethod = CompressionMethod.Default;
- /// <summary>
- /// Gets the custom compression parameters - for advanced users only.
- /// </summary>
- public Dictionary<string, string> CustomParameters { get; private set; }
- private int _volumeSize;
- private string _archiveName;
- /// <summary>
- /// Gets or sets the value indicating whether to include empty directories to archives. Default is true.
- /// </summary>
- public bool IncludeEmptyDirectories { get; set; }
- /// <summary>
- /// Gets or sets the value indicating whether to preserve the directory root for CompressDirectory.
- /// </summary>
- public bool PreserveDirectoryRoot { get; set; }
- /// <summary>
- /// Gets or sets the value indicating whether to preserve the directory structure.
- /// </summary>
- public bool DirectoryStructure { get; set; }
- private bool _directoryCompress;
- /// <summary>
- /// Gets or sets the compression mode.
- /// </summary>
- public CompressionMode CompressionMode { get; set; }
- private UpdateData _updateData;
- private uint _oldFilesCount;
- /// <summary>
- /// Gets or sets the value indicating whether to encrypt 7-Zip archive headers.
- /// </summary>
- public bool EncryptHeaders { get; set; }
- /// <summary>
- /// 获取或设置该值指示是否将压缩文件只开放式写作。
- /// Gets or sets the value indicating whether to compress files only open for writing.
- /// </summary>
- public bool ScanOnlyWritable { get; set; }
- /// <summary>
- /// Gets or sets the encryption method for zip archives.
- /// </summary>
- public ZipEncryptionMethod ZipEncryptionMethod { get; set; }
- /// <summary>
- /// Gets or sets the temporary folder path.
- /// </summary>
- public string TempFolderPath { get; set; }
- /// <summary>
- /// Gets or sets the default archive item name used when an item to be compressed has no name,
- /// for example, when you compress a MemoryStream instance.
- /// </summary>
- public string DefaultItemName { get; set; }
- /// <summary>
- /// Gets or sets the value indicating whether to compress as fast as possible, without calling events.
- /// </summary>
- public bool FastCompression { get; set; }
- #endregion
- #endif
- private static int _lzmaDictionarySize = 1 << 22;
- #if UNMANAGED
- private void CommonInit()
- {
- DirectoryStructure = true;
- IncludeEmptyDirectories = true;
- CompressionLevel = CompressionLevel.Normal;
- CompressionMode = CompressionMode.Create;
- ZipEncryptionMethod = ZipEncryptionMethod.ZipCrypto;
- CustomParameters = new Dictionary<string, string>();
- _updateData = new UpdateData();
- DefaultItemName = "default";
- }
- /// <summary>
- /// Initializes a new instance of the SevenZipCompressor class.
- /// </summary>
- public SevenZipCompressor()
- {
- try
- {
- #if !WINCE
- TempFolderPath = Path.GetTempPath();
- //TempFolderPath = Environment.GetEnvironmentVariable("TEMP", EnvironmentVariableTarget.User);
- #else
- TempFolderPath = "Temp";
- #endif
- }
- catch (System.Security.SecurityException) // Registry access is not allowed, etc.
- {
- /*throw new SevenZipCompressionFailedException(
- "Attempted to get TEMP environment variable but registry access was not allowed (security settings on your machine). You must call SevenZipCompressor constructor overload with your own temporary path.");
- */
- throw new SevenZipCompressionFailedException(
- "Path.GetTempPath() threw a System.Security.SecurityException. You must call SevenZipCompressor constructor overload with your own temporary path.");
- }
- CommonInit();
- }
- /// <summary>
- /// Initializes a new instance of the SevenZipCompressor class.
- /// </summary>
- /// <param name="temporaryPath">Your own temporary path (default is set in the parameterless constructor overload.)</param>
- public SevenZipCompressor(string temporaryPath)
- {
- TempFolderPath = temporaryPath;
- if (!Directory.Exists(TempFolderPath))
- {
- try
- {
- Directory.CreateDirectory(TempFolderPath);
- }
- catch (Exception)
- {
- throw new SevenZipCompressionFailedException("The specified temporary path is invalid.");
- }
- }
- CommonInit();
- }
- #endif
- /// <summary>
- /// Checks if the specified stream supports compression.
- /// </summary>
- /// <param name="stream">The stream to check.</param>
- private static void ValidateStream(Stream stream)
- {
- if (!stream.CanWrite || !stream.CanSeek)
- {
- throw new ArgumentException("The specified stream can not seek or is not writable.", "stream");
- }
- }
- #if UNMANAGED
- #region Private functions
- private IOutArchive MakeOutArchive(IInStream inArchiveStream)
- {
- IInArchive inArchive = SevenZipLibraryManager.InArchive(
- Formats.InForOutFormats[_archiveFormat], this);
- using (ArchiveOpenCallback openCallback = GetArchiveOpenCallback())
- {
- ulong checkPos = 1 << 15;
- if (inArchive.Open(inArchiveStream, ref checkPos, openCallback) != (int) OperationResult.Ok)
- {
- if (
- !ThrowException(null, new SevenZipArchiveException("Can not update the archive: Open() failed.")))
- {
- return null;
- }
- }
- _oldFilesCount = inArchive.GetNumberOfItems();
- }
- return (IOutArchive) inArchive;
- }
- /// <summary>
- /// Guaranties the correct work of the SetCompressionProperties function
- /// </summary>
- /// <param name="method">The compression method to check</param>
- /// <returns>The value indicating whether the specified method is valid for the current ArchiveFormat</returns>
- private bool MethodIsValid(CompressionMethod method)
- {
- if (method == CompressionMethod.Default)
- {
- return true;
- }
- switch (_archiveFormat)
- {
- case OutArchiveFormat.Zip:
- return method != CompressionMethod.Ppmd;
- case OutArchiveFormat.GZip:
- return method == CompressionMethod.Deflate;
- case OutArchiveFormat.BZip2:
- return method == CompressionMethod.BZip2;
- case OutArchiveFormat.SevenZip:
- return method != CompressionMethod.Deflate && method != CompressionMethod.Deflate64;
- case OutArchiveFormat.Tar:
- return method == CompressionMethod.Copy;
- default:
- return true;
- }
- }
- private bool SwitchIsInCustomParameters(string name)
- {
- return CustomParameters.ContainsKey(name);
- }
- /// <summary>
- /// Sets the compression properties
- /// </summary>
- private void SetCompressionProperties()
- {
- switch (_archiveFormat)
- {
- case OutArchiveFormat.Tar:
- break;
- default:
- ISetProperties setter = CompressionMode == CompressionMode.Create && _updateData.FileNamesToModify == null
- ? (ISetProperties) SevenZipLibraryManager.OutArchive(
- _archiveFormat, this)
- : (ISetProperties) SevenZipLibraryManager.InArchive(
- Formats.InForOutFormats[_archiveFormat], this);
- if (setter == null)
- {
- if (!ThrowException(null,
- new CompressionFailedException(
- "The specified archive format is unsupported.")))
- {
- return;
- }
- }
- if (_volumeSize > 0 && ArchiveFormat != OutArchiveFormat.SevenZip)
- {
- throw new CompressionFailedException("Unfortunately, the creation of multivolume non-7Zip archives is not implemented. It will be one day, though.");
- }
- if (CustomParameters.ContainsKey("x") || CustomParameters.ContainsKey("m"))
- {
- if (
- !ThrowException(null,
- new CompressionFailedException(
- "The specified compression parameters are invalid.")))
- {
- return;
- }
- }
- var names = new List<IntPtr>(2 + CustomParameters.Count);
- var values = new List<PropVariant>(2 + CustomParameters.Count);
- #if !WINCE
- var sp = new SecurityPermission(SecurityPermissionFlag.UnmanagedCode);
- sp.Demand();
- #endif
- #region Initialize compression properties
- if (_compressionMethod == CompressionMethod.Default)
- {
- names.Add(Marshal.StringToBSTR("x"));
- values.Add(new PropVariant());
- foreach (var pair in CustomParameters)
- {
- names.Add(Marshal.StringToBSTR(pair.Key));
- var pv = new PropVariant();
- if (pair.Key == "fb" || pair.Key == "pass" || pair.Key == "d")
- {
- pv.VarType = VarEnum.VT_UI4;
- pv.UInt32Value = Convert.ToUInt32(pair.Value, CultureInfo.InvariantCulture);
- }
- else
- {
- pv.VarType = VarEnum.VT_BSTR;
- pv.Value = Marshal.StringToBSTR(pair.Value);
- }
- values.Add(pv);
- }
- }
- else
- {
- names.Add(Marshal.StringToBSTR("x"));
- names.Add(_archiveFormat == OutArchiveFormat.Zip
- ? Marshal.StringToBSTR("m")
- : Marshal.StringToBSTR("0"));
- values.Add(new PropVariant());
- var pv = new PropVariant
- {
- VarType = VarEnum.VT_BSTR,
- Value = Marshal.StringToBSTR(Formats.MethodNames[_compressionMethod])
- };
- values.Add(pv);
- foreach (var pair in CustomParameters)
- {
- names.Add(Marshal.StringToBSTR(pair.Key));
- pv = new PropVariant();
- if (pair.Key == "fb" || pair.Key == "pass" || pair.Key == "d")
- {
- pv.VarType = VarEnum.VT_UI4;
- pv.UInt32Value = Convert.ToUInt32(pair.Value, CultureInfo.InvariantCulture);
- }
- else
- {
- pv.VarType = VarEnum.VT_BSTR;
- pv.Value = Marshal.StringToBSTR(pair.Value);
- }
- values.Add(pv);
- }
- }
- #endregion
- #region Set compression level
- PropVariant clpv = values[0];
- clpv.VarType = VarEnum.VT_UI4;
- switch (CompressionLevel)
- {
- case CompressionLevel.None:
- clpv.UInt32Value = 0;
- break;
- case CompressionLevel.Fast:
- clpv.UInt32Value = 1;
- break;
- case CompressionLevel.Low:
- clpv.UInt32Value = 3;
- break;
- case CompressionLevel.Normal:
- clpv.UInt32Value = 5;
- break;
- case CompressionLevel.High:
- clpv.UInt32Value = 7;
- break;
- case CompressionLevel.Ultra:
- clpv.UInt32Value = 9;
- break;
- }
- values[0] = clpv;
- #endregion
- #region Encrypt headers
- if (EncryptHeaders && _archiveFormat == OutArchiveFormat.SevenZip &&
- !SwitchIsInCustomParameters("he"))
- {
- names.Add(Marshal.StringToBSTR("he"));
- var tmp = new PropVariant {VarType = VarEnum.VT_BSTR, Value = Marshal.StringToBSTR("on")};
- values.Add(tmp);
- }
- #endregion
- #region Zip Encryption
- if (_archiveFormat == OutArchiveFormat.Zip && ZipEncryptionMethod != ZipEncryptionMethod.ZipCrypto &&
- !SwitchIsInCustomParameters("em"))
- {
- names.Add(Marshal.StringToBSTR("em"));
- var tmp = new PropVariant
- {
- VarType = VarEnum.VT_BSTR,
- Value = Marshal.StringToBSTR(
- #if !WINCE
- Enum.GetName(typeof (ZipEncryptionMethod), ZipEncryptionMethod))
- #else
- OpenNETCF.Enum2.GetName(typeof (ZipEncryptionMethod), ZipEncryptionMethod))
- #endif
- };
- values.Add(tmp);
- }
- #endregion
- var namesHandle = GCHandle.Alloc(names.ToArray(), GCHandleType.Pinned);
- var valuesHandle = GCHandle.Alloc(values.ToArray(), GCHandleType.Pinned);
- try
- {
- if (setter != null) //ReSharper
- setter.SetProperties(namesHandle.AddrOfPinnedObject(), valuesHandle.AddrOfPinnedObject(),
- names.Count);
- }
- finally
- {
- namesHandle.Free();
- valuesHandle.Free();
- }
- break;
- }
- }
- /// <summary>
- /// Finds the common root of file names
- /// </summary>
- /// <param name="files">Array of file names</param>
- /// <returns>Common root</returns>
- private static int CommonRoot(ICollection<string> files)
- {
- var splittedFileNames = new List<string[]>(files.Count);
- #if CS4
- splittedFileNames.AddRange(files.Select(fn => fn.Split(Path.DirectorySeparatorChar)));
- #else
- foreach (string fn in files)
- {
- splittedFileNames.Add(fn.Split(Path.DirectorySeparatorChar));
- }
- #endif
- int minSplitLength = splittedFileNames[0].Length - 1;
- if (files.Count > 1)
- {
- for (int i = 1; i < files.Count; i++)
- {
- if (minSplitLength > splittedFileNames[i].Length)
- {
- minSplitLength = splittedFileNames[i].Length;
- }
- }
- }
- string res = "";
- for (int i = 0; i < minSplitLength; i++)
- {
- bool common = true;
- for (int j = 1; j < files.Count; j++)
- {
- if (!(common &= splittedFileNames[j - 1][i] == splittedFileNames[j][i]))
- {
- break;
- }
- }
- if (common)
- {
- res += splittedFileNames[0][i] + Path.DirectorySeparatorChar;
- }
- else
- {
- break;
- }
- }
- return res.Length;
- }
- /// <summary>
- /// Validates the common root
- /// </summary>
- /// <param name="commonRootLength">The length of the common root of the file names.</param>
- /// <param name="files">Array of file names</param>
- private static void CheckCommonRoot(string[] files, ref int commonRootLength)
- {
- string commonRoot;
- try
- {
- commonRoot = files[0].Substring(0, commonRootLength);
- }
- catch (ArgumentOutOfRangeException)
- {
- throw new SevenZipInvalidFileNamesException("invalid common root.");
- }
- if (commonRoot.EndsWith(new string(Path.DirectorySeparatorChar, 1), StringComparison.CurrentCulture))
- {
- commonRoot = commonRoot.Substring(0, commonRootLength - 1);
- commonRootLength--;
- }
- #if CS4
- if (files.Any(fn => !fn.StartsWith(commonRoot, StringComparison.CurrentCulture)))
- {
- throw new SevenZipInvalidFileNamesException("invalid common root.");
- }
- #else
- foreach (string fn in files)
- {
- if (!fn.StartsWith(commonRoot, StringComparison.CurrentCulture))
- {
- throw new SevenZipInvalidFileNamesException("invalid common root.");
- }
- }
- #endif
- }
- /// <summary>
- /// Ensures that directory directory is not empty
- /// </summary>
- /// <param name="directory">Directory name</param>
- /// <returns>False if is not empty</returns>
- private static bool RecursiveDirectoryEmptyCheck(string directory)
- {
- var di = new DirectoryInfo(directory);
- if (di.GetFiles().Length > 0)
- {
- return false;
- }
- bool empty = true;
- foreach (DirectoryInfo cdi in di.GetDirectories())
- {
- empty &= RecursiveDirectoryEmptyCheck(cdi.FullName);
- if (!empty)
- {
- return false;
- }
- }
- return true;
- }
- /// <summary>
- /// Makes special FileInfo array for the archive file table.
- /// </summary>
- /// <param name="files">Array of files to pack.</param>
- /// <param name="commonRootLength">The length of the common root of file names</param>
- /// <param name="directoryCompress">The value indicating whether to produce the array for files in a particular directory or just for an array of files.</param>
- /// <param name="directoryStructure">Preserve directory structure.</param>
- /// <returns>Special FileInfo array for the archive file table.</returns>
- private static FileInfo[] ProduceFileInfoArray(
- string[] files, int commonRootLength,
- bool directoryCompress, bool directoryStructure)
- {
- var fis = new List<FileInfo>(files.Length);
- string commonRoot = files[0].Substring(0, commonRootLength);
- if (directoryCompress)
- {
- #if CS4
- fis.AddRange(files.Select(fn => new FileInfo(fn)));
- #else
- foreach (string fn in files)
- {
- fis.Add(new FileInfo(fn));
- }
- #endif
- }
- else
- {
- if (!directoryStructure)
- {
- #if CS4
- fis.AddRange(from fn in files where !Directory.Exists(fn) select new FileInfo(fn));
- #else
- foreach (string fn in files)
- {
- if (!Directory.Exists(fn))
- {
- fis.Add(new FileInfo(fn));
- }
- }
- #endif
- }
- else
- {
- var fns = new List<string>(files.Length);
- CheckCommonRoot(files, ref commonRootLength);
- if (commonRootLength > 0)
- {
- commonRootLength++;
- foreach (string f in files)
- {
- string[] splittedAfn = f.Substring(commonRootLength).Split(Path.DirectorySeparatorChar);
- string cfn = commonRoot;
- foreach (string t in splittedAfn) {
- cfn += Path.DirectorySeparatorChar + t;
- if (!fns.Contains(cfn))
- {
- fis.Add(new FileInfo(cfn));
- fns.Add(cfn);
- }
- }
- }
- }
- else
- {
- foreach (string f in files)
- {
- string[] splittedAfn = f.Substring(commonRootLength).Split(Path.DirectorySeparatorChar);
- string cfn = splittedAfn[0];
- for (int i = 1; i < splittedAfn.Length; i++)
- {
- cfn += Path.DirectorySeparatorChar + splittedAfn[i];
- if (!fns.Contains(cfn))
- {
- fis.Add(new FileInfo(cfn));
- fns.Add(cfn);
- }
- }
- }
- }
- }
- }
- return fis.ToArray();
- }
- /// <summary>
- /// Recursive function for adding files in directory
- /// </summary>
- /// <param name="directory">Directory directory</param>
- /// <param name="files">List of files</param>
- /// <param name="searchPattern">Search string, such as "*.txt"</param>
- private void AddFilesFromDirectory(string directory, ICollection<string> files, string searchPattern)
- {
- var di = new DirectoryInfo(directory);
- foreach (FileInfo fi in di.GetFiles(searchPattern))
- {
- if (!ScanOnlyWritable)
- {
- files.Add(fi.FullName);
- }
- else
- {
- try
- {
- using (fi.OpenWrite()) {}
- files.Add(fi.FullName);
- }
- catch (IOException) {}
- }
- }
- foreach (DirectoryInfo cdi in di.GetDirectories())
- {
- if (IncludeEmptyDirectories)
- {
- files.Add(cdi.FullName);
- }
- AddFilesFromDirectory(cdi.FullName, files, searchPattern);
- }
- }
- #endregion
- #region GetArchiveUpdateCallback overloads
- /// <summary>
- /// Performs the common ArchiveUpdateCallback initialization.
- /// </summary>
- /// <param name="auc">The ArchiveUpdateCallback instance to initialize.</param>
- private void CommonUpdateCallbackInit(ArchiveUpdateCallback auc)
- {
- auc.FileCompressionStarted += FileCompressionStartedEventProxy;
- auc.Compressing += CompressingEventProxy;
- auc.FileCompressionFinished += FileCompressionFinishedEventProxy;
- auc.DefaultItemName = DefaultItemName;
- auc.FastCompression = FastCompression;
- }
- private float GetDictionarySize()
- {
- float dictionarySize = 0.001f;
- switch (_compressionMethod)
- {
- case CompressionMethod.Default:
- case CompressionMethod.Lzma:
- case CompressionMethod.Lzma2:
- switch (CompressionLevel)
- {
- case CompressionLevel.None:
- dictionarySize = 0.001f;
- break;
- case CompressionLevel.Fast:
- dictionarySize = 1.0f / 16 * 7.5f + 4;
- break;
- case CompressionLevel.Low:
- dictionarySize = 7.5f * 11.5f + 4;
- break;
- case CompressionLevel.Normal:
- dictionarySize = 16 * 11.5f + 4;
- break;
- case CompressionLevel.High:
- dictionarySize = 32 * 11.5f + 4;
- break;
- case CompressionLevel.Ultra:
- dictionarySize = 64 * 11.5f + 4;
- break;
- }
- break;
- case CompressionMethod.BZip2:
- switch (CompressionLevel)
- {
- case CompressionLevel.None:
- dictionarySize = 0;
- break;
- case CompressionLevel.Fast:
- dictionarySize = 0.095f;
- break;
- case CompressionLevel.Low:
- dictionarySize = 0.477f;
- break;
- case CompressionLevel.Normal:
- case CompressionLevel.High:
- case CompressionLevel.Ultra:
- dictionarySize = 0.858f;
- break;
- }
- break;
- case CompressionMethod.Deflate:
- case CompressionMethod.Deflate64:
- dictionarySize = 32;
- break;
- case CompressionMethod.Ppmd:
- dictionarySize = 16;
- break;
- }
- return dictionarySize;
- }
- /// <summary>
- /// Produces a new instance of ArchiveUpdateCallback class.
- /// </summary>
- /// <param name="files">Array of FileInfo - files to pack</param>
- /// <param name="rootLength">Length of the common root of file names</param>
- /// <param name="password">The archive password</param>
- /// <returns></returns>
- private ArchiveUpdateCallback GetArchiveUpdateCallback(
- FileInfo[] files, int rootLength, string password)
- {
- SetCompressionProperties();
- var auc = (String.IsNullOrEmpty(password))
- ? new ArchiveUpdateCallback(files, rootLength, this, GetUpdateData(), DirectoryStructure)
- { DictionarySize = GetDictionarySize() }
- : new ArchiveUpdateCallback(files, rootLength, password, this, GetUpdateData(), DirectoryStructure)
- { DictionarySize = GetDictionarySize() };
- CommonUpdateCallbackInit(auc);
- return auc;
- }
- /// <summary>
- /// Produces a new instance of ArchiveUpdateCallback class.
- /// </summary>
- /// <param name="inStream">The archive input stream.</param>
- /// <param name="password">The archive password.</param>
- /// <returns></returns>
- private ArchiveUpdateCallback GetArchiveUpdateCallback(Stream inStream, string password)
- {
- SetCompressionProperties();
- var auc = (String.IsNullOrEmpty(password))
- ? new ArchiveUpdateCallback(inStream, this, GetUpdateData(), DirectoryStructure)
- { DictionarySize = GetDictionarySize() }
- : new ArchiveUpdateCallback(inStream, password, this, GetUpdateData(), DirectoryStructure)
- { DictionarySize = GetDictionarySize() };
- CommonUpdateCallbackInit(auc);
- return auc;
- }
- /// <summary>
- /// Produces a new instance of ArchiveUpdateCallback class.
- /// </summary>
- /// <param name="streamDict">Dictionary<name of the archive entry, stream>.</param>
- /// <param name="password">The archive password</param>
- /// <returns></returns>
- private ArchiveUpdateCallback GetArchiveUpdateCallback(
- Dictionary<string, Stream> streamDict, string password)
- {
- SetCompressionProperties();
- var auc = (String.IsNullOrEmpty(password))
- ? new ArchiveUpdateCallback(streamDict, this, GetUpdateData(), DirectoryStructure)
- { DictionarySize = GetDictionarySize() }
- : new ArchiveUpdateCallback(streamDict, password, this, GetUpdateData(), DirectoryStructure)
- { DictionarySize = GetDictionarySize() };
- CommonUpdateCallbackInit(auc);
- return auc;
- }
- #endregion
- #region Service "Get" functions
- private void FreeCompressionCallback(ArchiveUpdateCallback callback)
- {
- callback.FileCompressionStarted -= FileCompressionStartedEventProxy;
- callback.Compressing -= CompressingEventProxy;
- callback.FileCompressionFinished -= FileCompressionFinishedEventProxy;
- }
- private string GetTempArchiveFileName(string archiveName)
- {
- return Path.Combine(TempFolderPath, Path.GetFileName(archiveName) + ".~");
- }
- private FileStream GetArchiveFileStream(string archiveName)
- {
- if ((CompressionMode != CompressionMode.Create || _updateData.FileNamesToModify != null) && !File.Exists(archiveName))
- {
- if (
- !ThrowException(null, new CompressionFailedException("file \"" + archiveName + "\" does not exist.")))
- {
- return null;
- }
- }
- return _volumeSize == 0
- ? CompressionMode == CompressionMode.Create && _updateData.FileNamesToModify == null
- ? File.Create(archiveName)
- : File.Create(GetTempArchiveFileName(archiveName))
- : null;
- }
- private void FinalizeUpdate()
- {
- if (_volumeSize == 0 && (CompressionMode != CompressionMode.Create || _updateData.FileNamesToModify != null))
- {
- File.Move(GetTempArchiveFileName(_archiveName), _archiveName);
- }
- }
- private UpdateData GetUpdateData()
- {
- if (_updateData.FileNamesToModify == null)
- {
- var updateData = new UpdateData {Mode = (InternalCompressionMode) ((int) CompressionMode)};
- switch (CompressionMode)
- {
- case CompressionMode.Create:
- updateData.FilesCount = UInt32.MaxValue;
- break;
- case CompressionMode.Append:
- updateData.FilesCount = _oldFilesCount;
- break;
- }
- return updateData;
- }
- return _updateData;
- }
- private ISequentialOutStream GetOutStream(Stream outStream)
- {
- if (!_compressingFilesOnDisk)
- {
- return new OutStreamWrapper(outStream, false);
- }
- if (_volumeSize == 0 || CompressionMode != CompressionMode.Create || _updateData.FileNamesToModify != null)
- {
- return new OutStreamWrapper(outStream, true);
- }
- return new OutMultiStreamWrapper(_archiveName, _volumeSize);
- }
- private IInStream GetInStream()
- {
- return File.Exists(_archiveName) &&
- (CompressionMode != CompressionMode.Create && _compressingFilesOnDisk || _updateData.FileNamesToModify != null)
- ?
- new InStreamWrapper(
- new FileStream(_archiveName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite),
- true)
- : null;
- }
- private ArchiveOpenCallback GetArchiveOpenCallback()
- {
- return String.IsNullOrEmpty(Password)
- ?
- new ArchiveOpenCallback(_archiveName)
- :
- new ArchiveOpenCallback(_archiveName, Password);
- }
- #endregion
- #region Core public Members
- #region Events
- /// <summary>
- /// 当下一个文件打包时发生
- /// Occurs when the next file is going to be packed.
- /// </summary>
- /// <remarks>当7-zip引擎请求下一个文件的输入流打包时发生Occurs when 7-zip engine requests for an input stream for the next file to pack it</remarks>
- public event EventHandler<FileNameEventArgs> FileCompressionStarted;
- /// <summary>
- /// 压缩当前文件时发生。
- /// Occurs when the current file was compressed.
- /// </summary>
- public event EventHandler<EventArgs> FileCompressionFinished;
- /// <summary>
- /// 数据压缩时发生
- /// Occurs when data are being compressed
- /// </summary>
- /// <remarks>Use this event for accurate progress handling and various ProgressBar.StepBy(e.PercentDelta) routines</remarks>
- public event EventHandler<ProgressEventArgs> Compressing;
- /// <summary>
- /// 当所有文件信息确定并且SevenZipCompressor即将开始压缩它们时发生。
- /// Occurs when all files information was determined and SevenZipCompressor is about to start to compress them.
- /// </summary>
- /// <remarks>The incoming int value indicates the number of scanned files.</remarks>
- public event EventHandler<IntEventArgs> FilesFound;
- /// <summary>
- /// 压缩过程完成时发生
- /// Occurs when the compression procedure is finished
- /// </summary>
- public event EventHandler<EventArgs> CompressionFinished;
- #region Event proxies
- /// <summary>
- /// Event proxy for FileCompressionStarted.
- /// </summary>
- /// <param name="sender">The sender of the event.</param>
- /// <param name="e">The event arguments.</param>
- private void FileCompressionStartedEventProxy(object sender, FileNameEventArgs e)
- {
- OnEvent(FileCompressionStarted, e, false);
- }
- /// <summary>
- /// Event proxy for FileCompressionFinished.
- /// </summary>
- /// <param name="sender">The sender of the event.</param>
- /// <param name="e">The event arguments.</param>
- private void FileCompressionFinishedEventProxy(object sender, EventArgs e)
- {
- OnEvent(FileCompressionFinished, e, false);
- }
- /// <summary>
- /// Event proxy for Compressing.
- /// </summary>
- /// <param name="sender">The sender of the event.</param>
- /// <param name="e">The event arguments.</param>
- private void CompressingEventProxy(object sender, ProgressEventArgs e)
- {
- OnEvent(Compressing, e, false);
- }
- /// <summary>
- /// Event proxy for FilesFound.
- /// </summary>
- /// <param name="sender">The sender of the event.</param>
- /// <param name="e">The event arguments.</param>
- private void FilesFoundEventProxy(object sender, IntEventArgs e)
- {
- OnEvent(FilesFound, e, false);
- }
- #endregion
- #endregion
- #region Properties
- /// <summary>
- /// Gets or sets the archive format
- /// </summary>
- public OutArchiveFormat ArchiveFormat
- {
- get
- {
- return _archiveFormat;
- }
- set
- {
- _archiveFormat = value;
- if (!MethodIsValid(_compressionMethod))
- {
- _compressionMethod = CompressionMethod.Default;
- }
- }
- }
- /// <summary>
- /// Gets or sets the compression method
- /// </summary>
- public CompressionMethod CompressionMethod
- {
- get
- {
- return _compressionMethod;
- }
- set
- {
- _compressionMethod = !MethodIsValid(value) ? CompressionMethod.Default : value;
- }
- }
- /// <summary>
- /// 获取或设置(0表示无卷)在归档量的字节大小。
- /// Gets or sets the size in bytes of an archive volume (0 for no volumes).
- /// </summary>
- public int VolumeSize
- {
- get
- {
- return _volumeSize;
- }
- set
- {
- _volumeSize = value > 0 ? value : 0;
- }
- }
- #endregion
- #region CompressFiles overloads
- /// <summary>
- /// 包文件到存档。
- /// Packs files into the archive.
- /// </summary>
- /// <param name="fileFullNames">Array of file names to pack.</param>
- /// <param name="archiveName">The archive file name.</param>
- public void CompressFiles(
- string archiveName, params string[] fileFullNames)
- {
- CompressFilesEncrypted(archiveName, "", fileFullNames);
- }
- /// <summary>
- /// Packs files into the archive.
- /// </summary>
- /// <param name="fileFullNames">Array of file names to pack.</param>
- /// <param name="archiveStream">The archive output stream.
- /// Use CompressFiles(string archiveName ... ) overloads for archiving to disk.</param>
- public void CompressFiles(
- Stream archiveStream, params string[] fileFullNames)
- {
- CompressFilesEncrypted(archiveStream, "", fileFullNames);
- }
- /// <summary>
- /// Packs files into the archive.
- /// </summary>
- /// <param name="fileFullNames">Array of file names to pack.</param>
- /// <param name="commonRootLength">The length of the common root of the file names.</param>
- /// <param name="archiveName">The archive file name.</param>
- public void CompressFiles(
- string archiveName, int commonRootLength, params string[] fileFullNames)
- {
- CompressFilesEncrypted(archiveName, commonRootLength, "", fileFullNames);
- }
- /// <summary>
- /// Packs files into the archive.
- /// </summary>
- /// <param name="fileFullNames">Array of file names to pack.</param>
- /// <param name="commonRootLength">The length of the common root of the file names.</param>
- /// <param name="archiveStream">The archive output stream.
- /// Use CompressFiles(string archiveName, ... ) overloads for archiving to disk.</param>
- public void CompressFiles(
- Stream archiveStream, int commonRootLength, params string[] fileFullNames)
- {
- CompressFilesEncrypted(archiveStream, commonRootLength, "", fileFullNames);
- }
- /// <summary>
- /// Packs files into the archive.
- /// </summary>
- /// <param name="fileFullNames">Array of file names to pack.</param>
- /// <param name="archiveName">The archive file name.</param>
- /// <param name="password">The archive password.</param>
- public void CompressFilesEncrypted(
- string archiveName, string password, params string[] fileFullNames)
- {
- CompressFilesEncrypted(archiveName, CommonRoot(fileFullNames), password, fileFullNames);
- }
- /// <summary>
- /// Packs files into the archive.
- /// </summary>
- /// <param name="fileFullNames">Array of file names to pack.</param>
- /// <param name="archiveStream">The archive output stream.
- /// Use CompressFiles( ... string archiveName ... ) overloads for archiving to disk.</param>
- /// <param name="password">The archive password.</param>
- public void CompressFilesEncrypted(
- Stream archiveStream, string password, params string[] fileFullNames)
- {
- CompressFilesEncrypted(archiveStream, CommonRoot(fileFullNames), password, fileFullNames);
- }
- /// <summary>
- /// Packs files into the archive.
- /// </summary>
- /// <param name="fileFullNames">Array of file names to pack.</param>
- /// <param name="commonRootLength">The length of the common root of the file names.</param>
- /// <param name="archiveName">The archive file name.</param>
- /// <param name="password">The archive password.</param>
- public void CompressFilesEncrypted(
- string archiveName, int commonRootLength, string password, params string[] fileFullNames)
- {
- _compressingFilesOnDisk = true;
- _archiveName = archiveName;
- using (FileStream fs = GetArchiveFileStream(archiveName))
- {
- if (fs == null)
- {
- return;
- }
- CompressFilesEncrypted(fs, commonRootLength, password, fileFullNames);
- }
- FinalizeUpdate();
- }
- /// <summary>
- /// Packs files into the archive.
- /// </summary>
- /// <param name="fileFullNames">Array of file names to pack.</param>
- /// <param name="commonRootLength">The length of the common root of the file names.</param>
- /// <param name="archiveStream">The archive output stream.
- /// Use CompressFiles( ... string archiveName ... ) overloads for archiving to disk.</param>
- /// <param name="password">The archive password.</param>
- public void CompressFilesEncrypted(
- Stream archiveStream, int commonRootLength, string password, params string[] fileFullNames)
- {
- ClearExceptions();
- if (fileFullNames.Length > 1 &&
- (_archiveFormat == OutArchiveFormat.BZip2 || _archiveFormat == OutArchiveFormat.GZip ||
- _archiveFormat == OutArchiveFormat.XZ))
- {
- if (!ThrowException(null,
- new CompressionFailedException("Can not compress more than one file in this format.")))
- {
- return;
- }
- }
- if (_volumeSize == 0 || !_compressingFilesOnDisk)
- {
- ValidateStream(archiveStream);
- }
- FileInfo[] files = null;
- try
- {
- files = ProduceFileInfoArray(fileFullNames, commonRootLength, _directoryCompress, DirectoryStructure);
- }
- catch (Exception e)
- {
- if (!ThrowException(null, e))
- {
- return;
- }
- }
- _directoryCompress = false;
- if (FilesFound != null)
- {
- FilesFound(this, new IntEventArgs(fileFullNames.Length));
- }
- try
- {
- ISequentialOutStream sequentialArchiveStream;
- using ((sequentialArchiveStream = GetOutStream(archiveStream)) as IDisposable)
- {
- IInStream inArchiveStream;
- using ((inArchiveStream = GetInStream()) as IDisposable)
- {
- IOutArchive outArchive;
- if (CompressionMode == CompressionMode.Create || !_compressingFilesOnDisk)
- {
- SevenZipLibraryManager.LoadLibrary(this, _archiveFormat);
- outArchive = SevenZipLibraryManager.OutArchive(_archiveFormat, this);
- }
- else
- {
- // Create IInArchive, read it and convert to IOutArchive
- SevenZipLibraryManager.LoadLibrary(
- this, Formats.InForOutFormats[_archiveFormat]);
- if ((outArchive = MakeOutArchive(inArchiveStream)) == null)
- {
- return;
- }
- }
- using (var auc = GetArchiveUpdateCallback(files, commonRootLength, password))
- {
- try
- {
- if (files != null) //ReSharper
- CheckedExecute(
- outArchive.UpdateItems(
- sequentialArchiveStream, (uint) files.Length + _oldFilesCount, auc),
- SevenZipCompressionFailedException.DEFAULT_MESSAGE, auc);
- }
- finally
- {
- FreeCompressionCallback(auc);
- }
- }
- }
- }
- }
- finally
- {
- if (CompressionMode == CompressionMode.Create || !_compressingFilesOnDisk)
- {
- SevenZipLibraryManager.FreeLibrary(this, _archiveFormat);
- }
- else
- {
- SevenZipLibraryManager.FreeLibrary(this, Formats.InForOutFormats[_archiveFormat]);
- File.Delete(_archiveName);
- }
- _compressingFilesOnDisk = false;
- OnEvent(CompressionFinished, EventArgs.Empty, false);
- }
- ThrowUserException();
- }
- #endregion
- #region CompressDirectory overloads
- #if !CS4
- /// <summary>
- /// Recursively packs all files in the specified directory.
- /// </summary>
- /// <param name="directory">The directory to compress.</param>
- /// <param name="archiveName">The archive file name.</param>
- public void CompressDirectory(
- string directory, string archiveName)
- {
- CompressDirectory(directory, archiveName, "", "*", true);
- }
- /// <summary>
- /// Recursively packs all files in the specified directory.
- /// </summary>
- /// <param name="directory">The directory to compress.</param>
- /// <param name="archiveStream">The archive output stream.
- /// Use CompressDirectory( ... string archiveName ... ) overloads for archiving to disk.</param>
- public void CompressDirectory(
- string directory, Stream archiveStream)
- {
- CompressDirectory(directory, archiveStream, "", "*", true);
- }
- /// <summary>
- /// Recursively packs all files in the specified directory.
- /// </summary>
- /// <param name="directory">The directory to compress.</param>
- /// <param name="archiveName">The archive file name.</param>
- /// <param name="password">The archive password.</param>
- public void CompressDirectory(
- string directory, string archiveName, string password)
- {
- CompressDirectory(directory, archiveName, password, "*", true);
- }
- /// <summary>
- /// Recursively packs all files in the specified directory.
- /// </summary>
- /// <param name="directory">The directory to compress.</param>
- /// <param name="archiveStream">The archive output stream.
- /// Use CompressDirectory( ... string archiveName ... ) overloads for archiving to disk.</param>
- /// <param name="password">The archive password.</param>
- public void CompressDirectory(
- string directory, Stream archiveStream, string password)
- {
- CompressDirectory(directory, archiveStream, password, "*", true);
- }
- /// <summary>
- /// Packs all files in the specified directory.
- /// </summary>
- /// <param name="directory">The directory to compress.</param>
- /// <param name="archiveName">The archive file name.</param>
- /// <param name="recursion">If true, files will be searched for recursively; otherwise, not.</param>
- public void CompressDirectory(
- string directory, string archiveName, bool recursion)
- {
- CompressDirectory(directory, archiveName, "", "*", recursion);
- }
- /// <summary>
- /// Packs all files in the specified directory.
- /// </summary>
- /// <param name="directory">The directory to compress.</param>
- /// <param name="archiveStream">The archive output stream.
- /// Use CompressDirectory( ... string archiveName ... ) overloads for archiving to disk.</param>
- /// <param name="recursion">If true, files will be searched for recursively; otherwise, not.</param>
- public void CompressDirectory(
- string directory, Stream archiveStream, bool recursion)
- {
- CompressDirectory(directory, archiveStream, "", "*", recursion);
- }
- /// <summary>
- /// Packs all files found by the specified pattern in the specified directory.
- /// </summary>
- /// <param name="directory">The directory to compress.</param>
- /// <param name="archiveName">The archive file name.</param>
- /// <param name="searchPattern">Search string, such as "*.txt".</param>
- /// <param name="recursion">If true, files will be searched for recursively; otherwise, not.</param>
- public void CompressDirectory(
- string directory, string archiveName,
- string searchPattern, bool recursion)
- {
- CompressDirectory(directory, archiveName, "", searchPattern, recursion);
- }
- /// <summary>
- /// Packs all files found by the specified pattern in the specified directory.
- /// </summary>
- /// <param name="directory">The directory to compress.</param>
- /// <param name="archiveStream">The archive output stream.
- /// Use CompressDirectory( ... string archiveName ... ) overloads for archiving to disk.</param>
- /// <param name="searchPattern">Search string, such as "*.txt".</param>
- /// <param name="recursion">If true, files will be searched for recursively; otherwise, not.</param>
- public void CompressDirectory(
- string directory, Stream archiveStream,
- string searchPattern, bool recursion)
- {
- CompressDirectory(directory, archiveStream, "", searchPattern, recursion);
- }
- /// <summary>
- /// Packs all files in the specified directory.
- /// </summary>
- /// <param name="directory">The directory to compress.</param>
- /// <param name="archiveName">The archive file name.</param>
- /// <param name="recursion">If true, files will be searched for recursively; otherwise, not.</param>
- /// <param name="password">The archive password.</param>
- public void CompressDirectory(
- string directory, string archiveName,
- bool recursion, string password)
- {
- CompressDirectory(directory, archiveName, password, "*", recursion);
- }
- /// <summary>
- /// Packs all files in the specified directory.
- /// </summary>
- /// <param name="directory">The directory to compress.</param>
- /// <param name="archiveStream">The archive output stream.
- /// Use CompressDirectory( ... string archiveName ... ) overloads for archiving to disk.</param>
- /// <param name="recursion">If true, files will be searched for recursively; otherwise, not.</param>
- /// <param name="password">The archive password.</param>
- public void CompressDirectory(
- string directory, Stream archiveStream,
- bool recursion, string password)
- {
- CompressDirectory(directory, archiveStream, password, "*", recursion);
- }
- #endif
- #if !CS4
- /// <summary>
- /// Packs all files in the specified directory.
- /// </summary>
- /// <param name="directory">The directory to compress.</param>
- /// <param name="archiveName">The archive file name.</param>
- /// <param name="password">The archive password.</param>
- /// <param name="searchPattern">Search string, such as "*.txt".</param>
- /// <param name="recursion">If true, files will be searched for recursively; otherwise, not.</param>
- public void CompressDirectory(
- string directory, string archiveName,
- string password, string searchPattern, bool recursion)
- #else
- /// <summary>
- /// 包中的指定目录下的所有文件。
- /// Packs all files in the specified directory.
- /// </summary>
- /// <param name="directory">The directory to compress.</param>
- /// <param name="archiveName">The archive file name.</param>
- /// <param name="password">The archive password.</param>
- /// <param name="searchPattern">Search string, such as "*.txt".</param>
- /// <param name="recursion">If true, files will be searched for recursively; otherwise, not.</param>
- public void CompressDirectory(
- string directory, string archiveName,
- string password = "", string searchPattern = "*", bool recursion = true)
- #endif
- {
- _compressingFilesOnDisk = true;
- _archiveName = archiveName;
- using (FileStream fs = GetArchiveFileStream(archiveName))
- {
- if (fs == null && _volumeSize == 0)
- {
- return;
- }
- CompressDirectory(directory, fs, password, searchPattern, recursion);
- }
- FinalizeUpdate();
- }
- #if !CS4
- /// <summary>
- /// Packs all files in the specified directory.
- /// </summary>
- /// <param name="directory">The directory to compress.</param>
- /// <param name="archiveStream">The archive output stream.
- /// Use CompressDirectory( ... string archiveName ... ) overloads for archiving to disk.</param>
- /// <param name="password">The archive password.</param>
- /// <param name="searchPattern">Search string, such as "*.txt".</param>
- /// <param name="recursion">If true, files will be searched for recursively; otherwise, not.</param>
- public void CompressDirectory(
- string directory, Stream archiveStream,
- string password, string searchPattern, bool recursion)
- #else
- /// <summary>
- /// Packs all files in the specified directory.
- /// </summary>
- /// <param name="directory">The directory to compress.</param>
- /// <param name="archiveStream">The archive output stream.
- /// Use CompressDirectory( ... string archiveName ... ) overloads for archiving to disk.</param>
- /// <param name="password">The archive password.</param>
- /// <param name="searchPattern">Search string, such as "*.txt".</param>
- /// <param name="recursion">If true, files will be searched for recursively; otherwise, not.</param>
- public void CompressDirectory(
- string directory, Stream archiveStream,
- string password = "", string searchPattern = "*", bool recursion = true)
- #endif
- {
- var files = new List<string>();
- if (!Directory.Exists(directory))
- {
- throw new ArgumentException("Directory \"" + directory + "\" does not exist!");
- }
- if (RecursiveDirectoryEmptyCheck(directory))
- {
- throw new SevenZipInvalidFileNamesException("the specified directory is empty!");
- }
- if (recursion)
- {
- AddFilesFromDirectory(directory, files, searchPattern);
- }
- else
- {
- #if CS4
- files.AddRange((new DirectoryInfo(directory)).GetFiles(searchPattern).Select(fi => fi.FullName));
- #else
- foreach (FileInfo fi in (new DirectoryInfo(directory)).GetFiles(searchPattern))
- {
- files.Add(fi.FullName);
- }
- #endif
- }
- int commonRootLength = directory.Length;
- if (directory.EndsWith("\\", StringComparison.OrdinalIgnoreCase))
- {
- directory = directory.Substring(0, directory.Length - 1);
- }
- else
- {
- commonRootLength++;
- }
- if (PreserveDirectoryRoot)
- {
- var upperRoot = Path.GetDirectoryName(directory);
- commonRootLength = upperRoot.Length +
- (upperRoot.EndsWith("\\", StringComparison.OrdinalIgnoreCase) ? 0 : 1);
- }
- _directoryCompress = true;
- CompressFilesEncrypted(archiveStream, commonRootLength, password, files.ToArray());
- }
- #endregion
- #region CompressFileDictionary overloads
- #if !CS4
- /// <summary>
- /// Packs the specified file dictionary.
- /// </summary>
- /// <param name="fileDictionary">Dictionary<name of the archive entry, file name>.
- /// If a file name is null, the corresponding archive entry becomes a directory.</param>
- /// <param name="archiveName">The archive file name.</param>
- public void CompressFileDictionary(
- Dictionary<string, string> fileDictionary, string archiveName)
- {
- CompressFileDictionary(fileDictionary, archiveName, "");
- }
- /// <summary>
- /// Packs the specified file dictionary.
- /// </summary>
- /// <param name="fileDictionary">Dictionary<name of the archive entry, file name>.
- /// If a file name is null, the corresponding archive entry becomes a directory.</param>
- /// <param name="archiveStream">The archive output stream.
- /// Use CompressFileDictionary( ... string archiveName ... ) overloads for archiving to disk.</param>
- public void CompressFileDictionary(
- Dictionary<string, string> fileDictionary, Stream archiveStream)
- {
- CompressFileDictionary(fileDictionary, archiveStream, "");
- }
- #endif
-
- #if !CS4
- /// <summary>
- /// Packs the specified file dictionary.
- /// </summary>
- /// <param name="fileDictionary">Dictionary<name of the archive entry, file name>.
- /// If a file name is null, the corresponding archive entry becomes a directory.</param>
- /// <param name="archiveName">The archive file name.</param>
- /// <param name="password">The archive password.</param>
- public void CompressFileDictionary(
- Dictionary<string, string> fileDictionary, string archiveName, string password)
- #else
- /// <summary>
- /// Packs the specified file dictionary.
- /// </summary>
- /// <param name="fileDictionary">Dictionary<name of the archive entry, file name>.
- /// If a file name is null, the corresponding archive entry becomes a directory.</param>
- /// <param name="archiveName">The archive file name.</param>
- /// <param name="password">The archive password.</param>
- public void CompressFileDictionary(
- Dictionary<string, string> fileDictionary, string archiveName, string password = "")
- #endif
- {
- _compressingFilesOnDisk = true;
- _archiveName = archiveName;
- using (FileStream fs = GetArchiveFileStream(archiveName))
- {
- if (fs == null)
- {
- return;
- }
- CompressFileDictionary(fileDictionary, fs, password);
- }
- FinalizeUpdate();
- }
-
- #if !CS4
- /// <summary>
- /// Packs the specified file dictionary.
- /// </summary>
- /// <param name="fileDictionary">Dictionary<name of the archive entry, file name>.
- /// If a file name is null, the corresponding archive entry becomes a directory.</param>
- /// <param name="archiveStream">The archive output stream.
- /// Use CompressStreamDictionary( ... string archiveName ... ) overloads for archiving to disk.</param>
- /// <param name="password">The archive password.</param>
- public void CompressFileDictionary(
- Dictionary<string, string> fileDictionary, Stream archiveStream, string password)
- #else
- /// <summary>
- /// Packs the specified file dictionary.
- /// </summary>
- /// <param name="fileDictionary">Dictionary<name of the archive entry, file name>.
- /// If a file name is null, the corresponding archive entry becomes a directory.</param>
- /// <param name="archiveStream">The archive output stream.
- /// Use CompressStreamDictionary( ... string archiveName ... ) overloads for archiving to disk.</param>
- /// <param name="password">The archive password.</param>
- public void CompressFileDictionary(
- Dictionary<string, string> fileDictionary, Stream archiveStream, string password = "")
- #endif
- {
- var streamDict = new Dictionary<string, Stream>(fileDictionary.Count);
- foreach (var pair in fileDictionary)
- {
- if (pair.Value == null)
- {
- streamDict.Add(pair.Key, null);
- }
- else
- {
- if (!File.Exists(pair.Value))
- {
- throw new CompressionFailedException("The file corresponding to the archive entry \"" + pair.Key + "\" does not exist.");
- }
- streamDict.Add(
- pair.Key,
- new FileStream(pair.Value, FileMode.Open, FileAccess.Read, FileShare.ReadWrite));
- }
- }
- //The created streams will be automatically disposed inside.
- CompressStreamDictionary(streamDict, archiveStream, password);
- }
- #endregion
- #region CompressStreamDictionary overloads
- #if !CS4
- /// <summary>
- /// Packs the specified stream dictionary.
- /// </summary>
- /// <param name="streamDictionary">Dictionary<name of the archive entry, stream>.
- /// If a stream is null, the corresponding string becomes a directory name.</param>
- /// <param name="archiveName">The archive file name.</param>
- public void CompressStreamDictionary(
- Dictionary<string, Stream> streamDictionary, string archiveName)
- {
- CompressStreamDictionary(streamDictionary, archiveName, "");
- }
- /// <summary>
- /// Packs the specified stream dictionary.
- /// </summary>
- /// <param name="streamDictionary">Dictionary<name of the archive entry, stream>.
- /// If a stream is null, the corresponding string becomes a directory name.</param>
- /// <param name="archiveStream">The archive output stream.
- /// Use CompressStreamDictionary( ... string archiveName ... ) overloads for archiving to disk.</param>
- public void CompressStreamDictionary(
- Dictionary<string, Stream> streamDictionary, Stream archiveStream)
- {
- CompressStreamDictionary(streamDictionary, archiveStream, "");
- }
- #endif
-
- #if !CS4
- /// <summary>
- /// Packs the specified stream dictionary.
- /// </summary>
- /// <param name="streamDictionary">Dictionary<name of the archive entry, stream>.
- /// If a stream is null, the corresponding string becomes a directory name.</param>
- /// <param name="archiveName">The archive file name.</param>
- /// <param name="password">The archive password.</param>
- public void CompressStreamDictionary(
- Dictionary<string, Stream> streamDictionary, string archiveName, string password)
- #else
- /// <summary>
- /// Packs the specified stream dictionary.
- /// </summary>
- /// <param name="streamDictionary">Dictionary<name of the archive entry, stream>.
- /// If a stream is null, the corresponding string becomes a directory name.</param>
- /// <param name="archiveName">The archive file name.</param>
- /// <param name="password">The archive password.</param>
- public void CompressStreamDictionary(
- Dictionary<string, Stream> streamDictionary, string archiveName, string password = "")
- #endif
- {
- _compressingFilesOnDisk = true;
- _archiveName = archiveName;
- using (FileStream fs = GetArchiveFileStream(archiveName))
- {
- if (fs == null)
- {
- return;
- }
- CompressStreamDictionary(streamDictionary, fs, password);
- }
- FinalizeUpdate();
- }
-
- #if !CS4
- /// <summary>
- /// Packs the specified stream dictionary.
- /// </summary>
- /// <param name="streamDictionary">Dictionary<name of the archive entry, stream>.
- /// If a stream is null, the corresponding string becomes a directory name.</param>
- /// <param name="archiveStream">The archive output stream.
- /// Use CompressStreamDictionary( ... string archiveName ... ) overloads for archiving to disk.</param>
- /// <param name="password">The archive password.</param>
- public void CompressStreamDictionary(
- Dictionary<string, Stream> streamDictionary, Stream archiveStream, string password)
- #else
- /// <summary>
- /// Packs the specified stream dictionary.
- /// </summary>
- /// <param name="streamDictionary">Dictionary<name of the archive entry, stream>.
- /// If a stream is null, the corresponding string becomes a directory name.</param>
- /// <param name="archiveStream">The archive output stream.
- /// Use CompressStreamDictionary( ... string archiveName ... ) overloads for archiving to disk.</param>
- /// <param name="password">The archive password.</param>
- public void CompressStreamDictionary(
- Dictionary<string, Stream> streamDictionary, Stream archiveStream, string password = "")
- #endif
- {
- ClearExceptions();
- if (streamDictionary.Count > 1 &&
- (_archiveFormat == OutArchiveFormat.BZip2 || _archiveFormat == OutArchiveFormat.GZip ||
- _archiveFormat == OutArchiveFormat.XZ))
- {
- if (!ThrowException(null,
- new CompressionFailedException("Can not compress more than one file/stream in this format.")))
- {
- return;
- }
- }
- if (_volumeSize == 0 || !_compressingFilesOnDisk)
- {
- ValidateStream(archiveStream);
- }
- #if CS4
- if (streamDictionary.Where(
- pair => pair.Value != null && (!pair.Value.CanSeek || !pair.Value.CanRead)).Any(
- pair => !ThrowException(null,
- new ArgumentException("The specified stream dictionary contains an invalid stream corresponding to the archive entry \""
- + pair.Key + "\".", "streamDictionary")))) {
- return;
- }
- #else
- foreach (var pair in streamDictionary)
- {
- if (pair.Value != null && (!pair.Value.CanSeek || !pair.Value.CanRead))
- {
- if (!ThrowException(null, new ArgumentException(
- "The specified stream dictionary contains an invalid stream corresponding to the archive entry \"" + pair.Key + "\".",
- "streamDictionary")))
- {
- return;
- }
- }
- }
- #endif
- try
- {
- ISequentialOutStream sequentialArchiveStream;
- using ((sequentialArchiveStream = GetOutStream(archiveStream)) as IDisposable)
- {
- IInStream inArchiveStream;
- using ((inArchiveStream = GetInStream()) as IDisposable)
- {
- IOutArchive outArchive;
- if (CompressionMode == CompressionMode.Create || !_compressingFilesOnDisk)
- {
- SevenZipLibraryManager.LoadLibrary(this, _archiveFormat);
- outArchive = SevenZipLibraryManager.OutArchive(_archiveFormat, this);
- }
- else
- {
- // Create IInArchive, read it and convert to IOutArchive
- SevenZipLibraryManager.LoadLibrary(
- this, Formats.InForOutFormats[_archiveFormat]);
- if ((outArchive = MakeOutArchive(inArchiveStream)) == null)
- {
- return;
- }
- }
- using (ArchiveUpdateCallback auc = GetArchiveUpdateCallback(
- streamDictionary, password))
- {
- try
- {
- CheckedExecute(outArchive.UpdateItems(sequentialArchiveStream,
- (uint)streamDictionary.Count + _oldFilesCount, auc),
- SevenZipCompressionFailedException.DEFAULT_MESSAGE, auc);
- }
- finally
- {
- FreeCompressionCallback(auc);
- }
- }
- }
- }
- }
- finally
- {
- if (CompressionMode == CompressionMode.Create || !_compressingFilesOnDisk)
- {
- SevenZipLibraryManager.FreeLibrary(this, _archiveFormat);
- }
- else
- {
- SevenZipLibraryManager.FreeLibrary(this, Formats.InForOutFormats[_archiveFormat]);
- File.Delete(_archiveName);
- }
- _compressingFilesOnDisk = false;
- OnEvent(CompressionFinished, EventArgs.Empty, false);
- }
- ThrowUserException();
- }
- #endregion
- #region CompressStream overloads
- #if !CS4
- /// <summary>
- /// Compresses the specified stream.
- /// </summary>
- /// <param name="inStream">The source uncompressed stream.</param>
- /// <param name="outStream">The destination compressed stream.</param>
- /// <exception cref="ArgumentException">ArgumentException: at least one of the specified streams is invalid.</exception>
- public void CompressStream(Stream inStream, Stream outStream)
- {
- CompressStream(inStream, outStream, "");
- }
- #endif
- /// <summary>
- /// Compresses the specified stream.
- /// </summary>
- /// <param name="inStream">The source uncompressed stream.</param>
- /// <param name="outStream">The destination compressed stream.</param>
- /// <param name="password">The archive password.</param>
- /// <exception cref="ArgumentException">ArgumentException: at least one of the specified streams is invalid.</exception>
- public void CompressStream(Stream inStream, Stream outStream, string password
- #if CS4
- = ""
- #endif
- )
- {
- ClearExceptions();
- if (!inStream.CanSeek || !inStream.CanRead || !outStream.CanWrite)
- {
- if (!ThrowException(null, new ArgumentException("The specified streams are invalid.")))
- {
- return;
- }
- }
- try
- {
- SevenZipLibraryManager.LoadLibrary(this, _archiveFormat);
- ISequentialOutStream sequentialArchiveStream;
- using ((sequentialArchiveStream = GetOutStream(outStream)) as IDisposable)
- {
- using (ArchiveUpdateCallback auc = GetArchiveUpdateCallback(inStream, password))
- {
- try
- {
- CheckedExecute(
- SevenZipLibraryManager.OutArchive(_archiveFormat, this).UpdateItems(
- sequentialArchiveStream, 1, auc),
- SevenZipCompressionFailedException.DEFAULT_MESSAGE, auc);
- }
- finally
- {
- FreeCompressionCallback(auc);
- }
- }
- }
- }
- finally
- {
- SevenZipLibraryManager.FreeLibrary(this, _archiveFormat);
- OnEvent(CompressionFinished, EventArgs.Empty, false);
- }
- ThrowUserException();
- }
- #endregion
- #region ModifyArchive overloads
- #if !CS4
- /// <summary>
- /// Modifies the existing archive (renames files or deletes them).
- /// </summary>
- /// <param name="archiveName">The archive file name.</param>
- /// <param name="newFileNames">New file names. Null value to delete the corresponding index.</param>
- public void ModifyArchive(string archiveName, Dictionary<int, string> newFileNames)
- {
- ModifyArchive(archiveName, newFileNames, "");
- }
- #endif
-
- /// <summary>
- /// Modifies the existing archive (renames files or deletes them).
- /// </summary>
- /// <param name="archiveName">The archive file name.</param>
- /// <param name="newFileNames">New file names. Null value to delete the corresponding index.</param>
- /// <param name="password">The archive password.</param>
- public void ModifyArchive(string archiveName, Dictionary<int, string> newFileNames, string password
- #if CS4
- = ""
- #endif
- )
- {
- ClearExceptions();
- if (!SevenZipLibraryManager.ModifyCapable)
- {
- throw new SevenZipLibraryException("The specified 7zip native library does not support this method.");
- }
- if (!File.Exists(archiveName))
- {
- if (!ThrowException(null, new ArgumentException("The specified archive does not exist.", "archiveName")))
- {
- return;
- }
- }
- if (newFileNames == null || newFileNames.Count == 0)
- {
- if (!ThrowException(null, new ArgumentException("Invalid new file names.", "newFileNames")))
- {
- return;
- }
- }
- try
- {
- using (var extr = new SevenZipExtractor(archiveName))
- {
- _updateData = new UpdateData();
- var archiveData = new ArchiveFileInfo[extr.ArchiveFileData.Count];
- extr.ArchiveFileData.CopyTo(archiveData, 0);
- _updateData.ArchiveFileData = new List<ArchiveFileInfo>(archiveData);
- }
- _updateData.FileNamesToModify = newFileNames;
- _updateData.Mode = InternalCompressionMode.Modify;
- }
- catch (SevenZipException e)
- {
- if (!ThrowException(null, e))
- {
- return;
- }
- }
- try
- {
- ISequentialOutStream sequentialArchiveStream;
- _compressingFilesOnDisk = true;
- using ((sequentialArchiveStream = GetOutStream(GetArchiveFileStream(archiveName))) as IDisposable)
- {
- IInStream inArchiveStream;
- _archiveName = archiveName;
- using ((inArchiveStream = GetInStream()) as IDisposable)
- {
- IOutArchive outArchive;
- // Create IInArchive, read it and convert to IOutArchive
- SevenZipLibraryManager.LoadLibrary(
- this, Formats.InForOutFormats[_archiveFormat]);
- if ((outArchive = MakeOutArchive(inArchiveStream)) == null)
- {
- return;
- }
- using (ArchiveUpdateCallback auc = GetArchiveUpdateCallback(null, 0, password))
- {
- UInt32 deleteCount = 0;
- if (_updateData.FileNamesToModify != null)
- {
- #if CS4 // System.Linq of C# 4 is great
- deleteCount = (UInt32)_updateData.FileNamesToModify.Sum(
- pairDeleted => pairDeleted.Value == null ? 1 : 0);
- #else
- foreach(var pairDeleted in _updateData.FileNamesToModify)
- {
- if (pairDeleted.Value == null)
- {
- deleteCount++;
- }
- }
- #endif
- }
- try
- {
- CheckedExecute(
- outArchive.UpdateItems(
- sequentialArchiveStream, _oldFilesCount - deleteCount, auc),
- SevenZipCompressionFailedException.DEFAULT_MESSAGE, auc);
- }
- finally
- {
- FreeCompressionCallback(auc);
- }
- }
- }
- }
- }
- finally
- {
- SevenZipLibraryManager.FreeLibrary(this, Formats.InForOutFormats[_archiveFormat]);
- File.Delete(archiveName);
- FinalizeUpdate();
- _compressingFilesOnDisk = false;
- _updateData.FileNamesToModify = null;
- _updateData.ArchiveFileData = null;
- OnEvent(CompressionFinished, EventArgs.Empty, false);
- }
- ThrowUserException();
- }
- #endregion
- #endregion
- #endif
- /// <summary>
- /// Gets or sets the dictionary size for the managed LZMA algorithm.
- /// </summary>
- public static int LzmaDictionarySize
- {
- get
- {
- return _lzmaDictionarySize;
- }
- set
- {
- _lzmaDictionarySize = value;
- }
- }
- internal static void WriteLzmaProperties(Encoder encoder)
- {
- #region LZMA properties definition
- CoderPropId[] propIDs =
- {
- CoderPropId.DictionarySize,
- CoderPropId.PosStateBits,
- CoderPropId.LitContextBits,
- CoderPropId.LitPosBits,
- CoderPropId.Algorithm,
- CoderPropId.NumFastBytes,
- CoderPropId.MatchFinder,
- CoderPropId.EndMarker
- };
- object[] properties =
- {
- _lzmaDictionarySize,
- 2,
- 3,
- 0,
- 2,
- 256,
- "bt4",
- false
- };
- #endregion
- encoder.SetCoderProperties(propIDs, properties);
- }
- /// <summary>
- /// Compresses the specified stream with LZMA algorithm (C# inside)
- /// </summary>
- /// <param name="inStream">The source uncompressed stream</param>
- /// <param name="outStream">The destination compressed stream</param>
- /// <param name="inLength">The length of uncompressed data (null for inStream.Length)</param>
- /// <param name="codeProgressEvent">The event for handling the code progress</param>
- public static void CompressStream(Stream inStream, Stream outStream, int? inLength,
- EventHandler<ProgressEventArgs> codeProgressEvent)
- {
- if (!inStream.CanRead || !outStream.CanWrite)
- {
- throw new ArgumentException("The specified streams are invalid.");
- }
- var encoder = new Encoder();
- WriteLzmaProperties(encoder);
- encoder.WriteCoderProperties(outStream);
- long streamSize = inLength.HasValue ? inLength.Value : inStream.Length;
- for (int i = 0; i < 8; i++)
- {
- outStream.WriteByte((byte) (streamSize >> (8*i)));
- }
- encoder.Code(inStream, outStream, -1, -1, new LzmaProgressCallback(streamSize, codeProgressEvent));
- }
- /// <summary>
- /// Compresses byte array with LZMA algorithm (C# inside)
- /// </summary>
- /// <param name="data">Byte array to compress</param>
- /// <returns>Compressed byte array</returns>
- public static byte[] CompressBytes(byte[] data)
- {
- using (var inStream = new MemoryStream(data))
- {
- using (var outStream = new MemoryStream())
- {
- var encoder = new Encoder();
- WriteLzmaProperties(encoder);
- encoder.WriteCoderProperties(outStream);
- long streamSize = inStream.Length;
- for (int i = 0; i < 8; i++)
- outStream.WriteByte((byte) (streamSize >> (8*i)));
- encoder.Code(inStream, outStream, -1, -1, null);
- return outStream.ToArray();
- }
- }
- }
- }
- #endif
- }
|