/[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 2427 - (hide annotations) (download)
Sat Mar 2 07:03:04 2013 UTC (11 years, 1 month ago) by persson
File size: 71455 byte(s)
* code refactoring: added a lock guard class for exception safe mutex
  handling and used it everywhere appropriate

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

  ViewVC Help
Powered by ViewVC