I'm trying to read a jpg file from disk, and copy to a char buffer. The problem is that on the bytes there are some NULL character, and I'm having problems when I read the char buffer.
This is the current code:
char* readImg(char* filename)
{
FILE * pFile;
char jpgBuffer[20048];
long lSize;
errno_t result = fopen_s (&pFile,filename,"rb");
if (result != 0) {
printf("Error \n");
}
fseek (pFile , 0 , SEEK_END);
lSize = ftell (pFile);
rewind (pFile);
result = fread (jpgBuffer,1,lSize,pFile);
fclose (pFile);
jpgBuffer[lSize] = '\0';
return jpgBuffer;
}
and the call to the function is:
char* img = readImg("img.jpg");
then, I need to encode into base64, but if I want to know the size of the image buffer with strlen(), I'm getting a size of 4, because the 5 character is a "0".
How can I avoid the NULL characters into image buffer?
You may change your function prototype.
long readImage(const char* filename, char* buf, long bufSize)
{
FILE * pFile;
long lSize;
errno_t result = fopen_s (&pFile,filename,"rb");
if (result != 0) {
printf("Error \n");
}
fseek (pFile , 0 , SEEK_END);
lSize = ftell (pFile);
rewind (pFile);
if(bufSize < lSize)
{
printf("buf too small, needs %lu\n", lSize);
fclose(pFile);
return -1;
}
result = fread (buf,1,lSize,pFile);
fclose (pFile);
return lSize;
}
Then you get img data & actual size of it.
If you don't mind using malloc, you can alloc memory for buffer in your function.
long readImage(const char* filename, char** pbuf)
{
FILE * pFile;
long lSize;
errno_t result = fopen_s (&pFile,filename,"rb");
if (result != 0) {
printf("Error \n");
}
fseek (pFile , 0 , SEEK_END);
lSize = ftell (pFile);
rewind (pFile);
*pbuf = (char*)malloc(lSize * sizeof(char));
result = fread (*buf,1,lSize,pFile);
fclose (pFile);
return lSize;
}
call this function like following, and you need to remember free buffer.
char* buf = NULL;
long len = 0;
len = readImage(filename, &buf);
...
free(buf);
Use the lSize you determine in readImg(...) as the file size. strlen is for null terminated strings. dont use strlen to determine image size in bytes.
Note also, that you should assign jpgBuffer as a heap variable via new[] using lSize as the byte size. That way you can return a pointer to heap memory. Your current stack variable jpgBuffer will be invalid after the function returns, and hence the pointer to it. This way you also dont have to worry about the situation where you need more bytes than your hardcoded value (which you currently dont check!).
You will also want to return the lSize via an input parameter pointer/ref variable so you have a bounds to iterate over later on.
You can't use strlen to something that is not a string. You should return the size from the readIamge function. e.g.
char* readImg(char* filename, int *size);
If you program in C++ your should instead return an instance of a kind of an image class. This would avoid the splattered location of results.
Further you should never return the address of a local variable as your jpgBuffer. This variable will be overwritten aftern return from function.
You can return your data as a char* without any size information.
You can't return your jpgBuffer, locally allocated.
Change your function into:
int readImg(char* filename, unsigned char* buffer)
{
//...
result = fread (buffer,1,lSize,pFile);
return lSize;
}
If you can, allocate your buffer in the calling function, it will simplify your code.
However, it you want to avoid buffer overflow, you should pass the size of the allocated buffer to your read function, and return an error/throw an exception if the file size is greater than the size you allocated.
int readImg(char* filename, unsigned char* buffer, size_t aSize)
{
//...
fseek (pFile , 0 , SEEK_END);
lSize = ftell (pFile);
if (lSize > aSize)
{
// Manage error case
}
//...
result = fread (buffer,1,lSize,pFile);
return lSize;
}
Keep in mind that this way of coding is more C-style than C++-style. If you wish and can use C++, take advantage of C++ constructs, standard library to improve your code.
jpgBuffer is a "binary" buffer, not a "string". Put a null char at the end is non-sense. You should use the result variable to read your buffer.
Related
To read data from a file, I create heap memory then pass the variable pointer to a function so fread() will put the file data into the pointer. But when the function returns, there is no data in the new created memory.
int main(...) {
MyFile File;
File.Open(...);
int filesize = File.Tell();
char* buffer = new buffer[filesize]; // Create some memory for the data
File.Read((char**)&buffer);
// Now do something with the buffer. BUT there is trash in it.
File.Close();
delete [] buffer;
}
size_t File::Read(void* buf) {
...
::fseek(fStream, 0, SEEK_END);
int fileSize = ::ftell(fStream); // Get file size.
::fseek(fStream, 0, SEEK_SET);
::fread(buf, 1, fileSize, fStream);
return (fileSize);
}
Yes, I can put char * myBuffer = new char[fileSize]; inside of File::Read(...) before ::fread(myBuffer, 1, fileSize, fStream);,
but I should not have to do this because I already have heap memory
(buffer) in main().
You're reading your file contents into the pointer buffer, not the array it points to.
You're overcomplicating things anyway. You don't need a pointer to a pointer, or a void*. You can simply pass a char* to Read. You should really also pass the size of the buffer pointed to into Read as well. Otherwise you risk overflowing your buffer.
int main() {
MyFile File;
File.Open(/*.....*/);
int filesize = File.Tell()
char* buffer = new buffer[filesize]; // Create some memory for the data
File.Read(buffer, filesize);
// Now do something with the buffer. BUT there is trash in it.
File.Close();
delete [] buffer;
}
size_t File::Read(char* buf, size_t count) {
// ......
// No need to find the size of the file a second time
// Return the actual number of bytes read
return ::fread(buf, 1, count, fStream);
}
I changed my function to:
size_t nvFile::Read( char * pszBuffer, const size_t uiCount ) ...
Thank you Miles Budnek! I did not think enought of my problem. I am opening a binary file and it is a byte (char), so it not have to be void *. (I put on my 'cone-of-shame' for not thinking.)
Thank you for help and makeing me think more. :)
So i have this function that reads file, allocates memory, and puts file's content into buffer. I constantly get garbage data in the end though, so i need a way to null terminate the buffer.
#include "GetText.h"
void GetText(const char* filename, char** buffer)
{
FILE* file = fopen(filename,"rb");
long file_lenght;
if(file)
{
fseek(file, 0, SEEK_END);
file_lenght = ftell(file);
rewind(file);
*buffer = (char*) malloc(file_lenght + 1);
fread(*buffer, 1, file_lenght, file);
*buffer[file_lenght] = '\0'; //This line crashed program
fclose(file);
}
}
Since the bracket operator has higher precedence than pointer dereference you need to dereference buffer before indexing, like this:
(*buffer)[file_lenght] = '\0';
In your program you also need to make sure malloc was successful.
I used fwrite to store some data and now I'm trying to use fread to read the data from the txt file for processing. I want to read the values individually but I can't figure out how you'd do that. This is what I have tried:
#include <stdio.h>
#include <stdlib.h>
int main ()
{
FILE * pFile;
long lSize;
unsigned short * buffer;
size_t result;
pFile = fopen ( "myfile.txt" , "rb" );
// obtain file size:
fseek (pFile , 0 , SEEK_END);
lSize = ftell (pFile);
rewind (pFile);
// allocate memory to contain the whole file:
buffer = (unsigned short *) malloc (sizeof(unsigned short)*lSize);
// copy the file into the buffer:
result = fread (buffer,1,lSize,pFile);
printf("%uz\n", result);
// terminate
fclose (pFile);
free (buffer);
return 0;
}
The above program compiles fine but when I run it with ./a.out I get a Segmentation fault. When I run it with sudo ./a.out I don't get seg fault but nothing prints out.
Any idea what I can do to fix it?
Problems I see:
Allocating more memory than needed
After
lSize = ftell (pFile);
lSize is set to the number of characters in the file, not the number of unsigned shorts. Hence, you need
buffer = malloc(lSize);
See Do I cast the result of malloc?. If you are using a C++ compiler (as your C++ tag seems to imply), you need to cast the return value of malloc.
Wrong format specifier
printf("%s\n", result);
uses the wrong format specifier to print result. You need to use
printf("%zu\n", result);
That line is the most likely culprit for the segmentation fault you are seeing.
Reading objects one by one
You can certainly use:
size_t count = lSize/sizeof(short);
for ( size_t i = 0; i < count; ++i )
{
unsigned short number;
result = fread (&number, sizeof(unsigned short), 1, pFile);
}
You can also use:
size_t count = lSize/sizeof(short);
for ( size_t i = 0; i < count; ++i )
{
result = fread (buffer+i, sizeof(unsigned short), 1, pFile);
}
I have written a C++ Dll which has two functions, one writes a binary file to disk and and other reads that file from disk and load into memory.
//extremely simplified code looks like this
bool Utilities::WriteToBinary(wstring const fileName)
{
//lot of code
DWORD size = //get size of data to write
LPBYTE * blob = new LPBYTE[size];
WriteDataToMemoryBlob(blob, & size);
FILE * pFile;
if(0 != _wfopen_s (&pFile , fileName.c_str() , L"wb" ))
{
//do something
return false;
}
fwrite (blob, 1, size , pFile );
fclose (pFile);
delete[] blob;
return true;
}
bool Utilities::ReadDataFromDisk(wstring const fileName)
{
long fileSize = GetFileSize(fileName);
FILE * filePointer;
if(0 != _wfopen_s (&filePointer, fileName.c_str() , L"rb" ))
return false;
//read from file
LPBYTE * blobRead = new LPBYTE[fileSize];
fread (blobRead, 1, fileSize , filePointer );
fclose (filePointer);
//rest of the code...
Problem
I have created another C++ project which call these DLL methods for testing.
Problem which is driving me crazy is that when I call WriteToBinary and ReadDataFromDisk consecutively inside same program they work perfectly fine. But when I call WriteToBinary at one time and let the program exit and call ReadDataFromDisk next time and give it path of file written earlier by WriteToBinary, I get a BadPtr in blobRead after doing fread.
I have tried my best to make sure there are no shared or static data structures involved. Both methods are totally independent.
Any idea what might be causing this?
A mistake is the allocation of the array as LPBYTE is a BYTE* so the:
LPBYTE * blobRead = new LPBYTE[fileSize];
Is allocating an array of BYTE*, not an array of BYTE. Change to:
BYTE* blobRead = new BYTE[fileSize];
To avoid dynamic allocation you could use a std::vector<BYTE> instead:
std::vector<BYTE> blobRead(fileSize);
I have this theory, I can grab the file size using fseek and ftell and build a dynamic array as a buffer. Then use the buffer for fgets(). I currently can not come up with a way to do it.
My theory is based off of not knowing the size of the first file in bytes. So, I do not know how big of a buffer to build. What if the file is over 2 gigs? I want to be able to build a buffer that will change and recognize the file size of whatever file I put into SearchInFile().
Here is what I have so far below:
int SearchInFile(char *fname, char *fname2)
{
FILE *pFile, *pFile2;
int szFile, szFile2;
// Open first file
if( (fopen_s(&pFile, fname, "r")) != NULL )
{
return(-1);
}
// Open second file
if( (fopen_s(&pFile2, fname2, "r")) != NULL )
{
return(-1);
}
// Find file size
fseek(pFile, 0L, SEEK_END);
szFile = ftell(pFile);
// Readjust File Pointer
fseek(pFile, 0L, SEEK_SET);
std::vector <char> buff;
//char buff[szFile];
while(fgets(buff.push_back(), szFile, pFile))
{
}
Any thoughts or examples would be great. I've been searching the net for the last few hours.
Vector can grow, so you don't have to know the size beforehand. The following four lines do what you want.
std::vector<char> buff;
int ch;
while ((ch = fgetc(pFile)) != EOF)
buff.push_back(ch);
fgetc is a function to read a single char, simpler than using fgets.
If you do know the file size beforehand then you could call buff.reserve(szFile) before the loop. This will make the loop a little more efficient.