RarHeader.cs 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. using System;
  2. using System.IO;
  3. using SharpCompress.IO;
  4. namespace SharpCompress.Common.Rar.Headers
  5. {
  6. // http://www.forensicswiki.org/w/images/5/5b/RARFileStructure.txt
  7. // https://www.rarlab.com/technote.htm
  8. internal class RarHeader : IRarHeader
  9. {
  10. private readonly HeaderType _headerType;
  11. private readonly bool _isRar5;
  12. internal static RarHeader TryReadBase(RarCrcBinaryReader reader, bool isRar5, ArchiveEncoding archiveEncoding)
  13. {
  14. try
  15. {
  16. return new RarHeader(reader, isRar5, archiveEncoding);
  17. }
  18. catch (EndOfStreamException)
  19. {
  20. return null;
  21. }
  22. }
  23. private RarHeader(RarCrcBinaryReader reader, bool isRar5, ArchiveEncoding archiveEncoding)
  24. {
  25. _headerType = HeaderType.Null;
  26. _isRar5 = isRar5;
  27. ArchiveEncoding = archiveEncoding;
  28. if (IsRar5)
  29. {
  30. HeaderCrc = reader.ReadUInt32();
  31. reader.ResetCrc();
  32. HeaderSize = (int)reader.ReadRarVIntUInt32(3);
  33. reader.Mark();
  34. HeaderCode = reader.ReadRarVIntByte();
  35. HeaderFlags = reader.ReadRarVIntUInt16(2);
  36. if (HasHeaderFlag(HeaderFlagsV5.HAS_EXTRA))
  37. {
  38. ExtraSize = reader.ReadRarVIntUInt32();
  39. }
  40. if (HasHeaderFlag(HeaderFlagsV5.HAS_DATA))
  41. {
  42. AdditionalDataSize = (long)reader.ReadRarVInt();
  43. }
  44. } else {
  45. reader.Mark();
  46. HeaderCrc = reader.ReadUInt16();
  47. reader.ResetCrc();
  48. HeaderCode = reader.ReadByte();
  49. HeaderFlags = reader.ReadUInt16();
  50. HeaderSize = reader.ReadInt16();
  51. if (HasHeaderFlag(HeaderFlagsV4.HAS_DATA))
  52. {
  53. AdditionalDataSize = reader.ReadUInt32();
  54. }
  55. }
  56. }
  57. protected RarHeader(RarHeader header, RarCrcBinaryReader reader, HeaderType headerType) {
  58. _headerType = headerType;
  59. _isRar5 = header.IsRar5;
  60. HeaderCrc = header.HeaderCrc;
  61. HeaderCode = header.HeaderCode;
  62. HeaderFlags = header.HeaderFlags;
  63. HeaderSize = header.HeaderSize;
  64. ExtraSize = header.ExtraSize;
  65. AdditionalDataSize = header.AdditionalDataSize;
  66. ArchiveEncoding = header.ArchiveEncoding;
  67. ReadFinish(reader);
  68. int n = RemainingHeaderBytes(reader);
  69. if (n > 0)
  70. {
  71. reader.ReadBytes(n);
  72. }
  73. VerifyHeaderCrc(reader.GetCrc32());
  74. }
  75. protected int RemainingHeaderBytes(MarkingBinaryReader reader) {
  76. return checked(HeaderSize - (int)reader.CurrentReadByteCount);
  77. }
  78. protected virtual void ReadFinish(MarkingBinaryReader reader)
  79. {
  80. throw new NotImplementedException();
  81. }
  82. private void VerifyHeaderCrc(uint crc32)
  83. {
  84. var b = (IsRar5 ? crc32 : (ushort)crc32) == HeaderCrc;
  85. if (!b)
  86. {
  87. throw new InvalidFormatException("rar header crc mismatch");
  88. }
  89. }
  90. public HeaderType HeaderType => _headerType;
  91. protected bool IsRar5 => _isRar5;
  92. protected uint HeaderCrc { get; }
  93. internal byte HeaderCode { get; }
  94. protected ushort HeaderFlags { get; }
  95. protected bool HasHeaderFlag(ushort flag)
  96. {
  97. return (HeaderFlags & flag) == flag;
  98. }
  99. protected int HeaderSize { get; }
  100. internal ArchiveEncoding ArchiveEncoding { get; }
  101. /// <summary>
  102. /// Extra header size.
  103. /// </summary>
  104. protected uint ExtraSize { get; }
  105. /// <summary>
  106. /// Size of additional data (eg file contents)
  107. /// </summary>
  108. protected long AdditionalDataSize { get; }
  109. }
  110. }