/[svn]/linuxsampler/trunk/src/db/InstrumentsDb.cpp
ViewVC logotype

Annotation of /linuxsampler/trunk/src/db/InstrumentsDb.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3290 - (hide annotations) (download)
Fri Jun 23 12:24:58 2017 UTC (6 years, 10 months ago) by schoenebeck
File size: 71935 byte(s)
* Revised fundamental C++ classes "Thread", "Mutex" and
  "Condition" which fixes potential undefined behavior
  (note: this addresses mainly the POSIX implementation,
   Win32 is untested yet and would also need an update).
* Bumped version (2.0.0.svn64).

1 iliev 1161 /***************************************************************************
2     * *
3 persson 2427 * Copyright (C) 2007-2013 Grigor Iliev, Benno Senoner *
4 iliev 1161 * *
5     * This program is free software; you can redistribute it and/or modify *
6     * it under the terms of the GNU General Public License as published by *
7     * the Free Software Foundation; either version 2 of the License, or *
8     * (at your option) any later version. *
9     * *
10     * This program is distributed in the hope that it will be useful, *
11     * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13     * GNU General Public License for more details. *
14     * *
15     * You should have received a copy of the GNU General Public License *
16     * along with this program; if not, write to the Free Software *
17     * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, *
18     * MA 02110-1301 USA *
19     ***************************************************************************/
20    
21     #include "InstrumentsDb.h"
22    
23 iliev 1717 #include "../common/File.h"
24 iliev 1782 #include "../common/Path.h"
25 schoenebeck 1424 #include "../common/global_private.h"
26 iliev 1161
27     #include <iostream>
28     #include <sstream>
29 iliev 1200 #include <vector>
30 persson 1944 #include <algorithm>
31 iliev 1161 #include <errno.h>
32 persson 1908 #ifndef WIN32
33 iliev 1187 #include <fnmatch.h>
34 senoner 1912 #else
35     #include <direct.h>
36 persson 1908 #endif
37 iliev 1161 #include "../common/Exception.h"
38    
39     namespace LinuxSampler {
40    
41 persson 1644 InstrumentsDb InstrumentsDb::instance;
42 iliev 1161
43 iliev 1717 void InstrumentsDb::CreateInstrumentsDb(String FilePath) {
44 schoenebeck 3091 if (FilePath.empty()) {
45     FilePath = GetDefaultDBLocation();
46     dmsg(0,("InstrumentsDb: Creating database at default location '%s'\n", FilePath.c_str()));
47     }
48    
49 iliev 1717 File f = File(FilePath);
50     if (f.Exist()) {
51     throw Exception("File exists: " + FilePath);
52 iliev 1187 }
53    
54 schoenebeck 3091 SetDbFile(FilePath);
55    
56 iliev 1187 String sql =
57     " CREATE TABLE instr_dirs ( "
58     " dir_id INTEGER PRIMARY KEY AUTOINCREMENT, "
59     " parent_dir_id INTEGER DEFAULT 0, "
60     " dir_name TEXT, "
61     " created TIMESTAMP DEFAULT CURRENT_TIMESTAMP, "
62     " modified TIMESTAMP DEFAULT CURRENT_TIMESTAMP, "
63     " description TEXT, "
64     " FOREIGN KEY(parent_dir_id) REFERENCES instr_dirs(dir_id), "
65     " UNIQUE (parent_dir_id,dir_name) "
66     " ); ";
67    
68 schoenebeck 3091 ExecSql(sql);
69 iliev 1187
70 iliev 1350 sql = "INSERT INTO instr_dirs (dir_id, parent_dir_id, dir_name) VALUES (0, -2, '/');";
71 schoenebeck 3091 ExecSql(sql);
72 iliev 1187
73     sql =
74     " CREATE TABLE instruments ( "
75     " instr_id INTEGER PRIMARY KEY AUTOINCREMENT, "
76     " dir_id INTEGER DEFAULT 0, "
77     " instr_name TEXT, "
78     " instr_file TEXT, "
79     " instr_nr INTEGER, "
80     " format_family TEXT, "
81     " format_version TEXT, "
82     " instr_size INTEGER, "
83     " created TIMESTAMP DEFAULT CURRENT_TIMESTAMP, "
84     " modified TIMESTAMP DEFAULT CURRENT_TIMESTAMP, "
85     " description TEXT, "
86     " is_drum INTEGER(1), "
87     " product TEXT, "
88     " artists TEXT, "
89     " keywords TEXT, "
90     " FOREIGN KEY(dir_id) REFERENCES instr_dirs(dir_id), "
91     " UNIQUE (dir_id,instr_name) "
92     " ); ";
93    
94 schoenebeck 3091 ExecSql(sql);
95 iliev 1187 }
96    
97 iliev 1161 InstrumentsDb::InstrumentsDb() {
98     db = NULL;
99 iliev 1187 InTransaction = false;
100 iliev 1161 }
101    
102     InstrumentsDb::~InstrumentsDb() {
103 schoenebeck 3290 InstrumentsDbThread.StopThread();
104 iliev 1161 if (db != NULL) sqlite3_close(db);
105     }
106    
107     void InstrumentsDb::AddInstrumentsDbListener(InstrumentsDb::Listener* l) {
108     llInstrumentsDbListeners.AddListener(l);
109     }
110    
111     void InstrumentsDb::RemoveInstrumentsDbListener(InstrumentsDb::Listener* l) {
112     llInstrumentsDbListeners.RemoveListener(l);
113     }
114    
115     InstrumentsDb* InstrumentsDb::GetInstrumentsDb() {
116 persson 1644 return &instance;
117 iliev 1161 }
118    
119     void InstrumentsDb::SetDbFile(String File) {
120 persson 2427 LockGuard lock(DbInstrumentsMutex);
121 iliev 1161 if (File.empty() || DbFile.length() > 0) {
122     throw Exception("Failed to set the database file");
123     }
124     DbFile = File;
125     }
126    
127 schoenebeck 3091 String InstrumentsDb::GetDefaultDBLocation() {
128     #ifdef WIN32
129     char* userprofile = getenv("USERPROFILE");
130     if (userprofile) {
131     String s = userprofile;
132     s += "\\.linuxsampler\\instruments.db";
133     return s;
134     } else {
135     // in case USERPROFILE is not set (which should not occur)
136     return "instruments.db";
137     }
138     #else // POSIX ...
139     String s = CONFIG_DEFAULT_INSTRUMENTS_DB_LOCATION;
140     # if defined(__APPLE__)
141     if (s.find("~") == 0)
142     s.replace(0, 1, getenv("HOME"));
143     # endif
144     return s;
145     #endif
146     }
147 iliev 1161
148 schoenebeck 3091 void InstrumentsDb::EnsureDBFileExists() {
149     if (DbFile.empty())
150     DbFile = GetDefaultDBLocation();
151 nagata 1642 #if defined(__APPLE__) /* 20071224 Toshi Nagata */
152     if (DbFile.find("~") == 0)
153     DbFile.replace(0, 1, getenv("HOME"));
154     #endif
155 schoenebeck 3091 Path DbPath(DbFile);
156     String DbDir = DbPath.stripLastName();
157     // create directory if it does not exist yet
158     if (!DbPath.nodes().empty()) {
159     File d(DbDir);
160     if (!d.Exist()) {
161     #ifdef WIN32
162     if (_mkdir(DbDir.c_str()))
163     throw Exception("Could not create instruments DB directory '" + DbDir + "'");
164     #else
165     if (mkdir(DbDir.c_str(), S_IRWXU))
166     throw Exception("Could not create instruments DB directory '" + DbDir + "'");
167     #endif
168     }
169     }
170     // create database file if it does not exist yet
171     File f(DbFile);
172     if (!f.Exist()) {
173     // formats the DB, which creates a new instruments.db file
174     Format();
175     }
176     }
177    
178     sqlite3* InstrumentsDb::GetDb() {
179     if ( db != NULL) return db;
180    
181     if (DbFile.empty())
182     DbFile = GetDefaultDBLocation();
183    
184     {
185     // first check if the instruments DB's directory exists, if not give up
186     Path path(DbFile);
187     String sDir = path.stripLastName();
188     File d(sDir);
189     if (!d.Exist())
190     throw Exception("Instruments DB directory '" + sDir + "' does not exist!");
191    
192     // just to give the user a notice about the DB file being created in case it does not exist yet
193     File f(DbFile);
194     if (!f.Exist())
195     dmsg(0,("Instruments DB file '%s' does not exist yet. Trying to create it now.\n", DbFile.c_str()));
196     }
197    
198     dmsg(0,("Opening instruments DB at '%s'\n", DbFile.c_str()));
199 iliev 1161 int rc = sqlite3_open(DbFile.c_str(), &db);
200     if (rc) {
201     sqlite3_close(db);
202     db = NULL;
203     throw Exception("Cannot open instruments database: " + DbFile);
204     }
205 persson 1908 #ifndef WIN32
206 iliev 1187 rc = sqlite3_create_function(db, "regexp", 2, SQLITE_UTF8, NULL, Regexp, NULL, NULL);
207     if (rc) { throw Exception("Failed to add user function for handling regular expressions."); }
208 persson 1908 #endif
209 iliev 1350
210     // TODO: remove this in the next version
211     try {
212     int i = ExecSqlInt("SELECT parent_dir_id FROM instr_dirs WHERE dir_id=0");
213     // The parent ID of the root directory should be -2 now.
214     if(i != -2) ExecSql("UPDATE instr_dirs SET parent_dir_id=-2 WHERE dir_id=0");
215     } catch(Exception e) { }
216     ////////////////////////////////////////
217 iliev 1161
218     return db;
219     }
220    
221     int InstrumentsDb::GetDirectoryCount(int DirId) {
222     dmsg(2,("InstrumentsDb: GetDirectoryCount(DirId=%d)\n", DirId));
223     if(DirId == -1) return -1;
224    
225     std::stringstream sql;
226     sql << "SELECT COUNT(*) FROM instr_dirs WHERE parent_dir_id=" << DirId;
227    
228     int count = ExecSqlInt(sql.str());
229    
230     return count;
231     }
232    
233 iliev 1187 int InstrumentsDb::GetDirectoryCount(String Dir, bool Recursive) {
234     dmsg(2,("InstrumentsDb: GetDirectoryCount(Dir=%s,Recursive=%d)\n", Dir.c_str(), Recursive));
235 iliev 1161 int i;
236    
237 iliev 1187 BeginTransaction();
238     try {
239     if (Recursive) {
240     DirectoryCounter directoryCounter;
241     DirectoryTreeWalk(Dir, &directoryCounter);
242     i = directoryCounter.GetDirectoryCount();
243     } else {
244     i = GetDirectoryCount(GetDirectoryId(Dir));
245     }
246     } catch (Exception e) {
247     EndTransaction();
248 iliev 1161 throw e;
249     }
250 iliev 1187 EndTransaction();
251 iliev 1345 if (i == -1) throw Exception("Unkown DB directory: " + toEscapedPath(Dir));
252 iliev 1161
253     return i;
254     }
255    
256     IntListPtr InstrumentsDb::GetDirectoryIDs(int DirId) {
257     std::stringstream sql;
258     sql << "SELECT dir_id FROM instr_dirs ";
259     sql << "WHERE parent_dir_id=" << DirId << " AND dir_id!=0";
260    
261     return ExecSqlIntList(sql.str());
262     }
263    
264 iliev 1187 StringListPtr InstrumentsDb::GetDirectories(String Dir, bool Recursive) {
265     dmsg(2,("InstrumentsDb: GetDirectories(Dir=%s,Recursive=%d)\n", Dir.c_str(), Recursive));
266 iliev 1161
267 iliev 1187 BeginTransaction();
268 iliev 1161 try {
269     int dirId = GetDirectoryId(Dir);
270 iliev 1345 if(dirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
271 iliev 1161
272 iliev 1187 StringListPtr pDirs;
273     if (Recursive) {
274     SearchQuery q;
275     DirectoryFinder directoryFinder(&q);
276     DirectoryTreeWalk(Dir, &directoryFinder);
277     pDirs = directoryFinder.GetDirectories();
278     } else {
279     pDirs = GetDirectories(dirId);
280     }
281     EndTransaction();
282     return pDirs;
283 iliev 1161 } catch (Exception e) {
284 iliev 1187 EndTransaction();
285 iliev 1161 throw e;
286     }
287     }
288 iliev 1187
289     StringListPtr InstrumentsDb::GetDirectories(int DirId) {
290     std::stringstream sql;
291     sql << "SELECT dir_name FROM instr_dirs ";
292     sql << "WHERE parent_dir_id=" << DirId << " AND dir_id!=0";
293 iliev 1345 StringListPtr dirs = ExecSqlStringList(sql.str());
294    
295     for (int i = 0; i < dirs->size(); i++) {
296     for (int j = 0; j < dirs->at(i).length(); j++) {
297     if (dirs->at(i).at(j) == '/') dirs->at(i).at(j) = '\0';
298     }
299     }
300    
301     return dirs;
302 iliev 1187 }
303 iliev 1161
304     int InstrumentsDb::GetDirectoryId(String Dir) {
305     dmsg(2,("InstrumentsDb: GetDirectoryId(Dir=%s)\n", Dir.c_str()));
306     CheckPathName(Dir);
307    
308     if (Dir.empty() || Dir.at(0) != '/') {
309     return -1;
310     } else if (Dir.length() == 1) {
311     // We expect the root directory id to be always 0.
312     return 0;
313     }
314    
315     int id = 0, i = 1;
316 schoenebeck 3101 int j = (int) Dir.find('/', i);
317 iliev 1161
318     while(j != std::string::npos) {
319     id = GetDirectoryId(id, Dir.substr(i, j - i));
320     i = j + 1;
321     if (i >= Dir.length()) return id;
322 schoenebeck 3101 j = (int) Dir.find('/', i);
323 iliev 1161 }
324    
325     return GetDirectoryId(id, Dir.substr(i));
326     }
327    
328     int InstrumentsDb::GetDirectoryId(int ParentDirId, String DirName) {
329     dmsg(2,("InstrumentsDb: GetDirectoryId(ParentDirId=%d, DirName=%s)\n", ParentDirId, DirName.c_str()));
330 iliev 1345 DirName = toDbName(DirName);
331 iliev 1161 std::stringstream sql;
332     sql << "SELECT dir_id FROM instr_dirs WHERE parent_dir_id=";
333     sql << ParentDirId << " AND dir_name=?";
334     return ExecSqlInt(sql.str(), DirName);
335     }
336    
337 iliev 1727 int InstrumentsDb::GetDirectoryId(int InstrId) {
338     dmsg(2,("InstrumentsDb: GetDirectoryId(InstrId=%d)\n", InstrId));
339     std::stringstream sql;
340     sql << "SELECT dir_id FROM instruments WHERE instr_id=" << InstrId;
341     return ExecSqlInt(sql.str());
342     }
343    
344 iliev 1187 String InstrumentsDb::GetDirectoryName(int DirId) {
345     String sql = "SELECT dir_name FROM instr_dirs WHERE dir_id=" + ToString(DirId);
346     String name = ExecSqlString(sql);
347     if (name.empty()) throw Exception("Directory ID not found");
348     return name;
349     }
350    
351     int InstrumentsDb::GetParentDirectoryId(int DirId) {
352     if (DirId == 0) throw Exception("The root directory is specified");
353     String sql = "SELECT parent_dir_id FROM instr_dirs WHERE dir_id=" + ToString(DirId);
354     int parentId = ExecSqlInt(sql);
355     if (parentId == -1) throw Exception("DB directory not found");
356     return parentId;
357     }
358    
359     String InstrumentsDb::GetDirectoryPath(int DirId) {
360     String path = "";
361     int count = 1000; // used to prevent infinite loops
362    
363     while(--count) {
364     if (DirId == 0) {
365     path = "/" + path;
366     break;
367     }
368 iliev 1727 path = GetDirectoryName(DirId) + "/" + path;
369 iliev 1187 DirId = GetParentDirectoryId(DirId);
370     }
371    
372     if (!count) throw Exception("Possible infinite loop detected");
373    
374     return path;
375     }
376 iliev 1727
377     StringListPtr InstrumentsDb::GetInstrumentsByFile(String File) {
378     dmsg(2,("InstrumentsDb: GetInstrumentsByFile(File=%s)\n", File.c_str()));
379 iliev 1187
380 iliev 1727 StringListPtr instrs(new std::vector<String>);
381    
382     BeginTransaction();
383     try {
384     File = toEscapedFsPath(File);
385     IntListPtr ids = ExecSqlIntList("SELECT instr_id FROM instruments WHERE instr_file=?", File);
386    
387     for (int i = 0; i < ids->size(); i++) {
388     String name = GetInstrumentName(ids->at(i));
389     String dir = GetDirectoryPath(GetDirectoryId(ids->at(i)));
390     instrs->push_back(dir + name);
391     }
392     } catch (Exception e) {
393     EndTransaction();
394     throw e;
395     }
396     EndTransaction();
397    
398     return instrs;
399     }
400    
401 iliev 1161 void InstrumentsDb::AddDirectory(String Dir) {
402     dmsg(2,("InstrumentsDb: AddDirectory(Dir=%s)\n", Dir.c_str()));
403     CheckPathName(Dir);
404     String ParentDir = GetParentDirectory(Dir);
405    
406 iliev 1187 BeginTransaction();
407 iliev 1161 try {
408     if (Dir.length() > 1) {
409     if (Dir.at(Dir.length() - 1) == '/') Dir.erase(Dir.length() - 1);
410     }
411    
412     String dirName = GetFileName(Dir);
413     if(ParentDir.empty() || dirName.empty()) {
414 iliev 1345 throw Exception("Failed to add DB directory: " + toEscapedPath(Dir));
415 iliev 1161 }
416    
417     int id = GetDirectoryId(ParentDir);
418 iliev 1345 if (id == -1) throw Exception("DB directory doesn't exist: " + toEscapedPath(ParentDir));
419 iliev 1161 int id2 = GetDirectoryId(id, dirName);
420 iliev 1345 if (id2 != -1) throw Exception("DB directory already exist: " + toEscapedPath(Dir));
421 iliev 1187 id2 = GetInstrumentId(id, dirName);
422 iliev 1345 if (id2 != -1) throw Exception("Instrument with that name exist: " + toEscapedPath(Dir));
423 iliev 1161
424     std::stringstream sql;
425     sql << "INSERT INTO instr_dirs (parent_dir_id, dir_name) VALUES (";
426     sql << id << ", ?)";
427    
428 iliev 1345 ExecSql(sql.str(), toDbName(dirName));
429 iliev 1161 } catch (Exception e) {
430 iliev 1187 EndTransaction();
431 iliev 1161 throw e;
432     }
433    
434 iliev 1187 EndTransaction();
435 iliev 1161
436     FireDirectoryCountChanged(ParentDir);
437     }
438    
439     void InstrumentsDb::RemoveDirectory(String Dir, bool Force) {
440     dmsg(2,("InstrumentsDb: RemoveDirectory(Dir=%s,Force=%d)\n", Dir.c_str(), Force));
441    
442     String ParentDir = GetParentDirectory(Dir);
443    
444 iliev 1187 BeginTransaction();
445 iliev 1161 try {
446     int dirId = GetDirectoryId(Dir);
447 iliev 1345 if (dirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
448 iliev 1161 if (dirId == 0) throw Exception("Cannot delete the root directory: " + Dir);
449     if(ParentDir.empty()) throw Exception("Unknown parent directory");
450     if (Force) RemoveDirectoryContent(dirId);
451     RemoveDirectory(dirId);
452     } catch (Exception e) {
453 iliev 1187 EndTransaction();
454 iliev 1161 throw e;
455     }
456    
457 iliev 1187 EndTransaction();
458 iliev 1161 FireDirectoryCountChanged(ParentDir);
459     }
460    
461     void InstrumentsDb::RemoveDirectoryContent(int DirId, int Level) {
462     dmsg(2,("InstrumentsDb: RemoveDirectoryContent(DirId=%d,Level=%d)\n", DirId, Level));
463     if (Level > 1000) throw Exception("Directory level too deep: " + ToString(Level));
464     IntListPtr dirIds = GetDirectoryIDs(DirId);
465    
466     for (int i = 0; i < dirIds->size(); i++) {
467     RemoveDirectoryContent(dirIds->at(i), Level + 1);
468     }
469    
470     RemoveAllDirectories(DirId);
471     RemoveAllInstruments(DirId);
472     }
473    
474     void InstrumentsDb::RemoveDirectory(int DirId) {
475     dmsg(2,("InstrumentsDb: RemoveDirectory(DirId=%d)\n", DirId));
476     if (GetInstrumentCount(DirId) > 0 || GetDirectoryCount(DirId) > 0) {
477     throw Exception("The specified DB directory is not empty");
478     }
479    
480     std::stringstream sql;
481     sql << "DELETE FROM instr_dirs WHERE dir_id=" << DirId;
482    
483     ExecSql(sql.str());
484     }
485    
486     void InstrumentsDb::RemoveAllDirectories(int DirId) {
487     dmsg(2,("InstrumentsDb: RemoveAllDirectories(DirId=%d)\n", DirId));
488     IntListPtr dirIds = GetDirectoryIDs(DirId);
489    
490     for (int i = 0; i < dirIds->size(); i++) {
491     if (!IsDirectoryEmpty(dirIds->at(i))) {
492     throw Exception("DB directory not empty!");
493     }
494     }
495     std::stringstream sql;
496     sql << "DELETE FROM instr_dirs WHERE parent_dir_id=" << DirId;
497     sql << " AND dir_id!=0";
498    
499     ExecSql(sql.str());
500     }
501    
502     bool InstrumentsDb::IsDirectoryEmpty(int DirId) {
503     dmsg(2,("InstrumentsDb: IsDirectoryEmpty(DirId=%d)\n", DirId));
504     int dirCount = GetDirectoryCount(DirId);
505     int instrCount = GetInstrumentCount(DirId);
506     dmsg(3,("InstrumentsDb: IsDirectoryEmpty: dirCount=%d,instrCount=%d\n", dirCount, instrCount));
507     if (dirCount == -1 || instrCount == -1) return false;
508     return dirCount == 0 && instrCount == 0;
509     }
510    
511     bool InstrumentsDb::DirectoryExist(String Dir) {
512     dmsg(2,("InstrumentsDb: DirectoryExist(Dir=%s)\n", Dir.c_str()));
513 persson 2427 {
514     LockGuard lock(DbInstrumentsMutex);
515     return GetDirectoryId(Dir) != -1;
516 iliev 1161 }
517     }
518    
519     DbDirectory InstrumentsDb::GetDirectoryInfo(String Dir) {
520     dmsg(2,("InstrumentsDb: GetDirectoryInfo(Dir=%s)\n", Dir.c_str()));
521     DbDirectory d;
522    
523 iliev 1187 BeginTransaction();
524 iliev 1161
525     try {
526     int id = GetDirectoryId(Dir);
527 iliev 1345 if(id == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
528 iliev 1161
529     sqlite3_stmt *pStmt = NULL;
530     std::stringstream sql;
531     sql << "SELECT created,modified,description FROM instr_dirs ";
532     sql << "WHERE dir_id=" << id;
533    
534     int res = sqlite3_prepare(GetDb(), sql.str().c_str(), -1, &pStmt, NULL);
535     if (res != SQLITE_OK) {
536     throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
537     }
538    
539     res = sqlite3_step(pStmt);
540     if(res == SQLITE_ROW) {
541     d.Created = ToString(sqlite3_column_text(pStmt, 0));
542     d.Modified = ToString(sqlite3_column_text(pStmt, 1));
543     d.Description = ToString(sqlite3_column_text(pStmt, 2));
544     } else {
545     sqlite3_finalize(pStmt);
546    
547     if (res != SQLITE_DONE) {
548     throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
549     } else {
550 iliev 1345 throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
551 iliev 1161 }
552     }
553    
554     sqlite3_finalize(pStmt);
555     } catch (Exception e) {
556 iliev 1187 EndTransaction();
557 iliev 1161 throw e;
558     }
559    
560 iliev 1187 EndTransaction();
561 iliev 1161 return d;
562     }
563    
564     void InstrumentsDb::RenameDirectory(String Dir, String Name) {
565     dmsg(2,("InstrumentsDb: RenameDirectory(Dir=%s,Name=%s)\n", Dir.c_str(), Name.c_str()));
566     CheckFileName(Name);
567 iliev 1345 String dbName = toDbName(Name);
568 iliev 1161
569 iliev 1187 BeginTransaction();
570 iliev 1161 try {
571     int dirId = GetDirectoryId(Dir);
572 iliev 1345 if (dirId == -1) throw Exception("Unknown DB directory: " + toEscapedText(Dir));
573 iliev 1161
574     std::stringstream sql;
575     sql << "SELECT parent_dir_id FROM instr_dirs WHERE dir_id=" << dirId;
576    
577     int parent = ExecSqlInt(sql.str());
578 iliev 1345 if (parent == -1) throw Exception("Unknown parent directory: " + toEscapedPath(Dir));
579    
580     if (GetDirectoryId(parent, dbName) != -1) {
581     String s = toEscapedPath(Name);
582     throw Exception("Cannot rename. Directory with that name already exists: " + s);
583 iliev 1161 }
584    
585 iliev 1345 if (GetInstrumentId(parent, dbName) != -1) {
586     throw Exception("Cannot rename. Instrument with that name exist: " + toEscapedPath(Dir));
587 iliev 1187 }
588    
589 iliev 1161 sql.str("");
590     sql << "UPDATE instr_dirs SET dir_name=? WHERE dir_id=" << dirId;
591 iliev 1345 ExecSql(sql.str(), dbName);
592 iliev 1161 } catch (Exception e) {
593 iliev 1187 EndTransaction();
594 iliev 1161 throw e;
595     }
596    
597 iliev 1187 EndTransaction();
598 iliev 1350 FireDirectoryNameChanged(Dir, toAbstractName(Name));
599 iliev 1161 }
600    
601     void InstrumentsDb::MoveDirectory(String Dir, String Dst) {
602     dmsg(2,("InstrumentsDb: MoveDirectory(Dir=%s,Dst=%s)\n", Dir.c_str(), Dst.c_str()));
603    
604 iliev 1187 if(Dir.compare("/") == 0) throw Exception("Cannot move the root directory");
605 iliev 1161 String ParentDir = GetParentDirectory(Dir);
606     if(ParentDir.empty()) throw Exception("Unknown parent directory");
607    
608 iliev 1187 BeginTransaction();
609 iliev 1161 try {
610     int dirId = GetDirectoryId(Dir);
611 iliev 1345 if (dirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
612 iliev 1161 int dstId = GetDirectoryId(Dst);
613 iliev 1345 if (dstId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dst));
614 iliev 1161 if (dirId == dstId) {
615     throw Exception("Cannot move directory to itself");
616     }
617    
618     if (Dir.at(Dir.length() - 1) != '/') Dir.append("/");
619     if (Dst.length() > Dir.length()) {
620     if (Dir.compare(Dst.substr(0, Dir.length())) == 0) {
621     throw Exception("Cannot move a directory to a subdirectory of itself.");
622     }
623     }
624 iliev 1187
625     Dir.erase(Dir.length() - 1);
626     String dirName = GetFileName(Dir);
627 iliev 1161
628 iliev 1187 int id2 = GetDirectoryId(dstId, dirName);
629 iliev 1345 if (id2 != -1) throw Exception("DB directory already exist: " + toEscapedPath(dirName));
630 iliev 1187 id2 = GetInstrumentId(dstId, dirName);
631 iliev 1345 if (id2 != -1) throw Exception("Instrument with that name exist: " + toEscapedPath(dirName));
632 iliev 1187
633 iliev 1161 std::stringstream sql;
634     sql << "UPDATE instr_dirs SET parent_dir_id=" << dstId;
635     sql << " WHERE dir_id=" << dirId;
636     ExecSql(sql.str());
637     } catch (Exception e) {
638 iliev 1187 EndTransaction();
639 iliev 1161 throw e;
640     }
641    
642 iliev 1187 EndTransaction();
643 iliev 1161 FireDirectoryCountChanged(ParentDir);
644     FireDirectoryCountChanged(Dst);
645     }
646    
647 iliev 1187 void InstrumentsDb::CopyDirectory(String Dir, String Dst) {
648     dmsg(2,("InstrumentsDb: CopyDirectory(Dir=%s,Dst=%s)\n", Dir.c_str(), Dst.c_str()));
649    
650     if(Dir.compare("/") == 0) throw Exception("Cannot copy the root directory");
651     String ParentDir = GetParentDirectory(Dir);
652     if(ParentDir.empty()) throw Exception("Unknown parent directory");
653    
654     BeginTransaction();
655     try {
656     int dirId = GetDirectoryId(Dir);
657 iliev 1345 if (dirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
658 iliev 1187 int dstId = GetDirectoryId(Dst);
659 iliev 1345 if (dstId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dst));
660 iliev 1187 if (dirId == dstId) {
661     throw Exception("Cannot copy directory to itself");
662     }
663    
664     if (Dir.at(Dir.length() - 1) != '/') Dir.append("/");
665     if (Dst.length() > Dir.length()) {
666     if (Dir.compare(Dst.substr(0, Dir.length())) == 0) {
667     throw Exception("Cannot copy a directory to a subdirectory of itself.");
668     }
669     }
670    
671     Dir.erase(Dir.length() - 1);
672     String dirName = GetFileName(Dir);
673    
674     int id2 = GetDirectoryId(dstId, dirName);
675 iliev 1345 if (id2 != -1) throw Exception("DB directory already exist: " + toEscapedPath(dirName));
676 iliev 1187 id2 = GetInstrumentId(dstId, dirName);
677 iliev 1345 if (id2 != -1) throw Exception("Instrument with that name exist: " + toEscapedPath(dirName));
678 iliev 1187
679     DirectoryCopier directoryCopier(ParentDir, Dst);
680     DirectoryTreeWalk(Dir, &directoryCopier);
681     } catch (Exception e) {
682     EndTransaction();
683     throw e;
684     }
685    
686     EndTransaction();
687     }
688    
689 iliev 1161 void InstrumentsDb::SetDirectoryDescription(String Dir, String Desc) {
690     dmsg(2,("InstrumentsDb: SetDirectoryDescription(Dir=%s,Desc=%s)\n", Dir.c_str(), Desc.c_str()));
691    
692 iliev 1187 BeginTransaction();
693 iliev 1161 try {
694     int id = GetDirectoryId(Dir);
695 iliev 1345 if(id == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
696 iliev 1161
697     std::stringstream sql;
698     sql << "UPDATE instr_dirs SET description=?,modified=CURRENT_TIMESTAMP ";
699     sql << "WHERE dir_id="<< id;
700    
701     ExecSql(sql.str(), Desc);
702     } catch (Exception e) {
703 iliev 1187 EndTransaction();
704 iliev 1161 throw e;
705     }
706 iliev 1187 EndTransaction();
707 iliev 1161
708     FireDirectoryInfoChanged(Dir);
709     }
710    
711 iliev 1781 int InstrumentsDb::AddInstruments(ScanMode Mode, String DbDir, String FsDir, bool bBackground, bool insDir) {
712     dmsg(2,("InstrumentsDb: AddInstruments(Mode=%d,DbDir=%s,FsDir=%s,bBackground=%d,insDir=%d)\n", Mode, DbDir.c_str(), FsDir.c_str(), bBackground, insDir));
713 iliev 1200 if(!bBackground) {
714     switch (Mode) {
715     case NON_RECURSIVE:
716 iliev 1781 AddInstrumentsNonrecursive(DbDir, FsDir, insDir);
717 iliev 1200 break;
718     case RECURSIVE:
719 iliev 1781 AddInstrumentsRecursive(DbDir, FsDir, false, insDir);
720 iliev 1200 break;
721     case FLAT:
722 iliev 1781 AddInstrumentsRecursive(DbDir, FsDir, true, insDir);
723 iliev 1200 break;
724     default:
725     throw Exception("Unknown scan mode");
726     }
727    
728     return -1;
729     }
730    
731     ScanJob job;
732     int jobId = Jobs.AddJob(job);
733 iliev 1781 InstrumentsDbThread.Execute(new AddInstrumentsJob(jobId, Mode, DbDir, FsDir, insDir));
734 iliev 1200
735     return jobId;
736     }
737    
738     int InstrumentsDb::AddInstruments(String DbDir, String FilePath, int Index, bool bBackground) {
739     dmsg(2,("InstrumentsDb: AddInstruments(DbDir=%s,FilePath=%s,Index=%d,bBackground=%d)\n", DbDir.c_str(), FilePath.c_str(), Index, bBackground));
740     if(!bBackground) {
741 iliev 1781 AddInstruments(DbDir, false, FilePath, Index);
742 iliev 1200 return -1;
743     }
744    
745     ScanJob job;
746     int jobId = Jobs.AddJob(job);
747 iliev 1781 InstrumentsDbThread.Execute(new AddInstrumentsFromFileJob(jobId, DbDir, FilePath, Index, false));
748 iliev 1200
749     return jobId;
750 iliev 1781 }
751 iliev 1200
752 iliev 1781 void InstrumentsDb::AddInstruments(String DbDir, bool insDir, String FilePath, int Index, ScanProgress* pProgress) {
753     dmsg(2,("InstrumentsDb: AddInstruments(DbDir=%s,insDir=%d,FilePath=%s,Index=%d)\n", DbDir.c_str(), insDir, FilePath.c_str(), Index));
754 iliev 1161 if (DbDir.empty() || FilePath.empty()) return;
755    
756 persson 2427 {
757     LockGuard lock(DbInstrumentsMutex);
758    
759 iliev 1161 int dirId = GetDirectoryId(DbDir);
760 iliev 1345 if (dirId == -1) throw Exception("Invalid DB directory: " + toEscapedText(DbDir));
761 iliev 1161
762 iliev 1717 File f = File(FilePath);
763     if (!f.Exist()) {
764 iliev 1161 std::stringstream ss;
765 iliev 1717 ss << "Fail to stat `" << FilePath << "`: " << f.GetErrorMsg();
766 iliev 1161 throw Exception(ss.str());
767     }
768    
769 iliev 1717 if (!f.IsFile()) {
770 iliev 1161 std::stringstream ss;
771 iliev 1200 ss << "`" << FilePath << "` is not an instrument file";
772 iliev 1161 throw Exception(ss.str());
773     }
774 iliev 1200
775 iliev 1782 String dir = insDir ? PrepareSubdirectory(DbDir, FilePath) : DbDir;
776     AddInstrumentsFromFile(dir, FilePath, Index, pProgress);
777 iliev 1161 }
778     }
779    
780 iliev 1781 void InstrumentsDb::AddInstrumentsNonrecursive(String DbDir, String FsDir, bool insDir, ScanProgress* pProgress) {
781     dmsg(2,("InstrumentsDb: AddInstrumentsNonrecursive(DbDir=%s,FsDir=%s,insDir=%d)\n", DbDir.c_str(), FsDir.c_str(), insDir));
782 iliev 1161 if (DbDir.empty() || FsDir.empty()) return;
783    
784 persson 2427 {
785     LockGuard lock(DbInstrumentsMutex);
786    
787 iliev 1161 int dirId = GetDirectoryId(DbDir);
788 iliev 1345 if (dirId == -1) throw Exception("Invalid DB directory: " + toEscapedPath(DbDir));
789 iliev 1161
790 iliev 1717 File f = File(FsDir);
791     if (!f.Exist()) {
792 iliev 1161 std::stringstream ss;
793 iliev 1717 ss << "Fail to stat `" << FsDir << "`: " << f.GetErrorMsg();
794 iliev 1161 throw Exception(ss.str());
795     }
796    
797 iliev 1717 if (!f.IsDirectory()) {
798     throw Exception("Directory expected: " + FsDir);
799 iliev 1161 }
800    
801 iliev 1717 if (FsDir.at(FsDir.length() - 1) != File::DirSeparator) {
802     FsDir.push_back(File::DirSeparator);
803     }
804    
805     try {
806     FileListPtr fileList = File::GetFiles(FsDir);
807     for (int i = 0; i < fileList->size(); i++) {
808 iliev 1782 String dir = insDir ? PrepareSubdirectory(DbDir, fileList->at(i)) : DbDir;
809     AddInstrumentsFromFile(dir, FsDir + fileList->at(i), -1, pProgress);
810 iliev 1717 }
811     } catch(Exception e) {
812     e.PrintMessage();
813 iliev 1161 }
814     }
815     }
816    
817 iliev 1781 void InstrumentsDb::AddInstrumentsRecursive(String DbDir, String FsDir, bool Flat, bool insDir, ScanProgress* pProgress) {
818     dmsg(2,("InstrumentsDb: AddInstrumentsRecursive(DbDir=%s,FsDir=%s,Flat=%d,insDir=%d)\n", DbDir.c_str(), FsDir.c_str(), Flat, insDir));
819 iliev 1200 if (pProgress != NULL) {
820 iliev 1717 InstrumentFileCounter c;
821     pProgress->SetTotalFileCount(c.Count(FsDir));
822 iliev 1200 }
823    
824 iliev 1717 DirectoryScanner d;
825 iliev 1781 d.Scan(DbDir, FsDir, Flat, insDir, pProgress);
826 iliev 1161 }
827    
828     int InstrumentsDb::GetInstrumentCount(int DirId) {
829     dmsg(2,("InstrumentsDb: GetInstrumentCount(DirId=%d)\n", DirId));
830     if(DirId == -1) return -1;
831    
832     std::stringstream sql;
833     sql << "SELECT COUNT(*) FROM instruments WHERE dir_id=" << DirId;
834    
835     return ExecSqlInt(sql.str());
836     }
837    
838 iliev 1187 int InstrumentsDb::GetInstrumentCount(String Dir, bool Recursive) {
839     dmsg(2,("InstrumentsDb: GetInstrumentCount(Dir=%s,Recursive=%d)\n", Dir.c_str(), Recursive));
840 iliev 1161 int i;
841    
842 iliev 1187 BeginTransaction();
843     try {
844     if (Recursive) {
845     InstrumentCounter instrumentCounter;
846     DirectoryTreeWalk(Dir, &instrumentCounter);
847     i = instrumentCounter.GetInstrumentCount();
848     } else {
849     i = GetInstrumentCount(GetDirectoryId(Dir));
850     }
851     } catch (Exception e) {
852     EndTransaction();
853 iliev 1161 throw e;
854     }
855 iliev 1187 EndTransaction();
856 iliev 1161
857 iliev 1345 if (i == -1) throw Exception("Unknown Db directory: " + toEscapedPath(Dir));
858 iliev 1161 return i;
859     }
860    
861     IntListPtr InstrumentsDb::GetInstrumentIDs(int DirId) {
862     std::stringstream sql;
863     sql << "SELECT instr_id FROM instruments WHERE dir_id=" << DirId;
864    
865     return ExecSqlIntList(sql.str());
866     }
867    
868 iliev 1187 StringListPtr InstrumentsDb::GetInstruments(String Dir, bool Recursive) {
869     dmsg(2,("InstrumentsDb: GetInstruments(Dir=%s,Recursive=%d)\n", Dir.c_str(), Recursive));
870     BeginTransaction();
871 iliev 1161 try {
872     int dirId = GetDirectoryId(Dir);
873 iliev 1345 if(dirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
874 iliev 1161
875 iliev 1187 StringListPtr pInstrs;
876 iliev 1161
877 iliev 1187 if(Recursive) {
878     SearchQuery q;
879     InstrumentFinder instrumentFinder(&q);
880     DirectoryTreeWalk(Dir, &instrumentFinder);
881     pInstrs = instrumentFinder.GetInstruments();
882     } else {
883     std::stringstream sql;
884     sql << "SELECT instr_name FROM instruments WHERE dir_id=" << dirId;
885    
886     pInstrs = ExecSqlStringList(sql.str());
887 iliev 1350 // Converting to abstract names
888     for (int i = 0; i < pInstrs->size(); i++) {
889     for (int j = 0; j < pInstrs->at(i).length(); j++) {
890     if (pInstrs->at(i).at(j) == '/') pInstrs->at(i).at(j) = '\0';
891     }
892     }
893 iliev 1187 }
894     EndTransaction();
895     return pInstrs;
896 iliev 1161 } catch (Exception e) {
897 iliev 1187 EndTransaction();
898 iliev 1161 throw e;
899     }
900     }
901    
902     int InstrumentsDb::GetInstrumentId(String Instr) {
903     dmsg(2,("InstrumentsDb: GetInstrumentId(Instr=%s)\n", Instr.c_str()));
904     String Dir = GetDirectoryPath(Instr);
905     if (Dir.empty()) return -1;
906    
907     return GetInstrumentId(GetDirectoryId(Dir), GetFileName(Instr));
908     }
909    
910     int InstrumentsDb::GetInstrumentId(int DirId, String InstrName) {
911     dmsg(2,("InstrumentsDb: GetInstrumentId(DirId=%d,InstrName=%s)\n", DirId, InstrName.c_str()));
912     if (DirId == -1 || InstrName.empty()) return -1;
913    
914     std::stringstream sql;
915     sql << "SELECT instr_id FROM instruments WHERE dir_id=";
916     sql << DirId << " AND instr_name=?";
917 iliev 1345 return ExecSqlInt(sql.str(), toDbName(InstrName));
918 iliev 1161 }
919 iliev 1187
920     String InstrumentsDb::GetInstrumentName(int InstrId) {
921     dmsg(2,("InstrumentsDb: GetInstrumentName(InstrId=%d)\n", InstrId));
922     std::stringstream sql;
923     sql << "SELECT instr_name FROM instruments WHERE instr_id=" << InstrId;
924 iliev 1345 return toAbstractName(ExecSqlString(sql.str()));
925 iliev 1187 }
926 iliev 1161
927     void InstrumentsDb::RemoveInstrument(String Instr) {
928     dmsg(2,("InstrumentsDb: RemoveInstrument(Instr=%s)\n", Instr.c_str()));
929     String ParentDir = GetDirectoryPath(Instr);
930     if(ParentDir.empty()) throw Exception("Unknown parent directory");
931    
932 iliev 1187 BeginTransaction();
933 iliev 1161 try {
934     int instrId = GetInstrumentId(Instr);
935     if(instrId == -1) {
936 iliev 1345 throw Exception("The specified instrument does not exist: " + toEscapedPath(Instr));
937 iliev 1161 }
938     RemoveInstrument(instrId);
939     } catch (Exception e) {
940 iliev 1187 EndTransaction();
941 iliev 1161 throw e;
942     }
943 iliev 1187 EndTransaction();
944 iliev 1161 FireInstrumentCountChanged(ParentDir);
945     }
946    
947     void InstrumentsDb::RemoveInstrument(int InstrId) {
948     dmsg(2,("InstrumentsDb: RemoveInstrument(InstrId=%d)\n", InstrId));
949    
950     std::stringstream sql;
951     sql << "DELETE FROM instruments WHERE instr_id=" << InstrId;
952    
953     ExecSql(sql.str());
954     }
955    
956     void InstrumentsDb::RemoveAllInstruments(int DirId) {
957     dmsg(2,("InstrumentsDb: RemoveAllInstruments(DirId=%d)\n", DirId));
958    
959     std::stringstream sql;
960     sql << "DELETE FROM instruments WHERE dir_id=" << DirId;
961     ExecSql(sql.str());
962     }
963    
964     DbInstrument InstrumentsDb::GetInstrumentInfo(String Instr) {
965     dmsg(2,("InstrumentsDb: GetInstrumentInfo(Instr=%s)\n", Instr.c_str()));
966     DbInstrument i;
967    
968 iliev 1187 BeginTransaction();
969 iliev 1161 try {
970     int id = GetInstrumentId(Instr);
971 iliev 1345 if(id == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
972 iliev 1187 i = GetInstrumentInfo(id);
973     } catch (Exception e) {
974     EndTransaction();
975     throw e;
976     }
977     EndTransaction();
978 iliev 1161
979 iliev 1187 return i;
980     }
981 iliev 1161
982 iliev 1187 DbInstrument InstrumentsDb::GetInstrumentInfo(int InstrId) {
983     sqlite3_stmt *pStmt = NULL;
984     std::stringstream sql;
985     sql << "SELECT instr_file,instr_nr,format_family,format_version,";
986     sql << "instr_size,created,modified,description,is_drum,product,";
987     sql << "artists,keywords FROM instruments WHERE instr_id=" << InstrId;
988    
989     int res = sqlite3_prepare(GetDb(), sql.str().c_str(), -1, &pStmt, NULL);
990     if (res != SQLITE_OK) {
991     throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
992     }
993    
994     DbInstrument i;
995     res = sqlite3_step(pStmt);
996     if(res == SQLITE_ROW) {
997     i.InstrFile = ToString(sqlite3_column_text(pStmt, 0));
998     i.InstrNr = sqlite3_column_int(pStmt, 1);
999     i.FormatFamily = ToString(sqlite3_column_text(pStmt, 2));
1000     i.FormatVersion = ToString(sqlite3_column_text(pStmt, 3));
1001     i.Size = sqlite3_column_int64(pStmt, 4);
1002     i.Created = ToString(sqlite3_column_text(pStmt, 5));
1003     i.Modified = ToString(sqlite3_column_text(pStmt, 6));
1004     i.Description = ToString(sqlite3_column_text(pStmt, 7));
1005     i.IsDrum = sqlite3_column_int(pStmt, 8);
1006     i.Product = ToString(sqlite3_column_text(pStmt, 9));
1007     i.Artists = ToString(sqlite3_column_text(pStmt, 10));
1008     i.Keywords = ToString(sqlite3_column_text(pStmt, 11));
1009     } else {
1010     sqlite3_finalize(pStmt);
1011    
1012     if (res != SQLITE_DONE) {
1013 iliev 1161 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1014     } else {
1015 iliev 1187 throw Exception("Unknown DB instrument");
1016 iliev 1161 }
1017 iliev 1187 }
1018 iliev 1161
1019 iliev 1187 sqlite3_finalize(pStmt);
1020 iliev 1161 return i;
1021     }
1022    
1023     void InstrumentsDb::RenameInstrument(String Instr, String Name) {
1024     dmsg(2,("InstrumentsDb: RenameInstrument(Instr=%s,Name=%s)\n", Instr.c_str(), Name.c_str()));
1025     CheckFileName(Name);
1026    
1027 iliev 1187 BeginTransaction();
1028 iliev 1161 try {
1029     int dirId = GetDirectoryId(GetDirectoryPath(Instr));
1030 iliev 1345 if (dirId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1031 iliev 1161
1032     int instrId = GetInstrumentId(dirId, GetFileName(Instr));
1033 iliev 1345 if (instrId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1034 iliev 1161
1035     if (GetInstrumentId(dirId, Name) != -1) {
1036 iliev 1345 String s = toEscapedPath(Name);
1037     throw Exception("Cannot rename. Instrument with that name already exists: " + s);
1038 iliev 1161 }
1039    
1040 iliev 1187 if (GetDirectoryId(dirId, Name) != -1) {
1041 iliev 1345 String s = toEscapedPath(Name);
1042     throw Exception("Cannot rename. Directory with that name already exists: " + s);
1043 iliev 1187 }
1044    
1045 iliev 1161 std::stringstream sql;
1046     sql << "UPDATE instruments SET instr_name=? WHERE instr_id=" << instrId;
1047 iliev 1345 ExecSql(sql.str(), toDbName(Name));
1048 iliev 1161 } catch (Exception e) {
1049 iliev 1187 EndTransaction();
1050 iliev 1161 throw e;
1051     }
1052 iliev 1187 EndTransaction();
1053 iliev 1350 FireInstrumentNameChanged(Instr, toAbstractName(Name));
1054 iliev 1161 }
1055    
1056     void InstrumentsDb::MoveInstrument(String Instr, String Dst) {
1057     dmsg(2,("InstrumentsDb: MoveInstrument(Instr=%s,Dst=%s)\n", Instr.c_str(), Dst.c_str()));
1058     String ParentDir = GetDirectoryPath(Instr);
1059     if(ParentDir.empty()) throw Exception("Unknown parent directory");
1060    
1061 iliev 1187 BeginTransaction();
1062 iliev 1161 try {
1063 iliev 1345 int dirId = GetDirectoryId(ParentDir);
1064     if (dirId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1065 iliev 1161
1066     String instrName = GetFileName(Instr);
1067     int instrId = GetInstrumentId(dirId, instrName);
1068 iliev 1345 if (instrId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1069 iliev 1161
1070     int dstId = GetDirectoryId(Dst);
1071 iliev 1345 if (dstId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dst));
1072 iliev 1161 if (dirId == dstId) {
1073 iliev 1187 EndTransaction();
1074 iliev 1161 return;
1075     }
1076    
1077     if (GetInstrumentId(dstId, instrName) != -1) {
1078 iliev 1345 String s = toEscapedPath(instrName);
1079     throw Exception("Cannot move. Instrument with that name already exists: " + s);
1080 iliev 1161 }
1081    
1082 iliev 1187 if (GetDirectoryId(dstId, instrName) != -1) {
1083 iliev 1345 String s = toEscapedPath(instrName);
1084     throw Exception("Cannot move. Directory with that name already exists: " + s);
1085 iliev 1187 }
1086    
1087 iliev 1161 std::stringstream sql;
1088     sql << "UPDATE instruments SET dir_id=" << dstId;
1089     sql << " WHERE instr_id=" << instrId;
1090     ExecSql(sql.str());
1091     } catch (Exception e) {
1092 iliev 1187 EndTransaction();
1093 iliev 1161 throw e;
1094     }
1095 iliev 1187 EndTransaction();
1096 iliev 1161 FireInstrumentCountChanged(ParentDir);
1097     FireInstrumentCountChanged(Dst);
1098     }
1099    
1100 iliev 1187 void InstrumentsDb::CopyInstrument(String Instr, String Dst) {
1101     dmsg(2,("InstrumentsDb: CopyInstrument(Instr=%s,Dst=%s)\n", Instr.c_str(), Dst.c_str()));
1102     String ParentDir = GetDirectoryPath(Instr);
1103     if(ParentDir.empty()) throw Exception("Unknown parent directory");
1104    
1105     BeginTransaction();
1106     try {
1107     int dirId = GetDirectoryId(GetDirectoryPath(Instr));
1108 iliev 1345 if (dirId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1109 iliev 1187
1110     String instrName = GetFileName(Instr);
1111     int instrId = GetInstrumentId(dirId, instrName);
1112 iliev 1345 if (instrId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1113 iliev 1187
1114     int dstId = GetDirectoryId(Dst);
1115 iliev 1345 if (dstId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dst));
1116 iliev 1187 if (dirId == dstId) {
1117     EndTransaction();
1118     return;
1119     }
1120    
1121     CopyInstrument(instrId, instrName, dstId, Dst);
1122     } catch (Exception e) {
1123     EndTransaction();
1124     throw e;
1125     }
1126     EndTransaction();
1127    
1128     }
1129    
1130     void InstrumentsDb::CopyInstrument(int InstrId, String InstrName, int DstDirId, String DstDir) {
1131 iliev 1350 if (GetInstrumentId(DstDirId, InstrName) != -1) {
1132     String s = toEscapedPath(InstrName);
1133     throw Exception("Cannot copy. Instrument with that name already exists: " + s);
1134     }
1135    
1136     if (GetDirectoryId(DstDirId, InstrName) != -1) {
1137     String s = toEscapedPath(InstrName);
1138     throw Exception("Cannot copy. Directory with that name already exists: " + s);
1139     }
1140    
1141 iliev 1187 DbInstrument i = GetInstrumentInfo(InstrId);
1142     sqlite3_stmt *pStmt = NULL;
1143     std::stringstream sql;
1144     sql << "INSERT INTO instruments (dir_id,instr_name,instr_file,instr_nr,format_family,";
1145     sql << "format_version,instr_size,description,is_drum,product,artists,keywords) ";
1146     sql << "VALUES (" << DstDirId << ",?,?," << i.InstrNr << ",?,?," << i.Size << ",?,";
1147     sql << i.IsDrum << ",?,?,?)";
1148    
1149     int res = sqlite3_prepare(GetDb(), sql.str().c_str(), -1, &pStmt, NULL);
1150     if (res != SQLITE_OK) {
1151     throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1152     }
1153    
1154 iliev 1350 String s = toDbName(InstrName);
1155     BindTextParam(pStmt, 1, s);
1156 iliev 1187 BindTextParam(pStmt, 2, i.InstrFile);
1157     BindTextParam(pStmt, 3, i.FormatFamily);
1158     BindTextParam(pStmt, 4, i.FormatVersion);
1159     BindTextParam(pStmt, 5, i.Description);
1160     BindTextParam(pStmt, 6, i.Product);
1161     BindTextParam(pStmt, 7, i.Artists);
1162     BindTextParam(pStmt, 8, i.Keywords);
1163    
1164     res = sqlite3_step(pStmt);
1165     if(res != SQLITE_DONE) {
1166     sqlite3_finalize(pStmt);
1167     throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1168     }
1169    
1170     sqlite3_finalize(pStmt);
1171     FireInstrumentCountChanged(DstDir);
1172     }
1173    
1174 iliev 1161 void InstrumentsDb::SetInstrumentDescription(String Instr, String Desc) {
1175     dmsg(2,("InstrumentsDb: SetInstrumentDescription(Instr=%s,Desc=%s)\n", Instr.c_str(), Desc.c_str()));
1176    
1177 iliev 1187 BeginTransaction();
1178 iliev 1161 try {
1179     int id = GetInstrumentId(Instr);
1180 iliev 1345 if(id == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1181 iliev 1161
1182     std::stringstream sql;
1183     sql << "UPDATE instruments SET description=?,modified=CURRENT_TIMESTAMP ";
1184     sql << "WHERE instr_id="<< id;
1185    
1186     ExecSql(sql.str(), Desc);
1187     } catch (Exception e) {
1188 iliev 1187 EndTransaction();
1189 iliev 1161 throw e;
1190     }
1191 iliev 1187 EndTransaction();
1192 iliev 1161 FireInstrumentInfoChanged(Instr);
1193     }
1194    
1195 schoenebeck 3092 void InstrumentsDb::AddInstrumentsFromFile(String DbDir, String file, int Index, ScanProgress* pProgress) {
1196     dmsg(2,("InstrumentsDb: AddInstrumentsFromFile(DbDir=%s,File=%s,Index=%d)\n", DbDir.c_str(), file.c_str(), Index));
1197    
1198     if (!InstrumentFileInfo::isSupportedFile(file)) return;
1199    
1200 iliev 1161 try {
1201 schoenebeck 3092 if (pProgress != NULL) {
1202     pProgress->SetStatus(0);
1203     pProgress->CurrentFile = file;
1204     }
1205 iliev 1200
1206 schoenebeck 3092 int dirId = GetDirectoryId(DbDir);
1207     if (dirId == -1) throw Exception("Invalid DB directory: " + toEscapedPath(DbDir));
1208 iliev 1200
1209 schoenebeck 3092 File f = File(file);
1210     if (!f.Exist()) {
1211     std::stringstream ss;
1212     ss << "Fail to stat `" << file << "`: " << f.GetErrorMsg();
1213     throw Exception(ss.str());
1214 iliev 1161 }
1215 schoenebeck 3092
1216     if (!f.IsFile()) {
1217     std::stringstream ss;
1218     ss << "`" << file << "` is not a regular file";
1219     throw Exception(ss.str());
1220     }
1221    
1222     AddInstrumentsFromFilePriv(DbDir, dirId, file, f, Index, pProgress);
1223    
1224     if (pProgress != NULL) {
1225     pProgress->SetScannedFileCount(pProgress->GetScannedFileCount() + 1);
1226     }
1227 iliev 1161 } catch(Exception e) {
1228 iliev 1717 e.PrintMessage();
1229 iliev 1161 }
1230     }
1231    
1232 schoenebeck 3092 void InstrumentsDb::AddInstrumentsFromFilePriv(String DbDir, const int dirId, String FilePath, File file, int Index, ScanProgress* pProgress) {
1233 iliev 1717 dmsg(2,("InstrumentsDb: AddGigInstruments(DbDir=%s,FilePath=%s,Index=%d)\n", DbDir.c_str(), FilePath.c_str(), Index));
1234 iliev 1161
1235 iliev 1881 bool unlocked = false;
1236 schoenebeck 3092 InstrumentFileInfo* fileInfo = NULL;
1237     sqlite3_stmt* pStmt = NULL;
1238 iliev 1161 try {
1239 schoenebeck 3092 fileInfo = InstrumentFileInfo::getFileInfoFor(FilePath);
1240     if (!fileInfo) return;
1241 iliev 1200
1242 iliev 1161 std::stringstream sql;
1243     sql << "INSERT INTO instruments (dir_id,instr_name,instr_file,";
1244     sql << "instr_nr,format_family,format_version,instr_size,";
1245     sql << "description,is_drum,product,artists,keywords) VALUES (";
1246 schoenebeck 3092 sql << dirId << ",?,?,?,?,?," << file.GetSize() << ",?,?,?,?,?)";
1247 iliev 1161
1248 schoenebeck 3092 // instr_name 1
1249     // instr_file 2
1250     // instr_nr 3
1251     // format_family 4
1252     // format_version 5
1253     // description 6
1254     // is_drum 7
1255     // product 8
1256     // artists 9
1257     // keywords 10
1258 iliev 1161
1259     int res = sqlite3_prepare(GetDb(), sql.str().c_str(), -1, &pStmt, NULL);
1260     if (res != SQLITE_OK) {
1261     throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1262     }
1263    
1264 schoenebeck 3092 BindTextParam(pStmt, 2, toEscapedFsPath(FilePath));
1265     BindTextParam(pStmt, 4, fileInfo->formatName());
1266     BindTextParam(pStmt, 5, fileInfo->formatVersion());
1267 iliev 1161
1268 schoenebeck 3092 int instrIndex = (Index == -1) ? 0 : Index;
1269 iliev 1881
1270 schoenebeck 3092 // Assume that it's locked and should be unlocked at this point
1271     // to be able to use the database from another threads
1272     if (!InTransaction) {
1273     DbInstrumentsMutex.Unlock();
1274     unlocked = true;
1275     } else {
1276     std::cerr << "Shouldn't be in transaction when adding instruments." << std::endl;
1277     }
1278 iliev 1881
1279 schoenebeck 3092 optional<InstrumentInfo> info = fileInfo->getInstrumentInfo(0, pProgress);
1280     if (!InTransaction) DbInstrumentsMutex.Lock();
1281     while (info) {
1282     String instrumentName = info->instrumentName;
1283     if (instrumentName.empty())
1284     instrumentName = Path::getBaseName(FilePath);
1285     instrumentName = GetUniqueName(dirId, instrumentName);
1286 iliev 1161
1287 schoenebeck 3092 BindTextParam(pStmt, 8, info->product);
1288     BindTextParam(pStmt, 9, info->artists);
1289     BindTextParam(pStmt, 10, info->keywords);
1290    
1291     std::stringstream sql2;
1292     sql2 << "SELECT COUNT(*) FROM instruments WHERE instr_file=? AND ";
1293     sql2 << "instr_nr=" << instrIndex;
1294     String s = toEscapedFsPath(FilePath);
1295     if (ExecSqlInt(sql2.str(), s) > 0) goto next;
1296    
1297     BindTextParam(pStmt, 1, instrumentName);
1298     BindIntParam(pStmt, 3, instrIndex);
1299    
1300     BindTextParam(pStmt, 6, info->comments);
1301     BindIntParam(pStmt, 7, info->isDrum);
1302    
1303     res = sqlite3_step(pStmt);
1304     if (res != SQLITE_DONE) {
1305     throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1306 iliev 1161 }
1307 schoenebeck 3092 res = sqlite3_reset(pStmt);
1308     FireInstrumentCountChanged(DbDir);
1309    
1310     next:
1311     if (Index != -1) break;
1312    
1313     instrIndex++;
1314     info = fileInfo->getInstrumentInfo(instrIndex, pProgress);
1315 iliev 1161 }
1316 schoenebeck 3092 } catch (Exception e) {
1317     if (pStmt) sqlite3_finalize(pStmt);
1318     if (fileInfo) delete fileInfo;
1319 iliev 1881 if (unlocked) DbInstrumentsMutex.Lock();
1320 iliev 1161 std::stringstream ss;
1321 schoenebeck 3092 ss << "Failed to scan `" << FilePath << "`: " << e.Message();
1322 iliev 1161 throw Exception(ss.str());
1323     } catch (...) {
1324 schoenebeck 3092 if (pStmt) sqlite3_finalize(pStmt);
1325     if (fileInfo) delete fileInfo;
1326 iliev 1881 if (unlocked) DbInstrumentsMutex.Lock();
1327 iliev 1717 throw Exception("Failed to scan `" + FilePath + "`");
1328 iliev 1161 }
1329 schoenebeck 3092 if (pStmt) sqlite3_finalize(pStmt);
1330     if (fileInfo) delete fileInfo;
1331     if (unlocked) DbInstrumentsMutex.Lock();
1332 iliev 1161 }
1333    
1334 iliev 1345 void InstrumentsDb::DirectoryTreeWalk(String AbstractPath, DirectoryHandler* pHandler) {
1335     int DirId = GetDirectoryId(AbstractPath);
1336     if(DirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(AbstractPath));
1337     DirectoryTreeWalk(pHandler, AbstractPath, DirId, 0);
1338 iliev 1187 }
1339    
1340 iliev 1345 void InstrumentsDb::DirectoryTreeWalk(DirectoryHandler* pHandler, String AbstractPath, int DirId, int Level) {
1341 iliev 1187 if(Level == 1000) throw Exception("Possible infinite loop detected");
1342 iliev 1345 pHandler->ProcessDirectory(AbstractPath, DirId);
1343 iliev 1187
1344     String s;
1345     StringListPtr pDirs = GetDirectories(DirId);
1346     for(int i = 0; i < pDirs->size(); i++) {
1347 iliev 1345 if (AbstractPath.length() == 1 && AbstractPath.at(0) == '/') {
1348     s = "/" + pDirs->at(i);
1349     } else {
1350     s = AbstractPath + "/" + pDirs->at(i);
1351     }
1352 iliev 1187 DirectoryTreeWalk(pHandler, s, GetDirectoryId(DirId, pDirs->at(i)), Level + 1);
1353     }
1354     }
1355    
1356     StringListPtr InstrumentsDb::FindDirectories(String Dir, SearchQuery* pQuery, bool Recursive) {
1357     dmsg(2,("InstrumentsDb: FindDirectories(Dir=%s)\n", Dir.c_str()));
1358     DirectoryFinder directoryFinder(pQuery);
1359    
1360     BeginTransaction();
1361     try {
1362     int DirId = GetDirectoryId(Dir);
1363 iliev 1345 if(DirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
1364 iliev 1187
1365     if (Recursive) DirectoryTreeWalk(Dir, &directoryFinder);
1366     else directoryFinder.ProcessDirectory(Dir, DirId);
1367     } catch (Exception e) {
1368     EndTransaction();
1369     throw e;
1370     }
1371     EndTransaction();
1372    
1373     return directoryFinder.GetDirectories();
1374     }
1375    
1376     StringListPtr InstrumentsDb::FindInstruments(String Dir, SearchQuery* pQuery, bool Recursive) {
1377     dmsg(2,("InstrumentsDb: FindInstruments(Dir=%s)\n", Dir.c_str()));
1378     InstrumentFinder instrumentFinder(pQuery);
1379    
1380     BeginTransaction();
1381     try {
1382     int DirId = GetDirectoryId(Dir);
1383 iliev 1345 if(DirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
1384 iliev 1187
1385     if (Recursive) DirectoryTreeWalk(Dir, &instrumentFinder);
1386     else instrumentFinder.ProcessDirectory(Dir, DirId);
1387     } catch (Exception e) {
1388     EndTransaction();
1389     throw e;
1390     }
1391     EndTransaction();
1392    
1393     return instrumentFinder.GetInstruments();
1394     }
1395 iliev 1727
1396     StringListPtr InstrumentsDb::FindLostInstrumentFiles() {
1397     dmsg(2,("InstrumentsDb: FindLostInstrumentFiles()\n"));
1398 iliev 1187
1399 iliev 1727 BeginTransaction();
1400     try {
1401     StringListPtr files = ExecSqlStringList("SELECT DISTINCT instr_file FROM instruments");
1402     StringListPtr result(new std::vector<String>);
1403     for (int i = 0; i < files->size(); i++) {
1404     File f(toNonEscapedFsPath(files->at(i)));
1405     if (!f.Exist()) result->push_back(files->at(i));
1406     }
1407 schoenebeck 3101 EndTransaction();
1408 iliev 1727 return result;
1409     } catch (Exception e) {
1410     EndTransaction();
1411     throw e;
1412     }
1413     }
1414    
1415     void InstrumentsDb::SetInstrumentFilePath(String OldPath, String NewPath) {
1416     if (OldPath == NewPath) return;
1417     StringListPtr instrs;
1418     BeginTransaction();
1419     try {
1420     std::vector<String> params(2);
1421     params[0] = toEscapedFsPath(NewPath);
1422     params[1] = toEscapedFsPath(OldPath);
1423     instrs = GetInstrumentsByFile(OldPath);
1424     ExecSql("UPDATE instruments SET instr_file=? WHERE instr_file=?", params);
1425     } catch (Exception e) {
1426     EndTransaction();
1427     throw e;
1428     }
1429     EndTransaction();
1430    
1431     for (int i = 0; i < instrs->size(); i++) {
1432     FireInstrumentInfoChanged(instrs->at(i));
1433     }
1434     }
1435    
1436 iliev 1187 void InstrumentsDb::BeginTransaction() {
1437     dmsg(2,("InstrumentsDb: BeginTransaction(InTransaction=%d)\n", InTransaction));
1438     DbInstrumentsMutex.Lock();
1439     if (InTransaction) return;
1440    
1441     if(db == NULL) return;
1442     sqlite3_stmt *pStmt = NULL;
1443    
1444     InTransaction = true;
1445     int res = sqlite3_prepare(db, "BEGIN TRANSACTION", -1, &pStmt, NULL);
1446     if (res != SQLITE_OK) {
1447     std::cerr << ToString(sqlite3_errmsg(db)) << std::endl;
1448     return;
1449     }
1450    
1451     res = sqlite3_step(pStmt);
1452     if(res != SQLITE_DONE) {
1453     sqlite3_finalize(pStmt);
1454     std::cerr << ToString(sqlite3_errmsg(db)) << std::endl;
1455     return;
1456     }
1457    
1458     sqlite3_finalize(pStmt);
1459     }
1460    
1461     void InstrumentsDb::EndTransaction() {
1462     dmsg(2,("InstrumentsDb: EndTransaction(InTransaction=%d)\n", InTransaction));
1463     if (!InTransaction) {
1464     DbInstrumentsMutex.Unlock();
1465     return;
1466     }
1467     InTransaction = false;
1468    
1469 persson 2427 if (db == NULL) {
1470 iliev 1187 DbInstrumentsMutex.Unlock();
1471     return;
1472     }
1473     sqlite3_stmt *pStmt = NULL;
1474    
1475     int res = sqlite3_prepare(db, "END TRANSACTION", -1, &pStmt, NULL);
1476     if (res != SQLITE_OK) {
1477     std::cerr << ToString(sqlite3_errmsg(db)) << std::endl;
1478     DbInstrumentsMutex.Unlock();
1479     return;
1480     }
1481    
1482     res = sqlite3_step(pStmt);
1483     if(res != SQLITE_DONE) {
1484     sqlite3_finalize(pStmt);
1485     std::cerr << ToString(sqlite3_errmsg(db)) << std::endl;
1486     DbInstrumentsMutex.Unlock();
1487     return;
1488     }
1489    
1490     sqlite3_finalize(pStmt);
1491     DbInstrumentsMutex.Unlock();
1492     }
1493    
1494 iliev 1161 void InstrumentsDb::ExecSql(String Sql) {
1495     dmsg(2,("InstrumentsDb: ExecSql(Sql=%s)\n", Sql.c_str()));
1496 iliev 1727 std::vector<String> Params;
1497     ExecSql(Sql, Params);
1498 iliev 1161 }
1499    
1500     void InstrumentsDb::ExecSql(String Sql, String Param) {
1501     dmsg(2,("InstrumentsDb: ExecSql(Sql=%s,Param=%s)\n", Sql.c_str(), Param.c_str()));
1502 iliev 1727 std::vector<String> Params;
1503     Params.push_back(Param);
1504     ExecSql(Sql, Params);
1505     }
1506    
1507     void InstrumentsDb::ExecSql(String Sql, std::vector<String>& Params) {
1508     dmsg(2,("InstrumentsDb: ExecSql(Sql=%s,Params)\n", Sql.c_str()));
1509 iliev 1161 sqlite3_stmt *pStmt = NULL;
1510    
1511     int res = sqlite3_prepare(GetDb(), Sql.c_str(), -1, &pStmt, NULL);
1512     if (res != SQLITE_OK) {
1513     sqlite3_finalize(pStmt);
1514     throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1515     }
1516    
1517 iliev 1727 for(int i = 0; i < Params.size(); i++) {
1518     BindTextParam(pStmt, i + 1, Params[i]);
1519     }
1520 iliev 1161
1521     res = sqlite3_step(pStmt);
1522     if (res != SQLITE_DONE) {
1523     sqlite3_finalize(pStmt);
1524     throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1525     }
1526    
1527     sqlite3_finalize(pStmt);
1528     }
1529    
1530     int InstrumentsDb::ExecSqlInt(String Sql) {
1531     dmsg(2,("InstrumentsDb: ExecSqlInt(Sql=%s)\n", Sql.c_str()));
1532     sqlite3_stmt *pStmt = NULL;
1533    
1534     int res = sqlite3_prepare(GetDb(), Sql.c_str(), -1, &pStmt, NULL);
1535     if (res != SQLITE_OK) {
1536     throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1537     }
1538    
1539     int i = -1;
1540     res = sqlite3_step(pStmt);
1541     if(res == SQLITE_ROW) {
1542     i = sqlite3_column_int(pStmt, 0);
1543     } else if (res != SQLITE_DONE) {
1544     sqlite3_finalize(pStmt);
1545     throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1546     }
1547    
1548     sqlite3_finalize(pStmt);
1549    
1550     return i;
1551     }
1552    
1553     int InstrumentsDb::ExecSqlInt(String Sql, String Param) {
1554     dmsg(2,("InstrumentsDb: ExecSqlInt(Sql=%s,Param=%s)\n", Sql.c_str(), Param.c_str()));
1555     sqlite3_stmt *pStmt = NULL;
1556    
1557     int res = sqlite3_prepare(GetDb(), Sql.c_str(), -1, &pStmt, NULL);
1558     if (res != SQLITE_OK) {
1559     throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1560     }
1561    
1562     BindTextParam(pStmt, 1, Param);
1563    
1564     int i = -1;
1565     res = sqlite3_step(pStmt);
1566     if(res == SQLITE_ROW) {
1567     i = sqlite3_column_int(pStmt, 0);
1568     } else if (res != SQLITE_DONE) {
1569     sqlite3_finalize(pStmt);
1570     throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1571     }
1572    
1573     sqlite3_finalize(pStmt);
1574     return i;
1575     }
1576    
1577     String InstrumentsDb::ExecSqlString(String Sql) {
1578     dmsg(2,("InstrumentsDb: ExecSqlString(Sql=%s)\n", Sql.c_str()));
1579     sqlite3_stmt *pStmt = NULL;
1580    
1581     int res = sqlite3_prepare(GetDb(), Sql.c_str(), -1, &pStmt, NULL);
1582     if (res != SQLITE_OK) {
1583     throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1584     }
1585    
1586     String s;
1587     res = sqlite3_step(pStmt);
1588     if(res == SQLITE_ROW) {
1589     s = ToString(sqlite3_column_text(pStmt, 0));
1590     } else if (res != SQLITE_DONE) {
1591     sqlite3_finalize(pStmt);
1592     throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1593     }
1594    
1595     sqlite3_finalize(pStmt);
1596    
1597     return s;
1598     }
1599    
1600     IntListPtr InstrumentsDb::ExecSqlIntList(String Sql) {
1601 iliev 1727 dmsg(2,("InstrumentsDb: ExecSqlIntList(Sql=%s)\n", Sql.c_str()));
1602     std::vector<String> Params;
1603     return ExecSqlIntList(Sql, Params);
1604     }
1605    
1606     IntListPtr InstrumentsDb::ExecSqlIntList(String Sql, String Param) {
1607     dmsg(2,("InstrumentsDb: ExecSqlIntList(Sql=%s,Param=%s)\n", Sql.c_str(), Param.c_str()));
1608     std::vector<String> Params;
1609     Params.push_back(Param);
1610     return ExecSqlIntList(Sql, Params);
1611     }
1612    
1613     IntListPtr InstrumentsDb::ExecSqlIntList(String Sql, std::vector<String>& Params) {
1614     dmsg(2,("InstrumentsDb: ExecSqlIntList(Sql=%s)\n", Sql.c_str()));
1615 iliev 1161 IntListPtr intList(new std::vector<int>);
1616    
1617     sqlite3_stmt *pStmt = NULL;
1618    
1619     int res = sqlite3_prepare(GetDb(), Sql.c_str(), -1, &pStmt, NULL);
1620     if (res != SQLITE_OK) {
1621     throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1622     }
1623    
1624 iliev 1727 for(int i = 0; i < Params.size(); i++) {
1625     BindTextParam(pStmt, i + 1, Params[i]);
1626     }
1627    
1628 iliev 1161 res = sqlite3_step(pStmt);
1629     while(res == SQLITE_ROW) {
1630     intList->push_back(sqlite3_column_int(pStmt, 0));
1631     res = sqlite3_step(pStmt);
1632     }
1633    
1634     if (res != SQLITE_DONE) {
1635     sqlite3_finalize(pStmt);
1636     throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1637     }
1638    
1639     sqlite3_finalize(pStmt);
1640    
1641     return intList;
1642     }
1643    
1644     StringListPtr InstrumentsDb::ExecSqlStringList(String Sql) {
1645 iliev 1727 dmsg(2,("InstrumentsDb: ExecSqlStringList(Sql=%s)\n", Sql.c_str()));
1646 iliev 1161 StringListPtr stringList(new std::vector<String>);
1647    
1648     sqlite3_stmt *pStmt = NULL;
1649    
1650     int res = sqlite3_prepare(GetDb(), Sql.c_str(), -1, &pStmt, NULL);
1651     if (res != SQLITE_OK) {
1652     throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1653     }
1654    
1655     res = sqlite3_step(pStmt);
1656     while(res == SQLITE_ROW) {
1657     stringList->push_back(ToString(sqlite3_column_text(pStmt, 0)));
1658     res = sqlite3_step(pStmt);
1659     }
1660    
1661     if (res != SQLITE_DONE) {
1662     sqlite3_finalize(pStmt);
1663     throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1664     }
1665    
1666     sqlite3_finalize(pStmt);
1667    
1668     return stringList;
1669     }
1670    
1671     void InstrumentsDb::BindTextParam(sqlite3_stmt* pStmt, int Index, String Text) {
1672     if (pStmt == NULL) return;
1673 schoenebeck 3050 int res = sqlite3_bind_text(pStmt, Index, Text.c_str(), -1, SQLITE_TRANSIENT);
1674 iliev 1161 if (res != SQLITE_OK) {
1675     sqlite3_finalize(pStmt);
1676     throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1677     }
1678     }
1679    
1680     void InstrumentsDb::BindIntParam(sqlite3_stmt* pStmt, int Index, int Param) {
1681     if (pStmt == NULL) return;
1682     int res = sqlite3_bind_int(pStmt, Index, Param);
1683     if (res != SQLITE_OK) {
1684     sqlite3_finalize(pStmt);
1685     throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1686     }
1687     }
1688    
1689 persson 1908 #ifndef WIN32
1690 iliev 1187 void InstrumentsDb::Regexp(sqlite3_context* pContext, int argc, sqlite3_value** ppValue) {
1691     if (argc != 2) return;
1692    
1693     String pattern = ToString(sqlite3_value_text(ppValue[0]));
1694     String str = ToString(sqlite3_value_text(ppValue[1]));
1695    
1696     if(!fnmatch(pattern.c_str(), str.c_str(), FNM_CASEFOLD)) {
1697     sqlite3_result_int(pContext, 1);
1698     }
1699     }
1700 persson 1908 #endif
1701 iliev 1187
1702 iliev 1161 String InstrumentsDb::GetDirectoryPath(String File) {
1703     if (File.empty()) return String("");
1704     if (File.at(0) != '/') String("");
1705     if (File.length() == 1) return File;
1706     if (File.at(File.length() - 1) == '/') return File.substr(0, File.length() - 1);
1707 schoenebeck 3101 int i = (int) File.rfind('/', File.length() - 1);
1708 iliev 1161 if(i == std::string::npos) return String("");
1709     if(i == 0) return String("/");
1710     return File.substr(0, i);
1711     }
1712    
1713     String InstrumentsDb::GetFileName(String Path) {
1714     if (Path.length() < 2) return String("");
1715     if (Path.at(0) != '/') String("");
1716     if (Path.at(Path.length() - 1) == '/') return String("");
1717 schoenebeck 3101 int i = (int) Path.rfind('/', Path.length() - 1);
1718 iliev 1161 return Path.substr(i + 1);
1719     }
1720    
1721     void InstrumentsDb::CheckPathName(String Path) {
1722     if (Path.empty()) return;
1723    
1724 schoenebeck 3101 int i = 0, j = (int)Path.find('/', i);
1725 iliev 1161
1726     while(j != std::string::npos) {
1727     if (j + 1 >= Path.length()) return;
1728     if (Path.at(j + 1) == '/') throw Exception("Invalid path name: " + Path);
1729    
1730     i = j + 1;
1731 schoenebeck 3101 j = (int) Path.find('/', i);
1732 iliev 1161 }
1733     }
1734    
1735     String InstrumentsDb::GetParentDirectory(String Dir) {
1736     if (Dir.length() < 2) return String("");
1737     if (Dir.at(0) != '/') String("");
1738 schoenebeck 3101 int i = (int) Dir.rfind('/', Dir.length() - 2);
1739 iliev 1161 if (i == 0) return "/";
1740     return Dir.substr(0, i);
1741     }
1742    
1743 iliev 1353 void InstrumentsDb::Format() {
1744 persson 2427 {
1745     LockGuard lock(DbInstrumentsMutex);
1746 iliev 1353
1747 persson 2427 if (db != NULL) {
1748     sqlite3_close(db);
1749     db = NULL;
1750     }
1751    
1752 schoenebeck 3091 if (DbFile.empty()) DbFile = GetDefaultDBLocation();
1753 persson 2427 String bkp = DbFile + ".bkp";
1754     remove(bkp.c_str());
1755     if (rename(DbFile.c_str(), bkp.c_str()) && errno != ENOENT) {
1756     throw Exception(String("Failed to backup database: ") + strerror(errno));
1757     }
1758 iliev 1353
1759 persson 2427 String f = DbFile;
1760     DbFile = "";
1761     CreateInstrumentsDb(f);
1762 iliev 1353 }
1763     FireDirectoryCountChanged("/");
1764     FireInstrumentCountChanged("/");
1765     }
1766    
1767 iliev 1161 void InstrumentsDb::CheckFileName(String File) {
1768     if (File.empty()) throw Exception("Invalid file name: " + File);
1769     }
1770    
1771 iliev 1782 String InstrumentsDb::GetUniqueName(int DirId, String Name) {
1772 iliev 1161 dmsg(2,("InstrumentsDb: GetUniqueInstrumentName(DirId=%d,Name=%s)\n", DirId, Name.c_str()));
1773    
1774 iliev 1187 if (GetInstrumentId(DirId, Name) == -1 && GetDirectoryId(DirId, Name) == -1) return Name;
1775 iliev 1161 std::stringstream ss;
1776     for(int i = 2; i < 1001; i++) {
1777     ss.str("");
1778     ss << Name << '[' << i << ']';
1779 iliev 1187 if (GetInstrumentId(DirId, ss.str()) == -1 && GetInstrumentId(DirId, ss.str()) == -1) {
1780     return ss.str();
1781     }
1782 iliev 1161 }
1783    
1784     throw Exception("Unable to find an unique name: " + Name);
1785     }
1786 iliev 1782
1787     String InstrumentsDb::PrepareSubdirectory(String DbDir, String FsPath) {
1788     std::string dir = Path::getBaseName(FsPath);
1789     dir = toAbstractName(dir);
1790     if(dir.empty()) dir = "New Directory";
1791     dir = GetUniqueName(GetDirectoryId(DbDir), dir);
1792     dir = AppendNode(DbDir, dir);
1793     AddDirectory(dir);
1794     return dir;
1795     }
1796 iliev 1200
1797 iliev 1782 String InstrumentsDb::AppendNode(String DbDir, String Node) {
1798 iliev 1810 if(DbDir.length() == 1 && DbDir.at(0) == '/') return DbDir + Node;
1799     if(DbDir.at(DbDir.length() - 1) == '/') return DbDir + Node;
1800     return DbDir + "/" + Node;
1801 iliev 1782 }
1802    
1803 iliev 1345 String InstrumentsDb::toDbName(String AbstractName) {
1804     for (int i = 0; i < AbstractName.length(); i++) {
1805     if (AbstractName.at(i) == '\0') AbstractName.at(i) = '/';
1806     }
1807     return AbstractName;
1808     }
1809    
1810     String InstrumentsDb::toEscapedPath(String AbstractName) {
1811     for (int i = 0; i < AbstractName.length(); i++) {
1812 iliev 1350 if (AbstractName.at(i) == '\0') AbstractName.replace(i++, 1, "\\x2f");
1813 iliev 1345 else if (AbstractName.at(i) == '\\') AbstractName.replace(i++, 1, "\\\\");
1814     else if (AbstractName.at(i) == '\'') AbstractName.replace(i++, 1, "\\'");
1815     else if (AbstractName.at(i) == '"') AbstractName.replace(i++, 1, "\\\"");
1816     else if (AbstractName.at(i) == '\r') AbstractName.replace(i++, 1, "\\r");
1817     else if (AbstractName.at(i) == '\n') AbstractName.replace(i++, 1, "\\n");
1818     }
1819     return AbstractName;
1820     }
1821    
1822     String InstrumentsDb::toEscapedText(String text) {
1823     for (int i = 0; i < text.length(); i++) {
1824     if (text.at(i) == '\\') text.replace(i++, 1, "\\\\");
1825     else if (text.at(i) == '\'') text.replace(i++, 1, "\\'");
1826     else if (text.at(i) == '"') text.replace(i++, 1, "\\\"");
1827     else if (text.at(i) == '\r') text.replace(i++, 1, "\\r");
1828     else if (text.at(i) == '\n') text.replace(i++, 1, "\\n");
1829     }
1830     return text;
1831     }
1832    
1833 iliev 1727 String InstrumentsDb::toNonEscapedText(String text) {
1834     String sb;
1835     for (int i = 0; i < text.length(); i++) {
1836     char c = text.at(i);
1837     if(c == '\\') {
1838     if(i >= text.length()) {
1839     std::cerr << "Broken escape sequence!" << std::endl;
1840     break;
1841     }
1842     char c2 = text.at(++i);
1843     if(c2 == '\'') sb.push_back('\'');
1844     else if(c2 == '"') sb.push_back('"');
1845     else if(c2 == '\\') sb.push_back('\\');
1846     else if(c2 == 'r') sb.push_back('\r');
1847     else if(c2 == 'n') sb.push_back('\n');
1848     else std::cerr << "Unknown escape sequence \\" << c2 << std::endl;
1849     } else {
1850     sb.push_back(c);
1851     }
1852     }
1853     return sb;
1854     }
1855    
1856 iliev 1350 String InstrumentsDb::toEscapedFsPath(String FsPath) {
1857 persson 1943 #ifdef WIN32
1858     replace(FsPath.begin(), FsPath.end(), '\\', '/');
1859     #endif
1860 iliev 1350 return toEscapedText(FsPath);
1861 iliev 1345 }
1862    
1863 iliev 1727 String InstrumentsDb::toNonEscapedFsPath(String FsPath) {
1864 persson 1943 FsPath = toNonEscapedText(FsPath);
1865     #ifdef WIN32
1866     replace(FsPath.begin(), FsPath.end(), '/', '\\');
1867     #endif
1868     return FsPath;
1869 iliev 1727 }
1870    
1871 iliev 1345 String InstrumentsDb::toAbstractName(String DbName) {
1872     for (int i = 0; i < DbName.length(); i++) {
1873     if (DbName.at(i) == '/') DbName.at(i) = '\0';
1874     }
1875     return DbName;
1876     }
1877    
1878 iliev 1161 void InstrumentsDb::FireDirectoryCountChanged(String Dir) {
1879     for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1880     llInstrumentsDbListeners.GetListener(i)->DirectoryCountChanged(Dir);
1881     }
1882     }
1883 iliev 1200
1884 iliev 1161 void InstrumentsDb::FireDirectoryInfoChanged(String Dir) {
1885     for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1886     llInstrumentsDbListeners.GetListener(i)->DirectoryInfoChanged(Dir);
1887     }
1888     }
1889 iliev 1200
1890 iliev 1161 void InstrumentsDb::FireDirectoryNameChanged(String Dir, String NewName) {
1891     for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1892     llInstrumentsDbListeners.GetListener(i)->DirectoryNameChanged(Dir, NewName);
1893     }
1894     }
1895 iliev 1200
1896 iliev 1161 void InstrumentsDb::FireInstrumentCountChanged(String Dir) {
1897     for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1898     llInstrumentsDbListeners.GetListener(i)->InstrumentCountChanged(Dir);
1899     }
1900     }
1901 iliev 1200
1902 iliev 1161 void InstrumentsDb::FireInstrumentInfoChanged(String Instr) {
1903     for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1904     llInstrumentsDbListeners.GetListener(i)->InstrumentInfoChanged(Instr);
1905     }
1906     }
1907 iliev 1200
1908 iliev 1161 void InstrumentsDb::FireInstrumentNameChanged(String Instr, String NewName) {
1909     for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1910     llInstrumentsDbListeners.GetListener(i)->InstrumentNameChanged(Instr, NewName);
1911     }
1912     }
1913    
1914 iliev 1200 void InstrumentsDb::FireJobStatusChanged(int JobId) {
1915     for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1916     llInstrumentsDbListeners.GetListener(i)->JobStatusChanged(JobId);
1917 iliev 1161 }
1918     }
1919    
1920     } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC