String allocation problem on each iteration - c++

l have a string like "hello_1_world". And in each iteration l want to increment "1" part. "hello_2_world", "hello_3_world" etc... So l can not use const char* or string_view. l have to allocate new memory in every iteration by using std::string. But, l do not want to because of performance issue. Could you suggest a solution?
So, my code is like below. Guess index is incrementing each time.
std::string value{"hello_" + std::to_string(index) + "_world"};
l tried so many ways. And one of them is like below:
string_view result(value, 39);
And concat something but again. l cant modify string_view

Do you really need a std::string, or will a simple char[] suffice? If so, then try something like this:
// a 32bit positive int takes up 10 digits max...
const int MAX_DIGITS = 10;
char value[6 + MAX_DIGITS + 6 + 1];
for(int index = 0; index < ...; ++index) {
std::snprintf(value, std::size(value), "hello_%d_world", index);
// use value as needed...
}
Alternatively, if you don't mind having leading zeros in the number, then you can update just that portion of the buffer on each iteration:
const int MAX_DIGITS = ...; // whatever you need, up to 10 max
char value[6 + MAX_DIGITS + 6 + 1];
std::strcpy(value, "hello_");
std::strcpy(&value[6 + MAX_DIGITS], "_world");
for(int index = 0; index < ...; ++index) {
std::snprintf(&value[6], MAX_DIGITS, "%0.*d", MAX_DIGITS, index);
// use value as needed...
}
If you really need a std::string, then simply pre-allocate it before the iteration, and then fill in its existing memory during the iteration, similar to a char[]:
const int MAX_DIGITS = 10;
std::string value;
value.reserve(6 + MAX_DIGITS + 6); // allocate capacity
for(int index = 0; index < ...; ++index) {
value.resize(value.capacity()); // preset size, no allocation when newsize <= capacity
std::copy_n("hello_", 6, value.begin());
auto ptr = std::to_chars(&value[6], &value[6 + MAX_DIGITS], index).ptr;
/* or:
auto numWritten = std::snprintf(&value[6], MAX_DIGITS, "%d", index);
auto ptr = &value[6 + numWritten];
*/
auto newEnd = std::copy_n("_world", 6, ptr);
value.resize(newEnd - value.data()); // no allocation when shrinking size
// use value as needed...
}
Alternatively, with leading zeros:
const int MAX_DIGITS = ...; // up to 10 max
std::string value(6 + MAX_DIGITS + 6, '\0');
std::copy_n("hello_", 6, value.begin());
std::copy_n("_world", 6, &value[6 + MAX_DIGITS]);
for(int index = 0; index < ...; ++index) {
std::snprintf(&value[6], MAX_DIGITS, "%0.*d", MAX_DIGITS, index);
// use value as needed...
}

you could use a std::stringstream to construct the string incrementally:
std::stringstream ss;
ss << "hello_";
ss << index;
ss << "_world";
std::string value = ss.str();

Related

Converting char array to uint16_t array C/C++

I've written the below code to convert and store the data from a string (array of chars) called strinto an array of 16-bit integers called arr16bit
The code works. However, i'd say that there's a better or cleaner way to implement this logic, using less variables etc.
I don't want to use index i to get the modulus % 2, because if using little endian, I have the same algorithm but i starts at the last index of the string and counts down instead of up. Any recommendations are appreciated.
// assuming str had already been initialised before this ..
int strLength = CalculateStringLength(str); // function implementation now shown
uint16_t* arr16bit = new uint16_t[ (strLength /2) + 1]; // The only C++ feature used here , so I didn't want to tag it
int indexWrite = 0;
int counter = 0;
for(int i = 0; i < strLength; ++i)
{
arr16bit[indexWrite] <<= 8;
arr16bit[indexWrite] |= str[i];
if ( (counter % 2) != 0)
{
indexWrite++;
}
counter++;
}
Yes, there are some redundant variables here.
You have both counter and i which do exactly the same thing and always hold the same value. And you have indexWrite which is always exactly half (per integer division) of both of them.
You're also shifting too far (16 bits rather than 8).
const std::size_t strLength = CalculateStringLength(str);
std::vector<uint16_t> arr16bit((strLength/2) + 1);
for (std::size_t i = 0; i < strLength; ++i)
{
arr16bit[i/2] <<= 8;
arr16bit[i/2] |= str[i];
}
Though I'd probably do it more like this to avoid N redundant |= operations:
const std::size_t strLength = CalculateStringLength(str);
std::vector<uint16_t> arr16bit((strLength/2) + 1);
for (std::size_t i = 0; i < strLength+1; i += 2)
{
arr16bit[i/2] = (str[i] << 8);
arr16bit[(i/2)+1] |= str[i+1];
}
You may also wish to consider a simple std::copy over the whole dang buffer, if your endianness is right for it.

