promoe/dir_iterator/archive_read_open_qiodevice.cpp
Thomas Frauendorfer 2aabed9491 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
2010-03-12 19:59:19 +01:00

148 lines
4.3 KiB
C++

/*-
* 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;
}