/[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 2427 by persson, Sat Mar 2 07:03:04 2013 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;          File f = File(FilePath);
45          int res = stat(File.c_str(), &statBuf);          if (f.Exist()) {
46          if (!res) {              throw Exception("File exists: " + FilePath);
             throw Exception("File exists: " + File);  
47          }          }
48                    
49          GetInstrumentsDb()->SetDbFile(File);          GetInstrumentsDb()->SetDbFile(FilePath);
50    
51          String sql =          String sql =
52              "  CREATE TABLE instr_dirs (                                      "              "  CREATE TABLE instr_dirs (                                      "
# Line 58  namespace LinuxSampler { Line 62  namespace LinuxSampler {
62                    
63          GetInstrumentsDb()->ExecSql(sql);          GetInstrumentsDb()->ExecSql(sql);
64    
65          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, '/');";
66          GetInstrumentsDb()->ExecSql(sql);          GetInstrumentsDb()->ExecSql(sql);
67    
68          sql =          sql =
# Line 87  namespace LinuxSampler { Line 91  namespace LinuxSampler {
91    
92      InstrumentsDb::InstrumentsDb() {      InstrumentsDb::InstrumentsDb() {
93          db = NULL;          db = NULL;
         DbInstrumentsMutex = Mutex();  
94          InTransaction = false;          InTransaction = false;
95      }      }
96    
# Line 95  namespace LinuxSampler { Line 98  namespace LinuxSampler {
98          if (db != NULL) sqlite3_close(db);          if (db != NULL) sqlite3_close(db);
99      }      }
100            
     void InstrumentsDb::Destroy() {  
         if (pInstrumentsDb != NULL) {  
             delete pInstrumentsDb;  
             pInstrumentsDb = NULL;  
         }  
     }  
   
101      void InstrumentsDb::AddInstrumentsDbListener(InstrumentsDb::Listener* l) {      void InstrumentsDb::AddInstrumentsDbListener(InstrumentsDb::Listener* l) {
102          llInstrumentsDbListeners.AddListener(l);          llInstrumentsDbListeners.AddListener(l);
103      }      }
# Line 111  namespace LinuxSampler { Line 107  namespace LinuxSampler {
107      }      }
108            
109      InstrumentsDb* InstrumentsDb::GetInstrumentsDb() {      InstrumentsDb* InstrumentsDb::GetInstrumentsDb() {
110          return pInstrumentsDb;          return &instance;
111      }      }
112            
113      void InstrumentsDb::SetDbFile(String File) {      void InstrumentsDb::SetDbFile(String File) {
114          DbInstrumentsMutex.Lock();          LockGuard lock(DbInstrumentsMutex);
115          if (File.empty() || DbFile.length() > 0) {          if (File.empty() || DbFile.length() > 0) {
             DbInstrumentsMutex.Unlock();  
116              throw Exception("Failed to set the database file");              throw Exception("Failed to set the database file");
117          }          }
118          DbFile = File;          DbFile = File;
         DbInstrumentsMutex.Unlock();  
119      }      }
120    
121      sqlite3* InstrumentsDb::GetDb() {      sqlite3* InstrumentsDb::GetDb() {
122          if ( db != NULL) return db;          if ( db != NULL) return db;
123    
124          if (DbFile.empty()) DbFile = "/var/lib/linuxsampler/instruments.db";          if (DbFile.empty()) {
125                        #ifndef WIN32
126                        DbFile = CONFIG_DEFAULT_INSTRUMENTS_DB_LOCATION;
127                            #else
128                            char *userprofile = getenv("USERPROFILE");
129                            if(userprofile) {
130                                String DbPath = userprofile;
131                                    DbPath += "\\.linuxsampler";
132                                DbFile = DbPath + "\\instruments.db";
133                                    File InstrumentsDbFile(DbFile);
134                                    // if no DB exists create the subdir and then the DB
135                                    if( !InstrumentsDbFile.Exist() ) {
136                                        _mkdir( DbPath.c_str() );
137                                            // formats the DB, which creates a new instruments.db file
138                                            Format();
139                                    }
140                        }
141                            else {
142                                // in case USERPROFILE is not set (which should not occur)
143                                DbFile = "instruments.db";
144                            }
145                            #endif
146                }
147                    #if defined(__APPLE__)  /* 20071224 Toshi Nagata  */
148                    if (DbFile.find("~") == 0)
149                            DbFile.replace(0, 1, getenv("HOME"));
150                    #endif
151          int rc = sqlite3_open(DbFile.c_str(), &db);          int rc = sqlite3_open(DbFile.c_str(), &db);
152          if (rc) {          if (rc) {
153              sqlite3_close(db);              sqlite3_close(db);
154              db = NULL;              db = NULL;
155              throw Exception("Cannot open instruments database: " + DbFile);              throw Exception("Cannot open instruments database: " + DbFile);
156          }          }
157    #ifndef WIN32
158          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);
159          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."); }
160    #endif
161    
162            // TODO: remove this in the next version
163            try {
164                int i = ExecSqlInt("SELECT parent_dir_id FROM instr_dirs WHERE dir_id=0");
165                // The parent ID of the root directory should be -2 now.
166                if(i != -2) ExecSql("UPDATE instr_dirs SET parent_dir_id=-2 WHERE dir_id=0");
167            } catch(Exception e) { }
168            ////////////////////////////////////////
169                    
170          return db;          return db;
171      }      }
# Line 149  namespace LinuxSampler { Line 179  namespace LinuxSampler {
179                    
180          int count = ExecSqlInt(sql.str());          int count = ExecSqlInt(sql.str());
181    
         // 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--;  
