Skip to content

Instantly share code, notes, and snippets.

@mindw
Created May 20, 2014 07:24
Show Gist options
  • Select an option

  • Save mindw/20814408ea03b1736a6c to your computer and use it in GitHub Desktop.

Select an option

Save mindw/20814408ea03b1736a6c to your computer and use it in GitHub Desktop.
Escape a string for use in any FS using C++11
#include <assert.h>
#include <string>
#include <time.h>
#include <stdlib.h>
#include <vector>
std::string UriDecode(const std::string & src)
{
// Note from RFC1630: "Sequences which start with a percent sign
// but are not followed by two hexadecimal characters (0-9, A-F) are reserved
// for future extension"
std::string out;
out.reserve(src.length());
auto inserter = std::back_insert_iterator<std::string>(out);
for (auto iter = src.begin(); iter != src.end(); ++iter)
{
if (*iter == '%')
{
++iter;
std::string charCode(iter , iter + 2);
char ret = std::stoi(charCode, NULL, 16);
inserter = ret;
iter += 1;
}
else
{
inserter = *iter;
}
}
return out;
}
// Only alphanum is safe.
static const char SAFE[256] =
{
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
/* 0 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
/* 1 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
/* 2 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
/* 3 */ 1,1,1,1, 1,1,1,1, 1,1,0,0, 0,0,0,0,
/* 4 */ 0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,
/* 5 */ 1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,0,0,
/* 6 */ 0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,
/* 7 */ 1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,0,0,
/* 8 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
/* 9 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
/* A */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
/* B */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
/* C */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
/* D */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
/* E */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
/* F */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0
};
#include <iterator>
std::string UriEncode(const std::string & src)
{
static const char DEC2HEX[] = "0123456789ABCDEF";
std::string out;
out.reserve(src.length());
auto inserter = std::back_insert_iterator<std::string>(out);
for (auto iter = src.begin(); iter != src.end(); ++iter)
{
if (SAFE[*iter])
{
inserter = *iter;
}
else
{
inserter = '%';
inserter = DEC2HEX[(*iter >> 4) & 0xF];
inserter = DEC2HEX[*iter & 0xF];
}
}
return out;
}
void encodeDecodeTest(void)
{
TEST_ASSERT_EQUAL_STRING(UriEncode("ABC").c_str(), "ABC");
std::vector<char> v = {0, 1, 2};
const std::string ORG(v.begin(), v.end());
const std::string ENC("%00%01%02");
TEST_ASSERT_EQUAL_STRING(UriEncode(ORG).c_str(), ENC.c_str());
TEST_ASSERT_EQUAL_STRING(UriDecode(ENC).c_str(), ORG.c_str());
TEST_ASSERT_EQUAL_STRING(UriEncode("\xFF").c_str(), "%FF");
TEST_ASSERT_EQUAL_STRING(UriDecode("%FF").c_str(), "\xFF");
TEST_ASSERT_EQUAL_STRING(UriDecode("%ff").c_str(), "\xFF");
// unsafe chars test, RFC1738
const std::string UNSAFE(" <>#{}|\\^~[]`");
std::string sUnsafeEnc = UriEncode(UNSAFE);
TEST_ASSERT_EQUAL(std::string::npos, sUnsafeEnc.find_first_of(UNSAFE));
TEST_ASSERT_EQUAL_STRING(UriDecode(sUnsafeEnc).c_str(), UNSAFE.c_str());
// random test
const int MAX_LEN = 128;
char a[MAX_LEN];
srand((unsigned)time(NULL));
for (int i = 0; i < 100; i++)
{
for (int j = 0; j < MAX_LEN; j++)
a[j] = rand() % (1 << 8);
int nLen = rand() % MAX_LEN;
std::string sOrg(a, nLen);
std::string sEnc = UriEncode(sOrg);
TEST_ASSERT_EQUAL_STRING(sOrg.c_str(), UriDecode(sEnc).c_str());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment