Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c003519bb8 | ||
|
|
3833391447 | ||
|
|
155b0f8db2 | ||
|
|
bcc60797c6 | ||
|
|
28b670c2dc | ||
|
|
5392cc4109 | ||
|
|
7b2d1d95d3 | ||
|
|
f329b7239a | ||
|
|
3e3c73ee90 | ||
|
|
10b2aa0c5d | ||
|
|
5bfd04b9f3 | ||
|
|
f4159e06f6 | ||
|
|
99868323d7 | ||
|
|
0af0af2415 | ||
|
|
fcbe2c997b | ||
|
|
d7748d9227 | ||
|
|
0b8e1f89d7 | ||
|
|
388fce358a | ||
|
|
ad2b567216 | ||
|
|
210601ffe4 | ||
|
|
e337b7933b | ||
|
|
fccbd6790c | ||
|
|
e5ab9908fa |
2
3rdparty/qocoa/main.cpp
vendored
2
3rdparty/qocoa/main.cpp
vendored
@@ -1,4 +1,4 @@
|
|||||||
#include <QtGui/QApplication>
|
#include <QApplication>
|
||||||
#include "gallery.h"
|
#include "gallery.h"
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
|
|||||||
1
3rdparty/qocoa/qbutton.h
vendored
1
3rdparty/qocoa/qbutton.h
vendored
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include <QPointer>
|
#include <QPointer>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
class QButtonPrivate;
|
class QButtonPrivate;
|
||||||
class QButton : public QWidget
|
class QButton : public QWidget
|
||||||
|
|||||||
15
3rdparty/qocoa/qbutton_nonmac.cpp
vendored
15
3rdparty/qocoa/qbutton_nonmac.cpp
vendored
@@ -20,12 +20,19 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "qbutton.h"
|
#include <QtGlobal>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QPointer>
|
||||||
|
#include <QString>
|
||||||
|
#include <QPixmap>
|
||||||
|
#include <QAbstractButton>
|
||||||
|
#include <QBoxLayout>
|
||||||
|
#include <QPushButton>
|
||||||
#include <QToolBar>
|
#include <QToolBar>
|
||||||
#include <QToolButton>
|
#include <QToolButton>
|
||||||
#include <QPushButton>
|
|
||||||
#include <QVBoxLayout>
|
#include "qbutton.h"
|
||||||
|
|
||||||
class QButtonPrivate : public QObject
|
class QButtonPrivate : public QObject
|
||||||
{
|
{
|
||||||
|
|||||||
3
3rdparty/qocoa/qocoa_mac.h
vendored
3
3rdparty/qocoa/qocoa_mac.h
vendored
@@ -21,8 +21,9 @@ THE SOFTWARE.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <Foundation/NSString.h>
|
#include <Foundation/NSString.h>
|
||||||
|
#include <QByteArray>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QVBoxLayout>
|
#include <QBoxLayout>
|
||||||
#include <QMacCocoaViewContainer>
|
#include <QMacCocoaViewContainer>
|
||||||
|
|
||||||
static inline NSString* fromQString(const QString &string)
|
static inline NSString* fromQString(const QString &string)
|
||||||
|
|||||||
3
3rdparty/qocoa/qprogressindicatorspinning.h
vendored
3
3rdparty/qocoa/qprogressindicatorspinning.h
vendored
@@ -17,8 +17,7 @@ public:
|
|||||||
Aqua = 12
|
Aqua = 12
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit QProgressIndicatorSpinning(QWidget *parent,
|
explicit QProgressIndicatorSpinning(QWidget *parent, Thickness thickness = Default);
|
||||||
Thickness thickness = Default);
|
|
||||||
public slots:
|
public slots:
|
||||||
void animate(bool animate = true);
|
void animate(bool animate = true);
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -20,11 +20,16 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "qprogressindicatorspinning.h"
|
#include <QtGlobal>
|
||||||
|
#include <QObject>
|
||||||
#include <QVBoxLayout>
|
#include <QWidget>
|
||||||
#include <QMovie>
|
#include <QBoxLayout>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
|
#include <QMovie>
|
||||||
|
#include <QPointer>
|
||||||
|
#include <QSize>
|
||||||
|
|
||||||
|
#include "qprogressindicatorspinning.h"
|
||||||
|
|
||||||
class QProgressIndicatorSpinningPrivate : public QObject
|
class QProgressIndicatorSpinningPrivate : public QObject
|
||||||
{
|
{
|
||||||
|
|||||||
4
3rdparty/qocoa/qsearchfield.h
vendored
4
3rdparty/qocoa/qsearchfield.h
vendored
@@ -2,7 +2,11 @@
|
|||||||
#define QSEARCHFIELD_H
|
#define QSEARCHFIELD_H
|
||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
#include <QObject>
|
||||||
#include <QPointer>
|
#include <QPointer>
|
||||||
|
#include <QString>
|
||||||
|
#include <QEvent>
|
||||||
|
#include <QResizeEvent>
|
||||||
|
|
||||||
class QSearchFieldPrivate;
|
class QSearchFieldPrivate;
|
||||||
class QSearchField : public QWidget
|
class QSearchField : public QWidget
|
||||||
|
|||||||
22
3rdparty/qocoa/qsearchfield_nonmac.cpp
vendored
22
3rdparty/qocoa/qsearchfield_nonmac.cpp
vendored
@@ -20,18 +20,22 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "qsearchfield.h"
|
#include <QtGlobal>
|
||||||
#include "../../src/core/iconloader.h"
|
#include <QObject>
|
||||||
|
#include <QWidget>
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QEvent>
|
#include <QPointer>
|
||||||
#include <QLineEdit>
|
#include <QString>
|
||||||
#include <QVBoxLayout>
|
#include <QIcon>
|
||||||
#include <QToolButton>
|
#include <QSize>
|
||||||
#include <QStyle>
|
#include <QStyle>
|
||||||
|
#include <QLineEdit>
|
||||||
|
#include <QBoxLayout>
|
||||||
|
#include <QToolButton>
|
||||||
|
#include <QtEvents>
|
||||||
|
|
||||||
#include <QDir>
|
#include "../../src/core/iconloader.h"
|
||||||
#include <QDebug>
|
#include "qsearchfield.h"
|
||||||
|
|
||||||
class QSearchFieldPrivate : public QObject
|
class QSearchFieldPrivate : public QObject
|
||||||
{
|
{
|
||||||
|
|||||||
50
3rdparty/qsqlite/CMakeLists.txt
vendored
50
3rdparty/qsqlite/CMakeLists.txt
vendored
@@ -1,50 +0,0 @@
|
|||||||
cmake_minimum_required(VERSION 2.8.11)
|
|
||||||
|
|
||||||
add_definitions(-DQT_STATICPLUGIN)
|
|
||||||
|
|
||||||
# Source files
|
|
||||||
set(SQLITE-SOURCES
|
|
||||||
qsql_sqlite.cpp
|
|
||||||
sqlcachedresult.cpp
|
|
||||||
smain.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
# Header files that have Q_OBJECT in
|
|
||||||
set(SQLITE-MOC-HEADERS
|
|
||||||
qsql_sqlite.h
|
|
||||||
smain.h
|
|
||||||
)
|
|
||||||
|
|
||||||
set(SQLITE-WIN32-RESOURCES qsqlite_resource.rc)
|
|
||||||
|
|
||||||
qt5_wrap_cpp(SQLITE-SOURCES-MOC ${SQLITE-MOC-HEADERS})
|
|
||||||
|
|
||||||
include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
|
|
||||||
|
|
||||||
add_definitions(-DQT_PLUGIN -DQT_NO_DEBUG)
|
|
||||||
|
|
||||||
find_path(SQLITE_INCLUDE_DIRS sqlite3.h)
|
|
||||||
find_library(SQLITE_LIBRARIES sqlite3)
|
|
||||||
|
|
||||||
if (SQLITE_INCLUDE_DIRS AND SQLITE_LIBRARIES)
|
|
||||||
set(SQLITE_FOUND true)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (NOT SQLITE_FOUND)
|
|
||||||
message(SEND_ERROR "Could not find sqlite3")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
include_directories(${SQLITE_INCLUDE_DIRS})
|
|
||||||
|
|
||||||
add_library(qsqlite STATIC
|
|
||||||
${SQLITE-SOURCES}
|
|
||||||
${SQLITE-SOURCES-MOC}
|
|
||||||
${SQLITE-WIN32-RESOURCES}
|
|
||||||
)
|
|
||||||
|
|
||||||
set_property(TARGET qsqlite PROPERTY QT_STATICPLUGIN 1)
|
|
||||||
|
|
||||||
target_link_libraries(qsqlite
|
|
||||||
Qt5::Core Qt5::Sql
|
|
||||||
${SQLITE_LIBRARIES}
|
|
||||||
)
|
|
||||||
6
3rdparty/qsqlite/README
vendored
6
3rdparty/qsqlite/README
vendored
@@ -1,6 +0,0 @@
|
|||||||
This is the qsqlite plugin from the Qt SDK. It's built statically on Windows
|
|
||||||
and linked with libclementine. This is so librarybackend.cpp can use QLibrary
|
|
||||||
to load the symbols from sqlite (like sqlite3_create_function) which by
|
|
||||||
default aren't exported from the .dll on windows.
|
|
||||||
|
|
||||||
See the individual files for licensing information.
|
|
||||||
762
3rdparty/qsqlite/qsql_sqlite.cpp
vendored
762
3rdparty/qsqlite/qsql_sqlite.cpp
vendored
@@ -1,762 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
**
|
|
||||||
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
|
|
||||||
** Contact: http://www.qt-project.org/legal
|
|
||||||
**
|
|
||||||
** This file is part of the QtSql module of the Qt Toolkit.
|
|
||||||
**
|
|
||||||
** $QT_BEGIN_LICENSE:LGPL$
|
|
||||||
** Commercial License Usage
|
|
||||||
** Licensees holding valid commercial Qt licenses may use this file in
|
|
||||||
** accordance with the commercial license agreement provided with the
|
|
||||||
** Software or, alternatively, in accordance with the terms contained in
|
|
||||||
** a written agreement between you and Digia. For licensing terms and
|
|
||||||
** conditions see http://qt.digia.com/licensing. For further information
|
|
||||||
** use the contact form at http://qt.digia.com/contact-us.
|
|
||||||
**
|
|
||||||
** GNU Lesser General Public License Usage
|
|
||||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
|
||||||
** General Public License version 2.1 as published by the Free Software
|
|
||||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
|
||||||
** packaging of this file. Please review the following information to
|
|
||||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
|
||||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
|
||||||
**
|
|
||||||
** In addition, as a special exception, Digia gives you certain additional
|
|
||||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
|
||||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
||||||
**
|
|
||||||
** GNU General Public License Usage
|
|
||||||
** Alternatively, this file may be used under the terms of the GNU
|
|
||||||
** General Public License version 3.0 as published by the Free Software
|
|
||||||
** Foundation and appearing in the file LICENSE.GPL included in the
|
|
||||||
** packaging of this file. Please review the following information to
|
|
||||||
** ensure the GNU General Public License version 3.0 requirements will be
|
|
||||||
** met: http://www.gnu.org/copyleft/gpl.html.
|
|
||||||
**
|
|
||||||
**
|
|
||||||
** $QT_END_LICENSE$
|
|
||||||
**
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#include "qsql_sqlite.h"
|
|
||||||
|
|
||||||
#include <qcoreapplication.h>
|
|
||||||
#include <qvariant.h>
|
|
||||||
#include <qsqlerror.h>
|
|
||||||
#include <qsqlfield.h>
|
|
||||||
#include <qsqlindex.h>
|
|
||||||
#include <qsqlquery.h>
|
|
||||||
#include <qstringlist.h>
|
|
||||||
#include <qvector.h>
|
|
||||||
#include <qdebug.h>
|
|
||||||
|
|
||||||
#if defined Q_OS_WIN
|
|
||||||
# include <qt_windows.h>
|
|
||||||
#else
|
|
||||||
# include <unistd.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <sqlite3.h>
|
|
||||||
|
|
||||||
Q_DECLARE_OPAQUE_POINTER(sqlite3*)
|
|
||||||
Q_DECLARE_METATYPE(sqlite3*)
|
|
||||||
|
|
||||||
Q_DECLARE_OPAQUE_POINTER(sqlite3_stmt*)
|
|
||||||
Q_DECLARE_METATYPE(sqlite3_stmt*)
|
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
|
||||||
|
|
||||||
static QString _q_escapeIdentifier(const QString &identifier)
|
|
||||||
{
|
|
||||||
QString res = identifier;
|
|
||||||
if(!identifier.isEmpty() && identifier.left(1) != QString(QLatin1Char('"')) && identifier.right(1) != QString(QLatin1Char('"')) ) {
|
|
||||||
res.replace(QLatin1Char('"'), QLatin1String("\"\""));
|
|
||||||
res.prepend(QLatin1Char('"')).append(QLatin1Char('"'));
|
|
||||||
res.replace(QLatin1Char('.'), QLatin1String("\".\""));
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
static QVariant::Type qGetColumnType(const QString &tpName)
|
|
||||||
{
|
|
||||||
const QString typeName = tpName.toLower();
|
|
||||||
|
|
||||||
if (typeName == QLatin1String("integer")
|
|
||||||
|| typeName == QLatin1String("int"))
|
|
||||||
return QVariant::Int;
|
|
||||||
if (typeName == QLatin1String("double")
|
|
||||||
|| typeName == QLatin1String("float")
|
|
||||||
|| typeName == QLatin1String("real")
|
|
||||||
|| typeName.startsWith(QLatin1String("numeric")))
|
|
||||||
return QVariant::Double;
|
|
||||||
if (typeName == QLatin1String("blob"))
|
|
||||||
return QVariant::ByteArray;
|
|
||||||
if (typeName == QLatin1String("boolean")
|
|
||||||
|| typeName == QLatin1String("bool"))
|
|
||||||
return QVariant::Bool;
|
|
||||||
return QVariant::String;
|
|
||||||
}
|
|
||||||
|
|
||||||
static QSqlError qMakeError(sqlite3 *access, const QString &descr, QSqlError::ErrorType type,
|
|
||||||
int errorCode = -1)
|
|
||||||
{
|
|
||||||
return QSqlError(descr,
|
|
||||||
QString(reinterpret_cast<const QChar *>(sqlite3_errmsg16(access))),
|
|
||||||
type, errorCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
class QSQLiteDriverPrivate
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
inline QSQLiteDriverPrivate() : access(0) {}
|
|
||||||
sqlite3 *access;
|
|
||||||
QList <QSQLiteResult *> results;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class QSQLiteResultPrivate
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
QSQLiteResultPrivate(QSQLiteResult *res);
|
|
||||||
void cleanup();
|
|
||||||
bool fetchNext(ClementineSqlCachedResult::ValueCache &values, int idx, bool initialFetch);
|
|
||||||
// initializes the recordInfo and the cache
|
|
||||||
void initColumns(bool emptyResultset);
|
|
||||||
void finalize();
|
|
||||||
|
|
||||||
QSQLiteResult* q;
|
|
||||||
sqlite3 *access;
|
|
||||||
|
|
||||||
sqlite3_stmt *stmt;
|
|
||||||
|
|
||||||
bool skippedStatus; // the status of the fetchNext() that's skipped
|
|
||||||
bool skipRow; // skip the next fetchNext()?
|
|
||||||
QSqlRecord rInf;
|
|
||||||
QVector<QVariant> firstRow;
|
|
||||||
};
|
|
||||||
|
|
||||||
QSQLiteResultPrivate::QSQLiteResultPrivate(QSQLiteResult* res) : q(res), access(0),
|
|
||||||
stmt(0), skippedStatus(false), skipRow(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void QSQLiteResultPrivate::cleanup()
|
|
||||||
{
|
|
||||||
finalize();
|
|
||||||
rInf.clear();
|
|
||||||
skippedStatus = false;
|
|
||||||
skipRow = false;
|
|
||||||
q->setAt(QSql::BeforeFirstRow);
|
|
||||||
q->setActive(false);
|
|
||||||
q->cleanup();
|
|
||||||
}
|
|
||||||
|
|
||||||
void QSQLiteResultPrivate::finalize()
|
|
||||||
{
|
|
||||||
if (!stmt)
|
|
||||||
return;
|
|
||||||
|
|
||||||
sqlite3_finalize(stmt);
|
|
||||||
stmt = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void QSQLiteResultPrivate::initColumns(bool emptyResultset)
|
|
||||||
{
|
|
||||||
int nCols = sqlite3_column_count(stmt);
|
|
||||||
if (nCols <= 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
q->init(nCols);
|
|
||||||
|
|
||||||
for (int i = 0; i < nCols; ++i) {
|
|
||||||
QString colName = QString(reinterpret_cast<const QChar *>(
|
|
||||||
sqlite3_column_name16(stmt, i))
|
|
||||||
).remove(QLatin1Char('"'));
|
|
||||||
|
|
||||||
// must use typeName for resolving the type to match QSqliteDriver::record
|
|
||||||
QString typeName = QString(reinterpret_cast<const QChar *>(
|
|
||||||
sqlite3_column_decltype16(stmt, i)));
|
|
||||||
// sqlite3_column_type is documented to have undefined behavior if the result set is empty
|
|
||||||
int stp = emptyResultset ? -1 : sqlite3_column_type(stmt, i);
|
|
||||||
|
|
||||||
QVariant::Type fieldType;
|
|
||||||
|
|
||||||
if (!typeName.isEmpty()) {
|
|
||||||
fieldType = qGetColumnType(typeName);
|
|
||||||
} else {
|
|
||||||
// Get the proper type for the field based on stp value
|
|
||||||
switch (stp) {
|
|
||||||
case SQLITE_INTEGER:
|
|
||||||
fieldType = QVariant::Int;
|
|
||||||
break;
|
|
||||||
case SQLITE_FLOAT:
|
|
||||||
fieldType = QVariant::Double;
|
|
||||||
break;
|
|
||||||
case SQLITE_BLOB:
|
|
||||||
fieldType = QVariant::ByteArray;
|
|
||||||
break;
|
|
||||||
case SQLITE_TEXT:
|
|
||||||
fieldType = QVariant::String;
|
|
||||||
break;
|
|
||||||
case SQLITE_NULL:
|
|
||||||
default:
|
|
||||||
fieldType = QVariant::Invalid;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int dotIdx = colName.lastIndexOf(QLatin1Char('.'));
|
|
||||||
QSqlField fld(colName.mid(dotIdx == -1 ? 0 : dotIdx + 1), fieldType);
|
|
||||||
fld.setSqlType(stp);
|
|
||||||
rInf.append(fld);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool QSQLiteResultPrivate::fetchNext(ClementineSqlCachedResult::ValueCache &values, int idx, bool initialFetch)
|
|
||||||
{
|
|
||||||
int res;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (skipRow) {
|
|
||||||
// already fetched
|
|
||||||
Q_ASSERT(!initialFetch);
|
|
||||||
skipRow = false;
|
|
||||||
for(int i=0;i<firstRow.count();i++)
|
|
||||||
values[i]=firstRow[i];
|
|
||||||
return skippedStatus;
|
|
||||||
}
|
|
||||||
skipRow = initialFetch;
|
|
||||||
|
|
||||||
if(initialFetch) {
|
|
||||||
firstRow.clear();
|
|
||||||
firstRow.resize(sqlite3_column_count(stmt));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!stmt) {
|
|
||||||
q->setLastError(QSqlError(QCoreApplication::translate("QSQLiteResult", "Unable to fetch row"),
|
|
||||||
QCoreApplication::translate("QSQLiteResult", "No query"), QSqlError::ConnectionError));
|
|
||||||
q->setAt(QSql::AfterLastRow);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
res = sqlite3_step(stmt);
|
|
||||||
|
|
||||||
switch(res) {
|
|
||||||
case SQLITE_ROW:
|
|
||||||
// check to see if should fill out columns
|
|
||||||
if (rInf.isEmpty())
|
|
||||||
// must be first call.
|
|
||||||
initColumns(false);
|
|
||||||
if (idx < 0 && !initialFetch)
|
|
||||||
return true;
|
|
||||||
for (i = 0; i < rInf.count(); ++i) {
|
|
||||||
switch (sqlite3_column_type(stmt, i)) {
|
|
||||||
case SQLITE_BLOB:
|
|
||||||
values[i + idx] = QByteArray(static_cast<const char *>(
|
|
||||||
sqlite3_column_blob(stmt, i)),
|
|
||||||
sqlite3_column_bytes(stmt, i));
|
|
||||||
break;
|
|
||||||
case SQLITE_INTEGER:
|
|
||||||
values[i + idx] = sqlite3_column_int64(stmt, i);
|
|
||||||
break;
|
|
||||||
case SQLITE_FLOAT:
|
|
||||||
switch(q->numericalPrecisionPolicy()) {
|
|
||||||
case QSql::LowPrecisionInt32:
|
|
||||||
values[i + idx] = sqlite3_column_int(stmt, i);
|
|
||||||
break;
|
|
||||||
case QSql::LowPrecisionInt64:
|
|
||||||
values[i + idx] = sqlite3_column_int64(stmt, i);
|
|
||||||
break;
|
|
||||||
case QSql::LowPrecisionDouble:
|
|
||||||
case QSql::HighPrecision:
|
|
||||||
default:
|
|
||||||
values[i + idx] = sqlite3_column_double(stmt, i);
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
case SQLITE_NULL:
|
|
||||||
values[i + idx] = QVariant(QVariant::String);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
values[i + idx] = QString(reinterpret_cast<const QChar *>(
|
|
||||||
sqlite3_column_text16(stmt, i)),
|
|
||||||
sqlite3_column_bytes16(stmt, i) / sizeof(QChar));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
case SQLITE_DONE:
|
|
||||||
if (rInf.isEmpty())
|
|
||||||
// must be first call.
|
|
||||||
initColumns(true);
|
|
||||||
q->setAt(QSql::AfterLastRow);
|
|
||||||
sqlite3_reset(stmt);
|
|
||||||
return false;
|
|
||||||
case SQLITE_CONSTRAINT:
|
|
||||||
case SQLITE_ERROR:
|
|
||||||
// SQLITE_ERROR is a generic error code and we must call sqlite3_reset()
|
|
||||||
// to get the specific error message.
|
|
||||||
res = sqlite3_reset(stmt);
|
|
||||||
q->setLastError(qMakeError(access, QCoreApplication::translate("QSQLiteResult",
|
|
||||||
"Unable to fetch row"), QSqlError::ConnectionError, res));
|
|
||||||
q->setAt(QSql::AfterLastRow);
|
|
||||||
return false;
|
|
||||||
case SQLITE_MISUSE:
|
|
||||||
case SQLITE_BUSY:
|
|
||||||
default:
|
|
||||||
// something wrong, don't get col info, but still return false
|
|
||||||
q->setLastError(qMakeError(access, QCoreApplication::translate("QSQLiteResult",
|
|
||||||
"Unable to fetch row"), QSqlError::ConnectionError, res));
|
|
||||||
sqlite3_reset(stmt);
|
|
||||||
q->setAt(QSql::AfterLastRow);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
QSQLiteResult::QSQLiteResult(const QSQLiteDriver* db)
|
|
||||||
: ClementineSqlCachedResult(db)
|
|
||||||
{
|
|
||||||
d = new QSQLiteResultPrivate(this);
|
|
||||||
d->access = db->d->access;
|
|
||||||
db->d->results.append(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
QSQLiteResult::~QSQLiteResult()
|
|
||||||
{
|
|
||||||
const QSqlDriver *sqlDriver = driver();
|
|
||||||
if (sqlDriver)
|
|
||||||
qobject_cast<const QSQLiteDriver *>(sqlDriver)->d->results.removeOne(this);
|
|
||||||
d->cleanup();
|
|
||||||
delete d;
|
|
||||||
}
|
|
||||||
|
|
||||||
void QSQLiteResult::virtual_hook(int id, void *data)
|
|
||||||
{
|
|
||||||
ClementineSqlCachedResult::virtual_hook(id, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool QSQLiteResult::reset(const QString &query)
|
|
||||||
{
|
|
||||||
if (!prepare(query))
|
|
||||||
return false;
|
|
||||||
return exec();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool QSQLiteResult::prepare(const QString &query)
|
|
||||||
{
|
|
||||||
if (!driver() || !driver()->isOpen() || driver()->isOpenError())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
d->cleanup();
|
|
||||||
|
|
||||||
setSelect(false);
|
|
||||||
|
|
||||||
const void *pzTail = NULL;
|
|
||||||
|
|
||||||
#if (SQLITE_VERSION_NUMBER >= 3003011)
|
|
||||||
int res = sqlite3_prepare16_v2(d->access, query.constData(), (query.size() + 1) * sizeof(QChar),
|
|
||||||
&d->stmt, &pzTail);
|
|
||||||
#else
|
|
||||||
int res = sqlite3_prepare16(d->access, query.constData(), (query.size() + 1) * sizeof(QChar),
|
|
||||||
&d->stmt, &pzTail);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (res != SQLITE_OK) {
|
|
||||||
setLastError(qMakeError(d->access, QCoreApplication::translate("QSQLiteResult",
|
|
||||||
"Unable to execute statement"), QSqlError::StatementError, res));
|
|
||||||
d->finalize();
|
|
||||||
return false;
|
|
||||||
} else if (pzTail && !QString(reinterpret_cast<const QChar *>(pzTail)).trimmed().isEmpty()) {
|
|
||||||
setLastError(qMakeError(d->access, QCoreApplication::translate("QSQLiteResult",
|
|
||||||
"Unable to execute multiple statements at a time"), QSqlError::StatementError, SQLITE_MISUSE));
|
|
||||||
d->finalize();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool QSQLiteResult::exec()
|
|
||||||
{
|
|
||||||
const QVector<QVariant> values = boundValues();
|
|
||||||
|
|
||||||
d->skippedStatus = false;
|
|
||||||
d->skipRow = false;
|
|
||||||
d->rInf.clear();
|
|
||||||
clearValues();
|
|
||||||
setLastError(QSqlError());
|
|
||||||
|
|
||||||
int res = sqlite3_reset(d->stmt);
|
|
||||||
if (res != SQLITE_OK) {
|
|
||||||
setLastError(qMakeError(d->access, QCoreApplication::translate("QSQLiteResult",
|
|
||||||
"Unable to reset statement"), QSqlError::StatementError, res));
|
|
||||||
d->finalize();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
int paramCount = sqlite3_bind_parameter_count(d->stmt);
|
|
||||||
if (paramCount == values.count()) {
|
|
||||||
for (int i = 0; i < paramCount; ++i) {
|
|
||||||
res = SQLITE_OK;
|
|
||||||
const QVariant value = values.at(i);
|
|
||||||
|
|
||||||
if (value.isNull()) {
|
|
||||||
res = sqlite3_bind_null(d->stmt, i + 1);
|
|
||||||
} else {
|
|
||||||
switch (value.type()) {
|
|
||||||
case QVariant::ByteArray: {
|
|
||||||
const QByteArray *ba = static_cast<const QByteArray*>(value.constData());
|
|
||||||
res = sqlite3_bind_blob(d->stmt, i + 1, ba->constData(),
|
|
||||||
ba->size(), SQLITE_STATIC);
|
|
||||||
break; }
|
|
||||||
case QVariant::Int:
|
|
||||||
case QVariant::Bool:
|
|
||||||
res = sqlite3_bind_int(d->stmt, i + 1, value.toInt());
|
|
||||||
break;
|
|
||||||
case QVariant::Double:
|
|
||||||
res = sqlite3_bind_double(d->stmt, i + 1, value.toDouble());
|
|
||||||
break;
|
|
||||||
case QVariant::UInt:
|
|
||||||
case QVariant::LongLong:
|
|
||||||
res = sqlite3_bind_int64(d->stmt, i + 1, value.toLongLong());
|
|
||||||
break;
|
|
||||||
case QVariant::String: {
|
|
||||||
// lifetime of string == lifetime of its qvariant
|
|
||||||
const QString *str = static_cast<const QString*>(value.constData());
|
|
||||||
res = sqlite3_bind_text16(d->stmt, i + 1, str->utf16(),
|
|
||||||
(str->size()) * sizeof(QChar), SQLITE_STATIC);
|
|
||||||
break; }
|
|
||||||
default: {
|
|
||||||
QString str = value.toString();
|
|
||||||
// SQLITE_TRANSIENT makes sure that sqlite buffers the data
|
|
||||||
res = sqlite3_bind_text16(d->stmt, i + 1, str.utf16(),
|
|
||||||
(str.size()) * sizeof(QChar), SQLITE_TRANSIENT);
|
|
||||||
break; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (res != SQLITE_OK) {
|
|
||||||
setLastError(qMakeError(d->access, QCoreApplication::translate("QSQLiteResult",
|
|
||||||
"Unable to bind parameters"), QSqlError::StatementError, res));
|
|
||||||
d->finalize();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
setLastError(QSqlError(QCoreApplication::translate("QSQLiteResult",
|
|
||||||
"Parameter count mismatch") + QString::number(paramCount, 10) + "/" + QString::number(values.count(), 10), QString(), QSqlError::StatementError));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
d->skippedStatus = d->fetchNext(d->firstRow, 0, true);
|
|
||||||
if (lastError().isValid()) {
|
|
||||||
setSelect(false);
|
|
||||||
setActive(false);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
setSelect(!d->rInf.isEmpty());
|
|
||||||
setActive(true);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool QSQLiteResult::gotoNext(ClementineSqlCachedResult::ValueCache& row, int idx)
|
|
||||||
{
|
|
||||||
return d->fetchNext(row, idx, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
int QSQLiteResult::size()
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int QSQLiteResult::numRowsAffected()
|
|
||||||
{
|
|
||||||
return sqlite3_changes(d->access);
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariant QSQLiteResult::lastInsertId() const
|
|
||||||
{
|
|
||||||
if (isActive()) {
|
|
||||||
qint64 id = sqlite3_last_insert_rowid(d->access);
|
|
||||||
if (id)
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
return QVariant();
|
|
||||||
}
|
|
||||||
|
|
||||||
QSqlRecord QSQLiteResult::record() const
|
|
||||||
{
|
|
||||||
if (!isActive() || !isSelect())
|
|
||||||
return QSqlRecord();
|
|
||||||
return d->rInf;
|
|
||||||
}
|
|
||||||
|
|
||||||
void QSQLiteResult::detachFromResultSet()
|
|
||||||
{
|
|
||||||
if (d->stmt)
|
|
||||||
sqlite3_reset(d->stmt);
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariant QSQLiteResult::handle() const
|
|
||||||
{
|
|
||||||
return QVariant::fromValue(d->stmt);
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
QSQLiteDriver::QSQLiteDriver(QObject * parent)
|
|
||||||
: QSqlDriver(parent)
|
|
||||||
{
|
|
||||||
d = new QSQLiteDriverPrivate();
|
|
||||||
}
|
|
||||||
|
|
||||||
QSQLiteDriver::QSQLiteDriver(sqlite3 *connection, QObject *parent)
|
|
||||||
: QSqlDriver(parent)
|
|
||||||
{
|
|
||||||
d = new QSQLiteDriverPrivate();
|
|
||||||
d->access = connection;
|
|
||||||
setOpen(true);
|
|
||||||
setOpenError(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
QSQLiteDriver::~QSQLiteDriver()
|
|
||||||
{
|
|
||||||
delete d;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool QSQLiteDriver::hasFeature(DriverFeature f) const
|
|
||||||
{
|
|
||||||
switch (f) {
|
|
||||||
case BLOB:
|
|
||||||
case Transactions:
|
|
||||||
case Unicode:
|
|
||||||
case LastInsertId:
|
|
||||||
case PreparedQueries:
|
|
||||||
case PositionalPlaceholders:
|
|
||||||
case SimpleLocking:
|
|
||||||
case FinishQuery:
|
|
||||||
case LowPrecisionNumbers:
|
|
||||||
return true;
|
|
||||||
case QuerySize:
|
|
||||||
case NamedPlaceholders:
|
|
||||||
case BatchOperations:
|
|
||||||
case EventNotifications:
|
|
||||||
case MultipleResultSets:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
SQLite dbs have no user name, passwords, hosts or ports.
|
|
||||||
just file names.
|
|
||||||
*/
|
|
||||||
bool QSQLiteDriver::open(const QString & db, const QString &, const QString &, const QString &, int, const QString &conOpts)
|
|
||||||
{
|
|
||||||
if (isOpen())
|
|
||||||
close();
|
|
||||||
|
|
||||||
if (db.isEmpty())
|
|
||||||
return false;
|
|
||||||
bool sharedCache = false;
|
|
||||||
int openMode = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, timeOut=5000;
|
|
||||||
QStringList opts=QString(conOpts).remove(QLatin1Char(' ')).split(QLatin1Char(';'));
|
|
||||||
foreach(const QString &option, opts) {
|
|
||||||
if (option.startsWith(QLatin1String("QSQLITE_BUSY_TIMEOUT="))) {
|
|
||||||
bool ok;
|
|
||||||
int nt = option.mid(21).toInt(&ok);
|
|
||||||
if (ok)
|
|
||||||
timeOut = nt;
|
|
||||||
}
|
|
||||||
if (option == QLatin1String("QSQLITE_OPEN_READONLY"))
|
|
||||||
openMode = SQLITE_OPEN_READONLY;
|
|
||||||
if (option == QLatin1String("QSQLITE_ENABLE_SHARED_CACHE"))
|
|
||||||
sharedCache = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
sqlite3_enable_shared_cache(sharedCache);
|
|
||||||
|
|
||||||
if (sqlite3_open_v2(db.toUtf8().constData(), &d->access, openMode, NULL) == SQLITE_OK) {
|
|
||||||
sqlite3_busy_timeout(d->access, timeOut);
|
|
||||||
setOpen(true);
|
|
||||||
setOpenError(false);
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
if (d->access) {
|
|
||||||
sqlite3_close(d->access);
|
|
||||||
d->access = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
setLastError(qMakeError(d->access, tr("Error opening database"),
|
|
||||||
QSqlError::ConnectionError));
|
|
||||||
setOpenError(true);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void QSQLiteDriver::close()
|
|
||||||
{
|
|
||||||
if (isOpen()) {
|
|
||||||
foreach (QSQLiteResult *result, d->results) {
|
|
||||||
result->d->finalize();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sqlite3_close(d->access) != SQLITE_OK)
|
|
||||||
setLastError(qMakeError(d->access, tr("Error closing database"),
|
|
||||||
QSqlError::ConnectionError));
|
|
||||||
d->access = 0;
|
|
||||||
setOpen(false);
|
|
||||||
setOpenError(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QSqlResult *QSQLiteDriver::createResult() const
|
|
||||||
{
|
|
||||||
return new QSQLiteResult(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool QSQLiteDriver::beginTransaction()
|
|
||||||
{
|
|
||||||
if (!isOpen() || isOpenError())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
QSqlQuery q(createResult());
|
|
||||||
if (!q.exec(QLatin1String("BEGIN"))) {
|
|
||||||
setLastError(QSqlError(tr("Unable to begin transaction"),
|
|
||||||
q.lastError().databaseText(), QSqlError::TransactionError));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool QSQLiteDriver::commitTransaction()
|
|
||||||
{
|
|
||||||
if (!isOpen() || isOpenError())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
QSqlQuery q(createResult());
|
|
||||||
if (!q.exec(QLatin1String("COMMIT"))) {
|
|
||||||
setLastError(QSqlError(tr("Unable to commit transaction"),
|
|
||||||
q.lastError().databaseText(), QSqlError::TransactionError));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool QSQLiteDriver::rollbackTransaction()
|
|
||||||
{
|
|
||||||
if (!isOpen() || isOpenError())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
QSqlQuery q(createResult());
|
|
||||||
if (!q.exec(QLatin1String("ROLLBACK"))) {
|
|
||||||
setLastError(QSqlError(tr("Unable to rollback transaction"),
|
|
||||||
q.lastError().databaseText(), QSqlError::TransactionError));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringList QSQLiteDriver::tables(QSql::TableType type) const
|
|
||||||
{
|
|
||||||
QStringList res;
|
|
||||||
if (!isOpen())
|
|
||||||
return res;
|
|
||||||
|
|
||||||
QSqlQuery q(createResult());
|
|
||||||
q.setForwardOnly(true);
|
|
||||||
|
|
||||||
QString sql = QLatin1String("SELECT name FROM sqlite_master WHERE %1 "
|
|
||||||
"UNION ALL SELECT name FROM sqlite_temp_master WHERE %1");
|
|
||||||
if ((type & QSql::Tables) && (type & QSql::Views))
|
|
||||||
sql = sql.arg(QLatin1String("type='table' OR type='view'"));
|
|
||||||
else if (type & QSql::Tables)
|
|
||||||
sql = sql.arg(QLatin1String("type='table'"));
|
|
||||||
else if (type & QSql::Views)
|
|
||||||
sql = sql.arg(QLatin1String("type='view'"));
|
|
||||||
else
|
|
||||||
sql.clear();
|
|
||||||
|
|
||||||
if (!sql.isEmpty() && q.exec(sql)) {
|
|
||||||
while(q.next())
|
|
||||||
res.append(q.value(0).toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type & QSql::SystemTables) {
|
|
||||||
// there are no internal tables beside this one:
|
|
||||||
res.append(QLatin1String("sqlite_master"));
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
static QSqlIndex qGetTableInfo(QSqlQuery &q, const QString &tableName, bool onlyPIndex = false)
|
|
||||||
{
|
|
||||||
QString schema;
|
|
||||||
QString table(tableName);
|
|
||||||
int indexOfSeparator = tableName.indexOf(QLatin1Char('.'));
|
|
||||||
if (indexOfSeparator > -1) {
|
|
||||||
schema = tableName.left(indexOfSeparator).append(QLatin1Char('.'));
|
|
||||||
table = tableName.mid(indexOfSeparator + 1);
|
|
||||||
}
|
|
||||||
q.exec(QLatin1String("PRAGMA ") + schema + QLatin1String("table_info (") + _q_escapeIdentifier(table) + QLatin1String(")"));
|
|
||||||
|
|
||||||
QSqlIndex ind;
|
|
||||||
while (q.next()) {
|
|
||||||
bool isPk = q.value(5).toInt();
|
|
||||||
if (onlyPIndex && !isPk)
|
|
||||||
continue;
|
|
||||||
QString typeName = q.value(2).toString().toLower();
|
|
||||||
QSqlField fld(q.value(1).toString(), qGetColumnType(typeName));
|
|
||||||
if (isPk && (typeName == QLatin1String("integer")))
|
|
||||||
// INTEGER PRIMARY KEY fields are auto-generated in sqlite
|
|
||||||
// INT PRIMARY KEY is not the same as INTEGER PRIMARY KEY!
|
|
||||||
fld.setAutoValue(true);
|
|
||||||
fld.setRequired(q.value(3).toInt() != 0);
|
|
||||||
fld.setDefaultValue(q.value(4));
|
|
||||||
ind.append(fld);
|
|
||||||
}
|
|
||||||
return ind;
|
|
||||||
}
|
|
||||||
|
|
||||||
QSqlIndex QSQLiteDriver::primaryIndex(const QString &tblname) const
|
|
||||||
{
|
|
||||||
if (!isOpen())
|
|
||||||
return QSqlIndex();
|
|
||||||
|
|
||||||
QString table = tblname;
|
|
||||||
if (isIdentifierEscaped(table, QSqlDriver::TableName))
|
|
||||||
table = stripDelimiters(table, QSqlDriver::TableName);
|
|
||||||
|
|
||||||
QSqlQuery q(createResult());
|
|
||||||
q.setForwardOnly(true);
|
|
||||||
return qGetTableInfo(q, table, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
QSqlRecord QSQLiteDriver::record(const QString &tbl) const
|
|
||||||
{
|
|
||||||
if (!isOpen())
|
|
||||||
return QSqlRecord();
|
|
||||||
|
|
||||||
QString table = tbl;
|
|
||||||
if (isIdentifierEscaped(table, QSqlDriver::TableName))
|
|
||||||
table = stripDelimiters(table, QSqlDriver::TableName);
|
|
||||||
|
|
||||||
QSqlQuery q(createResult());
|
|
||||||
q.setForwardOnly(true);
|
|
||||||
return qGetTableInfo(q, table);
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariant QSQLiteDriver::handle() const
|
|
||||||
{
|
|
||||||
return QVariant::fromValue(d->access);
|
|
||||||
}
|
|
||||||
|
|
||||||
QString QSQLiteDriver::escapeIdentifier(const QString &identifier, IdentifierType type) const
|
|
||||||
{
|
|
||||||
Q_UNUSED(type);
|
|
||||||
return _q_escapeIdentifier(identifier);
|
|
||||||
}
|
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
|
||||||
124
3rdparty/qsqlite/qsql_sqlite.h
vendored
124
3rdparty/qsqlite/qsql_sqlite.h
vendored
@@ -1,124 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
**
|
|
||||||
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
|
|
||||||
** Contact: http://www.qt-project.org/legal
|
|
||||||
**
|
|
||||||
** This file is part of the QtSql module of the Qt Toolkit.
|
|
||||||
**
|
|
||||||
** $QT_BEGIN_LICENSE:LGPL$
|
|
||||||
** Commercial License Usage
|
|
||||||
** Licensees holding valid commercial Qt licenses may use this file in
|
|
||||||
** accordance with the commercial license agreement provided with the
|
|
||||||
** Software or, alternatively, in accordance with the terms contained in
|
|
||||||
** a written agreement between you and Digia. For licensing terms and
|
|
||||||
** conditions see http://qt.digia.com/licensing. For further information
|
|
||||||
** use the contact form at http://qt.digia.com/contact-us.
|
|
||||||
**
|
|
||||||
** GNU Lesser General Public License Usage
|
|
||||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
|
||||||
** General Public License version 2.1 as published by the Free Software
|
|
||||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
|
||||||
** packaging of this file. Please review the following information to
|
|
||||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
|
||||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
|
||||||
**
|
|
||||||
** In addition, as a special exception, Digia gives you certain additional
|
|
||||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
|
||||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
||||||
**
|
|
||||||
** GNU General Public License Usage
|
|
||||||
** Alternatively, this file may be used under the terms of the GNU
|
|
||||||
** General Public License version 3.0 as published by the Free Software
|
|
||||||
** Foundation and appearing in the file LICENSE.GPL included in the
|
|
||||||
** packaging of this file. Please review the following information to
|
|
||||||
** ensure the GNU General Public License version 3.0 requirements will be
|
|
||||||
** met: http://www.gnu.org/copyleft/gpl.html.
|
|
||||||
**
|
|
||||||
**
|
|
||||||
** $QT_END_LICENSE$
|
|
||||||
**
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#ifndef QSQL_SQLITE_H
|
|
||||||
#define QSQL_SQLITE_H
|
|
||||||
|
|
||||||
#include <QtSql/qsqldriver.h>
|
|
||||||
#include <QtSql/qsqlresult.h>
|
|
||||||
#include "sqlcachedresult.h"
|
|
||||||
|
|
||||||
struct sqlite3;
|
|
||||||
|
|
||||||
#ifdef QT_PLUGIN
|
|
||||||
#define Q_EXPORT_SQLDRIVER_SQLITE
|
|
||||||
#else
|
|
||||||
#define Q_EXPORT_SQLDRIVER_SQLITE Q_SQL_EXPORT
|
|
||||||
#endif
|
|
||||||
|
|
||||||
QT_BEGIN_HEADER
|
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
|
||||||
class QSQLiteDriverPrivate;
|
|
||||||
class QSQLiteResultPrivate;
|
|
||||||
class QSQLiteDriver;
|
|
||||||
|
|
||||||
class QSQLiteResult : public ClementineSqlCachedResult
|
|
||||||
{
|
|
||||||
friend class QSQLiteDriver;
|
|
||||||
friend class QSQLiteResultPrivate;
|
|
||||||
public:
|
|
||||||
explicit QSQLiteResult(const QSQLiteDriver* db);
|
|
||||||
~QSQLiteResult();
|
|
||||||
QVariant handle() const;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
bool gotoNext(ClementineSqlCachedResult::ValueCache& row, int idx);
|
|
||||||
bool reset(const QString &query);
|
|
||||||
bool prepare(const QString &query);
|
|
||||||
bool exec();
|
|
||||||
int size();
|
|
||||||
int numRowsAffected();
|
|
||||||
QVariant lastInsertId() const;
|
|
||||||
QSqlRecord record() const;
|
|
||||||
void detachFromResultSet();
|
|
||||||
void virtual_hook(int id, void *data);
|
|
||||||
|
|
||||||
private:
|
|
||||||
QSQLiteResultPrivate* d;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Q_EXPORT_SQLDRIVER_SQLITE QSQLiteDriver : public QSqlDriver
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
friend class QSQLiteResult;
|
|
||||||
public:
|
|
||||||
explicit QSQLiteDriver(QObject *parent = 0);
|
|
||||||
explicit QSQLiteDriver(sqlite3 *connection, QObject *parent = 0);
|
|
||||||
~QSQLiteDriver();
|
|
||||||
bool hasFeature(DriverFeature f) const;
|
|
||||||
bool open(const QString & db,
|
|
||||||
const QString & user,
|
|
||||||
const QString & password,
|
|
||||||
const QString & host,
|
|
||||||
int port,
|
|
||||||
const QString & connOpts);
|
|
||||||
void close();
|
|
||||||
QSqlResult *createResult() const;
|
|
||||||
bool beginTransaction();
|
|
||||||
bool commitTransaction();
|
|
||||||
bool rollbackTransaction();
|
|
||||||
QStringList tables(QSql::TableType) const;
|
|
||||||
|
|
||||||
QSqlRecord record(const QString& tablename) const;
|
|
||||||
QSqlIndex primaryIndex(const QString &table) const;
|
|
||||||
QVariant handle() const;
|
|
||||||
QString escapeIdentifier(const QString &identifier, IdentifierType) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
QSQLiteDriverPrivate* d;
|
|
||||||
};
|
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
|
||||||
|
|
||||||
QT_END_HEADER
|
|
||||||
|
|
||||||
#endif // QSQL_SQLITE_H
|
|
||||||
3
3rdparty/qsqlite/qsqlite.json
vendored
3
3rdparty/qsqlite/qsqlite.json
vendored
@@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"Keys": [ "QSQLITE" ]
|
|
||||||
}
|
|
||||||
35
3rdparty/qsqlite/qsqlite_resource.rc
vendored
35
3rdparty/qsqlite/qsqlite_resource.rc
vendored
@@ -1,35 +0,0 @@
|
|||||||
#include <windows.h>
|
|
||||||
|
|
||||||
VS_VERSION_INFO VERSIONINFO
|
|
||||||
FILEVERSION 5,10,1,0
|
|
||||||
PRODUCTVERSION 5,10,1,0
|
|
||||||
FILEFLAGSMASK 0x3fL
|
|
||||||
#ifdef _DEBUG
|
|
||||||
FILEFLAGS VS_FF_DEBUG
|
|
||||||
#else
|
|
||||||
FILEFLAGS 0x0L
|
|
||||||
#endif
|
|
||||||
FILEOS VOS__WINDOWS32
|
|
||||||
FILETYPE VFT_DLL
|
|
||||||
FILESUBTYPE 0x0L
|
|
||||||
BEGIN
|
|
||||||
BLOCK "StringFileInfo"
|
|
||||||
BEGIN
|
|
||||||
BLOCK "040904b0"
|
|
||||||
BEGIN
|
|
||||||
VALUE "CompanyName", "The Qt Company Ltd.\0"
|
|
||||||
VALUE "FileDescription", "C++ Application Development Framework\0"
|
|
||||||
VALUE "FileVersion", "5.10.1.0\0"
|
|
||||||
VALUE "LegalCopyright", "Copyright (C) 2017 The Qt Company Ltd.\0"
|
|
||||||
VALUE "OriginalFilename", "qsqlite.dll\0"
|
|
||||||
VALUE "ProductName", "Qt5\0"
|
|
||||||
VALUE "ProductVersion", "5.10.1.0\0"
|
|
||||||
END
|
|
||||||
END
|
|
||||||
BLOCK "VarFileInfo"
|
|
||||||
BEGIN
|
|
||||||
VALUE "Translation", 0x0409, 1200
|
|
||||||
END
|
|
||||||
END
|
|
||||||
/* End of Version info */
|
|
||||||
|
|
||||||
52
3rdparty/qsqlite/smain.cpp
vendored
52
3rdparty/qsqlite/smain.cpp
vendored
@@ -1,52 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
**
|
|
||||||
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
|
|
||||||
** Contact: http://www.qt-project.org/legal
|
|
||||||
**
|
|
||||||
** This file is part of the plugins of the Qt Toolkit.
|
|
||||||
**
|
|
||||||
** $QT_BEGIN_LICENSE:LGPL21$
|
|
||||||
** Commercial License Usage
|
|
||||||
** Licensees holding valid commercial Qt licenses may use this file in
|
|
||||||
** accordance with the commercial license agreement provided with the
|
|
||||||
** Software or, alternatively, in accordance with the terms contained in
|
|
||||||
** a written agreement between you and Digia. For licensing terms and
|
|
||||||
** conditions see http://qt.digia.com/licensing. For further information
|
|
||||||
** use the contact form at http://qt.digia.com/contact-us.
|
|
||||||
**
|
|
||||||
** GNU Lesser General Public License Usage
|
|
||||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
|
||||||
** General Public License version 2.1 or version 3 as published by the Free
|
|
||||||
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
|
||||||
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
|
||||||
** following information to ensure the GNU Lesser General Public License
|
|
||||||
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
|
||||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
|
||||||
**
|
|
||||||
** In addition, as a special exception, Digia gives you certain additional
|
|
||||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
|
||||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
||||||
**
|
|
||||||
** $QT_END_LICENSE$
|
|
||||||
**
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#include "smain.h"
|
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
|
||||||
|
|
||||||
QSQLiteDriverPlugin::QSQLiteDriverPlugin()
|
|
||||||
: QSqlDriverPlugin()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
QSqlDriver* QSQLiteDriverPlugin::create(const QString &name)
|
|
||||||
{
|
|
||||||
if (name == QLatin1String("QSQLITE")) {
|
|
||||||
QSQLiteDriver* driver = new QSQLiteDriver();
|
|
||||||
return driver;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
|
||||||
51
3rdparty/qsqlite/smain.h
vendored
51
3rdparty/qsqlite/smain.h
vendored
@@ -1,51 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
**
|
|
||||||
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
|
|
||||||
** Contact: http://www.qt-project.org/legal
|
|
||||||
**
|
|
||||||
** This file is part of the plugins of the Qt Toolkit.
|
|
||||||
**
|
|
||||||
** $QT_BEGIN_LICENSE:LGPL21$
|
|
||||||
** Commercial License Usage
|
|
||||||
** Licensees holding valid commercial Qt licenses may use this file in
|
|
||||||
** accordance with the commercial license agreement provided with the
|
|
||||||
** Software or, alternatively, in accordance with the terms contained in
|
|
||||||
** a written agreement between you and Digia. For licensing terms and
|
|
||||||
** conditions see http://qt.digia.com/licensing. For further information
|
|
||||||
** use the contact form at http://qt.digia.com/contact-us.
|
|
||||||
**
|
|
||||||
** GNU Lesser General Public License Usage
|
|
||||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
|
||||||
** General Public License version 2.1 or version 3 as published by the Free
|
|
||||||
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
|
||||||
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
|
||||||
** following information to ensure the GNU Lesser General Public License
|
|
||||||
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
|
||||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
|
||||||
**
|
|
||||||
** In addition, as a special exception, Digia gives you certain additional
|
|
||||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
|
||||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
||||||
**
|
|
||||||
** $QT_END_LICENSE$
|
|
||||||
**
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#include <qsqldriverplugin.h>
|
|
||||||
#include <qstringlist.h>
|
|
||||||
#include "qsql_sqlite.h"
|
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
|
||||||
|
|
||||||
class QSQLiteDriverPlugin : public QSqlDriverPlugin
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QSqlDriverFactoryInterface" FILE "qsqlite.json")
|
|
||||||
|
|
||||||
public:
|
|
||||||
QSQLiteDriverPlugin();
|
|
||||||
|
|
||||||
QSqlDriver* create(const QString &);
|
|
||||||
};
|
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
|
||||||
322
3rdparty/qsqlite/sqlcachedresult.cpp
vendored
322
3rdparty/qsqlite/sqlcachedresult.cpp
vendored
@@ -1,322 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
**
|
|
||||||
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
|
|
||||||
** Contact: http://www.qt-project.org/legal
|
|
||||||
**
|
|
||||||
** This file is part of the QtSql module of the Qt Toolkit.
|
|
||||||
**
|
|
||||||
** $QT_BEGIN_LICENSE:LGPL$
|
|
||||||
** Commercial License Usage
|
|
||||||
** Licensees holding valid commercial Qt licenses may use this file in
|
|
||||||
** accordance with the commercial license agreement provided with the
|
|
||||||
** Software or, alternatively, in accordance with the terms contained in
|
|
||||||
** a written agreement between you and Digia. For licensing terms and
|
|
||||||
** conditions see http://qt.digia.com/licensing. For further information
|
|
||||||
** use the contact form at http://qt.digia.com/contact-us.
|
|
||||||
**
|
|
||||||
** GNU Lesser General Public License Usage
|
|
||||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
|
||||||
** General Public License version 2.1 as published by the Free Software
|
|
||||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
|
||||||
** packaging of this file. Please review the following information to
|
|
||||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
|
||||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
|
||||||
**
|
|
||||||
** In addition, as a special exception, Digia gives you certain additional
|
|
||||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
|
||||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
||||||
**
|
|
||||||
** GNU General Public License Usage
|
|
||||||
** Alternatively, this file may be used under the terms of the GNU
|
|
||||||
** General Public License version 3.0 as published by the Free Software
|
|
||||||
** Foundation and appearing in the file LICENSE.GPL included in the
|
|
||||||
** packaging of this file. Please review the following information to
|
|
||||||
** ensure the GNU General Public License version 3.0 requirements will be
|
|
||||||
** met: http://www.gnu.org/copyleft/gpl.html.
|
|
||||||
**
|
|
||||||
**
|
|
||||||
** $QT_END_LICENSE$
|
|
||||||
**
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#include <qvariant.h>
|
|
||||||
#include <qdatetime.h>
|
|
||||||
#include <qvector.h>
|
|
||||||
|
|
||||||
#include "sqlcachedresult.h"
|
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
|
||||||
|
|
||||||
/*
|
|
||||||
ClementineSqlCachedResult is a convenience class for databases that only allow
|
|
||||||
forward only fetching. It will cache all the results so we can iterate
|
|
||||||
backwards over the results again.
|
|
||||||
|
|
||||||
All you need to do is to inherit from ClementineSqlCachedResult and reimplement
|
|
||||||
gotoNext(). gotoNext() will have a reference to the internal cache and
|
|
||||||
will give you an index where you can start filling in your data. Special
|
|
||||||
case: If the user actually wants a forward-only query, idx will be -1
|
|
||||||
to indicate that we are not interested in the actual values.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static const uint initial_cache_size = 128;
|
|
||||||
|
|
||||||
class ClementineSqlCachedResultPrivate
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ClementineSqlCachedResultPrivate();
|
|
||||||
bool canSeek(int i) const;
|
|
||||||
inline int cacheCount() const;
|
|
||||||
void init(int count, bool fo);
|
|
||||||
void cleanup();
|
|
||||||
int nextIndex();
|
|
||||||
void revertLast();
|
|
||||||
|
|
||||||
ClementineSqlCachedResult::ValueCache cache;
|
|
||||||
int rowCacheEnd;
|
|
||||||
int colCount;
|
|
||||||
bool forwardOnly;
|
|
||||||
bool atEnd;
|
|
||||||
};
|
|
||||||
|
|
||||||
ClementineSqlCachedResultPrivate::ClementineSqlCachedResultPrivate():
|
|
||||||
rowCacheEnd(0), colCount(0), forwardOnly(false), atEnd(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClementineSqlCachedResultPrivate::cleanup()
|
|
||||||
{
|
|
||||||
cache.clear();
|
|
||||||
forwardOnly = false;
|
|
||||||
atEnd = false;
|
|
||||||
colCount = 0;
|
|
||||||
rowCacheEnd = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClementineSqlCachedResultPrivate::init(int count, bool fo)
|
|
||||||
{
|
|
||||||
Q_ASSERT(count);
|
|
||||||
cleanup();
|
|
||||||
forwardOnly = fo;
|
|
||||||
colCount = count;
|
|
||||||
if (fo) {
|
|
||||||
cache.resize(count);
|
|
||||||
rowCacheEnd = count;
|
|
||||||
} else {
|
|
||||||
cache.resize(initial_cache_size * count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int ClementineSqlCachedResultPrivate::nextIndex()
|
|
||||||
{
|
|
||||||
if (forwardOnly)
|
|
||||||
return 0;
|
|
||||||
int newIdx = rowCacheEnd;
|
|
||||||
if (newIdx + colCount > cache.size())
|
|
||||||
cache.resize(qMin(cache.size() * 2, cache.size() + 10000));
|
|
||||||
rowCacheEnd += colCount;
|
|
||||||
|
|
||||||
return newIdx;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ClementineSqlCachedResultPrivate::canSeek(int i) const
|
|
||||||
{
|
|
||||||
if (forwardOnly || i < 0)
|
|
||||||
return false;
|
|
||||||
return rowCacheEnd >= (i + 1) * colCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClementineSqlCachedResultPrivate::revertLast()
|
|
||||||
{
|
|
||||||
if (forwardOnly)
|
|
||||||
return;
|
|
||||||
rowCacheEnd -= colCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int ClementineSqlCachedResultPrivate::cacheCount() const
|
|
||||||
{
|
|
||||||
Q_ASSERT(!forwardOnly);
|
|
||||||
Q_ASSERT(colCount);
|
|
||||||
return rowCacheEnd / colCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////
|
|
||||||
|
|
||||||
ClementineSqlCachedResult::ClementineSqlCachedResult(const QSqlDriver * db): QSqlResult (db)
|
|
||||||
{
|
|
||||||
d = new ClementineSqlCachedResultPrivate();
|
|
||||||
}
|
|
||||||
|
|
||||||
ClementineSqlCachedResult::~ClementineSqlCachedResult()
|
|
||||||
{
|
|
||||||
delete d;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClementineSqlCachedResult::init(int colCount)
|
|
||||||
{
|
|
||||||
d->init(colCount, isForwardOnly());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ClementineSqlCachedResult::fetch(int i)
|
|
||||||
{
|
|
||||||
if ((!isActive()) || (i < 0))
|
|
||||||
return false;
|
|
||||||
if (at() == i)
|
|
||||||
return true;
|
|
||||||
if (d->forwardOnly) {
|
|
||||||
// speed hack - do not copy values if not needed
|
|
||||||
if (at() > i || at() == QSql::AfterLastRow)
|
|
||||||
return false;
|
|
||||||
while(at() < i - 1) {
|
|
||||||
if (!gotoNext(d->cache, -1))
|
|
||||||
return false;
|
|
||||||
setAt(at() + 1);
|
|
||||||
}
|
|
||||||
if (!gotoNext(d->cache, 0))
|
|
||||||
return false;
|
|
||||||
setAt(at() + 1);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (d->canSeek(i)) {
|
|
||||||
setAt(i);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (d->rowCacheEnd > 0)
|
|
||||||
setAt(d->cacheCount());
|
|
||||||
while (at() < i + 1) {
|
|
||||||
if (!cacheNext()) {
|
|
||||||
if (d->canSeek(i))
|
|
||||||
break;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
setAt(i);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ClementineSqlCachedResult::fetchNext()
|
|
||||||
{
|
|
||||||
if (d->canSeek(at() + 1)) {
|
|
||||||
setAt(at() + 1);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return cacheNext();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ClementineSqlCachedResult::fetchPrevious()
|
|
||||||
{
|
|
||||||
return fetch(at() - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ClementineSqlCachedResult::fetchFirst()
|
|
||||||
{
|
|
||||||
if (d->forwardOnly && at() != QSql::BeforeFirstRow) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (d->canSeek(0)) {
|
|
||||||
setAt(0);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return cacheNext();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ClementineSqlCachedResult::fetchLast()
|
|
||||||
{
|
|
||||||
if (d->atEnd) {
|
|
||||||
if (d->forwardOnly)
|
|
||||||
return false;
|
|
||||||
else
|
|
||||||
return fetch(d->cacheCount() - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
int i = at();
|
|
||||||
while (fetchNext())
|
|
||||||
++i; /* brute force */
|
|
||||||
if (d->forwardOnly && at() == QSql::AfterLastRow) {
|
|
||||||
setAt(i);
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return fetch(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariant ClementineSqlCachedResult::data(int i)
|
|
||||||
{
|
|
||||||
int idx = d->forwardOnly ? i : at() * d->colCount + i;
|
|
||||||
if (i >= d->colCount || i < 0 || at() < 0 || idx >= d->rowCacheEnd)
|
|
||||||
return QVariant();
|
|
||||||
|
|
||||||
return d->cache.at(idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ClementineSqlCachedResult::isNull(int i)
|
|
||||||
{
|
|
||||||
int idx = d->forwardOnly ? i : at() * d->colCount + i;
|
|
||||||
if (i > d->colCount || i < 0 || at() < 0 || idx >= d->rowCacheEnd)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return d->cache.at(idx).isNull();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClementineSqlCachedResult::cleanup()
|
|
||||||
{
|
|
||||||
setAt(QSql::BeforeFirstRow);
|
|
||||||
setActive(false);
|
|
||||||
d->cleanup();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClementineSqlCachedResult::clearValues()
|
|
||||||
{
|
|
||||||
setAt(QSql::BeforeFirstRow);
|
|
||||||
d->rowCacheEnd = 0;
|
|
||||||
d->atEnd = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ClementineSqlCachedResult::cacheNext()
|
|
||||||
{
|
|
||||||
if (d->atEnd)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if(isForwardOnly()) {
|
|
||||||
d->cache.clear();
|
|
||||||
d->cache.resize(d->colCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!gotoNext(d->cache, d->nextIndex())) {
|
|
||||||
d->revertLast();
|
|
||||||
d->atEnd = true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
setAt(at() + 1);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ClementineSqlCachedResult::colCount() const
|
|
||||||
{
|
|
||||||
return d->colCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
ClementineSqlCachedResult::ValueCache &ClementineSqlCachedResult::cache()
|
|
||||||
{
|
|
||||||
return d->cache;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClementineSqlCachedResult::virtual_hook(int id, void *data)
|
|
||||||
{
|
|
||||||
QSqlResult::virtual_hook(id, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClementineSqlCachedResult::detachFromResultSet()
|
|
||||||
{
|
|
||||||
cleanup();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClementineSqlCachedResult::setNumericalPrecisionPolicy(QSql::NumericalPrecisionPolicy policy)
|
|
||||||
{
|
|
||||||
QSqlResult::setNumericalPrecisionPolicy(policy);
|
|
||||||
cleanup();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
|
||||||
102
3rdparty/qsqlite/sqlcachedresult.h
vendored
102
3rdparty/qsqlite/sqlcachedresult.h
vendored
@@ -1,102 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
**
|
|
||||||
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
|
|
||||||
** Contact: http://www.qt-project.org/legal
|
|
||||||
**
|
|
||||||
** This file is part of the QtSql module of the Qt Toolkit.
|
|
||||||
**
|
|
||||||
** $QT_BEGIN_LICENSE:LGPL$
|
|
||||||
** Commercial License Usage
|
|
||||||
** Licensees holding valid commercial Qt licenses may use this file in
|
|
||||||
** accordance with the commercial license agreement provided with the
|
|
||||||
** Software or, alternatively, in accordance with the terms contained in
|
|
||||||
** a written agreement between you and Digia. For licensing terms and
|
|
||||||
** conditions see http://qt.digia.com/licensing. For further information
|
|
||||||
** use the contact form at http://qt.digia.com/contact-us.
|
|
||||||
**
|
|
||||||
** GNU Lesser General Public License Usage
|
|
||||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
|
||||||
** General Public License version 2.1 as published by the Free Software
|
|
||||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
|
||||||
** packaging of this file. Please review the following information to
|
|
||||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
|
||||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
|
||||||
**
|
|
||||||
** In addition, as a special exception, Digia gives you certain additional
|
|
||||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
|
||||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
||||||
**
|
|
||||||
** GNU General Public License Usage
|
|
||||||
** Alternatively, this file may be used under the terms of the GNU
|
|
||||||
** General Public License version 3.0 as published by the Free Software
|
|
||||||
** Foundation and appearing in the file LICENSE.GPL included in the
|
|
||||||
** packaging of this file. Please review the following information to
|
|
||||||
** ensure the GNU General Public License version 3.0 requirements will be
|
|
||||||
** met: http://www.gnu.org/copyleft/gpl.html.
|
|
||||||
**
|
|
||||||
**
|
|
||||||
** $QT_END_LICENSE$
|
|
||||||
**
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#ifndef QSQLCACHEDRESULT_P_H
|
|
||||||
#define QSQLCACHEDRESULT_P_H
|
|
||||||
|
|
||||||
//
|
|
||||||
// W A R N I N G
|
|
||||||
// -------------
|
|
||||||
//
|
|
||||||
// This file is not part of the Qt API. It exists for the convenience
|
|
||||||
// of other Qt classes. This header file may change from version to
|
|
||||||
// version without notice, or even be removed.
|
|
||||||
//
|
|
||||||
// We mean it.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include <QtSql/qsqlresult.h>
|
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
|
||||||
|
|
||||||
class QVariant;
|
|
||||||
template <typename T> class QVector;
|
|
||||||
|
|
||||||
class ClementineSqlCachedResultPrivate;
|
|
||||||
|
|
||||||
class ClementineSqlCachedResult: public QSqlResult
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ~ClementineSqlCachedResult();
|
|
||||||
|
|
||||||
typedef QVector<QVariant> ValueCache;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
ClementineSqlCachedResult(const QSqlDriver * db);
|
|
||||||
|
|
||||||
void init(int colCount);
|
|
||||||
void cleanup();
|
|
||||||
void clearValues();
|
|
||||||
|
|
||||||
virtual bool gotoNext(ValueCache &values, int index) = 0;
|
|
||||||
|
|
||||||
QVariant data(int i);
|
|
||||||
bool isNull(int i);
|
|
||||||
bool fetch(int i);
|
|
||||||
bool fetchNext();
|
|
||||||
bool fetchPrevious();
|
|
||||||
bool fetchFirst();
|
|
||||||
bool fetchLast();
|
|
||||||
|
|
||||||
int colCount() const;
|
|
||||||
ValueCache &cache();
|
|
||||||
|
|
||||||
void virtual_hook(int id, void *data);
|
|
||||||
void detachFromResultSet();
|
|
||||||
void setNumericalPrecisionPolicy(QSql::NumericalPrecisionPolicy policy);
|
|
||||||
private:
|
|
||||||
bool cacheNext();
|
|
||||||
ClementineSqlCachedResultPrivate *d;
|
|
||||||
};
|
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
|
||||||
|
|
||||||
#endif // QSQLCACHEDRESULT_P_H
|
|
||||||
21
3rdparty/qtsingleapplication/qtlocalpeer.cpp
vendored
21
3rdparty/qtsingleapplication/qtlocalpeer.cpp
vendored
@@ -39,14 +39,27 @@
|
|||||||
|
|
||||||
|
|
||||||
#include "qtlocalpeer.h"
|
#include "qtlocalpeer.h"
|
||||||
#include <QCoreApplication>
|
|
||||||
#include <QTime>
|
|
||||||
#include <QDataStream>
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <QtGlobal>
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QAbstractSocket>
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QChar>
|
||||||
|
#include <QDataStream>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QIODevice>
|
||||||
|
#include <QLocalServer>
|
||||||
|
#include <QLocalSocket>
|
||||||
|
#include <QRegExp>
|
||||||
|
|
||||||
#if defined(Q_OS_WIN)
|
#if defined(Q_OS_WIN)
|
||||||
#include <QLibrary>
|
|
||||||
#include <qt_windows.h>
|
#include <qt_windows.h>
|
||||||
|
#include <QLibrary>
|
||||||
|
|
||||||
typedef BOOL(WINAPI*PProcessIdToSessionId)(DWORD,DWORD*);
|
typedef BOOL(WINAPI*PProcessIdToSessionId)(DWORD,DWORD*);
|
||||||
static PProcessIdToSessionId pProcessIdToSessionId = 0;
|
static PProcessIdToSessionId pProcessIdToSessionId = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
4
3rdparty/qtsingleapplication/qtlocalpeer.h
vendored
4
3rdparty/qtsingleapplication/qtlocalpeer.h
vendored
@@ -40,9 +40,9 @@
|
|||||||
#ifndef QTLOCALPEER_H
|
#ifndef QTLOCALPEER_H
|
||||||
#define QTLOCALPEER_H
|
#define QTLOCALPEER_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QString>
|
||||||
#include <QLocalServer>
|
#include <QLocalServer>
|
||||||
#include <QLocalSocket>
|
|
||||||
#include <QDir>
|
|
||||||
|
|
||||||
#include "qtlockedfile.h"
|
#include "qtlockedfile.h"
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,9 @@
|
|||||||
**
|
**
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include <QFile>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
#include "qtlockedfile.h"
|
#include "qtlockedfile.h"
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|||||||
2
3rdparty/qtsingleapplication/qtlockedfile.h
vendored
2
3rdparty/qtsingleapplication/qtlockedfile.h
vendored
@@ -42,7 +42,7 @@
|
|||||||
|
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
#include <QtCore/QVector>
|
#include <QVector>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(Q_WS_WIN) || defined(Q_OS_WIN)
|
#if defined(Q_WS_WIN) || defined(Q_OS_WIN)
|
||||||
|
|||||||
@@ -37,9 +37,10 @@
|
|||||||
**
|
**
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include <QFileInfo>
|
||||||
|
|
||||||
#include "qtlockedfile.h"
|
#include "qtlockedfile.h"
|
||||||
#include <qt_windows.h>
|
#include <qt_windows.h>
|
||||||
#include <QFileInfo>
|
|
||||||
|
|
||||||
#define MUTEX_PREFIX "QtLockedFile mutex "
|
#define MUTEX_PREFIX "QtLockedFile mutex "
|
||||||
// Maximum number of concurrent read locks. Must not be greater than MAXIMUM_WAIT_OBJECTS
|
// Maximum number of concurrent read locks. Must not be greater than MAXIMUM_WAIT_OBJECTS
|
||||||
|
|||||||
@@ -39,8 +39,12 @@
|
|||||||
|
|
||||||
|
|
||||||
#include "qtsingleapplication.h"
|
#include "qtsingleapplication.h"
|
||||||
#include "qtlocalpeer.h"
|
|
||||||
|
#include <QApplication>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
#include "qtlocalpeer.h"
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\class QtSingleApplication qtsingleapplication.h
|
\class QtSingleApplication qtsingleapplication.h
|
||||||
|
|||||||
@@ -40,8 +40,11 @@
|
|||||||
#ifndef QTSINGLEAPPLICATION_H
|
#ifndef QTSINGLEAPPLICATION_H
|
||||||
#define QTSINGLEAPPLICATION_H
|
#define QTSINGLEAPPLICATION_H
|
||||||
|
|
||||||
|
#include <QtGlobal>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QWidget>
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
|
#include <QString>
|
||||||
class QtLocalPeer;
|
class QtLocalPeer;
|
||||||
|
|
||||||
#if defined(Q_WS_WIN) || defined(Q_OS_WIN32)
|
#if defined(Q_WS_WIN) || defined(Q_OS_WIN32)
|
||||||
|
|||||||
@@ -37,6 +37,9 @@
|
|||||||
**
|
**
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include <QString>
|
||||||
|
#include <QFlags>
|
||||||
|
|
||||||
#include "qtsinglecoreapplication.h"
|
#include "qtsinglecoreapplication.h"
|
||||||
#include "qtlocalpeer.h"
|
#include "qtlocalpeer.h"
|
||||||
@@ -70,8 +73,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
QtSingleCoreApplication::QtSingleCoreApplication(int &argc, char **argv)
|
QtSingleCoreApplication::QtSingleCoreApplication(int &argc, char **argv)
|
||||||
: QCoreApplication(argc, argv)
|
: QCoreApplication(argc, argv) {
|
||||||
{
|
|
||||||
peer = new QtLocalPeer(this);
|
peer = new QtLocalPeer(this);
|
||||||
connect(peer, SIGNAL(messageReceived(const QString&)), SIGNAL(messageReceived(const QString&)));
|
connect(peer, SIGNAL(messageReceived(const QString&)), SIGNAL(messageReceived(const QString&)));
|
||||||
}
|
}
|
||||||
@@ -83,8 +85,7 @@ QtSingleCoreApplication::QtSingleCoreApplication(int &argc, char **argv)
|
|||||||
QCoreAppliation constructor.
|
QCoreAppliation constructor.
|
||||||
*/
|
*/
|
||||||
QtSingleCoreApplication::QtSingleCoreApplication(const QString &appId, int &argc, char **argv)
|
QtSingleCoreApplication::QtSingleCoreApplication(const QString &appId, int &argc, char **argv)
|
||||||
: QCoreApplication(argc, argv)
|
: QCoreApplication(argc, argv) {
|
||||||
{
|
|
||||||
peer = new QtLocalPeer(this, appId);
|
peer = new QtLocalPeer(this, appId);
|
||||||
connect(peer, SIGNAL(messageReceived(const QString&)), SIGNAL(messageReceived(const QString&)));
|
connect(peer, SIGNAL(messageReceived(const QString&)), SIGNAL(messageReceived(const QString&)));
|
||||||
}
|
}
|
||||||
@@ -101,8 +102,7 @@ QtSingleCoreApplication::QtSingleCoreApplication(const QString &appId, int &argc
|
|||||||
\sa sendMessage()
|
\sa sendMessage()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
bool QtSingleCoreApplication::isRunning()
|
bool QtSingleCoreApplication::isRunning() {
|
||||||
{
|
|
||||||
return peer->isClient();
|
return peer->isClient();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,8 +121,7 @@ bool QtSingleCoreApplication::isRunning()
|
|||||||
\sa isRunning(), messageReceived()
|
\sa isRunning(), messageReceived()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
bool QtSingleCoreApplication::sendMessage(const QString &message, int timeout)
|
bool QtSingleCoreApplication::sendMessage(const QString &message, int timeout) {
|
||||||
{
|
|
||||||
return peer->sendMessage(message, timeout);
|
return peer->sendMessage(message, timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,8 +131,7 @@ bool QtSingleCoreApplication::sendMessage(const QString &message, int timeout)
|
|||||||
identifier will be regarded as instances of the same application.
|
identifier will be regarded as instances of the same application.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
QString QtSingleCoreApplication::id() const
|
QString QtSingleCoreApplication::id() const {
|
||||||
{
|
|
||||||
return peer->applicationId();
|
return peer->applicationId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,6 +41,8 @@
|
|||||||
#define QTSINGLECOREAPPLICATION_H
|
#define QTSINGLECOREAPPLICATION_H
|
||||||
|
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
class QtLocalPeer;
|
class QtLocalPeer;
|
||||||
|
|
||||||
|
|||||||
6
3rdparty/qxt/qxtglobalshortcut.cpp
vendored
6
3rdparty/qxt/qxtglobalshortcut.cpp
vendored
@@ -29,10 +29,14 @@
|
|||||||
** <http://libqxt.org> <foundation@libqxt.org>
|
** <http://libqxt.org> <foundation@libqxt.org>
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
#include "qxtglobalshortcut_p.h"
|
#include <QtGlobal>
|
||||||
#include <QAbstractEventDispatcher>
|
#include <QAbstractEventDispatcher>
|
||||||
|
#include <QHash>
|
||||||
|
#include <QPair>
|
||||||
#include <QtDebug>
|
#include <QtDebug>
|
||||||
|
|
||||||
|
#include "qxtglobalshortcut_p.h"
|
||||||
|
|
||||||
bool QxtGlobalShortcutPrivate::error = false;
|
bool QxtGlobalShortcutPrivate::error = false;
|
||||||
#ifndef Q_WS_MAC
|
#ifndef Q_WS_MAC
|
||||||
int QxtGlobalShortcutPrivate::ref = 0;
|
int QxtGlobalShortcutPrivate::ref = 0;
|
||||||
|
|||||||
5
3rdparty/qxt/qxtglobalshortcut.h
vendored
5
3rdparty/qxt/qxtglobalshortcut.h
vendored
@@ -31,9 +31,12 @@
|
|||||||
|
|
||||||
#define QXTGLOBALSHORTCUT_H
|
#define QXTGLOBALSHORTCUT_H
|
||||||
|
|
||||||
#include "qxtglobal.h"
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QKeySequence>
|
#include <QKeySequence>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
#include "qxtglobal.h"
|
||||||
|
|
||||||
class QxtGlobalShortcutPrivate;
|
class QxtGlobalShortcutPrivate;
|
||||||
|
|
||||||
class QXT_GUI_EXPORT QxtGlobalShortcut : public QObject
|
class QXT_GUI_EXPORT QxtGlobalShortcut : public QObject
|
||||||
|
|||||||
13
3rdparty/qxt/qxtglobalshortcut_x11.cpp
vendored
13
3rdparty/qxt/qxtglobalshortcut_x11.cpp
vendored
@@ -32,12 +32,21 @@
|
|||||||
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
|
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
|
||||||
# include <QX11Info>
|
# include <QX11Info>
|
||||||
#else
|
#else
|
||||||
# include <QApplication>
|
|
||||||
# include <qpa/qplatformnativeinterface.h>
|
# include <qpa/qplatformnativeinterface.h>
|
||||||
# include <xcb/xcb.h>
|
# include <xcb/xcb.h>
|
||||||
|
# include <QApplication>
|
||||||
#endif
|
#endif
|
||||||
#include <QVector>
|
#include <X11/X.h>
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
|
#include <xcb/xproto.h>
|
||||||
|
|
||||||
|
#include <QtGlobal>
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QGuiApplication>
|
||||||
|
#include <QKeySequence>
|
||||||
|
#include <QString>
|
||||||
|
#include <QVector>
|
||||||
|
|
||||||
#include "keymapper_x11.h"
|
#include "keymapper_x11.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|||||||
5
3rdparty/sha2/sha2.cpp
vendored
5
3rdparty/sha2/sha2.cpp
vendored
@@ -31,8 +31,9 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <string.h> /* memcpy()/memset() or bcopy()/bzero() */
|
#include <string.h>
|
||||||
#include <assert.h> /* assert() */
|
#include <assert.h>
|
||||||
|
|
||||||
#include "sha2.h"
|
#include "sha2.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
2
3rdparty/sha2/sha2.h
vendored
2
3rdparty/sha2/sha2.h
vendored
@@ -35,6 +35,8 @@
|
|||||||
#ifndef __STRAWBERRY_SHA2_H__
|
#ifndef __STRAWBERRY_SHA2_H__
|
||||||
#define __STRAWBERRY_SHA2_H__
|
#define __STRAWBERRY_SHA2_H__
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Import u_intXX_t size_t type definitions from system headers. You
|
* Import u_intXX_t size_t type definitions from system headers. You
|
||||||
* may need to change this, or define these things yourself in this
|
* may need to change this, or define these things yourself in this
|
||||||
|
|||||||
378
3rdparty/taglib/CMakeLists.txt
vendored
Normal file
378
3rdparty/taglib/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,378 @@
|
|||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-delete-non-virtual-dtor")
|
||||||
|
|
||||||
|
set(TAGLIB_SOVERSION_CURRENT 17)
|
||||||
|
set(TAGLIB_SOVERSION_REVISION 0)
|
||||||
|
set(TAGLIB_SOVERSION_AGE 16)
|
||||||
|
|
||||||
|
math(EXPR TAGLIB_SOVERSION_MAJOR "${TAGLIB_SOVERSION_CURRENT} - ${TAGLIB_SOVERSION_AGE}")
|
||||||
|
math(EXPR TAGLIB_SOVERSION_MINOR "${TAGLIB_SOVERSION_AGE}")
|
||||||
|
math(EXPR TAGLIB_SOVERSION_PATCH "${TAGLIB_SOVERSION_REVISION}")
|
||||||
|
|
||||||
|
include(TestBigEndian)
|
||||||
|
test_big_endian(IS_BIG_ENDIAN)
|
||||||
|
|
||||||
|
if(NOT IS_BIG_ENDIAN)
|
||||||
|
add_definitions(-DSYSTEM_BYTEORDER=1)
|
||||||
|
else()
|
||||||
|
add_definitions(-DSYSTEM_BYTEORDER=2)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
configure_file(taglib_config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/taglib_config.h)
|
||||||
|
|
||||||
|
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||||
|
include_directories(
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/toolkit
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/asf
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/mpeg
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/ogg
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/ogg/flac
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/flac
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/mpc
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/mp4
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/ogg/vorbis
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/ogg/speex
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/ogg/opus
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/mpeg/id3v2
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/mpeg/id3v2/frames
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/mpeg/id3v1
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/ape
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/wavpack
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/trueaudio
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/riff
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/riff/aiff
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/riff/wav
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/mod
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/s3m
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/it
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/xm
|
||||||
|
${CMAKE_SOURCE_DIR}/3rdparty
|
||||||
|
)
|
||||||
|
|
||||||
|
if(ZLIB_FOUND)
|
||||||
|
include_directories(${ZLIB_INCLUDE_DIR})
|
||||||
|
elseif(HAVE_ZLIB_SOURCE)
|
||||||
|
include_directories(${ZLIB_SOURCE})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(tag_HDRS
|
||||||
|
tag.h
|
||||||
|
fileref.h
|
||||||
|
audioproperties.h
|
||||||
|
taglib_export.h
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/taglib_config.h
|
||||||
|
toolkit/taglib.h
|
||||||
|
toolkit/tstring.h
|
||||||
|
toolkit/tlist.h
|
||||||
|
toolkit/tlist.tcc
|
||||||
|
toolkit/tstringlist.h
|
||||||
|
toolkit/tbytevector.h
|
||||||
|
toolkit/tbytevectorlist.h
|
||||||
|
toolkit/tbytevectorstream.h
|
||||||
|
toolkit/tiostream.h
|
||||||
|
toolkit/tfile.h
|
||||||
|
toolkit/tfilestream.h
|
||||||
|
toolkit/tmap.h
|
||||||
|
toolkit/tmap.tcc
|
||||||
|
toolkit/tpropertymap.h
|
||||||
|
toolkit/trefcounter.h
|
||||||
|
toolkit/tdebuglistener.h
|
||||||
|
mpeg/mpegfile.h
|
||||||
|
mpeg/mpegproperties.h
|
||||||
|
mpeg/mpegheader.h
|
||||||
|
mpeg/xingheader.h
|
||||||
|
mpeg/id3v1/id3v1tag.h
|
||||||
|
mpeg/id3v1/id3v1genres.h
|
||||||
|
mpeg/id3v2/id3v2extendedheader.h
|
||||||
|
mpeg/id3v2/id3v2frame.h
|
||||||
|
mpeg/id3v2/id3v2header.h
|
||||||
|
mpeg/id3v2/id3v2synchdata.h
|
||||||
|
mpeg/id3v2/id3v2footer.h
|
||||||
|
mpeg/id3v2/id3v2framefactory.h
|
||||||
|
mpeg/id3v2/id3v2tag.h
|
||||||
|
mpeg/id3v2/frames/attachedpictureframe.h
|
||||||
|
mpeg/id3v2/frames/commentsframe.h
|
||||||
|
mpeg/id3v2/frames/eventtimingcodesframe.h
|
||||||
|
mpeg/id3v2/frames/generalencapsulatedobjectframe.h
|
||||||
|
mpeg/id3v2/frames/ownershipframe.h
|
||||||
|
mpeg/id3v2/frames/popularimeterframe.h
|
||||||
|
mpeg/id3v2/frames/privateframe.h
|
||||||
|
mpeg/id3v2/frames/relativevolumeframe.h
|
||||||
|
mpeg/id3v2/frames/synchronizedlyricsframe.h
|
||||||
|
mpeg/id3v2/frames/textidentificationframe.h
|
||||||
|
mpeg/id3v2/frames/uniquefileidentifierframe.h
|
||||||
|
mpeg/id3v2/frames/unknownframe.h
|
||||||
|
mpeg/id3v2/frames/unsynchronizedlyricsframe.h
|
||||||
|
mpeg/id3v2/frames/urllinkframe.h
|
||||||
|
mpeg/id3v2/frames/chapterframe.h
|
||||||
|
mpeg/id3v2/frames/tableofcontentsframe.h
|
||||||
|
mpeg/id3v2/frames/podcastframe.h
|
||||||
|
ogg/oggfile.h
|
||||||
|
ogg/oggpage.h
|
||||||
|
ogg/oggpageheader.h
|
||||||
|
ogg/xiphcomment.h
|
||||||
|
ogg/vorbis/vorbisfile.h
|
||||||
|
ogg/vorbis/vorbisproperties.h
|
||||||
|
ogg/flac/oggflacfile.h
|
||||||
|
ogg/speex/speexfile.h
|
||||||
|
ogg/speex/speexproperties.h
|
||||||
|
ogg/opus/opusfile.h
|
||||||
|
ogg/opus/opusproperties.h
|
||||||
|
flac/flacfile.h
|
||||||
|
flac/flacpicture.h
|
||||||
|
flac/flacproperties.h
|
||||||
|
flac/flacmetadatablock.h
|
||||||
|
ape/apefile.h
|
||||||
|
ape/apeproperties.h
|
||||||
|
ape/apetag.h
|
||||||
|
ape/apefooter.h
|
||||||
|
ape/apeitem.h
|
||||||
|
mpc/mpcfile.h
|
||||||
|
mpc/mpcproperties.h
|
||||||
|
wavpack/wavpackfile.h
|
||||||
|
wavpack/wavpackproperties.h
|
||||||
|
trueaudio/trueaudiofile.h
|
||||||
|
trueaudio/trueaudioproperties.h
|
||||||
|
riff/rifffile.h
|
||||||
|
riff/aiff/aifffile.h
|
||||||
|
riff/aiff/aiffproperties.h
|
||||||
|
riff/wav/wavfile.h
|
||||||
|
riff/wav/wavproperties.h
|
||||||
|
riff/wav/infotag.h
|
||||||
|
asf/asffile.h
|
||||||
|
asf/asfproperties.h
|
||||||
|
asf/asftag.h
|
||||||
|
asf/asfattribute.h
|
||||||
|
asf/asfpicture.h
|
||||||
|
mp4/mp4file.h
|
||||||
|
mp4/mp4atom.h
|
||||||
|
mp4/mp4tag.h
|
||||||
|
mp4/mp4item.h
|
||||||
|
mp4/mp4properties.h
|
||||||
|
mp4/mp4coverart.h
|
||||||
|
mod/modfilebase.h
|
||||||
|
mod/modfile.h
|
||||||
|
mod/modtag.h
|
||||||
|
mod/modproperties.h
|
||||||
|
it/itfile.h
|
||||||
|
it/itproperties.h
|
||||||
|
s3m/s3mfile.h
|
||||||
|
s3m/s3mproperties.h
|
||||||
|
xm/xmfile.h
|
||||||
|
xm/xmproperties.h
|
||||||
|
)
|
||||||
|
|
||||||
|
set(mpeg_SRCS
|
||||||
|
mpeg/mpegfile.cpp
|
||||||
|
mpeg/mpegproperties.cpp
|
||||||
|
mpeg/mpegheader.cpp
|
||||||
|
mpeg/xingheader.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(id3v1_SRCS
|
||||||
|
mpeg/id3v1/id3v1tag.cpp
|
||||||
|
mpeg/id3v1/id3v1genres.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(id3v2_SRCS
|
||||||
|
mpeg/id3v2/id3v2framefactory.cpp
|
||||||
|
mpeg/id3v2/id3v2synchdata.cpp
|
||||||
|
mpeg/id3v2/id3v2tag.cpp
|
||||||
|
mpeg/id3v2/id3v2header.cpp
|
||||||
|
mpeg/id3v2/id3v2frame.cpp
|
||||||
|
mpeg/id3v2/id3v2footer.cpp
|
||||||
|
mpeg/id3v2/id3v2extendedheader.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(frames_SRCS
|
||||||
|
mpeg/id3v2/frames/attachedpictureframe.cpp
|
||||||
|
mpeg/id3v2/frames/commentsframe.cpp
|
||||||
|
mpeg/id3v2/frames/eventtimingcodesframe.cpp
|
||||||
|
mpeg/id3v2/frames/generalencapsulatedobjectframe.cpp
|
||||||
|
mpeg/id3v2/frames/ownershipframe.cpp
|
||||||
|
mpeg/id3v2/frames/popularimeterframe.cpp
|
||||||
|
mpeg/id3v2/frames/privateframe.cpp
|
||||||
|
mpeg/id3v2/frames/relativevolumeframe.cpp
|
||||||
|
mpeg/id3v2/frames/synchronizedlyricsframe.cpp
|
||||||
|
mpeg/id3v2/frames/textidentificationframe.cpp
|
||||||
|
mpeg/id3v2/frames/uniquefileidentifierframe.cpp
|
||||||
|
mpeg/id3v2/frames/unknownframe.cpp
|
||||||
|
mpeg/id3v2/frames/unsynchronizedlyricsframe.cpp
|
||||||
|
mpeg/id3v2/frames/urllinkframe.cpp
|
||||||
|
mpeg/id3v2/frames/chapterframe.cpp
|
||||||
|
mpeg/id3v2/frames/tableofcontentsframe.cpp
|
||||||
|
mpeg/id3v2/frames/podcastframe.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(ogg_SRCS
|
||||||
|
ogg/oggfile.cpp
|
||||||
|
ogg/oggpage.cpp
|
||||||
|
ogg/oggpageheader.cpp
|
||||||
|
ogg/xiphcomment.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(vorbis_SRCS
|
||||||
|
ogg/vorbis/vorbisfile.cpp
|
||||||
|
ogg/vorbis/vorbisproperties.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(flacs_SRCS
|
||||||
|
flac/flacfile.cpp
|
||||||
|
flac/flacpicture.cpp
|
||||||
|
flac/flacproperties.cpp
|
||||||
|
flac/flacmetadatablock.cpp
|
||||||
|
flac/flacunknownmetadatablock.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(oggflacs_SRCS
|
||||||
|
ogg/flac/oggflacfile.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(mpc_SRCS
|
||||||
|
mpc/mpcfile.cpp
|
||||||
|
mpc/mpcproperties.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(mp4_SRCS
|
||||||
|
mp4/mp4file.cpp
|
||||||
|
mp4/mp4atom.cpp
|
||||||
|
mp4/mp4tag.cpp
|
||||||
|
mp4/mp4item.cpp
|
||||||
|
mp4/mp4properties.cpp
|
||||||
|
mp4/mp4coverart.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(ape_SRCS
|
||||||
|
ape/apetag.cpp
|
||||||
|
ape/apefooter.cpp
|
||||||
|
ape/apeitem.cpp
|
||||||
|
ape/apefile.cpp
|
||||||
|
ape/apeproperties.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(wavpack_SRCS
|
||||||
|
wavpack/wavpackfile.cpp
|
||||||
|
wavpack/wavpackproperties.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(speex_SRCS
|
||||||
|
ogg/speex/speexfile.cpp
|
||||||
|
ogg/speex/speexproperties.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(opus_SRCS
|
||||||
|
ogg/opus/opusfile.cpp
|
||||||
|
ogg/opus/opusproperties.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(trueaudio_SRCS
|
||||||
|
trueaudio/trueaudiofile.cpp
|
||||||
|
trueaudio/trueaudioproperties.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(asf_SRCS
|
||||||
|
asf/asftag.cpp
|
||||||
|
asf/asffile.cpp
|
||||||
|
asf/asfproperties.cpp
|
||||||
|
asf/asfattribute.cpp
|
||||||
|
asf/asfpicture.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(riff_SRCS
|
||||||
|
riff/rifffile.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(aiff_SRCS
|
||||||
|
riff/aiff/aifffile.cpp
|
||||||
|
riff/aiff/aiffproperties.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(wav_SRCS
|
||||||
|
riff/wav/wavfile.cpp
|
||||||
|
riff/wav/wavproperties.cpp
|
||||||
|
riff/wav/infotag.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(mod_SRCS
|
||||||
|
mod/modfilebase.cpp
|
||||||
|
mod/modfile.cpp
|
||||||
|
mod/modtag.cpp
|
||||||
|
mod/modproperties.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(s3m_SRCS
|
||||||
|
s3m/s3mfile.cpp
|
||||||
|
s3m/s3mproperties.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(it_SRCS
|
||||||
|
it/itfile.cpp
|
||||||
|
it/itproperties.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(xm_SRCS
|
||||||
|
xm/xmfile.cpp
|
||||||
|
xm/xmproperties.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(toolkit_SRCS
|
||||||
|
toolkit/tstring.cpp
|
||||||
|
toolkit/tstringlist.cpp
|
||||||
|
toolkit/tbytevector.cpp
|
||||||
|
toolkit/tbytevectorlist.cpp
|
||||||
|
toolkit/tbytevectorstream.cpp
|
||||||
|
toolkit/tiostream.cpp
|
||||||
|
toolkit/tfile.cpp
|
||||||
|
toolkit/tfilestream.cpp
|
||||||
|
toolkit/tdebug.cpp
|
||||||
|
toolkit/tpropertymap.cpp
|
||||||
|
toolkit/trefcounter.cpp
|
||||||
|
toolkit/tdebuglistener.cpp
|
||||||
|
toolkit/tzlib.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
if(HAVE_ZLIB_SOURCE)
|
||||||
|
set(zlib_SRCS
|
||||||
|
${ZLIB_SOURCE}/adler32.c
|
||||||
|
${ZLIB_SOURCE}/crc32.c
|
||||||
|
${ZLIB_SOURCE}/inffast.c
|
||||||
|
${ZLIB_SOURCE}/inflate.c
|
||||||
|
${ZLIB_SOURCE}/inftrees.c
|
||||||
|
${ZLIB_SOURCE}/zutil.c
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(tag_LIB_SRCS
|
||||||
|
${mpeg_SRCS} ${id3v1_SRCS} ${id3v2_SRCS} ${frames_SRCS} ${ogg_SRCS}
|
||||||
|
${vorbis_SRCS} ${oggflacs_SRCS} ${mpc_SRCS} ${ape_SRCS} ${toolkit_SRCS} ${flacs_SRCS}
|
||||||
|
${wavpack_SRCS} ${speex_SRCS} ${trueaudio_SRCS} ${riff_SRCS} ${aiff_SRCS} ${wav_SRCS}
|
||||||
|
${asf_SRCS} ${mp4_SRCS} ${mod_SRCS} ${s3m_SRCS} ${it_SRCS} ${xm_SRCS} ${opus_SRCS}
|
||||||
|
${zlib_SRCS}
|
||||||
|
tag.cpp
|
||||||
|
tagunion.cpp
|
||||||
|
fileref.cpp
|
||||||
|
audioproperties.cpp
|
||||||
|
tagutils.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
add_library(tag STATIC ${tag_LIB_SRCS} ${tag_HDRS})
|
||||||
|
|
||||||
|
if(HAVE_ZLIB AND NOT HAVE_ZLIB_SOURCE)
|
||||||
|
target_link_libraries(tag ${ZLIB_LIBRARIES})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set_target_properties(tag PROPERTIES
|
||||||
|
VERSION ${TAGLIB_SOVERSION_MAJOR}.${TAGLIB_SOVERSION_MINOR}.${TAGLIB_SOVERSION_PATCH}
|
||||||
|
SOVERSION ${TAGLIB_SOVERSION_MAJOR}
|
||||||
|
DEFINE_SYMBOL MAKE_TAGLIB_LIB
|
||||||
|
LINK_INTERFACE_LIBRARIES ""
|
||||||
|
)
|
||||||
|
|
||||||
|
foreach(header ${tag_HDRS})
|
||||||
|
get_filename_component(header_name ${header} NAME)
|
||||||
|
configure_file(
|
||||||
|
"${header}"
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}/headers/taglib/${header_name}"
|
||||||
|
COPYONLY
|
||||||
|
)
|
||||||
|
endforeach()
|
||||||
|
|
||||||
@@ -1,15 +1,5 @@
|
|||||||
GNU LESSER GENERAL PUBLIC LICENSE
|
GNU LESSER GENERAL PUBLIC LICENSE
|
||||||
|
Version 2.1, February 1999
|
||||||
The Qt GUI Toolkit is Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
|
||||||
Contact: Nokia Corporation (qt-info@nokia.com)
|
|
||||||
|
|
||||||
You may use, distribute and copy the Qt GUI Toolkit under the terms of
|
|
||||||
GNU Lesser General Public License version 2.1, which is displayed below.
|
|
||||||
|
|
||||||
-------------------------------------------------------------------------
|
|
||||||
|
|
||||||
GNU LESSER GENERAL PUBLIC LICENSE
|
|
||||||
Version 2.1, February 1999
|
|
||||||
|
|
||||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
@@ -20,7 +10,7 @@
|
|||||||
as the successor of the GNU Library Public License, version 2, hence
|
as the successor of the GNU Library Public License, version 2, hence
|
||||||
the version number 2.1.]
|
the version number 2.1.]
|
||||||
|
|
||||||
Preamble
|
Preamble
|
||||||
|
|
||||||
The licenses for most software are designed to take away your
|
The licenses for most software are designed to take away your
|
||||||
freedom to share and change it. By contrast, the GNU General Public
|
freedom to share and change it. By contrast, the GNU General Public
|
||||||
@@ -122,7 +112,7 @@ modification follow. Pay close attention to the difference between a
|
|||||||
former contains code derived from the library, whereas the latter must
|
former contains code derived from the library, whereas the latter must
|
||||||
be combined with the library in order to run.
|
be combined with the library in order to run.
|
||||||
|
|
||||||
GNU LESSER GENERAL PUBLIC LICENSE
|
GNU LESSER GENERAL PUBLIC LICENSE
|
||||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
0. This License Agreement applies to any software library or other
|
0. This License Agreement applies to any software library or other
|
||||||
@@ -442,7 +432,7 @@ decision will be guided by the two goals of preserving the free status
|
|||||||
of all derivatives of our free software and of promoting the sharing
|
of all derivatives of our free software and of promoting the sharing
|
||||||
and reuse of software generally.
|
and reuse of software generally.
|
||||||
|
|
||||||
NO WARRANTY
|
NO WARRANTY
|
||||||
|
|
||||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||||
@@ -465,7 +455,7 @@ FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
|||||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||||
DAMAGES.
|
DAMAGES.
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
How to Apply These Terms to Your New Libraries
|
How to Apply These Terms to Your New Libraries
|
||||||
|
|
||||||
@@ -510,5 +500,3 @@ necessary. Here is a sample; alter the names:
|
|||||||
Ty Coon, President of Vice
|
Ty Coon, President of Vice
|
||||||
|
|
||||||
That's all there is to it!
|
That's all there is to it!
|
||||||
|
|
||||||
|
|
||||||
170
3rdparty/taglib/ape/ape-tag-format.txt
vendored
Normal file
170
3rdparty/taglib/ape/ape-tag-format.txt
vendored
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
================================================================================
|
||||||
|
= APE Tag Specification, Version 2.000
|
||||||
|
================================================================================
|
||||||
|
|
||||||
|
Original Content (C) 2004, Frank Klemm <frank.klemm@elster.offl.uni-jena.de>
|
||||||
|
Formatting / Editing (C) 2004, Scott Wheeler <wheeler@kde.org>
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
= Contents
|
||||||
|
================================================================================
|
||||||
|
|
||||||
|
1 - APE Tag General Structure
|
||||||
|
2 - APE Tag Header / Footer Format
|
||||||
|
3 - APE Tag Flags
|
||||||
|
4 - APE Tag Item Format
|
||||||
|
5 - APE Tag Item Supported Keys
|
||||||
|
6 - APE Tag Item Content
|
||||||
|
7 - Data Types
|
||||||
|
7.1 - Data Types / UTF-8
|
||||||
|
7.2 - Data Types / Dates
|
||||||
|
7.3 - Data Types / Timestamps
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
= 1 - APE Tag General Structure
|
||||||
|
================================================================================
|
||||||
|
|
||||||
|
Member of Basic Components of SV8 Stream Note:
|
||||||
|
|
||||||
|
It is strongly recommended that the data size be stored in the tags. The size
|
||||||
|
should normally be in the roughly one kilobyte, never more than 8 kilobytes.
|
||||||
|
|
||||||
|
Larger data should be stored externally using link entries. Linked data is much
|
||||||
|
easier to process by normal programs, so for instance JPEG data should not be
|
||||||
|
included inside the audio file.
|
||||||
|
|
||||||
|
APE Tag Version 2.000 (with header, recommended):
|
||||||
|
|
||||||
|
/================================\
|
||||||
|
| APE Tag Header | 32 bytes |
|
||||||
|
|-------------------|------------|
|
||||||
|
| APE Tag Item 1 | > 10 bytes |
|
||||||
|
| APE Tag Item 2 | > 10 bytes |
|
||||||
|
| APE Tag Item n-1 | > 10 bytes |
|
||||||
|
| APE Tag Item n | > 10 bytes |
|
||||||
|
|-------------------|------------|
|
||||||
|
| APE Tag Footer | 32 bytes |
|
||||||
|
\================================/
|
||||||
|
|
||||||
|
|
||||||
|
APE tag items should be sorted ascending by size. When streaming, parts of the
|
||||||
|
APE tag may be dropped to reduce the danger of drop outs between tracks. This
|
||||||
|
is not required, but is strongly recommended. It would be desirable for the i
|
||||||
|
tems to be sorted by importance / size, but this is not feasible. This
|
||||||
|
convention should only be broken when adding less important small items and it
|
||||||
|
is not desirable to rewrite the entire tag. An APE tag at the end of a file
|
||||||
|
(the recommended location) must have at least a footer; an APE tag at the
|
||||||
|
beginning of a file (strongly discouraged) must have at least a header.
|
||||||
|
|
||||||
|
APE Tag Version 1.000 (without header, deprecated)
|
||||||
|
|
||||||
|
/================================\
|
||||||
|
| APE Tag Item 1 | > 10 bytes |
|
||||||
|
| APE Tag Item 2 | > 10 bytes |
|
||||||
|
| APE Tag Item n-1 | > 10 bytes |
|
||||||
|
| APE Tag Item n | > 10 bytes |
|
||||||
|
|-------------------|------------|
|
||||||
|
| APE Tag Footer | 32 bytes |
|
||||||
|
\================================/
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
= 2 - APE Tag Header / Footer Format
|
||||||
|
================================================================================
|
||||||
|
|
||||||
|
Contains number, length and attributes of all tag items
|
||||||
|
|
||||||
|
Header and Footer are different in 1 bit in the Tags Flags to distinguish
|
||||||
|
between them.
|
||||||
|
|
||||||
|
Member of APE Tag 2.0
|
||||||
|
|
||||||
|
/===========================================================================\
|
||||||
|
| Preamble | 8 bytes | { 'A', 'P', 'E', 'T', 'A', 'G', 'E', 'X' } |
|
||||||
|
|----------------|---------|------------------------------------------------|
|
||||||
|
| Version Number | 4 bytes | 1000 = Version 1.000, 2000 = Version 2.000 |
|
||||||
|
|----------------|---------|------------------------------------------------|
|
||||||
|
| Tag Size | 4 bytes | Tag size in bytes including footer and all tag |
|
||||||
|
| | | items excluding the header (for 1.000 |
|
||||||
|
| | | compatibility) |
|
||||||
|
|----------------|---------|------------------------------------------------|
|
||||||
|
| Item Count | 4 bytes | Number of items in the tag |
|
||||||
|
|----------------|---------|------------------------------------------------|
|
||||||
|
| Tag Flags | 4 bytes | Global flags |
|
||||||
|
|----------------|---------|------------------------------------------------|
|
||||||
|
| Reserved | 8 bytes | Must be zeroed |
|
||||||
|
\===========================================================================/
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
= 3 - APE Tag Flags
|
||||||
|
================================================================================
|
||||||
|
|
||||||
|
The general flag structure for either items or headers / footers is the same.
|
||||||
|
Bits 31, 30 and 29 are specific to headers / footers, whereas 2 through 0 are
|
||||||
|
item specific.
|
||||||
|
|
||||||
|
Note: APE Tags from Version 1.0 do not use any of the following. All flags in
|
||||||
|
that version are zeroed and ignored when reading.
|
||||||
|
|
||||||
|
/=================================================================\
|
||||||
|
| Contains Header | Bit 31 | 1 - has header | 0 - no header |
|
||||||
|
|-----------------|-------------|---------------------------------|
|
||||||
|
| Contains Footer | Bit 30 | 1 - has footer | 0 - no footer |
|
||||||
|
|-----------------|-------------|---------------------------------|
|
||||||
|
| Is Header | Bit 29 | 1 - is header | 0 - is footer |
|
||||||
|
|-----------------|-------------|---------------------------------|
|
||||||
|
| Undefined | Bits 28 - 3 | Undefined, must be zeroed |
|
||||||
|
|-----------------|-------------|---------------------------------|
|
||||||
|
| Encoding | Bits 2 - 1 | 00 - UTF-8 |
|
||||||
|
| | | 01 - Binary Data * |
|
||||||
|
| | | 10 - External Reference ** |
|
||||||
|
| | | 11 - Reserved |
|
||||||
|
|-----------------|-------------|---------------------------------|
|
||||||
|
| Read Only | Bit 0 | 1 - read only | 0 - read/write |
|
||||||
|
\=================================================================/
|
||||||
|
|
||||||
|
(*) Should be ignored by tools for editing text values
|
||||||
|
(**) Allowed external reference formats:
|
||||||
|
- http://host/directory/filename.ext
|
||||||
|
- ftp://host/directory/filename.ext
|
||||||
|
- filename.ext
|
||||||
|
- /directory/filename.ext
|
||||||
|
- DRIVE:/directory/filename.ext
|
||||||
|
|
||||||
|
Note: External references are also UTF-8 encoded.
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
= 4 - APE Tag Item Format
|
||||||
|
================================================================================
|
||||||
|
|
||||||
|
APE Tag Items are stored as key-value pairs. APE Tags Item Key are case
|
||||||
|
sensitive, however it is illegal to use keys which only differ in case and
|
||||||
|
it is recommended that tag reading not be case sensitive.
|
||||||
|
|
||||||
|
Every key can only occur (at most) once. It is not possible to repeat a key
|
||||||
|
to signify updated contents.
|
||||||
|
|
||||||
|
Tags can be partially or completely repeated in the streaming format. This
|
||||||
|
makes it possible to display an artist and / or title if it was missed at the
|
||||||
|
beginning of the stream. It is recommended that the important information like
|
||||||
|
artist, album and title should occur approximately every 2 minutes in the
|
||||||
|
stream and again 5 to 10 seconds before the end. However, care should be tak
|
||||||
|
en not to replicate this information too often or during passages with high
|
||||||
|
bitrate demands to avoid unnecessary drop-outs.
|
||||||
|
|
||||||
|
/==============================================================================\
|
||||||
|
| Content Size | 4 bytes | Length of the value in bytes |
|
||||||
|
|----------------|---------------|---------------------------------------------|
|
||||||
|
| Flags | 4 bytes | Item flags |
|
||||||
|
|----------------|---------------|---------------------------------------------|
|
||||||
|
| Key | 2 - 255 bytes | Item key |
|
||||||
|
|----------------|---------------|---------------------------------------------|
|
||||||
|
| Key Terminator | 1 byte | Null byte that indicates the end of the key |
|
||||||
|
|----------------|---------------|---------------------------------------------|
|
||||||
|
| Value | variable | Content (formatted according to the flags) |
|
||||||
|
\==============================================================================/
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
|
||||||
|
Sections 5 - 7 haven't yet been converted from:
|
||||||
|
|
||||||
|
http://www.personal.uni-jena.de/~pfk/mpp/sv8/apetag.html
|
||||||
314
3rdparty/taglib/ape/apefile.cpp
vendored
Normal file
314
3rdparty/taglib/ape/apefile.cpp
vendored
Normal file
@@ -0,0 +1,314 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
copyright : (C) 2010 by Alex Novichkov
|
||||||
|
email : novichko@atnet.ru
|
||||||
|
|
||||||
|
copyright : (C) 2006 by Lukáš Lalinský
|
||||||
|
email : lalinsky@gmail.com
|
||||||
|
(original WavPack implementation)
|
||||||
|
|
||||||
|
copyright : (C) 2004 by Allan Sandfeld Jensen
|
||||||
|
email : kde@carewolf.org
|
||||||
|
(original MPC implementation)
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include <tbytevector.h>
|
||||||
|
#include <tstring.h>
|
||||||
|
#include <tdebug.h>
|
||||||
|
#include <tagunion.h>
|
||||||
|
#include <id3v1tag.h>
|
||||||
|
#include <id3v2header.h>
|
||||||
|
#include <tpropertymap.h>
|
||||||
|
#include <tagutils.h>
|
||||||
|
|
||||||
|
#include "apefile.h"
|
||||||
|
#include "apetag.h"
|
||||||
|
#include "apefooter.h"
|
||||||
|
|
||||||
|
using namespace TagLib;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
enum { ApeAPEIndex = 0, ApeID3v1Index = 1 };
|
||||||
|
}
|
||||||
|
|
||||||
|
class APE::File::FilePrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FilePrivate() :
|
||||||
|
APELocation(-1),
|
||||||
|
APESize(0),
|
||||||
|
ID3v1Location(-1),
|
||||||
|
ID3v2Header(0),
|
||||||
|
ID3v2Location(-1),
|
||||||
|
ID3v2Size(0),
|
||||||
|
properties(0) {}
|
||||||
|
|
||||||
|
~FilePrivate()
|
||||||
|
{
|
||||||
|
delete ID3v2Header;
|
||||||
|
delete properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
long APELocation;
|
||||||
|
long APESize;
|
||||||
|
|
||||||
|
long ID3v1Location;
|
||||||
|
|
||||||
|
ID3v2::Header *ID3v2Header;
|
||||||
|
long ID3v2Location;
|
||||||
|
long ID3v2Size;
|
||||||
|
|
||||||
|
TagUnion tag;
|
||||||
|
|
||||||
|
Properties *properties;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// static members
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
bool APE::File::isSupported(IOStream *stream)
|
||||||
|
{
|
||||||
|
// An APE file has an ID "MAC " somewhere. An ID3v2 tag may precede.
|
||||||
|
|
||||||
|
const ByteVector buffer = Utils::readHeader(stream, bufferSize(), true);
|
||||||
|
return (buffer.find("MAC ") >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// public members
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
APE::File::File(FileName file, bool readProperties, Properties::ReadStyle) :
|
||||||
|
TagLib::File(file),
|
||||||
|
d(new FilePrivate())
|
||||||
|
{
|
||||||
|
if(isOpen())
|
||||||
|
read(readProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
APE::File::File(IOStream *stream, bool readProperties, Properties::ReadStyle) :
|
||||||
|
TagLib::File(stream),
|
||||||
|
d(new FilePrivate())
|
||||||
|
{
|
||||||
|
if(isOpen())
|
||||||
|
read(readProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
APE::File::~File()
|
||||||
|
{
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
TagLib::Tag *APE::File::tag() const
|
||||||
|
{
|
||||||
|
return &d->tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyMap APE::File::properties() const
|
||||||
|
{
|
||||||
|
return d->tag.properties();
|
||||||
|
}
|
||||||
|
|
||||||
|
void APE::File::removeUnsupportedProperties(const StringList &properties)
|
||||||
|
{
|
||||||
|
d->tag.removeUnsupportedProperties(properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyMap APE::File::setProperties(const PropertyMap &properties)
|
||||||
|
{
|
||||||
|
if(ID3v1Tag())
|
||||||
|
ID3v1Tag()->setProperties(properties);
|
||||||
|
|
||||||
|
return APETag(true)->setProperties(properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
APE::Properties *APE::File::audioProperties() const
|
||||||
|
{
|
||||||
|
return d->properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool APE::File::save()
|
||||||
|
{
|
||||||
|
if(readOnly()) {
|
||||||
|
debug("APE::File::save() -- File is read only.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update ID3v1 tag
|
||||||
|
|
||||||
|
if(ID3v1Tag() && !ID3v1Tag()->isEmpty()) {
|
||||||
|
|
||||||
|
// ID3v1 tag is not empty. Update the old one or create a new one.
|
||||||
|
|
||||||
|
if(d->ID3v1Location >= 0) {
|
||||||
|
seek(d->ID3v1Location);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
seek(0, End);
|
||||||
|
d->ID3v1Location = tell();
|
||||||
|
}
|
||||||
|
|
||||||
|
writeBlock(ID3v1Tag()->render());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
// ID3v1 tag is empty. Remove the old one.
|
||||||
|
|
||||||
|
if(d->ID3v1Location >= 0) {
|
||||||
|
truncate(d->ID3v1Location);
|
||||||
|
d->ID3v1Location = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update APE tag
|
||||||
|
|
||||||
|
if(APETag() && !APETag()->isEmpty()) {
|
||||||
|
|
||||||
|
// APE tag is not empty. Update the old one or create a new one.
|
||||||
|
|
||||||
|
if(d->APELocation < 0) {
|
||||||
|
if(d->ID3v1Location >= 0)
|
||||||
|
d->APELocation = d->ID3v1Location;
|
||||||
|
else
|
||||||
|
d->APELocation = length();
|
||||||
|
}
|
||||||
|
|
||||||
|
const ByteVector data = APETag()->render();
|
||||||
|
insert(data, d->APELocation, d->APESize);
|
||||||
|
|
||||||
|
if(d->ID3v1Location >= 0)
|
||||||
|
d->ID3v1Location += (static_cast<long>(data.size()) - d->APESize);
|
||||||
|
|
||||||
|
d->APESize = data.size();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
// APE tag is empty. Remove the old one.
|
||||||
|
|
||||||
|
if(d->APELocation >= 0) {
|
||||||
|
removeBlock(d->APELocation, d->APESize);
|
||||||
|
|
||||||
|
if(d->ID3v1Location >= 0)
|
||||||
|
d->ID3v1Location -= d->APESize;
|
||||||
|
|
||||||
|
d->APELocation = -1;
|
||||||
|
d->APESize = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ID3v1::Tag *APE::File::ID3v1Tag(bool create)
|
||||||
|
{
|
||||||
|
return d->tag.access<ID3v1::Tag>(ApeID3v1Index, create);
|
||||||
|
}
|
||||||
|
|
||||||
|
APE::Tag *APE::File::APETag(bool create)
|
||||||
|
{
|
||||||
|
return d->tag.access<APE::Tag>(ApeAPEIndex, create);
|
||||||
|
}
|
||||||
|
|
||||||
|
void APE::File::strip(int tags)
|
||||||
|
{
|
||||||
|
if(tags & ID3v1)
|
||||||
|
d->tag.set(ApeID3v1Index, 0);
|
||||||
|
|
||||||
|
if(tags & APE)
|
||||||
|
d->tag.set(ApeAPEIndex, 0);
|
||||||
|
|
||||||
|
if(!ID3v1Tag())
|
||||||
|
APETag(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool APE::File::hasAPETag() const
|
||||||
|
{
|
||||||
|
return (d->APELocation >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool APE::File::hasID3v1Tag() const
|
||||||
|
{
|
||||||
|
return (d->ID3v1Location >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// private members
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void APE::File::read(bool readProperties)
|
||||||
|
{
|
||||||
|
// Look for an ID3v2 tag
|
||||||
|
|
||||||
|
d->ID3v2Location = Utils::findID3v2(this);
|
||||||
|
|
||||||
|
if(d->ID3v2Location >= 0) {
|
||||||
|
seek(d->ID3v2Location);
|
||||||
|
d->ID3v2Header = new ID3v2::Header(readBlock(ID3v2::Header::size()));
|
||||||
|
d->ID3v2Size = d->ID3v2Header->completeTagSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look for an ID3v1 tag
|
||||||
|
|
||||||
|
d->ID3v1Location = Utils::findID3v1(this);
|
||||||
|
|
||||||
|
if(d->ID3v1Location >= 0)
|
||||||
|
d->tag.set(ApeID3v1Index, new ID3v1::Tag(this, d->ID3v1Location));
|
||||||
|
|
||||||
|
// Look for an APE tag
|
||||||
|
|
||||||
|
d->APELocation = Utils::findAPE(this, d->ID3v1Location);
|
||||||
|
|
||||||
|
if(d->APELocation >= 0) {
|
||||||
|
d->tag.set(ApeAPEIndex, new APE::Tag(this, d->APELocation));
|
||||||
|
d->APESize = APETag()->footer()->completeTagSize();
|
||||||
|
d->APELocation = d->APELocation + APE::Footer::size() - d->APESize;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(d->ID3v1Location < 0)
|
||||||
|
APETag(true);
|
||||||
|
|
||||||
|
// Look for APE audio properties
|
||||||
|
|
||||||
|
if(readProperties) {
|
||||||
|
|
||||||
|
long streamLength;
|
||||||
|
|
||||||
|
if(d->APELocation >= 0)
|
||||||
|
streamLength = d->APELocation;
|
||||||
|
else if(d->ID3v1Location >= 0)
|
||||||
|
streamLength = d->ID3v1Location;
|
||||||
|
else
|
||||||
|
streamLength = length();
|
||||||
|
|
||||||
|
if(d->ID3v2Location >= 0) {
|
||||||
|
seek(d->ID3v2Location + d->ID3v2Size);
|
||||||
|
streamLength -= (d->ID3v2Location + d->ID3v2Size);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
seek(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
d->properties = new Properties(this, streamLength);
|
||||||
|
}
|
||||||
|
}
|
||||||
235
3rdparty/taglib/ape/apefile.h
vendored
Normal file
235
3rdparty/taglib/ape/apefile.h
vendored
Normal file
@@ -0,0 +1,235 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
copyright : (C) 2010 by Alex Novichkov
|
||||||
|
email : novichko@atnet.ru
|
||||||
|
|
||||||
|
copyright : (C) 2006 by Lukáš Lalinský
|
||||||
|
email : lalinsky@gmail.com
|
||||||
|
(original WavPack implementation)
|
||||||
|
|
||||||
|
copyright : (C) 2004 by Allan Sandfeld Jensen
|
||||||
|
email : kde@carewolf.org
|
||||||
|
(original MPC implementation)
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef TAGLIB_APEFILE_H
|
||||||
|
#define TAGLIB_APEFILE_H
|
||||||
|
|
||||||
|
#include "tfile.h"
|
||||||
|
#include "taglib_export.h"
|
||||||
|
#include "apeproperties.h"
|
||||||
|
|
||||||
|
namespace TagLib {
|
||||||
|
|
||||||
|
class Tag;
|
||||||
|
|
||||||
|
namespace ID3v1 { class Tag; }
|
||||||
|
namespace APE { class Tag; }
|
||||||
|
|
||||||
|
//! An implementation of APE metadata
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* This is implementation of APE metadata.
|
||||||
|
*
|
||||||
|
* This supports ID3v1 and APE (v1 and v2) style comments as well as reading stream
|
||||||
|
* properties from the file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace APE {
|
||||||
|
|
||||||
|
//! An implementation of TagLib::File with APE specific methods
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* This implements and provides an interface for APE files to the
|
||||||
|
* TagLib::Tag and TagLib::AudioProperties interfaces by way of implementing
|
||||||
|
* the abstract TagLib::File API as well as providing some additional
|
||||||
|
* information specific to APE files.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class TAGLIB_EXPORT File : public TagLib::File
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/*!
|
||||||
|
* This set of flags is used for various operations and is suitable for
|
||||||
|
* being OR-ed together.
|
||||||
|
*/
|
||||||
|
enum TagTypes {
|
||||||
|
//! Empty set. Matches no tag types.
|
||||||
|
NoTags = 0x0000,
|
||||||
|
//! Matches ID3v1 tags.
|
||||||
|
ID3v1 = 0x0001,
|
||||||
|
//! Matches APE tags.
|
||||||
|
APE = 0x0002,
|
||||||
|
//! Matches all tag types.
|
||||||
|
AllTags = 0xffff
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Constructs an APE file from \a file. If \a readProperties is true the
|
||||||
|
* file's audio properties will also be read.
|
||||||
|
*
|
||||||
|
* \note In the current implementation, \a propertiesStyle is ignored.
|
||||||
|
*/
|
||||||
|
File(FileName file, bool readProperties = true,
|
||||||
|
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Constructs an APE file from \a stream. If \a readProperties is true the
|
||||||
|
* file's audio properties will also be read.
|
||||||
|
*
|
||||||
|
* \note TagLib will *not* take ownership of the stream, the caller is
|
||||||
|
* responsible for deleting it after the File object.
|
||||||
|
*
|
||||||
|
* \note In the current implementation, \a propertiesStyle is ignored.
|
||||||
|
*/
|
||||||
|
File(IOStream *stream, bool readProperties = true,
|
||||||
|
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Destroys this instance of the File.
|
||||||
|
*/
|
||||||
|
virtual ~File();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the Tag for this file. This will be an APE tag, an ID3v1 tag
|
||||||
|
* or a combination of the two.
|
||||||
|
*/
|
||||||
|
virtual TagLib::Tag *tag() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Implements the unified property interface -- export function.
|
||||||
|
* If the file contains both an APE and an ID3v1 tag, only APE
|
||||||
|
* will be converted to the PropertyMap.
|
||||||
|
*/
|
||||||
|
PropertyMap properties() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Removes unsupported properties. Forwards to the actual Tag's
|
||||||
|
* removeUnsupportedProperties() function.
|
||||||
|
*/
|
||||||
|
void removeUnsupportedProperties(const StringList &properties);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Implements the unified property interface -- import function.
|
||||||
|
* Creates an APEv2 tag if necessary. A potentially existing ID3v1
|
||||||
|
* tag will be updated as well.
|
||||||
|
*/
|
||||||
|
PropertyMap setProperties(const PropertyMap &);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the APE::Properties for this file. If no audio properties
|
||||||
|
* were read then this will return a null pointer.
|
||||||
|
*/
|
||||||
|
virtual Properties *audioProperties() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Saves the file.
|
||||||
|
*
|
||||||
|
* \note According to the official Monkey's Audio SDK, an APE file
|
||||||
|
* can only have either ID3V1 or APE tags, so a parameter is used here.
|
||||||
|
*/
|
||||||
|
virtual bool save();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns a pointer to the ID3v1 tag of the file.
|
||||||
|
*
|
||||||
|
* If \a create is false (the default) this may return a null pointer
|
||||||
|
* if there is no valid ID3v1 tag. If \a create is true it will create
|
||||||
|
* an ID3v1 tag if one does not exist and returns a valid pointer.
|
||||||
|
*
|
||||||
|
* \note This may return a valid pointer regardless of whether or not the
|
||||||
|
* file on disk has an ID3v1 tag. Use hasID3v1Tag() to check if the file
|
||||||
|
* on disk actually has an ID3v1 tag.
|
||||||
|
*
|
||||||
|
* \note The Tag <b>is still</b> owned by the MPEG::File and should not be
|
||||||
|
* deleted by the user. It will be deleted when the file (object) is
|
||||||
|
* destroyed.
|
||||||
|
*
|
||||||
|
* \see hasID3v1Tag()
|
||||||
|
*/
|
||||||
|
ID3v1::Tag *ID3v1Tag(bool create = false);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns a pointer to the APE tag of the file.
|
||||||
|
*
|
||||||
|
* If \a create is false (the default) this may return a null pointer
|
||||||
|
* if there is no valid APE tag. If \a create is true it will create
|
||||||
|
* an APE tag if one does not exist and returns a valid pointer.
|
||||||
|
*
|
||||||
|
* \note This may return a valid pointer regardless of whether or not the
|
||||||
|
* file on disk has an APE tag. Use hasAPETag() to check if the file
|
||||||
|
* on disk actually has an APE tag.
|
||||||
|
*
|
||||||
|
* \note The Tag <b>is still</b> owned by the MPEG::File and should not be
|
||||||
|
* deleted by the user. It will be deleted when the file (object) is
|
||||||
|
* destroyed.
|
||||||
|
*
|
||||||
|
* \see hasAPETag()
|
||||||
|
*/
|
||||||
|
APE::Tag *APETag(bool create = false);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* This will remove the tags that match the OR-ed together TagTypes from the
|
||||||
|
* file. By default it removes all tags.
|
||||||
|
*
|
||||||
|
* \note This will also invalidate pointers to the tags
|
||||||
|
* as their memory will be freed.
|
||||||
|
* \note In order to make the removal permanent save() still needs to be called
|
||||||
|
*/
|
||||||
|
void strip(int tags = AllTags);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns whether or not the file on disk actually has an APE tag.
|
||||||
|
*
|
||||||
|
* \see APETag()
|
||||||
|
*/
|
||||||
|
bool hasAPETag() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns whether or not the file on disk actually has an ID3v1 tag.
|
||||||
|
*
|
||||||
|
* \see ID3v1Tag()
|
||||||
|
*/
|
||||||
|
bool hasID3v1Tag() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns whether or not the given \a stream can be opened as an APE
|
||||||
|
* file.
|
||||||
|
*
|
||||||
|
* \note This method is designed to do a quick check. The result may
|
||||||
|
* not necessarily be correct.
|
||||||
|
*/
|
||||||
|
static bool isSupported(IOStream *stream);
|
||||||
|
|
||||||
|
private:
|
||||||
|
File(const File &);
|
||||||
|
File &operator=(const File &);
|
||||||
|
|
||||||
|
void read(bool readProperties);
|
||||||
|
|
||||||
|
class FilePrivate;
|
||||||
|
FilePrivate *d;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
234
3rdparty/taglib/ape/apefooter.cpp
vendored
Normal file
234
3rdparty/taglib/ape/apefooter.cpp
vendored
Normal file
@@ -0,0 +1,234 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
copyright : (C) 2004 by Allan Sandfeld Jensen
|
||||||
|
(C) 2002 - 2008 by Scott Wheeler (id3v2header.cpp)
|
||||||
|
email : kde@carewolf.org
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <bitset>
|
||||||
|
|
||||||
|
#include <tstring.h>
|
||||||
|
#include <tdebug.h>
|
||||||
|
|
||||||
|
#include "apefooter.h"
|
||||||
|
|
||||||
|
using namespace TagLib;
|
||||||
|
using namespace APE;
|
||||||
|
|
||||||
|
class APE::Footer::FooterPrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FooterPrivate() :
|
||||||
|
version(0),
|
||||||
|
footerPresent(true),
|
||||||
|
headerPresent(false),
|
||||||
|
isHeader(false),
|
||||||
|
itemCount(0),
|
||||||
|
tagSize(0) {}
|
||||||
|
|
||||||
|
unsigned int version;
|
||||||
|
|
||||||
|
bool footerPresent;
|
||||||
|
bool headerPresent;
|
||||||
|
|
||||||
|
bool isHeader;
|
||||||
|
|
||||||
|
unsigned int itemCount;
|
||||||
|
unsigned int tagSize;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// static members
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
unsigned int APE::Footer::size()
|
||||||
|
{
|
||||||
|
return 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector APE::Footer::fileIdentifier()
|
||||||
|
{
|
||||||
|
return ByteVector("APETAGEX");
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// public members
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
APE::Footer::Footer() :
|
||||||
|
d(new FooterPrivate())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
APE::Footer::Footer(const ByteVector &data) :
|
||||||
|
d(new FooterPrivate())
|
||||||
|
{
|
||||||
|
parse(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
APE::Footer::~Footer()
|
||||||
|
{
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int APE::Footer::version() const
|
||||||
|
{
|
||||||
|
return d->version;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool APE::Footer::headerPresent() const
|
||||||
|
{
|
||||||
|
return d->headerPresent;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool APE::Footer::footerPresent() const
|
||||||
|
{
|
||||||
|
return d->footerPresent;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool APE::Footer::isHeader() const
|
||||||
|
{
|
||||||
|
return d->isHeader;
|
||||||
|
}
|
||||||
|
|
||||||
|
void APE::Footer::setHeaderPresent(bool b) const
|
||||||
|
{
|
||||||
|
d->headerPresent = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int APE::Footer::itemCount() const
|
||||||
|
{
|
||||||
|
return d->itemCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void APE::Footer::setItemCount(unsigned int s)
|
||||||
|
{
|
||||||
|
d->itemCount = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int APE::Footer::tagSize() const
|
||||||
|
{
|
||||||
|
return d->tagSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int APE::Footer::completeTagSize() const
|
||||||
|
{
|
||||||
|
if(d->headerPresent)
|
||||||
|
return d->tagSize + size();
|
||||||
|
else
|
||||||
|
return d->tagSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
void APE::Footer::setTagSize(unsigned int s)
|
||||||
|
{
|
||||||
|
d->tagSize = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void APE::Footer::setData(const ByteVector &data)
|
||||||
|
{
|
||||||
|
parse(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector APE::Footer::renderFooter() const
|
||||||
|
{
|
||||||
|
return render(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector APE::Footer::renderHeader() const
|
||||||
|
{
|
||||||
|
if(!d->headerPresent)
|
||||||
|
return ByteVector();
|
||||||
|
else
|
||||||
|
return render(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// protected members
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void APE::Footer::parse(const ByteVector &data)
|
||||||
|
{
|
||||||
|
if(data.size() < size())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// The first eight bytes, data[0..7], are the File Identifier, "APETAGEX".
|
||||||
|
|
||||||
|
// Read the version number
|
||||||
|
|
||||||
|
d->version = data.toUInt(8, false);
|
||||||
|
|
||||||
|
// Read the tag size
|
||||||
|
|
||||||
|
d->tagSize = data.toUInt(12, false);
|
||||||
|
|
||||||
|
// Read the item count
|
||||||
|
|
||||||
|
d->itemCount = data.toUInt(16, false);
|
||||||
|
|
||||||
|
// Read the flags
|
||||||
|
|
||||||
|
std::bitset<32> flags(TAGLIB_CONSTRUCT_BITSET(data.toUInt(20, false)));
|
||||||
|
|
||||||
|
d->headerPresent = flags[31];
|
||||||
|
d->footerPresent = !flags[30];
|
||||||
|
d->isHeader = flags[29];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector APE::Footer::render(bool isHeader) const
|
||||||
|
{
|
||||||
|
ByteVector v;
|
||||||
|
|
||||||
|
// add the file identifier -- "APETAGEX"
|
||||||
|
|
||||||
|
v.append(fileIdentifier());
|
||||||
|
|
||||||
|
// add the version number -- we always render a 2.000 tag regardless of what
|
||||||
|
// the tag originally was.
|
||||||
|
|
||||||
|
v.append(ByteVector::fromUInt(2000, false));
|
||||||
|
|
||||||
|
// add the tag size
|
||||||
|
|
||||||
|
v.append(ByteVector::fromUInt(d->tagSize, false));
|
||||||
|
|
||||||
|
// add the item count
|
||||||
|
|
||||||
|
v.append(ByteVector::fromUInt(d->itemCount, false));
|
||||||
|
|
||||||
|
// render and add the flags
|
||||||
|
|
||||||
|
std::bitset<32> flags;
|
||||||
|
|
||||||
|
flags[31] = d->headerPresent;
|
||||||
|
flags[30] = false; // footer is always present
|
||||||
|
flags[29] = isHeader;
|
||||||
|
|
||||||
|
v.append(ByteVector::fromUInt(flags.to_ulong(), false));
|
||||||
|
|
||||||
|
// add the reserved 64bit
|
||||||
|
|
||||||
|
v.append(ByteVector::fromLongLong(0));
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
173
3rdparty/taglib/ape/apefooter.h
vendored
Normal file
173
3rdparty/taglib/ape/apefooter.h
vendored
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
copyright : (C) 2004 by Allan Sandfeld Jensen
|
||||||
|
email : kde@carewolf.org
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef TAGLIB_APEFOOTER_H
|
||||||
|
#define TAGLIB_APEFOOTER_H
|
||||||
|
|
||||||
|
#include "tbytevector.h"
|
||||||
|
#include "taglib_export.h"
|
||||||
|
|
||||||
|
namespace TagLib {
|
||||||
|
|
||||||
|
namespace APE {
|
||||||
|
|
||||||
|
//! An implementation of APE footers
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* This class implements APE footers (and headers). It attempts to follow, both
|
||||||
|
* semantically and programmatically, the structure specified in
|
||||||
|
* the APE v2.0 standard. The API is based on the properties of APE footer and
|
||||||
|
* headers specified there.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class TAGLIB_EXPORT Footer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/*!
|
||||||
|
* Constructs an empty APE footer.
|
||||||
|
*/
|
||||||
|
Footer();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Constructs an APE footer based on \a data. parse() is called
|
||||||
|
* immediately.
|
||||||
|
*/
|
||||||
|
Footer(const ByteVector &data);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Destroys the footer.
|
||||||
|
*/
|
||||||
|
virtual ~Footer();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the version number. (Note: This is the 1000 or 2000.)
|
||||||
|
*/
|
||||||
|
unsigned int version() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns true if a header is present in the tag.
|
||||||
|
*/
|
||||||
|
bool headerPresent() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns true if a footer is present in the tag.
|
||||||
|
*/
|
||||||
|
bool footerPresent() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns true this is actually the header.
|
||||||
|
*/
|
||||||
|
bool isHeader() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets whether the header should be rendered or not
|
||||||
|
*/
|
||||||
|
void setHeaderPresent(bool b) const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the number of items in the tag.
|
||||||
|
*/
|
||||||
|
unsigned int itemCount() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Set the item count to \a s.
|
||||||
|
* \see itemCount()
|
||||||
|
*/
|
||||||
|
void setItemCount(unsigned int s);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the tag size in bytes. This is the size of the frame content and footer.
|
||||||
|
* The size of the \e entire tag will be this plus the header size, if present.
|
||||||
|
*
|
||||||
|
* \see completeTagSize()
|
||||||
|
*/
|
||||||
|
unsigned int tagSize() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the tag size, including if present, the header
|
||||||
|
* size.
|
||||||
|
*
|
||||||
|
* \see tagSize()
|
||||||
|
*/
|
||||||
|
unsigned int completeTagSize() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Set the tag size to \a s.
|
||||||
|
* \see tagSize()
|
||||||
|
*/
|
||||||
|
void setTagSize(unsigned int s);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the size of the footer. Presently this is always 32 bytes.
|
||||||
|
*/
|
||||||
|
static unsigned int size();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the string used to identify an APE tag inside of a file.
|
||||||
|
* Presently this is always "APETAGEX".
|
||||||
|
*/
|
||||||
|
static ByteVector fileIdentifier();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets the data that will be used as the footer. 32 bytes,
|
||||||
|
* starting from \a data will be used.
|
||||||
|
*/
|
||||||
|
void setData(const ByteVector &data);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Renders the footer back to binary format.
|
||||||
|
*/
|
||||||
|
ByteVector renderFooter() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Renders the header corresponding to the footer. If headerPresent is
|
||||||
|
* set to false, it returns an empty ByteVector.
|
||||||
|
*/
|
||||||
|
ByteVector renderHeader() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/*!
|
||||||
|
* Called by setData() to parse the footer data. It makes this information
|
||||||
|
* available through the public API.
|
||||||
|
*/
|
||||||
|
void parse(const ByteVector &data);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Called by renderFooter and renderHeader
|
||||||
|
*/
|
||||||
|
ByteVector render(bool isHeader) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Footer(const Footer &);
|
||||||
|
Footer &operator=(const Footer &);
|
||||||
|
|
||||||
|
class FooterPrivate;
|
||||||
|
FooterPrivate *d;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
301
3rdparty/taglib/ape/apeitem.cpp
vendored
Normal file
301
3rdparty/taglib/ape/apeitem.cpp
vendored
Normal file
@@ -0,0 +1,301 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
copyright : (C) 2004 by Allan Sandfeld Jensen
|
||||||
|
email : kde@carewolf.com
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include <tbytevectorlist.h>
|
||||||
|
#include <tdebug.h>
|
||||||
|
|
||||||
|
#include "apeitem.h"
|
||||||
|
|
||||||
|
using namespace TagLib;
|
||||||
|
using namespace APE;
|
||||||
|
|
||||||
|
class APE::Item::ItemPrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ItemPrivate() :
|
||||||
|
type(Text),
|
||||||
|
readOnly(false) {}
|
||||||
|
|
||||||
|
Item::ItemTypes type;
|
||||||
|
String key;
|
||||||
|
ByteVector value;
|
||||||
|
StringList text;
|
||||||
|
bool readOnly;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// public members
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
APE::Item::Item() :
|
||||||
|
d(new ItemPrivate())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
APE::Item::Item(const String &key, const String &value) :
|
||||||
|
d(new ItemPrivate())
|
||||||
|
{
|
||||||
|
d->key = key;
|
||||||
|
d->text.append(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
APE::Item::Item(const String &key, const StringList &values) :
|
||||||
|
d(new ItemPrivate())
|
||||||
|
{
|
||||||
|
d->key = key;
|
||||||
|
d->text = values;
|
||||||
|
}
|
||||||
|
|
||||||
|
APE::Item::Item(const String &key, const ByteVector &value, bool binary) :
|
||||||
|
d(new ItemPrivate())
|
||||||
|
{
|
||||||
|
d->key = key;
|
||||||
|
if(binary) {
|
||||||
|
d->type = Binary;
|
||||||
|
d->value = value;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
d->text.append(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
APE::Item::Item(const Item &item) :
|
||||||
|
d(new ItemPrivate(*item.d))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
APE::Item::~Item()
|
||||||
|
{
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
Item &APE::Item::operator=(const Item &item)
|
||||||
|
{
|
||||||
|
Item(item).swap(*this);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void APE::Item::swap(Item &item)
|
||||||
|
{
|
||||||
|
using std::swap;
|
||||||
|
|
||||||
|
swap(d, item.d);
|
||||||
|
}
|
||||||
|
|
||||||
|
void APE::Item::setReadOnly(bool readOnly)
|
||||||
|
{
|
||||||
|
d->readOnly = readOnly;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool APE::Item::isReadOnly() const
|
||||||
|
{
|
||||||
|
return d->readOnly;
|
||||||
|
}
|
||||||
|
|
||||||
|
void APE::Item::setType(APE::Item::ItemTypes val)
|
||||||
|
{
|
||||||
|
d->type = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
APE::Item::ItemTypes APE::Item::type() const
|
||||||
|
{
|
||||||
|
return d->type;
|
||||||
|
}
|
||||||
|
|
||||||
|
String APE::Item::key() const
|
||||||
|
{
|
||||||
|
return d->key;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector APE::Item::binaryData() const
|
||||||
|
{
|
||||||
|
return d->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void APE::Item::setBinaryData(const ByteVector &value)
|
||||||
|
{
|
||||||
|
d->type = Binary;
|
||||||
|
d->value = value;
|
||||||
|
d->text.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector APE::Item::value() const
|
||||||
|
{
|
||||||
|
// This seems incorrect as it won't be actually rendering the value to keep it
|
||||||
|
// up to date.
|
||||||
|
|
||||||
|
return d->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void APE::Item::setKey(const String &key)
|
||||||
|
{
|
||||||
|
d->key = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
void APE::Item::setValue(const String &value)
|
||||||
|
{
|
||||||
|
d->type = Text;
|
||||||
|
d->text = value;
|
||||||
|
d->value.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void APE::Item::setValues(const StringList &value)
|
||||||
|
{
|
||||||
|
d->type = Text;
|
||||||
|
d->text = value;
|
||||||
|
d->value.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void APE::Item::appendValue(const String &value)
|
||||||
|
{
|
||||||
|
d->type = Text;
|
||||||
|
d->text.append(value);
|
||||||
|
d->value.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void APE::Item::appendValues(const StringList &values)
|
||||||
|
{
|
||||||
|
d->type = Text;
|
||||||
|
d->text.append(values);
|
||||||
|
d->value.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
int APE::Item::size() const
|
||||||
|
{
|
||||||
|
int result = 8 + d->key.size() + 1;
|
||||||
|
switch(d->type) {
|
||||||
|
case Text:
|
||||||
|
if(!d->text.isEmpty()) {
|
||||||
|
StringList::ConstIterator it = d->text.begin();
|
||||||
|
|
||||||
|
result += it->data(String::UTF8).size();
|
||||||
|
it++;
|
||||||
|
for(; it != d->text.end(); ++it)
|
||||||
|
result += 1 + it->data(String::UTF8).size();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Binary:
|
||||||
|
case Locator:
|
||||||
|
result += d->value.size();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringList APE::Item::toStringList() const
|
||||||
|
{
|
||||||
|
return d->text;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringList APE::Item::values() const
|
||||||
|
{
|
||||||
|
return d->text;
|
||||||
|
}
|
||||||
|
|
||||||
|
String APE::Item::toString() const
|
||||||
|
{
|
||||||
|
if(d->type == Text && !isEmpty())
|
||||||
|
return d->text.front();
|
||||||
|
else
|
||||||
|
return String();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool APE::Item::isEmpty() const
|
||||||
|
{
|
||||||
|
switch(d->type) {
|
||||||
|
case Text:
|
||||||
|
if(d->text.isEmpty())
|
||||||
|
return true;
|
||||||
|
if(d->text.size() == 1 && d->text.front().isEmpty())
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
case Binary:
|
||||||
|
case Locator:
|
||||||
|
return d->value.isEmpty();
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void APE::Item::parse(const ByteVector &data)
|
||||||
|
{
|
||||||
|
// 11 bytes is the minimum size for an APE item
|
||||||
|
|
||||||
|
if(data.size() < 11) {
|
||||||
|
debug("APE::Item::parse() -- no data in item");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const unsigned int valueLength = data.toUInt(0, false);
|
||||||
|
const unsigned int flags = data.toUInt(4, false);
|
||||||
|
|
||||||
|
// An item key can contain ASCII characters from 0x20 up to 0x7E, not UTF-8.
|
||||||
|
// We assume that the validity of the given key has been checked.
|
||||||
|
|
||||||
|
d->key = String(&data[8], String::Latin1);
|
||||||
|
|
||||||
|
const ByteVector value = data.mid(8 + d->key.size() + 1, valueLength);
|
||||||
|
|
||||||
|
setReadOnly(flags & 1);
|
||||||
|
setType(ItemTypes((flags >> 1) & 3));
|
||||||
|
|
||||||
|
if(Text == d->type)
|
||||||
|
d->text = StringList(ByteVectorList::split(value, '\0'), String::UTF8);
|
||||||
|
else
|
||||||
|
d->value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector APE::Item::render() const
|
||||||
|
{
|
||||||
|
ByteVector data;
|
||||||
|
unsigned int flags = ((d->readOnly) ? 1 : 0) | (d->type << 1);
|
||||||
|
ByteVector value;
|
||||||
|
|
||||||
|
if(isEmpty())
|
||||||
|
return data;
|
||||||
|
|
||||||
|
if(d->type == Text) {
|
||||||
|
StringList::ConstIterator it = d->text.begin();
|
||||||
|
|
||||||
|
value.append(it->data(String::UTF8));
|
||||||
|
it++;
|
||||||
|
for(; it != d->text.end(); ++it) {
|
||||||
|
value.append('\0');
|
||||||
|
value.append(it->data(String::UTF8));
|
||||||
|
}
|
||||||
|
d->value = value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
value.append(d->value);
|
||||||
|
|
||||||
|
data.append(ByteVector::fromUInt(value.size(), false));
|
||||||
|
data.append(ByteVector::fromUInt(flags, false));
|
||||||
|
data.append(d->key.data(String::Latin1));
|
||||||
|
data.append(ByteVector('\0'));
|
||||||
|
data.append(value);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
224
3rdparty/taglib/ape/apeitem.h
vendored
Normal file
224
3rdparty/taglib/ape/apeitem.h
vendored
Normal file
@@ -0,0 +1,224 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
copyright : (C) 2004 by Allan Sandfeld Jensen
|
||||||
|
email : kde@carewolf.org
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef TAGLIB_APEITEM_H
|
||||||
|
#define TAGLIB_APEITEM_H
|
||||||
|
|
||||||
|
#include "tbytevector.h"
|
||||||
|
#include "tstring.h"
|
||||||
|
#include "tstringlist.h"
|
||||||
|
|
||||||
|
namespace TagLib {
|
||||||
|
|
||||||
|
namespace APE {
|
||||||
|
|
||||||
|
//! An implementation of APE-items
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* This class provides the features of items in the APEv2 standard.
|
||||||
|
*/
|
||||||
|
class TAGLIB_EXPORT Item
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/*!
|
||||||
|
* Enum of types an Item can have. The value of 3 is reserved.
|
||||||
|
*/
|
||||||
|
enum ItemTypes {
|
||||||
|
//! Item contains text information coded in UTF-8
|
||||||
|
Text = 0,
|
||||||
|
//! Item contains binary information
|
||||||
|
Binary = 1,
|
||||||
|
//! Item is a locator of external stored information
|
||||||
|
Locator = 2
|
||||||
|
};
|
||||||
|
/*!
|
||||||
|
* Constructs an empty item.
|
||||||
|
*/
|
||||||
|
Item();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Constructs a text item with \a key and \a value.
|
||||||
|
*/
|
||||||
|
// BIC: Remove this, StringList has a constructor from a single string
|
||||||
|
Item(const String &key, const String &value);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Constructs a text item with \a key and \a values.
|
||||||
|
*/
|
||||||
|
Item(const String &key, const StringList &values);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Constructs an item with \a key and \a value.
|
||||||
|
* If \a binary is true a Binary item will be created, otherwise \a value will be interpreted as text
|
||||||
|
*/
|
||||||
|
Item(const String &key, const ByteVector &value, bool binary);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Construct an item as a copy of \a item.
|
||||||
|
*/
|
||||||
|
Item(const Item &item);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Destroys the item.
|
||||||
|
*/
|
||||||
|
virtual ~Item();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Copies the contents of \a item into this item.
|
||||||
|
*/
|
||||||
|
Item &operator=(const Item &item);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Exchanges the content of this item by the content of \a item.
|
||||||
|
*/
|
||||||
|
void swap(Item &item);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the key.
|
||||||
|
*/
|
||||||
|
String key() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the binary value.
|
||||||
|
* If the item type is not \a Binary, always returns an empty ByteVector.
|
||||||
|
*/
|
||||||
|
ByteVector binaryData() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Set the binary value to \a value
|
||||||
|
* The item's type will also be set to \a Binary
|
||||||
|
*/
|
||||||
|
void setBinaryData(const ByteVector &value);
|
||||||
|
|
||||||
|
#ifndef DO_NOT_DOCUMENT
|
||||||
|
/* Remove in next binary incompatible release */
|
||||||
|
ByteVector value() const;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets the key for the item to \a key.
|
||||||
|
*/
|
||||||
|
void setKey(const String &key);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets the text value of the item to \a value and clears any previous contents.
|
||||||
|
*
|
||||||
|
* \see toString()
|
||||||
|
*/
|
||||||
|
void setValue(const String &value);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets the text value of the item to the list of values in \a value and clears
|
||||||
|
* any previous contents.
|
||||||
|
*
|
||||||
|
* \see toStringList()
|
||||||
|
*/
|
||||||
|
void setValues(const StringList &values);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Appends \a value to create (or extend) the current list of text values.
|
||||||
|
*
|
||||||
|
* \see toString()
|
||||||
|
*/
|
||||||
|
void appendValue(const String &value);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Appends \a values to extend the current list of text values.
|
||||||
|
*
|
||||||
|
* \see toStringList()
|
||||||
|
*/
|
||||||
|
void appendValues(const StringList &values);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the size of the full item.
|
||||||
|
*/
|
||||||
|
int size() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the value as a single string. In case of multiple strings,
|
||||||
|
* the first is returned. If the data type is not \a Text, always returns
|
||||||
|
* an empty String.
|
||||||
|
*/
|
||||||
|
String toString() const;
|
||||||
|
|
||||||
|
#ifndef DO_NOT_DOCUMENT
|
||||||
|
/* Remove in next binary incompatible release */
|
||||||
|
StringList toStringList() const;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the list of text values. If the data type is not \a Text, always
|
||||||
|
* returns an empty StringList.
|
||||||
|
*/
|
||||||
|
StringList values() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Render the item to a ByteVector.
|
||||||
|
*/
|
||||||
|
ByteVector render() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Parse the item from the ByteVector \a data.
|
||||||
|
*/
|
||||||
|
void parse(const ByteVector& data);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Set the item to read-only.
|
||||||
|
*/
|
||||||
|
void setReadOnly(bool readOnly);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Return true if the item is read-only.
|
||||||
|
*/
|
||||||
|
bool isReadOnly() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets the type of the item to \a type.
|
||||||
|
*
|
||||||
|
* \see ItemTypes
|
||||||
|
*/
|
||||||
|
void setType(ItemTypes type);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the type of the item.
|
||||||
|
*/
|
||||||
|
ItemTypes type() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns if the item has any real content.
|
||||||
|
*/
|
||||||
|
bool isEmpty() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
class ItemPrivate;
|
||||||
|
ItemPrivate *d;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
252
3rdparty/taglib/ape/apeproperties.cpp
vendored
Normal file
252
3rdparty/taglib/ape/apeproperties.cpp
vendored
Normal file
@@ -0,0 +1,252 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
copyright : (C) 2010 by Alex Novichkov
|
||||||
|
email : novichko@atnet.ru
|
||||||
|
|
||||||
|
copyright : (C) 2006 by Lukáš Lalinský
|
||||||
|
email : lalinsky@gmail.com
|
||||||
|
(original WavPack implementation)
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include <tstring.h>
|
||||||
|
#include <tdebug.h>
|
||||||
|
#include <bitset>
|
||||||
|
#include "id3v2tag.h"
|
||||||
|
#include "apeproperties.h"
|
||||||
|
#include "apefile.h"
|
||||||
|
#include "apetag.h"
|
||||||
|
#include "apefooter.h"
|
||||||
|
|
||||||
|
using namespace TagLib;
|
||||||
|
|
||||||
|
class APE::Properties::PropertiesPrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PropertiesPrivate() :
|
||||||
|
length(0),
|
||||||
|
bitrate(0),
|
||||||
|
sampleRate(0),
|
||||||
|
channels(0),
|
||||||
|
version(0),
|
||||||
|
bitsPerSample(0),
|
||||||
|
sampleFrames(0) {}
|
||||||
|
|
||||||
|
int length;
|
||||||
|
int bitrate;
|
||||||
|
int sampleRate;
|
||||||
|
int channels;
|
||||||
|
int version;
|
||||||
|
int bitsPerSample;
|
||||||
|
unsigned int sampleFrames;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// public members
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
APE::Properties::Properties(File *, ReadStyle style) :
|
||||||
|
AudioProperties(style),
|
||||||
|
d(new PropertiesPrivate())
|
||||||
|
{
|
||||||
|
debug("APE::Properties::Properties() -- This constructor is no longer used.");
|
||||||
|
}
|
||||||
|
|
||||||
|
APE::Properties::Properties(File *file, long streamLength, ReadStyle style) :
|
||||||
|
AudioProperties(style),
|
||||||
|
d(new PropertiesPrivate())
|
||||||
|
{
|
||||||
|
read(file, streamLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
APE::Properties::~Properties()
|
||||||
|
{
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
int APE::Properties::length() const
|
||||||
|
{
|
||||||
|
return lengthInSeconds();
|
||||||
|
}
|
||||||
|
|
||||||
|
int APE::Properties::lengthInSeconds() const
|
||||||
|
{
|
||||||
|
return d->length / 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
int APE::Properties::lengthInMilliseconds() const
|
||||||
|
{
|
||||||
|
return d->length;
|
||||||
|
}
|
||||||
|
|
||||||
|
int APE::Properties::bitrate() const
|
||||||
|
{
|
||||||
|
return d->bitrate;
|
||||||
|
}
|
||||||
|
|
||||||
|
int APE::Properties::sampleRate() const
|
||||||
|
{
|
||||||
|
return d->sampleRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
int APE::Properties::channels() const
|
||||||
|
{
|
||||||
|
return d->channels;
|
||||||
|
}
|
||||||
|
|
||||||
|
int APE::Properties::version() const
|
||||||
|
{
|
||||||
|
return d->version;
|
||||||
|
}
|
||||||
|
|
||||||
|
int APE::Properties::bitsPerSample() const
|
||||||
|
{
|
||||||
|
return d->bitsPerSample;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int APE::Properties::sampleFrames() const
|
||||||
|
{
|
||||||
|
return d->sampleFrames;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// private members
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
int headerVersion(const ByteVector &header)
|
||||||
|
{
|
||||||
|
if(header.size() < 6 || !header.startsWith("MAC "))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return header.toUShort(4, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void APE::Properties::read(File *file, long streamLength)
|
||||||
|
{
|
||||||
|
// First, we assume that the file pointer is set at the first descriptor.
|
||||||
|
long offset = file->tell();
|
||||||
|
int version = headerVersion(file->readBlock(6));
|
||||||
|
|
||||||
|
// Next, we look for the descriptor.
|
||||||
|
if(version < 0) {
|
||||||
|
offset = file->find("MAC ", offset);
|
||||||
|
file->seek(offset);
|
||||||
|
version = headerVersion(file->readBlock(6));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(version < 0) {
|
||||||
|
debug("APE::Properties::read() -- APE descriptor not found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
d->version = version;
|
||||||
|
|
||||||
|
if(d->version >= 3980)
|
||||||
|
analyzeCurrent(file);
|
||||||
|
else
|
||||||
|
analyzeOld(file);
|
||||||
|
|
||||||
|
if(d->sampleFrames > 0 && d->sampleRate > 0) {
|
||||||
|
const double length = d->sampleFrames * 1000.0 / d->sampleRate;
|
||||||
|
d->length = static_cast<int>(length + 0.5);
|
||||||
|
d->bitrate = static_cast<int>(streamLength * 8.0 / length + 0.5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void APE::Properties::analyzeCurrent(File *file)
|
||||||
|
{
|
||||||
|
// Read the descriptor
|
||||||
|
file->seek(2, File::Current);
|
||||||
|
const ByteVector descriptor = file->readBlock(44);
|
||||||
|
if(descriptor.size() < 44) {
|
||||||
|
debug("APE::Properties::analyzeCurrent() -- descriptor is too short.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const unsigned int descriptorBytes = descriptor.toUInt(0, false);
|
||||||
|
|
||||||
|
if((descriptorBytes - 52) > 0)
|
||||||
|
file->seek(descriptorBytes - 52, File::Current);
|
||||||
|
|
||||||
|
// Read the header
|
||||||
|
const ByteVector header = file->readBlock(24);
|
||||||
|
if(header.size() < 24) {
|
||||||
|
debug("APE::Properties::analyzeCurrent() -- MAC header is too short.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the APE info
|
||||||
|
d->channels = header.toShort(18, false);
|
||||||
|
d->sampleRate = header.toUInt(20, false);
|
||||||
|
d->bitsPerSample = header.toShort(16, false);
|
||||||
|
|
||||||
|
const unsigned int totalFrames = header.toUInt(12, false);
|
||||||
|
if(totalFrames == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const unsigned int blocksPerFrame = header.toUInt(4, false);
|
||||||
|
const unsigned int finalFrameBlocks = header.toUInt(8, false);
|
||||||
|
d->sampleFrames = (totalFrames - 1) * blocksPerFrame + finalFrameBlocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
void APE::Properties::analyzeOld(File *file)
|
||||||
|
{
|
||||||
|
const ByteVector header = file->readBlock(26);
|
||||||
|
if(header.size() < 26) {
|
||||||
|
debug("APE::Properties::analyzeOld() -- MAC header is too short.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const unsigned int totalFrames = header.toUInt(18, false);
|
||||||
|
|
||||||
|
// Fail on 0 length APE files (catches non-finalized APE files)
|
||||||
|
if(totalFrames == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const short compressionLevel = header.toShort(0, false);
|
||||||
|
unsigned int blocksPerFrame;
|
||||||
|
if(d->version >= 3950)
|
||||||
|
blocksPerFrame = 73728 * 4;
|
||||||
|
else if(d->version >= 3900 || (d->version >= 3800 && compressionLevel == 4000))
|
||||||
|
blocksPerFrame = 73728;
|
||||||
|
else
|
||||||
|
blocksPerFrame = 9216;
|
||||||
|
|
||||||
|
// Get the APE info
|
||||||
|
d->channels = header.toShort(4, false);
|
||||||
|
d->sampleRate = header.toUInt(6, false);
|
||||||
|
|
||||||
|
const unsigned int finalFrameBlocks = header.toUInt(22, false);
|
||||||
|
d->sampleFrames = (totalFrames - 1) * blocksPerFrame + finalFrameBlocks;
|
||||||
|
|
||||||
|
// Get the bit depth from the RIFF-fmt chunk.
|
||||||
|
file->seek(16, File::Current);
|
||||||
|
const ByteVector fmt = file->readBlock(28);
|
||||||
|
if(fmt.size() < 28 || !fmt.startsWith("WAVEfmt ")) {
|
||||||
|
debug("APE::Properties::analyzeOld() -- fmt header is too short.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
d->bitsPerSample = fmt.toShort(26, false);
|
||||||
|
}
|
||||||
143
3rdparty/taglib/ape/apeproperties.h
vendored
Normal file
143
3rdparty/taglib/ape/apeproperties.h
vendored
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
copyright : (C) 2010 by Alex Novichkov
|
||||||
|
email : novichko@atnet.ru
|
||||||
|
|
||||||
|
copyright : (C) 2006 by Lukáš Lalinský
|
||||||
|
email : lalinsky@gmail.com
|
||||||
|
(original WavPack implementation)
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef TAGLIB_APEPROPERTIES_H
|
||||||
|
#define TAGLIB_APEPROPERTIES_H
|
||||||
|
|
||||||
|
#include "taglib_export.h"
|
||||||
|
#include "audioproperties.h"
|
||||||
|
|
||||||
|
namespace TagLib {
|
||||||
|
|
||||||
|
namespace APE {
|
||||||
|
|
||||||
|
class File;
|
||||||
|
|
||||||
|
//! An implementation of audio property reading for APE
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* This reads the data from an APE stream found in the AudioProperties
|
||||||
|
* API.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class TAGLIB_EXPORT Properties : public AudioProperties
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/*!
|
||||||
|
* Create an instance of APE::Properties with the data read from the
|
||||||
|
* APE::File \a file.
|
||||||
|
*
|
||||||
|
* \deprecated
|
||||||
|
*/
|
||||||
|
Properties(File *file, ReadStyle style = Average);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Create an instance of APE::Properties with the data read from the
|
||||||
|
* APE::File \a file.
|
||||||
|
*/
|
||||||
|
Properties(File *file, long streamLength, ReadStyle style = Average);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Destroys this APE::Properties instance.
|
||||||
|
*/
|
||||||
|
virtual ~Properties();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the length of the file in seconds. The length is rounded down to
|
||||||
|
* the nearest whole second.
|
||||||
|
*
|
||||||
|
* \note This method is just an alias of lengthInSeconds().
|
||||||
|
*
|
||||||
|
* \deprecated
|
||||||
|
*/
|
||||||
|
virtual int length() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the length of the file in seconds. The length is rounded down to
|
||||||
|
* the nearest whole second.
|
||||||
|
*
|
||||||
|
* \see lengthInMilliseconds()
|
||||||
|
*/
|
||||||
|
// BIC: make virtual
|
||||||
|
int lengthInSeconds() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the length of the file in milliseconds.
|
||||||
|
*
|
||||||
|
* \see lengthInSeconds()
|
||||||
|
*/
|
||||||
|
// BIC: make virtual
|
||||||
|
int lengthInMilliseconds() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the average bit rate of the file in kb/s.
|
||||||
|
*/
|
||||||
|
virtual int bitrate() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the sample rate in Hz.
|
||||||
|
*/
|
||||||
|
virtual int sampleRate() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the number of audio channels.
|
||||||
|
*/
|
||||||
|
virtual int channels() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the number of bits per audio sample.
|
||||||
|
*/
|
||||||
|
int bitsPerSample() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the total number of audio samples in file.
|
||||||
|
*/
|
||||||
|
unsigned int sampleFrames() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns APE version.
|
||||||
|
*/
|
||||||
|
int version() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Properties(const Properties &);
|
||||||
|
Properties &operator=(const Properties &);
|
||||||
|
|
||||||
|
void read(File *file, long streamLength);
|
||||||
|
|
||||||
|
void analyzeCurrent(File *file);
|
||||||
|
void analyzeOld(File *file);
|
||||||
|
|
||||||
|
class PropertiesPrivate;
|
||||||
|
PropertiesPrivate *d;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
437
3rdparty/taglib/ape/apetag.cpp
vendored
Normal file
437
3rdparty/taglib/ape/apetag.cpp
vendored
Normal file
@@ -0,0 +1,437 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
copyright : (C) 2004 by Allan Sandfeld Jensen
|
||||||
|
email : kde@carewolf.com
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#if defined(__SUNPRO_CC) && (__SUNPRO_CC < 0x5130)
|
||||||
|
// Sun Studio finds multiple specializations of Map because
|
||||||
|
// it considers specializations with and without class types
|
||||||
|
// to be different; this define forces Map to use only the
|
||||||
|
// specialization with the class keyword.
|
||||||
|
#define WANT_CLASS_INSTANTIATION_OF_MAP (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <tfile.h>
|
||||||
|
#include <tstring.h>
|
||||||
|
#include <tmap.h>
|
||||||
|
#include <tpropertymap.h>
|
||||||
|
#include <tdebug.h>
|
||||||
|
#include <tutils.h>
|
||||||
|
|
||||||
|
#include "apetag.h"
|
||||||
|
#include "apefooter.h"
|
||||||
|
#include "apeitem.h"
|
||||||
|
|
||||||
|
using namespace TagLib;
|
||||||
|
using namespace APE;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
const unsigned int MinKeyLength = 2;
|
||||||
|
const unsigned int MaxKeyLength = 255;
|
||||||
|
|
||||||
|
bool isKeyValid(const ByteVector &key)
|
||||||
|
{
|
||||||
|
const char *invalidKeys[] = { "ID3", "TAG", "OGGS", "MP+", 0 };
|
||||||
|
|
||||||
|
// only allow printable ASCII including space (32..126)
|
||||||
|
|
||||||
|
for(ByteVector::ConstIterator it = key.begin(); it != key.end(); ++it) {
|
||||||
|
const int c = static_cast<unsigned char>(*it);
|
||||||
|
if(c < 32 || c > 126)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const String upperKey = String(key).upper();
|
||||||
|
for(size_t i = 0; invalidKeys[i] != 0; ++i) {
|
||||||
|
if(upperKey == invalidKeys[i])
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class APE::Tag::TagPrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TagPrivate() :
|
||||||
|
file(0),
|
||||||
|
footerLocation(0) {}
|
||||||
|
|
||||||
|
File *file;
|
||||||
|
long footerLocation;
|
||||||
|
|
||||||
|
Footer footer;
|
||||||
|
ItemListMap itemListMap;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// public methods
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
APE::Tag::Tag() :
|
||||||
|
TagLib::Tag(),
|
||||||
|
d(new TagPrivate())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
APE::Tag::Tag(TagLib::File *file, long footerLocation) :
|
||||||
|
TagLib::Tag(),
|
||||||
|
d(new TagPrivate())
|
||||||
|
{
|
||||||
|
d->file = file;
|
||||||
|
d->footerLocation = footerLocation;
|
||||||
|
|
||||||
|
read();
|
||||||
|
}
|
||||||
|
|
||||||
|
APE::Tag::~Tag()
|
||||||
|
{
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector APE::Tag::fileIdentifier()
|
||||||
|
{
|
||||||
|
return ByteVector::fromCString("APETAGEX");
|
||||||
|
}
|
||||||
|
|
||||||
|
String APE::Tag::title() const
|
||||||
|
{
|
||||||
|
if(d->itemListMap["TITLE"].isEmpty())
|
||||||
|
return String();
|
||||||
|
return d->itemListMap["TITLE"].values().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
String APE::Tag::artist() const
|
||||||
|
{
|
||||||
|
if(d->itemListMap["ARTIST"].isEmpty())
|
||||||
|
return String();
|
||||||
|
return d->itemListMap["ARTIST"].values().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
String APE::Tag::album() const
|
||||||
|
{
|
||||||
|
if(d->itemListMap["ALBUM"].isEmpty())
|
||||||
|
return String();
|
||||||
|
return d->itemListMap["ALBUM"].values().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
String APE::Tag::comment() const
|
||||||
|
{
|
||||||
|
if(d->itemListMap["COMMENT"].isEmpty())
|
||||||
|
return String();
|
||||||
|
return d->itemListMap["COMMENT"].values().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
String APE::Tag::genre() const
|
||||||
|
{
|
||||||
|
if(d->itemListMap["GENRE"].isEmpty())
|
||||||
|
return String();
|
||||||
|
return d->itemListMap["GENRE"].values().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int APE::Tag::year() const
|
||||||
|
{
|
||||||
|
if(d->itemListMap["YEAR"].isEmpty())
|
||||||
|
return 0;
|
||||||
|
return d->itemListMap["YEAR"].toString().toInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int APE::Tag::track() const
|
||||||
|
{
|
||||||
|
if(d->itemListMap["TRACK"].isEmpty())
|
||||||
|
return 0;
|
||||||
|
return d->itemListMap["TRACK"].toString().toInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
void APE::Tag::setTitle(const String &s)
|
||||||
|
{
|
||||||
|
addValue("TITLE", s, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void APE::Tag::setArtist(const String &s)
|
||||||
|
{
|
||||||
|
addValue("ARTIST", s, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void APE::Tag::setAlbum(const String &s)
|
||||||
|
{
|
||||||
|
addValue("ALBUM", s, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void APE::Tag::setComment(const String &s)
|
||||||
|
{
|
||||||
|
addValue("COMMENT", s, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void APE::Tag::setGenre(const String &s)
|
||||||
|
{
|
||||||
|
addValue("GENRE", s, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void APE::Tag::setYear(unsigned int i)
|
||||||
|
{
|
||||||
|
if(i == 0)
|
||||||
|
removeItem("YEAR");
|
||||||
|
else
|
||||||
|
addValue("YEAR", String::number(i), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void APE::Tag::setTrack(unsigned int i)
|
||||||
|
{
|
||||||
|
if(i == 0)
|
||||||
|
removeItem("TRACK");
|
||||||
|
else
|
||||||
|
addValue("TRACK", String::number(i), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
// conversions of tag keys between what we use in PropertyMap and what's usual
|
||||||
|
// for APE tags
|
||||||
|
// usual, APE
|
||||||
|
const char *keyConversions[][2] = {{"TRACKNUMBER", "TRACK" },
|
||||||
|
{"DATE", "YEAR" },
|
||||||
|
{"ALBUMARTIST", "ALBUM ARTIST"},
|
||||||
|
{"DISCNUMBER", "DISC" },
|
||||||
|
{"REMIXER", "MIXARTIST" }};
|
||||||
|
const size_t keyConversionsSize = sizeof(keyConversions) / sizeof(keyConversions[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyMap APE::Tag::properties() const
|
||||||
|
{
|
||||||
|
PropertyMap properties;
|
||||||
|
ItemListMap::ConstIterator it = itemListMap().begin();
|
||||||
|
for(; it != itemListMap().end(); ++it) {
|
||||||
|
String tagName = it->first.upper();
|
||||||
|
// if the item is Binary or Locator, or if the key is an invalid string,
|
||||||
|
// add to unsupportedData
|
||||||
|
if(it->second.type() != Item::Text || tagName.isEmpty()) {
|
||||||
|
properties.unsupportedData().append(it->first);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Some tags need to be handled specially
|
||||||
|
for(size_t i = 0; i < keyConversionsSize; ++i) {
|
||||||
|
if(tagName == keyConversions[i][1])
|
||||||
|
tagName = keyConversions[i][0];
|
||||||
|
}
|
||||||
|
properties[tagName].append(it->second.toStringList());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
void APE::Tag::removeUnsupportedProperties(const StringList &properties)
|
||||||
|
{
|
||||||
|
StringList::ConstIterator it = properties.begin();
|
||||||
|
for(; it != properties.end(); ++it)
|
||||||
|
removeItem(*it);
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyMap APE::Tag::setProperties(const PropertyMap &origProps)
|
||||||
|
{
|
||||||
|
PropertyMap properties(origProps); // make a local copy that can be modified
|
||||||
|
|
||||||
|
// see comment in properties()
|
||||||
|
for(size_t i = 0; i < keyConversionsSize; ++i)
|
||||||
|
if(properties.contains(keyConversions[i][0])) {
|
||||||
|
properties.insert(keyConversions[i][1], properties[keyConversions[i][0]]);
|
||||||
|
properties.erase(keyConversions[i][0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// first check if tags need to be removed completely
|
||||||
|
StringList toRemove;
|
||||||
|
ItemListMap::ConstIterator remIt = itemListMap().begin();
|
||||||
|
for(; remIt != itemListMap().end(); ++remIt) {
|
||||||
|
String key = remIt->first.upper();
|
||||||
|
// only remove if a) key is valid, b) type is text, c) key not contained in new properties
|
||||||
|
if(!key.isEmpty() && remIt->second.type() == APE::Item::Text && !properties.contains(key))
|
||||||
|
toRemove.append(remIt->first);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(StringList::ConstIterator removeIt = toRemove.begin(); removeIt != toRemove.end(); removeIt++)
|
||||||
|
removeItem(*removeIt);
|
||||||
|
|
||||||
|
// now sync in the "forward direction"
|
||||||
|
PropertyMap::ConstIterator it = properties.begin();
|
||||||
|
PropertyMap invalid;
|
||||||
|
for(; it != properties.end(); ++it) {
|
||||||
|
const String &tagName = it->first;
|
||||||
|
if(!checkKey(tagName))
|
||||||
|
invalid.insert(it->first, it->second);
|
||||||
|
else if(!(itemListMap().contains(tagName)) || !(itemListMap()[tagName].values() == it->second)) {
|
||||||
|
if(it->second.isEmpty())
|
||||||
|
removeItem(tagName);
|
||||||
|
else {
|
||||||
|
StringList::ConstIterator valueIt = it->second.begin();
|
||||||
|
addValue(tagName, *valueIt, true);
|
||||||
|
++valueIt;
|
||||||
|
for(; valueIt != it->second.end(); ++valueIt)
|
||||||
|
addValue(tagName, *valueIt, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool APE::Tag::checkKey(const String &key)
|
||||||
|
{
|
||||||
|
if(key.size() < MinKeyLength || key.size() > MaxKeyLength)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return isKeyValid(key.data(String::UTF8));
|
||||||
|
}
|
||||||
|
|
||||||
|
APE::Footer *APE::Tag::footer() const
|
||||||
|
{
|
||||||
|
return &d->footer;
|
||||||
|
}
|
||||||
|
|
||||||
|
const APE::ItemListMap& APE::Tag::itemListMap() const
|
||||||
|
{
|
||||||
|
return d->itemListMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
void APE::Tag::removeItem(const String &key)
|
||||||
|
{
|
||||||
|
d->itemListMap.erase(key.upper());
|
||||||
|
}
|
||||||
|
|
||||||
|
void APE::Tag::addValue(const String &key, const String &value, bool replace)
|
||||||
|
{
|
||||||
|
if(replace)
|
||||||
|
removeItem(key);
|
||||||
|
|
||||||
|
if(value.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Text items may contain more than one value.
|
||||||
|
// Binary or locator items may have only one value, hence always replaced.
|
||||||
|
|
||||||
|
ItemListMap::Iterator it = d->itemListMap.find(key.upper());
|
||||||
|
|
||||||
|
if(it != d->itemListMap.end() && it->second.type() == Item::Text)
|
||||||
|
it->second.appendValue(value);
|
||||||
|
else
|
||||||
|
setItem(key, Item(key, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
void APE::Tag::setData(const String &key, const ByteVector &value)
|
||||||
|
{
|
||||||
|
removeItem(key);
|
||||||
|
|
||||||
|
if(value.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
setItem(key, Item(key, value, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
void APE::Tag::setItem(const String &key, const Item &item)
|
||||||
|
{
|
||||||
|
if(!checkKey(key)) {
|
||||||
|
debug("APE::Tag::setItem() - Couldn't set an item due to an invalid key.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
d->itemListMap[key.upper()] = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool APE::Tag::isEmpty() const
|
||||||
|
{
|
||||||
|
return d->itemListMap.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// protected methods
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void APE::Tag::read()
|
||||||
|
{
|
||||||
|
if(d->file && d->file->isValid()) {
|
||||||
|
|
||||||
|
d->file->seek(d->footerLocation);
|
||||||
|
d->footer.setData(d->file->readBlock(Footer::size()));
|
||||||
|
|
||||||
|
if(d->footer.tagSize() <= Footer::size() ||
|
||||||
|
d->footer.tagSize() > static_cast<unsigned long>(d->file->length()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
d->file->seek(d->footerLocation + Footer::size() - d->footer.tagSize());
|
||||||
|
parse(d->file->readBlock(d->footer.tagSize() - Footer::size()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector APE::Tag::render() const
|
||||||
|
{
|
||||||
|
ByteVector data;
|
||||||
|
unsigned int itemCount = 0;
|
||||||
|
|
||||||
|
for(ItemListMap::ConstIterator it = d->itemListMap.begin(); it != d->itemListMap.end(); ++it) {
|
||||||
|
data.append(it->second.render());
|
||||||
|
itemCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
d->footer.setItemCount(itemCount);
|
||||||
|
d->footer.setTagSize(data.size() + Footer::size());
|
||||||
|
d->footer.setHeaderPresent(true);
|
||||||
|
|
||||||
|
return d->footer.renderHeader() + data + d->footer.renderFooter();
|
||||||
|
}
|
||||||
|
|
||||||
|
void APE::Tag::parse(const ByteVector &data)
|
||||||
|
{
|
||||||
|
// 11 bytes is the minimum size for an APE item
|
||||||
|
|
||||||
|
if(data.size() < 11)
|
||||||
|
return;
|
||||||
|
|
||||||
|
unsigned int pos = 0;
|
||||||
|
|
||||||
|
for(unsigned int i = 0; i < d->footer.itemCount() && pos <= data.size() - 11; i++) {
|
||||||
|
|
||||||
|
const int nullPos = data.find('\0', pos + 8);
|
||||||
|
if(nullPos < 0) {
|
||||||
|
debug("APE::Tag::parse() - Couldn't find a key/value separator. Stopped parsing.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const unsigned int keyLength = nullPos - pos - 8;
|
||||||
|
const unsigned int valLegnth = data.toUInt(pos, false);
|
||||||
|
|
||||||
|
if(keyLength >= MinKeyLength
|
||||||
|
&& keyLength <= MaxKeyLength
|
||||||
|
&& isKeyValid(data.mid(pos + 8, keyLength)))
|
||||||
|
{
|
||||||
|
APE::Item item;
|
||||||
|
item.parse(data.mid(pos));
|
||||||
|
|
||||||
|
d->itemListMap.insert(item.key().upper(), item);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
debug("APE::Tag::parse() - Skipped an item due to an invalid key.");
|
||||||
|
}
|
||||||
|
|
||||||
|
pos += keyLength + valLegnth + 9;
|
||||||
|
}
|
||||||
|
}
|
||||||
208
3rdparty/taglib/ape/apetag.h
vendored
Normal file
208
3rdparty/taglib/ape/apetag.h
vendored
Normal file
@@ -0,0 +1,208 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
copyright : (C) 2004 by Allan Sandfeld Jensen
|
||||||
|
email : kde@carewolf.org
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef TAGLIB_APETAG_H
|
||||||
|
#define TAGLIB_APETAG_H
|
||||||
|
|
||||||
|
#include "tag.h"
|
||||||
|
#include "tbytevector.h"
|
||||||
|
#include "tmap.h"
|
||||||
|
#include "tstring.h"
|
||||||
|
#include "taglib_export.h"
|
||||||
|
|
||||||
|
#include "apeitem.h"
|
||||||
|
|
||||||
|
namespace TagLib {
|
||||||
|
|
||||||
|
class File;
|
||||||
|
|
||||||
|
//! An implementation of the APE tagging format
|
||||||
|
|
||||||
|
namespace APE {
|
||||||
|
|
||||||
|
class Footer;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* A mapping between a list of item names, or keys, and the associated item.
|
||||||
|
*
|
||||||
|
* \see APE::Tag::itemListMap()
|
||||||
|
*/
|
||||||
|
typedef Map<const String, Item> ItemListMap;
|
||||||
|
|
||||||
|
|
||||||
|
//! An APE tag implementation
|
||||||
|
|
||||||
|
class TAGLIB_EXPORT Tag : public TagLib::Tag
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/*!
|
||||||
|
* Create an APE tag with default values.
|
||||||
|
*/
|
||||||
|
Tag();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Create an APE tag and parse the data in \a file with APE footer at
|
||||||
|
* \a tagOffset.
|
||||||
|
*/
|
||||||
|
Tag(TagLib::File *file, long footerLocation);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Destroys this Tag instance.
|
||||||
|
*/
|
||||||
|
virtual ~Tag();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Renders the in memory values to a ByteVector suitable for writing to
|
||||||
|
* the file.
|
||||||
|
*/
|
||||||
|
ByteVector render() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the string "APETAGEX" suitable for usage in locating the tag in a
|
||||||
|
* file.
|
||||||
|
*/
|
||||||
|
static ByteVector fileIdentifier();
|
||||||
|
|
||||||
|
// Reimplementations.
|
||||||
|
|
||||||
|
virtual String title() const;
|
||||||
|
virtual String artist() const;
|
||||||
|
virtual String album() const;
|
||||||
|
virtual String comment() const;
|
||||||
|
virtual String genre() const;
|
||||||
|
virtual unsigned int year() const;
|
||||||
|
virtual unsigned int track() const;
|
||||||
|
|
||||||
|
virtual void setTitle(const String &s);
|
||||||
|
virtual void setArtist(const String &s);
|
||||||
|
virtual void setAlbum(const String &s);
|
||||||
|
virtual void setComment(const String &s);
|
||||||
|
virtual void setGenre(const String &s);
|
||||||
|
virtual void setYear(unsigned int i);
|
||||||
|
virtual void setTrack(unsigned int i);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Implements the unified tag dictionary interface -- export function.
|
||||||
|
* APE tags are perfectly compatible with the dictionary interface because they
|
||||||
|
* support both arbitrary tag names and multiple values. Currently only
|
||||||
|
* APE items of type *Text* are handled by the dictionary interface; all *Binary*
|
||||||
|
* and *Locator* items will be put into the unsupportedData list and can be
|
||||||
|
* deleted on request using removeUnsupportedProperties(). The same happens
|
||||||
|
* to Text items if their key is invalid for PropertyMap (which should actually
|
||||||
|
* never happen).
|
||||||
|
*
|
||||||
|
* The only conversion done by this export function is to rename the APE tags
|
||||||
|
* TRACK to TRACKNUMBER, YEAR to DATE, and ALBUM ARTIST to ALBUMARTIST, respectively,
|
||||||
|
* in order to be compliant with the names used in other formats.
|
||||||
|
*/
|
||||||
|
PropertyMap properties() const;
|
||||||
|
|
||||||
|
void removeUnsupportedProperties(const StringList &properties);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Implements the unified tag dictionary interface -- import function. The same
|
||||||
|
* comments as for the export function apply; additionally note that the APE tag
|
||||||
|
* specification requires keys to have between 2 and 16 printable ASCII characters
|
||||||
|
* with the exception of the fixed strings "ID3", "TAG", "OGGS", and "MP+".
|
||||||
|
*/
|
||||||
|
PropertyMap setProperties(const PropertyMap &);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Check if the given String is a valid APE tag key.
|
||||||
|
*/
|
||||||
|
static bool checkKey(const String&);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns a pointer to the tag's footer.
|
||||||
|
*/
|
||||||
|
Footer *footer() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns a reference to the item list map. This is an ItemListMap of
|
||||||
|
* all of the items in the tag.
|
||||||
|
*
|
||||||
|
* This is the most powerful structure for accessing the items of the tag.
|
||||||
|
*
|
||||||
|
* APE tags are case-insensitive, all keys in this map have been converted
|
||||||
|
* to upper case.
|
||||||
|
*
|
||||||
|
* \warning You should not modify this data structure directly, instead
|
||||||
|
* use setItem() and removeItem().
|
||||||
|
*/
|
||||||
|
const ItemListMap &itemListMap() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Removes the \a key item from the tag
|
||||||
|
*/
|
||||||
|
void removeItem(const String &key);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Adds to the text item specified by \a key the data \a value. If \a replace
|
||||||
|
* is true, then all of the other values on the same key will be removed
|
||||||
|
* first. If a binary item exists for \a key it will be removed first.
|
||||||
|
*/
|
||||||
|
void addValue(const String &key, const String &value, bool replace = true);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Set the binary data for the key specified by \a item to \a value
|
||||||
|
* This will convert the item to type \a Binary if it isn't already and
|
||||||
|
* all of the other values on the same key will be removed.
|
||||||
|
*/
|
||||||
|
void setData(const String &key, const ByteVector &value);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets the \a key item to the value of \a item. If an item with the \a key is already
|
||||||
|
* present, it will be replaced.
|
||||||
|
*/
|
||||||
|
void setItem(const String &key, const Item &item);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns true if the tag does not contain any data.
|
||||||
|
*/
|
||||||
|
bool isEmpty() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Reads from the file specified in the constructor.
|
||||||
|
*/
|
||||||
|
void read();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Parses the body of the tag in \a data.
|
||||||
|
*/
|
||||||
|
void parse(const ByteVector &data);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Tag(const Tag &);
|
||||||
|
Tag &operator=(const Tag &);
|
||||||
|
|
||||||
|
class TagPrivate;
|
||||||
|
TagPrivate *d;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
351
3rdparty/taglib/asf/asfattribute.cpp
vendored
Normal file
351
3rdparty/taglib/asf/asfattribute.cpp
vendored
Normal file
@@ -0,0 +1,351 @@
|
|||||||
|
/**************************************************************************
|
||||||
|
copyright : (C) 2005-2007 by Lukáš Lalinský
|
||||||
|
email : lalinsky@gmail.com
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include <taglib.h>
|
||||||
|
#include <tdebug.h>
|
||||||
|
#include <trefcounter.h>
|
||||||
|
|
||||||
|
#include "asfattribute.h"
|
||||||
|
#include "asffile.h"
|
||||||
|
#include "asfutils.h"
|
||||||
|
|
||||||
|
using namespace TagLib;
|
||||||
|
|
||||||
|
class ASF::Attribute::AttributePrivate : public RefCounter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AttributePrivate() :
|
||||||
|
pictureValue(ASF::Picture::fromInvalid()),
|
||||||
|
numericValue(0),
|
||||||
|
stream(0),
|
||||||
|
language(0) {}
|
||||||
|
AttributeTypes type;
|
||||||
|
String stringValue;
|
||||||
|
ByteVector byteVectorValue;
|
||||||
|
ASF::Picture pictureValue;
|
||||||
|
unsigned long long numericValue;
|
||||||
|
int stream;
|
||||||
|
int language;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// public members
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
ASF::Attribute::Attribute() :
|
||||||
|
d(new AttributePrivate())
|
||||||
|
{
|
||||||
|
d->type = UnicodeType;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASF::Attribute::Attribute(const ASF::Attribute &other) :
|
||||||
|
d(other.d)
|
||||||
|
{
|
||||||
|
d->ref();
|
||||||
|
}
|
||||||
|
|
||||||
|
ASF::Attribute::Attribute(const String &value) :
|
||||||
|
d(new AttributePrivate())
|
||||||
|
{
|
||||||
|
d->type = UnicodeType;
|
||||||
|
d->stringValue = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASF::Attribute::Attribute(const ByteVector &value) :
|
||||||
|
d(new AttributePrivate())
|
||||||
|
{
|
||||||
|
d->type = BytesType;
|
||||||
|
d->byteVectorValue = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASF::Attribute::Attribute(const ASF::Picture &value) :
|
||||||
|
d(new AttributePrivate())
|
||||||
|
{
|
||||||
|
d->type = BytesType;
|
||||||
|
d->pictureValue = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASF::Attribute::Attribute(unsigned int value) :
|
||||||
|
d(new AttributePrivate())
|
||||||
|
{
|
||||||
|
d->type = DWordType;
|
||||||
|
d->numericValue = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASF::Attribute::Attribute(unsigned long long value) :
|
||||||
|
d(new AttributePrivate())
|
||||||
|
{
|
||||||
|
d->type = QWordType;
|
||||||
|
d->numericValue = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASF::Attribute::Attribute(unsigned short value) :
|
||||||
|
d(new AttributePrivate())
|
||||||
|
{
|
||||||
|
d->type = WordType;
|
||||||
|
d->numericValue = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASF::Attribute::Attribute(bool value) :
|
||||||
|
d(new AttributePrivate())
|
||||||
|
{
|
||||||
|
d->type = BoolType;
|
||||||
|
d->numericValue = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASF::Attribute &ASF::Attribute::operator=(const ASF::Attribute &other)
|
||||||
|
{
|
||||||
|
Attribute(other).swap(*this);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ASF::Attribute::swap(Attribute &other)
|
||||||
|
{
|
||||||
|
using std::swap;
|
||||||
|
|
||||||
|
swap(d, other.d);
|
||||||
|
}
|
||||||
|
|
||||||
|
ASF::Attribute::~Attribute()
|
||||||
|
{
|
||||||
|
if(d->deref())
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASF::Attribute::AttributeTypes ASF::Attribute::type() const
|
||||||
|
{
|
||||||
|
return d->type;
|
||||||
|
}
|
||||||
|
|
||||||
|
String ASF::Attribute::toString() const
|
||||||
|
{
|
||||||
|
return d->stringValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector ASF::Attribute::toByteVector() const
|
||||||
|
{
|
||||||
|
if(d->pictureValue.isValid())
|
||||||
|
return d->pictureValue.render();
|
||||||
|
return d->byteVectorValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned short ASF::Attribute::toBool() const
|
||||||
|
{
|
||||||
|
return d->numericValue ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned short ASF::Attribute::toUShort() const
|
||||||
|
{
|
||||||
|
return static_cast<unsigned short>(d->numericValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int ASF::Attribute::toUInt() const
|
||||||
|
{
|
||||||
|
return static_cast<unsigned int>(d->numericValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long long ASF::Attribute::toULongLong() const
|
||||||
|
{
|
||||||
|
return static_cast<unsigned long long>(d->numericValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
ASF::Picture ASF::Attribute::toPicture() const
|
||||||
|
{
|
||||||
|
return d->pictureValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
String ASF::Attribute::parse(ASF::File &f, int kind)
|
||||||
|
{
|
||||||
|
unsigned int size, nameLength;
|
||||||
|
String name;
|
||||||
|
d->pictureValue = Picture::fromInvalid();
|
||||||
|
// extended content descriptor
|
||||||
|
if(kind == 0) {
|
||||||
|
nameLength = readWORD(&f);
|
||||||
|
name = readString(&f, nameLength);
|
||||||
|
d->type = ASF::Attribute::AttributeTypes(readWORD(&f));
|
||||||
|
size = readWORD(&f);
|
||||||
|
}
|
||||||
|
// metadata & metadata library
|
||||||
|
else {
|
||||||
|
int temp = readWORD(&f);
|
||||||
|
// metadata library
|
||||||
|
if(kind == 2) {
|
||||||
|
d->language = temp;
|
||||||
|
}
|
||||||
|
d->stream = readWORD(&f);
|
||||||
|
nameLength = readWORD(&f);
|
||||||
|
d->type = ASF::Attribute::AttributeTypes(readWORD(&f));
|
||||||
|
size = readDWORD(&f);
|
||||||
|
name = readString(&f, nameLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(kind != 2 && size > 65535) {
|
||||||
|
debug("ASF::Attribute::parse() -- Value larger than 64kB");
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(d->type) {
|
||||||
|
case WordType:
|
||||||
|
d->numericValue = readWORD(&f);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BoolType:
|
||||||
|
if(kind == 0) {
|
||||||
|
d->numericValue = (readDWORD(&f) != 0);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
d->numericValue = (readWORD(&f) != 0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DWordType:
|
||||||
|
d->numericValue = readDWORD(&f);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case QWordType:
|
||||||
|
d->numericValue = readQWORD(&f);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case UnicodeType:
|
||||||
|
d->stringValue = readString(&f, size);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BytesType:
|
||||||
|
case GuidType:
|
||||||
|
d->byteVectorValue = f.readBlock(size);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(d->type == BytesType && name == "WM/Picture") {
|
||||||
|
d->pictureValue.parse(d->byteVectorValue);
|
||||||
|
if(d->pictureValue.isValid()) {
|
||||||
|
d->byteVectorValue.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ASF::Attribute::dataSize() const
|
||||||
|
{
|
||||||
|
switch (d->type) {
|
||||||
|
case WordType:
|
||||||
|
return 2;
|
||||||
|
case BoolType:
|
||||||
|
return 4;
|
||||||
|
case DWordType:
|
||||||
|
return 4;
|
||||||
|
case QWordType:
|
||||||
|
return 5;
|
||||||
|
case UnicodeType:
|
||||||
|
return d->stringValue.size() * 2 + 2;
|
||||||
|
case BytesType:
|
||||||
|
if(d->pictureValue.isValid())
|
||||||
|
return d->pictureValue.dataSize();
|
||||||
|
case GuidType:
|
||||||
|
return d->byteVectorValue.size();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector ASF::Attribute::render(const String &name, int kind) const
|
||||||
|
{
|
||||||
|
ByteVector data;
|
||||||
|
|
||||||
|
switch (d->type) {
|
||||||
|
case WordType:
|
||||||
|
data.append(ByteVector::fromShort(toUShort(), false));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BoolType:
|
||||||
|
if(kind == 0) {
|
||||||
|
data.append(ByteVector::fromUInt(toBool(), false));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
data.append(ByteVector::fromShort(toBool(), false));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DWordType:
|
||||||
|
data.append(ByteVector::fromUInt(toUInt(), false));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case QWordType:
|
||||||
|
data.append(ByteVector::fromLongLong(toULongLong(), false));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case UnicodeType:
|
||||||
|
data.append(renderString(d->stringValue));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BytesType:
|
||||||
|
if(d->pictureValue.isValid()) {
|
||||||
|
data.append(d->pictureValue.render());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case GuidType:
|
||||||
|
data.append(d->byteVectorValue);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(kind == 0) {
|
||||||
|
data = renderString(name, true) +
|
||||||
|
ByteVector::fromShort((int)d->type, false) +
|
||||||
|
ByteVector::fromShort(data.size(), false) +
|
||||||
|
data;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ByteVector nameData = renderString(name);
|
||||||
|
data = ByteVector::fromShort(kind == 2 ? d->language : 0, false) +
|
||||||
|
ByteVector::fromShort(d->stream, false) +
|
||||||
|
ByteVector::fromShort(nameData.size(), false) +
|
||||||
|
ByteVector::fromShort((int)d->type, false) +
|
||||||
|
ByteVector::fromUInt(data.size(), false) +
|
||||||
|
nameData +
|
||||||
|
data;
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ASF::Attribute::language() const
|
||||||
|
{
|
||||||
|
return d->language;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ASF::Attribute::setLanguage(int value)
|
||||||
|
{
|
||||||
|
d->language = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ASF::Attribute::stream() const
|
||||||
|
{
|
||||||
|
return d->stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ASF::Attribute::setStream(int value)
|
||||||
|
{
|
||||||
|
d->stream = value;
|
||||||
|
}
|
||||||
208
3rdparty/taglib/asf/asfattribute.h
vendored
Normal file
208
3rdparty/taglib/asf/asfattribute.h
vendored
Normal file
@@ -0,0 +1,208 @@
|
|||||||
|
/**************************************************************************
|
||||||
|
copyright : (C) 2005-2007 by Lukáš Lalinský
|
||||||
|
email : lalinsky@gmail.com
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef TAGLIB_ASFATTRIBUTE_H
|
||||||
|
#define TAGLIB_ASFATTRIBUTE_H
|
||||||
|
|
||||||
|
#include "tstring.h"
|
||||||
|
#include "tbytevector.h"
|
||||||
|
#include "taglib_export.h"
|
||||||
|
#include "asfpicture.h"
|
||||||
|
|
||||||
|
namespace TagLib
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace ASF
|
||||||
|
{
|
||||||
|
|
||||||
|
class File;
|
||||||
|
class Picture;
|
||||||
|
|
||||||
|
class TAGLIB_EXPORT Attribute
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Enum of types an Attribute can have.
|
||||||
|
*/
|
||||||
|
enum AttributeTypes {
|
||||||
|
UnicodeType = 0,
|
||||||
|
BytesType = 1,
|
||||||
|
BoolType = 2,
|
||||||
|
DWordType = 3,
|
||||||
|
QWordType = 4,
|
||||||
|
WordType = 5,
|
||||||
|
GuidType = 6
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Constructs an empty attribute.
|
||||||
|
*/
|
||||||
|
Attribute();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Constructs an attribute with \a key and a UnicodeType \a value.
|
||||||
|
*/
|
||||||
|
Attribute(const String &value);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Constructs an attribute with \a key and a BytesType \a value.
|
||||||
|
*/
|
||||||
|
Attribute(const ByteVector &value);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Constructs an attribute with \a key and a Picture \a value.
|
||||||
|
*
|
||||||
|
* This attribute is compatible with the ID3 frame, APIC. The ID3 specification for the APIC frame stipulates that,
|
||||||
|
* while there may be any number of APIC frames associated with a file,
|
||||||
|
* only one may be of type 1 and only one may be of type 2.
|
||||||
|
*
|
||||||
|
* The specification also states that the description of the picture can be no longer than 64 characters, but can be empty.
|
||||||
|
* WM/Picture attributes added with TagLib::ASF are not automatically validated to conform to ID3 specifications.
|
||||||
|
* You must add code in your application to perform validations if you want to maintain complete compatibility with ID3.
|
||||||
|
*/
|
||||||
|
Attribute(const Picture &value);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Constructs an attribute with \a key and a DWordType \a value.
|
||||||
|
*/
|
||||||
|
Attribute(unsigned int value);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Constructs an attribute with \a key and a QWordType \a value.
|
||||||
|
*/
|
||||||
|
Attribute(unsigned long long value);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Constructs an attribute with \a key and a WordType \a value.
|
||||||
|
*/
|
||||||
|
Attribute(unsigned short value);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Constructs an attribute with \a key and a BoolType \a value.
|
||||||
|
*/
|
||||||
|
Attribute(bool value);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Construct an attribute as a copy of \a other.
|
||||||
|
*/
|
||||||
|
Attribute(const Attribute &item);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Copies the contents of \a other into this item.
|
||||||
|
*/
|
||||||
|
Attribute &operator=(const Attribute &other);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Exchanges the content of the Attribute by the content of \a other.
|
||||||
|
*/
|
||||||
|
void swap(Attribute &other);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Destroys the attribute.
|
||||||
|
*/
|
||||||
|
virtual ~Attribute();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns type of the value.
|
||||||
|
*/
|
||||||
|
AttributeTypes type() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the BoolType \a value.
|
||||||
|
*/
|
||||||
|
unsigned short toBool() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the WordType \a value.
|
||||||
|
*/
|
||||||
|
unsigned short toUShort() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the DWordType \a value.
|
||||||
|
*/
|
||||||
|
unsigned int toUInt() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the QWordType \a value.
|
||||||
|
*/
|
||||||
|
unsigned long long toULongLong() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the UnicodeType \a value.
|
||||||
|
*/
|
||||||
|
String toString() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the BytesType \a value.
|
||||||
|
*/
|
||||||
|
ByteVector toByteVector() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the Picture \a value.
|
||||||
|
*/
|
||||||
|
Picture toPicture() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the language number, or 0 is no stream number was set.
|
||||||
|
*/
|
||||||
|
int language() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets the language number.
|
||||||
|
*/
|
||||||
|
void setLanguage(int value);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the stream number, or 0 is no stream number was set.
|
||||||
|
*/
|
||||||
|
int stream() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets the stream number.
|
||||||
|
*/
|
||||||
|
void setStream(int value);
|
||||||
|
|
||||||
|
#ifndef DO_NOT_DOCUMENT
|
||||||
|
/* THIS IS PRIVATE, DON'T TOUCH IT! */
|
||||||
|
String parse(ASF::File &file, int kind = 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//! Returns the size of the stored data
|
||||||
|
int dataSize() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class File;
|
||||||
|
|
||||||
|
ByteVector render(const String &name, int kind = 0) const;
|
||||||
|
|
||||||
|
class AttributePrivate;
|
||||||
|
AttributePrivate *d;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
705
3rdparty/taglib/asf/asffile.cpp
vendored
Normal file
705
3rdparty/taglib/asf/asffile.cpp
vendored
Normal file
@@ -0,0 +1,705 @@
|
|||||||
|
/**************************************************************************
|
||||||
|
copyright : (C) 2005-2007 by Lukáš Lalinský
|
||||||
|
email : lalinsky@gmail.com
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include <tdebug.h>
|
||||||
|
#include <tbytevectorlist.h>
|
||||||
|
#include <tpropertymap.h>
|
||||||
|
#include <tstring.h>
|
||||||
|
#include <tagutils.h>
|
||||||
|
|
||||||
|
#include "asffile.h"
|
||||||
|
#include "asftag.h"
|
||||||
|
#include "asfproperties.h"
|
||||||
|
#include "asfutils.h"
|
||||||
|
|
||||||
|
using namespace TagLib;
|
||||||
|
|
||||||
|
class ASF::File::FilePrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
class BaseObject;
|
||||||
|
class UnknownObject;
|
||||||
|
class FilePropertiesObject;
|
||||||
|
class StreamPropertiesObject;
|
||||||
|
class ContentDescriptionObject;
|
||||||
|
class ExtendedContentDescriptionObject;
|
||||||
|
class HeaderExtensionObject;
|
||||||
|
class CodecListObject;
|
||||||
|
class MetadataObject;
|
||||||
|
class MetadataLibraryObject;
|
||||||
|
|
||||||
|
FilePrivate():
|
||||||
|
headerSize(0),
|
||||||
|
tag(0),
|
||||||
|
properties(0),
|
||||||
|
contentDescriptionObject(0),
|
||||||
|
extendedContentDescriptionObject(0),
|
||||||
|
headerExtensionObject(0),
|
||||||
|
metadataObject(0),
|
||||||
|
metadataLibraryObject(0)
|
||||||
|
{
|
||||||
|
objects.setAutoDelete(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
~FilePrivate()
|
||||||
|
{
|
||||||
|
delete tag;
|
||||||
|
delete properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long long headerSize;
|
||||||
|
|
||||||
|
ASF::Tag *tag;
|
||||||
|
ASF::Properties *properties;
|
||||||
|
|
||||||
|
List<BaseObject *> objects;
|
||||||
|
|
||||||
|
ContentDescriptionObject *contentDescriptionObject;
|
||||||
|
ExtendedContentDescriptionObject *extendedContentDescriptionObject;
|
||||||
|
HeaderExtensionObject *headerExtensionObject;
|
||||||
|
MetadataObject *metadataObject;
|
||||||
|
MetadataLibraryObject *metadataLibraryObject;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
const ByteVector headerGuid("\x30\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C", 16);
|
||||||
|
const ByteVector filePropertiesGuid("\xA1\xDC\xAB\x8C\x47\xA9\xCF\x11\x8E\xE4\x00\xC0\x0C\x20\x53\x65", 16);
|
||||||
|
const ByteVector streamPropertiesGuid("\x91\x07\xDC\xB7\xB7\xA9\xCF\x11\x8E\xE6\x00\xC0\x0C\x20\x53\x65", 16);
|
||||||
|
const ByteVector contentDescriptionGuid("\x33\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C", 16);
|
||||||
|
const ByteVector extendedContentDescriptionGuid("\x40\xA4\xD0\xD2\x07\xE3\xD2\x11\x97\xF0\x00\xA0\xC9\x5E\xA8\x50", 16);
|
||||||
|
const ByteVector headerExtensionGuid("\xb5\x03\xbf_.\xa9\xcf\x11\x8e\xe3\x00\xc0\x0c Se", 16);
|
||||||
|
const ByteVector metadataGuid("\xEA\xCB\xF8\xC5\xAF[wH\204g\xAA\214D\xFAL\xCA", 16);
|
||||||
|
const ByteVector metadataLibraryGuid("\224\034#D\230\224\321I\241A\x1d\x13NEpT", 16);
|
||||||
|
const ByteVector codecListGuid("\x40\x52\xd1\x86\x1d\x31\xd0\x11\xa3\xa4\x00\xa0\xc9\x03\x48\xf6", 16);
|
||||||
|
const ByteVector contentEncryptionGuid("\xFB\xB3\x11\x22\x23\xBD\xD2\x11\xB4\xB7\x00\xA0\xC9\x55\xFC\x6E", 16);
|
||||||
|
const ByteVector extendedContentEncryptionGuid("\x14\xE6\x8A\x29\x22\x26 \x17\x4C\xB9\x35\xDA\xE0\x7E\xE9\x28\x9C", 16);
|
||||||
|
const ByteVector advancedContentEncryptionGuid("\xB6\x9B\x07\x7A\xA4\xDA\x12\x4E\xA5\xCA\x91\xD3\x8D\xC1\x1A\x8D", 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
class ASF::File::FilePrivate::BaseObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ByteVector data;
|
||||||
|
virtual ~BaseObject() {}
|
||||||
|
virtual ByteVector guid() const = 0;
|
||||||
|
virtual void parse(ASF::File *file, unsigned int size);
|
||||||
|
virtual ByteVector render(ASF::File *file);
|
||||||
|
};
|
||||||
|
|
||||||
|
class ASF::File::FilePrivate::UnknownObject : public ASF::File::FilePrivate::BaseObject
|
||||||
|
{
|
||||||
|
ByteVector myGuid;
|
||||||
|
public:
|
||||||
|
UnknownObject(const ByteVector &guid);
|
||||||
|
ByteVector guid() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ASF::File::FilePrivate::FilePropertiesObject : public ASF::File::FilePrivate::BaseObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ByteVector guid() const;
|
||||||
|
void parse(ASF::File *file, unsigned int size);
|
||||||
|
};
|
||||||
|
|
||||||
|
class ASF::File::FilePrivate::StreamPropertiesObject : public ASF::File::FilePrivate::BaseObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ByteVector guid() const;
|
||||||
|
void parse(ASF::File *file, unsigned int size);
|
||||||
|
};
|
||||||
|
|
||||||
|
class ASF::File::FilePrivate::ContentDescriptionObject : public ASF::File::FilePrivate::BaseObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ByteVector guid() const;
|
||||||
|
void parse(ASF::File *file, unsigned int size);
|
||||||
|
ByteVector render(ASF::File *file);
|
||||||
|
};
|
||||||
|
|
||||||
|
class ASF::File::FilePrivate::ExtendedContentDescriptionObject : public ASF::File::FilePrivate::BaseObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ByteVectorList attributeData;
|
||||||
|
ByteVector guid() const;
|
||||||
|
void parse(ASF::File *file, unsigned int size);
|
||||||
|
ByteVector render(ASF::File *file);
|
||||||
|
};
|
||||||
|
|
||||||
|
class ASF::File::FilePrivate::MetadataObject : public ASF::File::FilePrivate::BaseObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ByteVectorList attributeData;
|
||||||
|
ByteVector guid() const;
|
||||||
|
void parse(ASF::File *file, unsigned int size);
|
||||||
|
ByteVector render(ASF::File *file);
|
||||||
|
};
|
||||||
|
|
||||||
|
class ASF::File::FilePrivate::MetadataLibraryObject : public ASF::File::FilePrivate::BaseObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ByteVectorList attributeData;
|
||||||
|
ByteVector guid() const;
|
||||||
|
void parse(ASF::File *file, unsigned int size);
|
||||||
|
ByteVector render(ASF::File *file);
|
||||||
|
};
|
||||||
|
|
||||||
|
class ASF::File::FilePrivate::HeaderExtensionObject : public ASF::File::FilePrivate::BaseObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
List<ASF::File::FilePrivate::BaseObject *> objects;
|
||||||
|
HeaderExtensionObject();
|
||||||
|
ByteVector guid() const;
|
||||||
|
void parse(ASF::File *file, unsigned int size);
|
||||||
|
ByteVector render(ASF::File *file);
|
||||||
|
};
|
||||||
|
|
||||||
|
class ASF::File::FilePrivate::CodecListObject : public ASF::File::FilePrivate::BaseObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ByteVector guid() const;
|
||||||
|
void parse(ASF::File *file, unsigned int size);
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum CodecType
|
||||||
|
{
|
||||||
|
Video = 0x0001,
|
||||||
|
Audio = 0x0002,
|
||||||
|
Unknown = 0xFFFF
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
void ASF::File::FilePrivate::BaseObject::parse(ASF::File *file, unsigned int size)
|
||||||
|
{
|
||||||
|
data.clear();
|
||||||
|
if(size > 24 && size <= (unsigned int)(file->length()))
|
||||||
|
data = file->readBlock(size - 24);
|
||||||
|
else
|
||||||
|
data = ByteVector();
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector ASF::File::FilePrivate::BaseObject::render(ASF::File * /*file*/)
|
||||||
|
{
|
||||||
|
return guid() + ByteVector::fromLongLong(data.size() + 24, false) + data;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASF::File::FilePrivate::UnknownObject::UnknownObject(const ByteVector &guid) : myGuid(guid)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector ASF::File::FilePrivate::UnknownObject::guid() const
|
||||||
|
{
|
||||||
|
return myGuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector ASF::File::FilePrivate::FilePropertiesObject::guid() const
|
||||||
|
{
|
||||||
|
return filePropertiesGuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ASF::File::FilePrivate::FilePropertiesObject::parse(ASF::File *file, unsigned int size)
|
||||||
|
{
|
||||||
|
BaseObject::parse(file, size);
|
||||||
|
if(data.size() < 64) {
|
||||||
|
debug("ASF::File::FilePrivate::FilePropertiesObject::parse() -- data is too short.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const long long duration = data.toLongLong(40, false);
|
||||||
|
const long long preroll = data.toLongLong(56, false);
|
||||||
|
file->d->properties->setLengthInMilliseconds(static_cast<int>(duration / 10000.0 - preroll + 0.5));
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector ASF::File::FilePrivate::StreamPropertiesObject::guid() const
|
||||||
|
{
|
||||||
|
return streamPropertiesGuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ASF::File::FilePrivate::StreamPropertiesObject::parse(ASF::File *file, unsigned int size)
|
||||||
|
{
|
||||||
|
BaseObject::parse(file, size);
|
||||||
|
if(data.size() < 70) {
|
||||||
|
debug("ASF::File::FilePrivate::StreamPropertiesObject::parse() -- data is too short.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
file->d->properties->setCodec(data.toUShort(54, false));
|
||||||
|
file->d->properties->setChannels(data.toUShort(56, false));
|
||||||
|
file->d->properties->setSampleRate(data.toUInt(58, false));
|
||||||
|
file->d->properties->setBitrate(static_cast<int>(data.toUInt(62, false) * 8.0 / 1000.0 + 0.5));
|
||||||
|
file->d->properties->setBitsPerSample(data.toUShort(68, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector ASF::File::FilePrivate::ContentDescriptionObject::guid() const
|
||||||
|
{
|
||||||
|
return contentDescriptionGuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ASF::File::FilePrivate::ContentDescriptionObject::parse(ASF::File *file, unsigned int /*size*/)
|
||||||
|
{
|
||||||
|
const int titleLength = readWORD(file);
|
||||||
|
const int artistLength = readWORD(file);
|
||||||
|
const int copyrightLength = readWORD(file);
|
||||||
|
const int commentLength = readWORD(file);
|
||||||
|
const int ratingLength = readWORD(file);
|
||||||
|
file->d->tag->setTitle(readString(file,titleLength));
|
||||||
|
file->d->tag->setArtist(readString(file,artistLength));
|
||||||
|
file->d->tag->setCopyright(readString(file,copyrightLength));
|
||||||
|
file->d->tag->setComment(readString(file,commentLength));
|
||||||
|
file->d->tag->setRating(readString(file,ratingLength));
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector ASF::File::FilePrivate::ContentDescriptionObject::render(ASF::File *file)
|
||||||
|
{
|
||||||
|
const ByteVector v1 = renderString(file->d->tag->title());
|
||||||
|
const ByteVector v2 = renderString(file->d->tag->artist());
|
||||||
|
const ByteVector v3 = renderString(file->d->tag->copyright());
|
||||||
|
const ByteVector v4 = renderString(file->d->tag->comment());
|
||||||
|
const ByteVector v5 = renderString(file->d->tag->rating());
|
||||||
|
data.clear();
|
||||||
|
data.append(ByteVector::fromShort(v1.size(), false));
|
||||||
|
data.append(ByteVector::fromShort(v2.size(), false));
|
||||||
|
data.append(ByteVector::fromShort(v3.size(), false));
|
||||||
|
data.append(ByteVector::fromShort(v4.size(), false));
|
||||||
|
data.append(ByteVector::fromShort(v5.size(), false));
|
||||||
|
data.append(v1);
|
||||||
|
data.append(v2);
|
||||||
|
data.append(v3);
|
||||||
|
data.append(v4);
|
||||||
|
data.append(v5);
|
||||||
|
return BaseObject::render(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector ASF::File::FilePrivate::ExtendedContentDescriptionObject::guid() const
|
||||||
|
{
|
||||||
|
return extendedContentDescriptionGuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ASF::File::FilePrivate::ExtendedContentDescriptionObject::parse(ASF::File *file, unsigned int /*size*/)
|
||||||
|
{
|
||||||
|
int count = readWORD(file);
|
||||||
|
while(count--) {
|
||||||
|
ASF::Attribute attribute;
|
||||||
|
String name = attribute.parse(*file);
|
||||||
|
file->d->tag->addAttribute(name, attribute);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector ASF::File::FilePrivate::ExtendedContentDescriptionObject::render(ASF::File *file)
|
||||||
|
{
|
||||||
|
data.clear();
|
||||||
|
data.append(ByteVector::fromShort(attributeData.size(), false));
|
||||||
|
data.append(attributeData.toByteVector(""));
|
||||||
|
return BaseObject::render(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector ASF::File::FilePrivate::MetadataObject::guid() const
|
||||||
|
{
|
||||||
|
return metadataGuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ASF::File::FilePrivate::MetadataObject::parse(ASF::File *file, unsigned int /*size*/)
|
||||||
|
{
|
||||||
|
int count = readWORD(file);
|
||||||
|
while(count--) {
|
||||||
|
ASF::Attribute attribute;
|
||||||
|
String name = attribute.parse(*file, 1);
|
||||||
|
file->d->tag->addAttribute(name, attribute);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector ASF::File::FilePrivate::MetadataObject::render(ASF::File *file)
|
||||||
|
{
|
||||||
|
data.clear();
|
||||||
|
data.append(ByteVector::fromShort(attributeData.size(), false));
|
||||||
|
data.append(attributeData.toByteVector(""));
|
||||||
|
return BaseObject::render(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector ASF::File::FilePrivate::MetadataLibraryObject::guid() const
|
||||||
|
{
|
||||||
|
return metadataLibraryGuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ASF::File::FilePrivate::MetadataLibraryObject::parse(ASF::File *file, unsigned int /*size*/)
|
||||||
|
{
|
||||||
|
int count = readWORD(file);
|
||||||
|
while(count--) {
|
||||||
|
ASF::Attribute attribute;
|
||||||
|
String name = attribute.parse(*file, 2);
|
||||||
|
file->d->tag->addAttribute(name, attribute);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector ASF::File::FilePrivate::MetadataLibraryObject::render(ASF::File *file)
|
||||||
|
{
|
||||||
|
data.clear();
|
||||||
|
data.append(ByteVector::fromShort(attributeData.size(), false));
|
||||||
|
data.append(attributeData.toByteVector(""));
|
||||||
|
return BaseObject::render(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
ASF::File::FilePrivate::HeaderExtensionObject::HeaderExtensionObject()
|
||||||
|
{
|
||||||
|
objects.setAutoDelete(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector ASF::File::FilePrivate::HeaderExtensionObject::guid() const
|
||||||
|
{
|
||||||
|
return headerExtensionGuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ASF::File::FilePrivate::HeaderExtensionObject::parse(ASF::File *file, unsigned int /*size*/)
|
||||||
|
{
|
||||||
|
file->seek(18, File::Current);
|
||||||
|
long long dataSize = readDWORD(file);
|
||||||
|
long long dataPos = 0;
|
||||||
|
while(dataPos < dataSize) {
|
||||||
|
ByteVector guid = file->readBlock(16);
|
||||||
|
if(guid.size() != 16) {
|
||||||
|
file->setValid(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
bool ok;
|
||||||
|
long long size = readQWORD(file, &ok);
|
||||||
|
if(!ok) {
|
||||||
|
file->setValid(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
BaseObject *obj;
|
||||||
|
if(guid == metadataGuid) {
|
||||||
|
file->d->metadataObject = new MetadataObject();
|
||||||
|
obj = file->d->metadataObject;
|
||||||
|
}
|
||||||
|
else if(guid == metadataLibraryGuid) {
|
||||||
|
file->d->metadataLibraryObject = new MetadataLibraryObject();
|
||||||
|
obj = file->d->metadataLibraryObject;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
obj = new UnknownObject(guid);
|
||||||
|
}
|
||||||
|
obj->parse(file, (unsigned int)size);
|
||||||
|
objects.append(obj);
|
||||||
|
dataPos += size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector ASF::File::FilePrivate::HeaderExtensionObject::render(ASF::File *file)
|
||||||
|
{
|
||||||
|
data.clear();
|
||||||
|
for(List<BaseObject *>::ConstIterator it = objects.begin(); it != objects.end(); ++it) {
|
||||||
|
data.append((*it)->render(file));
|
||||||
|
}
|
||||||
|
data = ByteVector("\x11\xD2\xD3\xAB\xBA\xA9\xcf\x11\x8E\xE6\x00\xC0\x0C\x20\x53\x65\x06\x00", 18) + ByteVector::fromUInt(data.size(), false) + data;
|
||||||
|
return BaseObject::render(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector ASF::File::FilePrivate::CodecListObject::guid() const
|
||||||
|
{
|
||||||
|
return codecListGuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ASF::File::FilePrivate::CodecListObject::parse(ASF::File *file, unsigned int size)
|
||||||
|
{
|
||||||
|
BaseObject::parse(file, size);
|
||||||
|
if(data.size() <= 20) {
|
||||||
|
debug("ASF::File::FilePrivate::CodecListObject::parse() -- data is too short.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int pos = 16;
|
||||||
|
|
||||||
|
const int count = data.toUInt(pos, false);
|
||||||
|
pos += 4;
|
||||||
|
|
||||||
|
for(int i = 0; i < count; ++i) {
|
||||||
|
|
||||||
|
if(pos >= data.size())
|
||||||
|
break;
|
||||||
|
|
||||||
|
const CodecType type = static_cast<CodecType>(data.toUShort(pos, false));
|
||||||
|
pos += 2;
|
||||||
|
|
||||||
|
int nameLength = data.toUShort(pos, false);
|
||||||
|
pos += 2;
|
||||||
|
|
||||||
|
const unsigned int namePos = pos;
|
||||||
|
pos += nameLength * 2;
|
||||||
|
|
||||||
|
const int descLength = data.toUShort(pos, false);
|
||||||
|
pos += 2;
|
||||||
|
|
||||||
|
const unsigned int descPos = pos;
|
||||||
|
pos += descLength * 2;
|
||||||
|
|
||||||
|
const int infoLength = data.toUShort(pos, false);
|
||||||
|
pos += 2 + infoLength * 2;
|
||||||
|
|
||||||
|
if(type == CodecListObject::Audio) {
|
||||||
|
// First audio codec found.
|
||||||
|
|
||||||
|
const String name(data.mid(namePos, nameLength * 2), String::UTF16LE);
|
||||||
|
file->d->properties->setCodecName(name.stripWhiteSpace());
|
||||||
|
|
||||||
|
const String desc(data.mid(descPos, descLength * 2), String::UTF16LE);
|
||||||
|
file->d->properties->setCodecDescription(desc.stripWhiteSpace());
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// static members
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
bool ASF::File::isSupported(IOStream *stream)
|
||||||
|
{
|
||||||
|
// An ASF file has to start with the designated GUID.
|
||||||
|
|
||||||
|
const ByteVector id = Utils::readHeader(stream, 16, false);
|
||||||
|
return (id == headerGuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// public members
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
ASF::File::File(FileName file, bool, Properties::ReadStyle) :
|
||||||
|
TagLib::File(file),
|
||||||
|
d(new FilePrivate())
|
||||||
|
{
|
||||||
|
if(isOpen())
|
||||||
|
read();
|
||||||
|
}
|
||||||
|
|
||||||
|
ASF::File::File(IOStream *stream, bool, Properties::ReadStyle) :
|
||||||
|
TagLib::File(stream),
|
||||||
|
d(new FilePrivate())
|
||||||
|
{
|
||||||
|
if(isOpen())
|
||||||
|
read();
|
||||||
|
}
|
||||||
|
|
||||||
|
ASF::File::~File()
|
||||||
|
{
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASF::Tag *ASF::File::tag() const
|
||||||
|
{
|
||||||
|
return d->tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyMap ASF::File::properties() const
|
||||||
|
{
|
||||||
|
return d->tag->properties();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ASF::File::removeUnsupportedProperties(const StringList &properties)
|
||||||
|
{
|
||||||
|
d->tag->removeUnsupportedProperties(properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyMap ASF::File::setProperties(const PropertyMap &properties)
|
||||||
|
{
|
||||||
|
return d->tag->setProperties(properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
ASF::Properties *ASF::File::audioProperties() const
|
||||||
|
{
|
||||||
|
return d->properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ASF::File::save()
|
||||||
|
{
|
||||||
|
if(readOnly()) {
|
||||||
|
debug("ASF::File::save() -- File is read only.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!isValid()) {
|
||||||
|
debug("ASF::File::save() -- Trying to save invalid file.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!d->contentDescriptionObject) {
|
||||||
|
d->contentDescriptionObject = new FilePrivate::ContentDescriptionObject();
|
||||||
|
d->objects.append(d->contentDescriptionObject);
|
||||||
|
}
|
||||||
|
if(!d->extendedContentDescriptionObject) {
|
||||||
|
d->extendedContentDescriptionObject = new FilePrivate::ExtendedContentDescriptionObject();
|
||||||
|
d->objects.append(d->extendedContentDescriptionObject);
|
||||||
|
}
|
||||||
|
if(!d->headerExtensionObject) {
|
||||||
|
d->headerExtensionObject = new FilePrivate::HeaderExtensionObject();
|
||||||
|
d->objects.append(d->headerExtensionObject);
|
||||||
|
}
|
||||||
|
if(!d->metadataObject) {
|
||||||
|
d->metadataObject = new FilePrivate::MetadataObject();
|
||||||
|
d->headerExtensionObject->objects.append(d->metadataObject);
|
||||||
|
}
|
||||||
|
if(!d->metadataLibraryObject) {
|
||||||
|
d->metadataLibraryObject = new FilePrivate::MetadataLibraryObject();
|
||||||
|
d->headerExtensionObject->objects.append(d->metadataLibraryObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
d->extendedContentDescriptionObject->attributeData.clear();
|
||||||
|
d->metadataObject->attributeData.clear();
|
||||||
|
d->metadataLibraryObject->attributeData.clear();
|
||||||
|
|
||||||
|
const AttributeListMap allAttributes = d->tag->attributeListMap();
|
||||||
|
|
||||||
|
for(AttributeListMap::ConstIterator it = allAttributes.begin(); it != allAttributes.end(); ++it) {
|
||||||
|
|
||||||
|
const String &name = it->first;
|
||||||
|
const AttributeList &attributes = it->second;
|
||||||
|
|
||||||
|
bool inExtendedContentDescriptionObject = false;
|
||||||
|
bool inMetadataObject = false;
|
||||||
|
|
||||||
|
for(AttributeList::ConstIterator jt = attributes.begin(); jt != attributes.end(); ++jt) {
|
||||||
|
|
||||||
|
const Attribute &attribute = *jt;
|
||||||
|
const bool largeValue = (attribute.dataSize() > 65535);
|
||||||
|
const bool guid = (attribute.type() == Attribute::GuidType);
|
||||||
|
|
||||||
|
if(!inExtendedContentDescriptionObject && !guid && !largeValue && attribute.language() == 0 && attribute.stream() == 0) {
|
||||||
|
d->extendedContentDescriptionObject->attributeData.append(attribute.render(name));
|
||||||
|
inExtendedContentDescriptionObject = true;
|
||||||
|
}
|
||||||
|
else if(!inMetadataObject && !guid && !largeValue && attribute.language() == 0 && attribute.stream() != 0) {
|
||||||
|
d->metadataObject->attributeData.append(attribute.render(name, 1));
|
||||||
|
inMetadataObject = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
d->metadataLibraryObject->attributeData.append(attribute.render(name, 2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector data;
|
||||||
|
for(List<FilePrivate::BaseObject *>::ConstIterator it = d->objects.begin(); it != d->objects.end(); ++it) {
|
||||||
|
data.append((*it)->render(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
seek(16);
|
||||||
|
writeBlock(ByteVector::fromLongLong(data.size() + 30, false));
|
||||||
|
writeBlock(ByteVector::fromUInt(d->objects.size(), false));
|
||||||
|
writeBlock(ByteVector("\x01\x02", 2));
|
||||||
|
|
||||||
|
insert(data, 30, static_cast<unsigned long>(d->headerSize - 30));
|
||||||
|
|
||||||
|
d->headerSize = data.size() + 30;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// private members
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void ASF::File::read()
|
||||||
|
{
|
||||||
|
if(!isValid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(readBlock(16) != headerGuid) {
|
||||||
|
debug("ASF::File::read(): Not an ASF file.");
|
||||||
|
setValid(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
d->tag = new ASF::Tag();
|
||||||
|
d->properties = new ASF::Properties();
|
||||||
|
|
||||||
|
bool ok;
|
||||||
|
d->headerSize = readQWORD(this, &ok);
|
||||||
|
if(!ok) {
|
||||||
|
setValid(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int numObjects = readDWORD(this, &ok);
|
||||||
|
if(!ok) {
|
||||||
|
setValid(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
seek(2, Current);
|
||||||
|
|
||||||
|
FilePrivate::FilePropertiesObject *filePropertiesObject = 0;
|
||||||
|
FilePrivate::StreamPropertiesObject *streamPropertiesObject = 0;
|
||||||
|
for(int i = 0; i < numObjects; i++) {
|
||||||
|
const ByteVector guid = readBlock(16);
|
||||||
|
if(guid.size() != 16) {
|
||||||
|
setValid(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
long size = (long)readQWORD(this, &ok);
|
||||||
|
if(!ok) {
|
||||||
|
setValid(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
FilePrivate::BaseObject *obj;
|
||||||
|
if(guid == filePropertiesGuid) {
|
||||||
|
filePropertiesObject = new FilePrivate::FilePropertiesObject();
|
||||||
|
obj = filePropertiesObject;
|
||||||
|
}
|
||||||
|
else if(guid == streamPropertiesGuid) {
|
||||||
|
streamPropertiesObject = new FilePrivate::StreamPropertiesObject();
|
||||||
|
obj = streamPropertiesObject;
|
||||||
|
}
|
||||||
|
else if(guid == contentDescriptionGuid) {
|
||||||
|
d->contentDescriptionObject = new FilePrivate::ContentDescriptionObject();
|
||||||
|
obj = d->contentDescriptionObject;
|
||||||
|
}
|
||||||
|
else if(guid == extendedContentDescriptionGuid) {
|
||||||
|
d->extendedContentDescriptionObject = new FilePrivate::ExtendedContentDescriptionObject();
|
||||||
|
obj = d->extendedContentDescriptionObject;
|
||||||
|
}
|
||||||
|
else if(guid == headerExtensionGuid) {
|
||||||
|
d->headerExtensionObject = new FilePrivate::HeaderExtensionObject();
|
||||||
|
obj = d->headerExtensionObject;
|
||||||
|
}
|
||||||
|
else if(guid == codecListGuid) {
|
||||||
|
obj = new FilePrivate::CodecListObject();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(guid == contentEncryptionGuid ||
|
||||||
|
guid == extendedContentEncryptionGuid ||
|
||||||
|
guid == advancedContentEncryptionGuid) {
|
||||||
|
d->properties->setEncrypted(true);
|
||||||
|
}
|
||||||
|
obj = new FilePrivate::UnknownObject(guid);
|
||||||
|
}
|
||||||
|
obj->parse(this, size);
|
||||||
|
d->objects.append(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!filePropertiesObject || !streamPropertiesObject) {
|
||||||
|
debug("ASF::File::read(): Missing mandatory header objects.");
|
||||||
|
setValid(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
138
3rdparty/taglib/asf/asffile.h
vendored
Normal file
138
3rdparty/taglib/asf/asffile.h
vendored
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
/**************************************************************************
|
||||||
|
copyright : (C) 2005-2007 by Lukáš Lalinský
|
||||||
|
email : lalinsky@gmail.com
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef TAGLIB_ASFFILE_H
|
||||||
|
#define TAGLIB_ASFFILE_H
|
||||||
|
|
||||||
|
#include "tag.h"
|
||||||
|
#include "tfile.h"
|
||||||
|
#include "taglib_export.h"
|
||||||
|
#include "asfproperties.h"
|
||||||
|
#include "asftag.h"
|
||||||
|
|
||||||
|
namespace TagLib {
|
||||||
|
|
||||||
|
//! An implementation of ASF (WMA) metadata
|
||||||
|
namespace ASF {
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* This implements and provides an interface for ASF files to the
|
||||||
|
* TagLib::Tag and TagLib::AudioProperties interfaces by way of implementing
|
||||||
|
* the abstract TagLib::File API as well as providing some additional
|
||||||
|
* information specific to ASF files.
|
||||||
|
*/
|
||||||
|
class TAGLIB_EXPORT File : public TagLib::File
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Constructs an ASF file from \a file.
|
||||||
|
*
|
||||||
|
* \note In the current implementation, both \a readProperties and
|
||||||
|
* \a propertiesStyle are ignored. The audio properties are always
|
||||||
|
* read.
|
||||||
|
*/
|
||||||
|
File(FileName file, bool readProperties = true,
|
||||||
|
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Constructs an ASF file from \a stream.
|
||||||
|
*
|
||||||
|
* \note In the current implementation, both \a readProperties and
|
||||||
|
* \a propertiesStyle are ignored. The audio properties are always
|
||||||
|
* read.
|
||||||
|
*
|
||||||
|
* \note TagLib will *not* take ownership of the stream, the caller is
|
||||||
|
* responsible for deleting it after the File object.
|
||||||
|
*/
|
||||||
|
File(IOStream *stream, bool readProperties = true,
|
||||||
|
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Destroys this instance of the File.
|
||||||
|
*/
|
||||||
|
virtual ~File();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns a pointer to the ASF tag of the file.
|
||||||
|
*
|
||||||
|
* ASF::Tag implements the tag interface, so this serves as the
|
||||||
|
* reimplementation of TagLib::File::tag().
|
||||||
|
*
|
||||||
|
* \note The Tag <b>is still</b> owned by the ASF::File and should not be
|
||||||
|
* deleted by the user. It will be deleted when the file (object) is
|
||||||
|
* destroyed.
|
||||||
|
*/
|
||||||
|
virtual Tag *tag() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Implements the unified property interface -- export function.
|
||||||
|
*/
|
||||||
|
PropertyMap properties() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Removes unsupported properties. Forwards to the actual Tag's
|
||||||
|
* removeUnsupportedProperties() function.
|
||||||
|
*/
|
||||||
|
void removeUnsupportedProperties(const StringList &properties);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Implements the unified property interface -- import function.
|
||||||
|
*/
|
||||||
|
PropertyMap setProperties(const PropertyMap &);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the ASF audio properties for this file.
|
||||||
|
*/
|
||||||
|
virtual Properties *audioProperties() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Save the file.
|
||||||
|
*
|
||||||
|
* This returns true if the save was successful.
|
||||||
|
*/
|
||||||
|
virtual bool save();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns whether or not the given \a stream can be opened as an ASF
|
||||||
|
* file.
|
||||||
|
*
|
||||||
|
* \note This method is designed to do a quick check. The result may
|
||||||
|
* not necessarily be correct.
|
||||||
|
*/
|
||||||
|
static bool isSupported(IOStream *stream);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void read();
|
||||||
|
|
||||||
|
class FilePrivate;
|
||||||
|
FilePrivate *d;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
183
3rdparty/taglib/asf/asfpicture.cpp
vendored
Normal file
183
3rdparty/taglib/asf/asfpicture.cpp
vendored
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
/**************************************************************************
|
||||||
|
copyright : (C) 2010 by Anton Sergunov
|
||||||
|
email : setosha@gmail.com
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include <taglib.h>
|
||||||
|
#include <tdebug.h>
|
||||||
|
#include <trefcounter.h>
|
||||||
|
|
||||||
|
#include "asfattribute.h"
|
||||||
|
#include "asffile.h"
|
||||||
|
#include "asfpicture.h"
|
||||||
|
#include "asfutils.h"
|
||||||
|
|
||||||
|
using namespace TagLib;
|
||||||
|
|
||||||
|
class ASF::Picture::PicturePrivate : public RefCounter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool valid;
|
||||||
|
Type type;
|
||||||
|
String mimeType;
|
||||||
|
String description;
|
||||||
|
ByteVector picture;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Picture class members
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
ASF::Picture::Picture() :
|
||||||
|
d(new PicturePrivate())
|
||||||
|
{
|
||||||
|
d->valid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASF::Picture::Picture(const Picture& other) :
|
||||||
|
d(other.d)
|
||||||
|
{
|
||||||
|
d->ref();
|
||||||
|
}
|
||||||
|
|
||||||
|
ASF::Picture::~Picture()
|
||||||
|
{
|
||||||
|
if(d->deref())
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ASF::Picture::isValid() const
|
||||||
|
{
|
||||||
|
return d->valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
String ASF::Picture::mimeType() const
|
||||||
|
{
|
||||||
|
return d->mimeType;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ASF::Picture::setMimeType(const String &value)
|
||||||
|
{
|
||||||
|
d->mimeType = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASF::Picture::Type ASF::Picture::type() const
|
||||||
|
{
|
||||||
|
return d->type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ASF::Picture::setType(const ASF::Picture::Type& t)
|
||||||
|
{
|
||||||
|
d->type = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
String ASF::Picture::description() const
|
||||||
|
{
|
||||||
|
return d->description;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ASF::Picture::setDescription(const String &desc)
|
||||||
|
{
|
||||||
|
d->description = desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector ASF::Picture::picture() const
|
||||||
|
{
|
||||||
|
return d->picture;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ASF::Picture::setPicture(const ByteVector &p)
|
||||||
|
{
|
||||||
|
d->picture = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ASF::Picture::dataSize() const
|
||||||
|
{
|
||||||
|
return
|
||||||
|
9 + (d->mimeType.length() + d->description.length()) * 2 +
|
||||||
|
d->picture.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
ASF::Picture& ASF::Picture::operator=(const ASF::Picture& other)
|
||||||
|
{
|
||||||
|
Picture(other).swap(*this);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ASF::Picture::swap(Picture &other)
|
||||||
|
{
|
||||||
|
using std::swap;
|
||||||
|
|
||||||
|
swap(d, other.d);
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector ASF::Picture::render() const
|
||||||
|
{
|
||||||
|
if(!isValid())
|
||||||
|
return ByteVector();
|
||||||
|
|
||||||
|
return
|
||||||
|
ByteVector((char)d->type) +
|
||||||
|
ByteVector::fromUInt(d->picture.size(), false) +
|
||||||
|
renderString(d->mimeType) +
|
||||||
|
renderString(d->description) +
|
||||||
|
d->picture;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ASF::Picture::parse(const ByteVector& bytes)
|
||||||
|
{
|
||||||
|
d->valid = false;
|
||||||
|
if(bytes.size() < 9)
|
||||||
|
return;
|
||||||
|
int pos = 0;
|
||||||
|
d->type = (Type)bytes[0]; ++pos;
|
||||||
|
const unsigned int dataLen = bytes.toUInt(pos, false); pos+=4;
|
||||||
|
|
||||||
|
const ByteVector nullStringTerminator(2, 0);
|
||||||
|
|
||||||
|
int endPos = bytes.find(nullStringTerminator, pos, 2);
|
||||||
|
if(endPos < 0)
|
||||||
|
return;
|
||||||
|
d->mimeType = String(bytes.mid(pos, endPos - pos), String::UTF16LE);
|
||||||
|
pos = endPos+2;
|
||||||
|
|
||||||
|
endPos = bytes.find(nullStringTerminator, pos, 2);
|
||||||
|
if(endPos < 0)
|
||||||
|
return;
|
||||||
|
d->description = String(bytes.mid(pos, endPos - pos), String::UTF16LE);
|
||||||
|
pos = endPos+2;
|
||||||
|
|
||||||
|
if(dataLen + pos != bytes.size())
|
||||||
|
return;
|
||||||
|
|
||||||
|
d->picture = bytes.mid(pos, dataLen);
|
||||||
|
d->valid = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASF::Picture ASF::Picture::fromInvalid()
|
||||||
|
{
|
||||||
|
Picture ret;
|
||||||
|
ret.d->valid = false;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
222
3rdparty/taglib/asf/asfpicture.h
vendored
Normal file
222
3rdparty/taglib/asf/asfpicture.h
vendored
Normal file
@@ -0,0 +1,222 @@
|
|||||||
|
/**************************************************************************
|
||||||
|
copyright : (C) 2010 by Anton Sergunov
|
||||||
|
email : setosha@gmail.com
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef ASFPICTURE_H
|
||||||
|
#define ASFPICTURE_H
|
||||||
|
|
||||||
|
#include "tstring.h"
|
||||||
|
#include "tbytevector.h"
|
||||||
|
#include "taglib_export.h"
|
||||||
|
#include "attachedpictureframe.h"
|
||||||
|
|
||||||
|
namespace TagLib
|
||||||
|
{
|
||||||
|
namespace ASF
|
||||||
|
{
|
||||||
|
|
||||||
|
//! An ASF attached picture interface implementation
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* This is an implementation of ASF attached pictures interface. Pictures may be
|
||||||
|
* included in attributes, one per WM/Picture attribute (but there may be multiple WM/Picture
|
||||||
|
* attribute in a single tag). These pictures are usually in either JPEG or
|
||||||
|
* PNG format.
|
||||||
|
* \see Attribute::toPicture()
|
||||||
|
* \see Attribute::Attribute(const Picture& picture)
|
||||||
|
*/
|
||||||
|
class TAGLIB_EXPORT Picture {
|
||||||
|
public:
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* This describes the function or content of the picture.
|
||||||
|
*/
|
||||||
|
enum Type {
|
||||||
|
//! A type not enumerated below
|
||||||
|
Other = 0x00,
|
||||||
|
//! 32x32 PNG image that should be used as the file icon
|
||||||
|
FileIcon = 0x01,
|
||||||
|
//! File icon of a different size or format
|
||||||
|
OtherFileIcon = 0x02,
|
||||||
|
//! Front cover image of the album
|
||||||
|
FrontCover = 0x03,
|
||||||
|
//! Back cover image of the album
|
||||||
|
BackCover = 0x04,
|
||||||
|
//! Inside leaflet page of the album
|
||||||
|
LeafletPage = 0x05,
|
||||||
|
//! Image from the album itself
|
||||||
|
Media = 0x06,
|
||||||
|
//! Picture of the lead artist or soloist
|
||||||
|
LeadArtist = 0x07,
|
||||||
|
//! Picture of the artist or performer
|
||||||
|
Artist = 0x08,
|
||||||
|
//! Picture of the conductor
|
||||||
|
Conductor = 0x09,
|
||||||
|
//! Picture of the band or orchestra
|
||||||
|
Band = 0x0A,
|
||||||
|
//! Picture of the composer
|
||||||
|
Composer = 0x0B,
|
||||||
|
//! Picture of the lyricist or text writer
|
||||||
|
Lyricist = 0x0C,
|
||||||
|
//! Picture of the recording location or studio
|
||||||
|
RecordingLocation = 0x0D,
|
||||||
|
//! Picture of the artists during recording
|
||||||
|
DuringRecording = 0x0E,
|
||||||
|
//! Picture of the artists during performance
|
||||||
|
DuringPerformance = 0x0F,
|
||||||
|
//! Picture from a movie or video related to the track
|
||||||
|
MovieScreenCapture = 0x10,
|
||||||
|
//! Picture of a large, coloured fish
|
||||||
|
ColouredFish = 0x11,
|
||||||
|
//! Illustration related to the track
|
||||||
|
Illustration = 0x12,
|
||||||
|
//! Logo of the band or performer
|
||||||
|
BandLogo = 0x13,
|
||||||
|
//! Logo of the publisher (record company)
|
||||||
|
PublisherLogo = 0x14
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Constructs an empty picture.
|
||||||
|
*/
|
||||||
|
Picture();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Construct an picture as a copy of \a other.
|
||||||
|
*/
|
||||||
|
Picture(const Picture& other);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Destroys the picture.
|
||||||
|
*/
|
||||||
|
virtual ~Picture();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Copies the contents of \a other into this picture.
|
||||||
|
*/
|
||||||
|
Picture& operator=(const Picture& other);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Exchanges the content of the Picture by the content of \a other.
|
||||||
|
*/
|
||||||
|
void swap(Picture &other);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns true if Picture stores valid picture
|
||||||
|
*/
|
||||||
|
bool isValid() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the mime type of the image. This should in most cases be
|
||||||
|
* "image/png" or "image/jpeg".
|
||||||
|
* \see setMimeType(const String &)
|
||||||
|
* \see picture()
|
||||||
|
* \see setPicture(const ByteArray&)
|
||||||
|
*/
|
||||||
|
String mimeType() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets the mime type of the image. This should in most cases be
|
||||||
|
* "image/png" or "image/jpeg".
|
||||||
|
* \see setMimeType(const String &)
|
||||||
|
* \see picture()
|
||||||
|
* \see setPicture(const ByteArray&)
|
||||||
|
*/
|
||||||
|
void setMimeType(const String &value);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the type of the image.
|
||||||
|
*
|
||||||
|
* \see Type
|
||||||
|
* \see setType()
|
||||||
|
*/
|
||||||
|
Type type() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets the type for the image.
|
||||||
|
*
|
||||||
|
* \see Type
|
||||||
|
* \see type()
|
||||||
|
*/
|
||||||
|
void setType(const ASF::Picture::Type& t);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns a text description of the image.
|
||||||
|
*
|
||||||
|
* \see setDescription()
|
||||||
|
*/
|
||||||
|
String description() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets a textual description of the image to \a desc.
|
||||||
|
*
|
||||||
|
* \see description()
|
||||||
|
*/
|
||||||
|
void setDescription(const String &desc);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the image data as a ByteVector.
|
||||||
|
*
|
||||||
|
* \note ByteVector has a data() method that returns a const char * which
|
||||||
|
* should make it easy to export this data to external programs.
|
||||||
|
*
|
||||||
|
* \see setPicture()
|
||||||
|
* \see mimeType()
|
||||||
|
*/
|
||||||
|
ByteVector picture() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets the image data to \a p. \a p should be of the type specified in
|
||||||
|
* this frame's mime-type specification.
|
||||||
|
*
|
||||||
|
* \see picture()
|
||||||
|
* \see mimeType()
|
||||||
|
* \see setMimeType()
|
||||||
|
*/
|
||||||
|
void setPicture(const ByteVector &p);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns picture as binary raw data \a value
|
||||||
|
*/
|
||||||
|
ByteVector render() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns picture as binary raw data \a value
|
||||||
|
*/
|
||||||
|
int dataSize() const;
|
||||||
|
|
||||||
|
#ifndef DO_NOT_DOCUMENT
|
||||||
|
/* THIS IS PRIVATE, DON'T TOUCH IT! */
|
||||||
|
void parse(const ByteVector& );
|
||||||
|
static Picture fromInvalid();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
class PicturePrivate;
|
||||||
|
PicturePrivate *d;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // ASFPICTURE_H
|
||||||
194
3rdparty/taglib/asf/asfproperties.cpp
vendored
Normal file
194
3rdparty/taglib/asf/asfproperties.cpp
vendored
Normal file
@@ -0,0 +1,194 @@
|
|||||||
|
/**************************************************************************
|
||||||
|
copyright : (C) 2005-2007 by Lukáš Lalinský
|
||||||
|
email : lalinsky@gmail.com
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include <tdebug.h>
|
||||||
|
#include <tstring.h>
|
||||||
|
#include "asfproperties.h"
|
||||||
|
|
||||||
|
using namespace TagLib;
|
||||||
|
|
||||||
|
class ASF::Properties::PropertiesPrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PropertiesPrivate() :
|
||||||
|
length(0),
|
||||||
|
bitrate(0),
|
||||||
|
sampleRate(0),
|
||||||
|
channels(0),
|
||||||
|
bitsPerSample(0),
|
||||||
|
codec(ASF::Properties::Unknown),
|
||||||
|
encrypted(false) {}
|
||||||
|
|
||||||
|
int length;
|
||||||
|
int bitrate;
|
||||||
|
int sampleRate;
|
||||||
|
int channels;
|
||||||
|
int bitsPerSample;
|
||||||
|
ASF::Properties::Codec codec;
|
||||||
|
String codecName;
|
||||||
|
String codecDescription;
|
||||||
|
bool encrypted;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// public members
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
ASF::Properties::Properties() :
|
||||||
|
AudioProperties(AudioProperties::Average),
|
||||||
|
d(new PropertiesPrivate())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ASF::Properties::~Properties()
|
||||||
|
{
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ASF::Properties::length() const
|
||||||
|
{
|
||||||
|
return lengthInSeconds();
|
||||||
|
}
|
||||||
|
|
||||||
|
int ASF::Properties::lengthInSeconds() const
|
||||||
|
{
|
||||||
|
return d->length / 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ASF::Properties::lengthInMilliseconds() const
|
||||||
|
{
|
||||||
|
return d->length;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ASF::Properties::bitrate() const
|
||||||
|
{
|
||||||
|
return d->bitrate;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ASF::Properties::sampleRate() const
|
||||||
|
{
|
||||||
|
return d->sampleRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ASF::Properties::channels() const
|
||||||
|
{
|
||||||
|
return d->channels;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ASF::Properties::bitsPerSample() const
|
||||||
|
{
|
||||||
|
return d->bitsPerSample;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASF::Properties::Codec ASF::Properties::codec() const
|
||||||
|
{
|
||||||
|
return d->codec;
|
||||||
|
}
|
||||||
|
|
||||||
|
String ASF::Properties::codecName() const
|
||||||
|
{
|
||||||
|
return d->codecName;
|
||||||
|
}
|
||||||
|
|
||||||
|
String ASF::Properties::codecDescription() const
|
||||||
|
{
|
||||||
|
return d->codecDescription;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ASF::Properties::isEncrypted() const
|
||||||
|
{
|
||||||
|
return d->encrypted;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// private members
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void ASF::Properties::setLength(int /*length*/)
|
||||||
|
{
|
||||||
|
debug("ASF::Properties::setLength() -- This method is deprecated. Do not use.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void ASF::Properties::setLengthInMilliseconds(int value)
|
||||||
|
{
|
||||||
|
d->length = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ASF::Properties::setBitrate(int value)
|
||||||
|
{
|
||||||
|
d->bitrate = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ASF::Properties::setSampleRate(int value)
|
||||||
|
{
|
||||||
|
d->sampleRate = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ASF::Properties::setChannels(int value)
|
||||||
|
{
|
||||||
|
d->channels = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ASF::Properties::setBitsPerSample(int value)
|
||||||
|
{
|
||||||
|
d->bitsPerSample = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ASF::Properties::setCodec(int value)
|
||||||
|
{
|
||||||
|
switch(value)
|
||||||
|
{
|
||||||
|
case 0x0160:
|
||||||
|
d->codec = WMA1;
|
||||||
|
break;
|
||||||
|
case 0x0161:
|
||||||
|
d->codec = WMA2;
|
||||||
|
break;
|
||||||
|
case 0x0162:
|
||||||
|
d->codec = WMA9Pro;
|
||||||
|
break;
|
||||||
|
case 0x0163:
|
||||||
|
d->codec = WMA9Lossless;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
d->codec = Unknown;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ASF::Properties::setCodecName(const String &value)
|
||||||
|
{
|
||||||
|
d->codecName = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ASF::Properties::setCodecDescription(const String &value)
|
||||||
|
{
|
||||||
|
d->codecDescription = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ASF::Properties::setEncrypted(bool value)
|
||||||
|
{
|
||||||
|
d->encrypted = value;
|
||||||
|
}
|
||||||
186
3rdparty/taglib/asf/asfproperties.h
vendored
Normal file
186
3rdparty/taglib/asf/asfproperties.h
vendored
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
/**************************************************************************
|
||||||
|
copyright : (C) 2005-2007 by Lukáš Lalinský
|
||||||
|
email : lalinsky@gmail.com
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef TAGLIB_ASFPROPERTIES_H
|
||||||
|
#define TAGLIB_ASFPROPERTIES_H
|
||||||
|
|
||||||
|
#include "audioproperties.h"
|
||||||
|
#include "tstring.h"
|
||||||
|
#include "taglib_export.h"
|
||||||
|
|
||||||
|
namespace TagLib {
|
||||||
|
|
||||||
|
namespace ASF {
|
||||||
|
|
||||||
|
//! An implementation of ASF audio properties
|
||||||
|
class TAGLIB_EXPORT Properties : public AudioProperties
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Audio codec types can be used in ASF file.
|
||||||
|
*/
|
||||||
|
enum Codec
|
||||||
|
{
|
||||||
|
/*!
|
||||||
|
* Couldn't detect the codec.
|
||||||
|
*/
|
||||||
|
Unknown = 0,
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Windows Media Audio 1
|
||||||
|
*/
|
||||||
|
WMA1,
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Windows Media Audio 2 or above
|
||||||
|
*/
|
||||||
|
WMA2,
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Windows Media Audio 9 Professional
|
||||||
|
*/
|
||||||
|
WMA9Pro,
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Windows Media Audio 9 Lossless
|
||||||
|
*/
|
||||||
|
WMA9Lossless,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Creates an instance of ASF::Properties.
|
||||||
|
*/
|
||||||
|
Properties();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Destroys this ASF::Properties instance.
|
||||||
|
*/
|
||||||
|
virtual ~Properties();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the length of the file in seconds. The length is rounded down to
|
||||||
|
* the nearest whole second.
|
||||||
|
*
|
||||||
|
* \note This method is just an alias of lengthInSeconds().
|
||||||
|
*
|
||||||
|
* \deprecated
|
||||||
|
*/
|
||||||
|
virtual int length() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the length of the file in seconds. The length is rounded down to
|
||||||
|
* the nearest whole second.
|
||||||
|
*
|
||||||
|
* \see lengthInMilliseconds()
|
||||||
|
*/
|
||||||
|
// BIC: make virtual
|
||||||
|
int lengthInSeconds() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the length of the file in milliseconds.
|
||||||
|
*
|
||||||
|
* \see lengthInSeconds()
|
||||||
|
*/
|
||||||
|
// BIC: make virtual
|
||||||
|
int lengthInMilliseconds() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the average bit rate of the file in kb/s.
|
||||||
|
*/
|
||||||
|
virtual int bitrate() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the sample rate in Hz.
|
||||||
|
*/
|
||||||
|
virtual int sampleRate() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the number of audio channels.
|
||||||
|
*/
|
||||||
|
virtual int channels() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the number of bits per audio sample.
|
||||||
|
*/
|
||||||
|
int bitsPerSample() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the codec used in the file.
|
||||||
|
*
|
||||||
|
* \see codecName()
|
||||||
|
* \see codecDescription()
|
||||||
|
*/
|
||||||
|
Codec codec() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the concrete codec name, for example "Windows Media Audio 9.1"
|
||||||
|
* used in the file if available, otherwise an empty string.
|
||||||
|
*
|
||||||
|
* \see codec()
|
||||||
|
* \see codecDescription()
|
||||||
|
*/
|
||||||
|
String codecName() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the codec description, typically contains the encoder settings,
|
||||||
|
* for example "VBR Quality 50, 44kHz, stereo 1-pass VBR" if available,
|
||||||
|
* otherwise an empty string.
|
||||||
|
*
|
||||||
|
* \see codec()
|
||||||
|
* \see codecName()
|
||||||
|
*/
|
||||||
|
String codecDescription() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns whether or not the file is encrypted.
|
||||||
|
*/
|
||||||
|
bool isEncrypted() const;
|
||||||
|
|
||||||
|
#ifndef DO_NOT_DOCUMENT
|
||||||
|
// deprecated
|
||||||
|
void setLength(int value);
|
||||||
|
|
||||||
|
void setLengthInMilliseconds(int value);
|
||||||
|
void setBitrate(int value);
|
||||||
|
void setSampleRate(int value);
|
||||||
|
void setChannels(int value);
|
||||||
|
void setBitsPerSample(int value);
|
||||||
|
void setCodec(int value);
|
||||||
|
void setCodecName(const String &value);
|
||||||
|
void setCodecDescription(const String &value);
|
||||||
|
void setEncrypted(bool value);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
class PropertiesPrivate;
|
||||||
|
PropertiesPrivate *d;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
378
3rdparty/taglib/asf/asftag.cpp
vendored
Normal file
378
3rdparty/taglib/asf/asftag.cpp
vendored
Normal file
@@ -0,0 +1,378 @@
|
|||||||
|
/**************************************************************************
|
||||||
|
copyright : (C) 2005-2007 by Lukáš Lalinský
|
||||||
|
email : lalinsky@gmail.com
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include <tpropertymap.h>
|
||||||
|
#include "asftag.h"
|
||||||
|
|
||||||
|
using namespace TagLib;
|
||||||
|
|
||||||
|
class ASF::Tag::TagPrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
String title;
|
||||||
|
String artist;
|
||||||
|
String copyright;
|
||||||
|
String comment;
|
||||||
|
String rating;
|
||||||
|
AttributeListMap attributeListMap;
|
||||||
|
};
|
||||||
|
|
||||||
|
ASF::Tag::Tag() :
|
||||||
|
TagLib::Tag(),
|
||||||
|
d(new TagPrivate())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ASF::Tag::~Tag()
|
||||||
|
{
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
String ASF::Tag::title() const
|
||||||
|
{
|
||||||
|
return d->title;
|
||||||
|
}
|
||||||
|
|
||||||
|
String ASF::Tag::artist() const
|
||||||
|
{
|
||||||
|
return d->artist;
|
||||||
|
}
|
||||||
|
|
||||||
|
String ASF::Tag::album() const
|
||||||
|
{
|
||||||
|
if(d->attributeListMap.contains("WM/AlbumTitle"))
|
||||||
|
return d->attributeListMap["WM/AlbumTitle"][0].toString();
|
||||||
|
return String();
|
||||||
|
}
|
||||||
|
|
||||||
|
String ASF::Tag::copyright() const
|
||||||
|
{
|
||||||
|
return d->copyright;
|
||||||
|
}
|
||||||
|
|
||||||
|
String ASF::Tag::comment() const
|
||||||
|
{
|
||||||
|
return d->comment;
|
||||||
|
}
|
||||||
|
|
||||||
|
String ASF::Tag::rating() const
|
||||||
|
{
|
||||||
|
return d->rating;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int ASF::Tag::year() const
|
||||||
|
{
|
||||||
|
if(d->attributeListMap.contains("WM/Year"))
|
||||||
|
return d->attributeListMap["WM/Year"][0].toString().toInt();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int ASF::Tag::track() const
|
||||||
|
{
|
||||||
|
if(d->attributeListMap.contains("WM/TrackNumber")) {
|
||||||
|
const ASF::Attribute attr = d->attributeListMap["WM/TrackNumber"][0];
|
||||||
|
if(attr.type() == ASF::Attribute::DWordType)
|
||||||
|
return attr.toUInt();
|
||||||
|
else
|
||||||
|
return attr.toString().toInt();
|
||||||
|
}
|
||||||
|
if(d->attributeListMap.contains("WM/Track"))
|
||||||
|
return d->attributeListMap["WM/Track"][0].toUInt();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
String ASF::Tag::genre() const
|
||||||
|
{
|
||||||
|
if(d->attributeListMap.contains("WM/Genre"))
|
||||||
|
return d->attributeListMap["WM/Genre"][0].toString();
|
||||||
|
return String();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ASF::Tag::setTitle(const String &value)
|
||||||
|
{
|
||||||
|
d->title = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ASF::Tag::setArtist(const String &value)
|
||||||
|
{
|
||||||
|
d->artist = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ASF::Tag::setCopyright(const String &value)
|
||||||
|
{
|
||||||
|
d->copyright = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ASF::Tag::setComment(const String &value)
|
||||||
|
{
|
||||||
|
d->comment = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ASF::Tag::setRating(const String &value)
|
||||||
|
{
|
||||||
|
d->rating = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ASF::Tag::setAlbum(const String &value)
|
||||||
|
{
|
||||||
|
setAttribute("WM/AlbumTitle", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ASF::Tag::setGenre(const String &value)
|
||||||
|
{
|
||||||
|
setAttribute("WM/Genre", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ASF::Tag::setYear(unsigned int value)
|
||||||
|
{
|
||||||
|
setAttribute("WM/Year", String::number(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ASF::Tag::setTrack(unsigned int value)
|
||||||
|
{
|
||||||
|
setAttribute("WM/TrackNumber", String::number(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
ASF::AttributeListMap& ASF::Tag::attributeListMap()
|
||||||
|
{
|
||||||
|
return d->attributeListMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ASF::AttributeListMap &ASF::Tag::attributeListMap() const
|
||||||
|
{
|
||||||
|
return d->attributeListMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ASF::Tag::contains(const String &key) const
|
||||||
|
{
|
||||||
|
return d->attributeListMap.contains(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ASF::Tag::removeItem(const String &key)
|
||||||
|
{
|
||||||
|
d->attributeListMap.erase(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
ASF::AttributeList ASF::Tag::attribute(const String &name) const
|
||||||
|
{
|
||||||
|
return d->attributeListMap[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
void ASF::Tag::setAttribute(const String &name, const Attribute &attribute)
|
||||||
|
{
|
||||||
|
AttributeList value;
|
||||||
|
value.append(attribute);
|
||||||
|
d->attributeListMap.insert(name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ASF::Tag::setAttribute(const String &name, const AttributeList &values)
|
||||||
|
{
|
||||||
|
d->attributeListMap.insert(name, values);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ASF::Tag::addAttribute(const String &name, const Attribute &attribute)
|
||||||
|
{
|
||||||
|
if(d->attributeListMap.contains(name)) {
|
||||||
|
d->attributeListMap[name].append(attribute);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
setAttribute(name, attribute);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ASF::Tag::isEmpty() const
|
||||||
|
{
|
||||||
|
return TagLib::Tag::isEmpty() &&
|
||||||
|
copyright().isEmpty() &&
|
||||||
|
rating().isEmpty() &&
|
||||||
|
d->attributeListMap.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
const char *keyTranslation[][2] = {
|
||||||
|
{ "WM/AlbumTitle", "ALBUM" },
|
||||||
|
{ "WM/AlbumArtist", "ALBUMARTIST" },
|
||||||
|
{ "WM/Composer", "COMPOSER" },
|
||||||
|
{ "WM/Writer", "WRITER" },
|
||||||
|
{ "WM/Conductor", "CONDUCTOR" },
|
||||||
|
{ "WM/ModifiedBy", "REMIXER" },
|
||||||
|
{ "WM/Year", "DATE" },
|
||||||
|
{ "WM/OriginalReleaseYear", "ORIGINALDATE" },
|
||||||
|
{ "WM/Producer", "PRODUCER" },
|
||||||
|
{ "WM/ContentGroupDescription", "GROUPING" },
|
||||||
|
{ "WM/SubTitle", "SUBTITLE" },
|
||||||
|
{ "WM/SetSubTitle", "DISCSUBTITLE" },
|
||||||
|
{ "WM/TrackNumber", "TRACKNUMBER" },
|
||||||
|
{ "WM/PartOfSet", "DISCNUMBER" },
|
||||||
|
{ "WM/Genre", "GENRE" },
|
||||||
|
{ "WM/BeatsPerMinute", "BPM" },
|
||||||
|
{ "WM/Mood", "MOOD" },
|
||||||
|
{ "WM/ISRC", "ISRC" },
|
||||||
|
{ "WM/Lyrics", "LYRICS" },
|
||||||
|
{ "WM/Media", "MEDIA" },
|
||||||
|
{ "WM/Publisher", "LABEL" },
|
||||||
|
{ "WM/CatalogNo", "CATALOGNUMBER" },
|
||||||
|
{ "WM/Barcode", "BARCODE" },
|
||||||
|
{ "WM/EncodedBy", "ENCODEDBY" },
|
||||||
|
{ "WM/AlbumSortOrder", "ALBUMSORT" },
|
||||||
|
{ "WM/AlbumArtistSortOrder", "ALBUMARTISTSORT" },
|
||||||
|
{ "WM/ArtistSortOrder", "ARTISTSORT" },
|
||||||
|
{ "WM/TitleSortOrder", "TITLESORT" },
|
||||||
|
{ "WM/Script", "SCRIPT" },
|
||||||
|
{ "WM/Language", "LANGUAGE" },
|
||||||
|
{ "MusicBrainz/Track Id", "MUSICBRAINZ_TRACKID" },
|
||||||
|
{ "MusicBrainz/Artist Id", "MUSICBRAINZ_ARTISTID" },
|
||||||
|
{ "MusicBrainz/Album Id", "MUSICBRAINZ_ALBUMID" },
|
||||||
|
{ "MusicBrainz/Album Artist Id", "MUSICBRAINZ_ALBUMARTISTID" },
|
||||||
|
{ "MusicBrainz/Release Group Id", "MUSICBRAINZ_RELEASEGROUPID" },
|
||||||
|
{ "MusicBrainz/Work Id", "MUSICBRAINZ_WORKID" },
|
||||||
|
{ "MusicIP/PUID", "MUSICIP_PUID" },
|
||||||
|
{ "Acoustid/Id", "ACOUSTID_ID" },
|
||||||
|
{ "Acoustid/Fingerprint", "ACOUSTID_FINGERPRINT" },
|
||||||
|
};
|
||||||
|
const size_t keyTranslationSize = sizeof(keyTranslation) / sizeof(keyTranslation[0]);
|
||||||
|
|
||||||
|
String translateKey(const String &key)
|
||||||
|
{
|
||||||
|
for(size_t i = 0; i < keyTranslationSize; ++i) {
|
||||||
|
if(key == keyTranslation[i][0])
|
||||||
|
return keyTranslation[i][1];
|
||||||
|
}
|
||||||
|
|
||||||
|
return String();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyMap ASF::Tag::properties() const
|
||||||
|
{
|
||||||
|
PropertyMap props;
|
||||||
|
|
||||||
|
if(!d->title.isEmpty()) {
|
||||||
|
props["TITLE"] = d->title;
|
||||||
|
}
|
||||||
|
if(!d->artist.isEmpty()) {
|
||||||
|
props["ARTIST"] = d->artist;
|
||||||
|
}
|
||||||
|
if(!d->copyright.isEmpty()) {
|
||||||
|
props["COPYRIGHT"] = d->copyright;
|
||||||
|
}
|
||||||
|
if(!d->comment.isEmpty()) {
|
||||||
|
props["COMMENT"] = d->comment;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASF::AttributeListMap::ConstIterator it = d->attributeListMap.begin();
|
||||||
|
for(; it != d->attributeListMap.end(); ++it) {
|
||||||
|
const String key = translateKey(it->first);
|
||||||
|
if(!key.isEmpty()) {
|
||||||
|
AttributeList::ConstIterator it2 = it->second.begin();
|
||||||
|
for(; it2 != it->second.end(); ++it2) {
|
||||||
|
if(key == "TRACKNUMBER") {
|
||||||
|
if(it2->type() == ASF::Attribute::DWordType)
|
||||||
|
props.insert(key, String::number(it2->toUInt()));
|
||||||
|
else
|
||||||
|
props.insert(key, it2->toString());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
props.insert(key, it2->toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
props.unsupportedData().append(it->first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return props;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ASF::Tag::removeUnsupportedProperties(const StringList &props)
|
||||||
|
{
|
||||||
|
StringList::ConstIterator it = props.begin();
|
||||||
|
for(; it != props.end(); ++it)
|
||||||
|
d->attributeListMap.erase(*it);
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyMap ASF::Tag::setProperties(const PropertyMap &props)
|
||||||
|
{
|
||||||
|
static Map<String, String> reverseKeyMap;
|
||||||
|
if(reverseKeyMap.isEmpty()) {
|
||||||
|
int numKeys = sizeof(keyTranslation) / sizeof(keyTranslation[0]);
|
||||||
|
for(int i = 0; i < numKeys; i++) {
|
||||||
|
reverseKeyMap[keyTranslation[i][1]] = keyTranslation[i][0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyMap origProps = properties();
|
||||||
|
PropertyMap::ConstIterator it = origProps.begin();
|
||||||
|
for(; it != origProps.end(); ++it) {
|
||||||
|
if(!props.contains(it->first) || props[it->first].isEmpty()) {
|
||||||
|
if(it->first == "TITLE") {
|
||||||
|
d->title.clear();
|
||||||
|
}
|
||||||
|
else if(it->first == "ARTIST") {
|
||||||
|
d->artist.clear();
|
||||||
|
}
|
||||||
|
else if(it->first == "COMMENT") {
|
||||||
|
d->comment.clear();
|
||||||
|
}
|
||||||
|
else if(it->first == "COPYRIGHT") {
|
||||||
|
d->copyright.clear();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
d->attributeListMap.erase(reverseKeyMap[it->first]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyMap ignoredProps;
|
||||||
|
it = props.begin();
|
||||||
|
for(; it != props.end(); ++it) {
|
||||||
|
if(reverseKeyMap.contains(it->first)) {
|
||||||
|
String name = reverseKeyMap[it->first];
|
||||||
|
removeItem(name);
|
||||||
|
StringList::ConstIterator it2 = it->second.begin();
|
||||||
|
for(; it2 != it->second.end(); ++it2) {
|
||||||
|
addAttribute(name, *it2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(it->first == "TITLE") {
|
||||||
|
d->title = it->second.toString();
|
||||||
|
}
|
||||||
|
else if(it->first == "ARTIST") {
|
||||||
|
d->artist = it->second.toString();
|
||||||
|
}
|
||||||
|
else if(it->first == "COMMENT") {
|
||||||
|
d->comment = it->second.toString();
|
||||||
|
}
|
||||||
|
else if(it->first == "COPYRIGHT") {
|
||||||
|
d->copyright = it->second.toString();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ignoredProps.insert(it->first, it->second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ignoredProps;
|
||||||
|
}
|
||||||
209
3rdparty/taglib/asf/asftag.h
vendored
Normal file
209
3rdparty/taglib/asf/asftag.h
vendored
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
/**************************************************************************
|
||||||
|
copyright : (C) 2005-2007 by Lukáš Lalinský
|
||||||
|
email : lalinsky@gmail.com
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef TAGLIB_ASFTAG_H
|
||||||
|
#define TAGLIB_ASFTAG_H
|
||||||
|
|
||||||
|
#include "tag.h"
|
||||||
|
#include "tlist.h"
|
||||||
|
#include "tmap.h"
|
||||||
|
#include "taglib_export.h"
|
||||||
|
#include "asfattribute.h"
|
||||||
|
|
||||||
|
namespace TagLib {
|
||||||
|
|
||||||
|
namespace ASF {
|
||||||
|
|
||||||
|
typedef List<Attribute> AttributeList;
|
||||||
|
typedef Map<String, AttributeList> AttributeListMap;
|
||||||
|
|
||||||
|
class TAGLIB_EXPORT Tag : public TagLib::Tag {
|
||||||
|
|
||||||
|
friend class File;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Tag();
|
||||||
|
|
||||||
|
virtual ~Tag();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the track name.
|
||||||
|
*/
|
||||||
|
virtual String title() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the artist name.
|
||||||
|
*/
|
||||||
|
virtual String artist() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the album name; if no album name is present in the tag
|
||||||
|
* String::null will be returned.
|
||||||
|
*/
|
||||||
|
virtual String album() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the track comment.
|
||||||
|
*/
|
||||||
|
virtual String comment() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the genre name; if no genre is present in the tag String::null
|
||||||
|
* will be returned.
|
||||||
|
*/
|
||||||
|
virtual String genre() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the rating.
|
||||||
|
*/
|
||||||
|
virtual String rating() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the genre name; if no genre is present in the tag String::null
|
||||||
|
* will be returned.
|
||||||
|
*/
|
||||||
|
virtual String copyright() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the year; if there is no year set, this will return 0.
|
||||||
|
*/
|
||||||
|
virtual unsigned int year() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the track number; if there is no track number set, this will
|
||||||
|
* return 0.
|
||||||
|
*/
|
||||||
|
virtual unsigned int track() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets the title to \a s.
|
||||||
|
*/
|
||||||
|
virtual void setTitle(const String &s);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets the artist to \a s.
|
||||||
|
*/
|
||||||
|
virtual void setArtist(const String &s);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets the album to \a s. If \a s is String::null then this value will be
|
||||||
|
* cleared.
|
||||||
|
*/
|
||||||
|
virtual void setAlbum(const String &s);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets the comment to \a s.
|
||||||
|
*/
|
||||||
|
virtual void setComment(const String &s);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets the rating to \a s.
|
||||||
|
*/
|
||||||
|
virtual void setRating(const String &s);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets the copyright to \a s.
|
||||||
|
*/
|
||||||
|
virtual void setCopyright(const String &s);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets the genre to \a s.
|
||||||
|
*/
|
||||||
|
virtual void setGenre(const String &s);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets the year to \a i. If \a s is 0 then this value will be cleared.
|
||||||
|
*/
|
||||||
|
virtual void setYear(unsigned int i);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets the track to \a i. If \a s is 0 then this value will be cleared.
|
||||||
|
*/
|
||||||
|
virtual void setTrack(unsigned int i);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns true if the tag does not contain any data. This should be
|
||||||
|
* reimplemented in subclasses that provide more than the basic tagging
|
||||||
|
* abilities in this class.
|
||||||
|
*/
|
||||||
|
virtual bool isEmpty() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \deprecated
|
||||||
|
*/
|
||||||
|
AttributeListMap &attributeListMap();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns a reference to the item list map. This is an AttributeListMap of
|
||||||
|
* all of the items in the tag.
|
||||||
|
*/
|
||||||
|
const AttributeListMap &attributeListMap() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \return True if a value for \a attribute is currently set.
|
||||||
|
*/
|
||||||
|
bool contains(const String &name) const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Removes the \a key attribute from the tag
|
||||||
|
*/
|
||||||
|
void removeItem(const String &name);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \return The list of values for the key \a name, or an empty list if no
|
||||||
|
* values have been set.
|
||||||
|
*/
|
||||||
|
AttributeList attribute(const String &name) const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets the \a key attribute to the value of \a attribute. If an attribute
|
||||||
|
* with the \a key is already present, it will be replaced.
|
||||||
|
*/
|
||||||
|
void setAttribute(const String &name, const Attribute &attribute);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets multiple \a values to the key \a name.
|
||||||
|
*/
|
||||||
|
void setAttribute(const String &name, const AttributeList &values);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets the \a key attribute to the value of \a attribute. If an attribute
|
||||||
|
* with the \a key is already present, it will be added to the list.
|
||||||
|
*/
|
||||||
|
void addAttribute(const String &name, const Attribute &attribute);
|
||||||
|
|
||||||
|
PropertyMap properties() const;
|
||||||
|
void removeUnsupportedProperties(const StringList& properties);
|
||||||
|
PropertyMap setProperties(const PropertyMap &properties);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
class TagPrivate;
|
||||||
|
TagPrivate *d;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
104
3rdparty/taglib/asf/asfutils.h
vendored
Normal file
104
3rdparty/taglib/asf/asfutils.h
vendored
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
copyright : (C) 2015 by Tsuda Kageyu
|
||||||
|
email : tsuda.kageyu@gmail.com
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef TAGLIB_ASFUTILS_H
|
||||||
|
#define TAGLIB_ASFUTILS_H
|
||||||
|
|
||||||
|
// THIS FILE IS NOT A PART OF THE TAGLIB API
|
||||||
|
|
||||||
|
#ifndef DO_NOT_DOCUMENT // tell Doxygen not to document this header
|
||||||
|
|
||||||
|
namespace TagLib
|
||||||
|
{
|
||||||
|
namespace ASF
|
||||||
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
inline unsigned short readWORD(File *file, bool *ok = 0)
|
||||||
|
{
|
||||||
|
const ByteVector v = file->readBlock(2);
|
||||||
|
if(v.size() != 2) {
|
||||||
|
if(ok) *ok = false;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if(ok) *ok = true;
|
||||||
|
return v.toUShort(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline unsigned int readDWORD(File *file, bool *ok = 0)
|
||||||
|
{
|
||||||
|
const ByteVector v = file->readBlock(4);
|
||||||
|
if(v.size() != 4) {
|
||||||
|
if(ok) *ok = false;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if(ok) *ok = true;
|
||||||
|
return v.toUInt(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline long long readQWORD(File *file, bool *ok = 0)
|
||||||
|
{
|
||||||
|
const ByteVector v = file->readBlock(8);
|
||||||
|
if(v.size() != 8) {
|
||||||
|
if(ok) *ok = false;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if(ok) *ok = true;
|
||||||
|
return v.toLongLong(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline String readString(File *file, int length)
|
||||||
|
{
|
||||||
|
ByteVector data = file->readBlock(length);
|
||||||
|
unsigned int size = data.size();
|
||||||
|
while (size >= 2) {
|
||||||
|
if(data[size - 1] != '\0' || data[size - 2] != '\0') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
size -= 2;
|
||||||
|
}
|
||||||
|
if(size != data.size()) {
|
||||||
|
data.resize(size);
|
||||||
|
}
|
||||||
|
return String(data, String::UTF16LE);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ByteVector renderString(const String &str, bool includeLength = false)
|
||||||
|
{
|
||||||
|
ByteVector data = str.data(String::UTF16LE) + ByteVector::fromShort(0, false);
|
||||||
|
if(includeLength) {
|
||||||
|
data = ByteVector::fromShort(data.size(), false) + data;
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
111
3rdparty/taglib/audioproperties.cpp
vendored
Normal file
111
3rdparty/taglib/audioproperties.cpp
vendored
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||||
|
email : wheeler@kde.org
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include <tbytevector.h>
|
||||||
|
|
||||||
|
#include "aiffproperties.h"
|
||||||
|
#include "apeproperties.h"
|
||||||
|
#include "asfproperties.h"
|
||||||
|
#include "flacproperties.h"
|
||||||
|
#include "mp4properties.h"
|
||||||
|
#include "mpcproperties.h"
|
||||||
|
#include "mpegproperties.h"
|
||||||
|
#include "opusproperties.h"
|
||||||
|
#include "speexproperties.h"
|
||||||
|
#include "trueaudioproperties.h"
|
||||||
|
#include "vorbisproperties.h"
|
||||||
|
#include "wavproperties.h"
|
||||||
|
#include "wavpackproperties.h"
|
||||||
|
|
||||||
|
#include "audioproperties.h"
|
||||||
|
|
||||||
|
using namespace TagLib;
|
||||||
|
|
||||||
|
// This macro is a workaround for the fact that we can't add virtual functions.
|
||||||
|
// Should be true virtual functions in taglib2.
|
||||||
|
|
||||||
|
#define VIRTUAL_FUNCTION_WORKAROUND(function_name, default_value) \
|
||||||
|
if(dynamic_cast<const APE::Properties*>(this)) \
|
||||||
|
return dynamic_cast<const APE::Properties*>(this)->function_name(); \
|
||||||
|
else if(dynamic_cast<const ASF::Properties*>(this)) \
|
||||||
|
return dynamic_cast<const ASF::Properties*>(this)->function_name(); \
|
||||||
|
else if(dynamic_cast<const FLAC::Properties*>(this)) \
|
||||||
|
return dynamic_cast<const FLAC::Properties*>(this)->function_name(); \
|
||||||
|
else if(dynamic_cast<const MP4::Properties*>(this)) \
|
||||||
|
return dynamic_cast<const MP4::Properties*>(this)->function_name(); \
|
||||||
|
else if(dynamic_cast<const MPC::Properties*>(this)) \
|
||||||
|
return dynamic_cast<const MPC::Properties*>(this)->function_name(); \
|
||||||
|
else if(dynamic_cast<const MPEG::Properties*>(this)) \
|
||||||
|
return dynamic_cast<const MPEG::Properties*>(this)->function_name(); \
|
||||||
|
else if(dynamic_cast<const Ogg::Opus::Properties*>(this)) \
|
||||||
|
return dynamic_cast<const Ogg::Opus::Properties*>(this)->function_name(); \
|
||||||
|
else if(dynamic_cast<const Ogg::Speex::Properties*>(this)) \
|
||||||
|
return dynamic_cast<const Ogg::Speex::Properties*>(this)->function_name(); \
|
||||||
|
else if(dynamic_cast<const TrueAudio::Properties*>(this)) \
|
||||||
|
return dynamic_cast<const TrueAudio::Properties*>(this)->function_name(); \
|
||||||
|
else if(dynamic_cast<const RIFF::AIFF::Properties*>(this)) \
|
||||||
|
return dynamic_cast<const RIFF::AIFF::Properties*>(this)->function_name(); \
|
||||||
|
else if(dynamic_cast<const RIFF::WAV::Properties*>(this)) \
|
||||||
|
return dynamic_cast<const RIFF::WAV::Properties*>(this)->function_name(); \
|
||||||
|
else if(dynamic_cast<const Vorbis::Properties*>(this)) \
|
||||||
|
return dynamic_cast<const Vorbis::Properties*>(this)->function_name(); \
|
||||||
|
else if(dynamic_cast<const WavPack::Properties*>(this)) \
|
||||||
|
return dynamic_cast<const WavPack::Properties*>(this)->function_name(); \
|
||||||
|
else \
|
||||||
|
return (default_value);
|
||||||
|
|
||||||
|
class AudioProperties::AudioPropertiesPrivate
|
||||||
|
{
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// public methods
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
AudioProperties::~AudioProperties()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int AudioProperties::lengthInSeconds() const
|
||||||
|
{
|
||||||
|
VIRTUAL_FUNCTION_WORKAROUND(lengthInSeconds, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
int AudioProperties::lengthInMilliseconds() const
|
||||||
|
{
|
||||||
|
VIRTUAL_FUNCTION_WORKAROUND(lengthInMilliseconds, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// protected methods
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
AudioProperties::AudioProperties(ReadStyle) :
|
||||||
|
d(0)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
127
3rdparty/taglib/audioproperties.h
vendored
Normal file
127
3rdparty/taglib/audioproperties.h
vendored
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||||
|
email : wheeler@kde.org
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef TAGLIB_AUDIOPROPERTIES_H
|
||||||
|
#define TAGLIB_AUDIOPROPERTIES_H
|
||||||
|
|
||||||
|
#include "taglib_export.h"
|
||||||
|
|
||||||
|
namespace TagLib {
|
||||||
|
|
||||||
|
//! A simple, abstract interface to common audio properties
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* The values here are common to most audio formats. For more specific, codec
|
||||||
|
* dependent values, please see see the subclasses APIs. This is meant to
|
||||||
|
* compliment the TagLib::File and TagLib::Tag APIs in providing a simple
|
||||||
|
* interface that is sufficient for most applications.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class TAGLIB_EXPORT AudioProperties
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Reading audio properties from a file can sometimes be very time consuming
|
||||||
|
* and for the most accurate results can often involve reading the entire
|
||||||
|
* file. Because in many situations speed is critical or the accuracy of the
|
||||||
|
* values is not particularly important this allows the level of desired
|
||||||
|
* accuracy to be set.
|
||||||
|
*/
|
||||||
|
enum ReadStyle {
|
||||||
|
//! Read as little of the file as possible
|
||||||
|
Fast,
|
||||||
|
//! Read more of the file and make better values guesses
|
||||||
|
Average,
|
||||||
|
//! Read as much of the file as needed to report accurate values
|
||||||
|
Accurate
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Destroys this AudioProperties instance.
|
||||||
|
*/
|
||||||
|
virtual ~AudioProperties();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the length of the file in seconds.
|
||||||
|
*/
|
||||||
|
virtual int length() const = 0;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the length of the file in seconds. The length is rounded down to
|
||||||
|
* the nearest whole second.
|
||||||
|
*
|
||||||
|
* \see lengthInMilliseconds()
|
||||||
|
*/
|
||||||
|
// BIC: make virtual
|
||||||
|
int lengthInSeconds() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the length of the file in milliseconds.
|
||||||
|
*
|
||||||
|
* \see lengthInSeconds()
|
||||||
|
*/
|
||||||
|
// BIC: make virtual
|
||||||
|
int lengthInMilliseconds() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the most appropriate bit rate for the file in kb/s. For constant
|
||||||
|
* bitrate formats this is simply the bitrate of the file. For variable
|
||||||
|
* bitrate formats this is either the average or nominal bitrate.
|
||||||
|
*/
|
||||||
|
virtual int bitrate() const = 0;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the sample rate in Hz.
|
||||||
|
*/
|
||||||
|
virtual int sampleRate() const = 0;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the number of audio channels.
|
||||||
|
*/
|
||||||
|
virtual int channels() const = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Construct an audio properties instance. This is protected as this class
|
||||||
|
* should not be instantiated directly, but should be instantiated via its
|
||||||
|
* subclasses and can be fetched from the FileRef or File APIs.
|
||||||
|
*
|
||||||
|
* \see ReadStyle
|
||||||
|
*/
|
||||||
|
AudioProperties(ReadStyle style);
|
||||||
|
|
||||||
|
private:
|
||||||
|
AudioProperties(const AudioProperties &);
|
||||||
|
AudioProperties &operator=(const AudioProperties &);
|
||||||
|
|
||||||
|
class AudioPropertiesPrivate;
|
||||||
|
AudioPropertiesPrivate *d;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
474
3rdparty/taglib/fileref.cpp
vendored
Normal file
474
3rdparty/taglib/fileref.cpp
vendored
Normal file
@@ -0,0 +1,474 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||||
|
email : wheeler@kde.org
|
||||||
|
|
||||||
|
copyright : (C) 2010 by Alex Novichkov
|
||||||
|
email : novichko@atnet.ru
|
||||||
|
(added APE file support)
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include <tfile.h>
|
||||||
|
#include <tfilestream.h>
|
||||||
|
#include <tstring.h>
|
||||||
|
#include <tdebug.h>
|
||||||
|
#include <trefcounter.h>
|
||||||
|
|
||||||
|
#include "fileref.h"
|
||||||
|
#include "asffile.h"
|
||||||
|
#include "mpegfile.h"
|
||||||
|
#include "vorbisfile.h"
|
||||||
|
#include "flacfile.h"
|
||||||
|
#include "oggflacfile.h"
|
||||||
|
#include "mpcfile.h"
|
||||||
|
#include "mp4file.h"
|
||||||
|
#include "wavpackfile.h"
|
||||||
|
#include "speexfile.h"
|
||||||
|
#include "opusfile.h"
|
||||||
|
#include "trueaudiofile.h"
|
||||||
|
#include "aifffile.h"
|
||||||
|
#include "wavfile.h"
|
||||||
|
#include "apefile.h"
|
||||||
|
#include "modfile.h"
|
||||||
|
#include "s3mfile.h"
|
||||||
|
#include "itfile.h"
|
||||||
|
#include "xmfile.h"
|
||||||
|
|
||||||
|
using namespace TagLib;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
typedef List<const FileRef::FileTypeResolver *> ResolverList;
|
||||||
|
ResolverList fileTypeResolvers;
|
||||||
|
|
||||||
|
// Detect the file type by user-defined resolvers.
|
||||||
|
|
||||||
|
File *detectByResolvers(FileName fileName, bool readAudioProperties,
|
||||||
|
AudioProperties::ReadStyle audioPropertiesStyle)
|
||||||
|
{
|
||||||
|
ResolverList::ConstIterator it = fileTypeResolvers.begin();
|
||||||
|
for(; it != fileTypeResolvers.end(); ++it) {
|
||||||
|
File *file = (*it)->createFile(fileName, readAudioProperties, audioPropertiesStyle);
|
||||||
|
if(file)
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detect the file type based on the file extension.
|
||||||
|
|
||||||
|
File* detectByExtension(IOStream *stream, bool readAudioProperties,
|
||||||
|
AudioProperties::ReadStyle audioPropertiesStyle)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
const String s = stream->name().toString();
|
||||||
|
#else
|
||||||
|
const String s(stream->name());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
String ext;
|
||||||
|
const int pos = s.rfind(".");
|
||||||
|
if(pos != -1)
|
||||||
|
ext = s.substr(pos + 1).upper();
|
||||||
|
|
||||||
|
// If this list is updated, the method defaultFileExtensions() should also be
|
||||||
|
// updated. However at some point that list should be created at the same time
|
||||||
|
// that a default file type resolver is created.
|
||||||
|
|
||||||
|
if(ext.isEmpty())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// .oga can be any audio in the Ogg container. So leave it to content-based detection.
|
||||||
|
|
||||||
|
if(ext == "MP3")
|
||||||
|
return new MPEG::File(stream, ID3v2::FrameFactory::instance(), readAudioProperties, audioPropertiesStyle);
|
||||||
|
if(ext == "OGG")
|
||||||
|
return new Ogg::Vorbis::File(stream, readAudioProperties, audioPropertiesStyle);
|
||||||
|
if(ext == "FLAC")
|
||||||
|
return new FLAC::File(stream, ID3v2::FrameFactory::instance(), readAudioProperties, audioPropertiesStyle);
|
||||||
|
if(ext == "MPC")
|
||||||
|
return new MPC::File(stream, readAudioProperties, audioPropertiesStyle);
|
||||||
|
if(ext == "WV")
|
||||||
|
return new WavPack::File(stream, readAudioProperties, audioPropertiesStyle);
|
||||||
|
if(ext == "SPX")
|
||||||
|
return new Ogg::Speex::File(stream, readAudioProperties, audioPropertiesStyle);
|
||||||
|
if(ext == "OPUS")
|
||||||
|
return new Ogg::Opus::File(stream, readAudioProperties, audioPropertiesStyle);
|
||||||
|
if(ext == "TTA")
|
||||||
|
return new TrueAudio::File(stream, readAudioProperties, audioPropertiesStyle);
|
||||||
|
if(ext == "M4A" || ext == "M4R" || ext == "M4B" || ext == "M4P" || ext == "MP4" || ext == "3G2" || ext == "M4V")
|
||||||
|
return new MP4::File(stream, readAudioProperties, audioPropertiesStyle);
|
||||||
|
if(ext == "WMA" || ext == "ASF")
|
||||||
|
return new ASF::File(stream, readAudioProperties, audioPropertiesStyle);
|
||||||
|
if(ext == "AIF" || ext == "AIFF" || ext == "AFC" || ext == "AIFC")
|
||||||
|
return new RIFF::AIFF::File(stream, readAudioProperties, audioPropertiesStyle);
|
||||||
|
if(ext == "WAV")
|
||||||
|
return new RIFF::WAV::File(stream, readAudioProperties, audioPropertiesStyle);
|
||||||
|
if(ext == "APE")
|
||||||
|
return new APE::File(stream, readAudioProperties, audioPropertiesStyle);
|
||||||
|
// module, nst and wow are possible but uncommon extensions
|
||||||
|
if(ext == "MOD" || ext == "MODULE" || ext == "NST" || ext == "WOW")
|
||||||
|
return new Mod::File(stream, readAudioProperties, audioPropertiesStyle);
|
||||||
|
if(ext == "S3M")
|
||||||
|
return new S3M::File(stream, readAudioProperties, audioPropertiesStyle);
|
||||||
|
if(ext == "IT")
|
||||||
|
return new IT::File(stream, readAudioProperties, audioPropertiesStyle);
|
||||||
|
if(ext == "XM")
|
||||||
|
return new XM::File(stream, readAudioProperties, audioPropertiesStyle);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detect the file type based on the actual content of the stream.
|
||||||
|
|
||||||
|
File *detectByContent(IOStream *stream, bool readAudioProperties,
|
||||||
|
AudioProperties::ReadStyle audioPropertiesStyle)
|
||||||
|
{
|
||||||
|
File *file = 0;
|
||||||
|
|
||||||
|
if(MPEG::File::isSupported(stream))
|
||||||
|
file = new MPEG::File(stream, ID3v2::FrameFactory::instance(), readAudioProperties, audioPropertiesStyle);
|
||||||
|
else if(Ogg::Vorbis::File::isSupported(stream))
|
||||||
|
file = new Ogg::Vorbis::File(stream, readAudioProperties, audioPropertiesStyle);
|
||||||
|
else if(Ogg::FLAC::File::isSupported(stream))
|
||||||
|
file = new Ogg::FLAC::File(stream, readAudioProperties, audioPropertiesStyle);
|
||||||
|
else if(FLAC::File::isSupported(stream))
|
||||||
|
file = new FLAC::File(stream, ID3v2::FrameFactory::instance(), readAudioProperties, audioPropertiesStyle);
|
||||||
|
else if(MPC::File::isSupported(stream))
|
||||||
|
file = new MPC::File(stream, readAudioProperties, audioPropertiesStyle);
|
||||||
|
else if(WavPack::File::isSupported(stream))
|
||||||
|
file = new WavPack::File(stream, readAudioProperties, audioPropertiesStyle);
|
||||||
|
else if(Ogg::Speex::File::isSupported(stream))
|
||||||
|
file = new Ogg::Speex::File(stream, readAudioProperties, audioPropertiesStyle);
|
||||||
|
else if(Ogg::Opus::File::isSupported(stream))
|
||||||
|
file = new Ogg::Opus::File(stream, readAudioProperties, audioPropertiesStyle);
|
||||||
|
else if(TrueAudio::File::isSupported(stream))
|
||||||
|
file = new TrueAudio::File(stream, readAudioProperties, audioPropertiesStyle);
|
||||||
|
else if(MP4::File::isSupported(stream))
|
||||||
|
file = new MP4::File(stream, readAudioProperties, audioPropertiesStyle);
|
||||||
|
else if(ASF::File::isSupported(stream))
|
||||||
|
file = new ASF::File(stream, readAudioProperties, audioPropertiesStyle);
|
||||||
|
else if(RIFF::AIFF::File::isSupported(stream))
|
||||||
|
file = new RIFF::AIFF::File(stream, readAudioProperties, audioPropertiesStyle);
|
||||||
|
else if(RIFF::WAV::File::isSupported(stream))
|
||||||
|
file = new RIFF::WAV::File(stream, readAudioProperties, audioPropertiesStyle);
|
||||||
|
else if(APE::File::isSupported(stream))
|
||||||
|
file = new APE::File(stream, readAudioProperties, audioPropertiesStyle);
|
||||||
|
|
||||||
|
// isSupported() only does a quick check, so double check the file here.
|
||||||
|
|
||||||
|
if(file) {
|
||||||
|
if(file->isValid())
|
||||||
|
return file;
|
||||||
|
else
|
||||||
|
delete file;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internal function that supports FileRef::create().
|
||||||
|
// This looks redundant, but necessary in order not to change the previous
|
||||||
|
// behavior of FileRef::create().
|
||||||
|
|
||||||
|
File* createInternal(FileName fileName, bool readAudioProperties,
|
||||||
|
AudioProperties::ReadStyle audioPropertiesStyle)
|
||||||
|
{
|
||||||
|
File *file = detectByResolvers(fileName, readAudioProperties, audioPropertiesStyle);
|
||||||
|
if(file)
|
||||||
|
return file;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
const String s = fileName.toString();
|
||||||
|
#else
|
||||||
|
const String s(fileName);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
String ext;
|
||||||
|
const int pos = s.rfind(".");
|
||||||
|
if(pos != -1)
|
||||||
|
ext = s.substr(pos + 1).upper();
|
||||||
|
|
||||||
|
if(ext.isEmpty())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if(ext == "MP3")
|
||||||
|
return new MPEG::File(fileName, ID3v2::FrameFactory::instance(), readAudioProperties, audioPropertiesStyle);
|
||||||
|
if(ext == "OGG")
|
||||||
|
return new Ogg::Vorbis::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||||
|
if(ext == "OGA") {
|
||||||
|
/* .oga can be any audio in the Ogg container. First try FLAC, then Vorbis. */
|
||||||
|
File *file = new Ogg::FLAC::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||||
|
if(file->isValid())
|
||||||
|
return file;
|
||||||
|
delete file;
|
||||||
|
return new Ogg::Vorbis::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||||
|
}
|
||||||
|
if(ext == "FLAC")
|
||||||
|
return new FLAC::File(fileName, ID3v2::FrameFactory::instance(), readAudioProperties, audioPropertiesStyle);
|
||||||
|
if(ext == "MPC")
|
||||||
|
return new MPC::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||||
|
if(ext == "WV")
|
||||||
|
return new WavPack::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||||
|
if(ext == "SPX")
|
||||||
|
return new Ogg::Speex::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||||
|
if(ext == "OPUS")
|
||||||
|
return new Ogg::Opus::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||||
|
if(ext == "TTA")
|
||||||
|
return new TrueAudio::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||||
|
if(ext == "M4A" || ext == "M4R" || ext == "M4B" || ext == "M4P" || ext == "MP4" || ext == "3G2" || ext == "M4V")
|
||||||
|
return new MP4::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||||
|
if(ext == "WMA" || ext == "ASF")
|
||||||
|
return new ASF::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||||
|
if(ext == "AIF" || ext == "AIFF" || ext == "AFC" || ext == "AIFC")
|
||||||
|
return new RIFF::AIFF::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||||
|
if(ext == "WAV")
|
||||||
|
return new RIFF::WAV::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||||
|
if(ext == "APE")
|
||||||
|
return new APE::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||||
|
// module, nst and wow are possible but uncommon extensions
|
||||||
|
if(ext == "MOD" || ext == "MODULE" || ext == "NST" || ext == "WOW")
|
||||||
|
return new Mod::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||||
|
if(ext == "S3M")
|
||||||
|
return new S3M::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||||
|
if(ext == "IT")
|
||||||
|
return new IT::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||||
|
if(ext == "XM")
|
||||||
|
return new XM::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class FileRef::FileRefPrivate : public RefCounter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FileRefPrivate() :
|
||||||
|
RefCounter(),
|
||||||
|
file(0),
|
||||||
|
stream(0) {}
|
||||||
|
|
||||||
|
~FileRefPrivate() {
|
||||||
|
delete file;
|
||||||
|
delete stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
File *file;
|
||||||
|
IOStream *stream;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// public members
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
FileRef::FileRef() :
|
||||||
|
d(new FileRefPrivate())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
FileRef::FileRef(FileName fileName, bool readAudioProperties,
|
||||||
|
AudioProperties::ReadStyle audioPropertiesStyle) :
|
||||||
|
d(new FileRefPrivate())
|
||||||
|
{
|
||||||
|
parse(fileName, readAudioProperties, audioPropertiesStyle);
|
||||||
|
}
|
||||||
|
|
||||||
|
FileRef::FileRef(IOStream* stream, bool readAudioProperties, AudioProperties::ReadStyle audioPropertiesStyle) :
|
||||||
|
d(new FileRefPrivate())
|
||||||
|
{
|
||||||
|
parse(stream, readAudioProperties, audioPropertiesStyle);
|
||||||
|
}
|
||||||
|
|
||||||
|
FileRef::FileRef(File *file) :
|
||||||
|
d(new FileRefPrivate())
|
||||||
|
{
|
||||||
|
d->file = file;
|
||||||
|
}
|
||||||
|
|
||||||
|
FileRef::FileRef(const FileRef &ref) :
|
||||||
|
d(ref.d)
|
||||||
|
{
|
||||||
|
d->ref();
|
||||||
|
}
|
||||||
|
|
||||||
|
FileRef::~FileRef()
|
||||||
|
{
|
||||||
|
if(d->deref())
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
Tag *FileRef::tag() const
|
||||||
|
{
|
||||||
|
if(isNull()) {
|
||||||
|
debug("FileRef::tag() - Called without a valid file.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return d->file->tag();
|
||||||
|
}
|
||||||
|
|
||||||
|
AudioProperties *FileRef::audioProperties() const
|
||||||
|
{
|
||||||
|
if(isNull()) {
|
||||||
|
debug("FileRef::audioProperties() - Called without a valid file.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return d->file->audioProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
File *FileRef::file() const
|
||||||
|
{
|
||||||
|
return d->file;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileRef::save()
|
||||||
|
{
|
||||||
|
if(isNull()) {
|
||||||
|
debug("FileRef::save() - Called without a valid file.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return d->file->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
const FileRef::FileTypeResolver *FileRef::addFileTypeResolver(const FileRef::FileTypeResolver *resolver) // static
|
||||||
|
{
|
||||||
|
fileTypeResolvers.prepend(resolver);
|
||||||
|
return resolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringList FileRef::defaultFileExtensions()
|
||||||
|
{
|
||||||
|
StringList l;
|
||||||
|
|
||||||
|
l.append("ogg");
|
||||||
|
l.append("flac");
|
||||||
|
l.append("oga");
|
||||||
|
l.append("mp3");
|
||||||
|
l.append("mpc");
|
||||||
|
l.append("wv");
|
||||||
|
l.append("spx");
|
||||||
|
l.append("tta");
|
||||||
|
l.append("m4a");
|
||||||
|
l.append("m4r");
|
||||||
|
l.append("m4b");
|
||||||
|
l.append("m4p");
|
||||||
|
l.append("3g2");
|
||||||
|
l.append("mp4");
|
||||||
|
l.append("m4v");
|
||||||
|
l.append("wma");
|
||||||
|
l.append("asf");
|
||||||
|
l.append("aif");
|
||||||
|
l.append("aiff");
|
||||||
|
l.append("wav");
|
||||||
|
l.append("ape");
|
||||||
|
l.append("mod");
|
||||||
|
l.append("module"); // alias for "mod"
|
||||||
|
l.append("nst"); // alias for "mod"
|
||||||
|
l.append("wow"); // alias for "mod"
|
||||||
|
l.append("s3m");
|
||||||
|
l.append("it");
|
||||||
|
l.append("xm");
|
||||||
|
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileRef::isNull() const
|
||||||
|
{
|
||||||
|
return (!d->file || !d->file->isValid());
|
||||||
|
}
|
||||||
|
|
||||||
|
FileRef &FileRef::operator=(const FileRef &ref)
|
||||||
|
{
|
||||||
|
FileRef(ref).swap(*this);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileRef::swap(FileRef &ref)
|
||||||
|
{
|
||||||
|
using std::swap;
|
||||||
|
|
||||||
|
swap(d, ref.d);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileRef::operator==(const FileRef &ref) const
|
||||||
|
{
|
||||||
|
return (ref.d->file == d->file);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileRef::operator!=(const FileRef &ref) const
|
||||||
|
{
|
||||||
|
return (ref.d->file != d->file);
|
||||||
|
}
|
||||||
|
|
||||||
|
File *FileRef::create(FileName fileName, bool readAudioProperties,
|
||||||
|
AudioProperties::ReadStyle audioPropertiesStyle) // static
|
||||||
|
{
|
||||||
|
return createInternal(fileName, readAudioProperties, audioPropertiesStyle);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// private members
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void FileRef::parse(FileName fileName, bool readAudioProperties,
|
||||||
|
AudioProperties::ReadStyle audioPropertiesStyle)
|
||||||
|
{
|
||||||
|
// Try user-defined resolvers.
|
||||||
|
|
||||||
|
d->file = detectByResolvers(fileName, readAudioProperties, audioPropertiesStyle);
|
||||||
|
if(d->file)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Try to resolve file types based on the file extension.
|
||||||
|
|
||||||
|
d->stream = new FileStream(fileName);
|
||||||
|
d->file = detectByExtension(d->stream, readAudioProperties, audioPropertiesStyle);
|
||||||
|
if(d->file)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// At last, try to resolve file types based on the actual content.
|
||||||
|
|
||||||
|
d->file = detectByContent(d->stream, readAudioProperties, audioPropertiesStyle);
|
||||||
|
if(d->file)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Stream have to be closed here if failed to resolve file types.
|
||||||
|
|
||||||
|
delete d->stream;
|
||||||
|
d->stream = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileRef::parse(IOStream *stream, bool readAudioProperties,
|
||||||
|
AudioProperties::ReadStyle audioPropertiesStyle)
|
||||||
|
{
|
||||||
|
// User-defined resolvers won't work with a stream.
|
||||||
|
|
||||||
|
// Try to resolve file types based on the file extension.
|
||||||
|
|
||||||
|
d->file = detectByExtension(stream, readAudioProperties, audioPropertiesStyle);
|
||||||
|
if(d->file)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// At last, try to resolve file types based on the actual content of the file.
|
||||||
|
|
||||||
|
d->file = detectByContent(stream, readAudioProperties, audioPropertiesStyle);
|
||||||
|
}
|
||||||
287
3rdparty/taglib/fileref.h
vendored
Normal file
287
3rdparty/taglib/fileref.h
vendored
Normal file
@@ -0,0 +1,287 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||||
|
email : wheeler@kde.org
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef TAGLIB_FILEREF_H
|
||||||
|
#define TAGLIB_FILEREF_H
|
||||||
|
|
||||||
|
#include "tfile.h"
|
||||||
|
#include "tstringlist.h"
|
||||||
|
|
||||||
|
#include "taglib_export.h"
|
||||||
|
#include "audioproperties.h"
|
||||||
|
|
||||||
|
namespace TagLib {
|
||||||
|
|
||||||
|
class Tag;
|
||||||
|
|
||||||
|
//! This class provides a simple abstraction for creating and handling files
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* FileRef exists to provide a minimal, generic and value-based wrapper around
|
||||||
|
* a File. It is lightweight and implicitly shared, and as such suitable for
|
||||||
|
* pass-by-value use. This hides some of the uglier details of TagLib::File
|
||||||
|
* and the non-generic portions of the concrete file implementations.
|
||||||
|
*
|
||||||
|
* This class is useful in a "simple usage" situation where it is desirable
|
||||||
|
* to be able to get and set some of the tag information that is similar
|
||||||
|
* across file types.
|
||||||
|
*
|
||||||
|
* Also note that it is probably a good idea to plug this into your mime
|
||||||
|
* type system rather than using the constructor that accepts a file name using
|
||||||
|
* the FileTypeResolver.
|
||||||
|
*
|
||||||
|
* \see FileTypeResolver
|
||||||
|
* \see addFileTypeResolver()
|
||||||
|
*/
|
||||||
|
|
||||||
|
class TAGLIB_EXPORT FileRef
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
//! A class for pluggable file type resolution.
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* This class is used to add extend TagLib's very basic file name based file
|
||||||
|
* type resolution.
|
||||||
|
*
|
||||||
|
* This can be accomplished with:
|
||||||
|
*
|
||||||
|
* \code
|
||||||
|
*
|
||||||
|
* class MyFileTypeResolver : FileTypeResolver
|
||||||
|
* {
|
||||||
|
* TagLib::File *createFile(TagLib::FileName *fileName, bool, AudioProperties::ReadStyle) const
|
||||||
|
* {
|
||||||
|
* if(someCheckForAnMP3File(fileName))
|
||||||
|
* return new TagLib::MPEG::File(fileName);
|
||||||
|
* return 0;
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* FileRef::addFileTypeResolver(new MyFileTypeResolver);
|
||||||
|
*
|
||||||
|
* \endcode
|
||||||
|
*
|
||||||
|
* Naturally a less contrived example would be slightly more complex. This
|
||||||
|
* can be used to plug in mime-type detection systems or to add new file types
|
||||||
|
* to TagLib.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class TAGLIB_EXPORT FileTypeResolver
|
||||||
|
{
|
||||||
|
TAGLIB_IGNORE_MISSING_DESTRUCTOR
|
||||||
|
public:
|
||||||
|
/*!
|
||||||
|
* This method must be overridden to provide an additional file type
|
||||||
|
* resolver. If the resolver is able to determine the file type it should
|
||||||
|
* return a valid File object; if not it should return 0.
|
||||||
|
*
|
||||||
|
* \note The created file is then owned by the FileRef and should not be
|
||||||
|
* deleted. Deletion will happen automatically when the FileRef passes
|
||||||
|
* out of scope.
|
||||||
|
*/
|
||||||
|
virtual File *createFile(FileName fileName,
|
||||||
|
bool readAudioProperties = true,
|
||||||
|
AudioProperties::ReadStyle
|
||||||
|
audioPropertiesStyle = AudioProperties::Average) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Creates a null FileRef.
|
||||||
|
*/
|
||||||
|
FileRef();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Create a FileRef from \a fileName. If \a readAudioProperties is true then
|
||||||
|
* the audio properties will be read using \a audioPropertiesStyle. If
|
||||||
|
* \a readAudioProperties is false then \a audioPropertiesStyle will be
|
||||||
|
* ignored.
|
||||||
|
*
|
||||||
|
* Also see the note in the class documentation about why you may not want to
|
||||||
|
* use this method in your application.
|
||||||
|
*/
|
||||||
|
explicit FileRef(FileName fileName,
|
||||||
|
bool readAudioProperties = true,
|
||||||
|
AudioProperties::ReadStyle
|
||||||
|
audioPropertiesStyle = AudioProperties::Average);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Construct a FileRef from an opened \a IOStream. If \a readAudioProperties
|
||||||
|
* is true then the audio properties will be read using \a audioPropertiesStyle.
|
||||||
|
* If \a readAudioProperties is false then \a audioPropertiesStyle will be
|
||||||
|
* ignored.
|
||||||
|
*
|
||||||
|
* Also see the note in the class documentation about why you may not want to
|
||||||
|
* use this method in your application.
|
||||||
|
*
|
||||||
|
* \note TagLib will *not* take ownership of the stream, the caller is
|
||||||
|
* responsible for deleting it after the File object.
|
||||||
|
*/
|
||||||
|
explicit FileRef(IOStream* stream,
|
||||||
|
bool readAudioProperties = true,
|
||||||
|
AudioProperties::ReadStyle
|
||||||
|
audioPropertiesStyle = AudioProperties::Average);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Construct a FileRef using \a file. The FileRef now takes ownership of the
|
||||||
|
* pointer and will delete the File when it passes out of scope.
|
||||||
|
*/
|
||||||
|
explicit FileRef(File *file);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Make a copy of \a ref.
|
||||||
|
*/
|
||||||
|
FileRef(const FileRef &ref);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Destroys this FileRef instance.
|
||||||
|
*/
|
||||||
|
virtual ~FileRef();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns a pointer to represented file's tag.
|
||||||
|
*
|
||||||
|
* \warning This pointer will become invalid when this FileRef and all
|
||||||
|
* copies pass out of scope.
|
||||||
|
*
|
||||||
|
* \warning Do not cast it to any subclasses of \class Tag.
|
||||||
|
* Use tag returning methods of appropriate subclasses of \class File instead.
|
||||||
|
*
|
||||||
|
* \see File::tag()
|
||||||
|
*/
|
||||||
|
Tag *tag() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the audio properties for this FileRef. If no audio properties
|
||||||
|
* were read then this will returns a null pointer.
|
||||||
|
*/
|
||||||
|
AudioProperties *audioProperties() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns a pointer to the file represented by this handler class.
|
||||||
|
*
|
||||||
|
* As a general rule this call should be avoided since if you need to work
|
||||||
|
* with file objects directly, you are probably better served instantiating
|
||||||
|
* the File subclasses (i.e. MPEG::File) manually and working with their APIs.
|
||||||
|
*
|
||||||
|
* This <i>handle</i> exists to provide a minimal, generic and value-based
|
||||||
|
* wrapper around a File. Accessing the file directly generally indicates
|
||||||
|
* a moving away from this simplicity (and into things beyond the scope of
|
||||||
|
* FileRef).
|
||||||
|
*
|
||||||
|
* \warning This pointer will become invalid when this FileRef and all
|
||||||
|
* copies pass out of scope.
|
||||||
|
*/
|
||||||
|
File *file() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Saves the file. Returns true on success.
|
||||||
|
*/
|
||||||
|
bool save();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Adds a FileTypeResolver to the list of those used by TagLib. Each
|
||||||
|
* additional FileTypeResolver is added to the front of a list of resolvers
|
||||||
|
* that are tried. If the FileTypeResolver returns zero the next resolver
|
||||||
|
* is tried.
|
||||||
|
*
|
||||||
|
* Returns a pointer to the added resolver (the same one that's passed in --
|
||||||
|
* this is mostly so that static initializers have something to use for
|
||||||
|
* assignment).
|
||||||
|
*
|
||||||
|
* \see FileTypeResolver
|
||||||
|
*/
|
||||||
|
static const FileTypeResolver *addFileTypeResolver(const FileTypeResolver *resolver);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* As is mentioned elsewhere in this class's documentation, the default file
|
||||||
|
* type resolution code provided by TagLib only works by comparing file
|
||||||
|
* extensions.
|
||||||
|
*
|
||||||
|
* This method returns the list of file extensions that are used by default.
|
||||||
|
*
|
||||||
|
* The extensions are all returned in lowercase, though the comparison used
|
||||||
|
* by TagLib for resolution is case-insensitive.
|
||||||
|
*
|
||||||
|
* \note This does not account for any additional file type resolvers that
|
||||||
|
* are plugged in. Also note that this is not intended to replace a proper
|
||||||
|
* mime-type resolution system, but is just here for reference.
|
||||||
|
*
|
||||||
|
* \see FileTypeResolver
|
||||||
|
*/
|
||||||
|
static StringList defaultFileExtensions();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns true if the file (and as such other pointers) are null.
|
||||||
|
*/
|
||||||
|
bool isNull() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Assign the file pointed to by \a ref to this FileRef.
|
||||||
|
*/
|
||||||
|
FileRef &operator=(const FileRef &ref);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Exchanges the content of the FileRef by the content of \a ref.
|
||||||
|
*/
|
||||||
|
void swap(FileRef &ref);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns true if this FileRef and \a ref point to the same File object.
|
||||||
|
*/
|
||||||
|
bool operator==(const FileRef &ref) const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns true if this FileRef and \a ref do not point to the same File
|
||||||
|
* object.
|
||||||
|
*/
|
||||||
|
bool operator!=(const FileRef &ref) const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* A simple implementation of file type guessing. If \a readAudioProperties
|
||||||
|
* is true then the audio properties will be read using
|
||||||
|
* \a audioPropertiesStyle. If \a readAudioProperties is false then
|
||||||
|
* \a audioPropertiesStyle will be ignored.
|
||||||
|
*
|
||||||
|
* \note You generally shouldn't use this method, but instead the constructor
|
||||||
|
* directly.
|
||||||
|
*
|
||||||
|
* \deprecated
|
||||||
|
*/
|
||||||
|
static File *create(FileName fileName,
|
||||||
|
bool readAudioProperties = true,
|
||||||
|
AudioProperties::ReadStyle audioPropertiesStyle = AudioProperties::Average);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void parse(FileName fileName, bool readAudioProperties, AudioProperties::ReadStyle audioPropertiesStyle);
|
||||||
|
void parse(IOStream *stream, bool readAudioProperties, AudioProperties::ReadStyle audioPropertiesStyle);
|
||||||
|
|
||||||
|
class FileRefPrivate;
|
||||||
|
FileRefPrivate *d;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace TagLib
|
||||||
|
|
||||||
|
#endif
|
||||||
575
3rdparty/taglib/flac/flacfile.cpp
vendored
Normal file
575
3rdparty/taglib/flac/flacfile.cpp
vendored
Normal file
@@ -0,0 +1,575 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
copyright : (C) 2003-2004 by Allan Sandfeld Jensen
|
||||||
|
email : kde@carewolf.org
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include <tbytevector.h>
|
||||||
|
#include <tstring.h>
|
||||||
|
#include <tlist.h>
|
||||||
|
#include <tdebug.h>
|
||||||
|
#include <tagunion.h>
|
||||||
|
#include <tpropertymap.h>
|
||||||
|
#include <tagutils.h>
|
||||||
|
|
||||||
|
#include <id3v2header.h>
|
||||||
|
#include <id3v2tag.h>
|
||||||
|
#include <id3v1tag.h>
|
||||||
|
#include <xiphcomment.h>
|
||||||
|
|
||||||
|
#include "flacpicture.h"
|
||||||
|
#include "flacfile.h"
|
||||||
|
#include "flacmetadatablock.h"
|
||||||
|
#include "flacunknownmetadatablock.h"
|
||||||
|
|
||||||
|
using namespace TagLib;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
typedef List<FLAC::MetadataBlock *> BlockList;
|
||||||
|
typedef BlockList::Iterator BlockIterator;
|
||||||
|
typedef BlockList::Iterator BlockConstIterator;
|
||||||
|
|
||||||
|
enum { FlacXiphIndex = 0, FlacID3v2Index = 1, FlacID3v1Index = 2 };
|
||||||
|
|
||||||
|
const long MinPaddingLength = 4096;
|
||||||
|
const long MaxPaddingLegnth = 1024 * 1024;
|
||||||
|
|
||||||
|
const char LastBlockFlag = '\x80';
|
||||||
|
}
|
||||||
|
|
||||||
|
class FLAC::File::FilePrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FilePrivate(const ID3v2::FrameFactory *frameFactory = ID3v2::FrameFactory::instance()) :
|
||||||
|
ID3v2FrameFactory(frameFactory),
|
||||||
|
ID3v2Location(-1),
|
||||||
|
ID3v2OriginalSize(0),
|
||||||
|
ID3v1Location(-1),
|
||||||
|
properties(0),
|
||||||
|
flacStart(0),
|
||||||
|
streamStart(0),
|
||||||
|
scanned(false)
|
||||||
|
{
|
||||||
|
blocks.setAutoDelete(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
~FilePrivate()
|
||||||
|
{
|
||||||
|
delete properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ID3v2::FrameFactory *ID3v2FrameFactory;
|
||||||
|
long ID3v2Location;
|
||||||
|
long ID3v2OriginalSize;
|
||||||
|
|
||||||
|
long ID3v1Location;
|
||||||
|
|
||||||
|
TagUnion tag;
|
||||||
|
|
||||||
|
Properties *properties;
|
||||||
|
ByteVector xiphCommentData;
|
||||||
|
BlockList blocks;
|
||||||
|
|
||||||
|
long flacStart;
|
||||||
|
long streamStart;
|
||||||
|
bool scanned;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// static members
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
bool FLAC::File::isSupported(IOStream *stream)
|
||||||
|
{
|
||||||
|
// A FLAC file has an ID "fLaC" somewhere. An ID3v2 tag may precede.
|
||||||
|
|
||||||
|
const ByteVector buffer = Utils::readHeader(stream, bufferSize(), true);
|
||||||
|
return (buffer.find("fLaC") >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// public members
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
FLAC::File::File(FileName file, bool readProperties, Properties::ReadStyle) :
|
||||||
|
TagLib::File(file),
|
||||||
|
d(new FilePrivate())
|
||||||
|
{
|
||||||
|
if(isOpen())
|
||||||
|
read(readProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
FLAC::File::File(FileName file, ID3v2::FrameFactory *frameFactory,
|
||||||
|
bool readProperties, Properties::ReadStyle) :
|
||||||
|
TagLib::File(file),
|
||||||
|
d(new FilePrivate(frameFactory))
|
||||||
|
{
|
||||||
|
if(isOpen())
|
||||||
|
read(readProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
FLAC::File::File(IOStream *stream, ID3v2::FrameFactory *frameFactory,
|
||||||
|
bool readProperties, Properties::ReadStyle) :
|
||||||
|
TagLib::File(stream),
|
||||||
|
d(new FilePrivate(frameFactory))
|
||||||
|
{
|
||||||
|
if(isOpen())
|
||||||
|
read(readProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
FLAC::File::~File()
|
||||||
|
{
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
TagLib::Tag *FLAC::File::tag() const
|
||||||
|
{
|
||||||
|
return &d->tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyMap FLAC::File::properties() const
|
||||||
|
{
|
||||||
|
return d->tag.properties();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FLAC::File::removeUnsupportedProperties(const StringList &unsupported)
|
||||||
|
{
|
||||||
|
d->tag.removeUnsupportedProperties(unsupported);
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyMap FLAC::File::setProperties(const PropertyMap &properties)
|
||||||
|
{
|
||||||
|
return xiphComment(true)->setProperties(properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
FLAC::Properties *FLAC::File::audioProperties() const
|
||||||
|
{
|
||||||
|
return d->properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FLAC::File::save()
|
||||||
|
{
|
||||||
|
if(readOnly()) {
|
||||||
|
debug("FLAC::File::save() - Cannot save to a read only file.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!isValid()) {
|
||||||
|
debug("FLAC::File::save() -- Trying to save invalid file.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create new vorbis comments
|
||||||
|
if(!hasXiphComment())
|
||||||
|
Tag::duplicate(&d->tag, xiphComment(true), false);
|
||||||
|
|
||||||
|
d->xiphCommentData = xiphComment()->render(false);
|
||||||
|
|
||||||
|
// Replace metadata blocks
|
||||||
|
|
||||||
|
for(BlockIterator it = d->blocks.begin(); it != d->blocks.end(); ++it) {
|
||||||
|
if((*it)->code() == MetadataBlock::VorbisComment) {
|
||||||
|
// Set the new Vorbis Comment block
|
||||||
|
delete *it;
|
||||||
|
d->blocks.erase(it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
d->blocks.append(new UnknownMetadataBlock(MetadataBlock::VorbisComment, d->xiphCommentData));
|
||||||
|
|
||||||
|
// Render data for the metadata blocks
|
||||||
|
|
||||||
|
ByteVector data;
|
||||||
|
for(BlockConstIterator it = d->blocks.begin(); it != d->blocks.end(); ++it) {
|
||||||
|
ByteVector blockData = (*it)->render();
|
||||||
|
ByteVector blockHeader = ByteVector::fromUInt(blockData.size());
|
||||||
|
blockHeader[0] = (*it)->code();
|
||||||
|
data.append(blockHeader);
|
||||||
|
data.append(blockData);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute the amount of padding, and append that to data.
|
||||||
|
|
||||||
|
long originalLength = d->streamStart - d->flacStart;
|
||||||
|
long paddingLength = originalLength - data.size() - 4;
|
||||||
|
|
||||||
|
if(paddingLength <= 0) {
|
||||||
|
paddingLength = MinPaddingLength;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Padding won't increase beyond 1% of the file size or 1MB.
|
||||||
|
|
||||||
|
long threshold = length() / 100;
|
||||||
|
threshold = std::max(threshold, MinPaddingLength);
|
||||||
|
threshold = std::min(threshold, MaxPaddingLegnth);
|
||||||
|
|
||||||
|
if(paddingLength > threshold)
|
||||||
|
paddingLength = MinPaddingLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector paddingHeader = ByteVector::fromUInt(paddingLength);
|
||||||
|
paddingHeader[0] = static_cast<char>(MetadataBlock::Padding | LastBlockFlag);
|
||||||
|
data.append(paddingHeader);
|
||||||
|
data.resize(static_cast<unsigned int>(data.size() + paddingLength));
|
||||||
|
|
||||||
|
// Write the data to the file
|
||||||
|
|
||||||
|
insert(data, d->flacStart, originalLength);
|
||||||
|
|
||||||
|
d->streamStart += (static_cast<long>(data.size()) - originalLength);
|
||||||
|
|
||||||
|
if(d->ID3v1Location >= 0)
|
||||||
|
d->ID3v1Location += (static_cast<long>(data.size()) - originalLength);
|
||||||
|
|
||||||
|
// Update ID3 tags
|
||||||
|
|
||||||
|
if(ID3v2Tag() && !ID3v2Tag()->isEmpty()) {
|
||||||
|
|
||||||
|
// ID3v2 tag is not empty. Update the old one or create a new one.
|
||||||
|
|
||||||
|
if(d->ID3v2Location < 0)
|
||||||
|
d->ID3v2Location = 0;
|
||||||
|
|
||||||
|
data = ID3v2Tag()->render();
|
||||||
|
insert(data, d->ID3v2Location, d->ID3v2OriginalSize);
|
||||||
|
|
||||||
|
d->flacStart += (static_cast<long>(data.size()) - d->ID3v2OriginalSize);
|
||||||
|
d->streamStart += (static_cast<long>(data.size()) - d->ID3v2OriginalSize);
|
||||||
|
|
||||||
|
if(d->ID3v1Location >= 0)
|
||||||
|
d->ID3v1Location += (static_cast<long>(data.size()) - d->ID3v2OriginalSize);
|
||||||
|
|
||||||
|
d->ID3v2OriginalSize = data.size();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
// ID3v2 tag is empty. Remove the old one.
|
||||||
|
|
||||||
|
if(d->ID3v2Location >= 0) {
|
||||||
|
removeBlock(d->ID3v2Location, d->ID3v2OriginalSize);
|
||||||
|
|
||||||
|
d->flacStart -= d->ID3v2OriginalSize;
|
||||||
|
d->streamStart -= d->ID3v2OriginalSize;
|
||||||
|
|
||||||
|
if(d->ID3v1Location >= 0)
|
||||||
|
d->ID3v1Location -= d->ID3v2OriginalSize;
|
||||||
|
|
||||||
|
d->ID3v2Location = -1;
|
||||||
|
d->ID3v2OriginalSize = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ID3v1Tag() && !ID3v1Tag()->isEmpty()) {
|
||||||
|
|
||||||
|
// ID3v1 tag is not empty. Update the old one or create a new one.
|
||||||
|
|
||||||
|
if(d->ID3v1Location >= 0) {
|
||||||
|
seek(d->ID3v1Location);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
seek(0, End);
|
||||||
|
d->ID3v1Location = tell();
|
||||||
|
}
|
||||||
|
|
||||||
|
writeBlock(ID3v1Tag()->render());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
// ID3v1 tag is empty. Remove the old one.
|
||||||
|
|
||||||
|
if(d->ID3v1Location >= 0) {
|
||||||
|
truncate(d->ID3v1Location);
|
||||||
|
d->ID3v1Location = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ID3v2::Tag *FLAC::File::ID3v2Tag(bool create)
|
||||||
|
{
|
||||||
|
return d->tag.access<ID3v2::Tag>(FlacID3v2Index, create);
|
||||||
|
}
|
||||||
|
|
||||||
|
ID3v1::Tag *FLAC::File::ID3v1Tag(bool create)
|
||||||
|
{
|
||||||
|
return d->tag.access<ID3v1::Tag>(FlacID3v1Index, create);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ogg::XiphComment *FLAC::File::xiphComment(bool create)
|
||||||
|
{
|
||||||
|
return d->tag.access<Ogg::XiphComment>(FlacXiphIndex, create);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FLAC::File::setID3v2FrameFactory(const ID3v2::FrameFactory *factory)
|
||||||
|
{
|
||||||
|
d->ID3v2FrameFactory = factory;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector FLAC::File::streamInfoData()
|
||||||
|
{
|
||||||
|
debug("FLAC::File::streamInfoData() -- This function is obsolete. Returning an empty ByteVector.");
|
||||||
|
return ByteVector();
|
||||||
|
}
|
||||||
|
|
||||||
|
long FLAC::File::streamLength()
|
||||||
|
{
|
||||||
|
debug("FLAC::File::streamLength() -- This function is obsolete. Returning zero.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<FLAC::Picture *> FLAC::File::pictureList()
|
||||||
|
{
|
||||||
|
List<Picture *> pictures;
|
||||||
|
for(BlockConstIterator it = d->blocks.begin(); it != d->blocks.end(); ++it) {
|
||||||
|
Picture *picture = dynamic_cast<Picture *>(*it);
|
||||||
|
if(picture) {
|
||||||
|
pictures.append(picture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pictures;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FLAC::File::addPicture(Picture *picture)
|
||||||
|
{
|
||||||
|
d->blocks.append(picture);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FLAC::File::removePicture(Picture *picture, bool del)
|
||||||
|
{
|
||||||
|
BlockIterator it = d->blocks.find(picture);
|
||||||
|
if(it != d->blocks.end())
|
||||||
|
d->blocks.erase(it);
|
||||||
|
|
||||||
|
if(del)
|
||||||
|
delete picture;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FLAC::File::removePictures()
|
||||||
|
{
|
||||||
|
for(BlockIterator it = d->blocks.begin(); it != d->blocks.end(); ) {
|
||||||
|
if(dynamic_cast<Picture *>(*it)) {
|
||||||
|
delete *it;
|
||||||
|
it = d->blocks.erase(it);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FLAC::File::strip(int tags)
|
||||||
|
{
|
||||||
|
if(tags & ID3v1)
|
||||||
|
d->tag.set(FlacID3v1Index, 0);
|
||||||
|
|
||||||
|
if(tags & ID3v2)
|
||||||
|
d->tag.set(FlacID3v2Index, 0);
|
||||||
|
|
||||||
|
if(tags & XiphComment) {
|
||||||
|
xiphComment()->removeAllFields();
|
||||||
|
xiphComment()->removeAllPictures();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FLAC::File::hasXiphComment() const
|
||||||
|
{
|
||||||
|
return !d->xiphCommentData.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FLAC::File::hasID3v1Tag() const
|
||||||
|
{
|
||||||
|
return (d->ID3v1Location >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FLAC::File::hasID3v2Tag() const
|
||||||
|
{
|
||||||
|
return (d->ID3v2Location >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// private members
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void FLAC::File::read(bool readProperties)
|
||||||
|
{
|
||||||
|
// Look for an ID3v2 tag
|
||||||
|
|
||||||
|
d->ID3v2Location = Utils::findID3v2(this);
|
||||||
|
|
||||||
|
if(d->ID3v2Location >= 0) {
|
||||||
|
d->tag.set(FlacID3v2Index, new ID3v2::Tag(this, d->ID3v2Location, d->ID3v2FrameFactory));
|
||||||
|
d->ID3v2OriginalSize = ID3v2Tag()->header()->completeTagSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look for an ID3v1 tag
|
||||||
|
|
||||||
|
d->ID3v1Location = Utils::findID3v1(this);
|
||||||
|
|
||||||
|
if(d->ID3v1Location >= 0)
|
||||||
|
d->tag.set(FlacID3v1Index, new ID3v1::Tag(this, d->ID3v1Location));
|
||||||
|
|
||||||
|
// Look for FLAC metadata, including vorbis comments
|
||||||
|
|
||||||
|
scan();
|
||||||
|
|
||||||
|
if(!isValid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(!d->xiphCommentData.isEmpty())
|
||||||
|
d->tag.set(FlacXiphIndex, new Ogg::XiphComment(d->xiphCommentData));
|
||||||
|
else
|
||||||
|
d->tag.set(FlacXiphIndex, new Ogg::XiphComment());
|
||||||
|
|
||||||
|
if(readProperties) {
|
||||||
|
|
||||||
|
// First block should be the stream_info metadata
|
||||||
|
|
||||||
|
const ByteVector infoData = d->blocks.front()->render();
|
||||||
|
|
||||||
|
long streamLength;
|
||||||
|
|
||||||
|
if(d->ID3v1Location >= 0)
|
||||||
|
streamLength = d->ID3v1Location - d->streamStart;
|
||||||
|
else
|
||||||
|
streamLength = length() - d->streamStart;
|
||||||
|
|
||||||
|
d->properties = new Properties(infoData, streamLength);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FLAC::File::scan()
|
||||||
|
{
|
||||||
|
// Scan the metadata pages
|
||||||
|
|
||||||
|
if(d->scanned)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(!isValid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
long nextBlockOffset;
|
||||||
|
|
||||||
|
if(d->ID3v2Location >= 0)
|
||||||
|
nextBlockOffset = find("fLaC", d->ID3v2Location + d->ID3v2OriginalSize);
|
||||||
|
else
|
||||||
|
nextBlockOffset = find("fLaC");
|
||||||
|
|
||||||
|
if(nextBlockOffset < 0) {
|
||||||
|
debug("FLAC::File::scan() -- FLAC stream not found");
|
||||||
|
setValid(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nextBlockOffset += 4;
|
||||||
|
d->flacStart = nextBlockOffset;
|
||||||
|
|
||||||
|
while(true) {
|
||||||
|
|
||||||
|
seek(nextBlockOffset);
|
||||||
|
const ByteVector header = readBlock(4);
|
||||||
|
|
||||||
|
// Header format (from spec):
|
||||||
|
// <1> Last-metadata-block flag
|
||||||
|
// <7> BLOCK_TYPE
|
||||||
|
// 0 : STREAMINFO
|
||||||
|
// 1 : PADDING
|
||||||
|
// ..
|
||||||
|
// 4 : VORBIS_COMMENT
|
||||||
|
// ..
|
||||||
|
// 6 : PICTURE
|
||||||
|
// ..
|
||||||
|
// <24> Length of metadata to follow
|
||||||
|
|
||||||
|
const char blockType = header[0] & ~LastBlockFlag;
|
||||||
|
const bool isLastBlock = (header[0] & LastBlockFlag) != 0;
|
||||||
|
const unsigned int blockLength = header.toUInt(1U, 3U);
|
||||||
|
|
||||||
|
// First block should be the stream_info metadata
|
||||||
|
|
||||||
|
if(d->blocks.isEmpty() && blockType != MetadataBlock::StreamInfo) {
|
||||||
|
debug("FLAC::File::scan() -- First block should be the stream_info metadata");
|
||||||
|
setValid(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(blockLength == 0
|
||||||
|
&& blockType != MetadataBlock::Padding && blockType != MetadataBlock::SeekTable)
|
||||||
|
{
|
||||||
|
debug("FLAC::File::scan() -- Zero-sized metadata block found");
|
||||||
|
setValid(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ByteVector data = readBlock(blockLength);
|
||||||
|
if(data.size() != blockLength) {
|
||||||
|
debug("FLAC::File::scan() -- Failed to read a metadata block");
|
||||||
|
setValid(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MetadataBlock *block = 0;
|
||||||
|
|
||||||
|
// Found the vorbis-comment
|
||||||
|
if(blockType == MetadataBlock::VorbisComment) {
|
||||||
|
if(d->xiphCommentData.isEmpty()) {
|
||||||
|
d->xiphCommentData = data;
|
||||||
|
block = new UnknownMetadataBlock(MetadataBlock::VorbisComment, data);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
debug("FLAC::File::scan() -- multiple Vorbis Comment blocks found, discarding");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(blockType == MetadataBlock::Picture) {
|
||||||
|
FLAC::Picture *picture = new FLAC::Picture();
|
||||||
|
if(picture->parse(data)) {
|
||||||
|
block = picture;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
debug("FLAC::File::scan() -- invalid picture found, discarding");
|
||||||
|
delete picture;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(blockType == MetadataBlock::Padding) {
|
||||||
|
// Skip all padding blocks.
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
block = new UnknownMetadataBlock(blockType, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(block)
|
||||||
|
d->blocks.append(block);
|
||||||
|
|
||||||
|
nextBlockOffset += blockLength + 4;
|
||||||
|
|
||||||
|
if(isLastBlock)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// End of metadata, now comes the datastream
|
||||||
|
|
||||||
|
d->streamStart = nextBlockOffset;
|
||||||
|
|
||||||
|
d->scanned = true;
|
||||||
|
}
|
||||||
343
3rdparty/taglib/flac/flacfile.h
vendored
Normal file
343
3rdparty/taglib/flac/flacfile.h
vendored
Normal file
@@ -0,0 +1,343 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
copyright : (C) 2003 by Allan Sandfeld Jensen
|
||||||
|
email : kde@carewolf.org
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef TAGLIB_FLACFILE_H
|
||||||
|
#define TAGLIB_FLACFILE_H
|
||||||
|
|
||||||
|
#include "taglib_export.h"
|
||||||
|
#include "tfile.h"
|
||||||
|
#include "tlist.h"
|
||||||
|
#include "tag.h"
|
||||||
|
|
||||||
|
#include "flacpicture.h"
|
||||||
|
#include "flacproperties.h"
|
||||||
|
|
||||||
|
namespace TagLib {
|
||||||
|
|
||||||
|
class Tag;
|
||||||
|
namespace ID3v2 { class FrameFactory; class Tag; }
|
||||||
|
namespace ID3v1 { class Tag; }
|
||||||
|
namespace Ogg { class XiphComment; }
|
||||||
|
|
||||||
|
//! An implementation of FLAC metadata
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* This is implementation of FLAC metadata for non-Ogg FLAC files. At some
|
||||||
|
* point when Ogg / FLAC is more common there will be a similar implementation
|
||||||
|
* under the Ogg hierarchy.
|
||||||
|
*
|
||||||
|
* This supports ID3v1, ID3v2 and Xiph style comments as well as reading stream
|
||||||
|
* properties from the file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace FLAC {
|
||||||
|
|
||||||
|
//! An implementation of TagLib::File with FLAC specific methods
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* This implements and provides an interface for FLAC files to the
|
||||||
|
* TagLib::Tag and TagLib::AudioProperties interfaces by way of implementing
|
||||||
|
* the abstract TagLib::File API as well as providing some additional
|
||||||
|
* information specific to FLAC files.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class TAGLIB_EXPORT File : public TagLib::File
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/*!
|
||||||
|
* This set of flags is used for various operations and is suitable for
|
||||||
|
* being OR-ed together.
|
||||||
|
*/
|
||||||
|
enum TagTypes {
|
||||||
|
//! Empty set. Matches no tag types.
|
||||||
|
NoTags = 0x0000,
|
||||||
|
//! Matches Vorbis comments.
|
||||||
|
XiphComment = 0x0001,
|
||||||
|
//! Matches ID3v1 tags.
|
||||||
|
ID3v1 = 0x0002,
|
||||||
|
//! Matches ID3v2 tags.
|
||||||
|
ID3v2 = 0x0004,
|
||||||
|
//! Matches all tag types.
|
||||||
|
AllTags = 0xffff
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Constructs a FLAC file from \a file. If \a readProperties is true the
|
||||||
|
* file's audio properties will also be read.
|
||||||
|
*
|
||||||
|
* \note In the current implementation, \a propertiesStyle is ignored.
|
||||||
|
*
|
||||||
|
* \deprecated This constructor will be dropped in favor of the one below
|
||||||
|
* in a future version.
|
||||||
|
*/
|
||||||
|
File(FileName file, bool readProperties = true,
|
||||||
|
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Constructs an FLAC file from \a file. If \a readProperties is true the
|
||||||
|
* file's audio properties will also be read.
|
||||||
|
*
|
||||||
|
* If this file contains and ID3v2 tag the frames will be created using
|
||||||
|
* \a frameFactory.
|
||||||
|
*
|
||||||
|
* \note In the current implementation, \a propertiesStyle is ignored.
|
||||||
|
*/
|
||||||
|
// BIC: merge with the above constructor
|
||||||
|
File(FileName file, ID3v2::FrameFactory *frameFactory,
|
||||||
|
bool readProperties = true,
|
||||||
|
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Constructs a FLAC file from \a stream. If \a readProperties is true the
|
||||||
|
* file's audio properties will also be read.
|
||||||
|
*
|
||||||
|
* \note TagLib will *not* take ownership of the stream, the caller is
|
||||||
|
* responsible for deleting it after the File object.
|
||||||
|
*
|
||||||
|
* If this file contains and ID3v2 tag the frames will be created using
|
||||||
|
* \a frameFactory.
|
||||||
|
*
|
||||||
|
* \note In the current implementation, \a propertiesStyle is ignored.
|
||||||
|
*/
|
||||||
|
// BIC: merge with the above constructor
|
||||||
|
File(IOStream *stream, ID3v2::FrameFactory *frameFactory,
|
||||||
|
bool readProperties = true,
|
||||||
|
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Destroys this instance of the File.
|
||||||
|
*/
|
||||||
|
virtual ~File();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the Tag for this file. This will be a union of XiphComment,
|
||||||
|
* ID3v1 and ID3v2 tags.
|
||||||
|
*
|
||||||
|
* \see ID3v2Tag()
|
||||||
|
* \see ID3v1Tag()
|
||||||
|
* \see XiphComment()
|
||||||
|
*/
|
||||||
|
virtual TagLib::Tag *tag() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Implements the unified property interface -- export function.
|
||||||
|
* If the file contains more than one tag (e.g. XiphComment and ID3v1),
|
||||||
|
* only the first one (in the order XiphComment, ID3v2, ID3v1) will be
|
||||||
|
* converted to the PropertyMap.
|
||||||
|
*/
|
||||||
|
PropertyMap properties() const;
|
||||||
|
|
||||||
|
void removeUnsupportedProperties(const StringList &);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Implements the unified property interface -- import function.
|
||||||
|
* This always creates a Xiph comment, if none exists. The return value
|
||||||
|
* relates to the Xiph comment only.
|
||||||
|
* Ignores any changes to ID3v1 or ID3v2 comments since they are not allowed
|
||||||
|
* in the FLAC specification.
|
||||||
|
*/
|
||||||
|
PropertyMap setProperties(const PropertyMap &);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the FLAC::Properties for this file. If no audio properties
|
||||||
|
* were read then this will return a null pointer.
|
||||||
|
*/
|
||||||
|
virtual Properties *audioProperties() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Save the file. This will primarily save the XiphComment, but
|
||||||
|
* will also keep any old ID3-tags up to date. If the file
|
||||||
|
* has no XiphComment, one will be constructed from the ID3-tags.
|
||||||
|
*
|
||||||
|
* This returns true if the save was successful.
|
||||||
|
*/
|
||||||
|
virtual bool save();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns a pointer to the ID3v2 tag of the file.
|
||||||
|
*
|
||||||
|
* If \a create is false (the default) this returns a null pointer
|
||||||
|
* if there is no valid ID3v2 tag. If \a create is true it will create
|
||||||
|
* an ID3v2 tag if one does not exist and returns a valid pointer.
|
||||||
|
*
|
||||||
|
* \note This may return a valid pointer regardless of whether or not the
|
||||||
|
* file on disk has an ID3v2 tag. Use hasID3v2Tag() to check if the file
|
||||||
|
* on disk actually has an ID3v2 tag.
|
||||||
|
*
|
||||||
|
* \note The Tag <b>is still</b> owned by the MPEG::File and should not be
|
||||||
|
* deleted by the user. It will be deleted when the file (object) is
|
||||||
|
* destroyed.
|
||||||
|
*
|
||||||
|
* \see hasID3v2Tag()
|
||||||
|
*/
|
||||||
|
ID3v2::Tag *ID3v2Tag(bool create = false);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns a pointer to the ID3v1 tag of the file.
|
||||||
|
*
|
||||||
|
* If \a create is false (the default) this returns a null pointer
|
||||||
|
* if there is no valid APE tag. If \a create is true it will create
|
||||||
|
* an APE tag if one does not exist and returns a valid pointer.
|
||||||
|
*
|
||||||
|
* \note This may return a valid pointer regardless of whether or not the
|
||||||
|
* file on disk has an ID3v1 tag. Use hasID3v1Tag() to check if the file
|
||||||
|
* on disk actually has an ID3v1 tag.
|
||||||
|
*
|
||||||
|
* \note The Tag <b>is still</b> owned by the MPEG::File and should not be
|
||||||
|
* deleted by the user. It will be deleted when the file (object) is
|
||||||
|
* destroyed.
|
||||||
|
*
|
||||||
|
* \see hasID3v1Tag()
|
||||||
|
*/
|
||||||
|
ID3v1::Tag *ID3v1Tag(bool create = false);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns a pointer to the XiphComment for the file.
|
||||||
|
*
|
||||||
|
* If \a create is false (the default) this returns a null pointer
|
||||||
|
* if there is no valid XiphComment. If \a create is true it will create
|
||||||
|
* a XiphComment if one does not exist and returns a valid pointer.
|
||||||
|
*
|
||||||
|
* \note This may return a valid pointer regardless of whether or not the
|
||||||
|
* file on disk has a XiphComment. Use hasXiphComment() to check if the
|
||||||
|
* file on disk actually has a XiphComment.
|
||||||
|
*
|
||||||
|
* \note The Tag <b>is still</b> owned by the FLAC::File and should not be
|
||||||
|
* deleted by the user. It will be deleted when the file (object) is
|
||||||
|
* destroyed.
|
||||||
|
*
|
||||||
|
* \see hasXiphComment()
|
||||||
|
*/
|
||||||
|
Ogg::XiphComment *xiphComment(bool create = false);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Set the ID3v2::FrameFactory to something other than the default. This
|
||||||
|
* can be used to specify the way that ID3v2 frames will be interpreted
|
||||||
|
* when
|
||||||
|
*
|
||||||
|
* \see ID3v2FrameFactory
|
||||||
|
* \deprecated This value should be passed in via the constructor
|
||||||
|
*/
|
||||||
|
void setID3v2FrameFactory(const ID3v2::FrameFactory *factory);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the block of data used by FLAC::Properties for parsing the
|
||||||
|
* stream properties.
|
||||||
|
*
|
||||||
|
* \deprecated Always returns an empty vector.
|
||||||
|
*/
|
||||||
|
ByteVector streamInfoData(); // BIC: remove
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the length of the audio-stream, used by FLAC::Properties for
|
||||||
|
* calculating the bitrate.
|
||||||
|
*
|
||||||
|
* \deprecated Always returns zero.
|
||||||
|
*/
|
||||||
|
long streamLength(); // BIC: remove
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns a list of pictures attached to the FLAC file.
|
||||||
|
*/
|
||||||
|
List<Picture *> pictureList();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Removes an attached picture. If \a del is true the picture's memory
|
||||||
|
* will be freed; if it is false, it must be deleted by the user.
|
||||||
|
*/
|
||||||
|
void removePicture(Picture *picture, bool del = true);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Remove all attached images.
|
||||||
|
*/
|
||||||
|
void removePictures();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Add a new picture to the file. The file takes ownership of the
|
||||||
|
* picture and will handle freeing its memory.
|
||||||
|
*
|
||||||
|
* \note The file will be saved only after calling save().
|
||||||
|
*/
|
||||||
|
void addPicture(Picture *picture);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* This will remove the tags that match the OR-ed together TagTypes from
|
||||||
|
* the file. By default it removes all tags.
|
||||||
|
*
|
||||||
|
* \warning This will also invalidate pointers to the tags as their memory
|
||||||
|
* will be freed.
|
||||||
|
*
|
||||||
|
* \note In order to make the removal permanent save() still needs to be
|
||||||
|
* called.
|
||||||
|
*
|
||||||
|
* \note This won't remove the Vorbis comment block completely. The
|
||||||
|
* vendor ID will be preserved.
|
||||||
|
*/
|
||||||
|
void strip(int tags = AllTags);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns whether or not the file on disk actually has a XiphComment.
|
||||||
|
*
|
||||||
|
* \see xiphComment()
|
||||||
|
*/
|
||||||
|
bool hasXiphComment() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns whether or not the file on disk actually has an ID3v1 tag.
|
||||||
|
*
|
||||||
|
* \see ID3v1Tag()
|
||||||
|
*/
|
||||||
|
bool hasID3v1Tag() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns whether or not the file on disk actually has an ID3v2 tag.
|
||||||
|
*
|
||||||
|
* \see ID3v2Tag()
|
||||||
|
*/
|
||||||
|
bool hasID3v2Tag() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns whether or not the given \a stream can be opened as a FLAC
|
||||||
|
* file.
|
||||||
|
*
|
||||||
|
* \note This method is designed to do a quick check. The result may
|
||||||
|
* not necessarily be correct.
|
||||||
|
*/
|
||||||
|
static bool isSupported(IOStream *stream);
|
||||||
|
|
||||||
|
private:
|
||||||
|
File(const File &);
|
||||||
|
File &operator=(const File &);
|
||||||
|
|
||||||
|
void read(bool readProperties);
|
||||||
|
void scan();
|
||||||
|
|
||||||
|
class FilePrivate;
|
||||||
|
FilePrivate *d;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
47
3rdparty/taglib/flac/flacmetadatablock.cpp
vendored
Normal file
47
3rdparty/taglib/flac/flacmetadatablock.cpp
vendored
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
/**************************************************************************
|
||||||
|
copyright : (C) 2010 by Lukáš Lalinský
|
||||||
|
email : lalinsky@gmail.com
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include <taglib.h>
|
||||||
|
#include <tdebug.h>
|
||||||
|
#include "flacmetadatablock.h"
|
||||||
|
|
||||||
|
using namespace TagLib;
|
||||||
|
|
||||||
|
class FLAC::MetadataBlock::MetadataBlockPrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MetadataBlockPrivate() {}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
FLAC::MetadataBlock::MetadataBlock()
|
||||||
|
{
|
||||||
|
d = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
FLAC::MetadataBlock::~MetadataBlock()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
75
3rdparty/taglib/flac/flacmetadatablock.h
vendored
Normal file
75
3rdparty/taglib/flac/flacmetadatablock.h
vendored
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
/**************************************************************************
|
||||||
|
copyright : (C) 2010 by Lukáš Lalinský
|
||||||
|
email : lalinsky@gmail.com
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef TAGLIB_FLACMETADATABLOCK_H
|
||||||
|
#define TAGLIB_FLACMETADATABLOCK_H
|
||||||
|
|
||||||
|
#include "tlist.h"
|
||||||
|
#include "tbytevector.h"
|
||||||
|
#include "taglib_export.h"
|
||||||
|
|
||||||
|
namespace TagLib {
|
||||||
|
|
||||||
|
namespace FLAC {
|
||||||
|
|
||||||
|
class TAGLIB_EXPORT MetadataBlock
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MetadataBlock();
|
||||||
|
virtual ~MetadataBlock();
|
||||||
|
|
||||||
|
enum BlockType {
|
||||||
|
StreamInfo = 0,
|
||||||
|
Padding,
|
||||||
|
Application,
|
||||||
|
SeekTable,
|
||||||
|
VorbisComment,
|
||||||
|
CueSheet,
|
||||||
|
Picture
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the FLAC metadata block type.
|
||||||
|
*/
|
||||||
|
virtual int code() const = 0;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Render the content of the block.
|
||||||
|
*/
|
||||||
|
virtual ByteVector render() const = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
MetadataBlock(const MetadataBlock &item);
|
||||||
|
MetadataBlock &operator=(const MetadataBlock &item);
|
||||||
|
|
||||||
|
class MetadataBlockPrivate;
|
||||||
|
MetadataBlockPrivate *d;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
217
3rdparty/taglib/flac/flacpicture.cpp
vendored
Normal file
217
3rdparty/taglib/flac/flacpicture.cpp
vendored
Normal file
@@ -0,0 +1,217 @@
|
|||||||
|
/**************************************************************************
|
||||||
|
copyright : (C) 2010 by Lukáš Lalinský
|
||||||
|
email : lalinsky@gmail.com
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include <taglib.h>
|
||||||
|
#include <tdebug.h>
|
||||||
|
#include "flacpicture.h"
|
||||||
|
|
||||||
|
using namespace TagLib;
|
||||||
|
|
||||||
|
class FLAC::Picture::PicturePrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PicturePrivate() :
|
||||||
|
type(FLAC::Picture::Other),
|
||||||
|
width(0),
|
||||||
|
height(0),
|
||||||
|
colorDepth(0),
|
||||||
|
numColors(0)
|
||||||
|
{}
|
||||||
|
|
||||||
|
Type type;
|
||||||
|
String mimeType;
|
||||||
|
String description;
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
int colorDepth;
|
||||||
|
int numColors;
|
||||||
|
ByteVector data;
|
||||||
|
};
|
||||||
|
|
||||||
|
FLAC::Picture::Picture() :
|
||||||
|
d(new PicturePrivate())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
FLAC::Picture::Picture(const ByteVector &data) :
|
||||||
|
d(new PicturePrivate())
|
||||||
|
{
|
||||||
|
parse(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
FLAC::Picture::~Picture()
|
||||||
|
{
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FLAC::Picture::code() const
|
||||||
|
{
|
||||||
|
return FLAC::MetadataBlock::Picture;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FLAC::Picture::parse(const ByteVector &data)
|
||||||
|
{
|
||||||
|
if(data.size() < 32) {
|
||||||
|
debug("A picture block must contain at least 5 bytes.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int pos = 0;
|
||||||
|
d->type = FLAC::Picture::Type(data.toUInt(pos));
|
||||||
|
pos += 4;
|
||||||
|
unsigned int mimeTypeLength = data.toUInt(pos);
|
||||||
|
pos += 4;
|
||||||
|
if(pos + mimeTypeLength + 24 > data.size()) {
|
||||||
|
debug("Invalid picture block.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
d->mimeType = String(data.mid(pos, mimeTypeLength), String::UTF8);
|
||||||
|
pos += mimeTypeLength;
|
||||||
|
unsigned int descriptionLength = data.toUInt(pos);
|
||||||
|
pos += 4;
|
||||||
|
if(pos + descriptionLength + 20 > data.size()) {
|
||||||
|
debug("Invalid picture block.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
d->description = String(data.mid(pos, descriptionLength), String::UTF8);
|
||||||
|
pos += descriptionLength;
|
||||||
|
d->width = data.toUInt(pos);
|
||||||
|
pos += 4;
|
||||||
|
d->height = data.toUInt(pos);
|
||||||
|
pos += 4;
|
||||||
|
d->colorDepth = data.toUInt(pos);
|
||||||
|
pos += 4;
|
||||||
|
d->numColors = data.toUInt(pos);
|
||||||
|
pos += 4;
|
||||||
|
unsigned int dataLength = data.toUInt(pos);
|
||||||
|
pos += 4;
|
||||||
|
if(pos + dataLength > data.size()) {
|
||||||
|
debug("Invalid picture block.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
d->data = data.mid(pos, dataLength);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector FLAC::Picture::render() const
|
||||||
|
{
|
||||||
|
ByteVector result;
|
||||||
|
result.append(ByteVector::fromUInt(d->type));
|
||||||
|
ByteVector mimeTypeData = d->mimeType.data(String::UTF8);
|
||||||
|
result.append(ByteVector::fromUInt(mimeTypeData.size()));
|
||||||
|
result.append(mimeTypeData);
|
||||||
|
ByteVector descriptionData = d->description.data(String::UTF8);
|
||||||
|
result.append(ByteVector::fromUInt(descriptionData.size()));
|
||||||
|
result.append(descriptionData);
|
||||||
|
result.append(ByteVector::fromUInt(d->width));
|
||||||
|
result.append(ByteVector::fromUInt(d->height));
|
||||||
|
result.append(ByteVector::fromUInt(d->colorDepth));
|
||||||
|
result.append(ByteVector::fromUInt(d->numColors));
|
||||||
|
result.append(ByteVector::fromUInt(d->data.size()));
|
||||||
|
result.append(d->data);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
FLAC::Picture::Type FLAC::Picture::type() const
|
||||||
|
{
|
||||||
|
return d->type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FLAC::Picture::setType(FLAC::Picture::Type type)
|
||||||
|
{
|
||||||
|
d->type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
String FLAC::Picture::mimeType() const
|
||||||
|
{
|
||||||
|
return d->mimeType;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FLAC::Picture::setMimeType(const String &mimeType)
|
||||||
|
{
|
||||||
|
d->mimeType = mimeType;
|
||||||
|
}
|
||||||
|
|
||||||
|
String FLAC::Picture::description() const
|
||||||
|
{
|
||||||
|
return d->description;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FLAC::Picture::setDescription(const String &description)
|
||||||
|
{
|
||||||
|
d->description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FLAC::Picture::width() const
|
||||||
|
{
|
||||||
|
return d->width;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FLAC::Picture::setWidth(int width)
|
||||||
|
{
|
||||||
|
d->width = width;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FLAC::Picture::height() const
|
||||||
|
{
|
||||||
|
return d->height;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FLAC::Picture::setHeight(int height)
|
||||||
|
{
|
||||||
|
d->height = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FLAC::Picture::colorDepth() const
|
||||||
|
{
|
||||||
|
return d->colorDepth;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FLAC::Picture::setColorDepth(int colorDepth)
|
||||||
|
{
|
||||||
|
d->colorDepth = colorDepth;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FLAC::Picture::numColors() const
|
||||||
|
{
|
||||||
|
return d->numColors;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FLAC::Picture::setNumColors(int numColors)
|
||||||
|
{
|
||||||
|
d->numColors = numColors;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector FLAC::Picture::data() const
|
||||||
|
{
|
||||||
|
return d->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FLAC::Picture::setData(const ByteVector &data)
|
||||||
|
{
|
||||||
|
d->data = data;
|
||||||
|
}
|
||||||
|
|
||||||
208
3rdparty/taglib/flac/flacpicture.h
vendored
Normal file
208
3rdparty/taglib/flac/flacpicture.h
vendored
Normal file
@@ -0,0 +1,208 @@
|
|||||||
|
/**************************************************************************
|
||||||
|
copyright : (C) 2010 by Lukáš Lalinský
|
||||||
|
email : lalinsky@gmail.com
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef TAGLIB_FLACPICTURE_H
|
||||||
|
#define TAGLIB_FLACPICTURE_H
|
||||||
|
|
||||||
|
#include "tlist.h"
|
||||||
|
#include "tstring.h"
|
||||||
|
#include "tbytevector.h"
|
||||||
|
#include "taglib_export.h"
|
||||||
|
#include "flacmetadatablock.h"
|
||||||
|
|
||||||
|
namespace TagLib {
|
||||||
|
|
||||||
|
namespace FLAC {
|
||||||
|
|
||||||
|
class TAGLIB_EXPORT Picture : public MetadataBlock
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* This describes the function or content of the picture.
|
||||||
|
*/
|
||||||
|
enum Type {
|
||||||
|
//! A type not enumerated below
|
||||||
|
Other = 0x00,
|
||||||
|
//! 32x32 PNG image that should be used as the file icon
|
||||||
|
FileIcon = 0x01,
|
||||||
|
//! File icon of a different size or format
|
||||||
|
OtherFileIcon = 0x02,
|
||||||
|
//! Front cover image of the album
|
||||||
|
FrontCover = 0x03,
|
||||||
|
//! Back cover image of the album
|
||||||
|
BackCover = 0x04,
|
||||||
|
//! Inside leaflet page of the album
|
||||||
|
LeafletPage = 0x05,
|
||||||
|
//! Image from the album itself
|
||||||
|
Media = 0x06,
|
||||||
|
//! Picture of the lead artist or soloist
|
||||||
|
LeadArtist = 0x07,
|
||||||
|
//! Picture of the artist or performer
|
||||||
|
Artist = 0x08,
|
||||||
|
//! Picture of the conductor
|
||||||
|
Conductor = 0x09,
|
||||||
|
//! Picture of the band or orchestra
|
||||||
|
Band = 0x0A,
|
||||||
|
//! Picture of the composer
|
||||||
|
Composer = 0x0B,
|
||||||
|
//! Picture of the lyricist or text writer
|
||||||
|
Lyricist = 0x0C,
|
||||||
|
//! Picture of the recording location or studio
|
||||||
|
RecordingLocation = 0x0D,
|
||||||
|
//! Picture of the artists during recording
|
||||||
|
DuringRecording = 0x0E,
|
||||||
|
//! Picture of the artists during performance
|
||||||
|
DuringPerformance = 0x0F,
|
||||||
|
//! Picture from a movie or video related to the track
|
||||||
|
MovieScreenCapture = 0x10,
|
||||||
|
//! Picture of a large, coloured fish
|
||||||
|
ColouredFish = 0x11,
|
||||||
|
//! Illustration related to the track
|
||||||
|
Illustration = 0x12,
|
||||||
|
//! Logo of the band or performer
|
||||||
|
BandLogo = 0x13,
|
||||||
|
//! Logo of the publisher (record company)
|
||||||
|
PublisherLogo = 0x14
|
||||||
|
};
|
||||||
|
|
||||||
|
Picture();
|
||||||
|
Picture(const ByteVector &data);
|
||||||
|
~Picture();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the type of the image.
|
||||||
|
*/
|
||||||
|
Type type() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets the type of the image.
|
||||||
|
*/
|
||||||
|
void setType(Type type);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the mime type of the image. This should in most cases be
|
||||||
|
* "image/png" or "image/jpeg".
|
||||||
|
*/
|
||||||
|
String mimeType() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets the mime type of the image. This should in most cases be
|
||||||
|
* "image/png" or "image/jpeg".
|
||||||
|
*/
|
||||||
|
void setMimeType(const String &m);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns a text description of the image.
|
||||||
|
*/
|
||||||
|
|
||||||
|
String description() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets a textual description of the image to \a desc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void setDescription(const String &desc);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the width of the image.
|
||||||
|
*/
|
||||||
|
int width() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets the width of the image.
|
||||||
|
*/
|
||||||
|
void setWidth(int w);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the height of the image.
|
||||||
|
*/
|
||||||
|
int height() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets the height of the image.
|
||||||
|
*/
|
||||||
|
void setHeight(int h);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the color depth (in bits-per-pixel) of the image.
|
||||||
|
*/
|
||||||
|
int colorDepth() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets the color depth (in bits-per-pixel) of the image.
|
||||||
|
*/
|
||||||
|
void setColorDepth(int depth);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the number of colors used on the image..
|
||||||
|
*/
|
||||||
|
int numColors() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets the number of colors used on the image (for indexed images).
|
||||||
|
*/
|
||||||
|
void setNumColors(int numColors);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the image data.
|
||||||
|
*/
|
||||||
|
ByteVector data() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets the image data.
|
||||||
|
*/
|
||||||
|
void setData(const ByteVector &data);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the FLAC metadata block type.
|
||||||
|
*/
|
||||||
|
int code() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Render the content to the FLAC picture block format.
|
||||||
|
*/
|
||||||
|
ByteVector render() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Parse the picture data in the FLAC picture block format.
|
||||||
|
*/
|
||||||
|
bool parse(const ByteVector &rawData);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Picture(const Picture &item);
|
||||||
|
Picture &operator=(const Picture &item);
|
||||||
|
|
||||||
|
class PicturePrivate;
|
||||||
|
PicturePrivate *d;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef List<Picture> PictureList;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
176
3rdparty/taglib/flac/flacproperties.cpp
vendored
Normal file
176
3rdparty/taglib/flac/flacproperties.cpp
vendored
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
copyright : (C) 2003 by Allan Sandfeld Jensen
|
||||||
|
email : kde@carewolf.org
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include <tstring.h>
|
||||||
|
#include <tdebug.h>
|
||||||
|
|
||||||
|
#include "flacproperties.h"
|
||||||
|
#include "flacfile.h"
|
||||||
|
|
||||||
|
using namespace TagLib;
|
||||||
|
|
||||||
|
class FLAC::Properties::PropertiesPrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PropertiesPrivate() :
|
||||||
|
length(0),
|
||||||
|
bitrate(0),
|
||||||
|
sampleRate(0),
|
||||||
|
bitsPerSample(0),
|
||||||
|
channels(0),
|
||||||
|
sampleFrames(0) {}
|
||||||
|
|
||||||
|
int length;
|
||||||
|
int bitrate;
|
||||||
|
int sampleRate;
|
||||||
|
int bitsPerSample;
|
||||||
|
int channels;
|
||||||
|
unsigned long long sampleFrames;
|
||||||
|
ByteVector signature;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// public members
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
FLAC::Properties::Properties(ByteVector data, long streamLength, ReadStyle style) :
|
||||||
|
AudioProperties(style),
|
||||||
|
d(new PropertiesPrivate())
|
||||||
|
{
|
||||||
|
read(data, streamLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
FLAC::Properties::Properties(File *, ReadStyle style) :
|
||||||
|
AudioProperties(style),
|
||||||
|
d(new PropertiesPrivate())
|
||||||
|
{
|
||||||
|
debug("FLAC::Properties::Properties() - This constructor is no longer used.");
|
||||||
|
}
|
||||||
|
|
||||||
|
FLAC::Properties::~Properties()
|
||||||
|
{
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FLAC::Properties::length() const
|
||||||
|
{
|
||||||
|
return lengthInSeconds();
|
||||||
|
}
|
||||||
|
|
||||||
|
int FLAC::Properties::lengthInSeconds() const
|
||||||
|
{
|
||||||
|
return d->length / 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FLAC::Properties::lengthInMilliseconds() const
|
||||||
|
{
|
||||||
|
return d->length;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FLAC::Properties::bitrate() const
|
||||||
|
{
|
||||||
|
return d->bitrate;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FLAC::Properties::sampleRate() const
|
||||||
|
{
|
||||||
|
return d->sampleRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FLAC::Properties::bitsPerSample() const
|
||||||
|
{
|
||||||
|
return d->bitsPerSample;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FLAC::Properties::sampleWidth() const
|
||||||
|
{
|
||||||
|
return bitsPerSample();
|
||||||
|
}
|
||||||
|
|
||||||
|
int FLAC::Properties::channels() const
|
||||||
|
{
|
||||||
|
return d->channels;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long long FLAC::Properties::sampleFrames() const
|
||||||
|
{
|
||||||
|
return d->sampleFrames;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector FLAC::Properties::signature() const
|
||||||
|
{
|
||||||
|
return d->signature;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// private members
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void FLAC::Properties::read(const ByteVector &data, long streamLength)
|
||||||
|
{
|
||||||
|
if(data.size() < 18) {
|
||||||
|
debug("FLAC::Properties::read() - FLAC properties must contain at least 18 bytes.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int pos = 0;
|
||||||
|
|
||||||
|
// Minimum block size (in samples)
|
||||||
|
pos += 2;
|
||||||
|
|
||||||
|
// Maximum block size (in samples)
|
||||||
|
pos += 2;
|
||||||
|
|
||||||
|
// Minimum frame size (in bytes)
|
||||||
|
pos += 3;
|
||||||
|
|
||||||
|
// Maximum frame size (in bytes)
|
||||||
|
pos += 3;
|
||||||
|
|
||||||
|
const unsigned int flags = data.toUInt(pos, true);
|
||||||
|
pos += 4;
|
||||||
|
|
||||||
|
d->sampleRate = flags >> 12;
|
||||||
|
d->channels = ((flags >> 9) & 7) + 1;
|
||||||
|
d->bitsPerSample = ((flags >> 4) & 31) + 1;
|
||||||
|
|
||||||
|
// The last 4 bits are the most significant 4 bits for the 36 bit
|
||||||
|
// stream length in samples. (Audio files measured in days)
|
||||||
|
|
||||||
|
const unsigned long long hi = flags & 0xf;
|
||||||
|
const unsigned long long lo = data.toUInt(pos, true);
|
||||||
|
pos += 4;
|
||||||
|
|
||||||
|
d->sampleFrames = (hi << 32) | lo;
|
||||||
|
|
||||||
|
if(d->sampleFrames > 0 && d->sampleRate > 0) {
|
||||||
|
const double length = d->sampleFrames * 1000.0 / d->sampleRate;
|
||||||
|
d->length = static_cast<int>(length + 0.5);
|
||||||
|
d->bitrate = static_cast<int>(streamLength * 8.0 / length + 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(data.size() >= pos + 16)
|
||||||
|
d->signature = data.mid(pos, 16);
|
||||||
|
}
|
||||||
148
3rdparty/taglib/flac/flacproperties.h
vendored
Normal file
148
3rdparty/taglib/flac/flacproperties.h
vendored
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
copyright : (C) 2003 by Allan Sandfeld Jensen
|
||||||
|
email : kde@carewolf.org
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef TAGLIB_FLACPROPERTIES_H
|
||||||
|
#define TAGLIB_FLACPROPERTIES_H
|
||||||
|
|
||||||
|
#include "taglib_export.h"
|
||||||
|
#include "audioproperties.h"
|
||||||
|
|
||||||
|
namespace TagLib {
|
||||||
|
|
||||||
|
namespace FLAC {
|
||||||
|
|
||||||
|
class File;
|
||||||
|
|
||||||
|
//! An implementation of audio property reading for FLAC
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* This reads the data from an FLAC stream found in the AudioProperties
|
||||||
|
* API.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class TAGLIB_EXPORT Properties : public AudioProperties
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/*!
|
||||||
|
* Create an instance of FLAC::Properties with the data read from the
|
||||||
|
* ByteVector \a data.
|
||||||
|
*/
|
||||||
|
// BIC: switch to const reference
|
||||||
|
Properties(ByteVector data, long streamLength, ReadStyle style = Average);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Create an instance of FLAC::Properties with the data read from the
|
||||||
|
* FLAC::File \a file.
|
||||||
|
*/
|
||||||
|
// BIC: remove
|
||||||
|
Properties(File *file, ReadStyle style = Average);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Destroys this FLAC::Properties instance.
|
||||||
|
*/
|
||||||
|
virtual ~Properties();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the length of the file in seconds. The length is rounded down to
|
||||||
|
* the nearest whole second.
|
||||||
|
*
|
||||||
|
* \note This method is just an alias of lengthInSeconds().
|
||||||
|
*
|
||||||
|
* \deprecated
|
||||||
|
*/
|
||||||
|
virtual int length() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the length of the file in seconds. The length is rounded down to
|
||||||
|
* the nearest whole second.
|
||||||
|
*
|
||||||
|
* \see lengthInMilliseconds()
|
||||||
|
*/
|
||||||
|
// BIC: make virtual
|
||||||
|
int lengthInSeconds() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the length of the file in milliseconds.
|
||||||
|
*
|
||||||
|
* \see lengthInSeconds()
|
||||||
|
*/
|
||||||
|
// BIC: make virtual
|
||||||
|
int lengthInMilliseconds() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the average bit rate of the file in kb/s.
|
||||||
|
*/
|
||||||
|
virtual int bitrate() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the sample rate in Hz.
|
||||||
|
*/
|
||||||
|
virtual int sampleRate() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the number of audio channels.
|
||||||
|
*/
|
||||||
|
virtual int channels() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the number of bits per audio sample as read from the FLAC
|
||||||
|
* identification header.
|
||||||
|
*/
|
||||||
|
int bitsPerSample() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the sample width as read from the FLAC identification
|
||||||
|
* header.
|
||||||
|
*
|
||||||
|
* \note This method is just an alias of bitsPerSample().
|
||||||
|
*
|
||||||
|
* \deprecated
|
||||||
|
*/
|
||||||
|
int sampleWidth() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Return the number of sample frames.
|
||||||
|
*/
|
||||||
|
unsigned long long sampleFrames() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the MD5 signature of the uncompressed audio stream as read
|
||||||
|
* from the stream info header.
|
||||||
|
*/
|
||||||
|
ByteVector signature() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Properties(const Properties &);
|
||||||
|
Properties &operator=(const Properties &);
|
||||||
|
|
||||||
|
void read(const ByteVector &data, long streamLength);
|
||||||
|
|
||||||
|
class PropertiesPrivate;
|
||||||
|
PropertiesPrivate *d;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
78
3rdparty/taglib/flac/flacunknownmetadatablock.cpp
vendored
Normal file
78
3rdparty/taglib/flac/flacunknownmetadatablock.cpp
vendored
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
/**************************************************************************
|
||||||
|
copyright : (C) 2010 by Lukáš Lalinský
|
||||||
|
email : lalinsky@gmail.com
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include <taglib.h>
|
||||||
|
#include <tdebug.h>
|
||||||
|
#include <tstring.h>
|
||||||
|
#include "flacunknownmetadatablock.h"
|
||||||
|
|
||||||
|
using namespace TagLib;
|
||||||
|
|
||||||
|
class FLAC::UnknownMetadataBlock::UnknownMetadataBlockPrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
UnknownMetadataBlockPrivate() : code(0) {}
|
||||||
|
|
||||||
|
int code;
|
||||||
|
ByteVector data;
|
||||||
|
};
|
||||||
|
|
||||||
|
FLAC::UnknownMetadataBlock::UnknownMetadataBlock(int code, const ByteVector &data) :
|
||||||
|
d(new UnknownMetadataBlockPrivate())
|
||||||
|
{
|
||||||
|
d->code = code;
|
||||||
|
d->data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
FLAC::UnknownMetadataBlock::~UnknownMetadataBlock()
|
||||||
|
{
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FLAC::UnknownMetadataBlock::code() const
|
||||||
|
{
|
||||||
|
return d->code;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FLAC::UnknownMetadataBlock::setCode(int code)
|
||||||
|
{
|
||||||
|
d->code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector FLAC::UnknownMetadataBlock::data() const
|
||||||
|
{
|
||||||
|
return d->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FLAC::UnknownMetadataBlock::setData(const ByteVector &data)
|
||||||
|
{
|
||||||
|
d->data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector FLAC::UnknownMetadataBlock::render() const
|
||||||
|
{
|
||||||
|
return d->data;
|
||||||
|
}
|
||||||
|
|
||||||
81
3rdparty/taglib/flac/flacunknownmetadatablock.h
vendored
Normal file
81
3rdparty/taglib/flac/flacunknownmetadatablock.h
vendored
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
/**************************************************************************
|
||||||
|
copyright : (C) 2010 by Lukáš Lalinský
|
||||||
|
email : lalinsky@gmail.com
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef TAGLIB_FLACUNKNOWNMETADATABLOCK_H
|
||||||
|
#define TAGLIB_FLACUNKNOWNMETADATABLOCK_H
|
||||||
|
|
||||||
|
#include "tlist.h"
|
||||||
|
#include "tbytevector.h"
|
||||||
|
#include "taglib_export.h"
|
||||||
|
#include "flacmetadatablock.h"
|
||||||
|
|
||||||
|
namespace TagLib {
|
||||||
|
|
||||||
|
namespace FLAC {
|
||||||
|
|
||||||
|
class TAGLIB_EXPORT UnknownMetadataBlock : public MetadataBlock
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
UnknownMetadataBlock(int blockType, const ByteVector &data);
|
||||||
|
~UnknownMetadataBlock();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the FLAC metadata block type.
|
||||||
|
*/
|
||||||
|
int code() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets the FLAC metadata block type.
|
||||||
|
*/
|
||||||
|
void setCode(int code);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the FLAC metadata block type.
|
||||||
|
*/
|
||||||
|
ByteVector data() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets the FLAC metadata block type.
|
||||||
|
*/
|
||||||
|
void setData(const ByteVector &data);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Render the content of the block.
|
||||||
|
*/
|
||||||
|
ByteVector render() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
UnknownMetadataBlock(const MetadataBlock &item);
|
||||||
|
UnknownMetadataBlock &operator=(const MetadataBlock &item);
|
||||||
|
|
||||||
|
class UnknownMetadataBlockPrivate;
|
||||||
|
UnknownMetadataBlockPrivate *d;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
335
3rdparty/taglib/it/itfile.cpp
vendored
Normal file
335
3rdparty/taglib/it/itfile.cpp
vendored
Normal file
@@ -0,0 +1,335 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
copyright : (C) 2011 by Mathias Panzenböck
|
||||||
|
email : grosser.meister.morti@gmx.net
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
#include "tstringlist.h"
|
||||||
|
#include "itfile.h"
|
||||||
|
#include "tdebug.h"
|
||||||
|
#include "modfileprivate.h"
|
||||||
|
#include "tpropertymap.h"
|
||||||
|
|
||||||
|
using namespace TagLib;
|
||||||
|
using namespace IT;
|
||||||
|
|
||||||
|
class IT::File::FilePrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FilePrivate(AudioProperties::ReadStyle propertiesStyle)
|
||||||
|
: tag(), properties(propertiesStyle)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Mod::Tag tag;
|
||||||
|
IT::Properties properties;
|
||||||
|
};
|
||||||
|
|
||||||
|
IT::File::File(FileName file, bool readProperties,
|
||||||
|
AudioProperties::ReadStyle propertiesStyle) :
|
||||||
|
Mod::FileBase(file),
|
||||||
|
d(new FilePrivate(propertiesStyle))
|
||||||
|
{
|
||||||
|
if(isOpen())
|
||||||
|
read(readProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
IT::File::File(IOStream *stream, bool readProperties,
|
||||||
|
AudioProperties::ReadStyle propertiesStyle) :
|
||||||
|
Mod::FileBase(stream),
|
||||||
|
d(new FilePrivate(propertiesStyle))
|
||||||
|
{
|
||||||
|
if(isOpen())
|
||||||
|
read(readProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
IT::File::~File()
|
||||||
|
{
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mod::Tag *IT::File::tag() const
|
||||||
|
{
|
||||||
|
return &d->tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyMap IT::File::properties() const
|
||||||
|
{
|
||||||
|
return d->tag.properties();
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyMap IT::File::setProperties(const PropertyMap &properties)
|
||||||
|
{
|
||||||
|
return d->tag.setProperties(properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
IT::Properties *IT::File::audioProperties() const
|
||||||
|
{
|
||||||
|
return &d->properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IT::File::save()
|
||||||
|
{
|
||||||
|
if(readOnly())
|
||||||
|
{
|
||||||
|
debug("IT::File::save() - Cannot save to a read only file.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
seek(4);
|
||||||
|
writeString(d->tag.title(), 25);
|
||||||
|
writeByte(0);
|
||||||
|
|
||||||
|
seek(2, Current);
|
||||||
|
|
||||||
|
unsigned short length = 0;
|
||||||
|
unsigned short instrumentCount = 0;
|
||||||
|
unsigned short sampleCount = 0;
|
||||||
|
|
||||||
|
if(!readU16L(length) || !readU16L(instrumentCount) || !readU16L(sampleCount))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
seek(15, Current);
|
||||||
|
|
||||||
|
// write comment as instrument and sample names:
|
||||||
|
StringList lines = d->tag.comment().split("\n");
|
||||||
|
for(unsigned short i = 0; i < instrumentCount; ++ i) {
|
||||||
|
seek(192L + length + ((long)i << 2));
|
||||||
|
unsigned long instrumentOffset = 0;
|
||||||
|
if(!readU32L(instrumentOffset))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
seek(instrumentOffset + 32);
|
||||||
|
|
||||||
|
if(i < lines.size())
|
||||||
|
writeString(lines[i], 25);
|
||||||
|
else
|
||||||
|
writeString(String(), 25);
|
||||||
|
writeByte(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(unsigned short i = 0; i < sampleCount; ++ i) {
|
||||||
|
seek(192L + length + ((long)instrumentCount << 2) + ((long)i << 2));
|
||||||
|
unsigned long sampleOffset = 0;
|
||||||
|
if(!readU32L(sampleOffset))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
seek(sampleOffset + 20);
|
||||||
|
|
||||||
|
if((unsigned int)(i + instrumentCount) < lines.size())
|
||||||
|
writeString(lines[i + instrumentCount], 25);
|
||||||
|
else
|
||||||
|
writeString(String(), 25);
|
||||||
|
writeByte(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// write rest as message:
|
||||||
|
StringList messageLines;
|
||||||
|
for(unsigned int i = instrumentCount + sampleCount; i < lines.size(); ++ i)
|
||||||
|
messageLines.append(lines[i]);
|
||||||
|
ByteVector message = messageLines.toString("\r").data(String::Latin1);
|
||||||
|
|
||||||
|
// it's actually not really stated if the message needs a
|
||||||
|
// terminating NUL but it does not hurt to add one:
|
||||||
|
if(message.size() > 7999)
|
||||||
|
message.resize(7999);
|
||||||
|
message.append((char)0);
|
||||||
|
|
||||||
|
unsigned short special = 0;
|
||||||
|
unsigned short messageLength = 0;
|
||||||
|
unsigned long messageOffset = 0;
|
||||||
|
|
||||||
|
seek(46);
|
||||||
|
if(!readU16L(special))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
unsigned long fileSize = File::length();
|
||||||
|
if(special & Properties::MessageAttached) {
|
||||||
|
seek(54);
|
||||||
|
if(!readU16L(messageLength) || !readU32L(messageOffset))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(messageLength == 0)
|
||||||
|
messageOffset = fileSize;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
messageOffset = fileSize;
|
||||||
|
seek(46);
|
||||||
|
writeU16L(special | 0x1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(messageOffset + messageLength >= fileSize) {
|
||||||
|
// append new message
|
||||||
|
seek(54);
|
||||||
|
writeU16L(message.size());
|
||||||
|
writeU32L(messageOffset);
|
||||||
|
seek(messageOffset);
|
||||||
|
writeBlock(message);
|
||||||
|
truncate(messageOffset + message.size());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Only overwrite existing message.
|
||||||
|
// I'd need to parse (understand!) the whole file for more.
|
||||||
|
// Although I could just move the message to the end of file
|
||||||
|
// and let the existing one be, but that would waste space.
|
||||||
|
message.resize(messageLength, 0);
|
||||||
|
seek(messageOffset);
|
||||||
|
writeBlock(message);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IT::File::read(bool)
|
||||||
|
{
|
||||||
|
if(!isOpen())
|
||||||
|
return;
|
||||||
|
|
||||||
|
seek(0);
|
||||||
|
READ_ASSERT(readBlock(4) == "IMPM");
|
||||||
|
READ_STRING(d->tag.setTitle, 26);
|
||||||
|
|
||||||
|
seek(2, Current);
|
||||||
|
|
||||||
|
READ_U16L_AS(length);
|
||||||
|
READ_U16L_AS(instrumentCount);
|
||||||
|
READ_U16L_AS(sampleCount);
|
||||||
|
|
||||||
|
d->properties.setInstrumentCount(instrumentCount);
|
||||||
|
d->properties.setSampleCount(sampleCount);
|
||||||
|
READ_U16L(d->properties.setPatternCount);
|
||||||
|
READ_U16L(d->properties.setVersion);
|
||||||
|
READ_U16L(d->properties.setCompatibleVersion);
|
||||||
|
READ_U16L(d->properties.setFlags);
|
||||||
|
READ_U16L_AS(special);
|
||||||
|
d->properties.setSpecial(special);
|
||||||
|
READ_BYTE(d->properties.setGlobalVolume);
|
||||||
|
READ_BYTE(d->properties.setMixVolume);
|
||||||
|
READ_BYTE(d->properties.setBpmSpeed);
|
||||||
|
READ_BYTE(d->properties.setTempo);
|
||||||
|
READ_BYTE(d->properties.setPanningSeparation);
|
||||||
|
READ_BYTE(d->properties.setPitchWheelDepth);
|
||||||
|
|
||||||
|
// IT supports some kind of comment tag. Still, the
|
||||||
|
// sample/instrument names are abused as comments so
|
||||||
|
// I just add all together.
|
||||||
|
String message;
|
||||||
|
if(special & Properties::MessageAttached) {
|
||||||
|
READ_U16L_AS(messageLength);
|
||||||
|
READ_U32L_AS(messageOffset);
|
||||||
|
seek(messageOffset);
|
||||||
|
ByteVector messageBytes = readBlock(messageLength);
|
||||||
|
READ_ASSERT(messageBytes.size() == messageLength);
|
||||||
|
int index = messageBytes.find((char) 0);
|
||||||
|
if(index > -1)
|
||||||
|
messageBytes.resize(index, 0);
|
||||||
|
messageBytes.replace('\r', '\n');
|
||||||
|
message = messageBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
seek(64);
|
||||||
|
|
||||||
|
ByteVector pannings = readBlock(64);
|
||||||
|
ByteVector volumes = readBlock(64);
|
||||||
|
READ_ASSERT(pannings.size() == 64 && volumes.size() == 64);
|
||||||
|
int channels = 0;
|
||||||
|
for(int i = 0; i < 64; ++ i) {
|
||||||
|
// Strictly speaking an IT file has always 64 channels, but
|
||||||
|
// I don't count disabled and muted channels.
|
||||||
|
// But this always gives 64 channels for all my files anyway.
|
||||||
|
// Strangely VLC does report other values. I wonder how VLC
|
||||||
|
// gets it's values.
|
||||||
|
if((unsigned char) pannings[i] < 128 && volumes[i] > 0)
|
||||||
|
++channels;
|
||||||
|
}
|
||||||
|
d->properties.setChannels(channels);
|
||||||
|
|
||||||
|
// real length might be shorter because of skips and terminator
|
||||||
|
unsigned short realLength = 0;
|
||||||
|
for(unsigned short i = 0; i < length; ++ i) {
|
||||||
|
READ_BYTE_AS(order);
|
||||||
|
if(order == 255) break;
|
||||||
|
if(order != 254) ++ realLength;
|
||||||
|
}
|
||||||
|
d->properties.setLengthInPatterns(realLength);
|
||||||
|
|
||||||
|
StringList comment;
|
||||||
|
// Note: I found files that have nil characters somewhere
|
||||||
|
// in the instrument/sample names and more characters
|
||||||
|
// afterwards. The spec does not mention such a case.
|
||||||
|
// Currently I just discard anything after a nil, but
|
||||||
|
// e.g. VLC seems to interprete a nil as a space. I
|
||||||
|
// don't know what is the proper behaviour.
|
||||||
|
for(unsigned short i = 0; i < instrumentCount; ++ i) {
|
||||||
|
seek(192L + length + ((long)i << 2));
|
||||||
|
READ_U32L_AS(instrumentOffset);
|
||||||
|
seek(instrumentOffset);
|
||||||
|
|
||||||
|
ByteVector instrumentMagic = readBlock(4);
|
||||||
|
READ_ASSERT(instrumentMagic == "IMPI");
|
||||||
|
|
||||||
|
READ_STRING_AS(dosFileName, 13);
|
||||||
|
|
||||||
|
seek(15, Current);
|
||||||
|
|
||||||
|
READ_STRING_AS(instrumentName, 26);
|
||||||
|
comment.append(instrumentName);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(unsigned short i = 0; i < sampleCount; ++ i) {
|
||||||
|
seek(192L + length + ((long)instrumentCount << 2) + ((long)i << 2));
|
||||||
|
READ_U32L_AS(sampleOffset);
|
||||||
|
|
||||||
|
seek(sampleOffset);
|
||||||
|
|
||||||
|
ByteVector sampleMagic = readBlock(4);
|
||||||
|
READ_ASSERT(sampleMagic == "IMPS");
|
||||||
|
|
||||||
|
READ_STRING_AS(dosFileName, 13);
|
||||||
|
READ_BYTE_AS(globalVolume);
|
||||||
|
READ_BYTE_AS(sampleFlags);
|
||||||
|
READ_BYTE_AS(sampleVolume);
|
||||||
|
READ_STRING_AS(sampleName, 26);
|
||||||
|
/*
|
||||||
|
READ_BYTE_AS(sampleCvt);
|
||||||
|
READ_BYTE_AS(samplePanning);
|
||||||
|
READ_U32L_AS(sampleLength);
|
||||||
|
READ_U32L_AS(loopStart);
|
||||||
|
READ_U32L_AS(loopStop);
|
||||||
|
READ_U32L_AS(c5speed);
|
||||||
|
READ_U32L_AS(sustainLoopStart);
|
||||||
|
READ_U32L_AS(sustainLoopEnd);
|
||||||
|
READ_U32L_AS(sampleDataOffset);
|
||||||
|
READ_BYTE_AS(vibratoSpeed);
|
||||||
|
READ_BYTE_AS(vibratoDepth);
|
||||||
|
READ_BYTE_AS(vibratoRate);
|
||||||
|
READ_BYTE_AS(vibratoType);
|
||||||
|
*/
|
||||||
|
|
||||||
|
comment.append(sampleName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(message.size() > 0)
|
||||||
|
comment.append(message);
|
||||||
|
d->tag.setComment(comment.toString("\n"));
|
||||||
|
d->tag.setTrackerName("Impulse Tracker");
|
||||||
|
}
|
||||||
109
3rdparty/taglib/it/itfile.h
vendored
Normal file
109
3rdparty/taglib/it/itfile.h
vendored
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
copyright : (C) 2011 by Mathias Panzenböck
|
||||||
|
email : grosser.meister.morti@gmx.net
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, *
|
||||||
|
* MA 02110-1301 USA *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef TAGLIB_ITFILE_H
|
||||||
|
#define TAGLIB_ITFILE_H
|
||||||
|
|
||||||
|
#include "tfile.h"
|
||||||
|
#include "audioproperties.h"
|
||||||
|
#include "taglib_export.h"
|
||||||
|
#include "modfilebase.h"
|
||||||
|
#include "modtag.h"
|
||||||
|
#include "itproperties.h"
|
||||||
|
|
||||||
|
namespace TagLib {
|
||||||
|
|
||||||
|
namespace IT {
|
||||||
|
|
||||||
|
class TAGLIB_EXPORT File : public Mod::FileBase {
|
||||||
|
public:
|
||||||
|
/*!
|
||||||
|
* Constructs a Impulse Tracker file from \a file.
|
||||||
|
*
|
||||||
|
* \note In the current implementation, both \a readProperties and
|
||||||
|
* \a propertiesStyle are ignored. The audio properties are always
|
||||||
|
* read.
|
||||||
|
*/
|
||||||
|
File(FileName file, bool readProperties = true,
|
||||||
|
AudioProperties::ReadStyle propertiesStyle =
|
||||||
|
AudioProperties::Average);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Constructs a Impulse Tracker file from \a stream.
|
||||||
|
*
|
||||||
|
* \note In the current implementation, both \a readProperties and
|
||||||
|
* \a propertiesStyle are ignored. The audio properties are always
|
||||||
|
* read.
|
||||||
|
*
|
||||||
|
* \note TagLib will *not* take ownership of the stream, the caller is
|
||||||
|
* responsible for deleting it after the File object.
|
||||||
|
*/
|
||||||
|
File(IOStream *stream, bool readProperties = true,
|
||||||
|
AudioProperties::ReadStyle propertiesStyle =
|
||||||
|
AudioProperties::Average);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Destroys this instance of the File.
|
||||||
|
*/
|
||||||
|
virtual ~File();
|
||||||
|
|
||||||
|
Mod::Tag *tag() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Forwards to Mod::Tag::properties().
|
||||||
|
* BIC: will be removed once File::toDict() is made virtual
|
||||||
|
*/
|
||||||
|
PropertyMap properties() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Forwards to Mod::Tag::setProperties().
|
||||||
|
* BIC: will be removed once File::setProperties() is made virtual
|
||||||
|
*/
|
||||||
|
PropertyMap setProperties(const PropertyMap &);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the IT::Properties for this file. If no audio properties
|
||||||
|
* were read then this will return a null pointer.
|
||||||
|
*/
|
||||||
|
IT::Properties *audioProperties() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Save the file.
|
||||||
|
* This is the same as calling save(AllTags);
|
||||||
|
*
|
||||||
|
* \note Saving Impulse Tracker tags is not supported.
|
||||||
|
*/
|
||||||
|
bool save();
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
File(const File &);
|
||||||
|
File &operator=(const File &);
|
||||||
|
|
||||||
|
void read(bool readProperties);
|
||||||
|
|
||||||
|
class FilePrivate;
|
||||||
|
FilePrivate *d;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
260
3rdparty/taglib/it/itproperties.cpp
vendored
Normal file
260
3rdparty/taglib/it/itproperties.cpp
vendored
Normal file
@@ -0,0 +1,260 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
copyright :(C) 2011 by Mathias Panzenböck
|
||||||
|
email : grosser.meister.morti@gmx.net
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
#include "itproperties.h"
|
||||||
|
|
||||||
|
using namespace TagLib;
|
||||||
|
using namespace IT;
|
||||||
|
|
||||||
|
class IT::Properties::PropertiesPrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PropertiesPrivate() :
|
||||||
|
channels(0),
|
||||||
|
lengthInPatterns(0),
|
||||||
|
instrumentCount(0),
|
||||||
|
sampleCount(0),
|
||||||
|
patternCount(0),
|
||||||
|
version(0),
|
||||||
|
compatibleVersion(0),
|
||||||
|
flags(0),
|
||||||
|
special(0),
|
||||||
|
globalVolume(0),
|
||||||
|
mixVolume(0),
|
||||||
|
tempo(0),
|
||||||
|
bpmSpeed(0),
|
||||||
|
panningSeparation(0),
|
||||||
|
pitchWheelDepth(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int channels;
|
||||||
|
unsigned short lengthInPatterns;
|
||||||
|
unsigned short instrumentCount;
|
||||||
|
unsigned short sampleCount;
|
||||||
|
unsigned short patternCount;
|
||||||
|
unsigned short version;
|
||||||
|
unsigned short compatibleVersion;
|
||||||
|
unsigned short flags;
|
||||||
|
unsigned short special;
|
||||||
|
unsigned char globalVolume;
|
||||||
|
unsigned char mixVolume;
|
||||||
|
unsigned char tempo;
|
||||||
|
unsigned char bpmSpeed;
|
||||||
|
unsigned char panningSeparation;
|
||||||
|
unsigned char pitchWheelDepth;
|
||||||
|
};
|
||||||
|
|
||||||
|
IT::Properties::Properties(AudioProperties::ReadStyle propertiesStyle) :
|
||||||
|
AudioProperties(propertiesStyle),
|
||||||
|
d(new PropertiesPrivate())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
IT::Properties::~Properties()
|
||||||
|
{
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IT::Properties::length() const
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IT::Properties::lengthInSeconds() const
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IT::Properties::lengthInMilliseconds() const
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IT::Properties::bitrate() const
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IT::Properties::sampleRate() const
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IT::Properties::channels() const
|
||||||
|
{
|
||||||
|
return d->channels;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned short IT::Properties::lengthInPatterns() const
|
||||||
|
{
|
||||||
|
return d->lengthInPatterns;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IT::Properties::stereo() const
|
||||||
|
{
|
||||||
|
return d->flags & Stereo;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned short IT::Properties::instrumentCount() const
|
||||||
|
{
|
||||||
|
return d->instrumentCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned short IT::Properties::sampleCount() const
|
||||||
|
{
|
||||||
|
return d->sampleCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned short IT::Properties::patternCount() const
|
||||||
|
{
|
||||||
|
return d->patternCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned short IT::Properties::version() const
|
||||||
|
{
|
||||||
|
return d->version;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned short IT::Properties::compatibleVersion() const
|
||||||
|
{
|
||||||
|
return d->compatibleVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned short IT::Properties::flags() const
|
||||||
|
{
|
||||||
|
return d->flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned short IT::Properties::special() const
|
||||||
|
{
|
||||||
|
return d->special;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char IT::Properties::globalVolume() const
|
||||||
|
{
|
||||||
|
return d->globalVolume;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char IT::Properties::mixVolume() const
|
||||||
|
{
|
||||||
|
return d->mixVolume;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char IT::Properties::tempo() const
|
||||||
|
{
|
||||||
|
return d->tempo;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char IT::Properties::bpmSpeed() const
|
||||||
|
{
|
||||||
|
return d->bpmSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char IT::Properties::panningSeparation() const
|
||||||
|
{
|
||||||
|
return d->panningSeparation;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char IT::Properties::pitchWheelDepth() const
|
||||||
|
{
|
||||||
|
return d->pitchWheelDepth;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IT::Properties::setChannels(int channels)
|
||||||
|
{
|
||||||
|
d->channels = channels;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IT::Properties::setLengthInPatterns(unsigned short lengthInPatterns)
|
||||||
|
{
|
||||||
|
d->lengthInPatterns = lengthInPatterns;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IT::Properties::setInstrumentCount(unsigned short instrumentCount)
|
||||||
|
{
|
||||||
|
d->instrumentCount = instrumentCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IT::Properties::setSampleCount(unsigned short sampleCount)
|
||||||
|
{
|
||||||
|
d->sampleCount = sampleCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IT::Properties::setPatternCount(unsigned short patternCount)
|
||||||
|
{
|
||||||
|
d->patternCount = patternCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IT::Properties::setFlags(unsigned short flags)
|
||||||
|
{
|
||||||
|
d->flags = flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IT::Properties::setSpecial(unsigned short special)
|
||||||
|
{
|
||||||
|
d->special = special;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IT::Properties::setCompatibleVersion(unsigned short compatibleVersion)
|
||||||
|
{
|
||||||
|
d->compatibleVersion = compatibleVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IT::Properties::setVersion(unsigned short version)
|
||||||
|
{
|
||||||
|
d->version = version;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IT::Properties::setGlobalVolume(unsigned char globalVolume)
|
||||||
|
{
|
||||||
|
d->globalVolume = globalVolume;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IT::Properties::setMixVolume(unsigned char mixVolume)
|
||||||
|
{
|
||||||
|
d->mixVolume = mixVolume;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IT::Properties::setTempo(unsigned char tempo)
|
||||||
|
{
|
||||||
|
d->tempo = tempo;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IT::Properties::setBpmSpeed(unsigned char bpmSpeed)
|
||||||
|
{
|
||||||
|
d->bpmSpeed = bpmSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IT::Properties::setPanningSeparation(unsigned char panningSeparation)
|
||||||
|
{
|
||||||
|
d->panningSeparation = panningSeparation;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IT::Properties::setPitchWheelDepth(unsigned char pitchWheelDepth)
|
||||||
|
{
|
||||||
|
d->pitchWheelDepth = pitchWheelDepth;
|
||||||
|
}
|
||||||
107
3rdparty/taglib/it/itproperties.h
vendored
Normal file
107
3rdparty/taglib/it/itproperties.h
vendored
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
copyright : (C) 2011 by Mathias Panzenböck
|
||||||
|
email : grosser.meister.morti@gmx.net
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef TAGLIB_ITPROPERTIES_H
|
||||||
|
#define TAGLIB_ITPROPERTIES_H
|
||||||
|
|
||||||
|
#include "taglib.h"
|
||||||
|
#include "audioproperties.h"
|
||||||
|
|
||||||
|
namespace TagLib {
|
||||||
|
namespace IT {
|
||||||
|
class TAGLIB_EXPORT Properties : public AudioProperties {
|
||||||
|
friend class File;
|
||||||
|
public:
|
||||||
|
/*! Flag bits. */
|
||||||
|
enum {
|
||||||
|
Stereo = 1,
|
||||||
|
Vol0MixOptimizations = 2,
|
||||||
|
UseInstruments = 4,
|
||||||
|
LinearSlides = 8,
|
||||||
|
OldEffects = 16,
|
||||||
|
LinkEffects = 32,
|
||||||
|
UseMidiPitchController = 64,
|
||||||
|
RequestEmbeddedMidiConf = 128
|
||||||
|
};
|
||||||
|
|
||||||
|
/*! Special bits. */
|
||||||
|
enum {
|
||||||
|
MessageAttached = 1,
|
||||||
|
MidiConfEmbedded = 8
|
||||||
|
};
|
||||||
|
|
||||||
|
Properties(AudioProperties::ReadStyle propertiesStyle);
|
||||||
|
virtual ~Properties();
|
||||||
|
|
||||||
|
int length() const;
|
||||||
|
int lengthInSeconds() const;
|
||||||
|
int lengthInMilliseconds() const;
|
||||||
|
int bitrate() const;
|
||||||
|
int sampleRate() const;
|
||||||
|
int channels() const;
|
||||||
|
|
||||||
|
unsigned short lengthInPatterns() const;
|
||||||
|
bool stereo() const;
|
||||||
|
unsigned short instrumentCount() const;
|
||||||
|
unsigned short sampleCount() const;
|
||||||
|
unsigned short patternCount() const;
|
||||||
|
unsigned short version() const;
|
||||||
|
unsigned short compatibleVersion() const;
|
||||||
|
unsigned short flags() const;
|
||||||
|
unsigned short special() const;
|
||||||
|
unsigned char globalVolume() const;
|
||||||
|
unsigned char mixVolume() const;
|
||||||
|
unsigned char tempo() const;
|
||||||
|
unsigned char bpmSpeed() const;
|
||||||
|
unsigned char panningSeparation() const;
|
||||||
|
unsigned char pitchWheelDepth() const;
|
||||||
|
|
||||||
|
void setChannels(int channels);
|
||||||
|
void setLengthInPatterns(unsigned short lengthInPatterns);
|
||||||
|
void setInstrumentCount(unsigned short instrumentCount);
|
||||||
|
void setSampleCount (unsigned short sampleCount);
|
||||||
|
void setPatternCount(unsigned short patternCount);
|
||||||
|
void setVersion (unsigned short version);
|
||||||
|
void setCompatibleVersion(unsigned short compatibleVersion);
|
||||||
|
void setFlags (unsigned short flags);
|
||||||
|
void setSpecial (unsigned short special);
|
||||||
|
void setGlobalVolume(unsigned char globalVolume);
|
||||||
|
void setMixVolume (unsigned char mixVolume);
|
||||||
|
void setTempo (unsigned char tempo);
|
||||||
|
void setBpmSpeed (unsigned char bpmSpeed);
|
||||||
|
void setPanningSeparation(unsigned char panningSeparation);
|
||||||
|
void setPitchWheelDepth (unsigned char pitchWheelDepth);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Properties(const Properties&);
|
||||||
|
Properties &operator=(const Properties&);
|
||||||
|
|
||||||
|
class PropertiesPrivate;
|
||||||
|
PropertiesPrivate *d;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
192
3rdparty/taglib/mod/modfile.cpp
vendored
Normal file
192
3rdparty/taglib/mod/modfile.cpp
vendored
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
copyright : (C) 2011 by Mathias Panzenböck
|
||||||
|
email : grosser.meister.morti@gmx.net
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
#include "modfile.h"
|
||||||
|
#include "tstringlist.h"
|
||||||
|
#include "tdebug.h"
|
||||||
|
#include "modfileprivate.h"
|
||||||
|
#include "tpropertymap.h"
|
||||||
|
|
||||||
|
using namespace TagLib;
|
||||||
|
using namespace Mod;
|
||||||
|
|
||||||
|
class Mod::File::FilePrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FilePrivate(AudioProperties::ReadStyle propertiesStyle)
|
||||||
|
: properties(propertiesStyle)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Mod::Tag tag;
|
||||||
|
Mod::Properties properties;
|
||||||
|
};
|
||||||
|
|
||||||
|
Mod::File::File(FileName file, bool readProperties,
|
||||||
|
AudioProperties::ReadStyle propertiesStyle) :
|
||||||
|
Mod::FileBase(file),
|
||||||
|
d(new FilePrivate(propertiesStyle))
|
||||||
|
{
|
||||||
|
if(isOpen())
|
||||||
|
read(readProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
Mod::File::File(IOStream *stream, bool readProperties,
|
||||||
|
AudioProperties::ReadStyle propertiesStyle) :
|
||||||
|
Mod::FileBase(stream),
|
||||||
|
d(new FilePrivate(propertiesStyle))
|
||||||
|
{
|
||||||
|
if(isOpen())
|
||||||
|
read(readProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
Mod::File::~File()
|
||||||
|
{
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mod::Tag *Mod::File::tag() const
|
||||||
|
{
|
||||||
|
return &d->tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mod::Properties *Mod::File::audioProperties() const
|
||||||
|
{
|
||||||
|
return &d->properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyMap Mod::File::properties() const
|
||||||
|
{
|
||||||
|
return d->tag.properties();
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyMap Mod::File::setProperties(const PropertyMap &properties)
|
||||||
|
{
|
||||||
|
return d->tag.setProperties(properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Mod::File::save()
|
||||||
|
{
|
||||||
|
if(readOnly()) {
|
||||||
|
debug("Mod::File::save() - Cannot save to a read only file.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
seek(0);
|
||||||
|
writeString(d->tag.title(), 20);
|
||||||
|
StringList lines = d->tag.comment().split("\n");
|
||||||
|
unsigned int n = std::min(lines.size(), d->properties.instrumentCount());
|
||||||
|
for(unsigned int i = 0; i < n; ++ i) {
|
||||||
|
writeString(lines[i], 22);
|
||||||
|
seek(8, Current);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(unsigned int i = n; i < d->properties.instrumentCount(); ++ i) {
|
||||||
|
writeString(String(), 22);
|
||||||
|
seek(8, Current);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mod::File::read(bool)
|
||||||
|
{
|
||||||
|
if(!isOpen())
|
||||||
|
return;
|
||||||
|
|
||||||
|
seek(1080);
|
||||||
|
ByteVector modId = readBlock(4);
|
||||||
|
READ_ASSERT(modId.size() == 4);
|
||||||
|
|
||||||
|
int channels = 4;
|
||||||
|
unsigned int instruments = 31;
|
||||||
|
if(modId == "M.K." || modId == "M!K!" || modId == "M&K!" || modId == "N.T.") {
|
||||||
|
d->tag.setTrackerName("ProTracker");
|
||||||
|
channels = 4;
|
||||||
|
}
|
||||||
|
else if(modId.startsWith("FLT") || modId.startsWith("TDZ")) {
|
||||||
|
d->tag.setTrackerName("StarTrekker");
|
||||||
|
char digit = modId[3];
|
||||||
|
READ_ASSERT(digit >= '0' && digit <= '9');
|
||||||
|
channels = digit - '0';
|
||||||
|
}
|
||||||
|
else if(modId.endsWith("CHN")) {
|
||||||
|
d->tag.setTrackerName("StarTrekker");
|
||||||
|
char digit = modId[0];
|
||||||
|
READ_ASSERT(digit >= '0' && digit <= '9');
|
||||||
|
channels = digit - '0';
|
||||||
|
}
|
||||||
|
else if(modId == "CD81" || modId == "OKTA") {
|
||||||
|
d->tag.setTrackerName("Atari Oktalyzer");
|
||||||
|
channels = 8;
|
||||||
|
}
|
||||||
|
else if(modId.endsWith("CH") || modId.endsWith("CN")) {
|
||||||
|
d->tag.setTrackerName("TakeTracker");
|
||||||
|
char digit = modId[0];
|
||||||
|
READ_ASSERT(digit >= '0' && digit <= '9');
|
||||||
|
channels = (digit - '0') * 10;
|
||||||
|
digit = modId[1];
|
||||||
|
READ_ASSERT(digit >= '0' && digit <= '9');
|
||||||
|
channels += digit - '0';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Not sure if this is correct. I'd need a file
|
||||||
|
// created with NoiseTracker to check this.
|
||||||
|
d->tag.setTrackerName("NoiseTracker"); // probably
|
||||||
|
channels = 4;
|
||||||
|
instruments = 15;
|
||||||
|
}
|
||||||
|
d->properties.setChannels(channels);
|
||||||
|
d->properties.setInstrumentCount(instruments);
|
||||||
|
|
||||||
|
seek(0);
|
||||||
|
READ_STRING(d->tag.setTitle, 20);
|
||||||
|
|
||||||
|
StringList comment;
|
||||||
|
for(unsigned int i = 0; i < instruments; ++ i) {
|
||||||
|
READ_STRING_AS(instrumentName, 22);
|
||||||
|
// value in words, * 2 (<< 1) for bytes:
|
||||||
|
READ_U16B_AS(sampleLength);
|
||||||
|
|
||||||
|
READ_BYTE_AS(fineTuneByte);
|
||||||
|
int fineTune = fineTuneByte & 0xF;
|
||||||
|
// > 7 means negative value
|
||||||
|
if(fineTune > 7) fineTune -= 16;
|
||||||
|
|
||||||
|
READ_BYTE_AS(volume);
|
||||||
|
if(volume > 64) volume = 64;
|
||||||
|
// volume in decibels: 20 * log10(volume / 64)
|
||||||
|
|
||||||
|
// value in words, * 2 (<< 1) for bytes:
|
||||||
|
READ_U16B_AS(repeatStart);
|
||||||
|
// value in words, * 2 (<< 1) for bytes:
|
||||||
|
READ_U16B_AS(repatLength);
|
||||||
|
|
||||||
|
comment.append(instrumentName);
|
||||||
|
}
|
||||||
|
|
||||||
|
READ_BYTE(d->properties.setLengthInPatterns);
|
||||||
|
|
||||||
|
d->tag.setComment(comment.toString("\n"));
|
||||||
|
}
|
||||||
114
3rdparty/taglib/mod/modfile.h
vendored
Normal file
114
3rdparty/taglib/mod/modfile.h
vendored
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
copyright : (C) 2011 by Mathias Panzenböck
|
||||||
|
email : grosser.meister.morti@gmx.net
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef TAGLIB_MODFILE_H
|
||||||
|
#define TAGLIB_MODFILE_H
|
||||||
|
|
||||||
|
#include "tfile.h"
|
||||||
|
#include "audioproperties.h"
|
||||||
|
#include "taglib_export.h"
|
||||||
|
#include "modfilebase.h"
|
||||||
|
#include "modtag.h"
|
||||||
|
#include "modproperties.h"
|
||||||
|
|
||||||
|
namespace TagLib {
|
||||||
|
|
||||||
|
namespace Mod {
|
||||||
|
|
||||||
|
class TAGLIB_EXPORT File : public TagLib::Mod::FileBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/*!
|
||||||
|
* Constructs a Protracker file from \a file.
|
||||||
|
*
|
||||||
|
* \note In the current implementation, both \a readProperties and
|
||||||
|
* \a propertiesStyle are ignored. The audio properties are always
|
||||||
|
* read.
|
||||||
|
*/
|
||||||
|
File(FileName file, bool readProperties = true,
|
||||||
|
AudioProperties::ReadStyle propertiesStyle =
|
||||||
|
AudioProperties::Average);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Constructs a Protracker file from \a stream.
|
||||||
|
*
|
||||||
|
* \note In the current implementation, both \a readProperties and
|
||||||
|
* \a propertiesStyle are ignored. The audio properties are always
|
||||||
|
* read.
|
||||||
|
*
|
||||||
|
* \note TagLib will *not* take ownership of the stream, the caller is
|
||||||
|
* responsible for deleting it after the File object.
|
||||||
|
*/
|
||||||
|
File(IOStream *stream, bool readProperties = true,
|
||||||
|
AudioProperties::ReadStyle propertiesStyle =
|
||||||
|
AudioProperties::Average);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Destroys this instance of the File.
|
||||||
|
*/
|
||||||
|
virtual ~File();
|
||||||
|
|
||||||
|
Mod::Tag *tag() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Implements the unified property interface -- export function.
|
||||||
|
* Forwards to Mod::Tag::properties().
|
||||||
|
*/
|
||||||
|
PropertyMap properties() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Implements the unified property interface -- import function.
|
||||||
|
* Forwards to Mod::Tag::setProperties().
|
||||||
|
*/
|
||||||
|
PropertyMap setProperties(const PropertyMap &);
|
||||||
|
/*!
|
||||||
|
* Returns the Mod::Properties for this file. If no audio properties
|
||||||
|
* were read then this will return a null pointer.
|
||||||
|
*/
|
||||||
|
Mod::Properties *audioProperties() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Save the file.
|
||||||
|
* This is the same as calling save(AllTags);
|
||||||
|
*
|
||||||
|
* \note Saving Protracker tags is not supported.
|
||||||
|
*/
|
||||||
|
bool save();
|
||||||
|
|
||||||
|
private:
|
||||||
|
File(const File &);
|
||||||
|
File &operator=(const File &);
|
||||||
|
|
||||||
|
void read(bool readProperties);
|
||||||
|
|
||||||
|
class FilePrivate;
|
||||||
|
FilePrivate *d;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
125
3rdparty/taglib/mod/modfilebase.cpp
vendored
Normal file
125
3rdparty/taglib/mod/modfilebase.cpp
vendored
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
copyright : (C) 2011 by Mathias Panzenböck
|
||||||
|
email : grosser.meister.morti@gmx.net
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
#include "tdebug.h"
|
||||||
|
#include "modfilebase.h"
|
||||||
|
|
||||||
|
using namespace TagLib;
|
||||||
|
using namespace Mod;
|
||||||
|
|
||||||
|
Mod::FileBase::FileBase(FileName file) : TagLib::File(file)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Mod::FileBase::FileBase(IOStream *stream) : TagLib::File(stream)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mod::FileBase::writeString(const String &s, unsigned long size, char padding)
|
||||||
|
{
|
||||||
|
ByteVector data(s.data(String::Latin1));
|
||||||
|
data.resize(size, padding);
|
||||||
|
writeBlock(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Mod::FileBase::readString(String &s, unsigned long size)
|
||||||
|
{
|
||||||
|
ByteVector data(readBlock(size));
|
||||||
|
if(data.size() < size) return false;
|
||||||
|
int index = data.find((char) 0);
|
||||||
|
if(index > -1)
|
||||||
|
{
|
||||||
|
data.resize(index);
|
||||||
|
}
|
||||||
|
data.replace('\xff', ' ');
|
||||||
|
|
||||||
|
s = data;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mod::FileBase::writeByte(unsigned char byte)
|
||||||
|
{
|
||||||
|
ByteVector data(1, byte);
|
||||||
|
writeBlock(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mod::FileBase::writeU16L(unsigned short number)
|
||||||
|
{
|
||||||
|
writeBlock(ByteVector::fromShort(number, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mod::FileBase::writeU32L(unsigned long number)
|
||||||
|
{
|
||||||
|
writeBlock(ByteVector::fromUInt(number, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mod::FileBase::writeU16B(unsigned short number)
|
||||||
|
{
|
||||||
|
writeBlock(ByteVector::fromShort(number, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mod::FileBase::writeU32B(unsigned long number)
|
||||||
|
{
|
||||||
|
writeBlock(ByteVector::fromUInt(number, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Mod::FileBase::readByte(unsigned char &byte)
|
||||||
|
{
|
||||||
|
ByteVector data(readBlock(1));
|
||||||
|
if(data.size() < 1) return false;
|
||||||
|
byte = data[0];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Mod::FileBase::readU16L(unsigned short &number)
|
||||||
|
{
|
||||||
|
ByteVector data(readBlock(2));
|
||||||
|
if(data.size() < 2) return false;
|
||||||
|
number = data.toUShort(false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Mod::FileBase::readU32L(unsigned long &number) {
|
||||||
|
ByteVector data(readBlock(4));
|
||||||
|
if(data.size() < 4) return false;
|
||||||
|
number = data.toUInt(false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Mod::FileBase::readU16B(unsigned short &number)
|
||||||
|
{
|
||||||
|
ByteVector data(readBlock(2));
|
||||||
|
if(data.size() < 2) return false;
|
||||||
|
number = data.toUShort(true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Mod::FileBase::readU32B(unsigned long &number) {
|
||||||
|
ByteVector data(readBlock(4));
|
||||||
|
if(data.size() < 4) return false;
|
||||||
|
number = data.toUInt(true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
66
3rdparty/taglib/mod/modfilebase.h
vendored
Normal file
66
3rdparty/taglib/mod/modfilebase.h
vendored
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
copyright : (C) 2011 by Mathias Panzenböck
|
||||||
|
email : grosser.meister.morti@gmx.net
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef TAGLIB_MODFILEBASE_H
|
||||||
|
#define TAGLIB_MODFILEBASE_H
|
||||||
|
|
||||||
|
#include "taglib.h"
|
||||||
|
#include "tfile.h"
|
||||||
|
#include "tstring.h"
|
||||||
|
#include "tlist.h"
|
||||||
|
#include "taglib_export.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
namespace TagLib {
|
||||||
|
|
||||||
|
namespace Mod {
|
||||||
|
|
||||||
|
class TAGLIB_EXPORT FileBase : public TagLib::File
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
FileBase(FileName file);
|
||||||
|
FileBase(IOStream *stream);
|
||||||
|
|
||||||
|
void writeString(const String &s, unsigned long size, char padding = 0);
|
||||||
|
void writeByte(unsigned char byte);
|
||||||
|
void writeU16L(unsigned short number);
|
||||||
|
void writeU32L(unsigned long number);
|
||||||
|
void writeU16B(unsigned short number);
|
||||||
|
void writeU32B(unsigned long number);
|
||||||
|
|
||||||
|
bool readString(String &s, unsigned long size);
|
||||||
|
bool readByte(unsigned char &byte);
|
||||||
|
bool readU16L(unsigned short &number);
|
||||||
|
bool readU32L(unsigned long &number);
|
||||||
|
bool readU16B(unsigned short &number);
|
||||||
|
bool readU32B(unsigned long &number);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
67
3rdparty/taglib/mod/modfileprivate.h
vendored
Normal file
67
3rdparty/taglib/mod/modfileprivate.h
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
copyright : (C) 2011 by Mathias Panzenböck
|
||||||
|
email : grosser.meister.morti@gmx.net
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, *
|
||||||
|
* MA 02110-1301 USA *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef TAGLIB_MODFILEPRIVATE_H
|
||||||
|
#define TAGLIB_MODFILEPRIVATE_H
|
||||||
|
|
||||||
|
// some helper-macros only used internally by (s3m|it|xm)file.cpp
|
||||||
|
#define READ_ASSERT(cond) \
|
||||||
|
if(!(cond)) \
|
||||||
|
{ \
|
||||||
|
setValid(false); \
|
||||||
|
return; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define READ(setter,type,read) \
|
||||||
|
{ \
|
||||||
|
type number; \
|
||||||
|
READ_ASSERT(read(number)); \
|
||||||
|
setter(number); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define READ_BYTE(setter) READ(setter,unsigned char,readByte)
|
||||||
|
#define READ_U16L(setter) READ(setter,unsigned short,readU16L)
|
||||||
|
#define READ_U32L(setter) READ(setter,unsigned long,readU32L)
|
||||||
|
#define READ_U16B(setter) READ(setter,unsigned short,readU16B)
|
||||||
|
#define READ_U32B(setter) READ(setter,unsigned long,readU32B)
|
||||||
|
|
||||||
|
#define READ_STRING(setter,size) \
|
||||||
|
{ \
|
||||||
|
String s; \
|
||||||
|
READ_ASSERT(readString(s, size)); \
|
||||||
|
setter(s); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define READ_AS(type,name,read) \
|
||||||
|
type name = 0; \
|
||||||
|
READ_ASSERT(read(name));
|
||||||
|
|
||||||
|
#define READ_BYTE_AS(name) READ_AS(unsigned char,name,readByte)
|
||||||
|
#define READ_U16L_AS(name) READ_AS(unsigned short,name,readU16L)
|
||||||
|
#define READ_U32L_AS(name) READ_AS(unsigned long,name,readU32L)
|
||||||
|
#define READ_U16B_AS(name) READ_AS(unsigned short,name,readU16B)
|
||||||
|
#define READ_U32B_AS(name) READ_AS(unsigned long,name,readU32B)
|
||||||
|
|
||||||
|
#define READ_STRING_AS(name,size) \
|
||||||
|
String name; \
|
||||||
|
READ_ASSERT(readString(name, size));
|
||||||
|
|
||||||
|
#endif
|
||||||
111
3rdparty/taglib/mod/modproperties.cpp
vendored
Normal file
111
3rdparty/taglib/mod/modproperties.cpp
vendored
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
copyright : (C) 2011 by Mathias Panzenböck
|
||||||
|
email : grosser.meister.morti@gmx.net
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
#include "modproperties.h"
|
||||||
|
|
||||||
|
using namespace TagLib;
|
||||||
|
using namespace Mod;
|
||||||
|
|
||||||
|
class Mod::Properties::PropertiesPrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PropertiesPrivate() :
|
||||||
|
channels(0),
|
||||||
|
instrumentCount(0),
|
||||||
|
lengthInPatterns(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int channels;
|
||||||
|
unsigned int instrumentCount;
|
||||||
|
unsigned char lengthInPatterns;
|
||||||
|
};
|
||||||
|
|
||||||
|
Mod::Properties::Properties(AudioProperties::ReadStyle propertiesStyle) :
|
||||||
|
AudioProperties(propertiesStyle),
|
||||||
|
d(new PropertiesPrivate())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Mod::Properties::~Properties()
|
||||||
|
{
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Mod::Properties::length() const
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Mod::Properties::lengthInSeconds() const
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Mod::Properties::lengthInMilliseconds() const
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Mod::Properties::bitrate() const
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Mod::Properties::sampleRate() const
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Mod::Properties::channels() const
|
||||||
|
{
|
||||||
|
return d->channels;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int Mod::Properties::instrumentCount() const
|
||||||
|
{
|
||||||
|
return d->instrumentCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char Mod::Properties::lengthInPatterns() const
|
||||||
|
{
|
||||||
|
return d->lengthInPatterns;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mod::Properties::setChannels(int channels)
|
||||||
|
{
|
||||||
|
d->channels = channels;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mod::Properties::setInstrumentCount(unsigned int instrumentCount)
|
||||||
|
{
|
||||||
|
d->instrumentCount = instrumentCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mod::Properties::setLengthInPatterns(unsigned char lengthInPatterns)
|
||||||
|
{
|
||||||
|
d->lengthInPatterns = lengthInPatterns;
|
||||||
|
}
|
||||||
71
3rdparty/taglib/mod/modproperties.h
vendored
Normal file
71
3rdparty/taglib/mod/modproperties.h
vendored
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
copyright : (C) 2011 by Mathias Panzenböck
|
||||||
|
email : grosser.meister.morti@gmx.net
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef TAGLIB_MODPROPERTIES_H
|
||||||
|
#define TAGLIB_MODPROPERTIES_H
|
||||||
|
|
||||||
|
#include "taglib.h"
|
||||||
|
#include "audioproperties.h"
|
||||||
|
|
||||||
|
namespace TagLib {
|
||||||
|
|
||||||
|
namespace Mod {
|
||||||
|
|
||||||
|
class TAGLIB_EXPORT Properties : public AudioProperties
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Properties(AudioProperties::ReadStyle propertiesStyle);
|
||||||
|
virtual ~Properties();
|
||||||
|
|
||||||
|
int length() const;
|
||||||
|
int lengthInSeconds() const;
|
||||||
|
int lengthInMilliseconds() const;
|
||||||
|
int bitrate() const;
|
||||||
|
int sampleRate() const;
|
||||||
|
int channels() const;
|
||||||
|
|
||||||
|
unsigned int instrumentCount() const;
|
||||||
|
unsigned char lengthInPatterns() const;
|
||||||
|
|
||||||
|
void setChannels(int channels);
|
||||||
|
|
||||||
|
void setInstrumentCount(unsigned int sampleCount);
|
||||||
|
void setLengthInPatterns(unsigned char lengthInPatterns);
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class File;
|
||||||
|
|
||||||
|
Properties(const Properties&);
|
||||||
|
Properties &operator=(const Properties&);
|
||||||
|
|
||||||
|
class PropertiesPrivate;
|
||||||
|
PropertiesPrivate *d;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
174
3rdparty/taglib/mod/modtag.cpp
vendored
Normal file
174
3rdparty/taglib/mod/modtag.cpp
vendored
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
copyright : (C) 2011 by Mathias Panzenböck
|
||||||
|
email : grosser.meister.morti@gmx.net
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
#include "modtag.h"
|
||||||
|
#include "tstringlist.h"
|
||||||
|
#include "tpropertymap.h"
|
||||||
|
|
||||||
|
using namespace TagLib;
|
||||||
|
using namespace Mod;
|
||||||
|
|
||||||
|
class Mod::Tag::TagPrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TagPrivate()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
String title;
|
||||||
|
String comment;
|
||||||
|
String trackerName;
|
||||||
|
};
|
||||||
|
|
||||||
|
Mod::Tag::Tag() :
|
||||||
|
TagLib::Tag(),
|
||||||
|
d(new TagPrivate())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Mod::Tag::~Tag()
|
||||||
|
{
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
String Mod::Tag::title() const
|
||||||
|
{
|
||||||
|
return d->title;
|
||||||
|
}
|
||||||
|
|
||||||
|
String Mod::Tag::artist() const
|
||||||
|
{
|
||||||
|
return String();
|
||||||
|
}
|
||||||
|
|
||||||
|
String Mod::Tag::album() const
|
||||||
|
{
|
||||||
|
return String();
|
||||||
|
}
|
||||||
|
|
||||||
|
String Mod::Tag::comment() const
|
||||||
|
{
|
||||||
|
return d->comment;
|
||||||
|
}
|
||||||
|
|
||||||
|
String Mod::Tag::genre() const
|
||||||
|
{
|
||||||
|
return String();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int Mod::Tag::year() const
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int Mod::Tag::track() const
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
String Mod::Tag::trackerName() const
|
||||||
|
{
|
||||||
|
return d->trackerName;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mod::Tag::setTitle(const String &title)
|
||||||
|
{
|
||||||
|
d->title = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mod::Tag::setArtist(const String &)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mod::Tag::setAlbum(const String &)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mod::Tag::setComment(const String &comment)
|
||||||
|
{
|
||||||
|
d->comment = comment;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mod::Tag::setGenre(const String &)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mod::Tag::setYear(unsigned int)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mod::Tag::setTrack(unsigned int)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mod::Tag::setTrackerName(const String &trackerName)
|
||||||
|
{
|
||||||
|
d->trackerName = trackerName;
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyMap Mod::Tag::properties() const
|
||||||
|
{
|
||||||
|
PropertyMap properties;
|
||||||
|
properties["TITLE"] = d->title;
|
||||||
|
properties["COMMENT"] = d->comment;
|
||||||
|
if(!(d->trackerName.isEmpty()))
|
||||||
|
properties["TRACKERNAME"] = d->trackerName;
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyMap Mod::Tag::setProperties(const PropertyMap &origProps)
|
||||||
|
{
|
||||||
|
PropertyMap properties(origProps);
|
||||||
|
properties.removeEmpty();
|
||||||
|
StringList oneValueSet;
|
||||||
|
if(properties.contains("TITLE")) {
|
||||||
|
d->title = properties["TITLE"].front();
|
||||||
|
oneValueSet.append("TITLE");
|
||||||
|
} else
|
||||||
|
d->title.clear();
|
||||||
|
|
||||||
|
if(properties.contains("COMMENT")) {
|
||||||
|
d->comment = properties["COMMENT"].front();
|
||||||
|
oneValueSet.append("COMMENT");
|
||||||
|
} else
|
||||||
|
d->comment.clear();
|
||||||
|
|
||||||
|
if(properties.contains("TRACKERNAME")) {
|
||||||
|
d->trackerName = properties["TRACKERNAME"].front();
|
||||||
|
oneValueSet.append("TRACKERNAME");
|
||||||
|
} else
|
||||||
|
d->trackerName.clear();
|
||||||
|
|
||||||
|
// for each tag that has been set above, remove the first entry in the corresponding
|
||||||
|
// value list. The others will be returned as unsupported by this format.
|
||||||
|
for(StringList::ConstIterator it = oneValueSet.begin(); it != oneValueSet.end(); ++it) {
|
||||||
|
if(properties[*it].size() == 1)
|
||||||
|
properties.erase(*it);
|
||||||
|
else
|
||||||
|
properties[*it].erase( properties[*it].begin() );
|
||||||
|
}
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
194
3rdparty/taglib/mod/modtag.h
vendored
Normal file
194
3rdparty/taglib/mod/modtag.h
vendored
Normal file
@@ -0,0 +1,194 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
copyright : (C) 2011 by Mathias Panzenböck
|
||||||
|
email : grosser.meister.morti@gmx.net
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef TAGLIB_MODTAG_H
|
||||||
|
#define TAGLIB_MODTAG_H
|
||||||
|
|
||||||
|
#include "tag.h"
|
||||||
|
|
||||||
|
namespace TagLib {
|
||||||
|
|
||||||
|
namespace Mod {
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Tags for module files (Mod, S3M, IT, XM).
|
||||||
|
*
|
||||||
|
* Note that only the \a title is supported as such by most
|
||||||
|
* module file formats. Except for XM files the \a trackerName
|
||||||
|
* is derived from the file format or the flavour of the file
|
||||||
|
* format. For XM files it is stored in the file.
|
||||||
|
*
|
||||||
|
* The \a comment tag is not strictly supported by module files,
|
||||||
|
* but it is common practice to abuse instrument/sample/pattern
|
||||||
|
* names as multiline comments. TagLib does so as well.
|
||||||
|
*/
|
||||||
|
class TAGLIB_EXPORT Tag : public TagLib::Tag
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Tag();
|
||||||
|
virtual ~Tag();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the track name; if no track name is present in the tag
|
||||||
|
* String::null will be returned.
|
||||||
|
*/
|
||||||
|
virtual String title() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Not supported by module files. Therefore always returns String::null.
|
||||||
|
*/
|
||||||
|
virtual String artist() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Not supported by module files. Therefore always returns String::null.
|
||||||
|
*/
|
||||||
|
virtual String album() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the track comment derived from the instrument/sample/pattern
|
||||||
|
* names; if no comment is present in the tag String::null will be
|
||||||
|
* returned.
|
||||||
|
*/
|
||||||
|
virtual String comment() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Not supported by module files. Therefore always returns String::null.
|
||||||
|
*/
|
||||||
|
virtual String genre() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Not supported by module files. Therefore always returns 0.
|
||||||
|
*/
|
||||||
|
virtual unsigned int year() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Not supported by module files. Therefore always returns 0.
|
||||||
|
*/
|
||||||
|
virtual unsigned int track() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the name of the tracker used to create/edit the module file.
|
||||||
|
* Only XM files store this tag to the file as such, for other formats
|
||||||
|
* (Mod, S3M, IT) this is derived from the file type or the flavour of
|
||||||
|
* the file type. Therefore only XM files might have an empty
|
||||||
|
* (String::null) tracker name.
|
||||||
|
*/
|
||||||
|
String trackerName() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets the title to \a title. If \a title is String::null then this
|
||||||
|
* value will be cleared.
|
||||||
|
*
|
||||||
|
* The length limits per file type are (1 character = 1 byte):
|
||||||
|
* Mod 20 characters, S3M 27 characters, IT 25 characters and XM 20
|
||||||
|
* characters.
|
||||||
|
*/
|
||||||
|
virtual void setTitle(const String &title);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Not supported by module files and therefore ignored.
|
||||||
|
*/
|
||||||
|
virtual void setArtist(const String &artist);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Not supported by module files and therefore ignored.
|
||||||
|
*/
|
||||||
|
virtual void setAlbum(const String &album);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets the comment to \a comment. If \a comment is String::null then
|
||||||
|
* this value will be cleared.
|
||||||
|
*
|
||||||
|
* Note that module file formats don't actually support a comment tag.
|
||||||
|
* Instead the names of instruments/patterns/samples are abused as
|
||||||
|
* a multiline comment. Because of this the number of lines in a
|
||||||
|
* module file is fixed to the number of instruments/patterns/samples.
|
||||||
|
*
|
||||||
|
* Also note that the instrument/pattern/sample name length is limited
|
||||||
|
* an thus the line length in comments are limited. Too big comments
|
||||||
|
* will be truncated.
|
||||||
|
*
|
||||||
|
* The line length limits per file type are (1 character = 1 byte):
|
||||||
|
* Mod 22 characters, S3M 27 characters, IT 25 characters and XM 22
|
||||||
|
* characters.
|
||||||
|
*/
|
||||||
|
virtual void setComment(const String &comment);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Not supported by module files and therefore ignored.
|
||||||
|
*/
|
||||||
|
virtual void setGenre(const String &genre);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Not supported by module files and therefore ignored.
|
||||||
|
*/
|
||||||
|
virtual void setYear(unsigned int year);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Not supported by module files and therefore ignored.
|
||||||
|
*/
|
||||||
|
virtual void setTrack(unsigned int track);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets the tracker name to \a trackerName. If \a trackerName is
|
||||||
|
* String::null then this value will be cleared.
|
||||||
|
*
|
||||||
|
* Note that only XM files support this tag. Setting the
|
||||||
|
* tracker name for other module file formats will be ignored.
|
||||||
|
*
|
||||||
|
* The length of this tag is limited to 20 characters (1 character
|
||||||
|
* = 1 byte).
|
||||||
|
*/
|
||||||
|
void setTrackerName(const String &trackerName);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Implements the unified property interface -- export function.
|
||||||
|
* Since the module tag is very limited, the exported map is as well.
|
||||||
|
*/
|
||||||
|
PropertyMap properties() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Implements the unified property interface -- import function.
|
||||||
|
* Because of the limitations of the module file tag, any tags besides
|
||||||
|
* COMMENT, TITLE and, if it is an XM file, TRACKERNAME, will be
|
||||||
|
* returned. Additionally, if the map contains tags with multiple values,
|
||||||
|
* all but the first will be contained in the returned map of unsupported
|
||||||
|
* properties.
|
||||||
|
*/
|
||||||
|
PropertyMap setProperties(const PropertyMap &);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Tag(const Tag &);
|
||||||
|
Tag &operator=(const Tag &);
|
||||||
|
|
||||||
|
class TagPrivate;
|
||||||
|
TagPrivate *d;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
197
3rdparty/taglib/mp4/mp4atom.cpp
vendored
Normal file
197
3rdparty/taglib/mp4/mp4atom.cpp
vendored
Normal file
@@ -0,0 +1,197 @@
|
|||||||
|
/**************************************************************************
|
||||||
|
copyright : (C) 2007 by Lukáš Lalinský
|
||||||
|
email : lalinsky@gmail.com
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include <climits>
|
||||||
|
|
||||||
|
#include <tdebug.h>
|
||||||
|
#include <tstring.h>
|
||||||
|
#include "mp4atom.h"
|
||||||
|
|
||||||
|
using namespace TagLib;
|
||||||
|
|
||||||
|
const char *MP4::Atom::containers[11] = {
|
||||||
|
"moov", "udta", "mdia", "meta", "ilst",
|
||||||
|
"stbl", "minf", "moof", "traf", "trak",
|
||||||
|
"stsd"
|
||||||
|
};
|
||||||
|
|
||||||
|
MP4::Atom::Atom(File *file)
|
||||||
|
{
|
||||||
|
children.setAutoDelete(true);
|
||||||
|
|
||||||
|
offset = file->tell();
|
||||||
|
ByteVector header = file->readBlock(8);
|
||||||
|
if(header.size() != 8) {
|
||||||
|
// The atom header must be 8 bytes long, otherwise there is either
|
||||||
|
// trailing garbage or the file is truncated
|
||||||
|
debug("MP4: Couldn't read 8 bytes of data for atom header");
|
||||||
|
length = 0;
|
||||||
|
file->seek(0, File::End);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
length = header.toUInt();
|
||||||
|
|
||||||
|
if(length == 0) {
|
||||||
|
// The last atom which extends to the end of the file.
|
||||||
|
length = file->length() - offset;
|
||||||
|
}
|
||||||
|
else if(length == 1) {
|
||||||
|
// The atom has a 64-bit length.
|
||||||
|
const long long longLength = file->readBlock(8).toLongLong();
|
||||||
|
if(longLength <= LONG_MAX) {
|
||||||
|
// The actual length fits in long. That's always the case if long is 64-bit.
|
||||||
|
length = static_cast<long>(longLength);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
debug("MP4: 64-bit atoms are not supported");
|
||||||
|
length = 0;
|
||||||
|
file->seek(0, File::End);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(length < 8) {
|
||||||
|
debug("MP4: Invalid atom size");
|
||||||
|
length = 0;
|
||||||
|
file->seek(0, File::End);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
name = header.mid(4, 4);
|
||||||
|
|
||||||
|
for(int i = 0; i < numContainers; i++) {
|
||||||
|
if(name == containers[i]) {
|
||||||
|
if(name == "meta") {
|
||||||
|
file->seek(4, File::Current);
|
||||||
|
}
|
||||||
|
else if(name == "stsd") {
|
||||||
|
file->seek(8, File::Current);
|
||||||
|
}
|
||||||
|
while(file->tell() < offset + length) {
|
||||||
|
MP4::Atom *child = new MP4::Atom(file);
|
||||||
|
children.append(child);
|
||||||
|
if(child->length == 0)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
file->seek(offset + length);
|
||||||
|
}
|
||||||
|
|
||||||
|
MP4::Atom::~Atom()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
MP4::Atom *
|
||||||
|
MP4::Atom::find(const char *name1, const char *name2, const char *name3, const char *name4)
|
||||||
|
{
|
||||||
|
if(name1 == 0) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
for(AtomList::ConstIterator it = children.begin(); it != children.end(); ++it) {
|
||||||
|
if((*it)->name == name1) {
|
||||||
|
return (*it)->find(name2, name3, name4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
MP4::AtomList
|
||||||
|
MP4::Atom::findall(const char *name, bool recursive)
|
||||||
|
{
|
||||||
|
MP4::AtomList result;
|
||||||
|
for(AtomList::ConstIterator it = children.begin(); it != children.end(); ++it) {
|
||||||
|
if((*it)->name == name) {
|
||||||
|
result.append(*it);
|
||||||
|
}
|
||||||
|
if(recursive) {
|
||||||
|
result.append((*it)->findall(name, recursive));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
MP4::Atom::path(MP4::AtomList &path, const char *name1, const char *name2, const char *name3)
|
||||||
|
{
|
||||||
|
path.append(this);
|
||||||
|
if(name1 == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
for(AtomList::ConstIterator it = children.begin(); it != children.end(); ++it) {
|
||||||
|
if((*it)->name == name1) {
|
||||||
|
return (*it)->path(path, name2, name3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
MP4::Atoms::Atoms(File *file)
|
||||||
|
{
|
||||||
|
atoms.setAutoDelete(true);
|
||||||
|
|
||||||
|
file->seek(0, File::End);
|
||||||
|
long end = file->tell();
|
||||||
|
file->seek(0);
|
||||||
|
while(file->tell() + 8 <= end) {
|
||||||
|
MP4::Atom *atom = new MP4::Atom(file);
|
||||||
|
atoms.append(atom);
|
||||||
|
if (atom->length == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MP4::Atoms::~Atoms()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
MP4::Atom *
|
||||||
|
MP4::Atoms::find(const char *name1, const char *name2, const char *name3, const char *name4)
|
||||||
|
{
|
||||||
|
for(AtomList::ConstIterator it = atoms.begin(); it != atoms.end(); ++it) {
|
||||||
|
if((*it)->name == name1) {
|
||||||
|
return (*it)->find(name2, name3, name4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
MP4::AtomList
|
||||||
|
MP4::Atoms::path(const char *name1, const char *name2, const char *name3, const char *name4)
|
||||||
|
{
|
||||||
|
MP4::AtomList path;
|
||||||
|
for(AtomList::ConstIterator it = atoms.begin(); it != atoms.end(); ++it) {
|
||||||
|
if((*it)->name == name1) {
|
||||||
|
if(!(*it)->path(path, name2, name3, name4)) {
|
||||||
|
path.clear();
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
111
3rdparty/taglib/mp4/mp4atom.h
vendored
Normal file
111
3rdparty/taglib/mp4/mp4atom.h
vendored
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
/**************************************************************************
|
||||||
|
copyright : (C) 2007,2011 by Lukáš Lalinský
|
||||||
|
email : lalinsky@gmail.com
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
// This file is not part of the public API!
|
||||||
|
|
||||||
|
#ifndef DO_NOT_DOCUMENT
|
||||||
|
|
||||||
|
#ifndef TAGLIB_MP4ATOM_H
|
||||||
|
#define TAGLIB_MP4ATOM_H
|
||||||
|
|
||||||
|
#include "tfile.h"
|
||||||
|
#include "tlist.h"
|
||||||
|
|
||||||
|
namespace TagLib {
|
||||||
|
|
||||||
|
namespace MP4 {
|
||||||
|
|
||||||
|
class Atom;
|
||||||
|
typedef TagLib::List<Atom *> AtomList;
|
||||||
|
|
||||||
|
enum AtomDataType
|
||||||
|
{
|
||||||
|
TypeImplicit = 0, // for use with tags for which no type needs to be indicated because only one type is allowed
|
||||||
|
TypeUTF8 = 1, // without any count or null terminator
|
||||||
|
TypeUTF16 = 2, // also known as UTF-16BE
|
||||||
|
TypeSJIS = 3, // deprecated unless it is needed for special Japanese characters
|
||||||
|
TypeHTML = 6, // the HTML file header specifies which HTML version
|
||||||
|
TypeXML = 7, // the XML header must identify the DTD or schemas
|
||||||
|
TypeUUID = 8, // also known as GUID; stored as 16 bytes in binary (valid as an ID)
|
||||||
|
TypeISRC = 9, // stored as UTF-8 text (valid as an ID)
|
||||||
|
TypeMI3P = 10, // stored as UTF-8 text (valid as an ID)
|
||||||
|
TypeGIF = 12, // (deprecated) a GIF image
|
||||||
|
TypeJPEG = 13, // a JPEG image
|
||||||
|
TypePNG = 14, // a PNG image
|
||||||
|
TypeURL = 15, // absolute, in UTF-8 characters
|
||||||
|
TypeDuration = 16, // in milliseconds, 32-bit integer
|
||||||
|
TypeDateTime = 17, // in UTC, counting seconds since midnight, January 1, 1904; 32 or 64-bits
|
||||||
|
TypeGenred = 18, // a list of enumerated values
|
||||||
|
TypeInteger = 21, // a signed big-endian integer with length one of { 1,2,3,4,8 } bytes
|
||||||
|
TypeRIAAPA = 24, // RIAA parental advisory; { -1=no, 1=yes, 0=unspecified }, 8-bit integer
|
||||||
|
TypeUPC = 25, // Universal Product Code, in text UTF-8 format (valid as an ID)
|
||||||
|
TypeBMP = 27, // Windows bitmap image
|
||||||
|
TypeUndefined = 255 // undefined
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AtomData {
|
||||||
|
AtomData(AtomDataType type, ByteVector data) : type(type), locale(0), data(data) {}
|
||||||
|
AtomDataType type;
|
||||||
|
int locale;
|
||||||
|
ByteVector data;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef TagLib::List<AtomData> AtomDataList;
|
||||||
|
|
||||||
|
class Atom
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Atom(File *file);
|
||||||
|
~Atom();
|
||||||
|
Atom *find(const char *name1, const char *name2 = 0, const char *name3 = 0, const char *name4 = 0);
|
||||||
|
bool path(AtomList &path, const char *name1, const char *name2 = 0, const char *name3 = 0);
|
||||||
|
AtomList findall(const char *name, bool recursive = false);
|
||||||
|
long offset;
|
||||||
|
long length;
|
||||||
|
TagLib::ByteVector name;
|
||||||
|
AtomList children;
|
||||||
|
private:
|
||||||
|
static const int numContainers = 11;
|
||||||
|
static const char *containers[11];
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Root-level atoms
|
||||||
|
class Atoms
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Atoms(File *file);
|
||||||
|
~Atoms();
|
||||||
|
Atom *find(const char *name1, const char *name2 = 0, const char *name3 = 0, const char *name4 = 0);
|
||||||
|
AtomList path(const char *name1, const char *name2 = 0, const char *name3 = 0, const char *name4 = 0);
|
||||||
|
AtomList atoms;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
93
3rdparty/taglib/mp4/mp4coverart.cpp
vendored
Normal file
93
3rdparty/taglib/mp4/mp4coverart.cpp
vendored
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
/**************************************************************************
|
||||||
|
copyright : (C) 2009 by Lukáš Lalinský
|
||||||
|
email : lalinsky@gmail.com
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include <taglib.h>
|
||||||
|
#include <tdebug.h>
|
||||||
|
#include "trefcounter.h"
|
||||||
|
#include "mp4coverart.h"
|
||||||
|
|
||||||
|
using namespace TagLib;
|
||||||
|
|
||||||
|
class MP4::CoverArt::CoverArtPrivate : public RefCounter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CoverArtPrivate() :
|
||||||
|
RefCounter(),
|
||||||
|
format(MP4::CoverArt::JPEG) {}
|
||||||
|
|
||||||
|
Format format;
|
||||||
|
ByteVector data;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// public members
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
MP4::CoverArt::CoverArt(Format format, const ByteVector &data) :
|
||||||
|
d(new CoverArtPrivate())
|
||||||
|
{
|
||||||
|
d->format = format;
|
||||||
|
d->data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
MP4::CoverArt::CoverArt(const CoverArt &item) :
|
||||||
|
d(item.d)
|
||||||
|
{
|
||||||
|
d->ref();
|
||||||
|
}
|
||||||
|
|
||||||
|
MP4::CoverArt &
|
||||||
|
MP4::CoverArt::operator=(const CoverArt &item)
|
||||||
|
{
|
||||||
|
CoverArt(item).swap(*this);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MP4::CoverArt::swap(CoverArt &item)
|
||||||
|
{
|
||||||
|
using std::swap;
|
||||||
|
|
||||||
|
swap(d, item.d);
|
||||||
|
}
|
||||||
|
|
||||||
|
MP4::CoverArt::~CoverArt()
|
||||||
|
{
|
||||||
|
if(d->deref()) {
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MP4::CoverArt::Format
|
||||||
|
MP4::CoverArt::format() const
|
||||||
|
{
|
||||||
|
return d->format;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector
|
||||||
|
MP4::CoverArt::data() const
|
||||||
|
{
|
||||||
|
return d->data;
|
||||||
|
}
|
||||||
84
3rdparty/taglib/mp4/mp4coverart.h
vendored
Normal file
84
3rdparty/taglib/mp4/mp4coverart.h
vendored
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
/**************************************************************************
|
||||||
|
copyright : (C) 2009 by Lukáš Lalinský
|
||||||
|
email : lalinsky@gmail.com
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef TAGLIB_MP4COVERART_H
|
||||||
|
#define TAGLIB_MP4COVERART_H
|
||||||
|
|
||||||
|
#include "tlist.h"
|
||||||
|
#include "tbytevector.h"
|
||||||
|
#include "taglib_export.h"
|
||||||
|
#include "mp4atom.h"
|
||||||
|
|
||||||
|
namespace TagLib {
|
||||||
|
|
||||||
|
namespace MP4 {
|
||||||
|
|
||||||
|
class TAGLIB_EXPORT CoverArt
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/*!
|
||||||
|
* This describes the image type.
|
||||||
|
*/
|
||||||
|
enum Format {
|
||||||
|
JPEG = TypeJPEG,
|
||||||
|
PNG = TypePNG,
|
||||||
|
BMP = TypeBMP,
|
||||||
|
GIF = TypeGIF,
|
||||||
|
Unknown = TypeImplicit,
|
||||||
|
};
|
||||||
|
|
||||||
|
CoverArt(Format format, const ByteVector &data);
|
||||||
|
~CoverArt();
|
||||||
|
|
||||||
|
CoverArt(const CoverArt &item);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Copies the contents of \a item into this CoverArt.
|
||||||
|
*/
|
||||||
|
CoverArt &operator=(const CoverArt &item);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Exchanges the content of the CoverArt by the content of \a item.
|
||||||
|
*/
|
||||||
|
void swap(CoverArt &item);
|
||||||
|
|
||||||
|
//! Format of the image
|
||||||
|
Format format() const;
|
||||||
|
|
||||||
|
//! The image data
|
||||||
|
ByteVector data() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
class CoverArtPrivate;
|
||||||
|
CoverArtPrivate *d;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef List<CoverArt> CoverArtList;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
182
3rdparty/taglib/mp4/mp4file.cpp
vendored
Normal file
182
3rdparty/taglib/mp4/mp4file.cpp
vendored
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
/**************************************************************************
|
||||||
|
copyright : (C) 2007 by Lukáš Lalinský
|
||||||
|
email : lalinsky@gmail.com
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include <tdebug.h>
|
||||||
|
#include <tstring.h>
|
||||||
|
#include <tpropertymap.h>
|
||||||
|
#include <tagutils.h>
|
||||||
|
|
||||||
|
#include "mp4atom.h"
|
||||||
|
#include "mp4tag.h"
|
||||||
|
#include "mp4file.h"
|
||||||
|
|
||||||
|
using namespace TagLib;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
bool checkValid(const MP4::AtomList &list)
|
||||||
|
{
|
||||||
|
for(MP4::AtomList::ConstIterator it = list.begin(); it != list.end(); ++it) {
|
||||||
|
|
||||||
|
if((*it)->length == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(!checkValid((*it)->children))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MP4::File::FilePrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FilePrivate() :
|
||||||
|
tag(0),
|
||||||
|
atoms(0),
|
||||||
|
properties(0) {}
|
||||||
|
|
||||||
|
~FilePrivate()
|
||||||
|
{
|
||||||
|
delete atoms;
|
||||||
|
delete tag;
|
||||||
|
delete properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
MP4::Tag *tag;
|
||||||
|
MP4::Atoms *atoms;
|
||||||
|
MP4::Properties *properties;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// static members
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
bool MP4::File::isSupported(IOStream *stream)
|
||||||
|
{
|
||||||
|
// An MP4 file has to have an "ftyp" box first.
|
||||||
|
|
||||||
|
const ByteVector id = Utils::readHeader(stream, 8, false);
|
||||||
|
return id.containsAt("ftyp", 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// public members
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
MP4::File::File(FileName file, bool readProperties, AudioProperties::ReadStyle) :
|
||||||
|
TagLib::File(file),
|
||||||
|
d(new FilePrivate())
|
||||||
|
{
|
||||||
|
if(isOpen())
|
||||||
|
read(readProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
MP4::File::File(IOStream *stream, bool readProperties, AudioProperties::ReadStyle) :
|
||||||
|
TagLib::File(stream),
|
||||||
|
d(new FilePrivate())
|
||||||
|
{
|
||||||
|
if(isOpen())
|
||||||
|
read(readProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
MP4::File::~File()
|
||||||
|
{
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
MP4::Tag *
|
||||||
|
MP4::File::tag() const
|
||||||
|
{
|
||||||
|
return d->tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyMap MP4::File::properties() const
|
||||||
|
{
|
||||||
|
return d->tag->properties();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MP4::File::removeUnsupportedProperties(const StringList &properties)
|
||||||
|
{
|
||||||
|
d->tag->removeUnsupportedProperties(properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyMap MP4::File::setProperties(const PropertyMap &properties)
|
||||||
|
{
|
||||||
|
return d->tag->setProperties(properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
MP4::Properties *
|
||||||
|
MP4::File::audioProperties() const
|
||||||
|
{
|
||||||
|
return d->properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MP4::File::read(bool readProperties)
|
||||||
|
{
|
||||||
|
if(!isValid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
d->atoms = new Atoms(this);
|
||||||
|
if(!checkValid(d->atoms->atoms)) {
|
||||||
|
setValid(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// must have a moov atom, otherwise consider it invalid
|
||||||
|
if(!d->atoms->find("moov")) {
|
||||||
|
setValid(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
d->tag = new Tag(this, d->atoms);
|
||||||
|
if(readProperties) {
|
||||||
|
d->properties = new Properties(this, d->atoms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
MP4::File::save()
|
||||||
|
{
|
||||||
|
if(readOnly()) {
|
||||||
|
debug("MP4::File::save() -- File is read only.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!isValid()) {
|
||||||
|
debug("MP4::File::save() -- Trying to save invalid file.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return d->tag->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
MP4::File::hasMP4Tag() const
|
||||||
|
{
|
||||||
|
return (d->atoms->find("moov", "udta", "meta", "ilst") != 0);
|
||||||
|
}
|
||||||
143
3rdparty/taglib/mp4/mp4file.h
vendored
Normal file
143
3rdparty/taglib/mp4/mp4file.h
vendored
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
/**************************************************************************
|
||||||
|
copyright : (C) 2007 by Lukáš Lalinský
|
||||||
|
email : lalinsky@gmail.com
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef TAGLIB_MP4FILE_H
|
||||||
|
#define TAGLIB_MP4FILE_H
|
||||||
|
|
||||||
|
#include "tag.h"
|
||||||
|
#include "tfile.h"
|
||||||
|
#include "taglib_export.h"
|
||||||
|
#include "mp4properties.h"
|
||||||
|
#include "mp4tag.h"
|
||||||
|
|
||||||
|
namespace TagLib {
|
||||||
|
|
||||||
|
//! An implementation of MP4 (AAC, ALAC, ...) metadata
|
||||||
|
namespace MP4 {
|
||||||
|
|
||||||
|
class Atoms;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* This implements and provides an interface for MP4 files to the
|
||||||
|
* TagLib::Tag and TagLib::AudioProperties interfaces by way of implementing
|
||||||
|
* the abstract TagLib::File API as well as providing some additional
|
||||||
|
* information specific to MP4 files.
|
||||||
|
*/
|
||||||
|
class TAGLIB_EXPORT File : public TagLib::File
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/*!
|
||||||
|
* Constructs an MP4 file from \a file. If \a readProperties is true the
|
||||||
|
* file's audio properties will also be read.
|
||||||
|
*
|
||||||
|
* \note In the current implementation, \a propertiesStyle is ignored.
|
||||||
|
*/
|
||||||
|
File(FileName file, bool readProperties = true,
|
||||||
|
Properties::ReadStyle audioPropertiesStyle = Properties::Average);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Constructs an MP4 file from \a stream. If \a readProperties is true the
|
||||||
|
* file's audio properties will also be read.
|
||||||
|
*
|
||||||
|
* \note TagLib will *not* take ownership of the stream, the caller is
|
||||||
|
* responsible for deleting it after the File object.
|
||||||
|
*
|
||||||
|
* \note In the current implementation, \a propertiesStyle is ignored.
|
||||||
|
*/
|
||||||
|
File(IOStream *stream, bool readProperties = true,
|
||||||
|
Properties::ReadStyle audioPropertiesStyle = Properties::Average);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Destroys this instance of the File.
|
||||||
|
*/
|
||||||
|
virtual ~File();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns a pointer to the MP4 tag of the file.
|
||||||
|
*
|
||||||
|
* MP4::Tag implements the tag interface, so this serves as the
|
||||||
|
* reimplementation of TagLib::File::tag().
|
||||||
|
*
|
||||||
|
* \note The Tag <b>is still</b> owned by the MP4::File and should not be
|
||||||
|
* deleted by the user. It will be deleted when the file (object) is
|
||||||
|
* destroyed.
|
||||||
|
*/
|
||||||
|
Tag *tag() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Implements the unified property interface -- export function.
|
||||||
|
*/
|
||||||
|
PropertyMap properties() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Removes unsupported properties. Forwards to the actual Tag's
|
||||||
|
* removeUnsupportedProperties() function.
|
||||||
|
*/
|
||||||
|
void removeUnsupportedProperties(const StringList &properties);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Implements the unified property interface -- import function.
|
||||||
|
*/
|
||||||
|
PropertyMap setProperties(const PropertyMap &);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the MP4 audio properties for this file.
|
||||||
|
*/
|
||||||
|
Properties *audioProperties() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Save the file.
|
||||||
|
*
|
||||||
|
* This returns true if the save was successful.
|
||||||
|
*/
|
||||||
|
bool save();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns whether or not the file on disk actually has an MP4 tag, or the
|
||||||
|
* file has a Metadata Item List (ilst) atom.
|
||||||
|
*/
|
||||||
|
bool hasMP4Tag() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns whether or not the given \a stream can be opened as an ASF
|
||||||
|
* file.
|
||||||
|
*
|
||||||
|
* \note This method is designed to do a quick check. The result may
|
||||||
|
* not necessarily be correct.
|
||||||
|
*/
|
||||||
|
static bool isSupported(IOStream *stream);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void read(bool readProperties);
|
||||||
|
|
||||||
|
class FilePrivate;
|
||||||
|
FilePrivate *d;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
212
3rdparty/taglib/mp4/mp4item.cpp
vendored
Normal file
212
3rdparty/taglib/mp4/mp4item.cpp
vendored
Normal file
@@ -0,0 +1,212 @@
|
|||||||
|
/**************************************************************************
|
||||||
|
copyright : (C) 2007 by Lukáš Lalinský
|
||||||
|
email : lalinsky@gmail.com
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include <taglib.h>
|
||||||
|
#include <tdebug.h>
|
||||||
|
#include "trefcounter.h"
|
||||||
|
#include "mp4item.h"
|
||||||
|
|
||||||
|
using namespace TagLib;
|
||||||
|
|
||||||
|
class MP4::Item::ItemPrivate : public RefCounter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ItemPrivate() :
|
||||||
|
RefCounter(),
|
||||||
|
valid(true),
|
||||||
|
atomDataType(TypeUndefined) {}
|
||||||
|
|
||||||
|
bool valid;
|
||||||
|
AtomDataType atomDataType;
|
||||||
|
union {
|
||||||
|
bool m_bool;
|
||||||
|
int m_int;
|
||||||
|
IntPair m_intPair;
|
||||||
|
unsigned char m_byte;
|
||||||
|
unsigned int m_uint;
|
||||||
|
long long m_longlong;
|
||||||
|
};
|
||||||
|
StringList m_stringList;
|
||||||
|
ByteVectorList m_byteVectorList;
|
||||||
|
MP4::CoverArtList m_coverArtList;
|
||||||
|
};
|
||||||
|
|
||||||
|
MP4::Item::Item() :
|
||||||
|
d(new ItemPrivate())
|
||||||
|
{
|
||||||
|
d->valid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
MP4::Item::Item(const Item &item) :
|
||||||
|
d(item.d)
|
||||||
|
{
|
||||||
|
d->ref();
|
||||||
|
}
|
||||||
|
|
||||||
|
MP4::Item &
|
||||||
|
MP4::Item::operator=(const Item &item)
|
||||||
|
{
|
||||||
|
Item(item).swap(*this);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MP4::Item::swap(Item &item)
|
||||||
|
{
|
||||||
|
using std::swap;
|
||||||
|
|
||||||
|
swap(d, item.d);
|
||||||
|
}
|
||||||
|
|
||||||
|
MP4::Item::~Item()
|
||||||
|
{
|
||||||
|
if(d->deref())
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
MP4::Item::Item(bool value) :
|
||||||
|
d(new ItemPrivate())
|
||||||
|
{
|
||||||
|
d->m_bool = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
MP4::Item::Item(int value) :
|
||||||
|
d(new ItemPrivate())
|
||||||
|
{
|
||||||
|
d->m_int = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
MP4::Item::Item(unsigned char value) :
|
||||||
|
d(new ItemPrivate())
|
||||||
|
{
|
||||||
|
d->m_byte = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
MP4::Item::Item(unsigned int value) :
|
||||||
|
d(new ItemPrivate())
|
||||||
|
{
|
||||||
|
d->m_uint = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
MP4::Item::Item(long long value) :
|
||||||
|
d(new ItemPrivate())
|
||||||
|
{
|
||||||
|
d->m_longlong = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
MP4::Item::Item(int value1, int value2) :
|
||||||
|
d(new ItemPrivate())
|
||||||
|
{
|
||||||
|
d->m_intPair.first = value1;
|
||||||
|
d->m_intPair.second = value2;
|
||||||
|
}
|
||||||
|
|
||||||
|
MP4::Item::Item(const ByteVectorList &value) :
|
||||||
|
d(new ItemPrivate())
|
||||||
|
{
|
||||||
|
d->m_byteVectorList = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
MP4::Item::Item(const StringList &value) :
|
||||||
|
d(new ItemPrivate())
|
||||||
|
{
|
||||||
|
d->m_stringList = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
MP4::Item::Item(const MP4::CoverArtList &value) :
|
||||||
|
d(new ItemPrivate())
|
||||||
|
{
|
||||||
|
d->m_coverArtList = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MP4::Item::setAtomDataType(MP4::AtomDataType type)
|
||||||
|
{
|
||||||
|
d->atomDataType = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
MP4::AtomDataType MP4::Item::atomDataType() const
|
||||||
|
{
|
||||||
|
return d->atomDataType;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
MP4::Item::toBool() const
|
||||||
|
{
|
||||||
|
return d->m_bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
MP4::Item::toInt() const
|
||||||
|
{
|
||||||
|
return d->m_int;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char
|
||||||
|
MP4::Item::toByte() const
|
||||||
|
{
|
||||||
|
return d->m_byte;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int
|
||||||
|
MP4::Item::toUInt() const
|
||||||
|
{
|
||||||
|
return d->m_uint;
|
||||||
|
}
|
||||||
|
|
||||||
|
long long
|
||||||
|
MP4::Item::toLongLong() const
|
||||||
|
{
|
||||||
|
return d->m_longlong;
|
||||||
|
}
|
||||||
|
|
||||||
|
MP4::Item::IntPair
|
||||||
|
MP4::Item::toIntPair() const
|
||||||
|
{
|
||||||
|
return d->m_intPair;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringList
|
||||||
|
MP4::Item::toStringList() const
|
||||||
|
{
|
||||||
|
return d->m_stringList;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVectorList
|
||||||
|
MP4::Item::toByteVectorList() const
|
||||||
|
{
|
||||||
|
return d->m_byteVectorList;
|
||||||
|
}
|
||||||
|
|
||||||
|
MP4::CoverArtList
|
||||||
|
MP4::Item::toCoverArtList() const
|
||||||
|
{
|
||||||
|
return d->m_coverArtList;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
MP4::Item::isValid() const
|
||||||
|
{
|
||||||
|
return d->valid;
|
||||||
|
}
|
||||||
93
3rdparty/taglib/mp4/mp4item.h
vendored
Normal file
93
3rdparty/taglib/mp4/mp4item.h
vendored
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
/**************************************************************************
|
||||||
|
copyright : (C) 2007 by Lukáš Lalinský
|
||||||
|
email : lalinsky@gmail.com
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef TAGLIB_MP4ITEM_H
|
||||||
|
#define TAGLIB_MP4ITEM_H
|
||||||
|
|
||||||
|
#include "tstringlist.h"
|
||||||
|
#include "mp4coverart.h"
|
||||||
|
#include "taglib_export.h"
|
||||||
|
|
||||||
|
namespace TagLib {
|
||||||
|
|
||||||
|
namespace MP4 {
|
||||||
|
|
||||||
|
class TAGLIB_EXPORT Item
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct IntPair {
|
||||||
|
int first, second;
|
||||||
|
};
|
||||||
|
|
||||||
|
Item();
|
||||||
|
Item(const Item &item);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Copies the contents of \a item into this Item.
|
||||||
|
*/
|
||||||
|
Item &operator=(const Item &item);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Exchanges the content of the Item by the content of \a item.
|
||||||
|
*/
|
||||||
|
void swap(Item &item);
|
||||||
|
|
||||||
|
~Item();
|
||||||
|
|
||||||
|
Item(int value);
|
||||||
|
Item(unsigned char value);
|
||||||
|
Item(unsigned int value);
|
||||||
|
Item(long long value);
|
||||||
|
Item(bool value);
|
||||||
|
Item(int first, int second);
|
||||||
|
Item(const StringList &value);
|
||||||
|
Item(const ByteVectorList &value);
|
||||||
|
Item(const CoverArtList &value);
|
||||||
|
|
||||||
|
void setAtomDataType(AtomDataType type);
|
||||||
|
AtomDataType atomDataType() const;
|
||||||
|
|
||||||
|
int toInt() const;
|
||||||
|
unsigned char toByte() const;
|
||||||
|
unsigned int toUInt() const;
|
||||||
|
long long toLongLong() const;
|
||||||
|
bool toBool() const;
|
||||||
|
IntPair toIntPair() const;
|
||||||
|
StringList toStringList() const;
|
||||||
|
ByteVectorList toByteVectorList() const;
|
||||||
|
CoverArtList toCoverArtList() const;
|
||||||
|
|
||||||
|
bool isValid() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
class ItemPrivate;
|
||||||
|
ItemPrivate *d;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
234
3rdparty/taglib/mp4/mp4properties.cpp
vendored
Normal file
234
3rdparty/taglib/mp4/mp4properties.cpp
vendored
Normal file
@@ -0,0 +1,234 @@
|
|||||||
|
/**************************************************************************
|
||||||
|
copyright : (C) 2007 by Lukáš Lalinský
|
||||||
|
email : lalinsky@gmail.com
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include <tdebug.h>
|
||||||
|
#include <tstring.h>
|
||||||
|
#include "mp4file.h"
|
||||||
|
#include "mp4atom.h"
|
||||||
|
#include "mp4properties.h"
|
||||||
|
|
||||||
|
using namespace TagLib;
|
||||||
|
|
||||||
|
class MP4::Properties::PropertiesPrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PropertiesPrivate() :
|
||||||
|
length(0),
|
||||||
|
bitrate(0),
|
||||||
|
sampleRate(0),
|
||||||
|
channels(0),
|
||||||
|
bitsPerSample(0),
|
||||||
|
encrypted(false),
|
||||||
|
codec(MP4::Properties::Unknown) {}
|
||||||
|
|
||||||
|
int length;
|
||||||
|
int bitrate;
|
||||||
|
int sampleRate;
|
||||||
|
int channels;
|
||||||
|
int bitsPerSample;
|
||||||
|
bool encrypted;
|
||||||
|
Codec codec;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// public members
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
MP4::Properties::Properties(File *file, MP4::Atoms *atoms, ReadStyle style) :
|
||||||
|
AudioProperties(style),
|
||||||
|
d(new PropertiesPrivate())
|
||||||
|
{
|
||||||
|
read(file, atoms);
|
||||||
|
}
|
||||||
|
|
||||||
|
MP4::Properties::~Properties()
|
||||||
|
{
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
MP4::Properties::channels() const
|
||||||
|
{
|
||||||
|
return d->channels;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
MP4::Properties::sampleRate() const
|
||||||
|
{
|
||||||
|
return d->sampleRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
MP4::Properties::length() const
|
||||||
|
{
|
||||||
|
return lengthInSeconds();
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
MP4::Properties::lengthInSeconds() const
|
||||||
|
{
|
||||||
|
return d->length / 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
MP4::Properties::lengthInMilliseconds() const
|
||||||
|
{
|
||||||
|
return d->length;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
MP4::Properties::bitrate() const
|
||||||
|
{
|
||||||
|
return d->bitrate;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
MP4::Properties::bitsPerSample() const
|
||||||
|
{
|
||||||
|
return d->bitsPerSample;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
MP4::Properties::isEncrypted() const
|
||||||
|
{
|
||||||
|
return d->encrypted;
|
||||||
|
}
|
||||||
|
|
||||||
|
MP4::Properties::Codec
|
||||||
|
MP4::Properties::codec() const
|
||||||
|
{
|
||||||
|
return d->codec;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// private members
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void
|
||||||
|
MP4::Properties::read(File *file, Atoms *atoms)
|
||||||
|
{
|
||||||
|
MP4::Atom *moov = atoms->find("moov");
|
||||||
|
if(!moov) {
|
||||||
|
debug("MP4: Atom 'moov' not found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MP4::Atom *trak = 0;
|
||||||
|
ByteVector data;
|
||||||
|
|
||||||
|
const MP4::AtomList trakList = moov->findall("trak");
|
||||||
|
for(MP4::AtomList::ConstIterator it = trakList.begin(); it != trakList.end(); ++it) {
|
||||||
|
trak = *it;
|
||||||
|
MP4::Atom *hdlr = trak->find("mdia", "hdlr");
|
||||||
|
if(!hdlr) {
|
||||||
|
debug("MP4: Atom 'trak.mdia.hdlr' not found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
file->seek(hdlr->offset);
|
||||||
|
data = file->readBlock(hdlr->length);
|
||||||
|
if(data.containsAt("soun", 16)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
trak = 0;
|
||||||
|
}
|
||||||
|
if(!trak) {
|
||||||
|
debug("MP4: No audio tracks");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MP4::Atom *mdhd = trak->find("mdia", "mdhd");
|
||||||
|
if(!mdhd) {
|
||||||
|
debug("MP4: Atom 'trak.mdia.mdhd' not found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
file->seek(mdhd->offset);
|
||||||
|
data = file->readBlock(mdhd->length);
|
||||||
|
|
||||||
|
const unsigned int version = data[8];
|
||||||
|
long long unit;
|
||||||
|
long long length;
|
||||||
|
if(version == 1) {
|
||||||
|
if(data.size() < 36 + 8) {
|
||||||
|
debug("MP4: Atom 'trak.mdia.mdhd' is smaller than expected");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
unit = data.toLongLong(28U);
|
||||||
|
length = data.toLongLong(36U);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(data.size() < 24 + 4) {
|
||||||
|
debug("MP4: Atom 'trak.mdia.mdhd' is smaller than expected");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
unit = data.toUInt(20U);
|
||||||
|
length = data.toUInt(24U);
|
||||||
|
}
|
||||||
|
if(unit > 0 && length > 0)
|
||||||
|
d->length = static_cast<int>(length * 1000.0 / unit + 0.5);
|
||||||
|
|
||||||
|
MP4::Atom *atom = trak->find("mdia", "minf", "stbl", "stsd");
|
||||||
|
if(!atom) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
file->seek(atom->offset);
|
||||||
|
data = file->readBlock(atom->length);
|
||||||
|
if(data.containsAt("mp4a", 20)) {
|
||||||
|
d->codec = AAC;
|
||||||
|
d->channels = data.toShort(40U);
|
||||||
|
d->bitsPerSample = data.toShort(42U);
|
||||||
|
d->sampleRate = data.toUInt(46U);
|
||||||
|
if(data.containsAt("esds", 56) && data[64] == 0x03) {
|
||||||
|
unsigned int pos = 65;
|
||||||
|
if(data.containsAt("\x80\x80\x80", pos)) {
|
||||||
|
pos += 3;
|
||||||
|
}
|
||||||
|
pos += 4;
|
||||||
|
if(data[pos] == 0x04) {
|
||||||
|
pos += 1;
|
||||||
|
if(data.containsAt("\x80\x80\x80", pos)) {
|
||||||
|
pos += 3;
|
||||||
|
}
|
||||||
|
pos += 10;
|
||||||
|
d->bitrate = static_cast<int>((data.toUInt(pos) + 500) / 1000.0 + 0.5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(data.containsAt("alac", 20)) {
|
||||||
|
if(atom->length == 88 && data.containsAt("alac", 56)) {
|
||||||
|
d->codec = ALAC;
|
||||||
|
d->bitsPerSample = data.at(69);
|
||||||
|
d->channels = data.at(73);
|
||||||
|
d->bitrate = static_cast<int>(data.toUInt(80U) / 1000.0 + 0.5);
|
||||||
|
d->sampleRate = data.toUInt(84U);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MP4::Atom *drms = atom->find("drms");
|
||||||
|
if(drms) {
|
||||||
|
d->encrypted = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
120
3rdparty/taglib/mp4/mp4properties.h
vendored
Normal file
120
3rdparty/taglib/mp4/mp4properties.h
vendored
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
/**************************************************************************
|
||||||
|
copyright : (C) 2007 by Lukáš Lalinský
|
||||||
|
email : lalinsky@gmail.com
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef TAGLIB_MP4PROPERTIES_H
|
||||||
|
#define TAGLIB_MP4PROPERTIES_H
|
||||||
|
|
||||||
|
#include "taglib_export.h"
|
||||||
|
#include "audioproperties.h"
|
||||||
|
|
||||||
|
namespace TagLib {
|
||||||
|
|
||||||
|
namespace MP4 {
|
||||||
|
|
||||||
|
class Atoms;
|
||||||
|
class File;
|
||||||
|
|
||||||
|
//! An implementation of MP4 audio properties
|
||||||
|
class TAGLIB_EXPORT Properties : public AudioProperties
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum Codec {
|
||||||
|
Unknown = 0,
|
||||||
|
AAC,
|
||||||
|
ALAC
|
||||||
|
};
|
||||||
|
|
||||||
|
Properties(File *file, Atoms *atoms, ReadStyle style = Average);
|
||||||
|
virtual ~Properties();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the length of the file in seconds. The length is rounded down to
|
||||||
|
* the nearest whole second.
|
||||||
|
*
|
||||||
|
* \note This method is just an alias of lengthInSeconds().
|
||||||
|
*
|
||||||
|
* \deprecated
|
||||||
|
*/
|
||||||
|
virtual int length() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the length of the file in seconds. The length is rounded down to
|
||||||
|
* the nearest whole second.
|
||||||
|
*
|
||||||
|
* \see lengthInMilliseconds()
|
||||||
|
*/
|
||||||
|
// BIC: make virtual
|
||||||
|
int lengthInSeconds() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the length of the file in milliseconds.
|
||||||
|
*
|
||||||
|
* \see lengthInSeconds()
|
||||||
|
*/
|
||||||
|
// BIC: make virtual
|
||||||
|
int lengthInMilliseconds() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the average bit rate of the file in kb/s.
|
||||||
|
*/
|
||||||
|
virtual int bitrate() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the sample rate in Hz.
|
||||||
|
*/
|
||||||
|
virtual int sampleRate() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the number of audio channels.
|
||||||
|
*/
|
||||||
|
virtual int channels() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the number of bits per audio sample.
|
||||||
|
*/
|
||||||
|
virtual int bitsPerSample() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns whether or not the file is encrypted.
|
||||||
|
*/
|
||||||
|
bool isEncrypted() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the codec used in the file.
|
||||||
|
*/
|
||||||
|
Codec codec() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void read(File *file, Atoms *atoms);
|
||||||
|
|
||||||
|
class PropertiesPrivate;
|
||||||
|
PropertiesPrivate *d;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
997
3rdparty/taglib/mp4/mp4tag.cpp
vendored
Normal file
997
3rdparty/taglib/mp4/mp4tag.cpp
vendored
Normal file
@@ -0,0 +1,997 @@
|
|||||||
|
/**************************************************************************
|
||||||
|
copyright : (C) 2007,2011 by Lukáš Lalinský
|
||||||
|
email : lalinsky@gmail.com
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include <tdebug.h>
|
||||||
|
#include <tstring.h>
|
||||||
|
#include <tpropertymap.h>
|
||||||
|
#include "mp4atom.h"
|
||||||
|
#include "mp4tag.h"
|
||||||
|
#include "id3v1genres.h"
|
||||||
|
|
||||||
|
using namespace TagLib;
|
||||||
|
|
||||||
|
class MP4::Tag::TagPrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TagPrivate() :
|
||||||
|
file(0),
|
||||||
|
atoms(0) {}
|
||||||
|
|
||||||
|
TagLib::File *file;
|
||||||
|
Atoms *atoms;
|
||||||
|
ItemMap items;
|
||||||
|
};
|
||||||
|
|
||||||
|
MP4::Tag::Tag() :
|
||||||
|
d(new TagPrivate())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
MP4::Tag::Tag(TagLib::File *file, MP4::Atoms *atoms) :
|
||||||
|
d(new TagPrivate())
|
||||||
|
{
|
||||||
|
d->file = file;
|
||||||
|
d->atoms = atoms;
|
||||||
|
|
||||||
|
MP4::Atom *ilst = atoms->find("moov", "udta", "meta", "ilst");
|
||||||
|
if(!ilst) {
|
||||||
|
//debug("Atom moov.udta.meta.ilst not found.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(AtomList::ConstIterator it = ilst->children.begin(); it != ilst->children.end(); ++it) {
|
||||||
|
MP4::Atom *atom = *it;
|
||||||
|
file->seek(atom->offset + 8);
|
||||||
|
if(atom->name == "----") {
|
||||||
|
parseFreeForm(atom);
|
||||||
|
}
|
||||||
|
else if(atom->name == "trkn" || atom->name == "disk") {
|
||||||
|
parseIntPair(atom);
|
||||||
|
}
|
||||||
|
else if(atom->name == "cpil" || atom->name == "pgap" || atom->name == "pcst" ||
|
||||||
|
atom->name == "hdvd" || atom->name == "shwm") {
|
||||||
|
parseBool(atom);
|
||||||
|
}
|
||||||
|
else if(atom->name == "tmpo" || atom->name == "rate" || atom->name == "\251mvi" || atom->name == "\251mvc") {
|
||||||
|
parseInt(atom);
|
||||||
|
}
|
||||||
|
else if(atom->name == "tvsn" || atom->name == "tves" || atom->name == "cnID" ||
|
||||||
|
atom->name == "sfID" || atom->name == "atID" || atom->name == "geID" ||
|
||||||
|
atom->name == "cmID") {
|
||||||
|
parseUInt(atom);
|
||||||
|
}
|
||||||
|
else if(atom->name == "plID") {
|
||||||
|
parseLongLong(atom);
|
||||||
|
}
|
||||||
|
else if(atom->name == "stik" || atom->name == "rtng" || atom->name == "akID") {
|
||||||
|
parseByte(atom);
|
||||||
|
}
|
||||||
|
else if(atom->name == "gnre") {
|
||||||
|
parseGnre(atom);
|
||||||
|
}
|
||||||
|
else if(atom->name == "covr") {
|
||||||
|
parseCovr(atom);
|
||||||
|
}
|
||||||
|
else if(atom->name == "purl" || atom->name == "egid") {
|
||||||
|
parseText(atom, -1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
parseText(atom);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MP4::Tag::~Tag()
|
||||||
|
{
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
MP4::AtomDataList
|
||||||
|
MP4::Tag::parseData2(const MP4::Atom *atom, int expectedFlags, bool freeForm)
|
||||||
|
{
|
||||||
|
AtomDataList result;
|
||||||
|
ByteVector data = d->file->readBlock(atom->length - 8);
|
||||||
|
int i = 0;
|
||||||
|
unsigned int pos = 0;
|
||||||
|
while(pos < data.size()) {
|
||||||
|
const int length = static_cast<int>(data.toUInt(pos));
|
||||||
|
if(length < 12) {
|
||||||
|
debug("MP4: Too short atom");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ByteVector name = data.mid(pos + 4, 4);
|
||||||
|
const int flags = static_cast<int>(data.toUInt(pos + 8));
|
||||||
|
if(freeForm && i < 2) {
|
||||||
|
if(i == 0 && name != "mean") {
|
||||||
|
debug("MP4: Unexpected atom \"" + name + "\", expecting \"mean\"");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
else if(i == 1 && name != "name") {
|
||||||
|
debug("MP4: Unexpected atom \"" + name + "\", expecting \"name\"");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
result.append(AtomData(AtomDataType(flags), data.mid(pos + 12, length - 12)));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(name != "data") {
|
||||||
|
debug("MP4: Unexpected atom \"" + name + "\", expecting \"data\"");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
if(expectedFlags == -1 || flags == expectedFlags) {
|
||||||
|
result.append(AtomData(AtomDataType(flags), data.mid(pos + 16, length - 16)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pos += length;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVectorList
|
||||||
|
MP4::Tag::parseData(const MP4::Atom *atom, int expectedFlags, bool freeForm)
|
||||||
|
{
|
||||||
|
AtomDataList data = parseData2(atom, expectedFlags, freeForm);
|
||||||
|
ByteVectorList result;
|
||||||
|
for(AtomDataList::ConstIterator it = data.begin(); it != data.end(); ++it) {
|
||||||
|
result.append(it->data);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MP4::Tag::parseInt(const MP4::Atom *atom)
|
||||||
|
{
|
||||||
|
ByteVectorList data = parseData(atom);
|
||||||
|
if(!data.isEmpty()) {
|
||||||
|
addItem(atom->name, (int)data[0].toShort());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MP4::Tag::parseUInt(const MP4::Atom *atom)
|
||||||
|
{
|
||||||
|
ByteVectorList data = parseData(atom);
|
||||||
|
if(!data.isEmpty()) {
|
||||||
|
addItem(atom->name, data[0].toUInt());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MP4::Tag::parseLongLong(const MP4::Atom *atom)
|
||||||
|
{
|
||||||
|
ByteVectorList data = parseData(atom);
|
||||||
|
if(!data.isEmpty()) {
|
||||||
|
addItem(atom->name, data[0].toLongLong());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MP4::Tag::parseByte(const MP4::Atom *atom)
|
||||||
|
{
|
||||||
|
ByteVectorList data = parseData(atom);
|
||||||
|
if(!data.isEmpty()) {
|
||||||
|
addItem(atom->name, static_cast<unsigned char>(data[0].at(0)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MP4::Tag::parseGnre(const MP4::Atom *atom)
|
||||||
|
{
|
||||||
|
ByteVectorList data = parseData(atom);
|
||||||
|
if(!data.isEmpty()) {
|
||||||
|
int idx = (int)data[0].toShort();
|
||||||
|
if(idx > 0) {
|
||||||
|
addItem("\251gen", StringList(ID3v1::genre(idx - 1)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MP4::Tag::parseIntPair(const MP4::Atom *atom)
|
||||||
|
{
|
||||||
|
ByteVectorList data = parseData(atom);
|
||||||
|
if(!data.isEmpty()) {
|
||||||
|
const int a = data[0].toShort(2U);
|
||||||
|
const int b = data[0].toShort(4U);
|
||||||
|
addItem(atom->name, MP4::Item(a, b));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MP4::Tag::parseBool(const MP4::Atom *atom)
|
||||||
|
{
|
||||||
|
ByteVectorList data = parseData(atom);
|
||||||
|
if(!data.isEmpty()) {
|
||||||
|
bool value = data[0].size() ? data[0][0] != '\0' : false;
|
||||||
|
addItem(atom->name, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MP4::Tag::parseText(const MP4::Atom *atom, int expectedFlags)
|
||||||
|
{
|
||||||
|
ByteVectorList data = parseData(atom, expectedFlags);
|
||||||
|
if(!data.isEmpty()) {
|
||||||
|
StringList value;
|
||||||
|
for(ByteVectorList::ConstIterator it = data.begin(); it != data.end(); ++it) {
|
||||||
|
value.append(String(*it, String::UTF8));
|
||||||
|
}
|
||||||
|
addItem(atom->name, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MP4::Tag::parseFreeForm(const MP4::Atom *atom)
|
||||||
|
{
|
||||||
|
AtomDataList data = parseData2(atom, -1, true);
|
||||||
|
if(data.size() > 2) {
|
||||||
|
AtomDataList::ConstIterator itBegin = data.begin();
|
||||||
|
|
||||||
|
String name = "----:";
|
||||||
|
name += String((itBegin++)->data, String::UTF8); // data[0].data
|
||||||
|
name += ':';
|
||||||
|
name += String((itBegin++)->data, String::UTF8); // data[1].data
|
||||||
|
|
||||||
|
AtomDataType type = itBegin->type; // data[2].type
|
||||||
|
|
||||||
|
for(AtomDataList::ConstIterator it = itBegin; it != data.end(); ++it) {
|
||||||
|
if(it->type != type) {
|
||||||
|
debug("MP4: We currently don't support values with multiple types");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(type == TypeUTF8) {
|
||||||
|
StringList value;
|
||||||
|
for(AtomDataList::ConstIterator it = itBegin; it != data.end(); ++it) {
|
||||||
|
value.append(String(it->data, String::UTF8));
|
||||||
|
}
|
||||||
|
Item item(value);
|
||||||
|
item.setAtomDataType(type);
|
||||||
|
addItem(name, item);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ByteVectorList value;
|
||||||
|
for(AtomDataList::ConstIterator it = itBegin; it != data.end(); ++it) {
|
||||||
|
value.append(it->data);
|
||||||
|
}
|
||||||
|
Item item(value);
|
||||||
|
item.setAtomDataType(type);
|
||||||
|
addItem(name, item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MP4::Tag::parseCovr(const MP4::Atom *atom)
|
||||||
|
{
|
||||||
|
MP4::CoverArtList value;
|
||||||
|
ByteVector data = d->file->readBlock(atom->length - 8);
|
||||||
|
unsigned int pos = 0;
|
||||||
|
while(pos < data.size()) {
|
||||||
|
const int length = static_cast<int>(data.toUInt(pos));
|
||||||
|
if(length < 12) {
|
||||||
|
debug("MP4: Too short atom");
|
||||||
|
break;;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ByteVector name = data.mid(pos + 4, 4);
|
||||||
|
const int flags = static_cast<int>(data.toUInt(pos + 8));
|
||||||
|
if(name != "data") {
|
||||||
|
debug("MP4: Unexpected atom \"" + name + "\", expecting \"data\"");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(flags == TypeJPEG || flags == TypePNG || flags == TypeBMP ||
|
||||||
|
flags == TypeGIF || flags == TypeImplicit) {
|
||||||
|
value.append(MP4::CoverArt(MP4::CoverArt::Format(flags),
|
||||||
|
data.mid(pos + 16, length - 16)));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
debug("MP4: Unknown covr format " + String::number(flags));
|
||||||
|
}
|
||||||
|
pos += length;
|
||||||
|
}
|
||||||
|
if(!value.isEmpty())
|
||||||
|
addItem(atom->name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector
|
||||||
|
MP4::Tag::padIlst(const ByteVector &data, int length) const
|
||||||
|
{
|
||||||
|
if(length == -1) {
|
||||||
|
length = ((data.size() + 1023) & ~1023) - data.size();
|
||||||
|
}
|
||||||
|
return renderAtom("free", ByteVector(length, '\1'));
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector
|
||||||
|
MP4::Tag::renderAtom(const ByteVector &name, const ByteVector &data) const
|
||||||
|
{
|
||||||
|
return ByteVector::fromUInt(data.size() + 8) + name + data;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector
|
||||||
|
MP4::Tag::renderData(const ByteVector &name, int flags, const ByteVectorList &data) const
|
||||||
|
{
|
||||||
|
ByteVector result;
|
||||||
|
for(ByteVectorList::ConstIterator it = data.begin(); it != data.end(); ++it) {
|
||||||
|
result.append(renderAtom("data", ByteVector::fromUInt(flags) + ByteVector(4, '\0') + *it));
|
||||||
|
}
|
||||||
|
return renderAtom(name, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector
|
||||||
|
MP4::Tag::renderBool(const ByteVector &name, const MP4::Item &item) const
|
||||||
|
{
|
||||||
|
ByteVectorList data;
|
||||||
|
data.append(ByteVector(1, item.toBool() ? '\1' : '\0'));
|
||||||
|
return renderData(name, TypeInteger, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector
|
||||||
|
MP4::Tag::renderInt(const ByteVector &name, const MP4::Item &item) const
|
||||||
|
{
|
||||||
|
ByteVectorList data;
|
||||||
|
data.append(ByteVector::fromShort(item.toInt()));
|
||||||
|
return renderData(name, TypeInteger, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector
|
||||||
|
MP4::Tag::renderUInt(const ByteVector &name, const MP4::Item &item) const
|
||||||
|
{
|
||||||
|
ByteVectorList data;
|
||||||
|
data.append(ByteVector::fromUInt(item.toUInt()));
|
||||||
|
return renderData(name, TypeInteger, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector
|
||||||
|
MP4::Tag::renderLongLong(const ByteVector &name, const MP4::Item &item) const
|
||||||
|
{
|
||||||
|
ByteVectorList data;
|
||||||
|
data.append(ByteVector::fromLongLong(item.toLongLong()));
|
||||||
|
return renderData(name, TypeInteger, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector
|
||||||
|
MP4::Tag::renderByte(const ByteVector &name, const MP4::Item &item) const
|
||||||
|
{
|
||||||
|
ByteVectorList data;
|
||||||
|
data.append(ByteVector(1, item.toByte()));
|
||||||
|
return renderData(name, TypeInteger, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector
|
||||||
|
MP4::Tag::renderIntPair(const ByteVector &name, const MP4::Item &item) const
|
||||||
|
{
|
||||||
|
ByteVectorList data;
|
||||||
|
data.append(ByteVector(2, '\0') +
|
||||||
|
ByteVector::fromShort(item.toIntPair().first) +
|
||||||
|
ByteVector::fromShort(item.toIntPair().second) +
|
||||||
|
ByteVector(2, '\0'));
|
||||||
|
return renderData(name, TypeImplicit, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector
|
||||||
|
MP4::Tag::renderIntPairNoTrailing(const ByteVector &name, const MP4::Item &item) const
|
||||||
|
{
|
||||||
|
ByteVectorList data;
|
||||||
|
data.append(ByteVector(2, '\0') +
|
||||||
|
ByteVector::fromShort(item.toIntPair().first) +
|
||||||
|
ByteVector::fromShort(item.toIntPair().second));
|
||||||
|
return renderData(name, TypeImplicit, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector
|
||||||
|
MP4::Tag::renderText(const ByteVector &name, const MP4::Item &item, int flags) const
|
||||||
|
{
|
||||||
|
ByteVectorList data;
|
||||||
|
StringList value = item.toStringList();
|
||||||
|
for(StringList::ConstIterator it = value.begin(); it != value.end(); ++it) {
|
||||||
|
data.append(it->data(String::UTF8));
|
||||||
|
}
|
||||||
|
return renderData(name, flags, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector
|
||||||
|
MP4::Tag::renderCovr(const ByteVector &name, const MP4::Item &item) const
|
||||||
|
{
|
||||||
|
ByteVector data;
|
||||||
|
MP4::CoverArtList value = item.toCoverArtList();
|
||||||
|
for(MP4::CoverArtList::ConstIterator it = value.begin(); it != value.end(); ++it) {
|
||||||
|
data.append(renderAtom("data", ByteVector::fromUInt(it->format()) +
|
||||||
|
ByteVector(4, '\0') + it->data()));
|
||||||
|
}
|
||||||
|
return renderAtom(name, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteVector
|
||||||
|
MP4::Tag::renderFreeForm(const String &name, const MP4::Item &item) const
|
||||||
|
{
|
||||||
|
StringList header = StringList::split(name, ":");
|
||||||
|
if(header.size() != 3) {
|
||||||
|
debug("MP4: Invalid free-form item name \"" + name + "\"");
|
||||||
|
return ByteVector();
|
||||||
|
}
|
||||||
|
ByteVector data;
|
||||||
|
data.append(renderAtom("mean", ByteVector::fromUInt(0) + header[1].data(String::UTF8)));
|
||||||
|
data.append(renderAtom("name", ByteVector::fromUInt(0) + header[2].data(String::UTF8)));
|
||||||
|
AtomDataType type = item.atomDataType();
|
||||||
|
if(type == TypeUndefined) {
|
||||||
|
if(!item.toStringList().isEmpty()) {
|
||||||
|
type = TypeUTF8;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
type = TypeImplicit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(type == TypeUTF8) {
|
||||||
|
StringList value = item.toStringList();
|
||||||
|
for(StringList::ConstIterator it = value.begin(); it != value.end(); ++it) {
|
||||||
|
data.append(renderAtom("data", ByteVector::fromUInt(type) + ByteVector(4, '\0') + it->data(String::UTF8)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ByteVectorList value = item.toByteVectorList();
|
||||||
|
for(ByteVectorList::ConstIterator it = value.begin(); it != value.end(); ++it) {
|
||||||
|
data.append(renderAtom("data", ByteVector::fromUInt(type) + ByteVector(4, '\0') + *it));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return renderAtom("----", data);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
MP4::Tag::save()
|
||||||
|
{
|
||||||
|
ByteVector data;
|
||||||
|
for(MP4::ItemMap::ConstIterator it = d->items.begin(); it != d->items.end(); ++it) {
|
||||||
|
const String name = it->first;
|
||||||
|
if(name.startsWith("----")) {
|
||||||
|
data.append(renderFreeForm(name, it->second));
|
||||||
|
}
|
||||||
|
else if(name == "trkn") {
|
||||||
|
data.append(renderIntPair(name.data(String::Latin1), it->second));
|
||||||
|
}
|
||||||
|
else if(name == "disk") {
|
||||||
|
data.append(renderIntPairNoTrailing(name.data(String::Latin1), it->second));
|
||||||
|
}
|
||||||
|
else if(name == "cpil" || name == "pgap" || name == "pcst" || name == "hdvd" ||
|
||||||
|
name == "shwm") {
|
||||||
|
data.append(renderBool(name.data(String::Latin1), it->second));
|
||||||
|
}
|
||||||
|
else if(name == "tmpo" || name == "rate" || name == "\251mvi" || name == "\251mvc") {
|
||||||
|
data.append(renderInt(name.data(String::Latin1), it->second));
|
||||||
|
}
|
||||||
|
else if(name == "tvsn" || name == "tves" || name == "cnID" ||
|
||||||
|
name == "sfID" || name == "atID" || name == "geID" ||
|
||||||
|
name == "cmID") {
|
||||||
|
data.append(renderUInt(name.data(String::Latin1), it->second));
|
||||||
|
}
|
||||||
|
else if(name == "plID") {
|
||||||
|
data.append(renderLongLong(name.data(String::Latin1), it->second));
|
||||||
|
}
|
||||||
|
else if(name == "stik" || name == "rtng" || name == "akID") {
|
||||||
|
data.append(renderByte(name.data(String::Latin1), it->second));
|
||||||
|
}
|
||||||
|
else if(name == "covr") {
|
||||||
|
data.append(renderCovr(name.data(String::Latin1), it->second));
|
||||||
|
}
|
||||||
|
else if(name == "purl" || name == "egid") {
|
||||||
|
data.append(renderText(name.data(String::Latin1), it->second, TypeImplicit));
|
||||||
|
}
|
||||||
|
else if(name.size() == 4){
|
||||||
|
data.append(renderText(name.data(String::Latin1), it->second));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
debug("MP4: Unknown item name \"" + name + "\"");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
data = renderAtom("ilst", data);
|
||||||
|
|
||||||
|
AtomList path = d->atoms->path("moov", "udta", "meta", "ilst");
|
||||||
|
if(path.size() == 4) {
|
||||||
|
saveExisting(data, path);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
saveNew(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MP4::Tag::updateParents(const AtomList &path, long delta, int ignore)
|
||||||
|
{
|
||||||
|
if(static_cast<int>(path.size()) <= ignore)
|
||||||
|
return;
|
||||||
|
|
||||||
|
AtomList::ConstIterator itEnd = path.end();
|
||||||
|
std::advance(itEnd, 0 - ignore);
|
||||||
|
|
||||||
|
for(AtomList::ConstIterator it = path.begin(); it != itEnd; ++it) {
|
||||||
|
d->file->seek((*it)->offset);
|
||||||
|
long size = d->file->readBlock(4).toUInt();
|
||||||
|
// 64-bit
|
||||||
|
if (size == 1) {
|
||||||
|
d->file->seek(4, File::Current); // Skip name
|
||||||
|
long long longSize = d->file->readBlock(8).toLongLong();
|
||||||
|
// Seek the offset of the 64-bit size
|
||||||
|
d->file->seek((*it)->offset + 8);
|
||||||
|
d->file->writeBlock(ByteVector::fromLongLong(longSize + delta));
|
||||||
|
}
|
||||||
|
// 32-bit
|
||||||
|
else {
|
||||||
|
d->file->seek((*it)->offset);
|
||||||
|
d->file->writeBlock(ByteVector::fromUInt(size + delta));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MP4::Tag::updateOffsets(long delta, long offset)
|
||||||
|
{
|
||||||
|
MP4::Atom *moov = d->atoms->find("moov");
|
||||||
|
if(moov) {
|
||||||
|
MP4::AtomList stco = moov->findall("stco", true);
|
||||||
|
for(MP4::AtomList::ConstIterator it = stco.begin(); it != stco.end(); ++it) {
|
||||||
|
MP4::Atom *atom = *it;
|
||||||
|
if(atom->offset > offset) {
|
||||||
|
atom->offset += delta;
|
||||||
|
}
|
||||||
|
d->file->seek(atom->offset + 12);
|
||||||
|
ByteVector data = d->file->readBlock(atom->length - 12);
|
||||||
|
unsigned int count = data.toUInt();
|
||||||
|
d->file->seek(atom->offset + 16);
|
||||||
|
unsigned int pos = 4;
|
||||||
|
while(count--) {
|
||||||
|
long o = static_cast<long>(data.toUInt(pos));
|
||||||
|
if(o > offset) {
|
||||||
|
o += delta;
|
||||||
|
}
|
||||||
|
d->file->writeBlock(ByteVector::fromUInt(o));
|
||||||
|
pos += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MP4::AtomList co64 = moov->findall("co64", true);
|
||||||
|
for(MP4::AtomList::ConstIterator it = co64.begin(); it != co64.end(); ++it) {
|
||||||
|
MP4::Atom *atom = *it;
|
||||||
|
if(atom->offset > offset) {
|
||||||
|
atom->offset += delta;
|
||||||
|
}
|
||||||
|
d->file->seek(atom->offset + 12);
|
||||||
|
ByteVector data = d->file->readBlock(atom->length - 12);
|
||||||
|
unsigned int count = data.toUInt();
|
||||||
|
d->file->seek(atom->offset + 16);
|
||||||
|
unsigned int pos = 4;
|
||||||
|
while(count--) {
|
||||||
|
long long o = data.toLongLong(pos);
|
||||||
|
if(o > offset) {
|
||||||
|
o += delta;
|
||||||
|
}
|
||||||
|
d->file->writeBlock(ByteVector::fromLongLong(o));
|
||||||
|
pos += 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MP4::Atom *moof = d->atoms->find("moof");
|
||||||
|
if(moof) {
|
||||||
|
MP4::AtomList tfhd = moof->findall("tfhd", true);
|
||||||
|
for(MP4::AtomList::ConstIterator it = tfhd.begin(); it != tfhd.end(); ++it) {
|
||||||
|
MP4::Atom *atom = *it;
|
||||||
|
if(atom->offset > offset) {
|
||||||
|
atom->offset += delta;
|
||||||
|
}
|
||||||
|
d->file->seek(atom->offset + 9);
|
||||||
|
ByteVector data = d->file->readBlock(atom->length - 9);
|
||||||
|
const unsigned int flags = data.toUInt(0, 3, true);
|
||||||
|
if(flags & 1) {
|
||||||
|
long long o = data.toLongLong(7U);
|
||||||
|
if(o > offset) {
|
||||||
|
o += delta;
|
||||||
|
}
|
||||||
|
d->file->seek(atom->offset + 16);
|
||||||
|
d->file->writeBlock(ByteVector::fromLongLong(o));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MP4::Tag::saveNew(ByteVector data)
|
||||||
|
{
|
||||||
|
data = renderAtom("meta", ByteVector(4, '\0') +
|
||||||
|
renderAtom("hdlr", ByteVector(8, '\0') + ByteVector("mdirappl") +
|
||||||
|
ByteVector(9, '\0')) +
|
||||||
|
data + padIlst(data));
|
||||||
|
|
||||||
|
AtomList path = d->atoms->path("moov", "udta");
|
||||||
|
if(path.size() != 2) {
|
||||||
|
path = d->atoms->path("moov");
|
||||||
|
data = renderAtom("udta", data);
|
||||||
|
}
|
||||||
|
|
||||||
|
long offset = path.back()->offset + 8;
|
||||||
|
d->file->insert(data, offset, 0);
|
||||||
|
|
||||||
|
updateParents(path, data.size());
|
||||||
|
updateOffsets(data.size(), offset);
|
||||||
|
|
||||||
|
// Insert the newly created atoms into the tree to keep it up-to-date.
|
||||||
|
|
||||||
|
d->file->seek(offset);
|
||||||
|
path.back()->children.prepend(new Atom(d->file));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MP4::Tag::saveExisting(ByteVector data, const AtomList &path)
|
||||||
|
{
|
||||||
|
AtomList::ConstIterator it = path.end();
|
||||||
|
|
||||||
|
MP4::Atom *ilst = *(--it);
|
||||||
|
long offset = ilst->offset;
|
||||||
|
long length = ilst->length;
|
||||||
|
|
||||||
|
MP4::Atom *meta = *(--it);
|
||||||
|
AtomList::ConstIterator index = meta->children.find(ilst);
|
||||||
|
|
||||||
|
// check if there is an atom before 'ilst', and possibly use it as padding
|
||||||
|
if(index != meta->children.begin()) {
|
||||||
|
AtomList::ConstIterator prevIndex = index;
|
||||||
|
prevIndex--;
|
||||||
|
MP4::Atom *prev = *prevIndex;
|
||||||
|
if(prev->name == "free") {
|
||||||
|
offset = prev->offset;
|
||||||
|
length += prev->length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// check if there is an atom after 'ilst', and possibly use it as padding
|
||||||
|
AtomList::ConstIterator nextIndex = index;
|
||||||
|
nextIndex++;
|
||||||
|
if(nextIndex != meta->children.end()) {
|
||||||
|
MP4::Atom *next = *nextIndex;
|
||||||
|
if(next->name == "free") {
|
||||||
|
length += next->length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
long delta = data.size() - length;
|
||||||
|
if(delta > 0 || (delta < 0 && delta > -8)) {
|
||||||
|
data.append(padIlst(data));
|
||||||
|
delta = data.size() - length;
|
||||||
|
}
|
||||||
|
else if(delta < 0) {
|
||||||
|
data.append(padIlst(data, -delta - 8));
|
||||||
|
delta = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
d->file->insert(data, offset, length);
|
||||||
|
|
||||||
|
if(delta) {
|
||||||
|
updateParents(path, delta, 1);
|
||||||
|
updateOffsets(delta, offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String
|
||||||
|
MP4::Tag::title() const
|
||||||
|
{
|
||||||
|
if(d->items.contains("\251nam"))
|
||||||
|
return d->items["\251nam"].toStringList().toString(", ");
|
||||||
|
return String();
|
||||||
|
}
|
||||||
|
|
||||||
|
String
|
||||||
|
MP4::Tag::artist() const
|
||||||
|
{
|
||||||
|
if(d->items.contains("\251ART"))
|
||||||
|
return d->items["\251ART"].toStringList().toString(", ");
|
||||||
|
return String();
|
||||||
|
}
|
||||||
|
|
||||||
|
String
|
||||||
|
MP4::Tag::album() const
|
||||||
|
{
|
||||||
|
if(d->items.contains("\251alb"))
|
||||||
|
return d->items["\251alb"].toStringList().toString(", ");
|
||||||
|
return String();
|
||||||
|
}
|
||||||
|
|
||||||
|
String
|
||||||
|
MP4::Tag::comment() const
|
||||||
|
{
|
||||||
|
if(d->items.contains("\251cmt"))
|
||||||
|
return d->items["\251cmt"].toStringList().toString(", ");
|
||||||
|
return String();
|
||||||
|
}
|
||||||
|
|
||||||
|
String
|
||||||
|
MP4::Tag::genre() const
|
||||||
|
{
|
||||||
|
if(d->items.contains("\251gen"))
|
||||||
|
return d->items["\251gen"].toStringList().toString(", ");
|
||||||
|
return String();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int
|
||||||
|
MP4::Tag::year() const
|
||||||
|
{
|
||||||
|
if(d->items.contains("\251day"))
|
||||||
|
return d->items["\251day"].toStringList().toString().toInt();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int
|
||||||
|
MP4::Tag::track() const
|
||||||
|
{
|
||||||
|
if(d->items.contains("trkn"))
|
||||||
|
return d->items["trkn"].toIntPair().first;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MP4::Tag::setTitle(const String &value)
|
||||||
|
{
|
||||||
|
d->items["\251nam"] = StringList(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MP4::Tag::setArtist(const String &value)
|
||||||
|
{
|
||||||
|
d->items["\251ART"] = StringList(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MP4::Tag::setAlbum(const String &value)
|
||||||
|
{
|
||||||
|
d->items["\251alb"] = StringList(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MP4::Tag::setComment(const String &value)
|
||||||
|
{
|
||||||
|
d->items["\251cmt"] = StringList(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MP4::Tag::setGenre(const String &value)
|
||||||
|
{
|
||||||
|
d->items["\251gen"] = StringList(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MP4::Tag::setYear(unsigned int value)
|
||||||
|
{
|
||||||
|
d->items["\251day"] = StringList(String::number(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MP4::Tag::setTrack(unsigned int value)
|
||||||
|
{
|
||||||
|
d->items["trkn"] = MP4::Item(value, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MP4::Tag::isEmpty() const
|
||||||
|
{
|
||||||
|
return d->items.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
MP4::ItemMap &MP4::Tag::itemListMap()
|
||||||
|
{
|
||||||
|
return d->items;
|
||||||
|
}
|
||||||
|
|
||||||
|
const MP4::ItemMap &MP4::Tag::itemMap() const
|
||||||
|
{
|
||||||
|
return d->items;
|
||||||
|
}
|
||||||
|
|
||||||
|
MP4::Item MP4::Tag::item(const String &key) const
|
||||||
|
{
|
||||||
|
return d->items[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
void MP4::Tag::setItem(const String &key, const Item &value)
|
||||||
|
{
|
||||||
|
d->items[key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MP4::Tag::removeItem(const String &key)
|
||||||
|
{
|
||||||
|
d->items.erase(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MP4::Tag::contains(const String &key) const
|
||||||
|
{
|
||||||
|
return d->items.contains(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
const char *keyTranslation[][2] = {
|
||||||
|
{ "\251nam", "TITLE" },
|
||||||
|
{ "\251ART", "ARTIST" },
|
||||||
|
{ "\251alb", "ALBUM" },
|
||||||
|
{ "\251cmt", "COMMENT" },
|
||||||
|
{ "\251gen", "GENRE" },
|
||||||
|
{ "\251day", "DATE" },
|
||||||
|
{ "\251wrt", "COMPOSER" },
|
||||||
|
{ "\251grp", "GROUPING" },
|
||||||
|
{ "aART", "ALBUMARTIST" },
|
||||||
|
{ "trkn", "TRACKNUMBER" },
|
||||||
|
{ "disk", "DISCNUMBER" },
|
||||||
|
{ "cpil", "COMPILATION" },
|
||||||
|
{ "tmpo", "BPM" },
|
||||||
|
{ "cprt", "COPYRIGHT" },
|
||||||
|
{ "\251lyr", "LYRICS" },
|
||||||
|
{ "\251too", "ENCODEDBY" },
|
||||||
|
{ "soal", "ALBUMSORT" },
|
||||||
|
{ "soaa", "ALBUMARTISTSORT" },
|
||||||
|
{ "soar", "ARTISTSORT" },
|
||||||
|
{ "sonm", "TITLESORT" },
|
||||||
|
{ "soco", "COMPOSERSORT" },
|
||||||
|
{ "sosn", "SHOWSORT" },
|
||||||
|
{ "shwm", "SHOWWORKMOVEMENT" },
|
||||||
|
{ "\251wrk", "WORK" },
|
||||||
|
{ "\251mvn", "MOVEMENTNAME" },
|
||||||
|
{ "\251mvi", "MOVEMENTNUMBER" },
|
||||||
|
{ "\251mvc", "MOVEMENTCOUNT" },
|
||||||
|
{ "----:com.apple.iTunes:MusicBrainz Track Id", "MUSICBRAINZ_TRACKID" },
|
||||||
|
{ "----:com.apple.iTunes:MusicBrainz Artist Id", "MUSICBRAINZ_ARTISTID" },
|
||||||
|
{ "----:com.apple.iTunes:MusicBrainz Album Id", "MUSICBRAINZ_ALBUMID" },
|
||||||
|
{ "----:com.apple.iTunes:MusicBrainz Album Artist Id", "MUSICBRAINZ_ALBUMARTISTID" },
|
||||||
|
{ "----:com.apple.iTunes:MusicBrainz Release Group Id", "MUSICBRAINZ_RELEASEGROUPID" },
|
||||||
|
{ "----:com.apple.iTunes:MusicBrainz Work Id", "MUSICBRAINZ_WORKID" },
|
||||||
|
{ "----:com.apple.iTunes:ASIN", "ASIN" },
|
||||||
|
{ "----:com.apple.iTunes:LABEL", "LABEL" },
|
||||||
|
{ "----:com.apple.iTunes:LYRICIST", "LYRICIST" },
|
||||||
|
{ "----:com.apple.iTunes:CONDUCTOR", "CONDUCTOR" },
|
||||||
|
{ "----:com.apple.iTunes:REMIXER", "REMIXER" },
|
||||||
|
{ "----:com.apple.iTunes:ENGINEER", "ENGINEER" },
|
||||||
|
{ "----:com.apple.iTunes:PRODUCER", "PRODUCER" },
|
||||||
|
{ "----:com.apple.iTunes:DJMIXER", "DJMIXER" },
|
||||||
|
{ "----:com.apple.iTunes:MIXER", "MIXER" },
|
||||||
|
{ "----:com.apple.iTunes:SUBTITLE", "SUBTITLE" },
|
||||||
|
{ "----:com.apple.iTunes:DISCSUBTITLE", "DISCSUBTITLE" },
|
||||||
|
{ "----:com.apple.iTunes:MOOD", "MOOD" },
|
||||||
|
{ "----:com.apple.iTunes:ISRC", "ISRC" },
|
||||||
|
{ "----:com.apple.iTunes:CATALOGNUMBER", "CATALOGNUMBER" },
|
||||||
|
{ "----:com.apple.iTunes:BARCODE", "BARCODE" },
|
||||||
|
{ "----:com.apple.iTunes:SCRIPT", "SCRIPT" },
|
||||||
|
{ "----:com.apple.iTunes:LANGUAGE", "LANGUAGE" },
|
||||||
|
{ "----:com.apple.iTunes:LICENSE", "LICENSE" },
|
||||||
|
{ "----:com.apple.iTunes:MEDIA", "MEDIA" },
|
||||||
|
};
|
||||||
|
const size_t keyTranslationSize = sizeof(keyTranslation) / sizeof(keyTranslation[0]);
|
||||||
|
|
||||||
|
String translateKey(const String &key)
|
||||||
|
{
|
||||||
|
for(size_t i = 0; i < keyTranslationSize; ++i) {
|
||||||
|
if(key == keyTranslation[i][0])
|
||||||
|
return keyTranslation[i][1];
|
||||||
|
}
|
||||||
|
|
||||||
|
return String();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyMap MP4::Tag::properties() const
|
||||||
|
{
|
||||||
|
PropertyMap props;
|
||||||
|
for(MP4::ItemMap::ConstIterator it = d->items.begin(); it != d->items.end(); ++it) {
|
||||||
|
const String key = translateKey(it->first);
|
||||||
|
if(!key.isEmpty()) {
|
||||||
|
if(key == "TRACKNUMBER" || key == "DISCNUMBER") {
|
||||||
|
MP4::Item::IntPair ip = it->second.toIntPair();
|
||||||
|
String value = String::number(ip.first);
|
||||||
|
if(ip.second) {
|
||||||
|
value += "/" + String::number(ip.second);
|
||||||
|
}
|
||||||
|
props[key] = value;
|
||||||
|
}
|
||||||
|
else if(key == "BPM" || key == "MOVEMENTNUMBER" || key == "MOVEMENTCOUNT") {
|
||||||
|
props[key] = String::number(it->second.toInt());
|
||||||
|
}
|
||||||
|
else if(key == "COMPILATION" || key == "SHOWWORKMOVEMENT") {
|
||||||
|
props[key] = String::number(it->second.toBool());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
props[key] = it->second.toStringList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
props.unsupportedData().append(it->first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return props;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MP4::Tag::removeUnsupportedProperties(const StringList &props)
|
||||||
|
{
|
||||||
|
for(StringList::ConstIterator it = props.begin(); it != props.end(); ++it)
|
||||||
|
d->items.erase(*it);
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyMap MP4::Tag::setProperties(const PropertyMap &props)
|
||||||
|
{
|
||||||
|
static Map<String, String> reverseKeyMap;
|
||||||
|
if(reverseKeyMap.isEmpty()) {
|
||||||
|
int numKeys = sizeof(keyTranslation) / sizeof(keyTranslation[0]);
|
||||||
|
for(int i = 0; i < numKeys; i++) {
|
||||||
|
reverseKeyMap[keyTranslation[i][1]] = keyTranslation[i][0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyMap origProps = properties();
|
||||||
|
for(PropertyMap::ConstIterator it = origProps.begin(); it != origProps.end(); ++it) {
|
||||||
|
if(!props.contains(it->first) || props[it->first].isEmpty()) {
|
||||||
|
d->items.erase(reverseKeyMap[it->first]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyMap ignoredProps;
|
||||||
|
for(PropertyMap::ConstIterator it = props.begin(); it != props.end(); ++it) {
|
||||||
|
if(reverseKeyMap.contains(it->first)) {
|
||||||
|
String name = reverseKeyMap[it->first];
|
||||||
|
if((it->first == "TRACKNUMBER" || it->first == "DISCNUMBER") && !it->second.isEmpty()) {
|
||||||
|
StringList parts = StringList::split(it->second.front(), "/");
|
||||||
|
if(!parts.isEmpty()) {
|
||||||
|
int first = parts[0].toInt();
|
||||||
|
int second = 0;
|
||||||
|
if(parts.size() > 1) {
|
||||||
|
second = parts[1].toInt();
|
||||||
|
}
|
||||||
|
d->items[name] = MP4::Item(first, second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if((it->first == "BPM" || it->first == "MOVEMENTNUMBER" || it->first == "MOVEMENTCOUNT") && !it->second.isEmpty()) {
|
||||||
|
int value = it->second.front().toInt();
|
||||||
|
d->items[name] = MP4::Item(value);
|
||||||
|
}
|
||||||
|
else if((it->first == "COMPILATION" || it->first == "SHOWWORKMOVEMENT") && !it->second.isEmpty()) {
|
||||||
|
bool value = (it->second.front().toInt() != 0);
|
||||||
|
d->items[name] = MP4::Item(value);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
d->items[name] = it->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ignoredProps.insert(it->first, it->second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ignoredProps;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MP4::Tag::addItem(const String &name, const Item &value)
|
||||||
|
{
|
||||||
|
if(!d->items.contains(name)) {
|
||||||
|
d->items.insert(name, value);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
debug("MP4: Ignoring duplicate atom \"" + name + "\"");
|
||||||
|
}
|
||||||
|
}
|
||||||
157
3rdparty/taglib/mp4/mp4tag.h
vendored
Normal file
157
3rdparty/taglib/mp4/mp4tag.h
vendored
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
/**************************************************************************
|
||||||
|
copyright : (C) 2007,2011 by Lukáš Lalinský
|
||||||
|
email : lalinsky@gmail.com
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef TAGLIB_MP4TAG_H
|
||||||
|
#define TAGLIB_MP4TAG_H
|
||||||
|
|
||||||
|
#include "tag.h"
|
||||||
|
#include "tbytevectorlist.h"
|
||||||
|
#include "tfile.h"
|
||||||
|
#include "tmap.h"
|
||||||
|
#include "tstringlist.h"
|
||||||
|
#include "taglib_export.h"
|
||||||
|
#include "mp4atom.h"
|
||||||
|
#include "mp4item.h"
|
||||||
|
|
||||||
|
namespace TagLib {
|
||||||
|
|
||||||
|
namespace MP4 {
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \deprecated
|
||||||
|
*/
|
||||||
|
typedef TagLib::Map<String, Item> ItemListMap;
|
||||||
|
typedef TagLib::Map<String, Item> ItemMap;
|
||||||
|
|
||||||
|
class TAGLIB_EXPORT Tag: public TagLib::Tag
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Tag();
|
||||||
|
Tag(TagLib::File *file, Atoms *atoms);
|
||||||
|
virtual ~Tag();
|
||||||
|
bool save();
|
||||||
|
|
||||||
|
virtual String title() const;
|
||||||
|
virtual String artist() const;
|
||||||
|
virtual String album() const;
|
||||||
|
virtual String comment() const;
|
||||||
|
virtual String genre() const;
|
||||||
|
virtual unsigned int year() const;
|
||||||
|
virtual unsigned int track() const;
|
||||||
|
|
||||||
|
virtual void setTitle(const String &value);
|
||||||
|
virtual void setArtist(const String &value);
|
||||||
|
virtual void setAlbum(const String &value);
|
||||||
|
virtual void setComment(const String &value);
|
||||||
|
virtual void setGenre(const String &value);
|
||||||
|
virtual void setYear(unsigned int value);
|
||||||
|
virtual void setTrack(unsigned int value);
|
||||||
|
|
||||||
|
virtual bool isEmpty() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \deprecated Use the item() and setItem() API instead
|
||||||
|
*/
|
||||||
|
ItemMap &itemListMap();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns a string-keyed map of the MP4::Items for this tag.
|
||||||
|
*/
|
||||||
|
const ItemMap &itemMap() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \return The item, if any, corresponding to \a key.
|
||||||
|
*/
|
||||||
|
Item item(const String &key) const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets the value of \a key to \a value, overwriting any previous value.
|
||||||
|
*/
|
||||||
|
void setItem(const String &key, const Item &value);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Removes the entry with \a key from the tag, or does nothing if it does
|
||||||
|
* not exist.
|
||||||
|
*/
|
||||||
|
void removeItem(const String &key);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \return True if the tag contains an entry for \a key.
|
||||||
|
*/
|
||||||
|
bool contains(const String &key) const;
|
||||||
|
|
||||||
|
PropertyMap properties() const;
|
||||||
|
void removeUnsupportedProperties(const StringList& properties);
|
||||||
|
PropertyMap setProperties(const PropertyMap &properties);
|
||||||
|
|
||||||
|
private:
|
||||||
|
AtomDataList parseData2(const Atom *atom, int expectedFlags = -1,
|
||||||
|
bool freeForm = false);
|
||||||
|
ByteVectorList parseData(const Atom *atom, int expectedFlags = -1,
|
||||||
|
bool freeForm = false);
|
||||||
|
void parseText(const Atom *atom, int expectedFlags = 1);
|
||||||
|
void parseFreeForm(const Atom *atom);
|
||||||
|
void parseInt(const Atom *atom);
|
||||||
|
void parseByte(const Atom *atom);
|
||||||
|
void parseUInt(const Atom *atom);
|
||||||
|
void parseLongLong(const Atom *atom);
|
||||||
|
void parseGnre(const Atom *atom);
|
||||||
|
void parseIntPair(const Atom *atom);
|
||||||
|
void parseBool(const Atom *atom);
|
||||||
|
void parseCovr(const Atom *atom);
|
||||||
|
|
||||||
|
ByteVector padIlst(const ByteVector &data, int length = -1) const;
|
||||||
|
ByteVector renderAtom(const ByteVector &name, const ByteVector &data) const;
|
||||||
|
ByteVector renderData(const ByteVector &name, int flags,
|
||||||
|
const ByteVectorList &data) const;
|
||||||
|
ByteVector renderText(const ByteVector &name, const Item &item,
|
||||||
|
int flags = TypeUTF8) const;
|
||||||
|
ByteVector renderFreeForm(const String &name, const Item &item) const;
|
||||||
|
ByteVector renderBool(const ByteVector &name, const Item &item) const;
|
||||||
|
ByteVector renderInt(const ByteVector &name, const Item &item) const;
|
||||||
|
ByteVector renderByte(const ByteVector &name, const Item &item) const;
|
||||||
|
ByteVector renderUInt(const ByteVector &name, const Item &item) const;
|
||||||
|
ByteVector renderLongLong(const ByteVector &name, const Item &item) const;
|
||||||
|
ByteVector renderIntPair(const ByteVector &name, const Item &item) const;
|
||||||
|
ByteVector renderIntPairNoTrailing(const ByteVector &name, const Item &item) const;
|
||||||
|
ByteVector renderCovr(const ByteVector &name, const Item &item) const;
|
||||||
|
|
||||||
|
void updateParents(const AtomList &path, long delta, int ignore = 0);
|
||||||
|
void updateOffsets(long delta, long offset);
|
||||||
|
|
||||||
|
void saveNew(ByteVector data);
|
||||||
|
void saveExisting(ByteVector data, const AtomList &path);
|
||||||
|
|
||||||
|
void addItem(const String &name, const Item &value);
|
||||||
|
|
||||||
|
class TagPrivate;
|
||||||
|
TagPrivate *d;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
332
3rdparty/taglib/mpc/mpcfile.cpp
vendored
Normal file
332
3rdparty/taglib/mpc/mpcfile.cpp
vendored
Normal file
@@ -0,0 +1,332 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
copyright : (C) 2004 by Allan Sandfeld Jensen
|
||||||
|
email : kde@carewolf.org
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include <tbytevector.h>
|
||||||
|
#include <tstring.h>
|
||||||
|
#include <tagunion.h>
|
||||||
|
#include <tdebug.h>
|
||||||
|
#include <tpropertymap.h>
|
||||||
|
#include <tagutils.h>
|
||||||
|
|
||||||
|
#include "mpcfile.h"
|
||||||
|
#include "id3v1tag.h"
|
||||||
|
#include "id3v2header.h"
|
||||||
|
#include "apetag.h"
|
||||||
|
#include "apefooter.h"
|
||||||
|
|
||||||
|
using namespace TagLib;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
enum { MPCAPEIndex = 0, MPCID3v1Index = 1 };
|
||||||
|
}
|
||||||
|
|
||||||
|
class MPC::File::FilePrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FilePrivate() :
|
||||||
|
APELocation(-1),
|
||||||
|
APESize(0),
|
||||||
|
ID3v1Location(-1),
|
||||||
|
ID3v2Header(0),
|
||||||
|
ID3v2Location(-1),
|
||||||
|
ID3v2Size(0),
|
||||||
|
properties(0) {}
|
||||||
|
|
||||||
|
~FilePrivate()
|
||||||
|
{
|
||||||
|
delete ID3v2Header;
|
||||||
|
delete properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
long APELocation;
|
||||||
|
long APESize;
|
||||||
|
|
||||||
|
long ID3v1Location;
|
||||||
|
|
||||||
|
ID3v2::Header *ID3v2Header;
|
||||||
|
long ID3v2Location;
|
||||||
|
long ID3v2Size;
|
||||||
|
|
||||||
|
TagUnion tag;
|
||||||
|
|
||||||
|
Properties *properties;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// static members
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
bool MPC::File::isSupported(IOStream *stream)
|
||||||
|
{
|
||||||
|
// A newer MPC file has to start with "MPCK" or "MP+", but older files don't
|
||||||
|
// have keys to do a quick check.
|
||||||
|
|
||||||
|
const ByteVector id = Utils::readHeader(stream, 4, false);
|
||||||
|
return (id == "MPCK" || id.startsWith("MP+"));
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// public members
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
MPC::File::File(FileName file, bool readProperties, Properties::ReadStyle) :
|
||||||
|
TagLib::File(file),
|
||||||
|
d(new FilePrivate())
|
||||||
|
{
|
||||||
|
if(isOpen())
|
||||||
|
read(readProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
MPC::File::File(IOStream *stream, bool readProperties, Properties::ReadStyle) :
|
||||||
|
TagLib::File(stream),
|
||||||
|
d(new FilePrivate())
|
||||||
|
{
|
||||||
|
if(isOpen())
|
||||||
|
read(readProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
MPC::File::~File()
|
||||||
|
{
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
TagLib::Tag *MPC::File::tag() const
|
||||||
|
{
|
||||||
|
return &d->tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyMap MPC::File::properties() const
|
||||||
|
{
|
||||||
|
return d->tag.properties();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MPC::File::removeUnsupportedProperties(const StringList &properties)
|
||||||
|
{
|
||||||
|
d->tag.removeUnsupportedProperties(properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyMap MPC::File::setProperties(const PropertyMap &properties)
|
||||||
|
{
|
||||||
|
if(ID3v1Tag())
|
||||||
|
ID3v1Tag()->setProperties(properties);
|
||||||
|
|
||||||
|
return APETag(true)->setProperties(properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
MPC::Properties *MPC::File::audioProperties() const
|
||||||
|
{
|
||||||
|
return d->properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MPC::File::save()
|
||||||
|
{
|
||||||
|
if(readOnly()) {
|
||||||
|
debug("MPC::File::save() -- File is read only.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Possibly strip ID3v2 tag
|
||||||
|
|
||||||
|
if(!d->ID3v2Header && d->ID3v2Location >= 0) {
|
||||||
|
removeBlock(d->ID3v2Location, d->ID3v2Size);
|
||||||
|
|
||||||
|
if(d->APELocation >= 0)
|
||||||
|
d->APELocation -= d->ID3v2Size;
|
||||||
|
|
||||||
|
if(d->ID3v1Location >= 0)
|
||||||
|
d->ID3v1Location -= d->ID3v2Size;
|
||||||
|
|
||||||
|
d->ID3v2Location = -1;
|
||||||
|
d->ID3v2Size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update ID3v1 tag
|
||||||
|
|
||||||
|
if(ID3v1Tag() && !ID3v1Tag()->isEmpty()) {
|
||||||
|
|
||||||
|
// ID3v1 tag is not empty. Update the old one or create a new one.
|
||||||
|
|
||||||
|
if(d->ID3v1Location >= 0) {
|
||||||
|
seek(d->ID3v1Location);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
seek(0, End);
|
||||||
|
d->ID3v1Location = tell();
|
||||||
|
}
|
||||||
|
|
||||||
|
writeBlock(ID3v1Tag()->render());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
// ID3v1 tag is empty. Remove the old one.
|
||||||
|
|
||||||
|
if(d->ID3v1Location >= 0) {
|
||||||
|
truncate(d->ID3v1Location);
|
||||||
|
d->ID3v1Location = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update APE tag
|
||||||
|
|
||||||
|
if(APETag() && !APETag()->isEmpty()) {
|
||||||
|
|
||||||
|
// APE tag is not empty. Update the old one or create a new one.
|
||||||
|
|
||||||
|
if(d->APELocation < 0) {
|
||||||
|
if(d->ID3v1Location >= 0)
|
||||||
|
d->APELocation = d->ID3v1Location;
|
||||||
|
else
|
||||||
|
d->APELocation = length();
|
||||||
|
}
|
||||||
|
|
||||||
|
const ByteVector data = APETag()->render();
|
||||||
|
insert(data, d->APELocation, d->APESize);
|
||||||
|
|
||||||
|
if(d->ID3v1Location >= 0)
|
||||||
|
d->ID3v1Location += (static_cast<long>(data.size()) - d->APESize);
|
||||||
|
|
||||||
|
d->APESize = data.size();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
// APE tag is empty. Remove the old one.
|
||||||
|
|
||||||
|
if(d->APELocation >= 0) {
|
||||||
|
removeBlock(d->APELocation, d->APESize);
|
||||||
|
|
||||||
|
if(d->ID3v1Location >= 0)
|
||||||
|
d->ID3v1Location -= d->APESize;
|
||||||
|
|
||||||
|
d->APELocation = -1;
|
||||||
|
d->APESize = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ID3v1::Tag *MPC::File::ID3v1Tag(bool create)
|
||||||
|
{
|
||||||
|
return d->tag.access<ID3v1::Tag>(MPCID3v1Index, create);
|
||||||
|
}
|
||||||
|
|
||||||
|
APE::Tag *MPC::File::APETag(bool create)
|
||||||
|
{
|
||||||
|
return d->tag.access<APE::Tag>(MPCAPEIndex, create);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MPC::File::strip(int tags)
|
||||||
|
{
|
||||||
|
if(tags & ID3v1)
|
||||||
|
d->tag.set(MPCID3v1Index, 0);
|
||||||
|
|
||||||
|
if(tags & APE)
|
||||||
|
d->tag.set(MPCAPEIndex, 0);
|
||||||
|
|
||||||
|
if(!ID3v1Tag())
|
||||||
|
APETag(true);
|
||||||
|
|
||||||
|
if(tags & ID3v2) {
|
||||||
|
delete d->ID3v2Header;
|
||||||
|
d->ID3v2Header = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MPC::File::remove(int tags)
|
||||||
|
{
|
||||||
|
strip(tags);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MPC::File::hasID3v1Tag() const
|
||||||
|
{
|
||||||
|
return (d->ID3v1Location >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MPC::File::hasAPETag() const
|
||||||
|
{
|
||||||
|
return (d->APELocation >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// private members
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void MPC::File::read(bool readProperties)
|
||||||
|
{
|
||||||
|
// Look for an ID3v2 tag
|
||||||
|
|
||||||
|
d->ID3v2Location = Utils::findID3v2(this);
|
||||||
|
|
||||||
|
if(d->ID3v2Location >= 0) {
|
||||||
|
seek(d->ID3v2Location);
|
||||||
|
d->ID3v2Header = new ID3v2::Header(readBlock(ID3v2::Header::size()));
|
||||||
|
d->ID3v2Size = d->ID3v2Header->completeTagSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look for an ID3v1 tag
|
||||||
|
|
||||||
|
d->ID3v1Location = Utils::findID3v1(this);
|
||||||
|
|
||||||
|
if(d->ID3v1Location >= 0)
|
||||||
|
d->tag.set(MPCID3v1Index, new ID3v1::Tag(this, d->ID3v1Location));
|
||||||
|
|
||||||
|
// Look for an APE tag
|
||||||
|
|
||||||
|
d->APELocation = Utils::findAPE(this, d->ID3v1Location);
|
||||||
|
|
||||||
|
if(d->APELocation >= 0) {
|
||||||
|
d->tag.set(MPCAPEIndex, new APE::Tag(this, d->APELocation));
|
||||||
|
d->APESize = APETag()->footer()->completeTagSize();
|
||||||
|
d->APELocation = d->APELocation + APE::Footer::size() - d->APESize;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(d->ID3v1Location < 0)
|
||||||
|
APETag(true);
|
||||||
|
|
||||||
|
// Look for MPC metadata
|
||||||
|
|
||||||
|
if(readProperties) {
|
||||||
|
|
||||||
|
long streamLength;
|
||||||
|
|
||||||
|
if(d->APELocation >= 0)
|
||||||
|
streamLength = d->APELocation;
|
||||||
|
else if(d->ID3v1Location >= 0)
|
||||||
|
streamLength = d->ID3v1Location;
|
||||||
|
else
|
||||||
|
streamLength = length();
|
||||||
|
|
||||||
|
if(d->ID3v2Location >= 0) {
|
||||||
|
seek(d->ID3v2Location + d->ID3v2Size);
|
||||||
|
streamLength -= (d->ID3v2Location + d->ID3v2Size);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
seek(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
d->properties = new Properties(this, streamLength);
|
||||||
|
}
|
||||||
|
}
|
||||||
238
3rdparty/taglib/mpc/mpcfile.h
vendored
Normal file
238
3rdparty/taglib/mpc/mpcfile.h
vendored
Normal file
@@ -0,0 +1,238 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
copyright : (C) 2004 by Allan Sandfeld Jensen
|
||||||
|
email : kde@carewolf.org
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef TAGLIB_MPCFILE_H
|
||||||
|
#define TAGLIB_MPCFILE_H
|
||||||
|
|
||||||
|
#include "taglib_export.h"
|
||||||
|
#include "tfile.h"
|
||||||
|
#include "tag.h"
|
||||||
|
|
||||||
|
#include "mpcproperties.h"
|
||||||
|
|
||||||
|
#include "tlist.h"
|
||||||
|
|
||||||
|
namespace TagLib {
|
||||||
|
|
||||||
|
class Tag;
|
||||||
|
|
||||||
|
namespace ID3v1 { class Tag; }
|
||||||
|
namespace APE { class Tag; }
|
||||||
|
|
||||||
|
//! An implementation of MPC metadata
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* This is implementation of MPC metadata.
|
||||||
|
*
|
||||||
|
* This supports ID3v1 and APE (v1 and v2) style comments as well as reading stream
|
||||||
|
* properties from the file. ID3v2 tags are invalid in MPC-files, but will be skipped
|
||||||
|
* and ignored.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace MPC {
|
||||||
|
|
||||||
|
//! An implementation of TagLib::File with MPC specific methods
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* This implements and provides an interface for MPC files to the
|
||||||
|
* TagLib::Tag and TagLib::AudioProperties interfaces by way of implementing
|
||||||
|
* the abstract TagLib::File API as well as providing some additional
|
||||||
|
* information specific to MPC files.
|
||||||
|
* The only invalid tag combination supported is an ID3v1 tag after an APE tag.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class TAGLIB_EXPORT File : public TagLib::File
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/*!
|
||||||
|
* This set of flags is used for various operations and is suitable for
|
||||||
|
* being OR-ed together.
|
||||||
|
*/
|
||||||
|
enum TagTypes {
|
||||||
|
//! Empty set. Matches no tag types.
|
||||||
|
NoTags = 0x0000,
|
||||||
|
//! Matches ID3v1 tags.
|
||||||
|
ID3v1 = 0x0001,
|
||||||
|
//! Matches ID3v2 tags.
|
||||||
|
ID3v2 = 0x0002,
|
||||||
|
//! Matches APE tags.
|
||||||
|
APE = 0x0004,
|
||||||
|
//! Matches all tag types.
|
||||||
|
AllTags = 0xffff
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Constructs an MPC file from \a file. If \a readProperties is true the
|
||||||
|
* file's audio properties will also be read.
|
||||||
|
*
|
||||||
|
* \note In the current implementation, \a propertiesStyle is ignored.
|
||||||
|
*/
|
||||||
|
File(FileName file, bool readProperties = true,
|
||||||
|
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Constructs an MPC file from \a stream. If \a readProperties is true the
|
||||||
|
* file's audio properties will also be read.
|
||||||
|
*
|
||||||
|
* \note TagLib will *not* take ownership of the stream, the caller is
|
||||||
|
* responsible for deleting it after the File object.
|
||||||
|
*
|
||||||
|
* \note In the current implementation, \a propertiesStyle is ignored.
|
||||||
|
*/
|
||||||
|
File(IOStream *stream, bool readProperties = true,
|
||||||
|
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Destroys this instance of the File.
|
||||||
|
*/
|
||||||
|
virtual ~File();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the Tag for this file. This will be an APE tag, an ID3v1 tag
|
||||||
|
* or a combination of the two.
|
||||||
|
*/
|
||||||
|
virtual TagLib::Tag *tag() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Implements the unified property interface -- export function.
|
||||||
|
* If the file contains both an APE and an ID3v1 tag, only the APE
|
||||||
|
* tag will be converted to the PropertyMap.
|
||||||
|
*/
|
||||||
|
PropertyMap properties() const;
|
||||||
|
|
||||||
|
void removeUnsupportedProperties(const StringList &properties);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Implements the unified property interface -- import function.
|
||||||
|
* Affects only the APEv2 tag which will be created if necessary.
|
||||||
|
* If an ID3v1 tag exists, it will be updated as well.
|
||||||
|
*/
|
||||||
|
PropertyMap setProperties(const PropertyMap &);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the MPC::Properties for this file. If no audio properties
|
||||||
|
* were read then this will return a null pointer.
|
||||||
|
*/
|
||||||
|
virtual Properties *audioProperties() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Saves the file.
|
||||||
|
*
|
||||||
|
* This returns true if the save was successful.
|
||||||
|
*/
|
||||||
|
virtual bool save();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns a pointer to the ID3v1 tag of the file.
|
||||||
|
*
|
||||||
|
* If \a create is false (the default) this returns a null pointer
|
||||||
|
* if there is no valid APE tag. If \a create is true it will create
|
||||||
|
* an APE tag if one does not exist and returns a valid pointer.
|
||||||
|
*
|
||||||
|
* \note This may return a valid pointer regardless of whether or not the
|
||||||
|
* file on disk has an ID3v1 tag. Use hasID3v1Tag() to check if the file
|
||||||
|
* on disk actually has an ID3v1 tag.
|
||||||
|
*
|
||||||
|
* \note The Tag <b>is still</b> owned by the MPEG::File and should not be
|
||||||
|
* deleted by the user. It will be deleted when the file (object) is
|
||||||
|
* destroyed.
|
||||||
|
*
|
||||||
|
* \see hasID3v1Tag()
|
||||||
|
*/
|
||||||
|
ID3v1::Tag *ID3v1Tag(bool create = false);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns a pointer to the APE tag of the file.
|
||||||
|
*
|
||||||
|
* If \a create is false (the default) this may return a null pointer
|
||||||
|
* if there is no valid APE tag. If \a create is true it will create
|
||||||
|
* an APE tag if one does not exist and returns a valid pointer. If
|
||||||
|
* there already be an ID3v1 tag, the new APE tag will be placed before it.
|
||||||
|
*
|
||||||
|
* \note This may return a valid pointer regardless of whether or not the
|
||||||
|
* file on disk has an APE tag. Use hasAPETag() to check if the file
|
||||||
|
* on disk actually has an APE tag.
|
||||||
|
*
|
||||||
|
* \note The Tag <b>is still</b> owned by the MPEG::File and should not be
|
||||||
|
* deleted by the user. It will be deleted when the file (object) is
|
||||||
|
* destroyed.
|
||||||
|
*
|
||||||
|
* \see hasAPETag()
|
||||||
|
*/
|
||||||
|
APE::Tag *APETag(bool create = false);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* This will remove the tags that match the OR-ed together TagTypes from the
|
||||||
|
* file. By default it removes all tags.
|
||||||
|
*
|
||||||
|
* \warning This will also invalidate pointers to the tags
|
||||||
|
* as their memory will be freed.
|
||||||
|
*
|
||||||
|
* \note In order to make the removal permanent save() still needs to be called.
|
||||||
|
*/
|
||||||
|
void strip(int tags = AllTags);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \deprecated
|
||||||
|
* \see strip
|
||||||
|
*/
|
||||||
|
void remove(int tags = AllTags);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns whether or not the file on disk actually has an ID3v1 tag.
|
||||||
|
*
|
||||||
|
* \see ID3v1Tag()
|
||||||
|
*/
|
||||||
|
bool hasID3v1Tag() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns whether or not the file on disk actually has an APE tag.
|
||||||
|
*
|
||||||
|
* \see APETag()
|
||||||
|
*/
|
||||||
|
bool hasAPETag() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns whether or not the given \a stream can be opened as an MPC
|
||||||
|
* file.
|
||||||
|
*
|
||||||
|
* \note This method is designed to do a quick check. The result may
|
||||||
|
* not necessarily be correct.
|
||||||
|
*/
|
||||||
|
static bool isSupported(IOStream *stream);
|
||||||
|
|
||||||
|
private:
|
||||||
|
File(const File &);
|
||||||
|
File &operator=(const File &);
|
||||||
|
|
||||||
|
void read(bool readProperties);
|
||||||
|
|
||||||
|
class FilePrivate;
|
||||||
|
FilePrivate *d;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
369
3rdparty/taglib/mpc/mpcproperties.cpp
vendored
Normal file
369
3rdparty/taglib/mpc/mpcproperties.cpp
vendored
Normal file
@@ -0,0 +1,369 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
copyright : (C) 2004 by Allan Sandfeld Jensen
|
||||||
|
email : kde@carewolf.org
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include <tstring.h>
|
||||||
|
#include <tdebug.h>
|
||||||
|
#include <bitset>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#include "mpcproperties.h"
|
||||||
|
#include "mpcfile.h"
|
||||||
|
|
||||||
|
using namespace TagLib;
|
||||||
|
|
||||||
|
class MPC::Properties::PropertiesPrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PropertiesPrivate() :
|
||||||
|
version(0),
|
||||||
|
length(0),
|
||||||
|
bitrate(0),
|
||||||
|
sampleRate(0),
|
||||||
|
channels(0),
|
||||||
|
totalFrames(0),
|
||||||
|
sampleFrames(0),
|
||||||
|
trackGain(0),
|
||||||
|
trackPeak(0),
|
||||||
|
albumGain(0),
|
||||||
|
albumPeak(0) {}
|
||||||
|
|
||||||
|
int version;
|
||||||
|
int length;
|
||||||
|
int bitrate;
|
||||||
|
int sampleRate;
|
||||||
|
int channels;
|
||||||
|
unsigned int totalFrames;
|
||||||
|
unsigned int sampleFrames;
|
||||||
|
unsigned int trackGain;
|
||||||
|
unsigned int trackPeak;
|
||||||
|
unsigned int albumGain;
|
||||||
|
unsigned int albumPeak;
|
||||||
|
String flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// public members
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
MPC::Properties::Properties(const ByteVector &data, long streamLength, ReadStyle style) :
|
||||||
|
AudioProperties(style),
|
||||||
|
d(new PropertiesPrivate())
|
||||||
|
{
|
||||||
|
readSV7(data, streamLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
MPC::Properties::Properties(File *file, long streamLength, ReadStyle style) :
|
||||||
|
AudioProperties(style),
|
||||||
|
d(new PropertiesPrivate())
|
||||||
|
{
|
||||||
|
ByteVector magic = file->readBlock(4);
|
||||||
|
if(magic == "MPCK") {
|
||||||
|
// Musepack version 8
|
||||||
|
readSV8(file, streamLength);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Musepack version 7 or older, fixed size header
|
||||||
|
readSV7(magic + file->readBlock(MPC::HeaderSize - 4), streamLength);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MPC::Properties::~Properties()
|
||||||
|
{
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
int MPC::Properties::length() const
|
||||||
|
{
|
||||||
|
return lengthInSeconds();
|
||||||
|
}
|
||||||
|
|
||||||
|
int MPC::Properties::lengthInSeconds() const
|
||||||
|
{
|
||||||
|
return d->length / 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
int MPC::Properties::lengthInMilliseconds() const
|
||||||
|
{
|
||||||
|
return d->length;
|
||||||
|
}
|
||||||
|
|
||||||
|
int MPC::Properties::bitrate() const
|
||||||
|
{
|
||||||
|
return d->bitrate;
|
||||||
|
}
|
||||||
|
|
||||||
|
int MPC::Properties::sampleRate() const
|
||||||
|
{
|
||||||
|
return d->sampleRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
int MPC::Properties::channels() const
|
||||||
|
{
|
||||||
|
return d->channels;
|
||||||
|
}
|
||||||
|
|
||||||
|
int MPC::Properties::mpcVersion() const
|
||||||
|
{
|
||||||
|
return d->version;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int MPC::Properties::totalFrames() const
|
||||||
|
{
|
||||||
|
return d->totalFrames;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int MPC::Properties::sampleFrames() const
|
||||||
|
{
|
||||||
|
return d->sampleFrames;
|
||||||
|
}
|
||||||
|
|
||||||
|
int MPC::Properties::trackGain() const
|
||||||
|
{
|
||||||
|
return d->trackGain;
|
||||||
|
}
|
||||||
|
|
||||||
|
int MPC::Properties::trackPeak() const
|
||||||
|
{
|
||||||
|
return d->trackPeak;
|
||||||
|
}
|
||||||
|
|
||||||
|
int MPC::Properties::albumGain() const
|
||||||
|
{
|
||||||
|
return d->albumGain;
|
||||||
|
}
|
||||||
|
|
||||||
|
int MPC::Properties::albumPeak() const
|
||||||
|
{
|
||||||
|
return d->albumPeak;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// private members
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
unsigned long readSize(File *file, unsigned int &sizeLength, bool &eof)
|
||||||
|
{
|
||||||
|
sizeLength = 0;
|
||||||
|
eof = false;
|
||||||
|
|
||||||
|
unsigned char tmp;
|
||||||
|
unsigned long size = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
const ByteVector b = file->readBlock(1);
|
||||||
|
if(b.isEmpty()) {
|
||||||
|
eof = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp = b[0];
|
||||||
|
size = (size << 7) | (tmp & 0x7F);
|
||||||
|
sizeLength++;
|
||||||
|
} while((tmp & 0x80));
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long readSize(const ByteVector &data, unsigned int &pos)
|
||||||
|
{
|
||||||
|
unsigned char tmp;
|
||||||
|
unsigned long size = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
tmp = data[pos++];
|
||||||
|
size = (size << 7) | (tmp & 0x7F);
|
||||||
|
} while((tmp & 0x80) && (pos < data.size()));
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This array looks weird, but the same as original MusePack code found at:
|
||||||
|
// https://www.musepack.net/index.php?pg=src
|
||||||
|
const unsigned short sftable [8] = { 44100, 48000, 37800, 32000, 0, 0, 0, 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
void MPC::Properties::readSV8(File *file, long streamLength)
|
||||||
|
{
|
||||||
|
bool readSH = false, readRG = false;
|
||||||
|
|
||||||
|
while(!readSH && !readRG) {
|
||||||
|
const ByteVector packetType = file->readBlock(2);
|
||||||
|
|
||||||
|
unsigned int packetSizeLength;
|
||||||
|
bool eof;
|
||||||
|
const unsigned long packetSize = readSize(file, packetSizeLength, eof);
|
||||||
|
if(eof) {
|
||||||
|
debug("MPC::Properties::readSV8() - Reached to EOF.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const unsigned long dataSize = packetSize - 2 - packetSizeLength;
|
||||||
|
|
||||||
|
const ByteVector data = file->readBlock(dataSize);
|
||||||
|
if(data.size() != dataSize) {
|
||||||
|
debug("MPC::Properties::readSV8() - dataSize doesn't match the actual data size.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(packetType == "SH") {
|
||||||
|
// Stream Header
|
||||||
|
// http://trac.musepack.net/wiki/SV8Specification#StreamHeaderPacket
|
||||||
|
|
||||||
|
if(dataSize <= 5) {
|
||||||
|
debug("MPC::Properties::readSV8() - \"SH\" packet is too short to parse.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
readSH = true;
|
||||||
|
|
||||||
|
unsigned int pos = 4;
|
||||||
|
d->version = data[pos];
|
||||||
|
pos += 1;
|
||||||
|
d->sampleFrames = readSize(data, pos);
|
||||||
|
if(pos > dataSize - 3) {
|
||||||
|
debug("MPC::Properties::readSV8() - \"SH\" packet is corrupt.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const unsigned long begSilence = readSize(data, pos);
|
||||||
|
if(pos > dataSize - 2) {
|
||||||
|
debug("MPC::Properties::readSV8() - \"SH\" packet is corrupt.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const unsigned short flags = data.toUShort(pos, true);
|
||||||
|
pos += 2;
|
||||||
|
|
||||||
|
d->sampleRate = sftable[(flags >> 13) & 0x07];
|
||||||
|
d->channels = ((flags >> 4) & 0x0F) + 1;
|
||||||
|
|
||||||
|
const unsigned int frameCount = d->sampleFrames - begSilence;
|
||||||
|
if(frameCount > 0 && d->sampleRate > 0) {
|
||||||
|
const double length = frameCount * 1000.0 / d->sampleRate;
|
||||||
|
d->length = static_cast<int>(length + 0.5);
|
||||||
|
d->bitrate = static_cast<int>(streamLength * 8.0 / length + 0.5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (packetType == "RG") {
|
||||||
|
// Replay Gain
|
||||||
|
// http://trac.musepack.net/wiki/SV8Specification#ReplaygainPacket
|
||||||
|
|
||||||
|
if(dataSize <= 9) {
|
||||||
|
debug("MPC::Properties::readSV8() - \"RG\" packet is too short to parse.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
readRG = true;
|
||||||
|
|
||||||
|
const int replayGainVersion = data[0];
|
||||||
|
if(replayGainVersion == 1) {
|
||||||
|
d->trackGain = data.toShort(1, true);
|
||||||
|
d->trackPeak = data.toShort(3, true);
|
||||||
|
d->albumGain = data.toShort(5, true);
|
||||||
|
d->albumPeak = data.toShort(7, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if(packetType == "SE") {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
file->seek(dataSize, File::Current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MPC::Properties::readSV7(const ByteVector &data, long streamLength)
|
||||||
|
{
|
||||||
|
if(data.startsWith("MP+")) {
|
||||||
|
d->version = data[3] & 15;
|
||||||
|
if(d->version < 7)
|
||||||
|
return;
|
||||||
|
|
||||||
|
d->totalFrames = data.toUInt(4, false);
|
||||||
|
|
||||||
|
const unsigned int flags = data.toUInt(8, false);
|
||||||
|
d->sampleRate = sftable[(flags >> 16) & 0x03];
|
||||||
|
d->channels = 2;
|
||||||
|
|
||||||
|
const unsigned int gapless = data.toUInt(5, false);
|
||||||
|
|
||||||
|
d->trackGain = data.toShort(14, false);
|
||||||
|
d->trackPeak = data.toShort(12, false);
|
||||||
|
d->albumGain = data.toShort(18, false);
|
||||||
|
d->albumPeak = data.toShort(16, false);
|
||||||
|
|
||||||
|
// convert gain info
|
||||||
|
if(d->trackGain != 0) {
|
||||||
|
int tmp = (int)((64.82 - (short)d->trackGain / 100.) * 256. + .5);
|
||||||
|
if(tmp >= (1 << 16) || tmp < 0) tmp = 0;
|
||||||
|
d->trackGain = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(d->albumGain != 0) {
|
||||||
|
int tmp = (int)((64.82 - d->albumGain / 100.) * 256. + .5);
|
||||||
|
if(tmp >= (1 << 16) || tmp < 0) tmp = 0;
|
||||||
|
d->albumGain = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d->trackPeak != 0)
|
||||||
|
d->trackPeak = (int)(log10((double)d->trackPeak) * 20 * 256 + .5);
|
||||||
|
|
||||||
|
if (d->albumPeak != 0)
|
||||||
|
d->albumPeak = (int)(log10((double)d->albumPeak) * 20 * 256 + .5);
|
||||||
|
|
||||||
|
bool trueGapless = (gapless >> 31) & 0x0001;
|
||||||
|
if(trueGapless) {
|
||||||
|
unsigned int lastFrameSamples = (gapless >> 20) & 0x07FF;
|
||||||
|
d->sampleFrames = d->totalFrames * 1152 - lastFrameSamples;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
d->sampleFrames = d->totalFrames * 1152 - 576;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const unsigned int headerData = data.toUInt(0, false);
|
||||||
|
|
||||||
|
d->bitrate = (headerData >> 23) & 0x01ff;
|
||||||
|
d->version = (headerData >> 11) & 0x03ff;
|
||||||
|
d->sampleRate = 44100;
|
||||||
|
d->channels = 2;
|
||||||
|
|
||||||
|
if(d->version >= 5)
|
||||||
|
d->totalFrames = data.toUInt(4, false);
|
||||||
|
else
|
||||||
|
d->totalFrames = data.toUShort(6, false);
|
||||||
|
|
||||||
|
d->sampleFrames = d->totalFrames * 1152 - 576;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(d->sampleFrames > 0 && d->sampleRate > 0) {
|
||||||
|
const double length = d->sampleFrames * 1000.0 / d->sampleRate;
|
||||||
|
d->length = static_cast<int>(length + 0.5);
|
||||||
|
|
||||||
|
if(d->bitrate == 0)
|
||||||
|
d->bitrate = static_cast<int>(streamLength * 8.0 / length + 0.5);
|
||||||
|
}
|
||||||
|
}
|
||||||
158
3rdparty/taglib/mpc/mpcproperties.h
vendored
Normal file
158
3rdparty/taglib/mpc/mpcproperties.h
vendored
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
copyright : (C) 2004 by Allan Sandfeld Jensen
|
||||||
|
email : kde@carewolf.org
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef TAGLIB_MPCPROPERTIES_H
|
||||||
|
#define TAGLIB_MPCPROPERTIES_H
|
||||||
|
|
||||||
|
#include "taglib_export.h"
|
||||||
|
#include "audioproperties.h"
|
||||||
|
|
||||||
|
namespace TagLib {
|
||||||
|
|
||||||
|
namespace MPC {
|
||||||
|
|
||||||
|
class File;
|
||||||
|
|
||||||
|
static const unsigned int HeaderSize = 8 * 7;
|
||||||
|
|
||||||
|
//! An implementation of audio property reading for MPC
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* This reads the data from an MPC stream found in the AudioProperties
|
||||||
|
* API.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class TAGLIB_EXPORT Properties : public AudioProperties
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/*!
|
||||||
|
* Create an instance of MPC::Properties with the data read from the
|
||||||
|
* ByteVector \a data.
|
||||||
|
*
|
||||||
|
* This constructor is deprecated. It only works for MPC version up to 7.
|
||||||
|
*/
|
||||||
|
Properties(const ByteVector &data, long streamLength, ReadStyle style = Average);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Create an instance of MPC::Properties with the data read directly
|
||||||
|
* from a MPC::File.
|
||||||
|
*/
|
||||||
|
Properties(File *file, long streamLength, ReadStyle style = Average);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Destroys this MPC::Properties instance.
|
||||||
|
*/
|
||||||
|
virtual ~Properties();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the length of the file in seconds. The length is rounded down to
|
||||||
|
* the nearest whole second.
|
||||||
|
*
|
||||||
|
* \note This method is just an alias of lengthInSeconds().
|
||||||
|
*
|
||||||
|
* \deprecated
|
||||||
|
*/
|
||||||
|
virtual int length() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the length of the file in seconds. The length is rounded down to
|
||||||
|
* the nearest whole second.
|
||||||
|
*
|
||||||
|
* \see lengthInMilliseconds()
|
||||||
|
*/
|
||||||
|
// BIC: make virtual
|
||||||
|
int lengthInSeconds() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the length of the file in milliseconds.
|
||||||
|
*
|
||||||
|
* \see lengthInSeconds()
|
||||||
|
*/
|
||||||
|
// BIC: make virtual
|
||||||
|
int lengthInMilliseconds() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the average bit rate of the file in kb/s.
|
||||||
|
*/
|
||||||
|
virtual int bitrate() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the sample rate in Hz.
|
||||||
|
*/
|
||||||
|
virtual int sampleRate() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the number of audio channels.
|
||||||
|
*/
|
||||||
|
virtual int channels() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the version of the bitstream (SV4-SV8)
|
||||||
|
*/
|
||||||
|
int mpcVersion() const;
|
||||||
|
|
||||||
|
unsigned int totalFrames() const;
|
||||||
|
unsigned int sampleFrames() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the track gain as an integer value,
|
||||||
|
* to convert to dB: trackGain in dB = 64.82 - (trackGain / 256)
|
||||||
|
*/
|
||||||
|
int trackGain() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the track peak as an integer value,
|
||||||
|
* to convert to dB: trackPeak in dB = trackPeak / 256
|
||||||
|
* to convert to floating [-1..1]: trackPeak = 10^(trackPeak / 256 / 20)/32768
|
||||||
|
*/
|
||||||
|
int trackPeak() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the album gain as an integer value,
|
||||||
|
* to convert to dB: albumGain in dB = 64.82 - (albumGain / 256)
|
||||||
|
*/
|
||||||
|
int albumGain() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the album peak as an integer value,
|
||||||
|
* to convert to dB: albumPeak in dB = albumPeak / 256
|
||||||
|
* to convert to floating [-1..1]: albumPeak = 10^(albumPeak / 256 / 20)/32768
|
||||||
|
*/
|
||||||
|
int albumPeak() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Properties(const Properties &);
|
||||||
|
Properties &operator=(const Properties &);
|
||||||
|
|
||||||
|
void readSV7(const ByteVector &data, long streamLength);
|
||||||
|
void readSV8(File *file, long streamLength);
|
||||||
|
|
||||||
|
class PropertiesPrivate;
|
||||||
|
PropertiesPrivate *d;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
265
3rdparty/taglib/mpeg/id3v1/id3v1genres.cpp
vendored
Normal file
265
3rdparty/taglib/mpeg/id3v1/id3v1genres.cpp
vendored
Normal file
@@ -0,0 +1,265 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||||
|
email : wheeler@kde.org
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This library is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU Lesser General Public License version *
|
||||||
|
* 2.1 as published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU Lesser General Public *
|
||||||
|
* License along with this library; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||||
|
* 02110-1301 USA *
|
||||||
|
* *
|
||||||
|
* Alternatively, this file is available under the Mozilla Public *
|
||||||
|
* License Version 1.1. You may obtain a copy of the License at *
|
||||||
|
* http://www.mozilla.org/MPL/ *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include "id3v1genres.h"
|
||||||
|
|
||||||
|
using namespace TagLib;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
const wchar_t *genres[] = {
|
||||||
|
L"Blues",
|
||||||
|
L"Classic Rock",
|
||||||
|
L"Country",
|
||||||
|
L"Dance",
|
||||||
|
L"Disco",
|
||||||
|
L"Funk",
|
||||||
|
L"Grunge",
|
||||||
|
L"Hip-Hop",
|
||||||
|
L"Jazz",
|
||||||
|
L"Metal",
|
||||||
|
L"New Age",
|
||||||
|
L"Oldies",
|
||||||
|
L"Other",
|
||||||
|
L"Pop",
|
||||||
|
L"R&B",
|
||||||
|
L"Rap",
|
||||||
|
L"Reggae",
|
||||||
|
L"Rock",
|
||||||
|
L"Techno",
|
||||||
|
L"Industrial",
|
||||||
|
L"Alternative",
|
||||||
|
L"Ska",
|
||||||
|
L"Death Metal",
|
||||||
|
L"Pranks",
|
||||||
|
L"Soundtrack",
|
||||||
|
L"Euro-Techno",
|
||||||
|
L"Ambient",
|
||||||
|
L"Trip-Hop",
|
||||||
|
L"Vocal",
|
||||||
|
L"Jazz+Funk",
|
||||||
|
L"Fusion",
|
||||||
|
L"Trance",
|
||||||
|
L"Classical",
|
||||||
|
L"Instrumental",
|
||||||
|
L"Acid",
|
||||||
|
L"House",
|
||||||
|
L"Game",
|
||||||
|
L"Sound Clip",
|
||||||
|
L"Gospel",
|
||||||
|
L"Noise",
|
||||||
|
L"Alternative Rock",
|
||||||
|
L"Bass",
|
||||||
|
L"Soul",
|
||||||
|
L"Punk",
|
||||||
|
L"Space",
|
||||||
|
L"Meditative",
|
||||||
|
L"Instrumental Pop",
|
||||||
|
L"Instrumental Rock",
|
||||||
|
L"Ethnic",
|
||||||
|
L"Gothic",
|
||||||
|
L"Darkwave",
|
||||||
|
L"Techno-Industrial",
|
||||||
|
L"Electronic",
|
||||||
|
L"Pop-Folk",
|
||||||
|
L"Eurodance",
|
||||||
|
L"Dream",
|
||||||
|
L"Southern Rock",
|
||||||
|
L"Comedy",
|
||||||
|
L"Cult",
|
||||||
|
L"Gangsta",
|
||||||
|
L"Top 40",
|
||||||
|
L"Christian Rap",
|
||||||
|
L"Pop/Funk",
|
||||||
|
L"Jungle",
|
||||||
|
L"Native American",
|
||||||
|
L"Cabaret",
|
||||||
|
L"New Wave",
|
||||||
|
L"Psychedelic",
|
||||||
|
L"Rave",
|
||||||
|
L"Showtunes",
|
||||||
|
L"Trailer",
|
||||||
|
L"Lo-Fi",
|
||||||
|
L"Tribal",
|
||||||
|
L"Acid Punk",
|
||||||
|
L"Acid Jazz",
|
||||||
|
L"Polka",
|
||||||
|
L"Retro",
|
||||||
|
L"Musical",
|
||||||
|
L"Rock & Roll",
|
||||||
|
L"Hard Rock",
|
||||||
|
L"Folk",
|
||||||
|
L"Folk/Rock",
|
||||||
|
L"National Folk",
|
||||||
|
L"Swing",
|
||||||
|
L"Fusion",
|
||||||
|
L"Bebob",
|
||||||
|
L"Latin",
|
||||||
|
L"Revival",
|
||||||
|
L"Celtic",
|
||||||
|
L"Bluegrass",
|
||||||
|
L"Avantgarde",
|
||||||
|
L"Gothic Rock",
|
||||||
|
L"Progressive Rock",
|
||||||
|
L"Psychedelic Rock",
|
||||||
|
L"Symphonic Rock",
|
||||||
|
L"Slow Rock",
|
||||||
|
L"Big Band",
|
||||||
|
L"Chorus",
|
||||||
|
L"Easy Listening",
|
||||||
|
L"Acoustic",
|
||||||
|
L"Humour",
|
||||||
|
L"Speech",
|
||||||
|
L"Chanson",
|
||||||
|
L"Opera",
|
||||||
|
L"Chamber Music",
|
||||||
|
L"Sonata",
|
||||||
|
L"Symphony",
|
||||||
|
L"Booty Bass",
|
||||||
|
L"Primus",
|
||||||
|
L"Porn Groove",
|
||||||
|
L"Satire",
|
||||||
|
L"Slow Jam",
|
||||||
|
L"Club",
|
||||||
|
L"Tango",
|
||||||
|
L"Samba",
|
||||||
|
L"Folklore",
|
||||||
|
L"Ballad",
|
||||||
|
L"Power Ballad",
|
||||||
|
L"Rhythmic Soul",
|
||||||
|
L"Freestyle",
|
||||||
|
L"Duet",
|
||||||
|
L"Punk Rock",
|
||||||
|
L"Drum Solo",
|
||||||
|
L"A Cappella",
|
||||||
|
L"Euro-House",
|
||||||
|
L"Dance Hall",
|
||||||
|
L"Goa",
|
||||||
|
L"Drum & Bass",
|
||||||
|
L"Club-House",
|
||||||
|
L"Hardcore",
|
||||||
|
L"Terror",
|
||||||
|
L"Indie",
|
||||||
|
L"BritPop",
|
||||||
|
L"Negerpunk",
|
||||||
|
L"Polsk Punk",
|
||||||
|
L"Beat",
|
||||||
|
L"Christian Gangsta Rap",
|
||||||
|
L"Heavy Metal",
|
||||||
|
L"Black Metal",
|
||||||
|
L"Crossover",
|
||||||
|
L"Contemporary Christian",
|
||||||
|
L"Christian Rock",
|
||||||
|
L"Merengue",
|
||||||
|
L"Salsa",
|
||||||
|
L"Thrash Metal",
|
||||||
|
L"Anime",
|
||||||
|
L"Jpop",
|
||||||
|
L"Synthpop",
|
||||||
|
L"Abstract",
|
||||||
|
L"Art Rock",
|
||||||
|
L"Baroque",
|
||||||
|
L"Bhangra",
|
||||||
|
L"Big Beat",
|
||||||
|
L"Breakbeat",
|
||||||
|
L"Chillout",
|
||||||
|
L"Downtempo",
|
||||||
|
L"Dub",
|
||||||
|
L"EBM",
|
||||||
|
L"Eclectic",
|
||||||
|
L"Electro",
|
||||||
|
L"Electroclash",
|
||||||
|
L"Emo",
|
||||||
|
L"Experimental",
|
||||||
|
L"Garage",
|
||||||
|
L"Global",
|
||||||
|
L"IDM",
|
||||||
|
L"Illbient",
|
||||||
|
L"Industro-Goth",
|
||||||
|
L"Jam Band",
|
||||||
|
L"Krautrock",
|
||||||
|
L"Leftfield",
|
||||||
|
L"Lounge",
|
||||||
|
L"Math Rock",
|
||||||
|
L"New Romantic",
|
||||||
|
L"Nu-Breakz",
|
||||||
|
L"Post-Punk",
|
||||||
|
L"Post-Rock",
|
||||||
|
L"Psytrance",
|
||||||
|
L"Shoegaze",
|
||||||
|
L"Space Rock",
|
||||||
|
L"Trop Rock",
|
||||||
|
L"World Music",
|
||||||
|
L"Neoclassical",
|
||||||
|
L"Audiobook",
|
||||||
|
L"Audio Theatre",
|
||||||
|
L"Neue Deutsche Welle",
|
||||||
|
L"Podcast",
|
||||||
|
L"Indie Rock",
|
||||||
|
L"G-Funk",
|
||||||
|
L"Dubstep",
|
||||||
|
L"Garage Rock",
|
||||||
|
L"Psybient"
|
||||||
|
};
|
||||||
|
const int genresSize = sizeof(genres) / sizeof(genres[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
StringList ID3v1::genreList()
|
||||||
|
{
|
||||||
|
StringList l;
|
||||||
|
for(int i = 0; i < genresSize; i++) {
|
||||||
|
l.append(genres[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
ID3v1::GenreMap ID3v1::genreMap()
|
||||||
|
{
|
||||||
|
GenreMap m;
|
||||||
|
for(int i = 0; i < genresSize; i++) {
|
||||||
|
m.insert(genres[i], i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
String ID3v1::genre(int i)
|
||||||
|
{
|
||||||
|
if(i >= 0 && i < genresSize)
|
||||||
|
return String(genres[i]); // always make a copy
|
||||||
|
else
|
||||||
|
return String();
|
||||||
|
}
|
||||||
|
|
||||||
|
int ID3v1::genreIndex(const String &name)
|
||||||
|
{
|
||||||
|
for(int i = 0; i < genresSize; ++i) {
|
||||||
|
if(name == genres[i])
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 255;
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user