/[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 1781 by iliev, Mon Sep 29 18:21:21 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/File.h"
24    #include "../common/global_private.h"
25    
26  #include <iostream>  #include <iostream>
27  #include <sstream>  #include <sstream>
28  #include <dirent.h>  #include <vector>
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 FilePath) {
39          if (this == &Dir) return;          File f = File(FilePath);
40            if (f.Exist()) {
41          Created = Dir.Created;              throw Exception("File exists: " + FilePath);
42          Modified = Dir.Modified;          }
43          Description = Dir.Description;          
44            GetInstrumentsDb()->SetDbFile(FilePath);
45    
46            String sql =
47                "  CREATE TABLE instr_dirs (                                      "
48                "      dir_id         INTEGER PRIMARY KEY AUTOINCREMENT,          "
49                "      parent_dir_id  INTEGER DEFAULT 0,                          "
50                "      dir_name       TEXT,                                       "
51                "      created        TIMESTAMP DEFAULT CURRENT_TIMESTAMP,        "
52                "      modified       TIMESTAMP DEFAULT CURRENT_TIMESTAMP,        "
53                "      description    TEXT,                                       "
54                "      FOREIGN KEY(parent_dir_id) REFERENCES instr_dirs(dir_id),  "
55                "      UNIQUE (parent_dir_id,dir_name)                            "
56                "  );                                                             ";
57            
58            GetInstrumentsDb()->ExecSql(sql);
59    
60            sql = "INSERT INTO instr_dirs (dir_id, parent_dir_id, dir_name) VALUES (0, -2, '/');";
61            GetInstrumentsDb()->ExecSql(sql);
62    
63            sql =
64                "  CREATE TABLE instruments (                                "
65                "      instr_id        INTEGER PRIMARY KEY AUTOINCREMENT,    "
66                "      dir_id          INTEGER DEFAULT 0,                    "
67                "      instr_name      TEXT,                                 "
68                "      instr_file      TEXT,                                 "
69                "      instr_nr        INTEGER,                              "
70                "      format_family   TEXT,                                 "
71                "      format_version  TEXT,                                 "
72                "      instr_size      INTEGER,                              "
73                "      created         TIMESTAMP DEFAULT CURRENT_TIMESTAMP,  "
74                "      modified        TIMESTAMP DEFAULT CURRENT_TIMESTAMP,  "
75                "      description     TEXT,                                 "
76                "      is_drum         INTEGER(1),                           "
77                "      product         TEXT,                                 "
78                "      artists         TEXT,                                 "
79                "      keywords        TEXT,                                 "
80                "      FOREIGN KEY(dir_id) REFERENCES instr_dirs(dir_id),    "
81                "      UNIQUE (dir_id,instr_name)                            "
82                "  );                                                        ";
83            
84            GetInstrumentsDb()->ExecSql(sql);
85      }      }
86    
   
     InstrumentsDb* InstrumentsDb::pInstrumentsDb = new InstrumentsDb;  
   
87      InstrumentsDb::InstrumentsDb() {      InstrumentsDb::InstrumentsDb() {
88          db = NULL;          db = NULL;
89          DbInstrumentsMutex = Mutex();          DbInstrumentsMutex = Mutex();
90            InTransaction = false;
91      }      }
92    
93      InstrumentsDb::~InstrumentsDb() {      InstrumentsDb::~InstrumentsDb() {
94          if (db != NULL) sqlite3_close(db);          if (db != NULL) sqlite3_close(db);
95      }      }
96            
     void InstrumentsDb::Destroy() {  
         if (pInstrumentsDb != NULL) {  
             delete pInstrumentsDb;  
             pInstrumentsDb = NULL;  
         }  
     }  
   
