OTHER: read support for zipped skins
For now, zipped skins don't show up in the selection dialog yet But they are loaded when set in the config file
This commit is contained in:
parent
ff721650c0
commit
2aabed9491
8 changed files with 497 additions and 7 deletions
148
dir_iterator/archive_read_open_qiodevice.cpp
Normal file
148
dir_iterator/archive_read_open_qiodevice.cpp
Normal file
|
@ -0,0 +1,148 @@
|
|||
/*-
|
||||
* Copyright (C) 2010 Thomas Frauendorfer
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
// On Debian, libarchive is compiled with 64bit off_t, but nothing in the
|
||||
// libarchive headers tells so. In other words: Debian sucks.
|
||||
#define _LARGEFILE_SOURCE 1
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
|
||||
#include <archive.h>
|
||||
#include <QIODevice>
|
||||
|
||||
#include <QtDebug>
|
||||
|
||||
#if (ARCHIVE_API_VERSION < 2)
|
||||
typedef __LA_SSIZE_T archive_skip_t;
|
||||
#elif (ARCHIVE_API_VERSION < 3)
|
||||
typedef off_t archive_skip_t;
|
||||
#else
|
||||
typedef __LA_INT64_T archive_skip_t;
|
||||
#endif
|
||||
|
||||
static const int READ_MAX = 4096;
|
||||
|
||||
struct read_qiodevice_data {
|
||||
QIODevice *device;
|
||||
char buffer[READ_MAX];
|
||||
};
|
||||
|
||||
static int qiodevice_read_close(struct archive *, void *);
|
||||
static archive_skip_t qiodevice_read_skip(struct archive *, void *, archive_skip_t);
|
||||
static __LA_SSIZE_T qiodevice_read(struct archive *, void *, const void **);
|
||||
|
||||
int
|
||||
archive_read_open_qiodevice(struct archive *a, QIODevice *device)
|
||||
{
|
||||
if (device == 0) {
|
||||
qDebug () << "archive_read_open_qiodevice";
|
||||
archive_set_error(a, -1, "Invalid QIODevice");
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
|
||||
if (!device->isOpen() && !device->open(QIODevice::ReadOnly)) {
|
||||
qDebug () << "archive_read_open_qiodevice";
|
||||
archive_set_error(a, -1, "Could not open QIODevice for reading");
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
|
||||
if (!device->isReadable()) {
|
||||
qDebug () << "archive_read_open_qiodevice";
|
||||
archive_set_error(a, -1, "Could not open QIODevice for reading");
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
|
||||
struct read_qiodevice_data *data = new read_qiodevice_data;
|
||||
if (data == 0) {
|
||||
qDebug () << "archive_read_open_qiodevice";
|
||||
archive_set_error(a, -1, "No Memory");
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
data->device = device;
|
||||
|
||||
device->reset(); // Seek to begining of file
|
||||
device->setTextModeEnabled(false); // Binary mode
|
||||
|
||||
return (archive_read_open2(a, data, NULL, qiodevice_read,
|
||||
qiodevice_read_skip, qiodevice_read_close));
|
||||
}
|
||||
|
||||
static int
|
||||
qiodevice_read_close(struct archive *a, void *v)
|
||||
{
|
||||
const struct read_qiodevice_data *data = static_cast<read_qiodevice_data *>(v);
|
||||
|
||||
(void)a;
|
||||
if (data != 0) {
|
||||
delete data;
|
||||
}
|
||||
|
||||
return ARCHIVE_OK;
|
||||
}
|
||||
|
||||
static archive_skip_t
|
||||
qiodevice_read_skip(struct archive *a, void *v, archive_skip_t _request)
|
||||
{
|
||||
const struct read_qiodevice_data *data = static_cast<read_qiodevice_data *>(v);
|
||||
|
||||
(void)a; /* unused */
|
||||
const qint64 request = _request; // make sure we work with 64bit values
|
||||
|
||||
|
||||
if (data->device->isSequential()) {
|
||||
return 0;
|
||||
}
|
||||
if (request == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const qint64 oldpos = data->device->pos();
|
||||
if (data->device->seek(oldpos + request)) {
|
||||
return request;
|
||||
}
|
||||
|
||||
// Seek might have failed because we tried to seek beyond the end of a file
|
||||
qDebug("Seek failed, seeked: %lli", data->device->pos() - oldpos);
|
||||
|
||||
return data->device->pos() - oldpos;
|
||||
}
|
||||
|
||||
static __LA_SSIZE_T
|
||||
qiodevice_read(struct archive *a, void *v, const void **buf)
|
||||
{
|
||||
struct read_qiodevice_data *data = static_cast<read_qiodevice_data *>(v);
|
||||
|
||||
(void)a;
|
||||
|
||||
*buf = data->buffer;
|
||||
qint64 bytes_read = data->device->read(data->buffer, READ_MAX);
|
||||
|
||||
if (bytes_read < 0) {
|
||||
archive_set_error(a, 1, "Error reading from QIODevice");
|
||||
}
|
||||
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
|
167
dir_iterator/archiveiterator.cpp
Normal file
167
dir_iterator/archiveiterator.cpp
Normal file
|
@ -0,0 +1,167 @@
|
|||
/**
|
||||
* This file is a part of Promoe, an XMMS2 Client.
|
||||
*
|
||||
* Copyright (C) 2010 XMMS2 Team
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "archiveiterator.h"
|
||||
#include "archivereaddevice.h"
|
||||
|
||||
#include "promoe_config.h"
|
||||
#if HAVE_LIBARCHIVE
|
||||
#include "archive.h"
|
||||
#include "archive_entry.h"
|
||||
#endif
|
||||
|
||||
#include <QtDebug>
|
||||
|
||||
int archive_read_open_qiodevice(struct archive *a, QIODevice *device);
|
||||
|
||||
ArchiveIterator::ArchiveIterator (const QString &path) : QObject (),
|
||||
DirIteratorBase (), m_current(NULL)
|
||||
{
|
||||
m_dev = new QFile (path);
|
||||
m_valid = finish_init (m_dev);
|
||||
}
|
||||
|
||||
ArchiveIterator::ArchiveIterator (QIODevice *d) : QObject (),
|
||||
DirIteratorBase (), m_current(NULL), m_dev (NULL)
|
||||
{
|
||||
m_valid = finish_init (d);
|
||||
}
|
||||
|
||||
bool
|
||||
ArchiveIterator::finish_init (QIODevice *d)
|
||||
{
|
||||
m_archive_entry = NULL;
|
||||
m_archive = NULL;
|
||||
m_atEnd = false;
|
||||
|
||||
#if HAVE_LIBARCHIVE
|
||||
m_archive = archive_read_new ();
|
||||
if (m_archive == 0) {
|
||||
qDebug () << "archive_read_new failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (archive_read_support_compression_all (m_archive) != ARCHIVE_OK) {
|
||||
qDebug () << "archive_read_support_compression_all failed";
|
||||
return false;
|
||||
}
|
||||
if (archive_read_support_format_all (m_archive) != ARCHIVE_OK) {
|
||||
qDebug () << "archive_read_support_format_all failed";
|
||||
return false;
|
||||
}
|
||||
if (archive_read_open_qiodevice (m_archive, d) != ARCHIVE_OK) {
|
||||
qDebug () << "archive_read_open_qiodevice failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
ArchiveIterator::~ArchiveIterator ()
|
||||
{
|
||||
#if HAVE_LIBARCHIVE
|
||||
if (m_archive != 0) {
|
||||
archive_read_finish (m_archive);
|
||||
m_archive = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (m_dev != 0) {
|
||||
delete m_dev;
|
||||
m_dev = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* DirIteratorBase methods
|
||||
*/
|
||||
|
||||
QString
|
||||
ArchiveIterator::next ()
|
||||
{
|
||||
#if HAVE_LIBARCHIVE
|
||||
if (!m_valid || m_atEnd) {
|
||||
return QString ();
|
||||
}
|
||||
if (m_current != 0) {
|
||||
m_current->close ();
|
||||
m_current->deleteLater ();
|
||||
}
|
||||
if (archive_read_next_header (m_archive, &m_archive_entry) != ARCHIVE_OK) {
|
||||
m_atEnd = true;
|
||||
return QString ();
|
||||
}
|
||||
QString s(archive_entry_pathname (m_archive_entry));
|
||||
m_current = new ArchiveReadDevice (this, s);
|
||||
return s;
|
||||
#else
|
||||
return QString ();
|
||||
#endif
|
||||
}
|
||||
|
||||
QString
|
||||
ArchiveIterator::pathName ()
|
||||
{
|
||||
#if HAVE_LIBARCHIVE
|
||||
if (!m_valid || m_atEnd) {
|
||||
return QString ();
|
||||
}
|
||||
QString s(archive_entry_pathname (m_archive_entry));
|
||||
return s;
|
||||
#else
|
||||
return QString ();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
ArchiveIterator::hasNext ()
|
||||
{
|
||||
#if HAVE_LIBARCHIVE
|
||||
return !m_atEnd; // workaround, as there is no has_next method in libarchive
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
QPointer<QIODevice>
|
||||
ArchiveIterator::entry ()
|
||||
{
|
||||
#if HAVE_LIBARCHIVE
|
||||
return m_current;
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
qint64
|
||||
ArchiveIterator::readData(char *data, qint64 size)
|
||||
{
|
||||
#if HAVE_LIBARCHIVE
|
||||
if (!m_valid || m_atEnd) {
|
||||
qDebug () << "gnarf";
|
||||
return -1;
|
||||
}
|
||||
qint64 ret = archive_read_data (m_archive, data, size);
|
||||
return ret;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
#include "archiveiterator.moc"
|
57
dir_iterator/archiveiterator.h
Normal file
57
dir_iterator/archiveiterator.h
Normal file
|
@ -0,0 +1,57 @@
|
|||
/**
|
||||
* This file is a part of Promoe, an XMMS2 Client.
|
||||
*
|
||||
* Copyright (C) 2010 XMMS2 Team
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef __ARCHIVEITERATOR_H__
|
||||
#define __ARCHIVEITERATOR_H__
|
||||
|
||||
#include <QIODevice>
|
||||
|
||||
#include "diriteratorbase.h"
|
||||
|
||||
struct archive;
|
||||
struct archive_entry;
|
||||
|
||||
class ArchiveIterator : public QObject, public DirIteratorBase
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ArchiveIterator (const QString &path);
|
||||
ArchiveIterator (QIODevice *);
|
||||
~ArchiveIterator ();
|
||||
|
||||
// DirIteratorBase Methods
|
||||
QString next ();
|
||||
QString pathName ();
|
||||
bool hasNext ();
|
||||
QPointer<QIODevice> entry ();
|
||||
|
||||
// QIODevice Methods
|
||||
qint64 readData(char*, qint64);
|
||||
|
||||
protected:
|
||||
bool m_valid;
|
||||
bool m_atEnd;
|
||||
|
||||
struct archive *m_archive;
|
||||
struct archive_entry *m_archive_entry;
|
||||
|
||||
QIODevice *m_dev;
|
||||
QPointer<QIODevice> m_current;
|
||||
bool finish_init (QIODevice *);
|
||||
};
|
||||
|
||||
#endif
|
45
dir_iterator/archivereaddevice.cpp
Normal file
45
dir_iterator/archivereaddevice.cpp
Normal file
|
@ -0,0 +1,45 @@
|
|||
/**
|
||||
* This file is a part of Promoe, an XMMS2 Client.
|
||||
*
|
||||
* Copyright (C) 2010 XMMS2 Team
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
|
||||
#include "archivereaddevice.h"
|
||||
|
||||
#include "promoe_config.h"
|
||||
|
||||
#include <QtDebug>
|
||||
|
||||
ArchiveReadDevice::ArchiveReadDevice (ArchiveIterator *parent,
|
||||
const QString &name)
|
||||
: QIODevice (parent), m_iter(parent), m_atEnd(false)
|
||||
{
|
||||
setObjectName (name);
|
||||
setOpenMode (QIODevice::ReadOnly);
|
||||
}
|
||||
|
||||
qint64
|
||||
ArchiveReadDevice::readData (char* buf, qint64 size)
|
||||
{
|
||||
if (!isOpen ()) {
|
||||
return -1;
|
||||
}
|
||||
qint64 ret = m_iter->readData (buf, size);
|
||||
if (ret <= 0) {
|
||||
m_atEnd = true;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#include "archivereaddevice.moc"
|
47
dir_iterator/archivereaddevice.h
Normal file
47
dir_iterator/archivereaddevice.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
/**
|
||||
* This file is a part of Promoe, an XMMS2 Client.
|
||||
*
|
||||
* Copyright (C) 2010 XMMS2 Team
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef __ARCHIVEREADDEVICE_H__
|
||||
#define __ARCHIVEREADDEVICE_H__
|
||||
|
||||
#include <QIODevice>
|
||||
|
||||
#include "archiveiterator.h"
|
||||
|
||||
struct archive;
|
||||
struct archive_entry;
|
||||
|
||||
class ArchiveReadDevice : public QIODevice
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ArchiveReadDevice (ArchiveIterator *parent, const QString &name = QString ());
|
||||
~ArchiveReadDevice () {};
|
||||
|
||||
// QIODevice Methods
|
||||
qint64 readData(char*, qint64);
|
||||
qint64 writeData(const char*, qint64) { return -1; } // read only
|
||||
|
||||
bool atEnd () const { return m_atEnd; }
|
||||
|
||||
protected:
|
||||
ArchiveIterator *m_iter;
|
||||
|
||||
bool m_atEnd;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -16,8 +16,9 @@
|
|||
|
||||
#include "diriteratorbase.h"
|
||||
#include "diriterator.h"
|
||||
#include "archiveiterator.h"
|
||||
#include <QDataStream>
|
||||
#include "QFile"
|
||||
#include "QFileInfo"
|
||||
|
||||
|
||||
#include <QDebug>
|
||||
|
@ -35,17 +36,32 @@ DirIteratorBase::pixmapEntry ()
|
|||
QPixmap p;
|
||||
p.loadFromData(a);
|
||||
|
||||
if (p.isNull ()) {
|
||||
qDebug () << "Size:" << a.size ();
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
DirIteratorBase *
|
||||
DirIteratorBase::open(const QString &path)
|
||||
{
|
||||
QDir dir(path);
|
||||
if (!dir.exists ()) {
|
||||
QFileInfo info(path);
|
||||
if (!info.exists ()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return new DirIterator (dir);
|
||||
if (info.isDir ()) {
|
||||
return new DirIterator (path);
|
||||
}
|
||||
|
||||
if (info.isFile ()) {
|
||||
ArchiveIterator *iter = new ArchiveIterator (path);
|
||||
if (iter && !iter->hasNext ()) {
|
||||
delete iter;
|
||||
return 0;
|
||||
}
|
||||
return iter;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -36,20 +36,25 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
lib_source = """
|
||||
diriteratorbase.cpp
|
||||
diriterator.cpp
|
||||
archiveiterator.cpp
|
||||
archivereaddevice.cpp
|
||||
archive_read_open_qiodevice.cpp
|
||||
"""
|
||||
|
||||
|
||||
def set_options(opt):
|
||||
pass
|
||||
def configure(conf):
|
||||
conf.check_cfg(package='libarchive', args="--cflags --libs")
|
||||
pass
|
||||
|
||||
def build(bld):
|
||||
obj = bld.new_task_gen(features='qt4 cstaticlib cxx')
|
||||
obj.target = 'dir_iterator'
|
||||
obj.install_path = 0 # Don't install
|
||||
obj.includes = '.'
|
||||
obj.source = lib_source
|
||||
obj.uselib = 'QTCORE QTGUI'
|
||||
obj.uselib = 'QTCORE QTGUI LIBARCHIVE'
|
||||
obj.export_incdirs = '.'
|
||||
pass
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <QDir>
|
||||
#include <QPainter>
|
||||
#include <QSettings>
|
||||
#include <QFileInfo>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
|
@ -700,8 +701,12 @@ Skin::setSkin (const QString& path)
|
|||
QPixmap p_numbers;
|
||||
QPixmap p_volume;
|
||||
|
||||
while (iter->hasNext ()) {
|
||||
QString entry = iter->next ().toLower ();
|
||||
QString entry;
|
||||
while (!(entry = iter->next ().toLower ()).isEmpty ()) {
|
||||
if ((entry = QFileInfo (entry).fileName ()).isEmpty ()) {
|
||||
// workaround to ignore pathes in archives
|
||||
continue;
|
||||
}
|
||||
if (entry.endsWith (".txt")) {
|
||||
QPointer<QIODevice> d = iter->entry ();
|
||||
if (d == 0)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue