| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406 |
- // 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
|