/[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 1353 by iliev, Mon Sep 17 23:15: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, -2, '/');";
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            // TODO: remove this in the next version
141            try {
142                int i = ExecSqlInt("SELECT parent_dir_id FROM instr_dirs WHERE dir_id=0");
143                // The parent ID of the root directory should be -2 now.
144                if(i != -2) ExecSql("UPDATE instr_dirs SET parent_dir_id=-2 WHERE dir_id=0");
145            } catch(Exception e) { }
146            ////////////////////////////////////////
147                    
148          return db;          return db;
149      }      }
# Line 121  namespace LinuxSampler { Line 157  namespace LinuxSampler {
157                    
158          int count = ExecSqlInt(sql.str());          int count = ExecSqlInt(sql.str());
159    
         // While the root dir has ID 0 and parent ID 0, the directory  
         // count for the root dir will be incorrect, so we should fix it.  
         if (count != -1 && DirId == 0) count--;  
160          return count;          return count;
161      }      }
162    
163      int InstrumentsDb::GetDirectoryCount(String Dir) {      int InstrumentsDb::GetDirectoryCount(String Dir, bool Recursive) {
164          dmsg(2,("InstrumentsDb: GetDirectoryCount(Dir=%s)\n", Dir.c_str()));          dmsg(2,("InstrumentsDb: GetDirectoryCount(Dir=%s,Recursive=%d)\n", Dir.c_str(), Recursive));
165          int i;          int i;
166    
167          DbInstrumentsMutex.Lock();          BeginTransaction();
168          try { i = GetDirectoryCount(GetDirectoryId(Dir)); }          try {
169          catch (Exception e) {              if (Recursive) {
170              DbInstrumentsMutex.Unlock();                  DirectoryCounter directoryCounter;
171                    DirectoryTreeWalk(Dir, &directoryCounter);
172                    i = directoryCounter.GetDirectoryCount();
173                } else {
174                    i = GetDirectoryCount(GetDirectoryId(Dir));
175                }
176            } catch (Exception e) {
177                EndTransaction();
178              throw e;              throw e;
179          }          }
180          DbInstrumentsMutex.Unlock();          EndTransaction();
181          if (i == -1) throw Exception("Unkown DB directory: " + Dir);          if (i == -1) throw Exception("Unkown DB directory: " + toEscapedPath(Dir));
182                    
183          return i;          return i;
184      }      }
# Line 151  namespace LinuxSampler { Line 191  namespace LinuxSampler {
191          return ExecSqlIntList(sql.str());          return ExecSqlIntList(sql.str());
192      }      }
193    
194      StringListPtr InstrumentsDb::GetDirectories(String Dir) {      StringListPtr InstrumentsDb::GetDirectories(String Dir, bool Recursive) {
195          dmsg(2,("InstrumentsDb: GetDirectories(Dir=%s)\n", Dir.c_str()));          dmsg(2,("InstrumentsDb: GetDirectories(Dir=%s,Recursive=%d)\n", Dir.c_str(), Recursive));
196    
197          DbInstrumentsMutex.Lock();          BeginTransaction();
198          try {          try {
199              int dirId = GetDirectoryId(Dir);              int dirId = GetDirectoryId(Dir);
200              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";  
201    
202              DbInstrumentsMutex.Unlock();              StringListPtr pDirs;
203              return ExecSqlStringList(sql.str());              if (Recursive) {
204                    SearchQuery q;
205                    DirectoryFinder directoryFinder(&q);
206                    DirectoryTreeWalk(Dir, &directoryFinder);
207                    pDirs = directoryFinder.GetDirectories();
208                } else {
209                    pDirs = GetDirectories(dirId);
210                }
211                EndTransaction();
212                return pDirs;
213          } catch (Exception e) {          } catch (Exception e) {
214              DbInstrumentsMutex.Unlock();              EndTransaction();
215              throw e;              throw e;
216          }          }
217      }      }
218        
219        StringListPtr InstrumentsDb::GetDirectories(int DirId) {
220            std::stringstream sql;
221            sql << "SELECT dir_name FROM instr_dirs ";
222            sql << "WHERE parent_dir_id=" << DirId << " AND dir_id!=0";
223            StringListPtr dirs = ExecSqlStringList(sql.str());
224    
225            for (int i = 0; i < dirs->size(); i++) {
226                for (int j = 0; j < dirs->at(i).length(); j++) {
227                    if (dirs->at(i).at(j) == '/') dirs->at(i).at(j) = '\0';
228                }
229            }
230    
231            return dirs;
232        }
233    
234      int InstrumentsDb::GetDirectoryId(String Dir) {      int InstrumentsDb::GetDirectoryId(String Dir) {
235          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 257  namespace LinuxSampler {
257    
258      int InstrumentsDb::GetDirectoryId(int ParentDirId, String DirName) {      int InstrumentsDb::GetDirectoryId(int ParentDirId, String DirName) {
259          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()));
260            DirName = toDbName(DirName);
261          std::stringstream sql;          std::stringstream sql;
262          sql << "SELECT dir_id FROM instr_dirs WHERE parent_dir_id=";          sql << "SELECT dir_id FROM instr_dirs WHERE parent_dir_id=";
263          sql << ParentDirId << " AND dir_name=?";          sql << ParentDirId << " AND dir_name=?";
264          return ExecSqlInt(sql.str(), DirName);          return ExecSqlInt(sql.str(), DirName);
265      }      }
266    
267        String InstrumentsDb::GetDirectoryName(int DirId) {
268            String sql = "SELECT dir_name FROM instr_dirs WHERE dir_id=" + ToString(DirId);
269            String name = ExecSqlString(sql);
270            if (name.empty()) throw Exception("Directory ID not found");
271            return name;
272        }
273    
274        int InstrumentsDb::GetParentDirectoryId(int DirId) {
275            if (DirId == 0) throw Exception("The root directory is specified");
276            String sql = "SELECT parent_dir_id FROM instr_dirs WHERE dir_id=" + ToString(DirId);
277            int parentId = ExecSqlInt(sql);
278            if (parentId == -1) throw Exception("DB directory not found");
279            return parentId;
280        }
281    
282        String InstrumentsDb::GetDirectoryPath(int DirId) {
283            String path = "";
284            int count = 1000; // used to prevent infinite loops
285    
286            while(--count) {
287                if (DirId == 0) {
288                    path = "/" + path;
289                    break;
290                }
291                path = GetDirectoryName(DirId) + path;
292                DirId = GetParentDirectoryId(DirId);
293            }
294    
295            if (!count) throw Exception("Possible infinite loop detected");
296    
297            return path;
298        }
299    
300      void InstrumentsDb::AddDirectory(String Dir) {      void InstrumentsDb::AddDirectory(String Dir) {
301          dmsg(2,("InstrumentsDb: AddDirectory(Dir=%s)\n", Dir.c_str()));          dmsg(2,("InstrumentsDb: AddDirectory(Dir=%s)\n", Dir.c_str()));
302          CheckPathName(Dir);          CheckPathName(Dir);
303          String ParentDir = GetParentDirectory(Dir);          String ParentDir = GetParentDirectory(Dir);
304                    
305          DbInstrumentsMutex.Lock();          BeginTransaction();
306          try {          try {
307              if (Dir.length() > 1) {              if (Dir.length() > 1) {
308                  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 310  namespace LinuxSampler {
310    
311              String dirName = GetFileName(Dir);              String dirName = GetFileName(Dir);
312              if(ParentDir.empty() || dirName.empty()) {              if(ParentDir.empty() || dirName.empty()) {
313                  throw Exception("Failed to add DB directory: " + Dir);                  throw Exception("Failed to add DB directory: " + toEscapedPath(Dir));
314              }              }
315    
316              int id = GetDirectoryId(ParentDir);              int id = GetDirectoryId(ParentDir);
317              if (id == -1) throw Exception("DB directory doesn't exist: " + ParentDir);              if (id == -1) throw Exception("DB directory doesn't exist: " + toEscapedPath(ParentDir));
318              int id2 = GetDirectoryId(id, dirName);              int id2 = GetDirectoryId(id, dirName);
319              if (id2 != -1) throw Exception("DB directory already exist: " + Dir);              if (id2 != -1) throw Exception("DB directory already exist: " + toEscapedPath(Dir));
320                id2 = GetInstrumentId(id, dirName);
321                if (id2 != -1) throw Exception("Instrument with that name exist: " + toEscapedPath(Dir));
322    
323              std::stringstream sql;              std::stringstream sql;
324              sql << "INSERT INTO instr_dirs (parent_dir_id, dir_name) VALUES (";              sql << "INSERT INTO instr_dirs (parent_dir_id, dir_name) VALUES (";
325              sql << id << ", ?)";              sql << id << ", ?)";
326    
327              ExecSql(sql.str(), dirName);              ExecSql(sql.str(), toDbName(dirName));
328          } catch (Exception e) {          } catch (Exception e) {
329              DbInstrumentsMutex.Unlock();              EndTransaction();
330              throw e;              throw e;
331          }          }
332    
333          DbInstrumentsMutex.Unlock();          EndTransaction();
334    
335          FireDirectoryCountChanged(ParentDir);          FireDirectoryCountChanged(ParentDir);
336      }      }
# Line 244  namespace LinuxSampler { Line 340  namespace LinuxSampler {
340    
341          String ParentDir = GetParentDirectory(Dir);          String ParentDir = GetParentDirectory(Dir);
342    
343          DbInstrumentsMutex.Lock();          BeginTransaction();
344          try {          try {
345              int dirId = GetDirectoryId(Dir);              int dirId = GetDirectoryId(Dir);
346              if (dirId == -1) throw Exception("Unknown DB directory: " + Dir);              if (dirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
347              if (dirId == 0) throw Exception("Cannot delete the root directory: " + Dir);              if (dirId == 0) throw Exception("Cannot delete the root directory: " + Dir);
348              if(ParentDir.empty()) throw Exception("Unknown parent directory");              if(ParentDir.empty()) throw Exception("Unknown parent directory");
349              if (Force) RemoveDirectoryContent(dirId);              if (Force) RemoveDirectoryContent(dirId);
350              RemoveDirectory(dirId);              RemoveDirectory(dirId);
351          } catch (Exception e) {          } catch (Exception e) {
352              DbInstrumentsMutex.Unlock();              EndTransaction();
353              throw e;              throw e;
354          }          }
355    
356          DbInstrumentsMutex.Unlock();          EndTransaction();
357          FireDirectoryCountChanged(ParentDir);          FireDirectoryCountChanged(ParentDir);
358      }      }
359    
# Line 330  namespace LinuxSampler { Line 426  namespace LinuxSampler {
426          dmsg(2,("InstrumentsDb: GetDirectoryInfo(Dir=%s)\n", Dir.c_str()));          dmsg(2,("InstrumentsDb: GetDirectoryInfo(Dir=%s)\n", Dir.c_str()));
427          DbDirectory d;          DbDirectory d;
428    
429          DbInstrumentsMutex.Lock();          BeginTransaction();
430    
431          try {          try {
432              int id = GetDirectoryId(Dir);              int id = GetDirectoryId(Dir);
433              if(id == -1) throw Exception("Unknown DB directory: " + Dir);              if(id == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
434    
435              sqlite3_stmt *pStmt = NULL;              sqlite3_stmt *pStmt = NULL;
436              std::stringstream sql;              std::stringstream sql;
# Line 357  namespace LinuxSampler { Line 453  namespace LinuxSampler {
453                  if (res != SQLITE_DONE) {                  if (res != SQLITE_DONE) {
454                      throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));                      throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
455                  } else {                  } else {
456                      throw Exception("Unknown DB directory: " + Dir);                      throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
457                  }                  }
458              }              }
459                            
460              sqlite3_finalize(pStmt);              sqlite3_finalize(pStmt);
461          } catch (Exception e) {          } catch (Exception e) {
462              DbInstrumentsMutex.Unlock();              EndTransaction();
463              throw e;              throw e;
464          }          }
465    
466          DbInstrumentsMutex.Unlock();          EndTransaction();
467          return d;          return d;
468      }      }
469    
470      void InstrumentsDb::RenameDirectory(String Dir, String Name) {      void InstrumentsDb::RenameDirectory(String Dir, String Name) {
471          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()));
472          CheckFileName(Name);          CheckFileName(Name);
473            String dbName = toDbName(Name);
474    
475          DbInstrumentsMutex.Lock();          BeginTransaction();
476          try {          try {
477              int dirId = GetDirectoryId(Dir);              int dirId = GetDirectoryId(Dir);
478              if (dirId == -1) throw Exception("Unknown DB directory: " + Dir);              if (dirId == -1) throw Exception("Unknown DB directory: " + toEscapedText(Dir));
479    
480              std::stringstream sql;              std::stringstream sql;
481              sql << "SELECT parent_dir_id FROM instr_dirs WHERE dir_id=" <<  dirId;              sql << "SELECT parent_dir_id FROM instr_dirs WHERE dir_id=" <<  dirId;
482    
483              int parent = ExecSqlInt(sql.str());              int parent = ExecSqlInt(sql.str());
484              if (parent == -1) throw Exception("Unknown parent directory: " + Dir);              if (parent == -1) throw Exception("Unknown parent directory: " + toEscapedPath(Dir));
485              if (GetDirectoryId(parent, Name) != -1) {  
486                  throw Exception("Cannot rename. Directory with that name already exists: " + Name);              if (GetDirectoryId(parent, dbName) != -1) {
487                    String s = toEscapedPath(Name);
488                    throw Exception("Cannot rename. Directory with that name already exists: " + s);
489                }
490    
491                if (GetInstrumentId(parent, dbName) != -1) {
492                    throw Exception("Cannot rename. Instrument with that name exist: " + toEscapedPath(Dir));
493              }              }
494    
495              sql.str("");              sql.str("");
496              sql << "UPDATE instr_dirs SET dir_name=? WHERE dir_id=" << dirId;              sql << "UPDATE instr_dirs SET dir_name=? WHERE dir_id=" << dirId;
497              ExecSql(sql.str(), Name);              ExecSql(sql.str(), dbName);
498          } catch (Exception e) {          } catch (Exception e) {
499              DbInstrumentsMutex.Unlock();              EndTransaction();
500              throw e;              throw e;
501          }          }
502    
503          DbInstrumentsMutex.Unlock();          EndTransaction();
504          FireDirectoryNameChanged(Dir, Name);          FireDirectoryNameChanged(Dir, toAbstractName(Name));
505      }      }
506    
507      void InstrumentsDb::MoveDirectory(String Dir, String Dst) {      void InstrumentsDb::MoveDirectory(String Dir, String Dst) {
508          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()));
509    
510            if(Dir.compare("/") == 0) throw Exception("Cannot move the root directory");
511          String ParentDir = GetParentDirectory(Dir);          String ParentDir = GetParentDirectory(Dir);
512          if(ParentDir.empty()) throw Exception("Unknown parent directory");          if(ParentDir.empty()) throw Exception("Unknown parent directory");
513    
514          DbInstrumentsMutex.Lock();          BeginTransaction();
515          try {          try {
516              int dirId = GetDirectoryId(Dir);              int dirId = GetDirectoryId(Dir);
517              if (dirId == -1) throw Exception("Unknown DB directory: " + Dir);              if (dirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
518              int dstId = GetDirectoryId(Dst);              int dstId = GetDirectoryId(Dst);
519              if (dstId == -1) throw Exception("Unknown DB directory: " + Dst);              if (dstId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dst));
520              if (dirId == dstId) {              if (dirId == dstId) {
521                  throw Exception("Cannot move directory to itself");                  throw Exception("Cannot move directory to itself");
522              }              }
# Line 423  namespace LinuxSampler { Line 527  namespace LinuxSampler {
527                      throw Exception("Cannot move a directory to a subdirectory of itself.");                      throw Exception("Cannot move a directory to a subdirectory of itself.");
528                  }                  }
529              }              }
530                
531                Dir.erase(Dir.length() - 1);
532                String dirName = GetFileName(Dir);
533    
534                int id2 = GetDirectoryId(dstId, dirName);
535                if (id2 != -1) throw Exception("DB directory already exist: " + toEscapedPath(dirName));
536                id2 = GetInstrumentId(dstId, dirName);
537                if (id2 != -1) throw Exception("Instrument with that name exist: " + toEscapedPath(dirName));
538    
539              std::stringstream sql;              std::stringstream sql;
540              sql << "UPDATE instr_dirs SET parent_dir_id=" << dstId;              sql << "UPDATE instr_dirs SET parent_dir_id=" << dstId;
541              sql << " WHERE dir_id=" << dirId;              sql << " WHERE dir_id=" << dirId;
542              ExecSql(sql.str());              ExecSql(sql.str());
543          } catch (Exception e) {          } catch (Exception e) {
544              DbInstrumentsMutex.Unlock();              EndTransaction();
545              throw e;              throw e;
546          }          }
547    
548          DbInstrumentsMutex.Unlock();          EndTransaction();
549          FireDirectoryCountChanged(ParentDir);          FireDirectoryCountChanged(ParentDir);
550          FireDirectoryCountChanged(Dst);          FireDirectoryCountChanged(Dst);
551      }      }
552    
553        void InstrumentsDb::CopyDirectory(String Dir, String Dst) {
554            dmsg(2,("InstrumentsDb: CopyDirectory(Dir=%s,Dst=%s)\n", Dir.c_str(), Dst.c_str()));
555    
556            if(Dir.compare("/") == 0) throw Exception("Cannot copy the root directory");
557            String ParentDir = GetParentDirectory(Dir);
558            if(ParentDir.empty()) throw Exception("Unknown parent directory");
559    
560            BeginTransaction();
561            try {
562                int dirId = GetDirectoryId(Dir);
563                if (dirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
564                int dstId = GetDirectoryId(Dst);
565                if (dstId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dst));
566                if (dirId == dstId) {
567                    throw Exception("Cannot copy directory to itself");
568                }
569    
570                if (Dir.at(Dir.length() - 1) != '/') Dir.append("/");
571                if (Dst.length() > Dir.length()) {
572                    if (Dir.compare(Dst.substr(0, Dir.length())) == 0) {
573                        throw Exception("Cannot copy a directory to a subdirectory of itself.");
574                    }
575                }
576                
577                Dir.erase(Dir.length() - 1);
578                String dirName = GetFileName(Dir);
579    
580                int id2 = GetDirectoryId(dstId, dirName);
581                if (id2 != -1) throw Exception("DB directory already exist: " + toEscapedPath(dirName));
582                id2 = GetInstrumentId(dstId, dirName);
583                if (id2 != -1) throw Exception("Instrument with that name exist: " + toEscapedPath(dirName));
584    
585                DirectoryCopier directoryCopier(ParentDir, Dst);
586                DirectoryTreeWalk(Dir, &directoryCopier);
587            } catch (Exception e) {
588                EndTransaction();
589                throw e;
590            }
591    
592            EndTransaction();
593        }
594    
595      void InstrumentsDb::SetDirectoryDescription(String Dir, String Desc) {      void InstrumentsDb::SetDirectoryDescription(String Dir, String Desc) {
596          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()));
597                    
598          DbInstrumentsMutex.Lock();          BeginTransaction();
599          try {          try {
600              int id = GetDirectoryId(Dir);              int id = GetDirectoryId(Dir);
601              if(id == -1) throw Exception("Unknown DB directory: " + Dir);              if(id == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
602    
603              std::stringstream sql;              std::stringstream sql;
604              sql << "UPDATE instr_dirs SET description=?,modified=CURRENT_TIMESTAMP ";              sql << "UPDATE instr_dirs SET description=?,modified=CURRENT_TIMESTAMP ";
# Line 452  namespace LinuxSampler { Line 606  namespace LinuxSampler {
606                    
607              ExecSql(sql.str(), Desc);              ExecSql(sql.str(), Desc);
608          } catch (Exception e) {          } catch (Exception e) {
609              DbInstrumentsMutex.Unlock();              EndTransaction();
610              throw e;              throw e;
611          }          }
612          DbInstrumentsMutex.Unlock();          EndTransaction();
613                    
614          FireDirectoryInfoChanged(Dir);          FireDirectoryInfoChanged(Dir);
615      }      }
616    
617      void InstrumentsDb::AddInstruments(String DbDir, String FilePath, int Index) {      int InstrumentsDb::AddInstruments(ScanMode Mode, String DbDir, String FsDir, bool bBackground) {
618            dmsg(2,("InstrumentsDb: AddInstruments(Mode=%d,DbDir=%s,FsDir=%s,bBackground=%d)\n", Mode, DbDir.c_str(), FsDir.c_str(), bBackground));
619            if(!bBackground) {
620                switch (Mode) {
621                    case NON_RECURSIVE:
622                        AddInstrumentsNonrecursive(DbDir, FsDir);
623                        break;
624                    case RECURSIVE:
625                        AddInstrumentsRecursive(DbDir, FsDir);
626                        break;
627                    case FLAT:
628                        AddInstrumentsRecursive(DbDir, FsDir, true);
629                        break;
630                    default:
631                        throw Exception("Unknown scan mode");
632                }
633    
634                return -1;
635            }
636    
637            ScanJob job;
638            int jobId = Jobs.AddJob(job);
639            InstrumentsDbThread.Execute(new AddInstrumentsJob(jobId, Mode, DbDir, FsDir));
640    
641            return jobId;
642        }
643        
644        int InstrumentsDb::AddInstruments(String DbDir, String FilePath, int Index, bool bBackground) {
645            dmsg(2,("InstrumentsDb: AddInstruments(DbDir=%s,FilePath=%s,Index=%d,bBackground=%d)\n", DbDir.c_str(), FilePath.c_str(), Index, bBackground));
646            if(!bBackground) {
647                AddInstruments(DbDir, FilePath, Index);
648                return -1;
649            }
650    
651            ScanJob job;
652            int jobId = Jobs.AddJob(job);
653            InstrumentsDbThread.Execute(new AddInstrumentsFromFileJob(jobId, DbDir, FilePath, Index));
654    
655            return jobId;
656        }
657    
658        void InstrumentsDb::AddInstruments(String DbDir, String FilePath, int Index, ScanProgress* pProgress) {
659          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));
660          if (DbDir.empty() || FilePath.empty()) return;          if (DbDir.empty() || FilePath.empty()) return;
661                    
662          DbInstrumentsMutex.Lock();          DbInstrumentsMutex.Lock();
663          try {          try {
664              int dirId = GetDirectoryId(DbDir);              int dirId = GetDirectoryId(DbDir);
665              if (dirId == -1) throw Exception("Invalid DB directory: " + DbDir);              if (dirId == -1) throw Exception("Invalid DB directory: " + toEscapedText(DbDir));
666    
667              struct stat statBuf;              struct stat statBuf;
668              int res = stat(FilePath.c_str(), &statBuf);              int res = stat(FilePath.c_str(), &statBuf);
# Line 477  namespace LinuxSampler { Line 672  namespace LinuxSampler {
672                  throw Exception(ss.str());                  throw Exception(ss.str());
673              }              }
674    
675              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) {  
676                  std::stringstream ss;                  std::stringstream ss;
677                  ss << "`" << FilePath << "` is directory, not an instrument file";                  ss << "`" << FilePath << "` is not an instrument file";
678                  throw Exception(ss.str());                  throw Exception(ss.str());
679              }              }
680            
681              AddInstrumentsRecursive(DbDir, FilePath, false);              AddInstrumentsFromFile(DbDir, FilePath, Index, pProgress);
682          } catch (Exception e) {          } catch (Exception e) {
683              DbInstrumentsMutex.Unlock();              DbInstrumentsMutex.Unlock();
684              throw e;              throw e;
# Line 503  namespace LinuxSampler { Line 687  namespace LinuxSampler {
687          DbInstrumentsMutex.Unlock();          DbInstrumentsMutex.Unlock();
688      }      }
689    
690      void InstrumentsDb::AddInstrumentsNonrecursive(String DbDir, String FsDir) {      void InstrumentsDb::AddInstrumentsNonrecursive(String DbDir, String FsDir, ScanProgress* pProgress) {
691          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()));
692          if (DbDir.empty() || FsDir.empty()) return;          if (DbDir.empty() || FsDir.empty()) return;
693                    
694          DbInstrumentsMutex.Lock();          DbInstrumentsMutex.Lock();
695          try {          try {
696              int dirId = GetDirectoryId(DbDir);              int dirId = GetDirectoryId(DbDir);
697              if (dirId == -1) throw Exception("Invalid DB directory: " + DbDir);              if (dirId == -1) throw Exception("Invalid DB directory: " + toEscapedPath(DbDir));
698    
699              struct stat statBuf;              struct stat statBuf;
700              int res = stat(FsDir.c_str(), &statBuf);              int res = stat(FsDir.c_str(), &statBuf);
# Line 531  namespace LinuxSampler { Line 715  namespace LinuxSampler {
715                  std::stringstream ss;                  std::stringstream ss;
716                  ss << "The scanning of directory `" << FsDir << "` failed: ";                  ss << "The scanning of directory `" << FsDir << "` failed: ";
717                  ss << strerror(errno);                  ss << strerror(errno);
718                  std::cout << ss.str();                  std::cerr << ss.str();
719                  DbInstrumentsMutex.Unlock();                  DbInstrumentsMutex.Unlock();
720                  return;                  return;
721              }              }
# Line 543  namespace LinuxSampler { Line 727  namespace LinuxSampler {
727                      continue;                      continue;
728                  }                  }
729    
730                  AddInstrumentsFromFile(DbDir, FsDir + String(pEnt->d_name));                  AddInstrumentsFromFile(DbDir, FsDir + String(pEnt->d_name), -1, pProgress);
731                  pEnt = readdir(pDir);                  pEnt = readdir(pDir);
732              }              }
733    
# Line 551  namespace LinuxSampler { Line 735  namespace LinuxSampler {
735                  std::stringstream ss;                  std::stringstream ss;
736                  ss << "Failed to close directory `" << FsDir << "`: ";                  ss << "Failed to close directory `" << FsDir << "`: ";
737                  ss << strerror(errno);                  ss << strerror(errno);
738                  std::cout << ss.str();                  std::cerr << ss.str();
739              }              }
740          } catch (Exception e) {          } catch (Exception e) {
741              DbInstrumentsMutex.Unlock();              DbInstrumentsMutex.Unlock();
# Line 561  namespace LinuxSampler { Line 745  namespace LinuxSampler {
745          DbInstrumentsMutex.Unlock();          DbInstrumentsMutex.Unlock();
746      }      }
747    
748      void InstrumentsDb::AddInstrumentsRecursive(String DbDir, String FsDir, bool Flat) {      void InstrumentsDb::AddInstrumentsRecursive(String DbDir, String FsDir, bool Flat, ScanProgress* pProgress) {
749          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));
750          DirectoryScanner::Scan(DbDir, FsDir, Flat);          if (pProgress != NULL) {
751                pProgress->SetTotalFileCount(InstrumentFileCounter::Count(FsDir));
752            }
753    
754            DirectoryScanner::Scan(DbDir, FsDir, Flat, pProgress);
755      }      }
756    
757      int InstrumentsDb::GetInstrumentCount(int DirId) {      int InstrumentsDb::GetInstrumentCount(int DirId) {
# Line 576  namespace LinuxSampler { Line 764  namespace LinuxSampler {
764          return ExecSqlInt(sql.str());          return ExecSqlInt(sql.str());
765      }      }
766    
767      int InstrumentsDb::GetInstrumentCount(String Dir) {      int InstrumentsDb::GetInstrumentCount(String Dir, bool Recursive) {
768          dmsg(2,("InstrumentsDb: GetInstrumentCount(Dir=%s)\n", Dir.c_str()));          dmsg(2,("InstrumentsDb: GetInstrumentCount(Dir=%s,Recursive=%d)\n", Dir.c_str(), Recursive));
769          int i;          int i;
770                    
771          DbInstrumentsMutex.Lock();          BeginTransaction();
772          try { i = GetInstrumentCount(GetDirectoryId(Dir)); }          try {
773          catch (Exception e) {              if (Recursive) {
774              DbInstrumentsMutex.Unlock();                  InstrumentCounter instrumentCounter;
775                    DirectoryTreeWalk(Dir, &instrumentCounter);
776                    i = instrumentCounter.GetInstrumentCount();
777                } else {
778                    i = GetInstrumentCount(GetDirectoryId(Dir));
779                }
780            } catch (Exception e) {
781                EndTransaction();
782              throw e;              throw e;
783          }          }
784          DbInstrumentsMutex.Unlock();          EndTransaction();
785    
786          if (i == -1) throw Exception("Unknown Db directory: " + Dir);          if (i == -1) throw Exception("Unknown Db directory: " + toEscapedPath(Dir));
787          return i;          return i;
788      }      }
789    
# Line 599  namespace LinuxSampler { Line 794  namespace LinuxSampler {
794          return ExecSqlIntList(sql.str());          return ExecSqlIntList(sql.str());
795      }      }
796    
797      StringListPtr InstrumentsDb::GetInstruments(String Dir) {      StringListPtr InstrumentsDb::GetInstruments(String Dir, bool Recursive) {
798          dmsg(2,("InstrumentsDb: GetInstruments(Dir=%s)\n", Dir.c_str()));          dmsg(2,("InstrumentsDb: GetInstruments(Dir=%s,Recursive=%d)\n", Dir.c_str(), Recursive));
799          DbInstrumentsMutex.Lock();          BeginTransaction();
800          try {          try {
801              int dirId = GetDirectoryId(Dir);              int dirId = GetDirectoryId(Dir);
802              if(dirId == -1) throw Exception("Unknown DB directory: " + Dir);              if(dirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
803    
804              std::stringstream sql;              StringListPtr pInstrs;
             sql << "SELECT instr_name FROM instruments WHERE dir_id=" << dirId;  
805    
806              StringListPtr instrs = ExecSqlStringList(sql.str());              if(Recursive) {
807              DbInstrumentsMutex.Unlock();                  SearchQuery q;
808              return instrs;                  InstrumentFinder instrumentFinder(&q);
809                    DirectoryTreeWalk(Dir, &instrumentFinder);
810                    pInstrs = instrumentFinder.GetInstruments();
811                } else {
812                    std::stringstream sql;
813                    sql << "SELECT instr_name FROM instruments WHERE dir_id=" << dirId;
814    
815                    pInstrs = ExecSqlStringList(sql.str());
816                    // Converting to abstract names
817                    for (int i = 0; i < pInstrs->size(); i++) {
818                        for (int j = 0; j < pInstrs->at(i).length(); j++) {
819                            if (pInstrs->at(i).at(j) == '/') pInstrs->at(i).at(j) = '\0';
820                        }
821                    }
822                }
823                EndTransaction();
824                return pInstrs;
825          } catch (Exception e) {          } catch (Exception e) {
826              DbInstrumentsMutex.Unlock();              EndTransaction();
827              throw e;              throw e;
828          }          }
829      }      }
# Line 633  namespace LinuxSampler { Line 843  namespace LinuxSampler {
843          std::stringstream sql;          std::stringstream sql;
844          sql << "SELECT instr_id FROM instruments WHERE dir_id=";          sql << "SELECT instr_id FROM instruments WHERE dir_id=";
845          sql << DirId << " AND instr_name=?";          sql << DirId << " AND instr_name=?";
846          return ExecSqlInt(sql.str(), InstrName);          return ExecSqlInt(sql.str(), toDbName(InstrName));
847        }
848    
849        String InstrumentsDb::GetInstrumentName(int InstrId) {
850            dmsg(2,("InstrumentsDb: GetInstrumentName(InstrId=%d)\n", InstrId));
851            std::stringstream sql;
852            sql << "SELECT instr_name FROM instruments WHERE instr_id=" << InstrId;
853            return toAbstractName(ExecSqlString(sql.str()));
854      }      }
855            
856      void InstrumentsDb::RemoveInstrument(String Instr) {      void InstrumentsDb::RemoveInstrument(String Instr) {
# Line 641  namespace LinuxSampler { Line 858  namespace LinuxSampler {
858          String ParentDir = GetDirectoryPath(Instr);          String ParentDir = GetDirectoryPath(Instr);
859          if(ParentDir.empty()) throw Exception("Unknown parent directory");          if(ParentDir.empty()) throw Exception("Unknown parent directory");
860                    
861          DbInstrumentsMutex.Lock();          BeginTransaction();
862          try {          try {
863              int instrId = GetInstrumentId(Instr);              int instrId = GetInstrumentId(Instr);
864              if(instrId == -1) {              if(instrId == -1) {
865                  throw Exception("The specified instrument does not exist: " + Instr);                  throw Exception("The specified instrument does not exist: " + toEscapedPath(Instr));
866              }              }
867              RemoveInstrument(instrId);              RemoveInstrument(instrId);
868          } catch (Exception e) {          } catch (Exception e) {
869              DbInstrumentsMutex.Unlock();              EndTransaction();
870              throw e;              throw e;
871          }          }
872          DbInstrumentsMutex.Unlock();          EndTransaction();
873          FireInstrumentCountChanged(ParentDir);          FireInstrumentCountChanged(ParentDir);
874      }      }
875    
# Line 677  namespace LinuxSampler { Line 894  namespace LinuxSampler {
894          dmsg(2,("InstrumentsDb: GetInstrumentInfo(Instr=%s)\n", Instr.c_str()));          dmsg(2,("InstrumentsDb: GetInstrumentInfo(Instr=%s)\n", Instr.c_str()));
895          DbInstrument i;          DbInstrument i;
896                    
897          DbInstrumentsMutex.Lock();          BeginTransaction();
898          try {          try {
899              int id = GetInstrumentId(Instr);              int id = GetInstrumentId(Instr);
900              if(id == -1) throw Exception("Unknown DB instrument: " + Instr);              if(id == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
901                i = GetInstrumentInfo(id);
902            } catch (Exception e) {
903                EndTransaction();
904                throw e;
905            }
906            EndTransaction();
907                    
908              sqlite3_stmt *pStmt = NULL;          return i;
909              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;  
910    
911              int res = sqlite3_prepare(GetDb(), sql.str().c_str(), -1, &pStmt, NULL);      DbInstrument InstrumentsDb::GetInstrumentInfo(int InstrId) {
912              if (res != SQLITE_OK) {          sqlite3_stmt *pStmt = NULL;
913                  throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));          std::stringstream sql;
914              }          sql << "SELECT instr_file,instr_nr,format_family,format_version,";
915            sql << "instr_size,created,modified,description,is_drum,product,";
916            sql << "artists,keywords FROM instruments WHERE instr_id=" << InstrId;
917    
918              res = sqlite3_step(pStmt);          int res = sqlite3_prepare(GetDb(), sql.str().c_str(), -1, &pStmt, NULL);
919              if(res == SQLITE_ROW) {          if (res != SQLITE_OK) {
920                  i.InstrFile = ToString(sqlite3_column_text(pStmt, 0));              throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
921                  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);  
                 }  
             }  
