/[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 1881 - (show annotations) (download)
Mon Mar 30 16:56:41 2009 UTC (11 years, 9 months ago) by iliev
File size: 71208 byte(s)
* Unlock the access to the instruments database while scanning a gig file

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

  ViewVC Help
Powered by ViewVC