Now I have a char array with the mac address stored in:
char mac_addr[6];
And I sprintf it into another char array:
char cmdstr[64];
sprintf(cmdstr, "MAC: %2x:%2x:%2x:%2x:%2x:%2x;",
mac_addr[0], mac_addr[1], mac_addr[2],
mac_addr[3], mac_addr[4], mac_addr[5]);
When I print cmdstr, it looks like this:
MAC: 08:10:76:10:26:21;
Then I send the cmdstr to a remote server, there is a parse function to parse this char array. After the cmdstr is parsed, the six parts separated by a : are stored in a multi char array:
char mac[6][10];
With:
char mac[0] = "08"
char mac[1] = "10"
char mac[2] = "76"
char mac[3] = "10"
char mac[4] = "26"
char mac[5] = "21"
Now, on the server side, how can I re-convert each part of the mac address to char and make it possible that the whole mac address can be stored in a char array like this?
char my_mac[6];
With:
my_mac[0] = '08'
my_mac[1] = '10'
my_mac[2] = '76'
my_mac[3] = '10'
my_mac[4] = '26'
my_mac[5] = '21'
Many thanks!
Edit:
Sorry I think I described something wrongly, the text '08' itself should not stored in my_mac[0]. Actually when I gdb the program, I found that:
(gdb) p mac_addr[0]
$15 = 8 '\b'
(gdb) p mac_addr[1]
$16 = 16 '\020'
(gdb) p mac_addr[2]
$17 = 118 'v'
(gdb) p mac_addr[3]
$18 = 16 '\020'
(gdb) p mac_addr[4]
$19 = 38 '&'
(gdb) p mac_addr[5]
$20 = 33 '!'
I think I should convert the mac[6][10] to a char array just like above.
You can use strtol function in stdlib.h
char *dummy;
for (int i = 0; i < 6; i++) {
my_mac[i] = strtol(mac[i], &dummy, 16);
}
Related
server -> AUTH GateKeeper S :GKSSP\0\0\0\0\0\0\0\0\0r!W\tvM
Client -> AUTH GateKeeper S :GKSSP\0\0\0\0\0\0\0\0\0"g#çójDî3(ƒP¡Á"
VB.NET tcp code:
Do While Stream.CanRead
responseData = Trim(System.Text.Encoding.UTF8.GetString(data2, 0, bytes))
Feed = responseData.Split(Chr(13), Chr(10))
Dim datax As [Byte]()
For Each line As String In Feed
If line <> "" Then
Select Case UCase(Split(line.Trim, " ")(0))
Case "AUTH"
If (Split(line, " ")(2) = "S") And (Split(line, " ")(3) <> ":OK") Then
ChOK = ":GKSSP\0\0\0" & Chr(2) & "\0\0\0" & Chr(3) & "\0\0\0" & Challenge_1(Mid(line, InStr(line, "\0\0\0\0\0\0") + Len("\0\0\0\0\0\0"))) & "Sm(" &
HexToAsc("e4") & "HS" & HexToAsc("c1") & "M" & HexToAsc("847f8293f98d") & "UC"
message = "AUTH GateKeeper S " & ChOK & vbCrLf
VB.NET challenge functions
Public Function Challenge_1(Challenge As String) As String
Dim c1 As String, a1 As String, c2 As String, a2 As String
c1 = "edp{}e|wxrdse}}u666666666666666666666666666666666666666666666666" + Challenge
a1 = HexToAsc(GetIRC7PWD(c1))
Dim Aaah As New String("\"c, 48)
c2 = HexToAsc("0f0e1a11170f161d12180e190f17171f") & Aaah & a1
a2 = HexToAsc(GetIRC7PWD(c2))
Challenge_1 = a2
End Function
Public Function GetIRC7PWD(source As String)
Dim md5Hash As MD5 = MD5.Create()
' Dim source As String = "edp{}e|wxrdse}}u666666666666666666666666666666666666666666666666"
Dim data As Byte() = md5Hash.ComputeHash(Encoding.Default.GetBytes(source))
Dim sBuilder As New StringBuilder()
Dim i As Integer
For i = 0 To data.Length - 1
sBuilder.Append(data(i).ToString("x2"))
Next i
Return sBuilder.ToString()
End Function
The above code authenticates successfully.
My C++ code works fine, until it reads data sent from the AUTH and MD5's it. However, it creates the wrong MD5 hash:
while (true)
{
ZeroMemory(buff, 1024);
int bytesReceived = NetDll_recv(XNCALLER_SYSAPP,Sock, buff, 1024, 0);
if (bytesReceived == SOCKET_ERROR)
{
}
if (bytesReceived > 0) {
std::string Recieved(buff, bytesReceived);
std::stringstream iss(Recieved);
while(iss.good())
{
std::string SingleLine;
getline(iss,SingleLine);
if (!SingleLine.empty()) {
stringstream ss(SingleLine);
string s;
int xUp = 1;
vector <string> tokens;
while (getline(ss, s, ' ')) {
tokens.push_back(s);
xUp++;
}
if (tokens[0] == "AUTH" && tokens[2] == "S") {
MD5 md5;
string ChOK3 = SingleLine.substr(46);
string ChallengeCode = "edp{}e|wxrdse}}u666666666666666666666666666666666666666666666666" + ChOK3;
char* cz = const_cast<char*>(ChallengeCode.c_str());
string g1 = md5.digestString( cz );
string a1 = hexToASCII(g1);
int n = 48;
char cx = '\\';
string c2 = hexToASCII("0f0e1a11170f161d12180e190f17171f") + std::string(n, cx) + a1;
char* c = const_cast<char*>(c2.c_str());
string a2 = md5.digestString( c );
string a3 = hexToASCII(a2);
//string ChOK4 = ChOK + a2 + "Sm(" + hexToASCII("e4") + "HS" + hexToASCII("c1") + "M" + hexToASCII("847f8293f98d") + "UC\r\n";
string ChOK4 = "AUTH GateKeeper S :GKSSP\\0\\0\\0\x02\\0\\0\\0\x03\\0\\0\\0" + a3 + "Sm(" + hexToASCII("e4") + "HS" + hexToASCII("c1") + "M" + hexToASCII("847f8293f98d") + "UC\r\n";
const char *cstr = ChOK4.c_str();
NetDll_send(XNCALLER_SYSAPP, Sock,ChOK4.c_str(),ChOK4.length(), 0);
}
It looks like my code is the same.
Is it because the characters are UTF-16? How can I read the buffer in UTF-16 so that I can properly MD5 the string?
The two codes are NOT doing the same thing, which is why they are producing different results. Differences are highlighted below:
While reading from the socket:
the VB code is:
reading arbitrary bytes (without regard to message boundaries)
converting the bytes from UTF-8 to a UTF-16 string (without regard to codeunit boundaries)
trimming the string
splitting the string on line breaks
parsing each line
the C++ code is:
reading arbitrary bytes (without regard to message boundaries)
converting the bytes as-is to a std::string (without regard to encoding)
splitting the string on line breaks (without trimming it first)
parsing each line
Up to this point, given the data shown, the results are logically the same for both codes (though technically different layouts in memory), even though they are being processed differently. But even up to this point, both codes are NOT handling the socket data adequately, and there IS potential for data corruption and data loss here.
Now, assuming no corruption/loss has actually occurred, then for the actual AUTH command:
the VB code is:
extracting the challenge from position 37, after the first "\0\0\0\0\0\0" substring (thus, the extracted challenge is "\0\0\0r!W\tvM")
AUTH GateKeeper S :GKSSP\0\0\0\0\0\0\0\0\0r!W\tvM
^ ^ ^
1 25 37
converting the challenge from UTF-16 to ANSI bytes
calculating an MD5 for those bytes
calculating a 2nd MD5 based on the 1st MD5
creating a response for the 2nd MD5
the C++ code is:
extracting the challenge from fixed index 46 (position 47) (thus, the extracted challenge is "tvM")
AUTH GateKeeper S :GKSSP\0\0\0\0\0\0\0\0\0r!W\tvM
^ ^ ^ ^
0 24 36 46
getting the challenge's raw UTF-8 bytes
calculating an MD5 for those bytes
calculating a 2nd MD5 based on the 1st MD5
creating a response for the 2nd MD5
So, the biggest issues I see that you need to fix are the following:
in both languages, fix the socket reading logic to avoid data loss. Right now, you are extracting all bytes from the socket and throwing away any incomplete lines that are waiting for more bytes to arrive. You need to save all raw bytes from the socket into an intermediate buffer first, and then extract only complete lines from that buffer, leaving behind incomplete lines in the buffer so they can be finished on subsequent reads.
on the VB side, for ASCII-only data (as you have shown), the conversion from UTF-8 to UTF-16 to ANSI is loss-less, but for non-ASCII data this will be lossy. Consider converting the UTF-16 data back to UTF-8 instead of ANSI, to match the C++ code.
on the C++ side, fix the code to extract the server's challenge from the correct string position to match the VB code.
Let's imagine I have
String x = "hello there";
So I can print it from index e.g. 1 as:
Serial.println(x.substring(1));
ello there
I wanna do the same with
char x[] = "hello there";
Any ideas? (Except using loops to print char by char)
You can use the & operator to get the string after the desired index like this:
Serial.println(&x[1]);
I have problem with getting out a character or characters of a string in C++.
It was easy in python, for example I could take the first block of a string like this:
x = "Hello Word"
p = x[0]
now the H character would save in p.
As mentioned, surely you mean a char (character?)
std::string x = "Hello Word";
char p = x[0]; //p now contains 'H'
See http://en.cppreference.com/w/cpp/string/basic_string for more detail (thanks for suggestion of link)
For example if the string is:
XYZ ::[1][20 BB EC 45 40 C8 97 20 84 8B 10]
The output should be:
20 BB EC 45 40 C8 97 20 84 8B 10
int main()
{
char input = "XYZ ::[1][20 BB EC 45 40 C8 97 20 84 8B 10]";
char output[500];
// what to write here so that i can get the desired output as:
// output = "20 BB EC 45 40 C8 97 20 84 8B 10"
return 0;
}
In C, you could do this with a scanset conversion (though it's a bit RE-like, so the syntax gets a bit strange):
sscanf(input, "[%*[^]]][%[^]]]", second_string);
In case you're wondering how that works, the first [ matches an open bracket literally. Then you have a scanset, which looks like %[allowed_chars] or %[^not_allowed_chars]. In this case, you're scanning up to the first ], so it's %[^]]. In the first one, we have a * between the % and the rest of the conversion specification, which means sscanf will try to match that pattern, but ignore it -- not assign the result to anything. That's followed by a ] that gets matched literally.
Then we repeat essentially the same thing over again, but without the *, so the second data that's matched by this conversion gets assigned to second_string.
With the typo fixed and a bit of extra code added to skip over the initial XYZ ::, working (tested) code looks like this:
#include <stdio.h>
int main() {
char *input = "XYZ ::[1][20 BB EC 45 40 C8 97 20 84 8B 10]";
char second_string[64];
sscanf(input, "%*[^[][%*[^]]][%[^]]]", second_string);
printf("content: %s\n", second_string);
return 0;
}
Just find the second [ and start extracting (or just printing) until next ]....
You can use string::substr if you are willing to convert to std::string
If you don't know the location of brackets, you can use string::find_last_of for the last bracket and again string::find_last_of to find the open bracket.
Well, say, your file looks like this:
XYZ ::[1][20 BB EC 45 40 C8 97 20 84 8B 10]
XYZ ::[1][Maybe some other text]
XYZ ::[1][Some numbers maybe: 123 98345 123 9-834 ]
XYZ ::[1][blah-blah-blah]
The code that will extract the data will look something like this:
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
//opening the file to read from
std::ifstream file( "in.txt" );
if( !file.is_open() )
{
cout << "Cannot open the file";
return -1;
}
std::string in, out;
int blockNumber = 1;//Which bracket block we are looking for. We are currently looking for the second one.
while( getline( file, in ) )
{
int n = 0;//Variable for storing index in the string (where our target text starts)
int i = 0;//Counter for [] blocks we have encountered.
while( i <= blockNumber )
{
//What we are doing here is searching for the position of [ symbol, starting
//from the n + 1'st symbol of the string.
n = in.find_first_of('[', n + 1);
i++;
}
//Getting our data and printing it.
out = in.substr( n + 1, ( in.find_first_of(']', n) - n - 1) );
std::cout << out << std::endl;
}
return 0;
}
The output after executing this will be:
20 BB EC 45 40 C8 97 20 84 8B 10
Maybe some other text
Some numbers maybe: 123 98345 123 9-834
blah-blah-blah
The simplest solution is something along the lines of:
std::string
match( std::string const& input )
{
static boost::regex const matcher( ".*\\[[^]]*\\]\\[(.*)\\]" );
boost::smatch matched;
return regex_match( input, matched, matcher )
? matched[1]
: std::string();
}
The regular expression looks a bit complicated because you need to match
meta-characters, and because the compiler I use doesn't support raw
strings yet. (With raw strings, I think the expression would be
R"^(.*\[[^]]\]\[(.*)\])^". But I can't verify that.)
This returns an empty string in case there is no match; if you're sure
about the format, you might prefer to throw an exception. You can also
extend it to do as much error checking as necessary: in general, the
more you validate a text input, the better it is, but you didn't give
precise enough information about what was legal for me to fill it out
completely. (For your example string, for example, you might replace
the ".*" at the beginning of the regular expression with
"\\u{3}\\s*::": three upper case characters followed by zero or more
whitespace, then two ':'. Or the first [] group might be
"\\[\\d\\]", if you're certain it's always a single digit.
This could work for you in a very specific sense:
std::string str(input);
std::string output(input.find_last_of('['), input.find_last_of(']'));
out = output.c_str();
The syntax isnt quite correct so you will need to look that up. You probably need to define your question a little better as well as this will only work if you want the brcketed string at the end.
Using string library in C. I'll give a code snippet that process a single linewhich can be used in a loop that reads the file line by line. NOTE: string.h should be included
int length = strlen( input );
char* output = 0;
// Search
char* firstBr = strchr( input, '[' );
if( 0 != firstBr++ ) // check for null pointer
{
char* secondBr = strchr( firstBr, '[' );
// we don't need '['
if( 0 != secondBr++ )
{
int nOutLen = strlen( secondBr ) - 1;
if( 0 < nOutLen )
{
output = new char[nOutLen+1];
strncpy( output, secondBr, nOutLen );
output[ nOutLen ] = '\0';
}
}
}
if( 0 != output )
{
cout << output;
delete[] output;
output = 0;
}
else
{
cout << "Error!";
}
You could use this regex to get what is inside "<" and ">":
// Regex: "<%999[^>]>" (Max of 999 Bytes)
int n1 = sscanf(source, "<%999[^>]>", dest);
I am trying to create an XML parser in C++. I am currently using cygwin and gcc to compile and gdb to debug. I have this piece of code:
const size_t mDataSize = mData.size();
...
size_t ltPos = mData.find_first_of('<', pos);
if (ltPos==mData.npos) {
...
mData is declared as private const std::string & within the class and holds the XML file content. After debugging with gdb I found the following:
(gdb) print pos
$12 = 636
(gdb) print mDataSize
$13 = 2692
(gdb) n
141 size_t ltPos = mData.find_first_of('<', pos);
(gdb) print ltPos
$14 = 114
(gdb) print pos
$15 = 636
(gdb) n
143 if (ltPos==mData.npos)
(gdb) print ltPos
$16 = 4294967295
(gdb) print mData[636]
$17 = (const char &) #0xb2b2a8: 10 '\n'
(gdb) print mData[637]
$18 = (const char &) #0xb2b2a9: 32 ' '
(gdb) print mData[638]
$19 = (const char &) #0xb2b2aa: 32 ' '
(gdb) print mData[639]
$20 = (const char &) #0xb2b2ab: 60 '<'
I was expecting 639 as result of calling find_first_of, but I am getting 4294967295 (which is -1 in a signed 32-bit int and matches std::string::npos). Can someone justify this behaviour? Or tell me how to workaround this?
So mData is declared as a reference? If so it doesn't really hold the content it holds a reference to the content. Is the thing to which mData refers still in existence at the time you're calling find_first_of?