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:
Thomas Frauendorfer 2010-02-09 22:52:04 +01:00
parent ff721650c0
commit 2aabed9491
8 changed files with 497 additions and 7 deletions

View 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;
}

View 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"

View 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

View 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"

View 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

View file

@ -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;
}
}

View file

@ -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

View file

@ -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)