/[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 1187 - (hide annotations) (download)
Wed May 16 14:22:26 2007 UTC (16 years, 10 months ago) by iliev
File size: 72471 byte(s)
* updated instruments db support
* added transactions for improving the db performance
* added commands for copying and finding instruments and directories

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

  ViewVC Help
Powered by ViewVC