/* 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 . */ #define DOTNET20 #define UNMANAGED #define COMPRESS using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Runtime.InteropServices; using System.Security.Permissions; #if !WINCE using FILETIME=System.Runtime.InteropServices.ComTypes.FILETIME; #elif WINCE using FILETIME=OpenNETCF.Runtime.InteropServices.ComTypes.FILETIME; #endif namespace SevenZip { #if UNMANAGED /// /// The structure to fix x64 and x32 variant size mismatch. /// [StructLayout(LayoutKind.Sequential)] internal struct PropArray { uint _cElems; IntPtr _pElems; } /// /// COM VARIANT structure with special interface routines. /// [StructLayout(LayoutKind.Explicit)] internal struct PropVariant { [FieldOffset(0)] private ushort _vt; /// /// IntPtr variant value. /// [FieldOffset(8)] private IntPtr _value; /*/// /// Byte variant value. /// [FieldOffset(8)] private byte _ByteValue;*/ /// /// Signed int variant value. /// [FieldOffset(8)] private Int32 _int32Value; /// /// Unsigned int variant value. /// [FieldOffset(8)] private UInt32 _uInt32Value; /// /// Long variant value. /// [FieldOffset(8)] private Int64 _int64Value; /// /// Unsigned long variant value. /// [FieldOffset(8)] private UInt64 _uInt64Value; /// /// FILETIME variant value. /// [FieldOffset(8)] private FILETIME _fileTime; /// /// The PropArray instance to fix the variant size on x64 bit systems. /// [FieldOffset(8)] private PropArray _propArray; /// /// Gets or sets variant type. /// public VarEnum VarType { private get { return (VarEnum) _vt; } set { _vt = (ushort) value; } } /// /// Gets or sets the pointer value of the COM variant /// public IntPtr Value { private get { return _value; } set { _value = value; } } /* /// /// Gets or sets the byte value of the COM variant /// public byte ByteValue { get { return _ByteValue; } set { _ByteValue = value; } } */ /// /// Gets or sets the UInt32 value of the COM variant. /// public UInt32 UInt32Value { private get { return _uInt32Value; } set { _uInt32Value = value; } } /// /// Gets or sets the UInt32 value of the COM variant. /// public Int32 Int32Value { private get { return _int32Value; } set { _int32Value = value; } } /// /// Gets or sets the Int64 value of the COM variant /// public Int64 Int64Value { private get { return _int64Value; } set { _int64Value = value; } } /// /// Gets or sets the UInt64 value of the COM variant /// public UInt64 UInt64Value { private get { return _uInt64Value; } set { _uInt64Value = value; } } /* /// /// Gets or sets the FILETIME value of the COM variant /// public System.Runtime.InteropServices.ComTypes.FILETIME FileTime { get { return _fileTime; } set { _fileTime = value; } } */ /*/// /// Gets or sets variant type (ushort). /// public ushort VarTypeNative { get { return _vt; } set { _vt = value; } }*/ /*/// /// Clears variant /// public void Clear() { switch (VarType) { case VarEnum.VT_EMPTY: break; case VarEnum.VT_NULL: case VarEnum.VT_I2: case VarEnum.VT_I4: case VarEnum.VT_R4: case VarEnum.VT_R8: case VarEnum.VT_CY: case VarEnum.VT_DATE: case VarEnum.VT_ERROR: case VarEnum.VT_BOOL: case VarEnum.VT_I1: case VarEnum.VT_UI1: case VarEnum.VT_UI2: case VarEnum.VT_UI4: case VarEnum.VT_I8: case VarEnum.VT_UI8: case VarEnum.VT_INT: case VarEnum.VT_UINT: case VarEnum.VT_HRESULT: case VarEnum.VT_FILETIME: _vt = 0; break; default: if (NativeMethods.PropVariantClear(ref this) != (int)OperationResult.Ok) { throw new ArgumentException("PropVariantClear has failed for some reason."); } break; } }*/ /// /// Gets the object for this PropVariant. /// /// public object Object { get { #if !WINCE var sp = new SecurityPermission(SecurityPermissionFlag.UnmanagedCode); sp.Demand(); #endif switch (VarType) { case VarEnum.VT_EMPTY: return null; case VarEnum.VT_FILETIME: try { return DateTime.FromFileTime(Int64Value); } catch (ArgumentOutOfRangeException) { return DateTime.MinValue; } default: GCHandle propHandle = GCHandle.Alloc(this, GCHandleType.Pinned); try { return Marshal.GetObjectForNativeVariant(propHandle.AddrOfPinnedObject()); } #if WINCE catch (NotSupportedException) { switch (VarType) { case VarEnum.VT_UI8: return UInt64Value; case VarEnum.VT_UI4: return UInt32Value; case VarEnum.VT_I8: return Int64Value; case VarEnum.VT_I4: return Int32Value; default: return 0; } } #endif finally { propHandle.Free(); } } } } /// /// Determines whether the specified System.Object is equal to the current PropVariant. /// /// The System.Object to compare with the current PropVariant. /// true if the specified System.Object is equal to the current PropVariant; otherwise, false. public override bool Equals(object obj) { return (obj is PropVariant) ? Equals((PropVariant) obj) : false; } /// /// Determines whether the specified PropVariant is equal to the current PropVariant. /// /// The PropVariant to compare with the current PropVariant. /// true if the specified PropVariant is equal to the current PropVariant; otherwise, false. private bool Equals(PropVariant afi) { if (afi.VarType != VarType) { return false; } if (VarType != VarEnum.VT_BSTR) { return afi.Int64Value == Int64Value; } return afi.Value == Value; } /// /// Serves as a hash function for a particular type. /// /// A hash code for the current PropVariant. public override int GetHashCode() { return Value.GetHashCode(); } /// /// Returns a System.String that represents the current PropVariant. /// /// A System.String that represents the current PropVariant. public override string ToString() { return "[" + Value + "] " + Int64Value.ToString(CultureInfo.CurrentCulture); } /// /// Determines whether the specified PropVariant instances are considered equal. /// /// The first PropVariant to compare. /// The second PropVariant to compare. /// true if the specified PropVariant instances are considered equal; otherwise, false. public static bool operator ==(PropVariant afi1, PropVariant afi2) { return afi1.Equals(afi2); } /// /// Determines whether the specified PropVariant instances are not considered equal. /// /// The first PropVariant to compare. /// The second PropVariant to compare. /// true if the specified PropVariant instances are not considered equal; otherwise, false. public static bool operator !=(PropVariant afi1, PropVariant afi2) { return !afi1.Equals(afi2); } } /// /// Stores file extraction modes. /// internal enum AskMode { /// /// Extraction mode /// Extract = 0, /// /// Test mode /// Test, /// /// Skip mode /// Skip } /// /// Stores operation result values /// public enum OperationResult { /// /// Success /// Ok = 0, /// /// Method is unsupported /// UnsupportedMethod, /// /// Data error has occured /// DataError, /// /// CrcError has occured /// CrcError } /// /// Codes of item properities /// internal enum ItemPropId : uint { /// /// No property /// NoProperty = 0, /// /// Handler item index /// HandlerItemIndex = 2, /// /// Item path /// Path, /// /// Item name /// Name, /// /// Item extension /// Extension, /// /// true if the item is a folder; otherwise, false /// IsDirectory, /// /// Item size /// Size, /// /// Item packed sise; usually absent /// PackedSize, /// /// Item attributes; usually absent /// Attributes, /// /// Item creation time; usually absent /// CreationTime, /// /// Item last access time; usually absent /// LastAccessTime, /// /// Item last write time /// LastWriteTime, /// /// true if the item is solid; otherwise, false /// Solid, /// /// true if the item is commented; otherwise, false /// Commented, /// /// true if the item is encrypted; otherwise, false /// Encrypted, /// /// (?) /// SplitBefore, /// /// (?) /// SplitAfter, /// /// Dictionary size(?) /// DictionarySize, /// /// Item CRC checksum /// Crc, /// /// Item type(?) /// Type, /// /// (?) /// IsAnti, /// /// Compression method /// Method, /// /// (?); usually absent /// HostOS, /// /// Item file system; usually absent /// FileSystem, /// /// Item user(?); usually absent /// User, /// /// Item group(?); usually absent /// Group, /// /// Bloack size(?) /// Block, /// /// Item comment; usually absent /// Comment, /// /// Item position /// Position, /// /// Item prefix(?) /// Prefix, /// /// Number of subdirectories /// NumSubDirs, /// /// Numbers of subfiles /// NumSubFiles, /// /// The archive legacy unpacker version /// UnpackVersion, /// /// Volume(?) /// Volume, /// /// Is a volume /// IsVolume, /// /// Offset value(?) /// Offset, /// /// Links(?) /// Links, /// /// Number of blocks /// NumBlocks, /// /// Number of volumes(?) /// NumVolumes, /// /// Time type(?) /// TimeType, /// /// 64-bit(?) /// Bit64, /// /// BigEndian /// BigEndian, /// /// Cpu(?) /// Cpu, /// /// Physical archive size /// PhysicalSize, /// /// Headers size /// HeadersSize, /// /// Archive checksum /// Checksum, /// /// (?) /// TotalSize = 0x1100, /// /// (?) /// FreeSpace, /// /// Cluster size(?) /// ClusterSize, /// /// Volume name(?) /// VolumeName, /// /// Local item name(?); usually absent /// LocalName = 0x1200, /// /// (?) /// Provider, /// /// User defined property; usually absent /// UserDefined = 0x10000 } /*/// /// Codes of archive properties or modes. /// internal enum ArchivePropId : uint { Name = 0, ClassID, Extension, AddExtension, Update, KeepName, StartSignature, FinishSignature, Associate }*/ /// /// PropId string names dictionary wrapper. /// internal static class PropIdToName { /// /// PropId string names /// public static readonly Dictionary PropIdNames = #region Initialization new Dictionary(46) { {ItemPropId.Path, "Path"}, {ItemPropId.Name, "Name"}, {ItemPropId.IsDirectory, "Folder"}, {ItemPropId.Size, "Size"}, {ItemPropId.PackedSize, "Packed Size"}, {ItemPropId.Attributes, "Attributes"}, {ItemPropId.CreationTime, "Created"}, {ItemPropId.LastAccessTime, "Accessed"}, {ItemPropId.LastWriteTime, "Modified"}, {ItemPropId.Solid, "Solid"}, {ItemPropId.Commented, "Commented"}, {ItemPropId.Encrypted, "Encrypted"}, {ItemPropId.SplitBefore, "Split Before"}, {ItemPropId.SplitAfter, "Split After"}, { ItemPropId.DictionarySize, "Dictionary Size" }, {ItemPropId.Crc, "CRC"}, {ItemPropId.Type, "Type"}, {ItemPropId.IsAnti, "Anti"}, {ItemPropId.Method, "Method"}, {ItemPropId.HostOS, "Host OS"}, {ItemPropId.FileSystem, "File System"}, {ItemPropId.User, "User"}, {ItemPropId.Group, "Group"}, {ItemPropId.Block, "Block"}, {ItemPropId.Comment, "Comment"}, {ItemPropId.Position, "Position"}, {ItemPropId.Prefix, "Prefix"}, { ItemPropId.NumSubDirs, "Number of subdirectories" }, { ItemPropId.NumSubFiles, "Number of subfiles" }, { ItemPropId.UnpackVersion, "Unpacker version" }, {ItemPropId.Volume, "Volume"}, {ItemPropId.IsVolume, "IsVolume"}, {ItemPropId.Offset, "Offset"}, {ItemPropId.Links, "Links"}, { ItemPropId.NumBlocks, "Number of blocks" }, { ItemPropId.NumVolumes, "Number of volumes" }, {ItemPropId.TimeType, "Time type"}, {ItemPropId.Bit64, "64-bit"}, {ItemPropId.BigEndian, "Big endian"}, {ItemPropId.Cpu, "CPU"}, { ItemPropId.PhysicalSize, "Physical Size" }, {ItemPropId.HeadersSize, "Headers Size"}, {ItemPropId.Checksum, "Checksum"}, {ItemPropId.FreeSpace, "Free Space"}, {ItemPropId.ClusterSize, "Cluster Size"} }; #endregion } /// /// 7-zip IArchiveOpenCallback imported interface to handle the opening of an archive. /// [ComImport] [Guid("23170F69-40C1-278A-0000-000600100000")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] internal interface IArchiveOpenCallback { // ref ulong replaced with IntPtr because handlers often pass null value // read actual value with Marshal.ReadInt64 /// /// Sets total data size /// /// Files pointer /// Total size in bytes void SetTotal( IntPtr files, IntPtr bytes); /// /// Sets completed size /// /// Files pointer /// Completed size in bytes void SetCompleted( IntPtr files, IntPtr bytes); } /// /// 7-zip ICryptoGetTextPassword imported interface to get the archive password. /// [ComImport] [Guid("23170F69-40C1-278A-0000-000500100000")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] internal interface ICryptoGetTextPassword { /// /// Gets password for the archive /// /// Password for the archive /// Zero if everything is OK [PreserveSig] int CryptoGetTextPassword( [MarshalAs(UnmanagedType.BStr)] out string password); } /// /// 7-zip ICryptoGetTextPassword2 imported interface for setting the archive password. /// [ComImport] [Guid("23170F69-40C1-278A-0000-000500110000")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] internal interface ICryptoGetTextPassword2 { /// /// Sets password for the archive /// /// Specifies whether archive has a password or not (0 if not) /// Password for the archive /// Zero if everything is OK [PreserveSig] int CryptoGetTextPassword2( ref int passwordIsDefined, [MarshalAs(UnmanagedType.BStr)] out string password); } /// /// 7-zip IArchiveExtractCallback imported interface. /// [ComImport] [Guid("23170F69-40C1-278A-0000-000600200000")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] internal interface IArchiveExtractCallback { /// /// Gives the size of the unpacked archive files /// /// Size of the unpacked archive files (in bytes) void SetTotal(ulong total); /// /// SetCompleted 7-zip function /// /// void SetCompleted([In] ref ulong completeValue); /// /// Gets the stream for file extraction /// /// File index in the archive file table /// Pointer to the stream /// Extraction mode /// S_OK - OK, S_FALSE - skip this file [PreserveSig] int GetStream( uint index, [Out, MarshalAs(UnmanagedType.Interface)] out ISequentialOutStream outStream, AskMode askExtractMode); /// /// PrepareOperation 7-zip function /// /// Ask mode void PrepareOperation(AskMode askExtractMode); /// /// Sets the operaton result /// /// The operation result void SetOperationResult(OperationResult operationResult); } /// /// 7-zip IArchiveUpdateCallback imported interface. /// [ComImport] [Guid("23170F69-40C1-278A-0000-000600800000")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] internal interface IArchiveUpdateCallback { /// /// Gives the size of the unpacked archive files. /// /// Size of the unpacked archive files (in bytes) void SetTotal(ulong total); /// /// SetCompleted 7-zip internal function. /// /// void SetCompleted([In] ref ulong completeValue); /// /// Gets archive update mode. /// /// File index /// 1 if new, 0 if not /// 1 if new, 0 if not /// -1 if doesn't matter /// [PreserveSig] int GetUpdateItemInfo( uint index, ref int newData, ref int newProperties, ref uint indexInArchive); /// /// Gets the archive item property data. /// /// Item index /// Property identificator /// Property value /// Zero if Ok [PreserveSig] int GetProperty(uint index, ItemPropId propId, ref PropVariant value); /// /// Gets the stream for reading. /// /// The item index. /// The ISequentialInStream pointer for reading. /// Zero if Ok [PreserveSig] int GetStream( uint index, [Out, MarshalAs(UnmanagedType.Interface)] out ISequentialInStream inStream); /// /// Sets the result for currently performed operation. /// /// The result value. void SetOperationResult(OperationResult operationResult); /// /// EnumProperties 7-zip internal function. /// /// The enumerator pointer. /// long EnumProperties(IntPtr enumerator); } /// /// 7-zip IArchiveOpenVolumeCallback imported interface to handle archive volumes. /// [ComImport] [Guid("23170F69-40C1-278A-0000-000600300000")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] internal interface IArchiveOpenVolumeCallback { /// /// Gets the archive property data. /// /// The property identificator. /// The property value. [PreserveSig] int GetProperty( ItemPropId propId, ref PropVariant value); /// /// Gets the stream for reading the volume. /// /// The volume file name. /// The IInStream pointer for reading. /// Zero if Ok [PreserveSig] int GetStream( [MarshalAs(UnmanagedType.LPWStr)] string name, [Out, MarshalAs(UnmanagedType.Interface)] out IInStream inStream); } /// /// 7-zip ISequentialInStream imported interface /// [ComImport] [Guid("23170F69-40C1-278A-0000-000300010000")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] internal interface ISequentialInStream { /// /// Writes data to 7-zip packer /// /// Array of bytes available for writing /// Array size /// S_OK if success /// If (size > 0) and there are bytes in stream, /// this function must read at least 1 byte. /// This function is allowed to read less than "size" bytes. /// You must call Read function in loop, if you need exact amount of data. /// int Read( [Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] byte[] data, uint size); } /// /// 7-zip ISequentialOutStream imported interface /// [ComImport] [Guid("23170F69-40C1-278A-0000-000300020000")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] internal interface ISequentialOutStream { /// /// Writes data to unpacked file stream /// /// Array of bytes available for reading /// Array size /// Processed data size /// S_OK if success /// If size != 0, return value is S_OK and (*processedSize == 0), /// then there are no more bytes in stream. /// If (size > 0) and there are bytes in stream, /// this function must read at least 1 byte. /// This function is allowed to rwrite less than "size" bytes. /// You must call Write function in loop, if you need exact amount of data. /// [PreserveSig] int Write( [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] byte[] data, uint size, IntPtr processedSize); } /// /// 7-zip IInStream imported interface /// [ComImport] [Guid("23170F69-40C1-278A-0000-000300030000")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] internal interface IInStream { /// /// Read routine /// /// Array of bytes to set /// Array size /// Zero if Ok int Read( [Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] byte[] data, uint size); /// /// Seek routine /// /// Offset value /// Seek origin value /// New position pointer void Seek( long offset, SeekOrigin seekOrigin, IntPtr newPosition); } /// /// 7-zip IOutStream imported interface /// [ComImport] [Guid("23170F69-40C1-278A-0000-000300040000")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] internal interface IOutStream { /// /// Write routine /// /// Array of bytes to get /// Array size /// Processed size /// Zero if Ok [PreserveSig] int Write( [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] byte[] data, uint size, IntPtr processedSize); /// /// Seek routine /// /// Offset value /// Seek origin value /// New position pointer void Seek( long offset, SeekOrigin seekOrigin, IntPtr newPosition); /// /// Set size routine /// /// New size value /// Zero if Ok [PreserveSig] int SetSize(long newSize); } /// /// 7-zip essential in archive interface /// [ComImport] [Guid("23170F69-40C1-278A-0000-000600600000")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] internal interface IInArchive { /// /// Opens archive for reading. /// /// Archive file stream /// Maximum start position for checking /// Callback for opening archive /// [PreserveSig] int Open( IInStream stream, [In] ref ulong maxCheckStartPosition, [MarshalAs(UnmanagedType.Interface)] IArchiveOpenCallback openArchiveCallback); /// /// Closes the archive. /// void Close(); /// /// Gets the number of files in the archive file table . /// /// The number of files in the archive uint GetNumberOfItems(); /// /// Retrieves specific property data. /// /// File index in the archive file table /// Property code /// Property variant value void GetProperty( uint index, ItemPropId propId, ref PropVariant value); // PropVariant /// /// Extracts files from the opened archive. /// /// indexes of files to be extracted (must be sorted) /// 0xFFFFFFFF means all files /// testMode != 0 means "test files operation" /// IArchiveExtractCallback for operations handling /// 0 if success [PreserveSig] int Extract( [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] uint[] indexes, uint numItems, int testMode, [MarshalAs(UnmanagedType.Interface)] IArchiveExtractCallback extractCallback); /// /// Gets archive property data /// /// Archive property identificator /// Archive property value void GetArchiveProperty( ItemPropId propId, // PROPID ref PropVariant value); // PropVariant /// /// Gets the number of properties /// /// The number of properties uint GetNumberOfProperties(); /// /// Gets property information /// /// Item index /// Name /// Property identificator /// Variant type void GetPropertyInfo( uint index, [MarshalAs(UnmanagedType.BStr)] out string name, out ItemPropId propId, // PROPID out ushort varType); //VARTYPE /// /// Gets the number of archive properties /// /// The number of archive properties uint GetNumberOfArchiveProperties(); /// /// Gets the archive property information /// /// Item index /// Name /// Property identificator /// Variant type void GetArchivePropertyInfo( uint index, [MarshalAs(UnmanagedType.BStr)] out string name, out ItemPropId propId, // PROPID out ushort varType); //VARTYPE } /// /// 7-zip essential out archive interface /// [ComImport] [Guid("23170F69-40C1-278A-0000-000600A00000")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] internal interface IOutArchive { /// /// Updates archive items /// /// The ISequentialOutStream pointer for writing the archive data /// Number of archive items /// The IArchiveUpdateCallback pointer /// Zero if Ok [PreserveSig] int UpdateItems( [MarshalAs(UnmanagedType.Interface)] ISequentialOutStream outStream, uint numItems, [MarshalAs(UnmanagedType.Interface)] IArchiveUpdateCallback updateCallback); /// /// Gets file time type(?) /// /// Type pointer void GetFileTimeType(IntPtr type); } /// /// 7-zip ISetProperties interface for setting various archive properties /// [ComImport] [Guid("23170F69-40C1-278A-0000-000600030000")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] internal interface ISetProperties { /// /// Sets the archive properties /// /// The names of the properties /// The values of the properties /// The properties count /// int SetProperties(IntPtr names, IntPtr values, int numProperties); } #endif }