Self written HMAC function, not working correctly

I wrote the following function to generate HMAC-SHA1 referring https://www.rfc-editor.org/rfc/rfc2104, however, the values I generate seem to differ from the values given on https://www.rfc-editor.org/rfc/rfc2202 and from what I've tested on https://www.freeformatter.com/hmac-generator.html.
For example, the function should be generating de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9 for text "The quick brown fox jumps over the lazy dog" with key "key", but it generates d3c446dbd70f5db3693f63f96a5931d49eaa5bab instead.
Could anyone point out my mistakes?
The function:
const int block_size = 64;
const int hash_output_size = 20;
const int ipadVal = 0x36;
const int opadVal = 0x5C;
std::string HMAC::getHMAC(const std::string &text)
{
// check if key length is block_size
// else, append 0x00 till the length of new key is block_size
int key_length = key.length();
std::string newkey = key;
if (key_length < block_size)
{
int appended_zeros = block_size - key_length;
// create new string with appended_zeros number of zeros
std::string zeros = std::string(appended_zeros, '0');
newkey = key + zeros;
}
if (key_length > block_size)
{
SHA1 sha1;
newkey = sha1(key);
}
// calculate hash of newkey XOR ipad and newkey XOR opad
std::string keyXipad = newkey;
std::string keyXopad = newkey;
for (int i = 0; i < 64; i++)
{
keyXipad[i] ^= ipadVal;
keyXopad[i] ^= opadVal;
}
// get first hash, hash of keyXipad+text
std::string inner_hash = getSHA1(keyXipad + text);
// get outer hash, hash of keyXopad+inner_hash
std::string outer_hash = getSHA1(keyXopad + inner_hash);
// return outer_hash
return outer_hash;
}
edit: In the line
std::string zeros = std::string(appended_zeros, '0');
'0' should be 0 instead : int instead of char. Thanks to #Igor Tandetnik for that.
Ok..so a little look around lead me to HMAC produces wrong results. Turns out, I was doing the same mistake of using hex as ascii.
I used a function to convert the inner_hash from hex to ascii and then everything turned out perfect.
The final version of the function:
std::string HMAC::getHMAC(const std::string &text)
{
// check if key length is block_size
// else, append 0x00 till the length of new key is block_size
int key_length = key.length();
std::string newkey = key;
if (key_length < block_size)
{
int appended_zeros = block_size - key_length;
// create new string with appended_zeros number of zeros
std::cout << "\nAppending " << appended_zeros << " 0s to key";
std::string zeros = std::string(appended_zeros, 0);
newkey = key + zeros;
}
if (key_length > block_size)
{
SHA1 sha1;
newkey = sha1(key);
}
// calculate hash of newkey XOR ipad and newkey XOR opad
std::string keyXipad = newkey;
std::string keyXopad = newkey;
for (int i = 0; i < 64; i++)
{
keyXipad[i] ^= ipadVal;
keyXopad[i] ^= opadVal;
}
// get first hash, hash of keyXipad+text
std::string toInnerHash = keyXipad + text;
std::string inner_hash = getHash(toInnerHash);
// get outer hash, hash of keyXopad+inner_hash
std::string toOuterHash = keyXopad + hex_to_string(inner_hash);
std::string outer_hash = getHash(toOuterHash);
// return outer_hash
return outer_hash;
}
hex_to_string function taken from https://stackoverflow.com/a/16125797/3818617

What is the fastest way to convert unsigned char array to IP string

