390 lines
		
	
	
	
		
			8.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			390 lines
		
	
	
	
		
			8.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*
 | 
						|
WARNING! All changes made in this file will be lost!
 | 
						|
Created from 'colors.palette' by 'codegen_style'
 | 
						|
 | 
						|
This file is part of Telegram Desktop,
 | 
						|
the official desktop version of Telegram messaging app, see https://telegram.org
 | 
						|
 | 
						|
Telegram Desktop is free software: you can redistribute it and/or modify
 | 
						|
it under the terms of the GNU General Public License as published by
 | 
						|
the Free Software Foundation, either version 3 of the License, or
 | 
						|
(at your option) any later version.
 | 
						|
 | 
						|
It is distributed in the hope that it will be useful,
 | 
						|
but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | 
						|
GNU General Public License for more details.
 | 
						|
 | 
						|
In addition, as a special exception, the copyright holders give permission
 | 
						|
to link the code of portions of this program with the OpenSSL library.
 | 
						|
 | 
						|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
 | 
						|
Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
 | 
						|
*/
 | 
						|
#pragma once
 | 
						|
 | 
						|
#include "zip.h"
 | 
						|
#include "unzip.h"
 | 
						|
 | 
						|
namespace zlib {
 | 
						|
namespace internal {
 | 
						|
 | 
						|
class InMemoryFile {
 | 
						|
public:
 | 
						|
	InMemoryFile(const QByteArray &data = QByteArray()) : _data(data) {
 | 
						|
	}
 | 
						|
 | 
						|
	zlib_filefunc_def funcs() {
 | 
						|
		zlib_filefunc_def result;
 | 
						|
		result.opaque = this;
 | 
						|
		result.zopen_file = &InMemoryFile::Open;
 | 
						|
		result.zerror_file = &InMemoryFile::Error;
 | 
						|
		result.zread_file = &InMemoryFile::Read;
 | 
						|
		result.zwrite_file = &InMemoryFile::Write;
 | 
						|
		result.zclose_file = &InMemoryFile::Close;
 | 
						|
		result.zseek_file = &InMemoryFile::Seek;
 | 
						|
		result.ztell_file = &InMemoryFile::Tell;
 | 
						|
		return result;
 | 
						|
	}
 | 
						|
 | 
						|
	int error() const {
 | 
						|
		return _error;
 | 
						|
	}
 | 
						|
 | 
						|
	QByteArray result() const {
 | 
						|
		return _data;
 | 
						|
	}
 | 
						|
 | 
						|
private:
 | 
						|
	voidpf open(const char *filename, int mode) {
 | 
						|
		if (mode & ZLIB_FILEFUNC_MODE_WRITE) {
 | 
						|
			if (mode & ZLIB_FILEFUNC_MODE_CREATE) {
 | 
						|
				_data.clear();
 | 
						|
			}
 | 
						|
			_position = _data.size();
 | 
						|
			_data.reserve(2 * 1024 * 1024);
 | 
						|
		} else if (mode & ZLIB_FILEFUNC_MODE_READ) {
 | 
						|
			_position = 0;
 | 
						|
		}
 | 
						|
		_error = 0;
 | 
						|
		return this;
 | 
						|
	}
 | 
						|
 | 
						|
	uLong read(voidpf stream, void* buf, uLong size) {
 | 
						|
		uLong toRead = 0;
 | 
						|
		if (!_error) {
 | 
						|
			if (_data.size() > int(_position)) {
 | 
						|
				toRead = qMin(size, uLong(_data.size() - _position));
 | 
						|
				memcpy(buf, _data.constData() + _position, toRead);
 | 
						|
				_position += toRead;
 | 
						|
			}
 | 
						|
			if (toRead < size) {
 | 
						|
				_error = -1;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		return toRead;
 | 
						|
	}
 | 
						|
 | 
						|
	uLong write(voidpf stream, const void* buf, uLong size) {
 | 
						|
		if (_data.size() < int(_position + size)) {
 | 
						|
			_data.resize(_position + size);
 | 
						|
		}
 | 
						|
		memcpy(_data.data() + _position, buf, size);
 | 
						|
		_position += size;
 | 
						|
		return size;
 | 
						|
	}
 | 
						|
 | 
						|
	int close(voidpf stream) {
 | 
						|
		auto result = _error;
 | 
						|
		_position = 0;
 | 
						|
		_error = 0;
 | 
						|
		return result;
 | 
						|
	}
 | 
						|
 | 
						|
	int error(voidpf stream) const {
 | 
						|
		return _error;
 | 
						|
	}
 | 
						|
 | 
						|
	long tell(voidpf stream) const {
 | 
						|
		return _position;
 | 
						|
	}
 | 
						|
 | 
						|
	long seek(voidpf stream, uLong offset, int origin) {
 | 
						|
		if (!_error) {
 | 
						|
			switch (origin) {
 | 
						|
			case ZLIB_FILEFUNC_SEEK_SET: _position = offset; break;
 | 
						|
			case ZLIB_FILEFUNC_SEEK_CUR: _position += offset; break;
 | 
						|
			case ZLIB_FILEFUNC_SEEK_END: _position = _data.size() + offset; break;
 | 
						|
			}
 | 
						|
			if (int(_position) > _data.size()) {
 | 
						|
				_error = -1;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		return _error;
 | 
						|
	}
 | 
						|
 | 
						|
	static voidpf Open(voidpf opaque, const char* filename, int mode) {
 | 
						|
		return static_cast<InMemoryFile*>(opaque)->open(filename, mode);
 | 
						|
	}
 | 
						|
 | 
						|
	static uLong Read(voidpf opaque, voidpf stream, void* buf, uLong size) {
 | 
						|
		return static_cast<InMemoryFile*>(opaque)->read(stream, buf, size);
 | 
						|
	}
 | 
						|
 | 
						|
	static uLong Write(voidpf opaque, voidpf stream, const void* buf, uLong size) {
 | 
						|
		return static_cast<InMemoryFile*>(opaque)->write(stream, buf, size);
 | 
						|
	}
 | 
						|
 | 
						|
	static int Close(voidpf opaque, voidpf stream) {
 | 
						|
		return static_cast<InMemoryFile*>(opaque)->close(stream);
 | 
						|
	}
 | 
						|
 | 
						|
	static int Error(voidpf opaque, voidpf stream) {
 | 
						|
		return static_cast<InMemoryFile*>(opaque)->error(stream);
 | 
						|
	}
 | 
						|
 | 
						|
	static long Tell(voidpf opaque, voidpf stream) {
 | 
						|
		return static_cast<InMemoryFile*>(opaque)->tell(stream);
 | 
						|
	}
 | 
						|
 | 
						|
	static long Seek(voidpf opaque, voidpf stream, uLong offset, int origin) {
 | 
						|
		return static_cast<InMemoryFile*>(opaque)->seek(stream, offset, origin);
 | 
						|
	}
 | 
						|
 | 
						|
	uLong _position = 0;
 | 
						|
	int _error = 0;
 | 
						|
	QByteArray _data;
 | 
						|
 | 
						|
};
 | 
						|
 | 
						|
} // namespace internal
 | 
						|
 | 
						|
constexpr int kCaseSensitive = 1;
 | 
						|
constexpr int kCaseInsensitive = 2;
 | 
						|
 | 
						|
class FileToRead {
 | 
						|
public:
 | 
						|
	FileToRead(const QByteArray &content) : _data(content) {
 | 
						|
		auto funcs = _data.funcs();
 | 
						|
		if (!(_handle = unzOpen2(nullptr, &funcs))) {
 | 
						|
			_error = -1;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	int getGlobalInfo(unz_global_info *pglobal_info) {
 | 
						|
		if (error() == UNZ_OK) {
 | 
						|
			_error = _handle ? unzGetGlobalInfo(_handle, pglobal_info) : -1;
 | 
						|
		}
 | 
						|
		return _error;
 | 
						|
	}
 | 
						|
 | 
						|
	int locateFile(const char *szFileName, int iCaseSensitivity) {
 | 
						|
		if (error() == UNZ_OK) {
 | 
						|
			_error = _handle ? unzLocateFile(_handle, szFileName, iCaseSensitivity) : -1;
 | 
						|
		}
 | 
						|
		return error();
 | 
						|
	}
 | 
						|
 | 
						|
	int getCurrentFileInfo(
 | 
						|
		unz_file_info *pfile_info,
 | 
						|
		char *szFileName,
 | 
						|
		uLong fileNameBufferSize,
 | 
						|
		void *extraField,
 | 
						|
		uLong extraFieldBufferSize,
 | 
						|
		char *szComment,
 | 
						|
		uLong commentBufferSize
 | 
						|
	) {
 | 
						|
		if (error() == UNZ_OK) {
 | 
						|
			_error = _handle ? unzGetCurrentFileInfo(
 | 
						|
				_handle,
 | 
						|
				pfile_info,
 | 
						|
				szFileName,
 | 
						|
				fileNameBufferSize,
 | 
						|
				extraField,
 | 
						|
				extraFieldBufferSize,
 | 
						|
				szComment,
 | 
						|
				commentBufferSize
 | 
						|
			) : -1;
 | 
						|
		}
 | 
						|
		return error();
 | 
						|
	}
 | 
						|
 | 
						|
	int openCurrentFile() {
 | 
						|
		if (error() == UNZ_OK) {
 | 
						|
			_error = _handle ? unzOpenCurrentFile(_handle) : -1;
 | 
						|
		}
 | 
						|
		return error();
 | 
						|
	}
 | 
						|
 | 
						|
	int readCurrentFile(voidp buf, unsigned len) {
 | 
						|
		if (error() == UNZ_OK) {
 | 
						|
			auto result = _handle ? unzReadCurrentFile(_handle, buf, len) : -1;
 | 
						|
			if (result >= 0) {
 | 
						|
				return result;
 | 
						|
			} else {
 | 
						|
				_error = result;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		return error();
 | 
						|
	}
 | 
						|
 | 
						|
	int closeCurrentFile() {
 | 
						|
		if (error() == UNZ_OK) {
 | 
						|
			_error = _handle ? unzCloseCurrentFile(_handle) : -1;
 | 
						|
		}
 | 
						|
		return error();
 | 
						|
	}
 | 
						|
 | 
						|
	QByteArray readCurrentFileContent(int fileSizeLimit) {
 | 
						|
		unz_file_info fileInfo = { 0 };
 | 
						|
		if (getCurrentFileInfo(&fileInfo, nullptr, 0, nullptr, 0, nullptr, 0) != UNZ_OK) {
 | 
						|
			LOG(("Error: could not get current file info in a zip file."));
 | 
						|
			return QByteArray();
 | 
						|
		}
 | 
						|
 | 
						|
		auto size = fileInfo.uncompressed_size;
 | 
						|
		if (size > static_cast<uint32>(fileSizeLimit)) {
 | 
						|
			if (_error == UNZ_OK) _error = -1;
 | 
						|
			LOG(("Error: current file is too large (should be less than %1, got %2) in a zip file.").arg(fileSizeLimit).arg(size));
 | 
						|
			return QByteArray();
 | 
						|
		}
 | 
						|
		if (openCurrentFile() != UNZ_OK) {
 | 
						|
			LOG(("Error: could not open current file in a zip file."));
 | 
						|
			return QByteArray();
 | 
						|
		}
 | 
						|
 | 
						|
		QByteArray result;
 | 
						|
		result.resize(size);
 | 
						|
 | 
						|
		auto couldRead = readCurrentFile(result.data(), size);
 | 
						|
		if (couldRead != static_cast<int>(size)) {
 | 
						|
			LOG(("Error: could not read current file in a zip file, got %1.").arg(couldRead));
 | 
						|
			return QByteArray();
 | 
						|
		}
 | 
						|
 | 
						|
		if (closeCurrentFile() != UNZ_OK) {
 | 
						|
			LOG(("Error: could not close current file in a zip file."));
 | 
						|
			return QByteArray();
 | 
						|
		}
 | 
						|
 | 
						|
		return result;
 | 
						|
	}
 | 
						|
 | 
						|
	QByteArray readFileContent(const char *szFileName, int iCaseSensitivity, int fileSizeLimit) {
 | 
						|
		if (locateFile(szFileName, iCaseSensitivity) != UNZ_OK) {
 | 
						|
			LOG(("Error: could not locate '%1' in a zip file.").arg(szFileName));
 | 
						|
			return QByteArray();
 | 
						|
		}
 | 
						|
		return readCurrentFileContent(fileSizeLimit);
 | 
						|
	}
 | 
						|
 | 
						|
	void close() {
 | 
						|
		if (_handle && unzClose(_handle) != UNZ_OK && _error == UNZ_OK) {
 | 
						|
			_error = -1;
 | 
						|
		}
 | 
						|
		_handle = nullptr;
 | 
						|
	}
 | 
						|
 | 
						|
	int error() const {
 | 
						|
		if (auto dataError = _data.error()) {
 | 
						|
			return dataError;
 | 
						|
		}
 | 
						|
		return _error;
 | 
						|
	}
 | 
						|
 | 
						|
	void clearError() {
 | 
						|
		_error = UNZ_OK;
 | 
						|
	}
 | 
						|
 | 
						|
	~FileToRead() {
 | 
						|
		close();
 | 
						|
	}
 | 
						|
 | 
						|
private:
 | 
						|
	internal::InMemoryFile _data;
 | 
						|
	unzFile _handle = nullptr;
 | 
						|
	int _error = 0;
 | 
						|
 | 
						|
};
 | 
						|
 | 
						|
class FileToWrite {
 | 
						|
public:
 | 
						|
	FileToWrite() {
 | 
						|
		auto funcs = _data.funcs();
 | 
						|
		if (!(_handle = zipOpen2(nullptr, APPEND_STATUS_CREATE, nullptr, &funcs))) {
 | 
						|
			_error = -1;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	int openNewFile(
 | 
						|
		const char *filename,
 | 
						|
		const zip_fileinfo *zipfi,
 | 
						|
		const void *extrafield_local,
 | 
						|
		uInt size_extrafield_local,
 | 
						|
		const void* extrafield_global,
 | 
						|
		uInt size_extrafield_global,
 | 
						|
		const char* comment,
 | 
						|
		int method,
 | 
						|
		int level
 | 
						|
	) {
 | 
						|
		if (error() == ZIP_OK) {
 | 
						|
			_error = _handle ? zipOpenNewFileInZip(
 | 
						|
				_handle,
 | 
						|
				filename,
 | 
						|
				zipfi,
 | 
						|
				extrafield_local,
 | 
						|
				size_extrafield_local,
 | 
						|
				extrafield_global,
 | 
						|
				size_extrafield_global,
 | 
						|
				comment,
 | 
						|
				method,
 | 
						|
				level
 | 
						|
			) : -1;
 | 
						|
		}
 | 
						|
		return error();
 | 
						|
	}
 | 
						|
 | 
						|
	int writeInFile(const void* buf, unsigned len) {
 | 
						|
		if (error() == ZIP_OK) {
 | 
						|
			_error = _handle ? zipWriteInFileInZip(_handle, buf, len) : -1;
 | 
						|
		}
 | 
						|
		return error();
 | 
						|
	}
 | 
						|
 | 
						|
	int closeFile() {
 | 
						|
		if (error() == ZIP_OK) {
 | 
						|
			_error = _handle ? zipCloseFileInZip(_handle) : -1;
 | 
						|
		}
 | 
						|
		return error();
 | 
						|
	}
 | 
						|
 | 
						|
	void close() {
 | 
						|
		if (_handle && zipClose(_handle, nullptr) != ZIP_OK && _error == ZIP_OK) {
 | 
						|
			_error = -1;
 | 
						|
		}
 | 
						|
		_handle = nullptr;
 | 
						|
	}
 | 
						|
 | 
						|
	int error() const {
 | 
						|
		if (auto dataError = _data.error()) {
 | 
						|
			return dataError;
 | 
						|
		}
 | 
						|
		return _error;
 | 
						|
	}
 | 
						|
 | 
						|
	QByteArray result() const {
 | 
						|
		return _data.result();
 | 
						|
	}
 | 
						|
 | 
						|
	~FileToWrite() {
 | 
						|
		close();
 | 
						|
	}
 | 
						|
 | 
						|
private:
 | 
						|
	internal::InMemoryFile _data;
 | 
						|
	zipFile _handle = nullptr;
 | 
						|
	int _error = 0;
 | 
						|
 | 
						|
};
 | 
						|
 | 
						|
} // namespace zlib
 |