PT_Extension.cpp

 /* 
PT Extensions
    Copyright (C) 2004  Phyrstorm Technologies, Inc.
Copyright (C) 2004  Nate Davis <nate@phyrtech.com>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include "PT_Extension.h"

//SMTP extensions
std::string addr_smtp_GetCommonName(std::string str) {
//format: [common name]<user@host.tld>
str = str_TrimLeft(str, " \t\r\n"); //remove all leading white space

int idx = str.find('<');

if(idx == -1)
return STRING_ERR;

str = str.substr(0, idx);
str = str_TrimRight(str, " \t\r\n");

return str;
}

std::string addr_smtp_GetFullEmail(std::string str) {
//format: [common name]<user@host.tld>
if(str_CountChar(str, "<") != 1 || str_CountChar(str, ">") != 1)
return STRING_ERR;

int idx = str.find('<');
if(idx > str.find('>'))
return STRING_ERR; //malformed

return str.substr(idx+1, str.find('>')-idx-1);
}

std::string addr_smtp_GetUser(std::string str) {
str = addr_smtp_GetFullEmail(str);

int idx = str.find('@');
if(idx < 1)
return STRING_ERR;

return str.substr(0, idx);
}

std::string addr_smtp_GetServer(std::string str) {
str = addr_smtp_GetFullEmail(str);
//format: user@domain.tld
int idx = str.find('@');
if(idx == str.size()-1)
return STRING_ERR;

return str.substr(idx+1);
}

//HTTP extensions
//http://user:pwd@v_host.v_host.v_host.domain.tld:80?[query_string]
std::string addr_http_GetPort(std::string str) {
str = addr_http_StripUserAndPass(addr_http_StripProtocol(addr_http_StripQueryString(str)));

int idx = str.find(':');
if(idx == -1 || idx == str.size()-1)
return STRING_ERR;

return str.substr(idx+1);
}

std::string addr_http_GetQueryString(std::string str) {
str = addr_http_StripUserAndPass(addr_http_StripProtocol(str));

int idx = str.find('?');
if(idx == -1 || idx == str.size()-1)
return STRING_ERR;

return str.substr(idx+1);
}

std::string addr_http_GetTLD(std::string str) {
str = addr_http_StripUserAndPass(addr_http_StripProtocol(addr_http_StripQueryString(str)));
int cnt = str_CountChar(str, ".");

if(cnt < 1)
return STRING_ERR;

while(cnt > 1) {
str = str.substr(str.find('.')+1);
cnt = str_CountChar(str, ".");
}

str = str.substr(str.find('.')+1);
cnt = str.find(':');
if(cnt == -1)
return str;
return str.substr(0, cnt);
}

std::string addr_http_GetUser(std::string str) {
str = addr_http_StripProtocol(str);
str = addr_http_StripQueryString(str);
int idx = str.find('@');
if(idx != -1) {
str = str.substr(0,idx);
idx = str.find(':');
if(idx == -1)
return str;
return str.substr(0, idx);
}
return STRING_ERR;
}

std::string addr_http_GetPassword(std::string str) {
str = addr_http_StripProtocol(addr_http_StripQueryString(str));
int idx = str.find('@');
if(idx != -1) {
str = str.substr(0,idx);
idx = str.find(':');
if(idx == -1 || idx == str.size()-1)
return STRING_ERR;
return str.substr(idx+1);
}
return STRING_ERR;
}

std::vector<std::string> addr_http_GetPrefixes(std::string str) {
std::vector<std::string> prefixes;
str = addr_http_StripUserAndPass(addr_http_StripProtocol(addr_http_StripQueryString(str)));

if(str_CountChar(str, ".") < 2)
return prefixes;

str = str.substr(0, str.find_last_of('.'));
str = str.substr(0, str.find_last_of('.'));

int idx = str.find('.');
while(idx != -1) {
prefixes.resize(prefixes.size()+1);
prefixes[prefixes.size()-1] = str.substr(0, idx);
str = str.substr(idx+1);
idx = str.find('.');
}

prefixes.resize(prefixes.size()+1);
prefixes[prefixes.size()-1] = str;
return prefixes;
}

std::string addr_http_GetDomain(std::string str) {
str = addr_http_StripUserAndPass(addr_http_StripProtocol(addr_http_StripQueryString(str)));
int cnt = str_CountChar(str, ".");

if(cnt < 1)
return STRING_ERR;

while(cnt > 1) {
str = str.substr(str.find('.')+1);
cnt = str_CountChar(str, ".");
}

return str.substr(0, str.find('.'));
}

std::string addr_http_StripProtocol(std::string str) {
int idx = str.find("//");

if(idx == -1)
return str;

return str.substr(idx+2);
}

std::string addr_http_StripQueryString(std::string str) {
int idx = str.find('?');
if(idx == -1)
return str;

return str.substr(0, idx);
}

std::string addr_http_StripUserAndPass(std::string str) {
int idx = str.find('@');
if(idx > str.find('?'))
return str;

int p_idx = str.find("//");
if(p_idx == -1)
return str.substr(idx+1);
return str.substr(0, p_idx+2) + str.substr(idx+1);
}

//string lib extensions

static const unsigned char *b64_tbl =
        (unsigned char*)"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static const unsigned char b64_pad = '=';

//MD5 padding
static unsigned char PADDING[64] = {
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

//MD5 algorithms
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | (~z)))

/* ROTATE_LEFT rotates x left n bits */
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))

