/[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 1345 by iliev, Thu Sep 13 21:46:25 2007 UTC
# Line 24  Line 24 
24    
25  #include <iostream>  #include <iostream>
26  #include <sstream>  #include <sstream>
27    #include <vector>
28  #include <dirent.h>  #include <dirent.h>
29  #include <errno.h>  #include <errno.h>
30  #include <ftw.h>  #include <fnmatch.h>
31    
32  #include "../common/Exception.h"  #include "../common/Exception.h"
33    
34  namespace LinuxSampler {  namespace LinuxSampler {
35    
36      void DbInstrument::Copy(const DbInstrument& Instr) {      InstrumentsDb* InstrumentsDb::pInstrumentsDb = new InstrumentsDb;
         if (this == &Instr) return;  
   
         InstrFile = Instr.InstrFile;  
         InstrNr = Instr.InstrNr;  
         FormatFamily = Instr.FormatFamily;  
         FormatVersion = Instr.FormatVersion;  
         Size = Instr.Size;  
         Created = Instr.Created;  
         Modified = Instr.Modified;  
         Description = Instr.Description;  
         IsDrum = Instr.IsDrum;  
         Product = Instr.Product;  
         Artists = Instr.Artists;  
         Keywords = Instr.Keywords;  
     }  
37    
38        void InstrumentsDb::CreateInstrumentsDb(String File) {
39            struct stat statBuf;
40            int res = stat(File.c_str(), &statBuf);
41            if (!res) {
42                throw Exception("File exists: " + File);
43            }
44            
45            GetInstrumentsDb()->SetDbFile(File);
46    
47      void DbDirectory::Copy(const DbDirectory& Dir) {          String sql =
48          if (this == &Dir) return;              "  CREATE TABLE instr_dirs (                                      "
49                "      dir_id         INTEGER PRIMARY KEY AUTOINCREMENT,          "
50          Created = Dir.Created;              "      parent_dir_id  INTEGER DEFAULT 0,                          "
51          Modified = Dir.Modified;              "      dir_name       TEXT,                                       "
52          Description = Dir.Description;              "      created        TIMESTAMP DEFAULT CURRENT_TIMESTAMP,        "
53                "      modified       TIMESTAMP DEFAULT CURRENT_TIMESTAMP,        "
54                "      description    TEXT,                                       "
55                "      FOREIGN KEY(parent_dir_id) REFERENCES instr_dirs(dir_id),  "
56                "      UNIQUE (parent_dir_id,dir_name)                            "
57                "  );                                                             ";
58            
59            GetInstrumentsDb()->ExecSql(sql);
60    
61            sql = "INSERT INTO instr_dirs (dir_id, parent_dir_id, dir_name) VALUES (0, 0, '/');";
62            GetInstrumentsDb()->ExecSql(sql);
63    
64            sql =
65                "  CREATE TABLE instruments (                                "
66                "      instr_id        INTEGER PRIMARY KEY AUTOINCREMENT,    "
67                "      dir_id          INTEGER DEFAULT 0,                    "
68                "      instr_name      TEXT,                                 "
69                "      instr_file      TEXT,                                 "
70                "      instr_nr        INTEGER,                              "
71                "      format_family   TEXT,                                 "
72                "      format_version  TEXT,                                 "
73                "      instr_size      INTEGER,                              "
74                "      created         TIMESTAMP DEFAULT CURRENT_TIMESTAMP,  "
75                "      modified        TIMESTAMP DEFAULT CURRENT_TIMESTAMP,  "
76                "      description     TEXT,                                 "
77                "      is_drum         INTEGER(1),                           "
78                "      product         TEXT,                                 "
79                "      artists         TEXT,                                 "
80                "      keywords        TEXT,                                 "
81                "      FOREIGN KEY(dir_id) REFERENCES instr_dirs(dir_id),    "
82                "      UNIQUE (dir_id,instr_name)                            "
83                "  );                                                        ";
84            
85            GetInstrumentsDb()->ExecSql(sql);
86      }      }
87    
   
     InstrumentsDb* InstrumentsDb::pInstrumentsDb = new InstrumentsDb;  
   
88      InstrumentsDb::InstrumentsDb() {      InstrumentsDb::InstrumentsDb() {
89          db = NULL;          db = NULL;
90          DbInstrumentsMutex = Mutex();          DbInstrumentsMutex = Mutex();
91            InTransaction = false;
92      }      }
93    
94      InstrumentsDb::~InstrumentsDb() {      InstrumentsDb::~InstrumentsDb() {
# Line 108  namespace LinuxSampler { Line 134  namespace LinuxSampler {
134              db = NULL;              db = NULL;
135              throw Exception("Cannot open instruments database: " + DbFile);              throw Exception("Cannot open instruments database: " + DbFile);
136          }          }
137            rc = sqlite3_create_function(db, "regexp", 2, SQLITE_UTF8, NULL, Regexp, NULL, NULL);
138            if (rc) { throw Exception("Failed to add user function for handling regular expressions."); }
139                    
140          return db;          return db;
141      }      }
# Line 127  namespace LinuxSampler { Line 155  namespace LinuxSampler {
155          return count;          return count;
156      }      }
157    
158      int InstrumentsDb::GetDirectoryCount(String Dir) {      int InstrumentsDb::GetDirectoryCount(String Dir, bool Recursive) {
159          dmsg(2,("InstrumentsDb: GetDirectoryCount(Dir=%s)\n", Dir.c_str()));          dmsg(2,("InstrumentsDb: GetDirectoryCount(Dir=%s,Recursive=%d)\n", Dir.c_str(), Recursive));
160          int i;          int i;
161    
162          DbInstrumentsMutex.Lock();          BeginTransaction();
163          try { i = GetDirectoryCount(GetDirectoryId(Dir)); }          try {
164          catch (Exception e) {              if (Recursive) {
165              DbInstrumentsMutex.Unlock();                  DirectoryCounter directoryCounter;
166                    DirectoryTreeWalk(Dir, &directoryCounter);
167                    i = directoryCounter.GetDirectoryCount();
168                } else {
169                    i = GetDirectoryCount(GetDirectoryId(Dir));
170                }
171            } catch (Exception e) {
172                EndTransaction();
173              throw e;              throw e;
174          }          }
175          DbInstrumentsMutex.Unlock();          EndTransaction();
176          if (i == -1) throw Exception("Unkown DB directory: " + Dir);          if (i == -1) throw Exception("Unkown DB directory: " + toEscapedPath(Dir));
177                    
178          return i;          return i;
179      }      }
# Line 151  namespace LinuxSampler { Line 186  namespace LinuxSampler {
186          return ExecSqlIntList(sql.str());          return ExecSqlIntList(sql.str());
187      }      }
188    
189      StringListPtr InstrumentsDb::GetDirectories(String Dir) {      StringListPtr InstrumentsDb::GetDirectories(String Dir, bool Recursive) {
190          dmsg(2,("InstrumentsDb: GetDirectories(Dir=%s)\n", Dir.c_str()));          dmsg(2,("InstrumentsDb: GetDirectories(Dir=%s,Recursive=%d)\n", Dir.c_str(), Recursive));
191    
192          DbInstrumentsMutex.Lock();          BeginTransaction();
193          try {          try {
194              int dirId = GetDirectoryId(Dir);              int dirId = GetDirectoryId(Dir);
195              if(dirId == -1) throw Exception("Unknown DB directory: " + Dir);              if(dirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
   
             std::stringstream sql;  
             sql << "SELECT dir_name FROM instr_dirs ";  
             sql << "WHERE parent_dir_id=" << dirId << " AND dir_id!=0";  
196    
197              DbInstrumentsMutex.Unlock();              StringListPtr pDirs;
198              return ExecSqlStringList(sql.str());              if (Recursive) {
199                    SearchQuery q;
200                    DirectoryFinder directoryFinder(&q);
201                    DirectoryTreeWalk(Dir, &directoryFinder);
202                    pDirs = directoryFinder.GetDirectories();
203                } else {
204                    pDirs = GetDirectories(dirId);
205                }
206                EndTransaction();
207                return pDirs;
208          } catch (Exception e) {          } catch (Exception e) {
209              DbInstrumentsMutex.Unlock();              EndTransaction();
210              throw e;              throw e;
211          }          }
212      }      }
213        
214        StringListPtr InstrumentsDb::GetDirectories(int DirId) {
215            std::stringstream sql;
216            sql << "SELECT dir_name FROM instr_dirs ";
217            sql << "WHERE parent_dir_id=" << DirId << " AND dir_id!=0";
218            StringListPtr dirs = ExecSqlStringList(sql.str());
219    
220            for (int i = 0; i < dirs->size(); i++) {
221                for (int j = 0; j < dirs->at(i).length(); j++) {
222                    if (dirs->at(i).at(j) == '/') dirs->at(i).at(j) = '\0';
223                }
224            }
225    
226            return dirs;
227        }
228    
229      int InstrumentsDb::GetDirectoryId(String Dir) {      int InstrumentsDb::GetDirectoryId(String Dir) {
230          dmsg(2,("InstrumentsDb: GetDirectoryId(Dir=%s)\n", Dir.c_str()));          dmsg(2,("InstrumentsDb: GetDirectoryId(Dir=%s)\n", Dir.c_str()));
# Line 197  namespace LinuxSampler { Line 252  namespace LinuxSampler {
252    
253      int InstrumentsDb::GetDirectoryId(int ParentDirId, String DirName) {      int InstrumentsDb::GetDirectoryId(int ParentDirId, String DirName) {
254          dmsg(2,("InstrumentsDb: GetDirectoryId(ParentDirId=%d, DirName=%s)\n", ParentDirId, DirName.c_str()));          dmsg(2,("InstrumentsDb: GetDirectoryId(ParentDirId=%d, DirName=%s)\n", ParentDirId, DirName.c_str()));
255            DirName = toDbName(DirName);
256          std::stringstream sql;          std::stringstream sql;
257          sql << "SELECT dir_id FROM instr_dirs WHERE parent_dir_id=";          sql << "SELECT dir_id FROM instr_dirs WHERE parent_dir_id=";
258          sql << ParentDirId << " AND dir_name=?";          sql << ParentDirId << " AND dir_name=?";
259          return ExecSqlInt(sql.str(), DirName);          return ExecSqlInt(sql.str(), DirName);
260      }      }
261    
262        String InstrumentsDb::GetDirectoryName(int DirId) {
263            String sql = "SELECT dir_name FROM instr_dirs WHERE dir_id=" + ToString(DirId);
264            String name = ExecSqlString(sql);
265            if (name.empty()) throw Exception("Directory ID not found");
266            return name;
267        }
268    
269        int InstrumentsDb::GetParentDirectoryId(int DirId) {
270            if (DirId == 0) throw Exception("The root directory is specified");
271            String sql = "SELECT parent_dir_id FROM instr_dirs WHERE dir_id=" + ToString(DirId);
272            int parentId = ExecSqlInt(sql);
273            if (parentId == -1) throw Exception("DB directory not found");
274            return parentId;
275        }
276    
277        String InstrumentsDb::GetDirectoryPath(int DirId) {
278            String path = "";
279            int count = 1000; // used to prevent infinite loops
280    
281            while(--count) {
282                if (DirId == 0) {
283                    path = "/" + path;
284                    break;
285                }
286                path = GetDirectoryName(DirId) + path;
287                DirId = GetParentDirectoryId(DirId);
288            }
289    
290            if (!count) throw Exception("Possible infinite loop detected");
291    
292            return path;
293        }
294    
295      void InstrumentsDb::AddDirectory(String Dir) {      void InstrumentsDb::AddDirectory(String Dir) {
296          dmsg(2,("InstrumentsDb: AddDirectory(Dir=%s)\n", Dir.c_str()));          dmsg(2,("InstrumentsDb: AddDirectory(Dir=%s)\n", Dir.c_str()));
297          CheckPathName(Dir);          CheckPathName(Dir);
298          String ParentDir = GetParentDirectory(Dir);          String ParentDir = GetParentDirectory(Dir);
299                    
300          DbInstrumentsMutex.Lock();          BeginTransaction();
301          try {          try {
302              if (Dir.length() > 1) {              if (Dir.length() > 1) {
303                  if (Dir.at(Dir.length() - 1) == '/') Dir.erase(Dir.length() - 1);                  if (Dir.at(Dir.length() - 1) == '/') Dir.erase(Dir.length() - 1);
# Line 216  namespace LinuxSampler { Line 305  namespace LinuxSampler {
305    
306              String dirName = GetFileName(Dir);              String dirName = GetFileName(Dir);
307              if(ParentDir.empty() || dirName.empty()) {              if(ParentDir.empty() || dirName.empty()) {
308                  throw Exception("Failed to add DB directory: " + Dir);                  throw Exception("Failed to add DB directory: " + toEscapedPath(Dir));
309              }              }
310    
311              int id = GetDirectoryId(ParentDir);              int id = GetDirectoryId(ParentDir);
312              if (id == -1) throw Exception("DB directory doesn't exist: " + ParentDir);              if (id == -1) throw Exception("DB directory doesn't exist: " + toEscapedPath(ParentDir));
313              int id2 = GetDirectoryId(id, dirName);              int id2 = GetDirectoryId(id, dirName);
314              if (id2 != -1) throw Exception("DB directory already exist: " + Dir);              if (id2 != -1) throw Exception("DB directory already exist: " + toEscapedPath(Dir));
315                id2 = GetInstrumentId(id, dirName);
316                if (id2 != -1) throw Exception("Instrument with that name exist: " + toEscapedPath(Dir));
317    
318              std::stringstream sql;              std::stringstream sql;
319              sql << "INSERT INTO instr_dirs (parent_dir_id, dir_name) VALUES (";              sql << "INSERT INTO instr_dirs (parent_dir_id, dir_name) VALUES (";
320              sql << id << ", ?)";              sql << id << ", ?)";
321    
322              ExecSql(sql.str(), dirName);              ExecSql(sql.str(), toDbName(dirName));
323          } catch (Exception e) {          } catch (Exception e) {
324              DbInstrumentsMutex.Unlock();              EndTransaction();
325              throw e;              throw e;
326          }          }
327    
328          DbInstrumentsMutex.Unlock();          EndTransaction();
329    
330          FireDirectoryCountChanged(ParentDir);          FireDirectoryCountChanged(ParentDir);
331      }      }
# Line 244  namespace LinuxSampler { Line 335  namespace LinuxSampler {
335    
336          String ParentDir = GetParentDirectory(Dir);          String ParentDir = GetParentDirectory(Dir);
337    
338          DbInstrumentsMutex.Lock();          BeginTransaction();
339          try {          try {
340              int dirId = GetDirectoryId(Dir);              int dirId = GetDirectoryId(Dir);
341              if (dirId == -1) throw Exception("Unknown DB directory: " + Dir);              if (dirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
342              if (dirId == 0) throw Exception("Cannot delete the root directory: " + Dir);              if (dirId == 0) throw Exception("Cannot delete the root directory: " + Dir);
343              if(ParentDir.empty()) throw Exception("Unknown parent directory");              if(ParentDir.empty()) throw Exception("Unknown parent directory");
344              if (Force) RemoveDirectoryContent(dirId);              if (Force) RemoveDirectoryContent(dirId);
345              RemoveDirectory(dirId);              RemoveDirectory(dirId);
346          } catch (Exception e) {          } catch (Exception e) {
347              DbInstrumentsMutex.Unlock();              EndTransaction();
348              throw e;              throw e;
349          }          }
350    
351          DbInstrumentsMutex.Unlock();          EndTransaction();
352          FireDirectoryCountChanged(ParentDir);          FireDirectoryCountChanged(ParentDir);
353      }      }
354    
# Line 330  namespace LinuxSampler { Line 421  namespace LinuxSampler {
421          dmsg(2,("InstrumentsDb: GetDirectoryInfo(Dir=%s)\n", Dir.c_str()));          dmsg(2,("InstrumentsDb: GetDirectoryInfo(Dir=%s)\n", Dir.c_str()));
422          DbDirectory d;          DbDirectory d;
423    
424          DbInstrumentsMutex.Lock();          BeginTransaction();
425    
426          try {          try {
427              int id = GetDirectoryId(Dir);              int id = GetDirectoryId(Dir);
428              if(id == -1) throw Exception("Unknown DB directory: " + Dir);              if(id == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
429    
430              sqlite3_stmt *pStmt = NULL;              sqlite3_stmt *pStmt = NULL;
431              std::stringstream sql;              std::stringstream sql;
# Line 357  namespace LinuxSampler { Line 448  namespace LinuxSampler {
448                  if (res != SQLITE_DONE) {                  if (res != SQLITE_DONE) {
449                      throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));                      throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
450                  } else {                  } else {
451                      throw Exception("Unknown DB directory: " + Dir);                      throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
452                  }                  }
453              }              }
454                            
455              sqlite3_finalize(pStmt);              sqlite3_finalize(pStmt);
456          } catch (Exception e) {          } catch (Exception e) {
457              DbInstrumentsMutex.Unlock();              EndTransaction();
458              throw e;              throw e;
459          }          }
460    
461          DbInstrumentsMutex.Unlock();          EndTransaction();
462          return d;          return d;
463      }      }
464    
465      void InstrumentsDb::RenameDirectory(String Dir, String Name) {      void InstrumentsDb::RenameDirectory(String Dir, String Name) {
466          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()));
467          CheckFileName(Name);          CheckFileName(Name);
468            String dbName = toDbName(Name);
469    
470          DbInstrumentsMutex.Lock();          BeginTransaction();
471          try {          try {
472              int dirId = GetDirectoryId(Dir);              int dirId = GetDirectoryId(Dir);
473              if (dirId == -1) throw Exception("Unknown DB directory: " + Dir);              if (dirId == -1) throw Exception("Unknown DB directory: " + toEscapedText(Dir));
474    
475              std::stringstream sql;              std::stringstream sql;
476              sql << "SELECT parent_dir_id FROM instr_dirs WHERE dir_id=" <<  dirId;              sql << "SELECT parent_dir_id FROM instr_dirs WHERE dir_id=" <<  dirId;
477    
478              int parent = ExecSqlInt(sql.str());              int parent = ExecSqlInt(sql.str());
479              if (parent == -1) throw Exception("Unknown parent directory: " + Dir);              if (parent == -1) throw Exception("Unknown parent directory: " + toEscapedPath(Dir));
480              if (GetDirectoryId(parent, Name) != -1) {  
481                  throw Exception("Cannot rename. Directory with that name already exists: " + Name);              if (GetDirectoryId(parent, dbName) != -1) {
482                    String s = toEscapedPath(Name);
483                    throw Exception("Cannot rename. Directory with that name already exists: " + s);
484                }
485    
486                if (GetInstrumentId(parent, dbName) != -1) {
487                    throw Exception("Cannot rename. Instrument with that name exist: " + toEscapedPath(Dir));
488              }              }
489    
490              sql.str("");              sql.str("");
491              sql << "UPDATE instr_dirs SET dir_name=? WHERE dir_id=" << dirId;              sql << "UPDATE instr_dirs SET dir_name=? WHERE dir_id=" << dirId;
492              ExecSql(sql.str(), Name);              ExecSql(sql.str(), dbName);
493          } catch (Exception e) {          } catch (Exception e) {
494              DbInstrumentsMutex.Unlock();              EndTransaction();
495              throw e;              throw e;
496          }          }
497    
498          DbInstrumentsMutex.Unlock();          EndTransaction();
499          FireDirectoryNameChanged(Dir, Name);          FireDirectoryNameChanged(Dir, Name);
500      }      }
501    
502      void InstrumentsDb::MoveDirectory(String Dir, String Dst) {      void InstrumentsDb::MoveDirectory(String Dir, String Dst) {
503          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()));
504    
505            if(Dir.compare("/") == 0) throw Exception("Cannot move the root directory");
506          String ParentDir = GetParentDirectory(Dir);          String ParentDir = GetParentDirectory(Dir);
507          if(ParentDir.empty()) throw Exception("Unknown parent directory");          if(ParentDir.empty()) throw Exception("Unknown parent directory");
508    
509          DbInstrumentsMutex.Lock();          BeginTransaction();
510          try {          try {
511              int dirId = GetDirectoryId(Dir);              int dirId = GetDirectoryId(Dir);
512              if (dirId == -1) throw Exception("Unknown DB directory: " + Dir);              if (dirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
513              int dstId = GetDirectoryId(Dst);              int dstId = GetDirectoryId(Dst);
514              if (dstId == -1) throw Exception("Unknown DB directory: " + Dst);              if (dstId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dst));
515              if (dirId == dstId) {              if (dirId == dstId) {
516                  throw Exception("Cannot move directory to itself");                  throw Exception("Cannot move directory to itself");
517              }              }
# Line 423  namespace LinuxSampler { Line 522  namespace LinuxSampler {
522                      throw Exception("Cannot move a directory to a subdirectory of itself.");                      throw Exception("Cannot move a directory to a subdirectory of itself.");
523                  }                  }
524              }              }
525                
526                Dir.erase(Dir.length() - 1);
527                String dirName = GetFileName(Dir);
528    
529                int id2 = GetDirectoryId(dstId, dirName);
530                if (id2 != -1) throw Exception("DB directory already exist: " + toEscapedPath(dirName));
531                id2 = GetInstrumentId(dstId, dirName);
532                if (id2 != -1) throw Exception("Instrument with that name exist: " + toEscapedPath(dirName));
533    
534              std::stringstream sql;              std::stringstream sql;
535              sql << "UPDATE instr_dirs SET parent_dir_id=" << dstId;              sql << "UPDATE instr_dirs SET parent_dir_id=" << dstId;
536              sql << " WHERE dir_id=" << dirId;              sql << " WHERE dir_id=" << dirId;
537              ExecSql(sql.str());              ExecSql(sql.str());
538          } catch (Exception e) {          } catch (Exception e) {
539              DbInstrumentsMutex.Unlock();              EndTransaction();
540              throw e;              throw e;
541          }          }
542    
543          DbInstrumentsMutex.Unlock();          EndTransaction();
544          FireDirectoryCountChanged(ParentDir);          FireDirectoryCountChanged(ParentDir);
545          FireDirectoryCountChanged(Dst);          FireDirectoryCountChanged(Dst);
546      }      }
547    
548        void InstrumentsDb::CopyDirectory(String Dir, String Dst) {
549            dmsg(2,("InstrumentsDb: CopyDirectory(Dir=%s,Dst=%s)\n", Dir.c_str(), Dst.c_str()));
550    
551            if(Dir.compare("/") == 0) throw Exception("Cannot copy the root directory");
552            String ParentDir = GetParentDirectory(Dir);
553            if(ParentDir.empty()) throw Exception("Unknown parent directory");
554    
555            BeginTransaction();
556            try {
557                int dirId = GetDirectoryId(Dir);
558                if (dirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
559                int dstId = GetDirectoryId(Dst);
560                if (dstId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dst));
561                if (dirId == dstId) {
562                    throw Exception("Cannot copy directory to itself");
563                }
564    
565                if (Dir.at(Dir.length() - 1) != '/') Dir.append("/");
566                if (Dst.length() > Dir.length()) {
567                    if (Dir.compare(Dst.substr(0, Dir.length())) == 0) {
568                        throw Exception("Cannot copy a directory to a subdirectory of itself.");
569                    }
570                }
571                
572                Dir.erase(Dir.length() - 1);
573                String dirName = GetFileName(Dir);
574    
575                int id2 = GetDirectoryId(dstId, dirName);
576                if (id2 != -1) throw Exception("DB directory already exist: " + toEscapedPath(dirName));
577                id2 = GetInstrumentId(dstId, dirName);
578                if (id2 != -1) throw Exception("Instrument with that name exist: " + toEscapedPath(dirName));
579    
580                DirectoryCopier directoryCopier(ParentDir, Dst);
581                DirectoryTreeWalk(Dir, &directoryCopier);
582            } catch (Exception e) {
583                EndTransaction();
584                throw e;
585            }
586    
587            EndTransaction();
588        }
589    
590      void InstrumentsDb::SetDirectoryDescription(String Dir, String Desc) {      void InstrumentsDb::SetDirectoryDescription(String Dir, String Desc) {
591          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()));
592                    
593          DbInstrumentsMutex.Lock();          BeginTransaction();
594          try {          try {
595              int id = GetDirectoryId(Dir);              int id = GetDirectoryId(Dir);
596              if(id == -1) throw Exception("Unknown DB directory: " + Dir);              if(id == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
597    
598              std::stringstream sql;              std::stringstream sql;
599              sql << "UPDATE instr_dirs SET description=?,modified=CURRENT_TIMESTAMP ";              sql << "UPDATE instr_dirs SET description=?,modified=CURRENT_TIMESTAMP ";
# Line 452  namespace LinuxSampler { Line 601  namespace LinuxSampler {
601                    
602              ExecSql(sql.str(), Desc);              ExecSql(sql.str(), Desc);
603          } catch (Exception e) {          } catch (Exception e) {
604              DbInstrumentsMutex.Unlock();              EndTransaction();
605              throw e;              throw e;
606          }          }
607          DbInstrumentsMutex.Unlock();          EndTransaction();
608                    
609          FireDirectoryInfoChanged(Dir);          FireDirectoryInfoChanged(Dir);
610      }      }
611    
612      void InstrumentsDb::AddInstruments(String DbDir, String FilePath, int Index) {      int InstrumentsDb::AddInstruments(ScanMode Mode, String DbDir, String FsDir, bool bBackground) {
613            dmsg(2,("InstrumentsDb: AddInstruments(Mode=%d,DbDir=%s,FsDir=%s,bBackground=%d)\n", Mode, DbDir.c_str(), FsDir.c_str(), bBackground));
614            if(!bBackground) {
615                switch (Mode) {
616                    case NON_RECURSIVE:
617                        AddInstrumentsNonrecursive(DbDir, FsDir);
618                        break;
619                    case RECURSIVE:
620                        AddInstrumentsRecursive(DbDir, FsDir);
621                        break;
622                    case FLAT:
623                        AddInstrumentsRecursive(DbDir, FsDir, true);
624                        break;
625                    default:
626                        throw Exception("Unknown scan mode");
627                }
628    
629                return -1;
630            }
631    
632            ScanJob job;
633            int jobId = Jobs.AddJob(job);
634            InstrumentsDbThread.Execute(new AddInstrumentsJob(jobId, Mode, DbDir, FsDir));
635    
636            return jobId;
637        }
638        
639        int InstrumentsDb::AddInstruments(String DbDir, String FilePath, int Index, bool bBackground) {
640            dmsg(2,("InstrumentsDb: AddInstruments(DbDir=%s,FilePath=%s,Index=%d,bBackground=%d)\n", DbDir.c_str(), FilePath.c_str(), Index, bBackground));
641            if(!bBackground) {
642                AddInstruments(DbDir, FilePath, Index);
643                return -1;
644            }
645    
646            ScanJob job;
647            int jobId = Jobs.AddJob(job);
648            InstrumentsDbThread.Execute(new AddInstrumentsFromFileJob(jobId, DbDir, FilePath, Index));
649    
650            return jobId;
651        }
652    
653        void InstrumentsDb::AddInstruments(String DbDir, String FilePath, int Index, ScanProgress* pProgress) {
654          dmsg(2,("InstrumentsDb: AddInstruments(DbDir=%s,FilePath=%s,Index=%d)\n", DbDir.c_str(), FilePath.c_str(), Index));          dmsg(2,("InstrumentsDb: AddInstruments(DbDir=%s,FilePath=%s,Index=%d)\n", DbDir.c_str(), FilePath.c_str(), Index));
655          if (DbDir.empty() || FilePath.empty()) return;          if (DbDir.empty() || FilePath.empty()) return;
656                    
657          DbInstrumentsMutex.Lock();          DbInstrumentsMutex.Lock();
658          try {          try {
659              int dirId = GetDirectoryId(DbDir);              int dirId = GetDirectoryId(DbDir);
660              if (dirId == -1) throw Exception("Invalid DB directory: " + DbDir);              if (dirId == -1) throw Exception("Invalid DB directory: " + toEscapedText(DbDir));
661    
662              struct stat statBuf;              struct stat statBuf;
663              int res = stat(FilePath.c_str(), &statBuf);              int res = stat(FilePath.c_str(), &statBuf);
# Line 477  namespace LinuxSampler { Line 667  namespace LinuxSampler {
667                  throw Exception(ss.str());                  throw Exception(ss.str());
668              }              }
669    
670              if (S_ISREG(statBuf.st_mode)) {              if (!S_ISREG(statBuf.st_mode)) {
                 AddInstrumentsFromFile(DbDir, FilePath, Index);  
                 DbInstrumentsMutex.Unlock();  
                 return;  
             }  
   
             if (!S_ISDIR(statBuf.st_mode)) {  
                 DbInstrumentsMutex.Unlock();  
                 return;  
             }  
               
             if (Index != -1) {  
671                  std::stringstream ss;                  std::stringstream ss;
672                  ss << "`" << FilePath << "` is directory, not an instrument file";                  ss << "`" << FilePath << "` is not an instrument file";
673                  throw Exception(ss.str());                  throw Exception(ss.str());
674              }              }
675            
676              AddInstrumentsRecursive(DbDir, FilePath, false);              AddInstrumentsFromFile(DbDir, FilePath, Index, pProgress);
677          } catch (Exception e) {          } catch (Exception e) {
678              DbInstrumentsMutex.Unlock();              DbInstrumentsMutex.Unlock();
679              throw e;              throw e;
# Line 503  namespace LinuxSampler { Line 682  namespace LinuxSampler {
682          DbInstrumentsMutex.Unlock();          DbInstrumentsMutex.Unlock();
683      }      }
684    
685      void InstrumentsDb::AddInstrumentsNonrecursive(String DbDir, String FsDir) {      void InstrumentsDb::AddInstrumentsNonrecursive(String DbDir, String FsDir, ScanProgress* pProgress) {
686          dmsg(2,("InstrumentsDb: AddInstrumentsNonrecursive(DbDir=%s,FsDir=%s)\n", DbDir.c_str(), FsDir.c_str()));          dmsg(2,("InstrumentsDb: AddInstrumentsNonrecursive(DbDir=%s,FsDir=%s)\n", DbDir.c_str(), FsDir.c_str()));
687          if (DbDir.empty() || FsDir.empty()) return;          if (DbDir.empty() || FsDir.empty()) return;
688                    
689          DbInstrumentsMutex.Lock();          DbInstrumentsMutex.Lock();
690          try {          try {
691              int dirId = GetDirectoryId(DbDir);              int dirId = GetDirectoryId(DbDir);
692              if (dirId == -1) throw Exception("Invalid DB directory: " + DbDir);              if (dirId == -1) throw Exception("Invalid DB directory: " + toEscapedPath(DbDir));
693    
694              struct stat statBuf;              struct stat statBuf;
695              int res = stat(FsDir.c_str(), &statBuf);              int res = stat(FsDir.c_str(), &statBuf);
# Line 531  namespace LinuxSampler { Line 710  namespace LinuxSampler {
710                  std::stringstream ss;                  std::stringstream ss;
711                  ss << "The scanning of directory `" << FsDir << "` failed: ";                  ss << "The scanning of directory `" << FsDir << "` failed: ";
712                  ss << strerror(errno);                  ss << strerror(errno);
713                  std::cout << ss.str();                  std::cerr << ss.str();
714                  DbInstrumentsMutex.Unlock();                  DbInstrumentsMutex.Unlock();
715                  return;                  return;
716              }              }
# Line 543  namespace LinuxSampler { Line 722  namespace LinuxSampler {
722                      continue;                      continue;
723                  }                  }
724    
725                  AddInstrumentsFromFile(DbDir, FsDir + String(pEnt->d_name));                  AddInstrumentsFromFile(DbDir, FsDir + String(pEnt->d_name), -1, pProgress);
726                  pEnt = readdir(pDir);                  pEnt = readdir(pDir);
727              }              }
728    
# Line 551  namespace LinuxSampler { Line 730  namespace LinuxSampler {
730                  std::stringstream ss;                  std::stringstream ss;
731                  ss << "Failed to close directory `" << FsDir << "`: ";                  ss << "Failed to close directory `" << FsDir << "`: ";
732                  ss << strerror(errno);                  ss << strerror(errno);
733                  std::cout << ss.str();                  std::cerr << ss.str();
734              }              }
735          } catch (Exception e) {          } catch (Exception e) {
736              DbInstrumentsMutex.Unlock();              DbInstrumentsMutex.Unlock();
# Line 561  namespace LinuxSampler { Line 740  namespace LinuxSampler {
740          DbInstrumentsMutex.Unlock();          DbInstrumentsMutex.Unlock();
741      }      }
742    
743      void InstrumentsDb::AddInstrumentsRecursive(String DbDir, String FsDir, bool Flat) {      void InstrumentsDb::AddInstrumentsRecursive(String DbDir, String FsDir, bool Flat, ScanProgress* pProgress) {
744          dmsg(2,("InstrumentsDb: AddInstrumentsRecursive(DbDir=%s,FsDir=%s,Flat=%d)\n", DbDir.c_str(), FsDir.c_str(), Flat));          dmsg(2,("InstrumentsDb: AddInstrumentsRecursive(DbDir=%s,FsDir=%s,Flat=%d)\n", DbDir.c_str(), FsDir.c_str(), Flat));
745          DirectoryScanner::Scan(DbDir, FsDir, Flat);          if (pProgress != NULL) {
746                pProgress->SetTotalFileCount(InstrumentFileCounter::Count(FsDir));
747            }
748    
749            DirectoryScanner::Scan(DbDir, FsDir, Flat, pProgress);
750      }      }
751    
752      int InstrumentsDb::GetInstrumentCount(int DirId) {      int InstrumentsDb::GetInstrumentCount(int DirId) {
# Line 576  namespace LinuxSampler { Line 759  namespace LinuxSampler {
759          return ExecSqlInt(sql.str());          return ExecSqlInt(sql.str());
760      }      }
761    
762      int InstrumentsDb::GetInstrumentCount(String Dir) {      int InstrumentsDb::GetInstrumentCount(String Dir, bool Recursive) {
763          dmsg(2,("InstrumentsDb: GetInstrumentCount(Dir=%s)\n", Dir.c_str()));          dmsg(2,("InstrumentsDb: GetInstrumentCount(Dir=%s,Recursive=%d)\n", Dir.c_str(), Recursive));
764          int i;          int i;
765                    
766          DbInstrumentsMutex.Lock();          BeginTransaction();
767          try { i = GetInstrumentCount(GetDirectoryId(Dir)); }          try {
768          catch (Exception e) {              if (Recursive) {
769              DbInstrumentsMutex.Unlock();                  InstrumentCounter instrumentCounter;
770                    DirectoryTreeWalk(Dir, &instrumentCounter);
771                    i = instrumentCounter.GetInstrumentCount();
772                } else {
773                    i = GetInstrumentCount(GetDirectoryId(Dir));
774                }
775            } catch (Exception e) {
776                EndTransaction();
777              throw e;              throw e;
778          }          }
779          DbInstrumentsMutex.Unlock();          EndTransaction();
780    
781          if (i == -1) throw Exception("Unknown Db directory: " + Dir);          if (i == -1) throw Exception("Unknown Db directory: " + toEscapedPath(Dir));
782          return i;          return i;
783      }      }
784    
# Line 599  namespace LinuxSampler { Line 789  namespace LinuxSampler {
789          return ExecSqlIntList(sql.str());          return ExecSqlIntList(sql.str());
790      }      }
791    
792      StringListPtr InstrumentsDb::GetInstruments(String Dir) {      StringListPtr InstrumentsDb::GetInstruments(String Dir, bool Recursive) {
793          dmsg(2,("InstrumentsDb: GetInstruments(Dir=%s)\n", Dir.c_str()));          dmsg(2,("InstrumentsDb: GetInstruments(Dir=%s,Recursive=%d)\n", Dir.c_str(), Recursive));
794          DbInstrumentsMutex.Lock();          BeginTransaction();
795          try {          try {
796              int dirId = GetDirectoryId(Dir);              int dirId = GetDirectoryId(Dir);
797              if(dirId == -1) throw Exception("Unknown DB directory: " + Dir);              if(dirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
798    
799              std::stringstream sql;              StringListPtr pInstrs;
             sql << "SELECT instr_name FROM instruments WHERE dir_id=" << dirId;  
800    
801              StringListPtr instrs = ExecSqlStringList(sql.str());              if(Recursive) {
802              DbInstrumentsMutex.Unlock();                  SearchQuery q;
803              return instrs;                  InstrumentFinder instrumentFinder(&q);
804                    DirectoryTreeWalk(Dir, &instrumentFinder);
805                    pInstrs = instrumentFinder.GetInstruments();
806                } else {
807                    std::stringstream sql;
808                    sql << "SELECT instr_name FROM instruments WHERE dir_id=" << dirId;
809    
810                    pInstrs = ExecSqlStringList(sql.str());
811                }
812                EndTransaction();
813                return pInstrs;
814          } catch (Exception e) {          } catch (Exception e) {
815              DbInstrumentsMutex.Unlock();              EndTransaction();
816              throw e;              throw e;
817          }          }
818      }      }
# Line 633  namespace LinuxSampler { Line 832  namespace LinuxSampler {
832          std::stringstream sql;          std::stringstream sql;
833          sql << "SELECT instr_id FROM instruments WHERE dir_id=";          sql << "SELECT instr_id FROM instruments WHERE dir_id=";
834          sql << DirId << " AND instr_name=?";          sql << DirId << " AND instr_name=?";
835          return ExecSqlInt(sql.str(), InstrName);          return ExecSqlInt(sql.str(), toDbName(InstrName));
836        }
837    
838        String InstrumentsDb::GetInstrumentName(int InstrId) {
839            dmsg(2,("InstrumentsDb: GetInstrumentName(InstrId=%d)\n", InstrId));
840            std::stringstream sql;
841            sql << "SELECT instr_name FROM instruments WHERE instr_id=" << InstrId;
842            return toAbstractName(ExecSqlString(sql.str()));
843      }      }
844            
845      void InstrumentsDb::RemoveInstrument(String Instr) {      void InstrumentsDb::RemoveInstrument(String Instr) {
# Line 641  namespace LinuxSampler { Line 847  namespace LinuxSampler {
847          String ParentDir = GetDirectoryPath(Instr);          String ParentDir = GetDirectoryPath(Instr);
848          if(ParentDir.empty()) throw Exception("Unknown parent directory");          if(ParentDir.empty()) throw Exception("Unknown parent directory");
849                    
850          DbInstrumentsMutex.Lock();          BeginTransaction();
851          try {          try {
852              int instrId = GetInstrumentId(Instr);              int instrId = GetInstrumentId(Instr);
853              if(instrId == -1) {              if(instrId == -1) {
854                  throw Exception("The specified instrument does not exist: " + Instr);                  throw Exception("The specified instrument does not exist: " + toEscapedPath(Instr));
855              }              }
856              RemoveInstrument(instrId);              RemoveInstrument(instrId);
857          } catch (Exception e) {          } catch (Exception e) {
858              DbInstrumentsMutex.Unlock();              EndTransaction();
859              throw e;              throw e;
860          }          }
861          DbInstrumentsMutex.Unlock();          EndTransaction();
862          FireInstrumentCountChanged(ParentDir);          FireInstrumentCountChanged(ParentDir);
863      }      }
864    
# Line 677  namespace LinuxSampler { Line 883  namespace LinuxSampler {
883          dmsg(2,("InstrumentsDb: GetInstrumentInfo(Instr=%s)\n", Instr.c_str()));          dmsg(2,("InstrumentsDb: GetInstrumentInfo(Instr=%s)\n", Instr.c_str()));
884          DbInstrument i;          DbInstrument i;
885                    
886          DbInstrumentsMutex.Lock();          BeginTransaction();
887          try {          try {
888              int id = GetInstrumentId(Instr);              int id = GetInstrumentId(Instr);
889              if(id == -1) throw Exception("Unknown DB instrument: " + Instr);              if(id == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
890                i = GetInstrumentInfo(id);
891            } catch (Exception e) {
892                EndTransaction();
893                throw e;
894            }
895            EndTransaction();
896                    
897              sqlite3_stmt *pStmt = NULL;          return i;
898              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;  
899    
900              int res = sqlite3_prepare(GetDb(), sql.str().c_str(), -1, &pStmt, NULL);      DbInstrument InstrumentsDb::GetInstrumentInfo(int InstrId) {
901              if (res != SQLITE_OK) {          sqlite3_stmt *pStmt = NULL;
902                  throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));          std::stringstream sql;
903              }          sql << "SELECT instr_file,instr_nr,format_family,format_version,";
904            sql << "instr_size,created,modified,description,is_drum,product,";
905            sql << "artists,keywords FROM instruments WHERE instr_id=" << InstrId;
906    
907              res = sqlite3_step(pStmt);          int res = sqlite3_prepare(GetDb(), sql.str().c_str(), -1, &pStmt, NULL);
908              if(res == SQLITE_ROW) {          if (res != SQLITE_OK) {
909                  i.InstrFile = ToString(sqlite3_column_text(pStmt, 0));              throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
910                  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);  
                 }  
             }  
