C++: unpack the data back again - c++

I'm packing my string with this function:
std::vector<char> pack(const std::string& str) {
const uint32_t sz = str.size();
const uint32_t n_sz = htonl(sz);
std::vector<char> result(sizeof(sz) + sz);
memcpy(result.data(), &n_sz, sizeof(n_sz));
memcpy(result.data() + sizeof(sz), str.data(), sz);
return result;
}
How can i unpack it again so...i get the original string back?
I tried to do:
int len;
len = ntohl(ourbuffer.size());
char* string = ( char* )malloc(sizeof (char) * (len + 1));
string[len] = '\0';
becouse i know the function pack is using big endian. But that did not work. Can someone please show how to to unpack again??

uint32_t n_sz;
memcpy(&n_sz, ourbuffer.data(), sizeof n_sz);
const uint32_t sz = ntohl(n_sz);
std::string str(ourbuffer.data() + sizeof n_sz, sz);

Related

Return without memory leak

I try to write a function which converts a char* to a wchar_t* to simplify multiple steps in my program.
wchar_t* ConvertToWString(char* str)
{
size_t newStrSize = strlen(str) + 1;
wchar_t* newWStr = new wchar_t[newStrSize];
size_t convertedChars = 0;
mbstowcs_s(&convertedChars, newWStr , newStrSize, str, _TRUNCATE);
return newWStr; // I know i need to call "delete[] newWStr;" but then I can't return the converted string...
}
The function works but it is obviously memory leaking. Does someone know another way how to convert a char* to a wchar_t*?
My issue is that the function needs to handle different string lengths.
Right now I am using a workaround with a fixed buffer but that can't be the only solution:
wchar_t* ConvertToWStringUgly(char* str)
{
wchar_t buffer[1024]; // fixed array for 1023 wchars
size_t newStrSize = strlen(str) + 1;
size_t convertedChars = 0;
mbstowcs_s(&convertedChars, buffer, newStrSize, str, _TRUNCATE);
return buffer; // This is working but not really a good way
}
Classic. Use the C++ power ! ... Destructors freeing allocated memory
Instead of your
wchar_t buffer [1024];
why not declare and use a Wstr class, looking approximately like this (maybe malloc and free to used instead of new and delete ?):
class Wstr {
public :
Wstr () : val_ ((wchar_t*) NULL), size_ (0) {}
~Wstr () {
if (val_ != (wchar_t*)NULL) {
delete[] val_;
val_ = (wchar_t*)NULL;
}
}
Wstr& operator = (const char*& str) {
size_ = strlen(str) + 1;
if (val_ != (wchar_t*) NULL) {
delete [] val_;
val_ = (wchar_t*) NULL;
}
size_t newStrSize = strlen(str) + 1;
size_t convertedChars = 0;
mbstowcs_s(&convertedChars, val_, newStrSize, str, _TRUNCATE);
size_ = newStrSize;
return *this;
}
//.. copy cons, op =, op ==, op != to be written
wchar_t* val_;
size_t size_;
};

overcome rpc endianness convert

