diff options
author | Juan Linietsky <reduzio@gmail.com> | 2014-02-09 22:10:30 -0300 |
---|---|---|
committer | Juan Linietsky <reduzio@gmail.com> | 2014-02-09 22:10:30 -0300 |
commit | 0b806ee0fc9097fa7bda7ac0109191c9c5e0a1ac (patch) | |
tree | 276c4d099e178eb67fbd14f61d77b05e3808e9e3 /core/io/config_file.cpp | |
parent | 0e49da1687bc8192ed210947da52c9e5c5f301bb (diff) | |
download | redot-engine-0b806ee0fc9097fa7bda7ac0109191c9c5e0a1ac.tar.gz |
GODOT IS OPEN SOURCE
Diffstat (limited to 'core/io/config_file.cpp')
-rw-r--r-- | core/io/config_file.cpp | 744 |
1 files changed, 744 insertions, 0 deletions
diff --git a/core/io/config_file.cpp b/core/io/config_file.cpp new file mode 100644 index 0000000000..45e8cf69ab --- /dev/null +++ b/core/io/config_file.cpp @@ -0,0 +1,744 @@ +/*************************************************************************/ +/* config_file.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#include "config_file.h" +#include "os/keyboard.h" +#include "os/file_access.h" + +StringArray ConfigFile::_get_sections() const { + + List<String> s; + get_sections(&s); + StringArray arr; + arr.resize(s.size()); + int idx=0; + for(const List<String>::Element *E=s.front();E;E=E->next()) { + + arr.set(idx++,E->get()); + } + + return arr; +} + +StringArray ConfigFile::_get_section_keys(const String& p_section) const{ + + List<String> s; + get_section_keys(p_section,&s); + StringArray arr; + arr.resize(s.size()); + int idx=0; + for(const List<String>::Element *E=s.front();E;E=E->next()) { + + arr.set(idx++,E->get()); + } + + return arr; + +} + + +void ConfigFile::set_value(const String& p_section, const String& p_key, const Variant& p_value){ + + if (p_value.get_type()==Variant::NIL) { + //erase + if (!values.has(p_section)) + return; // ? + values[p_section].erase(p_key); + if (values[p_section].empty()) { + values.erase(p_section); + } + + } else { + if (!values.has(p_section)) { + values[p_section]=Map<String, Variant>(); + } + + values[p_section][p_key]=p_value; + + } + +} +Variant ConfigFile::get_value(const String& p_section, const String& p_key) const{ + + ERR_FAIL_COND_V(!values.has(p_section),Variant()); + ERR_FAIL_COND_V(!values[p_section].has(p_key),Variant()); + return values[p_section][p_key]; + +} + +bool ConfigFile::has_section(const String& p_section) const { + + return values.has(p_section); +} +bool ConfigFile::has_section_key(const String& p_section,const String& p_key) const { + + if (!values.has(p_section)) + return false; + return values[p_section].has(p_key); +} + +void ConfigFile::get_sections(List<String> *r_sections) const{ + + for(const Map< String, Map<String, Variant> >::Element *E=values.front();E;E=E->next()) { + r_sections->push_back(E->key()); + } +} +void ConfigFile::get_section_keys(const String& p_section,List<String> *r_keys) const{ + + ERR_FAIL_COND(!values.has(p_section)); + + for(const Map<String, Variant> ::Element *E=values[p_section].front();E;E=E->next()) { + r_keys->push_back(E->key()); + } + +} + +static String _encode_variant(const Variant& p_variant) { + + switch(p_variant.get_type()) { + + case Variant::BOOL: { + bool val = p_variant; + return (val?"true":"false"); + } break; + case Variant::INT: { + int val = p_variant; + return itos(val); + } break; + case Variant::REAL: { + float val = p_variant; + return rtos(val)+(val==int(val)?".0":""); + } break; + case Variant::STRING: { + String val = p_variant; + return "\""+val.xml_escape()+"\""; + } break; + case Variant::COLOR: { + + Color val = p_variant; + return "#"+val.to_html(); + } break; + case Variant::STRING_ARRAY: + case Variant::INT_ARRAY: + case Variant::REAL_ARRAY: + case Variant::ARRAY: { + Array arr = p_variant; + String str="["; + for(int i=0;i<arr.size();i++) { + + if (i>0) + str+=", "; + str+=_encode_variant(arr[i]); + } + str+="]"; + return str; + } break; + case Variant::DICTIONARY: { + Dictionary d = p_variant; + String str="{"; + List<Variant> keys; + d.get_key_list(&keys); + for(List<Variant>::Element *E=keys.front();E;E=E->next()) { + + if (E!=keys.front()) + str+=", "; + str+=_encode_variant(E->get()); + str+=":"; + str+=_encode_variant(d[E->get()]); + + } + str+="}"; + return str; + } break; + case Variant::IMAGE: { + String str="img("; + + Image img=p_variant; + if (!img.empty()) { + + String format; + switch(img.get_format()) { + + case Image::FORMAT_GRAYSCALE: format="grayscale"; break; + case Image::FORMAT_INTENSITY: format="intensity"; break; + case Image::FORMAT_GRAYSCALE_ALPHA: format="grayscale_alpha"; break; + case Image::FORMAT_RGB: format="rgb"; break; + case Image::FORMAT_RGBA: format="rgba"; break; + case Image::FORMAT_INDEXED : format="indexed"; break; + case Image::FORMAT_INDEXED_ALPHA: format="indexed_alpha"; break; + case Image::FORMAT_BC1: format="bc1"; break; + case Image::FORMAT_BC2: format="bc2"; break; + case Image::FORMAT_BC3: format="bc3"; break; + case Image::FORMAT_BC4: format="bc4"; break; + case Image::FORMAT_BC5: format="bc5"; break; + case Image::FORMAT_CUSTOM: format="custom custom_size="+itos(img.get_data().size())+""; break; + default: {} + } + + str+=format+", "; + str+=itos(img.get_mipmaps())+", "; + str+=itos(img.get_width())+", "; + str+=itos(img.get_height())+", "; + DVector<uint8_t> data = img.get_data(); + int ds=data.size(); + DVector<uint8_t>::Read r = data.read(); + for(int i=0;i<ds;i++) { + uint8_t byte = r[i]; + const char hex[16]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; + char bstr[3]={ hex[byte>>4], hex[byte&0xF], 0}; + str+=bstr; + } + } + str+=")"; + return str; + } break; + case Variant::INPUT_EVENT: { + + InputEvent ev = p_variant; + + switch(ev.type) { + + case InputEvent::KEY: { + + String mods; + if (ev.key.mod.control) + mods+="C"; + if (ev.key.mod.shift) + mods+="S"; + if (ev.key.mod.alt) + mods+="A"; + if (ev.key.mod.meta) + mods+="M"; + if (mods!="") + mods=", "+mods; + + return "key("+keycode_get_string(ev.key.scancode)+mods+")"; + } break; + case InputEvent::MOUSE_BUTTON: { + + return "mbutton("+itos(ev.device)+", "+itos(ev.mouse_button.button_index)+")"; + } break; + case InputEvent::JOYSTICK_BUTTON: { + + return "jbutton("+itos(ev.device)+", "+itos(ev.joy_button.button_index)+")"; + } break; + case InputEvent::JOYSTICK_MOTION: { + + return "jaxis("+itos(ev.device)+", "+itos(ev.joy_motion.axis)+")"; + } break; + default: { + + return "nil"; + } break; + + } + } break; + default: {} + } + + return "nil"; //don't know wha to do with this +} + + +Error ConfigFile::save(const String& p_path){ + + Error err; + FileAccess *file = FileAccess::open(p_path,FileAccess::WRITE,&err); + + if (err) { + return err; + } + + + for(Map< String, Map<String, Variant> >::Element *E=values.front();E;E=E->next()) { + + if (E!=values.front()) + file->store_string("\n"); + file->store_string("["+E->key()+"]\n\n"); + + for(Map<String, Variant>::Element *F=E->get().front();F;F=F->next()) { + + file->store_string(F->key()+"="+_encode_variant(F->get())+"\n"); + } + } + + memdelete(file); + + return OK; +} + +static Vector<String> _decode_params(const String& p_string) { + + int begin=p_string.find("("); + ERR_FAIL_COND_V(begin==-1,Vector<String>()); + begin++; + int end=p_string.find(")"); + ERR_FAIL_COND_V(end<begin,Vector<String>()); + return p_string.substr(begin,end-begin).split(","); +} + +static String _get_chunk(const String& str,int &pos, int close_pos) { + + + enum { + MIN_COMMA, + MIN_COLON, + MIN_CLOSE, + MIN_QUOTE, + MIN_PARENTHESIS, + MIN_CURLY_OPEN, + MIN_OPEN + }; + + int min_pos=close_pos; + int min_what=MIN_CLOSE; + +#define TEST_MIN(m_how,m_what) \ +{\ +int res = str.find(m_how,pos);\ +if (res!=-1 && res < min_pos) {\ + min_pos=res;\ + min_what=m_what;\ +}\ +}\ + + + TEST_MIN(",",MIN_COMMA); + TEST_MIN("[",MIN_OPEN); + TEST_MIN("{",MIN_CURLY_OPEN); + TEST_MIN("(",MIN_PARENTHESIS); + TEST_MIN("\"",MIN_QUOTE); + + int end=min_pos; + + + switch(min_what) { + + case MIN_COMMA: { + } break; + case MIN_CLOSE: { + //end because it's done + } break; + case MIN_QUOTE: { + end=str.find("\"",min_pos+1)+1; + ERR_FAIL_COND_V(end==-1,Variant()); + + } break; + case MIN_PARENTHESIS: { + + end=str.find(")",min_pos+1)+1; + ERR_FAIL_COND_V(end==-1,Variant()); + + } break; + case MIN_OPEN: { + int level=1; + while(end<close_pos) { + + if (str[end]=='[') + level++; + if (str[end]==']') { + level--; + if (level==0) + break; + } + end++; + } + ERR_FAIL_COND_V(level!=0,Variant()); + end++; + } break; + case MIN_CURLY_OPEN: { + int level=1; + while(end<close_pos) { + + if (str[end]=='{') + level++; + if (str[end]=='}') { + level--; + if (level==0) + break; + } + end++; + } + ERR_FAIL_COND_V(level!=0,Variant()); + end++; + } break; + + } + + String ret = str.substr(pos,end-pos); + + pos=end; + while(pos<close_pos) { + if (str[pos]!=',' && str[pos]!=' ' && str[pos]!=':') + break; + pos++; + } + + return ret; + +} + + +static Variant _decode_variant(const String& p_string) { + + + String str = p_string.strip_edges(); + + if (str.nocasecmp_to("true")==0) + return Variant(true); + if (str.nocasecmp_to("false")==0) + return Variant(false); + if (str.nocasecmp_to("nil")==0) + return Variant(); + if (str.is_valid_float()) { + if (str.find(".")==-1) + return str.to_int(); + else + return str.to_double(); + + } + if (str.begins_with("#")) { //string + return Color::html(str); + } + if (str.begins_with("\"")) { //string + int end = str.find_last("\""); + ERR_FAIL_COND_V(end==0,Variant()); + return str.substr(1,end-1).xml_unescape(); + + } + + if (str.begins_with("[")) { //array + + int close_pos = str.find_last("]"); + ERR_FAIL_COND_V(close_pos==-1,Variant()); + Array array; + + int pos=1; + + while(pos<close_pos) { + + String s = _get_chunk(str,pos,close_pos); + array.push_back(_decode_variant(s)); + } + return array; + + } + + if (str.begins_with("{")) { //array + + int close_pos = str.find_last("}"); + ERR_FAIL_COND_V(close_pos==-1,Variant()); + Dictionary d; + + int pos=1; + + while(pos<close_pos) { + + String key = _get_chunk(str,pos,close_pos); + String data = _get_chunk(str,pos,close_pos); + d[_decode_variant(key)]=_decode_variant(data); + } + return d; + + } + if (str.begins_with("key")) { + Vector<String> params = _decode_params(p_string); + ERR_FAIL_COND_V(params.size()!=1 && params.size()!=2,Variant()); + int scode=0; + + if (params[0].is_numeric()) + scode=params[0].to_int(); + else + scode=find_keycode(params[0]); + + InputEvent ie; + ie.type=InputEvent::KEY; + ie.key.scancode=scode; + + if (params.size()==2) { + String mods=params[1]; + if (mods.findn("C")!=-1) + ie.key.mod.control=true; + if (mods.findn("A")!=-1) + ie.key.mod.alt=true; + if (mods.findn("S")!=-1) + ie.key.mod.shift=true; + if (mods.findn("M")!=-1) + ie.key.mod.meta=true; + } + return ie; + + } + + if (str.begins_with("mbutton")) { + Vector<String> params = _decode_params(p_string); + ERR_FAIL_COND_V(params.size()!=2,Variant()); + + InputEvent ie; + ie.type=InputEvent::MOUSE_BUTTON; + ie.device=params[0].to_int(); + ie.mouse_button.button_index=params[1].to_int(); + + return ie; + } + + if (str.begins_with("jbutton")) { + Vector<String> params = _decode_params(p_string); + ERR_FAIL_COND_V(params.size()!=2,Variant()); + + InputEvent ie; + ie.type=InputEvent::JOYSTICK_BUTTON; + ie.device=params[0].to_int(); + ie.joy_button.button_index=params[1].to_int(); + + return ie; + } + + if (str.begins_with("jaxis")) { + Vector<String> params = _decode_params(p_string); + ERR_FAIL_COND_V(params.size()!=2,Variant()); + + InputEvent ie; + ie.type=InputEvent::JOYSTICK_MOTION; + ie.device=params[0].to_int(); + ie.joy_motion.axis=params[1].to_int(); + + return ie; + } + if (str.begins_with("img")) { + Vector<String> params = _decode_params(p_string); + if (params.size()==0) { + return Image(); + } + + ERR_FAIL_COND_V(params.size()!=5,Image()); + + String format=params[0].strip_edges(); + + Image::Format imgformat; + + if (format=="grayscale") { + imgformat=Image::FORMAT_GRAYSCALE; + } else if (format=="intensity") { + imgformat=Image::FORMAT_INTENSITY; + } else if (format=="grayscale_alpha") { + imgformat=Image::FORMAT_GRAYSCALE_ALPHA; + } else if (format=="rgb") { + imgformat=Image::FORMAT_RGB; + } else if (format=="rgba") { + imgformat=Image::FORMAT_RGBA; + } else if (format=="indexed") { + imgformat=Image::FORMAT_INDEXED; + } else if (format=="indexed_alpha") { + imgformat=Image::FORMAT_INDEXED_ALPHA; + } else if (format=="bc1") { + imgformat=Image::FORMAT_BC1; + } else if (format=="bc2") { + imgformat=Image::FORMAT_BC2; + } else if (format=="bc3") { + imgformat=Image::FORMAT_BC3; + } else if (format=="bc4") { + imgformat=Image::FORMAT_BC4; + } else if (format=="bc5") { + imgformat=Image::FORMAT_BC5; + } else if (format=="custom") { + imgformat=Image::FORMAT_CUSTOM; + } else { + + ERR_FAIL_V( Image() ); + } + + int mipmaps=params[1].to_int(); + int w=params[2].to_int(); + int h=params[3].to_int(); + + if (w == 0 && w == 0) { + //r_v = Image(w, h, imgformat); + return Image(); + }; + + + String data=params[4]; + int datasize=data.length()/2; + DVector<uint8_t> pixels; + pixels.resize(datasize); + DVector<uint8_t>::Write wb = pixels.write(); + const CharType *cptr=data.c_str(); + + int idx=0; + uint8_t byte; + while( idx<datasize*2) { + + CharType c=*(cptr++); + + ERR_FAIL_COND_V(c=='<',ERR_FILE_CORRUPT); + + if ( (c>='0' && c<='9') || (c>='A' && c<='F') || (c>='a' && c<='f') ) { + + if (idx&1) { + + byte|=HEX2CHR(c); + wb[idx>>1]=byte; + } else { + + byte=HEX2CHR(c)<<4; + } + + idx++; + } + + } + + wb = DVector<uint8_t>::Write(); + + return Image(w,h,mipmaps,imgformat,pixels); + } + + if (str.find(",")!=-1) { //vector2 or vector3 + Vector<float> farr = str.split_floats(",",true); + if (farr.size()==2) { + return Point2(farr[0],farr[1]); + } + if (farr.size()==3) { + return Vector3(farr[0],farr[1],farr[2]); + } + ERR_FAIL_V(Variant()); + } + + + return Variant(); +} + +Error ConfigFile::load(const String& p_path) { + + Error err; + FileAccess *f= FileAccess::open(p_path,FileAccess::READ,&err); + + if (err!=OK) { + + return err; + } + + + String line; + String section; + String subpath; + + int line_count = 0; + + while(!f->eof_reached()) { + + String line = f->get_line().strip_edges(); + line_count++; + + if (line=="") + continue; + + // find comments + + { + + int pos=0; + while (true) { + int ret = line.find(";",pos); + if (ret==-1) + break; + + int qc=0; + for(int i=0;i<ret;i++) { + + if (line[i]=='"') + qc++; + } + + if ( !(qc&1) ) { + //not inside string, real comment + line=line.substr(0,ret); + break; + + } + + pos=ret+1; + + + } + } + + if (line.begins_with("[")) { + + int end = line.find_last("]"); + ERR_CONTINUE(end!=line.length()-1); + + section=line.substr(1,line.length()-2); + + } else if (line.find("=")!=-1) { + + + int eqpos = line.find("="); + String var=line.substr(0,eqpos).strip_edges(); + String value=line.substr(eqpos+1,line.length()).strip_edges(); + + Variant val = _decode_variant(value); + + set_value(section,var,val); + + } else { + + if (line.length() > 0) { + ERR_PRINT(String("Syntax error on line "+itos(line_count)+" of file "+p_path).ascii().get_data()); + }; + }; + } + + memdelete(f); + + return OK; +} + + + +void ConfigFile::_bind_methods(){ + + ObjectTypeDB::bind_method(_MD("set_value","section","key","value"),&ConfigFile::set_value); + ObjectTypeDB::bind_method(_MD("get_value","section","key"),&ConfigFile::get_value); + + ObjectTypeDB::bind_method(_MD("has_section","section"),&ConfigFile::has_section); + ObjectTypeDB::bind_method(_MD("has_section_key","section","key"),&ConfigFile::has_section_key); + + ObjectTypeDB::bind_method(_MD("get_sections"),&ConfigFile::_get_sections); + ObjectTypeDB::bind_method(_MD("get_section_keys"),&ConfigFile::_get_section_keys); + + ObjectTypeDB::bind_method(_MD("load:Error","path"),&ConfigFile::load); + ObjectTypeDB::bind_method(_MD("save:Error","path"),&ConfigFile::save); + +} + + +ConfigFile::ConfigFile() +{ +} |