/**
 * Gunzip a given file and remove the .gz if successful.
 * @param ci container with filename
 * @return true if the gunzip completed
 */
static bool GunzipFile(const ContentInfo *ci)
{
#if defined(WITH_ZLIB)
	bool ret = true;
	FILE *ftmp = fopen(GetFullFilename(ci, true), "rb");
	gzFile fin = gzdopen(fileno(ftmp), "rb");
	FILE *fout = fopen(GetFullFilename(ci, false), "wb");

	if (fin == NULL || fout == NULL) {
		ret = false;
	} else {
		byte buff[8192];
		while (1) {
			int read = gzread(fin, buff, sizeof(buff));
			if (read == 0) {
				/* If gzread() returns 0, either the end-of-file has been
				 * reached or an underlying read error has occurred.
				 *
				 * gzeof() can't be used, because:
				 * 1.2.5 - it is safe, 1 means 'everything was OK'
				 * 1.2.3.5, 1.2.4 - 0 or 1 is returned 'randomly'
				 * 1.2.3.3 - 1 is returned for truncated archive
				 *
				 * So we use gzerror(). When proper end of archive
				 * has been reached, then:
				 * errnum == Z_STREAM_END in 1.2.3.3,
				 * errnum == 0 in 1.2.4 and 1.2.5 */
				int errnum;
				gzerror(fin, &errnum);
				if (errnum != 0 && errnum != Z_STREAM_END) ret = false;
				break;
			}
			if (read < 0 || (size_t)read != fwrite(buff, 1, read, fout)) {
				/* If gzread() returns -1, there was an error in archive */
				ret = false;
				break;
			}
			/* DO NOT DO THIS! It will fail to detect broken archive with 1.2.3.3!
			 * if (read < sizeof(buff)) break; */
		}
	}

	if (fin != NULL) {
		/* Closes ftmp too! */
		gzclose(fin);
	} else if (ftmp != NULL) {
		/* In case the gz stream was opened correctly this will
		 * be closed by gzclose. */
		fclose(ftmp);
	}
	if (fout != NULL) fclose(fout);

	return ret;
#else
	NOT_REACHED();
#endif /* defined(WITH_ZLIB) */
}
/*===========================================================================
 *
 * Class CSrResourceInstance Method - const char* GetFullFilenameAbs (void);
 *
 *=========================================================================*/
const char* CSrResourceInstance::GetFullFilenameAbs (void) {
  static CSString s_Buffer;

  s_Buffer  = GetBasePath();
  s_Buffer += GetFullFilename();
  
  return (s_Buffer);
}
Esempio n. 3
0
FILE *SDLS_fopen(const char *fname, const char *mode)
{
	char buffer[256];
	if (GetFullFilename(fname, buffer))
		return NULL;
	
	return fopen(buffer, mode);
}
/**
 * Gunzip a given file and remove the .gz if successful.
 * @param ci container with filename
 * @return true if the gunzip completed
 */
static bool GunzipFile(const ContentInfo *ci)
{
#if defined(WITH_ZLIB)
	bool ret = true;
	FILE *ftmp = fopen(GetFullFilename(ci, true), "rb");
	gzFile fin = gzdopen(fileno(ftmp), "rb");
	FILE *fout = fopen(GetFullFilename(ci, false), "wb");

	if (fin == NULL || fout == NULL) {
		ret = false;
		goto exit;
	}

	byte buff[8192];
	while (!gzeof(fin)) {
		int read = gzread(fin, buff, sizeof(buff));
		if (read < 0 || (size_t)read != fwrite(buff, 1, read, fout)) {
			ret = false;
			break;
		}
	}

exit:
	if (fin != NULL) {
		/* Closes ftmp too! */
		gzclose(fin);
	} else if (ftmp != NULL) {
		/* In case the gz stream was opened correctly this will
		 * be closed by gzclose. */
		fclose(ftmp);
	}
	if (fout != NULL) fclose(fout);

	return ret;
#else
	NOT_REACHED();
#endif /* defined(WITH_ZLIB) */
}
/**
 * Handle the closing and extracting of a file after
 * downloading it has been done.
 */
void ClientNetworkContentSocketHandler::AfterDownload()
{
	/* We read nothing; that's our marker for end-of-stream.
	 * Now gunzip the tar and make it known. */
	fclose(this->curFile);
	this->curFile = NULL;

	if (GunzipFile(this->curInfo)) {
		unlink(GetFullFilename(this->curInfo, true));

		TarListAddFile(GetFullFilename(this->curInfo, false));

		if (this->curInfo->type == CONTENT_TYPE_BASE_MUSIC) {
			/* Music can't be in a tar. So extract the tar! */
			ExtractTar(GetFullFilename(this->curInfo, false));
			unlink(GetFullFilename(this->curInfo, false));
		}

		this->OnDownloadComplete(this->curInfo->id);
	} else {
		ShowErrorMessage(STR_CONTENT_ERROR_COULD_NOT_EXTRACT, INVALID_STRING_ID, WL_ERROR);
	}
}
/**
 * Handle the opening of the file before downloading.
 * @return false on any error.
 */
bool ClientNetworkContentSocketHandler::BeforeDownload()
{
	if (!this->curInfo->IsValid()) {
		delete this->curInfo;
		this->curInfo = NULL;
		return false;
	}

	if (this->curInfo->filesize != 0) {
		/* The filesize is > 0, so we are going to download it */
		const char *filename = GetFullFilename(this->curInfo, true);
		if (filename == NULL || (this->curFile = fopen(filename, "wb")) == NULL) {
			/* Unless that fails ofcourse... */
			DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0);
			ShowErrorMessage(STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD, STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD_FILE_NOT_WRITABLE, WL_ERROR);
			return false;
		}
	}
	return true;
}