init
Some checks failed
Docker. / Ubuntu (push) Has been cancelled
User-agent updater. / User-agent (push) Failing after 15s
Lock Threads / lock (push) Failing after 10s
Waiting for answer. / waiting-for-answer (push) Failing after 22s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
Close stale issues and PRs / stale (push) Has been cancelled
Some checks failed
Docker. / Ubuntu (push) Has been cancelled
User-agent updater. / User-agent (push) Failing after 15s
Lock Threads / lock (push) Failing after 10s
Waiting for answer. / waiting-for-answer (push) Failing after 22s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
Close stale issues and PRs / stale (push) Has been cancelled
This commit is contained in:
406
Telegram/lib_base/base/zlib_help.h
Normal file
406
Telegram/lib_base/base/zlib_help.h
Normal file
@@ -0,0 +1,406 @@
|
||||
// This file is part of Desktop App Toolkit,
|
||||
// a set of libraries for developing nice desktop applications.
|
||||
//
|
||||
// For license and copyright information please follow this link:
|
||||
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include <zip.h>
|
||||
#include <unzip.h>
|
||||
#include "logs.h"
|
||||
|
||||
#ifdef small
|
||||
#undef small
|
||||
#endif // small
|
||||
|
||||
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 goToFirstFile() {
|
||||
if (error() == UNZ_OK) {
|
||||
_error = _handle ? unzGoToFirstFile(_handle) : -1;
|
||||
}
|
||||
return error();
|
||||
}
|
||||
|
||||
int goToNextFile() {
|
||||
if (error() == UNZ_OK) {
|
||||
_error = _handle ? unzGoToNextFile(_handle) : -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();
|
||||
}
|
||||
|
||||
QString getCurrentFileName() {
|
||||
unz_file_info info = { 0 };
|
||||
constexpr auto kMaxName = 128;
|
||||
char name[kMaxName + 1] = { 0 };
|
||||
const auto result = getCurrentFileInfo(
|
||||
&info,
|
||||
name,
|
||||
kMaxName,
|
||||
nullptr,
|
||||
0,
|
||||
nullptr,
|
||||
0);
|
||||
return (result == UNZ_OK) ? QString::fromUtf8(name) : QString();
|
||||
}
|
||||
|
||||
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
|
||||
Reference in New Issue
Block a user