You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
sems/apps/sbc/arg_conversion.cpp

180 lines
4.0 KiB

#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;
}