/[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 1910 - (show annotations) (download)
Fri Jun 5 14:22:20 2009 UTC (14 years, 10 months ago) by senoner
File size: 71407 byte(s)
* Added Instruments DB on Windows.
* Relative path support for DB file (stdalone and VST) not implemented yet

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

  ViewVC Help
Powered by ViewVC