97      void InstrumentsDb::AddInstrumentsDbListener(InstrumentsDb::Listener* l) {      void InstrumentsDb::AddInstrumentsDbListener(InstrumentsDb::Listener* l) {
98          llInstrumentsDbListeners.AddListener(l);          llInstrumentsDbListeners.AddListener(l);
99      }      }
# Line 85  namespace LinuxSampler { Line 103  namespace LinuxSampler {
103      }      }
104            
105      InstrumentsDb* InstrumentsDb::GetInstrumentsDb() {      InstrumentsDb* InstrumentsDb::GetInstrumentsDb() {
106          return pInstrumentsDb;          return &instance;
107      }      }
108            
109      void InstrumentsDb::SetDbFile(String File) {      void InstrumentsDb::SetDbFile(String File) {
# Line 101  namespace LinuxSampler { Line 119  namespace LinuxSampler {
119      sqlite3* InstrumentsDb::GetDb() {      sqlite3* InstrumentsDb::GetDb() {
120          if ( db != NULL) return db;          if ( db != NULL) return db;
121    
122          if (DbFile.empty()) DbFile = "/var/lib/linuxsampler/instruments.db";          if (DbFile.empty()) DbFile = CONFIG_DEFAULT_INSTRUMENTS_DB_LOCATION;
123                    #if defined(__APPLE__)  /* 20071224 Toshi Nagata  */
124                    if (DbFile.find("~") == 0)
125                            DbFile.replace(0, 1, getenv("HOME"));
126                    #endif
127          int rc = sqlite3_open(DbFile.c_str(), &db);          int rc = sqlite3_open(DbFile.c_str(), &db);
128          if (rc) {          if (rc) {
129              sqlite3_close(db);              sqlite3_close(db);
130              db = NULL;              db = NULL;
131              throw Exception("Cannot open instruments database: " + DbFile);              throw Exception("Cannot open instruments database: " + DbFile);
132          }          }
133            rc = sqlite3_create_function(db, "regexp", 2, SQLITE_UTF8, NULL, Regexp, NULL, NULL);
134            if (rc) { throw Exception("Failed to add user function for handling regular expressions."); }
135    
136            // TODO: remove this in the next version
137            try {
138                int i = ExecSqlInt("SELECT parent_dir_id FROM instr_dirs WHERE dir_id=0");
139                // The parent ID of the root directory should be -2 now.
140                if(i != -2) ExecSql("UPDATE instr_dirs SET parent_dir_id=-2 WHERE dir_id=0");
141            } catch(Exception e) { }
142            ////////////////////////////////////////
143                    
144          return db;          return db;
145      }      }
# Line 121  namespace LinuxSampler { Line 153  namespace LinuxSampler {
153                    
154          int count = ExecSqlInt(sql.str());          int count = ExecSqlInt(sql.str());
155    
         // 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--;  
156          return count;          return count;
157      }      }
158    
159      int InstrumentsDb::GetDirectoryCount(String Dir) {      int InstrumentsDb::GetDirectoryCount(String Dir, bool Recursive) {
160          dmsg(2,("InstrumentsDb: GetDirectoryCount(Dir=%s)\n", Dir.c_str()));          dmsg(2,("InstrumentsDb: GetDirectoryCount(Dir=%s,Recursive=%d)\n", Dir.c_str(), Recursive));
161          int i;          int i;
162    
163          DbInstrumentsMutex.Lock();          BeginTransaction();
164          try { i = GetDirectoryCount(GetDirectoryId(Dir)); }          try {
165          catch (Exception e) {              if (Recursive) {
166              DbInstrumentsMutex.Unlock();                  DirectoryCounter directoryCounter;
167                    DirectoryTreeWalk(Dir, &directoryCounter);
168                    i = directoryCounter.GetDirectoryCount();
169                } else {
170                    i = GetDirectoryCount(GetDirectoryId(Dir));
171                }
172            } catch (Exception e) {
173                EndTransaction();
174              throw e;              throw e;
175          }          }
176          DbInstrumentsMutex.Unlock();          EndTransaction();
177          if (i == -1) throw Exception("Unkown DB directory: " + Dir);          if (i == -1) throw Exception("Unkown DB directory: " + toEscapedPath(Dir));
178                    
179          return i;          return i;
180      }      }
# Line 151  namespace LinuxSampler { Line 187  namespace LinuxSampler {
187          return ExecSqlIntList(sql.str());          return ExecSqlIntList(sql.str());
188      }      }
189    
190      StringListPtr InstrumentsDb::GetDirectories(String Dir) {      StringListPtr InstrumentsDb::GetDirectories(String Dir, bool Recursive) {
191          dmsg(2,("InstrumentsDb: GetDirectories(Dir=%s)\n", Dir.c_str()));          dmsg(2,("InstrumentsDb: GetDirectories(Dir=%s,Recursive=%d)\n", Dir.c_str(), Recursive));
192    
193          DbInstrumentsMutex.Lock();          BeginTransaction();
194          try {          try {
195              int dirId = GetDirectoryId(Dir);              int dirId = GetDirectoryId(Dir);
196              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";  
197    
198              DbInstrumentsMutex.Unlock();              StringListPtr pDirs;
199              return ExecSqlStringList(sql.str());              if (Recursive) {
200                    SearchQuery q;
201                    DirectoryFinder directoryFinder(&q);
202                    DirectoryTreeWalk(Dir, &directoryFinder);
203                    pDirs = directoryFinder.GetDirectories();
204                } else {
205                    pDirs = GetDirectories(dirId);
206                }
207                EndTransaction();
208                return pDirs;
209          } catch (Exception e) {          } catch (Exception e) {
210              DbInstrumentsMutex.Unlock();              EndTransaction();
211              throw e;              throw e;
212          }          }
213      }      }
214        
215        StringListPtr InstrumentsDb::GetDirectories(int DirId) {
216            std::stringstream sql;
217            sql << "SELECT dir_name FROM instr_dirs ";
218            sql << "WHERE parent_dir_id=" << DirId << " AND dir_id!=0";
219            StringListPtr dirs = ExecSqlStringList(sql.str());
220    
221            for (int i = 0; i < dirs->size(); i++) {
222                for (int j = 0; j < dirs->at(i).length(); j++) {
223                    if (dirs->at(i).at(j) == '/') dirs->at(i).at(j) = '\0';
224                }
225            }
226    
227            return dirs;
228        }
229    
230      int InstrumentsDb::GetDirectoryId(String Dir) {      int InstrumentsDb::GetDirectoryId(String Dir) {
231          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 253  namespace LinuxSampler {
253    
254      int InstrumentsDb::GetDirectoryId(int ParentDirId, String DirName) {      int InstrumentsDb::GetDirectoryId(int ParentDirId, String DirName) {
255          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()));
256            DirName = toDbName(DirName);
257          std::stringstream sql;          std::stringstream sql;
258          sql << "SELECT dir_id FROM instr_dirs WHERE parent_dir_id=";          sql << "SELECT dir_id FROM instr_dirs WHERE parent_dir_id=";
259          sql << ParentDirId << " AND dir_name=?";          sql << ParentDirId << " AND dir_name=?";
260          return ExecSqlInt(sql.str(), DirName);          return ExecSqlInt(sql.str(), DirName);
261      }      }
262    
263        int InstrumentsDb::GetDirectoryId(int InstrId) {
264            dmsg(2,("InstrumentsDb: GetDirectoryId(InstrId=%d)\n", InstrId));
265            std::stringstream sql;
266            sql << "SELECT dir_id FROM instruments WHERE instr_id=" << InstrId;
267            return ExecSqlInt(sql.str());
268        }
269    
270        String InstrumentsDb::GetDirectoryName(int DirId) {
271            String sql = "SELECT dir_name FROM instr_dirs WHERE dir_id=" + ToString(DirId);
272            String name = ExecSqlString(sql);
273            if (name.empty()) throw Exception("Directory ID not found");
274            return name;
275        }
276    
277        int InstrumentsDb::GetParentDirectoryId(int DirId) {
278            if (DirId == 0) throw Exception("The root directory is specified");
279            String sql = "SELECT parent_dir_id FROM instr_dirs WHERE dir_id=" + ToString(DirId);
280            int parentId = ExecSqlInt(sql);
281            if (parentId == -1) throw Exception("DB directory not found");
282            return parentId;
283        }
284    
285        String InstrumentsDb::GetDirectoryPath(int DirId) {
286            String path = "";
287            int count = 1000; // used to prevent infinite loops
288    
289            while(--count) {
290                if (DirId == 0) {
291                    path = "/" + path;
292                    break;
293                }
294                path = GetDirectoryName(DirId) + "/" + path;
295                DirId = GetParentDirectoryId(DirId);
296            }
297    
298            if (!count) throw Exception("Possible infinite loop detected");
299    
300            return path;
301        }
302        
303        StringListPtr InstrumentsDb::GetInstrumentsByFile(String File) {
304            dmsg(2,("InstrumentsDb: GetInstrumentsByFile(File=%s)\n", File.c_str()));
305    
306            StringListPtr instrs(new std::vector<String>);
307            
308            BeginTransaction();
309            try {
310                File = toEscapedFsPath(File);
311                IntListPtr ids = ExecSqlIntList("SELECT instr_id FROM instruments WHERE instr_file=?", File);
312                
313                for (int i = 0; i < ids->size(); i++) {
314                    String name = GetInstrumentName(ids->at(i));
315                    String dir = GetDirectoryPath(GetDirectoryId(ids->at(i)));
316                    instrs->push_back(dir + name);
317                }
318            } catch (Exception e) {
319                EndTransaction();
320                throw e;
321            }
322            EndTransaction();
323            
324            return instrs;
325        }
326    
327      void InstrumentsDb::AddDirectory(String Dir) {      void InstrumentsDb::AddDirectory(String Dir) {
328          dmsg(2,("InstrumentsDb: AddDirectory(Dir=%s)\n", Dir.c_str()));          dmsg(2,("InstrumentsDb: AddDirectory(Dir=%s)\n", Dir.c_str()));
329          CheckPathName(Dir);          CheckPathName(Dir);
330          String ParentDir = GetParentDirectory(Dir);          String ParentDir = GetParentDirectory(Dir);
331                    
332          DbInstrumentsMutex.Lock();          BeginTransaction();
333          try {          try {
334              if (Dir.length() > 1) {              if (Dir.length() > 1) {
335                  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 337  namespace LinuxSampler {
337    
338              String dirName = GetFileName(Dir);              String dirName = GetFileName(Dir);
339              if(ParentDir.empty() || dirName.empty()) {              if(ParentDir.empty() || dirName.empty()) {
340                  throw Exception("Failed to add DB directory: " + Dir);                  throw Exception("Failed to add DB directory: " + toEscapedPath(Dir));
341              }              }
342    
343              int id = GetDirectoryId(ParentDir);              int id = GetDirectoryId(ParentDir);
344              if (id == -1) throw Exception("DB directory doesn't exist: " + ParentDir);              if (id == -1) throw Exception("DB directory doesn't exist: " + toEscapedPath(ParentDir));
345              int id2 = GetDirectoryId(id, dirName);              int id2 = GetDirectoryId(id, dirName);
346              if (id2 != -1) throw Exception("DB directory already exist: " + Dir);              if (id2 != -1) throw Exception("DB directory already exist: " + toEscapedPath(Dir));
347                id2 = GetInstrumentId(id, dirName);
348                if (id2 != -1) throw Exception("Instrument with that name exist: " + toEscapedPath(Dir));
349    
350              std::stringstream sql;              std::stringstream sql;
351              sql << "INSERT INTO instr_dirs (parent_dir_id, dir_name) VALUES (";              sql << "INSERT INTO instr_dirs (parent_dir_id, dir_name) VALUES (";
352              sql << id << ", ?)";              sql << id << ", ?)";
353    
354              ExecSql(sql.str(), dirName);              ExecSql(sql.str(), toDbName(dirName));
355          } catch (Exception e) {          } catch (Exception e) {
356              DbInstrumentsMutex.Unlock();              EndTransaction();
357              throw e;              throw e;
358          }          }
359    
360          DbInstrumentsMutex.Unlock();          EndTransaction();
361    
362          FireDirectoryCountChanged(ParentDir);          FireDirectoryCountChanged(ParentDir);
363      }      }
# Line 244  namespace LinuxSampler { Line 367  namespace LinuxSampler {
367    
368          String ParentDir = GetParentDirectory(Dir);          String ParentDir = GetParentDirectory(Dir);
369    
370          DbInstrumentsMutex.Lock();          BeginTransaction();
371          try {          try {
372              int dirId = GetDirectoryId(Dir);              int dirId = GetDirectoryId(Dir);
373              if (dirId == -1) throw Exception("Unknown DB directory: " + Dir);              if (dirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
374              if (dirId == 0) throw Exception("Cannot delete the root directory: " + Dir);              if (dirId == 0) throw Exception("Cannot delete the root directory: " + Dir);
375              if(ParentDir.empty()) throw Exception("Unknown parent directory");              if(ParentDir.empty()) throw Exception("Unknown parent directory");
376              if (Force) RemoveDirectoryContent(dirId);              if (Force) RemoveDirectoryContent(dirId);
377              RemoveDirectory(dirId);              RemoveDirectory(dirId);
378          } catch (Exception e) {          } catch (Exception e) {
379              DbInstrumentsMutex.Unlock();              EndTransaction();
380              throw e;              throw e;
381          }          }
382    
383          DbInstrumentsMutex.Unlock();          EndTransaction();
384          FireDirectoryCountChanged(ParentDir);          FireDirectoryCountChanged(ParentDir);
385      }      }
386    
# Line 330  namespace LinuxSampler { Line 453  namespace LinuxSampler {
453          dmsg(2,("InstrumentsDb: GetDirectoryInfo(Dir=%s)\n", Dir.c_str()));          dmsg(2,("InstrumentsDb: GetDirectoryInfo(Dir=%s)\n", Dir.c_str()));
454          DbDirectory d;          DbDirectory d;
455    
456          DbInstrumentsMutex.Lock();          BeginTransaction();
457    
458          try {          try {
459              int id = GetDirectoryId(Dir);              int id = GetDirectoryId(Dir);
460              if(id == -1) throw Exception("Unknown DB directory: " + Dir);              if(id == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
461    
462              sqlite3_stmt *pStmt = NULL;              sqlite3_stmt *pStmt = NULL;
463              std::stringstream sql;              std::stringstream sql;
# Line 357  namespace LinuxSampler { Line 480  namespace LinuxSampler {
480                  if (res != SQLITE_DONE) {                  if (res != SQLITE_DONE) {
481                      throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));                      throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
482                  } else {                  } else {
483                      throw Exception("Unknown DB directory: " + Dir);                      throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
484                  }                  }
485              }              }
486                            
487              sqlite3_finalize(pStmt);              sqlite3_finalize(pStmt);
488          } catch (Exception e) {          } catch (Exception e) {
489              DbInstrumentsMutex.Unlock();              EndTransaction();
490              throw e;              throw e;
491          }          }
492    
493          DbInstrumentsMutex.Unlock();          EndTransaction();
494          return d;          return d;
495      }      }
496    
497      void InstrumentsDb::RenameDirectory(String Dir, String Name) {      void InstrumentsDb::RenameDirectory(String Dir, String Name) {
498          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()));
499          CheckFileName(Name);          CheckFileName(Name);
500            String dbName = toDbName(Name);
501    
502          DbInstrumentsMutex.Lock();          BeginTransaction();
503          try {          try {
504              int dirId = GetDirectoryId(Dir);              int dirId = GetDirectoryId(Dir);
505              if (dirId == -1) throw Exception("Unknown DB directory: " + Dir);              if (dirId == -1) throw Exception("Unknown DB directory: " + toEscapedText(Dir));
506    
507              std::stringstream sql;              std::stringstream sql;
508              sql << "SELECT parent_dir_id FROM instr_dirs WHERE dir_id=" <<  dirId;              sql << "SELECT parent_dir_id FROM instr_dirs WHERE dir_id=" <<  dirId;
509    
510              int parent = ExecSqlInt(sql.str());              int parent = ExecSqlInt(sql.str());
511              if (parent == -1) throw Exception("Unknown parent directory: " + Dir);              if (parent == -1) throw Exception("Unknown parent directory: " + toEscapedPath(Dir));
512              if (GetDirectoryId(parent, Name) != -1) {  
513                  throw Exception("Cannot rename. Directory with that name already exists: " + Name);              if (GetDirectoryId(parent, dbName) != -1) {
514                    String s = toEscapedPath(Name);
515                    throw Exception("Cannot rename. Directory with that name already exists: " + s);
516                }
517    
518                if (GetInstrumentId(parent, dbName) != -1) {
519                    throw Exception("Cannot rename. Instrument with that name exist: " + toEscapedPath(Dir));
520              }              }
521    
522              sql.str("");              sql.str("");
523              sql << "UPDATE instr_dirs SET dir_name=? WHERE dir_id=" << dirId;              sql << "UPDATE instr_dirs SET dir_name=? WHERE dir_id=" << dirId;
524              ExecSql(sql.str(), Name);              ExecSql(sql.str(), dbName);
525          } catch (Exception e) {          } catch (Exception e) {
526              DbInstrumentsMutex.Unlock();              EndTransaction();
527              throw e;              throw e;
528          }          }
529    
530          DbInstrumentsMutex.Unlock();          EndTransaction();
531          FireDirectoryNameChanged(Dir, Name);          FireDirectoryNameChanged(Dir, toAbstractName(Name));
532      }      }
533    
534      void InstrumentsDb::MoveDirectory(String Dir, String Dst) {      void InstrumentsDb::MoveDirectory(String Dir, String Dst) {
535          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()));
536    
537            if(Dir.compare("/") == 0) throw Exception("Cannot move the root directory");
538          String ParentDir = GetParentDirectory(Dir);          String ParentDir = GetParentDirectory(Dir);
539          if(ParentDir.empty()) throw Exception("Unknown parent directory");          if(ParentDir.empty()) throw Exception("Unknown parent directory");
540    
541          DbInstrumentsMutex.Lock();          BeginTransaction();
542          try {          try {
543              int dirId = GetDirectoryId(Dir);              int dirId = GetDirectoryId(Dir);
544              if (dirId == -1) throw Exception("Unknown DB directory: " + Dir);              if (dirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
545              int dstId = GetDirectoryId(Dst);              int dstId = GetDirectoryId(Dst);
546              if (dstId == -1) throw Exception("Unknown DB directory: " + Dst);              if (dstId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dst));
547              if (dirId == dstId) {              if (dirId == dstId) {
548                  throw Exception("Cannot move directory to itself");                  throw Exception("Cannot move directory to itself");
549              }              }
# Line 423  namespace LinuxSampler { Line 554  namespace LinuxSampler {
554                      throw Exception("Cannot move a directory to a subdirectory of itself.");                      throw Exception("Cannot move a directory to a subdirectory of itself.");
555                  }                  }
556              }              }
557                
558                Dir.erase(Dir.length() - 1);
559                String dirName = GetFileName(Dir);
560    
561                int id2 = GetDirectoryId(dstId, dirName);
562                if (id2 != -1) throw Exception("DB directory already exist: " + toEscapedPath(dirName));
563                id2 = GetInstrumentId(dstId, dirName);
564                if (id2 != -1) throw Exception("Instrument with that name exist: " + toEscapedPath(dirName));
565    
566              std::stringstream sql;              std::stringstream sql;
567              sql << "UPDATE instr_dirs SET parent_dir_id=" << dstId;              sql << "UPDATE instr_dirs SET parent_dir_id=" << dstId;
568              sql << " WHERE dir_id=" << dirId;              sql << " WHERE dir_id=" << dirId;
569              ExecSql(sql.str());              ExecSql(sql.str());
570          } catch (Exception e) {          } catch (Exception e) {
571              DbInstrumentsMutex.Unlock();              EndTransaction();
572              throw e;              throw e;
573          }          }
574    
575          DbInstrumentsMutex.Unlock();          EndTransaction();
576          FireDirectoryCountChanged(ParentDir);          FireDirectoryCountChanged(ParentDir);
577          FireDirectoryCountChanged(Dst);          FireDirectoryCountChanged(Dst);
578      }      }
579    
580        void InstrumentsDb::CopyDirectory(String Dir, String Dst) {
581            dmsg(2,("InstrumentsDb: CopyDirectory(Dir=%s,Dst=%s)\n", Dir.c_str(), Dst.c_str()));
582    
583            if(Dir.compare("/") == 0) throw Exception("Cannot copy the root directory");
584            String ParentDir = GetParentDirectory(Dir);
585            if(ParentDir.empty()) throw Exception("Unknown parent directory");
586    
587            BeginTransaction();
588            try {
589                int dirId = GetDirectoryId(Dir);
590                if (dirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
591                int dstId = GetDirectoryId(Dst);
592                if (dstId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dst));
593                if (dirId == dstId) {
594                    throw Exception("Cannot copy directory to itself");
595                }
596    
597                if (Dir.at(Dir.length() - 1) != '/') Dir.append("/");
598                if (Dst.length() > Dir.length()) {
599                    if (Dir.compare(Dst.substr(0, Dir.length())) == 0) {
600                        throw Exception("Cannot copy a directory to a subdirectory of itself.");
601                    }
602                }
603                
604                Dir.erase(Dir.length() - 1);
605                String dirName = GetFileName(Dir);
606    
607                int id2 = GetDirectoryId(dstId, dirName);
608                if (id2 != -1) throw Exception("DB directory already exist: " + toEscapedPath(dirName));
609                id2 = GetInstrumentId(dstId, dirName);
610                if (id2 != -1) throw Exception("Instrument with that name exist: " + toEscapedPath(dirName));
611    
612                DirectoryCopier directoryCopier(ParentDir, Dst);
613                DirectoryTreeWalk(Dir, &directoryCopier);
614            } catch (Exception e) {
615                EndTransaction();
616                throw e;
617            }
618    
619            EndTransaction();
620        }
621    
622      void InstrumentsDb::SetDirectoryDescription(String Dir, String Desc) {      void InstrumentsDb::SetDirectoryDescription(String Dir, String Desc) {
623          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()));
624                    
625          DbInstrumentsMutex.Lock();          BeginTransaction();
626          try {          try {
627              int id = GetDirectoryId(Dir);              int id = GetDirectoryId(Dir);
628              if(id == -1) throw Exception("Unknown DB directory: " + Dir);              if(id == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
629    
630              std::stringstream sql;              std::stringstream sql;
631              sql << "UPDATE instr_dirs SET description=?,modified=CURRENT_TIMESTAMP ";              sql << "UPDATE instr_dirs SET description=?,modified=CURRENT_TIMESTAMP ";
# Line 452  namespace LinuxSampler { Line 633  namespace LinuxSampler {
633                    
634              ExecSql(sql.str(), Desc);              ExecSql(sql.str(), Desc);
635          } catch (Exception e) {          } catch (Exception e) {
636              DbInstrumentsMutex.Unlock();              EndTransaction();
637              throw e;              throw e;
638          }          }
639          DbInstrumentsMutex.Unlock();          EndTransaction();
640                    
641          FireDirectoryInfoChanged(Dir);          FireDirectoryInfoChanged(Dir);
642      }      }
643    
644      void InstrumentsDb::AddInstruments(String DbDir, String FilePath, int Index) {      int InstrumentsDb::AddInstruments(ScanMode Mode, String DbDir, String FsDir, bool bBackground, bool insDir) {
645          dmsg(2,("InstrumentsDb: AddInstruments(DbDir=%s,FilePath=%s,Index=%d)\n", DbDir.c_str(), FilePath.c_str(), Index));          dmsg(2,("InstrumentsDb: AddInstruments(Mode=%d,DbDir=%s,FsDir=%s,bBackground=%d,insDir=%d)\n", Mode, DbDir.c_str(), FsDir.c_str(), bBackground, insDir));
646            if(!bBackground) {
647                switch (Mode) {
648                    case NON_RECURSIVE:
649                        AddInstrumentsNonrecursive(DbDir, FsDir, insDir);
650                        break;
651                    case RECURSIVE:
652                        AddInstrumentsRecursive(DbDir, FsDir, false, insDir);
653                        break;
654                    case FLAT:
655                        AddInstrumentsRecursive(DbDir, FsDir, true, insDir);
656                        break;
657                    default:
658                        throw Exception("Unknown scan mode");
659                }
660    
661                return -1;
662            }
663    
664            ScanJob job;
665            int jobId = Jobs.AddJob(job);
666            InstrumentsDbThread.Execute(new AddInstrumentsJob(jobId, Mode, DbDir, FsDir, insDir));
667    
668            return jobId;
669        }
670        
671        int InstrumentsDb::AddInstruments(String DbDir, String FilePath, int Index, bool bBackground) {
672            dmsg(2,("InstrumentsDb: AddInstruments(DbDir=%s,FilePath=%s,Index=%d,bBackground=%d)\n", DbDir.c_str(), FilePath.c_str(), Index, bBackground));
673            if(!bBackground) {
674                AddInstruments(DbDir, false, FilePath, Index);
675                return -1;
676            }
677    
678            ScanJob job;
679            int jobId = Jobs.AddJob(job);
680            InstrumentsDbThread.Execute(new AddInstrumentsFromFileJob(jobId, DbDir, FilePath, Index, false));
681    
682            return jobId;
683        }
684    
685        void InstrumentsDb::AddInstruments(String DbDir, bool insDir, String FilePath, int Index, ScanProgress* pProgress) {
686            dmsg(2,("InstrumentsDb: AddInstruments(DbDir=%s,insDir=%d,FilePath=%s,Index=%d)\n", DbDir.c_str(), insDir, FilePath.c_str(), Index));
687          if (DbDir.empty() || FilePath.empty()) return;          if (DbDir.empty() || FilePath.empty()) return;
688                    
689          DbInstrumentsMutex.Lock();          DbInstrumentsMutex.Lock();
690          try {          try {
691              int dirId = GetDirectoryId(DbDir);              int dirId = GetDirectoryId(DbDir);
692              if (dirId == -1) throw Exception("Invalid DB directory: " + DbDir);              if (dirId == -1) throw Exception("Invalid DB directory: " + toEscapedText(DbDir));
693    
694              struct stat statBuf;              File f = File(FilePath);
695              int res = stat(FilePath.c_str(), &statBuf);              if (!f.Exist()) {
             if (res) {  
696                  std::stringstream ss;                  std::stringstream ss;
697                  ss << "Fail to stat `" << FilePath << "`: " << strerror(errno);                  ss << "Fail to stat `" << FilePath << "`: " << f.GetErrorMsg();
698                  throw Exception(ss.str());                  throw Exception(ss.str());
699              }              }
700    
701              if (S_ISREG(statBuf.st_mode)) {              if (!f.IsFile()) {
                 AddInstrumentsFromFile(DbDir, FilePath, Index);  
                 DbInstrumentsMutex.Unlock();  
                 return;  
             }  
   
             if (!S_ISDIR(statBuf.st_mode)) {  
                 DbInstrumentsMutex.Unlock();  
                 return;  
             }  
               
             if (Index != -1) {  
702                  std::stringstream ss;                  std::stringstream ss;
703                  ss << "`" << FilePath << "` is directory, not an instrument file";                  ss << "`" << FilePath << "` is not an instrument file";
704                  throw Exception(ss.str());                  throw Exception(ss.str());
705              }              }
706            
707              AddInstrumentsRecursive(DbDir, FilePath, false);                          if(insDir) {
708                                    std::string tmp = f.basename(FilePath, ".");
709                                    String gigDir;
710                                    if(DbDir.length() == 1 && DbDir.at(0) == '/') //DbDir is /
711                                            gigDir = DbDir + (String)tmp + "/";
712                                    else
713                                            gigDir = DbDir +"/"+ (String)tmp + "/";
714                                    dmsg(2,("InstrumentsDb: AddInstrumentsNonrecursive(Dir from file mode=%d, Created SubDir=%s)\n",insDir, gigDir.c_str()));
715                    DbInstrumentsMutex.Unlock();
716                                    AddDirectory(gigDir);//TODO: Add some error checking here to make sure the dir is created
717                    DbInstrumentsMutex.Lock();
718                    AddInstrumentsFromFile(gigDir, FilePath, Index, pProgress);
719                            } else {
720                    AddInstrumentsFromFile(DbDir, FilePath, Index, pProgress);
721                            }
722          } catch (Exception e) {          } catch (Exception e) {
723              DbInstrumentsMutex.Unlock();              DbInstrumentsMutex.Unlock();
724              throw e;              throw e;
# Line 503  namespace LinuxSampler { Line 727  namespace LinuxSampler {
727          DbInstrumentsMutex.Unlock();          DbInstrumentsMutex.Unlock();
728      }      }
729    
730      void InstrumentsDb::AddInstrumentsNonrecursive(String DbDir, String FsDir) {      void InstrumentsDb::AddInstrumentsNonrecursive(String DbDir, String FsDir, bool insDir, ScanProgress* pProgress) {
731          dmsg(2,("InstrumentsDb: AddInstrumentsNonrecursive(DbDir=%s,FsDir=%s)\n", DbDir.c_str(), FsDir.c_str()));          dmsg(2,("InstrumentsDb: AddInstrumentsNonrecursive(DbDir=%s,FsDir=%s,insDir=%d)\n", DbDir.c_str(), FsDir.c_str(), insDir));
732          if (DbDir.empty() || FsDir.empty()) return;          if (DbDir.empty() || FsDir.empty()) return;
733                    
734          DbInstrumentsMutex.Lock();          DbInstrumentsMutex.Lock();
735          try {          try {
736              int dirId = GetDirectoryId(DbDir);              int dirId = GetDirectoryId(DbDir);
737              if (dirId == -1) throw Exception("Invalid DB directory: " + DbDir);              if (dirId == -1) throw Exception("Invalid DB directory: " + toEscapedPath(DbDir));
738    
739              struct stat statBuf;              File f = File(FsDir);
740              int res = stat(FsDir.c_str(), &statBuf);              if (!f.Exist()) {
             if (res) {  
741                  std::stringstream ss;                  std::stringstream ss;
742                  ss << "Fail to stat `" << FsDir << "`: " << strerror(errno);                  ss << "Fail to stat `" << FsDir << "`: " << f.GetErrorMsg();
743                  throw Exception(ss.str());                  throw Exception(ss.str());
744              }              }
745    
746              if (!S_ISDIR(statBuf.st_mode)) {              if (!f.IsDirectory()) {
747                  throw Exception("Directory expected");                  throw Exception("Directory expected: " + FsDir);
748              }              }
749                            
750              if (FsDir.at(FsDir.length() - 1) != '/') FsDir.append("/");              if (FsDir.at(FsDir.length() - 1) != File::DirSeparator) {
751                    FsDir.push_back(File::DirSeparator);
             DIR* pDir = opendir(FsDir.c_str());  
             if (pDir == NULL) {  
                 std::stringstream ss;  
                 ss << "The scanning of directory `" << FsDir << "` failed: ";  
                 ss << strerror(errno);  
                 std::cout << ss.str();  
                 DbInstrumentsMutex.Unlock();  
                 return;  
752              }              }
753                
754              struct dirent* pEnt = readdir(pDir);              try {
755              while (pEnt != NULL) {                  FileListPtr fileList = File::GetFiles(FsDir);
756                  if (pEnt->d_type != DT_REG) {                  for (int i = 0; i < fileList->size(); i++) {
757                      pEnt = readdir(pDir);                                          if(insDir)
758                      continue;                                          {
759                                                    //File gFile = File(fileList->at(i));
760                                                    String gigDir;
761                                                    if(DbDir.length() == 1 && DbDir.at(0) == '/') //DbDir is /
762                                                            gigDir  = DbDir + f.basename(fileList->at(i),".") + "/";
763                                                    else
764                                                            gigDir  = DbDir +"/"+ f.basename(fileList->at(i),".") + "/";
765                                                    dmsg(2,("InstrumentsDb: AddInstrumentsNonrecursive(Dir from file mode=%d, Created SubDir=%s)\n",insDir, gigDir.c_str()));
766                                    DbInstrumentsMutex.Unlock(); // UnLock the db so we can add our extra directory
767                                                    AddDirectory(gigDir);//TODO: Add some error checking here to make sure the dir is created
768                                            DbInstrumentsMutex.Lock(); //Lock and carry on
769                            AddInstrumentsFromFile(gigDir, FsDir + fileList->at(i), -1, pProgress);
770                                            }
771                                            else
772                                            {
773                            AddInstrumentsFromFile(DbDir, FsDir + fileList->at(i), -1, pProgress);
774                                            }
775                  }                  }
776                } catch(Exception e) {
777                  AddInstrumentsFromFile(DbDir, FsDir + String(pEnt->d_name));                  e.PrintMessage();
778                  pEnt = readdir(pDir);                  DbInstrumentsMutex.Unlock();
779              }                  return;
   
             if (closedir(pDir)) {  
                 std::stringstream ss;  
                 ss << "Failed to close directory `" << FsDir << "`: ";  
                 ss << strerror(errno);  
                 std::cout << ss.str();  
780              }              }
781          } catch (Exception e) {          } catch (Exception e) {
782              DbInstrumentsMutex.Unlock();              DbInstrumentsMutex.Unlock();
# Line 561  namespace LinuxSampler { Line 786  namespace LinuxSampler {
786          DbInstrumentsMutex.Unlock();          DbInstrumentsMutex.Unlock();
787      }      }
788    
789      void InstrumentsDb::AddInstrumentsRecursive(String DbDir, String FsDir, bool Flat) {      void InstrumentsDb::AddInstrumentsRecursive(String DbDir, String FsDir, bool Flat, bool insDir, ScanProgress* pProgress) {
790          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,insDir=%d)\n", DbDir.c_str(), FsDir.c_str(), Flat, insDir));
791          DirectoryScanner::Scan(DbDir, FsDir, Flat);          if (pProgress != NULL) {
792                InstrumentFileCounter c;
793                pProgress->SetTotalFileCount(c.Count(FsDir));
794            }
795    
796            DirectoryScanner d;
797            d.Scan(DbDir, FsDir, Flat, insDir, pProgress);
798      }      }
799    
800      int InstrumentsDb::GetInstrumentCount(int DirId) {      int InstrumentsDb::GetInstrumentCount(int DirId) {
# Line 576  namespace LinuxSampler { Line 807  namespace LinuxSampler {
807          return ExecSqlInt(sql.str());          return ExecSqlInt(sql.str());
808      }      }
809    
810      int InstrumentsDb::GetInstrumentCount(String Dir) {      int InstrumentsDb::GetInstrumentCount(String Dir, bool Recursive) {
811          dmsg(2,("InstrumentsDb: GetInstrumentCount(Dir=%s)\n", Dir.c_str()));          dmsg(2,("InstrumentsDb: GetInstrumentCount(Dir=%s,Recursive=%d)\n", Dir.c_str(), Recursive));
812          int i;          int i;
813                    
814          DbInstrumentsMutex.Lock();          BeginTransaction();
815          try { i = GetInstrumentCount(GetDirectoryId(Dir)); }          try {
816          catch (Exception e) {              if (Recursive) {
817              DbInstrumentsMutex.Unlock();                  InstrumentCounter instrumentCounter;
818                    DirectoryTreeWalk(Dir, &instrumentCounter);
819                    i = instrumentCounter.GetInstrumentCount();
820                } else {
821                    i = GetInstrumentCount(GetDirectoryId(Dir));
822                }
823            } catch (Exception e) {
824                EndTransaction();
825              throw e;              throw e;
826          }          }
827          DbInstrumentsMutex.Unlock();          EndTransaction();
828    
829          if (i == -1) throw Exception("Unknown Db directory: " + Dir);          if (i == -1) throw Exception("Unknown Db directory: " + toEscapedPath(Dir));
830          return i;          return i;
831      }      }
832    
# Line 599  namespace LinuxSampler { Line 837  namespace LinuxSampler {
837          return ExecSqlIntList(sql.str());          return ExecSqlIntList(sql.str());
838      }      }
839    
840      StringListPtr InstrumentsDb::GetInstruments(String Dir) {      StringListPtr InstrumentsDb::GetInstruments(String Dir, bool Recursive) {
841          dmsg(2,("InstrumentsDb: GetInstruments(Dir=%s)\n", Dir.c_str()));          dmsg(2,("InstrumentsDb: GetInstruments(Dir=%s,Recursive=%d)\n", Dir.c_str(), Recursive));
842          DbInstrumentsMutex.Lock();          BeginTransaction();
843          try {          try {
844              int dirId = GetDirectoryId(Dir);              int dirId = GetDirectoryId(Dir);
845              if(dirId == -1) throw Exception("Unknown DB directory: " + Dir);              if(dirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
846    
847              std::stringstream sql;              StringListPtr pInstrs;
             sql << "SELECT instr_name FROM instruments WHERE dir_id=" << dirId;  
848    
849              StringListPtr instrs = ExecSqlStringList(sql.str());              if(Recursive) {
850              DbInstrumentsMutex.Unlock();                  SearchQuery q;
851              return instrs;                  InstrumentFinder instrumentFinder(&q);
852                    DirectoryTreeWalk(Dir, &instrumentFinder);
853                    pInstrs = instrumentFinder.GetInstruments();
854                } else {
855                    std::stringstream sql;
856                    sql << "SELECT instr_name FROM instruments WHERE dir_id=" << dirId;
857    
858                    pInstrs = ExecSqlStringList(sql.str());
859                    // Converting to abstract names
860                    for (int i = 0; i < pInstrs->size(); i++) {
861                        for (int j = 0; j < pInstrs->at(i).length(); j++) {
862                            if (pInstrs->at(i).at(j) == '/') pInstrs->at(i).at(j) = '\0';
863                        }
864                    }
865                }
866                EndTransaction();
867                return pInstrs;
868          } catch (Exception e) {          } catch (Exception e) {
869              DbInstrumentsMutex.Unlock();              EndTransaction();
870              throw e;              throw e;
871          }          }
872      }      }
# Line 633  namespace LinuxSampler { Line 886  namespace LinuxSampler {
886          std::stringstream sql;          std::stringstream sql;
887          sql << "SELECT instr_id FROM instruments WHERE dir_id=";          sql << "SELECT instr_id FROM instruments WHERE dir_id=";
888          sql << DirId << " AND instr_name=?";          sql << DirId << " AND instr_name=?";
889          return ExecSqlInt(sql.str(), InstrName);          return ExecSqlInt(sql.str(), toDbName(InstrName));
890        }
891    
892        String InstrumentsDb::GetInstrumentName(int InstrId) {
893            dmsg(2,("InstrumentsDb: GetInstrumentName(InstrId=%d)\n", InstrId));
894            std::stringstream sql;
895            sql << "SELECT instr_name FROM instruments WHERE instr_id=" << InstrId;
896            return toAbstractName(ExecSqlString(sql.str()));
897      }      }
898            
899      void InstrumentsDb::RemoveInstrument(String Instr) {      void InstrumentsDb::RemoveInstrument(String Instr) {
# Line 641  namespace LinuxSampler { Line 901  namespace LinuxSampler {
901          String ParentDir = GetDirectoryPath(Instr);          String ParentDir = GetDirectoryPath(Instr);
902          if(ParentDir.empty()) throw Exception("Unknown parent directory");          if(ParentDir.empty()) throw Exception("Unknown parent directory");
903                    
904          DbInstrumentsMutex.Lock();          BeginTransaction();
905          try {          try {
906              int instrId = GetInstrumentId(Instr);              int instrId = GetInstrumentId(Instr);
907              if(instrId == -1) {              if(instrId == -1) {
908                  throw Exception("The specified instrument does not exist: " + Instr);                  throw Exception("The specified instrument does not exist: " + toEscapedPath(Instr));
909              }              }
910              RemoveInstrument(instrId);              RemoveInstrument(instrId);
911          } catch (Exception e) {          } catch (Exception e) {
912              DbInstrumentsMutex.Unlock();              EndTransaction();
913              throw e;              throw e;
914          }          }
915          DbInstrumentsMutex.Unlock();          EndTransaction();
916          FireInstrumentCountChanged(ParentDir);          FireInstrumentCountChanged(ParentDir);
917      }      }
918    
# Line 677  namespace LinuxSampler { Line 937  namespace LinuxSampler {
937          dmsg(2,("InstrumentsDb: GetInstrumentInfo(Instr=%s)\n", Instr.c_str()));          dmsg(2,("InstrumentsDb: GetInstrumentInfo(Instr=%s)\n", Instr.c_str()));
938          DbInstrument i;          DbInstrument i;
939                    
940          DbInstrumentsMutex.Lock();          BeginTransaction();
941          try {          try {
942              int id = GetInstrumentId(Instr);              int id = GetInstrumentId(Instr);
943              if(id == -1) throw Exception("Unknown DB instrument: " + Instr);              if(id == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
944                i = GetInstrumentInfo(id);
945            } catch (Exception e) {
946                EndTransaction();
947                throw e;
948            }
949            EndTransaction();
950                    
951              sqlite3_stmt *pStmt = NULL;          return i;
952              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;  
953    
954              int res = sqlite3_prepare(GetDb(), sql.str().c_str(), -1, &pStmt, NULL);      DbInstrument InstrumentsDb::GetInstrumentInfo(int InstrId) {
955              if (res != SQLITE_OK) {          sqlite3_stmt *pStmt = NULL;
956                  throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));          std::stringstream sql;
957              }          sql << "SELECT instr_file,instr_nr,format_family,format_version,";
958            sql << "instr_size,created,modified,description,is_drum,product,";
959            sql << "artists,keywords FROM instruments WHERE instr_id=" << InstrId;
960    
961              res = sqlite3_step(pStmt);          int res = sqlite3_prepare(GetDb(), sql.str().c_str(), -1, &pStmt, NULL);
962              if(res == SQLITE_ROW) {          if (res != SQLITE_OK) {
963                  i.InstrFile = ToString(sqlite3_column_text(pStmt, 0));              throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
964                  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);  
                 }  
             }  
