Reading blacklist from a text file in C++ - c++

I actually need my driver to read (line by line) some programs that are going to be blacklisted.
_T("bannedfile.exe") is where I actually need to put the blacklisted program.
How can I make _tcscmp read a text file, line by line?
(It makes a comparison between the host program that loads the driver, and the blacklisted one)
BOOL ProcessBlackList() {
TCHAR modulename[MAX_PATH];
GetModuleFileName(NULL, modulename, MAX_PATH);
PathStripPath(modulename);
if (_tcscmp(modulename, _T("bannedfile.exe")) != 1) {
return 0;
}
else {
return 0x2;
}
}

Can't be done that way.
You should be able to use use getline to read the file line by line and then pass the lines to _tcscmp. Should work something like this:
wchar_t const name[] = L"bannedfile.exe";
std::wifstream file(name);
std::wstring line;
while (std::getline(file, line)
{
if (_tcscmp(modulename, line.c_str()) == 0) {
return TRUE; //module is in list
}
}
return FALSE; // module is not in list
Lacking a copy of VS to test it at the moment.
If you run into unicode parsing problems because the file's encoding isn't quite what the defaults expect, give this a read: What is std::wifstream::getline doing to my wchar_t array? It's treated like a byte array after getline returns

Related

Reading from FileStream with arbitrary delimiter

I have encountered a problem to read msg from a file using C++. Usually what people does is create a file stream then use getline() function to fetch msg. getline() function can accept an additional parameter as delimiter so that it return each "line" separated by the new delimiter but not default '\n'. However, this delimiter has to be a char. In my usecase, it is possible the delimiter in the msg is something else like "|--|", so I try to get a solution such that it accept a string as delimiter instead of a char.
I have searched StackOverFlow a little bit and found some interesting posts.
Parse (split) a string in C++ using string delimiter (standard C++)
This one gives a solution to use string::find() and string::substr() to parse with arbitrary delimiter. However, all the solutions there assumes input is a string instead of a stream, In my case, the file stream data is too big/waste to fit into memory at once so it should read in msg by msg (or a bulk of msg at once).
Actually, read through the gcc implementation of std::getline() function, it seems it is much more easier to handle the case delimiter is a singe char. Since every time you load in a chunk of characters, you can always search the delimiter and separate them. While it is different if you delimiter is more than one char, the delimiter itself may straddle between two different chunks and cause many other corner cases.
Not sure whether anyone else has faced this kind of requirement before and how you guys handled it elegantly. It seems it would be nice to have a standard function like istream& getNext (istream&& is, string& str, string delim)? This seems to be a general usecase to me. Why not this one is in Standard lib so that people no longer to implement their own version separately?
Thank you very much
The STL simply does not natively support what you are asking for. You will have to write your own function (or find a 3rd party function) that does what you need.
For instance, you can use std::getline() to read up to the first character of your delimiter, and then use std::istream::get() to read subsequent characters and compare them to the rest of your delimiter. For example:
std::istream& my_getline(std::istream &input, std::string &str, const std::string &delim)
{
if (delim.empty())
throw std::invalid_argument("delim cannot be empty!");
if (delim.size() == 1)
return std::getline(input, str, delim[0]);
str.clear();
std::string temp;
char ch;
bool found = false;
do
{
if (!std::getline(input, temp, delim[0]))
break;
str += temp;
found = true;
for (int i = 1; i < delim.size(); ++i)
{
if (!input.get(ch))
{
if (input.eof())
input.clear(std::ios_base::eofbit);
str.append(delim.c_str(), i);
return input;
}
if (delim[i] != ch)
{
str.append(delim.c_str(), i);
str += ch;
found = false;
break;
}
}
}
while (!found);
return input;
}
if you are ok with reading byte by byte, you could build a state transition table implementation of a finite state machine to recognize your stop condition
std::string delimeter="someString";
//initialize table with a row per target string character, a column per possible char and all zeros
std::vector<vector<int> > table(delimeter.size(),std::vector<int>(256,0));
int endState=delimeter.size();
//set the entry for the state looking for the next letter and finding that character to the next state
for(unsigned int i=0;i<delimeter.size();i++){
table[i][(int)delimeter[i]]=i+1;
}
now in you can use it like this
int currentState=0;
int read=0;
bool done=false;
while(!done&&(read=<istream>.read())>=0){
if(read>=256){
currentState=0;
}else{
currentState=table[currentState][read];
}
if(currentState==endState){
done=true;
}
//do your streamy stuff
}
granted this only works if the delimiter is in extended ASCII, but it will work fine for some thing like your example.
It seems, it is easiest to create something like getline(): read to the last character of the separator. Then check if the string is long enough for the separator and, if so, if it ends with the separator. If it is not, carry on reading:
std::string getline(std::istream& in, std::string& value, std::string const& separator) {
std::istreambuf_iterator<char> it(in), end;
if (separator.empty()) { // empty separator -> return the entire stream
return std::string(it, end);
}
std::string rc;
char last(separator.back());
for (; it != end; ++it) {
rc.push_back(*it);
if (rc.back() == last
&& separator.size() <= rc.size()
&& rc.substr(rc.size() - separator.size()) == separator) {
return rc.resize(rc.size() - separator.size());
}
}
return rc; // no separator was found
}

C++ Strange characters appear when writing to text file

I have a program that writes out the frame number and current system time whenever a picture is taken on a camera:
SYSTEMTIME st;
GetSystemTime(&st);
lStr.Format( _T("%d %d.%d.%d.%d\r\n"),GetFrames() ,st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
std::wfstream myfile;
myfile.open("test.txt", std::ios::out | std::ios::in | std::ios::app );
if (myfile.is_open())
{
myfile.write((LPCTSTR)lStr, lStr.GetLength()*sizeof(TCHAR));
myfile.close();
}
else {lStr.Format( _T("open file failed: %d"), WSAGetLastError());
}
The text file that the program outputs seems to write the data correctly, but I get spaces and characters that shouldn't be there at the start of each line. The website doesn't seem to format the spaces correctly so i'll post a picture, this is what the text file looks like. The file also shows bullet points sometimes in addition to the zero's.
As you can see the first line is fine but it seems to get worse the longer I write to the text file. The program is writing to the file about 10 times every second. I am new to C++ and I am not sure what could be causing this. I tried to look for other questions similar to this but they didn't seem to have a solution I was looking for. Any help would be appreciated.
The solution has 2 parts:
lStr.Format( _T("%d %d.%d.%d.%d\r\n"),GetFrames() ,st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
should be
lStr.Format( _T("%lu %d.%d.%d.%d\n"),GetFrames() ,st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
As GetFrames() returns DWORD which is unsigned long and you are writing the file as text so \n is converted to \r\n if needed, depending on the operating system.
The other part is that the second parameter of wfstream::write is number of characters not number of bytes so
myfile.write((LPCTSTR)lStr, lStr.GetLength()*sizeof(TCHAR));
should be
myfile.write((LPCTSTR)lStr, lStr.GetLength());
When you use std::wfstream::write (basic_ostream), it takes the size of your string. You multiply that size again with * sizeof(TCHAR). Removing this additional multiply should simply fix your problem.
Though if you have anywhere else issues (e.g. a third-party library returns with too many spaces), you could always trim the string.
A basic example for this:
template<class TString>
static inline TString &trim_left(TString &s)
{
s.erase(std::begin(s), std::find_if(std::begin(s), std::end(s), std::not1(std::ptr_fun<int, int>(std::isspace))));
return s;
}
template<class TString>
static inline TString &trim_right(TString &s)
{
s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), std::end(s));
return s;
}
template<class TString>
static inline TString &trim(TString &s)
{
return trim_left(trim_right(s));
}

Skip reading a line in a INI file if its length greater than n in C++

I want to skip reading a line in the INI file if has more than 1000 characters.This is the code i'm using:
#define MAX_LINE 1000
char buf[MAX_LINE];
CString strTemp;
str.Empty();
for(;;)
{
is.getline(buf,MAX_LINE);
strTemp=buf;
if(strTemp.IsEmpty()) break;
str+=strTemp;
if(str.Find("^")>-1)
{
str=str.Left( str.Find("^") );
do
{
is.get(buf,2);
} while(is.gcount()>0);
is.getline(buf,2);
}
else if(strTemp.GetLength()!=MAX_LINE-1) break;
}
//is.getline(buf,MAX_LINE);
return is;
...
The problem i'm facing is that if the characters exceed 1000 if seems to fall in a infinite loop(unable to read next line).How can i make the getline to skip that line and read the next line??
const std::size_t max_line = 1000; // not a macro, macros are disgusting
std::string line;
while (std::getline(is, line))
{
if (line.length() > max_line)
continue;
// else process the line ...
}
How abut checking the return value of getline and break if that fails?
..or if is is an istream, you could check for an eof() condition to break you out.
#define MAX_LINE 1000
char buf[MAX_LINE];
CString strTemp;
str.Empty();
while(is.eof() == false)
{
is.getline(buf,MAX_LINE);
strTemp=buf;
if(strTemp.IsEmpty()) break;
str+=strTemp;
if(str.Find("^")>-1)
{
str=str.Left( str.Find("^") );
do
{
is.get(buf,2);
} while((is.gcount()>0) && (is.eof() == false));
stillReading = is.getline(buf,2);
}
else if(strTemp.GetLength()!=MAX_LINE-1)
{
break;
}
}
return is;
For something completely different:
std::string strTemp;
str.Empty();
while(std::getline(is, strTemp)) {
if(strTemp.empty()) break;
str+=strTemp.c_str(); //don't need .c_str() if str is also a std::string
int pos = str.Find("^"); //extracted this for speed
if(pos>-1){
str=str.Left(pos);
//Did not translate this part since it was buggy
} else
//not sure of the intent here either
//it would stop reading if the line was less than 1000 characters.
}
return is;
This uses strings for ease of use, and no maximum limits on lines. It also uses the std::getline for the dynamic/magic everything, but I did not translate the bit in the middle since it seemed very buggy to me, and I couldn't interpret the intent.
The part in the middle simply reads two characters at a time until it reaches the end of the file, and then everything after that would have done bizarre stuff since you weren't checking return values. Since it was completely wrong, I didn't interpret it.

ifstream fails to open in recursive calls

we are running into an odd issue when trying to parse an input file. the idea is that this file can include other files, which must be parsed as well. We are doing this recursively in a function defined as
int parse_inp(const char* filename)
The main file parses no problem, but recursive calls cannot open their file streams.
int parse_inp(const char* filename)
{
char buffer[BUFFER_MAX+1];
char* token;
std::string tok;
int keywordSection;
bool end_of_file;
int cardNum;
...
int i;
std::string tempop;
double tempd1, tempd2;
SetSegmentCard2 tempSetSegmentCard2;
int offset;
printf("%s\n", filename);
std::ifstream inp;
inp.clear();
inp.open(filename, std::ios::in);
if(!inp.good() || !inp.is_open())
{
char path1[256];
getcwd(path1,256);
printf("CWD: %s\n", path1);
fflush(NULL);
printf("Unable to open '%s'\n", filename);
return 0;
}
std::set<std::string> unrecognized;
std::string line;
while(inp.good() && !inp.eof())
{
getline(inp, line);
strcpy(buffer, line.c_str());
if (isComments(buffer)) //skip the comments line
continue;
if (buffer[0]=='*') //this is a keyword line
{
token = strtok(buffer," \n");
keywordSection = is_inp_keyw(token);
if (keywordSection==0)
unrecognized.insert(token);
cardNum = 0;
continue;
}
//a data line
tempop="";
char* found = NULL;
char path_buffer[100] = "Dyna3DWriter\\";
int pos = 0;
switch(keywordSection)
{
case 0: //not recognized
//end of last keyword, not recognizable word
break;
case 1: //KEYWORD
//"KEYWORD didn't do anything
break;
case 2: //TITLE
break;
case 3: //INCLUDE
token = strtok(buffer, "\n");
inp.clear();
parse_inp(token);
break;
...
}
}
if(inp.is_open())
{
inp.close();
inp.clear();
}
}
The recursive files never parse. I looked around a lot and most issues seemed to be either that the fail bit was set (which is why we are calling inp.clear() a lot), or that we are making the wrong assumption about the current working directory.
To test the second theory, we added in:
if(!inp.good() || !inp.is_open())
{
char path1[256];
getcwd(path1,256);
printf("CWD: %s\n", path1);
fflush(NULL);
printf("Unable to open '%s'\n", filename);
return 0;
}
And our working directory and file name are both correct. We see the same behavior when using fopen(filename, "r") --- a call to perror("fopen") results in:
fopen: no such file or directory
EDIT: Filled in more code
Are you sure the filename does not contain any garbage or bad character that would lead to this issue?
If the error is file not found, that means the filename is wrong in some way.
Could it come from a bad declaration of buffer? We don't see it in your code.
Another possibility is that you use strtok again in your initialization before opening the file. You must avoid using strtok that is based on global storage for recursive method like this. You should use strtok_r instead.
If your recursive function is called very deeply you can easily overload the OS limit on the number of open files.
I used to run my Gentoo Linux with a per-process file limit of 250 with exceptions for programs that needed a lot more.
Windows has limits that vary depending on how much memory is available to the system and how many objects have already been created system-wide.
The smart way to do this is to have two functions. The first function is the one everyone else calls and it does the setup, including opening the file. The second function is the recursive function and it takes nothing but a reference to a std::ifstream object.
EDIT:
I see that I misunderstood your question, and you aren't recursively opening the same file. I will leave my above paragraph anyway.

Getting input from a file in C++

I am currently developing an application, which gets the input from a text file and proceeds accordingly. The concept is the input file will have details in this fomat
A AND B
B OR C
Each and every line will be seperated by a blank space and the input must be taken from the text file and processed by logic. I use a TCPP compiler and i am facing problems reading the input. Please help me with the issue...
Reading input a line at a time is normally done with std::getline, something like this:
std::string line;
std::ifstream infile("filename");
while (std::getline(line, infile))
// show what we read
std::cout << line << "\n";
If you're having trouble with things like this, you might consider looking for a (better) book on C++ than whatever you're now (hopefully) using.
Following can be used straightaway:
BOOL ReadFile(CString filename)
{
BOOL bRead = TRUE;
std::ifstream m_strmFile;
m_strmFile.open(filename, std::ios::in);
char pszLine[256];
memset(pszLine, 256, 0);
if (m_strmFile)
{
// Read whatever number of lines in your file
for (unsigned int i = 0; i < 5/*number of lines*/; i++)
m_strmFile.getline(pszLine, 256);
// Do whatever you want to do with your read lines here...
}
else bRead = FALSE;
return bRead;
}
are you using headr files like:
include
or #include and you can make use of the fileobject.getline(), (do check its proper syntax.) function in C++ or for char by char use fileobject.get(ch) kind of function