/[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 1911 - (hide annotations) (download)
Sat Jun 6 13:50:36 2009 UTC (14 years, 10 months ago) by senoner
File size: 71729 byte(s)
* InstrumentsDB on Windows now works in both standalone and VST mode
* DB is stored in %USERPROFILE%\.linuxsampler\instruments.db
* removed stat() implementation as mingw already provides it

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

  ViewVC Help
Powered by ViewVC