/[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 1200 by iliev, Thu May 24 14:04:18 2007 UTC revision 3091 by schoenebeck, Mon Jan 16 15:01:21 2017 UTC
# Line 1  Line 1 
1  /***************************************************************************  /***************************************************************************
2   *                                                                         *   *                                                                         *
3   *   Copyright (C) 2007 Grigor Iliev                                       *   *   Copyright (C) 2007-2013 Grigor Iliev, Benno Senoner                   *
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/Path.h"
25    #include "../common/global_private.h"
26    
27  #include <iostream>  #include <iostream>
28  #include <sstream>  #include <sstream>
29  #include <vector>  #include <vector>
30  #include <dirent.h>  #include <algorithm>
31  #include <errno.h>  #include <errno.h>
32    #ifndef WIN32
33  #include <fnmatch.h>  #include <fnmatch.h>
34    #else
35    #include <direct.h>
36    #endif
37  #include "../common/Exception.h"  #include "../common/Exception.h"
38    
39  namespace LinuxSampler {  namespace LinuxSampler {
40    
41      InstrumentsDb* InstrumentsDb::pInstrumentsDb = new InstrumentsDb;      InstrumentsDb InstrumentsDb::instance;
42    
43      void InstrumentsDb::CreateInstrumentsDb(String File) {      void InstrumentsDb::CreateInstrumentsDb(String FilePath) {
44          struct stat statBuf;          if (FilePath.empty()) {
45          int res = stat(File.c_str(), &statBuf);              FilePath = GetDefaultDBLocation();
46          if (!res) {              dmsg(0,("InstrumentsDb: Creating database at default location '%s'\n", FilePath.c_str()));
             throw Exception("File exists: " + File);  
47          }          }
48            
49          GetInstrumentsDb()->SetDbFile(File);          File f = File(FilePath);
50            if (f.Exist()) {
51                throw Exception("File exists: " + FilePath);
52            }
53    
54            SetDbFile(FilePath);
55    
56          String sql =          String sql =
57              "  CREATE TABLE instr_dirs (                                      "              "  CREATE TABLE instr_dirs (                                      "
# Line 56  namespace LinuxSampler { Line 65  namespace LinuxSampler {
65              "      UNIQUE (parent_dir_id,dir_name)                            "              "      UNIQUE (parent_dir_id,dir_name)                            "
66              "  );                                                             ";              "  );                                                             ";
67                    
68          GetInstrumentsDb()->ExecSql(sql);          ExecSql(sql);
69    
70          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, '/');";
71          GetInstrumentsDb()->ExecSql(sql);          ExecSql(sql);
72    
73          sql =          sql =
74              "  CREATE TABLE instruments (                                "              "  CREATE TABLE instruments (                                "
# Line 82  namespace LinuxSampler { Line 91  namespace LinuxSampler {
91              "      UNIQUE (dir_id,instr_name)                            "              "      UNIQUE (dir_id,instr_name)                            "
92              "  );                                                        ";              "  );                                                        ";
93                    
94          GetInstrumentsDb()->ExecSql(sql);          ExecSql(sql);
95      }      }
96    
97      InstrumentsDb::InstrumentsDb() {      InstrumentsDb::InstrumentsDb() {
98          db = NULL;          db = NULL;
         DbInstrumentsMutex = Mutex();  
99          InTransaction = false;          InTransaction = false;
100      }      }
101    
# Line 95  namespace LinuxSampler { Line 103  namespace LinuxSampler {
103          if (db != NULL) sqlite3_close(db);          if (db != NULL) sqlite3_close(db);
104      }      }
105            
     void InstrumentsDb::Destroy() {  
         if (pInstrumentsDb != NULL) {  
             delete pInstrumentsDb;  
             pInstrumentsDb = NULL;  
         }  
     }  
   
106      void InstrumentsDb::AddInstrumentsDbListener(InstrumentsDb::Listener* l) {      void InstrumentsDb::AddInstrumentsDbListener(InstrumentsDb::Listener* l) {
107          llInstrumentsDbListeners.AddListener(l);          llInstrumentsDbListeners.AddListener(l);
108      }      }
# Line 111  namespace LinuxSampler { Line 112  namespace LinuxSampler {
112      }      }
113            
114      InstrumentsDb* InstrumentsDb::GetInstrumentsDb() {      InstrumentsDb* InstrumentsDb::GetInstrumentsDb() {
115          return pInstrumentsDb;          return &instance;
116      }      }
117            
118      void InstrumentsDb::SetDbFile(String File) {      void InstrumentsDb::SetDbFile(String File) {
119          DbInstrumentsMutex.Lock();          LockGuard lock(DbInstrumentsMutex);
120          if (File.empty() || DbFile.length() > 0) {          if (File.empty() || DbFile.length() > 0) {
             DbInstrumentsMutex.Unlock();  
121              throw Exception("Failed to set the database file");              throw Exception("Failed to set the database file");
122          }          }
123          DbFile = File;          DbFile = File;
124          DbInstrumentsMutex.Unlock();      }
125    
126        String InstrumentsDb::GetDefaultDBLocation() {
127            #ifdef WIN32
128            char* userprofile = getenv("USERPROFILE");
129            if (userprofile) {
130                String s = userprofile;
131                s += "\\.linuxsampler\\instruments.db";
132                return s;
133            } else {
134                // in case USERPROFILE is not set (which should not occur)
135                return "instruments.db";
136            }
137            #else // POSIX ...
138            String s = CONFIG_DEFAULT_INSTRUMENTS_DB_LOCATION;
139            # if defined(__APPLE__)
140            if (s.find("~") == 0)
141                s.replace(0, 1, getenv("HOME"));
142            # endif
143            return s;
144            #endif
145        }
146    
147        void InstrumentsDb::EnsureDBFileExists() {
148            if (DbFile.empty())
149                DbFile = GetDefaultDBLocation();
150                    #if defined(__APPLE__)  /* 20071224 Toshi Nagata  */
151                    if (DbFile.find("~") == 0)
152                            DbFile.replace(0, 1, getenv("HOME"));
153                    #endif
154            Path DbPath(DbFile);
155            String DbDir = DbPath.stripLastName();
156            // create directory if it does not exist yet
157            if (!DbPath.nodes().empty()) {
158                File d(DbDir);
159                if (!d.Exist()) {
160                    #ifdef WIN32
161                    if (_mkdir(DbDir.c_str()))
162                        throw Exception("Could not create instruments DB directory '" + DbDir + "'");
163                    #else
164                    if (mkdir(DbDir.c_str(), S_IRWXU))
165                        throw Exception("Could not create instruments DB directory '" + DbDir + "'");
166                    #endif
167                }
168            }
169            // create database file if it does not exist yet
170            File f(DbFile);
171            if (!f.Exist()) {
172                // formats the DB, which creates a new instruments.db file
173                Format();
174            }
175      }      }
176    
177      sqlite3* InstrumentsDb::GetDb() {      sqlite3* InstrumentsDb::GetDb() {
178          if ( db != NULL) return db;          if ( db != NULL) return db;
179    
180          if (DbFile.empty()) DbFile = "/var/lib/linuxsampler/instruments.db";          if (DbFile.empty())
181                DbFile = GetDefaultDBLocation();
182    
183            {
184                // first check if the instruments DB's directory exists, if not give up
185                Path path(DbFile);
186                String sDir = path.stripLastName();
187                File d(sDir);
188                if (!d.Exist())
189                    throw Exception("Instruments DB directory '" + sDir + "' does not exist!");
190    
191                // just to give the user a notice about the DB file being created in case it does not exist yet
192                File f(DbFile);
193                if (!f.Exist())
194                    dmsg(0,("Instruments DB file '%s' does not exist yet. Trying to create it now.\n", DbFile.c_str()));
195            }
196    
197            dmsg(0,("Opening instruments DB at '%s'\n", DbFile.c_str()));
198          int rc = sqlite3_open(DbFile.c_str(), &db);          int rc = sqlite3_open(DbFile.c_str(), &db);
199          if (rc) {          if (rc) {
200              sqlite3_close(db);              sqlite3_close(db);
201              db = NULL;              db = NULL;
202              throw Exception("Cannot open instruments database: " + DbFile);              throw Exception("Cannot open instruments database: " + DbFile);
203          }          }
204    #ifndef WIN32
205          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);
206          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."); }
207    #endif
208    
209            // TODO: remove this in the next version
210            try {
211                int i = ExecSqlInt("SELECT parent_dir_id FROM instr_dirs WHERE dir_id=0");
212                // The parent ID of the root directory should be -2 now.
213                if(i != -2) ExecSql("UPDATE instr_dirs SET parent_dir_id=-2 WHERE dir_id=0");
214            } catch(Exception e) { }
215            ////////////////////////////////////////
216                    
217          return db;          return db;
218      }      }
# Line 149  namespace LinuxSampler { Line 226  namespace LinuxSampler {
226                    
227          int count = ExecSqlInt(sql.str());          int count = ExecSqlInt(sql.str());
228    
         // 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--;  
229          return count;          return count;
230      }      }
231    
# Line 173  namespace LinuxSampler { Line 247  namespace LinuxSampler {
247              throw e;              throw e;
248          }          }
249          EndTransaction();          EndTransaction();
250          if (i == -1) throw Exception("Unkown DB directory: " + Dir);          if (i == -1) throw Exception("Unkown DB directory: " + toEscapedPath(Dir));
251                    
252          return i;          return i;
253      }      }
# Line 192  namespace LinuxSampler { Line 266  namespace LinuxSampler {
266          BeginTransaction();          BeginTransaction();
267          try {          try {
268              int dirId = GetDirectoryId(Dir);              int dirId = GetDirectoryId(Dir);
269              if(dirId == -1) throw Exception("Unknown DB directory: " + Dir);              if(dirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
270    
271              StringListPtr pDirs;              StringListPtr pDirs;
272              if (Recursive) {              if (Recursive) {
# Line 215  namespace LinuxSampler { Line 289  namespace LinuxSampler {
289          std::stringstream sql;          std::stringstream sql;
290          sql << "SELECT dir_name FROM instr_dirs ";          sql << "SELECT dir_name FROM instr_dirs ";
291          sql << "WHERE parent_dir_id=" << DirId << " AND dir_id!=0";          sql << "WHERE parent_dir_id=" << DirId << " AND dir_id!=0";
292          return ExecSqlStringList(sql.str());          StringListPtr dirs = ExecSqlStringList(sql.str());
293    
294            for (int i = 0; i < dirs->size(); i++) {
295                for (int j = 0; j < dirs->at(i).length(); j++) {
296                    if (dirs->at(i).at(j) == '/') dirs->at(i).at(j) = '\0';
297                }
298            }
299    
300            return dirs;
301      }      }
302    
303      int InstrumentsDb::GetDirectoryId(String Dir) {      int InstrumentsDb::GetDirectoryId(String Dir) {
# Line 244  namespace LinuxSampler { Line 326  namespace LinuxSampler {
326    
327      int InstrumentsDb::GetDirectoryId(int ParentDirId, String DirName) {      int InstrumentsDb::GetDirectoryId(int ParentDirId, String DirName) {
328          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()));
329            DirName = toDbName(DirName);
330          std::stringstream sql;          std::stringstream sql;
331          sql << "SELECT dir_id FROM instr_dirs WHERE parent_dir_id=";          sql << "SELECT dir_id FROM instr_dirs WHERE parent_dir_id=";
332          sql << ParentDirId << " AND dir_name=?";          sql << ParentDirId << " AND dir_name=?";
333          return ExecSqlInt(sql.str(), DirName);          return ExecSqlInt(sql.str(), DirName);
334      }      }
335    
336        int InstrumentsDb::GetDirectoryId(int InstrId) {
337            dmsg(2,("InstrumentsDb: GetDirectoryId(InstrId=%d)\n", InstrId));
338            std::stringstream sql;
339            sql << "SELECT dir_id FROM instruments WHERE instr_id=" << InstrId;
340            return ExecSqlInt(sql.str());
341        }
342    
343      String InstrumentsDb::GetDirectoryName(int DirId) {      String InstrumentsDb::GetDirectoryName(int DirId) {
344          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);
345          String name = ExecSqlString(sql);          String name = ExecSqlString(sql);
# Line 274  namespace LinuxSampler { Line 364  namespace LinuxSampler {
364                  path = "/" + path;                  path = "/" + path;
365                  break;                  break;
366              }              }
367              path = GetDirectoryName(DirId) + path;              path = GetDirectoryName(DirId) + "/" + path;
368              DirId = GetParentDirectoryId(DirId);              DirId = GetParentDirectoryId(DirId);
369          }          }
370    
# Line 282  namespace LinuxSampler { Line 372  namespace LinuxSampler {
372    
373          return path;          return path;
374      }      }
375        
376        StringListPtr InstrumentsDb::GetInstrumentsByFile(String File) {
377            dmsg(2,("InstrumentsDb: GetInstrumentsByFile(File=%s)\n", File.c_str()));
378    
379            StringListPtr instrs(new std::vector<String>);
380            
381            BeginTransaction();
382            try {
383                File = toEscapedFsPath(File);
384                IntListPtr ids = ExecSqlIntList("SELECT instr_id FROM instruments WHERE instr_file=?", File);
385                
386                for (int i = 0; i < ids->size(); i++) {
387                    String name = GetInstrumentName(ids->at(i));
388                    String dir = GetDirectoryPath(GetDirectoryId(ids->at(i)));
389                    instrs->push_back(dir + name);
390                }
391            } catch (Exception e) {
392                EndTransaction();
393                throw e;
394            }
395            EndTransaction();
396            
397            return instrs;
398        }
399    
400      void InstrumentsDb::AddDirectory(String Dir) {      void InstrumentsDb::AddDirectory(String Dir) {
401          dmsg(2,("InstrumentsDb: AddDirectory(Dir=%s)\n", Dir.c_str()));          dmsg(2,("InstrumentsDb: AddDirectory(Dir=%s)\n", Dir.c_str()));
# Line 296  namespace LinuxSampler { Line 410  namespace LinuxSampler {
410    
411              String dirName = GetFileName(Dir);              String dirName = GetFileName(Dir);
412              if(ParentDir.empty() || dirName.empty()) {              if(ParentDir.empty() || dirName.empty()) {
413                  throw Exception("Failed to add DB directory: " + Dir);                  throw Exception("Failed to add DB directory: " + toEscapedPath(Dir));
414              }              }
415    
416              int id = GetDirectoryId(ParentDir);              int id = GetDirectoryId(ParentDir);
417              if (id == -1) throw Exception("DB directory doesn't exist: " + ParentDir);              if (id == -1) throw Exception("DB directory doesn't exist: " + toEscapedPath(ParentDir));
418              int id2 = GetDirectoryId(id, dirName);              int id2 = GetDirectoryId(id, dirName);
419              if (id2 != -1) throw Exception("DB directory already exist: " + Dir);              if (id2 != -1) throw Exception("DB directory already exist: " + toEscapedPath(Dir));
420              id2 = GetInstrumentId(id, dirName);              id2 = GetInstrumentId(id, dirName);
421              if (id2 != -1) throw Exception("Instrument with that name exist: " + Dir);              if (id2 != -1) throw Exception("Instrument with that name exist: " + toEscapedPath(Dir));
422    
423              std::stringstream sql;              std::stringstream sql;
424              sql << "INSERT INTO instr_dirs (parent_dir_id, dir_name) VALUES (";              sql << "INSERT INTO instr_dirs (parent_dir_id, dir_name) VALUES (";
425              sql << id << ", ?)";              sql << id << ", ?)";
426    
427              ExecSql(sql.str(), dirName);              ExecSql(sql.str(), toDbName(dirName));
428          } catch (Exception e) {          } catch (Exception e) {
429              EndTransaction();              EndTransaction();
430              throw e;              throw e;
# Line 329  namespace LinuxSampler { Line 443  namespace LinuxSampler {
443          BeginTransaction();          BeginTransaction();
444          try {          try {
445              int dirId = GetDirectoryId(Dir);              int dirId = GetDirectoryId(Dir);
446              if (dirId == -1) throw Exception("Unknown DB directory: " + Dir);              if (dirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
447              if (dirId == 0) throw Exception("Cannot delete the root directory: " + Dir);              if (dirId == 0) throw Exception("Cannot delete the root directory: " + Dir);
448              if(ParentDir.empty()) throw Exception("Unknown parent directory");              if(ParentDir.empty()) throw Exception("Unknown parent directory");
449              if (Force) RemoveDirectoryContent(dirId);              if (Force) RemoveDirectoryContent(dirId);
# Line 395  namespace LinuxSampler { Line 509  namespace LinuxSampler {
509    
510      bool InstrumentsDb::DirectoryExist(String Dir) {      bool InstrumentsDb::DirectoryExist(String Dir) {
511          dmsg(2,("InstrumentsDb: DirectoryExist(Dir=%s)\n", Dir.c_str()));          dmsg(2,("InstrumentsDb: DirectoryExist(Dir=%s)\n", Dir.c_str()));
512          bool b;          {
513                LockGuard lock(DbInstrumentsMutex);
514          DbInstrumentsMutex.Lock();              return GetDirectoryId(Dir) != -1;
         try { b = GetDirectoryId(Dir) != -1; }  
         catch (Exception e) {  
             DbInstrumentsMutex.Unlock();  
             throw e;  
515          }          }
         DbInstrumentsMutex.Unlock();  
   
         return b;  
516      }      }
517    
518      DbDirectory InstrumentsDb::GetDirectoryInfo(String Dir) {      DbDirectory InstrumentsDb::GetDirectoryInfo(String Dir) {
# Line 416  namespace LinuxSampler { Line 523  namespace LinuxSampler {
523    
524          try {          try {
525              int id = GetDirectoryId(Dir);              int id = GetDirectoryId(Dir);
526              if(id == -1) throw Exception("Unknown DB directory: " + Dir);              if(id == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
527    
528              sqlite3_stmt *pStmt = NULL;              sqlite3_stmt *pStmt = NULL;
529              std::stringstream sql;              std::stringstream sql;
# Line 439  namespace LinuxSampler { Line 546  namespace LinuxSampler {
546                  if (res != SQLITE_DONE) {                  if (res != SQLITE_DONE) {
547                      throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));                      throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
548                  } else {                  } else {
549                      throw Exception("Unknown DB directory: " + Dir);                      throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
550                  }                  }
551              }              }
552                            
# Line 456  namespace LinuxSampler { Line 563  namespace LinuxSampler {
563      void InstrumentsDb::RenameDirectory(String Dir, String Name) {      void InstrumentsDb::RenameDirectory(String Dir, String Name) {
564          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()));
565          CheckFileName(Name);          CheckFileName(Name);
566            String dbName = toDbName(Name);
567    
568          BeginTransaction();          BeginTransaction();
569          try {          try {
570              int dirId = GetDirectoryId(Dir);              int dirId = GetDirectoryId(Dir);
571              if (dirId == -1) throw Exception("Unknown DB directory: " + Dir);              if (dirId == -1) throw Exception("Unknown DB directory: " + toEscapedText(Dir));
572    
573              std::stringstream sql;              std::stringstream sql;
574              sql << "SELECT parent_dir_id FROM instr_dirs WHERE dir_id=" <<  dirId;              sql << "SELECT parent_dir_id FROM instr_dirs WHERE dir_id=" <<  dirId;
575    
576              int parent = ExecSqlInt(sql.str());              int parent = ExecSqlInt(sql.str());
577              if (parent == -1) throw Exception("Unknown parent directory: " + Dir);              if (parent == -1) throw Exception("Unknown parent directory: " + toEscapedPath(Dir));
578              if (GetDirectoryId(parent, Name) != -1) {  
579                  throw Exception("Cannot rename. Directory with that name already exists: " + Name);              if (GetDirectoryId(parent, dbName) != -1) {
580                    String s = toEscapedPath(Name);
581                    throw Exception("Cannot rename. Directory with that name already exists: " + s);
582              }              }
583    
584              if (GetInstrumentId(parent, Name) != -1) {              if (GetInstrumentId(parent, dbName) != -1) {
585                  throw Exception("Cannot rename. Instrument with that name exist: " + Dir);                  throw Exception("Cannot rename. Instrument with that name exist: " + toEscapedPath(Dir));
586              }              }
587    
588              sql.str("");              sql.str("");
589              sql << "UPDATE instr_dirs SET dir_name=? WHERE dir_id=" << dirId;              sql << "UPDATE instr_dirs SET dir_name=? WHERE dir_id=" << dirId;
590              ExecSql(sql.str(), Name);              ExecSql(sql.str(), dbName);
591          } catch (Exception e) {          } catch (Exception e) {
592              EndTransaction();              EndTransaction();
593              throw e;              throw e;
594          }          }
595    
596          EndTransaction();          EndTransaction();
597          FireDirectoryNameChanged(Dir, Name);          FireDirectoryNameChanged(Dir, toAbstractName(Name));
598      }      }
599    
600      void InstrumentsDb::MoveDirectory(String Dir, String Dst) {      void InstrumentsDb::MoveDirectory(String Dir, String Dst) {
# Line 497  namespace LinuxSampler { Line 607  namespace LinuxSampler {
607          BeginTransaction();          BeginTransaction();
608          try {          try {
609              int dirId = GetDirectoryId(Dir);              int dirId = GetDirectoryId(Dir);
610              if (dirId == -1) throw Exception("Unknown DB directory: " + Dir);              if (dirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
611              int dstId = GetDirectoryId(Dst);              int dstId = GetDirectoryId(Dst);
612              if (dstId == -1) throw Exception("Unknown DB directory: " + Dst);              if (dstId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dst));
613              if (dirId == dstId) {              if (dirId == dstId) {
614                  throw Exception("Cannot move directory to itself");                  throw Exception("Cannot move directory to itself");
615              }              }
# Line 515  namespace LinuxSampler { Line 625  namespace LinuxSampler {
625              String dirName = GetFileName(Dir);              String dirName = GetFileName(Dir);
626    
627              int id2 = GetDirectoryId(dstId, dirName);              int id2 = GetDirectoryId(dstId, dirName);
628              if (id2 != -1) throw Exception("DB directory already exist: " + dirName);              if (id2 != -1) throw Exception("DB directory already exist: " + toEscapedPath(dirName));
629              id2 = GetInstrumentId(dstId, dirName);              id2 = GetInstrumentId(dstId, dirName);
630              if (id2 != -1) throw Exception("Instrument with that name exist: " + dirName);              if (id2 != -1) throw Exception("Instrument with that name exist: " + toEscapedPath(dirName));
631    
632              std::stringstream sql;              std::stringstream sql;
633              sql << "UPDATE instr_dirs SET parent_dir_id=" << dstId;              sql << "UPDATE instr_dirs SET parent_dir_id=" << dstId;
# Line 543  namespace LinuxSampler { Line 653  namespace LinuxSampler {
653          BeginTransaction();          BeginTransaction();
654          try {          try {
655              int dirId = GetDirectoryId(Dir);              int dirId = GetDirectoryId(Dir);
656              if (dirId == -1) throw Exception("Unknown DB directory: " + Dir);              if (dirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
657              int dstId = GetDirectoryId(Dst);              int dstId = GetDirectoryId(Dst);
658              if (dstId == -1) throw Exception("Unknown DB directory: " + Dst);              if (dstId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dst));
659              if (dirId == dstId) {              if (dirId == dstId) {
660                  throw Exception("Cannot copy directory to itself");                  throw Exception("Cannot copy directory to itself");
661              }              }
# Line 561  namespace LinuxSampler { Line 671  namespace LinuxSampler {
671              String dirName = GetFileName(Dir);              String dirName = GetFileName(Dir);
672    
673              int id2 = GetDirectoryId(dstId, dirName);              int id2 = GetDirectoryId(dstId, dirName);
674              if (id2 != -1) throw Exception("DB directory already exist: " + dirName);              if (id2 != -1) throw Exception("DB directory already exist: " + toEscapedPath(dirName));
675              id2 = GetInstrumentId(dstId, dirName);              id2 = GetInstrumentId(dstId, dirName);
676              if (id2 != -1) throw Exception("Instrument with that name exist: " + dirName);              if (id2 != -1) throw Exception("Instrument with that name exist: " + toEscapedPath(dirName));
677    
678              DirectoryCopier directoryCopier(ParentDir, Dst);              DirectoryCopier directoryCopier(ParentDir, Dst);
679              DirectoryTreeWalk(Dir, &directoryCopier);              DirectoryTreeWalk(Dir, &directoryCopier);
# Line 581  namespace LinuxSampler { Line 691  namespace LinuxSampler {
691          BeginTransaction();          BeginTransaction();
692          try {          try {
693              int id = GetDirectoryId(Dir);              int id = GetDirectoryId(Dir);
694              if(id == -1) throw Exception("Unknown DB directory: " + Dir);              if(id == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
695    
696              std::stringstream sql;              std::stringstream sql;
697              sql << "UPDATE instr_dirs SET description=?,modified=CURRENT_TIMESTAMP ";              sql << "UPDATE instr_dirs SET description=?,modified=CURRENT_TIMESTAMP ";
# Line 597  namespace LinuxSampler { Line 707  namespace LinuxSampler {
707          FireDirectoryInfoChanged(Dir);          FireDirectoryInfoChanged(Dir);
708      }      }
709    
710      int InstrumentsDb::AddInstruments(ScanMode Mode, String DbDir, String FsDir, bool bBackground) {      int InstrumentsDb::AddInstruments(ScanMode Mode, String DbDir, String FsDir, bool bBackground, bool insDir) {
711          dmsg(2,("InstrumentsDb: AddInstruments(Mode=%d,DbDir=%s,FsDir=%s,bBackground=%d)\n", Mode, DbDir.c_str(), FsDir.c_str(), bBackground));          dmsg(2,("InstrumentsDb: AddInstruments(Mode=%d,DbDir=%s,FsDir=%s,bBackground=%d,insDir=%d)\n", Mode, DbDir.c_str(), FsDir.c_str(), bBackground, insDir));
712          if(!bBackground) {          if(!bBackground) {
713              switch (Mode) {              switch (Mode) {
714                  case NON_RECURSIVE:                  case NON_RECURSIVE:
715                      AddInstrumentsNonrecursive(DbDir, FsDir);                      AddInstrumentsNonrecursive(DbDir, FsDir, insDir);
716                      break;                      break;
717                  case RECURSIVE:                  case RECURSIVE:
718                      AddInstrumentsRecursive(DbDir, FsDir);                      AddInstrumentsRecursive(DbDir, FsDir, false, insDir);
719                      break;                      break;
720                  case FLAT:                  case FLAT:
721                      AddInstrumentsRecursive(DbDir, FsDir, true);                      AddInstrumentsRecursive(DbDir, FsDir, true, insDir);
722                      break;                      break;
723                  default:                  default:
724                      throw Exception("Unknown scan mode");                      throw Exception("Unknown scan mode");
# Line 619  namespace LinuxSampler { Line 729  namespace LinuxSampler {
729    
730          ScanJob job;          ScanJob job;
731          int jobId = Jobs.AddJob(job);          int jobId = Jobs.AddJob(job);
732          InstrumentsDbThread.Execute(new AddInstrumentsJob(jobId, Mode, DbDir, FsDir));          InstrumentsDbThread.Execute(new AddInstrumentsJob(jobId, Mode, DbDir, FsDir, insDir));
733    
734          return jobId;          return jobId;
735      }      }
# Line 627  namespace LinuxSampler { Line 737  namespace LinuxSampler {
737      int InstrumentsDb::AddInstruments(String DbDir, String FilePath, int Index, bool bBackground) {      int InstrumentsDb::AddInstruments(String DbDir, String FilePath, int Index, bool bBackground) {
738          dmsg(2,("InstrumentsDb: AddInstruments(DbDir=%s,FilePath=%s,Index=%d,bBackground=%d)\n", DbDir.c_str(), FilePath.c_str(), Index, bBackground));          dmsg(2,("InstrumentsDb: AddInstruments(DbDir=%s,FilePath=%s,Index=%d,bBackground=%d)\n", DbDir.c_str(), FilePath.c_str(), Index, bBackground));
739          if(!bBackground) {          if(!bBackground) {
740              AddInstruments(DbDir, FilePath, Index);              AddInstruments(DbDir, false, FilePath, Index);
741              return -1;              return -1;
742          }          }
743    
744          ScanJob job;          ScanJob job;
745          int jobId = Jobs.AddJob(job);          int jobId = Jobs.AddJob(job);
746          InstrumentsDbThread.Execute(new AddInstrumentsFromFileJob(jobId, DbDir, FilePath, Index));          InstrumentsDbThread.Execute(new AddInstrumentsFromFileJob(jobId, DbDir, FilePath, Index, false));
747    
748          return jobId;          return jobId;
749      }      }
750    
751      void InstrumentsDb::AddInstruments(String DbDir, String FilePath, int Index, ScanProgress* pProgress) {      void InstrumentsDb::AddInstruments(String DbDir, bool insDir, String FilePath, int Index, ScanProgress* pProgress) {
752          dmsg(2,("InstrumentsDb: AddInstruments(DbDir=%s,FilePath=%s,Index=%d)\n", DbDir.c_str(), FilePath.c_str(), Index));          dmsg(2,("InstrumentsDb: AddInstruments(DbDir=%s,insDir=%d,FilePath=%s,Index=%d)\n", DbDir.c_str(), insDir, FilePath.c_str(), Index));
753          if (DbDir.empty() || FilePath.empty()) return;          if (DbDir.empty() || FilePath.empty()) return;
754                    
755          DbInstrumentsMutex.Lock();          {
756          try {              LockGuard lock(DbInstrumentsMutex);
757    
758              int dirId = GetDirectoryId(DbDir);              int dirId = GetDirectoryId(DbDir);
759              if (dirId == -1) throw Exception("Invalid DB directory: " + DbDir);              if (dirId == -1) throw Exception("Invalid DB directory: " + toEscapedText(DbDir));
760    
761              struct stat statBuf;              File f = File(FilePath);
762              int res = stat(FilePath.c_str(), &statBuf);              if (!f.Exist()) {
             if (res) {  
763                  std::stringstream ss;                  std::stringstream ss;
764                  ss << "Fail to stat `" << FilePath << "`: " << strerror(errno);                  ss << "Fail to stat `" << FilePath << "`: " << f.GetErrorMsg();
765                  throw Exception(ss.str());                  throw Exception(ss.str());
766              }              }
767    
768              if (!S_ISREG(statBuf.st_mode)) {              if (!f.IsFile()) {
769                  std::stringstream ss;                  std::stringstream ss;
770                  ss << "`" << FilePath << "` is not an instrument file";                  ss << "`" << FilePath << "` is not an instrument file";
771                  throw Exception(ss.str());                  throw Exception(ss.str());
772              }              }
773    
774              AddInstrumentsFromFile(DbDir, FilePath, Index, pProgress);              String dir = insDir ? PrepareSubdirectory(DbDir, FilePath) : DbDir;
775          } catch (Exception e) {              AddInstrumentsFromFile(dir, FilePath, Index, pProgress);
             DbInstrumentsMutex.Unlock();  
             throw e;  
776          }          }
   
         DbInstrumentsMutex.Unlock();  
777      }      }
778    
779      void InstrumentsDb::AddInstrumentsNonrecursive(String DbDir, String FsDir, ScanProgress* pProgress) {      void InstrumentsDb::AddInstrumentsNonrecursive(String DbDir, String FsDir, bool insDir, ScanProgress* pProgress) {
780          dmsg(2,("InstrumentsDb: AddInstrumentsNonrecursive(DbDir=%s,FsDir=%s)\n", DbDir.c_str(), FsDir.c_str()));          dmsg(2,("InstrumentsDb: AddInstrumentsNonrecursive(DbDir=%s,FsDir=%s,insDir=%d)\n", DbDir.c_str(), FsDir.c_str(), insDir));
781          if (DbDir.empty() || FsDir.empty()) return;          if (DbDir.empty() || FsDir.empty()) return;
782                    
783          DbInstrumentsMutex.Lock();          {
784          try {              LockGuard lock(DbInstrumentsMutex);
785    
786              int dirId = GetDirectoryId(DbDir);              int dirId = GetDirectoryId(DbDir);
787              if (dirId == -1) throw Exception("Invalid DB directory: " + DbDir);              if (dirId == -1) throw Exception("Invalid DB directory: " + toEscapedPath(DbDir));
788    
789              struct stat statBuf;              File f = File(FsDir);
790              int res = stat(FsDir.c_str(), &statBuf);              if (!f.Exist()) {
             if (res) {  
791                  std::stringstream ss;                  std::stringstream ss;
792                  ss << "Fail to stat `" << FsDir << "`: " << strerror(errno);                  ss << "Fail to stat `" << FsDir << "`: " << f.GetErrorMsg();
793                  throw Exception(ss.str());                  throw Exception(ss.str());
794              }              }
795    
796              if (!S_ISDIR(statBuf.st_mode)) {              if (!f.IsDirectory()) {
797                  throw Exception("Directory expected");                  throw Exception("Directory expected: " + FsDir);
798              }              }
799                            
800              if (FsDir.at(FsDir.length() - 1) != '/') FsDir.append("/");              if (FsDir.at(FsDir.length() - 1) != File::DirSeparator) {
801                    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;  
802              }              }
803                
804              struct dirent* pEnt = readdir(pDir);              try {
805              while (pEnt != NULL) {                  FileListPtr fileList = File::GetFiles(FsDir);
806                  if (pEnt->d_type != DT_REG) {                  for (int i = 0; i < fileList->size(); i++) {
807                      pEnt = readdir(pDir);                      String dir = insDir ? PrepareSubdirectory(DbDir, fileList->at(i)) : DbDir;
808                      continue;                                          AddInstrumentsFromFile(dir, FsDir + fileList->at(i), -1, pProgress);
809                  }                  }
810                } catch(Exception e) {
811                  AddInstrumentsFromFile(DbDir, FsDir + String(pEnt->d_name), -1, pProgress);                  e.PrintMessage();
                 pEnt = readdir(pDir);  
812              }              }
   
             if (closedir(pDir)) {  
                 std::stringstream ss;  
                 ss << "Failed to close directory `" << FsDir << "`: ";  
                 ss << strerror(errno);  
                 std::cerr << ss.str();  
             }  
         } catch (Exception e) {  
             DbInstrumentsMutex.Unlock();  
             throw e;  
813          }          }
   
         DbInstrumentsMutex.Unlock();  
814      }      }
815    
816      void InstrumentsDb::AddInstrumentsRecursive(String DbDir, String FsDir, bool Flat, ScanProgress* pProgress) {      void InstrumentsDb::AddInstrumentsRecursive(String DbDir, String FsDir, bool Flat, bool insDir, ScanProgress* pProgress) {
817          dmsg(2,("InstrumentsDb: AddInstrumentsRecursive(DbDir=%s,FsDir=%s,Flat=%d)\n", DbDir.c_str(), FsDir.c_str(), Flat));          dmsg(2,("InstrumentsDb: AddInstrumentsRecursive(DbDir=%s,FsDir=%s,Flat=%d,insDir=%d)\n", DbDir.c_str(), FsDir.c_str(), Flat, insDir));
818          if (pProgress != NULL) {          if (pProgress != NULL) {
819              pProgress->SetTotalFileCount(InstrumentFileCounter::Count(FsDir));              InstrumentFileCounter c;
820                pProgress->SetTotalFileCount(c.Count(FsDir));
821          }          }
822    
823          DirectoryScanner::Scan(DbDir, FsDir, Flat, pProgress);          DirectoryScanner d;
824            d.Scan(DbDir, FsDir, Flat, insDir, pProgress);
825      }      }
826    
827      int InstrumentsDb::GetInstrumentCount(int DirId) {      int InstrumentsDb::GetInstrumentCount(int DirId) {
# Line 766  namespace LinuxSampler { Line 853  namespace LinuxSampler {
853          }          }
854          EndTransaction();          EndTransaction();
855    
856          if (i == -1) throw Exception("Unknown Db directory: " + Dir);          if (i == -1) throw Exception("Unknown Db directory: " + toEscapedPath(Dir));
857          return i;          return i;
858      }      }
859    
# Line 782  namespace LinuxSampler { Line 869  namespace LinuxSampler {
869          BeginTransaction();          BeginTransaction();
870          try {          try {
871              int dirId = GetDirectoryId(Dir);              int dirId = GetDirectoryId(Dir);
872              if(dirId == -1) throw Exception("Unknown DB directory: " + Dir);              if(dirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
873    
874              StringListPtr pInstrs;              StringListPtr pInstrs;
875    
# Line 796  namespace LinuxSampler { Line 883  namespace LinuxSampler {
883                  sql << "SELECT instr_name FROM instruments WHERE dir_id=" << dirId;                  sql << "SELECT instr_name FROM instruments WHERE dir_id=" << dirId;
884    
885                  pInstrs = ExecSqlStringList(sql.str());                  pInstrs = ExecSqlStringList(sql.str());
886                    // Converting to abstract names
887                    for (int i = 0; i < pInstrs->size(); i++) {
888                        for (int j = 0; j < pInstrs->at(i).length(); j++) {
889                            if (pInstrs->at(i).at(j) == '/') pInstrs->at(i).at(j) = '\0';
890                        }
891                    }
892              }              }
893              EndTransaction();              EndTransaction();
894              return pInstrs;              return pInstrs;
# Line 820  namespace LinuxSampler { Line 913  namespace LinuxSampler {
913          std::stringstream sql;          std::stringstream sql;
914          sql << "SELECT instr_id FROM instruments WHERE dir_id=";          sql << "SELECT instr_id FROM instruments WHERE dir_id=";
915          sql << DirId << " AND instr_name=?";          sql << DirId << " AND instr_name=?";
916          return ExecSqlInt(sql.str(), InstrName);          return ExecSqlInt(sql.str(), toDbName(InstrName));
917      }      }
918    
919      String InstrumentsDb::GetInstrumentName(int InstrId) {      String InstrumentsDb::GetInstrumentName(int InstrId) {
920          dmsg(2,("InstrumentsDb: GetInstrumentName(InstrId=%d)\n", InstrId));          dmsg(2,("InstrumentsDb: GetInstrumentName(InstrId=%d)\n", InstrId));
921          std::stringstream sql;          std::stringstream sql;
922          sql << "SELECT instr_name FROM instruments WHERE instr_id=" << InstrId;          sql << "SELECT instr_name FROM instruments WHERE instr_id=" << InstrId;
923          return ExecSqlString(sql.str());          return toAbstractName(ExecSqlString(sql.str()));
924      }      }
925            
926      void InstrumentsDb::RemoveInstrument(String Instr) {      void InstrumentsDb::RemoveInstrument(String Instr) {
# Line 839  namespace LinuxSampler { Line 932  namespace LinuxSampler {
932          try {          try {
933              int instrId = GetInstrumentId(Instr);              int instrId = GetInstrumentId(Instr);
934              if(instrId == -1) {              if(instrId == -1) {
935                  throw Exception("The specified instrument does not exist: " + Instr);                  throw Exception("The specified instrument does not exist: " + toEscapedPath(Instr));
936              }              }
937              RemoveInstrument(instrId);              RemoveInstrument(instrId);
938          } catch (Exception e) {          } catch (Exception e) {
# Line 874  namespace LinuxSampler { Line 967  namespace LinuxSampler {
967          BeginTransaction();          BeginTransaction();
968          try {          try {
969              int id = GetInstrumentId(Instr);              int id = GetInstrumentId(Instr);
970              if(id == -1) throw Exception("Unknown DB instrument: " + Instr);              if(id == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
971              i = GetInstrumentInfo(id);              i = GetInstrumentInfo(id);
972          } catch (Exception e) {          } catch (Exception e) {
973              EndTransaction();              EndTransaction();
# Line 933  namespace LinuxSampler { Line 1026  namespace LinuxSampler {
1026          BeginTransaction();          BeginTransaction();
1027          try {          try {
1028              int dirId = GetDirectoryId(GetDirectoryPath(Instr));              int dirId = GetDirectoryId(GetDirectoryPath(Instr));
1029              if (dirId == -1) throw Exception("Unknown DB instrument: " + Instr);              if (dirId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1030    
1031              int instrId = GetInstrumentId(dirId, GetFileName(Instr));              int instrId = GetInstrumentId(dirId, GetFileName(Instr));
1032              if (instrId == -1) throw Exception("Unknown DB instrument: " + Instr);              if (instrId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1033    
1034              if (GetInstrumentId(dirId, Name) != -1) {              if (GetInstrumentId(dirId, Name) != -1) {
1035                  throw Exception("Cannot rename. Instrument with that name already exists: " + Name);                  String s = toEscapedPath(Name);
1036                    throw Exception("Cannot rename. Instrument with that name already exists: " + s);
1037              }              }
1038    
1039              if (GetDirectoryId(dirId, Name) != -1) {              if (GetDirectoryId(dirId, Name) != -1) {
1040                  throw Exception("Cannot rename. Directory with that name already exists: " + Name);                  String s = toEscapedPath(Name);
1041                    throw Exception("Cannot rename. Directory with that name already exists: " + s);
1042              }              }
1043    
1044              std::stringstream sql;              std::stringstream sql;
1045              sql << "UPDATE instruments SET instr_name=? WHERE instr_id=" << instrId;              sql << "UPDATE instruments SET instr_name=? WHERE instr_id=" << instrId;
1046              ExecSql(sql.str(), Name);              ExecSql(sql.str(), toDbName(Name));
1047          } catch (Exception e) {          } catch (Exception e) {
1048              EndTransaction();              EndTransaction();
1049              throw e;              throw e;
1050          }          }
1051          EndTransaction();          EndTransaction();
1052          FireInstrumentNameChanged(Instr, Name);          FireInstrumentNameChanged(Instr, toAbstractName(Name));
1053      }      }
1054    
1055      void InstrumentsDb::MoveInstrument(String Instr, String Dst) {      void InstrumentsDb::MoveInstrument(String Instr, String Dst) {
# Line 964  namespace LinuxSampler { Line 1059  namespace LinuxSampler {
1059    
1060          BeginTransaction();          BeginTransaction();
1061          try {          try {
1062              int dirId = GetDirectoryId(GetDirectoryPath(Instr));              int dirId = GetDirectoryId(ParentDir);
1063              if (dirId == -1) throw Exception("Unknown DB instrument: " + Instr);              if (dirId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1064    
1065              String instrName = GetFileName(Instr);              String instrName = GetFileName(Instr);
1066              int instrId = GetInstrumentId(dirId, instrName);              int instrId = GetInstrumentId(dirId, instrName);
1067              if (instrId == -1) throw Exception("Unknown DB instrument: " + Instr);              if (instrId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1068    
1069              int dstId = GetDirectoryId(Dst);              int dstId = GetDirectoryId(Dst);
1070              if (dstId == -1) throw Exception("Unknown DB directory: " + Dst);              if (dstId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dst));
1071              if (dirId == dstId) {              if (dirId == dstId) {
1072                  EndTransaction();                  EndTransaction();
1073                  return;                  return;
1074              }              }
1075    
1076              if (GetInstrumentId(dstId, instrName) != -1) {              if (GetInstrumentId(dstId, instrName) != -1) {
1077                  throw Exception("Cannot move. Instrument with that name already exists: " + instrName);                  String s = toEscapedPath(instrName);
1078                    throw Exception("Cannot move. Instrument with that name already exists: " + s);
1079              }              }
1080    
1081              if (GetDirectoryId(dstId, instrName) != -1) {              if (GetDirectoryId(dstId, instrName) != -1) {
1082                  throw Exception("Cannot move. Directory with that name already exists: " + instrName);                  String s = toEscapedPath(instrName);
1083                    throw Exception("Cannot move. Directory with that name already exists: " + s);
1084              }              }
1085    
1086              std::stringstream sql;              std::stringstream sql;
# Line 1007  namespace LinuxSampler { Line 1104  namespace LinuxSampler {
1104          BeginTransaction();          BeginTransaction();
1105          try {          try {
1106              int dirId = GetDirectoryId(GetDirectoryPath(Instr));              int dirId = GetDirectoryId(GetDirectoryPath(Instr));
1107              if (dirId == -1) throw Exception("Unknown DB instrument: " + Instr);              if (dirId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1108    
1109              String instrName = GetFileName(Instr);              String instrName = GetFileName(Instr);
1110              int instrId = GetInstrumentId(dirId, instrName);              int instrId = GetInstrumentId(dirId, instrName);
1111              if (instrId == -1) throw Exception("Unknown DB instrument: " + Instr);              if (instrId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1112    
1113              int dstId = GetDirectoryId(Dst);              int dstId = GetDirectoryId(Dst);
1114              if (dstId == -1) throw Exception("Unknown DB directory: " + Dst);              if (dstId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dst));
1115              if (dirId == dstId) {              if (dirId == dstId) {
1116                  EndTransaction();                  EndTransaction();
1117                  return;                  return;
1118              }              }
1119    
             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);  
             }  
   
1120              CopyInstrument(instrId, instrName, dstId, Dst);              CopyInstrument(instrId, instrName, dstId, Dst);
1121          } catch (Exception e) {          } catch (Exception e) {
1122              EndTransaction();              EndTransaction();
# Line 1038  namespace LinuxSampler { Line 1127  namespace LinuxSampler {
1127      }      }
1128    
1129      void InstrumentsDb::CopyInstrument(int InstrId, String InstrName, int DstDirId, String DstDir) {      void InstrumentsDb::CopyInstrument(int InstrId, String InstrName, int DstDirId, String DstDir) {
1130            if (GetInstrumentId(DstDirId, InstrName) != -1) {
1131                String s = toEscapedPath(InstrName);
1132                throw Exception("Cannot copy. Instrument with that name already exists: " + s);
1133            }
1134    
1135            if (GetDirectoryId(DstDirId, InstrName) != -1) {
1136                String s = toEscapedPath(InstrName);
1137                throw Exception("Cannot copy. Directory with that name already exists: " + s);
1138            }
1139    
1140          DbInstrument i = GetInstrumentInfo(InstrId);          DbInstrument i = GetInstrumentInfo(InstrId);
1141          sqlite3_stmt *pStmt = NULL;          sqlite3_stmt *pStmt = NULL;
1142          std::stringstream sql;          std::stringstream sql;
# Line 1051  namespace LinuxSampler { Line 1150  namespace LinuxSampler {
1150              throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));              throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1151          }          }
1152    
1153          BindTextParam(pStmt, 1, InstrName);          String s = toDbName(InstrName);
1154            BindTextParam(pStmt, 1, s);
1155          BindTextParam(pStmt, 2, i.InstrFile);          BindTextParam(pStmt, 2, i.InstrFile);
1156          BindTextParam(pStmt, 3, i.FormatFamily);          BindTextParam(pStmt, 3, i.FormatFamily);
1157          BindTextParam(pStmt, 4, i.FormatVersion);          BindTextParam(pStmt, 4, i.FormatVersion);
# Line 1076  namespace LinuxSampler { Line 1176  namespace LinuxSampler {
1176          BeginTransaction();          BeginTransaction();
1177          try {          try {
1178              int id = GetInstrumentId(Instr);              int id = GetInstrumentId(Instr);
1179              if(id == -1) throw Exception("Unknown DB instrument: " + Instr);              if(id == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1180    
1181              std::stringstream sql;              std::stringstream sql;
1182              sql << "UPDATE instruments SET description=?,modified=CURRENT_TIMESTAMP ";              sql << "UPDATE instruments SET description=?,modified=CURRENT_TIMESTAMP ";
# Line 1110  namespace LinuxSampler { Line 1210  namespace LinuxSampler {
1210                  }                  }
1211              }              }
1212          } catch(Exception e) {          } catch(Exception e) {
1213              std::cerr << e.Message() << std::endl;              e.PrintMessage();
1214          }          }
1215      }      }
1216    
1217      void InstrumentsDb::AddGigInstruments(String DbDir, String File, int Index, ScanProgress* pProgress) {      void InstrumentsDb::AddGigInstruments(String DbDir, String FilePath, int Index, ScanProgress* pProgress) {
1218          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));
1219          int dirId = GetDirectoryId(DbDir);          int dirId = GetDirectoryId(DbDir);
1220          if (dirId == -1) throw Exception("Invalid DB directory: " + DbDir);          if (dirId == -1) throw Exception("Invalid DB directory: " + toEscapedPath(DbDir));
1221    
1222          struct stat statBuf;          File f = File(FilePath);
1223          int res = stat(File.c_str(), &statBuf);          if (!f.Exist()) {
         if (res) {  
1224              std::stringstream ss;              std::stringstream ss;
1225              ss << "Fail to stat `" << File << "`: " << strerror(errno);              ss << "Fail to stat `" << FilePath << "`: " << f.GetErrorMsg();
1226              throw Exception(ss.str());              throw Exception(ss.str());
1227          }          }
1228    
1229          if (!S_ISREG(statBuf.st_mode)) {          if (!f.IsFile()) {
1230              std::stringstream ss;              std::stringstream ss;
1231              ss << "`" << File << "` is not a regular file";              ss << "`" << FilePath << "` is not a regular file";
1232              throw Exception(ss.str());              throw Exception(ss.str());
1233          }          }
1234    
1235            bool unlocked = false;
1236          RIFF::File* riff = NULL;          RIFF::File* riff = NULL;
1237          gig::File* gig = NULL;          gig::File* gig = NULL;
1238          try {          try {
1239              riff = new RIFF::File(File);              riff = new RIFF::File(FilePath);
1240              gig::File* gig = new gig::File(riff);              gig::File* gig = new gig::File(riff);
1241                gig->SetAutoLoad(false); // avoid time consuming samples scanning
1242    
1243              std::stringstream sql;              std::stringstream sql;
1244              sql << "INSERT INTO instruments (dir_id,instr_name,instr_file,";              sql << "INSERT INTO instruments (dir_id,instr_name,instr_file,";
1245              sql << "instr_nr,format_family,format_version,instr_size,";              sql << "instr_nr,format_family,format_version,instr_size,";
1246              sql << "description,is_drum,product,artists,keywords) VALUES (";              sql << "description,is_drum,product,artists,keywords) VALUES (";
1247              sql << dirId << ",?,?,?,'GIG',?," << statBuf.st_size << ",?,?,?,?,?)";              sql << dirId << ",?,?,?,'GIG',?," << f.GetSize() << ",?,?,?,?,?)";
1248    
1249              sqlite3_stmt* pStmt = NULL;              sqlite3_stmt* pStmt = NULL;
1250    
# Line 1152  namespace LinuxSampler { Line 1253  namespace LinuxSampler {
1253                  throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));                  throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1254              }              }
1255    
1256              BindTextParam(pStmt, 2, File);              String s = FilePath;
1257                s = toEscapedFsPath(s);
1258                BindTextParam(pStmt, 2, s);
1259              String ver = "";              String ver = "";
1260              if (gig->pVersion != NULL) ver = ToString(gig->pVersion->major);              if (gig->pVersion != NULL) ver = ToString(gig->pVersion->major);
1261              BindTextParam(pStmt, 4, ver);              BindTextParam(pStmt, 4, ver);
1262    
1263              if (Index == -1) {              if (Index == -1) {
1264                  int instrIndex = 0;                  int instrIndex = 0;
1265                    // Assume that it's locked and should be unlocked at this point
1266                    // to be able to use the database from another threads
1267                    if (!InTransaction) {
1268                        DbInstrumentsMutex.Unlock();
1269                        unlocked = true;
1270                    } else {
1271                        std::cerr << "Shouldn't be in transaction when adding instruments." << std::endl;
1272                    }
1273    
1274                  if (pProgress != NULL) gig->GetInstrument(0, &(pProgress->GigFileProgress)); // TODO: this workaround should be fixed                  if (pProgress != NULL) gig->GetInstrument(0, &(pProgress->GigFileProgress)); // TODO: this workaround should be fixed
1275                  gig::Instrument* pInstrument = gig->GetFirstInstrument();                  gig::Instrument* pInstrument = gig->GetFirstInstrument();
1276    
1277                    if (!InTransaction) DbInstrumentsMutex.Lock();
1278                  while (pInstrument) {                  while (pInstrument) {
1279                      BindTextParam(pStmt, 7, gig->pInfo->Product);                      BindTextParam(pStmt, 7, gig->pInfo->Product);
1280                      BindTextParam(pStmt, 8, gig->pInfo->Artists);                      BindTextParam(pStmt, 8, gig->pInfo->Artists);
1281                      BindTextParam(pStmt, 9, gig->pInfo->Keywords);                      BindTextParam(pStmt, 9, gig->pInfo->Keywords);
1282                      AddGigInstrument(pStmt, DbDir, dirId, File, pInstrument, instrIndex);                      AddGigInstrument(pStmt, DbDir, dirId, FilePath, pInstrument, instrIndex);
1283    
1284                      instrIndex++;                      instrIndex++;
1285                      pInstrument = gig->GetNextInstrument();                      pInstrument = gig->GetNextInstrument();
# Line 1178  namespace LinuxSampler { Line 1292  namespace LinuxSampler {
1292                      BindTextParam(pStmt, 7, gig->pInfo->Product);                      BindTextParam(pStmt, 7, gig->pInfo->Product);
1293                      BindTextParam(pStmt, 8, gig->pInfo->Artists);                      BindTextParam(pStmt, 8, gig->pInfo->Artists);
1294                      BindTextParam(pStmt, 9, gig->pInfo->Keywords);                      BindTextParam(pStmt, 9, gig->pInfo->Keywords);
1295                      AddGigInstrument(pStmt, DbDir, dirId, File, pInstrument, Index);                      AddGigInstrument(pStmt, DbDir, dirId, FilePath, pInstrument, Index);
1296                  }                  }
1297              }              }
1298    
# Line 1188  namespace LinuxSampler { Line 1302  namespace LinuxSampler {
1302          } catch (RIFF::Exception e) {          } catch (RIFF::Exception e) {
1303              if (gig != NULL) delete gig;              if (gig != NULL) delete gig;
1304              if (riff != NULL) delete riff;              if (riff != NULL) delete riff;
1305                if (unlocked) DbInstrumentsMutex.Lock();
1306              std::stringstream ss;              std::stringstream ss;
1307              ss << "Failed to scan `" << File << "`: " << e.Message;              ss << "Failed to scan `" << FilePath << "`: " << e.Message;
1308                            
1309              throw Exception(ss.str());              throw Exception(ss.str());
1310          } catch (Exception e) {          } catch (Exception e) {
1311              if (gig != NULL) delete gig;              if (gig != NULL) delete gig;
1312              if (riff != NULL) delete riff;              if (riff != NULL) delete riff;
1313                if (unlocked) DbInstrumentsMutex.Lock();
1314              throw e;              throw e;
1315          } catch (...) {          } catch (...) {
1316              if (gig != NULL) delete gig;              if (gig != NULL) delete gig;
1317              if (riff != NULL) delete riff;              if (riff != NULL) delete riff;
1318              throw Exception("Failed to scan `" + File + "`");              if (unlocked) DbInstrumentsMutex.Lock();
1319                throw Exception("Failed to scan `" + FilePath + "`");
1320          }          }
1321      }      }
1322    
1323      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) {
1324            dmsg(2,("InstrumentsDb: AddGigInstrument(DbDir=%s,DirId=%d,File=%s,Index=%d)\n", DbDir.c_str(), DirId, File.c_str(), Index));
1325          String name = pInstrument->pInfo->Name;          String name = pInstrument->pInfo->Name;
1326          if (name == "") return;          if (name == "") return;
1327          name = GetUniqueInstrumentName(DirId, name);          name = GetUniqueName(DirId, name);
1328                    
1329          std::stringstream sql2;          std::stringstream sql2;
1330          sql2 << "SELECT COUNT(*) FROM instruments WHERE instr_file=? AND ";          sql2 << "SELECT COUNT(*) FROM instruments WHERE instr_file=? AND ";
1331          sql2 << "instr_nr=" << Index;          sql2 << "instr_nr=" << Index;
1332          if (ExecSqlInt(sql2.str(), File) > 0) return;          String s = toEscapedFsPath(File);
1333            if (ExecSqlInt(sql2.str(), s) > 0) return;
1334    
1335          BindTextParam(pStmt, 1, name);          BindTextParam(pStmt, 1, name);
1336          BindIntParam(pStmt, 3, Index);          BindIntParam(pStmt, 3, Index);
# Line 1240  namespace LinuxSampler { Line 1359  namespace LinuxSampler {
1359          FireInstrumentCountChanged(DbDir);          FireInstrumentCountChanged(DbDir);
1360      }      }
1361    
1362      void InstrumentsDb::DirectoryTreeWalk(String Path, DirectoryHandler* pHandler) {      void InstrumentsDb::DirectoryTreeWalk(String AbstractPath, DirectoryHandler* pHandler) {
1363          int DirId = GetDirectoryId(Path);          int DirId = GetDirectoryId(AbstractPath);
1364          if(DirId == -1) throw Exception("Unknown DB directory: " + Path);          if(DirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(AbstractPath));
1365          DirectoryTreeWalk(pHandler, Path, DirId, 0);          DirectoryTreeWalk(pHandler, AbstractPath, DirId, 0);
1366      }      }
1367    
1368      void InstrumentsDb::DirectoryTreeWalk(DirectoryHandler* pHandler, String Path, int DirId, int Level) {      void InstrumentsDb::DirectoryTreeWalk(DirectoryHandler* pHandler, String AbstractPath, int DirId, int Level) {
1369          if(Level == 1000) throw Exception("Possible infinite loop detected");          if(Level == 1000) throw Exception("Possible infinite loop detected");
1370          pHandler->ProcessDirectory(Path, DirId);          pHandler->ProcessDirectory(AbstractPath, DirId);
1371                    
1372          String s;          String s;
1373          StringListPtr pDirs = GetDirectories(DirId);          StringListPtr pDirs = GetDirectories(DirId);
1374          for(int i = 0; i < pDirs->size(); i++) {          for(int i = 0; i < pDirs->size(); i++) {
1375              if (Path.length() == 1 && Path.at(0) == '/') s = "/" + pDirs->at(i);              if (AbstractPath.length() == 1 && AbstractPath.at(0) == '/') {
1376              else s = Path + "/" + pDirs->at(i);                  s = "/" + pDirs->at(i);
1377                } else {
1378                    s = AbstractPath + "/" + pDirs->at(i);
1379                }
1380              DirectoryTreeWalk(pHandler, s, GetDirectoryId(DirId, pDirs->at(i)), Level + 1);              DirectoryTreeWalk(pHandler, s, GetDirectoryId(DirId, pDirs->at(i)), Level + 1);
1381          }          }
1382      }      }
# Line 1266  namespace LinuxSampler { Line 1388  namespace LinuxSampler {
1388          BeginTransaction();          BeginTransaction();
1389          try {          try {
1390              int DirId = GetDirectoryId(Dir);              int DirId = GetDirectoryId(Dir);
1391              if(DirId == -1) throw Exception("Unknown DB directory: " + Dir);              if(DirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
1392    
1393              if (Recursive) DirectoryTreeWalk(Dir, &directoryFinder);              if (Recursive) DirectoryTreeWalk(Dir, &directoryFinder);
1394              else directoryFinder.ProcessDirectory(Dir, DirId);              else directoryFinder.ProcessDirectory(Dir, DirId);
# Line 1286  namespace LinuxSampler { Line 1408  namespace LinuxSampler {
1408          BeginTransaction();          BeginTransaction();
1409          try {          try {
1410              int DirId = GetDirectoryId(Dir);              int DirId = GetDirectoryId(Dir);
1411              if(DirId == -1) throw Exception("Unknown DB directory: " + Dir);              if(DirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
1412    
1413              if (Recursive) DirectoryTreeWalk(Dir, &instrumentFinder);              if (Recursive) DirectoryTreeWalk(Dir, &instrumentFinder);
1414              else instrumentFinder.ProcessDirectory(Dir, DirId);              else instrumentFinder.ProcessDirectory(Dir, DirId);
# Line 1298  namespace LinuxSampler { Line 1420  namespace LinuxSampler {
1420    
1421          return instrumentFinder.GetInstruments();          return instrumentFinder.GetInstruments();
1422      }      }
1423        
1424        StringListPtr InstrumentsDb::FindLostInstrumentFiles() {
1425            dmsg(2,("InstrumentsDb: FindLostInstrumentFiles()\n"));
1426    
1427            BeginTransaction();
1428            try {
1429                StringListPtr files = ExecSqlStringList("SELECT DISTINCT instr_file FROM instruments");
1430                StringListPtr result(new std::vector<String>);
1431                for (int i = 0; i < files->size(); i++) {
1432                    File f(toNonEscapedFsPath(files->at(i)));
1433                    if (!f.Exist()) result->push_back(files->at(i));
1434                }
1435                return result;
1436            } catch (Exception e) {
1437                EndTransaction();
1438                throw e;
1439            }
1440            EndTransaction();
1441        }
1442        
1443        void InstrumentsDb::SetInstrumentFilePath(String OldPath, String NewPath) {
1444            if (OldPath == NewPath) return;
1445            StringListPtr instrs;
1446            BeginTransaction();
1447            try {
1448                std::vector<String> params(2);
1449                params[0] = toEscapedFsPath(NewPath);
1450                params[1] = toEscapedFsPath(OldPath);
1451                instrs = GetInstrumentsByFile(OldPath);
1452                ExecSql("UPDATE instruments SET instr_file=? WHERE instr_file=?", params);
1453            } catch (Exception e) {
1454                EndTransaction();
1455                throw e;
1456            }
1457            EndTransaction();
1458            
1459            for (int i = 0; i < instrs->size(); i++) {
1460                FireInstrumentInfoChanged(instrs->at(i));
1461            }
1462        }
1463    
1464      void InstrumentsDb::BeginTransaction() {      void InstrumentsDb::BeginTransaction() {
1465          dmsg(2,("InstrumentsDb: BeginTransaction(InTransaction=%d)\n", InTransaction));          dmsg(2,("InstrumentsDb: BeginTransaction(InTransaction=%d)\n", InTransaction));
# Line 1332  namespace LinuxSampler { Line 1494  namespace LinuxSampler {
1494          }          }
1495          InTransaction = false;          InTransaction = false;
1496                    
1497          if(db == NULL) {          if (db == NULL) {
1498              DbInstrumentsMutex.Unlock();              DbInstrumentsMutex.Unlock();
1499              return;              return;
1500          }          }
# Line 1359  namespace LinuxSampler { Line 1521  namespace LinuxSampler {
1521    
1522      void InstrumentsDb::ExecSql(String Sql) {      void InstrumentsDb::ExecSql(String Sql) {
1523          dmsg(2,("InstrumentsDb: ExecSql(Sql=%s)\n", Sql.c_str()));          dmsg(2,("InstrumentsDb: ExecSql(Sql=%s)\n", Sql.c_str()));
1524          sqlite3_stmt *pStmt = NULL;          std::vector<String> Params;
1525                    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);  
1526      }      }
1527    
1528      void InstrumentsDb::ExecSql(String Sql, String Param) {      void InstrumentsDb::ExecSql(String Sql, String Param) {
1529          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()));
1530            std::vector<String> Params;
1531            Params.push_back(Param);
1532            ExecSql(Sql, Params);
1533        }
1534    
1535        void InstrumentsDb::ExecSql(String Sql, std::vector<String>& Params) {
1536            dmsg(2,("InstrumentsDb: ExecSql(Sql=%s,Params)\n", Sql.c_str()));
1537          sqlite3_stmt *pStmt = NULL;          sqlite3_stmt *pStmt = NULL;
1538                    
1539          int res = sqlite3_prepare(GetDb(), Sql.c_str(), -1, &pStmt, NULL);          int res = sqlite3_prepare(GetDb(), Sql.c_str(), -1, &pStmt, NULL);
# Line 1385  namespace LinuxSampler { Line 1542  namespace LinuxSampler {
1542              throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));              throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1543          }          }
1544    
1545          BindTextParam(pStmt, 1, Param);          for(int i = 0; i < Params.size(); i++) {
1546                BindTextParam(pStmt, i + 1, Params[i]);
1547            }
1548    
1549          res = sqlite3_step(pStmt);          res = sqlite3_step(pStmt);
1550          if (res != SQLITE_DONE) {          if (res != SQLITE_DONE) {
# Line 1467  namespace LinuxSampler { Line 1626  namespace LinuxSampler {
1626      }      }
1627    
1628      IntListPtr InstrumentsDb::ExecSqlIntList(String Sql) {      IntListPtr InstrumentsDb::ExecSqlIntList(String Sql) {
1629            dmsg(2,("InstrumentsDb: ExecSqlIntList(Sql=%s)\n", Sql.c_str()));
1630            std::vector<String> Params;
1631            return ExecSqlIntList(Sql, Params);
1632        }
1633    
1634        IntListPtr InstrumentsDb::ExecSqlIntList(String Sql, String Param) {
1635            dmsg(2,("InstrumentsDb: ExecSqlIntList(Sql=%s,Param=%s)\n", Sql.c_str(), Param.c_str()));
1636            std::vector<String> Params;
1637            Params.push_back(Param);
1638            return ExecSqlIntList(Sql, Params);
1639        }
1640    
1641        IntListPtr InstrumentsDb::ExecSqlIntList(String Sql, std::vector<String>& Params) {
1642            dmsg(2,("InstrumentsDb: ExecSqlIntList(Sql=%s)\n", Sql.c_str()));
1643          IntListPtr intList(new std::vector<int>);          IntListPtr intList(new std::vector<int>);
1644                    
1645          sqlite3_stmt *pStmt = NULL;          sqlite3_stmt *pStmt = NULL;
# Line 1476  namespace LinuxSampler { Line 1649  namespace LinuxSampler {
1649              throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));              throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1650          }          }
1651                    
1652            for(int i = 0; i < Params.size(); i++) {
1653                BindTextParam(pStmt, i + 1, Params[i]);
1654            }
1655            
1656          res = sqlite3_step(pStmt);          res = sqlite3_step(pStmt);
1657          while(res == SQLITE_ROW) {          while(res == SQLITE_ROW) {
1658              intList->push_back(sqlite3_column_int(pStmt, 0));              intList->push_back(sqlite3_column_int(pStmt, 0));
# Line 1493  namespace LinuxSampler { Line 1670  namespace LinuxSampler {
1670      }      }
1671            
1672      StringListPtr InstrumentsDb::ExecSqlStringList(String Sql) {      StringListPtr InstrumentsDb::ExecSqlStringList(String Sql) {
1673            dmsg(2,("InstrumentsDb: ExecSqlStringList(Sql=%s)\n", Sql.c_str()));
1674          StringListPtr stringList(new std::vector<String>);          StringListPtr stringList(new std::vector<String>);
1675                    
1676          sqlite3_stmt *pStmt = NULL;          sqlite3_stmt *pStmt = NULL;
# Line 1520  namespace LinuxSampler { Line 1698  namespace LinuxSampler {
1698    
1699      void InstrumentsDb::BindTextParam(sqlite3_stmt* pStmt, int Index, String Text) {      void InstrumentsDb::BindTextParam(sqlite3_stmt* pStmt, int Index, String Text) {
1700          if (pStmt == NULL) return;          if (pStmt == NULL) return;
1701          int res = sqlite3_bind_text(pStmt, Index, Text.c_str(), -1, SQLITE_STATIC);          int res = sqlite3_bind_text(pStmt, Index, Text.c_str(), -1, SQLITE_TRANSIENT);
1702          if (res != SQLITE_OK) {          if (res != SQLITE_OK) {
1703              sqlite3_finalize(pStmt);              sqlite3_finalize(pStmt);
1704              throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));              throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
# Line 1536  namespace LinuxSampler { Line 1714  namespace LinuxSampler {
1714          }          }
1715      }      }
1716    
1717    #ifndef WIN32
1718      void InstrumentsDb::Regexp(sqlite3_context* pContext, int argc, sqlite3_value** ppValue) {      void InstrumentsDb::Regexp(sqlite3_context* pContext, int argc, sqlite3_value** ppValue) {
1719          if (argc != 2) return;          if (argc != 2) return;
1720    
# Line 1546  namespace LinuxSampler { Line 1725  namespace LinuxSampler {
1725              sqlite3_result_int(pContext, 1);              sqlite3_result_int(pContext, 1);
1726          }          }
1727      }      }
1728    #endif
1729    
1730      String InstrumentsDb::GetDirectoryPath(String File) {      String InstrumentsDb::GetDirectoryPath(String File) {
1731          if (File.empty()) return String("");          if (File.empty()) return String("");
# Line 1588  namespace LinuxSampler { Line 1768  namespace LinuxSampler {
1768          return Dir.substr(0, i);          return Dir.substr(0, i);
1769      }      }
1770    
1771        void InstrumentsDb::Format() {
1772            {
1773                LockGuard lock(DbInstrumentsMutex);
1774    
1775                if (db != NULL) {
1776                    sqlite3_close(db);
1777                    db = NULL;
1778                }
1779    
1780                if (DbFile.empty()) DbFile = GetDefaultDBLocation();
1781                String bkp = DbFile + ".bkp";
1782                remove(bkp.c_str());
1783                if (rename(DbFile.c_str(), bkp.c_str()) && errno != ENOENT) {
1784                    throw Exception(String("Failed to backup database: ") + strerror(errno));
1785                }
1786            
1787                String f = DbFile;
1788                DbFile = "";
1789                CreateInstrumentsDb(f);
1790            }
1791            FireDirectoryCountChanged("/");
1792            FireInstrumentCountChanged("/");
1793        }
1794    
1795      void InstrumentsDb::CheckFileName(String File) {      void InstrumentsDb::CheckFileName(String File) {
1796          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);  
         }  
1797      }      }
1798    
1799      String InstrumentsDb::GetUniqueInstrumentName(int DirId, String Name) {      String InstrumentsDb::GetUniqueName(int DirId, String Name) {
1800          dmsg(2,("InstrumentsDb: GetUniqueInstrumentName(DirId=%d,Name=%s)\n", DirId, Name.c_str()));          dmsg(2,("InstrumentsDb: GetUniqueInstrumentName(DirId=%d,Name=%s)\n", DirId, Name.c_str()));
1801    
1802          if (GetInstrumentId(DirId, Name) == -1 && GetDirectoryId(DirId, Name) == -1) return Name;          if (GetInstrumentId(DirId, Name) == -1 && GetDirectoryId(DirId, Name) == -1) return Name;
# Line 1610  namespace LinuxSampler { Line 1811  namespace LinuxSampler {
1811    
1812          throw Exception("Unable to find an unique name: " + Name);          throw Exception("Unable to find an unique name: " + Name);
1813      }      }
1814        
1815        String InstrumentsDb::PrepareSubdirectory(String DbDir, String FsPath) {
1816            std::string dir = Path::getBaseName(FsPath);
1817            dir = toAbstractName(dir);
1818            if(dir.empty()) dir = "New Directory";
1819            dir = GetUniqueName(GetDirectoryId(DbDir), dir);
1820            dir = AppendNode(DbDir, dir);
1821            AddDirectory(dir);
1822            return dir;
1823        }
1824    
1825        String InstrumentsDb::AppendNode(String DbDir, String Node) {
1826            if(DbDir.length() == 1 && DbDir.at(0) == '/') return DbDir + Node;
1827            if(DbDir.at(DbDir.length() - 1) == '/') return DbDir + Node;
1828            return DbDir + "/" + Node;
1829        }
1830    
1831        String InstrumentsDb::toDbName(String AbstractName) {
1832            for (int i = 0; i < AbstractName.length(); i++) {
1833                if (AbstractName.at(i) == '\0') AbstractName.at(i) = '/';
1834            }
1835            return AbstractName;
1836        }
1837    
1838        String InstrumentsDb::toEscapedPath(String AbstractName) {
1839            for (int i = 0; i < AbstractName.length(); i++) {
1840                if (AbstractName.at(i) == '\0')      AbstractName.replace(i++, 1, "\\x2f");
1841                else if (AbstractName.at(i) == '\\') AbstractName.replace(i++, 1, "\\\\");
1842                else if (AbstractName.at(i) == '\'') AbstractName.replace(i++, 1, "\\'");
1843                else if (AbstractName.at(i) == '"')  AbstractName.replace(i++, 1, "\\\"");
1844                else if (AbstractName.at(i) == '\r') AbstractName.replace(i++, 1, "\\r");
1845                else if (AbstractName.at(i) == '\n') AbstractName.replace(i++, 1, "\\n");
1846            }
1847            return AbstractName;
1848        }
1849        
1850        String InstrumentsDb::toEscapedText(String text) {
1851            for (int i = 0; i < text.length(); i++) {
1852                if (text.at(i) == '\\')      text.replace(i++, 1, "\\\\");
1853                else if (text.at(i) == '\'') text.replace(i++, 1, "\\'");
1854                else if (text.at(i) == '"')  text.replace(i++, 1, "\\\"");
1855                else if (text.at(i) == '\r') text.replace(i++, 1, "\\r");
1856                else if (text.at(i) == '\n') text.replace(i++, 1, "\\n");
1857            }
1858            return text;
1859        }
1860        
1861        String InstrumentsDb::toNonEscapedText(String text) {
1862            String sb;
1863            for (int i = 0; i < text.length(); i++) {
1864                char c = text.at(i);
1865                            if(c == '\\') {
1866                                    if(i >= text.length()) {
1867                                            std::cerr << "Broken escape sequence!" << std::endl;
1868                                            break;
1869                                    }
1870                                    char c2 = text.at(++i);
1871                                    if(c2 == '\'')      sb.push_back('\'');
1872                                    else if(c2 == '"')  sb.push_back('"');
1873                                    else if(c2 == '\\') sb.push_back('\\');
1874                                    else if(c2 == 'r')  sb.push_back('\r');
1875                                    else if(c2 == 'n')  sb.push_back('\n');
1876                                    else std::cerr << "Unknown escape sequence \\" << c2 << std::endl;
1877                            } else {
1878                                    sb.push_back(c);
1879                            }
1880            }
1881            return sb;
1882        }
1883        
1884        String InstrumentsDb::toEscapedFsPath(String FsPath) {
1885    #ifdef WIN32
1886            replace(FsPath.begin(), FsPath.end(), '\\', '/');
1887    #endif
1888            return toEscapedText(FsPath);
1889        }
1890        
1891        String InstrumentsDb::toNonEscapedFsPath(String FsPath) {
1892            FsPath = toNonEscapedText(FsPath);
1893    #ifdef WIN32
1894            replace(FsPath.begin(), FsPath.end(), '/', '\\');
1895    #endif
1896            return FsPath;
1897        }
1898        
1899        String InstrumentsDb::toAbstractName(String DbName) {
1900            for (int i = 0; i < DbName.length(); i++) {
1901                if (DbName.at(i) == '/') DbName.at(i) = '\0';
1902            }
1903            return DbName;
1904        }
1905    
1906      void InstrumentsDb::FireDirectoryCountChanged(String Dir) {      void InstrumentsDb::FireDirectoryCountChanged(String Dir) {
1907          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
# Line 1654  namespace LinuxSampler { Line 1946  namespace LinuxSampler {
1946      }      }
1947    
1948  } // namespace LinuxSampler  } // namespace LinuxSampler
   
 #endif // HAVE_SQLITE3  

Legend:
Removed from v.1200  
changed lines
  Added in v.3091

  ViewVC Help
Powered by ViewVC