965    
966            DbInstrument i;
967            res = sqlite3_step(pStmt);
968            if(res == SQLITE_ROW) {
969                i.InstrFile = ToString(sqlite3_column_text(pStmt, 0));
970                i.InstrNr = sqlite3_column_int(pStmt, 1);
971                i.FormatFamily = ToString(sqlite3_column_text(pStmt, 2));
972                i.FormatVersion = ToString(sqlite3_column_text(pStmt, 3));
973                i.Size = sqlite3_column_int64(pStmt, 4);
974                i.Created = ToString(sqlite3_column_text(pStmt, 5));
975                i.Modified = ToString(sqlite3_column_text(pStmt, 6));
976                i.Description = ToString(sqlite3_column_text(pStmt, 7));
977                i.IsDrum = sqlite3_column_int(pStmt, 8);
978                i.Product = ToString(sqlite3_column_text(pStmt, 9));
979                i.Artists = ToString(sqlite3_column_text(pStmt, 10));
980                i.Keywords = ToString(sqlite3_column_text(pStmt, 11));
981            } else {
982              sqlite3_finalize(pStmt);              sqlite3_finalize(pStmt);
983          } catch (Exception e) {  
984              DbInstrumentsMutex.Unlock();              if (res != SQLITE_DONE) {
985              throw e;                  throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
986                } else {
987                    throw Exception("Unknown DB instrument");
988                }
989          }          }
990          DbInstrumentsMutex.Unlock();  
991                    sqlite3_finalize(pStmt);
992          return i;          return i;
993      }      }
994    
# Line 731  namespace LinuxSampler { Line 996  namespace LinuxSampler {
996          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()));
997          CheckFileName(Name);          CheckFileName(Name);
998    
999          DbInstrumentsMutex.Lock();          BeginTransaction();
1000          try {          try {
1001              int dirId = GetDirectoryId(GetDirectoryPath(Instr));              int dirId = GetDirectoryId(GetDirectoryPath(Instr));
1002              if (dirId == -1) throw Exception("Unknown DB instrument: " + Instr);              if (dirId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1003    
1004              int instrId = GetInstrumentId(dirId, GetFileName(Instr));              int instrId = GetInstrumentId(dirId, GetFileName(Instr));
1005              if (instrId == -1) throw Exception("Unknown DB instrument: " + Instr);              if (instrId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1006    
1007              if (GetInstrumentId(dirId, Name) != -1) {              if (GetInstrumentId(dirId, Name) != -1) {
1008                  throw Exception("Cannot rename. Instrument with that name already exists: " + Name);                  String s = toEscapedPath(Name);
1009                    throw Exception("Cannot rename. Instrument with that name already exists: " + s);
1010                }
1011    
1012                if (GetDirectoryId(dirId, Name) != -1) {
1013                    String s = toEscapedPath(Name);
1014                    throw Exception("Cannot rename. Directory with that name already exists: " + s);
1015              }              }
1016    
1017              std::stringstream sql;              std::stringstream sql;
1018              sql << "UPDATE instruments SET instr_name=? WHERE instr_id=" << instrId;              sql << "UPDATE instruments SET instr_name=? WHERE instr_id=" << instrId;
1019              ExecSql(sql.str(), Name);              ExecSql(sql.str(), toDbName(Name));
1020          } catch (Exception e) {          } catch (Exception e) {
1021              DbInstrumentsMutex.Unlock();              EndTransaction();
1022              throw e;              throw e;
1023          }          }
1024          DbInstrumentsMutex.Unlock();          EndTransaction();
1025          FireInstrumentNameChanged(Instr, Name);          FireInstrumentNameChanged(Instr, toAbstractName(Name));
1026      }      }
1027    
1028      void InstrumentsDb::MoveInstrument(String Instr, String Dst) {      void InstrumentsDb::MoveInstrument(String Instr, String Dst) {
# Line 759  namespace LinuxSampler { Line 1030  namespace LinuxSampler {
1030          String ParentDir = GetDirectoryPath(Instr);          String ParentDir = GetDirectoryPath(Instr);
1031          if(ParentDir.empty()) throw Exception("Unknown parent directory");          if(ParentDir.empty()) throw Exception("Unknown parent directory");
1032    
1033          DbInstrumentsMutex.Lock();          BeginTransaction();
1034          try {          try {
1035              int dirId = GetDirectoryId(GetDirectoryPath(Instr));              int dirId = GetDirectoryId(ParentDir);
1036              if (dirId == -1) throw Exception("Unknown DB instrument: " + Instr);              if (dirId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1037    
1038              String instrName = GetFileName(Instr);              String instrName = GetFileName(Instr);
1039              int instrId = GetInstrumentId(dirId, instrName);              int instrId = GetInstrumentId(dirId, instrName);
1040              if (instrId == -1) throw Exception("Unknown DB instrument: " + Instr);              if (instrId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1041    
1042              int dstId = GetDirectoryId(Dst);              int dstId = GetDirectoryId(Dst);
1043              if (dstId == -1) throw Exception("Unknown DB directory: " + Dst);              if (dstId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dst));
1044              if (dirId == dstId) {              if (dirId == dstId) {
1045                  DbInstrumentsMutex.Unlock();                  EndTransaction();
1046                  return;                  return;
1047              }              }
1048    
1049              if (GetInstrumentId(dstId, instrName) != -1) {              if (GetInstrumentId(dstId, instrName) != -1) {
1050                  throw Exception("Cannot move. Instrument with that name already exists: " + instrName);                  String s = toEscapedPath(instrName);
1051                    throw Exception("Cannot move. Instrument with that name already exists: " + s);
1052                }
1053    
1054                if (GetDirectoryId(dstId, instrName) != -1) {
1055                    String s = toEscapedPath(instrName);
1056                    throw Exception("Cannot move. Directory with that name already exists: " + s);
1057              }              }
1058    
1059              std::stringstream sql;              std::stringstream sql;
# Line 784  namespace LinuxSampler { Line 1061  namespace LinuxSampler {
1061              sql << " WHERE instr_id=" << instrId;              sql << " WHERE instr_id=" << instrId;
1062              ExecSql(sql.str());              ExecSql(sql.str());
1063          } catch (Exception e) {          } catch (Exception e) {
1064              DbInstrumentsMutex.Unlock();              EndTransaction();
1065              throw e;              throw e;
1066          }          }
1067          DbInstrumentsMutex.Unlock();          EndTransaction();
1068          FireInstrumentCountChanged(ParentDir);          FireInstrumentCountChanged(ParentDir);
1069          FireInstrumentCountChanged(Dst);          FireInstrumentCountChanged(Dst);
1070      }      }
1071    
1072        void InstrumentsDb::CopyInstrument(String Instr, String Dst) {
1073            dmsg(2,("InstrumentsDb: CopyInstrument(Instr=%s,Dst=%s)\n", Instr.c_str(), Dst.c_str()));
1074            String ParentDir = GetDirectoryPath(Instr);
1075            if(ParentDir.empty()) throw Exception("Unknown parent directory");
1076    
1077            BeginTransaction();
1078            try {
1079                int dirId = GetDirectoryId(GetDirectoryPath(Instr));
1080                if (dirId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1081    
1082                String instrName = GetFileName(Instr);
1083                int instrId = GetInstrumentId(dirId, instrName);
1084                if (instrId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1085    
1086                int dstId = GetDirectoryId(Dst);
1087                if (dstId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dst));
1088                if (dirId == dstId) {
1089                    EndTransaction();
1090                    return;
1091                }
1092    
1093                CopyInstrument(instrId, instrName, dstId, Dst);
1094            } catch (Exception e) {
1095                EndTransaction();
1096                throw e;
1097            }
1098            EndTransaction();
1099            
1100        }
1101    
1102        void InstrumentsDb::CopyInstrument(int InstrId, String InstrName, int DstDirId, String DstDir) {
1103            if (GetInstrumentId(DstDirId, InstrName) != -1) {
1104                String s = toEscapedPath(InstrName);
1105                throw Exception("Cannot copy. Instrument with that name already exists: " + s);
1106            }
1107    
1108            if (GetDirectoryId(DstDirId, InstrName) != -1) {
1109                String s = toEscapedPath(InstrName);
1110                throw Exception("Cannot copy. Directory with that name already exists: " + s);
1111            }
1112    
1113            DbInstrument i = GetInstrumentInfo(InstrId);
1114            sqlite3_stmt *pStmt = NULL;
1115            std::stringstream sql;
1116            sql << "INSERT INTO instruments (dir_id,instr_name,instr_file,instr_nr,format_family,";
1117            sql << "format_version,instr_size,description,is_drum,product,artists,keywords) ";
1118            sql << "VALUES (" << DstDirId << ",?,?," << i.InstrNr << ",?,?," << i.Size << ",?,";
1119            sql << i.IsDrum << ",?,?,?)";
1120    
1121            int res = sqlite3_prepare(GetDb(), sql.str().c_str(), -1, &pStmt, NULL);
1122            if (res != SQLITE_OK) {
1123                throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1124            }
1125    
1126            String s = toDbName(InstrName);
1127            BindTextParam(pStmt, 1, s);
1128            BindTextParam(pStmt, 2, i.InstrFile);
1129            BindTextParam(pStmt, 3, i.FormatFamily);
1130            BindTextParam(pStmt, 4, i.FormatVersion);
1131            BindTextParam(pStmt, 5, i.Description);
1132            BindTextParam(pStmt, 6, i.Product);
1133            BindTextParam(pStmt, 7, i.Artists);
1134            BindTextParam(pStmt, 8, i.Keywords);
1135    
1136            res = sqlite3_step(pStmt);
1137            if(res != SQLITE_DONE) {
1138                sqlite3_finalize(pStmt);
1139                throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1140            }
1141            
1142            sqlite3_finalize(pStmt);
1143            FireInstrumentCountChanged(DstDir);
1144        }
1145    
1146      void InstrumentsDb::SetInstrumentDescription(String Instr, String Desc) {      void InstrumentsDb::SetInstrumentDescription(String Instr, String Desc) {
1147          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()));
1148    
1149          DbInstrumentsMutex.Lock();          BeginTransaction();
1150          try {          try {
1151              int id = GetInstrumentId(Instr);              int id = GetInstrumentId(Instr);
1152              if(id == -1) throw Exception("Unknown DB instrument: " + Instr);              if(id == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1153    
1154              std::stringstream sql;              std::stringstream sql;
1155              sql << "UPDATE instruments SET description=?,modified=CURRENT_TIMESTAMP ";              sql << "UPDATE instruments SET description=?,modified=CURRENT_TIMESTAMP ";
# Line 806  namespace LinuxSampler { Line 1157  namespace LinuxSampler {
1157    
1158              ExecSql(sql.str(), Desc);              ExecSql(sql.str(), Desc);
1159          } catch (Exception e) {          } catch (Exception e) {
1160              DbInstrumentsMutex.Unlock();              EndTransaction();
1161              throw e;              throw e;
1162          }          }
1163          DbInstrumentsMutex.Unlock();          EndTransaction();
1164          FireInstrumentInfoChanged(Instr);          FireInstrumentInfoChanged(Instr);
1165      }      }
1166    
1167      void InstrumentsDb::AddInstrumentsFromFile(String DbDir, String File, int Index) {      void InstrumentsDb::AddInstrumentsFromFile(String DbDir, String File, int Index, ScanProgress* pProgress) {
1168          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));
1169                    
1170          if(File.length() < 4) return;          if(File.length() < 4) return;
1171                    
1172          try {          try {
1173              if(!strcasecmp(".gig", File.substr(File.length() - 4).c_str())) {              if(!strcasecmp(".gig", File.substr(File.length() - 4).c_str())) {
1174                  AddGigInstruments(DbDir, File, Index);                  if (pProgress != NULL) {
1175                        pProgress->SetStatus(0);
1176                        pProgress->CurrentFile = File;
1177                    }
1178    
1179                    AddGigInstruments(DbDir, File, Index, pProgress);
1180    
1181                    if (pProgress != NULL) {
1182                        pProgress->SetScannedFileCount(pProgress->GetScannedFileCount() + 1);
1183                    }
1184              }              }
1185          } catch(Exception e) {          } catch(Exception e) {
1186              std::cout << e.Message() << std::endl;              e.PrintMessage();
1187          }          }
1188      }      }
1189    
1190      void InstrumentsDb::AddGigInstruments(String DbDir, String File, int Index) {      void InstrumentsDb::AddGigInstruments(String DbDir, String FilePath, int Index, ScanProgress* pProgress) {
1191          dmsg(2,("InstrumentsDb: AddGigInstruments(DbDir=%s,File=%s,Index=%d)\n", DbDir.c_str(), File.c_str(), Index));          dmsg(2,("InstrumentsDb: AddGigInstruments(DbDir=%s,FilePath=%s,Index=%d)\n", DbDir.c_str(), FilePath.c_str(), Index));
1192          int dirId = GetDirectoryId(DbDir);          int dirId = GetDirectoryId(DbDir);
1193          if (dirId == -1) throw Exception("Invalid DB directory: " + DbDir);          if (dirId == -1) throw Exception("Invalid DB directory: " + toEscapedPath(DbDir));
1194    
1195          struct stat statBuf;          File f = File(FilePath);
1196          int res = stat(File.c_str(), &statBuf);          if (!f.Exist()) {
         if (res) {  
1197              std::stringstream ss;              std::stringstream ss;
1198              ss << "Fail to stat `" << File << "`: " << strerror(errno);              ss << "Fail to stat `" << FilePath << "`: " << f.GetErrorMsg();
1199              throw Exception(ss.str());              throw Exception(ss.str());
1200          }          }
1201    
1202          if (!S_ISREG(statBuf.st_mode)) {          if (!f.IsFile()) {
1203              std::stringstream ss;              std::stringstream ss;
1204              ss << "`" << File << "` is not a regular file";              ss << "`" << FilePath << "` is not a regular file";
1205              throw Exception(ss.str());              throw Exception(ss.str());
1206          }          }
1207    
1208          RIFF::File* riff = NULL;          RIFF::File* riff = NULL;
1209          gig::File* gig = NULL;          gig::File* gig = NULL;
1210          try {          try {
1211              riff = new RIFF::File(File);              riff = new RIFF::File(FilePath);
1212              gig::File* gig = new gig::File(riff);              gig::File* gig = new gig::File(riff);
1213                            gig->SetAutoLoad(false); // avoid time consuming samples scanning
1214    
1215              std::stringstream sql;              std::stringstream sql;
1216              sql << "INSERT INTO instruments (dir_id,instr_name,instr_file,";              sql << "INSERT INTO instruments (dir_id,instr_name,instr_file,";
1217              sql << "instr_nr,format_family,format_version,instr_size,";              sql << "instr_nr,format_family,format_version,instr_size,";
1218              sql << "description,is_drum,product,artists,keywords) VALUES (";              sql << "description,is_drum,product,artists,keywords) VALUES (";
1219              sql << dirId << ",?,?,?,'GIG',?," << statBuf.st_size << ",?,?,?,?,?)";              sql << dirId << ",?,?,?,'GIG',?," << f.GetSize() << ",?,?,?,?,?)";
1220    
1221              sqlite3_stmt* pStmt = NULL;              sqlite3_stmt* pStmt = NULL;
1222    
# Line 865  namespace LinuxSampler { Line 1225  namespace LinuxSampler {
1225                  throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));                  throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1226              }              }
1227    
1228              BindTextParam(pStmt, 2, File);              String s = toEscapedFsPath(FilePath);
1229                BindTextParam(pStmt, 2, s);
1230              String ver = "";              String ver = "";
1231              if (gig->pVersion != NULL) ver = ToString(gig->pVersion->major);              if (gig->pVersion != NULL) ver = ToString(gig->pVersion->major);
1232              BindTextParam(pStmt, 4, ver);              BindTextParam(pStmt, 4, ver);
1233    
1234              if (Index == -1) {              if (Index == -1) {
1235                  int instrIndex = 0;                  int instrIndex = 0;
1236                    if (pProgress != NULL) gig->GetInstrument(0, &(pProgress->GigFileProgress)); // TODO: this workaround should be fixed
1237                  gig::Instrument* pInstrument = gig->GetFirstInstrument();                  gig::Instrument* pInstrument = gig->GetFirstInstrument();
1238                  while (pInstrument) {                  while (pInstrument) {
1239                      BindTextParam(pStmt, 7, gig->pInfo->Product);                      BindTextParam(pStmt, 7, gig->pInfo->Product);
1240                      BindTextParam(pStmt, 8, gig->pInfo->Artists);                      BindTextParam(pStmt, 8, gig->pInfo->Artists);
1241                      BindTextParam(pStmt, 9, gig->pInfo->Keywords);                      BindTextParam(pStmt, 9, gig->pInfo->Keywords);
1242                      AddGigInstrument(pStmt, DbDir, dirId, File, pInstrument, instrIndex);                      AddGigInstrument(pStmt, DbDir, dirId, FilePath, pInstrument, instrIndex);
1243    
1244                      instrIndex++;                      instrIndex++;
1245                      pInstrument = gig->GetNextInstrument();                      pInstrument = gig->GetNextInstrument();
1246                  }                  }
1247              } else {              } else {
1248                  gig::Instrument* pInstrument = gig->GetInstrument(Index);                  gig::Instrument* pInstrument;
1249                    if (pProgress == NULL) pInstrument = gig->GetInstrument(Index);
1250                    else pInstrument = gig->GetInstrument(Index, &(pProgress->GigFileProgress));
1251                  if (pInstrument != NULL) {                  if (pInstrument != NULL) {
1252                      BindTextParam(pStmt, 7, gig->pInfo->Product);                      BindTextParam(pStmt, 7, gig->pInfo->Product);
1253                      BindTextParam(pStmt, 8, gig->pInfo->Artists);                      BindTextParam(pStmt, 8, gig->pInfo->Artists);
1254                      BindTextParam(pStmt, 9, gig->pInfo->Keywords);                      BindTextParam(pStmt, 9, gig->pInfo->Keywords);
1255                      AddGigInstrument(pStmt, DbDir, dirId, File, pInstrument, Index);                      AddGigInstrument(pStmt, DbDir, dirId, FilePath, pInstrument, Index);
1256                  }                  }
1257              }              }
1258    
1259                sqlite3_finalize(pStmt);
1260              delete gig;              delete gig;
1261              delete riff;              delete riff;
1262          } catch (RIFF::Exception e) {          } catch (RIFF::Exception e) {
1263              if (gig != NULL) delete gig;              if (gig != NULL) delete gig;
1264              if (riff != NULL) delete riff;              if (riff != NULL) delete riff;
1265              std::stringstream ss;              std::stringstream ss;
1266              ss << "Failed to scan `" << File << "`: " << e.Message;              ss << "Failed to scan `" << FilePath << "`: " << e.Message;
1267                            
1268              throw Exception(ss.str());              throw Exception(ss.str());
1269          } catch (Exception e) {          } catch (Exception e) {
# Line 908  namespace LinuxSampler { Line 1273  namespace LinuxSampler {
1273          } catch (...) {          } catch (...) {
1274              if (gig != NULL) delete gig;              if (gig != NULL) delete gig;
1275              if (riff != NULL) delete riff;              if (riff != NULL) delete riff;
1276              throw Exception("Failed to scan `" + File + "`");              throw Exception("Failed to scan `" + FilePath + "`");
1277          }          }
1278      }      }
1279    
1280      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) {
1281            dmsg(2,("InstrumentsDb: AddGigInstrument(DbDir=%s,DirId=%d,File=%s,Index=%d)\n", DbDir.c_str(), DirId, File.c_str(), Index));
1282          String name = pInstrument->pInfo->Name;          String name = pInstrument->pInfo->Name;
1283          if (name == "") return;          if (name == "") return;
1284          name = GetUniqueInstrumentName(DirId, name);          name = GetUniqueInstrumentName(DirId, name);
# Line 920  namespace LinuxSampler { Line 1286  namespace LinuxSampler {
1286          std::stringstream sql2;          std::stringstream sql2;
1287          sql2 << "SELECT COUNT(*) FROM instruments WHERE instr_file=? AND ";          sql2 << "SELECT COUNT(*) FROM instruments WHERE instr_file=? AND ";
1288          sql2 << "instr_nr=" << Index;          sql2 << "instr_nr=" << Index;
1289          if (ExecSqlInt(sql2.str(), File) > 0) return;          String s = toEscapedFsPath(File);
1290            if (ExecSqlInt(sql2.str(), s) > 0) return;
1291    
1292          BindTextParam(pStmt, 1, name);          BindTextParam(pStmt, 1, name);
1293          BindIntParam(pStmt, 3, Index);          BindIntParam(pStmt, 3, Index);
# Line 949  namespace LinuxSampler { Line 1316  namespace LinuxSampler {
1316          FireInstrumentCountChanged(DbDir);          FireInstrumentCountChanged(DbDir);
1317      }      }
1318    
1319      void InstrumentsDb::ExecSql(String Sql) {      void InstrumentsDb::DirectoryTreeWalk(String AbstractPath, DirectoryHandler* pHandler) {
1320          dmsg(2,("InstrumentsDb: ExecSql(Sql=%s)\n", Sql.c_str()));          int DirId = GetDirectoryId(AbstractPath);
1321            if(DirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(AbstractPath));
1322            DirectoryTreeWalk(pHandler, AbstractPath, DirId, 0);
1323        }
1324    
1325        void InstrumentsDb::DirectoryTreeWalk(DirectoryHandler* pHandler, String AbstractPath, int DirId, int Level) {
1326            if(Level == 1000) throw Exception("Possible infinite loop detected");
1327            pHandler->ProcessDirectory(AbstractPath, DirId);
1328            
1329            String s;
1330            StringListPtr pDirs = GetDirectories(DirId);
1331            for(int i = 0; i < pDirs->size(); i++) {
1332                if (AbstractPath.length() == 1 && AbstractPath.at(0) == '/') {
1333                    s = "/" + pDirs->at(i);
1334                } else {
1335                    s = AbstractPath + "/" + pDirs->at(i);
1336                }
1337                DirectoryTreeWalk(pHandler, s, GetDirectoryId(DirId, pDirs->at(i)), Level + 1);
1338            }
1339        }
1340    
1341        StringListPtr InstrumentsDb::FindDirectories(String Dir, SearchQuery* pQuery, bool Recursive) {
1342            dmsg(2,("InstrumentsDb: FindDirectories(Dir=%s)\n", Dir.c_str()));
1343            DirectoryFinder directoryFinder(pQuery);
1344            
1345            BeginTransaction();
1346            try {
1347                int DirId = GetDirectoryId(Dir);
1348                if(DirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
1349    
1350                if (Recursive) DirectoryTreeWalk(Dir, &directoryFinder);
1351                else directoryFinder.ProcessDirectory(Dir, DirId);
1352            } catch (Exception e) {
1353                EndTransaction();
1354                throw e;
1355            }
1356            EndTransaction();
1357    
1358            return directoryFinder.GetDirectories();
1359        }
1360    
1361        StringListPtr InstrumentsDb::FindInstruments(String Dir, SearchQuery* pQuery, bool Recursive) {
1362            dmsg(2,("InstrumentsDb: FindInstruments(Dir=%s)\n", Dir.c_str()));
1363            InstrumentFinder instrumentFinder(pQuery);
1364            
1365            BeginTransaction();
1366            try {
1367                int DirId = GetDirectoryId(Dir);
1368                if(DirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
1369    
1370                if (Recursive) DirectoryTreeWalk(Dir, &instrumentFinder);
1371                else instrumentFinder.ProcessDirectory(Dir, DirId);
1372            } catch (Exception e) {
1373                EndTransaction();
1374                throw e;
1375            }
1376            EndTransaction();
1377    
1378            return instrumentFinder.GetInstruments();
1379        }
1380        
1381        StringListPtr InstrumentsDb::FindLostInstrumentFiles() {
1382            dmsg(2,("InstrumentsDb: FindLostInstrumentFiles()\n"));
1383    
1384            BeginTransaction();
1385            try {
1386                StringListPtr files = ExecSqlStringList("SELECT DISTINCT instr_file FROM instruments");
1387                StringListPtr result(new std::vector<String>);
1388                for (int i = 0; i < files->size(); i++) {
1389                    File f(toNonEscapedFsPath(files->at(i)));
1390                    if (!f.Exist()) result->push_back(files->at(i));
1391                }
1392                return result;
1393            } catch (Exception e) {
1394                EndTransaction();
1395                throw e;
1396            }
1397            EndTransaction();
1398        }
1399        
1400        void InstrumentsDb::SetInstrumentFilePath(String OldPath, String NewPath) {
1401            if (OldPath == NewPath) return;
1402            StringListPtr instrs;
1403            BeginTransaction();
1404            try {
1405                std::vector<String> params(2);
1406                params[0] = toEscapedFsPath(NewPath);
1407                params[1] = toEscapedFsPath(OldPath);
1408                instrs = GetInstrumentsByFile(OldPath);
1409                ExecSql("UPDATE instruments SET instr_file=? WHERE instr_file=?", params);
1410            } catch (Exception e) {
1411                EndTransaction();
1412                throw e;
1413            }
1414            EndTransaction();
1415            
1416            for (int i = 0; i < instrs->size(); i++) {
1417                FireInstrumentInfoChanged(instrs->at(i));
1418            }
1419        }
1420    
1421        void InstrumentsDb::BeginTransaction() {
1422            dmsg(2,("InstrumentsDb: BeginTransaction(InTransaction=%d)\n", InTransaction));
1423            DbInstrumentsMutex.Lock();
1424            if (InTransaction) return;
1425            
1426            if(db == NULL) return;
1427          sqlite3_stmt *pStmt = NULL;          sqlite3_stmt *pStmt = NULL;
1428                    
1429          int res = sqlite3_prepare(GetDb(), Sql.c_str(), -1, &pStmt, NULL);          InTransaction = true;
1430            int res = sqlite3_prepare(db, "BEGIN TRANSACTION", -1, &pStmt, NULL);
1431          if (res != SQLITE_OK) {          if (res != SQLITE_OK) {
1432              throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));              std::cerr << ToString(sqlite3_errmsg(db)) << std::endl;
1433                return;
1434          }          }
1435                    
1436          res = sqlite3_step(pStmt);          res = sqlite3_step(pStmt);
1437          if(res != SQLITE_DONE) {          if(res != SQLITE_DONE) {
1438              sqlite3_finalize(pStmt);              sqlite3_finalize(pStmt);
1439              throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));              std::cerr << ToString(sqlite3_errmsg(db)) << std::endl;
1440                return;
1441          }          }
1442    
1443          sqlite3_finalize(pStmt);          sqlite3_finalize(pStmt);
1444      }      }
1445    
1446        void InstrumentsDb::EndTransaction() {
1447            dmsg(2,("InstrumentsDb: EndTransaction(InTransaction=%d)\n", InTransaction));
1448            if (!InTransaction) {
1449                DbInstrumentsMutex.Unlock();
1450                return;
1451            }
1452            InTransaction = false;
1453            
1454            if(db == NULL) {
1455                DbInstrumentsMutex.Unlock();
1456                return;
1457            }
1458            sqlite3_stmt *pStmt = NULL;
1459            
1460            int res = sqlite3_prepare(db, "END TRANSACTION", -1, &pStmt, NULL);
1461            if (res != SQLITE_OK) {
1462                std::cerr << ToString(sqlite3_errmsg(db)) << std::endl;
1463                DbInstrumentsMutex.Unlock();
1464                return;
1465            }
1466            
1467            res = sqlite3_step(pStmt);
1468            if(res != SQLITE_DONE) {
1469                sqlite3_finalize(pStmt);
1470                std::cerr << ToString(sqlite3_errmsg(db)) << std::endl;
1471                DbInstrumentsMutex.Unlock();
1472                return;
1473            }
1474    
1475            sqlite3_finalize(pStmt);
1476            DbInstrumentsMutex.Unlock();
1477        }
1478    
1479        void InstrumentsDb::ExecSql(String Sql) {
1480            dmsg(2,("InstrumentsDb: ExecSql(Sql=%s)\n", Sql.c_str()));
1481            std::vector<String> Params;
1482            ExecSql(Sql, Params);
1483        }
1484    
1485      void InstrumentsDb::ExecSql(String Sql, String Param) {      void InstrumentsDb::ExecSql(String Sql, String Param) {
1486          dmsg(2,("InstrumentsDb: ExecSql(Sql=%s,Param=%s)\n", Sql.c_str(), Param.c_str()));          dmsg(2,("InstrumentsDb: ExecSql(Sql=%s,Param=%s)\n", Sql.c_str(), Param.c_str()));
1487            std::vector<String> Params;
1488            Params.push_back(Param);
1489            ExecSql(Sql, Params);
1490        }
1491    
1492        void InstrumentsDb::ExecSql(String Sql, std::vector<String>& Params) {
1493            dmsg(2,("InstrumentsDb: ExecSql(Sql=%s,Params)\n", Sql.c_str()));
1494          sqlite3_stmt *pStmt = NULL;          sqlite3_stmt *pStmt = NULL;
1495                    
1496          int res = sqlite3_prepare(GetDb(), Sql.c_str(), -1, &pStmt, NULL);          int res = sqlite3_prepare(GetDb(), Sql.c_str(), -1, &pStmt, NULL);
# Line 977  namespace LinuxSampler { Line 1499  namespace LinuxSampler {
1499              throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));              throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1500          }          }
1501    
1502          BindTextParam(pStmt, 1, Param);          for(int i = 0; i < Params.size(); i++) {
1503                BindTextParam(pStmt, i + 1, Params[i]);
1504            }
1505    
1506          res = sqlite3_step(pStmt);          res = sqlite3_step(pStmt);
1507          if (res != SQLITE_DONE) {          if (res != SQLITE_DONE) {
# Line 1059  namespace LinuxSampler { Line 1583  namespace LinuxSampler {
1583      }      }
1584    
1585      IntListPtr InstrumentsDb::ExecSqlIntList(String Sql) {      IntListPtr InstrumentsDb::ExecSqlIntList(String Sql) {
1586            dmsg(2,("InstrumentsDb: ExecSqlIntList(Sql=%s)\n", Sql.c_str()));
1587            std::vector<String> Params;
1588            return ExecSqlIntList(Sql, Params);
1589        }
1590    
1591        IntListPtr InstrumentsDb::ExecSqlIntList(String Sql, String Param) {
1592            dmsg(2,("InstrumentsDb: ExecSqlIntList(Sql=%s,Param=%s)\n", Sql.c_str(), Param.c_str()));
1593            std::vector<String> Params;
1594            Params.push_back(Param);
1595            return ExecSqlIntList(Sql, Params);
1596        }
1597    
1598        IntListPtr InstrumentsDb::ExecSqlIntList(String Sql, std::vector<String>& Params) {
1599            dmsg(2,("InstrumentsDb: ExecSqlIntList(Sql=%s)\n", Sql.c_str()));
1600          IntListPtr intList(new std::vector<int>);          IntListPtr intList(new std::vector<int>);
1601                    
1602          sqlite3_stmt *pStmt = NULL;          sqlite3_stmt *pStmt = NULL;
# Line 1068  namespace LinuxSampler { Line 1606  namespace LinuxSampler {
1606              throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));              throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1607          }          }
1608                    
1609            for(int i = 0; i < Params.size(); i++) {
1610                BindTextParam(pStmt, i + 1, Params[i]);
1611            }
1612            
1613          res = sqlite3_step(pStmt);          res = sqlite3_step(pStmt);
1614          while(res == SQLITE_ROW) {          while(res == SQLITE_ROW) {
1615              intList->push_back(sqlite3_column_int(pStmt, 0));              intList->push_back(sqlite3_column_int(pStmt, 0));
# Line 1085  namespace LinuxSampler { Line 1627  namespace LinuxSampler {
1627      }      }
1628            
1629      StringListPtr InstrumentsDb::ExecSqlStringList(String Sql) {      StringListPtr InstrumentsDb::ExecSqlStringList(String Sql) {
1630            dmsg(2,("InstrumentsDb: ExecSqlStringList(Sql=%s)\n", Sql.c_str()));
1631          StringListPtr stringList(new std::vector<String>);          StringListPtr stringList(new std::vector<String>);
1632                    
1633          sqlite3_stmt *pStmt = NULL;          sqlite3_stmt *pStmt = NULL;
# Line 1128  namespace LinuxSampler { Line 1671  namespace LinuxSampler {
1671          }          }
1672      }      }
1673    
1674        void InstrumentsDb::Regexp(sqlite3_context* pContext, int argc, sqlite3_value** ppValue) {
1675            if (argc != 2) return;
1676    
1677            String pattern = ToString(sqlite3_value_text(ppValue[0]));
1678            String str = ToString(sqlite3_value_text(ppValue[1]));
1679    
1680            if(!fnmatch(pattern.c_str(), str.c_str(), FNM_CASEFOLD)) {
1681                sqlite3_result_int(pContext, 1);
1682            }
1683        }
1684    
1685      String InstrumentsDb::GetDirectoryPath(String File) {      String InstrumentsDb::GetDirectoryPath(String File) {
1686          if (File.empty()) return String("");          if (File.empty()) return String("");
1687          if (File.at(0) != '/') String("");          if (File.at(0) != '/') String("");
# Line 1169  namespace LinuxSampler { Line 1723  namespace LinuxSampler {
1723          return Dir.substr(0, i);          return Dir.substr(0, i);
1724      }      }
1725    
1726        void InstrumentsDb::Format() {
1727            DbInstrumentsMutex.Lock();
1728            if (db != NULL) {
1729                sqlite3_close(db);
1730                db = NULL;
1731            }
1732    
1733            if (DbFile.empty()) DbFile = CONFIG_DEFAULT_INSTRUMENTS_DB_LOCATION;
1734            String bkp = DbFile + ".bkp";
1735            remove(bkp.c_str());
1736            if (rename(DbFile.c_str(), bkp.c_str()) && errno != ENOENT) {
1737                DbInstrumentsMutex.Unlock();
1738                throw Exception(String("Failed to backup database: ") + strerror(errno));
1739            }
1740            
1741            String f = DbFile;
1742            DbFile = "";
1743            try { CreateInstrumentsDb(f); }
1744            catch(Exception e) {
1745                DbInstrumentsMutex.Unlock();
1746                throw e;
1747            }
1748            DbInstrumentsMutex.Unlock();
1749            
1750            FireDirectoryCountChanged("/");
1751            FireInstrumentCountChanged("/");
1752        }
1753    
1754      void InstrumentsDb::CheckFileName(String File) {      void InstrumentsDb::CheckFileName(String File) {
1755          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);  
         }  
