[engraving] removed Qt dependencies

This commit is contained in:
Igor Korsukov 2022-07-01 11:27:31 +03:00
parent fd059563a0
commit c83d6630a2
23 changed files with 1141 additions and 137 deletions

View file

@ -98,6 +98,7 @@ QString SettingListModel::typeToString(Val::Type t) const
case Val::Type::Undefined: return "Undefined";
case Val::Type::Bool: return "Bool";
case Val::Type::Int: return "Int";
case Val::Type::Int64: return "Int";
case Val::Type::Double: return "Double";
case Val::Type::String: return "String";
case Val::Type::Color: return "Color";

View file

@ -122,10 +122,12 @@ QString AdvancedPreferencesModel::typeToString(Val::Type type) const
case Val::Type::Undefined: return "Undefined";
case Val::Type::Bool: return "Bool";
case Val::Type::Int: return "Int";
case Val::Type::Int64: return "Int";
case Val::Type::Double: return "Double";
case Val::Type::String: return "String";
case Val::Type::Color: return "Color";
default: return "Undefined";
case Val::Type::List: return "List";
case Val::Type::Map: return "Map";
}
return "Undefined";
}

View file

@ -291,8 +291,8 @@ StringList MscReader::ZipFileReader::fileList() const
StringList files;
std::vector<ZipReader::FileInfo> fileInfoList = m_zip->fileInfoList();
if (m_zip->status() != ZipReader::NoError) {
LOGD() << "failed read meta, status: " << m_zip->status();
if (m_zip->hasError()) {
LOGD() << "failed read meta";
}
for (const ZipReader::FileInfo& fi : fileInfoList) {
@ -311,8 +311,8 @@ ByteArray MscReader::ZipFileReader::fileData(const String& fileName) const
}
ByteArray data = m_zip->fileData(fileName.toStdString());
if (m_zip->status() != ZipReader::NoError) {
LOGD() << "failed read data, status: " << m_zip->status();
if (m_zip->hasError()) {
LOGD() << "failed read data";
return ByteArray();
}
return data;

View file

@ -296,8 +296,8 @@ bool MscWriter::ZipFileWriter::addFileData(const String& fileName, const ByteArr
}
m_zip->addFile(fileName.toStdString(), data);
if (m_zip->status() != ZipWriter::NoError) {
LOGE() << "failed write files to zip, status: " << m_zip->status();
if (m_zip->hasError()) {
LOGE() << "failed write files to zip";
return false;
}
return true;

View file

@ -63,10 +63,6 @@ set(MODULE_SRC
${CMAKE_CURRENT_LIST_DIR}/progress.h
${CMAKE_CURRENT_LIST_DIR}/smuflranges.cpp
${CMAKE_CURRENT_LIST_DIR}/smuflranges.h
${CMAKE_CURRENT_LIST_DIR}/xmlreader.cpp
${CMAKE_CURRENT_LIST_DIR}/xmlreader.h
${CMAKE_CURRENT_LIST_DIR}/xmlwriter.cpp
${CMAKE_CURRENT_LIST_DIR}/xmlwriter.h
${CMAKE_CURRENT_LIST_DIR}/utils.cpp
${CMAKE_CURRENT_LIST_DIR}/utils.h
${CMAKE_CURRENT_LIST_DIR}/defer.h
@ -109,9 +105,9 @@ set(MODULE_SRC
${CMAKE_CURRENT_LIST_DIR}/serialization/zipreader.h
${CMAKE_CURRENT_LIST_DIR}/serialization/zipwriter.cpp
${CMAKE_CURRENT_LIST_DIR}/serialization/zipwriter.h
${CMAKE_CURRENT_LIST_DIR}/serialization/internal/qzip.cpp
${CMAKE_CURRENT_LIST_DIR}/serialization/internal/qzipreader_p.h
${CMAKE_CURRENT_LIST_DIR}/serialization/internal/qzipwriter_p.h
${CMAKE_CURRENT_LIST_DIR}/serialization/internal/zipcontainer.cpp
${CMAKE_CURRENT_LIST_DIR}/serialization/internal/zipcontainer.h
${CMAKE_CURRENT_LIST_DIR}/serialization/textstream.cpp
${CMAKE_CURRENT_LIST_DIR}/serialization/textstream.h
${CMAKE_CURRENT_LIST_DIR}/serialization/json.cpp
@ -124,6 +120,10 @@ if (NOT GLOBAL_NO_INTERNAL)
${CMAKE_CURRENT_LIST_DIR}/globalmodule.h
${CMAKE_CURRENT_LIST_DIR}/settings.cpp
${CMAKE_CURRENT_LIST_DIR}/settings.h
${CMAKE_CURRENT_LIST_DIR}/xmlreader.cpp
${CMAKE_CURRENT_LIST_DIR}/xmlreader.h
${CMAKE_CURRENT_LIST_DIR}/xmlwriter.cpp
${CMAKE_CURRENT_LIST_DIR}/xmlwriter.h
${CMAKE_CURRENT_LIST_DIR}/internal/application.cpp
${CMAKE_CURRENT_LIST_DIR}/internal/application.h
${CMAKE_CURRENT_LIST_DIR}/internal/globalconfiguration.cpp
@ -137,6 +137,10 @@ if (NOT GLOBAL_NO_INTERNAL)
${CMAKE_CURRENT_LIST_DIR}/io/internal/filesystem.cpp
${CMAKE_CURRENT_LIST_DIR}/io/internal/filesystem.h
${CMAKE_CURRENT_LIST_DIR}/serialization/internal/qzip.cpp
${CMAKE_CURRENT_LIST_DIR}/serialization/internal/qzipreader_p.h
${CMAKE_CURRENT_LIST_DIR}/serialization/internal/qzipwriter_p.h
)
endif()

View file

@ -31,6 +31,11 @@ Dir::Dir(const path_t& path)
{
}
path_t Dir::path() const
{
return m_path;
}
path_t Dir::absolutePath() const
{
return fileSystem()->absoluteFilePath(m_path);
@ -55,3 +60,30 @@ RetVal<io::paths_t> Dir::scanFiles(const io::path_t& rootDir, const std::vector<
{
return fileSystem()->scanFiles(rootDir, filters, mode);
}
path_t Dir::fromNativeSeparators(const path_t& pathName)
{
#if defined(Q_OS_WIN)
String path = pathName.toString();
size_t i = path.indexOf(u'\\');
if (i != mu::nidx) {
String n(path);
if (n.startsWith(u"\\\\?\\")) {
n.remove(0, 4);
i = n.indexOf(u'\\');
if (i == mu::nidx) {
return n;
}
}
for (i = 0; i < n.size(); ++i) {
if (n.at(i) == u'\\') {
n[i] = u'/';
}
}
return n;
}
#endif
return pathName;
}

View file

@ -40,6 +40,7 @@ public:
Dir() = default;
Dir(const path_t& path);
path_t path() const;
path_t absolutePath() const;
bool exists() const;
@ -50,6 +51,8 @@ public:
static RetVal<io::paths_t> scanFiles(const io::path_t& rootDir, const std::vector<std::string>& filters,
ScanMode mode = ScanMode::FilesInCurrentDirAndSubdirs);
static path_t fromNativeSeparators(const path_t& pathName);
private:
path_t m_path;
};

View file

@ -127,6 +127,10 @@ String FileInfo::doSuffix(const String& filePath)
}
size_t lastSep = filePath.lastIndexOf(u'/');
if (lastSep == mu::nidx) {
lastSep = 0;
}
if (lastDot < lastSep) {
return String();
}
@ -173,3 +177,13 @@ bool FileInfo::exists(const path_t& filePath)
{
return fileSystem()->exists(filePath);
}
Dir FileInfo::dir() const
{
size_t lastSep = m_filePath.lastIndexOf(u'/');
if (lastSep == mu::nidx) {
return Dir(".");
}
String dirPath = m_filePath.mid(0, lastSep);
return Dir(io::path_t(dirPath));
}

View file

@ -22,6 +22,9 @@
#ifndef MU_IO_FILEINFO_H
#define MU_IO_FILEINFO_H
#include "types/string.h"
#include "dir.h"
#include "modularity/ioc.h"
#include "ifilesystem.h"
@ -53,6 +56,8 @@ public:
DateTime birthTime() const;
DateTime lastModified() const;
Dir dir() const;
private:
static String doSuffix(const String& filePath);

View file

@ -21,9 +21,6 @@
*/
#include "path.h"
#include <QDir>
#include <QRegularExpression>
#include "stringutils.h"
#include "fileinfo.h"
@ -114,99 +111,98 @@ std::wstring path_t::toStdWString() const
std::string mu::io::suffix(const mu::io::path_t& path)
{
QFileInfo fi(path.toQString());
return fi.suffix().toLower().toStdString();
return FileInfo::suffix(path).toLower().toStdString();
}
mu::io::path_t mu::io::filename(const mu::io::path_t& path, bool includingExtension)
{
QFileInfo fi(path.toQString());
FileInfo fi(path);
return includingExtension ? fi.fileName() : fi.completeBaseName();
}
mu::io::path_t mu::io::basename(const mu::io::path_t& path)
{
QFileInfo fi(path.toQString());
FileInfo fi(path);
return fi.baseName();
}
mu::io::path_t mu::io::completeBasename(const mu::io::path_t& path)
{
QFileInfo fi(path.toQString());
FileInfo fi(path);
return fi.completeBaseName();
}
mu::io::path_t mu::io::absolutePath(const path_t& path)
{
return QFileInfo(path.toQString()).absolutePath();
}
mu::io::path_t mu::io::dirname(const mu::io::path_t& path)
{
return QFileInfo(path.toQString()).dir().dirName();
return FileInfo(path).absolutePath();
}
mu::io::path_t mu::io::dirpath(const mu::io::path_t& path)
{
return QFileInfo(path.toQString()).dir().path();
return FileInfo(path).dir().path();
}
mu::io::path_t mu::io::absoluteDirpath(const mu::io::path_t& path)
{
return QFileInfo(path.toQString()).dir().absolutePath();
return FileInfo(path).dir().absolutePath();
}
bool mu::io::isAbsolute(const path_t& path)
{
return QFileInfo(path.toQString()).isAbsolute();
return FileInfo(path).isAbsolute();
}
bool mu::io::isAllowedFileName(const path_t& fn_)
{
QString fn = basename(fn_).toQString();
std::string fn = basename(fn_).toStdString();
if (fn.empty()) {
return false;
}
// Windows filenames are not case sensitive.
fn = fn.toUpper();
fn = String::fromStdString(fn).toUpper().toStdString();
static const QString illegal="<>:\"|?*";
static const std::string illegal="<>:\"|?*";
for (const QChar& c : fn) {
for (const char& c : fn) {
// Check for control characters
if (c.toLatin1() > 0 && c.toLatin1() < 32) {
if (c > 0 && c < 32) {
return false;
}
// Check for illegal characters
if (illegal.contains(c)) {
return false;
for (const char& ilc : illegal) {
if (c == ilc) {
return false;
}
}
}
// Check for device names in filenames
static const QStringList devices = {
static const std::vector<std::string> devices = {
"CON", "PRN", "AUX", "NUL",
"COM0", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9",
"LPT0", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9"
};
foreach (const QString& s, devices) {
for (const std::string& s : devices) {
if (fn == s) {
return false;
}
}
// Check for trailing periods or spaces
if (fn.right(1) == "." || fn.right(1) == " ") {
if (fn.back() == '.' || fn.back() == ' ') {
return false;
}
// Check for pathnames that are too long
if (fn.length() > 96) {
if (fn.size() > 96) {
return false;
}
// Since we are checking for a filename, it mustn't be a directory
if (fn.right(1) == "\\") {
if (fn.back() == '\\') {
return false;
}
@ -219,20 +215,30 @@ mu::io::path_t mu::io::escapeFileName(const mu::io::path_t& fn_)
// special characters in filenames are a constant source
// of trouble, this replaces some of them common in german:
//
QString fn = fn_.toQString();
String fn = fn_.toString();
fn = fn.simplified();
fn = fn.replace(QChar(' '), "_");
fn = fn.replace(QChar('\n'), "_");
fn = fn.replace(QChar(0xe4), "ae"); // &auml;
fn = fn.replace(QChar(0xf6), "oe"); // &ouml;
fn = fn.replace(QChar(0xfc), "ue"); // &uuml;
fn = fn.replace(QChar(0xdf), "ss"); // &szlig;
fn = fn.replace(QChar(0xc4), "Ae"); // &Auml;
fn = fn.replace(QChar(0xd6), "Oe"); // &Ouml;
fn = fn.replace(QChar(0xdc), "Ue"); // &Uuml;
fn = fn.replace(QChar(0x266d), "b"); // musical flat sign, happen in instrument names, so can happen in part (file) names
fn = fn.replace(QChar(0x266f), "#"); // musical sharp sign, can happen in titles, so can happen in score (file) names
fn = fn.replace(QRegularExpression("[" + QRegularExpression::escape("\\/:*?\"<>|") + "]"), "_"); //FAT/NTFS special chars
fn = fn.replace(' ', '_');
fn = fn.replace('\n', '_');
fn = fn.replace(Char(0xe4), u"ae"); // &auml;
fn = fn.replace(Char(0xf6), u"oe"); // &ouml;
fn = fn.replace(Char(0xfc), u"ue"); // &uuml;
fn = fn.replace(Char(0xdf), u"ss"); // &szlig;
fn = fn.replace(Char(0xc4), u"Ae"); // &Auml;
fn = fn.replace(Char(0xd6), u"Oe"); // &Ouml;
fn = fn.replace(Char(0xdc), u"Ue"); // &Uuml;
fn = fn.replace(Char(0x266d), u"b"); // musical flat sign, happen in instrument names, so can happen in part (file) names
fn = fn.replace(Char(0x266f), u"#"); // musical sharp sign, can happen in titles, so can happen in score (file) names
//FAT/NTFS special chars
fn = fn.replace('<', '_')
.replace('>', '_')
.replace(':', '_')
.replace('"', '_')
.replace('/', '_')
.replace('\\', '_')
.replace('|', '_')
.replace('?', '_')
.replace('*', '_');
return fn;
}

View file

@ -100,7 +100,7 @@ path_t filename(const path_t& path, bool includingExtension = true);
path_t basename(const path_t& path);
path_t completeBasename(const path_t& path);
path_t absolutePath(const path_t& path);
path_t dirname(const path_t& path);
//path_t dirname(const path_t& path);
path_t dirpath(const path_t& path);
path_t absoluteDirpath(const path_t& path);

View file

@ -0,0 +1,828 @@
/*
* SPDX-License-Identifier: GPL-3.0-only
* MuseScore-CLA-applies
*
* MuseScore
* Music Composition & Notation
*
* Copyright (C) 2021 MuseScore BVBA and others
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program 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.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "zipcontainer.h"
#include <ctime>
#include <cstring>
#include <zlib.h>
#include "io/dir.h"
#include "log.h"
// Zip standard version for archives handled by this API
// (actually, the only basic support of this version is implemented but it is enough for now)
#define ZIP_VERSION 20
#if 0
#define ZDEBUG LOGD
#else
#define ZDEBUG if (0) LOGD
#endif
using namespace mu::io;
namespace mu {
static inline uint readUInt(const uint8_t* data)
{
return (data[0]) + (data[1] << 8) + (data[2] << 16) + (data[3] << 24);
}
static inline ushort readUShort(const uint8_t* data)
{
return (data[0]) + (data[1] << 8);
}
static inline void writeUInt(uint8_t* data, uint i)
{
data[0] = i & 0xff;
data[1] = (i >> 8) & 0xff;
data[2] = (i >> 16) & 0xff;
data[3] = (i >> 24) & 0xff;
}
static inline void writeUShort(uint8_t* data, ushort i)
{
data[0] = i & 0xff;
data[1] = (i >> 8) & 0xff;
}
static inline void copyUInt(uint8_t* dest, const uint8_t* src)
{
dest[0] = src[0];
dest[1] = src[1];
dest[2] = src[2];
dest[3] = src[3];
}
static inline void copyUShort(uint8_t* dest, const uint8_t* src)
{
dest[0] = src[0];
dest[1] = src[1];
}
static void writeMSDosDate(uint8_t* dest, const std::tm& dt)
{
if (dt.tm_year > 0) {
uint16_t time
=(dt.tm_hour << 11) // 5 bit hour
| (dt.tm_min << 5) // 6 bit minute
| (dt.tm_sec >> 1); // 5 bit double seconds
dest[0] = time & 0xff;
dest[1] = time >> 8;
uint16_t date
=((dt.tm_year + 1900 - 1980) << 9) // 7 bit year 1980-based
| ((dt.tm_mon + 1) << 5) // 4 bit month
| (dt.tm_mday); // 5 bit day
dest[2] = char(date);
dest[3] = char(date >> 8);
} else {
dest[0] = 0;
dest[1] = 0;
dest[2] = 0;
dest[3] = 0;
}
}
static int inflate(Bytef* dest, ulong* destLen, const Bytef* source, ulong sourceLen)
{
z_stream stream;
int err;
stream.next_in = const_cast<Bytef*>(source);
stream.avail_in = (uInt)sourceLen;
if ((uLong)stream.avail_in != sourceLen) {
return Z_BUF_ERROR;
}
stream.next_out = dest;
stream.avail_out = (uInt) * destLen;
if ((uLong)stream.avail_out != *destLen) {
return Z_BUF_ERROR;
}
stream.zalloc = (alloc_func)0;
stream.zfree = (free_func)0;
err = inflateInit2(&stream, -MAX_WBITS);
if (err != Z_OK) {
return err;
}
err = inflate(&stream, Z_FINISH);
if (err != Z_STREAM_END) {
inflateEnd(&stream);
if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0)) {
return Z_DATA_ERROR;
}
return err;
}
*destLen = stream.total_out;
err = inflateEnd(&stream);
return err;
}
static int deflate(Bytef* dest, ulong* destLen, const Bytef* source, ulong sourceLen)
{
z_stream stream;
int err;
stream.next_in = const_cast<Bytef*>(source);
stream.avail_in = (uInt)sourceLen;
stream.next_out = dest;
stream.avail_out = (uInt) * destLen;
if ((uLong)stream.avail_out != *destLen) {
return Z_BUF_ERROR;
}
stream.zalloc = (alloc_func)0;
stream.zfree = (free_func)0;
stream.opaque = (voidpf)0;
err = deflateInit2(&stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS, 8, Z_DEFAULT_STRATEGY);
if (err != Z_OK) {
return err;
}
err = deflate(&stream, Z_FINISH);
if (err != Z_STREAM_END) {
deflateEnd(&stream);
return err == Z_OK ? Z_BUF_ERROR : err;
}
*destLen = stream.total_out;
err = deflateEnd(&stream);
return err;
}
namespace WindowsFileAttributes {
enum {
Dir = 0x10, // FILE_ATTRIBUTE_DIRECTORY
File = 0x80, // FILE_ATTRIBUTE_NORMAL
TypeMask = 0x90,
ReadOnly = 0x01, // FILE_ATTRIBUTE_READONLY
PermMask = 0x01
};
}
namespace UnixFileAttributes {
enum {
Dir = 0040000, // __S_IFDIR
File = 0100000, // __S_IFREG
SymLink = 0120000, // __S_IFLNK
TypeMask = 0170000, // __S_IFMT
ReadUser = 0400, // __S_IRUSR
WriteUser = 0200, // __S_IWUSR
ExeUser = 0100, // __S_IXUSR
ReadGroup = 0040, // __S_IRGRP
WriteGroup = 0020, // __S_IWGRP
ExeGroup = 0010, // __S_IXGRP
ReadOther = 0004, // __S_IROTH
WriteOther = 0002, // __S_IWOTH
ExeOther = 0001, // __S_IXOTH
PermMask = 0777
};
}
static std::tm readMSDosDate(const uint8_t* src)
{
std::tm tm;
uint dosDate = readUInt(src);
uint64_t uDate;
uDate = (uint64_t)(dosDate >> 16);
tm.tm_mday = (uDate & 0x1f);
tm.tm_mon = ((uDate & 0x1E0) >> 5) - 1;
tm.tm_year = (((uDate & 0x0FE00) >> 9) + 1980 - 1900);
tm.tm_hour = ((dosDate & 0xF800) >> 11);
tm.tm_min = ((dosDate & 0x7E0) >> 5);
tm.tm_sec = ((dosDate & 0x1f) << 1);
return tm;
}
// for details, see http://www.pkware.com/documents/casestudies/APPNOTE.TXT
enum HostOS {
HostFAT = 0,
HostAMIGA = 1,
HostVMS = 2, // VAX/VMS
HostUnix = 3,
HostVM_CMS = 4,
HostAtari = 5, // what if it's a minix filesystem? [cjh]
HostHPFS = 6, // filesystem used by OS/2 (and NT 3.x)
HostMac = 7,
HostZ_System = 8,
HostCPM = 9,
HostTOPS20 = 10, // pkzip 2.50 NTFS
HostNTFS = 11, // filesystem used by Windows NT
HostQDOS = 12, // SMS/QDOS
HostAcorn = 13, // Archimedes Acorn RISC OS
HostVFAT = 14, // filesystem used by Windows 95, NT
HostMVS = 15,
HostBeOS = 16, // hybrid POSIX/database filesystem
HostTandem = 17,
HostOS400 = 18,
HostOSX = 19
};
enum GeneralPurposeFlag {
Encrypted = 0x01,
AlgTune1 = 0x02,
AlgTune2 = 0x04,
HasDataDescriptor = 0x08,
PatchedData = 0x20,
StrongEncrypted = 0x40,
Utf8Names = 0x0800,
CentralDirectoryEncrypted = 0x2000
};
enum CompressionMethod {
CompressionMethodStored = 0,
CompressionMethodShrunk = 1,
CompressionMethodReduced1 = 2,
CompressionMethodReduced2 = 3,
CompressionMethodReduced3 = 4,
CompressionMethodReduced4 = 5,
CompressionMethodImploded = 6,
CompressionMethodReservedTokenizing = 7, // reserved for tokenizing
CompressionMethodDeflated = 8,
CompressionMethodDeflated64 = 9,
CompressionMethodPKImploding = 10,
CompressionMethodBZip2 = 12,
CompressionMethodLZMA = 14,
CompressionMethodTerse = 18,
CompressionMethodLz77 = 19,
CompressionMethodJpeg = 96,
CompressionMethodWavPack = 97,
CompressionMethodPPMd = 98,
CompressionMethodWzAES = 99
};
struct LocalFileHeader
{
uint8_t signature[4]; // 0x04034b50
uint8_t version_needed[2];
uint8_t general_purpose_bits[2];
uint8_t compression_method[2];
uint8_t last_mod_file[4];
uint8_t crc_32[4];
uint8_t compressed_size[4];
uint8_t uncompressed_size[4];
uint8_t file_name_length[2];
uint8_t extra_field_length[2];
};
struct DataDescriptor
{
uint8_t crc_32[4];
uint8_t compressed_size[4];
uint8_t uncompressed_size[4];
};
struct CentralFileHeader
{
uint8_t signature[4]; // 0x02014b50
uint8_t version_made[2];
uint8_t version_needed[2];
uint8_t general_purpose_bits[2];
uint8_t compression_method[2];
uint8_t last_mod_file[4];
uint8_t crc_32[4];
uint8_t compressed_size[4];
uint8_t uncompressed_size[4];
uint8_t file_name_length[2];
uint8_t extra_field_length[2];
uint8_t file_comment_length[2];
uint8_t disk_start[2];
uint8_t internal_file_attributes[2];
uint8_t external_file_attributes[4];
uint8_t offset_local_header[4];
LocalFileHeader toLocalHeader() const;
};
struct EndOfDirectory
{
uint8_t signature[4]; // 0x06054b50
uint8_t this_disk[2];
uint8_t start_of_directory_disk[2];
uint8_t num_dir_entries_this_disk[2];
uint8_t num_dir_entries[2];
uint8_t directory_size[4];
uint8_t dir_start_offset[4];
uint8_t comment_length[2];
};
struct FileHeader
{
CentralFileHeader h;
ByteArray file_name;
ByteArray extra_field;
ByteArray file_comment;
};
LocalFileHeader CentralFileHeader::toLocalHeader() const
{
LocalFileHeader h;
writeUInt(h.signature, 0x04034b50);
copyUShort(h.version_needed, version_needed);
copyUShort(h.general_purpose_bits, general_purpose_bits);
copyUShort(h.compression_method, compression_method);
copyUInt(h.last_mod_file, last_mod_file);
copyUInt(h.crc_32, crc_32);
copyUInt(h.compressed_size, compressed_size);
copyUInt(h.uncompressed_size, uncompressed_size);
copyUShort(h.file_name_length, file_name_length);
copyUShort(h.extra_field_length, extra_field_length);
return h;
}
struct ZipContainer::Impl {
IODevice* device = nullptr;
bool dirtyFileTree = true;
std::vector<FileHeader> fileHeaders;
ByteArray comment;
uint start_of_directory = 0;
ZipContainer::Status status = ZipContainer::NoError;
ZipContainer::CompressionPolicy compressionPolicy;
enum EntryType {
Directory, File, Symlink
};
void addEntry(EntryType type, const std::string& fileName, const ByteArray& contents);
Impl(IODevice* d)
: device(d) {}
void scanFiles();
ZipContainer::FileInfo fillFileInfo(int index) const;
};
void ZipContainer::Impl::scanFiles()
{
if (!dirtyFileTree) {
return;
}
if (!(device->isOpen() || device->open(IODevice::ReadOnly))) {
status = ZipContainer::FileOpenError;
return;
}
if ((device->openMode() & IODevice::ReadOnly) == 0) { // only read the index from readable files.
status = ZipContainer::FileReadError;
return;
}
dirtyFileTree = false;
uint8_t tmp[4];
device->read(tmp, 4);
if (readUInt(tmp) != 0x04034b50) {
LOGW("Zip: not a zip file!");
return;
}
// find EndOfDirectory header
int i = 0;
int start_of_directory_local = -1;
int num_dir_entries = 0;
EndOfDirectory eod;
while (start_of_directory_local == -1) {
const int pos = device->size() - int(sizeof(EndOfDirectory)) - i;
if (pos < 0 || i > 65535) {
LOGW("Zip: EndOfDirectory not found");
return;
}
device->seek(pos);
device->read((uint8_t*)&eod, sizeof(EndOfDirectory));
if (readUInt(eod.signature) == 0x06054b50) {
break;
}
++i;
}
// have the eod
start_of_directory_local = readUInt(eod.dir_start_offset);
num_dir_entries = readUShort(eod.num_dir_entries);
ZDEBUG("start_of_directory at %d, num_dir_entries=%d", start_of_directory_local, num_dir_entries);
int comment_length = readUShort(eod.comment_length);
if (comment_length != i) {
LOGW("Zip: failed to parse zip file.");
}
comment = device->read(std::min(comment_length, i));
device->seek(start_of_directory_local);
for (i = 0; i < num_dir_entries; ++i) {
FileHeader header;
int read = device->read((uint8_t*)&header.h, sizeof(CentralFileHeader));
if (read < (int)sizeof(CentralFileHeader)) {
LOGW("Zip: Failed to read complete header, index may be incomplete");
break;
}
if (readUInt(header.h.signature) != 0x02014b50) {
LOGW("Zip: invalid header signature, index may be incomplete");
break;
}
size_t l = readUShort(header.h.file_name_length);
header.file_name = device->read(l);
if (header.file_name.size() != l) {
LOGW("Zip: Failed to read filename from zip index, index may be incomplete");
break;
}
l = readUShort(header.h.extra_field_length);
header.extra_field = device->read(l);
if (header.extra_field.size() != l) {
LOGW("Zip: Failed to read extra field in zip file, skipping file, index may be incomplete");
break;
}
l = readUShort(header.h.file_comment_length);
header.file_comment = device->read(l);
if (header.file_comment.size() != l) {
LOGW("Zip: Failed to read read file comment, index may be incomplete");
break;
}
ZDEBUG("found file '%s'", header.file_name.data());
fileHeaders.push_back(header);
}
}
ZipContainer::FileInfo ZipContainer::Impl::fillFileInfo(int index) const
{
ZipContainer::FileInfo fileInfo;
FileHeader header = fileHeaders.at(index);
uint32_t mode = readUInt(header.h.external_file_attributes);
const HostOS hostOS = HostOS(readUShort(header.h.version_made) >> 8);
switch (hostOS) {
case HostUnix:
mode = (mode >> 16) & 0xffff;
switch (mode & UnixFileAttributes::TypeMask) {
case UnixFileAttributes::SymLink:
fileInfo.isSymLink = true;
break;
case UnixFileAttributes::Dir:
fileInfo.isDir = true;
break;
case UnixFileAttributes::File:
default: // ### just for the case; should we warn?
fileInfo.isFile = true;
break;
}
break;
case HostFAT:
case HostNTFS:
case HostHPFS:
case HostVFAT:
switch (mode & WindowsFileAttributes::TypeMask) {
case WindowsFileAttributes::Dir:
fileInfo.isDir = true;
break;
case WindowsFileAttributes::File:
default:
fileInfo.isFile = true;
break;
}
break;
default:
LOGW("Zip: Zip entry format at %d is not supported.", index);
return fileInfo; // we don't support anything else
}
// ushort general_purpose_bits = readUShort(header.h.general_purpose_bits);
// if bit 11 is set, the filename and comment fields must be encoded using UTF-8
// const bool inUtf8 = (general_purpose_bits & Utf8Names) != 0;
fileInfo.filePath = header.file_name.constChar();
fileInfo.crc = readUInt(header.h.crc_32);
fileInfo.size = readUInt(header.h.uncompressed_size);
fileInfo.lastModified = readMSDosDate(header.h.last_mod_file);
// fix the file path, if broken (convert separators, eat leading and trailing ones)
fileInfo.filePath = Dir::fromNativeSeparators(fileInfo.filePath).toStdString();
while (!fileInfo.filePath.empty() && (fileInfo.filePath.front() == '.' || fileInfo.filePath.front() == '/')) {
fileInfo.filePath = fileInfo.filePath.substr(1);
}
while (!fileInfo.filePath.empty() && fileInfo.filePath.back() == '/') {
fileInfo.filePath = fileInfo.filePath.substr(fileInfo.filePath.size() - 1);
}
return fileInfo;
}
void ZipContainer::Impl::addEntry(EntryType type, const std::string& fileName, const ByteArray& contents)
{
if (!(device->isOpen() || device->open(IODevice::WriteOnly))) {
status = ZipContainer::FileOpenError;
return;
}
device->seek(start_of_directory);
// don't compress small files
ZipContainer::CompressionPolicy compression = compressionPolicy;
if (compressionPolicy == ZipContainer::AutoCompress) {
if (contents.size() < 64) {
compression = ZipContainer::NeverCompress;
} else {
compression = ZipContainer::AlwaysCompress;
}
}
FileHeader header;
std::memset(&header.h, 0, sizeof(CentralFileHeader));
writeUInt(header.h.signature, 0x02014b50);
writeUShort(header.h.version_needed, ZIP_VERSION);
writeUInt(header.h.uncompressed_size, contents.size());
std::time_t t = std::time(0); // get time now
std::tm* now = std::localtime(&t);
writeMSDosDate(header.h.last_mod_file, *now);
ByteArray data = contents;
if (compression == ZipContainer::AlwaysCompress) {
writeUShort(header.h.compression_method, CompressionMethodDeflated);
ulong len = contents.size();
// shamelessly copied form zlib
len += (len >> 12) + (len >> 14) + 11;
int res;
do {
data.resize(len);
res = deflate((uint8_t*)data.data(), &len, (const uint8_t*)contents.constData(), contents.size());
switch (res) {
case Z_OK:
data.resize(len);
break;
case Z_MEM_ERROR:
LOGW("Zip: Z_MEM_ERROR: Not enough memory to compress file, skipping");
data.resize(0);
break;
case Z_BUF_ERROR:
len *= 2;
break;
}
} while (res == Z_BUF_ERROR);
}
// TODO add a check if data.size() > contents.size(). Then try to store the original and revert the compression method to be uncompressed
writeUInt(header.h.compressed_size, data.size());
uint crc_32 = ::crc32(0, 0, 0);
crc_32 = ::crc32(crc_32, (const uint8_t*)contents.constData(), contents.size());
writeUInt(header.h.crc_32, crc_32);
// if bit 11 is set, the filename and comment fields must be encoded using UTF-8
ushort general_purpose_bits = Utf8Names; // always use utf-8
writeUShort(header.h.general_purpose_bits, general_purpose_bits);
//const bool inUtf8 = (general_purpose_bits & Utf8Names) != 0;
header.file_name = ByteArray(fileName.c_str(), fileName.size());
if (header.file_name.size() > 0xffff) {
LOGW("Zip: Filename is too long, chopping it to 65535 bytes");
header.file_name = header.file_name.left(0xffff); // ### don't break the utf-8 sequence, if any
}
if (header.file_comment.size() + header.file_name.size() > 0xffff) {
LOGW("Zip: File comment is too long, chopping it to 65535 bytes");
header.file_comment.truncate(0xffff - header.file_name.size()); // ### don't break the utf-8 sequence, if any
}
writeUShort(header.h.file_name_length, header.file_name.size());
//h.extra_field_length[2];
writeUShort(header.h.version_made, HostUnix << 8);
//uint8_t internal_file_attributes[2];
//uint8_t external_file_attributes[4];
uint32_t mode = 0;
switch (type) {
case Symlink:
mode |= UnixFileAttributes::SymLink;
break;
case Directory:
mode |= UnixFileAttributes::Dir;
break;
case File:
mode |= UnixFileAttributes::File;
break;
default:
UNREACHABLE;
break;
}
writeUInt(header.h.external_file_attributes, mode << 16);
writeUInt(header.h.offset_local_header, start_of_directory);
fileHeaders.push_back(header);
LocalFileHeader h = header.h.toLocalHeader();
device->write((const uint8_t*)&h, sizeof(LocalFileHeader));
device->write(header.file_name);
device->write(data);
start_of_directory = device->pos();
dirtyFileTree = true;
}
ZipContainer::ZipContainer(IODevice* device)
: p(new Impl(device))
{
assert(device);
}
ZipContainer::~ZipContainer()
{
close();
delete p;
}
std::vector<ZipContainer::FileInfo> ZipContainer::fileInfoList() const
{
p->scanFiles();
std::vector<FileInfo> files;
const int numFileHeaders = p->fileHeaders.size();
files.reserve(numFileHeaders);
for (int i = 0; i < numFileHeaders; ++i) {
files.push_back(p->fillFileInfo(i));
}
return files;
}
int ZipContainer::count() const
{
p->scanFiles();
return p->fileHeaders.size();
}
ByteArray ZipContainer::fileData(const std::string& fileName) const
{
p->scanFiles();
size_t i;
for (i = 0; i < p->fileHeaders.size(); ++i) {
if (p->fileHeaders.at(i).file_name == ByteArray::fromRawData(fileName.c_str(), fileName.size())) {
break;
}
}
if (i == p->fileHeaders.size()) {
return ByteArray();
}
FileHeader header = p->fileHeaders.at(i);
ushort version_needed = readUShort(header.h.version_needed);
if (version_needed > ZIP_VERSION) {
LOGW("Zip: .ZIP specification version %d implementationis needed to extract the data.", version_needed);
return ByteArray();
}
ushort general_purpose_bits = readUShort(header.h.general_purpose_bits);
int compressed_size = readUInt(header.h.compressed_size);
int uncompressed_size = readUInt(header.h.uncompressed_size);
int start = readUInt(header.h.offset_local_header);
p->device->seek(start);
LocalFileHeader lh;
p->device->read((uint8_t*)&lh, sizeof(LocalFileHeader));
uint skip = readUShort(lh.file_name_length) + readUShort(lh.extra_field_length);
p->device->seek(p->device->pos() + skip);
int compression_method = readUShort(lh.compression_method);
if ((general_purpose_bits & Encrypted) != 0) {
LOGW("Zip: Unsupported encryption method is needed to extract the data.");
return ByteArray();
}
ByteArray compressed = p->device->read(compressed_size);
if (compression_method == CompressionMethodStored) {
// no compression
compressed.truncate(uncompressed_size);
return compressed;
} else if (compression_method == CompressionMethodDeflated) {
// Deflate
//qDebug("compressed=%d", compressed.size());
compressed.truncate(compressed_size);
ByteArray baunzip;
ulong len = std::max(uncompressed_size, 1);
int res;
do {
baunzip.resize(len);
res = inflate((uint8_t*)baunzip.data(), &len,
(const uint8_t*)compressed.constData(), compressed_size);
switch (res) {
case Z_OK:
if ((size_t)len != baunzip.size()) {
baunzip.resize(len);
}
break;
case Z_MEM_ERROR:
LOGW("Zip: Z_MEM_ERROR: Not enough memory");
break;
case Z_BUF_ERROR:
len *= 2;
break;
case Z_DATA_ERROR:
LOGW("Zip: Z_DATA_ERROR: Input data is corrupted");
break;
}
} while (res == Z_BUF_ERROR);
return baunzip;
}
LOGW("Zip: Unsupported compression method %d is needed to extract the data.", compression_method);
return ByteArray();
}
ZipContainer::Status ZipContainer::status() const
{
return p->status;
}
void ZipContainer::setCompressionPolicy(CompressionPolicy policy)
{
p->compressionPolicy = policy;
}
ZipContainer::CompressionPolicy ZipContainer::compressionPolicy() const
{
return p->compressionPolicy;
}
void ZipContainer::addFile(const std::string& fileName, const ByteArray& data)
{
p->addEntry(Impl::File, Dir::fromNativeSeparators(fileName).toStdString(), data);
}
void ZipContainer::addDirectory(const std::string& dirName)
{
std::string name(Dir::fromNativeSeparators(dirName).toStdString());
// separator is mandatory
if (name.back() != '/') {
name.push_back('/');
}
p->addEntry(Impl::Directory, name, ByteArray());
}
void ZipContainer::close()
{
if (!(p->device->openMode() & IODevice::WriteOnly)) {
p->device->close();
return;
}
//qDebug("Zip::close writing directory, %d entries", p->fileHeaders.size());
p->device->seek(p->start_of_directory);
// write new directory
for (size_t i = 0; i < p->fileHeaders.size(); ++i) {
const FileHeader& header = p->fileHeaders.at(i);
p->device->write((const uint8_t*)&header.h, sizeof(CentralFileHeader));
p->device->write(header.file_name);
p->device->write(header.extra_field);
p->device->write(header.file_comment);
}
int dir_size = p->device->pos() - p->start_of_directory;
// write end of directory
EndOfDirectory eod;
memset(&eod, 0, sizeof(EndOfDirectory));
writeUInt(eod.signature, 0x06054b50);
//uint8_t this_disk[2];
//uint8_t start_of_directory_disk[2];
writeUShort(eod.num_dir_entries_this_disk, p->fileHeaders.size());
writeUShort(eod.num_dir_entries, p->fileHeaders.size());
writeUInt(eod.directory_size, dir_size);
writeUInt(eod.dir_start_offset, p->start_of_directory);
writeUShort(eod.comment_length, p->comment.size());
p->device->write((const uint8_t*)&eod, sizeof(EndOfDirectory));
p->device->write(p->comment);
p->device->close();
}
}

View file

@ -0,0 +1,87 @@
/*
* SPDX-License-Identifier: GPL-3.0-only
* MuseScore-CLA-applies
*
* MuseScore
* Music Composition & Notation
*
* Copyright (C) 2021 MuseScore BVBA and others
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program 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.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef MU_GLOBAL_ZIPCONTAINER_H
#define MU_GLOBAL_ZIPCONTAINER_H
#include <ctime>
#include <string>
#include "io/iodevice.h"
namespace mu {
class ZipContainer
{
public:
explicit ZipContainer(io::IODevice* device);
~ZipContainer();
enum Status {
NoError,
FileOpenError,
FileReadError,
FileWriteError,
FileError
};
struct FileInfo
{
std::string filePath;
bool isDir = false;
bool isFile = false;
bool isSymLink = false;
uint crc = 0;
int64_t size = 0;
std::tm lastModified;
bool isValid() const { return isDir || isFile || isSymLink; }
};
Status status() const;
void close();
// Read
std::vector<FileInfo> fileInfoList() const;
int count() const;
ByteArray fileData(const std::string& fileName) const;
// Write
enum CompressionPolicy {
AlwaysCompress,
NeverCompress,
AutoCompress
};
void setCompressionPolicy(CompressionPolicy policy);
CompressionPolicy compressionPolicy() const;
void addFile(const std::string& fileName, const ByteArray& data);
void addDirectory(const std::string& dirName);
private:
struct Impl;
Impl* p = nullptr;
};
}
#endif // MU_GLOBAL_ZIPCONTAINER_H

View file

@ -21,9 +21,7 @@
*/
#include "zipreader.h"
#include <QBuffer>
#include "internal/qzipreader_p.h"
#include "internal/zipcontainer.h"
#include "io/file.h"
using namespace mu;
@ -31,40 +29,36 @@ using namespace mu::io;
struct ZipReader::Impl
{
MQZipReader* zip = nullptr;
ByteArray data;
QByteArray ba;
QBuffer buf;
ZipContainer* zip = nullptr;
IODevice* device = nullptr;
bool isSelfDevice = false;
};
ZipReader::ZipReader(const io::path_t& filePath)
: m_filePath(filePath)
{
m_impl = new Impl();
File f(filePath);
if (f.open(IODevice::ReadOnly)) {
m_impl->data = f.readAll();
m_impl->ba = m_impl->data.toQByteArrayNoCopy();
m_impl->device = new File(filePath);
m_impl->isSelfDevice = true;
if (m_impl->device->open(IODevice::ReadOnly)) {
}
m_impl->buf.setBuffer(&m_impl->ba);
m_impl->buf.open(QIODevice::ReadOnly);
m_impl->zip = new MQZipReader(&m_impl->buf);
m_impl->zip = new ZipContainer(m_impl->device);
}
ZipReader::ZipReader(IODevice* device)
{
m_impl = new Impl();
m_impl->data = device->readAll();
m_impl->ba = m_impl->data.toQByteArrayNoCopy();
m_impl->buf.setBuffer(&m_impl->ba);
m_impl->buf.open(QIODevice::ReadOnly);
m_impl->zip = new MQZipReader(&m_impl->buf);
m_impl->device = device;
m_impl->zip = new ZipContainer(m_impl->device);
}
ZipReader::~ZipReader()
{
close();
delete m_impl->zip;
if (m_impl->isSelfDevice) {
delete m_impl->device;
}
delete m_impl;
}
@ -78,17 +72,17 @@ void ZipReader::close()
m_impl->zip->close();
}
ZipReader::Status ZipReader::status() const
bool ZipReader::hasError() const
{
return static_cast<Status>(m_impl->zip->status());
return m_impl->zip->status() != ZipContainer::NoError;
}
std::vector<ZipReader::FileInfo> ZipReader::fileInfoList() const
{
std::vector<FileInfo> ret;
QVector<MQZipReader::FileInfo> qfis = m_impl->zip->fileInfoList();
ret.reserve(qfis.size());
for (const MQZipReader::FileInfo& qfi : qfis) {
std::vector<ZipContainer::FileInfo> fis = m_impl->zip->fileInfoList();
ret.reserve(fis.size());
for (const ZipContainer::FileInfo& qfi : fis) {
FileInfo fi;
fi.filePath = qfi.filePath;
fi.isDir = qfi.isDir;
@ -104,6 +98,5 @@ std::vector<ZipReader::FileInfo> ZipReader::fileInfoList() const
ByteArray ZipReader::fileData(const std::string& fileName) const
{
QByteArray ba = m_impl->zip->fileData(QString::fromStdString(fileName));
return ByteArray(reinterpret_cast<const uint8_t*>(ba.constData()), ba.size());
return m_impl->zip->fileData(fileName);
}

View file

@ -32,14 +32,6 @@ class ZipReader
{
public:
enum Status {
NoError,
FileReadError,
FileOpenError,
FilePermissionsError,
FileError
};
struct FileInfo
{
io::path_t filePath;
@ -57,7 +49,7 @@ public:
bool exists() const;
void close();
Status status() const;
bool hasError() const;
std::vector<FileInfo> fileInfoList() const;
ByteArray fileData(const std::string& fileName) const;

View file

@ -21,10 +21,8 @@
*/
#include "zipwriter.h"
#include <QBuffer>
#include "internal/zipcontainer.h"
#include "io/file.h"
#include "internal/qzipwriter_p.h"
#include "log.h"
@ -32,9 +30,7 @@ using namespace mu;
struct ZipWriter::Impl
{
MQZipWriter* zip = nullptr;
QByteArray data;
QBuffer buf;
ZipContainer* zip = nullptr;
bool isClosed = false;
};
@ -47,18 +43,14 @@ ZipWriter::ZipWriter(const io::path_t& filePath)
}
m_impl = new Impl();
m_impl->buf.setBuffer(&m_impl->data);
m_impl->buf.open(QIODevice::WriteOnly);
m_impl->zip = new MQZipWriter(&m_impl->buf);
m_impl->zip = new ZipContainer(m_device);
}
ZipWriter::ZipWriter(io::IODevice* device)
{
m_device = device;
m_impl = new Impl();
m_impl->buf.setBuffer(&m_impl->data);
m_impl->buf.open(QIODevice::WriteOnly);
m_impl->zip = new MQZipWriter(&m_impl->buf);
m_impl->zip = new ZipContainer(m_device);
}
ZipWriter::~ZipWriter()
@ -75,10 +67,6 @@ ZipWriter::~ZipWriter()
void ZipWriter::flush()
{
if (m_device) {
m_device->seek(0);
m_device->write(m_impl->data);
}
}
void ZipWriter::close()
@ -96,13 +84,13 @@ void ZipWriter::close()
m_impl->isClosed = true;
}
ZipWriter::Status ZipWriter::status() const
bool ZipWriter::hasError() const
{
return static_cast<Status>(m_impl->zip->status());
return m_impl->zip->status() != ZipContainer::NoError;
}
void ZipWriter::addFile(const std::string& fileName, const ByteArray& data)
{
m_impl->zip->addFile(QString::fromStdString(fileName), data.toQByteArrayNoCopy());
m_impl->zip->addFile(fileName, data);
flush();
}

View file

@ -29,20 +29,13 @@ namespace mu {
class ZipWriter
{
public:
enum Status {
NoError,
FileWriteError,
FileOpenError,
FilePermissionsError,
FileError
};
explicit ZipWriter(const io::path_t& filePath);
explicit ZipWriter(io::IODevice* device);
~ZipWriter();
void close();
Status status() const;
bool hasError() const;
void addFile(const std::string& fileName, const ByteArray& data);

View file

@ -25,6 +25,9 @@
#include "io/fileinfo.h"
#include <QFileInfo>
#include <QDir>
using namespace mu::io;
class Global_IO_FileInfoTests : public ::testing::Test
@ -370,3 +373,15 @@ TEST_F(Global_IO_FileInfoTests, IsAbsolute)
EXPECT_TRUE(ret);
}
}
TEST_F(Global_IO_FileInfoTests, DirPath)
{
{
//! GIVE Some file path
path_t filePath = "/path/to/filename.ext1";
//! DO
path_t dirPath = FileInfo(filePath).dir().path();
//! CHECK
EXPECT_EQ(dirPath, "/path/to");
}
}

View file

@ -116,13 +116,21 @@ char Char::toAscii(char16_t c, bool* ok)
bool Char::isLetter(char16_t c)
{
//! TODO
#ifndef GLOBAL_NO_QT_SUPPORT
return QChar::isLetter(c);
#else
return std::isalpha(static_cast<unsigned char>(c));
#endif
}
bool Char::isSpace(char16_t c)
{
//! TODO
#ifndef GLOBAL_NO_QT_SUPPORT
return QChar::isSpace(c);
#else
return std::isspace(static_cast<unsigned char>(c));
#endif
}
bool Char::isDigit(char16_t c)
@ -138,21 +146,33 @@ int Char::digitValue() const
return m_ch - '0';
}
bool Char::isPunct(char16_t c)
bool Char::isPunct(char16_t ch)
{
return QChar::isPunct(c);
#ifndef GLOBAL_NO_QT_SUPPORT
return QChar::isPunct(ch);
#else
return std::ispunct(static_cast<unsigned char>(ch));
#endif
}
char16_t Char::toLower(char16_t ch)
{
//! TODO
#ifndef GLOBAL_NO_QT_SUPPORT
return QChar::toLower(ch);
#else
return std::tolower(static_cast<unsigned char>(ch));
#endif
}
char16_t Char::toUpper(char16_t ch)
{
//! TODO
#ifndef GLOBAL_NO_QT_SUPPORT
return QChar::toUpper(ch);
#else
return std::toupper(static_cast<unsigned char>(ch));
#endif
}
// ============================
@ -419,6 +439,7 @@ std::u32string String::toStdU32String() const
return s32;
}
#ifndef GLOBAL_NO_QT_SUPPORT
String String::fromQString(const QString& str)
{
const QChar* qu = str.unicode();
@ -437,6 +458,8 @@ QString String::toQString() const
return QString(reinterpret_cast<const QChar*>(u), static_cast<int>(size()));
}
#endif
size_t String::size() const
{
return constStr().size();
@ -868,7 +891,11 @@ String String::trimmed() const
String String::simplified() const
{
//! TODO
#ifndef GLOBAL_NO_QT_SUPPORT
return String::fromQString(toQString().simplified());
#else
return *this;
#endif
}
String String::toXmlEscaped(char16_t c)
@ -910,15 +937,29 @@ String String::toXmlEscaped() const
String String::toLower() const
{
//! TODO
#ifndef GLOBAL_NO_QT_SUPPORT
QString qs = toQString();
return String::fromQString(qs.toLower());
#else
String s = *this;
std::u16string& us = s.mutStr();
std::transform(us.begin(), us.end(), us.begin(), [](char16_t c){ return Char::toLower(c); });
return s;
#endif
}
String String::toUpper() const
{
//! TODO
#ifndef GLOBAL_NO_QT_SUPPORT
QString qs = toQString();
return String::fromQString(qs.toUpper());
#else
String s = *this;
std::u16string& us = s.mutStr();
std::transform(us.begin(), us.end(), us.begin(), [](char16_t c){ return Char::toUpper(c); });
return s;
#endif
}
int String::toInt(bool* ok, int base) const
@ -989,15 +1030,6 @@ double String::toDouble(bool* ok) const
// ============================
// StringList
// ============================
StringList::StringList(const QStringList& l)
{
reserve(l.size());
for (const QString& s : l) {
push_back(String::fromQString(s));
}
}
StringList& StringList::append(const StringList& l)
{
for (const String& s : l) {
@ -1051,6 +1083,15 @@ void StringList::removeAt(size_t i)
erase(begin() + i);
}
#ifndef GLOBAL_NO_QT_SUPPORT
StringList::StringList(const QStringList& l)
{
reserve(l.size());
for (const QString& s : l) {
push_back(String::fromQString(s));
}
}
QStringList StringList::toQStringList() const
{
QStringList l;
@ -1061,6 +1102,7 @@ QStringList StringList::toQStringList() const
return l;
}
#endif
// ============================
// AsciiChar
// ============================

View file

@ -275,7 +275,6 @@ void GPConverter::fixPercussion()
void GPConverter::setupTabDisplayStyle()
{
GPDomModel::GPProperties properties = _gpDom->properties();
using parts_import_t = GPDomModel::TabImportOption;
std::vector<GPDomModel::TabImportOption>& partsImportOpts = properties.partsImportOptions;
bool importLinkedStaffForce = properties.createLinkedTabForce;

View file

@ -45,8 +45,8 @@ void StaffSettingsModel::load(const QString& staffId)
m_type = staff->staffType()->type();
m_voicesVisibility.clear();
for (const QVariant& voice: staff->visibilityVoices()) {
m_voicesVisibility << voice.toBool();
for (const bool& voice : staff->visibilityVoices()) {
m_voicesVisibility << voice;
}
emit cutawayEnabledChanged();

View file

@ -445,7 +445,7 @@ bool Palette::writeToFile(const QString& p) const
}
ZipWriter f(path);
if (f.status() != ZipWriter::NoError) {
if (f.hasError()) {
showWritingPaletteError(path);
return false;
}
@ -486,7 +486,7 @@ bool Palette::writeToFile(const QString& p) const
f.addFile("palette.xml", cbuf1.data());
}
f.close();
if (f.status() != ZipWriter::NoError) {
if (f.hasError()) {
showWritingPaletteError(path);
return false;
}

View file

@ -152,14 +152,14 @@ MasterPalette::MasterPalette(QWidget* parent)
m_symbolItem->addChild(child);
std::vector<String> symbols = mu::keys(mu::smuflRanges());
for (int i = 0; i < symbols.size(); i++) {
for (size_t i = 0; i < symbols.size(); i++) {
QString symbol = symbols[i].toQString();
if (symbol == mu::SMUFL_ALL_SYMBOLS) {
continue;
}
QTreeWidgetItem* chld = new QTreeWidgetItem(QStringList(symbol));
chld->setData(0, Qt::UserRole, m_idxAllSymbols + i + 1);
chld->setData(0, Qt::UserRole, m_idxAllSymbols + static_cast<int>(i) + 1);
m_symbolItem->addChild(chld);
}