Long question for a very simple & rookie problem BUT yet I need some advise.
So I have a binary file that I need to parse. This file starts with some magic string that contains the null char (\0
). let's define is as ab\0cd
.
I'm writing a method that returns true if some file starts with the magic string.
#define MAGIC_STRING "ab\0cd"
bool IsMagicFile(const wpath& pathFile)
{
string strData;
if (!ReadFile(pathFile, strData))
return false;
if (strData.size() < 5)
return false;
string strPrefix = strData.substr(0, 5);
if (strcmp(strPrefix.c_str(), MAGIC_STRING) != 0)
return false;
return true;
}
What bothers me with the above code is that I "hardcodedly" assume the size of the magic string is 5
.
what if tomorrow the magic string changes? say:
#define MAGIC_STRING "abe\0fcd"
the string macro changed and the code no longers work properly.
#define MAGIC_STRING "ab\0cd"
bool IsMagicFile(const wpath& pathFile)
{
string strMagic = MAGIC_STRING;
string strData;
if (!ReadFile(pathFile, strData))
return false;
if (strData.size() < strMagic.size())
return false;
string strPrefix = strData.substr(0, strMagic.size());
if (strcmp(strPrefix.c_str(), MAGIC_STRING) != 0)
return false;
return true;
}
I supposedly got rid of the hard-coded size problem BUT the size of strMagic
is not really 5 but 2. string ends with \0
#define MAGIC_STRING "ab\0cd" // CAUTION - MAGIC_STRING & MAGIC_STRING_SIZE must be changes together
#define MAGIC_STRING_SIZE 5 // CAUTION - MAGIC_STRING & MAGIC_STRING_SIZE must be changes together
bool IsMagicFile(const wpath& pathFile)
{
string strData;
if (!ReadFile(pathFile, strData))
return false;
if (strData.size() < MAGIC_STRING_SIZE)
return false;
string strPrefix = strData.substr(0, MAGIC_STRING_SIZE);
if (strcmp(strPrefix.c_str(), MAGIC_STRING) != 0)
return false;
return true;
}
This solved the first problem but I still don't get the seamless magic string change I wanted.
Is attempt 3 good enough? do you have a better approach?
Instead of using the macro definition you could define a constant character array. For example
const char MAGIC_STRING[] = "abe\0fcd";
In this case the number of characters excluding the terminating zero is equal to
sizeof( MAGIC_STRING ) - 1
To compare raw bytes you can use standard C function memcmp
supplying the number of compared bytes that is equal to the expression above.
Here is a demonstrative program
#include <iostream>
#include <string>
#include <cstring>
#include <iterator>
const char MAGIC_STRING[] = "abe\0fcd";
int main()
{
std::string s( std::begin( MAGIC_STRING ), std::prev( std::end( MAGIC_STRING ) ) );
if ( memcmp( s.c_str(), MAGIC_STRING, sizeof( MAGIC_STRING ) - 1 ) == 0 )
{
std::cout << "The string starts with the MAGIC_STRING" << std::endl;
}
return 0;
}
Its output is
The string starts with the MAGIC_STRING