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