tdesktop/Telegram/SourceFiles/base/zlib_help.h

391 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