/[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 1881 - (hide annotations) (download)
Mon Mar 30 16:56:41 2009 UTC (15 years ago) by iliev
File size: 71208 byte(s)
* Unlock the access to the instruments database while scanning a gig file

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

  ViewVC Help
Powered by ViewVC