/[svn]/linuxsampler/trunk/src/db/InstrumentsDb.cpp
ViewVC logotype

Diff of /linuxsampler/trunk/src/db/InstrumentsDb.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1161 by iliev, Mon Apr 16 15:51:18 2007 UTC revision 1187 by iliev, Wed May 16 14:22:26 2007 UTC
# Line 26  Line 26 
26  #include <sstream>  #include <sstream>
27  #include <dirent.h>  #include <dirent.h>
28  #include <errno.h>  #include <errno.h>
29    #include <fnmatch.h>
30  #include <ftw.h>  #include <ftw.h>
31  #include "../common/Exception.h"  #include "../common/Exception.h"
32    
# Line 57  namespace LinuxSampler { Line 58  namespace LinuxSampler {
58          Description = Dir.Description;          Description = Dir.Description;
59      }      }
60    
61        SearchQuery::SearchQuery() {
62            MinSize = -1;
63            MaxSize = -1;
64            InstrType = BOTH;
65        }
66    
67        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      InstrumentsDb* InstrumentsDb::pInstrumentsDb = new InstrumentsDb;      InstrumentsDb* InstrumentsDb::pInstrumentsDb = new InstrumentsDb;
374    
375        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      InstrumentsDb::InstrumentsDb() {      InstrumentsDb::InstrumentsDb() {
426          db = NULL;          db = NULL;
427          DbInstrumentsMutex = Mutex();          DbInstrumentsMutex = Mutex();
428            InTransaction = false;
429      }      }
430    
431      InstrumentsDb::~InstrumentsDb() {      InstrumentsDb::~InstrumentsDb() {
# Line 108  namespace LinuxSampler { Line 471  namespace LinuxSampler {
471              db = NULL;              db = NULL;
472              throw Exception("Cannot open instruments database: " + DbFile);              throw Exception("Cannot open instruments database: " + DbFile);
473          }          }
474            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                    
477          return db;          return db;
478      }      }
# Line 127  namespace LinuxSampler { Line 492  namespace LinuxSampler {
492          return count;          return count;
493      }      }
494    
495      int InstrumentsDb::GetDirectoryCount(String Dir) {      int InstrumentsDb::GetDirectoryCount(String Dir, bool Recursive) {
496          dmsg(2,("InstrumentsDb: GetDirectoryCount(Dir=%s)\n", Dir.c_str()));          dmsg(2,("InstrumentsDb: GetDirectoryCount(Dir=%s,Recursive=%d)\n", Dir.c_str(), Recursive));
497          int i;          int i;
498    
499          DbInstrumentsMutex.Lock();          BeginTransaction();
500          try { i = GetDirectoryCount(GetDirectoryId(Dir)); }          try {
501          catch (Exception e) {              if (Recursive) {
502              DbInstrumentsMutex.Unlock();                  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              throw e;              throw e;
511          }          }
512          DbInstrumentsMutex.Unlock();          EndTransaction();
513          if (i == -1) throw Exception("Unkown DB directory: " + Dir);          if (i == -1) throw Exception("Unkown DB directory: " + Dir);
514                    
515          return i;          return i;
# Line 151  namespace LinuxSampler { Line 523  namespace LinuxSampler {
523          return ExecSqlIntList(sql.str());          return ExecSqlIntList(sql.str());
524      }      }
525    
526      StringListPtr InstrumentsDb::GetDirectories(String Dir) {      StringListPtr InstrumentsDb::GetDirectories(String Dir, bool Recursive) {
527          dmsg(2,("InstrumentsDb: GetDirectories(Dir=%s)\n", Dir.c_str()));          dmsg(2,("InstrumentsDb: GetDirectories(Dir=%s,Recursive=%d)\n", Dir.c_str(), Recursive));
528    
529          DbInstrumentsMutex.Lock();          BeginTransaction();
530          try {          try {
531              int dirId = GetDirectoryId(Dir);              int dirId = GetDirectoryId(Dir);
532              if(dirId == -1) throw Exception("Unknown DB directory: " + Dir);              if(dirId == -1) throw Exception("Unknown DB directory: " + Dir);
533    
534              std::stringstream sql;              StringListPtr pDirs;
535              sql << "SELECT dir_name FROM instr_dirs ";              if (Recursive) {
536              sql << "WHERE parent_dir_id=" << dirId << " AND dir_id!=0";                  SearchQuery q;
537                    DirectoryFinder directoryFinder(&q);
538              DbInstrumentsMutex.Unlock();                  DirectoryTreeWalk(Dir, &directoryFinder);
539              return ExecSqlStringList(sql.str());                  pDirs = directoryFinder.GetDirectories();
540                } else {
541                    pDirs = GetDirectories(dirId);
542                }
543                EndTransaction();
544                return pDirs;
545          } catch (Exception e) {          } catch (Exception e) {
546              DbInstrumentsMutex.Unlock();              EndTransaction();
547              throw e;              throw e;
548          }          }
549      }      }
550        
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    
558      int InstrumentsDb::GetDirectoryId(String Dir) {      int InstrumentsDb::GetDirectoryId(String Dir) {
559          dmsg(2,("InstrumentsDb: GetDirectoryId(Dir=%s)\n", Dir.c_str()));          dmsg(2,("InstrumentsDb: GetDirectoryId(Dir=%s)\n", Dir.c_str()));
# Line 203  namespace LinuxSampler { Line 587  namespace LinuxSampler {
587          return ExecSqlInt(sql.str(), DirName);          return ExecSqlInt(sql.str(), DirName);
588      }      }
589    
590        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      void InstrumentsDb::AddDirectory(String Dir) {      void InstrumentsDb::AddDirectory(String Dir) {
624          dmsg(2,("InstrumentsDb: AddDirectory(Dir=%s)\n", Dir.c_str()));          dmsg(2,("InstrumentsDb: AddDirectory(Dir=%s)\n", Dir.c_str()));
625          CheckPathName(Dir);          CheckPathName(Dir);
626          String ParentDir = GetParentDirectory(Dir);          String ParentDir = GetParentDirectory(Dir);
627                    
628          DbInstrumentsMutex.Lock();          BeginTransaction();
629          try {          try {
630              if (Dir.length() > 1) {              if (Dir.length() > 1) {
631                  if (Dir.at(Dir.length() - 1) == '/') Dir.erase(Dir.length() - 1);                  if (Dir.at(Dir.length() - 1) == '/') Dir.erase(Dir.length() - 1);
# Line 223  namespace LinuxSampler { Line 640  namespace LinuxSampler {
640              if (id == -1) throw Exception("DB directory doesn't exist: " + ParentDir);              if (id == -1) throw Exception("DB directory doesn't exist: " + ParentDir);
641              int id2 = GetDirectoryId(id, dirName);              int id2 = GetDirectoryId(id, dirName);
642              if (id2 != -1) throw Exception("DB directory already exist: " + Dir);              if (id2 != -1) throw Exception("DB directory already exist: " + Dir);
643                id2 = GetInstrumentId(id, dirName);
644                if (id2 != -1) throw Exception("Instrument with that name exist: " + Dir);
645    
646              std::stringstream sql;              std::stringstream sql;
647              sql << "INSERT INTO instr_dirs (parent_dir_id, dir_name) VALUES (";              sql << "INSERT INTO instr_dirs (parent_dir_id, dir_name) VALUES (";
# Line 230  namespace LinuxSampler { Line 649  namespace LinuxSampler {
649    
650              ExecSql(sql.str(), dirName);              ExecSql(sql.str(), dirName);
651          } catch (Exception e) {          } catch (Exception e) {
652              DbInstrumentsMutex.Unlock();              EndTransaction();
653              throw e;              throw e;
654          }          }
655    
656          DbInstrumentsMutex.Unlock();          EndTransaction();
657    
658          FireDirectoryCountChanged(ParentDir);          FireDirectoryCountChanged(ParentDir);
659      }      }
# Line 244  namespace LinuxSampler { Line 663  namespace LinuxSampler {
663    
664          String ParentDir = GetParentDirectory(Dir);          String ParentDir = GetParentDirectory(Dir);
665    
666          DbInstrumentsMutex.Lock();          BeginTransaction();
667          try {          try {
668              int dirId = GetDirectoryId(Dir);              int dirId = GetDirectoryId(Dir);
669              if (dirId == -1) throw Exception("Unknown DB directory: " + Dir);              if (dirId == -1) throw Exception("Unknown DB directory: " + Dir);
# Line 253  namespace LinuxSampler { Line 672  namespace LinuxSampler {
672              if (Force) RemoveDirectoryContent(dirId);              if (Force) RemoveDirectoryContent(dirId);
673              RemoveDirectory(dirId);              RemoveDirectory(dirId);
674          } catch (Exception e) {          } catch (Exception e) {
675              DbInstrumentsMutex.Unlock();              EndTransaction();
676              throw e;              throw e;
677          }          }
678    
679          DbInstrumentsMutex.Unlock();          EndTransaction();
680          FireDirectoryCountChanged(ParentDir);          FireDirectoryCountChanged(ParentDir);
681      }      }
682    
# Line 330  namespace LinuxSampler { Line 749  namespace LinuxSampler {
749          dmsg(2,("InstrumentsDb: GetDirectoryInfo(Dir=%s)\n", Dir.c_str()));          dmsg(2,("InstrumentsDb: GetDirectoryInfo(Dir=%s)\n", Dir.c_str()));
750          DbDirectory d;          DbDirectory d;
751    
752          DbInstrumentsMutex.Lock();          BeginTransaction();
753    
754          try {          try {
755              int id = GetDirectoryId(Dir);              int id = GetDirectoryId(Dir);
# Line 363  namespace LinuxSampler { Line 782  namespace LinuxSampler {
782                            
783              sqlite3_finalize(pStmt);              sqlite3_finalize(pStmt);
784          } catch (Exception e) {          } catch (Exception e) {
785              DbInstrumentsMutex.Unlock();              EndTransaction();
786              throw e;              throw e;
787          }          }
788    
789          DbInstrumentsMutex.Unlock();          EndTransaction();
790          return d;          return d;
791      }      }
792    
# Line 375  namespace LinuxSampler { Line 794  namespace LinuxSampler {
794          dmsg(2,("InstrumentsDb: RenameDirectory(Dir=%s,Name=%s)\n", Dir.c_str(), Name.c_str()));          dmsg(2,("InstrumentsDb: RenameDirectory(Dir=%s,Name=%s)\n", Dir.c_str(), Name.c_str()));
795          CheckFileName(Name);          CheckFileName(Name);
796    
797          DbInstrumentsMutex.Lock();          BeginTransaction();
798          try {          try {
799              int dirId = GetDirectoryId(Dir);              int dirId = GetDirectoryId(Dir);
800              if (dirId == -1) throw Exception("Unknown DB directory: " + Dir);              if (dirId == -1) throw Exception("Unknown DB directory: " + Dir);
# Line 389  namespace LinuxSampler { Line 808  namespace LinuxSampler {
808                  throw Exception("Cannot rename. Directory with that name already exists: " + Name);                  throw Exception("Cannot rename. Directory with that name already exists: " + Name);
809              }              }
810    
811                if (GetInstrumentId(parent, Name) != -1) {
812                    throw Exception("Cannot rename. Instrument with that name exist: " + Dir);
813                }
814    
815              sql.str("");              sql.str("");
816              sql << "UPDATE instr_dirs SET dir_name=? WHERE dir_id=" << dirId;              sql << "UPDATE instr_dirs SET dir_name=? WHERE dir_id=" << dirId;
817              ExecSql(sql.str(), Name);              ExecSql(sql.str(), Name);
818          } catch (Exception e) {          } catch (Exception e) {
819              DbInstrumentsMutex.Unlock();              EndTransaction();
820              throw e;              throw e;
821          }          }
822    
823          DbInstrumentsMutex.Unlock();          EndTransaction();
824          FireDirectoryNameChanged(Dir, Name);          FireDirectoryNameChanged(Dir, Name);
825      }      }
826    
827      void InstrumentsDb::MoveDirectory(String Dir, String Dst) {      void InstrumentsDb::MoveDirectory(String Dir, String Dst) {
828          dmsg(2,("InstrumentsDb: MoveDirectory(Dir=%s,Dst=%s)\n", Dir.c_str(), Dst.c_str()));          dmsg(2,("InstrumentsDb: MoveDirectory(Dir=%s,Dst=%s)\n", Dir.c_str(), Dst.c_str()));
829    
830            if(Dir.compare("/") == 0) throw Exception("Cannot move the root directory");
831          String ParentDir = GetParentDirectory(Dir);          String ParentDir = GetParentDirectory(Dir);
832          if(ParentDir.empty()) throw Exception("Unknown parent directory");          if(ParentDir.empty()) throw Exception("Unknown parent directory");
833    
834          DbInstrumentsMutex.Lock();          BeginTransaction();
835          try {          try {
836              int dirId = GetDirectoryId(Dir);              int dirId = GetDirectoryId(Dir);
837              if (dirId == -1) throw Exception("Unknown DB directory: " + Dir);              if (dirId == -1) throw Exception("Unknown DB directory: " + Dir);
# Line 423  namespace LinuxSampler { Line 847  namespace LinuxSampler {
847                      throw Exception("Cannot move a directory to a subdirectory of itself.");                      throw Exception("Cannot move a directory to a subdirectory of itself.");
848                  }                  }
849              }              }
850                
851                Dir.erase(Dir.length() - 1);
852                String dirName = GetFileName(Dir);
853    
854                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              std::stringstream sql;              std::stringstream sql;
860              sql << "UPDATE instr_dirs SET parent_dir_id=" << dstId;              sql << "UPDATE instr_dirs SET parent_dir_id=" << dstId;
861              sql << " WHERE dir_id=" << dirId;              sql << " WHERE dir_id=" << dirId;
862              ExecSql(sql.str());              ExecSql(sql.str());
863          } catch (Exception e) {          } catch (Exception e) {
864              DbInstrumentsMutex.Unlock();              EndTransaction();
865              throw e;              throw e;
866          }          }
867    
868          DbInstrumentsMutex.Unlock();          EndTransaction();
869          FireDirectoryCountChanged(ParentDir);          FireDirectoryCountChanged(ParentDir);
870          FireDirectoryCountChanged(Dst);          FireDirectoryCountChanged(Dst);
871      }      }
872    
873        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      void InstrumentsDb::SetDirectoryDescription(String Dir, String Desc) {      void InstrumentsDb::SetDirectoryDescription(String Dir, String Desc) {
916          dmsg(2,("InstrumentsDb: SetDirectoryDescription(Dir=%s,Desc=%s)\n", Dir.c_str(), Desc.c_str()));          dmsg(2,("InstrumentsDb: SetDirectoryDescription(Dir=%s,Desc=%s)\n", Dir.c_str(), Desc.c_str()));
917                    
918          DbInstrumentsMutex.Lock();          BeginTransaction();
919          try {          try {
920              int id = GetDirectoryId(Dir);              int id = GetDirectoryId(Dir);
921              if(id == -1) throw Exception("Unknown DB directory: " + Dir);              if(id == -1) throw Exception("Unknown DB directory: " + Dir);
# Line 452  namespace LinuxSampler { Line 926  namespace LinuxSampler {
926                    
927              ExecSql(sql.str(), Desc);              ExecSql(sql.str(), Desc);
928          } catch (Exception e) {          } catch (Exception e) {
929              DbInstrumentsMutex.Unlock();              EndTransaction();
930              throw e;              throw e;
931          }          }
932          DbInstrumentsMutex.Unlock();          EndTransaction();
933                    
934          FireDirectoryInfoChanged(Dir);          FireDirectoryInfoChanged(Dir);
935      }      }
# Line 531  namespace LinuxSampler { Line 1005  namespace LinuxSampler {
1005                  std::stringstream ss;                  std::stringstream ss;
1006                  ss << "The scanning of directory `" << FsDir << "` failed: ";                  ss << "The scanning of directory `" << FsDir << "` failed: ";
1007                  ss << strerror(errno);                  ss << strerror(errno);
1008                  std::cout << ss.str();                  std::cerr << ss.str();
1009                  DbInstrumentsMutex.Unlock();                  DbInstrumentsMutex.Unlock();
1010                  return;                  return;
1011              }              }
# Line 551  namespace LinuxSampler { Line 1025  namespace LinuxSampler {
1025                  std::stringstream ss;                  std::stringstream ss;
1026                  ss << "Failed to close directory `" << FsDir << "`: ";                  ss << "Failed to close directory `" << FsDir << "`: ";
1027                  ss << strerror(errno);                  ss << strerror(errno);
1028                  std::cout << ss.str();                  std::cerr << ss.str();
1029              }              }
1030          } catch (Exception e) {          } catch (Exception e) {
1031              DbInstrumentsMutex.Unlock();              DbInstrumentsMutex.Unlock();
# Line 576  namespace LinuxSampler { Line 1050  namespace LinuxSampler {
1050          return ExecSqlInt(sql.str());          return ExecSqlInt(sql.str());
1051      }      }
1052    
1053      int InstrumentsDb::GetInstrumentCount(String Dir) {      int InstrumentsDb::GetInstrumentCount(String Dir, bool Recursive) {
1054          dmsg(2,("InstrumentsDb: GetInstrumentCount(Dir=%s)\n", Dir.c_str()));          dmsg(2,("InstrumentsDb: GetInstrumentCount(Dir=%s,Recursive=%d)\n", Dir.c_str(), Recursive));
1055          int i;          int i;
1056                    
1057          DbInstrumentsMutex.Lock();          BeginTransaction();
1058          try { i = GetInstrumentCount(GetDirectoryId(Dir)); }          try {
1059          catch (Exception e) {              if (Recursive) {
1060              DbInstrumentsMutex.Unlock();                  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              throw e;              throw e;
1069          }          }
1070          DbInstrumentsMutex.Unlock();          EndTransaction();
1071    
1072          if (i == -1) throw Exception("Unknown Db directory: " + Dir);          if (i == -1) throw Exception("Unknown Db directory: " + Dir);
1073          return i;          return i;
# Line 599  namespace LinuxSampler { Line 1080  namespace LinuxSampler {
1080          return ExecSqlIntList(sql.str());          return ExecSqlIntList(sql.str());
1081      }      }
1082    
1083      StringListPtr InstrumentsDb::GetInstruments(String Dir) {      StringListPtr InstrumentsDb::GetInstruments(String Dir, bool Recursive) {
1084          dmsg(2,("InstrumentsDb: GetInstruments(Dir=%s)\n", Dir.c_str()));          dmsg(2,("InstrumentsDb: GetInstruments(Dir=%s,Recursive=%d)\n", Dir.c_str(), Recursive));
1085          DbInstrumentsMutex.Lock();          BeginTransaction();
1086          try {          try {
1087              int dirId = GetDirectoryId(Dir);              int dirId = GetDirectoryId(Dir);
1088              if(dirId == -1) throw Exception("Unknown DB directory: " + Dir);              if(dirId == -1) throw Exception("Unknown DB directory: " + Dir);
1089    
1090              std::stringstream sql;              StringListPtr pInstrs;
             sql << "SELECT instr_name FROM instruments WHERE dir_id=" << dirId;  
1091    
1092              StringListPtr instrs = ExecSqlStringList(sql.str());              if(Recursive) {
1093              DbInstrumentsMutex.Unlock();                  SearchQuery q;
1094              return instrs;                  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          } catch (Exception e) {          } catch (Exception e) {
1106              DbInstrumentsMutex.Unlock();              EndTransaction();
1107              throw e;              throw e;
1108          }          }
1109      }      }
# Line 635  namespace LinuxSampler { Line 1125  namespace LinuxSampler {
1125          sql << DirId << " AND instr_name=?";          sql << DirId << " AND instr_name=?";
1126          return ExecSqlInt(sql.str(), InstrName);          return ExecSqlInt(sql.str(), InstrName);
1127      }      }
1128    
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            
1136      void InstrumentsDb::RemoveInstrument(String Instr) {      void InstrumentsDb::RemoveInstrument(String Instr) {
1137          dmsg(2,("InstrumentsDb: RemoveInstrument(Instr=%s)\n", Instr.c_str()));          dmsg(2,("InstrumentsDb: RemoveInstrument(Instr=%s)\n", Instr.c_str()));
1138          String ParentDir = GetDirectoryPath(Instr);          String ParentDir = GetDirectoryPath(Instr);
1139          if(ParentDir.empty()) throw Exception("Unknown parent directory");          if(ParentDir.empty()) throw Exception("Unknown parent directory");
1140                    
1141          DbInstrumentsMutex.Lock();          BeginTransaction();
1142          try {          try {
1143              int instrId = GetInstrumentId(Instr);              int instrId = GetInstrumentId(Instr);
1144              if(instrId == -1) {              if(instrId == -1) {
# Line 649  namespace LinuxSampler { Line 1146  namespace LinuxSampler {
1146              }              }
1147              RemoveInstrument(instrId);              RemoveInstrument(instrId);
1148          } catch (Exception e) {          } catch (Exception e) {
1149              DbInstrumentsMutex.Unlock();              EndTransaction();
1150              throw e;              throw e;
1151          }          }
1152          DbInstrumentsMutex.Unlock();          EndTransaction();
1153          FireInstrumentCountChanged(ParentDir);          FireInstrumentCountChanged(ParentDir);
1154      }      }
1155    
# Line 677  namespace LinuxSampler { Line 1174  namespace LinuxSampler {
1174          dmsg(2,("InstrumentsDb: GetInstrumentInfo(Instr=%s)\n", Instr.c_str()));          dmsg(2,("InstrumentsDb: GetInstrumentInfo(Instr=%s)\n", Instr.c_str()));
1175          DbInstrument i;          DbInstrument i;
1176                    
1177          DbInstrumentsMutex.Lock();          BeginTransaction();
1178          try {          try {
1179              int id = GetInstrumentId(Instr);              int id = GetInstrumentId(Instr);
1180              if(id == -1) throw Exception("Unknown DB instrument: " + Instr);              if(id == -1) throw Exception("Unknown DB instrument: " + Instr);
1181                i = GetInstrumentInfo(id);
1182            } catch (Exception e) {
1183                EndTransaction();
1184                throw e;
1185            }
1186            EndTransaction();
1187                    
1188              sqlite3_stmt *pStmt = NULL;          return i;
1189              std::stringstream sql;      }
             sql << "SELECT instr_file,instr_nr,format_family,format_version,";  
             sql << "instr_size,created,modified,description,is_drum,product,";  
             sql << "artists,keywords FROM instruments WHERE instr_id=" << id;  
