/[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 1782 - (hide annotations) (download)
Tue Sep 30 02:16:41 2008 UTC (15 years, 6 months ago) by iliev
File size: 70479 byte(s)
* updated the lscp spec
* code cleanup in InstrumentsDb

1 iliev 1161 /***************************************************************************
2     * *
3 persson 1644 * Copyright (C) 2007, 2008 Grigor Iliev *
4 iliev 1161 * *
5     * This program is free software; you can redistribute it and/or modify *
6     * it under the terms of the GNU General Public License as published by *
7     * the Free Software Foundation; either version 2 of the License, or *
8     * (at your option) any later version. *
9     * *
10     * This program is distributed in the hope that it will be useful, *
11     * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13     * GNU General Public License for more details. *
14     * *
15     * You should have received a copy of the GNU General Public License *
16     * along with this program; if not, write to the Free Software *
17     * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, *
18     * MA 02110-1301 USA *
19     ***************************************************************************/
20    
21     #include "InstrumentsDb.h"
22    
23 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     RIFF::File* riff = NULL;
1181     gig::File* gig = NULL;
1182     try {
1183 iliev 1717 riff = new RIFF::File(FilePath);
1184 iliev 1161 gig::File* gig = new gig::File(riff);
1185 iliev 1603 gig->SetAutoLoad(false); // avoid time consuming samples scanning
1186 iliev 1200
1187 iliev 1161 std::stringstream sql;
1188     sql << "INSERT INTO instruments (dir_id,instr_name,instr_file,";
1189     sql << "instr_nr,format_family,format_version,instr_size,";
1190     sql << "description,is_drum,product,artists,keywords) VALUES (";
1191 iliev 1717 sql << dirId << ",?,?,?,'GIG',?," << f.GetSize() << ",?,?,?,?,?)";
1192 iliev 1161
1193     sqlite3_stmt* pStmt = NULL;
1194    
1195     int res = sqlite3_prepare(GetDb(), sql.str().c_str(), -1, &pStmt, NULL);
1196     if (res != SQLITE_OK) {
1197     throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1198     }
1199    
1200 iliev 1717 String s = toEscapedFsPath(FilePath);
1201 iliev 1350 BindTextParam(pStmt, 2, s);
1202 iliev 1161 String ver = "";
1203     if (gig->pVersion != NULL) ver = ToString(gig->pVersion->major);
1204     BindTextParam(pStmt, 4, ver);
1205    
1206     if (Index == -1) {
1207     int instrIndex = 0;
1208 iliev 1200 if (pProgress != NULL) gig->GetInstrument(0, &(pProgress->GigFileProgress)); // TODO: this workaround should be fixed
1209 iliev 1161 gig::Instrument* pInstrument = gig->GetFirstInstrument();
1210     while (pInstrument) {
1211     BindTextParam(pStmt, 7, gig->pInfo->Product);
1212     BindTextParam(pStmt, 8, gig->pInfo->Artists);
1213     BindTextParam(pStmt, 9, gig->pInfo->Keywords);
1214 iliev 1717 AddGigInstrument(pStmt, DbDir, dirId, FilePath, pInstrument, instrIndex);
1215 iliev 1161
1216     instrIndex++;
1217     pInstrument = gig->GetNextInstrument();
1218     }
1219     } else {
1220 iliev 1200 gig::Instrument* pInstrument;
1221     if (pProgress == NULL) pInstrument = gig->GetInstrument(Index);
1222     else pInstrument = gig->GetInstrument(Index, &(pProgress->GigFileProgress));
1223 iliev 1161 if (pInstrument != NULL) {
1224     BindTextParam(pStmt, 7, gig->pInfo->Product);
1225     BindTextParam(pStmt, 8, gig->pInfo->Artists);
1226     BindTextParam(pStmt, 9, gig->pInfo->Keywords);
1227 iliev 1717 AddGigInstrument(pStmt, DbDir, dirId, FilePath, pInstrument, Index);
1228 iliev 1161 }
1229     }
1230    
1231 iliev 1187 sqlite3_finalize(pStmt);
1232 iliev 1161 delete gig;
1233     delete riff;
1234     } catch (RIFF::Exception e) {
1235     if (gig != NULL) delete gig;
1236     if (riff != NULL) delete riff;
1237     std::stringstream ss;
1238 iliev 1717 ss << "Failed to scan `" << FilePath << "`: " << e.Message;
1239 iliev 1161
1240     throw Exception(ss.str());
1241     } catch (Exception e) {
1242     if (gig != NULL) delete gig;
1243     if (riff != NULL) delete riff;
1244     throw e;
1245     } catch (...) {
1246     if (gig != NULL) delete gig;
1247     if (riff != NULL) delete riff;
1248 iliev 1717 throw Exception("Failed to scan `" + FilePath + "`");
1249 iliev 1161 }
1250     }
1251    
1252 iliev 1187 void InstrumentsDb::AddGigInstrument(sqlite3_stmt* pStmt, String DbDir, int DirId, String File, gig::Instrument* pInstrument, int Index) {
1253 iliev 1717 dmsg(2,("InstrumentsDb: AddGigInstrument(DbDir=%s,DirId=%d,File=%s,Index=%d)\n", DbDir.c_str(), DirId, File.c_str(), Index));
1254 iliev 1161 String name = pInstrument->pInfo->Name;
1255     if (name == "") return;
1256 iliev 1782 name = GetUniqueName(DirId, name);
1257 iliev 1161
1258     std::stringstream sql2;
1259     sql2 << "SELECT COUNT(*) FROM instruments WHERE instr_file=? AND ";
1260     sql2 << "instr_nr=" << Index;
1261 iliev 1350 String s = toEscapedFsPath(File);
1262     if (ExecSqlInt(sql2.str(), s) > 0) return;
1263 iliev 1161
1264     BindTextParam(pStmt, 1, name);
1265     BindIntParam(pStmt, 3, Index);
1266    
1267     BindTextParam(pStmt, 5, pInstrument->pInfo->Comments);
1268     BindIntParam(pStmt, 6, pInstrument->IsDrum);
1269    
1270     if (!pInstrument->pInfo->Product.empty()) {
1271     BindTextParam(pStmt, 7, pInstrument->pInfo->Product);
1272     }
1273     if (!pInstrument->pInfo->Artists.empty()) {
1274     BindTextParam(pStmt, 8, pInstrument->pInfo->Artists);
1275     }
1276    
1277     if (!pInstrument->pInfo->Keywords.empty()) {
1278     BindTextParam(pStmt, 9, pInstrument->pInfo->Keywords);
1279     }
1280    
1281     int res = sqlite3_step(pStmt);
1282     if(res != SQLITE_DONE) {
1283     sqlite3_finalize(pStmt);
1284     throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1285     }
1286    
1287     res = sqlite3_reset(pStmt);
1288     FireInstrumentCountChanged(DbDir);
1289     }
1290    
1291 iliev 1345 void InstrumentsDb::DirectoryTreeWalk(String AbstractPath, DirectoryHandler* pHandler) {
1292     int DirId = GetDirectoryId(AbstractPath);
1293     if(DirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(AbstractPath));
1294     DirectoryTreeWalk(pHandler, AbstractPath, DirId, 0);
1295 iliev 1187 }
1296    
1297 iliev 1345 void InstrumentsDb::DirectoryTreeWalk(DirectoryHandler* pHandler, String AbstractPath, int DirId, int Level) {
1298 iliev 1187 if(Level == 1000) throw Exception("Possible infinite loop detected");
1299 iliev 1345 pHandler->ProcessDirectory(AbstractPath, DirId);
1300 iliev 1187
1301     String s;
1302     StringListPtr pDirs = GetDirectories(DirId);
1303     for(int i = 0; i < pDirs->size(); i++) {
1304 iliev 1345 if (AbstractPath.length() == 1 && AbstractPath.at(0) == '/') {
1305     s = "/" + pDirs->at(i);
1306     } else {
1307     s = AbstractPath + "/" + pDirs->at(i);
1308     }
1309 iliev 1187 DirectoryTreeWalk(pHandler, s, GetDirectoryId(DirId, pDirs->at(i)), Level + 1);
1310     }
1311     }
1312    
1313     StringListPtr InstrumentsDb::FindDirectories(String Dir, SearchQuery* pQuery, bool Recursive) {
1314     dmsg(2,("InstrumentsDb: FindDirectories(Dir=%s)\n", Dir.c_str()));
1315     DirectoryFinder directoryFinder(pQuery);
1316    
1317     BeginTransaction();
1318     try {
1319     int DirId = GetDirectoryId(Dir);
1320 iliev 1345 if(DirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
1321 iliev 1187
1322     if (Recursive) DirectoryTreeWalk(Dir, &directoryFinder);
1323     else directoryFinder.ProcessDirectory(Dir, DirId);
1324     } catch (Exception e) {
1325     EndTransaction();
1326     throw e;
1327     }
1328     EndTransaction();
1329    
1330     return directoryFinder.GetDirectories();
1331     }
1332    
1333     StringListPtr InstrumentsDb::FindInstruments(String Dir, SearchQuery* pQuery, bool Recursive) {
1334     dmsg(2,("InstrumentsDb: FindInstruments(Dir=%s)\n", Dir.c_str()));
1335     InstrumentFinder instrumentFinder(pQuery);
1336    
1337     BeginTransaction();
1338     try {
1339     int DirId = GetDirectoryId(Dir);
1340 iliev 1345 if(DirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
1341 iliev 1187
1342     if (Recursive) DirectoryTreeWalk(Dir, &instrumentFinder);
1343     else instrumentFinder.ProcessDirectory(Dir, DirId);
1344     } catch (Exception e) {
1345     EndTransaction();
1346     throw e;
1347     }
1348     EndTransaction();
1349    
1350     return instrumentFinder.GetInstruments();
1351     }
1352 iliev 1727
1353     StringListPtr InstrumentsDb::FindLostInstrumentFiles() {
1354     dmsg(2,("InstrumentsDb: FindLostInstrumentFiles()\n"));
1355 iliev 1187
1356 iliev 1727 BeginTransaction();
1357     try {
1358     StringListPtr files = ExecSqlStringList("SELECT DISTINCT instr_file FROM instruments");
1359     StringListPtr result(new std::vector<String>);
1360     for (int i = 0; i < files->size(); i++) {
1361     File f(toNonEscapedFsPath(files->at(i)));
1362     if (!f.Exist()) result->push_back(files->at(i));
1363     }
1364     return result;
1365     } catch (Exception e) {
1366     EndTransaction();
1367     throw e;
1368     }
1369     EndTransaction();
1370     }
1371    
1372     void InstrumentsDb::SetInstrumentFilePath(String OldPath, String NewPath) {
1373     if (OldPath == NewPath) return;
1374     StringListPtr instrs;
1375     BeginTransaction();
1376     try {
1377     std::vector<String> params(2);
1378     params[0] = toEscapedFsPath(NewPath);
1379     params[1] = toEscapedFsPath(OldPath);
1380     instrs = GetInstrumentsByFile(OldPath);
1381     ExecSql("UPDATE instruments SET instr_file=? WHERE instr_file=?", params);
1382     } catch (Exception e) {
1383     EndTransaction();
1384     throw e;
1385     }
1386     EndTransaction();
1387    
1388     for (int i = 0; i < instrs->size(); i++) {
1389     FireInstrumentInfoChanged(instrs->at(i));
1390     }
1391     }
1392    
1393 iliev 1187 void InstrumentsDb::BeginTransaction() {
1394     dmsg(2,("InstrumentsDb: BeginTransaction(InTransaction=%d)\n", InTransaction));
1395     DbInstrumentsMutex.Lock();
1396     if (InTransaction) return;
1397    
1398     if(db == NULL) return;
1399     sqlite3_stmt *pStmt = NULL;
1400    
1401     InTransaction = true;
1402     int res = sqlite3_prepare(db, "BEGIN TRANSACTION", -1, &pStmt, NULL);
1403     if (res != SQLITE_OK) {
1404     std::cerr << ToString(sqlite3_errmsg(db)) << std::endl;
1405     return;
1406     }
1407    
1408     res = sqlite3_step(pStmt);
1409     if(res != SQLITE_DONE) {
1410     sqlite3_finalize(pStmt);
1411     std::cerr << ToString(sqlite3_errmsg(db)) << std::endl;
1412     return;
1413     }
1414    
1415     sqlite3_finalize(pStmt);
1416     }
1417    
1418     void InstrumentsDb::EndTransaction() {
1419     dmsg(2,("InstrumentsDb: EndTransaction(InTransaction=%d)\n", InTransaction));
1420     if (!InTransaction) {
1421     DbInstrumentsMutex.Unlock();
1422     return;
1423     }
1424     InTransaction = false;
1425    
1426     if(db == NULL) {
1427     DbInstrumentsMutex.Unlock();
1428     return;
1429     }
1430     sqlite3_stmt *pStmt = NULL;
1431    
1432     int res = sqlite3_prepare(db, "END TRANSACTION", -1, &pStmt, NULL);
1433     if (res != SQLITE_OK) {
1434     std::cerr << ToString(sqlite3_errmsg(db)) << std::endl;
1435     DbInstrumentsMutex.Unlock();
1436     return;
1437     }
1438    
1439     res = sqlite3_step(pStmt);
1440     if(res != SQLITE_DONE) {
1441     sqlite3_finalize(pStmt);
1442     std::cerr << ToString(sqlite3_errmsg(db)) << std::endl;
1443     DbInstrumentsMutex.Unlock();
1444     return;
1445     }
1446    
1447     sqlite3_finalize(pStmt);
1448     DbInstrumentsMutex.Unlock();
1449     }
1450    
1451 iliev 1161 void InstrumentsDb::ExecSql(String Sql) {
1452     dmsg(2,("InstrumentsDb: ExecSql(Sql=%s)\n", Sql.c_str()));
1453 iliev 1727 std::vector<String> Params;
1454     ExecSql(Sql, Params);
1455 iliev 1161 }
1456    
1457     void InstrumentsDb::ExecSql(String Sql, String Param) {
1458     dmsg(2,("InstrumentsDb: ExecSql(Sql=%s,Param=%s)\n", Sql.c_str(), Param.c_str()));
1459 iliev 1727 std::vector<String> Params;
1460     Params.push_back(Param);
1461     ExecSql(Sql, Params);
1462     }
1463    
1464     void InstrumentsDb::ExecSql(String Sql, std::vector<String>& Params) {
1465     dmsg(2,("InstrumentsDb: ExecSql(Sql=%s,Params)\n", Sql.c_str()));
1466 iliev 1161 sqlite3_stmt *pStmt = NULL;
1467    
1468     int res = sqlite3_prepare(GetDb(), Sql.c_str(), -1, &pStmt, NULL);
1469     if (res != SQLITE_OK) {
1470     sqlite3_finalize(pStmt);
1471     throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1472     }
1473    
1474 iliev 1727 for(int i = 0; i < Params.size(); i++) {
1475     BindTextParam(pStmt, i + 1, Params[i]);
1476     }
1477 iliev 1161
1478     res = sqlite3_step(pStmt);
1479     if (res != SQLITE_DONE) {
1480     sqlite3_finalize(pStmt);
1481     throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1482     }
1483    
1484     sqlite3_finalize(pStmt);
1485     }
1486    
1487     int InstrumentsDb::ExecSqlInt(String Sql) {
1488     dmsg(2,("InstrumentsDb: ExecSqlInt(Sql=%s)\n", Sql.c_str()));
1489     sqlite3_stmt *pStmt = NULL;
1490    
1491     int res = sqlite3_prepare(GetDb(), Sql.c_str(), -1, &pStmt, NULL);
1492     if (res != SQLITE_OK) {
1493     throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1494     }
1495    
1496     int i = -1;
1497     res = sqlite3_step(pStmt);
1498     if(res == SQLITE_ROW) {
1499     i = sqlite3_column_int(pStmt, 0);
1500     } else if (res != SQLITE_DONE) {
1501     sqlite3_finalize(pStmt);
1502     throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1503     }
1504    
1505     sqlite3_finalize(pStmt);
1506    
1507     return i;
1508     }
1509    
1510     int InstrumentsDb::ExecSqlInt(String Sql, String Param) {
1511     dmsg(2,("InstrumentsDb: ExecSqlInt(Sql=%s,Param=%s)\n", Sql.c_str(), Param.c_str()));
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     BindTextParam(pStmt, 1, Param);
1520    
1521     int i = -1;
1522     res = sqlite3_step(pStmt);
1523     if(res == SQLITE_ROW) {
1524     i = sqlite3_column_int(pStmt, 0);
1525     } else if (res != SQLITE_DONE) {
1526     sqlite3_finalize(pStmt);
1527     throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1528     }
1529    
1530     sqlite3_finalize(pStmt);
1531     return i;
1532     }
1533    
1534     String InstrumentsDb::ExecSqlString(String Sql) {
1535     dmsg(2,("InstrumentsDb: ExecSqlString(Sql=%s)\n", Sql.c_str()));
1536     sqlite3_stmt *pStmt = NULL;
1537    
1538     int res = sqlite3_prepare(GetDb(), Sql.c_str(), -1, &pStmt, NULL);
1539     if (res != SQLITE_OK) {
1540     throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1541     }
1542    
1543     String s;
1544     res = sqlite3_step(pStmt);
1545     if(res == SQLITE_ROW) {
1546     s = ToString(sqlite3_column_text(pStmt, 0));
1547     } else if (res != SQLITE_DONE) {
1548     sqlite3_finalize(pStmt);
1549     throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1550     }
1551    
1552     sqlite3_finalize(pStmt);
1553    
1554     return s;
1555     }
1556    
1557     IntListPtr InstrumentsDb::ExecSqlIntList(String Sql) {
1558 iliev 1727 dmsg(2,("InstrumentsDb: ExecSqlIntList(Sql=%s)\n", Sql.c_str()));
1559     std::vector<String> Params;
1560     return ExecSqlIntList(Sql, Params);
1561     }
1562    
1563     IntListPtr InstrumentsDb::ExecSqlIntList(String Sql, String Param) {
1564     dmsg(2,("InstrumentsDb: ExecSqlIntList(Sql=%s,Param=%s)\n", Sql.c_str(), Param.c_str()));
1565     std::vector<String> Params;
1566     Params.push_back(Param);
1567     return ExecSqlIntList(Sql, Params);
1568     }
1569    
1570     IntListPtr InstrumentsDb::ExecSqlIntList(String Sql, std::vector<String>& Params) {
1571     dmsg(2,("InstrumentsDb: ExecSqlIntList(Sql=%s)\n", Sql.c_str()));
1572 iliev 1161 IntListPtr intList(new std::vector<int>);
1573    
1574     sqlite3_stmt *pStmt = NULL;
1575    
1576     int res = sqlite3_prepare(GetDb(), Sql.c_str(), -1, &pStmt, NULL);
1577     if (res != SQLITE_OK) {
1578     throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1579     }
1580    
1581 iliev 1727 for(int i = 0; i < Params.size(); i++) {
1582     BindTextParam(pStmt, i + 1, Params[i]);
1583     }
1584    
1585 iliev 1161 res = sqlite3_step(pStmt);
1586     while(res == SQLITE_ROW) {
1587     intList->push_back(sqlite3_column_int(pStmt, 0));
1588     res = sqlite3_step(pStmt);
1589     }
1590    
1591     if (res != SQLITE_DONE) {
1592     sqlite3_finalize(pStmt);
1593     throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1594     }
1595    
1596     sqlite3_finalize(pStmt);
1597    
1598     return intList;
1599     }
1600    
1601     StringListPtr InstrumentsDb::ExecSqlStringList(String Sql) {
1602 iliev 1727 dmsg(2,("InstrumentsDb: ExecSqlStringList(Sql=%s)\n", Sql.c_str()));
1603 iliev 1161 StringListPtr stringList(new std::vector<String>);
1604    
1605     sqlite3_stmt *pStmt = NULL;
1606    
1607     int res = sqlite3_prepare(GetDb(), Sql.c_str(), -1, &pStmt, NULL);
1608     if (res != SQLITE_OK) {
1609     throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1610     }
1611    
1612     res = sqlite3_step(pStmt);
1613     while(res == SQLITE_ROW) {
1614     stringList->push_back(ToString(sqlite3_column_text(pStmt, 0)));
1615     res = sqlite3_step(pStmt);
1616     }
1617    
1618     if (res != SQLITE_DONE) {
1619     sqlite3_finalize(pStmt);
1620     throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1621     }
1622    
1623     sqlite3_finalize(pStmt);
1624    
1625     return stringList;
1626     }
1627    
1628     void InstrumentsDb::BindTextParam(sqlite3_stmt* pStmt, int Index, String Text) {
1629     if (pStmt == NULL) return;
1630     int res = sqlite3_bind_text(pStmt, Index, Text.c_str(), -1, SQLITE_STATIC);
1631     if (res != SQLITE_OK) {
1632     sqlite3_finalize(pStmt);
1633     throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1634     }
1635     }
1636    
1637     void InstrumentsDb::BindIntParam(sqlite3_stmt* pStmt, int Index, int Param) {
1638     if (pStmt == NULL) return;
1639     int res = sqlite3_bind_int(pStmt, Index, Param);
1640     if (res != SQLITE_OK) {
1641     sqlite3_finalize(pStmt);
1642     throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1643     }
1644     }
1645    
1646 iliev 1187 void InstrumentsDb::Regexp(sqlite3_context* pContext, int argc, sqlite3_value** ppValue) {
1647     if (argc != 2) return;
1648    
1649     String pattern = ToString(sqlite3_value_text(ppValue[0]));
1650     String str = ToString(sqlite3_value_text(ppValue[1]));
1651    
1652     if(!fnmatch(pattern.c_str(), str.c_str(), FNM_CASEFOLD)) {
1653     sqlite3_result_int(pContext, 1);
1654     }
1655     }
1656    
1657 iliev 1161 String InstrumentsDb::GetDirectoryPath(String File) {
1658     if (File.empty()) return String("");
1659     if (File.at(0) != '/') String("");
1660     if (File.length() == 1) return File;
1661     if (File.at(File.length() - 1) == '/') return File.substr(0, File.length() - 1);
1662     int i = File.rfind('/', File.length() - 1);
1663     if(i == std::string::npos) return String("");
1664     if(i == 0) return String("/");
1665     return File.substr(0, i);
1666     }
1667    
1668     String InstrumentsDb::GetFileName(String Path) {
1669     if (Path.length() < 2) return String("");
1670     if (Path.at(0) != '/') String("");
1671     if (Path.at(Path.length() - 1) == '/') return String("");
1672     int i = Path.rfind('/', Path.length() - 1);
1673     return Path.substr(i + 1);
1674     }
1675    
1676     void InstrumentsDb::CheckPathName(String Path) {
1677     if (Path.empty()) return;
1678    
1679     int i = 0, j = Path.find('/', i);
1680    
1681     while(j != std::string::npos) {
1682     if (j + 1 >= Path.length()) return;
1683     if (Path.at(j + 1) == '/') throw Exception("Invalid path name: " + Path);
1684    
1685     i = j + 1;
1686     j = Path.find('/', i);
1687     }
1688     }
1689    
1690     String InstrumentsDb::GetParentDirectory(String Dir) {
1691     if (Dir.length() < 2) return String("");
1692     if (Dir.at(0) != '/') String("");
1693     int i = Dir.rfind('/', Dir.length() - 2);
1694     if (i == 0) return "/";
1695     return Dir.substr(0, i);
1696     }
1697    
1698 iliev 1353 void InstrumentsDb::Format() {
1699     DbInstrumentsMutex.Lock();
1700     if (db != NULL) {
1701     sqlite3_close(db);
1702     db = NULL;
1703     }
1704    
1705 schoenebeck 1364 if (DbFile.empty()) DbFile = CONFIG_DEFAULT_INSTRUMENTS_DB_LOCATION;
1706 iliev 1353 String bkp = DbFile + ".bkp";
1707     remove(bkp.c_str());
1708     if (rename(DbFile.c_str(), bkp.c_str()) && errno != ENOENT) {
1709     DbInstrumentsMutex.Unlock();
1710     throw Exception(String("Failed to backup database: ") + strerror(errno));
1711     }
1712    
1713     String f = DbFile;
1714     DbFile = "";
1715     try { CreateInstrumentsDb(f); }
1716     catch(Exception e) {
1717     DbInstrumentsMutex.Unlock();
1718     throw e;
1719     }
1720     DbInstrumentsMutex.Unlock();
1721    
1722     FireDirectoryCountChanged("/");
1723     FireInstrumentCountChanged("/");
1724     }
1725    
1726 iliev 1161 void InstrumentsDb::CheckFileName(String File) {
1727     if (File.empty()) throw Exception("Invalid file name: " + File);
1728     }
1729    
1730 iliev 1782 String InstrumentsDb::GetUniqueName(int DirId, String Name) {
1731 iliev 1161 dmsg(2,("InstrumentsDb: GetUniqueInstrumentName(DirId=%d,Name=%s)\n", DirId, Name.c_str()));
1732    
1733 iliev 1187 if (GetInstrumentId(DirId, Name) == -1 && GetDirectoryId(DirId, Name) == -1) return Name;
1734 iliev 1161 std::stringstream ss;
1735     for(int i = 2; i < 1001; i++) {
1736     ss.str("");
1737     ss << Name << '[' << i << ']';
1738 iliev 1187 if (GetInstrumentId(DirId, ss.str()) == -1 && GetInstrumentId(DirId, ss.str()) == -1) {
1739     return ss.str();
1740     }
1741 iliev 1161 }
1742    
1743     throw Exception("Unable to find an unique name: " + Name);
1744     }
1745 iliev 1782
1746     String InstrumentsDb::PrepareSubdirectory(String DbDir, String FsPath) {
1747     std::string dir = Path::getBaseName(FsPath);
1748     dir = toAbstractName(dir);
1749     if(dir.empty()) dir = "New Directory";
1750     dir = GetUniqueName(GetDirectoryId(DbDir), dir);
1751     dir = AppendNode(DbDir, dir);
1752     AddDirectory(dir);
1753     return dir;
1754     }
1755 iliev 1200
1756 iliev 1782 String InstrumentsDb::AppendNode(String DbDir, String Node) {
1757     if(DbDir.length() == 1 && DbDir.at(0) == '/') return DbDir + Node + "/";
1758     return DbDir + "/" + Node + "/";
1759     }
1760    
1761 iliev 1345 String InstrumentsDb::toDbName(String AbstractName) {
1762     for (int i = 0; i < AbstractName.length(); i++) {
1763     if (AbstractName.at(i) == '\0') AbstractName.at(i) = '/';
1764     }
1765     return AbstractName;
1766     }
1767    
1768     String InstrumentsDb::toEscapedPath(String AbstractName) {
1769     for (int i = 0; i < AbstractName.length(); i++) {
1770 iliev 1350 if (AbstractName.at(i) == '\0') AbstractName.replace(i++, 1, "\\x2f");
1771 iliev 1345 else if (AbstractName.at(i) == '\\') AbstractName.replace(i++, 1, "\\\\");
1772     else if (AbstractName.at(i) == '\'') AbstractName.replace(i++, 1, "\\'");
1773     else if (AbstractName.at(i) == '"') AbstractName.replace(i++, 1, "\\\"");
1774     else if (AbstractName.at(i) == '\r') AbstractName.replace(i++, 1, "\\r");
1775     else if (AbstractName.at(i) == '\n') AbstractName.replace(i++, 1, "\\n");
1776     }
1777     return AbstractName;
1778     }
1779    
1780     String InstrumentsDb::toEscapedText(String text) {
1781     for (int i = 0; i < text.length(); i++) {
1782     if (text.at(i) == '\\') text.replace(i++, 1, "\\\\");
1783     else if (text.at(i) == '\'') text.replace(i++, 1, "\\'");
1784     else if (text.at(i) == '"') text.replace(i++, 1, "\\\"");
1785     else if (text.at(i) == '\r') text.replace(i++, 1, "\\r");
1786     else if (text.at(i) == '\n') text.replace(i++, 1, "\\n");
1787     }
1788     return text;
1789     }
1790    
1791 iliev 1727 String InstrumentsDb::toNonEscapedText(String text) {
1792     String sb;
1793     for (int i = 0; i < text.length(); i++) {
1794     char c = text.at(i);
1795     if(c == '\\') {
1796     if(i >= text.length()) {
1797     std::cerr << "Broken escape sequence!" << std::endl;
1798     break;
1799     }
1800     char c2 = text.at(++i);
1801     if(c2 == '\'') sb.push_back('\'');
1802     else if(c2 == '"') sb.push_back('"');
1803     else if(c2 == '\\') sb.push_back('\\');
1804     else if(c2 == 'r') sb.push_back('\r');
1805     else if(c2 == 'n') sb.push_back('\n');
1806     else std::cerr << "Unknown escape sequence \\" << c2 << std::endl;
1807     } else {
1808     sb.push_back(c);
1809     }
1810     }
1811     return sb;
1812     }
1813    
1814 iliev 1350 String InstrumentsDb::toEscapedFsPath(String FsPath) {
1815     return toEscapedText(FsPath);
1816 iliev 1345 }
1817    
1818 iliev 1727 String InstrumentsDb::toNonEscapedFsPath(String FsPath) {
1819     return toNonEscapedText(FsPath);
1820     }
1821    
1822 iliev 1345 String InstrumentsDb::toAbstractName(String DbName) {
1823     for (int i = 0; i < DbName.length(); i++) {
1824     if (DbName.at(i) == '/') DbName.at(i) = '\0';
1825     }
1826     return DbName;
1827     }
1828    
1829 iliev 1161 void InstrumentsDb::FireDirectoryCountChanged(String Dir) {
1830     for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1831     llInstrumentsDbListeners.GetListener(i)->DirectoryCountChanged(Dir);
1832     }
1833     }
1834 iliev 1200
1835 iliev 1161 void InstrumentsDb::FireDirectoryInfoChanged(String Dir) {
1836     for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1837     llInstrumentsDbListeners.GetListener(i)->DirectoryInfoChanged(Dir);
1838     }
1839     }
1840 iliev 1200
1841 iliev 1161 void InstrumentsDb::FireDirectoryNameChanged(String Dir, String NewName) {
1842     for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1843     llInstrumentsDbListeners.GetListener(i)->DirectoryNameChanged(Dir, NewName);
1844     }
1845     }
1846 iliev 1200
1847 iliev 1161 void InstrumentsDb::FireInstrumentCountChanged(String Dir) {
1848     for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1849     llInstrumentsDbListeners.GetListener(i)->InstrumentCountChanged(Dir);
1850     }
1851     }
1852 iliev 1200
1853 iliev 1161 void InstrumentsDb::FireInstrumentInfoChanged(String Instr) {
1854     for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1855     llInstrumentsDbListeners.GetListener(i)->InstrumentInfoChanged(Instr);
1856     }
1857     }
1858 iliev 1200
1859 iliev 1161 void InstrumentsDb::FireInstrumentNameChanged(String Instr, String NewName) {
1860     for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1861     llInstrumentsDbListeners.GetListener(i)->InstrumentNameChanged(Instr, NewName);
1862     }
1863     }
1864    
1865 iliev 1200 void InstrumentsDb::FireJobStatusChanged(int JobId) {
1866     for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1867     llInstrumentsDbListeners.GetListener(i)->JobStatusChanged(JobId);
1868 iliev 1161 }
1869     }
1870    
1871     } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC