/[svn]/linuxsampler/trunk/src/db/InstrumentsDb.cpp
ViewVC logotype

Contents of /linuxsampler/trunk/src/db/InstrumentsDb.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1944 - (show annotations) (download)
Tue Jul 14 18:54:08 2009 UTC (11 years, 4 months ago) by persson
File size: 72089 byte(s)
- added include statement, which was missing in previous commit

1 /***************************************************************************
2 * *
3 * Copyright (C) 2007-2009 Grigor Iliev, Benno Senoner *
4 * *
5 * 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 *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the Free Software *
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, *
18 * MA 02110-1301 USA *
19 ***************************************************************************/
20
21 #include "InstrumentsDb.h"
22
23 #include "../common/File.h"
24 #include "../common/Path.h"
25 #include "../common/global_private.h"
26
27 #include <iostream>
28 #include <sstream>
29 #include <vector>
30 #include <algorithm>
31 #include <errno.h>
32 #ifndef WIN32
33 #include <fnmatch.h>
34 #else
35 #include <direct.h>
36 #endif
37 #include "../common/Exception.h"
38
39 namespace LinuxSampler {
40
41 InstrumentsDb InstrumentsDb::instance;
42
43 void InstrumentsDb::CreateInstrumentsDb(String FilePath) {
44 File f = File(FilePath);
45 if (f.Exist()) {
46 throw Exception("File exists: " + FilePath);
47 }
48
49 GetInstrumentsDb()->SetDbFile(FilePath);
50
51 String sql =
52 " CREATE TABLE instr_dirs ( "
53 " dir_id INTEGER PRIMARY KEY AUTOINCREMENT, "
54 " parent_dir_id INTEGER DEFAULT 0, "
55 " dir_name TEXT, "
56 " created TIMESTAMP DEFAULT CURRENT_TIMESTAMP, "
57 " modified TIMESTAMP DEFAULT CURRENT_TIMESTAMP, "
58 " description TEXT, "
59 " FOREIGN KEY(parent_dir_id) REFERENCES instr_dirs(dir_id), "
60 " UNIQUE (parent_dir_id,dir_name) "
61 " ); ";
62
63 GetInstrumentsDb()->ExecSql(sql);
64
65 sql = "INSERT INTO instr_dirs (dir_id, parent_dir_id, dir_name) VALUES (0, -2, '/');";
66 GetInstrumentsDb()->ExecSql(sql);
67
68 sql =
69 " CREATE TABLE instruments ( "
70 " instr_id INTEGER PRIMARY KEY AUTOINCREMENT, "
71 " dir_id INTEGER DEFAULT 0, "
72 " instr_name TEXT, "
73 " instr_file TEXT, "
74 " instr_nr INTEGER, "
75 " format_family TEXT, "
76 " format_version TEXT, "
77 " instr_size INTEGER, "
78 " created TIMESTAMP DEFAULT CURRENT_TIMESTAMP, "
79 " modified TIMESTAMP DEFAULT CURRENT_TIMESTAMP, "
80 " description TEXT, "
81 " is_drum INTEGER(1), "
82 " product TEXT, "
83 " artists TEXT, "
84 " keywords TEXT, "
85 " FOREIGN KEY(dir_id) REFERENCES instr_dirs(dir_id), "
86 " UNIQUE (dir_id,instr_name) "
87 " ); ";
88
89 GetInstrumentsDb()->ExecSql(sql);
90 }
91
92 InstrumentsDb::InstrumentsDb() {
93 db = NULL;
94 InTransaction = false;
95 }
96
97 InstrumentsDb::~InstrumentsDb() {
98 if (db != NULL) sqlite3_close(db);
99 }
100
101 void InstrumentsDb::AddInstrumentsDbListener(InstrumentsDb::Listener* l) {
102 llInstrumentsDbListeners.AddListener(l);
103 }
104
105 void InstrumentsDb::RemoveInstrumentsDbListener(InstrumentsDb::Listener* l) {
106 llInstrumentsDbListeners.RemoveListener(l);
107 }
108
109 InstrumentsDb* InstrumentsDb::GetInstrumentsDb() {
110 return &instance;
111 }
112
113 void InstrumentsDb::SetDbFile(String File) {
114 DbInstrumentsMutex.Lock();
115 if (File.empty() || DbFile.length() > 0) {
116 DbInstrumentsMutex.Unlock();
117 throw Exception("Failed to set the database file");
118 }
119 DbFile = File;
120 DbInstrumentsMutex.Unlock();
121 }
122
123 sqlite3* InstrumentsDb::GetDb() {
124 if ( db != NULL) return db;
125
126 if (DbFile.empty()) {
127 #ifndef WIN32
128 DbFile = CONFIG_DEFAULT_INSTRUMENTS_DB_LOCATION;
129 #else
130 char *userprofile = getenv("USERPROFILE");
131 if(userprofile) {
132 String DbPath = userprofile;
133 DbPath += "\\.linuxsampler";
134 DbFile = DbPath + "\\instruments.db";
135 File InstrumentsDbFile(DbFile);
136 // if no DB exists create the subdir and then the DB
137 if( !InstrumentsDbFile.Exist() ) {
138 _mkdir( DbPath.c_str() );
139 // formats the DB, which creates a new instruments.db file
140 Format();
141 }
142 }
143 else {
144 // in case USERPROFILE is not set (which should not occur)
145 DbFile = "instruments.db";
146 }
147 #endif
148 }
149 #if defined(__APPLE__) /* 20071224 Toshi Nagata */
150 if (DbFile.find("~") == 0)
151 DbFile.replace(0, 1, getenv("HOME"));
152 #endif
153 int rc = sqlite3_open(DbFile.c_str(), &db);
154 if (rc) {
155 sqlite3_close(db);
156 db = NULL;
157 throw Exception("Cannot open instruments database: " + DbFile);
158 }
159 #ifndef WIN32
160 rc = sqlite3_create_function(db, "regexp", 2, SQLITE_UTF8, NULL, Regexp, NULL, NULL);
161 if (rc) { throw Exception("Failed to add user function for handling regular expressions."); }
162 #endif
163
164 // TODO: remove this in the next version
165 try {
166 int i = ExecSqlInt("SELECT parent_dir_id FROM instr_dirs WHERE dir_id=0");
167 // The parent ID of the root directory should be -2 now.
168 if(i != -2) ExecSql("UPDATE instr_dirs SET parent_dir_id=-2 WHERE dir_id=0");
169 } catch(Exception e) { }
170 ////////////////////////////////////////
171
172 return db;
173 }
174
175 int InstrumentsDb::GetDirectoryCount(int DirId) {
176 dmsg(2,("InstrumentsDb: GetDirectoryCount(DirId=%d)\n", DirId));
177 if(DirId == -1) return -1;
178
179 std::stringstream sql;
180 sql << "SELECT COUNT(*) FROM instr_dirs WHERE parent_dir_id=" << DirId;
181
182 int count = ExecSqlInt(sql.str());
183
184 return count;
185 }
186
187 int InstrumentsDb::GetDirectoryCount(String Dir, bool Recursive) {
188 dmsg(2,("InstrumentsDb: GetDirectoryCount(Dir=%s,Recursive=%d)\n", Dir.c_str(), Recursive));
189 int i;
190
191 BeginTransaction();
192 try {
193 if (Recursive) {
194 DirectoryCounter directoryCounter;
195 DirectoryTreeWalk(Dir, &directoryCounter);
196 i = directoryCounter.GetDirectoryCount();
197 } else {
198 i = GetDirectoryCount(GetDirectoryId(Dir));
199 }
200 } catch (Exception e) {
201 EndTransaction();
202 throw e;
203 }
204 EndTransaction();
205 if (i == -1) throw Exception("Unkown DB directory: " + toEscapedPath(Dir));
206
207 return i;
208 }
209
210 IntListPtr InstrumentsDb::GetDirectoryIDs(int DirId) {
211 std::stringstream sql;
212 sql << "SELECT dir_id FROM instr_dirs ";
213 sql << "WHERE parent_dir_id=" << DirId << " AND dir_id!=0";
214
215 return ExecSqlIntList(sql.str());
216 }
217
218 StringListPtr InstrumentsDb::GetDirectories(String Dir, bool Recursive) {
219 dmsg(2,("InstrumentsDb: GetDirectories(Dir=%s,Recursive=%d)\n", Dir.c_str(), Recursive));
220
221 BeginTransaction();
222 try {
223 int dirId = GetDirectoryId(Dir);
224 if(dirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
225
226 StringListPtr pDirs;
227 if (Recursive) {
228 SearchQuery q;
229 DirectoryFinder directoryFinder(&q);
230 DirectoryTreeWalk(Dir, &directoryFinder);
231 pDirs = directoryFinder.GetDirectories();
232 } else {
233 pDirs = GetDirectories(dirId);
234 }
235 EndTransaction();
236 return pDirs;
237 } catch (Exception e) {
238 EndTransaction();
239 throw e;
240 }
241 }
242
243 StringListPtr InstrumentsDb::GetDirectories(int DirId) {
244 std::stringstream sql;
245 sql << "SELECT dir_name FROM instr_dirs ";
246 sql << "WHERE parent_dir_id=" << DirId << " AND dir_id!=0";
247 StringListPtr dirs = ExecSqlStringList(sql.str());
248
249 for (int i = 0; i < dirs->size(); i++) {
250 for (int j = 0; j < dirs->at(i).length(); j++) {
251 if (dirs->at(i).at(j) == '/') dirs->at(i).at(j) = '\0';
252 }
253 }
254
255 return dirs;
256 }
257
258 int InstrumentsDb::GetDirectoryId(String Dir) {
259 dmsg(2,("InstrumentsDb: GetDirectoryId(Dir=%s)\n", Dir.c_str()));
260 CheckPathName(Dir);
261
262 if (Dir.empty() || Dir.at(0) != '/') {
263 return -1;
264 } else if (Dir.length() == 1) {
265 // We expect the root directory id to be always 0.
266 return 0;
267 }
268
269 int id = 0, i = 1;
270 int j = Dir.find('/', i);
271
272 while(j != std::string::npos) {
273 id = GetDirectoryId(id, Dir.substr(i, j - i));
274 i = j + 1;
275 if (i >= Dir.length()) return id;
276 j = Dir.find('/', i);
277 }
278
279 return GetDirectoryId(id, Dir.substr(i));
280 }
281
282 int InstrumentsDb::GetDirectoryId(int ParentDirId, String DirName) {
283 dmsg(2,("InstrumentsDb: GetDirectoryId(ParentDirId=%d, DirName=%s)\n", ParentDirId, DirName.c_str()));
284 DirName = toDbName(DirName);
285 std::stringstream sql;
286 sql << "SELECT dir_id FROM instr_dirs WHERE parent_dir_id=";
287 sql << ParentDirId << " AND dir_name=?";
288 return ExecSqlInt(sql.str(), DirName);
289 }
290
291 int InstrumentsDb::GetDirectoryId(int InstrId) {
292 dmsg(2,("InstrumentsDb: GetDirectoryId(InstrId=%d)\n", InstrId));
293 std::stringstream sql;
294 sql << "SELECT dir_id FROM instruments WHERE instr_id=" << InstrId;
295 return ExecSqlInt(sql.str());
296 }
297
298 String InstrumentsDb::GetDirectoryName(int DirId) {
299 String sql = "SELECT dir_name FROM instr_dirs WHERE dir_id=" + ToString(DirId);
300 String name = ExecSqlString(sql);
301 if (name.empty()) throw Exception("Directory ID not found");
302 return name;
303 }
304
305 int InstrumentsDb::GetParentDirectoryId(int DirId) {
306 if (DirId == 0) throw Exception("The root directory is specified");
307 String sql = "SELECT parent_dir_id FROM instr_dirs WHERE dir_id=" + ToString(DirId);
308 int parentId = ExecSqlInt(sql);
309 if (parentId == -1) throw Exception("DB directory not found");
310 return parentId;
311 }
312
313 String InstrumentsDb::GetDirectoryPath(int DirId) {
314 String path = "";
315 int count = 1000; // used to prevent infinite loops
316
317 while(--count) {
318 if (DirId == 0) {
319 path = "/" + path;
320 break;
321 }
322 path = GetDirectoryName(DirId) + "/" + path;
323 DirId = GetParentDirectoryId(DirId);
324 }
325
326 if (!count) throw Exception("Possible infinite loop detected");
327
328 return path;
329 }
330
331 StringListPtr InstrumentsDb::GetInstrumentsByFile(String File) {
332 dmsg(2,("InstrumentsDb: GetInstrumentsByFile(File=%s)\n", File.c_str()));
333
334 StringListPtr instrs(new std::vector<String>);
335
336 BeginTransaction();
337 try {
338 File = toEscapedFsPath(File);
339 IntListPtr ids = ExecSqlIntList("SELECT instr_id FROM instruments WHERE instr_file=?", File);
340
341 for (int i = 0; i < ids->size(); i++) {
342 String name = GetInstrumentName(ids->at(i));
343 String dir = GetDirectoryPath(GetDirectoryId(ids->at(i)));
344 instrs->push_back(dir + name);
345 }
346 } catch (Exception e) {
347 EndTransaction();
348 throw e;
349 }
350 EndTransaction();
351
352 return instrs;
353 }
354
355 void InstrumentsDb::AddDirectory(String Dir) {
356 dmsg(2,("InstrumentsDb: AddDirectory(Dir=%s)\n", Dir.c_str()));
357 CheckPathName(Dir);
358 String ParentDir = GetParentDirectory(Dir);
359
360 BeginTransaction();
361 try {
362 if (Dir.length() > 1) {
363 if (Dir.at(Dir.length() - 1) == '/') Dir.erase(Dir.length() - 1);
364 }
365
366 String dirName = GetFileName(Dir);
367 if(ParentDir.empty() || dirName.empty()) {
368 throw Exception("Failed to add DB directory: " + toEscapedPath(Dir));
369 }
370
371 int id = GetDirectoryId(ParentDir);
372 if (id == -1) throw Exception("DB directory doesn't exist: " + toEscapedPath(ParentDir));
373 int id2 = GetDirectoryId(id, dirName);
374 if (id2 != -1) throw Exception("DB directory already exist: " + toEscapedPath(Dir));
375 id2 = GetInstrumentId(id, dirName);
376 if (id2 != -1) throw Exception("Instrument with that name exist: " + toEscapedPath(Dir));
377
378 std::stringstream sql;
379 sql << "INSERT INTO instr_dirs (parent_dir_id, dir_name) VALUES (";
380 sql << id << ", ?)";
381
382 ExecSql(sql.str(), toDbName(dirName));
383 } catch (Exception e) {
384 EndTransaction();
385 throw e;
386 }
387
388 EndTransaction();
389
390 FireDirectoryCountChanged(ParentDir);
391 }
392
393 void InstrumentsDb::RemoveDirectory(String Dir, bool Force) {
394 dmsg(2,("InstrumentsDb: RemoveDirectory(Dir=%s,Force=%d)\n", Dir.c_str(), Force));
395
396 String ParentDir = GetParentDirectory(Dir);
397
398 BeginTransaction();
399 try {
400 int dirId = GetDirectoryId(Dir);
401 if (dirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
402 if (dirId == 0) throw Exception("Cannot delete the root directory: " + Dir);
403 if(ParentDir.empty()) throw Exception("Unknown parent directory");
404 if (Force) RemoveDirectoryContent(dirId);
405 RemoveDirectory(dirId);
406 } catch (Exception e) {
407 EndTransaction();
408 throw e;
409 }
410
411 EndTransaction();
412 FireDirectoryCountChanged(ParentDir);
413 }
414
415 void InstrumentsDb::RemoveDirectoryContent(int DirId, int Level) {
416 dmsg(2,("InstrumentsDb: RemoveDirectoryContent(DirId=%d,Level=%d)\n", DirId, Level));
417 if (Level > 1000) throw Exception("Directory level too deep: " + ToString(Level));
418 IntListPtr dirIds = GetDirectoryIDs(DirId);
419
420 for (int i = 0; i < dirIds->size(); i++) {
421 RemoveDirectoryContent(dirIds->at(i), Level + 1);
422 }
423
424 RemoveAllDirectories(DirId);
425 RemoveAllInstruments(DirId);
426 }
427
428 void InstrumentsDb::RemoveDirectory(int DirId) {
429 dmsg(2,("InstrumentsDb: RemoveDirectory(DirId=%d)\n", DirId));
430 if (GetInstrumentCount(DirId) > 0 || GetDirectoryCount(DirId) > 0) {
431 throw Exception("The specified DB directory is not empty");
432 }
433
434 std::stringstream sql;
435 sql << "DELETE FROM instr_dirs WHERE dir_id=" << DirId;
436
437 ExecSql(sql.str());
438 }
439
440 void InstrumentsDb::RemoveAllDirectories(int DirId) {
441 dmsg(2,("InstrumentsDb: RemoveAllDirectories(DirId=%d)\n", DirId));
442 IntListPtr dirIds = GetDirectoryIDs(DirId);
443
444 for (int i = 0; i < dirIds->size(); i++) {
445 if (!IsDirectoryEmpty(dirIds->at(i))) {
446 throw Exception("DB directory not empty!");
447 }
448 }
449 std::stringstream sql;
450 sql << "DELETE FROM instr_dirs WHERE parent_dir_id=" << DirId;
451 sql << " AND dir_id!=0";
452
453 ExecSql(sql.str());
454 }
455
456 bool InstrumentsDb::IsDirectoryEmpty(int DirId) {
457 dmsg(2,("InstrumentsDb: IsDirectoryEmpty(DirId=%d)\n", DirId));
458 int dirCount = GetDirectoryCount(DirId);
459 int instrCount = GetInstrumentCount(DirId);
460 dmsg(3,("InstrumentsDb: IsDirectoryEmpty: dirCount=%d,instrCount=%d\n", dirCount, instrCount));
461 if (dirCount == -1 || instrCount == -1) return false;
462 return dirCount == 0 && instrCount == 0;
463 }
464
465 bool InstrumentsDb::DirectoryExist(String Dir) {
466 dmsg(2,("InstrumentsDb: DirectoryExist(Dir=%s)\n", Dir.c_str()));
467 bool b;
468
469 DbInstrumentsMutex.Lock();
470 try { b = GetDirectoryId(Dir) != -1; }
471 catch (Exception e) {
472 DbInstrumentsMutex.Unlock();
473 throw e;
474 }
475 DbInstrumentsMutex.Unlock();
476
477 return b;
478 }
479
480 DbDirectory InstrumentsDb::GetDirectoryInfo(String Dir) {
481 dmsg(2,("InstrumentsDb: GetDirectoryInfo(Dir=%s)\n", Dir.c_str()));
482 DbDirectory d;
483
484 BeginTransaction();
485
486 try {
487 int id = GetDirectoryId(Dir);
488 if(id == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
489
490 sqlite3_stmt *pStmt = NULL;
491 std::stringstream sql;
492 sql << "SELECT created,modified,description FROM instr_dirs ";
493 sql << "WHERE dir_id=" << id;
494
495 int res = sqlite3_prepare(GetDb(), sql.str().c_str(), -1, &pStmt, NULL);
496 if (res != SQLITE_OK) {
497 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
498 }
499
500 res = sqlite3_step(pStmt);
501 if(res == SQLITE_ROW) {
502 d.Created = ToString(sqlite3_column_text(pStmt, 0));
503 d.Modified = ToString(sqlite3_column_text(pStmt, 1));
504 d.Description = ToString(sqlite3_column_text(pStmt, 2));
505 } else {
506 sqlite3_finalize(pStmt);
507
508 if (res != SQLITE_DONE) {
509 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
510 } else {
511 throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
512 }
513 }
514
515 sqlite3_finalize(pStmt);
516 } catch (Exception e) {
517 EndTransaction();
518 throw e;
519 }
520
521 EndTransaction();
522 return d;
523 }
524
525 void InstrumentsDb::RenameDirectory(String Dir, String Name) {
526 dmsg(2,("InstrumentsDb: RenameDirectory(Dir=%s,Name=%s)\n", Dir.c_str(), Name.c_str()));
527 CheckFileName(Name);
528 String dbName = toDbName(Name);
529
530 BeginTransaction();
531 try {
532 int dirId = GetDirectoryId(Dir);
533 if (dirId == -1) throw Exception("Unknown DB directory: " + toEscapedText(Dir));
534
535 std::stringstream sql;
536 sql << "SELECT parent_dir_id FROM instr_dirs WHERE dir_id=" << dirId;
537
538 int parent = ExecSqlInt(sql.str());
539 if (parent == -1) throw Exception("Unknown parent directory: " + toEscapedPath(Dir));
540
541 if (GetDirectoryId(parent, dbName) != -1) {
542 String s = toEscapedPath(Name);
543 throw Exception("Cannot rename. Directory with that name already exists: " + s);
544 }
545
546 if (GetInstrumentId(parent, dbName) != -1) {
547 throw Exception("Cannot rename. Instrument with that name exist: " + toEscapedPath(Dir));
548 }
549
550 sql.str("");
551 sql << "UPDATE instr_dirs SET dir_name=? WHERE dir_id=" << dirId;
552 ExecSql(sql.str(), dbName);
553 } catch (Exception e) {
554 EndTransaction();
555 throw e;
556 }
557
558 EndTransaction();
559 FireDirectoryNameChanged(Dir, toAbstractName(Name));
560 }
561
562 void InstrumentsDb::MoveDirectory(String Dir, String Dst) {
563 dmsg(2,("InstrumentsDb: MoveDirectory(Dir=%s,Dst=%s)\n", Dir.c_str(), Dst.c_str()));
564
565 if(Dir.compare("/") == 0) throw Exception("Cannot move the root directory");
566 String ParentDir = GetParentDirectory(Dir);
567 if(ParentDir.empty()) throw Exception("Unknown parent directory");
568
569 BeginTransaction();
570 try {
571 int dirId = GetDirectoryId(Dir);
572 if (dirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
573 int dstId = GetDirectoryId(Dst);
574 if (dstId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dst));
575 if (dirId == dstId) {
576 throw Exception("Cannot move directory to itself");
577 }
578
579 if (Dir.at(Dir.length() - 1) != '/') Dir.append("/");
580 if (Dst.length() > Dir.length()) {
581 if (Dir.compare(Dst.substr(0, Dir.length())) == 0) {
582 throw Exception("Cannot move a directory to a subdirectory of itself.");
583 }
584 }
585
586 Dir.erase(Dir.length() - 1);
587 String dirName = GetFileName(Dir);
588
589 int id2 = GetDirectoryId(dstId, dirName);
590 if (id2 != -1) throw Exception("DB directory already exist: " + toEscapedPath(dirName));
591 id2 = GetInstrumentId(dstId, dirName);
592 if (id2 != -1) throw Exception("Instrument with that name exist: " + toEscapedPath(dirName));
593
594 std::stringstream sql;
595 sql << "UPDATE instr_dirs SET parent_dir_id=" << dstId;
596 sql << " WHERE dir_id=" << dirId;
597 ExecSql(sql.str());
598 } catch (Exception e) {
599 EndTransaction();
600 throw e;
601 }
602
603 EndTransaction();
604 FireDirectoryCountChanged(ParentDir);
605 FireDirectoryCountChanged(Dst);
606 }
607
608 void InstrumentsDb::CopyDirectory(String Dir, String Dst) {
609 dmsg(2,("InstrumentsDb: CopyDirectory(Dir=%s,Dst=%s)\n", Dir.c_str(), Dst.c_str()));
610
611 if(Dir.compare("/") == 0) throw Exception("Cannot copy the root directory");
612 String ParentDir = GetParentDirectory(Dir);
613 if(ParentDir.empty()) throw Exception("Unknown parent directory");
614
615 BeginTransaction();
616 try {
617 int dirId = GetDirectoryId(Dir);
618 if (dirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
619 int dstId = GetDirectoryId(Dst);
620 if (dstId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dst));
621 if (dirId == dstId) {
622 throw Exception("Cannot copy directory to itself");
623 }
624
625 if (Dir.at(Dir.length() - 1) != '/') Dir.append("/");
626 if (Dst.length() > Dir.length()) {
627 if (Dir.compare(Dst.substr(0, Dir.length())) == 0) {
628 throw Exception("Cannot copy a directory to a subdirectory of itself.");
629 }
630 }
631
632 Dir.erase(Dir.length() - 1);
633 String dirName = GetFileName(Dir);
634
635 int id2 = GetDirectoryId(dstId, dirName);
636 if (id2 != -1) throw Exception("DB directory already exist: " + toEscapedPath(dirName));
637 id2 = GetInstrumentId(dstId, dirName);
638 if (id2 != -1) throw Exception("Instrument with that name exist: " + toEscapedPath(dirName));
639
640 DirectoryCopier directoryCopier(ParentDir, Dst);
641 DirectoryTreeWalk(Dir, &directoryCopier);
642 } catch (Exception e) {
643 EndTransaction();
644 throw e;
645 }
646
647 EndTransaction();
648 }
649
650 void InstrumentsDb::SetDirectoryDescription(String Dir, String Desc) {
651 dmsg(2,("InstrumentsDb: SetDirectoryDescription(Dir=%s,Desc=%s)\n", Dir.c_str(), Desc.c_str()));
652
653 BeginTransaction();
654 try {
655 int id = GetDirectoryId(Dir);
656 if(id == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
657
658 std::stringstream sql;
659 sql << "UPDATE instr_dirs SET description=?,modified=CURRENT_TIMESTAMP ";
660 sql << "WHERE dir_id="<< id;
661
662 ExecSql(sql.str(), Desc);
663 } catch (Exception e) {
664 EndTransaction();
665 throw e;
666 }
667 EndTransaction();
668
669 FireDirectoryInfoChanged(Dir);
670 }
671
672 int InstrumentsDb::AddInstruments(ScanMode Mode, String DbDir, String FsDir, bool bBackground, bool insDir) {
673 dmsg(2,("InstrumentsDb: AddInstruments(Mode=%d,DbDir=%s,FsDir=%s,bBackground=%d,insDir=%d)\n", Mode, DbDir.c_str(), FsDir.c_str(), bBackground, insDir));
674 if(!bBackground) {
675 switch (Mode) {
676 case NON_RECURSIVE:
677 AddInstrumentsNonrecursive(DbDir, FsDir, insDir);
678 break;
679 case RECURSIVE:
680 AddInstrumentsRecursive(DbDir, FsDir, false, insDir);
681 break;
682 case FLAT:
683 AddInstrumentsRecursive(DbDir, FsDir, true, insDir);
684 break;
685 default:
686 throw Exception("Unknown scan mode");
687 }
688
689 return -1;
690 }
691
692 ScanJob job;
693 int jobId = Jobs.AddJob(job);
694 InstrumentsDbThread.Execute(new AddInstrumentsJob(jobId, Mode, DbDir, FsDir, insDir));
695
696 return jobId;
697 }
698
699 int InstrumentsDb::AddInstruments(String DbDir, String FilePath, int Index, bool bBackground) {
700 dmsg(2,("InstrumentsDb: AddInstruments(DbDir=%s,FilePath=%s,Index=%d,bBackground=%d)\n", DbDir.c_str(), FilePath.c_str(), Index, bBackground));
701 if(!bBackground) {
702 AddInstruments(DbDir, false, FilePath, Index);
703 return -1;
704 }
705
706 ScanJob job;
707 int jobId = Jobs.AddJob(job);
708 InstrumentsDbThread.Execute(new AddInstrumentsFromFileJob(jobId, DbDir, FilePath, Index, false));
709
710 return jobId;
711 }
712
713 void InstrumentsDb::AddInstruments(String DbDir, bool insDir, String FilePath, int Index, ScanProgress* pProgress) {
714 dmsg(2,("InstrumentsDb: AddInstruments(DbDir=%s,insDir=%d,FilePath=%s,Index=%d)\n", DbDir.c_str(), insDir, FilePath.c_str(), Index));
715 if (DbDir.empty() || FilePath.empty()) return;
716
717 DbInstrumentsMutex.Lock();
718 try {
719 int dirId = GetDirectoryId(DbDir);
720 if (dirId == -1) throw Exception("Invalid DB directory: " + toEscapedText(DbDir));
721
722 File f = File(FilePath);
723 if (!f.Exist()) {
724 std::stringstream ss;
725 ss << "Fail to stat `" << FilePath << "`: " << f.GetErrorMsg();
726 throw Exception(ss.str());
727 }
728
729 if (!f.IsFile()) {
730 std::stringstream ss;
731 ss << "`" << FilePath << "` is not an instrument file";
732 throw Exception(ss.str());
733 }
734
735 String dir = insDir ? PrepareSubdirectory(DbDir, FilePath) : DbDir;
736 AddInstrumentsFromFile(dir, FilePath, Index, pProgress);
737 } catch (Exception e) {
738 DbInstrumentsMutex.Unlock();
739 throw e;
740 }
741
742 DbInstrumentsMutex.Unlock();
743 }
744
745 void InstrumentsDb::AddInstrumentsNonrecursive(String DbDir, String FsDir, bool insDir, ScanProgress* pProgress) {
746 dmsg(2,("InstrumentsDb: AddInstrumentsNonrecursive(DbDir=%s,FsDir=%s,insDir=%d)\n", DbDir.c_str(), FsDir.c_str(), insDir));
747 if (DbDir.empty() || FsDir.empty()) return;
748
749 DbInstrumentsMutex.Lock();
750 try {
751 int dirId = GetDirectoryId(DbDir);
752 if (dirId == -1) throw Exception("Invalid DB directory: " + toEscapedPath(DbDir));
753
754 File f = File(FsDir);
755 if (!f.Exist()) {
756 std::stringstream ss;
757 ss << "Fail to stat `" << FsDir << "`: " << f.GetErrorMsg();
758 throw Exception(ss.str());
759 }
760
761 if (!f.IsDirectory()) {
762 throw Exception("Directory expected: " + FsDir);
763 }
764
765 if (FsDir.at(FsDir.length() - 1) != File::DirSeparator) {
766 FsDir.push_back(File::DirSeparator);
767 }
768
769 try {
770 FileListPtr fileList = File::GetFiles(FsDir);
771 for (int i = 0; i < fileList->size(); i++) {
772 String dir = insDir ? PrepareSubdirectory(DbDir, fileList->at(i)) : DbDir;
773 AddInstrumentsFromFile(dir, FsDir + fileList->at(i), -1, pProgress);
774 }
775 } catch(Exception e) {
776 e.PrintMessage();
777 DbInstrumentsMutex.Unlock();
778 return;
779 }
780 } catch (Exception e) {
781 DbInstrumentsMutex.Unlock();
782 throw e;
783 }
784
785 DbInstrumentsMutex.Unlock();
786 }
787
788 void InstrumentsDb::AddInstrumentsRecursive(String DbDir, String FsDir, bool Flat, bool insDir, ScanProgress* pProgress) {
789 dmsg(2,("InstrumentsDb: AddInstrumentsRecursive(DbDir=%s,FsDir=%s,Flat=%d,insDir=%d)\n", DbDir.c_str(), FsDir.c_str(), Flat, insDir));
790 if (pProgress != NULL) {
791 InstrumentFileCounter c;
792 pProgress->SetTotalFileCount(c.Count(FsDir));
793 }
794
795 DirectoryScanner d;
796 d.Scan(DbDir, FsDir, Flat, insDir, pProgress);
797 }
798
799 int InstrumentsDb::GetInstrumentCount(int DirId) {
800 dmsg(2,("InstrumentsDb: GetInstrumentCount(DirId=%d)\n", DirId));
801 if(DirId == -1) return -1;
802
803 std::stringstream sql;
804 sql << "SELECT COUNT(*) FROM instruments WHERE dir_id=" << DirId;
805
806 return ExecSqlInt(sql.str());
807 }
808
809 int InstrumentsDb::GetInstrumentCount(String Dir, bool Recursive) {
810 dmsg(2,("InstrumentsDb: GetInstrumentCount(Dir=%s,Recursive=%d)\n", Dir.c_str(), Recursive));
811 int i;
812
813 BeginTransaction();
814 try {
815 if (Recursive) {
816 InstrumentCounter instrumentCounter;
817 DirectoryTreeWalk(Dir, &instrumentCounter);
818 i = instrumentCounter.GetInstrumentCount();
819 } else {
820 i = GetInstrumentCount(GetDirectoryId(Dir));
821 }
822 } catch (Exception e) {
823 EndTransaction();
824 throw e;
825 }
826 EndTransaction();
827
828 if (i == -1) throw Exception("Unknown Db directory: " + toEscapedPath(Dir));
829 return i;
830 }
831
832 IntListPtr InstrumentsDb::GetInstrumentIDs(int DirId) {
833 std::stringstream sql;
834 sql << "SELECT instr_id FROM instruments WHERE dir_id=" << DirId;
835
836 return ExecSqlIntList(sql.str());
837 }
838
839 StringListPtr InstrumentsDb::GetInstruments(String Dir, bool Recursive) {
840 dmsg(2,("InstrumentsDb: GetInstruments(Dir=%s,Recursive=%d)\n", Dir.c_str(), Recursive));
841 BeginTransaction();
842 try {
843 int dirId = GetDirectoryId(Dir);
844 if(dirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
845
846 StringListPtr pInstrs;
847
848 if(Recursive) {
849 SearchQuery q;
850 InstrumentFinder instrumentFinder(&q);
851 DirectoryTreeWalk(Dir, &instrumentFinder);
852 pInstrs = instrumentFinder.GetInstruments();
853 } else {
854 std::stringstream sql;
855 sql << "SELECT instr_name FROM instruments WHERE dir_id=" << dirId;
856
857 pInstrs = ExecSqlStringList(sql.str());
858 // Converting to abstract names
859 for (int i = 0; i < pInstrs->size(); i++) {
860 for (int j = 0; j < pInstrs->at(i).length(); j++) {
861 if (pInstrs->at(i).at(j) == '/') pInstrs->at(i).at(j) = '\0';
862 }
863 }
864 }
865 EndTransaction();
866 return pInstrs;
867 } catch (Exception e) {
868 EndTransaction();
869 throw e;
870 }
871 }
872
873 int InstrumentsDb::GetInstrumentId(String Instr) {
874 dmsg(2,("InstrumentsDb: GetInstrumentId(Instr=%s)\n", Instr.c_str()));
875 String Dir = GetDirectoryPath(Instr);
876 if (Dir.empty()) return -1;
877
878 return GetInstrumentId(GetDirectoryId(Dir), GetFileName(Instr));
879 }
880
881 int InstrumentsDb::GetInstrumentId(int DirId, String InstrName) {
882 dmsg(2,("InstrumentsDb: GetInstrumentId(DirId=%d,InstrName=%s)\n", DirId, InstrName.c_str()));
883 if (DirId == -1 || InstrName.empty()) return -1;
884
885 std::stringstream sql;
886 sql << "SELECT instr_id FROM instruments WHERE dir_id=";
887 sql << DirId << " AND instr_name=?";
888 return ExecSqlInt(sql.str(), toDbName(InstrName));
889 }
890
891 String InstrumentsDb::GetInstrumentName(int InstrId) {
892 dmsg(2,("InstrumentsDb: GetInstrumentName(InstrId=%d)\n", InstrId));
893 std::stringstream sql;
894 sql << "SELECT instr_name FROM instruments WHERE instr_id=" << InstrId;
895 return toAbstractName(ExecSqlString(sql.str()));
896 }
897
898 void InstrumentsDb::RemoveInstrument(String Instr) {
899 dmsg(2,("InstrumentsDb: RemoveInstrument(Instr=%s)\n", Instr.c_str()));
900 String ParentDir = GetDirectoryPath(Instr);
901 if(ParentDir.empty()) throw Exception("Unknown parent directory");
902
903 BeginTransaction();
904 try {
905 int instrId = GetInstrumentId(Instr);
906 if(instrId == -1) {
907 throw Exception("The specified instrument does not exist: " + toEscapedPath(Instr));
908 }
909 RemoveInstrument(instrId);
910 } catch (Exception e) {
911 EndTransaction();
912 throw e;
913 }
914 EndTransaction();
915 FireInstrumentCountChanged(ParentDir);
916 }
917
918 void InstrumentsDb::RemoveInstrument(int InstrId) {
919 dmsg(2,("InstrumentsDb: RemoveInstrument(InstrId=%d)\n", InstrId));
920
921 std::stringstream sql;
922 sql << "DELETE FROM instruments WHERE instr_id=" << InstrId;
923
924 ExecSql(sql.str());
925 }
926
927 void InstrumentsDb::RemoveAllInstruments(int DirId) {
928 dmsg(2,("InstrumentsDb: RemoveAllInstruments(DirId=%d)\n", DirId));
929
930 std::stringstream sql;
931 sql << "DELETE FROM instruments WHERE dir_id=" << DirId;
932 ExecSql(sql.str());
933 }
934
935 DbInstrument InstrumentsDb::GetInstrumentInfo(String Instr) {
936 dmsg(2,("InstrumentsDb: GetInstrumentInfo(Instr=%s)\n", Instr.c_str()));
937 DbInstrument i;
938
939 BeginTransaction();
940 try {
941 int id = GetInstrumentId(Instr);
942 if(id == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
943 i = GetInstrumentInfo(id);
944 } catch (Exception e) {
945 EndTransaction();
946 throw e;
947 }
948 EndTransaction();
949
950 return i;
951 }
952
953 DbInstrument InstrumentsDb::GetInstrumentInfo(int InstrId) {
954 sqlite3_stmt *pStmt = NULL;
955 std::stringstream sql;
956 sql << "SELECT instr_file,instr_nr,format_family,format_version,";
957 sql << "instr_size,created,modified,description,is_drum,product,";
958 sql << "artists,keywords FROM instruments WHERE instr_id=" << InstrId;
959
960 int res = sqlite3_prepare(GetDb(), sql.str().c_str(), -1, &pStmt, NULL);
961 if (res != SQLITE_OK) {
962 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
963 }
964
965 DbInstrument i;
966 res = sqlite3_step(pStmt);
967 if(res == SQLITE_ROW) {
968 i.InstrFile = ToString(sqlite3_column_text(pStmt, 0));
969 i.InstrNr = sqlite3_column_int(pStmt, 1);
970 i.FormatFamily = ToString(sqlite3_column_text(pStmt, 2));
971 i.FormatVersion = ToString(sqlite3_column_text(pStmt, 3));
972 i.Size = sqlite3_column_int64(pStmt, 4);
973 i.Created = ToString(sqlite3_column_text(pStmt, 5));
974 i.Modified = ToString(sqlite3_column_text(pStmt, 6));
975 i.Description = ToString(sqlite3_column_text(pStmt, 7));
976 i.IsDrum = sqlite3_column_int(pStmt, 8);
977 i.Product = ToString(sqlite3_column_text(pStmt, 9));
978 i.Artists = ToString(sqlite3_column_text(pStmt, 10));
979 i.Keywords = ToString(sqlite3_column_text(pStmt, 11));
980 } else {
981 sqlite3_finalize(pStmt);
982
983 if (res != SQLITE_DONE) {
984 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
985 } else {
986 throw Exception("Unknown DB instrument");
987 }
988 }
989
990 sqlite3_finalize(pStmt);
991 return i;
992 }
993
994 void InstrumentsDb::RenameInstrument(String Instr, String Name) {
995 dmsg(2,("InstrumentsDb: RenameInstrument(Instr=%s,Name=%s)\n", Instr.c_str(), Name.c_str()));
996 CheckFileName(Name);
997
998 BeginTransaction();
999 try {
1000 int dirId = GetDirectoryId(GetDirectoryPath(Instr));
1001 if (dirId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1002
1003 int instrId = GetInstrumentId(dirId, GetFileName(Instr));
1004 if (instrId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1005
1006 if (GetInstrumentId(dirId, Name) != -1) {
1007 String s = toEscapedPath(Name);
1008 throw Exception("Cannot rename. Instrument with that name already exists: " + s);
1009 }
1010
1011 if (GetDirectoryId(dirId, Name) != -1) {
1012 String s = toEscapedPath(Name);
1013 throw Exception("Cannot rename. Directory with that name already exists: " + s);
1014 }
1015
1016 std::stringstream sql;
1017 sql << "UPDATE instruments SET instr_name=? WHERE instr_id=" << instrId;
1018 ExecSql(sql.str(), toDbName(Name));
1019 } catch (Exception e) {
1020 EndTransaction();
1021 throw e;
1022 }
1023 EndTransaction();
1024 FireInstrumentNameChanged(Instr, toAbstractName(Name));
1025 }
1026
1027 void InstrumentsDb::MoveInstrument(String Instr, String Dst) {
1028 dmsg(2,("InstrumentsDb: MoveInstrument(Instr=%s,Dst=%s)\n", Instr.c_str(), Dst.c_str()));
1029 String ParentDir = GetDirectoryPath(Instr);
1030 if(ParentDir.empty()) throw Exception("Unknown parent directory");
1031
1032 BeginTransaction();
1033 try {
1034 int dirId = GetDirectoryId(ParentDir);
1035 if (dirId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1036
1037 String instrName = GetFileName(Instr);
1038 int instrId = GetInstrumentId(dirId, instrName);
1039 if (instrId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1040
1041 int dstId = GetDirectoryId(Dst);
1042 if (dstId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dst));
1043 if (dirId == dstId) {
1044 EndTransaction();
1045 return;
1046 }
1047
1048 if (GetInstrumentId(dstId, instrName) != -1) {
1049 String s = toEscapedPath(instrName);
1050 throw Exception("Cannot move. Instrument with that name already exists: " + s);
1051 }
1052
1053 if (GetDirectoryId(dstId, instrName) != -1) {
1054 String s = toEscapedPath(instrName);
1055 throw Exception("Cannot move. Directory with that name already exists: " + s);
1056 }
1057
1058 std::stringstream sql;
1059 sql << "UPDATE instruments SET dir_id=" << dstId;
1060 sql << " WHERE instr_id=" << instrId;
1061 ExecSql(sql.str());
1062 } catch (Exception e) {
1063 EndTransaction();
1064 throw e;
1065 }
1066 EndTransaction();
1067 FireInstrumentCountChanged(ParentDir);
1068 FireInstrumentCountChanged(Dst);
1069 }
1070
1071 void InstrumentsDb::CopyInstrument(String Instr, String Dst) {
1072 dmsg(2,("InstrumentsDb: CopyInstrument(Instr=%s,Dst=%s)\n", Instr.c_str(), Dst.c_str()));
1073 String ParentDir = GetDirectoryPath(Instr);
1074 if(ParentDir.empty()) throw Exception("Unknown parent directory");
1075
1076 BeginTransaction();
1077 try {
1078 int dirId = GetDirectoryId(GetDirectoryPath(Instr));
1079 if (dirId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1080
1081 String instrName = GetFileName(Instr);
1082 int instrId = GetInstrumentId(dirId, instrName);
1083 if (instrId == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1084
1085 int dstId = GetDirectoryId(Dst);
1086 if (dstId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dst));
1087 if (dirId == dstId) {
1088 EndTransaction();
1089 return;
1090 }
1091
1092 CopyInstrument(instrId, instrName, dstId, Dst);
1093 } catch (Exception e) {
1094 EndTransaction();
1095 throw e;
1096 }
1097 EndTransaction();
1098
1099 }
1100
1101 void InstrumentsDb::CopyInstrument(int InstrId, String InstrName, int DstDirId, String DstDir) {
1102 if (GetInstrumentId(DstDirId, InstrName) != -1) {
1103 String s = toEscapedPath(InstrName);
1104 throw Exception("Cannot copy. Instrument with that name already exists: " + s);
1105 }
1106
1107 if (GetDirectoryId(DstDirId, InstrName) != -1) {
1108 String s = toEscapedPath(InstrName);
1109 throw Exception("Cannot copy. Directory with that name already exists: " + s);
1110 }
1111
1112 DbInstrument i = GetInstrumentInfo(InstrId);
1113 sqlite3_stmt *pStmt = NULL;
1114 std::stringstream sql;
1115 sql << "INSERT INTO instruments (dir_id,instr_name,instr_file,instr_nr,format_family,";
1116 sql << "format_version,instr_size,description,is_drum,product,artists,keywords) ";
1117 sql << "VALUES (" << DstDirId << ",?,?," << i.InstrNr << ",?,?," << i.Size << ",?,";
1118 sql << i.IsDrum << ",?,?,?)";
1119
1120 int res = sqlite3_prepare(GetDb(), sql.str().c_str(), -1, &pStmt, NULL);
1121 if (res != SQLITE_OK) {
1122 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1123 }
1124
1125 String s = toDbName(InstrName);
1126 BindTextParam(pStmt, 1, s);
1127 BindTextParam(pStmt, 2, i.InstrFile);
1128 BindTextParam(pStmt, 3, i.FormatFamily);
1129 BindTextParam(pStmt, 4, i.FormatVersion);
1130 BindTextParam(pStmt, 5, i.Description);
1131 BindTextParam(pStmt, 6, i.Product);
1132 BindTextParam(pStmt, 7, i.Artists);
1133 BindTextParam(pStmt, 8, i.Keywords);
1134
1135 res = sqlite3_step(pStmt);
1136 if(res != SQLITE_DONE) {
1137 sqlite3_finalize(pStmt);
1138 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1139 }
1140
1141 sqlite3_finalize(pStmt);
1142 FireInstrumentCountChanged(DstDir);
1143 }
1144
1145 void InstrumentsDb::SetInstrumentDescription(String Instr, String Desc) {
1146 dmsg(2,("InstrumentsDb: SetInstrumentDescription(Instr=%s,Desc=%s)\n", Instr.c_str(), Desc.c_str()));
1147
1148 BeginTransaction();
1149 try {
1150 int id = GetInstrumentId(Instr);
1151 if(id == -1) throw Exception("Unknown DB instrument: " + toEscapedPath(Instr));
1152
1153 std::stringstream sql;
1154 sql << "UPDATE instruments SET description=?,modified=CURRENT_TIMESTAMP ";
1155 sql << "WHERE instr_id="<< id;
1156
1157 ExecSql(sql.str(), Desc);
1158 } catch (Exception e) {
1159 EndTransaction();
1160 throw e;
1161 }
1162 EndTransaction();
1163 FireInstrumentInfoChanged(Instr);
1164 }
1165
1166 void InstrumentsDb::AddInstrumentsFromFile(String DbDir, String File, int Index, ScanProgress* pProgress) {
1167 dmsg(2,("InstrumentsDb: AddInstrumentsFromFile(DbDir=%s,File=%s,Index=%d)\n", DbDir.c_str(), File.c_str(), Index));
1168
1169 if(File.length() < 4) return;
1170
1171 try {
1172 if(!strcasecmp(".gig", File.substr(File.length() - 4).c_str())) {
1173 if (pProgress != NULL) {
1174 pProgress->SetStatus(0);
1175 pProgress->CurrentFile = File;
1176 }
1177
1178 AddGigInstruments(DbDir, File, Index, pProgress);
1179
1180 if (pProgress != NULL) {
1181 pProgress->SetScannedFileCount(pProgress->GetScannedFileCount() + 1);
1182 }
1183 }
1184 } catch(Exception e) {
1185 e.PrintMessage();
1186 }
1187 }
1188
1189 void InstrumentsDb::AddGigInstruments(String DbDir, String FilePath, int Index, ScanProgress* pProgress) {
1190 dmsg(2,("InstrumentsDb: AddGigInstruments(DbDir=%s,FilePath=%s,Index=%d)\n", DbDir.c_str(), FilePath.c_str(), Index));
1191 int dirId = GetDirectoryId(DbDir);
1192 if (dirId == -1) throw Exception("Invalid DB directory: " + toEscapedPath(DbDir));
1193
1194 File f = File(FilePath);
1195 if (!f.Exist()) {
1196 std::stringstream ss;
1197 ss << "Fail to stat `" << FilePath << "`: " << f.GetErrorMsg();
1198 throw Exception(ss.str());
1199 }
1200
1201 if (!f.IsFile()) {
1202 std::stringstream ss;
1203 ss << "`" << FilePath << "` is not a regular file";
1204 throw Exception(ss.str());
1205 }
1206
1207 bool unlocked = false;
1208 RIFF::File* riff = NULL;
1209 gig::File* gig = NULL;
1210 try {
1211 riff = new RIFF::File(FilePath);
1212 gig::File* gig = new gig::File(riff);
1213 gig->SetAutoLoad(false); // avoid time consuming samples scanning
1214
1215 std::stringstream sql;
1216 sql << "INSERT INTO instruments (dir_id,instr_name,instr_file,";
1217 sql << "instr_nr,format_family,format_version,instr_size,";
1218 sql << "description,is_drum,product,artists,keywords) VALUES (";
1219 sql << dirId << ",?,?,?,'GIG',?," << f.GetSize() << ",?,?,?,?,?)";
1220
1221 sqlite3_stmt* pStmt = NULL;
1222
1223 int res = sqlite3_prepare(GetDb(), sql.str().c_str(), -1, &pStmt, NULL);
1224 if (res != SQLITE_OK) {
1225 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1226 }
1227
1228 String s = FilePath;
1229 s = toEscapedFsPath(s);
1230 BindTextParam(pStmt, 2, s);
1231 String ver = "";
1232 if (gig->pVersion != NULL) ver = ToString(gig->pVersion->major);
1233 BindTextParam(pStmt, 4, ver);
1234
1235 if (Index == -1) {
1236 int instrIndex = 0;
1237 // Assume that it's locked and should be unlocked at this point
1238 // to be able to use the database from another threads
1239 if (!InTransaction) {
1240 DbInstrumentsMutex.Unlock();
1241 unlocked = true;
1242 } else {
1243 std::cerr << "Shouldn't be in transaction when adding instruments." << std::endl;
1244 }
1245
1246 if (pProgress != NULL) gig->GetInstrument(0, &(pProgress->GigFileProgress)); // TODO: this workaround should be fixed
1247 gig::Instrument* pInstrument = gig->GetFirstInstrument();
1248
1249 if (!InTransaction) DbInstrumentsMutex.Lock();
1250 while (pInstrument) {
1251 BindTextParam(pStmt, 7, gig->pInfo->Product);
1252 BindTextParam(pStmt, 8, gig->pInfo->Artists);
1253 BindTextParam(pStmt, 9, gig->pInfo->Keywords);
1254 AddGigInstrument(pStmt, DbDir, dirId, FilePath, pInstrument, instrIndex);
1255
1256 instrIndex++;
1257 pInstrument = gig->GetNextInstrument();
1258 }
1259 } else {
1260 gig::Instrument* pInstrument;
1261 if (pProgress == NULL) pInstrument = gig->GetInstrument(Index);
1262 else pInstrument = gig->GetInstrument(Index, &(pProgress->GigFileProgress));
1263 if (pInstrument != NULL) {
1264 BindTextParam(pStmt, 7, gig->pInfo->Product);
1265 BindTextParam(pStmt, 8, gig->pInfo->Artists);
1266 BindTextParam(pStmt, 9, gig->pInfo->Keywords);
1267 AddGigInstrument(pStmt, DbDir, dirId, FilePath, pInstrument, Index);
1268 }
1269 }
1270
1271 sqlite3_finalize(pStmt);
1272 delete gig;
1273 delete riff;
1274 } catch (RIFF::Exception e) {
1275 if (gig != NULL) delete gig;
1276 if (riff != NULL) delete riff;
1277 if (unlocked) DbInstrumentsMutex.Lock();
1278 std::stringstream ss;
1279 ss << "Failed to scan `" << FilePath << "`: " << e.Message;
1280
1281 throw Exception(ss.str());
1282 } catch (Exception e) {
1283 if (gig != NULL) delete gig;
1284 if (riff != NULL) delete riff;
1285 if (unlocked) DbInstrumentsMutex.Lock();
1286 throw e;
1287 } catch (...) {
1288 if (gig != NULL) delete gig;
1289 if (riff != NULL) delete riff;
1290 if (unlocked) DbInstrumentsMutex.Lock();
1291 throw Exception("Failed to scan `" + FilePath + "`");
1292 }
1293 }
1294
1295 void InstrumentsDb::AddGigInstrument(sqlite3_stmt* pStmt, String DbDir, int DirId, String File, gig::Instrument* pInstrument, int Index) {
1296 dmsg(2,("InstrumentsDb: AddGigInstrument(DbDir=%s,DirId=%d,File=%s,Index=%d)\n", DbDir.c_str(), DirId, File.c_str(), Index));
1297 String name = pInstrument->pInfo->Name;
1298 if (name == "") return;
1299 name = GetUniqueName(DirId, name);
1300
1301 std::stringstream sql2;
1302 sql2 << "SELECT COUNT(*) FROM instruments WHERE instr_file=? AND ";
1303 sql2 << "instr_nr=" << Index;
1304 String s = toEscapedFsPath(File);
1305 if (ExecSqlInt(sql2.str(), s) > 0) return;
1306
1307 BindTextParam(pStmt, 1, name);
1308 BindIntParam(pStmt, 3, Index);
1309
1310 BindTextParam(pStmt, 5, pInstrument->pInfo->Comments);
1311 BindIntParam(pStmt, 6, pInstrument->IsDrum);
1312
1313 if (!pInstrument->pInfo->Product.empty()) {
1314 BindTextParam(pStmt, 7, pInstrument->pInfo->Product);
1315 }
1316 if (!pInstrument->pInfo->Artists.empty()) {
1317 BindTextParam(pStmt, 8, pInstrument->pInfo->Artists);
1318 }
1319
1320 if (!pInstrument->pInfo->Keywords.empty()) {
1321 BindTextParam(pStmt, 9, pInstrument->pInfo->Keywords);
1322 }
1323
1324 int res = sqlite3_step(pStmt);
1325 if(res != SQLITE_DONE) {
1326 sqlite3_finalize(pStmt);
1327 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1328 }
1329
1330 res = sqlite3_reset(pStmt);
1331 FireInstrumentCountChanged(DbDir);
1332 }
1333
1334 void InstrumentsDb::DirectoryTreeWalk(String AbstractPath, DirectoryHandler* pHandler) {
1335 int DirId = GetDirectoryId(AbstractPath);
1336 if(DirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(AbstractPath));
1337 DirectoryTreeWalk(pHandler, AbstractPath, DirId, 0);
1338 }
1339
1340 void InstrumentsDb::DirectoryTreeWalk(DirectoryHandler* pHandler, String AbstractPath, int DirId, int Level) {
1341 if(Level == 1000) throw Exception("Possible infinite loop detected");
1342 pHandler->ProcessDirectory(AbstractPath, DirId);
1343
1344 String s;
1345 StringListPtr pDirs = GetDirectories(DirId);
1346 for(int i = 0; i < pDirs->size(); i++) {
1347 if (AbstractPath.length() == 1 && AbstractPath.at(0) == '/') {
1348 s = "/" + pDirs->at(i);
1349 } else {
1350 s = AbstractPath + "/" + pDirs->at(i);
1351 }
1352 DirectoryTreeWalk(pHandler, s, GetDirectoryId(DirId, pDirs->at(i)), Level + 1);
1353 }
1354 }
1355
1356 StringListPtr InstrumentsDb::FindDirectories(String Dir, SearchQuery* pQuery, bool Recursive) {
1357 dmsg(2,("InstrumentsDb: FindDirectories(Dir=%s)\n", Dir.c_str()));
1358 DirectoryFinder directoryFinder(pQuery);
1359
1360 BeginTransaction();
1361 try {
1362 int DirId = GetDirectoryId(Dir);
1363 if(DirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
1364
1365 if (Recursive) DirectoryTreeWalk(Dir, &directoryFinder);
1366 else directoryFinder.ProcessDirectory(Dir, DirId);
1367 } catch (Exception e) {
1368 EndTransaction();
1369 throw e;
1370 }
1371 EndTransaction();
1372
1373 return directoryFinder.GetDirectories();
1374 }
1375
1376 StringListPtr InstrumentsDb::FindInstruments(String Dir, SearchQuery* pQuery, bool Recursive) {
1377 dmsg(2,("InstrumentsDb: FindInstruments(Dir=%s)\n", Dir.c_str()));
1378 InstrumentFinder instrumentFinder(pQuery);
1379
1380 BeginTransaction();
1381 try {
1382 int DirId = GetDirectoryId(Dir);
1383 if(DirId == -1) throw Exception("Unknown DB directory: " + toEscapedPath(Dir));
1384
1385 if (Recursive) DirectoryTreeWalk(Dir, &instrumentFinder);
1386 else instrumentFinder.ProcessDirectory(Dir, DirId);
1387 } catch (Exception e) {
1388 EndTransaction();
1389 throw e;
1390 }
1391 EndTransaction();
1392
1393 return instrumentFinder.GetInstruments();
1394 }
1395
1396 StringListPtr InstrumentsDb::FindLostInstrumentFiles() {
1397 dmsg(2,("InstrumentsDb: FindLostInstrumentFiles()\n"));
1398
1399 BeginTransaction();
1400 try {
1401 StringListPtr files = ExecSqlStringList("SELECT DISTINCT instr_file FROM instruments");
1402 StringListPtr result(new std::vector<String>);
1403 for (int i = 0; i < files->size(); i++) {
1404 File f(toNonEscapedFsPath(files->at(i)));
1405 if (!f.Exist()) result->push_back(files->at(i));
1406 }
1407 return result;
1408 } catch (Exception e) {
1409 EndTransaction();
1410 throw e;
1411 }
1412 EndTransaction();
1413 }
1414
1415 void InstrumentsDb::SetInstrumentFilePath(String OldPath, String NewPath) {
1416 if (OldPath == NewPath) return;
1417 StringListPtr instrs;
1418 BeginTransaction();
1419 try {
1420 std::vector<String> params(2);
1421 params[0] = toEscapedFsPath(NewPath);
1422 params[1] = toEscapedFsPath(OldPath);
1423 instrs = GetInstrumentsByFile(OldPath);
1424 ExecSql("UPDATE instruments SET instr_file=? WHERE instr_file=?", params);
1425 } catch (Exception e) {
1426 EndTransaction();
1427 throw e;
1428 }
1429 EndTransaction();
1430
1431 for (int i = 0; i < instrs->size(); i++) {
1432 FireInstrumentInfoChanged(instrs->at(i));
1433 }
1434 }
1435
1436 void InstrumentsDb::BeginTransaction() {
1437 dmsg(2,("InstrumentsDb: BeginTransaction(InTransaction=%d)\n", InTransaction));
1438 DbInstrumentsMutex.Lock();
1439 if (InTransaction) return;
1440
1441 if(db == NULL) return;
1442 sqlite3_stmt *pStmt = NULL;
1443
1444 InTransaction = true;
1445 int res = sqlite3_prepare(db, "BEGIN TRANSACTION", -1, &pStmt, NULL);
1446 if (res != SQLITE_OK) {
1447 std::cerr << ToString(sqlite3_errmsg(db)) << std::endl;
1448 return;
1449 }
1450
1451 res = sqlite3_step(pStmt);
1452 if(res != SQLITE_DONE) {
1453 sqlite3_finalize(pStmt);
1454 std::cerr << ToString(sqlite3_errmsg(db)) << std::endl;
1455 return;
1456 }
1457
1458 sqlite3_finalize(pStmt);
1459 }
1460
1461 void InstrumentsDb::EndTransaction() {
1462 dmsg(2,("InstrumentsDb: EndTransaction(InTransaction=%d)\n", InTransaction));
1463 if (!InTransaction) {
1464 DbInstrumentsMutex.Unlock();
1465 return;
1466 }
1467 InTransaction = false;
1468
1469 if(db == NULL) {
1470 DbInstrumentsMutex.Unlock();
1471 return;
1472 }
1473 sqlite3_stmt *pStmt = NULL;
1474
1475 int res = sqlite3_prepare(db, "END TRANSACTION", -1, &pStmt, NULL);
1476 if (res != SQLITE_OK) {
1477 std::cerr << ToString(sqlite3_errmsg(db)) << std::endl;
1478 DbInstrumentsMutex.Unlock();
1479 return;
1480 }
1481
1482 res = sqlite3_step(pStmt);
1483 if(res != SQLITE_DONE) {
1484 sqlite3_finalize(pStmt);
1485 std::cerr << ToString(sqlite3_errmsg(db)) << std::endl;
1486 DbInstrumentsMutex.Unlock();
1487 return;
1488 }
1489
1490 sqlite3_finalize(pStmt);
1491 DbInstrumentsMutex.Unlock();
1492 }
1493
1494 void InstrumentsDb::ExecSql(String Sql) {
1495 dmsg(2,("InstrumentsDb: ExecSql(Sql=%s)\n", Sql.c_str()));
1496 std::vector<String> Params;
1497 ExecSql(Sql, Params);
1498 }
1499
1500 void InstrumentsDb::ExecSql(String Sql, String Param) {
1501 dmsg(2,("InstrumentsDb: ExecSql(Sql=%s,Param=%s)\n", Sql.c_str(), Param.c_str()));
1502 std::vector<String> Params;
1503 Params.push_back(Param);
1504 ExecSql(Sql, Params);
1505 }
1506
1507 void InstrumentsDb::ExecSql(String Sql, std::vector<String>& Params) {
1508 dmsg(2,("InstrumentsDb: ExecSql(Sql=%s,Params)\n", Sql.c_str()));
1509 sqlite3_stmt *pStmt = NULL;
1510
1511 int res = sqlite3_prepare(GetDb(), Sql.c_str(), -1, &pStmt, NULL);
1512 if (res != SQLITE_OK) {
1513 sqlite3_finalize(pStmt);
1514 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1515 }
1516
1517 for(int i = 0; i < Params.size(); i++) {
1518 BindTextParam(pStmt, i + 1, Params[i]);
1519 }
1520
1521 res = sqlite3_step(pStmt);
1522 if (res != SQLITE_DONE) {
1523 sqlite3_finalize(pStmt);
1524 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1525 }
1526
1527 sqlite3_finalize(pStmt);
1528 }
1529
1530 int InstrumentsDb::ExecSqlInt(String Sql) {
1531 dmsg(2,("InstrumentsDb: ExecSqlInt(Sql=%s)\n", Sql.c_str()));
1532 sqlite3_stmt *pStmt = NULL;
1533
1534 int res = sqlite3_prepare(GetDb(), Sql.c_str(), -1, &pStmt, NULL);
1535 if (res != SQLITE_OK) {
1536 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1537 }
1538
1539 int i = -1;
1540 res = sqlite3_step(pStmt);
1541 if(res == SQLITE_ROW) {
1542 i = sqlite3_column_int(pStmt, 0);
1543 } else if (res != SQLITE_DONE) {
1544 sqlite3_finalize(pStmt);
1545 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1546 }
1547
1548 sqlite3_finalize(pStmt);
1549
1550 return i;
1551 }
1552
1553 int InstrumentsDb::ExecSqlInt(String Sql, String Param) {
1554 dmsg(2,("InstrumentsDb: ExecSqlInt(Sql=%s,Param=%s)\n", Sql.c_str(), Param.c_str()));
1555 sqlite3_stmt *pStmt = NULL;
1556
1557 int res = sqlite3_prepare(GetDb(), Sql.c_str(), -1, &pStmt, NULL);
1558 if (res != SQLITE_OK) {
1559 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1560 }
1561
1562 BindTextParam(pStmt, 1, Param);
1563
1564 int i = -1;
1565 res = sqlite3_step(pStmt);
1566 if(res == SQLITE_ROW) {
1567 i = sqlite3_column_int(pStmt, 0);
1568 } else if (res != SQLITE_DONE) {
1569 sqlite3_finalize(pStmt);
1570 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1571 }
1572
1573 sqlite3_finalize(pStmt);
1574 return i;
1575 }
1576
1577 String InstrumentsDb::ExecSqlString(String Sql) {
1578 dmsg(2,("InstrumentsDb: ExecSqlString(Sql=%s)\n", Sql.c_str()));
1579 sqlite3_stmt *pStmt = NULL;
1580
1581 int res = sqlite3_prepare(GetDb(), Sql.c_str(), -1, &pStmt, NULL);
1582 if (res != SQLITE_OK) {
1583 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1584 }
1585
1586 String s;
1587 res = sqlite3_step(pStmt);
1588 if(res == SQLITE_ROW) {
1589 s = ToString(sqlite3_column_text(pStmt, 0));
1590 } else if (res != SQLITE_DONE) {
1591 sqlite3_finalize(pStmt);
1592 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1593 }
1594
1595 sqlite3_finalize(pStmt);
1596
1597 return s;
1598 }
1599
1600 IntListPtr InstrumentsDb::ExecSqlIntList(String Sql) {
1601 dmsg(2,("InstrumentsDb: ExecSqlIntList(Sql=%s)\n", Sql.c_str()));
1602 std::vector<String> Params;
1603 return ExecSqlIntList(Sql, Params);
1604 }
1605
1606 IntListPtr InstrumentsDb::ExecSqlIntList(String Sql, String Param) {
1607 dmsg(2,("InstrumentsDb: ExecSqlIntList(Sql=%s,Param=%s)\n", Sql.c_str(), Param.c_str()));
1608 std::vector<String> Params;
1609 Params.push_back(Param);
1610 return ExecSqlIntList(Sql, Params);
1611 }
1612
1613 IntListPtr InstrumentsDb::ExecSqlIntList(String Sql, std::vector<String>& Params) {
1614 dmsg(2,("InstrumentsDb: ExecSqlIntList(Sql=%s)\n", Sql.c_str()));
1615 IntListPtr intList(new std::vector<int>);
1616
1617 sqlite3_stmt *pStmt = NULL;
1618
1619 int res = sqlite3_prepare(GetDb(), Sql.c_str(), -1, &pStmt, NULL);
1620 if (res != SQLITE_OK) {
1621 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1622 }
1623
1624 for(int i = 0; i < Params.size(); i++) {
1625 BindTextParam(pStmt, i + 1, Params[i]);
1626 }
1627
1628 res = sqlite3_step(pStmt);
1629 while(res == SQLITE_ROW) {
1630 intList->push_back(sqlite3_column_int(pStmt, 0));
1631 res = sqlite3_step(pStmt);
1632 }
1633
1634 if (res != SQLITE_DONE) {
1635 sqlite3_finalize(pStmt);
1636 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1637 }
1638
1639 sqlite3_finalize(pStmt);
1640
1641 return intList;
1642 }
1643
1644 StringListPtr InstrumentsDb::ExecSqlStringList(String Sql) {
1645 dmsg(2,("InstrumentsDb: ExecSqlStringList(Sql=%s)\n", Sql.c_str()));
1646 StringListPtr stringList(new std::vector<String>);
1647
1648 sqlite3_stmt *pStmt = NULL;
1649
1650 int res = sqlite3_prepare(GetDb(), Sql.c_str(), -1, &pStmt, NULL);
1651 if (res != SQLITE_OK) {
1652 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1653 }
1654
1655 res = sqlite3_step(pStmt);
1656 while(res == SQLITE_ROW) {
1657 stringList->push_back(ToString(sqlite3_column_text(pStmt, 0)));
1658 res = sqlite3_step(pStmt);
1659 }
1660
1661 if (res != SQLITE_DONE) {
1662 sqlite3_finalize(pStmt);
1663 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1664 }
1665
1666 sqlite3_finalize(pStmt);
1667
1668 return stringList;
1669 }
1670
1671 void InstrumentsDb::BindTextParam(sqlite3_stmt* pStmt, int Index, String Text) {
1672 if (pStmt == NULL) return;
1673 int res = sqlite3_bind_text(pStmt, Index, Text.c_str(), -1, SQLITE_STATIC);
1674 if (res != SQLITE_OK) {
1675 sqlite3_finalize(pStmt);
1676 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1677 }
1678 }
1679
1680 void InstrumentsDb::BindIntParam(sqlite3_stmt* pStmt, int Index, int Param) {
1681 if (pStmt == NULL) return;
1682 int res = sqlite3_bind_int(pStmt, Index, Param);
1683 if (res != SQLITE_OK) {
1684 sqlite3_finalize(pStmt);
1685 throw Exception("DB error: " + ToString(sqlite3_errmsg(db)));
1686 }
1687 }
1688
1689 #ifndef WIN32
1690 void InstrumentsDb::Regexp(sqlite3_context* pContext, int argc, sqlite3_value** ppValue) {
1691 if (argc != 2) return;
1692
1693 String pattern = ToString(sqlite3_value_text(ppValue[0]));
1694 String str = ToString(sqlite3_value_text(ppValue[1]));
1695
1696 if(!fnmatch(pattern.c_str(), str.c_str(), FNM_CASEFOLD)) {
1697 sqlite3_result_int(pContext, 1);
1698 }
1699 }
1700 #endif
1701
1702 String InstrumentsDb::GetDirectoryPath(String File) {
1703 if (File.empty()) return String("");
1704 if (File.at(0) != '/') String("");
1705 if (File.length() == 1) return File;
1706 if (File.at(File.length() - 1) == '/') return File.substr(0, File.length() - 1);
1707 int i = File.rfind('/', File.length() - 1);
1708 if(i == std::string::npos) return String("");
1709 if(i == 0) return String("/");
1710 return File.substr(0, i);
1711 }
1712
1713 String InstrumentsDb::GetFileName(String Path) {
1714 if (Path.length() < 2) return String("");
1715 if (Path.at(0) != '/') String("");
1716 if (Path.at(Path.length() - 1) == '/') return String("");
1717 int i = Path.rfind('/', Path.length() - 1);
1718 return Path.substr(i + 1);
1719 }
1720
1721 void InstrumentsDb::CheckPathName(String Path) {
1722 if (Path.empty()) return;
1723
1724 int i = 0, j = Path.find('/', i);
1725
1726 while(j != std::string::npos) {
1727 if (j + 1 >= Path.length()) return;
1728 if (Path.at(j + 1) == '/') throw Exception("Invalid path name: " + Path);
1729
1730 i = j + 1;
1731 j = Path.find('/', i);
1732 }
1733 }
1734
1735 String InstrumentsDb::GetParentDirectory(String Dir) {
1736 if (Dir.length() < 2) return String("");
1737 if (Dir.at(0) != '/') String("");
1738 int i = Dir.rfind('/', Dir.length() - 2);
1739 if (i == 0) return "/";
1740 return Dir.substr(0, i);
1741 }
1742
1743 void InstrumentsDb::Format() {
1744 DbInstrumentsMutex.Lock();
1745 if (db != NULL) {
1746 sqlite3_close(db);
1747 db = NULL;
1748 }
1749
1750 if (DbFile.empty()) DbFile = CONFIG_DEFAULT_INSTRUMENTS_DB_LOCATION;
1751 String bkp = DbFile + ".bkp";
1752 remove(bkp.c_str());
1753 if (rename(DbFile.c_str(), bkp.c_str()) && errno != ENOENT) {
1754 DbInstrumentsMutex.Unlock();
1755 throw Exception(String("Failed to backup database: ") + strerror(errno));
1756 }
1757
1758 String f = DbFile;
1759 DbFile = "";
1760 try { CreateInstrumentsDb(f); }
1761 catch(Exception e) {
1762 DbInstrumentsMutex.Unlock();
1763 throw e;
1764 }
1765 DbInstrumentsMutex.Unlock();
1766
1767 FireDirectoryCountChanged("/");
1768 FireInstrumentCountChanged("/");
1769 }
1770
1771 void InstrumentsDb::CheckFileName(String File) {
1772 if (File.empty()) throw Exception("Invalid file name: " + File);
1773 }
1774
1775 String InstrumentsDb::GetUniqueName(int DirId, String Name) {
1776 dmsg(2,("InstrumentsDb: GetUniqueInstrumentName(DirId=%d,Name=%s)\n", DirId, Name.c_str()));
1777
1778 if (GetInstrumentId(DirId, Name) == -1 && GetDirectoryId(DirId, Name) == -1) return Name;
1779 std::stringstream ss;
1780 for(int i = 2; i < 1001; i++) {
1781 ss.str("");
1782 ss << Name << '[' << i << ']';
1783 if (GetInstrumentId(DirId, ss.str()) == -1 && GetInstrumentId(DirId, ss.str()) == -1) {
1784 return ss.str();
1785 }
1786 }
1787
1788 throw Exception("Unable to find an unique name: " + Name);
1789 }
1790
1791 String InstrumentsDb::PrepareSubdirectory(String DbDir, String FsPath) {
1792 std::string dir = Path::getBaseName(FsPath);
1793 dir = toAbstractName(dir);
1794 if(dir.empty()) dir = "New Directory";
1795 dir = GetUniqueName(GetDirectoryId(DbDir), dir);
1796 dir = AppendNode(DbDir, dir);
1797 AddDirectory(dir);
1798 return dir;
1799 }
1800
1801 String InstrumentsDb::AppendNode(String DbDir, String Node) {
1802 if(DbDir.length() == 1 && DbDir.at(0) == '/') return DbDir + Node;
1803 if(DbDir.at(DbDir.length() - 1) == '/') return DbDir + Node;
1804 return DbDir + "/" + Node;
1805 }
1806
1807 String InstrumentsDb::toDbName(String AbstractName) {
1808 for (int i = 0; i < AbstractName.length(); i++) {
1809 if (AbstractName.at(i) == '\0') AbstractName.at(i) = '/';
1810 }
1811 return AbstractName;
1812 }
1813
1814 String InstrumentsDb::toEscapedPath(String AbstractName) {
1815 for (int i = 0; i < AbstractName.length(); i++) {
1816 if (AbstractName.at(i) == '\0') AbstractName.replace(i++, 1, "\\x2f");
1817 else if (AbstractName.at(i) == '\\') AbstractName.replace(i++, 1, "\\\\");
1818 else if (AbstractName.at(i) == '\'') AbstractName.replace(i++, 1, "\\'");
1819 else if (AbstractName.at(i) == '"') AbstractName.replace(i++, 1, "\\\"");
1820 else if (AbstractName.at(i) == '\r') AbstractName.replace(i++, 1, "\\r");
1821 else if (AbstractName.at(i) == '\n') AbstractName.replace(i++, 1, "\\n");
1822 }
1823 return AbstractName;
1824 }
1825
1826 String InstrumentsDb::toEscapedText(String text) {
1827 for (int i = 0; i < text.length(); i++) {
1828 if (text.at(i) == '\\') text.replace(i++, 1, "\\\\");
1829 else if (text.at(i) == '\'') text.replace(i++, 1, "\\'");
1830 else if (text.at(i) == '"') text.replace(i++, 1, "\\\"");
1831 else if (text.at(i) == '\r') text.replace(i++, 1, "\\r");
1832 else if (text.at(i) == '\n') text.replace(i++, 1, "\\n");
1833 }
1834 return text;
1835 }
1836
1837 String InstrumentsDb::toNonEscapedText(String text) {
1838 String sb;
1839 for (int i = 0; i < text.length(); i++) {
1840 char c = text.at(i);
1841 if(c == '\\') {
1842 if(i >= text.length()) {
1843 std::cerr << "Broken escape sequence!" << std::endl;
1844 break;
1845 }
1846 char c2 = text.at(++i);
1847 if(c2 == '\'') sb.push_back('\'');
1848 else if(c2 == '"') sb.push_back('"');
1849 else if(c2 == '\\') sb.push_back('\\');
1850 else if(c2 == 'r') sb.push_back('\r');
1851 else if(c2 == 'n') sb.push_back('\n');
1852 else std::cerr << "Unknown escape sequence \\" << c2 << std::endl;
1853 } else {
1854 sb.push_back(c);
1855 }
1856 }
1857 return sb;
1858 }
1859
1860 String InstrumentsDb::toEscapedFsPath(String FsPath) {
1861 #ifdef WIN32
1862 replace(FsPath.begin(), FsPath.end(), '\\', '/');
1863 #endif
1864 return toEscapedText(FsPath);
1865 }
1866
1867 String InstrumentsDb::toNonEscapedFsPath(String FsPath) {
1868 FsPath = toNonEscapedText(FsPath);
1869 #ifdef WIN32
1870 replace(FsPath.begin(), FsPath.end(), '/', '\\');
1871 #endif
1872 return FsPath;
1873 }
1874
1875 String InstrumentsDb::toAbstractName(String DbName) {
1876 for (int i = 0; i < DbName.length(); i++) {
1877 if (DbName.at(i) == '/') DbName.at(i) = '\0';
1878 }
1879 return DbName;
1880 }
1881
1882 void InstrumentsDb::FireDirectoryCountChanged(String Dir) {
1883 for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1884 llInstrumentsDbListeners.GetListener(i)->DirectoryCountChanged(Dir);
1885 }
1886 }
1887
1888 void InstrumentsDb::FireDirectoryInfoChanged(String Dir) {
1889 for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1890 llInstrumentsDbListeners.GetListener(i)->DirectoryInfoChanged(Dir);
1891 }
1892 }
1893
1894 void InstrumentsDb::FireDirectoryNameChanged(String Dir, String NewName) {
1895 for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1896 llInstrumentsDbListeners.GetListener(i)->DirectoryNameChanged(Dir, NewName);
1897 }
1898 }
1899
1900 void InstrumentsDb::FireInstrumentCountChanged(String Dir) {
1901 for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1902 llInstrumentsDbListeners.GetListener(i)->InstrumentCountChanged(Dir);
1903 }
1904 }
1905
1906 void InstrumentsDb::FireInstrumentInfoChanged(String Instr) {
1907 for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1908 llInstrumentsDbListeners.GetListener(i)->InstrumentInfoChanged(Instr);
1909 }
1910 }
1911
1912 void InstrumentsDb::FireInstrumentNameChanged(String Instr, String NewName) {
1913 for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1914 llInstrumentsDbListeners.GetListener(i)->InstrumentNameChanged(Instr, NewName);
1915 }
1916 }
1917
1918 void InstrumentsDb::FireJobStatusChanged(int JobId) {
1919 for (int i = 0; i < llInstrumentsDbListeners.GetListenerCount(); i++) {
1920 llInstrumentsDbListeners.GetListener(i)->JobStatusChanged(JobId);
1921 }
1922 }
1923
1924 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC