diff options
| author | trialuser02 <trialuser02@90c681e8-e032-0410-971d-27865f9a5e38> | 2016-09-16 08:13:14 +0000 |
|---|---|---|
| committer | trialuser02 <trialuser02@90c681e8-e032-0410-971d-27865f9a5e38> | 2016-09-16 08:13:14 +0000 |
| commit | 2d0439faf537a922c88f8b3436b2d91eb9f70503 (patch) | |
| tree | 6aeddb430e4dc4ec5d89089e61fea583d903119d | |
| parent | 4b06a19515626c220cef3c4e48db67069303a241 (diff) | |
| download | qmmp-2d0439faf537a922c88f8b3436b2d91eb9f70503.tar.gz qmmp-2d0439faf537a922c88f8b3436b2d91eb9f70503.tar.bz2 qmmp-2d0439faf537a922c88f8b3436b2d91eb9f70503.zip | |
added archive reader (first test implementation)
git-svn-id: http://svn.code.sf.net/p/qmmp-dev/code/trunk/qmmp@6727 90c681e8-e032-0410-971d-27865f9a5e38
| -rw-r--r-- | src/plugins/Input/archive/archive.pro | 43 | ||||
| -rw-r--r-- | src/plugins/Input/archive/archiveinputdevice.cpp | 52 | ||||
| -rw-r--r-- | src/plugins/Input/archive/archiveinputdevice.h | 29 | ||||
| -rw-r--r-- | src/plugins/Input/archive/decoder_archive.cpp | 159 | ||||
| -rw-r--r-- | src/plugins/Input/archive/decoder_archive.h | 30 | ||||
| -rw-r--r-- | src/plugins/Input/archive/decoderarchivefactory.cpp | 120 | ||||
| -rw-r--r-- | src/plugins/Input/archive/decoderarchivefactory.h | 50 |
7 files changed, 483 insertions, 0 deletions
diff --git a/src/plugins/Input/archive/archive.pro b/src/plugins/Input/archive/archive.pro new file mode 100644 index 000000000..8cd6b7548 --- /dev/null +++ b/src/plugins/Input/archive/archive.pro @@ -0,0 +1,43 @@ +include(../../plugins.pri) + +HEADERS += \ + archiveinputdevice.h \ + decoderarchivefactory.h \ + decoder_archive.h + +SOURCES += \ + archiveinputdevice.cpp \ + decoderarchivefactory.cpp \ + decoder_archive.cpp + +TARGET=$$PLUGINS_PREFIX/Input/archive + + +INCLUDEPATH += ../../../ +CONFIG += warn_on \ +plugin \ +link_pkgconfig + +TEMPLATE = lib + +QMAKE_LIBDIR += ../../../../lib + +#RESOURCES = translations/translations.qrc + +unix { + isEmpty(LIB_DIR):LIB_DIR = /lib + target.path = $$LIB_DIR/qmmp/Input + INSTALLS += target + + QMAKE_LIBDIR += ../../../../lib + LIBS += -lqmmp + PKGCONFIG += libarchive + QMAKE_CLEAN =$$PLUGINS_PREFIX/Input/libarc.so +} + +win32 { +# HEADERS += ../../../../src/qmmp/metadatamodel.h \ +# ../../../../src/qmmp/decoderfactory.h + QMAKE_LIBDIR += ../../../../bin + LIBS += -lqmmp0 -larchive +} diff --git a/src/plugins/Input/archive/archiveinputdevice.cpp b/src/plugins/Input/archive/archiveinputdevice.cpp new file mode 100644 index 000000000..d9017ccda --- /dev/null +++ b/src/plugins/Input/archive/archiveinputdevice.cpp @@ -0,0 +1,52 @@ +#include "archiveinputdevice.h" + +ArchiveInputDevice::ArchiveInputDevice(archive *a, archive_entry *e, QObject *parent) : QIODevice(parent) +{ + m_archive = a; + m_entry = e; + open(QIODevice::ReadOnly); + m_buffer.open(QBuffer::ReadWrite); +} + +bool ArchiveInputDevice::seek(qint64 pos) +{ + QIODevice::seek(pos); + + if(pos > m_buffer.size()) + { + char tmp[1024]; + qint64 delta = pos - m_buffer.size(); + while (delta > 0) + { + qint64 r = qMin(qint64(sizeof(tmp)), delta); + r = archive_read_data(m_archive, tmp, r); + m_buffer.buffer().append(tmp, r); + delta -= r; + } + + } + + m_buffer.seek(pos); + return true; +} + +qint64 ArchiveInputDevice::size() const +{ + return archive_entry_size(m_entry); +} + +qint64 ArchiveInputDevice::readData(char *data, qint64 maxSize) +{ + if(m_buffer.atEnd()) + { + char tmp[maxSize]; + int r = archive_read_data(m_archive, tmp, maxSize); + m_buffer.buffer().append(tmp, r); + } + return m_buffer.read(data, maxSize); +} + +qint64 ArchiveInputDevice::writeData(const char *, qint64) +{ + return -1; +} diff --git a/src/plugins/Input/archive/archiveinputdevice.h b/src/plugins/Input/archive/archiveinputdevice.h new file mode 100644 index 000000000..7e7dd56f7 --- /dev/null +++ b/src/plugins/Input/archive/archiveinputdevice.h @@ -0,0 +1,29 @@ +#ifndef ARCHIVEINPUTDEVICE_H +#define ARCHIVEINPUTDEVICE_H + +#include <QIODevice> +#include <QBuffer> +#include <archive.h> +#include <archive_entry.h> + +class ArchiveInputDevice : public QIODevice +{ + Q_OBJECT +public: + ArchiveInputDevice(struct archive *a, struct archive_entry *e, QObject *parent); + + bool seek(qint64 pos); + qint64 size() const; + +protected: + virtual qint64 readData(char *data, qint64 maxSize); + virtual qint64 writeData(const char *, qint64); + +private: + struct archive *m_archive; + struct archive_entry *m_entry; + QBuffer m_buffer; + +}; + +#endif // ARCHIVEINPUTDEVICE_H diff --git a/src/plugins/Input/archive/decoder_archive.cpp b/src/plugins/Input/archive/decoder_archive.cpp new file mode 100644 index 000000000..89f93cf9a --- /dev/null +++ b/src/plugins/Input/archive/decoder_archive.cpp @@ -0,0 +1,159 @@ +#include <QFile> +#include <archive_entry.h> +#include "archiveinputdevice.h" +#include "decoder_archive.h" + +DecoderArchive::DecoderArchive(const QString &url) +{ + m_url = url; + m_archive = 0; + m_decoder = 0; + m_input = 0; +} + +DecoderArchive::~DecoderArchive() +{ + if(m_decoder) + { + delete m_decoder; + m_decoder = 0; + } + if(m_input) + { + delete m_input; + m_input = 0; + } + if(m_archive) + { + archive_read_close(m_archive); + archive_read_free(m_archive); + m_archive = 0; + } +} + +bool DecoderArchive::initialize() +{ + QString filePath = m_url.section("#", -1); + QString archivePath = m_url; + archivePath.remove(QRegExp("^.+://")); + archivePath.remove(QRegExp("#.+$")); + + if(!QFile::exists(archivePath)) + { + qWarning("DecoderArc: file '%s' not found", qPrintable(archivePath)); + return false; + } + + QList<DecoderFactory*> filtered; + foreach (DecoderFactory *fact, Decoder::enabledFactories()) + { + if(fact->properties().noInput) + continue; + + foreach(QString filter, fact->properties().filters) + { + QRegExp regexp(filter, Qt::CaseInsensitive, QRegExp::Wildcard); + if (regexp.exactMatch(filePath)) + { + filtered.append(fact); + break; + } + } + } + + if(filtered.isEmpty()) + { + qWarning("DecoderArc: unable to find decoder"); + return false; + } + + m_archive = archive_read_new(); + archive_read_support_filter_all(m_archive); + archive_read_support_format_all(m_archive); + + int r = archive_read_open_filename(m_archive, archivePath.toLocal8Bit().constData(), 10240); + if (r != ARCHIVE_OK) + { + qWarning("DecoderArc: unable to open file '%s', error code: %d", qPrintable(archivePath), r); + return false; + } + + struct archive_entry *entry = 0; + + while (archive_read_next_header(m_archive, &entry) == ARCHIVE_OK) + { + QString pathName = QString::fromLocal8Bit(archive_entry_pathname(entry)); + if(!pathName.startsWith("/")) + pathName.prepend("/"); + + if(archive_entry_filetype(entry) == AE_IFREG && filePath == pathName) + { + m_input = new ArchiveInputDevice(m_archive, entry, 0); + break; + } + archive_read_data_skip(m_archive); + } + + if(!m_input) + { + qWarning("DecoderArc: unable to find file '%s' inside archive '%s'", qPrintable(filePath), + qPrintable(archivePath)); + return false; + } + + DecoderFactory *factory = 0; + if(filtered.size() == 1) + factory = filtered.first(); + else + { + //several factories, so trying to determine by content + foreach (DecoderFactory *fact, filtered) + { + if(fact->canDecode(m_input)) + { + factory = fact; + break; + } + } + } + + if(!factory) + { + qWarning("DecoderArc: unable to find supported decoder factory"); + return false; + } + + qDebug("DecoderArc: selected decoder: %s", qPrintable(factory->properties().shortName)); + qDebug("+"); + m_decoder = factory->create(m_url, m_input); + qDebug("+1"); + if(!m_decoder->initialize()) + { + qWarning("DecoderArc: unable to initialize decoder"); + return false; + } + qDebug("+2"); + configure(m_decoder->audioParameters().sampleRate(), m_decoder->audioParameters().channelMap(), + m_decoder->audioParameters().format()); + return true; +} + +qint64 DecoderArchive::totalTime() const +{ + return m_decoder->totalTime(); +} + +void DecoderArchive::seek(qint64 time) +{ + m_decoder->seek(time); +} + +qint64 DecoderArchive::read(unsigned char *data, qint64 maxSize) +{ + return m_decoder->read(data, maxSize); +} + +int DecoderArchive::bitrate() const +{ + return m_decoder->bitrate(); +} diff --git a/src/plugins/Input/archive/decoder_archive.h b/src/plugins/Input/archive/decoder_archive.h new file mode 100644 index 000000000..df88acf15 --- /dev/null +++ b/src/plugins/Input/archive/decoder_archive.h @@ -0,0 +1,30 @@ +#ifndef DECODERARCHIVE_H +#define DECODERARCHIVE_H + +#include <QString> +#include <archive.h> +#include <qmmp/decoder.h> + + +class DecoderArchive : public Decoder +{ +public: + DecoderArchive(const QString &url); + + virtual ~DecoderArchive(); + + bool initialize(); + qint64 totalTime() const; + void seek(qint64 time); + qint64 read(unsigned char *data, qint64 maxSize); + int bitrate() const; + +private: + QString m_url; + struct archive *m_archive; + Decoder *m_decoder; + QIODevice *m_input; + +}; + +#endif // DECODERARCHIVE_H diff --git a/src/plugins/Input/archive/decoderarchivefactory.cpp b/src/plugins/Input/archive/decoderarchivefactory.cpp new file mode 100644 index 000000000..9765664a5 --- /dev/null +++ b/src/plugins/Input/archive/decoderarchivefactory.cpp @@ -0,0 +1,120 @@ +/*************************************************************************** + * Copyright (C) 2016 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ +#include <QRegExp> +#include <QMessageBox> +#include <QTranslator> +#include <QtPlugin> +#include <archive.h> +#include <archive_entry.h> +#include "decoder_archive.h" +#include "decoderarchivefactory.h" + +// DecoderSndFileFactory +bool DecoderArchiveFactory::canDecode(QIODevice *input) const +{ + return false; +} + +const DecoderProperties DecoderArchiveFactory::properties() const +{ + DecoderProperties properties; + properties.name = tr("Archive Plugin"); + properties.filters << "*.rar" << "*.zip"; + properties.description = tr("Archives"); + //properties.contentType = ""; + properties.shortName = "archive"; + properties.hasAbout = false; + properties.hasSettings = false; + properties.noInput = true; + properties.protocols << "rar" << "zip"; + return properties; +} + +Decoder *DecoderArchiveFactory::create(const QString &url, QIODevice *) +{ + return new DecoderArchive(url); +} + +QList<FileInfo *> DecoderArchiveFactory::createPlayList(const QString &fileName, bool useMetaData, QStringList *) +{ + QList <FileInfo *> list; + + + struct archive *a; + struct archive_entry *entry; + int r; + + a = archive_read_new(); + archive_read_support_filter_all(a); + archive_read_support_format_all(a); + r = archive_read_open_filename(a, fileName.toLocal8Bit().constData(), 10240); + if (r != ARCHIVE_OK) + { + //exit(1); + return list; + } + while (archive_read_next_header(a, &entry) == ARCHIVE_OK) + { + if(archive_entry_filetype(entry) == AE_IFREG) + { + QString pathName = QString::fromLocal8Bit(archive_entry_pathname(entry)); + if(!pathName.startsWith("/")) + pathName.prepend("/"); + + list << new FileInfo(QString("%1://%2#%3") + .arg(fileName.section(".", -1)).toLower() + .arg(fileName) + .arg(pathName)); + //TODO read tags + } + archive_read_data_skip(a); + } + r = archive_read_free(a); + + return list; +} + +MetaDataModel* DecoderArchiveFactory::createMetaDataModel(const QString&, QObject *) +{ + return 0; +} + +void DecoderArchiveFactory::showSettings(QWidget *) +{} + +void DecoderArchiveFactory::showAbout(QWidget *parent) +{ + /*char version [128] ; + sf_command (NULL, SFC_GET_LIB_VERSION, version, sizeof (version)) ; + QMessageBox::about (parent, tr("About Sndfile Audio Plugin"), + tr("Qmmp Sndfile Audio Plugin")+"\n"+ + tr("Compiled against")+" "+QString(version)+"\n" + + tr("Written by: Ilya Kotov <forkotov02@hotmail.ru>"));*/ +} + +QTranslator *DecoderArchiveFactory::createTranslator(QObject *parent) +{ + QTranslator *translator = new QTranslator(parent); + QString locale = Qmmp::systemLanguageID(); + translator->load(QString(":/archive_plugin_") + locale); + return translator; +} + +Q_EXPORT_PLUGIN2(archive, DecoderArchiveFactory) diff --git a/src/plugins/Input/archive/decoderarchivefactory.h b/src/plugins/Input/archive/decoderarchivefactory.h new file mode 100644 index 000000000..bf4a20829 --- /dev/null +++ b/src/plugins/Input/archive/decoderarchivefactory.h @@ -0,0 +1,50 @@ +/*************************************************************************** + * Copyright (C) 2016 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ +#ifndef DECODERARCHIVEFACTORY_H +#define DECODERARCHIVEFACTORY_H + +#include <QObject> +#include <QString> +#include <QIODevice> +#include <QWidget> + +#include <qmmp/decoder.h> +#include <qmmp/output.h> +#include <qmmp/decoderfactory.h> +#include <qmmp/fileinfo.h> + +class DecoderArchiveFactory : public QObject, + DecoderFactory +{ +Q_OBJECT +Q_INTERFACES(DecoderFactory) + +public: + bool canDecode(QIODevice *input) const; + const DecoderProperties properties() const; + Decoder *create(const QString &url, QIODevice *); + QList<FileInfo *> createPlayList(const QString &fileName, bool useMetaData, QStringList *); + MetaDataModel* createMetaDataModel(const QString &path, QObject *parent = 0); + void showSettings(QWidget *parent); + void showAbout(QWidget *parent); + QTranslator *createTranslator(QObject *parent); +}; + +#endif |
