config_file.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750
  1. /*************************************************************************/
  2. /* config_file.cpp */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* http://www.godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
  9. /* */
  10. /* Permission is hereby granted, free of charge, to any person obtaining */
  11. /* a copy of this software and associated documentation files (the */
  12. /* "Software"), to deal in the Software without restriction, including */
  13. /* without limitation the rights to use, copy, modify, merge, publish, */
  14. /* distribute, sublicense, and/or sell copies of the Software, and to */
  15. /* permit persons to whom the Software is furnished to do so, subject to */
  16. /* the following conditions: */
  17. /* */
  18. /* The above copyright notice and this permission notice shall be */
  19. /* included in all copies or substantial portions of the Software. */
  20. /* */
  21. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  22. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  23. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
  24. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  25. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  26. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  27. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  28. /*************************************************************************/
  29. #include "config_file.h"
  30. #include "os/keyboard.h"
  31. #include "os/file_access.h"
  32. StringArray ConfigFile::_get_sections() const {
  33. List<String> s;
  34. get_sections(&s);
  35. StringArray arr;
  36. arr.resize(s.size());
  37. int idx=0;
  38. for(const List<String>::Element *E=s.front();E;E=E->next()) {
  39. arr.set(idx++,E->get());
  40. }
  41. return arr;
  42. }
  43. StringArray ConfigFile::_get_section_keys(const String& p_section) const{
  44. List<String> s;
  45. get_section_keys(p_section,&s);
  46. StringArray arr;
  47. arr.resize(s.size());
  48. int idx=0;
  49. for(const List<String>::Element *E=s.front();E;E=E->next()) {
  50. arr.set(idx++,E->get());
  51. }
  52. return arr;
  53. }
  54. void ConfigFile::set_value(const String& p_section, const String& p_key, const Variant& p_value){
  55. if (p_value.get_type()==Variant::NIL) {
  56. //erase
  57. if (!values.has(p_section))
  58. return; // ?
  59. values[p_section].erase(p_key);
  60. if (values[p_section].empty()) {
  61. values.erase(p_section);
  62. }
  63. } else {
  64. if (!values.has(p_section)) {
  65. values[p_section]=Map<String, Variant>();
  66. }
  67. values[p_section][p_key]=p_value;
  68. }
  69. }
  70. Variant ConfigFile::get_value(const String& p_section, const String& p_key) const{
  71. ERR_FAIL_COND_V(!values.has(p_section),Variant());
  72. ERR_FAIL_COND_V(!values[p_section].has(p_key),Variant());
  73. return values[p_section][p_key];
  74. }
  75. bool ConfigFile::has_section(const String& p_section) const {
  76. return values.has(p_section);
  77. }
  78. bool ConfigFile::has_section_key(const String& p_section,const String& p_key) const {
  79. if (!values.has(p_section))
  80. return false;
  81. return values[p_section].has(p_key);
  82. }
  83. void ConfigFile::get_sections(List<String> *r_sections) const{
  84. for(const Map< String, Map<String, Variant> >::Element *E=values.front();E;E=E->next()) {
  85. r_sections->push_back(E->key());
  86. }
  87. }
  88. void ConfigFile::get_section_keys(const String& p_section,List<String> *r_keys) const{
  89. ERR_FAIL_COND(!values.has(p_section));
  90. for(const Map<String, Variant> ::Element *E=values[p_section].front();E;E=E->next()) {
  91. r_keys->push_back(E->key());
  92. }
  93. }
  94. static String _encode_variant(const Variant& p_variant) {
  95. switch(p_variant.get_type()) {
  96. case Variant::BOOL: {
  97. bool val = p_variant;
  98. return (val?"true":"false");
  99. } break;
  100. case Variant::INT: {
  101. int val = p_variant;
  102. return itos(val);
  103. } break;
  104. case Variant::REAL: {
  105. float val = p_variant;
  106. return rtos(val)+(val==int(val)?".0":"");
  107. } break;
  108. case Variant::STRING: {
  109. String val = p_variant;
  110. return "\""+val.xml_escape()+"\"";
  111. } break;
  112. case Variant::COLOR: {
  113. Color val = p_variant;
  114. return "#"+val.to_html();
  115. } break;
  116. case Variant::STRING_ARRAY:
  117. case Variant::INT_ARRAY:
  118. case Variant::REAL_ARRAY:
  119. case Variant::ARRAY: {
  120. Array arr = p_variant;
  121. String str="[";
  122. for(int i=0;i<arr.size();i++) {
  123. if (i>0)
  124. str+=", ";
  125. str+=_encode_variant(arr[i]);
  126. }
  127. str+="]";
  128. return str;
  129. } break;
  130. case Variant::DICTIONARY: {
  131. Dictionary d = p_variant;
  132. String str="{";
  133. List<Variant> keys;
  134. d.get_key_list(&keys);
  135. for(List<Variant>::Element *E=keys.front();E;E=E->next()) {
  136. if (E!=keys.front())
  137. str+=", ";
  138. str+=_encode_variant(E->get());
  139. str+=":";
  140. str+=_encode_variant(d[E->get()]);
  141. }
  142. str+="}";
  143. return str;
  144. } break;
  145. case Variant::IMAGE: {
  146. String str="img(";
  147. Image img=p_variant;
  148. if (!img.empty()) {
  149. String format;
  150. switch(img.get_format()) {
  151. case Image::FORMAT_GRAYSCALE: format="grayscale"; break;
  152. case Image::FORMAT_INTENSITY: format="intensity"; break;
  153. case Image::FORMAT_GRAYSCALE_ALPHA: format="grayscale_alpha"; break;
  154. case Image::FORMAT_RGB: format="rgb"; break;
  155. case Image::FORMAT_RGBA: format="rgba"; break;
  156. case Image::FORMAT_INDEXED : format="indexed"; break;
  157. case Image::FORMAT_INDEXED_ALPHA: format="indexed_alpha"; break;
  158. case Image::FORMAT_BC1: format="bc1"; break;
  159. case Image::FORMAT_BC2: format="bc2"; break;
  160. case Image::FORMAT_BC3: format="bc3"; break;
  161. case Image::FORMAT_BC4: format="bc4"; break;
  162. case Image::FORMAT_BC5: format="bc5"; break;
  163. case Image::FORMAT_CUSTOM: format="custom custom_size="+itos(img.get_data().size())+""; break;
  164. default: {}
  165. }
  166. str+=format+", ";
  167. str+=itos(img.get_mipmaps())+", ";
  168. str+=itos(img.get_width())+", ";
  169. str+=itos(img.get_height())+", ";
  170. DVector<uint8_t> data = img.get_data();
  171. int ds=data.size();
  172. DVector<uint8_t>::Read r = data.read();
  173. for(int i=0;i<ds;i++) {
  174. uint8_t byte = r[i];
  175. const char hex[16]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
  176. char bstr[3]={ hex[byte>>4], hex[byte&0xF], 0};
  177. str+=bstr;
  178. }
  179. }
  180. str+=")";
  181. return str;
  182. } break;
  183. case Variant::INPUT_EVENT: {
  184. InputEvent ev = p_variant;
  185. switch(ev.type) {
  186. case InputEvent::KEY: {
  187. String mods;
  188. if (ev.key.mod.control)
  189. mods+="C";
  190. if (ev.key.mod.shift)
  191. mods+="S";
  192. if (ev.key.mod.alt)
  193. mods+="A";
  194. if (ev.key.mod.meta)
  195. mods+="M";
  196. if (mods!="")
  197. mods=", "+mods;
  198. return "key("+keycode_get_string(ev.key.scancode)+mods+")";
  199. } break;
  200. case InputEvent::MOUSE_BUTTON: {
  201. return "mbutton("+itos(ev.device)+", "+itos(ev.mouse_button.button_index)+")";
  202. } break;
  203. case InputEvent::JOYSTICK_BUTTON: {
  204. return "jbutton("+itos(ev.device)+", "+itos(ev.joy_button.button_index)+")";
  205. } break;
  206. case InputEvent::JOYSTICK_MOTION: {
  207. return "jaxis("+itos(ev.device)+", "+itos(ev.joy_motion.axis)+")";
  208. } break;
  209. default: {
  210. return "nil";
  211. } break;
  212. }
  213. } break;
  214. default: {}
  215. }
  216. return "nil"; //don't know wha to do with this
  217. }
  218. Error ConfigFile::save(const String& p_path){
  219. Error err;
  220. FileAccess *file = FileAccess::open(p_path,FileAccess::WRITE,&err);
  221. if (err) {
  222. return err;
  223. }
  224. for(Map< String, Map<String, Variant> >::Element *E=values.front();E;E=E->next()) {
  225. if (E!=values.front())
  226. file->store_string("\n");
  227. file->store_string("["+E->key()+"]\n\n");
  228. for(Map<String, Variant>::Element *F=E->get().front();F;F=F->next()) {
  229. file->store_string(F->key()+"="+_encode_variant(F->get())+"\n");
  230. }
  231. }
  232. memdelete(file);
  233. return OK;
  234. }
  235. static Vector<String> _decode_params(const String& p_string) {
  236. int begin=p_string.find("(");
  237. ERR_FAIL_COND_V(begin==-1,Vector<String>());
  238. begin++;
  239. int end=p_string.find(")");
  240. ERR_FAIL_COND_V(end<begin,Vector<String>());
  241. return p_string.substr(begin,end-begin).split(",");
  242. }
  243. static String _get_chunk(const String& str,int &pos, int close_pos) {
  244. enum {
  245. MIN_COMMA,
  246. MIN_COLON,
  247. MIN_CLOSE,
  248. MIN_QUOTE,
  249. MIN_PARENTHESIS,
  250. MIN_CURLY_OPEN,
  251. MIN_OPEN
  252. };
  253. int min_pos=close_pos;
  254. int min_what=MIN_CLOSE;
  255. #define TEST_MIN(m_how,m_what) \
  256. {\
  257. int res = str.find(m_how,pos);\
  258. if (res!=-1 && res < min_pos) {\
  259. min_pos=res;\
  260. min_what=m_what;\
  261. }\
  262. }\
  263. TEST_MIN(",",MIN_COMMA);
  264. TEST_MIN("[",MIN_OPEN);
  265. TEST_MIN("{",MIN_CURLY_OPEN);
  266. TEST_MIN("(",MIN_PARENTHESIS);
  267. TEST_MIN("\"",MIN_QUOTE);
  268. int end=min_pos;
  269. switch(min_what) {
  270. case MIN_COMMA: {
  271. } break;
  272. case MIN_CLOSE: {
  273. //end because it's done
  274. } break;
  275. case MIN_QUOTE: {
  276. end=str.find("\"",min_pos+1)+1;
  277. ERR_FAIL_COND_V(end==-1,Variant());
  278. } break;
  279. case MIN_PARENTHESIS: {
  280. end=str.find(")",min_pos+1)+1;
  281. ERR_FAIL_COND_V(end==-1,Variant());
  282. } break;
  283. case MIN_OPEN: {
  284. int level=1;
  285. end++;
  286. while(end<close_pos) {
  287. if (str[end]=='[')
  288. level++;
  289. if (str[end]==']') {
  290. level--;
  291. if (level==0)
  292. break;
  293. }
  294. end++;
  295. }
  296. ERR_FAIL_COND_V(level!=0,Variant());
  297. end++;
  298. } break;
  299. case MIN_CURLY_OPEN: {
  300. int level=1;
  301. end++;
  302. while(end<close_pos) {
  303. if (str[end]=='{')
  304. level++;
  305. if (str[end]=='}') {
  306. level--;
  307. if (level==0)
  308. break;
  309. }
  310. end++;
  311. }
  312. ERR_FAIL_COND_V(level!=0,Variant());
  313. end++;
  314. } break;
  315. }
  316. String ret = str.substr(pos,end-pos);
  317. pos=end;
  318. while(pos<close_pos) {
  319. if (str[pos]!=',' && str[pos]!=' ' && str[pos]!=':')
  320. break;
  321. pos++;
  322. }
  323. return ret;
  324. }
  325. static Variant _decode_variant(const String& p_string) {
  326. String str = p_string.strip_edges();
  327. if (str.nocasecmp_to("true")==0)
  328. return Variant(true);
  329. if (str.nocasecmp_to("false")==0)
  330. return Variant(false);
  331. if (str.nocasecmp_to("nil")==0)
  332. return Variant();
  333. if (str.is_valid_float()) {
  334. if (str.find(".")==-1)
  335. return str.to_int();
  336. else
  337. return str.to_double();
  338. }
  339. if (str.begins_with("#")) { //string
  340. return Color::html(str);
  341. }
  342. if (str.begins_with("\"")) { //string
  343. int end = str.find_last("\"");
  344. ERR_FAIL_COND_V(end==0,Variant());
  345. return str.substr(1,end-1).xml_unescape();
  346. }
  347. if (str.begins_with("[")) { //array
  348. int close_pos = str.find_last("]");
  349. ERR_FAIL_COND_V(close_pos==-1,Variant());
  350. Array array;
  351. int pos=1;
  352. while(pos<close_pos) {
  353. String s = _get_chunk(str,pos,close_pos);
  354. array.push_back(_decode_variant(s));
  355. }
  356. return array;
  357. }
  358. if (str.begins_with("{")) { //array
  359. int close_pos = str.find_last("}");
  360. ERR_FAIL_COND_V(close_pos==-1,Variant());
  361. Dictionary d;
  362. int pos=1;
  363. while(pos<close_pos) {
  364. String key = _get_chunk(str,pos,close_pos);
  365. String data = _get_chunk(str,pos,close_pos);
  366. d[_decode_variant(key)]=_decode_variant(data);
  367. }
  368. return d;
  369. }
  370. if (str.begins_with("key")) {
  371. Vector<String> params = _decode_params(p_string);
  372. ERR_FAIL_COND_V(params.size()!=1 && params.size()!=2,Variant());
  373. int scode=0;
  374. if (params[0].is_numeric()) {
  375. scode=params[0].to_int();
  376. if (scode < 10) {
  377. scode=KEY_0+scode;
  378. }
  379. } else
  380. scode=find_keycode(params[0]);
  381. InputEvent ie;
  382. ie.type=InputEvent::KEY;
  383. ie.key.scancode=scode;
  384. if (params.size()==2) {
  385. String mods=params[1];
  386. if (mods.findn("C")!=-1)
  387. ie.key.mod.control=true;
  388. if (mods.findn("A")!=-1)
  389. ie.key.mod.alt=true;
  390. if (mods.findn("S")!=-1)
  391. ie.key.mod.shift=true;
  392. if (mods.findn("M")!=-1)
  393. ie.key.mod.meta=true;
  394. }
  395. return ie;
  396. }
  397. if (str.begins_with("mbutton")) {
  398. Vector<String> params = _decode_params(p_string);
  399. ERR_FAIL_COND_V(params.size()!=2,Variant());
  400. InputEvent ie;
  401. ie.type=InputEvent::MOUSE_BUTTON;
  402. ie.device=params[0].to_int();
  403. ie.mouse_button.button_index=params[1].to_int();
  404. return ie;
  405. }
  406. if (str.begins_with("jbutton")) {
  407. Vector<String> params = _decode_params(p_string);
  408. ERR_FAIL_COND_V(params.size()!=2,Variant());
  409. InputEvent ie;
  410. ie.type=InputEvent::JOYSTICK_BUTTON;
  411. ie.device=params[0].to_int();
  412. ie.joy_button.button_index=params[1].to_int();
  413. return ie;
  414. }
  415. if (str.begins_with("jaxis")) {
  416. Vector<String> params = _decode_params(p_string);
  417. ERR_FAIL_COND_V(params.size()!=2,Variant());
  418. InputEvent ie;
  419. ie.type=InputEvent::JOYSTICK_MOTION;
  420. ie.device=params[0].to_int();
  421. ie.joy_motion.axis=params[1].to_int();
  422. return ie;
  423. }
  424. if (str.begins_with("img")) {
  425. Vector<String> params = _decode_params(p_string);
  426. if (params.size()==0) {
  427. return Image();
  428. }
  429. ERR_FAIL_COND_V(params.size()!=5,Image());
  430. String format=params[0].strip_edges();
  431. Image::Format imgformat;
  432. if (format=="grayscale") {
  433. imgformat=Image::FORMAT_GRAYSCALE;
  434. } else if (format=="intensity") {
  435. imgformat=Image::FORMAT_INTENSITY;
  436. } else if (format=="grayscale_alpha") {
  437. imgformat=Image::FORMAT_GRAYSCALE_ALPHA;
  438. } else if (format=="rgb") {
  439. imgformat=Image::FORMAT_RGB;
  440. } else if (format=="rgba") {
  441. imgformat=Image::FORMAT_RGBA;
  442. } else if (format=="indexed") {
  443. imgformat=Image::FORMAT_INDEXED;
  444. } else if (format=="indexed_alpha") {
  445. imgformat=Image::FORMAT_INDEXED_ALPHA;
  446. } else if (format=="bc1") {
  447. imgformat=Image::FORMAT_BC1;
  448. } else if (format=="bc2") {
  449. imgformat=Image::FORMAT_BC2;
  450. } else if (format=="bc3") {
  451. imgformat=Image::FORMAT_BC3;
  452. } else if (format=="bc4") {
  453. imgformat=Image::FORMAT_BC4;
  454. } else if (format=="bc5") {
  455. imgformat=Image::FORMAT_BC5;
  456. } else if (format=="custom") {
  457. imgformat=Image::FORMAT_CUSTOM;
  458. } else {
  459. ERR_FAIL_V( Image() );
  460. }
  461. int mipmaps=params[1].to_int();
  462. int w=params[2].to_int();
  463. int h=params[3].to_int();
  464. if (w == 0 && h == 0) {
  465. //r_v = Image(w, h, imgformat);
  466. return Image();
  467. };
  468. String data=params[4];
  469. int datasize=data.length()/2;
  470. DVector<uint8_t> pixels;
  471. pixels.resize(datasize);
  472. DVector<uint8_t>::Write wb = pixels.write();
  473. const CharType *cptr=data.c_str();
  474. int idx=0;
  475. uint8_t byte;
  476. while( idx<datasize*2) {
  477. CharType c=*(cptr++);
  478. ERR_FAIL_COND_V(c=='<',ERR_FILE_CORRUPT);
  479. if ( (c>='0' && c<='9') || (c>='A' && c<='F') || (c>='a' && c<='f') ) {
  480. if (idx&1) {
  481. byte|=HEX2CHR(c);
  482. wb[idx>>1]=byte;
  483. } else {
  484. byte=HEX2CHR(c)<<4;
  485. }
  486. idx++;
  487. }
  488. }
  489. wb = DVector<uint8_t>::Write();
  490. return Image(w,h,mipmaps,imgformat,pixels);
  491. }
  492. if (str.find(",")!=-1) { //vector2 or vector3
  493. Vector<float> farr = str.split_floats(",",true);
  494. if (farr.size()==2) {
  495. return Point2(farr[0],farr[1]);
  496. }
  497. if (farr.size()==3) {
  498. return Vector3(farr[0],farr[1],farr[2]);
  499. }
  500. ERR_FAIL_V(Variant());
  501. }
  502. return Variant();
  503. }
  504. Error ConfigFile::load(const String& p_path) {
  505. Error err;
  506. FileAccess *f= FileAccess::open(p_path,FileAccess::READ,&err);
  507. if (err!=OK) {
  508. return err;
  509. }
  510. String line;
  511. String section;
  512. String subpath;
  513. int line_count = 0;
  514. while(!f->eof_reached()) {
  515. String line = f->get_line().strip_edges();
  516. line_count++;
  517. if (line=="")
  518. continue;
  519. // find comments
  520. {
  521. int pos=0;
  522. while (true) {
  523. int ret = line.find(";",pos);
  524. if (ret==-1)
  525. break;
  526. int qc=0;
  527. for(int i=0;i<ret;i++) {
  528. if (line[i]=='"')
  529. qc++;
  530. }
  531. if ( !(qc&1) ) {
  532. //not inside string, real comment
  533. line=line.substr(0,ret);
  534. break;
  535. }
  536. pos=ret+1;
  537. }
  538. }
  539. if (line.begins_with("[")) {
  540. int end = line.find_last("]");
  541. ERR_CONTINUE(end!=line.length()-1);
  542. section=line.substr(1,line.length()-2);
  543. } else if (line.find("=")!=-1) {
  544. int eqpos = line.find("=");
  545. String var=line.substr(0,eqpos).strip_edges();
  546. String value=line.substr(eqpos+1,line.length()).strip_edges();
  547. Variant val = _decode_variant(value);
  548. set_value(section,var,val);
  549. } else {
  550. if (line.length() > 0) {
  551. ERR_PRINT(String("Syntax error on line "+itos(line_count)+" of file "+p_path).ascii().get_data());
  552. };
  553. };
  554. }
  555. memdelete(f);
  556. return OK;
  557. }
  558. void ConfigFile::_bind_methods(){
  559. ObjectTypeDB::bind_method(_MD("set_value","section","key","value"),&ConfigFile::set_value);
  560. ObjectTypeDB::bind_method(_MD("get_value","section","key"),&ConfigFile::get_value);
  561. ObjectTypeDB::bind_method(_MD("has_section","section"),&ConfigFile::has_section);
  562. ObjectTypeDB::bind_method(_MD("has_section_key","section","key"),&ConfigFile::has_section_key);
  563. ObjectTypeDB::bind_method(_MD("get_sections"),&ConfigFile::_get_sections);
  564. ObjectTypeDB::bind_method(_MD("get_section_keys"),&ConfigFile::_get_section_keys);
  565. ObjectTypeDB::bind_method(_MD("load:Error","path"),&ConfigFile::load);
  566. ObjectTypeDB::bind_method(_MD("save:Error","path"),&ConfigFile::save);
  567. }
  568. ConfigFile::ConfigFile()
  569. {
  570. }