1756      }      }
1757    
1758      String InstrumentsDb::GetUniqueInstrumentName(int DirId, String Name) {      String InstrumentsDb::GetUniqueInstrumentName(int DirId, String Name) {
1759          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=?";  
1760    
1761          if (ExecSqlInt(sql.str(), Name) == 0) return Name;          if (GetInstrumentId(DirId, Name) == -1 && GetDirectoryId(DirId, Name) == -1) return Name;
1762          std::stringstream ss;          std::stringstream ss;
1763          for(int i = 2; i < 1001; i++) {          for(int i = 2; i < 1001; i++) {
1764              ss.str("");              ss.str("");
1765              ss << Name << '[' << i << ']';              ss << Name << '[' << i << ']';
1766              if (ExecSqlInt(sql.str(), ss.str()) == 0) return ss.str();              if (GetInstrumentId(DirId, ss.str()) == -1 && GetInstrumentId(DirId, ss.str()) == -1) {
1767                    return ss.str();
1768                }
1769          }          }
1770    
1771          throw Exception("Unable to find an unique name: " + Name);          throw Exception("Unable to find an unique name: " + Name);
1772      }      }
1773    
1774        String InstrumentsDb::toDbName(String AbstractName) {
1775            for (int i = 0; i < AbstractName.length(); i++) {
1776                if (AbstractName.at(i) == '\0') AbstractName.at(i) = '/';
1777            }
1778            return AbstractName;
1779        }
1780    
1781        String InstrumentsDb::toEscapedPath(String AbstractName) {
1782            for (int i = 0; i < AbstractName.length(); i++) {
1783                if (AbstractName.at(i) == '\0')      AbstractName.replace(i++, 1, "\\x2f");
1784                else if (AbstractName.at(i) == '\\') AbstractName.replace(i++, 1, "\\\\");
1785                else if (AbstractName.at(i) == '\'') AbstractName.replace(i++, 1, "\\'");
1786                else if (AbstractName.at(i) == '"')  AbstractName.replace(i++, 1, "\\\"");
1787                else if (AbstractName.at(i) == '\r') AbstractName.replace(i++, 1, "\\r");
1788                else if (AbstractName.at(i) == '\n') AbstractName.replace(i++, 1, "\\n");
1789            }
1790            return AbstractName;
1791        }
1792            
1793        String InstrumentsDb::toEscapedText(String text) {
1794            for (int i = 0; i < text.length(); i++) {
1795                if (text.at(i) == '\\')      text.replace(i++, 1, "\\\\");
1796                else if (text.at(i) == '\'') text.replace(i++, 1, "\\'");
1797                else if (text.at(i) == '"')  text.replace(i++, 1, "\\\"");
1798                else if (text.at(i) == '\r') text.replace(i++, 1, "\\r");
1799                else if (text.at(i) == '\n') text.replace(i++, 1, "\\n");
1800            }
1801            return text;
1802        }
1803        
1804        String InstrumentsDb::toNonEscapedText(String text) {
1805            String sb;
1806            for (int i = 0; i < text.length(); i++) {
1807                char c = text.at(i);
1808                            if(c == '\\') {
1809                                    if(i >= text.length()) {
1810                                            std::cerr << "Broken escape sequence!" << std::endl;
1811                                            break;
1812                                    }
1813                                    char c2 = text.at(++i);
1814                                    if(c2 == '\'')      sb.push_back('\'');
1815                                    else if(c2 == '"')  sb.push_back('"');
1816                                    else if(c2 == '\\') sb.push_back('\\');
1817                                    else if(c2 == 'r')  sb.push_back('\r');
1818                                    else if(c2 == 'n')  sb.push_back('\n');
1819                                    else std::cerr << "Unknown escape sequence \\" << c2 << std::endl;
1820                            } else {
1821                                    sb.push_back(c);
1822                            }
1823            }
1824            return sb;
1825        }
1826        
1827        String InstrumentsDb::toEscapedFsPath(String FsPath) {
1828            return toEscapedText(FsPath);
1829        }
1830        
1831        String InstrumentsDb::toNonEscapedFsPath(String FsPath) {
1832            return toNonEscapedText(FsPath);
1833        }
1834        
1835        String InstrumentsDb::toAbstractName(String DbName) {
1836            for (int i = 0; i < DbName.length(); i++) {
1837                if (DbName.at(i) == '/') DbName.at(i) = '\0';
1838            }
1839            return DbName;
1840        }
1841    
1842      void InstrumentsDb::FireDirectoryCountChanged(String Dir) {      void InstrumentsDb::FireDirectoryCountChanged(String Dir) {
1843          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1844              llInstrumentsDbListeners.GetListener(i)->DirectoryCountChanged(Dir);              llInstrumentsDbListeners.GetListener(i)->DirectoryCountChanged(Dir);
1845          }          }
1846      }      }
1847        
1848      void InstrumentsDb::FireDirectoryInfoChanged(String Dir) {      void InstrumentsDb::FireDirectoryInfoChanged(String Dir) {
1849          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1850              llInstrumentsDbListeners.GetListener(i)->DirectoryInfoChanged(Dir);              llInstrumentsDbListeners.GetListener(i)->DirectoryInfoChanged(Dir);
1851          }          }
1852      }      }
1853        
1854      void InstrumentsDb::FireDirectoryNameChanged(String Dir, String NewName) {      void InstrumentsDb::FireDirectoryNameChanged(String Dir, String NewName) {
1855          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1856              llInstrumentsDbListeners.GetListener(i)->DirectoryNameChanged(Dir, NewName);              llInstrumentsDbListeners.GetListener(i)->DirectoryNameChanged(Dir, NewName);
1857          }          }
1858      }      }
1859        
1860      void InstrumentsDb::FireInstrumentCountChanged(String Dir) {      void InstrumentsDb::FireInstrumentCountChanged(String Dir) {
1861          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1862              llInstrumentsDbListeners.GetListener(i)->InstrumentCountChanged(Dir);              llInstrumentsDbListeners.GetListener(i)->InstrumentCountChanged(Dir);
1863          }          }
1864      }      }
1865        
1866      void InstrumentsDb::FireInstrumentInfoChanged(String Instr) {      void InstrumentsDb::FireInstrumentInfoChanged(String Instr) {
1867          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1868              llInstrumentsDbListeners.GetListener(i)->InstrumentInfoChanged(Instr);              llInstrumentsDbListeners.GetListener(i)->InstrumentInfoChanged(Instr);
1869          }          }
1870      }      }
1871        
1872      void InstrumentsDb::FireInstrumentNameChanged(String Instr, String NewName) {      void InstrumentsDb::FireInstrumentNameChanged(String Instr, String NewName) {
1873          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1874              llInstrumentsDbListeners.GetListener(i)->InstrumentNameChanged(Instr, NewName);              llInstrumentsDbListeners.GetListener(i)->InstrumentNameChanged(Instr, NewName);
1875          }          }
1876      }      }
       
   
     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());  
         }  
1877    
1878          if (!S_ISDIR(statBuf.st_mode)) {      void InstrumentsDb::FireJobStatusChanged(int JobId) {
1879              throw Exception("Directory expected");          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1880          }              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("/");  
1881          }          }
         DirectoryScanner::Flat = Flat;  
           
         ftw(FsDir.c_str(), FtwCallback, 10);  
1882      }      }
1883    
     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;  
     };  
   
1884  } // namespace LinuxSampler  } // namespace LinuxSampler
   
 #endif // HAVE_SQLITE3  

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

  ViewVC Help
Powered by ViewVC