/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */
/* Rotation is separate from addition to prevent recomputation */
#define FF(a, b, c, d, x, s, ac) { (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); }
#define GG(a, b, c, d, x, s, ac) { (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); }
#define HH(a, b, c, d, x, s, ac) { (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); }
#define II(a, b, c, d, x, s, ac) { (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); }

//MD5 round definitions
#define S11 7
#define S12 12
#define S13 17
#define S14 22
#define S21 5
#define S22 9
#define S23 14
#define S24 20
#define S31 4
#define S32 11
#define S33 16
#define S34 23
#define S41 6
#define S42 10
#define S43 15
#define S44 21

//str_date defines
#define CONTAINS(a, b) ((a & b) == b)
#define REQUIRE_ONE(a, b) ((a && !b) || (b && !a))

void MD5Init(MD5_CTX *mdContext) {
mdContext->i[0] = mdContext->i[1] = (UINT4)0;

mdContext->buf[0] = (UINT4)0x67452301;
mdContext->buf[1] = (UINT4)0xefcdab89;
mdContext->buf[2] = (UINT4)0x98badcfe;
mdContext->buf[3] = (UINT4)0x10325476;
}

void MD5Update(MD5_CTX *mdContext, unsigned char *inBuf, unsigned int inLen) {
UINT4 in[16];
int mdi;
unsigned int i, ii;

mdi = (int)((mdContext->i[0] >> 3) & 0x3F);

if ((mdContext->i[0] + ((UINT4)inLen << 3)) < mdContext->i[0])
mdContext->i[1]++;
mdContext->i[0] += ((UINT4)inLen << 3);
mdContext->i[1] += ((UINT4)inLen >> 29);

while (inLen--) {
mdContext->in[mdi++] = *inBuf++;

if(mdi == 0x40) {
for (i = 0, ii = 0; i < 16; i++, ii += 4)
in[i] = (((UINT4)mdContext->in[ii+3]) << 24) |
(((UINT4)mdContext->in[ii+2]) << 16) |
(((UINT4)mdContext->in[ii+1]) << 8) |
((UINT4)mdContext->in[ii]);
Transform(mdContext->buf, in);
mdi = 0;
}
}
}

void MD5Final(MD5_CTX *mdContext) {
UINT4 in[16];
int mdi;
unsigned int i, ii;
unsigned int padLen;

in[14] = mdContext->i[0];
in[15] = mdContext->i[1];

mdi = (int)((mdContext->i[0] >> 3) & 0x3F);

padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi);
MD5Update(mdContext, PADDING, padLen);

for (i = 0, ii = 0; i < 14; i++, ii += 4)
in[i] = (((UINT4)mdContext->in[ii+3]) << 24) |
(((UINT4)mdContext->in[ii+2]) << 16) |
(((UINT4)mdContext->in[ii+1]) << 8) |
((UINT4)mdContext->in[ii]);
Transform(mdContext->buf, in);

for (i = 0, ii = 0; i < 4; i++, ii += 4) {
mdContext->digest[ii] = (unsigned char)(mdContext->buf[i] & 0xFF);
mdContext->digest[ii+1] = (unsigned char)((mdContext->buf[i] >> 8) & 0xFF);
mdContext->digest[ii+2] = (unsigned char)((mdContext->buf[i] >> 16) & 0xFF);
mdContext->digest[ii+3] = (unsigned char)((mdContext->buf[i] >> 24) & 0xFF);
}
}

static void Transform(UINT4 *buf, UINT4 *in) {
UINT4 a = buf[0], b = buf[1], c = buf[2], d = buf[3];
FF(a, b, c, d, in[ 0], S11, 3614090360);
FF(d, a, b, c, in[ 1], S12, 3905402710);
FF(c, d, a, b, in[ 2], S13,  606105819);
FF(b, c, d, a, in[ 3], S14, 3250441966);
FF(a, b, c, d, in[ 4], S11, 4118548399);
FF(d, a, b, c, in[ 5], S12, 1200080426);
FF(c, d, a, b, in[ 6], S13, 2821735955);
FF(b, c, d, a, in[ 7], S14, 4249261313);
FF(a, b, c, d, in[ 8], S11, 1770035416);
FF(d, a, b, c, in[ 9], S12, 2336552879);
FF(c, d, a, b, in[10], S13, 4294925233);
FF(b, c, d, a, in[11], S14, 2304563134);
FF(a, b, c, d, in[12], S11, 1804603682);
FF(d, a, b, c, in[13], S12, 4254626195);
FF(c, d, a, b, in[14], S13, 2792965006);
FF(b, c, d, a, in[15], S14, 1236535329);

GG(a, b, c, d, in[ 1], S21, 4129170786);
GG(d, a, b, c, in[ 6], S22, 3225465664);
GG(c, d, a, b, in[11], S23,  643717713);
GG(b, c, d, a, in[ 0], S24, 3921069994);
GG(a, b, c, d, in[ 5], S21, 3593408605);
GG(d, a, b, c, in[10], S22,   38016083);
GG(c, d, a, b, in[15], S23, 3634488961);
GG(b, c, d, a, in[ 4], S24, 3889429448);
GG(a, b, c, d, in[ 9], S21,  568446438);
GG(d, a, b, c, in[14], S22, 3275163606);
GG(c, d, a, b, in[ 3], S23, 4107603335);
GG(b, c, d, a, in[ 8], S24, 1163531501);
GG(a, b, c, d, in[13], S21, 2850285829);
GG(d, a, b, c, in[ 2], S22, 4243563512);
GG(c, d, a, b, in[ 7], S23, 1735328473);
GG(b, c, d, a, in[12], S24, 2368359562);

HH(a, b, c, d, in[ 5], S31, 4294588738);
HH(d, a, b, c, in[ 8], S32, 2272392833);
HH(c, d, a, b, in[11], S33, 1839030562);
HH(b, c, d, a, in[14], S34, 4259657740);
HH(a, b, c, d, in[ 1], S31, 2763975236);
HH(d, a, b, c, in[ 4], S32, 1272893353);
HH(c, d, a, b, in[ 7], S33, 4139469664);
HH(b, c, d, a, in[10], S34, 3200236656);
HH(a, b, c, d, in[13], S31,  681279174);
HH(d, a, b, c, in[ 0], S32, 3936430074);
HH(c, d, a, b, in[ 3], S33, 3572445317);
HH(b, c, d, a, in[ 6], S34,   76029189);
HH(a, b, c, d, in[ 9], S31, 3654602809);
HH(d, a, b, c, in[12], S32, 3873151461);
HH(c, d, a, b, in[15], S33,  530742520);
HH(b, c, d, a, in[ 2], S34, 3299628645);

II(a, b, c, d, in[ 0], S41, 4096336452);
II(d, a, b, c, in[ 7], S42, 1126891415);
II(c, d, a, b, in[14], S43, 2878612391);
II(b, c, d, a, in[ 5], S44, 4237533241);
II(a, b, c, d, in[12], S41, 1700485571);
II(d, a, b, c, in[ 3], S42, 2399980690);
II(c, d, a, b, in[10], S43, 4293915773);
II(b, c, d, a, in[ 1], S44, 2240044497);
II(a, b, c, d, in[ 8], S41, 1873313359);
II(d, a, b, c, in[15], S42, 4264355552);
II(c, d, a, b, in[ 6], S43, 2734768916);
II(b, c, d, a, in[13], S44, 1309151649);
II(a, b, c, d, in[ 4], S41, 4149444226);
II(d, a, b, c, in[11], S42, 3174756917);
II(c, d, a, b, in[ 2], S43,  718787259);
II(b, c, d, a, in[ 9], S44, 3951481745);

buf[0] += a;
buf[1] += b;
buf[2] += c;
buf[3] += d;
}