182          return count;          return count;
183      }      }
184    
# Line 173  namespace LinuxSampler { Line 200  namespace LinuxSampler {
200              throw e;              throw e;
201          }          }
202          EndTransaction();          EndTransaction();
203          if (i == -1) throw Exception("Unkown DB directory: " + Dir);          if (i == -1) throw Exception("Unkown DB directory: " + toEscapedPath(Dir));
204                    
205          return i;          return i;
206      }      }
# Line 192  namespace LinuxSampler { Line 219  namespace LinuxSampler {
219          BeginTransaction();          BeginTransaction();
220          try {          try {
221              int dirId = GetDirectoryId(Dir);              int dirId = GetDirectoryId(Dir);
222              if(dirId == -1) throw Exception("Unknown DB directory: " + Dir);              if(dirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
223    
224              StringListPtr pDirs;              StringListPtr pDirs;
225              if (Recursive) {              if (Recursive) {
# Line 215  namespace LinuxSampler { Line 242  namespace LinuxSampler {
242          std::stringstream sql;          std::stringstream sql;
243          sql << "SELECT dir_name FROM instr_dirs ";          sql << "SELECT dir_name FROM instr_dirs ";
244          sql << "WHERE parent_dir_id=" << DirId << " AND dir_id!=0";          sql << "WHERE parent_dir_id=" << DirId << " AND dir_id!=0";
245          return ExecSqlStringList(sql.str());          StringListPtr dirs = ExecSqlStringList(sql.str());
246    
247            for (int i = 0; i < dirs->size(); i++) {
248                for (int j = 0; j < dirs->at(i).length(); j++) {
249                    if (dirs->at(i).at(j) == '/') dirs->at(i).at(j) = '\0';
250                }
251            }
252    
253            return dirs;
254      }      }
255    
256      int InstrumentsDb::GetDirectoryId(String Dir) {      int InstrumentsDb::GetDirectoryId(String Dir) {
# Line 244  namespace LinuxSampler { Line 279  namespace LinuxSampler {
279    
280      int InstrumentsDb::GetDirectoryId(int ParentDirId, String DirName) {      int InstrumentsDb::GetDirectoryId(int ParentDirId, String DirName) {
281          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()));
282            DirName = toDbName(DirName);
283          std::stringstream sql;          std::stringstream sql;
284          sql << "SELECT dir_id FROM instr_dirs WHERE parent_dir_id=";          sql << "SELECT dir_id FROM instr_dirs WHERE parent_dir_id=";
285          sql << ParentDirId << " AND dir_name=?";          sql << ParentDirId << " AND dir_name=?";
286          return ExecSqlInt(sql.str(), DirName);          return ExecSqlInt(sql.str(), DirName);
287      }      }
288    
289        int InstrumentsDb::GetDirectoryId(int InstrId) {
290            dmsg(2,("InstrumentsDb: GetDirectoryId(InstrId=%d)\n", InstrId));
291            std::stringstream sql;
292            sql << "SELECT dir_id FROM instruments WHERE instr_id=" << InstrId;
293            return ExecSqlInt(sql.str());
294        }
295    
296      String InstrumentsDb::GetDirectoryName(int DirId) {      String InstrumentsDb::GetDirectoryName(int DirId) {
297          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);
298          String name = ExecSqlString(sql);          String name = ExecSqlString(sql);
# Line 274  namespace LinuxSampler { Line 317  namespace LinuxSampler {
317                  path = "/" + path;                  path = "/" + path;
318                  break;                  break;
319              }              }
320              path = GetDirectoryName(DirId) + path;              path = GetDirectoryName(DirId) + "/" + path;
321              DirId = GetParentDirectoryId(DirId);              DirId = GetParentDirectoryId(DirId);
322          }          }
323    
# Line 282  namespace LinuxSampler { Line 325  namespace LinuxSampler {
325    
326          return path;          return path;
327      }      }
328        
329        StringListPtr InstrumentsDb::GetInstrumentsByFile(String File) {
330            dmsg(2,("InstrumentsDb: GetInstrumentsByFile(File=%s)\n", File.c_str()));
331    
332            StringListPtr instrs(new std::vector<String>);
333            
334            BeginTransaction();
335            try {
336                File = toEscapedFsPath(File);
337                IntListPtr ids = ExecSqlIntList("SELECT instr_id FROM instruments WHERE instr_file=?", File);
338                
339                for (int i = 0; i < ids->size(); i++) {
340                    String name = GetInstrumentName(ids->at(i));
341                    String dir = GetDirectoryPath(GetDirectoryId(ids->at(i)));
342                    instrs->push_back(dir + name);
343                }
344            } catch (Exception e) {
345                EndTransaction();
346                throw e;
347            }
348            EndTransaction();
349            
350            return instrs;
351        }
352    
353      void InstrumentsDb::AddDirectory(String Dir) {      void InstrumentsDb::AddDirectory(String Dir) {
354          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 363  namespace LinuxSampler {
363    
364              String dirName = GetFileName(Dir);              String dirName = GetFileName(Dir);
365              if(ParentDir.empty() || dirName.empty()) {              if(ParentDir.empty() || dirName.empty()) {
366                  throw Exception("Failed to add DB directory: " + Dir);                  throw Exception("Failed to add DB directory: " + toEscapedPath(Dir));
367              }              }
368    
369              int id = GetDirectoryId(ParentDir);              int id = GetDirectoryId(ParentDir);
370              if (id == -1) throw Exception("DB directory doesn't exist: " + ParentDir);              if (id == -1) throw Exception("DB directory doesn't exist: " + toEscapedPath(ParentDir));
371              int id2 = GetDirectoryId(id, dirName);              int id2 = GetDirectoryId(id, dirName);
372              if (id2 != -1) throw Exception("DB directory already exist: " + Dir);              if (id2 != -1) throw Exception("DB directory already exist: " + toEscapedPath(Dir));
373              id2 = GetInstrumentId(id, dirName);              id2 = GetInstrumentId(id, dirName);
374              if (id2 != -1) throw Exception("Instrument with that name exist: " + Dir);              if (id2 != -1) throw Exception("Instrument with that name exist: " + toEscapedPath(Dir));
375    
376              std::stringstream sql;              std::stringstream sql;
377              sql << "INSERT INTO instr_dirs (parent_dir_id, dir_name) VALUES (";              sql << "INSERT INTO instr_dirs (parent_dir_id, dir_name) VALUES (";
378              sql << id << ", ?)";              sql << id << ", ?)";
379    
380              ExecSql(sql.str(), dirName);              ExecSql(sql.str(), toDbName(dirName));
381          } catch (Exception e) {          } catch (Exception e) {
382              EndTransaction();              EndTransaction();
383              throw e;              throw e;
# Line 329  namespace LinuxSampler { Line 396  namespace LinuxSampler {
396          BeginTransaction();          BeginTransaction();
397          try {          try {
398              int dirId = GetDirectoryId(Dir);              int dirId = GetDirectoryId(Dir);
399              if (dirId == -1) throw Exception("Unknown DB directory: " + Dir);              if (dirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
400              if (dirId == 0) throw Exception("Cannot delete the root directory: " + Dir);              if (dirId == 0) throw Exception("Cannot delete the root directory: " + Dir);
401              if(ParentDir.empty()) throw Exception("Unknown parent directory");              if(ParentDir.empty()) throw Exception("Unknown parent directory");
402              if (Force) RemoveDirectoryContent(dirId);              if (Force) RemoveDirectoryContent(dirId);
# Line 395  namespace LinuxSampler { Line 462  namespace LinuxSampler {
462    
463      bool InstrumentsDb::DirectoryExist(String Dir) {      bool InstrumentsDb::DirectoryExist(String Dir) {
464          dmsg(2,("InstrumentsDb: DirectoryExist(Dir=%s)\n", Dir.c_str()));          dmsg(2,("InstrumentsDb: DirectoryExist(Dir=%s)\n", Dir.c_str()));
465          bool b;          {
466                LockGuard lock(DbInstrumentsMutex);
467          DbInstrumentsMutex.Lock();              return GetDirectoryId(Dir) != -1;
         try { b = GetDirectoryId(Dir) != -1; }  
         catch (Exception e) {  
             DbInstrumentsMutex.Unlock();  
             throw e;  
468          }          }
         DbInstrumentsMutex.Unlock();  
   
         return b;  
469      }      }
470    
471      DbDirectory InstrumentsDb::GetDirectoryInfo(String Dir) {      DbDirectory InstrumentsDb::GetDirectoryInfo(String Dir) {
# Line 416  namespace LinuxSampler { Line 476  namespace LinuxSampler {
476    
477          try {          try {
478              int id = GetDirectoryId(Dir);              int id = GetDirectoryId(Dir);
479              if(id == -1) throw Exception("Unknown DB directory: " + Dir);              if(id == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
480    
481              sqlite3_stmt *pStmt = NULL;              sqlite3_stmt *pStmt = NULL;
482              std::stringstream sql;              std::stringstream sql;
# Line 439  namespace LinuxSampler { Line 499  namespace LinuxSampler {
499                  if (res != SQLITE_DONE) {                  if (res != SQLITE_DONE) {
500                      throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));                      throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
501                  } else {                  } else {
502                      throw Exception("Unknown DB directory: " + Dir);                      throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
503                  }                  }
504              }              }
505                            
# Line 456  namespace LinuxSampler { Line 516  namespace LinuxSampler {
516      void InstrumentsDb::RenameDirectory(String Dir, String Name) {      void InstrumentsDb::RenameDirectory(String Dir, String Name) {
517          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()));
518          CheckFileName(Name);          CheckFileName(Name);
519            String dbName = toDbName(Name);
520    
521          BeginTransaction();          BeginTransaction();
522          try {          try {
523              int dirId = GetDirectoryId(Dir);              int dirId = GetDirectoryId(Dir);
524              if (dirId == -1) throw Exception("Unknown DB directory: " + Dir);              if (dirId == -1) throw Exception("Unknown DB directory: " + toEscapedText(Dir));
525    
526              std::stringstream sql;              std::stringstream sql;
527              sql << "SELECT parent_dir_id FROM instr_dirs WHERE dir_id=" <<  dirId;              sql << "SELECT parent_dir_id FROM instr_dirs WHERE dir_id=" <<  dirId;
528    
529              int parent = ExecSqlInt(sql.str());              int parent = ExecSqlInt(sql.str());
530              if (parent == -1) throw Exception("Unknown parent directory: " + Dir);              if (parent == -1) throw Exception("Unknown parent directory: " + toEscapedPath(Dir));
531              if (GetDirectoryId(parent, Name) != -1) {  
532                  throw Exception("Cannot rename. Directory with that name already exists: " + Name);              if (GetDirectoryId(parent, dbName) != -1) {
533                    String s = toEscapedPath(Name);
534                    throw Exception("Cannot rename. Directory with that name already exists: " + s);
535              }              }
536    
537              if (GetInstrumentId(parent, Name) != -1) {              if (GetInstrumentId(parent, dbName) != -1) {
538                  throw Exception("Cannot rename. Instrument with that name exist: " + Dir);                  throw Exception("Cannot rename. Instrument with that name exist: " + toEscapedPath(Dir));
539              }              }
540    
541              sql.str("");              sql.str("");
542              sql << "UPDATE instr_dirs SET dir_name=? WHERE dir_id=" << dirId;              sql << "UPDATE instr_dirs SET dir_name=? WHERE dir_id=" << dirId;
543              ExecSql(sql.str(), Name);              ExecSql(sql.str(), dbName);
544          } catch (Exception e) {          } catch (Exception e) {
545              EndTransaction();              EndTransaction();
546              throw e;              throw e;
547          }          }
548    
549          EndTransaction();          EndTransaction();
550          FireDirectoryNameChanged(Dir, Name);          FireDirectoryNameChanged(Dir, toAbstractName(Name));
551      }      }
552    
553      void InstrumentsDb::MoveDirectory(String Dir, String Dst) {      void InstrumentsDb::MoveDirectory(String Dir, String Dst) {
# Line 497  namespace LinuxSampler { Line 560  namespace LinuxSampler {
560          BeginTransaction();          BeginTransaction();
561          try {          try {
562              int dirId = GetDirectoryId(Dir);              int dirId = GetDirectoryId(Dir);
563              if (dirId == -1) throw Exception("Unknown DB directory: " + Dir);              if (dirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
564              int dstId = GetDirectoryId(Dst);              int dstId = GetDirectoryId(Dst);
565              if (dstId == -1) throw Exception("Unknown DB directory: " + Dst);              if (dstId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dst));
566              if (dirId == dstId) {              if (dirId == dstId) {
567                  throw Exception("Cannot move directory to itself");                  throw Exception("Cannot move directory to itself");
568              }              }
# Line 515  namespace LinuxSampler { Line 578  namespace LinuxSampler {
578              String dirName = GetFileName(Dir);              String dirName = GetFileName(Dir);
579    
580              int id2 = GetDirectoryId(dstId, dirName);              int id2 = GetDirectoryId(dstId, dirName);
581              if (id2 != -1) throw Exception("DB directory already exist: " + dirName);              if (id2 != -1) throw Exception("DB directory already exist: " + toEscapedPath(dirName));
582              id2 = GetInstrumentId(dstId, dirName);              id2 = GetInstrumentId(dstId, dirName);
583              if (id2 != -1) throw Exception("Instrument with that name exist: " + dirName);              if (id2 != -1) throw Exception("Instrument with that name exist: " + toEscapedPath(dirName));
584    
585              std::stringstream sql;              std::stringstream sql;
586              sql << "UPDATE instr_dirs SET parent_dir_id=" << dstId;              sql << "UPDATE instr_dirs SET parent_dir_id=" << dstId;
# Line 543  namespace LinuxSampler { Line 606  namespace LinuxSampler {
606          BeginTransaction();          BeginTransaction();
607          try {          try {
608              int dirId = GetDirectoryId(Dir);              int dirId = GetDirectoryId(Dir);
609              if (dirId == -1) throw Exception("Unknown DB directory: " + Dir);              if (dirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
610              int dstId = GetDirectoryId(Dst);              int dstId = GetDirectoryId(Dst);
611              if (dstId == -1) throw Exception("Unknown DB directory: " + Dst);              if (dstId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dst));
612              if (dirId == dstId) {              if (dirId == dstId) {
613                  throw Exception("Cannot copy directory to itself");                  throw Exception("Cannot copy directory to itself");
614              }              }
# Line 561  namespace LinuxSampler { Line 624  namespace LinuxSampler {
624              String dirName = GetFileName(Dir);              String dirName = GetFileName(Dir);
625    
626              int id2 = GetDirectoryId(dstId, dirName);              int id2 = GetDirectoryId(dstId, dirName);
627              if (id2 != -1) throw Exception("DB directory already exist: " + dirName);              if (id2 != -1) throw Exception("DB directory already exist: " + toEscapedPath(dirName));
628              id2 = GetInstrumentId(dstId, dirName);              id2 = GetInstrumentId(dstId, dirName);
629              if (id2 != -1) throw Exception("Instrument with that name exist: " + dirName);              if (id2 != -1) throw Exception("Instrument with that name exist: " + toEscapedPath(dirName));
630    
631              DirectoryCopier directoryCopier(ParentDir, Dst);              DirectoryCopier directoryCopier(ParentDir, Dst);
632              DirectoryTreeWalk(Dir, &directoryCopier);              DirectoryTreeWalk(Dir, &directoryCopier);
# Line 581  namespace LinuxSampler { Line 644  namespace LinuxSampler {
644          BeginTransaction();          BeginTransaction();
645          try {          try {
646              int id = GetDirectoryId(Dir);              int id = GetDirectoryId(Dir);
647              if(id == -1) throw Exception("Unknown DB directory: " + Dir);              if(id == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
648    
649              std::stringstream sql;              std::stringstream sql;
650              sql << "UPDATE instr_dirs SET description=?,modified=CURRENT_TIMESTAMP ";              sql << "UPDATE instr_dirs SET description=?,modified=CURRENT_TIMESTAMP ";
# Line 597  namespace LinuxSampler { Line 660  namespace LinuxSampler {
660          FireDirectoryInfoChanged(Dir);          FireDirectoryInfoChanged(Dir);
661      }      }
662    
663      int InstrumentsDb::AddInstruments(ScanMode Mode, String DbDir, String FsDir, bool bBackground) {      int InstrumentsDb::AddInstruments(ScanMode Mode, String DbDir, String FsDir, bool bBackground, bool insDir) {
664          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));
665          if(!bBackground) {          if(!bBackground) {
666              switch (Mode) {              switch (Mode) {
667                  case NON_RECURSIVE:                  case NON_RECURSIVE:
668                      AddInstrumentsNonrecursive(DbDir, FsDir);                      AddInstrumentsNonrecursive(DbDir, FsDir, insDir);
669                      break;                      break;
670                  case RECURSIVE:                  case RECURSIVE:
671                      AddInstrumentsRecursive(DbDir, FsDir);                      AddInstrumentsRecursive(DbDir, FsDir, false, insDir);
672                      break;                      break;
673                  case FLAT:                  case FLAT:
674                      AddInstrumentsRecursive(DbDir, FsDir, true);                      AddInstrumentsRecursive(DbDir, FsDir, true, insDir);
675                      break;                      break;
676                  default:                  default:
677                      throw Exception("Unknown scan mode");                      throw Exception("Unknown scan mode");
# Line 619  namespace LinuxSampler { Line 682  namespace LinuxSampler {
682    
683          ScanJob job;          ScanJob job;
684          int jobId = Jobs.AddJob(job);          int jobId = Jobs.AddJob(job);
685          InstrumentsDbThread.Execute(new AddInstrumentsJob(jobId, Mode, DbDir, FsDir));          InstrumentsDbThread.Execute(new AddInstrumentsJob(jobId, Mode, DbDir, FsDir, insDir));
686    
687          return jobId;          return jobId;
688      }      }
# Line 627  namespace LinuxSampler { Line 690  namespace LinuxSampler {
690      int InstrumentsDb::AddInstruments(String DbDir, String FilePath, int Index, bool bBackground) {      int InstrumentsDb::AddInstruments(String DbDir, String FilePath, int Index, bool bBackground) {
691          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));
692          if(!bBackground) {          if(!bBackground) {
693              AddInstruments(DbDir, FilePath, Index);              AddInstruments(DbDir, false, FilePath, Index);
694              return -1;              return -1;
695          }          }
696    
697          ScanJob job;          ScanJob job;
698          int jobId = Jobs.AddJob(job);          int jobId = Jobs.AddJob(job);
699          InstrumentsDbThread.Execute(new AddInstrumentsFromFileJob(jobId, DbDir, FilePath, Index));          InstrumentsDbThread.Execute(new AddInstrumentsFromFileJob(jobId, DbDir, FilePath, Index, false));
700    
701          return jobId;          return jobId;
702      }      }
703    
704      void InstrumentsDb::AddInstruments(String DbDir, String FilePath, int Index, ScanProgress* pProgress) {      void InstrumentsDb::AddInstruments(String DbDir, bool insDir, String FilePath, int Index, ScanProgress* pProgress) {
705          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));
706          if (DbDir.empty() || FilePath.empty()) return;          if (DbDir.empty() || FilePath.empty()) return;
707                    
708          DbInstrumentsMutex.Lock();          {
709          try {              LockGuard lock(DbInstrumentsMutex);
710    
711              int dirId = GetDirectoryId(DbDir);              int dirId = GetDirectoryId(DbDir);
712              if (dirId == -1) throw Exception("Invalid DB directory: " + DbDir);              if (dirId == -1) throw Exception("Invalid DB directory: " + toEscapedText(DbDir));
713    
714              struct stat statBuf;              File f = File(FilePath);
715              int res = stat(FilePath.c_str(), &statBuf);              if (!f.Exist()) {
             if (res) {  
716                  std::stringstream ss;                  std::stringstream ss;
717                  ss << "Fail to stat `" << FilePath << "`: " << strerror(errno);                  ss << "Fail to stat `" << FilePath << "`: " << f.GetErrorMsg();
718                  throw Exception(ss.str());                  throw Exception(ss.str());
719              }              }
720    
721              if (!S_ISREG(statBuf.st_mode)) {              if (!f.IsFile()) {
722                  std::stringstream ss;                  std::stringstream ss;
723                  ss << "`" << FilePath << "` is not an instrument file";                  ss << "`" << FilePath << "` is not an instrument file";
724                  throw Exception(ss.str());                  throw Exception(ss.str());
725              }              }
726    
727              AddInstrumentsFromFile(DbDir, FilePath, Index, pProgress);              String dir = insDir ? PrepareSubdirectory(DbDir, FilePath) : DbDir;
728          } catch (Exception e) {              AddInstrumentsFromFile(dir, FilePath, Index, pProgress);
             DbInstrumentsMutex.Unlock();  
             throw e;  
729          }          }
   
         DbInstrumentsMutex.Unlock();  
730      }      }
731    
732      void InstrumentsDb::AddInstrumentsNonrecursive(String DbDir, String FsDir, ScanProgress* pProgress) {      void InstrumentsDb::AddInstrumentsNonrecursive(String DbDir, String FsDir, bool insDir, ScanProgress* pProgress) {
733          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));
734          if (DbDir.empty() || FsDir.empty()) return;          if (DbDir.empty() || FsDir.empty()) return;
735                    
736          DbInstrumentsMutex.Lock();          {
737          try {              LockGuard lock(DbInstrumentsMutex);
738    
739              int dirId = GetDirectoryId(DbDir);              int dirId = GetDirectoryId(DbDir);
740              if (dirId == -1) throw Exception("Invalid DB directory: " + DbDir);              if (dirId == -1) throw Exception("Invalid DB directory: " + toEscapedPath(DbDir));
741    
742              struct stat statBuf;              File f = File(FsDir);
743              int res = stat(FsDir.c_str(), &statBuf);              if (!f.Exist()) {
             if (res) {  
744                  std::stringstream ss;                  std::stringstream ss;
745                  ss << "Fail to stat `" << FsDir << "`: " << strerror(errno);                  ss << "Fail to stat `" << FsDir << "`: " << f.GetErrorMsg();
746                  throw Exception(ss.str());                  throw Exception(ss.str());
747              }              }
748    
749              if (!S_ISDIR(statBuf.st_mode)) {              if (!f.IsDirectory()) {
750                  throw Exception("Directory expected");                  throw Exception("Directory expected: " + FsDir);
751              }              }
752                            
753              if (FsDir.at(FsDir.length() - 1) != '/') FsDir.append("/");              if (FsDir.at(FsDir.length() - 1) != File::DirSeparator) {
754                    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;  
755              }              }
756                
757              struct dirent* pEnt = readdir(pDir);              try {
758              while (pEnt != NULL) {                  FileListPtr fileList = File::GetFiles(FsDir);
759                  if (pEnt->d_type != DT_REG) {                  for (int i = 0; i < fileList->size(); i++) {
760                      pEnt = readdir(pDir);                      String dir = insDir ? PrepareSubdirectory(DbDir, fileList->at(i)) : DbDir;
761                      continue;                                          AddInstrumentsFromFile(dir, FsDir + fileList->at(i), -1, pProgress);
762                  }                  }
763                } catch(Exception e) {
764                  AddInstrumentsFromFile(DbDir, FsDir + String(pEnt->d_name), -1, pProgress);                  e.PrintMessage();
                 pEnt = readdir(pDir);  
             }  
   
             if (closedir(pDir)) {  
                 std::stringstream ss;  
                 ss << "Failed to close directory `" << FsDir << "`: ";  
                 ss << strerror(errno);  
                 std::cerr << ss.str();  
765              }              }
         } catch (Exception e) {  
             DbInstrumentsMutex.Unlock();  
             throw e;  
766          }          }
   
         DbInstrumentsMutex.Unlock();  
767      }      }
768    
769      void InstrumentsDb::AddInstrumentsRecursive(String DbDir, String FsDir, bool Flat, ScanProgress* pProgress) {      void InstrumentsDb::AddInstrumentsRecursive(String DbDir, String FsDir, bool Flat, bool insDir, ScanProgress* pProgress) {
770          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));
771          if (pProgress != NULL) {          if (pProgress != NULL) {
772              pProgress->SetTotalFileCount(InstrumentFileCounter::Count(FsDir));              InstrumentFileCounter c;
773                pProgress->SetTotalFileCount(c.Count(FsDir));
774          }          }
775    
776          DirectoryScanner::Scan(DbDir, FsDir, Flat, pProgress);          DirectoryScanner d;
777            d.Scan(DbDir, FsDir, Flat, insDir, pProgress);
778      }      }
779    
780      int InstrumentsDb::GetInstrumentCount(int DirId) {      int InstrumentsDb::GetInstrumentCount(int DirId) {
# Line 766  namespace LinuxSampler { Line 806  namespace LinuxSampler {
806          }          }
807          EndTransaction();          EndTransaction();
808    
809          if (i == -1) throw Exception("Unknown Db directory: " + Dir);          if (i == -1) throw Exception("Unknown Db directory: " + toEscapedPath(Dir));
810          return i;          return i;
811      }      }
812    
# Line 782  namespace LinuxSampler { Line 822  namespace LinuxSampler {
822          BeginTransaction();          BeginTransaction();
823          try {          try {
824              int dirId = GetDirectoryId(Dir);              int dirId = GetDirectoryId(Dir);
825              if(dirId == -1) throw Exception("Unknown DB directory: " + Dir);              if(dirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
826    
827              StringListPtr pInstrs;              StringListPtr pInstrs;
828    
# Line 796  namespace LinuxSampler { Line 836  namespace LinuxSampler {
836                  sql << "SELECT instr_name FROM instruments WHERE dir_id=" << dirId;                  sql << "SELECT instr_name FROM instruments WHERE dir_id=" << dirId;
837    
838                  pInstrs = ExecSqlStringList(sql.str());                  pInstrs = ExecSqlStringList(sql.str());
839                    // Converting to abstract names
840                    for (int i = 0; i < pInstrs->size(); i++) {
841                        for (int j = 0; j < pInstrs->at(i).length(); j++) {
842                            if (pInstrs->at(i).at(j) == '/') pInstrs->at(i).at(j) = '\0';
843                        }
844                    }
845              }              }
846              EndTransaction();              EndTransaction();
847              return pInstrs;              return pInstrs;
# Line 820  namespace LinuxSampler { Line 866  namespace LinuxSampler {
866          std::stringstream sql;          std::stringstream sql;
867          sql << "SELECT instr_id FROM instruments WHERE dir_id=";          sql << "SELECT instr_id FROM instruments WHERE dir_id=";
868          sql << DirId << " AND instr_name=?";          sql << DirId << " AND instr_name=?";
869          return ExecSqlInt(sql.str(), InstrName);          return ExecSqlInt(sql.str(), toDbName(InstrName));
870      }      }
871    
872      String InstrumentsDb::GetInstrumentName(int InstrId) {      String InstrumentsDb::GetInstrumentName(int InstrId) {
873          dmsg(2,("InstrumentsDb: GetInstrumentName(InstrId=%d)\n", InstrId));          dmsg(2,("InstrumentsDb: GetInstrumentName(InstrId=%d)\n", InstrId));
874          std::stringstream sql;          std::stringstream sql;
875          sql << "SELECT instr_name FROM instruments WHERE instr_id=" << InstrId;          sql << "SELECT instr_name FROM instruments WHERE instr_id=" << InstrId;
876          return ExecSqlString(sql.str());          return toAbstractName(ExecSqlString(sql.str()));
877      }      }
878            
879      void InstrumentsDb::RemoveInstrument(String Instr) {      void InstrumentsDb::RemoveInstrument(String Instr) {
# Line 839  namespace LinuxSampler { Line 885  namespace LinuxSampler {
885          try {          try {
886              int instrId = GetInstrumentId(Instr);              int instrId = GetInstrumentId(Instr);
887              if(instrId == -1) {              if(instrId == -1) {
888                  throw Exception("The specified instrument does not exist: " + Instr);                  throw Exception("The specified instrument does not exist: " + toEscapedPath(Instr));
889              }              }
890              RemoveInstrument(instrId);              RemoveInstrument(instrId);
891          } catch (Exception e) {          } catch (Exception e) {
# Line 874  namespace LinuxSampler { Line 920  namespace LinuxSampler {
920          BeginTransaction();          BeginTransaction();
921          try {          try {
922              int id = GetInstrumentId(Instr);              int id = GetInstrumentId(Instr);
923              if(id == -1) throw Exception("Unknown DB instrument: " + Instr);              if(id == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
924              i = GetInstrumentInfo(id);              i = GetInstrumentInfo(id);
925          } catch (Exception e) {          } catch (Exception e) {
926              EndTransaction();              EndTransaction();
# Line 933  namespace LinuxSampler { Line 979  namespace LinuxSampler {
979          BeginTransaction();          BeginTransaction();
980          try {          try {
981              int dirId = GetDirectoryId(GetDirectoryPath(Instr));              int dirId = GetDirectoryId(GetDirectoryPath(Instr));
982              if (dirId == -1) throw Exception("Unknown DB instrument: " + Instr);              if (dirId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
983    
984              int instrId = GetInstrumentId(dirId, GetFileName(Instr));              int instrId = GetInstrumentId(dirId, GetFileName(Instr));
985              if (instrId == -1) throw Exception("Unknown DB instrument: " + Instr);              if (instrId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
986    
987              if (GetInstrumentId(dirId, Name) != -1) {              if (GetInstrumentId(dirId, Name) != -1) {
988                  throw Exception("Cannot rename. Instrument with that name already exists: " + Name);                  String s = toEscapedPath(Name);
989                    throw Exception("Cannot rename. Instrument with that name already exists: " + s);
990              }              }
991    
992              if (GetDirectoryId(dirId, Name) != -1) {              if (GetDirectoryId(dirId, Name) != -1) {
993                  throw Exception("Cannot rename. Directory with that name already exists: " + Name);                  String s = toEscapedPath(Name);
994                    throw Exception("Cannot rename. Directory with that name already exists: " + s);
995              }              }
996    
997              std::stringstream sql;              std::stringstream sql;
998              sql << "UPDATE instruments SET instr_name=? WHERE instr_id=" << instrId;              sql << "UPDATE instruments SET instr_name=? WHERE instr_id=" << instrId;
999              ExecSql(sql.str(), Name);              ExecSql(sql.str(), toDbName(Name));
1000          } catch (Exception e) {          } catch (Exception e) {
1001              EndTransaction();              EndTransaction();
1002              throw e;              throw e;
1003          }          }
1004          EndTransaction();          EndTransaction();
1005          FireInstrumentNameChanged(Instr, Name);          FireInstrumentNameChanged(Instr, toAbstractName(Name));
1006      }      }
1007    
1008      void InstrumentsDb::MoveInstrument(String Instr, String Dst) {      void InstrumentsDb::MoveInstrument(String Instr, String Dst) {
# Line 964  namespace LinuxSampler { Line 1012  namespace LinuxSampler {
1012    
1013          BeginTransaction();          BeginTransaction();
1014          try {          try {
1015              int dirId = GetDirectoryId(GetDirectoryPath(Instr));              int dirId = GetDirectoryId(ParentDir);
1016              if (dirId == -1) throw Exception("Unknown DB instrument: " + Instr);              if (dirId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1017    
1018              String instrName = GetFileName(Instr);              String instrName = GetFileName(Instr);
1019              int instrId = GetInstrumentId(dirId, instrName);              int instrId = GetInstrumentId(dirId, instrName);
1020              if (instrId == -1) throw Exception("Unknown DB instrument: " + Instr);              if (instrId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1021    
1022              int dstId = GetDirectoryId(Dst);              int dstId = GetDirectoryId(Dst);
1023              if (dstId == -1) throw Exception("Unknown DB directory: " + Dst);              if (dstId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dst));
1024              if (dirId == dstId) {              if (dirId == dstId) {
1025                  EndTransaction();                  EndTransaction();
1026                  return;                  return;
1027              }              }
1028    
1029              if (GetInstrumentId(dstId, instrName) != -1) {              if (GetInstrumentId(dstId, instrName) != -1) {
1030                  throw Exception("Cannot move. Instrument with that name already exists: " + instrName);                  String s = toEscapedPath(instrName);
1031                    throw Exception("Cannot move. Instrument with that name already exists: " + s);
1032              }              }
1033    
1034              if (GetDirectoryId(dstId, instrName) != -1) {              if (GetDirectoryId(dstId, instrName) != -1) {
1035                  throw Exception("Cannot move. Directory with that name already exists: " + instrName);                  String s = toEscapedPath(instrName);
1036                    throw Exception("Cannot move. Directory with that name already exists: " + s);
1037              }              }
1038    
1039              std::stringstream sql;              std::stringstream sql;
# Line 1007  namespace LinuxSampler { Line 1057  namespace LinuxSampler {
1057          BeginTransaction();          BeginTransaction();
1058          try {          try {
1059              int dirId = GetDirectoryId(GetDirectoryPath(Instr));              int dirId = GetDirectoryId(GetDirectoryPath(Instr));
1060              if (dirId == -1) throw Exception("Unknown DB instrument: " + Instr);              if (dirId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1061    
1062              String instrName = GetFileName(Instr);              String instrName = GetFileName(Instr);
1063              int instrId = GetInstrumentId(dirId, instrName);              int instrId = GetInstrumentId(dirId, instrName);
1064              if (instrId == -1) throw Exception("Unknown DB instrument: " + Instr);              if (instrId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1065    
1066              int dstId = GetDirectoryId(Dst);              int dstId = GetDirectoryId(Dst);
1067              if (dstId == -1) throw Exception("Unknown DB directory: " + Dst);              if (dstId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dst));
1068              if (dirId == dstId) {              if (dirId == dstId) {
1069                  EndTransaction();                  EndTransaction();
1070                  return;                  return;
1071              }              }
1072    
             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);  
             }  
   
1073              CopyInstrument(instrId, instrName, dstId, Dst);              CopyInstrument(instrId, instrName, dstId, Dst);
1074          } catch (Exception e) {          } catch (Exception e) {
1075              EndTransaction();              EndTransaction();
# Line 1038  namespace LinuxSampler { Line 1080  namespace LinuxSampler {
1080      }      }
1081    
1082      void InstrumentsDb::CopyInstrument(int InstrId, String InstrName, int DstDirId, String DstDir) {      void InstrumentsDb::CopyInstrument(int InstrId, String InstrName, int DstDirId, String DstDir) {
1083            if (GetInstrumentId(DstDirId, InstrName) != -1) {
1084                String s = toEscapedPath(InstrName);
1085                throw Exception("Cannot copy. Instrument with that name already exists: " + s);
1086            }
1087    
1088            if (GetDirectoryId(DstDirId, InstrName) != -1) {
1089                String s = toEscapedPath(InstrName);
1090                throw Exception("Cannot copy. Directory with that name already exists: " + s);
1091            }
1092    
1093          DbInstrument i = GetInstrumentInfo(InstrId);          DbInstrument i = GetInstrumentInfo(InstrId);
1094          sqlite3_stmt *pStmt = NULL;          sqlite3_stmt *pStmt = NULL;
1095          std::stringstream sql;          std::stringstream sql;
# Line 1051  namespace LinuxSampler { Line 1103  namespace LinuxSampler {
1103              throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));              throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1104          }          }
1105    
1106          BindTextParam(pStmt, 1, InstrName);          String s = toDbName(InstrName);
1107            BindTextParam(pStmt, 1, s);
1108          BindTextParam(pStmt, 2, i.InstrFile);          BindTextParam(pStmt, 2, i.InstrFile);
1109          BindTextParam(pStmt, 3, i.FormatFamily);          BindTextParam(pStmt, 3, i.FormatFamily);
1110          BindTextParam(pStmt, 4, i.FormatVersion);          BindTextParam(pStmt, 4, i.FormatVersion);
# Line 1076  namespace LinuxSampler { Line 1129  namespace LinuxSampler {
1129          BeginTransaction();          BeginTransaction();
1130          try {          try {
1131              int id = GetInstrumentId(Instr);              int id = GetInstrumentId(Instr);
1132              if(id == -1) throw Exception("Unknown DB instrument: " + Instr);              if(id == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1133    
1134              std::stringstream sql;              std::stringstream sql;
1135              sql << "UPDATE instruments SET description=?,modified=CURRENT_TIMESTAMP ";              sql << "UPDATE instruments SET description=?,modified=CURRENT_TIMESTAMP ";
# Line 1110  namespace LinuxSampler { Line 1163  namespace LinuxSampler {
1163                  }                  }
1164              }              }
1165          } catch(Exception e) {          } catch(Exception e) {
1166              std::cerr << e.Message() << std::endl;              e.PrintMessage();
1167          }          }
1168      }      }
1169    
1170      void InstrumentsDb::AddGigInstruments(String DbDir, String File, int Index, ScanProgress* pProgress) {      void InstrumentsDb::AddGigInstruments(String DbDir, String FilePath, int Index, ScanProgress* pProgress) {
1171          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));
1172          int dirId = GetDirectoryId(DbDir);          int dirId = GetDirectoryId(DbDir);
1173          if (dirId == -1) throw Exception("Invalid DB directory: " + DbDir);          if (dirId == -1) throw Exception("Invalid DB directory: " + toEscapedPath(DbDir));
1174    
1175          struct stat statBuf;          File f = File(FilePath);
1176          int res = stat(File.c_str(), &statBuf);          if (!f.Exist()) {
         if (res) {  
1177              std::stringstream ss;              std::stringstream ss;
1178              ss << "Fail to stat `" << File << "`: " << strerror(errno);              ss << "Fail to stat `" << FilePath << "`: " << f.GetErrorMsg();
1179              throw Exception(ss.str());              throw Exception(ss.str());
1180          }          }
1181    
1182          if (!S_ISREG(statBuf.st_mode)) {          if (!f.IsFile()) {
1183              std::stringstream ss;              std::stringstream ss;
1184              ss << "`" << File << "` is not a regular file";              ss << "`" << FilePath << "` is not a regular file";
1185              throw Exception(ss.str());              throw Exception(ss.str());
1186          }          }
1187    
1188            bool unlocked = false;
1189          RIFF::File* riff = NULL;          RIFF::File* riff = NULL;
1190          gig::File* gig = NULL;          gig::File* gig = NULL;
1191          try {          try {
1192              riff = new RIFF::File(File);              riff = new RIFF::File(FilePath);
1193              gig::File* gig = new gig::File(riff);              gig::File* gig = new gig::File(riff);
1194                gig->SetAutoLoad(false); // avoid time consuming samples scanning
1195    
1196              std::stringstream sql;              std::stringstream sql;
1197              sql << "INSERT INTO instruments (dir_id,instr_name,instr_file,";              sql << "INSERT INTO instruments (dir_id,instr_name,instr_file,";
1198              sql << "instr_nr,format_family,format_version,instr_size,";              sql << "instr_nr,format_family,format_version,instr_size,";
1199              sql << "description,is_drum,product,artists,keywords) VALUES (";              sql << "description,is_drum,product,artists,keywords) VALUES (";
1200              sql << dirId << ",?,?,?,'GIG',?," << statBuf.st_size << ",?,?,?,?,?)";              sql << dirId << ",?,?,?,'GIG',?," << f.GetSize() << ",?,?,?,?,?)";
1201    
1202              sqlite3_stmt* pStmt = NULL;              sqlite3_stmt* pStmt = NULL;
1203    
# Line 1152  namespace LinuxSampler { Line 1206  namespace LinuxSampler {
1206                  throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));                  throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1207              }              }
1208    
1209              BindTextParam(pStmt, 2, File);              String s = FilePath;
1210                s = toEscapedFsPath(s);
1211                BindTextParam(pStmt, 2, s);
1212              String ver = "";              String ver = "";
1213              if (gig->pVersion != NULL) ver = ToString(gig->pVersion->major);              if (gig->pVersion != NULL) ver = ToString(gig->pVersion->major);
1214              BindTextParam(pStmt, 4, ver);              BindTextParam(pStmt, 4, ver);
1215    
1216              if (Index == -1) {              if (Index == -1) {
1217                  int instrIndex = 0;                  int instrIndex = 0;
1218                    // Assume that it's locked and should be unlocked at this point
1219                    // to be able to use the database from another threads
1220                    if (!InTransaction) {
1221                        DbInstrumentsMutex.Unlock();
1222                        unlocked = true;
1223                    } else {
1224                        std::cerr << "Shouldn't be in transaction when adding instruments." << std::endl;
1225                    }
1226    
1227                  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
1228                  gig::Instrument* pInstrument = gig->GetFirstInstrument();                  gig::Instrument* pInstrument = gig->GetFirstInstrument();
1229    
1230                    if (!InTransaction) DbInstrumentsMutex.Lock();
1231                  while (pInstrument) {                  while (pInstrument) {
1232                      BindTextParam(pStmt, 7, gig->pInfo->Product);                      BindTextParam(pStmt, 7, gig->pInfo->Product);
1233                      BindTextParam(pStmt, 8, gig->pInfo->Artists);                      BindTextParam(pStmt, 8, gig->pInfo->Artists);
1234                      BindTextParam(pStmt, 9, gig->pInfo->Keywords);                      BindTextParam(pStmt, 9, gig->pInfo->Keywords);
1235                      AddGigInstrument(pStmt, DbDir, dirId, File, pInstrument, instrIndex);                      AddGigInstrument(pStmt, DbDir, dirId, FilePath, pInstrument, instrIndex);
1236    
1237                      instrIndex++;                      instrIndex++;
1238                      pInstrument = gig->GetNextInstrument();                      pInstrument = gig->GetNextInstrument();
# Line 1178  namespace LinuxSampler { Line 1245  namespace LinuxSampler {
1245                      BindTextParam(pStmt, 7, gig->pInfo->Product);                      BindTextParam(pStmt, 7, gig->pInfo->Product);
1246                      BindTextParam(pStmt, 8, gig->pInfo->Artists);                      BindTextParam(pStmt, 8, gig->pInfo->Artists);
1247                      BindTextParam(pStmt, 9, gig->pInfo->Keywords);                      BindTextParam(pStmt, 9, gig->pInfo->Keywords);
1248                      AddGigInstrument(pStmt, DbDir, dirId, File, pInstrument, Index);                      AddGigInstrument(pStmt, DbDir, dirId, FilePath, pInstrument, Index);
1249                  }                  }
1250              }              }
1251    
# Line 1188  namespace LinuxSampler { Line 1255  namespace LinuxSampler {
1255          } catch (RIFF::Exception e) {          } catch (RIFF::Exception e) {
1256              if (gig != NULL) delete gig;              if (gig != NULL) delete gig;
1257              if (riff != NULL) delete riff;              if (riff != NULL) delete riff;
1258                if (unlocked) DbInstrumentsMutex.Lock();
1259              std::stringstream ss;              std::stringstream ss;
1260              ss << "Failed to scan `" << File << "`: " << e.Message;              ss << "Failed to scan `" << FilePath << "`: " << e.Message;
1261                            
1262              throw Exception(ss.str());              throw Exception(ss.str());
1263          } catch (Exception e) {          } catch (Exception e) {
1264              if (gig != NULL) delete gig;              if (gig != NULL) delete gig;
1265              if (riff != NULL) delete riff;              if (riff != NULL) delete riff;
1266                if (unlocked) DbInstrumentsMutex.Lock();
1267              throw e;              throw e;
1268          } catch (...) {          } catch (...) {
1269              if (gig != NULL) delete gig;              if (gig != NULL) delete gig;
1270              if (riff != NULL) delete riff;              if (riff != NULL) delete riff;
1271              throw Exception("Failed to scan `" + File + "`");              if (unlocked) DbInstrumentsMutex.Lock();
1272                throw Exception("Failed to scan `" + FilePath + "`");
1273          }          }
1274      }      }
1275    
1276      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) {
1277            dmsg(2,("InstrumentsDb: AddGigInstrument(DbDir=%s,DirId=%d,File=%s,Index=%d)\n", DbDir.c_str(), DirId, File.c_str(), Index));
1278          String name = pInstrument->pInfo->Name;          String name = pInstrument->pInfo->Name;
1279          if (name == "") return;          if (name == "") return;
1280          name = GetUniqueInstrumentName(DirId, name);          name = GetUniqueName(DirId, name);
1281                    
1282          std::stringstream sql2;          std::stringstream sql2;
1283          sql2 << "SELECT COUNT(*) FROM instruments WHERE instr_file=? AND ";          sql2 << "SELECT COUNT(*) FROM instruments WHERE instr_file=? AND ";
1284          sql2 << "instr_nr=" << Index;          sql2 << "instr_nr=" << Index;
1285          if (ExecSqlInt(sql2.str(), File) > 0) return;          String s = toEscapedFsPath(File);
1286            if (ExecSqlInt(sql2.str(), s) > 0) return;
1287    
1288          BindTextParam(pStmt, 1, name);          BindTextParam(pStmt, 1, name);
1289          BindIntParam(pStmt, 3, Index);          BindIntParam(pStmt, 3, Index);
# Line 1240  namespace LinuxSampler { Line 1312  namespace LinuxSampler {
1312          FireInstrumentCountChanged(DbDir);          FireInstrumentCountChanged(DbDir);
1313      }      }
1314    
1315      void InstrumentsDb::DirectoryTreeWalk(String Path, DirectoryHandler* pHandler) {      void InstrumentsDb::DirectoryTreeWalk(String AbstractPath, DirectoryHandler* pHandler) {
1316          int DirId = GetDirectoryId(Path);          int DirId = GetDirectoryId(AbstractPath);
1317          if(DirId == -1) throw Exception("Unknown DB directory: " + Path);          if(DirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(AbstractPath));
1318          DirectoryTreeWalk(pHandler, Path, DirId, 0);          DirectoryTreeWalk(pHandler, AbstractPath, DirId, 0);
1319      }      }
1320    
1321      void InstrumentsDb::DirectoryTreeWalk(DirectoryHandler* pHandler, String Path, int DirId, int Level) {      void InstrumentsDb::DirectoryTreeWalk(DirectoryHandler* pHandler, String AbstractPath, int DirId, int Level) {
1322          if(Level == 1000) throw Exception("Possible infinite loop detected");          if(Level == 1000) throw Exception("Possible infinite loop detected");
1323          pHandler->ProcessDirectory(Path, DirId);          pHandler->ProcessDirectory(AbstractPath, DirId);
1324                    
1325          String s;          String s;
1326          StringListPtr pDirs = GetDirectories(DirId);          StringListPtr pDirs = GetDirectories(DirId);
1327          for(int i = 0; i < pDirs->size(); i++) {          for(int i = 0; i < pDirs->size(); i++) {
1328              if (Path.length() == 1 && Path.at(0) == '/') s = "/" + pDirs->at(i);              if (AbstractPath.length() == 1 && AbstractPath.at(0) == '/') {
1329              else s = Path + "/" + pDirs->at(i);                  s = "/" + pDirs->at(i);
1330                } else {
1331                    s = AbstractPath + "/" + pDirs->at(i);
1332                }
1333              DirectoryTreeWalk(pHandler, s, GetDirectoryId(DirId, pDirs->at(i)), Level + 1);              DirectoryTreeWalk(pHandler, s, GetDirectoryId(DirId, pDirs->at(i)), Level + 1);
1334          }          }
1335      }      }
# Line 1266  namespace LinuxSampler { Line 1341  namespace LinuxSampler {
1341          BeginTransaction();          BeginTransaction();
1342          try {          try {
1343              int DirId = GetDirectoryId(Dir);              int DirId = GetDirectoryId(Dir);
1344              if(DirId == -1) throw Exception("Unknown DB directory: " + Dir);              if(DirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
1345    
1346              if (Recursive) DirectoryTreeWalk(Dir, &directoryFinder);              if (Recursive) DirectoryTreeWalk(Dir, &directoryFinder);
1347              else directoryFinder.ProcessDirectory(Dir, DirId);              else directoryFinder.ProcessDirectory(Dir, DirId);
# Line 1286  namespace LinuxSampler { Line 1361  namespace LinuxSampler {
1361          BeginTransaction();          BeginTransaction();
1362          try {          try {
1363              int DirId = GetDirectoryId(Dir);              int DirId = GetDirectoryId(Dir);
1364              if(DirId == -1) throw Exception("Unknown DB directory: " + Dir);              if(DirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
1365    
1366              if (Recursive) DirectoryTreeWalk(Dir, &instrumentFinder);              if (Recursive) DirectoryTreeWalk(Dir, &instrumentFinder);
1367              else instrumentFinder.ProcessDirectory(Dir, DirId);              else instrumentFinder.ProcessDirectory(Dir, DirId);
# Line 1298  namespace LinuxSampler { Line 1373  namespace LinuxSampler {
1373    
1374          return instrumentFinder.GetInstruments();          return instrumentFinder.GetInstruments();
1375      }      }
1376        
1377        StringListPtr InstrumentsDb::FindLostInstrumentFiles() {
1378            dmsg(2,("InstrumentsDb: FindLostInstrumentFiles()\n"));
1379    
1380            BeginTransaction();
1381            try {
1382                StringListPtr files = ExecSqlStringList("SELECT DISTINCT instr_file FROM instruments");
1383                StringListPtr result(new std::vector<String>);
1384                for (int i = 0; i < files->size(); i++) {
1385                    File f(toNonEscapedFsPath(files->at(i)));
1386                    if (!f.Exist()) result->push_back(files->at(i));
1387                }
1388                return result;
1389            } catch (Exception e) {
1390                EndTransaction();
1391                throw e;
1392            }
1393            EndTransaction();
1394        }
1395        
1396        void InstrumentsDb::SetInstrumentFilePath(String OldPath, String NewPath) {
1397            if (OldPath == NewPath) return;
1398            StringListPtr instrs;
1399            BeginTransaction();
1400            try {
1401                std::vector<String> params(2);
1402                params[0] = toEscapedFsPath(NewPath);
1403                params[1] = toEscapedFsPath(OldPath);
1404                instrs = GetInstrumentsByFile(OldPath);
1405                ExecSql("UPDATE instruments SET instr_file=? WHERE instr_file=?", params);
1406            } catch (Exception e) {
1407                EndTransaction();
1408                throw e;
1409            }
1410            EndTransaction();
1411            
1412            for (int i = 0; i < instrs->size(); i++) {
1413                FireInstrumentInfoChanged(instrs->at(i));
1414            }
1415        }
1416    
1417      void InstrumentsDb::BeginTransaction() {      void InstrumentsDb::BeginTransaction() {
1418          dmsg(2,("InstrumentsDb: BeginTransaction(InTransaction=%d)\n", InTransaction));          dmsg(2,("InstrumentsDb: BeginTransaction(InTransaction=%d)\n", InTransaction));
# Line 1332  namespace LinuxSampler { Line 1447  namespace LinuxSampler {
1447          }          }
1448          InTransaction = false;          InTransaction = false;
1449                    
1450          if(db == NULL) {          if (db == NULL) {
1451              DbInstrumentsMutex.Unlock();              DbInstrumentsMutex.Unlock();
1452              return;              return;
1453          }          }
# Line 1359  namespace LinuxSampler { Line 1474  namespace LinuxSampler {
1474    
1475      void InstrumentsDb::ExecSql(String Sql) {      void InstrumentsDb::ExecSql(String Sql) {
1476          dmsg(2,("InstrumentsDb: ExecSql(Sql=%s)\n", Sql.c_str()));          dmsg(2,("InstrumentsDb: ExecSql(Sql=%s)\n", Sql.c_str()));
1477          sqlite3_stmt *pStmt = NULL;          std::vector<String> Params;
1478                    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);  
1479      }      }
1480    
1481      void InstrumentsDb::ExecSql(String Sql, String Param) {      void InstrumentsDb::ExecSql(String Sql, String Param) {
1482          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()));
1483            std::vector<String> Params;
1484            Params.push_back(Param);
1485            ExecSql(Sql, Params);
1486        }
1487    
1488        void InstrumentsDb::ExecSql(String Sql, std::vector<String>& Params) {
1489            dmsg(2,("InstrumentsDb: ExecSql(Sql=%s,Params)\n", Sql.c_str()));
1490          sqlite3_stmt *pStmt = NULL;          sqlite3_stmt *pStmt = NULL;
1491                    
1492          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 1495  namespace LinuxSampler {
1495              throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));              throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1496          }          }
1497    
1498          BindTextParam(pStmt, 1, Param);          for(int i = 0; i < Params.size(); i++) {
1499                BindTextParam(pStmt, i + 1, Params[i]);
1500            }
1501    
1502          res = sqlite3_step(pStmt);          res = sqlite3_step(pStmt);
1503          if (res != SQLITE_DONE) {          if (res != SQLITE_DONE) {
# Line 1467  namespace LinuxSampler { Line 1579  namespace LinuxSampler {
1579      }      }
1580    
1581      IntListPtr InstrumentsDb::ExecSqlIntList(String Sql) {      IntListPtr InstrumentsDb::ExecSqlIntList(String Sql) {
1582            dmsg(2,("InstrumentsDb: ExecSqlIntList(Sql=%s)\n", Sql.c_str()));
1583            std::vector<String> Params;
1584            return ExecSqlIntList(Sql, Params);
1585        }
1586    
1587        IntListPtr InstrumentsDb::ExecSqlIntList(String Sql, String Param) {
1588            dmsg(2,("InstrumentsDb: ExecSqlIntList(Sql=%s,Param=%s)\n", Sql.c_str(), Param.c_str()));
1589            std::vector<String> Params;
1590            Params.push_back(Param);
1591            return ExecSqlIntList(Sql, Params);
1592        }
1593    
1594        IntListPtr InstrumentsDb::ExecSqlIntList(String Sql, std::vector<String>& Params) {
1595            dmsg(2,("InstrumentsDb: ExecSqlIntList(Sql=%s)\n", Sql.c_str()));
1596          IntListPtr intList(new std::vector<int>);          IntListPtr intList(new std::vector<int>);
1597                    
1598          sqlite3_stmt *pStmt = NULL;          sqlite3_stmt *pStmt = NULL;
# Line 1476  namespace LinuxSampler { Line 1602  namespace LinuxSampler {
1602              throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));              throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1603          }          }
1604                    
1605            for(int i = 0; i < Params.size(); i++) {
1606                BindTextParam(pStmt, i + 1, Params[i]);
1607            }
1608            
1609          res = sqlite3_step(pStmt);          res = sqlite3_step(pStmt);
1610          while(res == SQLITE_ROW) {          while(res == SQLITE_ROW) {
1611              intList->push_back(sqlite3_column_int(pStmt, 0));              intList->push_back(sqlite3_column_int(pStmt, 0));
# Line 1493  namespace LinuxSampler { Line 1623  namespace LinuxSampler {
1623      }      }
1624            
1625      StringListPtr InstrumentsDb::ExecSqlStringList(String Sql) {      StringListPtr InstrumentsDb::ExecSqlStringList(String Sql) {
1626            dmsg(2,("InstrumentsDb: ExecSqlStringList(Sql=%s)\n", Sql.c_str()));
1627          StringListPtr stringList(new std::vector<String>);          StringListPtr stringList(new std::vector<String>);
1628                    
1629          sqlite3_stmt *pStmt = NULL;          sqlite3_stmt *pStmt = NULL;
# Line 1536  namespace LinuxSampler { Line 1667  namespace LinuxSampler {
1667          }          }
1668      }      }
1669    
1670    #ifndef WIN32
1671      void InstrumentsDb::Regexp(sqlite3_context* pContext, int argc, sqlite3_value** ppValue) {      void InstrumentsDb::Regexp(sqlite3_context* pContext, int argc, sqlite3_value** ppValue) {
1672          if (argc != 2) return;          if (argc != 2) return;
1673    
# Line 1546  namespace LinuxSampler { Line 1678  namespace LinuxSampler {
1678              sqlite3_result_int(pContext, 1);              sqlite3_result_int(pContext, 1);
1679          }          }
1680      }      }
1681    #endif
1682    
1683      String InstrumentsDb::GetDirectoryPath(String File) {      String InstrumentsDb::GetDirectoryPath(String File) {
1684          if (File.empty()) return String("");          if (File.empty()) return String("");
# Line 1588  namespace LinuxSampler { Line 1721  namespace LinuxSampler {
1721          return Dir.substr(0, i);          return Dir.substr(0, i);
1722      }      }
1723    
1724        void InstrumentsDb::Format() {
1725            {
1726                LockGuard lock(DbInstrumentsMutex);
1727    
1728                if (db != NULL) {
1729                    sqlite3_close(db);
1730                    db = NULL;
1731                }
1732    
1733                if (DbFile.empty()) DbFile = CONFIG_DEFAULT_INSTRUMENTS_DB_LOCATION;
1734                String bkp = DbFile + ".bkp";
1735                remove(bkp.c_str());
1736                if (rename(DbFile.c_str(), bkp.c_str()) && errno != ENOENT) {
1737                    throw Exception(String("Failed to backup database: ") + strerror(errno));
1738                }
1739            
1740                String f = DbFile;
1741                DbFile = "";
1742                CreateInstrumentsDb(f);
1743            }
1744            FireDirectoryCountChanged("/");
1745            FireInstrumentCountChanged("/");
1746        }
1747    
1748      void InstrumentsDb::CheckFileName(String File) {      void InstrumentsDb::CheckFileName(String File) {
1749          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);  
         }  
