/[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 1603 by iliev, Mon Dec 31 10:17:51 2007 UTC
# Line 20  Line 20 
20    
21  #include "InstrumentsDb.h"  #include "InstrumentsDb.h"
22    
23  #if HAVE_SQLITE3  #include "../common/global_private.h"
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 101  namespace LinuxSampler { Line 127  namespace LinuxSampler {
127      sqlite3* InstrumentsDb::GetDb() {      sqlite3* InstrumentsDb::GetDb() {
128          if ( db != NULL) return db;          if ( db != NULL) return db;
129    
130          if (DbFile.empty()) DbFile = "/var/lib/linuxsampler/instruments.db";          if (DbFile.empty()) DbFile = CONFIG_DEFAULT_INSTRUMENTS_DB_LOCATION;
131          int rc = sqlite3_open(DbFile.c_str(), &db);          int rc = sqlite3_open(DbFile.c_str(), &db);
132          if (rc) {          if (rc) {
133              sqlite3_close(db);              sqlite3_close(db);
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                            gig->SetAutoLoad(false); // avoid time consuming samples scanning
1172    
1173              std::stringstream sql;              std::stringstream sql;
1174              sql << "INSERT INTO instruments (dir_id,instr_name,instr_file,";              sql << "INSERT INTO instruments (dir_id,instr_name,instr_file,";
1175              sql << "instr_nr,format_family,format_version,instr_size,";              sql << "instr_nr,format_family,format_version,instr_size,";
# Line 865  namespace LinuxSampler { Line 1183  namespace LinuxSampler {
1183                  throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));                  throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1184              }              }
1185    
1186              BindTextParam(pStmt, 2, File);              String s = toEscapedFsPath(File);
1187                BindTextParam(pStmt, 2, s);
1188              String ver = "";              String ver = "";
1189              if (gig->pVersion != NULL) ver = ToString(gig->pVersion->major);              if (gig->pVersion != NULL) ver = ToString(gig->pVersion->major);
1190              BindTextParam(pStmt, 4, ver);              BindTextParam(pStmt, 4, ver);
1191    
1192              if (Index == -1) {              if (Index == -1) {
1193                  int instrIndex = 0;                  int instrIndex = 0;
1194                    if (pProgress != NULL) gig->GetInstrument(0, &(pProgress->GigFileProgress)); // TODO: this workaround should be fixed
1195                  gig::Instrument* pInstrument = gig->GetFirstInstrument();                  gig::Instrument* pInstrument = gig->GetFirstInstrument();
1196                  while (pInstrument) {                  while (pInstrument) {
1197                      BindTextParam(pStmt, 7, gig->pInfo->Product);                      BindTextParam(pStmt, 7, gig->pInfo->Product);
# Line 883  namespace LinuxSampler { Line 1203  namespace LinuxSampler {
1203                      pInstrument = gig->GetNextInstrument();                      pInstrument = gig->GetNextInstrument();
1204                  }                  }
1205              } else {              } else {
1206                  gig::Instrument* pInstrument = gig->GetInstrument(Index);                  gig::Instrument* pInstrument;
1207                    if (pProgress == NULL) pInstrument = gig->GetInstrument(Index);
1208                    else pInstrument = gig->GetInstrument(Index, &(pProgress->GigFileProgress));
1209                  if (pInstrument != NULL) {                  if (pInstrument != NULL) {
1210                      BindTextParam(pStmt, 7, gig->pInfo->Product);                      BindTextParam(pStmt, 7, gig->pInfo->Product);
1211                      BindTextParam(pStmt, 8, gig->pInfo->Artists);                      BindTextParam(pStmt, 8, gig->pInfo->Artists);
# Line 892  namespace LinuxSampler { Line 1214  namespace LinuxSampler {
1214                  }                  }
1215              }              }
1216    
1217                sqlite3_finalize(pStmt);
1218              delete gig;              delete gig;
1219              delete riff;              delete riff;
1220          } catch (RIFF::Exception e) {          } catch (RIFF::Exception e) {
# Line 912  namespace LinuxSampler { Line 1235  namespace LinuxSampler {
1235          }          }
1236      }      }
1237    
1238      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) {
1239          String name = pInstrument->pInfo->Name;          String name = pInstrument->pInfo->Name;
1240          if (name == "") return;          if (name == "") return;
1241          name = GetUniqueInstrumentName(DirId, name);          name = GetUniqueInstrumentName(DirId, name);
# Line 920  namespace LinuxSampler { Line 1243  namespace LinuxSampler {
1243          std::stringstream sql2;          std::stringstream sql2;
1244          sql2 << "SELECT COUNT(*) FROM instruments WHERE instr_file=? AND ";          sql2 << "SELECT COUNT(*) FROM instruments WHERE instr_file=? AND ";
1245          sql2 << "instr_nr=" << Index;          sql2 << "instr_nr=" << Index;
1246          if (ExecSqlInt(sql2.str(), File) > 0) return;          String s = toEscapedFsPath(File);
1247            if (ExecSqlInt(sql2.str(), s) > 0) return;
1248    
1249          BindTextParam(pStmt, 1, name);          BindTextParam(pStmt, 1, name);
1250          BindIntParam(pStmt, 3, Index);          BindIntParam(pStmt, 3, Index);
# Line 949  namespace LinuxSampler { Line 1273  namespace LinuxSampler {
1273          FireInstrumentCountChanged(DbDir);          FireInstrumentCountChanged(DbDir);
1274      }      }
1275    
1276        void InstrumentsDb::DirectoryTreeWalk(String AbstractPath, DirectoryHandler* pHandler) {
1277            int DirId = GetDirectoryId(AbstractPath);
1278            if(DirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(AbstractPath));
1279            DirectoryTreeWalk(pHandler, AbstractPath, DirId, 0);
1280        }
1281    
1282        void InstrumentsDb::DirectoryTreeWalk(DirectoryHandler* pHandler, String AbstractPath, int DirId, int Level) {
1283            if(Level == 1000) throw Exception("Possible infinite loop detected");
1284            pHandler->ProcessDirectory(AbstractPath, DirId);
1285            
1286            String s;
1287            StringListPtr pDirs = GetDirectories(DirId);
1288            for(int i = 0; i < pDirs->size(); i++) {
1289                if (AbstractPath.length() == 1 && AbstractPath.at(0) == '/') {
1290                    s = "/" + pDirs->at(i);
1291                } else {
1292                    s = AbstractPath + "/" + pDirs->at(i);
1293                }
1294                DirectoryTreeWalk(pHandler, s, GetDirectoryId(DirId, pDirs->at(i)), Level + 1);
1295            }
1296        }
1297    
1298        StringListPtr InstrumentsDb::FindDirectories(String Dir, SearchQuery* pQuery, bool Recursive) {
1299            dmsg(2,("InstrumentsDb: FindDirectories(Dir=%s)\n", Dir.c_str()));
1300            DirectoryFinder directoryFinder(pQuery);
1301            
1302            BeginTransaction();
1303            try {
1304                int DirId = GetDirectoryId(Dir);
1305                if(DirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
1306    
1307                if (Recursive) DirectoryTreeWalk(Dir, &directoryFinder);
1308                else directoryFinder.ProcessDirectory(Dir, DirId);
1309            } catch (Exception e) {
1310                EndTransaction();
1311                throw e;
1312            }
1313            EndTransaction();
1314    
1315            return directoryFinder.GetDirectories();
1316        }
1317    
1318        StringListPtr InstrumentsDb::FindInstruments(String Dir, SearchQuery* pQuery, bool Recursive) {
1319            dmsg(2,("InstrumentsDb: FindInstruments(Dir=%s)\n", Dir.c_str()));
1320            InstrumentFinder instrumentFinder(pQuery);
1321            
1322            BeginTransaction();
1323            try {
1324                int DirId = GetDirectoryId(Dir);
1325                if(DirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
1326    
1327                if (Recursive) DirectoryTreeWalk(Dir, &instrumentFinder);
1328                else instrumentFinder.ProcessDirectory(Dir, DirId);
1329            } catch (Exception e) {
1330                EndTransaction();
1331                throw e;
1332            }
1333            EndTransaction();
1334    
1335            return instrumentFinder.GetInstruments();
1336        }
1337    
1338        void InstrumentsDb::BeginTransaction() {
1339            dmsg(2,("InstrumentsDb: BeginTransaction(InTransaction=%d)\n", InTransaction));
1340            DbInstrumentsMutex.Lock();
1341            if (InTransaction) return;
1342            
1343            if(db == NULL) return;
1344            sqlite3_stmt *pStmt = NULL;
1345            
1346            InTransaction = true;
1347            int res = sqlite3_prepare(db, "BEGIN TRANSACTION", -1, &pStmt, NULL);
1348            if (res != SQLITE_OK) {
1349                std::cerr << ToString(sqlite3_errmsg(db)) << std::endl;
1350                return;
1351            }
1352            
1353            res = sqlite3_step(pStmt);
1354            if(res != SQLITE_DONE) {
1355                sqlite3_finalize(pStmt);
1356                std::cerr << ToString(sqlite3_errmsg(db)) << std::endl;
1357                return;
1358            }
1359    
1360            sqlite3_finalize(pStmt);
1361        }
1362    
1363        void InstrumentsDb::EndTransaction() {
1364            dmsg(2,("InstrumentsDb: EndTransaction(InTransaction=%d)\n", InTransaction));
1365            if (!InTransaction) {
1366                DbInstrumentsMutex.Unlock();
1367                return;
1368            }
1369            InTransaction = false;
1370            
1371            if(db == NULL) {
1372                DbInstrumentsMutex.Unlock();
1373                return;
1374            }
1375            sqlite3_stmt *pStmt = NULL;
1376            
1377            int res = sqlite3_prepare(db, "END TRANSACTION", -1, &pStmt, NULL);
1378            if (res != SQLITE_OK) {
1379                std::cerr << ToString(sqlite3_errmsg(db)) << std::endl;
1380                DbInstrumentsMutex.Unlock();
1381                return;
1382            }
1383            
1384            res = sqlite3_step(pStmt);
1385            if(res != SQLITE_DONE) {
1386                sqlite3_finalize(pStmt);
1387                std::cerr << ToString(sqlite3_errmsg(db)) << std::endl;
1388                DbInstrumentsMutex.Unlock();
1389                return;
1390            }
1391    
1392            sqlite3_finalize(pStmt);
1393            DbInstrumentsMutex.Unlock();
1394        }
1395    
1396      void InstrumentsDb::ExecSql(String Sql) {      void InstrumentsDb::ExecSql(String Sql) {
1397          dmsg(2,("InstrumentsDb: ExecSql(Sql=%s)\n", Sql.c_str()));          dmsg(2,("InstrumentsDb: ExecSql(Sql=%s)\n", Sql.c_str()));
1398          sqlite3_stmt *pStmt = NULL;          sqlite3_stmt *pStmt = NULL;
# Line 1128  namespace LinuxSampler { Line 1572  namespace LinuxSampler {
1572          }          }
1573      }      }
1574    
1575        void InstrumentsDb::Regexp(sqlite3_context* pContext, int argc, sqlite3_value** ppValue) {
1576            if (argc != 2) return;
1577    
1578            String pattern = ToString(sqlite3_value_text(ppValue[0]));
1579            String str = ToString(sqlite3_value_text(ppValue[1]));
1580    
1581            if(!fnmatch(pattern.c_str(), str.c_str(), FNM_CASEFOLD)) {
1582                sqlite3_result_int(pContext, 1);
1583            }
1584        }
1585    
1586      String InstrumentsDb::GetDirectoryPath(String File) {      String InstrumentsDb::GetDirectoryPath(String File) {
1587          if (File.empty()) return String("");          if (File.empty()) return String("");
1588          if (File.at(0) != '/') String("");          if (File.at(0) != '/') String("");
# Line 1169  namespace LinuxSampler { Line 1624  namespace LinuxSampler {
1624          return Dir.substr(0, i);          return Dir.substr(0, i);
1625      }      }
1626    
1627        void InstrumentsDb::Format() {
1628            DbInstrumentsMutex.Lock();
1629            if (db != NULL) {
1630                sqlite3_close(db);
1631                db = NULL;
1632            }
1633    
1634            if (DbFile.empty()) DbFile = CONFIG_DEFAULT_INSTRUMENTS_DB_LOCATION;
1635            String bkp = DbFile + ".bkp";
1636            remove(bkp.c_str());
1637            if (rename(DbFile.c_str(), bkp.c_str()) && errno != ENOENT) {
1638                DbInstrumentsMutex.Unlock();
1639                throw Exception(String("Failed to backup database: ") + strerror(errno));
1640            }
1641            
1642            String f = DbFile;
1643            DbFile = "";
1644            try { CreateInstrumentsDb(f); }
1645            catch(Exception e) {
1646                DbInstrumentsMutex.Unlock();
1647                throw e;
1648            }
1649            DbInstrumentsMutex.Unlock();
1650            
1651            FireDirectoryCountChanged("/");
1652            FireInstrumentCountChanged("/");
1653        }
1654    
1655      void InstrumentsDb::CheckFileName(String File) {      void InstrumentsDb::CheckFileName(String File) {
1656          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);  
         }  
