/[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 1644 - (hide annotations) (download)
Sat Jan 19 16:55:03 2008 UTC (16 years, 3 months ago) by persson
File size: 65992 byte(s)
* fixed memory leaks that occurred when liblinuxsampler was unloaded
* fixed a memory leak that could happen when a channel was deleted
  while notes were playing
* fixed memory management bug in ASIO driver
* optimized the SynchronizedConfig class so it doesn't wait
  unnecessarily long after an update

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

  ViewVC Help
Powered by ViewVC