/[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 1782 by iliev, Tue Sep 30 02:16:41 2008 UTC
# Line 1  Line 1 
1  /***************************************************************************  /***************************************************************************
2   *                                                                         *   *                                                                         *
3   *   Copyright (C) 2007 Grigor Iliev                                       *   *   Copyright (C) 2007, 2008 Grigor Iliev                                 *
4   *                                                                         *   *                                                                         *
5   *   This program is free software; you can redistribute it and/or modify  *   *   This program is free software; you can redistribute it and/or modify  *
6   *   it under the terms of the GNU General Public License as published by  *   *   it under the terms of the GNU General Public License as published by  *
# Line 20  Line 20 
20    
21  #include "InstrumentsDb.h"  #include "InstrumentsDb.h"
22    
23  #if HAVE_SQLITE3  #include "../common/File.h"
24    #include "../common/Path.h"
25    #include "../common/global_private.h"
26    
27  #include <iostream>  #include <iostream>
28  #include <sstream>  #include <sstream>
29  #include <vector>  #include <vector>
 #include <dirent.h>  
30  #include <errno.h>  #include <errno.h>
31  #include <fnmatch.h>  #include <fnmatch.h>
32    
# Line 33  Line 34 
34    
35  namespace LinuxSampler {  namespace LinuxSampler {
36    
37      InstrumentsDb* InstrumentsDb::pInstrumentsDb = new InstrumentsDb;      InstrumentsDb InstrumentsDb::instance;
38    
39      void InstrumentsDb::CreateInstrumentsDb(String File) {      void InstrumentsDb::CreateInstrumentsDb(String FilePath) {
40          struct stat statBuf;          File f = File(FilePath);
41          int res = stat(File.c_str(), &statBuf);          if (f.Exist()) {
42          if (!res) {              throw Exception("File exists: " + FilePath);
             throw Exception("File exists: " + File);  
43          }          }
44                    
45          GetInstrumentsDb()->SetDbFile(File);          GetInstrumentsDb()->SetDbFile(FilePath);
46    
47          String sql =          String sql =
48              "  CREATE TABLE instr_dirs (                                      "              "  CREATE TABLE instr_dirs (                                      "
# Line 58  namespace LinuxSampler { Line 58  namespace LinuxSampler {
58                    
59          GetInstrumentsDb()->ExecSql(sql);          GetInstrumentsDb()->ExecSql(sql);
60    
61          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, '/');";
62          GetInstrumentsDb()->ExecSql(sql);          GetInstrumentsDb()->ExecSql(sql);
63    
64          sql =          sql =
# Line 95  namespace LinuxSampler { Line 95  namespace LinuxSampler {
95          if (db != NULL) sqlite3_close(db);          if (db != NULL) sqlite3_close(db);
96      }      }
97            
     void InstrumentsDb::Destroy() {  
         if (pInstrumentsDb != NULL) {  
             delete pInstrumentsDb;  
             pInstrumentsDb = NULL;  
         }  
     }  
   
98      void InstrumentsDb::AddInstrumentsDbListener(InstrumentsDb::Listener* l) {      void InstrumentsDb::AddInstrumentsDbListener(InstrumentsDb::Listener* l) {
99          llInstrumentsDbListeners.AddListener(l);          llInstrumentsDbListeners.AddListener(l);
100      }      }
# Line 111  namespace LinuxSampler { Line 104  namespace LinuxSampler {
104      }      }
105            
106      InstrumentsDb* InstrumentsDb::GetInstrumentsDb() {      InstrumentsDb* InstrumentsDb::GetInstrumentsDb() {
107          return pInstrumentsDb;          return &instance;
108      }      }
109            
110      void InstrumentsDb::SetDbFile(String File) {      void InstrumentsDb::SetDbFile(String File) {
# Line 127  namespace LinuxSampler { Line 120  namespace LinuxSampler {
120      sqlite3* InstrumentsDb::GetDb() {      sqlite3* InstrumentsDb::GetDb() {
121          if ( db != NULL) return db;          if ( db != NULL) return db;
122    
123          if (DbFile.empty()) DbFile = "/var/lib/linuxsampler/instruments.db";          if (DbFile.empty()) DbFile = CONFIG_DEFAULT_INSTRUMENTS_DB_LOCATION;
124                    #if defined(__APPLE__)  /* 20071224 Toshi Nagata  */
125                    if (DbFile.find("~") == 0)
126                            DbFile.replace(0, 1, getenv("HOME"));
127                    #endif
128          int rc = sqlite3_open(DbFile.c_str(), &db);          int rc = sqlite3_open(DbFile.c_str(), &db);
129          if (rc) {          if (rc) {
130              sqlite3_close(db);              sqlite3_close(db);
# Line 136  namespace LinuxSampler { Line 133  namespace LinuxSampler {
133          }          }
134          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);
135          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."); }
136    
137            // TODO: remove this in the next version
138            try {
139                int i = ExecSqlInt("SELECT parent_dir_id FROM instr_dirs WHERE dir_id=0");
140                // The parent ID of the root directory should be -2 now.
141                if(i != -2) ExecSql("UPDATE instr_dirs SET parent_dir_id=-2 WHERE dir_id=0");
142            } catch(Exception e) { }
143            ////////////////////////////////////////
144                    
145          return db;          return db;
146      }      }
# Line 149  namespace LinuxSampler { Line 154  namespace LinuxSampler {
154                    
155          int count = ExecSqlInt(sql.str());          int count = ExecSqlInt(sql.str());
156    
         // While the root dir has ID 0 and parent ID 0, the directory  
         // count for the root dir will be incorrect, so we should fix it.  
         if (count != -1 && DirId == 0) count--;  
157          return count;          return count;
158      }      }
159    
# Line 173  namespace LinuxSampler { Line 175  namespace LinuxSampler {
175              throw e;              throw e;
176          }          }
177          EndTransaction();          EndTransaction();
178          if (i == -1) throw Exception("Unkown DB directory: " + Dir);          if (i == -1) throw Exception("Unkown DB directory: " + toEscapedPath(Dir));
179                    
180          return i;          return i;
181      }      }
# Line 192  namespace LinuxSampler { Line 194  namespace LinuxSampler {
194          BeginTransaction();          BeginTransaction();
195          try {          try {
196              int dirId = GetDirectoryId(Dir);              int dirId = GetDirectoryId(Dir);
197              if(dirId == -1) throw Exception("Unknown DB directory: " + Dir);              if(dirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
198    
199              StringListPtr pDirs;              StringListPtr pDirs;
200              if (Recursive) {              if (Recursive) {
# Line 215  namespace LinuxSampler { Line 217  namespace LinuxSampler {
217          std::stringstream sql;          std::stringstream sql;
218          sql << "SELECT dir_name FROM instr_dirs ";          sql << "SELECT dir_name FROM instr_dirs ";
219          sql << "WHERE parent_dir_id=" << DirId << " AND dir_id!=0";          sql << "WHERE parent_dir_id=" << DirId << " AND dir_id!=0";
220          return ExecSqlStringList(sql.str());          StringListPtr dirs = ExecSqlStringList(sql.str());
221    
222            for (int i = 0; i < dirs->size(); i++) {
223                for (int j = 0; j < dirs->at(i).length(); j++) {
224                    if (dirs->at(i).at(j) == '/') dirs->at(i).at(j) = '\0';
225                }
226            }
227    
228            return dirs;
229      }      }
230    
231      int InstrumentsDb::GetDirectoryId(String Dir) {      int InstrumentsDb::GetDirectoryId(String Dir) {
# Line 244  namespace LinuxSampler { Line 254  namespace LinuxSampler {
254    
255      int InstrumentsDb::GetDirectoryId(int ParentDirId, String DirName) {      int InstrumentsDb::GetDirectoryId(int ParentDirId, String DirName) {
256          dmsg(2,("InstrumentsDb: GetDirectoryId(ParentDirId=%d, DirName=%s)\n", ParentDirId, DirName.c_str()));          dmsg(2,("InstrumentsDb: GetDirectoryId(ParentDirId=%d, DirName=%s)\n", ParentDirId, DirName.c_str()));
257            DirName = toDbName(DirName);
258          std::stringstream sql;          std::stringstream sql;
259          sql << "SELECT dir_id FROM instr_dirs WHERE parent_dir_id=";          sql << "SELECT dir_id FROM instr_dirs WHERE parent_dir_id=";
260          sql << ParentDirId << " AND dir_name=?";          sql << ParentDirId << " AND dir_name=?";
261          return ExecSqlInt(sql.str(), DirName);          return ExecSqlInt(sql.str(), DirName);
262      }      }
263    
264        int InstrumentsDb::GetDirectoryId(int InstrId) {
265            dmsg(2,("InstrumentsDb: GetDirectoryId(InstrId=%d)\n", InstrId));
266            std::stringstream sql;
267            sql << "SELECT dir_id FROM instruments WHERE instr_id=" << InstrId;
268            return ExecSqlInt(sql.str());
269        }
270    
271      String InstrumentsDb::GetDirectoryName(int DirId) {      String InstrumentsDb::GetDirectoryName(int DirId) {
272          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);
273          String name = ExecSqlString(sql);          String name = ExecSqlString(sql);
# Line 274  namespace LinuxSampler { Line 292  namespace LinuxSampler {
292                  path = "/" + path;                  path = "/" + path;
293                  break;                  break;
294              }              }
295              path = GetDirectoryName(DirId) + path;              path = GetDirectoryName(DirId) + "/" + path;
296              DirId = GetParentDirectoryId(DirId);              DirId = GetParentDirectoryId(DirId);
297          }          }
298    
# Line 282  namespace LinuxSampler { Line 300  namespace LinuxSampler {
300    
301          return path;          return path;
302      }      }
303        
304        StringListPtr InstrumentsDb::GetInstrumentsByFile(String File) {
305            dmsg(2,("InstrumentsDb: GetInstrumentsByFile(File=%s)\n", File.c_str()));
306    
307            StringListPtr instrs(new std::vector<String>);
308            
309            BeginTransaction();
310            try {
311                File = toEscapedFsPath(File);
312                IntListPtr ids = ExecSqlIntList("SELECT instr_id FROM instruments WHERE instr_file=?", File);
313                
314                for (int i = 0; i < ids->size(); i++) {
315                    String name = GetInstrumentName(ids->at(i));
316                    String dir = GetDirectoryPath(GetDirectoryId(ids->at(i)));
317                    instrs->push_back(dir + name);
318                }
319            } catch (Exception e) {
320                EndTransaction();
321                throw e;
322            }
323            EndTransaction();
324            
325            return instrs;
326        }
327    
328      void InstrumentsDb::AddDirectory(String Dir) {      void InstrumentsDb::AddDirectory(String Dir) {
329          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 338  namespace LinuxSampler {
338    
339              String dirName = GetFileName(Dir);              String dirName = GetFileName(Dir);
340              if(ParentDir.empty() || dirName.empty()) {              if(ParentDir.empty() || dirName.empty()) {
341                  throw Exception("Failed to add DB directory: " + Dir);                  throw Exception("Failed to add DB directory: " + toEscapedPath(Dir));
342              }              }
343    
344              int id = GetDirectoryId(ParentDir);              int id = GetDirectoryId(ParentDir);
345              if (id == -1) throw Exception("DB directory doesn't exist: " + ParentDir);              if (id == -1) throw Exception("DB directory doesn't exist: " + toEscapedPath(ParentDir));
346              int id2 = GetDirectoryId(id, dirName);              int id2 = GetDirectoryId(id, dirName);
347              if (id2 != -1) throw Exception("DB directory already exist: " + Dir);              if (id2 != -1) throw Exception("DB directory already exist: " + toEscapedPath(Dir));
348              id2 = GetInstrumentId(id, dirName);              id2 = GetInstrumentId(id, dirName);
349              if (id2 != -1) throw Exception("Instrument with that name exist: " + Dir);              if (id2 != -1) throw Exception("Instrument with that name exist: " + toEscapedPath(Dir));
350    
351              std::stringstream sql;              std::stringstream sql;
352              sql << "INSERT INTO instr_dirs (parent_dir_id, dir_name) VALUES (";              sql << "INSERT INTO instr_dirs (parent_dir_id, dir_name) VALUES (";
353              sql << id << ", ?)";              sql << id << ", ?)";
354    
355              ExecSql(sql.str(), dirName);              ExecSql(sql.str(), toDbName(dirName));
356          } catch (Exception e) {          } catch (Exception e) {
357              EndTransaction();              EndTransaction();
358              throw e;              throw e;
# Line 329  namespace LinuxSampler { Line 371  namespace LinuxSampler {
371          BeginTransaction();          BeginTransaction();
372          try {          try {
373              int dirId = GetDirectoryId(Dir);              int dirId = GetDirectoryId(Dir);
374              if (dirId == -1) throw Exception("Unknown DB directory: " + Dir);              if (dirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
375              if (dirId == 0) throw Exception("Cannot delete the root directory: " + Dir);              if (dirId == 0) throw Exception("Cannot delete the root directory: " + Dir);
376              if(ParentDir.empty()) throw Exception("Unknown parent directory");              if(ParentDir.empty()) throw Exception("Unknown parent directory");
377              if (Force) RemoveDirectoryContent(dirId);              if (Force) RemoveDirectoryContent(dirId);
# Line 416  namespace LinuxSampler { Line 458  namespace LinuxSampler {
458    
459          try {          try {
460              int id = GetDirectoryId(Dir);              int id = GetDirectoryId(Dir);
461              if(id == -1) throw Exception("Unknown DB directory: " + Dir);              if(id == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
462    
463              sqlite3_stmt *pStmt = NULL;              sqlite3_stmt *pStmt = NULL;
464              std::stringstream sql;              std::stringstream sql;
# Line 439  namespace LinuxSampler { Line 481  namespace LinuxSampler {
481                  if (res != SQLITE_DONE) {                  if (res != SQLITE_DONE) {
482                      throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));                      throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
483                  } else {                  } else {
484                      throw Exception("Unknown DB directory: " + Dir);                      throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
485                  }                  }
486              }              }
487                            
# Line 456  namespace LinuxSampler { Line 498  namespace LinuxSampler {
498      void InstrumentsDb::RenameDirectory(String Dir, String Name) {      void InstrumentsDb::RenameDirectory(String Dir, String Name) {
499          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()));
500          CheckFileName(Name);          CheckFileName(Name);
501            String dbName = toDbName(Name);
502    
503          BeginTransaction();          BeginTransaction();
504          try {          try {
505              int dirId = GetDirectoryId(Dir);              int dirId = GetDirectoryId(Dir);
506              if (dirId == -1) throw Exception("Unknown DB directory: " + Dir);              if (dirId == -1) throw Exception("Unknown DB directory: " + toEscapedText(Dir));
507    
508              std::stringstream sql;              std::stringstream sql;
509              sql << "SELECT parent_dir_id FROM instr_dirs WHERE dir_id=" <<  dirId;              sql << "SELECT parent_dir_id FROM instr_dirs WHERE dir_id=" <<  dirId;
510    
511              int parent = ExecSqlInt(sql.str());              int parent = ExecSqlInt(sql.str());
512              if (parent == -1) throw Exception("Unknown parent directory: " + Dir);              if (parent == -1) throw Exception("Unknown parent directory: " + toEscapedPath(Dir));
513              if (GetDirectoryId(parent, Name) != -1) {  
514                  throw Exception("Cannot rename. Directory with that name already exists: " + Name);              if (GetDirectoryId(parent, dbName) != -1) {
515                    String s = toEscapedPath(Name);
516                    throw Exception("Cannot rename. Directory with that name already exists: " + s);
517              }              }
518    
519              if (GetInstrumentId(parent, Name) != -1) {              if (GetInstrumentId(parent, dbName) != -1) {
520                  throw Exception("Cannot rename. Instrument with that name exist: " + Dir);                  throw Exception("Cannot rename. Instrument with that name exist: " + toEscapedPath(Dir));
521              }              }
522    
523              sql.str("");              sql.str("");
524              sql << "UPDATE instr_dirs SET dir_name=? WHERE dir_id=" << dirId;              sql << "UPDATE instr_dirs SET dir_name=? WHERE dir_id=" << dirId;
525              ExecSql(sql.str(), Name);              ExecSql(sql.str(), dbName);
526          } catch (Exception e) {          } catch (Exception e) {
527              EndTransaction();              EndTransaction();
528              throw e;              throw e;
529          }          }
530    
531          EndTransaction();          EndTransaction();
532          FireDirectoryNameChanged(Dir, Name);          FireDirectoryNameChanged(Dir, toAbstractName(Name));
533      }      }
534    
535      void InstrumentsDb::MoveDirectory(String Dir, String Dst) {      void InstrumentsDb::MoveDirectory(String Dir, String Dst) {
# Line 497  namespace LinuxSampler { Line 542  namespace LinuxSampler {
542          BeginTransaction();          BeginTransaction();
543          try {          try {
544              int dirId = GetDirectoryId(Dir);              int dirId = GetDirectoryId(Dir);
545              if (dirId == -1) throw Exception("Unknown DB directory: " + Dir);              if (dirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
546              int dstId = GetDirectoryId(Dst);              int dstId = GetDirectoryId(Dst);
547              if (dstId == -1) throw Exception("Unknown DB directory: " + Dst);              if (dstId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dst));
548              if (dirId == dstId) {              if (dirId == dstId) {
549                  throw Exception("Cannot move directory to itself");                  throw Exception("Cannot move directory to itself");
550              }              }
# Line 515  namespace LinuxSampler { Line 560  namespace LinuxSampler {
560              String dirName = GetFileName(Dir);              String dirName = GetFileName(Dir);
561    
562              int id2 = GetDirectoryId(dstId, dirName);              int id2 = GetDirectoryId(dstId, dirName);
563              if (id2 != -1) throw Exception("DB directory already exist: " + dirName);              if (id2 != -1) throw Exception("DB directory already exist: " + toEscapedPath(dirName));
564              id2 = GetInstrumentId(dstId, dirName);              id2 = GetInstrumentId(dstId, dirName);
565              if (id2 != -1) throw Exception("Instrument with that name exist: " + dirName);              if (id2 != -1) throw Exception("Instrument with that name exist: " + toEscapedPath(dirName));
566    
567              std::stringstream sql;              std::stringstream sql;
568              sql << "UPDATE instr_dirs SET parent_dir_id=" << dstId;              sql << "UPDATE instr_dirs SET parent_dir_id=" << dstId;
# Line 543  namespace LinuxSampler { Line 588  namespace LinuxSampler {
588          BeginTransaction();          BeginTransaction();
589          try {          try {
590              int dirId = GetDirectoryId(Dir);              int dirId = GetDirectoryId(Dir);
591              if (dirId == -1) throw Exception("Unknown DB directory: " + Dir);              if (dirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
592              int dstId = GetDirectoryId(Dst);              int dstId = GetDirectoryId(Dst);
593              if (dstId == -1) throw Exception("Unknown DB directory: " + Dst);              if (dstId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dst));
594              if (dirId == dstId) {              if (dirId == dstId) {
595                  throw Exception("Cannot copy directory to itself");                  throw Exception("Cannot copy directory to itself");
596              }              }
# Line 561  namespace LinuxSampler { Line 606  namespace LinuxSampler {
606              String dirName = GetFileName(Dir);              String dirName = GetFileName(Dir);
607    
608              int id2 = GetDirectoryId(dstId, dirName);              int id2 = GetDirectoryId(dstId, dirName);
609              if (id2 != -1) throw Exception("DB directory already exist: " + dirName);              if (id2 != -1) throw Exception("DB directory already exist: " + toEscapedPath(dirName));
610              id2 = GetInstrumentId(dstId, dirName);              id2 = GetInstrumentId(dstId, dirName);
611              if (id2 != -1) throw Exception("Instrument with that name exist: " + dirName);              if (id2 != -1) throw Exception("Instrument with that name exist: " + toEscapedPath(dirName));
612    
613              DirectoryCopier directoryCopier(ParentDir, Dst);              DirectoryCopier directoryCopier(ParentDir, Dst);
614              DirectoryTreeWalk(Dir, &directoryCopier);              DirectoryTreeWalk(Dir, &directoryCopier);
# Line 581  namespace LinuxSampler { Line 626  namespace LinuxSampler {
626          BeginTransaction();          BeginTransaction();
627          try {          try {
628              int id = GetDirectoryId(Dir);              int id = GetDirectoryId(Dir);
629              if(id == -1) throw Exception("Unknown DB directory: " + Dir);              if(id == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
630    
631              std::stringstream sql;              std::stringstream sql;
632              sql << "UPDATE instr_dirs SET description=?,modified=CURRENT_TIMESTAMP ";              sql << "UPDATE instr_dirs SET description=?,modified=CURRENT_TIMESTAMP ";
# Line 597  namespace LinuxSampler { Line 642  namespace LinuxSampler {
642          FireDirectoryInfoChanged(Dir);          FireDirectoryInfoChanged(Dir);
643      }      }
644    
645      int InstrumentsDb::AddInstruments(ScanMode Mode, String DbDir, String FsDir, bool bBackground) {      int InstrumentsDb::AddInstruments(ScanMode Mode, String DbDir, String FsDir, bool bBackground, bool insDir) {
646          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));
647          if(!bBackground) {          if(!bBackground) {
648              switch (Mode) {              switch (Mode) {
649                  case NON_RECURSIVE:                  case NON_RECURSIVE:
650                      AddInstrumentsNonrecursive(DbDir, FsDir);                      AddInstrumentsNonrecursive(DbDir, FsDir, insDir);
651                      break;                      break;
652                  case RECURSIVE:                  case RECURSIVE:
653                      AddInstrumentsRecursive(DbDir, FsDir);                      AddInstrumentsRecursive(DbDir, FsDir, false, insDir);
654                      break;                      break;
655                  case FLAT:                  case FLAT:
656                      AddInstrumentsRecursive(DbDir, FsDir, true);                      AddInstrumentsRecursive(DbDir, FsDir, true, insDir);
657                      break;                      break;
658                  default:                  default:
659                      throw Exception("Unknown scan mode");                      throw Exception("Unknown scan mode");
# Line 619  namespace LinuxSampler { Line 664  namespace LinuxSampler {
664    
665          ScanJob job;          ScanJob job;
666          int jobId = Jobs.AddJob(job);          int jobId = Jobs.AddJob(job);
667          InstrumentsDbThread.Execute(new AddInstrumentsJob(jobId, Mode, DbDir, FsDir));          InstrumentsDbThread.Execute(new AddInstrumentsJob(jobId, Mode, DbDir, FsDir, insDir));
668    
669          return jobId;          return jobId;
670      }      }
# Line 627  namespace LinuxSampler { Line 672  namespace LinuxSampler {
672      int InstrumentsDb::AddInstruments(String DbDir, String FilePath, int Index, bool bBackground) {      int InstrumentsDb::AddInstruments(String DbDir, String FilePath, int Index, bool bBackground) {
673          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));
674          if(!bBackground) {          if(!bBackground) {
675              AddInstruments(DbDir, FilePath, Index);              AddInstruments(DbDir, false, FilePath, Index);
676              return -1;              return -1;
677          }          }
678    
679          ScanJob job;          ScanJob job;
680          int jobId = Jobs.AddJob(job);          int jobId = Jobs.AddJob(job);
681          InstrumentsDbThread.Execute(new AddInstrumentsFromFileJob(jobId, DbDir, FilePath, Index));          InstrumentsDbThread.Execute(new AddInstrumentsFromFileJob(jobId, DbDir, FilePath, Index, false));
682    
683          return jobId;          return jobId;
684      }      }
685    
686      void InstrumentsDb::AddInstruments(String DbDir, String FilePath, int Index, ScanProgress* pProgress) {      void InstrumentsDb::AddInstruments(String DbDir, bool insDir, String FilePath, int Index, ScanProgress* pProgress) {
687          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));
688          if (DbDir.empty() || FilePath.empty()) return;          if (DbDir.empty() || FilePath.empty()) return;
689                    
690          DbInstrumentsMutex.Lock();          DbInstrumentsMutex.Lock();
691          try {          try {
692              int dirId = GetDirectoryId(DbDir);              int dirId = GetDirectoryId(DbDir);
693              if (dirId == -1) throw Exception("Invalid DB directory: " + DbDir);              if (dirId == -1) throw Exception("Invalid DB directory: " + toEscapedText(DbDir));
694    
695              struct stat statBuf;              File f = File(FilePath);
696              int res = stat(FilePath.c_str(), &statBuf);              if (!f.Exist()) {
             if (res) {  
697                  std::stringstream ss;                  std::stringstream ss;
698                  ss << "Fail to stat `" << FilePath << "`: " << strerror(errno);                  ss << "Fail to stat `" << FilePath << "`: " << f.GetErrorMsg();
699                  throw Exception(ss.str());                  throw Exception(ss.str());
700              }              }
701    
702              if (!S_ISREG(statBuf.st_mode)) {              if (!f.IsFile()) {
703                  std::stringstream ss;                  std::stringstream ss;
704                  ss << "`" << FilePath << "` is not an instrument file";                  ss << "`" << FilePath << "` is not an instrument file";
705                  throw Exception(ss.str());                  throw Exception(ss.str());
706              }              }
707    
708              AddInstrumentsFromFile(DbDir, FilePath, Index, pProgress);              String dir = insDir ? PrepareSubdirectory(DbDir, FilePath) : DbDir;
709                AddInstrumentsFromFile(dir, FilePath, Index, pProgress);
710          } catch (Exception e) {          } catch (Exception e) {
711              DbInstrumentsMutex.Unlock();              DbInstrumentsMutex.Unlock();
712              throw e;              throw e;
# Line 670  namespace LinuxSampler { Line 715  namespace LinuxSampler {
715          DbInstrumentsMutex.Unlock();          DbInstrumentsMutex.Unlock();
716      }      }
717    
718      void InstrumentsDb::AddInstrumentsNonrecursive(String DbDir, String FsDir, ScanProgress* pProgress) {      void InstrumentsDb::AddInstrumentsNonrecursive(String DbDir, String FsDir, bool insDir, ScanProgress* pProgress) {
719          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));
720          if (DbDir.empty() || FsDir.empty()) return;          if (DbDir.empty() || FsDir.empty()) return;
721                    
722          DbInstrumentsMutex.Lock();          DbInstrumentsMutex.Lock();
723          try {          try {
724              int dirId = GetDirectoryId(DbDir);              int dirId = GetDirectoryId(DbDir);
725              if (dirId == -1) throw Exception("Invalid DB directory: " + DbDir);              if (dirId == -1) throw Exception("Invalid DB directory: " + toEscapedPath(DbDir));
726    
727              struct stat statBuf;              File f = File(FsDir);
728              int res = stat(FsDir.c_str(), &statBuf);              if (!f.Exist()) {
             if (res) {  
729                  std::stringstream ss;                  std::stringstream ss;
730                  ss << "Fail to stat `" << FsDir << "`: " << strerror(errno);                  ss << "Fail to stat `" << FsDir << "`: " << f.GetErrorMsg();
731                  throw Exception(ss.str());                  throw Exception(ss.str());
732              }              }
733    
734              if (!S_ISDIR(statBuf.st_mode)) {              if (!f.IsDirectory()) {
735                  throw Exception("Directory expected");                  throw Exception("Directory expected: " + FsDir);
736              }              }
737                            
738              if (FsDir.at(FsDir.length() - 1) != '/') FsDir.append("/");              if (FsDir.at(FsDir.length() - 1) != File::DirSeparator) {
739                    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;  
740              }              }
741                
742              struct dirent* pEnt = readdir(pDir);              try {
743              while (pEnt != NULL) {                  FileListPtr fileList = File::GetFiles(FsDir);
744                  if (pEnt->d_type != DT_REG) {                  for (int i = 0; i < fileList->size(); i++) {
745                      pEnt = readdir(pDir);                      String dir = insDir ? PrepareSubdirectory(DbDir, fileList->at(i)) : DbDir;
746                      continue;                                          AddInstrumentsFromFile(dir, FsDir + fileList->at(i), -1, pProgress);
747                  }                  }
748                } catch(Exception e) {
749                  AddInstrumentsFromFile(DbDir, FsDir + String(pEnt->d_name), -1, pProgress);                  e.PrintMessage();
750                  pEnt = readdir(pDir);                  DbInstrumentsMutex.Unlock();
751              }                  return;
   
             if (closedir(pDir)) {  
                 std::stringstream ss;  
                 ss << "Failed to close directory `" << FsDir << "`: ";  
                 ss << strerror(errno);  
                 std::cerr << ss.str();  
752              }              }
753          } catch (Exception e) {          } catch (Exception e) {
754              DbInstrumentsMutex.Unlock();              DbInstrumentsMutex.Unlock();
# Line 728  namespace LinuxSampler { Line 758  namespace LinuxSampler {
758          DbInstrumentsMutex.Unlock();          DbInstrumentsMutex.Unlock();
759      }      }
760    
761      void InstrumentsDb::AddInstrumentsRecursive(String DbDir, String FsDir, bool Flat, ScanProgress* pProgress) {      void InstrumentsDb::AddInstrumentsRecursive(String DbDir, String FsDir, bool Flat, bool insDir, ScanProgress* pProgress) {
762          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));
763          if (pProgress != NULL) {          if (pProgress != NULL) {
764              pProgress->SetTotalFileCount(InstrumentFileCounter::Count(FsDir));              InstrumentFileCounter c;
765                pProgress->SetTotalFileCount(c.Count(FsDir));
766          }          }
767    
768          DirectoryScanner::Scan(DbDir, FsDir, Flat, pProgress);          DirectoryScanner d;
769            d.Scan(DbDir, FsDir, Flat, insDir, pProgress);
770      }      }
771    
772      int InstrumentsDb::GetInstrumentCount(int DirId) {      int InstrumentsDb::GetInstrumentCount(int DirId) {
# Line 766  namespace LinuxSampler { Line 798  namespace LinuxSampler {
798          }          }
799          EndTransaction();          EndTransaction();
800    
801          if (i == -1) throw Exception("Unknown Db directory: " + Dir);          if (i == -1) throw Exception("Unknown Db directory: " + toEscapedPath(Dir));
802          return i;          return i;
803      }      }
804    
# Line 782  namespace LinuxSampler { Line 814  namespace LinuxSampler {
814          BeginTransaction();          BeginTransaction();
815          try {          try {
816              int dirId = GetDirectoryId(Dir);              int dirId = GetDirectoryId(Dir);
817              if(dirId == -1) throw Exception("Unknown DB directory: " + Dir);              if(dirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
818    
819              StringListPtr pInstrs;              StringListPtr pInstrs;
820    
# Line 796  namespace LinuxSampler { Line 828  namespace LinuxSampler {
828                  sql << "SELECT instr_name FROM instruments WHERE dir_id=" << dirId;                  sql << "SELECT instr_name FROM instruments WHERE dir_id=" << dirId;
829    
830                  pInstrs = ExecSqlStringList(sql.str());                  pInstrs = ExecSqlStringList(sql.str());
831                    // Converting to abstract names
832                    for (int i = 0; i < pInstrs->size(); i++) {
833                        for (int j = 0; j < pInstrs->at(i).length(); j++) {
834                            if (pInstrs->at(i).at(j) == '/') pInstrs->at(i).at(j) = '\0';
835                        }
836                    }
837              }              }
838              EndTransaction();              EndTransaction();
839              return pInstrs;              return pInstrs;
# Line 820  namespace LinuxSampler { Line 858  namespace LinuxSampler {
858          std::stringstream sql;          std::stringstream sql;
859          sql << "SELECT instr_id FROM instruments WHERE dir_id=";          sql << "SELECT instr_id FROM instruments WHERE dir_id=";
860          sql << DirId << " AND instr_name=?";          sql << DirId << " AND instr_name=?";
861          return ExecSqlInt(sql.str(), InstrName);          return ExecSqlInt(sql.str(), toDbName(InstrName));
862      }      }
863    
864      String InstrumentsDb::GetInstrumentName(int InstrId) {      String InstrumentsDb::GetInstrumentName(int InstrId) {
865          dmsg(2,("InstrumentsDb: GetInstrumentName(InstrId=%d)\n", InstrId));          dmsg(2,("InstrumentsDb: GetInstrumentName(InstrId=%d)\n", InstrId));
866          std::stringstream sql;          std::stringstream sql;
867          sql << "SELECT instr_name FROM instruments WHERE instr_id=" << InstrId;          sql << "SELECT instr_name FROM instruments WHERE instr_id=" << InstrId;
868          return ExecSqlString(sql.str());          return toAbstractName(ExecSqlString(sql.str()));
869      }      }
870            
871      void InstrumentsDb::RemoveInstrument(String Instr) {      void InstrumentsDb::RemoveInstrument(String Instr) {
# Line 839  namespace LinuxSampler { Line 877  namespace LinuxSampler {
877          try {          try {
878              int instrId = GetInstrumentId(Instr);              int instrId = GetInstrumentId(Instr);
879              if(instrId == -1) {              if(instrId == -1) {
880                  throw Exception("The specified instrument does not exist: " + Instr);                  throw Exception("The specified instrument does not exist: " + toEscapedPath(Instr));
881              }              }
882              RemoveInstrument(instrId);              RemoveInstrument(instrId);
883          } catch (Exception e) {          } catch (Exception e) {
# Line 874  namespace LinuxSampler { Line 912  namespace LinuxSampler {
912          BeginTransaction();          BeginTransaction();
913          try {          try {
914              int id = GetInstrumentId(Instr);              int id = GetInstrumentId(Instr);
915              if(id == -1) throw Exception("Unknown DB instrument: " + Instr);              if(id == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
916              i = GetInstrumentInfo(id);              i = GetInstrumentInfo(id);
917          } catch (Exception e) {          } catch (Exception e) {
918              EndTransaction();              EndTransaction();
# Line 933  namespace LinuxSampler { Line 971  namespace LinuxSampler {
971          BeginTransaction();          BeginTransaction();
972          try {          try {
973              int dirId = GetDirectoryId(GetDirectoryPath(Instr));              int dirId = GetDirectoryId(GetDirectoryPath(Instr));
974              if (dirId == -1) throw Exception("Unknown DB instrument: " + Instr);              if (dirId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
975    
976              int instrId = GetInstrumentId(dirId, GetFileName(Instr));              int instrId = GetInstrumentId(dirId, GetFileName(Instr));
977              if (instrId == -1) throw Exception("Unknown DB instrument: " + Instr);              if (instrId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
978    
979              if (GetInstrumentId(dirId, Name) != -1) {              if (GetInstrumentId(dirId, Name) != -1) {
980                  throw Exception("Cannot rename. Instrument with that name already exists: " + Name);                  String s = toEscapedPath(Name);
981                    throw Exception("Cannot rename. Instrument with that name already exists: " + s);
982              }              }
983    
984              if (GetDirectoryId(dirId, Name) != -1) {              if (GetDirectoryId(dirId, Name) != -1) {
985                  throw Exception("Cannot rename. Directory with that name already exists: " + Name);                  String s = toEscapedPath(Name);
986                    throw Exception("Cannot rename. Directory with that name already exists: " + s);
987              }              }
988    
989              std::stringstream sql;              std::stringstream sql;
990              sql << "UPDATE instruments SET instr_name=? WHERE instr_id=" << instrId;              sql << "UPDATE instruments SET instr_name=? WHERE instr_id=" << instrId;
991              ExecSql(sql.str(), Name);              ExecSql(sql.str(), toDbName(Name));
992          } catch (Exception e) {          } catch (Exception e) {
993              EndTransaction();              EndTransaction();
994              throw e;              throw e;
995          }          }
996          EndTransaction();          EndTransaction();
997          FireInstrumentNameChanged(Instr, Name);          FireInstrumentNameChanged(Instr, toAbstractName(Name));
998      }      }
999    
1000      void InstrumentsDb::MoveInstrument(String Instr, String Dst) {      void InstrumentsDb::MoveInstrument(String Instr, String Dst) {
# Line 964  namespace LinuxSampler { Line 1004  namespace LinuxSampler {
1004    
1005          BeginTransaction();          BeginTransaction();
1006          try {          try {
1007              int dirId = GetDirectoryId(GetDirectoryPath(Instr));              int dirId = GetDirectoryId(ParentDir);
1008              if (dirId == -1) throw Exception("Unknown DB instrument: " + Instr);              if (dirId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1009    
1010              String instrName = GetFileName(Instr);              String instrName = GetFileName(Instr);
1011              int instrId = GetInstrumentId(dirId, instrName);              int instrId = GetInstrumentId(dirId, instrName);
1012              if (instrId == -1) throw Exception("Unknown DB instrument: " + Instr);              if (instrId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1013    
1014              int dstId = GetDirectoryId(Dst);              int dstId = GetDirectoryId(Dst);
1015              if (dstId == -1) throw Exception("Unknown DB directory: " + Dst);              if (dstId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dst));
1016              if (dirId == dstId) {              if (dirId == dstId) {
1017                  EndTransaction();                  EndTransaction();
1018                  return;                  return;
1019              }              }
1020    
1021              if (GetInstrumentId(dstId, instrName) != -1) {              if (GetInstrumentId(dstId, instrName) != -1) {
1022                  throw Exception("Cannot move. Instrument with that name already exists: " + instrName);                  String s = toEscapedPath(instrName);
1023                    throw Exception("Cannot move. Instrument with that name already exists: " + s);
1024              }              }
1025    
1026              if (GetDirectoryId(dstId, instrName) != -1) {              if (GetDirectoryId(dstId, instrName) != -1) {
1027                  throw Exception("Cannot move. Directory with that name already exists: " + instrName);                  String s = toEscapedPath(instrName);
1028                    throw Exception("Cannot move. Directory with that name already exists: " + s);
1029              }              }
1030    
1031              std::stringstream sql;              std::stringstream sql;
# Line 1007  namespace LinuxSampler { Line 1049  namespace LinuxSampler {
1049          BeginTransaction();          BeginTransaction();
1050          try {          try {
1051              int dirId = GetDirectoryId(GetDirectoryPath(Instr));              int dirId = GetDirectoryId(GetDirectoryPath(Instr));
1052              if (dirId == -1) throw Exception("Unknown DB instrument: " + Instr);              if (dirId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1053    
1054              String instrName = GetFileName(Instr);              String instrName = GetFileName(Instr);
1055              int instrId = GetInstrumentId(dirId, instrName);              int instrId = GetInstrumentId(dirId, instrName);
1056              if (instrId == -1) throw Exception("Unknown DB instrument: " + Instr);              if (instrId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1057    
1058              int dstId = GetDirectoryId(Dst);              int dstId = GetDirectoryId(Dst);
1059              if (dstId == -1) throw Exception("Unknown DB directory: " + Dst);              if (dstId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dst));
1060              if (dirId == dstId) {              if (dirId == dstId) {
1061                  EndTransaction();                  EndTransaction();
1062                  return;                  return;
1063              }              }
1064    
             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);  
             }  
   
1065              CopyInstrument(instrId, instrName, dstId, Dst);              CopyInstrument(instrId, instrName, dstId, Dst);
1066          } catch (Exception e) {          } catch (Exception e) {
1067              EndTransaction();              EndTransaction();
# Line 1038  namespace LinuxSampler { Line 1072  namespace LinuxSampler {
1072      }      }
1073    
1074      void InstrumentsDb::CopyInstrument(int InstrId, String InstrName, int DstDirId, String DstDir) {      void InstrumentsDb::CopyInstrument(int InstrId, String InstrName, int DstDirId, String DstDir) {
1075            if (GetInstrumentId(DstDirId, InstrName) != -1) {
1076                String s = toEscapedPath(InstrName);
1077                throw Exception("Cannot copy. Instrument with that name already exists: " + s);
1078            }
1079    
1080            if (GetDirectoryId(DstDirId, InstrName) != -1) {
1081                String s = toEscapedPath(InstrName);
1082                throw Exception("Cannot copy. Directory with that name already exists: " + s);
1083            }
1084    
1085          DbInstrument i = GetInstrumentInfo(InstrId);          DbInstrument i = GetInstrumentInfo(InstrId);
1086          sqlite3_stmt *pStmt = NULL;          sqlite3_stmt *pStmt = NULL;
1087          std::stringstream sql;          std::stringstream sql;
# Line 1051  namespace LinuxSampler { Line 1095  namespace LinuxSampler {
1095              throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));              throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1096          }          }
1097    
1098          BindTextParam(pStmt, 1, InstrName);          String s = toDbName(InstrName);
1099            BindTextParam(pStmt, 1, s);
1100          BindTextParam(pStmt, 2, i.InstrFile);          BindTextParam(pStmt, 2, i.InstrFile);
1101          BindTextParam(pStmt, 3, i.FormatFamily);          BindTextParam(pStmt, 3, i.FormatFamily);
1102          BindTextParam(pStmt, 4, i.FormatVersion);          BindTextParam(pStmt, 4, i.FormatVersion);
# Line 1076  namespace LinuxSampler { Line 1121  namespace LinuxSampler {
1121          BeginTransaction();          BeginTransaction();
1122          try {          try {
1123              int id = GetInstrumentId(Instr);              int id = GetInstrumentId(Instr);
1124              if(id == -1) throw Exception("Unknown DB instrument: " + Instr);              if(id == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1125    
1126              std::stringstream sql;              std::stringstream sql;
1127              sql << "UPDATE instruments SET description=?,modified=CURRENT_TIMESTAMP ";              sql << "UPDATE instruments SET description=?,modified=CURRENT_TIMESTAMP ";
# Line 1110  namespace LinuxSampler { Line 1155  namespace LinuxSampler {
1155                  }                  }
1156              }              }
1157          } catch(Exception e) {          } catch(Exception e) {
1158              std::cerr << e.Message() << std::endl;              e.PrintMessage();
1159          }          }
1160      }      }
1161    
1162      void InstrumentsDb::AddGigInstruments(String DbDir, String File, int Index, ScanProgress* pProgress) {      void InstrumentsDb::AddGigInstruments(String DbDir, String FilePath, int Index, ScanProgress* pProgress) {
1163          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));
1164          int dirId = GetDirectoryId(DbDir);          int dirId = GetDirectoryId(DbDir);
1165          if (dirId == -1) throw Exception("Invalid DB directory: " + DbDir);          if (dirId == -1) throw Exception("Invalid DB directory: " + toEscapedPath(DbDir));
1166    
1167          struct stat statBuf;          File f = File(FilePath);
1168          int res = stat(File.c_str(), &statBuf);          if (!f.Exist()) {
         if (res) {  
1169              std::stringstream ss;              std::stringstream ss;
1170              ss << "Fail to stat `" << File << "`: " << strerror(errno);              ss << "Fail to stat `" << FilePath << "`: " << f.GetErrorMsg();
1171              throw Exception(ss.str());              throw Exception(ss.str());
1172          }          }
1173    
1174          if (!S_ISREG(statBuf.st_mode)) {          if (!f.IsFile()) {
1175              std::stringstream ss;              std::stringstream ss;
1176              ss << "`" << File << "` is not a regular file";              ss << "`" << FilePath << "` is not a regular file";
1177              throw Exception(ss.str());              throw Exception(ss.str());
1178          }          }
1179    
1180          RIFF::File* riff = NULL;          RIFF::File* riff = NULL;
1181          gig::File* gig = NULL;          gig::File* gig = NULL;
1182          try {          try {
1183              riff = new RIFF::File(File);              riff = new RIFF::File(FilePath);
1184              gig::File* gig = new gig::File(riff);              gig::File* gig = new gig::File(riff);
1185                gig->SetAutoLoad(false); // avoid time consuming samples scanning
1186    
1187              std::stringstream sql;              std::stringstream sql;
1188              sql << "INSERT INTO instruments (dir_id,instr_name,instr_file,";              sql << "INSERT INTO instruments (dir_id,instr_name,instr_file,";
1189              sql << "instr_nr,format_family,format_version,instr_size,";              sql << "instr_nr,format_family,format_version,instr_size,";
1190              sql << "description,is_drum,product,artists,keywords) VALUES (";              sql << "description,is_drum,product,artists,keywords) VALUES (";
1191              sql << dirId << ",?,?,?,'GIG',?," << statBuf.st_size << ",?,?,?,?,?)";              sql << dirId << ",?,?,?,'GIG',?," << f.GetSize() << ",?,?,?,?,?)";
1192    
1193              sqlite3_stmt* pStmt = NULL;              sqlite3_stmt* pStmt = NULL;
1194    
# Line 1152  namespace LinuxSampler { Line 1197  namespace LinuxSampler {
1197                  throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));                  throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1198              }              }
1199    
1200              BindTextParam(pStmt, 2, File);              String s = toEscapedFsPath(FilePath);
1201                BindTextParam(pStmt, 2, s);
1202              String ver = "";              String ver = "";
1203              if (gig->pVersion != NULL) ver = ToString(gig->pVersion->major);              if (gig->pVersion != NULL) ver = ToString(gig->pVersion->major);
1204              BindTextParam(pStmt, 4, ver);              BindTextParam(pStmt, 4, ver);
# Line 1165  namespace LinuxSampler { Line 1211  namespace LinuxSampler {
1211                      BindTextParam(pStmt, 7, gig->pInfo->Product);                      BindTextParam(pStmt, 7, gig->pInfo->Product);
1212                      BindTextParam(pStmt, 8, gig->pInfo->Artists);                      BindTextParam(pStmt, 8, gig->pInfo->Artists);
1213                      BindTextParam(pStmt, 9, gig->pInfo->Keywords);                      BindTextParam(pStmt, 9, gig->pInfo->Keywords);
1214                      AddGigInstrument(pStmt, DbDir, dirId, File, pInstrument, instrIndex);                      AddGigInstrument(pStmt, DbDir, dirId, FilePath, pInstrument, instrIndex);
1215    
1216                      instrIndex++;                      instrIndex++;
1217                      pInstrument = gig->GetNextInstrument();                      pInstrument = gig->GetNextInstrument();
# Line 1178  namespace LinuxSampler { Line 1224  namespace LinuxSampler {
1224                      BindTextParam(pStmt, 7, gig->pInfo->Product);                      BindTextParam(pStmt, 7, gig->pInfo->Product);
1225                      BindTextParam(pStmt, 8, gig->pInfo->Artists);                      BindTextParam(pStmt, 8, gig->pInfo->Artists);
1226                      BindTextParam(pStmt, 9, gig->pInfo->Keywords);                      BindTextParam(pStmt, 9, gig->pInfo->Keywords);
1227                      AddGigInstrument(pStmt, DbDir, dirId, File, pInstrument, Index);                      AddGigInstrument(pStmt, DbDir, dirId, FilePath, pInstrument, Index);
1228                  }                  }
1229              }              }
1230    
# Line 1189  namespace LinuxSampler { Line 1235  namespace LinuxSampler {
1235              if (gig != NULL) delete gig;              if (gig != NULL) delete gig;
1236              if (riff != NULL) delete riff;              if (riff != NULL) delete riff;
1237              std::stringstream ss;              std::stringstream ss;
1238              ss << "Failed to scan `" << File << "`: " << e.Message;              ss << "Failed to scan `" << FilePath << "`: " << e.Message;
1239                            
1240              throw Exception(ss.str());              throw Exception(ss.str());
1241          } catch (Exception e) {          } catch (Exception e) {
# Line 1199  namespace LinuxSampler { Line 1245  namespace LinuxSampler {
1245          } catch (...) {          } catch (...) {
1246              if (gig != NULL) delete gig;              if (gig != NULL) delete gig;
1247              if (riff != NULL) delete riff;              if (riff != NULL) delete riff;
1248              throw Exception("Failed to scan `" + File + "`");              throw Exception("Failed to scan `" + FilePath + "`");
1249          }          }
1250      }      }
1251    
1252      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) {
1253            dmsg(2,("InstrumentsDb: AddGigInstrument(DbDir=%s,DirId=%d,File=%s,Index=%d)\n", DbDir.c_str(), DirId, File.c_str(), Index));
1254          String name = pInstrument->pInfo->Name;          String name = pInstrument->pInfo->Name;
1255          if (name == "") return;          if (name == "") return;
1256          name = GetUniqueInstrumentName(DirId, name);          name = GetUniqueName(DirId, name);
1257                    
1258          std::stringstream sql2;          std::stringstream sql2;
1259          sql2 << "SELECT COUNT(*) FROM instruments WHERE instr_file=? AND ";          sql2 << "SELECT COUNT(*) FROM instruments WHERE instr_file=? AND ";
1260          sql2 << "instr_nr=" << Index;          sql2 << "instr_nr=" << Index;
1261          if (ExecSqlInt(sql2.str(), File) > 0) return;          String s = toEscapedFsPath(File);
1262            if (ExecSqlInt(sql2.str(), s) > 0) return;
1263    
1264          BindTextParam(pStmt, 1, name);          BindTextParam(pStmt, 1, name);
1265          BindIntParam(pStmt, 3, Index);          BindIntParam(pStmt, 3, Index);
# Line 1240  namespace LinuxSampler { Line 1288  namespace LinuxSampler {
1288          FireInstrumentCountChanged(DbDir);          FireInstrumentCountChanged(DbDir);
1289      }      }
1290    
1291      void InstrumentsDb::DirectoryTreeWalk(String Path, DirectoryHandler* pHandler) {      void InstrumentsDb::DirectoryTreeWalk(String AbstractPath, DirectoryHandler* pHandler) {
1292          int DirId = GetDirectoryId(Path);          int DirId = GetDirectoryId(AbstractPath);
1293          if(DirId == -1) throw Exception("Unknown DB directory: " + Path);          if(DirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(AbstractPath));
1294          DirectoryTreeWalk(pHandler, Path, DirId, 0);          DirectoryTreeWalk(pHandler, AbstractPath, DirId, 0);
1295      }      }
1296    
1297      void InstrumentsDb::DirectoryTreeWalk(DirectoryHandler* pHandler, String Path, int DirId, int Level) {      void InstrumentsDb::DirectoryTreeWalk(DirectoryHandler* pHandler, String AbstractPath, int DirId, int Level) {
1298          if(Level == 1000) throw Exception("Possible infinite loop detected");          if(Level == 1000) throw Exception("Possible infinite loop detected");
1299          pHandler->ProcessDirectory(Path, DirId);          pHandler->ProcessDirectory(AbstractPath, DirId);
1300                    
1301          String s;          String s;
1302          StringListPtr pDirs = GetDirectories(DirId);          StringListPtr pDirs = GetDirectories(DirId);
1303          for(int i = 0; i < pDirs->size(); i++) {          for(int i = 0; i < pDirs->size(); i++) {
1304              if (Path.length() == 1 && Path.at(0) == '/') s = "/" + pDirs->at(i);              if (AbstractPath.length() == 1 && AbstractPath.at(0) == '/') {
1305              else s = Path + "/" + pDirs->at(i);                  s = "/" + pDirs->at(i);
1306                } else {
1307                    s = AbstractPath + "/" + pDirs->at(i);
1308                }
1309              DirectoryTreeWalk(pHandler, s, GetDirectoryId(DirId, pDirs->at(i)), Level + 1);              DirectoryTreeWalk(pHandler, s, GetDirectoryId(DirId, pDirs->at(i)), Level + 1);
1310          }          }
1311      }      }
# Line 1266  namespace LinuxSampler { Line 1317  namespace LinuxSampler {
1317          BeginTransaction();          BeginTransaction();
1318          try {          try {
1319              int DirId = GetDirectoryId(Dir);              int DirId = GetDirectoryId(Dir);
1320              if(DirId == -1) throw Exception("Unknown DB directory: " + Dir);              if(DirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
1321    
1322              if (Recursive) DirectoryTreeWalk(Dir, &directoryFinder);              if (Recursive) DirectoryTreeWalk(Dir, &directoryFinder);
1323              else directoryFinder.ProcessDirectory(Dir, DirId);              else directoryFinder.ProcessDirectory(Dir, DirId);
# Line 1286  namespace LinuxSampler { Line 1337  namespace LinuxSampler {
1337          BeginTransaction();          BeginTransaction();
1338          try {          try {
1339              int DirId = GetDirectoryId(Dir);              int DirId = GetDirectoryId(Dir);
1340              if(DirId == -1) throw Exception("Unknown DB directory: " + Dir);              if(DirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
1341    
1342              if (Recursive) DirectoryTreeWalk(Dir, &instrumentFinder);              if (Recursive) DirectoryTreeWalk(Dir, &instrumentFinder);
1343              else instrumentFinder.ProcessDirectory(Dir, DirId);              else instrumentFinder.ProcessDirectory(Dir, DirId);
# Line 1298  namespace LinuxSampler { Line 1349  namespace LinuxSampler {
1349    
1350          return instrumentFinder.GetInstruments();          return instrumentFinder.GetInstruments();
1351      }      }
1352        
1353        StringListPtr InstrumentsDb::FindLostInstrumentFiles() {
1354            dmsg(2,("InstrumentsDb: FindLostInstrumentFiles()\n"));
1355    
1356            BeginTransaction();
1357            try {
1358                StringListPtr files = ExecSqlStringList("SELECT DISTINCT instr_file FROM instruments");
1359                StringListPtr result(new std::vector<String>);
1360                for (int i = 0; i < files->size(); i++) {
1361                    File f(toNonEscapedFsPath(files->at(i)));
1362                    if (!f.Exist()) result->push_back(files->at(i));
1363                }
1364                return result;
1365            } catch (Exception e) {
1366                EndTransaction();
1367                throw e;
1368            }
1369            EndTransaction();
1370        }
1371        
1372        void InstrumentsDb::SetInstrumentFilePath(String OldPath, String NewPath) {
1373            if (OldPath == NewPath) return;
1374            StringListPtr instrs;
1375            BeginTransaction();
1376            try {
1377                std::vector<String> params(2);
1378                params[0] = toEscapedFsPath(NewPath);
1379                params[1] = toEscapedFsPath(OldPath);
1380                instrs = GetInstrumentsByFile(OldPath);
1381                ExecSql("UPDATE instruments SET instr_file=? WHERE instr_file=?", params);
1382            } catch (Exception e) {
1383                EndTransaction();
1384                throw e;
1385            }
1386            EndTransaction();
1387            
1388            for (int i = 0; i < instrs->size(); i++) {
1389                FireInstrumentInfoChanged(instrs->at(i));
1390            }
1391        }
1392    
1393      void InstrumentsDb::BeginTransaction() {      void InstrumentsDb::BeginTransaction() {
1394          dmsg(2,("InstrumentsDb: BeginTransaction(InTransaction=%d)\n", InTransaction));          dmsg(2,("InstrumentsDb: BeginTransaction(InTransaction=%d)\n", InTransaction));
# Line 1359  namespace LinuxSampler { Line 1450  namespace LinuxSampler {
1450    
1451      void InstrumentsDb::ExecSql(String Sql) {      void InstrumentsDb::ExecSql(String Sql) {
1452          dmsg(2,("InstrumentsDb: ExecSql(Sql=%s)\n", Sql.c_str()));          dmsg(2,("InstrumentsDb: ExecSql(Sql=%s)\n", Sql.c_str()));
1453          sqlite3_stmt *pStmt = NULL;          std::vector<String> Params;
1454                    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);  
1455      }      }
1456    
1457      void InstrumentsDb::ExecSql(String Sql, String Param) {      void InstrumentsDb::ExecSql(String Sql, String Param) {
1458          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()));
1459            std::vector<String> Params;
1460            Params.push_back(Param);
1461            ExecSql(Sql, Params);
1462        }
1463    
1464        void InstrumentsDb::ExecSql(String Sql, std::vector<String>& Params) {
1465            dmsg(2,("InstrumentsDb: ExecSql(Sql=%s,Params)\n", Sql.c_str()));
1466          sqlite3_stmt *pStmt = NULL;          sqlite3_stmt *pStmt = NULL;
1467                    
1468          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 1471  namespace LinuxSampler {
1471              throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));              throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1472          }          }
1473    
1474          BindTextParam(pStmt, 1, Param);          for(int i = 0; i < Params.size(); i++) {
1475                BindTextParam(pStmt, i + 1, Params[i]);
1476            }
1477    
1478          res = sqlite3_step(pStmt);          res = sqlite3_step(pStmt);
1479          if (res != SQLITE_DONE) {          if (res != SQLITE_DONE) {
# Line 1467  namespace LinuxSampler { Line 1555  namespace LinuxSampler {
1555      }      }
1556    
1557      IntListPtr InstrumentsDb::ExecSqlIntList(String Sql) {      IntListPtr InstrumentsDb::ExecSqlIntList(String Sql) {
1558            dmsg(2,("InstrumentsDb: ExecSqlIntList(Sql=%s)\n", Sql.c_str()));
1559            std::vector<String> Params;
1560            return ExecSqlIntList(Sql, Params);
1561        }
1562    
1563        IntListPtr InstrumentsDb::ExecSqlIntList(String Sql, String Param) {
1564            dmsg(2,("InstrumentsDb: ExecSqlIntList(Sql=%s,Param=%s)\n", Sql.c_str(), Param.c_str()));
1565            std::vector<String> Params;
1566            Params.push_back(Param);
1567            return ExecSqlIntList(Sql, Params);
1568        }
1569    
1570        IntListPtr InstrumentsDb::ExecSqlIntList(String Sql, std::vector<String>& Params) {
1571            dmsg(2,("InstrumentsDb: ExecSqlIntList(Sql=%s)\n", Sql.c_str()));
1572          IntListPtr intList(new std::vector<int>);          IntListPtr intList(new std::vector<int>);
1573                    
1574          sqlite3_stmt *pStmt = NULL;          sqlite3_stmt *pStmt = NULL;
# Line 1476  namespace LinuxSampler { Line 1578  namespace LinuxSampler {
1578              throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));              throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1579          }          }
1580                    
1581            for(int i = 0; i < Params.size(); i++) {
1582                BindTextParam(pStmt, i + 1, Params[i]);
1583            }
1584            
1585          res = sqlite3_step(pStmt);          res = sqlite3_step(pStmt);
1586          while(res == SQLITE_ROW) {          while(res == SQLITE_ROW) {
1587              intList->push_back(sqlite3_column_int(pStmt, 0));              intList->push_back(sqlite3_column_int(pStmt, 0));
# Line 1493  namespace LinuxSampler { Line 1599  namespace LinuxSampler {
1599      }      }
1600            
1601      StringListPtr InstrumentsDb::ExecSqlStringList(String Sql) {      StringListPtr InstrumentsDb::ExecSqlStringList(String Sql) {
1602            dmsg(2,("InstrumentsDb: ExecSqlStringList(Sql=%s)\n", Sql.c_str()));
1603          StringListPtr stringList(new std::vector<String>);          StringListPtr stringList(new std::vector<String>);
1604                    
1605          sqlite3_stmt *pStmt = NULL;          sqlite3_stmt *pStmt = NULL;
# Line 1588  namespace LinuxSampler { Line 1695  namespace LinuxSampler {
1695          return Dir.substr(0, i);          return Dir.substr(0, i);
1696      }      }
1697    
1698        void InstrumentsDb::Format() {
1699            DbInstrumentsMutex.Lock();
1700            if (db != NULL) {
1701                sqlite3_close(db);
1702                db = NULL;
1703            }
1704    
1705            if (DbFile.empty()) DbFile = CONFIG_DEFAULT_INSTRUMENTS_DB_LOCATION;
1706            String bkp = DbFile + ".bkp";
1707            remove(bkp.c_str());
1708            if (rename(DbFile.c_str(), bkp.c_str()) && errno != ENOENT) {
1709                DbInstrumentsMutex.Unlock();
1710                throw Exception(String("Failed to backup database: ") + strerror(errno));
1711            }
1712            
1713            String f = DbFile;
1714            DbFile = "";
1715            try { CreateInstrumentsDb(f); }
1716            catch(Exception e) {
1717                DbInstrumentsMutex.Unlock();
1718                throw e;
1719            }
1720            DbInstrumentsMutex.Unlock();
1721            
1722            FireDirectoryCountChanged("/");
1723            FireInstrumentCountChanged("/");
1724        }
1725    
1726      void InstrumentsDb::CheckFileName(String File) {      void InstrumentsDb::CheckFileName(String File) {
1727          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);  
         }  
