/[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 1911 - (show annotations) (download)
Sat Jun 6 13:50:36 2009 UTC (14 years, 10 months ago) by senoner
File size: 71729 byte(s)
* InstrumentsDB on Windows now works in both standalone and VST mode
* DB is stored in %USERPROFILE%\.linuxsampler\instruments.db
* removed stat() implementation as mingw already provides it

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

  ViewVC Help
Powered by ViewVC