MultiVolumeReadOnlyStream.cs 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using SharpCompress.Common;
  5. using SharpCompress.Common.Rar;
  6. namespace SharpCompress.Compressors.Rar
  7. {
  8. internal class MultiVolumeReadOnlyStream : Stream
  9. {
  10. private long currentPosition;
  11. private long maxPosition;
  12. private IEnumerator<RarFilePart> filePartEnumerator;
  13. private Stream currentStream;
  14. private readonly IExtractionListener streamListener;
  15. private long currentPartTotalReadBytes;
  16. private long currentEntryTotalReadBytes;
  17. internal MultiVolumeReadOnlyStream(IEnumerable<RarFilePart> parts, IExtractionListener streamListener)
  18. {
  19. this.streamListener = streamListener;
  20. filePartEnumerator = parts.GetEnumerator();
  21. filePartEnumerator.MoveNext();
  22. InitializeNextFilePart();
  23. }
  24. protected override void Dispose(bool disposing)
  25. {
  26. base.Dispose(disposing);
  27. if (disposing)
  28. {
  29. if (filePartEnumerator != null)
  30. {
  31. filePartEnumerator.Dispose();
  32. filePartEnumerator = null;
  33. }
  34. currentStream = null;
  35. }
  36. }
  37. private void InitializeNextFilePart()
  38. {
  39. maxPosition = filePartEnumerator.Current.FileHeader.CompressedSize;
  40. currentPosition = 0;
  41. currentStream = filePartEnumerator.Current.GetCompressedStream();
  42. currentPartTotalReadBytes = 0;
  43. CurrentCrc = filePartEnumerator.Current.FileHeader.FileCrc;
  44. streamListener.FireFilePartExtractionBegin(filePartEnumerator.Current.FilePartName,
  45. filePartEnumerator.Current.FileHeader.CompressedSize,
  46. filePartEnumerator.Current.FileHeader.UncompressedSize);
  47. }
  48. public override int Read(byte[] buffer, int offset, int count)
  49. {
  50. int totalRead = 0;
  51. int currentOffset = offset;
  52. int currentCount = count;
  53. while (currentCount > 0)
  54. {
  55. int readSize = currentCount;
  56. if (currentCount > maxPosition - currentPosition)
  57. {
  58. readSize = (int)(maxPosition - currentPosition);
  59. }
  60. int read = currentStream.Read(buffer, currentOffset, readSize);
  61. if (read < 0)
  62. {
  63. throw new EndOfStreamException();
  64. }
  65. currentPosition += read;
  66. currentOffset += read;
  67. currentCount -= read;
  68. totalRead += read;
  69. if (((maxPosition - currentPosition) == 0)
  70. && filePartEnumerator.Current.FileHeader.IsSplitAfter)
  71. {
  72. if (filePartEnumerator.Current.FileHeader.R4Salt != null)
  73. {
  74. throw new InvalidFormatException("Sharpcompress currently does not support multi-volume decryption.");
  75. }
  76. string fileName = filePartEnumerator.Current.FileHeader.FileName;
  77. if (!filePartEnumerator.MoveNext())
  78. {
  79. throw new InvalidFormatException(
  80. "Multi-part rar file is incomplete. Entry expects a new volume: " + fileName);
  81. }
  82. InitializeNextFilePart();
  83. }
  84. else
  85. {
  86. break;
  87. }
  88. }
  89. currentPartTotalReadBytes += totalRead;
  90. currentEntryTotalReadBytes += totalRead;
  91. streamListener.FireCompressedBytesRead(currentPartTotalReadBytes, currentEntryTotalReadBytes);
  92. return totalRead;
  93. }
  94. public override bool CanRead => true;
  95. public override bool CanSeek => false;
  96. public override bool CanWrite => false;
  97. public uint CurrentCrc { get; private set; }
  98. public override void Flush()
  99. {
  100. throw new NotSupportedException();
  101. }
  102. public override long Length => throw new NotSupportedException();
  103. public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); }
  104. public override long Seek(long offset, SeekOrigin origin)
  105. {
  106. throw new NotSupportedException();
  107. }
  108. public override void SetLength(long value)
  109. {
  110. throw new NotSupportedException();
  111. }
  112. public override void Write(byte[] buffer, int offset, int count)
  113. {
  114. throw new NotSupportedException();
  115. }
  116. }
  117. }