/[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 1642 - (hide annotations) (download)
Sun Jan 13 16:36:14 2008 UTC (16 years, 3 months ago) by nagata
File size: 66185 byte(s)
* OSX: Definition of ATOMIC_INIT is added
* OSX: "~" in DB/plugin names are expanded to "$HOME"
* OSX: MIDI device name are now "linuxsampler_in_%d" where %d=0,1,etc.

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

  ViewVC Help
Powered by ViewVC