Bellow you can find a code snippet that I used to write an string_length with it to binary file but the code does not works as expected. After it writes I opened the output file and the string was located there but when I read the string from file it reads the string partially. It seems that after reading the string_length the file pointer seeks more than what it should and then it missed the first 8 characters of the string!
#include <iostream>
#include <string>
FILE* file = nullptr;
bool open(std::string mode)
{
errno_t err = fopen_s(&file, "test.code", mode.c_str());
if (err == 0) return true;
return false;
}
void close()
{
std::fflush(file);
std::fclose(file);
file = nullptr;
}
int main()
{
open("wb"); // open file in write binary mode
std::string str = "blablaablablaa";
auto sz = str.size();
fwrite(&sz, sizeof sz, 1, file); // first write size of string
fwrite(str.c_str(), sizeof(char), sz, file); // second write the string
close(); // flush the file and close it
open("rb"); // open file in read binary mode
std::string retrived_str = "";
sz = -1;
fread(&sz, sizeof(size_t), 1, file); // it has the right value (i.e 14) but it seems it seeks 8 bytes more!
retrived_str.resize(sz);
fread(&retrived_str, sizeof(char), sz, file); // it missed the first 8 char
close(); // flush the file and close it
std::cout << retrived_str << std::endl;
return 0;
}
PS: I removed checks in the code in order to makes it more readable.
You're clobbering the retrieved_str object with the file contents rather than reading the file contents into the buffer controlled by retrieved_str.
fread(&retrived_str[0], 1, sz, file);
Or, if you're using C++17 with its non-const std::string::data method:
fread(retrived_str.data(), 1, sz, file);
Change
fread(&retrived_str, sizeof(char), sz, file); // it missed the first 8 char
To
fread((void*)( retrived_str.data()), sizeof(char), sz, file); // set the data rather than the object
Related
I'm trying to determine how big a file i'm reading is in bytes so I used Fseek to jump to the end and it triggered the error: file.exe has triggered a breakpoint.
Heses the code:
FileUtils.cpp:
#include "FileUtils.h"
namespace impact {
std::string read_file(const char* filepath)
{
FILE* file = fopen(filepath, "rt");
fseek(file, 0, SEEK_END);
unsigned long length = ftell(file);
char* data = new char[length + 1];
memset(data, 0, length + 1);
fseek(file, 0 ,SEEK_SET);
fread(data, 1, length, file);
fclose(file);
std::string result(data);
delete[] data;
return result;
}
}
FileUtils.h:
#pragma once
#include <stdio.h>
#include <string>
#include <fstream>
namespace impact {
std::string read_file(const char* filepath);
}
If more info is required just ask me for it I would be more than happy to provide more!
You are doing this in the C way, C++ has much better (in my opinion) ways of handling files.
Your error looks like it may be caused because the file didn't open correctly (you need to check if file != nullptr).
To do this in C++17 you should use the standard library filesystem
(Note: You can also do this with C++11 experimental/filesystem using std::experimental::filesystem namespace)
Example:
std::string read_file(const std::filesystem::path& filepath) {
auto f_size = std::filesystem::file_size(filepath);
...
}
Additionally to read a file in C++ you do not need to know the size of the file. You can use streams:
std::string read_file(const std::filesystem::path& filepath) {
std::ifstream file(filepath); // Open the file
// Throw if failed to open the file
if (!file) throw std::runtime_error("File failed to open");
std::stringstream data; // Create the buffer
data << file.rdbuf(); // Read into the buffer the internal buffer of the file
return data.str(); // Convert the stringstream to string and return it
}
As you can see, the C++ way of doing it is much shorter and much easier to debug (helpful exceptions with descriptions are thrown when something goes wrong)
I read a text file and it works very well.
std::string str_buf = "";
FILE *file = fopen("/home/pi/log_2019-03-07.txt", "r");
if (file != NULL)
{
while (true)
{
char buffer[MAX_BUFFER_SIZE] = { 0x00, };
size_t rSize = fread(buffer, MAX_BUFFER_SIZE, sizeof(char), file);
str_buf += buffer;
if (rSize == 0)
break;
}
printf("%s", str_buf.data());
fclose(file);
}
Then I try to write it to same path, another name. This is the code:
FILE *writefile = fopen("/home/pi/WriteTest.txt", "wb");
if (writefile != NULL)
{
int offset = 0;
while (true)
{
size_t wSize = fwrite(&str_buf.data()[offset], sizeof(char), strlen(str_buf.data()) - 1, writefile);
offset += (int)wSize;
if (offset >= strlen(str_buf.data()))
break;
}
fclose(writefile);
}
If I try to execute this code, it works. I open WriteTest.txt, it has same string. It's perfectly same.
But I found WriteTest.txt's volume is almost 2 twice read text.
Why it happens?
size_t wSize = fwrite(&str_buf.data()[offset], sizeof(char), strlen(str_buf.data()) - 1, writefile);
you start writing the text at offset &str_buf.data()[offset] but you write the length of a string starting at position 0. You are writing offset bytes too much. You should
size_t wSize = fwrite(&str_buf.data()[offset], sizeof(char),
strlen(str_buf.data()) - offset, writefile);
Also, you don't write string length nor a NUL terminator. So you'd have trouble figuring out how much to read unless, like in your simple example, it is at file's end.
And last, it's better to use str_buf.length() rather than strlen. It's faster and works with strings that have NUL in the middle.
I would like to know how to insert an argument to a function call using libclang? I have to following code that just prints the arguments:
class CASTVisitor : public RecursiveASTVisitor<CASTVisitor>
{
public:
CASTVisitor(Rewriter &R) : rewriter(R)
{
}
virtual bool VisitCallExpr(CallExpr *call)
{
for(int i = 0, j = call->getNumArgs(); i < j; ++ i)
{
errs() << "argType: " << call->getArg(i)->getType().getAsString() << "\n";
}
errs() << "** Added parameter to function call\n";
return true;
}
...
};
Edit:
And although I can read and set the arguments, I don't see any way to insert one at the beginning of the parmVarDcl() matcher.
The same goes with adding member variables to base classes and compound statements. It would seem you can change existing text but you cannot insert new object easily. Am I right?
The only solution I found so far is by getting a file pointer from a cursor and injecting code manually:
https://github.com/burnflare/libclang-experiments
CXFile file;
unsigned line;
unsigned offset;
clang_getSpellingLocation(clang_getCursorLocation(cursors[i+1]),
&file,
&line,
NULL,
&offset);
const char* filename = clang_getCString(clang_getFileName(file));
printf("\n\nMethod found in %s in line %d, offset %d\n", clang_getCString(clang_getFileName(file)), line, offset);
// File reader
FILE *fr = fopen(filename, "r");
fseek(fr, 0, SEEK_END);
long fsize = ftell(fr);
fseek(fr, 0, SEEK_SET);
// Reading file to string
char *input = malloc(fsize);
fread(input, fsize, 1, fr);
fclose(fr);
// Making an output that is input(start till offset) + code injection + input(offset till end)
FILE *fw = fopen(filename, "w");
char *output = malloc(fsize);
strncpy(output, input, offset);
strcat(output, injectCode);
strcat(output, input+offset);
// Rewrite the whole file with output string
fwrite(output, fsize, sizeof(output), fw);
fclose(fw);
If anybody has a better idea then please let me know!
I am trying to read a binary file's data sadly opening in C++ is a lot different than in python for these things as they have byte mode. It seems C++ does not have that.
for (auto p = directory_iterator(path); p != directory_iterator(); p++) {
if (!is_directory(p->path()))
byte tmpdata;
std::ifstream tmpreader;
tmpreader.open(desfile, std::ios_base::binary);
int currentByte = tmpreader.get();
while (currentByte >= 0)
{
//std::cout << "Does this get Called?" << std::endl;
int currentByte = tmpreader.get();
tmpdata = currentByte;
}
tmpreader.close()
}
else
{
continue;
}
I want basically a clone of Python's methods of opening a file in 'rb' mode. To have to actual byte data of all of the contents (which is not readable as it has nonprintable chars even for C++. Most of which probably cant be converted to signed chars just because it contains zlib compressed data that I need to feed in my DLL to decompress it all.
I do know that in Python I can do something like this:
file_object = open('[file here]', 'rb')
turns out that replacing the C++ Code above with this helps. However fopen is depreciated but I dont care.
What the Code above did not do was work because I was not reading from the buffer data. I did realize later that fopen, fseek, fread, and fclose was the functions I needed for read bytes mode ('rb').
for (auto p = directory_iterator(path); p != directory_iterator(); p++) {
if (!is_directory(p->path()))
{
std::string desfile = p->path().filename().string();
byte tmpdata;
unsigned char* data2;
FILE *fp = fopen("data.d", "rb");
fseek(fp, 0, SEEK_END); // GO TO END OF FILE
size_t size = ftell(fp);
fseek(fp, 0, SEEK_SET); // GO BACK TO START
data2 = new unsigned char[size];
tmpdata = fread(data2, 1, size, fp);
fclose(fp);
}
else
{
continue;
}
int currentByte = tmpreader.get();
while (currentByte >= 0)
{
//std::cout << "Does this get Called?" << std::endl;
int currentByte = tmpreader.get();
//^ here!
You are declaring a second variable hiding the outer one. However, this inner one is only valid within the while loop's body, so the while condition checks the outer variable which is not modified any more. Rather do it this way:
int currentByte;
while ((currentByte = tmpreader.get()) >= 0)
{
Like always, problems with pointers. This time I am trying to read a file (opened in binary mode) and store some portion of it in a std::string object.
Let's see:
FILE* myfile = fopen("myfile.bin", "rb");
if (myfile != NULL) {
short stringlength = 6;
string mystring;
fseek(myfile , 0, SEEK_SET);
fread((char*)mystring.c_str(), sizeof(char), (size_t)stringlength, myfile);
cout << mystring;
fclose(myfile );
}
Is this possible? I don't get any message. I am sure the file is O.K. When I try with char* it does work but I want to store it directly into the string. Thanks for your help!
Set the string to be large enough first to avoid buffer overrun, and access the byte array as &mystring[0] to satisfy const and other requirements of std::string.
FILE* myfile = fopen("myfile.bin", "rb");
if (myfile != NULL) {
short stringlength = 6;
string mystring( stringlength, '\0' );
fseek(myfile , 0, SEEK_SET);
fread(&mystring[0], sizeof(char), (size_t)stringlength, myfile);
cout << mystring;
fclose(myfile );
}
There are many, many issues in this code but that is a minimal adjustment to properly use std::string.
I would recommend this as the best way to do such a thing. Also you should check to make sure that all the bytes were read.
FILE* sFile = fopen(this->file.c_str(), "r");
// if unable to open file
if (sFile == nullptr)
{
return false;
}
// seek to end of file
fseek(sFile, 0, SEEK_END);
// get current file position which is end from seek
size_t size = ftell(sFile);
std::string ss;
// allocate string space and set length
ss.resize(size);
// go back to beginning of file for read
rewind(sFile);
// read 1*size bytes from sfile into ss
fread(&ss[0], 1, size, sFile);
// close the file
fclose(sFile);
string::c_str() returns const char* which you can not modify.
One way to do this would be use a char* first and construct a string from it.
Example
char buffer = malloc(stringlength * sizeof(char));
fread(buffer, sizeof(char), (size_t)stringlength, myfile);
string mystring(buffer);
free(buffer);
But then again, if you want a string, you should perhaps ask yourself Why am I using fopen and fread in the first place??
fstream would be a much much better option.
You can read more about it here
Please check out the following regarding c_str to see some things that are wrong with your program. A few issues include the c_str not being modifiable, but also that it returns a pointer to your string contents, but you never initialized the string.
http://www.cplusplus.com/reference/string/string/c_str/
As for resolving it... you could try reading into a char* and then initializing your string from that.
No it is not. std::string::c_str() method does not return a modifiable character sequence as you can validate from here. A better solution would be using a buffer char array. Here is an example:
FILE* myfile = fopen("myfile.bin", "rb");
if (myfile != NULL) {
char buffer[7]; //Or you can use malloc() / new instead.
short stringlength = 6;
fseek(myfile , 0, SEEK_SET);
fread(buffer, sizeof(char), (size_t)stringlength, myfile);
string mystring(buffer);
cout << mystring;
fclose(myfile );
//use free() or delete if buffer is allocated dynamically
}