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

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

  ViewVC Help
Powered by ViewVC