1190    
1191              int res = sqlite3_prepare(GetDb(), sql.str().c_str(), -1, &pStmt, NULL);      DbInstrument InstrumentsDb::GetInstrumentInfo(int InstrId) {
1192              if (res != SQLITE_OK) {          sqlite3_stmt *pStmt = NULL;
1193                  throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));          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              res = sqlite3_step(pStmt);          int res = sqlite3_prepare(GetDb(), sql.str().c_str(), -1, &pStmt, NULL);
1199              if(res == SQLITE_ROW) {          if (res != SQLITE_OK) {
1200                  i.InstrFile = ToString(sqlite3_column_text(pStmt, 0));              throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1201                  i.InstrNr = sqlite3_column_int(pStmt, 1);          }
                 i.FormatFamily = ToString(sqlite3_column_text(pStmt, 2));  
                 i.FormatVersion = ToString(sqlite3_column_text(pStmt, 3));  
                 i.Size = sqlite3_column_int64(pStmt, 4);  
                 i.Created = ToString(sqlite3_column_text(pStmt, 5));  
                 i.Modified = ToString(sqlite3_column_text(pStmt, 6));  
                 i.Description = ToString(sqlite3_column_text(pStmt, 7));  
                 i.IsDrum = sqlite3_column_int(pStmt, 8);  
                 i.Product = ToString(sqlite3_column_text(pStmt, 9));  
                 i.Artists = ToString(sqlite3_column_text(pStmt, 10));  
                 i.Keywords = ToString(sqlite3_column_text(pStmt, 11));  
             } else {  
                 sqlite3_finalize(pStmt);  
               
                 if (res != SQLITE_DONE) {  
                     throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));  
                 } else {  
                     throw Exception("Unknown DB instrument: " + Instr);  
                 }  
             }  
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);              sqlite3_finalize(pStmt);
1220          } catch (Exception e) {  
1221              DbInstrumentsMutex.Unlock();              if (res != SQLITE_DONE) {
1222              throw e;                  throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1223                } else {
1224                    throw Exception("Unknown DB instrument");
1225                }
1226          }          }
1227          DbInstrumentsMutex.Unlock();  
1228                    sqlite3_finalize(pStmt);
1229          return i;          return i;
1230      }      }
1231    
# Line 731  namespace LinuxSampler { Line 1233  namespace LinuxSampler {
1233          dmsg(2,("InstrumentsDb: RenameInstrument(Instr=%s,Name=%s)\n", Instr.c_str(), Name.c_str()));          dmsg(2,("InstrumentsDb: RenameInstrument(Instr=%s,Name=%s)\n", Instr.c_str(), Name.c_str()));
1234          CheckFileName(Name);          CheckFileName(Name);
1235    
1236          DbInstrumentsMutex.Lock();          BeginTransaction();
1237          try {          try {
1238              int dirId = GetDirectoryId(GetDirectoryPath(Instr));              int dirId = GetDirectoryId(GetDirectoryPath(Instr));
1239              if (dirId == -1) throw Exception("Unknown DB instrument: " + Instr);              if (dirId == -1) throw Exception("Unknown DB instrument: " + Instr);
# Line 743  namespace LinuxSampler { Line 1245  namespace LinuxSampler {
1245                  throw Exception("Cannot rename. Instrument with that name already exists: " + Name);                  throw Exception("Cannot rename. Instrument with that name already exists: " + Name);
1246              }              }
1247    
1248                if (GetDirectoryId(dirId, Name) != -1) {
1249                    throw Exception("Cannot rename. Directory with that name already exists: " + Name);
1250                }
1251    
1252              std::stringstream sql;              std::stringstream sql;
1253              sql << "UPDATE instruments SET instr_name=? WHERE instr_id=" << instrId;              sql << "UPDATE instruments SET instr_name=? WHERE instr_id=" << instrId;
1254              ExecSql(sql.str(), Name);              ExecSql(sql.str(), Name);
1255          } catch (Exception e) {          } catch (Exception e) {
1256              DbInstrumentsMutex.Unlock();              EndTransaction();
1257              throw e;              throw e;
1258          }          }
1259          DbInstrumentsMutex.Unlock();          EndTransaction();
1260          FireInstrumentNameChanged(Instr, Name);          FireInstrumentNameChanged(Instr, Name);
1261      }      }
1262    
# Line 759  namespace LinuxSampler { Line 1265  namespace LinuxSampler {
1265          String ParentDir = GetDirectoryPath(Instr);          String ParentDir = GetDirectoryPath(Instr);
1266          if(ParentDir.empty()) throw Exception("Unknown parent directory");          if(ParentDir.empty()) throw Exception("Unknown parent directory");
1267    
1268          DbInstrumentsMutex.Lock();          BeginTransaction();
1269          try {          try {
1270              int dirId = GetDirectoryId(GetDirectoryPath(Instr));              int dirId = GetDirectoryId(GetDirectoryPath(Instr));
1271              if (dirId == -1) throw Exception("Unknown DB instrument: " + Instr);              if (dirId == -1) throw Exception("Unknown DB instrument: " + Instr);
# Line 771  namespace LinuxSampler { Line 1277  namespace LinuxSampler {
1277              int dstId = GetDirectoryId(Dst);              int dstId = GetDirectoryId(Dst);
1278              if (dstId == -1) throw Exception("Unknown DB directory: " + Dst);              if (dstId == -1) throw Exception("Unknown DB directory: " + Dst);
1279              if (dirId == dstId) {              if (dirId == dstId) {
1280                  DbInstrumentsMutex.Unlock();                  EndTransaction();
1281                  return;                  return;
1282              }              }
1283    
# Line 779  namespace LinuxSampler { Line 1285  namespace LinuxSampler {
1285                  throw Exception("Cannot move. Instrument with that name already exists: " + instrName);                  throw Exception("Cannot move. Instrument with that name already exists: " + instrName);
1286              }              }
1287    
1288                if (GetDirectoryId(dstId, instrName) != -1) {
1289                    throw Exception("Cannot move. Directory with that name already exists: " + instrName);
1290                }
1291    
1292              std::stringstream sql;              std::stringstream sql;
1293              sql << "UPDATE instruments SET dir_id=" << dstId;              sql << "UPDATE instruments SET dir_id=" << dstId;
1294              sql << " WHERE instr_id=" << instrId;              sql << " WHERE instr_id=" << instrId;
1295              ExecSql(sql.str());              ExecSql(sql.str());
1296          } catch (Exception e) {          } catch (Exception e) {
1297              DbInstrumentsMutex.Unlock();              EndTransaction();
1298              throw e;              throw e;
1299          }          }
1300          DbInstrumentsMutex.Unlock();          EndTransaction();
1301          FireInstrumentCountChanged(ParentDir);          FireInstrumentCountChanged(ParentDir);
1302          FireInstrumentCountChanged(Dst);          FireInstrumentCountChanged(Dst);
1303      }      }
1304    
1305        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      void InstrumentsDb::SetInstrumentDescription(String Instr, String Desc) {      void InstrumentsDb::SetInstrumentDescription(String Instr, String Desc) {
1377          dmsg(2,("InstrumentsDb: SetInstrumentDescription(Instr=%s,Desc=%s)\n", Instr.c_str(), Desc.c_str()));          dmsg(2,("InstrumentsDb: SetInstrumentDescription(Instr=%s,Desc=%s)\n", Instr.c_str(), Desc.c_str()));
1378    
1379          DbInstrumentsMutex.Lock();          BeginTransaction();
1380          try {          try {
1381              int id = GetInstrumentId(Instr);              int id = GetInstrumentId(Instr);
1382              if(id == -1) throw Exception("Unknown DB instrument: " + Instr);              if(id == -1) throw Exception("Unknown DB instrument: " + Instr);
# Line 806  namespace LinuxSampler { Line 1387  namespace LinuxSampler {
1387    
1388              ExecSql(sql.str(), Desc);              ExecSql(sql.str(), Desc);
1389          } catch (Exception e) {          } catch (Exception e) {
1390              DbInstrumentsMutex.Unlock();              EndTransaction();
1391              throw e;              throw e;
1392          }          }
1393          DbInstrumentsMutex.Unlock();          EndTransaction();
1394          FireInstrumentInfoChanged(Instr);          FireInstrumentInfoChanged(Instr);
1395      }      }
1396    
# Line 823  namespace LinuxSampler { Line 1404  namespace LinuxSampler {
1404                  AddGigInstruments(DbDir, File, Index);                  AddGigInstruments(DbDir, File, Index);
1405              }              }
1406          } catch(Exception e) {          } catch(Exception e) {
1407              std::cout << e.Message() << std::endl;              std::cerr << e.Message() << std::endl;
1408          }          }
1409      }      }
1410    
# Line 892  namespace LinuxSampler { Line 1473  namespace LinuxSampler {
1473                  }                  }
1474              }              }
1475    
1476                sqlite3_finalize(pStmt);
1477              delete gig;              delete gig;
1478              delete riff;              delete riff;
1479          } catch (RIFF::Exception e) {          } catch (RIFF::Exception e) {
# Line 912  namespace LinuxSampler { Line 1494  namespace LinuxSampler {
1494          }          }
1495      }      }
1496    
1497      void InstrumentsDb::AddGigInstrument (sqlite3_stmt* pStmt, String DbDir, int DirId, String File, gig::Instrument* pInstrument, int Index) {      void InstrumentsDb::AddGigInstrument(sqlite3_stmt* pStmt, String DbDir, int DirId, String File, gig::Instrument* pInstrument, int Index) {
1498          String name = pInstrument->pInfo->Name;          String name = pInstrument->pInfo->Name;
1499          if (name == "") return;          if (name == "") return;
1500          name = GetUniqueInstrumentName(DirId, name);          name = GetUniqueInstrumentName(DirId, name);
# Line 949  namespace LinuxSampler { Line 1531  namespace LinuxSampler {
1531          FireInstrumentCountChanged(DbDir);          FireInstrumentCountChanged(DbDir);
1532      }      }
1533    
1534        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      void InstrumentsDb::ExecSql(String Sql) {      void InstrumentsDb::ExecSql(String Sql) {
1652          dmsg(2,("InstrumentsDb: ExecSql(Sql=%s)\n", Sql.c_str()));          dmsg(2,("InstrumentsDb: ExecSql(Sql=%s)\n", Sql.c_str()));
1653          sqlite3_stmt *pStmt = NULL;          sqlite3_stmt *pStmt = NULL;
# Line 1128  namespace LinuxSampler { Line 1827  namespace LinuxSampler {
1827          }          }
1828      }      }
1829    
1830        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      String InstrumentsDb::GetDirectoryPath(String File) {      String InstrumentsDb::GetDirectoryPath(String File) {
1842          if (File.empty()) return String("");          if (File.empty()) return String("");
1843          if (File.at(0) != '/') String("");          if (File.at(0) != '/') String("");
# Line 1178  namespace LinuxSampler { Line 1888  namespace LinuxSampler {
1888    
1889      String InstrumentsDb::GetUniqueInstrumentName(int DirId, String Name) {      String InstrumentsDb::GetUniqueInstrumentName(int DirId, String Name) {
1890          dmsg(2,("InstrumentsDb: GetUniqueInstrumentName(DirId=%d,Name=%s)\n", DirId, Name.c_str()));          dmsg(2,("InstrumentsDb: GetUniqueInstrumentName(DirId=%d,Name=%s)\n", DirId, Name.c_str()));
         std::stringstream sql;  
         sql << "SELECT COUNT(*) FROM instruments WHERE dir_id=" << DirId;  
         sql << " AND instr_name=?";  
1891    
1892          if (ExecSqlInt(sql.str(), Name) == 0) return Name;          if (GetInstrumentId(DirId, Name) == -1 && GetDirectoryId(DirId, Name) == -1) return Name;
1893          std::stringstream ss;          std::stringstream ss;
1894          for(int i = 2; i < 1001; i++) {          for(int i = 2; i < 1001; i++) {
1895              ss.str("");              ss.str("");
1896              ss << Name << '[' << i << ']';              ss << Name << '[' << i << ']';
1897              if (ExecSqlInt(sql.str(), ss.str()) == 0) return ss.str();              if (GetInstrumentId(DirId, ss.str()) == -1 && GetInstrumentId(DirId, ss.str()) == -1) {
1898                    return ss.str();
1899                }
1900          }          }
1901    
1902          throw Exception("Unable to find an unique name: " + Name);          throw Exception("Unable to find an unique name: " + Name);

Legend:
Removed from v.1161  
changed lines
  Added in v.1187

  ViewVC Help
Powered by ViewVC