ArchiveOpenCallback.cs 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. namespace SevenZip
  2. {
  3. using System;
  4. using System.Collections.Generic;
  5. using System.IO;
  6. using System.Runtime.InteropServices;
  7. #if UNMANAGED
  8. /// <summary>
  9. /// Callback to handle the archive opening
  10. /// </summary>
  11. internal sealed class ArchiveOpenCallback : CallbackBase, IArchiveOpenCallback, IArchiveOpenVolumeCallback,
  12. ICryptoGetTextPassword, IDisposable
  13. {
  14. private FileInfo _fileInfo;
  15. private Dictionary<string, InStreamWrapper> _wrappers =
  16. new Dictionary<string, InStreamWrapper>();
  17. private readonly List<string> _volumeFileNames = new List<string>();
  18. /// <summary>
  19. /// Gets the list of volume file names.
  20. /// </summary>
  21. public IList<string> VolumeFileNames => _volumeFileNames;
  22. /// <summary>
  23. /// Performs the common initialization.
  24. /// </summary>
  25. /// <param name="fileName">Volume file name.</param>
  26. private void Init(string fileName)
  27. {
  28. if (!string.IsNullOrEmpty(fileName))
  29. {
  30. _fileInfo = new FileInfo(fileName);
  31. _volumeFileNames.Add(fileName);
  32. if (fileName.EndsWith("001"))
  33. {
  34. int index = 2;
  35. var baseName = fileName.Substring(0, fileName.Length - 3);
  36. var volName = baseName + (index > 99 ? index.ToString() :
  37. index > 9 ? "0" + index : "00" + index);
  38. while (File.Exists(volName))
  39. {
  40. _volumeFileNames.Add(volName);
  41. index++;
  42. volName = baseName + (index > 99 ? index.ToString() :
  43. index > 9 ? "0" + index : "00" + index);
  44. }
  45. }
  46. }
  47. }
  48. /// <summary>
  49. /// Initializes a new instance of the ArchiveOpenCallback class.
  50. /// </summary>
  51. /// <param name="fileName">The archive file name.</param>
  52. public ArchiveOpenCallback(string fileName)
  53. {
  54. Init(fileName);
  55. }
  56. /// <summary>
  57. /// Initializes a new instance of the ArchiveOpenCallback class.
  58. /// </summary>
  59. /// <param name="fileName">The archive file name.</param>
  60. /// <param name="password">Password for the archive.</param>
  61. public ArchiveOpenCallback(string fileName, string password) : base(password)
  62. {
  63. Init(fileName);
  64. }
  65. #region IArchiveOpenCallback Members
  66. public void SetTotal(IntPtr files, IntPtr bytes) {}
  67. public void SetCompleted(IntPtr files, IntPtr bytes) {}
  68. #endregion
  69. #region IArchiveOpenVolumeCallback Members
  70. public int GetProperty(ItemPropId propId, ref PropVariant value)
  71. {
  72. if (_fileInfo == null)
  73. {
  74. // We are likely opening an archive from a Stream, and no file or _fileInfo exists.
  75. return 0;
  76. }
  77. switch (propId)
  78. {
  79. case ItemPropId.Name:
  80. value.VarType = VarEnum.VT_BSTR;
  81. value.Value = Marshal.StringToBSTR(_fileInfo.FullName);
  82. break;
  83. case ItemPropId.IsDirectory:
  84. value.VarType = VarEnum.VT_BOOL;
  85. value.UInt64Value = (byte) (_fileInfo.Attributes & FileAttributes.Directory);
  86. break;
  87. case ItemPropId.Size:
  88. value.VarType = VarEnum.VT_UI8;
  89. value.UInt64Value = (ulong) _fileInfo.Length;
  90. break;
  91. case ItemPropId.Attributes:
  92. value.VarType = VarEnum.VT_UI4;
  93. value.UInt32Value = (uint) _fileInfo.Attributes;
  94. break;
  95. case ItemPropId.CreationTime:
  96. value.VarType = VarEnum.VT_FILETIME;
  97. value.Int64Value = _fileInfo.CreationTime.ToFileTime();
  98. break;
  99. case ItemPropId.LastAccessTime:
  100. value.VarType = VarEnum.VT_FILETIME;
  101. value.Int64Value = _fileInfo.LastAccessTime.ToFileTime();
  102. break;
  103. case ItemPropId.LastWriteTime:
  104. value.VarType = VarEnum.VT_FILETIME;
  105. value.Int64Value = _fileInfo.LastWriteTime.ToFileTime();
  106. break;
  107. }
  108. return 0;
  109. }
  110. public int GetStream(string name, out IInStream inStream)
  111. {
  112. if (!File.Exists(name))
  113. {
  114. name = Path.Combine(Path.GetDirectoryName(_fileInfo.FullName), name);
  115. if (!File.Exists(name))
  116. {
  117. inStream = null;
  118. AddException(new FileNotFoundException("The volume \"" + name + "\" was not found. Extraction can be impossible."));
  119. return 1;
  120. }
  121. }
  122. _volumeFileNames.Add(name);
  123. if (_wrappers.ContainsKey(name))
  124. {
  125. _wrappers[name].Seek(0, SeekOrigin.Begin, IntPtr.Zero);
  126. inStream = _wrappers[name];
  127. }
  128. else
  129. {
  130. try
  131. {
  132. var wrapper = new InStreamWrapper(
  133. new FileStream(name, FileMode.Open, FileAccess.Read, FileShare.ReadWrite), true);
  134. _wrappers.Add(name, wrapper);
  135. inStream = wrapper;
  136. }
  137. catch (Exception)
  138. {
  139. AddException(new FileNotFoundException("Failed to open the volume \"" + name + "\". Extraction is impossible."));
  140. inStream = null;
  141. return 1;
  142. }
  143. }
  144. return 0;
  145. }
  146. #endregion
  147. #region ICryptoGetTextPassword Members
  148. /// <summary>
  149. /// Sets password for the archive
  150. /// </summary>
  151. /// <param name="password">Password for the archive</param>
  152. /// <returns>Zero if everything is OK</returns>
  153. public int CryptoGetTextPassword(out string password)
  154. {
  155. password = Password;
  156. return 0;
  157. }
  158. #endregion
  159. #region IDisposable Members
  160. public void Dispose()
  161. {
  162. if (_wrappers != null)
  163. {
  164. foreach (InStreamWrapper wrap in _wrappers.Values)
  165. {
  166. wrap.Dispose();
  167. }
  168. _wrappers = null;
  169. }
  170. GC.SuppressFinalize(this);
  171. }
  172. #endregion
  173. }
  174. #endif
  175. }