MCPcopy Create free account
hub / github.com/OpenTTD/OpenTTD / GunzipFile

Function GunzipFile

src/network/network_content.cpp:388–448  ·  view source on GitHub ↗

* Gunzip a given file and remove the .gz if successful. * @param ci container with filename * @return true if the gunzip completed */

Source from the content-addressed store, hash-verified

386 * @return true if the gunzip completed
387 */
388static bool GunzipFile(const ContentInfo &ci)
389{
390#if defined(WITH_ZLIB)
391 bool ret = true;
392
393 /* Need to open the file with fopen() to support non-ASCII on Windows. */
394 auto ftmp = FileHandle::Open(GetFullFilename(ci, true), "rb");
395 if (!ftmp.has_value()) return false;
396 /* Duplicate the handle, and close the FILE*, to avoid double-closing the handle later. */
397 int fdup = dup(fileno(*ftmp));
398 gzFile fin = gzdopen(fdup, "rb");
399 ftmp.reset();
400
401 auto fout = FileHandle::Open(GetFullFilename(ci, false), "wb");
402
403 if (fin == nullptr || !fout.has_value()) {
404 ret = false;
405 } else {
406 uint8_t buff[8192];
407 for (;;) {
408 int read = gzread(fin, buff, sizeof(buff));
409 if (read == 0) {
410 /* If gzread() returns 0, either the end-of-file has been
411 * reached or an underlying read error has occurred.
412 *
413 * gzeof() can't be used, because:
414 * 1.2.5 - it is safe, 1 means 'everything was OK'
415 * 1.2.3.5, 1.2.4 - 0 or 1 is returned 'randomly'
416 * 1.2.3.3 - 1 is returned for truncated archive
417 *
418 * So we use gzerror(). When proper end of archive
419 * has been reached, then:
420 * errnum == Z_STREAM_END in 1.2.3.3,
421 * errnum == 0 in 1.2.4 and 1.2.5 */
422 int errnum;
423 gzerror(fin, &errnum);
424 if (errnum != 0 && errnum != Z_STREAM_END) ret = false;
425 break;
426 }
427 if (read < 0 || static_cast<size_t>(read) != fwrite(buff, 1, read, *fout)) {
428 /* If gzread() returns -1, there was an error in archive */
429 ret = false;
430 break;
431 }
432 /* DO NOT DO THIS! It will fail to detect broken archive with 1.2.3.3!
433 * if (read < sizeof(buff)) break; */
434 }
435 }
436
437 if (fin != nullptr) {
438 gzclose(fin);
439 } else if (fdup != -1) {
440 /* Failing gzdopen does not close the passed file descriptor. */
441 close(fdup);
442 }
443
444 return ret;
445#else

Callers 1

AfterDownloadMethod · 0.85

Calls 4

GetFullFilenameFunction · 0.85
closeFunction · 0.85
NOT_REACHEDFunction · 0.85
resetMethod · 0.45

Tested by

no test coverage detected