922    
923            DbInstrument i;
924            res = sqlite3_step(pStmt);
925            if(res == SQLITE_ROW) {
926                i.InstrFile = ToString(sqlite3_column_text(pStmt, 0));
927                i.InstrNr = sqlite3_column_int(pStmt, 1);
928                i.FormatFamily = ToString(sqlite3_column_text(pStmt, 2));
929                i.FormatVersion = ToString(sqlite3_column_text(pStmt, 3));
930                i.Size = sqlite3_column_int64(pStmt, 4);
931                i.Created = ToString(sqlite3_column_text(pStmt, 5));
932                i.Modified = ToString(sqlite3_column_text(pStmt, 6));
933                i.Description = ToString(sqlite3_column_text(pStmt, 7));
934                i.IsDrum = sqlite3_column_int(pStmt, 8);
935                i.Product = ToString(sqlite3_column_text(pStmt, 9));
936                i.Artists = ToString(sqlite3_column_text(pStmt, 10));
937                i.Keywords = ToString(sqlite3_column_text(pStmt, 11));
938            } else {
939              sqlite3_finalize(pStmt);              sqlite3_finalize(pStmt);
940          } catch (Exception e) {  
941              DbInstrumentsMutex.Unlock();              if (res != SQLITE_DONE) {
942              throw e;                  throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
943                } else {
944                    throw Exception("Unknown DB instrument");
945                }
946          }          }
947          DbInstrumentsMutex.Unlock();  
948                    sqlite3_finalize(pStmt);
949          return i;          return i;
950      }      }
951    
# Line 731  namespace LinuxSampler { Line 953  namespace LinuxSampler {
953          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()));
954          CheckFileName(Name);          CheckFileName(Name);
955    
956          DbInstrumentsMutex.Lock();          BeginTransaction();
957          try {          try {
958              int dirId = GetDirectoryId(GetDirectoryPath(Instr));              int dirId = GetDirectoryId(GetDirectoryPath(Instr));
959              if (dirId == -1) throw Exception("Unknown DB instrument: " + Instr);              if (dirId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
960    
961              int instrId = GetInstrumentId(dirId, GetFileName(Instr));              int instrId = GetInstrumentId(dirId, GetFileName(Instr));
962              if (instrId == -1) throw Exception("Unknown DB instrument: " + Instr);              if (instrId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
963    
964              if (GetInstrumentId(dirId, Name) != -1) {              if (GetInstrumentId(dirId, Name) != -1) {
965                  throw Exception("Cannot rename. Instrument with that name already exists: " + Name);                  String s = toEscapedPath(Name);
966                    throw Exception("Cannot rename. Instrument with that name already exists: " + s);
967                }
968    
969                if (GetDirectoryId(dirId, Name) != -1) {
970                    String s = toEscapedPath(Name);
971                    throw Exception("Cannot rename. Directory with that name already exists: " + s);
972              }              }
973    
974              std::stringstream sql;              std::stringstream sql;
975              sql << "UPDATE instruments SET instr_name=? WHERE instr_id=" << instrId;              sql << "UPDATE instruments SET instr_name=? WHERE instr_id=" << instrId;
976              ExecSql(sql.str(), Name);              ExecSql(sql.str(), toDbName(Name));
977          } catch (Exception e) {          } catch (Exception e) {
978              DbInstrumentsMutex.Unlock();              EndTransaction();
979              throw e;              throw e;
980          }          }
981          DbInstrumentsMutex.Unlock();          EndTransaction();
982          FireInstrumentNameChanged(Instr, Name);          FireInstrumentNameChanged(Instr, toAbstractName(Name));
983      }      }
984    
985      void InstrumentsDb::MoveInstrument(String Instr, String Dst) {      void InstrumentsDb::MoveInstrument(String Instr, String Dst) {
# Line 759  namespace LinuxSampler { Line 987  namespace LinuxSampler {
987          String ParentDir = GetDirectoryPath(Instr);          String ParentDir = GetDirectoryPath(Instr);
988          if(ParentDir.empty()) throw Exception("Unknown parent directory");          if(ParentDir.empty()) throw Exception("Unknown parent directory");
989    
990          DbInstrumentsMutex.Lock();          BeginTransaction();
991          try {          try {
992              int dirId = GetDirectoryId(GetDirectoryPath(Instr));              int dirId = GetDirectoryId(ParentDir);
993              if (dirId == -1) throw Exception("Unknown DB instrument: " + Instr);              if (dirId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
994    
995              String instrName = GetFileName(Instr);              String instrName = GetFileName(Instr);
996              int instrId = GetInstrumentId(dirId, instrName);              int instrId = GetInstrumentId(dirId, instrName);
997              if (instrId == -1) throw Exception("Unknown DB instrument: " + Instr);              if (instrId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
998    
999              int dstId = GetDirectoryId(Dst);              int dstId = GetDirectoryId(Dst);
1000              if (dstId == -1) throw Exception("Unknown DB directory: " + Dst);              if (dstId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dst));
1001              if (dirId == dstId) {              if (dirId == dstId) {
1002                  DbInstrumentsMutex.Unlock();                  EndTransaction();
1003                  return;                  return;
1004              }              }
1005    
1006              if (GetInstrumentId(dstId, instrName) != -1) {              if (GetInstrumentId(dstId, instrName) != -1) {
1007                  throw Exception("Cannot move. Instrument with that name already exists: " + instrName);                  String s = toEscapedPath(instrName);
1008                    throw Exception("Cannot move. Instrument with that name already exists: " + s);
1009                }
1010    
1011                if (GetDirectoryId(dstId, instrName) != -1) {
1012                    String s = toEscapedPath(instrName);
1013                    throw Exception("Cannot move. Directory with that name already exists: " + s);
1014              }              }
1015    
1016              std::stringstream sql;              std::stringstream sql;
# Line 784  namespace LinuxSampler { Line 1018  namespace LinuxSampler {
1018              sql << " WHERE instr_id=" << instrId;              sql << " WHERE instr_id=" << instrId;
1019              ExecSql(sql.str());              ExecSql(sql.str());
1020          } catch (Exception e) {          } catch (Exception e) {
1021              DbInstrumentsMutex.Unlock();              EndTransaction();
1022              throw e;              throw e;
1023          }          }
1024          DbInstrumentsMutex.Unlock();          EndTransaction();
1025          FireInstrumentCountChanged(ParentDir);          FireInstrumentCountChanged(ParentDir);
1026          FireInstrumentCountChanged(Dst);          FireInstrumentCountChanged(Dst);
1027      }      }
1028    
1029        void InstrumentsDb::CopyInstrument(String Instr, String Dst) {
1030            dmsg(2,("InstrumentsDb: CopyInstrument(Instr=%s,Dst=%s)\n", Instr.c_str(), Dst.c_str()));
1031            String ParentDir = GetDirectoryPath(Instr);
1032            if(ParentDir.empty()) throw Exception("Unknown parent directory");
1033    
1034            BeginTransaction();
1035            try {
1036                int dirId = GetDirectoryId(GetDirectoryPath(Instr));
1037                if (dirId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1038    
1039                String instrName = GetFileName(Instr);
1040                int instrId = GetInstrumentId(dirId, instrName);
1041                if (instrId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1042    
1043                int dstId = GetDirectoryId(Dst);
1044                if (dstId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dst));
1045                if (dirId == dstId) {
1046                    EndTransaction();
1047                    return;
1048                }
1049    
1050                CopyInstrument(instrId, instrName, dstId, Dst);
1051            } catch (Exception e) {
1052                EndTransaction();
1053                throw e;
1054            }
1055            EndTransaction();
1056            
1057        }
1058    
1059        void InstrumentsDb::CopyInstrument(int InstrId, String InstrName, int DstDirId, String DstDir) {
1060            if (GetInstrumentId(DstDirId, InstrName) != -1) {
1061                String s = toEscapedPath(InstrName);
1062                throw Exception("Cannot copy. Instrument with that name already exists: " + s);
1063            }
1064    
1065            if (GetDirectoryId(DstDirId, InstrName) != -1) {
1066                String s = toEscapedPath(InstrName);
1067                throw Exception("Cannot copy. Directory with that name already exists: " + s);
1068            }
1069    
1070            DbInstrument i = GetInstrumentInfo(InstrId);
1071            sqlite3_stmt *pStmt = NULL;
1072            std::stringstream sql;
1073            sql << "INSERT INTO instruments (dir_id,instr_name,instr_file,instr_nr,format_family,";
1074            sql << "format_version,instr_size,description,is_drum,product,artists,keywords) ";
1075            sql << "VALUES (" << DstDirId << ",?,?," << i.InstrNr << ",?,?," << i.Size << ",?,";
1076            sql << i.IsDrum << ",?,?,?)";
1077    
1078            int res = sqlite3_prepare(GetDb(), sql.str().c_str(), -1, &pStmt, NULL);
1079            if (res != SQLITE_OK) {
1080                throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1081            }
1082    
1083            String s = toDbName(InstrName);
1084            BindTextParam(pStmt, 1, s);
1085            BindTextParam(pStmt, 2, i.InstrFile);
1086            BindTextParam(pStmt, 3, i.FormatFamily);
1087            BindTextParam(pStmt, 4, i.FormatVersion);
1088            BindTextParam(pStmt, 5, i.Description);
1089            BindTextParam(pStmt, 6, i.Product);
1090            BindTextParam(pStmt, 7, i.Artists);
1091            BindTextParam(pStmt, 8, i.Keywords);
1092    
1093            res = sqlite3_step(pStmt);
1094            if(res != SQLITE_DONE) {
1095                sqlite3_finalize(pStmt);
1096                throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1097            }
1098            
1099            sqlite3_finalize(pStmt);
1100            FireInstrumentCountChanged(DstDir);
1101        }
1102    
1103      void InstrumentsDb::SetInstrumentDescription(String Instr, String Desc) {      void InstrumentsDb::SetInstrumentDescription(String Instr, String Desc) {
1104          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()));
1105    
1106          DbInstrumentsMutex.Lock();          BeginTransaction();
1107          try {          try {
1108              int id = GetInstrumentId(Instr);              int id = GetInstrumentId(Instr);
1109              if(id == -1) throw Exception("Unknown DB instrument: " + Instr);              if(id == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1110    
1111              std::stringstream sql;              std::stringstream sql;
1112              sql << "UPDATE instruments SET description=?,modified=CURRENT_TIMESTAMP ";              sql << "UPDATE instruments SET description=?,modified=CURRENT_TIMESTAMP ";
# Line 806  namespace LinuxSampler { Line 1114  namespace LinuxSampler {
1114    
1115              ExecSql(sql.str(), Desc);              ExecSql(sql.str(), Desc);
1116          } catch (Exception e) {          } catch (Exception e) {
1117              DbInstrumentsMutex.Unlock();              EndTransaction();
1118              throw e;              throw e;
1119          }          }
1120          DbInstrumentsMutex.Unlock();          EndTransaction();
1121          FireInstrumentInfoChanged(Instr);          FireInstrumentInfoChanged(Instr);
1122      }      }
1123    
1124      void InstrumentsDb::AddInstrumentsFromFile(String DbDir, String File, int Index) {      void InstrumentsDb::AddInstrumentsFromFile(String DbDir, String File, int Index, ScanProgress* pProgress) {
1125          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));
1126                    
1127          if(File.length() < 4) return;          if(File.length() < 4) return;
1128                    
1129          try {          try {
1130              if(!strcasecmp(".gig", File.substr(File.length() - 4).c_str())) {              if(!strcasecmp(".gig", File.substr(File.length() - 4).c_str())) {
1131                  AddGigInstruments(DbDir, File, Index);                  if (pProgress != NULL) {
1132                        pProgress->SetStatus(0);
1133                        pProgress->CurrentFile = File;
1134                    }
1135    
1136                    AddGigInstruments(DbDir, File, Index, pProgress);
1137    
1138                    if (pProgress != NULL) {
1139                        pProgress->SetScannedFileCount(pProgress->GetScannedFileCount() + 1);
1140                    }
1141              }              }
1142          } catch(Exception e) {          } catch(Exception e) {
1143              std::cout << e.Message() << std::endl;              std::cerr << e.Message() << std::endl;
1144          }          }
1145      }      }
1146    
1147      void InstrumentsDb::AddGigInstruments(String DbDir, String File, int Index) {      void InstrumentsDb::AddGigInstruments(String DbDir, String File, int Index, ScanProgress* pProgress) {
1148          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));
1149          int dirId = GetDirectoryId(DbDir);          int dirId = GetDirectoryId(DbDir);
1150          if (dirId == -1) throw Exception("Invalid DB directory: " + DbDir);          if (dirId == -1) throw Exception("Invalid DB directory: " + toEscapedPath(DbDir));
1151    
1152          struct stat statBuf;          struct stat statBuf;
1153          int res = stat(File.c_str(), &statBuf);          int res = stat(File.c_str(), &statBuf);
# Line 851  namespace LinuxSampler { Line 1168  namespace LinuxSampler {
1168          try {          try {
1169              riff = new RIFF::File(File);              riff = new RIFF::File(File);
1170              gig::File* gig = new gig::File(riff);              gig::File* gig = new gig::File(riff);
1171                
1172              std::stringstream sql;              std::stringstream sql;
1173              sql << "INSERT INTO instruments (dir_id,instr_name,instr_file,";              sql << "INSERT INTO instruments (dir_id,instr_name,instr_file,";
1174              sql << "instr_nr,format_family,format_version,instr_size,";              sql << "instr_nr,format_family,format_version,instr_size,";
# Line 865  namespace LinuxSampler { Line 1182  namespace LinuxSampler {
1182                  throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));                  throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1183              }              }
1184    
1185              BindTextParam(pStmt, 2, File);              String s = toEscapedFsPath(File);
1186                BindTextParam(pStmt, 2, s);
1187              String ver = "";              String ver = "";
1188              if (gig->pVersion != NULL) ver = ToString(gig->pVersion->major);              if (gig->pVersion != NULL) ver = ToString(gig->pVersion->major);
1189              BindTextParam(pStmt, 4, ver);              BindTextParam(pStmt, 4, ver);
1190    
1191              if (Index == -1) {              if (Index == -1) {
1192                  int instrIndex = 0;                  int instrIndex = 0;
1193                    if (pProgress != NULL) gig->GetInstrument(0, &(pProgress->GigFileProgress)); // TODO: this workaround should be fixed
1194                  gig::Instrument* pInstrument = gig->GetFirstInstrument();                  gig::Instrument* pInstrument = gig->GetFirstInstrument();
1195                  while (pInstrument) {                  while (pInstrument) {
1196                      BindTextParam(pStmt, 7, gig->pInfo->Product);                      BindTextParam(pStmt, 7, gig->pInfo->Product);
# Line 883  namespace LinuxSampler { Line 1202  namespace LinuxSampler {
1202                      pInstrument = gig->GetNextInstrument();                      pInstrument = gig->GetNextInstrument();
1203                  }                  }
1204              } else {              } else {
1205                  gig::Instrument* pInstrument = gig->GetInstrument(Index);                  gig::Instrument* pInstrument;
1206                    if (pProgress == NULL) pInstrument = gig->GetInstrument(Index);
1207                    else pInstrument = gig->GetInstrument(Index, &(pProgress->GigFileProgress));
1208                  if (pInstrument != NULL) {                  if (pInstrument != NULL) {
1209                      BindTextParam(pStmt, 7, gig->pInfo->Product);                      BindTextParam(pStmt, 7, gig->pInfo->Product);
1210                      BindTextParam(pStmt, 8, gig->pInfo->Artists);                      BindTextParam(pStmt, 8, gig->pInfo->Artists);
# Line 892  namespace LinuxSampler { Line 1213  namespace LinuxSampler {
1213                  }                  }
1214              }              }
1215    
1216                sqlite3_finalize(pStmt);
1217              delete gig;              delete gig;
1218              delete riff;              delete riff;
1219          } catch (RIFF::Exception e) {          } catch (RIFF::Exception e) {
# Line 912  namespace LinuxSampler { Line 1234  namespace LinuxSampler {
1234          }          }
1235      }      }
1236    
1237      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) {
1238          String name = pInstrument->pInfo->Name;          String name = pInstrument->pInfo->Name;
1239          if (name == "") return;          if (name == "") return;
1240          name = GetUniqueInstrumentName(DirId, name);          name = GetUniqueInstrumentName(DirId, name);
# Line 920  namespace LinuxSampler { Line 1242  namespace LinuxSampler {
1242          std::stringstream sql2;          std::stringstream sql2;
1243          sql2 << "SELECT COUNT(*) FROM instruments WHERE instr_file=? AND ";          sql2 << "SELECT COUNT(*) FROM instruments WHERE instr_file=? AND ";
1244          sql2 << "instr_nr=" << Index;          sql2 << "instr_nr=" << Index;
1245          if (ExecSqlInt(sql2.str(), File) > 0) return;          String s = toEscapedFsPath(File);
1246            if (ExecSqlInt(sql2.str(), s) > 0) return;
1247    
1248          BindTextParam(pStmt, 1, name);          BindTextParam(pStmt, 1, name);
1249          BindIntParam(pStmt, 3, Index);          BindIntParam(pStmt, 3, Index);
# Line 949  namespace LinuxSampler { Line 1272  namespace LinuxSampler {
1272          FireInstrumentCountChanged(DbDir);          FireInstrumentCountChanged(DbDir);
1273      }      }
1274    
1275        void InstrumentsDb::DirectoryTreeWalk(String AbstractPath, DirectoryHandler* pHandler) {
1276            int DirId = GetDirectoryId(AbstractPath);
1277            if(DirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(AbstractPath));
1278            DirectoryTreeWalk(pHandler, AbstractPath, DirId, 0);
1279        }
1280    
1281        void InstrumentsDb::DirectoryTreeWalk(DirectoryHandler* pHandler, String AbstractPath, int DirId, int Level) {
1282            if(Level == 1000) throw Exception("Possible infinite loop detected");
1283            pHandler->ProcessDirectory(AbstractPath, DirId);
1284            
1285            String s;
1286            StringListPtr pDirs = GetDirectories(DirId);
1287            for(int i = 0; i < pDirs->size(); i++) {
1288                if (AbstractPath.length() == 1 && AbstractPath.at(0) == '/') {
1289                    s = "/" + pDirs->at(i);
1290                } else {
1291                    s = AbstractPath + "/" + pDirs->at(i);
1292                }
1293                DirectoryTreeWalk(pHandler, s, GetDirectoryId(DirId, pDirs->at(i)), Level + 1);
1294            }
1295        }
1296    
1297        StringListPtr InstrumentsDb::FindDirectories(String Dir, SearchQuery* pQuery, bool Recursive) {
1298            dmsg(2,("InstrumentsDb: FindDirectories(Dir=%s)\n", Dir.c_str()));
1299            DirectoryFinder directoryFinder(pQuery);
1300            
1301            BeginTransaction();
1302            try {
1303                int DirId = GetDirectoryId(Dir);
1304                if(DirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
1305    
1306                if (Recursive) DirectoryTreeWalk(Dir, &directoryFinder);
1307                else directoryFinder.ProcessDirectory(Dir, DirId);
1308            } catch (Exception e) {
1309                EndTransaction();
1310                throw e;
1311            }
1312            EndTransaction();
1313    
1314            return directoryFinder.GetDirectories();
1315        }
1316    
1317        StringListPtr InstrumentsDb::FindInstruments(String Dir, SearchQuery* pQuery, bool Recursive) {
1318            dmsg(2,("InstrumentsDb: FindInstruments(Dir=%s)\n", Dir.c_str()));
1319            InstrumentFinder instrumentFinder(pQuery);
1320            
1321            BeginTransaction();
1322            try {
1323                int DirId = GetDirectoryId(Dir);
1324                if(DirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
1325    
1326                if (Recursive) DirectoryTreeWalk(Dir, &instrumentFinder);
1327                else instrumentFinder.ProcessDirectory(Dir, DirId);
1328            } catch (Exception e) {
1329                EndTransaction();
1330                throw e;
1331            }
1332            EndTransaction();
1333    
1334            return instrumentFinder.GetInstruments();
1335        }
1336    
1337        void InstrumentsDb::BeginTransaction() {
1338            dmsg(2,("InstrumentsDb: BeginTransaction(InTransaction=%d)\n", InTransaction));
1339            DbInstrumentsMutex.Lock();
1340            if (InTransaction) return;
1341            
1342            if(db == NULL) return;
1343            sqlite3_stmt *pStmt = NULL;
1344            
1345            InTransaction = true;
1346            int res = sqlite3_prepare(db, "BEGIN TRANSACTION", -1, &pStmt, NULL);
1347            if (res != SQLITE_OK) {
1348                std::cerr << ToString(sqlite3_errmsg(db)) << std::endl;
1349                return;
1350            }
1351            
1352            res = sqlite3_step(pStmt);
1353            if(res != SQLITE_DONE) {
1354                sqlite3_finalize(pStmt);
1355                std::cerr << ToString(sqlite3_errmsg(db)) << std::endl;
1356                return;
1357            }
1358    
1359            sqlite3_finalize(pStmt);
1360        }
1361    
1362        void InstrumentsDb::EndTransaction() {
1363            dmsg(2,("InstrumentsDb: EndTransaction(InTransaction=%d)\n", InTransaction));
1364            if (!InTransaction) {
1365                DbInstrumentsMutex.Unlock();
1366                return;
1367            }
1368            InTransaction = false;
1369            
1370            if(db == NULL) {
1371                DbInstrumentsMutex.Unlock();
1372                return;
1373            }
1374            sqlite3_stmt *pStmt = NULL;
1375            
1376            int res = sqlite3_prepare(db, "END TRANSACTION", -1, &pStmt, NULL);
1377            if (res != SQLITE_OK) {
1378                std::cerr << ToString(sqlite3_errmsg(db)) << std::endl;
1379                DbInstrumentsMutex.Unlock();
1380                return;
1381            }
1382            
1383            res = sqlite3_step(pStmt);
1384            if(res != SQLITE_DONE) {
1385                sqlite3_finalize(pStmt);
1386                std::cerr << ToString(sqlite3_errmsg(db)) << std::endl;
1387                DbInstrumentsMutex.Unlock();
1388                return;
1389            }
1390    
1391            sqlite3_finalize(pStmt);
1392            DbInstrumentsMutex.Unlock();
1393        }
1394    
1395      void InstrumentsDb::ExecSql(String Sql) {      void InstrumentsDb::ExecSql(String Sql) {
1396          dmsg(2,("InstrumentsDb: ExecSql(Sql=%s)\n", Sql.c_str()));          dmsg(2,("InstrumentsDb: ExecSql(Sql=%s)\n", Sql.c_str()));
1397          sqlite3_stmt *pStmt = NULL;          sqlite3_stmt *pStmt = NULL;
# Line 1128  namespace LinuxSampler { Line 1571  namespace LinuxSampler {
1571          }          }
1572      }      }
1573    
1574        void InstrumentsDb::Regexp(sqlite3_context* pContext, int argc, sqlite3_value** ppValue) {
1575            if (argc != 2) return;
1576    
1577            String pattern = ToString(sqlite3_value_text(ppValue[0]));
1578            String str = ToString(sqlite3_value_text(ppValue[1]));
1579    
1580            if(!fnmatch(pattern.c_str(), str.c_str(), FNM_CASEFOLD)) {
1581                sqlite3_result_int(pContext, 1);
1582            }
1583        }
1584    
1585      String InstrumentsDb::GetDirectoryPath(String File) {      String InstrumentsDb::GetDirectoryPath(String File) {
1586          if (File.empty()) return String("");          if (File.empty()) return String("");
1587          if (File.at(0) != '/') String("");          if (File.at(0) != '/') String("");
# Line 1169  namespace LinuxSampler { Line 1623  namespace LinuxSampler {
1623          return Dir.substr(0, i);          return Dir.substr(0, i);
1624      }      }
1625    
1626        void InstrumentsDb::Format() {
1627            DbInstrumentsMutex.Lock();
1628            if (db != NULL) {
1629                sqlite3_close(db);
1630                db = NULL;
1631            }
1632    
1633            if (DbFile.empty()) DbFile = "/var/lib/linuxsampler/instruments.db";
1634            String bkp = DbFile + ".bkp";
1635            remove(bkp.c_str());
1636            if (rename(DbFile.c_str(), bkp.c_str()) && errno != ENOENT) {
1637                DbInstrumentsMutex.Unlock();
1638                throw Exception(String("Failed to backup database: ") + strerror(errno));
1639            }
1640            
1641            String f = DbFile;
1642            DbFile = "";
1643            try { CreateInstrumentsDb(f); }
1644            catch(Exception e) {
1645                DbInstrumentsMutex.Unlock();
1646                throw e;
1647            }
1648            DbInstrumentsMutex.Unlock();
1649            
1650            FireDirectoryCountChanged("/");
1651            FireInstrumentCountChanged("/");
1652        }
1653    
1654      void InstrumentsDb::CheckFileName(String File) {      void InstrumentsDb::CheckFileName(String File) {
1655          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);  
         }  
1656      }      }
1657    
1658      String InstrumentsDb::GetUniqueInstrumentName(int DirId, String Name) {      String InstrumentsDb::GetUniqueInstrumentName(int DirId, String Name) {
1659          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=?";  
1660    
1661          if (ExecSqlInt(sql.str(), Name) == 0) return Name;          if (GetInstrumentId(DirId, Name) == -1 && GetDirectoryId(DirId, Name) == -1) return Name;
1662          std::stringstream ss;          std::stringstream ss;
1663          for(int i = 2; i < 1001; i++) {          for(int i = 2; i < 1001; i++) {
1664              ss.str("");              ss.str("");
1665              ss << Name << '[' << i << ']';              ss << Name << '[' << i << ']';
1666              if (ExecSqlInt(sql.str(), ss.str()) == 0) return ss.str();              if (GetInstrumentId(DirId, ss.str()) == -1 && GetInstrumentId(DirId, ss.str()) == -1) {
1667                    return ss.str();
1668                }
1669          }          }
1670    
1671          throw Exception("Unable to find an unique name: " + Name);          throw Exception("Unable to find an unique name: " + Name);
1672      }      }
1673    
1674        String InstrumentsDb::toDbName(String AbstractName) {
1675            for (int i = 0; i < AbstractName.length(); i++) {
1676                if (AbstractName.at(i) == '\0') AbstractName.at(i) = '/';
1677            }
1678            return AbstractName;
1679        }
1680    
1681        String InstrumentsDb::toEscapedPath(String AbstractName) {
1682            for (int i = 0; i < AbstractName.length(); i++) {
1683                if (AbstractName.at(i) == '\0')      AbstractName.replace(i++, 1, "\\x2f");
1684                else if (AbstractName.at(i) == '\\') AbstractName.replace(i++, 1, "\\\\");
1685                else if (AbstractName.at(i) == '\'') AbstractName.replace(i++, 1, "\\'");
1686                else if (AbstractName.at(i) == '"')  AbstractName.replace(i++, 1, "\\\"");
1687                else if (AbstractName.at(i) == '\r') AbstractName.replace(i++, 1, "\\r");
1688                else if (AbstractName.at(i) == '\n') AbstractName.replace(i++, 1, "\\n");
1689            }
1690            return AbstractName;
1691        }
1692        
1693        String InstrumentsDb::toEscapedText(String text) {
1694            for (int i = 0; i < text.length(); i++) {
1695                if (text.at(i) == '\\')      text.replace(i++, 1, "\\\\");
1696                else if (text.at(i) == '\'') text.replace(i++, 1, "\\'");
1697                else if (text.at(i) == '"')  text.replace(i++, 1, "\\\"");
1698                else if (text.at(i) == '\r') text.replace(i++, 1, "\\r");
1699                else if (text.at(i) == '\n') text.replace(i++, 1, "\\n");
1700            }
1701            return text;
1702        }
1703            
1704        String InstrumentsDb::toEscapedFsPath(String FsPath) {
1705            return toEscapedText(FsPath);
1706        }
1707        
1708        String InstrumentsDb::toAbstractName(String DbName) {
1709            for (int i = 0; i < DbName.length(); i++) {
1710                if (DbName.at(i) == '/') DbName.at(i) = '\0';
1711            }
1712            return DbName;
1713        }
1714    
1715      void InstrumentsDb::FireDirectoryCountChanged(String Dir) {      void InstrumentsDb::FireDirectoryCountChanged(String Dir) {
1716          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1717              llInstrumentsDbListeners.GetListener(i)->DirectoryCountChanged(Dir);              llInstrumentsDbListeners.GetListener(i)->DirectoryCountChanged(Dir);
1718          }          }
1719      }      }
1720        
1721      void InstrumentsDb::FireDirectoryInfoChanged(String Dir) {      void InstrumentsDb::FireDirectoryInfoChanged(String Dir) {
1722          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1723              llInstrumentsDbListeners.GetListener(i)->DirectoryInfoChanged(Dir);              llInstrumentsDbListeners.GetListener(i)->DirectoryInfoChanged(Dir);
1724          }          }
1725      }      }
1726        
1727      void InstrumentsDb::FireDirectoryNameChanged(String Dir, String NewName) {      void InstrumentsDb::FireDirectoryNameChanged(String Dir, String NewName) {
1728          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1729              llInstrumentsDbListeners.GetListener(i)->DirectoryNameChanged(Dir, NewName);              llInstrumentsDbListeners.GetListener(i)->DirectoryNameChanged(Dir, NewName);
1730          }          }
1731      }      }
1732        
1733      void InstrumentsDb::FireInstrumentCountChanged(String Dir) {      void InstrumentsDb::FireInstrumentCountChanged(String Dir) {
1734          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1735              llInstrumentsDbListeners.GetListener(i)->InstrumentCountChanged(Dir);              llInstrumentsDbListeners.GetListener(i)->InstrumentCountChanged(Dir);
1736          }          }
1737      }      }
1738        
1739      void InstrumentsDb::FireInstrumentInfoChanged(String Instr) {      void InstrumentsDb::FireInstrumentInfoChanged(String Instr) {
1740          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1741              llInstrumentsDbListeners.GetListener(i)->InstrumentInfoChanged(Instr);              llInstrumentsDbListeners.GetListener(i)->InstrumentInfoChanged(Instr);
1742          }          }
1743      }      }
1744        
1745      void InstrumentsDb::FireInstrumentNameChanged(String Instr, String NewName) {      void InstrumentsDb::FireInstrumentNameChanged(String Instr, String NewName) {
1746          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1747              llInstrumentsDbListeners.GetListener(i)->InstrumentNameChanged(Instr, NewName);              llInstrumentsDbListeners.GetListener(i)->InstrumentNameChanged(Instr, NewName);
1748          }          }
1749      }      }
       
   
     String DirectoryScanner::DbDir;  
     String DirectoryScanner::FsDir;  
     bool DirectoryScanner::Flat;  
   
     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());  
         }  
1750    
1751          if (!S_ISDIR(statBuf.st_mode)) {      void InstrumentsDb::FireJobStatusChanged(int JobId) {
1752              throw Exception("Directory expected");          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1753          }              llInstrumentsDbListeners.GetListener(i)->JobStatusChanged(JobId);
           
         DirectoryScanner::DbDir = DbDir;  
         DirectoryScanner::FsDir = FsDir;  
         if (DbDir.at(DbDir.length() - 1) != '/') {  
             DirectoryScanner::DbDir.append("/");  
         }  
         if (FsDir.at(FsDir.length() - 1) != '/') {  
             DirectoryScanner::FsDir.append("/");  
1754          }          }
         DirectoryScanner::Flat = Flat;  
           
         ftw(FsDir.c_str(), FtwCallback, 10);  
1755      }      }
1756    
     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;  
     };  
   
1757  } // namespace LinuxSampler  } // namespace LinuxSampler
1758    
1759  #endif // HAVE_SQLITE3  #endif // HAVE_SQLITE3

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

  ViewVC Help
Powered by ViewVC