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

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

  ViewVC Help
Powered by ViewVC