aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortrialuser02 <trialuser02@90c681e8-e032-0410-971d-27865f9a5e38>2016-09-16 08:13:14 +0000
committertrialuser02 <trialuser02@90c681e8-e032-0410-971d-27865f9a5e38>2016-09-16 08:13:14 +0000
commit2d0439faf537a922c88f8b3436b2d91eb9f70503 (patch)
tree6aeddb430e4dc4ec5d89089e61fea583d903119d
parent4b06a19515626c220cef3c4e48db67069303a241 (diff)
downloadqmmp-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.pro43
-rw-r--r--src/plugins/Input/archive/archiveinputdevice.cpp52
-rw-r--r--src/plugins/Input/archive/archiveinputdevice.h29
-rw-r--r--src/plugins/Input/archive/decoder_archive.cpp159
-rw-r--r--src/plugins/Input/archive/decoder_archive.h30
-rw-r--r--src/plugins/Input/archive/decoderarchivefactory.cpp120
-rw-r--r--src/plugins/Input/archive/decoderarchivefactory.h50
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