Merge pull request #511 from negativeExponent/updates
[pcsx_rearmed.git] / deps / lzma-16.04 / C / XzIn.c
CommitLineData
ce188d4d 1/* XzIn.c - Xz input\r
22015-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
12SRes 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
25SRes 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
48UInt64 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
57UInt64 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
67SRes 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
73static 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
118static 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
138static 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
145static 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
235void Xzs_Construct(CXzs *p)\r
236{\r
237 p->num = p->numAllocated = 0;\r
238 p->streams = 0;\r
239}\r
240\r
241void 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
251UInt64 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
260UInt64 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
270UInt64 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
280SRes 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