/[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 1944 - (hide annotations) (download)
Tue Jul 14 18:54:08 2009 UTC (14 years, 9 months ago) by persson
File size: 72089 byte(s)
- added include statement, which was missing in previous commit

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

  ViewVC Help
Powered by ViewVC