#include "arg_conversion.h" #include "jsonArg.h" #include "AmUtils.h" using namespace std; #define CSTR_LABEL 's' #define ARRAY_LABEL 'a' #define STRUCT_LABEL 'x' static string arg2string(const AmArg &a) { string s; char tmp[32]; const char *p; switch (a.getType()) { case AmArg::CStr: p = a.asCStr(); sprintf(tmp, "%c%zd/", CSTR_LABEL, strlen(p)); s = tmp; s += p; return s; case AmArg::Array: sprintf(tmp, "%c%zd/", ARRAY_LABEL, a.size()); s = tmp; for (size_t i = 0; i < a.size(); i ++) s += arg2string(a[i]); return s; case AmArg::Struct: sprintf(tmp, "%c%zd/", STRUCT_LABEL, a.size()); s = tmp; for (AmArg::ValueStruct::const_iterator it = a.asStruct().begin(); it != a.asStruct().end(); ++it) { sprintf(tmp, "%zd/", it->first.size()); s += tmp; s += it->first; s += arg2string(it->second); } return s; default: throw string("arg2string not fully implenmented!"); } return "???"; } static bool read_len(const char *&src, int &len, int &dst) { int i; dst = 0; for (i = 0; i < len; i++) { if ((src[i] >= '0') && (src[i] <= '9')) { dst = 10 * dst + (src[i] - '0'); continue; } if (src[i] == '/') break; return false; // not our length separator } if (i == len) return false; // separator is missing if (i == 0) return false; // no number there len -= i + 1; src += i + 1; return true; } static bool read_string(const char *&src, int &len, string &dst) { int l; if (!read_len(src, len, l)) return false; if (l <= len) { dst.assign(src, l); len -= l; src += l; return true; } return false; } static bool string2arg(const char *&src, int &len, AmArg &dst) { string s; int cnt; if (len < 1) return false; switch (src[0]) { case CSTR_LABEL: if (!read_string(++src, --len, s)) return false; dst = s; return true; case ARRAY_LABEL: dst.assertArray(); if (!read_len(++src, --len, cnt)) return false; for (int i = 0; i < cnt; i++) { dst.push(AmArg()); if (!string2arg(src, len, dst.get(dst.size() - 1))) return false; } return true; case STRUCT_LABEL: dst.assertStruct(); if (!read_len(++src, --len, cnt)) return false; for (int i = 0; i < cnt; i++) { if (!read_string(src, len, s)) return false; dst[s] = AmArg(); if (!string2arg(src, len, dst[s])) return false; } return true; default: DBG("unknown label '%c'\n", src[0]); return false; } } #define ESCAPE_CHAR '?' // use % instead? string arg2username(const AmArg &a) { string encoded = arg2string(a); // encode the string using characters allowed in username static const char *allowed = "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789" "-_.!~*'" "&=+$,;/"; string res; for (size_t i = 0; i < encoded.size(); i++) { if (strchr(allowed, encoded[i])) res += encoded[i]; else { res += ESCAPE_CHAR; res += char2hex(encoded[i], true); } } string json_vars = arg2json(a); DBG("encoding variables: '%s'\n", json_vars.c_str()); DBG("encoded variables: '%s'\n", res.c_str()); return res; } bool username2arg(const string &src, AmArg &dst) { string encoded(src); size_t pos = encoded.find(ESCAPE_CHAR); while (pos != string::npos) { if (pos + 2 >= encoded.size()) return false; unsigned int c; if (reverse_hex2int(string() + encoded[pos + 2] + encoded[pos + 1], c)) { DBG("%c%c does not convert from hex\n", encoded[pos + 1], encoded[pos + 2]); return false; } encoded.replace(pos, 3, 1, c); pos = encoded.find(ESCAPE_CHAR, pos + 1); } DBG("encoded variables: '%s'\n", encoded.c_str()); const char *s = encoded.c_str(); int len = encoded.size(); bool res = string2arg(s, len, dst); if (res) { string json_vars = arg2json(dst); DBG("decoded variables: '%s'\n", json_vars.c_str()); } else DBG("decoding failed\n"); return res; }