
1 changed files with 413 additions and 0 deletions
@ -0,0 +1,413 @@ |
|||
#include <iostream> |
|||
#include <cctype> |
|||
#include <pEp/pEpEngine.h> |
|||
#include <pEp/message_api.h> |
|||
#include <pEp/keymanagement.h> |
|||
#include <pEp/identity_list.h> |
|||
#include <pEp/utils.hh> |
|||
#include <pEp/pEpLog.hh> |
|||
#include <sstream> |
|||
#include <type_traits> |
|||
//using namespace pEp;
|
|||
|
|||
|
|||
namespace pEp { |
|||
|
|||
template<class T> |
|||
std::string type_add_val(const T c, size_t val_len = 30) |
|||
{ |
|||
static_assert(std::is_pointer<T>::value, "only pointer types are valid"); |
|||
std::stringstream ss_type; |
|||
//type
|
|||
ss_type << typeid(T).name(); |
|||
|
|||
//addr
|
|||
std::stringstream ss_addr{}; |
|||
ss_addr << static_cast<const void*>(c); |
|||
|
|||
//value
|
|||
std::stringstream ss_val{}; |
|||
if (c != nullptr) { |
|||
ss_val << "\"" << c << "\""; |
|||
} else { |
|||
ss_val << "<NULL>"; |
|||
} |
|||
|
|||
std::stringstream ret{}; |
|||
ret << "{ " << ss_type.str() << " | " + ss_addr.str() << " | " |
|||
<< pEp::Utils::clip(ss_val.str(), val_len) << " }"; |
|||
return ret.str(); |
|||
} |
|||
|
|||
char* alloc(const std::string& str) |
|||
{ |
|||
char* ret = strdup(str.c_str()); |
|||
pEpLog(type_add_val(ret)); |
|||
return ret; |
|||
} |
|||
|
|||
template<class T> |
|||
void free(T ptr_type) |
|||
{ |
|||
pEpLog(type_add_val(ptr_type)); |
|||
::pEp_free(ptr_type); |
|||
} |
|||
|
|||
template<> |
|||
void free(char* ptr_type) |
|||
{ |
|||
pEpLog(type_add_val(ptr_type)); |
|||
::pEp_free(ptr_type); |
|||
} |
|||
|
|||
template<> |
|||
void free(::pEp_identity* ptr_type) |
|||
{ |
|||
pEpLog(type_add_val(ptr_type)); |
|||
::pEp_free(ptr_type); |
|||
} |
|||
|
|||
|
|||
//---------------------------------------------------------------------------------------------
|
|||
#define EXSTR(msg) std::string(__FUNCTION__) + " - " + msg |
|||
|
|||
|
|||
// Manages a char* to appear like a std::string
|
|||
// char* c_str
|
|||
// c_str MUST point to either:
|
|||
// * NULL - means there is no value/mem alloc yet
|
|||
// * dyn allocated memory
|
|||
// in case the mem is already allocated, there must be 2 modes
|
|||
// * take ownership (and free it)
|
|||
// * dont take ownership, only provide a C++ interface
|
|||
// There must be the option to construct the object before the wrapped c_str (char*)
|
|||
// is known. This leads to a pEp::String object in invalid state, and it must be initialized using
|
|||
// set(). Otherwise all(most) functions will throw.
|
|||
// set() can only be called once, will throw otherwise.
|
|||
class String { |
|||
public: |
|||
String() = default; |
|||
|
|||
// Best to use this constructor, as the object is in a valid state when the wrapped
|
|||
// c_str (char*) is known
|
|||
explicit String(char** c_str_pp) |
|||
{ |
|||
initialize(c_str_pp); |
|||
} |
|||
|
|||
~String() |
|||
{ |
|||
_free(); |
|||
} |
|||
|
|||
void initialize(char** c_str_pp) |
|||
{ |
|||
if (c_str_pp == nullptr) { |
|||
throw Exception{ EXSTR("cant initialize on a nullptr") }; |
|||
} |
|||
|
|||
if (_is_initialized) { |
|||
throw Exception{ EXSTR("double initialization") }; |
|||
} |
|||
|
|||
// init
|
|||
_c_str_pp = c_str_pp; |
|||
// _c_str_p.reset(*_c_str_pp, [&](char* ptr) { this->_free(ptr); });
|
|||
_c_str_p = *_c_str_pp; |
|||
|
|||
_is_initialized = true; |
|||
pEpLogClass(to_string() + " - taking ownership"); |
|||
} |
|||
|
|||
// make a copy
|
|||
String& operator=(const std::string& str) |
|||
{ |
|||
pEpLogClass("Before: " + to_string() + " - new val: '" + pEp::Utils::clip(str, 30) + "'"); |
|||
if (_c_str_pp == nullptr) { |
|||
throw Exception{ EXSTR("invalid state") }; |
|||
} |
|||
|
|||
// DEALLOCATION
|
|||
_free(); |
|||
// // if we point to an initialized string
|
|||
// if (*_c_str_pp != nullptr) {
|
|||
// // if the string there is not the one we created
|
|||
//// if (*_c_str_pp != _c_str_p.get()) {
|
|||
// if (*_c_str_pp != _c_str_p) {
|
|||
// // we need to free it before we lose the pointer to it
|
|||
// pEpLog("freeing foreign allocated string");
|
|||
// pEp::free(*_c_str_pp);
|
|||
// // } // else it will be free automatically upon .reset()
|
|||
// }
|
|||
// //and we need to anyways free the strings we create ourselfes
|
|||
// if
|
|||
// pEp::free(_c_str_p;)
|
|||
// }
|
|||
|
|||
|
|||
// ALLOCATION
|
|||
if (str.empty()) { |
|||
// if the new value is empty str, lets point to nothing
|
|||
*_c_str_pp = nullptr; |
|||
// _c_str_p.reset(*_c_str_pp);
|
|||
_c_str_p = *_c_str_pp; |
|||
} else { |
|||
*_c_str_pp = pEp::alloc(str); |
|||
// _c_str_p.reset(*_c_str_pp, [&](char* ptr) { this->_free(ptr); });
|
|||
_c_str_p = *_c_str_pp; |
|||
} |
|||
pEpLogClass("After: " + to_string()); |
|||
return *this; |
|||
} |
|||
|
|||
// return a copy of whatever c_str currently is (maybe created by us, maybe changed meanwhile)
|
|||
operator std::string() const |
|||
{ |
|||
if (_c_str_pp == nullptr) { |
|||
throw Exception{ EXSTR("invalid state") }; |
|||
} |
|||
|
|||
if (*_c_str_pp != nullptr) { |
|||
return { *_c_str_pp }; |
|||
} |
|||
return {}; |
|||
} |
|||
|
|||
char** data() |
|||
{ |
|||
return _c_str_pp; |
|||
} |
|||
|
|||
const char* c_data() const |
|||
{ |
|||
if (_c_str_pp == nullptr) { |
|||
throw Exception{ EXSTR("invalid state") }; |
|||
} |
|||
return *_c_str_pp; |
|||
} |
|||
|
|||
std::string to_string() const |
|||
{ |
|||
if (_c_str_pp == nullptr) { |
|||
throw Exception{ EXSTR("invalid state") }; |
|||
} |
|||
|
|||
std::string ret{ "[" + type_add_val(_c_str_pp) + " / " + type_add_val(*_c_str_pp) + "]" }; |
|||
return ret; |
|||
} |
|||
|
|||
static bool log_enabled; |
|||
|
|||
|
|||
private: |
|||
void _free() |
|||
{ |
|||
// if the c_str points to a different address now, than the one we created
|
|||
if (*_c_str_pp != _c_str_p) { |
|||
// a new string has been created, and we need to free it as well
|
|||
pEpLog("raw access string change detected"); |
|||
pEp::free(*_c_str_pp); |
|||
} else { |
|||
// we anyways need to free the one we created
|
|||
// NO: WE ASSUME THAT:
|
|||
// if the char* has been replaced, it has been freed, as well
|
|||
if (_c_str_p != nullptr) { |
|||
pEp::free(_c_str_p); |
|||
} |
|||
} |
|||
} |
|||
|
|||
bool _is_initialized{ false }; |
|||
char** _c_str_pp{ nullptr }; |
|||
// std::shared_ptr<char> _c_str_p{};
|
|||
char* _c_str_p{ nullptr }; |
|||
|
|||
Adapter::pEpLog::pEpLogger logger{ "pEp::String", log_enabled }; |
|||
Adapter::pEpLog::pEpLogger& m4gic_logger_n4me = logger; |
|||
|
|||
class Exception : public std::runtime_error { |
|||
public: |
|||
explicit Exception(const std::string& msg) : std::runtime_error(msg) {} |
|||
}; |
|||
}; |
|||
|
|||
bool pEp::String::log_enabled{ true }; |
|||
|
|||
std::ostream& operator<<(std::ostream& o, const pEp::String& pEpStr) |
|||
{ |
|||
return o << std::string(pEpStr); |
|||
} |
|||
|
|||
//---------------------------------------------------------------------------------------------
|
|||
|
|||
// TOOD:
|
|||
// ctor not exception safe
|
|||
class Identity { |
|||
public: |
|||
Identity( |
|||
const std::string& address = "", |
|||
const std::string& username = "", |
|||
const std::string& user_id = "", |
|||
const std::string& fpr = "") |
|||
{ |
|||
pEpLogClass("called"); |
|||
_wrappee = ::new_identity(nullptr, nullptr, nullptr, nullptr); |
|||
|
|||
// set the pEp::String wrapper underlying c_str
|
|||
this->address.initialize(&_wrappee->address); |
|||
this->username.initialize(&_wrappee->username); |
|||
this->user_id.initialize(&_wrappee->user_id); |
|||
this->fpr.initialize(&_wrappee->fpr); |
|||
|
|||
// set the values
|
|||
this->address = address; |
|||
this->username = username; |
|||
this->user_id = user_id; |
|||
this->fpr = fpr; |
|||
} |
|||
|
|||
~Identity() |
|||
{ |
|||
_free(); |
|||
} |
|||
|
|||
|
|||
pEp::String address{}; |
|||
pEp::String username{}; |
|||
pEp::String user_id{}; |
|||
pEp::String fpr{}; |
|||
|
|||
operator ::pEp_identity*() |
|||
{ |
|||
return _wrappee; |
|||
} |
|||
|
|||
static bool log_enabled; |
|||
|
|||
private: |
|||
void _free() |
|||
{ |
|||
// pEp::free(_wrappee);
|
|||
} |
|||
|
|||
::pEp_identity* _wrappee{ nullptr }; |
|||
Adapter::pEpLog::pEpLogger logger{ "IdentWrappySP", log_enabled }; |
|||
Adapter::pEpLog::pEpLogger& m4gic_logger_n4me = logger; |
|||
}; |
|||
|
|||
bool Identity::log_enabled{ true }; |
|||
|
|||
} // namespace pEp
|
|||
|
|||
|
|||
::PEP_SESSION session; |
|||
|
|||
void test_getters(char const* const* const c_str_p, pEp::String& pstr) |
|||
{ |
|||
pEpLog("to_string(): " + pstr.to_string()); |
|||
assert(pstr.c_data() == *c_str_p); |
|||
assert(pstr.data() == c_str_p); |
|||
|
|||
if (*c_str_p != nullptr) { |
|||
std::string tmp{ pstr }; |
|||
pEpLog("operator std::string(): " + tmp); |
|||
assert(tmp == std::string(*c_str_p)); |
|||
|
|||
// will segfault with nullptr, and this is correct
|
|||
std::string tmp2{ *pstr.data() }; |
|||
pEpLog("data(): " + tmp2); |
|||
assert(tmp2 == std::string(*c_str_p)); |
|||
|
|||
std::string tmp3{ pstr.c_data() }; |
|||
pEpLog("c_data(): " + tmp2); |
|||
assert(tmp3 == std::string(*c_str_p)); |
|||
} else { |
|||
std::string tmp{ pstr }; |
|||
pEpLog("operator std::string(): " + tmp); |
|||
assert(tmp == ""); |
|||
} |
|||
} |
|||
|
|||
void test_assign_and_getters(char** c_str_p, pEp::String& pstr) |
|||
{ |
|||
test_getters(c_str_p, pstr); |
|||
pEpLogH2("assign operator"); |
|||
pstr = "assign operator"; |
|||
test_getters(c_str_p, pstr); |
|||
|
|||
pEpLogH2("raw c_str assign"); |
|||
*c_str_p = strdup("raw c_str assign"); |
|||
test_getters(c_str_p, pstr); |
|||
} |
|||
|
|||
int main() |
|||
{ |
|||
// pEp::Utils::readKey();
|
|||
pEp::Adapter::pEpLog::set_enabled(true); |
|||
|
|||
// pEp::String::log_enabled = false;
|
|||
if (1) { |
|||
// INVALID USAGE
|
|||
// char* c_str_u; // uninitialized == INVALID
|
|||
// undefined behaviour, most likely "pointer being freed was not allocated"
|
|||
// {
|
|||
// char* c_str;
|
|||
// pEp::String pstr(c_str);
|
|||
// }
|
|||
// char* c_str_s = "fdsfs"; // statically initialized == INVALID
|
|||
// {
|
|||
// char ca[4] = { 'p', 'E', 'p'};
|
|||
// char* c_str = ca;
|
|||
// pEp::String pstr(c_str);
|
|||
// }
|
|||
|
|||
// VALID USAGE
|
|||
// new pEp::String on char* pointing to NULL
|
|||
{ |
|||
pEpLogH1("new pEp::String on char* pointing to NULL"); |
|||
char* c_str = NULL; // nullptr
|
|||
|
|||
pEp::String pstr(&c_str); |
|||
test_assign_and_getters(&c_str, pstr); |
|||
} |
|||
|
|||
// new pEp::String on already initalized char*
|
|||
{ |
|||
pEpLogH1("new pEp::String on already initalized char*"); |
|||
char* c_str = strdup("initialized c string"); |
|||
|
|||
pEp::String pstr(&c_str); |
|||
test_assign_and_getters(&c_str, pstr); |
|||
} |
|||
|
|||
// initialize()
|
|||
{ |
|||
pEpLogH1("initialize()"); |
|||
pEp::String pstr{}; |
|||
|
|||
char* c_str = strdup("initialized c string"); |
|||
//TODO: PITYASSERT_THROWS
|
|||
pstr.initialize(&c_str); |
|||
|
|||
test_assign_and_getters(&c_str, pstr); |
|||
} |
|||
} |
|||
|
|||
setenv("HOME", ".", 1); |
|||
::init(&session, nullptr, nullptr, nullptr); |
|||
|
|||
// create identity
|
|||
pEp::Identity id1{ "wrong@entry.lol", "wrong", "23", "INVA_FPR" }; |
|||
|
|||
pEpLog(*id1); |
|||
id1.username = "alice"; |
|||
id1.address = "alice@peptest.org"; |
|||
pEpLog(id1.address); |
|||
pEpLog(id1.username); |
|||
::myself(session, id1); |
|||
pEpLog(*id1); |
|||
|
|||
pEp::Identity id2{ "bob" }; |
|||
::update_identity(session, id2); |
|||
pEpLog(*id2); |
|||
} |
Loading…
Reference in new issue