/[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 1200 - (hide annotations) (download)
Thu May 24 14:04:18 2007 UTC (16 years, 10 months ago) by iliev
File size: 61489 byte(s)
* Implemented instrument scanning in background
  and commands for monitoring the scan progress

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

  ViewVC Help
Powered by ViewVC