aboutsummaryrefslogtreecommitdiff
path: root/C/XzIn.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--C/XzIn.c265
1 files changed, 155 insertions, 110 deletions
diff --git a/C/XzIn.c b/C/XzIn.c
index b68af96..ba31636 100644
--- a/C/XzIn.c
+++ b/C/XzIn.c
@@ -1,38 +1,39 @@
1/* XzIn.c - Xz input 1/* XzIn.c - Xz input
22023-09-07 : Igor Pavlov : Public domain */ 2: Igor Pavlov : Public domain */
3 3
4#include "Precomp.h" 4#include "Precomp.h"
5 5
6#include <string.h> 6#include <string.h>
7 7
8#include "7zCrc.h" 8#include "7zCrc.h"
9#include "CpuArch.h"
10#include "Xz.h" 9#include "Xz.h"
10#include "CpuArch.h"
11 11
12/* 12#define XZ_FOOTER_12B_ALIGNED16_SIG_CHECK(p) \
13#define XZ_FOOTER_SIG_CHECK(p) (memcmp((p), XZ_FOOTER_SIG, XZ_FOOTER_SIG_SIZE) == 0) 13 (GetUi16a((const Byte *)(const void *)(p) + 10) == \
14*/ 14 (XZ_FOOTER_SIG_0 | (XZ_FOOTER_SIG_1 << 8)))
15#define XZ_FOOTER_SIG_CHECK(p) ((p)[0] == XZ_FOOTER_SIG_0 && (p)[1] == XZ_FOOTER_SIG_1)
16
17 15
18SRes Xz_ReadHeader(CXzStreamFlags *p, ISeqInStreamPtr inStream) 16SRes Xz_ReadHeader(CXzStreamFlags *p, ISeqInStreamPtr inStream)
19{ 17{
20 Byte sig[XZ_STREAM_HEADER_SIZE]; 18 UInt32 data32[XZ_STREAM_HEADER_SIZE / 4];
21 size_t processedSize = XZ_STREAM_HEADER_SIZE; 19 size_t processedSize = XZ_STREAM_HEADER_SIZE;
22 RINOK(SeqInStream_ReadMax(inStream, sig, &processedSize)) 20 RINOK(SeqInStream_ReadMax(inStream, data32, &processedSize))
23 if (processedSize != XZ_STREAM_HEADER_SIZE 21 if (processedSize != XZ_STREAM_HEADER_SIZE
24 || memcmp(sig, XZ_SIG, XZ_SIG_SIZE) != 0) 22 || memcmp(data32, XZ_SIG, XZ_SIG_SIZE) != 0)
25 return SZ_ERROR_NO_ARCHIVE; 23 return SZ_ERROR_NO_ARCHIVE;
26 return Xz_ParseHeader(p, sig); 24 return Xz_ParseHeader(p, (const Byte *)(const void *)data32);
27} 25}
28 26
29#define READ_VARINT_AND_CHECK(buf, pos, size, res) \ 27#define READ_VARINT_AND_CHECK(buf, size, res) \
30 { const unsigned s = Xz_ReadVarInt(buf + pos, size - pos, res); \ 28{ const unsigned s = Xz_ReadVarInt(buf, size, res); \
31 if (s == 0) return SZ_ERROR_ARCHIVE; \ 29 if (s == 0) return SZ_ERROR_ARCHIVE; \
32 pos += s; } 30 size -= s; \
31 buf += s; \
32}
33 33
34SRes XzBlock_ReadHeader(CXzBlock *p, ISeqInStreamPtr inStream, BoolInt *isIndex, UInt32 *headerSizeRes) 34SRes XzBlock_ReadHeader(CXzBlock *p, ISeqInStreamPtr inStream, BoolInt *isIndex, UInt32 *headerSizeRes)
35{ 35{
36 MY_ALIGN(4)
36 Byte header[XZ_BLOCK_HEADER_SIZE_MAX]; 37 Byte header[XZ_BLOCK_HEADER_SIZE_MAX];
37 unsigned headerSize; 38 unsigned headerSize;
38 *headerSizeRes = 0; 39 *headerSizeRes = 0;
@@ -57,8 +58,12 @@ SRes XzBlock_ReadHeader(CXzBlock *p, ISeqInStreamPtr inStream, BoolInt *isIndex,
57 return XzBlock_Parse(p, header); 58 return XzBlock_Parse(p, header);
58} 59}
59 60
61
60#define ADD_SIZE_CHECK(size, val) \ 62#define ADD_SIZE_CHECK(size, val) \
61 { const UInt64 newSize = size + (val); if (newSize < size) return XZ_SIZE_OVERFLOW; size = newSize; } 63{ const UInt64 newSize = size + (val); \
64 if (newSize < size) return XZ_SIZE_OVERFLOW; \
65 size = newSize; \
66}
62 67
63UInt64 Xz_GetUnpackSize(const CXzStream *p) 68UInt64 Xz_GetUnpackSize(const CXzStream *p)
64{ 69{
@@ -82,76 +87,85 @@ UInt64 Xz_GetPackSize(const CXzStream *p)
82 return size; 87 return size;
83} 88}
84 89
85/*
86SRes XzBlock_ReadFooter(CXzBlock *p, CXzStreamFlags f, ISeqInStreamPtr inStream)
87{
88 return SeqInStream_Read(inStream, p->check, XzFlags_GetCheckSize(f));
89}
90*/
91 90
92static SRes Xz_ReadIndex2(CXzStream *p, const Byte *buf, size_t size, ISzAllocPtr alloc) 91// input;
92// CXzStream (p) is empty object.
93// size != 0
94// (size & 3) == 0
95// (buf) is aligned for at least 4 bytes.
96// output:
97// p->numBlocks is number of allocated items in p->blocks
98// p->blocks[*] values must be ignored, if function returns error.
99static SRes Xz_ParseIndex(CXzStream *p, const Byte *buf, size_t size, ISzAllocPtr alloc)
93{ 100{
94 size_t numBlocks, pos = 1; 101 size_t numBlocks;
95 UInt32 crc;
96
97 if (size < 5 || buf[0] != 0) 102 if (size < 5 || buf[0] != 0)
98 return SZ_ERROR_ARCHIVE; 103 return SZ_ERROR_ARCHIVE;
99
100 size -= 4; 104 size -= 4;
101 crc = CrcCalc(buf, size); 105 {
102 if (crc != GetUi32(buf + size)) 106 const UInt32 crc = CrcCalc(buf, size);
103 return SZ_ERROR_ARCHIVE; 107 if (crc != GetUi32a(buf + size))
104 108 return SZ_ERROR_ARCHIVE;
109 }
110 buf++;
111 size--;
105 { 112 {
106 UInt64 numBlocks64; 113 UInt64 numBlocks64;
107 READ_VARINT_AND_CHECK(buf, pos, size, &numBlocks64) 114 READ_VARINT_AND_CHECK(buf, size, &numBlocks64)
108 numBlocks = (size_t)numBlocks64; 115 // (numBlocks64) is 63-bit value, so we can calculate (numBlocks64 * 2):
109 if (numBlocks != numBlocks64 || numBlocks * 2 > size) 116 if (numBlocks64 * 2 > size)
110 return SZ_ERROR_ARCHIVE; 117 return SZ_ERROR_ARCHIVE;
118 if (numBlocks64 >= ((size_t)1 << (sizeof(size_t) * 8 - 1)) / sizeof(CXzBlockSizes))
119 return SZ_ERROR_MEM; // SZ_ERROR_ARCHIVE
120 numBlocks = (size_t)numBlocks64;
111 } 121 }
112 122 // Xz_Free(p, alloc); // it's optional, because (p) is empty already
113 Xz_Free(p, alloc); 123 if (numBlocks)
114 if (numBlocks != 0)
115 { 124 {
116 size_t i; 125 CXzBlockSizes *blocks = (CXzBlockSizes *)ISzAlloc_Alloc(alloc, sizeof(CXzBlockSizes) * numBlocks);
117 p->numBlocks = numBlocks; 126 if (!blocks)
118 p->blocks = (CXzBlockSizes *)ISzAlloc_Alloc(alloc, sizeof(CXzBlockSizes) * numBlocks);
119 if (!p->blocks)
120 return SZ_ERROR_MEM; 127 return SZ_ERROR_MEM;
121 for (i = 0; i < numBlocks; i++) 128 p->blocks = blocks;
129 p->numBlocks = numBlocks;
130 // the caller will call Xz_Free() in case of error
131 do
122 { 132 {
123 CXzBlockSizes *block = &p->blocks[i]; 133 READ_VARINT_AND_CHECK(buf, size, &blocks->totalSize)
124 READ_VARINT_AND_CHECK(buf, pos, size, &block->totalSize) 134 READ_VARINT_AND_CHECK(buf, size, &blocks->unpackSize)
125 READ_VARINT_AND_CHECK(buf, pos, size, &block->unpackSize) 135 if (blocks->totalSize == 0)
126 if (block->totalSize == 0)
127 return SZ_ERROR_ARCHIVE; 136 return SZ_ERROR_ARCHIVE;
137 blocks++;
128 } 138 }
139 while (--numBlocks);
129 } 140 }
130 while ((pos & 3) != 0) 141 if (size >= 4)
131 if (buf[pos++] != 0) 142 return SZ_ERROR_ARCHIVE;
143 while (size)
144 if (buf[--size])
132 return SZ_ERROR_ARCHIVE; 145 return SZ_ERROR_ARCHIVE;
133 return (pos == size) ? SZ_OK : SZ_ERROR_ARCHIVE; 146 return SZ_OK;
134} 147}
135 148
149
150/*
136static SRes Xz_ReadIndex(CXzStream *p, ILookInStreamPtr stream, UInt64 indexSize, ISzAllocPtr alloc) 151static SRes Xz_ReadIndex(CXzStream *p, ILookInStreamPtr stream, UInt64 indexSize, ISzAllocPtr alloc)
137{ 152{
138 SRes res; 153 SRes res;
139 size_t size; 154 size_t size;
140 Byte *buf; 155 Byte *buf;
141 if (indexSize > ((UInt32)1 << 31)) 156 if (indexSize >= ((size_t)1 << (sizeof(size_t) * 8 - 1)))
142 return SZ_ERROR_UNSUPPORTED; 157 return SZ_ERROR_MEM; // SZ_ERROR_ARCHIVE
143 size = (size_t)indexSize; 158 size = (size_t)indexSize;
144 if (size != indexSize)
145 return SZ_ERROR_UNSUPPORTED;
146 buf = (Byte *)ISzAlloc_Alloc(alloc, size); 159 buf = (Byte *)ISzAlloc_Alloc(alloc, size);
147 if (!buf) 160 if (!buf)
148 return SZ_ERROR_MEM; 161 return SZ_ERROR_MEM;
149 res = LookInStream_Read2(stream, buf, size, SZ_ERROR_UNSUPPORTED); 162 res = LookInStream_Read2(stream, buf, size, SZ_ERROR_UNSUPPORTED);
150 if (res == SZ_OK) 163 if (res == SZ_OK)
151 res = Xz_ReadIndex2(p, buf, size, alloc); 164 res = Xz_ParseIndex(p, buf, size, alloc);
152 ISzAlloc_Free(alloc, buf); 165 ISzAlloc_Free(alloc, buf);
153 return res; 166 return res;
154} 167}
168*/
155 169
156static SRes LookInStream_SeekRead_ForArc(ILookInStreamPtr stream, UInt64 offset, void *buf, size_t size) 170static SRes LookInStream_SeekRead_ForArc(ILookInStreamPtr stream, UInt64 offset, void *buf, size_t size)
157{ 171{
@@ -160,84 +174,102 @@ static SRes LookInStream_SeekRead_ForArc(ILookInStreamPtr stream, UInt64 offset,
160 /* return LookInStream_Read2(stream, buf, size, SZ_ERROR_NO_ARCHIVE); */ 174 /* return LookInStream_Read2(stream, buf, size, SZ_ERROR_NO_ARCHIVE); */
161} 175}
162 176
177
178/*
179in:
180 (*startOffset) is position in (stream) where xz_stream must be finished.
181out:
182 if returns SZ_OK, then (*startOffset) is position in stream that shows start of xz_stream.
183*/
163static SRes Xz_ReadBackward(CXzStream *p, ILookInStreamPtr stream, Int64 *startOffset, ISzAllocPtr alloc) 184static SRes Xz_ReadBackward(CXzStream *p, ILookInStreamPtr stream, Int64 *startOffset, ISzAllocPtr alloc)
164{ 185{
165 UInt64 indexSize; 186 #define TEMP_BUF_SIZE (1 << 10)
166 Byte buf[XZ_STREAM_FOOTER_SIZE]; 187 UInt32 buf32[TEMP_BUF_SIZE / 4];
167 UInt64 pos = (UInt64)*startOffset; 188 UInt64 pos = (UInt64)*startOffset;
168 189
169 if ((pos & 3) != 0 || pos < XZ_STREAM_FOOTER_SIZE) 190 if ((pos & 3) || pos < XZ_STREAM_FOOTER_SIZE)
170 return SZ_ERROR_NO_ARCHIVE; 191 return SZ_ERROR_NO_ARCHIVE;
171
172 pos -= XZ_STREAM_FOOTER_SIZE; 192 pos -= XZ_STREAM_FOOTER_SIZE;
173 RINOK(LookInStream_SeekRead_ForArc(stream, pos, buf, XZ_STREAM_FOOTER_SIZE)) 193 RINOK(LookInStream_SeekRead_ForArc(stream, pos, buf32, XZ_STREAM_FOOTER_SIZE))
174 194
175 if (!XZ_FOOTER_SIG_CHECK(buf + 10)) 195 if (!XZ_FOOTER_12B_ALIGNED16_SIG_CHECK(buf32))
176 { 196 {
177 UInt32 total = 0;
178 pos += XZ_STREAM_FOOTER_SIZE; 197 pos += XZ_STREAM_FOOTER_SIZE;
179
180 for (;;) 198 for (;;)
181 { 199 {
182 size_t i; 200 // pos != 0
183 #define TEMP_BUF_SIZE (1 << 10) 201 // (pos & 3) == 0
184 Byte temp[TEMP_BUF_SIZE]; 202 size_t i = pos >= TEMP_BUF_SIZE ? TEMP_BUF_SIZE : (size_t)pos;
185
186 i = (pos > TEMP_BUF_SIZE) ? TEMP_BUF_SIZE : (size_t)pos;
187 pos -= i; 203 pos -= i;
188 RINOK(LookInStream_SeekRead_ForArc(stream, pos, temp, i)) 204 RINOK(LookInStream_SeekRead_ForArc(stream, pos, buf32, i))
189 total += (UInt32)i; 205 i /= 4;
190 for (; i != 0; i--) 206 do
191 if (temp[i - 1] != 0) 207 if (buf32[i - 1] != 0)
192 break; 208 break;
193 if (i != 0) 209 while (--i);
194 { 210
195 if ((i & 3) != 0) 211 pos += i * 4;
196 return SZ_ERROR_NO_ARCHIVE; 212 #define XZ_STREAM_BACKWARD_READING_PAD_MAX (1 << 16)
197 pos += i; 213 // here we don't support rare case with big padding for xz stream.
198 break; 214 // so we have padding limit for backward reading.
199 } 215 if ((UInt64)*startOffset - pos > XZ_STREAM_BACKWARD_READING_PAD_MAX)
200 if (pos < XZ_STREAM_FOOTER_SIZE || total > (1 << 16))
201 return SZ_ERROR_NO_ARCHIVE; 216 return SZ_ERROR_NO_ARCHIVE;
217 if (i)
218 break;
202 } 219 }
203 220 // we try to open xz stream after skipping zero padding.
221 // ((UInt64)*startOffset == pos) is possible here!
204 if (pos < XZ_STREAM_FOOTER_SIZE) 222 if (pos < XZ_STREAM_FOOTER_SIZE)
205 return SZ_ERROR_NO_ARCHIVE; 223 return SZ_ERROR_NO_ARCHIVE;
206 pos -= XZ_STREAM_FOOTER_SIZE; 224 pos -= XZ_STREAM_FOOTER_SIZE;
207 RINOK(LookInStream_SeekRead_ForArc(stream, pos, buf, XZ_STREAM_FOOTER_SIZE)) 225 RINOK(LookInStream_SeekRead_ForArc(stream, pos, buf32, XZ_STREAM_FOOTER_SIZE))
208 if (!XZ_FOOTER_SIG_CHECK(buf + 10)) 226 if (!XZ_FOOTER_12B_ALIGNED16_SIG_CHECK(buf32))
209 return SZ_ERROR_NO_ARCHIVE; 227 return SZ_ERROR_NO_ARCHIVE;
210 } 228 }
211 229
212 p->flags = (CXzStreamFlags)GetBe16(buf + 8); 230 p->flags = (CXzStreamFlags)GetBe16a(buf32 + 2);
213
214 if (!XzFlags_IsSupported(p->flags)) 231 if (!XzFlags_IsSupported(p->flags))
215 return SZ_ERROR_UNSUPPORTED; 232 return SZ_ERROR_UNSUPPORTED;
216
217 { 233 {
218 /* to eliminate GCC 6.3 warning: 234 /* to eliminate GCC 6.3 warning:
219 dereferencing type-punned pointer will break strict-aliasing rules */ 235 dereferencing type-punned pointer will break strict-aliasing rules */
220 const Byte *buf_ptr = buf; 236 const UInt32 *buf_ptr = buf32;
221 if (GetUi32(buf_ptr) != CrcCalc(buf + 4, 6)) 237 if (GetUi32a(buf_ptr) != CrcCalc(buf32 + 1, 6))
222 return SZ_ERROR_ARCHIVE; 238 return SZ_ERROR_ARCHIVE;
223 } 239 }
224
225 indexSize = ((UInt64)GetUi32(buf + 4) + 1) << 2;
226
227 if (pos < indexSize)
228 return SZ_ERROR_ARCHIVE;
229
230 pos -= indexSize;
231 RINOK(LookInStream_SeekTo(stream, pos))
232 RINOK(Xz_ReadIndex(p, stream, indexSize, alloc))
233
234 { 240 {
235 UInt64 totalSize = Xz_GetPackSize(p); 241 const UInt64 indexSize = ((UInt64)GetUi32a(buf32 + 1) + 1) << 2;
236 if (totalSize == XZ_SIZE_OVERFLOW 242 if (pos < indexSize)
237 || totalSize >= ((UInt64)1 << 63)
238 || pos < totalSize + XZ_STREAM_HEADER_SIZE)
239 return SZ_ERROR_ARCHIVE; 243 return SZ_ERROR_ARCHIVE;
240 pos -= (totalSize + XZ_STREAM_HEADER_SIZE); 244 pos -= indexSize;
245 // v25.00: relaxed indexSize check. We allow big index table.
246 // if (indexSize > ((UInt32)1 << 31))
247 if (indexSize >= ((size_t)1 << (sizeof(size_t) * 8 - 1)))
248 return SZ_ERROR_MEM; // SZ_ERROR_ARCHIVE
249 RINOK(LookInStream_SeekTo(stream, pos))
250 // RINOK(Xz_ReadIndex(p, stream, indexSize, alloc))
251 {
252 SRes res;
253 const size_t size = (size_t)indexSize;
254 // if (size != indexSize) return SZ_ERROR_UNSUPPORTED;
255 Byte *buf = (Byte *)ISzAlloc_Alloc(alloc, size);
256 if (!buf)
257 return SZ_ERROR_MEM;
258 res = LookInStream_Read2(stream, buf, size, SZ_ERROR_UNSUPPORTED);
259 if (res == SZ_OK)
260 res = Xz_ParseIndex(p, buf, size, alloc);
261 ISzAlloc_Free(alloc, buf);
262 RINOK(res)
263 }
264 }
265 {
266 UInt64 total = Xz_GetPackSize(p);
267 if (total == XZ_SIZE_OVERFLOW || total >= ((UInt64)1 << 63))
268 return SZ_ERROR_ARCHIVE;
269 total += XZ_STREAM_HEADER_SIZE;
270 if (pos < total)
271 return SZ_ERROR_ARCHIVE;
272 pos -= total;
241 RINOK(LookInStream_SeekTo(stream, pos)) 273 RINOK(LookInStream_SeekTo(stream, pos))
242 *startOffset = (Int64)pos; 274 *startOffset = (Int64)pos;
243 } 275 }
@@ -246,7 +278,6 @@ static SRes Xz_ReadBackward(CXzStream *p, ILookInStreamPtr stream, Int64 *startO
246 CSecToRead secToRead; 278 CSecToRead secToRead;
247 SecToRead_CreateVTable(&secToRead); 279 SecToRead_CreateVTable(&secToRead);
248 secToRead.realStream = stream; 280 secToRead.realStream = stream;
249
250 RINOK(Xz_ReadHeader(&headerFlags, &secToRead.vt)) 281 RINOK(Xz_ReadHeader(&headerFlags, &secToRead.vt))
251 return (p->flags == headerFlags) ? SZ_OK : SZ_ERROR_ARCHIVE; 282 return (p->flags == headerFlags) ? SZ_OK : SZ_ERROR_ARCHIVE;
252 } 283 }
@@ -257,8 +288,7 @@ static SRes Xz_ReadBackward(CXzStream *p, ILookInStreamPtr stream, Int64 *startO
257 288
258void Xzs_Construct(CXzs *p) 289void Xzs_Construct(CXzs *p)
259{ 290{
260 p->num = p->numAllocated = 0; 291 Xzs_CONSTRUCT(p)
261 p->streams = 0;
262} 292}
263 293
264void Xzs_Free(CXzs *p, ISzAllocPtr alloc) 294void Xzs_Free(CXzs *p, ISzAllocPtr alloc)
@@ -268,7 +298,7 @@ void Xzs_Free(CXzs *p, ISzAllocPtr alloc)
268 Xz_Free(&p->streams[i], alloc); 298 Xz_Free(&p->streams[i], alloc);
269 ISzAlloc_Free(alloc, p->streams); 299 ISzAlloc_Free(alloc, p->streams);
270 p->num = p->numAllocated = 0; 300 p->num = p->numAllocated = 0;
271 p->streams = 0; 301 p->streams = NULL;
272} 302}
273 303
274UInt64 Xzs_GetNumBlocks(const CXzs *p) 304UInt64 Xzs_GetNumBlocks(const CXzs *p)
@@ -307,34 +337,49 @@ UInt64 Xzs_GetPackSize(const CXzs *p)
307SRes Xzs_ReadBackward(CXzs *p, ILookInStreamPtr stream, Int64 *startOffset, ICompressProgressPtr progress, ISzAllocPtr alloc) 337SRes Xzs_ReadBackward(CXzs *p, ILookInStreamPtr stream, Int64 *startOffset, ICompressProgressPtr progress, ISzAllocPtr alloc)
308{ 338{
309 Int64 endOffset = 0; 339 Int64 endOffset = 0;
340 // it's supposed that CXzs object is empty here.
341 // if CXzs object is not empty, it will add new streams to that non-empty object.
342 // Xzs_Free(p, alloc); // it's optional call to empty CXzs object.
310 RINOK(ILookInStream_Seek(stream, &endOffset, SZ_SEEK_END)) 343 RINOK(ILookInStream_Seek(stream, &endOffset, SZ_SEEK_END))
311 *startOffset = endOffset; 344 *startOffset = endOffset;
312 for (;;) 345 for (;;)
313 { 346 {
314 CXzStream st; 347 CXzStream st;
315 SRes res; 348 SRes res;
316 Xz_Construct(&st); 349 Xz_CONSTRUCT(&st)
317 res = Xz_ReadBackward(&st, stream, startOffset, alloc); 350 res = Xz_ReadBackward(&st, stream, startOffset, alloc);
351 // if (res == SZ_OK), then (*startOffset) is start offset of new stream if
352 // if (res != SZ_OK), then (*startOffset) is unchend or it's expected start offset of stream with error
318 st.startOffset = (UInt64)*startOffset; 353 st.startOffset = (UInt64)*startOffset;
319 RINOK(res) 354 // we must store (st) object to array, or we must free (st) local object.
355 if (res != SZ_OK)
356 {
357 Xz_Free(&st, alloc);
358 return res;
359 }
320 if (p->num == p->numAllocated) 360 if (p->num == p->numAllocated)
321 { 361 {
322 const size_t newNum = p->num + p->num / 4 + 1; 362 const size_t newNum = p->num + p->num / 4 + 1;
323 void *data = ISzAlloc_Alloc(alloc, newNum * sizeof(CXzStream)); 363 void *data = ISzAlloc_Alloc(alloc, newNum * sizeof(CXzStream));
324 if (!data) 364 if (!data)
365 {
366 Xz_Free(&st, alloc);
325 return SZ_ERROR_MEM; 367 return SZ_ERROR_MEM;
368 }
326 p->numAllocated = newNum; 369 p->numAllocated = newNum;
327 if (p->num != 0) 370 if (p->num != 0)
328 memcpy(data, p->streams, p->num * sizeof(CXzStream)); 371 memcpy(data, p->streams, p->num * sizeof(CXzStream));
329 ISzAlloc_Free(alloc, p->streams); 372 ISzAlloc_Free(alloc, p->streams);
330 p->streams = (CXzStream *)data; 373 p->streams = (CXzStream *)data;
331 } 374 }
375 // we use direct copying of raw data from local variable (st) to object in array.
376 // so we don't need to call Xz_Free(&st, alloc) after copying and after p->num++
332 p->streams[p->num++] = st; 377 p->streams[p->num++] = st;
333 if (*startOffset == 0) 378 if (*startOffset == 0)
334 break; 379 return SZ_OK;
335 RINOK(LookInStream_SeekTo(stream, (UInt64)*startOffset)) 380 // seek operation is optional:
381 // RINOK(LookInStream_SeekTo(stream, (UInt64)*startOffset))
336 if (progress && ICompressProgress_Progress(progress, (UInt64)(endOffset - *startOffset), (UInt64)(Int64)-1) != SZ_OK) 382 if (progress && ICompressProgress_Progress(progress, (UInt64)(endOffset - *startOffset), (UInt64)(Int64)-1) != SZ_OK)
337 return SZ_ERROR_PROGRESS; 383 return SZ_ERROR_PROGRESS;
338 } 384 }
339 return SZ_OK;
340} 385}