apps/sbc/arg_conversion.cpp
87f79fef
 #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;
 }