/[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 1912 - (hide annotations) (download)
Sat Jun 6 16:48:00 2009 UTC (14 years, 9 months ago) by senoner
File size: 72041 byte(s)
* Instruments DB on Windows gets automatically created if not present

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

  ViewVC Help
Powered by ViewVC