/* str_TrimLeft
deletes all instances of any index item from "items" at the very front of "str"
example: str_TrimLeft("aabcdeff", "ab") would result in "cdeff"
*/
std::string str_TrimLeft(std::string str, std::string items) {
if(items.size() == 0 || str.size() == 0)
return str;

bool trim = str.find_first_not_of(items) != 0;
while(trim) {
str = str.substr(1);
trim = str.find_first_not_of(items) != 0;
}
return str;
}

/* str_TrimRight
deletes all instance of any index item from "items" at the end of "str"
example: str_TrimRight("aabcdeff", "ef") would result in "aabcd"
*/
std::string str_TrimRight(std::string str, std::string items) {
if(items.size() == 0 || str.size() == 0)
return str;

bool trim = str.find_last_of(items) == str.size()-1;
while(trim) {
str = str.substr(0,str.size()-1);
trim = str.find_last_of(items) == str.size()-1;
}
return str;
}

int str_CountChar(std::string str, std::string items) {
int ret = 0;
for(int i=0;i<str.size();i++)
for(int n=0;n<items.size();n++)
if(str[i] == items[n])
++ret;
return ret;
}

static void str_b64_encode_group(std::string &output, const std::string &input, int n) {
unsigned char ingrp[3];

if(n > 0) {
ingrp[0] = input[0];
ingrp[1] = input[1];
ingrp[2] = input[2];
}
else
ingrp[0] = ingrp[1] = ingrp[2] = 0;

if(n > 0) {
output += b64_tbl[ingrp[0] >> 2];
output += b64_tbl[((ingrp[0] & 0x3) << 4) | (ingrp[1] >> 4)];
}
else {
output += b64_pad;
output += b64_pad;
}

if(n > 1)
output += b64_tbl[((ingrp[1] & 0xf) << 2) | (ingrp[2] >> 6)];
else
output += b64_pad;

if(n > 2)
output += b64_tbl[ingrp[2] & 0x3f];
else
output += b64_pad;
}

std::string str_b64_encode(const std::string &src) {
int outsz = 0;
int ptr = 0;
int len = src.size();
std::string str;

while(len > 0) {
str_b64_encode_group(str, src.substr(ptr, 3), len > 3 ? 3 : len);
len -= 3;
ptr += 3;
outsz += 4;
}

return str;
}

static bool str_b64_decode_group(std::string &output, const std::string &input) {
unsigned char *t1,*t2;

if(input[0] == b64_pad)
return true;

if(input[1] == b64_pad)
return true;

t1 = (unsigned char *)strchr((const char *)b64_tbl, input[0]);
t2 = (unsigned char *)strchr((const char *)b64_tbl, input[1]);

if((t1 == NULL) || (t2 == NULL))
return false;

output += ((t1 - b64_tbl) << 2) | ((t2 - b64_tbl) >> 4);

if(input[2] == b64_pad)
return true;

t1 = (unsigned char *)strchr((const char *)b64_tbl, input[2]);

if(t1 == NULL)
return false;

output += ((t2 - b64_tbl) << 4) | ((t1 - b64_tbl) >> 2);

if(input[3] == b64_pad)
return true;

t2 = (unsigned char *)strchr((const char *)b64_tbl, input[3]);

if(t2 == NULL)
return false;

output += ((t1 - b64_tbl) << 6) | (t2 - b64_tbl);

return true;
}

std::string str_b64_decode(const std::string &src) {
int ptr = 0;
std::string str;

while(ptr < src.size()) {
if(!str_b64_decode_group(str, src.substr(ptr, 4)))
return "";
ptr += 4;
}

return str;
}