1657      }      }
1658    
1659      String InstrumentsDb::GetUniqueInstrumentName(int DirId, String Name) {      String InstrumentsDb::GetUniqueInstrumentName(int DirId, String Name) {
1660          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=?";  
1661    
1662          if (ExecSqlInt(sql.str(), Name) == 0) return Name;          if (GetInstrumentId(DirId, Name) == -1 && GetDirectoryId(DirId, Name) == -1) return Name;
1663          std::stringstream ss;          std::stringstream ss;
1664          for(int i = 2; i < 1001; i++) {          for(int i = 2; i < 1001; i++) {
1665              ss.str("");              ss.str("");
1666              ss << Name << '[' << i << ']';              ss << Name << '[' << i << ']';
1667              if (ExecSqlInt(sql.str(), ss.str()) == 0) return ss.str();              if (GetInstrumentId(DirId, ss.str()) == -1 && GetInstrumentId(DirId, ss.str()) == -1) {
1668                    return ss.str();
1669                }
1670          }          }
1671    
1672          throw Exception("Unable to find an unique name: " + Name);          throw Exception("Unable to find an unique name: " + Name);
1673      }      }
1674    
1675        String InstrumentsDb::toDbName(String AbstractName) {
1676            for (int i = 0; i < AbstractName.length(); i++) {
1677                if (AbstractName.at(i) == '\0') AbstractName.at(i) = '/';
1678            }
1679            return AbstractName;
1680        }
1681    
1682        String InstrumentsDb::toEscapedPath(String AbstractName) {
1683            for (int i = 0; i < AbstractName.length(); i++) {
1684                if (AbstractName.at(i) == '\0')      AbstractName.replace(i++, 1, "\\x2f");
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) == '"')  AbstractName.replace(i++, 1, "\\\"");
1688                else if (AbstractName.at(i) == '\r') AbstractName.replace(i++, 1, "\\r");
1689                else if (AbstractName.at(i) == '\n') AbstractName.replace(i++, 1, "\\n");
1690            }
1691            return AbstractName;
1692        }
1693        
1694        String InstrumentsDb::toEscapedText(String text) {
1695            for (int i = 0; i < text.length(); i++) {
1696                if (text.at(i) == '\\')      text.replace(i++, 1, "\\\\");
1697                else if (text.at(i) == '\'') text.replace(i++, 1, "\\'");
1698                else if (text.at(i) == '"')  text.replace(i++, 1, "\\\"");
1699                else if (text.at(i) == '\r') text.replace(i++, 1, "\\r");
1700                else if (text.at(i) == '\n') text.replace(i++, 1, "\\n");
1701            }
1702            return text;
1703        }
1704        
1705        String InstrumentsDb::toEscapedFsPath(String FsPath) {
1706            return toEscapedText(FsPath);
1707        }
1708            
1709        String InstrumentsDb::toAbstractName(String DbName) {
1710            for (int i = 0; i < DbName.length(); i++) {
1711                if (DbName.at(i) == '/') DbName.at(i) = '\0';
1712            }
1713            return DbName;
1714        }
1715    
1716      void InstrumentsDb::FireDirectoryCountChanged(String Dir) {      void InstrumentsDb::FireDirectoryCountChanged(String Dir) {
1717          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1718              llInstrumentsDbListeners.GetListener(i)->DirectoryCountChanged(Dir);              llInstrumentsDbListeners.GetListener(i)->DirectoryCountChanged(Dir);
1719          }          }
1720      }      }
1721        
1722      void InstrumentsDb::FireDirectoryInfoChanged(String Dir) {      void InstrumentsDb::FireDirectoryInfoChanged(String Dir) {
1723          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1724              llInstrumentsDbListeners.GetListener(i)->DirectoryInfoChanged(Dir);              llInstrumentsDbListeners.GetListener(i)->DirectoryInfoChanged(Dir);
1725          }          }
1726      }      }
1727        
1728      void InstrumentsDb::FireDirectoryNameChanged(String Dir, String NewName) {      void InstrumentsDb::FireDirectoryNameChanged(String Dir, String NewName) {
1729          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1730              llInstrumentsDbListeners.GetListener(i)->DirectoryNameChanged(Dir, NewName);              llInstrumentsDbListeners.GetListener(i)->DirectoryNameChanged(Dir, NewName);
1731          }          }
1732      }      }
1733        
1734      void InstrumentsDb::FireInstrumentCountChanged(String Dir) {      void InstrumentsDb::FireInstrumentCountChanged(String Dir) {
1735          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1736              llInstrumentsDbListeners.GetListener(i)->InstrumentCountChanged(Dir);              llInstrumentsDbListeners.GetListener(i)->InstrumentCountChanged(Dir);
1737          }          }
1738      }      }
1739        
1740      void InstrumentsDb::FireInstrumentInfoChanged(String Instr) {      void InstrumentsDb::FireInstrumentInfoChanged(String Instr) {
1741          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1742              llInstrumentsDbListeners.GetListener(i)->InstrumentInfoChanged(Instr);              llInstrumentsDbListeners.GetListener(i)->InstrumentInfoChanged(Instr);
1743          }          }
1744      }      }
1745        
1746      void InstrumentsDb::FireInstrumentNameChanged(String Instr, String NewName) {      void InstrumentsDb::FireInstrumentNameChanged(String Instr, String NewName) {
1747          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1748              llInstrumentsDbListeners.GetListener(i)->InstrumentNameChanged(Instr, NewName);              llInstrumentsDbListeners.GetListener(i)->InstrumentNameChanged(Instr, NewName);
1749          }          }
1750      }      }
       
   
     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());  
         }  
1751    
1752          if (!S_ISDIR(statBuf.st_mode)) {      void InstrumentsDb::FireJobStatusChanged(int JobId) {
1753              throw Exception("Directory expected");          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1754          }              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("/");  
1755          }          }
         DirectoryScanner::Flat = Flat;  
           
         ftw(FsDir.c_str(), FtwCallback, 10);  
1756      }      }
1757    
     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;  
     };  
   
1758  } // namespace LinuxSampler  } // namespace LinuxSampler
   
 #endif // HAVE_SQLITE3  

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

  ViewVC Help
Powered by ViewVC