-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
351 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
/** | ||
* Jsondecode.h | ||
* | ||
* Built-in "|jsondecode" modifier | ||
* | ||
* @author Michael van der Werve <[email protected]> | ||
* @copyright 2020 Copernica BV | ||
*/ | ||
|
||
/** | ||
* Namespace | ||
*/ | ||
namespace SmartTpl { namespace Internal { | ||
|
||
/** | ||
* Class definition | ||
*/ | ||
class JsondecodeModifier : public Modifier | ||
{ | ||
public: | ||
/** | ||
* Destructor | ||
*/ | ||
virtual ~JsondecodeModifier() {}; | ||
|
||
/** | ||
* Modify a value object | ||
* @param input | ||
* @param params Parameters used for this modification | ||
* @return Value | ||
*/ | ||
VariantValue modify(const Value &input, const SmartTpl::Parameters ¶ms) override | ||
{ | ||
// Get the json encoder | ||
const Escaper *escaper = Escaper::get("json"); | ||
|
||
// Turn our input into a string | ||
std::string output(input.toString()); | ||
|
||
// Call encode and return the output | ||
return escaper->decode(output); | ||
} | ||
}; | ||
|
||
/** | ||
* End namespace | ||
*/ | ||
}} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
/** | ||
* Jsonencode.h | ||
* | ||
* Built-in "|jsonencode" modifier | ||
* | ||
* @author Michael van der Werve <[email protected]> | ||
* @copyright 2020 Copernica BV | ||
*/ | ||
|
||
/** | ||
* Namespace | ||
*/ | ||
namespace SmartTpl { namespace Internal { | ||
|
||
/** | ||
* Class definition | ||
*/ | ||
class JsonencodeModifier : public Modifier | ||
{ | ||
public: | ||
/** | ||
* Destructor | ||
*/ | ||
virtual ~JsonencodeModifier() {}; | ||
|
||
/** | ||
* Modify a value object | ||
* @param input | ||
* @param params Parameters used for this modification | ||
* @return Value | ||
*/ | ||
VariantValue modify(const Value &input, const SmartTpl::Parameters ¶ms) override | ||
{ | ||
// Get the json encoder | ||
const Escaper *escaper = Escaper::get("json"); | ||
|
||
// Turn our input into a string | ||
std::string output(input.toString()); | ||
|
||
// Call encode and return the output | ||
return escaper->encode(output); | ||
} | ||
}; | ||
|
||
/** | ||
* End namespace | ||
*/ | ||
}} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,7 +4,7 @@ | |
* Implementation file for the Data class | ||
* | ||
* @author Emiel Bruijntjes <[email protected]> | ||
* @copyright 2014 Copernica BV | ||
* @copyright 2014 - 2020 Copernica BV | ||
*/ | ||
|
||
/** | ||
|
@@ -43,6 +43,8 @@ static Internal::StrPosModifier strpos; | |
static Internal::StrStrModifier strstr; | ||
static Internal::NumberFormatModifier number_format; | ||
static Internal::DateFormatModifier date_format; | ||
static Internal::JsonencodeModifier jsonencode; | ||
static Internal::JsondecodeModifier jsondecode; | ||
static Internal::UrlencodeModifier urlencode; | ||
static Internal::UrldecodeModifier urldecode; | ||
static Internal::Md5Modifier md5; | ||
|
@@ -84,6 +86,8 @@ Data::Data() | |
{"strpos", &strpos}, | ||
{"number_format", &number_format}, | ||
{"date_format", &date_format}, | ||
{"jsonencode", &jsonencode}, | ||
{"jsondecode", &jsondecode}, | ||
{"urlencode", &urlencode}, | ||
{"urldecode", &urldecode}, | ||
{"range", &range_modifier}}) // register built-in modifiers | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,7 +4,7 @@ | |
* Implementation of the Escaper class | ||
* | ||
* @author Toon Schoenmakers <[email protected]> | ||
* @copyright 2014 Copernica BV | ||
* @copyright 2014 - 2020 Copernica BV | ||
*/ | ||
|
||
#include "includes.h" | ||
|
@@ -34,6 +34,7 @@ Escaper::Escaper(const char *name) | |
*/ | ||
static NullEscaper _null; | ||
static HtmlEscaper _html; | ||
static JsonEscaper _json; | ||
static UrlEscaper _url; | ||
static Base64Escaper _base64; | ||
|
||
|
@@ -57,4 +58,4 @@ Escaper* Escaper::get(const std::string &encoding) | |
/** | ||
* End namespace | ||
*/ | ||
}} | ||
}} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,185 @@ | ||
/** | ||
* Json.h | ||
* | ||
* A JSON en/decoder | ||
* | ||
* @author Michael van der Werve <[email protected]> | ||
* @copyright 2020 Copernica BV | ||
*/ | ||
|
||
/** | ||
* Namespace | ||
*/ | ||
namespace SmartTpl { namespace Internal { | ||
|
||
/** | ||
* Class definition | ||
*/ | ||
class JsonEscaper : public Escaper | ||
{ | ||
private: | ||
/** | ||
* Hex lookup table | ||
*/ | ||
static constexpr const char *hex = "0123456789abcdefABCDEF"; | ||
|
||
/** | ||
* Helper method to convert a hex digit to decimal | ||
* @param digit | ||
* @return uint8_t | ||
*/ | ||
inline uint8_t decimal(uint8_t digit) const | ||
{ | ||
// convert hex digit to decimal (doesnt check for hex number validity) | ||
return (digit <= 9) ? digit - '0' : ((digit & 7) + 9); | ||
} | ||
|
||
/** | ||
* Helper method to convert two hex digits to a byte | ||
* @param digit1 | ||
*/ | ||
uint8_t byte(uint8_t left, uint8_t right) const | ||
{ | ||
// reverse the byte sequence | ||
return decimal(left) << 4 & decimal(right); | ||
} | ||
|
||
public: | ||
/** | ||
* Constructor, in case the openssl library failed to load we simply are | ||
* giving our base constructor a nullptr so it doesn't register us | ||
*/ | ||
JsonEscaper() : Escaper("json") {}; | ||
|
||
/** | ||
* Destructor | ||
*/ | ||
virtual ~JsonEscaper() {} | ||
|
||
/** | ||
* Encode the given input | ||
* It is probably a good idea to directly modify the input instead of making | ||
* a copy and modifying that. | ||
* @param input | ||
*/ | ||
virtual std::string &encode(std::string &input) const override | ||
{ | ||
// we need to make a copy, because there's no 1-1 transformation on characters | ||
std::string output; | ||
|
||
// reserve at least enough bytes | ||
output.reserve(input.size()); | ||
|
||
// iterate over the characters | ||
for (const uint8_t &c : input) | ||
{ | ||
// in the first 32 bits we always have to escape | ||
if (c < 32 || c == '"' || c == '\\') | ||
{ | ||
switch(c) { | ||
case '\b': output.append("\\b"); break; | ||
case '\n': output.append("\\n"); break; | ||
case '\r': output.append("\\r"); break; | ||
case '\t': output.append("\\t"); break; | ||
case '\f': output.append("\\f"); break; | ||
case '"': output.append("\\\""); break; | ||
case '\\': output.append("\\\\"); break; | ||
default: | ||
// write a byte in hex | ||
output.append("\\x"); | ||
output.push_back(hex[c >> 4]); | ||
output.push_back(hex[c & 0xf]); | ||
} | ||
} | ||
|
||
// append character normally | ||
else output.push_back(c); | ||
} | ||
|
||
// swap the output and the input | ||
std::swap(output, input); | ||
|
||
// return the input | ||
return input; | ||
} | ||
|
||
/** | ||
* Decode the given input | ||
* It is probably a good idea to directly modify the input instead of making | ||
* a copy and modifying that. | ||
* @param input | ||
*/ | ||
virtual std::string &decode(std::string &input) const override | ||
{ | ||
// we need to make a copy, because there's no 1-1 transformation on characters | ||
std::string output; | ||
|
||
// reserve at least enough bytes | ||
output.reserve(input.size()); | ||
|
||
// store the 'current' pointer | ||
const char *current = input.data(); | ||
|
||
// the next character that is escaped | ||
const char *next = nullptr; | ||
|
||
// we always remove a backslash and move one forward, unless it is followed by an x | ||
while ((next = strchr(current, '\\'))) | ||
{ | ||
// wirte everything since last | ||
output.append(current, next - current); | ||
|
||
// we now have a new current, because we'll consume two extra bytes, the found \ and a character (skip those) | ||
current = next + 2; | ||
|
||
// parse the next character at this point, it is special | ||
switch (next[1]) { | ||
case 'b': output.push_back('\b'); break; | ||
case 'n': output.push_back('\n'); break; | ||
case 'r': output.push_back('\r'); break; | ||
case 't': output.push_back('\t'); break; | ||
case 'f': output.push_back('\f'); break; | ||
case '"': output.push_back('"'); break; | ||
case '\\': output.push_back('\\'); break; | ||
// solidus should also be escapable, but does not need to be escaped | ||
case '/': output.push_back('/'); break; | ||
case 'x': | ||
// we consume two extra bytes, so check if they are actually valid. since this is a json string, we can easily | ||
// check with simply null character checking | ||
if (current[0] && !current[1] && isxdigit(current[0]) && isxdigit(current[1])) | ||
{ | ||
// add a single byte, we consume 3 | ||
output.push_back(byte(current[0], current[1])); | ||
|
||
// we consumed two extra bytes | ||
current += 2; | ||
} | ||
|
||
// if we arrived here, there were no more bytes or they're not hex, and so we're in an invalid state. | ||
// we fall through to the error-correction. | ||
case '\0': | ||
default: | ||
// this is not allowed, some unknown character was escaped. return the result so far | ||
std::swap(output, input); | ||
|
||
// and we leap out of the function | ||
return input; | ||
} | ||
} | ||
|
||
// append the rest of the output | ||
output.append(current); | ||
|
||
// swap the output with the input | ||
std::swap(output, input); | ||
|
||
// and return the input | ||
return input; | ||
} | ||
|
||
}; | ||
|
||
/** | ||
* End namespace | ||
*/ | ||
}} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.