   C++ JSON tutorial?
  I am making a game with SDL, and I want to add the ability to customize controls. I figured that ideally, it should be a human readable and editable textfile.It should have key value pairs likeLEFTARROW = MOVELEFT, etc.where multiple keys can be assigned to the same function, but each key has only one function.I think JSON sounds like it is a good format, however I am not sure how to implement a parser. I guess I could use Boost Spirit, but a) I don't know how to use spirit, and B) I heard spirit makes compile times really long, something I'd obviously prefer to avoid.I saw some mentions of existing libraries to parse JSON files, but I couldn't find any elaborations or explanations of how to use this. What should I do?   
Check this out [smile]   ;  I'm really confused.What are the template paramters of ptree supposed to be? How do I get it to parse a file?   ;  Json or Boost Property Trees sound like overkill for this. You don't need to support nesting. Spirit is an insanely complex solution.Its pretty trivial to download or implement a simple parser for things like java properties (name = value), which is really all you need for this..   ;  I just realized another problem. Currently, I am using PhysFS for all my file IO, but it appears to support only binary access. Should I switch to a more STD friendly method for reading and writing the configuration files?   ;  That shouldn't be a problem. Once you have the raw file data read in you should be able to parse it quite easily, a simple way would be to wrap it in a stringstream. The only thing that the Standard C++ Library provides that might take a bit of work is handling platform specific end-of-line character sequences.   ;  Did you check the list of C++ JSON parsers at http://www.json.org/? Or better yet, the C++ YAML parsers at http://yaml.org/?   ;  I decided to take Ripoffs advice and not use JSONHere's what I came up with#pragma once#include <string>#include <map>#include "SDL/SDL.h"#include "BOOST/array.hpp"#include "BOOST/function.hpp"namespace Configuration{    class InputEvent    {   int key;   public:   //InputEvent(): key(SDLK_UNKNOWN) {}   InputEvent(int newkey): key(newkey) {}   bool Valid() const {return key != SDLK_UNKNOWN;}   std::string ToString() const;   static InputEvent FromString(const std::string name);   bool operator == (const InputEvent& other) const {return key == other.key;}   bool operator < (const InputEvent& other) const {return key < other.key;}    };    enum ActionEnum {MENU_UP, MENU_DOWN, MENU_SELECT, SCREENSHOT, MOVELEFT, MOVERIGHT, JUMP, SHOOT, SUICIDE, RESTART, PAUSE,   UNSAVE, OPENMENU, TITLESCREEN, MUTE, CHEAT_SAVE, CHEAT_SLOW, CHEAT_FAST, NUMACTIONS};    typedef int action_t;    std::string ToString(action_t a);    action_t FromString(const std::string name);    class ControlMap    {   std::map<InputEvent, action_t> controls;   void AssignInput(InputEvent k, action_t a);   void AssignKey(SDLKey k, ActionEnum ae);   public:   ControlMap();   action_t Input2Action(InputEvent i) const;   void Serialize(std::ostream& sink) const;   void Deserialize(std::istream& source);    };    class InputMapper    {   typedef boost::function<void (bool)> voidFunct_bool;   ControlMap mycontrols;   boost::array<voidFunct_bool, NUMACTIONS> mycallbacks;   bool changed;   public:   InputMapper();   void SetCallback(ActionEnum ae, voidFunct_bool cb);   void KeyEvent(SDLKey k, bool pressed);   void SerializeIfChanged(std::string filename) const;   void Deserialize(std::string filename);    };}#include "controls.h"#include <fstream>#include "BOOST/foreach.hpp"#include "BOOST/algorithm/string.hpp"namespace Configuration{    void ControlMap::AssignInput(InputEvent k, action_t a)    {   assert(k.Valid()); assert(a <= NUMACTIONS);   controls[k] = a;    }    void ControlMap::AssignKey(SDLKey k, ActionEnum ae)    {   if (ae<NUMACTIONS)   {  AssignInput(InputEvent(k), action_t(ae));   }    }    ControlMap::ControlMap()    {   AssignKey(SDLK_UP, MENU_UP);   AssignKey(SDLK_DOWN, MENU_DOWN);   AssignKey(SDLK_RETURN, MENU_SELECT);   AssignKey(SDLK_PRINT, SCREENSHOT);   AssignKey(SDLK_LEFT, MOVELEFT);   AssignKey(SDLK_RIGHT, MOVERIGHT);   AssignKey(SDLK_LSHIFT, JUMP);   AssignKey(SDLK_z, SHOOT);   AssignKey(SDLK_q, SUICIDE);   AssignKey(SDLK_r, RESTART);   AssignKey(SDLK_p, PAUSE);   AssignKey(SDLK_BACKSPACE, UNSAVE);   AssignKey(SDLK_ESCAPE, OPENMENU);   AssignKey(SDLK_F2, TITLESCREEN);   AssignKey(SDLK_F3, MUTE);   AssignKey(SDLK_HOME, CHEAT_SAVE);   AssignKey(SDLK_PAGEUP, CHEAT_FAST);   AssignKey(SDLK_PAGEDOWN, CHEAT_SLOW);    }    action_t ControlMap::Input2Action(InputEvent i) const    {   std::map<InputEvent, action_t>::const_iterator iter = controls.find(i);   if (iter != controls.end())   {  return iter->second;   }   else   {  return NUMACTIONS;   }    }    void ControlMap::Serialize(std::ostream& sink) const    {   typedef std::map<InputEvent, action_t>::value_type cpair;   BOOST_FOREACH(cpair p, controls)   {  sink << p.first.ToString() << " = " << ToString(p.second) << "\n";   }    }    void ControlMap::Deserialize(std::istream& source)    {   controls.clear();   std::string input, equals, action;   while (source >> input >> equals >> action)   {  InputEvent i = InputEvent::FromString(input);  action_t a = FromString(action);  if (!equals.compare("=") && a != NUMACTIONS && i.Valid())  { AssignInput(i,a);  }   }    }    InputMapper::InputMapper(): changed(true) {}    void InputMapper::SetCallback(ActionEnum ae, voidFunct_bool cb)    {   assert(ae<NUMACTIONS && ae>=0); assert(cb);   mycallbacks.at( action_t(ae) ) = cb;    }    void InputMapper::KeyEvent(SDLKey k, bool pressed)    {   action_t a = mycontrols.Input2Action(InputEvent(k));   if (a<NUMACTIONS && mycallbacks.at(a))   {  mycallbacks.at(a)(pressed); //call the cb   }    }    void InputMapper::SerializeIfChanged(std::string filename) const    {   if (changed)   {  std::ofstream mystream(filename.c_str());  if (!mystream.fail())  { mycontrols.Serialize(mystream);  }   }    }    void InputMapper::Deserialize(std::string filename)    {   std::ifstream mystream(filename.c_str());   if (!mystream.fail()) //check if file failed to open   {  mycontrols.Deserialize(mystream);  changed = false; //The controls aren't changed since reading them from the file, so no reason to serialize at the end   }    }    action_t FromString(const std::string name)    {   std::string s = boost::trim_copy( boost::to_upper_copy(name) );   for (action_t a = 0; a < NUMACTIONS; ++a)   {  if (s.compare(ToString(a)) == 0)  { return a;  }   }   return NUMACTIONS; //invalid    }    InputEvent InputEvent::FromString(const std::string name)    {   std::string s = boost::trim_copy( boost::to_upper_copy(name) );   for (int k = SDLK_FIRST; k < SDLK_LAST; ++k)   {  if (s.compare(InputEvent(k).ToString()) == 0)  { return InputEvent(k);  }   }   return InputEvent(SDLK_UNKNOWN);    }    std::string ToString(action_t a)    {   switch (a)   {  case MENU_UP: return "MENU_UP";  case MENU_DOWN: return "MENU_DOWN";  case MENU_SELECT: return "MENU_SELECT";  case SCREENSHOT: return "SCREENSHOT";  case MOVELEFT: return "MOVELEFT";  case MOVERIGHT: return "MOVERIGHT";  case JUMP: return "JUMP";  case SHOOT: return "SHOOT";  case SUICIDE: return "SUICIDE";  case RESTART: return "RESTART";  case PAUSE: return "PAUSE";  case UNSAVE: return "UNSAVE";  case OPENMENU: return "OPENMENU";  case TITLESCREEN: return "TITLESCREEN";  case MUTE: return "MUTE";  case CHEAT_SAVE: return "CHEAT_SAVE";  case CHEAT_SLOW: return "CHEAT_SLOW";  case CHEAT_FAST: return "CHEAT_FAST";  default: return "???";   }    }    std::string InputEvent::ToString() const    {   switch (key)   {  case SDLK_BACKSPACE: return "BACKSPACE";  case SDLK_TAB: return "TAB";  case SDLK_CLEAR: return "CLEAR";  case SDLK_RETURN: return "RETURN";  case SDLK_PAUSE: return "PAUSE";  case SDLK_ESCAPE: return "ESCAPE";  case SDLK_SPACE: return "SPACE";  case SDLK_EXCLAIM: return "EXCLAIM";  case SDLK_QUOTEDBL: return "QUOTEDBL";  case SDLK_HASH: return "HASH";  case SDLK_DOLLAR: return "DOLLAR";  case SDLK_AMPERSAND: return "AMPERSAND";  case SDLK_QUOTE: return "QUOTE";  case SDLK_LEFTPAREN: return "LEFTPAREN";  case SDLK_RIGHTPAREN: return "RIGHTPAREN";  case SDLK_ASTERISK: return "ASTERISK";  case SDLK_PLUS: return "PLUS";  case SDLK_COMMA: return "COMMA";  case SDLK_MINUS: return "MINUS";  case SDLK_PERIOD: return "PERIOD";  case SDLK_SLASH: return "SLASH";  case SDLK_0: return "0";  case SDLK_1: return "1";  case SDLK_2: return "2";  case SDLK_3: return "3";  case SDLK_4: return "4";  case SDLK_5: return "5";  case SDLK_6: return "6";  case SDLK_7: return "7";  case SDLK_8: return "8";  case SDLK_9: return "9";  case SDLK_COLON: return "COLON";  case SDLK_SEMICOLON: return "SEMICOLON";  case SDLK_LESS: return "LESS";  case SDLK_EQUALS: return "EQUALS";  case SDLK_GREATER: return "GREATER";  case SDLK_QUESTION: return "QUESTION";  case SDLK_AT: return "AT";  case SDLK_LEFTBRACKET: return "LEFTBRACKET";  case SDLK_BACKSLASH: return "BACKSLASH";  case SDLK_RIGHTBRACKET: return "RIGHTBRACKET";  case SDLK_CARET: return "CARET";  case SDLK_UNDERSCORE: return "UNDERSCORE";  case SDLK_BACKQUOTE: return "BACKQUOTE";  case SDLK_a: return "A";  case SDLK_b: return "B";  case SDLK_c: return "C";  case SDLK_d: return "D";  case SDLK_e: return "E";  case SDLK_f: return "F";  case SDLK_g: return "G";  case SDLK_h: return "H";  case SDLK_i: return "I";  case SDLK_j: return "J";  case SDLK_k: return "K";  case SDLK_l: return "L";  case SDLK_m: return "M";  case SDLK_n: return "N";  case SDLK_o: return "O";  case SDLK_p: return "P";  case SDLK_q: return "Q";  case SDLK_r: return "R";  case SDLK_s: return "S";  case SDLK_t: return "T";  case SDLK_u: return "U";  case SDLK_v: return "V";  case SDLK_w: return "W";  case SDLK_x: return "X";  case SDLK_y: return "Y";  case SDLK_z: return "Z";  case SDLK_DELETE: return "DELETE";  case SDLK_WORLD_0: return "WORLD_0";  case SDLK_WORLD_1: return "WORLD_1";  case SDLK_WORLD_2: return "WORLD_2";  case SDLK_WORLD_3: return "WORLD_3";  case SDLK_WORLD_4: return "WORLD_4";  case SDLK_WORLD_5: return "WORLD_5";  case SDLK_WORLD_6: return "WORLD_6";  case SDLK_WORLD_7: return "WORLD_7";  case SDLK_WORLD_8: return "WORLD_8";  case SDLK_WORLD_9: return "WORLD_9";  case SDLK_WORLD_10: return "WORLD_10";  case SDLK_WORLD_11: return "WORLD_11";  case SDLK_WORLD_12: return "WORLD_12";  case SDLK_WORLD_13: return "WORLD_13";  case SDLK_WORLD_14: return "WORLD_14";  case SDLK_WORLD_15: return "WORLD_15";  case SDLK_WORLD_16: return "WORLD_16";  case SDLK_WORLD_17: return "WORLD_17";  case SDLK_WORLD_18: return "WORLD_18";  case SDLK_WORLD_19: return "WORLD_19";  case SDLK_WORLD_20: return "WORLD_20";  case SDLK_WORLD_21: return "WORLD_21";  case SDLK_WORLD_22: return "WORLD_22";  case SDLK_WORLD_23: return "WORLD_23";  case SDLK_WORLD_24: return "WORLD_24";  case SDLK_WORLD_25: return "WORLD_25";  case SDLK_WORLD_26: return "WORLD_26";  case SDLK_WORLD_27: return "WORLD_27";  case SDLK_WORLD_28: return "WORLD_28";  case SDLK_WORLD_29: return "WORLD_29";  case SDLK_WORLD_30: return "WORLD_30";  case SDLK_WORLD_31: return "WORLD_31";  case SDLK_WORLD_32: return "WORLD_32";  case SDLK_WORLD_33: return "WORLD_33";  case SDLK_WORLD_34: return "WORLD_34";  case SDLK_WORLD_35: return "WORLD_35";  case SDLK_WORLD_36: return "WORLD_36";  case SDLK_WORLD_37: return "WORLD_37";  case SDLK_WORLD_38: return "WORLD_38";  case SDLK_WORLD_39: return "WORLD_39";  case SDLK_WORLD_40: return "WORLD_40";  case SDLK_WORLD_41: return "WORLD_41";  case SDLK_WORLD_42: return "WORLD_42";  case SDLK_WORLD_43: return "WORLD_43";  case SDLK_WORLD_44: return "WORLD_44";  case SDLK_WORLD_45: return "WORLD_45";  case SDLK_WORLD_46: return "WORLD_46";  case SDLK_WORLD_47: return "WORLD_47";  case SDLK_WORLD_48: return "WORLD_48";  case SDLK_WORLD_49: return "WORLD_49";  case SDLK_WORLD_50: return "WORLD_50";  case SDLK_WORLD_51: return "WORLD_51";  case SDLK_WORLD_52: return "WORLD_52";  case SDLK_WORLD_53: return "WORLD_53";  case SDLK_WORLD_54: return "WORLD_54";  case SDLK_WORLD_55: return "WORLD_55";  case SDLK_WORLD_56: return "WORLD_56";  case SDLK_WORLD_57: return "WORLD_57";  case SDLK_WORLD_58: return "WORLD_58";  case SDLK_WORLD_59: return "WORLD_59";  case SDLK_WORLD_60: return "WORLD_60";  case SDLK_WORLD_61: return "WORLD_61";  case SDLK_WORLD_62: return "WORLD_62";  case SDLK_WORLD_63: return "WORLD_63";  case SDLK_WORLD_64: return "WORLD_64";  case SDLK_WORLD_65: return "WORLD_65";  case SDLK_WORLD_66: return "WORLD_66";  case SDLK_WORLD_67: return "WORLD_67";  case SDLK_WORLD_68: return "WORLD_68";  case SDLK_WORLD_69: return "WORLD_69";  case SDLK_WORLD_70: return "WORLD_70";  case SDLK_WORLD_71: return "WORLD_71";  case SDLK_WORLD_72: return "WORLD_72";  case SDLK_WORLD_73: return "WORLD_73";  case SDLK_WORLD_74: return "WORLD_74";  case SDLK_WORLD_75: return "WORLD_75";  case SDLK_WORLD_76: return "WORLD_76";  case SDLK_WORLD_77: return "WORLD_77";  case SDLK_WORLD_78: return "WORLD_78";  case SDLK_WORLD_79: return "WORLD_79";  case SDLK_WORLD_80: return "WORLD_80";  case SDLK_WORLD_81: return "WORLD_81";  case SDLK_WORLD_82: return "WORLD_82";  case SDLK_WORLD_83: return "WORLD_83";  case SDLK_WORLD_84: return "WORLD_84";  case SDLK_WORLD_85: return "WORLD_85";  case SDLK_WORLD_86: return "WORLD_86";  case SDLK_WORLD_87: return "WORLD_87";  case SDLK_WORLD_88: return "WORLD_88";  case SDLK_WORLD_89: return "WORLD_89";  case SDLK_WORLD_90: return "WORLD_90";  case SDLK_WORLD_91: return "WORLD_91";  case SDLK_WORLD_92: return "WORLD_92";  case SDLK_WORLD_93: return "WORLD_93";  case SDLK_WORLD_94: return "WORLD_94";  case SDLK_WORLD_95: return "WORLD_95";  case SDLK_KP0: return "KP0";  case SDLK_KP1: return "KP1";  case SDLK_KP2: return "KP2";  case SDLK_KP3: return "KP3";  case SDLK_KP4: return "KP4";  case SDLK_KP5: return "KP5";  case SDLK_KP6: return "KP6";  case SDLK_KP7: return "KP7";  case SDLK_KP8: return "KP8";  case SDLK_KP9: return "KP9";  case SDLK_KP_PERIOD: return "KP_PERIOD";  case SDLK_KP_DIVIDE: return "KP_DIVIDE";  case SDLK_KP_MULTIPLY: return "KP_MULTIPLY";  case SDLK_KP_MINUS: return "KP_MINUS";  case SDLK_KP_PLUS: return "KP_PLUS";  case SDLK_KP_ENTER: return "KP_ENTER";  case SDLK_KP_EQUALS: return "KP_EQUALS";  case SDLK_UP: return "UP";  case SDLK_DOWN: return "DOWN";  case SDLK_RIGHT: return "RIGHT";  case SDLK_LEFT: return "LEFT";  case SDLK_INSERT: return "INSERT";  case SDLK_HOME: return "HOME";  case SDLK_END: return "END";  case SDLK_PAGEUP: return "PAGEUP";  case SDLK_PAGEDOWN: return "PAGEDOWN";  case SDLK_F1: return "F1";  case SDLK_F2: return "F2";  case SDLK_F3: return "F3";  case SDLK_F4: return "F4";  case SDLK_F5: return "F5";  case SDLK_F6: return "F6";  case SDLK_F7: return "F7";  case SDLK_F8: return "F8";  case SDLK_F9: return "F9";  case SDLK_F10: return "F10";  case SDLK_F11: return "F11";  case SDLK_F12: return "F12";  case SDLK_F13: return "F13";  case SDLK_F14: return "F14";  case SDLK_F15: return "F15";  case SDLK_NUMLOCK: return "NUMLOCK";  case SDLK_CAPSLOCK: return "CAPSLOCK";  case SDLK_SCROLLOCK: return "SCROLLOCK";  case SDLK_RSHIFT: return "RSHIFT";  case SDLK_LSHIFT: return "LSHIFT";  case SDLK_RCTRL: return "RCTRL";  case SDLK_LCTRL: return "LCTRL";  case SDLK_RALT: return "RALT";  case SDLK_LALT: return "LALT";  case SDLK_RMETA: return "RMETA";  case SDLK_LMETA: return "LMETA";  case SDLK_LSUPER: return "LSUPER";  case SDLK_RSUPER: return "RSUPER";  case SDLK_MODE: return "MODE";  case SDLK_COMPOSE: return "COMPOSE";  case SDLK_HELP: return "HELP";  case SDLK_PRINT: return "PRINT";  case SDLK_SYSREQ: return "SYSREQ";  case SDLK_BREAK: return "BREAK";  case SDLK_MENU: return "MENU";  case SDLK_POWER: return "POWER";  case SDLK_EURO: return "EURO";  case SDLK_UNDO: return "UNDO";  default: return "UNKNOWNKEY";   }    }}