31 bool check_mtime(
const std::string& filename, time_t& mtime) {
33 if (stat(filename.c_str(), &st) != 0) {
37 time_t t =
max(st.st_mtime, st.st_ctime);
52 deferred_nl(enable_newlines ? 0 : -1),
62 if (deferred_nl == 1) {
72 if (deferred_nl == 1) {
78 inline void JsonWriter::komma() {
81 else if (deferred_nl == 0)
88 inline void JsonWriter::space() {
91 else if (deferred_nl == 0)
96 inline void JsonWriter::iplus() {
100 inline void JsonWriter::iminus() {
101 if (!indent.empty()) {
102 indent = indent.substr(0, indent.size() - 2);
106 template<
class T>
static inline T fp_sanitize(T v) {
107 switch (fpclassify(v)) {
108 case FP_NORMAL:
return v;
109 case FP_NAN: assert(
false);
return 1e50;
110 case FP_INFINITE: assert(
false);
return (v < 0 ? -1e50 : 1e50);
111 case FP_SUBNORMAL:
return 0;
118 *os << fp_sanitize(v);
124 *os << fp_sanitize(v);
152 case '\\':
case '"': *os <<
'\\';
break;
153 case '\b': *os <<
'\\'; *os <<
'b';
continue;
154 case '\f': *os <<
'\\'; *os <<
'f';
continue;
155 case '\n': *os <<
'\\'; *os <<
'n';
continue;
156 case '\r': *os <<
'\\'; *os <<
'r';
continue;
157 case '\t': *os <<
'\\'; *os <<
't';
continue;
214 if (deferred_nl == 1) {
299 default: assert(
false);
return 0;
313 const int maskbits = 0x3F;
314 const int maskbyte = 0x80;
315 const int mask2bytes = 0xC0;
316 const int mask3bytes = 0xE0;
317 static char result[4];
321 result[n++] = static_cast<char>(input);
324 }
else if (input < 0x800) {
325 result[n++] = (static_cast<char>(mask2bytes | (input >> 6)));
326 result[n++] = (static_cast<char>(maskbyte | (input & maskbits)));
330 result[n++] = (static_cast<char>(mask3bytes | (input >> 12)));
331 result[n++] = (static_cast<char>(maskbyte | ((input >> 6) & maskbits)));
332 result[n++] = (static_cast<char>(maskbyte | (input & maskbits)));
338 const char* JsonParser::readcode() {
340 for (
int i = 0; i < 4; i++) {
343 throw JsonExceptionEOF(
"eof");
344 if (
'0' <= n && n <=
'9')
347 n = 10 + (toupper(n) -
'A');
348 code = code * 16 + n;
353 string JsonParser::readstring() {
354 ostringstream os(
"");
365 case 'b': os <<
'\b';
break;
366 case 'f': os <<
'\f';
break;
367 case 'n': os <<
'\n';
break;
368 case 'r': os <<
'\r';
break;
369 case 't': os <<
'\t';
break;
370 case '"': os <<
'"';
break;
371 case 'u': os << readcode();
break;
372 default: is->get(c); os << c;
break;
374 }
else if (c ==
'"') {
382 string JsonParser::readnumber(
char c) {
383 ostringstream os(
"");
384 static int count_dn = 0;
389 case '+':
case '-':
case '0':
case '1':
case '2':
case '3':
case '4':
390 case '5':
case '6':
case '7':
case '8':
case '9':
case 'e':
case 'E':
394 case 'n':
case 'a':
case 'i':
case 'f':
397 gx_print_warning(
"JsonParser", Glib::ustring::compose(
"DENORMAL VALUE DETECTED in %1", log_tok));
405 }
while (is->good());
410 ostringstream os(
"");
414 if (c < 'a' || c >
'z') {
418 }
while (is->good());
420 if (next_str ==
"null") {
423 if (next_str ==
"true") {
426 if (next_str ==
"false") {
432 void JsonParser::read_next() {
435 if (next_tok !=
no_token and next_depth == 0) {
445 throw JsonExceptionEOF(
"eof");
448 }
while (c ==
' ' || c ==
'\t' || c ==
'\r' || c ==
'\n');
449 next_pos = is->tellg();
451 case '[': next_tok =
begin_array; next_depth++;
break;
453 case ']': next_tok =
end_array; next_depth--;
break;
457 case '}': next_tok =
end_object; next_depth--;
break;
462 next_str = log_tok = readstring();
465 throw JsonExceptionEOF(
"eof");
474 case '-':
case '0':
case '1':
case '2':
case '3':
case '4':
475 case '5':
case '6':
case '7':
case '8':
case '9':
476 next_str = readnumber(c);
480 case 'n':
case 'a':
case 'i':
case 'f':
481 next_str = readnumber(c);
486 next_tok = read_value_token(c);
488 throw JsonException(
"bad token");
581 int curdepth = depth;
608 }
while (curdepth != depth);
612 int curdepth = depth;
615 throw JsonException(
"unexpected eof");
617 }
while (curdepth != depth);
653 jw.
write(
"gx_head_file_version");
670 jw.
write(file_major);
685 ofstream os(name.c_str());
728 is =
new ifstream(filename.c_str());
730 JsonReader *jp =
new JsonReader(is);
735 gx_print_info(_(
"recall settings"), _(
"loading converted state"));
738 _(
"recall settings"),
739 boost::format(_(
"major version mismatch in %1%: found %2%, expected %3%"))
753 if (filename.empty() || !mtime) {
772 virtual void close();
777 tmpfile(filename +
"_tmp"),
778 os(tmpfile.c_str()) {
797 boost::format(_(
"couldn't write %1%")) % tmpfile);
799 int rc = rename(tmpfile.c_str(), filename.c_str());
802 boost::format(_(
"couldn't rename %1% to %2%"))
803 % tmpfile % filename);
808 class ModifyStatePreservePreset:
public ModifyState {
829 if (jp.current_value() ==
"current_preset") {
830 write(jp.current_value());
831 jp.copy_object(*
this);
837 }
catch(JsonException& e) {
842 *preserve_preset =
false;
851 if (*preserve_preset) {
852 jw =
new ModifyStatePreservePreset(filename, preserve_preset);
854 jw =
new ModifyState(filename);
931 default: jw.
write(
"unknown");
break;
947 for (
int i = 0; i <
size(); i++) {
958 _(
"open factory preset"),
959 boost::format(_(
"couldn't open %1%")) % path);
980 bool PresetFile::open_file(
const Glib::ustring& name_,
const std::string& path,
int tp_,
int flags_) {
1005 _(
"create preset bank"),
1006 boost::format(_(
"couldn't create %1%")) % path);
1053 jw.write(Gio::File::create_for_path(
filename)->get_basename());
1057 jw.write(static_cast<int>(
mtime));
1077 is->setstate(istream::failbit);
1080 boost::format(_(
"%1% is a state file, not a preset file")) %
filename);
1081 throw JsonException(_(
"This is a state file, not a preset file"));
1124 for (vector<Position>::const_iterator i =
entries.begin(); i !=
entries.end(); ++i) {
1125 l.push_back(i->name);
1141 for (
int i = 0; i <
size(); i++) {
1159 tmpfile(filename +
"_tmp"),
1160 os(tmpfile.c_str()),
1187 remove(tmpfile.c_str());
1198 boost::format(_(
"couldn't write %1%")) % tmpfile);
1201 int rc = rename(tmpfile.c_str(), filename.c_str());
1204 boost::format(_(
"couldn't rename %1% to %2%"))
1205 % tmpfile % filename);
1220 class ModifyPreset:
public PresetTransformer {
1233 : PresetTransformer(fname, is) {
1271 jw->jp.skip_object();
1300 jw.jp.skip_object();
1320 jw.jp.copy_object(jw);
1325 if (!Gio::File::create_for_path(
filename)->move(Gio::File::create_for_path(newfile))) {
1327 boost::format(_(
"couldn't move to %1%")) % newfile);
1336 if (!Gio::File::create_for_path(
filename)->remove()) {
1338 boost::format(_(
"couldn't remove %1%")) %
filename);
1362 static const char *std_presetname_postfix =
".gx";
1365 : banklist(), filepath(), mtime(), preset_dir() {
1375 for (iterator i =
begin(); i !=
end(); ++i) {
1383 banklist.push_back(pf);
1390 bool reload =
false;
1391 for (iterator i =
begin(); i !=
end(); ++i) {
1392 int tp = i->get_type();
1394 if (!i->ensure_is_current()) {
1409 for (bl_type::iterator i = banklist.begin(); i != banklist.end();) {
1410 int tp = (*i)->get_type();
1412 bl_type::iterator j = i;
1420 parse_bank_list(banklist.begin());
1424 void PresetBanks::parse(
const std::string& bank_path,
const std::string& preset_dir_,
1425 const std::string& factory_dir,
const char* scratchpad_name,
1426 const char* scratchpad_file) {
1427 filepath = bank_path;
1428 preset_dir = preset_dir_;
1430 parse_bank_list(banklist.end());
1431 collect_lost_banks(scratchpad_name, scratchpad_file);
1432 parse_factory_list(factory_dir);
1436 Glib::ustring::iterator i;
1437 while (!s.validate(i)) {
1438 Glib::ustring::iterator j = i;
1439 s.replace(i,++j,1,
'?');
1447 return filename + std_presetname_postfix;
1451 if (name.compare(name.size()-3, 3, std_presetname_postfix) != 0) {
1454 name = name.substr(0, name.size()-3);
1460 Glib::ustring t = name;
1466 if (!file || !Gio::File::create_for_path(*file)->query_exists()) {
1476 for (bl_type::const_iterator i = banklist.begin(); i != banklist.end(); ++i) {
1477 if ((*i)->get_filename() == file) {
1484 void PresetBanks::collect_lost_banks(
const char* scratchpad_name,
const char* scratchpad_file) {
1485 Glib::RefPtr<Gio::FileEnumerator> en = Gio::File::create_for_path(
1486 preset_dir)->enumerate_children(G_FILE_ATTRIBUTE_STANDARD_NAME);
1488 Glib::RefPtr<Gio::FileInfo> fi = en->next_file();
1492 std::string n = fi->get_name();
1493 if (n.size() <= 3 || n.substr(n.size()-3) != std_presetname_postfix) {
1496 std::string path = Glib::build_filename(preset_dir, n);
1500 PresetFile *f =
new PresetFile();
1501 if (n == scratchpad_file) {
1502 Glib::ustring nm = scratchpad_name;
1518 if (filepath.empty()) {
1521 std::string tmpfile = filepath +
"_tmp";
1522 ofstream os(tmpfile.c_str());
1524 jw.begin_array(
true);
1525 for (iterator i =
begin(); i !=
end(); ++i) {
1526 int tp = i->get_type();
1536 boost::format(_(
"couldn't write %1%")) % tmpfile);
1538 int rc =
::rename(tmpfile.c_str(), filepath.c_str());
1541 boost::format(_(
"couldn't rename %1% to %2%"))
1542 % tmpfile % filepath);
1548 void PresetBanks::parse_factory_list(
const std::string& path) {
1549 ifstream is(Glib::build_filename(path,
"dirlist.js").c_str());
1551 gx_print_error(_(
"Presets"), _(
"factory preset list not found"));
1563 string fname = Glib::build_filename(path, jp.
current_value());
1564 PresetFile *f =
new PresetFile();
1566 if (f->set_factory(name, fname)) {
1567 banklist.push_back(f);
1587 void PresetBanks::parse_bank_list(bl_type::iterator pos) {
1588 ifstream is(filepath.c_str());
1591 _(
"Presets"), boost::format(_(
"banks not found: '%1%'")) % filepath);
1595 bool mtime_diff =
false;
1600 f =
new PresetFile();
1601 if (!f->readJSON(preset_dir, jp, &mtime_diff)) {
1604 banklist.insert(pos, f);
1624 for (bl_type::const_iterator i = banklist.begin(); i != banklist.end(); ++i) {
1625 if ((*i)->get_name() == bank) {
1634 for (bl_type::const_iterator i = banklist.begin(); i != banklist.end(); ++i) {
1635 if ((*i)->get_name() == bank) {
1643 bool PresetBanks::rename(
const Glib::ustring& oldname,
const Glib::ustring& newname,
const std::string& newfile) {
1648 if (!f->set_name(newname, newfile)) {
1660 if (!f->remove_file()) {
1670 bl_type::iterator j = banklist.begin();
1671 for (std::vector<Glib::ustring>::const_iterator i = neworder.begin(); i != neworder.end(); ++i) {
1672 assert(j != banklist.end());
1673 if (*i == (*j)->get_name()) {
1676 for (bl_type::iterator k = j; k != banklist.end(); ++k) {
1677 if (*i == (*k)->get_name()) {
1678 banklist.splice(j, banklist, k);
1688 for (iterator i =
begin(); i !=
end(); ++i, --n) {
1690 return i->get_name();
1712 selection_changed(),
1713 presetlist_changed() {
1722 JsonParser *jp = p->create_reader(name);
1729 boost::format(_(
"%1% from file %2%")) % name % p->get_filename());
1742 }
catch(JsonException& e) {
1746 boost::format(_(
"error loading %1% from file %2%")) % name % p->get_filename());
1750 boost::format(_(
"error loading state from file %1%"))
1760 jp = p->create_reader(0);
1765 _(
"load online preset"),
1766 boost::format(_(
"error loading online presets")) );
1777 }
catch(JsonException& e) {
1780 boost::format(_(
"parse error in %1%"))
1781 % p->get_filename());
1785 if (!pf->has_entry(name)) {
1786 gx_print_error(_(
"open preset"), Glib::ustring::compose(
"bank %1 does not contain preset %2", pf->get_name(), name));
1807 if (modules_changed) {
1818 if (modules_changed) {
1844 void GxSettingsBase::append(PresetFile& pf,
const Glib::ustring& src, PresetFile& pftgt,
const Glib::ustring& name) {
1848 jp = pf.create_reader(src);
1849 jw = pftgt.create_writer(name);
1850 jp->copy_object(*jw);
1851 }
catch(JsonException& e) {
1854 boost::format(_(
"parse error in %1%"))
1855 % pf.get_filename());
1862 void GxSettingsBase::insert_before(PresetFile& pf,
const Glib::ustring& src, PresetFile& pftgt,
const Glib::ustring& pos,
const Glib::ustring& name) {
1866 jp = pf.create_reader(src);
1867 jw = pftgt.create_writer_at(pos, name);
1868 jp->copy_object(*jw);
1870 dynamic_cast<ModifyPreset*>(jw)->copy_object();
1871 }
catch(JsonException& e) {
1874 boost::format(_(
"parse error in %1%"))
1875 % pf.get_filename());
1882 void GxSettingsBase::insert_after(PresetFile& pf,
const Glib::ustring& src, PresetFile& pftgt,
const Glib::ustring& pos,
const Glib::ustring& name) {
1883 int i = pftgt.get_index(pos) + 1;
1884 if (i >= pftgt.size()) {
1885 append(pf, src, pftgt, name);
1892 bool newentry = (pf.get_index(name) < 0);
1895 jw = pf.create_writer(name);
1897 }
catch(JsonException& e) {
1900 boost::format(_(
"parse error in %1%"))
1901 % pf.get_filename());
1917 PresetTransformer *jw = 0;
1919 jw = pf.create_transformer();
1920 for (std::vector<Glib::ustring>::const_iterator i = neworder.begin(); i != neworder.end(); ++i) {
1921 JsonParser *jp = pf.create_reader(*i);
1923 jp->copy_object(*jw);
1926 jw->close_nocheck();
1927 }
catch(JsonException& e) {
1929 _(
"reorder presetfile"),
1930 boost::format(_(
"parse error in %1%"))
1931 % pf.get_filename());
1942 }
catch(JsonException& e) {
1945 boost::format(_(
"parse error in %1%"))
1946 % pf.get_filename());
1956 bool preset_preset =
false;
1961 PresetTransformer *jw = 0;
1964 jw = pf.create_transformer();
1967 jw->write(jw->jp.current_value());
1971 }
catch(JsonException& e) {
1973 _(
"convert presetfile"),
1974 boost::format(_(
"parse error in %1%"))
1975 % pf.get_filename());
2010 if (!pf.rename(oldname, newname)) {