Clone of Bael'Zharon's Respite @ https://github.com/boardwalk/bzr

Config.cpp 4.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. /*
  2. * Bael'Zharon's Respite
  3. * Copyright (C) 2014 Daniel Skorupski
  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. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License along
  15. * with this program; if not, write to the Free Software Foundation, Inc.,
  16. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  17. */
  18. #include "Config.h"
  19. #include <jansson.h>
  20. #include <sstream>
  21. static vector<string> splitName(const string& name)
  22. {
  23. vector<string> nameParts;
  24. size_t tokenBegin = 0;
  25. for(;;)
  26. {
  27. size_t tokenEnd = name.find('.', tokenBegin);
  28. if(tokenEnd == string::npos)
  29. {
  30. break;
  31. }
  32. nameParts.push_back(name.substr(tokenBegin, tokenEnd - tokenBegin));
  33. tokenBegin = tokenEnd + 1;
  34. }
  35. nameParts.push_back(name.substr(tokenBegin));
  36. return nameParts;
  37. }
  38. Config::Config()
  39. {
  40. char* prefPath = SDL_GetPrefPath("boardwalk", "Bael'Zharon's Revenge");
  41. path_ = string(prefPath) + "config.json";
  42. SDL_free(prefPath);
  43. FILE* fp = fopen(path_.c_str(), "r");
  44. if(fp != nullptr)
  45. {
  46. json_error_t err;
  47. root_ = json_loadf(fp, 0, &err);
  48. fclose(fp);
  49. if(root_ == nullptr)
  50. {
  51. stringstream errStream;
  52. errStream << "Configuration parsing error on line " << err.line << ", column " << err.column << ": " << err.text;
  53. throw runtime_error(errStream.str());
  54. }
  55. if(!json_is_object(root_))
  56. {
  57. throw runtime_error("Configuration must be an object");
  58. }
  59. }
  60. else
  61. {
  62. root_ = json_object();
  63. }
  64. }
  65. Config::~Config()
  66. {
  67. json_dump_file(root_, path_.c_str(), JSON_INDENT(2) | JSON_SORT_KEYS);
  68. json_decref(root_);
  69. }
  70. void Config::setBool(const char* name, bool value)
  71. {
  72. set(name, json_boolean(value));
  73. }
  74. void Config::setInt(const char* name, int value)
  75. {
  76. set(name, json_integer(value));
  77. }
  78. void Config::setFloat(const char* name, fp_t value)
  79. {
  80. set(name, json_real(value));
  81. }
  82. void Config::setString(const char* name, const string& value)
  83. {
  84. set(name, json_string(value.c_str()));
  85. }
  86. bool Config::getBool(const char* name, bool defaultValue)
  87. {
  88. json_t* value = get(name);
  89. if(json_is_boolean(value))
  90. {
  91. return json_is_true(value);
  92. }
  93. else
  94. {
  95. setBool(name, defaultValue);
  96. return defaultValue;
  97. }
  98. }
  99. int Config::getInt(const char* name, int defaultValue)
  100. {
  101. json_t* value = get(name);
  102. if(json_is_integer(value))
  103. {
  104. return static_cast<int>(json_integer_value(value));
  105. }
  106. else
  107. {
  108. setInt(name, defaultValue);
  109. return defaultValue;
  110. }
  111. }
  112. fp_t Config::getFloat(const char* name, fp_t defaultValue)
  113. {
  114. json_t* value = get(name);
  115. if(json_is_real(value))
  116. {
  117. return static_cast<fp_t>(json_real_value(value));
  118. }
  119. else
  120. {
  121. setFloat(name, defaultValue);
  122. return defaultValue;
  123. }
  124. }
  125. string Config::getString(const char* name, const string& defaultValue)
  126. {
  127. json_t* value = get(name);
  128. if(json_is_string(value))
  129. {
  130. return json_string_value(value);
  131. }
  132. else
  133. {
  134. setString(name, defaultValue);
  135. return defaultValue;
  136. }
  137. }
  138. void Config::erase(const char* name)
  139. {
  140. vector<string> nameParts = splitName(name);
  141. string lastPart = nameParts.back();
  142. nameParts.pop_back();
  143. json_t* node = root_;
  144. for(string& part : nameParts)
  145. {
  146. json_t* childNode = json_object_get(node, part.c_str());
  147. if(!json_is_object(childNode))
  148. {
  149. return;
  150. }
  151. node = childNode;
  152. }
  153. json_object_del(node, lastPart.c_str());
  154. }
  155. void Config::set(const char* name, json_t* value)
  156. {
  157. vector<string> nameParts = splitName(name);
  158. string lastPart = nameParts.back();
  159. nameParts.pop_back();
  160. json_t* node = root_;
  161. for(string& part : nameParts)
  162. {
  163. json_t* childNode = json_object_get(node, part.c_str());
  164. if(!json_is_object(childNode))
  165. {
  166. childNode = json_object();
  167. json_object_set_new(node, part.c_str(), childNode);
  168. }
  169. node = childNode;
  170. }
  171. json_object_set_new(node, lastPart.c_str(), value);
  172. }
  173. json_t* Config::get(const char* name) const
  174. {
  175. vector<string> nameParts = splitName(name);
  176. json_t* node = root_;
  177. for(string& part : nameParts)
  178. {
  179. if(!json_is_object(node))
  180. {
  181. return nullptr;
  182. }
  183. node = json_object_get(node, part.c_str());
  184. }
  185. return node;
  186. }