911    
912            DbInstrument i;
913            res = sqlite3_step(pStmt);
914            if(res == SQLITE_ROW) {
915                i.InstrFile = ToString(sqlite3_column_text(pStmt, 0));
916                i.InstrNr = sqlite3_column_int(pStmt, 1);
917                i.FormatFamily = ToString(sqlite3_column_text(pStmt, 2));
918                i.FormatVersion = ToString(sqlite3_column_text(pStmt, 3));
919                i.Size = sqlite3_column_int64(pStmt, 4);
920                i.Created = ToString(sqlite3_column_text(pStmt, 5));
921                i.Modified = ToString(sqlite3_column_text(pStmt, 6));
922                i.Description = ToString(sqlite3_column_text(pStmt, 7));
923                i.IsDrum = sqlite3_column_int(pStmt, 8);
924                i.Product = ToString(sqlite3_column_text(pStmt, 9));
925                i.Artists = ToString(sqlite3_column_text(pStmt, 10));
926                i.Keywords = ToString(sqlite3_column_text(pStmt, 11));
927            } else {
928              sqlite3_finalize(pStmt);              sqlite3_finalize(pStmt);
929          } catch (Exception e) {  
930              DbInstrumentsMutex.Unlock();              if (res != SQLITE_DONE) {
931              throw e;                  throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
932                } else {
933                    throw Exception("Unknown DB instrument");
934                }
935          }          }
936          DbInstrumentsMutex.Unlock();  
937                    sqlite3_finalize(pStmt);
938          return i;          return i;
939      }      }
940    
# Line 731  namespace LinuxSampler { Line 942  namespace LinuxSampler {
942          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()));
943          CheckFileName(Name);          CheckFileName(Name);
944    
945          DbInstrumentsMutex.Lock();          BeginTransaction();
946          try {          try {
947              int dirId = GetDirectoryId(GetDirectoryPath(Instr));              int dirId = GetDirectoryId(GetDirectoryPath(Instr));
948              if (dirId == -1) throw Exception("Unknown DB instrument: " + Instr);              if (dirId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
949    
950              int instrId = GetInstrumentId(dirId, GetFileName(Instr));              int instrId = GetInstrumentId(dirId, GetFileName(Instr));
951              if (instrId == -1) throw Exception("Unknown DB instrument: " + Instr);              if (instrId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
952    
953              if (GetInstrumentId(dirId, Name) != -1) {              if (GetInstrumentId(dirId, Name) != -1) {
954                  throw Exception("Cannot rename. Instrument with that name already exists: " + Name);                  String s = toEscapedPath(Name);
955                    throw Exception("Cannot rename. Instrument with that name already exists: " + s);
956                }
957    
958                if (GetDirectoryId(dirId, Name) != -1) {
959                    String s = toEscapedPath(Name);
960                    throw Exception("Cannot rename. Directory with that name already exists: " + s);
961              }              }
962    
963              std::stringstream sql;              std::stringstream sql;
964              sql << "UPDATE instruments SET instr_name=? WHERE instr_id=" << instrId;              sql << "UPDATE instruments SET instr_name=? WHERE instr_id=" << instrId;
965              ExecSql(sql.str(), Name);              ExecSql(sql.str(), toDbName(Name));
966          } catch (Exception e) {          } catch (Exception e) {
967              DbInstrumentsMutex.Unlock();              EndTransaction();
968              throw e;              throw e;
969          }          }
970          DbInstrumentsMutex.Unlock();          EndTransaction();
971          FireInstrumentNameChanged(Instr, Name);          FireInstrumentNameChanged(Instr, Name);
972      }      }
973    
# Line 759  namespace LinuxSampler { Line 976  namespace LinuxSampler {
976          String ParentDir = GetDirectoryPath(Instr);          String ParentDir = GetDirectoryPath(Instr);
977          if(ParentDir.empty()) throw Exception("Unknown parent directory");          if(ParentDir.empty()) throw Exception("Unknown parent directory");
978    
979          DbInstrumentsMutex.Lock();          BeginTransaction();
980          try {          try {
981              int dirId = GetDirectoryId(GetDirectoryPath(Instr));              int dirId = GetDirectoryId(ParentDir);
982              if (dirId == -1) throw Exception("Unknown DB instrument: " + Instr);              if (dirId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
983    
984              String instrName = GetFileName(Instr);              String instrName = GetFileName(Instr);
985              int instrId = GetInstrumentId(dirId, instrName);              int instrId = GetInstrumentId(dirId, instrName);
986              if (instrId == -1) throw Exception("Unknown DB instrument: " + Instr);              if (instrId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
987    
988              int dstId = GetDirectoryId(Dst);              int dstId = GetDirectoryId(Dst);
989              if (dstId == -1) throw Exception("Unknown DB directory: " + Dst);              if (dstId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dst));
990              if (dirId == dstId) {              if (dirId == dstId) {
991                  DbInstrumentsMutex.Unlock();                  EndTransaction();
992                  return;                  return;
993              }              }
994    
995              if (GetInstrumentId(dstId, instrName) != -1) {              if (GetInstrumentId(dstId, instrName) != -1) {
996                  throw Exception("Cannot move. Instrument with that name already exists: " + instrName);                  String s = toEscapedPath(instrName);
997                    throw Exception("Cannot move. Instrument with that name already exists: " + s);
998                }
999    
1000                if (GetDirectoryId(dstId, instrName) != -1) {
1001                    String s = toEscapedPath(instrName);
1002                    throw Exception("Cannot move. Directory with that name already exists: " + s);
1003              }              }
1004    
1005              std::stringstream sql;              std::stringstream sql;
# Line 784  namespace LinuxSampler { Line 1007  namespace LinuxSampler {
1007              sql << " WHERE instr_id=" << instrId;              sql << " WHERE instr_id=" << instrId;
1008              ExecSql(sql.str());              ExecSql(sql.str());
1009          } catch (Exception e) {          } catch (Exception e) {
1010              DbInstrumentsMutex.Unlock();              EndTransaction();
1011              throw e;              throw e;
1012          }          }
1013          DbInstrumentsMutex.Unlock();          EndTransaction();
1014          FireInstrumentCountChanged(ParentDir);          FireInstrumentCountChanged(ParentDir);
1015          FireInstrumentCountChanged(Dst);          FireInstrumentCountChanged(Dst);
1016      }      }
1017    
1018        void InstrumentsDb::CopyInstrument(String Instr, String Dst) {
1019            dmsg(2,("InstrumentsDb: CopyInstrument(Instr=%s,Dst=%s)\n", Instr.c_str(), Dst.c_str()));
1020            String ParentDir = GetDirectoryPath(Instr);
1021            if(ParentDir.empty()) throw Exception("Unknown parent directory");
1022    
1023            BeginTransaction();
1024            try {
1025                int dirId = GetDirectoryId(GetDirectoryPath(Instr));
1026                if (dirId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1027    
1028                String instrName = GetFileName(Instr);
1029                int instrId = GetInstrumentId(dirId, instrName);
1030                if (instrId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1031    
1032                int dstId = GetDirectoryId(Dst);
1033                if (dstId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dst));
1034                if (dirId == dstId) {
1035                    EndTransaction();
1036                    return;
1037                }
1038    
1039                if (GetInstrumentId(dstId, instrName) != -1) {
1040                    String s = toEscapedPath(instrName);
1041                    throw Exception("Cannot copy. Instrument with that name already exists: " + s);
1042                }
1043    
1044                if (GetDirectoryId(dstId, instrName) != -1) {
1045                    String s = toEscapedPath(instrName);
1046                    throw Exception("Cannot copy. Directory with that name already exists: " + s);
1047                }
1048    
1049                CopyInstrument(instrId, instrName, dstId, Dst);
1050            } catch (Exception e) {
1051                EndTransaction();
1052                throw e;
1053            }
1054            EndTransaction();
1055            
1056        }
1057    
1058        void InstrumentsDb::CopyInstrument(int InstrId, String InstrName, int DstDirId, String DstDir) {
1059            DbInstrument i = GetInstrumentInfo(InstrId);
1060            sqlite3_stmt *pStmt = NULL;
1061            std::stringstream sql;
1062            sql << "INSERT INTO instruments (dir_id,instr_name,instr_file,instr_nr,format_family,";
1063            sql << "format_version,instr_size,description,is_drum,product,artists,keywords) ";
1064            sql << "VALUES (" << DstDirId << ",?,?," << i.InstrNr << ",?,?," << i.Size << ",?,";
1065            sql << i.IsDrum << ",?,?,?)";
1066    
1067            int res = sqlite3_prepare(GetDb(), sql.str().c_str(), -1, &pStmt, NULL);
1068            if (res != SQLITE_OK) {
1069                throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1070            }
1071    
1072            BindTextParam(pStmt, 1, toDbName(InstrName));
1073            BindTextParam(pStmt, 2, i.InstrFile);
1074            BindTextParam(pStmt, 3, i.FormatFamily);
1075            BindTextParam(pStmt, 4, i.FormatVersion);
1076            BindTextParam(pStmt, 5, i.Description);
1077            BindTextParam(pStmt, 6, i.Product);
1078            BindTextParam(pStmt, 7, i.Artists);
1079            BindTextParam(pStmt, 8, i.Keywords);
1080    
1081            res = sqlite3_step(pStmt);
1082            if(res != SQLITE_DONE) {
1083                sqlite3_finalize(pStmt);
1084                throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1085            }
1086            
1087            sqlite3_finalize(pStmt);
1088            FireInstrumentCountChanged(DstDir);
1089        }
1090    
1091      void InstrumentsDb::SetInstrumentDescription(String Instr, String Desc) {      void InstrumentsDb::SetInstrumentDescription(String Instr, String Desc) {
1092          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()));
1093    
1094          DbInstrumentsMutex.Lock();          BeginTransaction();
1095          try {          try {
1096              int id = GetInstrumentId(Instr);              int id = GetInstrumentId(Instr);
1097              if(id == -1) throw Exception("Unknown DB instrument: " + Instr);              if(id == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1098    
1099              std::stringstream sql;              std::stringstream sql;
1100              sql << "UPDATE instruments SET description=?,modified=CURRENT_TIMESTAMP ";              sql << "UPDATE instruments SET description=?,modified=CURRENT_TIMESTAMP ";
# Line 806  namespace LinuxSampler { Line 1102  namespace LinuxSampler {
1102    
1103              ExecSql(sql.str(), Desc);              ExecSql(sql.str(), Desc);
1104          } catch (Exception e) {          } catch (Exception e) {
1105              DbInstrumentsMutex.Unlock();              EndTransaction();
1106              throw e;              throw e;
1107          }          }
1108          DbInstrumentsMutex.Unlock();          EndTransaction();
1109          FireInstrumentInfoChanged(Instr);          FireInstrumentInfoChanged(Instr);
1110      }      }
1111    
1112      void InstrumentsDb::AddInstrumentsFromFile(String DbDir, String File, int Index) {      void InstrumentsDb::AddInstrumentsFromFile(String DbDir, String File, int Index, ScanProgress* pProgress) {
1113          dmsg(2,("InstrumentsDb: AddInstrumentsFromFile(DbDir=%s,File=%s,Index=%d)\n", DbDir.c_str(), File.c_str(), Index));          dmsg(2,("InstrumentsDb: AddInstrumentsFromFile(DbDir=%s,File=%s,Index=%d)\n", DbDir.c_str(), File.c_str(), Index));
1114                    
1115          if(File.length() < 4) return;          if(File.length() < 4) return;
1116                    
1117          try {          try {
1118              if(!strcasecmp(".gig", File.substr(File.length() - 4).c_str())) {              if(!strcasecmp(".gig", File.substr(File.length() - 4).c_str())) {
1119                  AddGigInstruments(DbDir, File, Index);                  if (pProgress != NULL) {
1120                        pProgress->SetStatus(0);
1121                        pProgress->CurrentFile = File;
1122                    }
1123    
1124                    AddGigInstruments(DbDir, File, Index, pProgress);
1125    
1126                    if (pProgress != NULL) {
1127                        pProgress->SetScannedFileCount(pProgress->GetScannedFileCount() + 1);
1128                    }
1129              }              }
1130          } catch(Exception e) {          } catch(Exception e) {
1131              std::cout << e.Message() << std::endl;              std::cerr << e.Message() << std::endl;
1132          }          }
1133      }      }
1134    
1135      void InstrumentsDb::AddGigInstruments(String DbDir, String File, int Index) {      void InstrumentsDb::AddGigInstruments(String DbDir, String File, int Index, ScanProgress* pProgress) {
1136          dmsg(2,("InstrumentsDb: AddGigInstruments(DbDir=%s,File=%s,Index=%d)\n", DbDir.c_str(), File.c_str(), Index));          dmsg(2,("InstrumentsDb: AddGigInstruments(DbDir=%s,File=%s,Index=%d)\n", DbDir.c_str(), File.c_str(), Index));
1137          int dirId = GetDirectoryId(DbDir);          int dirId = GetDirectoryId(DbDir);
1138          if (dirId == -1) throw Exception("Invalid DB directory: " + DbDir);          if (dirId == -1) throw Exception("Invalid DB directory: " + toEscapedPath(DbDir));
1139    
1140          struct stat statBuf;          struct stat statBuf;
1141          int res = stat(File.c_str(), &statBuf);          int res = stat(File.c_str(), &statBuf);
# Line 851  namespace LinuxSampler { Line 1156  namespace LinuxSampler {
1156          try {          try {
1157              riff = new RIFF::File(File);              riff = new RIFF::File(File);
1158              gig::File* gig = new gig::File(riff);              gig::File* gig = new gig::File(riff);
1159                
1160              std::stringstream sql;              std::stringstream sql;
1161              sql << "INSERT INTO instruments (dir_id,instr_name,instr_file,";              sql << "INSERT INTO instruments (dir_id,instr_name,instr_file,";
1162              sql << "instr_nr,format_family,format_version,instr_size,";              sql << "instr_nr,format_family,format_version,instr_size,";
# Line 872  namespace LinuxSampler { Line 1177  namespace LinuxSampler {
1177    
1178              if (Index == -1) {              if (Index == -1) {
1179                  int instrIndex = 0;                  int instrIndex = 0;
1180                    if (pProgress != NULL) gig->GetInstrument(0, &(pProgress->GigFileProgress)); // TODO: this workaround should be fixed
1181                  gig::Instrument* pInstrument = gig->GetFirstInstrument();                  gig::Instrument* pInstrument = gig->GetFirstInstrument();
1182                  while (pInstrument) {                  while (pInstrument) {
1183                      BindTextParam(pStmt, 7, gig->pInfo->Product);                      BindTextParam(pStmt, 7, gig->pInfo->Product);
# Line 883  namespace LinuxSampler { Line 1189  namespace LinuxSampler {
1189                      pInstrument = gig->GetNextInstrument();                      pInstrument = gig->GetNextInstrument();
1190                  }                  }
1191              } else {              } else {
1192                  gig::Instrument* pInstrument = gig->GetInstrument(Index);                  gig::Instrument* pInstrument;
1193                    if (pProgress == NULL) pInstrument = gig->GetInstrument(Index);
1194                    else pInstrument = gig->GetInstrument(Index, &(pProgress->GigFileProgress));
1195                  if (pInstrument != NULL) {                  if (pInstrument != NULL) {
1196                      BindTextParam(pStmt, 7, gig->pInfo->Product);                      BindTextParam(pStmt, 7, gig->pInfo->Product);
1197                      BindTextParam(pStmt, 8, gig->pInfo->Artists);                      BindTextParam(pStmt, 8, gig->pInfo->Artists);
# Line 892  namespace LinuxSampler { Line 1200  namespace LinuxSampler {
1200                  }                  }
1201              }              }
1202    
1203                sqlite3_finalize(pStmt);
1204              delete gig;              delete gig;
1205              delete riff;              delete riff;
1206          } catch (RIFF::Exception e) {          } catch (RIFF::Exception e) {
# Line 912  namespace LinuxSampler { Line 1221  namespace LinuxSampler {
1221          }          }
1222      }      }
1223    
1224      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) {
1225          String name = pInstrument->pInfo->Name;          String name = pInstrument->pInfo->Name;
1226          if (name == "") return;          if (name == "") return;
1227          name = GetUniqueInstrumentName(DirId, name);          name = GetUniqueInstrumentName(DirId, name);
# Line 949  namespace LinuxSampler { Line 1258  namespace LinuxSampler {
1258          FireInstrumentCountChanged(DbDir);          FireInstrumentCountChanged(DbDir);
1259      }      }
1260    
1261        void InstrumentsDb::DirectoryTreeWalk(String AbstractPath, DirectoryHandler* pHandler) {
1262            int DirId = GetDirectoryId(AbstractPath);
1263            if(DirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(AbstractPath));
1264            DirectoryTreeWalk(pHandler, AbstractPath, DirId, 0);
1265        }
1266    
1267        void InstrumentsDb::DirectoryTreeWalk(DirectoryHandler* pHandler, String AbstractPath, int DirId, int Level) {
1268            if(Level == 1000) throw Exception("Possible infinite loop detected");
1269            pHandler->ProcessDirectory(AbstractPath, DirId);
1270            
1271            String s;
1272            StringListPtr pDirs = GetDirectories(DirId);
1273            for(int i = 0; i < pDirs->size(); i++) {
1274                if (AbstractPath.length() == 1 && AbstractPath.at(0) == '/') {
1275                    s = "/" + pDirs->at(i);
1276                } else {
1277                    s = AbstractPath + "/" + pDirs->at(i);
1278                }
1279                DirectoryTreeWalk(pHandler, s, GetDirectoryId(DirId, pDirs->at(i)), Level + 1);
1280            }
1281        }
1282    
1283        StringListPtr InstrumentsDb::FindDirectories(String Dir, SearchQuery* pQuery, bool Recursive) {
1284            dmsg(2,("InstrumentsDb: FindDirectories(Dir=%s)\n", Dir.c_str()));
1285            DirectoryFinder directoryFinder(pQuery);
1286            
1287            BeginTransaction();
1288            try {
1289                int DirId = GetDirectoryId(Dir);
1290                if(DirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
1291    
1292                if (Recursive) DirectoryTreeWalk(Dir, &directoryFinder);
1293                else directoryFinder.ProcessDirectory(Dir, DirId);
1294            } catch (Exception e) {
1295                EndTransaction();
1296                throw e;
1297            }
1298            EndTransaction();
1299    
1300            return directoryFinder.GetDirectories();
1301        }
1302    
1303        StringListPtr InstrumentsDb::FindInstruments(String Dir, SearchQuery* pQuery, bool Recursive) {
1304            dmsg(2,("InstrumentsDb: FindInstruments(Dir=%s)\n", Dir.c_str()));
1305            InstrumentFinder instrumentFinder(pQuery);
1306            
1307            BeginTransaction();
1308            try {
1309                int DirId = GetDirectoryId(Dir);
1310                if(DirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
1311    
1312                if (Recursive) DirectoryTreeWalk(Dir, &instrumentFinder);
1313                else instrumentFinder.ProcessDirectory(Dir, DirId);
1314            } catch (Exception e) {
1315                EndTransaction();
1316                throw e;
1317            }
1318            EndTransaction();
1319    
1320            return instrumentFinder.GetInstruments();
1321        }
1322    
1323        void InstrumentsDb::BeginTransaction() {
1324            dmsg(2,("InstrumentsDb: BeginTransaction(InTransaction=%d)\n", InTransaction));
1325            DbInstrumentsMutex.Lock();
1326            if (InTransaction) return;
1327            
1328            if(db == NULL) return;
1329            sqlite3_stmt *pStmt = NULL;
1330            
1331            InTransaction = true;
1332            int res = sqlite3_prepare(db, "BEGIN TRANSACTION", -1, &pStmt, NULL);
1333            if (res != SQLITE_OK) {
1334                std::cerr << ToString(sqlite3_errmsg(db)) << std::endl;
1335                return;
1336            }
1337            
1338            res = sqlite3_step(pStmt);
1339            if(res != SQLITE_DONE) {
1340                sqlite3_finalize(pStmt);
1341                std::cerr << ToString(sqlite3_errmsg(db)) << std::endl;
1342                return;
1343            }
1344    
1345            sqlite3_finalize(pStmt);
1346        }
1347    
1348        void InstrumentsDb::EndTransaction() {
1349            dmsg(2,("InstrumentsDb: EndTransaction(InTransaction=%d)\n", InTransaction));
1350            if (!InTransaction) {
1351                DbInstrumentsMutex.Unlock();
1352                return;
1353            }
1354            InTransaction = false;
1355            
1356            if(db == NULL) {
1357                DbInstrumentsMutex.Unlock();
1358                return;
1359            }
1360            sqlite3_stmt *pStmt = NULL;
1361            
1362            int res = sqlite3_prepare(db, "END TRANSACTION", -1, &pStmt, NULL);
1363            if (res != SQLITE_OK) {
1364                std::cerr << ToString(sqlite3_errmsg(db)) << std::endl;
1365                DbInstrumentsMutex.Unlock();
1366                return;
1367            }
1368            
1369            res = sqlite3_step(pStmt);
1370            if(res != SQLITE_DONE) {
1371                sqlite3_finalize(pStmt);
1372                std::cerr << ToString(sqlite3_errmsg(db)) << std::endl;
1373                DbInstrumentsMutex.Unlock();
1374                return;
1375            }
1376    
1377            sqlite3_finalize(pStmt);
1378            DbInstrumentsMutex.Unlock();
1379        }
1380    
1381      void InstrumentsDb::ExecSql(String Sql) {      void InstrumentsDb::ExecSql(String Sql) {
1382          dmsg(2,("InstrumentsDb: ExecSql(Sql=%s)\n", Sql.c_str()));          dmsg(2,("InstrumentsDb: ExecSql(Sql=%s)\n", Sql.c_str()));
1383          sqlite3_stmt *pStmt = NULL;          sqlite3_stmt *pStmt = NULL;
# Line 1128  namespace LinuxSampler { Line 1557  namespace LinuxSampler {
1557          }          }
1558      }      }
1559    
1560        void InstrumentsDb::Regexp(sqlite3_context* pContext, int argc, sqlite3_value** ppValue) {
1561            if (argc != 2) return;
1562    
1563            String pattern = ToString(sqlite3_value_text(ppValue[0]));
1564            String str = ToString(sqlite3_value_text(ppValue[1]));
1565    
1566            if(!fnmatch(pattern.c_str(), str.c_str(), FNM_CASEFOLD)) {
1567                sqlite3_result_int(pContext, 1);
1568            }
1569        }
1570    
1571      String InstrumentsDb::GetDirectoryPath(String File) {      String InstrumentsDb::GetDirectoryPath(String File) {
1572          if (File.empty()) return String("");          if (File.empty()) return String("");
1573          if (File.at(0) != '/') String("");          if (File.at(0) != '/') String("");
# Line 1171  namespace LinuxSampler { Line 1611  namespace LinuxSampler {
1611    
1612      void InstrumentsDb::CheckFileName(String File) {      void InstrumentsDb::CheckFileName(String File) {
1613          if (File.empty()) throw Exception("Invalid file name: " + File);          if (File.empty()) throw Exception("Invalid file name: " + File);
         if (File.find('/') != std::string::npos) {  
             throw Exception("Invalid file name: " + File);  
         }  
1614      }      }
1615    
1616      String InstrumentsDb::GetUniqueInstrumentName(int DirId, String Name) {      String InstrumentsDb::GetUniqueInstrumentName(int DirId, String Name) {
1617          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=?";  
1618    
1619          if (ExecSqlInt(sql.str(), Name) == 0) return Name;          if (GetInstrumentId(DirId, Name) == -1 && GetDirectoryId(DirId, Name) == -1) return Name;
1620          std::stringstream ss;          std::stringstream ss;
1621          for(int i = 2; i < 1001; i++) {          for(int i = 2; i < 1001; i++) {
1622              ss.str("");              ss.str("");
1623              ss << Name << '[' << i << ']';              ss << Name << '[' << i << ']';
1624              if (ExecSqlInt(sql.str(), ss.str()) == 0) return ss.str();              if (GetInstrumentId(DirId, ss.str()) == -1 && GetInstrumentId(DirId, ss.str()) == -1) {
1625                    return ss.str();
1626                }
1627          }          }
1628    
1629          throw Exception("Unable to find an unique name: " + Name);          throw Exception("Unable to find an unique name: " + Name);
1630      }      }
1631    
1632        String InstrumentsDb::toDbName(String AbstractName) {
1633            for (int i = 0; i < AbstractName.length(); i++) {
1634                if (AbstractName.at(i) == '\0') AbstractName.at(i) = '/';
1635            }
1636            return AbstractName;
1637        }
1638    
1639        String InstrumentsDb::toEscapedPath(String AbstractName) {
1640            for (int i = 0; i < AbstractName.length(); i++) {
1641                if (AbstractName.at(i) == '\0')      AbstractName.replace(i++, 1, "\\/");
1642                else if (AbstractName.at(i) == '\\') AbstractName.replace(i++, 1, "\\\\");
1643                else if (AbstractName.at(i) == '\'') AbstractName.replace(i++, 1, "\\'");
1644                else if (AbstractName.at(i) == '"')  AbstractName.replace(i++, 1, "\\\"");
1645                else if (AbstractName.at(i) == '\r') AbstractName.replace(i++, 1, "\\r");
1646                else if (AbstractName.at(i) == '\n') AbstractName.replace(i++, 1, "\\n");
1647            }
1648            return AbstractName;
1649        }
1650        
1651        String InstrumentsDb::toEscapedText(String text) {
1652            for (int i = 0; i < text.length(); i++) {
1653                if (text.at(i) == '\\')      text.replace(i++, 1, "\\\\");
1654                else if (text.at(i) == '\'') text.replace(i++, 1, "\\'");
1655                else if (text.at(i) == '"')  text.replace(i++, 1, "\\\"");
1656                else if (text.at(i) == '\r') text.replace(i++, 1, "\\r");
1657                else if (text.at(i) == '\n') text.replace(i++, 1, "\\n");
1658            }
1659            return text;
1660        }
1661        
1662        String InstrumentsDb::toEscapedName(String AbstractName) {
1663            for (int i = 0; i < AbstractName.length(); i++) {
1664                if (AbstractName.at(i) == '\0')      AbstractName.at(i) = '/';
1665                else if (AbstractName.at(i) == '\\') AbstractName.replace(i++, 1, "\\\\");
1666                else if (AbstractName.at(i) == '\'') AbstractName.replace(i++, 1, "\\'");
1667                else if (AbstractName.at(i) == '"')  AbstractName.replace(i++, 1, "\\\"");
1668                else if (AbstractName.at(i) == '\r') AbstractName.replace(i++, 1, "\\r");
1669                else if (AbstractName.at(i) == '\n') AbstractName.replace(i++, 1, "\\n");
1670            }
1671            return AbstractName;
1672        }
1673            
1674        String InstrumentsDb::toAbstractName(String DbName) {
1675            for (int i = 0; i < DbName.length(); i++) {
1676                if (DbName.at(i) == '/') DbName.at(i) = '\0';
1677            }
1678            return DbName;
1679        }
1680    
1681      void InstrumentsDb::FireDirectoryCountChanged(String Dir) {      void InstrumentsDb::FireDirectoryCountChanged(String Dir) {
1682          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1683              llInstrumentsDbListeners.GetListener(i)->DirectoryCountChanged(Dir);              llInstrumentsDbListeners.GetListener(i)->DirectoryCountChanged(Dir);
1684          }          }
1685      }      }
1686        
1687      void InstrumentsDb::FireDirectoryInfoChanged(String Dir) {      void InstrumentsDb::FireDirectoryInfoChanged(String Dir) {
1688          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1689              llInstrumentsDbListeners.GetListener(i)->DirectoryInfoChanged(Dir);              llInstrumentsDbListeners.GetListener(i)->DirectoryInfoChanged(Dir);
1690          }          }
1691      }      }
1692        
1693      void InstrumentsDb::FireDirectoryNameChanged(String Dir, String NewName) {      void InstrumentsDb::FireDirectoryNameChanged(String Dir, String NewName) {
1694          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1695              llInstrumentsDbListeners.GetListener(i)->DirectoryNameChanged(Dir, NewName);              llInstrumentsDbListeners.GetListener(i)->DirectoryNameChanged(Dir, NewName);
1696          }          }
1697      }      }
1698        
1699      void InstrumentsDb::FireInstrumentCountChanged(String Dir) {      void InstrumentsDb::FireInstrumentCountChanged(String Dir) {
1700          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1701              llInstrumentsDbListeners.GetListener(i)->InstrumentCountChanged(Dir);              llInstrumentsDbListeners.GetListener(i)->InstrumentCountChanged(Dir);
1702          }          }
1703      }      }
1704        
1705      void InstrumentsDb::FireInstrumentInfoChanged(String Instr) {      void InstrumentsDb::FireInstrumentInfoChanged(String Instr) {
1706          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1707              llInstrumentsDbListeners.GetListener(i)->InstrumentInfoChanged(Instr);              llInstrumentsDbListeners.GetListener(i)->InstrumentInfoChanged(Instr);
1708          }          }
1709      }      }
1710        
1711      void InstrumentsDb::FireInstrumentNameChanged(String Instr, String NewName) {      void InstrumentsDb::FireInstrumentNameChanged(String Instr, String NewName) {
1712          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1713              llInstrumentsDbListeners.GetListener(i)->InstrumentNameChanged(Instr, NewName);              llInstrumentsDbListeners.GetListener(i)->InstrumentNameChanged(Instr, NewName);
1714          }          }
1715      }      }
       
