/[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 1187 by iliev, Wed May 16 14:22:26 2007 UTC revision 1727 by iliev, Tue Apr 29 15:44:09 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 <fnmatch.h>  #include <fnmatch.h>
31  #include <ftw.h>  
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;  
     }  
   
   
     void DbDirectory::Copy(const DbDirectory& Dir) {  
         if (this == &Dir) return;  
   
         Created = Dir.Created;  
         Modified = Dir.Modified;  
         Description = Dir.Description;  
     }  
   
     SearchQuery::SearchQuery() {  
         MinSize = -1;  
         MaxSize = -1;  
         InstrType = BOTH;  
     }  
   
     void SearchQuery::SetFormatFamilies(String s) {  
         if (s.length() == 0) return;  
         int i = 0;  
         int j = s.find(',', 0);  
           
         while (j != std::string::npos) {  
             FormatFamilies.push_back(s.substr(i, j - i));  
             i = j + 1;  
             j = s.find(',', i);  
         }  
           
         if (i < s.length()) FormatFamilies.push_back(s.substr(i));  
     }  
   
     void SearchQuery::SetSize(String s) {  
         String s2 = GetMin(s);  
         if (s2.length() > 0) MinSize = atoll(s2.c_str());  
         else MinSize = -1;  
           
         s2 = GetMax(s);  
         if (s2.length() > 0) MaxSize = atoll(s2.c_str());  
         else MaxSize = -1;  
     }  
   
     void SearchQuery::SetCreated(String s) {  
         CreatedAfter = GetMin(s);  
         CreatedBefore = GetMax(s);  
     }  
   
     void SearchQuery::SetModified(String s) {  
         ModifiedAfter = GetMin(s);  
         ModifiedBefore = GetMax(s);  
     }  
   
     String SearchQuery::GetMin(String s) {  
         if (s.length() < 3) return "";  
         if (s.at(0) == '.' && s.at(1) == '.') return "";  
         int i = s.find("..");  
         if (i == std::string::npos) return "";  
         return s.substr(0, i);  
     }  
   
     String SearchQuery::GetMax(String s) {  
         if (s.length() < 3) return "";  
         if (s.find("..", s.length() - 2) != std::string::npos) return "";  
         int i = s.find("..");  
         if (i == std::string::npos) return "";  
         return s.substr(i + 2);  
     }  
       
     bool InstrumentsDb::AbstractFinder::IsRegex(String Pattern) {  
         if(Pattern.find('?') != String::npos) return true;  
         if(Pattern.find('*') != String::npos) return true;  
         return false;  
     }  
   
     void InstrumentsDb::AbstractFinder::AddSql(String Col, String Pattern, std::stringstream& Sql) {  
         if (Pattern.length() == 0) return;  
   
         if (IsRegex(Pattern)) {  
             Sql << " AND " << Col << " regexp ?";  
             Params.push_back(Pattern);  
             return;  
         }  
   
         String buf;  
         std::vector<String> tokens;  
         std::vector<String> tokens2;  
         std::stringstream ss(Pattern);  
         while (ss >> buf) tokens.push_back(buf);  
   
         if (tokens.size() == 0) {  
             Sql << " AND " << Col << " LIKE ?";  
             Params.push_back("%" + Pattern + "%");  
             return;  
         }  
   
         bool b = false;  
         for (int i = 0; i < tokens.size(); i++) {  
             Sql << (i == 0 ? " AND (" : "");  
   
             for (int j = 0; j < tokens.at(i).length(); j++) {  
                 if (tokens.at(i).at(j) == '+') tokens.at(i).at(j) = ' ';  
             }  
   
             ss.clear();  
             ss.str("");  
             ss << tokens.at(i);  
   
             tokens2.clear();  
             while (ss >> buf) tokens2.push_back(buf);  
   
             if (b && tokens2.size() > 0) Sql << " OR ";  
             if (tokens2.size() > 1) Sql << "(";  
             for (int j = 0; j < tokens2.size(); j++) {  
                 if (j != 0) Sql << " AND ";  
                 Sql << Col << " LIKE ?";  
                 Params.push_back("%" + tokens2.at(j) + "%");  
                 b = true;  
             }  
             if (tokens2.size() > 1) Sql << ")";  
         }  
         if (!b) Sql << "0)";  
         else Sql << ")";  
     }  
   
     InstrumentsDb::DirectoryFinder::DirectoryFinder(SearchQuery* pQuery) : pDirectories(new std::vector<String>) {  
         pStmt = NULL;  
         this->pQuery = pQuery;  
         std::stringstream sql;  
         sql << "SELECT dir_name from instr_dirs WHERE parent_dir_id=?";  
   
         if (pQuery->CreatedAfter.length() != 0) {  
             sql << " AND created > ?";  
             Params.push_back(pQuery->CreatedAfter);  
         }  
         if (pQuery->CreatedBefore.length() != 0) {  
             sql << " AND created < ?";  
             Params.push_back(pQuery->CreatedBefore);  
         }  
         if (pQuery->ModifiedAfter.length() != 0) {  
             sql << " AND modified > ?";  
             Params.push_back(pQuery->ModifiedAfter);  
         }  
         if (pQuery->ModifiedBefore.length() != 0) {  
             sql << " AND modified < ?";  
             Params.push_back(pQuery->ModifiedBefore);  
         }  
   
         AddSql("dir_name", pQuery->Name, sql);  
         AddSql("description", pQuery->Description, sql);  
         SqlQuery = sql.str();  
   
         InstrumentsDb* idb = InstrumentsDb::GetInstrumentsDb();  
   
         int res = sqlite3_prepare(idb->GetDb(), SqlQuery.c_str(), -1, &pStmt, NULL);  
         if (res != SQLITE_OK) {  
             throw Exception("DB error: " + ToString(sqlite3_errmsg(idb->GetDb())));  
         }  
   
         for(int i = 0; i < Params.size(); i++) {  
             idb->BindTextParam(pStmt, i + 2, Params.at(i));  
         }  
     }  
       
     InstrumentsDb::DirectoryFinder::~DirectoryFinder() {  
         if (pStmt != NULL) sqlite3_finalize(pStmt);  
     }  
   
     StringListPtr InstrumentsDb::DirectoryFinder::GetDirectories() {  
         return pDirectories;  
     }  
       
     void InstrumentsDb::DirectoryFinder::ProcessDirectory(String Path, int DirId) {  
         InstrumentsDb* idb = InstrumentsDb::GetInstrumentsDb();  
         idb->BindIntParam(pStmt, 1, DirId);  
37    
38          String s = Path;      void InstrumentsDb::CreateInstrumentsDb(String FilePath) {
39          if(Path.compare("/") != 0) s += "/";          File f = File(FilePath);
40          int res = sqlite3_step(pStmt);          if (f.Exist()) {
41          while(res == SQLITE_ROW) {              throw Exception("File exists: " + FilePath);
             pDirectories->push_back(s + ToString(sqlite3_column_text(pStmt, 0)));  
             res = sqlite3_step(pStmt);  
42          }          }
43                    
44          if (res != SQLITE_DONE) {          GetInstrumentsDb()->SetDbFile(FilePath);
             sqlite3_finalize(pStmt);  
             throw Exception("DB error: " + ToString(sqlite3_errmsg(idb->GetDb())));  
         }  
   
         res = sqlite3_reset(pStmt);  
         if (res != SQLITE_OK) {  
             sqlite3_finalize(pStmt);  
             throw Exception("DB error: " + ToString(sqlite3_errmsg(idb->GetDb())));  
         }  
     }  
   
     InstrumentsDb::InstrumentFinder::InstrumentFinder(SearchQuery* pQuery) : pInstruments(new std::vector<String>) {  
         pStmt = NULL;  
         this->pQuery = pQuery;  
         std::stringstream sql;  
         sql << "SELECT instr_name from instruments WHERE dir_id=?";  
   
         if (pQuery->CreatedAfter.length() != 0) {  
             sql << " AND created > ?";  
             Params.push_back(pQuery->CreatedAfter);  
         }  
         if (pQuery->CreatedBefore.length() != 0) {  
             sql << " AND created < ?";  
             Params.push_back(pQuery->CreatedBefore);  
         }  
         if (pQuery->ModifiedAfter.length() != 0) {  
             sql << " AND modified > ?";  
             Params.push_back(pQuery->ModifiedAfter);  
         }  
         if (pQuery->ModifiedBefore.length() != 0) {  
             sql << " AND modified < ?";  
             Params.push_back(pQuery->ModifiedBefore);  
         }  
         if (pQuery->MinSize != -1) sql << " AND instr_size > " << pQuery->MinSize;  
         if (pQuery->MaxSize != -1) sql << " AND instr_size < " << pQuery->MaxSize;  
   
         if (pQuery->InstrType == SearchQuery::CHROMATIC) sql << " AND is_drum = 0";  
         else if (pQuery->InstrType == SearchQuery::DRUM) sql << " AND is_drum != 0";  
   
         if (pQuery->FormatFamilies.size() > 0) {  
             sql << " AND (format_family=?";  
             Params.push_back(pQuery->FormatFamilies.at(0));  
             for (int i = 1; i < pQuery->FormatFamilies.size(); i++) {  
                 sql << "OR format_family=?";  
                 Params.push_back(pQuery->FormatFamilies.at(i));  
             }  
             sql << ")";  
         }  
   
         AddSql("instr_name", pQuery->Name, sql);  
         AddSql("description", pQuery->Description, sql);  
         AddSql("product", pQuery->Product, sql);  
         AddSql("artists", pQuery->Artists, sql);  
         AddSql("keywords", pQuery->Keywords, sql);  
         SqlQuery = sql.str();  
   
         InstrumentsDb* idb = InstrumentsDb::GetInstrumentsDb();  
   
         int res = sqlite3_prepare(idb->GetDb(), SqlQuery.c_str(), -1, &pStmt, NULL);  
         if (res != SQLITE_OK) {  
             throw Exception("DB error: " + ToString(sqlite3_errmsg(idb->GetDb())));  
         }  
   
         for(int i = 0; i < Params.size(); i++) {  
             idb->BindTextParam(pStmt, i + 2, Params.at(i));  
         }  
     }  
       
     InstrumentsDb::InstrumentFinder::~InstrumentFinder() {  
         if (pStmt != NULL) sqlite3_finalize(pStmt);  
     }  
       
     void InstrumentsDb::InstrumentFinder::ProcessDirectory(String Path, int DirId) {  
         InstrumentsDb* idb = InstrumentsDb::GetInstrumentsDb();  
         idb->BindIntParam(pStmt, 1, DirId);  
   
         String s = Path;  
         if(Path.compare("/") != 0) s += "/";  
         int res = sqlite3_step(pStmt);  
         while(res == SQLITE_ROW) {  
             pInstruments->push_back(s + ToString(sqlite3_column_text(pStmt, 0)));  
             res = sqlite3_step(pStmt);  
         }  
           
         if (res != SQLITE_DONE) {  
             sqlite3_finalize(pStmt);  
             throw Exception("DB error: " + ToString(sqlite3_errmsg(idb->GetDb())));  
         }  
   
         res = sqlite3_reset(pStmt);  
         if (res != SQLITE_OK) {  
             sqlite3_finalize(pStmt);  
             throw Exception("DB error: " + ToString(sqlite3_errmsg(idb->GetDb())));  
         }  
     }  
   
     StringListPtr InstrumentsDb::InstrumentFinder::GetInstruments() {  
         return pInstruments;  
     }  
   
     void InstrumentsDb::DirectoryCounter::ProcessDirectory(String Path, int DirId) {  
         count += InstrumentsDb::GetInstrumentsDb()->GetDirectoryCount(DirId);  
     }  
   
     void InstrumentsDb::InstrumentCounter::ProcessDirectory(String Path, int DirId) {  
         count += InstrumentsDb::GetInstrumentsDb()->GetInstrumentCount(DirId);  
     }  
   
     InstrumentsDb::DirectoryCopier::DirectoryCopier(String SrcParentDir, String DestDir) {  
         this->SrcParentDir = SrcParentDir;  
         this->DestDir = DestDir;  
   
         if (DestDir.at(DestDir.length() - 1) != '/') {  
             this->DestDir.append("/");  
         }  
         if (SrcParentDir.at(SrcParentDir.length() - 1) != '/') {  
             this->SrcParentDir.append("/");  
         }  
     }  
   
     void InstrumentsDb::DirectoryCopier::ProcessDirectory(String Path, int DirId) {  
         InstrumentsDb* db = InstrumentsDb::GetInstrumentsDb();  
   
         String dir = DestDir;  
         String subdir = Path;  
         if(subdir.length() > SrcParentDir.length()) {  
             subdir = subdir.substr(SrcParentDir.length());  
             dir += subdir;  
             db->AddDirectory(dir);  
         }  
   
         int dstDirId = db->GetDirectoryId(dir);  
         if(dstDirId == -1) throw Exception("Unkown DB directory: " + dir);  
         IntListPtr ids = db->GetInstrumentIDs(DirId);  
         for (int i = 0; i < ids->size(); i++) {  
             String name = db->GetInstrumentName(ids->at(i));  
             db->CopyInstrument(ids->at(i), name, dstDirId, dir);  
         }  
     }  
   
     InstrumentsDb* InstrumentsDb::pInstrumentsDb = new InstrumentsDb;  
   
     void InstrumentsDb::CreateInstrumentsDb(String File) {  
         struct stat statBuf;  
         int res = stat(File.c_str(), &statBuf);  
         if (!res) {  
             throw Exception("File exists: " + File);  
         }  
           
         GetInstrumentsDb()->SetDbFile(File);  
45    
46          String sql =          String sql =
47              "  CREATE TABLE instr_dirs (                                      "              "  CREATE TABLE instr_dirs (                                      "
# Line 395  namespace LinuxSampler { Line 57  namespace LinuxSampler {
57                    
58          GetInstrumentsDb()->ExecSql(sql);          GetInstrumentsDb()->ExecSql(sql);
59    
60          sql = "INSERT INTO instr_dirs (dir_id, parent_dir_id, dir_name) VALUES (0, 0, '/');";          sql = "INSERT INTO instr_dirs (dir_id, parent_dir_id, dir_name) VALUES (0, -2, '/');";
61          GetInstrumentsDb()->ExecSql(sql);          GetInstrumentsDb()->ExecSql(sql);
62    
63          sql =          sql =
# Line 432  namespace LinuxSampler { Line 94  namespace LinuxSampler {
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 448  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 464  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);
# Line 473  namespace LinuxSampler { Line 132  namespace LinuxSampler {
132          }          }
133          rc = sqlite3_create_function(db, "regexp", 2, SQLITE_UTF8, NULL, Regexp, NULL, NULL);          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."); }          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 486  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    
# Line 510  namespace LinuxSampler { Line 174  namespace LinuxSampler {
174              throw e;              throw e;
175          }          }
176          EndTransaction();          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 529  namespace LinuxSampler { Line 193  namespace LinuxSampler {
193          BeginTransaction();          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));
197    
198              StringListPtr pDirs;              StringListPtr pDirs;
199              if (Recursive) {              if (Recursive) {
# Line 552  namespace LinuxSampler { Line 216  namespace LinuxSampler {
216          std::stringstream sql;          std::stringstream sql;
217          sql << "SELECT dir_name FROM instr_dirs ";          sql << "SELECT dir_name FROM instr_dirs ";
218          sql << "WHERE parent_dir_id=" << DirId << " AND dir_id!=0";          sql << "WHERE parent_dir_id=" << DirId << " AND dir_id!=0";
219          return ExecSqlStringList(sql.str());          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) {
# Line 581  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) {      String InstrumentsDb::GetDirectoryName(int DirId) {
271          String sql = "SELECT dir_name FROM instr_dirs WHERE dir_id=" + ToString(DirId);          String sql = "SELECT dir_name FROM instr_dirs WHERE dir_id=" + ToString(DirId);
272          String name = ExecSqlString(sql);          String name = ExecSqlString(sql);
# Line 611  namespace LinuxSampler { Line 291  namespace LinuxSampler {
291                  path = "/" + path;                  path = "/" + path;
292                  break;                  break;
293              }              }
294              path = GetDirectoryName(DirId) + path;              path = GetDirectoryName(DirId) + "/" + path;
295              DirId = GetParentDirectoryId(DirId);              DirId = GetParentDirectoryId(DirId);
296          }          }
297    
# Line 619  namespace LinuxSampler { Line 299  namespace LinuxSampler {
299    
300          return path;          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()));
# Line 633  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);              id2 = GetInstrumentId(id, dirName);
348              if (id2 != -1) throw Exception("Instrument with that name exist: " + Dir);              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              EndTransaction();              EndTransaction();
357              throw e;              throw e;
# Line 666  namespace LinuxSampler { Line 370  namespace LinuxSampler {
370          BeginTransaction();          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);
# Line 753  namespace LinuxSampler { Line 457  namespace LinuxSampler {
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 776  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                            
# Line 793  namespace LinuxSampler { Line 497  namespace LinuxSampler {
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          BeginTransaction();          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, Name) != -1) {              if (GetInstrumentId(parent, dbName) != -1) {
519                  throw Exception("Cannot rename. Instrument with that name exist: " + Dir);                  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              EndTransaction();              EndTransaction();
527              throw e;              throw e;
528          }          }
529    
530          EndTransaction();          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) {
# Line 834  namespace LinuxSampler { Line 541  namespace LinuxSampler {
541          BeginTransaction();          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 852  namespace LinuxSampler { Line 559  namespace LinuxSampler {
559              String dirName = GetFileName(Dir);              String dirName = GetFileName(Dir);
560    
561              int id2 = GetDirectoryId(dstId, dirName);              int id2 = GetDirectoryId(dstId, dirName);
562              if (id2 != -1) throw Exception("DB directory already exist: " + dirName);              if (id2 != -1) throw Exception("DB directory already exist: " + toEscapedPath(dirName));
563              id2 = GetInstrumentId(dstId, dirName);              id2 = GetInstrumentId(dstId, dirName);
564              if (id2 != -1) throw Exception("Instrument with that name exist: " + dirName);              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;
# Line 880  namespace LinuxSampler { Line 587  namespace LinuxSampler {
587          BeginTransaction();          BeginTransaction();
588          try {          try {
589              int dirId = GetDirectoryId(Dir);              int dirId = GetDirectoryId(Dir);
590              if (dirId == -1) throw Exception("Unknown DB directory: " + Dir);              if (dirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
591              int dstId = GetDirectoryId(Dst);              int dstId = GetDirectoryId(Dst);
592              if (dstId == -1) throw Exception("Unknown DB directory: " + Dst);              if (dstId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dst));
593              if (dirId == dstId) {              if (dirId == dstId) {
594                  throw Exception("Cannot copy directory to itself");                  throw Exception("Cannot copy directory to itself");
595              }              }
# Line 898  namespace LinuxSampler { Line 605  namespace LinuxSampler {
605              String dirName = GetFileName(Dir);              String dirName = GetFileName(Dir);
606    
607              int id2 = GetDirectoryId(dstId, dirName);              int id2 = GetDirectoryId(dstId, dirName);
608              if (id2 != -1) throw Exception("DB directory already exist: " + dirName);              if (id2 != -1) throw Exception("DB directory already exist: " + toEscapedPath(dirName));
609              id2 = GetInstrumentId(dstId, dirName);              id2 = GetInstrumentId(dstId, dirName);
610              if (id2 != -1) throw Exception("Instrument with that name exist: " + dirName);              if (id2 != -1) throw Exception("Instrument with that name exist: " + toEscapedPath(dirName));
611    
612              DirectoryCopier directoryCopier(ParentDir, Dst);              DirectoryCopier directoryCopier(ParentDir, Dst);
613              DirectoryTreeWalk(Dir, &directoryCopier);              DirectoryTreeWalk(Dir, &directoryCopier);
# Line 918  namespace LinuxSampler { Line 625  namespace LinuxSampler {
625          BeginTransaction();          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 934  namespace LinuxSampler { Line 641  namespace LinuxSampler {
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) {
645            dmsg(2,("InstrumentsDb: AddInstruments(Mode=%d,DbDir=%s,FsDir=%s,bBackground=%d)\n", Mode, DbDir.c_str(), FsDir.c_str(), bBackground));
646            if(!bBackground) {
647                switch (Mode) {
648                    case NON_RECURSIVE:
649                        AddInstrumentsNonrecursive(DbDir, FsDir);
650                        break;
651                    case RECURSIVE:
652                        AddInstrumentsRecursive(DbDir, FsDir);
653                        break;
654                    case FLAT:
655                        AddInstrumentsRecursive(DbDir, FsDir, true);
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));
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, 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));
681    
682            return jobId;
683        }
684    
685        void InstrumentsDb::AddInstruments(String DbDir, String FilePath, int Index, ScanProgress* pProgress) {
686          dmsg(2,("InstrumentsDb: AddInstruments(DbDir=%s,FilePath=%s,Index=%d)\n", DbDir.c_str(), FilePath.c_str(), Index));          dmsg(2,("InstrumentsDb: AddInstruments(DbDir=%s,FilePath=%s,Index=%d)\n", DbDir.c_str(), FilePath.c_str(), Index));
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);              AddInstrumentsFromFile(DbDir, FilePath, Index, pProgress);
708          } catch (Exception e) {          } catch (Exception e) {
709              DbInstrumentsMutex.Unlock();              DbInstrumentsMutex.Unlock();
710              throw e;              throw e;
# Line 977  namespace LinuxSampler { Line 713  namespace LinuxSampler {
713          DbInstrumentsMutex.Unlock();          DbInstrumentsMutex.Unlock();
714      }      }
715    
716      void InstrumentsDb::AddInstrumentsNonrecursive(String DbDir, String FsDir) {      void InstrumentsDb::AddInstrumentsNonrecursive(String DbDir, String FsDir, ScanProgress* pProgress) {
717          dmsg(2,("InstrumentsDb: AddInstrumentsNonrecursive(DbDir=%s,FsDir=%s)\n", DbDir.c_str(), FsDir.c_str()));          dmsg(2,("InstrumentsDb: AddInstrumentsNonrecursive(DbDir=%s,FsDir=%s)\n", DbDir.c_str(), FsDir.c_str()));
718          if (DbDir.empty() || FsDir.empty()) return;          if (DbDir.empty() || FsDir.empty()) return;
719                    
720          DbInstrumentsMutex.Lock();          DbInstrumentsMutex.Lock();
721          try {          try {
722              int dirId = GetDirectoryId(DbDir);              int dirId = GetDirectoryId(DbDir);
723              if (dirId == -1) throw Exception("Invalid DB directory: " + DbDir);              if (dirId == -1) throw Exception("Invalid DB directory: " + toEscapedPath(DbDir));
724    
725              struct stat statBuf;              File f = File(FsDir);
726              int res = stat(FsDir.c_str(), &statBuf);              if (!f.Exist()) {
             if (res) {  
727                  std::stringstream ss;                  std::stringstream ss;
728                  ss << "Fail to stat `" << FsDir << "`: " << strerror(errno);                  ss << "Fail to stat `" << FsDir << "`: " << f.GetErrorMsg();
729                  throw Exception(ss.str());                  throw Exception(ss.str());
730              }              }
731    
732              if (!S_ISDIR(statBuf.st_mode)) {              if (!f.IsDirectory()) {
733                  throw Exception("Directory expected");                  throw Exception("Directory expected: " + FsDir);
734              }              }
735                            
736              if (FsDir.at(FsDir.length() - 1) != '/') FsDir.append("/");              if (FsDir.at(FsDir.length() - 1) != File::DirSeparator) {
737                    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::cerr << ss.str();  
                 DbInstrumentsMutex.Unlock();  
                 return;  
738              }              }
739                
740              struct dirent* pEnt = readdir(pDir);              try {
741              while (pEnt != NULL) {                  FileListPtr fileList = File::GetFiles(FsDir);
742                  if (pEnt->d_type != DT_REG) {                  for (int i = 0; i < fileList->size(); i++) {
743                      pEnt = readdir(pDir);                      AddInstrumentsFromFile(DbDir, FsDir + fileList->at(i), -1, pProgress);
                     continue;  
744                  }                  }
745                } catch(Exception e) {
746                  AddInstrumentsFromFile(DbDir, FsDir + String(pEnt->d_name));                  e.PrintMessage();
747                  pEnt = readdir(pDir);                  DbInstrumentsMutex.Unlock();
748              }                  return;
   
             if (closedir(pDir)) {  
                 std::stringstream ss;  
                 ss << "Failed to close directory `" << FsDir << "`: ";  
                 ss << strerror(errno);  
                 std::cerr << ss.str();  
749              }              }
750          } catch (Exception e) {          } catch (Exception e) {
751              DbInstrumentsMutex.Unlock();              DbInstrumentsMutex.Unlock();
# Line 1035  namespace LinuxSampler { Line 755  namespace LinuxSampler {
755          DbInstrumentsMutex.Unlock();          DbInstrumentsMutex.Unlock();
756      }      }
757    
758      void InstrumentsDb::AddInstrumentsRecursive(String DbDir, String FsDir, bool Flat) {      void InstrumentsDb::AddInstrumentsRecursive(String DbDir, String FsDir, bool Flat, ScanProgress* pProgress) {
759          dmsg(2,("InstrumentsDb: AddInstrumentsRecursive(DbDir=%s,FsDir=%s,Flat=%d)\n", DbDir.c_str(), FsDir.c_str(), Flat));          dmsg(2,("InstrumentsDb: AddInstrumentsRecursive(DbDir=%s,FsDir=%s,Flat=%d)\n", DbDir.c_str(), FsDir.c_str(), Flat));
760          DirectoryScanner::Scan(DbDir, FsDir, Flat);          if (pProgress != NULL) {
761                InstrumentFileCounter c;
762                pProgress->SetTotalFileCount(c.Count(FsDir));
763            }
764    
765            DirectoryScanner d;
766            d.Scan(DbDir, FsDir, Flat, pProgress);
767      }      }
768    
769      int InstrumentsDb::GetInstrumentCount(int DirId) {      int InstrumentsDb::GetInstrumentCount(int DirId) {
# Line 1069  namespace LinuxSampler { Line 795  namespace LinuxSampler {
795          }          }
796          EndTransaction();          EndTransaction();
797    
798          if (i == -1) throw Exception("Unknown Db directory: " + Dir);          if (i == -1) throw Exception("Unknown Db directory: " + toEscapedPath(Dir));
799          return i;          return i;
800      }      }
801    
# Line 1085  namespace LinuxSampler { Line 811  namespace LinuxSampler {
811          BeginTransaction();          BeginTransaction();
812          try {          try {
813              int dirId = GetDirectoryId(Dir);              int dirId = GetDirectoryId(Dir);
814              if(dirId == -1) throw Exception("Unknown DB directory: " + Dir);              if(dirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
815    
816              StringListPtr pInstrs;              StringListPtr pInstrs;
817    
# Line 1099  namespace LinuxSampler { Line 825  namespace LinuxSampler {
825                  sql << "SELECT instr_name FROM instruments WHERE dir_id=" << dirId;                  sql << "SELECT instr_name FROM instruments WHERE dir_id=" << dirId;
826    
827                  pInstrs = ExecSqlStringList(sql.str());                  pInstrs = ExecSqlStringList(sql.str());
828                    // Converting to abstract names
829                    for (int i = 0; i < pInstrs->size(); i++) {
830                        for (int j = 0; j < pInstrs->at(i).length(); j++) {
831                            if (pInstrs->at(i).at(j) == '/') pInstrs->at(i).at(j) = '\0';
832                        }
833                    }
834              }              }
835              EndTransaction();              EndTransaction();
836              return pInstrs;              return pInstrs;
# Line 1123  namespace LinuxSampler { Line 855  namespace LinuxSampler {
855          std::stringstream sql;          std::stringstream sql;
856          sql << "SELECT instr_id FROM instruments WHERE dir_id=";          sql << "SELECT instr_id FROM instruments WHERE dir_id=";
857          sql << DirId << " AND instr_name=?";          sql << DirId << " AND instr_name=?";
858          return ExecSqlInt(sql.str(), InstrName);          return ExecSqlInt(sql.str(), toDbName(InstrName));
859      }      }
860    
861      String InstrumentsDb::GetInstrumentName(int InstrId) {      String InstrumentsDb::GetInstrumentName(int InstrId) {
862          dmsg(2,("InstrumentsDb: GetInstrumentName(InstrId=%d)\n", InstrId));          dmsg(2,("InstrumentsDb: GetInstrumentName(InstrId=%d)\n", InstrId));
863          std::stringstream sql;          std::stringstream sql;
864          sql << "SELECT instr_name FROM instruments WHERE instr_id=" << InstrId;          sql << "SELECT instr_name FROM instruments WHERE instr_id=" << InstrId;
865          return ExecSqlString(sql.str());          return toAbstractName(ExecSqlString(sql.str()));
866      }      }
867            
868      void InstrumentsDb::RemoveInstrument(String Instr) {      void InstrumentsDb::RemoveInstrument(String Instr) {
# Line 1142  namespace LinuxSampler { Line 874  namespace LinuxSampler {
874          try {          try {
875              int instrId = GetInstrumentId(Instr);              int instrId = GetInstrumentId(Instr);
876              if(instrId == -1) {              if(instrId == -1) {
877                  throw Exception("The specified instrument does not exist: " + Instr);                  throw Exception("The specified instrument does not exist: " + toEscapedPath(Instr));
878              }              }
879              RemoveInstrument(instrId);              RemoveInstrument(instrId);
880          } catch (Exception e) {          } catch (Exception e) {
# Line 1177  namespace LinuxSampler { Line 909  namespace LinuxSampler {
909          BeginTransaction();          BeginTransaction();
910          try {          try {
911              int id = GetInstrumentId(Instr);              int id = GetInstrumentId(Instr);
912              if(id == -1) throw Exception("Unknown DB instrument: " + Instr);              if(id == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
913              i = GetInstrumentInfo(id);              i = GetInstrumentInfo(id);
914          } catch (Exception e) {          } catch (Exception e) {
915              EndTransaction();              EndTransaction();
# Line 1236  namespace LinuxSampler { Line 968  namespace LinuxSampler {
968          BeginTransaction();          BeginTransaction();
969          try {          try {
970              int dirId = GetDirectoryId(GetDirectoryPath(Instr));              int dirId = GetDirectoryId(GetDirectoryPath(Instr));
971              if (dirId == -1) throw Exception("Unknown DB instrument: " + Instr);              if (dirId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
972    
973              int instrId = GetInstrumentId(dirId, GetFileName(Instr));              int instrId = GetInstrumentId(dirId, GetFileName(Instr));
974              if (instrId == -1) throw Exception("Unknown DB instrument: " + Instr);              if (instrId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
975    
976              if (GetInstrumentId(dirId, Name) != -1) {              if (GetInstrumentId(dirId, Name) != -1) {
977                  throw Exception("Cannot rename. Instrument with that name already exists: " + Name);                  String s = toEscapedPath(Name);
978                    throw Exception("Cannot rename. Instrument with that name already exists: " + s);
979              }              }
980    
981              if (GetDirectoryId(dirId, Name) != -1) {              if (GetDirectoryId(dirId, Name) != -1) {
982                  throw Exception("Cannot rename. Directory with that name already exists: " + Name);                  String s = toEscapedPath(Name);
983                    throw Exception("Cannot rename. Directory with that name already exists: " + s);
984              }              }
985    
986              std::stringstream sql;              std::stringstream sql;
987              sql << "UPDATE instruments SET instr_name=? WHERE instr_id=" << instrId;              sql << "UPDATE instruments SET instr_name=? WHERE instr_id=" << instrId;
988              ExecSql(sql.str(), Name);              ExecSql(sql.str(), toDbName(Name));
989          } catch (Exception e) {          } catch (Exception e) {
990              EndTransaction();              EndTransaction();
991              throw e;              throw e;
992          }          }
993          EndTransaction();          EndTransaction();
994          FireInstrumentNameChanged(Instr, Name);          FireInstrumentNameChanged(Instr, toAbstractName(Name));
995      }      }
996    
997      void InstrumentsDb::MoveInstrument(String Instr, String Dst) {      void InstrumentsDb::MoveInstrument(String Instr, String Dst) {
# Line 1267  namespace LinuxSampler { Line 1001  namespace LinuxSampler {
1001    
1002          BeginTransaction();          BeginTransaction();
1003          try {          try {
1004              int dirId = GetDirectoryId(GetDirectoryPath(Instr));              int dirId = GetDirectoryId(ParentDir);
1005              if (dirId == -1) throw Exception("Unknown DB instrument: " + Instr);              if (dirId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1006    
1007              String instrName = GetFileName(Instr);              String instrName = GetFileName(Instr);
1008              int instrId = GetInstrumentId(dirId, instrName);              int instrId = GetInstrumentId(dirId, instrName);
1009              if (instrId == -1) throw Exception("Unknown DB instrument: " + Instr);              if (instrId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1010    
1011              int dstId = GetDirectoryId(Dst);              int dstId = GetDirectoryId(Dst);
1012              if (dstId == -1) throw Exception("Unknown DB directory: " + Dst);              if (dstId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dst));
1013              if (dirId == dstId) {              if (dirId == dstId) {
1014                  EndTransaction();                  EndTransaction();
1015                  return;                  return;
1016              }              }
1017    
1018              if (GetInstrumentId(dstId, instrName) != -1) {              if (GetInstrumentId(dstId, instrName) != -1) {
1019                  throw Exception("Cannot move. Instrument with that name already exists: " + instrName);                  String s = toEscapedPath(instrName);
1020                    throw Exception("Cannot move. Instrument with that name already exists: " + s);
1021              }              }
1022    
1023              if (GetDirectoryId(dstId, instrName) != -1) {              if (GetDirectoryId(dstId, instrName) != -1) {
1024                  throw Exception("Cannot move. Directory with that name already exists: " + instrName);                  String s = toEscapedPath(instrName);
1025                    throw Exception("Cannot move. Directory with that name already exists: " + s);
1026              }              }
1027    
1028              std::stringstream sql;              std::stringstream sql;
# Line 1310  namespace LinuxSampler { Line 1046  namespace LinuxSampler {
1046          BeginTransaction();          BeginTransaction();
1047          try {          try {
1048              int dirId = GetDirectoryId(GetDirectoryPath(Instr));              int dirId = GetDirectoryId(GetDirectoryPath(Instr));
1049              if (dirId == -1) throw Exception("Unknown DB instrument: " + Instr);              if (dirId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1050    
1051              String instrName = GetFileName(Instr);              String instrName = GetFileName(Instr);
1052              int instrId = GetInstrumentId(dirId, instrName);              int instrId = GetInstrumentId(dirId, instrName);
1053              if (instrId == -1) throw Exception("Unknown DB instrument: " + Instr);              if (instrId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1054    
1055              int dstId = GetDirectoryId(Dst);              int dstId = GetDirectoryId(Dst);
1056              if (dstId == -1) throw Exception("Unknown DB directory: " + Dst);              if (dstId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dst));
1057              if (dirId == dstId) {              if (dirId == dstId) {
1058                  EndTransaction();                  EndTransaction();
1059                  return;                  return;
1060              }              }
1061    
             if (GetInstrumentId(dstId, instrName) != -1) {  
                 throw Exception("Cannot copy. Instrument with that name already exists: " + instrName);  
             }  
   
             if (GetDirectoryId(dstId, instrName) != -1) {  
                 throw Exception("Cannot copy. Directory with that name already exists: " + instrName);  
             }  
   
1062              CopyInstrument(instrId, instrName, dstId, Dst);              CopyInstrument(instrId, instrName, dstId, Dst);
1063          } catch (Exception e) {          } catch (Exception e) {
1064              EndTransaction();              EndTransaction();
# Line 1341  namespace LinuxSampler { Line 1069  namespace LinuxSampler {
1069      }      }
1070    
1071      void InstrumentsDb::CopyInstrument(int InstrId, String InstrName, int DstDirId, String DstDir) {      void InstrumentsDb::CopyInstrument(int InstrId, String InstrName, int DstDirId, String DstDir) {
1072            if (GetInstrumentId(DstDirId, InstrName) != -1) {
1073                String s = toEscapedPath(InstrName);
1074                throw Exception("Cannot copy. Instrument with that name already exists: " + s);
1075            }
1076    
1077            if (GetDirectoryId(DstDirId, InstrName) != -1) {
1078                String s = toEscapedPath(InstrName);
1079                throw Exception("Cannot copy. Directory with that name already exists: " + s);
1080            }
1081    
1082          DbInstrument i = GetInstrumentInfo(InstrId);          DbInstrument i = GetInstrumentInfo(InstrId);
1083          sqlite3_stmt *pStmt = NULL;          sqlite3_stmt *pStmt = NULL;
1084          std::stringstream sql;          std::stringstream sql;
# Line 1354  namespace LinuxSampler { Line 1092  namespace LinuxSampler {
1092              throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));              throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1093          }          }
1094    
1095          BindTextParam(pStmt, 1, InstrName);          String s = toDbName(InstrName);
1096            BindTextParam(pStmt, 1, s);
1097          BindTextParam(pStmt, 2, i.InstrFile);          BindTextParam(pStmt, 2, i.InstrFile);
1098          BindTextParam(pStmt, 3, i.FormatFamily);          BindTextParam(pStmt, 3, i.FormatFamily);
1099          BindTextParam(pStmt, 4, i.FormatVersion);          BindTextParam(pStmt, 4, i.FormatVersion);
# Line 1379  namespace LinuxSampler { Line 1118  namespace LinuxSampler {
1118          BeginTransaction();          BeginTransaction();
1119          try {          try {
1120              int id = GetInstrumentId(Instr);              int id = GetInstrumentId(Instr);
1121              if(id == -1) throw Exception("Unknown DB instrument: " + Instr);              if(id == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1122    
1123              std::stringstream sql;              std::stringstream sql;
1124              sql << "UPDATE instruments SET description=?,modified=CURRENT_TIMESTAMP ";              sql << "UPDATE instruments SET description=?,modified=CURRENT_TIMESTAMP ";
# Line 1394  namespace LinuxSampler { Line 1133  namespace LinuxSampler {
1133          FireInstrumentInfoChanged(Instr);          FireInstrumentInfoChanged(Instr);
1134      }      }
1135    
1136      void InstrumentsDb::AddInstrumentsFromFile(String DbDir, String File, int Index) {      void InstrumentsDb::AddInstrumentsFromFile(String DbDir, String File, int Index, ScanProgress* pProgress) {
1137          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));
1138                    
1139          if(File.length() < 4) return;          if(File.length() < 4) return;
1140                    
1141          try {          try {
1142              if(!strcasecmp(".gig", File.substr(File.length() - 4).c_str())) {              if(!strcasecmp(".gig", File.substr(File.length() - 4).c_str())) {
1143                  AddGigInstruments(DbDir, File, Index);                  if (pProgress != NULL) {
1144                        pProgress->SetStatus(0);
1145                        pProgress->CurrentFile = File;
1146                    }
1147    
1148                    AddGigInstruments(DbDir, File, Index, pProgress);
1149    
1150                    if (pProgress != NULL) {
1151                        pProgress->SetScannedFileCount(pProgress->GetScannedFileCount() + 1);
1152                    }
1153              }              }
1154          } catch(Exception e) {          } catch(Exception e) {
1155              std::cerr << e.Message() << std::endl;              e.PrintMessage();
1156          }          }
1157      }      }
1158    
1159      void InstrumentsDb::AddGigInstruments(String DbDir, String File, int Index) {      void InstrumentsDb::AddGigInstruments(String DbDir, String FilePath, int Index, ScanProgress* pProgress) {
1160          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));
1161          int dirId = GetDirectoryId(DbDir);          int dirId = GetDirectoryId(DbDir);
1162          if (dirId == -1) throw Exception("Invalid DB directory: " + DbDir);          if (dirId == -1) throw Exception("Invalid DB directory: " + toEscapedPath(DbDir));
1163    
1164          struct stat statBuf;          File f = File(FilePath);
1165          int res = stat(File.c_str(), &statBuf);          if (!f.Exist()) {
         if (res) {  
1166              std::stringstream ss;              std::stringstream ss;
1167              ss << "Fail to stat `" << File << "`: " << strerror(errno);              ss << "Fail to stat `" << FilePath << "`: " << f.GetErrorMsg();
1168              throw Exception(ss.str());              throw Exception(ss.str());
1169          }          }
1170    
1171          if (!S_ISREG(statBuf.st_mode)) {          if (!f.IsFile()) {
1172              std::stringstream ss;              std::stringstream ss;
1173              ss << "`" << File << "` is not a regular file";              ss << "`" << FilePath << "` is not a regular file";
1174              throw Exception(ss.str());              throw Exception(ss.str());
1175          }          }
1176    
1177          RIFF::File* riff = NULL;          RIFF::File* riff = NULL;
1178          gig::File* gig = NULL;          gig::File* gig = NULL;
1179          try {          try {
1180              riff = new RIFF::File(File);              riff = new RIFF::File(FilePath);
1181              gig::File* gig = new gig::File(riff);              gig::File* gig = new gig::File(riff);
1182                            gig->SetAutoLoad(false); // avoid time consuming samples scanning
1183    
1184              std::stringstream sql;              std::stringstream sql;
1185              sql << "INSERT INTO instruments (dir_id,instr_name,instr_file,";              sql << "INSERT INTO instruments (dir_id,instr_name,instr_file,";
1186              sql << "instr_nr,format_family,format_version,instr_size,";              sql << "instr_nr,format_family,format_version,instr_size,";
1187              sql << "description,is_drum,product,artists,keywords) VALUES (";              sql << "description,is_drum,product,artists,keywords) VALUES (";
1188              sql << dirId << ",?,?,?,'GIG',?," << statBuf.st_size << ",?,?,?,?,?)";              sql << dirId << ",?,?,?,'GIG',?," << f.GetSize() << ",?,?,?,?,?)";
1189    
1190              sqlite3_stmt* pStmt = NULL;              sqlite3_stmt* pStmt = NULL;
1191    
# Line 1446  namespace LinuxSampler { Line 1194  namespace LinuxSampler {
1194                  throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));                  throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1195              }              }
1196    
1197              BindTextParam(pStmt, 2, File);              String s = toEscapedFsPath(FilePath);
1198                BindTextParam(pStmt, 2, s);
1199              String ver = "";              String ver = "";
1200              if (gig->pVersion != NULL) ver = ToString(gig->pVersion->major);              if (gig->pVersion != NULL) ver = ToString(gig->pVersion->major);
1201              BindTextParam(pStmt, 4, ver);              BindTextParam(pStmt, 4, ver);
1202    
1203              if (Index == -1) {              if (Index == -1) {
1204                  int instrIndex = 0;                  int instrIndex = 0;
1205                    if (pProgress != NULL) gig->GetInstrument(0, &(pProgress->GigFileProgress)); // TODO: this workaround should be fixed
1206                  gig::Instrument* pInstrument = gig->GetFirstInstrument();                  gig::Instrument* pInstrument = gig->GetFirstInstrument();
1207                  while (pInstrument) {                  while (pInstrument) {
1208                      BindTextParam(pStmt, 7, gig->pInfo->Product);                      BindTextParam(pStmt, 7, gig->pInfo->Product);
1209                      BindTextParam(pStmt, 8, gig->pInfo->Artists);                      BindTextParam(pStmt, 8, gig->pInfo->Artists);
1210                      BindTextParam(pStmt, 9, gig->pInfo->Keywords);                      BindTextParam(pStmt, 9, gig->pInfo->Keywords);
1211                      AddGigInstrument(pStmt, DbDir, dirId, File, pInstrument, instrIndex);                      AddGigInstrument(pStmt, DbDir, dirId, FilePath, pInstrument, instrIndex);
1212    
1213                      instrIndex++;                      instrIndex++;
1214                      pInstrument = gig->GetNextInstrument();                      pInstrument = gig->GetNextInstrument();
1215                  }                  }
1216              } else {              } else {
1217                  gig::Instrument* pInstrument = gig->GetInstrument(Index);                  gig::Instrument* pInstrument;
1218                    if (pProgress == NULL) pInstrument = gig->GetInstrument(Index);
1219                    else pInstrument = gig->GetInstrument(Index, &(pProgress->GigFileProgress));
1220                  if (pInstrument != NULL) {                  if (pInstrument != NULL) {
1221                      BindTextParam(pStmt, 7, gig->pInfo->Product);                      BindTextParam(pStmt, 7, gig->pInfo->Product);
1222                      BindTextParam(pStmt, 8, gig->pInfo->Artists);                      BindTextParam(pStmt, 8, gig->pInfo->Artists);
1223                      BindTextParam(pStmt, 9, gig->pInfo->Keywords);                      BindTextParam(pStmt, 9, gig->pInfo->Keywords);
1224                      AddGigInstrument(pStmt, DbDir, dirId, File, pInstrument, Index);                      AddGigInstrument(pStmt, DbDir, dirId, FilePath, pInstrument, Index);
1225                  }                  }
1226              }              }
1227    
# Line 1480  namespace LinuxSampler { Line 1232  namespace LinuxSampler {
1232              if (gig != NULL) delete gig;              if (gig != NULL) delete gig;
1233              if (riff != NULL) delete riff;              if (riff != NULL) delete riff;
1234              std::stringstream ss;              std::stringstream ss;
1235              ss << "Failed to scan `" << File << "`: " << e.Message;              ss << "Failed to scan `" << FilePath << "`: " << e.Message;
1236                            
1237              throw Exception(ss.str());              throw Exception(ss.str());
1238          } catch (Exception e) {          } catch (Exception e) {
# Line 1490  namespace LinuxSampler { Line 1242  namespace LinuxSampler {
1242          } catch (...) {          } catch (...) {
1243              if (gig != NULL) delete gig;              if (gig != NULL) delete gig;
1244              if (riff != NULL) delete riff;              if (riff != NULL) delete riff;
1245              throw Exception("Failed to scan `" + File + "`");              throw Exception("Failed to scan `" + FilePath + "`");
1246          }          }
1247      }      }
1248    
1249      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) {
1250            dmsg(2,("InstrumentsDb: AddGigInstrument(DbDir=%s,DirId=%d,File=%s,Index=%d)\n", DbDir.c_str(), DirId, File.c_str(), Index));
1251          String name = pInstrument->pInfo->Name;          String name = pInstrument->pInfo->Name;
1252          if (name == "") return;          if (name == "") return;
1253          name = GetUniqueInstrumentName(DirId, name);          name = GetUniqueInstrumentName(DirId, name);
# Line 1502  namespace LinuxSampler { Line 1255  namespace LinuxSampler {
1255          std::stringstream sql2;          std::stringstream sql2;
1256          sql2 << "SELECT COUNT(*) FROM instruments WHERE instr_file=? AND ";          sql2 << "SELECT COUNT(*) FROM instruments WHERE instr_file=? AND ";
1257          sql2 << "instr_nr=" << Index;          sql2 << "instr_nr=" << Index;
1258          if (ExecSqlInt(sql2.str(), File) > 0) return;          String s = toEscapedFsPath(File);
1259            if (ExecSqlInt(sql2.str(), s) > 0) return;
1260    
1261          BindTextParam(pStmt, 1, name);          BindTextParam(pStmt, 1, name);
1262          BindIntParam(pStmt, 3, Index);          BindIntParam(pStmt, 3, Index);
# Line 1531  namespace LinuxSampler { Line 1285  namespace LinuxSampler {
1285          FireInstrumentCountChanged(DbDir);          FireInstrumentCountChanged(DbDir);
1286      }      }
1287    
1288      void InstrumentsDb::DirectoryTreeWalk(String Path, DirectoryHandler* pHandler) {      void InstrumentsDb::DirectoryTreeWalk(String AbstractPath, DirectoryHandler* pHandler) {
1289          int DirId = GetDirectoryId(Path);          int DirId = GetDirectoryId(AbstractPath);
1290          if(DirId == -1) throw Exception("Unknown DB directory: " + Path);          if(DirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(AbstractPath));
1291          DirectoryTreeWalk(pHandler, Path, DirId, 0);          DirectoryTreeWalk(pHandler, AbstractPath, DirId, 0);
1292      }      }
1293    
1294      void InstrumentsDb::DirectoryTreeWalk(DirectoryHandler* pHandler, String Path, int DirId, int Level) {      void InstrumentsDb::DirectoryTreeWalk(DirectoryHandler* pHandler, String AbstractPath, int DirId, int Level) {
1295          if(Level == 1000) throw Exception("Possible infinite loop detected");          if(Level == 1000) throw Exception("Possible infinite loop detected");
1296          pHandler->ProcessDirectory(Path, DirId);          pHandler->ProcessDirectory(AbstractPath, DirId);
1297                    
1298          String s;          String s;
1299          StringListPtr pDirs = GetDirectories(DirId);          StringListPtr pDirs = GetDirectories(DirId);
1300          for(int i = 0; i < pDirs->size(); i++) {          for(int i = 0; i < pDirs->size(); i++) {
1301              if (Path.length() == 1 && Path.at(0) == '/') s = "/" + pDirs->at(i);              if (AbstractPath.length() == 1 && AbstractPath.at(0) == '/') {
1302              else s = Path + "/" + pDirs->at(i);                  s = "/" + pDirs->at(i);
1303                } else {
1304                    s = AbstractPath + "/" + pDirs->at(i);
1305                }
1306              DirectoryTreeWalk(pHandler, s, GetDirectoryId(DirId, pDirs->at(i)), Level + 1);              DirectoryTreeWalk(pHandler, s, GetDirectoryId(DirId, pDirs->at(i)), Level + 1);
1307          }          }
1308      }      }
# Line 1557  namespace LinuxSampler { Line 1314  namespace LinuxSampler {
1314          BeginTransaction();          BeginTransaction();
1315          try {          try {
1316              int DirId = GetDirectoryId(Dir);              int DirId = GetDirectoryId(Dir);
1317              if(DirId == -1) throw Exception("Unknown DB directory: " + Dir);              if(DirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
1318    
1319              if (Recursive) DirectoryTreeWalk(Dir, &directoryFinder);              if (Recursive) DirectoryTreeWalk(Dir, &directoryFinder);
1320              else directoryFinder.ProcessDirectory(Dir, DirId);              else directoryFinder.ProcessDirectory(Dir, DirId);
# Line 1577  namespace LinuxSampler { Line 1334  namespace LinuxSampler {
1334          BeginTransaction();          BeginTransaction();
1335          try {          try {
1336              int DirId = GetDirectoryId(Dir);              int DirId = GetDirectoryId(Dir);
1337              if(DirId == -1) throw Exception("Unknown DB directory: " + Dir);              if(DirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
1338    
1339              if (Recursive) DirectoryTreeWalk(Dir, &instrumentFinder);              if (Recursive) DirectoryTreeWalk(Dir, &instrumentFinder);
1340              else instrumentFinder.ProcessDirectory(Dir, DirId);              else instrumentFinder.ProcessDirectory(Dir, DirId);
# Line 1589  namespace LinuxSampler { Line 1346  namespace LinuxSampler {
1346    
1347          return instrumentFinder.GetInstruments();          return instrumentFinder.GetInstruments();
1348      }      }
1349        
1350        StringListPtr InstrumentsDb::FindLostInstrumentFiles() {
1351            dmsg(2,("InstrumentsDb: FindLostInstrumentFiles()\n"));
1352    
1353            BeginTransaction();
1354            try {
1355                StringListPtr files = ExecSqlStringList("SELECT DISTINCT instr_file FROM instruments");
1356                StringListPtr result(new std::vector<String>);
1357                for (int i = 0; i < files->size(); i++) {
1358                    File f(toNonEscapedFsPath(files->at(i)));
1359                    if (!f.Exist()) result->push_back(files->at(i));
1360                }
1361                return result;
1362            } catch (Exception e) {
1363                EndTransaction();
1364                throw e;
1365            }
1366            EndTransaction();
1367        }
1368        
1369        void InstrumentsDb::SetInstrumentFilePath(String OldPath, String NewPath) {
1370            if (OldPath == NewPath) return;
1371            StringListPtr instrs;
1372            BeginTransaction();
1373            try {
1374                std::vector<String> params(2);
1375                params[0] = toEscapedFsPath(NewPath);
1376                params[1] = toEscapedFsPath(OldPath);
1377                instrs = GetInstrumentsByFile(OldPath);
1378                ExecSql("UPDATE instruments SET instr_file=? WHERE instr_file=?", params);
1379            } catch (Exception e) {
1380                EndTransaction();
1381                throw e;
1382            }
1383            EndTransaction();
1384            
1385            for (int i = 0; i < instrs->size(); i++) {
1386                FireInstrumentInfoChanged(instrs->at(i));
1387            }
1388        }
1389    
1390      void InstrumentsDb::BeginTransaction() {      void InstrumentsDb::BeginTransaction() {
1391          dmsg(2,("InstrumentsDb: BeginTransaction(InTransaction=%d)\n", InTransaction));          dmsg(2,("InstrumentsDb: BeginTransaction(InTransaction=%d)\n", InTransaction));
# Line 1650  namespace LinuxSampler { Line 1447  namespace LinuxSampler {
1447    
1448      void InstrumentsDb::ExecSql(String Sql) {      void InstrumentsDb::ExecSql(String Sql) {
1449          dmsg(2,("InstrumentsDb: ExecSql(Sql=%s)\n", Sql.c_str()));          dmsg(2,("InstrumentsDb: ExecSql(Sql=%s)\n", Sql.c_str()));
1450          sqlite3_stmt *pStmt = NULL;          std::vector<String> Params;
1451                    ExecSql(Sql, Params);
         int res = sqlite3_prepare(GetDb(), Sql.c_str(), -1, &pStmt, NULL);  
         if (res != SQLITE_OK) {  
             throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));  
         }  
           
         res = sqlite3_step(pStmt);  
         if(res != SQLITE_DONE) {  
             sqlite3_finalize(pStmt);  
             throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));  
         }  
   
         sqlite3_finalize(pStmt);  
1452      }      }
1453    
1454      void InstrumentsDb::ExecSql(String Sql, String Param) {      void InstrumentsDb::ExecSql(String Sql, String Param) {
1455          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()));
1456            std::vector<String> Params;
1457            Params.push_back(Param);
1458            ExecSql(Sql, Params);
1459        }
1460    
1461        void InstrumentsDb::ExecSql(String Sql, std::vector<String>& Params) {
1462            dmsg(2,("InstrumentsDb: ExecSql(Sql=%s,Params)\n", Sql.c_str()));
1463          sqlite3_stmt *pStmt = NULL;          sqlite3_stmt *pStmt = NULL;
1464                    
1465          int res = sqlite3_prepare(GetDb(), Sql.c_str(), -1, &pStmt, NULL);          int res = sqlite3_prepare(GetDb(), Sql.c_str(), -1, &pStmt, NULL);
# Line 1676  namespace LinuxSampler { Line 1468  namespace LinuxSampler {
1468              throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));              throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1469          }          }
1470    
1471          BindTextParam(pStmt, 1, Param);          for(int i = 0; i < Params.size(); i++) {
1472                BindTextParam(pStmt, i + 1, Params[i]);
1473            }
1474    
1475          res = sqlite3_step(pStmt);          res = sqlite3_step(pStmt);
1476          if (res != SQLITE_DONE) {          if (res != SQLITE_DONE) {
# Line 1758  namespace LinuxSampler { Line 1552  namespace LinuxSampler {
1552      }      }
1553    
1554      IntListPtr InstrumentsDb::ExecSqlIntList(String Sql) {      IntListPtr InstrumentsDb::ExecSqlIntList(String Sql) {
1555            dmsg(2,("InstrumentsDb: ExecSqlIntList(Sql=%s)\n", Sql.c_str()));
1556            std::vector<String> Params;
1557            return ExecSqlIntList(Sql, Params);
1558        }
1559    
1560        IntListPtr InstrumentsDb::ExecSqlIntList(String Sql, String Param) {
1561            dmsg(2,("InstrumentsDb: ExecSqlIntList(Sql=%s,Param=%s)\n", Sql.c_str(), Param.c_str()));
1562            std::vector<String> Params;
1563            Params.push_back(Param);
1564            return ExecSqlIntList(Sql, Params);
1565        }
1566    
1567        IntListPtr InstrumentsDb::ExecSqlIntList(String Sql, std::vector<String>& Params) {
1568            dmsg(2,("InstrumentsDb: ExecSqlIntList(Sql=%s)\n", Sql.c_str()));
1569          IntListPtr intList(new std::vector<int>);          IntListPtr intList(new std::vector<int>);
1570                    
1571          sqlite3_stmt *pStmt = NULL;          sqlite3_stmt *pStmt = NULL;
# Line 1767  namespace LinuxSampler { Line 1575  namespace LinuxSampler {
1575              throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));              throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1576          }          }
1577                    
1578            for(int i = 0; i < Params.size(); i++) {
1579                BindTextParam(pStmt, i + 1, Params[i]);
1580            }
1581            
1582          res = sqlite3_step(pStmt);          res = sqlite3_step(pStmt);
1583          while(res == SQLITE_ROW) {          while(res == SQLITE_ROW) {
1584              intList->push_back(sqlite3_column_int(pStmt, 0));              intList->push_back(sqlite3_column_int(pStmt, 0));
# Line 1784  namespace LinuxSampler { Line 1596  namespace LinuxSampler {
1596      }      }
1597            
1598      StringListPtr InstrumentsDb::ExecSqlStringList(String Sql) {      StringListPtr InstrumentsDb::ExecSqlStringList(String Sql) {
1599            dmsg(2,("InstrumentsDb: ExecSqlStringList(Sql=%s)\n", Sql.c_str()));
1600          StringListPtr stringList(new std::vector<String>);          StringListPtr stringList(new std::vector<String>);
1601                    
1602          sqlite3_stmt *pStmt = NULL;          sqlite3_stmt *pStmt = NULL;
# Line 1879  namespace LinuxSampler { Line 1692  namespace LinuxSampler {
1692          return Dir.substr(0, i);          return Dir.substr(0, i);
1693      }      }
1694    
1695        void InstrumentsDb::Format() {
1696            DbInstrumentsMutex.Lock();
1697            if (db != NULL) {
1698                sqlite3_close(db);
1699                db = NULL;
1700            }
1701    
1702            if (DbFile.empty()) DbFile = CONFIG_DEFAULT_INSTRUMENTS_DB_LOCATION;
1703            String bkp = DbFile + ".bkp";
1704            remove(bkp.c_str());
1705            if (rename(DbFile.c_str(), bkp.c_str()) && errno != ENOENT) {
1706                DbInstrumentsMutex.Unlock();
1707                throw Exception(String("Failed to backup database: ") + strerror(errno));
1708            }
1709            
1710            String f = DbFile;
1711            DbFile = "";
1712            try { CreateInstrumentsDb(f); }
1713            catch(Exception e) {
1714                DbInstrumentsMutex.Unlock();
1715                throw e;
1716            }
1717            DbInstrumentsMutex.Unlock();
1718            
1719            FireDirectoryCountChanged("/");
1720            FireInstrumentCountChanged("/");
1721        }
1722    
1723      void InstrumentsDb::CheckFileName(String File) {      void InstrumentsDb::CheckFileName(String File) {
1724          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);  
         }  
