From c4961a8b15e26d37ccbd849363ddbd9a95e50988 Mon Sep 17 00:00:00 2001 From: codestation Date: Fri, 17 Jan 2014 01:57:21 -0430 Subject: [PATCH 1/9] New base for the database backend. --- qcma.pro | 5 +- src/avdecoder.cpp | 48 ++- src/avdecoder.h | 11 + src/sqlitedb.cpp | 810 ++++++++++++++++++++++++++++++++++++++++++++++ src/sqlitedb.h | 66 ++++ 5 files changed, 938 insertions(+), 2 deletions(-) create mode 100644 src/sqlitedb.cpp create mode 100644 src/sqlitedb.h diff --git a/qcma.pro b/qcma.pro index 5555337..39291a5 100644 --- a/qcma.pro +++ b/qcma.pro @@ -7,7 +7,8 @@ QT += core \ gui \ widgets \ - network + network \ + sql TARGET = qcma @@ -31,6 +32,7 @@ SOURCES += src/main.cpp \ src/clientmanager.cpp \ src/filterlineedit.cpp \ src/dds.cpp \ + src/sqlitedb.cpp \ # forms src/forms/backupitem.cpp \ src/forms/backupmanagerform.cpp \ @@ -56,6 +58,7 @@ HEADERS += \ src/clientmanager.h \ src/filterlineedit.h \ src/dds.h \ + src/sqlitedb.h \ # forms src/forms/backupitem.h \ src/forms/backupmanagerform.h \ diff --git a/src/avdecoder.cpp b/src/avdecoder.cpp index 66315b3..42156d1 100644 --- a/src/avdecoder.cpp +++ b/src/avdecoder.cpp @@ -28,7 +28,7 @@ AVDecoder::AvInit init; AVDecoder::AVDecoder() : - pFormatCtx(NULL), file(NULL) + pFormatCtx(NULL), pCodecCtx(NULL), file(NULL) { } @@ -95,6 +95,16 @@ bool AVDecoder::open(const QString filename) return true; } +const char *AVDecoder::getMetadataEntry(const char *key, const char *default_value) +{ + AVDictionaryEntry *entry; + + if((entry = av_dict_get(pFormatCtx->metadata, key, NULL, 0)) != NULL) { + return entry->value; + } + return default_value; +} + void AVDecoder::getAudioMetadata(metadata_t &metadata) { AVDictionaryEntry *entry; @@ -164,6 +174,42 @@ void AVDecoder::getVideoMetadata(metadata_t &metadata) } } +int AVDecoder::getWidth() +{ + return pCodecCtx->width; +} + +int AVDecoder::getHeight() +{ + return pCodecCtx->height; +} + +int AVDecoder::getDuration() +{ + return pFormatCtx->duration / 1000; +} + +int AVDecoder::getBitrate() +{ + return pFormatCtx->bit_rate; +} + +int AVDecoder::getCodecBitrate() +{ + return pCodecCtx->bit_rate; +} + +bool AVDecoder::loadCodec(codec_type codec) +{ + int stream_index = av_find_best_stream(pFormatCtx, (AVMediaType)codec, -1, -1, NULL, 0); + if(stream_index >= 0) { + pCodecCtx = pFormatCtx->streams[stream_index]->codec; + return true; + } else { + return false; + } +} + QByteArray AVDecoder::getAudioThumbnail(int width, int height) { QByteArray data; diff --git a/src/avdecoder.h b/src/avdecoder.h index 360d46f..1e6d866 100644 --- a/src/avdecoder.h +++ b/src/avdecoder.h @@ -39,13 +39,23 @@ public: AVDecoder(); ~AVDecoder(); + enum codec_type {CODEC_VIDEO = AVMEDIA_TYPE_VIDEO, CODEC_AUDIO = AVMEDIA_TYPE_AUDIO}; + bool open(const QString filename); void close(); + bool loadCodec(codec_type codec); QByteArray getAudioThumbnail(int width, int height); QByteArray getVideoThumbnail(int width, int height); void getAudioMetadata(metadata_t &metadata); void getVideoMetadata(metadata_t &metadata); + const char *getMetadataEntry(const char *key, const char *default_value = NULL); + + int getWidth(); + int getHeight(); + int getDuration(); + int getBitrate(); + int getCodecBitrate(); // simulate a static constructor to initialize libav only once class AvInit @@ -66,6 +76,7 @@ private: static int64_t seekFunction(void* opaque, int64_t offset, int whence); AVFormatContext *pFormatCtx; + AVCodecContext *pCodecCtx; QFile *file; }; diff --git a/src/sqlitedb.cpp b/src/sqlitedb.cpp new file mode 100644 index 0000000..c832e75 --- /dev/null +++ b/src/sqlitedb.cpp @@ -0,0 +1,810 @@ +#include "sqlitedb.h" +#include "sforeader.h" +#include "avdecoder.h" + +#include +#include +#include +#include + +#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) +#include +#else +#include +#define QStandardPaths QDesktopServices +#define writableLocation storageLocation +#endif + +#include +#include + +static const char create_adjacent[] = "CREATE TABLE IF NOT EXISTS adjacent_objects (" + "parent_id INTEGER NOT NULL REFERENCES object_node(object_id) ON DELETE CASCADE," + "child_id INTEGER NOT NULL REFERENCES object_node(object_id) ON DELETE CASCADE)"; + +static const char create_obj_node[] = "CREATE TABLE IF NOT EXISTS object_node (" + "object_id INTEGER PRIMARY KEY AUTOINCREMENT," + "type INTEGER NOT NULL," + "title TEXT," + "child_count INTEGER NOT NULL DEFAULT 0," + "reference_count INTEGER NOT NULL DEFAULT 0);"; + +static const char create_sources[] = "CREATE TABLE IF NOT EXISTS sources (" + "object_id INTEGER PRIMARY KEY REFERENCES object_node(object_id) ON DELETE CASCADE," + "path TEXT UNIQUE NOT NULL CHECK (LENGTH(path) > 0)," + "size INTEGER," + "date_created TIMESTAMP," + "date_modified TIMESTAMP)"; + +static const char create_music[] = "CREATE TABLE IF NOT EXISTS music (" + "object_id INTEGER PRIMARY KEY REFERENCES object_node(object_id) ON DELETE CASCADE," + "file_format INTEGER," + "audio_bitrate INTEGER," + "audio_codec INTEGER," + "duration INTEGER," + "genre_id INTEGER REFERENCES object_node(object_id) ON DELETE SET NULL," + "track_id INTEGER REFERENCES object_node(object_id) ON DELETE SET NULL," + "artist_id INTEGER REFERENCES object_node(object_id) ON DELETE SET NULL," + "album_id INTEGER REFERENCES object_node(object_id) ON DELETE SET NULL," + "artist TEXT," + "album TEXT," + "track_number INTEGER)"; + +static const char create_photos[] = "CREATE TABLE IF NOT EXISTS photos (" + "object_id INTEGER PRIMARY KEY REFERENCES object_node(object_id) ON DELETE CASCADE," + "date_created TIMESTAMP," + "file_format INTEGER," + "photo_codec INTEGER," + "width INTEGER," + "height INTEGER)"; + +static const char create_videos[] = "CREATE TABLE IF NOT EXISTS videos (" + "object_id INTEGER PRIMARY KEY REFERENCES object_node(object_id) ON DELETE CASCADE," + "file_format INTEGER," + "parental_level INTEGER," + "explanation TEXT," + "copyright TEXT," + "width INTEGER," + "height INTEGER," + "video_codec INTEGER," + "video_bitrate INTEGER," + "audio_codec INTEGER," + "audio_bitrate INTEGER," + "duration INTEGER)"; + +static const char create_savedata[] = "CREATE TABLE IF NOT EXISTS savedata (" + "object_id INTEGER PRIMARY KEY REFERENCES object_node(object_id) ON DELETE CASCADE," + "detail TEXT," + "dir_name TEXT," + "title TEXT," + "date_updated TIMESTAMP)"; + +static const char create_trigger_node[] = "CREATE TRIGGER IF NOT EXISTS trg_objnode_deletechilds BEFORE DELETE ON object_node " + "FOR EACH ROW BEGIN " + "DELETE FROM object_node WHERE object_id IN " + "(SELECT child_id FROM adjacent_objects WHERE parent_id == OLD.object_id);" + "END"; + +static const char create_trigger_adjins[] = "CREATE TRIGGER IF NOT EXISTS trg_adjacentobjects_ins AFTER INSERT ON adjacent_objects " + "FOR EACH ROW BEGIN " + "UPDATE object_node SET child_count = child_count + 1 WHERE object_id = NEW.parent_id;" + "UPDATE object_node SET reference_count = reference_count + 1 WHERE object_id = NEW.child_id;" + "END"; + +static const char create_trigger_adjdel[] = "CREATE TRIGGER IF NOT EXISTS trg_adjacentobjects_del AFTER DELETE ON adjacent_objects " + "FOR EACH ROW BEGIN " + "UPDATE object_node SET child_count = child_count - 1 WHERE object_id = OLD.parent_id;" + "UPDATE object_node SET reference_count = reference_count - 1 WHERE object_id = OLD.child_id;" + "DELETE FROM object_node WHERE object_id = OLD.parent_id AND child_count <= 0;" + "DELETE FROM object_node WHERE object_id = OLD.child_id AND reference_count <= 0;" + "END"; + +typedef struct { + const char *file_ext; + int file_format; + int file_codec; +} file_type; + +#define FILE_FORMAT_MP4 1 +#define FILE_FORMAT_WAV 2 +#define FILE_FORMAT_MP3 3 +#define FILE_FORMAT_JPG 4 +#define FILE_FORMAT_PNG 5 +#define FILE_FORMAT_GIF 6 +#define FILE_FORMAT_BMP 7 +#define FILE_FORMAT_TIF 8 + +#define CODEC_TYPE_MPEG4 2 +#define CODEC_TYPE_AVC 3 +#define CODEC_TYPE_MP3 12 +#define CODEC_TYPE_AAC 13 +#define CODEC_TYPE_PCM 15 +#define CODEC_TYPE_JPG 17 +#define CODEC_TYPE_PNG 18 +#define CODEC_TYPE_TIF 19 +#define CODEC_TYPE_BMP 20 +#define CODEC_TYPE_GIF 21 + +static const file_type audio_list[] = { + {"mp3", FILE_FORMAT_MP3, CODEC_TYPE_MP3}, + {"mp4", FILE_FORMAT_MP4, CODEC_TYPE_AAC}, + {"wav", FILE_FORMAT_WAV, CODEC_TYPE_PCM} +}; + +static const file_type photo_list[] = { + {"jpg", FILE_FORMAT_JPG, CODEC_TYPE_JPG}, + {"jpeg", FILE_FORMAT_JPG, CODEC_TYPE_JPG}, + {"png", FILE_FORMAT_PNG, CODEC_TYPE_PNG}, + {"tif", FILE_FORMAT_TIF, CODEC_TYPE_TIF}, + {"tiff", FILE_FORMAT_TIF, CODEC_TYPE_TIF}, + {"bmp", FILE_FORMAT_BMP, CODEC_TYPE_BMP}, + {"gif", FILE_FORMAT_GIF, CODEC_TYPE_GIF}, +}; + +static const file_type video_list[] = { + {"mp4", FILE_FORMAT_MP4, 0} +}; + + +static const char *table_list[] = { + create_adjacent, create_obj_node, create_sources, + create_music, create_photos, create_videos, create_savedata +}; + +static const char *trigger_list[] = { + create_trigger_node, create_trigger_adjins, create_trigger_adjdel +}; + +SQLiteDB::SQLiteDB(QObject *parent) : + QObject(parent) +{ + uuid = QSettings().value("lastAccountId", "ffffffffffffffff").toString(); +} + +SQLiteDB::~SQLiteDB() +{ + db.close(); +} + +bool SQLiteDB::open() +{ + // fetch a configured database path if it exists + QString db_path = QStandardPaths::writableLocation(QStandardPaths::DataLocation); + db_path = QSettings().value("databasePath", db_path).toString(); + QDir(QDir::root()).mkpath(db_path); + + db = QSqlDatabase::addDatabase("QSQLITE"); + db.setDatabaseName(db_path + QDir::separator() + "qcma.sqlite"); + + return db.open(); +} + +void SQLiteDB::remove() +{ + QString db_path = QStandardPaths::writableLocation(QStandardPaths::DataLocation); + db_path = QSettings().value("databasePath", db_path).toString(); + QDir(QDir::root()).mkpath(db_path); + + QFile(db_path + QDir::separator() + "qcma.sqlite").remove(); +} + +bool SQLiteDB::initialize() +{ + if (!db.isOpen()) { + return false; + } + QSqlQuery query; + + for(unsigned int i = 0; i < sizeof(table_list) / sizeof(const char *); i++) { + if(!query.exec(table_list[i])) { + return false; + } + } + + for(unsigned int i = 0; i < sizeof(trigger_list) / sizeof(const char *); i++) { + if(!query.exec(trigger_list[i])) { + return false; + } + } + + // force object_id to start at 256 + if(query.exec("INSERT INTO object_node (object_id, type) VALUES (255, 0)")) { + query.exec("DELETE FROM object_node WHERE object_id = 255"); + } + return true; +} + +QSqlError SQLiteDB::getLastError() +{ + return db.lastError(); +} + +int SQLiteDB::checkFileType(const QString path, int ohfi_root) +{ + switch(ohfi_root) { + case VITA_OHFI_MUSIC: + for(int i = 0, max = sizeof(audio_list) / sizeof(file_type); i < max; i++) { + if(path.endsWith(audio_list[i].file_ext, Qt::CaseInsensitive)) { + return i; + } + } + break; + case VITA_OHFI_PHOTO: + for(int i = 0, max = sizeof(photo_list) / sizeof(file_type); i< max; i++) { + if(path.endsWith(photo_list[i].file_ext, Qt::CaseInsensitive)) { + return i; + } + } + break; + case VITA_OHFI_VIDEO: + for(int i = 0, max = sizeof(video_list) / sizeof(file_type); i< max; i++) { + if(path.endsWith(video_list[i].file_ext, Qt::CaseInsensitive)) { + return i; + } + } + break; + } + return -1; +} + +int SQLiteDB::create() +{ + int total_objects = 0; + + const int ohfi_array[] = { VITA_OHFI_MUSIC, VITA_OHFI_VIDEO, VITA_OHFI_PHOTO, + VITA_OHFI_BACKUP, VITA_OHFI_VITAAPP, VITA_OHFI_PSPAPP, + VITA_OHFI_PSPSAVE, VITA_OHFI_PSXAPP, VITA_OHFI_PSMAPP + }; + + QSettings settings; + QString base_path; + + for(int i = 0, max = sizeof(ohfi_array) / sizeof(int); i < max; i++) { + switch(ohfi_array[i]) { + case VITA_OHFI_MUSIC: + base_path = settings.value("musicPath").toString(); + break; + case VITA_OHFI_VIDEO: + base_path = settings.value("videoPath").toString(); + break; + case VITA_OHFI_PHOTO: + base_path = settings.value("photoPath").toString(); + break; + case VITA_OHFI_BACKUP: + continue; + base_path = settings.value("appsPath").toString() + QDir::separator() + "SYSTEM" + QDir::separator() + uuid; + break; + case VITA_OHFI_VITAAPP: + continue; + base_path = settings.value("appsPath").toString() + QDir::separator() + "APP" + QDir::separator() + uuid; + break; + case VITA_OHFI_PSPAPP: + continue; + base_path = settings.value("appsPath").toString() + QDir::separator() + "PGAME" + QDir::separator() + uuid; + break; + case VITA_OHFI_PSPSAVE: + base_path = settings.value("appsPath").toString() + QDir::separator() + "PSAVEDATA" + QDir::separator() + uuid; + break; + case VITA_OHFI_PSXAPP: + continue; + base_path = settings.value("appsPath").toString() + QDir::separator() + "PSGAME" + QDir::separator() + uuid; + break; + case VITA_OHFI_PSMAPP: + continue; + base_path = settings.value("appsPath").toString() + QDir::separator() + "PSM" + QDir::separator() + uuid; + break; + } + + int dir_count = recursiveScanRootDirectory(base_path, ohfi_array[i], OBJECT_FOLDER); + + if(dir_count < 0) { + return -1; + } + total_objects += dir_count; + } + return total_objects; +} + +int SQLiteDB::recursiveScanRootDirectory(const QString &base_path, int parent, int parent_type) +{ + int total_objects = 0; + + QDir dir(base_path); + dir.setSorting(QDir::Name); + QFileInfoList qsl = dir.entryInfoList(QDir::AllEntries | QDir::NoDotAndDotDot); + + foreach(const QFileInfo &info, qsl) { + qDebug() << "Processing " << info.fileName(); + if(info.isDir()) { + int ohfi = insertDirectoryEntry(info.absoluteFilePath(), parent_type, parent); + total_objects += recursiveScanRootDirectory(info.absoluteFilePath(), ohfi, parent_type); + } else if(info.isFile()) { + switch(parent_type) { + case VITA_OHFI_MUSIC: + insertMusicEntry(info.absoluteFilePath(), OBJECT_MUSIC | (parent_type & ~OBJECT_FOLDER), parent); + break; + case VITA_OHFI_PHOTO: + insertPhotoEntry(info.absoluteFilePath(), OBJECT_PHOTO | (parent_type & ~OBJECT_FOLDER), parent); + break; + case VITA_OHFI_VIDEO: + insertVideoEntry(info.absoluteFilePath(), OBJECT_VIDEO | (parent_type & ~OBJECT_FOLDER), parent); + break; + case VITA_OHFI_PSPSAVE: + insertSavedataEntry(info.absoluteFilePath(), OBJECT_SAVEDATA | (parent_type & ~OBJECT_FOLDER), parent); + break; + } + + total_objects++; + } + } + + return total_objects; +} + +int SQLiteDB::getPathId(const QString &path) +{ + if (!db.isOpen()) { + return -1; + } + QSqlQuery query(QString("SELECT object_id from sources WHERE path = %1").arg(path)); + if(query.next()) { + return query.value(0).toInt(); + } else { + return -1; + } +} + +QString SQLiteDB::getPathFromId(int ohfi) +{ + if (!db.isOpen()) { + return QString(); + } + QSqlQuery query(QString("SELECT path FROM sources WHERE object_id = %1").arg(ohfi)); + if(query.next()) { + return query.value(0).toString(); + } else { + return QString(); + } +} + +bool SQLiteDB::updateSize(int ohfi, quint64 size) +{ + if (!db.isOpen()) { + return false; + } + QSqlQuery query(QString("UPDATE sources SET size = %1 WHERE object_id == %2").arg(size).arg(ohfi)); + return query.exec(); +} + +bool SQLiteDB::deleteEntry(int ohfi) +{ + QSqlQuery query(QString("DELETE FROM object_node WHERE object_id == %1").arg(ohfi)); + return query.exec(); +} + +bool SQLiteDB::deleteEntry(const QString &path) +{ + QSqlQuery query(QString("DELETE FROM object_node WHERE object_id == (SELECT object_id FROM sources WHERE path == %1)").arg(path)); + return query.exec(); +} + +bool SQLiteDB::updateAdjacencyList(int ohfi, int parent) +{ + QSqlQuery query; + query.prepare("SELECT * FROM adjacent_objects WHERE parent_id == :parent_id AND child_id == :child_id"); + query.bindValue(0, parent); + query.bindValue(1, ohfi); + + if(query.exec() && query.next()) { + return true; + } + + query.prepare("INSERT INTO adjacent_objects (parent_id, child_id)" + "VALUES (:parentid, :child_id)"); + query.bindValue(0, parent); + query.bindValue(1, ohfi); + return query.exec(); +} + +uint SQLiteDB::insertDirectoryEntry(const QString &path, int type, int parent) +{ + uint ohfi; + db.transaction(); + QString dirname = QFileInfo(path).fileName(); + + if((ohfi = insertObjectEntry(dirname.toUtf8().constData(), type)) == 0) { + db.rollback(); + return 0; + } + + if(parent && !updateAdjacencyList(ohfi, parent)) { + db.rollback(); + return 0; + } + + if(!insertSourceEntry(ohfi, path)) { + db.rollback(); + return 0; + } + db.commit(); + return ohfi; +} + +uint SQLiteDB::insertObjectEntry(const char *title, int type) +{ + QSqlQuery query; + + query.prepare("SELECT object_id FROM object_node WHERE type == :type and title == :title"); + query.bindValue(0, type); + query.bindValue(1, title); + + if(!query.exec() || !query.next()) { + query.prepare("INSERT INTO object_node (type, title) VALUES (:type, :title)"); + query.bindValue(0, type); + query.bindValue(1, title); + + if(!query.exec() || !query.exec("SELECT last_insert_rowid()") || !query.next()) { + return 0; + } + } + + return query.value(0).toInt(); +} + +bool SQLiteDB::insertSourceEntry(uint object_id, const QString &path) +{ + qint64 size; + uint date_created, date_modified; + + QFileInfo info(path); + size = info.size(); + date_created = info.created().toTime_t(); + date_modified = info.lastModified().toTime_t(); + + QSqlQuery query; + query.prepare("REPLACE INTO sources (object_id, path, size, date_created, date_modified)" + "VALUES (:object_id, :path, :size, :date_created, :date_modified)"); + query.bindValue(0, object_id); + query.bindValue(1, path); + query.bindValue(2, size); + query.bindValue(3, date_created); + query.bindValue(4, date_modified); + return query.exec(); +} + +uint SQLiteDB::insertMusicEntry(const QString &path, int type, int parent) +{ + bool ok; + uint ohfi; + AVDecoder decoder; + quint64 duration; + const char *artist, *album, *albumartist, *genre, *track, *title; + int file_format, audio_codec, audio_bitrate, genre_id, artist_id, track_id, album_id, track_number; + + int file_type = checkFileType(path, type); + if(file_type < 0) { + qDebug() << "Excluding from database:" << path; + return 0; + } + + if(!decoder.open(path)) { + return 0; + } + + album = decoder.getMetadataEntry("album"); + genre = decoder.getMetadataEntry("genre"); + artist = decoder.getMetadataEntry("artist"); + albumartist = decoder.getMetadataEntry("album_artist"); + track = decoder.getMetadataEntry("track"); + + track_number = QString(track).toInt(&ok); + if(!ok) { + // set track number to 1 by default + track_number = 1; + } + audio_bitrate = decoder.getBitrate(); + duration = decoder.getDuration(); + + file_format = audio_list[file_type].file_format; + audio_codec = audio_list[file_type].file_codec; + + QByteArray basename = QFileInfo(path).baseName().toUtf8(); + title = decoder.getMetadataEntry("title", basename.constData()); + + db.transaction(); + + if((ohfi = insertObjectEntry(title, type)) == 0) { + db.rollback(); + return 0; + } + + if(parent && !updateAdjacencyList(ohfi, parent)) { + db.rollback(); + return 0; + } + + if(!insertSourceEntry(ohfi, path)) { + db.rollback(); + return 0; + } + + if(genre) { + genre_id = insertObjectEntry(genre, type | OBJECT_GENRE); + if(!updateAdjacencyList(ohfi, genre_id)) { + db.rollback(); + return 0; + } + } else { + genre_id = 0; + } + + if(artist) { + track_id = insertObjectEntry(artist, type | OBJECT_ARTIST); + if(!updateAdjacencyList(ohfi, track_id)) { + db.rollback(); + return 0; + } + } else { + track_id = 0; + } + + if(albumartist) { + artist_id = insertObjectEntry(albumartist, type | OBJECT_ALBUM_ARTIST); + if(!updateAdjacencyList(ohfi, artist_id)) { + db.rollback(); + return 0; + } + } else { + artist_id = 0; + } + + if(album) { + album_id = insertObjectEntry(album, type | OBJECT_ALBUM); + + if(track_id && !updateAdjacencyList(ohfi, album_id)) { + db.rollback(); + return 0; + } + if(track_id && !updateAdjacencyList(album_id, track_id)) { + db.rollback(); + return 0; + } + if(artist_id && !updateAdjacencyList(album_id, artist_id)) { + db.rollback(); + return 0; + } + } else { + album_id = 0; + } + + QSqlQuery query; + query.prepare("REPLACE INTO music" + "(object_id, file_format, audio_codec, audio_bitrate, duration, genre_id, artist_id, album_id, track_id, artist, album, track_number)" + "VALUES (:object_id, :file_format, :audio_codec, :audio_bitrate, :duration, :genre_id, :artist_id, :album_id, :track_id, :artist, :album, :track_number)"); + + query.bindValue(0, ohfi); + query.bindValue(1, file_format); + query.bindValue(2, audio_codec); + query.bindValue(3, audio_bitrate); + query.bindValue(4, duration); + query.bindValue(5, genre_id ? genre_id : QVariant(QVariant::Int)); + query.bindValue(6, artist_id ? artist_id : QVariant(QVariant::Int)); + query.bindValue(7, album_id ? album_id : QVariant(QVariant::Int)); + query.bindValue(8, track_id ? track_id : QVariant(QVariant::Int)); + query.bindValue(9, artist); + query.bindValue(10, album); + query.bindValue(11, track_number); + + if(!query.exec()) { + db.rollback(); + return 0; + } + + db.commit(); + return ohfi; +} + +uint SQLiteDB::insertVideoEntry(const QString &path, int type, int parent) +{ + int ohfi; + AVDecoder decoder; + quint64 duration; + int file_format, parental_level, width, height, video_codec, video_bitrate, audio_codec, audio_bitrate; + const char *explanation, *copyright, *title; + + if(!decoder.open(path) || !decoder.loadCodec(AVDecoder::CODEC_VIDEO)) { + return 0; + } + + int file_type = checkFileType(path, type); + if(file_type < 0) { + qDebug() << "Excluding from database:" << path; + return 0; + } + + parental_level = 0; + explanation = decoder.getMetadataEntry("comments", ""); + copyright = decoder.getMetadataEntry("copyright", ""); + width = decoder.getWidth(); + height = decoder.getHeight(); + duration = decoder.getDuration(); + video_codec = 3; + video_bitrate = decoder.getCodecBitrate(); + file_format = video_list[file_type].file_format; + + if(decoder.loadCodec(AVDecoder::CODEC_AUDIO)) { + audio_codec = 13; + audio_bitrate = decoder.getCodecBitrate(); + } else { + audio_codec = 0; + audio_bitrate = 0; + } + + QByteArray basename = QFileInfo(path).baseName().toUtf8(); + //title = decoder.getMetadataEntry("title", basename.constData()); + title = basename.constData(); + + db.transaction(); + + if((ohfi = insertObjectEntry(title, type)) == 0) { + db.rollback(); + return 0; + } + + if(parent && !updateAdjacencyList(ohfi, parent)) { + db.rollback(); + return 0; + } + + if(!insertSourceEntry(ohfi, path)) { + db.rollback(); + return 0; + } + + QSqlQuery query; + query.prepare("REPLACE INTO videos" + "(object_id, file_format, parental_level, explanation, copyright, width, height, video_codec, video_bitrate, audio_codec, audio_bitrate, duration)" + "VALUES (:object_id, :file_format, :parental_level, :explanation, :copyright, :width, :height, :video_codec, :video_bitrate, :audio_codec, :audio_bitrate, :duration)"); + + query.bindValue(0, ohfi); + query.bindValue(1, file_format); + query.bindValue(2, parental_level); + query.bindValue(3, explanation); + query.bindValue(4, copyright); + query.bindValue(5, width); + query.bindValue(6, height); + query.bindValue(7, video_codec); + query.bindValue(8, video_bitrate); + query.bindValue(9, audio_codec); + query.bindValue(10, audio_bitrate); + query.bindValue(11, duration); + + if(!query.exec()) { + qDebug() << query.lastError().text(); + db.rollback(); + return 0; + } + + db.commit(); + return ohfi; +} + +uint SQLiteDB::insertPhotoEntry(const QString &path, int type, int parent) +{ + int ohfi; + QImage img; + uint date_created; + int width, height, file_format, photo_codec; + + int file_type = checkFileType(path, type); + if(file_type < 0) { + qDebug() << "Excluding from database:" << path; + return 0; + } + + if(!img.load(path)) { + return 0; + } + + date_created = QFileInfo(path).created().toTime_t(); + width = img.width(); + height = img.height(); + file_format = photo_list[file_type].file_format; + photo_codec = photo_list[file_type].file_codec; + + QByteArray basename = QFileInfo(path).baseName().toUtf8(); + + db.transaction(); + + if((ohfi = insertObjectEntry(basename.constData(), type)) == 0) { + db.rollback(); + return 0; + } + + if(parent && !updateAdjacencyList(ohfi, parent)) { + db.rollback(); + return 0; + } + + if(!insertSourceEntry(ohfi, path)) { + db.rollback(); + return 0; + } + + QSqlQuery query; + query.prepare("REPLACE INTO photos" + "(object_id, date_created, file_format, photo_codec, width, height)" + "VALUES (:object_id, :date_created, :file_format, :photo_codec, :width, :height)"); + + query.bindValue(0, ohfi); + query.bindValue(1, date_created); + query.bindValue(2, file_format); + query.bindValue(3, photo_codec); + query.bindValue(4, width); + query.bindValue(5, height); + + if(!query.exec()) { + db.rollback(); + return 0; + } + + db.commit(); + return ohfi; +} + +uint SQLiteDB::insertSavedataEntry(const QString &path, int type, int parent) +{ + int ohfi; + + uint date_updated; + const char *title, *savedata_detail, *savedata_directory; + + SfoReader reader; + QString base_name = QFileInfo(path).baseName(); + QString sfo_file = QDir(path).absoluteFilePath("PARAM.SFO"); + + if(!reader.load(sfo_file)) { + return 0; + } + + title = reader.value("TITLE", base_name.toUtf8().constData()); + savedata_detail = reader.value("SAVEDATA_DETAIL", ""); + savedata_directory = reader.value("SAVEDATA_DIRECTORY", base_name.toUtf8().constData()); + date_updated = QFileInfo(sfo_file).lastModified().toTime_t(); + + db.transaction(); + + if((ohfi = insertObjectEntry(title, type)) == 0) { + db.rollback(); + return 0; + } + + if(parent && !updateAdjacencyList(ohfi, parent)) { + db.rollback(); + return 0; + } + + if(!insertSourceEntry(ohfi, path)) { + db.rollback(); + return 0; + } + + QSqlQuery query; + query.prepare("REPLACE INTO savedata" + "(object_id, detail, dir_name, title, date_updated)" + "VALUES (:object_id, :detail, :dir_name, :title, :updated)"); + + query.bindValue(0, ohfi); + query.bindValue(1, savedata_detail); + query.bindValue(2, savedata_directory); + query.bindValue(3, title); + query.bindValue(4, date_updated); + + if(!query.exec()) { + db.rollback(); + return 0; + } + + db.commit(); + return ohfi; +} diff --git a/src/sqlitedb.h b/src/sqlitedb.h new file mode 100644 index 0000000..52dd144 --- /dev/null +++ b/src/sqlitedb.h @@ -0,0 +1,66 @@ +#ifndef SQLITEDB_H +#define SQLITEDB_H + +#include + +#include +#include +#include + +#define OBJECT_FILE 0x10000000 +#define OBJECT_FOLDER 0x20000000 +#define OBJECT_SPECIAL 0x40000000 + +#define OBJECT_MUSIC 0x00000100 +#define OBJECT_PHOTO 0x00000200 +#define OBJECT_VIDEO 0x00000400 + +#define OBJECT_ALBUM 0x00000002 +#define OBJECT_ARTIST 0x00000005 +#define OBJECT_ALBUM_ARTIST 0x00000008 +#define OBJECT_GENRE 0x0000000B + +#define OBJECT_SAVEDATA 0x00040000 +#define OBJECT_SAVEDATA_FILE 0x00000002 + +class SQLiteDB : public QObject +{ + Q_OBJECT +public: + explicit SQLiteDB(QObject *parent = 0); + ~SQLiteDB(); + + bool open(); + int create(); + void remove(); + bool initialize(); + QSqlError getLastError(); + + int getPathId(const QString &path); + QString getPathFromId(int ohfi); + bool updateSize(int ohfi, quint64 size); + bool deleteEntry(int ohfi); + bool deleteEntry(const QString &path); + uint insertObjectEntry(const char *title, int type); + bool insertSourceEntry(uint object_id, const QString &path); + uint insertMusicEntry(const QString &path, int type, int parent); + uint insertVideoEntry(const QString &path, int type, int parent); + uint insertPhotoEntry(const QString &path, int type, int parent); + uint insertSavedataEntry(const QString &path, int type, int parent); + +private: + int recursiveScanRootDirectory(const QString &base_path, int parent, int type); + uint insertDirectoryEntry(const QString &path, int type, int parent); + int checkFileType(const QString path, int ohfi_root); + bool updateAdjacencyList(int ohfi, int parent); + + QString uuid; + QSqlDatabase db; + +signals: + +public slots: + +}; + +#endif // SQLITEDB_H From d4ad94bfdd7e28a3aa8b2bf0434b33a8e4cef9a6 Mon Sep 17 00:00:00 2001 From: codestation Date: Mon, 20 Jan 2014 23:23:57 -0430 Subject: [PATCH 2/9] Merge duplicated code from Database, CMAObject and SQListDB to utils. Fix savedata metadata processing. Insert metadata from games/apps into the database. --- src/cmaevent.cpp | 2 +- src/cmaobject.cpp | 18 ---- src/cmaobject.h | 30 ------ src/database.cpp | 31 +----- src/database.h | 2 - src/sqlitedb.cpp | 263 ++++++++++++++++++++++------------------------ src/sqlitedb.h | 6 +- src/utils.cpp | 50 +++++++++ src/utils.h | 31 ++++++ 9 files changed, 212 insertions(+), 221 deletions(-) diff --git a/src/cmaevent.cpp b/src/cmaevent.cpp index add1f2d..8ea2f7b 100644 --- a/src/cmaevent.cpp +++ b/src/cmaevent.cpp @@ -212,7 +212,7 @@ quint16 CmaEvent::processAllObjects(CMAObject *parent, quint32 handle) root_obj = root_obj->parent; } - fileType = Database::checkFileType(dir.absoluteFilePath(name), root_obj->metadata.ohfi); + fileType = checkFileType(dir.absoluteFilePath(name), root_obj->metadata.ohfi); } } diff --git a/src/cmaobject.cpp b/src/cmaobject.cpp index 9236c55..c6fc284 100644 --- a/src/cmaobject.cpp +++ b/src/cmaobject.cpp @@ -29,24 +29,6 @@ int CMAObject::ohfi_count = OHFI_OFFSET; -const CMAObject::file_type CMAObject::audio_list[] = { - {"mp3", FILE_FORMAT_MP3, CODEC_TYPE_MP3}, - {"mp4", FILE_FORMAT_MP4, CODEC_TYPE_AAC}, - {"wav", FILE_FORMAT_WAV, CODEC_TYPE_PCM} -}; - -const CMAObject::file_type CMAObject::photo_list[] = { - {"jpg", FILE_FORMAT_JPG, CODEC_TYPE_JPG}, - {"jpeg", FILE_FORMAT_JPG, CODEC_TYPE_JPG}, - {"png", FILE_FORMAT_PNG, CODEC_TYPE_PNG}, - {"tif", FILE_FORMAT_TIF, CODEC_TYPE_TIF}, - {"tiff", FILE_FORMAT_TIF, CODEC_TYPE_TIF}, - {"bmp", FILE_FORMAT_BMP, CODEC_TYPE_BMP}, - {"gif", FILE_FORMAT_GIF, CODEC_TYPE_GIF}, -}; - -const char *CMAObject::video_list[] = {"mp4"}; - CMAObject::CMAObject(CMAObject *obj_parent) : parent(obj_parent), metadata() { diff --git a/src/cmaobject.h b/src/cmaobject.h index eb49b8c..e5c0953 100644 --- a/src/cmaobject.h +++ b/src/cmaobject.h @@ -27,26 +27,6 @@ #define OHFI_OFFSET 256 -#define FILE_FORMAT_MP4 1 -#define FILE_FORMAT_WAV 2 -#define FILE_FORMAT_MP3 3 -#define FILE_FORMAT_JPG 4 -#define FILE_FORMAT_PNG 5 -#define FILE_FORMAT_GIF 6 -#define FILE_FORMAT_BMP 7 -#define FILE_FORMAT_TIF 8 - -#define CODEC_TYPE_MPEG4 2 -#define CODEC_TYPE_AVC 3 -#define CODEC_TYPE_MP3 12 -#define CODEC_TYPE_AAC 13 -#define CODEC_TYPE_PCM 15 -#define CODEC_TYPE_JPG 17 -#define CODEC_TYPE_PNG 18 -#define CODEC_TYPE_TIF 19 -#define CODEC_TYPE_BMP 20 -#define CODEC_TYPE_GIF 21 - class CMAObject { public: @@ -72,16 +52,6 @@ public: ohfi_count = OHFI_OFFSET; } - typedef struct { - const char *file_ext; - int file_format; - int file_codec; - } file_type; - - static const file_type audio_list[3]; - static const file_type photo_list[7]; - static const char *video_list[1]; - QString path; CMAObject *parent; metadata_t metadata; diff --git a/src/database.cpp b/src/database.cpp index 448a3dd..a7a95c2 100644 --- a/src/database.cpp +++ b/src/database.cpp @@ -17,6 +17,7 @@ * along with this program. If not, see . */ +#include "utils.h" #include "database.h" #include "cmaobject.h" @@ -477,33 +478,3 @@ int Database::filterObjects(int ohfiParent, metadata_t **p_head, int index, int return numObjects; } - -int Database::checkFileType(const QString path, int ohfi_root) -{ - switch(ohfi_root) { - case VITA_OHFI_MUSIC: - for(int i = 0, max = sizeof(CMAObject::audio_list) / sizeof(CMAObject::file_type); i < max; i++) { - if(path.endsWith(CMAObject::audio_list[i].file_ext, Qt::CaseInsensitive)) { - return i; - } - } - break; - case VITA_OHFI_PHOTO: - for(int i = 0, max = sizeof(CMAObject::photo_list) / sizeof(CMAObject::file_type); i < max; i++) { - if(path.endsWith(CMAObject::photo_list[i].file_ext, Qt::CaseInsensitive)) { - return i; - } - } - break; - case VITA_OHFI_VIDEO: - for(int i = 0, max = sizeof(CMAObject::video_list) / sizeof(const char *); i < max; i++) { - if(path.endsWith(CMAObject::video_list[i], Qt::CaseInsensitive)) { - return i; - } - } - break; - default: - return 0; - } - return -1; -} diff --git a/src/database.h b/src/database.h index 0f5a184..a2effc2 100644 --- a/src/database.h +++ b/src/database.h @@ -53,8 +53,6 @@ public: CMAObject *pathToObject(const char *path, int ohfiRoot); int acceptFilteredObject(const CMAObject *parent, const CMAObject *current, int type); - static int checkFileType(const QString path, int ohfi_root); - QMutex mutex; private: diff --git a/src/sqlitedb.cpp b/src/sqlitedb.cpp index c832e75..d6f1742 100644 --- a/src/sqlitedb.cpp +++ b/src/sqlitedb.cpp @@ -1,3 +1,4 @@ +#include "utils.h" #include "sqlitedb.h" #include "sforeader.h" #include "avdecoder.h" @@ -50,6 +51,11 @@ static const char create_music[] = "CREATE TABLE IF NOT EXISTS music (" "album TEXT," "track_number INTEGER)"; +static const char create_apps[] = "CREATE TABLE IF NOT EXISTS application (" + "object_id INTEGER PRIMARY KEY REFERENCES object_node(object_id) ON DELETE CASCADE," + "title TEXT NOT NULL CHECK (LENGTH(title) > 0)," + "app_type INTEGER)"; + static const char create_photos[] = "CREATE TABLE IF NOT EXISTS photos (" "object_id INTEGER PRIMARY KEY REFERENCES object_node(object_id) ON DELETE CASCADE," "date_created TIMESTAMP," @@ -80,75 +86,28 @@ static const char create_savedata[] = "CREATE TABLE IF NOT EXISTS savedata (" "date_updated TIMESTAMP)"; static const char create_trigger_node[] = "CREATE TRIGGER IF NOT EXISTS trg_objnode_deletechilds BEFORE DELETE ON object_node " - "FOR EACH ROW BEGIN " - "DELETE FROM object_node WHERE object_id IN " - "(SELECT child_id FROM adjacent_objects WHERE parent_id == OLD.object_id);" - "END"; + "FOR EACH ROW BEGIN " + "DELETE FROM object_node WHERE object_id IN " + "(SELECT child_id FROM adjacent_objects WHERE parent_id == OLD.object_id);" + "END"; static const char create_trigger_adjins[] = "CREATE TRIGGER IF NOT EXISTS trg_adjacentobjects_ins AFTER INSERT ON adjacent_objects " - "FOR EACH ROW BEGIN " - "UPDATE object_node SET child_count = child_count + 1 WHERE object_id = NEW.parent_id;" - "UPDATE object_node SET reference_count = reference_count + 1 WHERE object_id = NEW.child_id;" - "END"; + "FOR EACH ROW BEGIN " + "UPDATE object_node SET child_count = child_count + 1 WHERE object_id = NEW.parent_id;" + "UPDATE object_node SET reference_count = reference_count + 1 WHERE object_id = NEW.child_id;" + "END"; static const char create_trigger_adjdel[] = "CREATE TRIGGER IF NOT EXISTS trg_adjacentobjects_del AFTER DELETE ON adjacent_objects " - "FOR EACH ROW BEGIN " - "UPDATE object_node SET child_count = child_count - 1 WHERE object_id = OLD.parent_id;" - "UPDATE object_node SET reference_count = reference_count - 1 WHERE object_id = OLD.child_id;" - "DELETE FROM object_node WHERE object_id = OLD.parent_id AND child_count <= 0;" - "DELETE FROM object_node WHERE object_id = OLD.child_id AND reference_count <= 0;" - "END"; - -typedef struct { - const char *file_ext; - int file_format; - int file_codec; -} file_type; - -#define FILE_FORMAT_MP4 1 -#define FILE_FORMAT_WAV 2 -#define FILE_FORMAT_MP3 3 -#define FILE_FORMAT_JPG 4 -#define FILE_FORMAT_PNG 5 -#define FILE_FORMAT_GIF 6 -#define FILE_FORMAT_BMP 7 -#define FILE_FORMAT_TIF 8 - -#define CODEC_TYPE_MPEG4 2 -#define CODEC_TYPE_AVC 3 -#define CODEC_TYPE_MP3 12 -#define CODEC_TYPE_AAC 13 -#define CODEC_TYPE_PCM 15 -#define CODEC_TYPE_JPG 17 -#define CODEC_TYPE_PNG 18 -#define CODEC_TYPE_TIF 19 -#define CODEC_TYPE_BMP 20 -#define CODEC_TYPE_GIF 21 - -static const file_type audio_list[] = { - {"mp3", FILE_FORMAT_MP3, CODEC_TYPE_MP3}, - {"mp4", FILE_FORMAT_MP4, CODEC_TYPE_AAC}, - {"wav", FILE_FORMAT_WAV, CODEC_TYPE_PCM} -}; - -static const file_type photo_list[] = { - {"jpg", FILE_FORMAT_JPG, CODEC_TYPE_JPG}, - {"jpeg", FILE_FORMAT_JPG, CODEC_TYPE_JPG}, - {"png", FILE_FORMAT_PNG, CODEC_TYPE_PNG}, - {"tif", FILE_FORMAT_TIF, CODEC_TYPE_TIF}, - {"tiff", FILE_FORMAT_TIF, CODEC_TYPE_TIF}, - {"bmp", FILE_FORMAT_BMP, CODEC_TYPE_BMP}, - {"gif", FILE_FORMAT_GIF, CODEC_TYPE_GIF}, -}; - -static const file_type video_list[] = { - {"mp4", FILE_FORMAT_MP4, 0} -}; - + "FOR EACH ROW BEGIN " + "UPDATE object_node SET child_count = child_count - 1 WHERE object_id = OLD.parent_id;" + "UPDATE object_node SET reference_count = reference_count - 1 WHERE object_id = OLD.child_id;" + "DELETE FROM object_node WHERE object_id = OLD.parent_id AND child_count <= 0;" + "DELETE FROM object_node WHERE object_id = OLD.child_id AND reference_count <= 0;" + "END"; static const char *table_list[] = { create_adjacent, create_obj_node, create_sources, - create_music, create_photos, create_videos, create_savedata + create_music, create_photos, create_videos, create_savedata, create_apps }; static const char *trigger_list[] = { @@ -219,34 +178,6 @@ QSqlError SQLiteDB::getLastError() return db.lastError(); } -int SQLiteDB::checkFileType(const QString path, int ohfi_root) -{ - switch(ohfi_root) { - case VITA_OHFI_MUSIC: - for(int i = 0, max = sizeof(audio_list) / sizeof(file_type); i < max; i++) { - if(path.endsWith(audio_list[i].file_ext, Qt::CaseInsensitive)) { - return i; - } - } - break; - case VITA_OHFI_PHOTO: - for(int i = 0, max = sizeof(photo_list) / sizeof(file_type); i< max; i++) { - if(path.endsWith(photo_list[i].file_ext, Qt::CaseInsensitive)) { - return i; - } - } - break; - case VITA_OHFI_VIDEO: - for(int i = 0, max = sizeof(video_list) / sizeof(file_type); i< max; i++) { - if(path.endsWith(video_list[i].file_ext, Qt::CaseInsensitive)) { - return i; - } - } - break; - } - return -1; -} - int SQLiteDB::create() { int total_objects = 0; @@ -271,31 +202,26 @@ int SQLiteDB::create() base_path = settings.value("photoPath").toString(); break; case VITA_OHFI_BACKUP: - continue; base_path = settings.value("appsPath").toString() + QDir::separator() + "SYSTEM" + QDir::separator() + uuid; break; case VITA_OHFI_VITAAPP: - continue; base_path = settings.value("appsPath").toString() + QDir::separator() + "APP" + QDir::separator() + uuid; break; case VITA_OHFI_PSPAPP: - continue; base_path = settings.value("appsPath").toString() + QDir::separator() + "PGAME" + QDir::separator() + uuid; break; case VITA_OHFI_PSPSAVE: base_path = settings.value("appsPath").toString() + QDir::separator() + "PSAVEDATA" + QDir::separator() + uuid; break; case VITA_OHFI_PSXAPP: - continue; base_path = settings.value("appsPath").toString() + QDir::separator() + "PSGAME" + QDir::separator() + uuid; break; case VITA_OHFI_PSMAPP: - continue; base_path = settings.value("appsPath").toString() + QDir::separator() + "PSM" + QDir::separator() + uuid; break; } - int dir_count = recursiveScanRootDirectory(base_path, ohfi_array[i], OBJECT_FOLDER); + int dir_count = recursiveScanRootDirectory(base_path, ohfi_array[i], ohfi_array[i]); if(dir_count < 0) { return -1; @@ -314,7 +240,7 @@ int SQLiteDB::recursiveScanRootDirectory(const QString &base_path, int parent, i QFileInfoList qsl = dir.entryInfoList(QDir::AllEntries | QDir::NoDotAndDotDot); foreach(const QFileInfo &info, qsl) { - qDebug() << "Processing " << info.fileName(); + //qDebug() << "Processing " << info.fileName(); if(info.isDir()) { int ohfi = insertDirectoryEntry(info.absoluteFilePath(), parent_type, parent); total_objects += recursiveScanRootDirectory(info.absoluteFilePath(), ohfi, parent_type); @@ -332,6 +258,12 @@ int SQLiteDB::recursiveScanRootDirectory(const QString &base_path, int parent, i case VITA_OHFI_PSPSAVE: insertSavedataEntry(info.absoluteFilePath(), OBJECT_SAVEDATA | (parent_type & ~OBJECT_FOLDER), parent); break; + case VITA_OHFI_VITAAPP: + case VITA_OHFI_PSPAPP: + case VITA_OHFI_PSXAPP: + case VITA_OHFI_PSMAPP: + case VITA_OHFI_BACKUP: + insertApplicationEntry(info.absoluteFilePath(), OBJECT_APPLICATION | (parent_type & ~OBJECT_FOLDER), parent, parent_type); } total_objects++; @@ -434,19 +366,19 @@ uint SQLiteDB::insertObjectEntry(const char *title, int type) { QSqlQuery query; - query.prepare("SELECT object_id FROM object_node WHERE type == :type and title == :title"); + //query.prepare("SELECT object_id FROM object_node WHERE type == :type and title == :title"); + //query.bindValue(0, type); + //query.bindValue(1, title); + + //if(!query.exec() || !query.next()) { + query.prepare("INSERT INTO object_node (type, title) VALUES (:type, :title)"); query.bindValue(0, type); - query.bindValue(1, title); + query.bindValue(1, title); - if(!query.exec() || !query.next()) { - query.prepare("INSERT INTO object_node (type, title) VALUES (:type, :title)"); - query.bindValue(0, type); - query.bindValue(1, title); - - if(!query.exec() || !query.exec("SELECT last_insert_rowid()") || !query.next()) { - return 0; - } + if(!query.exec() || !query.exec("SELECT last_insert_rowid()") || !query.next()) { + return 0; } + //} return query.value(0).toInt(); } @@ -481,7 +413,7 @@ uint SQLiteDB::insertMusicEntry(const QString &path, int type, int parent) const char *artist, *album, *albumartist, *genre, *track, *title; int file_format, audio_codec, audio_bitrate, genre_id, artist_id, track_id, album_id, track_number; - int file_type = checkFileType(path, type); + int file_type = checkFileType(path, VITA_OHFI_MUSIC); if(file_type < 0) { qDebug() << "Excluding from database:" << path; return 0; @@ -497,12 +429,18 @@ uint SQLiteDB::insertMusicEntry(const QString &path, int type, int parent) albumartist = decoder.getMetadataEntry("album_artist"); track = decoder.getMetadataEntry("track"); - track_number = QString(track).toInt(&ok); + track_number = QString(track).split("/")[0].toInt(&ok); if(!ok) { // set track number to 1 by default track_number = 1; } - audio_bitrate = decoder.getBitrate(); + + if(decoder.loadCodec(AVDecoder::CODEC_AUDIO)) { + audio_bitrate = decoder.getBitrate(); + } else { + audio_bitrate = 0; + } + duration = decoder.getDuration(); file_format = audio_list[file_type].file_format; @@ -579,8 +517,8 @@ uint SQLiteDB::insertMusicEntry(const QString &path, int type, int parent) QSqlQuery query; query.prepare("REPLACE INTO music" - "(object_id, file_format, audio_codec, audio_bitrate, duration, genre_id, artist_id, album_id, track_id, artist, album, track_number)" - "VALUES (:object_id, :file_format, :audio_codec, :audio_bitrate, :duration, :genre_id, :artist_id, :album_id, :track_id, :artist, :album, :track_number)"); + "(object_id, file_format, audio_codec, audio_bitrate, duration, genre_id, artist_id, album_id, track_id, artist, album, track_number)" + "VALUES (:object_id, :file_format, :audio_codec, :audio_bitrate, :duration, :genre_id, :artist_id, :album_id, :track_id, :artist, :album, :track_number)"); query.bindValue(0, ohfi); query.bindValue(1, file_format); @@ -616,7 +554,7 @@ uint SQLiteDB::insertVideoEntry(const QString &path, int type, int parent) return 0; } - int file_type = checkFileType(path, type); + int file_type = checkFileType(path, VITA_OHFI_VIDEO); if(file_type < 0) { qDebug() << "Excluding from database:" << path; return 0; @@ -628,13 +566,13 @@ uint SQLiteDB::insertVideoEntry(const QString &path, int type, int parent) width = decoder.getWidth(); height = decoder.getHeight(); duration = decoder.getDuration(); - video_codec = 3; - video_bitrate = decoder.getCodecBitrate(); + video_codec = CODEC_TYPE_AVC; + video_bitrate = decoder.getBitrate(); file_format = video_list[file_type].file_format; if(decoder.loadCodec(AVDecoder::CODEC_AUDIO)) { - audio_codec = 13; - audio_bitrate = decoder.getCodecBitrate(); + audio_codec = CODEC_TYPE_AAC; + audio_bitrate = decoder.getBitrate(); } else { audio_codec = 0; audio_bitrate = 0; @@ -663,8 +601,8 @@ uint SQLiteDB::insertVideoEntry(const QString &path, int type, int parent) QSqlQuery query; query.prepare("REPLACE INTO videos" - "(object_id, file_format, parental_level, explanation, copyright, width, height, video_codec, video_bitrate, audio_codec, audio_bitrate, duration)" - "VALUES (:object_id, :file_format, :parental_level, :explanation, :copyright, :width, :height, :video_codec, :video_bitrate, :audio_codec, :audio_bitrate, :duration)"); + "(object_id, file_format, parental_level, explanation, copyright, width, height, video_codec, video_bitrate, audio_codec, audio_bitrate, duration)" + "VALUES (:object_id, :file_format, :parental_level, :explanation, :copyright, :width, :height, :video_codec, :video_bitrate, :audio_codec, :audio_bitrate, :duration)"); query.bindValue(0, ohfi); query.bindValue(1, file_format); @@ -696,7 +634,7 @@ uint SQLiteDB::insertPhotoEntry(const QString &path, int type, int parent) uint date_created; int width, height, file_format, photo_codec; - int file_type = checkFileType(path, type); + int file_type = checkFileType(path, VITA_OHFI_PHOTO); if(file_type < 0) { qDebug() << "Excluding from database:" << path; return 0; @@ -733,8 +671,8 @@ uint SQLiteDB::insertPhotoEntry(const QString &path, int type, int parent) QSqlQuery query; query.prepare("REPLACE INTO photos" - "(object_id, date_created, file_format, photo_codec, width, height)" - "VALUES (:object_id, :date_created, :file_format, :photo_codec, :width, :height)"); + "(object_id, date_created, file_format, photo_codec, width, height)" + "VALUES (:object_id, :date_created, :file_format, :photo_codec, :width, :height)"); query.bindValue(0, ohfi); query.bindValue(1, date_created); @@ -755,25 +693,24 @@ uint SQLiteDB::insertPhotoEntry(const QString &path, int type, int parent) uint SQLiteDB::insertSavedataEntry(const QString &path, int type, int parent) { int ohfi; - - uint date_updated; - const char *title, *savedata_detail, *savedata_directory; - SfoReader reader; - QString base_name = QFileInfo(path).baseName(); - QString sfo_file = QDir(path).absoluteFilePath("PARAM.SFO"); + uint date_updated = 0; + const char *title = NULL; + const char *savedata_detail = NULL; + const char *savedata_directory = NULL; - if(!reader.load(sfo_file)) { - return 0; - } - - title = reader.value("TITLE", base_name.toUtf8().constData()); - savedata_detail = reader.value("SAVEDATA_DETAIL", ""); - savedata_directory = reader.value("SAVEDATA_DIRECTORY", base_name.toUtf8().constData()); - date_updated = QFileInfo(sfo_file).lastModified().toTime_t(); + QString file_name = QFileInfo(path).fileName(); + QByteArray utf8name = file_name.toUtf8(); db.transaction(); + if(file_name.endsWith(".sfo", Qt::CaseInsensitive) && reader.load(path)) { + title = reader.value("TITLE", utf8name.constData()); + savedata_detail = reader.value("SAVEDATA_DETAIL", ""); + savedata_directory = reader.value("SAVEDATA_DIRECTORY", utf8name.constData()); + date_updated = QFileInfo(path).lastModified().toTime_t(); + } + if((ohfi = insertObjectEntry(title, type)) == 0) { db.rollback(); return 0; @@ -789,10 +726,18 @@ uint SQLiteDB::insertSavedataEntry(const QString &path, int type, int parent) return 0; } + if(!path.endsWith(".sfo", Qt::CaseInsensitive)) { + return 0; + } + + if(!title) { + return 0; + } + QSqlQuery query; query.prepare("REPLACE INTO savedata" - "(object_id, detail, dir_name, title, date_updated)" - "VALUES (:object_id, :detail, :dir_name, :title, :updated)"); + "(object_id, detail, dir_name, title, date_updated)" + "VALUES (:object_id, :detail, :dir_name, :title, :updated)"); query.bindValue(0, ohfi); query.bindValue(1, savedata_detail); @@ -808,3 +753,45 @@ uint SQLiteDB::insertSavedataEntry(const QString &path, int type, int parent) db.commit(); return ohfi; } + + +uint SQLiteDB::insertApplicationEntry(const QString &path, int type, int parent, int app_type) +{ + int ohfi; + + QString base_name = QFileInfo(path).baseName(); + + db.transaction(); + + if((ohfi = insertObjectEntry(base_name.toUtf8().constData(), type)) == 0) { + db.rollback(); + return 0; + } + + if(parent && !updateAdjacencyList(ohfi, parent)) { + db.rollback(); + return 0; + } + + if(!insertSourceEntry(ohfi, path)) { + db.rollback(); + return 0; + } + + QSqlQuery query; + query.prepare("REPLACE INTO application" + "(object_id, title, app_type)" + "VALUES (:object_id, :title, :app_type)"); + + query.bindValue(0, ohfi); + query.bindValue(1, base_name); + query.bindValue(2, app_type); + + if(!query.exec()) { + db.rollback(); + return 0; + } + + db.commit(); + return ohfi; +} diff --git a/src/sqlitedb.h b/src/sqlitedb.h index 52dd144..e2a42d6 100644 --- a/src/sqlitedb.h +++ b/src/sqlitedb.h @@ -23,6 +23,8 @@ #define OBJECT_SAVEDATA 0x00040000 #define OBJECT_SAVEDATA_FILE 0x00000002 +#define OBJECT_APPLICATION 0x00080000 + class SQLiteDB : public QObject { Q_OBJECT @@ -47,11 +49,11 @@ public: uint insertVideoEntry(const QString &path, int type, int parent); uint insertPhotoEntry(const QString &path, int type, int parent); uint insertSavedataEntry(const QString &path, int type, int parent); + uint insertApplicationEntry(const QString &path, int type, int parent, int app_type); -private: +private: int recursiveScanRootDirectory(const QString &base_path, int parent, int type); uint insertDirectoryEntry(const QString &path, int type, int parent); - int checkFileType(const QString path, int ohfi_root); bool updateAdjacencyList(int ohfi, int parent); QString uuid; diff --git a/src/utils.cpp b/src/utils.cpp index 22059f0..07e814d 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -31,6 +31,26 @@ #include #endif +const file_type audio_list[] = { + {"mp3", FILE_FORMAT_MP3, CODEC_TYPE_MP3}, + {"mp4", FILE_FORMAT_MP4, CODEC_TYPE_AAC}, + {"wav", FILE_FORMAT_WAV, CODEC_TYPE_PCM} +}; + +const file_type photo_list[] = { + {"jpg", FILE_FORMAT_JPG, CODEC_TYPE_JPG}, + {"jpeg", FILE_FORMAT_JPG, CODEC_TYPE_JPG}, + {"png", FILE_FORMAT_PNG, CODEC_TYPE_PNG}, + {"tif", FILE_FORMAT_TIF, CODEC_TYPE_TIF}, + {"tiff", FILE_FORMAT_TIF, CODEC_TYPE_TIF}, + {"bmp", FILE_FORMAT_BMP, CODEC_TYPE_BMP}, + {"gif", FILE_FORMAT_GIF, CODEC_TYPE_GIF}, +}; + +const file_type video_list[] = { + {"mp4", FILE_FORMAT_MP4, 0} +}; + bool getDiskSpace(const QString &dir, quint64 *free, quint64 *total) { #ifdef Q_OS_WIN32 @@ -175,3 +195,33 @@ QString readable_size(quint64 size, bool use_gib) } return QString().setNum(size_f,'f',2) + " " + unit; } + +int checkFileType(const QString path, int ohfi_root) +{ + switch(ohfi_root) { + case VITA_OHFI_MUSIC: + for(int i = 0, max = sizeof(audio_list) / sizeof(file_type); i < max; i++) { + if(path.endsWith(audio_list[i].file_ext, Qt::CaseInsensitive)) { + return i; + } + } + break; + case VITA_OHFI_PHOTO: + for(int i = 0, max = sizeof(photo_list) / sizeof(file_type); i< max; i++) { + if(path.endsWith(photo_list[i].file_ext, Qt::CaseInsensitive)) { + return i; + } + } + break; + case VITA_OHFI_VIDEO: + for(int i = 0, max = sizeof(video_list) / sizeof(file_type); i< max; i++) { + if(path.endsWith(video_list[i].file_ext, Qt::CaseInsensitive)) { + return i; + } + } + break; + default: + return 0; + } + return -1; +} diff --git a/src/utils.h b/src/utils.h index 8d8deba..816a34f 100644 --- a/src/utils.h +++ b/src/utils.h @@ -26,6 +26,36 @@ #include +typedef struct { + const char *file_ext; + int file_format; + int file_codec; +} file_type; + +#define FILE_FORMAT_MP4 1 +#define FILE_FORMAT_WAV 2 +#define FILE_FORMAT_MP3 3 +#define FILE_FORMAT_JPG 4 +#define FILE_FORMAT_PNG 5 +#define FILE_FORMAT_GIF 6 +#define FILE_FORMAT_BMP 7 +#define FILE_FORMAT_TIF 8 + +#define CODEC_TYPE_MPEG4 2 +#define CODEC_TYPE_AVC 3 +#define CODEC_TYPE_MP3 12 +#define CODEC_TYPE_AAC 13 +#define CODEC_TYPE_PCM 15 +#define CODEC_TYPE_JPG 17 +#define CODEC_TYPE_PNG 18 +#define CODEC_TYPE_TIF 19 +#define CODEC_TYPE_BMP 20 +#define CODEC_TYPE_GIF 21 + +extern const file_type audio_list[3]; +extern const file_type photo_list[7]; +extern const file_type video_list[1]; + // Qt4 doesn't have public methods for Thread::*sleep #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) typedef QThread Sleeper; @@ -49,5 +79,6 @@ bool removeRecursively(const QString &dirName); QString readable_size(quint64 size, bool use_gib = false); bool getDiskSpace(const QString &dir, quint64 *free, quint64 *total); QByteArray getThumbnail(const QString &path, DataType type, metadata_t *metadata); +int checkFileType(const QString path, int ohfi_root); #endif // UTILS_H From e1aa32894da3a865c5b0183ea8c631b9e2655ebb Mon Sep 17 00:00:00 2001 From: codestation Date: Fri, 24 Jan 2014 13:08:35 -0430 Subject: [PATCH 3/9] Renamed database class to qlistdb in preparation to create generic database class. --- qcma.pro | 12 +++---- src/clientmanager.h | 4 +-- src/cmaclient.h | 2 +- src/cmaevent.cpp | 6 ++-- src/cmaevent.h | 4 +-- src/forms/backupmanagerform.h | 4 +-- src/{database.cpp => qlistdb.cpp} | 56 +++++++++++++++---------------- src/{database.h => qlistdb.h} | 12 +++---- src/sqlitedb.cpp | 34 ++++++++++++------- 9 files changed, 72 insertions(+), 62 deletions(-) rename src/{database.cpp => qlistdb.cpp} (88%) rename src/{database.h => qlistdb.h} (95%) diff --git a/qcma.pro b/qcma.pro index 39291a5..85c3f2a 100644 --- a/qcma.pro +++ b/qcma.pro @@ -18,7 +18,6 @@ TEMPLATE = app SOURCES += src/main.cpp \ src/capability.cpp \ - src/database.cpp \ src/cmaobject.cpp \ src/cmarootobject.cpp \ src/utils.cpp \ @@ -33,18 +32,18 @@ SOURCES += src/main.cpp \ src/filterlineedit.cpp \ src/dds.cpp \ src/sqlitedb.cpp \ + src/httpdownloader.cpp \ + src/qlistdb.cpp \ # forms src/forms/backupitem.cpp \ src/forms/backupmanagerform.cpp \ src/forms/configwidget.cpp \ src/forms/confirmdialog.cpp \ src/forms/pinform.cpp \ - src/forms/progressform.cpp \ - src/httpdownloader.cpp + src/forms/progressform.cpp HEADERS += \ src/capability.h \ - src/database.h \ src/cmaobject.h \ src/cmarootobject.h \ src/utils.h \ @@ -59,14 +58,15 @@ HEADERS += \ src/filterlineedit.h \ src/dds.h \ src/sqlitedb.h \ + src/httpdownloader.h \ + src/qlistdb.h \ # forms src/forms/backupitem.h \ src/forms/backupmanagerform.h \ src/forms/configwidget.h \ src/forms/confirmdialog.h \ src/forms/pinform.h \ - src/forms/progressform.h \ - src/httpdownloader.h + src/forms/progressform.h FORMS += \ src/forms/configwidget.ui \ diff --git a/src/clientmanager.h b/src/clientmanager.h index 9ff8792..54bfede 100644 --- a/src/clientmanager.h +++ b/src/clientmanager.h @@ -20,7 +20,7 @@ #ifndef CLIENTMANAGER_H #define CLIENTMANAGER_H -#include "database.h" +#include "qlistdb.h" #include "forms/pinform.h" #include "forms/progressform.h" @@ -37,7 +37,7 @@ public: void start(); void stop(); - Database db; + QListDB db; private: int thread_count; diff --git a/src/cmaclient.h b/src/cmaclient.h index d2023f8..93bc550 100644 --- a/src/cmaclient.h +++ b/src/cmaclient.h @@ -20,7 +20,7 @@ #ifndef CMACLIENT_H #define CMACLIENT_H -#include "database.h" +#include "qlistdb.h" #include "cmaevent.h" #include "cmaobject.h" #include "cmabroadcast.h" diff --git a/src/cmaevent.cpp b/src/cmaevent.cpp index 8ea2f7b..1a7c8ba 100644 --- a/src/cmaevent.cpp +++ b/src/cmaevent.cpp @@ -29,7 +29,7 @@ #include -Database *CmaEvent::db = NULL; +QListDB *CmaEvent::db = NULL; QFile *CmaEvent::m_file = NULL; metadata_t CmaEvent::g_thumbmeta = {0, 0, 0, NULL, NULL, 0, 0, 0, Thumbnail, {{17, 240, 136, 0, 1, 1.0f, 2}}, NULL}; @@ -412,7 +412,7 @@ void CmaEvent::vitaEventSendObject(vita_event_t *event, int eventId) qDebug("Searching object with OHFI %d", ohfi); - Database::find_data iters; + QListDB::find_data iters; if(!db->find(ohfi, iters)) { qWarning("Failed to find OHFI %d", ohfi); VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_OHFI); @@ -816,7 +816,7 @@ void CmaEvent::vitaEventOperateObject(vita_event_t *event, int eventId) //rename the current object root->rename(operateobject.title); - Database::find_data iters; + QListDB::find_data iters; db->find(root->metadata.ohfi, iters); // rename the rest of the list only if has the renamed parent in some part of the chain diff --git a/src/cmaevent.h b/src/cmaevent.h index e2f1d98..3ff4e92 100644 --- a/src/cmaevent.h +++ b/src/cmaevent.h @@ -21,7 +21,7 @@ #define CMAEVENT_H #include "cmaobject.h" -#include "database.h" +#include "qlistdb.h" #include "httpdownloader.h" #include @@ -39,7 +39,7 @@ public: void vitaEventCancelTask(vita_event_t *event, int eventId); // don't make the db reference static - static Database *db; + static QListDB *db; private: uint16_t processAllObjects(CMAObject *parent, uint32_t handle); diff --git a/src/forms/backupmanagerform.h b/src/forms/backupmanagerform.h index e09fef7..eddeb63 100644 --- a/src/forms/backupmanagerform.h +++ b/src/forms/backupmanagerform.h @@ -20,7 +20,7 @@ #ifndef BACKUPMANAGERFORM_H #define BACKUPMANAGERFORM_H -#include "database.h" +#include "qlistdb.h" #include "backupitem.h" #include @@ -37,7 +37,7 @@ public: explicit BackupManagerForm(QWidget *parent = 0); ~BackupManagerForm(); - Database *db; + QListDB *db; private: void setupForm(); diff --git a/src/database.cpp b/src/qlistdb.cpp similarity index 88% rename from src/database.cpp rename to src/qlistdb.cpp index a7a95c2..eff9f9a 100644 --- a/src/database.cpp +++ b/src/qlistdb.cpp @@ -18,7 +18,7 @@ */ #include "utils.h" -#include "database.h" +#include "qlistdb.h" #include "cmaobject.h" #include @@ -28,7 +28,7 @@ #include #include -Database::Database() : +QListDB::QListDB() : mutex(QMutex::Recursive) { QString uuid = QSettings().value("lastAccountId", "ffffffffffffffff").toString(); @@ -43,7 +43,7 @@ Database::Database() : connect(timer, SIGNAL(timeout()), this, SLOT(process())); } -Database::~Database() +QListDB::~QListDB() { destroy(); timer->stop(); @@ -53,13 +53,13 @@ Database::~Database() delete thread; } -void Database::setUUID(const QString uuid) +void QListDB::setUUID(const QString uuid) { CMARootObject::uuid = uuid; QSettings().setValue("lastAccountId", uuid); } -bool Database::reload(bool &prepared) +bool QListDB::reload(bool &prepared) { if(mutex.tryLock()) { if(CMARootObject::uuid != "ffffffffffffffff") { @@ -76,7 +76,7 @@ bool Database::reload(bool &prepared) } } -void Database::process() +void QListDB::process() { destroy(); cancel_operation = false; @@ -90,19 +90,19 @@ void Database::process() mutex.unlock(); } -void Database::cancelOperation() +void QListDB::cancelOperation() { QMutexLocker locker(&cancel); cancel_operation = true; } -bool Database::continueOperation() +bool QListDB::continueOperation() { QMutexLocker locker(&cancel); return !cancel_operation; } -int Database::create() +int QListDB::create() { int total_objects = 0; //QMutexLocker locker(&mutex); @@ -153,7 +153,7 @@ int Database::create() return total_objects; } -CMAObject *Database::getParent(CMAObject *last_dir, const QString ¤t_path) +CMAObject *QListDB::getParent(CMAObject *last_dir, const QString ¤t_path) { while(last_dir && current_path != last_dir->path) { last_dir = last_dir->parent; @@ -162,7 +162,7 @@ CMAObject *Database::getParent(CMAObject *last_dir, const QString ¤t_path) return last_dir; } -int Database::scanRootDirectory(root_list &list, int ohfi_type) +int QListDB::scanRootDirectory(root_list &list, int ohfi_type) { int file_type = -1; int total_objects = 0; @@ -201,7 +201,7 @@ int Database::scanRootDirectory(root_list &list, int ohfi_type) return total_objects; } -int Database::recursiveScanRootDirectory(root_list &list, CMAObject *parent, int ohfi_type) +int QListDB::recursiveScanRootDirectory(root_list &list, CMAObject *parent, int ohfi_type) { int file_type = -1; int total_objects = 0; @@ -236,7 +236,7 @@ int Database::recursiveScanRootDirectory(root_list &list, CMAObject *parent, int return total_objects; } -void Database::destroy() +void QListDB::destroy() { //QMutexLocker locker(&mutex); @@ -249,7 +249,7 @@ void Database::destroy() object_list.clear(); } -bool Database::removeInternal(root_list &list, const CMAObject *obj) +bool QListDB::removeInternal(root_list &list, const CMAObject *obj) { bool found = false; QList::iterator it = list.begin(); @@ -270,7 +270,7 @@ bool Database::removeInternal(root_list &list, const CMAObject *obj) return found; } -bool Database::remove(const CMAObject *obj, int ohfi_root) +bool QListDB::remove(const CMAObject *obj, int ohfi_root) { QMutexLocker locker(&mutex); @@ -286,12 +286,12 @@ bool Database::remove(const CMAObject *obj, int ohfi_root) return false; } -bool Database::lessThanComparator(const CMAObject *a, const CMAObject *b) +bool QListDB::lessThanComparator(const CMAObject *a, const CMAObject *b) { return a->metadata.ohfi < b->metadata.ohfi; } -bool Database::hasFilter(const CMARootObject *object,int ohfi) +bool QListDB::hasFilter(const CMARootObject *object,int ohfi) { for(int i = 0; i < object->num_filters; i++) { if(object->filters[i].ohfi == ohfi) { @@ -301,20 +301,20 @@ bool Database::hasFilter(const CMARootObject *object,int ohfi) return false; } -bool Database::findInternal(const root_list &list, int ohfi, find_data &data) +bool QListDB::findInternal(const root_list &list, int ohfi, find_data &data) { if(hasFilter(static_cast(list.first()), ohfi)) { data.it = list.begin(); } else { CMAObject obj; obj.setOhfi(ohfi); - data.it = qBinaryFind(list.begin(), list.end(), &obj, Database::lessThanComparator); + data.it = qBinaryFind(list.begin(), list.end(), &obj, QListDB::lessThanComparator); } data.end = list.end(); return data.it != data.end; } -bool Database::find(int ohfi, Database::find_data &data) +bool QListDB::find(int ohfi, QListDB::find_data &data) { QMutexLocker locker(&mutex); @@ -326,7 +326,7 @@ bool Database::find(int ohfi, Database::find_data &data) return false; } -void Database::append(int parent_ohfi, CMAObject *object) +void QListDB::append(int parent_ohfi, CMAObject *object) { QMutexLocker locker(&mutex); CMAObject parent; @@ -334,7 +334,7 @@ void Database::append(int parent_ohfi, CMAObject *object) for(map_list::iterator root = object_list.begin(); root != object_list.end(); ++root) { root_list *cat_list = &(*root); - root_list::const_iterator it = qBinaryFind(cat_list->begin(), cat_list->end(), &parent, Database::lessThanComparator); + root_list::const_iterator it = qBinaryFind(cat_list->begin(), cat_list->end(), &parent, QListDB::lessThanComparator); if(it != cat_list->end()) { cat_list->append(object); @@ -343,14 +343,14 @@ void Database::append(int parent_ohfi, CMAObject *object) } } -CMAObject *Database::ohfiToObject(int ohfi) +CMAObject *QListDB::ohfiToObject(int ohfi) { QMutexLocker locker(&mutex); find_data data; return find(ohfi, data) ? *data.it : NULL; } -CMAObject *Database::pathToObjectInternal(const root_list &list, const char *path) +CMAObject *QListDB::pathToObjectInternal(const root_list &list, const char *path) { // skip the first element since is the root element root_list::const_iterator skipped_first = ++list.begin(); @@ -363,7 +363,7 @@ CMAObject *Database::pathToObjectInternal(const root_list &list, const char *pat return NULL; } -CMAObject *Database::pathToObject(const char *path, int ohfiRoot) +CMAObject *QListDB::pathToObject(const char *path, int ohfiRoot) { QMutexLocker locker(&mutex); @@ -381,7 +381,7 @@ CMAObject *Database::pathToObject(const char *path, int ohfiRoot) return NULL; } -int Database::acceptFilteredObject(const CMAObject *parent, const CMAObject *current, int type) +int QListDB::acceptFilteredObject(const CMAObject *parent, const CMAObject *current, int type) { QMutexLocker locker(&mutex); int result = 0; @@ -413,7 +413,7 @@ int Database::acceptFilteredObject(const CMAObject *parent, const CMAObject *cur return result; } -void Database::dumpMetadataList(const metadata_t *p_head) +void QListDB::dumpMetadataList(const metadata_t *p_head) { while(p_head) { qDebug("Metadata: %s with OHFI %d", p_head->name, p_head->ohfi); @@ -421,7 +421,7 @@ void Database::dumpMetadataList(const metadata_t *p_head) } } -int Database::filterObjects(int ohfiParent, metadata_t **p_head, int index, int max_number) +int QListDB::filterObjects(int ohfiParent, metadata_t **p_head, int index, int max_number) { QMutexLocker locker(&mutex); CMARootObject *parent = static_cast(ohfiToObject(ohfiParent)); diff --git a/src/database.h b/src/qlistdb.h similarity index 95% rename from src/database.h rename to src/qlistdb.h index a2effc2..edbb560 100644 --- a/src/database.h +++ b/src/qlistdb.h @@ -17,8 +17,8 @@ * along with this program. If not, see . */ -#ifndef DATABASE_H -#define DATABASE_H +#ifndef QLISTDB_H +#define QLISTDB_H #include "cmarootobject.h" @@ -30,7 +30,7 @@ #include -class Database : public QObject +class QListDB : public QObject { Q_OBJECT public: @@ -39,8 +39,8 @@ public: QList::const_iterator end; } find_data; - explicit Database(); - ~Database(); + explicit QListDB(); + ~QListDB(); bool reload(bool &prepared); void setUUID(const QString uuid); @@ -97,4 +97,4 @@ public slots: void cancelOperation(); }; -#endif // DATABASE_H +#endif // QLISTDB_H diff --git a/src/sqlitedb.cpp b/src/sqlitedb.cpp index d6f1742..6ba19af 100644 --- a/src/sqlitedb.cpp +++ b/src/sqlitedb.cpp @@ -156,12 +156,14 @@ bool SQLiteDB::initialize() for(unsigned int i = 0; i < sizeof(table_list) / sizeof(const char *); i++) { if(!query.exec(table_list[i])) { + qDebug() << query.lastError(); return false; } } for(unsigned int i = 0; i < sizeof(trigger_list) / sizeof(const char *); i++) { if(!query.exec(trigger_list[i])) { + qDebug() << query.lastError(); return false; } } @@ -275,35 +277,28 @@ int SQLiteDB::recursiveScanRootDirectory(const QString &base_path, int parent, i int SQLiteDB::getPathId(const QString &path) { - if (!db.isOpen()) { - return -1; - } QSqlQuery query(QString("SELECT object_id from sources WHERE path = %1").arg(path)); if(query.next()) { return query.value(0).toInt(); } else { + qDebug() << query.lastError(); return -1; } } QString SQLiteDB::getPathFromId(int ohfi) { - if (!db.isOpen()) { - return QString(); - } QSqlQuery query(QString("SELECT path FROM sources WHERE object_id = %1").arg(ohfi)); if(query.next()) { return query.value(0).toString(); } else { + qDebug() << query.lastError(); return QString(); } } bool SQLiteDB::updateSize(int ohfi, quint64 size) { - if (!db.isOpen()) { - return false; - } QSqlQuery query(QString("UPDATE sources SET size = %1 WHERE object_id == %2").arg(size).arg(ohfi)); return query.exec(); } @@ -311,7 +306,11 @@ bool SQLiteDB::updateSize(int ohfi, quint64 size) bool SQLiteDB::deleteEntry(int ohfi) { QSqlQuery query(QString("DELETE FROM object_node WHERE object_id == %1").arg(ohfi)); - return query.exec(); + bool ret = query.exec(); + if(!ret) { + qDebug() << query.lastError(); + } + return ret; } bool SQLiteDB::deleteEntry(const QString &path) @@ -329,13 +328,19 @@ bool SQLiteDB::updateAdjacencyList(int ohfi, int parent) if(query.exec() && query.next()) { return true; + } else { + qDebug() << query.lastError(); } query.prepare("INSERT INTO adjacent_objects (parent_id, child_id)" "VALUES (:parentid, :child_id)"); query.bindValue(0, parent); query.bindValue(1, ohfi); - return query.exec(); + bool ret = query.exec(); + if(!ret) { + qDebug() << query.lastError(); + } + return ret; } uint SQLiteDB::insertDirectoryEntry(const QString &path, int type, int parent) @@ -376,6 +381,7 @@ uint SQLiteDB::insertObjectEntry(const char *title, int type) query.bindValue(1, title); if(!query.exec() || !query.exec("SELECT last_insert_rowid()") || !query.next()) { + qDebug() << query.lastError(); return 0; } //} @@ -401,7 +407,11 @@ bool SQLiteDB::insertSourceEntry(uint object_id, const QString &path) query.bindValue(2, size); query.bindValue(3, date_created); query.bindValue(4, date_modified); - return query.exec(); + bool ret = query.exec(); + if(!ret) { + qDebug() << query.lastError(); + } + return ret; } uint SQLiteDB::insertMusicEntry(const QString &path, int type, int parent) From b7ad2b13f4d3b98ef18d4151d743f5dfc4e887ee Mon Sep 17 00:00:00 2001 From: codestation Date: Tue, 28 Jan 2014 14:00:15 -0430 Subject: [PATCH 4/9] Create a unified base class to access the database. Moved the default database class to QListDB and disallow leaking CMAObjects outside this class. Rewrote QListDB and CMAEvent to use the new internal API. Moved the file format constants to the base database class. Moved the metadata loading methods to the base database class. --- qcma.pro | 6 +- src/avdecoder.cpp | 2 +- src/cmaclient.h | 1 - src/cmaevent.cpp | 269 +++++++++++++++----------------- src/cmaevent.h | 4 +- src/cmaobject.cpp | 49 +----- src/database.cpp | 101 ++++++++++++ src/database.h | 63 ++++++++ src/forms/backupmanagerform.cpp | 28 ++-- src/qlistdb.cpp | 223 ++++++++++++++++++-------- src/qlistdb.h | 52 +++--- src/sqlitedb.cpp | 9 +- src/sqlitedb.h | 6 +- src/utils.cpp | 50 ------ src/utils.h | 31 ---- 15 files changed, 514 insertions(+), 380 deletions(-) create mode 100644 src/database.cpp create mode 100644 src/database.h diff --git a/qcma.pro b/qcma.pro index 85c3f2a..84cf31c 100644 --- a/qcma.pro +++ b/qcma.pro @@ -40,7 +40,8 @@ SOURCES += src/main.cpp \ src/forms/configwidget.cpp \ src/forms/confirmdialog.cpp \ src/forms/pinform.cpp \ - src/forms/progressform.cpp + src/forms/progressform.cpp \ + src/database.cpp HEADERS += \ src/capability.h \ @@ -66,7 +67,8 @@ HEADERS += \ src/forms/configwidget.h \ src/forms/confirmdialog.h \ src/forms/pinform.h \ - src/forms/progressform.h + src/forms/progressform.h \ + src/database.h FORMS += \ src/forms/configwidget.ui \ diff --git a/src/avdecoder.cpp b/src/avdecoder.cpp index 2f70bff..bcaf1d0 100644 --- a/src/avdecoder.cpp +++ b/src/avdecoder.cpp @@ -19,7 +19,7 @@ #include "utils.h" #include "avdecoder.h" -#include "cmaobject.h" +#include "database.h" #include #include diff --git a/src/cmaclient.h b/src/cmaclient.h index 93bc550..02d8131 100644 --- a/src/cmaclient.h +++ b/src/cmaclient.h @@ -22,7 +22,6 @@ #include "qlistdb.h" #include "cmaevent.h" -#include "cmaobject.h" #include "cmabroadcast.h" #include diff --git a/src/cmaevent.cpp b/src/cmaevent.cpp index 1a7c8ba..8e0dc0e 100644 --- a/src/cmaevent.cpp +++ b/src/cmaevent.cpp @@ -25,14 +25,13 @@ #include #include #include +#include #include -#include - QListDB *CmaEvent::db = NULL; QFile *CmaEvent::m_file = NULL; -metadata_t CmaEvent::g_thumbmeta = {0, 0, 0, NULL, NULL, 0, 0, 0, Thumbnail, {{17, 240, 136, 0, 1, 1.0f, 2}}, NULL}; +static metadata_t g_thumbmeta = {0, 0, 0, NULL, NULL, 0, 0, 0, Thumbnail, {{17, 240, 136, 0, 1, 1.0f, 2}}, NULL}; CmaEvent::CmaEvent(vita_device_t *s_device) : device(s_device), is_active(true) @@ -149,15 +148,13 @@ void CmaEvent::processEvent() qDebug("Ended event, code: 0x%x, id: %d", t_event.Code, t_event.Param1); } -quint16 CmaEvent::processAllObjects(CMAObject *parent, quint32 handle) +quint16 CmaEvent::processAllObjects(metadata_t &parent_metadata, quint32 handle) { - qDebug("Called %s, handle: %d, parent name: %s", Q_FUNC_INFO, handle, parent->metadata.name); + qDebug("Called %s, handle: %d, parent name: %s", Q_FUNC_INFO, handle, parent_metadata.name); char *name; - int fileType = -1; int dataType; - - uint32_t *p_handles; + quint32 *p_handles; unsigned int p_len; if(VitaMTP_GetObject_Info(device, handle, &name, &dataType) != PTP_RC_OK) { @@ -174,15 +171,16 @@ quint16 CmaEvent::processAllObjects(CMAObject *parent, quint32 handle) } - CMAObject *object = db->pathToObject(name, parent->metadata.ohfi); + int ohfi = db->getPathId(name, parent_metadata.ohfi); + const QString fullpath = db->getAbsolutePath(ohfi); - if(object) { - qDebug("Deleting %s", object->path.toStdString().c_str()); - removeRecursively(object->path); - db->remove(object); + if(ohfi > 0) { + qDebug() << "Deleting" << fullpath; + removeRecursively(fullpath); + db->deleteEntry(ohfi); } - QDir dir(parent->path); + QDir dir(db->getAbsolutePath(parent_metadata.ohfi)); if(dataType & Folder) { if(!dir.mkpath(name)) { @@ -205,33 +203,26 @@ quint16 CmaEvent::processAllObjects(CMAObject *parent, quint32 handle) VitaMTP_GetObject_Callback(device, handle, &size, CmaEvent::writeCallback); m_file->close(); delete m_file; - - // get the root ohfi type - CMAObject *root_obj = parent; - while(root_obj->parent) { - root_obj = root_obj->parent; - } - - fileType = checkFileType(dir.absoluteFilePath(name), root_obj->metadata.ohfi); } } QFileInfo info(dir, name); - object = new CMAObject(parent); - object->initObject(info, fileType); - object->metadata.handle = handle; - db->append(parent->metadata.ohfi, object); + int new_ohfi = db->insertObjectEntry(info.absoluteFilePath(), parent_metadata.ohfi); free(name); - qDebug("Added object %s with OHFI %i to database", object->metadata.path, object->metadata.ohfi); + qDebug() << QString("Added object %1 with OHFI %2 to database").arg(info.absoluteFilePath(), QString::number(new_ohfi)); if(dataType & Folder) { + metadata_t folder_metadata; + db->getObjectMetadata(new_ohfi, folder_metadata); + folder_metadata.handle = handle; + for(unsigned int i = 0; i < p_len; i++) { - quint16 ret = processAllObjects(object, p_handles[i]); + quint16 ret = processAllObjects(folder_metadata, p_handles[i]); if(ret != PTP_RC_OK) { - qDebug("Deleteting object with OHFI %d", object->metadata.ohfi); - db->remove(object); + qDebug("Deleteting object with OHFI %d", new_ohfi); + db->deleteEntry(new_ohfi); return ret; } } @@ -253,15 +244,15 @@ void CmaEvent::vitaEventGetTreatObject(vita_event_t *event, int eventId) QMutexLocker locker(&db->mutex); - CMAObject *parent = db->ohfiToObject(treatObject.ohfiParent); + metadata_t metadata; - if(parent == NULL) { + if(!db->getObjectMetadata(treatObject.ohfiParent, metadata)) { qWarning("Cannot find parent OHFI %d", treatObject.ohfiParent); VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_OHFI); return; } - VitaMTP_ReportResult(device, eventId, processAllObjects(parent, treatObject.handle)); + VitaMTP_ReportResult(device, eventId, processAllObjects(metadata, treatObject.handle)); } void CmaEvent::vitaEventSendCopyConfirmationInfo(vita_event_t *event, int eventId) @@ -276,21 +267,20 @@ void CmaEvent::vitaEventSendCopyConfirmationInfo(vita_event_t *event, int eventI QMutexLocker locker(&db->mutex); - quint64 size = 0; + qint64 size; + qint64 total_size = 0; for(quint32 i = 0; i < info->count; i++) { - CMAObject *object; - - if((object = db->ohfiToObject(info->ohfi[i])) == NULL) { + if((size = db->getObjectSize(info->ohfi[i])) < 0) { qWarning("Cannot find OHFI %d", info->ohfi[i]); free(info); return; } - size += object->metadata.size; + total_size += size; } - if(VitaMTP_SendCopyConfirmationInfo(device, eventId, info, size) != PTP_RC_OK) { + if(VitaMTP_SendCopyConfirmationInfo(device, eventId, info, total_size) != PTP_RC_OK) { qWarning("Error sending copy confirmation"); } else { VitaMTP_ReportResult(device, eventId, PTP_RC_OK); @@ -311,19 +301,18 @@ void CmaEvent::vitaEventSendObjectMetadataItems(vita_event_t *event, int eventId QMutexLocker locker(&db->mutex); - CMAObject *object = db->ohfiToObject(ohfi); + metadata_t metadata; - if(object == NULL) { + if(!db->getObjectMetadata(ohfi, metadata)) { qWarning("Cannot find OHFI %d in database", ohfi); VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_OHFI); return; } - metadata_t *metadata = &object->metadata; - metadata->next_metadata = NULL; - qDebug("Sending metadata for OHFI %d (%s)", ohfi, metadata->path); + metadata.next_metadata = NULL; + qDebug("Sending metadata for OHFI %d (%s)", ohfi, metadata.path); - quint16 ret = VitaMTP_SendObjectMetadata(device, eventId, metadata); + quint16 ret = VitaMTP_SendObjectMetadata(device, eventId, &metadata); if(ret != PTP_RC_OK) { qWarning("Error sending metadata. Code: %04X", ret); } else { @@ -368,8 +357,8 @@ void CmaEvent::vitaEventSendNumOfObject(vita_event_t *event, int eventId) QMutexLocker locker(&db->mutex); - uint ohfi = event->Param2; - int items = db->filterObjects(ohfi, NULL); + int ohfi = event->Param2; + int items = db->childObjectCount(ohfi); if(VitaMTP_SendNumOfObject(device, eventId, items) != PTP_RC_OK) { qWarning("Error occured receiving object count for OHFI parent %d", ohfi); @@ -391,8 +380,9 @@ void CmaEvent::vitaEventSendObjectMetadata(vita_event_t *event, int eventId) } QMutexLocker locker(&db->mutex); - metadata_t *meta; - int count = db->filterObjects(browse.ohfiParent, &meta, browse.index, browse.numObjects); // if meta is null, will return empty XML + metadata_t *meta = NULL; + + int count = db->getObjectMetadatas(browse.ohfiParent, meta, browse.index, browse.numObjects); // if meta is null, will return empty XML qDebug("Sending %i metadata filtered objects for OHFI %d", count, browse.ohfiParent); if(VitaMTP_SendObjectMetadata(device, eventId, meta) != PTP_RC_OK) { // send all objects with OHFI parent @@ -412,29 +402,27 @@ void CmaEvent::vitaEventSendObject(vita_event_t *event, int eventId) qDebug("Searching object with OHFI %d", ohfi); - QListDB::find_data iters; - if(!db->find(ohfi, iters)) { + metadata_t *metadata = NULL; + if(!db->getObjectMetadatas(ohfi, metadata)) { qWarning("Failed to find OHFI %d", ohfi); VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_OHFI); return; } - unsigned long len = 0; - CMAObject *object = *iters.it; - CMAObject *start = object; - uint parentHandle = event->Param3; - bool send_folder = object->metadata.dataType & Folder; - uint handle; + metadata_t *start = metadata; + quint32 parentHandle = event->Param3; + bool send_folder = metadata->dataType & Folder; + quint32 handle; do { - len = object->metadata.size; - m_file = new QFile(object->path); + unsigned long len = metadata->size; + m_file = new QFile(db->getAbsolutePath(metadata->ohfi)); // read the file to send if it's not a directory // if it is a directory, data and len are not used by VitaMTP - if(object->metadata.dataType & File) { + if(metadata->dataType & File) { if(!m_file->open(QIODevice::ReadOnly)) { - qWarning("Failed to read %s", object->path.toStdString().c_str()); + qWarning() << "Failed to read" << m_file->fileName(); delete m_file; VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Not_Exist_Object); return; @@ -445,18 +433,20 @@ void CmaEvent::vitaEventSendObject(vita_event_t *event, int eventId) // we know the parent has to be before the current node // the first time this is called, parentHandle is left untouched - if(start != object) { - parentHandle = object->parent->metadata.handle; + if(start != metadata) { + metadata_t parent_metadata; + db->getObjectMetadata(metadata->ohfiParent, parent_metadata); + parentHandle = parent_metadata.handle; } // send the data over - qDebug("Sending %s of %lu bytes to device", object->metadata.name, len); + qDebug("Sending %s of %lu bytes to device", metadata->name, len); qDebug("OHFI %d with handle 0x%08X", ohfi, parentHandle); VitaMTP_RegisterCancelEventId(eventId); - quint16 ret = VitaMTP_SendObject_Callback(device, &parentHandle, &handle, &object->metadata, &CmaEvent::readCallback); + quint16 ret = VitaMTP_SendObject_Callback(device, &parentHandle, &handle, metadata, &CmaEvent::readCallback); if(ret != PTP_RC_OK) { - qWarning("Sending of %s failed. Code: %04X", object->metadata.name, ret); + qWarning("Sending of %s failed. Code: %04X", metadata->name, ret); if(ret == PTP_ERROR_CANCEL) { VitaMTP_ReportResult(device, eventId, PTP_RC_GeneralError); } @@ -465,9 +455,9 @@ void CmaEvent::vitaEventSendObject(vita_event_t *event, int eventId) return; } - object->metadata.handle = handle; + metadata->handle = handle; - if(object->metadata.dataType & File) { + if(metadata->dataType & File) { m_file->close(); delete m_file; } @@ -477,9 +467,9 @@ void CmaEvent::vitaEventSendObject(vita_event_t *event, int eventId) break; } - object = *++iters.it; + metadata = metadata->next_metadata; - } while(iters.it != iters.end && object->metadata.ohfiParent >= OHFI_OFFSET); // get everything under this "folder" + } while(metadata && metadata->ohfiParent >= OHFI_OFFSET); // get everything under this "folder" VitaMTP_ReportResultWithParam(device, eventId, PTP_RC_OK, handle); @@ -573,18 +563,19 @@ void CmaEvent::vitaEventSendObjectStatus(vita_event_t *event, int eventId) QMutexLocker locker(&db->mutex); - CMAObject *object = db->pathToObject(objectstatus.title, objectstatus.ohfiRoot); + int ohfi = db->getPathId(objectstatus.title, objectstatus.ohfiRoot); - if(object == NULL) { // not in database, don't return metadata + if(ohfi == 0) { // not in database, don't return metadata qDebug("Object %s not in database (OHFI: %i). Sending OK response for non-existence", objectstatus.title, objectstatus.ohfiRoot); VitaMTP_ReportResult(device, eventId, PTP_RC_OK); } else { - metadata_t *metadata = &object->metadata; - metadata->next_metadata = NULL; - qDebug("Sending metadata for OHFI %d", object->metadata.ohfi); + metadata_t metadata; + db->getObjectMetadata(ohfi, metadata); + metadata.next_metadata = NULL; + qDebug("Sending metadata for OHFI %d", ohfi); - if(VitaMTP_SendObjectMetadata(device, eventId, metadata) != PTP_RC_OK) { - qWarning("Error sending metadata for %d", object->metadata.ohfi); + if(VitaMTP_SendObjectMetadata(device, eventId, &metadata) != PTP_RC_OK) { + qWarning("Error sending metadata for %d", ohfi); } else { VitaMTP_ReportResult(device, eventId, PTP_RC_OK); } @@ -600,22 +591,25 @@ void CmaEvent::vitaEventSendObjectThumb(vita_event_t *event, int eventId) QMutexLocker locker(&db->mutex); int ohfi = event->Param2; - CMAObject *object = db->ohfiToObject(ohfi); + metadata_t metadata; - if(object == NULL) { + if(!db->getObjectMetadata(ohfi, metadata)) { qWarning("Cannot find OHFI %d in database.", ohfi); VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_OHFI); return; } - QByteArray data = getThumbnail(object->path, object->metadata.dataType, &g_thumbmeta); + QString fullpath = db->getAbsolutePath(ohfi); + QByteArray data = getThumbnail(fullpath, metadata.dataType, &g_thumbmeta); if(data.size() == 0) { - qWarning("Cannot find/read thumbnail for %s", object->path.toStdString().c_str()); + qWarning() << "Cannot find/read thumbnail for" << fullpath; VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_Data); return; } + //FIXME: remove this after fixing vitamtp + // workaround for the vitamtp locale bug char *locale = strdup(setlocale(LC_ALL, NULL)); setlocale(LC_ALL, "C"); @@ -638,17 +632,18 @@ void CmaEvent::vitaEventDeleteObject(vita_event_t *event, int eventId) QMutexLocker locker(&db->mutex); int ohfi = event->Param2; - CMAObject *object = db->ohfiToObject(ohfi); + metadata_t metadata; - if(object == NULL) { + if(!db->getObjectMetadata(ohfi, metadata)) { qWarning("OHFI %d not found", ohfi); VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_OHFI); return; } - qDebug("Deleting %s, OHFI: %i", object->metadata.path, object->metadata.ohfi); - removeRecursively(object->path); - db->remove(object); + QString fullpath = db->getAbsolutePath(ohfi); + qDebug() << QString("Deleting %1, OHFI: %2").arg(fullpath, QString::number(ohfi)); + removeRecursively(fullpath); + db->deleteEntry(ohfi); VitaMTP_ReportResult(device, eventId, PTP_RC_OK); } @@ -727,24 +722,26 @@ void CmaEvent::vitaEventSendPartOfObject(vita_event_t *event, int eventId) QMutexLocker locker(&db->mutex); - CMAObject *object = db->ohfiToObject(part_init.ohfi); + QString fullpath = db->getAbsolutePath(part_init.ohfi); - if(object == NULL) { + if(fullpath.isNull()) { qWarning("Cannot find object for OHFI %d", part_init.ohfi); VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_Context); return; } - QFile file(object->path); + QFile file(fullpath); if(!file.open(QIODevice::ReadOnly)) { - qWarning("Cannot read %s", object->path.toStdString().c_str()); + qWarning() << "Cannot read" << fullpath; VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Not_Exist_Object); return; } else { file.seek(part_init.offset); QByteArray data = file.read(part_init.size); - qDebug("Sending %s at file offset %" PRIu64" for %" PRIu64" bytes", object->metadata.path, part_init.offset, part_init.size); + qDebug() << QString("Sending %1 at file offset %2 for %3 bytes").arg( + fullpath, QString::number(part_init.offset), QString::number(part_init.size) + ); if(VitaMTP_SendPartOfObject(device, eventId, (unsigned char *)data.data(), data.size()) != PTP_RC_OK) { qWarning("Failed to send part of object OHFI %d", part_init.ohfi); @@ -767,10 +764,10 @@ void CmaEvent::vitaEventOperateObject(vita_event_t *event, int eventId) QMutexLocker locker(&db->mutex); - CMAObject *root = db->ohfiToObject(operateobject.ohfi); + QString fullpath = db->getAbsolutePath(operateobject.ohfi); // end for renaming only - if(root == NULL) { + if(fullpath.isNull()) { VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Not_Exist_Object); return; } @@ -779,64 +776,46 @@ void CmaEvent::vitaEventOperateObject(vita_event_t *event, int eventId) case VITA_OPERATE_CREATE_FOLDER: { qDebug("Operate command %d: Create folder %s", operateobject.cmd, operateobject.title); - QDir dir(root->path); + QDir dir(fullpath); if(!dir.mkdir(operateobject.title)) { qWarning("Unable to create temporary folder: %s", operateobject.title); VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Failed_Operate_Object); } else { - CMAObject *newobj = new CMAObject(root); - newobj->initObject(QFileInfo(dir, operateobject.title)); - db->append(operateobject.ohfi, newobj); - qDebug("Created folder %s with OHFI %d under parent %s", newobj->metadata.path, newobj->metadata.ohfi, root->metadata.path); - VitaMTP_ReportResultWithParam(device, eventId, PTP_RC_OK, newobj->metadata.ohfi); + int new_ohfi = db->insertObjectEntry(QDir(dir).absoluteFilePath(operateobject.title), operateobject.ohfi); + qDebug("Created folder %s with OHFI %d", operateobject.title, new_ohfi); + VitaMTP_ReportResultWithParam(device, eventId, PTP_RC_OK, new_ohfi); } break; } case VITA_OPERATE_CREATE_FILE: { qDebug("Operate command %d: Create file %s", operateobject.cmd, operateobject.title); - QFile file(root->path + QDir::separator() + operateobject.title); + QFile file(fullpath + QDir::separator() + operateobject.title); if(!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { qWarning("Unable to create temporary file: %s", operateobject.title); VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Failed_Operate_Object); } else { - CMAObject *newobj = new CMAObject(root); - newobj->initObject(file); - db->append(root->metadata.ohfi, newobj); - qDebug("Created file %s with OHFI %d under parent %s", newobj->metadata.path, newobj->metadata.ohfi, root->metadata.path); - VitaMTP_ReportResultWithParam(device, eventId, PTP_RC_OK, newobj->metadata.ohfi); + int new_ohfi = db->insertObjectEntry(file.fileName(), operateobject.ohfi); + //qDebug("Created file %s with OHFI %d under parent %s", newobj->metadata.path, new_ohfi, root->metadata.path); + VitaMTP_ReportResultWithParam(device, eventId, PTP_RC_OK, new_ohfi); } break; } case VITA_OPERATE_RENAME: { - qDebug("Operate command %d: Rename %s to %s", operateobject.cmd, root->metadata.name, operateobject.title); + //qDebug("Operate command %d: Rename %s to %s", operateobject.cmd, root->metadata.name, operateobject.title); - QString oldpath = root->path; - QString oldname = root->metadata.name; - - //rename the current object - root->rename(operateobject.title); - QListDB::find_data iters; - db->find(root->metadata.ohfi, iters); - - // rename the rest of the list only if has the renamed parent in some part of the chain - while(iters.it != iters.end) { - CMAObject *obj = *iters.it++; - - if(obj->hasParent(root)) { - obj->refreshPath(); - } - } + db->renameObject(operateobject.ohfi, operateobject.title); + QString newpath = db->getAbsolutePath(operateobject.ohfi); // rename in filesystem - if(!QFile(oldpath).rename(root->path)) { - qWarning("Unable to rename %s to %s", oldname.toStdString().c_str(), operateobject.title); + if(!QFile(fullpath).rename(newpath)) { + qWarning("Unable to rename %s to %s", fullpath.toLocal8Bit().constData(), operateobject.title); VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Failed_Operate_Object); break; } - qDebug("Renamed OHFI %d from %s to %s", root->metadata.ohfi, oldname.toStdString().c_str(), root->metadata.name); - VitaMTP_ReportResultWithParam(device, eventId, PTP_RC_OK, root->metadata.ohfi); + qDebug("Renamed OHFI %d from %s to %s", operateobject.ohfi, fullpath.toLocal8Bit().constData(), newpath.toLocal8Bit().constData()); + VitaMTP_ReportResultWithParam(device, eventId, PTP_RC_OK, operateobject.ohfi); break; } @@ -862,26 +841,32 @@ void CmaEvent::vitaEventGetPartOfObject(vita_event_t *event, int eventId) } QMutexLocker locker(&db->mutex); - CMAObject *object = db->ohfiToObject(part_init.ohfi); + QString fullpath = db->getAbsolutePath(part_init.ohfi); - if(object == NULL) { + if(fullpath.isNull()) { qWarning("Cannot find OHFI %d", part_init.ohfi); VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_OHFI); free(data); return; } - qDebug("Receiving %s at offset %" PRIu64" for %" PRIu64" bytes", object->metadata.path, part_init.offset, part_init.size); + qDebug() << QString("Receiving %1 at offset %2 for %3 bytes").arg( + fullpath, QString::number(part_init.offset), QString::number(part_init.size) + ); - QFile file(object->path); + QFile file(fullpath); if(!file.open(QIODevice::ReadWrite)) { - qWarning("Cannot write to file %s", object->path.toStdString().c_str()); + qWarning() << "Cannot write to file" << fullpath; VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_Permission); } else { file.seek(part_init.offset); file.write((const char *)data, part_init.size); - object->updateObjectSize(part_init.size); - qDebug("Written %" PRIu64" bytes to %s at offset %" PRIu64, part_init.size, object->path.toStdString().c_str(), part_init.offset); + db->setObjectSize(part_init.ohfi, part_init.size); + + qDebug() << QString("Written %1 bytes to %2 at offset %3").arg( + QString::number(part_init.size), fullpath, QString::number(part_init.offset) + ); + VitaMTP_ReportResult(device, eventId, PTP_RC_OK); } @@ -895,20 +880,20 @@ void CmaEvent::vitaEventSendStorageSize(vita_event_t *event, int eventId) QMutexLocker locker(&db->mutex); int ohfi = event->Param2; - CMAObject *object = db->ohfiToObject(ohfi); + QString fullpath = db->getAbsolutePath(ohfi); - if(object == NULL) { + if(fullpath.isNull()) { qWarning("Error: Cannot find OHFI %d", ohfi); VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_OHFI); return; } else { - QFile file(object->path); + QFile file(fullpath); if(!file.exists()) { // create the directory if doesn't exist so the query don't fail - qDebug("Creating %s", object->path.toStdString().c_str()); + qDebug() << "Creating" << fullpath; - if(!QDir(QDir::root()).mkpath(object->path)) { + if(!QDir(QDir::root()).mkpath(QDir(fullpath).absolutePath())) { qWarning("Create directory failed"); VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_Permission); return; @@ -919,7 +904,7 @@ void CmaEvent::vitaEventSendStorageSize(vita_event_t *event, int eventId) quint64 total; quint64 free; - if(!getDiskSpace(object->path, &free, &total)) { + if(!getDiskSpace(fullpath, &free, &total)) { qWarning("Cannot get disk space"); VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_Permission); return; @@ -948,12 +933,12 @@ void CmaEvent::vitaEventCheckExistance(vita_event_t *event, int eventId) QMutexLocker locker(&db->mutex); - CMAObject *object = db->pathToObject(existance.name, 0); + int ohfi = db->getPathId(existance.name, 0); - if(object == NULL) { + if(ohfi == 0) { VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Different_Object); } else { - VitaMTP_ReportResultWithParam(device, eventId, PTP_RC_VITA_Same_Object, object->metadata.ohfi); + VitaMTP_ReportResultWithParam(device, eventId, PTP_RC_VITA_Same_Object, ohfi); } VitaMTP_ReportResult(device, eventId, PTP_RC_OK); diff --git a/src/cmaevent.h b/src/cmaevent.h index 3ff4e92..3eb2b8f 100644 --- a/src/cmaevent.h +++ b/src/cmaevent.h @@ -20,7 +20,6 @@ #ifndef CMAEVENT_H #define CMAEVENT_H -#include "cmaobject.h" #include "qlistdb.h" #include "httpdownloader.h" @@ -42,7 +41,7 @@ public: static QListDB *db; private: - uint16_t processAllObjects(CMAObject *parent, uint32_t handle); + uint16_t processAllObjects(metadata_t &metadata, uint32_t handle); void vitaEventSendObject(vita_event_t *event, int eventId); void vitaEventSendObjectMetadata(vita_event_t *event, int eventId); void vitaEventSendNumOfObject(vita_event_t *event, int eventId); @@ -79,7 +78,6 @@ private: QMutex active; QSemaphore sema; - static metadata_t g_thumbmeta; static QFile *m_file; signals: diff --git a/src/cmaobject.cpp b/src/cmaobject.cpp index c6fc284..a7783bc 100644 --- a/src/cmaobject.cpp +++ b/src/cmaobject.cpp @@ -20,6 +20,7 @@ #include "cmaobject.h" #include "sforeader.h" #include "avdecoder.h" +#include "database.h" #include "utils.h" #include @@ -108,48 +109,6 @@ void CMAObject::loadSfoMetadata(const QString &path) } } -void CMAObject::loadMusicMetadata(const QString &path) -{ - AVDecoder decoder; - bool skipMetadata = QSettings().value("skipMetadata", false).toBool(); - - if(!skipMetadata && decoder.open(path)) { - decoder.getAudioMetadata(metadata); - } else { - metadata.data.music.album = strdup(parent->metadata.name ? parent->metadata.name : ""); - metadata.data.music.artist = strdup(""); - metadata.data.music.title = strdup(metadata.name); - } -} - -void CMAObject::loadVideoMetadata(const QString &path) -{ - AVDecoder decoder; - bool skipMetadata = QSettings().value("skipMetadata", false).toBool(); - - if(!skipMetadata && decoder.open(path)) { - decoder.getVideoMetadata(metadata); - } else { - metadata.data.video.title = strdup(metadata.name); - metadata.data.video.explanation = strdup(""); - metadata.data.video.copyright = strdup(""); - // default to H264 video codec - metadata.data.video.tracks->data.track_video.codecType = CODEC_TYPE_AVC; - } -} - -void CMAObject::loadPhotoMetadata(const QString &path) -{ - QImage img; - bool skipMetadata = QSettings().value("skipMetadata", false).toBool(); - - if(!skipMetadata && img.load(path)) { - metadata.data.photo.tracks->data.track_photo.width = img.width(); - metadata.data.photo.tracks->data.track_photo.height = img.height(); - } - metadata.data.photo.title = strdup(metadata.name); -} - void CMAObject::initObject(const QFileInfo &file, int file_type) { metadata.name = strdup(file.fileName().toUtf8().data()); @@ -181,7 +140,7 @@ void CMAObject::initObject(const QFileInfo &file, int file_type) metadata.data.music.tracks = new media_track(); metadata.data.music.tracks->type = VITA_TRACK_TYPE_AUDIO; metadata.data.music.tracks->data.track_photo.codecType = audio_list[file_type].file_codec; - loadMusicMetadata(file.absoluteFilePath()); + Database::loadMusicMetadata(file.absoluteFilePath(), metadata); } else if(MASK_SET(metadata.dataType, Video | File)) { metadata.data.video.fileName = strdup(metadata.name); metadata.data.video.dateTimeUpdated = file.created().toTime_t(); @@ -191,7 +150,7 @@ void CMAObject::initObject(const QFileInfo &file, int file_type) metadata.data.video.numTracks = 1; metadata.data.video.tracks = new media_track(); metadata.data.video.tracks->type = VITA_TRACK_TYPE_VIDEO; - loadVideoMetadata(file.absoluteFilePath()); + Database::loadVideoMetadata(file.absoluteFilePath(), metadata); } else if(MASK_SET(metadata.dataType, Photo | File)) { if(file_type < 0) { @@ -207,7 +166,7 @@ void CMAObject::initObject(const QFileInfo &file, int file_type) metadata.data.photo.tracks = new media_track(); metadata.data.photo.tracks->type = VITA_TRACK_TYPE_PHOTO; metadata.data.photo.tracks->data.track_photo.codecType = photo_list[file_type].file_codec; - loadPhotoMetadata(file.absoluteFilePath()); + Database::loadPhotoMetadata(file.absoluteFilePath(), metadata); } path = file.absoluteFilePath(); diff --git a/src/database.cpp b/src/database.cpp new file mode 100644 index 0000000..7c80720 --- /dev/null +++ b/src/database.cpp @@ -0,0 +1,101 @@ +#include "database.h" +#include "avdecoder.h" + +#include + +const file_type audio_list[] = { + {"mp3", FILE_FORMAT_MP3, CODEC_TYPE_MP3}, + {"mp4", FILE_FORMAT_MP4, CODEC_TYPE_AAC}, + {"wav", FILE_FORMAT_WAV, CODEC_TYPE_PCM} +}; + +const file_type photo_list[] = { + {"jpg", FILE_FORMAT_JPG, CODEC_TYPE_JPG}, + {"jpeg", FILE_FORMAT_JPG, CODEC_TYPE_JPG}, + {"png", FILE_FORMAT_PNG, CODEC_TYPE_PNG}, + {"tif", FILE_FORMAT_TIF, CODEC_TYPE_TIF}, + {"tiff", FILE_FORMAT_TIF, CODEC_TYPE_TIF}, + {"bmp", FILE_FORMAT_BMP, CODEC_TYPE_BMP}, + {"gif", FILE_FORMAT_GIF, CODEC_TYPE_GIF}, +}; + +const file_type video_list[] = { + {"mp4", FILE_FORMAT_MP4, 0} +}; + +Database::Database(QObject *parent) : + QObject(parent) +{ +} + +int Database::checkFileType(const QString path, int ohfi_root) +{ + switch(ohfi_root) { + case VITA_OHFI_MUSIC: + for(int i = 0, max = sizeof(audio_list) / sizeof(file_type); i < max; i++) { + if(path.endsWith(audio_list[i].file_ext, Qt::CaseInsensitive)) { + return i; + } + } + break; + case VITA_OHFI_PHOTO: + for(int i = 0, max = sizeof(photo_list) / sizeof(file_type); i< max; i++) { + if(path.endsWith(photo_list[i].file_ext, Qt::CaseInsensitive)) { + return i; + } + } + break; + case VITA_OHFI_VIDEO: + for(int i = 0, max = sizeof(video_list) / sizeof(file_type); i< max; i++) { + if(path.endsWith(video_list[i].file_ext, Qt::CaseInsensitive)) { + return i; + } + } + break; + default: + return 0; + } + return -1; +} + +void Database::loadMusicMetadata(const QString &path, metadata_t &metadata) +{ + AVDecoder decoder; + bool skipMetadata = QSettings().value("skipMetadata", false).toBool(); + + if(!skipMetadata && decoder.open(path)) { + decoder.getAudioMetadata(metadata); + } else { + metadata.data.music.album = strdup(""); + metadata.data.music.artist = strdup(""); + metadata.data.music.title = strdup(metadata.name); + } +} + +void Database::loadVideoMetadata(const QString &path, metadata_t &metadata) +{ + AVDecoder decoder; + bool skipMetadata = QSettings().value("skipMetadata", false).toBool(); + + if(!skipMetadata && decoder.open(path)) { + decoder.getVideoMetadata(metadata); + } else { + metadata.data.video.title = strdup(metadata.name); + metadata.data.video.explanation = strdup(""); + metadata.data.video.copyright = strdup(""); + // default to H264 video codec + metadata.data.video.tracks->data.track_video.codecType = CODEC_TYPE_AVC; + } +} + +void Database::loadPhotoMetadata(const QString &path, metadata_t &metadata) +{ + QImage img; + bool skipMetadata = QSettings().value("skipMetadata", false).toBool(); + + if(!skipMetadata && img.load(path)) { + metadata.data.photo.tracks->data.track_photo.width = img.width(); + metadata.data.photo.tracks->data.track_photo.height = img.height(); + } + metadata.data.photo.title = strdup(metadata.name); +} diff --git a/src/database.h b/src/database.h new file mode 100644 index 0000000..29daf8c --- /dev/null +++ b/src/database.h @@ -0,0 +1,63 @@ +#ifndef DATABASE_H +#define DATABASE_H + +#include +#include + +typedef struct { + const char *file_ext; + int file_format; + int file_codec; +} file_type; + +#define FILE_FORMAT_MP4 1 +#define FILE_FORMAT_WAV 2 +#define FILE_FORMAT_MP3 3 +#define FILE_FORMAT_JPG 4 +#define FILE_FORMAT_PNG 5 +#define FILE_FORMAT_GIF 6 +#define FILE_FORMAT_BMP 7 +#define FILE_FORMAT_TIF 8 + +#define CODEC_TYPE_MPEG4 2 +#define CODEC_TYPE_AVC 3 +#define CODEC_TYPE_MP3 12 +#define CODEC_TYPE_AAC 13 +#define CODEC_TYPE_PCM 15 +#define CODEC_TYPE_JPG 17 +#define CODEC_TYPE_PNG 18 +#define CODEC_TYPE_TIF 19 +#define CODEC_TYPE_BMP 20 +#define CODEC_TYPE_GIF 21 + +extern const file_type audio_list[3]; +extern const file_type photo_list[7]; +extern const file_type video_list[1]; + +class Database : public QObject +{ + Q_OBJECT +public: + explicit Database(QObject *parent = 0); + + virtual int childObjectCount(int parent_ohfi) = 0; + virtual bool deleteEntry(int ohfi, int root_ohfi = 0) = 0; + virtual QString getAbsolutePath(int ohfi) = 0; + virtual QString getRelativePath(int ohfi) = 0; + virtual bool getObjectMetadata(int ohfi, metadata_t &metadata) = 0; + virtual int getObjectMetadatas(int parent_ohfi, metadata_t *&metadata, int index = 0, int max_number = 0) = 0; + virtual qint64 getObjectSize(int ohfi) = 0; + virtual int getPathId(const char *name, int ohfi) = 0; + virtual int insertObjectEntry(const QString &path, int parent_ohfi) = 0; + virtual bool renameObject(int ohfi, const QString &name) = 0; + virtual void setObjectSize(int ohfi, qint64 size) = 0; + virtual int getRootId(int ohfi) = 0; + + static int checkFileType(const QString path, int ohfi_root); + static void loadMusicMetadata(const QString &path, metadata_t &metadata); + static void loadPhotoMetadata(const QString &path, metadata_t &metadata); + static void loadVideoMetadata(const QString &path, metadata_t &metadata); + +}; + +#endif // DATABASE_H diff --git a/src/forms/backupmanagerform.cpp b/src/forms/backupmanagerform.cpp index c5fb9ab..72c825b 100644 --- a/src/forms/backupmanagerform.cpp +++ b/src/forms/backupmanagerform.cpp @@ -66,12 +66,13 @@ void BackupManagerForm::removeEntry(BackupItem *item) QMutexLocker locker(&db->mutex); - CMAObject *obj = db->ohfiToObject(item->ohfi); - if(obj) { - obj->removeReferencedObject(); - db->remove(obj); + metadata meta; + if(db->getObjectMetadata(item->ohfi, meta)) { + setBackupUsage(db->getObjectSize(meta.ohfiParent)); } + db->deleteEntry(item->ohfi); + for(int i = 0; i < ui->tableWidget->rowCount(); ++i) { BackupItem *iter_item = static_cast(ui->tableWidget->cellWidget(i, 0)); if(iter_item == item) { @@ -79,11 +80,6 @@ void BackupManagerForm::removeEntry(BackupItem *item) break; } } - - obj = db->ohfiToObject(obj->metadata.ohfiParent); - if(obj) { - setBackupUsage(obj->metadata.size); - } } void BackupManagerForm::setBackupUsage(quint64 size) @@ -146,10 +142,9 @@ void BackupManagerForm::loadBackupListing(int index) db->mutex.lock(); - // get the item list + // get the item list metadata_t *meta; - int row_count = db->filterObjects(ohfi, &meta); - + int row_count = db->getObjectMetadatas(ohfi, meta); ui->tableWidget->setRowCount(row_count); // exit if there aren't any items @@ -167,13 +162,12 @@ void BackupManagerForm::loadBackupListing(int index) #else horiz_header->setResizeMode(QHeaderView::Stretch); #endif - CMAObject *obj = db->ohfiToObject(ohfi); - setBackupUsage(obj->metadata.size); - + setBackupUsage(db->getObjectSize(ohfi)); + QString path = db->getAbsolutePath(ohfi); QList item_list; while(meta) { - QString base_path = obj->path + QDir::separator() + meta->name; + QString base_path = path + QDir::separator() + meta->name; QString parent_path = sys_dir ? base_path + QDir::separator() + "sce_sys" : base_path; SfoReader reader; QString game_name; @@ -213,7 +207,7 @@ void BackupManagerForm::loadBackupListing(int index) item->setItemInfo(game_name, size, info); item->setItemIcon(QDir(parent_path).absoluteFilePath(sys_dir ? "icon0.png" : "ICON0.PNG"), img_width, ohfi == VITA_OHFI_PSMAPP); - item->setDirectory(obj->path + QDir::separator() + meta->name); + item->setDirectory(path + QDir::separator() + meta->name); item->resize(646, 68); item_list << item; diff --git a/src/qlistdb.cpp b/src/qlistdb.cpp index eff9f9a..0fc1a23 100644 --- a/src/qlistdb.cpp +++ b/src/qlistdb.cpp @@ -28,7 +28,8 @@ #include #include -QListDB::QListDB() : +QListDB::QListDB(QObject *parent) : + Database(parent), mutex(QMutex::Recursive) { QString uuid = QSettings().value("lastAccountId", "ffffffffffffffff").toString(); @@ -249,18 +250,18 @@ void QListDB::destroy() object_list.clear(); } -bool QListDB::removeInternal(root_list &list, const CMAObject *obj) +bool QListDB::removeInternal(root_list &list, int ohfi) { bool found = false; QList::iterator it = list.begin(); while(it != list.end()) { - if(!found && (*it) == obj) { + if(!found && (*it)->metadata.ohfi == ohfi) { // update the size of the parent objects (*it)->updateObjectSize(-(*it)->metadata.size); it = list.erase(it); found = true; - } else if(found && (*it)->metadata.ohfiParent == obj->metadata.ohfi) { + } else if(found && (*it)->metadata.ohfiParent == ohfi) { it = list.erase(it); } else { ++it; @@ -270,22 +271,6 @@ bool QListDB::removeInternal(root_list &list, const CMAObject *obj) return found; } -bool QListDB::remove(const CMAObject *obj, int ohfi_root) -{ - QMutexLocker locker(&mutex); - - if(ohfi_root) { - return removeInternal(object_list[ohfi_root], obj); - } else { - for(map_list::iterator root = object_list.begin(); root != object_list.end(); ++root) { - if(removeInternal(*root, obj)) { - return true; - } - } - } - return false; -} - bool QListDB::lessThanComparator(const CMAObject *a, const CMAObject *b) { return a->metadata.ohfi < b->metadata.ohfi; @@ -326,23 +311,6 @@ bool QListDB::find(int ohfi, QListDB::find_data &data) return false; } -void QListDB::append(int parent_ohfi, CMAObject *object) -{ - QMutexLocker locker(&mutex); - CMAObject parent; - parent.setOhfi(parent_ohfi); - - for(map_list::iterator root = object_list.begin(); root != object_list.end(); ++root) { - root_list *cat_list = &(*root); - root_list::const_iterator it = qBinaryFind(cat_list->begin(), cat_list->end(), &parent, QListDB::lessThanComparator); - - if(it != cat_list->end()) { - cat_list->append(object); - break; - } - } -} - CMAObject *QListDB::ohfiToObject(int ohfi) { QMutexLocker locker(&mutex); @@ -363,24 +331,6 @@ CMAObject *QListDB::pathToObjectInternal(const root_list &list, const char *path return NULL; } -CMAObject *QListDB::pathToObject(const char *path, int ohfiRoot) -{ - QMutexLocker locker(&mutex); - - for(map_list::iterator root = object_list.begin(); root != object_list.end(); ++root) { - - if(ohfiRoot && (*root).first()->metadata.ohfi != ohfiRoot) { - continue; - } - CMAObject *obj = pathToObjectInternal(*root, path); - - if(obj) { - return obj; - } - } - return NULL; -} - int QListDB::acceptFilteredObject(const CMAObject *parent, const CMAObject *current, int type) { QMutexLocker locker(&mutex); @@ -421,10 +371,45 @@ void QListDB::dumpMetadataList(const metadata_t *p_head) } } -int QListDB::filterObjects(int ohfiParent, metadata_t **p_head, int index, int max_number) +bool QListDB::getObjectMetadata(int ohfi, metadata_t &metadata) { QMutexLocker locker(&mutex); - CMARootObject *parent = static_cast(ohfiToObject(ohfiParent)); + + CMAObject *obj = ohfiToObject(ohfi); + if(obj) { + //TODO: return the pointer instead of copying the struct + metadata = obj->metadata; + return true; + } + return false; +} + +int QListDB::childObjectCount(int parent_ohfi) +{ + metadata_t *metadata = NULL; + return getObjectMetadatas(parent_ohfi, metadata); +} + +bool QListDB::deleteEntry(int ohfi, int root_ohfi) +{ + QMutexLocker locker(&mutex); + + if(root_ohfi) { + return removeInternal(object_list[root_ohfi], ohfi); + } else { + for(map_list::iterator root = object_list.begin(); root != object_list.end(); ++root) { + if(removeInternal(*root, ohfi)) { + return true; + } + } + } + return false; +} + +int QListDB::getObjectMetadatas(int parent_ohfi, metadata_t *&metadata, int index, int max_number) +{ + QMutexLocker locker(&mutex); + CMARootObject *parent = static_cast(ohfiToObject(parent_ohfi)); if(parent == NULL) { return 0; @@ -433,11 +418,11 @@ int QListDB::filterObjects(int ohfiParent, metadata_t **p_head, int index, int m int type = parent->metadata.type; if(parent->metadata.ohfi < OHFI_OFFSET && parent->filters) { // if we have filters - if(ohfiParent == parent->metadata.ohfi) { // if we are looking at root - return parent->getFilters(p_head); + if(parent_ohfi == parent->metadata.ohfi) { // if we are looking at root + return parent->getFilters(&metadata); } else { // we are looking at a filter for(int j = 0; j < parent->num_filters; j++) { - if(parent->filters[j].ohfi == ohfiParent) { + if(parent->filters[j].ohfi == parent_ohfi) { type = parent->filters[j].type; break; } @@ -472,9 +457,123 @@ int QListDB::filterObjects(int ohfiParent, metadata_t **p_head, int index, int m tail->next_metadata = NULL; - if(p_head != NULL) { - *p_head = temp.next_metadata; + if(metadata != NULL) { + metadata = temp.next_metadata; } return numObjects; } + +qint64 QListDB::getObjectSize(int ohfi) +{ + QMutexLocker locker(&mutex); + + CMAObject *obj = ohfiToObject(ohfi); + return obj ? obj->metadata.size : -1; +} + +int QListDB::getPathId(const char *name, int ohfi) +{ + QMutexLocker locker(&mutex); + + for(map_list::iterator root = object_list.begin(); root != object_list.end(); ++root) { + + if(ohfi && (*root).first()->metadata.ohfi != ohfi) { + continue; + } + CMAObject *obj = pathToObjectInternal(*root, name); + + if(obj) { + return obj->metadata.ohfi; + } + } + return 0; +} + +int QListDB::insertObjectEntry(const QString &path, int parent_ohfi) +{ + QMutexLocker locker(&mutex); + + CMAObject *parent = ohfiToObject(parent_ohfi); + + for(map_list::iterator root = object_list.begin(); root != object_list.end(); ++root) { + root_list *cat_list = &(*root); + root_list::const_iterator it = qBinaryFind(cat_list->begin(), cat_list->end(), parent, QListDB::lessThanComparator); + + if(it != cat_list->end()) { + CMAObject *newobj = new CMAObject(parent); + newobj->initObject(path); + cat_list->append(newobj); + return newobj->metadata.ohfi; + } + } + + return 0; +} + +QString QListDB::getAbsolutePath(int ohfi) +{ + QMutexLocker locker(&mutex); + CMAObject *obj = ohfiToObject(ohfi); + return obj ? obj->path : NULL; +} + +QString QListDB::getRelativePath(int ohfi) +{ + QMutexLocker locker(&mutex); + CMAObject *obj = ohfiToObject(ohfi); + return obj ? obj->metadata.path : NULL; +} + +bool QListDB::renameObject(int ohfi, const QString &name) +{ + QMutexLocker locker(&mutex); + + CMAObject *root = ohfiToObject(ohfi); + + if(!root) { + return false; + } + + //rename the current object + root->rename(name); + QListDB::find_data iters; + find(root->metadata.ohfi, iters); + + // rename the rest of the list only if has the renamed parent in some part of the chain + while(iters.it != iters.end) { + CMAObject *obj = *iters.it++; + + if(obj->hasParent(root)) { + obj->refreshPath(); + } + } + + return true; +} + +void QListDB::setObjectSize(int ohfi, qint64 size) +{ + QMutexLocker locker(&mutex); + CMAObject *obj = ohfiToObject(ohfi); + + if(obj) { + obj->updateObjectSize(size); + } +} + +int QListDB::getRootId(int ohfi) +{ + QMutexLocker locker(&mutex); + CMAObject *obj = ohfiToObject(ohfi); + + if(!obj) { + return 0; + } + + while(obj->parent) { + obj = obj->parent; + } + + return obj->metadata.ohfi; +} diff --git a/src/qlistdb.h b/src/qlistdb.h index edbb560..ac8144b 100644 --- a/src/qlistdb.h +++ b/src/qlistdb.h @@ -20,6 +20,7 @@ #ifndef QLISTDB_H #define QLISTDB_H +#include "database.h" #include "cmarootobject.h" #include @@ -30,51 +31,54 @@ #include -class QListDB : public QObject +class QListDB : public Database { Q_OBJECT public: + explicit QListDB(QObject *parent = 0); + ~QListDB(); + + bool reload(bool &prepared); + void setUUID(const QString uuid); + + int childObjectCount(int parent_ohfi); + bool deleteEntry(int ohfi, int root_ohfi = 0); + QString getAbsolutePath(int ohfi); + bool getObjectMetadata(int ohfi, metadata_t &metadata); + int getObjectMetadatas(int parent_ohfi, metadata_t *&metadata, int index = 0, int max_number = 0); + qint64 getObjectSize(int ohfi); + int getPathId(const char *name, int ohfi); + QString getRelativePath(int ohfi); + int getRootId(int ohfi); + int insertObjectEntry(const QString &path, int parent_ohfi); + bool renameObject(int ohfi, const QString &name); + void setObjectSize(int ohfi, qint64 size); + + QMutex mutex; + +private: typedef struct { QList::const_iterator it; QList::const_iterator end; } find_data; - explicit QListDB(); - ~QListDB(); - - bool reload(bool &prepared); - void setUUID(const QString uuid); - void addEntries(CMAObject *root); - CMAObject *ohfiToObject(int ohfi); - bool find(int ohfi, find_data &data); - void append(int parent_ohfi, CMAObject *object); - bool remove(const CMAObject *obj, int ohfi_root = 0); - int filterObjects(int ohfiParent, metadata_t **p_head, int index = 0, int max_number = 0); - CMAObject *pathToObject(const char *path, int ohfiRoot); - int acceptFilteredObject(const CMAObject *parent, const CMAObject *current, int type); - - QMutex mutex; - -private: typedef QList root_list; typedef QMap map_list; - static const QStringList audio_types; - static const QStringList image_types; - static const QStringList video_types; - - int create(); void destroy(); int scanRootDirectory(root_list &list,int ohfi_type); int recursiveScanRootDirectory(root_list &list, CMAObject *parent, int ohfi_type); bool hasFilter(const CMARootObject *object,int ohfi); - bool removeInternal(root_list &list, const CMAObject *obj); + bool removeInternal(root_list &list, int ohfi); bool findInternal(const root_list &list, int ohfi, find_data &data); CMAObject *getParent(CMAObject *last_dir, const QString ¤t_path); CMAObject *pathToObjectInternal(const root_list &list, const char *path); static bool lessThanComparator(const CMAObject *a, const CMAObject *b); void dumpMetadataList(const metadata_t *p_head); + bool find(int ohfi, find_data &data); + int acceptFilteredObject(const CMAObject *parent, const CMAObject *current, int type); + CMAObject *ohfiToObject(int ohfi); bool continueOperation(); // control variables diff --git a/src/sqlitedb.cpp b/src/sqlitedb.cpp index 6ba19af..3ac1592 100644 --- a/src/sqlitedb.cpp +++ b/src/sqlitedb.cpp @@ -115,7 +115,7 @@ static const char *trigger_list[] = { }; SQLiteDB::SQLiteDB(QObject *parent) : - QObject(parent) + Database(parent) { uuid = QSettings().value("lastAccountId", "ffffffffffffffff").toString(); } @@ -275,6 +275,13 @@ int SQLiteDB::recursiveScanRootDirectory(const QString &base_path, int parent, i return total_objects; } +bool SQLiteDB::getObjectMetadata(int ohfi, metadata_t &metadata) +{ + Q_UNUSED(ohfi); + Q_UNUSED(metadata); + return false; +} + int SQLiteDB::getPathId(const QString &path) { QSqlQuery query(QString("SELECT object_id from sources WHERE path = %1").arg(path)); diff --git a/src/sqlitedb.h b/src/sqlitedb.h index e2a42d6..e78329b 100644 --- a/src/sqlitedb.h +++ b/src/sqlitedb.h @@ -1,6 +1,8 @@ #ifndef SQLITEDB_H #define SQLITEDB_H +#include "database.h" + #include #include @@ -25,7 +27,7 @@ #define OBJECT_APPLICATION 0x00080000 -class SQLiteDB : public QObject +class SQLiteDB : public Database { Q_OBJECT public: @@ -51,6 +53,8 @@ public: uint insertSavedataEntry(const QString &path, int type, int parent); uint insertApplicationEntry(const QString &path, int type, int parent, int app_type); + bool getObjectMetadata(int ohfi, metadata_t &metadata); + private: int recursiveScanRootDirectory(const QString &base_path, int parent, int type); uint insertDirectoryEntry(const QString &path, int type, int parent); diff --git a/src/utils.cpp b/src/utils.cpp index 07e814d..22059f0 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -31,26 +31,6 @@ #include #endif -const file_type audio_list[] = { - {"mp3", FILE_FORMAT_MP3, CODEC_TYPE_MP3}, - {"mp4", FILE_FORMAT_MP4, CODEC_TYPE_AAC}, - {"wav", FILE_FORMAT_WAV, CODEC_TYPE_PCM} -}; - -const file_type photo_list[] = { - {"jpg", FILE_FORMAT_JPG, CODEC_TYPE_JPG}, - {"jpeg", FILE_FORMAT_JPG, CODEC_TYPE_JPG}, - {"png", FILE_FORMAT_PNG, CODEC_TYPE_PNG}, - {"tif", FILE_FORMAT_TIF, CODEC_TYPE_TIF}, - {"tiff", FILE_FORMAT_TIF, CODEC_TYPE_TIF}, - {"bmp", FILE_FORMAT_BMP, CODEC_TYPE_BMP}, - {"gif", FILE_FORMAT_GIF, CODEC_TYPE_GIF}, -}; - -const file_type video_list[] = { - {"mp4", FILE_FORMAT_MP4, 0} -}; - bool getDiskSpace(const QString &dir, quint64 *free, quint64 *total) { #ifdef Q_OS_WIN32 @@ -195,33 +175,3 @@ QString readable_size(quint64 size, bool use_gib) } return QString().setNum(size_f,'f',2) + " " + unit; } - -int checkFileType(const QString path, int ohfi_root) -{ - switch(ohfi_root) { - case VITA_OHFI_MUSIC: - for(int i = 0, max = sizeof(audio_list) / sizeof(file_type); i < max; i++) { - if(path.endsWith(audio_list[i].file_ext, Qt::CaseInsensitive)) { - return i; - } - } - break; - case VITA_OHFI_PHOTO: - for(int i = 0, max = sizeof(photo_list) / sizeof(file_type); i< max; i++) { - if(path.endsWith(photo_list[i].file_ext, Qt::CaseInsensitive)) { - return i; - } - } - break; - case VITA_OHFI_VIDEO: - for(int i = 0, max = sizeof(video_list) / sizeof(file_type); i< max; i++) { - if(path.endsWith(video_list[i].file_ext, Qt::CaseInsensitive)) { - return i; - } - } - break; - default: - return 0; - } - return -1; -} diff --git a/src/utils.h b/src/utils.h index 816a34f..8d8deba 100644 --- a/src/utils.h +++ b/src/utils.h @@ -26,36 +26,6 @@ #include -typedef struct { - const char *file_ext; - int file_format; - int file_codec; -} file_type; - -#define FILE_FORMAT_MP4 1 -#define FILE_FORMAT_WAV 2 -#define FILE_FORMAT_MP3 3 -#define FILE_FORMAT_JPG 4 -#define FILE_FORMAT_PNG 5 -#define FILE_FORMAT_GIF 6 -#define FILE_FORMAT_BMP 7 -#define FILE_FORMAT_TIF 8 - -#define CODEC_TYPE_MPEG4 2 -#define CODEC_TYPE_AVC 3 -#define CODEC_TYPE_MP3 12 -#define CODEC_TYPE_AAC 13 -#define CODEC_TYPE_PCM 15 -#define CODEC_TYPE_JPG 17 -#define CODEC_TYPE_PNG 18 -#define CODEC_TYPE_TIF 19 -#define CODEC_TYPE_BMP 20 -#define CODEC_TYPE_GIF 21 - -extern const file_type audio_list[3]; -extern const file_type photo_list[7]; -extern const file_type video_list[1]; - // Qt4 doesn't have public methods for Thread::*sleep #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) typedef QThread Sleeper; @@ -79,6 +49,5 @@ bool removeRecursively(const QString &dirName); QString readable_size(quint64 size, bool use_gib = false); bool getDiskSpace(const QString &dir, quint64 *free, quint64 *total); QByteArray getThumbnail(const QString &path, DataType type, metadata_t *metadata); -int checkFileType(const QString path, int ohfi_root); #endif // UTILS_H From a021c5db8f5186175f41eb0e61a5ac7bc1ee2f5a Mon Sep 17 00:00:00 2001 From: codestation Date: Tue, 28 Jan 2014 18:05:43 -0430 Subject: [PATCH 5/9] Modify removeRecursively to be able to delete a file. Added getParentId func. Add the datatype for newly inserted items. Pass a double pointer instead of a pointer reference so the metadata_t can be optional. Make sure to delete the files after deleting an entry in the backup manager. --- src/cmaevent.cpp | 6 +++--- src/cmaobject.cpp | 9 -------- src/cmaobject.h | 4 ---- src/database.h | 3 ++- src/forms/backupmanagerform.cpp | 15 +++++++------ src/qlistdb.cpp | 36 ++++++++++++++++++++----------- src/qlistdb.h | 3 ++- src/utils.cpp | 38 +++++++++++++++++++-------------- src/utils.h | 2 +- 9 files changed, 62 insertions(+), 54 deletions(-) diff --git a/src/cmaevent.cpp b/src/cmaevent.cpp index 8e0dc0e..73f9cb9 100644 --- a/src/cmaevent.cpp +++ b/src/cmaevent.cpp @@ -172,9 +172,9 @@ quint16 CmaEvent::processAllObjects(metadata_t &parent_metadata, quint32 handle) } int ohfi = db->getPathId(name, parent_metadata.ohfi); - const QString fullpath = db->getAbsolutePath(ohfi); if(ohfi > 0) { + const QString fullpath = db->getAbsolutePath(ohfi); qDebug() << "Deleting" << fullpath; removeRecursively(fullpath); db->deleteEntry(ohfi); @@ -382,7 +382,7 @@ void CmaEvent::vitaEventSendObjectMetadata(vita_event_t *event, int eventId) metadata_t *meta = NULL; - int count = db->getObjectMetadatas(browse.ohfiParent, meta, browse.index, browse.numObjects); // if meta is null, will return empty XML + int count = db->getObjectMetadatas(browse.ohfiParent, &meta, browse.index, browse.numObjects); // if meta is null, will return empty XML qDebug("Sending %i metadata filtered objects for OHFI %d", count, browse.ohfiParent); if(VitaMTP_SendObjectMetadata(device, eventId, meta) != PTP_RC_OK) { // send all objects with OHFI parent @@ -403,7 +403,7 @@ void CmaEvent::vitaEventSendObject(vita_event_t *event, int eventId) qDebug("Searching object with OHFI %d", ohfi); metadata_t *metadata = NULL; - if(!db->getObjectMetadatas(ohfi, metadata)) { + if(!db->getObjectMetadatas(ohfi, &metadata)) { qWarning("Failed to find OHFI %d", ohfi); VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_OHFI); return; diff --git a/src/cmaobject.cpp b/src/cmaobject.cpp index a7783bc..68856a9 100644 --- a/src/cmaobject.cpp +++ b/src/cmaobject.cpp @@ -181,15 +181,6 @@ void CMAObject::initObject(const QFileInfo &file, int file_type) updateObjectSize(file.size()); } -bool CMAObject::removeReferencedObject() -{ - if(metadata.dataType & Folder) { - return removeRecursively(path); - } else { - return QFile::remove(path); - } -} - void CMAObject::updateObjectSize(qint64 size) { if(parent) { diff --git a/src/cmaobject.h b/src/cmaobject.h index e5c0953..4f36a07 100644 --- a/src/cmaobject.h +++ b/src/cmaobject.h @@ -34,7 +34,6 @@ public: ~CMAObject(); void refreshPath(); - bool removeReferencedObject(); void rename(const QString &name); void updateObjectSize(qint64 size); bool hasParent(const CMAObject *obj); @@ -61,9 +60,6 @@ protected: private: void loadSfoMetadata(const QString &path); - void loadMusicMetadata(const QString &path); - void loadVideoMetadata(const QString &path); - void loadPhotoMetadata(const QString &path); }; #endif // CMAOBJECT_H diff --git a/src/database.h b/src/database.h index 29daf8c..3086711 100644 --- a/src/database.h +++ b/src/database.h @@ -45,12 +45,13 @@ public: virtual QString getAbsolutePath(int ohfi) = 0; virtual QString getRelativePath(int ohfi) = 0; virtual bool getObjectMetadata(int ohfi, metadata_t &metadata) = 0; - virtual int getObjectMetadatas(int parent_ohfi, metadata_t *&metadata, int index = 0, int max_number = 0) = 0; + virtual int getObjectMetadatas(int parent_ohfi, metadata_t **metadata, int index = 0, int max_number = 0) = 0; virtual qint64 getObjectSize(int ohfi) = 0; virtual int getPathId(const char *name, int ohfi) = 0; virtual int insertObjectEntry(const QString &path, int parent_ohfi) = 0; virtual bool renameObject(int ohfi, const QString &name) = 0; virtual void setObjectSize(int ohfi, qint64 size) = 0; + virtual int getParentId(int ohfi) = 0; virtual int getRootId(int ohfi) = 0; static int checkFileType(const QString path, int ohfi_root); diff --git a/src/forms/backupmanagerform.cpp b/src/forms/backupmanagerform.cpp index 72c825b..23bbace 100644 --- a/src/forms/backupmanagerform.cpp +++ b/src/forms/backupmanagerform.cpp @@ -66,11 +66,8 @@ void BackupManagerForm::removeEntry(BackupItem *item) QMutexLocker locker(&db->mutex); - metadata meta; - if(db->getObjectMetadata(item->ohfi, meta)) { - setBackupUsage(db->getObjectSize(meta.ohfiParent)); - } - + int parent_ohfi = db->getParentId(item->ohfi); + removeRecursively(db->getAbsolutePath(item->ohfi)); db->deleteEntry(item->ohfi); for(int i = 0; i < ui->tableWidget->rowCount(); ++i) { @@ -80,6 +77,10 @@ void BackupManagerForm::removeEntry(BackupItem *item) break; } } + + if(parent_ohfi > 0) { + setBackupUsage(db->getObjectSize(parent_ohfi)); + } } void BackupManagerForm::setBackupUsage(quint64 size) @@ -143,8 +144,8 @@ void BackupManagerForm::loadBackupListing(int index) db->mutex.lock(); // get the item list - metadata_t *meta; - int row_count = db->getObjectMetadatas(ohfi, meta); + metadata_t *meta = NULL; + int row_count = db->getObjectMetadatas(ohfi, &meta); ui->tableWidget->setRowCount(row_count); // exit if there aren't any items diff --git a/src/qlistdb.cpp b/src/qlistdb.cpp index 0fc1a23..ef08e70 100644 --- a/src/qlistdb.cpp +++ b/src/qlistdb.cpp @@ -301,8 +301,6 @@ bool QListDB::findInternal(const root_list &list, int ohfi, find_data &data) bool QListDB::find(int ohfi, QListDB::find_data &data) { - QMutexLocker locker(&mutex); - for(map_list::iterator root = object_list.begin(); root != object_list.end(); ++root) { if(findInternal(*root, ohfi, data)) { return true; @@ -313,7 +311,6 @@ bool QListDB::find(int ohfi, QListDB::find_data &data) CMAObject *QListDB::ohfiToObject(int ohfi) { - QMutexLocker locker(&mutex); find_data data; return find(ohfi, data) ? *data.it : NULL; } @@ -365,6 +362,8 @@ int QListDB::acceptFilteredObject(const CMAObject *parent, const CMAObject *curr void QListDB::dumpMetadataList(const metadata_t *p_head) { + QMutexLocker locker(&mutex); + while(p_head) { qDebug("Metadata: %s with OHFI %d", p_head->name, p_head->ohfi); p_head = p_head->next_metadata; @@ -386,8 +385,7 @@ bool QListDB::getObjectMetadata(int ohfi, metadata_t &metadata) int QListDB::childObjectCount(int parent_ohfi) { - metadata_t *metadata = NULL; - return getObjectMetadatas(parent_ohfi, metadata); + return getObjectMetadatas(parent_ohfi, NULL); } bool QListDB::deleteEntry(int ohfi, int root_ohfi) @@ -406,7 +404,7 @@ bool QListDB::deleteEntry(int ohfi, int root_ohfi) return false; } -int QListDB::getObjectMetadatas(int parent_ohfi, metadata_t *&metadata, int index, int max_number) +int QListDB::getObjectMetadatas(int parent_ohfi, metadata_t **metadata, int index, int max_number) { QMutexLocker locker(&mutex); CMARootObject *parent = static_cast(ohfiToObject(parent_ohfi)); @@ -419,7 +417,7 @@ int QListDB::getObjectMetadatas(int parent_ohfi, metadata_t *&metadata, int inde if(parent->metadata.ohfi < OHFI_OFFSET && parent->filters) { // if we have filters if(parent_ohfi == parent->metadata.ohfi) { // if we are looking at root - return parent->getFilters(&metadata); + return parent->getFilters(metadata); } else { // we are looking at a filter for(int j = 0; j < parent->num_filters; j++) { if(parent->filters[j].ohfi == parent_ohfi) { @@ -458,7 +456,7 @@ int QListDB::getObjectMetadatas(int parent_ohfi, metadata_t *&metadata, int inde tail->next_metadata = NULL; if(metadata != NULL) { - metadata = temp.next_metadata; + *metadata = temp.next_metadata; } return numObjects; @@ -494,15 +492,21 @@ int QListDB::insertObjectEntry(const QString &path, int parent_ohfi) { QMutexLocker locker(&mutex); - CMAObject *parent = ohfiToObject(parent_ohfi); + CMAObject *parent_obj = ohfiToObject(parent_ohfi); for(map_list::iterator root = object_list.begin(); root != object_list.end(); ++root) { root_list *cat_list = &(*root); - root_list::const_iterator it = qBinaryFind(cat_list->begin(), cat_list->end(), parent, QListDB::lessThanComparator); + root_list::const_iterator it = qBinaryFind(cat_list->begin(), cat_list->end(), parent_obj, QListDB::lessThanComparator); if(it != cat_list->end()) { - CMAObject *newobj = new CMAObject(parent); - newobj->initObject(path); + CMAObject *newobj = new CMAObject(parent_obj); + + // get the root object + while(parent_obj->parent) { + parent_obj = parent_obj->parent; + } + + newobj->initObject(path, parent_obj->metadata.dataType); cat_list->append(newobj); return newobj->metadata.ohfi; } @@ -577,3 +581,11 @@ int QListDB::getRootId(int ohfi) return obj->metadata.ohfi; } + +int QListDB::getParentId(int ohfi) +{ + QMutexLocker locker(&mutex); + CMAObject *obj = ohfiToObject(ohfi); + + return obj ? obj->metadata.ohfiParent : 0; +} diff --git a/src/qlistdb.h b/src/qlistdb.h index ac8144b..6f32707 100644 --- a/src/qlistdb.h +++ b/src/qlistdb.h @@ -45,8 +45,9 @@ public: bool deleteEntry(int ohfi, int root_ohfi = 0); QString getAbsolutePath(int ohfi); bool getObjectMetadata(int ohfi, metadata_t &metadata); - int getObjectMetadatas(int parent_ohfi, metadata_t *&metadata, int index = 0, int max_number = 0); + int getObjectMetadatas(int parent_ohfi, metadata_t **metadata, int index = 0, int max_number = 0); qint64 getObjectSize(int ohfi); + int getParentId(int ohfi); int getPathId(const char *name, int ohfi); QString getRelativePath(int ohfi); int getRootId(int ohfi); diff --git a/src/utils.cpp b/src/utils.cpp index 22059f0..3e1680b 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -52,31 +52,37 @@ bool getDiskSpace(const QString &dir, quint64 *free, quint64 *total) return false; } -bool removeRecursively(const QString &dirName) +bool removeRecursively(const QString &path) { + QFileInfo info(path); + + if(info.isDir()) { #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) - return QDir(dirName).removeRecursively(); + return QDir(path).removeRecursively(); #else - bool result = false; - QDir dir(dirName); + bool result = false; + QDir dir(path); - if(dir.exists(dirName)) { - Q_FOREACH(QFileInfo info, dir.entryInfoList(QDir::NoDotAndDotDot | QDir::System | QDir::Hidden | QDir::AllDirs | QDir::Files, QDir::DirsFirst)) { - if(info.isDir()) { - result = removeRecursively(info.absoluteFilePath()); - } else { - result = QFile::remove(info.absoluteFilePath()); - } + if(dir.exists(path)) { + Q_FOREACH(QFileInfo info, dir.entryInfoList(QDir::NoDotAndDotDot | QDir::System | QDir::Hidden | QDir::AllDirs | QDir::Files, QDir::DirsFirst)) { + if(info.isDir()) { + result = removeRecursively(info.absoluteFilePath()); + } else { + result = QFile::remove(info.absoluteFilePath()); + } - if(!result) { - return result; + if(!result) { + return result; + } } + result = dir.rmdir(path); } - result = dir.rmdir(dirName); - } - return result; + return result; #endif + } else { + return QFile::remove(path); + } } QByteArray findFolderAlbumArt(const QString path, metadata_t *metadata) diff --git a/src/utils.h b/src/utils.h index 8d8deba..35f690f 100644 --- a/src/utils.h +++ b/src/utils.h @@ -45,7 +45,7 @@ public: }; #endif -bool removeRecursively(const QString &dirName); +bool removeRecursively(const QString &path); QString readable_size(quint64 size, bool use_gib = false); bool getDiskSpace(const QString &dir, quint64 *free, quint64 *total); QByteArray getThumbnail(const QString &path, DataType type, metadata_t *metadata); From f722c4579b9fc13dfb0fcd4d6f35deaab29574d5 Mon Sep 17 00:00:00 2001 From: codestation Date: Wed, 29 Jan 2014 01:06:19 -0430 Subject: [PATCH 6/9] Pass database object to others using their constructors. Prepare SQLiteDB class functions so it can be instantiated. --- src/clientmanager.cpp | 19 +++--- src/clientmanager.h | 6 +- src/cmaclient.cpp | 6 +- src/cmaclient.h | 3 +- src/cmaevent.cpp | 101 ++++++++++++++++---------------- src/cmaevent.h | 11 ++-- src/database.cpp | 3 +- src/database.h | 9 ++- src/forms/backupmanagerform.cpp | 26 ++++---- src/forms/backupmanagerform.h | 10 ++-- src/forms/configwidget.cpp | 2 + src/forms/configwidget.ui | 10 ++-- src/mainwidget.cpp | 44 +++++++++----- src/mainwidget.h | 9 ++- src/qlistdb.cpp | 3 +- src/qlistdb.h | 2 - src/sqlitedb.cpp | 74 ++++++++++++++++++++--- src/sqlitedb.h | 16 ++++- 18 files changed, 224 insertions(+), 130 deletions(-) diff --git a/src/clientmanager.cpp b/src/clientmanager.cpp index 3b2e6b5..395fb47 100644 --- a/src/clientmanager.cpp +++ b/src/clientmanager.cpp @@ -26,8 +26,8 @@ #include -ClientManager::ClientManager(QObject *parent) : - QObject(parent) +ClientManager::ClientManager(Database *db, QObject *parent) : + QObject(parent), m_db(db) { } @@ -63,11 +63,10 @@ void ClientManager::start() // initializing database for the first use refreshDatabase(); - CmaEvent::db = &db; - connect(&db, SIGNAL(fileAdded(QString)), &progress, SLOT(setFileName(QString))); - connect(&db, SIGNAL(directoryAdded(QString)), &progress, SLOT(setDirectoryName(QString))); - connect(&db, SIGNAL(updated(int)), this, SLOT(databaseUpdated(int))); - connect(&progress, SIGNAL(canceled()), &db, SLOT(cancelOperation()), Qt::DirectConnection); + connect(m_db, SIGNAL(fileAdded(QString)), &progress, SLOT(setFileName(QString))); + connect(m_db, SIGNAL(directoryAdded(QString)), &progress, SLOT(setDirectoryName(QString))); + connect(m_db, SIGNAL(updated(int)), this, SLOT(databaseUpdated(int))); + connect(&progress, SIGNAL(canceled()), m_db, SLOT(cancelOperation()), Qt::DirectConnection); thread_count = 0; qDebug("Starting cma threads"); @@ -76,7 +75,7 @@ void ClientManager::start() if(!settings.value("disableUSB", false).toBool()) { usb_thread = new QThread(); - client = new CmaClient(); + client = new CmaClient(m_db); usb_thread->setObjectName("usb_thread"); connect(usb_thread, SIGNAL(started()), client, SLOT(connectUsb())); connect(client, SIGNAL(messageSent(QString)), this, SIGNAL(messageSent(QString))); @@ -96,7 +95,7 @@ void ClientManager::start() if(!settings.value("disableWireless", false).toBool()) { wireless_thread = new QThread(); - client = new CmaClient(); + client = new CmaClient(m_db); wireless_thread->setObjectName("wireless_thread"); connect(wireless_thread, SIGNAL(started()), client, SLOT(connectWireless())); connect(client, SIGNAL(messageSent(QString)), this, SIGNAL(messageSent(QString))); @@ -124,7 +123,7 @@ void ClientManager::start() void ClientManager::refreshDatabase() { bool prepared; - if(!db.reload(prepared)) { + if(!m_db->reload(prepared)) { if(prepared) { emit messageSent(tr("Cannot refresh the database while is in use")); } else { diff --git a/src/clientmanager.h b/src/clientmanager.h index 54bfede..40fa562 100644 --- a/src/clientmanager.h +++ b/src/clientmanager.h @@ -31,18 +31,18 @@ class ClientManager : public QObject { Q_OBJECT public: - explicit ClientManager(QObject *parent = 0); + explicit ClientManager(Database *db, QObject *parent = 0); ~ClientManager(); void start(); void stop(); - QListDB db; - private: int thread_count; QMutex mutex; + Database *m_db; + PinForm pinForm; ProgressForm progress; diff --git a/src/cmaclient.cpp b/src/cmaclient.cpp index daa3efd..1a4b23f 100644 --- a/src/cmaclient.cpp +++ b/src/cmaclient.cpp @@ -45,8 +45,8 @@ bool CmaClient::in_progress = false; CmaClient *CmaClient::this_object = NULL; -CmaClient::CmaClient(QObject *parent) : - QObject(parent) +CmaClient::CmaClient(Database *db, QObject *parent) : + QObject(parent), m_db(db) { this_object = this; } @@ -188,7 +188,7 @@ void CmaClient::enterEventLoop(vita_device_t *device) qDebug("Starting event loop"); - CmaEvent eventLoop (device); + CmaEvent eventLoop(m_db, device); QThread thread; thread.setObjectName("event_thread"); diff --git a/src/cmaclient.h b/src/cmaclient.h index 02d8131..4fd0700 100644 --- a/src/cmaclient.h +++ b/src/cmaclient.h @@ -35,7 +35,7 @@ class CmaClient : public QObject { Q_OBJECT public: - explicit CmaClient(QObject *parent = 0); + explicit CmaClient(Database *db, QObject *parent = 0); static bool isRunning(); void launch(); @@ -55,6 +55,7 @@ private: static void registrationComplete(); CmaBroadcast broadcast; + Database *m_db; static QString tempOnlineId; //TODO: move all the control variables to the client manager class diff --git a/src/cmaevent.cpp b/src/cmaevent.cpp index 73f9cb9..d9c8f08 100644 --- a/src/cmaevent.cpp +++ b/src/cmaevent.cpp @@ -28,13 +28,12 @@ #include #include -QListDB *CmaEvent::db = NULL; QFile *CmaEvent::m_file = NULL; static metadata_t g_thumbmeta = {0, 0, 0, NULL, NULL, 0, 0, 0, Thumbnail, {{17, 240, 136, 0, 1, 1.0f, 2}}, NULL}; -CmaEvent::CmaEvent(vita_device_t *s_device) : - device(s_device), is_active(true) +CmaEvent::CmaEvent(Database *db, vita_device_t *s_device) : + device(s_device), m_db(db), is_active(true) { } @@ -171,16 +170,16 @@ quint16 CmaEvent::processAllObjects(metadata_t &parent_metadata, quint32 handle) } - int ohfi = db->getPathId(name, parent_metadata.ohfi); + int ohfi = m_db->getPathId(name, parent_metadata.ohfi); if(ohfi > 0) { - const QString fullpath = db->getAbsolutePath(ohfi); + const QString fullpath = m_db->getAbsolutePath(ohfi); qDebug() << "Deleting" << fullpath; removeRecursively(fullpath); - db->deleteEntry(ohfi); + m_db->deleteEntry(ohfi); } - QDir dir(db->getAbsolutePath(parent_metadata.ohfi)); + QDir dir(m_db->getAbsolutePath(parent_metadata.ohfi)); if(dataType & Folder) { if(!dir.mkpath(name)) { @@ -207,14 +206,14 @@ quint16 CmaEvent::processAllObjects(metadata_t &parent_metadata, quint32 handle) } QFileInfo info(dir, name); - int new_ohfi = db->insertObjectEntry(info.absoluteFilePath(), parent_metadata.ohfi); + int new_ohfi = m_db->insertObjectEntry(info.absoluteFilePath(), parent_metadata.ohfi); free(name); qDebug() << QString("Added object %1 with OHFI %2 to database").arg(info.absoluteFilePath(), QString::number(new_ohfi)); if(dataType & Folder) { metadata_t folder_metadata; - db->getObjectMetadata(new_ohfi, folder_metadata); + m_db->getObjectMetadata(new_ohfi, folder_metadata); folder_metadata.handle = handle; for(unsigned int i = 0; i < p_len; i++) { @@ -222,7 +221,7 @@ quint16 CmaEvent::processAllObjects(metadata_t &parent_metadata, quint32 handle) if(ret != PTP_RC_OK) { qDebug("Deleteting object with OHFI %d", new_ohfi); - db->deleteEntry(new_ohfi); + m_db->deleteEntry(new_ohfi); return ret; } } @@ -242,11 +241,11 @@ void CmaEvent::vitaEventGetTreatObject(vita_event_t *event, int eventId) return; } - QMutexLocker locker(&db->mutex); + QMutexLocker locker(&m_db->mutex); metadata_t metadata; - if(!db->getObjectMetadata(treatObject.ohfiParent, metadata)) { + if(!m_db->getObjectMetadata(treatObject.ohfiParent, metadata)) { qWarning("Cannot find parent OHFI %d", treatObject.ohfiParent); VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_OHFI); return; @@ -265,13 +264,13 @@ void CmaEvent::vitaEventSendCopyConfirmationInfo(vita_event_t *event, int eventI return; } - QMutexLocker locker(&db->mutex); + QMutexLocker locker(&m_db->mutex); qint64 size; qint64 total_size = 0; for(quint32 i = 0; i < info->count; i++) { - if((size = db->getObjectSize(info->ohfi[i])) < 0) { + if((size = m_db->getObjectSize(info->ohfi[i])) < 0) { qWarning("Cannot find OHFI %d", info->ohfi[i]); free(info); return; @@ -299,11 +298,11 @@ void CmaEvent::vitaEventSendObjectMetadataItems(vita_event_t *event, int eventId return; } - QMutexLocker locker(&db->mutex); + QMutexLocker locker(&m_db->mutex); metadata_t metadata; - if(!db->getObjectMetadata(ohfi, metadata)) { + if(!m_db->getObjectMetadata(ohfi, metadata)) { qWarning("Cannot find OHFI %d in database", ohfi); VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_OHFI); return; @@ -355,10 +354,10 @@ void CmaEvent::vitaEventSendNumOfObject(vita_event_t *event, int eventId) { qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId); - QMutexLocker locker(&db->mutex); + QMutexLocker locker(&m_db->mutex); int ohfi = event->Param2; - int items = db->childObjectCount(ohfi); + int items = m_db->childObjectCount(ohfi); if(VitaMTP_SendNumOfObject(device, eventId, items) != PTP_RC_OK) { qWarning("Error occured receiving object count for OHFI parent %d", ohfi); @@ -378,11 +377,11 @@ void CmaEvent::vitaEventSendObjectMetadata(vita_event_t *event, int eventId) qWarning("GetBrowseInfo failed"); return; } - QMutexLocker locker(&db->mutex); + QMutexLocker locker(&m_db->mutex); metadata_t *meta = NULL; - int count = db->getObjectMetadatas(browse.ohfiParent, &meta, browse.index, browse.numObjects); // if meta is null, will return empty XML + int count = m_db->getObjectMetadatas(browse.ohfiParent, &meta, browse.index, browse.numObjects); // if meta is null, will return empty XML qDebug("Sending %i metadata filtered objects for OHFI %d", count, browse.ohfiParent); if(VitaMTP_SendObjectMetadata(device, eventId, meta) != PTP_RC_OK) { // send all objects with OHFI parent @@ -398,12 +397,12 @@ void CmaEvent::vitaEventSendObject(vita_event_t *event, int eventId) int ohfi = event->Param2; - QMutexLocker locker(&db->mutex); + QMutexLocker locker(&m_db->mutex); qDebug("Searching object with OHFI %d", ohfi); metadata_t *metadata = NULL; - if(!db->getObjectMetadatas(ohfi, &metadata)) { + if(!m_db->getObjectMetadatas(ohfi, &metadata)) { qWarning("Failed to find OHFI %d", ohfi); VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_OHFI); return; @@ -416,7 +415,7 @@ void CmaEvent::vitaEventSendObject(vita_event_t *event, int eventId) do { unsigned long len = metadata->size; - m_file = new QFile(db->getAbsolutePath(metadata->ohfi)); + m_file = new QFile(m_db->getAbsolutePath(metadata->ohfi)); // read the file to send if it's not a directory // if it is a directory, data and len are not used by VitaMTP @@ -435,7 +434,7 @@ void CmaEvent::vitaEventSendObject(vita_event_t *event, int eventId) if(start != metadata) { metadata_t parent_metadata; - db->getObjectMetadata(metadata->ohfiParent, parent_metadata); + m_db->getObjectMetadata(metadata->ohfiParent, parent_metadata); parentHandle = parent_metadata.handle; } @@ -469,7 +468,7 @@ void CmaEvent::vitaEventSendObject(vita_event_t *event, int eventId) metadata = metadata->next_metadata; - } while(metadata && metadata->ohfiParent >= OHFI_OFFSET); // get everything under this "folder" + } while(metadata && metadata->ohfiParent >= OHFI_BASE_VALUE); // get everything under this "folder" VitaMTP_ReportResultWithParam(device, eventId, PTP_RC_OK, handle); @@ -561,16 +560,16 @@ void CmaEvent::vitaEventSendObjectStatus(vita_event_t *event, int eventId) return; } - QMutexLocker locker(&db->mutex); + QMutexLocker locker(&m_db->mutex); - int ohfi = db->getPathId(objectstatus.title, objectstatus.ohfiRoot); + int ohfi = m_db->getPathId(objectstatus.title, objectstatus.ohfiRoot); if(ohfi == 0) { // not in database, don't return metadata qDebug("Object %s not in database (OHFI: %i). Sending OK response for non-existence", objectstatus.title, objectstatus.ohfiRoot); VitaMTP_ReportResult(device, eventId, PTP_RC_OK); } else { metadata_t metadata; - db->getObjectMetadata(ohfi, metadata); + m_db->getObjectMetadata(ohfi, metadata); metadata.next_metadata = NULL; qDebug("Sending metadata for OHFI %d", ohfi); @@ -588,18 +587,18 @@ void CmaEvent::vitaEventSendObjectThumb(vita_event_t *event, int eventId) { qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId); - QMutexLocker locker(&db->mutex); + QMutexLocker locker(&m_db->mutex); int ohfi = event->Param2; metadata_t metadata; - if(!db->getObjectMetadata(ohfi, metadata)) { + if(!m_db->getObjectMetadata(ohfi, metadata)) { qWarning("Cannot find OHFI %d in database.", ohfi); VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_OHFI); return; } - QString fullpath = db->getAbsolutePath(ohfi); + QString fullpath = m_db->getAbsolutePath(ohfi); QByteArray data = getThumbnail(fullpath, metadata.dataType, &g_thumbmeta); if(data.size() == 0) { @@ -629,21 +628,21 @@ void CmaEvent::vitaEventDeleteObject(vita_event_t *event, int eventId) { qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId); - QMutexLocker locker(&db->mutex); + QMutexLocker locker(&m_db->mutex); int ohfi = event->Param2; metadata_t metadata; - if(!db->getObjectMetadata(ohfi, metadata)) { + if(!m_db->getObjectMetadata(ohfi, metadata)) { qWarning("OHFI %d not found", ohfi); VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_OHFI); return; } - QString fullpath = db->getAbsolutePath(ohfi); + QString fullpath = m_db->getAbsolutePath(ohfi); qDebug() << QString("Deleting %1, OHFI: %2").arg(fullpath, QString::number(ohfi)); removeRecursively(fullpath); - db->deleteEntry(ohfi); + m_db->deleteEntry(ohfi); VitaMTP_ReportResult(device, eventId, PTP_RC_OK); } @@ -663,7 +662,7 @@ void CmaEvent::vitaEventGetSettingInfo(vita_event_t *event, int eventId) QSettings settings; if(settings.value("lastAccountId").toString() != settingsinfo->current_account.accountId) { - db->setUUID(settingsinfo->current_account.accountId); + m_db->setUUID(settingsinfo->current_account.accountId); // set the database to be updated ASAP emit refreshDatabase(); } @@ -720,9 +719,9 @@ void CmaEvent::vitaEventSendPartOfObject(vita_event_t *event, int eventId) return; } - QMutexLocker locker(&db->mutex); + QMutexLocker locker(&m_db->mutex); - QString fullpath = db->getAbsolutePath(part_init.ohfi); + QString fullpath = m_db->getAbsolutePath(part_init.ohfi); if(fullpath.isNull()) { qWarning("Cannot find object for OHFI %d", part_init.ohfi); @@ -762,9 +761,9 @@ void CmaEvent::vitaEventOperateObject(vita_event_t *event, int eventId) return; } - QMutexLocker locker(&db->mutex); + QMutexLocker locker(&m_db->mutex); - QString fullpath = db->getAbsolutePath(operateobject.ohfi); + QString fullpath = m_db->getAbsolutePath(operateobject.ohfi); // end for renaming only if(fullpath.isNull()) { @@ -781,7 +780,7 @@ void CmaEvent::vitaEventOperateObject(vita_event_t *event, int eventId) qWarning("Unable to create temporary folder: %s", operateobject.title); VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Failed_Operate_Object); } else { - int new_ohfi = db->insertObjectEntry(QDir(dir).absoluteFilePath(operateobject.title), operateobject.ohfi); + int new_ohfi = m_db->insertObjectEntry(QDir(dir).absoluteFilePath(operateobject.title), operateobject.ohfi); qDebug("Created folder %s with OHFI %d", operateobject.title, new_ohfi); VitaMTP_ReportResultWithParam(device, eventId, PTP_RC_OK, new_ohfi); } @@ -795,7 +794,7 @@ void CmaEvent::vitaEventOperateObject(vita_event_t *event, int eventId) qWarning("Unable to create temporary file: %s", operateobject.title); VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Failed_Operate_Object); } else { - int new_ohfi = db->insertObjectEntry(file.fileName(), operateobject.ohfi); + int new_ohfi = m_db->insertObjectEntry(file.fileName(), operateobject.ohfi); //qDebug("Created file %s with OHFI %d under parent %s", newobj->metadata.path, new_ohfi, root->metadata.path); VitaMTP_ReportResultWithParam(device, eventId, PTP_RC_OK, new_ohfi); } @@ -804,8 +803,8 @@ void CmaEvent::vitaEventOperateObject(vita_event_t *event, int eventId) case VITA_OPERATE_RENAME: { //qDebug("Operate command %d: Rename %s to %s", operateobject.cmd, root->metadata.name, operateobject.title); - db->renameObject(operateobject.ohfi, operateobject.title); - QString newpath = db->getAbsolutePath(operateobject.ohfi); + m_db->renameObject(operateobject.ohfi, operateobject.title); + QString newpath = m_db->getAbsolutePath(operateobject.ohfi); // rename in filesystem if(!QFile(fullpath).rename(newpath)) { @@ -840,8 +839,8 @@ void CmaEvent::vitaEventGetPartOfObject(vita_event_t *event, int eventId) return; } - QMutexLocker locker(&db->mutex); - QString fullpath = db->getAbsolutePath(part_init.ohfi); + QMutexLocker locker(&m_db->mutex); + QString fullpath = m_db->getAbsolutePath(part_init.ohfi); if(fullpath.isNull()) { qWarning("Cannot find OHFI %d", part_init.ohfi); @@ -861,7 +860,7 @@ void CmaEvent::vitaEventGetPartOfObject(vita_event_t *event, int eventId) } else { file.seek(part_init.offset); file.write((const char *)data, part_init.size); - db->setObjectSize(part_init.ohfi, part_init.size); + m_db->setObjectSize(part_init.ohfi, part_init.size); qDebug() << QString("Written %1 bytes to %2 at offset %3").arg( QString::number(part_init.size), fullpath, QString::number(part_init.offset) @@ -877,10 +876,10 @@ void CmaEvent::vitaEventSendStorageSize(vita_event_t *event, int eventId) { qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId); - QMutexLocker locker(&db->mutex); + QMutexLocker locker(&m_db->mutex); int ohfi = event->Param2; - QString fullpath = db->getAbsolutePath(ohfi); + QString fullpath = m_db->getAbsolutePath(ohfi); if(fullpath.isNull()) { qWarning("Error: Cannot find OHFI %d", ohfi); @@ -931,9 +930,9 @@ void CmaEvent::vitaEventCheckExistance(vita_event_t *event, int eventId) return; } - QMutexLocker locker(&db->mutex); + QMutexLocker locker(&m_db->mutex); - int ohfi = db->getPathId(existance.name, 0); + int ohfi = m_db->getPathId(existance.name, 0); if(ohfi == 0) { VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Different_Object); diff --git a/src/cmaevent.h b/src/cmaevent.h index 3eb2b8f..1119d03 100644 --- a/src/cmaevent.h +++ b/src/cmaevent.h @@ -20,9 +20,10 @@ #ifndef CMAEVENT_H #define CMAEVENT_H -#include "qlistdb.h" +#include "database.h" #include "httpdownloader.h" +#include #include #include #include @@ -33,13 +34,9 @@ class CmaEvent : public QObject { Q_OBJECT public: - explicit CmaEvent(vita_device_t *s_device); - + explicit CmaEvent(Database *db, vita_device_t *s_device); void vitaEventCancelTask(vita_event_t *event, int eventId); - // don't make the db reference static - static QListDB *db; - private: uint16_t processAllObjects(metadata_t &metadata, uint32_t handle); void vitaEventSendObject(vita_event_t *event, int eventId); @@ -72,6 +69,8 @@ private: vita_device_t *device; vita_event_t t_event; + Database *m_db; + // control variables bool is_active; QMutex mutex; diff --git a/src/database.cpp b/src/database.cpp index 7c80720..c9785c2 100644 --- a/src/database.cpp +++ b/src/database.cpp @@ -24,7 +24,8 @@ const file_type video_list[] = { }; Database::Database(QObject *parent) : - QObject(parent) + QObject(parent), + mutex(QMutex::Recursive) { } diff --git a/src/database.h b/src/database.h index 3086711..0f1851f 100644 --- a/src/database.h +++ b/src/database.h @@ -1,7 +1,9 @@ #ifndef DATABASE_H #define DATABASE_H +#include #include + #include typedef struct { @@ -10,6 +12,8 @@ typedef struct { int file_codec; } file_type; +#define OHFI_BASE_VALUE 256 + #define FILE_FORMAT_MP4 1 #define FILE_FORMAT_WAV 2 #define FILE_FORMAT_MP3 3 @@ -39,7 +43,6 @@ class Database : public QObject Q_OBJECT public: explicit Database(QObject *parent = 0); - virtual int childObjectCount(int parent_ohfi) = 0; virtual bool deleteEntry(int ohfi, int root_ohfi = 0) = 0; virtual QString getAbsolutePath(int ohfi) = 0; @@ -54,11 +57,15 @@ public: virtual int getParentId(int ohfi) = 0; virtual int getRootId(int ohfi) = 0; + virtual bool reload(bool &prepared) = 0; + virtual void setUUID(const QString uuid) = 0; + static int checkFileType(const QString path, int ohfi_root); static void loadMusicMetadata(const QString &path, metadata_t &metadata); static void loadPhotoMetadata(const QString &path, metadata_t &metadata); static void loadVideoMetadata(const QString &path, metadata_t &metadata); + QMutex mutex; }; #endif // DATABASE_H diff --git a/src/forms/backupmanagerform.cpp b/src/forms/backupmanagerform.cpp index 23bbace..e8ec4e3 100644 --- a/src/forms/backupmanagerform.cpp +++ b/src/forms/backupmanagerform.cpp @@ -32,8 +32,8 @@ #include -BackupManagerForm::BackupManagerForm(QWidget *parent) : - QWidget(parent), +BackupManagerForm::BackupManagerForm(Database *db, QWidget *parent) : + QDialog(parent), m_db(db), ui(new Ui::BackupManagerForm) { ui->setupUi(this); @@ -64,11 +64,11 @@ void BackupManagerForm::removeEntry(BackupItem *item) return; } - QMutexLocker locker(&db->mutex); + QMutexLocker locker(&m_db->mutex); - int parent_ohfi = db->getParentId(item->ohfi); - removeRecursively(db->getAbsolutePath(item->ohfi)); - db->deleteEntry(item->ohfi); + int parent_ohfi = m_db->getParentId(item->ohfi); + removeRecursively(m_db->getAbsolutePath(item->ohfi)); + m_db->deleteEntry(item->ohfi); for(int i = 0; i < ui->tableWidget->rowCount(); ++i) { BackupItem *iter_item = static_cast(ui->tableWidget->cellWidget(i, 0)); @@ -79,7 +79,7 @@ void BackupManagerForm::removeEntry(BackupItem *item) } if(parent_ohfi > 0) { - setBackupUsage(db->getObjectSize(parent_ohfi)); + setBackupUsage(m_db->getObjectSize(parent_ohfi)); } } @@ -141,17 +141,17 @@ void BackupManagerForm::loadBackupListing(int index) sys_dir = true; } - db->mutex.lock(); + m_db->mutex.lock(); // get the item list metadata_t *meta = NULL; - int row_count = db->getObjectMetadatas(ohfi, &meta); + int row_count = m_db->getObjectMetadatas(ohfi, &meta); ui->tableWidget->setRowCount(row_count); // exit if there aren't any items if(row_count == 0) { setBackupUsage(0); - db->mutex.unlock(); + m_db->mutex.unlock(); return; } @@ -163,8 +163,8 @@ void BackupManagerForm::loadBackupListing(int index) #else horiz_header->setResizeMode(QHeaderView::Stretch); #endif - setBackupUsage(db->getObjectSize(ohfi)); - QString path = db->getAbsolutePath(ohfi); + setBackupUsage(m_db->getObjectSize(ohfi)); + QString path = m_db->getAbsolutePath(ohfi); QList item_list; while(meta) { @@ -228,7 +228,7 @@ void BackupManagerForm::loadBackupListing(int index) } vert_header->setUpdatesEnabled(true); - db->mutex.unlock(); + m_db->mutex.unlock(); // apply filter this->on_filterLineEdit_textChanged(ui->filterLineEdit->text()); diff --git a/src/forms/backupmanagerform.h b/src/forms/backupmanagerform.h index eddeb63..2290fbb 100644 --- a/src/forms/backupmanagerform.h +++ b/src/forms/backupmanagerform.h @@ -20,24 +20,24 @@ #ifndef BACKUPMANAGERFORM_H #define BACKUPMANAGERFORM_H -#include "qlistdb.h" +#include "database.h" #include "backupitem.h" -#include +#include namespace Ui { class BackupManagerForm; } -class BackupManagerForm : public QWidget +class BackupManagerForm : public QDialog { Q_OBJECT public: - explicit BackupManagerForm(QWidget *parent = 0); + explicit BackupManagerForm(Database *db, QWidget *parent = 0); ~BackupManagerForm(); - QListDB *db; + Database *m_db; private: void setupForm(); diff --git a/src/forms/configwidget.cpp b/src/forms/configwidget.cpp index f7ebf24..6f5b14a 100644 --- a/src/forms/configwidget.cpp +++ b/src/forms/configwidget.cpp @@ -83,6 +83,7 @@ void ConfigWidget::setDefaultData() ui->metadataCheck->setChecked(settings.value("skipMetadata", false).toBool()); ui->usbCheck->setChecked(settings.value("disableUSB", false).toBool()); ui->wifiCheck->setChecked(settings.value("disableWireless", false).toBool()); + ui->databaseSelect->setCurrentIndex(settings.value("useMemoryStorage", true).toBool() ? 0 : 1); } ConfigWidget::~ConfigWidget() @@ -154,6 +155,7 @@ void ConfigWidget::accept() settings.setValue("skipMetadata", ui->metadataCheck->isChecked()); settings.setValue("disableUSB", ui->usbCheck->isChecked()); settings.setValue("disableWireless", ui->wifiCheck->isChecked()); + settings.setValue("useMemoryStorage", ui->databaseSelect->currentIndex() == 0); settings.sync(); done(Accepted); diff --git a/src/forms/configwidget.ui b/src/forms/configwidget.ui index 9fe7cc7..08e504f 100644 --- a/src/forms/configwidget.ui +++ b/src/forms/configwidget.ui @@ -282,15 +282,17 @@ - - - false - + In Memory + + + SQLite + + diff --git a/src/mainwidget.cpp b/src/mainwidget.cpp index 35d8088..1e8e494 100644 --- a/src/mainwidget.cpp +++ b/src/mainwidget.cpp @@ -19,9 +19,11 @@ #include "mainwidget.h" #include "cmaclient.h" -#include "cmaevent.h" #include "utils.h" +#include "qlistdb.h" +#include "sqlitedb.h" + #include #include #include @@ -43,7 +45,7 @@ const QStringList MainWidget::path_list = QStringList() << "photoPath" << "music bool sleptOnce = false; MainWidget::MainWidget(QWidget *parent) : - QWidget(parent) + QWidget(parent), db(NULL), configForm(NULL), managerForm(NULL), backupForm(NULL) { } @@ -54,12 +56,12 @@ void MainWidget::checkSettings() foreach(const QString &path, path_list) { if(!settings.contains(path)) { first_run = true; - dialog.show(); + configForm->show(); return; } } first_run = false; - manager.start(); + managerForm->start(); } void MainWidget::dialogResult(int result) @@ -67,7 +69,7 @@ void MainWidget::dialogResult(int result) if(result == QDialog::Accepted) { if(first_run) { first_run = false; - manager.start(); + managerForm->start(); } } else if(first_run) { qApp->quit(); @@ -80,7 +82,7 @@ void MainWidget::stopServer() if(CmaClient::isRunning()) { receiveMessage(tr("Stopping QCMA (disconnect your PS Vita)")); } - manager.stop(); + managerForm->stop(); } void MainWidget::deviceDisconnect() @@ -117,6 +119,16 @@ void MainWidget::deviceConnected(QString message) void MainWidget::prepareApplication() { + //TODO: delete database before exit + if(QSettings().value("useMemoryStorage", true).toBool()) { + db = new QListDB(); + } else { + db = NULL; // new SQLiteDB(); + } + + configForm = new ConfigWidget(this); + backupForm = new BackupManagerForm(db, this); + managerForm = new ClientManager(db, this); connectSignals(); createTrayIcon(); checkSettings(); @@ -124,13 +136,13 @@ void MainWidget::prepareApplication() void MainWidget::connectSignals() { - connect(&dialog, SIGNAL(finished(int)), this, SLOT(dialogResult(int))); - connect(&manager, SIGNAL(stopped()), qApp, SLOT(quit())); - connect(&manager, SIGNAL(deviceConnected(QString)), this, SLOT(deviceConnected(QString))); - connect(&manager, SIGNAL(deviceDisconnected()), this, SLOT(deviceDisconnect())); - connect(&manager, SIGNAL(messageSent(QString)), this, SLOT(receiveMessage(QString))); + connect(configForm, SIGNAL(finished(int)), this, SLOT(dialogResult(int))); + connect(managerForm, SIGNAL(stopped()), qApp, SLOT(quit())); + connect(managerForm, SIGNAL(deviceConnected(QString)), this, SLOT(deviceConnected(QString))); + connect(managerForm, SIGNAL(deviceDisconnected()), this, SLOT(deviceDisconnect())); + connect(managerForm, SIGNAL(messageSent(QString)), this, SLOT(receiveMessage(QString))); - form.db = &manager.db; + //backupForm.db = managerForm.db; } void MainWidget::setTrayTooltip(QString message) @@ -144,8 +156,8 @@ void MainWidget::setTrayTooltip(QString message) void MainWidget::openManager() { - form.loadBackupListing(-1); - form.show(); + backupForm->loadBackupListing(-1); + backupForm->show(); } void MainWidget::showAboutDialog() @@ -186,9 +198,9 @@ void MainWidget::createTrayIcon() about_qt = new QAction(tr("Abou&t Qt"), this); quit = new QAction(tr("&Quit"), this); - connect(options, SIGNAL(triggered()), &dialog, SLOT(open())); + connect(options, SIGNAL(triggered()), configForm, SLOT(open())); connect(backup, SIGNAL(triggered()), this, SLOT(openManager())); - connect(reload, SIGNAL(triggered()), &manager, SLOT(refreshDatabase())); + connect(reload, SIGNAL(triggered()), managerForm, SLOT(refreshDatabase())); connect(about, SIGNAL(triggered()), this, SLOT(showAboutDialog())); connect(about_qt, SIGNAL(triggered()), this, SLOT(showAboutQt())); connect(quit, SIGNAL(triggered()), this, SLOT(stopServer())); diff --git a/src/mainwidget.h b/src/mainwidget.h index 2d0080f..ac80db3 100644 --- a/src/mainwidget.h +++ b/src/mainwidget.h @@ -52,10 +52,13 @@ private: bool first_run; + // database + Database *db; + // forms - ConfigWidget dialog; - ClientManager manager; - BackupManagerForm form; + ConfigWidget *configForm; + ClientManager *managerForm; + BackupManagerForm *backupForm; //system tray QAction *quit; diff --git a/src/qlistdb.cpp b/src/qlistdb.cpp index ef08e70..8b9aa01 100644 --- a/src/qlistdb.cpp +++ b/src/qlistdb.cpp @@ -29,8 +29,7 @@ #include QListDB::QListDB(QObject *parent) : - Database(parent), - mutex(QMutex::Recursive) + Database(parent) { QString uuid = QSettings().value("lastAccountId", "ffffffffffffffff").toString(); CMARootObject::uuid = uuid; diff --git a/src/qlistdb.h b/src/qlistdb.h index 6f32707..9c6298f 100644 --- a/src/qlistdb.h +++ b/src/qlistdb.h @@ -55,8 +55,6 @@ public: bool renameObject(int ohfi, const QString &name); void setObjectSize(int ohfi, qint64 size); - QMutex mutex; - private: typedef struct { QList::const_iterator it; diff --git a/src/sqlitedb.cpp b/src/sqlitedb.cpp index 3ac1592..192a6fe 100644 --- a/src/sqlitedb.cpp +++ b/src/sqlitedb.cpp @@ -275,13 +275,6 @@ int SQLiteDB::recursiveScanRootDirectory(const QString &base_path, int parent, i return total_objects; } -bool SQLiteDB::getObjectMetadata(int ohfi, metadata_t &metadata) -{ - Q_UNUSED(ohfi); - Q_UNUSED(metadata); - return false; -} - int SQLiteDB::getPathId(const QString &path) { QSqlQuery query(QString("SELECT object_id from sources WHERE path = %1").arg(path)); @@ -812,3 +805,70 @@ uint SQLiteDB::insertApplicationEntry(const QString &path, int type, int parent, db.commit(); return ohfi; } + + + +bool SQLiteDB::getObjectMetadata(int ohfi, metadata_t &metadata) +{ + return false; +} + +int SQLiteDB::childObjectCount(int parent_ohfi) +{ + return 0; +} + +bool SQLiteDB::deleteEntry(int ohfi, int root_ohfi) +{ + return false; +} + +int SQLiteDB::getObjectMetadatas(int parent_ohfi, metadata_t **metadata, int index, int max_number) +{ + return 0; +} + +qint64 SQLiteDB::getObjectSize(int ohfi) +{ + return -1; +} + +int SQLiteDB::getPathId(const char *name, int ohfi) +{ + return 0; +} + +int SQLiteDB::insertObjectEntry(const QString &path, int parent_ohfi) +{ + return 0; +} + +QString SQLiteDB::getAbsolutePath(int ohfi) +{ + return NULL; +} + +QString SQLiteDB::getRelativePath(int ohfi) +{ + return NULL; +} + +bool SQLiteDB::renameObject(int ohfi, const QString &name) +{ + return false; +} + +void SQLiteDB::setObjectSize(int ohfi, qint64 size) +{ + +} + +int SQLiteDB::getRootId(int ohfi) +{ + return 0; +} + +int SQLiteDB::getParentId(int ohfi) +{ + return 0; +} diff --git a/src/sqlitedb.h b/src/sqlitedb.h index e78329b..95ccf7f 100644 --- a/src/sqlitedb.h +++ b/src/sqlitedb.h @@ -40,6 +40,20 @@ public: bool initialize(); QSqlError getLastError(); + int childObjectCount(int parent_ohfi); + bool deleteEntry(int ohfi, int root_ohfi = 0); + QString getAbsolutePath(int ohfi); + bool getObjectMetadata(int ohfi, metadata_t &metadata); + int getObjectMetadatas(int parent_ohfi, metadata_t **metadata, int index = 0, int max_number = 0); + qint64 getObjectSize(int ohfi); + int getParentId(int ohfi); + int getPathId(const char *name, int ohfi); + QString getRelativePath(int ohfi); + int getRootId(int ohfi); + int insertObjectEntry(const QString &path, int parent_ohfi); + bool renameObject(int ohfi, const QString &name); + void setObjectSize(int ohfi, qint64 size); + int getPathId(const QString &path); QString getPathFromId(int ohfi); bool updateSize(int ohfi, quint64 size); @@ -53,8 +67,6 @@ public: uint insertSavedataEntry(const QString &path, int type, int parent); uint insertApplicationEntry(const QString &path, int type, int parent, int app_type); - bool getObjectMetadata(int ohfi, metadata_t &metadata); - private: int recursiveScanRootDirectory(const QString &base_path, int parent, int type); uint insertDirectoryEntry(const QString &path, int type, int parent); From 99d216d4748e409593dcfa8d1c96330ab7b961ef Mon Sep 17 00:00:00 2001 From: codestation Date: Wed, 5 Feb 2014 23:30:12 -0430 Subject: [PATCH 7/9] Enable SQLiteDB backend. Multiple fixed and finished the implementation of the SQLite backend. Try to load the database before trying to attempt a rescan. Delete the metadala list for backends that allocate them on demand. Moved some generic functions to the databse class. Renamed utils header to avoid rare QtCreator bug. --- qcma.pro | 12 +- src/avdecoder.cpp | 2 +- src/clientmanager.cpp | 15 +- src/cmaclient.cpp | 2 +- src/cmaevent.cpp | 21 +- src/cmaobject.cpp | 2 +- src/{utils.cpp => cmautils.cpp} | 4 +- src/{utils.h => cmautils.h} | 2 +- src/database.cpp | 28 ++ src/database.h | 34 +- src/forms/backupitem.cpp | 2 +- src/forms/backupmanagerform.cpp | 10 +- src/forms/backupmanagerform.h | 2 +- src/mainwidget.cpp | 5 +- src/qlistdb.cpp | 72 +-- src/qlistdb.h | 29 +- src/sqlitedb.cpp | 819 ++++++++++++++++++++++---------- src/sqlitedb.h | 85 ++-- 18 files changed, 747 insertions(+), 399 deletions(-) rename src/{utils.cpp => cmautils.cpp} (98%) rename src/{utils.h => cmautils.h} (96%) diff --git a/qcma.pro b/qcma.pro index 84cf31c..4adebd9 100644 --- a/qcma.pro +++ b/qcma.pro @@ -20,7 +20,7 @@ SOURCES += src/main.cpp \ src/capability.cpp \ src/cmaobject.cpp \ src/cmarootobject.cpp \ - src/utils.cpp \ + src/cmautils.cpp \ src/mainwidget.cpp \ src/singleapplication.cpp \ src/sforeader.cpp \ @@ -34,20 +34,20 @@ SOURCES += src/main.cpp \ src/sqlitedb.cpp \ src/httpdownloader.cpp \ src/qlistdb.cpp \ + src/database.cpp \ # forms src/forms/backupitem.cpp \ src/forms/backupmanagerform.cpp \ src/forms/configwidget.cpp \ src/forms/confirmdialog.cpp \ src/forms/pinform.cpp \ - src/forms/progressform.cpp \ - src/database.cpp + src/forms/progressform.cpp HEADERS += \ src/capability.h \ src/cmaobject.h \ src/cmarootobject.h \ - src/utils.h \ + src/cmautils.h \ src/mainwidget.h \ src/singleapplication.h \ src/sforeader.h \ @@ -61,14 +61,14 @@ HEADERS += \ src/sqlitedb.h \ src/httpdownloader.h \ src/qlistdb.h \ + src/database.h \ # forms src/forms/backupitem.h \ src/forms/backupmanagerform.h \ src/forms/configwidget.h \ src/forms/confirmdialog.h \ src/forms/pinform.h \ - src/forms/progressform.h \ - src/database.h + src/forms/progressform.h FORMS += \ src/forms/configwidget.ui \ diff --git a/src/avdecoder.cpp b/src/avdecoder.cpp index bcaf1d0..c5b0142 100644 --- a/src/avdecoder.cpp +++ b/src/avdecoder.cpp @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -#include "utils.h" +#include "cmautils.h" #include "avdecoder.h" #include "database.h" diff --git a/src/clientmanager.cpp b/src/clientmanager.cpp index 395fb47..7cce9d9 100644 --- a/src/clientmanager.cpp +++ b/src/clientmanager.cpp @@ -19,7 +19,7 @@ #include "clientmanager.h" #include "cmaclient.h" -#include "utils.h" +#include "cmautils.h" #include "forms/progressform.h" #include @@ -122,13 +122,12 @@ void ClientManager::start() void ClientManager::refreshDatabase() { - bool prepared; - if(!m_db->reload(prepared)) { - if(prepared) { - emit messageSent(tr("Cannot refresh the database while is in use")); - } else { - emit messageSent(tr("No PS Vita system has been registered")); - } + if(m_db->load()) { + return; + } + + if(!m_db->rescan()) { + emit messageSent(tr("No PS Vita system has been registered")); } else { progress.showDelayed(1000); } diff --git a/src/cmaclient.cpp b/src/cmaclient.cpp index 1a4b23f..b843230 100644 --- a/src/cmaclient.cpp +++ b/src/cmaclient.cpp @@ -21,7 +21,7 @@ #include "capability.h" #include "avdecoder.h" #include "cmaevent.h" -#include "utils.h" +#include "cmautils.h" #include #include diff --git a/src/cmaevent.cpp b/src/cmaevent.cpp index d9c8f08..d504b67 100644 --- a/src/cmaevent.cpp +++ b/src/cmaevent.cpp @@ -18,7 +18,7 @@ */ #include "cmaevent.h" -#include "utils.h" +#include "cmautils.h" #include #include @@ -179,7 +179,8 @@ quint16 CmaEvent::processAllObjects(metadata_t &parent_metadata, quint32 handle) m_db->deleteEntry(ohfi); } - QDir dir(m_db->getAbsolutePath(parent_metadata.ohfi)); + QString fullpath = m_db->getAbsolutePath(parent_metadata.ohfi); + QDir dir(fullpath); if(dataType & Folder) { if(!dir.mkpath(name)) { @@ -205,12 +206,10 @@ quint16 CmaEvent::processAllObjects(metadata_t &parent_metadata, quint32 handle) } } - QFileInfo info(dir, name); - int new_ohfi = m_db->insertObjectEntry(info.absoluteFilePath(), parent_metadata.ohfi); + int new_ohfi = m_db->insertObjectEntry(fullpath, name, parent_metadata.ohfi); + qDebug("Added object %s with OHFI %i to database", name, new_ohfi); free(name); - qDebug() << QString("Added object %1 with OHFI %2 to database").arg(info.absoluteFilePath(), QString::number(new_ohfi)); - if(dataType & Folder) { metadata_t folder_metadata; m_db->getObjectMetadata(new_ohfi, folder_metadata); @@ -389,6 +388,7 @@ void CmaEvent::vitaEventSendObjectMetadata(vita_event_t *event, int eventId) } else { VitaMTP_ReportResult(device, eventId, PTP_RC_OK); } + m_db->freeMetadata(meta); } void CmaEvent::vitaEventSendObject(vita_event_t *event, int eventId) @@ -470,6 +470,8 @@ void CmaEvent::vitaEventSendObject(vita_event_t *event, int eventId) } while(metadata && metadata->ohfiParent >= OHFI_BASE_VALUE); // get everything under this "folder" + m_db->freeMetadata(start); + VitaMTP_ReportResultWithParam(device, eventId, PTP_RC_OK, handle); VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_Data); // TODO: Send thumbnail @@ -562,13 +564,14 @@ void CmaEvent::vitaEventSendObjectStatus(vita_event_t *event, int eventId) QMutexLocker locker(&m_db->mutex); + qDebug("Checking for path %s under ohfi %i", objectstatus.title, objectstatus.ohfiRoot); int ohfi = m_db->getPathId(objectstatus.title, objectstatus.ohfiRoot); if(ohfi == 0) { // not in database, don't return metadata qDebug("Object %s not in database (OHFI: %i). Sending OK response for non-existence", objectstatus.title, objectstatus.ohfiRoot); VitaMTP_ReportResult(device, eventId, PTP_RC_OK); } else { - metadata_t metadata; + metadata_t metadata = metadata_t(); m_db->getObjectMetadata(ohfi, metadata); metadata.next_metadata = NULL; qDebug("Sending metadata for OHFI %d", ohfi); @@ -780,7 +783,7 @@ void CmaEvent::vitaEventOperateObject(vita_event_t *event, int eventId) qWarning("Unable to create temporary folder: %s", operateobject.title); VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Failed_Operate_Object); } else { - int new_ohfi = m_db->insertObjectEntry(QDir(dir).absoluteFilePath(operateobject.title), operateobject.ohfi); + int new_ohfi = m_db->insertObjectEntry(fullpath, operateobject.title, operateobject.ohfi); qDebug("Created folder %s with OHFI %d", operateobject.title, new_ohfi); VitaMTP_ReportResultWithParam(device, eventId, PTP_RC_OK, new_ohfi); } @@ -794,7 +797,7 @@ void CmaEvent::vitaEventOperateObject(vita_event_t *event, int eventId) qWarning("Unable to create temporary file: %s", operateobject.title); VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Failed_Operate_Object); } else { - int new_ohfi = m_db->insertObjectEntry(file.fileName(), operateobject.ohfi); + int new_ohfi = m_db->insertObjectEntry(fullpath, operateobject.title, operateobject.ohfi); //qDebug("Created file %s with OHFI %d under parent %s", newobj->metadata.path, new_ohfi, root->metadata.path); VitaMTP_ReportResultWithParam(device, eventId, PTP_RC_OK, new_ohfi); } diff --git a/src/cmaobject.cpp b/src/cmaobject.cpp index 68856a9..6e0a3fc 100644 --- a/src/cmaobject.cpp +++ b/src/cmaobject.cpp @@ -21,7 +21,7 @@ #include "sforeader.h" #include "avdecoder.h" #include "database.h" -#include "utils.h" +#include "cmautils.h" #include #include diff --git a/src/utils.cpp b/src/cmautils.cpp similarity index 98% rename from src/utils.cpp rename to src/cmautils.cpp index 3e1680b..0275180 100644 --- a/src/utils.cpp +++ b/src/cmautils.cpp @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -#include "utils.h" +#include "cmautils.h" #include "avdecoder.h" #include @@ -162,7 +162,7 @@ QByteArray getThumbnail(const QString &path, DataType type, metadata_t *metadata return data; } -QString readable_size(quint64 size, bool use_gib) +QString readable_size(qint64 size, bool use_gib) { QStringList list; list << "KiB" << "MiB"; diff --git a/src/utils.h b/src/cmautils.h similarity index 96% rename from src/utils.h rename to src/cmautils.h index 35f690f..a69af6d 100644 --- a/src/utils.h +++ b/src/cmautils.h @@ -46,7 +46,7 @@ public: #endif bool removeRecursively(const QString &path); -QString readable_size(quint64 size, bool use_gib = false); +QString readable_size(qint64 size, bool use_gib = false); bool getDiskSpace(const QString &dir, quint64 *free, quint64 *total); QByteArray getThumbnail(const QString &path, DataType type, metadata_t *metadata); diff --git a/src/database.cpp b/src/database.cpp index c9785c2..2d415c9 100644 --- a/src/database.cpp +++ b/src/database.cpp @@ -2,6 +2,7 @@ #include "avdecoder.h" #include +#include const file_type audio_list[] = { {"mp3", FILE_FORMAT_MP3, CODEC_TYPE_MP3}, @@ -28,6 +29,33 @@ Database::Database(QObject *parent) : mutex(QMutex::Recursive) { } +#include +void Database::process() +{ + qDebug("Starting database_thread: 0x%016" PRIxPTR, (uintptr_t)QThread::currentThreadId()); + clear(); + cancel_operation = false; + int count = create(); + cancel_operation = false; + qDebug("Added %i entries to the database", count); + if(count < 0) { + clear(); + } + emit updated(count); + mutex.unlock(); +} + +void Database::cancelOperation() +{ + QMutexLocker locker(&cancel); + cancel_operation = true; +} + +bool Database::continueOperation() +{ + QMutexLocker locker(&cancel); + return !cancel_operation; +} int Database::checkFileType(const QString path, int ohfi_root) { diff --git a/src/database.h b/src/database.h index 0f1851f..95b98f9 100644 --- a/src/database.h +++ b/src/database.h @@ -43,6 +43,11 @@ class Database : public QObject Q_OBJECT public: explicit Database(QObject *parent = 0); + + virtual bool load() = 0; + virtual bool rescan() = 0; + virtual void setUUID(const QString &uuid) = 0; + virtual int childObjectCount(int parent_ohfi) = 0; virtual bool deleteEntry(int ohfi, int root_ohfi = 0) = 0; virtual QString getAbsolutePath(int ohfi) = 0; @@ -51,14 +56,12 @@ public: virtual int getObjectMetadatas(int parent_ohfi, metadata_t **metadata, int index = 0, int max_number = 0) = 0; virtual qint64 getObjectSize(int ohfi) = 0; virtual int getPathId(const char *name, int ohfi) = 0; - virtual int insertObjectEntry(const QString &path, int parent_ohfi) = 0; + virtual int insertObjectEntry(const QString &path, const QString &name, int parent_ohfi) = 0; virtual bool renameObject(int ohfi, const QString &name) = 0; virtual void setObjectSize(int ohfi, qint64 size) = 0; virtual int getParentId(int ohfi) = 0; virtual int getRootId(int ohfi) = 0; - - virtual bool reload(bool &prepared) = 0; - virtual void setUUID(const QString uuid) = 0; + virtual void freeMetadata(metadata_t *metadata) = 0; static int checkFileType(const QString path, int ohfi_root); static void loadMusicMetadata(const QString &path, metadata_t &metadata); @@ -66,6 +69,29 @@ public: static void loadVideoMetadata(const QString &path, metadata_t &metadata); QMutex mutex; + +protected: + bool continueOperation(); + +private: + + virtual void clear() = 0; + virtual int create() = 0; + + // control variables + QMutex cancel; + bool cancel_operation; + +signals: + void fileAdded(QString); + void directoryAdded(QString); + void updated(int); + +protected slots: + void process(); + +public slots: + void cancelOperation(); }; #endif // DATABASE_H diff --git a/src/forms/backupitem.cpp b/src/forms/backupitem.cpp index 3cb6198..8257ffb 100644 --- a/src/forms/backupitem.cpp +++ b/src/forms/backupitem.cpp @@ -19,7 +19,7 @@ #include "backupitem.h" #include "ui_backupitem.h" -#include "utils.h" +#include "cmautils.h" #include "dds.h" #include diff --git a/src/forms/backupmanagerform.cpp b/src/forms/backupmanagerform.cpp index e8ec4e3..3f83244 100644 --- a/src/forms/backupmanagerform.cpp +++ b/src/forms/backupmanagerform.cpp @@ -22,7 +22,7 @@ #include "cmaobject.h" #include "sforeader.h" #include "confirmdialog.h" -#include "utils.h" +#include "cmautils.h" #include "filterlineedit.h" #include @@ -83,7 +83,7 @@ void BackupManagerForm::removeEntry(BackupItem *item) } } -void BackupManagerForm::setBackupUsage(quint64 size) +void BackupManagerForm::setBackupUsage(qint64 size) { ui->usageLabel->setText(tr("Backup disk usage: %1").arg(readable_size(size, true))); } @@ -163,10 +163,12 @@ void BackupManagerForm::loadBackupListing(int index) #else horiz_header->setResizeMode(QHeaderView::Stretch); #endif - setBackupUsage(m_db->getObjectSize(ohfi)); + qint64 backup_size = m_db->getObjectSize(ohfi); + setBackupUsage(backup_size); QString path = m_db->getAbsolutePath(ohfi); QList item_list; + metadata_t *first = meta; while(meta) { QString base_path = path + QDir::separator() + meta->name; QString parent_path = sys_dir ? base_path + QDir::separator() + "sce_sys" : base_path; @@ -215,6 +217,8 @@ void BackupManagerForm::loadBackupListing(int index) meta = meta->next_metadata; } + m_db->freeMetadata(first); + qSort(item_list.begin(), item_list.end(), BackupItem::lessThan); int row; diff --git a/src/forms/backupmanagerform.h b/src/forms/backupmanagerform.h index 2290fbb..2613df3 100644 --- a/src/forms/backupmanagerform.h +++ b/src/forms/backupmanagerform.h @@ -41,7 +41,7 @@ public: private: void setupForm(); - void setBackupUsage(quint64 size); + void setBackupUsage(qint64 size); Ui::BackupManagerForm *ui; diff --git a/src/mainwidget.cpp b/src/mainwidget.cpp index 1e8e494..e6c178e 100644 --- a/src/mainwidget.cpp +++ b/src/mainwidget.cpp @@ -19,7 +19,7 @@ #include "mainwidget.h" #include "cmaclient.h" -#include "utils.h" +#include "cmautils.h" #include "qlistdb.h" #include "sqlitedb.h" @@ -123,7 +123,7 @@ void MainWidget::prepareApplication() if(QSettings().value("useMemoryStorage", true).toBool()) { db = new QListDB(); } else { - db = NULL; // new SQLiteDB(); + db = new SQLiteDB(); } configForm = new ConfigWidget(this); @@ -267,4 +267,5 @@ MainWidget::~MainWidget() #ifndef ENABLE_KDE_NOTIFIER trayIcon->hide(); #endif + delete db; } diff --git a/src/qlistdb.cpp b/src/qlistdb.cpp index 8b9aa01..b698551 100644 --- a/src/qlistdb.cpp +++ b/src/qlistdb.cpp @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -#include "utils.h" +#include "cmautils.h" #include "qlistdb.h" #include "cmaobject.h" @@ -34,8 +34,8 @@ QListDB::QListDB(QObject *parent) : QString uuid = QSettings().value("lastAccountId", "ffffffffffffffff").toString(); CMARootObject::uuid = uuid; thread = new QThread(); - timer = new QTimer(); moveToThread(thread); + timer = new QTimer(); thread->start(); timer->setInterval(0); @@ -45,7 +45,7 @@ QListDB::QListDB(QObject *parent) : QListDB::~QListDB() { - destroy(); + clear(); timer->stop(); delete timer; thread->quit(); @@ -53,53 +53,41 @@ QListDB::~QListDB() delete thread; } -void QListDB::setUUID(const QString uuid) +void QListDB::setUUID(const QString &uuid) { CMARootObject::uuid = uuid; QSettings().setValue("lastAccountId", uuid); } -bool QListDB::reload(bool &prepared) +bool QListDB::load() { - if(mutex.tryLock()) { + // not implemented + return false; +} + +bool QListDB::rescan() +{ + if(mutex.tryLock(1000)) { if(CMARootObject::uuid != "ffffffffffffffff") { timer->start(); - prepared = true; + return true; } else { mutex.unlock(); - prepared = false; return false; } - return true; - } else { - return false; } + return false; } -void QListDB::process() +void QListDB::clear() { - destroy(); - cancel_operation = false; - int count = create(); - cancel_operation = false; - qDebug("Added %i entries to the database", count); - if(count < 0) { - destroy(); + for(map_list::iterator root = object_list.begin(); root != object_list.end(); ++root) { + CMARootObject *first = static_cast((*root).takeFirst()); + delete first; + qDeleteAll(*root); } - emit updated(count); - mutex.unlock(); -} -void QListDB::cancelOperation() -{ - QMutexLocker locker(&cancel); - cancel_operation = true; -} - -bool QListDB::continueOperation() -{ - QMutexLocker locker(&cancel); - return !cancel_operation; + object_list.clear(); } int QListDB::create() @@ -147,6 +135,8 @@ int QListDB::create() return -1; } + qDebug("Added %i objects for OHFI %#02X", dir_count, ohfi_array[i]); + total_objects += dir_count; object_list[ohfi_array[i]] = list; } @@ -236,19 +226,6 @@ int QListDB::recursiveScanRootDirectory(root_list &list, CMAObject *parent, int return total_objects; } -void QListDB::destroy() -{ - //QMutexLocker locker(&mutex); - - for(map_list::iterator root = object_list.begin(); root != object_list.end(); ++root) { - CMARootObject *first = static_cast((*root).takeFirst()); - delete first; - qDeleteAll(*root); - } - - object_list.clear(); -} - bool QListDB::removeInternal(root_list &list, int ohfi) { bool found = false; @@ -487,7 +464,7 @@ int QListDB::getPathId(const char *name, int ohfi) return 0; } -int QListDB::insertObjectEntry(const QString &path, int parent_ohfi) +int QListDB::insertObjectEntry(const QString &path, const QString &name, int parent_ohfi) { QMutexLocker locker(&mutex); @@ -505,7 +482,8 @@ int QListDB::insertObjectEntry(const QString &path, int parent_ohfi) parent_obj = parent_obj->parent; } - newobj->initObject(path, parent_obj->metadata.dataType); + QFileInfo info(path, name); + newobj->initObject(info, parent_obj->metadata.dataType); cat_list->append(newobj); return newobj->metadata.ohfi; } diff --git a/src/qlistdb.h b/src/qlistdb.h index 9c6298f..da45c86 100644 --- a/src/qlistdb.h +++ b/src/qlistdb.h @@ -38,8 +38,13 @@ public: explicit QListDB(QObject *parent = 0); ~QListDB(); + bool load(); + bool rescan(); + void close(); + void clear(); + bool reload(bool &prepared); - void setUUID(const QString uuid); + void setUUID(const QString &uuid); int childObjectCount(int parent_ohfi); bool deleteEntry(int ohfi, int root_ohfi = 0); @@ -51,9 +56,12 @@ public: int getPathId(const char *name, int ohfi); QString getRelativePath(int ohfi); int getRootId(int ohfi); - int insertObjectEntry(const QString &path, int parent_ohfi); + int insertObjectEntry(const QString &path, const QString &name, int parent_ohfi); bool renameObject(int ohfi, const QString &name); void setObjectSize(int ohfi, qint64 size); + void freeMetadata(metadata_t *metadata) { + Q_UNUSED(metadata); + } private: typedef struct { @@ -65,7 +73,6 @@ private: typedef QMap map_list; int create(); - void destroy(); int scanRootDirectory(root_list &list,int ohfi_type); int recursiveScanRootDirectory(root_list &list, CMAObject *parent, int ohfi_type); bool hasFilter(const CMARootObject *object,int ohfi); @@ -78,26 +85,10 @@ private: bool find(int ohfi, find_data &data); int acceptFilteredObject(const CMAObject *parent, const CMAObject *current, int type); CMAObject *ohfiToObject(int ohfi); - bool continueOperation(); - - // control variables - QMutex cancel; - bool cancel_operation; QTimer *timer; QThread *thread; map_list object_list; - -signals: - void fileAdded(QString); - void directoryAdded(QString); - void updated(int); - -protected slots: - void process(); - -public slots: - void cancelOperation(); }; #endif // QLISTDB_H diff --git a/src/sqlitedb.cpp b/src/sqlitedb.cpp index 192a6fe..162dc04 100644 --- a/src/sqlitedb.cpp +++ b/src/sqlitedb.cpp @@ -1,4 +1,23 @@ -#include "utils.h" +/* + * QCMA: Cross-platform content manager assistant for the PS Vita + * + * Copyright (C) 2014 Codestation + * + * 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 3 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, see . + */ + +#include "cmautils.h" #include "sqlitedb.h" #include "sforeader.h" #include "avdecoder.h" @@ -26,13 +45,14 @@ static const char create_adjacent[] = "CREATE TABLE IF NOT EXISTS adjacent_objec static const char create_obj_node[] = "CREATE TABLE IF NOT EXISTS object_node (" "object_id INTEGER PRIMARY KEY AUTOINCREMENT," "type INTEGER NOT NULL," + "data_type INTEGER NOT NULL," "title TEXT," "child_count INTEGER NOT NULL DEFAULT 0," "reference_count INTEGER NOT NULL DEFAULT 0);"; static const char create_sources[] = "CREATE TABLE IF NOT EXISTS sources (" "object_id INTEGER PRIMARY KEY REFERENCES object_node(object_id) ON DELETE CASCADE," - "path TEXT UNIQUE NOT NULL CHECK (LENGTH(path) > 0)," + "path TEXT NOT NULL CHECK (LENGTH(path) > 0)," "size INTEGER," "date_created TIMESTAMP," "date_modified TIMESTAMP)"; @@ -114,19 +134,23 @@ static const char *trigger_list[] = { create_trigger_node, create_trigger_adjins, create_trigger_adjdel }; +static const int ohfi_array[] = { VITA_OHFI_MUSIC, VITA_OHFI_PHOTO, VITA_OHFI_VIDEO, + VITA_OHFI_BACKUP, VITA_OHFI_VITAAPP, VITA_OHFI_PSPAPP, + VITA_OHFI_PSPSAVE, VITA_OHFI_PSXAPP, VITA_OHFI_PSMAPP + }; + SQLiteDB::SQLiteDB(QObject *parent) : Database(parent) { uuid = QSettings().value("lastAccountId", "ffffffffffffffff").toString(); -} + thread = new QThread(); + moveToThread(thread); + timer = new QTimer(); + thread->start(); + timer->setInterval(0); + timer->setSingleShot(true); + connect(timer, SIGNAL(timeout()), this, SLOT(process())); -SQLiteDB::~SQLiteDB() -{ - db.close(); -} - -bool SQLiteDB::open() -{ // fetch a configured database path if it exists QString db_path = QStandardPaths::writableLocation(QStandardPaths::DataLocation); db_path = QSettings().value("databasePath", db_path).toString(); @@ -134,24 +158,66 @@ bool SQLiteDB::open() db = QSqlDatabase::addDatabase("QSQLITE"); db.setDatabaseName(db_path + QDir::separator() + "qcma.sqlite"); - - return db.open(); } -void SQLiteDB::remove() +SQLiteDB::~SQLiteDB() { + db.close(); + timer->stop(); + delete timer; + thread->quit(); + thread->wait(); + delete thread; +} + + +void SQLiteDB::setUUID(const QString &uuid) +{ + this->uuid = uuid; + QSettings().setValue("lastAccountId", uuid); +} + +bool SQLiteDB::load() +{ + bool success = false; + + if(db.open()) { + qDebug() << "Database created/registered"; + success = !initialize(); + } else { + const QSqlError error = db.lastError(); + qWarning() << "Error opening connection to the database:" << error.text(); + } + + return success; +} + +bool SQLiteDB::rescan() +{ + if(mutex.tryLock(1000)) { + if(uuid != "ffffffffffffffff") { + timer->start(); + return true; + } else { + mutex.unlock(); + return false; + } + } + return false; +} + +void SQLiteDB::clear() +{ + db.close(); + //QSqlDatabase::removeDatabase("QSQLITE"); QString db_path = QStandardPaths::writableLocation(QStandardPaths::DataLocation); db_path = QSettings().value("databasePath", db_path).toString(); - QDir(QDir::root()).mkpath(db_path); - QFile(db_path + QDir::separator() + "qcma.sqlite").remove(); + load(); } bool SQLiteDB::initialize() { - if (!db.isOpen()) { - return false; - } QSqlQuery query; for(unsigned int i = 0; i < sizeof(table_list) / sizeof(const char *); i++) { @@ -169,7 +235,7 @@ bool SQLiteDB::initialize() } // force object_id to start at 256 - if(query.exec("INSERT INTO object_node (object_id, type) VALUES (255, 0)")) { + if(query.exec("INSERT INTO object_node (object_id, data_type, type) VALUES (255, 0, 0)")) { query.exec("DELETE FROM object_node WHERE object_id = 255"); } return true; @@ -184,97 +250,160 @@ int SQLiteDB::create() { int total_objects = 0; - const int ohfi_array[] = { VITA_OHFI_MUSIC, VITA_OHFI_VIDEO, VITA_OHFI_PHOTO, - VITA_OHFI_BACKUP, VITA_OHFI_VITAAPP, VITA_OHFI_PSPAPP, - VITA_OHFI_PSPSAVE, VITA_OHFI_PSXAPP, VITA_OHFI_PSMAPP - }; - - QSettings settings; - QString base_path; - + db.transaction(); for(int i = 0, max = sizeof(ohfi_array) / sizeof(int); i < max; i++) { - switch(ohfi_array[i]) { - case VITA_OHFI_MUSIC: - base_path = settings.value("musicPath").toString(); - break; - case VITA_OHFI_VIDEO: - base_path = settings.value("videoPath").toString(); - break; - case VITA_OHFI_PHOTO: - base_path = settings.value("photoPath").toString(); - break; - case VITA_OHFI_BACKUP: - base_path = settings.value("appsPath").toString() + QDir::separator() + "SYSTEM" + QDir::separator() + uuid; - break; - case VITA_OHFI_VITAAPP: - base_path = settings.value("appsPath").toString() + QDir::separator() + "APP" + QDir::separator() + uuid; - break; - case VITA_OHFI_PSPAPP: - base_path = settings.value("appsPath").toString() + QDir::separator() + "PGAME" + QDir::separator() + uuid; - break; - case VITA_OHFI_PSPSAVE: - base_path = settings.value("appsPath").toString() + QDir::separator() + "PSAVEDATA" + QDir::separator() + uuid; - break; - case VITA_OHFI_PSXAPP: - base_path = settings.value("appsPath").toString() + QDir::separator() + "PSGAME" + QDir::separator() + uuid; - break; - case VITA_OHFI_PSMAPP: - base_path = settings.value("appsPath").toString() + QDir::separator() + "PSM" + QDir::separator() + uuid; - break; - } - - int dir_count = recursiveScanRootDirectory(base_path, ohfi_array[i], ohfi_array[i]); + QString base_path = getBasePath(ohfi_array[i]); + int dir_count = recursiveScanRootDirectory(base_path, NULL, ohfi_array[i], ohfi_array[i]); if(dir_count < 0) { + db.rollback(); return -1; } + + //qDebug("Added %i objects for OHFI %#02X", dir_count, ohfi_array[i]); + total_objects += dir_count; } + db.commit(); return total_objects; } -int SQLiteDB::recursiveScanRootDirectory(const QString &base_path, int parent, int parent_type) +QString SQLiteDB::getBasePath(int root_ohfi) +{ + QString base_path; + QSettings settings; + + switch(root_ohfi) { + case VITA_OHFI_MUSIC: + base_path = settings.value("musicPath").toString(); + break; + case VITA_OHFI_VIDEO: + base_path = settings.value("videoPath").toString(); + break; + case VITA_OHFI_PHOTO: + base_path = settings.value("photoPath").toString(); + break; + case VITA_OHFI_BACKUP: + base_path = settings.value("appsPath").toString() + "/SYSTEM/" + uuid; + break; + case VITA_OHFI_VITAAPP: + base_path = settings.value("appsPath").toString() + "/APP/" + uuid; + break; + case VITA_OHFI_PSPAPP: + base_path = settings.value("appsPath").toString() + "/PGAME/" + uuid; + break; + case VITA_OHFI_PSPSAVE: + base_path = settings.value("appsPath").toString() + "/PSAVEDATA/" + uuid; + break; + case VITA_OHFI_PSXAPP: + base_path = settings.value("appsPath").toString() + "/PSGAME/" + uuid; + break; + case VITA_OHFI_PSMAPP: + base_path = settings.value("appsPath").toString() + "/PSM/" + uuid; + break; + } + return base_path; +} + +int SQLiteDB::recursiveScanRootDirectory(const QString &base_path, const QString &rel_path, int parent_ohfi, int root_ohfi) { int total_objects = 0; - QDir dir(base_path); + QDir dir(base_path + "/" + rel_path); dir.setSorting(QDir::Name); QFileInfoList qsl = dir.entryInfoList(QDir::AllEntries | QDir::NoDotAndDotDot); foreach(const QFileInfo &info, qsl) { - //qDebug() << "Processing " << info.fileName(); - if(info.isDir()) { - int ohfi = insertDirectoryEntry(info.absoluteFilePath(), parent_type, parent); - total_objects += recursiveScanRootDirectory(info.absoluteFilePath(), ohfi, parent_type); - } else if(info.isFile()) { - switch(parent_type) { - case VITA_OHFI_MUSIC: - insertMusicEntry(info.absoluteFilePath(), OBJECT_MUSIC | (parent_type & ~OBJECT_FOLDER), parent); - break; - case VITA_OHFI_PHOTO: - insertPhotoEntry(info.absoluteFilePath(), OBJECT_PHOTO | (parent_type & ~OBJECT_FOLDER), parent); - break; - case VITA_OHFI_VIDEO: - insertVideoEntry(info.absoluteFilePath(), OBJECT_VIDEO | (parent_type & ~OBJECT_FOLDER), parent); - break; - case VITA_OHFI_PSPSAVE: - insertSavedataEntry(info.absoluteFilePath(), OBJECT_SAVEDATA | (parent_type & ~OBJECT_FOLDER), parent); - break; - case VITA_OHFI_VITAAPP: - case VITA_OHFI_PSPAPP: - case VITA_OHFI_PSXAPP: - case VITA_OHFI_PSMAPP: - case VITA_OHFI_BACKUP: - insertApplicationEntry(info.absoluteFilePath(), OBJECT_APPLICATION | (parent_type & ~OBJECT_FOLDER), parent, parent_type); - } - total_objects++; + if(!continueOperation()) { + return -1; + } + + //qDebug() << "Processing " << info.fileName(); + + QString rel_name = rel_path.isNull() ? info.fileName() : rel_path + "/" + info.fileName(); + + int ohfi = insertObjectEntryInternal(base_path, rel_name, parent_ohfi, root_ohfi); + + if(ohfi > 0) { + // update progress dialog + if(info.isDir()) { + emit directoryAdded(base_path + "/" + rel_name); + total_objects += recursiveScanRootDirectory(base_path, rel_name, ohfi, root_ohfi); + qint64 dirsize = getChildenTotalSize(ohfi); + setObjectSize(ohfi, dirsize); + } else if(info.isFile()) { + emit fileAdded(info.fileName()); + total_objects++; + } } } return total_objects; } +int SQLiteDB::insertObjectEntry(const QString &path, const QString &name, int parent_ohfi) +{ + int ohfi; + int type; + + if((type = getObjectType(parent_ohfi)) == 0) { + return 0; + } + db.transaction(); + if((ohfi = insertObjectEntryInternal(path, name, parent_ohfi, type)) == 0) { + db.rollback(); + } + db.commit(); + + return ohfi; +} + +int SQLiteDB::insertObjectEntryInternal(const QString &path, const QString &name, int parent_ohfi, int root_ohfi) +{ + int ohfi; + QFileInfo info(path, name); + + if(info.isDir()) { + ohfi = insertDefaultEntry(path, name, info.fileName(), parent_ohfi, Folder); + } else { + ohfi = insertFileEntry(path, name, parent_ohfi, root_ohfi); + } + + return ohfi; +} + +int SQLiteDB::insertFileEntry(const QString &path, const QString &name, int parent_ohfi, int root_ohfi) +{ + int ohfi = 0; + + switch(root_ohfi) { + case VITA_OHFI_MUSIC: + ohfi = insertMusicEntry(path, name, parent_ohfi, File | Music); + break; + case VITA_OHFI_PHOTO: + ohfi = insertPhotoEntry(path, name, parent_ohfi, File | Photo); + break; + case VITA_OHFI_VIDEO: + ohfi = insertVideoEntry(path, name, parent_ohfi, File | Video); + break; + case VITA_OHFI_PSPSAVE: + ohfi = insertSavedataEntry(path, name, parent_ohfi, File | SaveData); + break; + case VITA_OHFI_VITAAPP: + case VITA_OHFI_PSPAPP: + case VITA_OHFI_PSXAPP: + case VITA_OHFI_PSMAPP: + case VITA_OHFI_BACKUP: + ohfi = insertApplicationEntry(path, name, parent_ohfi, File | App, root_ohfi); + break; + default: + qFatal("Invalid parent type"); + } + + return ohfi; +} + int SQLiteDB::getPathId(const QString &path) { QSqlQuery query(QString("SELECT object_id from sources WHERE path = %1").arg(path)); @@ -313,12 +442,6 @@ bool SQLiteDB::deleteEntry(int ohfi) return ret; } -bool SQLiteDB::deleteEntry(const QString &path) -{ - QSqlQuery query(QString("DELETE FROM object_node WHERE object_id == (SELECT object_id FROM sources WHERE path == %1)").arg(path)); - return query.exec(); -} - bool SQLiteDB::updateAdjacencyList(int ohfi, int parent) { QSqlQuery query; @@ -328,8 +451,6 @@ bool SQLiteDB::updateAdjacencyList(int ohfi, int parent) if(query.exec() && query.next()) { return true; - } else { - qDebug() << query.lastError(); } query.prepare("INSERT INTO adjacent_objects (parent_id, child_id)" @@ -343,67 +464,61 @@ bool SQLiteDB::updateAdjacencyList(int ohfi, int parent) return ret; } -uint SQLiteDB::insertDirectoryEntry(const QString &path, int type, int parent) +int SQLiteDB::insertDefaultEntry(const QString &path, const QString &name, const QString &title, int parent, int type) { - uint ohfi; - db.transaction(); - QString dirname = QFileInfo(path).fileName(); + int ohfi = 0; - if((ohfi = insertObjectEntry(dirname.toUtf8().constData(), type)) == 0) { - db.rollback(); + if((ohfi = insertNodeEntry(title, VITA_DIR_TYPE_MASK_REGULAR, type)) == 0) { return 0; } if(parent && !updateAdjacencyList(ohfi, parent)) { - db.rollback(); return 0; } - if(!insertSourceEntry(ohfi, path)) { - db.rollback(); + if(!name.isNull() && !insertSourceEntry(ohfi, path, name)) { return 0; } - db.commit(); return ohfi; } -uint SQLiteDB::insertObjectEntry(const char *title, int type) +int SQLiteDB::insertNodeEntry(const QString &title, int type, int data_type) { QSqlQuery query; - //query.prepare("SELECT object_id FROM object_node WHERE type == :type and title == :title"); - //query.bindValue(0, type); - //query.bindValue(1, title); - - //if(!query.exec() || !query.next()) { - query.prepare("INSERT INTO object_node (type, title) VALUES (:type, :title)"); + query.prepare("INSERT INTO object_node (type, data_type, title) VALUES (:type, :data_type, :title)"); query.bindValue(0, type); - query.bindValue(1, title); + query.bindValue(1, data_type); + query.bindValue(2, title); if(!query.exec() || !query.exec("SELECT last_insert_rowid()") || !query.next()) { qDebug() << query.lastError(); return 0; } - //} return query.value(0).toInt(); } -bool SQLiteDB::insertSourceEntry(uint object_id, const QString &path) +bool SQLiteDB::insertSourceEntry(uint object_id, const QString &path, const QString &name) { - qint64 size; - uint date_created, date_modified; + QVariant size, date_created, date_modified; - QFileInfo info(path); - size = info.size(); - date_created = info.created().toTime_t(); - date_modified = info.lastModified().toTime_t(); + QFileInfo info(path, name); + if(info.isFile()) { + size = QVariant(info.size()); + date_created = QVariant(info.created().toTime_t()); + } else { + size = QVariant(QVariant::LongLong); + date_created = QVariant(QVariant::UInt); + } + + date_modified = QVariant(info.lastModified().toTime_t()); QSqlQuery query; query.prepare("REPLACE INTO sources (object_id, path, size, date_created, date_modified)" "VALUES (:object_id, :path, :size, :date_created, :date_modified)"); query.bindValue(0, object_id); - query.bindValue(1, path); + query.bindValue(1, name); query.bindValue(2, size); query.bindValue(3, date_created); query.bindValue(4, date_modified); @@ -414,22 +529,22 @@ bool SQLiteDB::insertSourceEntry(uint object_id, const QString &path) return ret; } -uint SQLiteDB::insertMusicEntry(const QString &path, int type, int parent) +uint SQLiteDB::insertMusicEntry(const QString &path, const QString &name, int parent, int type) { bool ok; - uint ohfi; + int ohfi; AVDecoder decoder; quint64 duration; const char *artist, *album, *albumartist, *genre, *track, *title; int file_format, audio_codec, audio_bitrate, genre_id, artist_id, track_id, album_id, track_number; - int file_type = checkFileType(path, VITA_OHFI_MUSIC); + int file_type = checkFileType(name, VITA_OHFI_MUSIC); if(file_type < 0) { - qDebug() << "Excluding from database:" << path; + //qDebug() << "Excluding from database:" << path; return 0; } - if(!decoder.open(path)) { + if(!decoder.open(path + "/" + name)) { return 0; } @@ -456,30 +571,16 @@ uint SQLiteDB::insertMusicEntry(const QString &path, int type, int parent) file_format = audio_list[file_type].file_format; audio_codec = audio_list[file_type].file_codec; - QByteArray basename = QFileInfo(path).baseName().toUtf8(); + QByteArray basename = QFileInfo(name).baseName().toUtf8(); title = decoder.getMetadataEntry("title", basename.constData()); - db.transaction(); - - if((ohfi = insertObjectEntry(title, type)) == 0) { - db.rollback(); - return 0; - } - - if(parent && !updateAdjacencyList(ohfi, parent)) { - db.rollback(); - return 0; - } - - if(!insertSourceEntry(ohfi, path)) { - db.rollback(); + if((ohfi = insertDefaultEntry(path, name, title, parent, type)) == 0) { return 0; } if(genre) { - genre_id = insertObjectEntry(genre, type | OBJECT_GENRE); + genre_id = insertNodeEntry(genre, VITA_DIR_TYPE_MASK_GENRES, type); if(!updateAdjacencyList(ohfi, genre_id)) { - db.rollback(); return 0; } } else { @@ -487,9 +588,8 @@ uint SQLiteDB::insertMusicEntry(const QString &path, int type, int parent) } if(artist) { - track_id = insertObjectEntry(artist, type | OBJECT_ARTIST); + track_id = insertNodeEntry(artist, VITA_DIR_TYPE_MASK_ARTISTS, type); if(!updateAdjacencyList(ohfi, track_id)) { - db.rollback(); return 0; } } else { @@ -497,9 +597,8 @@ uint SQLiteDB::insertMusicEntry(const QString &path, int type, int parent) } if(albumartist) { - artist_id = insertObjectEntry(albumartist, type | OBJECT_ALBUM_ARTIST); + artist_id = insertNodeEntry(albumartist, VITA_DIR_TYPE_MASK_REGULAR, type); if(!updateAdjacencyList(ohfi, artist_id)) { - db.rollback(); return 0; } } else { @@ -507,18 +606,15 @@ uint SQLiteDB::insertMusicEntry(const QString &path, int type, int parent) } if(album) { - album_id = insertObjectEntry(album, type | OBJECT_ALBUM); + album_id = insertNodeEntry(album, VITA_DIR_TYPE_MASK_ALBUMS, type); if(track_id && !updateAdjacencyList(ohfi, album_id)) { - db.rollback(); return 0; } if(track_id && !updateAdjacencyList(album_id, track_id)) { - db.rollback(); return 0; } if(artist_id && !updateAdjacencyList(album_id, artist_id)) { - db.rollback(); return 0; } } else { @@ -544,15 +640,13 @@ uint SQLiteDB::insertMusicEntry(const QString &path, int type, int parent) query.bindValue(11, track_number); if(!query.exec()) { - db.rollback(); return 0; } - db.commit(); return ohfi; } -uint SQLiteDB::insertVideoEntry(const QString &path, int type, int parent) +uint SQLiteDB::insertVideoEntry(const QString &path, const QString &name, int parent, int type) { int ohfi; AVDecoder decoder; @@ -560,13 +654,13 @@ uint SQLiteDB::insertVideoEntry(const QString &path, int type, int parent) int file_format, parental_level, width, height, video_codec, video_bitrate, audio_codec, audio_bitrate; const char *explanation, *copyright, *title; - if(!decoder.open(path) || !decoder.loadCodec(AVDecoder::CODEC_VIDEO)) { + if(!decoder.open(path + "/" + name) || !decoder.loadCodec(AVDecoder::CODEC_VIDEO)) { return 0; } - int file_type = checkFileType(path, VITA_OHFI_VIDEO); + int file_type = checkFileType(name, VITA_OHFI_VIDEO); if(file_type < 0) { - qDebug() << "Excluding from database:" << path; + //qDebug() << "Excluding from database:" << path; return 0; } @@ -588,24 +682,12 @@ uint SQLiteDB::insertVideoEntry(const QString &path, int type, int parent) audio_bitrate = 0; } - QByteArray basename = QFileInfo(path).baseName().toUtf8(); + QByteArray basename = QFileInfo(name).baseName().toUtf8(); //title = decoder.getMetadataEntry("title", basename.constData()); title = basename.constData(); - db.transaction(); - if((ohfi = insertObjectEntry(title, type)) == 0) { - db.rollback(); - return 0; - } - - if(parent && !updateAdjacencyList(ohfi, parent)) { - db.rollback(); - return 0; - } - - if(!insertSourceEntry(ohfi, path)) { - db.rollback(); + if((ohfi = insertDefaultEntry(path, name, title, parent, type)) == 0) { return 0; } @@ -629,53 +711,38 @@ uint SQLiteDB::insertVideoEntry(const QString &path, int type, int parent) if(!query.exec()) { qDebug() << query.lastError().text(); - db.rollback(); return 0; } - db.commit(); return ohfi; } -uint SQLiteDB::insertPhotoEntry(const QString &path, int type, int parent) +uint SQLiteDB::insertPhotoEntry(const QString &path, const QString &name, int parent, int type) { int ohfi; QImage img; uint date_created; int width, height, file_format, photo_codec; - int file_type = checkFileType(path, VITA_OHFI_PHOTO); + int file_type = checkFileType(name, VITA_OHFI_PHOTO); if(file_type < 0) { - qDebug() << "Excluding from database:" << path; + //qDebug() << "Excluding from database:" << path; return 0; } - if(!img.load(path)) { + if(!img.load(path + "/" + name)) { return 0; } - date_created = QFileInfo(path).created().toTime_t(); + date_created = QFileInfo(path + "/" + name).created().toTime_t(); width = img.width(); height = img.height(); file_format = photo_list[file_type].file_format; photo_codec = photo_list[file_type].file_codec; - QByteArray basename = QFileInfo(path).baseName().toUtf8(); + QByteArray basename = QFileInfo(name).baseName().toUtf8(); - db.transaction(); - - if((ohfi = insertObjectEntry(basename.constData(), type)) == 0) { - db.rollback(); - return 0; - } - - if(parent && !updateAdjacencyList(ohfi, parent)) { - db.rollback(); - return 0; - } - - if(!insertSourceEntry(ohfi, path)) { - db.rollback(); + if((ohfi = insertDefaultEntry(path, name, basename, parent, type)) == 0) { return 0; } @@ -692,15 +759,13 @@ uint SQLiteDB::insertPhotoEntry(const QString &path, int type, int parent) query.bindValue(5, height); if(!query.exec()) { - db.rollback(); return 0; } - db.commit(); return ohfi; } -uint SQLiteDB::insertSavedataEntry(const QString &path, int type, int parent) +uint SQLiteDB::insertSavedataEntry(const QString &path, const QString &name, int parent, int type) { int ohfi; SfoReader reader; @@ -709,39 +774,22 @@ uint SQLiteDB::insertSavedataEntry(const QString &path, int type, int parent) const char *savedata_detail = NULL; const char *savedata_directory = NULL; - QString file_name = QFileInfo(path).fileName(); + QString file_name = QFileInfo(name).fileName(); QByteArray utf8name = file_name.toUtf8(); - db.transaction(); - - if(file_name.endsWith(".sfo", Qt::CaseInsensitive) && reader.load(path)) { + if(file_name.endsWith(".sfo", Qt::CaseInsensitive) && reader.load(path + "/" + name)) { title = reader.value("TITLE", utf8name.constData()); savedata_detail = reader.value("SAVEDATA_DETAIL", ""); savedata_directory = reader.value("SAVEDATA_DIRECTORY", utf8name.constData()); - date_updated = QFileInfo(path).lastModified().toTime_t(); + date_updated = QFileInfo(path + "/" + name).lastModified().toTime_t(); } - if((ohfi = insertObjectEntry(title, type)) == 0) { - db.rollback(); - return 0; - } - - if(parent && !updateAdjacencyList(ohfi, parent)) { - db.rollback(); - return 0; - } - - if(!insertSourceEntry(ohfi, path)) { - db.rollback(); - return 0; - } - - if(!path.endsWith(".sfo", Qt::CaseInsensitive)) { + if((ohfi = insertDefaultEntry(path, name, title, parent, type)) == 0) { return 0; } if(!title) { - return 0; + return ohfi; } QSqlQuery query; @@ -756,36 +804,31 @@ uint SQLiteDB::insertSavedataEntry(const QString &path, int type, int parent) query.bindValue(4, date_updated); if(!query.exec()) { - db.rollback(); return 0; } - db.commit(); return ohfi; } -uint SQLiteDB::insertApplicationEntry(const QString &path, int type, int parent, int app_type) +uint SQLiteDB::insertApplicationEntry(const QString &path, const QString &name, int parent, int type, int app_type) { int ohfi; + QString title_id; - QString base_name = QFileInfo(path).baseName(); + if(name.endsWith(".sfo", Qt::CaseInsensitive)) { + QDir curdir(path + "/" + name); + if(curdir.cdUp() && curdir.cdUp()) { + title_id = QFileInfo(curdir.absolutePath()).fileName(); + } + } - db.transaction(); - - if((ohfi = insertObjectEntry(base_name.toUtf8().constData(), type)) == 0) { - db.rollback(); + if((ohfi = insertDefaultEntry(path, name, QFileInfo(name).fileName(), parent, type)) == 0) { return 0; } - if(parent && !updateAdjacencyList(ohfi, parent)) { - db.rollback(); - return 0; - } - - if(!insertSourceEntry(ohfi, path)) { - db.rollback(); - return 0; + if(title_id.isNull()) { + return ohfi; } QSqlQuery query; @@ -794,81 +837,341 @@ uint SQLiteDB::insertApplicationEntry(const QString &path, int type, int parent, "VALUES (:object_id, :title, :app_type)"); query.bindValue(0, ohfi); - query.bindValue(1, base_name); + query.bindValue(1, title_id); query.bindValue(2, app_type); if(!query.exec()) { - db.rollback(); return 0; } - db.commit(); return ohfi; } - - -bool SQLiteDB::getObjectMetadata(int ohfi, metadata_t &metadata) -{ - return false; -} - int SQLiteDB::childObjectCount(int parent_ohfi) { - return 0; + QSqlQuery query; + query.prepare("SELECT count(child_id) FROM adjacent_objects WHERE parent_id = :object_id"); + query.bindValue(0, parent_ohfi); + if(!query.exec() || !query.next()) { + qDebug() << query.lastError(); + return -1; + } else { + return query.value(0).toInt(); + } } bool SQLiteDB::deleteEntry(int ohfi, int root_ohfi) { - return false; + Q_UNUSED(root_ohfi); + qDebug("Deleting node: %i", ohfi); + + QSqlQuery source_query("DELETE FROM sources WHERE object_id = :object_id"); + source_query.bindValue(0, ohfi); + + db.transaction(); + if(!source_query.exec()) { + db.rollback(); + return false; + } + + QSqlQuery object_query("DELETE FROM object_node WHERE object_id = :object_id"); + object_query.bindValue(0, ohfi); + if(!object_query.exec()) { + db.rollback(); + return false; + } + + db.commit(); + return true; +} + +void SQLiteDB::fillMetadata(const QSqlQuery &query, metadata_t &metadata) +{ + metadata.ohfi = query.value("ohfi").toInt(); + metadata.ohfiParent = query.value("parent").toInt(); + metadata.name = strdup(query.value("name").toByteArray().constData()); + metadata.path = strdup(query.value("path").toByteArray().constData()); + metadata.type = VITA_DIR_TYPE_MASK_REGULAR; + metadata.dataType = (DataType)query.value("data_type").toInt(); + metadata.size = query.value("size").toULongLong(); + metadata.dateTimeCreated = query.value("date_created").toInt(); + metadata.next_metadata = NULL; +} + +bool SQLiteDB::getObjectMetadata(int ohfi, metadata_t &metadata) +{ + QSqlQuery query( + "SELECT " + "t0.object_id as ohfi," + "t1.parent_id as parent," + "t2.path as path," + "t0.title as name," + "t0.type as type," + "t0.data_type as data_type," + "t2.size as size," + "t2.date_created as date_created " + "FROM object_node t0 " + "JOIN adjacent_objects t1 ON t1.child_id = t0.object_id " + "JOIN sources t2 ON t2.object_id = t0.object_id " + "WHERE t0.object_id = :object_id"); + query.bindValue(0, ohfi); + + if(query.exec() && query.next()) { + fillMetadata(query, metadata); + return true; + } else { + qDebug() << query.lastError(); + return false; + } } int SQLiteDB::getObjectMetadatas(int parent_ohfi, metadata_t **metadata, int index, int max_number) { - return 0; + if(metadata == NULL) { + return childObjectCount(parent_ohfi); + } + + int count = 0; + QString query_str( + "SELECT " + "t0.child_id as ohfi," + "t0.parent_id as parent," + "t2.path as path," + "t1.title as name," + "t1.type as type," + "t1.data_type as data_type," + "t2.size as size," + "t2.date_created as date_created " + "FROM adjacent_objects t0 " + "JOIN object_node t1 ON t0.child_id = t1.object_id " + "JOIN sources t2 ON t0.child_id = t2.object_id " + "WHERE t0.parent_id = :parent_id "); + + if(max_number > 0) { + query_str += "LIMIT :limit OFFSET :offset"; + } + + QSqlQuery query(query_str); + query.bindValue(0, parent_ohfi); + + if(max_number > 0) { + query.bindValue(1, max_number); + query.bindValue(2, index); + } + + if(query.exec()) { + metadata_t **last = &*metadata; + while(query.next()) { + metadata_t *meta = new metadata_t(); + fillMetadata(query, *meta); + *last = meta; + last = &meta->next_metadata; + count++; + } + } else { + qDebug() << query.lastError(); + } + return count; } qint64 SQLiteDB::getObjectSize(int ohfi) { - return -1; + if(ohfi < OHFI_BASE_VALUE) { + return getChildenTotalSize(ohfi); + } + + QSqlQuery query; + query.prepare("SELECT size FROM sources WHERE object_id = :object_id"); + query.bindValue(0, ohfi); + if(!query.exec() || !query.next()) { + qDebug() << query.lastError(); + return -1; + } else { + return query.value(0).toInt(); + } } int SQLiteDB::getPathId(const char *name, int ohfi) { - return 0; -} + //FIXME: use ohfi to filter by category + Q_UNUSED(ohfi); + QSqlQuery query; -int SQLiteDB::insertObjectEntry(const QString &path, int parent_ohfi) -{ - return 0; + query.prepare("SELECT object_id FROM sources WHERE path = :path"); + query.bindValue(0, name); + if(!query.exec() || !query.next()) { + qDebug() << query.lastError(); + return 0; + } else { + return query.value(0).toInt(); + } } QString SQLiteDB::getAbsolutePath(int ohfi) { - return NULL; + int root_ohfi = ohfi < OHFI_BASE_VALUE ? ohfi : getRootId(ohfi); + QString base_path = getBasePath(root_ohfi); + QString rel_path = getRelativePath(ohfi); + return rel_path.isNull() ? base_path : base_path + "/" + rel_path; } QString SQLiteDB::getRelativePath(int ohfi) { - return NULL; + QSqlQuery query; + query.prepare("SELECT path FROM sources WHERE object_id = :object_id"); + query.bindValue(0, ohfi); + if(!query.exec() || !query.next()) { + qDebug() << query.lastError(); + return NULL; + } else { + return query.value(0).toString(); + } +} + +bool SQLiteDB::updateObjectPath(int ohfi, const QString &name) +{ + int parent_ohfi = getParentId(ohfi); + QString parent_path, file; + + if(name.isNull()) { + QSqlQuery name_query("SELECT title FROM object_node WHERE object_id = :object_id"); + name_query.bindValue(0, ohfi); + if(!name_query.exec() || !name_query.next()) { + return false; + } + file = name_query.value(0).toString(); + } else { + file = name; + } + + if(parent_ohfi >= OHFI_BASE_VALUE) { + parent_path = getRelativePath(parent_ohfi); + if(parent_path.isNull()) { + parent_path = file; + } else { + parent_path += "/" + file; + } + } else { + parent_path = file; + } + + QSqlQuery query("UPDATE sources SET path = :path WHERE object_id = :object_id"); + query.bindValue(0, parent_path); + query.bindValue(1, ohfi); + + if(!query.exec()) { + return false; + } + + DataType type = (DataType)getObjectType(ohfi); + + if(type & Folder) { + QSqlQuery child_query("SELECT child_id, data_type FROM adjacent_objects " + "JOIN object_node ON object_id = child_id" + "WHERE parent_id = :parent_id"); + child_query.bindValue(0, ohfi); + + if(query.exec()) { + while(query.next()) { + int child_ohfi = query.value(0).toInt(); + if(!updateObjectPath(child_ohfi, NULL)) { + return false; + } + } + } + } + + return true; } bool SQLiteDB::renameObject(int ohfi, const QString &name) { - return false; + QSqlQuery query("UPDATE object_node SET title = :title WHERE object_id = :object_id"); + query.bindValue(0, name); + query.bindValue(1, ohfi); + + if(!query.exec()) { + return false; + } + + return updateObjectPath(ohfi, name); } void SQLiteDB::setObjectSize(int ohfi, qint64 size) { + QSqlQuery query; + query.prepare("UPDATE sources SET size = :size WHERE object_id = :object_id"); + query.bindValue(0, size); + query.bindValue(1, ohfi); + if(!query.exec()) { + qDebug() << query.lastError(); + } +} +qint64 SQLiteDB::getChildenTotalSize(int ohfi) +{ + QSqlQuery query; + query.prepare("SELECT SUM(t0.size) FROM sources t0 " + "JOIN adjacent_objects t1 ON t0.object_id = t1.child_id " + "where t1.parent_id = :parent_id"); + query.bindValue(0, ohfi); + if(!query.exec() || !query.next()) { + qDebug() << query.lastError(); + return -1; + } else { + return query.value(0).toLongLong(); + } } int SQLiteDB::getRootId(int ohfi) { - return 0; + QSqlQuery query; + int root_ohfi = ohfi; + + query.prepare("SELECT parent_id FROM adjacent_objects WHERE child_id = :child_id"); + while(root_ohfi >= OHFI_BASE_VALUE) { + query.bindValue(0, root_ohfi); + if(!query.exec() || !query.next()) { + qDebug() << query.lastError(); + root_ohfi = 0; + } else { + root_ohfi = query.value(0).toInt(); + } + } + return root_ohfi; +} + +int SQLiteDB::getObjectType(int ohfi) +{ + QSqlQuery query; + query.prepare("SELECT type FROM object_node WHERE object_id = :object_id"); + query.bindValue(0, ohfi); + if(!query.exec() || !query.next()) { + qDebug() << query.lastError(); + return 0; + } else { + return query.value(0).toInt(); + } } int SQLiteDB::getParentId(int ohfi) { - return 0; + QSqlQuery query; + query.prepare("SELECT parent_id FROM adjacent_objects WHERE child_id = :child_id"); + query.bindValue(0, ohfi); + if(!query.exec() || !query.next()) { + qDebug() << query.lastError(); + return 0; + } else { + return query.value(0).toInt(); + } +} + +void SQLiteDB::freeMetadata(metadata_t *metadata) +{ + while(metadata) { + metadata_t *current = metadata; + metadata = metadata->next_metadata; + delete current; + } } diff --git a/src/sqlitedb.h b/src/sqlitedb.h index 95ccf7f..c45cdf9 100644 --- a/src/sqlitedb.h +++ b/src/sqlitedb.h @@ -1,3 +1,22 @@ +/* + * QCMA: Cross-platform content manager assistant for the PS Vita + * + * Copyright (C) 2014 Codestation + * + * 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 3 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, see . + */ + #ifndef SQLITEDB_H #define SQLITEDB_H @@ -5,27 +24,11 @@ #include +#include #include #include #include - -#define OBJECT_FILE 0x10000000 -#define OBJECT_FOLDER 0x20000000 -#define OBJECT_SPECIAL 0x40000000 - -#define OBJECT_MUSIC 0x00000100 -#define OBJECT_PHOTO 0x00000200 -#define OBJECT_VIDEO 0x00000400 - -#define OBJECT_ALBUM 0x00000002 -#define OBJECT_ARTIST 0x00000005 -#define OBJECT_ALBUM_ARTIST 0x00000008 -#define OBJECT_GENRE 0x0000000B - -#define OBJECT_SAVEDATA 0x00040000 -#define OBJECT_SAVEDATA_FILE 0x00000002 - -#define OBJECT_APPLICATION 0x00080000 +#include class SQLiteDB : public Database { @@ -34,9 +37,16 @@ public: explicit SQLiteDB(QObject *parent = 0); ~SQLiteDB(); + bool load(); + bool rescan(); + void close(); + + bool reload(bool &prepared); + void setUUID(const QString &uuid); + bool open(); int create(); - void remove(); + void clear(); bool initialize(); QSqlError getLastError(); @@ -50,35 +60,40 @@ public: int getPathId(const char *name, int ohfi); QString getRelativePath(int ohfi); int getRootId(int ohfi); - int insertObjectEntry(const QString &path, int parent_ohfi); + int insertObjectEntry(const QString &path, const QString &name, int parent_ohfi); bool renameObject(int ohfi, const QString &name); void setObjectSize(int ohfi, qint64 size); + void freeMetadata(metadata_t *metadata); int getPathId(const QString &path); QString getPathFromId(int ohfi); bool updateSize(int ohfi, quint64 size); bool deleteEntry(int ohfi); - bool deleteEntry(const QString &path); - uint insertObjectEntry(const char *title, int type); - bool insertSourceEntry(uint object_id, const QString &path); - uint insertMusicEntry(const QString &path, int type, int parent); - uint insertVideoEntry(const QString &path, int type, int parent); - uint insertPhotoEntry(const QString &path, int type, int parent); - uint insertSavedataEntry(const QString &path, int type, int parent); - uint insertApplicationEntry(const QString &path, int type, int parent, int app_type); + bool insertSourceEntry(uint object_id, const QString &path, const QString &name); + uint insertMusicEntry(const QString &path, const QString &name, int parent, int type); + uint insertVideoEntry(const QString &path, const QString &name, int parent, int type); + uint insertPhotoEntry(const QString &path, const QString &name, int parent, int type); + uint insertSavedataEntry(const QString &path, const QString &name, int parent, int type); + uint insertApplicationEntry(const QString &path, const QString &name, int parent, int type, int app_type); private: - int recursiveScanRootDirectory(const QString &base_path, int parent, int type); - uint insertDirectoryEntry(const QString &path, int type, int parent); + int recursiveScanRootDirectory(const QString &base_path, const QString &rel_path, int parent_ohfi, int root_ohfi); + int insertObjectEntryInternal(const QString &path, const QString &name, int parent_ohfi, int type); + int insertDefaultEntry(const QString &path, const QString &name, const QString &title, int parent, int type); + int insertNodeEntry(const QString &title, int type, int data_type); bool updateAdjacencyList(int ohfi, int parent); + QString getBasePath(int root_ohfi); + int insertFileEntry(const QString &path, const QString &name, int parent, int parent_type); + int getObjectType(int ohfi); + void fillMetadata(const QSqlQuery &query, metadata_t &metadata); + qint64 getChildenTotalSize(int ohfi); + bool updateObjectPath(int ohfi, const QString &name); + + QTimer *timer; + QThread *thread; QString uuid; QSqlDatabase db; - -signals: - -public slots: - }; #endif // SQLITEDB_H From ae8657325af78c769ac843a527436c345e51d0e5 Mon Sep 17 00:00:00 2001 From: codestation Date: Tue, 25 Feb 2014 09:18:49 -0430 Subject: [PATCH 8/9] Create virtual node table to store category nodes (doesn't exist on the filesystem but need an OHFI). Enable triggers, disable sync mode and other tweaks so the creation of the database can be faster. Abort early if a database entry cannot be added. Fix games and savedatas not being saved with their correct parent id. Preparing getRootItems to return virtual categories. Code refactoring. --- src/sqlitedb.cpp | 202 +++++++++++++++++++++++++++++------------------ src/sqlitedb.h | 4 +- 2 files changed, 127 insertions(+), 79 deletions(-) diff --git a/src/sqlitedb.cpp b/src/sqlitedb.cpp index 162dc04..31fe34a 100644 --- a/src/sqlitedb.cpp +++ b/src/sqlitedb.cpp @@ -76,9 +76,15 @@ static const char create_apps[] = "CREATE TABLE IF NOT EXISTS application (" "title TEXT NOT NULL CHECK (LENGTH(title) > 0)," "app_type INTEGER)"; +static const char create_virtual[] = "CREATE TABLE IF NOT EXISTS virtual_nodes (" + "object_id INTEGER PRIMARY KEY REFERENCES object_node(object_id) ON DELETE CASCADE," + "title TEXT NOT NULL CHECK (LENGTH(title) > 0)," + "app_type INTEGER)"; + static const char create_photos[] = "CREATE TABLE IF NOT EXISTS photos (" "object_id INTEGER PRIMARY KEY REFERENCES object_node(object_id) ON DELETE CASCADE," "date_created TIMESTAMP," + "month_created TEXT," "file_format INTEGER," "photo_codec INTEGER," "width INTEGER," @@ -127,7 +133,7 @@ static const char create_trigger_adjdel[] = "CREATE TRIGGER IF NOT EXISTS trg_ad static const char *table_list[] = { create_adjacent, create_obj_node, create_sources, - create_music, create_photos, create_videos, create_savedata, create_apps + create_music, create_photos, create_videos, create_savedata, create_apps, create_virtual }; static const char *trigger_list[] = { @@ -182,6 +188,14 @@ bool SQLiteDB::load() bool success = false; if(db.open()) { + QSqlQuery query; + query.exec("PRAGMA foreign_keys = ON"); + query.exec("PRAGMA synchronous = OFF"); + query.exec("PRAGMA user_version = 1"); + query.exec("PRAGMA journal_mode = MEMORY"); + query.exec("PRAGMA recursive_triggers = true"); + query.exec("PRAGMA vacuum_db.synchronous = OFF"); + qDebug() << "Database created/registered"; success = !initialize(); } else { @@ -329,7 +343,12 @@ int SQLiteDB::recursiveScanRootDirectory(const QString &base_path, const QString // update progress dialog if(info.isDir()) { emit directoryAdded(base_path + "/" + rel_name); - total_objects += recursiveScanRootDirectory(base_path, rel_name, ohfi, root_ohfi); + int inserted = recursiveScanRootDirectory(base_path, rel_name, ohfi, root_ohfi); + if(inserted < 0) { + return -1; + } + + total_objects += inserted; qint64 dirsize = getChildenTotalSize(ohfi); setObjectSize(ohfi, dirsize); } else if(info.isFile()) { @@ -366,43 +385,39 @@ int SQLiteDB::insertObjectEntryInternal(const QString &path, const QString &name if(info.isDir()) { ohfi = insertDefaultEntry(path, name, info.fileName(), parent_ohfi, Folder); + switch(parent_ohfi) { + case VITA_OHFI_VITAAPP: + case VITA_OHFI_PSPAPP: + case VITA_OHFI_PSXAPP: + case VITA_OHFI_PSMAPP: + case VITA_OHFI_BACKUP: + insertApplicationEntry(name, ohfi, parent_ohfi); + } } else { - ohfi = insertFileEntry(path, name, parent_ohfi, root_ohfi); + switch(root_ohfi) { + case VITA_OHFI_MUSIC: + ohfi = insertMusicEntry(path, name, parent_ohfi, File | Music); + break; + case VITA_OHFI_PHOTO: + ohfi = insertPhotoEntry(path, name, parent_ohfi, File | Photo); + break; + case VITA_OHFI_VIDEO: + ohfi = insertVideoEntry(path, name, parent_ohfi, File | Video); + break; + case VITA_OHFI_PSPSAVE: + ohfi = insertSavedataEntry(path, name, parent_ohfi, File | SaveData); + break; + case VITA_OHFI_VITAAPP: + case VITA_OHFI_PSPAPP: + case VITA_OHFI_PSXAPP: + case VITA_OHFI_PSMAPP: + case VITA_OHFI_BACKUP: + ohfi = insertDefaultEntry(path, name, info.fileName(), parent_ohfi, File | App); + } } - return ohfi; } -int SQLiteDB::insertFileEntry(const QString &path, const QString &name, int parent_ohfi, int root_ohfi) -{ - int ohfi = 0; - - switch(root_ohfi) { - case VITA_OHFI_MUSIC: - ohfi = insertMusicEntry(path, name, parent_ohfi, File | Music); - break; - case VITA_OHFI_PHOTO: - ohfi = insertPhotoEntry(path, name, parent_ohfi, File | Photo); - break; - case VITA_OHFI_VIDEO: - ohfi = insertVideoEntry(path, name, parent_ohfi, File | Video); - break; - case VITA_OHFI_PSPSAVE: - ohfi = insertSavedataEntry(path, name, parent_ohfi, File | SaveData); - break; - case VITA_OHFI_VITAAPP: - case VITA_OHFI_PSPAPP: - case VITA_OHFI_PSXAPP: - case VITA_OHFI_PSMAPP: - case VITA_OHFI_BACKUP: - ohfi = insertApplicationEntry(path, name, parent_ohfi, File | App, root_ohfi); - break; - default: - qFatal("Invalid parent type"); - } - - return ohfi; -} int SQLiteDB::getPathId(const QString &path) { @@ -472,7 +487,7 @@ int SQLiteDB::insertDefaultEntry(const QString &path, const QString &name, const return 0; } - if(parent && !updateAdjacencyList(ohfi, parent)) { + if(parent >= OHFI_BASE_VALUE && !updateAdjacencyList(ohfi, parent)) { return 0; } @@ -734,7 +749,10 @@ uint SQLiteDB::insertPhotoEntry(const QString &path, const QString &name, int pa return 0; } - date_created = QFileInfo(path + "/" + name).created().toTime_t(); + QDateTime date = QFileInfo(path + "/" + name).created(); + date_created = date.toTime_t(); + QString month_created = date.toString("yyyy/MM"); + width = img.width(); height = img.height(); file_format = photo_list[file_type].file_format; @@ -748,8 +766,8 @@ uint SQLiteDB::insertPhotoEntry(const QString &path, const QString &name, int pa QSqlQuery query; query.prepare("REPLACE INTO photos" - "(object_id, date_created, file_format, photo_codec, width, height)" - "VALUES (:object_id, :date_created, :file_format, :photo_codec, :width, :height)"); + "(object_id, date_created, file_format, photo_codec, width, height, month_created)" + "VALUES (:object_id, :date_created, :file_format, :photo_codec, :width, :height, :month_created)"); query.bindValue(0, ohfi); query.bindValue(1, date_created); @@ -757,6 +775,7 @@ uint SQLiteDB::insertPhotoEntry(const QString &path, const QString &name, int pa query.bindValue(3, photo_codec); query.bindValue(4, width); query.bindValue(5, height); + query.bindValue(6, month_created); if(!query.exec()) { return 0; @@ -797,7 +816,7 @@ uint SQLiteDB::insertSavedataEntry(const QString &path, const QString &name, int "(object_id, detail, dir_name, title, date_updated)" "VALUES (:object_id, :detail, :dir_name, :title, :updated)"); - query.bindValue(0, ohfi); + query.bindValue(0, parent); query.bindValue(1, savedata_detail); query.bindValue(2, savedata_directory); query.bindValue(3, title); @@ -811,25 +830,9 @@ uint SQLiteDB::insertSavedataEntry(const QString &path, const QString &name, int } -uint SQLiteDB::insertApplicationEntry(const QString &path, const QString &name, int parent, int type, int app_type) +bool SQLiteDB::insertApplicationEntry(const QString &name, int ohfi, int app_type) { - int ohfi; - QString title_id; - - if(name.endsWith(".sfo", Qt::CaseInsensitive)) { - QDir curdir(path + "/" + name); - if(curdir.cdUp() && curdir.cdUp()) { - title_id = QFileInfo(curdir.absolutePath()).fileName(); - } - } - - if((ohfi = insertDefaultEntry(path, name, QFileInfo(name).fileName(), parent, type)) == 0) { - return 0; - } - - if(title_id.isNull()) { - return ohfi; - } + QString title_id = QFileInfo(name).fileName(); QSqlQuery query; query.prepare("REPLACE INTO application" @@ -841,10 +844,10 @@ uint SQLiteDB::insertApplicationEntry(const QString &path, const QString &name, query.bindValue(2, app_type); if(!query.exec()) { - return 0; + return false; } - return ohfi; + return true; } int SQLiteDB::childObjectCount(int parent_ohfi) @@ -865,24 +868,9 @@ bool SQLiteDB::deleteEntry(int ohfi, int root_ohfi) Q_UNUSED(root_ohfi); qDebug("Deleting node: %i", ohfi); - QSqlQuery source_query("DELETE FROM sources WHERE object_id = :object_id"); - source_query.bindValue(0, ohfi); - - db.transaction(); - if(!source_query.exec()) { - db.rollback(); - return false; - } - - QSqlQuery object_query("DELETE FROM object_node WHERE object_id = :object_id"); - object_query.bindValue(0, ohfi); - if(!object_query.exec()) { - db.rollback(); - return false; - } - - db.commit(); - return true; + QSqlQuery query("DELETE FROM object_node WHERE object_id = :object_id"); + query.bindValue(0, ohfi); + return query.exec(); } void SQLiteDB::fillMetadata(const QSqlQuery &query, metadata_t &metadata) @@ -896,6 +884,7 @@ void SQLiteDB::fillMetadata(const QSqlQuery &query, metadata_t &metadata) metadata.size = query.value("size").toULongLong(); metadata.dateTimeCreated = query.value("date_created").toInt(); metadata.next_metadata = NULL; + //TODO: fill the rest of the metadata } bool SQLiteDB::getObjectMetadata(int ohfi, metadata_t &metadata) @@ -931,6 +920,10 @@ int SQLiteDB::getObjectMetadatas(int parent_ohfi, metadata_t **metadata, int ind return childObjectCount(parent_ohfi); } + if(parent_ohfi < OHFI_BASE_VALUE) { + return getRootItems(parent_ohfi, metadata); + } + int count = 0; QString query_str( "SELECT " @@ -1175,3 +1168,58 @@ void SQLiteDB::freeMetadata(metadata_t *metadata) delete current; } } + +int SQLiteDB::getRootItems(int root_ohfi, metadata_t **metadata) +{ + QSqlQuery query; + int count = 0; + + switch(root_ohfi) { + case VITA_OHFI_MUSIC: + //query = QSqlQuery("SELECT * FROM music"); + break; + case VITA_OHFI_PHOTO: + //query = QSqlQuery("SELECT * FROM photos"); + break; + case VITA_OHFI_VIDEO: + //query = QSqlQuery("SELECT * FROM videos"); + break; + case VITA_OHFI_PSPSAVE: + //query = QSqlQuery("SELECT * FROM savedata"); + break; + case VITA_OHFI_VITAAPP: + case VITA_OHFI_PSPAPP: + case VITA_OHFI_PSXAPP: + case VITA_OHFI_PSMAPP: + case VITA_OHFI_BACKUP: + query = QSqlQuery("SELECT " + "t0.object_id as ohfi," + ":app_type as parent," + "t3.path as path," + "t0.title as name," + "t1.type as type," + "t1.data_type as data_type," + "t3.size as size," + "t3.date_created as date_created " + "FROM application t0 " + "JOIN object_node t1 on t0.object_id = t1.object_id " + "JOIN sources t3 ON t3.object_id = t0.object_id " + "WHERE app_type = :app_type"); + query.bindValue(0, root_ohfi); + if(query.exec()) { + metadata_t **last = &*metadata; + while(query.next()) { + metadata_t *meta = new metadata_t(); + fillMetadata(query, *meta); + *last = meta; + last = &meta->next_metadata; + count++; + } + } + break; + default: + qFatal("Invalid root ohfi type"); + } + + return count; +} diff --git a/src/sqlitedb.h b/src/sqlitedb.h index c45cdf9..8841a60 100644 --- a/src/sqlitedb.h +++ b/src/sqlitedb.h @@ -74,7 +74,7 @@ public: uint insertVideoEntry(const QString &path, const QString &name, int parent, int type); uint insertPhotoEntry(const QString &path, const QString &name, int parent, int type); uint insertSavedataEntry(const QString &path, const QString &name, int parent, int type); - uint insertApplicationEntry(const QString &path, const QString &name, int parent, int type, int app_type); + bool insertApplicationEntry(const QString &name, int ohfi, int app_type); private: int recursiveScanRootDirectory(const QString &base_path, const QString &rel_path, int parent_ohfi, int root_ohfi); @@ -83,11 +83,11 @@ private: int insertNodeEntry(const QString &title, int type, int data_type); bool updateAdjacencyList(int ohfi, int parent); QString getBasePath(int root_ohfi); - int insertFileEntry(const QString &path, const QString &name, int parent, int parent_type); int getObjectType(int ohfi); void fillMetadata(const QSqlQuery &query, metadata_t &metadata); qint64 getChildenTotalSize(int ohfi); bool updateObjectPath(int ohfi, const QString &name); + int getRootItems(int root_ohfi, metadata_t **metadata); QTimer *timer; QThread *thread; From 6ed8dd749e466c3164e49fc5375c3e664131c208 Mon Sep 17 00:00:00 2001 From: codestation Date: Sat, 22 Mar 2014 13:58:39 -0430 Subject: [PATCH 9/9] Added functions to create virtual entries on the database. Disabled sqlite setting in config dialog. --- src/database.cpp | 2 +- src/forms/configwidget.ui | 3 ++ src/qlistdb.cpp | 2 +- src/sqlitedb.cpp | 77 ++++++++++++++++++++++++++++++++++++++- src/sqlitedb.h | 2 + 5 files changed, 83 insertions(+), 3 deletions(-) diff --git a/src/database.cpp b/src/database.cpp index 2d415c9..ec6a33a 100644 --- a/src/database.cpp +++ b/src/database.cpp @@ -37,7 +37,7 @@ void Database::process() cancel_operation = false; int count = create(); cancel_operation = false; - qDebug("Added %i entries to the database", count); + qDebug("Total entries added to the database: %i", count); if(count < 0) { clear(); } diff --git a/src/forms/configwidget.ui b/src/forms/configwidget.ui index 08e504f..3e3d5fd 100644 --- a/src/forms/configwidget.ui +++ b/src/forms/configwidget.ui @@ -283,6 +283,9 @@ + + false + In Memory diff --git a/src/qlistdb.cpp b/src/qlistdb.cpp index b698551..ed5f13a 100644 --- a/src/qlistdb.cpp +++ b/src/qlistdb.cpp @@ -135,7 +135,7 @@ int QListDB::create() return -1; } - qDebug("Added %i objects for OHFI %#02X", dir_count, ohfi_array[i]); + qDebug("Added objects for OHFI 0x%02X: %i", ohfi_array[i], dir_count); total_objects += dir_count; object_list[ohfi_array[i]] = list; diff --git a/src/sqlitedb.cpp b/src/sqlitedb.cpp index 31fe34a..039c248 100644 --- a/src/sqlitedb.cpp +++ b/src/sqlitedb.cpp @@ -78,7 +78,6 @@ static const char create_apps[] = "CREATE TABLE IF NOT EXISTS application (" static const char create_virtual[] = "CREATE TABLE IF NOT EXISTS virtual_nodes (" "object_id INTEGER PRIMARY KEY REFERENCES object_node(object_id) ON DELETE CASCADE," - "title TEXT NOT NULL CHECK (LENGTH(title) > 0)," "app_type INTEGER)"; static const char create_photos[] = "CREATE TABLE IF NOT EXISTS photos (" @@ -265,6 +264,12 @@ int SQLiteDB::create() int total_objects = 0; db.transaction(); + + if(!insertVirtualEntries()) { + db.rollback(); + return -1; + } + for(int i = 0, max = sizeof(ohfi_array) / sizeof(int); i < max; i++) { QString base_path = getBasePath(ohfi_array[i]); int dir_count = recursiveScanRootDirectory(base_path, NULL, ohfi_array[i], ohfi_array[i]); @@ -1223,3 +1228,73 @@ int SQLiteDB::getRootItems(int root_ohfi, metadata_t **metadata) return count; } + +bool SQLiteDB::insertVirtualEntry(int ohfi) +{ + QSqlQuery query; + query.prepare("REPLACE INTO virtual_nodes (object_id)" + "VALUES (:object_id)"); + query.bindValue(0, ohfi); + bool ret = query.exec(); + if(!ret) { + qDebug() << query.lastError(); + } + return ret; +} + +bool SQLiteDB::insertVirtualEntries() +{ + int ohfi; + + if((ohfi = insertNodeEntry("Folders", VITA_DIR_TYPE_MASK_REGULAR, Video)) > 0) + insertVirtualEntry(ohfi); + else + return false; + + if((ohfi = insertNodeEntry("All", VITA_DIR_TYPE_MASK_ALL, Video)) > 0) + insertVirtualEntry(ohfi); + else + return false; + + if((ohfi = insertNodeEntry("Folders", VITA_DIR_TYPE_MASK_REGULAR, Photo)) > 0) + insertVirtualEntry(ohfi); + else + return false; + + if((ohfi = insertNodeEntry("Month", VITA_DIR_TYPE_MASK_MONTH, Photo)) > 0) + insertVirtualEntry(ohfi); + else + return false; + + if((ohfi = insertNodeEntry("All", VITA_DIR_TYPE_MASK_ALL, Photo)) > 0) + insertVirtualEntry(ohfi); + else + return false; + + if((ohfi = insertNodeEntry("Artists", VITA_DIR_TYPE_MASK_ARTISTS, Music)) > 0) + insertVirtualEntry(ohfi); + else + return false; + + if((ohfi = insertNodeEntry("Albums", VITA_DIR_TYPE_MASK_ALBUMS, Music)) > 0) + insertVirtualEntry(ohfi); + else + return false; + + if((ohfi = insertNodeEntry("Songs", VITA_DIR_TYPE_MASK_SONGS, Music)) > 0) + insertVirtualEntry(ohfi); + else + return false; + + if((ohfi = insertNodeEntry("Genres", VITA_DIR_TYPE_MASK_GENRES, Music)) > 0) + insertVirtualEntry(ohfi); + else + return false; + + if((ohfi = insertNodeEntry("Playlists", VITA_DIR_TYPE_MASK_PLAYLISTS, Music)) > 0) + insertVirtualEntry(ohfi); + else + return false; + + return true; +} diff --git a/src/sqlitedb.h b/src/sqlitedb.h index 8841a60..669d820 100644 --- a/src/sqlitedb.h +++ b/src/sqlitedb.h @@ -88,6 +88,8 @@ private: qint64 getChildenTotalSize(int ohfi); bool updateObjectPath(int ohfi, const QString &name); int getRootItems(int root_ohfi, metadata_t **metadata); + bool insertVirtualEntries(); + bool insertVirtualEntry(int ohfi); QTimer *timer; QThread *thread;