I want to assign unsigned char[8] to uint64 (c language) , pass this value with RPC and convert the uint64 back to unsigned char[8] with the same bytes order (cpp language).
The problem is that the RPC may convert my uint64 endianness.
what is the best way to do this?
While the endiannes may change, you can still extract individual bytes from uint64_t portably, e.g.:
void to_bytes(uint64_t from, char* to) {
for(size_t i = 0; i < sizeof from; ++i, from >>= 8)
to[i] = from & 0xff;
}
Alternatively, use reversing copy operations:
#ifdef BOOST_LITTLE_ENDIAN
inline void xcopy(void* dst, void const* src, size_t n)
{
char const* csrc = static_cast<char const*>(src);
std::reverse_copy(csrc, csrc + n, static_cast<char*>(dst));
}
#elif defined(BOOST_BIG_ENDIAN)
inline void xcopy(void* dst, void const* src, size_t n)
{
char const* csrc = static_cast<char const*>(src);
std::copy(csrc, csrc + n, static_cast<char*>(dst));
}
#endif
void to_bytes(uint64_t from, char* to) {
xcopy(to, &from, sizeof from);
}
void from_bytes(char const* from, uint64_t* to) {
xcopy(to, from, sizeof *to);
}
unit8_t data[8];
// fill the array, then ...
uint64_t carrier = data [0];
size_t position;
for (position = 1; position < 8; ++position) {
carrier <<= 8;
carrier |= data[position];
}
// ... on the other end
// variables of same type
position = 8;
while (position--) {
data[position] = 0xFF & carrier;
carrier >>= 8;
}
This should do it, since the value (so you don't have to worry about endianness) of carrier will be (hopefully) correctly transmitted by the RPC protocol.
Note the use of uint8_t instead of char. The later isn't guaranteed to be 1/8th of uint64_t.
The code should have well defined behaviour for both C and C++. For C++ you should rather use std::array instead of a raw array.

How to write strings and integers in a ring buffer?

How to write strings and integers in a ring buffer? I would like to write multiple strings and integers into the ring buffer but my c++ knowledge is limited. If you need some more info, please let me know. I appreciate any help that you can provide.
Here are the integer and string variables that I want to write and the write function of the ring buffer:
string payload;
int byte_pos;
size_t ringbuffer::write(u_char *data, size_t bytes)
{
if (bytes == 0) return 0;
size_t capacity = capacity_;
size_t bytes_to_write = std::min(bytes, capacity - size_);
// Write in a single step
if (bytes_to_write <= capacity - end_index_)
{
memcpy(data_ + end_index_, data, bytes_to_write);
end_index_ += bytes_to_write;
if (end_index_ == capacity) end_index_ = 0;
}
// Write in two steps
else
{
size_t size_1 = capacity - end_index_;
memcpy(data_ + end_index_, data, size_1);
size_t size_2 = bytes_to_write - size_1;
memcpy(data_, data + size_1, size_2);
end_index_ = size_2;
}
size_ += bytes_to_write;
return bytes_to_write;
}
You have to convert your std::string variable into a C-style pointer to char:
string payload;
char* cpayload = payload.c_str();
int len = strlen(cpayload);
ringbuffer::write(cpayload, len*sizeof(char));
This is what seems to be working but I haven't verified what exactly I am getting in the ringbuffer yet, no errors though.
ringbuffer::write((u_char*) payload.c_str(), payload.length());
ringbuffer::write((u_char*) &byte_pos, sizeof(byte_pos));

std::string substr method problems

Hello I'm writing this method. I want it to extract from a given buffer a portion that is in a given place. I have a string like this something=one;something=two and I want to get "one"
This is my idea :
static std::string Utils::getHeader( unsigned char * buffer)
{
std::string *str = new std::string(buffer);
std::size_t b_pos = str->find("=");
std::size_t a_pos = str->find(";");
return str->substr((a_pos + 1) ,(b_pos + 1));
}
but on eclipse I get this error in reference to the std::string substr method
Invalid arguments ...
Candidates are:
std::basic_string<char,std::char_traits<char>,std::allocator<char>> substr(?, ?)
Can someone explain me why I get this error and how I can fix it?
The code should probably look like:
static std::string Utils::getHeader(unsigned char * buffer, size_t size)
{
if(!buffer || !size)
return "";
const std::string str(reinterpret_cast<char*>(buffer), size);
std::size_t b_pos = str.find("=");
if(b_pos == std::string::npos)
throw ...;
std::size_t a_pos = str.find(";");
if(a_pos == std::string::npos)
throw ...;
if(b_pos > a_pos)
throw ...'
return str.substr((a_pos + 1), (b_pos + 1));
}
substr takes a starting position and a length. Maybe something like:
const size_t start = b_pos + 1;
const size_t length = (a_pos + 1) - (b_pos + 1) + 1;
And then, return str.substr(start, length);.
I'm not certain of the a_pos + 1 and b_pos + 1 is correct, though. Be certain that's what you want.
Ok, assuming you know that the input string is formatted as you mentioned you probably want something like this:
static std::string Utils::getHeader(const std::string & params) {
size_t start = params.find('=') +1; // Don't include =
size_t length = params.find(';') - start; // Already not including ';'
return str.substr(start, length);
}

Converting std::wsting to char* with wcstombs_s

I have input strings that contain only digits (just the plain Latin ones, 0-9, so for example "0123"), stored as std::wstring, and I need each as a char*. What's the best way for me to do this? This is my initial approach:
void type::convertWStringToCharPtr(_In_ std::wstring input, _Out_ char * outputString)
{
outputString = new char[outputSize];
size_t charsConverted = 0;
const wchar_t * inputW = input.c_str();
wcstombs_s(&charsConverted, outputString, sizeof(outputString), inputW, input.length());
}
EDIT: The code below works. Thanks all!
void type::convertWStringToCharPtr(_In_ std::wstring input, _Out_ char * outputString)
{
size_t outputSize = input.length() + 1; // +1 for null terminator
outputString = new char[outputSize];
size_t charsConverted = 0;
const wchar_t * inputW = input.c_str();
wcstombs_s(&charsConverted, outputString, outputSize, inputW, input.length());
}
You are not allocating enough memory for your buffer:
char * outputString = new char[input.length()];
Should be
char * outputString = new char[input.length() + 1];
because of terminating NUL-character.
Oh, and also, as per pm100's comment: sizeof(outputString) is giving you the size of the pointer. You should use input.length() + 1, as that is the size of the buffer.
There are a couple of errors in your code. First, you're not allocating enough space in your destination buffer for the NULL character. You must allocate at least input.length() + 1 chars for the function to succeed.
Second, you're not passing in the correct size of the output buffer to the function. sizeof(outputString) returns the size of outputString itself, a char *, and not the number of bytes pointed to by that pointer.
So your function should look like this:
void CoverageTileManager::convertWStringToCharPtr(_In_ std::wstring input, _Out_ char * outputString)
{
size_t outputSize = input.length() + 1;
outputString = new char[outputSize];
size_t charsConverted = 0;
wcstombs_s(&charsConverted, outputString, outputSize, input.c_str(), input.length());
// TODO verify charsConverted = outputSize
}
In C++ I would never use pure pointers: use vector if a char array needed in heap! Do you want to copy the source string? If not, const reference should be used for input. wcstombs_s is used only in Windows, so why doesn't use simply WideCharToMultiByte? Was the conversion success? Return value.
bool CoverageTileManager::convertWStringToCharPtr(const std::wstring& input, std::vector<char>& outputString )
{
if ( input.empty() ) {
return false;
}
int size = WideCharToMultiByte(CP_ACP,0,input.c_str(),input.size(),NULL,0,NULL,NULL);
if ( size <= 0 ) {
return false;
}
outputString.resize(size+1);
if ( WideCharToMultiByte(CP_ACP,0,input.c_str(),input.size(),&outputString[0],size,NULL,NULL) <= 0 ) {
outputString.clear();
return false;
}
outputString[size] = '\0';
return true;
}
Use vector to external C++ lib:
extern void call( const char*, size_t);
std::vector<char> buffer;
std::wstring input;
...
if ( convertWStringToCharPtr(input,buffer) ) {
call(&buffer[0],buffer.size());
}