diff --git a/cdatabase.cpp b/cdatabase.cpp deleted file mode 100644 index c6ab747..0000000 --- a/cdatabase.cpp +++ /dev/null @@ -1,159 +0,0 @@ -#include "cdatabase.h" -#include "common.h" - -#include -#include - - -cDatabase::cDatabase(QObject *parent) : - QObject(parent), m_iVersion(-1) -{ - init(); -} - -cDatabase::~cDatabase() -{ - if(m_DB.isOpen()) - m_DB.close(); -} - -QSqlDatabase cDatabase::getDB() -{ - return(m_DB); -} - -void cDatabase::init() -{ - QDir d; - QString szDB; - QSettings settings; - - m_DB = QSqlDatabase::addDatabase("QSQLITE"); - szDB = settings.value("application/data").toString()+QDir::separator()+settings.value("database/database").toString(); - m_DB.setDatabaseName(szDB); - m_DB.open(); - - initDB(); - QSqlQuery version("SELECT version FROM version", m_DB); - if(!version.exec()) - return; - else - { - version.first(); - m_iVersion = version.value("version").toInt(); - } -} - -int cDatabase::initDB() -{ - QSqlQuery query(m_DB); - - if(!m_DB.tables().contains("version")) - { - if(!query.exec("CREATE TABLE version\n" - "(version integer)")) - { - myDebug << query.lastError().text(); - return(0); - } - - if(!query.exec("INSERT INTO version (version) VALUES (1)")) - { - myDebug << query.lastError().text(); - return(0); - } - } - - if(!m_DB.tables().contains("file")) - { - if(!query.exec("CREATE TABLE file " - "(id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, " - " fileName TEXT, " - " fileSize INTEGER, " - " fileDate DATE, " - " fileType1 INTEGER, " - " fileType TEXT, " - " length1 INTEGER, " - " length INTEGER, " - " bitrate INTEGER, " - " sampleRate INTEGER, " - " channels INTEGER, " - " bitsPerSample INTEGER, " - " layer INTEGER, " - " version INTEGER, " - " sampleWidth INTEGER, " - " sampleFrames INTEGER, " - " isEncrypted BOOL, " - " trackGain INTEGER, " - " albumGain INTEGER, " - " trackPeak INTEGER, " - " albumPeak INTEGER, " - " protectionEnabled BOOL, " - " channelMode INTEGER, " - " isCopyrighted BOOL, " - " isOriginal BOOL, " - " album TEXT, " - " title TEXT, " - " copyright TEXT, " - " tracknumber TEXT, " - " contentGroupDescription TEXT, " - " subTitle TEXT, " - " originalAlbum TEXT, " - " partOfSet TEXT, " - " subTitleOfSet TEXT, " - " internationalStandardRecordingCode TEXT, " - " leadArtist TEXT, " - " band TEXT, " - " conductor TEXT, " - " interpret TEXT, " - " originalArtist TEXT, " - " textWriter TEXT, " - " originalTextWriter TEXT, " - " composer TEXT, " - " encodedBy TEXT, " - " beatsPerMinute INTEGER, " - " language TEXT, " - " contentType TEXT, " - " mediaType TEXT, " - " mood TEXT, " - " producedNotice TEXT, " - " publisher TEXT, " - " fileOwner TEXT, " - " internetRadioStationName TEXT, " - " internetRadioStationOwner TEXT, " - " originalFilename TEXT, " - " playlistDelay TEXT, " - " encodingTime INTEGER, " - " originalReleaseTime DATE, " - " recordingTime DATE, " - " releaseTime DATE, " - " taggingTime DATE, " - " swhwSettings TEXT, " - " albumSortOrder TEXT, " - " performerSortOrder TEXT, " - " titleSortOrder TEXT, " - " synchronizedLyrics TEXT, " - " unsynchronizedLyrics TEXT)")) - { - myDebug << query.lastError().text(); - return(0); - } - } - - if(!m_DB.tables().contains("image")) - { - if(!query.exec("CREATE TABLE image (" - " id INTEGER PRIMARY KEY," - " fileID INTEGER REFERENCES file(id)," - " fileName STRING," - " imageType INTEGER," - " description STRING," - " image BLOB);")) - { - myDebug << query.lastError().text(); - return(0); - } - } - - return(1); -} diff --git a/cdatabase.h b/cdatabase.h deleted file mode 100644 index 3880511..0000000 --- a/cdatabase.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef CDATABASE_H -#define CDATABASE_H - -#include -#include -#include -#include -#include - - -class cDatabase : public QObject -{ - Q_OBJECT -public: - explicit cDatabase(QObject *parent = 0); - ~cDatabase(); - - QSqlDatabase getDB(); -signals: - -public slots: - -protected: - QSqlDatabase m_DB; - qint16 m_iVersion; - - void init(); - int initDB(); -}; - -#endif // CDATABASE_H diff --git a/cid3field.cpp b/cid3field.cpp new file mode 100644 index 0000000..b95a95a --- /dev/null +++ b/cid3field.cpp @@ -0,0 +1,168 @@ +#include "cid3field.h" + + +cID3Field::cID3Field(uint16_t dwID, const QString& szShortName, const QString& szName) : + m_dwID(dwID), + m_szShortName(szShortName), + m_szName(szName), + m_bValid(false) +{ +} + +cID3Field::~cID3Field() +{ + if(m_Value.canConvert()) + { + cPictureList* lpPictureList = m_Value.value(); + delete lpPictureList; + } +} + +uint16_t cID3Field::getID() +{ + return(m_dwID); +} + +void cID3Field::setShortName(const QString& szShortName) +{ + m_bValid = false; + + if(szShortName.length()) + { + m_szShortName = szShortName; + if(m_Value.isValid() && m_szName.length()) + m_bValid = true; + } +} + +QString cID3Field::getShortName() +{ + return(m_szShortName); +} + +void cID3Field::setName(const QString& szName) +{ + m_bValid = false; + + if(szName.length()) + { + m_szName = szName; + if(m_Value.isValid() && m_szShortName.length()) + m_bValid = true; + } +} + +QString cID3Field::getName() +{ + return(m_szName); +} + +void cID3Field::setValue(const QVariant& Value) +{ + m_bValid = false; + if(!Value.isValid()) + return; + m_Value = Value; + if(m_szName.length() && m_szShortName.length()) + m_bValid = true; +} + +QVariant cID3Field::getValue() +{ + if(m_bValid) + return(m_Value); + return(QVariant()); +} + +bool cID3Field::isValid() +{ + return(m_bValid); +} + +cID3Field& cID3Field::operator=(const cID3Field& rhs) +{ + m_dwID = rhs.m_dwID; + m_szName = rhs.m_szName; + m_Value = rhs.m_Value; + m_bValid = rhs.m_bValid; + + return(*this); +} + +cID3FieldList::cID3FieldList() +{ +} + +cID3Field* cID3FieldList::add(uint16_t dwID, const QString& szShortName, const QString& szName, QObject *parent) +{ + cID3Field* lpID3Field = get(dwID); + if(lpID3Field) + return(lpID3Field); + + lpID3Field = new cID3Field(dwID, szShortName, szName); + this->append(lpID3Field); + return(lpID3Field); +} + +cID3Field* cID3FieldList::get(uint16_t dwID) +{ + int iIndex; + + for(iIndex = 0;iIndex < this->count();iIndex++) + { + if(this->at(iIndex)->getID() == dwID) + return(this->at(iIndex)); + } + return(0); +} + +cID3Field* cID3FieldList::get(const QString& szShortName) +{ + int iIndex; + + for(iIndex = 0;iIndex < this->count();iIndex++) + { + if(this->at(iIndex)->getShortName() == szShortName) + return(this->at(iIndex)); + } + return(0); +} + +void cID3FieldList::setValue(uint16_t dwID, const QVariant Value) +{ + cID3Field* lpID3Field = this->get(dwID); + if(lpID3Field) + lpID3Field->setValue(Value); +} + +QVariant cID3FieldList::getValue(uint16_t dwID) +{ + cID3Field* lpID3Field = this->get(dwID); + if(lpID3Field) + return(lpID3Field->getValue()); + return(QVariant()); +} + +QString cID3FieldList::getName(uint16_t dwID) +{ + cID3Field* lpID3Field = this->get(dwID); + if(lpID3Field) + return(lpID3Field->getName()); + return(""); +} + +QString cID3FieldList::getShortName(uint16_t dwID) +{ + cID3Field* lpID3Field = this->get(dwID); + if(lpID3Field) + return(lpID3Field->getShortName()); + return(""); +} + +bool cID3FieldList::isValid(uint16_t dwID) +{ + cID3Field* lpID3Field = this->get(dwID); + if(lpID3Field) + return(lpID3Field->isValid()); + return(false); +} diff --git a/cid3field.h b/cid3field.h new file mode 100644 index 0000000..cffcc12 --- /dev/null +++ b/cid3field.h @@ -0,0 +1,84 @@ +#ifndef cID3Field_H +#define cID3Field_H + +#include +#include +#include +#include + +#include "cpicture.h" + + +class cID3Field : public QObject +{ +public: + enum TAG + { + TAG_AudioEncryption, TAG_AttachedPicture, TAG_AudioSeekPointIndex, TAG_Comments, TAG_CommercialFrame, TAG_EncryptionMethodRegistration, + TAG_Equalisation, TAG_EventTimingCodes, TAG_GeneralEncapsulatedObject, TAG_GroupIdentificationRegistration, TAG_LinkedInformation, TAG_MusicCDIdentifier, + TAG_MPEGLocationLookupTable, TAG_OwnershipFrame, TAG_PrivateFrame, TAG_PlayCounter, TAG_Popularimeter, TAG_PositionSynchronisationFrame, + TAG_RecommendedBufferSize, TAG_RelativeVolumeAdjustment, TAG_Reverb, TAG_SeekFrame, TAG_SignatureFrame, TAG_SynchronisedLyric, + TAG_SynchronisedTempoCodes, TAG_Album, TAG_BeatsPerMinute, TAG_Composer, TAG_ContentType, TAG_CopyrightMessage, + TAG_EncodingTime, TAG_PlaylistDelay, TAG_OriginalReleaseTime, TAG_RecordingTime, TAG_ReleaseTime, TAG_TaggingTime, + TAG_EncodedBy, TAG_Lyricist, TAG_FileType, TAG_InvolvedPeopleList, TAG_ContentGroupDescription, TAG_Title, + TAG_Subtitle, TAG_InitialKey, TAG_Languages, TAG_Length, TAG_MusicianCreditsList, TAG_MediaType, + TAG_Mood, TAG_OriginalAlbum, TAG_OriginalFileName, TAG_OriginalLyricist, TAG_OriginalArtist, TAG_FileOwner, + TAG_LeadPerformer, TAG_Band, TAG_Conductor, TAG_InterpretedBy, TAG_PartOfASet, TAG_ProducedNotice, + TAG_Publisher, TAG_TrackNumber, TAG_InternetRadioStationName, TAG_InternetRadioStationOwner, TAG_AlbumSortOrder, TAG_PerformerSortOrder, + TAG_TitleSortOrder, TAG_InternationalStandardRecordingCode, TAG_Software_Hardware, TAG_SetSubtitle, TAG_UserDefinedTextInformation, TAG_UniqueFileIdentifier, + TAG_TermsOfUse, TAG_UnsynchronizedLyric, TAG_CommercialInformation, TAG_LegalInformation, TAG_OfficialAudioFileWebpage, TAG_OfficialArtistWebpage, + TAG_OfficialAudioSourceWebpage, TAG_OfficialInternetRadioStationWebpage, TAG_Payment, TAG_PublishersOfficialWebpage, TAG_UserDefinedURLLinkFrame, TAG_MAXFIELDS, + }; + + explicit cID3Field(uint16_t dwID = 0, const QString& szShortName = "", const QString& szName = ""); + ~cID3Field(); + + uint16_t getID(); + + void setShortName(const QString& szShortName); + QString getShortName(); + + void setName(const QString& szName); + QString getName(); + + void setValue(const QVariant& Value); + QVariant getValue(); + + bool isValid(); + + cID3Field& operator=(const cID3Field& rhs); + inline bool operator== (const cID3Field& other) const + { + return(m_dwID == other.m_dwID); + } + +private: + uint16_t m_dwID; + QString m_szShortName; + QString m_szName; + QVariant m_Value; + bool m_bValid; +}; + +Q_DECLARE_METATYPE(cID3Field*) + + +class cID3FieldList : public QList +{ +public: + cID3FieldList(); + cID3Field* add(uint16_t dwID, const QString& szShortName, const QString& szName, QObject *parent = 0); + + cID3Field* get(uint16_t dwID); + cID3Field* get(const QString& szShortName); + + void setValue(uint16_t dwID, const QVariant Value); + QVariant getValue(uint16_t dwID); + + QString getName(uint16_t dwID); + QString getShortName(uint16_t dwID); + + bool isValid(uint16_t dwID); +}; + +#endif // cID3Field_H diff --git a/cmainwindow.cpp b/cmainwindow.cpp index 1ab62e1..6b807c1 100644 --- a/cmainwindow.cpp +++ b/cmainwindow.cpp @@ -13,6 +13,10 @@ #include #include +#include + +#include +#include void cMainWindow::addFile(const QString& szFile) @@ -21,13 +25,15 @@ void cMainWindow::addFile(const QString& szFile) return; cMediaInfo* lpMediaInfo = new cMediaInfo; - lpMediaInfo->readFromFile(szFile); + lpMediaInfo->importFromFile(szFile); +/* if(lpMediaInfo->isValid()) { m_lpDB->getDB().transaction(); lpMediaInfo->writeToDB(); m_lpDB->getDB().commit(); } +*/ delete lpMediaInfo; } @@ -57,7 +63,6 @@ void cMainWindow::addPath(const QString& szPath) cMainWindow::cMainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::cMainWindow), - m_lpDB(0), m_lpMusicListModel(0), m_bProcessing(false) { @@ -68,8 +73,6 @@ cMainWindow::cMainWindow(QWidget *parent) : if(settings.value("application/version", QVariant(0.0)).toDouble() == 0.0) initSettings(); - m_lpDB = new cDatabase(this); - m_lpMusicListModel = new QStandardItemModel(0, 3); ui->m_lpMusicListOriginal->setModel(m_lpMusicListModel); ui->m_lpMusicListOriginal->setItemDelegate(new cMusicViewItemDelegate(ui->m_lpMusicListOriginal)); @@ -97,17 +100,26 @@ cMainWindow::cMainWindow(QWidget *parent) : connect(ui->m_lpMusicListOriginal->verticalScrollBar(), &QScrollBar::valueChanged, this, &cMainWindow::onScrollbarValueChangedOriginal); connect(ui->m_lpMusicListNew->verticalScrollBar(), &QScrollBar::valueChanged, this, &cMainWindow::onScrollbarValueChangedNew); + initDB(); loadDB(); displayDB(); +// QTime time; +// time.start(); +// addPath("C:/Users/birkeh/Music"); +// addPath("C:/Users/vet0572/Music"); +// qDebug() << time.elapsed(); // addPath("C:/Users/vet0572/Music"); // addPath("C:/Users/birkeh/Music"); -// addFile("C:/Users/vet0572/Music/Amy MacDonald/Under Stars (Deluxe)/01 - Dream On.mp3"); + addFile("C:/Users/vet0572/Music/Amy MacDonald/Under Stars (Deluxe)/01 - Dream On.mp3"); + addFile("C:/Users/vet0572/Music/Amy MacDonald/Under Stars (Deluxe)/01 - Dream On.mp3"); } cMainWindow::~cMainWindow() { - delete m_lpDB; + if(m_DB.isOpen()) + m_DB.close(); + delete ui; } @@ -124,6 +136,141 @@ void cMainWindow::initSettings() dir.mkdir(settings.value("application/data").toString()); } +bool cMainWindow::initDB() +{ + QDir d; + QString szDB; + QSettings settings; + + m_DB = QSqlDatabase::addDatabase("QSQLITE"); + szDB = settings.value("application/data").toString()+QDir::separator()+settings.value("database/database").toString(); + m_DB.setDatabaseName(szDB); + if(!m_DB.open()) + { + myDebug << m_DB.lastError().text(); + return(false); + } + + QSqlQuery query(m_DB); + + if(!m_DB.tables().contains("version")) + { + if(!query.exec("CREATE TABLE version\n" + "(version integer)")) + { + myDebug << query.lastError().text(); + return(false); + } + + if(!query.exec("INSERT INTO version (version) VALUES (1)")) + { + myDebug << query.lastError().text(); + return(false); + } + } + + if(!m_DB.tables().contains("file")) + { + if(!query.exec("CREATE TABLE file " + "(id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, " + " fileName TEXT, " + " fileSize INTEGER, " + " fileDate DATE, " + " fileType1 INTEGER, " + " fileType TEXT, " + " length1 INTEGER, " + " length INTEGER, " + " bitrate INTEGER, " + " sampleRate INTEGER, " + " channels INTEGER, " + " bitsPerSample INTEGER, " + " layer INTEGER, " + " version INTEGER, " + " sampleWidth INTEGER, " + " sampleFrames INTEGER, " + " isEncrypted BOOL, " + " trackGain INTEGER, " + " albumGain INTEGER, " + " trackPeak INTEGER, " + " albumPeak INTEGER, " + " protectionEnabled BOOL, " + " channelMode INTEGER, " + " isCopyrighted BOOL, " + " isOriginal BOOL, " + " album TEXT, " + " title TEXT, " + " copyright TEXT, " + " tracknumber TEXT, " + " contentGroupDescription TEXT, " + " subTitle TEXT, " + " originalAlbum TEXT, " + " partOfSet TEXT, " + " subTitleOfSet TEXT, " + " internationalStandardRecordingCode TEXT, " + " leadArtist TEXT, " + " band TEXT, " + " conductor TEXT, " + " interpret TEXT, " + " originalArtist TEXT, " + " textWriter TEXT, " + " originalTextWriter TEXT, " + " composer TEXT, " + " encodedBy TEXT, " + " beatsPerMinute INTEGER, " + " language TEXT, " + " contentType TEXT, " + " mediaType TEXT, " + " mood TEXT, " + " producedNotice TEXT, " + " publisher TEXT, " + " fileOwner TEXT, " + " internetRadioStationName TEXT, " + " internetRadioStationOwner TEXT, " + " originalFilename TEXT, " + " playlistDelay TEXT, " + " encodingTime INTEGER, " + " originalReleaseTime DATE, " + " recordingTime DATE, " + " releaseTime DATE, " + " taggingTime DATE, " + " swhwSettings TEXT, " + " albumSortOrder TEXT, " + " performerSortOrder TEXT, " + " titleSortOrder TEXT, " + " synchronizedLyrics TEXT, " + " unsynchronizedLyrics TEXT)")) + { + myDebug << query.lastError().text(); + return(false); + } + } + + if(!m_DB.tables().contains("image")) + { + if(!query.exec("CREATE TABLE image (" + " id INTEGER PRIMARY KEY," + " fileID INTEGER REFERENCES file(id)," + " fileName STRING," + " imageType INTEGER," + " description STRING," + " image BLOB);")) + { + myDebug << query.lastError().text(); + return(false); + } + } + + QSqlQuery version("SELECT version FROM version", m_DB); + if(!version.exec()) + return(false); + else + { + version.first(); + m_iVersion = version.value("version").toInt(); + } + return(true); +} + void cMainWindow::loadDB() { QSqlQuery query; diff --git a/cmainwindow.h b/cmainwindow.h index 1bcecfa..2e387fe 100644 --- a/cmainwindow.h +++ b/cmainwindow.h @@ -2,8 +2,6 @@ #define CMAINWINDOW_H -#include "cdatabase.h" - #include "calbum.h" #include @@ -13,6 +11,8 @@ #include +#include + namespace Ui { @@ -29,7 +29,9 @@ public: private: Ui::cMainWindow* ui; - cDatabase* m_lpDB; + QSqlDatabase m_DB; + qint16 m_iVersion; + QStandardItemModel* m_lpMusicListModel; bool m_bProcessing; @@ -38,6 +40,7 @@ private: void addFile(const QString& szFile); void addPath(const QString& szPath); + bool initDB(); void loadDB(); void displayDB(); diff --git a/cmediainfo.cpp b/cmediainfo.cpp index f8ba38c..ce4b235 100644 --- a/cmediainfo.cpp +++ b/cmediainfo.cpp @@ -1,1292 +1,770 @@ -#include "cmediainfo.h" - -#include "common.h" - +#include #include -#include -#include +#include +#include -#include - -#include -#include -#include -#include - -#include +#include "cmediainfo.h" +#include "fields.h" -cMediaInfo::cMediaInfo(bool bAPE, bool bID3V1, bool bID3V2, bool bProperties, QObject *parent) : - QObject(parent), m_bAPE(bAPE), m_bID3V1(bID3V1), m_bID3V2(bID3V2), m_bProperties(bProperties), m_bIsValid(false), m_fileType(MEDIA_TYPE_UNKNOWN) +//#define SORT_WHOLE_LIST + + +extern "C" { +#include "libmpg123/mpg123.h" +} + + +cMediaInfo::cMediaInfo(QObject *parent) : + QObject(parent), + m_szFileName(""), + m_FileCreated(QDateTime()), + m_FileModified(QDateTime()), + m_dwFileSize(0), + m_dwBitrate(0), + m_dwSamplerate(0), + m_dwChannels(0), + m_dwSeconds(0) { + initFields(); } cMediaInfo::~cMediaInfo() { - clear(); + for(int x = 0;x < m_ID3FieldList.count();x++) + delete (m_ID3FieldList.at(x)); } void cMediaInfo::clear() { - m_szFileName = ""; - m_fileType = MEDIA_TYPE_UNKNOWN; - m_bIsValid = false; - - m_iLength = -1; - m_iBitrate = -1; - m_iSampleRate = -1; - m_iChannels = -1; - m_iBitsPerSample = -1; - m_iLayer = -1; - m_iVersion = -1; - m_iSampleWidth = -1; - m_ullSampleFrames = 0; - m_bIsEncrypted = false; - m_iTrackGain = -1; - m_iAlbumGain = -1; - m_iTrackPeak = -1; - m_iAlbumPeak = -1; - m_bProtectionEnabled = false; - m_channelMode = CHANNEL_MODE_UNKNOWN; - m_bIsCopyrighted = false; - m_bIsOriginal = false; - - m_szContentGroupDescription = ""; - m_szTitle = ""; - m_szSubTitle = ""; - m_szAlbum = ""; - m_szOriginalAlbum = ""; - m_szTrackNumber = ""; - m_szPartOfSet = ""; - m_szSubTitleOfSet = ""; - m_szInternationalStandardRecordingCode = ""; - - m_szContentGroupDescription = ""; - m_szTitle = ""; - m_szSubTitle = ""; - m_szAlbum = ""; - m_szOriginalAlbum = ""; - m_szTrackNumber = ""; - m_szPartOfSet = ""; - m_szSubTitleOfSet = ""; - m_szInternationalStandardRecordingCode = ""; - - m_szLeadArtist = ""; - m_szBand = ""; - m_szConductor = ""; - m_szInterpret.clear(); - m_szOriginalArtist = ""; - m_szTextWriter = ""; - m_szOriginalTextWriter = ""; - m_szComposer = ""; - m_szEncodedBy = ""; - - m_iBeatsPerMinute = -1; - m_szLanguage.clear(); - m_szContentType.clear(); - m_szFileType = ""; - m_szMediaType.clear(); - m_szMood = ""; - - m_szCopyright = ""; - m_szProducedNotice = ""; - m_szPublisher = ""; - m_szFileOwner = ""; - m_szInternetRadioStationName = ""; - m_szInternetRadioStationOwner = ""; - - m_szOriginalFilename = ""; - m_iPlaylistDelay = -1; - m_szswhwSettings.clear(); - m_szAlbumSortOrder = ""; - m_szPerformerSortOrder = ""; - m_szTitleSortOrder = ""; - - m_szSynchronizedLyrics.clear(); - m_szSynchronizedLyricsLanguage = ""; - m_szSynchronizedLyricsDescription = ""; - - m_szUnsynchronizedLyrics.clear(); - m_szUnsynchronizedLyricsLanguage = ""; - m_szUnsynchronizedLyricsDescription = ""; - - m_szAlbum = ""; - m_szArtistList.clear(); - m_szAlbumArtistList.clear(); - m_szComposerList.clear(); - m_szComment = ""; - m_szGenreList.clear(); - m_szTitle = ""; - m_szRating = ""; - m_szCopyright = ""; - m_szTrackNumber = ""; - m_iYear = -1; - - m_iID3v2Version = -1; - m_iID3v2Revision = -1; - m_iID3v2Size = -1; - - m_TAGAPEList.clear(); - m_TAGPropertiesList.clear(); - - m_pixmapList.clear(); + m_szFileName = ""; + //m_ID3FieldList.clear(); + m_dwBitrate = 0; + m_dwSamplerate = 0; + m_dwChannels = 0; + m_dwSeconds = 0; } -bool cMediaInfo::readFromFile(const QString& szFileName) +uint16_t cMediaInfo::tagID(char* lpszTagName) +{ + cID3Field* lpID3Field = m_ID3FieldList.get(QString(lpszTagName)); + if(lpID3Field) + return(lpID3Field->getID()); + return(cID3Field::TAG_MAXFIELDS); +} + +QString cMediaInfo::tag2String(struct id3_frame* lpID3Frame, uint16_t dwField) +{ + QString szRet(""); + + if(id3_field_getnstrings(&lpID3Frame->fields[dwField])) + { + const id3_ucs4_t* lpszUCS4; + const id3_latin1_t* lpszLatin1; + + lpszUCS4 = id3_field_getstrings(&lpID3Frame->fields[dwField], 0); + if(lpszUCS4) + { + lpszLatin1 = id3_ucs4_latin1duplicate(lpszUCS4); + szRet = QString((const char*)lpszLatin1); + //free((void*)lpszUCS4); + free((void*)lpszLatin1); + } + } + return(szRet); +} + +QString cMediaInfo::tag2LyricsString(struct id3_frame* lpID3Frame) +{ + QString szRet(""); + + const id3_ucs4_t* lpszUCS4; + const id3_latin1_t* lpszLatin1; + + if(lpID3Frame->fields[1].immediate.value[0] == 'X' && + lpID3Frame->fields[1].immediate.value[1] == 'X' && + lpID3Frame->fields[1].immediate.value[2] == 'X') + { + lpszUCS4 = id3_field_getfullstring(&lpID3Frame->fields[3]); + if(lpszUCS4) + { + lpszLatin1 = id3_ucs4_latin1duplicate(lpszUCS4); + szRet = QString((const char*)lpszLatin1); + free((void*)lpszLatin1); + } + } + + return(szRet); +} + +void cMediaInfo::importInformation(struct id3_tag* lpID3Tag) +{ + struct id3_frame* lpID3Frame; + int iIndex = 0; + uint16_t dwID; + QString sz; + + while((lpID3Frame = id3_tag_findframe(lpID3Tag, NULL, iIndex)) != NULL) + { + dwID = tagID(lpID3Frame->id); + switch(dwID) + { + case cID3Field::TAG_Album: + case cID3Field::TAG_BeatsPerMinute: + case cID3Field::TAG_Composer: + case cID3Field::TAG_ContentType: + case cID3Field::TAG_CopyrightMessage: + case cID3Field::TAG_PlaylistDelay: + case cID3Field::TAG_OriginalReleaseTime: + case cID3Field::TAG_EncodingTime: + case cID3Field::TAG_RecordingTime: + case cID3Field::TAG_ReleaseTime: + case cID3Field::TAG_TaggingTime: + case cID3Field::TAG_EncodedBy: + case cID3Field::TAG_Lyricist: + case cID3Field::TAG_FileType: + case cID3Field::TAG_InvolvedPeopleList: + case cID3Field::TAG_ContentGroupDescription: + case cID3Field::TAG_Title: + case cID3Field::TAG_Subtitle: + case cID3Field::TAG_InitialKey: + case cID3Field::TAG_Languages: + case cID3Field::TAG_Length: + case cID3Field::TAG_MusicianCreditsList: + case cID3Field::TAG_MediaType: + case cID3Field::TAG_Mood: + case cID3Field::TAG_OriginalAlbum: + case cID3Field::TAG_OriginalFileName: + case cID3Field::TAG_OriginalLyricist: + case cID3Field::TAG_OriginalArtist: + case cID3Field::TAG_FileOwner: + case cID3Field::TAG_LeadPerformer: + case cID3Field::TAG_Band: + case cID3Field::TAG_Conductor: + case cID3Field::TAG_InterpretedBy: + case cID3Field::TAG_PartOfASet: + case cID3Field::TAG_ProducedNotice: + case cID3Field::TAG_Publisher: + case cID3Field::TAG_TrackNumber: + case cID3Field::TAG_InternetRadioStationName: + case cID3Field::TAG_InternetRadioStationOwner: + case cID3Field::TAG_AlbumSortOrder: + case cID3Field::TAG_PerformerSortOrder: + case cID3Field::TAG_TitleSortOrder: + case cID3Field::TAG_InternationalStandardRecordingCode: + case cID3Field::TAG_Software_Hardware: + case cID3Field::TAG_SetSubtitle: + case cID3Field::TAG_UserDefinedTextInformation: + case cID3Field::TAG_UniqueFileIdentifier: + case cID3Field::TAG_TermsOfUse: + m_ID3FieldList.get(dwID)->setValue(QVariant(tag2String(lpID3Frame, 1))); break; + case cID3Field::TAG_UnsynchronizedLyric: + sz = tag2LyricsString(lpID3Frame); + if(sz.length()) + m_ID3FieldList.get(dwID)->setValue(QVariant(sz)); break; + break; + case cID3Field::TAG_AttachedPicture: +#ifdef WITH_PICTURE + { + uint16_t dwType = id3_field_getint(&lpID3Frame->fields[2]); + QString szDescription = tag2String(lpID3Frame, 3); + id3_length_t dwLen; + const id3_byte_t* lpuData = id3_field_getbinarydata(&lpID3Frame->fields[4], &dwLen); + + QPixmap Pixmap; + Pixmap.loadFromData(lpuData, dwLen); + QVariant v = m_ID3FieldList.get(dwID)->getValue(); + if(v.canConvert()) + { + cPictureList* lpPictureList = v.value(); + lpPictureList->add(Pixmap, dwType, szDescription); + } + else + { + cPictureList* lpPictureList = new cPictureList; + lpPictureList->add(Pixmap, dwType, szDescription); + v.setValue(lpPictureList); + m_ID3FieldList.setValue(dwID, v); + } + } +#endif + break; + case cID3Field::TAG_AudioEncryption: + break; + case cID3Field::TAG_AudioSeekPointIndex: + break; + case cID3Field::TAG_Comments: + break; + case cID3Field::TAG_CommercialFrame: + break; + case cID3Field::TAG_EncryptionMethodRegistration: + break; + case cID3Field::TAG_Equalisation: + break; + case cID3Field::TAG_EventTimingCodes: + break; + case cID3Field::TAG_GeneralEncapsulatedObject: + break; + case cID3Field::TAG_GroupIdentificationRegistration: + break; + case cID3Field::TAG_LinkedInformation: + break; + case cID3Field::TAG_MusicCDIdentifier: + break; + case cID3Field::TAG_MPEGLocationLookupTable: + break; + case cID3Field::TAG_OwnershipFrame: + break; + case cID3Field::TAG_PrivateFrame: + break; + case cID3Field::TAG_PlayCounter: + break; + case cID3Field::TAG_Popularimeter: + break; + case cID3Field::TAG_PositionSynchronisationFrame: + break; + case cID3Field::TAG_RecommendedBufferSize: + break; + case cID3Field::TAG_RelativeVolumeAdjustment: + break; + case cID3Field::TAG_Reverb: + break; + case cID3Field::TAG_SeekFrame: + break; + case cID3Field::TAG_SignatureFrame: + break; + case cID3Field::TAG_SynchronisedLyric: + break; + case cID3Field::TAG_SynchronisedTempoCodes: + break; + case cID3Field::TAG_CommercialInformation: + break; + case cID3Field::TAG_LegalInformation: + break; + case cID3Field::TAG_OfficialAudioFileWebpage: + break; + case cID3Field::TAG_OfficialArtistWebpage: + break; + case cID3Field::TAG_OfficialAudioSourceWebpage: + break; + case cID3Field::TAG_OfficialInternetRadioStationWebpage: + break; + case cID3Field::TAG_Payment: + break; + case cID3Field::TAG_PublishersOfficialWebpage: + break; + case cID3Field::TAG_UserDefinedURLLinkFrame: + break; + } + + iIndex++; + } +} + +void cMediaInfo::readFileInformation(const QString& szFileName) +{ + FILE* file = fopen(szFileName.toLatin1(), "rb"); + if(!file) + return; + + uint32_t head; + unsigned char tmp[4]; + struct frame frm; + bool id3_found = false; + + + if(fread(tmp, 1, 4, file) != 4) + { + fclose(file); + return; + } + + // Skip data of the ID3v2.x tag (It may contain data similar to mpeg frame + // as, for example, in the id3 APIC frame) (patch from Artur Polaczynski) + if (tmp[0] == 'I' && tmp[1] == 'D' && tmp[2] == '3' && tmp[3] < 0xFF) + { + // ID3v2 tag skipeer $49 44 33 yy yy xx zz zz zz zz [zz size] + long id3v2size; + fseek(file, 2, SEEK_CUR); // Size is 6-9 position + if (fread(tmp, 1, 4, file) != 4) // Read bytes of tag size + { + fclose(file); + return; + } + id3v2size = 10 + ( (long)(tmp[3]) | ((long)(tmp[2]) << 7) | ((long)(tmp[1]) << 14) | ((long)(tmp[0]) << 21) ); + fseek(file, id3v2size, SEEK_SET); + if (fread(tmp, 1, 4, file) != 4) // Read mpeg header + { + fclose(file); + return; + } + } + + head = ((uint32_t) tmp[0] << 24) | ((uint32_t) tmp[1] << 16) | ((uint32_t) tmp[2] << 8) | (uint32_t) tmp[3]; + while (!mpg123_head_check(head)) + { + head <<= 8; + if (fread(tmp, 1, 1, file) != 1) + { + fclose(file); + return; + } + head |= tmp[0]; + } + + if (mpg123_decode_header(&frm, head)) + { + unsigned char* buf; + double tpf; + int pos; + XHEADDATA xing_header; + uint32_t num_frames; + + buf = (unsigned char*)malloc(frm.framesize + 4); + fseek(file, -4, SEEK_CUR); + fread(buf, 1, frm.framesize + 4, file); + xing_header.toc = NULL; + tpf = mpg123_compute_tpf(&frm); + // MPEG and Layer version + setMPEG(frm.mpeg25); + setVersion(frm.lsf+1); + setLayerVersion(frm.lay); + + pos = ftell(file); + fseek(file, 0, SEEK_END); + // Variable bitrate? + bitrate + uint16_t dwVarBitrate = mpg123_get_xing_header(&xing_header,buf); + if(dwVarBitrate) + { + num_frames = xing_header.frames; + setBitrate(((xing_header.bytes * 8) / (tpf * xing_header.frames * 1000))); + } + else + { + num_frames = ((ftell(file) - pos - (id3_found ? 128 : 0)) / mpg123_compute_bpf(&frm)) + 1; + setBitrate(tabsel_123[frm.lsf][frm.lay - 1][frm.bitrate_index]); + } + // Samplerate + setSamplerate(mpg123_freqs[frm.sampling_frequency]); + // Mode + setMode(frm.mode); + + free(buf); + } + + // Duration + setSeconds(mpg123_get_song_time(file)/1000); + + fclose(file); +} + +void cMediaInfo::importFromFile(const QString& szFileName) { clear(); - QFileInfo fileInfo(szFileName); - if(!fileInfo.exists()) - return(false); + struct id3_file* lpID3File; + struct id3_tag* lpID3Tag; - if(!fileInfo.suffix().compare("APE", Qt::CaseInsensitive)) - m_fileType = MEDIA_TYPE_APE; - else if(!fileInfo.suffix().compare("WMA", Qt::CaseInsensitive)) - m_fileType = MEDIA_TYPE_ASF; - else if(!fileInfo.suffix().compare("FLAC", Qt::CaseInsensitive)) - m_fileType = MEDIA_TYPE_FLAC; - else if(!fileInfo.suffix().compare("AAC", Qt::CaseInsensitive)) - m_fileType = MEDIA_TYPE_MP4; - else if(!fileInfo.suffix().compare("MP4", Qt::CaseInsensitive)) - m_fileType = MEDIA_TYPE_MP4; - else if(!fileInfo.suffix().compare("M4A", Qt::CaseInsensitive)) - m_fileType = MEDIA_TYPE_MP4; - else if(!fileInfo.suffix().compare("MPC", Qt::CaseInsensitive)) - m_fileType = MEDIA_TYPE_MPC; - else if(!fileInfo.suffix().compare("MP1", Qt::CaseInsensitive)) - m_fileType = MEDIA_TYPE_MPEG; - else if(!fileInfo.suffix().compare("MP2", Qt::CaseInsensitive)) - m_fileType = MEDIA_TYPE_MPEG; - else if(!fileInfo.suffix().compare("MP3", Qt::CaseInsensitive)) - m_fileType = MEDIA_TYPE_MPEG; - else if(!fileInfo.suffix().compare("TTA", Qt::CaseInsensitive)) - m_fileType = MEDIA_TYPE_TRUEAUDIO; - else if(!fileInfo.suffix().compare("WV", Qt::CaseInsensitive)) - m_fileType = MEDIA_TYPE_WAVPACK; - else if(!fileInfo.suffix().compare("WAV", Qt::CaseInsensitive)) - m_fileType = MEDIA_TYPE_WAV; + readFileInformation(szFileName); - if(m_fileType == MEDIA_TYPE_UNKNOWN) - return(false); + lpID3File = id3_file_open(szFileName.toUtf8(), ID3_FILE_MODE_READONLY); + if(!lpID3File) + return; - m_szFileName = szFileName; + m_szFileName = szFileName; + lpID3Tag = id3_file_tag(lpID3File); - ID3v1::Tag* lpTagV1 = 0; - ID3v2::Tag* lpTagV2 = 0; - APE::Tag* lpTagAPE = 0; - APE::File* lpApe = 0; - ASF::File* lpASF = 0; - FLAC::File* lpFlac = 0; - MP4::File* lpMP4 = 0; - MPC::File* lpMPC = 0; - MPEG::File* lpMPEG = 0; - TrueAudio::File* lpTrueAudio = 0; - WavPack::File* lpWavPack = 0; - RIFF::WAV::File* lpWav = 0; + importInformation(lpID3Tag); - TagLib::PropertyMap tags; - - QString szTmp; - - switch(m_fileType) - { - case MEDIA_TYPE_APE: - { - lpApe = new APE::File(m_szFileName.toLocal8Bit().data()); - - lpTagV1 = lpApe->ID3v1Tag(); - lpTagAPE = lpApe->APETag(); - tags = lpApe->properties(); - - APE::Properties* lpAudioProperties = lpApe->audioProperties(); - - if(lpAudioProperties) - { - m_iLength = lpAudioProperties->length(); - m_iBitrate = lpAudioProperties->bitrate(); - m_iSampleRate = lpAudioProperties->sampleRate(); - m_iChannels = lpAudioProperties->channels(); - m_iBitsPerSample = lpAudioProperties->bitsPerSample(); - m_iVersion = lpAudioProperties->version(); - } - break; - } - case MEDIA_TYPE_ASF: - { - lpASF = new ASF::File(m_szFileName.toLocal8Bit().data()); - TagLib::ASF::Tag* lpTag = lpASF->tag(); - m_szTitle = QString::fromStdWString(lpTag->title().toWString()); - szTmp = QString::fromStdWString(lpTag->artist().toWString()); - if(!szTmp.isEmpty() && m_bID3V1) - m_szArtistList = szTmp.split("\n"); - m_szAlbum = QString::fromStdWString(lpTag->album().toWString()); - m_szComment = QString::fromStdWString(lpTag->comment().toWString()); - szTmp = QString::fromStdWString(lpTag->genre().toWString()); - if(!szTmp.isEmpty() && m_bID3V1) - m_szGenreList = szTmp.split("\n"); - m_szRating = QString::fromStdWString(lpTag->genre().toWString()); - m_szCopyright = QString::fromStdWString(lpTag->copyright().toWString()); - m_iYear = lpTag->year(); - m_szTrackNumber = QString("%1").arg(lpTag->track()); - - tags = lpASF->properties(); - - ASF::Properties* lpAudioProperties = lpASF->audioProperties(); - - if(lpAudioProperties) - { - m_iLength = lpAudioProperties->length(); - m_iBitrate = lpAudioProperties->bitrate(); - m_iSampleRate = lpAudioProperties->sampleRate(); - m_iChannels = lpAudioProperties->channels(); - m_bIsEncrypted = lpAudioProperties->isEncrypted(); - } - break; - } - case MEDIA_TYPE_FLAC: - { - lpFlac = new FLAC::File(m_szFileName.toLocal8Bit().data()); - lpTagV1 = lpFlac->ID3v1Tag(); - lpTagV2 = lpFlac->ID3v2Tag(); - tags = lpFlac->properties(); - - FLAC::Properties* lpAudioProperties = lpFlac->audioProperties(); - - if(lpAudioProperties) - { - m_iLength = lpAudioProperties->length(); - m_iBitrate = lpAudioProperties->bitrate(); - m_iSampleRate = lpAudioProperties->sampleRate(); - m_iChannels = lpAudioProperties->channels(); - m_iSampleWidth = lpAudioProperties->sampleWidth(); - m_ullSampleFrames = lpAudioProperties->sampleFrames(); - } - break; - } - case MEDIA_TYPE_MP4: - { - lpMP4 = new MP4::File(m_szFileName.toLocal8Bit().data()); - TagLib::MP4::Tag* lpTag = lpMP4->tag(); - m_szTitle = QString::fromStdWString(lpTag->title().toWString()); - szTmp = QString::fromStdWString(lpTag->artist().toWString()); - if(!szTmp.isEmpty() && m_bID3V1) - m_szArtistList = szTmp.split("\n"); - m_szAlbum = QString::fromStdWString(lpTag->album().toWString()); - m_szComment = QString::fromStdWString(lpTag->comment().toWString()); - szTmp = QString::fromStdWString(lpTag->genre().toWString()); - if(!szTmp.isEmpty() && m_bID3V1) - m_szGenreList = szTmp.split("\n"); - m_iYear = lpTag->year(); - m_szTrackNumber = QString("%1").arg(lpTag->track()); - - tags = lpMP4->properties(); - - MP4::Properties* lpAudioProperties = lpMP4->audioProperties(); - - if(lpAudioProperties) - { - m_iLength = lpAudioProperties->length(); - m_iBitrate = lpAudioProperties->bitrate(); - m_iSampleRate = lpAudioProperties->sampleRate(); - m_iChannels = lpAudioProperties->channels(); - m_iBitsPerSample = lpAudioProperties->bitsPerSample(); - m_bIsEncrypted = lpAudioProperties->isEncrypted(); - } - break; - } - case MEDIA_TYPE_MPC: - { - lpMPC = new MPC::File(m_szFileName.toLocal8Bit().data()); - lpTagV1 = lpMPC->ID3v1Tag(); - lpTagAPE = lpMPC->APETag(); - tags = lpMPC->properties(); - - MPC::Properties* lpAudioProperties = lpMPC->audioProperties(); - - if(lpAudioProperties) - { - m_iLength = lpAudioProperties->length(); - m_iBitrate = lpAudioProperties->bitrate(); - m_iSampleRate = lpAudioProperties->sampleRate(); - m_iChannels = lpAudioProperties->channels(); - m_iVersion = lpAudioProperties->mpcVersion(); - m_ullSampleFrames = lpAudioProperties->sampleFrames(); - m_iTrackGain = lpAudioProperties->trackGain(); - m_iAlbumGain = lpAudioProperties->albumGain(); - m_iTrackPeak = lpAudioProperties->trackPeak(); - m_iAlbumPeak = lpAudioProperties->albumPeak(); - } - break; - } - case MEDIA_TYPE_MPEG: - { - lpMPEG = new MPEG::File(m_szFileName.toLocal8Bit().data()); - - lpTagV1 = lpMPEG->ID3v1Tag(); - lpTagV2 = lpMPEG->ID3v2Tag(); - lpTagAPE = lpMPEG->APETag(); - tags = lpMPEG->properties(); - - MPEG::Properties* lpAudioProperties = lpMPEG->audioProperties(); - - if(lpAudioProperties) - { - m_iLength = lpAudioProperties->length(); - m_iBitrate = lpAudioProperties->bitrate(); - m_iSampleRate = lpAudioProperties->sampleRate(); - m_iChannels = lpAudioProperties->channels(); - m_iLayer = lpAudioProperties->layer(); - switch(lpAudioProperties->version()) - { - case MPEG::Header::Version1: - m_iVersion = 10; - break; - case MPEG::Header::Version2: - m_iVersion = 20; - break; - case MPEG::Header::Version2_5: - m_iVersion = 25; - break; - } - m_bProtectionEnabled = lpAudioProperties->protectionEnabled(); - switch(lpAudioProperties->channelMode()) - { - case MPEG::Header::Stereo: - m_channelMode = CHANNEL_MODE_STEREO; - break; - case MPEG::Header::JointStereo: - m_channelMode = CHANNEL_MODE_JOINTSTEREO; - break; - case MPEG::Header::DualChannel: - m_channelMode = CHANNEL_MODE_DUALMONO; - break; - case MPEG::Header::SingleChannel: - m_channelMode = CHANNEL_MODE_MONO; - break; - } - m_bIsCopyrighted = lpAudioProperties->isCopyrighted(); - m_bIsOriginal = lpAudioProperties->isOriginal(); - } - break; - } - case MEDIA_TYPE_TRUEAUDIO: - { - lpTrueAudio = new TrueAudio::File(m_szFileName.toLocal8Bit().data()); - lpTagV1 = lpTrueAudio->ID3v1Tag(); - lpTagV2 = lpTrueAudio->ID3v2Tag(); - tags = lpTrueAudio->properties(); - - TrueAudio::Properties* lpAudioProperties = lpTrueAudio->audioProperties(); - - if(lpAudioProperties) - { - m_iLength = lpAudioProperties->length(); - m_iBitrate = lpAudioProperties->bitrate(); - m_iSampleRate = lpAudioProperties->sampleRate(); - m_iChannels = lpAudioProperties->channels(); - m_iBitsPerSample = lpAudioProperties->bitsPerSample(); - m_iVersion = lpAudioProperties->ttaVersion(); - } - break; - } - case MEDIA_TYPE_WAVPACK: - { - lpWavPack = new WavPack::File(m_szFileName.toLocal8Bit().data()); - lpTagV1 = lpWavPack->ID3v1Tag(); - lpTagAPE = lpWavPack->APETag(); - tags = lpWavPack->properties(); - - WavPack::Properties* lpAudioProperties = lpWavPack->audioProperties(); - - if(lpAudioProperties) - { - m_iLength = lpAudioProperties->length(); - m_iBitrate = lpAudioProperties->bitrate(); - m_iSampleRate = lpAudioProperties->sampleRate(); - m_iChannels = lpAudioProperties->channels(); - m_iBitsPerSample = lpAudioProperties->bitsPerSample(); - m_ullSampleFrames = lpAudioProperties->sampleFrames(); - m_iVersion = lpAudioProperties->version(); - } - break; - } - case MEDIA_TYPE_WAV: - { - lpWav = new RIFF::WAV::File(m_szFileName.toLocal8Bit().data()); - lpTagV2 = lpWav->tag(); - tags = lpWav->properties(); - - RIFF::WAV::Properties* lpAudioProperties = lpWav->audioProperties(); - - if(lpAudioProperties) - { - m_iLength = lpAudioProperties->length(); - m_iBitrate = lpAudioProperties->bitrate(); - m_iSampleRate = lpAudioProperties->sampleRate(); - m_iChannels = lpAudioProperties->channels(); - m_iSampleWidth = lpAudioProperties->sampleWidth(); - m_ullSampleFrames = lpAudioProperties->sampleFrames(); - } - break; - } - default: - break; - } - - if(lpTagV2 && m_bID3V2) - readTagV2(lpTagV2); - if(lpTagV1 && m_bID3V1) - readTagV1(lpTagV1); - if(lpTagAPE && m_bAPE) - readTagAPE(lpTagAPE); - if(m_bProperties) - readTagProperties(tags); - - if(lpApe) - delete lpApe; - if(lpASF) - delete lpASF; - if(lpFlac) - delete lpFlac; - if(lpMP4) - delete lpMP4; - if(lpMPC) - delete lpMPC; - if(lpMPEG) - delete lpMPEG; - if(lpTrueAudio) - delete lpTrueAudio; - if(lpWavPack) - delete lpWavPack; - if(lpWav) - delete lpWav; - - m_bIsValid = true; - return(true); + id3_file_close(lpID3File); } -bool cMediaInfo::readFromDB() +void cMediaInfo::initFields() { - return(true); + for(int z = 0;z < cID3Field::TAG_MAXFIELDS;z++) + m_ID3FieldList.add(g_Fields[z].dwID, g_Fields[z].lpszShortName, g_Fields[z].lpszName); } -qint32 cMediaInfo::writeFilename() +void cMediaInfo::setFileName(const QString& szFileName) { - QSqlQuery query; - - query.prepare("SELECT id FROM file WHERE fileName=:fileName AND fileSize=:fileSize AND fileDate=:fileDate;"); - query.bindValue(":fileName", fileName()); - query.bindValue(":fileSize", fileSize()); - query.bindValue(":fileDate", fileDate()); - - if(!query.exec()) - { - myDebug << query.lastError().text(); - return(-1); - } - - if(query.next()) - query.prepare("UPDATE file SET fileType1=:fileType1, fileType=:fileType, length1=:length1, length=:length, bitrate=:bitrate, sampleRate=:sampleRate, channels=:channels, bitsPerSample=:bitsPerSample, layer=:layer, version=:version, sampleWidth=:sampleWidth, sampleFrames=:sampleFrames, isEncrypted=:isEncrypted, trackGain=:trackGain, albumGain=:albumGain, trackPeak=:trackPeak, albumPeak=:albumPeak, protectionEnabled=:protectionEnabled, channelMode=:channelMode, isCopyrighted=:isCopyrighted, isOriginal=:isOriginal, album=:album, title=:title, copyright=:copyright, tracknumber=:tracknumber, contentGroupDescription=:contentGroupDescription, subTitle=:subTitle, originalAlbum=:originalAlbum, partOfSet=:partOfSet, subTitleOfSet=:subTitleOfSet, internationalStandardRecordingCode=:internationalStandardRecordingCode, leadArtist=:leadArtist, band=:band, conductor=:conductor, interpret=:interpret, originalArtist=:originalArtist, textWriter=:textWriter, originalTextWriter=:originalTextWriter, composer=:composer, encodedBy=:encodedBy, beatsPerMinute=:beatsPerMinute, language=:language, contentType=:contentType, mediaType=:mediaType, mood=:mood, producedNotice=:producedNotice, publisher=:publisher, fileOwner=:fileOwner, internetRadioStationName=:internetRadioStationName, internetRadioStationOwner=:internetRadioStationOwner, originalFilename=:originalFilename, playlistDelay=:playlistDelay, encodingTime=:encodingTime, originalReleaseTime=:originalReleaseTime, recordingTime=:recordingTime, releaseTime=:releaseTime, taggingTime=:taggingTime, swhwSettings=:swhwSettings, albumSortOrder=:albumSortOrder, performerSortOrder=:performerSortOrder, titleSortOrder=:titleSortOrder, synchronizedLyrics=:synchronizedLyrics, unsynchronizedLyrics=:unsynchronizedLyrics WHERE filename=:filename AND filesize=:filesize AND filedate=:filedate;"); - else - query.prepare("INSERT INTO file (fileName, fileSize, fileDate, fileType1, fileType, length1, length, bitrate, sampleRate, channels, bitsPerSample, layer, version, sampleWidth, sampleFrames, isEncrypted, trackGain, albumGain, trackPeak, albumPeak, protectionEnabled, channelMode, isCopyrighted, isOriginal, album, title, copyright, tracknumber, contentGroupDescription, subTitle, originalAlbum, partOfSet, subTitleOfSet, internationalStandardRecordingCode, leadArtist, band, conductor, interpret, originalArtist, textWriter, originalTextWriter, composer, encodedBy, beatsPerMinute, language, contentType, mediaType, mood, producedNotice, publisher, fileOwner, internetRadioStationName, internetRadioStationOwner, originalFilename, playlistDelay, encodingTime, originalReleaseTime, recordingTime, releaseTime, taggingTime, swhwSettings, albumSortOrder, performerSortOrder, titleSortOrder, synchronizedLyrics, unsynchronizedLyrics) VALUES (:fileName, :fileSize, :fileDate, :fileType1, :fileType, :length1, :length, :bitrate, :sampleRate, :channels, :bitsPerSample, :layer, :version, :sampleWidth, :sampleFrames, :isEncrypted, :trackGain, :albumGain, :trackPeak, :albumPeak, :protectionEnabled, :channelMode, :isCopyrighted, :isOriginal, :album, :title, :copyright, :tracknumber, :contentGroupDescription, :subTitle, :originalAlbum, :partOfSet, :subTitleOfSet, :internationalStandardRecordingCode, :leadArtist, :band, :conductor, :interpret, :originalArtist, :textWriter, :originalTextWriter, :composer, :encodedBy, :beatsPerMinute, :language, :contentType, :mediaType, :mood, :producedNotice, :publisher, :fileOwner, :internetRadioStationName, :internetRadioStationOwner, :originalFilename, :playlistDelay, :encodingTime, :originalReleaseTime, :recordingTime, :releaseTime, :taggingTime, :swhwSettings, :albumSortOrder, :performerSortOrder, :titleSortOrder, :synchronizedLyrics, :unsynchronizedLyrics);"); - - query.bindValue(":fileName", fileName()); - query.bindValue(":fileSize", fileSize()); - query.bindValue(":fileDate", fileDate()); - query.bindValue(":fileType1", fileType1()); - query.bindValue(":fileType", fileType()); - query.bindValue(":length1", length1()); - query.bindValue(":length", length()); - query.bindValue(":bitrate", bitrate()); - query.bindValue(":sampleRate", sampleRate()); - query.bindValue(":channels", channels()); - query.bindValue(":bitsPerSample", bitsPerSample()); - query.bindValue(":layer", layer()); - query.bindValue(":version", version()); - query.bindValue(":sampleWidth", sampleWidth()); - query.bindValue(":sampleFrames", sampleFrames()); - query.bindValue(":isEncrypted", isEncrypted()); - query.bindValue(":trackGain", trackGain()); - query.bindValue(":albumGain", albumGain()); - query.bindValue(":trackPeak", trackPeak()); - query.bindValue(":albumPeak", albumPeak()); - query.bindValue(":protectionEnabled", protectionEnabled()); - query.bindValue(":channelMode", channelMode()); - query.bindValue(":isCopyrighted", isCopyrighted()); - query.bindValue(":isOriginal", isOriginal()); - query.bindValue(":album", album()); - query.bindValue(":title", title()); - query.bindValue(":copyright", copyright()); - query.bindValue(":tracknumber", trackNumber()); - query.bindValue(":contentGroupDescription", contentGroupDescription()); - query.bindValue(":subTitle", subTitle()); - query.bindValue(":originalAlbum", originalAlbum()); - query.bindValue(":partOfSet", partOfSet()); - query.bindValue(":subTitleOfSet", subTitleOfSet()); - query.bindValue(":internationalStandardRecordingCode", internationalStandardRecordingCode()); - query.bindValue(":leadArtist", leadArtist()); - query.bindValue(":band", band()); - query.bindValue(":conductor", conductor()); - query.bindValue(":interpret", interpret().join(", ")); - query.bindValue(":originalArtist", originalArtist()); - query.bindValue(":textWriter", textWriter()); - query.bindValue(":originalTextWriter", originalTextWriter()); - query.bindValue(":composer", composer()); - query.bindValue(":encodedBy", encodedBy()); - query.bindValue(":beatsPerMinute", beatsPerMinute()); - query.bindValue(":language", language().join(", ")); - query.bindValue(":contentType", contentType().join(", ")); - query.bindValue(":mediaType", mediaType().join(", ")); - query.bindValue(":mood", mood()); - query.bindValue(":producedNotice", producedNotice()); - query.bindValue(":publisher", publisher()); - query.bindValue(":fileOwner", fileOwner()); - query.bindValue(":internetRadioStationName", internetRadioStationName()); - query.bindValue(":internetRadioStationOwner", internetRadioStationOwner()); - query.bindValue(":originalFilename", originalFilename()); - query.bindValue(":playlistDelay", playlistDelay()); - query.bindValue(":encodingTime", encodingTime()); - query.bindValue(":originalReleaseTime", originalReleaseTime()); - query.bindValue(":recordingTime", recordingTime()); - query.bindValue(":releaseTime", releaseTime()); - query.bindValue(":taggingTime", taggingTime()); - query.bindValue(":swhwSettings", swhwSettings().join(", ")); - query.bindValue(":albumSortOrder", albumSortOrder()); - query.bindValue(":performerSortOrder", performerSortOrder()); - query.bindValue(":titleSortOrder", titleSortOrder()); - query.bindValue(":synchronizedLyrics", synchronizedLyrics().join()); - query.bindValue(":unsynchronizedLyrics", unsynchronizedLyrics().join("||")); - - if(!query.exec()) - { - myDebug << query.lastError().text(); - return(-1); - } - - query.prepare("SELECT id FROM file WHERE fileName=:fileName AND fileSize=:fileSize AND fileDate=:fileDate;"); - query.bindValue(":fileName", fileName()); - query.bindValue(":fileSize", fileSize()); - query.bindValue(":fileDate", fileDate()); - - if(!query.exec()) - { - myDebug << query.lastError().text(); - return(-1); - } - - if(query.next()) - return(query.value("id").toInt()); - - return(-1); + m_szFileName = szFileName; } -bool cMediaInfo::writeToDB() -{ - QSqlQuery query; - qint32 idFile = writeFilename(); - - if(idFile == -1) - return(false); - - query.prepare("DELETE FROM image WHERE fileID=:fileID;"); - query.bindValue(":fileID", idFile); - - if(!query.exec()) - { - myDebug << query.lastError().text(); - return(false); - } - - for(int x = 0;x < m_pixmapList.count();x++) - { - cPixmap pixmap = m_pixmapList.at(x); - - query.prepare("INSERT INTO image (fileID, fileName, imageType, image) VALUES (:fileID, :fileName, :imageType, :image);"); - - query.bindValue(":fileID", idFile); - query.bindValue(":fileName", pixmap.fileName()); - query.bindValue(":imageType", (qint16)pixmap.imageType()); - query.bindValue(":description", pixmap.description()); - - QByteArray baImage; - QBuffer buffer(&baImage); - buffer.open(QIODevice::WriteOnly); - m_pixmapList.at(x).save(&buffer, "JPG"); - query.bindValue(":image", baImage); - - if(!query.exec()) - { - myDebug << query.lastError().text(); - return(false); - } - } - - return(true); -} - -void cMediaInfo::readTagV1(ID3v1::Tag* lpTag) -{ - QString szTmp; - m_szAlbum = QString::fromStdWString(lpTag->album().toWString()); - szTmp = QString::fromStdWString(lpTag->artist().toWString()); - if(!szTmp.isEmpty()) - m_szArtistList = szTmp.split("\n"); - m_szAlbum = QString::fromStdWString(lpTag->album().toWString()); - m_szComment = QString::fromStdWString(lpTag->comment().toWString()); - szTmp = QString::fromStdWString(lpTag->genre().toWString()); - if(!szTmp.isEmpty()) - m_szGenreList = szTmp.split("\n"); - m_szTitle = QString::fromStdWString(lpTag->title().toWString()); - m_szTrackNumber = QString("%1").arg(lpTag->track()); - m_iYear = lpTag->year(); -} - -void cMediaInfo::readTagV2(ID3v2::Tag* lpTag) -{ - m_iID3v2Version = lpTag->header()->majorVersion(); - m_iID3v2Revision = lpTag->header()->revisionNumber(); - m_iID3v2Size = lpTag->header()->tagSize(); - - for(ID3v2::FrameList::ConstIterator it = lpTag->frameList().begin();it != lpTag->frameList().end();it++) - { - QString szID = QString("%1").arg((*it)->frameID().data()).left(4); - - if(!szID.compare("TIT1")) - m_szContentGroupDescription = QString::fromStdWString((*it)->toString().toWString()); - else if(!szID.compare("TIT2")) - m_szTitle = QString::fromStdWString((*it)->toString().toWString()); - else if(!szID.compare("TIT3")) - m_szSubTitle = QString::fromStdWString((*it)->toString().toWString()); - else if(!szID.compare("TALB")) - m_szAlbum = QString::fromStdWString((*it)->toString().toWString()); - else if(!szID.compare("TOAL")) - m_szOriginalAlbum = QString::fromStdWString((*it)->toString().toWString()); - else if(!szID.compare("TRCK")) - m_szTrackNumber = QString::fromStdWString((*it)->toString().toWString()); - else if(!szID.compare("TPOS")) - m_szPartOfSet = QString::fromStdWString((*it)->toString().toWString()); - else if(!szID.compare("TSST")) - m_szSubTitleOfSet = QString::fromStdWString((*it)->toString().toWString()); - else if(!szID.compare("TSRC")) - m_szInternationalStandardRecordingCode = QString::fromStdWString((*it)->toString().toWString()); - else if(!szID.compare("TPE1")) - m_szLeadArtist = QString::fromStdWString((*it)->toString().toWString()); - else if(!szID.compare("TPE2")) - m_szBand = QString::fromStdWString((*it)->toString().toWString()); - else if(!szID.compare("TPE3")) - m_szConductor = QString::fromStdWString((*it)->toString().toWString()); - else if(!szID.compare("TPE4")) - m_szInterpret = QString::fromStdWString((*it)->toString().toWString()).split("\r\n"); - else if(!szID.compare("TOPE")) - m_szOriginalArtist = QString::fromStdWString((*it)->toString().toWString()); - else if(!szID.compare("TEXT")) - m_szTextWriter = QString::fromStdWString((*it)->toString().toWString()); - else if(!szID.compare("TOLY")) - m_szOriginalTextWriter = QString::fromStdWString((*it)->toString().toWString()); - else if(!szID.compare("TCOM")) - m_szComposer = QString::fromStdWString((*it)->toString().toWString()); - else if(!szID.compare("TENC")) - m_szEncodedBy = QString::fromStdWString((*it)->toString().toWString()); - else if(!szID.compare("TBPM")) - m_iBeatsPerMinute = QString::fromStdWString((*it)->toString().toWString()).toInt(); - else if(!szID.compare("TLEN") && m_iLength == 0) - m_iLength = QString::fromStdWString((*it)->toString().toWString()).toInt(); - else if(!szID.compare("TLAN")) - m_szLanguage = QString::fromStdWString((*it)->toString().toWString()).split("\r\n"); - else if(!szID.compare("TCON")) - m_szContentType = QString::fromStdWString((*it)->toString().toWString()).split("\r\n"); - else if(!szID.compare("TFLT")) - m_szFileType = QString::fromStdWString((*it)->toString().toWString()); - else if(!szID.compare("TMED")) - m_szMediaType = QString::fromStdWString((*it)->toString().toWString()).split("\r\n"); - else if(!szID.compare("TMOO")) - m_szMood = QString::fromStdWString((*it)->toString().toWString()); - else if(!szID.compare("TCOP")) - m_szCopyright = QString::fromStdWString((*it)->toString().toWString()); - else if(!szID.compare("TPRO")) - m_szProducedNotice = QString::fromStdWString((*it)->toString().toWString()); - else if(!szID.compare("TPUB")) - m_szPublisher = QString::fromStdWString((*it)->toString().toWString()); - else if(!szID.compare("TOWN")) - m_szFileOwner = QString::fromStdWString((*it)->toString().toWString()); - else if(!szID.compare("TRSN")) - m_szInternetRadioStationName = QString::fromStdWString((*it)->toString().toWString()); - else if(!szID.compare("TRSO")) - m_szInternetRadioStationOwner = QString::fromStdWString((*it)->toString().toWString()); - else if(!szID.compare("TOFN")) - m_szOriginalFilename = QString::fromStdWString((*it)->toString().toWString()); - else if(!szID.compare("TDLY")) - m_iPlaylistDelay = QString::fromStdWString((*it)->toString().toWString()).toInt(); - else if(!szID.compare("TDEN")) - m_encodingTime = str2TS(QString::fromStdWString((*it)->toString().toWString())); - else if(!szID.compare("TDOR")) - m_originalReleaseTime = str2TS(QString::fromStdWString((*it)->toString().toWString())); - else if(!szID.compare("TDRC")) - m_recordingTime = str2TS(QString::fromStdWString((*it)->toString().toWString())); - else if(!szID.compare("TDRL")) - m_releaseTime = str2TS(QString::fromStdWString((*it)->toString().toWString())); - else if(!szID.compare("TDTG")) - m_taggingTime = str2TS(QString::fromStdWString((*it)->toString().toWString())); - else if(!szID.compare("TSSE")) - m_szswhwSettings = QString(QString::fromStdWString((*it)->toString().toWString())).split("\r\n"); - else if(!szID.compare("TSOA")) - m_szAlbumSortOrder = QString::fromStdWString((*it)->toString().toWString()); - else if(!szID.compare("TSOP")) - m_szPerformerSortOrder = QString::fromStdWString((*it)->toString().toWString()); - else if(!szID.compare("TSOT")) - m_szTitleSortOrder = QString::fromStdWString((*it)->toString().toWString()); - else if(!szID.compare("SYLT")) - { - TagLib::ID3v2::SynchronizedLyricsFrame* lpLyrics = static_cast (*it); - - m_szSynchronizedLyricsLanguage = QString(lpLyrics->language().data()).left(3); - String::Type type = lpLyrics->textEncoding(); - m_szSynchronizedLyricsDescription = QString::fromStdWString(lpLyrics->description().toWString()); - - TagLib::ID3v2::SynchronizedLyricsFrame::SynchedTextList list = lpLyrics->synchedText(); - - for(ID3v2::SynchronizedLyricsFrame::SynchedTextList::ConstIterator it1 = list.begin(); it1 != list.end();it1++) - { - ID3v2::SynchronizedLyricsFrame::SynchedText t = *(it1); - m_szSynchronizedLyrics.add(t.time, QString::fromStdWString(t.text.toWString())); - } - } - else if(!szID.compare("USLT")) - { - TagLib::ID3v2::UnsynchronizedLyricsFrame* lpLyrics = static_cast (*it); - - m_szUnsynchronizedLyricsLanguage = QString(lpLyrics->language().data()).left(3); - String::Type type = lpLyrics->textEncoding(); - m_szUnsynchronizedLyricsDescription = QString::fromStdWString(lpLyrics->description().toWString()); - QString szText = QString::fromStdWString(lpLyrics->text().toWString()); - if(szText.contains("\r\n")) - m_szUnsynchronizedLyrics = szText.split("\r\n"); - else if(szText.contains("\r")) - m_szUnsynchronizedLyrics = szText.split("\r"); - else if(szText.contains("\n")) - m_szUnsynchronizedLyrics = szText.split("\n"); - else - m_szUnsynchronizedLyrics.append(szText); - } - else if(!szID.compare("APIC")) - { - TagLib::ID3v2::AttachedPictureFrame* lpPicture = static_cast (*it); - TagLib::ID3v2::AttachedPictureFrame::Type t = lpPicture->type(); - QString szDescription; - szDescription = QString::fromStdWString(lpPicture->description().toWString()); - - QByteArray pictureData = QByteArray(lpPicture->picture().data(), lpPicture->picture().size()); - m_pixmapList.add(pictureData, m_szFileName, (cPixmap::ImageType)t, szDescription); - } - } -} - -void cMediaInfo::readTagAPE(APE::Tag* lpTag) -{ - for(APE::ItemListMap::ConstIterator it = lpTag->itemListMap().begin();it != lpTag->itemListMap().end();++it) - { - QString szID = QString::fromStdWString((*it).first.toWString()); - QString szVal = QString::fromStdWString((*it).second.toString().toWString()); - if(!szID.isEmpty() && !szVal.isEmpty()) - m_TAGAPEList.add(szID.left(4), szVal); - } -} - -void cMediaInfo::readTagProperties(TagLib::PropertyMap& tags) -{ - QString szID; - - for(TagLib::PropertyMap::ConstIterator i = tags.begin(); i != tags.end(); ++i) - { - QStringList szValue; - szID = QString::fromStdWString(i->first.toWString()); - if(!szID.isEmpty()) - { - for(TagLib::StringList::ConstIterator j = i->second.begin(); j != i->second.end(); ++j) - { - QString sz = QString::fromStdWString((*j).toWString()); - if(!sz.isEmpty()) - { - if(!szID.compare("LYRICS")) - { - sz.replace("\"", "'"); - sz.replace("\r\n", "\n"); - szValue.append(sz); - } - else - szValue.append(sz.split("\n")); - } - } - if(!szID.isEmpty() && !szValue.isEmpty()) - m_TAGPropertiesList.add(szID, szValue); - } - } -} - -QDateTime cMediaInfo::str2TS(const QString& sz) -{ - QDateTime dt; - - switch(sz.length()) - { - case 4: - dt = QDateTime::fromString(sz, QString("yyyy")); - break; - case 7: - dt = QDateTime::fromString(sz, QString("yyyy-MM")); - break; - case 10: - dt = QDateTime::fromString(sz, QString("yyyy-MM-dd")); - break; - case 13: - dt = QDateTime::fromString(sz, QString("yyyy-MM-ddTHH")); - break; - case 16: - dt = QDateTime::fromString(sz, QString("yyyy-MM-ddTHH:mm")); - break; - case 19: - dt = QDateTime::fromString(sz, QString("yyyy-MM-ddTHH:mm:ss")); - break; - default: - return(QDateTime()); - } - return(dt); -} - -bool cMediaInfo::isValid() -{ - return(m_bIsValid); -} - -QString cMediaInfo::fileName() +QString cMediaInfo::getFileName() { return(m_szFileName); } -qint64 cMediaInfo::fileSize() +void cMediaInfo::setFileCreated(const QDateTime& FileCreated) { - QFileInfo fileInfo(m_szFileName); - return(fileInfo.size()); + m_FileCreated = FileCreated; } -QDateTime cMediaInfo::fileDate() +QDateTime cMediaInfo::getFileCreated() { - QFileInfo fileInfo(m_szFileName); - return(fileInfo.created()); + return(m_FileCreated); } -cMediaInfo::MEDIA_TYPE cMediaInfo::fileType1() +void cMediaInfo::setFileModified(const QDateTime& FileModified) { - return(m_fileType); + m_FileModified = FileModified; } -QString cMediaInfo::fileType1Text() +QDateTime cMediaInfo::getFileModified() { - switch(m_fileType) + return(m_FileModified); +} + +void cMediaInfo::setFileSize(uint64_t dwFileSize) +{ + m_dwFileSize = dwFileSize; +} + +uint64_t cMediaInfo::getFileSize() +{ + return(m_dwFileSize); +} + +QString cMediaInfo::getTAGName(uint16_t dwTag) +{ + if(dwTag >= cID3Field::TAG_MAXFIELDS) + return(""); + return(m_ID3FieldList.getName(dwTag)); +} + +QString cMediaInfo::getTAGShortName(uint16_t dwTag) +{ + if(dwTag >= cID3Field::TAG_MAXFIELDS) + return(""); + return(m_ID3FieldList.getShortName(dwTag)); +} + +void cMediaInfo::setBitrate(uint16_t dwBitrate) +{ + m_dwBitrate = dwBitrate; +} + +uint16_t cMediaInfo::getBitrate() +{ + return(m_dwBitrate); +} + +void cMediaInfo::setSamplerate(uint16_t dwSamplerate) +{ + m_dwSamplerate = dwSamplerate; +} + +uint16_t cMediaInfo::getSamplerate() +{ + return(m_dwSamplerate); +} + +void cMediaInfo::setChannels(uint16_t dwChannels) +{ + m_dwChannels = dwChannels; +} + +uint16_t cMediaInfo::getChannels() +{ + return(m_dwChannels); +} + +void cMediaInfo::setSeconds(uint16_t dwSeconds) +{ + m_dwSeconds = dwSeconds; +} + +uint16_t cMediaInfo::getSeconds() +{ + return(m_dwSeconds); +} + +void cMediaInfo::setMPEG(uint16_t dwMPEG) +{ + m_dwMPEG = dwMPEG; +} + +uint16_t cMediaInfo::getMPEG() +{ + return(m_dwMPEG); +} + +void cMediaInfo::setVersion(uint16_t dwVersion) +{ + m_dwVersion = dwVersion; +} + +uint16_t cMediaInfo::getVersion() +{ + return(m_dwVersion); +} + +void cMediaInfo::setLayerVersion(uint16_t dwLayerVersion) +{ + m_dwLayerVersion = dwLayerVersion; +} + +uint16_t cMediaInfo::getLayerVersion() +{ + return(m_dwLayerVersion); +} + +void cMediaInfo::setMode(uint16_t dwMode) +{ + m_dwMode = dwMode; +} + +uint16_t cMediaInfo::getMode() +{ + return(m_dwMode); +} + +void cMediaInfo::setValid(bool bValid) +{ + m_bValid = bValid; +} + +bool cMediaInfo::getValid() +{ + return(m_bValid); +} + +void cMediaInfo::setTAG(uint16_t dwTag, uint16_t dwData) +{ + if(dwTag >= cID3Field::TAG_MAXFIELDS) + return; + + m_ID3FieldList.setValue(dwTag, QVariant(dwData)); +} + +void cMediaInfo::setTAG(uint16_t dwTag, const QString& szData) +{ + if(dwTag >= cID3Field::TAG_MAXFIELDS) + return; + m_ID3FieldList.setValue(dwTag, QVariant(szData)); +} + +void cMediaInfo::setTAG(uint16_t dwTag, const QVariant& v) +{ + if(dwTag >= cID3Field::TAG_MAXFIELDS) + return; + m_ID3FieldList.setValue(dwTag, v); +} + +QVariant cMediaInfo::getTAG(uint16_t dwTag) +{ + if(dwTag >= cID3Field::TAG_MAXFIELDS) + return(QVariant()); + if(!m_ID3FieldList.getValue(dwTag).isValid()) + return(QVariant()); + return(m_ID3FieldList.getValue(dwTag)); +} + +uint16_t cMediaInfo::getTAGi(uint16_t dwTag) +{ + if(dwTag >= cID3Field::TAG_MAXFIELDS) + return(0); + if(!m_ID3FieldList.getValue(dwTag).isValid()) + return(0); + return(m_ID3FieldList.getValue(dwTag).toInt()); +} + +QString cMediaInfo::getTAGs(uint16_t dwTag) +{ + if(dwTag >= cID3Field::TAG_MAXFIELDS) + return(QString("")); + if(!m_ID3FieldList.isValid(dwTag)) + return(QString("")); + return(m_ID3FieldList.getValue(dwTag).toString()); +} + +bool cMediaInfo::getTAG(uint16_t dwTag, QString& szData) +{ + if(dwTag >= cID3Field::TAG_MAXFIELDS) + return(false); + if(!m_ID3FieldList.isValid(dwTag)) + return(false); + szData = m_ID3FieldList.getValue(dwTag).toString(); + return(true); +} + +bool cMediaInfo::getTAG(uint16_t dwTag, QString& szName, QString& szData) +{ + if(dwTag >= cID3Field::TAG_MAXFIELDS) + return(false); + if(!m_ID3FieldList.isValid(dwTag)) + return(false); + szName = m_ID3FieldList.getName(dwTag); + szData = m_ID3FieldList.getValue(dwTag).toString(); + return(true); +} + +bool cMediaInfo::getTAG(uint16_t dwTag, uint16_t& dwData) +{ + if(dwTag >= cID3Field::TAG_MAXFIELDS) + return(false); + if(!m_ID3FieldList.isValid(dwTag)) + return(false); + dwData = m_ID3FieldList.getValue(dwTag).toInt(); + return(true); +} + +bool cMediaInfo::getTAG(uint16_t dwTag, QString& szName, uint16_t& dwData) +{ + if(dwTag >= cID3Field::TAG_MAXFIELDS) + return(false); + if(!m_ID3FieldList.isValid(dwTag)) + return(false); + szName = m_ID3FieldList.getName(dwTag); + dwData = m_ID3FieldList.getValue(dwTag).toInt(); + return(true); +} + +bool cMediaInfo::getTAG(uint16_t dwTag, id3_byte_t* lpData, uint32_t& dwLen) +{ + if(dwTag >= cID3Field::TAG_MAXFIELDS) + return(false); + if(!m_ID3FieldList.isValid(dwTag)) + return(false); + lpData = (id3_byte_t*)m_ID3FieldList.getValue(dwTag).toByteArray().data(); + dwLen = m_ID3FieldList.getValue(dwTag).toByteArray().length(); + return(true); +} + +bool cMediaInfo::getTAG(uint16_t dwTag, QString& szName, id3_byte_t* lpData, uint32_t& dwLen) +{ + if(dwTag >= cID3Field::TAG_MAXFIELDS) + return(false); + if(!m_ID3FieldList.isValid(dwTag)) + return(false); + szName = m_ID3FieldList.getName(dwTag); + lpData = (id3_byte_t*)m_ID3FieldList.getValue(dwTag).toByteArray().data(); + dwLen = m_ID3FieldList.getValue(dwTag).toByteArray().length(); + return(true); +} + +bool cMediaInfo::getTAG(uint16_t dwTag, QPixmap& Pixmap) +{ + if(dwTag >= cID3Field::TAG_MAXFIELDS) + return(false); + if(!m_ID3FieldList.isValid(dwTag)) + return(false); + + QVariant v = m_ID3FieldList.getValue(dwTag); + if(v.canConvert()) { - case MEDIA_TYPE_APE: - return("APE"); - case MEDIA_TYPE_ASF: - return("ASF"); - case MEDIA_TYPE_FLAC: - return("FLAC"); - case MEDIA_TYPE_MP4: - return("MP4"); - case MEDIA_TYPE_MPC: - return("MPC"); - case MEDIA_TYPE_MPEG: - return("MPEG"); - case MEDIA_TYPE_TRUEAUDIO: - return("TrueAudio"); - case MEDIA_TYPE_WAVPACK: - return("WavPack"); - case MEDIA_TYPE_WAV: - return("Wave"); - default: - return("unknown"); + Pixmap = v.value(); + return(true); } + return(false); } -qint32 cMediaInfo::length1() +bool cMediaInfo::getTAG(uint16_t dwTag, QString& szName, QPixmap& Pixmap) { - return(m_iLength); -} + if(dwTag >= cID3Field::TAG_MAXFIELDS) + return(false); + if(!m_ID3FieldList.isValid(dwTag)) + return(false); + szName = m_ID3FieldList.getName(dwTag); -QString cMediaInfo::length1Text() -{ - return("not implemented"); -} - -qint16 cMediaInfo::bitrate() -{ - return(m_iBitrate); -} - -QString cMediaInfo::bitrateText() -{ - return("not implemented"); -} - -qint32 cMediaInfo::sampleRate() -{ - return(m_iSampleRate); -} - -QString cMediaInfo::sampleRateText() -{ - return("not implemented"); -} - -qint16 cMediaInfo::channels() -{ - return(m_iChannels); -} - -QString cMediaInfo::channelsText() -{ - return("not implemented"); -} - -qint16 cMediaInfo::bitsPerSample() -{ - return(m_iBitsPerSample); -} - -QString cMediaInfo::bitsPerSampleText() -{ - return("not implemented"); -} - -qint16 cMediaInfo::layer() -{ - return(m_iLayer); -} - -QString cMediaInfo::layerText() -{ - return("not implemented"); -} - -qint16 cMediaInfo::version() -{ - return(m_iVersion); -} - -QString cMediaInfo::versionText() -{ - return("not implemented"); -} - -qint16 cMediaInfo::sampleWidth() -{ - return(m_iSampleWidth); -} - -QString cMediaInfo::sampleWidthText() -{ - return("not implemented"); -} - -qint64 cMediaInfo::sampleFrames() -{ - return(m_ullSampleFrames); -} - -QString cMediaInfo::sampleFramesText() -{ - return("not implemented"); -} - -bool cMediaInfo::isEncrypted() -{ - return(m_bIsEncrypted); -} - -qint16 cMediaInfo::trackGain() -{ - return(m_iTrackGain); -} - -qint16 cMediaInfo::albumGain() -{ - return(m_iAlbumGain); -} - -qint16 cMediaInfo::trackPeak() -{ - return(m_iTrackPeak); -} - -qint16 cMediaInfo::albumPeak() -{ - return(m_iAlbumPeak); -} - -bool cMediaInfo::protectionEnabled() -{ - return(m_bProtectionEnabled); -} - -cMediaInfo::CHANNEL_MODE cMediaInfo::channelMode() -{ - return(m_channelMode); -} - -QString cMediaInfo::channelModeText() -{ - switch(m_channelMode) + QVariant v = m_ID3FieldList.getValue(dwTag); + if(v.canConvert()) { - case CHANNEL_MODE_STEREO: - return("stereo"); - case CHANNEL_MODE_JOINTSTEREO: - return("joint stereo"); - case CHANNEL_MODE_MONO: - return("mono"); - case CHANNEL_MODE_DUALMONO: - return("dual mono"); - default: - return("unknown"); + Pixmap = v.value(); + return(true); } + return(false); } -bool cMediaInfo::isCopyrighted() +bool cMediaInfo::getTAG(uint16_t dwTag, cPictureList& PictureList) { - return(m_bIsCopyrighted); + if(dwTag >= cID3Field::TAG_MAXFIELDS) + return(false); + if(!m_ID3FieldList.isValid(dwTag)) + return(false); + + QVariant v = m_ID3FieldList.getValue(dwTag); + if(v.canConvert()) + { + cPictureList* lpPictureList = v.value(); + PictureList = *lpPictureList; + return(true); + } + return(false); } -bool cMediaInfo::isOriginal() +bool cMediaInfo::getTAG(uint16_t dwTag, QString& szName, cPictureList& PictureList) { - return(m_bIsOriginal); + if(dwTag >= cID3Field::TAG_MAXFIELDS) + return(false); + if(!m_ID3FieldList.isValid(dwTag)) + return(false); + szName = m_ID3FieldList.getName(dwTag); + + QVariant v = m_ID3FieldList.getValue(dwTag); + if(v.canConvert()) + { + cPictureList* lpPictureList = v.value(); + PictureList = *lpPictureList; + return(true); + } + return(false); } -QString cMediaInfo::contentGroupDescription() +uint16_t cMediaInfo::tagIDFromShortName(const QString& szTAG) { - return(m_szContentGroupDescription); + for(int z = 0;z < cID3Field::TAG_MAXFIELDS;z++) + { + if(!szTAG.compare(g_Fields[z].lpszShortName, Qt::CaseInsensitive)) + return(z); + } + return(cID3Field::TAG_MAXFIELDS); } -QString cMediaInfo::title() +cMediaInfoList::cMediaInfoList() { - return(m_szTitle); } -QString cMediaInfo::subTitle() +cMediaInfo* cMediaInfoList::add(const QString& szFileName, QObject *parent) { - return(m_szSubTitle); + cMediaInfo* lpMediaInfo = this->get(szFileName); + if(lpMediaInfo) + return(lpMediaInfo); + + lpMediaInfo = new cMediaInfo(parent); + lpMediaInfo->setFileName(szFileName); + this->append(lpMediaInfo); + return(lpMediaInfo); } -QString cMediaInfo::album() +cMediaInfo* cMediaInfoList::add(const QString& szFileName, cMediaInfo* lpMediaInfo, QObject *parent) { - return(m_szAlbum); + parent = parent; + + cMediaInfo* lpMediaInfo1 = this->get(szFileName); + if(lpMediaInfo1) + return(lpMediaInfo1); + + lpMediaInfo->setFileName(szFileName); + QFileInfo FileInfo(szFileName); + lpMediaInfo->setFileCreated(FileInfo.created()); + lpMediaInfo->setFileModified(FileInfo.lastModified()); + lpMediaInfo->setFileSize(FileInfo.size()); + lpMediaInfo->setValid(true); + + this->append(lpMediaInfo); + + return(lpMediaInfo); } -QString cMediaInfo::originalAlbum() +cMediaInfo* cMediaInfoList::get(const QString& szFileName) { - return(m_szOriginalAlbum); -} + int iIndex; -QString cMediaInfo::trackNumber() -{ - return(m_szTrackNumber); + for(iIndex = 0;iIndex < this->count();iIndex++) + { + if(!this->at(iIndex)->getFileName().compare(szFileName, Qt::CaseInsensitive)) + return(this->at(iIndex)); + } + return(0); } - -QString cMediaInfo::partOfSet() -{ - return(m_szPartOfSet); -} - -QString cMediaInfo::subTitleOfSet() -{ - return(m_szSubTitleOfSet); -} - -QString cMediaInfo::internationalStandardRecordingCode() -{ - return(m_szInternationalStandardRecordingCode); -} - -QString cMediaInfo::leadArtist() -{ - return(m_szLeadArtist); -} - -QString cMediaInfo::band() -{ - return(m_szBand); -} - -QString cMediaInfo::conductor() -{ - return(m_szConductor); -} - -QStringList cMediaInfo::interpret() -{ - return(m_szInterpret); -} - -QString cMediaInfo::originalArtist() -{ - return(m_szOriginalArtist); -} - -QString cMediaInfo::textWriter() -{ - return(m_szTextWriter); -} - -QString cMediaInfo::originalTextWriter() -{ - return(m_szOriginalTextWriter); -} - -QString cMediaInfo::composer() -{ - return(m_szComposer); -} - -QString cMediaInfo::encodedBy() -{ - return(m_szEncodedBy); -} - -qint16 cMediaInfo::beatsPerMinute() -{ - return(m_iBeatsPerMinute); -} - -qint32 cMediaInfo::length() -{ - return(m_iLength); -} - -QStringList cMediaInfo::language() -{ - return(m_szLanguage); -} - -QStringList cMediaInfo::contentType() -{ - return(m_szContentType); -} - -QString cMediaInfo::fileType() -{ - return(m_szFileType); -} - -QStringList cMediaInfo::mediaType() -{ - return(m_szMediaType); -} - -QString cMediaInfo::mood() -{ - return(m_szMood); -} - -QString cMediaInfo::copyright() -{ - return(m_szCopyright); -} - -QString cMediaInfo::producedNotice() -{ - return(m_szProducedNotice); -} - -QString cMediaInfo::publisher() -{ - return(m_szPublisher); -} - -QString cMediaInfo::fileOwner() -{ - return(m_szFileOwner); -} - -QString cMediaInfo::internetRadioStationName() -{ - return(m_szInternetRadioStationName); -} - -QString cMediaInfo::internetRadioStationOwner() -{ - return(m_szInternetRadioStationOwner); -} - -QString cMediaInfo::originalFilename() -{ - return(m_szOriginalFilename); -} - -qint32 cMediaInfo::playlistDelay() -{ - return(m_iPlaylistDelay); -} - -QDateTime cMediaInfo::encodingTime() -{ - return(m_encodingTime); -} - -QDateTime cMediaInfo::originalReleaseTime() -{ - return(m_originalReleaseTime); -} - -QDateTime cMediaInfo::recordingTime() -{ - return(m_recordingTime); -} - -QDateTime cMediaInfo::releaseTime() -{ - return(m_releaseTime); -} - -QDateTime cMediaInfo::taggingTime() -{ - return(m_taggingTime); -} - -QStringList cMediaInfo::swhwSettings() -{ - return(m_szswhwSettings); -} - -QString cMediaInfo::albumSortOrder() -{ - return(m_szAlbumSortOrder); -} - -QString cMediaInfo::performerSortOrder() -{ - return(m_szPerformerSortOrder); -} - -QString cMediaInfo::titleSortOrder() -{ - return(m_szTitleSortOrder); -} - -cStringTimeList cMediaInfo::synchronizedLyrics() -{ - return(m_szSynchronizedLyrics); -} - -QStringList cMediaInfo::unsynchronizedLyrics() -{ - return(m_szUnsynchronizedLyrics); -} - -cPixmapList cMediaInfo::pixmaps() -{ - return(m_pixmapList); -} - -/* - * http://de.wikipedia.org/wiki/ID3-Tag - * http://id3.org/id3v2.4.0-frames - * http://id3.org/id3v2.4.0-structure -*/ diff --git a/cmediainfo.h b/cmediainfo.h index 096b706..05ff451 100644 --- a/cmediainfo.h +++ b/cmediainfo.h @@ -1,296 +1,130 @@ #ifndef CMEDIAINFO_H #define CMEDIAINFO_H + #include - -#include -#include -#include +#include #include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "ctag.h" -#include "cstring.h" -#include "cpixmap.h" +#include +#include "libid3tag/id3tag.h" +#include "cid3field.h" -using namespace TagLib; +#define WITH_PICTURE + class cMediaInfo : public QObject { - Q_OBJECT +Q_OBJECT public: - enum MEDIA_TYPE - { - MEDIA_TYPE_UNKNOWN = 0, - MEDIA_TYPE_APE = 1, // APE - MEDIA_TYPE_ASF = 2, // WMA - MEDIA_TYPE_FLAC = 3, // FLAC - MEDIA_TYPE_MP4 = 4, // AAC, MP4, M4A - MEDIA_TYPE_MPC = 5, // MPC - MEDIA_TYPE_MPEG = 6, // MP1, MP2, MP3 - MEDIA_TYPE_TRUEAUDIO = 7, // TTA - MEDIA_TYPE_WAVPACK = 8, // WV - MEDIA_TYPE_WAV = 9, // WAV - }; - enum CHANNEL_MODE - { - CHANNEL_MODE_UNKNOWN = 0, - CHANNEL_MODE_STEREO = 1, - CHANNEL_MODE_JOINTSTEREO = 2, - CHANNEL_MODE_MONO = 3, - CHANNEL_MODE_DUALMONO = 4 - }; - - explicit cMediaInfo(bool bAPE = true, bool bID3V1 = true, bool bID3V2 = true, bool bProperties = true, QObject *parent = 0); + explicit cMediaInfo(QObject *parent = 0); ~cMediaInfo(); - bool readFromFile(const QString& szFileName); - bool readFromDB(); - bool writeToDB(); - - bool isValid(); - - // - QString fileName(); - qint64 fileSize(); - QDateTime fileDate(); - MEDIA_TYPE fileType1(); - QString fileType1Text(); - - // - qint32 length1(); - QString length1Text(); - qint16 bitrate(); - QString bitrateText(); - qint32 sampleRate(); - QString sampleRateText(); - qint16 channels(); - QString channelsText(); - qint16 bitsPerSample(); - QString bitsPerSampleText(); - qint16 layer(); - QString layerText(); - qint16 version(); - QString versionText(); - qint16 sampleWidth(); - QString sampleWidthText(); - qint64 sampleFrames(); - QString sampleFramesText(); - bool isEncrypted(); - qint16 trackGain(); - qint16 albumGain(); - qint16 trackPeak(); - qint16 albumPeak(); - bool protectionEnabled(); - CHANNEL_MODE channelMode(); - QString channelModeText(); - bool isCopyrighted(); - bool isOriginal(); - - // Identification Frames - QString contentGroupDescription(); // TIT1 - QString title(); // TIT2 - QString subTitle(); // TIT3 - QString album(); // TALB - QString originalAlbum(); // TOAL - QString trackNumber(); // TRCK - QString partOfSet(); // TPOS - QString subTitleOfSet(); // TSST - QString internationalStandardRecordingCode(); // TSRC - - // Involved Persons Frames - QString leadArtist(); // TPE1 - QString band(); // TPE2 - QString conductor(); // TPE3 - QStringList interpret(); // TPE4 - QString originalArtist(); // TOPE - QString textWriter(); // TEXT - QString originalTextWriter(); // TOLY - QString composer(); // TCOM - //cString21List musicianCredits(); // TMCL - //cString21List involvedPeople(); // TIPL - QString encodedBy(); // TENC - - // Derived and subjective properties frames - qint16 beatsPerMinute(); // TBPM - qint32 length(); // TLEN - // TKEY - QStringList language(); // TLAN - QStringList contentType(); // TCON - QString fileType(); // TFLT - QStringList mediaType(); // TMED - QString mood(); // TMOO - - // Rights and license frames - QString copyright(); // TCOP - QString producedNotice(); // TPRO - QString publisher(); // TPUB - QString fileOwner(); // TOWN - QString internetRadioStationName(); // TRSN - QString internetRadioStationOwner(); // TRSO - - // Other text frames - QString originalFilename(); // TOFN - qint32 playlistDelay(); // TDLY - QDateTime encodingTime(); // TDEN - QDateTime originalReleaseTime(); // TDOR - QDateTime recordingTime(); // TDRC - QDateTime releaseTime(); // TDRL - QDateTime taggingTime(); // TDTG - QStringList swhwSettings(); // TSSE - QString albumSortOrder(); // TSOA - QString performerSortOrder(); // TSOP - QString titleSortOrder(); // TSOT - - cStringTimeList synchronizedLyrics(); // SYLT - QStringList unsynchronizedLyrics(); // USLT - - cPixmapList pixmaps(); // APIC -signals: - -public slots: - -protected: - bool m_bAPE; - bool m_bID3V1; - bool m_bID3V2; - bool m_bProperties; - bool m_bIsValid; - QString m_szFileName; - MEDIA_TYPE m_fileType; - - qint32 m_iLength; - qint16 m_iBitrate; - qint32 m_iSampleRate; - qint16 m_iChannels; - qint16 m_iBitsPerSample; - qint16 m_iLayer; - qint16 m_iVersion; - qint16 m_iSampleWidth; - qint64 m_ullSampleFrames; - bool m_bIsEncrypted; - qint16 m_iTrackGain; - qint16 m_iAlbumGain; - qint16 m_iTrackPeak; - qint16 m_iAlbumPeak; - bool m_bProtectionEnabled; - CHANNEL_MODE m_channelMode; - bool m_bIsCopyrighted; - bool m_bIsOriginal; - - // ID3V1 - QStringList m_szAlbumArtistList; - QStringList m_szArtistList; - QString m_szComment; - QStringList m_szComposerList; - QStringList m_szGenreList; - QString m_szRating; - qint16 m_iYear; - - // Identification Frames - QString m_szContentGroupDescription; // TIT1 - QString m_szTitle; // TIT2 - QString m_szSubTitle; // TIT3 - QString m_szAlbum; // TALB - QString m_szOriginalAlbum; // TOAL - QString m_szTrackNumber; // TRCK - QString m_szPartOfSet; // TPOS - QString m_szSubTitleOfSet; // TSST - QString m_szInternationalStandardRecordingCode; // TSRC - - // Involved Persons Frames - QString m_szLeadArtist; // TPE1 - QString m_szBand; // TPE2 - QString m_szConductor; // TPE3 - QStringList m_szInterpret; // TPE4 - QString m_szOriginalArtist; // TOPE - QString m_szTextWriter; // TEXT - QString m_szOriginalTextWriter; // TOLY - QString m_szComposer; // TCOM - QString m_szEncodedBy; // TENC - - // Derrived and subjective properties frames - qint16 m_iBeatsPerMinute; // TBPM -// qint16 m_iLength; // TLEN - // TKEY - QStringList m_szLanguage; // TLAN - QStringList m_szContentType; // TCON - QString m_szFileType; // TFLT - QStringList m_szMediaType; // TMED - QString m_szMood; // TMOO - - // Rights and license frames - QString m_szCopyright; // TCOP - QString m_szProducedNotice; // TPRO - QString m_szPublisher; // TPUB - QString m_szFileOwner; // TOWN - QString m_szInternetRadioStationName; // TRSN - QString m_szInternetRadioStationOwner; // TRSO - - // Other text frames - QString m_szOriginalFilename; // TOFN - qint32 m_iPlaylistDelay; // TDLY - QDateTime m_encodingTime; // TDEN - QDateTime m_originalReleaseTime; // TDOR - QDateTime m_recordingTime; // TDRC - QDateTime m_releaseTime; // TDRL - QDateTime m_taggingTime; // TDTG - QStringList m_szswhwSettings; // TSSE - QString m_szAlbumSortOrder; // TSOA - QString m_szPerformerSortOrder; // TSOP - QString m_szTitleSortOrder; // TSOT - - cStringTimeList m_szSynchronizedLyrics; // SYLT - QString m_szSynchronizedLyricsLanguage; - QString m_szSynchronizedLyricsDescription; - QStringList m_szUnsynchronizedLyrics; // USLT - QString m_szUnsynchronizedLyricsLanguage; - QString m_szUnsynchronizedLyricsDescription; - - //ID3V2 - qint32 m_iID3v2Version; - qint32 m_iID3v2Revision; - qint32 m_iID3v2Size; - //cTAGList m_TAGv2List; - cTAGList m_TAGAPEList; - cTAGList m_TAGPropertiesList; - - cPixmapList m_pixmapList; - void clear(); - void readTagV1(ID3v1::Tag* lpTag); - void readTagV2(ID3v2::Tag* lpTag); - void readTagAPE(APE::Tag* lpTag); - void readTagProperties(TagLib::PropertyMap& tags); + void importFromFile(const QString& szFileName); - QDateTime str2TS(const QString& sz); + void setFileName(const QString& szFileName); + QString getFileName(); - qint32 writeFilename(); + void setFileCreated(const QDateTime& FileCreated); + QDateTime getFileCreated(); + + void setFileModified(const QDateTime& FileModified); + QDateTime getFileModified(); + + void setFileSize(uint64_t dwFileSize); + uint64_t getFileSize(); + + QString getTAGName(uint16_t dwTag); + QString getTAGShortName(uint16_t dwTag); + + void setBitrate(uint16_t dwBitrate); + uint16_t getBitrate(); + + void setSamplerate(uint16_t dwSamplerate); + uint16_t getSamplerate(); + + void setChannels(uint16_t dwChannels); + uint16_t getChannels(); + + void setSeconds(uint16_t dwSeconds); + uint16_t getSeconds(); + + void setMPEG(uint16_t dwMPEG); + uint16_t getMPEG(); + + void setVersion(uint16_t dwVersion); + uint16_t getVersion(); + + void setLayerVersion(uint16_t dwLayerVersion); + uint16_t getLayerVersion(); + + void setMode(uint16_t dwMode); + uint16_t getMode(); + + void setValid(bool bValid); + bool getValid(); + + void setTAG(uint16_t dwTag, uint16_t dwData); + void setTAG(uint16_t dwTag, const QString& szData); + void setTAG(uint16_t dwTag, const QVariant& v); + QVariant getTAG(uint16_t dwTag); + uint16_t getTAGi(uint16_t dwTag); + QString getTAGs(uint16_t dwTag); + bool getTAG(uint16_t dwTag, QString& szData); + bool getTAG(uint16_t dwTag, QString& szName, QString& szData); + bool getTAG(uint16_t dwTag, uint16_t& dwData); + bool getTAG(uint16_t dwTag, QString& szName, uint16_t& dwData); + bool getTAG(uint16_t dwTag, id3_byte_t* dwData, uint32_t& dwLen); + bool getTAG(uint16_t dwTag, QString& szName, id3_byte_t* dwData, uint32_t& dwLen); + bool getTAG(uint16_t dwTag, QPixmap& Pixmap); + bool getTAG(uint16_t dwTag, QString& szName, QPixmap& Pixmap); + bool getTAG(uint16_t dwTag, cPictureList& PictureList); + bool getTAG(uint16_t dwTag, QString& szName, cPictureList& PictureList); + + static uint16_t tagIDFromShortName(const QString& szTAG); +protected: + QString m_szFileName; + QDateTime m_FileCreated; + QDateTime m_FileModified; + uint64_t m_dwFileSize; + cID3FieldList m_ID3FieldList; + uint16_t m_dwBitrate; + uint16_t m_dwSamplerate; + uint16_t m_dwChannels; + uint16_t m_dwSeconds; + uint16_t m_dwMPEG; + uint16_t m_dwVersion; + uint16_t m_dwLayerVersion; + uint16_t m_dwMode; + bool m_bValid; + + void readFileInformation(const QString& szFileName); + void importInformation(struct id3_tag* lpTag); + uint16_t tagID(char* lpszTagName); + QString tag2String(struct id3_frame* lpID3Frame, uint16_t dwField); + QString tag2LyricsString(struct id3_frame* lpID3Frame); + + void initFields(); +signals: + +public slots: +}; + +Q_DECLARE_METATYPE(cMediaInfo*); + +class cMediaInfoList : public QList +{ +public: + cMediaInfoList(); + + cMediaInfo* add(const QString& szFileName, QObject *parent = 0); + cMediaInfo* add(const QString& szFileName, cMediaInfo* lpMediaInfo, QObject *parent = 0); + cMediaInfo* get(const QString& szFileName); + +protected: + void initFields(); }; #endif // CMEDIAINFO_H diff --git a/cpicture.cpp b/cpicture.cpp new file mode 100644 index 0000000..568f1bd --- /dev/null +++ b/cpicture.cpp @@ -0,0 +1,158 @@ +#include "cpicture.h" + + +cPicture::cPicture() +{ +} + +cPicture::cPicture(const QPixmap& Pixmap, uint16_t dwType, const QString& szDescription) : + m_Pixmap(Pixmap), m_dwType(dwType), m_szDescription(szDescription) +{ +} + +void cPicture::setPixmap(const QPixmap& Pixmap) +{ + m_Pixmap = Pixmap; +} + +QPixmap cPicture::getPixmap() +{ + return(m_Pixmap); +} + +void cPicture::setType(uint16_t dwType) +{ + m_dwType = dwType; +} + +uint16_t cPicture::getType() +{ + return(m_dwType); +} + +void cPicture::setDescription(const QString& szDescription) +{ + m_szDescription = szDescription; +} + +QString cPicture::getDescription() +{ + return(m_szDescription); +} + +QString cPicture::type(uint16_t dwType) +{ + switch(dwType) + { + case TYPE_OTHER: + return("Other"); + case TYPE_ICON: + return("32x32 pixels 'file icon' (PNG only)"); + case TYPE_OTHER_ICON: + return("Other file icon"); + case TYPE_COVER_FRONT: + return("Cover (front)"); + case TYPE_COVER_BACK: + return("Cover (back)"); + case TYPE_LEAFLET: + return("Leaflet page"); + case TYPE_MEDIA: + return("Media (e.g. label side of CD)"); + case TYPE_LEAD_ARTIST: + return("Lead artist/lead performer/soloist"); + case TYPE_ARTIST: + return("Artist/performer"); + case TYPE_CONDUCTOR: + return("Conductor"); + case TYPE_BAND: + return("Band/Orchestra"); + case TYPE_COMPOSER: + return("Composer"); + case TYPE_LYRICIST: + return("Lyricist/text writer"); + case TYPE_RECORDING_LOCATION: + return("Recording Location"); + case TYPE_DURING_RECORDING: + return("During recording"); + case TYPE_DURING_PERFORMANCE: + return("During performance"); + case TYPE_SCREEN_CAPTURE: + return("Movie/video screen capture"); + case TYPE_COLOURED_FISH: + return("A bright coloured fish"); + case TYPE_ILLUSTRATION: + return("Illustration"); + case TYPE_BAND_LOGOTYPE: + return("Band/artist logotype"); + case TYPE_PUBLISHER_LOGOTYPE: + return("Publisher/Studio logotype"); + default: + return("Unknown"); + } +} + +uint16_t cPicture::type(const QString& szType) +{ + if(!szType.compare("Other", Qt::CaseInsensitive)) + return(TYPE_OTHER); + if(!szType.compare("32x32 pixels 'file icon' (PNG only)", Qt::CaseInsensitive)) + return(TYPE_ICON); + if(!szType.compare("Other file icon", Qt::CaseInsensitive)) + return(TYPE_OTHER_ICON); + if(!szType.compare("Cover (front)", Qt::CaseInsensitive)) + return(TYPE_COVER_FRONT); + if(!szType.compare("Cover (back)", Qt::CaseInsensitive)) + return(TYPE_COVER_BACK); + if(!szType.compare("Leaflet page", Qt::CaseInsensitive)) + return(TYPE_LEAFLET); + if(!szType.compare("Media (e.g. label side of CD)", Qt::CaseInsensitive)) + return(TYPE_MEDIA); + if(!szType.compare("Lead artist/lead performer/soloist", Qt::CaseInsensitive)) + return(TYPE_LEAD_ARTIST); + if(!szType.compare("Artist/performer", Qt::CaseInsensitive)) + return(TYPE_ARTIST); + if(!szType.compare("Conductor", Qt::CaseInsensitive)) + return(TYPE_CONDUCTOR); + if(!szType.compare("Band/Orchestra", Qt::CaseInsensitive)) + return(TYPE_BAND); + if(!szType.compare("Composer", Qt::CaseInsensitive)) + return(TYPE_COMPOSER); + if(!szType.compare("Lyricist/text writer", Qt::CaseInsensitive)) + return(TYPE_LYRICIST); + if(!szType.compare("Recording Location", Qt::CaseInsensitive)) + return(TYPE_RECORDING_LOCATION); + if(!szType.compare("During recording", Qt::CaseInsensitive)) + return(TYPE_DURING_RECORDING); + if(!szType.compare("During performance", Qt::CaseInsensitive)) + return(TYPE_DURING_PERFORMANCE); + if(!szType.compare("Movie/video screen capture", Qt::CaseInsensitive)) + return(TYPE_SCREEN_CAPTURE); + if(!szType.compare("A bright coloured fish", Qt::CaseInsensitive)) + return(TYPE_COLOURED_FISH); + if(!szType.compare("Illustration", Qt::CaseInsensitive)) + return(TYPE_ILLUSTRATION); + if(!szType.compare("Band/artist logotype", Qt::CaseInsensitive)) + return(TYPE_BAND_LOGOTYPE); + if(!szType.compare("Publisher/Studio logotype", Qt::CaseInsensitive)) + return(TYPE_PUBLISHER_LOGOTYPE); + return(9999); +} + +cPicture& cPicture::operator=(const cPicture& rhs) +{ + m_Pixmap = rhs.m_Pixmap; + m_dwType = rhs.m_dwType; + m_szDescription = rhs.m_szDescription; + return(*this); +} + +cPictureList::cPictureList() +{ +} + +cPicture cPictureList::add(const QPixmap& Pixmap, uint16_t dwType, const QString& szDescription) +{ + cPicture picture(Pixmap, dwType, szDescription); + this->append(picture); + return(picture); +} diff --git a/cpicture.h b/cpicture.h new file mode 100644 index 0000000..7315bad --- /dev/null +++ b/cpicture.h @@ -0,0 +1,77 @@ +#ifndef cPicture_H +#define cPicture_H + +#include +#include +#include +#include + + +class cPicture +{ +public: + enum TYPE + { + TYPE_OTHER, + TYPE_ICON, + TYPE_OTHER_ICON, + TYPE_COVER_FRONT, + TYPE_COVER_BACK, + TYPE_LEAFLET, + TYPE_MEDIA, + TYPE_LEAD_ARTIST, + TYPE_ARTIST, + TYPE_CONDUCTOR, + TYPE_BAND, + TYPE_COMPOSER, + TYPE_LYRICIST, + TYPE_RECORDING_LOCATION, + TYPE_DURING_RECORDING, + TYPE_DURING_PERFORMANCE, + TYPE_SCREEN_CAPTURE, + TYPE_COLOURED_FISH, + TYPE_ILLUSTRATION, + TYPE_BAND_LOGOTYPE, + TYPE_PUBLISHER_LOGOTYPE, + }; + + explicit cPicture(); + explicit cPicture(const QPixmap& Pixmap, uint16_t dwType, const QString& szDescription); + + void setPixmap(const QPixmap& Pixmap); + QPixmap getPixmap(); + + void setType(uint16_t dwType); + uint16_t getType(); + + void setDescription(const QString& szDescription); + QString getDescription(); + + cPicture& operator=(const cPicture& rhs); + + static QString type(uint16_t dwType); + static uint16_t type(const QString& szType); +protected: + QPixmap m_Pixmap; + uint16_t m_dwType; + QString m_szDescription; + +signals: + +public slots: + +}; + +Q_DECLARE_METATYPE(cPicture) + + +class cPictureList : public QList +{ +public: + cPictureList(); + cPicture add(const QPixmap& Pixmap, uint16_t dwType, const QString& szDescription); +}; + +Q_DECLARE_METATYPE(cPictureList*) + +#endif // cPicture_H diff --git a/cpixmap.cpp b/cpixmap.cpp deleted file mode 100644 index 40b31c9..0000000 --- a/cpixmap.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include "cpixmap.h" -#include "common.h" - -#include - - -cPixmap::cPixmap() : - QPixmap() -{ -} - -cPixmap::cPixmap(const QByteArray& array, const QString& szFileName, const cPixmap::ImageType& imageType, const QString& szDescription) : -// QPixmap(QPixmap::loadFromData(array)), - m_szFileName(szFileName), - m_ImageType(imageType), - m_szDescription(szDescription) -{ - loadFromData(array); -} - -QString cPixmap::fileName() -{ - return(m_szFileName); -} - -cPixmap::ImageType cPixmap::imageType() -{ - return(m_ImageType); -} - -QString cPixmap::description() -{ - return(m_szDescription); -} - -cPixmapList::cPixmapList() -{ -} - -cPixmap cPixmapList::add(const QByteArray &array, const QString& szFileName, const cPixmap::ImageType& imageType, const QString& szDescription) -{ - cPixmap image(array, szFileName, imageType, szDescription); - append(image); - return(image); -} diff --git a/cpixmap.h b/cpixmap.h deleted file mode 100644 index b514b3b..0000000 --- a/cpixmap.h +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef CPIXMAP_H -#define CPIXMAP_H - -#include -#include -#include - - -class cPixmap : public QPixmap -{ -public: - enum ImageType - { - Other = 0x00, - FileIcon = 0x01, - OtherFileIcon = 0x02, - FrontCover = 0x03, - BackCover = 0x04, - LeafletPage = 0x05, - Media = 0x06, - LeadArtist = 0x07, - Artist = 0x08, - Conductor = 0x09, - Band = 0x0A, - Composer = 0x0B, - Lyricist = 0x0C, - RecordingLocation = 0x0D, - DuringRecording = 0x0E, - DuringPerformance = 0x0F, - MovieScreenCapture = 0x10, - ColouredFish = 0x11, - Illustration = 0x12, - BandLogo = 0x13, - PublisherLogo = 0x14 - }; - cPixmap(); - cPixmap(const QByteArray& array, const QString& szFileName, const cPixmap::ImageType& imageType, const QString& szDescription); - - QString fileName(); - ImageType imageType(); - QString description(); -protected: - QString m_szFileName; - ImageType m_ImageType; - QString m_szDescription; - -signals: - -public slots: - -}; - -Q_DECLARE_METATYPE(cPixmap) - -class cPixmapList : public QList -{ -public: - cPixmapList(); - cPixmap add(const QByteArray& array, const QString& szFileName, const cPixmap::ImageType& imageType, const QString& szDescription); -}; - -#endif // CPIXMAP_H diff --git a/cstring.cpp b/cstring.cpp deleted file mode 100644 index 88604b1..0000000 --- a/cstring.cpp +++ /dev/null @@ -1,69 +0,0 @@ -#include "cstring.h" - - -cStringTime::cStringTime() -{ -} - -cStringTime::cStringTime(const qint32& iTime, const QString& szString) : - m_iTime(iTime), - m_szString(szString) -{ -} - -qint32 cStringTime::time() -{ - return(m_iTime); -} - -QString cStringTime::string() -{ - return(m_szString); -} - -cStringTimeList::cStringTimeList() -{ -} - -cStringTime* cStringTimeList::add(const qint32& iTime, const QString& szString) -{ - cStringTime* lpNew = new cStringTime(iTime, szString); - append(lpNew); - return(lpNew); -} - -QString cStringTimeList::join() -{ - QStringList szList; - QString str; - - for(int x = 0;x < count();x++) - { - str = QString::number(at(x)->time()) + "|" + at(x)->string(); - szList.append(str); - } - return(szList.join("||")); -} - -cString21::cString21() : - m_szLeft(QStringList()), - m_szRight("") -{ -} - -cString21::cString21(const QStringList& szLeft, const QString& szRight) : - m_szLeft(szLeft), - m_szRight(szRight) -{ -} - -cString21List::cString21List() -{ -} - -cString21* cString21List::add(const QStringList& szLeft, const QString& szRight) -{ - cString21* lpNew = new cString21(szLeft, szRight); - append(lpNew); - return(lpNew); -} diff --git a/cstring.h b/cstring.h deleted file mode 100644 index 4b0514a..0000000 --- a/cstring.h +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef CSTRING_H -#define CSTRING_H - -#include -#include -#include -#include - - -class cStringTime -{ -public: - explicit cStringTime(); - explicit cStringTime(const qint32& iTime, const QString& szString); - - qint32 time(); - QString string(); -protected: - qint32 m_iTime; - QString m_szString; -signals: - -public slots: -}; - -Q_DECLARE_METATYPE(cStringTime) - -class cStringTimeList : public QList -{ -public: - cStringTimeList(); - cStringTime* add(const qint32& iTime, const QString& szString); - QString join(); -}; - - -class cString21 -{ -public: - explicit cString21(); - explicit cString21(const QStringList& szLeft, const QString& szRight); -protected: - QStringList m_szLeft; - QString m_szRight; -signals: - -public slots: - -}; - -Q_DECLARE_METATYPE(cString21) - -class cString21List : public QList -{ -public: - cString21List(); - cString21* add(const QStringList& szLeft, const QString& szRight); -}; - -#endif // CSTRING_H diff --git a/ctag.cpp b/ctag.cpp deleted file mode 100644 index e075c0d..0000000 --- a/ctag.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include "ctag.h" - - -cTAG::cTAG() -{ - m_szTAG = ""; - m_szValue.clear(); -} - -cTAG::cTAG(const QString& szTAG, const QString& szValue) -{ - m_szTAG = szTAG; - m_szValue = szValue.split("\n"); -} - -cTAG::cTAG(const QString& szTAG, const QStringList& szValue) -{ - m_szTAG = szTAG; - m_szValue = szValue; -} - -QString cTAG::tag() -{ - return(m_szTAG); -} - -QStringList cTAG::valueList() -{ - return(m_szValue); -} - -cTAGList::cTAGList() -{ -} - -cTAG* cTAGList::add(const QString& szTAG, const QString& szValue) -{ - cTAG* lpTag = new cTAG(szTAG, szValue); - append(lpTag); - return(lpTag); -} - -cTAG* cTAGList::add(const QString& szTAG, const QStringList& szValue) -{ - cTAG* lpTag = new cTAG(szTAG, szValue); - append(lpTag); - return(lpTag); -} diff --git a/ctag.h b/ctag.h deleted file mode 100644 index e7d0055..0000000 --- a/ctag.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef CTAG_H -#define CTAG_H - -#include -#include -#include -#include - - -class cTAG -{ -public: - explicit cTAG(); - explicit cTAG(const QString& szTAG, const QString& szValue); - explicit cTAG(const QString& szTAG, const QStringList& szValue); - - QString tag(); - QStringList valueList(); -protected: - QString m_szTAG; - QStringList m_szValue; -signals: - -public slots: - -}; - -Q_DECLARE_METATYPE(cTAG) - -class cTAGList : public QList -{ -public: - cTAGList(); - cTAG* add(const QString& szTAG, const QString& szValue); - cTAG* add(const QString& szTAG, const QStringList& szValue); -}; - -#endif // CTAG_H diff --git a/fields.h b/fields.h new file mode 100644 index 0000000..61df178 --- /dev/null +++ b/fields.h @@ -0,0 +1,104 @@ +#ifndef FIELDS_H +#define FIELDS_H + + +#include "cid3field.h" + + +typedef struct tagFIELDS +{ + uint16_t dwID; + const char* lpszShortName; + const char* lpszName; +} FIELDS, *LPFIELDS; + + +FIELDS g_Fields[] = +{ + { cID3Field::TAG_AudioEncryption, "AENC", "Audio encryption" }, + { cID3Field::TAG_AttachedPicture, "APIC", "Attached picture" }, + { cID3Field::TAG_AudioSeekPointIndex, "ASPI", "Audio seek point index" }, + { cID3Field::TAG_Comments, "COMM", "Comments" }, + { cID3Field::TAG_CommercialFrame, "COMR", "Commercial frame" }, + { cID3Field::TAG_EncryptionMethodRegistration, "ENCR", "Encryption method registration" }, + { cID3Field::TAG_Equalisation, "EQU2", "Equalisation (2)" }, + { cID3Field::TAG_EventTimingCodes, "ETCO", "Event timing codes" }, + { cID3Field::TAG_GeneralEncapsulatedObject, "GEOB", "General encapsulated object" }, + { cID3Field::TAG_GroupIdentificationRegistration, "GRID", "Group identification registration" }, + { cID3Field::TAG_LinkedInformation, "LINK", "Linked information" }, + { cID3Field::TAG_MusicCDIdentifier, "MCDI", "Music CD identifier" }, + { cID3Field::TAG_MPEGLocationLookupTable, "MLLT", "MPEG location lookup table" }, + { cID3Field::TAG_OwnershipFrame, "OWNE", "Ownership frame" }, + { cID3Field::TAG_PrivateFrame, "PRIV", "Private frame" }, + { cID3Field::TAG_PlayCounter, "PCNT", "Play counter" }, + { cID3Field::TAG_Popularimeter, "POPM", "Popularimeter" }, + { cID3Field::TAG_PositionSynchronisationFrame, "POSS", "Position synchronisation frame" }, + { cID3Field::TAG_RecommendedBufferSize, "RBUF", "Recommended buffer size" }, + { cID3Field::TAG_RelativeVolumeAdjustment, "RVA2", "Relative volume adjustment (2)" }, + { cID3Field::TAG_Reverb, "RVRB", "Reverb" }, + { cID3Field::TAG_SeekFrame, "SEEK", "Seek frame" }, + { cID3Field::TAG_SignatureFrame, "SIGN", "Signature frame" }, + { cID3Field::TAG_SynchronisedLyric, "SYLT", "Synchronised lyric/text" }, + { cID3Field::TAG_SynchronisedTempoCodes, "SYTC", "Synchronised tempo codes" }, + { cID3Field::TAG_Album, "TALB", "Album/Movie/Show title" }, + { cID3Field::TAG_BeatsPerMinute, "TBPM", "BPM (beats per minute)" }, + { cID3Field::TAG_Composer, "TCOM", "Composer" }, + { cID3Field::TAG_ContentType, "TCON", "Content type" }, + { cID3Field::TAG_CopyrightMessage, "TCOP", "Copyright message" }, + { cID3Field::TAG_EncodingTime, "TDEN", "Encoding time" }, + { cID3Field::TAG_PlaylistDelay, "TDLY", "Playlist delay" }, + { cID3Field::TAG_OriginalReleaseTime, "TDOR", "Original release time" }, + { cID3Field::TAG_RecordingTime, "TDRC", "Recording time" }, + { cID3Field::TAG_ReleaseTime, "TDRL", "Release time" }, + { cID3Field::TAG_TaggingTime, "TDTG", "Tagging time" }, + { cID3Field::TAG_EncodedBy, "TENC", "Encoded by" }, + { cID3Field::TAG_Lyricist, "TEXT", "Lyricist/Text writer" }, + { cID3Field::TAG_FileType, "TFLT", "File type" }, + { cID3Field::TAG_InvolvedPeopleList, "TIPL", "Involved people list" }, + { cID3Field::TAG_ContentGroupDescription, "TIT1", "Content group description" }, + { cID3Field::TAG_Title, "TIT2", "Title/songname/content description" }, + { cID3Field::TAG_Subtitle, "TIT3", "Subtitle/Description refinement" }, + { cID3Field::TAG_InitialKey, "TKEY", "Initial key" }, + { cID3Field::TAG_Languages, "TLAN", "Language(s)" }, + { cID3Field::TAG_Length, "TLEN", "Length" }, + { cID3Field::TAG_MusicianCreditsList, "TMCL", "Musician credits list" }, + { cID3Field::TAG_MediaType, "TMED", "Media type" }, + { cID3Field::TAG_Mood, "TMOO", "Mood" }, + { cID3Field::TAG_OriginalAlbum, "TOAL", "Original album/movie/show title" }, + { cID3Field::TAG_OriginalFileName, "TOFN", "Original filename" }, + { cID3Field::TAG_OriginalLyricist, "TOLY", "Original lyricist(s)/text writer(s)" }, + { cID3Field::TAG_OriginalArtist, "TOPE", "Original artist(s)/performer(s)" }, + { cID3Field::TAG_FileOwner, "TOWN", "File owner/licensee" }, + { cID3Field::TAG_LeadPerformer, "TPE1", "Lead performer(s)/Soloist(s)" }, + { cID3Field::TAG_Band, "TPE2", "Band/orchestra/accompaniment" }, + { cID3Field::TAG_Conductor, "TPE3", "Conductor/performer refinement" }, + { cID3Field::TAG_InterpretedBy, "TPE4", "Interpreted, remixed, or otherwise modified by" }, + { cID3Field::TAG_PartOfASet, "TPOS", "Part of a set" }, + { cID3Field::TAG_ProducedNotice, "TPRO", "Produced notice" }, + { cID3Field::TAG_Publisher, "TPUB", "Publisher" }, + { cID3Field::TAG_TrackNumber, "TRCK", "Track number/Position in set" }, + { cID3Field::TAG_InternetRadioStationName, "TRSN", "Internet radio station name" }, + { cID3Field::TAG_InternetRadioStationOwner, "TRSO", "Internet radio station owner" }, + { cID3Field::TAG_AlbumSortOrder, "TSOA", "Album sort order" }, + { cID3Field::TAG_PerformerSortOrder, "TSOP", "Performer sort order" }, + { cID3Field::TAG_TitleSortOrder, "TSOT", "Title sort order" }, + { cID3Field::TAG_InternationalStandardRecordingCode, "TSRC", "ISRC (international standard recording code)" }, + { cID3Field::TAG_Software_Hardware, "TSSE", "Software/Hardware and settings used for encoding" }, + { cID3Field::TAG_SetSubtitle, "TSST", "Set subtitle" }, + { cID3Field::TAG_UserDefinedTextInformation, "TXXX", "User defined text information frame" }, + { cID3Field::TAG_UniqueFileIdentifier, "UFID", "Unique file identifier" }, + { cID3Field::TAG_TermsOfUse, "USER", "Terms of use" }, + { cID3Field::TAG_UnsynchronizedLyric, "USLT", "Unsynchronised lyric/text transcription" }, + { cID3Field::TAG_CommercialInformation, "WCOM", "Commercial information" }, + { cID3Field::TAG_LegalInformation, "WCOP", "Copyright/Legal information" }, + { cID3Field::TAG_OfficialAudioFileWebpage, "WOAF", "Official audio file webpage" }, + { cID3Field::TAG_OfficialArtistWebpage, "WOAR", "Official artist/performer webpage" }, + { cID3Field::TAG_OfficialAudioSourceWebpage, "WOAS", "Official audio source webpage" }, + { cID3Field::TAG_OfficialInternetRadioStationWebpage, "WORS", "Official Internet radio station homepage" }, + { cID3Field::TAG_Payment, "WPAY", "Payment" }, + { cID3Field::TAG_PublishersOfficialWebpage, "WPUB", "Publishers official webpage" }, + { cID3Field::TAG_UserDefinedURLLinkFrame, "WXXX", "User defined URL link frame" }, +}; + + +#endif // FIELDS_H diff --git a/libid3tag/compat.c b/libid3tag/compat.c new file mode 100644 index 0000000..820fdb2 --- /dev/null +++ b/libid3tag/compat.c @@ -0,0 +1,503 @@ +/* C code produced by gperf version 3.0.1 */ +/* Command-line: gperf -tCcTonD -K id -N id3_compat_lookup -s -3 -k '*' compat.gperf */ + +#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \ + && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \ + && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \ + && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \ + && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \ + && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \ + && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \ + && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \ + && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \ + && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \ + && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \ + && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \ + && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \ + && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \ + && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \ + && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \ + && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \ + && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \ + && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \ + && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \ + && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \ + && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \ + && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126)) +/* The character set is not based on ISO-646. */ +error "gperf generated tables don't work with this execution character set. Please report a bug to ." +#endif + +#line 1 "compat.gperf" + +/* + * libid3tag - ID3 tag manipulation library + * Copyright (C) 2000-2004 Underbit Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Id: compat.gperf,v 1.11 2004/01/23 09:41:32 rob Exp + */ + +# ifdef HAVE_CONFIG_H +# include "config.h" +# endif + +# include "global.h" + +# include +# include + +# ifdef HAVE_ASSERT_H +# include +# endif + +# include "id3tag.h" +# include "compat.h" +# include "frame.h" +# include "field.h" +# include "parse.h" +# include "ucs4.h" + +# define EQ(id) #id, 0 +# define OBSOLETE 0, 0 +# define TX(id) #id, translate_##id + +static id3_compat_func_t translate_TCON; + +#define TOTAL_KEYWORDS 73 +#define MIN_WORD_LENGTH 3 +#define MAX_WORD_LENGTH 4 +#define MIN_HASH_VALUE 6 +#define MAX_HASH_VALUE 127 +/* maximum key range = 122, duplicates = 0 */ + +#ifdef __GNUC__ +__inline +#else +#ifdef __cplusplus +inline +#endif +#endif +static unsigned int +hash (str, len) + register const char *str; + register unsigned int len; +{ + static const unsigned char asso_values[] = + { + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 64, + 58, 20, 15, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 10, 18, 3, 6, 1, + 47, 0, 128, 42, 62, 30, 31, 0, 19, 52, + 10, 24, 8, 30, 5, 3, 30, 8, 25, 47, + 3, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128 + }; + register int hval = 0; + + switch (len) + { + default: + hval += asso_values[(unsigned char)str[3]]; + /*FALLTHROUGH*/ + case 3: + hval += asso_values[(unsigned char)str[2]]; + /*FALLTHROUGH*/ + case 2: + hval += asso_values[(unsigned char)str[1]+1]; + /*FALLTHROUGH*/ + case 1: + hval += asso_values[(unsigned char)str[0]]; + break; + } + return hval; +} + +#ifdef __GNUC__ +__inline +#endif +const struct id3_compat * +id3_compat_lookup (str, len) + register const char *str; + register unsigned int len; +{ + static const struct id3_compat wordlist[] = + { +#line 97 "compat.gperf" + {"TLE", EQ(TLEN) /* Length */}, +#line 68 "compat.gperf" + {"ETC", EQ(ETCO) /* Event timing codes */}, +#line 126 "compat.gperf" + {"ULT", EQ(USLT) /* Unsynchronised lyric/text transcription */}, +#line 123 "compat.gperf" + {"TYE", OBSOLETE /* Year [obsolete] */}, +#line 92 "compat.gperf" + {"TFT", EQ(TFLT) /* File type */}, +#line 84 "compat.gperf" + {"TCM", EQ(TCOM) /* Composer */}, +#line 66 "compat.gperf" + {"EQU", OBSOLETE /* Equalization [obsolete] */}, +#line 63 "compat.gperf" + {"COM", EQ(COMM) /* Comments */}, +#line 130 "compat.gperf" + {"WCM", EQ(WCOM) /* Commercial information */}, +#line 96 "compat.gperf" + {"TLA", EQ(TLAN) /* Language(s) */}, +#line 88 "compat.gperf" + {"TDA", OBSOLETE /* Date [obsolete] */}, +#line 124 "compat.gperf" + {"TYER", OBSOLETE /* Year [obsolete] */}, +#line 83 "compat.gperf" + {"TBP", EQ(TBPM) /* BPM (beats per minute) */}, +#line 87 "compat.gperf" + {"TCR", EQ(TCOP) /* Copyright message */}, +#line 104 "compat.gperf" + {"TOT", EQ(TOAL) /* Original album/movie/show title */}, +#line 89 "compat.gperf" + {"TDAT", OBSOLETE /* Date [obsolete] */}, +#line 67 "compat.gperf" + {"EQUA", OBSOLETE /* Equalization [obsolete] */}, +#line 102 "compat.gperf" + {"TOR", EQ(TDOR) /* Original release year [obsolete] */}, +#line 131 "compat.gperf" + {"WCP", EQ(WCOP) /* Copyright/legal information */}, +#line 99 "compat.gperf" + {"TOA", EQ(TOPE) /* Original artist(s)/performer(s) */}, +#line 78 "compat.gperf" + {"RVA", OBSOLETE /* Relative volume adjustment [obsolete] */}, +#line 120 "compat.gperf" + {"TT3", EQ(TIT3) /* Subtitle/description refinement */}, +#line 98 "compat.gperf" + {"TMT", EQ(TMED) /* Media type */}, +#line 76 "compat.gperf" + {"POP", EQ(POPM) /* Popularimeter */}, +#line 74 "compat.gperf" + {"MLL", EQ(MLLT) /* MPEG location lookup table */}, +#line 79 "compat.gperf" + {"RVAD", OBSOLETE /* Relative volume adjustment [obsolete] */}, +#line 65 "compat.gperf" + {"CRM", OBSOLETE /* Encrypted meta frame [obsolete] */}, +#line 128 "compat.gperf" + {"WAR", EQ(WOAR) /* Official artist/performer webpage */}, +#line 80 "compat.gperf" + {"SLT", EQ(SYLT) /* Synchronised lyric/text */}, +#line 81 "compat.gperf" + {"STC", EQ(SYTC) /* Synchronised tempo codes */}, +#line 95 "compat.gperf" + {"TKE", EQ(TKEY) /* Initial key */}, +#line 111 "compat.gperf" + {"TRC", EQ(TSRC) /* ISRC (international standard recording code) */}, +#line 109 "compat.gperf" + {"TPA", EQ(TPOS) /* Part of a set */}, +#line 117 "compat.gperf" + {"TSS", EQ(TSSE) /* Software/hardware and settings used for encoding */}, +#line 112 "compat.gperf" + {"TRD", OBSOLETE /* Recording dates [obsolete] */}, +#line 64 "compat.gperf" + {"CRA", EQ(AENC) /* Audio encryption */}, +#line 108 "compat.gperf" + {"TP4", EQ(TPE4) /* Interpreted, remixed, or otherwise modified by */}, +#line 125 "compat.gperf" + {"UFI", EQ(UFID) /* Unique file identifier */}, +#line 101 "compat.gperf" + {"TOL", EQ(TOLY) /* Original lyricist(s)/text writer(s) */}, +#line 110 "compat.gperf" + {"TPB", EQ(TPUB) /* Publisher */}, +#line 73 "compat.gperf" + {"MCI", EQ(MCDI) /* Music CD identifier */}, +#line 107 "compat.gperf" + {"TP3", EQ(TPE3) /* Conductor/performer refinement */}, +#line 132 "compat.gperf" + {"WPB", EQ(WPUB) /* Publishers official webpage */}, +#line 113 "compat.gperf" + {"TRDA", OBSOLETE /* Recording dates [obsolete] */}, +#line 115 "compat.gperf" + {"TSI", OBSOLETE /* Size [obsolete] */}, +#line 90 "compat.gperf" + {"TDY", EQ(TDLY) /* Playlist delay */}, +#line 82 "compat.gperf" + {"TAL", EQ(TALB) /* Album/movie/show title */}, +#line 116 "compat.gperf" + {"TSIZ", OBSOLETE /* Size [obsolete] */}, +#line 129 "compat.gperf" + {"WAS", EQ(WOAS) /* Official audio source webpage */}, +#line 121 "compat.gperf" + {"TXT", EQ(TEXT) /* Lyricist/text writer */}, +#line 62 "compat.gperf" + {"CNT", EQ(PCNT) /* Play counter */}, +#line 100 "compat.gperf" + {"TOF", EQ(TOFN) /* Original filename */}, +#line 85 "compat.gperf" + {"TCO", TX(TCON) /* Content type */}, +#line 114 "compat.gperf" + {"TRK", EQ(TRCK) /* Track number/position in set */}, +#line 119 "compat.gperf" + {"TT2", EQ(TIT2) /* Title/songname/content description */}, +#line 93 "compat.gperf" + {"TIM", OBSOLETE /* Time [obsolete] */}, +#line 94 "compat.gperf" + {"TIME", OBSOLETE /* Time [obsolete] */}, +#line 103 "compat.gperf" + {"TORY", EQ(TDOR) /* Original release year [obsolete] */}, +#line 91 "compat.gperf" + {"TEN", EQ(TENC) /* Encoded by */}, +#line 118 "compat.gperf" + {"TT1", EQ(TIT1) /* Content group description */}, +#line 127 "compat.gperf" + {"WAF", EQ(WOAF) /* Official audio file webpage */}, +#line 75 "compat.gperf" + {"PIC", EQ(APIC) /* Attached picture */}, +#line 122 "compat.gperf" + {"TXX", EQ(TXXX) /* User defined text information frame */}, +#line 133 "compat.gperf" + {"WXX", EQ(WXXX) /* User defined URL link frame */}, +#line 86 "compat.gperf" + {"TCON", TX(TCON) /* Content type */}, +#line 77 "compat.gperf" + {"REV", EQ(RVRB) /* Reverb */}, +#line 106 "compat.gperf" + {"TP2", EQ(TPE2) /* Band/orchestra/accompaniment */}, +#line 105 "compat.gperf" + {"TP1", EQ(TPE1) /* Lead performer(s)/soloist(s) */}, +#line 61 "compat.gperf" + {"BUF", EQ(RBUF) /* Recommended buffer size */}, +#line 70 "compat.gperf" + {"IPL", EQ(TIPL) /* Involved people list */}, +#line 69 "compat.gperf" + {"GEO", EQ(GEOB) /* General encapsulated object */}, +#line 72 "compat.gperf" + {"LNK", EQ(LINK) /* Linked information */}, +#line 71 "compat.gperf" + {"IPLS", EQ(TIPL) /* Involved people list */} + }; + + static const short lookup[] = + { + -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, -1, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + -1, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, -1, -1, 50, -1, 51, 52, -1, 53, 54, 55, 56, -1, + 57, 58, 59, 60, -1, 61, -1, 62, -1, -1, 63, -1, 64, -1, + -1, 65, -1, 66, -1, -1, -1, -1, -1, 67, -1, 68, -1, 69, + -1, 70, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 71, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 72 + }; + + if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) + { + register int key = hash (str, len); + + if (key <= MAX_HASH_VALUE && key >= 0) + { + register int index = lookup[key]; + + if (index >= 0) + { + register const char *s = wordlist[index].id; + + if (*str == *s && !strncmp (str + 1, s + 1, len - 1) && s[len] == '\0') + return &wordlist[index]; + } + } + } + return 0; +} +#line 134 "compat.gperf" + + +static +int translate_TCON(struct id3_frame *frame, char const *oldid, + id3_byte_t const *data, id3_length_t length) +{ + id3_byte_t const *end; + enum id3_field_textencoding encoding; + id3_ucs4_t *string = 0, *ptr, *endptr; + int result = 0; + + /* translate old TCON syntax into multiple strings */ + + assert(frame->nfields == 2); + + encoding = ID3_FIELD_TEXTENCODING_ISO_8859_1; + + end = data + length; + + if (id3_field_parse(&frame->fields[0], &data, end - data, &encoding) == -1) + goto fail; + + string = id3_parse_string(&data, end - data, encoding, 0); + if (string == 0) + goto fail; + + ptr = string; + while (*ptr == '(') { + if (*++ptr == '(') + break; + + endptr = ptr; + while (*endptr && *endptr != ')') + ++endptr; + + if (*endptr) + *endptr++ = 0; + + if (id3_field_addstring(&frame->fields[1], ptr) == -1) + goto fail; + + ptr = endptr; + } + + if (*ptr && id3_field_addstring(&frame->fields[1], ptr) == -1) + goto fail; + + if (0) { + fail: + result = -1; + } + + if (string) + free(string); + + return result; +} + +/* + * NAME: compat->fixup() + * DESCRIPTION: finish compatibility translations + */ +int id3_compat_fixup(struct id3_tag *tag) +{ + struct id3_frame *frame; + unsigned int index; + id3_ucs4_t timestamp[17] = { 0 }; + int result = 0; + + /* create a TDRC frame from obsolete TYER/TDAT/TIME frames */ + + /* + * TYE/TYER: YYYY + * TDA/TDAT: DDMM + * TIM/TIME: HHMM + * + * TDRC: yyyy-MM-ddTHH:mm + */ + + index = 0; + while ((frame = id3_tag_findframe(tag, ID3_FRAME_OBSOLETE, index++))) { + char const *id; + id3_byte_t const *data, *end; + id3_length_t length; + enum id3_field_textencoding encoding; + id3_ucs4_t *string; + + id = id3_field_getframeid(&frame->fields[0]); + assert(id); + + if (strcmp(id, "TYER") != 0 && strcmp(id, "YTYE") != 0 && + strcmp(id, "TDAT") != 0 && strcmp(id, "YTDA") != 0 && + strcmp(id, "TIME") != 0 && strcmp(id, "YTIM") != 0) + continue; + + data = id3_field_getbinarydata(&frame->fields[1], &length); + assert(data); + + if (length < 1) + continue; + + end = data + length; + + encoding = id3_parse_uint(&data, 1); + string = id3_parse_string(&data, end - data, encoding, 0); + + if (id3_ucs4_length(string) < 4) { + free(string); + continue; + } + + if (strcmp(id, "TYER") == 0 || + strcmp(id, "YTYE") == 0) { + timestamp[0] = string[0]; + timestamp[1] = string[1]; + timestamp[2] = string[2]; + timestamp[3] = string[3]; + } + else if (strcmp(id, "TDAT") == 0 || + strcmp(id, "YTDA") == 0) { + timestamp[4] = '-'; + timestamp[5] = string[2]; + timestamp[6] = string[3]; + timestamp[7] = '-'; + timestamp[8] = string[0]; + timestamp[9] = string[1]; + } + else { /* TIME or YTIM */ + timestamp[10] = 'T'; + timestamp[11] = string[0]; + timestamp[12] = string[1]; + timestamp[13] = ':'; + timestamp[14] = string[2]; + timestamp[15] = string[3]; + } + + free(string); + } + + if (timestamp[0]) { + id3_ucs4_t *strings; + + frame = id3_frame_new("TDRC"); + if (frame == 0) + goto fail; + + strings = timestamp; + + if (id3_field_settextencoding(&frame->fields[0], + ID3_FIELD_TEXTENCODING_ISO_8859_1) == -1 || + id3_field_setstrings(&frame->fields[1], 1, &strings) == -1 || + id3_tag_attachframe(tag, frame) == -1) { + id3_frame_delete(frame); + goto fail; + } + } + + if (0) { + fail: + result = -1; + } + + return result; +} diff --git a/libid3tag/compat.h b/libid3tag/compat.h new file mode 100644 index 0000000..8af71ec --- /dev/null +++ b/libid3tag/compat.h @@ -0,0 +1,41 @@ +/* + * libid3tag - ID3 tag manipulation library + * Copyright (C) 2000-2004 Underbit Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: compat.h,v 1.8 2004/01/23 09:41:32 rob Exp $ + */ + +# ifndef LIBID3TAG_COMPAT_H +# define LIBID3TAG_COMPAT_H + +# include "id3tag.h" + +typedef int id3_compat_func_t(struct id3_frame *, char const *, + id3_byte_t const *, id3_length_t); + +struct id3_compat { + char const *id; + char const *equiv; + id3_compat_func_t *translate; +}; + +struct id3_compat const *id3_compat_lookup(register char const *, + register unsigned int); + +int id3_compat_fixup(struct id3_tag *); + +# endif diff --git a/libid3tag/crc.c b/libid3tag/crc.c new file mode 100644 index 0000000..742a5d8 --- /dev/null +++ b/libid3tag/crc.c @@ -0,0 +1,137 @@ +/* + * libid3tag - ID3 tag manipulation library + * Copyright (C) 2000-2004 Underbit Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: crc.c,v 1.11 2004/02/17 02:04:10 rob Exp $ + */ + +# ifdef HAVE_CONFIG_H +# include "config.h" +# endif + +# include "global.h" + +# include "id3tag.h" +# include "crc.h" + +static +unsigned long const crc_table[256] = { + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, + 0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L, + 0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, + 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L, + 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, + 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, + 0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, + 0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L, + + 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 0xa2677172L, + 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, + 0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, + 0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L, + 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL, + 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, + + 0x76dc4190L, 0x01db7106L, 0x98d220bcL, 0xefd5102aL, + 0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L, + 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 0xe10e9818L, + 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, + 0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, + 0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL, + 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L, + + 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, + 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, + 0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, + 0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L, + 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L, + 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, + 0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, + + 0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL, + 0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L, + 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, + 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, + 0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, + 0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L, + 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL, + 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, + 0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, + 0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L, + 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L, + 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, + 0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, + 0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL, + + 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 0x026d930aL, + 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, + 0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, + 0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL, + 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L, + 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, + 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, + + 0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, + 0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL, + 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L, + 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, + 0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL, + 0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, + 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL +}; + +/* + * NAME: crc->compute() + * DESCRIPTION: calculate CRC-32 value (ISO 3309) + */ +unsigned long id3_crc_compute(id3_byte_t const *data, id3_length_t length) +{ + register unsigned long crc; + + for (crc = 0xffffffffL; length >= 8; length -= 8) { + crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); + crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); + crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); + crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); + crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); + crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); + crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); + crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); + } + + switch (length) { + case 7: crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); + case 6: crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); + case 5: crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); + case 4: crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); + case 3: crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); + case 2: crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); + case 1: crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); + case 0: break; + } + + return crc ^ 0xffffffffL; +} diff --git a/libid3tag/crc.h b/libid3tag/crc.h new file mode 100644 index 0000000..89a5a39 --- /dev/null +++ b/libid3tag/crc.h @@ -0,0 +1,29 @@ +/* + * libid3tag - ID3 tag manipulation library + * Copyright (C) 2000-2004 Underbit Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: crc.h,v 1.8 2004/02/17 02:04:10 rob Exp $ + */ + +# ifndef LIBID3TAG_CRC_H +# define LIBID3TAG_CRC_H + +# include "id3tag.h" + +unsigned long id3_crc_compute(id3_byte_t const *, id3_length_t); + +# endif diff --git a/libid3tag/debug.c b/libid3tag/debug.c new file mode 100644 index 0000000..d91a2c5 --- /dev/null +++ b/libid3tag/debug.c @@ -0,0 +1,222 @@ +/* + * libid3tag - ID3 tag manipulation library + * Copyright (C) 2000-2004 Underbit Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: debug.c,v 1.8 2004/01/23 09:41:32 rob Exp $ + */ + +# ifdef HAVE_CONFIG_H +# include "config.h" +# endif + +# include "global.h" + +# undef malloc +# undef calloc +# undef realloc +# undef free + +# include +# include +# include + +# include "debug.h" + +# if defined(DEBUG) + +# define DEBUG_MAGIC 0xdeadbeefL + +struct debug { + char const *file; + unsigned int line; + size_t size; + struct debug *next; + struct debug *prev; + long int magic; +}; + +static struct debug *allocated; +static int registered; + +static +void check(void) +{ + struct debug *debug; + + for (debug = allocated; debug; debug = debug->next) { + if (debug->magic != DEBUG_MAGIC) { + fprintf(stderr, "memory corruption\n"); + break; + } + + fprintf(stderr, "%s:%u: leaked %lu bytes\n", + debug->file, debug->line, debug->size); + } +} + +void *id3_debug_malloc(size_t size, char const *file, unsigned int line) +{ + struct debug *debug; + + if (!registered) { + atexit(check); + registered = 1; + } + + if (size == 0) + fprintf(stderr, "%s:%u: malloc(0)\n", file, line); + + debug = malloc(sizeof(*debug) + size); + if (debug == 0) { + fprintf(stderr, "%s:%u: malloc(%lu) failed\n", file, line, size); + return 0; + } + + debug->magic = DEBUG_MAGIC; + + debug->file = file; + debug->line = line; + debug->size = size; + + debug->next = allocated; + debug->prev = 0; + + if (allocated) + allocated->prev = debug; + + allocated = debug; + + return ++debug; +} + +void *id3_debug_calloc(size_t nmemb, size_t size, + char const *file, unsigned int line) +{ + void *ptr; + + ptr = id3_debug_malloc(nmemb * size, file, line); + if (ptr) + memset(ptr, 0, nmemb * size); + + return ptr; +} + +void *id3_debug_realloc(void *ptr, size_t size, + char const *file, unsigned int line) +{ + struct debug *debug, *new; + + if (size == 0) { + id3_debug_free(ptr, file, line); + return 0; + } + + if (ptr == 0) + return id3_debug_malloc(size, file, line); + + debug = ptr; + --debug; + + if (debug->magic != DEBUG_MAGIC) { + fprintf(stderr, "%s:%u: realloc(%p, %lu) memory not allocated\n", + file, line, ptr, size); + return 0; + } + + new = realloc(debug, sizeof(*debug) + size); + if (new == 0) { + fprintf(stderr, "%s:%u: realloc(%p, %lu) failed\n", file, line, ptr, size); + return 0; + } + + if (allocated == debug) + allocated = new; + + debug = new; + + debug->file = file; + debug->line = line; + debug->size = size; + + if (debug->next) + debug->next->prev = debug; + if (debug->prev) + debug->prev->next = debug; + + return ++debug; +} + +void id3_debug_free(void *ptr, char const *file, unsigned int line) +{ + struct debug *debug; + + if (ptr == 0) { + fprintf(stderr, "%s:%u: free(0)\n", file, line); + return; + } + + debug = ptr; + --debug; + + if (debug->magic != DEBUG_MAGIC) { + fprintf(stderr, "%s:%u: free(%p) memory not allocated\n", file, line, ptr); + return; + } + + debug->magic = 0; + + if (debug->next) + debug->next->prev = debug->prev; + if (debug->prev) + debug->prev->next = debug->next; + + if (allocated == debug) + allocated = debug->next; + + free(debug); +} + +void *id3_debug_release(void *ptr, char const *file, unsigned int line) +{ + struct debug *debug; + + if (ptr == 0) + return 0; + + debug = ptr; + --debug; + + if (debug->magic != DEBUG_MAGIC) { + fprintf(stderr, "%s:%u: release(%p) memory not allocated\n", + file, line, ptr); + return ptr; + } + + if (debug->next) + debug->next->prev = debug->prev; + if (debug->prev) + debug->prev->next = debug->next; + + if (allocated == debug) + allocated = debug->next; + + memmove(debug, debug + 1, debug->size); + + return debug; +} + +# endif diff --git a/libid3tag/debug.h b/libid3tag/debug.h new file mode 100644 index 0000000..a9b4ce0 --- /dev/null +++ b/libid3tag/debug.h @@ -0,0 +1,34 @@ +/* + * libid3tag - ID3 tag manipulation library + * Copyright (C) 2000-2004 Underbit Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: debug.h,v 1.8 2004/01/23 09:41:32 rob Exp $ + */ + +# ifndef LIBID3TAG_DEBUG_H +# define LIBID3TAG_DEBUG_H + +# include + +void *id3_debug_malloc(size_t, char const *, unsigned int); +void *id3_debug_calloc(size_t, size_t, char const *, unsigned int); +void *id3_debug_realloc(void *, size_t, char const *, unsigned int); +void id3_debug_free(void *, char const *, unsigned int); + +void *id3_debug_release(void *, char const *, unsigned int); + +# endif diff --git a/libid3tag/field.c b/libid3tag/field.c new file mode 100644 index 0000000..f2ecc0f --- /dev/null +++ b/libid3tag/field.c @@ -0,0 +1,890 @@ +/* + * libid3tag - ID3 tag manipulation library + * Copyright (C) 2000-2004 Underbit Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: field.c,v 1.16 2004/01/23 09:41:32 rob Exp $ + */ + +# ifdef HAVE_CONFIG_H +# include "config.h" +# endif + +# include "global.h" + +# include +# include + +# ifdef HAVE_ASSERT_H +# include +# endif + +# include "id3tag.h" +# include "field.h" +# include "frame.h" +# include "render.h" +# include "ucs4.h" +# include "latin1.h" +# include "parse.h" + +/* + * NAME: field->init() + * DESCRIPTION: initialize a field to a default value for the given type + */ +void id3_field_init(union id3_field *field, enum id3_field_type type) +{ + assert(field); + + switch (field->type = type) { + case ID3_FIELD_TYPE_TEXTENCODING: + case ID3_FIELD_TYPE_INT8: + case ID3_FIELD_TYPE_INT16: + case ID3_FIELD_TYPE_INT24: + case ID3_FIELD_TYPE_INT32: + field->number.value = 0; + break; + + case ID3_FIELD_TYPE_LATIN1: + case ID3_FIELD_TYPE_LATIN1FULL: + field->latin1.ptr = 0; + break; + + case ID3_FIELD_TYPE_LATIN1LIST: + field->latin1list.nstrings = 0; + field->latin1list.strings = 0; + + case ID3_FIELD_TYPE_STRING: + case ID3_FIELD_TYPE_STRINGFULL: + field->string.ptr = 0; + break; + + case ID3_FIELD_TYPE_STRINGLIST: + field->stringlist.nstrings = 0; + field->stringlist.strings = 0; + break; + + case ID3_FIELD_TYPE_LANGUAGE: + strcpy(field->immediate.value, "XXX"); + break; + + case ID3_FIELD_TYPE_FRAMEID: + strcpy(field->immediate.value, "XXXX"); + break; + + case ID3_FIELD_TYPE_DATE: + memset(field->immediate.value, 0, sizeof(field->immediate.value)); + break; + + case ID3_FIELD_TYPE_INT32PLUS: + case ID3_FIELD_TYPE_BINARYDATA: + field->binary.data = 0; + field->binary.length = 0; + break; + } +} + +/* + * NAME: field->finish() + * DESCRIPTION: reset a field, deallocating memory if necessary + */ +void id3_field_finish(union id3_field *field) +{ + unsigned int i; + + assert(field); + + switch (field->type) { + case ID3_FIELD_TYPE_TEXTENCODING: + case ID3_FIELD_TYPE_INT8: + case ID3_FIELD_TYPE_INT16: + case ID3_FIELD_TYPE_INT24: + case ID3_FIELD_TYPE_INT32: + case ID3_FIELD_TYPE_LANGUAGE: + case ID3_FIELD_TYPE_FRAMEID: + case ID3_FIELD_TYPE_DATE: + break; + + case ID3_FIELD_TYPE_LATIN1: + case ID3_FIELD_TYPE_LATIN1FULL: + if (field->latin1.ptr) + free(field->latin1.ptr); + break; + + case ID3_FIELD_TYPE_LATIN1LIST: + for (i = 0; i < field->latin1list.nstrings; ++i) + free(field->latin1list.strings[i]); + + if (field->latin1list.strings) + free(field->latin1list.strings); + break; + + case ID3_FIELD_TYPE_STRING: + case ID3_FIELD_TYPE_STRINGFULL: + if (field->string.ptr) + free(field->string.ptr); + break; + + case ID3_FIELD_TYPE_STRINGLIST: + for (i = 0; i < field->stringlist.nstrings; ++i) + free(field->stringlist.strings[i]); + + if (field->stringlist.strings) + free(field->stringlist.strings); + break; + + case ID3_FIELD_TYPE_INT32PLUS: + case ID3_FIELD_TYPE_BINARYDATA: + if (field->binary.data) + free(field->binary.data); + break; + } + + id3_field_init(field, field->type); +} + +/* + * NAME: field->type() + * DESCRIPTION: return the value type of a field + */ +enum id3_field_type id3_field_type(union id3_field const *field) +{ + assert(field); + + return field->type; +} + +/* + * NAME: field->parse() + * DESCRIPTION: parse a field value + */ +int id3_field_parse(union id3_field *field, id3_byte_t const **ptr, + id3_length_t length, enum id3_field_textencoding *encoding) +{ + assert(field); + + id3_field_finish(field); + + switch (field->type) { + case ID3_FIELD_TYPE_INT32: + if (length < 4) + goto fail; + + field->number.value = id3_parse_uint(ptr, 4); + break; + + case ID3_FIELD_TYPE_INT24: + if (length < 3) + goto fail; + + field->number.value = id3_parse_uint(ptr, 3); + break; + + case ID3_FIELD_TYPE_INT16: + if (length < 2) + goto fail; + + field->number.value = id3_parse_uint(ptr, 2); + break; + + case ID3_FIELD_TYPE_INT8: + case ID3_FIELD_TYPE_TEXTENCODING: + if (length < 1) + goto fail; + + field->number.value = id3_parse_uint(ptr, 1); + + if (field->type == ID3_FIELD_TYPE_TEXTENCODING) + *encoding = field->number.value; + break; + + case ID3_FIELD_TYPE_LANGUAGE: + if (length < 3) + goto fail; + + id3_parse_immediate(ptr, 3, field->immediate.value); + break; + + case ID3_FIELD_TYPE_FRAMEID: + if (length < 4) + goto fail; + + id3_parse_immediate(ptr, 4, field->immediate.value); + break; + + case ID3_FIELD_TYPE_DATE: + if (length < 8) + goto fail; + + id3_parse_immediate(ptr, 8, field->immediate.value); + break; + + case ID3_FIELD_TYPE_LATIN1: + case ID3_FIELD_TYPE_LATIN1FULL: + { + id3_latin1_t *latin1; + + latin1 = id3_parse_latin1(ptr, length, + field->type == ID3_FIELD_TYPE_LATIN1FULL); + if (latin1 == 0) + goto fail; + + field->latin1.ptr = latin1; + } + break; + + case ID3_FIELD_TYPE_LATIN1LIST: + { + id3_byte_t const *end; + id3_latin1_t *latin1, **strings; + + end = *ptr + length; + + while (end - *ptr > 0) { + latin1 = id3_parse_latin1(ptr, end - *ptr, 0); + if (latin1 == 0) + goto fail; + + strings = realloc(field->latin1list.strings, + (field->latin1list.nstrings + 1) * sizeof(*strings)); + if (strings == 0) { + free(latin1); + goto fail; + } + + field->latin1list.strings = strings; + field->latin1list.strings[field->latin1list.nstrings++] = latin1; + } + } + break; + + case ID3_FIELD_TYPE_STRING: + case ID3_FIELD_TYPE_STRINGFULL: + { + id3_ucs4_t *ucs4; + + ucs4 = id3_parse_string(ptr, length, *encoding, + field->type == ID3_FIELD_TYPE_STRINGFULL); + if (ucs4 == 0) + goto fail; + + field->string.ptr = ucs4; + } + break; + + case ID3_FIELD_TYPE_STRINGLIST: + { + id3_byte_t const *end; + id3_ucs4_t *ucs4, **strings; + + end = *ptr + length; + + while (end - *ptr > 0) { + ucs4 = id3_parse_string(ptr, end - *ptr, *encoding, 0); + if (ucs4 == 0) + goto fail; + + strings = realloc(field->stringlist.strings, + (field->stringlist.nstrings + 1) * sizeof(*strings)); + if (strings == 0) { + free(ucs4); + goto fail; + } + + field->stringlist.strings = strings; + field->stringlist.strings[field->stringlist.nstrings++] = ucs4; + } + } + break; + + case ID3_FIELD_TYPE_INT32PLUS: + case ID3_FIELD_TYPE_BINARYDATA: + { + id3_byte_t *data; + + data = id3_parse_binary(ptr, length); + if (data == 0) + goto fail; + + field->binary.data = data; + field->binary.length = length; + } + break; + } + + return 0; + + fail: + return -1; +} + +/* + * NAME: field->render() + * DESCRIPTION: render a field value + */ +id3_length_t id3_field_render(union id3_field const *field, id3_byte_t **ptr, + enum id3_field_textencoding *encoding, + int terminate) +{ + id3_length_t size; + unsigned int i; + + assert(field && encoding); + + switch (field->type) { + case ID3_FIELD_TYPE_INT32: + return id3_render_int(ptr, field->number.value, 4); + + case ID3_FIELD_TYPE_INT24: + return id3_render_int(ptr, field->number.value, 3); + + case ID3_FIELD_TYPE_INT16: + return id3_render_int(ptr, field->number.value, 2); + + case ID3_FIELD_TYPE_TEXTENCODING: + *encoding = field->number.value; + case ID3_FIELD_TYPE_INT8: + return id3_render_int(ptr, field->number.value, 1); + + case ID3_FIELD_TYPE_LATIN1: + case ID3_FIELD_TYPE_LATIN1FULL: + return id3_render_latin1(ptr, field->latin1.ptr, terminate); + + case ID3_FIELD_TYPE_LATIN1LIST: + size = 0; + for (i = 0; i < field->latin1list.nstrings; ++i) { + size += id3_render_latin1(ptr, field->latin1list.strings[i], + (i < field->latin1list.nstrings - 1) || + terminate); + } + return size; + + case ID3_FIELD_TYPE_STRING: + case ID3_FIELD_TYPE_STRINGFULL: + return id3_render_string(ptr, field->string.ptr, *encoding, terminate); + + case ID3_FIELD_TYPE_STRINGLIST: + size = 0; + for (i = 0; i < field->stringlist.nstrings; ++i) { + size += id3_render_string(ptr, field->stringlist.strings[i], *encoding, + (i < field->stringlist.nstrings - 1) || + terminate); + } + return size; + + case ID3_FIELD_TYPE_LANGUAGE: + return id3_render_immediate(ptr, field->immediate.value, 3); + + case ID3_FIELD_TYPE_FRAMEID: + return id3_render_immediate(ptr, field->immediate.value, 4); + + case ID3_FIELD_TYPE_DATE: + return id3_render_immediate(ptr, field->immediate.value, 8); + + case ID3_FIELD_TYPE_INT32PLUS: + case ID3_FIELD_TYPE_BINARYDATA: + return id3_render_binary(ptr, field->binary.data, field->binary.length); + } + + return 0; +} + +/* + * NAME: field->setint() + * DESCRIPTION: set the value of an int field + */ +int id3_field_setint(union id3_field *field, signed long number) +{ + assert(field); + + switch (field->type) { + case ID3_FIELD_TYPE_INT8: + if (number > 0x7f || number < -0x80) + return -1; + break; + + case ID3_FIELD_TYPE_INT16: + if (number > 0x7fff || number < -0x8000) + return -1; + break; + + case ID3_FIELD_TYPE_INT24: + if (number > 0x7fffffL || number < -0x800000L) + return -1; + break; + + case ID3_FIELD_TYPE_INT32: + if (number > 0x7fffffffL || number < -0x80000000L) + return -1; + break; + + default: + return -1; + } + + id3_field_finish(field); + + field->number.value = number; + + return 0; +} + +/* + * NAME: field->settextencoding() + * DESCRIPTION: set the value of a textencoding field + */ +int id3_field_settextencoding(union id3_field *field, + enum id3_field_textencoding encoding) +{ + assert(field); + + if (field->type != ID3_FIELD_TYPE_TEXTENCODING) + return -1; + + id3_field_finish(field); + + field->number.value = encoding; + + return 0; +} + +static +int set_latin1(union id3_field *field, id3_latin1_t const *latin1) +{ + id3_latin1_t *data; + + if (latin1 == 0 || *latin1 == 0) + data = 0; + else { + data = id3_latin1_duplicate(latin1); + if (data == 0) + return -1; + } + + field->latin1.ptr = data; + + return 0; +} + +/* + * NAME: field->setlatin1() + * DESCRIPTION: set the value of a latin1 field + */ +int id3_field_setlatin1(union id3_field *field, id3_latin1_t const *latin1) +{ + assert(field); + + if (field->type != ID3_FIELD_TYPE_LATIN1) + return -1; + + id3_field_finish(field); + + if (latin1) { + id3_latin1_t const *ptr; + + for (ptr = latin1; *ptr; ++ptr) { + if (*ptr == '\n') + return -1; + } + } + + return set_latin1(field, latin1); +} + +/* + * NAME: field->setfulllatin1() + * DESCRIPTION: set the value of a full latin1 field + */ +int id3_field_setfulllatin1(union id3_field *field, id3_latin1_t const *latin1) +{ + assert(field); + + if (field->type != ID3_FIELD_TYPE_LATIN1FULL) + return -1; + + id3_field_finish(field); + + return set_latin1(field, latin1); +} + +static +int set_string(union id3_field *field, id3_ucs4_t const *string) +{ + id3_ucs4_t *data; + + if (string == 0 || *string == 0) + data = 0; + else { + data = id3_ucs4_duplicate(string); + if (data == 0) + return -1; + } + + field->string.ptr = data; + + return 0; +} + +/* + * NAME: field->setstring() + * DESCRIPTION: set the value of a string field + */ +int id3_field_setstring(union id3_field *field, id3_ucs4_t const *string) +{ + assert(field); + + if (field->type != ID3_FIELD_TYPE_STRING) + return -1; + + id3_field_finish(field); + + if (string) { + id3_ucs4_t const *ptr; + + for (ptr = string; *ptr; ++ptr) { + if (*ptr == '\n') + return -1; + } + } + + return set_string(field, string); +} + +/* + * NAME: field->setfullstring() + * DESCRIPTION: set the value of a full string field + */ +int id3_field_setfullstring(union id3_field *field, id3_ucs4_t const *string) +{ + assert(field); + + if (field->type != ID3_FIELD_TYPE_STRINGFULL) + return -1; + + id3_field_finish(field); + + return set_string(field, string); +} + +/* + * NAME: field->setstrings() + * DESCRIPTION: set the value of a stringlist field + */ +int id3_field_setstrings(union id3_field *field, + unsigned int length, id3_ucs4_t **ptrs) +{ + id3_ucs4_t **strings; + unsigned int i; + + assert(field); + + if (field->type != ID3_FIELD_TYPE_STRINGLIST) + return -1; + + id3_field_finish(field); + + if (length == 0) + return 0; + + strings = malloc(length * sizeof(*strings)); + if (strings == 0) + return -1; + + for (i = 0; i < length; ++i) { + strings[i] = id3_ucs4_duplicate(ptrs[i]); + if (strings[i] == 0) { + while (i--) + free(strings[i]); + + free(strings); + return -1; + } + } + + field->stringlist.strings = strings; + field->stringlist.nstrings = length; + + return 0; +} + +/* + * NAME: field->addstring() + * DESCRIPTION: add a string to a stringlist field + */ +int id3_field_addstring(union id3_field *field, id3_ucs4_t const *string) +{ + id3_ucs4_t *new, **strings; + + assert(field); + + if (field->type != ID3_FIELD_TYPE_STRINGLIST) + return -1; + + if (string == 0) + string = id3_ucs4_empty; + + new = id3_ucs4_duplicate(string); + if (new == 0) + return -1; + + strings = realloc(field->stringlist.strings, + (field->stringlist.nstrings + 1) * sizeof(*strings)); + if (strings == 0) { + free(new); + return -1; + } + + field->stringlist.strings = strings; + field->stringlist.strings[field->stringlist.nstrings++] = new; + + return 0; +} + +/* + * NAME: field->setlanguage() + * DESCRIPTION: set the value of a language field + */ +int id3_field_setlanguage(union id3_field *field, char const *language) +{ + assert(field); + + if (field->type != ID3_FIELD_TYPE_LANGUAGE) + return -1; + + id3_field_finish(field); + + if (language) { + if (strlen(language) != 3) + return -1; + + strcpy(field->immediate.value, language); + } + + return 0; +} + +/* + * NAME: field->setframeid() + * DESCRIPTION: set the value of a frameid field + */ +int id3_field_setframeid(union id3_field *field, char const *id) +{ + assert(field); + + if (field->type != ID3_FIELD_TYPE_FRAMEID || + !id3_frame_validid(id)) + return -1; + + id3_field_finish(field); + + field->immediate.value[0] = id[0]; + field->immediate.value[1] = id[1]; + field->immediate.value[2] = id[2]; + field->immediate.value[3] = id[3]; + field->immediate.value[4] = 0; + + return 0; +} + +/* + * NAME: field->setbinarydata() + * DESCRIPTION: set the value of a binarydata field + */ +int id3_field_setbinarydata(union id3_field *field, + id3_byte_t const *data, id3_length_t length) +{ + id3_byte_t *mem; + + assert(field); + + if (field->type != ID3_FIELD_TYPE_BINARYDATA) + return -1; + + id3_field_finish(field); + + if (length == 0) + mem = 0; + else { + mem = malloc(length); + if (mem == 0) + return -1; + + assert(data); + + memcpy(mem, data, length); + } + + field->binary.data = mem; + field->binary.length = length; + + return 0; +} + +/* + * NAME: field->getint() + * DESCRIPTION: return the value of an integer field + */ +signed long id3_field_getint(union id3_field const *field) +{ + assert(field); + + if (field->type != ID3_FIELD_TYPE_INT8 && + field->type != ID3_FIELD_TYPE_INT16 && + field->type != ID3_FIELD_TYPE_INT24 && + field->type != ID3_FIELD_TYPE_INT32) + return -1; + + return field->number.value; +} + +/* + * NAME: field->gettextencoding() + * DESCRIPTION: return the value of a text encoding field + */ +enum id3_field_textencoding +id3_field_gettextencoding(union id3_field const *field) +{ + assert(field); + + if (field->type != ID3_FIELD_TYPE_TEXTENCODING) + return -1; + + return field->number.value; +} + +/* + * NAME: field->getlatin1() + * DESCRIPTION: return the value of a latin1 field + */ +id3_latin1_t const *id3_field_getlatin1(union id3_field const *field) +{ + assert(field); + + if (field->type != ID3_FIELD_TYPE_LATIN1) + return 0; + + return field->latin1.ptr ? field->latin1.ptr : (id3_latin1_t const *) ""; +} + +/* + * NAME: field->getfulllatin1() + * DESCRIPTION: return the value of a full latin1 field + */ +id3_latin1_t const *id3_field_getfulllatin1(union id3_field const *field) +{ + assert(field); + + if (field->type != ID3_FIELD_TYPE_LATIN1FULL) + return 0; + + return field->latin1.ptr ? field->latin1.ptr : (id3_latin1_t const *) ""; +} + +/* + * NAME: field->getstring() + * DESCRIPTION: return the value of a string field + */ +id3_ucs4_t const *id3_field_getstring(union id3_field const *field) +{ + assert(field); + + if (field->type != ID3_FIELD_TYPE_STRING) + return 0; + + return field->string.ptr ? field->string.ptr : id3_ucs4_empty; +} + +/* + * NAME: field->getfullstring() + * DESCRIPTION: return the value of a fullstring field + */ +id3_ucs4_t const *id3_field_getfullstring(union id3_field const *field) +{ + assert(field); + + if (field->type != ID3_FIELD_TYPE_STRINGFULL) + return 0; + + return field->string.ptr ? field->string.ptr : id3_ucs4_empty; +} + +/* + * NAME: field->getnstrings() + * DESCRIPTION: return the number of strings in a stringlist field + */ +unsigned int id3_field_getnstrings(union id3_field const *field) +{ + assert(field); + + if (field->type != ID3_FIELD_TYPE_STRINGLIST) + return 0; + + return field->stringlist.nstrings; +} + +/* + * NAME: field->getstrings() + * DESCRIPTION: return one value of a stringlist field + */ +id3_ucs4_t const *id3_field_getstrings(union id3_field const *field, + unsigned int index) +{ + id3_ucs4_t const *string; + + assert(field); + + if (field->type != ID3_FIELD_TYPE_STRINGLIST || + index >= field->stringlist.nstrings) + return 0; + + string = field->stringlist.strings[index]; + + return string ? string : id3_ucs4_empty; +} + +/* + * NAME: field->getframeid() + * DESCRIPTION: return the value of a frameid field + */ +char const *id3_field_getframeid(union id3_field const *field) +{ + assert(field); + + if (field->type != ID3_FIELD_TYPE_FRAMEID) + return 0; + + return field->immediate.value; +} + +/* + * NAME: field->getbinarydata() + * DESCRIPTION: return the value of a binarydata field + */ +id3_byte_t const *id3_field_getbinarydata(union id3_field const *field, + id3_length_t *length) +{ + static id3_byte_t const empty; + + assert(field && length); + + if (field->type != ID3_FIELD_TYPE_BINARYDATA) + return 0; + + assert(field->binary.length == 0 || field->binary.data); + + *length = field->binary.length; + + return field->binary.data ? field->binary.data : ∅ +} diff --git a/libid3tag/field.h b/libid3tag/field.h new file mode 100644 index 0000000..2cf42b9 --- /dev/null +++ b/libid3tag/field.h @@ -0,0 +1,36 @@ +/* + * libid3tag - ID3 tag manipulation library + * Copyright (C) 2000-2004 Underbit Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: field.h,v 1.9 2004/01/23 09:41:32 rob Exp $ + */ + +# ifndef LIBID3TAG_FIELD_H +# define LIBID3TAG_FIELD_H + +# include "id3tag.h" + +void id3_field_init(union id3_field *, enum id3_field_type); +void id3_field_finish(union id3_field *); + +int id3_field_parse(union id3_field *, id3_byte_t const **, + id3_length_t, enum id3_field_textencoding *); + +id3_length_t id3_field_render(union id3_field const *, id3_byte_t **, + enum id3_field_textencoding *, int); + +# endif diff --git a/libid3tag/file.c b/libid3tag/file.c new file mode 100644 index 0000000..9d7319a --- /dev/null +++ b/libid3tag/file.c @@ -0,0 +1,674 @@ +/* + * libid3tag - ID3 tag manipulation library + * Copyright (C) 2000-2004 Underbit Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: file.c,v 1.21 2004/01/23 09:41:32 rob Exp $ + */ + +# ifdef HAVE_CONFIG_H +# include "config.h" +# endif + +# include "global.h" + +# include +# include +# include + +# ifdef HAVE_UNISTD_H +# include +# endif + +# ifdef HAVE_ASSERT_H +# include +# endif + +# include "id3tag.h" +# include "file.h" +# include "tag.h" +# include "field.h" + +struct filetag { + struct id3_tag *tag; + unsigned long location; + id3_length_t length; +}; + +struct id3_file { + FILE *iofile; + enum id3_file_mode mode; + char *path; + + int flags; + + struct id3_tag *primary; + + unsigned int ntags; + struct filetag *tags; +}; + +enum { + ID3_FILE_FLAG_ID3V1 = 0x0001 +}; + +/* + * NAME: query_tag() + * DESCRIPTION: check for a tag at a file's current position + */ +static +signed long query_tag(FILE *iofile) +{ + fpos_t save_position; + id3_byte_t query[ID3_TAG_QUERYSIZE]; + signed long size; + + if (fgetpos(iofile, &save_position) == -1) + return 0; + + size = id3_tag_query(query, fread(query, 1, sizeof(query), iofile)); + + if (fsetpos(iofile, &save_position) == -1) + return 0; + + return size; +} + +/* + * NAME: read_tag() + * DESCRIPTION: read and parse a tag at a file's current position + */ +static +struct id3_tag *read_tag(FILE *iofile, id3_length_t size) +{ + id3_byte_t *data; + struct id3_tag *tag = 0; + + data = malloc(size); + if (data) { + if (fread(data, size, 1, iofile) == 1) + tag = id3_tag_parse(data, size); + + free(data); + } + + return tag; +} + +/* + * NAME: update_primary() + * DESCRIPTION: update the primary tag with data from a new tag + */ +static +int update_primary(struct id3_tag *tag, struct id3_tag const *new) +{ + unsigned int i; + struct id3_frame *frame; + + if (new) { + if (!(new->extendedflags & ID3_TAG_EXTENDEDFLAG_TAGISANUPDATE)) + id3_tag_clearframes(tag); + + i = 0; + while ((frame = id3_tag_findframe(new, 0, i++))) { + if (id3_tag_attachframe(tag, frame) == -1) + return -1; + } + } + + return 0; +} + +/* + * NAME: tag_compare() + * DESCRIPTION: tag sort function for qsort() + */ +static +int tag_compare(const void *a, const void *b) +{ + struct filetag const *tag1 = a, *tag2 = b; + + if (tag1->location < tag2->location) + return -1; + else if (tag1->location > tag2->location) + return +1; + + return 0; +} + +/* + * NAME: add_filetag() + * DESCRIPTION: add a new file tag entry + */ +static +int add_filetag(struct id3_file *file, struct filetag const *filetag) +{ + struct filetag *tags; + + tags = realloc(file->tags, (file->ntags + 1) * sizeof(*tags)); + if (tags == 0) + return -1; + + file->tags = tags; + file->tags[file->ntags++] = *filetag; + + /* sort tags by location */ + + if (file->ntags > 1) + qsort(file->tags, file->ntags, sizeof(file->tags[0]), tag_compare); + + return 0; +} + +/* + * NAME: del_filetag() + * DESCRIPTION: delete a file tag entry + */ +static +void del_filetag(struct id3_file *file, unsigned int index) +{ + assert(index < file->ntags); + + while (index < file->ntags - 1) { + file->tags[index] = file->tags[index + 1]; + ++index; + } + + --file->ntags; +} + +/* + * NAME: add_tag() + * DESCRIPTION: read, parse, and add a tag to a file structure + */ +static +struct id3_tag *add_tag(struct id3_file *file, id3_length_t length) +{ + long location; + unsigned int i; + struct filetag filetag; + struct id3_tag *tag; + + location = ftell(file->iofile); + if (location == -1) + return 0; + + /* check for duplication/overlap */ + { + unsigned long begin1, end1, begin2, end2; + + begin1 = location; + end1 = begin1 + length; + + for (i = 0; i < file->ntags; ++i) { + begin2 = file->tags[i].location; + end2 = begin2 + file->tags[i].length; + + if (begin1 == begin2 && end1 == end2) + return file->tags[i].tag; /* duplicate */ + + if (begin1 < end2 && end1 > begin2) + return 0; /* overlap */ + } + } + + tag = read_tag(file->iofile, length); + + filetag.tag = tag; + filetag.location = location; + filetag.length = length; + + if (add_filetag(file, &filetag) == -1 || + update_primary(file->primary, tag) == -1) { + if (tag) + id3_tag_delete(tag); + return 0; + } + + if (tag) + id3_tag_addref(tag); + + return tag; +} + +/* + * NAME: search_tags() + * DESCRIPTION: search for tags in a file + */ +static +int search_tags(struct id3_file *file) +{ + fpos_t save_position; + signed long size; + + /* + * save the current seek position + * + * We also verify the stream is seekable by calling fsetpos(), since + * fgetpos() alone is not reliable enough for this purpose. + * + * [Apparently not even fsetpos() is sufficient under Win32.] + */ + + if (fgetpos(file->iofile, &save_position) == -1 || + fsetpos(file->iofile, &save_position) == -1) + return -1; + + /* look for an ID3v1 tag */ + + if (fseek(file->iofile, -128, SEEK_END) == 0) { + size = query_tag(file->iofile); + if (size > 0) { + struct id3_tag const *tag; + + tag = add_tag(file, size); + + /* if this is indeed an ID3v1 tag, mark the file so */ + + if (tag && (ID3_TAG_VERSION_MAJOR(id3_tag_version(tag)) == 1)) + file->flags |= ID3_FILE_FLAG_ID3V1; + } + } + + /* look for a tag at the beginning of the file */ + + rewind(file->iofile); + + size = query_tag(file->iofile); + if (size > 0) { + struct id3_tag const *tag; + struct id3_frame const *frame; + + tag = add_tag(file, size); + + /* locate tags indicated by SEEK frames */ + + while (tag && (frame = id3_tag_findframe(tag, "SEEK", 0))) { + long seek; + + seek = id3_field_getint(id3_frame_field(frame, 0)); + if (seek < 0 || fseek(file->iofile, seek, SEEK_CUR) == -1) + break; + + size = query_tag(file->iofile); + tag = (size > 0) ? add_tag(file, size) : 0; + } + } + + /* look for a tag at the end of the file (before any ID3v1 tag) */ + + if (fseek(file->iofile, ((file->flags & ID3_FILE_FLAG_ID3V1) ? -128 : 0) + + -10, SEEK_END) == 0) { + size = query_tag(file->iofile); + if (size < 0 && fseek(file->iofile, size, SEEK_CUR) == 0) { + size = query_tag(file->iofile); + if (size > 0) + add_tag(file, size); + } + } + + clearerr(file->iofile); + + /* restore seek position */ + + if (fsetpos(file->iofile, &save_position) == -1) + return -1; + + /* set primary tag options and target padded length for convenience */ + + if ((file->ntags > 0 && !(file->flags & ID3_FILE_FLAG_ID3V1)) || + (file->ntags > 1 && (file->flags & ID3_FILE_FLAG_ID3V1))) { + if (file->tags[0].location == 0) + id3_tag_setlength(file->primary, file->tags[0].length); + else + id3_tag_options(file->primary, ID3_TAG_OPTION_APPENDEDTAG, ~0); + } + + return 0; +} + +/* + * NAME: finish_file() + * DESCRIPTION: release memory associated with a file + */ +static +void finish_file(struct id3_file *file) +{ + unsigned int i; + + if (file->path) + free(file->path); + + if (file->primary) { + id3_tag_delref(file->primary); + id3_tag_delete(file->primary); + } + + for (i = 0; i < file->ntags; ++i) { + struct id3_tag *tag; + + tag = file->tags[i].tag; + if (tag) { + id3_tag_delref(tag); + id3_tag_delete(tag); + } + } + + if (file->tags) + free(file->tags); + + free(file); +} + +/* + * NAME: new_file() + * DESCRIPTION: create a new file structure and load tags + */ +static +struct id3_file *new_file(FILE *iofile, enum id3_file_mode mode, + char const *path) +{ + struct id3_file *file; + + file = malloc(sizeof(*file)); + if (file == 0) + goto fail; + + file->iofile = iofile; + file->mode = mode; + file->path = path ? strdup(path) : 0; + + file->flags = 0; + + file->ntags = 0; + file->tags = 0; + + file->primary = id3_tag_new(); + if (file->primary == 0) + goto fail; + + id3_tag_addref(file->primary); + + /* load tags from the file */ + + if (search_tags(file) == -1) + goto fail; + + id3_tag_options(file->primary, ID3_TAG_OPTION_ID3V1, + (file->flags & ID3_FILE_FLAG_ID3V1) ? ~0 : 0); + + if (0) { + fail: + if (file) { + finish_file(file); + file = 0; + } + } + + return file; +} + +/* + * NAME: file->open() + * DESCRIPTION: open a file given its pathname + */ +struct id3_file *id3_file_open(char const *path, enum id3_file_mode mode) +{ + FILE *iofile; + struct id3_file *file; + + assert(path); + + iofile = fopen(path, (mode == ID3_FILE_MODE_READWRITE) ? "r+b" : "rb"); + if (iofile == 0) + return 0; + + file = new_file(iofile, mode, path); + if (file == 0) + fclose(iofile); + + return file; +} + +/* + * NAME: file->fdopen() + * DESCRIPTION: open a file using an existing file descriptor + */ +struct id3_file *id3_file_fdopen(int fd, enum id3_file_mode mode) +{ +# if 1 || defined(HAVE_UNISTD_H) + FILE *iofile; + struct id3_file *file; + + iofile = fdopen(fd, (mode == ID3_FILE_MODE_READWRITE) ? "r+b" : "rb"); + if (iofile == 0) + return 0; + + file = new_file(iofile, mode, 0); + if (file == 0) { + int save_fd; + + /* close iofile without closing fd */ + + save_fd = dup(fd); + + fclose(iofile); + + dup2(save_fd, fd); + close(save_fd); + } + + return file; +# else + return 0; +# endif +} + +/* + * NAME: file->close() + * DESCRIPTION: close a file and delete its associated tags + */ +int id3_file_close(struct id3_file *file) +{ + int result = 0; + + assert(file); + + if (fclose(file->iofile) == EOF) + result = -1; + + finish_file(file); + + return result; +} + +/* + * NAME: file->tag() + * DESCRIPTION: return the primary tag structure for a file + */ +struct id3_tag *id3_file_tag(struct id3_file const *file) +{ + assert(file); + + return file->primary; +} + +/* + * NAME: v1_write() + * DESCRIPTION: write ID3v1 tag modifications to a file + */ +static +int v1_write(struct id3_file *file, + id3_byte_t const *data, id3_length_t length) +{ + assert(!data || length == 128); + + if (data) { + long location; + + if (fseek(file->iofile, (file->flags & ID3_FILE_FLAG_ID3V1) ? -128 : 0, + SEEK_END) == -1 || + (location = ftell(file->iofile)) == -1 || + fwrite(data, 128, 1, file->iofile) != 1 || + fflush(file->iofile) == EOF) + return -1; + + /* add file tag reference */ + + if (!(file->flags & ID3_FILE_FLAG_ID3V1)) { + struct filetag filetag; + + filetag.tag = 0; + filetag.location = location; + filetag.length = 128; + + if (add_filetag(file, &filetag) == -1) + return -1; + + file->flags |= ID3_FILE_FLAG_ID3V1; + } + } +# if defined(HAVE_FTRUNCATE) + else if (file->flags & ID3_FILE_FLAG_ID3V1) { + long length; + + if (fseek(file->iofile, 0, SEEK_END) == -1) + return -1; + + length = ftell(file->iofile); + if (length == -1 || + (length >= 0 && length < 128)) + return -1; + + if (ftruncate(fileno(file->iofile), length - 128) == -1) + return -1; + + /* delete file tag reference */ + + del_filetag(file, file->ntags - 1); + + file->flags &= ~ID3_FILE_FLAG_ID3V1; + } +# endif + + return 0; +} + +/* + * NAME: v2_write() + * DESCRIPTION: write ID3v2 tag modifications to a file + */ +static +int v2_write(struct id3_file *file, + id3_byte_t const *data, id3_length_t length) +{ + assert(!data || length > 0); + + if (data && + ((file->ntags == 1 && !(file->flags & ID3_FILE_FLAG_ID3V1)) || + (file->ntags == 2 && (file->flags & ID3_FILE_FLAG_ID3V1))) && + file->tags[0].length == length) { + /* easy special case: rewrite existing tag in-place */ + + if (fseek(file->iofile, file->tags[0].location, SEEK_SET) == -1 || + fwrite(data, length, 1, file->iofile) != 1 || + fflush(file->iofile) == EOF) + return -1; + + goto done; + } + + /* hard general case: rewrite entire file */ + + /* ... */ + + done: + return 0; +} + +/* + * NAME: file->update() + * DESCRIPTION: rewrite tag(s) to a file + */ +int id3_file_update(struct id3_file *file) +{ + int options, result = 0; + id3_length_t v1size = 0, v2size = 0; + id3_byte_t id3v1_data[128], *id3v1 = 0, *id3v2 = 0; + + assert(file); + + if (file->mode != ID3_FILE_MODE_READWRITE) + return -1; + + options = id3_tag_options(file->primary, 0, 0); + + /* render ID3v1 */ + + if (options & ID3_TAG_OPTION_ID3V1) { + v1size = id3_tag_render(file->primary, 0); + if (v1size) { + assert(v1size == sizeof(id3v1_data)); + + v1size = id3_tag_render(file->primary, id3v1_data); + if (v1size) { + assert(v1size == sizeof(id3v1_data)); + id3v1 = id3v1_data; + } + } + } + + /* render ID3v2 */ + + id3_tag_options(file->primary, ID3_TAG_OPTION_ID3V1, 0); + + v2size = id3_tag_render(file->primary, 0); + if (v2size) { + id3v2 = malloc(v2size); + if (id3v2 == 0) + goto fail; + + v2size = id3_tag_render(file->primary, id3v2); + if (v2size == 0) { + free(id3v2); + id3v2 = 0; + } + } + + /* write tags */ + + if (v2_write(file, id3v2, v2size) == -1 || + v1_write(file, id3v1, v1size) == -1) + goto fail; + + rewind(file->iofile); + + /* update file tags array? ... */ + + if (0) { + fail: + result = -1; + } + + /* clean up; restore tag options */ + + if (id3v2) + free(id3v2); + + id3_tag_options(file->primary, ~0, options); + + return result; +} diff --git a/libid3tag/file.h b/libid3tag/file.h new file mode 100644 index 0000000..032b189 --- /dev/null +++ b/libid3tag/file.h @@ -0,0 +1,25 @@ +/* + * libid3tag - ID3 tag manipulation library + * Copyright (C) 2000-2004 Underbit Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: file.h,v 1.8 2004/01/23 09:41:32 rob Exp $ + */ + +# ifndef LIBID3TAG_FILE_H +# define LIBID3TAG_FILE_H + +# endif diff --git a/libid3tag/frame.c b/libid3tag/frame.c new file mode 100644 index 0000000..1c680d9 --- /dev/null +++ b/libid3tag/frame.c @@ -0,0 +1,626 @@ +/* + * libid3tag - ID3 tag manipulation library + * Copyright (C) 2000-2004 Underbit Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: frame.c,v 1.15 2004/01/23 09:41:32 rob Exp $ + */ + +# ifdef HAVE_CONFIG_H +# include "config.h" +# endif + +# include "global.h" + +# include +# include + +# ifdef HAVE_ASSERT_H +# include +# endif + +# include "id3tag.h" +# include "frame.h" +# include "frametype.h" +# include "compat.h" +# include "field.h" +# include "render.h" +# include "parse.h" +# include "util.h" + +static +int valid_idchar(char c) +{ + return (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'); +} + +/* + * NAME: frame->validid() + * DESCRIPTION: return true if the parameter string is a legal frame ID + */ +int id3_frame_validid(char const *id) +{ + return id && + valid_idchar(id[0]) && + valid_idchar(id[1]) && + valid_idchar(id[2]) && + valid_idchar(id[3]); +} + +/* + * NAME: frame->new() + * DESCRIPTION: allocate and return a new frame + */ +struct id3_frame *id3_frame_new(char const *id) +{ + struct id3_frametype const *frametype; + struct id3_frame *frame; + unsigned int i; + + if (!id3_frame_validid(id)) + return 0; + + frametype = id3_frametype_lookup(id, 4); + if (frametype == 0) { + switch (id[0]) { + case 'T': + frametype = &id3_frametype_text; + break; + + case 'W': + frametype = &id3_frametype_url; + break; + + case 'X': + case 'Y': + case 'Z': + frametype = &id3_frametype_experimental; + break; + + default: + frametype = &id3_frametype_unknown; + if (id3_compat_lookup(id, 4)) + frametype = &id3_frametype_obsolete; + break; + } + } + + frame = malloc(sizeof(*frame) + frametype->nfields * sizeof(*frame->fields)); + if (frame) { + frame->id[0] = id[0]; + frame->id[1] = id[1]; + frame->id[2] = id[2]; + frame->id[3] = id[3]; + frame->id[4] = 0; + + frame->description = frametype->description; + frame->refcount = 0; + frame->flags = frametype->defaultflags; + frame->group_id = 0; + frame->encryption_method = 0; + frame->encoded = 0; + frame->encoded_length = 0; + frame->decoded_length = 0; + frame->nfields = frametype->nfields; + frame->fields = (union id3_field *) &frame[1]; + + for (i = 0; i < frame->nfields; ++i) + id3_field_init(&frame->fields[i], frametype->fields[i]); + } + + return frame; +} + +void id3_frame_delete(struct id3_frame *frame) +{ + assert(frame); + + if (frame->refcount == 0) { + unsigned int i; + + for (i = 0; i < frame->nfields; ++i) + id3_field_finish(&frame->fields[i]); + + if (frame->encoded) + free(frame->encoded); + + free(frame); + } +} + +/* + * NAME: frame->addref() + * DESCRIPTION: add an external reference to a frame + */ +void id3_frame_addref(struct id3_frame *frame) +{ + assert(frame); + + ++frame->refcount; +} + +/* + * NAME: frame->delref() + * DESCRIPTION: remove an external reference to a frame + */ +void id3_frame_delref(struct id3_frame *frame) +{ + assert(frame && frame->refcount > 0); + + --frame->refcount; +} + +/* + * NAME: frame->field() + * DESCRIPTION: return a pointer to a field in a frame + */ +union id3_field *id3_frame_field(struct id3_frame const *frame, + unsigned int index) +{ + assert(frame); + + return (index < frame->nfields) ? &frame->fields[index] : 0; +} + +static +struct id3_frame *obsolete(char const *id, id3_byte_t const *data, + id3_length_t length) +{ + struct id3_frame *frame; + + frame = id3_frame_new(ID3_FRAME_OBSOLETE); + if (frame) { + if (id3_field_setframeid(&frame->fields[0], id) == -1 || + id3_field_setbinarydata(&frame->fields[1], data, length) == -1) + goto fail; + } + + if (0) { + fail: + if (frame) { + id3_frame_delete(frame); + frame = 0; + } + } + + return frame; +} + +static +struct id3_frame *unparseable(char const *id, id3_byte_t const **ptr, + id3_length_t length, int flags, + int group_id, int encryption_method, + id3_length_t decoded_length) +{ + struct id3_frame *frame = 0; + id3_byte_t *mem; + + mem = malloc(length ? length : 1); + if (mem == 0) + goto fail; + + frame = id3_frame_new(id); + if (frame == 0) + free(mem); + else { + memcpy(mem, *ptr, length); + + frame->flags = flags; + frame->group_id = group_id; + frame->encryption_method = encryption_method; + frame->encoded = mem; + frame->encoded_length = length; + frame->decoded_length = decoded_length; + } + + if (0) { + fail: + ; + } + + *ptr += length; + + return frame; +} + +static +int parse_data(struct id3_frame *frame, + id3_byte_t const *data, id3_length_t length) +{ + enum id3_field_textencoding encoding; + id3_byte_t const *end; + unsigned int i; + + encoding = ID3_FIELD_TEXTENCODING_ISO_8859_1; + + end = data + length; + + for (i = 0; i < frame->nfields; ++i) { + if (id3_field_parse(&frame->fields[i], &data, end - data, &encoding) == -1) + return -1; + } + + return 0; +} + +/* + * NAME: frame->parse() + * DESCRIPTION: parse raw frame data according to the specified ID3 tag version + */ +struct id3_frame *id3_frame_parse(id3_byte_t const **ptr, id3_length_t length, + unsigned int version) +{ + struct id3_frame *frame = 0; + id3_byte_t const *id, *end, *data; + id3_length_t size, decoded_length = 0; + int flags = 0, group_id = 0, encryption_method = 0; + struct id3_compat const *compat = 0; + id3_byte_t *mem = 0; + char xid[4]; + + id = *ptr; + end = *ptr + length; + + if (ID3_TAG_VERSION_MAJOR(version) < 4) { + switch (ID3_TAG_VERSION_MAJOR(version)) { + case 2: + if (length < 6) + goto fail; + + compat = id3_compat_lookup(id, 3); + + *ptr += 3; + size = id3_parse_uint(ptr, 3); + + if (size > end - *ptr) + goto fail; + + end = *ptr + size; + + break; + + case 3: + if (length < 10) + goto fail; + + compat = id3_compat_lookup(id, 4); + + *ptr += 4; + size = id3_parse_uint(ptr, 4); + flags = id3_parse_uint(ptr, 2); + + if (size > end - *ptr) + goto fail; + + end = *ptr + size; + + if (flags & (ID3_FRAME_FLAG_FORMATFLAGS & ~0x00e0)) { + frame = unparseable(id, ptr, end - *ptr, 0, 0, 0, 0); + goto done; + } + + flags = + ((flags >> 1) & ID3_FRAME_FLAG_STATUSFLAGS) | + ((flags >> 4) & (ID3_FRAME_FLAG_COMPRESSION | + ID3_FRAME_FLAG_ENCRYPTION)) | + ((flags << 1) & ID3_FRAME_FLAG_GROUPINGIDENTITY); + + if (flags & ID3_FRAME_FLAG_COMPRESSION) { + if (end - *ptr < 4) + goto fail; + + decoded_length = id3_parse_uint(ptr, 4); + } + + if (flags & ID3_FRAME_FLAG_ENCRYPTION) { + if (end - *ptr < 1) + goto fail; + + encryption_method = id3_parse_uint(ptr, 1); + } + + if (flags & ID3_FRAME_FLAG_GROUPINGIDENTITY) { + if (end - *ptr < 1) + goto fail; + + group_id = id3_parse_uint(ptr, 1); + } + + break; + + default: + goto fail; + } + + /* canonicalize frame ID for ID3v2.4 */ + + if (compat && compat->equiv) + id = compat->equiv; + else if (ID3_TAG_VERSION_MAJOR(version) == 2) { + xid[0] = 'Y'; + xid[1] = id[0]; + xid[2] = id[1]; + xid[3] = id[2]; + + id = xid; + + flags |= + ID3_FRAME_FLAG_TAGALTERPRESERVATION | + ID3_FRAME_FLAG_FILEALTERPRESERVATION; + } + } + else { /* ID3v2.4 */ + if (length < 10) + goto fail; + + *ptr += 4; + size = id3_parse_syncsafe(ptr, 4); + flags = id3_parse_uint(ptr, 2); + + if (size > end - *ptr) + goto fail; + + end = *ptr + size; + + if (flags & (ID3_FRAME_FLAG_FORMATFLAGS & ~ID3_FRAME_FLAG_KNOWNFLAGS)) { + frame = unparseable(id, ptr, end - *ptr, flags, 0, 0, 0); + goto done; + } + + if (flags & ID3_FRAME_FLAG_GROUPINGIDENTITY) { + if (end - *ptr < 1) + goto fail; + + group_id = id3_parse_uint(ptr, 1); + } + + if ((flags & ID3_FRAME_FLAG_COMPRESSION) && + !(flags & ID3_FRAME_FLAG_DATALENGTHINDICATOR)) + goto fail; + + if (flags & ID3_FRAME_FLAG_ENCRYPTION) { + if (end - *ptr < 1) + goto fail; + + encryption_method = id3_parse_uint(ptr, 1); + } + + if (flags & ID3_FRAME_FLAG_DATALENGTHINDICATOR) { + if (end - *ptr < 4) + goto fail; + + decoded_length = id3_parse_syncsafe(ptr, 4); + } + } + + data = *ptr; + *ptr = end; + + /* undo frame encodings */ + + if ((flags & ID3_FRAME_FLAG_UNSYNCHRONISATION) && end - data > 0) { + mem = malloc(end - data); + if (mem == 0) + goto fail; + + memcpy(mem, data, end - data); + + end = mem + id3_util_deunsynchronise(mem, end - data); + data = mem; + } + + if (flags & ID3_FRAME_FLAG_ENCRYPTION) { + frame = unparseable(id, &data, end - data, flags, + group_id, encryption_method, decoded_length); + goto done; + } + + if (flags & ID3_FRAME_FLAG_COMPRESSION) { + id3_byte_t *decomp; + + decomp = id3_util_decompress(data, end - data, decoded_length); + if (decomp == 0) + goto fail; + + if (mem) + free(mem); + + data = mem = decomp; + end = data + decoded_length; + } + + /* check for obsolescence */ + + if (compat && !compat->equiv) { + frame = obsolete(id, data, end - data); + goto done; + } + + /* generate the internal frame structure */ + + frame = id3_frame_new(id); + if (frame) { + frame->flags = flags; + frame->group_id = group_id; + + if (compat && compat->translate) { + if (compat->translate(frame, compat->id, data, end - data) == -1) + goto fail; + } + else { + if (parse_data(frame, data, end - data) == -1) + goto fail; + } + } + + if (0) { + fail: + if (frame) { + id3_frame_delete(frame); + frame = 0; + } + } + + done: + if (mem) + free(mem); + + return frame; +} + +static +id3_length_t render_data(id3_byte_t **ptr, + union id3_field *fields, unsigned int length) +{ + id3_length_t size = 0; + enum id3_field_textencoding encoding; + unsigned int i; + + encoding = ID3_FIELD_TEXTENCODING_ISO_8859_1; + + for (i = 0; i < length; ++i) + size += id3_field_render(&fields[i], ptr, &encoding, i < length - 1); + + return size; +} + +/* + * NAME: frame->render() + * DESCRIPTION: render a single, complete frame + */ +id3_length_t id3_frame_render(struct id3_frame const *frame, + id3_byte_t **ptr, int options) +{ + id3_length_t size = 0, decoded_length, datalen; + id3_byte_t *size_ptr = 0, *flags_ptr = 0, *data = 0; + int flags; + + assert(frame); + + if ((frame->flags & ID3_FRAME_FLAG_TAGALTERPRESERVATION) || + ((options & ID3_TAG_OPTION_FILEALTERED) && + (frame->flags & ID3_FRAME_FLAG_FILEALTERPRESERVATION))) + return 0; + + /* a frame must be at least 1 byte big, excluding the header */ + + decoded_length = render_data(0, frame->fields, frame->nfields); + if (decoded_length == 0 && frame->encoded == 0) + return 0; + + /* header */ + + size += id3_render_immediate(ptr, frame->id, 4); + + if (ptr) + size_ptr = *ptr; + + size += id3_render_syncsafe(ptr, 0, 4); + + if (ptr) + flags_ptr = *ptr; + + flags = frame->flags; + + size += id3_render_int(ptr, flags, 2); + + if (flags & (ID3_FRAME_FLAG_FORMATFLAGS & ~ID3_FRAME_FLAG_KNOWNFLAGS)) { + size += id3_render_binary(ptr, frame->encoded, frame->encoded_length); + if (size_ptr) + id3_render_syncsafe(&size_ptr, size - 10, 4); + + return size; + } + + flags &= ID3_FRAME_FLAG_KNOWNFLAGS; + + flags &= ~ID3_FRAME_FLAG_UNSYNCHRONISATION; + if (options & ID3_TAG_OPTION_UNSYNCHRONISATION) + flags |= ID3_FRAME_FLAG_UNSYNCHRONISATION; + + if (!(flags & ID3_FRAME_FLAG_ENCRYPTION)) { + flags &= ~ID3_FRAME_FLAG_COMPRESSION; + if (options & ID3_TAG_OPTION_COMPRESSION) + flags |= ID3_FRAME_FLAG_COMPRESSION | ID3_FRAME_FLAG_DATALENGTHINDICATOR; + } + + if (flags & ID3_FRAME_FLAG_GROUPINGIDENTITY) + size += id3_render_int(ptr, frame->group_id, 1); + if (flags & ID3_FRAME_FLAG_ENCRYPTION) + size += id3_render_int(ptr, frame->encryption_method, 1); + if (flags & ID3_FRAME_FLAG_DATALENGTHINDICATOR) { + if (flags & ID3_FRAME_FLAG_ENCRYPTION) + decoded_length = frame->decoded_length; + size += id3_render_syncsafe(ptr, decoded_length, 4); + } + + if (ptr) + data = *ptr; + + if (flags & ID3_FRAME_FLAG_ENCRYPTION) + datalen = id3_render_binary(ptr, frame->encoded, frame->encoded_length); + else { + if (ptr == 0) + datalen = decoded_length; + else { + datalen = render_data(ptr, frame->fields, frame->nfields); + + if (flags & ID3_FRAME_FLAG_COMPRESSION) { + id3_byte_t *comp; + id3_length_t complen; + + comp = id3_util_compress(data, datalen, &complen); + if (comp == 0) + flags &= ~ID3_FRAME_FLAG_COMPRESSION; + else { + *ptr = data; + datalen = id3_render_binary(ptr, comp, complen); + + free(comp); + } + } + } + } + + /* unsynchronisation */ + + if (flags & ID3_FRAME_FLAG_UNSYNCHRONISATION) { + if (data == 0) + datalen *= 2; + else { + id3_length_t newlen; + + newlen = id3_util_unsynchronise(data, datalen); + if (newlen == datalen) + flags &= ~ID3_FRAME_FLAG_UNSYNCHRONISATION; + else { + *ptr += newlen - datalen; + datalen = newlen; + } + } + } + + size += datalen; + + /* patch size and flags */ + + if (size_ptr) + id3_render_syncsafe(&size_ptr, size - 10, 4); + if (flags_ptr) + id3_render_int(&flags_ptr, flags, 2); + + return size; +} diff --git a/libid3tag/frame.h b/libid3tag/frame.h new file mode 100644 index 0000000..05c6b04 --- /dev/null +++ b/libid3tag/frame.h @@ -0,0 +1,36 @@ +/* + * libid3tag - ID3 tag manipulation library + * Copyright (C) 2000-2004 Underbit Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: frame.h,v 1.8 2004/01/23 09:41:32 rob Exp $ + */ + +# ifndef LIBID3TAG_FRAME_H +# define LIBID3TAG_FRAME_H + +# include "id3tag.h" + +int id3_frame_validid(char const *); + +void id3_frame_addref(struct id3_frame *); +void id3_frame_delref(struct id3_frame *); + +struct id3_frame *id3_frame_parse(id3_byte_t const **, id3_length_t, + unsigned int); +id3_length_t id3_frame_render(struct id3_frame const *, id3_byte_t **, int); + +# endif diff --git a/libid3tag/frametype.c b/libid3tag/frametype.c new file mode 100644 index 0000000..13c5001 --- /dev/null +++ b/libid3tag/frametype.c @@ -0,0 +1,568 @@ +/* C code produced by gperf version 3.0.1 */ +/* Command-line: gperf -tCcTonD -K id -N id3_frametype_lookup -s -3 -k '*' frametype.gperf */ + +#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \ + && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \ + && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \ + && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \ + && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \ + && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \ + && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \ + && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \ + && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \ + && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \ + && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \ + && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \ + && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \ + && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \ + && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \ + && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \ + && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \ + && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \ + && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \ + && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \ + && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \ + && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \ + && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126)) +/* The character set is not based on ISO-646. */ +error "gperf generated tables don't work with this execution character set. Please report a bug to ." +#endif + +#line 1 "frametype.gperf" + +/* + * libid3tag - ID3 tag manipulation library + * Copyright (C) 2000-2004 Underbit Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Id: frametype.gperf,v 1.7 2004/01/23 09:41:32 rob Exp + */ + +# ifdef HAVE_CONFIG_H +# include "config.h" +# endif + +# include "global.h" + +# include + +# include "id3tag.h" +# include "frametype.h" + +# define FIELDS(id) static enum id3_field_type const fields_##id[] + +/* frame field descriptions */ + +FIELDS(UFID) = { + ID3_FIELD_TYPE_LATIN1, + ID3_FIELD_TYPE_BINARYDATA +}; + +FIELDS(TXXX) = { + ID3_FIELD_TYPE_TEXTENCODING, + ID3_FIELD_TYPE_STRING, + ID3_FIELD_TYPE_STRING +}; + +FIELDS(WXXX) = { + ID3_FIELD_TYPE_TEXTENCODING, + ID3_FIELD_TYPE_STRING, + ID3_FIELD_TYPE_LATIN1 +}; + +FIELDS(MCDI) = { + ID3_FIELD_TYPE_BINARYDATA +}; + +FIELDS(ETCO) = { + ID3_FIELD_TYPE_INT8, + ID3_FIELD_TYPE_BINARYDATA +}; + +FIELDS(MLLT) = { + ID3_FIELD_TYPE_INT16, + ID3_FIELD_TYPE_INT24, + ID3_FIELD_TYPE_INT24, + ID3_FIELD_TYPE_INT8, + ID3_FIELD_TYPE_INT8, + ID3_FIELD_TYPE_BINARYDATA +}; + +FIELDS(SYTC) = { + ID3_FIELD_TYPE_INT8, + ID3_FIELD_TYPE_BINARYDATA +}; + +FIELDS(USLT) = { + ID3_FIELD_TYPE_TEXTENCODING, + ID3_FIELD_TYPE_LANGUAGE, + ID3_FIELD_TYPE_STRING, + ID3_FIELD_TYPE_STRINGFULL +}; + +FIELDS(SYLT) = { + ID3_FIELD_TYPE_TEXTENCODING, + ID3_FIELD_TYPE_LANGUAGE, + ID3_FIELD_TYPE_INT8, + ID3_FIELD_TYPE_INT8, + ID3_FIELD_TYPE_STRING, + ID3_FIELD_TYPE_BINARYDATA +}; + +FIELDS(COMM) = { + ID3_FIELD_TYPE_TEXTENCODING, + ID3_FIELD_TYPE_LANGUAGE, + ID3_FIELD_TYPE_STRING, + ID3_FIELD_TYPE_STRINGFULL +}; + +FIELDS(RVA2) = { + ID3_FIELD_TYPE_LATIN1, + ID3_FIELD_TYPE_BINARYDATA +}; + +FIELDS(EQU2) = { + ID3_FIELD_TYPE_INT8, + ID3_FIELD_TYPE_LATIN1, + ID3_FIELD_TYPE_BINARYDATA +}; + +FIELDS(RVRB) = { + ID3_FIELD_TYPE_INT16, + ID3_FIELD_TYPE_INT16, + ID3_FIELD_TYPE_INT8, + ID3_FIELD_TYPE_INT8, + ID3_FIELD_TYPE_INT8, + ID3_FIELD_TYPE_INT8, + ID3_FIELD_TYPE_INT8, + ID3_FIELD_TYPE_INT8, + ID3_FIELD_TYPE_INT8, + ID3_FIELD_TYPE_INT8 +}; + +FIELDS(APIC) = { + ID3_FIELD_TYPE_TEXTENCODING, + ID3_FIELD_TYPE_LATIN1, + ID3_FIELD_TYPE_INT8, + ID3_FIELD_TYPE_STRING, + ID3_FIELD_TYPE_BINARYDATA +}; + +FIELDS(GEOB) = { + ID3_FIELD_TYPE_TEXTENCODING, + ID3_FIELD_TYPE_LATIN1, + ID3_FIELD_TYPE_STRING, + ID3_FIELD_TYPE_STRING, + ID3_FIELD_TYPE_BINARYDATA +}; + +FIELDS(PCNT) = { + ID3_FIELD_TYPE_INT32PLUS +}; + +FIELDS(POPM) = { + ID3_FIELD_TYPE_LATIN1, + ID3_FIELD_TYPE_INT8, + ID3_FIELD_TYPE_INT32PLUS +}; + +FIELDS(RBUF) = { + ID3_FIELD_TYPE_INT24, + ID3_FIELD_TYPE_INT8, + ID3_FIELD_TYPE_INT32 +}; + +FIELDS(AENC) = { + ID3_FIELD_TYPE_LATIN1, + ID3_FIELD_TYPE_INT16, + ID3_FIELD_TYPE_INT16, + ID3_FIELD_TYPE_BINARYDATA +}; + +FIELDS(LINK) = { + ID3_FIELD_TYPE_FRAMEID, + ID3_FIELD_TYPE_LATIN1, + ID3_FIELD_TYPE_LATIN1LIST +}; + +FIELDS(POSS) = { + ID3_FIELD_TYPE_INT8, + ID3_FIELD_TYPE_BINARYDATA +}; + +FIELDS(USER) = { + ID3_FIELD_TYPE_TEXTENCODING, + ID3_FIELD_TYPE_LANGUAGE, + ID3_FIELD_TYPE_STRING +}; + +FIELDS(OWNE) = { + ID3_FIELD_TYPE_TEXTENCODING, + ID3_FIELD_TYPE_LATIN1, + ID3_FIELD_TYPE_DATE, + ID3_FIELD_TYPE_STRING +}; + +FIELDS(COMR) = { + ID3_FIELD_TYPE_TEXTENCODING, + ID3_FIELD_TYPE_LATIN1, + ID3_FIELD_TYPE_DATE, + ID3_FIELD_TYPE_LATIN1, + ID3_FIELD_TYPE_INT8, + ID3_FIELD_TYPE_STRING, + ID3_FIELD_TYPE_STRING, + ID3_FIELD_TYPE_LATIN1, + ID3_FIELD_TYPE_BINARYDATA +}; + +FIELDS(ENCR) = { + ID3_FIELD_TYPE_LATIN1, + ID3_FIELD_TYPE_INT8, + ID3_FIELD_TYPE_BINARYDATA +}; + +FIELDS(GRID) = { + ID3_FIELD_TYPE_LATIN1, + ID3_FIELD_TYPE_INT8, + ID3_FIELD_TYPE_BINARYDATA +}; + +FIELDS(PRIV) = { + ID3_FIELD_TYPE_LATIN1, + ID3_FIELD_TYPE_BINARYDATA +}; + +FIELDS(SIGN) = { + ID3_FIELD_TYPE_INT8, + ID3_FIELD_TYPE_BINARYDATA +}; + +FIELDS(SEEK) = { + ID3_FIELD_TYPE_INT32 +}; + +FIELDS(ASPI) = { + ID3_FIELD_TYPE_INT32, + ID3_FIELD_TYPE_INT32, + ID3_FIELD_TYPE_INT16, + ID3_FIELD_TYPE_INT8, + ID3_FIELD_TYPE_BINARYDATA +}; + +FIELDS(text) = { + ID3_FIELD_TYPE_TEXTENCODING, + ID3_FIELD_TYPE_STRINGLIST +}; + +FIELDS(url) = { + ID3_FIELD_TYPE_LATIN1 +}; + +FIELDS(unknown) = { + ID3_FIELD_TYPE_BINARYDATA +}; + +FIELDS(ZOBS) = { + ID3_FIELD_TYPE_FRAMEID, + ID3_FIELD_TYPE_BINARYDATA +}; + +# define FRAME(id) \ + sizeof(fields_##id) / sizeof(fields_##id[0]), fields_##id + +# define PRESERVE 0 +# define DISCARD ID3_FRAME_FLAG_FILEALTERPRESERVATION +# define OBSOLETE (DISCARD | ID3_FRAME_FLAG_TAGALTERPRESERVATION) + +# define FRAMETYPE(type, id, flags, desc) \ + struct id3_frametype const id3_frametype_##type = { \ + 0, FRAME(id), flags, desc \ + } + +/* static frame types */ + +FRAMETYPE(text, text, PRESERVE, "Unknown text information frame"); +FRAMETYPE(url, url, PRESERVE, "Unknown URL link frame"); +FRAMETYPE(experimental, unknown, PRESERVE, "Experimental frame"); +FRAMETYPE(unknown, unknown, PRESERVE, "Unknown frame"); +FRAMETYPE(obsolete, unknown, OBSOLETE, "Obsolete frame"); + +#define TOTAL_KEYWORDS 84 +#define MIN_WORD_LENGTH 4 +#define MAX_WORD_LENGTH 4 +#define MIN_HASH_VALUE 7 +#define MAX_HASH_VALUE 155 +/* maximum key range = 149, duplicates = 0 */ + +#ifdef __GNUC__ +__inline +#else +#ifdef __cplusplus +inline +#endif +#endif +static unsigned int +hash (str, len) + register const char *str; + register unsigned int len; +{ + static const unsigned char asso_values[] = + { + 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, + 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, + 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, + 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, + 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, + 43, 4, 47, 49, 156, 156, 156, 156, 156, 156, + 156, 156, 156, 156, 156, 31, 53, 3, 15, 3, + 24, 25, 10, 52, 69, 34, 23, 30, 1, 5, + 10, 62, 20, 0, 28, 28, 22, 19, 47, 3, + 10, 156, 156, 156, 156, 156, 156, 156, 156, 156, + 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, + 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, + 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, + 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, + 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, + 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, + 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, + 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, + 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, + 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, + 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, + 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, + 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, + 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, + 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, + 156, 156, 156, 156, 156, 156, 156 + }; + return asso_values[(unsigned char)str[3]+1] + asso_values[(unsigned char)str[2]] + asso_values[(unsigned char)str[1]] + asso_values[(unsigned char)str[0]]; +} + +#ifdef __GNUC__ +__inline +#endif +const struct id3_frametype * +id3_frametype_lookup (str, len) + register const char *str; + register unsigned int len; +{ + static const struct id3_frametype wordlist[] = + { +#line 282 "frametype.gperf" + {"ENCR", FRAME(ENCR), PRESERVE, "Encryption method registration"}, +#line 292 "frametype.gperf" + {"POPM", FRAME(POPM), PRESERVE, "Popularimeter"}, +#line 351 "frametype.gperf" + {"WCOM", FRAME(url), PRESERVE, "Commercial information"}, +#line 298 "frametype.gperf" + {"SEEK", FRAME(SEEK), DISCARD, "Seek frame"}, +#line 349 "frametype.gperf" + {"USER", FRAME(USER), PRESERVE, "Terms of use"}, +#line 285 "frametype.gperf" + {"GEOB", FRAME(GEOB), PRESERVE, "General encapsulated object"}, +#line 304 "frametype.gperf" + {"TCOM", FRAME(text), PRESERVE, "Composer"}, +#line 281 "frametype.gperf" + {"COMR", FRAME(COMR), PRESERVE, "Commercial frame"}, +#line 280 "frametype.gperf" + {"COMM", FRAME(COMM), PRESERVE, "Comments"}, +#line 305 "frametype.gperf" + {"TCON", FRAME(text), PRESERVE, "Content type"}, +#line 291 "frametype.gperf" + {"PCNT", FRAME(PCNT), PRESERVE, "Play counter"}, +#line 293 "frametype.gperf" + {"POSS", FRAME(POSS), DISCARD, "Position synchronisation frame"}, +#line 284 "frametype.gperf" + {"ETCO", FRAME(ETCO), DISCARD, "Event timing codes"}, +#line 332 "frametype.gperf" + {"TPE2", FRAME(text), PRESERVE, "Band/orchestra/accompaniment"}, +#line 301 "frametype.gperf" + {"SYTC", FRAME(SYTC), DISCARD, "Synchronised tempo codes"}, +#line 313 "frametype.gperf" + {"TENC", FRAME(text), DISCARD, "Encoded by"}, +#line 309 "frametype.gperf" + {"TDOR", FRAME(text), PRESERVE, "Original release time"}, +#line 290 "frametype.gperf" + {"OWNE", FRAME(OWNE), PRESERVE, "Ownership frame"}, +#line 277 "frametype.gperf" + {"AENC", FRAME(AENC), DISCARD, "Audio encryption"}, +#line 307 "frametype.gperf" + {"TDEN", FRAME(text), PRESERVE, "Encoding time"}, +#line 345 "frametype.gperf" + {"TSSE", FRAME(text), PRESERVE, "Software/hardware and settings used for encoding"}, +#line 339 "frametype.gperf" + {"TRSN", FRAME(text), PRESERVE, "Internet radio station name"}, +#line 300 "frametype.gperf" + {"SYLT", FRAME(SYLT), DISCARD, "Synchronised lyric/text"}, +#line 354 "frametype.gperf" + {"WOAR", FRAME(url), PRESERVE, "Official artist/performer webpage"}, +#line 346 "frametype.gperf" + {"TSST", FRAME(text), PRESERVE, "Set subtitle"}, +#line 330 "frametype.gperf" + {"TOWN", FRAME(text), PRESERVE, "File owner/licensee"}, +#line 340 "frametype.gperf" + {"TRSO", FRAME(text), PRESERVE, "Internet radio station owner"}, +#line 322 "frametype.gperf" + {"TLEN", FRAME(text), DISCARD, "Length"}, +#line 358 "frametype.gperf" + {"WPUB", FRAME(url), PRESERVE, "Publishers official webpage"}, +#line 343 "frametype.gperf" + {"TSOT", FRAME(text), PRESERVE, "Title sort order"}, +#line 327 "frametype.gperf" + {"TOFN", FRAME(text), PRESERVE, "Original filename"}, +#line 344 "frametype.gperf" + {"TSRC", FRAME(text), PRESERVE, "ISRC (international standard recording code)"}, +#line 324 "frametype.gperf" + {"TMED", FRAME(text), PRESERVE, "Media type"}, +#line 297 "frametype.gperf" + {"RVRB", FRAME(RVRB), PRESERVE, "Reverb"}, +#line 328 "frametype.gperf" + {"TOLY", FRAME(text), PRESERVE, "Original lyricist(s)/text writer(s)"}, +#line 329 "frametype.gperf" + {"TOPE", FRAME(text), PRESERVE, "Original artist(s)/performer(s)"}, +#line 336 "frametype.gperf" + {"TPRO", FRAME(text), PRESERVE, "Produced notice"}, +#line 337 "frametype.gperf" + {"TPUB", FRAME(text), PRESERVE, "Publisher"}, +#line 357 "frametype.gperf" + {"WPAY", FRAME(url), PRESERVE, "Payment"}, +#line 335 "frametype.gperf" + {"TPOS", FRAME(text), PRESERVE, "Part of a set"}, +#line 356 "frametype.gperf" + {"WORS", FRAME(url), PRESERVE, "Official Internet radio station homepage"}, +#line 325 "frametype.gperf" + {"TMOO", FRAME(text), PRESERVE, "Mood"}, +#line 338 "frametype.gperf" + {"TRCK", FRAME(text), PRESERVE, "Track number/position in set"}, +#line 320 "frametype.gperf" + {"TKEY", FRAME(text), PRESERVE, "Initial key"}, +#line 308 "frametype.gperf" + {"TDLY", FRAME(text), PRESERVE, "Playlist delay"}, +#line 296 "frametype.gperf" + {"RVA2", FRAME(RVA2), DISCARD, "Relative volume adjustment (2)"}, +#line 310 "frametype.gperf" + {"TDRC", FRAME(text), PRESERVE, "Recording time"}, +#line 350 "frametype.gperf" + {"USLT", FRAME(USLT), PRESERVE, "Unsynchronised lyric/text transcription"}, +#line 353 "frametype.gperf" + {"WOAF", FRAME(url), PRESERVE, "Official audio file webpage"}, +#line 312 "frametype.gperf" + {"TDTG", FRAME(text), PRESERVE, "Tagging time"}, +#line 299 "frametype.gperf" + {"SIGN", FRAME(SIGN), PRESERVE, "Signature frame"}, +#line 355 "frametype.gperf" + {"WOAS", FRAME(url), PRESERVE, "Official audio source webpage"}, +#line 331 "frametype.gperf" + {"TPE1", FRAME(text), PRESERVE, "Lead performer(s)/soloist(s)"}, +#line 302 "frametype.gperf" + {"TALB", FRAME(text), PRESERVE, "Album/movie/show title"}, +#line 341 "frametype.gperf" + {"TSOA", FRAME(text), PRESERVE, "Album sort order"}, +#line 321 "frametype.gperf" + {"TLAN", FRAME(text), PRESERVE, "Language(s)"}, +#line 333 "frametype.gperf" + {"TPE3", FRAME(text), PRESERVE, "Conductor/performer refinement"}, +#line 352 "frametype.gperf" + {"WCOP", FRAME(url), PRESERVE, "Copyright/legal information"}, +#line 334 "frametype.gperf" + {"TPE4", FRAME(text), PRESERVE, "Interpreted, remixed, or otherwise modified by"}, +#line 323 "frametype.gperf" + {"TMCL", FRAME(text), PRESERVE, "Musician credits list"}, +#line 303 "frametype.gperf" + {"TBPM", FRAME(text), PRESERVE, "BPM (beats per minute)"}, +#line 311 "frametype.gperf" + {"TDRL", FRAME(text), PRESERVE, "Release time"}, +#line 326 "frametype.gperf" + {"TOAL", FRAME(text), PRESERVE, "Original album/movie/show title"}, +#line 342 "frametype.gperf" + {"TSOP", FRAME(text), PRESERVE, "Performer sort order"}, +#line 363 "frametype.gperf" + {"ZOBS", FRAME(ZOBS), OBSOLETE, "Obsolete frame"}, +#line 283 "frametype.gperf" + {"EQU2", FRAME(EQU2), DISCARD, "Equalisation (2)"}, +#line 306 "frametype.gperf" + {"TCOP", FRAME(text), PRESERVE, "Copyright message"}, +#line 287 "frametype.gperf" + {"LINK", FRAME(LINK), PRESERVE, "Linked information"}, +#line 286 "frametype.gperf" + {"GRID", FRAME(GRID), PRESERVE, "Group identification registration"}, +#line 294 "frametype.gperf" + {"PRIV", FRAME(PRIV), PRESERVE, "Private frame"}, +#line 315 "frametype.gperf" + {"TFLT", FRAME(text), PRESERVE, "File type"}, +#line 289 "frametype.gperf" + {"MLLT", FRAME(MLLT), DISCARD, "MPEG location lookup table"}, +#line 314 "frametype.gperf" + {"TEXT", FRAME(text), PRESERVE, "Lyricist/text writer"}, +#line 348 "frametype.gperf" + {"UFID", FRAME(UFID), PRESERVE, "Unique file identifier"}, +#line 278 "frametype.gperf" + {"APIC", FRAME(APIC), PRESERVE, "Attached picture"}, +#line 279 "frametype.gperf" + {"ASPI", FRAME(ASPI), DISCARD, "Audio seek point index"}, +#line 318 "frametype.gperf" + {"TIT2", FRAME(text), PRESERVE, "Title/songname/content description"}, +#line 359 "frametype.gperf" + {"WXXX", FRAME(WXXX), PRESERVE, "User defined URL link frame"}, +#line 288 "frametype.gperf" + {"MCDI", FRAME(MCDI), PRESERVE, "Music CD identifier"}, +#line 316 "frametype.gperf" + {"TIPL", FRAME(text), PRESERVE, "Involved people list"}, +#line 347 "frametype.gperf" + {"TXXX", FRAME(TXXX), PRESERVE, "User defined text information frame"}, +#line 295 "frametype.gperf" + {"RBUF", FRAME(RBUF), PRESERVE, "Recommended buffer size"}, +#line 317 "frametype.gperf" + {"TIT1", FRAME(text), PRESERVE, "Content group description"}, +#line 319 "frametype.gperf" + {"TIT3", FRAME(text), PRESERVE, "Subtitle/description refinement"} + }; + + static const short lookup[] = + { + -1, -1, -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, + 2, 3, -1, 4, -1, -1, -1, -1, 5, 6, 7, 8, -1, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, + 66, 67, 68, 69, -1, 70, 71, -1, 72, 73, 74, -1, 75, -1, + 76, -1, -1, -1, 77, 78, -1, -1, 79, -1, -1, -1, -1, 80, + 81, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 82, -1, -1, + -1, 83 + }; + + if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) + { + register int key = hash (str, len); + + if (key <= MAX_HASH_VALUE && key >= 0) + { + register int index = lookup[key]; + + if (index >= 0) + { + register const char *s = wordlist[index].id; + + if (*str == *s && !strncmp (str + 1, s + 1, len - 1) && s[len] == '\0') + return &wordlist[index]; + } + } + } + return 0; +} diff --git a/libid3tag/frametype.h b/libid3tag/frametype.h new file mode 100644 index 0000000..dd064b2 --- /dev/null +++ b/libid3tag/frametype.h @@ -0,0 +1,42 @@ +/* + * libid3tag - ID3 tag manipulation library + * Copyright (C) 2000-2004 Underbit Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: frametype.h,v 1.7 2004/01/23 09:41:32 rob Exp $ + */ + +# ifndef LIBID3TAG_FRAMETYPE_H +# define LIBID3TAG_FRAMETYPE_H + +struct id3_frametype { + char const *id; + unsigned int nfields; + enum id3_field_type const *fields; + int defaultflags; + char const *description; +}; + +extern struct id3_frametype const id3_frametype_text; +extern struct id3_frametype const id3_frametype_url; +extern struct id3_frametype const id3_frametype_experimental; +extern struct id3_frametype const id3_frametype_unknown; +extern struct id3_frametype const id3_frametype_obsolete; + +struct id3_frametype const *id3_frametype_lookup(register char const *, + register unsigned int); + +# endif diff --git a/libid3tag/genre.c b/libid3tag/genre.c new file mode 100644 index 0000000..32fccb1 --- /dev/null +++ b/libid3tag/genre.c @@ -0,0 +1,151 @@ +/* + * libid3tag - ID3 tag manipulation library + * Copyright (C) 2000-2004 Underbit Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: genre.c,v 1.8 2004/01/23 09:41:32 rob Exp $ + */ + +# ifdef HAVE_CONFIG_H +# include "config.h" +# endif + +# include "global.h" + +# include "id3tag.h" +# include "ucs4.h" + +/* genres are stored in ucs4 format */ +# include "genre.dat" + +# define NGENRES (sizeof(genre_table) / sizeof(genre_table[0])) + +/* + * NAME: genre->index() + * DESCRIPTION: return an ID3v1 genre string indexed by number + */ +id3_ucs4_t const *id3_genre_index(unsigned int index) +{ + return (index < NGENRES) ? genre_table[index] : 0; +} + +/* + * NAME: genre->name() + * DESCRIPTION: translate an ID3v2 genre number/keyword to its full name + */ +id3_ucs4_t const *id3_genre_name(id3_ucs4_t const *string) +{ + id3_ucs4_t const *ptr; + static id3_ucs4_t const genre_remix[] = { 'R', 'e', 'm', 'i', 'x', 0 }; + static id3_ucs4_t const genre_cover[] = { 'C', 'o', 'v', 'e', 'r', 0 }; + unsigned long number; + + if (string == 0 || *string == 0) + return id3_ucs4_empty; + + if (string[0] == 'R' && string[1] == 'X' && string[2] == 0) + return genre_remix; + if (string[0] == 'C' && string[1] == 'R' && string[2] == 0) + return genre_cover; + + for (ptr = string; *ptr; ++ptr) { + if (*ptr < '0' || *ptr > '9') + return string; + } + + number = id3_ucs4_getnumber(string); + + return (number < NGENRES) ? genre_table[number] : string; +} + +/* + * NAME: translate() + * DESCRIPTION: return a canonicalized character for testing genre equivalence + */ +static +id3_ucs4_t translate(id3_ucs4_t ch) +{ + if (ch) { + if (ch >= 'A' && ch <= 'Z') + ch += 'a' - 'A'; + + if (ch < 'a' || ch > 'z') + ch = ID3_UCS4_REPLACEMENTCHAR; + } + + return ch; +} + +/* + * NAME: compare() + * DESCRIPTION: test two ucs4 genre strings for equivalence + */ +static +int compare(id3_ucs4_t const *str1, id3_ucs4_t const *str2) +{ + id3_ucs4_t c1, c2; + + if (str1 == str2) + return 1; + + do { + do + c1 = translate(*str1++); + while (c1 == ID3_UCS4_REPLACEMENTCHAR); + + do + c2 = translate(*str2++); + while (c2 == ID3_UCS4_REPLACEMENTCHAR); + } + while (c1 && c1 == c2); + + return c1 == c2; +} + +/* + * NAME: genre->number() + * DESCRIPTION: translate an ID3v2 genre name/number to its ID3v1 index number + */ +int id3_genre_number(id3_ucs4_t const *string) +{ + id3_ucs4_t const *ptr; + int i; + + if (string == 0 || *string == 0) + return -1; + + for (ptr = string; *ptr; ++ptr) { + if (*ptr < '0' || *ptr > '9') + break; + } + + if (*ptr == 0) { + unsigned long number; + + number = id3_ucs4_getnumber(string); + + return (number <= 0xff) ? number : -1; + } + + for (i = 0; i < NGENRES; ++i) { + if (compare(string, genre_table[i])) + return i; + } + + /* no equivalent */ + + return -1; +} diff --git a/libid3tag/genre.dat b/libid3tag/genre.dat new file mode 100644 index 0000000..17acab5 --- /dev/null +++ b/libid3tag/genre.dat @@ -0,0 +1,480 @@ +/* Automatically generated from genre.dat.in */ +/* + * libid3tag - ID3 tag manipulation library + * Copyright (C) 2000-2004 Underbit Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Id: genre.dat.in,v 1.7 2004/01/23 09:41:32 rob Exp + */ + +/* + * These are the ID3 genre names, taken as a combination of names from ID3v1 + * (listed in Appendix A of the ID3 tag version 2.4.0 informal standard) and + * the extensions made by Winamp as of version 2.80. + */ + +/* ID3v1 names (0-79) */ + +static id3_ucs4_t const genre_BLUES[] = + { 'B', 'l', 'u', 'e', 's', 0 }; +static id3_ucs4_t const genre_CLASSIC_ROCK[] = + { 'C', 'l', 'a', 's', 's', 'i', 'c', ' ', 'R', 'o', 'c', 'k', 0 }; +static id3_ucs4_t const genre_COUNTRY[] = + { 'C', 'o', 'u', 'n', 't', 'r', 'y', 0 }; +static id3_ucs4_t const genre_DANCE[] = + { 'D', 'a', 'n', 'c', 'e', 0 }; +static id3_ucs4_t const genre_DISCO[] = + { 'D', 'i', 's', 'c', 'o', 0 }; +static id3_ucs4_t const genre_FUNK[] = + { 'F', 'u', 'n', 'k', 0 }; +static id3_ucs4_t const genre_GRUNGE[] = + { 'G', 'r', 'u', 'n', 'g', 'e', 0 }; +static id3_ucs4_t const genre_HIP_HOP[] = + { 'H', 'i', 'p', '-', 'H', 'o', 'p', 0 }; +static id3_ucs4_t const genre_JAZZ[] = + { 'J', 'a', 'z', 'z', 0 }; +static id3_ucs4_t const genre_METAL[] = + { 'M', 'e', 't', 'a', 'l', 0 }; +static id3_ucs4_t const genre_NEW_AGE[] = + { 'N', 'e', 'w', ' ', 'A', 'g', 'e', 0 }; +static id3_ucs4_t const genre_OLDIES[] = + { 'O', 'l', 'd', 'i', 'e', 's', 0 }; +static id3_ucs4_t const genre_OTHER[] = + { 'O', 't', 'h', 'e', 'r', 0 }; +static id3_ucs4_t const genre_POP[] = + { 'P', 'o', 'p', 0 }; +static id3_ucs4_t const genre_R_B[] = + { 'R', '&', 'B', 0 }; +static id3_ucs4_t const genre_RAP[] = + { 'R', 'a', 'p', 0 }; +static id3_ucs4_t const genre_REGGAE[] = + { 'R', 'e', 'g', 'g', 'a', 'e', 0 }; +static id3_ucs4_t const genre_ROCK[] = + { 'R', 'o', 'c', 'k', 0 }; +static id3_ucs4_t const genre_TECHNO[] = + { 'T', 'e', 'c', 'h', 'n', 'o', 0 }; +static id3_ucs4_t const genre_INDUSTRIAL[] = + { 'I', 'n', 'd', 'u', 's', 't', 'r', 'i', 'a', 'l', 0 }; +static id3_ucs4_t const genre_ALTERNATIVE[] = + { 'A', 'l', 't', 'e', 'r', 'n', 'a', 't', 'i', 'v', 'e', 0 }; +static id3_ucs4_t const genre_SKA[] = + { 'S', 'k', 'a', 0 }; +static id3_ucs4_t const genre_DEATH_METAL[] = + { 'D', 'e', 'a', 't', 'h', ' ', 'M', 'e', 't', 'a', 'l', 0 }; +static id3_ucs4_t const genre_PRANKS[] = + { 'P', 'r', 'a', 'n', 'k', 's', 0 }; +static id3_ucs4_t const genre_SOUNDTRACK[] = + { 'S', 'o', 'u', 'n', 'd', 't', 'r', 'a', 'c', 'k', 0 }; +static id3_ucs4_t const genre_EURO_TECHNO[] = + { 'E', 'u', 'r', 'o', '-', 'T', 'e', 'c', 'h', 'n', 'o', 0 }; +static id3_ucs4_t const genre_AMBIENT[] = + { 'A', 'm', 'b', 'i', 'e', 'n', 't', 0 }; +static id3_ucs4_t const genre_TRIP_HOP[] = + { 'T', 'r', 'i', 'p', '-', 'H', 'o', 'p', 0 }; +static id3_ucs4_t const genre_VOCAL[] = + { 'V', 'o', 'c', 'a', 'l', 0 }; +static id3_ucs4_t const genre_JAZZ_FUNK[] = + { 'J', 'a', 'z', 'z', '+', 'F', 'u', 'n', 'k', 0 }; +static id3_ucs4_t const genre_FUSION[] = + { 'F', 'u', 's', 'i', 'o', 'n', 0 }; +static id3_ucs4_t const genre_TRANCE[] = + { 'T', 'r', 'a', 'n', 'c', 'e', 0 }; +static id3_ucs4_t const genre_CLASSICAL[] = + { 'C', 'l', 'a', 's', 's', 'i', 'c', 'a', 'l', 0 }; +static id3_ucs4_t const genre_INSTRUMENTAL[] = + { 'I', 'n', 's', 't', 'r', 'u', 'm', 'e', 'n', 't', 'a', 'l', 0 }; +static id3_ucs4_t const genre_ACID[] = + { 'A', 'c', 'i', 'd', 0 }; +static id3_ucs4_t const genre_HOUSE[] = + { 'H', 'o', 'u', 's', 'e', 0 }; +static id3_ucs4_t const genre_GAME[] = + { 'G', 'a', 'm', 'e', 0 }; +static id3_ucs4_t const genre_SOUND_CLIP[] = + { 'S', 'o', 'u', 'n', 'd', ' ', 'C', 'l', 'i', 'p', 0 }; +static id3_ucs4_t const genre_GOSPEL[] = + { 'G', 'o', 's', 'p', 'e', 'l', 0 }; +static id3_ucs4_t const genre_NOISE[] = + { 'N', 'o', 'i', 's', 'e', 0 }; +static id3_ucs4_t const genre_ALTERNROCK[] = + { 'A', 'l', 't', 'e', 'r', 'n', 'R', 'o', 'c', 'k', 0 }; +static id3_ucs4_t const genre_BASS[] = + { 'B', 'a', 's', 's', 0 }; +static id3_ucs4_t const genre_SOUL[] = + { 'S', 'o', 'u', 'l', 0 }; +static id3_ucs4_t const genre_PUNK[] = + { 'P', 'u', 'n', 'k', 0 }; +static id3_ucs4_t const genre_SPACE[] = + { 'S', 'p', 'a', 'c', 'e', 0 }; +static id3_ucs4_t const genre_MEDITATIVE[] = + { 'M', 'e', 'd', 'i', 't', 'a', 't', 'i', 'v', 'e', 0 }; +static id3_ucs4_t const genre_INSTRUMENTAL_POP[] = + { 'I', 'n', 's', 't', 'r', 'u', 'm', 'e', 'n', 't', 'a', 'l', ' ', 'P', 'o', 'p', 0 }; +static id3_ucs4_t const genre_INSTRUMENTAL_ROCK[] = + { 'I', 'n', 's', 't', 'r', 'u', 'm', 'e', 'n', 't', 'a', 'l', ' ', 'R', 'o', 'c', 'k', 0 }; +static id3_ucs4_t const genre_ETHNIC[] = + { 'E', 't', 'h', 'n', 'i', 'c', 0 }; +static id3_ucs4_t const genre_GOTHIC[] = + { 'G', 'o', 't', 'h', 'i', 'c', 0 }; +static id3_ucs4_t const genre_DARKWAVE[] = + { 'D', 'a', 'r', 'k', 'w', 'a', 'v', 'e', 0 }; +static id3_ucs4_t const genre_TECHNO_INDUSTRIAL[] = + { 'T', 'e', 'c', 'h', 'n', 'o', '-', 'I', 'n', 'd', 'u', 's', 't', 'r', 'i', 'a', 'l', 0 }; +static id3_ucs4_t const genre_ELECTRONIC[] = + { 'E', 'l', 'e', 'c', 't', 'r', 'o', 'n', 'i', 'c', 0 }; +static id3_ucs4_t const genre_POP_FOLK[] = + { 'P', 'o', 'p', '-', 'F', 'o', 'l', 'k', 0 }; +static id3_ucs4_t const genre_EURODANCE[] = + { 'E', 'u', 'r', 'o', 'd', 'a', 'n', 'c', 'e', 0 }; +static id3_ucs4_t const genre_DREAM[] = + { 'D', 'r', 'e', 'a', 'm', 0 }; +static id3_ucs4_t const genre_SOUTHERN_ROCK[] = + { 'S', 'o', 'u', 't', 'h', 'e', 'r', 'n', ' ', 'R', 'o', 'c', 'k', 0 }; +static id3_ucs4_t const genre_COMEDY[] = + { 'C', 'o', 'm', 'e', 'd', 'y', 0 }; +static id3_ucs4_t const genre_CULT[] = + { 'C', 'u', 'l', 't', 0 }; +static id3_ucs4_t const genre_GANGSTA[] = + { 'G', 'a', 'n', 'g', 's', 't', 'a', 0 }; +static id3_ucs4_t const genre_TOP_40[] = + { 'T', 'o', 'p', ' ', '4', '0', 0 }; +static id3_ucs4_t const genre_CHRISTIAN_RAP[] = + { 'C', 'h', 'r', 'i', 's', 't', 'i', 'a', 'n', ' ', 'R', 'a', 'p', 0 }; +static id3_ucs4_t const genre_POP_FUNK[] = + { 'P', 'o', 'p', '/', 'F', 'u', 'n', 'k', 0 }; +static id3_ucs4_t const genre_JUNGLE[] = + { 'J', 'u', 'n', 'g', 'l', 'e', 0 }; +static id3_ucs4_t const genre_NATIVE_AMERICAN[] = + { 'N', 'a', 't', 'i', 'v', 'e', ' ', 'A', 'm', 'e', 'r', 'i', 'c', 'a', 'n', 0 }; +static id3_ucs4_t const genre_CABARET[] = + { 'C', 'a', 'b', 'a', 'r', 'e', 't', 0 }; +static id3_ucs4_t const genre_NEW_WAVE[] = + { 'N', 'e', 'w', ' ', 'W', 'a', 'v', 'e', 0 }; +static id3_ucs4_t const genre_PSYCHEDELIC[] = + { 'P', 's', 'y', 'c', 'h', 'e', 'd', 'e', 'l', 'i', 'c', 0 }; +static id3_ucs4_t const genre_RAVE[] = + { 'R', 'a', 'v', 'e', 0 }; +static id3_ucs4_t const genre_SHOWTUNES[] = + { 'S', 'h', 'o', 'w', 't', 'u', 'n', 'e', 's', 0 }; +static id3_ucs4_t const genre_TRAILER[] = + { 'T', 'r', 'a', 'i', 'l', 'e', 'r', 0 }; +static id3_ucs4_t const genre_LO_FI[] = + { 'L', 'o', '-', 'F', 'i', 0 }; +static id3_ucs4_t const genre_TRIBAL[] = + { 'T', 'r', 'i', 'b', 'a', 'l', 0 }; +static id3_ucs4_t const genre_ACID_PUNK[] = + { 'A', 'c', 'i', 'd', ' ', 'P', 'u', 'n', 'k', 0 }; +static id3_ucs4_t const genre_ACID_JAZZ[] = + { 'A', 'c', 'i', 'd', ' ', 'J', 'a', 'z', 'z', 0 }; +static id3_ucs4_t const genre_POLKA[] = + { 'P', 'o', 'l', 'k', 'a', 0 }; +static id3_ucs4_t const genre_RETRO[] = + { 'R', 'e', 't', 'r', 'o', 0 }; +static id3_ucs4_t const genre_MUSICAL[] = + { 'M', 'u', 's', 'i', 'c', 'a', 'l', 0 }; +static id3_ucs4_t const genre_ROCK___ROLL[] = + { 'R', 'o', 'c', 'k', ' ', '&', ' ', 'R', 'o', 'l', 'l', 0 }; +static id3_ucs4_t const genre_HARD_ROCK[] = + { 'H', 'a', 'r', 'd', ' ', 'R', 'o', 'c', 'k', 0 }; + +/* Winamp extensions (80-147) */ + +static id3_ucs4_t const genre_FOLK[] = + { 'F', 'o', 'l', 'k', 0 }; +static id3_ucs4_t const genre_FOLK_ROCK[] = + { 'F', 'o', 'l', 'k', '/', 'R', 'o', 'c', 'k', 0 }; +static id3_ucs4_t const genre_NATIONAL_FOLK[] = + { 'N', 'a', 't', 'i', 'o', 'n', 'a', 'l', ' ', 'F', 'o', 'l', 'k', 0 }; +static id3_ucs4_t const genre_SWING[] = + { 'S', 'w', 'i', 'n', 'g', 0 }; +static id3_ucs4_t const genre_FAST_FUSION[] = + { 'F', 'a', 's', 't', '-', 'F', 'u', 's', 'i', 'o', 'n', 0 }; +static id3_ucs4_t const genre_BEBOB[] = + { 'B', 'e', 'b', 'o', 'b', 0 }; +static id3_ucs4_t const genre_LATIN[] = + { 'L', 'a', 't', 'i', 'n', 0 }; +static id3_ucs4_t const genre_REVIVAL[] = + { 'R', 'e', 'v', 'i', 'v', 'a', 'l', 0 }; +static id3_ucs4_t const genre_CELTIC[] = + { 'C', 'e', 'l', 't', 'i', 'c', 0 }; +static id3_ucs4_t const genre_BLUEGRASS[] = + { 'B', 'l', 'u', 'e', 'g', 'r', 'a', 's', 's', 0 }; +static id3_ucs4_t const genre_AVANTGARDE[] = + { 'A', 'v', 'a', 'n', 't', 'g', 'a', 'r', 'd', 'e', 0 }; +static id3_ucs4_t const genre_GOTHIC_ROCK[] = + { 'G', 'o', 't', 'h', 'i', 'c', ' ', 'R', 'o', 'c', 'k', 0 }; +static id3_ucs4_t const genre_PROGRESSIVE_ROCK[] = + { 'P', 'r', 'o', 'g', 'r', 'e', 's', 's', 'i', 'v', 'e', ' ', 'R', 'o', 'c', 'k', 0 }; +static id3_ucs4_t const genre_PSYCHEDELIC_ROCK[] = + { 'P', 's', 'y', 'c', 'h', 'e', 'd', 'e', 'l', 'i', 'c', ' ', 'R', 'o', 'c', 'k', 0 }; +static id3_ucs4_t const genre_SYMPHONIC_ROCK[] = + { 'S', 'y', 'm', 'p', 'h', 'o', 'n', 'i', 'c', ' ', 'R', 'o', 'c', 'k', 0 }; +static id3_ucs4_t const genre_SLOW_ROCK[] = + { 'S', 'l', 'o', 'w', ' ', 'R', 'o', 'c', 'k', 0 }; +static id3_ucs4_t const genre_BIG_BAND[] = + { 'B', 'i', 'g', ' ', 'B', 'a', 'n', 'd', 0 }; +static id3_ucs4_t const genre_CHORUS[] = + { 'C', 'h', 'o', 'r', 'u', 's', 0 }; +static id3_ucs4_t const genre_EASY_LISTENING[] = + { 'E', 'a', 's', 'y', ' ', 'L', 'i', 's', 't', 'e', 'n', 'i', 'n', 'g', 0 }; +static id3_ucs4_t const genre_ACOUSTIC[] = + { 'A', 'c', 'o', 'u', 's', 't', 'i', 'c', 0 }; +static id3_ucs4_t const genre_HUMOUR[] = + { 'H', 'u', 'm', 'o', 'u', 'r', 0 }; +static id3_ucs4_t const genre_SPEECH[] = + { 'S', 'p', 'e', 'e', 'c', 'h', 0 }; +static id3_ucs4_t const genre_CHANSON[] = + { 'C', 'h', 'a', 'n', 's', 'o', 'n', 0 }; +static id3_ucs4_t const genre_OPERA[] = + { 'O', 'p', 'e', 'r', 'a', 0 }; +static id3_ucs4_t const genre_CHAMBER_MUSIC[] = + { 'C', 'h', 'a', 'm', 'b', 'e', 'r', ' ', 'M', 'u', 's', 'i', 'c', 0 }; +static id3_ucs4_t const genre_SONATA[] = + { 'S', 'o', 'n', 'a', 't', 'a', 0 }; +static id3_ucs4_t const genre_SYMPHONY[] = + { 'S', 'y', 'm', 'p', 'h', 'o', 'n', 'y', 0 }; +static id3_ucs4_t const genre_BOOTY_BASS[] = + { 'B', 'o', 'o', 't', 'y', ' ', 'B', 'a', 's', 's', 0 }; +static id3_ucs4_t const genre_PRIMUS[] = + { 'P', 'r', 'i', 'm', 'u', 's', 0 }; +static id3_ucs4_t const genre_PORN_GROOVE[] = + { 'P', 'o', 'r', 'n', ' ', 'G', 'r', 'o', 'o', 'v', 'e', 0 }; +static id3_ucs4_t const genre_SATIRE[] = + { 'S', 'a', 't', 'i', 'r', 'e', 0 }; +static id3_ucs4_t const genre_SLOW_JAM[] = + { 'S', 'l', 'o', 'w', ' ', 'J', 'a', 'm', 0 }; +static id3_ucs4_t const genre_CLUB[] = + { 'C', 'l', 'u', 'b', 0 }; +static id3_ucs4_t const genre_TANGO[] = + { 'T', 'a', 'n', 'g', 'o', 0 }; +static id3_ucs4_t const genre_SAMBA[] = + { 'S', 'a', 'm', 'b', 'a', 0 }; +static id3_ucs4_t const genre_FOLKLORE[] = + { 'F', 'o', 'l', 'k', 'l', 'o', 'r', 'e', 0 }; +static id3_ucs4_t const genre_BALLAD[] = + { 'B', 'a', 'l', 'l', 'a', 'd', 0 }; +static id3_ucs4_t const genre_POWER_BALLAD[] = + { 'P', 'o', 'w', 'e', 'r', ' ', 'B', 'a', 'l', 'l', 'a', 'd', 0 }; +static id3_ucs4_t const genre_RHYTHMIC_SOUL[] = + { 'R', 'h', 'y', 't', 'h', 'm', 'i', 'c', ' ', 'S', 'o', 'u', 'l', 0 }; +static id3_ucs4_t const genre_FREESTYLE[] = + { 'F', 'r', 'e', 'e', 's', 't', 'y', 'l', 'e', 0 }; +static id3_ucs4_t const genre_DUET[] = + { 'D', 'u', 'e', 't', 0 }; +static id3_ucs4_t const genre_PUNK_ROCK[] = + { 'P', 'u', 'n', 'k', ' ', 'R', 'o', 'c', 'k', 0 }; +static id3_ucs4_t const genre_DRUM_SOLO[] = + { 'D', 'r', 'u', 'm', ' ', 'S', 'o', 'l', 'o', 0 }; +static id3_ucs4_t const genre_A_CAPPELLA[] = + { 'A', ' ', 'C', 'a', 'p', 'p', 'e', 'l', 'l', 'a', 0 }; +static id3_ucs4_t const genre_EURO_HOUSE[] = + { 'E', 'u', 'r', 'o', '-', 'H', 'o', 'u', 's', 'e', 0 }; +static id3_ucs4_t const genre_DANCE_HALL[] = + { 'D', 'a', 'n', 'c', 'e', ' ', 'H', 'a', 'l', 'l', 0 }; +static id3_ucs4_t const genre_GOA[] = + { 'G', 'o', 'a', 0 }; +static id3_ucs4_t const genre_DRUM___BASS[] = + { 'D', 'r', 'u', 'm', ' ', '&', ' ', 'B', 'a', 's', 's', 0 }; +static id3_ucs4_t const genre_CLUB_HOUSE[] = + { 'C', 'l', 'u', 'b', '-', 'H', 'o', 'u', 's', 'e', 0 }; +static id3_ucs4_t const genre_HARDCORE[] = + { 'H', 'a', 'r', 'd', 'c', 'o', 'r', 'e', 0 }; +static id3_ucs4_t const genre_TERROR[] = + { 'T', 'e', 'r', 'r', 'o', 'r', 0 }; +static id3_ucs4_t const genre_INDIE[] = + { 'I', 'n', 'd', 'i', 'e', 0 }; +static id3_ucs4_t const genre_BRITPOP[] = + { 'B', 'r', 'i', 't', 'P', 'o', 'p', 0 }; +static id3_ucs4_t const genre_NEGERPUNK[] = + { 'N', 'e', 'g', 'e', 'r', 'p', 'u', 'n', 'k', 0 }; +static id3_ucs4_t const genre_POLSK_PUNK[] = + { 'P', 'o', 'l', 's', 'k', ' ', 'P', 'u', 'n', 'k', 0 }; +static id3_ucs4_t const genre_BEAT[] = + { 'B', 'e', 'a', 't', 0 }; +static id3_ucs4_t const genre_CHRISTIAN_GANGSTA_RAP[] = + { 'C', 'h', 'r', 'i', 's', 't', 'i', 'a', 'n', ' ', 'G', 'a', 'n', 'g', 's', 't', 'a', ' ', 'R', 'a', 'p', 0 }; +static id3_ucs4_t const genre_HEAVY_METAL[] = + { 'H', 'e', 'a', 'v', 'y', ' ', 'M', 'e', 't', 'a', 'l', 0 }; +static id3_ucs4_t const genre_BLACK_METAL[] = + { 'B', 'l', 'a', 'c', 'k', ' ', 'M', 'e', 't', 'a', 'l', 0 }; +static id3_ucs4_t const genre_CROSSOVER[] = + { 'C', 'r', 'o', 's', 's', 'o', 'v', 'e', 'r', 0 }; +static id3_ucs4_t const genre_CONTEMPORARY_CHRISTIAN[] = + { 'C', 'o', 'n', 't', 'e', 'm', 'p', 'o', 'r', 'a', 'r', 'y', ' ', 'C', 'h', 'r', 'i', 's', 't', 'i', 'a', 'n', 0 }; +static id3_ucs4_t const genre_CHRISTIAN_ROCK[] = + { 'C', 'h', 'r', 'i', 's', 't', 'i', 'a', 'n', ' ', 'R', 'o', 'c', 'k', 0 }; +static id3_ucs4_t const genre_MERENGUE[] = + { 'M', 'e', 'r', 'e', 'n', 'g', 'u', 'e', 0 }; +static id3_ucs4_t const genre_SALSA[] = + { 'S', 'a', 'l', 's', 'a', 0 }; +static id3_ucs4_t const genre_THRASH_METAL[] = + { 'T', 'h', 'r', 'a', 's', 'h', ' ', 'M', 'e', 't', 'a', 'l', 0 }; +static id3_ucs4_t const genre_ANIME[] = + { 'A', 'n', 'i', 'm', 'e', 0 }; +static id3_ucs4_t const genre_JPOP[] = + { 'J', 'P', 'o', 'p', 0 }; +static id3_ucs4_t const genre_SYNTHPOP[] = + { 'S', 'y', 'n', 't', 'h', 'p', 'o', 'p', 0 }; + +static id3_ucs4_t const *const genre_table[] = { + genre_BLUES, + genre_CLASSIC_ROCK, + genre_COUNTRY, + genre_DANCE, + genre_DISCO, + genre_FUNK, + genre_GRUNGE, + genre_HIP_HOP, + genre_JAZZ, + genre_METAL, + genre_NEW_AGE, + genre_OLDIES, + genre_OTHER, + genre_POP, + genre_R_B, + genre_RAP, + genre_REGGAE, + genre_ROCK, + genre_TECHNO, + genre_INDUSTRIAL, + genre_ALTERNATIVE, + genre_SKA, + genre_DEATH_METAL, + genre_PRANKS, + genre_SOUNDTRACK, + genre_EURO_TECHNO, + genre_AMBIENT, + genre_TRIP_HOP, + genre_VOCAL, + genre_JAZZ_FUNK, + genre_FUSION, + genre_TRANCE, + genre_CLASSICAL, + genre_INSTRUMENTAL, + genre_ACID, + genre_HOUSE, + genre_GAME, + genre_SOUND_CLIP, + genre_GOSPEL, + genre_NOISE, + genre_ALTERNROCK, + genre_BASS, + genre_SOUL, + genre_PUNK, + genre_SPACE, + genre_MEDITATIVE, + genre_INSTRUMENTAL_POP, + genre_INSTRUMENTAL_ROCK, + genre_ETHNIC, + genre_GOTHIC, + genre_DARKWAVE, + genre_TECHNO_INDUSTRIAL, + genre_ELECTRONIC, + genre_POP_FOLK, + genre_EURODANCE, + genre_DREAM, + genre_SOUTHERN_ROCK, + genre_COMEDY, + genre_CULT, + genre_GANGSTA, + genre_TOP_40, + genre_CHRISTIAN_RAP, + genre_POP_FUNK, + genre_JUNGLE, + genre_NATIVE_AMERICAN, + genre_CABARET, + genre_NEW_WAVE, + genre_PSYCHEDELIC, + genre_RAVE, + genre_SHOWTUNES, + genre_TRAILER, + genre_LO_FI, + genre_TRIBAL, + genre_ACID_PUNK, + genre_ACID_JAZZ, + genre_POLKA, + genre_RETRO, + genre_MUSICAL, + genre_ROCK___ROLL, + genre_HARD_ROCK, + genre_FOLK, + genre_FOLK_ROCK, + genre_NATIONAL_FOLK, + genre_SWING, + genre_FAST_FUSION, + genre_BEBOB, + genre_LATIN, + genre_REVIVAL, + genre_CELTIC, + genre_BLUEGRASS, + genre_AVANTGARDE, + genre_GOTHIC_ROCK, + genre_PROGRESSIVE_ROCK, + genre_PSYCHEDELIC_ROCK, + genre_SYMPHONIC_ROCK, + genre_SLOW_ROCK, + genre_BIG_BAND, + genre_CHORUS, + genre_EASY_LISTENING, + genre_ACOUSTIC, + genre_HUMOUR, + genre_SPEECH, + genre_CHANSON, + genre_OPERA, + genre_CHAMBER_MUSIC, + genre_SONATA, + genre_SYMPHONY, + genre_BOOTY_BASS, + genre_PRIMUS, + genre_PORN_GROOVE, + genre_SATIRE, + genre_SLOW_JAM, + genre_CLUB, + genre_TANGO, + genre_SAMBA, + genre_FOLKLORE, + genre_BALLAD, + genre_POWER_BALLAD, + genre_RHYTHMIC_SOUL, + genre_FREESTYLE, + genre_DUET, + genre_PUNK_ROCK, + genre_DRUM_SOLO, + genre_A_CAPPELLA, + genre_EURO_HOUSE, + genre_DANCE_HALL, + genre_GOA, + genre_DRUM___BASS, + genre_CLUB_HOUSE, + genre_HARDCORE, + genre_TERROR, + genre_INDIE, + genre_BRITPOP, + genre_NEGERPUNK, + genre_POLSK_PUNK, + genre_BEAT, + genre_CHRISTIAN_GANGSTA_RAP, + genre_HEAVY_METAL, + genre_BLACK_METAL, + genre_CROSSOVER, + genre_CONTEMPORARY_CHRISTIAN, + genre_CHRISTIAN_ROCK, + genre_MERENGUE, + genre_SALSA, + genre_THRASH_METAL, + genre_ANIME, + genre_JPOP, + genre_SYNTHPOP +}; diff --git a/libid3tag/genre.h b/libid3tag/genre.h new file mode 100644 index 0000000..56d538a --- /dev/null +++ b/libid3tag/genre.h @@ -0,0 +1,27 @@ +/* + * libid3tag - ID3 tag manipulation library + * Copyright (C) 2000-2004 Underbit Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: genre.h,v 1.6 2004/01/23 09:41:32 rob Exp $ + */ + +# ifndef LIBID3TAG_GENRE_H +# define LIBID3TAG_GENRE_H + +# define ID3_GENRE_OTHER 12 + +# endif diff --git a/libid3tag/global.h b/libid3tag/global.h new file mode 100644 index 0000000..377a5e6 --- /dev/null +++ b/libid3tag/global.h @@ -0,0 +1,53 @@ +/* + * libid3tag - ID3 tag manipulation library + * Copyright (C) 2000-2004 Underbit Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: global.h,v 1.9 2004/01/23 09:41:32 rob Exp $ + */ + +# ifndef LIBID3TAG_GLOBAL_H +# define LIBID3TAG_GLOBAL_H + +/* conditional debugging */ + +# if defined(DEBUG) && defined(NDEBUG) +# error "cannot define both DEBUG and NDEBUG" +# endif + +# if defined(DEBUG) +# include +# include "debug.h" +# define malloc(sz) id3_debug_malloc(sz, __FILE__, __LINE__) +# define calloc(n, sz) id3_debug_calloc(n, sz, __FILE__, __LINE__) +# define realloc(ptr, sz) id3_debug_realloc(ptr, sz, __FILE__, __LINE__) +# define free(ptr) id3_debug_free(ptr, __FILE__, __LINE__) +# define release(ptr) id3_debug_release(ptr, __FILE__, __LINE__) +# else +# define release(ptr) (ptr) +# endif + +/* conditional features */ + +# if !defined(HAVE_ASSERT_H) +# if defined(NDEBUG) +# define assert(x) /* nothing */ +# else +# define assert(x) do { if (!(x)) abort(); } while (0) +# endif +# endif + +# endif diff --git a/libid3tag/id3tag.h b/libid3tag/id3tag.h new file mode 100644 index 0000000..4f4c681 --- /dev/null +++ b/libid3tag/id3tag.h @@ -0,0 +1,364 @@ +/* + * libid3tag - ID3 tag manipulation library + * Copyright (C) 2000-2004 Underbit Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * If you would like to negotiate alternate licensing terms, you may do + * so by contacting: Underbit Technologies, Inc. + * + * $Id: id3tag.h,v 1.17 2004/01/23 23:22:46 rob Exp $ + */ + +# ifndef LIBID3TAG_ID3TAG_H +# define LIBID3TAG_ID3TAG_H + +# ifdef __cplusplus +extern "C" { +# endif + +# define ID3_TAG_VERSION 0x0400 +# define ID3_TAG_VERSION_MAJOR(x) (((x) >> 8) & 0xff) +# define ID3_TAG_VERSION_MINOR(x) (((x) >> 0) & 0xff) + +typedef unsigned char id3_byte_t; +typedef unsigned long id3_length_t; + +typedef unsigned long id3_ucs4_t; + +typedef unsigned char id3_latin1_t; +typedef unsigned short id3_utf16_t; +typedef signed char id3_utf8_t; + +struct id3_tag { + unsigned int refcount; + unsigned int version; + int flags; + int extendedflags; + int restrictions; + int options; + unsigned int nframes; + struct id3_frame **frames; + id3_length_t paddedsize; +}; + +# define ID3_TAG_QUERYSIZE 10 + +/* ID3v1 field frames */ + +# define ID3_FRAME_TITLE "TIT2" +# define ID3_FRAME_ARTIST "TPE1" +# define ID3_FRAME_ALBUM "TALB" +# define ID3_FRAME_TRACK "TRCK" +# define ID3_FRAME_YEAR "TDRC" +# define ID3_FRAME_GENRE "TCON" +# define ID3_FRAME_COMMENT "COMM" + +/* special frames */ + +# define ID3_FRAME_OBSOLETE "ZOBS" /* with apologies to the French */ + +/* tag flags */ + +enum { + ID3_TAG_FLAG_UNSYNCHRONISATION = 0x80, + ID3_TAG_FLAG_EXTENDEDHEADER = 0x40, + ID3_TAG_FLAG_EXPERIMENTALINDICATOR = 0x20, + ID3_TAG_FLAG_FOOTERPRESENT = 0x10, + + ID3_TAG_FLAG_KNOWNFLAGS = 0xf0 +}; + +/* tag extended flags */ + +enum { + ID3_TAG_EXTENDEDFLAG_TAGISANUPDATE = 0x40, + ID3_TAG_EXTENDEDFLAG_CRCDATAPRESENT = 0x20, + ID3_TAG_EXTENDEDFLAG_TAGRESTRICTIONS = 0x10, + + ID3_TAG_EXTENDEDFLAG_KNOWNFLAGS = 0x70 +}; + +/* tag restrictions */ + +enum { + ID3_TAG_RESTRICTION_TAGSIZE_MASK = 0xc0, + ID3_TAG_RESTRICTION_TAGSIZE_128_FRAMES_1_MB = 0x00, + ID3_TAG_RESTRICTION_TAGSIZE_64_FRAMES_128_KB = 0x40, + ID3_TAG_RESTRICTION_TAGSIZE_32_FRAMES_40_KB = 0x80, + ID3_TAG_RESTRICTION_TAGSIZE_32_FRAMES_4_KB = 0xc0 +}; + +enum { + ID3_TAG_RESTRICTION_TEXTENCODING_MASK = 0x20, + ID3_TAG_RESTRICTION_TEXTENCODING_NONE = 0x00, + ID3_TAG_RESTRICTION_TEXTENCODING_LATIN1_UTF8 = 0x20 +}; + +enum { + ID3_TAG_RESTRICTION_TEXTSIZE_MASK = 0x18, + ID3_TAG_RESTRICTION_TEXTSIZE_NONE = 0x00, + ID3_TAG_RESTRICTION_TEXTSIZE_1024_CHARS = 0x08, + ID3_TAG_RESTRICTION_TEXTSIZE_128_CHARS = 0x10, + ID3_TAG_RESTRICTION_TEXTSIZE_30_CHARS = 0x18 +}; + +enum { + ID3_TAG_RESTRICTION_IMAGEENCODING_MASK = 0x04, + ID3_TAG_RESTRICTION_IMAGEENCODING_NONE = 0x00, + ID3_TAG_RESTRICTION_IMAGEENCODING_PNG_JPEG = 0x04 +}; + +enum { + ID3_TAG_RESTRICTION_IMAGESIZE_MASK = 0x03, + ID3_TAG_RESTRICTION_IMAGESIZE_NONE = 0x00, + ID3_TAG_RESTRICTION_IMAGESIZE_256_256 = 0x01, + ID3_TAG_RESTRICTION_IMAGESIZE_64_64 = 0x02, + ID3_TAG_RESTRICTION_IMAGESIZE_64_64_EXACT = 0x03 +}; + +/* library options */ + +enum { + ID3_TAG_OPTION_UNSYNCHRONISATION = 0x0001, /* use unsynchronisation */ + ID3_TAG_OPTION_COMPRESSION = 0x0002, /* use compression */ + ID3_TAG_OPTION_CRC = 0x0004, /* use CRC */ + + ID3_TAG_OPTION_APPENDEDTAG = 0x0010, /* tag will be appended */ + ID3_TAG_OPTION_FILEALTERED = 0x0020, /* audio data was altered */ + + ID3_TAG_OPTION_ID3V1 = 0x0100 /* render ID3v1/ID3v1.1 tag */ +}; + +struct id3_frame { + char id[5]; + char const *description; + unsigned int refcount; + int flags; + int group_id; + int encryption_method; + id3_byte_t *encoded; + id3_length_t encoded_length; + id3_length_t decoded_length; + unsigned int nfields; + union id3_field *fields; +}; + +enum { + /* frame status flags */ + ID3_FRAME_FLAG_TAGALTERPRESERVATION = 0x4000, + ID3_FRAME_FLAG_FILEALTERPRESERVATION = 0x2000, + ID3_FRAME_FLAG_READONLY = 0x1000, + + ID3_FRAME_FLAG_STATUSFLAGS = 0xff00, + + /* frame format flags */ + ID3_FRAME_FLAG_GROUPINGIDENTITY = 0x0040, + ID3_FRAME_FLAG_COMPRESSION = 0x0008, + ID3_FRAME_FLAG_ENCRYPTION = 0x0004, + ID3_FRAME_FLAG_UNSYNCHRONISATION = 0x0002, + ID3_FRAME_FLAG_DATALENGTHINDICATOR = 0x0001, + + ID3_FRAME_FLAG_FORMATFLAGS = 0x00ff, + + ID3_FRAME_FLAG_KNOWNFLAGS = 0x704f +}; + +enum id3_field_type { + ID3_FIELD_TYPE_TEXTENCODING, + ID3_FIELD_TYPE_LATIN1, + ID3_FIELD_TYPE_LATIN1FULL, + ID3_FIELD_TYPE_LATIN1LIST, + ID3_FIELD_TYPE_STRING, + ID3_FIELD_TYPE_STRINGFULL, + ID3_FIELD_TYPE_STRINGLIST, + ID3_FIELD_TYPE_LANGUAGE, + ID3_FIELD_TYPE_FRAMEID, + ID3_FIELD_TYPE_DATE, + ID3_FIELD_TYPE_INT8, + ID3_FIELD_TYPE_INT16, + ID3_FIELD_TYPE_INT24, + ID3_FIELD_TYPE_INT32, + ID3_FIELD_TYPE_INT32PLUS, + ID3_FIELD_TYPE_BINARYDATA +}; + +enum id3_field_textencoding { + ID3_FIELD_TEXTENCODING_ISO_8859_1 = 0x00, + ID3_FIELD_TEXTENCODING_UTF_16 = 0x01, + ID3_FIELD_TEXTENCODING_UTF_16BE = 0x02, + ID3_FIELD_TEXTENCODING_UTF_8 = 0x03 +}; + +union id3_field { + enum id3_field_type type; + struct { + enum id3_field_type type; + signed long value; + } number; + struct { + enum id3_field_type type; + id3_latin1_t *ptr; + } latin1; + struct { + enum id3_field_type type; + unsigned int nstrings; + id3_latin1_t **strings; + } latin1list; + struct { + enum id3_field_type type; + id3_ucs4_t *ptr; + } string; + struct { + enum id3_field_type type; + unsigned int nstrings; + id3_ucs4_t **strings; + } stringlist; + struct { + enum id3_field_type type; + char value[9]; + } immediate; + struct { + enum id3_field_type type; + id3_byte_t *data; + id3_length_t length; + } binary; +}; + +/* file interface */ + +enum id3_file_mode { + ID3_FILE_MODE_READONLY = 0, + ID3_FILE_MODE_READWRITE +}; + +struct id3_file *id3_file_open(char const *, enum id3_file_mode); +struct id3_file *id3_file_fdopen(int, enum id3_file_mode); +int id3_file_close(struct id3_file *); + +struct id3_tag *id3_file_tag(struct id3_file const *); + +int id3_file_update(struct id3_file *); + +/* tag interface */ + +struct id3_tag *id3_tag_new(void); +void id3_tag_delete(struct id3_tag *); + +unsigned int id3_tag_version(struct id3_tag const *); + +int id3_tag_options(struct id3_tag *, int, int); +void id3_tag_setlength(struct id3_tag *, id3_length_t); + +void id3_tag_clearframes(struct id3_tag *); + +int id3_tag_attachframe(struct id3_tag *, struct id3_frame *); +int id3_tag_detachframe(struct id3_tag *, struct id3_frame *); + +struct id3_frame *id3_tag_findframe(struct id3_tag const *, + char const *, unsigned int); + +signed long id3_tag_query(id3_byte_t const *, id3_length_t); + +struct id3_tag *id3_tag_parse(id3_byte_t const *, id3_length_t); +id3_length_t id3_tag_render(struct id3_tag const *, id3_byte_t *); + +/* frame interface */ + +struct id3_frame *id3_frame_new(char const *); +void id3_frame_delete(struct id3_frame *); + +union id3_field *id3_frame_field(struct id3_frame const *, unsigned int); + +/* field interface */ + +enum id3_field_type id3_field_type(union id3_field const *); + +int id3_field_setint(union id3_field *, signed long); +int id3_field_settextencoding(union id3_field *, enum id3_field_textencoding); +int id3_field_setstrings(union id3_field *, unsigned int, id3_ucs4_t **); +int id3_field_addstring(union id3_field *, id3_ucs4_t const *); +int id3_field_setlanguage(union id3_field *, char const *); +int id3_field_setlatin1(union id3_field *, id3_latin1_t const *); +int id3_field_setfulllatin1(union id3_field *, id3_latin1_t const *); +int id3_field_setstring(union id3_field *, id3_ucs4_t const *); +int id3_field_setfullstring(union id3_field *, id3_ucs4_t const *); +int id3_field_setframeid(union id3_field *, char const *); +int id3_field_setbinarydata(union id3_field *, + id3_byte_t const *, id3_length_t); + +signed long id3_field_getint(union id3_field const *); +enum id3_field_textencoding id3_field_gettextencoding(union id3_field const *); +id3_latin1_t const *id3_field_getlatin1(union id3_field const *); +id3_latin1_t const *id3_field_getfulllatin1(union id3_field const *); +id3_ucs4_t const *id3_field_getstring(union id3_field const *); +id3_ucs4_t const *id3_field_getfullstring(union id3_field const *); +unsigned int id3_field_getnstrings(union id3_field const *); +id3_ucs4_t const *id3_field_getstrings(union id3_field const *, + unsigned int); +char const *id3_field_getframeid(union id3_field const *); +id3_byte_t const *id3_field_getbinarydata(union id3_field const *, + id3_length_t *); + +/* genre interface */ + +id3_ucs4_t const *id3_genre_index(unsigned int); +id3_ucs4_t const *id3_genre_name(id3_ucs4_t const *); +int id3_genre_number(id3_ucs4_t const *); + +/* ucs4 interface */ + +id3_latin1_t *id3_ucs4_latin1duplicate(id3_ucs4_t const *); +id3_utf16_t *id3_ucs4_utf16duplicate(id3_ucs4_t const *); +id3_utf8_t *id3_ucs4_utf8duplicate(id3_ucs4_t const *); + +void id3_ucs4_putnumber(id3_ucs4_t *, unsigned long); +unsigned long id3_ucs4_getnumber(id3_ucs4_t const *); + +/* latin1/utf16/utf8 interfaces */ + +id3_ucs4_t *id3_latin1_ucs4duplicate(id3_latin1_t const *); +id3_ucs4_t *id3_utf16_ucs4duplicate(id3_utf16_t const *); +id3_ucs4_t *id3_utf8_ucs4duplicate(id3_utf8_t const *); + +/* version interface */ + +# define ID3_VERSION_MAJOR 0 +# define ID3_VERSION_MINOR 15 +# define ID3_VERSION_PATCH 1 +# define ID3_VERSION_EXTRA " (beta)" + +# define ID3_VERSION_STRINGIZE(str) #str +# define ID3_VERSION_STRING(num) ID3_VERSION_STRINGIZE(num) + +# define ID3_VERSION ID3_VERSION_STRING(ID3_VERSION_MAJOR) "." \ + ID3_VERSION_STRING(ID3_VERSION_MINOR) "." \ + ID3_VERSION_STRING(ID3_VERSION_PATCH) \ + ID3_VERSION_EXTRA + +# define ID3_PUBLISHYEAR "2000-2004" +# define ID3_AUTHOR "Underbit Technologies, Inc." +# define ID3_EMAIL "info@underbit.com" + +extern char const id3_version[]; +extern char const id3_copyright[]; +extern char const id3_author[]; +extern char const id3_build[]; + +# ifdef __cplusplus +} +# endif + +# endif diff --git a/libid3tag/latin1.c b/libid3tag/latin1.c new file mode 100644 index 0000000..67b8199 --- /dev/null +++ b/libid3tag/latin1.c @@ -0,0 +1,217 @@ +/* + * libid3tag - ID3 tag manipulation library + * Copyright (C) 2000-2004 Underbit Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: latin1.c,v 1.10 2004/01/23 09:41:32 rob Exp $ + */ + +# ifdef HAVE_CONFIG_H +# include "config.h" +# endif + +# include "global.h" + +# include + +# include "id3tag.h" +# include "latin1.h" +# include "ucs4.h" + +/* + * NAME: latin1->length() + * DESCRIPTION: return the number of ucs4 chars represented by a latin1 string + */ +id3_length_t id3_latin1_length(id3_latin1_t const *latin1) +{ + id3_latin1_t const *ptr = latin1; + + while (*ptr) + ++ptr; + + return ptr - latin1; +} + +/* + * NAME: latin1->size() + * DESCRIPTION: return the encoding size of a latin1 string + */ +id3_length_t id3_latin1_size(id3_latin1_t const *latin1) +{ + return id3_latin1_length(latin1) + 1; +} + +/* + * NAME: latin1->copy() + * DESCRIPTION: copy a latin1 string + */ +void id3_latin1_copy(id3_latin1_t *dest, id3_latin1_t const *src) +{ + while ((*dest++ = *src++)) + ; +} + +/* + * NAME: latin1->duplicate() + * DESCRIPTION: duplicate a latin1 string + */ +id3_latin1_t *id3_latin1_duplicate(id3_latin1_t const *src) +{ + id3_latin1_t *latin1; + + latin1 = malloc(id3_latin1_size(src) * sizeof(*latin1)); + if (latin1) + id3_latin1_copy(latin1, src); + + return latin1; +} + +/* + * NAME: latin1->ucs4duplicate() + * DESCRIPTION: duplicate and decode a latin1 string into ucs4 + */ +id3_ucs4_t *id3_latin1_ucs4duplicate(id3_latin1_t const *latin1) +{ + id3_ucs4_t *ucs4; + + ucs4 = malloc((id3_latin1_length(latin1) + 1) * sizeof(*ucs4)); + if (ucs4) + id3_latin1_decode(latin1, ucs4); + + return release(ucs4); +} + +/* + * NAME: latin1->decodechar() + * DESCRIPTION: decode a (single) latin1 char into a single ucs4 char + */ +id3_length_t id3_latin1_decodechar(id3_latin1_t const *latin1, + id3_ucs4_t *ucs4) +{ + *ucs4 = *latin1; + + return 1; +} + +/* + * NAME: latin1->encodechar() + * DESCRIPTION: encode a single ucs4 char into a (single) latin1 char + */ +id3_length_t id3_latin1_encodechar(id3_latin1_t *latin1, id3_ucs4_t ucs4) +{ + *latin1 = ucs4; + if (ucs4 > 0x000000ffL) + *latin1 = ID3_UCS4_REPLACEMENTCHAR; + + return 1; +} + +/* + * NAME: latin1->decode() + * DESCRIPTION: decode a complete latin1 string into a ucs4 string + */ +void id3_latin1_decode(id3_latin1_t const *latin1, id3_ucs4_t *ucs4) +{ + do + latin1 += id3_latin1_decodechar(latin1, ucs4); + while (*ucs4++); +} + +/* + * NAME: latin1->encode() + * DESCRIPTION: encode a complete ucs4 string into a latin1 string + */ +void id3_latin1_encode(id3_latin1_t *latin1, id3_ucs4_t const *ucs4) +{ + do + latin1 += id3_latin1_encodechar(latin1, *ucs4); + while (*ucs4++); +} + +/* + * NAME: latin1->put() + * DESCRIPTION: serialize a single latin1 character + */ +id3_length_t id3_latin1_put(id3_byte_t **ptr, id3_latin1_t latin1) +{ + if (ptr) + *(*ptr)++ = latin1; + + return 1; +} + +/* + * NAME: latin1->get() + * DESCRIPTION: deserialize a single latin1 character + */ +id3_latin1_t id3_latin1_get(id3_byte_t const **ptr) +{ + return *(*ptr)++; +} + +/* + * NAME: latin1->serialize() + * DESCRIPTION: serialize a ucs4 string using latin1 encoding + */ +id3_length_t id3_latin1_serialize(id3_byte_t **ptr, id3_ucs4_t const *ucs4, + int terminate) +{ + id3_length_t size = 0; + id3_latin1_t latin1[1], *out; + + while (*ucs4) { + switch (id3_latin1_encodechar(out = latin1, *ucs4++)) { + case 1: size += id3_latin1_put(ptr, *out++); + case 0: break; + } + } + + if (terminate) + size += id3_latin1_put(ptr, 0); + + return size; +} + +/* + * NAME: latin1->deserialize() + * DESCRIPTION: deserialize a ucs4 string using latin1 encoding + */ +id3_ucs4_t *id3_latin1_deserialize(id3_byte_t const **ptr, id3_length_t length) +{ + id3_byte_t const *end; + id3_latin1_t *latin1ptr, *latin1; + id3_ucs4_t *ucs4; + + end = *ptr + length; + + latin1 = malloc((length + 1) * sizeof(*latin1)); + if (latin1 == 0) + return 0; + + latin1ptr = latin1; + while (end - *ptr > 0 && (*latin1ptr = id3_latin1_get(ptr))) + ++latin1ptr; + + *latin1ptr = 0; + + ucs4 = malloc((id3_latin1_length(latin1) + 1) * sizeof(*ucs4)); + if (ucs4) + id3_latin1_decode(latin1, ucs4); + + free(latin1); + + return ucs4; +} diff --git a/libid3tag/latin1.h b/libid3tag/latin1.h new file mode 100644 index 0000000..3604bbf --- /dev/null +++ b/libid3tag/latin1.h @@ -0,0 +1,45 @@ +/* + * libid3tag - ID3 tag manipulation library + * Copyright (C) 2000-2004 Underbit Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: latin1.h,v 1.8 2004/01/23 09:41:32 rob Exp $ + */ + +# ifndef LIBID3TAG_LATIN1_H +# define LIBID3TAG_LATIN1_H + +# include "id3tag.h" + +id3_length_t id3_latin1_length(id3_latin1_t const *); +id3_length_t id3_latin1_size(id3_latin1_t const *); + +void id3_latin1_copy(id3_latin1_t *, id3_latin1_t const *); +id3_latin1_t *id3_latin1_duplicate(id3_latin1_t const *); + +id3_length_t id3_latin1_decodechar(id3_latin1_t const *, id3_ucs4_t *); +id3_length_t id3_latin1_encodechar(id3_latin1_t *, id3_ucs4_t); + +void id3_latin1_decode(id3_latin1_t const *, id3_ucs4_t *); +void id3_latin1_encode(id3_latin1_t *, id3_ucs4_t const *); + +id3_length_t id3_latin1_put(id3_byte_t **, id3_latin1_t); +id3_latin1_t id3_latin1_get(id3_byte_t const **); + +id3_length_t id3_latin1_serialize(id3_byte_t **, id3_ucs4_t const *, int); +id3_ucs4_t *id3_latin1_deserialize(id3_byte_t const **, id3_length_t); + +# endif diff --git a/libid3tag/parse.c b/libid3tag/parse.c new file mode 100644 index 0000000..86a3f21 --- /dev/null +++ b/libid3tag/parse.c @@ -0,0 +1,196 @@ +/* + * libid3tag - ID3 tag manipulation library + * Copyright (C) 2000-2004 Underbit Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: parse.c,v 1.9 2004/01/23 09:41:32 rob Exp $ + */ + +# ifdef HAVE_CONFIG_H +# include "config.h" +# endif + +# include "global.h" + +# ifdef HAVE_ASSERT_H +# include +# endif + +# include +# include + +# include "id3tag.h" +# include "parse.h" +# include "latin1.h" +# include "utf16.h" +# include "utf8.h" + +signed long id3_parse_int(id3_byte_t const **ptr, unsigned int bytes) +{ + signed long value = 0; + + assert(bytes >= 1 && bytes <= 4); + + if (**ptr & 0x80) + value = ~0; + + switch (bytes) { + case 4: value = (value << 8) | *(*ptr)++; + case 3: value = (value << 8) | *(*ptr)++; + case 2: value = (value << 8) | *(*ptr)++; + case 1: value = (value << 8) | *(*ptr)++; + } + + return value; +} + +unsigned long id3_parse_uint(id3_byte_t const **ptr, unsigned int bytes) +{ + unsigned long value = 0; + + assert(bytes >= 1 && bytes <= 4); + + switch (bytes) { + case 4: value = (value << 8) | *(*ptr)++; + case 3: value = (value << 8) | *(*ptr)++; + case 2: value = (value << 8) | *(*ptr)++; + case 1: value = (value << 8) | *(*ptr)++; + } + + return value; +} + +unsigned long id3_parse_syncsafe(id3_byte_t const **ptr, unsigned int bytes) +{ + unsigned long value = 0; + + assert(bytes == 4 || bytes == 5); + + switch (bytes) { + case 5: value = (value << 4) | (*(*ptr)++ & 0x0f); + case 4: value = (value << 7) | (*(*ptr)++ & 0x7f); + value = (value << 7) | (*(*ptr)++ & 0x7f); + value = (value << 7) | (*(*ptr)++ & 0x7f); + value = (value << 7) | (*(*ptr)++ & 0x7f); + } + + return value; +} + +void id3_parse_immediate(id3_byte_t const **ptr, unsigned int bytes, + char *value) +{ + assert(value); + assert(bytes == 8 || bytes == 4 || bytes == 3); + + switch (bytes) { + case 8: *value++ = *(*ptr)++; + *value++ = *(*ptr)++; + *value++ = *(*ptr)++; + *value++ = *(*ptr)++; + case 4: *value++ = *(*ptr)++; + case 3: *value++ = *(*ptr)++; + *value++ = *(*ptr)++; + *value++ = *(*ptr)++; + } + + *value = 0; +} + +id3_latin1_t *id3_parse_latin1(id3_byte_t const **ptr, id3_length_t length, + int full) +{ + id3_byte_t const *end; + int terminated = 0; + id3_latin1_t *latin1; + + end = memchr(*ptr, 0, length); + if (end == 0) + end = *ptr + length; + else { + length = end - *ptr; + terminated = 1; + } + + latin1 = malloc(length + 1); + if (latin1) { + memcpy(latin1, *ptr, length); + latin1[length] = 0; + + if (!full) { + id3_latin1_t *check; + + for (check = latin1; *check; ++check) { + if (*check == '\n') + *check = ' '; + } + } + } + + *ptr += length + terminated; + + return latin1; +} + +id3_ucs4_t *id3_parse_string(id3_byte_t const **ptr, id3_length_t length, + enum id3_field_textencoding encoding, int full) +{ + id3_ucs4_t *ucs4 = 0; + enum id3_utf16_byteorder byteorder = ID3_UTF16_BYTEORDER_ANY; + + switch (encoding) { + case ID3_FIELD_TEXTENCODING_ISO_8859_1: + ucs4 = id3_latin1_deserialize(ptr, length); + break; + + case ID3_FIELD_TEXTENCODING_UTF_16BE: + byteorder = ID3_UTF16_BYTEORDER_BE; + case ID3_FIELD_TEXTENCODING_UTF_16: + ucs4 = id3_utf16_deserialize(ptr, length, byteorder); + break; + + case ID3_FIELD_TEXTENCODING_UTF_8: + ucs4 = id3_utf8_deserialize(ptr, length); + break; + } + + if (ucs4 && !full) { + id3_ucs4_t *check; + + for (check = ucs4; *check; ++check) { + if (*check == '\n') + *check = ' '; + } + } + + return ucs4; +} + +id3_byte_t *id3_parse_binary(id3_byte_t const **ptr, id3_length_t length) +{ + id3_byte_t *data; + + if (length == 0) + return malloc(1); + + data = malloc(length); + if (data) + memcpy(data, *ptr, length); + + *ptr += length; + + return data; +} diff --git a/libid3tag/parse.h b/libid3tag/parse.h new file mode 100644 index 0000000..5dfa23f --- /dev/null +++ b/libid3tag/parse.h @@ -0,0 +1,34 @@ +/* + * libid3tag - ID3 tag manipulation library + * Copyright (C) 2000-2004 Underbit Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: parse.h,v 1.6 2004/01/23 09:41:32 rob Exp $ + */ + +# ifndef LIBID3TAG_PARSE_H +# define LIBID3TAG_PARSE_H + +signed long id3_parse_int(id3_byte_t const **, unsigned int); +unsigned long id3_parse_uint(id3_byte_t const **, unsigned int); +unsigned long id3_parse_syncsafe(id3_byte_t const **, unsigned int); +void id3_parse_immediate(id3_byte_t const **, unsigned int, char *); +id3_latin1_t *id3_parse_latin1(id3_byte_t const **, id3_length_t, int); +id3_ucs4_t *id3_parse_string(id3_byte_t const **, id3_length_t, + enum id3_field_textencoding, int); +id3_byte_t *id3_parse_binary(id3_byte_t const **, id3_length_t); + +# endif diff --git a/libid3tag/render.c b/libid3tag/render.c new file mode 100644 index 0000000..668a487 --- /dev/null +++ b/libid3tag/render.c @@ -0,0 +1,200 @@ +/* + * libid3tag - ID3 tag manipulation library + * Copyright (C) 2000-2004 Underbit Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: render.c,v 1.11 2004/01/23 09:41:32 rob Exp $ + */ + +# ifdef HAVE_CONFIG_H +# include "config.h" +# endif + +# include "global.h" + +# include +# include + +# ifdef HAVE_ASSERT_H +# include +# endif + +# include "id3tag.h" +# include "render.h" +# include "ucs4.h" +# include "latin1.h" +# include "utf16.h" +# include "utf8.h" + +id3_length_t id3_render_immediate(id3_byte_t **ptr, + char const *value, unsigned int bytes) +{ + assert(value); + assert(bytes == 8 || bytes == 4 || bytes == 3); + + if (ptr) { + switch (bytes) { + case 8: *(*ptr)++ = *value++; + *(*ptr)++ = *value++; + *(*ptr)++ = *value++; + *(*ptr)++ = *value++; + case 4: *(*ptr)++ = *value++; + case 3: *(*ptr)++ = *value++; + *(*ptr)++ = *value++; + *(*ptr)++ = *value++; + } + } + + return bytes; +} + +id3_length_t id3_render_syncsafe(id3_byte_t **ptr, + unsigned long num, unsigned int bytes) +{ + assert(bytes == 4 || bytes == 5); + + if (ptr) { + switch (bytes) { + case 5: *(*ptr)++ = (num >> 28) & 0x0f; + case 4: *(*ptr)++ = (num >> 21) & 0x7f; + *(*ptr)++ = (num >> 14) & 0x7f; + *(*ptr)++ = (num >> 7) & 0x7f; + *(*ptr)++ = (num >> 0) & 0x7f; + } + } + + return bytes; +} + +id3_length_t id3_render_int(id3_byte_t **ptr, + signed long num, unsigned int bytes) +{ + assert(bytes >= 1 && bytes <= 4); + + if (ptr) { + switch (bytes) { + case 4: *(*ptr)++ = num >> 24; + case 3: *(*ptr)++ = num >> 16; + case 2: *(*ptr)++ = num >> 8; + case 1: *(*ptr)++ = num >> 0; + } + } + + return bytes; +} + +id3_length_t id3_render_binary(id3_byte_t **ptr, + id3_byte_t const *data, id3_length_t length) +{ + if (data == 0) + return 0; + + if (ptr) { + memcpy(*ptr, data, length); + *ptr += length; + } + + return length; +} + +id3_length_t id3_render_latin1(id3_byte_t **ptr, + id3_latin1_t const *latin1, int terminate) +{ + id3_length_t size; + + if (latin1 == 0) + latin1 = ""; + + size = id3_latin1_size(latin1); + if (!terminate) + --size; + + if (ptr) { + memcpy(*ptr, latin1, size); + *ptr += size; + } + + return size; +} + +id3_length_t id3_render_string(id3_byte_t **ptr, id3_ucs4_t const *ucs4, + enum id3_field_textencoding encoding, + int terminate) +{ + enum id3_utf16_byteorder byteorder = ID3_UTF16_BYTEORDER_ANY; + + if (ucs4 == 0) + ucs4 = id3_ucs4_empty; + + switch (encoding) { + case ID3_FIELD_TEXTENCODING_ISO_8859_1: + return id3_latin1_serialize(ptr, ucs4, terminate); + + case ID3_FIELD_TEXTENCODING_UTF_16BE: + byteorder = ID3_UTF16_BYTEORDER_BE; + case ID3_FIELD_TEXTENCODING_UTF_16: + return id3_utf16_serialize(ptr, ucs4, byteorder, terminate); + + case ID3_FIELD_TEXTENCODING_UTF_8: + return id3_utf8_serialize(ptr, ucs4, terminate); + } + + return 0; +} + +id3_length_t id3_render_padding(id3_byte_t **ptr, id3_byte_t value, + id3_length_t length) +{ + if (ptr) { + memset(*ptr, value, length); + *ptr += length; + } + + return length; +} + +/* + * NAME: render->paddedstring() + * DESCRIPTION: render a space-padded string using latin1 encoding + */ +id3_length_t id3_render_paddedstring(id3_byte_t **ptr, id3_ucs4_t const *ucs4, + id3_length_t length) +{ + id3_ucs4_t padded[31], *data, *end; + + /* latin1 encoding only (this is used for ID3v1 fields) */ + + assert(length <= 30); + + data = padded; + end = data + length; + + if (ucs4) { + while (*ucs4 && end - data > 0) { + *data++ = *ucs4++; + + if (data[-1] == '\n') + data[-1] = ' '; + } + } + + while (end - data > 0) + *data++ = ' '; + + *data = 0; + + return id3_latin1_serialize(ptr, padded, 0); +} diff --git a/libid3tag/render.h b/libid3tag/render.h new file mode 100644 index 0000000..702605d --- /dev/null +++ b/libid3tag/render.h @@ -0,0 +1,40 @@ +/* + * libid3tag - ID3 tag manipulation library + * Copyright (C) 2000-2004 Underbit Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: render.h,v 1.7 2004/01/23 09:41:32 rob Exp $ + */ + +# ifndef LIBID3TAG_RENDER_H +# define LIBID3TAG_RENDER_H + +# include "id3tag.h" + +id3_length_t id3_render_immediate(id3_byte_t **, char const *, unsigned int); +id3_length_t id3_render_syncsafe(id3_byte_t **, unsigned long, unsigned int); +id3_length_t id3_render_int(id3_byte_t **, signed long, unsigned int); +id3_length_t id3_render_binary(id3_byte_t **, + id3_byte_t const *, id3_length_t); +id3_length_t id3_render_latin1(id3_byte_t **, id3_latin1_t const *, int); +id3_length_t id3_render_string(id3_byte_t **, id3_ucs4_t const *, + enum id3_field_textencoding, int); +id3_length_t id3_render_padding(id3_byte_t **, id3_byte_t, id3_length_t); + +id3_length_t id3_render_paddedstring(id3_byte_t **, id3_ucs4_t const *, + id3_length_t); + +# endif diff --git a/libid3tag/tag.c b/libid3tag/tag.c new file mode 100644 index 0000000..be4e8e7 --- /dev/null +++ b/libid3tag/tag.c @@ -0,0 +1,909 @@ +/* + * libid3tag - ID3 tag manipulation library + * Copyright (C) 2000-2004 Underbit Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: tag.c,v 1.20 2004/02/17 02:04:10 rob Exp $ + */ + +# ifdef HAVE_CONFIG_H +# include "config.h" +# endif + +# include "global.h" + +# include +# include + +# ifdef HAVE_ASSERT_H +# include +# endif + +# include "id3tag.h" +# include "tag.h" +# include "frame.h" +# include "compat.h" +# include "parse.h" +# include "render.h" +# include "latin1.h" +# include "ucs4.h" +# include "genre.h" +# include "crc.h" +# include "field.h" +# include "util.h" + +/* + * NAME: tag->new() + * DESCRIPTION: allocate and return a new, empty tag + */ +struct id3_tag *id3_tag_new(void) +{ + struct id3_tag *tag; + + tag = malloc(sizeof(*tag)); + if (tag) { + tag->refcount = 0; + tag->version = ID3_TAG_VERSION; + tag->flags = 0; + tag->extendedflags = 0; + tag->restrictions = 0; + tag->options = /* ID3_TAG_OPTION_UNSYNCHRONISATION | */ + ID3_TAG_OPTION_COMPRESSION | ID3_TAG_OPTION_CRC; + tag->nframes = 0; + tag->frames = 0; + tag->paddedsize = 0; + } + + return tag; +} + +/* + * NAME: tag->delete() + * DESCRIPTION: destroy a tag and deallocate all associated memory + */ +void id3_tag_delete(struct id3_tag *tag) +{ + assert(tag); + + if (tag->refcount == 0) { + id3_tag_clearframes(tag); + + if (tag->frames) + free(tag->frames); + + free(tag); + } +} + +/* + * NAME: tag->addref() + * DESCRIPTION: add an external reference to a tag + */ +void id3_tag_addref(struct id3_tag *tag) +{ + assert(tag); + + ++tag->refcount; +} + +/* + * NAME: tag->delref() + * DESCRIPTION: remove an external reference to a tag + */ +void id3_tag_delref(struct id3_tag *tag) +{ + assert(tag && tag->refcount > 0); + + --tag->refcount; +} + +/* + * NAME: tag->version() + * DESCRIPTION: return the tag's original ID3 version number + */ +unsigned int id3_tag_version(struct id3_tag const *tag) +{ + assert(tag); + + return tag->version; +} + +/* + * NAME: tag->options() + * DESCRIPTION: get or set tag options + */ +int id3_tag_options(struct id3_tag *tag, int mask, int values) +{ + assert(tag); + + if (mask) + tag->options = (tag->options & ~mask) | (values & mask); + + return tag->options; +} + +/* + * NAME: tag->setlength() + * DESCRIPTION: set the minimum rendered tag size + */ +void id3_tag_setlength(struct id3_tag *tag, id3_length_t length) +{ + assert(tag); + + tag->paddedsize = length; +} + +/* + * NAME: tag->clearframes() + * DESCRIPTION: detach and delete all frames associated with a tag + */ +void id3_tag_clearframes(struct id3_tag *tag) +{ + unsigned int i; + + assert(tag); + + for (i = 0; i < tag->nframes; ++i) { + id3_frame_delref(tag->frames[i]); + id3_frame_delete(tag->frames[i]); + } + + tag->nframes = 0; +} + +/* + * NAME: tag->attachframe() + * DESCRIPTION: attach a frame to a tag + */ +int id3_tag_attachframe(struct id3_tag *tag, struct id3_frame *frame) +{ + struct id3_frame **frames; + + assert(tag && frame); + + frames = realloc(tag->frames, (tag->nframes + 1) * sizeof(*frames)); + if (frames == 0) + return -1; + + tag->frames = frames; + tag->frames[tag->nframes++] = frame; + + id3_frame_addref(frame); + + return 0; +} + +/* + * NAME: tag->detachframe() + * DESCRIPTION: detach (but don't delete) a frame from a tag + */ +int id3_tag_detachframe(struct id3_tag *tag, struct id3_frame *frame) +{ + unsigned int i; + + assert(tag && frame); + + for (i = 0; i < tag->nframes; ++i) { + if (tag->frames[i] == frame) + break; + } + + if (i == tag->nframes) + return -1; + + --tag->nframes; + while (i++ < tag->nframes) + tag->frames[i - 1] = tag->frames[i]; + + id3_frame_delref(frame); + + return 0; +} + +/* + * NAME: tag->findframe() + * DESCRIPTION: find in a tag the nth (0-based) frame with the given frame ID + */ +struct id3_frame *id3_tag_findframe(struct id3_tag const *tag, + char const *id, unsigned int index) +{ + unsigned int len, i; + + assert(tag); + + if (id == 0 || *id == 0) + return (index < tag->nframes) ? tag->frames[index] : 0; + + len = strlen(id); + + if (len == 4) { + struct id3_compat const *compat; + + compat = id3_compat_lookup(id, len); + if (compat && compat->equiv && !compat->translate) { + id = compat->equiv; + len = strlen(id); + } + } + + for (i = 0; i < tag->nframes; ++i) { + if (strncmp(tag->frames[i]->id, id, len) == 0 && index-- == 0) + return tag->frames[i]; + } + + return 0; +} + +enum tagtype { + TAGTYPE_NONE = 0, + TAGTYPE_ID3V1, + TAGTYPE_ID3V2, + TAGTYPE_ID3V2_FOOTER +}; + +static +enum tagtype tagtype(id3_byte_t const *data, id3_length_t length) +{ + if (length >= 3 && + data[0] == 'T' && data[1] == 'A' && data[2] == 'G') + return TAGTYPE_ID3V1; + + if (length >= 10 && + ((data[0] == 'I' && data[1] == 'D' && data[2] == '3') || + (data[0] == '3' && data[1] == 'D' && data[2] == 'I')) && + data[3] < 0xff && data[4] < 0xff && + data[6] < 0x80 && data[7] < 0x80 && data[8] < 0x80 && data[9] < 0x80) + return data[0] == 'I' ? TAGTYPE_ID3V2 : TAGTYPE_ID3V2_FOOTER; + + return TAGTYPE_NONE; +} + +static +void parse_header(id3_byte_t const **ptr, + unsigned int *version, int *flags, id3_length_t *size) +{ + *ptr += 3; + + *version = id3_parse_uint(ptr, 2); + *flags = id3_parse_uint(ptr, 1); + *size = id3_parse_syncsafe(ptr, 4); +} + +/* + * NAME: tag->query() + * DESCRIPTION: if a tag begins at the given location, return its size + */ +signed long id3_tag_query(id3_byte_t const *data, id3_length_t length) +{ + unsigned int version; + int flags; + id3_length_t size; + + assert(data); + + switch (tagtype(data, length)) { + case TAGTYPE_ID3V1: + return 128; + + case TAGTYPE_ID3V2: + parse_header(&data, &version, &flags, &size); + + if (flags & ID3_TAG_FLAG_FOOTERPRESENT) + size += 10; + + return 10 + size; + + case TAGTYPE_ID3V2_FOOTER: + parse_header(&data, &version, &flags, &size); + return -size - 10; + + case TAGTYPE_NONE: + break; + } + + return 0; +} + +static +void trim(char *str) +{ + char *ptr; + + ptr = str + strlen(str); + while (ptr > str && ptr[-1] == ' ') + --ptr; + + *ptr = 0; +} + +static +int v1_attachstr(struct id3_tag *tag, char const *id, + char *text, unsigned long number) +{ + struct id3_frame *frame; + id3_ucs4_t ucs4[31]; + + if (text) { + trim(text); + if (*text == 0) + return 0; + } + + frame = id3_frame_new(id); + if (frame == 0) + return -1; + + if (id3_field_settextencoding(&frame->fields[0], + ID3_FIELD_TEXTENCODING_ISO_8859_1) == -1) + goto fail; + + if (text) + id3_latin1_decode(text, ucs4); + else + id3_ucs4_putnumber(ucs4, number); + + if (strcmp(id, ID3_FRAME_COMMENT) == 0) { + if (id3_field_setlanguage(&frame->fields[1], "XXX") == -1 || + id3_field_setstring(&frame->fields[2], id3_ucs4_empty) == -1 || + id3_field_setfullstring(&frame->fields[3], ucs4) == -1) + goto fail; + } + else { + id3_ucs4_t *ptr = ucs4; + + if (id3_field_setstrings(&frame->fields[1], 1, &ptr) == -1) + goto fail; + } + + if (id3_tag_attachframe(tag, frame) == -1) + goto fail; + + return 0; + + fail: + id3_frame_delete(frame); + return -1; +} + +static +struct id3_tag *v1_parse(id3_byte_t const *data) +{ + struct id3_tag *tag; + + tag = id3_tag_new(); + if (tag) { + char title[31], artist[31], album[31], year[5], comment[31]; + unsigned int genre, track; + + tag->version = 0x0100; + + tag->options |= ID3_TAG_OPTION_ID3V1; + tag->options &= ~ID3_TAG_OPTION_COMPRESSION; + + tag->restrictions = + ID3_TAG_RESTRICTION_TEXTENCODING_LATIN1_UTF8 | + ID3_TAG_RESTRICTION_TEXTSIZE_30_CHARS; + + title[30] = artist[30] = album[30] = year[4] = comment[30] = 0; + + memcpy(title, &data[3], 30); + memcpy(artist, &data[33], 30); + memcpy(album, &data[63], 30); + memcpy(year, &data[93], 4); + memcpy(comment, &data[97], 30); + + genre = data[127]; + + track = 0; + if (comment[28] == 0 && comment[29] != 0) { + track = comment[29]; + tag->version = 0x0101; + } + + /* populate tag frames */ + + if (v1_attachstr(tag, ID3_FRAME_TITLE, title, 0) == -1 || + v1_attachstr(tag, ID3_FRAME_ARTIST, artist, 0) == -1 || + v1_attachstr(tag, ID3_FRAME_ALBUM, album, 0) == -1 || + v1_attachstr(tag, ID3_FRAME_YEAR, year, 0) == -1 || + (track && v1_attachstr(tag, ID3_FRAME_TRACK, 0, track) == -1) || + (genre < 0xff && v1_attachstr(tag, ID3_FRAME_GENRE, 0, genre) == -1) || + v1_attachstr(tag, ID3_FRAME_COMMENT, comment, 0) == -1) { + id3_tag_delete(tag); + tag = 0; + } + } + + return tag; +} + +static +struct id3_tag *v2_parse(id3_byte_t const *ptr) +{ + struct id3_tag *tag; + id3_byte_t *mem = 0; + + tag = id3_tag_new(); + if (tag) { + id3_byte_t const *end; + id3_length_t size; + + parse_header(&ptr, &tag->version, &tag->flags, &size); + + tag->paddedsize = 10 + size; + + if ((tag->flags & ID3_TAG_FLAG_UNSYNCHRONISATION) && + ID3_TAG_VERSION_MAJOR(tag->version) < 4) { + mem = malloc(size); + if (mem == 0) + goto fail; + + memcpy(mem, ptr, size); + + size = id3_util_deunsynchronise(mem, size); + ptr = mem; + } + + end = ptr + size; + + if (tag->flags & ID3_TAG_FLAG_EXTENDEDHEADER) { + switch (ID3_TAG_VERSION_MAJOR(tag->version)) { + case 2: + goto fail; + + case 3: + { + id3_byte_t const *ehptr, *ehend; + id3_length_t ehsize; + + enum { + EH_FLAG_CRC = 0x8000 /* CRC data present */ + }; + + if (end - ptr < 4) + goto fail; + + ehsize = id3_parse_uint(&ptr, 4); + + if (ehsize > end - ptr) + goto fail; + + ehptr = ptr; + ehend = ptr + ehsize; + + ptr = ehend; + + if (ehend - ehptr >= 6) { + int ehflags; + id3_length_t padsize; + + ehflags = id3_parse_uint(&ehptr, 2); + padsize = id3_parse_uint(&ehptr, 4); + + if (padsize > end - ptr) + goto fail; + + end -= padsize; + + if (ehflags & EH_FLAG_CRC) { + unsigned long crc; + + if (ehend - ehptr < 4) + goto fail; + + crc = id3_parse_uint(&ehptr, 4); + + if (crc != id3_crc_compute(ptr, end - ptr)) + goto fail; + + tag->extendedflags |= ID3_TAG_EXTENDEDFLAG_CRCDATAPRESENT; + } + } + } + break; + + case 4: + { + id3_byte_t const *ehptr, *ehend; + id3_length_t ehsize; + unsigned int bytes; + + if (end - ptr < 4) + goto fail; + + ehptr = ptr; + ehsize = id3_parse_syncsafe(&ptr, 4); + + if (ehsize < 6 || ehsize > end - ehptr) + goto fail; + + ehend = ehptr + ehsize; + + bytes = id3_parse_uint(&ptr, 1); + + if (bytes < 1 || bytes > ehend - ptr) + goto fail; + + ehptr = ptr + bytes; + + /* verify extended header size */ + { + id3_byte_t const *flagsptr = ptr, *dataptr = ehptr; + unsigned int datalen; + int ehflags; + + while (bytes--) { + for (ehflags = id3_parse_uint(&flagsptr, 1); ehflags; + ehflags = (ehflags << 1) & 0xff) { + if (ehflags & 0x80) { + if (dataptr == ehend) + goto fail; + datalen = id3_parse_uint(&dataptr, 1); + if (datalen > 0x7f || datalen > ehend - dataptr) + goto fail; + dataptr += datalen; + } + } + } + } + + tag->extendedflags = id3_parse_uint(&ptr, 1); + + ptr = ehend; + + if (tag->extendedflags & ID3_TAG_EXTENDEDFLAG_TAGISANUPDATE) { + bytes = id3_parse_uint(&ehptr, 1); + ehptr += bytes; + } + + if (tag->extendedflags & ID3_TAG_EXTENDEDFLAG_CRCDATAPRESENT) { + unsigned long crc; + + bytes = id3_parse_uint(&ehptr, 1); + if (bytes < 5) + goto fail; + + crc = id3_parse_syncsafe(&ehptr, 5); + ehptr += bytes - 5; + + if (crc != id3_crc_compute(ptr, end - ptr)) + goto fail; + } + + if (tag->extendedflags & ID3_TAG_EXTENDEDFLAG_TAGRESTRICTIONS) { + bytes = id3_parse_uint(&ehptr, 1); + if (bytes < 1) + goto fail; + + tag->restrictions = id3_parse_uint(&ehptr, 1); + ehptr += bytes - 1; + } + } + break; + } + } + + /* frames */ + + while (ptr < end) { + struct id3_frame *frame; + + if (*ptr == 0) + break; /* padding */ + + frame = id3_frame_parse(&ptr, end - ptr, tag->version); + if (frame == 0 || id3_tag_attachframe(tag, frame) == -1) + goto fail; + } + + if (ID3_TAG_VERSION_MAJOR(tag->version) < 4 && + id3_compat_fixup(tag) == -1) + goto fail; + } + + if (0) { + fail: + id3_tag_delete(tag); + tag = 0; + } + + if (mem) + free(mem); + + return tag; +} + +/* + * NAME: tag->parse() + * DESCRIPTION: parse a complete ID3 tag + */ +struct id3_tag *id3_tag_parse(id3_byte_t const *data, id3_length_t length) +{ + id3_byte_t const *ptr; + unsigned int version; + int flags; + id3_length_t size; + + assert(data); + + switch (tagtype(data, length)) { + case TAGTYPE_ID3V1: + return (length < 128) ? 0 : v1_parse(data); + + case TAGTYPE_ID3V2: + break; + + case TAGTYPE_ID3V2_FOOTER: + case TAGTYPE_NONE: + return 0; + } + + /* ID3v2.x */ + + ptr = data; + parse_header(&ptr, &version, &flags, &size); + + switch (ID3_TAG_VERSION_MAJOR(version)) { + case 4: + if (flags & ID3_TAG_FLAG_FOOTERPRESENT) + size += 10; + case 2: + case 3: + return (length < 10 + size) ? 0 : v2_parse(data); + } + + return 0; +} + +static +void v1_renderstr(struct id3_tag const *tag, char const *frameid, + id3_byte_t **buffer, id3_length_t length) +{ + struct id3_frame *frame; + id3_ucs4_t const *string; + + frame = id3_tag_findframe(tag, frameid, 0); + if (frame == 0) + string = id3_ucs4_empty; + else { + if (strcmp(frameid, ID3_FRAME_COMMENT) == 0) + string = id3_field_getfullstring(&frame->fields[3]); + else + string = id3_field_getstrings(&frame->fields[1], 0); + } + + id3_render_paddedstring(buffer, string, length); +} + +/* + * NAME: v1->render() + * DESCRIPTION: render an ID3v1 (or ID3v1.1) tag + */ +static +id3_length_t v1_render(struct id3_tag const *tag, id3_byte_t *buffer) +{ + id3_byte_t data[128], *ptr; + struct id3_frame *frame; + unsigned int i; + int genre = -1; + + ptr = data; + + id3_render_immediate(&ptr, "TAG", 3); + + v1_renderstr(tag, ID3_FRAME_TITLE, &ptr, 30); + v1_renderstr(tag, ID3_FRAME_ARTIST, &ptr, 30); + v1_renderstr(tag, ID3_FRAME_ALBUM, &ptr, 30); + v1_renderstr(tag, ID3_FRAME_YEAR, &ptr, 4); + v1_renderstr(tag, ID3_FRAME_COMMENT, &ptr, 30); + + /* ID3v1.1 track number */ + + frame = id3_tag_findframe(tag, ID3_FRAME_TRACK, 0); + if (frame) { + unsigned int track; + + track = id3_ucs4_getnumber(id3_field_getstrings(&frame->fields[1], 0)); + if (track > 0 && track <= 0xff) { + ptr[-2] = 0; + ptr[-1] = track; + } + } + + /* ID3v1 genre number */ + + frame = id3_tag_findframe(tag, ID3_FRAME_GENRE, 0); + if (frame) { + unsigned int nstrings; + + nstrings = id3_field_getnstrings(&frame->fields[1]); + + for (i = 0; i < nstrings; ++i) { + genre = id3_genre_number(id3_field_getstrings(&frame->fields[1], i)); + if (genre != -1) + break; + } + + if (i == nstrings && nstrings > 0) + genre = ID3_GENRE_OTHER; + } + + id3_render_int(&ptr, genre, 1); + + /* make sure the tag is not empty */ + + if (genre == -1) { + for (i = 3; i < 127; ++i) { + if (data[i] != ' ') + break; + } + + if (i == 127) + return 0; + } + + if (buffer) + memcpy(buffer, data, 128); + + return 128; +} + +/* + * NAME: tag->render() + * DESCRIPTION: render a complete ID3 tag + */ +id3_length_t id3_tag_render(struct id3_tag const *tag, id3_byte_t *buffer) +{ + id3_length_t size = 0; + id3_byte_t **ptr, + *header_ptr = 0, *tagsize_ptr = 0, *crc_ptr = 0, *frames_ptr = 0; + int flags, extendedflags; + unsigned int i; + + assert(tag); + + if (tag->options & ID3_TAG_OPTION_ID3V1) + return v1_render(tag, buffer); + + /* a tag must contain at least one (renderable) frame */ + + for (i = 0; i < tag->nframes; ++i) { + if (id3_frame_render(tag->frames[i], 0, 0) > 0) + break; + } + + if (i == tag->nframes) + return 0; + + ptr = buffer ? &buffer : 0; + + /* get flags */ + + flags = tag->flags & ID3_TAG_FLAG_KNOWNFLAGS; + extendedflags = tag->extendedflags & ID3_TAG_EXTENDEDFLAG_KNOWNFLAGS; + + extendedflags &= ~ID3_TAG_EXTENDEDFLAG_CRCDATAPRESENT; + if (tag->options & ID3_TAG_OPTION_CRC) + extendedflags |= ID3_TAG_EXTENDEDFLAG_CRCDATAPRESENT; + + extendedflags &= ~ID3_TAG_EXTENDEDFLAG_TAGRESTRICTIONS; + if (tag->restrictions) + extendedflags |= ID3_TAG_EXTENDEDFLAG_TAGRESTRICTIONS; + + flags &= ~ID3_TAG_FLAG_UNSYNCHRONISATION; + if (tag->options & ID3_TAG_OPTION_UNSYNCHRONISATION) + flags |= ID3_TAG_FLAG_UNSYNCHRONISATION; + + flags &= ~ID3_TAG_FLAG_EXTENDEDHEADER; + if (extendedflags) + flags |= ID3_TAG_FLAG_EXTENDEDHEADER; + + flags &= ~ID3_TAG_FLAG_FOOTERPRESENT; + if (tag->options & ID3_TAG_OPTION_APPENDEDTAG) + flags |= ID3_TAG_FLAG_FOOTERPRESENT; + + /* header */ + + if (ptr) + header_ptr = *ptr; + + size += id3_render_immediate(ptr, "ID3", 3); + size += id3_render_int(ptr, ID3_TAG_VERSION, 2); + size += id3_render_int(ptr, flags, 1); + + if (ptr) + tagsize_ptr = *ptr; + + size += id3_render_syncsafe(ptr, 0, 4); + + /* extended header */ + + if (flags & ID3_TAG_FLAG_EXTENDEDHEADER) { + id3_length_t ehsize = 0; + id3_byte_t *ehsize_ptr = 0; + + if (ptr) + ehsize_ptr = *ptr; + + ehsize += id3_render_syncsafe(ptr, 0, 4); + ehsize += id3_render_int(ptr, 1, 1); + ehsize += id3_render_int(ptr, extendedflags, 1); + + if (extendedflags & ID3_TAG_EXTENDEDFLAG_TAGISANUPDATE) + ehsize += id3_render_int(ptr, 0, 1); + + if (extendedflags & ID3_TAG_EXTENDEDFLAG_CRCDATAPRESENT) { + ehsize += id3_render_int(ptr, 5, 1); + + if (ptr) + crc_ptr = *ptr; + + ehsize += id3_render_syncsafe(ptr, 0, 5); + } + + if (extendedflags & ID3_TAG_EXTENDEDFLAG_TAGRESTRICTIONS) { + ehsize += id3_render_int(ptr, 1, 1); + ehsize += id3_render_int(ptr, tag->restrictions, 1); + } + + if (ehsize_ptr) + id3_render_syncsafe(&ehsize_ptr, ehsize, 4); + + size += ehsize; + } + + /* frames */ + + if (ptr) + frames_ptr = *ptr; + + for (i = 0; i < tag->nframes; ++i) + size += id3_frame_render(tag->frames[i], ptr, tag->options); + + /* padding */ + + if (!(flags & ID3_TAG_FLAG_FOOTERPRESENT)) { + if (size < tag->paddedsize) + size += id3_render_padding(ptr, 0, tag->paddedsize - size); + else if (tag->options & ID3_TAG_OPTION_UNSYNCHRONISATION) { + if (ptr == 0) + size += 1; + else { + if ((*ptr)[-1] == 0xff) + size += id3_render_padding(ptr, 0, 1); + } + } + } + + /* patch tag size and CRC */ + + if (tagsize_ptr) + id3_render_syncsafe(&tagsize_ptr, size - 10, 4); + + if (crc_ptr) { + id3_render_syncsafe(&crc_ptr, + id3_crc_compute(frames_ptr, *ptr - frames_ptr), 5); + } + + /* footer */ + + if (flags & ID3_TAG_FLAG_FOOTERPRESENT) { + size += id3_render_immediate(ptr, "3DI", 3); + size += id3_render_binary(ptr, header_ptr + 3, 7); + } + + return size; +} diff --git a/libid3tag/tag.h b/libid3tag/tag.h new file mode 100644 index 0000000..2ce84d7 --- /dev/null +++ b/libid3tag/tag.h @@ -0,0 +1,30 @@ +/* + * libid3tag - ID3 tag manipulation library + * Copyright (C) 2000-2004 Underbit Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: tag.h,v 1.10 2004/01/23 09:41:32 rob Exp $ + */ + +# ifndef LIBID3TAG_TAG_H +# define LIBID3TAG_TAG_H + +# include "id3tag.h" + +void id3_tag_addref(struct id3_tag *); +void id3_tag_delref(struct id3_tag *); + +# endif diff --git a/libid3tag/ucs4.c b/libid3tag/ucs4.c new file mode 100644 index 0000000..15dace8 --- /dev/null +++ b/libid3tag/ucs4.c @@ -0,0 +1,224 @@ +/* + * libid3tag - ID3 tag manipulation library + * Copyright (C) 2000-2004 Underbit Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: ucs4.c,v 1.13 2004/01/23 09:41:32 rob Exp $ + */ + +# ifdef HAVE_CONFIG_H +# include "config.h" +# endif + +# include "global.h" + +# include + +# include "id3tag.h" +# include "ucs4.h" +# include "latin1.h" +# include "utf16.h" +# include "utf8.h" + +id3_ucs4_t const id3_ucs4_empty[] = { 0 }; + +/* + * NAME: ucs4->length() + * DESCRIPTION: return the number of ucs4 chars represented by a ucs4 string + */ +id3_length_t id3_ucs4_length(id3_ucs4_t const *ucs4) +{ + id3_ucs4_t const *ptr = ucs4; + + while (*ptr) + ++ptr; + + return ptr - ucs4; +} + +/* + * NAME: ucs4->size() + * DESCRIPTION: return the encoding size of a ucs4 string + */ +id3_length_t id3_ucs4_size(id3_ucs4_t const *ucs4) +{ + return id3_ucs4_length(ucs4) + 1; +} + +/* + * NAME: ucs4->latin1size() + * DESCRIPTION: return the encoding size of a latin1-encoded ucs4 string + */ +id3_length_t id3_ucs4_latin1size(id3_ucs4_t const *ucs4) +{ + return id3_ucs4_size(ucs4); +} + +/* + * NAME: ucs4->utf16size() + * DESCRIPTION: return the encoding size of a utf16-encoded ucs4 string + */ +id3_length_t id3_ucs4_utf16size(id3_ucs4_t const *ucs4) +{ + id3_length_t size = 0; + + while (*ucs4) { + ++size; + if (*ucs4 >= 0x00010000L && + *ucs4 <= 0x0010ffffL) + ++size; + + ++ucs4; + } + + return size + 1; +} + +/* + * NAME: ucs4->utf8size() + * DESCRIPTION: return the encoding size of a utf8-encoded ucs4 string + */ +id3_length_t id3_ucs4_utf8size(id3_ucs4_t const *ucs4) +{ + id3_length_t size = 0; + + while (*ucs4) { + if (*ucs4 <= 0x0000007fL) + size += 1; + else if (*ucs4 <= 0x000007ffL) + size += 2; + else if (*ucs4 <= 0x0000ffffL) + size += 3; + else if (*ucs4 <= 0x001fffffL) + size += 4; + else if (*ucs4 <= 0x03ffffffL) + size += 5; + else if (*ucs4 <= 0x7fffffffL) + size += 6; + else + size += 2; /* based on U+00B7 replacement char */ + + ++ucs4; + } + + return size + 1; +} + +/* + * NAME: ucs4->latin1duplicate() + * DESCRIPTION: duplicate and encode a ucs4 string into latin1 + */ +id3_latin1_t *id3_ucs4_latin1duplicate(id3_ucs4_t const *ucs4) +{ + id3_latin1_t *latin1; + + latin1 = malloc(id3_ucs4_latin1size(ucs4) * sizeof(*latin1)); + if (latin1) + id3_latin1_encode(latin1, ucs4); + + return release(latin1); +} + +/* + * NAME: ucs4->utf16duplicate() + * DESCRIPTION: duplicate and encode a ucs4 string into utf16 + */ +id3_utf16_t *id3_ucs4_utf16duplicate(id3_ucs4_t const *ucs4) +{ + id3_utf16_t *utf16; + + utf16 = malloc(id3_ucs4_utf16size(ucs4) * sizeof(*utf16)); + if (utf16) + id3_utf16_encode(utf16, ucs4); + + return release(utf16); +} + +/* + * NAME: ucs4->utf8duplicate() + * DESCRIPTION: duplicate and encode a ucs4 string into utf8 + */ +id3_utf8_t *id3_ucs4_utf8duplicate(id3_ucs4_t const *ucs4) +{ + id3_utf8_t *utf8; + + utf8 = malloc(id3_ucs4_utf8size(ucs4) * sizeof(*utf8)); + if (utf8) + id3_utf8_encode(utf8, ucs4); + + return release(utf8); +} + +/* + * NAME: ucs4->copy() + * DESCRIPTION: copy a ucs4 string + */ +void id3_ucs4_copy(id3_ucs4_t *dest, id3_ucs4_t const *src) +{ + while ((*dest++ = *src++)) + ; +} + +/* + * NAME: ucs4->duplicate() + * DESCRIPTION: duplicate a ucs4 string + */ +id3_ucs4_t *id3_ucs4_duplicate(id3_ucs4_t const *src) +{ + id3_ucs4_t *ucs4; + + ucs4 = malloc(id3_ucs4_size(src) * sizeof(*ucs4)); + if (ucs4) + id3_ucs4_copy(ucs4, src); + + return ucs4; +} + +/* + * NAME: ucs4->putnumber() + * DESCRIPTION: write a ucs4 string containing a (positive) decimal number + */ +void id3_ucs4_putnumber(id3_ucs4_t *ucs4, unsigned long number) +{ + int digits[10], *digit; + + digit = digits; + + do { + *digit++ = number % 10; + number /= 10; + } + while (number); + + while (digit != digits) + *ucs4++ = '0' + *--digit; + + *ucs4 = 0; +} + +/* + * NAME: ucs4->getnumber() + * DESCRIPTION: read a ucs4 string containing a (positive) decimal number + */ +unsigned long id3_ucs4_getnumber(id3_ucs4_t const *ucs4) +{ + unsigned long number = 0; + + while (*ucs4 >= '0' && *ucs4 <= '9') + number = 10 * number + (*ucs4++ - '0'); + + return number; +} diff --git a/libid3tag/ucs4.h b/libid3tag/ucs4.h new file mode 100644 index 0000000..bfb325d --- /dev/null +++ b/libid3tag/ucs4.h @@ -0,0 +1,41 @@ +/* + * libid3tag - ID3 tag manipulation library + * Copyright (C) 2000-2004 Underbit Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: ucs4.h,v 1.11 2004/01/23 09:41:32 rob Exp $ + */ + +# ifndef LIBID3TAG_UCS4_H +# define LIBID3TAG_UCS4_H + +# include "id3tag.h" + +# define ID3_UCS4_REPLACEMENTCHAR 0x000000b7L /* middle dot */ + +extern id3_ucs4_t const id3_ucs4_empty[]; + +id3_length_t id3_ucs4_length(id3_ucs4_t const *); +id3_length_t id3_ucs4_size(id3_ucs4_t const *); + +id3_length_t id3_ucs4_latin1size(id3_ucs4_t const *); +id3_length_t id3_ucs4_utf16size(id3_ucs4_t const *); +id3_length_t id3_ucs4_utf8size(id3_ucs4_t const *); + +void id3_ucs4_copy(id3_ucs4_t *, id3_ucs4_t const *); +id3_ucs4_t *id3_ucs4_duplicate(id3_ucs4_t const *); + +# endif diff --git a/libid3tag/utf16.c b/libid3tag/utf16.c new file mode 100644 index 0000000..70ee9d5 --- /dev/null +++ b/libid3tag/utf16.c @@ -0,0 +1,286 @@ +/* + * libid3tag - ID3 tag manipulation library + * Copyright (C) 2000-2004 Underbit Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: utf16.c,v 1.9 2004/01/23 09:41:32 rob Exp $ + */ + +# ifdef HAVE_CONFIG_H +# include "config.h" +# endif + +# include "global.h" + +# include + +# include "id3tag.h" +# include "utf16.h" +# include "ucs4.h" + +/* + * NAME: utf16->length() + * DESCRIPTION: return the number of ucs4 chars represented by a utf16 string + */ +id3_length_t id3_utf16_length(id3_utf16_t const *utf16) +{ + id3_length_t length = 0; + + while (*utf16) { + if (utf16[0] < 0xd800 || utf16[0] > 0xdfff) + ++length; + else if (utf16[0] >= 0xd800 && utf16[0] <= 0xdbff && + utf16[1] >= 0xdc00 && utf16[1] <= 0xdfff) { + ++length; + ++utf16; + } + + ++utf16; + } + + return length; +} + +/* + * NAME: utf16->size() + * DESCRIPTION: return the encoding size of a utf16 string + */ +id3_length_t id3_utf16_size(id3_utf16_t const *utf16) +{ + id3_utf16_t const *ptr = utf16; + + while (*ptr) + ++ptr; + + return ptr - utf16 + 1; +} + +/* + * NAME: utf16->ucs4duplicate() + * DESCRIPTION: duplicate and decode a utf16 string into ucs4 + */ +id3_ucs4_t *id3_utf16_ucs4duplicate(id3_utf16_t const *utf16) +{ + id3_ucs4_t *ucs4; + + ucs4 = malloc((id3_utf16_length(utf16) + 1) * sizeof(*ucs4)); + if (ucs4) + id3_utf16_decode(utf16, ucs4); + + return release(ucs4); +} + +/* + * NAME: utf16->decodechar() + * DESCRIPTION: decode a series of utf16 chars into a single ucs4 char + */ +id3_length_t id3_utf16_decodechar(id3_utf16_t const *utf16, id3_ucs4_t *ucs4) +{ + id3_utf16_t const *start = utf16; + + while (1) { + if (utf16[0] < 0xd800 || utf16[0] > 0xdfff) { + *ucs4 = utf16[0]; + return utf16 - start + 1; + } + else if (utf16[0] >= 0xd800 && utf16[0] <= 0xdbff && + utf16[1] >= 0xdc00 && utf16[1] <= 0xdfff) { + *ucs4 = (((utf16[0] & 0x03ffL) << 10) | + ((utf16[1] & 0x03ffL) << 0)) + 0x00010000L; + return utf16 - start + 2; + } + + ++utf16; + } +} + +/* + * NAME: utf16->encodechar() + * DESCRIPTION: encode a single ucs4 char into a series of up to 2 utf16 chars + */ +id3_length_t id3_utf16_encodechar(id3_utf16_t *utf16, id3_ucs4_t ucs4) +{ + if (ucs4 < 0x00010000L) { + utf16[0] = ucs4; + + return 1; + } + else if (ucs4 < 0x00110000L) { + ucs4 -= 0x00010000L; + + utf16[0] = ((ucs4 >> 10) & 0x3ff) | 0xd800; + utf16[1] = ((ucs4 >> 0) & 0x3ff) | 0xdc00; + + return 2; + } + + /* default */ + + return id3_utf16_encodechar(utf16, ID3_UCS4_REPLACEMENTCHAR); +} + +/* + * NAME: utf16->decode() + * DESCRIPTION: decode a complete utf16 string into a ucs4 string + */ +void id3_utf16_decode(id3_utf16_t const *utf16, id3_ucs4_t *ucs4) +{ + do + utf16 += id3_utf16_decodechar(utf16, ucs4); + while (*ucs4++); +} + +/* + * NAME: utf16->encode() + * DESCRIPTION: encode a complete ucs4 string into a utf16 string + */ +void id3_utf16_encode(id3_utf16_t *utf16, id3_ucs4_t const *ucs4) +{ + do + utf16 += id3_utf16_encodechar(utf16, *ucs4); + while (*ucs4++); +} + +/* + * NAME: utf16->put() + * DESCRIPTION: serialize a single utf16 character + */ +id3_length_t id3_utf16_put(id3_byte_t **ptr, id3_utf16_t utf16, + enum id3_utf16_byteorder byteorder) +{ + if (ptr) { + switch (byteorder) { + default: + case ID3_UTF16_BYTEORDER_BE: + (*ptr)[0] = (utf16 >> 8) & 0xff; + (*ptr)[1] = (utf16 >> 0) & 0xff; + break; + + case ID3_UTF16_BYTEORDER_LE: + (*ptr)[0] = (utf16 >> 0) & 0xff; + (*ptr)[1] = (utf16 >> 8) & 0xff; + break; + } + + *ptr += 2; + } + + return 2; +} + +/* + * NAME: utf16->get() + * DESCRIPTION: deserialize a single utf16 character + */ +id3_utf16_t id3_utf16_get(id3_byte_t const **ptr, + enum id3_utf16_byteorder byteorder) +{ + id3_utf16_t utf16; + + switch (byteorder) { + default: + case ID3_UTF16_BYTEORDER_BE: + utf16 = + ((*ptr)[0] << 8) | + ((*ptr)[1] << 0); + break; + + case ID3_UTF16_BYTEORDER_LE: + utf16 = + ((*ptr)[0] << 0) | + ((*ptr)[1] << 8); + break; + } + + *ptr += 2; + + return utf16; +} + +/* + * NAME: utf16->serialize() + * DESCRIPTION: serialize a ucs4 string using utf16 encoding + */ +id3_length_t id3_utf16_serialize(id3_byte_t **ptr, id3_ucs4_t const *ucs4, + enum id3_utf16_byteorder byteorder, + int terminate) +{ + id3_length_t size = 0; + id3_utf16_t utf16[2], *out; + + if (byteorder == ID3_UTF16_BYTEORDER_ANY) + size += id3_utf16_put(ptr, 0xfeff, byteorder); + + while (*ucs4) { + switch (id3_utf16_encodechar(out = utf16, *ucs4++)) { + case 2: size += id3_utf16_put(ptr, *out++, byteorder); + case 1: size += id3_utf16_put(ptr, *out++, byteorder); + case 0: break; + } + } + + if (terminate) + size += id3_utf16_put(ptr, 0, byteorder); + + return size; +} + +/* + * NAME: utf16->deserialize() + * DESCRIPTION: deserialize a ucs4 string using utf16 encoding + */ +id3_ucs4_t *id3_utf16_deserialize(id3_byte_t const **ptr, id3_length_t length, + enum id3_utf16_byteorder byteorder) +{ + id3_byte_t const *end; + id3_utf16_t *utf16ptr, *utf16; + id3_ucs4_t *ucs4; + + end = *ptr + (length & ~1); + + utf16 = malloc((length / 2 + 1) * sizeof(*utf16)); + if (utf16 == 0) + return 0; + + if (byteorder == ID3_UTF16_BYTEORDER_ANY && end - *ptr > 0) { + switch (((*ptr)[0] << 8) | + ((*ptr)[1] << 0)) { + case 0xfeff: + byteorder = ID3_UTF16_BYTEORDER_BE; + *ptr += 2; + break; + + case 0xfffe: + byteorder = ID3_UTF16_BYTEORDER_LE; + *ptr += 2; + break; + } + } + + utf16ptr = utf16; + while (end - *ptr > 0 && (*utf16ptr = id3_utf16_get(ptr, byteorder))) + ++utf16ptr; + + *utf16ptr = 0; + + ucs4 = malloc((id3_utf16_length(utf16) + 1) * sizeof(*ucs4)); + if (ucs4) + id3_utf16_decode(utf16, ucs4); + + free(utf16); + + return ucs4; +} diff --git a/libid3tag/utf16.h b/libid3tag/utf16.h new file mode 100644 index 0000000..b7be49c --- /dev/null +++ b/libid3tag/utf16.h @@ -0,0 +1,51 @@ +/* + * libid3tag - ID3 tag manipulation library + * Copyright (C) 2000-2004 Underbit Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: utf16.h,v 1.8 2004/01/23 09:41:32 rob Exp $ + */ + +# ifndef LIBID3TAG_UTF16_H +# define LIBID3TAG_UTF16_H + +# include "id3tag.h" + +enum id3_utf16_byteorder { + ID3_UTF16_BYTEORDER_ANY, + ID3_UTF16_BYTEORDER_BE, + ID3_UTF16_BYTEORDER_LE +}; + +id3_length_t id3_utf16_length(id3_utf16_t const *); +id3_length_t id3_utf16_size(id3_utf16_t const *); + +id3_length_t id3_utf16_decodechar(id3_utf16_t const *, id3_ucs4_t *); +id3_length_t id3_utf16_encodechar(id3_utf16_t *, id3_ucs4_t); + +void id3_utf16_decode(id3_utf16_t const *, id3_ucs4_t *); +void id3_utf16_encode(id3_utf16_t *, id3_ucs4_t const *); + +id3_length_t id3_utf16_put(id3_byte_t **, id3_utf16_t, + enum id3_utf16_byteorder); +id3_utf16_t id3_utf16_get(id3_byte_t const **, enum id3_utf16_byteorder); + +id3_length_t id3_utf16_serialize(id3_byte_t **, id3_ucs4_t const *, + enum id3_utf16_byteorder, int); +id3_ucs4_t *id3_utf16_deserialize(id3_byte_t const **, id3_length_t, + enum id3_utf16_byteorder); + +# endif diff --git a/libid3tag/utf8.c b/libid3tag/utf8.c new file mode 100644 index 0000000..4d8649a --- /dev/null +++ b/libid3tag/utf8.c @@ -0,0 +1,365 @@ +/* + * libid3tag - ID3 tag manipulation library + * Copyright (C) 2000-2004 Underbit Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: utf8.c,v 1.9 2004/01/23 09:41:32 rob Exp $ + */ + +# ifdef HAVE_CONFIG_H +# include "config.h" +# endif + +# include "global.h" + +# include + +# include "id3tag.h" +# include "utf8.h" +# include "ucs4.h" + +/* + * NAME: utf8->length() + * DESCRIPTION: return the number of ucs4 chars represented by a utf8 string + */ +id3_length_t id3_utf8_length(id3_utf8_t const *utf8) +{ + id3_length_t length = 0; + + while (*utf8) { + if ((utf8[0] & 0x80) == 0x00) + ++length; + else if ((utf8[0] & 0xe0) == 0xc0 && + (utf8[1] & 0xc0) == 0x80) { + if (((utf8[0] & 0x1fL) << 6) >= 0x00000080L) { + ++length; + utf8 += 1; + } + } + else if ((utf8[0] & 0xf0) == 0xe0 && + (utf8[1] & 0xc0) == 0x80 && + (utf8[2] & 0xc0) == 0x80) { + if ((((utf8[0] & 0x0fL) << 12) | + ((utf8[1] & 0x3fL) << 6)) >= 0x00000800L) { + ++length; + utf8 += 2; + } + } + else if ((utf8[0] & 0xf8) == 0xf0 && + (utf8[1] & 0xc0) == 0x80 && + (utf8[2] & 0xc0) == 0x80 && + (utf8[3] & 0xc0) == 0x80) { + if ((((utf8[0] & 0x07L) << 18) | + ((utf8[1] & 0x3fL) << 12)) >= 0x00010000L) { + ++length; + utf8 += 3; + } + } + else if ((utf8[0] & 0xfc) == 0xf8 && + (utf8[1] & 0xc0) == 0x80 && + (utf8[2] & 0xc0) == 0x80 && + (utf8[3] & 0xc0) == 0x80 && + (utf8[4] & 0xc0) == 0x80) { + if ((((utf8[0] & 0x03L) << 24) | + ((utf8[0] & 0x3fL) << 18)) >= 0x00200000L) { + ++length; + utf8 += 4; + } + } + else if ((utf8[0] & 0xfe) == 0xfc && + (utf8[1] & 0xc0) == 0x80 && + (utf8[2] & 0xc0) == 0x80 && + (utf8[3] & 0xc0) == 0x80 && + (utf8[4] & 0xc0) == 0x80 && + (utf8[5] & 0xc0) == 0x80) { + if ((((utf8[0] & 0x01L) << 30) | + ((utf8[0] & 0x3fL) << 24)) >= 0x04000000L) { + ++length; + utf8 += 5; + } + } + + ++utf8; + } + + return length; +} + +/* + * NAME: utf8->size() + * DESCRIPTION: return the encoding size of a utf8 string + */ +id3_length_t id3_utf8_size(id3_utf8_t const *utf8) +{ + id3_utf8_t const *ptr = utf8; + + while (*ptr) + ++ptr; + + return ptr - utf8 + 1; +} + +/* + * NAME: utf8->ucs4duplicate() + * DESCRIPTION: duplicate and decode a utf8 string into ucs4 + */ +id3_ucs4_t *id3_utf8_ucs4duplicate(id3_utf8_t const *utf8) +{ + id3_ucs4_t *ucs4; + + ucs4 = malloc((id3_utf8_length(utf8) + 1) * sizeof(*ucs4)); + if (ucs4) + id3_utf8_decode(utf8, ucs4); + + return release(ucs4); +} + +/* + * NAME: utf8->decodechar() + * DESCRIPTION: decode a series of utf8 chars into a single ucs4 char + */ +id3_length_t id3_utf8_decodechar(id3_utf8_t const *utf8, id3_ucs4_t *ucs4) +{ + id3_utf8_t const *start = utf8; + + while (1) { + if ((utf8[0] & 0x80) == 0x00) { + *ucs4 = utf8[0]; + return utf8 - start + 1; + } + else if ((utf8[0] & 0xe0) == 0xc0 && + (utf8[1] & 0xc0) == 0x80) { + *ucs4 = + ((utf8[0] & 0x1fL) << 6) | + ((utf8[1] & 0x3fL) << 0); + if (*ucs4 >= 0x00000080L) + return utf8 - start + 2; + } + else if ((utf8[0] & 0xf0) == 0xe0 && + (utf8[1] & 0xc0) == 0x80 && + (utf8[2] & 0xc0) == 0x80) { + *ucs4 = + ((utf8[0] & 0x0fL) << 12) | + ((utf8[1] & 0x3fL) << 6) | + ((utf8[2] & 0x3fL) << 0); + if (*ucs4 >= 0x00000800L) + return utf8 - start + 3; + } + else if ((utf8[0] & 0xf8) == 0xf0 && + (utf8[1] & 0xc0) == 0x80 && + (utf8[2] & 0xc0) == 0x80 && + (utf8[3] & 0xc0) == 0x80) { + *ucs4 = + ((utf8[0] & 0x07L) << 18) | + ((utf8[1] & 0x3fL) << 12) | + ((utf8[2] & 0x3fL) << 6) | + ((utf8[3] & 0x3fL) << 0); + if (*ucs4 >= 0x00010000L) + return utf8 - start + 4; + } + else if ((utf8[0] & 0xfc) == 0xf8 && + (utf8[1] & 0xc0) == 0x80 && + (utf8[2] & 0xc0) == 0x80 && + (utf8[3] & 0xc0) == 0x80 && + (utf8[4] & 0xc0) == 0x80) { + *ucs4 = + ((utf8[0] & 0x03L) << 24) | + ((utf8[1] & 0x3fL) << 18) | + ((utf8[2] & 0x3fL) << 12) | + ((utf8[3] & 0x3fL) << 6) | + ((utf8[4] & 0x3fL) << 0); + if (*ucs4 >= 0x00200000L) + return utf8 - start + 5; + } + else if ((utf8[0] & 0xfe) == 0xfc && + (utf8[1] & 0xc0) == 0x80 && + (utf8[2] & 0xc0) == 0x80 && + (utf8[3] & 0xc0) == 0x80 && + (utf8[4] & 0xc0) == 0x80 && + (utf8[5] & 0xc0) == 0x80) { + *ucs4 = + ((utf8[0] & 0x01L) << 30) | + ((utf8[1] & 0x3fL) << 24) | + ((utf8[2] & 0x3fL) << 18) | + ((utf8[3] & 0x3fL) << 12) | + ((utf8[4] & 0x3fL) << 6) | + ((utf8[5] & 0x3fL) << 0); + if (*ucs4 >= 0x04000000L) + return utf8 - start + 6; + } + + ++utf8; + } +} + +/* + * NAME: utf8->encodechar() + * DESCRIPTION: encode a single ucs4 char into a series of up to 6 utf8 chars + */ +id3_length_t id3_utf8_encodechar(id3_utf8_t *utf8, id3_ucs4_t ucs4) +{ + if (ucs4 <= 0x0000007fL) { + utf8[0] = ucs4; + + return 1; + } + else if (ucs4 <= 0x000007ffL) { + utf8[0] = 0xc0 | ((ucs4 >> 6) & 0x1f); + utf8[1] = 0x80 | ((ucs4 >> 0) & 0x3f); + + return 2; + } + else if (ucs4 <= 0x0000ffffL) { + utf8[0] = 0xe0 | ((ucs4 >> 12) & 0x0f); + utf8[1] = 0x80 | ((ucs4 >> 6) & 0x3f); + utf8[2] = 0x80 | ((ucs4 >> 0) & 0x3f); + + return 3; + } + else if (ucs4 <= 0x001fffffL) { + utf8[0] = 0xf0 | ((ucs4 >> 18) & 0x07); + utf8[1] = 0x80 | ((ucs4 >> 12) & 0x3f); + utf8[2] = 0x80 | ((ucs4 >> 6) & 0x3f); + utf8[3] = 0x80 | ((ucs4 >> 0) & 0x3f); + + return 4; + } + else if (ucs4 <= 0x03ffffffL) { + utf8[0] = 0xf8 | ((ucs4 >> 24) & 0x03); + utf8[1] = 0x80 | ((ucs4 >> 18) & 0x3f); + utf8[2] = 0x80 | ((ucs4 >> 12) & 0x3f); + utf8[3] = 0x80 | ((ucs4 >> 6) & 0x3f); + utf8[4] = 0x80 | ((ucs4 >> 0) & 0x3f); + + return 5; + } + else if (ucs4 <= 0x7fffffffL) { + utf8[0] = 0xfc | ((ucs4 >> 30) & 0x01); + utf8[1] = 0x80 | ((ucs4 >> 24) & 0x3f); + utf8[2] = 0x80 | ((ucs4 >> 18) & 0x3f); + utf8[3] = 0x80 | ((ucs4 >> 12) & 0x3f); + utf8[4] = 0x80 | ((ucs4 >> 6) & 0x3f); + utf8[5] = 0x80 | ((ucs4 >> 0) & 0x3f); + + return 6; + } + + /* default */ + + return id3_utf8_encodechar(utf8, ID3_UCS4_REPLACEMENTCHAR); +} + +/* + * NAME: utf8->decode() + * DESCRIPTION: decode a complete utf8 string into a ucs4 string + */ +void id3_utf8_decode(id3_utf8_t const *utf8, id3_ucs4_t *ucs4) +{ + do + utf8 += id3_utf8_decodechar(utf8, ucs4); + while (*ucs4++); +} + +/* + * NAME: utf8->encode() + * DESCRIPTION: encode a complete ucs4 string into a utf8 string + */ +void id3_utf8_encode(id3_utf8_t *utf8, id3_ucs4_t const *ucs4) +{ + do + utf8 += id3_utf8_encodechar(utf8, *ucs4); + while (*ucs4++); +} + +/* + * NAME: utf8->put() + * DESCRIPTION: serialize a single utf8 character + */ +id3_length_t id3_utf8_put(id3_byte_t **ptr, id3_utf8_t utf8) +{ + if (ptr) + *(*ptr)++ = utf8; + + return 1; +} + +/* + * NAME: utf8->get() + * DESCRIPTION: deserialize a single utf8 character + */ +id3_utf8_t id3_utf8_get(id3_byte_t const **ptr) +{ + return *(*ptr)++; +} + +/* + * NAME: utf8->serialize() + * DESCRIPTION: serialize a ucs4 string using utf8 encoding + */ +id3_length_t id3_utf8_serialize(id3_byte_t **ptr, id3_ucs4_t const *ucs4, + int terminate) +{ + id3_length_t size = 0; + id3_utf8_t utf8[6], *out; + + while (*ucs4) { + switch (id3_utf8_encodechar(out = utf8, *ucs4++)) { + case 6: size += id3_utf8_put(ptr, *out++); + case 5: size += id3_utf8_put(ptr, *out++); + case 4: size += id3_utf8_put(ptr, *out++); + case 3: size += id3_utf8_put(ptr, *out++); + case 2: size += id3_utf8_put(ptr, *out++); + case 1: size += id3_utf8_put(ptr, *out++); + case 0: break; + } + } + + if (terminate) + size += id3_utf8_put(ptr, 0); + + return size; +} + +/* + * NAME: utf8->deserialize() + * DESCRIPTION: deserialize a ucs4 string using utf8 encoding + */ +id3_ucs4_t *id3_utf8_deserialize(id3_byte_t const **ptr, id3_length_t length) +{ + id3_byte_t const *end; + id3_utf8_t *utf8ptr, *utf8; + id3_ucs4_t *ucs4; + + end = *ptr + length; + + utf8 = malloc((length + 1) * sizeof(*utf8)); + if (utf8 == 0) + return 0; + + utf8ptr = utf8; + while (end - *ptr > 0 && (*utf8ptr = id3_utf8_get(ptr))) + ++utf8ptr; + + *utf8ptr = 0; + + ucs4 = malloc((id3_utf8_length(utf8) + 1) * sizeof(*ucs4)); + if (ucs4) + id3_utf8_decode(utf8, ucs4); + + free(utf8); + + return ucs4; +} diff --git a/libid3tag/utf8.h b/libid3tag/utf8.h new file mode 100644 index 0000000..572bb2a --- /dev/null +++ b/libid3tag/utf8.h @@ -0,0 +1,42 @@ +/* + * libid3tag - ID3 tag manipulation library + * Copyright (C) 2000-2004 Underbit Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: utf8.h,v 1.7 2004/01/23 09:41:32 rob Exp $ + */ + +# ifndef LIBID3TAG_UTF8_H +# define LIBID3TAG_UTF8_H + +# include "id3tag.h" + +id3_length_t id3_utf8_length(id3_utf8_t const *); +id3_length_t id3_utf8_size(id3_utf8_t const *); + +id3_length_t id3_utf8_decodechar(id3_utf8_t const *, id3_ucs4_t *); +id3_length_t id3_utf8_encodechar(id3_utf8_t *, id3_ucs4_t); + +void id3_utf8_decode(id3_utf8_t const *, id3_ucs4_t *); +void id3_utf8_encode(id3_utf8_t *, id3_ucs4_t const *); + +id3_length_t id3_utf8_put(id3_byte_t **, id3_utf8_t); +id3_utf8_t id3_utf8_get(id3_byte_t const **); + +id3_length_t id3_utf8_serialize(id3_byte_t **, id3_ucs4_t const *, int); +id3_ucs4_t *id3_utf8_deserialize(id3_byte_t const **, id3_length_t); + +# endif diff --git a/libid3tag/util.c b/libid3tag/util.c new file mode 100644 index 0000000..61ccccf --- /dev/null +++ b/libid3tag/util.c @@ -0,0 +1,147 @@ +/* + * libid3tag - ID3 tag manipulation library + * Copyright (C) 2000-2004 Underbit Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: util.c,v 1.9 2004/01/23 09:41:32 rob Exp $ + */ + +# ifdef HAVE_CONFIG_H +# include "config.h" +# endif + +# include "global.h" + +# include +# include + +# include "id3tag.h" +# include "util.h" + +/* + * NAME: util->unsynchronise() + * DESCRIPTION: perform (in-place) unsynchronisation + */ +id3_length_t id3_util_unsynchronise(id3_byte_t *data, id3_length_t length) +{ + id3_length_t bytes = 0, count; + id3_byte_t *end = data + length; + id3_byte_t const *ptr; + + if (length == 0) + return 0; + + for (ptr = data; ptr < end - 1; ++ptr) { + if (ptr[0] == 0xff && (ptr[1] == 0x00 || (ptr[1] & 0xe0) == 0xe0)) + ++bytes; + } + + if (bytes) { + ptr = end; + end += bytes; + + *--end = *--ptr; + + for (count = bytes; count; *--end = *--ptr) { + if (ptr[-1] == 0xff && (ptr[0] == 0x00 || (ptr[0] & 0xe0) == 0xe0)) { + *--end = 0x00; + --count; + } + } + } + + return length + bytes; +} + +/* + * NAME: util->deunsynchronise() + * DESCRIPTION: undo unsynchronisation (in-place) + */ +id3_length_t id3_util_deunsynchronise(id3_byte_t *data, id3_length_t length) +{ + id3_byte_t const *old, *end = data + length; + id3_byte_t *new; + + if (length == 0) + return 0; + + for (old = new = data; old < end - 1; ++old) { + *new++ = *old; + if (old[0] == 0xff && old[1] == 0x00) + ++old; + } + + *new++ = *old; + + return new - data; +} + +/* + * NAME: util->compress() + * DESCRIPTION: perform zlib deflate method compression + */ +id3_byte_t *id3_util_compress(id3_byte_t const *data, id3_length_t length, + id3_length_t *newlength) +{ + id3_byte_t *compressed; + + *newlength = length + 12; + *newlength += *newlength / 1000; + + compressed = malloc(*newlength); + if (compressed) { + if (compress2(compressed, newlength, data, length, + Z_BEST_COMPRESSION) != Z_OK || + *newlength >= length) { + free(compressed); + compressed = 0; + } + else { + id3_byte_t *resized; + + resized = realloc(compressed, *newlength ? *newlength : 1); + if (resized) + compressed = resized; + } + } + + return compressed; +} + +/* + * NAME: util->decompress() + * DESCRIPTION: undo zlib deflate method compression + */ +id3_byte_t *id3_util_decompress(id3_byte_t const *data, id3_length_t length, + id3_length_t newlength) +{ + id3_byte_t *decompressed; + + decompressed = malloc(newlength ? newlength : 1); + if (decompressed) { + id3_length_t size; + + size = newlength; + + if (uncompress(decompressed, &size, data, length) != Z_OK || + size != newlength) { + free(decompressed); + decompressed = 0; + } + } + + return decompressed; +} diff --git a/libid3tag/util.h b/libid3tag/util.h new file mode 100644 index 0000000..4b895d2 --- /dev/null +++ b/libid3tag/util.h @@ -0,0 +1,35 @@ +/* + * libid3tag - ID3 tag manipulation library + * Copyright (C) 2000-2004 Underbit Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: util.h,v 1.6 2004/01/23 09:41:32 rob Exp $ + */ + +# ifndef LIBID3TAG_UTIL_H +# define LIBID3TAG_UTIL_H + +# include "id3tag.h" + +id3_length_t id3_util_unsynchronise(id3_byte_t *, id3_length_t); +id3_length_t id3_util_deunsynchronise(id3_byte_t *, id3_length_t); + +id3_byte_t *id3_util_compress(id3_byte_t const *, id3_length_t, + id3_length_t *); +id3_byte_t *id3_util_decompress(id3_byte_t const *, id3_length_t, + id3_length_t); + +# endif diff --git a/libid3tag/version.c b/libid3tag/version.c new file mode 100644 index 0000000..d54b80a --- /dev/null +++ b/libid3tag/version.c @@ -0,0 +1,45 @@ +/* + * libid3tag - ID3 tag manipulation library + * Copyright (C) 2000-2004 Underbit Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: version.c,v 1.7 2004/01/23 09:41:32 rob Exp $ + */ + +# ifdef HAVE_CONFIG_H +# include "config.h" +# endif + +# include "global.h" + +# include "id3tag.h" +# include "version.h" + +char const id3_version[] = "ID3 Tag Library " ID3_VERSION; +char const id3_copyright[] = "Copyright (C) " ID3_PUBLISHYEAR " " ID3_AUTHOR; +char const id3_author[] = ID3_AUTHOR " <" ID3_EMAIL ">"; + +char const id3_build[] = "" +# if defined(DEBUG) + "DEBUG " +# elif defined(NDEBUG) + "NDEBUG " +# endif + +# if defined(EXPERIMENTAL) + "EXPERIMENTAL " +# endif +; diff --git a/libid3tag/version.h b/libid3tag/version.h new file mode 100644 index 0000000..5eaa11f --- /dev/null +++ b/libid3tag/version.h @@ -0,0 +1,25 @@ +/* + * libid3tag - ID3 tag manipulation library + * Copyright (C) 2000-2004 Underbit Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: version.h,v 1.7 2004/01/23 09:41:32 rob Exp $ + */ + +# ifndef LIBID3TAG_VERSION_H +# define LIBID3TAG_VERSION_H + +# endif diff --git a/libmpg123/dxhead.c b/libmpg123/dxhead.c new file mode 100644 index 0000000..21b5ceb --- /dev/null +++ b/libmpg123/dxhead.c @@ -0,0 +1,165 @@ +/* ---- DXhead.c -------------------------------------------- + * + * + * decoder MPEG Layer III handle Xing header + * + * mod 12/7/98 add vbr scale + * + * Copyright 1998 Xing Technology Corp. + * ----------------------------------------------------------- + */ +#include +#include +#include +#include +#include "dxhead.h" + +/* 4 Xing + * 4 flags + * 4 frames + * 4 bytes + * 100 toc + */ + +/*-------------------------------------------------------------*/ +static int ExtractI4(unsigned char *buf) +{ + int x; + + /* big endian extract */ + x = buf[0]; + x <<= 8; + x |= buf[1]; + x <<= 8; + x |= buf[2]; + x <<= 8; + x |= buf[3]; + return x; +} + +/*-------------------------------------------------------------*/ +int mpg123_get_xing_header(XHEADDATA * X, unsigned char *buf) +{ + int i, head_flags; + int h_id, h_mode, h_sr_index; + static int sr_table[4] = + {44100, 48000, 32000, 99999}; + + /* get Xing header data */ + X->flags = 0; /* clear to null incase fail */ + + /* get selected MPEG header data */ + h_id = (buf[1] >> 3) & 1; + h_sr_index = (buf[2] >> 2) & 3; + h_mode = (buf[3] >> 6) & 3; + + + + /* determine offset of header */ + if (h_id) + { /* mpeg1 */ + if (h_mode != 3) + buf += (32 + 4); + else + buf += (17 + 4); + } + else + { /* mpeg2 */ + if (h_mode != 3) + buf += (17 + 4); + else + buf += (9 + 4); + } + + if (buf[0] != 'X') + return 0; /* fail */ + if (buf[1] != 'i') + return 0; /* header not found */ + if (buf[2] != 'n') + return 0; + if (buf[3] != 'g') + return 0; + buf += 4; + + X->h_id = h_id; + X->samprate = sr_table[h_sr_index]; + if (h_id == 0) + X->samprate >>= 1; + head_flags = X->flags = ExtractI4(buf); + buf += 4; /* get flags */ + + if (head_flags & FRAMES_FLAG) + { + X->frames = ExtractI4(buf); + buf += 4; + } + if (head_flags & BYTES_FLAG) + { + X->bytes = ExtractI4(buf); + buf += 4; + } + + if (head_flags & TOC_FLAG) + { + if (X->toc != NULL) + { + for (i = 0; i < 100; i++) + X->toc[i] = buf[i]; + } + buf += 100; + } + + X->vbr_scale = -1; + if (head_flags & VBR_SCALE_FLAG) + { + X->vbr_scale = ExtractI4(buf); + buf += 4; + } + + +/*if( X->toc != NULL ) { + *for(i=0;i<100;i++) { + * if( (i%10) == 0 ) printf("\n"); + * printf(" %3d", (int)(X->toc[i])); + *} + *} + */ + + return 1; /* success */ +} + +/*-------------------------------------------------------------*/ +int mpg123_seek_point(unsigned char TOC[100], int file_bytes, float percent) +{ + + /* interpolate in TOC to get file seek point in bytes */ + int a, seekpoint; + float fa, fb, fx; + + if (percent < 0.0f) + percent = 0.0f; + + if (percent > 100.0f) + percent = 100.0f; + + a = (int) percent; + + if (a > 99) + a = 99; + fa = TOC[a]; + + if (a < 99) + { + fb = TOC[a + 1]; + } + else + { + fb = 256.0f; + } + + fx = fa + (fb - fa) * (percent - a); + seekpoint = (int) ((1.0f / 256.0f) * fx * file_bytes); + return seekpoint; +} + +/*-------------------------------------------------------------*/ diff --git a/libmpg123/dxhead.h b/libmpg123/dxhead.h new file mode 100644 index 0000000..bcbc66a --- /dev/null +++ b/libmpg123/dxhead.h @@ -0,0 +1,60 @@ +/*---- DXhead.h -------------------------------------------- + +decoder MPEG Layer III +handle Xing header + +Copyright 1998 Xing Technology Corp. +-----------------------------------------------------------*/ +/* A Xing header may be present in the ancillary + * data field of the first frame of an mp3 bitstream + * The Xing header (optionally) contains + * frames total number of audio frames in the bitstream + * bytes total number of bytes in the bitstream + * toc table of contents + + * toc (table of contents) gives seek points + * for random access + * the ith entry determines the seek point for + * i-percent duration + * seek point in bytes = (toc[i]/256.0) * total_bitstream_bytes + * e.g. half duration seek point = (toc[50]/256.0) * total_bitstream_bytes + */ + +#define FRAMES_FLAG 0x0001 +#define BYTES_FLAG 0x0002 +#define TOC_FLAG 0x0004 +#define VBR_SCALE_FLAG 0x0008 + +#define FRAMES_AND_BYTES (FRAMES_FLAG | BYTES_FLAG) + +/* structure to receive extracted header + * toc may be NULL + */ +typedef struct +{ + int h_id; /* from MPEG header, 0=MPEG2, 1=MPEG1 */ + int samprate; /* determined from MPEG header */ + int flags; /* from Xing header data */ + int frames; /* total bit stream frames from Xing header data */ + int bytes; /* total bit stream bytes from Xing header data */ + int vbr_scale; /* encoded vbr scale from Xing header data */ + unsigned char *toc; /* pointer to unsigned char toc_buffer[100] */ + /* may be NULL if toc not desired */ +} +XHEADDATA; + +int mpg123_get_xing_header(XHEADDATA * X, unsigned char *buf); + +/* return 0=fail, 1=success + * X structure to receive header data (output) + * buf bitstream input + */ + +int mpg123_seek_point(unsigned char TOC[100], int file_bytes, float percent); + +/* return seekpoint in bytes (may be at eof if percent=100.0) + * TOC = table of contents from Xing header + * file_bytes = number of bytes in mp3 file + * percent = play time percentage of total playtime. May be + * fractional (e.g. 87.245) + */ diff --git a/libmpg123/getbits.c b/libmpg123/getbits.c new file mode 100644 index 0000000..a071b5e --- /dev/null +++ b/libmpg123/getbits.c @@ -0,0 +1,126 @@ +#include "mpg123.h" + +#if 0 +static void check_buffer_range(int size) +{ + int pos = (bsi.wordpointer-bsbuf) + (size >> 3); + + if( pos >= fsizeold) { + fprintf(stderr, "Pointer out of range (%d,%d)!\n", pos, fsizeold); + } +} +#endif + +void mpg123_backbits(int number_of_bits) +{ + bsi.bitindex -= number_of_bits; + bsi.wordpointer += (bsi.bitindex>>3); + bsi.bitindex &= 0x7; +} + +int mpg123_getbitoffset(void) +{ + return (-bsi.bitindex)&0x7; +} + +int mpg123_getbyte(void) +{ +#ifdef DEBUG_GETBITS + if(bsi.bitindex) + fprintf(stderr,"getbyte called unsynched!\n"); +#endif + return *bsi.wordpointer++; +} + +unsigned int mpg123_getbits(int number_of_bits) +{ + unsigned long rval; + +#ifdef DEBUG_GETBITS + fprintf(stderr, "g%d", number_of_bits); +#endif + + if(!number_of_bits) + return 0; + +#if 0 + check_buffer_range(number_of_bits + bsi.bitindex); +#endif + + { + rval = bsi.wordpointer[0]; + rval <<= 8; + rval |= bsi.wordpointer[1]; + rval <<= 8; + rval |= bsi.wordpointer[2]; + + rval <<= bsi.bitindex; + rval &= 0xffffff; + + bsi.bitindex += number_of_bits; + + rval >>= (24-number_of_bits); + + bsi.wordpointer += (bsi.bitindex >> 3); + bsi.bitindex &= 7; + } + +#ifdef DEBUG_GETBITS + fprintf(stderr,":%x ",rval); +#endif + + return rval; +} + +unsigned int mpg123_getbits_fast(int number_of_bits) +{ + unsigned int rval; +#ifdef DEBUG_GETBITS + fprintf(stderr,"g%d",number_of_bits); +#endif + +#if 0 + check_buffer_range(number_of_bits+bsi.bitindex); +#endif + + rval = (unsigned char) (bsi.wordpointer[0] << bsi.bitindex); + rval |= ((unsigned int) bsi.wordpointer[1] << bsi.bitindex) >> 8; + rval <<= number_of_bits; + rval >>= 8; + + bsi.bitindex += number_of_bits; + + bsi.wordpointer += (bsi.bitindex >> 3); + bsi.bitindex &= 7; + +#ifdef DEBUG_GETBITS + fprintf(stderr,":%x ",rval); +#endif + return rval; +} + +unsigned int mpg123_get1bit(void) +{ + unsigned char rval; + +#ifdef DEBUG_GETBITS + fprintf(stderr,"g%d",1); +#endif + +#if 0 + check_buffer_range(1+bsi.bitindex); +#endif + + rval = *bsi.wordpointer << bsi.bitindex; + + bsi.bitindex++; + bsi.wordpointer += (bsi.bitindex >> 3); + bsi.bitindex &= 7; + +#ifdef DEBUG_GETBITS + fprintf(stderr,":%d ",rval >> 7); +#endif + + return rval>>7; +} + diff --git a/libmpg123/getbits.h b/libmpg123/getbits.h new file mode 100644 index 0000000..1e5cf65 --- /dev/null +++ b/libmpg123/getbits.h @@ -0,0 +1,46 @@ + +/* + * This does the same as getbits.c but with defines to + * force inlining + */ + +#define mpg123_backbits(nob) \ +do { \ + bsi.bitindex -= nob; \ + bsi.wordpointer += (bsi.bitindex >> 3); \ + bsi.bitindex &= 0x7; \ +} while (0) + +#define mpg123_getbitoffset() ((-bsi.bitindex) & 0x7) +#define mpg123_getbyte() (*bsi.wordpointer++) + +#define mpg123_getbits(nob) \ + (rval = bsi.wordpointer[0], \ + rval <<= 8, \ + rval |= bsi.wordpointer[1], \ + rval <<= 8, \ + rval |= bsi.wordpointer[2], \ + rval <<= bsi.bitindex, \ + rval &= 0xffffff, \ + bsi.bitindex += (nob), \ + rval >>= (24-(nob)), \ + bsi.wordpointer += (bsi.bitindex>>3), \ + bsi.bitindex &= 7, \ + rval) + +#define mpg123_getbits_fast(nob) \ + (rval = (unsigned char) (bsi.wordpointer[0] << bsi.bitindex), \ + rval |= ((unsigned long) bsi.wordpointer[1] << bsi.bitindex) >> 8, \ + rval <<= (nob), \ + rval >>= 8, \ + bsi.bitindex += (nob), \ + bsi.wordpointer += (bsi.bitindex >> 3), \ + bsi.bitindex &= 7, \ + rval) + +#define mpg123_get1bit() \ + (rval_uc = *bsi.wordpointer << bsi.bitindex, \ + bsi.bitindex++, \ + bsi.wordpointer += (bsi.bitindex>>3), \ + bsi.bitindex &= 7, \ + rval_uc >> 7) diff --git a/libmpg123/huffman.h b/libmpg123/huffman.h new file mode 100644 index 0000000..83a230b --- /dev/null +++ b/libmpg123/huffman.h @@ -0,0 +1,329 @@ + +/* + * huffman tables ... recalcualted to work with my optimzed + * decoder scheme (MH) + * + * probably we could save a few bytes of memory, because the + * smaller tables are often the part of a bigger table + */ + +struct newhuff +{ + unsigned int linbits; + short *table; +}; + +static short tab0[] = +{ + 0 +}; + +static short tab1[] = +{ + -5, -3, -1, 17, 1, 16, 0 +}; + +static short tab2[] = +{ + -15, -11, -9, -5, -3, -1, 34, 2, 18, -1, 33, 32, 17, -1, 1, + 16, 0 +}; + +static short tab3[] = +{ + -13, -11, -9, -5, -3, -1, 34, 2, 18, -1, 33, 32, 16, 17, -1, + 1, 0 +}; + +static short tab5[] = +{ + -29, -25, -23, -15, -7, -5, -3, -1, 51, 35, 50, 49, -3, -1, 19, + 3, -1, 48, 34, -3, -1, 18, 33, -1, 2, 32, 17, -1, 1, 16, + 0 +}; + +static short tab6[] = +{ + -25, -19, -13, -9, -5, -3, -1, 51, 3, 35, -1, 50, 48, -1, 19, + 49, -3, -1, 34, 2, 18, -3, -1, 33, 32, 1, -1, 17, -1, 16, + 0 +}; + +static short tab7[] = +{ + -69, -65, -57, -39, -29, -17, -11, -7, -3, -1, 85, 69, -1, 84, 83, + -1, 53, 68, -3, -1, 37, 82, 21, -5, -1, 81, -1, 5, 52, -1, + 80, -1, 67, 51, -5, -3, -1, 36, 66, 20, -1, 65, 64, -11, -7, + -3, -1, 4, 35, -1, 50, 3, -1, 19, 49, -3, -1, 48, 34, 18, + -5, -1, 33, -1, 2, 32, 17, -1, 1, 16, 0 +}; + +static short tab8[] = +{ + -65, -63, -59, -45, -31, -19, -13, -7, -5, -3, -1, 85, 84, 69, 83, + -3, -1, 53, 68, 37, -3, -1, 82, 5, 21, -5, -1, 81, -1, 52, + 67, -3, -1, 80, 51, 36, -5, -3, -1, 66, 20, 65, -3, -1, 4, + 64, -1, 35, 50, -9, -7, -3, -1, 19, 49, -1, 3, 48, 34, -1, + 2, 32, -1, 18, 33, 17, -3, -1, 1, 16, 0 +}; + +static short tab9[] = +{ + -63, -53, -41, -29, -19, -11, -5, -3, -1, 85, 69, 53, -1, 83, -1, + 84, 5, -3, -1, 68, 37, -1, 82, 21, -3, -1, 81, 52, -1, 67, + -1, 80, 4, -7, -3, -1, 36, 66, -1, 51, 64, -1, 20, 65, -5, + -3, -1, 35, 50, 19, -1, 49, -1, 3, 48, -5, -3, -1, 34, 2, + 18, -1, 33, 32, -3, -1, 17, 1, -1, 16, 0 +}; + +static short tab10[] = +{ + -125, -121, -111, -83, -55, -35, -21, -13, -7, -3, -1, 119, 103, -1, 118, + 87, -3, -1, 117, 102, 71, -3, -1, 116, 86, -1, 101, 55, -9, -3, + -1, 115, 70, -3, -1, 85, 84, 99, -1, 39, 114, -11, -5, -3, -1, + 100, 7, 112, -1, 98, -1, 69, 53, -5, -1, 6, -1, 83, 68, 23, + -17, -5, -1, 113, -1, 54, 38, -5, -3, -1, 37, 82, 21, -1, 81, + -1, 52, 67, -3, -1, 22, 97, -1, 96, -1, 5, 80, -19, -11, -7, + -3, -1, 36, 66, -1, 51, 4, -1, 20, 65, -3, -1, 64, 35, -1, + 50, 3, -3, -1, 19, 49, -1, 48, 34, -7, -3, -1, 18, 33, -1, + 2, 32, 17, -1, 1, 16, 0 +}; + +static short tab11[] = +{ + -121, -113, -89, -59, -43, -27, -17, -7, -3, -1, 119, 103, -1, 118, 117, + -3, -1, 102, 71, -1, 116, -1, 87, 85, -5, -3, -1, 86, 101, 55, + -1, 115, 70, -9, -7, -3, -1, 69, 84, -1, 53, 83, 39, -1, 114, + -1, 100, 7, -5, -1, 113, -1, 23, 112, -3, -1, 54, 99, -1, 96, + -1, 68, 37, -13, -7, -5, -3, -1, 82, 5, 21, 98, -3, -1, 38, + 6, 22, -5, -1, 97, -1, 81, 52, -5, -1, 80, -1, 67, 51, -1, + 36, 66, -15, -11, -7, -3, -1, 20, 65, -1, 4, 64, -1, 35, 50, + -1, 19, 49, -5, -3, -1, 3, 48, 34, 33, -5, -1, 18, -1, 2, + 32, 17, -3, -1, 1, 16, 0 +}; + +static short tab12[] = +{ + -115, -99, -73, -45, -27, -17, -9, -5, -3, -1, 119, 103, 118, -1, 87, + 117, -3, -1, 102, 71, -1, 116, 101, -3, -1, 86, 55, -3, -1, 115, + 85, 39, -7, -3, -1, 114, 70, -1, 100, 23, -5, -1, 113, -1, 7, + 112, -1, 54, 99, -13, -9, -3, -1, 69, 84, -1, 68, -1, 6, 5, + -1, 38, 98, -5, -1, 97, -1, 22, 96, -3, -1, 53, 83, -1, 37, + 82, -17, -7, -3, -1, 21, 81, -1, 52, 67, -5, -3, -1, 80, 4, + 36, -1, 66, 20, -3, -1, 51, 65, -1, 35, 50, -11, -7, -5, -3, + -1, 64, 3, 48, 19, -1, 49, 34, -1, 18, 33, -7, -5, -3, -1, + 2, 32, 0, 17, -1, 1, 16 +}; + +static short tab13[] = +{ + -509, -503, -475, -405, -333, -265, -205, -153, -115, -83, -53, -35, -21, -13, -9, + -7, -5, -3, -1, 254, 252, 253, 237, 255, -1, 239, 223, -3, -1, 238, + 207, -1, 222, 191, -9, -3, -1, 251, 206, -1, 220, -1, 175, 233, -1, + 236, 221, -9, -5, -3, -1, 250, 205, 190, -1, 235, 159, -3, -1, 249, + 234, -1, 189, 219, -17, -9, -3, -1, 143, 248, -1, 204, -1, 174, 158, + -5, -1, 142, -1, 127, 126, 247, -5, -1, 218, -1, 173, 188, -3, -1, + 203, 246, 111, -15, -7, -3, -1, 232, 95, -1, 157, 217, -3, -1, 245, + 231, -1, 172, 187, -9, -3, -1, 79, 244, -3, -1, 202, 230, 243, -1, + 63, -1, 141, 216, -21, -9, -3, -1, 47, 242, -3, -1, 110, 156, 15, + -5, -3, -1, 201, 94, 171, -3, -1, 125, 215, 78, -11, -5, -3, -1, + 200, 214, 62, -1, 185, -1, 155, 170, -1, 31, 241, -23, -13, -5, -1, + 240, -1, 186, 229, -3, -1, 228, 140, -1, 109, 227, -5, -1, 226, -1, + 46, 14, -1, 30, 225, -15, -7, -3, -1, 224, 93, -1, 213, 124, -3, + -1, 199, 77, -1, 139, 184, -7, -3, -1, 212, 154, -1, 169, 108, -1, + 198, 61, -37, -21, -9, -5, -3, -1, 211, 123, 45, -1, 210, 29, -5, + -1, 183, -1, 92, 197, -3, -1, 153, 122, 195, -7, -5, -3, -1, 167, + 151, 75, 209, -3, -1, 13, 208, -1, 138, 168, -11, -7, -3, -1, 76, + 196, -1, 107, 182, -1, 60, 44, -3, -1, 194, 91, -3, -1, 181, 137, + 28, -43, -23, -11, -5, -1, 193, -1, 152, 12, -1, 192, -1, 180, 106, + -5, -3, -1, 166, 121, 59, -1, 179, -1, 136, 90, -11, -5, -1, 43, + -1, 165, 105, -1, 164, -1, 120, 135, -5, -1, 148, -1, 119, 118, 178, + -11, -3, -1, 27, 177, -3, -1, 11, 176, -1, 150, 74, -7, -3, -1, + 58, 163, -1, 89, 149, -1, 42, 162, -47, -23, -9, -3, -1, 26, 161, + -3, -1, 10, 104, 160, -5, -3, -1, 134, 73, 147, -3, -1, 57, 88, + -1, 133, 103, -9, -3, -1, 41, 146, -3, -1, 87, 117, 56, -5, -1, + 131, -1, 102, 71, -3, -1, 116, 86, -1, 101, 115, -11, -3, -1, 25, + 145, -3, -1, 9, 144, -1, 72, 132, -7, -5, -1, 114, -1, 70, 100, + 40, -1, 130, 24, -41, -27, -11, -5, -3, -1, 55, 39, 23, -1, 113, + -1, 85, 7, -7, -3, -1, 112, 54, -1, 99, 69, -3, -1, 84, 38, + -1, 98, 53, -5, -1, 129, -1, 8, 128, -3, -1, 22, 97, -1, 6, + 96, -13, -9, -5, -3, -1, 83, 68, 37, -1, 82, 5, -1, 21, 81, + -7, -3, -1, 52, 67, -1, 80, 36, -3, -1, 66, 51, 20, -19, -11, + -5, -1, 65, -1, 4, 64, -3, -1, 35, 50, 19, -3, -1, 49, 3, + -1, 48, 34, -3, -1, 18, 33, -1, 2, 32, -3, -1, 17, 1, 16, + 0 +}; + +static short tab15[] = +{ +-495, -445, -355, -263, -183, -115, -77, -43, -27, -13, -7, -3, -1, 255, 239, + -1, 254, 223, -1, 238, -1, 253, 207, -7, -3, -1, 252, 222, -1, 237, + 191, -1, 251, -1, 206, 236, -7, -3, -1, 221, 175, -1, 250, 190, -3, + -1, 235, 205, -1, 220, 159, -15, -7, -3, -1, 249, 234, -1, 189, 219, + -3, -1, 143, 248, -1, 204, 158, -7, -3, -1, 233, 127, -1, 247, 173, + -3, -1, 218, 188, -1, 111, -1, 174, 15, -19, -11, -3, -1, 203, 246, + -3, -1, 142, 232, -1, 95, 157, -3, -1, 245, 126, -1, 231, 172, -9, + -3, -1, 202, 187, -3, -1, 217, 141, 79, -3, -1, 244, 63, -1, 243, + 216, -33, -17, -9, -3, -1, 230, 47, -1, 242, -1, 110, 240, -3, -1, + 31, 241, -1, 156, 201, -7, -3, -1, 94, 171, -1, 186, 229, -3, -1, + 125, 215, -1, 78, 228, -15, -7, -3, -1, 140, 200, -1, 62, 109, -3, + -1, 214, 227, -1, 155, 185, -7, -3, -1, 46, 170, -1, 226, 30, -5, + -1, 225, -1, 14, 224, -1, 93, 213, -45, -25, -13, -7, -3, -1, 124, + 199, -1, 77, 139, -1, 212, -1, 184, 154, -7, -3, -1, 169, 108, -1, + 198, 61, -1, 211, 210, -9, -5, -3, -1, 45, 13, 29, -1, 123, 183, + -5, -1, 209, -1, 92, 208, -1, 197, 138, -17, -7, -3, -1, 168, 76, + -1, 196, 107, -5, -1, 182, -1, 153, 12, -1, 60, 195, -9, -3, -1, + 122, 167, -1, 166, -1, 192, 11, -1, 194, -1, 44, 91, -55, -29, -15, + -7, -3, -1, 181, 28, -1, 137, 152, -3, -1, 193, 75, -1, 180, 106, + -5, -3, -1, 59, 121, 179, -3, -1, 151, 136, -1, 43, 90, -11, -5, + -1, 178, -1, 165, 27, -1, 177, -1, 176, 105, -7, -3, -1, 150, 74, + -1, 164, 120, -3, -1, 135, 58, 163, -17, -7, -3, -1, 89, 149, -1, + 42, 162, -3, -1, 26, 161, -3, -1, 10, 160, 104, -7, -3, -1, 134, + 73, -1, 148, 57, -5, -1, 147, -1, 119, 9, -1, 88, 133, -53, -29, + -13, -7, -3, -1, 41, 103, -1, 118, 146, -1, 145, -1, 25, 144, -7, + -3, -1, 72, 132, -1, 87, 117, -3, -1, 56, 131, -1, 102, 71, -7, + -3, -1, 40, 130, -1, 24, 129, -7, -3, -1, 116, 8, -1, 128, 86, + -3, -1, 101, 55, -1, 115, 70, -17, -7, -3, -1, 39, 114, -1, 100, + 23, -3, -1, 85, 113, -3, -1, 7, 112, 54, -7, -3, -1, 99, 69, + -1, 84, 38, -3, -1, 98, 22, -3, -1, 6, 96, 53, -33, -19, -9, + -5, -1, 97, -1, 83, 68, -1, 37, 82, -3, -1, 21, 81, -3, -1, + 5, 80, 52, -7, -3, -1, 67, 36, -1, 66, 51, -1, 65, -1, 20, + 4, -9, -3, -1, 35, 50, -3, -1, 64, 3, 19, -3, -1, 49, 48, + 34, -9, -7, -3, -1, 18, 33, -1, 2, 32, 17, -3, -1, 1, 16, + 0 +}; + +static short tab16[] = +{ + -509, -503, -461, -323, -103, -37, -27, -15, -7, -3, -1, 239, 254, -1, 223, + 253, -3, -1, 207, 252, -1, 191, 251, -5, -1, 175, -1, 250, 159, -3, + -1, 249, 248, 143, -7, -3, -1, 127, 247, -1, 111, 246, 255, -9, -5, + -3, -1, 95, 245, 79, -1, 244, 243, -53, -1, 240, -1, 63, -29, -19, + -13, -7, -5, -1, 206, -1, 236, 221, 222, -1, 233, -1, 234, 217, -1, + 238, -1, 237, 235, -3, -1, 190, 205, -3, -1, 220, 219, 174, -11, -5, + -1, 204, -1, 173, 218, -3, -1, 126, 172, 202, -5, -3, -1, 201, 125, + 94, 189, 242, -93, -5, -3, -1, 47, 15, 31, -1, 241, -49, -25, -13, + -5, -1, 158, -1, 188, 203, -3, -1, 142, 232, -1, 157, 231, -7, -3, + -1, 187, 141, -1, 216, 110, -1, 230, 156, -13, -7, -3, -1, 171, 186, + -1, 229, 215, -1, 78, -1, 228, 140, -3, -1, 200, 62, -1, 109, -1, + 214, 155, -19, -11, -5, -3, -1, 185, 170, 225, -1, 212, -1, 184, 169, + -5, -1, 123, -1, 183, 208, 227, -7, -3, -1, 14, 224, -1, 93, 213, + -3, -1, 124, 199, -1, 77, 139, -75, -45, -27, -13, -7, -3, -1, 154, + 108, -1, 198, 61, -3, -1, 92, 197, 13, -7, -3, -1, 138, 168, -1, + 153, 76, -3, -1, 182, 122, 60, -11, -5, -3, -1, 91, 137, 28, -1, + 192, -1, 152, 121, -1, 226, -1, 46, 30, -15, -7, -3, -1, 211, 45, + -1, 210, 209, -5, -1, 59, -1, 151, 136, 29, -7, -3, -1, 196, 107, + -1, 195, 167, -1, 44, -1, 194, 181, -23, -13, -7, -3, -1, 193, 12, + -1, 75, 180, -3, -1, 106, 166, 179, -5, -3, -1, 90, 165, 43, -1, + 178, 27, -13, -5, -1, 177, -1, 11, 176, -3, -1, 105, 150, -1, 74, + 164, -5, -3, -1, 120, 135, 163, -3, -1, 58, 89, 42, -97, -57, -33, + -19, -11, -5, -3, -1, 149, 104, 161, -3, -1, 134, 119, 148, -5, -3, + -1, 73, 87, 103, 162, -5, -1, 26, -1, 10, 160, -3, -1, 57, 147, + -1, 88, 133, -9, -3, -1, 41, 146, -3, -1, 118, 9, 25, -5, -1, + 145, -1, 144, 72, -3, -1, 132, 117, -1, 56, 131, -21, -11, -5, -3, + -1, 102, 40, 130, -3, -1, 71, 116, 24, -3, -1, 129, 128, -3, -1, + 8, 86, 55, -9, -5, -1, 115, -1, 101, 70, -1, 39, 114, -5, -3, + -1, 100, 85, 7, 23, -23, -13, -5, -1, 113, -1, 112, 54, -3, -1, + 99, 69, -1, 84, 38, -3, -1, 98, 22, -1, 97, -1, 6, 96, -9, + -5, -1, 83, -1, 53, 68, -1, 37, 82, -1, 81, -1, 21, 5, -33, + -23, -13, -7, -3, -1, 52, 67, -1, 80, 36, -3, -1, 66, 51, 20, + -5, -1, 65, -1, 4, 64, -1, 35, 50, -3, -1, 19, 49, -3, -1, + 3, 48, 34, -3, -1, 18, 33, -1, 2, 32, -3, -1, 17, 1, 16, + 0 +}; + +static short tab24[] = +{ + -451, -117, -43, -25, -15, -7, -3, -1, 239, 254, -1, 223, 253, -3, -1, + 207, 252, -1, 191, 251, -5, -1, 250, -1, 175, 159, -1, 249, 248, -9, + -5, -3, -1, 143, 127, 247, -1, 111, 246, -3, -1, 95, 245, -1, 79, + 244, -71, -7, -3, -1, 63, 243, -1, 47, 242, -5, -1, 241, -1, 31, + 240, -25, -9, -1, 15, -3, -1, 238, 222, -1, 237, 206, -7, -3, -1, + 236, 221, -1, 190, 235, -3, -1, 205, 220, -1, 174, 234, -15, -7, -3, + -1, 189, 219, -1, 204, 158, -3, -1, 233, 173, -1, 218, 188, -7, -3, + -1, 203, 142, -1, 232, 157, -3, -1, 217, 126, -1, 231, 172, 255, -235, + -143, -77, -45, -25, -15, -7, -3, -1, 202, 187, -1, 141, 216, -5, -3, + -1, 14, 224, 13, 230, -5, -3, -1, 110, 156, 201, -1, 94, 186, -9, + -5, -1, 229, -1, 171, 125, -1, 215, 228, -3, -1, 140, 200, -3, -1, + 78, 46, 62, -15, -7, -3, -1, 109, 214, -1, 227, 155, -3, -1, 185, + 170, -1, 226, 30, -7, -3, -1, 225, 93, -1, 213, 124, -3, -1, 199, + 77, -1, 139, 184, -31, -15, -7, -3, -1, 212, 154, -1, 169, 108, -3, + -1, 198, 61, -1, 211, 45, -7, -3, -1, 210, 29, -1, 123, 183, -3, + -1, 209, 92, -1, 197, 138, -17, -7, -3, -1, 168, 153, -1, 76, 196, + -3, -1, 107, 182, -3, -1, 208, 12, 60, -7, -3, -1, 195, 122, -1, + 167, 44, -3, -1, 194, 91, -1, 181, 28, -57, -35, -19, -7, -3, -1, + 137, 152, -1, 193, 75, -5, -3, -1, 192, 11, 59, -3, -1, 176, 10, + 26, -5, -1, 180, -1, 106, 166, -3, -1, 121, 151, -3, -1, 160, 9, + 144, -9, -3, -1, 179, 136, -3, -1, 43, 90, 178, -7, -3, -1, 165, + 27, -1, 177, 105, -1, 150, 164, -17, -9, -5, -3, -1, 74, 120, 135, + -1, 58, 163, -3, -1, 89, 149, -1, 42, 162, -7, -3, -1, 161, 104, + -1, 134, 119, -3, -1, 73, 148, -1, 57, 147, -63, -31, -15, -7, -3, + -1, 88, 133, -1, 41, 103, -3, -1, 118, 146, -1, 25, 145, -7, -3, + -1, 72, 132, -1, 87, 117, -3, -1, 56, 131, -1, 102, 40, -17, -7, + -3, -1, 130, 24, -1, 71, 116, -5, -1, 129, -1, 8, 128, -1, 86, + 101, -7, -5, -1, 23, -1, 7, 112, 115, -3, -1, 55, 39, 114, -15, + -7, -3, -1, 70, 100, -1, 85, 113, -3, -1, 54, 99, -1, 69, 84, + -7, -3, -1, 38, 98, -1, 22, 97, -5, -3, -1, 6, 96, 53, -1, + 83, 68, -51, -37, -23, -15, -9, -3, -1, 37, 82, -1, 21, -1, 5, + 80, -1, 81, -1, 52, 67, -3, -1, 36, 66, -1, 51, 20, -9, -5, + -1, 65, -1, 4, 64, -1, 35, 50, -1, 19, 49, -7, -5, -3, -1, + 3, 48, 34, 18, -1, 33, -1, 2, 32, -3, -1, 17, 1, -1, 16, + 0 +}; + +static short tab_c0[] = +{ + -29, -21, -13, -7, -3, -1, 11, 15, -1, 13, 14, -3, -1, 7, 5, + 9, -3, -1, 6, 3, -1, 10, 12, -3, -1, 2, 1, -1, 4, 8, + 0 +}; + +static short tab_c1[] = +{ + -15, -7, -3, -1, 15, 14, -1, 13, 12, -3, -1, 11, 10, -1, 9, + 8, -7, -3, -1, 7, 6, -1, 5, 4, -3, -1, 3, 2, -1, 1, + 0 +}; + +static struct newhuff ht[] = +{ + { /* 0 */ 0, tab0}, + { /* 2 */ 0, tab1}, + { /* 3 */ 0, tab2}, + { /* 3 */ 0, tab3}, + { /* 0 */ 0, tab0}, + { /* 4 */ 0, tab5}, + { /* 4 */ 0, tab6}, + { /* 6 */ 0, tab7}, + { /* 6 */ 0, tab8}, + { /* 6 */ 0, tab9}, + { /* 8 */ 0, tab10}, + { /* 8 */ 0, tab11}, + { /* 8 */ 0, tab12}, + { /* 16 */ 0, tab13}, + { /* 0 */ 0, tab0}, + { /* 16 */ 0, tab15}, + + { /* 16 */ 1, tab16}, + { /* 16 */ 2, tab16}, + { /* 16 */ 3, tab16}, + { /* 16 */ 4, tab16}, + { /* 16 */ 6, tab16}, + { /* 16 */ 8, tab16}, + { /* 16 */ 10, tab16}, + { /* 16 */ 13, tab16}, + { /* 16 */ 4, tab24}, + { /* 16 */ 5, tab24}, + { /* 16 */ 6, tab24}, + { /* 16 */ 7, tab24}, + { /* 16 */ 8, tab24}, + { /* 16 */ 9, tab24}, + { /* 16 */ 11, tab24}, + { /* 16 */ 13, tab24} +}; + +static struct newhuff htc[] = +{ + { /* 1 , 1 , */ 0, tab_c0}, + { /* 1 , 1 , */ 0, tab_c1} +}; diff --git a/libmpg123/l2tables.h b/libmpg123/l2tables.h new file mode 100644 index 0000000..51eb22f --- /dev/null +++ b/libmpg123/l2tables.h @@ -0,0 +1,997 @@ +/* + * Layer 2 Alloc tables .. + * most other tables are calculated on program start (which is (of course) + * not ISO-conform) .. + * Layer-3 huffman table is in huffman.h + */ + +struct al_table alloc_0[] = +{ + {4, 0}, + {5, 3}, + {3, -3}, + {4, -7}, + {5, -15}, + {6, -31}, + {7, -63}, + {8, -127}, + {9, -255}, + {10, -511}, + {11, -1023}, + {12, -2047}, + {13, -4095}, + {14, -8191}, + {15, -16383}, + {16, -32767}, + {4, 0}, + {5, 3}, + {3, -3}, + {4, -7}, + {5, -15}, + {6, -31}, + {7, -63}, + {8, -127}, + {9, -255}, + {10, -511}, + {11, -1023}, + {12, -2047}, + {13, -4095}, + {14, -8191}, + {15, -16383}, + {16, -32767}, + {4, 0}, + {5, 3}, + {3, -3}, + {4, -7}, + {5, -15}, + {6, -31}, + {7, -63}, + {8, -127}, + {9, -255}, + {10, -511}, + {11, -1023}, + {12, -2047}, + {13, -4095}, + {14, -8191}, + {15, -16383}, + {16, -32767}, + {4, 0}, + {5, 3}, + {7, 5}, + {3, -3}, + {10, 9}, + {4, -7}, + {5, -15}, + {6, -31}, + {7, -63}, + {8, -127}, + {9, -255}, + {10, -511}, + {11, -1023}, + {12, -2047}, + {13, -4095}, + {16, -32767}, + {4, 0}, + {5, 3}, + {7, 5}, + {3, -3}, + {10, 9}, + {4, -7}, + {5, -15}, + {6, -31}, + {7, -63}, + {8, -127}, + {9, -255}, + {10, -511}, + {11, -1023}, + {12, -2047}, + {13, -4095}, + {16, -32767}, + {4, 0}, + {5, 3}, + {7, 5}, + {3, -3}, + {10, 9}, + {4, -7}, + {5, -15}, + {6, -31}, + {7, -63}, + {8, -127}, + {9, -255}, + {10, -511}, + {11, -1023}, + {12, -2047}, + {13, -4095}, + {16, -32767}, + {4, 0}, + {5, 3}, + {7, 5}, + {3, -3}, + {10, 9}, + {4, -7}, + {5, -15}, + {6, -31}, + {7, -63}, + {8, -127}, + {9, -255}, + {10, -511}, + {11, -1023}, + {12, -2047}, + {13, -4095}, + {16, -32767}, + {4, 0}, + {5, 3}, + {7, 5}, + {3, -3}, + {10, 9}, + {4, -7}, + {5, -15}, + {6, -31}, + {7, -63}, + {8, -127}, + {9, -255}, + {10, -511}, + {11, -1023}, + {12, -2047}, + {13, -4095}, + {16, -32767}, + {4, 0}, + {5, 3}, + {7, 5}, + {3, -3}, + {10, 9}, + {4, -7}, + {5, -15}, + {6, -31}, + {7, -63}, + {8, -127}, + {9, -255}, + {10, -511}, + {11, -1023}, + {12, -2047}, + {13, -4095}, + {16, -32767}, + {4, 0}, + {5, 3}, + {7, 5}, + {3, -3}, + {10, 9}, + {4, -7}, + {5, -15}, + {6, -31}, + {7, -63}, + {8, -127}, + {9, -255}, + {10, -511}, + {11, -1023}, + {12, -2047}, + {13, -4095}, + {16, -32767}, + {4, 0}, + {5, 3}, + {7, 5}, + {3, -3}, + {10, 9}, + {4, -7}, + {5, -15}, + {6, -31}, + {7, -63}, + {8, -127}, + {9, -255}, + {10, -511}, + {11, -1023}, + {12, -2047}, + {13, -4095}, + {16, -32767}, + {3, 0}, + {5, 3}, + {7, 5}, + {3, -3}, + {10, 9}, + {4, -7}, + {5, -15}, + {16, -32767}, + {3, 0}, + {5, 3}, + {7, 5}, + {3, -3}, + {10, 9}, + {4, -7}, + {5, -15}, + {16, -32767}, + {3, 0}, + {5, 3}, + {7, 5}, + {3, -3}, + {10, 9}, + {4, -7}, + {5, -15}, + {16, -32767}, + {3, 0}, + {5, 3}, + {7, 5}, + {3, -3}, + {10, 9}, + {4, -7}, + {5, -15}, + {16, -32767}, + {3, 0}, + {5, 3}, + {7, 5}, + {3, -3}, + {10, 9}, + {4, -7}, + {5, -15}, + {16, -32767}, + {3, 0}, + {5, 3}, + {7, 5}, + {3, -3}, + {10, 9}, + {4, -7}, + {5, -15}, + {16, -32767}, + {3, 0}, + {5, 3}, + {7, 5}, + {3, -3}, + {10, 9}, + {4, -7}, + {5, -15}, + {16, -32767}, + {3, 0}, + {5, 3}, + {7, 5}, + {3, -3}, + {10, 9}, + {4, -7}, + {5, -15}, + {16, -32767}, + {3, 0}, + {5, 3}, + {7, 5}, + {3, -3}, + {10, 9}, + {4, -7}, + {5, -15}, + {16, -32767}, + {3, 0}, + {5, 3}, + {7, 5}, + {3, -3}, + {10, 9}, + {4, -7}, + {5, -15}, + {16, -32767}, + {3, 0}, + {5, 3}, + {7, 5}, + {3, -3}, + {10, 9}, + {4, -7}, + {5, -15}, + {16, -32767}, + {3, 0}, + {5, 3}, + {7, 5}, + {3, -3}, + {10, 9}, + {4, -7}, + {5, -15}, + {16, -32767}, + {2, 0}, + {5, 3}, + {7, 5}, + {16, -32767}, + {2, 0}, + {5, 3}, + {7, 5}, + {16, -32767}, + {2, 0}, + {5, 3}, + {7, 5}, + {16, -32767}, + {2, 0}, + {5, 3}, + {7, 5}, + {16, -32767}}; + +struct al_table alloc_1[] = +{ + {4, 0}, + {5, 3}, + {3, -3}, + {4, -7}, + {5, -15}, + {6, -31}, + {7, -63}, + {8, -127}, + {9, -255}, + {10, -511}, + {11, -1023}, + {12, -2047}, + {13, -4095}, + {14, -8191}, + {15, -16383}, + {16, -32767}, + {4, 0}, + {5, 3}, + {3, -3}, + {4, -7}, + {5, -15}, + {6, -31}, + {7, -63}, + {8, -127}, + {9, -255}, + {10, -511}, + {11, -1023}, + {12, -2047}, + {13, -4095}, + {14, -8191}, + {15, -16383}, + {16, -32767}, + {4, 0}, + {5, 3}, + {3, -3}, + {4, -7}, + {5, -15}, + {6, -31}, + {7, -63}, + {8, -127}, + {9, -255}, + {10, -511}, + {11, -1023}, + {12, -2047}, + {13, -4095}, + {14, -8191}, + {15, -16383}, + {16, -32767}, + {4, 0}, + {5, 3}, + {7, 5}, + {3, -3}, + {10, 9}, + {4, -7}, + {5, -15}, + {6, -31}, + {7, -63}, + {8, -127}, + {9, -255}, + {10, -511}, + {11, -1023}, + {12, -2047}, + {13, -4095}, + {16, -32767}, + {4, 0}, + {5, 3}, + {7, 5}, + {3, -3}, + {10, 9}, + {4, -7}, + {5, -15}, + {6, -31}, + {7, -63}, + {8, -127}, + {9, -255}, + {10, -511}, + {11, -1023}, + {12, -2047}, + {13, -4095}, + {16, -32767}, + {4, 0}, + {5, 3}, + {7, 5}, + {3, -3}, + {10, 9}, + {4, -7}, + {5, -15}, + {6, -31}, + {7, -63}, + {8, -127}, + {9, -255}, + {10, -511}, + {11, -1023}, + {12, -2047}, + {13, -4095}, + {16, -32767}, + {4, 0}, + {5, 3}, + {7, 5}, + {3, -3}, + {10, 9}, + {4, -7}, + {5, -15}, + {6, -31}, + {7, -63}, + {8, -127}, + {9, -255}, + {10, -511}, + {11, -1023}, + {12, -2047}, + {13, -4095}, + {16, -32767}, + {4, 0}, + {5, 3}, + {7, 5}, + {3, -3}, + {10, 9}, + {4, -7}, + {5, -15}, + {6, -31}, + {7, -63}, + {8, -127}, + {9, -255}, + {10, -511}, + {11, -1023}, + {12, -2047}, + {13, -4095}, + {16, -32767}, + {4, 0}, + {5, 3}, + {7, 5}, + {3, -3}, + {10, 9}, + {4, -7}, + {5, -15}, + {6, -31}, + {7, -63}, + {8, -127}, + {9, -255}, + {10, -511}, + {11, -1023}, + {12, -2047}, + {13, -4095}, + {16, -32767}, + {4, 0}, + {5, 3}, + {7, 5}, + {3, -3}, + {10, 9}, + {4, -7}, + {5, -15}, + {6, -31}, + {7, -63}, + {8, -127}, + {9, -255}, + {10, -511}, + {11, -1023}, + {12, -2047}, + {13, -4095}, + {16, -32767}, + {4, 0}, + {5, 3}, + {7, 5}, + {3, -3}, + {10, 9}, + {4, -7}, + {5, -15}, + {6, -31}, + {7, -63}, + {8, -127}, + {9, -255}, + {10, -511}, + {11, -1023}, + {12, -2047}, + {13, -4095}, + {16, -32767}, + {3, 0}, + {5, 3}, + {7, 5}, + {3, -3}, + {10, 9}, + {4, -7}, + {5, -15}, + {16, -32767}, + {3, 0}, + {5, 3}, + {7, 5}, + {3, -3}, + {10, 9}, + {4, -7}, + {5, -15}, + {16, -32767}, + {3, 0}, + {5, 3}, + {7, 5}, + {3, -3}, + {10, 9}, + {4, -7}, + {5, -15}, + {16, -32767}, + {3, 0}, + {5, 3}, + {7, 5}, + {3, -3}, + {10, 9}, + {4, -7}, + {5, -15}, + {16, -32767}, + {3, 0}, + {5, 3}, + {7, 5}, + {3, -3}, + {10, 9}, + {4, -7}, + {5, -15}, + {16, -32767}, + {3, 0}, + {5, 3}, + {7, 5}, + {3, -3}, + {10, 9}, + {4, -7}, + {5, -15}, + {16, -32767}, + {3, 0}, + {5, 3}, + {7, 5}, + {3, -3}, + {10, 9}, + {4, -7}, + {5, -15}, + {16, -32767}, + {3, 0}, + {5, 3}, + {7, 5}, + {3, -3}, + {10, 9}, + {4, -7}, + {5, -15}, + {16, -32767}, + {3, 0}, + {5, 3}, + {7, 5}, + {3, -3}, + {10, 9}, + {4, -7}, + {5, -15}, + {16, -32767}, + {3, 0}, + {5, 3}, + {7, 5}, + {3, -3}, + {10, 9}, + {4, -7}, + {5, -15}, + {16, -32767}, + {3, 0}, + {5, 3}, + {7, 5}, + {3, -3}, + {10, 9}, + {4, -7}, + {5, -15}, + {16, -32767}, + {3, 0}, + {5, 3}, + {7, 5}, + {3, -3}, + {10, 9}, + {4, -7}, + {5, -15}, + {16, -32767}, + {2, 0}, + {5, 3}, + {7, 5}, + {16, -32767}, + {2, 0}, + {5, 3}, + {7, 5}, + {16, -32767}, + {2, 0}, + {5, 3}, + {7, 5}, + {16, -32767}, + {2, 0}, + {5, 3}, + {7, 5}, + {16, -32767}, + {2, 0}, + {5, 3}, + {7, 5}, + {16, -32767}, + {2, 0}, + {5, 3}, + {7, 5}, + {16, -32767}, + {2, 0}, + {5, 3}, + {7, 5}, + {16, -32767}}; + +struct al_table alloc_2[] = +{ + {4, 0}, + {5, 3}, + {7, 5}, + {10, 9}, + {4, -7}, + {5, -15}, + {6, -31}, + {7, -63}, + {8, -127}, + {9, -255}, + {10, -511}, + {11, -1023}, + {12, -2047}, + {13, -4095}, + {14, -8191}, + {15, -16383}, + {4, 0}, + {5, 3}, + {7, 5}, + {10, 9}, + {4, -7}, + {5, -15}, + {6, -31}, + {7, -63}, + {8, -127}, + {9, -255}, + {10, -511}, + {11, -1023}, + {12, -2047}, + {13, -4095}, + {14, -8191}, + {15, -16383}, + {3, 0}, + {5, 3}, + {7, 5}, + {10, 9}, + {4, -7}, + {5, -15}, + {6, -31}, + {7, -63}, + {3, 0}, + {5, 3}, + {7, 5}, + {10, 9}, + {4, -7}, + {5, -15}, + {6, -31}, + {7, -63}, + {3, 0}, + {5, 3}, + {7, 5}, + {10, 9}, + {4, -7}, + {5, -15}, + {6, -31}, + {7, -63}, + {3, 0}, + {5, 3}, + {7, 5}, + {10, 9}, + {4, -7}, + {5, -15}, + {6, -31}, + {7, -63}, + {3, 0}, + {5, 3}, + {7, 5}, + {10, 9}, + {4, -7}, + {5, -15}, + {6, -31}, + {7, -63}, + {3, 0}, + {5, 3}, + {7, 5}, + {10, 9}, + {4, -7}, + {5, -15}, + {6, -31}, + {7, -63}}; + +struct al_table alloc_3[] = +{ + {4, 0}, + {5, 3}, + {7, 5}, + {10, 9}, + {4, -7}, + {5, -15}, + {6, -31}, + {7, -63}, + {8, -127}, + {9, -255}, + {10, -511}, + {11, -1023}, + {12, -2047}, + {13, -4095}, + {14, -8191}, + {15, -16383}, + {4, 0}, + {5, 3}, + {7, 5}, + {10, 9}, + {4, -7}, + {5, -15}, + {6, -31}, + {7, -63}, + {8, -127}, + {9, -255}, + {10, -511}, + {11, -1023}, + {12, -2047}, + {13, -4095}, + {14, -8191}, + {15, -16383}, + {3, 0}, + {5, 3}, + {7, 5}, + {10, 9}, + {4, -7}, + {5, -15}, + {6, -31}, + {7, -63}, + {3, 0}, + {5, 3}, + {7, 5}, + {10, 9}, + {4, -7}, + {5, -15}, + {6, -31}, + {7, -63}, + {3, 0}, + {5, 3}, + {7, 5}, + {10, 9}, + {4, -7}, + {5, -15}, + {6, -31}, + {7, -63}, + {3, 0}, + {5, 3}, + {7, 5}, + {10, 9}, + {4, -7}, + {5, -15}, + {6, -31}, + {7, -63}, + {3, 0}, + {5, 3}, + {7, 5}, + {10, 9}, + {4, -7}, + {5, -15}, + {6, -31}, + {7, -63}, + {3, 0}, + {5, 3}, + {7, 5}, + {10, 9}, + {4, -7}, + {5, -15}, + {6, -31}, + {7, -63}, + {3, 0}, + {5, 3}, + {7, 5}, + {10, 9}, + {4, -7}, + {5, -15}, + {6, -31}, + {7, -63}, + {3, 0}, + {5, 3}, + {7, 5}, + {10, 9}, + {4, -7}, + {5, -15}, + {6, -31}, + {7, -63}, + {3, 0}, + {5, 3}, + {7, 5}, + {10, 9}, + {4, -7}, + {5, -15}, + {6, -31}, + {7, -63}, + {3, 0}, + {5, 3}, + {7, 5}, + {10, 9}, + {4, -7}, + {5, -15}, + {6, -31}, + {7, -63}}; + +struct al_table alloc_4[] = +{ + {4, 0}, + {5, 3}, + {7, 5}, + {3, -3}, + {10, 9}, + {4, -7}, + {5, -15}, + {6, -31}, + {7, -63}, + {8, -127}, + {9, -255}, + {10, -511}, + {11, -1023}, + {12, -2047}, + {13, -4095}, + {14, -8191}, + {4, 0}, + {5, 3}, + {7, 5}, + {3, -3}, + {10, 9}, + {4, -7}, + {5, -15}, + {6, -31}, + {7, -63}, + {8, -127}, + {9, -255}, + {10, -511}, + {11, -1023}, + {12, -2047}, + {13, -4095}, + {14, -8191}, + {4, 0}, + {5, 3}, + {7, 5}, + {3, -3}, + {10, 9}, + {4, -7}, + {5, -15}, + {6, -31}, + {7, -63}, + {8, -127}, + {9, -255}, + {10, -511}, + {11, -1023}, + {12, -2047}, + {13, -4095}, + {14, -8191}, + {4, 0}, + {5, 3}, + {7, 5}, + {3, -3}, + {10, 9}, + {4, -7}, + {5, -15}, + {6, -31}, + {7, -63}, + {8, -127}, + {9, -255}, + {10, -511}, + {11, -1023}, + {12, -2047}, + {13, -4095}, + {14, -8191}, + {3, 0}, + {5, 3}, + {7, 5}, + {10, 9}, + {4, -7}, + {5, -15}, + {6, -31}, + {7, -63}, + {3, 0}, + {5, 3}, + {7, 5}, + {10, 9}, + {4, -7}, + {5, -15}, + {6, -31}, + {7, -63}, + {3, 0}, + {5, 3}, + {7, 5}, + {10, 9}, + {4, -7}, + {5, -15}, + {6, -31}, + {7, -63}, + {3, 0}, + {5, 3}, + {7, 5}, + {10, 9}, + {4, -7}, + {5, -15}, + {6, -31}, + {7, -63}, + {3, 0}, + {5, 3}, + {7, 5}, + {10, 9}, + {4, -7}, + {5, -15}, + {6, -31}, + {7, -63}, + {3, 0}, + {5, 3}, + {7, 5}, + {10, 9}, + {4, -7}, + {5, -15}, + {6, -31}, + {7, -63}, + {3, 0}, + {5, 3}, + {7, 5}, + {10, 9}, + {4, -7}, + {5, -15}, + {6, -31}, + {7, -63}, + {2, 0}, + {5, 3}, + {7, 5}, + {10, 9}, + {2, 0}, + {5, 3}, + {7, 5}, + {10, 9}, + {2, 0}, + {5, 3}, + {7, 5}, + {10, 9}, + {2, 0}, + {5, 3}, + {7, 5}, + {10, 9}, + {2, 0}, + {5, 3}, + {7, 5}, + {10, 9}, + {2, 0}, + {5, 3}, + {7, 5}, + {10, 9}, + {2, 0}, + {5, 3}, + {7, 5}, + {10, 9}, + {2, 0}, + {5, 3}, + {7, 5}, + {10, 9}, + {2, 0}, + {5, 3}, + {7, 5}, + {10, 9}, + {2, 0}, + {5, 3}, + {7, 5}, + {10, 9}, + {2, 0}, + {5, 3}, + {7, 5}, + {10, 9}, + {2, 0}, + {5, 3}, + {7, 5}, + {10, 9}, + {2, 0}, + {5, 3}, + {7, 5}, + {10, 9}, + {2, 0}, + {5, 3}, + {7, 5}, + {10, 9}, + {2, 0}, + {5, 3}, + {7, 5}, + {10, 9}, + {2, 0}, + {5, 3}, + {7, 5}, + {10, 9}, + {2, 0}, + {5, 3}, + {7, 5}, + {10, 9}, + {2, 0}, + {5, 3}, + {7, 5}, + {10, 9}, + {2, 0}, + {5, 3}, + {7, 5}, + {10, 9}}; diff --git a/libmpg123/layer1.c b/libmpg123/layer1.c new file mode 100644 index 0000000..057f08b --- /dev/null +++ b/libmpg123/layer1.c @@ -0,0 +1,187 @@ + +/* + * Mpeg Layer-1 audio decoder + * -------------------------- + * copyright (c) 1995 by Michael Hipp, All rights reserved. See also 'README' + * near unoptimzed ... + * + * may have a few bugs after last optimization ... + * + */ + +#include "mpg123.h" +#include "getbits.h" + +/* Used by the getbits macros */ +static unsigned long rval; + +void I_step_one(unsigned int balloc[], unsigned int scale_index[2][SBLIMIT], struct frame *fr) +{ + unsigned int *ba = balloc; + unsigned int *sca = (unsigned int *) scale_index; + + if (fr->stereo) + { + int i; + int jsbound = fr->jsbound; + + for (i = 0; i < jsbound; i++) + { + *ba++ = mpg123_getbits(4); + *ba++ = mpg123_getbits(4); + } + for (i = jsbound; i < SBLIMIT; i++) + *ba++ = mpg123_getbits(4); + + ba = balloc; + + for (i = 0; i < jsbound; i++) + { + if ((*ba++)) + *sca++ = mpg123_getbits(6); + if ((*ba++)) + *sca++ = mpg123_getbits(6); + } + for (i = jsbound; i < SBLIMIT; i++) + if ((*ba++)) + { + *sca++ = mpg123_getbits(6); + *sca++ = mpg123_getbits(6); + } + } + else + { + int i; + + for (i = 0; i < SBLIMIT; i++) + *ba++ = mpg123_getbits(4); + ba = balloc; + for (i = 0; i < SBLIMIT; i++) + if ((*ba++)) + *sca++ = mpg123_getbits(6); + } +} + +void I_step_two(real fraction[2][SBLIMIT], unsigned int balloc[2 * SBLIMIT], + unsigned int scale_index[2][SBLIMIT], struct frame *fr) +{ + int i, n; + int smpb[2 * SBLIMIT]; /* values: 0-65535 */ + int *sample; + register unsigned int *ba; + register unsigned int *sca = (unsigned int *) scale_index; + + if (fr->stereo) + { + int jsbound = fr->jsbound; + register real *f0 = fraction[0]; + register real *f1 = fraction[1]; + + ba = balloc; + for (sample = smpb, i = 0; i < jsbound; i++) + { + if ((n = *ba++)) + *sample++ = mpg123_getbits(n + 1); + if ((n = *ba++)) + *sample++ = mpg123_getbits(n + 1); + } + for (i = jsbound; i < SBLIMIT; i++) + if ((n = *ba++)) + *sample++ = mpg123_getbits(n + 1); + + ba = balloc; + for (sample = smpb, i = 0; i < jsbound; i++) + { + if ((n = *ba++)) + *f0++ = (real) (((-1) << n) + (*sample++) + 1) * mpg123_muls[n + 1][*sca++]; + else + *f0++ = 0.0; + if ((n = *ba++)) + *f1++ = (real) (((-1) << n) + (*sample++) + 1) * mpg123_muls[n + 1][*sca++]; + else + *f1++ = 0.0; + } + for (i = jsbound; i < SBLIMIT; i++) + { + if ((n = *ba++)) + { + real samp = (((-1) << n) + (*sample++) + 1); + + *f0++ = samp * mpg123_muls[n + 1][*sca++]; + *f1++ = samp * mpg123_muls[n + 1][*sca++]; + } + else + *f0++ = *f1++ = 0.0; + } + for (i = fr->down_sample_sblimit; i < 32; i++) + fraction[0][i] = fraction[1][i] = 0.0; + } + else + { + register real *f0 = fraction[0]; + + ba = balloc; + for (sample = smpb, i = 0; i < SBLIMIT; i++) + if ((n = *ba++)) + *sample++ = mpg123_getbits(n + 1); + ba = balloc; + for (sample = smpb, i = 0; i < SBLIMIT; i++) + { + if ((n = *ba++)) + *f0++ = (real) (((-1) << n) + (*sample++) + 1) * mpg123_muls[n + 1][*sca++]; + else + *f0++ = 0.0; + } + for (i = fr->down_sample_sblimit; i < 32; i++) + fraction[0][i] = 0.0; + } +} + +int mpg123_do_layer1(struct frame *fr) +{ + int i, stereo = fr->stereo; + unsigned int balloc[2 * SBLIMIT]; + unsigned int scale_index[2][SBLIMIT]; + real fraction[2][SBLIMIT]; + int single = fr->single; + + fr->jsbound = (fr->mode == MPG_MD_JOINT_STEREO) ? (fr->mode_ext << 2) + 4 : 32; + + if (stereo == 1 || single == 3) + single = 0; + + I_step_one(balloc, scale_index, fr); + + for (i = 0; i < SCALE_BLOCK; i++) + { + I_step_two(fraction, balloc, scale_index, fr); + + if (single >= 0) + { + (fr->synth_mono) ((real *) fraction[single], mpg123_pcm_sample, &mpg123_pcm_point); + } + else + { + int p1 = mpg123_pcm_point; + + (fr->synth) ((real *) fraction[0], 0, mpg123_pcm_sample, &p1); + (fr->synth) ((real *) fraction[1], 1, mpg123_pcm_sample, &mpg123_pcm_point); + } + +/*** + if (mpg123_info->output_audio) + { + + mpg123_ip.add_vis_pcm(mpg123_ip.output->written_time(), mpg123_cfg.resolution == 16 ? FMT_S16_NE : FMT_U8, + mpg123_cfg.channels == 2 ? fr->stereo : 1, mpg123_pcm_point, mpg123_pcm_sample); + while (mpg123_ip.output->buffer_free() < mpg123_pcm_point && mpg123_info->going && mpg123_info->jump_to_time == -1) + xmms_usleep(10000); + if (mpg123_info->going && mpg123_info->jump_to_time == -1) + mpg123_ip.output->write_audio(mpg123_pcm_sample, mpg123_pcm_point); + } +***/ + mpg123_pcm_point = 0; + } + + return 1; +} diff --git a/libmpg123/layer2.c b/libmpg123/layer2.c new file mode 100644 index 0000000..07ce258 --- /dev/null +++ b/libmpg123/layer2.c @@ -0,0 +1,336 @@ + +/* + * Mpeg Layer-2 audio decoder + * -------------------------- + * copyright (c) 1995 by Michael Hipp, All rights reserved. See also 'README' + * + */ + +#include "mpg123.h" +#include "l2tables.h" +#include "getbits.h" + +static int grp_3tab[32 * 3] = +{0,}; /* used: 27 */ +static int grp_5tab[128 * 3] = +{0,}; /* used: 125 */ +static int grp_9tab[1024 * 3] = +{0,}; /* used: 729 */ + +real mpg123_muls[27][64]; /* also used by layer 1 */ + +/* Used by the getbits macros */ +static unsigned long rval; + +void mpg123_init_layer2(void) +{ + static double mulmul[27] = { + 0.0, -2.0 / 3.0, 2.0 / 3.0, 2.0 / 7.0, 2.0 / 15.0, + 2.0 / 31.0, 2.0 / 63.0, 2.0 / 127.0, 2.0 / 255.0, + 2.0 / 511.0, 2.0 / 1023.0, 2.0 / 2047.0, 2.0 / 4095.0, + 2.0 / 8191.0, 2.0 / 16383.0, 2.0 / 32767.0, 2.0 / 65535.0, + -4.0 / 5.0, -2.0 / 5.0, 2.0 / 5.0, 4.0 / 5.0, -8.0 / 9.0, + -4.0 / 9.0, -2.0 / 9.0, 2.0 / 9.0, 4.0 / 9.0, 8.0 / 9.0 }; + static int base[3][9] = { + {1, 0, 2,}, + {17, 18, 0, 19, 20,}, + {21, 1, 22, 23, 0, 24, 25, 2, 26}}; + int i, j, k, l, len; + real *table; + static int tablen[3] = {3, 5, 9}; + static int *itable, *tables[3] = + {grp_3tab, grp_5tab, grp_9tab}; + + for (i = 0; i < 3; i++) + { + itable = tables[i]; + len = tablen[i]; + for (j = 0; j < len; j++) + for (k = 0; k < len; k++) + for (l = 0; l < len; l++) + { + *itable++ = base[i][l]; + *itable++ = base[i][k]; + *itable++ = base[i][j]; + } + } + + for (k = 0; k < 27; k++) + { + double m = mulmul[k]; + + table = mpg123_muls[k]; + for (j = 3, i = 0; i < 63; i++, j--) + *table++ = m * pow(2.0, (double) j / 3.0); + *table++ = 0.0; + } +} + +void II_step_one(unsigned int *bit_alloc, int *scale, struct frame *fr) +{ + int stereo = fr->stereo - 1; + int sblimit = fr->II_sblimit; + int jsbound = fr->jsbound; + int sblimit2 = fr->II_sblimit << stereo; + struct al_table *alloc1 = fr->alloc; + int i; + static unsigned int scfsi_buf[64]; + unsigned int *scfsi, *bita; + int sc, step; + + bita = bit_alloc; + if (stereo) + { + for (i = jsbound; i > 0; i--, alloc1 += (1 << step)) + { + *bita++ = (char) mpg123_getbits(step = alloc1->bits); + *bita++ = (char) mpg123_getbits(step); + } + for (i = sblimit - jsbound; i > 0; i--, alloc1 += (1 << step)) + { + bita[0] = (char) mpg123_getbits(step = alloc1->bits); + bita[1] = bita[0]; + bita += 2; + } + bita = bit_alloc; + scfsi = scfsi_buf; + for (i = sblimit2; i; i--) + if (*bita++) + *scfsi++ = (char) mpg123_getbits_fast(2); + } + else + /* mono */ + { + for (i = sblimit; i; i--, alloc1 += (1 << step)) + *bita++ = (char) mpg123_getbits(step = alloc1->bits); + bita = bit_alloc; + scfsi = scfsi_buf; + for (i = sblimit; i; i--) + if (*bita++) + *scfsi++ = (char) mpg123_getbits_fast(2); + } + + bita = bit_alloc; + scfsi = scfsi_buf; + for (i = sblimit2; i; i--) + if (*bita++) + switch (*scfsi++) + { + case 0: + *scale++ = mpg123_getbits_fast(6); + *scale++ = mpg123_getbits_fast(6); + *scale++ = mpg123_getbits_fast(6); + break; + case 1: + *scale++ = sc = mpg123_getbits_fast(6); + *scale++ = sc; + *scale++ = mpg123_getbits_fast(6); + break; + case 2: + *scale++ = sc = mpg123_getbits_fast(6); + *scale++ = sc; + *scale++ = sc; + break; + default: /* case 3 */ + *scale++ = mpg123_getbits_fast(6); + *scale++ = sc = mpg123_getbits_fast(6); + *scale++ = sc; + break; + } + +} + +void II_step_two(unsigned int *bit_alloc, real fraction[2][4][SBLIMIT], int *scale, struct frame *fr, int x1) +{ + int i, j, k, ba; + int stereo = fr->stereo; + int sblimit = fr->II_sblimit; + int jsbound = fr->jsbound; + struct al_table *alloc2, *alloc1 = fr->alloc; + unsigned int *bita = bit_alloc; + int d1, step; + + for (i = 0; i < jsbound; i++, alloc1 += (1 << step)) + { + step = alloc1->bits; + for (j = 0; j < stereo; j++) + { + if ((ba = *bita++)) + { + k = (alloc2 = alloc1 + ba)->bits; + if ((d1 = alloc2->d) < 0) + { + real cm = mpg123_muls[k][scale[x1]]; + + fraction[j][0][i] = ((real) ((int) mpg123_getbits(k) + d1)) * cm; + fraction[j][1][i] = ((real) ((int) mpg123_getbits(k) + d1)) * cm; + fraction[j][2][i] = ((real) ((int) mpg123_getbits(k) + d1)) * cm; + } + else + { + static int *table[] = + {0, 0, 0, grp_3tab, 0, grp_5tab, 0, 0, 0, grp_9tab}; + unsigned int idx, *tab, m = scale[x1]; + + idx = (unsigned int) mpg123_getbits(k); + tab = (unsigned int *) (table[d1] + idx + idx + idx); + fraction[j][0][i] = mpg123_muls[*tab++][m]; + fraction[j][1][i] = mpg123_muls[*tab++][m]; + fraction[j][2][i] = mpg123_muls[*tab][m]; + } + scale += 3; + } + else + fraction[j][0][i] = fraction[j][1][i] = fraction[j][2][i] = 0.0; + } + } + + for (i = jsbound; i < sblimit; i++, alloc1 += (1 << step)) + { + step = alloc1->bits; + bita++; /* channel 1 and channel 2 bitalloc are the same */ + if ((ba = *bita++)) + { + k = (alloc2 = alloc1 + ba)->bits; + if ((d1 = alloc2->d) < 0) + { + real cm; + + cm = mpg123_muls[k][scale[x1 + 3]]; + fraction[1][0][i] = (fraction[0][0][i] = (real) ((int) mpg123_getbits(k) + d1)) * cm; + fraction[1][1][i] = (fraction[0][1][i] = (real) ((int) mpg123_getbits(k) + d1)) * cm; + fraction[1][2][i] = (fraction[0][2][i] = (real) ((int) mpg123_getbits(k) + d1)) * cm; + cm = mpg123_muls[k][scale[x1]]; + fraction[0][0][i] *= cm; + fraction[0][1][i] *= cm; + fraction[0][2][i] *= cm; + } + else + { + static int *table[] = + {0, 0, 0, grp_3tab, 0, grp_5tab, 0, 0, 0, grp_9tab}; + unsigned int idx, *tab, m1, m2; + + m1 = scale[x1]; + m2 = scale[x1 + 3]; + idx = (unsigned int) mpg123_getbits(k); + tab = (unsigned int *) (table[d1] + idx + idx + idx); + fraction[0][0][i] = mpg123_muls[*tab][m1]; + fraction[1][0][i] = mpg123_muls[*tab++][m2]; + fraction[0][1][i] = mpg123_muls[*tab][m1]; + fraction[1][1][i] = mpg123_muls[*tab++][m2]; + fraction[0][2][i] = mpg123_muls[*tab][m1]; + fraction[1][2][i] = mpg123_muls[*tab][m2]; + } + scale += 6; + } + else + { + fraction[0][0][i] = fraction[0][1][i] = fraction[0][2][i] = + fraction[1][0][i] = fraction[1][1][i] = fraction[1][2][i] = 0.0; + } +/* + should we use individual scalefac for channel 2 or + is the current way the right one , where we just copy channel 1 to + channel 2 ?? + The current 'strange' thing is, that we throw away the scalefac + values for the second channel ...!! + -> changed .. now we use the scalefac values of channel one !! + */ + } + + if (sblimit > (fr->down_sample_sblimit)) + sblimit = fr->down_sample_sblimit; + + for (i = sblimit; i < SBLIMIT; i++) + for (j = 0; j < stereo; j++) + fraction[j][0][i] = fraction[j][1][i] = fraction[j][2][i] = 0.0; + +} + +static void II_select_table(struct frame *fr) +{ + static int translate[3][2][16] = { + {{0, 2, 2, 2, 2, 2, 2, 0, 0, 0, 1, 1, 1, 1, 1, 0}, + {0, 2, 2, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0}}, + {{0, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, + {{0, 3, 3, 3, 3, 3, 3, 0, 0, 0, 1, 1, 1, 1, 1, 0}, + {0, 3, 3, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0}} + }; + + int table, sblim; + static struct al_table *tables[5] = + {alloc_0, alloc_1, alloc_2, alloc_3, alloc_4}; + static int sblims[5] = { 27, 30, 8, 12, 30 }; + + if (fr->lsf) + table = 4; + else + table = translate[fr->sampling_frequency][2 - fr->stereo][fr->bitrate_index]; + sblim = sblims[table]; + + fr->alloc = tables[table]; + fr->II_sblimit = sblim; +} + + +int mpg123_do_layer2(struct frame *fr) +{ + int i, j; + int stereo = fr->stereo; + real fraction[2][4][SBLIMIT]; /* pick_table clears unused subbands */ + unsigned int bit_alloc[64]; + int scale[192]; + int single = fr->single; + + II_select_table(fr); + fr->jsbound = (fr->mode == MPG_MD_JOINT_STEREO) ? + (fr->mode_ext << 2) + 4 : fr->II_sblimit; + if (fr->jsbound > fr->II_sblimit) + fr->jsbound = fr->II_sblimit; + + if (stereo == 1 || single == 3) + single = 0; + + II_step_one(bit_alloc, scale, fr); + + for (i = 0; i < SCALE_BLOCK; i++) + { + II_step_two(bit_alloc, fraction, scale, fr, i >> 2); + for (j = 0; j < 3; j++) + { + if (single >= 0) + { + (fr->synth_mono) (fraction[single][j], mpg123_pcm_sample, &mpg123_pcm_point); + } + else + { + int p1 = mpg123_pcm_point; + + (fr->synth) (fraction[0][j], 0, mpg123_pcm_sample, &p1); + (fr->synth) (fraction[1][j], 1, mpg123_pcm_sample, &mpg123_pcm_point); + } + + /* if(mpg123_pcm_point >= audiobufsize) + audio_flush(outmode,ai); */ + } + } +/*** + if (mpg123_info->output_audio) + { + + mpg123_ip.add_vis_pcm(mpg123_ip.output->written_time(), mpg123_cfg.resolution == 16 ? FMT_S16_NE : FMT_U8, + mpg123_cfg.channels == 2 ? fr->stereo : 1, mpg123_pcm_point, mpg123_pcm_sample); + + while (mpg123_ip.output->buffer_free() < mpg123_pcm_point && mpg123_info->going && mpg123_info->jump_to_time == -1) + xmms_usleep(10000); + if (mpg123_info->going && mpg123_info->jump_to_time == -1) + mpg123_ip.output->write_audio(mpg123_pcm_sample, mpg123_pcm_point); + + } +***/ + mpg123_pcm_point = 0; + + return 1; +} diff --git a/libmpg123/layer3.c b/libmpg123/layer3.c new file mode 100644 index 0000000..c7cb8cd --- /dev/null +++ b/libmpg123/layer3.c @@ -0,0 +1,2100 @@ + +/* + * Mpeg Layer-3 audio decoder + * -------------------------- + * copyright (c) 1995-1999 by Michael Hipp. + * All rights reserved. See also 'README' + * + * Optimize-TODO: put short bands into the band-field without the stride of 3 reals + * Length-optimze: unify long and short band code where it is possible + */ + +#include +#include "mpg123.h" +#include "huffman.h" + +#include "getbits.h" + +static real ispow[8207]; +static real aa_ca[8], aa_cs[8]; +static real COS1[12][6]; +static real win[4][36]; +static real win1[4][36]; +static real gainpow2[256 + 118 + 4]; +real COS9[9]; +static real COS6_1, COS6_2; +real tfcos36[9]; +static real tfcos12[3]; +#define NEW_DCT9 +#ifdef NEW_DCT9 +static real cos9[3], cos18[3]; +#endif + +struct bandInfoStruct +{ + int longIdx[23]; + int longDiff[22]; + int shortIdx[14]; + int shortDiff[13]; +}; + +int longLimit[9][23]; +int shortLimit[9][14]; + +/* Used by the getbits macros */ +static unsigned long rval; +static unsigned char rval_uc; + +struct bandInfoStruct bandInfo[9] = +{ +/* MPEG 1.0 */ + { {0,4,8,12,16,20,24,30,36,44,52,62,74, 90,110,134,162,196,238,288,342,418,576}, + {4,4,4,4,4,4,6,6,8, 8,10,12,16,20,24,28,34,42,50,54, 76,158}, + {0,4*3,8*3,12*3,16*3,22*3,30*3,40*3,52*3,66*3, 84*3,106*3,136*3,192*3}, + {4,4,4,4,6,8,10,12,14,18,22,30,56} } , + + { {0,4,8,12,16,20,24,30,36,42,50,60,72, 88,106,128,156,190,230,276,330,384,576}, + {4,4,4,4,4,4,6,6,6, 8,10,12,16,18,22,28,34,40,46,54, 54,192}, + {0,4*3,8*3,12*3,16*3,22*3,28*3,38*3,50*3,64*3, 80*3,100*3,126*3,192*3}, + {4,4,4,4,6,6,10,12,14,16,20,26,66} } , + + { {0,4,8,12,16,20,24,30,36,44,54,66,82,102,126,156,194,240,296,364,448,550,576} , + {4,4,4,4,4,4,6,6,8,10,12,16,20,24,30,38,46,56,68,84,102, 26} , + {0,4*3,8*3,12*3,16*3,22*3,30*3,42*3,58*3,78*3,104*3,138*3,180*3,192*3} , + {4,4,4,4,6,8,12,16,20,26,34,42,12} } , + +/* MPEG 2.0 */ + { {0,6,12,18,24,30,36,44,54,66,80,96,116,140,168,200,238,284,336,396,464,522,576}, + {6,6,6,6,6,6,8,10,12,14,16,20,24,28,32,38,46,52,60,68,58,54 } , + {0,4*3,8*3,12*3,18*3,24*3,32*3,42*3,56*3,74*3,100*3,132*3,174*3,192*3} , + {4,4,4,6,6,8,10,14,18,26,32,42,18 } } , +/* + { {0,6,12,18,24,30,36,44,54,66,80,96,114,136,162,194,232,278,330,394,464,540,576}, + {6,6,6,6,6,6,8,10,12,14,16,18,22,26,32,38,46,52,64,70,76,36 } , +*/ +/* changed 19th value fropm 330 to 332 */ + { {0,6,12,18,24,30,36,44,54,66,80,96,114,136,162,194,232,278,332,394,464,540,576}, + {6,6,6,6,6,6,8,10,12,14,16,18,22,26,32,38,46,54,62,70,76,36 } , + {0,4*3,8*3,12*3,18*3,26*3,36*3,48*3,62*3,80*3,104*3,136*3,180*3,192*3} , + {4,4,4,6,8,10,12,14,18,24,32,44,12 } } , + + { {0,6,12,18,24,30,36,44,54,66,80,96,116,140,168,200,238,284,336,396,464,522,576}, + {6,6,6,6,6,6,8,10,12,14,16,20,24,28,32,38,46,52,60,68,58,54 }, + {0,4*3,8*3,12*3,18*3,26*3,36*3,48*3,62*3,80*3,104*3,134*3,174*3,192*3}, + {4,4,4,6,8,10,12,14,18,24,30,40,18 } } , +/* MPEG 2.5 */ + { {0,6,12,18,24,30,36,44,54,66,80,96,116,140,168,200,238,284,336,396,464,522,576} , + {6,6,6,6,6,6,8,10,12,14,16,20,24,28,32,38,46,52,60,68,58,54}, + {0,12,24,36,54,78,108,144,186,240,312,402,522,576}, + {4,4,4,6,8,10,12,14,18,24,30,40,18} }, + { {0,6,12,18,24,30,36,44,54,66,80,96,116,140,168,200,238,284,336,396,464,522,576} , + {6,6,6,6,6,6,8,10,12,14,16,20,24,28,32,38,46,52,60,68,58,54}, + {0,12,24,36,54,78,108,144,186,240,312,402,522,576}, + {4,4,4,6,8,10,12,14,18,24,30,40,18} }, + { {0,12,24,36,48,60,72,88,108,132,160,192,232,280,336,400,476,566,568,570,572,574,576}, + {12,12,12,12,12,12,16,20,24,28,32,40,48,56,64,76,90,2,2,2,2,2}, + {0, 24, 48, 72,108,156,216,288,372,480,486,492,498,576}, + {8,8,8,12,16,20,24,28,36,2,2,2,26} } , +}; + +static int mapbuf0[9][152]; +static int mapbuf1[9][156]; +static int mapbuf2[9][44]; +static int *map[9][3]; +static int *mapend[9][3]; + +static unsigned int n_slen2[512]; /* MPEG 2.0 slen for 'normal' mode */ +static unsigned int i_slen2[256]; /* MPEG 2.0 slen for intensity stereo */ + +static real tan1_1[16], tan2_1[16], tan1_2[16], tan2_2[16]; +static real pow1_1[2][16], pow2_1[2][16], pow1_2[2][16], pow2_2[2][16]; + +/* + * init tables for layer-3 + */ +void mpg123_init_layer3(int down_sample_sblimit) +{ + int i, j, k, l; + + for (i = -256; i < 118 + 4; i++) + gainpow2[i + 256] = pow((double) 2.0, -0.25 * (double) (i + 210)); + + for (i = 0; i < 8207; i++) + ispow[i] = pow((double) i, (double) 4.0 / 3.0); + + for (i = 0; i < 8; i++) + { + static double Ci[8] = + {-0.6, -0.535, -0.33, -0.185, -0.095, -0.041, -0.0142, -0.0037}; + double sq = sqrt(1.0 + Ci[i] * Ci[i]); + + aa_cs[i] = 1.0 / sq; + aa_ca[i] = Ci[i] / sq; + } + + for (i = 0; i < 18; i++) + { + win[0][i] = win[1][i] = 0.5 * sin(M_PI / 72.0 * (double) (2 * (i + 0) + 1)) / cos(M_PI * (double) (2 * (i + 0) + 19) / 72.0); + win[0][i + 18] = win[3][i + 18] = 0.5 * sin(M_PI / 72.0 * (double) (2 * (i + 18) + 1)) / cos(M_PI * (double) (2 * (i + 18) + 19) / 72.0); + } + for (i = 0; i < 6; i++) + { + win[1][i + 18] = 0.5 / cos(M_PI * (double) (2 * (i + 18) + 19) / 72.0); + win[3][i + 12] = 0.5 / cos(M_PI * (double) (2 * (i + 12) + 19) / 72.0); + win[1][i + 24] = 0.5 * sin(M_PI / 24.0 * (double) (2 * i + 13)) / cos(M_PI * (double) (2 * (i + 24) + 19) / 72.0); + win[1][i + 30] = win[3][i] = 0.0; + win[3][i + 6] = 0.5 * sin(M_PI / 24.0 * (double) (2 * i + 1)) / cos(M_PI * (double) (2 * (i + 6) + 19) / 72.0); + } + + for (i = 0; i < 9; i++) + COS9[i] = cos(M_PI / 18.0 * (double) i); + + for (i = 0; i < 9; i++) + tfcos36[i] = 0.5 / cos(M_PI * (double) (i * 2 + 1) / 36.0); + for (i = 0; i < 3; i++) + tfcos12[i] = 0.5 / cos(M_PI * (double) (i * 2 + 1) / 12.0); + + COS6_1 = cos(M_PI / 6.0 * (double) 1); + COS6_2 = cos(M_PI / 6.0 * (double) 2); + +#ifdef NEW_DCT9 + cos9[0] = cos(1.0 * M_PI / 9.0); + cos9[1] = cos(5.0 * M_PI / 9.0); + cos9[2] = cos(7.0 * M_PI / 9.0); + cos18[0] = cos(1.0 * M_PI / 18.0); + cos18[1] = cos(11.0 * M_PI / 18.0); + cos18[2] = cos(13.0 * M_PI / 18.0); +#endif + + for (i = 0; i < 12; i++) + { + win[2][i] = 0.5 * sin(M_PI / 24.0 * (double) (2 * i + 1)) / cos(M_PI * (double) (2 * i + 7) / 24.0); + for (j = 0; j < 6; j++) + COS1[i][j] = cos(M_PI / 24.0 * (double) ((2 * i + 7) * (2 * j + 1))); + } + + for (j = 0; j < 4; j++) + { + static int len[4] = { 36, 36, 12, 36 }; + + for (i = 0; i < len[j]; i += 2) + win1[j][i] = +win[j][i]; + for (i = 1; i < len[j]; i += 2) + win1[j][i] = -win[j][i]; + } + + for (i = 0; i < 16; i++) + { + double t = tan((double) i * M_PI / 12.0); + + tan1_1[i] = t / (1.0 + t); + tan2_1[i] = 1.0 / (1.0 + t); + tan1_2[i] = M_SQRT2 * t / (1.0 + t); + tan2_2[i] = M_SQRT2 / (1.0 + t); + + for (j = 0; j < 2; j++) + { + double base = pow(2.0, -0.25 * (j + 1.0)); + double p1 = 1.0, p2 = 1.0; + + if (i > 0) + { + if (i & 1) + p1 = pow(base, (i + 1.0) * 0.5); + else + p2 = pow(base, i * 0.5); + } + pow1_1[j][i] = p1; + pow2_1[j][i] = p2; + pow1_2[j][i] = M_SQRT2 * p1; + pow2_2[j][i] = M_SQRT2 * p2; + } + } + + for (j = 0; j < 9; j++) + { + struct bandInfoStruct *bi = &bandInfo[j]; + int *mp; + int cb, lwin; + int *bdf; + + mp = map[j][0] = mapbuf0[j]; + bdf = bi->longDiff; + for (i = 0, cb = 0; cb < 8; cb++, i += *bdf++) + { + *mp++ = (*bdf) >> 1; + *mp++ = i; + *mp++ = 3; + *mp++ = cb; + } + bdf = bi->shortDiff + 3; + for (cb = 3; cb < 13; cb++) + { + int l = (*bdf++) >> 1; + + for (lwin = 0; lwin < 3; lwin++) + { + *mp++ = l; + *mp++ = i + lwin; + *mp++ = lwin; + *mp++ = cb; + } + i += 6 * l; + } + mapend[j][0] = mp; + + mp = map[j][1] = mapbuf1[j]; + bdf = bi->shortDiff + 0; + for (i = 0, cb = 0; cb < 13; cb++) + { + int l = (*bdf++) >> 1; + + for (lwin = 0; lwin < 3; lwin++) + { + *mp++ = l; + *mp++ = i + lwin; + *mp++ = lwin; + *mp++ = cb; + } + i += 6 * l; + } + mapend[j][1] = mp; + + mp = map[j][2] = mapbuf2[j]; + bdf = bi->longDiff; + for (cb = 0; cb < 22; cb++) + { + *mp++ = (*bdf++) >> 1; + *mp++ = cb; + } + mapend[j][2] = mp; + + } + + for (j = 0; j < 9; j++) + { + for (i = 0; i < 23; i++) + { + longLimit[j][i] = (bandInfo[j].longIdx[i] - 1 + 8) / 18 + 1; + if (longLimit[j][i] > (down_sample_sblimit)) + longLimit[j][i] = down_sample_sblimit; + } + for (i = 0; i < 14; i++) + { + shortLimit[j][i] = (bandInfo[j].shortIdx[i] - 1) / 18 + 1; + if (shortLimit[j][i] > (down_sample_sblimit)) + shortLimit[j][i] = down_sample_sblimit; + } + } + + for (i = 0; i < 5; i++) + { + for (j = 0; j < 6; j++) + { + for (k = 0; k < 6; k++) + { + int n = k + j * 6 + i * 36; + + i_slen2[n] = i | (j << 3) | (k << 6) | (3 << 12); + } + } + } + for (i = 0; i < 4; i++) + { + for (j = 0; j < 4; j++) + { + for (k = 0; k < 4; k++) + { + int n = k + j * 4 + i * 16; + + i_slen2[n + 180] = i | (j << 3) | (k << 6) | (4 << 12); + } + } + } + for (i = 0; i < 4; i++) + { + for (j = 0; j < 3; j++) + { + int n = j + i * 3; + + i_slen2[n + 244] = i | (j << 3) | (5 << 12); + n_slen2[n + 500] = i | (j << 3) | (2 << 12) | (1 << 15); + } + } + + for (i = 0; i < 5; i++) + { + for (j = 0; j < 5; j++) + { + for (k = 0; k < 4; k++) + { + for (l = 0; l < 4; l++) + { + int n = l + k * 4 + j * 16 + i * 80; + + n_slen2[n] = i | (j << 3) | (k << 6) | (l << 9) | (0 << 12); + } + } + } + } + for (i = 0; i < 5; i++) + { + for (j = 0; j < 5; j++) + { + for (k = 0; k < 4; k++) + { + int n = k + j * 4 + i * 20; + + n_slen2[n + 400] = i | (j << 3) | (k << 6) | (1 << 12); + } + } + } +} + +/* + * read additional side information (for MPEG 1 and MPEG 2) + */ +static int III_get_side_info(struct III_sideinfo *si, int stereo, + int ms_stereo, long sfreq, int single, int lsf) +{ + int ch, gr; + int powdiff = (single == 3) ? 4 : 0; + + static const int tabs[2][5] = { {2, 9, 5, 3, 4}, {1, 8, 1, 2, 9} }; + const int *tab = tabs[lsf]; + + si->main_data_begin = mpg123_getbits(tab[1]); + if (stereo == 1) + si->private_bits = mpg123_getbits_fast(tab[2]); + else + si->private_bits = mpg123_getbits_fast(tab[3]); + + if (!lsf) + { + for (ch = 0; ch < stereo; ch++) + { + si->ch[ch].gr[0].scfsi = -1; + si->ch[ch].gr[1].scfsi = mpg123_getbits_fast(4); + } + } + + for (gr = 0; gr < tab[0]; gr++) + { + for (ch = 0; ch < stereo; ch++) + { + register struct gr_info_s *gr_info = &(si->ch[ch].gr[gr]); + + gr_info->part2_3_length = mpg123_getbits(12); + gr_info->big_values = mpg123_getbits(9); + if (gr_info->big_values > 288) + { + /* fprintf(stderr, "big_values too large!\n"); */ + /* gr_info->big_values = 288; */ + return 0; + } + gr_info->pow2gain = gainpow2 + 256 - mpg123_getbits_fast(8) + powdiff; + if (ms_stereo) + gr_info->pow2gain += 2; + gr_info->scalefac_compress = mpg123_getbits(tab[4]); + + if (mpg123_get1bit()) + { /* window switch flag */ + int i; + + gr_info->block_type = mpg123_getbits_fast(2); + gr_info->mixed_block_flag = mpg123_get1bit(); + gr_info->table_select[0] = mpg123_getbits_fast(5); + gr_info->table_select[1] = mpg123_getbits_fast(5); + /* + * table_select[2] not needed, because + * there is no region2, but to satisfy + * some verifications tools we set it + * either. + */ + gr_info->table_select[2] = 0; + for (i = 0; i < 3; i++) + gr_info->full_gain[i] = gr_info->pow2gain + (mpg123_getbits_fast(3) << 3); + + if (gr_info->block_type == 0) + { + /* fprintf(stderr, "Blocktype == 0 and window-switching == 1 not allowed.\n"); */ + /* exit(1); */ + return 0; + } + + /* region_count/start parameters are implicit in this case. */ + if (!lsf || gr_info->block_type == 2) + gr_info->region1start = 36 >> 1; + else + { + /* check this again for 2.5 and sfreq=8 */ + if (sfreq == 8) + gr_info->region1start = 108 >> 1; + else + gr_info->region1start = 54 >> 1; + } + gr_info->region2start = 576 >> 1; + } + else + { + int i, r0c, r1c; + + for (i = 0; i < 3; i++) + gr_info->table_select[i] = mpg123_getbits_fast(5); + r0c = mpg123_getbits_fast(4); + r1c = mpg123_getbits_fast(3); + gr_info->region1start = bandInfo[sfreq].longIdx[r0c + 1] >> 1; + if (r0c + r1c + 2 > 22) + gr_info->region2start = 576 >> 1; + else + gr_info->region2start = bandInfo[sfreq].longIdx[r0c + 1 + r1c + 1] >> 1; + gr_info->block_type = 0; + gr_info->mixed_block_flag = 0; + } + if (!lsf) + gr_info->preflag = mpg123_get1bit(); + gr_info->scalefac_scale = mpg123_get1bit(); + gr_info->count1table_select = mpg123_get1bit(); + } + } + return 1; +} + + +/* + * read scalefactors + */ +static int III_get_scale_factors_1(int *scf, struct gr_info_s *gr_info) +{ + static const unsigned char slen[2][16] = { + {0, 0, 0, 0, 3, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4}, + {0, 1, 2, 3, 0, 1, 2, 3, 1, 2, 3, 1, 2, 3, 2, 3} + }; + int numbits; + int num0 = slen[0][gr_info->scalefac_compress]; + int num1 = slen[1][gr_info->scalefac_compress]; + + if (gr_info->block_type == 2) + { + int i = 18; + + numbits = (num0 + num1) * 18; + + if (gr_info->mixed_block_flag) + { + for (i = 8; i; i--) + *scf++ = mpg123_getbits_fast(num0); + i = 9; + numbits -= num0; /* num0 * 17 + num1 * 18 */ + } + + for (; i; i--) + *scf++ = mpg123_getbits_fast(num0); + for (i = 18; i; i--) + *scf++ = mpg123_getbits_fast(num1); + *scf++ = 0; + *scf++ = 0; + *scf++ = 0; /* short[13][0..2] = 0 */ + } + else + { + int i; + int scfsi = gr_info->scfsi; + + if (scfsi < 0) + { /* scfsi < 0 => granule == 0 */ + for (i = 11; i; i--) + *scf++ = mpg123_getbits_fast(num0); + for (i = 10; i; i--) + *scf++ = mpg123_getbits_fast(num1); + numbits = (num0 + num1) * 10 + num0; + *scf++ = 0; + } + else + { + numbits = 0; + if (!(scfsi & 0x8)) + { + for (i = 0; i < 6; i++) + *scf++ = mpg123_getbits_fast(num0); + numbits += num0 * 6; + } + else + { + scf += 6; + } + + if (!(scfsi & 0x4)) + { + for (i = 0; i < 5; i++) + *scf++ = mpg123_getbits_fast(num0); + numbits += num0 * 5; + } + else + { + scf += 5; + } + + if (!(scfsi & 0x2)) + { + for (i = 0; i < 5; i++) + *scf++ = mpg123_getbits_fast(num1); + numbits += num1 * 5; + } + else + { + scf += 5; + } + + if (!(scfsi & 0x1)) + { + for (i = 0; i < 5; i++) + *scf++ = mpg123_getbits_fast(num1); + numbits += num1 * 5; + } + else + { + scf += 5; + } + *scf++ = 0; /* no l[21] in original sources */ + } + } + return numbits; +} + +static int III_get_scale_factors_2(int *scf, struct gr_info_s *gr_info, int i_stereo) +{ + unsigned char *pnt; + int i, j, n = 0, numbits = 0; + unsigned int slen; + + static unsigned char stab[3][6][4] = + { + {{6, 5, 5, 5}, {6, 5, 7, 3}, {11, 10, 0, 0}, + {7, 7, 7, 0}, {6, 6, 6, 3}, {8, 8, 5, 0}}, + {{9, 9, 9, 9}, {9, 9, 12, 6}, {18, 18, 0, 0}, + {12, 12, 12, 0}, {12, 9, 9, 6}, {15, 12, 9, 0}}, + {{6, 9, 9, 9}, {6, 9, 12, 6}, {15, 18, 0, 0}, + {6, 15, 12, 0}, {6, 12, 9, 6}, {6, 18, 9, 0}} + }; + + if (i_stereo) /* i_stereo AND second channel -> mpg123_do_layer3() checks this */ + slen = i_slen2[gr_info->scalefac_compress >> 1]; + else + slen = n_slen2[gr_info->scalefac_compress]; + + gr_info->preflag = (slen >> 15) & 0x1; + + n = 0; + if (gr_info->block_type == 2) + { + n++; + if (gr_info->mixed_block_flag) + n++; + } + + pnt = stab[n][(slen >> 12) & 0x7]; + + for (i = 0; i < 4; i++) + { + int num = slen & 0x7; + + slen >>= 3; + if (num) + { + for (j = 0; j < (int) (pnt[i]); j++) + *scf++ = mpg123_getbits_fast(num); + numbits += pnt[i] * num; + } + else + { + for (j = 0; j < (int) (pnt[i]); j++) + *scf++ = 0; + } + } + + n = (n << 1) + 1; + for (i = 0; i < n; i++) + *scf++ = 0; + + return numbits; +} + +static int pretab1[22] = +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 3, 2, 0}; +static int pretab2[22] = +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +/* + * Dequantize samples (includes huffman decoding) + */ +/* 24 is enough because tab13 has max. a 19 bit huffvector */ +#define BITSHIFT (int)((sizeof (long) - 1) * 8) + +#define REFRESH_MASK() \ +while(num < BITSHIFT) { \ + mask |= ((unsigned long)mpg123_getbyte()) << (BITSHIFT - num); \ + num += 8; \ + part2remain -= 8; \ +} + +static int III_dequantize_sample(real xr[SBLIMIT][SSLIMIT], int *scf, + struct gr_info_s *gr_info, int sfreq, int part2bits) +{ + int shift = 1 + gr_info->scalefac_scale; + real *xrpnt = (real *) xr; + int l[3], l3; + int part2remain = gr_info->part2_3_length - part2bits; + int *me; + + int num = mpg123_getbitoffset(); + long mask; + /* we must split this, because for num==0 the shift is undefined if you do it in one step */ + mask = ((unsigned long) mpg123_getbits(num)) << BITSHIFT; + mask <<= 8 - num; + part2remain -= num; + + { + int bv = gr_info->big_values; + int region1 = gr_info->region1start; + int region2 = gr_info->region2start; + + l3 = ((576 >> 1) - bv) >> 1; +/* + * we may lose the 'odd' bit here !! + * check this later again + */ + if (bv <= region1) + { + l[0] = bv; + l[1] = 0; + l[2] = 0; + } + else + { + l[0] = region1; + if (bv <= region2) + { + l[1] = bv - l[0]; + l[2] = 0; + } + else + { + l[1] = region2 - l[0]; + l[2] = bv - region2; + } + } + } + + if (gr_info->block_type == 2) + { + /* + * decoding with short or mixed mode BandIndex table + */ + int i, max[4]; + int step = 0, lwin = 3, cb = 0; + register real v = 0.0; + register int *m, mc; + + if (gr_info->mixed_block_flag) + { + max[3] = -1; + max[0] = max[1] = max[2] = 2; + m = map[sfreq][0]; + me = mapend[sfreq][0]; + } + else + { + max[0] = max[1] = max[2] = max[3] = -1; + /* max[3] not really needed in this case */ + m = map[sfreq][1]; + me = mapend[sfreq][1]; + } + + mc = 0; + for (i = 0; i < 2; i++) + { + int lp = l[i]; + struct newhuff *h = ht + gr_info->table_select[i]; + + for (; lp; lp--, mc--) + { + register int x, y; + if ((!mc)) + { + mc = *m++; + xrpnt = ((real *) xr) + (*m++); + lwin = *m++; + cb = *m++; + if (lwin == 3) + { + v = gr_info->pow2gain[(*scf++) << shift]; + step = 1; + } + else + { + v = gr_info->full_gain[lwin][(*scf++) << shift]; + step = 3; + } + } + { + register short *val = h->table; + + REFRESH_MASK(); + while ((y = *val++) < 0) + { + if (mask < 0) + val -= y; + num--; + mask <<= 1; + } + x = y >> 4; + y &= 0xf; + } + if (x == 15 && h->linbits) + { + max[lwin] = cb; + REFRESH_MASK(); + x += ((unsigned long) mask) >> (BITSHIFT + 8 - h->linbits); + num -= h->linbits + 1; + mask <<= h->linbits; + if (mask < 0) + *xrpnt = -ispow[x] * v; + else + *xrpnt = ispow[x] * v; + mask <<= 1; + } + else if (x) + { + max[lwin] = cb; + if (mask < 0) + *xrpnt = -ispow[x] * v; + else + *xrpnt = ispow[x] * v; + num--; + mask <<= 1; + } + else + *xrpnt = 0.0; + xrpnt += step; + if (y == 15 && h->linbits) + { + max[lwin] = cb; + REFRESH_MASK(); + y += ((unsigned long) mask) >> (BITSHIFT + 8 - h->linbits); + num -= h->linbits + 1; + mask <<= h->linbits; + if (mask < 0) + *xrpnt = -ispow[y] * v; + else + *xrpnt = ispow[y] * v; + mask <<= 1; + } + else if (y) + { + max[lwin] = cb; + if (mask < 0) + *xrpnt = -ispow[y] * v; + else + *xrpnt = ispow[y] * v; + num--; + mask <<= 1; + } + else + *xrpnt = 0.0; + xrpnt += step; + } + } + + for (; l3 && (part2remain + num > 0); l3--) + { + struct newhuff *h = htc + gr_info->count1table_select; + register short *val = h->table, a; + + REFRESH_MASK(); + while ((a = *val++) < 0) + { + if (mask < 0) + val -= a; + num--; + mask <<= 1; + } + if (part2remain + num <= 0) + { + num -= part2remain + num; + break; + } + + for (i = 0; i < 4; i++) + { + if (!(i & 1)) + { + if (!mc) + { + mc = *m++; + xrpnt = ((real *) xr) + (*m++); + lwin = *m++; + cb = *m++; + if (lwin == 3) + { + v = gr_info->pow2gain[(*scf++) << shift]; + step = 1; + } + else + { + v = gr_info->full_gain[lwin][(*scf++) << shift]; + step = 3; + } + } + mc--; + } + if ((a & (0x8 >> i))) + { + max[lwin] = cb; + if (part2remain + num <= 0) + { + break; + } + if (mask < 0) + *xrpnt = -v; + else + *xrpnt = v; + num--; + mask <<= 1; + } + else + *xrpnt = 0.0; + xrpnt += step; + } + } + + if (lwin < 3) + { /* short band? */ + while (1) + { + /* HACK Prevent overflowing the xr buffer */ + if (mc * 6 > &xr[SBLIMIT][SSLIMIT] - xrpnt) + return 1; + + for (; mc > 0; mc--) + { + *xrpnt = 0.0; + xrpnt += 3; /* short band -> step=3 */ + *xrpnt = 0.0; + xrpnt += 3; + } + if (m >= me) + break; + mc = *m++; + xrpnt = ((real *) xr) + *m++; + if (*m++ == 0) + break; /* optimize: field will be set to zero at the end of the function */ + m++; /* cb */ + } + } + + gr_info->maxband[0] = max[0] + 1; + gr_info->maxband[1] = max[1] + 1; + gr_info->maxband[2] = max[2] + 1; + gr_info->maxbandl = max[3] + 1; + + { + int rmax = max[0] > max[1] ? max[0] : max[1]; + + rmax = (rmax > max[2] ? rmax : max[2]) + 1; + gr_info->maxb = rmax ? shortLimit[sfreq][rmax] : longLimit[sfreq][max[3] + 1]; + } + + } + else + { + /* + * decoding with 'long' BandIndex table (block_type != 2) + */ + int *pretab = gr_info->preflag ? pretab1 : pretab2; + int i, max = -1; + int cb = 0; + int *m = map[sfreq][2]; + register real v = 0.0; + int mc = 0; + + /* + * long hash table values + */ + for (i = 0; i < 3; i++) + { + int lp = l[i]; + struct newhuff *h = ht + gr_info->table_select[i]; + + for (; lp; lp--, mc--) + { + int x, y; + + if (!mc) + { + mc = *m++; + cb = *m++; +/* if (cb == 21) */ +/* v = 0.0; */ +/* else */ + v = gr_info->pow2gain[((*scf++) + (*pretab++)) << shift]; + + } + { + register short *val = h->table; + REFRESH_MASK(); + while ((y = *val++) < 0) + { + if (mask < 0) + val -= y; + num--; + mask <<= 1; + } + x = y >> 4; + y &= 0xf; + } + + if (x == 15 && h->linbits) + { + max = cb; + REFRESH_MASK(); + x += ((unsigned long) mask) >> (BITSHIFT + 8 - h->linbits); + num -= h->linbits + 1; + mask <<= h->linbits; + if (mask < 0) + *xrpnt++ = -ispow[x] * v; + else + *xrpnt++ = ispow[x] * v; + mask <<= 1; + } + else if (x) + { + max = cb; + if (mask < 0) + *xrpnt++ = -ispow[x] * v; + else + *xrpnt++ = ispow[x] * v; + num--; + mask <<= 1; + } + else + *xrpnt++ = 0.0; + + if (y == 15 && h->linbits) + { + max = cb; + REFRESH_MASK(); + y += ((unsigned long) mask) >> (BITSHIFT + 8 - h->linbits); + num -= h->linbits + 1; + mask <<= h->linbits; + if (mask < 0) + *xrpnt++ = -ispow[y] * v; + else + *xrpnt++ = ispow[y] * v; + mask <<= 1; + } + else if (y) + { + max = cb; + if (mask < 0) + *xrpnt++ = -ispow[y] * v; + else + *xrpnt++ = ispow[y] * v; + num--; + mask <<= 1; + } + else + *xrpnt++ = 0.0; + } + } + + /* + * short (count1table) values + */ + for (; l3 && (part2remain + num > 0); l3--) + { + struct newhuff *h = htc + gr_info->count1table_select; + register short *val = h->table, a; + + REFRESH_MASK(); + while ((a = *val++) < 0) + { + if (mask < 0) + val -= a; + num--; + mask <<= 1; + } + if (part2remain + num <= 0) + { + num -= part2remain + num; + break; + } + + for (i = 0; i < 4; i++) + { + if (!(i & 1)) + { + if (!mc) + { + mc = *m++; + cb = *m++; +/* if (cb == 21) */ +/* v = 0.0; */ +/* else */ + v = gr_info->pow2gain[((*scf++) + (*pretab++)) << shift]; + } + mc--; + } + if ((a & (0x8 >> i))) + { + max = cb; + if (part2remain + num <= 0) + { + break; + } + if (mask < 0) + *xrpnt++ = -v; + else + *xrpnt++ = v; + num--; + mask <<= 1; + } + else + *xrpnt++ = 0.0; + } + } + + gr_info->maxbandl = max + 1; + gr_info->maxb = longLimit[sfreq][gr_info->maxbandl]; + } + + part2remain += num; + mpg123_backbits(num); + num = 0; + + while (xrpnt < &xr[SBLIMIT][0]) + *xrpnt++ = 0.0; + + while (part2remain > 16) + { + mpg123_getbits(16); /* Dismiss stuffing Bits */ + part2remain -= 16; + } + if (part2remain > 0) + mpg123_getbits(part2remain); + else if (part2remain < 0) + { +/* fprintf(stderr, "mpg123: Can't rewind stream by %d bits!\n", */ +/* -part2remain); */ + return 1; /* -> error */ + } + return 0; +} + +/* + * III_stereo: calculate real channel values for Joint-I-Stereo-mode + */ +static void III_i_stereo(real xr_buf[2][SBLIMIT][SSLIMIT], int *scalefac, struct gr_info_s *gr_info, int sfreq, int ms_stereo, int lsf) +{ + real(*xr)[SBLIMIT * SSLIMIT] = (real(*)[SBLIMIT * SSLIMIT]) xr_buf; + struct bandInfoStruct *bi = &bandInfo[sfreq]; + + const real *tab1, *tab2; + +#if 1 + int tab; + static const real *tabs[3][2][2] = { + {{tan1_1, tan2_1}, {tan1_2, tan2_2}}, + {{pow1_1[0], pow2_1[0]}, {pow1_2[0], pow2_2[0]}}, + {{pow1_1[1], pow2_1[1]}, {pow1_2[1], pow2_2[1]}} + }; + + tab = lsf + (gr_info->scalefac_compress & lsf); + tab1 = tabs[tab][ms_stereo][0]; + tab2 = tabs[tab][ms_stereo][1]; +#else + if (lsf) + { + int p = gr_info->scalefac_compress & 0x1; + + if (ms_stereo) + { + tab1 = pow1_2[p]; + tab2 = pow2_2[p]; + } + else + { + tab1 = pow1_1[p]; + tab2 = pow2_1[p]; + } + } + else + { + if (ms_stereo) + { + tab1 = tan1_2; + tab2 = tan2_2; + } + else + { + tab1 = tan1_1; + tab2 = tan2_1; + } + } +#endif + + if (gr_info->block_type == 2) + { + int lwin, do_l = 0; + + if (gr_info->mixed_block_flag) + do_l = 1; + + for (lwin = 0; lwin < 3; lwin++) + { /* process each window */ + /* get first band with zero values */ + int is_p, sb, idx, sfb = gr_info->maxband[lwin]; /* sfb is minimal 3 for mixed mode */ + + if (sfb > 3) + do_l = 0; + + for (; sfb < 12; sfb++) + { + is_p = scalefac[sfb * 3 + lwin - gr_info->mixed_block_flag]; /* scale: 0-15 */ + if (is_p != 7) + { + real t1, t2; + + sb = bi->shortDiff[sfb]; + idx = bi->shortIdx[sfb] + lwin; + t1 = tab1[is_p]; + t2 = tab2[is_p]; + for (; sb > 0; sb--, idx += 3) + { + real v = xr[0][idx]; + + xr[0][idx] = v * t1; + xr[1][idx] = v * t2; + } + } + } + +#if 1 +/* in the original: copy 10 to 11 , here: copy 11 to 12 + maybe still wrong??? (copy 12 to 13?) */ + is_p = scalefac[11 * 3 + lwin - gr_info->mixed_block_flag]; /* scale: 0-15 */ + sb = bi->shortDiff[12]; + idx = bi->shortIdx[12] + lwin; +#else + is_p = scalefac[10 * 3 + lwin - gr_info->mixed_block_flag]; /* scale: 0-15 */ + sb = bi->shortDiff[11]; + idx = bi->shortIdx[11] + lwin; +#endif + if (is_p != 7) + { + real t1, t2; + t1 = tab1[is_p]; + t2 = tab2[is_p]; + for (; sb > 0; sb--, idx += 3) + { + real v = xr[0][idx]; + xr[0][idx] = v * t1; + xr[1][idx] = v * t2; + } + } + } /* end for(lwin; .. ; . ) */ + +/* also check l-part, if ALL bands in the three windows are 'empty' + * and mode = mixed_mode + */ + if (do_l) + { + int sfb = gr_info->maxbandl; + int idx = bi->longIdx[sfb]; + + for (; sfb < 8; sfb++) + { + int sb = bi->longDiff[sfb]; + int is_p = scalefac[sfb]; /* scale: 0-15 */ + + if (is_p != 7) + { + real t1, t2; + + t1 = tab1[is_p]; + t2 = tab2[is_p]; + for (; sb > 0; sb--, idx++) + { + real v = xr[0][idx]; + + xr[0][idx] = v * t1; + xr[1][idx] = v * t2; + } + } + else + idx += sb; + } + } + } + else + { /* ((gr_info->block_type != 2)) */ + int sfb = gr_info->maxbandl; + int is_p, idx = bi->longIdx[sfb]; + +/* hmm ... maybe the maxbandl stuff for i-stereo is buggy? */ + if (sfb <= 21) + { + for (; sfb < 21; sfb++) + { + int sb = bi->longDiff[sfb]; + + is_p = scalefac[sfb]; /* scale: 0-15 */ + if (is_p != 7) + { + real t1, t2; + t1 = tab1[is_p]; + t2 = tab2[is_p]; + for (; sb > 0; sb--, idx++) + { + real v = xr[0][idx]; + xr[0][idx] = v * t1; + xr[1][idx] = v * t2; + } + } + else + idx += sb; + } + + is_p = scalefac[20]; + if (is_p != 7) + { /* copy l-band 20 to l-band 21 */ + int sb; + real t1 = tab1[is_p], t2 = tab2[is_p]; + + for (sb = bi->longDiff[21]; sb > 0; sb--, idx++) + { + real v = xr[0][idx]; + + xr[0][idx] = v * t1; + xr[1][idx] = v * t2; + } + } + } + } /* ... */ +} + +static void III_antialias(real xr[SBLIMIT][SSLIMIT], struct gr_info_s *gr_info) +{ + int sblim; + + if (gr_info->block_type == 2) + { + if (!gr_info->mixed_block_flag) + return; + sblim = 1; + } + else + { + sblim = gr_info->maxb - 1; + } + + /* 31 alias-reduction operations between each pair of sub-bands */ + /* with 8 butterflies between each pair */ + + { + int sb; + real *xr1 = (real *) xr[1]; + + if (sblim < 1 || sblim > SBLIMIT) + return; + + for (sb = sblim; sb; sb--, xr1 += 10) + { + int ss; + real *cs = aa_cs, *ca = aa_ca; + real *xr2 = xr1; + + for (ss = 7; ss >= 0; ss--) + { /* upper and lower butterfly inputs */ + register real bu = *--xr2, bd = *xr1; + + *xr2 = (bu * (*cs)) - (bd * (*ca)); + *xr1++ = (bd * (*cs++)) + (bu * (*ca++)); + } + } + } +} + +/* + This is an optimized DCT from Jeff Tsay's maplay 1.2+ package. + Saved one multiplication by doing the 'twiddle factor' stuff + together with the window mul. (MH) + + This uses Byeong Gi Lee's Fast Cosine Transform algorithm, but the + 9 point IDCT needs to be reduced further. Unfortunately, I don't + know how to do that, because 9 is not an even number. - Jeff. + + **************************************************************** + + 9 Point Inverse Discrete Cosine Transform + + This piece of code is Copyright 1997 Mikko Tommila and is freely usable + by anybody. The algorithm itself is of course in the public domain. + + Again derived heuristically from the 9-point WFTA. + + The algorithm is optimized (?) for speed, not for small rounding errors or + good readability. + + 36 additions, 11 multiplications + + Again this is very likely sub-optimal. + + The code is optimized to use a minimum number of temporary variables, + so it should compile quite well even on 8-register Intel x86 processors. + This makes the code quite obfuscated and very difficult to understand. + + References: + [1] S. Winograd: "On Computing the Discrete Fourier Transform", + Mathematics of Computation, Volume 32, Number 141, January 1978, + Pages 175-199 +*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Function: Calculation of the inverse MDCT */ +/* */ +/*------------------------------------------------------------------*/ + +#ifdef USE_3DNOW +void dct36(real *inbuf,real *o1,real *o2,real *wintab,real *tsbuf) +#else +static void dct36(real * inbuf, real * o1, real * o2, real * wintab, real * tsbuf) +#endif +{ +#ifdef NEW_DCT9 + real tmp[18]; +#endif + + { + register real *in = inbuf; + + in[17] += in[16]; + in[16] += in[15]; + in[15] += in[14]; + in[14] += in[13]; + in[13] += in[12]; + in[12] += in[11]; + in[11] += in[10]; + in[10] += in[9]; + in[9] += in[8]; + in[8] += in[7]; + in[7] += in[6]; + in[6] += in[5]; + in[5] += in[4]; + in[4] += in[3]; + in[3] += in[2]; + in[2] += in[1]; + in[1] += in[0]; + + in[17] += in[15]; + in[15] += in[13]; + in[13] += in[11]; + in[11] += in[9]; + in[9] += in[7]; + in[7] += in[5]; + in[5] += in[3]; + in[3] += in[1]; + + +#ifdef NEW_DCT9 +#if 1 + { + real t3; + { + real t0, t1, t2; + + t0 = COS6_2 * (in[8] + in[16] - in[4]); + t1 = COS6_2 * in[12]; + + t3 = in[0]; + t2 = t3 - t1 - t1; + tmp[1] = tmp[7] = t2 - t0; + tmp[4] = t2 + t0 + t0; + t3 += t1; + + t2 = COS6_1 * (in[10] + in[14] - in[2]); + tmp[1] -= t2; + tmp[7] += t2; + } + { + real t0, t1, t2; + + t0 = cos9[0] * (in[4] + in[8]); + t1 = cos9[1] * (in[8] - in[16]); + t2 = cos9[2] * (in[4] + in[16]); + + tmp[2] = tmp[6] = t3 - t0 - t2; + tmp[0] = tmp[8] = t3 + t0 + t1; + tmp[3] = tmp[5] = t3 - t1 + t2; + } + } + { + real t1, t2, t3; + + t1 = cos18[0] * (in[2] + in[10]); + t2 = cos18[1] * (in[10] - in[14]); + t3 = COS6_1 * in[6]; + + { + real t0 = t1 + t2 + t3; + tmp[0] += t0; + tmp[8] -= t0; + } + + t2 -= t3; + t1 -= t3; + + t3 = cos18[2] * (in[2] + in[14]); + + t1 += t3; + tmp[3] += t1; + tmp[5] -= t1; + + t2 -= t3; + tmp[2] += t2; + tmp[6] -= t2; + } + +#else + { + real t0, t1, t2, t3, t4, t5, t6, t7; + + t1 = COS6_2 * in[12]; + t2 = COS6_2 * (in[8] + in[16] - in[4]); + + t3 = in[0] + t1; + t4 = in[0] - t1 - t1; + t5 = t4 - t2; + tmp[4] = t4 + t2 + t2; + + t0 = cos9[0] * (in[4] + in[8]); + t1 = cos9[1] * (in[8] - in[16]); + + t2 = cos9[2] * (in[4] + in[16]); + + t6 = t3 - t0 - t2; + t0 += t3 + t1; + t3 += t2 - t1; + + t2 = cos18[0] * (in[2] + in[10]); + t4 = cos18[1] * (in[10] - in[14]); + t7 = COS6_1 * in[6]; + + t1 = t2 + t4 + t7; + tmp[0] = t0 + t1; + tmp[8] = t0 - t1; + t1 = cos18[2] * (in[2] + in[14]); + t2 += t1 - t7; + + tmp[3] = t3 + t2; + t0 = COS6_1 * (in[10] + in[14] - in[2]); + tmp[5] = t3 - t2; + + t4 -= t1 + t7; + + tmp[1] = t5 - t0; + tmp[7] = t5 + t0; + tmp[2] = t6 + t4; + tmp[6] = t6 - t4; + } +#endif + + { + real t0, t1, t2, t3, t4, t5, t6, t7; + + t1 = COS6_2 * in[13]; + t2 = COS6_2 * (in[9] + in[17] - in[5]); + + t3 = in[1] + t1; + t4 = in[1] - t1 - t1; + t5 = t4 - t2; + + t0 = cos9[0] * (in[5] + in[9]); + t1 = cos9[1] * (in[9] - in[17]); + + tmp[13] = (t4 + t2 + t2) * tfcos36[17 - 13]; + t2 = cos9[2] * (in[5] + in[17]); + + t6 = t3 - t0 - t2; + t0 += t3 + t1; + t3 += t2 - t1; + + t2 = cos18[0] * (in[3] + in[11]); + t4 = cos18[1] * (in[11] - in[15]); + t7 = COS6_1 * in[7]; + + t1 = t2 + t4 + t7; + tmp[17] = (t0 + t1) * tfcos36[17 - 17]; + tmp[9] = (t0 - t1) * tfcos36[17 - 9]; + t1 = cos18[2] * (in[3] + in[15]); + t2 += t1 - t7; + + tmp[14] = (t3 + t2) * tfcos36[17 - 14]; + t0 = COS6_1 * (in[11] + in[15] - in[3]); + tmp[12] = (t3 - t2) * tfcos36[17 - 12]; + + t4 -= t1 + t7; + + tmp[16] = (t5 - t0) * tfcos36[17 - 16]; + tmp[10] = (t5 + t0) * tfcos36[17 - 10]; + tmp[15] = (t6 + t4) * tfcos36[17 - 15]; + tmp[11] = (t6 - t4) * tfcos36[17 - 11]; + } + +#define MACRO(v) \ +do { \ + real tmpval; \ + \ + tmpval = tmp[(v)] + tmp[17-(v)]; \ + out2[9+(v)] = tmpval * w[27+(v)]; \ + out2[8-(v)] = tmpval * w[26-(v)]; \ + tmpval = tmp[(v)] - tmp[17-(v)]; \ + ts[SBLIMIT*(8-(v))] = out1[8-(v)] + tmpval * w[8-(v)]; \ + ts[SBLIMIT*(9+(v))] = out1[9+(v)] + tmpval * w[9+(v)]; \ +} while (0) + + { + register real *out2 = o2; + register real *w = wintab; + register real *out1 = o1; + register real *ts = tsbuf; + + MACRO(0); + MACRO(1); + MACRO(2); + MACRO(3); + MACRO(4); + MACRO(5); + MACRO(6); + MACRO(7); + MACRO(8); + } + +#else + + { + +#define MACRO0(v) \ +do { \ + real tmp; \ + out2[9+(v)] = (tmp = sum0 + sum1) * w[27+(v)]; \ + out2[8-(v)] = tmp * w[26-(v)]; \ + sum0 -= sum1; \ + ts[SBLIMIT*(8-(v))] = out1[8-(v)] + sum0 * w[8-(v)]; \ + ts[SBLIMIT*(9+(v))] = out1[9+(v)] + sum0 * w[9+(v)]; \ +} while (0) + +#define MACRO1(v) \ +do { \ + real sum0,sum1; \ + sum0 = tmp1a + tmp2a; \ + sum1 = (tmp1b + tmp2b) * tfcos36[(v)]; \ + MACRO0(v); \ +} while (0) + +#define MACRO2(v) \ +do { \ + real sum0, sum1; \ + sum0 = tmp2a - tmp1a; \ + sum1 = (tmp2b - tmp1b) * tfcos36[(v)]; \ + MACRO0(v); \ +} while (0) + + register const real *c = COS9; + register real *out2 = o2; + register real *w = wintab; + register real *out1 = o1; + register real *ts = tsbuf; + + real ta33, ta66, tb33, tb66; + + ta33 = in[2 * 3 + 0] * c[3]; + ta66 = in[2 * 6 + 0] * c[6] + in[2 * 0 + 0]; + tb33 = in[2 * 3 + 1] * c[3]; + tb66 = in[2 * 6 + 1] * c[6] + in[2 * 0 + 1]; + + { + real tmp1a, tmp2a, tmp1b, tmp2b; + tmp1a = in[2 * 1 + 0] * c[1] + ta33 + in[2 * 5 + 0] * c[5] + in[2 * 7 + 0] * c[7]; + tmp1b = in[2 * 1 + 1] * c[1] + tb33 + in[2 * 5 + 1] * c[5] + in[2 * 7 + 1] * c[7]; + tmp2a = in[2 * 2 + 0] * c[2] + in[2 * 4 + 0] * c[4] + ta66 + in[2 * 8 + 0] * c[8]; + tmp2b = in[2 * 2 + 1] * c[2] + in[2 * 4 + 1] * c[4] + tb66 + in[2 * 8 + 1] * c[8]; + + MACRO1(0); + MACRO2(8); + } + + { + real tmp1a, tmp2a, tmp1b, tmp2b; + tmp1a = (in[2 * 1 + 0] - in[2 * 5 + 0] - in[2 * 7 + 0]) * c[3]; + tmp1b = (in[2 * 1 + 1] - in[2 * 5 + 1] - in[2 * 7 + 1]) * c[3]; + tmp2a = (in[2 * 2 + 0] - in[2 * 4 + 0] - in[2 * 8 + 0]) * c[6] - in[2 * 6 + 0] + in[2 * 0 + 0]; + tmp2b = (in[2 * 2 + 1] - in[2 * 4 + 1] - in[2 * 8 + 1]) * c[6] - in[2 * 6 + 1] + in[2 * 0 + 1]; + + MACRO1(1); + MACRO2(7); + } + + { + real tmp1a, tmp2a, tmp1b, tmp2b; + tmp1a = in[2 * 1 + 0] * c[5] - ta33 - in[2 * 5 + 0] * c[7] + in[2 * 7 + 0] * c[1]; + tmp1b = in[2 * 1 + 1] * c[5] - tb33 - in[2 * 5 + 1] * c[7] + in[2 * 7 + 1] * c[1]; + tmp2a = -in[2 * 2 + 0] * c[8] - in[2 * 4 + 0] * c[2] + ta66 + in[2 * 8 + 0] * c[4]; + tmp2b = -in[2 * 2 + 1] * c[8] - in[2 * 4 + 1] * c[2] + tb66 + in[2 * 8 + 1] * c[4]; + + MACRO1(2); + MACRO2(6); + } + + { + real tmp1a, tmp2a, tmp1b, tmp2b; + tmp1a = in[2 * 1 + 0] * c[7] - ta33 + in[2 * 5 + 0] * c[1] - in[2 * 7 + 0] * c[5]; + tmp1b = in[2 * 1 + 1] * c[7] - tb33 + in[2 * 5 + 1] * c[1] - in[2 * 7 + 1] * c[5]; + tmp2a = -in[2 * 2 + 0] * c[4] + in[2 * 4 + 0] * c[8] + ta66 - in[2 * 8 + 0] * c[2]; + tmp2b = -in[2 * 2 + 1] * c[4] + in[2 * 4 + 1] * c[8] + tb66 - in[2 * 8 + 1] * c[2]; + + MACRO1(3); + MACRO2(5); + } + + { + real sum0, sum1; + + sum0 = in[2 * 0 + 0] - in[2 * 2 + 0] + in[2 * 4 + 0] - in[2 * 6 + 0] + in[2 * 8 + 0]; + sum1 = (in[2 * 0 + 1] - in[2 * 2 + 1] + in[2 * 4 + 1] - in[2 * 6 + 1] + in[2 * 8 + 1]) * tfcos36[4]; + MACRO0(4); + } + } +#endif + + } +} + +/* + * new DCT12 + */ +static void dct12(real * in, real * rawout1, real * rawout2, register real * wi, register real * ts) +{ + +#define DCT12_PART1() \ +do { \ + in5 = in[5*3]; \ + in5 += (in4 = in[4*3]); \ + in4 += (in3 = in[3*3]); \ + in3 += (in2 = in[2*3]); \ + in2 += (in1 = in[1*3]); \ + in1 += (in0 = in[0*3]); \ + \ + in5 += in3; in3 += in1; \ + \ + in2 *= COS6_1; \ + in3 *= COS6_1; \ +} while (0) + +#define DCT12_PART2() \ +do { \ + in0 += in4 * COS6_2; \ + \ + in4 = in0 + in2; \ + in0 -= in2; \ + \ + in1 += in5 * COS6_2; \ + \ + in5 = (in1 + in3) * tfcos12[0]; \ + in1 = (in1 - in3) * tfcos12[2]; \ + \ + in3 = in4 + in5; \ + in4 -= in5; \ + \ + in2 = in0 + in1; \ + in0 -= in1; \ +} while (0) + + + { + real in0, in1, in2, in3, in4, in5; + register real *out1 = rawout1; + + ts[SBLIMIT * 0] = out1[0]; + ts[SBLIMIT * 1] = out1[1]; + ts[SBLIMIT * 2] = out1[2]; + ts[SBLIMIT * 3] = out1[3]; + ts[SBLIMIT * 4] = out1[4]; + ts[SBLIMIT * 5] = out1[5]; + + DCT12_PART1(); + + { + real tmp0, tmp1 = (in0 - in4); + + { + real tmp2 = (in1 - in5) * tfcos12[1]; + + tmp0 = tmp1 + tmp2; + tmp1 -= tmp2; + } + ts[(17 - 1) * SBLIMIT] = out1[17 - 1] + tmp0 * wi[11 - 1]; + ts[(12 + 1) * SBLIMIT] = out1[12 + 1] + tmp0 * wi[6 + 1]; + ts[(6 + 1) * SBLIMIT] = out1[6 + 1] + tmp1 * wi[1]; + ts[(11 - 1) * SBLIMIT] = out1[11 - 1] + tmp1 * wi[5 - 1]; + } + + DCT12_PART2(); + + ts[(17 - 0) * SBLIMIT] = out1[17 - 0] + in2 * wi[11 - 0]; + ts[(12 + 0) * SBLIMIT] = out1[12 + 0] + in2 * wi[6 + 0]; + ts[(12 + 2) * SBLIMIT] = out1[12 + 2] + in3 * wi[6 + 2]; + ts[(17 - 2) * SBLIMIT] = out1[17 - 2] + in3 * wi[11 - 2]; + + ts[(6 + 0) * SBLIMIT] = out1[6 + 0] + in0 * wi[0]; + ts[(11 - 0) * SBLIMIT] = out1[11 - 0] + in0 * wi[5 - 0]; + ts[(6 + 2) * SBLIMIT] = out1[6 + 2] + in4 * wi[2]; + ts[(11 - 2) * SBLIMIT] = out1[11 - 2] + in4 * wi[5 - 2]; + } + + in++; + + { + real in0, in1, in2, in3, in4, in5; + register real *out2 = rawout2; + + DCT12_PART1(); + + { + real tmp0, tmp1 = (in0 - in4); + + { + real tmp2 = (in1 - in5) * tfcos12[1]; + + tmp0 = tmp1 + tmp2; + tmp1 -= tmp2; + } + out2[5 - 1] = tmp0 * wi[11 - 1]; + out2[0 + 1] = tmp0 * wi[6 + 1]; + ts[(12 + 1) * SBLIMIT] += tmp1 * wi[1]; + ts[(17 - 1) * SBLIMIT] += tmp1 * wi[5 - 1]; + } + + DCT12_PART2(); + + out2[5 - 0] = in2 * wi[11 - 0]; + out2[0 + 0] = in2 * wi[6 + 0]; + out2[0 + 2] = in3 * wi[6 + 2]; + out2[5 - 2] = in3 * wi[11 - 2]; + + ts[(12 + 0) * SBLIMIT] += in0 * wi[0]; + ts[(17 - 0) * SBLIMIT] += in0 * wi[5 - 0]; + ts[(12 + 2) * SBLIMIT] += in4 * wi[2]; + ts[(17 - 2) * SBLIMIT] += in4 * wi[5 - 2]; + } + + in++; + + { + real in0, in1, in2, in3, in4, in5; + register real *out2 = rawout2; + + out2[12] = out2[13] = out2[14] = out2[15] = out2[16] = out2[17] = 0.0; + + DCT12_PART1(); + + { + real tmp0, tmp1 = (in0 - in4); + + { + real tmp2 = (in1 - in5) * tfcos12[1]; + + tmp0 = tmp1 + tmp2; + tmp1 -= tmp2; + } + out2[11 - 1] = tmp0 * wi[11 - 1]; + out2[6 + 1] = tmp0 * wi[6 + 1]; + out2[0 + 1] += tmp1 * wi[1]; + out2[5 - 1] += tmp1 * wi[5 - 1]; + } + + DCT12_PART2(); + + out2[11 - 0] = in2 * wi[11 - 0]; + out2[6 + 0] = in2 * wi[6 + 0]; + out2[6 + 2] = in3 * wi[6 + 2]; + out2[11 - 2] = in3 * wi[11 - 2]; + + out2[0 + 0] += in0 * wi[0]; + out2[5 - 0] += in0 * wi[5 - 0]; + out2[0 + 2] += in4 * wi[2]; + out2[5 - 2] += in4 * wi[5 - 2]; + } +} + +/* + * III_hybrid + */ +static void III_hybrid(real fsIn[SBLIMIT][SSLIMIT], + real tsOut[SSLIMIT][SBLIMIT], int ch, + struct gr_info_s *gr_info, struct frame *fr) +{ + static real block[2][2][SBLIMIT * SSLIMIT] = { {{0,}} }; + static int blc[2] = { 0, 0 }; + + real *tspnt = (real *) tsOut; + real *rawout1, *rawout2; + int bt; + unsigned sb = 0; + + { + int b = blc[ch]; + rawout1 = block[b][ch]; + b = -b + 1; + rawout2 = block[b][ch]; + blc[ch] = b; + } + + if (gr_info->mixed_block_flag) + { + sb = 2; +#ifdef USE_3DNOW + (fr->dct36)(fsIn[0],rawout1,rawout2,win[0],tspnt); + (fr->dct36)(fsIn[1],rawout1+18,rawout2+18,win1[0],tspnt+1); +#else + dct36(fsIn[0], rawout1, rawout2, win[0], tspnt); + dct36(fsIn[1], rawout1 + 18, rawout2 + 18, win1[0], tspnt + 1); +#endif + rawout1 += 36; + rawout2 += 36; + tspnt += 2; + } + + bt = gr_info->block_type; + if (bt == 2) + { + for (; sb < gr_info->maxb; sb += 2, tspnt += 2, rawout1 += 36, rawout2 += 36) + { + dct12(fsIn[sb], rawout1, rawout2, win[2], tspnt); + dct12(fsIn[sb + 1], rawout1 + 18, rawout2 + 18, win1[2], tspnt + 1); + } + } + else + { + for (; sb < gr_info->maxb; sb += 2, tspnt += 2, rawout1 += 36, rawout2 += 36) + { +#ifdef USE_3DNOW + (fr->dct36)(fsIn[sb],rawout1,rawout2,win[bt],tspnt); + (fr->dct36)(fsIn[sb+1],rawout1+18,rawout2+18,win1[bt],tspnt+1); +#else + dct36(fsIn[sb], rawout1, rawout2, win[bt], tspnt); + dct36(fsIn[sb + 1], rawout1 + 18, rawout2 + 18, win1[bt], tspnt + 1); +#endif + } + } + + for (; sb < SBLIMIT; sb++, tspnt++) + { + int i; + for (i = 0; i < SSLIMIT; i++) + { + tspnt[i * SBLIMIT] = *rawout1++; + *rawout2++ = 0.0; + } + } +} + +/* + * main layer3 handler + */ +int mpg123_do_layer3(struct frame *fr) +{ + int gr, ch, ss; + int scalefacs[2][39]; /* max 39 for short[13][3] mode, mixed: 38, long: 22 */ + struct III_sideinfo sideinfo; + int stereo = fr->stereo; + int single = fr->single; + int ms_stereo, i_stereo; + int sfreq = fr->sampling_frequency; + int stereo1, granules; + + if (stereo == 1) + { /* stream is mono */ + stereo1 = 1; + single = 0; + } + else if (single >= 0) /* stream is stereo, but force to mono */ + stereo1 = 1; + else + stereo1 = 2; + + if (fr->mode == MPG_MD_JOINT_STEREO) + { + ms_stereo = (fr->mode_ext & 0x2) >> 1; + i_stereo = fr->mode_ext & 0x1; + } + else + ms_stereo = i_stereo = 0; + + granules = fr->lsf ? 1 : 2; + if (!III_get_side_info(&sideinfo, stereo, ms_stereo, sfreq, single, fr->lsf)) + return 0; + + mpg123_set_pointer(sideinfo.main_data_begin); + + for (gr = 0; gr < granules; gr++) + { + real hybridIn[2][SBLIMIT][SSLIMIT]; + real hybridOut[2][SSLIMIT][SBLIMIT]; + + { + struct gr_info_s *gr_info = &(sideinfo.ch[0].gr[gr]); + long part2bits; + + if (fr->lsf) + part2bits = III_get_scale_factors_2(scalefacs[0], gr_info, 0); + else + part2bits = III_get_scale_factors_1(scalefacs[0], gr_info); + + if (III_dequantize_sample(hybridIn[0], scalefacs[0], gr_info, sfreq, part2bits)) + return 0; + } + + if (stereo == 2) + { + struct gr_info_s *gr_info = &(sideinfo.ch[1].gr[gr]); + long part2bits; + + if (fr->lsf) + part2bits = III_get_scale_factors_2(scalefacs[1], gr_info, i_stereo); + else + part2bits = III_get_scale_factors_1(scalefacs[1], gr_info); + + if (III_dequantize_sample(hybridIn[1], scalefacs[1], gr_info, sfreq, part2bits)) + return 0; + + if (ms_stereo) + { + int i; + unsigned maxb = sideinfo.ch[0].gr[gr].maxb; + + if (sideinfo.ch[1].gr[gr].maxb > maxb) + maxb = sideinfo.ch[1].gr[gr].maxb; + for (i = 0; i < SSLIMIT * maxb; i++) + { + real tmp0 = ((real *) hybridIn[0])[i]; + real tmp1 = ((real *) hybridIn[1])[i]; + ((real *) hybridIn[0])[i] = tmp0 + tmp1; + ((real *) hybridIn[1])[i] = tmp0 - tmp1; + } + } + + if (i_stereo) + III_i_stereo(hybridIn, scalefacs[1], gr_info, sfreq, ms_stereo, fr->lsf); + + if (ms_stereo || i_stereo || (single == 3)) + { + if (gr_info->maxb > sideinfo.ch[0].gr[gr].maxb) + sideinfo.ch[0].gr[gr].maxb = gr_info->maxb; + else + gr_info->maxb = sideinfo.ch[0].gr[gr].maxb; + } + + switch (single) + { + case 3: + { + register unsigned i; + register real *in0 = (real *) hybridIn[0], + *in1 = (real *) hybridIn[1]; + for (i = 0; i < SSLIMIT * gr_info->maxb; i++, in0++) + *in0 = (*in0 + *in1++); /* *0.5 done by pow-scale */ + } + break; + case 1: + { + register unsigned i; + register real *in0 = (real *) hybridIn[0], + *in1 = (real *) hybridIn[1]; + for (i = 0; i < SSLIMIT * gr_info->maxb; i++) + *in0++ = *in1++; + } + break; + } + } +/*** + if (mpg123_info->eq_active) + { + int i, sb; + + if (single < 0) + { + for (sb = 0, i = 0; sb < SBLIMIT; sb++) + { + for (ss = 0; ss < SSLIMIT; ss++) + { + hybridIn[0][sb][ss] *= mpg123_info->eq_mul[i]; + hybridIn[1][sb][ss] *= mpg123_info->eq_mul[i++]; + } + } + } + else + { + for (sb = 0, i = 0; sb < SBLIMIT; sb++) + { + for (ss = 0; ss < SSLIMIT; ss++) + hybridIn[0][sb][ss] *= mpg123_info->eq_mul[i++]; + } + } + } +***/ + + for (ch = 0; ch < stereo1; ch++) + { + struct gr_info_s *gr_info = &(sideinfo.ch[ch].gr[gr]); + + III_antialias(hybridIn[ch], gr_info); + if (gr_info->maxb < 1 || gr_info->maxb > SBLIMIT) + return 0; + III_hybrid(hybridIn[ch], hybridOut[ch], ch, gr_info, fr); + } + + for (ss = 0; ss < SSLIMIT; ss++) + { + if (single >= 0) + { + (fr->synth_mono) (hybridOut[0][ss], mpg123_pcm_sample, &mpg123_pcm_point); + } + else + { + int p1 = mpg123_pcm_point; + + (fr->synth) (hybridOut[0][ss], 0, mpg123_pcm_sample, &p1); + (fr->synth) (hybridOut[1][ss], 1, mpg123_pcm_sample, &mpg123_pcm_point); + } + } + +/*** + if (mpg123_info->output_audio) + { + mpg123_ip.add_vis_pcm(mpg123_ip.output->written_time(), + mpg123_cfg.resolution == 16 ? FMT_S16_NE : FMT_U8, + mpg123_cfg.channels == 2 ? fr->stereo : 1, + mpg123_pcm_point, mpg123_pcm_sample); + while (mpg123_ip.output->buffer_free() < mpg123_pcm_point && + mpg123_info->going && mpg123_info->jump_to_time == -1) + xmms_usleep(10000); + if (mpg123_info->going && mpg123_info->jump_to_time == -1) + mpg123_ip.output->write_audio(mpg123_pcm_sample, mpg123_pcm_point); + } +***/ + mpg123_pcm_point = 0; + } + return 1; +} diff --git a/libmpg123/mpg123.c b/libmpg123/mpg123.c new file mode 100644 index 0000000..35cbcd0 --- /dev/null +++ b/libmpg123/mpg123.c @@ -0,0 +1,173 @@ +/* XMMS - Cross-platform multimedia player + * Copyright (C) 1998-2000 Peter Alm, Mikael Alm, Olle Hallnas, Thomas Nilsson and 4Front Technologies + * Copyright (C) 1999,2000 Håvard Kvålen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + * Note : removed code not used in EasyTAG + */ + +#include "mpg123.h" +#include + + +double mpg123_compute_tpf(struct frame *fr) +{ + const int bs[4] = {0, 384, 1152, 1152}; + double tpf; + + tpf = bs[fr->lay]; + tpf /= mpg123_freqs[fr->sampling_frequency] << (fr->lsf); + return tpf; +} + + +static uint32_t convert_to_header(uint8_t * buf) +{ + + return (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3]; +} + + +#define DET_BUF_SIZE 1024 + +#if 0 /* Not used at the present time */ +static gboolean mpg123_detect_by_content(gchar *filename) +{ + FILE *file; + guchar tmp[4]; + uint32_t head; + struct frame fr; + guchar buf[DET_BUF_SIZE]; + gint in_buf, i; + + if((file = fopen(filename, "rb")) == NULL) + return FALSE; + if (fread(tmp, 1, 4, file) != 4) + goto done; + head = convert_to_header(tmp); + while(!mpg123_head_check(head)) + { + /* + * The mpeg-stream can start anywhere in the file, + * so we check the entire file + */ + /* Optimize this */ + in_buf = fread(buf, 1, DET_BUF_SIZE, file); + if(in_buf == 0) + goto done; + + for (i = 0; i < in_buf; i++) + { + head <<= 8; + head |= buf[i]; + if(mpg123_head_check(head)) + { + fseek(file, i+1-in_buf, SEEK_CUR); + break; + } + } + } + if (mpg123_decode_header(&fr, head)) + { + /* + * We found something which looks like a MPEG-header. + * We check the next frame too, to be sure + */ + + if (fseek(file, fr.framesize, SEEK_CUR) != 0) + goto done; + if (fread(tmp, 1, 4, file) != 4) + goto done; + head = convert_to_header(tmp); + if (mpg123_head_check(head) && mpg123_decode_header(&fr, head)) + { + fclose(file); + return TRUE; + } + } + + done: + fclose(file); + return FALSE; +} +#endif + +//static guint get_song_time(FILE * file) +unsigned int mpg123_get_song_time(FILE * file) +{ + uint32_t head; + unsigned char tmp[4], *buf; + struct frame frm; + XHEADDATA xing_header; + double tpf, bpf; + uint32_t len; + long id3v2size = 0; + + if (!file) + return -1; + + fseek(file, 0, SEEK_SET); + if (fread(tmp, 1, 4, file) != 4) + return 0; + + // Skip data of the ID3v2.x tag (patch from Artur Polaczynski) + if (tmp[0] == 'I' && tmp[1] == 'D' && tmp[2] == '3' && tmp[3] < 0xFF) + { + // id3v2 tag skipeer $49 44 33 yy yy xx zz zz zz zz [zz size] + fseek(file, 2, SEEK_CUR); // Size is 6-9 position + if (fread(tmp, 1, 4, file) != 4) + return 0; + id3v2size = 10 + ( (long)(tmp[3]) | ((long)(tmp[2]) << 7) | ((long)(tmp[1]) << 14) | ((long)(tmp[0]) << 21) ); + fseek(file, id3v2size, SEEK_SET); + if (fread(tmp, 1, 4, file) != 4) // Read mpeg header + return 0; + } + + head = convert_to_header(tmp); + while (!mpg123_head_check(head)) + { + head <<= 8; + if (fread(tmp, 1, 1, file) != 1) + return 0; + head |= tmp[0]; + } + if (mpg123_decode_header(&frm, head)) + { + buf = malloc(frm.framesize + 4); + fseek(file, -4, SEEK_CUR); + fread(buf, 1, frm.framesize + 4, file); + xing_header.toc = NULL; + tpf = mpg123_compute_tpf(&frm); + if (mpg123_get_xing_header(&xing_header, buf)) + { + free(buf); + return ((unsigned int) (tpf * xing_header.frames * 1000)); + } + free(buf); + bpf = mpg123_compute_bpf(&frm); + fseek(file, 0, SEEK_END); + len = ftell(file) - id3v2size; + fseek(file, -128, SEEK_END); + fread(tmp, 1, 3, file); + if (!strncmp((char *)tmp, "TAG", 3)) + len -= 128; + return ((unsigned int) ((unsigned int)(len / bpf) * tpf * 1000)); + } + return 0; +} + diff --git a/libmpg123/mpg123.h b/libmpg123/mpg123.h new file mode 100644 index 0000000..f7cb7b5 --- /dev/null +++ b/libmpg123/mpg123.h @@ -0,0 +1,146 @@ +/* + * mpg123 defines + * used source: musicout.h from mpegaudio package + */ + +#ifndef __MPG123_H__ +#define __MPG123_H__ + + +#include + +#include +#include +#include +//#include + +#include "dxhead.h" + +#define real float + +/* #define MAX_NAME_SIZE 81 */ +#define SBLIMIT 32 +#define SCALE_BLOCK 12 +#define SSLIMIT 18 + +#define MPG_MD_STEREO 0 +#define MPG_MD_JOINT_STEREO 1 +#define MPG_MD_DUAL_CHANNEL 2 +#define MPG_MD_MONO 3 + + +struct al_table +{ + short bits; + short d; +}; + +struct frame +{ + struct al_table *alloc; + int (*synth) (real *, int, unsigned char *, int *); + int (*synth_mono) (real *, unsigned char *, int *); + int stereo; + int jsbound; + int single; + int II_sblimit; + int down_sample_sblimit; + int lsf; + int mpeg25; + int down_sample; + int header_change; + int lay; + int (*do_layer) (struct frame * fr); + int error_protection; + int bitrate_index; + int sampling_frequency; + int padding; + int extension; + int mode; + int mode_ext; + int copyright; + int original; + int emphasis; + int framesize; /* computed framesize */ +}; + + +struct bitstream_info +{ + int bitindex; + unsigned char *wordpointer; +}; + +extern struct bitstream_info bsi; + +/* ------ Declarations from "common.c" ------ */ +extern unsigned int mpg123_get1bit(void); +extern unsigned int mpg123_getbits(int); +extern unsigned int mpg123_getbits_fast(int); + +extern int mpg123_head_check(unsigned long); + +extern void mpg123_set_pointer(long); + +extern unsigned char *mpg123_pcm_sample; +extern int mpg123_pcm_point; + +struct gr_info_s +{ + int scfsi; + unsigned part2_3_length; + unsigned big_values; + unsigned scalefac_compress; + unsigned block_type; + unsigned mixed_block_flag; + unsigned table_select[3]; + unsigned subblock_gain[3]; + unsigned maxband[3]; + unsigned maxbandl; + unsigned maxb; + unsigned region1start; + unsigned region2start; + unsigned preflag; + unsigned scalefac_scale; + unsigned count1table_select; + real *full_gain[3]; + real *pow2gain; +}; + +struct III_sideinfo +{ + unsigned main_data_begin; + unsigned private_bits; + struct + { + struct gr_info_s gr[2]; + } + ch[2]; +}; + +int mpg123_stream_check_for_xing_header(struct frame *fr, XHEADDATA * xhead); + +extern int mpg123_do_layer3(struct frame *fr); +extern int mpg123_do_layer2(struct frame *fr); +extern int mpg123_do_layer1(struct frame *fr); + + +extern void mpg123_init_layer3(int); +extern void mpg123_init_layer2(void); + +int mpg123_decode_header(struct frame *fr, unsigned long newhead); +double mpg123_compute_bpf(struct frame *fr); +double mpg123_compute_tpf(struct frame *fr); + + +extern unsigned char *mpg123_conv16to8; +extern long mpg123_freqs[9]; +extern real mpg123_muls[27][64]; +extern real mpg123_decwin[512 + 32]; +extern real *mpg123_pnts[5]; + +extern int tabsel_123[2][3][16]; + +unsigned int mpg123_get_song_time(FILE * file); + +#endif diff --git a/qtJukeBox.pro b/qtJukeBox.pro index c033c07..c5ce4d8 100644 --- a/qtJukeBox.pro +++ b/qtJukeBox.pro @@ -18,25 +18,73 @@ LIBS += "C:/dev/3rdParty/taglib/lib/libtag.dll.a" SOURCES += main.cpp\ cmainwindow.cpp \ - cmediainfo.cpp \ - ctag.cpp \ - cdatabase.cpp \ - cstring.cpp \ common.cpp \ - cpixmap.cpp \ cmusicviewitemdelegate.cpp \ - calbum.cpp + calbum.cpp \ + cid3field.cpp \ + cmediainfo.cpp \ + cpicture.cpp \ + libid3tag/compat.c \ + libid3tag/crc.c \ + libid3tag/debug.c \ + libid3tag/field.c \ + libid3tag/file.c \ + libid3tag/frame.c \ + libid3tag/frametype.c \ + libid3tag/genre.c \ + libid3tag/latin1.c \ + libid3tag/parse.c \ + libid3tag/render.c \ + libid3tag/tag.c \ + libid3tag/ucs4.c \ + libid3tag/utf16.c \ + libid3tag/utf8.c \ + libid3tag/util.c \ + libid3tag/version.c \ + libmpg123/dxhead.c \ + libmpg123/getbits.c \ + libmpg123/layer1.c \ + libmpg123/layer2.c \ + libmpg123/layer3.c \ + libmpg123/mpg123.c HEADERS += cmainwindow.h \ - cmediainfo.h \ - ctag.h \ - cdatabase.h \ - cstring.h \ common.h \ - cpixmap.h \ cmusicviewitemdelegate.h \ - calbum.h + calbum.h \ + libid3tag/compat.h \ + libid3tag/crc.h \ + libid3tag/debug.h \ + libid3tag/field.h \ + libid3tag/file.h \ + libid3tag/frame.h \ + libid3tag/frametype.h \ + libid3tag/genre.h \ + libid3tag/global.h \ + libid3tag/id3tag.h \ + libid3tag/latin1.h \ + libid3tag/parse.h \ + libid3tag/render.h \ + libid3tag/tag.h \ + libid3tag/ucs4.h \ + libid3tag/utf16.h \ + libid3tag/utf8.h \ + libid3tag/util.h \ + libid3tag/version.h \ + libmpg123/dxhead.h \ + libmpg123/getbits.h \ + libmpg123/huffman.h \ + libmpg123/l2tables.h \ + libmpg123/mpg123.h \ + calbum.h \ + cid3field.h \ + cmediainfo.h \ + cpicture.h \ + fields.h FORMS += cmainwindow.ui -#LIBS += -ltaglib +LIBS += -lz + +DISTFILES += \ + libid3tag/genre.dat