I need to process a lot of these in (more or less) real-time. The method I'm currently using is not cutting it anymore.
std::string parse_ipv4_address( const std::vector<unsigned char> & data, int start )
{
char ip_addr[16];
snprintf( ip_addr, sizeof(ip_addr), "%d.%d.%d.%d",
data[start + 0], data[start + 1], data[start + 2], data[start + 3] );
return std::string( ip_addr );
}
// used like this
std::vector<unsigned char> ip = { 0xc0, 0xa8, 0x20, 0x0c };
std::string ip_address = parse_ipv4_address( ip, 0 );
std::cout << ip_address << std::endl; // not actually printed in real code
// produces 192.168.32.12
Is there a faster way to do it? And how?
NOTE! Performance is the issue here so this issue is not a duplicate.
Here are the potential candidates that impact performance:
snprintf needs to parse the format string, and performs error handling. Either costs time, to implement features you don't need.
Constructing a std::string object on return is costly. It stores the controlled sequence in freestore memory (usually implemented as heap memory), that is somewhat costly to allocate in C++ (and C).
Use of a std::vector to store a 4-byte value needlessly burns resources. It, too, allocates memory in the freestore. Replace that with char[4], or a 32-bit integer (uint32_t).
Since you don't need the versatility of the printf-family of functions, you might drop that altogether, and use a lookup-table instead. The lookup table consists of 256 entries, each of which holding the visual representation of the byte values 0 through 255. To optimize this, have the LUT contain a trailing . character as well. (Special care needs to be taken, to address endianness. I'm assuming little-endian here.)
A solution might look like this1):
const uint32_t mapping[] = { 0x2E303030, // "000."
0x2E313030, // "001."
// ...
0x2E343532, // "254."
0x2E353532 // "255."
};
alignas(uint32_t) char ip_addr[16];
uint32_t* p = reinterpret_cast<uint32_t*>(&ip_addr[0]);
p[0] = mapping[data[0]];
p[1] = mapping[data[1]];
p[2] = mapping[data[2]];
p[3] = mapping[data[3]];
// Zero-terminate string (overwriting the superfluous trailing .-character)
ip_addr[15] = '\0';
// As a final step, waste all the hard earned savings by constructing a std::string.
// (as an ironic twist, let's pick the c'tor with the best performance)
return std::string(&ip_addr[0], &ip_addr[15]);
// A more serious approach would either return the array (ip_addr), or have the caller
// pass in a pre-allocated array for output.
return ip_addr;
1) Disclaimer: Casting from char* to uint32_t* technically exhibits undefined behavior. Don't use, unless your platform (compiler and OS) provide additional guarantees to make this well defined.
Three Four answers for the price of one.
First, make really, really sure that you're optimizing the right part. Both std::vector and std::string creation involve memory allocations, and cout << could involve file access, graphics, etc!
Second: Don't use vector to represent the 4-bytes of an IP address. Just use char ip[4], or even a 32-bit integer
Third: I'm guessing that you're not dealing with totally random IP addresses. Probably a few hundred or thousand different addresses? In which case, use a std::map<INT32, std::string> as a cache, and just pull the required ones from the cache as required, writing new ones in as needed. If the cache gets too big, just empty it and start over...
Fourth: Consider writing the IP address in Hexadecimal dotted quad notation. This is still accepted by calls like inet_addr() and has several advantages: All fields are fixed width, there are only 8 'characters' to update, and the binary to Hex conversion is usually faster than binary to decimal. https://en.wikipedia.org/wiki/IPv4#Address_representations
Lookup table could be of use here (initialized on program start). I guess you already have profiling configured so I didn't profile solution and wonder what would be the results so please share when you get some.
char LOOKUP_TABLE[256][4];
void init_lookup_table() {
char digits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
for (int i = 0; i < 10; ++i) {
LOOKUP_TABLE[i][0] = digits[i % 10];
LOOKUP_TABLE[i][1] = '\0';
LOOKUP_TABLE[i][2] = '\0';
LOOKUP_TABLE[i][3] = '\0';
}
for (int i = 10; i < 100; ++i) {
LOOKUP_TABLE[i][0] = digits[(i / 10) % 10];
LOOKUP_TABLE[i][1] = digits[i % 10];
LOOKUP_TABLE[i][2] = '\0';
LOOKUP_TABLE[i][3] = '\0';
}
for (int i = 100; i < 256; ++i) {
LOOKUP_TABLE[i][0] = digits[(i / 100) % 10];
LOOKUP_TABLE[i][1] = digits[(i / 10) % 10];
LOOKUP_TABLE[i][2] = digits[i % 10];
LOOKUP_TABLE[i][3] = '\0';
}
}
void append_octet(char **buf, unsigned char value, char terminator) {
char *src = LOOKUP_TABLE[value];
if (value < 10) {
(*buf)[0] = src[0];
(*buf)[1] = terminator;
(*buf) += 2;
}
else if (value < 100) {
(*buf)[0] = src[0];
(*buf)[1] = src[1];
(*buf)[2] = terminator;
(*buf) += 3;
}
else {
(*buf)[0] = src[0];
(*buf)[1] = src[1];
(*buf)[2] = src[2];
(*buf)[3] = terminator;
(*buf) += 4;
}
}
std::string parse_ipv4_address( const std::vector<unsigned char> & data, int start ) {
char ip_addr[16];
char *dst = ip_addr;
append_octet(&dst, data[start + 0], '.');
append_octet(&dst, data[start + 1], '.');
append_octet(&dst, data[start + 2], '.');
append_octet(&dst, data[start + 3], '\0');
return std::string( ip_addr );
}
int main() {
init_lookup_table();
std::vector<unsigned char> ip = { 0xc0, 0x8, 0x20, 0x0c };
std::cout << parse_ipv4_address( ip, 0 ) << std::endl;
}
Other way to improve performance would be to replace string with specialized object. In that case you will be able to implement required I/O methods (my guess is that you need string to print it somewhere) and will be freed from copying on string construction.
UPD on second thought I guess in my code lookup table is out of use so one could just copy code used to build lookup table to append_octet directly making digits global.
Updated code (thanks to MikeMB and Matteo Italia) which also looks very cache friendly
inline void append_octet(char **buf, unsigned char value, char terminator) {
if (value < 10) {
(*buf)[0] = '0' + (value % 10);
(*buf)[1] = terminator;
(*buf) += 2;
}
else if (value < 100) {
(*buf)[0] = '0' + ((value / 10) % 10);
(*buf)[1] = '0' + (value % 10);
(*buf)[2] = terminator;
(*buf) += 3;
}
else {
(*buf)[0] = '0' + ((value / 100) % 10);
(*buf)[1] = '0' + ((value / 10) % 10);
(*buf)[2] = '0' + (value % 10);
(*buf)[3] = terminator;
(*buf) += 4;
}
}
std::string parse_ipv4_address( const std::vector<unsigned char> & data, int start ) {
char ip_addr[16];
char *dst = ip_addr;
append_octet(&dst, data[start + 0], '.');
append_octet(&dst, data[start + 1], '.');
append_octet(&dst, data[start + 2], '.');
append_octet(&dst, data[start + 3], '\0');
return std::string( ip_addr );
}
int main() {
std::vector<unsigned char> ip = { 0xc0, 0x8, 0x20, 0x0c };
std::cout << parse_ipv4_address( ip, 0 ) << std::endl;
}
UPD 2 I guess I found a way to avoid extra copy (altough there's still extra copy on return). Here's versions with look up table and w/o it
#include <string>
#include <iostream>
#include <vector>
std::string LUT[256];
void init_lookup_table() {
for (int i = 0; i < 10; ++i) {
LUT[i].reserve(2);
LUT[i].push_back('0' + i);
LUT[i].push_back('.');
}
for (int i = 10; i < 100; ++i) {
LUT[i].reserve(3);
LUT[i].push_back('0' + (i/10));
LUT[i].push_back('0' + (i%10));
LUT[i].push_back('.');
}
for (int i = 100; i < 256; ++i) {
LUT[i].reserve(4);
LUT[i].push_back('0' + (i/100));
LUT[i].push_back('0' + ((i/10)%10));
LUT[i].push_back('0' + (i%10));
LUT[i].push_back('.');
}
}
std::string parse_ipv4_address_lut( const std::vector<unsigned char> & data, int start ) {
std::string res;
res.reserve(16);
res.append(LUT[data[start + 0]]);
res.append(LUT[data[start + 1]]);
res.append(LUT[data[start + 2]]);
res.append(LUT[data[start + 3]]);
res.pop_back();
return res;
}
inline void append_octet_calc(std::string *str, unsigned char value, char terminator) {
if (value < 10) {
str->push_back('0' + (value % 10));
str->push_back(terminator);
}
else if (value < 100) {
str->push_back('0' + ((value / 10) % 10));
str->push_back('0' + (value % 10));
str->push_back(terminator);
}
else {
str->push_back('0' + ((value / 100) % 10));
str->push_back('0' + ((value / 10) % 10));
str->push_back('0' + (value % 10));
str->push_back(terminator);
}
}
std::string parse_ipv4_address_calc( const std::vector<unsigned char> & data, int start ) {
std::string res;
res.reserve(16);
append_octet_calc(&res, data[start + 0], '.');
append_octet_calc(&res, data[start + 1], '.');
append_octet_calc(&res, data[start + 2], '.');
append_octet_calc(&res, data[start + 3], '\0');
return res;
}
int main() {
init_lookup_table();
std::vector<unsigned char> ip = { 0xc0, 0x8, 0x20, 0x0c };
std::cout << parse_ipv4_address_calc( ip, 0 ) << std::endl;
std::cout << parse_ipv4_address_lut( ip, 0 ) << std::endl;
}
UPD 3 I made some measurements (1 000 000 repeats)
clang++ -O3
orig...done in 5053 ms // original implementation by OP
c_lut...done in 2083 ms // lookup table -> char[] -> std::string
c_calc...done in 2245 ms // calculate -> char[] -> std::string
cpp_lut...done in 2597 ms // lookup table + std::string::reserve + append
cpp_calc...done in 2632 ms // calculate -> std::string::reserve + push_back
hardcore...done in 1512 ms // reinterpret_cast solution by #IInspectable
g++ -O3
orig...done in 5598 ms // original implementation by OP
c_lut...done in 2285 ms // lookup table -> char[] -> std::string
c_calc...done in 2307 ms // calculate -> char[] -> std::string
cpp_lut...done in 2622 ms // lookup table + std::string::reserve + append
cpp_calc...done in 2601 ms // calculate -> std::string::reserve + push_back
hardcore...done in 1576 ms // reinterpret_cast solution by #IInspectable
Note that 'hardcore' solution doesn't equivalent because of leading zeroes.
you can use a lookup table which holds a string for numbers from 0 to 255.
if speed is very important, you can also use inline keyword or maybe a macro for the function.
also you can check sse instructions.
By the way, usually the more primitive your code the faster it is. I would use unsigned char array instead of vector, char array instead of string, memcpy(or even byte by byte copy directly) instead of sprintf.
Here you go...
std::string IP_parse(unsigned char data[4])
{
std::string parsedString = "";
snprintf((char*)parsedString.c_str(), sizeof(char[15]), "%d.%d.%d.%d", data[0], data[1], data[2], data[3]);
return parsedString;
}

FMS attack on WEP in C++

I'm trying to implement the FMS attack on WEP. I understand that the attack takes advantage of the probability of parts of the RC4 sbox not changing to create "known" sbox states to reverse engineer the key. With many samples, the correct key octet should appear more often than noise.
The value that should add to the frequency count is:
where (I think; the notation is not properly defined)
B starts at 0
P.out is the outputted keystream byte
S is the Sbox
j is the "pointer" used in the RC4 key scheduling algorithm
In my code, I am generating 6 million data packets: a constant root key and constant plaintext to simulate constant header, and then encrypting with RC4(IV + root_key).encrypt(plaintext), without discarding the first 256 octets). The (IV, encrypted_data) pairs are run through the get_key function:
uint8_t RC4_ksa(const std::string & k, std::array <uint8_t, 256> & s, const uint16_t octets = 256){
for(uint16_t i = 0; i < 256; i++){
s[i] = i;
}
uint8_t j = 0;
for(uint16_t i = 0; i < octets; i++){
j = (j + s[i] + k[i % k.size()]);
std::swap(s[i], s[j]);
}
return j;
}
std::string get_key(const uint8_t keylen, const std::vector <std::pair <std::string, std::string> > & captured){
std::string rkey = ""; // root key to build
const std::string & pt = header; // "plaintext" with constant header
// recreate root key one octet at a time
for(uint8_t i = 3; i < keylen; i++){
// vote counter for current octet
std::array <unsigned int, 256> votes;
votes.fill(0);
uint8_t most = 0; // most probable index/octet value
// get vote from each "captured" ciphertext
for(std::pair <std::string, std::string> const & c : captured){
const std::string & IV = c.first;
// IV should be of form (i = root key index + 3, 255, some value)
if ((static_cast<uint8_t> (IV[0]) != i) ||
(static_cast<uint8_t> (IV[1]) != 0xff)){
continue; // skip this data
}
const std::string & ct = c.second;
const std::string key = IV + rkey;
// find current packet's vote
std::array <uint8_t, 256> sbox; // SBox after simulating; fill with RC4_ksa
uint8_t j = RC4_ksa(key, sbox, i); // simulate using key in KSA, up to known octets only
uint8_t keybytestream = pt[i - 3] ^ ct[i - 3];
// S^-1[keybytestream]
uint16_t sinv;
for(sinv = 0; sinv < 256; sinv++){
if (sbox[sinv] == keybytestream){
break;
}
}
// get mapping
uint8_t ki = sinv - j - sbox[i];
// add to tally and keep track of which tally is highest
votes[ki]++;
if (votes[ki] > votes[most]){
most = ki;
}
}
// select highest voted value as next key octet
rkey += std::string(1, most);
}
return rkey;
}
I am getting keys that are completely incorrect. I feel that the error is probably a one-off error or something silly like that, but I have asked two people to look at this, and neither person has managed to figure out what is wrong.
Is there something that is blatantly wrong? If not, what is not-so-obviously wrong?

