/[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 3091 - (hide annotations) (download)
Mon Jan 16 15:01:21 2017 UTC (7 years, 3 months ago) by schoenebeck
File size: 73211 byte(s)
* Cleanup of instruments DB file creation and opening code.
* The instrument DB path of linuxsampler's --create-instruments-db argument
  is now optional, if it is missing, then a default location is used.
* Bumped version (2.0.0.svn39).

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

  ViewVC Help
Powered by ViewVC