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) {
247 what_str =
"Json parse error: " + desc;
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++) {
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) {
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();
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);
581 int curdepth = depth;
608 }
while (curdepth != depth);
612 int curdepth = depth;
617 }
while (curdepth != depth);
653 jw.
write(
"gx_head_file_version");
657 jw.
write(gx_version);
670 jw.
write(file_major);
671 jw.
write(file_minor);
685 ofstream os(name.c_str());
728 is =
new ifstream(filename.c_str());
733 if (header.is_major_diff()) {
734 if (header.get_major() == 0) {
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);
842 *preserve_preset =
false;
851 if (*preserve_preset) {
914 "PresetFile", Glib::ustring::compose(
"%1: unknown remote key: %2",
name, jp.
current_value()));
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);
1005 _(
"create preset bank"),
1006 boost::format(_(
"couldn't create %1%")) % path);
1053 jw.
write(Gio::File::create_for_path(
filename)->get_basename());
1074 if (jp.current_value() ==
"midi_controller") {
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"));
1084 streampos pos = jp.get_streampos();
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++) {
1142 if (name ==
entries[i].name) {
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);
1222 ModifyPreset(
string filename, istream*
is,
const Glib::ustring& presname);
1295 if (get_index(name) < 0) {
1314 if (get_index(name) < 0) {
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);
1347 return entries.end();
1354 return entries.begin();
1362 static const char *std_presetname_postfix =
".gx";
1365 : banklist(), filepath(), mtime(), preset_dir() {
1383 banklist.push_back(pf);
1390 bool reload =
false;
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());
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);
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);
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());
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;
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)) {
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);
1690 return i->get_name();
1712 selection_changed(),
1713 presetlist_changed() {
1729 boost::format(_(
"%1% from file %2%")) % name % p->
get_filename());
1745 boost::format(_(
"error loading %1% from file %2%")) % name % p->
get_filename());
1749 boost::format(_(
"error loading state from file %1%"))
1766 boost::format(_(
"parse error in %1%"))
1772 gx_print_error(_(
"open preset"), Glib::ustring::compose(
"bank %1 does not contain preset %2", pf->
get_name(), name));
1793 if (modules_changed) {
1804 if (modules_changed) {
1840 boost::format(_(
"parse error in %1%"))
1860 boost::format(_(
"parse error in %1%"))
1870 if (i >= pftgt.
size()) {
1871 append(pf, src, pftgt, name);
1878 bool newentry = (pf.
get_index(name) < 0);
1886 boost::format(_(
"parse error in %1%"))
1906 for (std::vector<Glib::ustring>::const_iterator i = neworder.begin(); i != neworder.end(); ++i) {
1915 _(
"reorder presetfile"),
1916 boost::format(_(
"parse error in %1%"))
1931 boost::format(_(
"parse error in %1%"))
1942 bool preset_preset =
false;
1959 _(
"convert presetfile"),
1960 boost::format(_(
"parse error in %1%"))
1996 if (!pf.
rename(oldname, newname)) {
gx_engine::EngineControl & seq
bool rename(const Glib::ustring &name, Glib::ustring newname)
void gx_print_info(const char *, const std::string &)
JsonParser * create_reader(int n)
void readJSON_remote(JsonParser &jp)
bool has_entry(const Glib::ustring &name)
void throw_unexpected(token expect)
void begin_array(bool nl=false)
void save(PresetFile &pf, const Glib::ustring &name)
PresetFile * get_current_bank_file()
bool rename_preset(PresetFile &pf, const Glib::ustring &oldname, const Glib::ustring &newname)
void set_stream(ostream *o)
void make_bank_unique(Glib::ustring &name, std::string *file=0)
const char * unicode2utf8(unsigned int input)
unsigned int current_value_uint()
void insert(PresetFile *f)
void end_array(bool nl=false)
void set_streampos(streampos pos)
void fill_names(vector< Glib::ustring > &)
const Glib::ustring & get_name() const
static std::string add_preset_postfix(const std::string &filename)
bool remove_bank(const Glib::ustring &bank)
const char * get_token_name(token tok)
sigc::signal< void > selection_changed
void reorder(const std::vector< Glib::ustring > &neworder)
virtual void commit_preset()=0
virtual void read_preset(JsonParser &, const SettingsFileHeader &)=0
PresetFile * get_file(const Glib::ustring &bank) const
ModifyStatePreservePreset(const string &name, bool *preserve_preset)
JsonParser * create_reader()
void set_flag(int flag, bool v)
Glib::ustring get_name(int n)
void append(PresetFile &pf, const Glib::ustring &src, PresetFile &pftgt, const Glib::ustring &name)
std::vector< Position >::iterator iterator
sigc::signal< void > presetlist_changed
JsonSubParser(JsonParser &jp, streampos pos)
void write_key(const char *p, bool nl=false)
virtual void write_state(JsonWriter &, bool)=0
PresetTransformer * create_transformer()
std::vector< Position > entries
std::string decode_filename(const std::string &s)
void writeJSON_remote(JsonWriter &jw)
int get_index(const Glib::ustring &bank) const
virtual void write_preset(JsonWriter &)=0
virtual ~AbstractPresetIO()
bool check_mtime(const std::string &filename, time_t &mtime)
const SettingsFileHeader & get_header()
bool open_file(const Glib::ustring &name, const std::string &path, int tp, int flags)
void parse(const std::string &bank_path, const std::string &preset_dir, const std::string &factory_path, const char *scratchpad_name, const char *scratchpad_file)
void gx_print_error(const char *, const std::string &)
bool read_kv(const char *key, float &v)
SettingsFileHeader header
static bool strip_preset_postfix(std::string &name)
void check_expect(token expect)
int get_index(const Glib::ustring &name)
bool set_factory(const Glib::ustring &name_, const std::string &path)
const std::string & get_filename() const
void set_filename(const string &fn)
void clear_rack_changed()
void set_source_to_state()
bool convert_preset(PresetFile &pf)
void begin_object(bool nl=false)
JsonException(const Glib::ustring &desc)
void insert_after(PresetFile &pf, const Glib::ustring &src, PresetFile &pftgt, const Glib::ustring &pos, const Glib::ustring &name)
void write_null(bool nl=false)
JsonWriter * create_writer(bool *preserve_preset)
virtual void wait_ramp_down_finished()=0
AbstractPresetIO * preset_io
void set_stream(istream *i)
void load_preset(PresetFile *pf, const Glib::ustring &name)
virtual void start_ramp_up()=0
bool has_entry(const Glib::ustring &bank) const
virtual void start_ramp_down()=0
void copy_object(JsonWriter &jw)
std::string to_string(const T &t)
virtual void read_state(JsonParser &, const SettingsFileHeader &)=0
bool rename(const Glib::ustring &oldname, const Glib::ustring &newname, const std::string &newfile)
void readJSON_remote(gx_system::JsonParser &jp)
JsonWriter(ostream *o=0, bool enable_newlines=true)
void send_notify_begin(const char *method)
bool readJSON(const std::string &dirpath, JsonParser &jp, bool *mtime_diff)
AbstractStateIO * state_io
void gx_print_warning(const char *, const std::string &)
string get_filename() const
const SettingsFileHeader & get_header() const
Glib::ustring current_name
virtual ~AbstractStateIO()
ModifyPreset(string filename, istream *is, const Glib::ustring &presname)
~ModifyStatePreservePreset()
JsonWriter * create_writer(int n)
virtual void copy_preset(JsonParser &, const SettingsFileHeader &, JsonWriter &)=0
Glib::ustring current_bank
const Glib::ustring & get_name(int n)
bool has_file(const std::string &file) const
string current_value() const
ModifyState(const string &name)
virtual bool update_module_lists()=0
float current_value_float()
virtual void commit_state()=0
bool erase(const Glib::ustring &name)
token next(token expect=no_token)
void write(float v, bool nl=false)
bool set_name(const Glib::ustring &n, const std::string &newfile)
void insert_before(PresetFile &pf, const Glib::ustring &src, PresetFile &pftgt, const Glib::ustring &pos, const Glib::ustring &name)
JsonWriter * create_writer_at(const Glib::ustring &pos, const Glib::ustring &name)
GxSettingsBase(gx_engine::EngineControl &seq_)
static void make_valid_utf8(Glib::ustring &s)
bool create_file(const Glib::ustring &name, const std::string &path, int tp, int flags)
bool loadsetting(PresetFile *p, const Glib::ustring &name)
void writeJSON(JsonWriter &jw)
bool rename_bank(const Glib::ustring &oldname, const Glib::ustring &newname, const std::string &newfile)
double current_value_double()
void end_object(bool nl=false)
void save_to_state(bool preserve_preset=false)
void reorder_preset(PresetFile &pf, const std::vector< Glib::ustring > &neworder)
bool remove(const Glib::ustring &bank)
void erase_preset(const Glib::ustring &name)
void write_lit(const string &s, bool nl=false)
std::string encode_filename(const std::string &s)