1750      }      }
1751    
1752      String InstrumentsDb::GetUniqueInstrumentName(int DirId, String Name) {      String InstrumentsDb::GetUniqueName(int DirId, String Name) {
1753          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()));
1754    
1755          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 1764  namespace LinuxSampler {
1764    
1765          throw Exception("Unable to find an unique name: " + Name);          throw Exception("Unable to find an unique name: " + Name);
1766      }      }
1767        
1768        String InstrumentsDb::PrepareSubdirectory(String DbDir, String FsPath) {
1769            std::string dir = Path::getBaseName(FsPath);
1770            dir = toAbstractName(dir);
1771            if(dir.empty()) dir = "New Directory";
1772            dir = GetUniqueName(GetDirectoryId(DbDir), dir);
1773            dir = AppendNode(DbDir, dir);
1774            AddDirectory(dir);
1775            return dir;
1776        }
1777    
1778        String InstrumentsDb::AppendNode(String DbDir, String Node) {
1779            if(DbDir.length() == 1 && DbDir.at(0) == '/') return DbDir + Node;
1780            if(DbDir.at(DbDir.length() - 1) == '/') return DbDir + Node;
1781            return DbDir + "/" + Node;
1782        }
1783    
1784        String InstrumentsDb::toDbName(String AbstractName) {
1785            for (int i = 0; i < AbstractName.length(); i++) {
1786                if (AbstractName.at(i) == '\0') AbstractName.at(i) = '/';
1787            }
1788            return AbstractName;
1789        }
1790    
1791        String InstrumentsDb::toEscapedPath(String AbstractName) {
1792            for (int i = 0; i < AbstractName.length(); i++) {
1793                if (AbstractName.at(i) == '\0')      AbstractName.replace(i++, 1, "\\x2f");
1794                else if (AbstractName.at(i) == '\\') AbstractName.replace(i++, 1, "\\\\");
1795                else if (AbstractName.at(i) == '\'') AbstractName.replace(i++, 1, "\\'");
1796                else if (AbstractName.at(i) == '"')  AbstractName.replace(i++, 1, "\\\"");
1797                else if (AbstractName.at(i) == '\r') AbstractName.replace(i++, 1, "\\r");
1798                else if (AbstractName.at(i) == '\n') AbstractName.replace(i++, 1, "\\n");
1799            }
1800            return AbstractName;
1801        }
1802        
1803        String InstrumentsDb::toEscapedText(String text) {
1804            for (int i = 0; i < text.length(); i++) {
1805                if (text.at(i) == '\\')      text.replace(i++, 1, "\\\\");
1806                else if (text.at(i) == '\'') text.replace(i++, 1, "\\'");
1807                else if (text.at(i) == '"')  text.replace(i++, 1, "\\\"");
1808                else if (text.at(i) == '\r') text.replace(i++, 1, "\\r");
1809                else if (text.at(i) == '\n') text.replace(i++, 1, "\\n");
1810            }
1811            return text;
1812        }
1813        
1814        String InstrumentsDb::toNonEscapedText(String text) {
1815            String sb;
1816            for (int i = 0; i < text.length(); i++) {
1817                char c = text.at(i);
1818                            if(c == '\\') {
1819                                    if(i >= text.length()) {
1820                                            std::cerr << "Broken escape sequence!" << std::endl;
1821                                            break;
1822                                    }
1823                                    char c2 = text.at(++i);
1824                                    if(c2 == '\'')      sb.push_back('\'');
1825                                    else if(c2 == '"')  sb.push_back('"');
1826                                    else if(c2 == '\\') sb.push_back('\\');
1827                                    else if(c2 == 'r')  sb.push_back('\r');
1828                                    else if(c2 == 'n')  sb.push_back('\n');
1829                                    else std::cerr << "Unknown escape sequence \\" << c2 << std::endl;
1830                            } else {
1831                                    sb.push_back(c);
1832                            }
1833            }
1834            return sb;
1835        }
1836        
1837        String InstrumentsDb::toEscapedFsPath(String FsPath) {
1838    #ifdef WIN32
1839            replace(FsPath.begin(), FsPath.end(), '\\', '/');
1840    #endif
1841            return toEscapedText(FsPath);
1842        }
1843        
1844        String InstrumentsDb::toNonEscapedFsPath(String FsPath) {
1845            FsPath = toNonEscapedText(FsPath);
1846    #ifdef WIN32
1847            replace(FsPath.begin(), FsPath.end(), '/', '\\');
1848    #endif
1849            return FsPath;
1850        }
1851        
1852        String InstrumentsDb::toAbstractName(String DbName) {
1853            for (int i = 0; i < DbName.length(); i++) {
1854                if (DbName.at(i) == '/') DbName.at(i) = '\0';
1855            }
1856            return DbName;
1857        }
1858    
1859      void InstrumentsDb::FireDirectoryCountChanged(String Dir) {      void InstrumentsDb::FireDirectoryCountChanged(String Dir) {
1860          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
# Line 1654  namespace LinuxSampler { Line 1899  namespace LinuxSampler {
1899      }      }
1900    
1901  } // namespace LinuxSampler  } // namespace LinuxSampler
   
 #endif // HAVE_SQLITE3  

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

  ViewVC Help
Powered by ViewVC