/[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 1187 - (show annotations) (download)
Wed May 16 14:22:26 2007 UTC (16 years, 10 months ago) by iliev
File size: 72471 byte(s)
* updated instruments db support
* added transactions for improving the db performance
* added commands for copying and finding instruments and directories

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

  ViewVC Help
Powered by ViewVC