XzIn.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. /* XzIn.c - Xz input
  2. 2015-11-08 : Igor Pavlov : Public domain */
  3. #include "Precomp.h"
  4. #include <string.h>
  5. #include "7zCrc.h"
  6. #include "CpuArch.h"
  7. #include "Xz.h"
  8. SRes Xz_ReadHeader(CXzStreamFlags *p, ISeqInStream *inStream)
  9. {
  10. Byte sig[XZ_STREAM_HEADER_SIZE];
  11. RINOK(SeqInStream_Read2(inStream, sig, XZ_STREAM_HEADER_SIZE, SZ_ERROR_NO_ARCHIVE));
  12. if (memcmp(sig, XZ_SIG, XZ_SIG_SIZE) != 0)
  13. return SZ_ERROR_NO_ARCHIVE;
  14. return Xz_ParseHeader(p, sig);
  15. }
  16. #define READ_VARINT_AND_CHECK(buf, pos, size, res) \
  17. { unsigned s = Xz_ReadVarInt(buf + pos, size - pos, res); \
  18. if (s == 0) return SZ_ERROR_ARCHIVE; pos += s; }
  19. SRes XzBlock_ReadHeader(CXzBlock *p, ISeqInStream *inStream, Bool *isIndex, UInt32 *headerSizeRes)
  20. {
  21. Byte header[XZ_BLOCK_HEADER_SIZE_MAX];
  22. unsigned headerSize;
  23. *headerSizeRes = 0;
  24. RINOK(SeqInStream_ReadByte(inStream, &header[0]));
  25. headerSize = ((unsigned)header[0] << 2) + 4;
  26. if (headerSize == 0)
  27. {
  28. *headerSizeRes = 1;
  29. *isIndex = True;
  30. return SZ_OK;
  31. }
  32. *isIndex = False;
  33. *headerSizeRes = headerSize;
  34. RINOK(SeqInStream_Read(inStream, header + 1, headerSize - 1));
  35. return XzBlock_Parse(p, header);
  36. }
  37. #define ADD_SIZE_CHECH(size, val) \
  38. { UInt64 newSize = size + (val); if (newSize < size) return XZ_SIZE_OVERFLOW; size = newSize; }
  39. UInt64 Xz_GetUnpackSize(const CXzStream *p)
  40. {
  41. UInt64 size = 0;
  42. size_t i;
  43. for (i = 0; i < p->numBlocks; i++)
  44. ADD_SIZE_CHECH(size, p->blocks[i].unpackSize);
  45. return size;
  46. }
  47. UInt64 Xz_GetPackSize(const CXzStream *p)
  48. {
  49. UInt64 size = 0;
  50. size_t i;
  51. for (i = 0; i < p->numBlocks; i++)
  52. ADD_SIZE_CHECH(size, (p->blocks[i].totalSize + 3) & ~(UInt64)3);
  53. return size;
  54. }
  55. /*
  56. SRes XzBlock_ReadFooter(CXzBlock *p, CXzStreamFlags f, ISeqInStream *inStream)
  57. {
  58. return SeqInStream_Read(inStream, p->check, XzFlags_GetCheckSize(f));
  59. }
  60. */
  61. static SRes Xz_ReadIndex2(CXzStream *p, const Byte *buf, size_t size, ISzAlloc *alloc)
  62. {
  63. size_t numBlocks, pos = 1;
  64. UInt32 crc;
  65. if (size < 5 || buf[0] != 0)
  66. return SZ_ERROR_ARCHIVE;
  67. size -= 4;
  68. crc = CrcCalc(buf, size);
  69. if (crc != GetUi32(buf + size))
  70. return SZ_ERROR_ARCHIVE;
  71. {
  72. UInt64 numBlocks64;
  73. READ_VARINT_AND_CHECK(buf, pos, size, &numBlocks64);
  74. numBlocks = (size_t)numBlocks64;
  75. if (numBlocks != numBlocks64 || numBlocks * 2 > size)
  76. return SZ_ERROR_ARCHIVE;
  77. }
  78. Xz_Free(p, alloc);
  79. if (numBlocks != 0)
  80. {
  81. size_t i;
  82. p->numBlocks = numBlocks;
  83. p->numBlocksAllocated = numBlocks;
  84. p->blocks = alloc->Alloc(alloc, sizeof(CXzBlockSizes) * numBlocks);
  85. if (p->blocks == 0)
  86. return SZ_ERROR_MEM;
  87. for (i = 0; i < numBlocks; i++)
  88. {
  89. CXzBlockSizes *block = &p->blocks[i];
  90. READ_VARINT_AND_CHECK(buf, pos, size, &block->totalSize);
  91. READ_VARINT_AND_CHECK(buf, pos, size, &block->unpackSize);
  92. if (block->totalSize == 0)
  93. return SZ_ERROR_ARCHIVE;
  94. }
  95. }
  96. while ((pos & 3) != 0)
  97. if (buf[pos++] != 0)
  98. return SZ_ERROR_ARCHIVE;
  99. return (pos == size) ? SZ_OK : SZ_ERROR_ARCHIVE;
  100. }
  101. static SRes Xz_ReadIndex(CXzStream *p, ILookInStream *stream, UInt64 indexSize, ISzAlloc *alloc)
  102. {
  103. SRes res;
  104. size_t size;
  105. Byte *buf;
  106. if (indexSize > ((UInt32)1 << 31))
  107. return SZ_ERROR_UNSUPPORTED;
  108. size = (size_t)indexSize;
  109. if (size != indexSize)
  110. return SZ_ERROR_UNSUPPORTED;
  111. buf = alloc->Alloc(alloc, size);
  112. if (buf == 0)
  113. return SZ_ERROR_MEM;
  114. res = LookInStream_Read2(stream, buf, size, SZ_ERROR_UNSUPPORTED);
  115. if (res == SZ_OK)
  116. res = Xz_ReadIndex2(p, buf, size, alloc);
  117. alloc->Free(alloc, buf);
  118. return res;
  119. }
  120. static SRes LookInStream_SeekRead_ForArc(ILookInStream *stream, UInt64 offset, void *buf, size_t size)
  121. {
  122. RINOK(LookInStream_SeekTo(stream, offset));
  123. return LookInStream_Read(stream, buf, size);
  124. /* return LookInStream_Read2(stream, buf, size, SZ_ERROR_NO_ARCHIVE); */
  125. }
  126. static SRes Xz_ReadBackward(CXzStream *p, ILookInStream *stream, Int64 *startOffset, ISzAlloc *alloc)
  127. {
  128. UInt64 indexSize;
  129. Byte buf[XZ_STREAM_FOOTER_SIZE];
  130. UInt64 pos = *startOffset;
  131. if ((pos & 3) != 0 || pos < XZ_STREAM_FOOTER_SIZE)
  132. return SZ_ERROR_NO_ARCHIVE;
  133. pos -= XZ_STREAM_FOOTER_SIZE;
  134. RINOK(LookInStream_SeekRead_ForArc(stream, pos, buf, XZ_STREAM_FOOTER_SIZE));
  135. if (memcmp(buf + 10, XZ_FOOTER_SIG, XZ_FOOTER_SIG_SIZE) != 0)
  136. {
  137. UInt32 total = 0;
  138. pos += XZ_STREAM_FOOTER_SIZE;
  139. for (;;)
  140. {
  141. size_t i;
  142. #define TEMP_BUF_SIZE (1 << 10)
  143. Byte temp[TEMP_BUF_SIZE];
  144. i = (pos > TEMP_BUF_SIZE) ? TEMP_BUF_SIZE : (size_t)pos;
  145. pos -= i;
  146. RINOK(LookInStream_SeekRead_ForArc(stream, pos, temp, i));
  147. total += (UInt32)i;
  148. for (; i != 0; i--)
  149. if (temp[i - 1] != 0)
  150. break;
  151. if (i != 0)
  152. {
  153. if ((i & 3) != 0)
  154. return SZ_ERROR_NO_ARCHIVE;
  155. pos += i;
  156. break;
  157. }
  158. if (pos < XZ_STREAM_FOOTER_SIZE || total > (1 << 16))
  159. return SZ_ERROR_NO_ARCHIVE;
  160. }
  161. if (pos < XZ_STREAM_FOOTER_SIZE)
  162. return SZ_ERROR_NO_ARCHIVE;
  163. pos -= XZ_STREAM_FOOTER_SIZE;
  164. RINOK(LookInStream_SeekRead_ForArc(stream, pos, buf, XZ_STREAM_FOOTER_SIZE));
  165. if (memcmp(buf + 10, XZ_FOOTER_SIG, XZ_FOOTER_SIG_SIZE) != 0)
  166. return SZ_ERROR_NO_ARCHIVE;
  167. }
  168. p->flags = (CXzStreamFlags)GetBe16(buf + 8);
  169. if (!XzFlags_IsSupported(p->flags))
  170. return SZ_ERROR_UNSUPPORTED;
  171. if (GetUi32(buf) != CrcCalc(buf + 4, 6))
  172. return SZ_ERROR_ARCHIVE;
  173. indexSize = ((UInt64)GetUi32(buf + 4) + 1) << 2;
  174. if (pos < indexSize)
  175. return SZ_ERROR_ARCHIVE;
  176. pos -= indexSize;
  177. RINOK(LookInStream_SeekTo(stream, pos));
  178. RINOK(Xz_ReadIndex(p, stream, indexSize, alloc));
  179. {
  180. UInt64 totalSize = Xz_GetPackSize(p);
  181. if (totalSize == XZ_SIZE_OVERFLOW
  182. || totalSize >= ((UInt64)1 << 63)
  183. || pos < totalSize + XZ_STREAM_HEADER_SIZE)
  184. return SZ_ERROR_ARCHIVE;
  185. pos -= (totalSize + XZ_STREAM_HEADER_SIZE);
  186. RINOK(LookInStream_SeekTo(stream, pos));
  187. *startOffset = pos;
  188. }
  189. {
  190. CXzStreamFlags headerFlags;
  191. CSecToRead secToRead;
  192. SecToRead_CreateVTable(&secToRead);
  193. secToRead.realStream = stream;
  194. RINOK(Xz_ReadHeader(&headerFlags, &secToRead.s));
  195. return (p->flags == headerFlags) ? SZ_OK : SZ_ERROR_ARCHIVE;
  196. }
  197. }
  198. /* ---------- Xz Streams ---------- */
  199. void Xzs_Construct(CXzs *p)
  200. {
  201. p->num = p->numAllocated = 0;
  202. p->streams = 0;
  203. }
  204. void Xzs_Free(CXzs *p, ISzAlloc *alloc)
  205. {
  206. size_t i;
  207. for (i = 0; i < p->num; i++)
  208. Xz_Free(&p->streams[i], alloc);
  209. alloc->Free(alloc, p->streams);
  210. p->num = p->numAllocated = 0;
  211. p->streams = 0;
  212. }
  213. UInt64 Xzs_GetNumBlocks(const CXzs *p)
  214. {
  215. UInt64 num = 0;
  216. size_t i;
  217. for (i = 0; i < p->num; i++)
  218. num += p->streams[i].numBlocks;
  219. return num;
  220. }
  221. UInt64 Xzs_GetUnpackSize(const CXzs *p)
  222. {
  223. UInt64 size = 0;
  224. size_t i;
  225. for (i = 0; i < p->num; i++)
  226. ADD_SIZE_CHECH(size, Xz_GetUnpackSize(&p->streams[i]));
  227. return size;
  228. }
  229. /*
  230. UInt64 Xzs_GetPackSize(const CXzs *p)
  231. {
  232. UInt64 size = 0;
  233. size_t i;
  234. for (i = 0; i < p->num; i++)
  235. ADD_SIZE_CHECH(size, Xz_GetTotalSize(&p->streams[i]));
  236. return size;
  237. }
  238. */
  239. SRes Xzs_ReadBackward(CXzs *p, ILookInStream *stream, Int64 *startOffset, ICompressProgress *progress, ISzAlloc *alloc)
  240. {
  241. Int64 endOffset = 0;
  242. RINOK(stream->Seek(stream, &endOffset, SZ_SEEK_END));
  243. *startOffset = endOffset;
  244. for (;;)
  245. {
  246. CXzStream st;
  247. SRes res;
  248. Xz_Construct(&st);
  249. res = Xz_ReadBackward(&st, stream, startOffset, alloc);
  250. st.startOffset = *startOffset;
  251. RINOK(res);
  252. if (p->num == p->numAllocated)
  253. {
  254. size_t newNum = p->num + p->num / 4 + 1;
  255. Byte *data = (Byte *)alloc->Alloc(alloc, newNum * sizeof(CXzStream));
  256. if (data == 0)
  257. return SZ_ERROR_MEM;
  258. p->numAllocated = newNum;
  259. if (p->num != 0)
  260. memcpy(data, p->streams, p->num * sizeof(CXzStream));
  261. alloc->Free(alloc, p->streams);
  262. p->streams = (CXzStream *)data;
  263. }
  264. p->streams[p->num++] = st;
  265. if (*startOffset == 0)
  266. break;
  267. RINOK(LookInStream_SeekTo(stream, *startOffset));
  268. if (progress && progress->Progress(progress, endOffset - *startOffset, (UInt64)(Int64)-1) != SZ_OK)
  269. return SZ_ERROR_PROGRESS;
  270. }
  271. return SZ_OK;
  272. }