1716    
1717      String DirectoryScanner::DbDir;      void InstrumentsDb::FireJobStatusChanged(int JobId) {
1718      String DirectoryScanner::FsDir;          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1719      bool DirectoryScanner::Flat;              llInstrumentsDbListeners.GetListener(i)->JobStatusChanged(JobId);
   
     void DirectoryScanner::Scan(String DbDir, String FsDir, bool Flat) {  
         dmsg(2,("DirectoryScanner: Scan(DbDir=%s,FsDir=%s,Flat=%d)\n", DbDir.c_str(), FsDir.c_str(), Flat));  
         if (DbDir.empty() || FsDir.empty()) throw Exception("Directory expected");  
           
         struct stat statBuf;  
         int res = stat(FsDir.c_str(), &statBuf);  
         if (res) {  
             std::stringstream ss;  
             ss << "Fail to stat `" << FsDir << "`: " << strerror(errno);  
             throw Exception(ss.str());  
         }  
   
         if (!S_ISDIR(statBuf.st_mode)) {  
             throw Exception("Directory expected");  
         }  
           
         DirectoryScanner::DbDir = DbDir;  
         DirectoryScanner::FsDir = FsDir;  
         if (DbDir.at(DbDir.length() - 1) != '/') {  
             DirectoryScanner::DbDir.append("/");  
         }  
         if (FsDir.at(FsDir.length() - 1) != '/') {  
             DirectoryScanner::FsDir.append("/");  
1720          }          }
         DirectoryScanner::Flat = Flat;  
           
         ftw(FsDir.c_str(), FtwCallback, 10);  
1721      }      }
1722    
     int DirectoryScanner::FtwCallback(const char* fpath, const struct stat* sb, int typeflag) {  
         dmsg(2,("DirectoryScanner: FtwCallback(fpath=%s)\n", fpath));  
         if (typeflag != FTW_D) return 0;  
   
         String dir = DbDir;  
         if (!Flat) {  
             String subdir = fpath;  
             if(subdir.length() > FsDir.length()) {  
                 subdir = subdir.substr(FsDir.length());  
                 dir += subdir;  
             }  
         }  
           
         InstrumentsDb* db = InstrumentsDb::GetInstrumentsDb();  
         if (!db->DirectoryExist(dir)) db->AddDirectory(dir);  
   
         db->AddInstrumentsNonrecursive(dir, String(fpath));  
   
         return 0;  
     };  
   
1723  } // namespace LinuxSampler  } // namespace LinuxSampler
1724    
1725  #endif // HAVE_SQLITE3  #endif // HAVE_SQLITE3

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

  ViewVC Help
Powered by ViewVC