1 #include "lc_global.h"
2 #include "lc_zipfile.h"
3 #include "lc_file.h"
4 #include "lc_math.h"
5 #include <zlib.h>
6 #include <time.h>
7 
8 #if MAX_MEM_LEVEL >= 8
9 #  define DEF_MEM_LEVEL 8
10 #else
11 #  define DEF_MEM_LEVEL  MAX_MEM_LEVEL
12 #endif
13 
lcZipFile()14 lcZipFile::lcZipFile()
15 {
16 	mModified = false;
17 }
18 
~lcZipFile()19 lcZipFile::~lcZipFile()
20 {
21 }
22 
OpenRead(const QString & FileName)23 bool lcZipFile::OpenRead(const QString& FileName)
24 {
25 	std::unique_ptr<lcDiskFile> File(new lcDiskFile(FileName));
26 
27 	if (!File->Open(QIODevice::ReadOnly))
28 		return false;
29 
30 	return OpenRead(std::move(File));
31 }
32 
OpenRead(std::unique_ptr<lcFile> File)33 bool lcZipFile::OpenRead(std::unique_ptr<lcFile> File)
34 {
35 	mFile = std::move(File);
36 
37 	if (!Open())
38 	{
39 		mFile = nullptr;
40 		return false;
41 	}
42 
43 	return true;
44 }
45 
OpenWrite(const QString & FileName)46 bool lcZipFile::OpenWrite(const QString& FileName)
47 {
48 	std::unique_ptr<lcDiskFile> File(new lcDiskFile(FileName));
49 
50 	if (!File->Open(QIODevice::WriteOnly))
51 		return false;
52 
53 	mFile = std::move(File);
54 
55 	mNumEntries = 0;
56 	mCentralDirSize = 0;
57 	mCentralDirOffset = 0;
58 	mBytesBeforeZipFile = 0;
59 	mCentralPos = 0;
60 
61 	return true;
62 }
63 
SearchCentralDir()64 quint64 lcZipFile::SearchCentralDir()
65 {
66 	quint64 SizeFile, MaxBack, BackRead, PosFound;
67 	const int CommentBufferSize = 1024;
68 	quint8 buf[CommentBufferSize + 4];
69 
70 	SizeFile = mFile->GetLength();
71 	MaxBack = lcMin(SizeFile, 0xffffULL);
72 	BackRead = 4;
73 	PosFound = 0;
74 
75 	while (BackRead < MaxBack)
76 	{
77 		quint64 ReadPos, ReadSize;
78 
79 		if (BackRead + CommentBufferSize > MaxBack)
80 			BackRead = MaxBack;
81 		else
82 			BackRead += CommentBufferSize;
83 		ReadPos = SizeFile - BackRead;
84 
85 		ReadSize = ((CommentBufferSize + 4) < (SizeFile - ReadPos)) ? (CommentBufferSize + 4) : (SizeFile - ReadPos);
86 		mFile->Seek(ReadPos, SEEK_SET);
87 
88 		if (mFile->ReadBuffer(buf, (long)ReadSize) != ReadSize)
89 			break;
90 
91 		for (int i = (int)ReadSize - 3; (i--) > 0;)
92 		{
93 			if (((*(buf+i)) == 0x50) && ((*(buf+i+1)) == 0x4b) && ((*(buf+i+2)) == 0x05) && ((*(buf+i+3)) == 0x06))
94 			{
95 				PosFound = ReadPos + i;
96 				break;
97 			}
98 		}
99 
100 		if (PosFound != 0)
101 			break;
102 	}
103 
104 	return PosFound;
105 }
106 
SearchCentralDir64()107 quint64 lcZipFile::SearchCentralDir64()
108 {
109 	quint64 SizeFile, MaxBack, BackRead, PosFound;
110 	const int CommentBufferSize = 1024;
111 	quint8 buf[CommentBufferSize + 4];
112 
113 	SizeFile = mFile->GetLength();
114 	MaxBack = lcMin(SizeFile, 0xffffULL);
115 	BackRead = 4;
116 	PosFound = 0;
117 
118 	while (BackRead < MaxBack)
119 	{
120 		quint64 ReadPos, ReadSize;
121 
122 		if (BackRead + CommentBufferSize > MaxBack)
123 			BackRead = MaxBack;
124 		else
125 			BackRead += CommentBufferSize;
126 		ReadPos = SizeFile - BackRead;
127 
128 		ReadSize = ((CommentBufferSize + 4) < (SizeFile - ReadPos)) ? (CommentBufferSize + 4) : (SizeFile - ReadPos);
129 		mFile->Seek(ReadPos, SEEK_SET);
130 
131 		if (mFile->ReadBuffer(buf, (long)ReadSize) != ReadSize)
132 			break;
133 
134 		for (int i=(int)ReadSize - 3; (i--) > 0; )
135 		{
136 			if (((*(buf+i)) == 0x50) && ((*(buf+i+1)) == 0x4b) && ((*(buf+i+2)) == 0x06) && ((*(buf+i+3)) == 0x07))
137 			{
138 				PosFound = ReadPos + i;
139 				break;
140 			}
141 		}
142 
143 		if (PosFound != 0)
144 			break;
145 	}
146 
147 	if (PosFound == 0)
148 		return 0;
149 
150 	mFile->Seek(PosFound, SEEK_SET);
151 
152 	quint32 Number;
153 	quint64 RelativeOffset;
154 
155 	// Signature.
156 	if (mFile->ReadU32(&Number, 1) != 1)
157 		return 0;
158 
159 	// Number of the disk with the start of the zip64 end of central directory.
160 	if (mFile->ReadU32(&Number, 1) != 1)
161 		return 0;
162 
163 	if (Number != 0)
164 		return 0;
165 
166 	// Relative offset of the zip64 end of central directory record.
167 	if (mFile->ReadU64(&RelativeOffset, 1) != 1)
168 		return 0;
169 
170 	// Total number of disks.
171 	if (mFile->ReadU32(&Number, 1) != 1)
172 		return 0;
173 
174 	if (Number != 0)
175 		return 0;
176 
177 	// Go to end of central directory record.
178 	mFile->Seek(RelativeOffset, SEEK_SET);
179 
180 	// The signature.
181 	if (mFile->ReadU32(&Number, 1) != 1)
182 		return 0;
183 
184 	if (Number != 0x06064b50)
185 		return 0;
186 
187 	return RelativeOffset;
188 }
189 
CheckFileCoherencyHeader(int FileIndex,quint32 * SizeVar,quint64 * OffsetLocalExtraField,quint32 * SizeLocalExtraField)190 bool lcZipFile::CheckFileCoherencyHeader(int FileIndex, quint32* SizeVar, quint64* OffsetLocalExtraField, quint32* SizeLocalExtraField)
191 {
192 	quint16 Number16, Flags;
193 	quint32 Number32, Magic;
194 	quint16 SizeFilename, SizeExtraField;
195 	const lcZipFileInfo& FileInfo = mFiles[FileIndex];
196 
197 	*SizeVar = 0;
198 	*OffsetLocalExtraField = 0;
199 	*SizeLocalExtraField = 0;
200 
201 	mFile->Seek(FileInfo.offset_curfile + mBytesBeforeZipFile, SEEK_SET);
202 
203 	if (mFile->ReadU32(&Magic, 1) != 1 || Magic != 0x04034b50)
204 		return false;
205 
206 	if (mFile->ReadU16(&Number16, 1) != 1)
207 		return false;
208 
209 	if (mFile->ReadU16(&Flags, 1) != 1)
210 		return false;
211 
212 	if (mFile->ReadU16(&Number16, 1) != 1 || Number16 != FileInfo.compression_method)
213 		return false;
214 
215 	if (FileInfo.compression_method != 0 && FileInfo.compression_method != Z_DEFLATED)
216 		return false;
217 
218 	if (mFile->ReadU32(&Number32, 1) != 1)
219 		return false;
220 
221 	if (mFile->ReadU32(&Number32, 1) != 1 || ((Number32 != FileInfo.crc) && ((Flags & 8)==0)))
222 		return false;
223 
224 	if (mFile->ReadU32(&Number32, 1) != 1 || (Number32 != 0xffffffffU && (Number32 != FileInfo.compressed_size) && ((Flags & 8)==0)))
225 		return false;
226 
227 	if (mFile->ReadU32(&Number32, 1) != 1 || (Number32 != 0xffffffffU && (Number32 != FileInfo.uncompressed_size) && ((Flags & 8)==0)))
228 		return false;
229 
230 	if (mFile->ReadU16(&SizeFilename, 1) != 1 || SizeFilename != FileInfo.size_filename)
231 		return false;
232 
233 	*SizeVar += SizeFilename;
234 
235 	if (mFile->ReadU16(&SizeExtraField, 1) != 1)
236 		return false;
237 
238 	*OffsetLocalExtraField= FileInfo.offset_curfile + 0x1e + SizeFilename;
239 	*SizeLocalExtraField = SizeExtraField;
240 
241 	*SizeVar += SizeExtraField;
242 
243 	return true;
244 }
245 
Open()246 bool lcZipFile::Open()
247 {
248 	quint64 NumberEntriesCD, CentralPos;
249 
250 	CentralPos = SearchCentralDir64();
251 
252 	if (CentralPos)
253 	{
254 		quint32 NumberDisk, NumberDiskWithCD;
255 
256 		mZip64 = true;
257 
258 		// Skip signature, size and versions.
259 		mFile->Seek(CentralPos + 4 + 8 + 2 + 2, SEEK_SET);
260 
261 		// Number of this disk.
262 		if (mFile->ReadU32(&NumberDisk, 1) != 1)
263 			return false;
264 
265 		// Number of the disk with the start of the central directory.
266 		if (mFile->ReadU32(&NumberDiskWithCD, 1) != 1)
267 			return false;
268 
269 		// Total number of entries in the central directory on this disk.
270 		if (mFile->ReadU64(&mNumEntries, 1) != 1)
271 			return false;
272 
273 		// Total number of entries in the central directory.
274 		if (mFile->ReadU64(&NumberEntriesCD, 1) != 1)
275 			return false;
276 
277 		if ((NumberEntriesCD != mNumEntries) || (NumberDiskWithCD != 0) || (NumberDisk != 0))
278 			return false;
279 
280 		// Size of the central directory.
281 		if (mFile->ReadU64(&mCentralDirSize, 1) != 1)
282 			return false;
283 
284 		// Offset of start of central directory with respect to the starting disk number.
285 		if (mFile->ReadU64(&mCentralDirOffset, 1) != 1)
286 			return false;
287 
288 //		us.gi.size_comment = 0;
289 	}
290 	else
291 	{
292 		quint16 NumberDisk, NumberDiskWithCD;
293 		quint16 Number16;
294 		quint32 Number32;
295 
296 		CentralPos = SearchCentralDir();
297 		if (CentralPos == 0)
298 			return false;
299 
300 		mZip64 = false;
301 
302 		// Skip signature.
303 		mFile->Seek(CentralPos + 4, SEEK_SET);
304 
305 		// Number of this disk.
306 		if (mFile->ReadU16(&NumberDisk, 1) != 1)
307 			return false;
308 
309 		// Number of the disk with the start of the central directory.
310 		if (mFile->ReadU16(&NumberDiskWithCD, 1) != 1)
311 			return false;
312 
313 		// Total number of entries in the central dir on this disk.
314 		if (mFile->ReadU16(&Number16, 1) != 1)
315 			return false;
316 		mNumEntries = Number16;
317 
318 		// Total number of entries in the central dir.
319 		if (mFile->ReadU16(&Number16, 1) != 1)
320 			return false;
321 		NumberEntriesCD = Number16;
322 
323 		if ((NumberEntriesCD != mNumEntries) || (NumberDiskWithCD != 0) || (NumberDisk != 0))
324 			return false;
325 
326 		// Size of the central directory.
327 		if (mFile->ReadU32(&Number32, 1) != 1)
328 			return false;
329 		mCentralDirSize = Number32;
330 
331 		// Offset of start of central directory with respect to the starting disk number.
332 		if (mFile->ReadU32(&Number32, 1) != 1)
333 			return false;
334 		mCentralDirOffset= Number32;
335 
336 		// zipfile comment length.
337 //		if (mFile->ReadU16(&us.z_filefunc, us.filestream,&us.gi.size_comment)!=1)
338 //			return false;
339 	}
340 
341 	if (CentralPos < mCentralDirOffset + mCentralDirSize)
342 		return false;
343 
344 	mBytesBeforeZipFile = CentralPos - (mCentralDirOffset + mCentralDirSize);
345 	mCentralPos = CentralPos;
346 
347 	return ReadCentralDir();
348 }
349 
ReadCentralDir()350 bool lcZipFile::ReadCentralDir()
351 {
352 	quint64 PosInCentralDir = mCentralDirOffset;
353 
354 	mFile->Seek(PosInCentralDir + mBytesBeforeZipFile, SEEK_SET);
355 	mFiles.AllocGrow((int)mNumEntries);
356 
357 	for (quint64 FileNum = 0; FileNum < mNumEntries; FileNum++)
358 	{
359 		quint32 Magic, Number32;
360 		lcZipFileInfo& FileInfo = mFiles.Add();
361 		long Seek = 0;
362 
363 		FileInfo.write_buffer = nullptr;
364 		FileInfo.deleted = false;
365 
366 		if (mFile->ReadU32(&Magic, 1) != 1 || Magic != 0x02014b50)
367 			return false;
368 
369 		if (mFile->ReadU16(&FileInfo.version, 1) != 1)
370 			return false;
371 
372 		if (mFile->ReadU16(&FileInfo.version_needed, 1) != 1)
373 			return false;
374 
375 		if (mFile->ReadU16(&FileInfo.flag, 1) != 1)
376 			return false;
377 
378 		if (mFile->ReadU16(&FileInfo.compression_method, 1) != 1)
379 			return false;
380 
381 		if (mFile->ReadU32(&FileInfo.dosDate, 1) != 1)
382 			return false;
383 
384 		quint32 Date = FileInfo.dosDate >> 16;
385 		FileInfo.tmu_date.tm_mday = (quint32)(Date & 0x1f);
386 		FileInfo.tmu_date.tm_mon = (quint32)((((Date) & 0x1E0) / 0x20) - 1);
387 		FileInfo.tmu_date.tm_year = (quint32)(((Date & 0x0FE00) / 0x0200) + 1980);
388 
389 		FileInfo.tmu_date.tm_hour = (quint32)((FileInfo.dosDate & 0xF800) / 0x800);
390 		FileInfo.tmu_date.tm_min = (quint32)((FileInfo.dosDate & 0x7E0) / 0x20);
391 		FileInfo.tmu_date.tm_sec = (quint32)(2*(FileInfo.dosDate & 0x1f));
392 
393 		if (mFile->ReadU32(&FileInfo.crc, 1) != 1)
394 			return false;
395 
396 		if (mFile->ReadU32(&Number32, 1) != 1)
397 			return false;
398 		FileInfo.compressed_size = Number32;
399 
400 		if (mFile->ReadU32(&Number32, 1) != 1)
401 			return false;
402 		FileInfo.uncompressed_size = Number32;
403 
404 		if (mFile->ReadU16(&FileInfo.size_filename, 1) != 1)
405 			return false;
406 
407 		if (mFile->ReadU16(&FileInfo.size_file_extra, 1) != 1)
408 			return false;
409 
410 		if (mFile->ReadU16(&FileInfo.size_file_comment, 1) != 1)
411 			return false;
412 
413 		if (mFile->ReadU16(&FileInfo.disk_num_start, 1) != 1)
414 			return false;
415 
416 		if (mFile->ReadU16(&FileInfo.internal_fa, 1) != 1)
417 			return false;
418 
419 		if (mFile->ReadU32(&FileInfo.external_fa, 1) != 1)
420 			return false;
421 
422 		// relative offset of local header
423 		if (mFile->ReadU32(&Number32, 1) != 1)
424 			return false;
425 		FileInfo.offset_curfile = Number32;
426 
427 		Seek += FileInfo.size_filename;
428 
429 		quint32 SizeRead;
430 		if (FileInfo.size_filename < sizeof(FileInfo.file_name) - 1)
431 		{
432 			*(FileInfo.file_name + FileInfo.size_filename) = '\0';
433 			SizeRead = FileInfo.size_filename;
434 		}
435 		else
436 		{
437 			*(FileInfo.file_name + sizeof(FileInfo.file_name) - 1) = '\0';
438 			SizeRead = sizeof(FileInfo.file_name) - 1;
439 		}
440 
441 		if (FileInfo.size_filename > 0)
442 			if (mFile->ReadBuffer(FileInfo.file_name, SizeRead) != SizeRead)
443 				return false;
444 		Seek -= SizeRead;
445 /*
446 		// Read extrafield
447 		if ((err==UNZ_OK) && (extraField!=nullptr))
448 		{
449 			ZPOS64_T uSizeRead ;
450 			if (file_info.size_file_extra<extraFieldBufferSize)
451 				uSizeRead = file_info.size_file_extra;
452 			else
453 				uSizeRead = extraFieldBufferSize;
454 
455 			if (lSeek!=0)
456 			{
457 				if (ZSEEK64(s->z_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0)
458 					lSeek=0;
459 				else
460 					err=UNZ_ERRNO;
461 			}
462 
463 			if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0))
464 				if (ZREAD64(s->z_filefunc, s->filestream,extraField,(uLong)uSizeRead)!=uSizeRead)
465 					err=UNZ_ERRNO;
466 
467 			lSeek += file_info.size_file_extra - (uLong)uSizeRead;
468 		}
469 		else
470 			lSeek += file_info.size_file_extra;
471 */
472 		Seek += FileInfo.size_file_extra;
473 
474 		if (FileInfo.size_file_extra != 0)
475 		{
476 			quint32 acc = 0;
477 
478 			// since lSeek now points to after the extra field we need to move back
479 			Seek -= FileInfo.size_file_extra;
480 
481 			if (Seek != 0)
482 			{
483 				mFile->Seek(Seek, SEEK_CUR);
484 				Seek = 0;
485 			}
486 
487 			while (acc < FileInfo.size_file_extra)
488 			{
489 				quint16 HeaderId, DataSize;
490 
491 				if (mFile->ReadU16(&HeaderId, 1) != 1)
492 					return false;
493 
494 				if (mFile->ReadU16(&DataSize, 1) != 1)
495 					return false;
496 
497 				// ZIP64 extra fields.
498 				if (HeaderId == 0x0001)
499 				{
500 					if (FileInfo.uncompressed_size == (quint64)(unsigned long)-1)
501 					{
502 						if (mFile->ReadU64(&FileInfo.uncompressed_size, 1) != 1)
503 							return false;
504 					}
505 
506 					if (FileInfo.compressed_size == (quint64)(unsigned long)-1)
507 					{
508 						if (mFile->ReadU64(&FileInfo.compressed_size, 1) != 1)
509 							return false;
510 					}
511 
512 					if (FileInfo.offset_curfile == (quint64)-1)
513 					{
514 						// Relative Header offset.
515 						if (mFile->ReadU64(&FileInfo.offset_curfile, 1) != 1)
516 							return false;
517 					}
518 
519 					if (FileInfo.disk_num_start == (quint16)-1)
520 					{
521 						// Disk Start Number.
522 						if (mFile->ReadU32(&Number32, 1) != 1)
523 							return false;
524 					}
525 				}
526 				else
527 				{
528 					mFile->Seek(DataSize, SEEK_CUR);
529 				}
530 
531 				acc += 2 + 2 + DataSize;
532 			}
533 		}
534 /*
535 		if ((err==UNZ_OK) && (szComment!=nullptr))
536 		{
537 			uLong uSizeRead ;
538 			if (file_info.size_file_comment<commentBufferSize)
539 			{
540 				*(szComment+file_info.size_file_comment)='\0';
541 				uSizeRead = file_info.size_file_comment;
542 			}
543 			else
544 				uSizeRead = commentBufferSize;
545 
546 			if (lSeek!=0)
547 			{
548 				if (ZSEEK64(s->z_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0)
549 					lSeek=0;
550 				else
551 					err=UNZ_ERRNO;
552 			}
553 
554 			if ((file_info.size_file_comment>0) && (commentBufferSize>0))
555 				if (ZREAD64(s->z_filefunc, s->filestream,szComment,uSizeRead)!=uSizeRead)
556 					err=UNZ_ERRNO;
557 			lSeek+=file_info.size_file_comment - uSizeRead;
558 		}
559 		else
560 			lSeek+=file_info.size_file_comment;
561 */
562 		Seek += FileInfo.size_file_comment;
563 
564 		mFile->Seek(Seek, SEEK_CUR);
565 	}
566 
567 	return true;
568 }
569 
ExtractFile(const char * FileName,lcMemFile & File,quint32 MaxLength)570 bool lcZipFile::ExtractFile(const char* FileName, lcMemFile& File, quint32 MaxLength)
571 {
572 	for (int FileIdx = 0; FileIdx < mFiles.GetSize(); FileIdx++)
573 	{
574 		lcZipFileInfo& FileInfo = mFiles[FileIdx];
575 
576 		if (!qstricmp(FileInfo.file_name, FileName))
577 			return ExtractFile(FileIdx, File, MaxLength);
578 	}
579 
580 	return false;
581 }
582 
ExtractFile(int FileIndex,lcMemFile & File,quint32 MaxLength)583 bool lcZipFile::ExtractFile(int FileIndex, lcMemFile& File, quint32 MaxLength)
584 {
585 	QMutexLocker Lock(&mMutex);
586 
587 	quint32 SizeVar;
588 	quint64 OffsetLocalExtraField;
589 	quint32 SizeLocalExtraField;
590 	const lcZipFileInfo& FileInfo = mFiles[FileIndex];
591 
592 	if (!CheckFileCoherencyHeader(FileIndex, &SizeVar, &OffsetLocalExtraField, &SizeLocalExtraField))
593 		return false;
594 
595 	const int BufferSize = 16384;
596 	char ReadBuffer[BufferSize];
597 	z_stream Stream;
598 	quint32 Crc32;
599 	quint64 PosInZipfile;
600 	quint64 RestReadCompressed;
601 	quint64 RestReadUncompressed;
602 
603 	Crc32 = 0;
604 	Stream.total_out = 0;
605 
606 	if (FileInfo.compression_method == Z_DEFLATED)
607 	{
608 		Stream.zalloc = (alloc_func)0;
609 		Stream.zfree = (free_func)0;
610 		Stream.opaque = (voidpf)0;
611 		Stream.next_in = 0;
612 		Stream.avail_in = 0;
613 
614 		int err = inflateInit2(&Stream, -MAX_WBITS);
615 		if (err != Z_OK)
616 			return false;
617 	}
618 
619 	RestReadCompressed = FileInfo.compressed_size;
620 	RestReadUncompressed = FileInfo.uncompressed_size;
621 	PosInZipfile = FileInfo.offset_curfile + 0x1e + SizeVar;
622 
623 	Stream.avail_in = (uInt)0;
624 
625 	quint32 Length = lcMin((quint32)FileInfo.uncompressed_size, MaxLength);
626 	File.SetLength(Length);
627 	File.Seek(0, SEEK_SET);
628 
629 	Stream.next_in = (Bytef*)ReadBuffer;
630 	Stream.next_out = (Bytef*)File.mBuffer;
631 	Stream.avail_out = Length;
632 
633 	quint32 Read = 0;
634 
635 	while (Stream.avail_out > 0)
636 	{
637 		if ((Stream.avail_in == 0) && (RestReadCompressed > 0))
638 		{
639 			quint32 ReadThis = BufferSize;
640 
641 			if (RestReadCompressed < ReadThis)
642 				ReadThis = (quint32)RestReadCompressed;
643 
644 			if (ReadThis == 0)
645 				return false;
646 
647 			mFile->Seek(PosInZipfile + mBytesBeforeZipFile, SEEK_SET);
648 			if (mFile->ReadBuffer(ReadBuffer, ReadThis) != ReadThis)
649 				return false;
650 
651 			PosInZipfile += ReadThis;
652 
653 			RestReadCompressed -= ReadThis;
654 
655 			Stream.next_in = (Bytef*)ReadBuffer;
656 			Stream.avail_in = (uInt)ReadThis;
657 		}
658 
659 		if (FileInfo.compression_method == 0)
660 		{
661 			quint32 DoCopy, i;
662 
663 			if ((Stream.avail_in == 0) && (RestReadCompressed == 0))
664 				return (Read == 0) ? false : true;
665 
666 			if (Stream.avail_out < Stream.avail_in)
667 				DoCopy = Stream.avail_out;
668 			else
669 				DoCopy = Stream.avail_in;
670 
671 			for (i = 0; i < DoCopy; i++)
672 				*(Stream.next_out+i) = *(Stream.next_in+i);
673 
674 			Crc32 = crc32(Crc32, Stream.next_out, DoCopy);
675 			RestReadUncompressed -= DoCopy;
676 			Stream.avail_in -= DoCopy;
677 			Stream.avail_out -= DoCopy;
678 			Stream.next_out += DoCopy;
679 			Stream.next_in += DoCopy;
680 			Stream.total_out += DoCopy;
681 			Read += DoCopy;
682 		}
683 		else
684 		{
685 			quint64 TotalOutBefore, TotalOutAfter;
686 			const Bytef *bufBefore;
687 			quint64 OutThis;
688 			int flush = Z_SYNC_FLUSH;
689 
690 			TotalOutBefore = Stream.total_out;
691 			bufBefore = Stream.next_out;
692 
693 			int err = inflate(&Stream,flush);
694 
695 			if ((err >= 0) && (Stream.msg != nullptr))
696 				err = Z_DATA_ERROR;
697 
698 			TotalOutAfter = Stream.total_out;
699 			OutThis = TotalOutAfter - TotalOutBefore;
700 
701 			Crc32 = crc32(Crc32, bufBefore, (uInt)(OutThis));
702 
703 			RestReadUncompressed -= OutThis;
704 
705 			Read += (uInt)(TotalOutAfter - TotalOutBefore);
706 
707 			if (err != Z_OK)
708 			{
709 				inflateEnd(&Stream);
710 
711 				if (RestReadUncompressed == 0)
712 				{
713 					if (Crc32 != FileInfo.crc)
714 						return false;
715 				}
716 
717 				if (err == Z_STREAM_END)
718 					return (Read == 0) ? false : true;
719 
720 				return false;
721 			}
722 		}
723 	}
724 
725 	if (FileInfo.compression_method == Z_DEFLATED)
726 		inflateEnd(&Stream);
727 
728 	return true;
729 }
730