How to pass a delimited txt file to a function that takes constant char *?

I have an API function that takes constant char * as an input. I have to create a delimited text file which is the input of the function like:
193.875 0.0 0.0 2
193.876 0.0 0.0 2
193.877 0.0 0.0 2
193.878 0.0 0.0 2
193.879 0.0 0.0 2
193.880 0.0 0.0 2
193.881 0.0 0.0 2
the support guy of the software told me that I can create and save every line of this file by using sprintf() so I used it like:
sprintf(wsp,"%.3f\t0.0\t0.0\t%d\n", start_freq, z);
and after putting this line in loop I saved every created wsp in an array of string:
for (int j = 0; j < start; j++){
sprintf(wsp,"%.3f\t0.0\t0.0\t%d\n", start_freq, z);
start_freq = start_freq + 0.001;
wspfile[j] = wsp;
}
now I have a file with the required format but comes in array of string. My question is after creating the array how can I pass this array as a constant char * or how can I convert it to constant char *
You could make wspFile an std::string instead of an array. Then instead of
wspFile[j]=wsp;
you would have
wspFile+=wsp;
Then to get the const char* version you would call
wspFile.c_str();
I hope I have not misunderstood your question. I start assuming I have an array of N char*, namely wspfile[], right? Now, I want to convert this array to a single string:
char *join(char **strings, int N)
{
//Step 1: find out the total amount of memory we need
int i, total = 0;
for (i = 0; i < N; i++) {
total += strlen(strings[i]);
}
//Step 2. Allocate resulting string.
char *str = malloc(total + 1); //Alloc 1 more byte for end \0
//Step 3. Join strings.
char *dst = str;
for (i = 0; i < N; i++) {
char *src = strings[i];
while(*src) *dst++ = *src++;
}
*dst = 0; //end \0
return str; //don't forget to free(str) !
}
Then, in your code:
char *s = join(wspfile, N);
/* do whatever with `s`*/
free(s);
It seems that you know the size of your data upfront, so you could do it like this:
std::vector<char> wspfile(start * wsp_max_length);
// C-ish way:
/* char* wspfile = (char*) malloc(start * wsp_max_length) */
for (int j = 0; j < start; j++) {
sprintf(wsp + (wsp_max_length * j), "%.3f\t0.0\t0.0\t%d\n", start_freq, z);
start_freq = start_freq + 0.001;
}
your_API_func(&wspfile[0]);
In more C++ like fashion:
#include <vector>
#include <sstream>
#include <string>
#include <iomanip> // for setprecision()
std::vector<char> wspfile;
double start_freq = 193.875;
for (int j = 0; j < start; ++j, start_freq += 0.0001) {
std::ostringstream oss;
oss << std::setprecision(3)
<< start_freq
<< "\t0.0\t0.0\t"
<< z << "\n\0"; // your version with sprintf adds '\0', too,
// although I'm pretty sure you don't want it
std::string wsp = oss.str();
wspfile.insert(wspfile.end(), wsp.begin(), wsp.end());
}
your_API_func(&wspfile[0]);