1725      }      }
1726    
1727      String InstrumentsDb::GetUniqueInstrumentName(int DirId, String Name) {      String InstrumentsDb::GetUniqueInstrumentName(int DirId, String Name) {
# Line 1901  namespace LinuxSampler { Line 1739  namespace LinuxSampler {
1739    
1740          throw Exception("Unable to find an unique name: " + Name);          throw Exception("Unable to find an unique name: " + Name);
1741      }      }
1742    
1743        String InstrumentsDb::toDbName(String AbstractName) {
1744            for (int i = 0; i < AbstractName.length(); i++) {
1745                if (AbstractName.at(i) == '\0') AbstractName.at(i) = '/';
1746            }
1747            return AbstractName;
1748        }
1749    
1750        String InstrumentsDb::toEscapedPath(String AbstractName) {
1751            for (int i = 0; i < AbstractName.length(); i++) {
1752                if (AbstractName.at(i) == '\0')      AbstractName.replace(i++, 1, "\\x2f");
1753                else if (AbstractName.at(i) == '\\') AbstractName.replace(i++, 1, "\\\\");
1754                else if (AbstractName.at(i) == '\'') AbstractName.replace(i++, 1, "\\'");
1755                else if (AbstractName.at(i) == '"')  AbstractName.replace(i++, 1, "\\\"");
1756                else if (AbstractName.at(i) == '\r') AbstractName.replace(i++, 1, "\\r");
1757                else if (AbstractName.at(i) == '\n') AbstractName.replace(i++, 1, "\\n");
1758            }
1759            return AbstractName;
1760        }
1761            
1762        String InstrumentsDb::toEscapedText(String text) {
1763            for (int i = 0; i < text.length(); i++) {
1764                if (text.at(i) == '\\')      text.replace(i++, 1, "\\\\");
1765                else if (text.at(i) == '\'') text.replace(i++, 1, "\\'");
1766                else if (text.at(i) == '"')  text.replace(i++, 1, "\\\"");
1767                else if (text.at(i) == '\r') text.replace(i++, 1, "\\r");
1768                else if (text.at(i) == '\n') text.replace(i++, 1, "\\n");
1769            }
1770            return text;
1771        }
1772        
1773        String InstrumentsDb::toNonEscapedText(String text) {
1774            String sb;
1775            for (int i = 0; i < text.length(); i++) {
1776                char c = text.at(i);
1777                            if(c == '\\') {
1778                                    if(i >= text.length()) {
1779                                            std::cerr << "Broken escape sequence!" << std::endl;
1780                                            break;
1781                                    }
1782                                    char c2 = text.at(++i);
1783                                    if(c2 == '\'')      sb.push_back('\'');
1784                                    else if(c2 == '"')  sb.push_back('"');
1785                                    else if(c2 == '\\') sb.push_back('\\');
1786                                    else if(c2 == 'r')  sb.push_back('\r');
1787                                    else if(c2 == 'n')  sb.push_back('\n');
1788                                    else std::cerr << "Unknown escape sequence \\" << c2 << std::endl;
1789                            } else {
1790                                    sb.push_back(c);
1791                            }
1792            }
1793            return sb;
1794        }
1795        
1796        String InstrumentsDb::toEscapedFsPath(String FsPath) {
1797            return toEscapedText(FsPath);
1798        }
1799        
1800        String InstrumentsDb::toNonEscapedFsPath(String FsPath) {
1801            return toNonEscapedText(FsPath);
1802        }
1803        
1804        String InstrumentsDb::toAbstractName(String DbName) {
1805            for (int i = 0; i < DbName.length(); i++) {
1806                if (DbName.at(i) == '/') DbName.at(i) = '\0';
1807            }
1808            return DbName;
1809        }
1810    
1811      void InstrumentsDb::FireDirectoryCountChanged(String Dir) {      void InstrumentsDb::FireDirectoryCountChanged(String Dir) {
1812          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1813              llInstrumentsDbListeners.GetListener(i)->DirectoryCountChanged(Dir);              llInstrumentsDbListeners.GetListener(i)->DirectoryCountChanged(Dir);
1814          }          }
1815      }      }
1816        
1817      void InstrumentsDb::FireDirectoryInfoChanged(String Dir) {      void InstrumentsDb::FireDirectoryInfoChanged(String Dir) {
1818          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1819              llInstrumentsDbListeners.GetListener(i)->DirectoryInfoChanged(Dir);              llInstrumentsDbListeners.GetListener(i)->DirectoryInfoChanged(Dir);
1820          }          }
1821      }      }
1822        
1823      void InstrumentsDb::FireDirectoryNameChanged(String Dir, String NewName) {      void InstrumentsDb::FireDirectoryNameChanged(String Dir, String NewName) {
1824          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1825              llInstrumentsDbListeners.GetListener(i)->DirectoryNameChanged(Dir, NewName);              llInstrumentsDbListeners.GetListener(i)->DirectoryNameChanged(Dir, NewName);
1826          }          }
1827      }      }
1828        
1829      void InstrumentsDb::FireInstrumentCountChanged(String Dir) {      void InstrumentsDb::FireInstrumentCountChanged(String Dir) {
1830          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1831              llInstrumentsDbListeners.GetListener(i)->InstrumentCountChanged(Dir);              llInstrumentsDbListeners.GetListener(i)->InstrumentCountChanged(Dir);
1832          }          }
1833      }      }
1834        
1835      void InstrumentsDb::FireInstrumentInfoChanged(String Instr) {      void InstrumentsDb::FireInstrumentInfoChanged(String Instr) {
1836          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1837              llInstrumentsDbListeners.GetListener(i)->InstrumentInfoChanged(Instr);              llInstrumentsDbListeners.GetListener(i)->InstrumentInfoChanged(Instr);
1838          }          }
1839      }      }
1840        
1841      void InstrumentsDb::FireInstrumentNameChanged(String Instr, String NewName) {      void InstrumentsDb::FireInstrumentNameChanged(String Instr, String NewName) {
1842          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1843              llInstrumentsDbListeners.GetListener(i)->InstrumentNameChanged(Instr, NewName);              llInstrumentsDbListeners.GetListener(i)->InstrumentNameChanged(Instr, NewName);
1844          }          }
1845      }      }
       
   
     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());  
         }  
1846    
1847          if (!S_ISDIR(statBuf.st_mode)) {      void InstrumentsDb::FireJobStatusChanged(int JobId) {
1848              throw Exception("Directory expected");          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1849          }              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("/");  
1850          }          }
         DirectoryScanner::Flat = Flat;  
           
         ftw(FsDir.c_str(), FtwCallback, 10);  
1851      }      }
1852    
     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;  
     };  
   
1853  } // namespace LinuxSampler  } // namespace LinuxSampler
   
 #endif // HAVE_SQLITE3  

Legend:
Removed from v.1187  
changed lines
  Added in v.1727

  ViewVC Help
Powered by ViewVC