/[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 1603 - (hide annotations) (download)
Mon Dec 31 10:17:51 2007 UTC (16 years, 3 months ago) by iliev
File size: 66051 byte(s)
* avoid time consuming samples scanning when
  adding instruments to the instruments database

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

  ViewVC Help
Powered by ViewVC