Hi (sorry for the title - I couldnt make it more meaningfull),
I am using encryption of string literals using constexpr from here: Compile time string encryption using constexpr
I use it to hide string literals (formats) used in logs in binary files. It works preety well, the macro looks as follows:
#define LOG(format, ...) do { \
constexpr auto secformat = LIT((format)); \
WriteLog(static_cast<std::string>(secformat).c_str(), ##__VA_ARGS__); \
} while(0)
void WriteLog(char const * format, ...);
The problem is that there is also an overloaded version of WriteLog :
void WriteLog(int param1, int param2, char const * format, ...);
and before the LOG macro looked as follows:
#define LOG WriteLog
so compiler was easily choosing a correct overload, this made it possible to make calls like:
LOG("Some log text %d %d", 1, 2); // *1
LOG(SEVERITY_HIGH, DEST_CLIENT, "Some log text %d %d", 1, 2); // *2
now I can handle only the first log case, but it wont work when logs like in *2 are found.
So the question is whether there is some method I could use to still allow to use logs like above *1 and *2?
I was trying to use constexpr functions, tried with variadic templates - but in both cases I was ending with some non constexpr parameters. But I am not very strong with both of those language features.
below is source code ( LIVE on coliru ):
#include <array>
#include <iostream>
#include <string>
#include <iostream>
#include <vector>
#include <stdio.h>
#include <stdarg.h>
// Based on:
// https://eden.dei.uc.pt/~sneves/pubs/2012-snfa2.pdf
typedef uint32_t u32;
typedef uint64_t u64;
typedef unsigned char uchar;
template<u32 S, u32 A = 16807UL, u32 C = 0UL, u32 M = (1UL << 31) - 1>
struct LinearGenerator {
static const u32 state = ((u64)S * A + C) % M;
static const u32 value = state;
typedef LinearGenerator<state> next;
struct Split { // Leapfrog
typedef LinearGenerator< state, A*A, 0, M> Gen1;
typedef LinearGenerator<next::state, A*A, 0, M> Gen2;
};
};
// Metafunction to get a particular index from generator
template<u32 S, std::size_t index>
struct Generate {
static const uchar value = Generate<LinearGenerator<S>::state, index - 1>::value;
};
template<u32 S>
struct Generate<S, 0> {
static const uchar value = static_cast<uchar> (LinearGenerator<S>::value);
};
// List of indices
template<std::size_t...>
struct StList {};
// Concatenate
template<typename TL, typename TR>
struct Concat;
template<std::size_t... SL, std::size_t... SR>
struct Concat<StList<SL...>, StList<SR...>> {
typedef StList<SL..., SR...> type;
};
template<typename TL, typename TR>
using Concat_t = typename Concat<TL, TR>::type;
// Count from zero to n-1
template<size_t s>
struct Count {
typedef Concat_t<typename Count<s - 1>::type, StList<s - 1>> type;
};
template<>
struct Count<0> {
typedef StList<> type;
};
template<size_t s>
using Count_t = typename Count<s>::type;
// Get a scrambled character of a string
template<u32 seed, std::size_t index, std::size_t N>
constexpr uchar get_scrambled_char(const char(&a)[N]) {
return static_cast<uchar>(a[index]) + Generate<seed, index>::value;
}
// Get a ciphertext from a plaintext string
template<u32 seed, typename T>
struct cipher_helper;
template<u32 seed, std::size_t... SL>
struct cipher_helper<seed, StList<SL...>> {
static constexpr std::array<uchar, sizeof...(SL)> get_array(const char(&a)[sizeof...(SL)]) {
return{ { get_scrambled_char<seed, SL>(a)... } };
}
};
template<u32 seed, std::size_t N>
constexpr std::array<uchar, N> get_cipher_text(const char(&a)[N]) {
return cipher_helper<seed, Count_t<N>>::get_array(a);
}
// Get a noise sequence from a seed and string length
template<u32 seed, typename T>
struct noise_helper;
template<u32 seed, std::size_t... SL>
struct noise_helper<seed, StList<SL...>> {
static constexpr std::array<uchar, sizeof...(SL)> get_array() {
return{ { Generate<seed, SL>::value ... } };
}
};
template<u32 seed, std::size_t N>
constexpr std::array<uchar, N> get_key() {
return noise_helper<seed, Count_t<N>>::get_array();
}
/*
// Get an unscrambled character of a string
template<u32 seed, std::size_t index, std::size_t N>
char get_unscrambled_char(const std::array<uchar, N> & a) {
return static_cast<char> (a[index] - Generate<seed, index>::value);
}
*/
// Metafunction to get the size of an array
template<typename T>
struct array_info;
template <typename T, size_t N>
struct array_info<T[N]>
{
typedef T type;
enum { size = N };
};
template <typename T, size_t N>
struct array_info<const T(&)[N]> : array_info<T[N]> {};
// Scramble a string
// taken from : https://stackoverflow.com/questions/32287125/compile-time-string-encryption-using-constexpr
template<u32 seed, std::size_t N>
class obfuscated_string {
private:
std::array<uchar, N> cipher_text_;
std::array<uchar, N> key_;
public:
explicit constexpr obfuscated_string(const char(&a)[N])
: cipher_text_(get_cipher_text<seed, N>(a))
, key_(get_key<seed, N>())
{}
std::string to_string() const {
return (std::string)(*this);
}
operator std::string() const {
char plain_text[N];
for (volatile std::size_t i = 0; i < N; ++i) {
volatile char temp = static_cast<char>(cipher_text_[i] - key_[i]);
plain_text[i] = temp;
}
return std::string{ plain_text, plain_text + N };
}
};
#define RNG_SEED ((__TIME__[7] - '0') * 1 + (__TIME__[6] - '0') * 10 + \
(__TIME__[4] - '0') * 60 + (__TIME__[3] - '0') * 600 + \
(__TIME__[1] - '0') * 3600 + (__TIME__[0] - '0') * 36000) + \
(__LINE__ * 100000)
#define LIT(STR) \
obfuscated_string<RNG_SEED, array_info<decltype((STR))>::size>{(STR)}
void WriteLog(int iSystem, int iSeverity, char const * szFormat, ...) {
va_list argptr;
va_start(argptr, szFormat);
static const int iBuffSize = 512;
char aLine[iBuffSize + 3];
char* szLine = &aLine[0];
vsnprintf(szLine, iBuffSize, szFormat, argptr);
std::cout << iSystem << ", " << iSeverity << ": " << szLine << "\n";
va_end(argptr);
}
void WriteLog(const char* szFormat, ...) {
va_list argptr;
va_start(argptr, szFormat);
static const int iBuffSize = 512;
char aLine[iBuffSize + 3];
char* szLine = &aLine[0];
vsnprintf(szLine, iBuffSize, szFormat, argptr);
std::cout << -1 << ", " << -1 << ": " << szLine << "\n";
va_end(argptr);
}
#define LOG(format, ...) do { \
constexpr auto secformat = LIT((format)); \
WriteLog(((std::string)(secformat)).c_str(), ##__VA_ARGS__); \
} while(0)
template<u32 seed, std::size_t N>
std::ostream & operator<< (std::ostream & s, const obfuscated_string<seed, N> & str) {
s << static_cast<std::string>(str);
return s;
}
int main() {
LOG("Echo 12 d");
LOG("Echo 12 %d", 12);
LOG("Echo 12 %d, %d", 12, 32);
#define LOG_SEVERITY_HIGH 1
#define LOG_SEVERITY_LOW 2
#define LOG_DEST_SERVER 1
#define LOG_DEST_CLIENT 2
//LOG(LOG_SEVERITY_LOW, LOG_DEST_CLIENT, "Echo 12 %d, %d", 12, 32);
}