String formation from hex string - c++

I m trying to create hash of file by reading its content, and then hashing it using SHA1, after this I m trying to create a filename with this hash value, but the issue only first two char of hash string is taken.
Hash function
void hash(const std::string& content, std::string& retValue, bool isFile)
{
SHA_CTX ctx;
SHA1_Init(&ctx);
SHA1_Update(&ctx, content.c_str(), content.size());
if (isFile) {
FILE* f = fopen(content.c_str(),"r");
assert(f != NULL);
char buffer[1024]={0};
while(fgets(buffer,1024,f))
SHA1_Update(&ctx,buffer,strlen(buffer));
fclose(f);
}
unsigned char hash[SHA_DIGEST_LENGTH] = {0};
SHA1_Final(hash,&ctx);
retValue.resize(60);
int cnt = 0;
for(int i=0;i<SHA_DIGEST_LENGTH;i++){
char ch[3] = {0};
sprintf(ch,"%02x",hash[i]);
retValue[cnt++] = ch[0];
retValue[cnt++] = ch[1];
retValue[cnt++] = ch[2];
}
std::cout<<retValue<<std::endl;
}
when I print hash value in console I get a valid looking val such as this 51d946cde43e90ec03493f88914ca948b5215916, but it contains only first two characters in this case '51', I switched to gdb to view the string, gdb shows me the string in a weird way 51\000d9\000\064\066\000cd\000e4\000\063e\000\071\060\000ec\000\060\063\000\064\071\000\063f\000\070\070\000\071\061\000\064c\000a9\000\064\070\000b5\000\062\06 1\000\065\071\000\061\066. I am saving file with std::ofstream. I have looked at prev answers that said this is a bug in gdb so it prints like this, but here I can see file getting created doesnt with only first char of hash.
Why is this happening?
Thank You.
-----------------------------------------------EDIT-------------------------------------------------------------------------
From comment of dvix, it got resolved, I was copying '\0' with ch[2], so basically I was needed to only copy first two character from each hex character, ch[0] and ch[1] and then place null at very end of string.
so the code inside of for loop should look like this
for(int i=0;i<SHA_DIGEST_LENGTH;i++){
char ch[3] = {0};
sprintf(ch,"%02x",hash[i]);
retValue[cnt++] = ch[0];
retValue[cnt++] = ch[1];
}
retValue[cnt] = '\0';

Here's a slightly shorter version that does the same thing:
for(int i=0;i<SHA_DIGEST_LENGTH;i++){
sprintf(retValue + cnt,"%02x",hash[i]);
cnt += 2;
}

Related

How to Convert Data structure to convert char* in c++

I'm think pointer is 4Byte or(2Byte) heap memory allocated
I need Structure data convert to char* Just need 12byte convert
this is my code
please Contact me.
thank you
struct MyData {
unsigned int myNumber;
float x;
float y;
};
int main(){
Mydata* mydata = new Mydata();
mydata->userNumber = 188242268;
mydata->x = 100.0f;
mydata->y = 102.0f;
char* sender = (char*)&mydata;
sioclient->send(sender);
// SocketIO Server Send
}
I don't think what you are asking is possible. string doesn't like having null characters in itself, which would be necessary to directly send the data (For example, a int(1) would have 1 NULL (0x0) character (modern systems would have 3 NULL characters) and 1 0x1 character, which string wouldn't like the null and terminate the string there).
I think you should find another networking library for what you are doing if you can't use WebSocket and need to have the efficiency of sending the bytes of a struct. (Boost::asio perhaps?)
But if you HAVE to use Cocos2d-x SIOClient without the WebSocket, then in the sending side, create a string with the values separated by commas:
string sendMe = to_string(mydata->userNumber) + "," + to_string(mydata->x) + "," + to_string(mydata->y);
And then on the receiving side:
Mydata receiver;
string recStr;//Received string
string temp;
int stage = 0;
for (int itr = 0; itr < temp.length(); itr++)
{
if (recStr[itr] == ',')
{
if (stage==0)
receiver.myNumber = stoi(temp);
else if (stage==1)
receiver.x = stof(temp);
stage++;
temp = "";
}
else
temp += recStr[itr];
}
receiver.y = stof(temp);
Hope that helps.
The old answer, in case you want to switch and have a solution:
Ok, try using the overloaded function
void send (const unsigned char * binaryMsg, unsigned int len);
instead. read about it here
This should look something like the following:
sioclient->send(reinterpret_cast<unsigned char*>(mydata), sizeof(MyData));
Tell me if you are using a different version of Cocos2d-x and thus this doesn't work, or if it failed to solve the problem. When I tried this, it compiled nicely and seemed to behave correctly.
If your compiler doesn't like unsigned char* for a const unsigned char* parameter, just add a const_cast.
Also, remember to delete (mydata); when you are done with it.

strchr, memchr fails to locate the character

I am trying to parse a string of format something like 1-3,5-7. I need to read 1,3 and 5,7.
What I am doing
char *dup_string;
dup_string = strdup(data);
tok = strtok(dup_string, ",");
while (tok != NULL)
{
char *rangeTok;
rangeTok = (char *)memchr(tok, "-", strlen(tok));
startpage = atoi(tok);
if(rangeTok != NULL)
{
*rangeTok++;
endpage = atoi(rangeTok);
}
else
endpage = startpage;
tok = strtok(NULL,",");
}
Here memchar returning a badptr, I have tried using strchr which is also returning batptr. Any ideas why it is returning badptr.
FYI, earlier I tried:
tok = strchr(dupstring, ",");
which worked fine for sometime, and started returning badptr. I am not sure why it is doing that.
You're passing the wrong argument to both strchr and memchr, as has already been pointed out. The second argument is an integer holding the value of a character, not a const char *.
This line
rangeTok = (char *)memchr(tok, "-", strlen(tok));
should be either
rangeTok = (char *)memchr(tok, '-', strlen(tok));
or preferably
rangeTok = strchr(tok, '-');
As an aside, what is this badptr? Do you just mean NULL?
The prototype of memchr() is as follows, void * memchr(void * ptr, int value, size_t num);. But you are passing a string in memchr(tok, "-", strlen(tok)); instead of an integer. The way you used strtok() is also wrong, It should be as follows,
tok = strtok(dup_string, ",");
while (tok != NULL)
{
/* Body of Loop */
tok = strtok(NULL,",");
}
On a first call, strtok() expects a string as the first argument, whose first character is used as the starting location to scan for tokens. In subsequent calls, the function expects a null pointer and uses the position right after the end of last token as the new starting location for scanning.
try to use sscanf() in this way
#include<stdio.h>
#include<string.h>
main()
{
char *data = "1-3,5,8-9";
char *ptr = data;
int e, pos=0, startpage, endpage;
while((e=sscanf(ptr, "%d-%d%n", &startpage, &endpage, &pos))>=1)
{
ptr+=pos;
if(e==1)
endpage = startpage;
printf("start page %d ** end page %d\n",startpage,endpage);
if (sscanf(ptr, " %*[,]%n", &pos) >= 0)
ptr+=pos;
}
}

C++ std::string length() or size() not working on method args

I have a method that that creates a MatLab array name from a file path and returns it as a std::string. the resulting string is passed into another method that writes the name to the file. When I try to get the length of the passed in string, it displays 0 when the length of the string is 12 or 13 chars.
My code:
bool MyClass::masterMethod(std::string fileURI){
FILE* dataStream;
// Assume dataStream is set up correctly
// Get arrayName from File URI
std::string arrayName = this->makeArrayNameFromPath( fileURI);
//Write array name to file
this->writeArrayName(arrayName , dataStream)
}
std::string MyClass::makeArrayNameFromPath(std::string filePathURI){
std::string tempString = filePathURI.substr(filePathURI.find_last_of('/')+1);
std::string returnString = "";
long index = 0;
for(long i = 0; i < tempString.length(); i++){
if((tempString[i] != ' ') && (tempString[i] != '.')){
returnString[index++] = tempString[i];
}
}
return returnString;
}
void MyClass::writeArrayName(std::string name , FILE *nameStream){
// long testLength = name.length();
// long testLength2 = name.size();
// const char* testChar = nam.c_str();
// long testCharLen = strlen(testChar);
// The size of the name is the number of Chars * sizeof(int8_t)
int32_t sizeOfName = (int32_t)(name.length() * sizeof(int8_t));
int32_t nameType = miINT8;
fwrite(&nameType , sizeof(int32_t) , 1 , nameStream);
fwrite(&sizeOfName, sizeof(sizeOfName), 1, nameStream);
fwrite(&name , sizeof(name[0]), sizeOfName , nameStream);
}
So I'm not sure why string::length is not working. If a create a std::string test = name, and print it , I can get the value of the string but can not get its length or size.
If I use const char* testName = name.c_str(); long test = strlen(testName), I get a the
correct value, but thought that wasn't necessary.
So any advice or suggestion is appreciated.
returnString[index++] = tempString[i]; doesn't do what you think it does. It's not adding additional space or length to the string, only overwriting memory at a location that the string doesn't actually own. I think returnString.append(1, tempString[i]) or similar should do it.
You never give the string a size, just trying to assign positions that isn't there.
Try this instead to add characters to the return value
returnString += tempString[i];

Get file name without extension?

I'm new to C++ world, I stuck with a very trivial problem i.e. to get file name without extension.
I have TCHAR variable containing sample.txt, and need to extract only sample, I used PathFindFileName function it just return same value what I passed.
I tried googling for solution but still no luck?!
EDIT: I always get three letter file extension, I have added the following code,
but at the end I get something like Montage (2)««þîþ how do I avoid junk chars at the end?
TCHAR* FileHandler::GetFileNameWithoutExtension(TCHAR* fileName)
{
int fileLength = _tcslen(fileName) - 4;
TCHAR* value1 = new TCHAR;
_tcsncpy(value1, fileName, fileLength);
return value1;
}
Here's how it's done.
#ifdef UNICODE //Test to see if we're using wchar_ts or not.
typedef std::wstring StringType;
#else
typedef std::string StringType;
#endif
StringType GetBaseFilename(const TCHAR *filename)
{
StringType fName(filename);
size_t pos = fName.rfind(T("."));
if(pos == StringType::npos) //No extension.
return fName;
if(pos == 0) //. is at the front. Not an extension.
return fName;
return fName.substr(0, pos);
}
This returns a std::string or a std::wstring, as appropriate to the UNICODE setting. To get back to a TCHAR*, you need to use StringType::c_str(); This is a const pointer, so you can't modify it, and it is not valid after the string object that produced it is destroyed.
You can use PathRemoveExtension function to remove extension from filename.
To get only the file name (with extension), you may have first to use PathStripPath, followed by PathRemoveExtension.
Try below solution,
string fileName = "sample.txt";
size_t position = fileName.find(".");
string extractName = (string::npos == position)? fileName : fileName.substr(0, position);
TCHAR* FileHandler::GetFileNameWithoutExtension(TCHAR* fileName)
{
int fileLength = _tcslen(fileName) - 4;
TCHAR* value1 = new TCHAR[fileLength+1];
_tcsncpy(value1, fileName, fileLength);
return value1;
}
Try this:
Assuming the file name is in a string.
string fileName = your file.
string newFileName;
for (int count = 0;
fileName[count] != '.';
count++)
{
newFileName.push_back(fileName[count]);
}
This will count up the letters in your original file name and add them one by one to the new file name string.
There are several ways to do this, but this is one basic way to do it.

C++, Get text from a website, part 3

So, thanks for all the help guys, I am just have one last problem, I am putting the website source in a char var, and then reading the product title (I have gotten that), however it only works if I take part of the source, or only the html from one of the featured products on neweggs page. I think the program is crashing, because it doesnt know which title to pick when I need to get all three titles and put them into an array. Any ideas? Thanks. Here is the parser code:
http://paste2.org/p/809045
Any solution is greatly appreciated.
/**
* num_to_next -
* takes in a pointer to a string and then counts how many
* characters are until the next occurance of the specified character
* #ptr: the pointer to a string in which to search
* #c: char delimiter to search until
**/
int num_to_next(char *ptr, char c)
{
unsigned int i = 0;
for (i = 0; i < strlen(ptr); i++) {
if (ptr[i] == c) {
return i;
}
}
return -1;
}
/**
* space_to_underscore -
* this should help to alleviate some problems when dealing with
* filepaths that have spaces in them (basically just changes all
* spaces in a string to underscores)
* #string: the string to convert, yo
**/
int space_to_underscore(char *string)
{
for (unsigned int i = 0; i < strlen(string); i++) {
if (string[i] == ' ') {
string[i] = '_';
}
}
return 0;
}
char *file_name = (char *)malloc(sizeof(char *)); // allocate memory for where the app name will be stored
memset(file_name, 0, sizeof(file_name)); // zero the memory
char td_one[] = "<ul class="featureCells"><li id="ItemCell" class="cell">";
char *pstr = strstr(buffer, td_one) + strlen(td_one) + 6; // buffer is the source
char *poop = pstr + num_to_next(pstr, '>') + 1;
int blah = num_to_next(poop, '<');
strncpy(file_name, poop, blah);
// null terminate the string //
file_name[blah] = '\0';
space_to_underscore(file_name);
MessageBox(NULL, file_name, "Product Name", MB_OK);
free(file_name);
I'm not sure if these are your only problems, but...
First, you can't do char* filename = (char*)malloc(sizeof(char*)) (well, you can, but that's not what you actually want from your app).
What you want to have is char* filename = (char*)malloc(SIZE_OF_YOUR_STRING * sizeof(char));, so you can't allocate just an abstract buffer for your string and you have to know the expected size of it. Actually, here you don't have to write sizeof(char) because it always equals 1, but this sometimes this way of writing the code can help you(or somebody else) to understand that this block would store a string as array of chars).
Another example on the same problem: char* filename = (char*)malloc(65); - is ok and will allocate a block of memory to store 65 char symbols.
If we go further (where you're doing the memset), char* is a plain pointer and sizeof(filename) in your case would return the size of your pointer, but not your string. What you should write here is strlen(filename).