std::vector<std::string> str_explode(char needle, const std::string &str, char delim) {
std::vector<std::string> arr;
arr.resize(1);
bool in_quotes = false;
for(int i=0;i<str.length();i++) {
if(str[i] == delim) {
if(i == 0 || str[i-1] != '\\')
in_quotes = !in_quotes;
arr[arr.size()-1] += delim;
}
else if(str[i] == needle && !in_quotes) {
arr.resize(arr.size()+1);
}
else {
arr[arr.size()-1] += str[i];
}
}
return arr;
}

std::string str_md5string(const std::string &str) {
MD5_CTX mdContext;
std::string ret;

MD5Init(&mdContext);
MD5Update(&mdContext, (unsigned char*)str.c_str(), str.size());
MD5Final(&mdContext);

for(int i=0;i<16;i++)
ret += str_ctoh(mdContext.digest[i]);

return ret;
}

std::string str_hmac_md5string(const std::string &k, const std::string &text) {
MD5_CTX context;
unsigned char k_ipad[65];
unsigned char k_opad[65];
std::string ret;
std::string key = k;

if(key.size() > 64)
key = str_md5string(key);

memset(k_ipad, 0, sizeof(k_ipad));
memset(k_opad, 0, sizeof(k_opad));
memcpy(k_ipad, key.c_str(), key.size());
memcpy(k_opad, key.c_str(), key.size());

for(int i=0;i<64;i++) {
k_ipad[i] ^= 0x36;
k_opad[i] ^= 0x5c;
}

MD5Init(&context);
MD5Update(&context, k_ipad, 64);
MD5Update(&context, (unsigned char*)text.c_str(), text.size());
MD5Final(&context);

unsigned char temp[16];
memcpy(temp, context.digest, 16);

MD5Init(&context);
MD5Update(&context, k_opad, 64);
MD5Update(&context, temp, 16);
MD5Final(&context);

for(i=0;i<16;i++)
ret += str_ctoh(context.digest[i]);

return ret;
}

std::string str_ctoh(unsigned char ch) {
unsigned char byte[2];
unsigned char szHex[3] = {'\0'};
byte[0] = ch/16;
byte[1] = ch%16;
for(int i=0;i<2;i++) {
if(byte[i] >= 0 && byte[i] <= 9)
szHex[i] = '0' + byte[i];
else
szHex[i] = 'A' + byte[i] - 10;
}
szHex[2] = 0;

return (char*)szHex;
}

char str_htoc(const std::string &hex) {
const char *szHex = str_to_upper(hex).c_str();
char rch = 0;
for(int i=0;i<2;i++) {
if(*(szHex + i) >= '0' && *(szHex + i) <= '9')
rch = (rch << 4) + (*(szHex + i) - '0');
else if(*(szHex + i) >= 'A' && *(szHex + i) <= 'F')
rch = (rch << 4) + (*(szHex + i) - 'A' + 10);
else
break;
}

return rch;
}

std::string str_tohex(const std::string &str) {
std::string ret;
for(int i=0;i<str.size();i++)
ret += str_ctoh(str[i]);
return ret;
}

std::string str_fromhex(const std::string &str) {
std::string ret;
for(int i=0;i<str.size();i+=2)
ret += str_htoc(str.substr(i, 2));

return ret;
}

std::string str_pad_both(std::string str, const std::string &padding) {
if(padding.size() % 2 != 0)
return str;

std::string rpad, lpad;
for(int i=0;i<padding.size()/2;i++) {
lpad += padding[i];
rpad += padding[padding.size()/2+i];
}

if(str.size() < lpad.size())
return lpad+str+rpad;
else {
if(str.find(lpad) != 0)
str = lpad+str;
if(str.find(rpad) != str.size() - rpad.size())
str += rpad;
}
return str;
}

std::string str_pad_right(std::string str, const std::string &pad, int sz) {
if(str.size() > sz)
return str;

while(str.size() < sz)
str += pad;

if(str.size() > sz)
return str.substr(0, sz);

return str;
}

std::string str_strip_left(std::string str, const char &n) {
while(str.size() > 0 && str[0] == n)
str = str.substr(1);
return str;
}

std::string str_strip_right(std::string str, const char &n) {
while(str.size() > 0 && str[str.size()-1] == n)
str = str.substr(0, str.size()-1);
return str;
}

std::string str_to_upper(std::string str) {
for(int i=0;i<str.size();i++)
str[i] = toupper(str[i]);
return str;
}

std::string str_to_lower(std::string str) {
for(int i=0;i<str.size();i++)
str[i] = tolower(str[i]);
return str;
}

