How do I convert a fixed byte array to a String in managed c++/cli ?
For example I have the following Byte array.
Byte byte_data[5];
byte_data[0]='a';
byte_data[1]='b';
byte_data[2]='c';
byte_data[3]='d';
byte_data[4]='e';
I have tried the following code
String ^mytext=System::Text::UTF8Encoding::UTF8->GetString(byte_data);
I get the following error:
error C2664: 'System::String ^System::Text::Encoding::GetString(cli::array<Type,dimension> ^)' : cannot convert parameter 1 from 'unsigned char [5]' to 'cli::array<Type,dimension> ^'
Arm yourself with some knowledge about casting between pointers to signed and unsigned types and then you should be set to use String::String(SByte*, Int32, Int32). It might also pay to read the Remarks on the page, specifically around encoding.
I've reproduced the sample from the page here:
// Null terminated ASCII characters in a simple char array
char charArray3[4] = {0x41,0x42,0x43,0x00};
char * pstr3 = &charArray3[ 0 ];
String^ szAsciiUpper = gcnew String( pstr3 );
char charArray4[4] = {0x61,0x62,0x63,0x00};
char * pstr4 = &charArray4[ 0 ];
String^ szAsciiLower = gcnew String( pstr4,0,sizeof(charArray4) );
// Prints "ABC abc"
Console::WriteLine( String::Concat( szAsciiUpper, " ", szAsciiLower ) );
// Compare Strings - the result is true
Console::WriteLine( String::Concat( "The Strings are equal when capitalized ? ", (0 == String::Compare( szAsciiUpper->ToUpper(), szAsciiLower->ToUpper() ) ? (String^)"TRUE" : "FALSE") ) );
// This is the effective equivalent of another Compare method, which ignores case
Console::WriteLine( String::Concat( "The Strings are equal when capitalized ? ", (0 == String::Compare( szAsciiUpper, szAsciiLower, true ) ? (String^)"TRUE" : "FALSE") ) );
Here is one option:
array<Byte>^ array_data = gcnew array<Byte>(5);
for(int i = 0; i < 5; i++)
array_data[i] = byte_data[i];
System::Text::UTF8Encoding::UTF8->GetString(array_data);
Not compiled but I think you get the idea.
Or use the String constructor, as indicated by #ta.speot.is, with encoding set to System.Text::UTF8Encoding.
For those interested in another working solution. I used the notes of ta.speot.is and developed a working solution,You should be able to use this solution or that provided by Rasmus.
Byte byte_data[5];
byte_data[0]='a';
byte_data[1]='b';
byte_data[2]='c';
byte_data[3]='d';
byte_data[4]='e';
char *pstr3 = reinterpret_cast<char*>(byte_data);
String^ example1 = gcnew String( pstr3 );//Note: This method FAILS if the string is not null terminated
//After executing this line the string contains garbage on the end example1="abcde<IqMŸÖð"
String^ example2 = gcnew String( pstr3,0,sizeof(byte_data)); //String Example 2 correctly contains the expected string even if it isn't null terminated
Related
I have this string in my C++ GNU ARM embedded system:
char* TempStr = "pressure 0.85";
I need the number value stored as a separate float variable called presmax.
Up until now the number to be parsed has always been an integer, so I could use sscanf without any issues. However, as I have read about extensively on the web (and experienced first hand), sscanf doesn't typically work on floats in embedded systems (without some extensive configuration/loss of flash space).
I'm wondering if anyone has any suggestions. Perhaps I could parse the "0.85" as a char array? I'm not quite sure how to do that, though it would allow me to use atof() to turn it into a float, as I've done elsewhere in the program.
I realize the other option is to write a function, however I'm quite an amateur programmer so if there's a more robust/time effective solution I'd best take it.
UPDATE:
In case it helps, TempStr is a string copied from a .txt file on an SD card using FatFs. Here's the full code that reads two lines and stores the results in TempStr each time. I parse the string into its respective variable each time TempStr is stored:
FILINFO fno;
FIL fsrc;
int FileEnd = 0;
int CurrentLine = 0;
int pressmax = 0;
int timemax = 0;
char* TempStr;
WCHAR CharBuffer[100];
res = f_stat("config.txt", &fno); //check for config.txt file
res = f_open(&fsrc, "config.txt", FA_READ | FA_OPEN_ALWAYS); //open config.txt file
//first line
TempStr = f_gets((char*)CharBuffer, sizeof(fsrc), &fsrc);
CurrentLine ++;
FileEnd = FileEnd + strlen(TempStr) + 1;
//sscanf(TempStr, "%*s %i", &presmax); //what I did when presmax was an int
//second line
while ((f_eof(&fsrc) == 0)){
TempStr = f_gets((char*)CharBuffer, sizeof(fsrc), &fsrc);
CurrentLine ++;
FileEnd = FileEnd + strlen(TempStr) + 1;
}
//sscanf(TempStr, "%*s %i", &timemax);
Using GNU ARM Build tools on an STM32L w/Eclipse.
If you are guaranteed that your input will be in the form of
text floating_point_number
then once you have TempStr you can advance a pointer through it until you reach the space, and then go one position further to get to the floating point part of the string. Then you pass that pointer to atof to get the value out of the remainder of string. That would look like
char* fp = TempStr;
while (*fp != ' ') ++fp; // get to the space
double value = atof(++fp); // advance to floating point part and pass to atof
If you don't need TempStr after you get the value then you can get rid of fp and just use
while (*TempStr != ' ') ++TempStr ; // get to the space
double value = atof(++TempStr); // advance to floating point part and pass to atof
It can be done as follows:
float presmax = (float)atof( strchr( TempStr, ' ' ) ;
The cast is only necessary because your question specifically asks for float and atof() returns a double. The cast would be implicit in any event, so:
float presmax = atof( strchr( TempStr, ' ' ) ;
is also acceptable.
strchr() returns a pointer to the first space character, and atof() ignores any leading space. If your config file might use a TAB character, then:
float presmax = (float)atof( strpbrk( TempStr, " \t" ) ;
It will fail if either strchr() or strpbrk() return NULL when the delimiter is not found, so you might make it more robust thus:
#define PRESMAX_DEFAULT 1.0f
const char* prestr = strchr( TempStr ) ;
float presmax = prestr == NULL ? PRESMAX_DEFAULT : (float)atof( prestr ) ;
I am trying to convert CString to LPCWSTR and it works well. But something went wrong in the processing of the code.
I want to copy a directory to another path so I am using SHFILEOPSTRUCT:
HWND console = GetConsoleWindow();
SHFILEOPSTRUCT s = { 0 };
s.hwnd = console;
s.wFunc = FO_COPY;
s.fFlags = FOF_SILENT;
CString _folderName("a6_töüst-Oa5Z.OZS-CI5O5235"),
firstPath("C:\\ORTIM-Daten\\a5Pc 2.0.3\\Temp\\"),
lastPart("\\Documents\\*\0"),
firstPathDest("C:\\ORTIM-Daten\\a5Pc 2.0.3\\"),
lastPartDest("Documents\\"),
_folderNameDest("a6_töüst-Oa5Z.OZS-CI5O5235\0");
CString cstrTemp = firstPath + _folderName + lastPart,
cstrTempDest = firstPathDest + lastPartDest + _folderNameDest;
s.pTo = cstrTempDest /*_TEXT("C:\\ORTIM-Daten\\a5Pc 2.0.3\\Documents\\a6_töüst-Oa5Z.OZS-CI5O5235\0")*/;
s.pFrom = cstrTemp /*_TEXT("C:\\ORTIM-Daten\\a5Pc 2.0.3\\Temp\\a6_töüst-Oa5Z.OZS-CI5O5235\\Documents\\*\0")*/;
SHFileOperation(&s);
When I am using CString directly, the copy operation doesn't work, but when I use the _TEXT() macro (as in the comments) to assign the LPCWSTR members in the struct everything works.
EDIT 1
In both variants of source and destination paths the code compiles.
In this variant, the code compiles and does the copy operation:
s.pTo = _TEXT("C:\\ORTIM-Daten\\a5Pc 2.0.3\\Documents\\a6_töüst-Oa5Z.OZS-CI5O5235\0");
s.pFrom = _TEXT("C:\\ORTIM-Daten\\a5Pc 2.0.3\\Temp\\a6_töüst-Oa5Z.OZS-CI5O5235\\Documents\\*\0");
In the other variant, which I actually need, the code compiles too, but the copy operation doesn't take place:
s.pTo = cstrTempDest;
s.pFrom = cstrTemp;
SHFILEOPSTRUCT expects strings ending with two NUL characters, but NUL terminated strings by definition end with one and any additional NUL characters are ignored by CString methods that don't take explicit length argument.
You can force double NUL by adding one manually:
CString cstrTempDest = firstPathDest + lastPartDest + _folderNameDest;
// *** Add NUL manually ***
cstrTempDest.AppendChar( 0 );
s.pTo = cstrTempDest;
// For debuging - verify resulting string with example.
TCHAR* test = _TEXT("C:\\ORTIM-Daten\\a5Pc 2.0.3\\Documents\\a6_töüst-Oa5Z.OZS-CI5O5235\0");
// +2 because we want to check two NULs at end.
ASSERT( memcmp( s.pTo, test, (_tcslen(test)+2)*sizeof(TCHAR) ) == 0 );
Alternative solution can use methods with explicit length argument:
CString cstrTempDest = firstPathDest + lastPartDest
+ CString(_folderNameDest, _tcslen(_folderNameDest)+1);
If your project is configured to use unicode character set, call CString constructors with wide strings:
CString _folderName(_T("a6_töüst-Oa5Z.OZS-CI5O5235")),
firstPath(_T("C:\\ORTIM-Daten\\a5Pc 2.0.3\\Temp\\"))
...
CString in unicode mode automatically converts narrow strings to wide ones, but it can fail when threre is discrepancy between runtime and development codepages. If you plan to go Unicode and never look back, throw away _TEXT, TEXT and _T macros and just use wide literals:
CString _folderName( L"a6_töüst-Oa5Z.OZS-CI5O5235" ),
firstPath( L"C:\\ORTIM-Daten\\a5Pc 2.0.3\\Temp\\" )
...
You should also check SHFileOperation return value.
The answer of user msp0815 on creating double null ended CString solves your issue.
// strings must be double-null terminated
CString from(cstrTemp + (TCHAR)'\0');
PCZZTSTR szzFrom= from;
s.pFrom= szzFrom;
CString dest(cstrTempDest + (TCHAR)'\0');
PCZZTSTR szzDest= dest;
s.pTo= szzDest;
I generally don't use LPCWSTR that much but here is my idea:
CString TestCSTR = "Hello world";
LPCWSTR TestLPC;
TestLPC = (LPCWSTR)_TEXT(TestCSTR.GetString());
It works as expected in fact the variable TestLPC holds "Hello world" or to be more precise a long pointer to it. It should be possible to remove _TEXT without consequences but I'm not sure, the result is the same btw.
I'm using GetOpenFileName function from Winapi, and I'm applying filter to the select file dialog.
THIS works perfectly:
LPSTR mfilter = "Filter\0*.PDF\0";
ofn.lpstrFilter = mfilter;
if(GetOpenFileName(&ofn)){
...
THIS fails (dialog opens but no filters apply):
string mfilter = "Filter\0*.PDF\0";
ofn.lpstrFilter = mfilter.c_str();
if(GetOpenFileName(&ofn)){
...
I need to use std:string because I'm getting the file extension via parameters and this type facilitates the concatenation but I'm getting incompatibility issues...
This would be my code if it worked as expected (IT FAILS the same as previous example):
const char * ext = &(4:); //Ampersand parameter (from CA Plex) It contains "PDF"
string mfilter = "Filter\0*." + ext + "\0"; //Final string: Filter\0*.PDF\0;
ofn.lpstrFilter = mfilter.c_str();
When I use this method, I'm getting runtime exception:
string mf;
mf.append("Filter")
.append('\0')
.append("*.pdf")
.append('\0');
ofn.lpstrFilter = mf.c_str();
With
string mfilter = "Filter\0*.PDF\0";
you are calling an std::string contructor, which terminates the string at the first \0.
The following code:
string mfilter = "Filter\0*.PDF\0";
cout << "string:" << mfilter << " len: " << mfilter.length() << endl;
prints
string: Filter len: 6
The string is only constructed until the first \0 terminator. Do the string is only composed of the word "Filter".
The GetOpenFileName function uses TCHARs, and TCHARs become WCHARs in case of UNICODE character set is used.
Here's an example:
std::wstring getOpenFileName(HWND hWnd, const std::wstring& sFilter)
{
wchar_t buffer[MAX_PATH] = L"";
OPENFILENAMEW ofn = {0};
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = hWnd;
ofn.lpstrFilter = sFilter.c_str();
ofn.nFilterIndex = 1;
ofn.lpstrFile = buffer;
ofn.nMaxFile = MAX_PATH;
ofn.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST;
if( !::GetOpenFileNameW( &ofn ) )
return L"";
return buffer;
}
If you want to parametrize lpstrFilter based on std::wstring you can just use wstring::c_str() to get LPCTSTR which is const wchar* in case of UNICODE.
IMPORTANT: The problem is that the std::wstring constructor that takes a const wchar* assumes the input is a C string. C strings are '\0' terminated and thus parsing stops when it reaches the '\0' character. To compensate for this you need to use the constructor that takes two parameters a pointer to the char array and a length.
You can also use string::push_back() method to append NULLs.
std::wstring sFilter = L"PDF Files";
sFilter.push_back('\0');
sFilter.append(L"*.pdf");
sFilter.push_back('\0');
string mfilter = "Filter\0*.PDF\0";
This calls a std::basic_string constructor that uses a null-terminated string. It will stop parsing the string literal at "Filter".
Try this one instead:
string mfilter( "Filter\0*.PDF", 13 ); // need double null at end
This calls a std::basic_string constructor that uses "the first count characters of character string pointed to by s. s can contain null characters."
You have to either count the characters yourself, or write wrapper code if you encounter this problem more often.
Related: std::basic_string constructors.
As for your runtime error:
string mf;
mf.append("Filter")
.append('\0')
.append("*.pdf")
.append('\0');
append() does not have an overload for a single character type. You are probably hitting the const CharT* s overload, with a null pointer.
Use either append( 1, '\0' ) or append( "", 1 ), either of which should append a null byte.
I'm implementing a system that uses libcrafter and crypto++ to transmit specific frames on the network. But the problem I'm stuck with isn't at this level at all.
It's about conversion between types used in these libraries.
1) At the emission (solved)
I'm trying to convert the Crafter::byte array to a std::string, in order to put this message into a network frame (as an initialization vector for an AES encryption/decryption).
Moreover, the iv must be zeroed, and I can't initialize it properly (despite the answers here or there).
EDIT : to initialize it to 00, I had to do it in hexadecimal : 0x30. And to convert it to a std::string I had to provide the length ie ivLen2 (thanks for the answers).
Here's what I do :
const int ivLen2 = 2;
std::string encrypted_message("whatever");
Crafter::byte iv[ivLen2]={0x30, 0x30}; // crypto salt of 2 bytes at 0.
std::string ivStr( reinterpret_cast< char const* >(iv), ivLen2 ) ;
string mess2send = ivStr + encrypted_message;
And if I display them, with this :
cout<<"iv[0] : "<<iv[0]<<endl; // display 0
cout<<"mess2send : "<<mess2send<<endl; // display 00whatever
Why don't I simply create a zeroed string and send it ? In order to have generic functions, and a re-usable code.
2) At the reception (pending)
Without surprises I have to do the opposite. I get a iv and the message concatenated within a vector<byte>* payload, and I have to extract the iv as a byte array, and the message within a string.
The message isn't actually the problem, given that std::string is close to vector.
Here's what I tempt to retrieve the iv :
Crafter::byte iv[ ivLen2 ];
for (int i = 0; i < ivLen2; i++)
{
iv[i] = (byte)payload->at(i);
}
std::string iv_rcv( reinterpret_cast< char const* >(iv) ) ;
And to display them, I do (in the same loop) :
cout<<iv[i];
But it gives me a non-ASCII character.
I've also tried this (following this and this answers) :
Crafter::byte* iv;
std::string iv_rcv( payload->begin(), payload->begin()+ivLen2 ) ;
iv = (byte*)iv_rcv.c_str();
But it doesn't give me the supposed initialized values...
Does anybody have a clue ? Is my code wrong ?
I don't think this will work:
const int ivLen2 = 2;
std::string encrypted_message("whatever");
Crafter::byte iv[ivLen2]={0x00, 0x00}; // crypto salt of 2 bytes
std::string ivStr( reinterpret_cast< char const* >(iv) ) ;
How does the std::string know how much data to copy from the iv pointer?
You have to use a constructor that takes the length of the data like:
std::string ivStr( reinterpret_cast< char const* >(iv), ivLen2 ) ;
The pointer only constructor is for specifically encoded strings that are terminated by a null character. Unless you are using one of those you must pass the length.
Try this:
const int ivLen2 = 2;
std::string encrypted_message("whatever");
Crafter::byte iv[ivLen2]={0x00, 0x00}; // crypto salt of 2 bytes
std::string ivStr( reinterpret_cast< char const* >(iv), ivLen2 ) ;
std::string mess2send = ivStr + encrypted_message;
std::cout << (int)mess2send[0] << (int)mess2send[1] << mess2send.substr(2) << '\n';
I want the following code to remove a leading zero from a price (0.00 should be cut to .00)
QString price1 = "0.00";
if( price1.at( 0 ) == "0" ) price1.remove( 0 );
This gives me the following error: "error: conversion from ‘const char [2]’ to ‘QChar’ is ambiguous"
The main issue is that Qt is seeing "0" as a null-terminated ASCII string, hence the compiler message about const char[2].
Also, QString::remove() takes two arguments. So you code should be:
if( price1.at( 0 ) == '0' ) price1.remove( 0, 1 );
This builds and runs on my system (Qt 4.7.3, VS2005).
Try this:
price1.at( 0 ) == '0' ?
The problem is that the 'at' function returns a QChar which is an object that can't be compared to the native char/string "0". You have a few choices, but I'll just put two here:
if( price1.at(0).toAscii() == '0')
or
if( price1.at(0).digitValue() == 0)
digitValue returns -1 if the char is not a digit.
QString s("foobar");
if (s[0]=="f") {
return;
}
QChar QString::front() const Returns the first character in the
string. Same as at(0).
This function is provided for STL compatibility.
Warning: Calling this function on an empty string constitutes
undefined behavior.
http://doc.qt.io/qt-5/qstring.html#front
QString s("foobar");
/* If string is not empty or null, check to see if the first character equals f */
if (!s.isEmpty() && s.front()=="f") {
return;
}