/[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 1908 - (show annotations) (download)
Mon Jun 1 18:50:06 2009 UTC (14 years, 10 months ago) by persson
File size: 71271 byte(s)
* VST: avoid opening Fantasia more than once for each VST instance
* VST: export main function as "main" on Linux too (fix for energyXT)
* VST: prepare code for multiple output channels
* work-around for missing fnmatch function on Windows to make
  instrument database compilable

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

  ViewVC Help
Powered by ViewVC