std::string str_date(const PT_TIME_TYPE &type, const int style) {
bool use_caps = CONTAINS(style, 0x01);
bool use_caps_smart = CONTAINS(style, 0x02);
bool textual = CONTAINS(style, 0x04);
bool numeric = CONTAINS(style, 0x08);
bool leading = CONTAINS(style, 0x10);
bool full_text = CONTAINS(style, 0x20);
bool abbreviate = CONTAINS(style, 0x40);
bool hour_24 = CONTAINS(style, 0x80);
bool hour_12 = CONTAINS(style, 0x100);

if(!REQUIRE_ONE(textual, numeric) || !REQUIRE_ONE(full_text, abbreviate) || !REQUIRE_ONE(hour_24, hour_12))
return "invalid identifier set";

switch(type) {
case AM_PM:
break;
case SWATCH:
break;
case ISO_8601:
break;
case RFC_2822:
break;
case DAYS_IN_MONTH:
break;
case DAY_OF_MONTH:
break;
case DAY_OF_WEEK:
break;
case YEAR:
break;
case MONTH:
break;
case HOUR:
break;
case MINUTE:
break;
case SECONDS:
break;
case LEAP_YEAR:
break;
case GMT_DIFF:
break;
default:
break;
}

return "";
}

std::string str_to_string(double num) {
char buf[80];
::sprintf(buf,"%lf", num);
std::string ret = buf;
ret = ret.substr(0,ret.find_last_not_of('0')+1);
if(ret[ret.length()-1] == '.')
ret = ret.substr(0,ret.length()-1);
return ret;
}

std::string str_to_string(Stringable *s) {
return s->toString();
}

std::string str_to_string(Stringable &s) {
return s.toString();
}

void stl_unserialize(void *tmpl, const std::string &str) {
memcpy(tmpl, str_fromhex(str).c_str(), str.size()/2);
}

void cmd_init(CMD_CTX *ctx, int flag) {
ctx->style = new bool[IDX_MAX];

ctx->style[IDX_NO_DELIM] = CONTAINS(flag, NO_DELIM);
ctx->style[IDX_SLASH_DELIM] = CONTAINS(flag, SLASH_DELIM);
ctx->style[IDX_HYPHEN_DELIM] = CONTAINS(flag, HYPHEN_DELIM);
ctx->style[IDX_DBL_HYPHEN_DELIM] = CONTAINS(flag, DBL_HYPHEN_DELIM);
ctx->style[IDX_EQUALS_STYLE] = CONTAINS(flag, EQUALS_STYLE);
ctx->style[IDX_EXTENDED_ARG] = CONTAINS(flag, EXTENDED_ARG);
ctx->style[IDX_QUOTED_ARG] = CONTAINS(flag, QUOTED_ARG);
ctx->style[IDX_CASE_INSENSITIVE] = CONTAINS(flag, CASE_INSENSITIVE);
}

void cmd_update(CMD_CTX *ctx, char **tmpl, int sz) {
std::string args;
for(int i=0;i<sz;i++) {
if(i != 0)
args += " ";
args += tmpl[i];
}

cmd_update(ctx, args, sz);
}

void cmd_update(CMD_CTX *ctx, const std::string &tmpl, int) {
char delim = char(0);

if(ctx->style[IDX_QUOTED_ARG])
delim = '"';

std::vector<std::string> parts = str_explode(' ', tmpl, delim);

bool f_key = false;
std::string key_buf;
std::string value_buf;

for(int i=0;i<parts.size();i++) {
if(ctx->style[IDX_NO_DELIM])
cmd_entry(ctx, parts[i]);
else {
if(ctx->style[IDX_DBL_HYPHEN_DELIM] && parts[i].find("--") == 0) {
if(f_key) {
cmd_add(ctx, key_buf, value_buf);
key_buf = "";
value_buf = "";
}

if(parts[i].find('=') != -1) {
key_buf = parts[i].substr(2, parts[i].find('=')-2);
value_buf = str_strip_right(str_strip_left(parts[i].substr(parts[i].find('=')+1), '"'), '"');
}
else
key_buf = parts[i].substr(2);
}
else if((ctx->style[IDX_HYPHEN_DELIM] && parts[i].find('-') == 0) ||
(ctx->style[IDX_SLASH_DELIM] && parts[i].find('/') == 0)) {
if(f_key) {
cmd_add(ctx, key_buf, value_buf);
key_buf = "";
value_buf = "";
}

if(parts[i].find('=') != -1) {
key_buf = parts[i].substr(1, parts[i].find('=')-1);
value_buf = str_strip_right(str_strip_left(parts[i].substr(parts[i].find('=')+1), '"'), '"');
}
else
key_buf = parts[i].substr(1);
}
else if(ctx->style[IDX_EXTENDED_ARG] && f_key) {
if(value_buf.size() > 0)
value_buf += " ";
value_buf += str_strip_left(str_strip_right(parts[i], '"'), '"');
}
else {
if(f_key) {
cmd_add(ctx, key_buf, parts[i]);
key_buf = "";
value_buf = "";
}
else
cmd_add(ctx, parts[i], "");

f_key = false;
continue;
}

f_key = true;
}
}

cmd_add(ctx, key_buf, value_buf);
}

