/[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 1200 by iliev, Thu May 24 14:04:18 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: " + Dir);
177                    
178          return i;          return i;
# 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: " + Dir);
196    
197              std::stringstream sql;              StringListPtr pDirs;
198              sql << "SELECT dir_name FROM instr_dirs ";              if (Recursive) {
199              sql << "WHERE parent_dir_id=" << dirId << " AND dir_id!=0";                  SearchQuery q;
200                    DirectoryFinder directoryFinder(&q);
201              DbInstrumentsMutex.Unlock();                  DirectoryTreeWalk(Dir, &directoryFinder);
202              return ExecSqlStringList(sql.str());                  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            return ExecSqlStringList(sql.str());
219        }
220    
221      int InstrumentsDb::GetDirectoryId(String Dir) {      int InstrumentsDb::GetDirectoryId(String Dir) {
222          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 250  namespace LinuxSampler {
250          return ExecSqlInt(sql.str(), DirName);          return ExecSqlInt(sql.str(), DirName);
251      }      }
252    
253        String InstrumentsDb::GetDirectoryName(int DirId) {
254            String sql = "SELECT dir_name FROM instr_dirs WHERE dir_id=" + ToString(DirId);
255            String name = ExecSqlString(sql);
256            if (name.empty()) throw Exception("Directory ID not found");
257            return name;
258        }
259    
260        int InstrumentsDb::GetParentDirectoryId(int DirId) {
261            if (DirId == 0) throw Exception("The root directory is specified");
262            String sql = "SELECT parent_dir_id FROM instr_dirs WHERE dir_id=" + ToString(DirId);
263            int parentId = ExecSqlInt(sql);
264            if (parentId == -1) throw Exception("DB directory not found");
265            return parentId;
266        }
267    
268        String InstrumentsDb::GetDirectoryPath(int DirId) {
269            String path = "";
270            int count = 1000; // used to prevent infinite loops
271    
272            while(--count) {
273                if (DirId == 0) {
274                    path = "/" + path;
275                    break;
276                }
277                path = GetDirectoryName(DirId) + path;
278                DirId = GetParentDirectoryId(DirId);
279            }
280    
281            if (!count) throw Exception("Possible infinite loop detected");
282    
283            return path;
284        }
285    
286      void InstrumentsDb::AddDirectory(String Dir) {      void InstrumentsDb::AddDirectory(String Dir) {
287          dmsg(2,("InstrumentsDb: AddDirectory(Dir=%s)\n", Dir.c_str()));          dmsg(2,("InstrumentsDb: AddDirectory(Dir=%s)\n", Dir.c_str()));
288          CheckPathName(Dir);          CheckPathName(Dir);
289          String ParentDir = GetParentDirectory(Dir);          String ParentDir = GetParentDirectory(Dir);
290                    
291          DbInstrumentsMutex.Lock();          BeginTransaction();
292          try {          try {
293              if (Dir.length() > 1) {              if (Dir.length() > 1) {
294                  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 303  namespace LinuxSampler {
303              if (id == -1) throw Exception("DB directory doesn't exist: " + ParentDir);              if (id == -1) throw Exception("DB directory doesn't exist: " + ParentDir);
304              int id2 = GetDirectoryId(id, dirName);              int id2 = GetDirectoryId(id, dirName);
305              if (id2 != -1) throw Exception("DB directory already exist: " + Dir);              if (id2 != -1) throw Exception("DB directory already exist: " + Dir);
306                id2 = GetInstrumentId(id, dirName);
307                if (id2 != -1) throw Exception("Instrument with that name exist: " + Dir);
308    
309              std::stringstream sql;              std::stringstream sql;
310              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 312  namespace LinuxSampler {
312    
313              ExecSql(sql.str(), dirName);              ExecSql(sql.str(), dirName);
314          } catch (Exception e) {          } catch (Exception e) {
315              DbInstrumentsMutex.Unlock();              EndTransaction();
316              throw e;              throw e;
317          }          }
318    
319          DbInstrumentsMutex.Unlock();          EndTransaction();
320    
321          FireDirectoryCountChanged(ParentDir);          FireDirectoryCountChanged(ParentDir);
322      }      }
# Line 244  namespace LinuxSampler { Line 326  namespace LinuxSampler {
326    
327          String ParentDir = GetParentDirectory(Dir);          String ParentDir = GetParentDirectory(Dir);
328    
329          DbInstrumentsMutex.Lock();          BeginTransaction();
330          try {          try {
331              int dirId = GetDirectoryId(Dir);              int dirId = GetDirectoryId(Dir);
332              if (dirId == -1) throw Exception("Unknown DB directory: " + Dir);              if (dirId == -1) throw Exception("Unknown DB directory: " + Dir);
# Line 253  namespace LinuxSampler { Line 335  namespace LinuxSampler {
335              if (Force) RemoveDirectoryContent(dirId);              if (Force) RemoveDirectoryContent(dirId);
336              RemoveDirectory(dirId);              RemoveDirectory(dirId);
337          } catch (Exception e) {          } catch (Exception e) {
338              DbInstrumentsMutex.Unlock();              EndTransaction();
339              throw e;              throw e;
340          }          }
341    
342          DbInstrumentsMutex.Unlock();          EndTransaction();
343          FireDirectoryCountChanged(ParentDir);          FireDirectoryCountChanged(ParentDir);
344      }      }
345    
# Line 330  namespace LinuxSampler { Line 412  namespace LinuxSampler {
412          dmsg(2,("InstrumentsDb: GetDirectoryInfo(Dir=%s)\n", Dir.c_str()));          dmsg(2,("InstrumentsDb: GetDirectoryInfo(Dir=%s)\n", Dir.c_str()));
413          DbDirectory d;          DbDirectory d;
414    
415          DbInstrumentsMutex.Lock();          BeginTransaction();
416    
417          try {          try {
418              int id = GetDirectoryId(Dir);              int id = GetDirectoryId(Dir);
# Line 363  namespace LinuxSampler { Line 445  namespace LinuxSampler {
445                            
446              sqlite3_finalize(pStmt);              sqlite3_finalize(pStmt);
447          } catch (Exception e) {          } catch (Exception e) {
448              DbInstrumentsMutex.Unlock();              EndTransaction();
449              throw e;              throw e;
450          }          }
451    
452          DbInstrumentsMutex.Unlock();          EndTransaction();
453          return d;          return d;
454      }      }
455    
# Line 375  namespace LinuxSampler { Line 457  namespace LinuxSampler {
457          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()));
458          CheckFileName(Name);          CheckFileName(Name);
459    
460          DbInstrumentsMutex.Lock();          BeginTransaction();
461          try {          try {
462              int dirId = GetDirectoryId(Dir);              int dirId = GetDirectoryId(Dir);
463              if (dirId == -1) throw Exception("Unknown DB directory: " + Dir);              if (dirId == -1) throw Exception("Unknown DB directory: " + Dir);
# Line 389  namespace LinuxSampler { Line 471  namespace LinuxSampler {
471                  throw Exception("Cannot rename. Directory with that name already exists: " + Name);                  throw Exception("Cannot rename. Directory with that name already exists: " + Name);
472              }              }
473    
474                if (GetInstrumentId(parent, Name) != -1) {
475                    throw Exception("Cannot rename. Instrument with that name exist: " + Dir);
476                }
477    
478              sql.str("");              sql.str("");
479              sql << "UPDATE instr_dirs SET dir_name=? WHERE dir_id=" << dirId;              sql << "UPDATE instr_dirs SET dir_name=? WHERE dir_id=" << dirId;
480              ExecSql(sql.str(), Name);              ExecSql(sql.str(), Name);
481          } catch (Exception e) {          } catch (Exception e) {
482              DbInstrumentsMutex.Unlock();              EndTransaction();
483              throw e;              throw e;
484          }          }
485    
486          DbInstrumentsMutex.Unlock();          EndTransaction();
487          FireDirectoryNameChanged(Dir, Name);          FireDirectoryNameChanged(Dir, Name);
488      }      }
489    
490      void InstrumentsDb::MoveDirectory(String Dir, String Dst) {      void InstrumentsDb::MoveDirectory(String Dir, String Dst) {
491          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()));
492    
493            if(Dir.compare("/") == 0) throw Exception("Cannot move the root directory");
494          String ParentDir = GetParentDirectory(Dir);          String ParentDir = GetParentDirectory(Dir);
495          if(ParentDir.empty()) throw Exception("Unknown parent directory");          if(ParentDir.empty()) throw Exception("Unknown parent directory");
496    
497          DbInstrumentsMutex.Lock();          BeginTransaction();
498          try {          try {
499              int dirId = GetDirectoryId(Dir);              int dirId = GetDirectoryId(Dir);
500              if (dirId == -1) throw Exception("Unknown DB directory: " + Dir);              if (dirId == -1) throw Exception("Unknown DB directory: " + Dir);
# Line 423  namespace LinuxSampler { Line 510  namespace LinuxSampler {
510                      throw Exception("Cannot move a directory to a subdirectory of itself.");                      throw Exception("Cannot move a directory to a subdirectory of itself.");
511                  }                  }
512              }              }
513                
514                Dir.erase(Dir.length() - 1);
515                String dirName = GetFileName(Dir);
516    
517                int id2 = GetDirectoryId(dstId, dirName);
518                if (id2 != -1) throw Exception("DB directory already exist: " + dirName);
519                id2 = GetInstrumentId(dstId, dirName);
520                if (id2 != -1) throw Exception("Instrument with that name exist: " + dirName);
521    
522              std::stringstream sql;              std::stringstream sql;
523              sql << "UPDATE instr_dirs SET parent_dir_id=" << dstId;              sql << "UPDATE instr_dirs SET parent_dir_id=" << dstId;
524              sql << " WHERE dir_id=" << dirId;              sql << " WHERE dir_id=" << dirId;
525              ExecSql(sql.str());              ExecSql(sql.str());
526          } catch (Exception e) {          } catch (Exception e) {
527              DbInstrumentsMutex.Unlock();              EndTransaction();
528              throw e;              throw e;
529          }          }
530    
531          DbInstrumentsMutex.Unlock();          EndTransaction();
532          FireDirectoryCountChanged(ParentDir);          FireDirectoryCountChanged(ParentDir);
533          FireDirectoryCountChanged(Dst);          FireDirectoryCountChanged(Dst);
534      }      }
535    
536        void InstrumentsDb::CopyDirectory(String Dir, String Dst) {
537            dmsg(2,("InstrumentsDb: CopyDirectory(Dir=%s,Dst=%s)\n", Dir.c_str(), Dst.c_str()));
538    
539            if(Dir.compare("/") == 0) throw Exception("Cannot copy the root directory");
540            String ParentDir = GetParentDirectory(Dir);
541            if(ParentDir.empty()) throw Exception("Unknown parent directory");
542    
543            BeginTransaction();
544            try {
545                int dirId = GetDirectoryId(Dir);
546                if (dirId == -1) throw Exception("Unknown DB directory: " + Dir);
547                int dstId = GetDirectoryId(Dst);
548                if (dstId == -1) throw Exception("Unknown DB directory: " + Dst);
549                if (dirId == dstId) {
550                    throw Exception("Cannot copy directory to itself");
551                }
552    
553                if (Dir.at(Dir.length() - 1) != '/') Dir.append("/");
554                if (Dst.length() > Dir.length()) {
555                    if (Dir.compare(Dst.substr(0, Dir.length())) == 0) {
556                        throw Exception("Cannot copy a directory to a subdirectory of itself.");
557                    }
558                }
559                
560                Dir.erase(Dir.length() - 1);
561                String dirName = GetFileName(Dir);
562    
563                int id2 = GetDirectoryId(dstId, dirName);
564                if (id2 != -1) throw Exception("DB directory already exist: " + dirName);
565                id2 = GetInstrumentId(dstId, dirName);
566                if (id2 != -1) throw Exception("Instrument with that name exist: " + dirName);
567    
568                DirectoryCopier directoryCopier(ParentDir, Dst);
569                DirectoryTreeWalk(Dir, &directoryCopier);
570            } catch (Exception e) {
571                EndTransaction();
572                throw e;
573            }
574    
575            EndTransaction();
576        }
577    
578      void InstrumentsDb::SetDirectoryDescription(String Dir, String Desc) {      void InstrumentsDb::SetDirectoryDescription(String Dir, String Desc) {
579          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()));
580                    
581          DbInstrumentsMutex.Lock();          BeginTransaction();
582          try {          try {
583              int id = GetDirectoryId(Dir);              int id = GetDirectoryId(Dir);
584              if(id == -1) throw Exception("Unknown DB directory: " + Dir);              if(id == -1) throw Exception("Unknown DB directory: " + Dir);
# Line 452  namespace LinuxSampler { Line 589  namespace LinuxSampler {
589                    
590              ExecSql(sql.str(), Desc);              ExecSql(sql.str(), Desc);
591          } catch (Exception e) {          } catch (Exception e) {
592              DbInstrumentsMutex.Unlock();              EndTransaction();
593              throw e;              throw e;
594          }          }
595          DbInstrumentsMutex.Unlock();          EndTransaction();
596                    
597          FireDirectoryInfoChanged(Dir);          FireDirectoryInfoChanged(Dir);
598      }      }
599    
600      void InstrumentsDb::AddInstruments(String DbDir, String FilePath, int Index) {      int InstrumentsDb::AddInstruments(ScanMode Mode, String DbDir, String FsDir, bool bBackground) {
601            dmsg(2,("InstrumentsDb: AddInstruments(Mode=%d,DbDir=%s,FsDir=%s,bBackground=%d)\n", Mode, DbDir.c_str(), FsDir.c_str(), bBackground));
602            if(!bBackground) {
603                switch (Mode) {
604                    case NON_RECURSIVE:
605                        AddInstrumentsNonrecursive(DbDir, FsDir);
606                        break;
607                    case RECURSIVE:
608                        AddInstrumentsRecursive(DbDir, FsDir);
609                        break;
610                    case FLAT:
611                        AddInstrumentsRecursive(DbDir, FsDir, true);
612                        break;
613                    default:
614                        throw Exception("Unknown scan mode");
615                }
616    
617                return -1;
618            }
619    
620            ScanJob job;
621            int jobId = Jobs.AddJob(job);
622            InstrumentsDbThread.Execute(new AddInstrumentsJob(jobId, Mode, DbDir, FsDir));
623    
624            return jobId;
625        }
626        
627        int InstrumentsDb::AddInstruments(String DbDir, String FilePath, int Index, bool bBackground) {
628            dmsg(2,("InstrumentsDb: AddInstruments(DbDir=%s,FilePath=%s,Index=%d,bBackground=%d)\n", DbDir.c_str(), FilePath.c_str(), Index, bBackground));
629            if(!bBackground) {
630                AddInstruments(DbDir, FilePath, Index);
631                return -1;
632            }
633    
634            ScanJob job;
635            int jobId = Jobs.AddJob(job);
636            InstrumentsDbThread.Execute(new AddInstrumentsFromFileJob(jobId, DbDir, FilePath, Index));
637    
638            return jobId;
639        }
640    
641        void InstrumentsDb::AddInstruments(String DbDir, String FilePath, int Index, ScanProgress* pProgress) {
642          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));
643          if (DbDir.empty() || FilePath.empty()) return;          if (DbDir.empty() || FilePath.empty()) return;
644                    
# Line 477  namespace LinuxSampler { Line 655  namespace LinuxSampler {
655                  throw Exception(ss.str());                  throw Exception(ss.str());
656              }              }
657    
658              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) {  
659                  std::stringstream ss;                  std::stringstream ss;
660                  ss << "`" << FilePath << "` is directory, not an instrument file";                  ss << "`" << FilePath << "` is not an instrument file";
661                  throw Exception(ss.str());                  throw Exception(ss.str());
662              }              }
663            
664              AddInstrumentsRecursive(DbDir, FilePath, false);              AddInstrumentsFromFile(DbDir, FilePath, Index, pProgress);
665          } catch (Exception e) {          } catch (Exception e) {
666              DbInstrumentsMutex.Unlock();              DbInstrumentsMutex.Unlock();
667              throw e;              throw e;
# Line 503  namespace LinuxSampler { Line 670  namespace LinuxSampler {
670          DbInstrumentsMutex.Unlock();          DbInstrumentsMutex.Unlock();
671      }      }
672    
673      void InstrumentsDb::AddInstrumentsNonrecursive(String DbDir, String FsDir) {      void InstrumentsDb::AddInstrumentsNonrecursive(String DbDir, String FsDir, ScanProgress* pProgress) {
674          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()));
675          if (DbDir.empty() || FsDir.empty()) return;          if (DbDir.empty() || FsDir.empty()) return;
676                    
# Line 531  namespace LinuxSampler { Line 698  namespace LinuxSampler {
698                  std::stringstream ss;                  std::stringstream ss;
699                  ss << "The scanning of directory `" << FsDir << "` failed: ";                  ss << "The scanning of directory `" << FsDir << "` failed: ";
700                  ss << strerror(errno);                  ss << strerror(errno);
701                  std::cout << ss.str();                  std::cerr << ss.str();
702                  DbInstrumentsMutex.Unlock();                  DbInstrumentsMutex.Unlock();
703                  return;                  return;
704              }              }
# Line 543  namespace LinuxSampler { Line 710  namespace LinuxSampler {
710                      continue;                      continue;
711                  }                  }
712    
713                  AddInstrumentsFromFile(DbDir, FsDir + String(pEnt->d_name));                  AddInstrumentsFromFile(DbDir, FsDir + String(pEnt->d_name), -1, pProgress);
714                  pEnt = readdir(pDir);                  pEnt = readdir(pDir);
715              }              }
716    
# Line 551  namespace LinuxSampler { Line 718  namespace LinuxSampler {
718                  std::stringstream ss;                  std::stringstream ss;
719                  ss << "Failed to close directory `" << FsDir << "`: ";                  ss << "Failed to close directory `" << FsDir << "`: ";
720                  ss << strerror(errno);                  ss << strerror(errno);
721                  std::cout << ss.str();                  std::cerr << ss.str();
722              }              }
723          } catch (Exception e) {          } catch (Exception e) {
724              DbInstrumentsMutex.Unlock();              DbInstrumentsMutex.Unlock();
# Line 561  namespace LinuxSampler { Line 728  namespace LinuxSampler {
728          DbInstrumentsMutex.Unlock();          DbInstrumentsMutex.Unlock();
729      }      }
730    
731      void InstrumentsDb::AddInstrumentsRecursive(String DbDir, String FsDir, bool Flat) {      void InstrumentsDb::AddInstrumentsRecursive(String DbDir, String FsDir, bool Flat, ScanProgress* pProgress) {
732          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));
733          DirectoryScanner::Scan(DbDir, FsDir, Flat);          if (pProgress != NULL) {
734                pProgress->SetTotalFileCount(InstrumentFileCounter::Count(FsDir));
735            }
736    
737            DirectoryScanner::Scan(DbDir, FsDir, Flat, pProgress);
738      }      }
739    
740      int InstrumentsDb::GetInstrumentCount(int DirId) {      int InstrumentsDb::GetInstrumentCount(int DirId) {
# Line 576  namespace LinuxSampler { Line 747  namespace LinuxSampler {
747          return ExecSqlInt(sql.str());          return ExecSqlInt(sql.str());
748      }      }
749    
750      int InstrumentsDb::GetInstrumentCount(String Dir) {      int InstrumentsDb::GetInstrumentCount(String Dir, bool Recursive) {
751          dmsg(2,("InstrumentsDb: GetInstrumentCount(Dir=%s)\n", Dir.c_str()));          dmsg(2,("InstrumentsDb: GetInstrumentCount(Dir=%s,Recursive=%d)\n", Dir.c_str(), Recursive));
752          int i;          int i;
753                    
754          DbInstrumentsMutex.Lock();          BeginTransaction();
755          try { i = GetInstrumentCount(GetDirectoryId(Dir)); }          try {
756          catch (Exception e) {              if (Recursive) {
757              DbInstrumentsMutex.Unlock();                  InstrumentCounter instrumentCounter;
758                    DirectoryTreeWalk(Dir, &instrumentCounter);
759                    i = instrumentCounter.GetInstrumentCount();
760                } else {
761                    i = GetInstrumentCount(GetDirectoryId(Dir));
762                }
763            } catch (Exception e) {
764                EndTransaction();
765              throw e;              throw e;
766          }          }
767          DbInstrumentsMutex.Unlock();          EndTransaction();
768    
769          if (i == -1) throw Exception("Unknown Db directory: " + Dir);          if (i == -1) throw Exception("Unknown Db directory: " + Dir);
770          return i;          return i;
# Line 599  namespace LinuxSampler { Line 777  namespace LinuxSampler {
777          return ExecSqlIntList(sql.str());          return ExecSqlIntList(sql.str());
778      }      }
779    
780      StringListPtr InstrumentsDb::GetInstruments(String Dir) {      StringListPtr InstrumentsDb::GetInstruments(String Dir, bool Recursive) {
781          dmsg(2,("InstrumentsDb: GetInstruments(Dir=%s)\n", Dir.c_str()));          dmsg(2,("InstrumentsDb: GetInstruments(Dir=%s,Recursive=%d)\n", Dir.c_str(), Recursive));
782          DbInstrumentsMutex.Lock();          BeginTransaction();
783          try {          try {
784              int dirId = GetDirectoryId(Dir);              int dirId = GetDirectoryId(Dir);
785              if(dirId == -1) throw Exception("Unknown DB directory: " + Dir);              if(dirId == -1) throw Exception("Unknown DB directory: " + Dir);
786    
787              std::stringstream sql;              StringListPtr pInstrs;
             sql << "SELECT instr_name FROM instruments WHERE dir_id=" << dirId;  
788    
789              StringListPtr instrs = ExecSqlStringList(sql.str());              if(Recursive) {
790              DbInstrumentsMutex.Unlock();                  SearchQuery q;
791              return instrs;                  InstrumentFinder instrumentFinder(&q);
792                    DirectoryTreeWalk(Dir, &instrumentFinder);
793                    pInstrs = instrumentFinder.GetInstruments();
794                } else {
795                    std::stringstream sql;
796                    sql << "SELECT instr_name FROM instruments WHERE dir_id=" << dirId;
797    
798                    pInstrs = ExecSqlStringList(sql.str());
799                }
800                EndTransaction();
801                return pInstrs;
802          } catch (Exception e) {          } catch (Exception e) {
803              DbInstrumentsMutex.Unlock();              EndTransaction();
804              throw e;              throw e;
805          }          }
806      }      }
# Line 635  namespace LinuxSampler { Line 822  namespace LinuxSampler {
822          sql << DirId << " AND instr_name=?";          sql << DirId << " AND instr_name=?";
823          return ExecSqlInt(sql.str(), InstrName);          return ExecSqlInt(sql.str(), InstrName);
824      }      }
825    
826        String InstrumentsDb::GetInstrumentName(int InstrId) {
827            dmsg(2,("InstrumentsDb: GetInstrumentName(InstrId=%d)\n", InstrId));
828            std::stringstream sql;
829            sql << "SELECT instr_name FROM instruments WHERE instr_id=" << InstrId;
830            return ExecSqlString(sql.str());
831        }
832            
833      void InstrumentsDb::RemoveInstrument(String Instr) {      void InstrumentsDb::RemoveInstrument(String Instr) {
834          dmsg(2,("InstrumentsDb: RemoveInstrument(Instr=%s)\n", Instr.c_str()));          dmsg(2,("InstrumentsDb: RemoveInstrument(Instr=%s)\n", Instr.c_str()));
835          String ParentDir = GetDirectoryPath(Instr);          String ParentDir = GetDirectoryPath(Instr);
836          if(ParentDir.empty()) throw Exception("Unknown parent directory");          if(ParentDir.empty()) throw Exception("Unknown parent directory");
837                    
838          DbInstrumentsMutex.Lock();          BeginTransaction();
839          try {          try {
840              int instrId = GetInstrumentId(Instr);              int instrId = GetInstrumentId(Instr);
841              if(instrId == -1) {              if(instrId == -1) {
# Line 649  namespace LinuxSampler { Line 843  namespace LinuxSampler {
843              }              }
844              RemoveInstrument(instrId);              RemoveInstrument(instrId);
845          } catch (Exception e) {          } catch (Exception e) {
846              DbInstrumentsMutex.Unlock();              EndTransaction();
847              throw e;              throw e;
848          }          }
849          DbInstrumentsMutex.Unlock();          EndTransaction();
850          FireInstrumentCountChanged(ParentDir);          FireInstrumentCountChanged(ParentDir);
851      }      }
852    
# Line 677  namespace LinuxSampler { Line 871  namespace LinuxSampler {
871          dmsg(2,("InstrumentsDb: GetInstrumentInfo(Instr=%s)\n", Instr.c_str()));          dmsg(2,("InstrumentsDb: GetInstrumentInfo(Instr=%s)\n", Instr.c_str()));
872          DbInstrument i;          DbInstrument i;
873                    
874          DbInstrumentsMutex.Lock();          BeginTransaction();
875          try {          try {
876              int id = GetInstrumentId(Instr);              int id = GetInstrumentId(Instr);
877              if(id == -1) throw Exception("Unknown DB instrument: " + Instr);              if(id == -1) throw Exception("Unknown DB instrument: " + Instr);
878                i = GetInstrumentInfo(id);
879            } catch (Exception e) {
880                EndTransaction();
881                throw e;
882            }
883            EndTransaction();
884                    
885              sqlite3_stmt *pStmt = NULL;          return i;
886              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;  
887    
888              int res = sqlite3_prepare(GetDb(), sql.str().c_str(), -1, &pStmt, NULL);      DbInstrument InstrumentsDb::GetInstrumentInfo(int InstrId) {
889              if (res != SQLITE_OK) {          sqlite3_stmt *pStmt = NULL;
890                  throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));          std::stringstream sql;
891              }          sql << "SELECT instr_file,instr_nr,format_family,format_version,";
892            sql << "instr_size,created,modified,description,is_drum,product,";
893            sql << "artists,keywords FROM instruments WHERE instr_id=" << InstrId;
894    
895              res = sqlite3_step(pStmt);          int res = sqlite3_prepare(GetDb(), sql.str().c_str(), -1, &pStmt, NULL);
896              if(res == SQLITE_ROW) {          if (res != SQLITE_OK) {
897                  i.InstrFile = ToString(sqlite3_column_text(pStmt, 0));              throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
898                  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);  
                 }  
             }  
899    
900            DbInstrument i;
901            res = sqlite3_step(pStmt);
902            if(res == SQLITE_ROW) {
903                i.InstrFile = ToString(sqlite3_column_text(pStmt, 0));
904                i.InstrNr = sqlite3_column_int(pStmt, 1);
905                i.FormatFamily = ToString(sqlite3_column_text(pStmt, 2));
906                i.FormatVersion = ToString(sqlite3_column_text(pStmt, 3));
907                i.Size = sqlite3_column_int64(pStmt, 4);
908                i.Created = ToString(sqlite3_column_text(pStmt, 5));
909                i.Modified = ToString(sqlite3_column_text(pStmt, 6));
910                i.Description = ToString(sqlite3_column_text(pStmt, 7));
911                i.IsDrum = sqlite3_column_int(pStmt, 8);
912                i.Product = ToString(sqlite3_column_text(pStmt, 9));
913                i.Artists = ToString(sqlite3_column_text(pStmt, 10));
914                i.Keywords = ToString(sqlite3_column_text(pStmt, 11));
915            } else {
916              sqlite3_finalize(pStmt);              sqlite3_finalize(pStmt);
917          } catch (Exception e) {  
918              DbInstrumentsMutex.Unlock();              if (res != SQLITE_DONE) {
919              throw e;                  throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
920                } else {
921                    throw Exception("Unknown DB instrument");
922                }
923          }          }
924          DbInstrumentsMutex.Unlock();  
925                    sqlite3_finalize(pStmt);
926          return i;          return i;
927      }      }
928    
# Line 731  namespace LinuxSampler { Line 930  namespace LinuxSampler {
930          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()));
931          CheckFileName(Name);          CheckFileName(Name);
932    
933          DbInstrumentsMutex.Lock();          BeginTransaction();
934          try {          try {
935              int dirId = GetDirectoryId(GetDirectoryPath(Instr));              int dirId = GetDirectoryId(GetDirectoryPath(Instr));
936              if (dirId == -1) throw Exception("Unknown DB instrument: " + Instr);              if (dirId == -1) throw Exception("Unknown DB instrument: " + Instr);
# Line 743  namespace LinuxSampler { Line 942  namespace LinuxSampler {
942                  throw Exception("Cannot rename. Instrument with that name already exists: " + Name);                  throw Exception("Cannot rename. Instrument with that name already exists: " + Name);
943              }              }
944    
945                if (GetDirectoryId(dirId, Name) != -1) {
946                    throw Exception("Cannot rename. Directory with that name already exists: " + Name);
947                }
948    
949              std::stringstream sql;              std::stringstream sql;
950              sql << "UPDATE instruments SET instr_name=? WHERE instr_id=" << instrId;              sql << "UPDATE instruments SET instr_name=? WHERE instr_id=" << instrId;
951              ExecSql(sql.str(), Name);              ExecSql(sql.str(), Name);
952          } catch (Exception e) {          } catch (Exception e) {
953              DbInstrumentsMutex.Unlock();              EndTransaction();
954              throw e;              throw e;
955          }          }
956          DbInstrumentsMutex.Unlock();          EndTransaction();
957          FireInstrumentNameChanged(Instr, Name);          FireInstrumentNameChanged(Instr, Name);
958      }      }
959    
# Line 759  namespace LinuxSampler { Line 962  namespace LinuxSampler {
962          String ParentDir = GetDirectoryPath(Instr);          String ParentDir = GetDirectoryPath(Instr);
963          if(ParentDir.empty()) throw Exception("Unknown parent directory");          if(ParentDir.empty()) throw Exception("Unknown parent directory");
964    
965          DbInstrumentsMutex.Lock();          BeginTransaction();
966          try {          try {
967              int dirId = GetDirectoryId(GetDirectoryPath(Instr));              int dirId = GetDirectoryId(GetDirectoryPath(Instr));
968              if (dirId == -1) throw Exception("Unknown DB instrument: " + Instr);              if (dirId == -1) throw Exception("Unknown DB instrument: " + Instr);
# Line 771  namespace LinuxSampler { Line 974  namespace LinuxSampler {
974              int dstId = GetDirectoryId(Dst);              int dstId = GetDirectoryId(Dst);
975              if (dstId == -1) throw Exception("Unknown DB directory: " + Dst);              if (dstId == -1) throw Exception("Unknown DB directory: " + Dst);
976              if (dirId == dstId) {              if (dirId == dstId) {
977                  DbInstrumentsMutex.Unlock();                  EndTransaction();
978                  return;                  return;
979              }              }
980    
# Line 779  namespace LinuxSampler { Line 982  namespace LinuxSampler {
982                  throw Exception("Cannot move. Instrument with that name already exists: " + instrName);                  throw Exception("Cannot move. Instrument with that name already exists: " + instrName);
983              }              }
984    
985                if (GetDirectoryId(dstId, instrName) != -1) {
986                    throw Exception("Cannot move. Directory with that name already exists: " + instrName);
987                }
988    
989              std::stringstream sql;              std::stringstream sql;
990              sql << "UPDATE instruments SET dir_id=" << dstId;              sql << "UPDATE instruments SET dir_id=" << dstId;
991              sql << " WHERE instr_id=" << instrId;              sql << " WHERE instr_id=" << instrId;
992              ExecSql(sql.str());              ExecSql(sql.str());
993          } catch (Exception e) {          } catch (Exception e) {
994              DbInstrumentsMutex.Unlock();              EndTransaction();
995              throw e;              throw e;
996          }          }
997          DbInstrumentsMutex.Unlock();          EndTransaction();
998          FireInstrumentCountChanged(ParentDir);          FireInstrumentCountChanged(ParentDir);
999          FireInstrumentCountChanged(Dst);          FireInstrumentCountChanged(Dst);
1000      }      }
1001    
1002        void InstrumentsDb::CopyInstrument(String Instr, String Dst) {
1003            dmsg(2,("InstrumentsDb: CopyInstrument(Instr=%s,Dst=%s)\n", Instr.c_str(), Dst.c_str()));
1004            String ParentDir = GetDirectoryPath(Instr);
1005            if(ParentDir.empty()) throw Exception("Unknown parent directory");
1006    
1007            BeginTransaction();
1008            try {
1009                int dirId = GetDirectoryId(GetDirectoryPath(Instr));
1010                if (dirId == -1) throw Exception("Unknown DB instrument: " + Instr);
1011    
1012                String instrName = GetFileName(Instr);
1013                int instrId = GetInstrumentId(dirId, instrName);
1014                if (instrId == -1) throw Exception("Unknown DB instrument: " + Instr);
1015    
1016                int dstId = GetDirectoryId(Dst);
1017                if (dstId == -1) throw Exception("Unknown DB directory: " + Dst);
1018                if (dirId == dstId) {
1019                    EndTransaction();
1020                    return;
1021                }
1022    
1023                if (GetInstrumentId(dstId, instrName) != -1) {
1024                    throw Exception("Cannot copy. Instrument with that name already exists: " + instrName);
1025                }
1026    
1027                if (GetDirectoryId(dstId, instrName) != -1) {
1028                    throw Exception("Cannot copy. Directory with that name already exists: " + instrName);
1029                }
1030    
1031                CopyInstrument(instrId, instrName, dstId, Dst);
1032            } catch (Exception e) {
1033                EndTransaction();
1034                throw e;
1035            }
1036            EndTransaction();
1037            
1038        }
1039    
1040        void InstrumentsDb::CopyInstrument(int InstrId, String InstrName, int DstDirId, String DstDir) {
1041            DbInstrument i = GetInstrumentInfo(InstrId);
1042            sqlite3_stmt *pStmt = NULL;
1043            std::stringstream sql;
1044            sql << "INSERT INTO instruments (dir_id,instr_name,instr_file,instr_nr,format_family,";
1045            sql << "format_version,instr_size,description,is_drum,product,artists,keywords) ";
1046            sql << "VALUES (" << DstDirId << ",?,?," << i.InstrNr << ",?,?," << i.Size << ",?,";
1047            sql << i.IsDrum << ",?,?,?)";
1048    
1049            int res = sqlite3_prepare(GetDb(), sql.str().c_str(), -1, &pStmt, NULL);
1050            if (res != SQLITE_OK) {
1051                throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1052            }
1053    
1054            BindTextParam(pStmt, 1, InstrName);
1055            BindTextParam(pStmt, 2, i.InstrFile);
1056            BindTextParam(pStmt, 3, i.FormatFamily);
1057            BindTextParam(pStmt, 4, i.FormatVersion);
1058            BindTextParam(pStmt, 5, i.Description);
1059            BindTextParam(pStmt, 6, i.Product);
1060            BindTextParam(pStmt, 7, i.Artists);
1061            BindTextParam(pStmt, 8, i.Keywords);
1062    
1063            res = sqlite3_step(pStmt);
1064            if(res != SQLITE_DONE) {
1065                sqlite3_finalize(pStmt);
1066                throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1067            }
1068            
1069            sqlite3_finalize(pStmt);
1070            FireInstrumentCountChanged(DstDir);
1071        }
1072    
1073      void InstrumentsDb::SetInstrumentDescription(String Instr, String Desc) {      void InstrumentsDb::SetInstrumentDescription(String Instr, String Desc) {
1074          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()));
1075    
1076          DbInstrumentsMutex.Lock();          BeginTransaction();
1077          try {          try {
1078              int id = GetInstrumentId(Instr);              int id = GetInstrumentId(Instr);
1079              if(id == -1) throw Exception("Unknown DB instrument: " + Instr);              if(id == -1) throw Exception("Unknown DB instrument: " + Instr);
# Line 806  namespace LinuxSampler { Line 1084  namespace LinuxSampler {
1084    
1085              ExecSql(sql.str(), Desc);              ExecSql(sql.str(), Desc);
1086          } catch (Exception e) {          } catch (Exception e) {
1087              DbInstrumentsMutex.Unlock();              EndTransaction();
1088              throw e;              throw e;
1089          }          }
1090          DbInstrumentsMutex.Unlock();          EndTransaction();
1091          FireInstrumentInfoChanged(Instr);          FireInstrumentInfoChanged(Instr);
1092      }      }
1093    
1094      void InstrumentsDb::AddInstrumentsFromFile(String DbDir, String File, int Index) {      void InstrumentsDb::AddInstrumentsFromFile(String DbDir, String File, int Index, ScanProgress* pProgress) {
1095          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));
1096                    
1097          if(File.length() < 4) return;          if(File.length() < 4) return;
1098                    
1099          try {          try {
1100              if(!strcasecmp(".gig", File.substr(File.length() - 4).c_str())) {              if(!strcasecmp(".gig", File.substr(File.length() - 4).c_str())) {
1101                  AddGigInstruments(DbDir, File, Index);                  if (pProgress != NULL) {
1102                        pProgress->SetStatus(0);
1103                        pProgress->CurrentFile = File;
1104                    }
1105    
1106                    AddGigInstruments(DbDir, File, Index, pProgress);
1107    
1108                    if (pProgress != NULL) {
1109                        pProgress->SetScannedFileCount(pProgress->GetScannedFileCount() + 1);
1110                    }
1111              }              }
1112          } catch(Exception e) {          } catch(Exception e) {
1113              std::cout << e.Message() << std::endl;              std::cerr << e.Message() << std::endl;
1114          }          }
1115      }      }
1116    
1117      void InstrumentsDb::AddGigInstruments(String DbDir, String File, int Index) {      void InstrumentsDb::AddGigInstruments(String DbDir, String File, int Index, ScanProgress* pProgress) {
1118          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));
1119          int dirId = GetDirectoryId(DbDir);          int dirId = GetDirectoryId(DbDir);
1120          if (dirId == -1) throw Exception("Invalid DB directory: " + DbDir);          if (dirId == -1) throw Exception("Invalid DB directory: " + DbDir);
# Line 851  namespace LinuxSampler { Line 1138  namespace LinuxSampler {
1138          try {          try {
1139              riff = new RIFF::File(File);              riff = new RIFF::File(File);
1140              gig::File* gig = new gig::File(riff);              gig::File* gig = new gig::File(riff);
1141                
1142              std::stringstream sql;              std::stringstream sql;
1143              sql << "INSERT INTO instruments (dir_id,instr_name,instr_file,";              sql << "INSERT INTO instruments (dir_id,instr_name,instr_file,";
1144              sql << "instr_nr,format_family,format_version,instr_size,";              sql << "instr_nr,format_family,format_version,instr_size,";
# Line 872  namespace LinuxSampler { Line 1159  namespace LinuxSampler {
1159    
1160              if (Index == -1) {              if (Index == -1) {
1161                  int instrIndex = 0;                  int instrIndex = 0;
1162                    if (pProgress != NULL) gig->GetInstrument(0, &(pProgress->GigFileProgress)); // TODO: this workaround should be fixed
1163                  gig::Instrument* pInstrument = gig->GetFirstInstrument();                  gig::Instrument* pInstrument = gig->GetFirstInstrument();
1164                  while (pInstrument) {                  while (pInstrument) {
1165                      BindTextParam(pStmt, 7, gig->pInfo->Product);                      BindTextParam(pStmt, 7, gig->pInfo->Product);
# Line 883  namespace LinuxSampler { Line 1171  namespace LinuxSampler {
1171                      pInstrument = gig->GetNextInstrument();                      pInstrument = gig->GetNextInstrument();
1172                  }                  }
1173              } else {              } else {
1174                  gig::Instrument* pInstrument = gig->GetInstrument(Index);                  gig::Instrument* pInstrument;
1175                    if (pProgress == NULL) pInstrument = gig->GetInstrument(Index);
1176                    else pInstrument = gig->GetInstrument(Index, &(pProgress->GigFileProgress));
1177                  if (pInstrument != NULL) {                  if (pInstrument != NULL) {
1178                      BindTextParam(pStmt, 7, gig->pInfo->Product);                      BindTextParam(pStmt, 7, gig->pInfo->Product);
1179                      BindTextParam(pStmt, 8, gig->pInfo->Artists);                      BindTextParam(pStmt, 8, gig->pInfo->Artists);
# Line 892  namespace LinuxSampler { Line 1182  namespace LinuxSampler {
1182                  }                  }
1183              }              }
1184    
1185                sqlite3_finalize(pStmt);
1186              delete gig;              delete gig;
1187              delete riff;              delete riff;
1188          } catch (RIFF::Exception e) {          } catch (RIFF::Exception e) {
# Line 912  namespace LinuxSampler { Line 1203  namespace LinuxSampler {
1203          }          }
1204      }      }
1205    
1206      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) {
1207          String name = pInstrument->pInfo->Name;          String name = pInstrument->pInfo->Name;
1208          if (name == "") return;          if (name == "") return;
1209          name = GetUniqueInstrumentName(DirId, name);          name = GetUniqueInstrumentName(DirId, name);
# Line 949  namespace LinuxSampler { Line 1240  namespace LinuxSampler {
1240          FireInstrumentCountChanged(DbDir);          FireInstrumentCountChanged(DbDir);
1241      }      }
1242    
1243        void InstrumentsDb::DirectoryTreeWalk(String Path, DirectoryHandler* pHandler) {
1244            int DirId = GetDirectoryId(Path);
1245            if(DirId == -1) throw Exception("Unknown DB directory: " + Path);
1246            DirectoryTreeWalk(pHandler, Path, DirId, 0);
1247        }
1248    
1249        void InstrumentsDb::DirectoryTreeWalk(DirectoryHandler* pHandler, String Path, int DirId, int Level) {
1250            if(Level == 1000) throw Exception("Possible infinite loop detected");
1251            pHandler->ProcessDirectory(Path, DirId);
1252            
1253            String s;
1254            StringListPtr pDirs = GetDirectories(DirId);
1255            for(int i = 0; i < pDirs->size(); i++) {
1256                if (Path.length() == 1 && Path.at(0) == '/') s = "/" + pDirs->at(i);
1257                else s = Path + "/" + pDirs->at(i);
1258                DirectoryTreeWalk(pHandler, s, GetDirectoryId(DirId, pDirs->at(i)), Level + 1);
1259            }
1260        }
1261    
1262        StringListPtr InstrumentsDb::FindDirectories(String Dir, SearchQuery* pQuery, bool Recursive) {
1263            dmsg(2,("InstrumentsDb: FindDirectories(Dir=%s)\n", Dir.c_str()));
1264            DirectoryFinder directoryFinder(pQuery);
1265            
1266            BeginTransaction();
1267            try {
1268                int DirId = GetDirectoryId(Dir);
1269                if(DirId == -1) throw Exception("Unknown DB directory: " + Dir);
1270    
1271                if (Recursive) DirectoryTreeWalk(Dir, &directoryFinder);
1272                else directoryFinder.ProcessDirectory(Dir, DirId);
1273            } catch (Exception e) {
1274                EndTransaction();
1275                throw e;
1276            }
1277            EndTransaction();
1278    
1279            return directoryFinder.GetDirectories();
1280        }
1281    
1282        StringListPtr InstrumentsDb::FindInstruments(String Dir, SearchQuery* pQuery, bool Recursive) {
1283            dmsg(2,("InstrumentsDb: FindInstruments(Dir=%s)\n", Dir.c_str()));
1284            InstrumentFinder instrumentFinder(pQuery);
1285            
1286            BeginTransaction();
1287            try {
1288                int DirId = GetDirectoryId(Dir);
1289                if(DirId == -1) throw Exception("Unknown DB directory: " + Dir);
1290    
1291                if (Recursive) DirectoryTreeWalk(Dir, &instrumentFinder);
1292                else instrumentFinder.ProcessDirectory(Dir, DirId);
1293            } catch (Exception e) {
1294                EndTransaction();
1295                throw e;
1296            }
1297            EndTransaction();
1298    
1299            return instrumentFinder.GetInstruments();
1300        }
1301    
1302        void InstrumentsDb::BeginTransaction() {
1303            dmsg(2,("InstrumentsDb: BeginTransaction(InTransaction=%d)\n", InTransaction));
1304            DbInstrumentsMutex.Lock();
1305            if (InTransaction) return;
1306            
1307            if(db == NULL) return;
1308            sqlite3_stmt *pStmt = NULL;
1309            
1310            InTransaction = true;
1311            int res = sqlite3_prepare(db, "BEGIN TRANSACTION", -1, &pStmt, NULL);
1312            if (res != SQLITE_OK) {
1313                std::cerr << ToString(sqlite3_errmsg(db)) << std::endl;
1314                return;
1315            }
1316            
1317            res = sqlite3_step(pStmt);
1318            if(res != SQLITE_DONE) {
1319                sqlite3_finalize(pStmt);
1320                std::cerr << ToString(sqlite3_errmsg(db)) << std::endl;
1321                return;
1322            }
1323    
1324            sqlite3_finalize(pStmt);
1325        }
1326    
1327        void InstrumentsDb::EndTransaction() {
1328            dmsg(2,("InstrumentsDb: EndTransaction(InTransaction=%d)\n", InTransaction));
1329            if (!InTransaction) {
1330                DbInstrumentsMutex.Unlock();
1331                return;
1332            }
1333            InTransaction = false;
1334            
1335            if(db == NULL) {
1336                DbInstrumentsMutex.Unlock();
1337                return;
1338            }
1339            sqlite3_stmt *pStmt = NULL;
1340            
1341            int res = sqlite3_prepare(db, "END TRANSACTION", -1, &pStmt, NULL);
1342            if (res != SQLITE_OK) {
1343                std::cerr << ToString(sqlite3_errmsg(db)) << std::endl;
1344                DbInstrumentsMutex.Unlock();
1345                return;
1346            }
1347            
1348            res = sqlite3_step(pStmt);
1349            if(res != SQLITE_DONE) {
1350                sqlite3_finalize(pStmt);
1351                std::cerr << ToString(sqlite3_errmsg(db)) << std::endl;
1352                DbInstrumentsMutex.Unlock();
1353                return;
1354            }
1355    
1356            sqlite3_finalize(pStmt);
1357            DbInstrumentsMutex.Unlock();
1358        }
1359    
1360      void InstrumentsDb::ExecSql(String Sql) {      void InstrumentsDb::ExecSql(String Sql) {
1361          dmsg(2,("InstrumentsDb: ExecSql(Sql=%s)\n", Sql.c_str()));          dmsg(2,("InstrumentsDb: ExecSql(Sql=%s)\n", Sql.c_str()));
1362          sqlite3_stmt *pStmt = NULL;          sqlite3_stmt *pStmt = NULL;
# Line 1128  namespace LinuxSampler { Line 1536  namespace LinuxSampler {
1536          }          }
1537      }      }
1538    
1539        void InstrumentsDb::Regexp(sqlite3_context* pContext, int argc, sqlite3_value** ppValue) {
1540            if (argc != 2) return;
1541    
1542            String pattern = ToString(sqlite3_value_text(ppValue[0]));
1543            String str = ToString(sqlite3_value_text(ppValue[1]));
1544    
1545            if(!fnmatch(pattern.c_str(), str.c_str(), FNM_CASEFOLD)) {
1546                sqlite3_result_int(pContext, 1);
1547            }
1548        }
1549    
1550      String InstrumentsDb::GetDirectoryPath(String File) {      String InstrumentsDb::GetDirectoryPath(String File) {
1551          if (File.empty()) return String("");          if (File.empty()) return String("");
1552          if (File.at(0) != '/') String("");          if (File.at(0) != '/') String("");
# Line 1178  namespace LinuxSampler { Line 1597  namespace LinuxSampler {
1597    
1598      String InstrumentsDb::GetUniqueInstrumentName(int DirId, String Name) {      String InstrumentsDb::GetUniqueInstrumentName(int DirId, String Name) {
1599          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=?";  
1600    
1601          if (ExecSqlInt(sql.str(), Name) == 0) return Name;          if (GetInstrumentId(DirId, Name) == -1 && GetDirectoryId(DirId, Name) == -1) return Name;
1602          std::stringstream ss;          std::stringstream ss;
1603          for(int i = 2; i < 1001; i++) {          for(int i = 2; i < 1001; i++) {
1604              ss.str("");              ss.str("");
1605              ss << Name << '[' << i << ']';              ss << Name << '[' << i << ']';
1606              if (ExecSqlInt(sql.str(), ss.str()) == 0) return ss.str();              if (GetInstrumentId(DirId, ss.str()) == -1 && GetInstrumentId(DirId, ss.str()) == -1) {
1607                    return ss.str();
1608                }
1609          }          }
1610    
1611          throw Exception("Unable to find an unique name: " + Name);          throw Exception("Unable to find an unique name: " + Name);
1612      }      }
1613        
1614      void InstrumentsDb::FireDirectoryCountChanged(String Dir) {      void InstrumentsDb::FireDirectoryCountChanged(String Dir) {
1615          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1616              llInstrumentsDbListeners.GetListener(i)->DirectoryCountChanged(Dir);              llInstrumentsDbListeners.GetListener(i)->DirectoryCountChanged(Dir);
1617          }          }
1618      }      }
1619        
1620      void InstrumentsDb::FireDirectoryInfoChanged(String Dir) {      void InstrumentsDb::FireDirectoryInfoChanged(String Dir) {
1621          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1622              llInstrumentsDbListeners.GetListener(i)->DirectoryInfoChanged(Dir);              llInstrumentsDbListeners.GetListener(i)->DirectoryInfoChanged(Dir);
1623          }          }
1624      }      }
1625        
1626      void InstrumentsDb::FireDirectoryNameChanged(String Dir, String NewName) {      void InstrumentsDb::FireDirectoryNameChanged(String Dir, String NewName) {
1627          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1628              llInstrumentsDbListeners.GetListener(i)->DirectoryNameChanged(Dir, NewName);              llInstrumentsDbListeners.GetListener(i)->DirectoryNameChanged(Dir, NewName);
1629          }          }
1630      }      }
1631        
1632      void InstrumentsDb::FireInstrumentCountChanged(String Dir) {      void InstrumentsDb::FireInstrumentCountChanged(String Dir) {
1633          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1634              llInstrumentsDbListeners.GetListener(i)->InstrumentCountChanged(Dir);              llInstrumentsDbListeners.GetListener(i)->InstrumentCountChanged(Dir);
1635          }          }
1636      }      }
1637        
1638      void InstrumentsDb::FireInstrumentInfoChanged(String Instr) {      void InstrumentsDb::FireInstrumentInfoChanged(String Instr) {
1639          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1640              llInstrumentsDbListeners.GetListener(i)->InstrumentInfoChanged(Instr);              llInstrumentsDbListeners.GetListener(i)->InstrumentInfoChanged(Instr);
1641          }          }
1642      }      }
1643        
1644      void InstrumentsDb::FireInstrumentNameChanged(String Instr, String NewName) {      void InstrumentsDb::FireInstrumentNameChanged(String Instr, String NewName) {
1645          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1646              llInstrumentsDbListeners.GetListener(i)->InstrumentNameChanged(Instr, NewName);              llInstrumentsDbListeners.GetListener(i)->InstrumentNameChanged(Instr, NewName);
1647          }          }
1648      }      }
       
1649    
1650      String DirectoryScanner::DbDir;      void InstrumentsDb::FireJobStatusChanged(int JobId) {
1651      String DirectoryScanner::FsDir;          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1652      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("/");  
1653          }          }
         DirectoryScanner::Flat = Flat;  
           
         ftw(FsDir.c_str(), FtwCallback, 10);  
1654      }      }
1655    
     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;  
     };  
   
1656  } // namespace LinuxSampler  } // namespace LinuxSampler
1657    
1658  #endif // HAVE_SQLITE3  #endif // HAVE_SQLITE3

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

  ViewVC Help
Powered by ViewVC