LocalEntryHeaderExtraFactory.cs 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. using System;
  2. using System.Text;
  3. using SharpCompress.Converters;
  4. namespace SharpCompress.Common.Zip.Headers
  5. {
  6. internal enum ExtraDataType : ushort
  7. {
  8. WinZipAes = 0x9901,
  9. NotImplementedExtraData = 0xFFFF,
  10. // Third Party Mappings
  11. // -Info-ZIP Unicode Path Extra Field
  12. UnicodePathExtraField = 0x7075,
  13. Zip64ExtendedInformationExtraField = 0x0001
  14. }
  15. internal class ExtraData
  16. {
  17. internal ExtraDataType Type { get; set; }
  18. internal ushort Length { get; set; }
  19. internal byte[] DataBytes { get; set; }
  20. }
  21. internal class ExtraUnicodePathExtraField : ExtraData
  22. {
  23. internal byte Version => DataBytes[0];
  24. internal byte[] NameCrc32
  25. {
  26. get
  27. {
  28. var crc = new byte[4];
  29. Buffer.BlockCopy(DataBytes, 1, crc, 0, 4);
  30. return crc;
  31. }
  32. }
  33. internal string UnicodeName
  34. {
  35. get
  36. {
  37. // PathNamelength = dataLength - Version(1 byte) - NameCRC32(4 bytes)
  38. var length = Length - 5;
  39. var nameStr = Encoding.UTF8.GetString(DataBytes, 5, length);
  40. return nameStr;
  41. }
  42. }
  43. }
  44. internal class Zip64ExtendedInformationExtraField : ExtraData
  45. {
  46. public Zip64ExtendedInformationExtraField(ExtraDataType type, ushort length, byte[] dataBytes)
  47. {
  48. Type = type;
  49. Length = length;
  50. DataBytes = dataBytes;
  51. Process();
  52. }
  53. //From the spec values are only in the extradata if the standard
  54. //value is set to 0xFFFF, but if one of the sizes are present, both are.
  55. //Hence if length == 4 volume only
  56. // if length == 8 offset only
  57. // if length == 12 offset + volume
  58. // if length == 16 sizes only
  59. // if length == 20 sizes + volume
  60. // if length == 24 sizes + offset
  61. // if length == 28 everything.
  62. //It is unclear how many of these are used in the wild.
  63. private void Process()
  64. {
  65. switch (DataBytes.Length)
  66. {
  67. case 4:
  68. VolumeNumber = DataConverter.LittleEndian.GetUInt32(DataBytes, 0);
  69. return;
  70. case 8:
  71. RelativeOffsetOfEntryHeader = (long)DataConverter.LittleEndian.GetUInt64(DataBytes, 0);
  72. return;
  73. case 12:
  74. RelativeOffsetOfEntryHeader = (long)DataConverter.LittleEndian.GetUInt64(DataBytes, 0);
  75. VolumeNumber = DataConverter.LittleEndian.GetUInt32(DataBytes, 8);
  76. return;
  77. case 16:
  78. UncompressedSize = (long)DataConverter.LittleEndian.GetUInt64(DataBytes, 0);
  79. CompressedSize = (long)DataConverter.LittleEndian.GetUInt64(DataBytes, 8);
  80. return;
  81. case 20:
  82. UncompressedSize = (long)DataConverter.LittleEndian.GetUInt64(DataBytes, 0);
  83. CompressedSize = (long)DataConverter.LittleEndian.GetUInt64(DataBytes, 8);
  84. VolumeNumber = DataConverter.LittleEndian.GetUInt32(DataBytes, 16);
  85. return;
  86. case 24:
  87. UncompressedSize = (long)DataConverter.LittleEndian.GetUInt64(DataBytes, 0);
  88. CompressedSize = (long)DataConverter.LittleEndian.GetUInt64(DataBytes, 8);
  89. RelativeOffsetOfEntryHeader = (long)DataConverter.LittleEndian.GetUInt64(DataBytes, 16);
  90. return;
  91. case 28:
  92. UncompressedSize = (long)DataConverter.LittleEndian.GetUInt64(DataBytes, 0);
  93. CompressedSize = (long)DataConverter.LittleEndian.GetUInt64(DataBytes, 8);
  94. RelativeOffsetOfEntryHeader = (long)DataConverter.LittleEndian.GetUInt64(DataBytes, 16);
  95. VolumeNumber = DataConverter.LittleEndian.GetUInt32(DataBytes, 24);
  96. return;
  97. default:
  98. throw new ArchiveException("Unexpected size of of Zip64 extended information extra field");
  99. }
  100. }
  101. public long UncompressedSize { get; private set; }
  102. public long CompressedSize { get; private set; }
  103. public long RelativeOffsetOfEntryHeader { get; private set; }
  104. public uint VolumeNumber { get; private set; }
  105. }
  106. internal static class LocalEntryHeaderExtraFactory
  107. {
  108. internal static ExtraData Create(ExtraDataType type, ushort length, byte[] extraData)
  109. {
  110. switch (type)
  111. {
  112. case ExtraDataType.UnicodePathExtraField:
  113. return new ExtraUnicodePathExtraField
  114. {
  115. Type = type,
  116. Length = length,
  117. DataBytes = extraData
  118. };
  119. case ExtraDataType.Zip64ExtendedInformationExtraField:
  120. return new Zip64ExtendedInformationExtraField
  121. (
  122. type,
  123. length,
  124. extraData
  125. );
  126. default:
  127. return new ExtraData
  128. {
  129. Type = type,
  130. Length = length,
  131. DataBytes = extraData
  132. };
  133. }
  134. }
  135. }
  136. }