/[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 1910 - (hide annotations) (download)
Fri Jun 5 14:22:20 2009 UTC (14 years, 10 months ago) by senoner
File size: 71407 byte(s)
* Added Instruments DB on Windows.
* Relative path support for DB file (stdalone and VST) not implemented yet

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

  ViewVC Help
Powered by ViewVC