1728      }      }
1729    
1730      String InstrumentsDb::GetUniqueInstrumentName(int DirId, String Name) {      String InstrumentsDb::GetUniqueName(int DirId, String Name) {
1731          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()));
1732    
1733          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 1742  namespace LinuxSampler {
1742    
1743          throw Exception("Unable to find an unique name: " + Name);          throw Exception("Unable to find an unique name: " + Name);
1744      }      }
1745        
1746        String InstrumentsDb::PrepareSubdirectory(String DbDir, String FsPath) {
1747            std::string dir = Path::getBaseName(FsPath);
1748            dir = toAbstractName(dir);
1749            if(dir.empty()) dir = "New Directory";
1750            dir = GetUniqueName(GetDirectoryId(DbDir), dir);
1751            dir = AppendNode(DbDir, dir);
1752            AddDirectory(dir);
1753            return dir;
1754        }
1755    
1756        String InstrumentsDb::AppendNode(String DbDir, String Node) {
1757            if(DbDir.length() == 1 && DbDir.at(0) == '/') return DbDir + Node + "/";
1758            return DbDir + "/" + Node + "/";  
1759        }
1760    
1761        String InstrumentsDb::toDbName(String AbstractName) {
1762            for (int i = 0; i < AbstractName.length(); i++) {
1763                if (AbstractName.at(i) == '\0') AbstractName.at(i) = '/';
1764            }
1765            return AbstractName;
1766        }
1767    
1768        String InstrumentsDb::toEscapedPath(String AbstractName) {
1769            for (int i = 0; i < AbstractName.length(); i++) {
1770                if (AbstractName.at(i) == '\0')      AbstractName.replace(i++, 1, "\\x2f");
1771                else if (AbstractName.at(i) == '\\') AbstractName.replace(i++, 1, "\\\\");
1772                else if (AbstractName.at(i) == '\'') AbstractName.replace(i++, 1, "\\'");
1773                else if (AbstractName.at(i) == '"')  AbstractName.replace(i++, 1, "\\\"");
1774                else if (AbstractName.at(i) == '\r') AbstractName.replace(i++, 1, "\\r");
1775                else if (AbstractName.at(i) == '\n') AbstractName.replace(i++, 1, "\\n");
1776            }
1777            return AbstractName;
1778        }
1779        
1780        String InstrumentsDb::toEscapedText(String text) {
1781            for (int i = 0; i < text.length(); i++) {
1782                if (text.at(i) == '\\')      text.replace(i++, 1, "\\\\");
1783                else if (text.at(i) == '\'') text.replace(i++, 1, "\\'");
1784                else if (text.at(i) == '"')  text.replace(i++, 1, "\\\"");
1785                else if (text.at(i) == '\r') text.replace(i++, 1, "\\r");
1786                else if (text.at(i) == '\n') text.replace(i++, 1, "\\n");
1787            }
1788            return text;
1789        }
1790        
1791        String InstrumentsDb::toNonEscapedText(String text) {
1792            String sb;
1793            for (int i = 0; i < text.length(); i++) {
1794                char c = text.at(i);
1795                            if(c == '\\') {
1796                                    if(i >= text.length()) {
1797                                            std::cerr << "Broken escape sequence!" << std::endl;
1798                                            break;
1799                                    }
1800                                    char c2 = text.at(++i);
1801                                    if(c2 == '\'')      sb.push_back('\'');
1802                                    else if(c2 == '"')  sb.push_back('"');
1803                                    else if(c2 == '\\') sb.push_back('\\');
1804                                    else if(c2 == 'r')  sb.push_back('\r');
1805                                    else if(c2 == 'n')  sb.push_back('\n');
1806                                    else std::cerr << "Unknown escape sequence \\" << c2 << std::endl;
1807                            } else {
1808                                    sb.push_back(c);
1809                            }
1810            }
1811            return sb;
1812        }
1813        
1814        String InstrumentsDb::toEscapedFsPath(String FsPath) {
1815            return toEscapedText(FsPath);
1816        }
1817        
1818        String InstrumentsDb::toNonEscapedFsPath(String FsPath) {
1819            return toNonEscapedText(FsPath);
1820        }
1821        
1822        String InstrumentsDb::toAbstractName(String DbName) {
1823            for (int i = 0; i < DbName.length(); i++) {
1824                if (DbName.at(i) == '/') DbName.at(i) = '\0';
1825            }
1826            return DbName;
1827        }
1828    
1829      void InstrumentsDb::FireDirectoryCountChanged(String Dir) {      void InstrumentsDb::FireDirectoryCountChanged(String Dir) {
1830          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {          for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
# Line 1654  namespace LinuxSampler { Line 1869  namespace LinuxSampler {
1869      }      }
1870    
1871  } // namespace LinuxSampler  } // namespace LinuxSampler
   
 #endif // HAVE_SQLITE3  

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

  ViewVC Help
Powered by ViewVC