std::string cmd_get_value(CMD_CTX *ctx, const std::string &key) {
for(int i=0;i<ctx->items.size();i++) {
std::string cmp;
if(ctx->style[IDX_CASE_INSENSITIVE])
cmp = str_to_lower(key);
else
cmp = key;

if(cmp == ctx->items[i].key)
return ctx->items[i].value;
}

return STRING_ERR;
}

bool cmd_isset(CMD_CTX *ctx, const std::string &str) {
for(int i=0;i<ctx->items.size();i++) {
if(ctx->style[IDX_CASE_INSENSITIVE] && ctx->items[i].key == str_to_lower(str))
return true;
else if(ctx->items[i].key == str)
return true;
}

return false;
}

void cmd_iterator(CMD_CTX *ctx, fn_cmd_iterator *fn, PTVOID arg) {
for(int i=0;i<ctx->items.size();i++) {
bool ret;
if(arg == NULL)
ret = fn(&ctx->items[i], &i);
else
ret = fn(&ctx->items[i], arg);

if(!ret)
break;
}
}

void cmd_entry(CMD_CTX *ctx, const std::string &str) {
if(ctx->style[IDX_EQUALS_STYLE] && str.find('=') != -1)
cmd_add(ctx, str.substr(0, str.find('=')), str_strip_left(str_strip_right(str.substr(str.find('=')+1), '"'), '"'));
else
cmd_add(ctx, str, "");
}

void cmd_add(CMD_CTX *ctx, const std::string &key, const std::string &value) {
if(key == "") //truely orphaned item
return;

for(int i=0;i<ctx->items.size();i++) {
if(ctx->items[i].key == key) {
ctx->items[i].value = value;
return;
}
}

ctx->items.resize(ctx->items.size()+1);

if(ctx->style[IDX_CASE_INSENSITIVE])
ctx->items[ctx->items.size()-1].key = str_to_lower(key);
else
ctx->items[ctx->items.size()-1].key = key;

ctx->items[ctx->items.size()-1].value = value;
}

void cmd_debug(CMD_CTX *ctx) {
std::cout << "styles:\n";
if(ctx->style[IDX_NO_DELIM])
std::cout << "\tNO_DELIM\n";
if(ctx->style[IDX_SLASH_DELIM])
std::cout << "\tSLASH_DELIM\n";
if(ctx->style[IDX_HYPHEN_DELIM])
std::cout << "\tHYPHEN_DELIM\n";
if(ctx->style[IDX_DBL_HYPHEN_DELIM])
std::cout << "\tDBL_HYPHEN_DELIM\n";
if(ctx->style[IDX_EQUALS_STYLE])
std::cout << "\tEQUALS_STYLE\n";
if(ctx->style[IDX_EXTENDED_ARG])
std::cout << "\tEXTENDED_ARG\n";
if(ctx->style[IDX_QUOTED_ARG])
std::cout << "\tQUOTED_ARG\n";
if(ctx->style[IDX_CASE_INSENSITIVE])
std::cout << "\tCASE_INSENSITIVE\n";

std::cout << "vector:\n";
for(int i=0;i<ctx->items.size();i++)
std::cout << "\t'" << ctx->items[i].key << "'='" << ctx->items[i].value << "'\n";
std::cout << std::flush;
}

Project Homepage: