C++ string append formatted data - c++

I have created my own string class in C++ (I didnt want to use 3rd party lib or std::string for some reasons).
Now I have an issue with appending formated string into my own. I have created this function:
void MyStringAnsi::AppendFormat(const char * str, ...)
{
va_list vl;
va_start(vl, str);
int newLength = static_cast<int>(this->length + 10 * strlen(str));
this->ResizeBuffer(this->length + newLength);
vsnprintf_s(this->str + this->length, newLength, newLength, str, vl);
va_end(vl);
this->length = static_cast<int>(strlen(this->str));
this->str[this->length] = '\0';
this->hashCode = UINT32_MAX;
}
Problem is with newLength of appended string. I can not calculate it, so I set it by some "magic" multiplier, but it is not enough.
Is this problem solvable (iterate all varagrs or change it to mething else)? I can use C++11 features, so maybe something there?
I call my code with
MyStringAnsi str = "xy";
str.AppendFormat("%s AND %d", someLongString, -50.7);

With gcc, you may use returned value of vsnprintf to know the wanted size.
For msvc, you have to increase size until vsnprintf doesn't return -1.

Related

Convert from vector<unsigned char> to char* includes garbage data

I'm trying to base64 decode a string, then convert that value to a char array for later use. The decode works fine, but then I get garbage data when converting.
Here's the code I have so far:
std::string encodedData = "VGVzdFN0cmluZw=="; //"TestString"
std::vector<BYTE> decodedData = base64_decode(encodedData);
char* decodedChar;
decodedChar = new char[decodedData.size() +1]; // +1 for the final 0
decodedChar[decodedData.size() + 1] = 0; // terminate the string
for (size_t i = 0; i < decodedData.size(); ++i) {
decodedChar[i] = decodedData[i];
}
vector<BYTE> is a typedef of unsigned char BYTE, as taken from this SO answer. The base64 code is also from this answer (the most upvoted answer, not the accepted answer).
When I run this code, I get the following value in the VisualStudio Text Visualiser:
TestStringÍ
I've also tried other conversion methods, such as:
char* decodedChar = reinterpret_cast< char *>(&decodedData[0]);
Which gives the following:
TestStringÍÍÍýýýýÝÝÝÝÝÝÝ*b4d“
Why am I getting the garbage data at the end of the string? What am i doing wrong?
EDIT: clarified which answer in the linked question I'm using
char* decodedChar;
decodedChar = new char[decodedData.size() +1]; // +1 for the final 0
Why would you manually allocate a buffer and then copy to it when you have std::string available that does this for you?
Just do:
std::string encodedData = "VGVzdFN0cmluZw=="; //"TestString"
std::vector<BYTE> decodedData = base64_decode(encodedData);
std::string decodedString { decodedData.begin(), decodedData.end() };
std::cout << decodedString << '\n';
If you need a char * out of this, just use .c_str()
const char* cstr = decodedString.c_str();
If you need to pass this on to a function that takes char* as input, for example:
void someFunc(char* data);
//...
//call site
someFunc( &decodedString[0] );
We have a TON of functions and abstractions and containers in C++ that were made to improve upon the C language, and so that programmers wouldn't have to write things by hand and make same mistakes every time they code. It would be best if we use those functionalities wherever we can to avoid raw loops or to do simple modifications like this.
You are writing beyond the last element of your allocated array, which can cause literally anything to happen (according to the C++ standard). You need decodedChar[decodedData.size()] = 0;

preprending and appending to a cstring

I have the following string tok_str which is like "default.png" I would like to preprend char ' and append char ' too.
That's what I have done, but the chars are appended and prepended in the wrong places
char *tok_str = const_cast<char*>(mReader->getAttributeValue(pAttrIdx));
char * mod_tok = new char[tok_str_len+2];
mod_tok[0] = '\'';
size_t len = strlen(tok_str);
size_t i;
memmove(mod_tok + len, mod_tok, strlen(mod_tok) + 1);
for (i = 0; i < len; ++i)
{
mod_tok[i] = tok_str[i];
}
char *dup;
char *cstr="'";
sprintf(mod_tok,"%s%s",cstr,(dup=strdup(mod_tok)));
free(dup);
If you want to continue using null-terminated byte strings there are a few things you need to think of and do.
The first is of course the null-terminated part. A string of X characters needs space for X+1 to include the terminator.
The second is that all you need is really a single sprintf (or better yet snprintf) call (once you allocated memory):
char* mod_tok = new char[strlen(tok_str) + 3]; // +2 for the extra characters, +1 for terminator
snprintf(mod_tok, strlen(tok_str) + 3, "'%s'", tok_str);
That is it, now you have added the single quotes in front and at the end of the original string.
There are a couple of things to improve:
usage of const when possible
len vs tok_str_len, use only one.
the memmove done in the middle seems to have no effect on the final result
pay attention to the indexes in the for loop
be aware that strlen doesn't count the NULL terminator
if your code starts to mix new/delete with free try to refactor it
That's my proposal:
//keep it const and protect your data
const char *tok_str = mReader->getAttributeValue(pAttrIdx);
//retrive the len once for all (const, no one is supposed to change it)
const size_t len = strlen(tok_str);
char * mod_tok = new char[len+3]; // 2 "'" + '\0'
mod_tok[0] = '\'';
for (size_t i = 0; i < len; ++i)
{
mod_tok[i+1] =tok_str[i];
}
mod_tok[len+1] = '\'';
mod_tok[len+2] = '\0';
//done.
//later...
delete[] mod_tok;
Enjoy your coding!
Stefano
PS: I agree, though, that a use of std::string is reccomended.

