/[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 1943 - (show annotations) (download)
Tue Jul 14 18:25:11 2009 UTC (14 years, 9 months ago) by persson
File size: 72068 byte(s)
* fixed instrument database recursive import, which was broken on
  Windows

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

  ViewVC Help
Powered by ViewVC