XZStream.cs 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. using System;
  2. using System.IO;
  3. namespace SharpCompress.Compressors.Xz
  4. {
  5. [CLSCompliant(false)]
  6. public sealed class XZStream : XZReadOnlyStream
  7. {
  8. public static bool IsXZStream(Stream stream)
  9. {
  10. try
  11. {
  12. return null != XZHeader.FromStream(stream);
  13. }
  14. catch (Exception)
  15. {
  16. return false;
  17. }
  18. }
  19. private void AssertBlockCheckTypeIsSupported()
  20. {
  21. switch (Header.BlockCheckType)
  22. {
  23. case CheckType.NONE:
  24. break;
  25. case CheckType.CRC32:
  26. break;
  27. case CheckType.CRC64:
  28. break;
  29. case CheckType.SHA256:
  30. throw new NotImplementedException();
  31. default:
  32. throw new NotSupportedException("Check Type unknown to this version of decoder.");
  33. }
  34. }
  35. public XZHeader Header { get; private set; }
  36. public XZIndex Index { get; private set; }
  37. public XZFooter Footer { get; private set; }
  38. public bool HeaderIsRead { get; private set; }
  39. private XZBlock _currentBlock;
  40. private bool _endOfStream;
  41. public XZStream(Stream stream) : base(stream)
  42. {
  43. }
  44. public override int Read(byte[] buffer, int offset, int count)
  45. {
  46. int bytesRead = 0;
  47. if (_endOfStream)
  48. return bytesRead;
  49. if (!HeaderIsRead)
  50. ReadHeader();
  51. bytesRead = ReadBlocks(buffer, offset, count);
  52. if (bytesRead < count)
  53. {
  54. _endOfStream = true;
  55. ReadIndex();
  56. ReadFooter();
  57. }
  58. return bytesRead;
  59. }
  60. private void ReadHeader()
  61. {
  62. Header = XZHeader.FromStream(BaseStream);
  63. AssertBlockCheckTypeIsSupported();
  64. HeaderIsRead = true;
  65. }
  66. private void ReadIndex()
  67. {
  68. Index = XZIndex.FromStream(BaseStream, true);
  69. // TODO veryfy Index
  70. }
  71. private void ReadFooter()
  72. {
  73. Footer = XZFooter.FromStream(BaseStream);
  74. // TODO verify footer
  75. }
  76. private int ReadBlocks(byte[] buffer, int offset, int count)
  77. {
  78. int bytesRead = 0;
  79. if (_currentBlock == null)
  80. NextBlock();
  81. for (;;)
  82. {
  83. try
  84. {
  85. if (bytesRead >= count)
  86. break;
  87. int remaining = count - bytesRead;
  88. int newOffset = offset + bytesRead;
  89. int justRead = _currentBlock.Read(buffer, newOffset, remaining);
  90. if (justRead < remaining)
  91. NextBlock();
  92. bytesRead += justRead;
  93. }
  94. catch (XZIndexMarkerReachedException)
  95. {
  96. break;
  97. }
  98. }
  99. return bytesRead;
  100. }
  101. private void NextBlock()
  102. {
  103. _currentBlock = new XZBlock(BaseStream, Header.BlockCheckType, Header.BlockCheckSize);
  104. }
  105. }
  106. }