/[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 1908 - (hide annotations) (download)
Mon Jun 1 18:50:06 2009 UTC (14 years, 10 months ago) by persson
File size: 71271 byte(s)
* VST: avoid opening Fantasia more than once for each VST instance
* VST: export main function as "main" on Linux too (fix for energyXT)
* VST: prepare code for multiple output channels
* work-around for missing fnmatch function on Windows to make
  instrument database compilable

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

  ViewVC Help
Powered by ViewVC