/[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 1781 - (hide annotations) (download)
Mon Sep 29 18:21:21 2008 UTC (15 years, 6 months ago) by iliev
File size: 71190 byte(s)
* Implemented option for adding instruments in separate directories
  in the instruments database
  (patch by Chris Cherrett & Andrew Williams, a bit adjusted)

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

  ViewVC Help
Powered by ViewVC