I need to read a stream out of a binary file from a function. I'd like to call it by reference of that char * to have a pointer to the start of the stream in the end. However, Every attempt of mine, did either not change the pointer, or caused an Memory Access Violation.
I call the method from another function.
Here the calling function:
APP_ERROR EncryptionHandler::encryptFile(char *file)
{
char *i_Stream = ""; // I get a compiler error if I dont initialize this
if(this->readFileStream("picture.png", i_Stream) != OPERATION_SUCCESSFUL) // Call the function and return a custom error, if the function does so
return ERROR_FILE_READING;
}
Here the function to read the file
APP_ERROR EncryptionHandler::readFileStream(char *fileName, char *Stream)
{
char *fileStream;
FILE *file = fopen(fileName, "rb");
// Some logic to get the file size
fileStream = new char[maxFileSize];
fread(fileStream, 1, maxFileSize, file); // Fill the stream with the fread function
fclose(file);
Stream = fileStream; // Set the given Pointer to my fileStream pointer
return OPERATION_SUCCESSFUL;
}
How ever in the calling function, the Variable i_Stream has never changed. It's still pointing to "" which causes problems in my program, later
I don't get this, as I set the given pointer = my fileStream pointer
However following methods didn't work aswell:
this->readFileStream("picture.png", char &i_Stream);
i_Error EncryptionHandler::readFileStream(char *fileName, char **Stream)
this->readFileStream("picture.png", char *i_Stream);
i_Error EncryptionHandler::readFileStream(char *fileName, char &Stream)
Procedures like memcpy aren't the right thing I think, as I've already got this pointer to my Stream. And they caused Access Violation Errors aswell...
There must be an easy way to give that stream pointer from within my file reading function to my calling methods variable...
I cannot use the return value of the function, because I am using my own Error system, as you can see...
It is also binary Data and the use of any strings is not welcome.
So what is the proper way of calling a char array by reference?
You should declare EncryptionHandler::readFileStream() as
APP_ERROR EncryptionHandler::readFileStream(char *fileName, char *&Stream)
Note the type of parameter Stream. With reference of pointer, you can pass the change of Stream inside readFileStream() back to caller.
Without the reference, the pointer is simply copied into readFileStream().
In addition to what #timrau said, I see a memory allocation problem. I don't see any code that allocates memory to hold the data that you are reading from the file. Something like the code below should work.
PP_ERROR EncryptionHandler::readFileStream(char *fileName, char*& Stream)
{
char *fileStream;
FILE *file = fopen(fileName, "rb");
// Some logic to get the file size
// Allocate memory for the data.
fileStream = new char[maxFileSize];
fread(fileStream, 1, maxFileSize, file); // Fill the stream with the fread function
fclose(file);
Stream = fileStream; // Set the given Pointer to my fileStream pointer
return OPERATION_SUCCESSFUL;
}
You can simplify the function a little bit by just using Stream.
PP_ERROR EncryptionHandler::readFileStream(char *fileName, char*& Stream)
{
FILE *file = fopen(fileName, "rb");
// Some logic to get the file size
// Allocate memory for the data.
Stream = new char[maxFileSize];
fread(Stream, 1, maxFileSize, file); // Fill the stream with the fread function
fclose(file);
return OPERATION_SUCCESSFUL;
}
Related
I am a C# developer so I'm a bit confused with this language. The problem here is that I'm working with someone elses code and I just need to do a slight change. I need to change a function that takes a file path parameter and uses fopen() to load it into a FILE type to a function that just takes a char array and converts that to a FILE type
How it looks right now:
bool ExampleFunction::Load(const string& fileName)
{
string f = filename;
FILE* fp = fopen(f.c_str(), "rb");
}
How I want it to be (pseudocode):
bool ExampleFunction::Load(const char* fileBytes)
{
FILE* fp = fopen(fileBytes, "rb");
}
Your so-called 'pseudo' code actually already is the correct function – apart from that you do not return a value. Just some further hints:
If you store the file pointer in a member variable, check if a file has already been opened before and close it if need be.
If you just load some data from file into local variables, don't forget to fclose the file again afterwards.
Otherwise you get a memory leaks.
However, inside your original function, you create a totally useless copy of the input string:
bool ExampleFunction::Load(const string& fileName)
{
string f = filename; // <--- copy!!!
FILE* fp = fopen(f.c_str(), "rb");
}
Either use the paramter directly:
FILE* fp = fopen(filename.c_str(), "rb");
or, if you want a shorter alias, create it as reference again:
string const& f = filename;
// alternatively:
auto& f = filename;
// ^ don't forget, otherwise copy again
I personally would recommend to keep original function as overload:
bool ExampleFunction::Load(char const* filename);
bool ExampleFunction::Load(std::string const& filename)
{
return Load(filename.c_str());
}
so that users having stored the file name in a std::string object can use that one directly.
I am trying to use the PEM_read_bio function to get data from a file.
The version of SSLeay we are using is from 1997, so documentation is a bit thin on the ground. Thankfully in this case it seems there is a matching function documented here: https://www.openssl.org/docs/man1.1.0/crypto/PEM_read_bio.html
I originally tried this:
char ** names;
char ** headers;
unsigned char ** data;
long len;
BIO *in = BIO_new_file("C:\\filename.txt", "r");
if (!in)
{
// error
}
else
{
int result = PEM_read_bio(in, names, headers, data, &len);
}
BIO_free(in);
OPENSSL_free(names);
OPENSSL_free(headers);
OPENSSL_free(data);
However this results in a run-time check failure: The variable 'names' is being used without being initialized.
The documentation mentions OPENSSL_malloc( num ) is used to initialize memory, but it fails to mention whether it does this behind the scenes, or the user does it.
OPENSSL_malloc is similar in usage to C's malloc, but how are we supposed to know how much memory to allocate in advance, before reading the file?
I have tried the following at the beginning:
char ** names = reinterpret_cast<char **>(OPENSSL_malloc(2));
char ** headers = reinterpret_cast<char **>(OPENSSL_malloc(2));
unsigned char ** data = reinterpret_cast<unsigned char **>(OPENSSL_malloc(2));
long len;
This results in apparently random data.
The documentation you linked to says:
The name, header and data pointers are allocated via OPENSSL_malloc() and should be freed by the caller via OPENSSL_free() when no longer needed.
That means PEM_read_bio() calls OPENSSL_malloc() for you, and then you call OPENSSL_free() on the allocated memory it returns when you are doing with it.
You are passing uninitialized pointers to PEM_read_bio(), that is why it is failing. The name, header and data parameters are all output parameters. You need to pass in the addresses of your own pointer variables to receive the memory that PEM_read_bio() allocates for you, eg:
char *name;
char *headers;
unsigned char *data;
long len;
BIO *in = BIO_new_file("C:\\filename.txt", "r");
if (!in)
{
// error
}
else
{
int result = PEM_read_bio(in, &name, &headers, &data, &len);
if (!result)
{
// error
}
else
{
...
OPENSSL_free(name);
OPENSSL_free(headers);
OPENSSL_free(data);
}
BIO_free(in);
}
i am working on a piece of code right now and got a problem with void pointer and char. basically, within the serialize function, we would have a new char. we would need to store that char in buffer. and here is the signature of serialize function.
void serialize(void *buffer,
//some other inputs here
){
std::string str = "";
/*some code here, store the final output in str first*/
char* charStr = new char[str.size()];
strcpy(charStr,str.c_str());
buffer = static_cast<void*>(charStr);
}
using the function like this,
char buffer[256];
serialize(buffer,
//some other inputs here
);
However, the data stored in buffer would be something real strange. I changed the void pointer in the signature to char pointer as a temporary solution. However, i know there must be a better one.
If you want to fill a buffer, you cannot assign to it (that will just overwrite the pointer, leaving the original buffer contents intact). You also do not need a temporary buffer in serialize (charStr). You can directly strcpy to the output buffer, like this:
void serialize(void *buffer
){
std::string str = "foo bar baz";
strcpy((char *)buffer, str.c_str());
}
define it as
void serialize(void *& buffer,
//some other inputs here
){
use pointer as parameter, remember to delete the buffer
char* buffer;
serialize(buffer,
//some other inputs here
);
I wrote a C++ class named DCstring similar to String class in Java.
class DCstring
{
public:
TCHAR *string;
DCstring();
DCstring(TCHAR * str);
DCstring in();
}
DCstring::DCstring()
{
string=NULL;
}
//constructor to initialize
DCstring::DCstring(TCHAR* temp)
{
_TINT i=0;
string=(TCHAR*)malloc(_tcslen(temp)*sizeof(TCHAR)+1);
for(;i<_tcslen(temp);i++)
string[i]=temp[i];
string[i]=0;
}
//to get input from user
DCstring DCstring::in()
{
wprintf(L"\n Enter the string :");
TCHAR arr[200],*s;
_getts(arr);
_TINT i=0;
string=(TCHAR*)realloc(string,_tcslen(arr)*sizeof(TCHAR)+1);
for(;i<_tcslen(arr);i++)
string[i]=arr[i];
string[i]=0;
return(*this);
}
This works fine.
I use this DCstring variable inside a struct and reads & writes that struct object into &from a file using fwrite & fread functions.
typedef struct Stud
{
DCstring name;
}stud;
void InsertToFile(stud *temp,FILE *file)
{
(temp->name)=DCstring();
fflush(stdin);
temp->name=(temp->name).in();
fseek(file,0,SEEK_END);
fwrite(&(*head),sizeof(stud),1,file);
}
void Show(stud *temp,FILE *file)
{
rewind (file ) ;
fread ( &temp,sizeof(stud), 1, file ) ;
wprintf ( L"\n%s",temp->name ) ;
}
This code can read and write data for the 1st time.when I reexecute the code and call Show(stud *temp,FILE *file) function,it throws an runtime error/exception.
"Unhandled exception at 0x77c815de in StudentRecord.exe: 0xC0000005: Access violation reading location 0x002850a8".
seems like problem in memory.Help me out.
Apart from the poor implementation of your DCString class (exposed instance variables, lack of destructor, fixed-sized input buffer, and some more) you have failed to understand that writing an instance of your struct stud won't, in fact, write the contents of the data pointed to by stud.name.string.
struct stud contains an instance of DCString however the memory used to store the string data is on the heap (which you allocated using malloc()); your code is writing the pointer to the allocated memory, which will be meaningless when you read it back in (certainly in a different session).
You need to provide a read/write DCString method, which is passed a FILE * (better would be to use istream and ostream, given this is C++) which reads/writes the string contents, allocating new memory during the read.
The problem is here:
public:
TCHAR *string;
This writes out a pointer to the string, so when you read back in you get a pointer that doesn't point to any data, thus your access violation. This question, for instance, discusses serialisation, which is what you probably want to do.
Furthermore:
fflush(stdin);
Is undefined behaviour.
Yet furthermore, you should really use C++ std::string and std::i/ofstream.
EDIT I just noticed:
wprintf ( L"\n%s %d %c",temp->name ) ;
You don't have anything matching the %d and %c parameters.
Im am a c programmer trying to begin a new phase of my life in c++ (i know i am still using printf below, but that because formatting is so easy). I am looking to print out the first byte of a datafile from a member function of an object. I think my streambuffer is being destroyed before I can read it's data but I'm lost as to what to do.
My class looks like the following
class MyParser {
MyParser(string filepath);
void readHeader();
streambuf *pbuf;
long size;
}
My constructor opens the file, gets the buffer out, outputs the first byte and returns. (I think pbuf is dying at the end of this code). This code outputs First Byte (in constructor): 0x8C
MyParser::MyParser(string filepath) {
ifstream file(filepath.c_str(), ios::in | ios::binary)
pbuf = file.rdbuf();
size = pbuf->pubseekoff(0,ios::end,ios::in);
pbuf->pubseekpos(0,ios::in);
unsigned char byte = pbuf->sgetc();
printf("First Byte (in constructor): 0x%02X\n", byte);
return;
}
My read header is dumping the first byte, but based on the output all is see is First Byte (in readHeader): 0xFF
void MyParser::readHeader() {
unsigned char byte = pbuf->sgetc();
printf("First Byte (in readHeader): 0x%02X\n", byte);
}
My main simply creates a parser and tries to readHeader
void main() {
MyParser parser("../data/data.bin");
parser.readHeader();
}
I think the solution to my problem is to create a new streambuffer but new streambuf(file.rdbuf()) isn't working for me. Any advice?
Your program has undefined behavior: the stream buffer you keep is owned by the std::ifstream you open in body of you constructor. When this object dies, the stream buffer is released as well. The easiest approach to avoid this problem is to have your std::ifstream be a member of your class: this binds the life-time of the stream to your object. It may also be easier to use the std::istream interface for your parsing rather than the somewhat awkward std::streambuf interface.
If you really want to just use a stream buffer, you can allocate a std::filebuf using new filebuf and the open() the file stream directly. To keep a pointer to it, you would probably use std::unique_ptr<std::filebuf> (or std::auto_ptr<std::filebuf> if you are not using C++ 2011). Using the pointer class arranges for automatic release of the object. Of course, the pointers would still be members of your class to get the life-times right.
Your attempt to copy a stream buffer didn't work because stream buffers are not copyable. You'd need to create the file buffer directly:
MyParser::MyParser(std::string const& filename)
: pbuf(new std::filebuf)
{
this-pbuf->open("whatever", std::ios_base::in);
...
}
You need some new C++ teaching material, because (sorry) but this is just so wrong. You need to declare the filestream as a member, there's no need for any new anywhere in this program, and pretty much nobody, ever, needs to deal with streambuf.
class MyParser {
std::ifstream file;
public:
MyParser(string filepath) {
file.open(filepath, std::ios::in | std::ios::binary );
char byte;
file.read(sizeof(byte), &byte);
printf("First Byte (in constructor): 0x%02X\n", byte);
}
void readHeader() {
char byte;
file.read(sizeof(byte), &byte);
printf("First Byte (in readHeader): 0x%02X\n", byte);
}
};