Why does vsnwprintf not translate normal strings to wide strings?

The following code does not produce the expected output. Why?
wchar_t* wchar_t_printf_return(wchar_t* formatstring, ...){
va_list argp;
va_start(argp, formatstring);
int templen = 256;
templen = vsnwprintf(NULL, 0, formatstring, argp)+3;
wchar_t *buffer = (wchar_t *) malloc ((templen+1)*sizeof(wchar_t));
memset(buffer, 0, (templen+1)*sizeof(*buffer));
int retval;
while ((retval = vsnwprintf(buffer, templen, formatstring, argp)) == -1 || (retval >= (templen-1))){
templen = templen &lt&lt 1;
buffer = (wchar_t *) realloc (buffer, (templen+1)*sizeof(wchar_t));
va_end(argp);
va_start(argp, formatstring);
}
va_end(argp);
buffer[templen] = L'\0';
return buffer;
}
int main(){
int i;
char *id = "2923BE84E16CD6AE529049F1F1BBE9EB";
wchar_t *val = wchar_t_printf_return(L"'%s'", id);
printf("%ls\n", val);
}
EDIT: to state more specifically, the printf in main should wrap the id in two single quotes thereby outputting: '2923BE84E16CD6AE529049F1F1BBE9EB'. The purpose of the main here is to illustrate the bug in the function, no more. The function is supposed to be an alternate of the printf family functions which return the result in a newly allocated buffer instead of a preexisting one. This is being run in cygwin compiled natively via gcc-3 with the -mno-cygwin option (aka mingw). Sorry for the confusion!
The %s specifier changes meaning depending on whether you are using a printf or wprintf family function. When used with a wprintf family function, the %s specifier indicates a wide string, but you're passing a narrow string. You need %hs to say "This is a narrow string."
(You seemed to be aware of this because you use %ls to print a wide string with a printf-family function, but you somehow forgot about it when going the other way.)
Try using %S for a translation, not %s.

Modify a char* string in C

I have this:
char* original = "html content";
And want to insert a new
char* mycontent = "newhtmlinsert";
into the "original" above just before </body> tag in the "original".
My new orginal is now:
char* neworiginal = "html content before </body>" + "newhtmlinsert" + "html content after </body>";
Basically i want to take a char* orginal and convert it into a char* neworiginal which has the original content plus new content that i added before the </body> in the "original html content"
here is the modified code, i still need some help:
* original data */
data = _msg_ptr->buff();
data_len = _msg_ptr->dataLen();
/*location of </body> in the original */
char *insert = strstr(data, "</body>");
/*length of the new buffer string */
int length = strlen(data)+strlen(ad_content);
newdata =(char*)malloc(sizeof(char)*length);
memset(newdata, 0, length);
/*copy the original data upto </body> into newdata*/
memcpy(newdata,data,insert-data);
/*now add the ad_content */
strcat(newdata,ad_content);
/*copy the data from </body> to end of original string(data) into newdata */
memcpy(newdata,data,data_len - ending );
how do i implement the the last statement : memcpy(newdata,data,data_len - ending );
i need to copy the remainder of the data from my char* data beginning from an
the very end...how do i correctly compute the "ending" parameter in the memcpy?
here is the c++ version using strings
char *insert = strstr(_in_mem_msg_ptr->buff(), "</body>");//get pointer to </body>
string ad_data = string(_in_mem_msg_ptr->buff(),insert - _in_mem_msg_ptr->buff()) ;//insert the part of _in_mem_msg_ptr->buff() before the </body>
ad_data.append(ad_content); //add the new html content
ad_data.append(_in_mem_msg_ptr->buff(),insert- _in_mem_msg_ptr->buff(),_in_mem_msg_ptr->dataLen()); //remainder of _in_mem_msg_ptr->buff() from and including </body> to the end
Assuming that char* original is composed by two parts, one starts at 0 while the other (html content after) starts at x you can use strcat and memcpy:
int length = strlen(original)+strlen(newcontent)+1;
char *neworiginal = malloc(sizeof(char)*length);
memset(neworiginal, 0, length);
memcpy(neworiginal,original,x*sizeof(char));
strcat(neworiginal,newcontent);
strcat(neworiginal,original+x);
You need to use strcat() for this problem.
Example =
/* strcat example */
#include <stdio.h>
#include <string.h>
int main ()
{
char str[80];
strcpy (str,"these ");
strcat (str,"strings ");
strcat (str,"are ");
strcat (str,"concatenated.");
puts (str);
return 0;
}
Though you need to check the bounds so you can use the bounds variant of strncat().
#include <string.h>
char *strncat(char *restrict s1, const char *restrict s2, size_t n);
Make sure whatever buffer you are appending your string into has enough space to not cause a buffer overflow.
C++ doesn't have + operator for char * strings. You need to use std::string, i.e.
std::string neworiginal = "html content before </body>";
neworiginal += "newhtlminsert";
neworiginal += "..."
Take a look at strstr, strcat and other cstring/string.h functions.
Make sure your char arrays are large enough to hold concatenated strings. Like, you may want to do the following:
char neworiginal[1024];
etc.
The string.h function strcat will concatenate two strings, however it will fail when there is not enough space for the new string. My solution is to make your own version of strcat:
char* myStrCat(const char* str1, const char* str2)
{
char* result;
char* itr1;
char* itr2;
if (str1 == NULL || str2 == NULL)
{
return NULL;
}
result = (char*)malloc(sizeof(char) * (strlen(str1) + strlen(str2) + 1));
itr1 = result;
itr2 = (char*)str1;
while (*itr2 != '\0')
{
*itr1 = *itr2;
itr1++;
itr2++;
}
itr2 = (char*)str2;
while (*itr2 != '\0')
{
*itr1 = *itr2;
itr1++;
itr2++;
}
*itr1 = '\0';
return result;
}
This is kinda ugly, but it gets the job done :)
Attempting to modify the contents of a string literal results in undefined behavior.
You will need to allocate a target buffer (either as an auto variable or by using malloc) that's large enough to hold your final string plus a 0 terminator.
Also, you might want to use sprintf to make life a little easier, such as
sprintf(result, "%s before %s - %s - %s after %s", original,
tag, mycontent, original, tag);

Why is the following C++ code printing only the first character?

I am trying to convert a char string to a wchar string.
In more detail: I am trying to convert a char[] to a wchar[] first and then append " 1" to that string and the print it.
char src[256] = "c:\\user";
wchar_t temp_src[256];
mbtowc(temp_src, src, 256);
wchar_t path[256];
StringCbPrintf(path, 256, _T("%s 1"), temp_src);
wcout << path;
But it prints just c
Is this the right way to convert from char to wchar? I have come to know of another way since. But I'd like to know why the above code works the way it does?
mbtowc converts only a single character. Did you mean to use mbstowcs?
Typically you call this function twice; the first to obtain the required buffer size, and the second to actually convert it:
#include <cstdlib> // for mbstowcs
const char* mbs = "c:\\user";
size_t requiredSize = ::mbstowcs(NULL, mbs, 0);
wchar_t* wcs = new wchar_t[requiredSize + 1];
if(::mbstowcs(wcs, mbs, requiredSize + 1) != (size_t)(-1))
{
// Do what's needed with the wcs string
}
delete[] wcs;
If you rather use mbstowcs_s (because of deprecation warnings), then do this:
#include <cstdlib> // also for mbstowcs_s
const char* mbs = "c:\\user";
size_t requiredSize = 0;
::mbstowcs_s(&requiredSize, NULL, 0, mbs, 0);
wchar_t* wcs = new wchar_t[requiredSize + 1];
::mbstowcs_s(&requiredSize, wcs, requiredSize + 1, mbs, requiredSize);
if(requiredSize != 0)
{
// Do what's needed with the wcs string
}
delete[] wcs;
Make sure you take care of locale issues via setlocale() or using the versions of mbstowcs() (such as mbstowcs_l() or mbstowcs_s_l()) that takes a locale argument.
why are you using C code, and why not write it in a more portable way, for example what I would do here is use the STL!
std::string src = std::string("C:\\user") +
std::string(" 1");
std::wstring dne = std::wstring(src.begin(), src.end());
wcout << dne;
it's so simple it's easy :D
L"Hello World"
the prefix L in front of the string makes it a wide char string.